From 8c4ebc2359a21373410cc3a786959b36a1a4ca27 Mon Sep 17 00:00:00 2001 From: "Jordan K. Hubbard" Date: Fri, 18 Jun 1993 04:22:21 +0000 Subject: [PATCH] Updated GNU utilities --- gnu/COPYING | 339 + gnu/Makefile | 5 + gnu/usr.bin/awk/ACKNOWLEDGMENT | 21 + gnu/usr.bin/awk/COPYING | 340 + gnu/usr.bin/awk/FUTURES | 120 + gnu/usr.bin/awk/LIMITATIONS | 14 + gnu/usr.bin/awk/Makefile | 13 + gnu/usr.bin/awk/NEWS | 1295 ++ gnu/usr.bin/awk/PORTS | 32 + gnu/usr.bin/awk/POSIX | 95 + gnu/usr.bin/awk/PROBLEMS | 6 + gnu/usr.bin/awk/README | 116 + gnu/usr.bin/awk/array.c | 293 + gnu/usr.bin/awk/awk.1 | 1873 +++ gnu/usr.bin/awk/awk.h | 763 ++ gnu/usr.bin/awk/awk.y | 1804 +++ gnu/usr.bin/awk/builtin.c | 1133 ++ gnu/usr.bin/awk/config.h | 272 + gnu/usr.bin/awk/dfa.c | 2291 ++++ gnu/usr.bin/awk/dfa.h | 543 + gnu/usr.bin/awk/eval.c | 1225 ++ gnu/usr.bin/awk/field.c | 645 + gnu/usr.bin/awk/gawk.texi | 11270 ++++++++++++++++ gnu/usr.bin/awk/getopt.c | 662 + gnu/usr.bin/awk/getopt.h | 128 + gnu/usr.bin/awk/getopt1.c | 160 + gnu/usr.bin/awk/io.c | 1207 ++ gnu/usr.bin/awk/iop.c | 318 + gnu/usr.bin/awk/main.c | 731 + gnu/usr.bin/awk/msg.c | 106 + gnu/usr.bin/awk/node.c | 429 + gnu/usr.bin/awk/patchlevel.h | 1 + gnu/usr.bin/awk/protos.h | 115 + gnu/usr.bin/awk/re.c | 208 + gnu/usr.bin/awk/regex.c | 2854 ++++ gnu/usr.bin/awk/regex.h | 260 + gnu/usr.bin/awk/version.c | 46 + gnu/usr.bin/groff/BUG-REPORT | 57 + gnu/usr.bin/groff/COPYING | 339 + gnu/usr.bin/groff/ChangeLog | 4958 +++++++ gnu/usr.bin/groff/Makefile | 13 + gnu/usr.bin/groff/Makefile.cfg | 38 + gnu/usr.bin/groff/NEWS | 662 + gnu/usr.bin/groff/PROBLEMS | 458 + gnu/usr.bin/groff/PROJECTS | 19 + gnu/usr.bin/groff/README.gnu | 38 + gnu/usr.bin/groff/TODO | 24 + gnu/usr.bin/groff/VERSION | 1 + gnu/usr.bin/groff/addftinfo/Makefile | 12 + gnu/usr.bin/groff/addftinfo/Makefile.dep | 3 + gnu/usr.bin/groff/addftinfo/addftinfo.1 | 85 + gnu/usr.bin/groff/addftinfo/addftinfo.cc | 194 + gnu/usr.bin/groff/addftinfo/guess.cc | 490 + gnu/usr.bin/groff/addftinfo/guess.h | 44 + gnu/usr.bin/groff/afmtodit/Makefile | 9 + gnu/usr.bin/groff/afmtodit/afmtodit.1 | 204 + gnu/usr.bin/groff/afmtodit/afmtodit.pl | 325 + gnu/usr.bin/groff/devices/Makefile | 10 + gnu/usr.bin/groff/devices/Makefile.dev | 63 + gnu/usr.bin/groff/devices/Makefile.tty | 52 + gnu/usr.bin/groff/devices/devX100-12/CB | 306 + gnu/usr.bin/groff/devices/devX100-12/CBI | 306 + gnu/usr.bin/groff/devices/devX100-12/CI | 306 + gnu/usr.bin/groff/devices/devX100-12/CR | 306 + gnu/usr.bin/groff/devices/devX100-12/DESC | 9 + gnu/usr.bin/groff/devices/devX100-12/HB | 306 + gnu/usr.bin/groff/devices/devX100-12/HBI | 306 + gnu/usr.bin/groff/devices/devX100-12/HI | 306 + gnu/usr.bin/groff/devices/devX100-12/HR | 306 + gnu/usr.bin/groff/devices/devX100-12/Makefile | 10 + gnu/usr.bin/groff/devices/devX100-12/NB | 306 + gnu/usr.bin/groff/devices/devX100-12/NBI | 306 + gnu/usr.bin/groff/devices/devX100-12/NI | 306 + gnu/usr.bin/groff/devices/devX100-12/NR | 306 + gnu/usr.bin/groff/devices/devX100-12/S | 226 + gnu/usr.bin/groff/devices/devX100-12/TB | 306 + gnu/usr.bin/groff/devices/devX100-12/TBI | 306 + gnu/usr.bin/groff/devices/devX100-12/TI | 306 + gnu/usr.bin/groff/devices/devX100-12/TR | Bin 0 -> 3302 bytes gnu/usr.bin/groff/devices/devX100/CB | 306 + gnu/usr.bin/groff/devices/devX100/CBI | Bin 0 -> 3190 bytes gnu/usr.bin/groff/devices/devX100/CI | 306 + gnu/usr.bin/groff/devices/devX100/CR | 306 + gnu/usr.bin/groff/devices/devX100/DESC | 9 + gnu/usr.bin/groff/devices/devX100/HB | 306 + gnu/usr.bin/groff/devices/devX100/HBI | 306 + gnu/usr.bin/groff/devices/devX100/HI | 306 + gnu/usr.bin/groff/devices/devX100/HR | 306 + gnu/usr.bin/groff/devices/devX100/Makefile | 10 + gnu/usr.bin/groff/devices/devX100/NB | 306 + gnu/usr.bin/groff/devices/devX100/NBI | 306 + gnu/usr.bin/groff/devices/devX100/NI | 306 + gnu/usr.bin/groff/devices/devX100/NR | 306 + gnu/usr.bin/groff/devices/devX100/S | 226 + gnu/usr.bin/groff/devices/devX100/TB | 306 + gnu/usr.bin/groff/devices/devX100/TBI | 306 + gnu/usr.bin/groff/devices/devX100/TI | 306 + gnu/usr.bin/groff/devices/devX100/TR | 306 + gnu/usr.bin/groff/devices/devX75-12/CB | 306 + gnu/usr.bin/groff/devices/devX75-12/CBI | 306 + gnu/usr.bin/groff/devices/devX75-12/CI | 306 + gnu/usr.bin/groff/devices/devX75-12/CR | 306 + gnu/usr.bin/groff/devices/devX75-12/DESC | 9 + gnu/usr.bin/groff/devices/devX75-12/HB | 306 + gnu/usr.bin/groff/devices/devX75-12/HBI | 306 + gnu/usr.bin/groff/devices/devX75-12/HI | 306 + gnu/usr.bin/groff/devices/devX75-12/HR | 306 + gnu/usr.bin/groff/devices/devX75-12/Makefile | 10 + gnu/usr.bin/groff/devices/devX75-12/NB | 306 + gnu/usr.bin/groff/devices/devX75-12/NBI | 306 + gnu/usr.bin/groff/devices/devX75-12/NI | 306 + gnu/usr.bin/groff/devices/devX75-12/NR | 306 + gnu/usr.bin/groff/devices/devX75-12/S | 226 + gnu/usr.bin/groff/devices/devX75-12/TB | 306 + gnu/usr.bin/groff/devices/devX75-12/TBI | 306 + gnu/usr.bin/groff/devices/devX75-12/TI | 306 + gnu/usr.bin/groff/devices/devX75-12/TR | 306 + gnu/usr.bin/groff/devices/devX75/CB | 306 + gnu/usr.bin/groff/devices/devX75/CBI | 306 + gnu/usr.bin/groff/devices/devX75/CI | 306 + gnu/usr.bin/groff/devices/devX75/CR | 306 + gnu/usr.bin/groff/devices/devX75/DESC | 9 + gnu/usr.bin/groff/devices/devX75/HB | 306 + gnu/usr.bin/groff/devices/devX75/HBI | 306 + gnu/usr.bin/groff/devices/devX75/HI | 306 + gnu/usr.bin/groff/devices/devX75/HR | 306 + gnu/usr.bin/groff/devices/devX75/Makefile | 10 + gnu/usr.bin/groff/devices/devX75/NB | 306 + gnu/usr.bin/groff/devices/devX75/NBI | 306 + gnu/usr.bin/groff/devices/devX75/NI | 306 + gnu/usr.bin/groff/devices/devX75/NR | 306 + gnu/usr.bin/groff/devices/devX75/S | 226 + gnu/usr.bin/groff/devices/devX75/TB | 306 + gnu/usr.bin/groff/devices/devX75/TBI | 306 + gnu/usr.bin/groff/devices/devX75/TI | 306 + gnu/usr.bin/groff/devices/devX75/TR | 306 + gnu/usr.bin/groff/devices/devascii/DESC.proto | 8 + gnu/usr.bin/groff/devices/devascii/Makefile | 6 + gnu/usr.bin/groff/devices/devascii/R.proto | 165 + gnu/usr.bin/groff/devices/devdvi/B | 347 + gnu/usr.bin/groff/devices/devdvi/BI | 352 + gnu/usr.bin/groff/devices/devdvi/CW | 158 + gnu/usr.bin/groff/devices/devdvi/DESC | 11 + gnu/usr.bin/groff/devices/devdvi/EX | 144 + gnu/usr.bin/groff/devices/devdvi/H | 302 + gnu/usr.bin/groff/devices/devdvi/HB | 302 + gnu/usr.bin/groff/devices/devdvi/HI | 303 + gnu/usr.bin/groff/devices/devdvi/I | 353 + gnu/usr.bin/groff/devices/devdvi/MI | 136 + gnu/usr.bin/groff/devices/devdvi/Makefile | 12 + gnu/usr.bin/groff/devices/devdvi/R | 430 + gnu/usr.bin/groff/devices/devdvi/S | 152 + gnu/usr.bin/groff/devices/devdvi/SA | 143 + gnu/usr.bin/groff/devices/devdvi/SB | 132 + .../devices/devdvi/generate/CompileFonts | 15 + .../groff/devices/devdvi/generate/Makefile | 93 + .../groff/devices/devdvi/generate/msam.map | 127 + .../groff/devices/devdvi/generate/msbm.map | 121 + .../groff/devices/devdvi/generate/texb.map | 127 + .../groff/devices/devdvi/generate/texex.map | 100 + .../groff/devices/devdvi/generate/texi.map | 127 + .../groff/devices/devdvi/generate/texmi.map | 32 + .../groff/devices/devdvi/generate/texr.map | 127 + .../groff/devices/devdvi/generate/texsy.map | 100 + .../groff/devices/devdvi/generate/textt.map | 126 + .../groff/devices/devlatin1/DESC.proto | 8 + gnu/usr.bin/groff/devices/devlatin1/Makefile | 6 + gnu/usr.bin/groff/devices/devlatin1/R.proto | 353 + gnu/usr.bin/groff/devices/devps/AB | 559 + gnu/usr.bin/groff/devices/devps/ABI | 560 + gnu/usr.bin/groff/devices/devps/AI | 559 + gnu/usr.bin/groff/devices/devps/AR | 558 + gnu/usr.bin/groff/devices/devps/BMB | 438 + gnu/usr.bin/groff/devices/devps/BMBI | 441 + gnu/usr.bin/groff/devices/devps/BMI | 434 + gnu/usr.bin/groff/devices/devps/BMR | 430 + gnu/usr.bin/groff/devices/devps/CB | 336 + gnu/usr.bin/groff/devices/devps/CBI | 337 + gnu/usr.bin/groff/devices/devps/CI | 337 + gnu/usr.bin/groff/devices/devps/CR | 336 + gnu/usr.bin/groff/devices/devps/DESC | 14 + gnu/usr.bin/groff/devices/devps/DESC-A4 | 14 + gnu/usr.bin/groff/devices/devps/DESC-letter | 14 + gnu/usr.bin/groff/devices/devps/HB | 546 + gnu/usr.bin/groff/devices/devps/HBI | 547 + gnu/usr.bin/groff/devices/devps/HI | 617 + gnu/usr.bin/groff/devices/devps/HNB | 546 + gnu/usr.bin/groff/devices/devps/HNBI | 547 + gnu/usr.bin/groff/devices/devps/HNI | 617 + gnu/usr.bin/groff/devices/devps/HNR | 616 + gnu/usr.bin/groff/devices/devps/HR | 616 + gnu/usr.bin/groff/devices/devps/Makefile | 15 + gnu/usr.bin/groff/devices/devps/NB | 446 + gnu/usr.bin/groff/devices/devps/NBI | 447 + gnu/usr.bin/groff/devices/devps/NI | 447 + gnu/usr.bin/groff/devices/devps/NR | 447 + gnu/usr.bin/groff/devices/devps/PB | 449 + gnu/usr.bin/groff/devices/devps/PBI | 451 + gnu/usr.bin/groff/devices/devps/PI | 453 + gnu/usr.bin/groff/devices/devps/PR | 456 + gnu/usr.bin/groff/devices/devps/S | 227 + gnu/usr.bin/groff/devices/devps/SS | 194 + gnu/usr.bin/groff/devices/devps/TB | 533 + gnu/usr.bin/groff/devices/devps/TBI | 515 + gnu/usr.bin/groff/devices/devps/TI | 528 + gnu/usr.bin/groff/devices/devps/TR | 519 + gnu/usr.bin/groff/devices/devps/ZCMI | 477 + gnu/usr.bin/groff/devices/devps/ZD | 193 + gnu/usr.bin/groff/devices/devps/ZDR | 193 + gnu/usr.bin/groff/devices/devps/download | 5 + .../groff/devices/devps/generate/Makefile | 224 + .../groff/devices/devps/generate/afmname | 44 + .../groff/devices/devps/generate/dingbatsmap | 2 + .../groff/devices/devps/generate/dingbatsrmap | 1 + .../groff/devices/devps/generate/lgreekmap | 28 + .../groff/devices/devps/generate/symbol.sed | 33 + .../groff/devices/devps/generate/symbolchars | 60 + .../groff/devices/devps/generate/symbolsl.afm | 203 + .../groff/devices/devps/generate/textmap | 449 + gnu/usr.bin/groff/devices/devps/prologue | 152 + gnu/usr.bin/groff/devices/devps/symbol.afm | 215 + gnu/usr.bin/groff/devices/devps/symbolsl.pfa | 29 + gnu/usr.bin/groff/devices/devps/text.enc | 231 + gnu/usr.bin/groff/devices/devps/zapfdr.afm | 222 + gnu/usr.bin/groff/devices/devps/zapfdr.pfa | 218 + gnu/usr.bin/groff/doc/Makefile | 55 + gnu/usr.bin/groff/doc/meintro.me | 2246 +++ gnu/usr.bin/groff/doc/meref.me | 2194 +++ gnu/usr.bin/groff/eqn/Makefile | 21 + gnu/usr.bin/groff/eqn/Makefile.dep | 31 + gnu/usr.bin/groff/eqn/TODO | 41 + gnu/usr.bin/groff/eqn/box.cc | 611 + gnu/usr.bin/groff/eqn/box.h | 277 + gnu/usr.bin/groff/eqn/delim.cc | 380 + gnu/usr.bin/groff/eqn/eqn.1 | 862 ++ gnu/usr.bin/groff/eqn/eqn.h | 51 + gnu/usr.bin/groff/eqn/eqn.y | 331 + gnu/usr.bin/groff/eqn/lex.cc | 1160 ++ gnu/usr.bin/groff/eqn/limit.cc | 195 + gnu/usr.bin/groff/eqn/list.cc | 236 + gnu/usr.bin/groff/eqn/main.cc | 352 + gnu/usr.bin/groff/eqn/mark.cc | 121 + gnu/usr.bin/groff/eqn/neqn.sh | 5 + gnu/usr.bin/groff/eqn/other.cc | 601 + gnu/usr.bin/groff/eqn/over.cc | 196 + gnu/usr.bin/groff/eqn/pbox.h | 141 + gnu/usr.bin/groff/eqn/pile.cc | 293 + gnu/usr.bin/groff/eqn/script.cc | 221 + gnu/usr.bin/groff/eqn/special.cc | 115 + gnu/usr.bin/groff/eqn/sqrt.cc | 179 + gnu/usr.bin/groff/eqn/text.cc | 528 + gnu/usr.bin/groff/grodvi/Makefile | 12 + gnu/usr.bin/groff/grodvi/Makefile.dep | 2 + gnu/usr.bin/groff/grodvi/dvi.cc | 895 ++ gnu/usr.bin/groff/grodvi/grodvi.1 | 154 + gnu/usr.bin/groff/groff/Makefile | 12 + gnu/usr.bin/groff/groff/Makefile.dep | 4 + gnu/usr.bin/groff/groff/groff.1 | 362 + gnu/usr.bin/groff/groff/groff.cc | 590 + gnu/usr.bin/groff/groff/pipeline.c | 240 + gnu/usr.bin/groff/groff/pipeline.h | 30 + gnu/usr.bin/groff/grog/Makefile | 8 + gnu/usr.bin/groff/grog/grog.1 | 54 + gnu/usr.bin/groff/grog/grog.pl | 149 + gnu/usr.bin/groff/grog/grog.sh | 78 + gnu/usr.bin/groff/grops/Makefile | 12 + gnu/usr.bin/groff/grops/Makefile.dep | 6 + gnu/usr.bin/groff/grops/TODO | 25 + gnu/usr.bin/groff/grops/grops.1 | 797 ++ gnu/usr.bin/groff/grops/ps.cc | 1507 +++ gnu/usr.bin/groff/grops/ps.h | 122 + gnu/usr.bin/groff/grops/psfig.diff | 106 + gnu/usr.bin/groff/grops/psrm.cc | 1091 ++ gnu/usr.bin/groff/grotty/Makefile | 12 + gnu/usr.bin/groff/grotty/Makefile.dep | 2 + gnu/usr.bin/groff/grotty/TODO | 3 + gnu/usr.bin/groff/grotty/grotty.1 | 204 + gnu/usr.bin/groff/grotty/tty.cc | 439 + gnu/usr.bin/groff/include/assert.h | 41 + gnu/usr.bin/groff/include/cmap.h | 56 + gnu/usr.bin/groff/include/cset.h | 75 + gnu/usr.bin/groff/include/defs.h | 9 + gnu/usr.bin/groff/include/device.h | 21 + gnu/usr.bin/groff/include/driver.h | 36 + gnu/usr.bin/groff/include/errarg.h | 46 + gnu/usr.bin/groff/include/error.h | 58 + gnu/usr.bin/groff/include/font.h | 113 + gnu/usr.bin/groff/include/index.h | 42 + gnu/usr.bin/groff/include/lib.h | 105 + gnu/usr.bin/groff/include/macropath.h | 21 + gnu/usr.bin/groff/include/posix.h | 49 + gnu/usr.bin/groff/include/printer.h | 66 + gnu/usr.bin/groff/include/ptable.h | 166 + gnu/usr.bin/groff/include/refid.h | 35 + gnu/usr.bin/groff/include/search.h | 96 + gnu/usr.bin/groff/include/searchpath.h | 29 + gnu/usr.bin/groff/include/stringclass.h | 174 + gnu/usr.bin/groff/include/unix.h | 0 gnu/usr.bin/groff/indxbib/Makefile | 20 + gnu/usr.bin/groff/indxbib/Makefile.dep | 5 + gnu/usr.bin/groff/indxbib/dirnamemax.c | 49 + gnu/usr.bin/groff/indxbib/eign | 133 + gnu/usr.bin/groff/indxbib/indxbib.1 | 187 + gnu/usr.bin/groff/indxbib/indxbib.cc | 742 + gnu/usr.bin/groff/indxbib/signal.c | 63 + gnu/usr.bin/groff/libbib/Makefile | 14 + gnu/usr.bin/groff/libbib/Makefile.dep | 12 + gnu/usr.bin/groff/libbib/common.cc | 38 + gnu/usr.bin/groff/libbib/index.cc | 614 + gnu/usr.bin/groff/libbib/linear.cc | 484 + gnu/usr.bin/groff/libbib/map.c | 75 + gnu/usr.bin/groff/libbib/search.cc | 130 + gnu/usr.bin/groff/libdriver/Makefile | 14 + gnu/usr.bin/groff/libdriver/Makefile.dep | 6 + gnu/usr.bin/groff/libdriver/input.cc | 473 + gnu/usr.bin/groff/libdriver/printer.cc | 240 + gnu/usr.bin/groff/libgroff/Makefile | 24 + gnu/usr.bin/groff/libgroff/Makefile.dep | 39 + gnu/usr.bin/groff/libgroff/assert.cc | 39 + gnu/usr.bin/groff/libgroff/change_lf.cc | 39 + gnu/usr.bin/groff/libgroff/cmap.cc | 55 + gnu/usr.bin/groff/libgroff/cset.cc | 101 + gnu/usr.bin/groff/libgroff/device.cc | 38 + gnu/usr.bin/groff/libgroff/errarg.cc | 120 + gnu/usr.bin/groff/libgroff/error.cc | 139 + gnu/usr.bin/groff/libgroff/fatal.cc | 29 + gnu/usr.bin/groff/libgroff/filename.cc | 1 + gnu/usr.bin/groff/libgroff/fmod.c | 28 + gnu/usr.bin/groff/libgroff/font.cc | 907 ++ gnu/usr.bin/groff/libgroff/fontfile.cc | 64 + gnu/usr.bin/groff/libgroff/getcwd.c | 38 + gnu/usr.bin/groff/libgroff/iftoa.c | 65 + gnu/usr.bin/groff/libgroff/illegal.cc | 22 + gnu/usr.bin/groff/libgroff/itoa.c | 43 + gnu/usr.bin/groff/libgroff/lf.cc | 63 + gnu/usr.bin/groff/libgroff/lineno.cc | 1 + gnu/usr.bin/groff/libgroff/macropath.cc | 28 + gnu/usr.bin/groff/libgroff/matherr.c | 45 + gnu/usr.bin/groff/libgroff/nametoindex.cc | 117 + gnu/usr.bin/groff/libgroff/new.cc | 67 + gnu/usr.bin/groff/libgroff/prime.cc | 28 + gnu/usr.bin/groff/libgroff/progname.cc | 1 + gnu/usr.bin/groff/libgroff/ptable.cc | 51 + gnu/usr.bin/groff/libgroff/putenv.c | 96 + gnu/usr.bin/groff/libgroff/searchpath.cc | 117 + gnu/usr.bin/groff/libgroff/strerror.c | 37 + gnu/usr.bin/groff/libgroff/string.cc | 310 + gnu/usr.bin/groff/libgroff/strsave.cc | 33 + gnu/usr.bin/groff/libgroff/strtol.c | 120 + gnu/usr.bin/groff/libgroff/tmpfile.cc | 99 + gnu/usr.bin/groff/lkbib/Makefile | 12 + gnu/usr.bin/groff/lkbib/Makefile.dep | 2 + gnu/usr.bin/groff/lkbib/lkbib.1 | 90 + gnu/usr.bin/groff/lkbib/lkbib.cc | 122 + gnu/usr.bin/groff/lookbib/Makefile | 12 + gnu/usr.bin/groff/lookbib/Makefile.dep | 2 + gnu/usr.bin/groff/lookbib/lookbib.1 | 58 + gnu/usr.bin/groff/lookbib/lookbib.cc | 127 + gnu/usr.bin/groff/man/Makefile | 7 + gnu/usr.bin/groff/man/groff_char.7 | 545 + gnu/usr.bin/groff/man/groff_font.5 | 351 + gnu/usr.bin/groff/man/groff_out.5 | 215 + gnu/usr.bin/groff/mm/ChangeLog | 252 + gnu/usr.bin/groff/mm/Makefile | 34 + gnu/usr.bin/groff/mm/NOTES | 101 + gnu/usr.bin/groff/mm/README | 26 + gnu/usr.bin/groff/mm/groff_mm.7 | 738 + gnu/usr.bin/groff/mm/groff_mmse.7 | 36 + gnu/usr.bin/groff/mm/mm/0.MT | 143 + gnu/usr.bin/groff/mm/mm/4.MT | 65 + gnu/usr.bin/groff/mm/mm/5.MT | 33 + gnu/usr.bin/groff/mm/mm/ms.cov | 82 + gnu/usr.bin/groff/mm/mm/se_ms.cov | 2 + gnu/usr.bin/groff/mm/tmac.m | 2582 ++++ gnu/usr.bin/groff/mm/tmac.mse | 42 + gnu/usr.bin/groff/nroff/Makefile | 11 + gnu/usr.bin/groff/nroff/nroff.1 | 58 + gnu/usr.bin/groff/nroff/nroff.sh | 52 + gnu/usr.bin/groff/nroff/psroff.sh | 2 + gnu/usr.bin/groff/pfbtops/Makefile | 11 + gnu/usr.bin/groff/pfbtops/Makefile.dep | 1 + gnu/usr.bin/groff/pfbtops/pfbtops.1 | 27 + gnu/usr.bin/groff/pfbtops/pfbtops.c | 112 + gnu/usr.bin/groff/pic/Makefile | 15 + gnu/usr.bin/groff/pic/Makefile.dep | 22 + gnu/usr.bin/groff/pic/TODO | 37 + gnu/usr.bin/groff/pic/common.cc | 495 + gnu/usr.bin/groff/pic/common.h | 70 + gnu/usr.bin/groff/pic/depend | 21 + gnu/usr.bin/groff/pic/lex.cc | 1938 +++ gnu/usr.bin/groff/pic/main.cc | 611 + gnu/usr.bin/groff/pic/object.cc | 1815 +++ gnu/usr.bin/groff/pic/object.h | 215 + gnu/usr.bin/groff/pic/output.h | 79 + gnu/usr.bin/groff/pic/pic.1 | 730 + gnu/usr.bin/groff/pic/pic.h | 101 + gnu/usr.bin/groff/pic/pic.y | 1780 +++ gnu/usr.bin/groff/pic/position.h | 47 + gnu/usr.bin/groff/pic/tex.cc | 411 + gnu/usr.bin/groff/pic/text.h | 28 + gnu/usr.bin/groff/pic/troff.cc | 499 + gnu/usr.bin/groff/psbb/Makefile | 9 + gnu/usr.bin/groff/psbb/Makefile.dep | 1 + gnu/usr.bin/groff/psbb/psbb.1 | 26 + gnu/usr.bin/groff/psbb/psbb.c | 169 + gnu/usr.bin/groff/refer/Makefile | 15 + gnu/usr.bin/groff/refer/Makefile.dep | 17 + gnu/usr.bin/groff/refer/command.cc | 807 ++ gnu/usr.bin/groff/refer/command.h | 36 + gnu/usr.bin/groff/refer/label.y | 1173 ++ gnu/usr.bin/groff/refer/ref.cc | 1144 ++ gnu/usr.bin/groff/refer/ref.h | 120 + gnu/usr.bin/groff/refer/refer.1 | 1282 ++ gnu/usr.bin/groff/refer/refer.cc | 1221 ++ gnu/usr.bin/groff/refer/refer.h | 78 + gnu/usr.bin/groff/refer/token.cc | 370 + gnu/usr.bin/groff/refer/token.h | 81 + gnu/usr.bin/groff/soelim/Makefile | 12 + gnu/usr.bin/groff/soelim/Makefile.dep | 2 + gnu/usr.bin/groff/soelim/soelim.1 | 42 + gnu/usr.bin/groff/soelim/soelim.cc | 278 + gnu/usr.bin/groff/tbl/Makefile | 12 + gnu/usr.bin/groff/tbl/Makefile.dep | 6 + gnu/usr.bin/groff/tbl/main.cc | 1497 ++ gnu/usr.bin/groff/tbl/table.cc | 2764 ++++ gnu/usr.bin/groff/tbl/table.h | 151 + gnu/usr.bin/groff/tbl/tbl.1 | 143 + gnu/usr.bin/groff/tfmtodit/Makefile | 12 + gnu/usr.bin/groff/tfmtodit/Makefile.dep | 2 + gnu/usr.bin/groff/tfmtodit/tfmtodit.1 | 150 + gnu/usr.bin/groff/tfmtodit/tfmtodit.cc | 850 ++ gnu/usr.bin/groff/tmac/Makefile | 26 + gnu/usr.bin/groff/tmac/TODO | 38 + gnu/usr.bin/groff/tmac/eqnrc | 60 + gnu/usr.bin/groff/tmac/groff_ms.7 | 210 + gnu/usr.bin/groff/tmac/man.local | 0 gnu/usr.bin/groff/tmac/tmac.X | 45 + gnu/usr.bin/groff/tmac/tmac.Xps | 44 + gnu/usr.bin/groff/tmac/tmac.an | 326 + gnu/usr.bin/groff/tmac/tmac.dvi | 132 + gnu/usr.bin/groff/tmac/tmac.latin1 | 101 + gnu/usr.bin/groff/tmac/tmac.pic | 10 + gnu/usr.bin/groff/tmac/tmac.ps | 52 + gnu/usr.bin/groff/tmac/tmac.psatk | 61 + gnu/usr.bin/groff/tmac/tmac.psfig | 87 + gnu/usr.bin/groff/tmac/tmac.psnew | 26 + gnu/usr.bin/groff/tmac/tmac.psold | 60 + gnu/usr.bin/groff/tmac/tmac.pspic | 41 + gnu/usr.bin/groff/tmac/tmac.s | 1803 +++ gnu/usr.bin/groff/tmac/tmac.tty | 48 + gnu/usr.bin/groff/tmac/tmac.tty-char | 196 + gnu/usr.bin/groff/tmac/troffrc | 24 + gnu/usr.bin/groff/troff/Makefile | 37 + gnu/usr.bin/groff/troff/Makefile.dep | 34 + gnu/usr.bin/groff/troff/TODO | 132 + gnu/usr.bin/groff/troff/charinfo.h | 165 + gnu/usr.bin/groff/troff/column.cc | 732 + gnu/usr.bin/groff/troff/dictionary.cc | 211 + gnu/usr.bin/groff/troff/dictionary.h | 92 + gnu/usr.bin/groff/troff/div.cc | 1124 ++ gnu/usr.bin/groff/troff/div.h | 146 + gnu/usr.bin/groff/troff/env.cc | 3052 +++++ gnu/usr.bin/groff/troff/env.h | 327 + gnu/usr.bin/groff/troff/hvunits.h | 340 + gnu/usr.bin/groff/troff/hyphen.us | 4449 ++++++ gnu/usr.bin/groff/troff/input.cc | 5824 ++++++++ gnu/usr.bin/groff/troff/node.cc | 4845 +++++++ gnu/usr.bin/groff/troff/node.h | 493 + gnu/usr.bin/groff/troff/number.cc | 669 + gnu/usr.bin/groff/troff/reg.cc | 458 + gnu/usr.bin/groff/troff/reg.h | 73 + gnu/usr.bin/groff/troff/request.h | 80 + gnu/usr.bin/groff/troff/symbol.cc | 144 + gnu/usr.bin/groff/troff/symbol.h | 73 + gnu/usr.bin/groff/troff/token.h | 197 + gnu/usr.bin/groff/troff/troff.1 | 2004 +++ gnu/usr.bin/groff/troff/troff.h | 88 + gnu/usr.bin/groff/xditview/ChangeLog | 259 + gnu/usr.bin/groff/xditview/DESC | 9 + gnu/usr.bin/groff/xditview/Dvi.c | 544 + gnu/usr.bin/groff/xditview/Dvi.h | 46 + gnu/usr.bin/groff/xditview/DviChar.c | 664 + gnu/usr.bin/groff/xditview/DviChar.h | 37 + gnu/usr.bin/groff/xditview/DviP.h | 233 + gnu/usr.bin/groff/xditview/FontMap | 17 + gnu/usr.bin/groff/xditview/GXditview.ad | 57 + gnu/usr.bin/groff/xditview/INSTALL | 20 + gnu/usr.bin/groff/xditview/Imakefile | 52 + gnu/usr.bin/groff/xditview/Makefile | 17 + gnu/usr.bin/groff/xditview/Menu.h | 46 + gnu/usr.bin/groff/xditview/README | 14 + gnu/usr.bin/groff/xditview/TODO | 15 + gnu/usr.bin/groff/xditview/XFontName.c | 256 + gnu/usr.bin/groff/xditview/XFontName.h | 45 + gnu/usr.bin/groff/xditview/device.c | 581 + gnu/usr.bin/groff/xditview/device.h | 21 + gnu/usr.bin/groff/xditview/draw.c | 721 + gnu/usr.bin/groff/xditview/font.c | 471 + gnu/usr.bin/groff/xditview/gxditview.1 | 217 + gnu/usr.bin/groff/xditview/lex.c | 103 + gnu/usr.bin/groff/xditview/page.c | 88 + gnu/usr.bin/groff/xditview/parse.c | 334 + gnu/usr.bin/groff/xditview/xdit.bm | 14 + gnu/usr.bin/groff/xditview/xdit_mask.bm | 14 + gnu/usr.bin/groff/xditview/xditview.c | 587 + gnu/usr.bin/groff/xditview/xtotroff.c | 303 + gnu/usr.bin/rcs/Makefile | 3 + gnu/usr.bin/rcs/Makefile.inc | 3 + gnu/usr.bin/rcs/ci/Makefile | 7 + gnu/usr.bin/rcs/ci/ci.1 | 772 ++ gnu/usr.bin/rcs/ci/ci.c | 1165 ++ gnu/usr.bin/rcs/co/Makefile | 7 + gnu/usr.bin/rcs/co/co.1 | 569 + gnu/usr.bin/rcs/co/co.c | 769 ++ gnu/usr.bin/rcs/doc/rcs.ms | 1524 +++ gnu/usr.bin/rcs/doc/rcs_func.ms | 95 + gnu/usr.bin/rcs/ident/Makefile | 7 + gnu/usr.bin/rcs/ident/ident.1 | 76 + gnu/usr.bin/rcs/ident/ident.c | 214 + gnu/usr.bin/rcs/lib/Makefile | 5 + gnu/usr.bin/rcs/lib/conf.h | 495 + gnu/usr.bin/rcs/lib/maketime.c | 344 + gnu/usr.bin/rcs/lib/merger.c | 139 + gnu/usr.bin/rcs/lib/partime.c | 639 + gnu/usr.bin/rcs/lib/rcsbase.h | 677 + gnu/usr.bin/rcs/lib/rcsedit.c | 1656 +++ gnu/usr.bin/rcs/lib/rcsfcmp.c | 321 + gnu/usr.bin/rcs/lib/rcsfnms.c | 1088 ++ gnu/usr.bin/rcs/lib/rcsgen.c | 432 + gnu/usr.bin/rcs/lib/rcskeep.c | 422 + gnu/usr.bin/rcs/lib/rcskeys.c | 102 + gnu/usr.bin/rcs/lib/rcslex.c | 1241 ++ gnu/usr.bin/rcs/lib/rcsmap.c | 68 + gnu/usr.bin/rcs/lib/rcsrev.c | 790 ++ gnu/usr.bin/rcs/lib/rcssyn.c | 857 ++ gnu/usr.bin/rcs/lib/rcsutil.c | 994 ++ gnu/usr.bin/rcs/merge/Makefile | 7 + gnu/usr.bin/rcs/merge/merge.1 | 102 + gnu/usr.bin/rcs/merge/merge.c | 97 + gnu/usr.bin/rcs/rcs/Makefile | 10 + gnu/usr.bin/rcs/rcs/rcs.1 | 397 + gnu/usr.bin/rcs/rcs/rcs.c | 1554 +++ gnu/usr.bin/rcs/rcs/rcsfile.5 | 224 + gnu/usr.bin/rcs/rcs/rcsintro.1 | 292 + gnu/usr.bin/rcs/rcsclean/Makefile | 7 + gnu/usr.bin/rcs/rcsclean/rcsclean | Bin 0 -> 101972 bytes gnu/usr.bin/rcs/rcsclean/rcsclean.0 | 132 + gnu/usr.bin/rcs/rcsclean/rcsclean.1 | 177 + gnu/usr.bin/rcs/rcsclean/rcsclean.c | 297 + gnu/usr.bin/rcs/rcsdiff/Makefile | 7 + gnu/usr.bin/rcs/rcsdiff/rcsdiff.1 | 152 + gnu/usr.bin/rcs/rcsdiff/rcsdiff.c | 422 + gnu/usr.bin/rcs/rcsfreeze/Makefile | 7 + gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1 | 68 + gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh | 100 + gnu/usr.bin/rcs/rcsmerge/Makefile | 7 + gnu/usr.bin/rcs/rcsmerge/rcsmerge.1 | 140 + gnu/usr.bin/rcs/rcsmerge/rcsmerge.c | 252 + gnu/usr.bin/rcs/rcstest | 397 + gnu/usr.bin/rcs/rlog/Makefile | 7 + gnu/usr.bin/rcs/rlog/rlog.1 | 260 + gnu/usr.bin/rcs/rlog/rlog.c | 1204 ++ gnu/usr.bin/tar/COPYING | 339 + gnu/usr.bin/tar/ChangeLog | 1732 +++ gnu/usr.bin/tar/Makefile | 14 + gnu/usr.bin/tar/Makefile.gnu | 185 + gnu/usr.bin/tar/README | 40 + gnu/usr.bin/tar/buffer.c | 1584 +++ gnu/usr.bin/tar/create.c | 1454 ++ gnu/usr.bin/tar/diffarch.c | 759 ++ gnu/usr.bin/tar/extract.c | 907 ++ gnu/usr.bin/tar/fnmatch.c | 173 + gnu/usr.bin/tar/fnmatch.h | 62 + gnu/usr.bin/tar/getdate.y | 969 ++ gnu/usr.bin/tar/getoldopt.c | 96 + gnu/usr.bin/tar/getopt.c | 712 + gnu/usr.bin/tar/getopt.h | 125 + gnu/usr.bin/tar/getopt1.c | 161 + gnu/usr.bin/tar/getpagesize.h | 38 + gnu/usr.bin/tar/gnu.c | 677 + gnu/usr.bin/tar/list.c | 881 ++ gnu/usr.bin/tar/mangle.c | 270 + gnu/usr.bin/tar/msd_dir.h | 44 + gnu/usr.bin/tar/names.c | 149 + gnu/usr.bin/tar/open3.h | 67 + gnu/usr.bin/tar/pathmax.h | 53 + gnu/usr.bin/tar/port.c | 1256 ++ gnu/usr.bin/tar/port.h | 215 + gnu/usr.bin/tar/regex.c | 4932 +++++++ gnu/usr.bin/tar/regex.h | 490 + gnu/usr.bin/tar/rmt.h | 98 + gnu/usr.bin/tar/rtapelib.c | 582 + gnu/usr.bin/tar/tar.c | 1504 +++ gnu/usr.bin/tar/tar.h | 291 + gnu/usr.bin/tar/update.c | 585 + gnu/usr.bin/tar/version.c | 1 + gnu/usr.bin/tar/y.tab.h | 18 + 597 files changed, 215290 insertions(+) create mode 100644 gnu/COPYING create mode 100644 gnu/Makefile create mode 100644 gnu/usr.bin/awk/ACKNOWLEDGMENT create mode 100644 gnu/usr.bin/awk/COPYING create mode 100644 gnu/usr.bin/awk/FUTURES create mode 100644 gnu/usr.bin/awk/LIMITATIONS create mode 100644 gnu/usr.bin/awk/Makefile create mode 100644 gnu/usr.bin/awk/NEWS create mode 100644 gnu/usr.bin/awk/PORTS create mode 100644 gnu/usr.bin/awk/POSIX create mode 100644 gnu/usr.bin/awk/PROBLEMS create mode 100644 gnu/usr.bin/awk/README create mode 100644 gnu/usr.bin/awk/array.c create mode 100644 gnu/usr.bin/awk/awk.1 create mode 100644 gnu/usr.bin/awk/awk.h create mode 100644 gnu/usr.bin/awk/awk.y create mode 100644 gnu/usr.bin/awk/builtin.c create mode 100644 gnu/usr.bin/awk/config.h create mode 100644 gnu/usr.bin/awk/dfa.c create mode 100644 gnu/usr.bin/awk/dfa.h create mode 100644 gnu/usr.bin/awk/eval.c create mode 100644 gnu/usr.bin/awk/field.c create mode 100644 gnu/usr.bin/awk/gawk.texi create mode 100644 gnu/usr.bin/awk/getopt.c create mode 100644 gnu/usr.bin/awk/getopt.h create mode 100644 gnu/usr.bin/awk/getopt1.c create mode 100644 gnu/usr.bin/awk/io.c create mode 100644 gnu/usr.bin/awk/iop.c create mode 100644 gnu/usr.bin/awk/main.c create mode 100644 gnu/usr.bin/awk/msg.c create mode 100644 gnu/usr.bin/awk/node.c create mode 100644 gnu/usr.bin/awk/patchlevel.h create mode 100644 gnu/usr.bin/awk/protos.h create mode 100644 gnu/usr.bin/awk/re.c create mode 100644 gnu/usr.bin/awk/regex.c create mode 100644 gnu/usr.bin/awk/regex.h create mode 100644 gnu/usr.bin/awk/version.c create mode 100644 gnu/usr.bin/groff/BUG-REPORT create mode 100644 gnu/usr.bin/groff/COPYING create mode 100644 gnu/usr.bin/groff/ChangeLog create mode 100644 gnu/usr.bin/groff/Makefile create mode 100644 gnu/usr.bin/groff/Makefile.cfg create mode 100644 gnu/usr.bin/groff/NEWS create mode 100644 gnu/usr.bin/groff/PROBLEMS create mode 100644 gnu/usr.bin/groff/PROJECTS create mode 100644 gnu/usr.bin/groff/README.gnu create mode 100644 gnu/usr.bin/groff/TODO create mode 100644 gnu/usr.bin/groff/VERSION create mode 100644 gnu/usr.bin/groff/addftinfo/Makefile create mode 100644 gnu/usr.bin/groff/addftinfo/Makefile.dep create mode 100644 gnu/usr.bin/groff/addftinfo/addftinfo.1 create mode 100644 gnu/usr.bin/groff/addftinfo/addftinfo.cc create mode 100644 gnu/usr.bin/groff/addftinfo/guess.cc create mode 100644 gnu/usr.bin/groff/addftinfo/guess.h create mode 100644 gnu/usr.bin/groff/afmtodit/Makefile create mode 100644 gnu/usr.bin/groff/afmtodit/afmtodit.1 create mode 100644 gnu/usr.bin/groff/afmtodit/afmtodit.pl create mode 100644 gnu/usr.bin/groff/devices/Makefile create mode 100644 gnu/usr.bin/groff/devices/Makefile.dev create mode 100644 gnu/usr.bin/groff/devices/Makefile.tty create mode 100644 gnu/usr.bin/groff/devices/devX100-12/CB create mode 100644 gnu/usr.bin/groff/devices/devX100-12/CBI create mode 100644 gnu/usr.bin/groff/devices/devX100-12/CI create mode 100644 gnu/usr.bin/groff/devices/devX100-12/CR create mode 100644 gnu/usr.bin/groff/devices/devX100-12/DESC create mode 100644 gnu/usr.bin/groff/devices/devX100-12/HB create mode 100644 gnu/usr.bin/groff/devices/devX100-12/HBI create mode 100644 gnu/usr.bin/groff/devices/devX100-12/HI create mode 100644 gnu/usr.bin/groff/devices/devX100-12/HR create mode 100644 gnu/usr.bin/groff/devices/devX100-12/Makefile create mode 100644 gnu/usr.bin/groff/devices/devX100-12/NB create mode 100644 gnu/usr.bin/groff/devices/devX100-12/NBI create mode 100644 gnu/usr.bin/groff/devices/devX100-12/NI create mode 100644 gnu/usr.bin/groff/devices/devX100-12/NR create mode 100644 gnu/usr.bin/groff/devices/devX100-12/S create mode 100644 gnu/usr.bin/groff/devices/devX100-12/TB create mode 100644 gnu/usr.bin/groff/devices/devX100-12/TBI create mode 100644 gnu/usr.bin/groff/devices/devX100-12/TI create mode 100644 gnu/usr.bin/groff/devices/devX100-12/TR create mode 100644 gnu/usr.bin/groff/devices/devX100/CB create mode 100644 gnu/usr.bin/groff/devices/devX100/CBI create mode 100644 gnu/usr.bin/groff/devices/devX100/CI create mode 100644 gnu/usr.bin/groff/devices/devX100/CR create mode 100644 gnu/usr.bin/groff/devices/devX100/DESC create mode 100644 gnu/usr.bin/groff/devices/devX100/HB create mode 100644 gnu/usr.bin/groff/devices/devX100/HBI create mode 100644 gnu/usr.bin/groff/devices/devX100/HI create mode 100644 gnu/usr.bin/groff/devices/devX100/HR create mode 100644 gnu/usr.bin/groff/devices/devX100/Makefile create mode 100644 gnu/usr.bin/groff/devices/devX100/NB create mode 100644 gnu/usr.bin/groff/devices/devX100/NBI create mode 100644 gnu/usr.bin/groff/devices/devX100/NI create mode 100644 gnu/usr.bin/groff/devices/devX100/NR create mode 100644 gnu/usr.bin/groff/devices/devX100/S create mode 100644 gnu/usr.bin/groff/devices/devX100/TB create mode 100644 gnu/usr.bin/groff/devices/devX100/TBI create mode 100644 gnu/usr.bin/groff/devices/devX100/TI create mode 100644 gnu/usr.bin/groff/devices/devX100/TR create mode 100644 gnu/usr.bin/groff/devices/devX75-12/CB create mode 100644 gnu/usr.bin/groff/devices/devX75-12/CBI create mode 100644 gnu/usr.bin/groff/devices/devX75-12/CI create mode 100644 gnu/usr.bin/groff/devices/devX75-12/CR create mode 100644 gnu/usr.bin/groff/devices/devX75-12/DESC create mode 100644 gnu/usr.bin/groff/devices/devX75-12/HB create mode 100644 gnu/usr.bin/groff/devices/devX75-12/HBI create mode 100644 gnu/usr.bin/groff/devices/devX75-12/HI create mode 100644 gnu/usr.bin/groff/devices/devX75-12/HR create mode 100644 gnu/usr.bin/groff/devices/devX75-12/Makefile create mode 100644 gnu/usr.bin/groff/devices/devX75-12/NB create mode 100644 gnu/usr.bin/groff/devices/devX75-12/NBI create mode 100644 gnu/usr.bin/groff/devices/devX75-12/NI create mode 100644 gnu/usr.bin/groff/devices/devX75-12/NR create mode 100644 gnu/usr.bin/groff/devices/devX75-12/S create mode 100644 gnu/usr.bin/groff/devices/devX75-12/TB create mode 100644 gnu/usr.bin/groff/devices/devX75-12/TBI create mode 100644 gnu/usr.bin/groff/devices/devX75-12/TI create mode 100644 gnu/usr.bin/groff/devices/devX75-12/TR create mode 100644 gnu/usr.bin/groff/devices/devX75/CB create mode 100644 gnu/usr.bin/groff/devices/devX75/CBI create mode 100644 gnu/usr.bin/groff/devices/devX75/CI create mode 100644 gnu/usr.bin/groff/devices/devX75/CR create mode 100644 gnu/usr.bin/groff/devices/devX75/DESC create mode 100644 gnu/usr.bin/groff/devices/devX75/HB create mode 100644 gnu/usr.bin/groff/devices/devX75/HBI create mode 100644 gnu/usr.bin/groff/devices/devX75/HI create mode 100644 gnu/usr.bin/groff/devices/devX75/HR create mode 100644 gnu/usr.bin/groff/devices/devX75/Makefile create mode 100644 gnu/usr.bin/groff/devices/devX75/NB create mode 100644 gnu/usr.bin/groff/devices/devX75/NBI create mode 100644 gnu/usr.bin/groff/devices/devX75/NI create mode 100644 gnu/usr.bin/groff/devices/devX75/NR create mode 100644 gnu/usr.bin/groff/devices/devX75/S create mode 100644 gnu/usr.bin/groff/devices/devX75/TB create mode 100644 gnu/usr.bin/groff/devices/devX75/TBI create mode 100644 gnu/usr.bin/groff/devices/devX75/TI create mode 100644 gnu/usr.bin/groff/devices/devX75/TR create mode 100644 gnu/usr.bin/groff/devices/devascii/DESC.proto create mode 100644 gnu/usr.bin/groff/devices/devascii/Makefile create mode 100644 gnu/usr.bin/groff/devices/devascii/R.proto create mode 100644 gnu/usr.bin/groff/devices/devdvi/B create mode 100644 gnu/usr.bin/groff/devices/devdvi/BI create mode 100644 gnu/usr.bin/groff/devices/devdvi/CW create mode 100644 gnu/usr.bin/groff/devices/devdvi/DESC create mode 100644 gnu/usr.bin/groff/devices/devdvi/EX create mode 100644 gnu/usr.bin/groff/devices/devdvi/H create mode 100644 gnu/usr.bin/groff/devices/devdvi/HB create mode 100644 gnu/usr.bin/groff/devices/devdvi/HI create mode 100644 gnu/usr.bin/groff/devices/devdvi/I create mode 100644 gnu/usr.bin/groff/devices/devdvi/MI create mode 100644 gnu/usr.bin/groff/devices/devdvi/Makefile create mode 100644 gnu/usr.bin/groff/devices/devdvi/R create mode 100644 gnu/usr.bin/groff/devices/devdvi/S create mode 100644 gnu/usr.bin/groff/devices/devdvi/SA create mode 100644 gnu/usr.bin/groff/devices/devdvi/SB create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/CompileFonts create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/Makefile create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/msam.map create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/msbm.map create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/texb.map create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/texex.map create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/texi.map create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/texmi.map create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/texr.map create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/texsy.map create mode 100644 gnu/usr.bin/groff/devices/devdvi/generate/textt.map create mode 100644 gnu/usr.bin/groff/devices/devlatin1/DESC.proto create mode 100644 gnu/usr.bin/groff/devices/devlatin1/Makefile create mode 100644 gnu/usr.bin/groff/devices/devlatin1/R.proto create mode 100644 gnu/usr.bin/groff/devices/devps/AB create mode 100644 gnu/usr.bin/groff/devices/devps/ABI create mode 100644 gnu/usr.bin/groff/devices/devps/AI create mode 100644 gnu/usr.bin/groff/devices/devps/AR create mode 100644 gnu/usr.bin/groff/devices/devps/BMB create mode 100644 gnu/usr.bin/groff/devices/devps/BMBI create mode 100644 gnu/usr.bin/groff/devices/devps/BMI create mode 100644 gnu/usr.bin/groff/devices/devps/BMR create mode 100644 gnu/usr.bin/groff/devices/devps/CB create mode 100644 gnu/usr.bin/groff/devices/devps/CBI create mode 100644 gnu/usr.bin/groff/devices/devps/CI create mode 100644 gnu/usr.bin/groff/devices/devps/CR create mode 100644 gnu/usr.bin/groff/devices/devps/DESC create mode 100644 gnu/usr.bin/groff/devices/devps/DESC-A4 create mode 100644 gnu/usr.bin/groff/devices/devps/DESC-letter create mode 100644 gnu/usr.bin/groff/devices/devps/HB create mode 100644 gnu/usr.bin/groff/devices/devps/HBI create mode 100644 gnu/usr.bin/groff/devices/devps/HI create mode 100644 gnu/usr.bin/groff/devices/devps/HNB create mode 100644 gnu/usr.bin/groff/devices/devps/HNBI create mode 100644 gnu/usr.bin/groff/devices/devps/HNI create mode 100644 gnu/usr.bin/groff/devices/devps/HNR create mode 100644 gnu/usr.bin/groff/devices/devps/HR create mode 100644 gnu/usr.bin/groff/devices/devps/Makefile create mode 100644 gnu/usr.bin/groff/devices/devps/NB create mode 100644 gnu/usr.bin/groff/devices/devps/NBI create mode 100644 gnu/usr.bin/groff/devices/devps/NI create mode 100644 gnu/usr.bin/groff/devices/devps/NR create mode 100644 gnu/usr.bin/groff/devices/devps/PB create mode 100644 gnu/usr.bin/groff/devices/devps/PBI create mode 100644 gnu/usr.bin/groff/devices/devps/PI create mode 100644 gnu/usr.bin/groff/devices/devps/PR create mode 100644 gnu/usr.bin/groff/devices/devps/S create mode 100644 gnu/usr.bin/groff/devices/devps/SS create mode 100644 gnu/usr.bin/groff/devices/devps/TB create mode 100644 gnu/usr.bin/groff/devices/devps/TBI create mode 100644 gnu/usr.bin/groff/devices/devps/TI create mode 100644 gnu/usr.bin/groff/devices/devps/TR create mode 100644 gnu/usr.bin/groff/devices/devps/ZCMI create mode 100644 gnu/usr.bin/groff/devices/devps/ZD create mode 100644 gnu/usr.bin/groff/devices/devps/ZDR create mode 100644 gnu/usr.bin/groff/devices/devps/download create mode 100644 gnu/usr.bin/groff/devices/devps/generate/Makefile create mode 100644 gnu/usr.bin/groff/devices/devps/generate/afmname create mode 100644 gnu/usr.bin/groff/devices/devps/generate/dingbatsmap create mode 100644 gnu/usr.bin/groff/devices/devps/generate/dingbatsrmap create mode 100644 gnu/usr.bin/groff/devices/devps/generate/lgreekmap create mode 100644 gnu/usr.bin/groff/devices/devps/generate/symbol.sed create mode 100644 gnu/usr.bin/groff/devices/devps/generate/symbolchars create mode 100644 gnu/usr.bin/groff/devices/devps/generate/symbolsl.afm create mode 100644 gnu/usr.bin/groff/devices/devps/generate/textmap create mode 100644 gnu/usr.bin/groff/devices/devps/prologue create mode 100644 gnu/usr.bin/groff/devices/devps/symbol.afm create mode 100644 gnu/usr.bin/groff/devices/devps/symbolsl.pfa create mode 100644 gnu/usr.bin/groff/devices/devps/text.enc create mode 100644 gnu/usr.bin/groff/devices/devps/zapfdr.afm create mode 100644 gnu/usr.bin/groff/devices/devps/zapfdr.pfa create mode 100644 gnu/usr.bin/groff/doc/Makefile create mode 100644 gnu/usr.bin/groff/doc/meintro.me create mode 100644 gnu/usr.bin/groff/doc/meref.me create mode 100644 gnu/usr.bin/groff/eqn/Makefile create mode 100644 gnu/usr.bin/groff/eqn/Makefile.dep create mode 100644 gnu/usr.bin/groff/eqn/TODO create mode 100644 gnu/usr.bin/groff/eqn/box.cc create mode 100644 gnu/usr.bin/groff/eqn/box.h create mode 100644 gnu/usr.bin/groff/eqn/delim.cc create mode 100644 gnu/usr.bin/groff/eqn/eqn.1 create mode 100644 gnu/usr.bin/groff/eqn/eqn.h create mode 100644 gnu/usr.bin/groff/eqn/eqn.y create mode 100644 gnu/usr.bin/groff/eqn/lex.cc create mode 100644 gnu/usr.bin/groff/eqn/limit.cc create mode 100644 gnu/usr.bin/groff/eqn/list.cc create mode 100644 gnu/usr.bin/groff/eqn/main.cc create mode 100644 gnu/usr.bin/groff/eqn/mark.cc create mode 100644 gnu/usr.bin/groff/eqn/neqn.sh create mode 100644 gnu/usr.bin/groff/eqn/other.cc create mode 100644 gnu/usr.bin/groff/eqn/over.cc create mode 100644 gnu/usr.bin/groff/eqn/pbox.h create mode 100644 gnu/usr.bin/groff/eqn/pile.cc create mode 100644 gnu/usr.bin/groff/eqn/script.cc create mode 100644 gnu/usr.bin/groff/eqn/special.cc create mode 100644 gnu/usr.bin/groff/eqn/sqrt.cc create mode 100644 gnu/usr.bin/groff/eqn/text.cc create mode 100644 gnu/usr.bin/groff/grodvi/Makefile create mode 100644 gnu/usr.bin/groff/grodvi/Makefile.dep create mode 100644 gnu/usr.bin/groff/grodvi/dvi.cc create mode 100644 gnu/usr.bin/groff/grodvi/grodvi.1 create mode 100644 gnu/usr.bin/groff/groff/Makefile create mode 100644 gnu/usr.bin/groff/groff/Makefile.dep create mode 100644 gnu/usr.bin/groff/groff/groff.1 create mode 100644 gnu/usr.bin/groff/groff/groff.cc create mode 100644 gnu/usr.bin/groff/groff/pipeline.c create mode 100644 gnu/usr.bin/groff/groff/pipeline.h create mode 100644 gnu/usr.bin/groff/grog/Makefile create mode 100644 gnu/usr.bin/groff/grog/grog.1 create mode 100644 gnu/usr.bin/groff/grog/grog.pl create mode 100644 gnu/usr.bin/groff/grog/grog.sh create mode 100644 gnu/usr.bin/groff/grops/Makefile create mode 100644 gnu/usr.bin/groff/grops/Makefile.dep create mode 100644 gnu/usr.bin/groff/grops/TODO create mode 100644 gnu/usr.bin/groff/grops/grops.1 create mode 100644 gnu/usr.bin/groff/grops/ps.cc create mode 100644 gnu/usr.bin/groff/grops/ps.h create mode 100644 gnu/usr.bin/groff/grops/psfig.diff create mode 100644 gnu/usr.bin/groff/grops/psrm.cc create mode 100644 gnu/usr.bin/groff/grotty/Makefile create mode 100644 gnu/usr.bin/groff/grotty/Makefile.dep create mode 100644 gnu/usr.bin/groff/grotty/TODO create mode 100644 gnu/usr.bin/groff/grotty/grotty.1 create mode 100644 gnu/usr.bin/groff/grotty/tty.cc create mode 100644 gnu/usr.bin/groff/include/assert.h create mode 100644 gnu/usr.bin/groff/include/cmap.h create mode 100644 gnu/usr.bin/groff/include/cset.h create mode 100644 gnu/usr.bin/groff/include/defs.h create mode 100644 gnu/usr.bin/groff/include/device.h create mode 100644 gnu/usr.bin/groff/include/driver.h create mode 100644 gnu/usr.bin/groff/include/errarg.h create mode 100644 gnu/usr.bin/groff/include/error.h create mode 100644 gnu/usr.bin/groff/include/font.h create mode 100644 gnu/usr.bin/groff/include/index.h create mode 100644 gnu/usr.bin/groff/include/lib.h create mode 100644 gnu/usr.bin/groff/include/macropath.h create mode 100644 gnu/usr.bin/groff/include/posix.h create mode 100644 gnu/usr.bin/groff/include/printer.h create mode 100644 gnu/usr.bin/groff/include/ptable.h create mode 100644 gnu/usr.bin/groff/include/refid.h create mode 100644 gnu/usr.bin/groff/include/search.h create mode 100644 gnu/usr.bin/groff/include/searchpath.h create mode 100644 gnu/usr.bin/groff/include/stringclass.h create mode 100644 gnu/usr.bin/groff/include/unix.h create mode 100644 gnu/usr.bin/groff/indxbib/Makefile create mode 100644 gnu/usr.bin/groff/indxbib/Makefile.dep create mode 100644 gnu/usr.bin/groff/indxbib/dirnamemax.c create mode 100644 gnu/usr.bin/groff/indxbib/eign create mode 100644 gnu/usr.bin/groff/indxbib/indxbib.1 create mode 100644 gnu/usr.bin/groff/indxbib/indxbib.cc create mode 100644 gnu/usr.bin/groff/indxbib/signal.c create mode 100644 gnu/usr.bin/groff/libbib/Makefile create mode 100644 gnu/usr.bin/groff/libbib/Makefile.dep create mode 100644 gnu/usr.bin/groff/libbib/common.cc create mode 100644 gnu/usr.bin/groff/libbib/index.cc create mode 100644 gnu/usr.bin/groff/libbib/linear.cc create mode 100644 gnu/usr.bin/groff/libbib/map.c create mode 100644 gnu/usr.bin/groff/libbib/search.cc create mode 100644 gnu/usr.bin/groff/libdriver/Makefile create mode 100644 gnu/usr.bin/groff/libdriver/Makefile.dep create mode 100644 gnu/usr.bin/groff/libdriver/input.cc create mode 100644 gnu/usr.bin/groff/libdriver/printer.cc create mode 100644 gnu/usr.bin/groff/libgroff/Makefile create mode 100644 gnu/usr.bin/groff/libgroff/Makefile.dep create mode 100644 gnu/usr.bin/groff/libgroff/assert.cc create mode 100644 gnu/usr.bin/groff/libgroff/change_lf.cc create mode 100644 gnu/usr.bin/groff/libgroff/cmap.cc create mode 100644 gnu/usr.bin/groff/libgroff/cset.cc create mode 100644 gnu/usr.bin/groff/libgroff/device.cc create mode 100644 gnu/usr.bin/groff/libgroff/errarg.cc create mode 100644 gnu/usr.bin/groff/libgroff/error.cc create mode 100644 gnu/usr.bin/groff/libgroff/fatal.cc create mode 100644 gnu/usr.bin/groff/libgroff/filename.cc create mode 100644 gnu/usr.bin/groff/libgroff/fmod.c create mode 100644 gnu/usr.bin/groff/libgroff/font.cc create mode 100644 gnu/usr.bin/groff/libgroff/fontfile.cc create mode 100644 gnu/usr.bin/groff/libgroff/getcwd.c create mode 100644 gnu/usr.bin/groff/libgroff/iftoa.c create mode 100644 gnu/usr.bin/groff/libgroff/illegal.cc create mode 100644 gnu/usr.bin/groff/libgroff/itoa.c create mode 100644 gnu/usr.bin/groff/libgroff/lf.cc create mode 100644 gnu/usr.bin/groff/libgroff/lineno.cc create mode 100644 gnu/usr.bin/groff/libgroff/macropath.cc create mode 100644 gnu/usr.bin/groff/libgroff/matherr.c create mode 100644 gnu/usr.bin/groff/libgroff/nametoindex.cc create mode 100644 gnu/usr.bin/groff/libgroff/new.cc create mode 100644 gnu/usr.bin/groff/libgroff/prime.cc create mode 100644 gnu/usr.bin/groff/libgroff/progname.cc create mode 100644 gnu/usr.bin/groff/libgroff/ptable.cc create mode 100644 gnu/usr.bin/groff/libgroff/putenv.c create mode 100644 gnu/usr.bin/groff/libgroff/searchpath.cc create mode 100644 gnu/usr.bin/groff/libgroff/strerror.c create mode 100644 gnu/usr.bin/groff/libgroff/string.cc create mode 100644 gnu/usr.bin/groff/libgroff/strsave.cc create mode 100644 gnu/usr.bin/groff/libgroff/strtol.c create mode 100644 gnu/usr.bin/groff/libgroff/tmpfile.cc create mode 100644 gnu/usr.bin/groff/lkbib/Makefile create mode 100644 gnu/usr.bin/groff/lkbib/Makefile.dep create mode 100644 gnu/usr.bin/groff/lkbib/lkbib.1 create mode 100644 gnu/usr.bin/groff/lkbib/lkbib.cc create mode 100644 gnu/usr.bin/groff/lookbib/Makefile create mode 100644 gnu/usr.bin/groff/lookbib/Makefile.dep create mode 100644 gnu/usr.bin/groff/lookbib/lookbib.1 create mode 100644 gnu/usr.bin/groff/lookbib/lookbib.cc create mode 100644 gnu/usr.bin/groff/man/Makefile create mode 100644 gnu/usr.bin/groff/man/groff_char.7 create mode 100644 gnu/usr.bin/groff/man/groff_font.5 create mode 100644 gnu/usr.bin/groff/man/groff_out.5 create mode 100644 gnu/usr.bin/groff/mm/ChangeLog create mode 100644 gnu/usr.bin/groff/mm/Makefile create mode 100644 gnu/usr.bin/groff/mm/NOTES create mode 100644 gnu/usr.bin/groff/mm/README create mode 100644 gnu/usr.bin/groff/mm/groff_mm.7 create mode 100644 gnu/usr.bin/groff/mm/groff_mmse.7 create mode 100644 gnu/usr.bin/groff/mm/mm/0.MT create mode 100644 gnu/usr.bin/groff/mm/mm/4.MT create mode 100644 gnu/usr.bin/groff/mm/mm/5.MT create mode 100644 gnu/usr.bin/groff/mm/mm/ms.cov create mode 100644 gnu/usr.bin/groff/mm/mm/se_ms.cov create mode 100644 gnu/usr.bin/groff/mm/tmac.m create mode 100644 gnu/usr.bin/groff/mm/tmac.mse create mode 100644 gnu/usr.bin/groff/nroff/Makefile create mode 100644 gnu/usr.bin/groff/nroff/nroff.1 create mode 100644 gnu/usr.bin/groff/nroff/nroff.sh create mode 100644 gnu/usr.bin/groff/nroff/psroff.sh create mode 100644 gnu/usr.bin/groff/pfbtops/Makefile create mode 100644 gnu/usr.bin/groff/pfbtops/Makefile.dep create mode 100644 gnu/usr.bin/groff/pfbtops/pfbtops.1 create mode 100644 gnu/usr.bin/groff/pfbtops/pfbtops.c create mode 100644 gnu/usr.bin/groff/pic/Makefile create mode 100644 gnu/usr.bin/groff/pic/Makefile.dep create mode 100644 gnu/usr.bin/groff/pic/TODO create mode 100644 gnu/usr.bin/groff/pic/common.cc create mode 100644 gnu/usr.bin/groff/pic/common.h create mode 100644 gnu/usr.bin/groff/pic/depend create mode 100644 gnu/usr.bin/groff/pic/lex.cc create mode 100644 gnu/usr.bin/groff/pic/main.cc create mode 100644 gnu/usr.bin/groff/pic/object.cc create mode 100644 gnu/usr.bin/groff/pic/object.h create mode 100644 gnu/usr.bin/groff/pic/output.h create mode 100644 gnu/usr.bin/groff/pic/pic.1 create mode 100644 gnu/usr.bin/groff/pic/pic.h create mode 100644 gnu/usr.bin/groff/pic/pic.y create mode 100644 gnu/usr.bin/groff/pic/position.h create mode 100644 gnu/usr.bin/groff/pic/tex.cc create mode 100644 gnu/usr.bin/groff/pic/text.h create mode 100644 gnu/usr.bin/groff/pic/troff.cc create mode 100644 gnu/usr.bin/groff/psbb/Makefile create mode 100644 gnu/usr.bin/groff/psbb/Makefile.dep create mode 100644 gnu/usr.bin/groff/psbb/psbb.1 create mode 100644 gnu/usr.bin/groff/psbb/psbb.c create mode 100644 gnu/usr.bin/groff/refer/Makefile create mode 100644 gnu/usr.bin/groff/refer/Makefile.dep create mode 100644 gnu/usr.bin/groff/refer/command.cc create mode 100644 gnu/usr.bin/groff/refer/command.h create mode 100644 gnu/usr.bin/groff/refer/label.y create mode 100644 gnu/usr.bin/groff/refer/ref.cc create mode 100644 gnu/usr.bin/groff/refer/ref.h create mode 100644 gnu/usr.bin/groff/refer/refer.1 create mode 100644 gnu/usr.bin/groff/refer/refer.cc create mode 100644 gnu/usr.bin/groff/refer/refer.h create mode 100644 gnu/usr.bin/groff/refer/token.cc create mode 100644 gnu/usr.bin/groff/refer/token.h create mode 100644 gnu/usr.bin/groff/soelim/Makefile create mode 100644 gnu/usr.bin/groff/soelim/Makefile.dep create mode 100644 gnu/usr.bin/groff/soelim/soelim.1 create mode 100644 gnu/usr.bin/groff/soelim/soelim.cc create mode 100644 gnu/usr.bin/groff/tbl/Makefile create mode 100644 gnu/usr.bin/groff/tbl/Makefile.dep create mode 100644 gnu/usr.bin/groff/tbl/main.cc create mode 100644 gnu/usr.bin/groff/tbl/table.cc create mode 100644 gnu/usr.bin/groff/tbl/table.h create mode 100644 gnu/usr.bin/groff/tbl/tbl.1 create mode 100644 gnu/usr.bin/groff/tfmtodit/Makefile create mode 100644 gnu/usr.bin/groff/tfmtodit/Makefile.dep create mode 100644 gnu/usr.bin/groff/tfmtodit/tfmtodit.1 create mode 100644 gnu/usr.bin/groff/tfmtodit/tfmtodit.cc create mode 100644 gnu/usr.bin/groff/tmac/Makefile create mode 100644 gnu/usr.bin/groff/tmac/TODO create mode 100644 gnu/usr.bin/groff/tmac/eqnrc create mode 100644 gnu/usr.bin/groff/tmac/groff_ms.7 create mode 100644 gnu/usr.bin/groff/tmac/man.local create mode 100644 gnu/usr.bin/groff/tmac/tmac.X create mode 100644 gnu/usr.bin/groff/tmac/tmac.Xps create mode 100644 gnu/usr.bin/groff/tmac/tmac.an create mode 100644 gnu/usr.bin/groff/tmac/tmac.dvi create mode 100644 gnu/usr.bin/groff/tmac/tmac.latin1 create mode 100644 gnu/usr.bin/groff/tmac/tmac.pic create mode 100644 gnu/usr.bin/groff/tmac/tmac.ps create mode 100644 gnu/usr.bin/groff/tmac/tmac.psatk create mode 100644 gnu/usr.bin/groff/tmac/tmac.psfig create mode 100644 gnu/usr.bin/groff/tmac/tmac.psnew create mode 100644 gnu/usr.bin/groff/tmac/tmac.psold create mode 100644 gnu/usr.bin/groff/tmac/tmac.pspic create mode 100644 gnu/usr.bin/groff/tmac/tmac.s create mode 100644 gnu/usr.bin/groff/tmac/tmac.tty create mode 100644 gnu/usr.bin/groff/tmac/tmac.tty-char create mode 100644 gnu/usr.bin/groff/tmac/troffrc create mode 100644 gnu/usr.bin/groff/troff/Makefile create mode 100644 gnu/usr.bin/groff/troff/Makefile.dep create mode 100644 gnu/usr.bin/groff/troff/TODO create mode 100644 gnu/usr.bin/groff/troff/charinfo.h create mode 100644 gnu/usr.bin/groff/troff/column.cc create mode 100644 gnu/usr.bin/groff/troff/dictionary.cc create mode 100644 gnu/usr.bin/groff/troff/dictionary.h create mode 100644 gnu/usr.bin/groff/troff/div.cc create mode 100644 gnu/usr.bin/groff/troff/div.h create mode 100644 gnu/usr.bin/groff/troff/env.cc create mode 100644 gnu/usr.bin/groff/troff/env.h create mode 100644 gnu/usr.bin/groff/troff/hvunits.h create mode 100644 gnu/usr.bin/groff/troff/hyphen.us create mode 100644 gnu/usr.bin/groff/troff/input.cc create mode 100644 gnu/usr.bin/groff/troff/node.cc create mode 100644 gnu/usr.bin/groff/troff/node.h create mode 100644 gnu/usr.bin/groff/troff/number.cc create mode 100644 gnu/usr.bin/groff/troff/reg.cc create mode 100644 gnu/usr.bin/groff/troff/reg.h create mode 100644 gnu/usr.bin/groff/troff/request.h create mode 100644 gnu/usr.bin/groff/troff/symbol.cc create mode 100644 gnu/usr.bin/groff/troff/symbol.h create mode 100644 gnu/usr.bin/groff/troff/token.h create mode 100644 gnu/usr.bin/groff/troff/troff.1 create mode 100644 gnu/usr.bin/groff/troff/troff.h create mode 100644 gnu/usr.bin/groff/xditview/ChangeLog create mode 100644 gnu/usr.bin/groff/xditview/DESC create mode 100644 gnu/usr.bin/groff/xditview/Dvi.c create mode 100644 gnu/usr.bin/groff/xditview/Dvi.h create mode 100644 gnu/usr.bin/groff/xditview/DviChar.c create mode 100644 gnu/usr.bin/groff/xditview/DviChar.h create mode 100644 gnu/usr.bin/groff/xditview/DviP.h create mode 100644 gnu/usr.bin/groff/xditview/FontMap create mode 100644 gnu/usr.bin/groff/xditview/GXditview.ad create mode 100644 gnu/usr.bin/groff/xditview/INSTALL create mode 100644 gnu/usr.bin/groff/xditview/Imakefile create mode 100644 gnu/usr.bin/groff/xditview/Makefile create mode 100644 gnu/usr.bin/groff/xditview/Menu.h create mode 100644 gnu/usr.bin/groff/xditview/README create mode 100644 gnu/usr.bin/groff/xditview/TODO create mode 100644 gnu/usr.bin/groff/xditview/XFontName.c create mode 100644 gnu/usr.bin/groff/xditview/XFontName.h create mode 100644 gnu/usr.bin/groff/xditview/device.c create mode 100644 gnu/usr.bin/groff/xditview/device.h create mode 100644 gnu/usr.bin/groff/xditview/draw.c create mode 100644 gnu/usr.bin/groff/xditview/font.c create mode 100644 gnu/usr.bin/groff/xditview/gxditview.1 create mode 100644 gnu/usr.bin/groff/xditview/lex.c create mode 100644 gnu/usr.bin/groff/xditview/page.c create mode 100644 gnu/usr.bin/groff/xditview/parse.c create mode 100644 gnu/usr.bin/groff/xditview/xdit.bm create mode 100644 gnu/usr.bin/groff/xditview/xdit_mask.bm create mode 100644 gnu/usr.bin/groff/xditview/xditview.c create mode 100644 gnu/usr.bin/groff/xditview/xtotroff.c create mode 100644 gnu/usr.bin/rcs/Makefile create mode 100644 gnu/usr.bin/rcs/Makefile.inc create mode 100644 gnu/usr.bin/rcs/ci/Makefile create mode 100644 gnu/usr.bin/rcs/ci/ci.1 create mode 100644 gnu/usr.bin/rcs/ci/ci.c create mode 100644 gnu/usr.bin/rcs/co/Makefile create mode 100644 gnu/usr.bin/rcs/co/co.1 create mode 100644 gnu/usr.bin/rcs/co/co.c create mode 100644 gnu/usr.bin/rcs/doc/rcs.ms create mode 100644 gnu/usr.bin/rcs/doc/rcs_func.ms create mode 100644 gnu/usr.bin/rcs/ident/Makefile create mode 100644 gnu/usr.bin/rcs/ident/ident.1 create mode 100644 gnu/usr.bin/rcs/ident/ident.c create mode 100644 gnu/usr.bin/rcs/lib/Makefile create mode 100644 gnu/usr.bin/rcs/lib/conf.h create mode 100644 gnu/usr.bin/rcs/lib/maketime.c create mode 100644 gnu/usr.bin/rcs/lib/merger.c create mode 100644 gnu/usr.bin/rcs/lib/partime.c create mode 100644 gnu/usr.bin/rcs/lib/rcsbase.h create mode 100644 gnu/usr.bin/rcs/lib/rcsedit.c create mode 100644 gnu/usr.bin/rcs/lib/rcsfcmp.c create mode 100644 gnu/usr.bin/rcs/lib/rcsfnms.c create mode 100644 gnu/usr.bin/rcs/lib/rcsgen.c create mode 100644 gnu/usr.bin/rcs/lib/rcskeep.c create mode 100644 gnu/usr.bin/rcs/lib/rcskeys.c create mode 100644 gnu/usr.bin/rcs/lib/rcslex.c create mode 100644 gnu/usr.bin/rcs/lib/rcsmap.c create mode 100644 gnu/usr.bin/rcs/lib/rcsrev.c create mode 100644 gnu/usr.bin/rcs/lib/rcssyn.c create mode 100644 gnu/usr.bin/rcs/lib/rcsutil.c create mode 100644 gnu/usr.bin/rcs/merge/Makefile create mode 100644 gnu/usr.bin/rcs/merge/merge.1 create mode 100644 gnu/usr.bin/rcs/merge/merge.c create mode 100644 gnu/usr.bin/rcs/rcs/Makefile create mode 100644 gnu/usr.bin/rcs/rcs/rcs.1 create mode 100644 gnu/usr.bin/rcs/rcs/rcs.c create mode 100644 gnu/usr.bin/rcs/rcs/rcsfile.5 create mode 100644 gnu/usr.bin/rcs/rcs/rcsintro.1 create mode 100644 gnu/usr.bin/rcs/rcsclean/Makefile create mode 100644 gnu/usr.bin/rcs/rcsclean/rcsclean create mode 100644 gnu/usr.bin/rcs/rcsclean/rcsclean.0 create mode 100644 gnu/usr.bin/rcs/rcsclean/rcsclean.1 create mode 100644 gnu/usr.bin/rcs/rcsclean/rcsclean.c create mode 100644 gnu/usr.bin/rcs/rcsdiff/Makefile create mode 100644 gnu/usr.bin/rcs/rcsdiff/rcsdiff.1 create mode 100644 gnu/usr.bin/rcs/rcsdiff/rcsdiff.c create mode 100644 gnu/usr.bin/rcs/rcsfreeze/Makefile create mode 100644 gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1 create mode 100644 gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh create mode 100644 gnu/usr.bin/rcs/rcsmerge/Makefile create mode 100644 gnu/usr.bin/rcs/rcsmerge/rcsmerge.1 create mode 100644 gnu/usr.bin/rcs/rcsmerge/rcsmerge.c create mode 100644 gnu/usr.bin/rcs/rcstest create mode 100644 gnu/usr.bin/rcs/rlog/Makefile create mode 100644 gnu/usr.bin/rcs/rlog/rlog.1 create mode 100644 gnu/usr.bin/rcs/rlog/rlog.c create mode 100644 gnu/usr.bin/tar/COPYING create mode 100644 gnu/usr.bin/tar/ChangeLog create mode 100644 gnu/usr.bin/tar/Makefile create mode 100644 gnu/usr.bin/tar/Makefile.gnu create mode 100644 gnu/usr.bin/tar/README create mode 100644 gnu/usr.bin/tar/buffer.c create mode 100644 gnu/usr.bin/tar/create.c create mode 100644 gnu/usr.bin/tar/diffarch.c create mode 100644 gnu/usr.bin/tar/extract.c create mode 100644 gnu/usr.bin/tar/fnmatch.c create mode 100644 gnu/usr.bin/tar/fnmatch.h create mode 100644 gnu/usr.bin/tar/getdate.y create mode 100644 gnu/usr.bin/tar/getoldopt.c create mode 100644 gnu/usr.bin/tar/getopt.c create mode 100644 gnu/usr.bin/tar/getopt.h create mode 100644 gnu/usr.bin/tar/getopt1.c create mode 100644 gnu/usr.bin/tar/getpagesize.h create mode 100644 gnu/usr.bin/tar/gnu.c create mode 100644 gnu/usr.bin/tar/list.c create mode 100644 gnu/usr.bin/tar/mangle.c create mode 100644 gnu/usr.bin/tar/msd_dir.h create mode 100644 gnu/usr.bin/tar/names.c create mode 100644 gnu/usr.bin/tar/open3.h create mode 100644 gnu/usr.bin/tar/pathmax.h create mode 100644 gnu/usr.bin/tar/port.c create mode 100644 gnu/usr.bin/tar/port.h create mode 100644 gnu/usr.bin/tar/regex.c create mode 100644 gnu/usr.bin/tar/regex.h create mode 100644 gnu/usr.bin/tar/rmt.h create mode 100644 gnu/usr.bin/tar/rtapelib.c create mode 100644 gnu/usr.bin/tar/tar.c create mode 100644 gnu/usr.bin/tar/tar.h create mode 100644 gnu/usr.bin/tar/update.c create mode 100644 gnu/usr.bin/tar/version.c create mode 100644 gnu/usr.bin/tar/y.tab.h diff --git a/gnu/COPYING b/gnu/COPYING new file mode 100644 index 0000000000..a43ea2126f --- /dev/null +++ b/gnu/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. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the 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. + + , 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/Makefile b/gnu/Makefile new file mode 100644 index 0000000000..7da2c32376 --- /dev/null +++ b/gnu/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 5.33.1.1 (Berkeley) 5/6/91 + +SUBDIR= gawk groff tar + +.include diff --git a/gnu/usr.bin/awk/ACKNOWLEDGMENT b/gnu/usr.bin/awk/ACKNOWLEDGMENT new file mode 100644 index 0000000000..b6c3b0b0c6 --- /dev/null +++ b/gnu/usr.bin/awk/ACKNOWLEDGMENT @@ -0,0 +1,21 @@ +The current developers of Gawk would like to thank and acknowledge the +many people who have contributed to the development through bug reports +and fixes and suggestions. Unfortunately, we have not been organized +enough to keep track of all the names -- for that we apologize. + +Another group of people have assisted even more by porting Gawk to new +platforms and providing a great deal of feedback. They are: + + Hal Peterson (Cray) + Pat Rankin (VMS) + Michal Jaegermann (Atari, NeXT, DEC 3100) + Mike Lijewski (IBM RS6000) + Scott Deifik (MSDOS 2.14) + Kent Williams (MSDOS 2.11) + Conrad Kwok (MSDOS earlier versions) + Scott Garfinkle (MSDOS earlier versions) + +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 +restraining touch when we have been overly tempted by "feeping +creaturism". diff --git a/gnu/usr.bin/awk/COPYING b/gnu/usr.bin/awk/COPYING new file mode 100644 index 0000000000..3358a7be86 --- /dev/null +++ b/gnu/usr.bin/awk/COPYING @@ -0,0 +1,340 @@ + 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. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the 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. + + , 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/awk/FUTURES b/gnu/usr.bin/awk/FUTURES new file mode 100644 index 0000000000..b09656046b --- /dev/null +++ b/gnu/usr.bin/awk/FUTURES @@ -0,0 +1,120 @@ +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 +don't bug us too much about schedules or what all this really means. + +For 2.16 +======== +David: + Move to autoconf-based configure system. + + Allow RS to be a regexp. + + RT variable to hold text of record terminator + + RECLEN variable for fixed length records + + Feedback alloca.s changes to FSF + + Extensible hashing in memory of awk arrays + + Split() with null string as third arg to split up strings + + 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. + + Undertake significant directory reorganization. + + 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) + + 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 + ? Add an error messages section to the manual + ? A section on where gawk is bounded + regex + i/o + sun fp conversions + +For 2.18 +======== + +Arnold: + 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: +================== +Add variables similar to C's __FILE__ and __LINE__ for better diagnostics +from within awk programs. + +Add an explicit concatenation operator and assignment version. + +? Add a switch statement + +Add the ability to seek on an open file and retrieve the current file position. + +Add lint checking everywhere, including check for use of builtin vars. +only in new awk. + +"restart" keyword + +Add |& + +Make awk '/foo/' files... run at egrep speeds + +Do a reference card + +Allow OFMT to be other than a floating point format. + +Allow redefining of builtin functions? + +Make it faster and smaller. + +For 3.x: +======== + +Create a gawk compiler? + +Create a gawk-to-C translator? (or C++??) + +Provide awk profiling and debugging. + + + diff --git a/gnu/usr.bin/awk/LIMITATIONS b/gnu/usr.bin/awk/LIMITATIONS new file mode 100644 index 0000000000..5877197aeb --- /dev/null +++ b/gnu/usr.bin/awk/LIMITATIONS @@ -0,0 +1,14 @@ +This file describes limits of gawk on a Unix system (although it +is variable even then). Non-Unix systems may have other limits. + +# of fields in a record: MAX_INT +Length of input record: MAX_INT +Length of output record: unlimited +Size of a field: MAX_INT +Size of a printf string: MAX_INT +Size of a literal string: MAX_INT +Characters in a character class: 2^(# of bits per byte) +# of file redirections: unlimited +# of pipe redirections: min(# of processes per user, # of open files) +double-precision floating point +Length of source line: unlimited diff --git a/gnu/usr.bin/awk/Makefile b/gnu/usr.bin/awk/Makefile new file mode 100644 index 0000000000..fdca82c448 --- /dev/null +++ b/gnu/usr.bin/awk/Makefile @@ -0,0 +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 + +MAN1= awk.0 + +.include +.include "../../usr.bin/Makefile.inc" diff --git a/gnu/usr.bin/awk/NEWS b/gnu/usr.bin/awk/NEWS new file mode 100644 index 0000000000..6711373d6e --- /dev/null +++ b/gnu/usr.bin/awk/NEWS @@ -0,0 +1,1295 @@ +Changes from 2.15.1 to 2.15.2 +--------------------------- + +Additions to the FUTURES file. + +Document undefined order of output when using both standard output + and /dev/stdout or any of the /dev output files that gawk emulates in + the absence of OS support. + +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 +--------------------------- + +Close stdout and stderr before all redirections on program exit. This allows + detection of write errors and also fixes the messages test on Solaris 2.x. + +Removed YYMAXDEPTH define in awk.y which was limiting the parser stack depth. + +Changes to config/bsd44, Makefile.bsd44 and configure to bring it into line + with the BSD4.4 release. + +Changed Makefile to use prefix, exec_prefix, bindir etc. + +make install now installs info files. + +make install now sets permissions on installed files. + +Make targets added: uninstall, distclean, mostlyclean and realclean. + +Added config.h to cleaner and clobber make targets. + +Changes to config/{hpux8x,sysv3,sysv4,ultrix41} to deal with alloca(). + +Change to getopt.h for portability. + +Added more special cases to the getpgrp() call. + +Added README.ibmrt-aos and config/ibmrt-aos. + +Changes from 2.14 to 2.15 +--------------------------- + +Command-line source can now be mixed with library functions. + +ARGIND variable tracks index in ARGV of FILENAME. + +GNU style long options in addition to short options. + +Plan 9 style special files interpreted by gawk: + /dev/pid + /dev/ppid + /dev/pgrpid + /dev/user + $1 = getuid + $2 = geteuid + $3 = getgid + $4 = getegid + $5 ... $NF = getgroups if supported + +ERRNO variable contains error string if getline or close fails. + +Very old options -a and -e have gone away. + +Inftest has been removed from the default target in test/Makefile -- the + results were too machine specific and resulted in too many false alarms. + +A README.amiga has been added. + +The "too many arguments supplied for format string" warning message is only + in effect under the lint option. + +Code improvements in dfa.c. + +Fixed all reported bugs: + + Writes are checked for failure (such as full filesystem). + + Stopped (at least some) runaway error messages. + + gsub(/^/, "x") does the right thing for $0 of 0, 1, or more length. + + close() on a command being piped to a getline now works properly. + + The input record will no longer be freed upon an explicit close() + of the input file. + + A NUL character in FS now works. + + In a substitute, \\& now means a literal backslash followed by what + was matched. + + Integer overflow of substring length in substr() is caught. + + An input record without a newline termination is handled properly. + + In io.c, check is against only EMFILE so that system file table + is not filled. + + Renamed all files with names longer than 14 characters. + + Escaped characters in regular expressions were being lost when + IGNORECASE was used. + + Long source lines were not being handled properly. + + Sourcefiles that ended in a tab but no newline were bombing. + + Patterns that could match zero characters in split() were not working + properly. + + The parsedebug option was not working. + + The grammar was being a bit too lenient, allowing some very dubious + programs to pass. + + Compilation with DEBUG defined now works. + + A variable read in with getline was not being treated as a potential + number. + + Array subscripts were not always of string type. + + +Changes from 2.13.2 to 2.14 +--------------------------- + +Updated manual! + +Added "next file" to skip efficiently to the next input file. + +Fixed potential of overflowing buffer in do_sprintf(). + +Plugged small memory leak in sub_common(). + +EOF on a redirect is now "sticky" -- it can only be cleared by close()ing + the pipe or file. + +Now works if used via a #! /bin/gawk line at the top of an executable file + when that line ends with whitespace. + +Added some checks to the grammar to catch redefinition of builtin functions. + This could eventually be the basis for an extension to allow redefining + functions, but in the mean time it's a good error catching facility. + +Negative integer exponents now work. + +Modified do_system() to make sure it had a non-null string to be passed + to system(3). Thus, system("") will flush any pending output but not go + through the overhead of forking an un-needed shell. + +A fix to floating point comparisons so that NaNs compare right on IEEE systems. + +Added code to make sure we're not opening directories for reading and such. + +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 + 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. + +Error messages now conform to GNU standard (I hope). + +Changed comparisons to conform to the description found in the file POSIX. + This is inconsistent with the current POSIX draft, but that is broken. + Hopefully the final POSIX standard will conform to this version. + (Alas, this will have to wait for 1003.2b, which will be a revision to + the 1003.2 standard. That standard has been frozen with the broken + comparison rules.) + +The length of a string was a short and now is a size_t. + +Updated VMS help. + +Added quite a few new tests to the test suite and deleted many due to lack of + written releases. Test output is only removed if it is identical to the + "good" output. + +Fixed a couple of bugs for reference to $0 when $0 is "" -- particularly in + a BEGIN block. + +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 + child of gawk and this caused a deadlock. + +Regexp can (once again) match a newline, if given explicitly. + +nextopen() makes sure file name is null terminated. + +Fixed VMS pipe simulation. Improved VMS I/O performance. + +Catch . used in variable names. + +Fixed bug in getline without redirect from a file -- it was quitting after the + first EOF, rather than trying the next file. + +Fixed bug in treatment of backslash at the end of a string -- it was bombing + rather than doing something sensible. It is not clear what this should mean, + but for now I issue a warning and take it as a literal backslash. + +Moved setting of regexp syntax to before the option parsing in main(), to + handle things like -v FS='[.,;]' + +Fixed bug when NF is set by user -- fields_arr must be expanded if necessary + and "new" fields must be initialized. + +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 + substitute throughout the string. + +make test does not assume the . is in PATH. + +Fixed bug when a field beyond the end of the record was requested after + $0 was altered (directly or indirectly). + +Fixed bug for assignment to field beyond end of record -- the assigned value + was not found on subsequent reference to that field. + +Fixed bug for FS a regexp and it matches at the end of a record. + +Fixed memory leak for an array local to a function. + +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. + +Fixed faking of /dev/stdin. + +Fixed problem with x += x + +Use of scalar as array and vice versa is now detected. + +IGNORECASE now obeyed for FS (even if FS is a single alphabetic character). + +Switch to GPL version 2. + +Renamed awk.tab.c to awktab.c for MSDOS and VMS tar programs. + +Renamed this file (CHANGES) to NEWS. + +Use fmod() instead of modf() and provide FMOD_MISSING #define to undo + this change. + +Correct the volatile declarations in eval.c. + +Avoid errant closing of the file descriptors for stdin, stdout and stderr. + +Be more flexible about where semi-colons can occur in programs. + +Check for write errors on all output, not just on close(). + +Eliminate the need for missing/{strtol.c,vprintf.c}. + +Use GNU getopt and eliminate missing/getopt.c. + +More "lint" checking. + + +Changes from 2.13.1 to 2.13.2 +----------------------------- + +Toward conformity with GNU standards, configure is a link to mkconf, the latter + to disappear in the next major release. + +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. + +Ultrix41 now propagates to config.h properly -- as part of a general + mechanism in configure for kludges -- #define anything from a config file + just gets tacked onto the end of config.h -- to be used sparingly. + +Got rid of an unnecessary and troublesome declaration of vprintf(). + +Small improvement in locality of error messages. + +Try to diagnose use of array as scalar and vice versa -- to be improved in + the future. + +Fix for last bug fix for Cray division code--sigh. + +More changes to test suite to explicitly use sh. Also get rid of + a few generated files. + +Fixed off-by-one bug in string concatenation code. + +Fix for use of array that is passed in from a previous function parameter. + Addition to test suite for above. + +A number of changes associated with changing NF and access to fields + beyond the end of the current record. + +Change to missing/memcmp.c to avoid seg. fault on zero length input. + +Updates to test suite (including some inadvertently left out of the last patch) + to invoke sh explicitly (rather than rely on #!/bin/sh) and remove some + junk files. test/chem/good updated to correspond to bug fixes. + +Changes from 2.13.0 to 2.13.1 +----------------------------- + +More configs and PORTS. + +Fixed bug wherein a simple division produced an erroneous FPE, caused by + the Cray division workaround -- that code is now #ifdef'd only for + Cray *and* fixed. + +Fixed bug in modulus implementation -- it was very close to the above + code, so I noticed it. + +Fixed portability problem with limits.h in missing.c + +Fixed portability problem with tzname and daylight -- define TZNAME_MISSING + if strftime() is missing and tzname is also. + +Better support for Latin-1 character set. + +Fixed portability problem in test Makefile. + +Updated PROBLEMS file. + +=============================== gawk-2.13 released ========================= +Changes from 2.12.42 to 2.12.43 +------------------------------- + +Typo in awk.y + +Fixed up strftime.3 and added doc. for %V. + +Changes from 2.12.41 to 2.12.42 +------------------------------- + +Fixed bug in devopen() -- if you had write permission in /dev, + it would just create /dev/stdout etc.!! + +Final (?) VMS update. + +Make NeXT use GFMT_WORKAROUND + +Fixed bug in sub_common() for substitute on zero-length match. Improved the + code a bit while I was at it. + +Fixed grammar so that $i++ parses as ($i)++ + +Put support/* back in the distribution (didn't I already do this?!) + +Changes from 2.12.40 to 2.12.41 +------------------------------- + +VMS workaround for broken %g format. + +Changes from 2.12.39 to 2.12.40 +------------------------------- + +Minor man page update. + +Fixed latent bug in redirect(). + +Changes from 2.12.38 to 2.12.39 +------------------------------- + +Updates to test suite -- remove dependence on changing gawk.1 man page. + +Changes from 2.12.37 to 2.12.38 +------------------------------- + +Fixed bug in use of *= without whitespace following. + +VMS update. + +Updates to man page. + +Option handling updates in main.c + +test/manyfiles redone and added to bigtest. + +Fixed latent (on Sun) bug in handling of save_fs. + +Changes from 2.12.36 to 2.12.37 +------------------------------- + +Update REL in Makefile-dist. Incorporate test suite into main distribution. + +Minor fix in regtest. + +Changes from 2.12.35 to 2.12.36 +------------------------------- + +Release takes on dual personality -- 2.12.36 and 2.13.0 -- any further + patches before public release won't count for 2.13, although they will for + 2.12 -- be careful to avoid confusion! patchlevel.h will be the last thing + to change. + +Cray updates to deal with arithmetic problems. + +Minor test suite updates. + +Fixed latent bug in parser (freeing memory). + +Changes from 2.12.34 to 2.12.35 +------------------------------- + +VMS updates. + +Flush stdout at top of err() and stderr at bottom. + +Fixed bug in eval_condition() -- it wasn't testing for MAYBE_NUM and + doing the force_number(). + +Included the missing manyfiles.awk and a new test to catch the above bug which + I am amazed wasn't already caught by the test suite -- it's pretty basic. + +Changes from 2.12.33 to 2.12.34 +------------------------------- + +Atari updates -- including bug fix. + +More VMS updates -- also nuke vms/version.com. + +Fixed bug in handling of large numbers of redirections -- it was probably never + tested before (blush!). + +Minor rearrangement of code in r_force_number(). + +Made chem and regtest tests a bit more portable (Ultrix again). + +Added another test -- manyfiles -- not invoked under any other test -- very Unix + specific. + +Rough beginning of LIMITATIONS file -- need my AWK book to complete it. + +Changes from 2.12.32 to 2.12.33 +------------------------------- + +Expunge debug.? from various files. + +Remove vestiges of Floor and Ceil kludge. + +Special case integer division -- mainly for Cray, but maybe someone else + will benefit. + +Workaround for iop_close closing an output pipe descriptor on Cray -- + not conditional since I think it may fix a bug on SGI as well and I don't + think it can hurt elsewhere. + +Fixed memory leak in assoc_lookup(). + +Small cleanup in test suite. + +Changes from 2.12.31 to 2.12.32 +------------------------------- + +Nuked debug.c and debugging flag -- there are better ways. + +Nuked version.sh and version.c in subdirectories. + +Fixed bug in handling of IGNORECASE. + +Fixed bug when FIELDWIDTHS was set via -v option. + +Fixed (obscure) bug when $0 is assigned a numerical value. + +Fixed so that escape sequences in command-line assignments work (as it already + said in the comment). + +Added a few cases to test suite. + +Moved support/* back into distribution. + +VMS updates. + +Changes from 2.12.30 to 2.12.31 +------------------------------- + +Cosmetic manual page changes. + +Updated sunos3 config. + +Small changes in test suite including renaming files over 14 chars. in length. + +Changes from 2.12.29 to 2.12.30 +------------------------------- + +Bug fix for many string concatenations in a row. + +Changes from 2.12.28 to 2.12.29 +------------------------------- + +Minor cleanup in awk.y + +Minor VMS update. + +Minor atari update. + +Changes from 2.12.27 to 2.12.28 +------------------------------- + +Got rid of the debugging goop in eval.c -- there are better ways. + +Sequent port. + +VMS changes left out of the last patch -- sigh! config/vms.h renamed + to config/vms-conf.h. + +Fixed missing/tzset.c + +Removed use of gcvt() and GCVT_MISSING -- turns out it was no faster than + sprintf("%g") and caused all sorts of portability headaches. + +Tuned get_field() -- it was unnecessarily parsing the whole record on reference + to $0. + +Tuned interpret() a bit in the rule_node loop. + +In r_force_number(), worked around bug in Uglix strtod() and got rid of + ugly do{}while(0) at Michal's urging. + +Replaced do_deref() and deref with unref(node) -- much cleaner and a bit faster. + +Got rid of assign_number() -- contrary to comment, it was no faster than + just making a new node and freeing the old one. + +Replaced make_number() and tmp_number() with macros that call mk_number(). + +Changed freenode() and newnode() into macros -- the latter is getnode() + which calls more_nodes() as necessary. + +Changes from 2.12.26 to 2.12.27 +------------------------------- + +Completion of Cray 2 port (includes a kludge for floor() and ceil() + that may go or be changed -- I think that it may just be working around + a bug in chem that is being tweaked on the Cray). + +More VMS updates. + +Moved kludge over yacc's insertion of malloc and realloc declarations + from protos.h to the Makefile. + +Added a lisp interpreter in awk to the test suite. (Invoked under + bigtest.) + +Cleanup in r_force_number() -- I had never gotten around to a thorough + profile of the cache code and it turns out to be not worth it. + +Performance boost -- do lazy force_number()'ing for fields etc. i.e. + flag them (MAYBE_NUM) and call force_number only as necessary. + +Changes from 2.12.25 to 2.12.26 +------------------------------- + +Rework of regexp stuff so that dynamic regexps have reasonable + performance -- string used for compiled regexp is stored and + compared to new string -- if same, no recompilation is necessary. + Also, very dynamic regexps cause dfa-based searching to be turned + off. + +Code in dev_open() is back to returning fileno(std*) rather than + dup()ing it. This will be documented. Sorry for the run-around + on this. + +Minor atari updates. + +Minor vms update. + +Missing file from MSDOS port. + +Added warning (under lint) if third arg. of [g]sub is a constant and + handle it properly in the code (i.e. return how many matches). + +Changes from 2.12.24 to 2.12.25 +------------------------------- + +MSDOS port. + +Non-consequential changes to regexp variables in preparation for + a more serious change to fix a serious performance problem. + +Changes from 2.12.23 to 2.12.24 +------------------------------- + +Fixed bug in output flushing introduced a few patches back. This caused + serious performance losses. + +Changes from 2.12.22 to 2.12.23 +------------------------------- + +Accidently left config/cray2-60 out of last patch. + +Added some missing dependencies to Makefile. + +Cleaned up mkconf a bit; made yacc the default parser (no alloca needed, + right?); added rs6000 hook for signed characters. + +Made regex.c with NO_ALLOCA undefined work. + +Fixed bug in dfa.c for systems where free(NULL) bombs. + +Deleted a few cant_happen()'s that *really* can't hapen. + +Changes from 2.12.21 to 2.12.22 +------------------------------- + +Added to config stuff the ability to choose YACC rather than bison. + +Fixed CHAR_UNSIGNED in config.h-dist. + +Second arg. of strtod() is char ** rather than const char **. + +stackb is now initially malloc()'ed since it may be realloc()'ed. + +VMS updates. + +Added SIZE_T_MISSING to config stuff and a default typedef to awk.h. + (Maybe it is not needed on any current systems??) + +re_compile_pattern()'s size is now size_t unconditionally. + +Changes from 2.12.20 to 2.12.21 +------------------------------- + +Corrected missing/gcvt.c. + +Got rid of use of dup2() and thus DUP_MISSING. + +Updated config/sgi33. + +Turned on (and fixed) in cmp_nodes() the behaviour that I *hope* will be in + POSIX 1003.2 for relational comparisons. + +Small updates to test suite. + +Changes from 2.12.19 to 2.12.20 +------------------------------- + +Sloppy, sloppy, sloppy!! I didn't even try to compile the last two + patches. This one fixes goofs in regex.c. + +Changes from 2.12.18 to 2.12.19 +------------------------------- + +Cleanup of last patch. + +Changes from 2.12.17 to 2.12.18 +------------------------------- + +Makefile renamed to Makefile-dist. + +Added alloca() configuration to mkconf. (A bit kludgey.) Just + add a single line containing ALLOCA_PW, ALLOCA_S or ALLOCA_C + to the appropriate config file to have Makefile-dist edited + accordingly. + +Reorganized output flushing to correspond with new semantics of + devopen() on "/dev/std*" etc. + +Fixed rest of last goof!! + +Save and restore errno in do_pathopen(). + +Miscellaneous atari updates. + +Get rid of the trailing comma in the NODETYPE definition (Cray + compiler won't take it). + +Try to make the use of `const' consistent since Cray compiler is + fussy about that. See the changes to `basename' and `myname'. + +It turns out that, according to section 3.8.3 (Macro Replacement) + of the ANSI Standard: ``If there are sequences of preprocessing + tokens within the list of arguments that would otherwise act as + preprocessing directives, the behavior is undefined.'' That means + that you cannot count on the behavior of the declaration of + re_compile_pattern in awk.h, and indeed the Cray compiler chokes on it. + +Replaced alloca with malloc/realloc/free in regex.c. It was much simpler + than expected. (Inside NO_ALLOCA for now -- by default no alloca.) + +Added a configuration file, config/cray60, for Unicos-6.0. + +Changes from 2.12.16 to 2.12.17 +------------------------------- + +Ooops. Goofed signal use in last patch. + +Changes from 2.12.15 to 2.12.16 +------------------------------- + +RENAMED *_dir to just * (e.g. missing_dir). + +Numerous VMS changes. + +Proper inclusion of atari and vms files. + +Added experimental (ifdef'd out) RELAXED_CONTINUATION and DEFAULT_FILETYPE + -- please comment on these! + +Moved pathopen() to io.c (sigh). + +Put local directory ahead in default AWKPATH. + +Added facility in mkconf to echo comments on stdout: lines beginning + with "#echo " will have the remainder of the line echoed when mkconf is run. + Any lines starting with "#" will otherwise be treated as comments. The + intent is to be able to say: + "#echo Make sure you uncomment alloca.c in the Makefile" + or the like. + +Prototype fix for V.4 + +Fixed version_string to not print leading @(#). + +Fixed FIELDWIDTHS to work with strict (turned out to be easy). + +Fixed conf for V.2. + +Changed semantics of /dev/fd/n to be like on real /dev/fd. + +Several configuration and updates in the makefile. + +Updated manpage. + +Include tzset.c and system.c from missing_dir that were accidently left out of + the last patch. + +Fixed bug in cmdline variable assignment -- arg was getting freed(!) in + call to variable. + +Backed out of parse-time constant folding for now, until I can figure out + how to do it right. + +Fixed devopen() so that getline <"-" works. + +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 + 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. + +Fixed bug in grammar -- didn't allow function definition to be separated from + other rules by a semi-colon. + +VMS fix to #includes in missing.c -- should we just be including awk.h? + +Updated README for texinfo.tex version. + +Updating of copyright in all .[chy] files. + +Added but commented out Michal's fix to strftime. + +Added tzset() emulation based on Rick Adams' code. Added TZSET_MISSING to + config.h-dist. + +Added strftime.3 man page for missing_dir + +More posix: func, **, **= don't work in -W posix + +More lint: ^, ^= not in old awk + +gawk.1: removed ref to -DNO_DEV_FD, other minor updating. + +Style change: pushbak becomes pushback() in yylex(). + +Changes from 2.12.13 to 2.12.14 +------------------------------- + +Better (?) organization of awk.h -- attempt to keep all system dependencies + near the top and move some of the non-general things out of the config.h + files. + +Change to handling of SYSTEM_MISSING. + +Small change to ultrix config. + +Do "/dev/fd/*" etc. checking at runtime. + +First pass at VMS port. + +Improvements to error handling (when lexeme spans buffers). + +Fixed backslash handling -- why didn't I notice this sooner? + +Added programs from book to test suite and new target "bigtest" to Makefile. + +Changes from 2.12.12 to 2.12.13 +------------------------------- + +Recognize OFS and ORS specially so that OFS = 9 works without efficiency hit. + Took advantage of opportunity to tune do_print*() for about 10% win on a + print with 5 args (i.e. small but significant). + +Somewhat pervasive changes to reconcile CONVFMT vs. OFMT. + +Better initialization of builtin vars. + +Make config/* consistent wrt STRTOL_MISSING. + +Small portability improvement to alloca.s + +Improvements to lint code in awk.y + +Replaced strtol() with a better one by Chris Torek. + +Changes from 2.12.11 to 2.12.12 +------------------------------- + +Added PORTS file to record successful ports. + +Added #define const to nothing if not STDC and added const to strtod() header. + +Added * to printf capabilities and partially implemented ' ' and '+' (has an + effect for %d only, silently ignored for other formats). I'm afraid that's + as far as I want to go before I look at a complete replacement for + do_sprintf(). + +Added warning for /regexp/ on LHS of MATCHOP. + +Changes from 2.12.10 to 2.12.11 +------------------------------- + +Small Makefile improvements. + +Some remaining nits from the NeXT port. + +Got rid of bcopy() define in awk.h -- not needed anymore (??) + +Changed private in builtin.c -- it is special on Sequent. + +Added subset implementation of strtol() and STRTOL_MISSING. + +A little bit of cleanup in debug.c, dfa.c. + +Changes from 2.12.9 to 2.12.10 +------------------------------ + +Redid compatability checking and checking for # of args. + +Removed all references to variables[] from outside awk.y, in preparation + for a more abstract interface to the symbol table. + +Got rid of a remaining use of bcopy() in regex.c. + +Changes from 2.12.8 to 2.12.9 +----------------------------- + +Portability improvements for atari, next and decstation. + +Bug fix in substr() -- wasn't handling 3rd arg. of -1 properly. + +Manpage updates. + +Moved support from src release to doc release. + +Updated FUTURES file. + +Added some "lint" warnings. + +Changes from 2.12.7 to 2.12.8 +----------------------------- + +Changed time() to systime(). + +Changed warning() in snode() to fatal(). + +strftime() now defaults second arg. to current time. + +Changes from 2.12.6 to 2.12.7 +----------------------------- + +Fixed bug in sub_common() involving inadequate allocation of a buffer. + +Added some missing files to the Makefile. + +Changes from 2.12.5 to 2.12.6 +----------------------------- + +Fixed bug wherein non-redirected getline could call iop_close() just + prior to a call from do_input(). + +Fixed bug in handling of /dev/stdout and /dev/stderr. + +Changes from 2.12.4 to 2.12.5 +----------------------------- + +Updated README and support directory. + +Changes from 2.12.3 to 2.12.4 +----------------------------- + +Updated CHANGES and TODO (should have been done in previous 2 patches). + +Changes from 2.12.2 to 2.12.3 +----------------------------- + +Brought regex.c and alloca.s into line with current FSF versions. + +Changes from 2.12.1 to 2.12.2 +----------------------------- + +Portability improvements; mostly moving system prototypes out of awk.h + +Introduction of strftime. + +Use of CONVFMT. + +Changes from 2.12 to 2.12.1 +----------------------------- + +Consolidated treatment of command-line assignments (thus correcting the +-v treatment). + +Rationalized builtin-variable handling into a table-driven process, thus +simplifying variable() and eliminating spc_var(). + +Fixed bug in handling of command-line source that ended in a newline. + +Simplified install() and lookup(). + +Did away with double-mallocing of identifiers and now free second and later +instances of a name, after the first gets installed into the symbol table. + +Treat IGNORECASE specially, simplifying a lot of code, and allowing +checking against strict conformance only on setting it, rather than on each +pattern match. + +Fixed regexp matching when IGNORECASE is non-zero (broken when dfa.c was +added). + +Fixed bug where $0 was not being marked as valid, even after it was rebuilt. +This caused mangling of $0. + + +Changes from 2.11.1 to 2.12 +----------------------------- + +Makefile: + +Portability improvements in Makefile. +Move configuration stuff into config.h + +FSF files: + +Synchronized alloca.[cs] and regex.[ch] with FSF. + +array.c: + +Rationalized hash routines into one with a different algorithm. +delete() now works if the array is a local variable. +Changed interface of assoc_next() and avoided dereferencing past the end of the + array. + +awk.h: + +Merged non-prototype and prototype declarations in awk.h. +Expanded tree_eval #define to short-circuit more calls of r_tree_eval(). + +awk.y: + +Delinted some of the code in the grammar. +Fixed and improved some of the error message printing. +Changed to accomodate unlimited length source lines. +Line continuation now works as advertised. +Source lines can be arbitrarily long. +Refined grammar hacks so that /= assignment works. Regular expressions + starting with /= are recognized at the beginning of a line, after && or || + and after ~ or !~. More contexts can be added if necessary. +Fixed IGNORECASE (multiple scans for backslash). +Condensed expression_lists in array references. +Detect and warn for correct # args in builtin functions -- call most of them + with a fixed number (i.e. fill in defaults at parse-time rather than at + run-time). +Load ENVIRON only if it is referenced (detected at parse-time). +Treat NF, FS, RS, NR, FNR specially at parse time, to improve run time. +Fold constant expressions at parse time. +Do make_regexp() on third arg. of split() at parse tiem if it is a constant. + +builtin.c: + +srand() returns 0 the first time called. +Replaced alloca() with malloc() in do_sprintf(). +Fixed setting of RSTART and RLENGTH in do_match(). +Got rid of get_{one,two,three} and allowance for variable # of args. at + run-time -- this is now done at parse-time. +Fixed latent bug in [g]sub whereby changes to $0 would never get made. +Rewrote much of sub_common() for simplicity and performance. +Added ctime() and time() builtin functions (unless -DSTRICT). ctime() returns + a time string like the C function, given the number of seconds since the epoch + and time() returns the current time in seconds. +do_sprintf() now checks for mismatch between format string and number of + arguments supplied. + +dfa.c + +This is borrowed (almost unmodified) from GNU grep to provide faster searches. + +eval.c + +Node_var, Node_var_array and Node_param_list handled from macro rather + than in r_tree_eval(). +Changed cmp_nodes() to not do a force_number() -- this, combined with a + force_number() on ARGV[] and ENVIRON[] brings it into line with other awks +Greatly simplified cmp_nodes(). +Separated out Node_NF, Node_FS, Node_RS, Node_NR and Node_FNR in get_lhs(). +All adjacent string concatenations now done at once. + +field.c + +Added support for FIELDWIDTHS. +Fixed bug in get_field() whereby changes to a field were not always + properly reflected in $0. +Reordered tests in parse_field() so that reference off the end of the buffer + doesn't happen. +set_FS() now sets *parse_field i.e. routine to call depending on type of FS. +It also does make_regexp() for FS if needed. get_field() passes FS_regexp + to re_parse_field(), as does do_split(). +Changes to set_field() and set_record() to avoid malloc'ing and free'ing the + field nodes repeatedly. The fields now just point into $0 unless they are + assigned to another variable or changed. force_number() on the field is + *only* done when the field is needed. + +gawk.1 + +Fixed troff formatting problem on .TP lines. + +io.c + +Moved some code out into iop.c. +Output from pipes and system() calls is properly synchronized. +Status from pipe close properly returned. +Bug in getline with no redirect fixed. + +iop.c + +This file contains a totally revamped get_a_record and associated code. + +main.c + +Command line programs no longer use a temporary file. +Therefore, tmpnam() no longer required. +Deprecated -a and -e options -- they will go away in the next release, + but for now they cause a warning. +Moved -C, -V, -c options to -W ala posix. +Added -W posix option: throw out \x +Added -W lint option. + + +node.c + +force_number() now allows pure numerics to have leading whitespace. +Added make_string facility to optimize case of adding an already malloc'd + string. +Cleaned up and simplified do_deref(). +Fixed bug in handling of stref==255 in do_deref(). + +re.c + +contains the interface to regexp code + +Changes from 2.11.1 to FSF version of same +------------------------------------------ +Thu Jan 4 14:19:30 1990 Jim Kingdon (kingdon at albert) + + * Makefile (YACC): Add -y to bison part. + + * missing.c: Add #include . + +Sun Dec 24 16:16:05 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * * Makefile: Add (commented out) default defines for Sony News. + + * awk.h: Move declaration of vprintf so it will compile when + -DVPRINTF_MISSING is defined. + +Mon Nov 13 18:54:08 1989 Robert J. Chassell (bob at apple-gunkies.ai.mit.edu) + + * gawk.texinfo: changed @-commands that are not part of the + standard, currently released texinfmt.el to those that are. + Otherwise, only people with the as-yet unreleased makeinfo.c can + format this file. + +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. + +MS-DOS changes added in. + +Signal handler return type parameterized in Makefile and awk.h and +some lint removed. debug.c cleaned up. + +Fixed FS splitting to never match null strings, per book. + +Correction to the manual's description of FS. + +Some compilers break on char *foo = "string" + 4 so fixed version.sh and +main.c. + +Changes from 2.10beta to 2.11beta +--------------------------------- + +This release fixes all reported bugs that we could reproduce. Probably +some of the changes are not documented here. + +The next release will probably not be a beta release! + +The most important change is the addition of the -nostalgia option. :-) + +The documentation has been improved and brought up-to-date. + +There has been a lot of general cleaning up of the code that is not otherwise +documented here. There has been a movement toward using standard-conforming +library routines and providing them (in missing.d) for systems lacking them. +Improved (hopefully) configuration through Makfile modifications and missing.c. +In particular, straightened out confusion over vprintf #defines, declarations +etc. + +Deleted RCS log comments from source, to reduce source size by about one third. +Most of them were horribly out-of-date, anyway. + +Renamed source files to reflect (for the most part) their contents. + +More and improved error messages. Cleanup and fixes to yyerror(). +String constants are not altered in input buffer, so error messages come out +better. Fixed usage message. Make use of ANSI C strerror() function +(provided). + +Plugged many more memory leaks. The memory consumption is now quite +reasonable over a wide range of programs. + +Uses volatile declaration if STDC > 0 to avoid problems due to longjmp. + +New -a and -e options to use awk or egrep style regexps, respectively, +since POSIX says awk should use egrep regexps. Default is -a. + +Added -v option for setting variables before the first file is encountered. +Version information now uses -V and copyleft uses -C. + +Added a patchlevel.h file and its use for -V and -C. + +Append_right() optimized for major improvement to programs with a *lot* +of statements. + +Operator precedence has been corrected to match draft Posix. + +Tightened up grammar for builtin functions so that only length +may be called without arguments or parentheses. + +/regex/ is now a normal expression that can appear in any expression +context. + +Allow /= to begin a regexp. Allow ..[../..].. in a regexp. + +Allow empty compound statements ({}). + +Made return and next illegal outside a function and in BEGIN/END respectively. + +Division by zero is now illegal and causes a fatal error. + +Fixed exponentiation so that x ^ 0 and x ^= 0 both return 1. + +Fixed do_sqrt, do_log, and do_exp to do argument/return checking and +print an error message, per the manual. + +Fixed main to catch SIGSEGV to get source and data file line numbers. + +Fixed yyerror to print the ^ at the beginning of the bad token, not the end. + +Fix to substr() builtin: it was failing if the arguments +weren't already strings. + +Added new node value flag NUMERIC to indicate that a variable is +purely a number as opposed to type NUM which indicates that +the node's numeric value is valid. This is set in make_number(), +tmp_number and r_force_number() when appropriate and used in +cmp_nodes(). This fixed a bug in comparison of variables that had +numeric prefixes. The new code uses strtod() and eliminates is_a_number(). +A simple strtod() is provided for systems lacking one. It does no +overflow checking, so could be improved. + +Simplification and efficiency improvement in force_string. + +Added performance tweak in r_force_number(). + +Fixed a bug with nested loops and break/continue in functions. + +Fixed inconsistency in handling of empty fields when $0 has to be rebuilt. +Happens to simplify rebuild_record(). + +Cleaned up the code associated with opening a pipe for reading. Gawk +now has its own popen routine (gawk_popen) that allocates an IOBUF +and keeps track of the pid of the child process. gawk_pclose +marks the appropriate child as defunct in the right struct redirect. + +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 +or pipe are flushed immediately and non-redirected output to a tty is flushed +before the next input record is read. + +Fixed a bug in get_a_record() where bcopy() could have copied over +a random pointer. + +Fixed a bug when RS="" and records separated by multiple blank lines. + +Got rid of SLOWIO code which was out-of-date anyway. + +Fix in get_field() for case where $0 is changed and then $(n) are +changed and then $0 is used. + +Fixed infinite loop on failure to open file for reading from getline. +Now handles redirect file open failures properly. + +Filenames such as /dev/stdin now allowed on the command line as well as +in redirects. + +Fixed so that gawk '$1' where $1 is a zero tests false. + +Fixed parsing so that `RLENGTH -1' parses the same as `RLENGTH - 1', +for example. + +The return from a user-defined function now defaults to the Null node. +This fixes a core-dump-causing bug when the return value of a function +is used and that function returns no value. + +Now catches floating point exceptions to avoid core dumps. + +Bug fix for deleting elements of an array -- under some conditions, it was +deleting more than one element at a time. + +Fix in AWKPATH code for running off the end of the string. + +Fixed handling of precision in *printf calls. %0.2d now works properly, +as does %c. [s]printf now recognizes %i and %X. + +Fixed a bug in printing of very large (>240) strings. + +Cleaned up erroneous behaviour for RS == "". + +Added IGNORECASE support to index(). + +Simplified and fixed newnode/freenode. + +Fixed reference to $(anything) in a BEGIN block. + +Eliminated use of USG rand48(). + +Bug fix in force_string for machines with 16-bit ints. + +Replaced use of mktemp() with tmpnam() and provided a partial implementation of +the latter for systems that don't have it. + +Added a portability check for includes in io.c. + +Minor portability fix in alloc.c plus addition of xmalloc(). + +Portability fix: on UMAX4.2, st_blksize is zero for a pipe, thus breaking +iop_alloc() -- fixed. + +Workaround for compiler bug on Sun386i in do_sprintf. + +More and improved prototypes in awk.h. + +Consolidated C escape parsing code into one place. + +strict flag is now turned on only when invoked with compatability option. +It now applies to fewer things. + +Changed cast of f._ptr in vprintf.c from (unsigned char *) to (char *). +Hopefully this is right for the systems that use this code (I don't). + +Support for pipes under MSDOS added. diff --git a/gnu/usr.bin/awk/PORTS b/gnu/usr.bin/awk/PORTS new file mode 100644 index 0000000000..95e133f9dd --- /dev/null +++ b/gnu/usr.bin/awk/PORTS @@ -0,0 +1,32 @@ +A recent version of gawk has been successfully compiled and run "make test" +on the following: + +Sun 4/490 running 4.1 +NeXT running 2.0 +DECstation 3100 running Ultrix 4.0 or Ultrix 3.1 (different config) +AtariST (16-bit ints, gcc compiler, byacc, running under TOS) +ESIX V.3.2 Rev D (== System V Release 3.2), the 386. compiler was gcc + bison +IBM RS/6000 (see README.rs6000) +486 running SVR4, using cc and bison +SGI running IRIX 3.3 using gcc (fails with cc) +Sequent Balance running Dynix V3.1 +Cray Y-MP8 running Unicos 6.0.11 +Cray 2 running Unicos 6.1 (modulo trailing zeroes in chem) +VAX/VMS V5.x (should also work on 4.6 and 4.7) +VMS POSIX V1.0, V1.1 +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): + +arch configured as: +---- -------------- +Hpux 9.0 hpux8x +NeXTStep 2.0 next20 +Sgi Irix 4.0.5 (/bin/cc) sgi405.cc (new file) +Stardent Titan 1500 OSv2.5 sysv3 +Stardent Vistra (i860) SVR4 sysv4 +SunOS 4.1.2 sunos41 +Tektronix XD88 (UTekV 3.2e) sysv3 +Ultrix 4.2 ultrix41 diff --git a/gnu/usr.bin/awk/POSIX b/gnu/usr.bin/awk/POSIX new file mode 100644 index 0000000000..f2405420ae --- /dev/null +++ b/gnu/usr.bin/awk/POSIX @@ -0,0 +1,95 @@ +Right now, the numeric vs. string comparisons are screwed up in draft +11.2. What prompted me to check it out was the note in gnu.bug.utils +which observed that gawk was doing the comparison $1 == "000" +numerically. I think that we can agree that intuitively, this should +be done as a string comparison. Version 2.13.2 of gawk follows the +current POSIX draft. Following is how I (now) think this +stuff should be done. + +1. A numeric literal or the result of a numeric operation has the NUMERIC + attribute. + +2. A string literal or the result of a string operation has the STRING + attribute. + +3. Fields, getline input, FILENAME, ARGV elements, ENVIRON elements and the + elements of an array created by split() that are numeric strings + have the STRNUM attribute. Otherwise, they have the STRING attribute. + Uninitialized variables also have the STRNUM attribute. + +4. Attributes propagate across assignments, but are not changed by + any use. (Although a use may cause the entity to acquire an additional + value such that it has both a numeric and string value -- this leaves the + attribute unchanged.) + +When two operands are compared, either string comparison or numeric comparison +may be used, depending on the attributes of the operands, according to the +following (symmetric) matrix: + + +---------------------------------------------- + | STRING NUMERIC STRNUM +--------+---------------------------------------------- + | +STRING | string string string + | +NUMERIC | string numeric numeric + | +STRNUM | string numeric numeric +--------+---------------------------------------------- + +So, the following program should print all OKs. + +echo '0e2 0a 0 0b +0e2 0a 0 0b' | +$AWK ' +NR == 1 { + num = 0 + str = "0e2" + + print ++test ": " ( (str == "0e2") ? "OK" : "OOPS" ) + print ++test ": " ( ("0e2" != 0) ? "OK" : "OOPS" ) + print ++test ": " ( ("0" != $2) ? "OK" : "OOPS" ) + print ++test ": " ( ("0e2" == $1) ? "OK" : "OOPS" ) + + print ++test ": " ( (0 == "0") ? "OK" : "OOPS" ) + print ++test ": " ( (0 == num) ? "OK" : "OOPS" ) + print ++test ": " ( (0 != $2) ? "OK" : "OOPS" ) + print ++test ": " ( (0 == $1) ? "OK" : "OOPS" ) + + print ++test ": " ( ($1 != "0") ? "OK" : "OOPS" ) + print ++test ": " ( ($1 == num) ? "OK" : "OOPS" ) + print ++test ": " ( ($2 != 0) ? "OK" : "OOPS" ) + print ++test ": " ( ($2 != $1) ? "OK" : "OOPS" ) + print ++test ": " ( ($3 == 0) ? "OK" : "OOPS" ) + print ++test ": " ( ($3 == $1) ? "OK" : "OOPS" ) + print ++test ": " ( ($2 != $4) ? "OK" : "OOPS" ) # 15 +} +{ + a = "+2" + b = 2 + if (NR % 2) + c = a + b + print ++test ": " ( (a != b) ? "OK" : "OOPS" ) # 16 and 22 + + d = "2a" + b = 2 + if (NR % 2) + c = d + b + print ++test ": " ( (d != b) ? "OK" : "OOPS" ) + + print ++test ": " ( (d + 0 == b) ? "OK" : "OOPS" ) + + e = "2" + print ++test ": " ( (e == b "") ? "OK" : "OOPS" ) + + a = "2.13" + print ++test ": " ( (a == 2.13) ? "OK" : "OOPS" ) + + a = "2.130000" + print ++test ": " ( (a != 2.13) ? "OK" : "OOPS" ) + + if (NR == 2) { + CONVFMT = "%.6f" + print ++test ": " ( (a == 2.13) ? "OK" : "OOPS" ) + } +}' diff --git a/gnu/usr.bin/awk/PROBLEMS b/gnu/usr.bin/awk/PROBLEMS new file mode 100644 index 0000000000..3b7c5148bd --- /dev/null +++ b/gnu/usr.bin/awk/PROBLEMS @@ -0,0 +1,6 @@ +This is a list of known problems in gawk 2.15. +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. diff --git a/gnu/usr.bin/awk/README b/gnu/usr.bin/awk/README new file mode 100644 index 0000000000..f4bd3df806 --- /dev/null +++ b/gnu/usr.bin/awk/README @@ -0,0 +1,116 @@ +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 release adds new features -- see NEWS for details. + +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. +Please read the LIMITATIONS and ACKNOWLEDGMENT files. + +Read the file POSIX for a discussion of how the standard says comparisons +should be done vs. how they really should be done and how gawk does them. + +To format the documentation with TeX, you must use texinfo.tex 2.53 +or later. Otherwise footnotes look unacceptable. + +If you wish to remake the Info files, you should use makeinfo. The 2.15 +version of makeinfo works with no errors. + +The man page is up to date. + +INSTALLATION: + +Check whether there is a system-specific README file for your system. + +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. + +All other changes should be made in a config file. Samples for +various systems are included in the config directory. Starting with +2.11, our intent has been to make the code conform to standards (ANSI, +POSIX, SVID, in that order) whenever possible, and to not penalize +standard conforming systems. We have included substitute versions of +routines not universally available. Simply add the appropriate define +for the missing feature(s) on your system. + +If you have neither bison nor yacc, use the awktab.c file here. It was +generated with bison, and should have no AT&T code in it. (Note that +modifying awk.y without bison or yacc will be difficult, at best. You might +want to get a copy of bison from the FSF too.) + +If no config file is included for your system, start by copying one +for a similar system. One way of determining the defines needed is to +try to load gawk with nothing defined and see what routines are +unresolved by the loader. This should give you a good idea of how to +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. +For an Atari there is an atari directory and similarly one for VMS. + +Chapter 16 of The GAWK Manual discusses configuration in detail. + +After successful compilation, do 'make test' to run a small test +suite. There should be no output from the 'cmp' invocations except in +the cases where there are small differences in floating point values. +If there are other differences, please investigate and report the +problem. + +PRINTING THE MANUAL + +The 'support' directory contains texinfo.tex 2.65, 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. + +CAVEATS + +The existence of a patchlevel.h file does *N*O*T* imply a commitment on +our part to issue bug fixes or patches. It is there in case we should +decide to do so. + +BUG REPORTS AND FIXES (Un*x systems): + +Please coordinate changes through David Trueman and/or Arnold Robbins. + +David Trueman +Department of Mathematics, Statistics and Computing Science, +Dalhousie University, Halifax, Nova Scotia, Canada + +UUCP: {uunet utai watmath}!dalcs!david +INTERNET: david@cs.dal.ca + +Arnold Robbins +1736 Reindeer Drive +Atlanta, GA, 30329, USA + +INTERNET: arnold@skeeve.atl.ga.us +UUCP: { gatech, emory, emoryu1 }!skeeve!arnold + +BUG REPORTS AND FIXES (non-Unix ports): + +MS-DOS: + Scott Deifik + AMGEN Inc. + Amgen Center, Bldg.17-Dept.393 + Thousand Oaks, CA 91320-1789 + Tel-805-499-5725 ext.4677 + Fax-805-498-0358 + scottd@amgen.com + +VMS: + Pat Rankin + rankin@eql.caltech.edu (e-mail only) + +Atari ST: + Michal Jaegermann + NTOMCZAK@vm.ucs.UAlberta.CA (e-mail only) diff --git a/gnu/usr.bin/awk/array.c b/gnu/usr.bin/awk/array.c new file mode 100644 index 0000000000..59be340c04 --- /dev/null +++ b/gnu/usr.bin/awk/array.c @@ -0,0 +1,293 @@ +/* + * array.c - routines for associative arrays. + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +static NODE *assoc_find P((NODE *symbol, NODE *subs, int hash1)); + +NODE * +concat_exp(tree) +register NODE *tree; +{ + register NODE *r; + char *str; + char *s; + unsigned len; + int offset; + int subseplen; + char *subsep; + + if (tree->type != Node_expression_list) + return force_string(tree_eval(tree)); + r = force_string(tree_eval(tree->lnode)); + if (tree->rnode == NULL) + return r; + subseplen = SUBSEP_node->lnode->stlen; + subsep = SUBSEP_node->lnode->stptr; + len = r->stlen + subseplen + 2; + emalloc(str, char *, len, "concat_exp"); + memcpy(str, r->stptr, r->stlen+1); + s = str + r->stlen; + free_temp(r); + tree = tree->rnode; + while (tree) { + if (subseplen == 1) + *s++ = *subsep; + else { + memcpy(s, subsep, subseplen+1); + s += subseplen; + } + r = force_string(tree_eval(tree->lnode)); + len += r->stlen + subseplen; + offset = s - str; + erealloc(str, char *, len, "concat_exp"); + s = str + offset; + memcpy(s, r->stptr, r->stlen+1); + s += r->stlen; + free_temp(r); + tree = tree->rnode; + } + r = make_str_node(str, s - str, ALREADY_MALLOCED); + r->flags |= TEMP; + return r; +} + +/* Flush all the values in symbol[] before doing a split() */ +void +assoc_clear(symbol) +NODE *symbol; +{ + int i; + NODE *bucket, *next; + + if (symbol->var_array == 0) + return; + for (i = 0; i < HASHSIZE; i++) { + for (bucket = symbol->var_array[i]; bucket; bucket = next) { + next = bucket->ahnext; + unref(bucket->ahname); + unref(bucket->ahvalue); + freenode(bucket); + } + symbol->var_array[i] = 0; + } +} + +/* + * calculate the hash function of the string in subs + */ +unsigned int +hash(s, len) +register char *s; +register int len; +{ + register unsigned long h = 0, g; + + while (len--) { + h = (h << 4) + *s++; + g = (h & 0xf0000000); + if (g) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + if (h < HASHSIZE) + return h; + else + return h%HASHSIZE; +} + +/* + * locate symbol[subs] + */ +static NODE * /* NULL if not found */ +assoc_find(symbol, subs, hash1) +NODE *symbol; +register NODE *subs; +int hash1; +{ + register NODE *bucket, *prev = 0; + + for (bucket = symbol->var_array[hash1]; bucket; bucket = bucket->ahnext) { + if (cmp_nodes(bucket->ahname, subs) == 0) { + if (prev) { /* move found to front of chain */ + prev->ahnext = bucket->ahnext; + bucket->ahnext = symbol->var_array[hash1]; + symbol->var_array[hash1] = bucket; + } + return bucket; + } else + prev = bucket; /* save previous list entry */ + } + return NULL; +} + +/* + * test whether the array element symbol[subs] exists or not + */ +int +in_array(symbol, subs) +NODE *symbol, *subs; +{ + register int hash1; + + if (symbol->type == Node_param_list) + symbol = stack_ptr[symbol->param_cnt]; + if (symbol->var_array == 0) + return 0; + subs = concat_exp(subs); /* concat_exp returns a string node */ + hash1 = hash(subs->stptr, subs->stlen); + if (assoc_find(symbol, subs, hash1) == NULL) { + free_temp(subs); + return 0; + } else { + free_temp(subs); + return 1; + } +} + +/* + * SYMBOL is the address of the node (or other pointer) being dereferenced. + * SUBS is a number or string used as the subscript. + * + * Find SYMBOL[SUBS] in the assoc array. Install it with value "" if it + * isn't there. Returns a pointer ala get_lhs to where its value is stored + */ +NODE ** +assoc_lookup(symbol, subs) +NODE *symbol, *subs; +{ + register int hash1; + 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); + symbol->type = Node_var_array; + } else { + bucket = assoc_find(symbol, subs, hash1); + if (bucket != NULL) { + free_temp(subs); + return &(bucket->ahvalue); + } + } + + /* It's not there, install it. */ + if (do_lint && subs->stlen == 0) + warning("subscript of array `%s' is null string", + symbol->vname); + getnode(bucket); + bucket->type = Node_ahash; + if (subs->flags & TEMP) + bucket->ahname = dupnode(subs); + else { + unsigned int saveflags = subs->flags; + + subs->flags &= ~MALLOC; + bucket->ahname = dupnode(subs); + subs->flags = saveflags; + } + free_temp(subs); + + /* array subscripts are strings */ + bucket->ahname->flags &= ~NUMBER; + bucket->ahname->flags |= STRING; + bucket->ahvalue = Nnull_string; + bucket->ahnext = symbol->var_array[hash1]; + symbol->var_array[hash1] = bucket; + return &(bucket->ahvalue); +} + +void +do_delete(symbol, tree) +NODE *symbol, *tree; +{ + register int hash1; + register NODE *bucket, *last; + NODE *subs; + + if (symbol->type == Node_param_list) + symbol = stack_ptr[symbol->param_cnt]; + if (symbol->var_array == 0) + return; + subs = concat_exp(tree); /* concat_exp returns string node */ + hash1 = hash(subs->stptr, subs->stlen); + + last = NULL; + for (bucket = symbol->var_array[hash1]; bucket; last = bucket, bucket = bucket->ahnext) + if (cmp_nodes(bucket->ahname, subs) == 0) + break; + free_temp(subs); + if (bucket == NULL) + return; + if (last) + last->ahnext = bucket->ahnext; + else + symbol->var_array[hash1] = bucket->ahnext; + unref(bucket->ahname); + unref(bucket->ahvalue); + freenode(bucket); +} + +void +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); +} + +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; + return; + } + lookat->arr_ptr++; + if (lookat->arr_ptr < lookat->arr_end) + lookat->bucket = *(lookat->arr_ptr); + else + lookat->retval = NULL; + } + return; +} diff --git a/gnu/usr.bin/awk/awk.1 b/gnu/usr.bin/awk/awk.1 new file mode 100644 index 0000000000..0338485e8d --- /dev/null +++ b/gnu/usr.bin/awk/awk.1 @@ -0,0 +1,1873 @@ +.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" +.SH NAME +gawk \- pattern scanning and processing language +.SH SYNOPSIS +.B gawk +[ POSIX or GNU style options ] +.B \-f +.I program-file +[ +.B \-\^\- +] file .\^.\^. +.br +.B gawk +[ POSIX or GNU style options ] +[ +.B \-\^\- +] +.I program-text +file .\^.\^. +.SH DESCRIPTION +.I Gawk +is the GNU Project's implementation of the AWK programming language. +It conforms to the definition of the language in +the \*(PX 1003.2 Command Language And Utilities Standard. +This version in turn is based on the description in +.IR "The AWK Programming Language" , +by Aho, Kernighan, and Weinberger, +with the additional features defined in the System V Release 4 version +of \*(UX +.IR awk . +.I Gawk +also provides some GNU-specific extensions. +.PP +The command line consists of options to +.I gawk +itself, the AWK program text (if not supplied via the +.B \-f +or +.B \-\^\-file +options), and values to be made +available in the +.B ARGC +and +.B ARGV +pre-defined AWK variables. +.SH OPTIONS +.PP +.I Gawk +options may be either the traditional \*(PX one letter options, +or the GNU style long options. \*(PX style options start with a single ``\-'', +while GNU long options start with ``\-\^\-''. +GNU style long options are provided for both GNU-specific features and +for \*(PX mandated features. Other implementations of the AWK language +are likely to only accept the traditional one letter options. +.PP +Following the \*(PX standard, +.IR gawk -specific +options are supplied via arguments to the +.B \-W +option. Multiple +.B \-W +options may be supplied, or multiple arguments may be supplied together +if they are separated by commas, or enclosed in quotes and separated +by white space. +Case is ignored in arguments to the +.B \-W +option. +Each +.B \-W +option has a corresponding GNU style long option, as detailed below. +.PP +.I Gawk +accepts the following options. +.TP +.PD 0 +.BI \-F " fs" +.TP +.PD +.BI \-\^\-field-separator= fs +Use +.I fs +for the input field separator (the value of the +.B FS +predefined +variable). +.TP +.PD 0 +\fB\-v\fI var\fB\^=\^\fIval\fR +.TP +.PD +\fB\-\^\-assign=\fIvar\fB\^=\^\fIval\fR +Assign the value +.IR val , +to the variable +.IR var , +before execution of the program begins. +Such variable values are available to the +.B BEGIN +block of an AWK program. +.TP +.PD 0 +.BI \-f " program-file" +.TP +.PD +.BI \-\^\-file= program-file +Read the AWK program source from the file +.IR program-file , +instead of from the first command line argument. +Multiple +.B \-f +(or +.BR \-\^\-file ) +options may be used. +.TP \w'\fB\-\^\-copyright\fR'u+1n +.PD 0 +.B "\-W compat" +.TP +.PD +.B \-\^\-compat +Run in +.I compatibility +mode. In compatibility mode, +.I gawk +behaves identically to \*(UX +.IR awk ; +none of the GNU-specific extensions are recognized. +See +.BR "GNU EXTENSIONS" , +below, for more information. +.TP +.PD 0 +.B "\-W copyleft" +.TP +.PD 0 +.B "\-W copyright" +.TP +.PD 0 +.B \-\^\-copyleft +.TP +.PD +.B \-\^\-copyright +Print the short version of the GNU copyright information message on +the error output. +.TP +.PD 0 +.B "\-W help" +.TP +.PD 0 +.B "\-W usage" +.TP +.PD 0 +.B \-\^\-help +.TP +.PD +.B \-\^\-usage +Print a relatively short summary of the available options on +the error output. +.TP +.PD 0 +.B "\-W lint" +.TP +.PD 0 +.B \-\^\-lint +Provide warnings about constructs that are +dubious or non-portable to other AWK implementations. +.ig +.\" This option is left undocumented, on purpose. +.TP +.PD 0 +.B "\-W nostalgia" +.TP +.PD +.B \-\^\-nostalgia +Provide a moment of nostalgia for long time +.I awk +users. +.. +.TP +.PD 0 +.B "\-W posix" +.TP +.PD +.B \-\^\-posix +This turns on +.I compatibility +mode, with the following additional restrictions: +.RS +.TP \w'\(bu'u+1n +\(bu +.B \ex +escape sequences are not recognized. +.TP +\(bu +The synonym +.B func +for the keyword +.B function +is not recognized. +.TP +\(bu +The operators +.B ** +and +.B **= +cannot be used in place of +.B ^ +and +.BR ^= . +.RE +.TP +.PD 0 +.BI "\-W source=" program-text +.TP +.PD +.BI \-\^\-source= program-text +Use +.I program-text +as AWK program source code. +This option allows the easy intermixing of library functions (used via the +.B \-f +and +.B \-\^\-file +options) with source code entered on the command line. +It is intended primarily for medium to large size AWK programs used +in shell scripts. +.sp .5 +The +.B "\-W source=" +form of this option uses the rest of the command line argument for +.IR program-text ; +no other options to +.B \-W +will be recognized in the same argument. +.TP +.PD 0 +.B "\-W version" +.TP +.PD +.B \-\^\-version +Print version information for this particular copy of +.I gawk +on the error output. +This is useful mainly for knowing if the current copy of +.I gawk +on your system +is up to date with respect to whatever the Free Software Foundation +is distributing. +.TP +.B \-\^\- +Signal the end of options. This is useful to allow further arguments to the +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. +.SH AWK PROGRAM EXECUTION +.PP +An AWK program consists of a sequence of pattern-action statements +and optional function definitions. +.RS +.PP +\fIpattern\fB { \fIaction statements\fB }\fR +.br +\fBfunction \fIname\fB(\fIparameter list\fB) { \fIstatements\fB }\fR +.RE +.PP +.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. +The +.B \-f +option may be used multiple times on the command line. +.I Gawk +will read the program text as if all the +.IR program-file s +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). +.PP +The environment variable +.B AWKPATH +specifies a search path to use when finding source files named with +the +.B \-f +option. If this variable does not exist, the default path is +\fB".:/usr/lib/awk:/usr/local/lib/awk"\fR. +If a file name given to the +.B \-f +option contains a ``/'' character, no path search is performed. +.PP +.I Gawk +executes AWK programs in the following order. +First, +.I gawk +compiles the program into an internal form. +Next, all variable assignments specified via the +.B \-v +option are performed. Then, +.I gawk +executes the code in the +.B BEGIN +block(s) (if any), +and then proceeds to read +each file named in the +.B ARGV +array. +If there are no files named on the command line, +.I gawk +reads the standard input. +.PP +If a filename on the command line has the form +.IB var = val +it is treated as a variable assignment. The variable +.I var +will be assigned the value +.IR val . +(This happens after any +.B BEGIN +block(s) have been run.) +Command line variable assignment +is most useful for dynamically assigning values to the variables +AWK uses to control how input is broken into fields and records. It +is also useful for controlling state if multiple passes are needed over +a single data file. +.PP +If the value of a particular element of +.B ARGV +is empty (\fB""\fR), +.I gawk +skips over it. +.PP +For each line in the input, +.I gawk +tests to see if it matches any +.I pattern +in the AWK program. +For each pattern that the line matches, the associated +.I action +is executed. +The patterns are tested in the order they occur in the program. +.PP +Finally, after all the input is exhausted, +.I gawk +executes the code in the +.B END +block(s) (if any). +.SH VARIABLES AND FIELDS +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. +Several pre-defined variables are set as a program +runs; these will be described as needed and summarized below. +.SS Fields +.PP +As each input line is read, +.I gawk +splits the line into +.IR fields , +using the value of the +.B FS +variable as the field separator. +If +.B FS +is a single character, fields are separated by that character. +Otherwise, +.B FS +is expected to be a full regular expression. +In the special case that +.B FS +is a single blank, fields are separated +by runs of blanks and/or tabs. +Note that the value of +.B IGNORECASE +(see below) will also affect how fields are split when +.B FS +is a regular expression. +.PP +If the +.B FIELDWIDTHS +variable is set to a space separated list of numbers, each field is +expected to have fixed width, and +.I gawk +will split up the record using the specified widths. The value of +.B FS +is ignored. +Assigning a new value to +.B FS +overrides the use of +.BR FIELDWIDTHS , +and restores the default behavior. +.PP +Each field in the input line may be referenced by its position, +.BR $1 , +.BR $2 , +and so on. +.B $0 +is the whole line. The value of a field may be assigned to as well. +Fields need not be referenced by constants: +.RS +.PP +.ft B +n = 5 +.br +print $n +.ft R +.RE +.PP +prints the fifth field in the input line. +The variable +.B NF +is set to the total number of fields in the input line. +.PP +References to non-existent fields (i.e. fields after +.BR $NF ) +produce the null-string. However, assigning to a non-existent field +(e.g., +.BR "$(NF+2) = 5" ) +will increase the value of +.BR NF , +create any intervening fields with the null string as their value, and +cause the value of +.B $0 +to be recomputed, with the fields being separated by the value of +.BR OFS . +.SS Built-in Variables +.PP +AWK's built-in variables are: +.PP +.TP \w'\fBFIELDWIDTHS\fR'u+1n +.B ARGC +The number of command line arguments (does not include options to +.IR gawk , +or the program source). +.TP +.B ARGIND +The index in +.B ARGV +of the current file being processed. +.TP +.B ARGV +Array of command line arguments. The array is indexed from +0 to +.B ARGC +\- 1. +Dynamically changing the contents of +.B ARGV +can control the files used for data. +.TP +.B CONVFMT +The conversion format for numbers, \fB"%.6g"\fR, by default. +.TP +.B ENVIRON +An array containing the values of the current environment. +The array is indexed by the environment variables, each element being +the value of that variable (e.g., \fBENVIRON["HOME"]\fP might be +.BR /u/arnold ). +Changing this array does not affect the environment seen by programs which +.I gawk +spawns via redirection or the +.B system() +function. +(This may change in a future version of +.IR gawk .) +.\" but don't hold your breath... +.TP +.B ERRNO +If a system error occurs either doing a redirection for +.BR getline , +during a read for +.BR getline , +or during a +.BR close , +then +.B ERRNO +will contain +a string describing the error. +.TP +.B FIELDWIDTHS +A white-space separated list of fieldwidths. When set, +.I gawk +parses the input into fields of fixed width, instead of using the +value of the +.B FS +variable as the field separator. +The fixed field width facility is still experimental; expect the +semantics to change as +.I gawk +evolves over time. +.TP +.B FILENAME +The name of the current input file. +If no files are specified on the command line, the value of +.B FILENAME +is ``\-''. +.TP +.B FNR +The input record number in the current input file. +.TP +.B FS +The input field separator, a blank by default. +.TP +.B IGNORECASE +Controls the case-sensitivity of all regular expression operations. If +.B IGNORECASE +has a non-zero value, then pattern matching in rules, +field splitting with +.BR FS , +regular expression +matching with +.B ~ +and +.BR !~ , +and the +.BR gsub() , +.BR index() , +.BR match() , +.BR split() , +and +.B sub() +pre-defined functions will all ignore case when doing regular expression +operations. Thus, if +.B IGNORECASE +is not equal to zero, +.B /aB/ +matches all of the strings \fB"ab"\fP, \fB"aB"\fP, \fB"Ab"\fP, +and \fB"AB"\fP. +As with all AWK variables, the initial value of +.B IGNORECASE +is zero, so all regular expression operations are normally case-sensitive. +.TP +.B NF +The number of fields in the current input record. +.TP +.B NR +The total number of input records seen so far. +.TP +.B OFMT +The output format for numbers, \fB"%.6g"\fR, by default. +.TP +.B OFS +The output field separator, a blank by default. +.TP +.B ORS +The output record separator, by default a newline. +.TP +.B RS +The input record separator, by default a newline. +.B RS +is exceptional in that only the first character of its string +value is used for separating records. +(This will probably change in a future release of +.IR gawk .) +If +.B RS +is set to the null string, then records are separated by +blank lines. +When +.B RS +is set to the null string, then the newline character always acts as +a field separator, in addition to whatever value +.B FS +may have. +.TP +.B RSTART +The index of the first character matched by +.BR match() ; +0 if no match. +.TP +.B RLENGTH +The length of the string matched by +.BR match() ; +\-1 if no match. +.TP +.B SUBSEP +The character used to separate multiple subscripts in array +elements, by default \fB"\e034"\fR. +.SS Arrays +.PP +Arrays are subscripted with an expression between square brackets +.RB ( [ " and " ] ). +If the expression is an expression list +.RI ( expr ", " expr " ...)" +then the array subscript is a string consisting of the +concatenation of the (string) value of each expression, +separated by the value of the +.B SUBSEP +variable. +This facility is used to simulate multiply dimensioned +arrays. For example: +.PP +.RS +.ft B +i = "A" ;\^ j = "B" ;\^ k = "C" +.br +x[i, j, k] = "hello, world\en" +.ft R +.RE +.PP +assigns the string \fB"hello, world\en"\fR to the element of the array +.B x +which is indexed by the string \fB"A\e034B\e034C"\fR. All arrays in AWK +are associative, i.e. indexed by string values. +.PP +The special operator +.B in +may be used in an +.B if +or +.B while +statement to see if an array has an index consisting of a particular +value. +.PP +.RS +.ft B +.nf +if (val in array) + print array[val] +.fi +.ft +.RE +.PP +If the array has multiple subscripts, use +.BR "(i, j) in array" . +.PP +The +.B in +construct may also be used in a +.B for +loop to iterate over all the elements of an array. +.PP +An element may be deleted from an array using the +.B delete +statement. +.SS Variable Typing And Conversion +.PP +Variables and fields +may be (floating point) numbers, or strings, or both. How the +value of a variable is interpreted depends upon its context. If used in +a numeric expression, it will be treated as a number, if used as a string +it will be treated as a string. +.PP +To force a variable to be treated as a number, add 0 to it; to force it +to be treated as a string, concatenate it with the null string. +.PP +When a string must be converted to a number, the conversion is accomplished +using +.IR atof (3). +A number is converted to a string by using the value of +.B CONVFMT +as a format string for +.IR sprintf (3), +with the numeric value of the variable as the argument. +However, even though all numbers in AWK are floating-point, +integral values are +.I always +converted as integers. Thus, given +.PP +.RS +.ft B +.nf +CONVFMT = "%2.2f" +a = 12 +b = a "" +.fi +.ft R +.RE +.PP +the variable +.B b +has a value of \fB"12"\fR and not \fB"12.00"\fR. +.PP +.I Gawk +performs comparisons as follows: +If two variables are numeric, they are compared numerically. +If one value is numeric and the other has a string value that is a +``numeric string,'' then comparisons are also done numerically. +Otherwise, the numeric value is converted to a string and a string +comparison is performed. +Two strings are compared, of course, as strings. +According to the \*(PX standard, even if two strings are +numeric strings, a numeric comparison is performed. However, this is +clearly incorrect, and +.I gawk +does not do this. +.PP +Uninitialized variables have the numeric value 0 and the string value "" +(the null, or empty, string). +.SH PATTERNS AND ACTIONS +AWK is a line oriented language. The pattern comes first, and then the +action. Action statements are enclosed in +.B { +and +.BR } . +Either the pattern may be missing, or the action may be missing, but, +of course, not both. If the pattern is missing, the action will be +executed for every single line of input. +A missing action is equivalent to +.RS +.PP +.B "{ print }" +.RE +.PP +which prints the entire line. +.PP +Comments begin with the ``#'' character, and continue until the +end of the line. +Blank lines may be used to separate statements. +Normally, a statement ends with a newline, however, this is not the +case for lines ending in +a ``,'', ``{'', ``?'', ``:'', ``&&'', or ``||''. +Lines ending in +.B do +or +.B else +also have their statements automatically continued on the following line. +In other cases, a line can be continued by ending it with a ``\e'', +in which case the newline will be ignored. +.PP +Multiple statements may +be put on one line by separating them with a ``;''. +This applies to both the statements within the action part of a +pattern-action pair (the usual case), +and to the pattern-action statements themselves. +.SS Patterns +AWK patterns may be one of the following: +.PP +.RS +.nf +.B BEGIN +.B END +.BI / "regular expression" / +.I "relational expression" +.IB pattern " && " pattern +.IB pattern " || " pattern +.IB pattern " ? " pattern " : " pattern +.BI ( pattern ) +.BI ! " pattern" +.IB pattern1 ", " pattern2 +.fi +.RE +.PP +.B BEGIN +and +.B END +are two special kinds of patterns which are not tested against +the input. +The action parts of all +.B BEGIN +patterns are merged as if all the statements had +been written in a single +.B BEGIN +block. They are executed before any +of the input is read. Similarly, all the +.B END +blocks are merged, +and executed when all the input is exhausted (or when an +.B exit +statement is executed). +.B BEGIN +and +.B END +patterns cannot be combined with other patterns in pattern expressions. +.B BEGIN +and +.B END +patterns cannot have missing action parts. +.PP +For +.BI / "regular expression" / +patterns, the associated statement is executed for each input line that matches +the regular expression. +Regular expressions are the same as those in +.IR egrep (1), +and are summarized below. +.PP +A +.I "relational expression" +may use any of the operators defined below in the section on actions. +These generally test whether certain fields match certain regular expressions. +.PP +The +.BR && , +.BR || , +and +.B ! +operators are logical AND, logical OR, and logical NOT, respectively, as in C. +They do short-circuit evaluation, also as in C, and are used for combining +more primitive pattern expressions. As in most languages, parentheses +may be used to change the order of evaluation. +.PP +The +.B ?\^: +operator is like the same operator in C. If the first pattern is true +then the pattern used for testing is the second pattern, otherwise it is +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. +It matches all input records starting with a line that matches +.IR pattern1 , +and continuing until a record that matches +.IR pattern2 , +inclusive. It does not combine with any other sort of pattern expression. +.SS Regular Expressions +Regular expressions are the extended kind found in +.IR egrep . +They are composed of characters as follows: +.TP \w'\fB[^\fIabc...\fB]\fR'u+2n +.I c +matches the non-metacharacter +.IR c . +.TP +.I \ec +matches the literal character +.IR c . +.TP +.B . +matches any character except newline. +.TP +.B ^ +matches the beginning of a line or a string. +.TP +.B $ +matches the end of a line or a string. +.TP +.BI [ abc... ] +character class, matches any of the characters +.IR abc... . +.TP +.BI [^ abc... ] +negated character class, matches any character except +.I abc... +and newline. +.TP +.IB r1 | r2 +alternation: matches either +.I r1 +or +.IR r2 . +.TP +.I r1r2 +concatenation: matches +.IR r1 , +and then +.IR r2 . +.TP +.IB r + +matches one or more +.IR r 's. +.TP +.IB r * +matches zero or more +.IR r 's. +.TP +.IB r ? +matches zero or one +.IR r 's. +.TP +.BI ( r ) +grouping: matches +.IR r . +.PP +The escape sequences that are valid in string constants (see below) +are also legal in regular expressions. +.SS Actions +Action statements are enclosed in braces, +.B { +and +.BR } . +Action statements consist of the usual assignment, conditional, and looping +statements found in most languages. The operators, control statements, +and input/output statements +available are patterned after those in C. +.SS Operators +.PP +The operators in AWK, in order of increasing precedence, are +.PP +.TP "\w'\fB*= /= %= ^=\fR'u+1n" +.PD 0 +.B "= += \-=" +.TP +.PD +.B "*= /= %= ^=" +Assignment. Both absolute assignment +.BI ( var " = " value ) +and operator-assignment (the other forms) are supported. +.TP +.B ?: +The C conditional expression. This has the form +.IB expr1 " ? " expr2 " : " expr3\c +\&. If +.I expr1 +is true, the value of the expression is +.IR expr2 , +otherwise it is +.IR expr3 . +Only one of +.I expr2 +and +.I expr3 +is evaluated. +.TP +.B || +Logical OR. +.TP +.B && +Logical AND. +.TP +.B "~ !~" +Regular expression match, negated match. +.B NOTE: +Do not use a constant regular expression +.RB ( /foo/ ) +on the left-hand side of a +.B ~ +or +.BR !~ . +Only use one on the right-hand side. The expression +.BI "/foo/ ~ " exp +has the same meaning as \fB(($0 ~ /foo/) ~ \fIexp\fB)\fR. +This is usually +.I not +what was intended. +.TP +.PD 0 +.B "< >" +.TP +.PD 0 +.B "<= >=" +.TP +.PD +.B "!= ==" +The regular relational operators. +.TP +.I blank +String concatenation. +.TP +.B "+ \-" +Addition and subtraction. +.TP +.B "* / %" +Multiplication, division, and modulus. +.TP +.B "+ \- !" +Unary plus, unary minus, and logical negation. +.TP +.B ^ +Exponentiation (\fB**\fR may also be used, and \fB**=\fR for +the assignment operator). +.TP +.B "++ \-\^\-" +Increment and decrement, both prefix and postfix. +.TP +.B $ +Field reference. +.SS Control Statements +.PP +The control statements are +as follows: +.PP +.RS +.nf +\fBif (\fIcondition\fB) \fIstatement\fR [ \fBelse\fI statement \fR] +\fBwhile (\fIcondition\fB) \fIstatement \fR +\fBdo \fIstatement \fBwhile (\fIcondition\fB)\fR +\fBfor (\fIexpr1\fB; \fIexpr2\fB; \fIexpr3\fB) \fIstatement\fR +\fBfor (\fIvar \fBin\fI array\fB) \fIstatement\fR +\fBbreak\fR +\fBcontinue\fR +\fBdelete \fIarray\^\fB[\^\fIindex\^\fB]\fR +\fBexit\fR [ \fIexpression\fR ] +\fB{ \fIstatements \fB} +.fi +.RE +.SS "I/O Statements" +.PP +The input/output statements are as follows: +.PP +.TP "\w'\fBprintf \fIfmt, expr-list\fR'u+1n" +.BI close( filename ) +Close file (or pipe, see below). +.TP +.B getline +Set +.B $0 +from next input record; set +.BR NF , +.BR NR , +.BR FNR . +.TP +.BI "getline <" file +Set +.B $0 +from next record of +.IR file ; +set +.BR NF . +.TP +.BI getline " var" +Set +.I var +from next input record; set +.BR NF , +.BR FNR . +.TP +.BI getline " var" " <" file +Set +.I var +from next record of +.IR file . +.TP +.B next +Stop processing the current input record. The next input record +is read and processing starts over with the first pattern in the +AWK program. If the end of the input data is reached, the +.B END +block(s), if any, are executed. +.TP +.B "next file" +Stop processing the current input file. The next input record read +comes from the next input file. +.B FILENAME +is updated, +.B FNR +is reset to 1, and processing starts over with the first pattern in the +AWK program. If the end of the input data is reached, the +.B END +block(s), if any, are executed. +.TP +.B print +Prints the current record. +.TP +.BI print " expr-list" +Prints expressions. +.TP +.BI print " expr-list" " >" file +Prints expressions on +.IR file . +.TP +.BI printf " fmt, expr-list" +Format and print. +.TP +.BI printf " fmt, expr-list" " >" file +Format and print on +.IR file . +.TP +.BI system( cmd-line ) +Execute the command +.IR cmd-line , +and return the exit status. +(This may not be available on non-\*(PX systems.) +.PP +Other input/output redirections are also allowed. For +.B print +and +.BR printf , +.BI >> file +appends output to the +.IR file , +while +.BI | " command" +writes on a pipe. +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. +.SS The \fIprintf\fP\^ Statement +.PP +The AWK versions of the +.B printf +statement and +.B sprintf() +function +(see below) +accept the following conversion specification formats: +.TP +.B %c +An \s-1ASCII\s+1 character. +If the argument used for +.B %c +is numeric, it is treated as a character and printed. +Otherwise, the argument is assumed to be a string, and the only first +character of that string is printed. +.TP +.B %d +A decimal number (the integer part). +.TP +.B %i +Just like +.BR %d . +.TP +.B %e +A floating point number of the form +.BR [\-]d.ddddddE[+\^\-]dd . +.TP +.B %f +A floating point number of the form +.BR [\-]ddd.dddddd . +.TP +.B %g +Use +.B e +or +.B f +conversion, whichever is shorter, with nonsignificant zeros suppressed. +.TP +.B %o +An unsigned octal number (again, an integer). +.TP +.B %s +A character string. +.TP +.B %x +An unsigned hexadecimal number (an integer). +.TP +.B %X +Like +.BR %x , +but using +.B ABCDEF +instead of +.BR abcdef . +.TP +.B %% +A single +.B % +character; no argument is converted. +.PP +There are optional, additional parameters that may lie between the +.B % +and the control letter: +.TP +.B \- +The expression should be left-justified within its field. +.TP +.I width +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. +.TP +.BI . prec +A number indicating the maximum width of strings or digits to the right +of the decimal point. +.PP +The dynamic +.I width +and +.I prec +capabilities of the \*(AN C +.B printf() +routines are supported. +A +.B * +in place of either the +.B width +or +.B prec +specifications will cause their values to be taken from +the argument list to +.B printf +or +.BR sprintf() . +.SS Special File Names +.PP +When doing I/O redirection from either +.B print +or +.B printf +into a file, +or via +.B getline +from a file, +.I gawk +recognizes certain special filenames internally. These filenames +allow access to open file descriptors inherited from +.IR gawk 's +parent process (usually the shell). +Other special filenames provide access information about the running +.B gawk +process. +The filenames are: +.TP \w'\fB/dev/stdout\fR'u+1n +.B /dev/pid +Reading this file returns the process ID of the current process, +in decimal, terminated with a newline. +.TP +.B /dev/ppid +Reading this file returns the parent process ID of the current process, +in decimal, terminated with a newline. +.TP +.B /dev/pgrpid +Reading this file returns the process group ID of the current process, +in decimal, terminated with a newline. +.TP +.B /dev/user +Reading this file returns a single record terminated with a newline. +The fields are separated with blanks. +.B $1 +is the value of the +.IR getuid (2) +system call, +.B $2 +is the value of the +.IR geteuid (2) +system call, +.B $3 +is the value of the +.IR getgid (2) +system call, and +.B $4 +is the value of the +.IR getegid (2) +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.) +.TP +.B /dev/stdin +The standard input. +.TP +.B /dev/stdout +The standard output. +.TP +.B /dev/stderr +The standard error output. +.TP +.BI /dev/fd/\^ n +The file associated with the open file descriptor +.IR n . +.PP +These are particularly useful for error messages. For example: +.PP +.RS +.ft B +print "You blew it!" > "/dev/stderr" +.ft R +.RE +.PP +whereas you would otherwise have to use +.PP +.RS +.ft B +print "You blew it!" | "cat 1>&2" +.ft R +.RE +.PP +These file names may also be used on the command line to name data files. +.SS Numeric Functions +.PP +AWK has the following pre-defined arithmetic functions: +.PP +.TP \w'\fBsrand(\^\fIexpr\^\fB)\fR'u+1n +.BI atan2( y , " x" ) +returns the arctangent of +.I y/x +in radians. +.TP +.BI cos( expr ) +returns the cosine in radians. +.TP +.BI exp( expr ) +the exponential function. +.TP +.BI int( expr ) +truncates to integer. +.TP +.BI log( expr ) +the natural logarithm function. +.TP +.B rand() +returns a random number between 0 and 1. +.TP +.BI sin( expr ) +returns the sine in radians. +.TP +.BI sqrt( expr ) +the square root function. +.TP +.BI srand( expr ) +use +.I expr +as a new seed for the random number generator. If no +.I expr +is provided, the time of day will be used. +The return value is the previous seed for the random +number generator. +.SS String Functions +.PP +AWK has the following pre-defined string functions: +.PP +.TP "\w'\fBsprintf(\^\fIfmt\fB\^, \fIexpr-list\^\fB)\fR'u+1n" +\fBgsub(\fIr\fB, \fIs\fB, \fIt\fB)\fR +for each substring matching the regular expression +.I r +in the string +.IR t , +substitute the string +.IR s , +and return the number of substitutions. +If +.I t +is not supplied, use +.BR $0 . +.TP +.BI index( s , " t" ) +returns the index of the string +.I t +in the string +.IR s , +or 0 if +.I t +is not present. +.TP +.BI length( s ) +returns the length of the string +.IR s , +or the length of +.B $0 +if +.I s +is not supplied. +.TP +.BI match( s , " r" ) +returns the position in +.I s +where the regular expression +.I r +occurs, or 0 if +.I r +is not present, and sets the values of +.B RSTART +and +.BR RLENGTH . +.TP +\fBsplit(\fIs\fB, \fIa\fB, \fIr\fB)\fR +splits the string +.I s +into the array +.I a +on the regular expression +.IR r , +and returns the number of fields. If +.I r +is omitted, +.B FS +is used instead. +.TP +.BI sprintf( fmt , " expr-list" ) +prints +.I expr-list +according to +.IR fmt , +and returns the resulting string. +.TP +\fBsub(\fIr\fB, \fIs\fB, \fIt\fB)\fR +just like +.BR gsub() , +but only the first matching substring is replaced. +.TP +\fBsubstr(\fIs\fB, \fIi\fB, \fIn\fB)\fR +returns the +.IR n -character +substring of +.I s +starting at +.IR i . +If +.I n +is omitted, the rest of +.I s +is used. +.TP +.BI tolower( str ) +returns a copy of the string +.IR str , +with all the upper-case characters in +.I str +translated to their corresponding lower-case counterparts. +Non-alphabetic characters are left unchanged. +.TP +.BI toupper( str ) +returns a copy of the string +.IR str , +with all the lower-case characters in +.I str +translated to their corresponding upper-case counterparts. +Non-alphabetic characters are left unchanged. +.SS Time Functions +.PP +Since one of the primary uses of AWK programs is processing log files +that contain time stamp information, +.I gawk +provides the following two functions for obtaining time stamps and +formatting them. +.PP +.TP "\w'\fBsystime()\fR'u+1n" +.B systime() +returns the current time of day as the number of seconds since the Epoch +(Midnight UTC, January 1, 1970 on \*(PX systems). +.TP +\fBstrftime(\fIformat\fR, \fItimestamp\fB)\fR +formats +.I timestamp +according to the specification in +.IR format. +The +.I timestamp +should be of the same form as returned by +.BR systime() . +If +.I timestamp +is missing, the current time of day is used. +See the specification for the +.B strftime() +function in \*(AN C for the format conversions that are +guaranteed to be available. +A public-domain version of +.IR strftime (3) +and a man page for it are shipped with +.IR gawk ; +if that version was used to build +.IR gawk , +then all of the conversions described in that man page are available to +.IR gawk. +.SS String Constants +.PP +String constants in AWK are sequences of characters enclosed +between double quotes (\fB"\fR). Within strings, certain +.I "escape sequences" +are recognized, as in C. These are: +.PP +.TP \w'\fB\e\^\fIddd\fR'u+1n +.B \e\e +A literal backslash. +.TP +.B \ea +The ``alert'' character; usually the \s-1ASCII\s+1 \s-1BEL\s+1 character. +.TP +.B \eb +backspace. +.TP +.B \ef +form-feed. +.TP +.B \en +new line. +.TP +.B \er +carriage return. +.TP +.B \et +horizontal tab. +.TP +.B \ev +vertical tab. +.TP +.BI \ex "\^hex digits" +The character represented by the string of hexadecimal digits following +the +.BR \ex . +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. +.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. +.TP +.BI \e c +The literal character +.IR c\^ . +.PP +The escape sequences may also be used inside constant regular expressions +(e.g., +.B "/[\ \et\ef\en\er\ev]/" +matches whitespace characters). +.SH FUNCTIONS +Functions in AWK are defined as follows: +.PP +.RS +\fBfunction \fIname\fB(\fIparameter list\fB) { \fIstatements \fB}\fR +.RE +.PP +Functions are executed when called from within the action parts of regular +pattern-action statements. Actual parameters supplied in the function +call are used to instantiate the formal parameters declared in the function. +Arrays are passed by reference, other variables are passed by value. +.PP +Since functions were not originally part of the AWK language, the provision +for local variables is rather clumsy: They are declared as extra parameters +in the parameter list. The convention is to separate local variables from +real parameters by extra spaces in the parameter list. For example: +.PP +.RS +.ft B +.nf +function f(p, q, a, b) { # a & b are local + ..... } + +/abc/ { ... ; f(1, 2) ; ... } +.fi +.ft R +.RE +.PP +The left parenthesis in a function call is required +to immediately follow the function name, +without any intervening white space. +This is to avoid a syntactic ambiguity with the concatenation operator. +This restriction does not apply to the built-in functions listed above. +.PP +Functions may call each other and may be recursive. +Function parameters used as local variables are initialized +to the null string and the number zero upon function invocation. +.PP +The word +.B func +may be used in place of +.BR function . +.SH EXAMPLES +.nf +Print and sort the login names of all users: + +.ft B + BEGIN { FS = ":" } + { print $1 | "sort" } + +.ft R +Count lines in a file: + +.ft B + { nlines++ } + END { print nlines } + +.ft R +Precede each line by its number in the file: + +.ft B + { print FNR, $0 } + +.ft R +Concatenate and line number (a variation on a theme): + +.ft B + { print NR, $0 } +.ft R +.fi +.SH SEE ALSO +.IR egrep (1) +.PP +.IR "The AWK Programming Language" , +Alfred V. Aho, Brian W. Kernighan, Peter J. Weinberger, +Addison-Wesley, 1988. ISBN 0-201-07981-X. +.PP +.IR "The GAWK Manual" , +Edition 0.15, published by the Free Software Foundation, 1993. +.SH POSIX COMPATIBILITY +A primary goal for +.I gawk +is compatibility with the \*(PX standard, as well as with the +latest version of \*(UX +.IR awk . +To this end, +.I gawk +incorporates the following user visible +features which are not described in the AWK book, +but are part of +.I awk +in System V Release 4, and are in the \*(PX standard. +.PP +The +.B \-v +option for assigning variables before program execution starts is new. +The book indicates that command line variable assignment happens when +.I awk +would otherwise open the argument as a file, which is after the +.B BEGIN +block is executed. However, in earlier implementations, when such an +assignment appeared before any file names, the assignment would happen +.I before +the +.B BEGIN +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. +(This feature was agreed upon by both the AT&T and GNU developers.) +.PP +The +.B \-W +option for implementation specific features is from the \*(PX standard. +.PP +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. +.PP +The AWK book does not define the return value of +.BR srand() . +The System V Release 4 version of \*(UX +.I awk +(and the \*(PX standard) +has it return the seed it was using, to allow keeping track +of random number sequences. Therefore +.B srand() +in +.I gawk +also returns its current seed. +.PP +Other new features are: +The use of multiple +.B \-f +options (from MKS +.IR awk ); +the +.B ENVIRON +array; the +.BR \ea , +and +.BR \ev +escape sequences (done originally in +.I gawk +and fed back into AT&T's); the +.B tolower() +and +.B toupper() +built-in functions (from AT&T); and the \*(AN C conversion specifications in +.B printf +(done first in AT&T's version). +.SH GNU EXTENSIONS +.I Gawk +has some extensions to \*(PX +.IR awk . +They are described in this section. All the extensions described here +can be disabled by +invoking +.I gawk +with the +.B "\-W compat" +option. +.PP +The following features of +.I gawk +are not available in +\*(PX +.IR awk . +.RS +.TP \w'\(bu'u+1n +\(bu +The +.B \ex +escape sequence. +.TP +\(bu +The +.B systime() +and +.B strftime() +functions. +.TP +\(bu +The special file names available for I/O redirection are not recognized. +.TP +\(bu +The +.B ARGIND +and +.B ERRNO +variables are not special. +.TP +\(bu +The +.B IGNORECASE +variable and its side-effects are not available. +.TP +\(bu +The +.B FIELDWIDTHS +variable and fixed width field splitting. +.TP +\(bu +No path search is performed for files named via the +.B \-f +option. Therefore the +.B AWKPATH +environment variable is not special. +.TP +\(bu +The use of +.B "next file" +to abandon processing of the current input file. +.RE +.PP +The AWK book does not define the return value of the +.B close() +function. +.IR Gawk\^ 's +.B close() +returns the value from +.IR fclose (3), +or +.IR pclose (3), +when closing a file or pipe, respectively. +.PP +When +.I gawk +is invoked with the +.B "\-W compat" +option, +if the +.I fs +argument to the +.B \-F +option is ``t'', then +.B FS +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 +has been specified. +.ig +.PP +If +.I gawk +was compiled for debugging, it will +accept the following additional options: +.TP +.PD 0 +.B \-Wparsedebug +.TP +.PD +.B \-\^\-parsedebug +Turn on +.IR yacc (1) +or +.IR bison (1) +debugging output during program parsing. +This option should only be of interest to the +.I gawk +maintainers, and may not even be compiled into +.IR gawk . +.. +.SH HISTORICAL FEATURES +There are two features of historical AWK implementations that +.I gawk +supports. +First, it is possible to call the +.B length() +built-in function not only with no argument, but even without parentheses! +Thus, +.RS +.PP +.ft B +a = length +.ft R +.RE +.PP +is the same as either of +.RS +.PP +.ft B +a = length() +.br +a = length($0) +.ft R +.RE +.PP +This feature is marked as ``deprecated'' in the \*(PX standard, and +.I gawk +will issue a warning about its use if +.B \-Wlint +is specified on the command line. +.PP +The other feature is the use of the +.B continue +statement outside the body of a +.BR while , +.BR for , +or +.B do +loop. Traditional AWK implementations have treated such usage as +equivalent to the +.B next +statement. +.I Gawk +will support this usage if +.B \-Wposix +has not been specified. +.SH BUGS +The +.B \-F +option is not necessary given the command line variable assignment feature; +it remains only for backwards compatibility. +.PP +If your system actually has support for +.B /dev/fd +and the associated +.BR /dev/stdin , +.BR /dev/stdout , +and +.B /dev/stderr +files, you may get different output from +.I gawk +than you would get on a system without those files. When +.I gawk +interprets these files internally, it synchronizes output to the standard +output with output to +.BR /dev/stdout , +while on a system with those files, the output is actually to different +open files. +Caveat Emptor. +.SH VERSION INFORMATION +This man page documents +.IR gawk , +version 2.15. +.PP +Starting with the 2.15 version of +.IR gawk , +the +.BR \-c , +.BR \-V , +.BR \-C , +.ig +.BR \-D , +.. +.BR \-a , +and +.B \-e +options of the 2.11 version are no longer recognized. +.SH AUTHORS +The original version of \*(UX +.I awk +was designed and implemented by Alfred Aho, +Peter Weinberger, and Brian Kernighan of AT&T Bell Labs. Brian Kernighan +continues to maintain and enhance it. +.PP +Paul Rubin and Jay Fenlason, +of the Free Software Foundation, wrote +.IR gawk , +to be compatible with the original version of +.I awk +distributed in Seventh Edition \*(UX. +John Woods contributed a number of bug fixes. +David Trueman, with contributions +from Arnold Robbins, made +.I gawk +compatible with the new version of \*(UX +.IR awk . +.PP +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. +.SH ACKNOWLEDGEMENTS +Brian Kernighan of Bell Labs +provided valuable assistance during testing and debugging. +We thank him. diff --git a/gnu/usr.bin/awk/awk.h b/gnu/usr.bin/awk/awk.h new file mode 100644 index 0000000000..ca3997f11d --- /dev/null +++ b/gnu/usr.bin/awk/awk.h @@ -0,0 +1,763 @@ +/* + * awk.h -- Definitions for gawk. + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* ------------------------------ Includes ------------------------------ */ +#include +#include +#include +#include +#include +#include +#include +#if !defined(errno) && !defined(MSDOS) +extern int errno; +#endif +#ifdef __GNU_LIBRARY__ +#ifndef linux +#include +#endif +#endif + +/* ----------------- System dependencies (with more includes) -----------*/ + +#if !defined(VMS) || (!defined(VAXC) && !defined(__DECC)) +#include +#include +#else /* VMS w/ VAXC or DECC */ +#include +#include +#include /* avoid in io.c */ +#endif + +#include + +#include "config.h" + +#ifdef __STDC__ +#define P(s) s +#define MALLOC_ARG_T size_t +#else +#define P(s) () +#define MALLOC_ARG_T unsigned +#define volatile +#define const +#endif + +#ifndef SIGTYPE +#define SIGTYPE void +#endif + +#ifdef SIZE_T_MISSING +typedef unsigned int size_t; +#endif + +#ifndef SZTC +#define SZTC +#define INTC +#endif + +#ifdef STDC_HEADERS +#include +#include +#ifdef NeXT +#include +#undef atof +#else +#if defined(atarist) || defined(VMS) +#include +#else /* atarist || VMS */ +#ifndef MSDOS +#include +#endif /* MSDOS */ +#endif /* atarist || VMS */ +#endif /* Next */ +#else /* STDC_HEADERS */ +#include "protos.h" +#endif /* STDC_HEADERS */ + +#if defined(ultrix) && !defined(Ultrix41) +extern char * getenv P((char *name)); +extern double atof P((char *s)); +#endif + +#ifndef __GNUC__ +#ifdef sparc +/* nasty nasty SunOS-ism */ +#include +#ifdef lint +extern char *alloca(); +#endif +#else /* not sparc */ +#if !defined(alloca) && !defined(ALLOCA_PROTO) +extern char *alloca(); +#endif +#endif /* sparc */ +#endif /* __GNUC__ */ + +#ifdef HAVE_UNDERSCORE_SETJMP +/* nasty nasty berkelixm */ +#define setjmp _setjmp +#define longjmp _longjmp +#endif + +/* + * if you don't have vprintf, try this and cross your fingers. + */ +#if defined(VPRINTF_MISSING) +#define vfprintf(fp,fmt,arg) _doprnt((fmt), (arg), (fp)) +#endif + +#ifdef VMS +/* some macros to redirect to code in vms/vms_misc.c */ +#define exit vms_exit +#define open vms_open +#define strerror vms_strerror +#define strdup vms_strdup +extern void exit P((int)); +extern int open P((const char *,int,...)); +extern char *strerror P((int)); +extern char *strdup P((const char *str)); +extern int vms_devopen P((const char *,int)); +# ifndef NO_TTY_FWRITE +#define fwrite tty_fwrite +#define fclose tty_fclose +extern size_t fwrite P((const void *,size_t,size_t,FILE *)); +extern int fclose P((FILE *)); +# endif +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 int unlink P((const char *)); +extern int getopt P((int,char **,char *)); +extern int isatty P((int)); +#ifndef fileno +extern int fileno P((FILE *)); +#endif +extern int close(), dup(), dup2(), fstat(), read(), stat(); +#endif /*VMS*/ + +#ifdef MSDOS +#include +extern FILE *popen P((char *, char *)); +extern int pclose P((FILE *)); +#endif + +#define GNU_REGEX +#ifdef GNU_REGEX +#include "regex.h" +#include "dfa.h" +typedef struct Regexp { + struct re_pattern_buffer pat; + struct re_registers regs; + struct regexp dfareg; + int dfa; +} Regexp; +#define RESTART(rp,s) (rp)->regs.start[0] +#define REEND(rp,s) (rp)->regs.end[0] +#else /* GNU_REGEX */ +#endif /* GNU_REGEX */ + +#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); +#endif + +#ifndef DEFPATH +#define DEFPATH ".:/usr/local/lib/awk:/usr/lib/awk" +#endif + +#ifndef ENVSEP +#define ENVSEP ':' +#endif + +/* ------------------ Constants, Structures, Typedefs ------------------ */ +#define AWKNUM double + +typedef enum { + /* illegal entry == 0 */ + Node_illegal, + + /* binary operators lnode and rnode are the expressions to work on */ + Node_times, + Node_quotient, + Node_mod, + Node_plus, + Node_minus, + Node_cond_pair, /* conditional pair (see Node_line_range) */ + Node_subscript, + Node_concat, + Node_exp, + + /* unary operators subnode is the expression to work on */ +/*10*/ Node_preincrement, + Node_predecrement, + Node_postincrement, + Node_postdecrement, + Node_unary_minus, + Node_field_spec, + + /* assignments lnode is the var to assign to, rnode is the exp */ + Node_assign, + Node_assign_times, + Node_assign_quotient, + Node_assign_mod, +/*20*/ Node_assign_plus, + Node_assign_minus, + Node_assign_exp, + + /* boolean binaries lnode and rnode are expressions */ + Node_and, + Node_or, + + /* binary relationals compares lnode and rnode */ + Node_equal, + Node_notequal, + Node_less, + Node_greater, + Node_leq, +/*30*/ Node_geq, + Node_match, + Node_nomatch, + + /* unary relationals works on subnode */ + Node_not, + + /* program structures */ + Node_rule_list, /* lnode is a rule, rnode is rest of list */ + Node_rule_node, /* lnode is pattern, rnode is statement */ + Node_statement_list, /* lnode is statement, rnode is more list */ + Node_if_branches, /* lnode is to run on true, rnode on false */ + Node_expression_list, /* lnode is an exp, rnode is more list */ + Node_param_list, /* lnode is a variable, rnode is more list */ + + /* keywords */ +/*40*/ Node_K_if, /* lnode is conditonal, rnode is if_branches */ + Node_K_while, /* lnode is condtional, rnode is stuff to run */ + Node_K_for, /* lnode is for_struct, rnode is stuff to run */ + Node_K_arrayfor, /* lnode is for_struct, rnode is stuff to run */ + Node_K_break, /* no subs */ + Node_K_continue, /* no stuff */ + Node_K_print, /* lnode is exp_list, rnode is redirect */ + Node_K_printf, /* lnode is exp_list, rnode is redirect */ + Node_K_next, /* no subs */ + Node_K_exit, /* subnode is return value, or NULL */ +/*50*/ Node_K_do, /* lnode is conditional, rnode stuff to run */ + Node_K_return, + Node_K_delete, + Node_K_getline, + Node_K_function, /* lnode is statement list, rnode is params */ + + /* I/O redirection for print statements */ + Node_redirect_output, /* subnode is where to redirect */ + Node_redirect_append, /* subnode is where to redirect */ + Node_redirect_pipe, /* subnode is where to redirect */ + Node_redirect_pipein, /* subnode is where to redirect */ + Node_redirect_input, /* subnode is where to redirect */ + + /* Variables */ +/*60*/ Node_var, /* rnode is value, lnode is array stuff */ + Node_var_array, /* array is ptr to elements, asize num of + * eles */ + Node_val, /* node is a value - type in flags */ + + /* Builtins subnode is explist to work on, proc is func to call */ + Node_builtin, + + /* + * pattern: conditional ',' conditional ; lnode of Node_line_range + * is the two conditionals (Node_cond_pair), other word (rnode place) + * is a flag indicating whether or not this range has been entered. + */ + Node_line_range, + + /* + * boolean test of membership in array lnode is string-valued + * expression rnode is array name + */ + Node_in_array, + + Node_func, /* lnode is param. list, rnode is body */ + Node_func_call, /* lnode is name, rnode is argument list */ + + Node_cond_exp, /* lnode is conditonal, rnode is if_branches */ + Node_regex, +/*70*/ Node_hashnode, + Node_ahash, + Node_NF, + Node_NR, + Node_FNR, + Node_FS, + Node_RS, + Node_FIELDWIDTHS, + Node_IGNORECASE, + Node_OFS, + Node_ORS, + Node_OFMT, + Node_CONVFMT, + Node_K_nextfile +} NODETYPE; + +/* + * NOTE - this struct is a rather kludgey -- it is packed to minimize + * space usage, at the expense of cleanliness. Alter at own risk. + */ +typedef struct exp_node { + union { + struct { + union { + struct exp_node *lptr; + char *param_name; + } l; + union { + struct exp_node *rptr; + struct exp_node *(*pptr) (); + Regexp *preg; + struct for_loop_header *hd; + struct exp_node **av; + int r_ent; /* range entered */ + } r; + union { + char *name; + struct exp_node *extra; + } x; + short number; + unsigned char reflags; +# define CASE 1 +# define CONST 2 +# define FS_DFLT 4 + } nodep; + struct { + AWKNUM fltnum; /* this is here for optimal packing of + * the structure on many machines + */ + char *sp; + size_t slen; + unsigned char sref; + char idx; + } val; + struct { + struct exp_node *next; + char *name; + int length; + struct exp_node *value; + } hash; +#define hnext sub.hash.next +#define hname sub.hash.name +#define hlength sub.hash.length +#define hvalue sub.hash.value + struct { + struct exp_node *next; + struct exp_node *name; + struct exp_node *value; + } ahash; +#define ahnext sub.ahash.next +#define ahname sub.ahash.name +#define ahvalue sub.ahash.value + } sub; + NODETYPE type; + unsigned short flags; +# define MALLOC 1 /* can be free'd */ +# define TEMP 2 /* should be free'd */ +# define PERM 4 /* can't be free'd */ +# define STRING 8 /* assigned as string */ +# define STR 16 /* string value is current */ +# define NUM 32 /* numeric value is current */ +# define NUMBER 64 /* assigned as number */ +# define MAYBE_NUM 128 /* user input: if NUMERIC then + * a NUMBER + */ + char *vname; /* variable's name */ +} NODE; + +#define lnode sub.nodep.l.lptr +#define nextp sub.nodep.l.lptr +#define rnode sub.nodep.r.rptr +#define source_file sub.nodep.x.name +#define source_line sub.nodep.number +#define param_cnt sub.nodep.number +#define param sub.nodep.l.param_name + +#define subnode lnode +#define proc sub.nodep.r.pptr + +#define re_reg sub.nodep.r.preg +#define re_flags sub.nodep.reflags +#define re_text lnode +#define re_exp sub.nodep.x.extra +#define re_cnt sub.nodep.number + +#define forsub lnode +#define forloop rnode->sub.nodep.r.hd + +#define stptr sub.val.sp +#define stlen sub.val.slen +#define stref sub.val.sref +#define stfmt sub.val.idx + +#define numbr sub.val.fltnum + +#define var_value lnode +#define var_array sub.nodep.r.av + +#define condpair lnode +#define triggered sub.nodep.r.r_ent + +#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; + NODE *cond; + NODE *incr; +} FOR_LOOP_HEADER; + +/* for "for(iggy in foo) {" */ +struct search { + NODE **arr_ptr; + NODE **arr_end; + NODE *bucket; + NODE *retval; +}; + +/* for faster input, bypass stdio */ +typedef struct iobuf { + int fd; + char *buf; + char *off; + char *end; + size_t size; /* this will be determined by an fstat() call */ + int cnt; + long secsiz; + int flag; +# define IOP_IS_TTY 1 +# define IOP_IS_INTERNAL 2 +# define IOP_NO_FREE 4 +} IOBUF; + +typedef void (*Func_ptr)(); + +/* + * structure used to dynamically maintain a linked-list of open files/pipes + */ +struct redirect { + unsigned int flag; +# define RED_FILE 1 +# define RED_PIPE 2 +# define RED_READ 4 +# define RED_WRITE 8 +# define RED_APPEND 16 +# define RED_NOBUF 32 +# define RED_USED 64 +# define RED_EOF 128 + char *value; + FILE *fp; + IOBUF *iop; + int pid; + int status; + struct redirect *prev; + struct redirect *next; +}; + +/* structure for our source, either a command line string or a source file */ +struct src { + enum srctype { CMDLINE = 1, SOURCEFILE } stype; + char *val; +}; + +/* longjmp return codes, must be nonzero */ +/* Continue means either for loop/while continue, or next input record */ +#define TAG_CONTINUE 1 +/* Break means either for/while break, or stop reading input */ +#define TAG_BREAK 2 +/* Return means return from a function call; leave value in ret_node */ +#define TAG_RETURN 3 + +#define HUGE INT_MAX + +/* -------------------------- External variables -------------------------- */ +/* gawk builtin variables */ +extern int NF; +extern int NR; +extern int FNR; +extern int IGNORECASE; +extern char *RS; +extern char *OFS; +extern int OFSlen; +extern char *ORS; +extern int ORSlen; +extern char *OFMT; +extern char *CONVFMT; +extern int CONVFMTidx; +extern int OFMTidx; +extern NODE *FS_node, *NF_node, *RS_node, *NR_node; +extern NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node; +extern NODE *CONVFMT_node; +extern NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node; +extern NODE *IGNORECASE_node; +extern NODE *FIELDWIDTHS_node; + +extern NODE **stack_ptr; +extern NODE *Nnull_string; +extern NODE **fields_arr; +extern int sourceline; +extern char *source; +extern NODE *expression_value; + +extern NODE *_t; /* used as temporary in tree_eval */ + +extern const char *myname; + +extern NODE *nextfree; +extern int field0_valid; +extern int do_unix; +extern int do_posix; +extern int do_lint; +extern int in_begin_rule; +extern int in_end_rule; + +/* ------------------------- Pseudo-functions ------------------------- */ + +#define is_identchar(c) (isalnum(c) || (c) == '_') + + +#ifndef MPROF +#define getnode(n) if (nextfree) n = nextfree, nextfree = nextfree->nextp;\ + else n = more_nodes() +#define freenode(n) ((n)->nextp = nextfree, nextfree = (n)) +#else +#define getnode(n) emalloc(n, NODE *, sizeof(NODE), "getnode") +#define freenode(n) free(n) +#endif + +#ifdef DEBUG +#define tree_eval(t) r_tree_eval(t) +#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)))))) +#endif + +#define make_number(x) mk_number((x), (MALLOC|NUM|NUMBER)) +#define tmp_number(x) mk_number((x), (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) +#define SCAN 1 +#define ALREADY_MALLOCED 2 + +#define cant_happen() fatal("internal error line %d, file: %s", \ + __LINE__, __FILE__); + +#if defined(__STDC__) && !defined(NO_TOKEN_PASTING) +#define emalloc(var,ty,x,str) (void)((var=(ty)malloc((MALLOC_ARG_T)(x))) ||\ + (fatal("%s: %s: can't allocate memory (%s)",\ + (str), #var, strerror(errno)),0)) +#define erealloc(var,ty,x,str) (void)((var=(ty)realloc((char *)var,\ + (MALLOC_ARG_T)(x))) ||\ + (fatal("%s: %s: can't allocate memory (%s)",\ + (str), #var, strerror(errno)),0)) +#else /* __STDC__ */ +#define emalloc(var,ty,x,str) (void)((var=(ty)malloc((MALLOC_ARG_T)(x))) ||\ + (fatal("%s: %s: can't allocate memory (%s)",\ + (str), "var", strerror(errno)),0)) +#define erealloc(var,ty,x,str) (void)((var=(ty)realloc((char *)var,\ + (MALLOC_ARG_T)(x))) ||\ + (fatal("%s: %s: can't allocate memory (%s)",\ + (str), "var", strerror(errno)),0)) +#endif /* __STDC__ */ + +#ifdef DEBUG +#define force_number r_force_number +#define force_string r_force_string +#else /* not DEBUG */ +#ifdef lint +extern AWKNUM force_number(); +#endif +#ifdef MSDOS +extern double _msc51bug; +#define force_number(n) (_msc51bug=(_t = (n),(_t->flags & NUM) ? _t->numbr : r_force_number(_t))) +#else /* not MSDOS */ +#define force_number(n) (_t = (n),(_t->flags & NUM) ? _t->numbr : r_force_number(_t)) +#endif /* MSDOS */ +#define force_string(s) (_t = (s),(_t->flags & STR) ? _t : r_force_string(_t)) +#endif /* not DEBUG */ + +#define STREQ(a,b) (*(a) == *(b) && strcmp((a), (b)) == 0) +#define STREQN(a,b,n) ((n)&& *(a)== *(b) && strncmp((a), (b), SZTC (n)) == 0) + +/* ------------- Function prototypes or defs (as appropriate) ------------- */ + +/* 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 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)); +extern void assoc_scan P((NODE *symbol, struct search *lookat)); +extern void assoc_next P((struct search *lookat)); +/* awk.tab.c */ +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 *variable P((char *name, int can_free)); +extern int yyparse P((void)); +/* builtin.c */ +extern NODE *do_exp P((NODE *tree)); +extern NODE *do_index P((NODE *tree)); +extern NODE *do_int P((NODE *tree)); +extern NODE *do_length P((NODE *tree)); +extern NODE *do_log P((NODE *tree)); +extern NODE *do_sprintf P((NODE *tree)); +extern void do_printf P((NODE *tree)); +extern void print_simple P((NODE *tree, FILE *fp)); +extern NODE *do_sqrt P((NODE *tree)); +extern NODE *do_substr P((NODE *tree)); +extern NODE *do_strftime P((NODE *tree)); +extern NODE *do_systime P((NODE *tree)); +extern NODE *do_system P((NODE *tree)); +extern void do_print P((NODE *tree)); +extern NODE *do_tolower P((NODE *tree)); +extern NODE *do_toupper P((NODE *tree)); +extern NODE *do_atan2 P((NODE *tree)); +extern NODE *do_sin P((NODE *tree)); +extern NODE *do_cos P((NODE *tree)); +extern NODE *do_rand P((NODE *tree)); +extern NODE *do_srand P((NODE *tree)); +extern NODE *do_match P((NODE *tree)); +extern NODE *do_gsub P((NODE *tree)); +extern NODE *do_sub P((NODE *tree)); +/* eval.c */ +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 void set_IGNORECASE P((void)); +void set_OFS P((void)); +void set_ORS P((void)); +void set_OFMT P((void)); +void set_CONVFMT P((void)); +/* field.c */ +extern void init_fields P((void)); +extern void set_record P((char *buf, int cnt, int freeold)); +extern void reset_record P((void)); +extern void set_NF P((void)); +extern NODE **get_field P((int num, Func_ptr *assign)); +extern NODE *do_split P((NODE *tree)); +extern void set_FS P((void)); +extern void set_RS P((void)); +extern void set_FIELDWIDTHS P((void)); +/* io.c */ +extern void set_FNR P((void)); +extern void set_NR P((void)); +extern void do_input P((void)); +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 NODE *do_getline P((NODE *tree)); +extern void do_nextfile P((void)); +/* iop.c */ +extern int optimal_bufsize P((int fd)); +extern IOBUF *iop_alloc P((int fd)); +extern int get_a_record P((char **out, IOBUF *iop, int rs, int *errcode)); +/* main.c */ +extern int main P((int argc, char **argv)); +extern Regexp *mk_re_parse P((char *s, int ignorecase)); +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, ...)); +#else +extern void err (); +extern void msg (); +extern void warning (); +extern void fatal (); +#endif +/* node.c */ +extern AWKNUM r_force_number P((NODE *n)); +extern NODE *r_force_string P((NODE *s)); +extern NODE *dupnode P((NODE *n)); +extern NODE *mk_number P((AWKNUM x, unsigned int flags)); +extern NODE *make_str_node P((char *s, size_t len, int scan )); +extern NODE *tmp_string P((char *s, size_t len )); +extern NODE *more_nodes P((void)); +#ifdef DEBUG +extern void freenode P((NODE *it)); +#endif +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 void refree P((Regexp *rp)); +extern void reg_error P((const char *s)); +extern Regexp *re_update P((NODE *t)); +extern void resyntax P((int syntax)); +extern void resetup P((void)); + +/* strcase.c */ +extern int strcasecmp P((const char *s1, const char *s2)); +extern int strncasecmp P((const char *s1, const char *s2, register size_t n)); + +#ifdef atarist +/* atari/tmpnam.c */ +extern char *tmpnam P((char *buf)); +extern char *tempnam P((const char *path, const char *base)); +#endif + +/* Figure out what '\a' really is. */ +#ifdef __STDC__ +#define BELL '\a' /* sure makes life easy, don't it? */ +#else +# if 'z' - 'a' == 25 /* ascii */ +# if 'a' != 97 /* machine is dumb enough to use mark parity */ +# define BELL '\207' +# else +# define BELL '\07' +# endif +# else +# define BELL '\057' +# endif +#endif + +extern char casetable[]; /* for case-independent regexp matching */ diff --git a/gnu/usr.bin/awk/awk.y b/gnu/usr.bin/awk/awk.y new file mode 100644 index 0000000000..6e87f1c449 --- /dev/null +++ b/gnu/usr.bin/awk/awk.y @@ -0,0 +1,1804 @@ +/* + * awk.y --- yacc/bison parser + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +%{ +#ifdef DEBUG +#define YYDEBUG 12 +#endif + +#include "awk.h" + +static void yyerror (); /* va_alist */ +static char *get_src_buf P((void)); +static int yylex P((void)); +static NODE *node_common P((NODETYPE op)); +static NODE *snode P((NODE *subn, NODETYPE op, int sindex)); +static NODE *mkrangenode P((NODE *cpair)); +static NODE *make_for_loop P((NODE *init, NODE *cond, NODE *incr)); +static NODE *append_right P((NODE *list, NODE *new)); +static void func_install P((NODE *params, NODE *def)); +static void pop_var P((NODE *np, int freeit)); +static void pop_params P((NODE *params)); +static NODE *make_param P((char *name)); +static NODE *mk_rexp P((NODE *exp)); + +static int want_assign; /* lexical scanning kludge */ +static int want_regexp; /* lexical scanning kludge */ +static int can_return; /* lexical scanning kludge */ +static int io_allowed = 1; /* lexical scanning kludge */ +static char *lexptr; /* pointer to next char during parsing */ +static char *lexend; +static char *lexptr_begin; /* keep track of where we were for error msgs */ +static char *lexeme; /* beginning of lexeme for debugging */ +static char *thisline = NULL; +#define YYDEBUG_LEXER_TEXT (lexeme) +static int param_counter; +static char *tokstart = NULL; +static char *token = NULL; +static char *tokend; + +NODE *variables[HASHSIZE]; + +extern char *source; +extern int sourceline; +extern struct src *srcfiles; +extern int numfiles; +extern int errcount; +extern NODE *begin_block; +extern NODE *end_block; +%} + +%union { + long lval; + AWKNUM fval; + NODE *nodeval; + NODETYPE nodetypeval; + char *sval; + NODE *(*ptrval)(); +} + +%type function_prologue function_body +%type rexp exp start program rule simp_exp +%type non_post_simp_exp +%type pattern +%type action variable param_list +%type rexpression_list opt_rexpression_list +%type expression_list opt_expression_list +%type statements statement if_statement opt_param_list +%type opt_exp opt_variable regexp +%type input_redir output_redir +%type print +%type func_name +%type lex_builtin + +%token FUNC_CALL NAME REGEXP +%token ERROR +%token YNUMBER YSTRING +%token RELOP APPEND_OP +%token ASSIGNOP MATCHOP NEWLINE CONCAT_OP +%token LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE +%token LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE +%token LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION +%token LEX_GETLINE +%token LEX_IN +%token LEX_AND LEX_OR INCREMENT DECREMENT +%token LEX_BUILTIN LEX_LENGTH + +/* these are just yylval numbers */ + +/* Lowest to highest */ +%right ASSIGNOP +%right '?' ':' +%left LEX_OR +%left LEX_AND +%left LEX_GETLINE +%nonassoc LEX_IN +%left FUNC_CALL LEX_BUILTIN LEX_LENGTH +%nonassoc MATCHOP +%nonassoc RELOP '<' '>' '|' APPEND_OP +%left CONCAT_OP +%left YSTRING YNUMBER +%left '+' '-' +%left '*' '/' '%' +%right '!' UNARY +%right '^' +%left INCREMENT DECREMENT +%left '$' +%left '(' ')' +%% + +start + : opt_nls program opt_nls + { expression_value = $2; } + ; + +program + : rule + { + if ($1 != NULL) + $$ = $1; + else + $$ = NULL; + yyerrok; + } + | program rule + /* add the rule to the tail of list */ + { + if ($2 == NULL) + $$ = $1; + else if ($1 == NULL) + $$ = $2; + else { + if ($1->type != Node_rule_list) + $1 = node($1, Node_rule_list, + (NODE*)NULL); + $$ = append_right ($1, + node($2, Node_rule_list,(NODE *) NULL)); + } + yyerrok; + } + | error { $$ = NULL; } + | program error { $$ = NULL; } + ; + +rule + : LEX_BEGIN { io_allowed = 0; } + action + { + if (begin_block) { + if (begin_block->type != Node_rule_list) + begin_block = node(begin_block, Node_rule_list, + (NODE *)NULL); + (void) append_right (begin_block, node( + node((NODE *)NULL, Node_rule_node, $3), + Node_rule_list, (NODE *)NULL) ); + } else + begin_block = node((NODE *)NULL, Node_rule_node, $3); + $$ = NULL; + io_allowed = 1; + yyerrok; + } + | LEX_END { io_allowed = 0; } + action + { + if (end_block) { + if (end_block->type != Node_rule_list) + end_block = node(end_block, Node_rule_list, + (NODE *)NULL); + (void) append_right (end_block, node( + node((NODE *)NULL, Node_rule_node, $3), + Node_rule_list, (NODE *)NULL)); + } else + end_block = node((NODE *)NULL, Node_rule_node, $3); + $$ = NULL; + io_allowed = 1; + yyerrok; + } + | LEX_BEGIN statement_term + { + warning("BEGIN blocks must have an action part"); + errcount++; + yyerrok; + } + | LEX_END statement_term + { + warning("END blocks must have an action part"); + errcount++; + yyerrok; + } + | pattern action + { $$ = node ($1, Node_rule_node, $2); yyerrok; } + | action + { $$ = node ((NODE *)NULL, Node_rule_node, $1); yyerrok; } + | pattern statement_term + { + $$ = node ($1, + Node_rule_node, + node(node(node(make_number(0.0), + Node_field_spec, + (NODE *) NULL), + Node_expression_list, + (NODE *) NULL), + Node_K_print, + (NODE *) NULL)); + yyerrok; + } + | function_prologue function_body + { + func_install($1, $2); + $$ = NULL; + yyerrok; + } + ; + +func_name + : NAME + { $$ = $1; } + | FUNC_CALL + { $$ = $1; } + | lex_builtin + { + yyerror("%s() is a built-in function, it cannot be redefined", + tokstart); + errcount++; + /* yyerrok; */ + } + ; + +lex_builtin + : LEX_BUILTIN + | LEX_LENGTH + ; + +function_prologue + : LEX_FUNCTION + { + param_counter = 0; + } + func_name '(' opt_param_list r_paren opt_nls + { + $$ = append_right(make_param($3), $5); + can_return = 1; + } + ; + +function_body + : l_brace statements r_brace opt_semi + { + $$ = $2; + can_return = 0; + } + ; + + +pattern + : exp + { $$ = $1; } + | exp comma exp + { $$ = mkrangenode ( node($1, Node_cond_pair, $3) ); } + ; + +regexp + /* + * In this rule, want_regexp tells yylex that the next thing + * is a regexp so it should read up to the closing slash. + */ + : '/' + { ++want_regexp; } + REGEXP '/' + { + NODE *n; + int len; + + getnode(n); + n->type = Node_regex; + len = strlen($3); + n->re_exp = make_string($3, len); + n->re_reg = make_regexp($3, len, 0, 1); + n->re_text = NULL; + n->re_flags = CONST; + n->re_cnt = 1; + $$ = n; + } + ; + +action + : l_brace statements r_brace opt_semi opt_nls + { $$ = $2 ; } + | l_brace r_brace opt_semi opt_nls + { $$ = NULL; } + ; + +statements + : statement + { $$ = $1; } + | statements statement + { + if ($1 == NULL || $1->type != Node_statement_list) + $1 = node($1, Node_statement_list,(NODE *)NULL); + $$ = append_right($1, + node( $2, Node_statement_list, (NODE *)NULL)); + yyerrok; + } + | error + { $$ = NULL; } + | statements error + { $$ = NULL; } + ; + +statement_term + : nls + | semi opt_nls + ; + +statement + : semi opt_nls + { $$ = NULL; } + | l_brace r_brace + { $$ = NULL; } + | l_brace statements r_brace + { $$ = $2; } + | if_statement + { $$ = $1; } + | LEX_WHILE '(' exp r_paren opt_nls statement + { $$ = node ($3, Node_K_while, $6); } + | LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls + { $$ = node ($6, Node_K_do, $3); } + | LEX_FOR '(' NAME LEX_IN NAME r_paren opt_nls statement + { + $$ = node ($8, Node_K_arrayfor, make_for_loop(variable($3,1), + (NODE *)NULL, variable($5,1))); + } + | LEX_FOR '(' opt_exp semi exp semi opt_exp r_paren opt_nls statement + { + $$ = node($10, Node_K_for, (NODE *)make_for_loop($3, $5, $7)); + } + | LEX_FOR '(' opt_exp semi semi opt_exp r_paren opt_nls statement + { + $$ = node ($9, Node_K_for, + (NODE *)make_for_loop($3, (NODE *)NULL, $6)); + } + | LEX_BREAK statement_term + /* for break, maybe we'll have to remember where to break to */ + { $$ = node ((NODE *)NULL, Node_K_break, (NODE *)NULL); } + | LEX_CONTINUE statement_term + /* similarly */ + { $$ = node ((NODE *)NULL, Node_K_continue, (NODE *)NULL); } + | print '(' expression_list r_paren output_redir statement_term + { $$ = node ($3, $1, $5); } + | print opt_rexpression_list output_redir statement_term + { + if ($1 == Node_K_print && $2 == NULL) + $2 = node(node(make_number(0.0), + Node_field_spec, + (NODE *) NULL), + Node_expression_list, + (NODE *) NULL); + + $$ = node ($2, $1, $3); + } + | LEX_NEXT opt_exp statement_term + { NODETYPE type; + + 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"); + type = Node_K_nextfile; + } else { + if (! io_allowed) + yyerror("next used in BEGIN or END action"); + type = Node_K_next; + } + $$ = node ((NODE *)NULL, type, (NODE *)NULL); + } + | LEX_EXIT opt_exp statement_term + { $$ = node ($2, Node_K_exit, (NODE *)NULL); } + | LEX_RETURN + { if (! can_return) yyerror("return used outside function context"); } + opt_exp statement_term + { $$ = node ($3, Node_K_return, (NODE *)NULL); } + | LEX_DELETE NAME '[' expression_list ']' statement_term + { $$ = node (variable($2,1), Node_K_delete, $4); } + | exp statement_term + { $$ = $1; } + ; + +print + : LEX_PRINT + { $$ = $1; } + | LEX_PRINTF + { $$ = $1; } + ; + +if_statement + : LEX_IF '(' exp r_paren opt_nls statement + { + $$ = node($3, Node_K_if, + node($6, Node_if_branches, (NODE *)NULL)); + } + | LEX_IF '(' exp r_paren opt_nls statement + LEX_ELSE opt_nls statement + { $$ = node ($3, Node_K_if, + node ($6, Node_if_branches, $9)); } + ; + +nls + : NEWLINE + { want_assign = 0; } + | nls NEWLINE + ; + +opt_nls + : /* empty */ + | nls + ; + +input_redir + : /* empty */ + { $$ = NULL; } + | '<' simp_exp + { $$ = node ($2, Node_redirect_input, (NODE *)NULL); } + ; + +output_redir + : /* empty */ + { $$ = NULL; } + | '>' exp + { $$ = node ($2, Node_redirect_output, (NODE *)NULL); } + | APPEND_OP exp + { $$ = node ($2, Node_redirect_append, (NODE *)NULL); } + | '|' exp + { $$ = node ($2, Node_redirect_pipe, (NODE *)NULL); } + ; + +opt_param_list + : /* empty */ + { $$ = NULL; } + | param_list + { $$ = $1; } + ; + +param_list + : NAME + { $$ = make_param($1); } + | param_list comma NAME + { $$ = append_right($1, make_param($3)); yyerrok; } + | error + { $$ = NULL; } + | param_list error + { $$ = NULL; } + | param_list comma error + { $$ = NULL; } + ; + +/* optional expression, as in for loop */ +opt_exp + : /* empty */ + { $$ = NULL; } + | exp + { $$ = $1; } + ; + +opt_rexpression_list + : /* empty */ + { $$ = NULL; } + | rexpression_list + { $$ = $1; } + ; + +rexpression_list + : rexp + { $$ = node ($1, Node_expression_list, (NODE *)NULL); } + | rexpression_list comma rexp + { + $$ = append_right($1, + node( $3, Node_expression_list, (NODE *)NULL)); + yyerrok; + } + | error + { $$ = NULL; } + | rexpression_list error + { $$ = NULL; } + | rexpression_list error rexp + { $$ = NULL; } + | rexpression_list comma error + { $$ = NULL; } + ; + +opt_expression_list + : /* empty */ + { $$ = NULL; } + | expression_list + { $$ = $1; } + ; + +expression_list + : exp + { $$ = node ($1, Node_expression_list, (NODE *)NULL); } + | expression_list comma exp + { + $$ = append_right($1, + node( $3, Node_expression_list, (NODE *)NULL)); + yyerrok; + } + | error + { $$ = NULL; } + | expression_list error + { $$ = NULL; } + | expression_list error exp + { $$ = NULL; } + | expression_list comma error + { $$ = NULL; } + ; + +/* Expressions, not including the comma operator. */ +exp : variable ASSIGNOP + { want_assign = 0; } + exp + { + if (do_lint && $4->type == Node_regex) + warning("Regular expression on left of assignment."); + $$ = node ($1, $2, $4); + } + | '(' expression_list r_paren LEX_IN NAME + { $$ = node (variable($5,1), Node_in_array, $2); } + | exp '|' LEX_GETLINE opt_variable + { + $$ = node ($4, Node_K_getline, + node ($1, Node_redirect_pipein, (NODE *)NULL)); + } + | LEX_GETLINE opt_variable input_redir + { + if (do_lint && ! io_allowed && $3 == NULL) + warning("non-redirected getline undefined inside BEGIN or END action"); + $$ = node ($2, Node_K_getline, $3); + } + | exp LEX_AND exp + { $$ = node ($1, Node_and, $3); } + | exp LEX_OR exp + { $$ = node ($1, Node_or, $3); } + | exp MATCHOP exp + { + if ($1->type == Node_regex) + warning("Regular expression on left of MATCH operator."); + $$ = node ($1, $2, mk_rexp($3)); + } + | regexp + { $$ = $1; } + | '!' regexp %prec UNARY + { + $$ = node(node(make_number(0.0), + Node_field_spec, + (NODE *) NULL), + Node_nomatch, + $2); + } + | exp LEX_IN NAME + { $$ = node (variable($3,1), Node_in_array, $1); } + | exp RELOP exp + { + if (do_lint && $3->type == Node_regex) + warning("Regular expression on left of comparison."); + $$ = node ($1, $2, $3); + } + | exp '<' exp + { $$ = node ($1, Node_less, $3); } + | exp '>' exp + { $$ = node ($1, Node_greater, $3); } + | exp '?' exp ':' exp + { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));} + | simp_exp + { $$ = $1; } + | exp simp_exp %prec CONCAT_OP + { $$ = node ($1, Node_concat, $2); } + ; + +rexp + : variable ASSIGNOP + { want_assign = 0; } + rexp + { $$ = node ($1, $2, $4); } + | rexp LEX_AND rexp + { $$ = node ($1, Node_and, $3); } + | rexp LEX_OR rexp + { $$ = node ($1, Node_or, $3); } + | LEX_GETLINE opt_variable input_redir + { + if (do_lint && ! io_allowed && $3 == NULL) + warning("non-redirected getline undefined inside BEGIN or END action"); + $$ = node ($2, Node_K_getline, $3); + } + | regexp + { $$ = $1; } + | '!' regexp %prec UNARY + { $$ = node((NODE *) NULL, Node_nomatch, $2); } + | rexp MATCHOP rexp + { $$ = node ($1, $2, mk_rexp($3)); } + | rexp LEX_IN NAME + { $$ = node (variable($3,1), Node_in_array, $1); } + | rexp RELOP rexp + { $$ = node ($1, $2, $3); } + | rexp '?' rexp ':' rexp + { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));} + | simp_exp + { $$ = $1; } + | rexp simp_exp %prec CONCAT_OP + { $$ = node ($1, Node_concat, $2); } + ; + +simp_exp + : non_post_simp_exp + /* Binary operators in order of decreasing precedence. */ + | simp_exp '^' simp_exp + { $$ = node ($1, Node_exp, $3); } + | simp_exp '*' simp_exp + { $$ = node ($1, Node_times, $3); } + | simp_exp '/' simp_exp + { $$ = node ($1, Node_quotient, $3); } + | simp_exp '%' simp_exp + { $$ = node ($1, Node_mod, $3); } + | simp_exp '+' simp_exp + { $$ = node ($1, Node_plus, $3); } + | simp_exp '-' simp_exp + { $$ = node ($1, Node_minus, $3); } + | variable INCREMENT + { $$ = node ($1, Node_postincrement, (NODE *)NULL); } + | variable DECREMENT + { $$ = node ($1, Node_postdecrement, (NODE *)NULL); } + ; + +non_post_simp_exp + : '!' simp_exp %prec UNARY + { $$ = node ($2, Node_not,(NODE *) NULL); } + | '(' exp r_paren + { $$ = $2; } + | LEX_BUILTIN + '(' opt_expression_list r_paren + { $$ = snode ($3, Node_builtin, (int) $1); } + | LEX_LENGTH '(' opt_expression_list r_paren + { $$ = snode ($3, Node_builtin, (int) $1); } + | LEX_LENGTH + { + if (do_lint) + warning("call of `length' without parentheses is not portable"); + $$ = snode ((NODE *)NULL, Node_builtin, (int) $1); + if (do_posix) + warning( "call of `length' without parentheses is deprecated by POSIX"); + } + | FUNC_CALL '(' opt_expression_list r_paren + { + $$ = node ($3, Node_func_call, make_string($1, strlen($1))); + } + | variable + | INCREMENT variable + { $$ = node ($2, Node_preincrement, (NODE *)NULL); } + | DECREMENT variable + { $$ = node ($2, Node_predecrement, (NODE *)NULL); } + | YNUMBER + { $$ = $1; } + | YSTRING + { $$ = $1; } + + | '-' simp_exp %prec UNARY + { if ($2->type == Node_val) { + $2->numbr = -(force_number($2)); + $$ = $2; + } else + $$ = node ($2, Node_unary_minus, (NODE *)NULL); + } + | '+' simp_exp %prec UNARY + { $$ = $2; } + ; + +opt_variable + : /* empty */ + { $$ = NULL; } + | variable + { $$ = $1; } + ; + +variable + : NAME + { $$ = variable($1,1); } + | NAME '[' expression_list ']' + { + if ($3->rnode == NULL) { + $$ = node (variable($1,1), Node_subscript, $3->lnode); + freenode($3); + } else + $$ = node (variable($1,1), Node_subscript, $3); + } + | '$' non_post_simp_exp + { $$ = node ($2, Node_field_spec, (NODE *)NULL); } + ; + +l_brace + : '{' opt_nls + ; + +r_brace + : '}' opt_nls { yyerrok; } + ; + +r_paren + : ')' { yyerrok; } + ; + +opt_semi + : /* empty */ + | semi + ; + +semi + : ';' { yyerrok; want_assign = 0; } + ; + +comma : ',' opt_nls { yyerrok; } + ; + +%% + +struct token { + char *operator; /* text to match */ + NODETYPE value; /* node type */ + int class; /* lexical class */ + unsigned flags; /* # of args. allowed and compatability */ +# define ARGS 0xFF /* 0, 1, 2, 3 args allowed (any combination */ +# define A(n) (1<<(n)) +# define VERSION 0xFF00 /* old awk is zero */ +# define NOT_OLD 0x0100 /* feature not in old awk */ +# define NOT_POSIX 0x0200 /* feature not in POSIX */ +# define GAWKX 0x0400 /* gawk extension */ + NODE *(*ptr) (); /* function that implements this keyword */ +}; + +extern NODE + *do_exp(), *do_getline(), *do_index(), *do_length(), + *do_sqrt(), *do_log(), *do_sprintf(), *do_substr(), + *do_split(), *do_system(), *do_int(), *do_close(), + *do_atan2(), *do_sin(), *do_cos(), *do_rand(), + *do_srand(), *do_match(), *do_tolower(), *do_toupper(), + *do_sub(), *do_gsub(), *do_strftime(), *do_systime(); + +/* Tokentab is sorted ascii ascending order, so it can be binary searched. */ + +static struct token tokentab[] = { +{"BEGIN", Node_illegal, LEX_BEGIN, 0, 0}, +{"END", Node_illegal, LEX_END, 0, 0}, +{"atan2", Node_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2}, +{"break", Node_K_break, LEX_BREAK, 0, 0}, +{"close", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_close}, +{"continue", Node_K_continue, LEX_CONTINUE, 0, 0}, +{"cos", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos}, +{"delete", Node_K_delete, LEX_DELETE, NOT_OLD, 0}, +{"do", Node_K_do, LEX_DO, NOT_OLD, 0}, +{"else", Node_illegal, LEX_ELSE, 0, 0}, +{"exit", Node_K_exit, LEX_EXIT, 0, 0}, +{"exp", Node_builtin, LEX_BUILTIN, A(1), do_exp}, +{"for", Node_K_for, LEX_FOR, 0, 0}, +{"func", Node_K_function, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0}, +{"function", Node_K_function, LEX_FUNCTION, NOT_OLD, 0}, +{"getline", Node_K_getline, LEX_GETLINE, NOT_OLD, 0}, +{"gsub", Node_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_gsub}, +{"if", Node_K_if, LEX_IF, 0, 0}, +{"in", Node_illegal, LEX_IN, 0, 0}, +{"index", Node_builtin, LEX_BUILTIN, A(2), do_index}, +{"int", Node_builtin, LEX_BUILTIN, A(1), do_int}, +{"length", Node_builtin, LEX_LENGTH, A(0)|A(1), do_length}, +{"log", Node_builtin, LEX_BUILTIN, A(1), do_log}, +{"match", Node_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_match}, +{"next", Node_K_next, LEX_NEXT, 0, 0}, +{"print", Node_K_print, LEX_PRINT, 0, 0}, +{"printf", Node_K_printf, LEX_PRINTF, 0, 0}, +{"rand", Node_builtin, LEX_BUILTIN, NOT_OLD|A(0), do_rand}, +{"return", Node_K_return, LEX_RETURN, NOT_OLD, 0}, +{"sin", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin}, +{"split", Node_builtin, LEX_BUILTIN, A(2)|A(3), do_split}, +{"sprintf", Node_builtin, LEX_BUILTIN, 0, do_sprintf}, +{"sqrt", Node_builtin, LEX_BUILTIN, A(1), do_sqrt}, +{"srand", Node_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand}, +{"strftime", Node_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_strftime}, +{"sub", Node_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_sub}, +{"substr", Node_builtin, LEX_BUILTIN, A(2)|A(3), do_substr}, +{"system", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system}, +{"systime", Node_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime}, +{"tolower", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower}, +{"toupper", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper}, +{"while", Node_K_while, LEX_WHILE, 0, 0}, +}; + +/* VARARGS0 */ +static void +yyerror(va_alist) +va_dcl +{ + va_list args; + char *mesg = NULL; + register char *bp, *cp; + char *scan; + char buf[120]; + + errcount++; + /* Find the current line in the input file */ + if (lexptr) { + if (!thisline) { + cp = lexeme; + if (*cp == '\n') { + cp--; + mesg = "unexpected newline"; + } + for ( ; cp != lexptr_begin && *cp != '\n'; --cp) + ; + if (*cp == '\n') + cp++; + thisline = cp; + } + /* NL isn't guaranteed */ + bp = lexeme; + while (bp < lexend && *bp && *bp != '\n') + bp++; + } else { + thisline = "(END OF FILE)"; + bp = thisline + 13; + } + msg("%.*s", (int) (bp - thisline), thisline); + bp = buf; + cp = buf + sizeof(buf) - 24; /* 24 more than longest msg. input */ + if (lexptr) { + scan = thisline; + while (bp < cp && scan < lexeme) + if (*scan++ == '\t') + *bp++ = '\t'; + else + *bp++ = ' '; + *bp++ = '^'; + *bp++ = ' '; + } + va_start(args); + if (mesg == NULL) + mesg = va_arg(args, char *); + strcpy(bp, mesg); + err("", buf, args); + va_end(args); + exit(2); +} + +static char * +get_src_buf() +{ + static int samefile = 0; + static int nextfile = 0; + static char *buf = NULL; + static int fd; + int n; + register char *scan; + static int len = 0; + static int did_newline = 0; +# define SLOP 128 /* enough space to hold most source lines */ + + if (nextfile > numfiles) + return NULL; + + if (srcfiles[nextfile].stype == CMDLINE) { + if (len == 0) { + len = strlen(srcfiles[nextfile].val); + sourceline = 1; + lexptr = lexptr_begin = srcfiles[nextfile].val; + lexend = lexptr + len; + } else if (!did_newline && *(lexptr-1) != '\n') { + /* + * The following goop is to ensure that the source + * ends with a newline and that the entire current + * line is available for error messages. + */ + int offset; + + did_newline = 1; + offset = lexptr - lexeme; + for (scan = lexeme; scan > lexptr_begin; scan--) + if (*scan == '\n') { + scan++; + break; + } + len = lexptr - scan; + emalloc(buf, char *, len+1, "get_src_buf"); + memcpy(buf, scan, len); + thisline = buf; + lexptr = buf + len; + *lexptr = '\n'; + lexeme = lexptr - offset; + lexptr_begin = buf; + lexend = lexptr + 1; + } else { + len = 0; + lexeme = lexptr = lexptr_begin = NULL; + } + if (lexptr == NULL && ++nextfile <= numfiles) + return get_src_buf(); + return lexptr; + } + if (!samefile) { + source = srcfiles[nextfile].val; + if (source == NULL) { + if (buf) { + free(buf); + buf = NULL; + } + len = 0; + return lexeme = lexptr = lexptr_begin = NULL; + } + fd = pathopen(source); + if (fd == -1) + fatal("can't open source file \"%s\" for reading (%s)", + source, strerror(errno)); + len = optimal_bufsize(fd); + if (buf) + free(buf); + emalloc(buf, char *, len + SLOP, "get_src_buf"); + lexptr_begin = buf + SLOP; + samefile = 1; + sourceline = 1; + } else { + /* + * Here, we retain the current source line (up to length SLOP) + * in the beginning of the buffer that was overallocated above + */ + int offset; + int linelen; + + offset = lexptr - lexeme; + for (scan = lexeme; scan > lexptr_begin; scan--) + if (*scan == '\n') { + scan++; + break; + } + linelen = lexptr - scan; + if (linelen > SLOP) + linelen = SLOP; + thisline = buf + SLOP - linelen; + memcpy(thisline, scan, linelen); + lexeme = buf + SLOP - offset; + lexptr_begin = thisline; + } + n = read(fd, buf + SLOP, len); + if (n == -1) + fatal("can't read sourcefile \"%s\" (%s)", + source, strerror(errno)); + if (n == 0) { + samefile = 0; + nextfile++; + len = 0; + return get_src_buf(); + } + lexptr = buf + SLOP; + lexend = lexptr + n; + return buf; +} + +#define tokadd(x) (*token++ = (x), token == tokend ? tokexpand() : token) + +char * +tokexpand() +{ + static int toksize = 60; + int tokoffset; + + tokoffset = token - tokstart; + toksize *= 2; + if (tokstart) + erealloc(tokstart, char *, toksize, "tokexpand"); + else + emalloc(tokstart, char *, toksize, "tokexpand"); + tokend = tokstart + toksize; + token = tokstart + tokoffset; + return token; +} + +#if DEBUG +char +nextc() { + if (lexptr && lexptr < lexend) + return *lexptr++; + else if (get_src_buf()) + return *lexptr++; + else + return '\0'; +} +#else +#define nextc() ((lexptr && lexptr < lexend) ? \ + *lexptr++ : \ + (get_src_buf() ? *lexptr++ : '\0') \ + ) +#endif +#define pushback() (lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr) + +/* + * Read the input and turn it into tokens. + */ + +static int +yylex() +{ + register int c; + int seen_e = 0; /* These are for numbers */ + int seen_point = 0; + int esc_seen; /* for literal strings */ + int low, mid, high; + static int did_newline = 0; + char *tokkey; + + if (!nextc()) + return 0; + pushback(); + lexeme = lexptr; + thisline = NULL; + if (want_regexp) { + int in_brack = 0; + + want_regexp = 0; + token = tokstart; + while ((c = nextc()) != 0) { + switch (c) { + case '[': + in_brack = 1; + break; + case ']': + in_brack = 0; + break; + case '\\': + if ((c = nextc()) == '\0') { + yyerror("unterminated regexp ends with \\ at end of file"); + } else if (c == '\n') { + sourceline++; + continue; + } else + tokadd('\\'); + break; + case '/': /* end of the regexp */ + if (in_brack) + break; + + pushback(); + tokadd('\0'); + yylval.sval = tokstart; + return REGEXP; + case '\n': + pushback(); + yyerror("unterminated regexp"); + case '\0': + yyerror("unterminated regexp at end of file"); + } + tokadd(c); + } + } +retry: + while ((c = nextc()) == ' ' || c == '\t') + ; + + lexeme = lexptr ? lexptr - 1 : lexptr; + thisline = NULL; + token = tokstart; + yylval.nodetypeval = Node_illegal; + + switch (c) { + case 0: + return 0; + + case '\n': + sourceline++; + return NEWLINE; + + case '#': /* it's a comment */ + while ((c = nextc()) != '\n') { + if (c == '\0') + return 0; + } + sourceline++; + return NEWLINE; + + case '\\': +#ifdef RELAXED_CONTINUATION + 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; + pushback(); + } +#endif /*RELAXED_CONTINUATION*/ + if (nextc() == '\n') { + sourceline++; + goto retry; + } else + yyerror("inappropriate use of backslash"); + break; + + case '$': + want_assign = 1; + return '$'; + + case ')': + case ']': + case '(': + case '[': + case ';': + case ':': + case '?': + case '{': + case ',': + return c; + + case '*': + if ((c = nextc()) == '=') { + yylval.nodetypeval = Node_assign_times; + return ASSIGNOP; + } else if (do_posix) { + pushback(); + return '*'; + } else if (c == '*') { + /* make ** and **= aliases for ^ and ^= */ + static int did_warn_op = 0, did_warn_assgn = 0; + + if (nextc() == '=') { + if (do_lint && ! did_warn_assgn) { + did_warn_assgn = 1; + warning("**= is not allowed by POSIX"); + } + yylval.nodetypeval = Node_assign_exp; + return ASSIGNOP; + } else { + pushback(); + if (do_lint && ! did_warn_op) { + did_warn_op = 1; + warning("** is not allowed by POSIX"); + } + return '^'; + } + } + pushback(); + return '*'; + + case '/': + if (want_assign) { + if (nextc() == '=') { + yylval.nodetypeval = Node_assign_quotient; + return ASSIGNOP; + } + pushback(); + } + return '/'; + + case '%': + if (nextc() == '=') { + yylval.nodetypeval = Node_assign_mod; + return ASSIGNOP; + } + pushback(); + return '%'; + + case '^': + { + static int did_warn_op = 0, did_warn_assgn = 0; + + if (nextc() == '=') { + + if (do_lint && ! did_warn_assgn) { + did_warn_assgn = 1; + warning("operator `^=' is not supported in old awk"); + } + yylval.nodetypeval = Node_assign_exp; + return ASSIGNOP; + } + pushback(); + if (do_lint && ! did_warn_op) { + did_warn_op = 1; + warning("operator `^' is not supported in old awk"); + } + return '^'; + } + + case '+': + if ((c = nextc()) == '=') { + yylval.nodetypeval = Node_assign_plus; + return ASSIGNOP; + } + if (c == '+') + return INCREMENT; + pushback(); + return '+'; + + case '!': + if ((c = nextc()) == '=') { + yylval.nodetypeval = Node_notequal; + return RELOP; + } + if (c == '~') { + yylval.nodetypeval = Node_nomatch; + want_assign = 0; + return MATCHOP; + } + pushback(); + return '!'; + + case '<': + if (nextc() == '=') { + yylval.nodetypeval = Node_leq; + return RELOP; + } + yylval.nodetypeval = Node_less; + pushback(); + return '<'; + + case '=': + if (nextc() == '=') { + yylval.nodetypeval = Node_equal; + return RELOP; + } + yylval.nodetypeval = Node_assign; + pushback(); + return ASSIGNOP; + + case '>': + if ((c = nextc()) == '=') { + yylval.nodetypeval = Node_geq; + return RELOP; + } else if (c == '>') { + yylval.nodetypeval = Node_redirect_append; + return APPEND_OP; + } + yylval.nodetypeval = Node_greater; + pushback(); + return '>'; + + case '~': + yylval.nodetypeval = Node_match; + want_assign = 0; + return MATCHOP; + + case '}': + /* + * Added did newline stuff. Easier than + * hacking the grammar + */ + if (did_newline) { + did_newline = 0; + return c; + } + did_newline++; + --lexptr; /* pick up } next time */ + return NEWLINE; + + case '"': + esc_seen = 0; + while ((c = nextc()) != '"') { + if (c == '\n') { + pushback(); + yyerror("unterminated string"); + } + if (c == '\\') { + c = nextc(); + if (c == '\n') { + sourceline++; + continue; + } + esc_seen = 1; + tokadd('\\'); + } + if (c == '\0') { + pushback(); + yyerror("unterminated string"); + } + tokadd(c); + } + yylval.nodeval = make_str_node(tokstart, + token - tokstart, esc_seen ? SCAN : 0); + yylval.nodeval->flags |= PERM; + return YSTRING; + + case '-': + if ((c = nextc()) == '=') { + yylval.nodetypeval = Node_assign_minus; + return ASSIGNOP; + } + if (c == '-') + return DECREMENT; + pushback(); + return '-'; + + case '.': + c = nextc(); + pushback(); + if (!isdigit(c)) + return '.'; + else + c = '.'; /* FALL THROUGH */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* It's a number */ + for (;;) { + int gotnumber = 0; + + tokadd(c); + switch (c) { + case '.': + if (seen_point) { + gotnumber++; + break; + } + ++seen_point; + break; + case 'e': + case 'E': + if (seen_e) { + gotnumber++; + break; + } + ++seen_e; + if ((c = nextc()) == '-' || c == '+') + tokadd(c); + else + pushback(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + gotnumber++; + } + if (gotnumber) + break; + c = nextc(); + } + pushback(); + yylval.nodeval = make_number(atof(tokstart)); + yylval.nodeval->flags |= PERM; + return YNUMBER; + + case '&': + if ((c = nextc()) == '&') { + yylval.nodetypeval = Node_and; + for (;;) { + c = nextc(); + if (c == '\0') + break; + if (c == '#') { + while ((c = nextc()) != '\n' && c != '\0') + ; + if (c == '\0') + break; + } + if (c == '\n') + sourceline++; + if (! isspace(c)) { + pushback(); + break; + } + } + want_assign = 0; + return LEX_AND; + } + pushback(); + return '&'; + + case '|': + if ((c = nextc()) == '|') { + yylval.nodetypeval = Node_or; + for (;;) { + c = nextc(); + if (c == '\0') + break; + if (c == '#') { + while ((c = nextc()) != '\n' && c != '\0') + ; + if (c == '\0') + break; + } + if (c == '\n') + sourceline++; + if (! isspace(c)) { + pushback(); + break; + } + } + want_assign = 0; + return LEX_OR; + } + pushback(); + return '|'; + } + + if (c != '_' && ! isalpha(c)) + yyerror("Invalid char '%c' in expression\n", c); + + /* it's some type of name-type-thing. Find its length */ + token = tokstart; + while (is_identchar(c)) { + tokadd(c); + c = nextc(); + } + tokadd('\0'); + emalloc(tokkey, char *, token - tokstart, "yylex"); + memcpy(tokkey, tokstart, token - tokstart); + pushback(); + + /* See if it is a special token. */ + low = 0; + high = (sizeof (tokentab) / sizeof (tokentab[0])) - 1; + while (low <= high) { + int i/* , c */; + + mid = (low + high) / 2; + c = *tokstart - tokentab[mid].operator[0]; + i = c ? c : strcmp (tokstart, tokentab[mid].operator); + + if (i < 0) { /* token < mid */ + high = mid - 1; + } else if (i > 0) { /* token > mid */ + low = mid + 1; + } else { + if (do_lint) { + if (tokentab[mid].flags & GAWKX) + warning("%s() is a gawk extension", + tokentab[mid].operator); + if (tokentab[mid].flags & NOT_POSIX) + warning("POSIX does not allow %s", + tokentab[mid].operator); + if (tokentab[mid].flags & NOT_OLD) + warning("%s is not supported in old awk", + tokentab[mid].operator); + } + if ((do_unix && (tokentab[mid].flags & GAWKX)) + || (do_posix && (tokentab[mid].flags & NOT_POSIX))) + break; + if (tokentab[mid].class == LEX_BUILTIN + || tokentab[mid].class == LEX_LENGTH + ) + yylval.lval = mid; + else + yylval.nodetypeval = tokentab[mid].value; + + return tokentab[mid].class; + } + } + + yylval.sval = tokkey; + if (*lexptr == '(') + return FUNC_CALL; + else { + want_assign = 1; + return NAME; + } +} + +static NODE * +node_common(op) +NODETYPE op; +{ + register NODE *r; + + getnode(r); + r->type = op; + r->flags = MALLOC; + /* if lookahead is NL, lineno is 1 too high */ + if (lexeme && *lexeme == '\n') + r->source_line = sourceline - 1; + else + r->source_line = sourceline; + r->source_file = source; + return r; +} + +/* + * This allocates a node with defined lnode and rnode. + */ +NODE * +node(left, op, right) +NODE *left, *right; +NODETYPE op; +{ + register NODE *r; + + r = node_common(op); + r->lnode = left; + r->rnode = right; + return r; +} + +/* + * This allocates a node with defined subnode and proc for builtin functions + * Checks for arg. count and supplies defaults where possible. + */ +static NODE * +snode(subn, op, idx) +NODETYPE op; +int idx; +NODE *subn; +{ + register NODE *r; + register NODE *n; + int nexp = 0; + int args_allowed; + + r = node_common(op); + + /* traverse expression list to see how many args. given */ + for (n= subn; n; n= n->rnode) { + nexp++; + if (nexp > 3) + break; + } + + /* check against how many args. are allowed for this builtin */ + args_allowed = tokentab[idx].flags & ARGS; + if (args_allowed && !(args_allowed & A(nexp))) + fatal("%s() cannot have %d argument%c", + tokentab[idx].operator, nexp, nexp == 1 ? ' ' : 's'); + + r->proc = tokentab[idx].ptr; + + /* special case processing for a few builtins */ + if (nexp == 0 && r->proc == do_length) { + subn = node(node(make_number(0.0),Node_field_spec,(NODE *)NULL), + Node_expression_list, + (NODE *) NULL); + } else if (r->proc == do_match) { + if (subn->rnode->lnode->type != Node_regex) + subn->rnode->lnode = mk_rexp(subn->rnode->lnode); + } else if (r->proc == do_sub || r->proc == do_gsub) { + if (subn->lnode->type != Node_regex) + subn->lnode = mk_rexp(subn->lnode); + if (nexp == 2) + append_right(subn, node(node(make_number(0.0), + Node_field_spec, + (NODE *) NULL), + Node_expression_list, + (NODE *) NULL)); + else if (do_lint && subn->rnode->rnode->lnode->type == Node_val) + warning("string literal as last arg of substitute"); + } else if (r->proc == do_split) { + if (nexp == 2) + append_right(subn, + node(FS_node, Node_expression_list, (NODE *) NULL)); + n = subn->rnode->rnode->lnode; + if (n->type != Node_regex) + subn->rnode->rnode->lnode = mk_rexp(n); + if (nexp == 2) + subn->rnode->rnode->lnode->re_flags |= FS_DFLT; + } + + r->subnode = subn; + return r; +} + +/* + * This allocates a Node_line_range node with defined condpair and + * zeroes the trigger word to avoid the temptation of assuming that calling + * 'node( foo, Node_line_range, 0)' will properly initialize 'triggered'. + */ +/* Otherwise like node() */ +static NODE * +mkrangenode(cpair) +NODE *cpair; +{ + register NODE *r; + + getnode(r); + r->type = Node_line_range; + r->condpair = cpair; + r->triggered = 0; + return r; +} + +/* Build a for loop */ +static NODE * +make_for_loop(init, cond, incr) +NODE *init, *cond, *incr; +{ + register FOR_LOOP_HEADER *r; + NODE *n; + + emalloc(r, FOR_LOOP_HEADER *, sizeof(FOR_LOOP_HEADER), "make_for_loop"); + getnode(n); + n->type = Node_illegal; + r->init = init; + r->cond = cond; + r->incr = incr; + n->sub.nodep.r.hd = r; + return n; +} + +/* + * Install a name in the symbol table, even if it is already there. + * Caller must check against redefinition if that is desired. + */ +NODE * +install(name, value) +char *name; +NODE *value; +{ + register NODE *hp; + register int len, bucket; + + len = strlen(name); + bucket = hash(name, len); + getnode(hp); + hp->type = Node_hashnode; + hp->hnext = variables[bucket]; + variables[bucket] = hp; + hp->hlength = len; + hp->hvalue = value; + hp->hname = name; + hp->hvalue->vname = name; + return hp->hvalue; +} + +/* find the most recent hash node for name installed by install */ +NODE * +lookup(name) +char *name; +{ + register NODE *bucket; + register int len; + + len = strlen(name); + bucket = variables[hash(name, len)]; + while (bucket) { + if (bucket->hlength == len && STREQN(bucket->hname, name, len)) + return bucket->hvalue; + bucket = bucket->hnext; + } + return NULL; +} + +/* + * Add new to the rightmost branch of LIST. This uses n^2 time, so we make + * a simple attempt at optimizing it. + */ +static NODE * +append_right(list, new) +NODE *list, *new; +{ + register NODE *oldlist; + static NODE *savefront = NULL, *savetail = NULL; + + oldlist = list; + if (savefront == oldlist) { + savetail = savetail->rnode = new; + return oldlist; + } else + savefront = oldlist; + while (list->rnode != NULL) + list = list->rnode; + savetail = list->rnode = new; + return oldlist; +} + +/* + * check if name is already installed; if so, it had better have Null value, + * in which case def is added as the value. Otherwise, install name with def + * as value. + */ +static void +func_install(params, def) +NODE *params; +NODE *def; +{ + NODE *r; + + pop_params(params->rnode); + pop_var(params, 0); + r = lookup(params->param); + if (r != NULL) { + fatal("function name `%s' previously defined", params->param); + } else + (void) install(params->param, node(params, Node_func, def)); +} + +static void +pop_var(np, freeit) +NODE *np; +int freeit; +{ + register NODE *bucket, **save; + register int len; + char *name; + + name = np->param; + len = strlen(name); + save = &(variables[hash(name, len)]); + for (bucket = *save; bucket; bucket = bucket->hnext) { + if (len == bucket->hlength && STREQN(bucket->hname, name, len)) { + *save = bucket->hnext; + freenode(bucket); + if (freeit) + free(np->param); + return; + } + save = &(bucket->hnext); + } +} + +static void +pop_params(params) +NODE *params; +{ + register NODE *np; + + for (np = params; np != NULL; np = np->rnode) + pop_var(np, 1); +} + +static NODE * +make_param(name) +char *name; +{ + NODE *r; + + getnode(r); + r->type = Node_param_list; + r->rnode = NULL; + r->param = name; + r->param_cnt = param_counter++; + return (install(name, r)); +} + +/* Name points to a variable name. Make sure its in the symbol table */ +NODE * +variable(name, can_free) +char *name; +int can_free; +{ + register NODE *r; + static int env_loaded = 0; + + if (!env_loaded && STREQ(name, "ENVIRON")) { + load_environ(); + env_loaded = 1; + } + if ((r = lookup(name)) == NULL) + r = install(name, node(Nnull_string, Node_var, (NODE *) NULL)); + else if (can_free) + free(name); + return r; +} + +static NODE * +mk_rexp(exp) +NODE *exp; +{ + if (exp->type == Node_regex) + return exp; + else { + NODE *n; + + getnode(n); + n->type = Node_regex; + n->re_exp = exp; + n->re_text = NULL; + n->re_reg = NULL; + n->re_flags = 0; + n->re_cnt = 1; + return n; + } +} diff --git a/gnu/usr.bin/awk/builtin.c b/gnu/usr.bin/awk/builtin.c new file mode 100644 index 0000000000..9d5e3b302f --- /dev/null +++ b/gnu/usr.bin/awk/builtin.c @@ -0,0 +1,1133 @@ +/* + * builtin.c - Builtin functions and various utility procedures + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "awk.h" + + +#ifndef SRANDOM_PROTO +extern void srandom P((int seed)); +#endif +#ifndef linux +extern char *initstate P((unsigned seed, char *state, int n)); +extern char *setstate P((char *state)); +extern long random P((void)); +#endif + +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 + +#ifdef _CRAY +/* Work around a problem in conversion of doubles to exact integers. */ +#include +#define Floor(n) floor((n) * (1.0 + DBL_EPSILON)) +#define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON)) + +/* Force the standard C compiler to use the library math functions. */ +extern double exp(double); +double (*Exp)() = exp; +#define exp(x) (*Exp)(x) +extern double log(double); +double (*Log)() = log; +#define log(x) (*Log)(x) +#else +#define Floor(n) floor(n) +#define Ceil(n) ceil(n) +#endif + +static void +efwrite(ptr, size, count, fp, from, rp, flush) +void *ptr; +unsigned size, count; +FILE *fp; +char *from; +struct redirect *rp; +int flush; +{ + errno = 0; + if (fwrite(ptr, size, count, fp) != count) + goto wrerror; + if (flush + && ((fp == stdout && output_is_tty) + || (rp && (rp->flag & RED_NOBUF)))) { + fflush(fp); + if (ferror(fp)) + goto wrerror; + } + return; + + wrerror: + fatal("%s to \"%s\" failed (%s)", from, + rp ? rp->value : "standard output", + errno ? strerror(errno) : "reason unknown"); +} + +/* Builtin functions */ +NODE * +do_exp(tree) +NODE *tree; +{ + NODE *tmp; + double d, res; +#ifndef exp + double exp P((double)); +#endif + + tmp= tree_eval(tree->lnode); + d = force_number(tmp); + free_temp(tmp); + errno = 0; + res = exp(d); + if (errno == ERANGE) + warning("exp argument %g is out of range", d); + return tmp_number((AWKNUM) res); +} + +NODE * +do_index(tree) +NODE *tree; +{ + NODE *s1, *s2; + register char *p1, *p2; + register int l1, l2; + long ret; + + + s1 = tree_eval(tree->lnode); + s2 = tree_eval(tree->rnode->lnode); + force_string(s1); + force_string(s2); + p1 = s1->stptr; + p2 = s2->stptr; + l1 = s1->stlen; + l2 = s2->stlen; + ret = 0; + if (IGNORECASE) { + while (l1) { + if (l2 > l1) + break; + if (casetable[(int)*p1] == casetable[(int)*p2] + && (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) { + ret = 1 + s1->stlen - l1; + break; + } + l1--; + p1++; + } + } else { + while (l1) { + if (l2 > l1) + break; + if (*p1 == *p2 + && (l2 == 1 || STREQN(p1, p2, l2))) { + ret = 1 + s1->stlen - l1; + break; + } + l1--; + p1++; + } + } + free_temp(s1); + free_temp(s2); + return tmp_number((AWKNUM) ret); +} + +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); + free_temp(tmp); + return tmp_number((AWKNUM) d); +} + +NODE * +do_length(tree) +NODE *tree; +{ + NODE *tmp; + int len; + + tmp = tree_eval(tree->lnode); + len = force_string(tmp)->stlen; + free_temp(tmp); + return tmp_number((AWKNUM) len); +} + +NODE * +do_log(tree) +NODE *tree; +{ + NODE *tmp; +#ifndef log + double log P((double)); +#endif + double d, arg; + + tmp = tree_eval(tree->lnode); + arg = (double) force_number(tmp); + if (arg < 0.0) + warning("log called with negative argument %g", arg); + d = log(arg); + free_temp(tmp); + return tmp_number((AWKNUM) d); +} + +/* %e and %f formats are not properly implemented. Someone should fix them */ +/* Actually, this whole thing should be reimplemented. */ + +NODE * +do_sprintf(tree) +NODE *tree; +{ +#define bchunk(s,l) if(l) {\ + while((l)>ofre) {\ + erealloc(obuf, char *, osiz*2, "do_sprintf");\ + ofre+=osiz;\ + osiz*=2;\ + }\ + memcpy(obuf+olen,s,(l));\ + olen+=(l);\ + ofre-=(l);\ + } + + /* Is there space for something L big in the buffer? */ +#define chksize(l) if((l)>ofre) {\ + erealloc(obuf, char *, osiz*2, "do_sprintf");\ + ofre+=osiz;\ + osiz*=2;\ + } + + /* + * Get the next arg to be formatted. If we've run out of args, + * return "" (Null string) + */ +#define parse_next_arg() {\ + if(!carg) { toofew = 1; break; }\ + else {\ + arg=tree_eval(carg->lnode);\ + carg=carg->rnode;\ + }\ + } + + 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; + long *cur; + long val; +#ifdef sun386 /* Can't cast unsigned (int/long) from ptr->value */ + long tmp_uval; /* on 386i 4.0.1 C compiler -- it just hangs */ +#endif + unsigned long uval; + int sgn; + int base; + 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; + + + emalloc(obuf, char *, 120, "do_sprintf"); + 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;) { + if (*s1 != '%') { + s1++; + continue; + } + bchunk(s0, s1 - s0); + s0 = s1; + cur = &fw; + fw = 0; + prec = 0; + lj = alt = big = 0; + fill = sp; + cp = cend; + s1++; + +retry: + --n0; + switch (*s1++) { + case '%': + bchunk("%", 1); + s0 = s1; + break; + + case '0': + if (fill != sp || lj) + goto lose; + if (cur == &fw) + fill = "0"; /* FALL through */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (cur == 0) + goto lose; + *cur = s1[-1] - '0'; + while (n0 > 0 && *s1 >= '0' && *s1 <= '9') { + --n0; + *cur = *cur * 10 + *s1++ - '0'; + } + goto retry; + case '*': + if (cur == 0) + goto lose; + parse_next_arg(); + *cur = force_number(arg); + free_temp(arg); + goto retry; + case ' ': /* print ' ' or '-' */ + case '+': /* print '+' or '-' */ + signchar = *(s1-1); + goto retry; + case '-': + if (lj || fill != sp) + goto lose; + lj++; + goto retry; + case '.': + if (cur != &fw) + goto lose; + cur = ≺ + goto retry; + case '#': + if (alt) + goto lose; + alt++; + goto retry; + case 'l': + if (big) + goto lose; + big++; + goto retry; + case 'c': + parse_next_arg(); + if (arg->flags & NUMBER) { +#ifdef sun386 + tmp_uval = arg->numbr; + uval= (unsigned long) tmp_uval; +#else + uval = (unsigned long) arg->numbr; +#endif + cpbuf[0] = uval; + prec = 1; + pr_str = cpbuf; + goto dopr_string; + } + if (! prec) + prec = 1; + else if (prec > arg->stlen) + prec = arg->stlen; + pr_str = arg->stptr; + goto dopr_string; + case 's': + parse_next_arg(); + arg = force_string(arg); + if (!prec || 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; + case 'd': + case 'i': + parse_next_arg(); + val = (long) force_number(arg); + free_temp(arg); + if (val < 0) { + sgn = 1; + val = -val; + } else + sgn = 0; + do { + *--cp = '0' + val % 10; + val /= 10; + } while (val); + if (sgn) + *--cp = '-'; + else if (signchar) + *--cp = signchar; + 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--; + } + } + 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; + case 'X': + ucasehex = 1; + case 'x': + base = 16; + goto pr_unsigned; + pr_unsigned: + parse_next_arg(); + uval = (unsigned long) force_number(arg); + free_temp(arg); + do { + *--cp = chbuf[uval % base]; + if (ucasehex && isalpha(*cp)) + *cp = toupper(*cp); + uval /= base; + } while (uval); + if (alt && (base == 8 || base == 16)) { + if (base == 16) { + if (ucasehex) + *--cp = 'X'; + else + *--cp = 'x'; + } + *--cp = '0'; + } + prec = cend - cp; + if (fw > prec && !lj) { + while (fw > prec) { + bchunk(fill, 1); + fw--; + } + } + bchunk(cp, (int) prec); + if (fw > prec) { + while (fw > prec) { + bchunk(fill, 1); + fw--; + } + } + s0 = s1; + break; + case 'g': + 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'; +#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); + } +#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); + } +#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); + ofre -= len; + olen += len; + s0 = s1; + break; + + default: + lose: + break; + } + if (toofew) + fatal("%s\n\t%s\n\t%*s%s", + "not enough arguments to satisfy format string", + sfmt->stptr, s1 - sfmt->stptr - 2, "", + "^ 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->flags |= TEMP; + return r; +} + +void +do_printf(tree) +register NODE *tree; +{ + struct redirect *rp = NULL; + register FILE *fp; + + if (tree->rnode) { + int errflg; /* not used, sigh */ + + rp = redirect(tree->rnode, &errflg); + if (rp) { + fp = rp->fp; + if (!fp) + return; + } else + return; + } else + fp = stdout; + tree = do_sprintf(tree->lnode); + efwrite(tree->stptr, sizeof(char), tree->stlen, fp, "printf", rp , 1); + free_temp(tree); +} + +NODE * +do_sqrt(tree) +NODE *tree; +{ + NODE *tmp; + double arg; + extern double sqrt P((double)); + + tmp = tree_eval(tree->lnode); + arg = (double) force_number(tmp); + free_temp(tmp); + if (arg < 0.0) + warning("sqrt called with negative argument %g", arg); + return tmp_number((AWKNUM) sqrt(arg)); +} + +NODE * +do_substr(tree) +NODE *tree; +{ + NODE *t1, *t2, *t3; + NODE *r; + register int indx; + size_t length; + + t1 = tree_eval(tree->lnode); + t2 = tree_eval(tree->rnode->lnode); + if (tree->rnode->rnode == NULL) /* third arg. missing */ + length = t1->stlen; + else { + t3 = tree_eval(tree->rnode->rnode->lnode); + length = (size_t) force_number(t3); + free_temp(t3); + } + indx = (int) force_number(t2) - 1; + free_temp(t2); + t1 = force_string(t1); + if (indx < 0) + indx = 0; + if (indx >= t1->stlen || length <= 0) { + free_temp(t1); + return Nnull_string; + } + if (indx + length > t1->stlen || LONG_MAX - indx < length) + length = t1->stlen - indx; + r = tmp_string(t1->stptr + indx, length); + free_temp(t1); + return r; +} + +NODE * +do_strftime(tree) +NODE *tree; +{ + NODE *t1, *t2; + struct tm *tm; + time_t fclock; + char buf[100]; + int ret; + + t1 = force_string(tree_eval(tree->lnode)); + + if (tree->rnode == NULL) /* second arg. missing, default */ + (void) time(&fclock); + else { + t2 = tree_eval(tree->rnode->lnode); + fclock = (time_t) force_number(t2); + free_temp(t2); + } + tm = localtime(&fclock); + + ret = strftime(buf, 100, t1->stptr, tm); + + return tmp_string(buf, ret); +} + +NODE * +do_systime(tree) +NODE *tree; +{ + time_t lclock; + + (void) time(&lclock); + return tmp_number((AWKNUM) lclock); +} + +NODE * +do_system(tree) +NODE *tree; +{ + NODE *tmp; + int ret = 0; + char *cmd; + + (void) flush_io (); /* so output is synchronous with gawk's */ + tmp = tree_eval(tree->lnode); + cmd = force_string(tmp)->stptr; + if (cmd && *cmd) { + ret = system(cmd); + ret = (ret >> 8) & 0xff; + } + free_temp(tmp); + return tmp_number((AWKNUM) ret); +} + +void +do_print(tree) +register NODE *tree; +{ + register NODE *t1; + struct redirect *rp = NULL; + register FILE *fp; + register char *s; + + if (tree->rnode) { + int errflg; /* not used, sigh */ + + rp = redirect(tree->rnode, &errflg); + if (rp) { + fp = rp->fp; + if (!fp) + return; + } else + return; + } else + fp = stdout; + tree = tree->lnode; + while (tree) { + t1 = tree_eval(tree->lnode); + if (t1->flags & NUMBER) { + if (OFMTidx == CONVFMTidx) + (void) force_string(t1); + else { + char buf[100]; + + sprintf(buf, OFMT, t1->numbr); + t1 = tmp_string(buf, strlen(buf)); + } + } + efwrite(t1->stptr, sizeof(char), t1->stlen, fp, "print", rp, 0); + free_temp(t1); + tree = tree->rnode; + if (tree) { + s = OFS; + if (OFSlen) + efwrite(s, sizeof(char), OFSlen, fp, "print", rp, 0); + } + } + s = ORS; + if (ORSlen) + efwrite(s, sizeof(char), ORSlen, fp, "print", rp, 1); +} + +NODE * +do_tolower(tree) +NODE *tree; +{ + NODE *t1, *t2; + register char *cp, *cp2; + + t1 = tree_eval(tree->lnode); + t1 = force_string(t1); + t2 = tmp_string(t1->stptr, t1->stlen); + for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++) + if (isupper(*cp)) + *cp = tolower(*cp); + free_temp(t1); + return t2; +} + +NODE * +do_toupper(tree) +NODE *tree; +{ + NODE *t1, *t2; + register char *cp; + + t1 = tree_eval(tree->lnode); + t1 = force_string(t1); + t2 = tmp_string(t1->stptr, t1->stlen); + for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++) + if (islower(*cp)) + *cp = toupper(*cp); + free_temp(t1); + return t2; +} + +NODE * +do_atan2(tree) +NODE *tree; +{ + NODE *t1, *t2; + extern double atan2 P((double, double)); + double d1, d2; + + t1 = tree_eval(tree->lnode); + t2 = tree_eval(tree->rnode->lnode); + d1 = force_number(t1); + d2 = force_number(t2); + free_temp(t1); + free_temp(t2); + return tmp_number((AWKNUM) atan2(d1, d2)); +} + +NODE * +do_sin(tree) +NODE *tree; +{ + NODE *tmp; + extern double sin P((double)); + double d; + + tmp = tree_eval(tree->lnode); + d = sin((double)force_number(tmp)); + free_temp(tmp); + return tmp_number((AWKNUM) d); +} + +NODE * +do_cos(tree) +NODE *tree; +{ + NODE *tmp; + extern double cos P((double)); + double d; + + tmp = tree_eval(tree->lnode); + d = cos((double)force_number(tmp)); + free_temp(tmp); + return tmp_number((AWKNUM) d); +} + +static int firstrand = 1; +static char state[256]; + +/* ARGSUSED */ +NODE * +do_rand(tree) +NODE *tree; +{ + if (firstrand) { + (void) initstate((unsigned) 1, state, sizeof state); + srandom(1); + firstrand = 0; + } + return tmp_number((AWKNUM) random() / LONG_MAX); +} + +NODE * +do_srand(tree) +NODE *tree; +{ + NODE *tmp; + static long save_seed = 0; + long ret = save_seed; /* SVR4 awk srand returns previous seed */ + + if (firstrand) + (void) initstate((unsigned) 1, state, sizeof state); + else + (void) setstate(state); + + if (!tree) + srandom((int) (save_seed = (long) time((time_t *) 0))); + else { + tmp = tree_eval(tree->lnode); + srandom((int) (save_seed = (long) force_number(tmp))); + free_temp(tmp); + } + firstrand = 0; + return tmp_number((AWKNUM) ret); +} + +NODE * +do_match(tree) +NODE *tree; +{ + NODE *t1; + int rstart; + AWKNUM rlength; + Regexp *rp; + + t1 = force_string(tree_eval(tree->lnode)); + tree = tree->rnode->lnode; + rp = re_update(tree); + rstart = research(rp, t1->stptr, 0, t1->stlen, 1); + if (rstart >= 0) { /* match succeded */ + rstart++; /* 1-based indexing */ + rlength = REEND(rp, t1->stptr) - RESTART(rp, t1->stptr); + } else { /* match failed */ + rstart = 0; + rlength = -1.0; + } + free_temp(t1); + unref(RSTART_node->var_value); + RSTART_node->var_value = make_number((AWKNUM) rstart); + unref(RLENGTH_node->var_value); + RLENGTH_node->var_value = make_number(rlength); + return tmp_number((AWKNUM) rstart); +} + +static NODE * +sub_common(tree, global) +NODE *tree; +int global; +{ + register char *scan; + register char *bp, *cp; + char *buf; + int buflen; + register char *matchend; + register int len; + char *matchstart; + char *text; + int textlen; + char *repl; + char *replend; + int repllen; + int sofar; + int ampersands; + int matches = 0; + Regexp *rp; + NODE *s; /* subst. pattern */ + NODE *t; /* string to make sub. in; $0 if none given */ + NODE *tmp; + NODE **lhs = &tree; /* value not used -- just different from NULL */ + int priv = 0; + Func_ptr after_assign = NULL; + + tmp = tree->lnode; + rp = re_update(tmp); + + tree = tree->rnode; + s = tree->lnode; + + tree = tree->rnode; + tmp = tree->lnode; + t = force_string(tree_eval(tmp)); + + /* 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)) { + free_temp(t); + return tmp_number((AWKNUM) matches); + } + + if (tmp->type == Node_val) + lhs = NULL; + else + lhs = get_lhs(tmp, &after_assign); + t->flags |= STRING; + /* + * create a private copy of the string + */ + if (t->stref > 1 || (t->flags & PERM)) { + unsigned int saveflags; + + saveflags = t->flags; + t->flags &= ~MALLOC; + tmp = dupnode(t); + t->flags = saveflags; + t = tmp; + priv = 1; + } + text = t->stptr; + textlen = t->stlen; + buflen = textlen + 2; + + s = force_string(tree_eval(s)); + repl = s->stptr; + replend = repl + s->stlen; + repllen = replend - repl; + emalloc(buf, char *, buflen, "do_sub"); + ampersands = 0; + for (scan = repl; scan < replend; scan++) { + if (*scan == '&') { + repllen--; + ampersands++; + } else if (*scan == '\\' && (*(scan+1) == '&' || *(scan+1) == '\\')) { + repllen--; + scan++; + } + } + + bp = buf; + for (;;) { + matches++; + matchstart = t->stptr + RESTART(rp, t->stptr); + matchend = t->stptr + REEND(rp, t->stptr); + + /* + * create the result, copying in parts of the original + * string + */ + len = matchstart - text + repllen + + ampersands * (matchend - matchstart); + sofar = bp - buf; + while (buflen - sofar - len - 1 < 0) { + buflen *= 2; + erealloc(buf, char *, buflen, "do_sub"); + bp = buf + sofar; + } + for (scan = text; scan < matchstart; scan++) + *bp++ = *scan; + for (scan = repl; scan < replend; scan++) + if (*scan == '&') + for (cp = matchstart; cp < matchend; cp++) + *bp++ = *cp; + else if (*scan == '\\' && (*(scan+1) == '&' || *(scan+1) == '\\')) { + scan++; + *bp++ = *scan; + } else + *bp++ = *scan; + if (global && matchstart == matchend && matchend < text + textlen) { + *bp++ = *matchend; + matchend++; + } + textlen = text + textlen - matchend; + text = matchend; + if (!global || textlen <= 0 || + research(rp, t->stptr, text-t->stptr, textlen, 1) == -1) + break; + } + sofar = bp - buf; + if (buflen - sofar - textlen - 1) { + buflen = sofar + textlen + 2; + erealloc(buf, char *, buflen, "do_sub"); + bp = buf + sofar; + } + for (scan = matchend; scan < text + textlen; scan++) + *bp++ = *scan; + textlen = bp - buf; + free(t->stptr); + t->stptr = buf; + t->stlen = textlen; + + free_temp(s); + if (matches > 0 && lhs) { + if (priv) { + unref(*lhs); + *lhs = t; + } + if (after_assign) + (*after_assign)(); + t->flags &= ~(NUM|NUMBER); + } + return tmp_number((AWKNUM) matches); +} + +NODE * +do_gsub(tree) +NODE *tree; +{ + return sub_common(tree, 1); +} + +NODE * +do_sub(tree) +NODE *tree; +{ + return sub_common(tree, 0); +} + +#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 */ +char *buf; /* return buffer; assumed big enough to hold result */ +{ + 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; + } + } + } + return buf; +} +#endif /* GFMT_WORKAROUND */ diff --git a/gnu/usr.bin/awk/config.h b/gnu/usr.bin/awk/config.h new file mode 100644 index 0000000000..8c20953ed5 --- /dev/null +++ b/gnu/usr.bin/awk/config.h @@ -0,0 +1,272 @@ +/* + * config.h -- configuration definitions for gawk. + * + * For generic 4.4 alpha + */ + +/* + * Copyright (C) 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * This file isolates configuration dependencies for gnu awk. + * You should know something about your system, perhaps by having + * a manual handy, when you edit this file. You should copy config.h-dist + * to config.h, and edit config.h. Do not modify config.h-dist, so that + * it will be easy to apply any patches that may be distributed. + * + * The general idea is that systems conforming to the various standards + * should need to do the least amount of changing. Definining the various + * items in ths file usually means that your system is missing that + * particular feature. + * + * The order of preference in standard conformance is ANSI C, POSIX, + * and the SVID. + * + * If you have no clue as to what's going on with your system, try + * compiling gawk without editing this file and see what shows up + * missing in the link stage. From there, you can probably figure out + * which defines to turn on. + */ + +/**************************/ +/* Miscellanious features */ +/**************************/ + +/* + * BLKSIZE_MISSING + * + * Check your /usr/include/sys/stat.h file. If the stat structure + * does not have a member named st_blksize, define this. (This will + * most likely be the case on most System V systems prior to V.4.) + */ +/* #define BLKSIZE_MISSING 1 */ + +/* + * SIGTYPE + * + * The return type of the routines passed to the signal function. + * Modern systems use `void', older systems use `int'. + * If left undefined, it will default to void. + */ +/* #define SIGTYPE int */ + +/* + * SIZE_T_MISSING + * + * If your system has no typedef for size_t, define this to get a default + */ +/* #define SIZE_T_MISSING 1 */ + +/* + * CHAR_UNSIGNED + * + * If your machine uses unsigned characters (IBM RT and RS/6000 and others) + * then define this for use in regex.c + */ +/* #define CHAR_UNSIGNED 1 */ + +/* + * HAVE_UNDERSCORE_SETJMP + * + * Check in your /usr/include/setjmp.h file. If there are routines + * there named _setjmp and _longjmp, then you should define this. + * Typically only systems derived from Berkeley Unix have this. + */ +#define HAVE_UNDERSCORE_SETJMP 1 + +/***********************************************/ +/* Missing library subroutines or system calls */ +/***********************************************/ + +/* + * MEMCMP_MISSING + * MEMCPY_MISSING + * MEMSET_MISSING + * + * These three routines are for manipulating blocks of memory. Most + * likely they will either all three be present or all three be missing, + * so they're grouped together. + */ +/* #define MEMCMP_MISSING 1 */ +/* #define MEMCPY_MISSING 1 */ +/* #define MEMSET_MISSING 1 */ + +/* + * RANDOM_MISSING + * + * Your system does not have the random(3) suite of random number + * generating routines. These are different than the old rand(3) + * routines! + */ +/* #define RANDOM_MISSING 1 */ + +/* + * STRCASE_MISSING + * + * Your system does not have the strcasemp() and strncasecmp() + * routines that originated in Berkeley Unix. + */ +/* #define STRCASE_MISSING 1 */ + +/* + * STRCHR_MISSING + * + * Your system does not have the strchr() and strrchr() functions. + */ +/* #define STRCHR_MISSING 1 */ + +/* + * STRERROR_MISSING + * + * Your system lacks the ANSI C strerror() routine for returning the + * strings associated with errno values. + */ +/* #define STRERROR_MISSING 1 */ + +/* + * STRTOD_MISSING + * + * Your system does not have the strtod() routine for converting + * strings to double precision floating point values. + */ +/* #define STRTOD_MISSING 1 */ + +/* + * STRFTIME_MISSING + * + * Your system lacks the ANSI C strftime() routine for formatting + * broken down time values. + */ +/* #define STRFTIME_MISSING 1 */ + +/* + * TZSET_MISSING + * + * If you have a 4.2 BSD vintage system, then the strftime() routine + * supplied in the missing directory won't be enough, because it relies on the + * tzset() routine from System V / Posix. Fortunately, there is an + * emulation for tzset() too that should do the trick. If you don't + * have tzset(), define this. + */ +/* #define TZSET_MISSING 1 */ + +/* + * TZNAME_MISSING + * + * Some systems do not support the external variables tzname and daylight. + * If this is the case *and* strftime() is missing, define this. + */ +/* #define TZNAME_MISSING 1 */ + +/* + * STDC_HEADERS + * + * If your system does have ANSI compliant header files that + * provide prototypes for library routines, then define this. + */ +#define STDC_HEADERS 1 + +/* + * NO_TOKEN_PASTING + * + * If your compiler define's __STDC__ but does not support token + * pasting (tok##tok), then define this. + */ +/* #define NO_TOKEN_PASTING 1 */ + +/*****************************************************************/ +/* Stuff related to the Standard I/O Library. */ +/*****************************************************************/ +/* Much of this is (still, unfortunately) black magic in nature. */ +/* You may have to use some or all of these together to get gawk */ +/* to work correctly. */ +/*****************************************************************/ + +/* + * NON_STD_SPRINTF + * + * Look in your /usr/include/stdio.h file. If the return type of the + * sprintf() function is NOT `int', define this. + */ +/* #define NON_STD_SPRINTF 1 */ + +/* + * VPRINTF_MISSING + * + * Define this if your system lacks vprintf() and the other routines + * that go with it. This will trigger an attempt to use _doprnt(). + * If you don't have that, this attempt will fail and you are on your own. + */ +/* #define VPRINTF_MISSING 1 */ + +/* + * Casts from size_t to int and back. These will become unnecessary + * at some point in the future, but for now are required where the + * two types are a different representation. + */ +/* #define SZTC */ +/* #define INTC */ + +/* + * SYSTEM_MISSING + * + * Define this if your library does not provide a system function + * or you are not entirely happy with it and would rather use + * a provided replacement (atari only). + */ +/* #define SYSTEM_MISSING 1 */ + +/* + * FMOD_MISSING + * + * Define this if your system lacks the fmod() function and modf() will + * be used instead. + */ +/* #define FMOD_MISSING 1 */ + + +/*******************************/ +/* Gawk configuration options. */ +/*******************************/ + +/* + * DEFPATH + * + * The default search path for the -f option of gawk. It is used + * if the AWKPATH environment variable is undefined. The default + * definition is provided here. Most likely you should not change + * this. + */ + +/* #define DEFPATH ".:/usr/lib/awk:/usr/local/lib/awk" */ +/* #define ENVSEP ':' */ + +/* + * alloca already has a prototype defined - don't redefine it + */ +#define ALLOCA_PROTO 1 + +/* + * srandom already has a prototype defined - don't redefine it + */ +#define SRANDOM_PROTO 1 + +/* 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 new file mode 100644 index 0000000000..5293c75587 --- /dev/null +++ b/gnu/usr.bin/awk/dfa.c @@ -0,0 +1,2291 @@ +/* dfa.c - determinisitic 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" +#include + +#ifdef setbit /* surprise - setbit and clrbit are macros on NeXT */ +#undef setbit +#endif +#ifdef clrbit +#undef clrbit +#endif + +#ifdef __STDC__ +typedef void *ptr_t; +#else +typedef char *ptr_t; +#endif + +typedef struct { + char ** in; + char * left; + char * right; + char * is; +} must; + +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, + 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 ptr_t +xcalloc(n, s) + int n; + size_t s; +{ + ptr_t r = calloc(n, s); + + if (NULL == r) + reg_error("Memory exhausted"); /* reg_error does not return */ + return r; +} + +static ptr_t +xmalloc(n) + size_t n; +{ + ptr_t r = malloc(n); + + assert(n != 0); + if (NULL == r) + reg_error("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 (NULL == r) + reg_error("Memory exhausted"); + return r; +} + +#define CALLOC(p, t, n) ((p) = (t *) xcalloc((n), sizeof (t))) +#undef MALLOC +#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); \ + } + +/* Stuff pertaining to charsets. */ + +static int +tstbit(b, c) + int b; + _charset c; +{ + return c[b / INTBITS] & 1 << b % INTBITS; +} + +static void +setbit(b, c) + int b; + _charset c; +{ + c[b / INTBITS] |= 1 << b % INTBITS; +} + +static void +clrbit(b, c) + int b; + _charset c; +{ + c[b / INTBITS] &= ~(1 << b % INTBITS); +} + +static void +copyset(src, dst) + const _charset src; + _charset dst; +{ + int i; + + for (i = 0; i < _CHARSET_INTS; ++i) + dst[i] = src[i]; +} + +static void +zeroset(s) + _charset s; +{ + int i; + + for (i = 0; i < _CHARSET_INTS; ++i) + s[i] = 0; +} + +static void +notset(s) + _charset s; +{ + int i; + + for (i = 0; i < _CHARSET_INTS; ++i) + s[i] = ~s[i]; +} + +static int +equal(s1, s2) + const _charset s1; + const _charset s2; +{ + int i; + + for (i = 0; i < _CHARSET_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. */ +static int +charset_index(s) + const _charset s; +{ + int i; + + for (i = 0; i < reg->cindex; ++i) + if (equal(s, reg->charsets[i])) + return i; + REALLOC_IF_NECESSARY(reg->charsets, _charset, reg->calloc, reg->cindex); + ++reg->cindex; + copyset(s, reg->charsets[i]); + return i; +} + +/* Syntax bits controlling the behavior of the lexical analyzer. */ +static syntax_bits, syntax_bits_set; + +/* Flag for case-folding letters into sets. */ +static case_fold; + +/* Entry point to set syntax options. */ +void +regsyntax(bits, fold) + long bits; + int fold; +{ + syntax_bits_set = 1; + syntax_bits = bits; + case_fold = fold; +} + +/* Lexical analyzer. */ +static const char *lexstart; /* Pointer to beginning of input string. */ +static const 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). */ + +/* Note that characters become unsigned here. */ +#define FETCH(c, eoferr) \ + { \ + if (! lexleft) \ + if (eoferr != NULL) \ + reg_error(eoferr); \ + else \ + return _END; \ + (c) = (unsigned char) *lexptr++; \ + --lexleft; \ + } + +static _token +lex() +{ + _token c, c2; + int invert; + _charset cset; + + FETCH(c, (char *) 0); + switch (c) + { + 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"); + switch (c) + { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + caret_allowed = 0; + closure_allowed = 1; + return _BACKREF; + + case '<': + caret_allowed = 0; + return _BEGWORD; + + case '>': + caret_allowed = 0; + return _ENDWORD; + + case 'b': + caret_allowed = 0; + return _LIMWORD; + + 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); + + case '?': + if (syntax_bits & RE_BK_PLUS_QM) + goto qmark; + goto normal_char; + + case '+': + if (syntax_bits & RE_BK_PLUS_QM) + goto plus; + goto normal_char; + + case '|': + if (! (syntax_bits & RE_NO_BK_VBAR)) + goto or; + goto normal_char; + + case '(': + if (! (syntax_bits & RE_NO_BK_PARENS)) + goto lparen; + goto normal_char; + + case ')': + if (! (syntax_bits & RE_NO_BK_PARENS)) + goto rparen; + goto normal_char; + + default: + goto normal_char; + } + + 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 == '^') + { + FETCH(c, "Unbalanced ["); + invert = 1; + } + else + invert = 0; + do + { + FETCH(c2, "Unbalanced ["); + if ((syntax_bits & RE_AWK_CLASS_HACK) && c == '\\') + { + c = c2; + FETCH(c2, "Unbalanced ["); + } + if (c2 == '-') + { + FETCH(c2, "Unbalanced ["); + if (c2 == ']' && (syntax_bits & RE_AWK_CLASS_HACK)) + { + setbit(c, cset); + setbit('-', cset); + break; + } + while (c <= c2) + setbit(c++, cset); + FETCH(c, "Unbalanced ["); + } + else + { + setbit(c, cset); + c = c2; + } + } + while (c != ']'); + if (invert) + notset(cset); + caret_allowed = 0; + closure_allowed = 1; + return _SET + charset_index(cset); + + 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); + } + return c; + } +} + +/* 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 + reganalyze(). */ + +/* 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(reg->tokens, _token, reg->talloc, reg->tindex); + reg->tokens[reg->tindex++] = t; + + switch (t) + { + case _QMARK: + case _STAR: + case _PLUS: + break; + + case _CAT: + case _OR: + --depth; + break; + + default: + ++reg->nleaves; + case _EMPTY: + ++depth; + break; + } + if (depth > reg->depth) + reg->depth = depth; +} + +/* The grammar understood by the parser is as follows. + + start: + regexp + _ALLBEGLINE regexp + regexp _ALLENDLINE + _ALLBEGLINE regexp _ALLENDLINE + + regexp: + regexp _OR branch + branch + + branch: + branch closure + closure + + closure: + closure _QMARK + closure _STAR + closure _PLUS + atom + + atom: + + _SET + _BACKREF + _BEGLINE + _ENDLINE + _BEGWORD + _ENDWORD + _LIMWORD + _NOTLIMWORD + + + 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)) + { + addtok(tok); + tok = lex(); + } + else if (tok == _LPAREN) + { + tok = lex(); + regexp(); + if (tok != _RPAREN) + reg_error("Unbalanced ("); + tok = lex(); + } + else + addtok(_EMPTY); +} + +static void +closure() +{ + atom(); + while (tok == _QMARK || tok == _STAR || tok == _PLUS) + { + addtok(tok); + tok = lex(); + } +} + +static void +branch() +{ + closure(); + while (tok != _RPAREN && tok != _OR && tok != _ALLENDLINE && tok >= 0) + { + closure(); + addtok(_CAT); + } +} + +static void +regexp() +{ + branch(); + while (tok == _OR) + { + tok = lex(); + branch(); + 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. */ +void +regparse(s, len, r) + const char *s; + size_t len; + struct regexp *r; +{ + reg = r; + lexstart = lexptr = s; + lexleft = len; + caret_allowed = 1; + closure_allowed = 0; + + if (! syntax_bits_set) + reg_error("No syntax specified"); + + tok = lex(); + depth = r->depth; + + if (tok == _ALLBEGLINE) + { + addtok(_BEGLINE); + tok = lex(); + regexp(); + addtok(_CAT); + } + else + regexp(); + + if (tok == _ALLENDLINE) + { + addtok(_ENDLINE); + addtok(_CAT); + tok = lex(); + } + + if (tok != _END) + reg_error("Unbalanced )"); + + addtok(_END - r->nregexps); + addtok(_CAT); + + if (r->nregexps) + addtok(_OR); + + ++r->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; +{ + 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(r, s, newline, letter) + struct regexp *r; + _position_set *s; + int newline; + int letter; +{ + int lhash = 0; + int constraint; + int i, j; + + newline = newline ? 1 : 0; + letter = letter ? 1 : 0; + + for (i = 0; i < s->nelem; ++i) + lhash ^= 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) + { + if (lhash != r->states[i].hash || s->nelem != r->states[i].elems.nelem + || newline != r->states[i].newline || letter != r->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) + 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; + for (j = 0; j < s->nelem; ++j) + if (r->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]; + } + else if (r->tokens[s->elems[j].index] == _BACKREF) + { + r->states[i].constraint = _NO_CONSTRAINT; + r->states[i].backref = 1; + } + + ++r->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(s, r) + _position_set *s; + struct regexp *r; +{ + int i, j; + int *visited; + _position p, old; + + MALLOC(visited, int, r->tindex); + for (i = 0; i < r->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) + { + old = s->elems[i]; + p.constraint = old.constraint; + delete(s->elems[i], s); + if (visited[old.index]) + { + --i; + continue; + } + visited[old.index] = 1; + switch (r->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 &= _ENDWORD_CONSTRAINT; + break; + case _NOTLIMWORD: + p.constraint &= _NOTLIMWORD_CONSTRAINT; + break; + default: + break; + } + for (j = 0; j < r->follows[old.index].nelem; ++j) + { + p.index = r->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 +reganalyze(r, searchflag) + struct regexp *r; + 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; + + r->searchflag = searchflag; + + MALLOC(nullable, int, r->depth); + o_nullable = nullable; + MALLOC(nfirstpos, int, r->depth); + o_nfirst = nfirstpos; + MALLOC(firstpos, _position, r->nleaves); + o_firstpos = firstpos, firstpos += r->nleaves; + MALLOC(nlastpos, int, r->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) + nalloc[i] = 0; + MALLOC(merged.elems, _position, r->nleaves); + + CALLOC(r->follows, _position_set, r->tindex); + + for (i = 0; i < r->tindex; ++i) + switch (r->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, &r->follows[pos[j].index], &merged); + REALLOC_IF_NECESSARY(r->follows[pos[j].index].elems, _position, + nalloc[pos[j].index], merged.nelem - 1); + copy(&merged, &r->follows[pos[j].index]); + } + + case _QMARK: + /* A _QMARK or _STAR node is automatically nullable. */ + if (r->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, &r->follows[pos[j].index], &merged); + REALLOC_IF_NECESSARY(r->follows[pos[j].index].elems, _position, + nalloc[pos[j].index], merged.nelem - 1); + copy(&merged, &r->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: + /* 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++ = r->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(r->follows[i].elems, _position, nalloc[i]); + break; + } + + /* 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) + { + 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]); + } + + /* 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, r); + + /* 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. */ + r->salloc = 1; + r->sindex = 0; + MALLOC(r->states, _dfa_state, r->salloc); + state_index(r, &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 r, 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 +regstate(s, r, trans) + int s; + struct regexp *r; + int trans[]; +{ + _position_set grps[_NOTCHAR]; /* As many as will ever be needed. */ + _charset 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. */ + int matchesf; /* True if matches is nonempty. */ + _charset intersect; /* Intersection with some label set. */ + int intersectf; /* True if intersect is nonempty. */ + _charset 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. */ + 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 < r->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); + else + continue; + + /* Some characters may need to be climinated from matches because + they fail in the current context. */ + if (pos.constraint != 0xff) + { + if (! _MATCHES_NEWLINE_CONTEXT(pos.constraint, + r->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) + matches[j] &= newline[j]; + if (! _MATCHES_LETTER_CONTEXT(pos.constraint, + r->states[s].letter, 1)) + for (j = 0; j < _CHARSET_INTS; ++j) + matches[j] &= ~letters[j]; + if (! _MATCHES_LETTER_CONTEXT(pos.constraint, + r->states[s].letter, 0)) + for (j = 0; j < _CHARSET_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) + 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 (r->tokens[pos.index] >= 0 && r->tokens[pos.index] < _NOTCHAR + && !tstbit(r->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; + if (! intersectf) + continue; + + /* It does; now find the set differences both ways. */ + leftoversf = matchesf = 0; + for (k = 0; k < _CHARSET_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, r->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, r->nleaves); + grps[ngrps].nelem = 1; + grps[ngrps].elems[0] = pos; + ++ngrps; + } + } + + MALLOC(follows.elems, _position, r->nleaves); + MALLOC(tmp.elems, _position, r->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) + { + wants_newline = 0; + wants_letter = 0; + for (i = 0; i < r->states[0].elems.nelem; ++i) + { + if (_PREV_NEWLINE_DEPENDENT(r->states[0].elems.elems[i].constraint)) + wants_newline = 1; + if (_PREV_LETTER_DEPENDENT(r->states[0].elems.elems[i].constraint)) + wants_letter = 1; + } + copy(&r->states[0].elems, &follows); + state = state_index(r, &follows, 0, 0); + if (wants_newline) + state_newline = state_index(r, &follows, 1, 0); + else + state_newline = state; + if (wants_letter) + state_letter = state_index(r, &follows, 0, 1); + else + state_letter = state; + for (i = 0; i < _NOTCHAR; ++i) + trans[i] = (ISALNUM(i)) ? state_letter : state ; + trans['\n'] = state_newline; + } + 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 < r->follows[grps[i].elems[j].index].nelem; ++k) + insert(r->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); + + /* 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 < _CHARSET_INTS; ++j) + if (labels[i][j] & letters[j]) + break; + if (j < _CHARSET_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(r, &follows, 0, 0); + if (wants_newline) + state_newline = state_index(r, &follows, 1, 0); + else + state_newline = state; + if (wants_letter) + state_letter = state_index(r, &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 (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 regexp'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. + TODO: Improve this comment, get rid of the unnecessary redundancy. */ + +static void +build_state(s, r) + int s; + struct regexp *r; +{ + 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 (r->trcount >= 1024) + { + for (i = 0; i < r->tralloc; ++i) + if (r->trans[i]) + { + free((ptr_t) r->trans[i]); + r->trans[i] = NULL; + } + else if (r->fails[i]) + { + free((ptr_t) r->fails[i]); + r->fails[i] = NULL; + } + r->trcount = 0; + } + + ++r->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); + + /* 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) + { + 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) + { + r->trans[oldalloc] = NULL; + r->fails[oldalloc++] = NULL; + } + } + + /* Keep the newline transition in a special place so we can use it as + a sentinel. */ + r->newlines[s] = trans['\n']; + trans['\n'] = -1; + + if (ACCEPTING(s, *r)) + r->fails[s] = trans; + else + r->trans[s] = trans; +} + +static void +build_state_zero(r) + struct regexp *r; +{ + 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); +} + +/* Search through a buffer looking for a match to the given struct regexp. + 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 * +regexecute(r, begin, end, newline, count, backref) + struct regexp *r; + 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 r->trans so it can be optimized + into a register. */ + static sbit[_NOTCHAR]; /* Table for anding with r->success. */ + static sbit_init; + + if (! sbit_init) + { + int i; + + sbit_init = 1; + for (i = 0; i < _NOTCHAR; ++i) + sbit[i] = (ISALNUM(i)) ? 2 : 1; + sbit['\n'] = 4; + } + + if (! r->tralloc) + build_state_zero(r); + + s = s1 = 0; + p = (unsigned char *) begin; + trans = r->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++]; + } + + if (s >= 0 && p <= (unsigned char *) end && r->fails[s]) + { + if (r->success[s] & sbit[*p]) + { + if (backref) + *backref = (r->states[s].backref != 0); + return (char *) p; + } + + s1 = s; + s = r->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, r); + trans = r->trans; + continue; + } + + if (p[-1] == '\n' && newline) + { + s = r->newlines[s1]; + continue; + } + + s = 0; + } +} + +/* Initialize the components of a regexp that the other routines don't + initialize for themselves. */ +void +reginit(r) + struct regexp *r; +{ + r->calloc = 1; + MALLOC(r->charsets, _charset, r->calloc); + r->cindex = 0; + + r->talloc = 1; + MALLOC(r->tokens, _token, r->talloc); + r->tindex = r->depth = r->nleaves = r->nregexps = 0; + + r->searchflag = 0; + r->tralloc = 0; +} + +/* Parse and analyze a single string of the given length. */ +void +regcompile(s, len, r, searchflag) + const char *s; + size_t len; + struct regexp *r; + int searchflag; +{ + if (case_fold) /* dummy folding in service of regmust() */ + { + char *regcopy; + int i; + + regcopy = malloc(len); + if (!regcopy) + reg_error("out of memory"); + + /* This is a complete kludge and could potentially break + \ escapes . . . */ + case_fold = 0; + for (i = 0; i < len; ++i) + if (ISUPPER(s[i])) + regcopy[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); + case_fold = 1; + reginit(r); + regparse(s, len, r); + reganalyze(r, searchflag); + } + else + { + reginit(r); + regparse(s, len, r); + regmust(r); + reganalyze(r, searchflag); + } +} + +/* Free the storage held by the components of a regexp. */ +void +reg_free(r) + struct regexp *r; +{ + 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); +} + +/* +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 + 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; +const 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; +} + +static char * +icpyalloc(string) +const char * string; +{ + return icatalloc((char *) NULL, string); +} + +static char * +istrstr(lookin, lookfor) +char * lookin; +register 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; +} + +static void +ifree(cp) +char * cp; +{ + if (cp != NULL) + free(cp); +} + +static void +freelist(cpp) +register char ** cpp; +{ + register 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) +register char ** cpp; +register char * new; +#ifdef __STDC__ +size_t len; +#else +int len; +#endif +{ + register 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; + 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; +{ + 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; + } + return cpp; +} + +static char ** +addlists(old, 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; +} + +/* +** Given two lists of substrings, +** return a new list giving substrings common to both. +*/ + +static char ** +inboth(left, 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; + } + } + return both; +} + +/* +typedef struct { + char ** in; + char * left; + char * right; + char * is; +} must; + */ +static void +resetmust(mp) +register must * mp; +{ + mp->left[0] = mp->right[0] = mp->is[0] = '\0'; + freelist(mp->in); +} + +static void +regmust(r) +register struct regexp * r; +{ + 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); + } + free((char *) mp); +} diff --git a/gnu/usr.bin/awk/dfa.h b/gnu/usr.bin/awk/dfa.h new file mode 100644 index 0000000000..65fc49565a --- /dev/null +++ b/gnu/usr.bin/awk/dfa.h @@ -0,0 +1,543 @@ +/* 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 + +#else /* ! __STDC__ */ + +#define const + +#define ISALNUM(c) (isascii(c) && isalnum(c)) +#define ISALPHA(c) (isascii(c) && isalpha(c)) +#define ISUPPER(c) (isascii(c) && isupper(c)) + +#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 + +/* 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) + +/* 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) + +/* Sets of unsigned characters are stored as bit vectors in arrays of ints. */ +typedef int _charset[_CHARSET_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 + 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 \; 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. */ + + _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 + 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 + 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. */ + + _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. */ + + _LPAREN, /* _LPAREN never appears in the parse tree, + it is only a lexeme. */ + + _RPAREN, /* _RPAREN never appears in the parse tree. */ + + _SET /* _SET and (and any value greater) is a + terminal symbol that matches any of a + class of characters. */ +} _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) + +/* 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 regexp 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 \. */ + unsigned char constraint; /* Constraint for this state to accept. */ + 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 + +/* A compiled regular expression. */ +struct regexp +{ + /* 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. */ + + /* 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 regparse(). */ + + /* Stuff owned by the state builder. */ + _dfa_state *states; /* States of the regexp. */ + 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 + regexecute 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. */ + char must[MUST_MAX]; + int mustn; +}; + +/* Some macros for user access to regexp 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, \ + 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) + +/* Entry points. */ + +#ifdef __STDC__ + +/* Regsyntax() 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); + +/* Compile the given string of the given length into the given struct regexp. + 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); + +/* Execute the given struct regexp 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 *regexecute(struct regexp *, char *, char *, int, int *, int *); + +/* Free the storage held by the components of a struct regexp. */ +extern void reg_free(struct regexp *); + +/* Entry points for people who know what they're doing. */ + +/* Initialize the components of a struct regexp. */ +extern void reginit(struct regexp *); + +/* Incrementally parse a string of given length into a struct regexp. */ +extern void regparse(const char *, size_t, struct regexp *); + +/* Analyze a parsed regexp; second argument tells whether to build a searching + or an exact matcher. */ +extern void reganalyze(struct regexp *, 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 []); + +/* Error handling. */ + +/* Regerror() 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 *); + +#else /* ! __STDC__ */ +extern void regsyntax(), regcompile(), reg_free(), reginit(), regparse(); +extern void reganalyze(), regstate(), reg_error(); +extern char *regexecute(); +#endif diff --git a/gnu/usr.bin/awk/eval.c b/gnu/usr.bin/awk/eval.c new file mode 100644 index 0000000000..f640f3733a --- /dev/null +++ b/gnu/usr.bin/awk/eval.c @@ -0,0 +1,1225 @@ +/* + * eval.c - gawk parse tree interpreter + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +extern double pow P((double x, double y)); +extern double modf P((double x, double *yp)); +extern double fmod P((double x, double y)); + +static int eval_condition P((NODE *tree)); +static NODE *op_assign P((NODE *tree)); +static NODE *func_call P((NODE *name, NODE *arg_list)); +static NODE *match_op P((NODE *tree)); + +NODE *_t; /* used as a temporary in macros */ +#ifdef MSDOS +double _msc51bug; /* to get around a bug in MSC 5.1 */ +#endif +NODE *ret_node; +int OFSlen; +int ORSlen; +int OFMTidx; +int CONVFMTidx; + +/* Macros and variables to save and restore function and loop bindings */ +/* + * the val variable allows return/continue/break-out-of-context to be + * caught and diagnosed + */ +#define PUSH_BINDING(stack, x, val) (memcpy ((char *)(stack), (char *)(x), sizeof (jmp_buf)), val++) +#define RESTORE_BINDING(stack, x, val) (memcpy ((char *)(x), (char *)(stack), sizeof (jmp_buf)), val--) + +static jmp_buf loop_tag; /* always the current binding */ +static int loop_tag_valid = 0; /* nonzero when loop_tag valid */ +static int func_tag_valid = 0; +static jmp_buf func_tag; +extern int exiting, exit_val; + +/* + * This table is used by the regexp routines to do case independant + * matching. Basically, every ascii character maps to itself, except + * uppercase letters map to lower case ones. This table has 256 + * entries, which may be overkill. Note also that if the system this + * is compiled on doesn't use 7-bit ascii, casetable[] should not be + * defined to the linker, so gawk should not load. + * + * Do NOT make this array static, it is used in several spots, not + * just in this file. + */ +#if 'a' == 97 /* it's ascii */ +char casetable[] = { + '\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', + /* '0' '1' '2' '3' '4' '5' '6' '7' */ + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + /* '8' '9' ':' ';' '<' '=' '>' '?' */ + '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + /* '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G' */ + '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + /* 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' */ + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + /* 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' */ + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + /* 'X' 'Y' 'Z' '[' '\' ']' '^' '_' */ + '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', + /* '`' 'a' 'b' 'c' 'd' 'e' 'f' 'g' */ + '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + /* 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' */ + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + /* 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' */ + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + /* 'x' 'y' 'z' '{' '|' '}' '~' */ + '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', + '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', + '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', + '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', + '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', + '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', + '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', + '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', + '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', +}; +#else +#include "You lose. You will need a translation table for your character set." +#endif + +/* + * Tree is a bunch of rules to run. Returns zero if it hit an exit() + * statement + */ +int +interpret(tree) +register NODE *volatile tree; +{ + jmp_buf volatile loop_tag_stack; /* shallow binding stack for loop_tag */ + static jmp_buf rule_tag; /* tag the rule currently being run, for NEXT + * and EXIT statements. It is static because + * there are no nested rules */ + register NODE *volatile t = NULL; /* temporary */ + NODE **volatile lhs; /* lhs == Left Hand Side for assigns, etc */ + NODE *volatile stable_tree; + int volatile traverse = 1; /* True => loop thru tree (Node_rule_list) */ + + if (tree == NULL) + return 1; + sourceline = tree->source_line; + source = tree->source_file; + switch (tree->type) { + case Node_rule_node: + traverse = 0; /* False => one for-loop iteration only */ + /* FALL THROUGH */ + case Node_rule_list: + for (t = tree; t != NULL; t = t->rnode) { + if (traverse) + tree = t->lnode; + sourceline = tree->source_line; + source = tree->source_file; + switch (setjmp(rule_tag)) { + case 0: /* normal non-jump */ + /* test pattern, if any */ + if (tree->lnode == NULL || + eval_condition(tree->lnode)) + (void) interpret(tree->rnode); + break; + case TAG_CONTINUE: /* NEXT statement */ + return 1; + case TAG_BREAK: + return 0; + default: + cant_happen(); + } + if (!traverse) /* case Node_rule_node */ + break; /* don't loop */ + } + break; + + case Node_statement_list: + for (t = tree; t != NULL; t = t->rnode) + (void) interpret(t->lnode); + break; + + case Node_K_if: + if (eval_condition(tree->lnode)) { + (void) interpret(tree->rnode->lnode); + } else { + (void) interpret(tree->rnode->rnode); + } + break; + + case Node_K_while: + PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + + stable_tree = tree; + while (eval_condition(stable_tree->lnode)) { + switch (setjmp(loop_tag)) { + case 0: /* normal non-jump */ + (void) interpret(stable_tree->rnode); + break; + case TAG_CONTINUE: /* continue statement */ + break; + case TAG_BREAK: /* break statement */ + RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + return 1; + default: + cant_happen(); + } + } + RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + break; + + case Node_K_do: + PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + stable_tree = tree; + do { + switch (setjmp(loop_tag)) { + case 0: /* normal non-jump */ + (void) interpret(stable_tree->rnode); + break; + case TAG_CONTINUE: /* continue statement */ + break; + case TAG_BREAK: /* break statement */ + RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + return 1; + default: + cant_happen(); + } + } while (eval_condition(stable_tree->lnode)); + RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + break; + + case Node_K_for: + PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + (void) interpret(tree->forloop->init); + stable_tree = tree; + while (eval_condition(stable_tree->forloop->cond)) { + switch (setjmp(loop_tag)) { + case 0: /* normal non-jump */ + (void) interpret(stable_tree->lnode); + /* fall through */ + case TAG_CONTINUE: /* continue statement */ + (void) interpret(stable_tree->forloop->incr); + break; + case TAG_BREAK: /* break statement */ + RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + return 1; + default: + cant_happen(); + } + } + RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + break; + + case Node_K_arrayfor: + { + volatile struct search l; /* For array_for */ + Func_ptr after_assign = NULL; + +#define hakvar forloop->init +#define arrvar forloop->incr + PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + lhs = get_lhs(tree->hakvar, &after_assign); + t = tree->arrvar; + if (t->type == Node_param_list) + t = stack_ptr[t->param_cnt]; + stable_tree = tree; + for (assoc_scan(t, (struct search *)&l); + l.retval; + assoc_next((struct search *)&l)) { + unref(*((NODE **) lhs)); + *lhs = dupnode(l.retval); + if (after_assign) + (*after_assign)(); + switch (setjmp(loop_tag)) { + case 0: + (void) interpret(stable_tree->lnode); + case TAG_CONTINUE: + break; + + case TAG_BREAK: + RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + return 1; + default: + cant_happen(); + } + } + RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + break; + } + + case Node_K_break: + if (loop_tag_valid == 0) + fatal("unexpected break"); + longjmp(loop_tag, TAG_BREAK); + break; + + case Node_K_continue: + if (loop_tag_valid == 0) { + /* + * AT&T nawk treats continue outside of loops like + * next. Allow it if not posix, and complain if + * lint. + */ + static int warned = 0; + + if (do_lint && ! warned) { + warning("use of `continue' outside of loop is not portable"); + warned = 1; + } + if (do_posix) + fatal("use of `continue' outside of loop is not allowed"); + longjmp(rule_tag, TAG_CONTINUE); + } else + longjmp(loop_tag, TAG_CONTINUE); + break; + + case Node_K_print: + do_print(tree); + break; + + case Node_K_printf: + do_printf(tree); + break; + + case Node_K_delete: + do_delete(tree->lnode, tree->rnode); + break; + + case Node_K_next: + longjmp(rule_tag, TAG_CONTINUE); + break; + + case Node_K_nextfile: + do_nextfile(); + break; + + case Node_K_exit: + /* + * In A,K,&W, p. 49, it says that an exit statement "... + * causes the program to behave as if the end of input had + * occurred; no more input is read, and the END actions, if + * any are executed." This implies that the rest of the rules + * are not done. So we immediately break out of the main loop. + */ + exiting = 1; + if (tree) { + t = tree_eval(tree->lnode); + exit_val = (int) force_number(t); + } + free_temp(t); + longjmp(rule_tag, TAG_BREAK); + break; + + case Node_K_return: + t = tree_eval(tree->lnode); + ret_node = dupnode(t); + free_temp(t); + longjmp(func_tag, TAG_RETURN); + break; + + default: + /* + * Appears to be an expression statement. Throw away the + * value. + */ + if (do_lint && tree->type == Node_var) + warning("statement has no effect"); + t = tree_eval(tree); + free_temp(t); + break; + } + return 1; +} + +/* evaluate a subtree */ + +NODE * +r_tree_eval(tree) +register NODE *tree; +{ + register NODE *r, *t1, *t2; /* return value & temporary subtrees */ + register NODE **lhs; + register int di; + AWKNUM x, x1, x2; + long lx; +#ifdef CRAY + long lx2; +#endif + +#ifdef DEBUG + if (tree == NULL) + return Nnull_string; + if (tree->type == Node_val) { + if (tree->stref <= 0) cant_happen(); + return tree; + } + if (tree->type == Node_var) { + if (tree->var_value->stref <= 0) cant_happen(); + return tree->var_value; + } + if (tree->type == Node_param_list) { + if (stack_ptr[tree->param_cnt] == NULL) + return Nnull_string; + else + return stack_ptr[tree->param_cnt]->var_value; + } +#endif + switch (tree->type) { + case Node_and: + return tmp_number((AWKNUM) (eval_condition(tree->lnode) + && eval_condition(tree->rnode))); + + case Node_or: + return tmp_number((AWKNUM) (eval_condition(tree->lnode) + || eval_condition(tree->rnode))); + + case Node_not: + return tmp_number((AWKNUM) ! eval_condition(tree->lnode)); + + /* Builtins */ + case Node_builtin: + return ((*tree->proc) (tree->subnode)); + + case Node_K_getline: + return (do_getline(tree)); + + case Node_in_array: + return tmp_number((AWKNUM) in_array(tree->lnode, tree->rnode)); + + case Node_func_call: + return func_call(tree->rnode, tree->lnode); + + /* unary operations */ + case Node_NR: + case Node_FNR: + case Node_NF: + case Node_FIELDWIDTHS: + case Node_FS: + case Node_RS: + case Node_field_spec: + case Node_subscript: + case Node_IGNORECASE: + case Node_OFS: + case Node_ORS: + case Node_OFMT: + case Node_CONVFMT: + lhs = get_lhs(tree, (Func_ptr *)0); + return *lhs; + + case Node_var_array: + fatal("attempt to use an array in a scalar context"); + + case Node_unary_minus: + t1 = tree_eval(tree->subnode); + x = -force_number(t1); + free_temp(t1); + return tmp_number(x); + + case Node_cond_exp: + if (eval_condition(tree->lnode)) + return tree_eval(tree->rnode->lnode); + return tree_eval(tree->rnode->rnode); + + case Node_match: + case Node_nomatch: + case Node_regex: + return match_op(tree); + + case Node_func: + fatal("function `%s' called with space between name and (,\n%s", + tree->lnode->param, + "or used in other expression context"); + + /* assignments */ + case Node_assign: + { + Func_ptr after_assign = NULL; + + r = tree_eval(tree->rnode); + lhs = get_lhs(tree->lnode, &after_assign); + if (r != *lhs) { + NODE *save; + + save = *lhs; + *lhs = dupnode(r); + unref(save); + } + free_temp(r); + if (after_assign) + (*after_assign)(); + return *lhs; + } + + case Node_concat: + { +#define STACKSIZE 10 + NODE *stack[STACKSIZE]; + register NODE **sp; + register int len; + char *str; + register char *dest; + + sp = stack; + len = 0; + 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 */ + break; + } + *sp = force_string(tree_eval(tree)); + len += (*sp)->stlen; + *++sp = NULL; + emalloc(str, char *, len+2, "tree_eval"); + dest = str; + sp = stack; + while (*sp) { + memcpy(dest, (*sp)->stptr, (*sp)->stlen); + dest += (*sp)->stlen; + free_temp(*sp); + sp++; + } + r = make_str_node(str, len, ALREADY_MALLOCED); + r->flags |= TEMP; + } + return r; + + /* other assignment types are easier because they are numeric */ + case Node_preincrement: + case Node_predecrement: + case Node_postincrement: + case Node_postdecrement: + case Node_assign_exp: + case Node_assign_times: + case Node_assign_quotient: + case Node_assign_mod: + case Node_assign_plus: + case Node_assign_minus: + return op_assign(tree); + default: + break; /* handled below */ + } + + /* evaluate subtrees in order to do binary operation, then keep going */ + t1 = tree_eval(tree->lnode); + t2 = tree_eval(tree->rnode); + + switch (tree->type) { + case Node_geq: + case Node_leq: + case Node_greater: + case Node_less: + case Node_notequal: + case Node_equal: + di = cmp_nodes(t1, t2); + free_temp(t1); + free_temp(t2); + switch (tree->type) { + case Node_equal: + return tmp_number((AWKNUM) (di == 0)); + case Node_notequal: + return tmp_number((AWKNUM) (di != 0)); + case Node_less: + return tmp_number((AWKNUM) (di < 0)); + case Node_greater: + return tmp_number((AWKNUM) (di > 0)); + case Node_leq: + return tmp_number((AWKNUM) (di <= 0)); + case Node_geq: + return tmp_number((AWKNUM) (di >= 0)); + default: + cant_happen(); + } + break; + default: + break; /* handled below */ + } + + x1 = force_number(t1); + free_temp(t1); + x2 = force_number(t2); + free_temp(t2); + switch (tree->type) { + case Node_exp: + if ((lx = x2) == x2 && lx >= 0) { /* integer exponent */ + if (lx == 0) + x = 1; + else if (lx == 1) + x = x1; + else { + /* doing it this way should be more precise */ + for (x = x1; --lx; ) + x *= x1; + } + } else + x = pow((double) x1, (double) x2); + return tmp_number(x); + + case Node_times: + return tmp_number(x1 * x2); + + case Node_quotient: + if (x2 == 0) + fatal("division by zero attempted"); +#ifdef _CRAY + /* + * special case for integer division, put in for Cray + */ + lx2 = x2; + if (lx2 == 0) + return tmp_number(x1 / x2); + lx = (long) x1 / lx2; + if (lx * x2 == x1) + return tmp_number((AWKNUM) lx); + else +#endif + return tmp_number(x1 / x2); + + case Node_mod: + if (x2 == 0) + fatal("division by zero attempted in mod"); +#ifndef FMOD_MISSING + return tmp_number(fmod (x1, x2)); +#else + (void) modf(x1 / x2, &x); + return tmp_number(x1 - x * x2); +#endif + + case Node_plus: + return tmp_number(x1 + x2); + + case Node_minus: + return tmp_number(x1 - x2); + + case Node_var_array: + fatal("attempt to use an array in a scalar context"); + + default: + fatal("illegal type (%d) in tree_eval", tree->type); + } + return 0; +} + +/* Is TREE true or false? Returns 0==false, non-zero==true */ +static int +eval_condition(tree) +register NODE *tree; +{ + register NODE *t1; + register int ret; + + if (tree == NULL) /* Null trees are the easiest kinds */ + return 1; + if (tree->type == Node_line_range) { + /* + * Node_line_range is kind of like Node_match, EXCEPT: the + * lnode field (more properly, the condpair field) is a node + * of a Node_cond_pair; whether we evaluate the lnode of that + * node or the rnode depends on the triggered word. More + * precisely: if we are not yet triggered, we tree_eval the + * lnode; if that returns true, we set the triggered word. + * If we are triggered (not ELSE IF, note), we tree_eval the + * rnode, clear triggered if it succeeds, and perform our + * action (regardless of success or failure). We want to be + * able to begin and end on a single input record, so this + * isn't an ELSE IF, as noted above. + */ + if (!tree->triggered) + if (!eval_condition(tree->condpair->lnode)) + return 0; + else + tree->triggered = 1; + /* Else we are triggered */ + if (eval_condition(tree->condpair->rnode)) + tree->triggered = 0; + return 1; + } + + /* + * Could just be J.random expression. in which case, null and 0 are + * false, anything else is true + */ + + t1 = tree_eval(tree); + if (t1->flags & MAYBE_NUM) + (void) force_number(t1); + if (t1->flags & NUMBER) + ret = t1->numbr != 0.0; + else + ret = t1->stlen != 0; + free_temp(t1); + return ret; +} + +/* + * compare two nodes, returning negative, 0, positive + */ +int +cmp_nodes(t1, t2) +register NODE *t1, *t2; +{ + register int ret; + register int len1, len2; + + if (t1 == t2) + return 0; + if (t1->flags & MAYBE_NUM) + (void) force_number(t1); + if (t2->flags & MAYBE_NUM) + (void) force_number(t2); + if ((t1->flags & NUMBER) && (t2->flags & NUMBER)) { + if (t1->numbr == t2->numbr) return 0; + else if (t1->numbr - t2->numbr < 0) return -1; + else return 1; + } + (void) force_string(t1); + (void) force_string(t2); + len1 = t1->stlen; + len2 = t2->stlen; + if (len1 == 0 || len2 == 0) + return len1 - len2; + ret = memcmp(t1->stptr, t2->stptr, len1 <= len2 ? len1 : len2); + return ret == 0 ? len1-len2 : ret; +} + +static NODE * +op_assign(tree) +register NODE *tree; +{ + AWKNUM rval, lval; + NODE **lhs; + AWKNUM t1, t2; + long ltemp; + NODE *tmp; + Func_ptr after_assign = NULL; + + lhs = get_lhs(tree->lnode, &after_assign); + lval = force_number(*lhs); + + /* + * Can't unref *lhs until we know the type; doing so + * too early breaks x += x sorts of things. + */ + switch(tree->type) { + case Node_preincrement: + case Node_predecrement: + unref(*lhs); + *lhs = make_number(lval + + (tree->type == Node_preincrement ? 1.0 : -1.0)); + if (after_assign) + (*after_assign)(); + return *lhs; + + case Node_postincrement: + case Node_postdecrement: + unref(*lhs); + *lhs = make_number(lval + + (tree->type == Node_postincrement ? 1.0 : -1.0)); + if (after_assign) + (*after_assign)(); + return tmp_number(lval); + default: + break; /* handled below */ + } + + tmp = tree_eval(tree->rnode); + rval = force_number(tmp); + free_temp(tmp); + unref(*lhs); + switch(tree->type) { + case Node_assign_exp: + if ((ltemp = rval) == rval) { /* integer exponent */ + if (ltemp == 0) + *lhs = make_number((AWKNUM) 1); + else if (ltemp == 1) + *lhs = make_number(lval); + else { + /* doing it this way should be more precise */ + for (t1 = t2 = lval; --ltemp; ) + t1 *= t2; + *lhs = make_number(t1); + } + } else + *lhs = make_number((AWKNUM) pow((double) lval, (double) rval)); + break; + + case Node_assign_times: + *lhs = make_number(lval * rval); + break; + + case Node_assign_quotient: + if (rval == (AWKNUM) 0) + fatal("division by zero attempted in /="); +#ifdef _CRAY + /* + * special case for integer division, put in for Cray + */ + ltemp = rval; + if (ltemp == 0) { + *lhs = make_number(lval / rval); + break; + } + ltemp = (long) lval / ltemp; + if (ltemp * lval == rval) + *lhs = make_number((AWKNUM) ltemp); + else +#endif + *lhs = make_number(lval / rval); + break; + + case Node_assign_mod: + if (rval == (AWKNUM) 0) + fatal("division by zero attempted in %="); +#ifndef FMOD_MISSING + *lhs = make_number(fmod(lval, rval)); +#else + (void) modf(lval / rval, &t1); + t2 = lval - rval * t1; + *lhs = make_number(t2); +#endif + break; + + case Node_assign_plus: + *lhs = make_number(lval + rval); + break; + + case Node_assign_minus: + *lhs = make_number(lval - rval); + break; + default: + cant_happen(); + } + if (after_assign) + (*after_assign)(); + return *lhs; +} + +NODE **stack_ptr; + +static NODE * +func_call(name, arg_list) +NODE *name; /* name is a Node_val giving function name */ +NODE *arg_list; /* Node_expression_list of calling args. */ +{ + register NODE *arg, *argp, *r; + NODE *n, *f; + jmp_buf volatile func_tag_stack; + jmp_buf volatile loop_tag_stack; + int volatile save_loop_tag_valid = 0; + NODE **volatile save_stack, *save_ret_node; + NODE **volatile local_stack = NULL, **sp; + int count; + extern NODE *ret_node; + + /* + * retrieve function definition node + */ + f = lookup(name->stptr); + if (!f || f->type != Node_func) + fatal("function `%s' not defined", name->stptr); +#ifdef FUNC_TRACE + fprintf(stderr, "function %s called\n", name->stptr); +#endif + count = f->lnode->param_cnt; + if (count) + emalloc(local_stack, NODE **, count*sizeof(NODE *), "func_call"); + sp = local_stack; + + /* + * for each calling arg. add NODE * on stack + */ + for (argp = arg_list; count && argp != NULL; argp = argp->rnode) { + arg = argp->lnode; + getnode(r); + r->type = Node_var; + /* + * call by reference for arrays; see below also + */ + if (arg->type == Node_param_list) + arg = stack_ptr[arg->param_cnt]; + if (arg->type == Node_var_array) + *r = *arg; + else { + n = tree_eval(arg); + r->lnode = dupnode(n); + r->rnode = (NODE *) NULL; + free_temp(n); + } + *sp++ = r; + count--; + } + if (argp != NULL) /* left over calling args. */ + warning( + "function `%s' called with more arguments than declared", + name->stptr); + /* + * add remaining params. on stack with null value + */ + while (count-- > 0) { + getnode(r); + r->type = Node_var; + r->lnode = Nnull_string; + r->rnode = (NODE *) NULL; + *sp++ = r; + } + + /* + * Execute function body, saving context, as a return statement + * will longjmp back here. + * + * Have to save and restore the loop_tag stuff so that a return + * inside a loop in a function body doesn't scrog any loops going + * on in the main program. We save the necessary info in variables + * local to this function so that function nesting works OK. + * We also only bother to save the loop stuff if we're in a loop + * when the function is called. + */ + if (loop_tag_valid) { + int junk = 0; + + save_loop_tag_valid = (volatile int) loop_tag_valid; + PUSH_BINDING(loop_tag_stack, loop_tag, junk); + loop_tag_valid = 0; + } + save_stack = stack_ptr; + stack_ptr = local_stack; + PUSH_BINDING(func_tag_stack, func_tag, func_tag_valid); + save_ret_node = ret_node; + ret_node = Nnull_string; /* default return value */ + if (setjmp(func_tag) == 0) + (void) interpret(f->rnode); + + r = ret_node; + ret_node = (NODE *) save_ret_node; + RESTORE_BINDING(func_tag_stack, func_tag, func_tag_valid); + stack_ptr = (NODE **) save_stack; + + /* + * here, we pop each parameter and check whether + * it was an array. If so, and if the arg. passed in was + * a simple variable, then the value should be copied back. + * This achieves "call-by-reference" for arrays. + */ + sp = local_stack; + count = f->lnode->param_cnt; + for (argp = arg_list; count > 0 && argp != NULL; argp = argp->rnode) { + arg = argp->lnode; + if (arg->type == Node_param_list) + arg = stack_ptr[arg->param_cnt]; + n = *sp++; + if (arg->type == Node_var && n->type == Node_var_array) { + /* should we free arg->var_value ? */ + arg->var_array = n->var_array; + arg->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) { + assoc_clear(n); + free(n->var_array); + } + unref(n->lnode); + freenode(n); + } + if (local_stack) + free((char *) local_stack); + + /* Restore the loop_tag stuff if necessary. */ + if (save_loop_tag_valid) { + int junk = 0; + + loop_tag_valid = (int) save_loop_tag_valid; + RESTORE_BINDING(loop_tag_stack, loop_tag, junk); + } + + if (!(r->flags & PERM)) + r->flags |= TEMP; + return r; +} + +/* + * This returns a POINTER to a node pointer. get_lhs(ptr) is the current + * value of the var, or where to store the var's new value + */ + +NODE ** +get_lhs(ptr, assign) +register NODE *ptr; +Func_ptr *assign; +{ + register NODE **aptr = NULL; + register NODE *n; + + switch (ptr->type) { + case Node_var_array: + fatal("attempt to use an array in a scalar context"); + case Node_var: + aptr = &(ptr->var_value); +#ifdef DEBUG + if (ptr->var_value->stref <= 0) + cant_happen(); +#endif + break; + + case Node_FIELDWIDTHS: + aptr = &(FIELDWIDTHS_node->var_value); + if (assign) + *assign = set_FIELDWIDTHS; + break; + + case Node_RS: + aptr = &(RS_node->var_value); + if (assign) + *assign = set_RS; + break; + + case Node_FS: + aptr = &(FS_node->var_value); + if (assign) + *assign = set_FS; + break; + + case Node_FNR: + unref(FNR_node->var_value); + FNR_node->var_value = make_number((AWKNUM) FNR); + aptr = &(FNR_node->var_value); + if (assign) + *assign = set_FNR; + break; + + case Node_NR: + unref(NR_node->var_value); + NR_node->var_value = make_number((AWKNUM) NR); + aptr = &(NR_node->var_value); + if (assign) + *assign = set_NR; + break; + + case Node_NF: + if (NF == -1) + (void) get_field(HUGE-1, assign); /* parse record */ + unref(NF_node->var_value); + NF_node->var_value = make_number((AWKNUM) NF); + aptr = &(NF_node->var_value); + if (assign) + *assign = set_NF; + break; + + case Node_IGNORECASE: + unref(IGNORECASE_node->var_value); + IGNORECASE_node->var_value = make_number((AWKNUM) IGNORECASE); + aptr = &(IGNORECASE_node->var_value); + if (assign) + *assign = set_IGNORECASE; + break; + + case Node_OFMT: + aptr = &(OFMT_node->var_value); + if (assign) + *assign = set_OFMT; + break; + + case Node_CONVFMT: + aptr = &(CONVFMT_node->var_value); + if (assign) + *assign = set_CONVFMT; + break; + + case Node_ORS: + aptr = &(ORS_node->var_value); + if (assign) + *assign = set_ORS; + break; + + case Node_OFS: + aptr = &(OFS_node->var_value); + if (assign) + *assign = set_OFS; + break; + + case Node_param_list: + aptr = &(stack_ptr[ptr->param_cnt]->var_value); + break; + + case Node_field_spec: + { + int field_num; + + n = tree_eval(ptr->lnode); + field_num = (int) force_number(n); + free_temp(n); + if (field_num < 0) + fatal("attempt to access field %d", field_num); + if (field_num == 0 && field0_valid) { /* short circuit */ + aptr = &fields_arr[0]; + if (assign) + *assign = reset_record; + break; + } + aptr = get_field(field_num, assign); + break; + } + case Node_subscript: + n = ptr->lnode; + if (n->type == Node_param_list) + n = stack_ptr[n->param_cnt]; + aptr = assoc_lookup(n, concat_exp(ptr->rnode)); + break; + + case Node_func: + fatal ("`%s' is a function, assignment is not allowed", + ptr->lnode->param); + default: + cant_happen(); + } + return aptr; +} + +static NODE * +match_op(tree) +register NODE *tree; +{ + register NODE *t1; + register Regexp *rp; + int i; + int match = 1; + + if (tree->type == Node_nomatch) + match = 0; + if (tree->type == Node_regex) + t1 = *get_field(0, (Func_ptr *) 0); + else { + t1 = force_string(tree_eval(tree->lnode)); + tree = tree->rnode; + } + rp = re_update(tree); + i = research(rp, t1->stptr, 0, t1->stlen, 0); + i = (i == -1) ^ (match == 1); + free_temp(t1); + return tmp_number((AWKNUM) i); +} + +void +set_IGNORECASE() +{ + static int warned = 0; + + if ((do_lint || do_unix) && ! warned) { + warned = 1; + warning("IGNORECASE not supported in compatibility mode"); + } + IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0); + set_FS(); +} + +void +set_OFS() +{ + OFS = force_string(OFS_node->var_value)->stptr; + OFSlen = OFS_node->var_value->stlen; + OFS[OFSlen] = '\0'; +} + +void +set_ORS() +{ + ORS = force_string(ORS_node->var_value)->stptr; + ORSlen = ORS_node->var_value->stlen; + ORS[ORSlen] = '\0'; +} + +static NODE **fmt_list = NULL; +static int fmt_ok P((NODE *n)); +static int fmt_index P((NODE *n)); + +static int +fmt_ok(n) +NODE *n; +{ + /* to be done later */ + return 1; +} + +static int +fmt_index(n) +NODE *n; +{ + register int ix = 0; + static int fmt_num = 4; + static int fmt_hiwater = 0; + + if (fmt_list == NULL) + emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), "fmt_index"); + (void) force_string(n); + while (ix < fmt_hiwater) { + if (cmp_nodes(fmt_list[ix], n) == 0) + return ix; + ix++; + } + /* not found */ + n->stptr[n->stlen] = '\0'; + if (!fmt_ok(n)) + warning("bad FMT specification"); + if (fmt_hiwater >= fmt_num) { + fmt_num *= 2; + emalloc(fmt_list, NODE **, fmt_num, "fmt_index"); + } + fmt_list[fmt_hiwater] = dupnode(n); + return fmt_hiwater++; +} + +void +set_OFMT() +{ + OFMTidx = fmt_index(OFMT_node->var_value); + OFMT = fmt_list[OFMTidx]->stptr; +} + +void +set_CONVFMT() +{ + CONVFMTidx = fmt_index(CONVFMT_node->var_value); + CONVFMT = fmt_list[CONVFMTidx]->stptr; +} diff --git a/gnu/usr.bin/awk/field.c b/gnu/usr.bin/awk/field.c new file mode 100644 index 0000000000..d8f9a54556 --- /dev/null +++ b/gnu/usr.bin/awk/field.c @@ -0,0 +1,645 @@ +/* + * field.c - routines for dealing with fields and record parsing + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +static int (*parse_field) P((int, char **, int, NODE *, + Regexp *, void (*)(), 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 void set_element P((int, char *, int, NODE *)); +static void grow_fields_arr P((int 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 int resave_fs; +static NODE *save_FS; /* save current value of FS when line is read, + * to be used in deferred parsing + */ + +NODE **fields_arr; /* array of pointers to the field nodes */ +int field0_valid; /* $(>0) has not been changed yet */ +int default_FS; +static NODE **nodes; /* permanent repository of field nodes */ +static int *FIELDWIDTHS = NULL; + +void +init_fields() +{ + NODE *n; + + emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields"); + emalloc(nodes, NODE **, sizeof(NODE *), "init_fields"); + getnode(n); + *n = *Nnull_string; + fields_arr[0] = nodes[0] = n; + parse_extent = fields_arr[0]->stptr; + save_FS = dupnode(FS_node->var_value); + field0_valid = 1; +} + + +static void +grow_fields_arr(num) +int num; +{ + register int t; + register NODE *n; + + erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field"); + erealloc(nodes, NODE **, (num+1) * sizeof(NODE *), "set_field"); + for (t = nf_high_water+1; t <= num; t++) { + getnode(n); + *n = *Nnull_string; + fields_arr[t] = nodes[t] = n; + } + nf_high_water = num; +} + +/*ARGSUSED*/ +static void +set_field(num, str, len, dummy) +int num; +char *str; +int len; +NODE *dummy; /* not used -- just to make interface same as set_element */ +{ + register NODE *n; + + if (num > nf_high_water) + grow_fields_arr(num); + n = nodes[num]; + n->stptr = str; + n->stlen = len; + n->flags = (PERM|STR|STRING|MAYBE_NUM); + fields_arr[num] = n; +} + +/* Someone assigned a value to $(something). Fix up $0 to be right */ +static void +rebuild_record() +{ + register int tlen; + register NODE *tmp; + NODE *ofs; + char *ops; + register char *cops; + register NODE **ptr; + register int ofslen; + + tlen = 0; + ofs = force_string(OFS_node->var_value); + ofslen = ofs->stlen; + ptr = &fields_arr[NF]; + while (ptr > &fields_arr[0]) { + tmp = force_string(*ptr); + tlen += tmp->stlen; + ptr--; + } + tlen += (NF - 1) * ofslen; + if (tlen < 0) + tlen = 0; + emalloc(ops, char *, tlen + 2, "fix_fields"); + cops = ops; + ops[0] = '\0'; + for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) { + tmp = *ptr; + if (tmp->stlen == 1) + *cops++ = tmp->stptr[0]; + else if (tmp->stlen != 0) { + memcpy(cops, tmp->stptr, tmp->stlen); + cops += tmp->stlen; + } + if (ptr != &fields_arr[NF]) { + if (ofslen == 1) + *cops++ = ofs->stptr[0]; + else if (ofslen != 0) { + memcpy(cops, ofs->stptr, ofslen); + cops += ofslen; + } + } + } + tmp = make_str_node(ops, tlen, ALREADY_MALLOCED); + unref(fields_arr[0]); + fields_arr[0] = tmp; + field0_valid = 1; +} + +/* + * setup $0, but defer parsing rest of line until reference is made to $(>0) + * or to NF. At that point, parse only as much as necessary. + */ +void +set_record(buf, cnt, freeold) +char *buf; +int cnt; +int freeold; +{ + register int i; + + NF = -1; + for (i = 1; i <= parse_high_water; i++) { + unref(fields_arr[i]); + } + parse_high_water = 0; + if (freeold) { + unref(fields_arr[0]); + if (resave_fs) { + resave_fs = 0; + unref(save_FS); + save_FS = dupnode(FS_node->var_value); + } + nodes[0]->stptr = buf; + nodes[0]->stlen = cnt; + nodes[0]->stref = 1; + nodes[0]->flags = (STRING|STR|PERM|MAYBE_NUM); + fields_arr[0] = nodes[0]; + } + fields_arr[0]->flags |= MAYBE_NUM; + field0_valid = 1; +} + +void +reset_record() +{ + (void) force_string(fields_arr[0]); + set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, 0); +} + +void +set_NF() +{ + register int i; + + NF = (int) force_number(NF_node->var_value); + if (NF > nf_high_water) + grow_fields_arr(NF); + for (i = parse_high_water + 1; i <= NF; i++) { + unref(fields_arr[i]); + fields_arr[i] = Nnull_string; + } + field0_valid = 0; +} + +/* + * this is called both from get_field() and from do_split() + * via (*parse_field)(). This variation is for when FS is a regular + * expression -- either user-defined or because RS=="" and FS==" " + */ +static int +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 */ +NODE *n; +{ + register char *scan = *buf; + register int nf = parse_high_water; + register char *field; + register char *end = scan + len; + + if (up_to == HUGE) + nf = 0; + if (len == 0) + return nf; + + if (*RS == 0 && default_FS) + while (scan < end && isspace(*scan)) + scan++; + field = scan; + while (scan < end + && research(rp, scan, 0, (int)(end - scan), 1) != -1 + && nf < up_to) { + if (REEND(rp, scan) == RESTART(rp, scan)) { /* null match */ + scan++; + if (scan == end) { + (*set)(++nf, field, scan - field, n); + up_to = nf; + break; + } + continue; + } + (*set)(++nf, field, scan + RESTART(rp, scan) - field, n); + scan += REEND(rp, scan); + field = scan; + if (scan == end) /* FS at end of record */ + (*set)(++nf, field, 0, n); + } + if (nf != up_to && scan < end) { + (*set)(++nf, scan, (int)(end - scan), n); + scan = end; + } + *buf = scan; + return (nf); +} + +/* + * this is called both from get_field() and from do_split() + * via (*parse_field)(). This variation is for when FS is a single space + * character. + */ +static int +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 */ +NODE *n; +{ + register char *scan = *buf; + register int nf = parse_high_water; + register char *field; + register char *end = scan + len; + char sav; + + if (up_to == HUGE) + nf = 0; + if (len == 0) + return nf; + + /* before doing anything save the char at *end */ + sav = *end; + /* because it will be destroyed now: */ + + *end = ' '; /* sentinel character */ + for (; nf < up_to; scan++) { + /* + * special case: fs is single space, strip leading whitespace + */ + while (scan < end && (*scan == ' ' || *scan == '\t')) + scan++; + if (scan >= end) + break; + field = scan; + while (*scan != ' ' && *scan != '\t') + scan++; + (*set)(++nf, field, (int)(scan - field), n); + if (scan == end) + break; + } + + /* everything done, restore original char at *end */ + *end = sav; + + *buf = scan; + return nf; +} + +/* + * this is called both from get_field() and from do_split() + * via (*parse_field)(). This variation is for when FS is a single character + * other than space. + */ +static int +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 */ +NODE *n; +{ + register char *scan = *buf; + register char fschar; + register int nf = parse_high_water; + register char *field; + register char *end = scan + len; + char sav; + + if (up_to == HUGE) + nf = 0; + if (len == 0) + return nf; + + if (*RS == 0 && fs->stlen == 0) + fschar = '\n'; + else + fschar = fs->stptr[0]; + + /* before doing anything save the char at *end */ + sav = *end; + /* because it will be destroyed now: */ + *end = fschar; /* sentinel character */ + + for (; nf < up_to; scan++) { + field = scan; + while (*scan++ != fschar) + ; + scan--; + (*set)(++nf, field, (int)(scan - field), n); + if (scan == end) + break; + } + + /* everything done, restore original char at *end */ + *end = sav; + + *buf = scan; + return nf; +} + +/* + * this is called both from get_field() and from do_split() + * via (*parse_field)(). This variation is for fields are fixed widths. + */ +static int +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 */ +NODE *n; +{ + register char *scan = *buf; + register int nf = parse_high_water; + register char *end = scan + len; + + if (up_to == HUGE) + nf = 0; + if (len == 0) + return nf; + for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) { + if (len > end - scan) + len = end - scan; + (*set)(++nf, scan, len, n); + scan += len; + } + if (len == -1) + *buf = end; + else + *buf = scan; + return nf; +} + +NODE ** +get_field(requested, assign) +register int requested; +Func_ptr *assign; /* this field is on the LHS of an assign */ +{ + /* + * if requesting whole line but some other field has been altered, + * then the whole line must be rebuilt + */ + if (requested == 0) { + if (!field0_valid) { + /* first, parse remainder of input record */ + if (NF == -1) { + NF = (*parse_field)(HUGE-1, &parse_extent, + fields_arr[0]->stlen - + (parse_extent - fields_arr[0]->stptr), + save_FS, FS_regexp, set_field, + (NODE *)NULL); + parse_high_water = NF; + } + rebuild_record(); + } + if (assign) + *assign = reset_record; + return &fields_arr[0]; + } + + /* assert(requested > 0); */ + + if (assign) + field0_valid = 0; /* $0 needs reconstruction */ + + if (requested <= parse_high_water) /* already parsed this field */ + return &fields_arr[requested]; + + if (NF == -1) { /* have not yet parsed to end of record */ + /* + * parse up to requested fields, calling set_field() for each, + * saving in parse_extent the point where the parse left off + */ + if (parse_high_water == 0) /* starting at the beginning */ + parse_extent = fields_arr[0]->stptr; + parse_high_water = (*parse_field)(requested, &parse_extent, + fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr), + save_FS, FS_regexp, set_field, (NODE *)NULL); + + /* + * if we reached the end of the record, set NF to the number of + * fields so far. Note that requested might actually refer to + * a field that is beyond the end of the record, but we won't + * set NF to that value at this point, since this is only a + * reference to the field and NF only gets set if the field + * is assigned to -- this case is handled below + */ + if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen) + NF = parse_high_water; + if (requested == HUGE-1) /* HUGE-1 means set NF */ + requested = parse_high_water; + } + if (parse_high_water < requested) { /* requested beyond end of record */ + if (assign) { /* expand record */ + register int i; + + if (requested > nf_high_water) + grow_fields_arr(requested); + + /* fill in fields that don't exist */ + for (i = parse_high_water + 1; i <= requested; i++) + fields_arr[i] = Nnull_string; + + NF = requested; + parse_high_water = requested; + } else + return &Nnull_string; + } + + return &fields_arr[requested]; +} + +static void +set_element(num, s, len, n) +int num; +char *s; +int len; +NODE *n; +{ + register NODE *it; + + it = make_string(s, len); + it->flags |= MAYBE_NUM; + *assoc_lookup(n, tmp_number((AWKNUM) (num))) = it; +} + +NODE * +do_split(tree) +NODE *tree; +{ + NODE *t1, *t2, *t3, *tmp; + NODE *fs; + char *s; + int (*parseit)P((int, char **, int, NODE *, + Regexp *, void (*)(), NODE *)); + Regexp *rp = NULL; + + t1 = tree_eval(tree->lnode); + t2 = tree->rnode->lnode; + t3 = tree->rnode->rnode->lnode; + + (void) force_string(t1); + + if (t2->type == Node_param_list) + t2 = stack_ptr[t2->param_cnt]; + if (t2->type != Node_var && t2->type != Node_var_array) + fatal("second argument of split is not a variable"); + assoc_clear(t2); + + if (t3->re_flags & FS_DFLT) { + parseit = parse_field; + fs = force_string(FS_node->var_value); + rp = FS_regexp; + } else { + tmp = force_string(tree_eval(t3->re_exp)); + if (tmp->stlen == 1) { + if (tmp->stptr[0] == ' ') + parseit = def_parse_field; + else + parseit = sc_parse_field; + } else { + parseit = re_parse_field; + rp = re_update(t3); + } + fs = tmp; + } + + s = t1->stptr; + tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int)t1->stlen, + fs, rp, set_element, t2)); + free_temp(t1); + free_temp(t3); + return tmp; +} + +void +set_FS() +{ + NODE *tmp = NULL; + char buf[10]; + NODE *fs; + + buf[0] = '\0'; + default_FS = 0; + if (FS_regexp) { + refree(FS_regexp); + FS_regexp = NULL; + } + fs = force_string(FS_node->var_value); + if (fs->stlen > 1) + parse_field = re_parse_field; + else if (*RS == 0) { + parse_field = sc_parse_field; + if (fs->stlen == 1) { + if (fs->stptr[0] == ' ') { + default_FS = 1; + strcpy(buf, "[ \t\n]+"); + } else if (fs->stptr[0] != '\n') + sprintf(buf, "[%c\n]", fs->stptr[0]); + } + } else { + parse_field = def_parse_field; + if (fs->stptr[0] == ' ' && fs->stlen == 1) + default_FS = 1; + else if (fs->stptr[0] != ' ' && fs->stlen == 1) { + if (IGNORECASE == 0) + parse_field = sc_parse_field; + else + sprintf(buf, "[%c]", fs->stptr[0]); + } + } + if (buf[0]) { + FS_regexp = make_regexp(buf, strlen(buf), IGNORECASE, 1); + parse_field = re_parse_field; + } else if (parse_field == re_parse_field) { + FS_regexp = make_regexp(fs->stptr, fs->stlen, IGNORECASE, 1); + } else + FS_regexp = NULL; + resave_fs = 1; +} + +void +set_RS() +{ + (void) force_string(RS_node->var_value); + RS = RS_node->var_value->stptr; + set_FS(); +} + +void +set_FIELDWIDTHS() +{ + register char *scan; + char *end; + register int i; + static int fw_alloc = 1; + static int warned = 0; + extern double strtod(); + + if (do_lint && ! warned) { + warned = 1; + warning("use of FIELDWIDTHS is a gawk extension"); + } + if (do_unix) /* quick and dirty, does the trick */ + return; + + parse_field = fw_parse_field; + scan = force_string(FIELDWIDTHS_node->var_value)->stptr; + end = scan + 1; + if (FIELDWIDTHS == NULL) + emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS"); + FIELDWIDTHS[0] = 0; + for (i = 1; ; i++) { + if (i >= fw_alloc) { + fw_alloc *= 2; + erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS"); + } + FIELDWIDTHS[i] = (int) strtod(scan, &end); + if (end == scan) + break; + scan = end; + } + FIELDWIDTHS[i] = -1; +} diff --git a/gnu/usr.bin/awk/gawk.texi b/gnu/usr.bin/awk/gawk.texi new file mode 100644 index 0000000000..b280262313 --- /dev/null +++ b/gnu/usr.bin/awk/gawk.texi @@ -0,0 +1,11270 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header (This is for running Texinfo on a region.) +@setfilename gawk.info +@settitle The GAWK Manual +@c @smallbook +@c %**end of header (This is for running Texinfo on a region.) + +@ifinfo +@synindex fn cp +@synindex vr cp +@end ifinfo +@iftex +@syncodeindex fn cp +@syncodeindex vr cp +@end iftex + +@c If "finalout" is commented out, the printed output will show +@c black boxes that mark lines that are too long. Thus, it is +@c unwise to comment it out when running a master in case there are +@c overfulls which are deemed okay. + +@iftex +@finalout +@end iftex + +@c ===> NOTE! <== +@c Determine the edition number in *four* places by hand: +@c 1. First ifinfo section 2. title page 3. copyright page 4. top node +@c To find the locations, search for !!set + +@ifinfo +This file documents @code{awk}, a program that you can use to select +particular records in a file and perform operations upon them. + +This is Edition 0.15 of @cite{The GAWK Manual}, @* +for the 2.15 version of the GNU implementation @* +of AWK. + +Copyright (C) 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@setchapternewpage odd + +@c !!set edition, date, version +@titlepage +@title The GAWK Manual +@subtitle Edition 0.15 +@subtitle April 1993 +@author Diane Barlow Close +@author Arnold D. Robbins +@author Paul H. Rubin +@author Richard Stallman + +@c Include the Distribution inside the titlepage environment so +@c that headings are turned off. Headings on and off do not work. + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1989, 1991, 1992, 1993 Free Software Foundation, Inc. +@sp 2 + +@c !!set edition, date, version +This is Edition 0.15 of @cite{The GAWK Manual}, @* +for the 2.15 version of the GNU implementation @* +of AWK. + +@sp 2 +Published by the Free Software Foundation @* +675 Massachusetts Avenue @* +Cambridge, MA 02139 USA @* +Printed copies are available for $20 each. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end titlepage + +@ifinfo +@node Top, Preface, (dir), (dir) +@comment node-name, next, previous, up +@top General Introduction +@c Preface or Licensing nodes should come right after the Top +@c node, in `unnumbered' sections, then the chapter, `What is gawk'. + +This file documents @code{awk}, a program that you can use to select +particular records in a file and perform operations upon them. + +@c !!set edition, date, version +This is Edition 0.15 of @cite{The GAWK Manual}, @* +for the 2.15 version of the GNU implementation @* +of AWK. + +@end ifinfo + +@menu +* Preface:: What you can do with @code{awk}; brief history + and acknowledgements. +* Copying:: Your right to copy and distribute @code{gawk}. +* This Manual:: Using this manual. + Includes sample input files that you can use. +* Getting Started:: A basic introduction to using @code{awk}. + How to run an @code{awk} program. + Command line syntax. +* Reading Files:: How to read files and manipulate fields. +* Printing:: How to print using @code{awk}. Describes the + @code{print} and @code{printf} statements. + Also describes redirection of output. +* One-liners:: Short, sample @code{awk} programs. +* Patterns:: The various types of patterns + explained in detail. +* Actions:: The various types of actions are + introduced here. Describes + expressions and the various operators in + detail. Also describes comparison expressions. +* Expressions:: Expressions are the basic building + blocks of statements. +* Statements:: The various control statements are + described in detail. +* Arrays:: The description and use of arrays. + Also includes array-oriented control + statements. +* Built-in:: The built-in functions are summarized here. +* User-defined:: User-defined functions are described in detail. +* Built-in Variables:: Built-in Variables +* Command Line:: How to run @code{gawk}. +* Language History:: The evolution of the @code{awk} language. +* Installation:: Installing @code{gawk} under + various operating systems. +* Gawk Summary:: @code{gawk} Options and Language Summary. +* Sample Program:: A sample @code{awk} program with a + complete explanation. +* Bugs:: Reporting Problems and Bugs. +* Notes:: Something about the + implementation of @code{gawk}. +* Glossary:: An explanation of some unfamiliar terms. +* Index:: +@end menu + +@node Preface, Copying, Top, Top +@comment node-name, next, previous, up +@unnumbered Preface + +@iftex +@cindex what is @code{awk} +@end iftex +If you are like many computer users, you would frequently like to make +changes in various text files wherever certain patterns appear, or +extract data from parts of certain lines while discarding the rest. To +write a program to do this in a language such as C or Pascal is a +time-consuming inconvenience that may take many lines of code. The job +may be easier with @code{awk}. + +The @code{awk} utility interprets a special-purpose programming language +that makes it possible to handle simple data-reformatting jobs easily +with just a few lines of code. + +The GNU implementation of @code{awk} is called @code{gawk}; it is fully +upward compatible with the System V Release 4 version of +@code{awk}. @code{gawk} is also upward compatible with the @sc{posix} +(draft) specification of the @code{awk} language. This means that all +properly written @code{awk} programs should work with @code{gawk}. +Thus, we usually don't distinguish between @code{gawk} and other @code{awk} +implementations in this manual.@refill + +@cindex uses of @code{awk} +This manual teaches you what @code{awk} does and how you can use +@code{awk} effectively. You should already be familiar with basic +system commands such as @code{ls}. Using @code{awk} you can: @refill + +@itemize @bullet +@item +manage small, personal databases + +@item +generate reports + +@item +validate data +@item +produce indexes, and perform other document preparation tasks + +@item +even experiment with algorithms that can be adapted later to other computer +languages +@end itemize + +@iftex +This manual has the difficult task of being both tutorial and reference. +If you are a novice, feel free to skip over details that seem too complex. +You should also ignore the many cross references; they are for the +expert user, and for the on-line Info version of the manual. +@end iftex + +@menu +* History:: The history of @code{gawk} and + @code{awk}. Acknowledgements. +@end menu + +@node History, , Preface, Preface +@comment node-name, next, previous, up +@unnumberedsec History of @code{awk} and @code{gawk} + +@cindex acronym +@cindex history of @code{awk} +The name @code{awk} comes from the initials of its designers: Alfred V. +Aho, Peter J. Weinberger, and Brian W. Kernighan. The original version of +@code{awk} was written in 1977. In 1985 a new version made the programming +language more powerful, introducing user-defined functions, multiple input +streams, and computed regular expressions. +This new version became generally available with System V Release 3.1. +The version in System V Release 4 added some new features and also cleaned +up the behavior in some of the ``dark corners'' of the language. +The specification for @code{awk} in the @sc{posix} Command Language +and Utilities standard further clarified the language based on feedback +from both the @code{gawk} designers, and the original @code{awk} +designers.@refill + +The GNU implementation, @code{gawk}, was written in 1986 by Paul Rubin +and Jay Fenlason, with advice from Richard Stallman. John Woods +contributed parts of the code as well. In 1988 and 1989, David Trueman, with +help from Arnold Robbins, thoroughly reworked @code{gawk} for compatibility +with the newer @code{awk}. Current development (1992) focuses on bug fixes, +performance improvements, and standards compliance. + +We need to thank many people for their assistance in producing this +manual. Jay Fenlason contributed many ideas and sample programs. Richard +Mlynarik and Robert J. Chassell gave helpful comments on early drafts of this +manual. The paper @cite{A Supplemental Document for @code{awk}} by John W. +Pierce of the Chemistry Department at UC San Diego, pinpointed several +issues relevant both to @code{awk} implementation and to this manual, that +would otherwise have escaped us. David Trueman, Pat Rankin, and Michal +Jaegermann also contributed sections of the manual.@refill + +The following people provided many helpful comments on this edition of +the manual: Rick Adams, Michael Brennan, Rich Burridge, Diane Close, +Christopher (``Topher'') Eliot, Michael Lijewski, Pat Rankin, Miriam Robbins, +and Michal Jaegermann. Robert J. Chassell provided much valuable advice on +the use of Texinfo. + +Finally, we would like to thank Brian Kernighan of Bell Labs for invaluable +assistance during the testing and debugging of @code{gawk}, and for +help in clarifying numerous points about the language.@refill + +@node Copying, This Manual, Preface, Top +@unnumbered GNU GENERAL PUBLIC LICENSE +@center Version 2, June 1991 + +@display +Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. +675 Mass Ave, Cambridge, MA 02139, USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +@end display + +@c fakenode --- for prepinfo +@unnumberedsec Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software---to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + +@iftex +@c fakenode --- for prepinfo +@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +@end iftex +@ifinfo +@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +@end ifinfo + +@enumerate +@item +This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The ``Program'', below, +refers to any such program or work, and a ``work based on the Program'' +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term ``modification''.) Each licensee is addressed as ``you''. + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +@item +You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +@item +You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +@enumerate a +@item +You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + +@item +You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any +part thereof, to be licensed as a whole at no charge to all third +parties under the terms of this License. + +@item +If the modified program normally reads commands interactively +when run, you must cause it, when started running for such +interactive use in the most ordinary way, to print or display an +announcement including an appropriate copyright notice and a +notice that there is no warranty (or else, saying that you provide +a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this +License. (Exception: if the Program itself is interactive but +does not normally print such an announcement, your work based on +the Program is not required to print an announcement.) +@end enumerate + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +@item +You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +@enumerate a +@item +Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections +1 and 2 above on a medium customarily used for software interchange; or, + +@item +Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your +cost of physically performing source distribution, a complete +machine-readable copy of the corresponding source code, to be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +@item +Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is +allowed only for noncommercial distribution and only if you +received the program in object code or executable form with such +an offer, in accord with Subsection b above.) +@end enumerate + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +@item +You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +@item +You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +@item +Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +@item +If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +@item +If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +@item +The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and ``any +later version'', you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +@item +If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + +@iftex +@c fakenode --- for prepinfo +@heading NO WARRANTY +@end iftex +@ifinfo +@center NO WARRANTY +@end ifinfo + +@item +BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +@item +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. +@end enumerate + +@iftex +@c fakenode --- for prepinfo +@heading END OF TERMS AND CONDITIONS +@end iftex +@ifinfo +@center END OF TERMS AND CONDITIONS +@end ifinfo + +@page +@c fakenode --- for prepinfo +@unnumberedsec How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the ``copyright'' line and a pointer to where the full notice is found. + +@smallexample +@var{one line to give the program's name and a brief idea of what it does.} +Copyright (C) 19@var{yy} @var{name of author} + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +@end smallexample + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + +@smallexample +Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author} +Gnomovision comes with ABSOLUTELY NO WARRANTY; for details +type `show w'. +This is free software, and you are welcome to redistribute it +under certain conditions; type `show c' for details. +@end smallexample + +The hypothetical commands @samp{show w} and @samp{show c} should show +the appropriate parts of the General Public License. Of course, the +commands you use may be called something other than @samp{show w} and +@samp{show c}; they could even be mouse-clicks or menu items---whatever +suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a ``copyright disclaimer'' for the program, if +necessary. Here is a sample; alter the names: + +@smallexample +Yoyodyne, Inc., hereby disclaims all copyright interest in the program +`Gnomovision' (which makes passes at compilers) written by James Hacker. + +@var{signature of Ty Coon}, 1 April 1989 +Ty Coon, President of Vice +@end smallexample + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +@node This Manual, Getting Started, Copying, Top +@chapter Using this Manual +@cindex manual, using this +@cindex using this manual +@cindex language, @code{awk} +@cindex program, @code{awk} +@cindex @code{awk} language +@cindex @code{awk} program + +The term @code{awk} refers to a particular program, and to the language you +use to tell this program what to do. When we need to be careful, we call +the program ``the @code{awk} utility'' and the language ``the @code{awk} +language.'' The term @code{gawk} refers to a version of @code{awk} developed +as part the GNU project. The purpose of this manual is to explain +both the +@code{awk} language and how to run the @code{awk} utility.@refill + +While concentrating on the features of @code{gawk}, the manual will also +attempt to describe important differences between @code{gawk} and other +@code{awk} implementations. In particular, any features that are not +in the @sc{posix} standard for @code{awk} will be noted. @refill + +The term @dfn{@code{awk} program} refers to a program written by you in +the @code{awk} programming language.@refill + +@xref{Getting Started, ,Getting Started with @code{awk}}, for the bare +essentials you need to know to start using @code{awk}. + +Some useful ``one-liners'' are included to give you a feel for the +@code{awk} language (@pxref{One-liners, ,Useful ``One-liners''}). + +@ignore +@strong{I deleted four paragraphs here because they would confuse the +beginner more than help him. They mention terms such as ``field,'' +``pattern,'' ``action,'' ``built-in function'' which the beginner +doesn't know.} + +@strong{If you can find a way to introduce several of these concepts here, +enough to give the reader a map of what is to follow, that might +be useful. I'm not sure that can be done without taking up more +space than ought to be used here. There may be no way to win.} + +@strong{ADR: I'd like to tackle this in phase 2 of my editing.} +@end ignore + +A sample @code{awk} program has been provided for you +(@pxref{Sample Program}).@refill + +If you find terms that you aren't familiar with, try looking them +up in the glossary (@pxref{Glossary}).@refill + +The entire @code{awk} language is summarized for quick reference in +@ref{Gawk Summary, ,@code{gawk} Summary}. Look there if you just need +to refresh your memory about a particular feature.@refill + +Most of the time complete @code{awk} programs are used as examples, but in +some of the more advanced sections, only the part of the @code{awk} program +that illustrates the concept being described is shown.@refill + +@menu +* Sample Data Files:: Sample data files for use in the @code{awk} + programs illustrated in this manual. +@end menu + +@node Sample Data Files, , This Manual, This Manual +@section Data Files for the Examples + +@cindex input file, sample +@cindex sample input file +@cindex @file{BBS-list} file +Many of the examples in this manual take their input from two sample +data files. The first, called @file{BBS-list}, represents a list of +computer bulletin board systems together with information about those systems. +The second data file, called @file{inventory-shipped}, contains +information about shipments on a monthly basis. Each line of these +files is one @dfn{record}. + +In the file @file{BBS-list}, each record contains the name of a computer +bulletin board, its phone number, the board's baud rate, and a code for +the number of hours it is operational. An @samp{A} in the last column +means the board operates 24 hours a day. A @samp{B} in the last +column means the board operates evening and weekend hours, only. A +@samp{C} means the board operates only on weekends. + +@example +aardvark 555-5553 1200/300 B +alpo-net 555-3412 2400/1200/300 A +barfly 555-7685 1200/300 A +bites 555-1675 2400/1200/300 A +camelot 555-0542 300 C +core 555-2912 1200/300 C +fooey 555-1234 2400/1200/300 B +foot 555-6699 1200/300 B +macfoo 555-6480 1200/300 A +sdace 555-3430 2400/1200/300 A +sabafoo 555-2127 1200/300 C +@end example + +@cindex @file{inventory-shipped} file +The second data file, called @file{inventory-shipped}, represents +information about shipments during the year. +Each record contains the month of the year, the number +of green crates shipped, the number of red boxes shipped, the number of +orange bags shipped, and the number of blue packages shipped, +respectively. There are 16 entries, covering the 12 months of one year +and 4 months of the next year.@refill + +@example +Jan 13 25 15 115 +Feb 15 32 24 226 +Mar 15 24 34 228 +Apr 31 52 63 420 +May 16 34 29 208 +Jun 31 42 75 492 +Jul 24 34 67 436 +Aug 15 34 47 316 +Sep 13 55 37 277 +Oct 29 54 68 525 +Nov 20 87 82 577 +Dec 17 35 61 401 + +Jan 21 36 64 620 +Feb 26 58 80 652 +Mar 24 75 70 495 +Apr 21 70 74 514 +@end example + +@ifinfo +If you are reading this in GNU Emacs using Info, you can copy the regions +of text showing these sample files into your own test files. This way you +can try out the examples shown in the remainder of this document. You do +this by using the command @kbd{M-x write-region} to copy text from the Info +file into a file for use with @code{awk} +(@xref{Misc File Ops, , , emacs, GNU Emacs Manual}, +for more information). Using this information, create your own +@file{BBS-list} and @file{inventory-shipped} files, and practice what you +learn in this manual. +@end ifinfo + +@node Getting Started, Reading Files, This Manual, Top +@chapter Getting Started with @code{awk} +@cindex script, definition of +@cindex rule, definition of +@cindex program, definition of +@cindex basic function of @code{gawk} + +The basic function of @code{awk} is to search files for lines (or other +units of text) that contain certain patterns. When a line matches one +of the patterns, @code{awk} performs specified actions on that line. +@code{awk} keeps processing input lines in this way until the end of the +input file is reached.@refill + +When you run @code{awk}, you specify an @code{awk} @dfn{program} which +tells @code{awk} what to do. The program consists of a series of +@dfn{rules}. (It may also contain @dfn{function definitions}, but that +is an advanced feature, so we will ignore it for now. +@xref{User-defined, ,User-defined Functions}.) Each rule specifies one +pattern to search for, and one action to perform when that pattern is found. + +Syntactically, a rule consists of a pattern followed by an action. The +action is enclosed in curly braces to separate it from the pattern. +Rules are usually separated by newlines. Therefore, an @code{awk} +program looks like this: + +@example +@var{pattern} @{ @var{action} @} +@var{pattern} @{ @var{action} @} +@dots{} +@end example + +@menu +* Very Simple:: A very simple example. +* Two Rules:: A less simple one-line example with two rules. +* More Complex:: A more complex example. +* Running gawk:: How to run @code{gawk} programs; + includes command line syntax. +* Comments:: Adding documentation to @code{gawk} programs. +* Statements/Lines:: Subdividing or combining statements into lines. +* When:: When to use @code{gawk} and + when to use other things. +@end menu + +@node Very Simple, Two Rules, Getting Started, Getting Started +@section A Very Simple Example + +@cindex @samp{print $0} +The following command runs a simple @code{awk} program that searches the +input file @file{BBS-list} for the string of characters: @samp{foo}. (A +string of characters is usually called, a @dfn{string}. +The term @dfn{string} is perhaps based on similar usage in English, such +as ``a string of pearls,'' or, ``a string of cars in a train.'') + +@example +awk '/foo/ @{ print $0 @}' BBS-list +@end example + +@noindent +When lines containing @samp{foo} are found, they are printed, because +@w{@samp{print $0}} means print the current line. (Just @samp{print} by +itself means the same thing, so we could have written that +instead.) + +You will notice that slashes, @samp{/}, surround the string @samp{foo} +in the actual @code{awk} program. The slashes indicate that @samp{foo} +is a pattern to search for. This type of pattern is called a +@dfn{regular expression}, and is covered in more detail later +(@pxref{Regexp, ,Regular Expressions as Patterns}). There are +single-quotes around the @code{awk} program so that the shell won't +interpret any of it as special shell characters.@refill + +Here is what this program prints: + +@example +@group +fooey 555-1234 2400/1200/300 B +foot 555-6699 1200/300 B +macfoo 555-6480 1200/300 A +sabafoo 555-2127 1200/300 C +@end group +@end example + +@cindex action, default +@cindex pattern, default +@cindex default action +@cindex default pattern +In an @code{awk} rule, either the pattern or the action can be omitted, +but not both. If the pattern is omitted, then the action is performed +for @emph{every} input line. If the action is omitted, the default +action is to print all lines that match the pattern. + +Thus, we could leave out the action (the @code{print} statement and the curly +braces) in the above example, and the result would be the same: all +lines matching the pattern @samp{foo} would be printed. By comparison, +omitting the @code{print} statement but retaining the curly braces makes an +empty action that does nothing; then no lines would be printed. + +@node Two Rules, More Complex, Very Simple, Getting Started +@section An Example with Two Rules +@cindex how @code{awk} works + +The @code{awk} utility reads the input files one line at a +time. For each line, @code{awk} tries the patterns of each of the rules. +If several patterns match then several actions are run, in the order in +which they appear in the @code{awk} program. If no patterns match, then +no actions are run. + +After processing all the rules (perhaps none) that match the line, +@code{awk} reads the next line (however, +@pxref{Next Statement, ,The @code{next} Statement}). This continues +until the end of the file is reached.@refill + +For example, the @code{awk} program: + +@example +/12/ @{ print $0 @} +/21/ @{ print $0 @} +@end example + +@noindent +contains two rules. The first rule has the string @samp{12} as the +pattern and @samp{print $0} as the action. The second rule has the +string @samp{21} as the pattern and also has @samp{print $0} as the +action. Each rule's action is enclosed in its own pair of braces. + +This @code{awk} program prints every line that contains the string +@samp{12} @emph{or} the string @samp{21}. If a line contains both +strings, it is printed twice, once by each rule. + +If we run this program on our two sample data files, @file{BBS-list} and +@file{inventory-shipped}, as shown here: + +@example +awk '/12/ @{ print $0 @} + /21/ @{ print $0 @}' BBS-list inventory-shipped +@end example + +@noindent +we get the following output: + +@example +aardvark 555-5553 1200/300 B +alpo-net 555-3412 2400/1200/300 A +barfly 555-7685 1200/300 A +bites 555-1675 2400/1200/300 A +core 555-2912 1200/300 C +fooey 555-1234 2400/1200/300 B +foot 555-6699 1200/300 B +macfoo 555-6480 1200/300 A +sdace 555-3430 2400/1200/300 A +sabafoo 555-2127 1200/300 C +sabafoo 555-2127 1200/300 C +Jan 21 36 64 620 +Apr 21 70 74 514 +@end example + +@noindent +Note how the line in @file{BBS-list} beginning with @samp{sabafoo} +was printed twice, once for each rule. + +@node More Complex, Running gawk, Two Rules, Getting Started +@comment node-name, next, previous, up +@section A More Complex Example + +Here is an example to give you an idea of what typical @code{awk} +programs do. This example shows how @code{awk} can be used to +summarize, select, and rearrange the output of another utility. It uses +features that haven't been covered yet, so don't worry if you don't +understand all the details. + +@example +ls -l | awk '$5 == "Nov" @{ sum += $4 @} + END @{ print sum @}' +@end example + +This command prints the total number of bytes in all the files in the +current directory that were last modified in November (of any year). +(In the C shell you would need to type a semicolon and then a backslash +at the end of the first line; in a @sc{posix}-compliant shell, such as the +Bourne shell or the Bourne-Again shell, you can type the example as shown.) + +The @w{@samp{ls -l}} part of this example is a command that gives you a +listing of the files in a directory, including file size and date. +Its output looks like this:@refill + +@example +-rw-r--r-- 1 close 1933 Nov 7 13:05 Makefile +-rw-r--r-- 1 close 10809 Nov 7 13:03 gawk.h +-rw-r--r-- 1 close 983 Apr 13 12:14 gawk.tab.h +-rw-r--r-- 1 close 31869 Jun 15 12:20 gawk.y +-rw-r--r-- 1 close 22414 Nov 7 13:03 gawk1.c +-rw-r--r-- 1 close 37455 Nov 7 13:03 gawk2.c +-rw-r--r-- 1 close 27511 Dec 9 13:07 gawk3.c +-rw-r--r-- 1 close 7989 Nov 7 13:03 gawk4.c +@end example + +@noindent +The first field contains read-write permissions, the second field contains +the number of links to the file, and the third field identifies the owner of +the file. The fourth field contains the size of the file in bytes. The +fifth, sixth, and seventh fields contain the month, day, and time, +respectively, that the file was last modified. Finally, the eighth field +contains the name of the file. + +The @code{$5 == "Nov"} in our @code{awk} program is an expression that +tests whether the fifth field of the output from @w{@samp{ls -l}} +matches the string @samp{Nov}. Each time a line has the string +@samp{Nov} in its fifth field, the action @samp{@{ sum += $4 @}} is +performed. This adds the fourth field (the file size) to the variable +@code{sum}. As a result, when @code{awk} has finished reading all the +input lines, @code{sum} is the sum of the sizes of files whose +lines matched the pattern. (This works because @code{awk} variables +are automatically initialized to zero.)@refill + +After the last line of output from @code{ls} has been processed, the +@code{END} rule is executed, and the value of @code{sum} is +printed. In this example, the value of @code{sum} would be 80600.@refill + +These more advanced @code{awk} techniques are covered in later sections +(@pxref{Actions, ,Overview of Actions}). Before you can move on to more +advanced @code{awk} programming, you have to know how @code{awk} interprets +your input and displays your output. By manipulating fields and using +@code{print} statements, you can produce some very useful and spectacular +looking reports.@refill + +@node Running gawk, Comments, More Complex, Getting Started +@section How to Run @code{awk} Programs + +@ignore +Date: Mon, 26 Aug 91 09:48:10 +0200 +From: gatech!vsoc07.cern.ch!matheys (Jean-Pol Matheys (CERN - ECP Division)) +To: uunet.UU.NET!skeeve!arnold +Subject: RE: status check + +The introduction of Chapter 2 (i.e. before 2.1) should include +the whole of section 2.4 - it's better to tell people how to run awk programs +before giving any examples + +ADR --- he's right. but for now, don't do this because the rest of the +chapter would need some rewriting. +@end ignore + +@cindex command line formats +@cindex running @code{awk} programs +There are several ways to run an @code{awk} program. If the program is +short, it is easiest to include it in the command that runs @code{awk}, +like this: + +@example +awk '@var{program}' @var{input-file1} @var{input-file2} @dots{} +@end example + +@noindent +where @var{program} consists of a series of patterns and actions, as +described earlier. + +When the program is long, it is usually more convenient to put it in a file +and run it with a command like this: + +@example +awk -f @var{program-file} @var{input-file1} @var{input-file2} @dots{} +@end example + +@menu +* One-shot:: Running a short throw-away @code{awk} program. +* Read Terminal:: Using no input files (input from + terminal instead). +* Long:: Putting permanent @code{awk} programs in files. +* Executable Scripts:: Making self-contained @code{awk} programs. +@end menu + +@node One-shot, Read Terminal, Running gawk, Running gawk +@subsection One-shot Throw-away @code{awk} Programs + +Once you are familiar with @code{awk}, you will often type simple +programs at the moment you want to use them. Then you can write the +program as the first argument of the @code{awk} command, like this: + +@example +awk '@var{program}' @var{input-file1} @var{input-file2} @dots{} +@end example + +@noindent +where @var{program} consists of a series of @var{patterns} and +@var{actions}, as described earlier. + +@cindex single quotes, why needed +This command format instructs the shell to start @code{awk} and use the +@var{program} to process records in the input file(s). There are single +quotes around @var{program} so that the shell doesn't interpret any +@code{awk} characters as special shell characters. They also cause the +shell to treat all of @var{program} as a single argument for +@code{awk} and allow @var{program} to be more than one line long.@refill + +This format is also useful for running short or medium-sized @code{awk} +programs from shell scripts, because it avoids the need for a separate +file for the @code{awk} program. A self-contained shell script is more +reliable since there are no other files to misplace. + +@node Read Terminal, Long, One-shot, Running gawk +@subsection Running @code{awk} without Input Files + +@cindex standard input +@cindex input, standard +You can also run @code{awk} without any input files. If you type the +command line:@refill + +@example +awk '@var{program}' +@end example + +@noindent +then @code{awk} applies the @var{program} to the @dfn{standard input}, +which usually means whatever you type on the terminal. This continues +until you indicate end-of-file by typing @kbd{Control-d}. + +For example, if you execute this command: + +@example +awk '/th/' +@end example + +@noindent +whatever you type next is taken as data for that @code{awk} +program. If you go on to type the following data: + +@example +Kathy +Ben +Tom +Beth +Seth +Karen +Thomas +@kbd{Control-d} +@end example + +@noindent +then @code{awk} prints this output: + +@example +Kathy +Beth +Seth +@end example + +@noindent +@cindex case sensitivity +@cindex pattern, case sensitive +as matching the pattern @samp{th}. Notice that it did not recognize +@samp{Thomas} as matching the pattern. The @code{awk} language is +@dfn{case sensitive}, and matches patterns exactly. (However, you can +override this with the variable @code{IGNORECASE}. +@xref{Case-sensitivity, ,Case-sensitivity in Matching}.) + +@node Long, Executable Scripts, Read Terminal, Running gawk +@subsection Running Long Programs + +@cindex running long programs +@cindex @samp{-f} option +@cindex program file +@cindex file, @code{awk} program +Sometimes your @code{awk} programs can be very long. In this case it is +more convenient to put the program into a separate file. To tell +@code{awk} to use that file for its program, you type:@refill + +@example +awk -f @var{source-file} @var{input-file1} @var{input-file2} @dots{} +@end example + +The @samp{-f} instructs the @code{awk} utility to get the @code{awk} program +from the file @var{source-file}. Any file name can be used for +@var{source-file}. For example, you could put the program:@refill + +@example +/th/ +@end example + +@noindent +into the file @file{th-prog}. Then this command: + +@example +awk -f th-prog +@end example + +@noindent +does the same thing as this one: + +@example +awk '/th/' +@end example + +@noindent +which was explained earlier (@pxref{Read Terminal, ,Running @code{awk} without Input Files}). +Note that you don't usually need single quotes around the file name that you +specify with @samp{-f}, because most file names don't contain any of the shell's +special characters. Notice that in @file{th-prog}, the @code{awk} +program did not have single quotes around it. The quotes are only needed +for programs that are provided on the @code{awk} command line. + +If you want to identify your @code{awk} program files clearly as such, +you can add the extension @file{.awk} to the file name. This doesn't +affect the execution of the @code{awk} program, but it does make +``housekeeping'' easier. + +@node Executable Scripts, , Long, Running gawk +@c node-name, next, previous, up +@subsection Executable @code{awk} Programs +@cindex executable scripts +@cindex scripts, executable +@cindex self contained programs +@cindex program, self contained +@cindex @samp{#!} + +Once you have learned @code{awk}, you may want to write self-contained +@code{awk} scripts, using the @samp{#!} script mechanism. You can do +this on many Unix systems @footnote{The @samp{#!} mechanism works on +Unix systems derived from Berkeley Unix, System V Release 4, and some System +V Release 3 systems.} (and someday on GNU).@refill + +For example, you could create a text file named @file{hello}, containing +the following (where @samp{BEGIN} is a feature we have not yet +discussed): + +@example +#! /bin/awk -f + +# a sample awk program +BEGIN @{ print "hello, world" @} +@end example + +@noindent +After making this file executable (with the @code{chmod} command), you +can simply type: + +@example +hello +@end example + +@noindent +at the shell, and the system will arrange to run @code{awk} @footnote{The +line beginning with @samp{#!} lists the full pathname of an interpreter +to be run, and an optional initial command line argument to pass to that +interpreter. The operating system then runs the interpreter with the given +argument and the full argument list of the executed program. The first argument +in the list is the full pathname of the @code{awk} program. The rest of the +argument list will either be options to @code{awk}, or data files, +or both.} as if you had typed:@refill + +@example +awk -f hello +@end example + +@noindent +Self-contained @code{awk} scripts are useful when you want to write a +program which users can invoke without knowing that the program is +written in @code{awk}. + +@cindex shell scripts +@cindex scripts, shell +If your system does not support the @samp{#!} mechanism, you can get a +similar effect using a regular shell script. It would look something +like this: + +@example +: The colon makes sure this script is executed by the Bourne shell. +awk '@var{program}' "$@@" +@end example + +Using this technique, it is @emph{vital} to enclose the @var{program} in +single quotes to protect it from interpretation by the shell. If you +omit the quotes, only a shell wizard can predict the results. + +The @samp{"$@@"} causes the shell to forward all the command line +arguments to the @code{awk} program, without interpretation. The first +line, which starts with a colon, is used so that this shell script will +work even if invoked by a user who uses the C shell. +@c Someday: (See @cite{The Bourne Again Shell}, by ??.) + +@node Comments, Statements/Lines, Running gawk, Getting Started +@section Comments in @code{awk} Programs +@cindex @samp{#} +@cindex comments +@cindex use of comments +@cindex documenting @code{awk} programs +@cindex programs, documenting + +A @dfn{comment} is some text that is included in a program for the sake +of human readers, and that is not really part of the program. Comments +can explain what the program does, and how it works. Nearly all +programming languages have provisions for comments, because programs are +typically hard to understand without their extra help. + +In the @code{awk} language, a comment starts with the sharp sign +character, @samp{#}, and continues to the end of the line. The +@code{awk} language ignores the rest of a line following a sharp sign. +For example, we could have put the following into @file{th-prog}:@refill + +@smallexample +# This program finds records containing the pattern @samp{th}. This is how +# you continue comments on additional lines. +/th/ +@end smallexample + +You can put comment lines into keyboard-composed throw-away @code{awk} +programs also, but this usually isn't very useful; the purpose of a +comment is to help you or another person understand the program at +a later time.@refill + +@node Statements/Lines, When, Comments, Getting Started +@section @code{awk} Statements versus Lines + +Most often, each line in an @code{awk} program is a separate statement or +separate rule, like this: + +@example +awk '/12/ @{ print $0 @} + /21/ @{ print $0 @}' BBS-list inventory-shipped +@end example + +But sometimes statements can be more than one line, and lines can +contain several statements. You can split a statement into multiple +lines by inserting a newline after any of the following:@refill + +@example +, @{ ? : || && do else +@end example + +@noindent +A newline at any other point is considered the end of the statement. +(Splitting lines after @samp{?} and @samp{:} is a minor @code{gawk} +extension. The @samp{?} and @samp{:} referred to here is the +three operand conditional expression described in +@ref{Conditional Exp, ,Conditional Expressions}.)@refill + +@cindex backslash continuation +@cindex continuation of lines +If you would like to split a single statement into two lines at a point +where a newline would terminate it, you can @dfn{continue} it by ending the +first line with a backslash character, @samp{\}. This is allowed +absolutely anywhere in the statement, even in the middle of a string or +regular expression. For example: + +@example +awk '/This program is too long, so continue it\ + on the next line/ @{ print $1 @}' +@end example + +@noindent +We have generally not used backslash continuation in the sample programs in +this manual. Since in @code{gawk} there is no limit on the length of a line, +it is never strictly necessary; it just makes programs prettier. We have +preferred to make them even more pretty by keeping the statements short. +Backslash continuation is most useful when your @code{awk} program is in a +separate source file, instead of typed in on the command line. You should +also note that many @code{awk} implementations are more picky about where +you may use backslash continuation. For maximal portability of your @code{awk} +programs, it is best not to split your lines in the middle of a regular +expression or a string.@refill + +@strong{Warning: backslash continuation does not work as described above +with the C shell.} Continuation with backslash works for @code{awk} +programs in files, and also for one-shot programs @emph{provided} you +are using a @sc{posix}-compliant shell, such as the Bourne shell or the +Bourne-again shell. But the C shell used on Berkeley Unix behaves +differently! There, you must use two backslashes in a row, followed by +a newline.@refill + +@cindex multiple statements on one line +When @code{awk} statements within one rule are short, you might want to put +more than one of them on a line. You do this by separating the statements +with a semicolon, @samp{;}. +This also applies to the rules themselves. +Thus, the previous program could have been written:@refill + +@example +/12/ @{ print $0 @} ; /21/ @{ print $0 @} +@end example + +@noindent +@strong{Note:} the requirement that rules on the same line must be +separated with a semicolon is a recent change in the @code{awk} +language; it was done for consistency with the treatment of statements +within an action. + +@node When, , Statements/Lines, Getting Started +@section When to Use @code{awk} + +@cindex when to use @code{awk} +@cindex applications of @code{awk} +You might wonder how @code{awk} might be useful for you. Using additional +utility programs, more advanced patterns, field separators, arithmetic +statements, and other selection criteria, you can produce much more +complex output. The @code{awk} language is very useful for producing +reports from large amounts of raw data, such as summarizing information +from the output of other utility programs like @code{ls}. +(@xref{More Complex, ,A More Complex Example}.) + +Programs written with @code{awk} are usually much smaller than they would +be in other languages. This makes @code{awk} programs easy to compose and +use. Often @code{awk} programs can be quickly composed at your terminal, +used once, and thrown away. Since @code{awk} programs are interpreted, you +can avoid the usually lengthy edit-compile-test-debug cycle of software +development. + +Complex programs have been written in @code{awk}, including a complete +retargetable assembler for 8-bit microprocessors (@pxref{Glossary}, for +more information) and a microcode assembler for a special purpose Prolog +computer. However, @code{awk}'s capabilities are strained by tasks of +such complexity. + +If you find yourself writing @code{awk} scripts of more than, say, a few +hundred lines, you might consider using a different programming +language. Emacs Lisp is a good choice if you need sophisticated string +or pattern matching capabilities. The shell is also good at string and +pattern matching; in addition, it allows powerful use of the system +utilities. More conventional languages, such as C, C++, and Lisp, offer +better facilities for system programming and for managing the complexity +of large programs. Programs in these languages may require more lines +of source code than the equivalent @code{awk} programs, but they are +easier to maintain and usually run more efficiently.@refill + +@node Reading Files, Printing, Getting Started, Top +@chapter Reading Input Files + +@cindex reading files +@cindex input +@cindex standard input +@vindex FILENAME +In the typical @code{awk} program, all input is read either from the +standard input (by default the keyboard, but often a pipe from another +command) or from files whose names you specify on the @code{awk} command +line. If you specify input files, @code{awk} reads them in order, reading +all the data from one before going on to the next. The name of the current +input file can be found in the built-in variable @code{FILENAME} +(@pxref{Built-in Variables}).@refill + +The input is read in units called records, and processed by the +rules one record at a time. By default, each record is one line. Each +record is split automatically into fields, to make it more +convenient for a rule to work on its parts. + +On rare occasions you will need to use the @code{getline} command, +which can do explicit input from any number of files +(@pxref{Getline, ,Explicit Input with @code{getline}}).@refill + +@menu +* Records:: Controlling how data is split into records. +* Fields:: An introduction to fields. +* Non-Constant Fields:: Non-constant Field Numbers. +* Changing Fields:: Changing the Contents of a Field. +* Field Separators:: The field separator and how to change it. +* Constant Size:: Reading constant width data. +* Multiple Line:: Reading multi-line records. +* Getline:: Reading files under explicit program control + using the @code{getline} function. +* Close Input:: Closing an input file (so you can read from + the beginning once more). +@end menu + +@node Records, Fields, Reading Files, Reading Files +@section How Input is Split into Records + +@cindex record separator +The @code{awk} language divides its input into records and fields. +Records are separated by a character called the @dfn{record separator}. +By default, the record separator is the newline character, defining +a record to be a single line of text.@refill + +@iftex +@cindex changing the record separator +@end iftex +@vindex RS +Sometimes you may want to use a different character to separate your +records. You can use a different character by changing the built-in +variable @code{RS}. The value of @code{RS} is a string that says how +to separate records; the default value is @code{"\n"}, the string containing +just a newline character. This is why records are, by default, single lines. + +@code{RS} can have any string as its value, but only the first character +of the string is used as the record separator. The other characters are +ignored. @code{RS} is exceptional in this regard; @code{awk} uses the +full value of all its other built-in variables.@refill + +@ignore +Someday this should be true! + +The value of @code{RS} is not limited to a one-character string. It can +be any regular expression (@pxref{Regexp, ,Regular Expressions as Patterns}). +In general, each record +ends at the next string that matches the regular expression; the next +record starts at the end of the matching string. This general rule is +actually at work in the usual case, where @code{RS} contains just a +newline: a record ends at the beginning of the next matching string (the +next newline in the input) and the following record starts just after +the end of this string (at the first character of the following line). +The newline, since it matches @code{RS}, is not part of either record.@refill +@end ignore + +You can change the value of @code{RS} in the @code{awk} program with the +assignment operator, @samp{=} (@pxref{Assignment Ops, ,Assignment Expressions}). +The new record-separator character should be enclosed in quotation marks to make +a string constant. Often the right time to do this is at the beginning +of execution, before any input has been processed, so that the very +first record will be read with the proper separator. To do this, use +the special @code{BEGIN} pattern +(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}). For +example:@refill + +@example +awk 'BEGIN @{ RS = "/" @} ; @{ print $0 @}' BBS-list +@end example + +@noindent +changes the value of @code{RS} to @code{"/"}, before reading any input. +This is a string whose first character is a slash; as a result, records +are separated by slashes. Then the input file is read, and the second +rule in the @code{awk} program (the action with no pattern) prints each +record. Since each @code{print} statement adds a newline at the end of +its output, the effect of this @code{awk} program is to copy the input +with each slash changed to a newline. + +Another way to change the record separator is on the command line, +using the variable-assignment feature +(@pxref{Command Line, ,Invoking @code{awk}}).@refill + +@example +awk '@{ print $0 @}' RS="/" BBS-list +@end example + +@noindent +This sets @code{RS} to @samp{/} before processing @file{BBS-list}. + +Reaching the end of an input file terminates the current input record, +even if the last character in the file is not the character in @code{RS}. + +@ignore +@c merge the preceding paragraph and this stuff into one paragraph +@c and put it in an `expert info' section. +This produces correct behavior in the vast majority of cases, although +the following (extreme) pipeline prints a surprising @samp{1}. (There +is one field, consisting of a newline.) + +@example +echo | awk 'BEGIN @{ RS = "a" @} ; @{ print NF @}' +@end example + +@end ignore + +The empty string, @code{""} (a string of no characters), has a special meaning +as the value of @code{RS}: it means that records are separated only +by blank lines. @xref{Multiple Line, ,Multiple-Line Records}, for more details. + +@cindex number of records, @code{NR} or @code{FNR} +@vindex NR +@vindex FNR +The @code{awk} utility keeps track of the number of records that have +been read so far from the current input file. This value is stored in a +built-in variable called @code{FNR}. It is reset to zero when a new +file is started. Another built-in variable, @code{NR}, is the total +number of input records read so far from all files. It starts at zero +but is never automatically reset to zero. + +If you change the value of @code{RS} in the middle of an @code{awk} run, +the new value is used to delimit subsequent records, but the record +currently being processed (and records already processed) are not +affected. + +@node Fields, Non-Constant Fields, Records, Reading Files +@section Examining Fields + +@cindex examining fields +@cindex fields +@cindex accessing fields +When @code{awk} reads an input record, the record is +automatically separated or @dfn{parsed} by the interpreter into chunks +called @dfn{fields}. By default, fields are separated by whitespace, +like words in a line. +Whitespace in @code{awk} means any string of one or more spaces and/or +tabs; other characters such as newline, formfeed, and so on, that are +considered whitespace by other languages are @emph{not} considered +whitespace by @code{awk}.@refill + +The purpose of fields is to make it more convenient for you to refer to +these pieces of the record. You don't have to use them---you can +operate on the whole record if you wish---but fields are what make +simple @code{awk} programs so powerful. + +@cindex @code{$} (field operator) +@cindex operators, @code{$} +To refer to a field in an @code{awk} program, you use a dollar-sign, +@samp{$}, followed by the number of the field you want. Thus, @code{$1} +refers to the first field, @code{$2} to the second, and so on. For +example, suppose the following is a line of input:@refill + +@example +This seems like a pretty nice example. +@end example + +@noindent +Here the first field, or @code{$1}, is @samp{This}; the second field, or +@code{$2}, is @samp{seems}; and so on. Note that the last field, +@code{$7}, is @samp{example.}. Because there is no space between the +@samp{e} and the @samp{.}, the period is considered part of the seventh +field.@refill + +No matter how many fields there are, the last field in a record can be +represented by @code{$NF}. So, in the example above, @code{$NF} would +be the same as @code{$7}, which is @samp{example.}. Why this works is +explained below (@pxref{Non-Constant Fields, ,Non-constant Field Numbers}). +If you try to refer to a field beyond the last one, such as @code{$8} +when the record has only 7 fields, you get the empty string.@refill + +@vindex NF +@cindex number of fields, @code{NF} +Plain @code{NF}, with no @samp{$}, is a built-in variable whose value +is the number of fields in the current record. + +@code{$0}, which looks like an attempt to refer to the zeroth field, is +a special case: it represents the whole input record. This is what you +would use if you weren't interested in fields. + +Here are some more examples: + +@example +awk '$1 ~ /foo/ @{ print $0 @}' BBS-list +@end example + +@noindent +This example prints each record in the file @file{BBS-list} whose first +field contains the string @samp{foo}. The operator @samp{~} is called a +@dfn{matching operator} (@pxref{Comparison Ops, ,Comparison Expressions}); +it tests whether a string (here, the field @code{$1}) matches a given regular +expression.@refill + +By contrast, the following example: + +@example +awk '/foo/ @{ print $1, $NF @}' BBS-list +@end example + +@noindent +looks for @samp{foo} in @emph{the entire record} and prints the first +field and the last field for each input record containing a +match.@refill + +@node Non-Constant Fields, Changing Fields, Fields, Reading Files +@section Non-constant Field Numbers + +The number of a field does not need to be a constant. Any expression in +the @code{awk} language can be used after a @samp{$} to refer to a +field. The value of the expression specifies the field number. If the +value is a string, rather than a number, it is converted to a number. +Consider this example:@refill + +@example +awk '@{ print $NR @}' +@end example + +@noindent +Recall that @code{NR} is the number of records read so far: 1 in the +first record, 2 in the second, etc. So this example prints the first +field of the first record, the second field of the second record, and so +on. For the twentieth record, field number 20 is printed; most likely, +the record has fewer than 20 fields, so this prints a blank line. + +Here is another example of using expressions as field numbers: + +@example +awk '@{ print $(2*2) @}' BBS-list +@end example + +The @code{awk} language must evaluate the expression @code{(2*2)} and use +its value as the number of the field to print. The @samp{*} sign +represents multiplication, so the expression @code{2*2} evaluates to 4. +The parentheses are used so that the multiplication is done before the +@samp{$} operation; they are necessary whenever there is a binary +operator in the field-number expression. This example, then, prints the +hours of operation (the fourth field) for every line of the file +@file{BBS-list}.@refill + +If the field number you compute is zero, you get the entire record. +Thus, @code{$(2-2)} has the same value as @code{$0}. Negative field +numbers are not allowed. + +The number of fields in the current record is stored in the built-in +variable @code{NF} (@pxref{Built-in Variables}). The expression +@code{$NF} is not a special feature: it is the direct consequence of +evaluating @code{NF} and using its value as a field number. + +@node Changing Fields, Field Separators, Non-Constant Fields, Reading Files +@section Changing the Contents of a Field + +@cindex field, changing contents of +@cindex changing contents of a field +@cindex assignment to fields +You can change the contents of a field as seen by @code{awk} within an +@code{awk} program; this changes what @code{awk} perceives as the +current input record. (The actual input is untouched: @code{awk} never +modifies the input file.) + +Consider this example: + +@smallexample +awk '@{ $3 = $2 - 10; print $2, $3 @}' inventory-shipped +@end smallexample + +@noindent +The @samp{-} sign represents subtraction, so this program reassigns +field three, @code{$3}, to be the value of field two minus ten, +@code{$2 - 10}. (@xref{Arithmetic Ops, ,Arithmetic Operators}.) +Then field two, and the new value for field three, are printed. + +In order for this to work, the text in field @code{$2} must make sense +as a number; the string of characters must be converted to a number in +order for the computer to do arithmetic on it. The number resulting +from the subtraction is converted back to a string of characters which +then becomes field three. +@xref{Conversion, ,Conversion of Strings and Numbers}.@refill + +When you change the value of a field (as perceived by @code{awk}), the +text of the input record is recalculated to contain the new field where +the old one was. Therefore, @code{$0} changes to reflect the altered +field. Thus, + +@smallexample +awk '@{ $2 = $2 - 10; print $0 @}' inventory-shipped +@end smallexample + +@noindent +prints a copy of the input file, with 10 subtracted from the second +field of each line. + +You can also assign contents to fields that are out of range. For +example: + +@smallexample +awk '@{ $6 = ($5 + $4 + $3 + $2) ; print $6 @}' inventory-shipped +@end smallexample + +@noindent +We've just created @code{$6}, whose value is the sum of fields +@code{$2}, @code{$3}, @code{$4}, and @code{$5}. The @samp{+} sign +represents addition. For the file @file{inventory-shipped}, @code{$6} +represents the total number of parcels shipped for a particular month. + +Creating a new field changes the internal @code{awk} copy of the current +input record---the value of @code{$0}. Thus, if you do @samp{print $0} +after adding a field, the record printed includes the new field, with +the appropriate number of field separators between it and the previously +existing fields. + +This recomputation affects and is affected by several features not yet +discussed, in particular, the @dfn{output field separator}, @code{OFS}, +which is used to separate the fields (@pxref{Output Separators}), and +@code{NF} (the number of fields; @pxref{Fields, ,Examining Fields}). +For example, the value of @code{NF} is set to the number of the highest +field you create.@refill + +Note, however, that merely @emph{referencing} an out-of-range field +does @emph{not} change the value of either @code{$0} or @code{NF}. +Referencing an out-of-range field merely produces a null string. For +example:@refill + +@smallexample +if ($(NF+1) != "") + print "can't happen" +else + print "everything is normal" +@end smallexample + +@noindent +should print @samp{everything is normal}, because @code{NF+1} is certain +to be out of range. (@xref{If Statement, ,The @code{if} Statement}, +for more information about @code{awk}'s @code{if-else} statements.)@refill + +It is important to note that assigning to a field will change the +value of @code{$0}, but will not change the value of @code{NF}, +even when you assign the null string to a field. For example: + +@smallexample +echo a b c d | awk '@{ OFS = ":"; $2 = "" ; print ; print NF @}' +@end smallexample + +@noindent +prints + +@smallexample +a::c:d +4 +@end smallexample + +@noindent +The field is still there, it just has an empty value. You can tell +because there are two colons in a row. + +@node Field Separators, Constant Size, Changing Fields, Reading Files +@section Specifying how Fields are Separated +@vindex FS +@cindex fields, separating +@cindex field separator, @code{FS} +@cindex @samp{-F} option + +(This section is rather long; it describes one of the most fundamental +operations in @code{awk}. If you are a novice with @code{awk}, we +recommend that you re-read this section after you have studied the +section on regular expressions, @ref{Regexp, ,Regular Expressions as Patterns}.) + +The way @code{awk} splits an input record into fields is controlled by +the @dfn{field separator}, which is a single character or a regular +expression. @code{awk} scans the input record for matches for the +separator; the fields themselves are the text between the matches. For +example, if the field separator is @samp{oo}, then the following line: + +@smallexample +moo goo gai pan +@end smallexample + +@noindent +would be split into three fields: @samp{m}, @samp{@ g} and @samp{@ gai@ +pan}. + +The field separator is represented by the built-in variable @code{FS}. +Shell programmers take note! @code{awk} does not use the name @code{IFS} +which is used by the shell.@refill + +You can change the value of @code{FS} in the @code{awk} program with the +assignment operator, @samp{=} (@pxref{Assignment Ops, ,Assignment Expressions}). +Often the right time to do this is at the beginning of execution, +before any input has been processed, so that the very first record +will be read with the proper separator. To do this, use the special +@code{BEGIN} pattern +(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}). +For example, here we set the value of @code{FS} to the string +@code{","}:@refill + +@smallexample +awk 'BEGIN @{ FS = "," @} ; @{ print $2 @}' +@end smallexample + +@noindent +Given the input line, + +@smallexample +John Q. Smith, 29 Oak St., Walamazoo, MI 42139 +@end smallexample + +@noindent +this @code{awk} program extracts the string @samp{@ 29 Oak St.}. + +@cindex field separator, choice of +@cindex regular expressions as field separators +Sometimes your input data will contain separator characters that don't +separate fields the way you thought they would. For instance, the +person's name in the example we've been using might have a title or +suffix attached, such as @samp{John Q. Smith, LXIX}. From input +containing such a name: + +@smallexample +John Q. Smith, LXIX, 29 Oak St., Walamazoo, MI 42139 +@end smallexample + +@noindent +the previous sample program would extract @samp{@ LXIX}, instead of +@samp{@ 29 Oak St.}. If you were expecting the program to print the +address, you would be surprised. So choose your data layout and +separator characters carefully to prevent such problems. + +As you know, by default, fields are separated by whitespace sequences +(spaces and tabs), not by single spaces: two spaces in a row do not +delimit an empty field. The default value of the field separator is a +string @w{@code{" "}} containing a single space. If this value were +interpreted in the usual way, each space character would separate +fields, so two spaces in a row would make an empty field between them. +The reason this does not happen is that a single space as the value of +@code{FS} is a special case: it is taken to specify the default manner +of delimiting fields. + +If @code{FS} is any other single character, such as @code{","}, then +each occurrence of that character separates two fields. Two consecutive +occurrences delimit an empty field. If the character occurs at the +beginning or the end of the line, that too delimits an empty field. The +space character is the only single character which does not follow these +rules. + +More generally, the value of @code{FS} may be a string containing any +regular expression. Then each match in the record for the regular +expression separates fields. For example, the assignment:@refill + +@smallexample +FS = ", \t" +@end smallexample + +@noindent +makes every area of an input line that consists of a comma followed by a +space and a tab, into a field separator. (@samp{\t} stands for a +tab.)@refill + +For a less trivial example of a regular expression, suppose you want +single spaces to separate fields the way single commas were used above. +You can set @code{FS} to @w{@code{"[@ ]"}}. This regular expression +matches a single space and nothing else. + +@c the following index entry is an overfull hbox. --mew 30jan1992 +@cindex field separator: on command line +@cindex command line, setting @code{FS} on +@code{FS} can be set on the command line. You use the @samp{-F} argument to +do so. For example: + +@smallexample +awk -F, '@var{program}' @var{input-files} +@end smallexample + +@noindent +sets @code{FS} to be the @samp{,} character. Notice that the argument uses +a capital @samp{F}. Contrast this with @samp{-f}, which specifies a file +containing an @code{awk} program. Case is significant in command options: +the @samp{-F} and @samp{-f} options have nothing to do with each other. +You can use both options at the same time to set the @code{FS} argument +@emph{and} get an @code{awk} program from a file.@refill + +@c begin expert info +The value used for the argument to @samp{-F} is processed in exactly the +same way as assignments to the built-in variable @code{FS}. This means that +if the field separator contains special characters, they must be escaped +appropriately. For example, to use a @samp{\} as the field separator, you +would have to type: + +@smallexample +# same as FS = "\\" +awk -F\\\\ '@dots{}' files @dots{} +@end smallexample + +@noindent +Since @samp{\} is used for quoting in the shell, @code{awk} will see +@samp{-F\\}. Then @code{awk} processes the @samp{\\} for escape +characters (@pxref{Constants, ,Constant Expressions}), finally yielding +a single @samp{\} to be used for the field separator. +@c end expert info + +As a special case, in compatibility mode +(@pxref{Command Line, ,Invoking @code{awk}}), if the +argument to @samp{-F} is @samp{t}, then @code{FS} is set to the tab +character. (This is because if you type @samp{-F\t}, without the quotes, +at the shell, the @samp{\} gets deleted, so @code{awk} figures that you +really want your fields to be separated with tabs, and not @samp{t}s. +Use @samp{-v FS="t"} on the command line if you really do want to separate +your fields with @samp{t}s.)@refill + +For example, let's use an @code{awk} program file called @file{baud.awk} +that contains the pattern @code{/300/}, and the action @samp{print $1}. +Here is the program: + +@smallexample +/300/ @{ print $1 @} +@end smallexample + +Let's also set @code{FS} to be the @samp{-} character, and run the +program on the file @file{BBS-list}. The following command prints a +list of the names of the bulletin boards that operate at 300 baud and +the first three digits of their phone numbers:@refill + +@smallexample +awk -F- -f baud.awk BBS-list +@end smallexample + +@noindent +It produces this output: + +@smallexample +aardvark 555 +alpo +barfly 555 +bites 555 +camelot 555 +core 555 +fooey 555 +foot 555 +macfoo 555 +sdace 555 +sabafoo 555 +@end smallexample + +@noindent +Note the second line of output. If you check the original file, you will +see that the second line looked like this: + +@smallexample +alpo-net 555-3412 2400/1200/300 A +@end smallexample + +The @samp{-} as part of the system's name was used as the field +separator, instead of the @samp{-} in the phone number that was +originally intended. This demonstrates why you have to be careful in +choosing your field and record separators. + +The following program searches the system password file, and prints +the entries for users who have no password: + +@smallexample +awk -F: '$2 == ""' /etc/passwd +@end smallexample + +@noindent +Here we use the @samp{-F} option on the command line to set the field +separator. Note that fields in @file{/etc/passwd} are separated by +colons. The second field represents a user's encrypted password, but if +the field is empty, that user has no password. + +@c begin expert info +According to the @sc{posix} standard, @code{awk} is supposed to behave +as if each record is split into fields at the time that it is read. +In particular, this means that you can change the value of @code{FS} +after a record is read, but before any of the fields are referenced. +The value of the fields (i.e. how they were split) should reflect the +old value of @code{FS}, not the new one. + +However, many implementations of @code{awk} do not do this. Instead, +they defer splitting the fields until a field reference actually happens, +using the @emph{current} value of @code{FS}! This behavior can be difficult +to diagnose. The following example illustrates the results of the two methods. +(The @code{sed} command prints just the first line of @file{/etc/passwd}.) + +@smallexample +sed 1q /etc/passwd | awk '@{ FS = ":" ; print $1 @}' +@end smallexample + +@noindent +will usually print + +@smallexample +root +@end smallexample + +@noindent +on an incorrect implementation of @code{awk}, while @code{gawk} +will print something like + +@smallexample +root:nSijPlPhZZwgE:0:0:Root:/: +@end smallexample +@c end expert info + +@c begin expert info +There is an important difference between the two cases of @samp{FS = @w{" "}} +(a single blank) and @samp{FS = @w{"[ \t]+"}} (which is a regular expression +matching one or more blanks or tabs). For both values of @code{FS}, fields +are separated by runs of blanks and/or tabs. However, when the value of +@code{FS} is @code{" "}, @code{awk} will strip leading and trailing whitespace +from the record, and then decide where the fields are. + +For example, the following expression prints @samp{b}: + +@smallexample +echo ' a b c d ' | awk '@{ print $2 @}' +@end smallexample + +@noindent +However, the following prints @samp{a}: + +@smallexample +echo ' a b c d ' | awk 'BEGIN @{ FS = "[ \t]+" @} ; @{ print $2 @}' +@end smallexample + +@noindent +In this case, the first field is null. + +The stripping of leading and trailing whitespace also comes into +play whenever @code{$0} is recomputed. For instance, this pipeline + +@smallexample +echo ' a b c d' | awk '@{ print; $2 = $2; print @}' +@end smallexample + +@noindent +produces this output: + +@smallexample + a b c d +a b c d +@end smallexample + +@noindent +The first @code{print} statement prints the record as it was read, +with leading whitespace intact. The assignment to @code{$2} rebuilds +@code{$0} by concatenating @code{$1} through @code{$NF} together, +separated by the value of @code{OFS}. Since the leading whitespace +was ignored when finding @code{$1}, it is not part of the new @code{$0}. +Finally, the last @code{print} statement prints the new @code{$0}. +@c end expert info + +The following table summarizes how fields are split, based on the +value of @code{FS}. + +@table @code +@item FS == " " +Fields are separated by runs of whitespace. Leading and trailing +whitespace are ignored. This is the default. + +@item FS == @var{any single character} +Fields are separated by each occurrence of the character. Multiple +successive occurrences delimit empty fields, as do leading and +trailing occurrences. + +@item FS == @var{regexp} +Fields are separated by occurrences of characters that match @var{regexp}. +Leading and trailing matches of @var{regexp} delimit empty fields. +@end table + +@node Constant Size, Multiple Line, Field Separators, Reading Files +@section Reading Fixed-width Data + +(This section discusses an advanced, experimental feature. If you are +a novice @code{awk} user, you may wish to skip it on the first reading.) + +@code{gawk} 2.13 introduced a new facility for dealing with fixed-width fields +with no distinctive field separator. Data of this nature arises typically +in one of at least two ways: the input for old FORTRAN programs where +numbers are run together, and the output of programs that did not anticipate +the use of their output as input for other programs. + +An example of the latter is a table where all the columns are lined up by +the use of a variable number of spaces and @emph{empty fields are just +spaces}. Clearly, @code{awk}'s normal field splitting based on @code{FS} +will not work well in this case. (Although a portable @code{awk} program +can use a series of @code{substr} calls on @code{$0}, this is awkward and +inefficient for a large number of fields.)@refill + +The splitting of an input record into fixed-width fields is specified by +assigning a string containing space-separated numbers to the built-in +variable @code{FIELDWIDTHS}. Each number specifies the width of the field +@emph{including} columns between fields. If you want to ignore the columns +between fields, you can specify the width as a separate field that is +subsequently ignored. + +The following data is the output of the @code{w} utility. It is useful +to illustrate the use of @code{FIELDWIDTHS}. + +@smallexample + 10:06pm up 21 days, 14:04, 23 users +User tty login@ idle JCPU PCPU what +hzuo ttyV0 8:58pm 9 5 vi p24.tex +hzang ttyV3 6:37pm 50 -csh +eklye ttyV5 9:53pm 7 1 em thes.tex +dportein ttyV6 8:17pm 1:47 -csh +gierd ttyD3 10:00pm 1 elm +dave ttyD4 9:47pm 4 4 w +brent ttyp0 26Jun91 4:46 26:46 4:41 bash +dave ttyq4 26Jun9115days 46 46 wnewmail +@end smallexample + +The following program takes the above input, converts the idle time to +number of seconds and prints out the first two fields and the calculated +idle time. (This program uses a number of @code{awk} features that +haven't been introduced yet.)@refill + +@smallexample +BEGIN @{ FIELDWIDTHS = "9 6 10 6 7 7 35" @} +NR > 2 @{ + idle = $4 + sub(/^ */, "", idle) # strip leading spaces + if (idle == "") idle = 0 + if (idle ~ /:/) @{ split(idle, t, ":"); idle = t[1] * 60 + t[2] @} + if (idle ~ /days/) @{ idle *= 24 * 60 * 60 @} + + print $1, $2, idle +@} +@end smallexample + +Here is the result of running the program on the data: + +@smallexample +hzuo ttyV0 0 +hzang ttyV3 50 +eklye ttyV5 0 +dportein ttyV6 107 +gierd ttyD3 1 +dave ttyD4 0 +brent ttyp0 286 +dave ttyq4 1296000 +@end smallexample + +Another (possibly more practical) example of fixed-width input data +would be the input from a deck of balloting cards. In some parts of +the United States, voters make their choices by punching holes in computer +cards. These cards are then processed to count the votes for any particular +candidate or on any particular issue. Since a voter may choose not to +vote on some issue, any column on the card may be empty. An @code{awk} +program for processing such data could use the @code{FIELDWIDTHS} feature +to simplify reading the data.@refill + +@c of course, getting gawk to run on a system with card readers is +@c another story! + +This feature is still experimental, and will likely evolve over time. + +@node Multiple Line, Getline, Constant Size, Reading Files +@section Multiple-Line Records + +@cindex multiple line records +@cindex input, multiple line records +@cindex reading files, multiple line records +@cindex records, multiple line +In some data bases, a single line cannot conveniently hold all the +information in one entry. In such cases, you can use multi-line +records. + +The first step in doing this is to choose your data format: when records +are not defined as single lines, how do you want to define them? +What should separate records? + +One technique is to use an unusual character or string to separate +records. For example, you could use the formfeed character (written +@code{\f} in @code{awk}, as in C) to separate them, making each record +a page of the file. To do this, just set the variable @code{RS} to +@code{"\f"} (a string containing the formfeed character). Any +other character could equally well be used, as long as it won't be part +of the data in a record.@refill + +@ignore +Another technique is to have blank lines separate records. The string +@code{"^\n+"} is a regular expression that matches any sequence of +newlines starting at the beginning of a line---in other words, it +matches a sequence of blank lines. If you set @code{RS} to this string, +a record always ends at the first blank line encountered. In +addition, a regular expression always matches the longest possible +sequence when there is a choice. So the next record doesn't start until +the first nonblank line that follows---no matter how many blank lines +appear in a row, they are considered one record-separator. +@end ignore + +Another technique is to have blank lines separate records. By a special +dispensation, a null string as the value of @code{RS} indicates that +records are separated by one or more blank lines. If you set @code{RS} +to the null string, a record always ends at the first blank line +encountered. And the next record doesn't start until the first nonblank +line that follows---no matter how many blank lines appear in a row, they +are considered one record-separator. (End of file is also considered +a record separator.)@refill +@c !!! This use of `end of file' is confusing. Needs to be clarified. + +The second step is to separate the fields in the record. One way to do +this is to put each field on a separate line: to do this, just set the +variable @code{FS} to the string @code{"\n"}. (This simple regular +expression matches a single newline.) + +Another way to separate fields is to divide each of the lines into fields +in the normal manner. This happens by default as a result of a special +feature: when @code{RS} is set to the null string, the newline character +@emph{always} acts as a field separator. This is in addition to whatever +field separations result from @code{FS}. + +The original motivation for this special exception was probably so that +you get useful behavior in the default case (i.e., @w{@code{FS == " "}}). +This feature can be a problem if you really don't want the +newline character to separate fields, since there is no way to +prevent it. However, you can work around this by using the @code{split} +function to break up the record manually +(@pxref{String Functions, ,Built-in Functions for String Manipulation}).@refill + +@ignore +Here are two ways to use records separated by blank lines and break each +line into fields normally: + +@example +awk 'BEGIN @{ RS = ""; FS = "[ \t\n]+" @} @{ print $1 @}' BBS-list + +@exdent @r{or} + +awk 'BEGIN @{ RS = "^\n+"; FS = "[ \t\n]+" @} @{ print $1 @}' BBS-list +@end example +@end ignore + +@ignore +Here is how to use records separated by blank lines and break each +line into fields normally: + +@example +awk 'BEGIN @{ RS = ""; FS = "[ \t\n]+" @} ; @{ print $1 @}' BBS-list +@end example +@end ignore + +@node Getline, Close Input, Multiple Line, Reading Files +@section Explicit Input with @code{getline} + +@findex getline +@cindex input, explicit +@cindex explicit input +@cindex input, @code{getline} command +@cindex reading files, @code{getline} command +So far we have been getting our input files from @code{awk}'s main +input stream---either the standard input (usually your terminal) or the +files specified on the command line. The @code{awk} language has a +special built-in command called @code{getline} that +can be used to read input under your explicit control.@refill + +This command is quite complex and should @emph{not} be used by +beginners. It is covered here because this is the chapter on input. +The examples that follow the explanation of the @code{getline} command +include material that has not been covered yet. Therefore, come back +and study the @code{getline} command @emph{after} you have reviewed the +rest of this manual and have a good knowledge of how @code{awk} works. + +@vindex ERRNO +@cindex differences: @code{gawk} and @code{awk} +@code{getline} returns 1 if it finds a record, and 0 if the end of the +file is encountered. If there is some error in getting a record, such +as a file that cannot be opened, then @code{getline} returns @minus{}1. +In this case, @code{gawk} sets the variable @code{ERRNO} to a string +describing the error that occurred. + +In the following examples, @var{command} stands for a string value that +represents a shell command. + +@table @code +@item getline +The @code{getline} command can be used without arguments to read input +from the current input file. All it does in this case is read the next +input record and split it up into fields. This is useful if you've +finished processing the current record, but you want to do some special +processing @emph{right now} on the next record. Here's an +example:@refill + +@example +awk '@{ + if (t = index($0, "/*")) @{ + if (t > 1) + tmp = substr($0, 1, t - 1) + else + tmp = "" + u = index(substr($0, t + 2), "*/") + while (u == 0) @{ + getline + t = -1 + u = index($0, "*/") + @} + if (u <= length($0) - 2) + $0 = tmp substr($0, t + u + 3) + else + $0 = tmp + @} + print $0 +@}' +@end example + +This @code{awk} program deletes all C-style comments, @samp{/* @dots{} +*/}, from the input. By replacing the @samp{print $0} with other +statements, you could perform more complicated processing on the +decommented input, like searching for matches of a regular +expression. (This program has a subtle problem---can you spot it?) + +@c the program to remove comments doesn't work if one +@c comment ends and another begins on the same line. (Your +@c idea for restart would be useful here). --- brennan@boeing.com + +This form of the @code{getline} command sets @code{NF} (the number of +fields; @pxref{Fields, ,Examining Fields}), @code{NR} (the number of +records read so far; @pxref{Records, ,How Input is Split into Records}), +@code{FNR} (the number of records read from this input file), and the +value of @code{$0}. + +@strong{Note:} the new value of @code{$0} is used in testing +the patterns of any subsequent rules. The original value +of @code{$0} that triggered the rule which executed @code{getline} +is lost. By contrast, the @code{next} statement reads a new record +but immediately begins processing it normally, starting with the first +rule in the program. @xref{Next Statement, ,The @code{next} Statement}. + +@item getline @var{var} +This form of @code{getline} reads a record into the variable @var{var}. +This is useful when you want your program to read the next record from +the current input file, but you don't want to subject the record to the +normal input processing. + +For example, suppose the next line is a comment, or a special string, +and you want to read it, but you must make certain that it won't trigger +any rules. This version of @code{getline} allows you to read that line +and store it in a variable so that the main +read-a-line-and-check-each-rule loop of @code{awk} never sees it. + +The following example swaps every two lines of input. For example, given: + +@example +wan +tew +free +phore +@end example + +@noindent +it outputs: + +@example +tew +wan +phore +free +@end example + +@noindent +Here's the program: + +@example +@group +awk '@{ + if ((getline tmp) > 0) @{ + print tmp + print $0 + @} else + print $0 +@}' +@end group +@end example + +The @code{getline} function used in this way sets only the variables +@code{NR} and @code{FNR} (and of course, @var{var}). The record is not +split into fields, so the values of the fields (including @code{$0}) and +the value of @code{NF} do not change.@refill + +@item getline < @var{file} +@cindex input redirection +@cindex redirection of input +This form of the @code{getline} function takes its input from the file +@var{file}. Here @var{file} is a string-valued expression that +specifies the file name. @samp{< @var{file}} is called a @dfn{redirection} +since it directs input to come from a different place. + +This form is useful if you want to read your input from a particular +file, instead of from the main input stream. For example, the following +program reads its input record from the file @file{foo.input} when it +encounters a first field with a value equal to 10 in the current input +file.@refill + +@example +awk '@{ + if ($1 == 10) @{ + getline < "foo.input" + print + @} else + print +@}' +@end example + +Since the main input stream is not used, the values of @code{NR} and +@code{FNR} are not changed. But the record read is split into fields in +the normal manner, so the values of @code{$0} and other fields are +changed. So is the value of @code{NF}. + +This does not cause the record to be tested against all the patterns +in the @code{awk} program, in the way that would happen if the record +were read normally by the main processing loop of @code{awk}. However +the new record is tested against any subsequent rules, just as when +@code{getline} is used without a redirection. + +@item getline @var{var} < @var{file} +This form of the @code{getline} function takes its input from the file +@var{file} and puts it in the variable @var{var}. As above, @var{file} +is a string-valued expression that specifies the file from which to read. + +In this version of @code{getline}, none of the built-in variables are +changed, and the record is not split into fields. The only variable +changed is @var{var}. + +For example, the following program copies all the input files to the +output, except for records that say @w{@samp{@@include @var{filename}}}. +Such a record is replaced by the contents of the file +@var{filename}.@refill + +@example +awk '@{ + if (NF == 2 && $1 == "@@include") @{ + while ((getline line < $2) > 0) + print line + close($2) + @} else + print +@}' +@end example + +Note here how the name of the extra input file is not built into +the program; it is taken from the data, from the second field on +the @samp{@@include} line.@refill + +The @code{close} function is called to ensure that if two identical +@samp{@@include} lines appear in the input, the entire specified file is +included twice. @xref{Close Input, ,Closing Input Files and Pipes}.@refill + +One deficiency of this program is that it does not process nested +@samp{@@include} statements the way a true macro preprocessor would. + +@item @var{command} | getline +You can @dfn{pipe} the output of a command into @code{getline}. A pipe is +simply a way to link the output of one program to the input of another. In +this case, the string @var{command} is run as a shell command and its output +is piped into @code{awk} to be used as input. This form of @code{getline} +reads one record from the pipe. + +For example, the following program copies input to output, except for lines +that begin with @samp{@@execute}, which are replaced by the output produced by +running the rest of the line as a shell command: + +@example +awk '@{ + if ($1 == "@@execute") @{ + tmp = substr($0, 10) + while ((tmp | getline) > 0) + print + close(tmp) + @} else + print +@}' +@end example + +@noindent +The @code{close} function is called to ensure that if two identical +@samp{@@execute} lines appear in the input, the command is run for +each one. @xref{Close Input, ,Closing Input Files and Pipes}. + +Given the input: + +@example +foo +bar +baz +@@execute who +bletch +@end example + +@noindent +the program might produce: + +@example +foo +bar +baz +hack ttyv0 Jul 13 14:22 +hack ttyp0 Jul 13 14:23 (gnu:0) +hack ttyp1 Jul 13 14:23 (gnu:0) +hack ttyp2 Jul 13 14:23 (gnu:0) +hack ttyp3 Jul 13 14:23 (gnu:0) +bletch +@end example + +@noindent +Notice that this program ran the command @code{who} and printed the result. +(If you try this program yourself, you will get different results, showing +you who is logged in on your system.) + +This variation of @code{getline} splits the record into fields, sets the +value of @code{NF} and recomputes the value of @code{$0}. The values of +@code{NR} and @code{FNR} are not changed. + +@item @var{command} | getline @var{var} +The output of the command @var{command} is sent through a pipe to +@code{getline} and into the variable @var{var}. For example, the +following program reads the current date and time into the variable +@code{current_time}, using the @code{date} utility, and then +prints it.@refill + +@example +awk 'BEGIN @{ + "date" | getline current_time + close("date") + print "Report printed on " current_time +@}' +@end example + +In this version of @code{getline}, none of the built-in variables are +changed, and the record is not split into fields. +@end table + +@node Close Input, , Getline, Reading Files +@section Closing Input Files and Pipes +@cindex closing input files and pipes +@findex close + +If the same file name or the same shell command is used with +@code{getline} more than once during the execution of an @code{awk} +program, the file is opened (or the command is executed) only the first time. +At that time, the first record of input is read from that file or command. +The next time the same file or command is used in @code{getline}, another +record is read from it, and so on. + +This implies that if you want to start reading the same file again from +the beginning, or if you want to rerun a shell command (rather than +reading more output from the command), you must take special steps. +What you must do is use the @code{close} function, as follows: + +@example +close(@var{filename}) +@end example + +@noindent +or + +@example +close(@var{command}) +@end example + +The argument @var{filename} or @var{command} can be any expression. Its +value must exactly equal the string that was used to open the file or +start the command---for example, if you open a pipe with this: + +@example +"sort -r names" | getline foo +@end example + +@noindent +then you must close it with this: + +@example +close("sort -r names") +@end example + +Once this function call is executed, the next @code{getline} from that +file or command will reopen the file or rerun the command. + +@iftex +@vindex ERRNO +@cindex differences: @code{gawk} and @code{awk} +@end iftex +@code{close} returns a value of zero if the close succeeded. +Otherwise, the value will be non-zero. +In this case, @code{gawk} sets the variable @code{ERRNO} to a string +describing the error that occurred. + +@node Printing, One-liners, Reading Files, Top +@chapter Printing Output + +@cindex printing +@cindex output +One of the most common things that actions do is to output or @dfn{print} +some or all of the input. For simple output, use the @code{print} +statement. For fancier formatting use the @code{printf} statement. +Both are described in this chapter. + +@menu +* Print:: The @code{print} statement. +* Print Examples:: Simple examples of @code{print} statements. +* Output Separators:: The output separators and how to change them. +* OFMT:: Controlling Numeric Output With @code{print}. +* Printf:: The @code{printf} statement. +* Redirection:: How to redirect output to multiple + files and pipes. +* Special Files:: File name interpretation in @code{gawk}. + @code{gawk} allows access to + inherited file descriptors. +@end menu + +@node Print, Print Examples, Printing, Printing +@section The @code{print} Statement +@cindex @code{print} statement + +The @code{print} statement does output with simple, standardized +formatting. You specify only the strings or numbers to be printed, in a +list separated by commas. They are output, separated by single spaces, +followed by a newline. The statement looks like this: + +@example +print @var{item1}, @var{item2}, @dots{} +@end example + +@noindent +The entire list of items may optionally be enclosed in parentheses. The +parentheses are necessary if any of the item expressions uses a +relational operator; otherwise it could be confused with a redirection +(@pxref{Redirection, ,Redirecting Output of @code{print} and @code{printf}}). +The relational operators are @samp{==}, +@samp{!=}, @samp{<}, @samp{>}, @samp{>=}, @samp{<=}, @samp{~} and +@samp{!~} (@pxref{Comparison Ops, ,Comparison Expressions}).@refill + +The items printed can be constant strings or numbers, fields of the +current record (such as @code{$1}), variables, or any @code{awk} +expressions. The @code{print} statement is completely general for +computing @emph{what} values to print. With two exceptions, +you cannot specify @emph{how} to print them---how many +columns, whether to use exponential notation or not, and so on. +(@xref{Output Separators}, and +@ref{OFMT, ,Controlling Numeric Output with @code{print}}.) +For that, you need the @code{printf} statement +(@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing}).@refill + +The simple statement @samp{print} with no items is equivalent to +@samp{print $0}: it prints the entire current record. To print a blank +line, use @samp{print ""}, where @code{""} is the null, or empty, +string. + +To print a fixed piece of text, use a string constant such as +@w{@code{"Hello there"}} as one item. If you forget to use the +double-quote characters, your text will be taken as an @code{awk} +expression, and you will probably get an error. Keep in mind that a +space is printed between any two items. + +Most often, each @code{print} statement makes one line of output. But it +isn't limited to one line. If an item value is a string that contains a +newline, the newline is output along with the rest of the string. A +single @code{print} can make any number of lines this way. + +@node Print Examples, Output Separators, Print, Printing +@section Examples of @code{print} Statements + +Here is an example of printing a string that contains embedded newlines: + +@example +awk 'BEGIN @{ print "line one\nline two\nline three" @}' +@end example + +@noindent +produces output like this: + +@example +line one +line two +line three +@end example + +Here is an example that prints the first two fields of each input record, +with a space between them: + +@example +awk '@{ print $1, $2 @}' inventory-shipped +@end example + +@noindent +Its output looks like this: + +@example +Jan 13 +Feb 15 +Mar 15 +@dots{} +@end example + +A common mistake in using the @code{print} statement is to omit the comma +between two items. This often has the effect of making the items run +together in the output, with no space. The reason for this is that +juxtaposing two string expressions in @code{awk} means to concatenate +them. For example, without the comma: + +@example +awk '@{ print $1 $2 @}' inventory-shipped +@end example + +@noindent +prints: + +@example +@group +Jan13 +Feb15 +Mar15 +@dots{} +@end group +@end example + +Neither example's output makes much sense to someone unfamiliar with the +file @file{inventory-shipped}. A heading line at the beginning would make +it clearer. Let's add some headings to our table of months (@code{$1}) and +green crates shipped (@code{$2}). We do this using the @code{BEGIN} pattern +(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}) to force the headings to be printed only once: + +@example +awk 'BEGIN @{ print "Month Crates" + print "----- ------" @} + @{ print $1, $2 @}' inventory-shipped +@end example + +@noindent +Did you already guess what happens? This program prints the following: + +@example +@group +Month Crates +----- ------ +Jan 13 +Feb 15 +Mar 15 +@dots{} +@end group +@end example + +@noindent +The headings and the table data don't line up! We can fix this by printing +some spaces between the two fields: + +@example +awk 'BEGIN @{ print "Month Crates" + print "----- ------" @} + @{ print $1, " ", $2 @}' inventory-shipped +@end example + +You can imagine that this way of lining up columns can get pretty +complicated when you have many columns to fix. Counting spaces for two +or three columns can be simple, but more than this and you can get +``lost'' quite easily. This is why the @code{printf} statement was +created (@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing}); +one of its specialties is lining up columns of data.@refill + +@node Output Separators, OFMT, Print Examples, Printing +@section Output Separators + +@cindex output field separator, @code{OFS} +@vindex OFS +@vindex ORS +@cindex output record separator, @code{ORS} +As mentioned previously, a @code{print} statement contains a list +of items, separated by commas. In the output, the items are normally +separated by single spaces. But they do not have to be spaces; a +single space is only the default. You can specify any string of +characters to use as the @dfn{output field separator} by setting the +built-in variable @code{OFS}. The initial value of this variable +is the string @w{@code{" "}}, that is, just a single space.@refill + +The output from an entire @code{print} statement is called an +@dfn{output record}. Each @code{print} statement outputs one output +record and then outputs a string called the @dfn{output record separator}. +The built-in variable @code{ORS} specifies this string. The initial +value of the variable is the string @code{"\n"} containing a newline +character; thus, normally each @code{print} statement makes a separate line. + +You can change how output fields and records are separated by assigning +new values to the variables @code{OFS} and/or @code{ORS}. The usual +place to do this is in the @code{BEGIN} rule +(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}), so +that it happens before any input is processed. You may also do this +with assignments on the command line, before the names of your input +files.@refill + +The following example prints the first and second fields of each input +record separated by a semicolon, with a blank line added after each +line:@refill + +@example +@group +awk 'BEGIN @{ OFS = ";"; ORS = "\n\n" @} + @{ print $1, $2 @}' BBS-list +@end group +@end example + +If the value of @code{ORS} does not contain a newline, all your output +will be run together on a single line, unless you output newlines some +other way. + +@node OFMT, Printf, Output Separators, Printing +@section Controlling Numeric Output with @code{print} +@vindex OFMT +When you use the @code{print} statement to print numeric values, +@code{awk} internally converts the number to a string of characters, +and prints that string. @code{awk} uses the @code{sprintf} function +to do this conversion. For now, it suffices to say that the @code{sprintf} +function accepts a @dfn{format specification} that tells it how to format +numbers (or strings), and that there are a number of different ways that +numbers can be formatted. The different format specifications are discussed +more fully in +@ref{Printf, ,Using @code{printf} Statements for Fancier Printing}.@refill + +The built-in variable @code{OFMT} contains the default format specification +that @code{print} uses with @code{sprintf} when it wants to convert a +number to a string for printing. By supplying different format specifications +as the value of @code{OFMT}, you can change how @code{print} will print +your numbers. As a brief example: + +@example +@group +awk 'BEGIN @{ OFMT = "%d" # print numbers as integers + print 17.23 @}' +@end group +@end example + +@noindent +will print @samp{17}. + +@node Printf, Redirection, OFMT, Printing +@section Using @code{printf} Statements for Fancier Printing +@cindex formatted output +@cindex output, formatted + +If you want more precise control over the output format than +@code{print} gives you, use @code{printf}. With @code{printf} you can +specify the width to use for each item, and you can specify various +stylistic choices for numbers (such as what radix to use, whether to +print an exponent, whether to print a sign, and how many digits to print +after the decimal point). You do this by specifying a string, called +the @dfn{format string}, which controls how and where to print the other +arguments. + +@menu +* Basic Printf:: Syntax of the @code{printf} statement. +* Control Letters:: Format-control letters. +* Format Modifiers:: Format-specification modifiers. +* Printf Examples:: Several examples. +@end menu + +@node Basic Printf, Control Letters, Printf, Printf +@subsection Introduction to the @code{printf} Statement + +@cindex @code{printf} statement, syntax of +The @code{printf} statement looks like this:@refill + +@example +printf @var{format}, @var{item1}, @var{item2}, @dots{} +@end example + +@noindent +The entire list of arguments may optionally be enclosed in parentheses. The +parentheses are necessary if any of the item expressions uses a +relational operator; otherwise it could be confused with a redirection +(@pxref{Redirection, ,Redirecting Output of @code{print} and @code{printf}}). +The relational operators are @samp{==}, +@samp{!=}, @samp{<}, @samp{>}, @samp{>=}, @samp{<=}, @samp{~} and +@samp{!~} (@pxref{Comparison Ops, ,Comparison Expressions}).@refill + +@cindex format string +The difference between @code{printf} and @code{print} is the argument +@var{format}. This is an expression whose value is taken as a string; it +specifies how to output each of the other arguments. It is called +the @dfn{format string}. + +The format string is the same as in the @sc{ansi} C library function +@code{printf}. Most of @var{format} is text to be output verbatim. +Scattered among this text are @dfn{format specifiers}, one per item. +Each format specifier says to output the next item at that place in the +format.@refill + +The @code{printf} statement does not automatically append a newline to its +output. It outputs only what the format specifies. So if you want +a newline, you must include one in the format. The output separator +variables @code{OFS} and @code{ORS} have no effect on @code{printf} +statements.@refill + +@node Control Letters, Format Modifiers, Basic Printf, Printf +@subsection Format-Control Letters +@cindex @code{printf}, format-control characters +@cindex format specifier + +A format specifier starts with the character @samp{%} and ends with a +@dfn{format-control letter}; it tells the @code{printf} statement how +to output one item. (If you actually want to output a @samp{%}, write +@samp{%%}.) The format-control letter specifies what kind of value to +print. The rest of the format specifier is made up of optional +@dfn{modifiers} which are parameters such as the field width to use.@refill + +Here is a list of the format-control letters: + +@table @samp +@item c +This prints a number as an ASCII character. Thus, @samp{printf "%c", +65} outputs the letter @samp{A}. The output for a string value is +the first character of the string. + +@item d +This prints a decimal integer. + +@item i +This also prints a decimal integer. + +@item e +This prints a number in scientific (exponential) notation. +For example, + +@example +printf "%4.3e", 1950 +@end example + +@noindent +prints @samp{1.950e+03}, with a total of four significant figures of +which three follow the decimal point. The @samp{4.3} are @dfn{modifiers}, +discussed below. + +@item f +This prints a number in floating point notation. + +@item g +This prints a number in either scientific notation or floating point +notation, whichever uses fewer characters. +@ignore +From: gatech!ames!elroy!cit-vax!EQL.Caltech.Edu!rankin (Pat Rankin) + +In the description of printf formats (p.43), the information for %g +is incorrect (mainly, it's too much of an oversimplification). It's +wrong in the AWK book too, and in the gawk man page. I suggested to +David Trueman before 2.13 was released that the latter be revised, so +that it matched gawk's behavior (rather than trying to change gawk to +match the docs ;-). The documented description is nice and simple, but +it doesn't match the actual underlying behavior of %g in the various C +run-time libraries that gawk relies on. The precision value for g format +is different than for f and e formats, so it's inaccurate to say 'g' is +the shorter of 'e' or 'f'. For 'g', precision represents the number of +significant digits rather than the number of decimal places, and it has +special rules about how to format numbers with range between 10E-1 and +10E-4. All in all, it's pretty messy, and I had to add that clumsy +GFMT_WORKAROUND code because the VMS run-time library doesn't conform to +the ANSI-C specifications. +@end ignore + +@item o +This prints an unsigned octal integer. + +@item s +This prints a string. + +@item x +This prints an unsigned hexadecimal integer. + +@item X +This prints an unsigned hexadecimal integer. However, for the values 10 +through 15, it uses the letters @samp{A} through @samp{F} instead of +@samp{a} through @samp{f}. + +@item % +This isn't really a format-control letter, but it does have a meaning +when used after a @samp{%}: the sequence @samp{%%} outputs one +@samp{%}. It does not consume an argument. +@end table + +@node Format Modifiers, Printf Examples, Control Letters, Printf +@subsection Modifiers for @code{printf} Formats + +@cindex @code{printf}, modifiers +@cindex modifiers (in format specifiers) +A format specification can also include @dfn{modifiers} that can control +how much of the item's value is printed and how much space it gets. The +modifiers come between the @samp{%} and the format-control letter. Here +are the possible modifiers, in the order in which they may appear: + +@table @samp +@item - +The minus sign, used before the width modifier, says to left-justify +the argument within its specified width. Normally the argument +is printed right-justified in the specified width. Thus, + +@example +printf "%-4s", "foo" +@end example + +@noindent +prints @samp{foo }. + +@item @var{width} +This is a number representing the desired width of a field. Inserting any +number between the @samp{%} sign and the format control character forces the +field to be expanded to this width. The default way to do this is to +pad with spaces on the left. For example, + +@example +printf "%4s", "foo" +@end example + +@noindent +prints @samp{ foo}. + +The value of @var{width} is a minimum width, not a maximum. If the item +value requires more than @var{width} characters, it can be as wide as +necessary. Thus, + +@example +printf "%4s", "foobar" +@end example + +@noindent +prints @samp{foobar}. + +Preceding the @var{width} with a minus sign causes the output to be +padded with spaces on the right, instead of on the left. + +@item .@var{prec} +This is a number that specifies the precision to use when printing. +This specifies the number of digits you want printed to the right of the +decimal point. For a string, it specifies the maximum number of +characters from the string that should be printed. +@end table + +The C library @code{printf}'s dynamic @var{width} and @var{prec} +capability (for example, @code{"%*.*s"}) is supported. Instead of +supplying explicit @var{width} and/or @var{prec} values in the format +string, you pass them in the argument list. For example:@refill + +@example +w = 5 +p = 3 +s = "abcdefg" +printf "<%*.*s>\n", w, p, s +@end example + +@noindent +is exactly equivalent to + +@example +s = "abcdefg" +printf "<%5.3s>\n", s +@end example + +@noindent +Both programs output @samp{@w{<@bullet{}@bullet{}abc>}}. (We have +used the bullet symbol ``@bullet{}'' to represent a space, to clearly +show you that there are two spaces in the output.)@refill + +Earlier versions of @code{awk} did not support this capability. You may +simulate it by using concatenation to build up the format string, +like so:@refill + +@example +w = 5 +p = 3 +s = "abcdefg" +printf "<%" w "." p "s>\n", s +@end example + +@noindent +This is not particularly easy to read, however. + +@node Printf Examples, , Format Modifiers, Printf +@subsection Examples of Using @code{printf} + +Here is how to use @code{printf} to make an aligned table: + +@example +awk '@{ printf "%-10s %s\n", $1, $2 @}' BBS-list +@end example + +@noindent +prints the names of bulletin boards (@code{$1}) of the file +@file{BBS-list} as a string of 10 characters, left justified. It also +prints the phone numbers (@code{$2}) afterward on the line. This +produces an aligned two-column table of names and phone numbers:@refill + +@example +@group +aardvark 555-5553 +alpo-net 555-3412 +barfly 555-7685 +bites 555-1675 +camelot 555-0542 +core 555-2912 +fooey 555-1234 +foot 555-6699 +macfoo 555-6480 +sdace 555-3430 +sabafoo 555-2127 +@end group +@end example + +Did you notice that we did not specify that the phone numbers be printed +as numbers? They had to be printed as strings because the numbers are +separated by a dash. This dash would be interpreted as a minus sign if +we had tried to print the phone numbers as numbers. This would have led +to some pretty confusing results. + +We did not specify a width for the phone numbers because they are the +last things on their lines. We don't need to put spaces after them. + +We could make our table look even nicer by adding headings to the tops +of the columns. To do this, use the @code{BEGIN} pattern +(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}) +to force the header to be printed only once, at the beginning of +the @code{awk} program:@refill + +@example +@group +awk 'BEGIN @{ print "Name Number" + print "---- ------" @} + @{ printf "%-10s %s\n", $1, $2 @}' BBS-list +@end group +@end example + +Did you notice that we mixed @code{print} and @code{printf} statements in +the above example? We could have used just @code{printf} statements to get +the same results: + +@example +@group +awk 'BEGIN @{ printf "%-10s %s\n", "Name", "Number" + printf "%-10s %s\n", "----", "------" @} + @{ printf "%-10s %s\n", $1, $2 @}' BBS-list +@end group +@end example + +@noindent +By outputting each column heading with the same format specification +used for the elements of the column, we have made sure that the headings +are aligned just like the columns. + +The fact that the same format specification is used three times can be +emphasized by storing it in a variable, like this: + +@example +awk 'BEGIN @{ format = "%-10s %s\n" + printf format, "Name", "Number" + printf format, "----", "------" @} + @{ printf format, $1, $2 @}' BBS-list +@end example + +See if you can use the @code{printf} statement to line up the headings and +table data for our @file{inventory-shipped} example covered earlier in the +section on the @code{print} statement +(@pxref{Print, ,The @code{print} Statement}).@refill + +@node Redirection, Special Files, Printf, Printing +@section Redirecting Output of @code{print} and @code{printf} + +@cindex output redirection +@cindex redirection of output +So far we have been dealing only with output that prints to the standard +output, usually your terminal. Both @code{print} and @code{printf} can +also send their output to other places. +This is called @dfn{redirection}.@refill + +A redirection appears after the @code{print} or @code{printf} statement. +Redirections in @code{awk} are written just like redirections in shell +commands, except that they are written inside the @code{awk} program. + +@menu +* File/Pipe Redirection:: Redirecting Output to Files and Pipes. +* Close Output:: How to close output files and pipes. +@end menu + +@node File/Pipe Redirection, Close Output, Redirection, Redirection +@subsection Redirecting Output to Files and Pipes + +Here are the three forms of output redirection. They are all shown for +the @code{print} statement, but they work identically for @code{printf} +also.@refill + +@table @code +@item print @var{items} > @var{output-file} +This type of redirection prints the items onto the output file +@var{output-file}. The file name @var{output-file} can be any +expression. Its value is changed to a string and then used as a +file name (@pxref{Expressions, ,Expressions as Action Statements}).@refill + +When this type of redirection is used, the @var{output-file} is erased +before the first output is written to it. Subsequent writes do not +erase @var{output-file}, but append to it. If @var{output-file} does +not exist, then it is created.@refill + +For example, here is how one @code{awk} program can write a list of +BBS names to a file @file{name-list} and a list of phone numbers to a +file @file{phone-list}. Each output file contains one name or number +per line. + +@smallexample +awk '@{ print $2 > "phone-list" + print $1 > "name-list" @}' BBS-list +@end smallexample + +@item print @var{items} >> @var{output-file} +This type of redirection prints the items onto the output file +@var{output-file}. The difference between this and the +single-@samp{>} redirection is that the old contents (if any) of +@var{output-file} are not erased. Instead, the @code{awk} output is +appended to the file. + +@cindex pipes for output +@cindex output, piping +@item print @var{items} | @var{command} +It is also possible to send output through a @dfn{pipe} instead of into a +file. This type of redirection opens a pipe to @var{command} and writes +the values of @var{items} through this pipe, to another process created +to execute @var{command}.@refill + +The redirection argument @var{command} is actually an @code{awk} +expression. Its value is converted to a string, whose contents give the +shell command to be run. + +For example, this produces two files, one unsorted list of BBS names +and one list sorted in reverse alphabetical order: + +@smallexample +awk '@{ print $1 > "names.unsorted" + print $1 | "sort -r > names.sorted" @}' BBS-list +@end smallexample + +Here the unsorted list is written with an ordinary redirection while +the sorted list is written by piping through the @code{sort} utility. + +Here is an example that uses redirection to mail a message to a mailing +list @samp{bug-system}. This might be useful when trouble is encountered +in an @code{awk} script run periodically for system maintenance. + +@smallexample +report = "mail bug-system" +print "Awk script failed:", $0 | report +print "at record number", FNR, "of", FILENAME | report +close(report) +@end smallexample + +We call the @code{close} function here because it's a good idea to close +the pipe as soon as all the intended output has been sent to it. +@xref{Close Output, ,Closing Output Files and Pipes}, for more information +on this. This example also illustrates the use of a variable to represent +a @var{file} or @var{command}: it is not necessary to always +use a string constant. Using a variable is generally a good idea, +since @code{awk} requires you to spell the string value identically +every time. +@end table + +Redirecting output using @samp{>}, @samp{>>}, or @samp{|} asks the system +to open a file or pipe only if the particular @var{file} or @var{command} +you've specified has not already been written to by your program, or if +it has been closed since it was last written to.@refill + +@node Close Output, , File/Pipe Redirection, Redirection +@subsection Closing Output Files and Pipes +@cindex closing output files and pipes +@findex close + +When a file or pipe is opened, the file name or command associated with +it is remembered by @code{awk} and subsequent writes to the same file or +command are appended to the previous writes. The file or pipe stays +open until @code{awk} exits. This is usually convenient. + +Sometimes there is a reason to close an output file or pipe earlier +than that. To do this, use the @code{close} function, as follows: + +@example +close(@var{filename}) +@end example + +@noindent +or + +@example +close(@var{command}) +@end example + +The argument @var{filename} or @var{command} can be any expression. +Its value must exactly equal the string used to open the file or pipe +to begin with---for example, if you open a pipe with this: + +@example +print $1 | "sort -r > names.sorted" +@end example + +@noindent +then you must close it with this: + +@example +close("sort -r > names.sorted") +@end example + +Here are some reasons why you might need to close an output file: + +@itemize @bullet +@item +To write a file and read it back later on in the same @code{awk} +program. Close the file when you are finished writing it; then +you can start reading it with @code{getline} +(@pxref{Getline, ,Explicit Input with @code{getline}}).@refill + +@item +To write numerous files, successively, in the same @code{awk} +program. If you don't close the files, eventually you may exceed a +system limit on the number of open files in one process. So close +each one when you are finished writing it. + +@item +To make a command finish. When you redirect output through a pipe, +the command reading the pipe normally continues to try to read input +as long as the pipe is open. Often this means the command cannot +really do its work until the pipe is closed. For example, if you +redirect output to the @code{mail} program, the message is not +actually sent until the pipe is closed. + +@item +To run the same program a second time, with the same arguments. +This is not the same thing as giving more input to the first run! + +For example, suppose you pipe output to the @code{mail} program. If you +output several lines redirected to this pipe without closing it, they make +a single message of several lines. By contrast, if you close the pipe +after each line of output, then each line makes a separate message. +@end itemize + +@iftex +@vindex ERRNO +@cindex differences: @code{gawk} and @code{awk} +@end iftex +@code{close} returns a value of zero if the close succeeded. +Otherwise, the value will be non-zero. +In this case, @code{gawk} sets the variable @code{ERRNO} to a string +describing the error that occurred. + +@node Special Files, , Redirection, Printing +@section Standard I/O Streams +@cindex standard input +@cindex standard output +@cindex standard error output +@cindex file descriptors + +Running programs conventionally have three input and output streams +already available to them for reading and writing. These are known as +the @dfn{standard input}, @dfn{standard output}, and @dfn{standard error +output}. These streams are, by default, terminal input and output, but +they are often redirected with the shell, via the @samp{<}, @samp{<<}, +@samp{>}, @samp{>>}, @samp{>&} and @samp{|} operators. Standard error +is used only for writing error messages; the reason we have two separate +streams, standard output and standard error, is so that they can be +redirected separately. + +@iftex +@cindex differences: @code{gawk} and @code{awk} +@end iftex +In other implementations of @code{awk}, the only way to write an error +message to standard error in an @code{awk} program is as follows: + +@smallexample +print "Serious error detected!\n" | "cat 1>&2" +@end smallexample + +@noindent +This works by opening a pipeline to a shell command which can access the +standard error stream which it inherits from the @code{awk} process. +This is far from elegant, and is also inefficient, since it requires a +separate process. So people writing @code{awk} programs have often +neglected to do this. Instead, they have sent the error messages to the +terminal, like this: + +@smallexample +@group +NF != 4 @{ + printf("line %d skipped: doesn't have 4 fields\n", FNR) > "/dev/tty" +@} +@end group +@end smallexample + +@noindent +This has the same effect most of the time, but not always: although the +standard error stream is usually the terminal, it can be redirected, and +when that happens, writing to the terminal is not correct. In fact, if +@code{awk} is run from a background job, it may not have a terminal at all. +Then opening @file{/dev/tty} will fail. + +@code{gawk} provides special file names for accessing the three standard +streams. When you redirect input or output in @code{gawk}, if the file name +matches one of these special names, then @code{gawk} directly uses the +stream it stands for. + +@cindex @file{/dev/stdin} +@cindex @file{/dev/stdout} +@cindex @file{/dev/stderr} +@cindex @file{/dev/fd/} +@table @file +@item /dev/stdin +The standard input (file descriptor 0). + +@item /dev/stdout +The standard output (file descriptor 1). + +@item /dev/stderr +The standard error output (file descriptor 2). + +@item /dev/fd/@var{N} +The file associated with file descriptor @var{N}. Such a file must have +been opened by the program initiating the @code{awk} execution (typically +the shell). Unless you take special pains, only descriptors 0, 1 and 2 +are available. +@end table + +The file names @file{/dev/stdin}, @file{/dev/stdout}, and @file{/dev/stderr} +are aliases for @file{/dev/fd/0}, @file{/dev/fd/1}, and @file{/dev/fd/2}, +respectively, but they are more self-explanatory. + +The proper way to write an error message in a @code{gawk} program +is to use @file{/dev/stderr}, like this: + +@smallexample +NF != 4 @{ + printf("line %d skipped: doesn't have 4 fields\n", FNR) > "/dev/stderr" +@} +@end smallexample + +@code{gawk} also provides special file names that give access to information +about the running @code{gawk} process. Each of these ``files'' provides +a single record of information. To read them more than once, you must +first close them with the @code{close} function +(@pxref{Close Input, ,Closing Input Files and Pipes}). +The filenames are: + +@cindex @file{/dev/pid} +@cindex @file{/dev/pgrpid} +@cindex @file{/dev/ppid} +@cindex @file{/dev/user} +@table @file +@item /dev/pid +Reading this file returns the process ID of the current process, +in decimal, terminated with a newline. + +@item /dev/ppid +Reading this file returns the parent process ID of the current process, +in decimal, terminated with a newline. + +@item /dev/pgrpid +Reading this file returns the process group ID of the current process, +in decimal, terminated with a newline. + +@item /dev/user +Reading this file returns a single record terminated with a newline. +The fields are separated with blanks. The fields represent the +following information: + +@table @code +@item $1 +The value of the @code{getuid} system call. + +@item $2 +The value of the @code{geteuid} system call. + +@item $3 +The value of the @code{getgid} system call. + +@item $4 +The value of the @code{getegid} system call. +@end table + +If there are any additional fields, they are the group IDs returned by +@code{getgroups} system call. +(Multiple groups may not be supported on all systems.)@refill +@end table + +These special file names may be used on the command line as data +files, as well as for I/O redirections within an @code{awk} program. +They may not be used as source files with the @samp{-f} option. + +Recognition of these special file names is disabled if @code{gawk} is in +compatibility mode (@pxref{Command Line, ,Invoking @code{awk}}). + +@quotation +@strong{Caution}: Unless your system actually has a @file{/dev/fd} directory +(or any of the other above listed special files), +the interpretation of these file names is done by @code{gawk} itself. +For example, using @samp{/dev/fd/4} for output will actually write on +file descriptor 4, and not on a new file descriptor that was @code{dup}'ed +from file descriptor 4. Most of the time this does not matter; however, it +is important to @emph{not} close any of the files related to file descriptors +0, 1, and 2. If you do close one of these files, unpredictable behavior +will result. +@end quotation + +@node One-liners, Patterns, Printing, Top +@chapter Useful ``One-liners'' + +@cindex one-liners +Useful @code{awk} programs are often short, just a line or two. Here is a +collection of useful, short programs to get you started. Some of these +programs contain constructs that haven't been covered yet. The description +of the program will give you a good idea of what is going on, but please +read the rest of the manual to become an @code{awk} expert! + +@c Per suggestions from Michal Jaegermann +@ifinfo +Since you are reading this in Info, each line of the example code is +enclosed in quotes, to represent text that you would type literally. +The examples themselves represent shell commands that use single quotes +to keep the shell from interpreting the contents of the program. +When reading the examples, focus on the text between the open and close +quotes. +@end ifinfo + +@table @code +@item awk '@{ if (NF > max) max = NF @} +@itemx @ @ @ @ @ END @{ print max @}' +This program prints the maximum number of fields on any input line. + +@item awk 'length($0) > 80' +This program prints every line longer than 80 characters. The sole +rule has a relational expression as its pattern, and has no action (so the +default action, printing the record, is used). + +@item awk 'NF > 0' +This program prints every line that has at least one field. This is an +easy way to delete blank lines from a file (or rather, to create a new +file similar to the old file but from which the blank lines have been +deleted). + +@item awk '@{ if (NF > 0) print @}' +This program also prints every line that has at least one field. Here we +allow the rule to match every line, then decide in the action whether +to print. + +@item awk@ 'BEGIN@ @{@ for (i = 1; i <= 7; i++) +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ print int(101 * rand()) @}' +This program prints 7 random numbers from 0 to 100, inclusive. + +@item ls -l @var{files} | awk '@{ x += $4 @} ; END @{ print "total bytes: " x @}' +This program prints the total number of bytes used by @var{files}. + +@item expand@ @var{file}@ |@ awk@ '@{ if (x < length()) x = length() @} +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ END @{ print "maximum line length is " x @}' +This program prints the maximum line length of @var{file}. The input +is piped through the @code{expand} program to change tabs into spaces, +so the widths compared are actually the right-margin columns. + +@item awk 'BEGIN @{ FS = ":" @} +@itemx @ @ @ @ @ @{ print $1 | "sort" @}' /etc/passwd +This program prints a sorted list of the login names of all users. + +@item awk '@{ nlines++ @} +@itemx @ @ @ @ @ END@ @{ print nlines @}' +This programs counts lines in a file. + +@item awk 'END @{ print NR @}' +This program also counts lines in a file, but lets @code{awk} do the work. + +@item awk '@{ print NR, $0 @}' +This program adds line numbers to all its input files, +similar to @samp{cat -n}. +@end table + +@node Patterns, Actions, One-liners, Top +@chapter Patterns +@cindex pattern, definition of + +Patterns in @code{awk} control the execution of rules: a rule is +executed when its pattern matches the current input record. This +chapter tells all about how to write patterns. + +@menu +* Kinds of Patterns:: A list of all kinds of patterns. + The following subsections describe + them in detail. +* Regexp:: Regular expressions such as @samp{/foo/}. +* Comparison Patterns:: Comparison expressions such as @code{$1 > 10}. +* Boolean Patterns:: Combining comparison expressions. +* Expression Patterns:: Any expression can be used as a pattern. +* Ranges:: Pairs of patterns specify record ranges. +* BEGIN/END:: Specifying initialization and cleanup rules. +* Empty:: The empty pattern, which matches every record. +@end menu + +@node Kinds of Patterns, Regexp, Patterns, Patterns +@section Kinds of Patterns +@cindex patterns, types of + +Here is a summary of the types of patterns supported in @code{awk}. +@c At the next rewrite, check to see that this order matches the +@c order in the text. It might not matter to a reader, but it's good +@c style. Also, it might be nice to mention all the topics of sections +@c that follow in this list; that way people can scan and know when to +@c expect a specific topic. Specifically please also make an entry +@c for Boolean operators as patterns in the right place. --mew + +@table @code +@item /@var{regular expression}/ +A regular expression as a pattern. It matches when the text of the +input record fits the regular expression. +(@xref{Regexp, ,Regular Expressions as Patterns}.)@refill + +@item @var{expression} +A single expression. It matches when its value, converted to a number, +is nonzero (if a number) or nonnull (if a string). +(@xref{Expression Patterns, ,Expressions as Patterns}.)@refill + +@item @var{pat1}, @var{pat2} +A pair of patterns separated by a comma, specifying a range of records. +(@xref{Ranges, ,Specifying Record Ranges with Patterns}.) + +@item BEGIN +@itemx END +Special patterns to supply start-up or clean-up information to +@code{awk}. (@xref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}.) + +@item @var{null} +The empty pattern matches every input record. +(@xref{Empty, ,The Empty Pattern}.)@refill +@end table + + +@node Regexp, Comparison Patterns, Kinds of Patterns, Patterns +@section Regular Expressions as Patterns +@cindex pattern, regular expressions +@cindex regexp +@cindex regular expressions as patterns + +A @dfn{regular expression}, or @dfn{regexp}, is a way of describing a +class of strings. A regular expression enclosed in slashes (@samp{/}) +is an @code{awk} pattern that matches every input record whose text +belongs to that class. + +The simplest regular expression is a sequence of letters, numbers, or +both. Such a regexp matches any string that contains that sequence. +Thus, the regexp @samp{foo} matches any string containing @samp{foo}. +Therefore, the pattern @code{/foo/} matches any input record containing +@samp{foo}. Other kinds of regexps let you specify more complicated +classes of strings. + +@menu +* Regexp Usage:: How to Use Regular Expressions +* Regexp Operators:: Regular Expression Operators +* Case-sensitivity:: How to do case-insensitive matching. +@end menu + +@node Regexp Usage, Regexp Operators, Regexp, Regexp +@subsection How to Use Regular Expressions + +A regular expression can be used as a pattern by enclosing it in +slashes. Then the regular expression is matched against the +entire text of each record. (Normally, it only needs +to match some part of the text in order to succeed.) For example, this +prints the second field of each record that contains @samp{foo} anywhere: + +@example +awk '/foo/ @{ print $2 @}' BBS-list +@end example + +@cindex regular expression matching operators +@cindex string-matching operators +@cindex operators, string-matching +@cindex operators, regexp matching +@cindex regexp search operators +Regular expressions can also be used in comparison expressions. Then +you can specify the string to match against; it need not be the entire +current input record. These comparison expressions can be used as +patterns or in @code{if}, @code{while}, @code{for}, and @code{do} statements. + +@table @code +@item @var{exp} ~ /@var{regexp}/ +This is true if the expression @var{exp} (taken as a character string) +is matched by @var{regexp}. The following example matches, or selects, +all input records with the upper-case letter @samp{J} somewhere in the +first field:@refill + +@example +awk '$1 ~ /J/' inventory-shipped +@end example + +So does this: + +@example +awk '@{ if ($1 ~ /J/) print @}' inventory-shipped +@end example + +@item @var{exp} !~ /@var{regexp}/ +This is true if the expression @var{exp} (taken as a character string) +is @emph{not} matched by @var{regexp}. The following example matches, +or selects, all input records whose first field @emph{does not} contain +the upper-case letter @samp{J}:@refill + +@example +awk '$1 !~ /J/' inventory-shipped +@end example +@end table + +@cindex computed regular expressions +@cindex regular expressions, computed +@cindex dynamic regular expressions +The right hand side of a @samp{~} or @samp{!~} operator need not be a +constant regexp (i.e., a string of characters between slashes). It may +be any expression. The expression is evaluated, and converted if +necessary to a string; the contents of the string are used as the +regexp. A regexp that is computed in this way is called a @dfn{dynamic +regexp}. For example: + +@example +identifier_regexp = "[A-Za-z_][A-Za-z_0-9]+" +$0 ~ identifier_regexp +@end example + +@noindent +sets @code{identifier_regexp} to a regexp that describes @code{awk} +variable names, and tests if the input record matches this regexp. + +@node Regexp Operators, Case-sensitivity, Regexp Usage, Regexp +@subsection Regular Expression Operators +@cindex metacharacters +@cindex regular expression metacharacters + +You can combine regular expressions with the following characters, +called @dfn{regular expression operators}, or @dfn{metacharacters}, to +increase the power and versatility of regular expressions. + +Here is a table of metacharacters. All characters not listed in the +table stand for themselves. + +@table @code +@item ^ +This matches the beginning of the string or the beginning of a line +within the string. For example: + +@example +^@@chapter +@end example + +@noindent +matches the @samp{@@chapter} at the beginning of a string, and can be used +to identify chapter beginnings in Texinfo source files. + +@item $ +This is similar to @samp{^}, but it matches only at the end of a string +or the end of a line within the string. For example: + +@example +p$ +@end example + +@noindent +matches a record that ends with a @samp{p}. + +@item . +This matches any single character except a newline. For example: + +@example +.P +@end example + +@noindent +matches any single character followed by a @samp{P} in a string. Using +concatenation we can make regular expressions like @samp{U.A}, which +matches any three-character sequence that begins with @samp{U} and ends +with @samp{A}. + +@item [@dots{}] +This is called a @dfn{character set}. It matches any one of the +characters that are enclosed in the square brackets. For example: + +@example +[MVX] +@end example + +@noindent +matches any one of the characters @samp{M}, @samp{V}, or @samp{X} in a +string.@refill + +Ranges of characters are indicated by using a hyphen between the beginning +and ending characters, and enclosing the whole thing in brackets. For +example:@refill + +@example +[0-9] +@end example + +@noindent +matches any digit. + +To include the character @samp{\}, @samp{]}, @samp{-} or @samp{^} in a +character set, put a @samp{\} in front of it. For example: + +@example +[d\]] +@end example + +@noindent +matches either @samp{d}, or @samp{]}.@refill + +This treatment of @samp{\} is compatible with other @code{awk} +implementations, and is also mandated by the @sc{posix} Command Language +and Utilities standard. The regular expressions in @code{awk} are a superset +of the @sc{posix} specification for Extended Regular Expressions (EREs). +@sc{posix} EREs are based on the regular expressions accepted by the +traditional @code{egrep} utility. + +In @code{egrep} syntax, backslash is not syntactically special within +square brackets. This means that special tricks have to be used to +represent the characters @samp{]}, @samp{-} and @samp{^} as members of a +character set. + +In @code{egrep} syntax, to match @samp{-}, write it as @samp{---}, +which is a range containing only @w{@samp{-}.} You may also give @samp{-} +as the first or last character in the set. To match @samp{^}, put it +anywhere except as the first character of a set. To match a @samp{]}, +make it the first character in the set. For example:@refill + +@example +[]d^] +@end example + +@noindent +matches either @samp{]}, @samp{d} or @samp{^}.@refill + +@item [^ @dots{}] +This is a @dfn{complemented character set}. The first character after +the @samp{[} @emph{must} be a @samp{^}. It matches any characters +@emph{except} those in the square brackets (or newline). For example: + +@example +[^0-9] +@end example + +@noindent +matches any character that is not a digit. + +@item | +This is the @dfn{alternation operator} and it is used to specify +alternatives. For example: + +@example +^P|[0-9] +@end example + +@noindent +matches any string that matches either @samp{^P} or @samp{[0-9]}. This +means it matches any string that contains a digit or starts with @samp{P}. + +The alternation applies to the largest possible regexps on either side. +@item (@dots{}) +Parentheses are used for grouping in regular expressions as in +arithmetic. They can be used to concatenate regular expressions +containing the alternation operator, @samp{|}. + +@item * +This symbol means that the preceding regular expression is to be +repeated as many times as possible to find a match. For example: + +@example +ph* +@end example + +@noindent +applies the @samp{*} symbol to the preceding @samp{h} and looks for matches +to one @samp{p} followed by any number of @samp{h}s. This will also match +just @samp{p} if no @samp{h}s are present. + +The @samp{*} repeats the @emph{smallest} possible preceding expression. +(Use parentheses if you wish to repeat a larger expression.) It finds +as many repetitions as possible. For example: + +@example +awk '/\(c[ad][ad]*r x\)/ @{ print @}' sample +@end example + +@noindent +prints every record in the input containing a string of the form +@samp{(car x)}, @samp{(cdr x)}, @samp{(cadr x)}, and so on.@refill + +@item + +This symbol is similar to @samp{*}, but the preceding expression must be +matched at least once. This means that: + +@example +wh+y +@end example + +@noindent +would match @samp{why} and @samp{whhy} but not @samp{wy}, whereas +@samp{wh*y} would match all three of these strings. This is a simpler +way of writing the last @samp{*} example: + +@example +awk '/\(c[ad]+r x\)/ @{ print @}' sample +@end example + +@item ? +This symbol is similar to @samp{*}, but the preceding expression can be +matched once or not at all. For example: + +@example +fe?d +@end example + +@noindent +will match @samp{fed} and @samp{fd}, but nothing else.@refill + +@item \ +This is used to suppress the special meaning of a character when +matching. For example: + +@example +\$ +@end example + +@noindent +matches the character @samp{$}. + +The escape sequences used for string constants +(@pxref{Constants, ,Constant Expressions}) are +valid in regular expressions as well; they are also introduced by a +@samp{\}.@refill +@end table + +In regular expressions, the @samp{*}, @samp{+}, and @samp{?} operators have +the highest precedence, followed by concatenation, and finally by @samp{|}. +As in arithmetic, parentheses can change how operators are grouped.@refill + +@node Case-sensitivity, , Regexp Operators, Regexp +@subsection Case-sensitivity in Matching + +Case is normally significant in regular expressions, both when matching +ordinary characters (i.e., not metacharacters), and inside character +sets. Thus a @samp{w} in a regular expression matches only a lower case +@samp{w} and not an upper case @samp{W}. + +The simplest way to do a case-independent match is to use a character +set: @samp{[Ww]}. However, this can be cumbersome if you need to use it +often; and it can make the regular expressions harder for humans to +read. There are two other alternatives that you might prefer. + +One way to do a case-insensitive match at a particular point in the +program is to convert the data to a single case, using the +@code{tolower} or @code{toupper} built-in string functions (which we +haven't discussed yet; +@pxref{String Functions, ,Built-in Functions for String Manipulation}). +For example:@refill + +@example +tolower($1) ~ /foo/ @{ @dots{} @} +@end example + +@noindent +converts the first field to lower case before matching against it. + +Another method is to set the variable @code{IGNORECASE} to a nonzero +value (@pxref{Built-in Variables}). When @code{IGNORECASE} is not zero, +@emph{all} regexp operations ignore case. Changing the value of +@code{IGNORECASE} dynamically controls the case sensitivity of your +program as it runs. Case is significant by default because +@code{IGNORECASE} (like most variables) is initialized to zero. + +@example +x = "aB" +if (x ~ /ab/) @dots{} # this test will fail + +IGNORECASE = 1 +if (x ~ /ab/) @dots{} # now it will succeed +@end example + +In general, you cannot use @code{IGNORECASE} to make certain rules +case-insensitive and other rules case-sensitive, because there is no way +to set @code{IGNORECASE} just for the pattern of a particular rule. To +do this, you must use character sets or @code{tolower}. However, one +thing you can do only with @code{IGNORECASE} is turn case-sensitivity on +or off dynamically for all the rules at once.@refill + +@code{IGNORECASE} can be set on the command line, or in a @code{BEGIN} +rule. Setting @code{IGNORECASE} from the command line is a way to make +a program case-insensitive without having to edit it. + +The value of @code{IGNORECASE} has no effect if @code{gawk} is in +compatibility mode (@pxref{Command Line, ,Invoking @code{awk}}). +Case is always significant in compatibility mode.@refill + +@node Comparison Patterns, Boolean Patterns, Regexp, Patterns +@section Comparison Expressions as Patterns +@cindex comparison expressions as patterns +@cindex pattern, comparison expressions +@cindex relational operators +@cindex operators, relational + +@dfn{Comparison patterns} test relationships such as equality between +two strings or numbers. They are a special case of expression patterns +(@pxref{Expression Patterns, ,Expressions as Patterns}). They are written +with @dfn{relational operators}, which are a superset of those in C. +Here is a table of them:@refill + +@table @code +@item @var{x} < @var{y} +True if @var{x} is less than @var{y}. + +@item @var{x} <= @var{y} +True if @var{x} is less than or equal to @var{y}. + +@item @var{x} > @var{y} +True if @var{x} is greater than @var{y}. + +@item @var{x} >= @var{y} +True if @var{x} is greater than or equal to @var{y}. + +@item @var{x} == @var{y} +True if @var{x} is equal to @var{y}. + +@item @var{x} != @var{y} +True if @var{x} is not equal to @var{y}. + +@item @var{x} ~ @var{y} +True if @var{x} matches the regular expression described by @var{y}. + +@item @var{x} !~ @var{y} +True if @var{x} does not match the regular expression described by @var{y}. +@end table + +The operands of a relational operator are compared as numbers if they +are both numbers. Otherwise they are converted to, and compared as, +strings (@pxref{Conversion, ,Conversion of Strings and Numbers}, +for the detailed rules). Strings are compared by comparing the first +character of each, then the second character of each, +and so on, until there is a difference. If the two strings are equal until +the shorter one runs out, the shorter one is considered to be less than the +longer one. Thus, @code{"10"} is less than @code{"9"}, and @code{"abc"} +is less than @code{"abcd"}.@refill + +The left operand of the @samp{~} and @samp{!~} operators is a string. +The right operand is either a constant regular expression enclosed in +slashes (@code{/@var{regexp}/}), or any expression, whose string value +is used as a dynamic regular expression +(@pxref{Regexp Usage, ,How to Use Regular Expressions}).@refill + +The following example prints the second field of each input record +whose first field is precisely @samp{foo}. + +@example +awk '$1 == "foo" @{ print $2 @}' BBS-list +@end example + +@noindent +Contrast this with the following regular expression match, which would +accept any record with a first field that contains @samp{foo}: + +@example +awk '$1 ~ "foo" @{ print $2 @}' BBS-list +@end example + +@noindent +or, equivalently, this one: + +@example +awk '$1 ~ /foo/ @{ print $2 @}' BBS-list +@end example + +@node Boolean Patterns, Expression Patterns, Comparison Patterns, Patterns +@section Boolean Operators and Patterns +@cindex patterns, boolean +@cindex boolean patterns + +A @dfn{boolean pattern} is an expression which combines other patterns +using the @dfn{boolean operators} ``or'' (@samp{||}), ``and'' +(@samp{&&}), and ``not'' (@samp{!}). Whether the boolean pattern +matches an input record depends on whether its subpatterns match. + +For example, the following command prints all records in the input file +@file{BBS-list} that contain both @samp{2400} and @samp{foo}.@refill + +@example +awk '/2400/ && /foo/' BBS-list +@end example + +The following command prints all records in the input file +@file{BBS-list} that contain @emph{either} @samp{2400} or @samp{foo}, or +both.@refill + +@example +awk '/2400/ || /foo/' BBS-list +@end example + +The following command prints all records in the input file +@file{BBS-list} that do @emph{not} contain the string @samp{foo}. + +@example +awk '! /foo/' BBS-list +@end example + +Note that boolean patterns are a special case of expression patterns +(@pxref{Expression Patterns, ,Expressions as Patterns}); they are +expressions that use the boolean operators. +@xref{Boolean Ops, ,Boolean Expressions}, for complete information +on the boolean operators.@refill + +The subpatterns of a boolean pattern can be constant regular +expressions, comparisons, or any other @code{awk} expressions. Range +patterns are not expressions, so they cannot appear inside boolean +patterns. Likewise, the special patterns @code{BEGIN} and @code{END}, +which never match any input record, are not expressions and cannot +appear inside boolean patterns. + +@node Expression Patterns, Ranges, Boolean Patterns, Patterns +@section Expressions as Patterns + +Any @code{awk} expression is also valid as an @code{awk} pattern. +Then the pattern ``matches'' if the expression's value is nonzero (if a +number) or nonnull (if a string). + +The expression is reevaluated each time the rule is tested against a new +input record. If the expression uses fields such as @code{$1}, the +value depends directly on the new input record's text; otherwise, it +depends only on what has happened so far in the execution of the +@code{awk} program, but that may still be useful. + +Comparison patterns are actually a special case of this. For +example, the expression @code{$5 == "foo"} has the value 1 when the +value of @code{$5} equals @code{"foo"}, and 0 otherwise; therefore, this +expression as a pattern matches when the two values are equal. + +Boolean patterns are also special cases of expression patterns. + +A constant regexp as a pattern is also a special case of an expression +pattern. @code{/foo/} as an expression has the value 1 if @samp{foo} +appears in the current input record; thus, as a pattern, @code{/foo/} +matches any record containing @samp{foo}. + +Other implementations of @code{awk} that are not yet @sc{posix} compliant +are less general than @code{gawk}: they allow comparison expressions, and +boolean combinations thereof (optionally with parentheses), but not +necessarily other kinds of expressions. + +@node Ranges, BEGIN/END, Expression Patterns, Patterns +@section Specifying Record Ranges with Patterns + +@cindex range pattern +@cindex patterns, range +A @dfn{range pattern} is made of two patterns separated by a comma, of +the form @code{@var{begpat}, @var{endpat}}. It matches ranges of +consecutive input records. The first pattern @var{begpat} controls +where the range begins, and the second one @var{endpat} controls where +it ends. For example,@refill + +@example +awk '$1 == "on", $1 == "off"' +@end example + +@noindent +prints every record between @samp{on}/@samp{off} pairs, inclusive. + +A range pattern starts out by matching @var{begpat} +against every input record; when a record matches @var{begpat}, the +range pattern becomes @dfn{turned on}. The range pattern matches this +record. As long as it stays turned on, it automatically matches every +input record read. It also matches @var{endpat} against +every input record; when that succeeds, the range pattern is turned +off again for the following record. Now it goes back to checking +@var{begpat} against each record. + +The record that turns on the range pattern and the one that turns it +off both match the range pattern. If you don't want to operate on +these records, you can write @code{if} statements in the rule's action +to distinguish them. + +It is possible for a pattern to be turned both on and off by the same +record, if both conditions are satisfied by that record. Then the action is +executed for just that record. + +@node BEGIN/END, Empty, Ranges, Patterns +@section @code{BEGIN} and @code{END} Special Patterns + +@cindex @code{BEGIN} special pattern +@cindex patterns, @code{BEGIN} +@cindex @code{END} special pattern +@cindex patterns, @code{END} +@code{BEGIN} and @code{END} are special patterns. They are not used to +match input records. Rather, they are used for supplying start-up or +clean-up information to your @code{awk} script. A @code{BEGIN} rule is +executed, once, before the first input record has been read. An @code{END} +rule is executed, once, after all the input has been read. For +example:@refill + +@example +awk 'BEGIN @{ print "Analysis of `foo'" @} + /foo/ @{ ++foobar @} + END @{ print "`foo' appears " foobar " times." @}' BBS-list +@end example + +This program finds the number of records in the input file @file{BBS-list} +that contain the string @samp{foo}. The @code{BEGIN} rule prints a title +for the report. There is no need to use the @code{BEGIN} rule to +initialize the counter @code{foobar} to zero, as @code{awk} does this +for us automatically (@pxref{Variables}). + +The second rule increments the variable @code{foobar} every time a +record containing the pattern @samp{foo} is read. The @code{END} rule +prints the value of @code{foobar} at the end of the run.@refill + +The special patterns @code{BEGIN} and @code{END} cannot be used in ranges +or with boolean operators (indeed, they cannot be used with any operators). + +An @code{awk} program may have multiple @code{BEGIN} and/or @code{END} +rules. They are executed in the order they appear, all the @code{BEGIN} +rules at start-up and all the @code{END} rules at termination. + +Multiple @code{BEGIN} and @code{END} sections are useful for writing +library functions, since each library can have its own @code{BEGIN} or +@code{END} rule to do its own initialization and/or cleanup. Note that +the order in which library functions are named on the command line +controls the order in which their @code{BEGIN} and @code{END} rules are +executed. Therefore you have to be careful to write such rules in +library files so that the order in which they are executed doesn't matter. +@xref{Command Line, ,Invoking @code{awk}}, for more information on +using library functions. + +If an @code{awk} program only has a @code{BEGIN} rule, and no other +rules, then the program exits after the @code{BEGIN} rule has been run. +(Older versions of @code{awk} used to keep reading and ignoring input +until end of file was seen.) However, if an @code{END} rule exists as +well, then the input will be read, even if there are no other rules in +the program. This is necessary in case the @code{END} rule checks the +@code{NR} variable. + +@code{BEGIN} and @code{END} rules must have actions; there is no default +action for these rules since there is no current record when they run. + +@node Empty, , BEGIN/END, Patterns +@comment node-name, next, previous, up +@section The Empty Pattern + +@cindex empty pattern +@cindex pattern, empty +An empty pattern is considered to match @emph{every} input record. For +example, the program:@refill + +@example +awk '@{ print $1 @}' BBS-list +@end example + +@noindent +prints the first field of every record. + +@node Actions, Expressions, Patterns, Top +@chapter Overview of Actions +@cindex action, definition of +@cindex curly braces +@cindex action, curly braces +@cindex action, separating statements + +An @code{awk} program or script consists of a series of +rules and function definitions, interspersed. (Functions are +described later. @xref{User-defined, ,User-defined Functions}.) + +A rule contains a pattern and an action, either of which may be +omitted. The purpose of the @dfn{action} is to tell @code{awk} what to do +once a match for the pattern is found. Thus, the entire program +looks somewhat like this: + +@example +@r{[}@var{pattern}@r{]} @r{[}@{ @var{action} @}@r{]} +@r{[}@var{pattern}@r{]} @r{[}@{ @var{action} @}@r{]} +@dots{} +function @var{name} (@var{args}) @{ @dots{} @} +@dots{} +@end example + +An action consists of one or more @code{awk} @dfn{statements}, enclosed +in curly braces (@samp{@{} and @samp{@}}). Each statement specifies one +thing to be done. The statements are separated by newlines or +semicolons. + +The curly braces around an action must be used even if the action +contains only one statement, or even if it contains no statements at +all. However, if you omit the action entirely, omit the curly braces as +well. (An omitted action is equivalent to @samp{@{ print $0 @}}.) + +Here are the kinds of statements supported in @code{awk}: + +@itemize @bullet +@item +Expressions, which can call functions or assign values to variables +(@pxref{Expressions, ,Expressions as Action Statements}). Executing +this kind of statement simply computes the value of the expression and +then ignores it. This is useful when the expression has side effects +(@pxref{Assignment Ops, ,Assignment Expressions}).@refill + +@item +Control statements, which specify the control flow of @code{awk} +programs. The @code{awk} language gives you C-like constructs +(@code{if}, @code{for}, @code{while}, and so on) as well as a few +special ones (@pxref{Statements, ,Control Statements in Actions}).@refill + +@item +Compound statements, which consist of one or more statements enclosed in +curly braces. A compound statement is used in order to put several +statements together in the body of an @code{if}, @code{while}, @code{do} +or @code{for} statement. + +@item +Input control, using the @code{getline} command +(@pxref{Getline, ,Explicit Input with @code{getline}}), and the @code{next} +statement (@pxref{Next Statement, ,The @code{next} Statement}). + +@item +Output statements, @code{print} and @code{printf}. +@xref{Printing, ,Printing Output}.@refill + +@item +Deletion statements, for deleting array elements. +@xref{Delete, ,The @code{delete} Statement}.@refill +@end itemize + +@iftex +The next two chapters cover in detail expressions and control +statements, respectively. We go on to treat arrays and built-in +functions, both of which are used in expressions. Then we proceed +to discuss how to define your own functions. +@end iftex + +@node Expressions, Statements, Actions, Top +@chapter Expressions as Action Statements +@cindex expression + +Expressions are the basic building block of @code{awk} actions. An +expression evaluates to a value, which you can print, test, store in a +variable or pass to a function. But beyond that, an expression can assign a new value to a variable +or a field, with an assignment operator. + +An expression can serve as a statement on its own. Most other kinds of +statements contain one or more expressions which specify data to be +operated on. As in other languages, expressions in @code{awk} include +variables, array references, constants, and function calls, as well as +combinations of these with various operators. + +@menu +* Constants:: String, numeric, and regexp constants. +* Variables:: Variables give names to values for later use. +* Arithmetic Ops:: Arithmetic operations (@samp{+}, @samp{-}, etc.) +* Concatenation:: Concatenating strings. +* Comparison Ops:: Comparison of numbers and strings + with @samp{<}, etc. +* Boolean Ops:: Combining comparison expressions + using boolean operators + @samp{||} (``or''), @samp{&&} (``and'') and @samp{!} (``not''). + +* Assignment Ops:: Changing the value of a variable or a field. +* Increment Ops:: Incrementing the numeric value of a variable. + +* Conversion:: The conversion of strings to numbers + and vice versa. +* Values:: The whole truth about numbers and strings. +* Conditional Exp:: Conditional expressions select + between two subexpressions under control + of a third subexpression. +* Function Calls:: A function call is an expression. +* Precedence:: How various operators nest. +@end menu + +@node Constants, Variables, Expressions, Expressions +@section Constant Expressions +@cindex constants, types of +@cindex string constants + +The simplest type of expression is the @dfn{constant}, which always has +the same value. There are three types of constants: numeric constants, +string constants, and regular expression constants. + +@cindex numeric constant +@cindex numeric value +A @dfn{numeric constant} stands for a number. This number can be an +integer, a decimal fraction, or a number in scientific (exponential) +notation. Note that all numeric values are represented within +@code{awk} in double-precision floating point. Here are some examples +of numeric constants, which all have the same value: + +@example +105 +1.05e+2 +1050e-1 +@end example + +A string constant consists of a sequence of characters enclosed in +double-quote marks. For example: + +@example +"parrot" +@end example + +@noindent +@iftex +@cindex differences between @code{gawk} and @code{awk} +@end iftex +represents the string whose contents are @samp{parrot}. Strings in +@code{gawk} can be of any length and they can contain all the possible +8-bit ASCII characters including ASCII NUL. Other @code{awk} +implementations may have difficulty with some character codes.@refill + +@cindex escape sequence notation +Some characters cannot be included literally in a string constant. You +represent them instead with @dfn{escape sequences}, which are character +sequences beginning with a backslash (@samp{\}). + +One use of an escape sequence is to include a double-quote character in +a string constant. Since a plain double-quote would end the string, you +must use @samp{\"} to represent a single double-quote character as a +part of the string. +The +backslash character itself is another character that cannot be +included normally; you write @samp{\\} to put one backslash in the +string. Thus, the string whose contents are the two characters +@samp{"\} must be written @code{"\"\\"}. + +Another use of backslash is to represent unprintable characters +such as newline. While there is nothing to stop you from writing most +of these characters directly in a string constant, they may look ugly. + +Here is a table of all the escape sequences used in @code{awk}: + +@table @code +@item \\ +Represents a literal backslash, @samp{\}. + +@item \a +Represents the ``alert'' character, control-g, ASCII code 7. + +@item \b +Represents a backspace, control-h, ASCII code 8. + +@item \f +Represents a formfeed, control-l, ASCII code 12. + +@item \n +Represents a newline, control-j, ASCII code 10. + +@item \r +Represents a carriage return, control-m, ASCII code 13. + +@item \t +Represents a horizontal tab, control-i, ASCII code 9. + +@item \v +Represents a vertical tab, control-k, ASCII code 11. + +@item \@var{nnn} +Represents the octal value @var{nnn}, where @var{nnn} are one to three +digits between 0 and 7. For example, the code for the ASCII ESC +(escape) character is @samp{\033}.@refill + +@item \x@var{hh}@dots{} +Represents the hexadecimal value @var{hh}, where @var{hh} are hexadecimal +digits (@samp{0} through @samp{9} and either @samp{A} through @samp{F} or +@samp{a} through @samp{f}). Like the same construct in @sc{ansi} C, the escape +sequence continues until the first non-hexadecimal digit is seen. However, +using more than two hexadecimal digits produces undefined results. (The +@samp{\x} escape sequence is not allowed in @sc{posix} @code{awk}.)@refill +@end table + +A @dfn{constant regexp} is a regular expression description enclosed in +slashes, such as @code{/^beginning and end$/}. Most regexps used in +@code{awk} programs are constant, but the @samp{~} and @samp{!~} +operators can also match computed or ``dynamic'' regexps +(@pxref{Regexp Usage, ,How to Use Regular Expressions}).@refill + +Constant regexps may be used like simple expressions. When a +constant regexp is not on the right hand side of the @samp{~} or +@samp{!~} operators, it has the same meaning as if it appeared +in a pattern, i.e. @samp{($0 ~ /foo/)} +(@pxref{Expression Patterns, ,Expressions as Patterns}). +This means that the two code segments,@refill + +@example +if ($0 ~ /barfly/ || $0 ~ /camelot/) + print "found" +@end example + +@noindent +and + +@example +if (/barfly/ || /camelot/) + print "found" +@end example + +@noindent +are exactly equivalent. One rather bizarre consequence of this rule is +that the following boolean expression is legal, but does not do what the user +intended:@refill + +@example +if (/foo/ ~ $1) print "found foo" +@end example + +This code is ``obviously'' testing @code{$1} for a match against the regexp +@code{/foo/}. But in fact, the expression @code{(/foo/ ~ $1)} actually means +@code{(($0 ~ /foo/) ~ $1)}. In other words, first match the input record +against the regexp @code{/foo/}. The result will be either a 0 or a 1, +depending upon the success or failure of the match. Then match that result +against the first field in the record.@refill + +Since it is unlikely that you would ever really wish to make this kind of +test, @code{gawk} will issue a warning when it sees this construct in +a program.@refill + +Another consequence of this rule is that the assignment statement + +@example +matches = /foo/ +@end example + +@noindent +will assign either 0 or 1 to the variable @code{matches}, depending +upon the contents of the current input record. + +Constant regular expressions are also used as the first argument for +the @code{sub} and @code{gsub} functions +(@pxref{String Functions, ,Built-in Functions for String Manipulation}).@refill + +This feature of the language was never well documented until the +@sc{posix} specification. + +You may be wondering, when is + +@example +$1 ~ /foo/ @{ @dots{} @} +@end example + +@noindent +preferable to + +@example +$1 ~ "foo" @{ @dots{} @} +@end example + +Since the right-hand sides of both @samp{~} operators are constants, +it is more efficient to use the @samp{/foo/} form: @code{awk} can note +that you have supplied a regexp and store it internally in a form that +makes pattern matching more efficient. In the second form, @code{awk} +must first convert the string into this internal form, and then perform +the pattern matching. The first form is also better style; it shows +clearly that you intend a regexp match. + +@node Variables, Arithmetic Ops, Constants, Expressions +@section Variables +@cindex variables, user-defined +@cindex user-defined variables +@c there should be more than one subsection, ideally. Not a big deal. +@c But usually there are supposed to be at least two. One way to get +@c around this is to write the info in the subsection as the info in the +@c section itself and not have any subsections.. --mew + +Variables let you give names to values and refer to them later. You have +already seen variables in many of the examples. The name of a variable +must be a sequence of letters, digits and underscores, but it may not begin +with a digit. Case is significant in variable names; @code{a} and @code{A} +are distinct variables. + +A variable name is a valid expression by itself; it represents the +variable's current value. Variables are given new values with +@dfn{assignment operators} and @dfn{increment operators}. +@xref{Assignment Ops, ,Assignment Expressions}. + +A few variables have special built-in meanings, such as @code{FS}, the +field separator, and @code{NF}, the number of fields in the current +input record. @xref{Built-in Variables}, for a list of them. These +built-in variables can be used and assigned just like all other +variables, but their values are also used or changed automatically by +@code{awk}. Each built-in variable's name is made entirely of upper case +letters. + +Variables in @code{awk} can be assigned either numeric or string +values. By default, variables are initialized to the null string, which +is effectively zero if converted to a number. There is no need to +``initialize'' each variable explicitly in @code{awk}, the way you would in C or most other traditional languages. + +@menu +* Assignment Options:: Setting variables on the command line + and a summary of command line syntax. + This is an advanced method of input. +@end menu + +@node Assignment Options, , Variables, Variables +@subsection Assigning Variables on the Command Line + +You can set any @code{awk} variable by including a @dfn{variable assignment} +among the arguments on the command line when you invoke @code{awk} +(@pxref{Command Line, ,Invoking @code{awk}}). Such an assignment has +this form:@refill + +@example +@var{variable}=@var{text} +@end example + +@noindent +With it, you can set a variable either at the beginning of the +@code{awk} run or in between input files. + +If you precede the assignment with the @samp{-v} option, like this: + +@example +-v @var{variable}=@var{text} +@end example + +@noindent +then the variable is set at the very beginning, before even the +@code{BEGIN} rules are run. The @samp{-v} option and its assignment +must precede all the file name arguments, as well as the program text. + +Otherwise, the variable assignment is performed at a time determined by +its position among the input file arguments: after the processing of the +preceding input file argument. For example: + +@example +awk '@{ print $n @}' n=4 inventory-shipped n=2 BBS-list +@end example + +@noindent +prints the value of field number @code{n} for all input records. Before +the first file is read, the command line sets the variable @code{n} +equal to 4. This causes the fourth field to be printed in lines from +the file @file{inventory-shipped}. After the first file has finished, +but before the second file is started, @code{n} is set to 2, so that the +second field is printed in lines from @file{BBS-list}. + +Command line arguments are made available for explicit examination by +the @code{awk} program in an array named @code{ARGV} +(@pxref{Built-in Variables}).@refill + +@code{awk} processes the values of command line assignments for escape +sequences (@pxref{Constants, ,Constant Expressions}). + +@node Arithmetic Ops, Concatenation, Variables, Expressions +@section Arithmetic Operators +@cindex arithmetic operators +@cindex operators, arithmetic +@cindex addition +@cindex subtraction +@cindex multiplication +@cindex division +@cindex remainder +@cindex quotient +@cindex exponentiation + +The @code{awk} language uses the common arithmetic operators when +evaluating expressions. All of these arithmetic operators follow normal +precedence rules, and work as you would expect them to. This example +divides field three by field four, adds field two, stores the result +into field one, and prints the resulting altered input record: + +@example +awk '@{ $1 = $2 + $3 / $4; print @}' inventory-shipped +@end example + +The arithmetic operators in @code{awk} are: + +@table @code +@item @var{x} + @var{y} +Addition. + +@item @var{x} - @var{y} +Subtraction. + +@item - @var{x} +Negation. + +@item + @var{x} +Unary plus. No real effect on the expression. + +@item @var{x} * @var{y} +Multiplication. + +@item @var{x} / @var{y} +Division. Since all numbers in @code{awk} are double-precision +floating point, the result is not rounded to an integer: @code{3 / 4} +has the value 0.75. + +@item @var{x} % @var{y} +@iftex +@cindex differences between @code{gawk} and @code{awk} +@end iftex +Remainder. The quotient is rounded toward zero to an integer, +multiplied by @var{y} and this result is subtracted from @var{x}. +This operation is sometimes known as ``trunc-mod.'' The following +relation always holds: + +@example +b * int(a / b) + (a % b) == a +@end example + +One possibly undesirable effect of this definition of remainder is that +@code{@var{x} % @var{y}} is negative if @var{x} is negative. Thus, + +@example +-17 % 8 = -1 +@end example + +In other @code{awk} implementations, the signedness of the remainder +may be machine dependent. + +@item @var{x} ^ @var{y} +@itemx @var{x} ** @var{y} +Exponentiation: @var{x} raised to the @var{y} power. @code{2 ^ 3} has +the value 8. The character sequence @samp{**} is equivalent to +@samp{^}. (The @sc{posix} standard only specifies the use of @samp{^} +for exponentiation.) +@end table + +@node Concatenation, Comparison Ops, Arithmetic Ops, Expressions +@section String Concatenation + +@cindex string operators +@cindex operators, string +@cindex concatenation +There is only one string operation: concatenation. It does not have a +specific operator to represent it. Instead, concatenation is performed by +writing expressions next to one another, with no operator. For example: + +@example +awk '@{ print "Field number one: " $1 @}' BBS-list +@end example + +@noindent +produces, for the first record in @file{BBS-list}: + +@example +Field number one: aardvark +@end example + +Without the space in the string constant after the @samp{:}, the line +would run together. For example: + +@example +awk '@{ print "Field number one:" $1 @}' BBS-list +@end example + +@noindent +produces, for the first record in @file{BBS-list}: + +@example +Field number one:aardvark +@end example + +Since string concatenation does not have an explicit operator, it is +often necessary to insure that it happens where you want it to by +enclosing the items to be concatenated in parentheses. For example, the +following code fragment does not concatenate @code{file} and @code{name} +as you might expect: + +@example +file = "file" +name = "name" +print "something meaningful" > file name +@end example + +@noindent +It is necessary to use the following: + +@example +print "something meaningful" > (file name) +@end example + +We recommend you use parentheses around concatenation in all but the +most common contexts (such as in the right-hand operand of @samp{=}). + +@ignore +@code{gawk} actually now allows a concatenation on the right hand +side of a @code{>} redirection, but other @code{awk}s don't. So for +now we won't mention that fact. +@end ignore + +@node Comparison Ops, Boolean Ops, Concatenation, Expressions +@section Comparison Expressions +@cindex comparison expressions +@cindex expressions, comparison +@cindex relational operators +@cindex operators, relational +@cindex regexp operators + +@dfn{Comparison expressions} compare strings or numbers for +relationships such as equality. They are written using @dfn{relational +operators}, which are a superset of those in C. Here is a table of +them: + +@table @code +@item @var{x} < @var{y} +True if @var{x} is less than @var{y}. + +@item @var{x} <= @var{y} +True if @var{x} is less than or equal to @var{y}. + +@item @var{x} > @var{y} +True if @var{x} is greater than @var{y}. + +@item @var{x} >= @var{y} +True if @var{x} is greater than or equal to @var{y}. + +@item @var{x} == @var{y} +True if @var{x} is equal to @var{y}. + +@item @var{x} != @var{y} +True if @var{x} is not equal to @var{y}. + +@item @var{x} ~ @var{y} +True if the string @var{x} matches the regexp denoted by @var{y}. + +@item @var{x} !~ @var{y} +True if the string @var{x} does not match the regexp denoted by @var{y}. + +@item @var{subscript} in @var{array} +True if array @var{array} has an element with the subscript @var{subscript}. +@end table + +Comparison expressions have the value 1 if true and 0 if false. + +The rules @code{gawk} uses for performing comparisons are based on those +in draft 11.2 of the @sc{posix} standard. The @sc{posix} standard introduced +the concept of a @dfn{numeric string}, which is simply a string that looks +like a number, for example, @code{@w{" +2"}}. + +@vindex CONVFMT +When performing a relational operation, @code{gawk} considers the type of an +operand to be the type it received on its last @emph{assignment}, rather +than the type of its last @emph{use} +(@pxref{Values, ,Numeric and String Values}). +This type is @emph{unknown} when the operand is from an ``external'' source: +field variables, command line arguments, array elements resulting from a +@code{split} operation, and the value of an @code{ENVIRON} element. +In this case only, if the operand is a numeric string, then it is +considered to be of both string type and numeric type. If at least one +operand of a comparison is of string type only, then a string +comparison is performed. Any numeric operand will be converted to a +string using the value of @code{CONVFMT} +(@pxref{Conversion, ,Conversion of Strings and Numbers}). +If one operand of a comparison is numeric, and the other operand is +either numeric or both numeric and string, then @code{gawk} does a +numeric comparison. If both operands have both types, then the +comparison is numeric. Strings are compared +by comparing the first character of each, then the second character of each, +and so on. Thus @code{"10"} is less than @code{"9"}. If there are two +strings where one is a prefix of the other, the shorter string is less than +the longer one. Thus @code{"abc"} is less than @code{"abcd"}.@refill + +Here are some sample expressions, how @code{gawk} compares them, and what +the result of the comparison is. + +@table @code +@item 1.5 <= 2.0 +numeric comparison (true) + +@item "abc" >= "xyz" +string comparison (false) + +@item 1.5 != " +2" +string comparison (true) + +@item "1e2" < "3" +string comparison (true) + +@item a = 2; b = "2" +@itemx a == b +string comparison (true) +@end table + +@example +echo 1e2 3 | awk '@{ print ($1 < $2) ? "true" : "false" @}' +@end example + +@noindent +prints @samp{false} since both @code{$1} and @code{$2} are numeric +strings and thus have both string and numeric types, thus dictating +a numeric comparison. + +The purpose of the comparison rules and the use of numeric strings is +to attempt to produce the behavior that is ``least surprising,'' while +still ``doing the right thing.'' + +String comparisons and regular expression comparisons are very different. +For example, + +@example +$1 == "foo" +@end example + +@noindent +has the value of 1, or is true, if the first field of the current input +record is precisely @samp{foo}. By contrast, + +@example +$1 ~ /foo/ +@end example + +@noindent +has the value 1 if the first field contains @samp{foo}, such as @samp{foobar}. + +The right hand operand of the @samp{~} and @samp{!~} operators may be +either a constant regexp (@code{/@dots{}/}), or it may be an ordinary +expression, in which case the value of the expression as a string is a +dynamic regexp (@pxref{Regexp Usage, ,How to Use Regular Expressions}). + +@cindex regexp as expression +In very recent implementations of @code{awk}, a constant regular +expression in slashes by itself is also an expression. The regexp +@code{/@var{regexp}/} is an abbreviation for this comparison expression: + +@example +$0 ~ /@var{regexp}/ +@end example + +In some contexts it may be necessary to write parentheses around the +regexp to avoid confusing the @code{gawk} parser. For example, +@code{(/x/ - /y/) > threshold} is not allowed, but @code{((/x/) - (/y/)) +> threshold} parses properly. + +One special place where @code{/foo/} is @emph{not} an abbreviation for +@code{$0 ~ /foo/} is when it is the right-hand operand of @samp{~} or +@samp{!~}! @xref{Constants, ,Constant Expressions}, where this is +discussed in more detail. + +@node Boolean Ops, Assignment Ops, Comparison Ops, Expressions +@section Boolean Expressions +@cindex expressions, boolean +@cindex boolean expressions +@cindex operators, boolean +@cindex boolean operators +@cindex logical operations +@cindex and operator +@cindex or operator +@cindex not operator + +A @dfn{boolean expression} is a combination of comparison expressions or +matching expressions, using the boolean operators ``or'' +(@samp{||}), ``and'' (@samp{&&}), and ``not'' (@samp{!}), along with +parentheses to control nesting. The truth of the boolean expression is +computed by combining the truth values of the component expressions. + +Boolean expressions can be used wherever comparison and matching +expressions can be used. They can be used in @code{if}, @code{while} +@code{do} and @code{for} statements. They have numeric values (1 if true, +0 if false), which come into play if the result of the boolean expression +is stored in a variable, or used in arithmetic.@refill + +In addition, every boolean expression is also a valid boolean pattern, so +you can use it as a pattern to control the execution of rules. + +Here are descriptions of the three boolean operators, with an example of +each. It may be instructive to compare these examples with the +analogous examples of boolean patterns +(@pxref{Boolean Patterns, ,Boolean Operators and Patterns}), which +use the same boolean operators in patterns instead of expressions.@refill + +@table @code +@item @var{boolean1} && @var{boolean2} +True if both @var{boolean1} and @var{boolean2} are true. For example, +the following statement prints the current input record if it contains +both @samp{2400} and @samp{foo}.@refill + +@smallexample +if ($0 ~ /2400/ && $0 ~ /foo/) print +@end smallexample + +The subexpression @var{boolean2} is evaluated only if @var{boolean1} +is true. This can make a difference when @var{boolean2} contains +expressions that have side effects: in the case of @code{$0 ~ /foo/ && +($2 == bar++)}, the variable @code{bar} is not incremented if there is +no @samp{foo} in the record. + +@item @var{boolean1} || @var{boolean2} +True if at least one of @var{boolean1} or @var{boolean2} is true. +For example, the following command prints all records in the input +file @file{BBS-list} that contain @emph{either} @samp{2400} or +@samp{foo}, or both.@refill + +@smallexample +awk '@{ if ($0 ~ /2400/ || $0 ~ /foo/) print @}' BBS-list +@end smallexample + +The subexpression @var{boolean2} is evaluated only if @var{boolean1} +is false. This can make a difference when @var{boolean2} contains +expressions that have side effects. + +@item !@var{boolean} +True if @var{boolean} is false. For example, the following program prints +all records in the input file @file{BBS-list} that do @emph{not} contain the +string @samp{foo}. + +@smallexample +awk '@{ if (! ($0 ~ /foo/)) print @}' BBS-list +@end smallexample +@end table + +@node Assignment Ops, Increment Ops, Boolean Ops, Expressions +@section Assignment Expressions +@cindex assignment operators +@cindex operators, assignment +@cindex expressions, assignment + +An @dfn{assignment} is an expression that stores a new value into a +variable. For example, let's assign the value 1 to the variable +@code{z}:@refill + +@example +z = 1 +@end example + +After this expression is executed, the variable @code{z} has the value 1. +Whatever old value @code{z} had before the assignment is forgotten. + +Assignments can store string values also. For example, this would store +the value @code{"this food is good"} in the variable @code{message}: + +@example +thing = "food" +predicate = "good" +message = "this " thing " is " predicate +@end example + +@noindent +(This also illustrates concatenation of strings.) + +The @samp{=} sign is called an @dfn{assignment operator}. It is the +simplest assignment operator because the value of the right-hand +operand is stored unchanged. + +@cindex side effect +Most operators (addition, concatenation, and so on) have no effect +except to compute a value. If you ignore the value, you might as well +not use the operator. An assignment operator is different; it does +produce a value, but even if you ignore the value, the assignment still +makes itself felt through the alteration of the variable. We call this +a @dfn{side effect}. + +@cindex lvalue +The left-hand operand of an assignment need not be a variable +(@pxref{Variables}); it can also be a field +(@pxref{Changing Fields, ,Changing the Contents of a Field}) or +an array element (@pxref{Arrays, ,Arrays in @code{awk}}). +These are all called @dfn{lvalues}, +which means they can appear on the left-hand side of an assignment operator. +The right-hand operand may be any expression; it produces the new value +which the assignment stores in the specified variable, field or array +element.@refill + +It is important to note that variables do @emph{not} have permanent types. +The type of a variable is simply the type of whatever value it happens +to hold at the moment. In the following program fragment, the variable +@code{foo} has a numeric value at first, and a string value later on: + +@example +foo = 1 +print foo +foo = "bar" +print foo +@end example + +@noindent +When the second assignment gives @code{foo} a string value, the fact that +it previously had a numeric value is forgotten. + +An assignment is an expression, so it has a value: the same value that +is assigned. Thus, @code{z = 1} as an expression has the value 1. +One consequence of this is that you can write multiple assignments together: + +@example +x = y = z = 0 +@end example + +@noindent +stores the value 0 in all three variables. It does this because the +value of @code{z = 0}, which is 0, is stored into @code{y}, and then +the value of @code{y = z = 0}, which is 0, is stored into @code{x}. + +You can use an assignment anywhere an expression is called for. For +example, it is valid to write @code{x != (y = 1)} to set @code{y} to 1 +and then test whether @code{x} equals 1. But this style tends to make +programs hard to read; except in a one-shot program, you should +rewrite it to get rid of such nesting of assignments. This is never very +hard. + +Aside from @samp{=}, there are several other assignment operators that +do arithmetic with the old value of the variable. For example, the +operator @samp{+=} computes a new value by adding the right-hand value +to the old value of the variable. Thus, the following assignment adds +5 to the value of @code{foo}: + +@example +foo += 5 +@end example + +@noindent +This is precisely equivalent to the following: + +@example +foo = foo + 5 +@end example + +@noindent +Use whichever one makes the meaning of your program clearer. + +Here is a table of the arithmetic assignment operators. In each +case, the right-hand operand is an expression whose value is converted +to a number. + +@table @code +@item @var{lvalue} += @var{increment} +Adds @var{increment} to the value of @var{lvalue} to make the new value +of @var{lvalue}. + +@item @var{lvalue} -= @var{decrement} +Subtracts @var{decrement} from the value of @var{lvalue}. + +@item @var{lvalue} *= @var{coefficient} +Multiplies the value of @var{lvalue} by @var{coefficient}. + +@item @var{lvalue} /= @var{quotient} +Divides the value of @var{lvalue} by @var{quotient}. + +@item @var{lvalue} %= @var{modulus} +Sets @var{lvalue} to its remainder by @var{modulus}. + +@item @var{lvalue} ^= @var{power} +@itemx @var{lvalue} **= @var{power} +Raises @var{lvalue} to the power @var{power}. +(Only the @code{^=} operator is specified by @sc{posix}.) +@end table + +@ignore +From: gatech!ames!elroy!cit-vax!EQL.Caltech.Edu!rankin (Pat Rankin) + In the discussion of assignment operators, it states that +``foo += 5'' "is precisely equivalent to" ``foo = foo + 5'' (p.77). That +may be true for simple variables, but it's not true for expressions with +side effects, like array references. For proof, try + BEGIN { + foo[rand()] += 5; for (x in foo) print x, foo[x] + bar[rand()] = bar[rand()] + 5; for (x in bar) print x, bar[x] + } +I suspect that the original statement is simply untrue--that '+=' is more +efficient in all cases. + +ADR --- Try to add something about this here for the next go 'round. +@end ignore + +@node Increment Ops, Conversion, Assignment Ops, Expressions +@section Increment Operators + +@cindex increment operators +@cindex operators, increment +@dfn{Increment operators} increase or decrease the value of a variable +by 1. You could do the same thing with an assignment operator, so +the increment operators add no power to the @code{awk} language; but they +are convenient abbreviations for something very common. + +The operator to add 1 is written @samp{++}. It can be used to increment +a variable either before or after taking its value. + +To pre-increment a variable @var{v}, write @code{++@var{v}}. This adds +1 to the value of @var{v} and that new value is also the value of this +expression. The assignment expression @code{@var{v} += 1} is completely +equivalent. + +Writing the @samp{++} after the variable specifies post-increment. This +increments the variable value just the same; the difference is that the +value of the increment expression itself is the variable's @emph{old} +value. Thus, if @code{foo} has the value 4, then the expression @code{foo++} +has the value 4, but it changes the value of @code{foo} to 5. + +The post-increment @code{foo++} is nearly equivalent to writing @code{(foo ++= 1) - 1}. It is not perfectly equivalent because all numbers in +@code{awk} are floating point: in floating point, @code{foo + 1 - 1} does +not necessarily equal @code{foo}. But the difference is minute as +long as you stick to numbers that are fairly small (less than a trillion). + +Any lvalue can be incremented. Fields and array elements are incremented +just like variables. (Use @samp{$(i++)} when you wish to do a field reference +and a variable increment at the same time. The parentheses are necessary +because of the precedence of the field reference operator, @samp{$}.) +@c expert information in the last parenthetical remark + +The decrement operator @samp{--} works just like @samp{++} except that +it subtracts 1 instead of adding. Like @samp{++}, it can be used before +the lvalue to pre-decrement or after it to post-decrement. + +Here is a summary of increment and decrement expressions. + +@table @code +@item ++@var{lvalue} +This expression increments @var{lvalue} and the new value becomes the +value of this expression. + +@item @var{lvalue}++ +This expression causes the contents of @var{lvalue} to be incremented. +The value of the expression is the @emph{old} value of @var{lvalue}. + +@item --@var{lvalue} +Like @code{++@var{lvalue}}, but instead of adding, it subtracts. It +decrements @var{lvalue} and delivers the value that results. + +@item @var{lvalue}-- +Like @code{@var{lvalue}++}, but instead of adding, it subtracts. It +decrements @var{lvalue}. The value of the expression is the @emph{old} +value of @var{lvalue}. +@end table + +@node Conversion, Values, Increment Ops, Expressions +@section Conversion of Strings and Numbers + +@cindex conversion of strings and numbers +Strings are converted to numbers, and numbers to strings, if the context +of the @code{awk} program demands it. For example, if the value of +either @code{foo} or @code{bar} in the expression @code{foo + bar} +happens to be a string, it is converted to a number before the addition +is performed. If numeric values appear in string concatenation, they +are converted to strings. Consider this:@refill + +@example +two = 2; three = 3 +print (two three) + 4 +@end example + +@noindent +This eventually prints the (numeric) value 27. The numeric values of +the variables @code{two} and @code{three} are converted to strings and +concatenated together, and the resulting string is converted back to the +number 23, to which 4 is then added. + +If, for some reason, you need to force a number to be converted to a +string, concatenate the null string with that number. To force a string +to be converted to a number, add zero to that string. + +A string is converted to a number by interpreting a numeric prefix +of the string as numerals: +@code{"2.5"} converts to 2.5, @code{"1e3"} converts to 1000, and @code{"25fix"} +has a numeric value of 25. +Strings that can't be interpreted as valid numbers are converted to +zero. + +@vindex CONVFMT +The exact manner in which numbers are converted into strings is controlled +by the @code{awk} built-in variable @code{CONVFMT} (@pxref{Built-in Variables}). +Numbers are converted using a special version of the @code{sprintf} function +(@pxref{Built-in, ,Built-in Functions}) with @code{CONVFMT} as the format +specifier.@refill + +@code{CONVFMT}'s default value is @code{"%.6g"}, which prints a value with +at least six significant digits. For some applications you will want to +change it to specify more precision. Double precision on most modern +machines gives you 16 or 17 decimal digits of precision. + +Strange results can happen if you set @code{CONVFMT} to a string that doesn't +tell @code{sprintf} how to format floating point numbers in a useful way. +For example, if you forget the @samp{%} in the format, all numbers will be +converted to the same constant string.@refill + +As a special case, if a number is an integer, then the result of converting +it to a string is @emph{always} an integer, no matter what the value of +@code{CONVFMT} may be. Given the following code fragment: + +@example +CONVFMT = "%2.2f" +a = 12 +b = a "" +@end example + +@noindent +@code{b} has the value @code{"12"}, not @code{"12.00"}. + +@ignore +For the 2.14 version, describe the ``stickyness'' of conversions. Right now +the manual assumes everywhere that variables are either numbers or strings; +in fact both kinds of values may be valid. If both happen to be valid, a +conversion isn't necessary and isn't done. Revising the manual to be +consistent with this, though, is too big a job to tackle at the moment. + +7/92: This has sort of been done, only the section isn't completely right! + What to do? +7/92: Pretty much fixed, at least for the short term, thanks to text + from David. +@end ignore + +@vindex OFMT +Prior to the @sc{posix} standard, @code{awk} specified that the value +of @code{OFMT} was used for converting numbers to strings. @code{OFMT} +specifies the output format to use when printing numbers with @code{print}. +@code{CONVFMT} was introduced in order to separate the semantics of +conversions from the semantics of printing. Both @code{CONVFMT} and +@code{OFMT} have the same default value: @code{"%.6g"}. In the vast majority +of cases, old @code{awk} programs will not change their behavior. +However, this use of @code{OFMT} is something to keep in mind if you must +port your program to other implementations of @code{awk}; we recommend +that instead of changing your programs, you just port @code{gawk} itself!@refill + +@node Values, Conditional Exp, Conversion, Expressions +@section Numeric and String Values +@cindex conversion of strings and numbers + +Through most of this manual, we present @code{awk} values (such as constants, +fields, or variables) as @emph{either} numbers @emph{or} strings. This is +a convenient way to think about them, since typically they are used in only +one way, or the other. + +In truth though, @code{awk} values can be @emph{both} string and +numeric, at the same time. Internally, @code{awk} represents values +with a string, a (floating point) number, and an indication that one, +the other, or both representations of the value are valid. + +Keeping track of both kinds of values is important for execution +efficiency: a variable can acquire a string value the first time it +is used as a string, and then that string value can be used until the +variable is assigned a new value. Thus, if a variable with only a numeric +value is used in several concatenations in a row, it only has to be given +a string representation once. The numeric value remains valid, so that +no conversion back to a number is necessary if the variable is later used +in an arithmetic expression. + +Tracking both kinds of values is also important for precise numerical +calculations. Consider the following: + +@smallexample +a = 123.321 +CONVFMT = "%3.1f" +b = a " is a number" +c = a + 1.654 +@end smallexample + +@noindent +The variable @code{a} receives a string value in the concatenation and +assignment to @code{b}. The string value of @code{a} is @code{"123.3"}. +If the numeric value was lost when it was converted to a string, then the +numeric use of @code{a} in the last statement would lose information. +@code{c} would be assigned the value 124.954 instead of 124.975. +Such errors accumulate rapidly, and very adversely affect numeric +computations.@refill + +Once a numeric value acquires a corresponding string value, it stays valid +until a new assignment is made. If @code{CONVFMT} +(@pxref{Conversion, ,Conversion of Strings and Numbers}) changes in the +meantime, the old string value will still be used. For example:@refill + +@smallexample +BEGIN @{ + CONVFMT = "%2.2f" + a = 123.456 + b = a "" # force `a' to have string value too + printf "a = %s\n", a + CONVFMT = "%.6g" + printf "a = %s\n", a + a += 0 # make `a' numeric only again + printf "a = %s\n", a # use `a' as string +@} +@end smallexample + +@noindent +This program prints @samp{a = 123.46} twice, and then prints +@samp{a = 123.456}. + +@xref{Conversion, ,Conversion of Strings and Numbers}, for the rules that +specify how string values are made from numeric values. + +@node Conditional Exp, Function Calls, Values, Expressions +@section Conditional Expressions +@cindex conditional expression +@cindex expression, conditional + +A @dfn{conditional expression} is a special kind of expression with +three operands. It allows you to use one expression's value to select +one of two other expressions. + +The conditional expression looks the same as in the C language: + +@example +@var{selector} ? @var{if-true-exp} : @var{if-false-exp} +@end example + +@noindent +There are three subexpressions. The first, @var{selector}, is always +computed first. If it is ``true'' (not zero and not null) then +@var{if-true-exp} is computed next and its value becomes the value of +the whole expression. Otherwise, @var{if-false-exp} is computed next +and its value becomes the value of the whole expression.@refill + +For example, this expression produces the absolute value of @code{x}: + +@example +x > 0 ? x : -x +@end example + +Each time the conditional expression is computed, exactly one of +@var{if-true-exp} and @var{if-false-exp} is computed; the other is ignored. +This is important when the expressions contain side effects. For example, +this conditional expression examines element @code{i} of either array +@code{a} or array @code{b}, and increments @code{i}. + +@example +x == y ? a[i++] : b[i++] +@end example + +@noindent +This is guaranteed to increment @code{i} exactly once, because each time +one or the other of the two increment expressions is executed, +and the other is not. + +@node Function Calls, Precedence, Conditional Exp, Expressions +@section Function Calls +@cindex function call +@cindex calling a function + +A @dfn{function} is a name for a particular calculation. Because it has +a name, you can ask for it by name at any point in the program. For +example, the function @code{sqrt} computes the square root of a number. + +A fixed set of functions are @dfn{built-in}, which means they are +available in every @code{awk} program. The @code{sqrt} function is one +of these. @xref{Built-in, ,Built-in Functions}, for a list of built-in +functions and their descriptions. In addition, you can define your own +functions in the program for use elsewhere in the same program. +@xref{User-defined, ,User-defined Functions}, for how to do this.@refill + +@cindex arguments in function call +The way to use a function is with a @dfn{function call} expression, +which consists of the function name followed by a list of +@dfn{arguments} in parentheses. The arguments are expressions which +give the raw materials for the calculation that the function will do. +When there is more than one argument, they are separated by commas. If +there are no arguments, write just @samp{()} after the function name. +Here are some examples: + +@example +sqrt(x^2 + y^2) # @r{One argument} +atan2(y, x) # @r{Two arguments} +rand() # @r{No arguments} +@end example + +@strong{Do not put any space between the function name and the +open-parenthesis!} A user-defined function name looks just like the name of +a variable, and space would make the expression look like concatenation +of a variable with an expression inside parentheses. Space before the +parenthesis is harmless with built-in functions, but it is best not to get +into the habit of using space to avoid mistakes with user-defined +functions. + +Each function expects a particular number of arguments. For example, the +@code{sqrt} function must be called with a single argument, the number +to take the square root of: + +@example +sqrt(@var{argument}) +@end example + +Some of the built-in functions allow you to omit the final argument. +If you do so, they use a reasonable default. +@xref{Built-in, ,Built-in Functions}, for full details. If arguments +are omitted in calls to user-defined functions, then those arguments are +treated as local variables, initialized to the null string +(@pxref{User-defined, ,User-defined Functions}).@refill + +Like every other expression, the function call has a value, which is +computed by the function based on the arguments you give it. In this +example, the value of @code{sqrt(@var{argument})} is the square root of the +argument. A function can also have side effects, such as assigning the +values of certain variables or doing I/O. + +Here is a command to read numbers, one number per line, and print the +square root of each one: + +@example +awk '@{ print "The square root of", $1, "is", sqrt($1) @}' +@end example + +@node Precedence, , Function Calls, Expressions +@section Operator Precedence (How Operators Nest) +@cindex precedence +@cindex operator precedence + +@dfn{Operator precedence} determines how operators are grouped, when +different operators appear close by in one expression. For example, +@samp{*} has higher precedence than @samp{+}; thus, @code{a + b * c} +means to multiply @code{b} and @code{c}, and then add @code{a} to the +product (i.e., @code{a + (b * c)}). + +You can overrule the precedence of the operators by using parentheses. +You can think of the precedence rules as saying where the +parentheses are assumed if you do not write parentheses yourself. In +fact, it is wise to always use parentheses whenever you have an unusual +combination of operators, because other people who read the program may +not remember what the precedence is in this case. You might forget, +too; then you could make a mistake. Explicit parentheses will help prevent +any such mistake. + +When operators of equal precedence are used together, the leftmost +operator groups first, except for the assignment, conditional and +exponentiation operators, which group in the opposite order. +Thus, @code{a - b + c} groups as @code{(a - b) + c}; +@code{a = b = c} groups as @code{a = (b = c)}.@refill + +The precedence of prefix unary operators does not matter as long as only +unary operators are involved, because there is only one way to parse +them---innermost first. Thus, @code{$++i} means @code{$(++i)} and +@code{++$x} means @code{++($x)}. However, when another operator follows +the operand, then the precedence of the unary operators can matter. +Thus, @code{$x^2} means @code{($x)^2}, but @code{-x^2} means +@code{-(x^2)}, because @samp{-} has lower precedence than @samp{^} +while @samp{$} has higher precedence. + +Here is a table of the operators of @code{awk}, in order of increasing +precedence: + +@table @asis +@item assignment +@samp{=}, @samp{+=}, @samp{-=}, @samp{*=}, @samp{/=}, @samp{%=}, +@samp{^=}, @samp{**=}. These operators group right-to-left. +(The @samp{**=} operator is not specified by @sc{posix}.) + +@item conditional +@samp{?:}. This operator groups right-to-left. + +@item logical ``or''. +@samp{||}. + +@item logical ``and''. +@samp{&&}. + +@item array membership +@samp{in}. + +@item matching +@samp{~}, @samp{!~}. + +@item relational, and redirection +The relational operators and the redirections have the same precedence +level. Characters such as @samp{>} serve both as relationals and as +redirections; the context distinguishes between the two meanings. + +The relational operators are @samp{<}, @samp{<=}, @samp{==}, @samp{!=}, +@samp{>=} and @samp{>}. + +The I/O redirection operators are @samp{<}, @samp{>}, @samp{>>} and +@samp{|}. + +Note that I/O redirection operators in @code{print} and @code{printf} +statements belong to the statement level, not to expressions. The +redirection does not produce an expression which could be the operand of +another operator. As a result, it does not make sense to use a +redirection operator near another operator of lower precedence, without +parentheses. Such combinations, for example @samp{print foo > a ? b : +c}, result in syntax errors. + +@item concatenation +No special token is used to indicate concatenation. +The operands are simply written side by side. + +@item add, subtract +@samp{+}, @samp{-}. + +@item multiply, divide, mod +@samp{*}, @samp{/}, @samp{%}. + +@item unary plus, minus, ``not'' +@samp{+}, @samp{-}, @samp{!}. + +@item exponentiation +@samp{^}, @samp{**}. These operators group right-to-left. +(The @samp{**} operator is not specified by @sc{posix}.) + +@item increment, decrement +@samp{++}, @samp{--}. + +@item field +@samp{$}. +@end table + +@node Statements, Arrays, Expressions, Top +@chapter Control Statements in Actions +@cindex control statement + +@dfn{Control statements} such as @code{if}, @code{while}, and so on +control the flow of execution in @code{awk} programs. Most of the +control statements in @code{awk} are patterned on similar statements in +C. + +All the control statements start with special keywords such as @code{if} +and @code{while}, to distinguish them from simple expressions. + +Many control statements contain other statements; for example, the +@code{if} statement contains another statement which may or may not be +executed. The contained statement is called the @dfn{body}. If you +want to include more than one statement in the body, group them into a +single compound statement with curly braces, separating them with +newlines or semicolons. + +@menu +* If Statement:: Conditionally execute + some @code{awk} statements. +* While Statement:: Loop until some condition is satisfied. +* Do Statement:: Do specified action while looping until some + condition is satisfied. +* For Statement:: Another looping statement, that provides + initialization and increment clauses. +* Break Statement:: Immediately exit the innermost enclosing loop. +* Continue Statement:: Skip to the end of the innermost + enclosing loop. +* Next Statement:: Stop processing the current input record. +* Next File Statement:: Stop processing the current file. +* Exit Statement:: Stop execution of @code{awk}. +@end menu + +@node If Statement, While Statement, Statements, Statements +@section The @code{if} Statement + +@cindex @code{if} statement +The @code{if}-@code{else} statement is @code{awk}'s decision-making +statement. It looks like this:@refill + +@example +if (@var{condition}) @var{then-body} @r{[}else @var{else-body}@r{]} +@end example + +@noindent +@var{condition} is an expression that controls what the rest of the +statement will do. If @var{condition} is true, @var{then-body} is +executed; otherwise, @var{else-body} is executed (assuming that the +@code{else} clause is present). The @code{else} part of the statement is +optional. The condition is considered false if its value is zero or +the null string, and true otherwise.@refill + +Here is an example: + +@example +if (x % 2 == 0) + print "x is even" +else + print "x is odd" +@end example + +In this example, if the expression @code{x % 2 == 0} is true (that is, +the value of @code{x} is divisible by 2), then the first @code{print} +statement is executed, otherwise the second @code{print} statement is +performed.@refill + +If the @code{else} appears on the same line as @var{then-body}, and +@var{then-body} is not a compound statement (i.e., not surrounded by +curly braces), then a semicolon must separate @var{then-body} from +@code{else}. To illustrate this, let's rewrite the previous example: + +@example +awk '@{ if (x % 2 == 0) print "x is even"; else + print "x is odd" @}' +@end example + +@noindent +If you forget the @samp{;}, @code{awk} won't be able to parse the +statement, and you will get a syntax error. + +We would not actually write this example this way, because a human +reader might fail to see the @code{else} if it were not the first thing +on its line. + +@node While Statement, Do Statement, If Statement, Statements +@section The @code{while} Statement +@cindex @code{while} statement +@cindex loop +@cindex body of a loop + +In programming, a @dfn{loop} means a part of a program that is (or at least can +be) executed two or more times in succession. + +The @code{while} statement is the simplest looping statement in +@code{awk}. It repeatedly executes a statement as long as a condition is +true. It looks like this: + +@example +while (@var{condition}) + @var{body} +@end example + +@noindent +Here @var{body} is a statement that we call the @dfn{body} of the loop, +and @var{condition} is an expression that controls how long the loop +keeps running. + +The first thing the @code{while} statement does is test @var{condition}. +If @var{condition} is true, it executes the statement @var{body}. +(@var{condition} is true when the value +is not zero and not a null string.) After @var{body} has been executed, +@var{condition} is tested again, and if it is still true, @var{body} is +executed again. This process repeats until @var{condition} is no longer +true. If @var{condition} is initially false, the body of the loop is +never executed.@refill + +This example prints the first three fields of each record, one per line. + +@example +awk '@{ i = 1 + while (i <= 3) @{ + print $i + i++ + @} +@}' +@end example + +@noindent +Here the body of the loop is a compound statement enclosed in braces, +containing two statements. + +The loop works like this: first, the value of @code{i} is set to 1. +Then, the @code{while} tests whether @code{i} is less than or equal to +three. This is the case when @code{i} equals one, so the @code{i}-th +field is printed. Then the @code{i++} increments the value of @code{i} +and the loop repeats. The loop terminates when @code{i} reaches 4. + +As you can see, a newline is not required between the condition and the +body; but using one makes the program clearer unless the body is a +compound statement or is very simple. The newline after the open-brace +that begins the compound statement is not required either, but the +program would be hard to read without it. + +@node Do Statement, For Statement, While Statement, Statements +@section The @code{do}-@code{while} Statement + +The @code{do} loop is a variation of the @code{while} looping statement. +The @code{do} loop executes the @var{body} once, then repeats @var{body} +as long as @var{condition} is true. It looks like this: + +@example +do + @var{body} +while (@var{condition}) +@end example + +Even if @var{condition} is false at the start, @var{body} is executed at +least once (and only once, unless executing @var{body} makes +@var{condition} true). Contrast this with the corresponding +@code{while} statement: + +@example +while (@var{condition}) + @var{body} +@end example + +@noindent +This statement does not execute @var{body} even once if @var{condition} +is false to begin with. + +Here is an example of a @code{do} statement: + +@example +awk '@{ i = 1 + do @{ + print $0 + i++ + @} while (i <= 10) +@}' +@end example + +@noindent +prints each input record ten times. It isn't a very realistic example, +since in this case an ordinary @code{while} would do just as well. But +this reflects actual experience; there is only occasionally a real use +for a @code{do} statement.@refill + +@node For Statement, Break Statement, Do Statement, Statements +@section The @code{for} Statement +@cindex @code{for} statement + +The @code{for} statement makes it more convenient to count iterations of a +loop. The general form of the @code{for} statement looks like this:@refill + +@example +for (@var{initialization}; @var{condition}; @var{increment}) + @var{body} +@end example + +@noindent +This statement starts by executing @var{initialization}. Then, as long +as @var{condition} is true, it repeatedly executes @var{body} and then +@var{increment}. Typically @var{initialization} sets a variable to +either zero or one, @var{increment} adds 1 to it, and @var{condition} +compares it against the desired number of iterations. + +Here is an example of a @code{for} statement: + +@example +@group +awk '@{ for (i = 1; i <= 3; i++) + print $i +@}' +@end group +@end example + +@noindent +This prints the first three fields of each input record, one field per +line. + +In the @code{for} statement, @var{body} stands for any statement, but +@var{initialization}, @var{condition} and @var{increment} are just +expressions. You cannot set more than one variable in the +@var{initialization} part unless you use a multiple assignment statement +such as @code{x = y = 0}, which is possible only if all the initial values +are equal. (But you can initialize additional variables by writing +their assignments as separate statements preceding the @code{for} loop.) + +The same is true of the @var{increment} part; to increment additional +variables, you must write separate statements at the end of the loop. +The C compound expression, using C's comma operator, would be useful in +this context, but it is not supported in @code{awk}. + +Most often, @var{increment} is an increment expression, as in the +example above. But this is not required; it can be any expression +whatever. For example, this statement prints all the powers of 2 +between 1 and 100: + +@example +for (i = 1; i <= 100; i *= 2) + print i +@end example + +Any of the three expressions in the parentheses following the @code{for} may +be omitted if there is nothing to be done there. Thus, @w{@samp{for (;x +> 0;)}} is equivalent to @w{@samp{while (x > 0)}}. If the +@var{condition} is omitted, it is treated as @var{true}, effectively +yielding an @dfn{infinite loop} (i.e., a loop that will never +terminate).@refill + +In most cases, a @code{for} loop is an abbreviation for a @code{while} +loop, as shown here: + +@example +@var{initialization} +while (@var{condition}) @{ + @var{body} + @var{increment} +@} +@end example + +@noindent +The only exception is when the @code{continue} statement +(@pxref{Continue Statement, ,The @code{continue} Statement}) is used +inside the loop; changing a @code{for} statement to a @code{while} +statement in this way can change the effect of the @code{continue} +statement inside the loop.@refill + +There is an alternate version of the @code{for} loop, for iterating over +all the indices of an array: + +@example +for (i in array) + @var{do something with} array[i] +@end example + +@noindent +@xref{Arrays, ,Arrays in @code{awk}}, for more information on this +version of the @code{for} loop. + +The @code{awk} language has a @code{for} statement in addition to a +@code{while} statement because often a @code{for} loop is both less work to +type and more natural to think of. Counting the number of iterations is +very common in loops. It can be easier to think of this counting as part +of looping rather than as something to do inside the loop. + +The next section has more complicated examples of @code{for} loops. + +@node Break Statement, Continue Statement, For Statement, Statements +@section The @code{break} Statement +@cindex @code{break} statement +@cindex loops, exiting + +The @code{break} statement jumps out of the innermost @code{for}, +@code{while}, or @code{do}-@code{while} loop that encloses it. The +following example finds the smallest divisor of any integer, and also +identifies prime numbers:@refill + +@smallexample +awk '# find smallest divisor of num + @{ num = $1 + for (div = 2; div*div <= num; div++) + if (num % div == 0) + break + if (num % div == 0) + printf "Smallest divisor of %d is %d\n", num, div + else + printf "%d is prime\n", num @}' +@end smallexample + +When the remainder is zero in the first @code{if} statement, @code{awk} +immediately @dfn{breaks out} of the containing @code{for} loop. This means +that @code{awk} proceeds immediately to the statement following the loop +and continues processing. (This is very different from the @code{exit} +statement which stops the entire @code{awk} program. +@xref{Exit Statement, ,The @code{exit} Statement}.)@refill + +Here is another program equivalent to the previous one. It illustrates how +the @var{condition} of a @code{for} or @code{while} could just as well be +replaced with a @code{break} inside an @code{if}: + +@smallexample +@group +awk '# find smallest divisor of num + @{ num = $1 + for (div = 2; ; div++) @{ + if (num % div == 0) @{ + printf "Smallest divisor of %d is %d\n", num, div + break + @} + if (div*div > num) @{ + printf "%d is prime\n", num + break + @} + @} +@}' +@end group +@end smallexample + +@node Continue Statement, Next Statement, Break Statement, Statements +@section The @code{continue} Statement + +@cindex @code{continue} statement +The @code{continue} statement, like @code{break}, is used only inside +@code{for}, @code{while}, and @code{do}-@code{while} loops. It skips +over the rest of the loop body, causing the next cycle around the loop +to begin immediately. Contrast this with @code{break}, which jumps out +of the loop altogether. Here is an example:@refill + +@example +# print names that don't contain the string "ignore" + +# first, save the text of each line +@{ names[NR] = $0 @} + +# print what we're interested in +END @{ + for (x in names) @{ + if (names[x] ~ /ignore/) + continue + print names[x] + @} +@} +@end example + +If one of the input records contains the string @samp{ignore}, this +example skips the print statement for that record, and continues back to +the first statement in the loop. + +This is not a practical example of @code{continue}, since it would be +just as easy to write the loop like this: + +@example +for (x in names) + if (names[x] !~ /ignore/) + print names[x] +@end example + +@ignore +from brennan@boeing.com: + +page 90, section 9.6. The example is too artificial as +the one line program + + !/ignore/ + +does the same thing. +@end ignore +@c ADR --- he's right, but don't worry about this for now + +The @code{continue} statement in a @code{for} loop directs @code{awk} to +skip the rest of the body of the loop, and resume execution with the +increment-expression of the @code{for} statement. The following program +illustrates this fact:@refill + +@example +awk 'BEGIN @{ + for (x = 0; x <= 20; x++) @{ + if (x == 5) + continue + printf ("%d ", x) + @} + print "" +@}' +@end example + +@noindent +This program prints all the numbers from 0 to 20, except for 5, for +which the @code{printf} is skipped. Since the increment @code{x++} +is not skipped, @code{x} does not remain stuck at 5. Contrast the +@code{for} loop above with the @code{while} loop: + +@example +awk 'BEGIN @{ + x = 0 + while (x <= 20) @{ + if (x == 5) + continue + printf ("%d ", x) + x++ + @} + print "" +@}' +@end example + +@noindent +This program loops forever once @code{x} gets to 5. + +As described above, the @code{continue} statement has no meaning when +used outside the body of a loop. However, although it was never documented, +historical implementations of @code{awk} have treated the @code{continue} +statement outside of a loop as if it were a @code{next} statement +(@pxref{Next Statement, ,The @code{next} Statement}). +By default, @code{gawk} silently supports this usage. However, if +@samp{-W posix} has been specified on the command line +(@pxref{Command Line, ,Invoking @code{awk}}), +it will be treated as an error, since the @sc{posix} standard specifies +that @code{continue} should only be used inside the body of a loop.@refill + +@node Next Statement, Next File Statement, Continue Statement, Statements +@section The @code{next} Statement +@cindex @code{next} statement + +The @code{next} statement forces @code{awk} to immediately stop processing +the current record and go on to the next record. This means that no +further rules are executed for the current record. The rest of the +current rule's action is not executed either. + +Contrast this with the effect of the @code{getline} function +(@pxref{Getline, ,Explicit Input with @code{getline}}). That too causes +@code{awk} to read the next record immediately, but it does not alter the +flow of control in any way. So the rest of the current action executes +with a new input record. + +At the highest level, @code{awk} program execution is a loop that reads +an input record and then tests each rule's pattern against it. If you +think of this loop as a @code{for} statement whose body contains the +rules, then the @code{next} statement is analogous to a @code{continue} +statement: it skips to the end of the body of this implicit loop, and +executes the increment (which reads another record). + +For example, if your @code{awk} program works only on records with four +fields, and you don't want it to fail when given bad input, you might +use this rule near the beginning of the program: + +@smallexample +NF != 4 @{ + printf("line %d skipped: doesn't have 4 fields", FNR) > "/dev/stderr" + next +@} +@end smallexample + +@noindent +so that the following rules will not see the bad record. The error +message is redirected to the standard error output stream, as error +messages should be. @xref{Special Files, ,Standard I/O Streams}. + +According to the @sc{posix} standard, the behavior is undefined if +the @code{next} statement is used in a @code{BEGIN} or @code{END} rule. +@code{gawk} will treat it as a syntax error. + +If the @code{next} statement causes the end of the input to be reached, +then the code in the @code{END} rules, if any, will be executed. +@xref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}. + +@node Next File Statement, Exit Statement, Next Statement, Statements +@section The @code{next file} Statement + +@cindex @code{next file} statement +The @code{next file} statement is similar to the @code{next} statement. +However, instead of abandoning processing of the current record, the +@code{next file} statement instructs @code{awk} to stop processing the +current data file. + +Upon execution of the @code{next file} statement, @code{FILENAME} is +updated to the name of the next data file listed on the command line, +@code{FNR} is reset to 1, and processing starts over with the first +rule in the progam. @xref{Built-in Variables}. + +If the @code{next file} statement causes the end of the input to be reached, +then the code in the @code{END} rules, if any, will be executed. +@xref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}. + +The @code{next file} statement is a @code{gawk} extension; it is not +(currently) available in any other @code{awk} implementation. You can +simulate its behavior by creating a library file named @file{nextfile.awk}, +with the following contents. (This sample program uses user-defined +functions, a feature that has not been presented yet. +@xref{User-defined, ,User-defined Functions}, +for more information.)@refill + +@smallexample +# nextfile --- function to skip remaining records in current file + +# this should be read in before the "main" awk program + +function nextfile() @{ _abandon_ = FILENAME; next @} + +_abandon_ == FILENAME && FNR > 1 @{ next @} +_abandon_ == FILENAME && FNR == 1 @{ _abandon_ = "" @} +@end smallexample + +The @code{nextfile} function simply sets a ``private'' variable@footnote{Since +all variables in @code{awk} are global, this program uses the common +practice of prefixing the variable name with an underscore. In fact, it +also suffixes the variable name with an underscore, as extra insurance +against using a variable name that might be used in some other library +file.} to the name of the current data file, and then retrieves the next +record. Since this file is read before the main @code{awk} program, +the rules that follows the function definition will be executed before the +rules in the main program. The first rule continues to skip records as long as +the name of the input file has not changed, and this is not the first +record in the file. This rule is sufficient most of the time. But what if +the @emph{same} data file is named twice in a row on the command line? +This rule would not process the data file the second time. The second rule +catches this case: If the data file name is what was being skipped, but +@code{FNR} is 1, then this is the second time the file is being processed, +and it should not be skipped. + +The @code{next file} statement would be useful if you have many data +files to process, and due to the nature of the data, you expect that you +would not want to process every record in the file. In order to move on to +the next data file, you would have to continue scanning the unwanted +records (as described above). The @code{next file} statement accomplishes +this much more efficiently. + +@ignore +Would it make sense down the road to nuke `next file' in favor of +semantics that would make this work? + + function nextfile() { ARGIND++ ; next } +@end ignore + +@node Exit Statement, , Next File Statement, Statements +@section The @code{exit} Statement + +@cindex @code{exit} statement +The @code{exit} statement causes @code{awk} to immediately stop +executing the current rule and to stop processing input; any remaining input +is ignored.@refill + +If an @code{exit} statement is executed from a @code{BEGIN} rule the +program stops processing everything immediately. No input records are +read. However, if an @code{END} rule is present, it is executed +(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}). + +If @code{exit} is used as part of an @code{END} rule, it causes +the program to stop immediately. + +An @code{exit} statement that is part of an ordinary rule (that is, not part +of a @code{BEGIN} or @code{END} rule) stops the execution of any further +automatic rules, but the @code{END} rule is executed if there is one. +If you do not want the @code{END} rule to do its job in this case, you +can set a variable to nonzero before the @code{exit} statement, and check +that variable in the @code{END} rule. + +If an argument is supplied to @code{exit}, its value is used as the exit +status code for the @code{awk} process. If no argument is supplied, +@code{exit} returns status zero (success).@refill + +For example, let's say you've discovered an error condition you really +don't know how to handle. Conventionally, programs report this by +exiting with a nonzero status. Your @code{awk} program can do this +using an @code{exit} statement with a nonzero argument. Here's an +example of this:@refill + +@example +@group +BEGIN @{ + if (("date" | getline date_now) < 0) @{ + print "Can't get system date" > "/dev/stderr" + exit 4 + @} +@} +@end group +@end example + +@node Arrays, Built-in, Statements, Top +@chapter Arrays in @code{awk} + +An @dfn{array} is a table of values, called @dfn{elements}. The +elements of an array are distinguished by their indices. @dfn{Indices} +may be either numbers or strings. Each array has a name, which looks +like a variable name, but must not be in use as a variable name in the +same @code{awk} program. + +@menu +* Array Intro:: Introduction to Arrays +* Reference to Elements:: How to examine one element of an array. +* Assigning Elements:: How to change an element of an array. +* Array Example:: Basic Example of an Array +* Scanning an Array:: A variation of the @code{for} statement. + It loops through the indices of + an array's existing elements. +* Delete:: The @code{delete} statement removes + an element from an array. +* Numeric Array Subscripts:: How to use numbers as subscripts in @code{awk}. +* Multi-dimensional:: Emulating multi-dimensional arrays in @code{awk}. +* Multi-scanning:: Scanning multi-dimensional arrays. +@end menu + +@node Array Intro, Reference to Elements, Arrays, Arrays +@section Introduction to Arrays + +@cindex arrays +The @code{awk} language has one-dimensional @dfn{arrays} for storing groups +of related strings or numbers. + +Every @code{awk} array must have a name. Array names have the same +syntax as variable names; any valid variable name would also be a valid +array name. But you cannot use one name in both ways (as an array and +as a variable) in one @code{awk} program. + +Arrays in @code{awk} superficially resemble arrays in other programming +languages; but there are fundamental differences. In @code{awk}, you +don't need to specify the size of an array before you start to use it. +Additionally, any number or string in @code{awk} may be used as an +array index. + +In most other languages, you have to @dfn{declare} an array and specify +how many elements or components it contains. In such languages, the +declaration causes a contiguous block of memory to be allocated for that +many elements. An index in the array must be a positive integer; for +example, the index 0 specifies the first element in the array, which is +actually stored at the beginning of the block of memory. Index 1 +specifies the second element, which is stored in memory right after the +first element, and so on. It is impossible to add more elements to the +array, because it has room for only as many elements as you declared. + +A contiguous array of four elements might look like this, +conceptually, if the element values are @code{8}, @code{"foo"}, +@code{""} and @code{30}:@refill + +@example ++---------+---------+--------+---------+ +| 8 | "foo" | "" | 30 | @r{value} ++---------+---------+--------+---------+ + 0 1 2 3 @r{index} +@end example + +@noindent +Only the values are stored; the indices are implicit from the order of +the values. @code{8} is the value at index 0, because @code{8} appears in the +position with 0 elements before it. + +@cindex arrays, definition of +@cindex associative arrays +Arrays in @code{awk} are different: they are @dfn{associative}. This means +that each array is a collection of pairs: an index, and its corresponding +array element value: + +@example +@r{Element} 4 @r{Value} 30 +@r{Element} 2 @r{Value} "foo" +@r{Element} 1 @r{Value} 8 +@r{Element} 3 @r{Value} "" +@end example + +@noindent +We have shown the pairs in jumbled order because their order is irrelevant. + +One advantage of an associative array is that new pairs can be added +at any time. For example, suppose we add to the above array a tenth element +whose value is @w{@code{"number ten"}}. The result is this: + +@example +@r{Element} 10 @r{Value} "number ten" +@r{Element} 4 @r{Value} 30 +@r{Element} 2 @r{Value} "foo" +@r{Element} 1 @r{Value} 8 +@r{Element} 3 @r{Value} "" +@end example + +@noindent +Now the array is @dfn{sparse} (i.e., some indices are missing): it has +elements 1--4 and 10, but doesn't have elements 5, 6, 7, 8, or 9.@refill + +Another consequence of associative arrays is that the indices don't +have to be positive integers. Any number, or even a string, can be +an index. For example, here is an array which translates words from +English into French: + +@example +@r{Element} "dog" @r{Value} "chien" +@r{Element} "cat" @r{Value} "chat" +@r{Element} "one" @r{Value} "un" +@r{Element} 1 @r{Value} "un" +@end example + +@noindent +Here we decided to translate the number 1 in both spelled-out and +numeric form---thus illustrating that a single array can have both +numbers and strings as indices. + +When @code{awk} creates an array for you, e.g., with the @code{split} +built-in function, +that array's indices are consecutive integers starting at 1. +(@xref{String Functions, ,Built-in Functions for String Manipulation}.) + +@node Reference to Elements, Assigning Elements, Array Intro, Arrays +@section Referring to an Array Element +@cindex array reference +@cindex element of array +@cindex reference to array + +The principal way of using an array is to refer to one of its elements. +An array reference is an expression which looks like this: + +@example +@var{array}[@var{index}] +@end example + +@noindent +Here, @var{array} is the name of an array. The expression @var{index} is +the index of the element of the array that you want. + +The value of the array reference is the current value of that array +element. For example, @code{foo[4.3]} is an expression for the element +of array @code{foo} at index 4.3. + +If you refer to an array element that has no recorded value, the value +of the reference is @code{""}, the null string. This includes elements +to which you have not assigned any value, and elements that have been +deleted (@pxref{Delete, ,The @code{delete} Statement}). Such a reference +automatically creates that array element, with the null string as its value. +(In some cases, this is unfortunate, because it might waste memory inside +@code{awk}). + +@cindex arrays, presence of elements +You can find out if an element exists in an array at a certain index with +the expression: + +@example +@var{index} in @var{array} +@end example + +@noindent +This expression tests whether or not the particular index exists, +without the side effect of creating that element if it is not present. +The expression has the value 1 (true) if @code{@var{array}[@var{index}]} +exists, and 0 (false) if it does not exist.@refill + +For example, to test whether the array @code{frequencies} contains the +index @code{"2"}, you could write this statement:@refill + +@smallexample +if ("2" in frequencies) print "Subscript \"2\" is present." +@end smallexample + +Note that this is @emph{not} a test of whether or not the array +@code{frequencies} contains an element whose @emph{value} is @code{"2"}. +(There is no way to do that except to scan all the elements.) Also, this +@emph{does not} create @code{frequencies["2"]}, while the following +(incorrect) alternative would do so:@refill + +@smallexample +if (frequencies["2"] != "") print "Subscript \"2\" is present." +@end smallexample + +@node Assigning Elements, Array Example, Reference to Elements, Arrays +@section Assigning Array Elements +@cindex array assignment +@cindex element assignment + +Array elements are lvalues: they can be assigned values just like +@code{awk} variables: + +@example +@var{array}[@var{subscript}] = @var{value} +@end example + +@noindent +Here @var{array} is the name of your array. The expression +@var{subscript} is the index of the element of the array that you want +to assign a value. The expression @var{value} is the value you are +assigning to that element of the array.@refill + +@node Array Example, Scanning an Array, Assigning Elements, Arrays +@section Basic Example of an Array + +The following program takes a list of lines, each beginning with a line +number, and prints them out in order of line number. The line numbers are +not in order, however, when they are first read: they are scrambled. This +program sorts the lines by making an array using the line numbers as +subscripts. It then prints out the lines in sorted order of their numbers. +It is a very simple program, and gets confused if it encounters repeated +numbers, gaps, or lines that don't begin with a number.@refill + +@example +@{ + if ($1 > max) + max = $1 + arr[$1] = $0 +@} + +END @{ + for (x = 1; x <= max; x++) + print arr[x] +@} +@end example + +The first rule keeps track of the largest line number seen so far; +it also stores each line into the array @code{arr}, at an index that +is the line's number. + +The second rule runs after all the input has been read, to print out +all the lines. + +When this program is run with the following input: + +@example +5 I am the Five man +2 Who are you? The new number two! +4 . . . And four on the floor +1 Who is number one? +3 I three you. +@end example + +@noindent +its output is this: + +@example +1 Who is number one? +2 Who are you? The new number two! +3 I three you. +4 . . . And four on the floor +5 I am the Five man +@end example + +If a line number is repeated, the last line with a given number overrides +the others. + +Gaps in the line numbers can be handled with an easy improvement to the +program's @code{END} rule: + +@example +END @{ + for (x = 1; x <= max; x++) + if (x in arr) + print arr[x] +@} +@end example + +@node Scanning an Array, Delete, Array Example, Arrays +@section Scanning all Elements of an Array +@cindex @code{for (x in @dots{})} +@cindex arrays, special @code{for} statement +@cindex scanning an array + +In programs that use arrays, often you need a loop that executes +once for each element of an array. In other languages, where arrays are +contiguous and indices are limited to positive integers, this is +easy: the largest index is one less than the length of the array, and you can +find all the valid indices by counting from zero up to that value. This +technique won't do the job in @code{awk}, since any number or string +may be an array index. So @code{awk} has a special kind of @code{for} +statement for scanning an array: + +@example +for (@var{var} in @var{array}) + @var{body} +@end example + +@noindent +This loop executes @var{body} once for each different value that your +program has previously used as an index in @var{array}, with the +variable @var{var} set to that index.@refill + +Here is a program that uses this form of the @code{for} statement. The +first rule scans the input records and notes which words appear (at +least once) in the input, by storing a 1 into the array @code{used} with +the word as index. The second rule scans the elements of @code{used} to +find all the distinct words that appear in the input. It prints each +word that is more than 10 characters long, and also prints the number of +such words. @xref{Built-in, ,Built-in Functions}, for more information +on the built-in function @code{length}. + +@smallexample +# Record a 1 for each word that is used at least once. +@{ + for (i = 1; i <= NF; i++) + used[$i] = 1 +@} + +# Find number of distinct words more than 10 characters long. +END @{ + for (x in used) + if (length(x) > 10) @{ + ++num_long_words + print x + @} + print num_long_words, "words longer than 10 characters" +@} +@end smallexample + +@noindent +@xref{Sample Program}, for a more detailed example of this type. + +The order in which elements of the array are accessed by this statement +is determined by the internal arrangement of the array elements within +@code{awk} and cannot be controlled or changed. This can lead to +problems if new elements are added to @var{array} by statements in +@var{body}; you cannot predict whether or not the @code{for} loop will +reach them. Similarly, changing @var{var} inside the loop can produce +strange results. It is best to avoid such things.@refill + +@node Delete, Numeric Array Subscripts, Scanning an Array, Arrays +@section The @code{delete} Statement +@cindex @code{delete} statement +@cindex deleting elements of arrays +@cindex removing elements of arrays +@cindex arrays, deleting an element + +You can remove an individual element of an array using the @code{delete} +statement: + +@example +delete @var{array}[@var{index}] +@end example + +You can not refer to an array element after it has been deleted; +it is as if you had never referred +to it and had never given it any value. You can no longer obtain any +value the element once had. + +Here is an example of deleting elements in an array: + +@example +for (i in frequencies) + delete frequencies[i] +@end example + +@noindent +This example removes all the elements from the array @code{frequencies}. + +If you delete an element, a subsequent @code{for} statement to scan the array +will not report that element, and the @code{in} operator to check for +the presence of that element will return 0: + +@example +delete foo[4] +if (4 in foo) + print "This will never be printed" +@end example + +It is not an error to delete an element which does not exist. + +@node Numeric Array Subscripts, Multi-dimensional, Delete, Arrays +@section Using Numbers to Subscript Arrays + +An important aspect of arrays to remember is that array subscripts +are @emph{always} strings. If you use a numeric value as a subscript, +it will be converted to a string value before it is used for subscripting +(@pxref{Conversion, ,Conversion of Strings and Numbers}). + +@cindex conversions, during subscripting +@cindex numbers, used as subscripts +@vindex CONVFMT +This means that the value of the @code{CONVFMT} can potentially +affect how your program accesses elements of an array. For example: + +@example +a = b = 12.153 +data[a] = 1 +CONVFMT = "%2.2f" +if (b in data) + printf "%s is in data", b +else + printf "%s is not in data", b +@end example + +@noindent +should print @samp{12.15 is not in data}. The first statement gives +both @code{a} and @code{b} the same numeric value. Assigning to +@code{data[a]} first gives @code{a} the string value @code{"12.153"} +(using the default conversion value of @code{CONVFMT}, @code{"%.6g"}), +and then assigns 1 to @code{data["12.153"]}. The program then changes +the value of @code{CONVFMT}. The test @samp{(b in data)} forces @code{b} +to be converted to a string, this time @code{"12.15"}, since the value of +@code{CONVFMT} only allows two significant digits. This test fails, +since @code{"12.15"} is a different string from @code{"12.153"}.@refill + +According to the rules for conversions +(@pxref{Conversion, ,Conversion of Strings and Numbers}), integer +values are always converted to strings as integers, no matter what the +value of @code{CONVFMT} may happen to be. So the usual case of@refill + +@example +for (i = 1; i <= maxsub; i++) + @i{do something with} array[i] +@end example + +@noindent +will work, no matter what the value of @code{CONVFMT}. + +Like many things in @code{awk}, the majority of the time things work +as you would expect them to work. But it is useful to have a precise +knowledge of the actual rules, since sometimes they can have a subtle +effect on your programs. + +@node Multi-dimensional, Multi-scanning, Numeric Array Subscripts, Arrays +@section Multi-dimensional Arrays + +@c the following index entry is an overfull hbox. --mew 30jan1992 +@cindex subscripts in arrays +@cindex arrays, multi-dimensional subscripts +@cindex multi-dimensional subscripts +A multi-dimensional array is an array in which an element is identified +by a sequence of indices, not a single index. For example, a +two-dimensional array requires two indices. The usual way (in most +languages, including @code{awk}) to refer to an element of a +two-dimensional array named @code{grid} is with +@code{grid[@var{x},@var{y}]}. + +@vindex SUBSEP +Multi-dimensional arrays are supported in @code{awk} through +concatenation of indices into one string. What happens is that +@code{awk} converts the indices into strings +(@pxref{Conversion, ,Conversion of Strings and Numbers}) and +concatenates them together, with a separator between them. This creates +a single string that describes the values of the separate indices. The +combined string is used as a single index into an ordinary, +one-dimensional array. The separator used is the value of the built-in +variable @code{SUBSEP}.@refill + +For example, suppose we evaluate the expression @code{foo[5,12]="value"} +when the value of @code{SUBSEP} is @code{"@@"}. The numbers 5 and 12 are +converted to strings and +concatenated with an @samp{@@} between them, yielding @code{"5@@12"}; thus, +the array element @code{foo["5@@12"]} is set to @code{"value"}.@refill + +Once the element's value is stored, @code{awk} has no record of whether +it was stored with a single index or a sequence of indices. The two +expressions @code{foo[5,12]} and @w{@code{foo[5 SUBSEP 12]}} always have +the same value. + +The default value of @code{SUBSEP} is the string @code{"\034"}, +which contains a nonprinting character that is unlikely to appear in an +@code{awk} program or in the input data. + +The usefulness of choosing an unlikely character comes from the fact +that index values that contain a string matching @code{SUBSEP} lead to +combined strings that are ambiguous. Suppose that @code{SUBSEP} were +@code{"@@"}; then @w{@code{foo["a@@b", "c"]}} and @w{@code{foo["a", +"b@@c"]}} would be indistinguishable because both would actually be +stored as @code{foo["a@@b@@c"]}. Because @code{SUBSEP} is +@code{"\034"}, such confusion can arise only when an index +contains the character with ASCII code 034, which is a rare +event.@refill + +You can test whether a particular index-sequence exists in a +``multi-dimensional'' array with the same operator @code{in} used for single +dimensional arrays. Instead of a single index as the left-hand operand, +write the whole sequence of indices, separated by commas, in +parentheses:@refill + +@example +(@var{subscript1}, @var{subscript2}, @dots{}) in @var{array} +@end example + +The following example treats its input as a two-dimensional array of +fields; it rotates this array 90 degrees clockwise and prints the +result. It assumes that all lines have the same number of +elements. + +@example +awk '@{ + if (max_nf < NF) + max_nf = NF + max_nr = NR + for (x = 1; x <= NF; x++) + vector[x, NR] = $x +@} + +END @{ + for (x = 1; x <= max_nf; x++) @{ + for (y = max_nr; y >= 1; --y) + printf("%s ", vector[x, y]) + printf("\n") + @} +@}' +@end example + +@noindent +When given the input: + +@example +@group +1 2 3 4 5 6 +2 3 4 5 6 1 +3 4 5 6 1 2 +4 5 6 1 2 3 +@end group +@end example + +@noindent +it produces: + +@example +@group +4 3 2 1 +5 4 3 2 +6 5 4 3 +1 6 5 4 +2 1 6 5 +3 2 1 6 +@end group +@end example + +@node Multi-scanning, , Multi-dimensional, Arrays +@section Scanning Multi-dimensional Arrays + +There is no special @code{for} statement for scanning a +``multi-dimensional'' array; there cannot be one, because in truth there +are no multi-dimensional arrays or elements; there is only a +multi-dimensional @emph{way of accessing} an array. + +However, if your program has an array that is always accessed as +multi-dimensional, you can get the effect of scanning it by combining +the scanning @code{for} statement +(@pxref{Scanning an Array, ,Scanning all Elements of an Array}) with the +@code{split} built-in function +(@pxref{String Functions, ,Built-in Functions for String Manipulation}). +It works like this:@refill + +@example +for (combined in @var{array}) @{ + split(combined, separate, SUBSEP) + @dots{} +@} +@end example + +@noindent +This finds each concatenated, combined index in the array, and splits it +into the individual indices by breaking it apart where the value of +@code{SUBSEP} appears. The split-out indices become the elements of +the array @code{separate}. + +Thus, suppose you have previously stored in @code{@var{array}[1, +"foo"]}; then an element with index @code{"1\034foo"} exists in +@var{array}. (Recall that the default value of @code{SUBSEP} contains +the character with code 034.) Sooner or later the @code{for} statement +will find that index and do an iteration with @code{combined} set to +@code{"1\034foo"}. Then the @code{split} function is called as +follows: + +@example +split("1\034foo", separate, "\034") +@end example + +@noindent +The result of this is to set @code{separate[1]} to 1 and @code{separate[2]} +to @code{"foo"}. Presto, the original sequence of separate indices has +been recovered. + +@node Built-in, User-defined, Arrays, Top +@chapter Built-in Functions + +@cindex built-in functions +@dfn{Built-in} functions are functions that are always available for +your @code{awk} program to call. This chapter defines all the built-in +functions in @code{awk}; some of them are mentioned in other sections, +but they are summarized here for your convenience. (You can also define +new functions yourself. @xref{User-defined, ,User-defined Functions}.) + +@menu +* Calling Built-in:: How to call built-in functions. +* Numeric Functions:: Functions that work with numbers, + including @code{int}, @code{sin} and @code{rand}. +* String Functions:: Functions for string manipulation, + such as @code{split}, @code{match}, and @code{sprintf}. +* I/O Functions:: Functions for files and shell commands. +* Time Functions:: Functions for dealing with time stamps. +@end menu + +@node Calling Built-in, Numeric Functions, Built-in, Built-in +@section Calling Built-in Functions + +To call a built-in function, write the name of the function followed +by arguments in parentheses. For example, @code{atan2(y + z, 1)} +is a call to the function @code{atan2}, with two arguments. + +Whitespace is ignored between the built-in function name and the +open-parenthesis, but we recommend that you avoid using whitespace +there. User-defined functions do not permit whitespace in this way, and +you will find it easier to avoid mistakes by following a simple +convention which always works: no whitespace after a function name. + +Each built-in function accepts a certain number of arguments. In most +cases, any extra arguments given to built-in functions are ignored. The +defaults for omitted arguments vary from function to function and are +described under the individual functions. + +When a function is called, expressions that create the function's actual +parameters are evaluated completely before the function call is performed. +For example, in the code fragment: + +@example +i = 4 +j = sqrt(i++) +@end example + +@noindent +the variable @code{i} is set to 5 before @code{sqrt} is called +with a value of 4 for its actual parameter. + +@node Numeric Functions, String Functions, Calling Built-in, Built-in +@section Numeric Built-in Functions +@c I didn't make all the examples small because a couple of them were +@c short already. --mew 29jan1992 + +Here is a full list of built-in functions that work with numbers: + +@table @code +@item int(@var{x}) +This gives you the integer part of @var{x}, truncated toward 0. This +produces the nearest integer to @var{x}, located between @var{x} and 0. + +For example, @code{int(3)} is 3, @code{int(3.9)} is 3, @code{int(-3.9)} +is @minus{}3, and @code{int(-3)} is @minus{}3 as well.@refill + +@item sqrt(@var{x}) +This gives you the positive square root of @var{x}. It reports an error +if @var{x} is negative. Thus, @code{sqrt(4)} is 2.@refill + +@item exp(@var{x}) +This gives you the exponential of @var{x}, or reports an error if +@var{x} is out of range. The range of values @var{x} can have depends +on your machine's floating point representation.@refill + +@item log(@var{x}) +This gives you the natural logarithm of @var{x}, if @var{x} is positive; +otherwise, it reports an error.@refill + +@item sin(@var{x}) +This gives you the sine of @var{x}, with @var{x} in radians. + +@item cos(@var{x}) +This gives you the cosine of @var{x}, with @var{x} in radians. + +@item atan2(@var{y}, @var{x}) +This gives you the arctangent of @code{@var{y} / @var{x}} in radians. + +@item rand() +This gives you a random number. The values of @code{rand} are +uniformly-distributed between 0 and 1. The value is never 0 and never +1. + +Often you want random integers instead. Here is a user-defined function +you can use to obtain a random nonnegative integer less than @var{n}: + +@example +function randint(n) @{ + return int(n * rand()) +@} +@end example + +@noindent +The multiplication produces a random real number greater than 0 and less +than @var{n}. We then make it an integer (using @code{int}) between 0 +and @code{@var{n} @minus{} 1}. + +Here is an example where a similar function is used to produce +random integers between 1 and @var{n}. Note that this program will +print a new random number for each input record. + +@smallexample +awk ' +# Function to roll a simulated die. +function roll(n) @{ return 1 + int(rand() * n) @} + +# Roll 3 six-sided dice and print total number of points. +@{ + printf("%d points\n", roll(6)+roll(6)+roll(6)) +@}' +@end smallexample + +@strong{Note:} @code{rand} starts generating numbers from the same +point, or @dfn{seed}, each time you run @code{awk}. This means that +a program will produce the same results each time you run it. +The numbers are random within one @code{awk} run, but predictable +from run to run. This is convenient for debugging, but if you want +a program to do different things each time it is used, you must change +the seed to a value that will be different in each run. To do this, +use @code{srand}. + +@item srand(@var{x}) +The function @code{srand} sets the starting point, or @dfn{seed}, +for generating random numbers to the value @var{x}. + +Each seed value leads to a particular sequence of ``random'' numbers. +Thus, if you set the seed to the same value a second time, you will get +the same sequence of ``random'' numbers again. + +If you omit the argument @var{x}, as in @code{srand()}, then the current +date and time of day are used for a seed. This is the way to get random +numbers that are truly unpredictable. + +The return value of @code{srand} is the previous seed. This makes it +easy to keep track of the seeds for use in consistently reproducing +sequences of random numbers. +@end table + +@node String Functions, I/O Functions, Numeric Functions, Built-in +@section Built-in Functions for String Manipulation + +The functions in this section look at or change the text of one or more +strings. + +@table @code +@item index(@var{in}, @var{find}) +@findex match +This searches the string @var{in} for the first occurrence of the string +@var{find}, and returns the position in characters where that occurrence +begins in the string @var{in}. For example:@refill + +@smallexample +awk 'BEGIN @{ print index("peanut", "an") @}' +@end smallexample + +@noindent +prints @samp{3}. If @var{find} is not found, @code{index} returns 0. +(Remember that string indices in @code{awk} start at 1.) + +@item length(@var{string}) +@findex length +This gives you the number of characters in @var{string}. If +@var{string} is a number, the length of the digit string representing +that number is returned. For example, @code{length("abcde")} is 5. By +contrast, @code{length(15 * 35)} works out to 3. How? Well, 15 * 35 = +525, and 525 is then converted to the string @samp{"525"}, which has +three characters. + +If no argument is supplied, @code{length} returns the length of @code{$0}. + +In older versions of @code{awk}, you could call the @code{length} function +without any parentheses. Doing so is marked as ``deprecated'' in the +@sc{posix} standard. This means that while you can do this in your +programs, it is a feature that can eventually be removed from a future +version of the standard. Therefore, for maximal portability of your +@code{awk} programs you should always supply the parentheses. + +@item match(@var{string}, @var{regexp}) +@findex match +The @code{match} function searches the string, @var{string}, for the +longest, leftmost substring matched by the regular expression, +@var{regexp}. It returns the character position, or @dfn{index}, of +where that substring begins (1, if it starts at the beginning of +@var{string}). If no match if found, it returns 0. + +@vindex RSTART +@vindex RLENGTH +The @code{match} function sets the built-in variable @code{RSTART} to +the index. It also sets the built-in variable @code{RLENGTH} to the +length in characters of the matched substring. If no match is found, +@code{RSTART} is set to 0, and @code{RLENGTH} to @minus{}1. + +For example: + +@smallexample +awk '@{ + if ($1 == "FIND") + regex = $2 + else @{ + where = match($0, regex) + if (where) + print "Match of", regex, "found at", where, "in", $0 + @} +@}' +@end smallexample + +@noindent +This program looks for lines that match the regular expression stored in +the variable @code{regex}. This regular expression can be changed. If the +first word on a line is @samp{FIND}, @code{regex} is changed to be the +second word on that line. Therefore, given: + +@smallexample +FIND fo*bar +My program was a foobar +But none of it would doobar +FIND Melvin +JF+KM +This line is property of The Reality Engineering Co. +This file created by Melvin. +@end smallexample + +@noindent +@code{awk} prints: + +@smallexample +Match of fo*bar found at 18 in My program was a foobar +Match of Melvin found at 26 in This file created by Melvin. +@end smallexample + +@item split(@var{string}, @var{array}, @var{fieldsep}) +@findex split +This divides @var{string} into pieces separated by @var{fieldsep}, +and stores the pieces in @var{array}. The first piece is stored in +@code{@var{array}[1]}, the second piece in @code{@var{array}[2]}, and so +forth. The string value of the third argument, @var{fieldsep}, is +a regexp describing where to split @var{string} (much as @code{FS} can +be a regexp describing where to split input records). If +the @var{fieldsep} is omitted, the value of @code{FS} is used. +@code{split} returns the number of elements created.@refill + +The @code{split} function, then, splits strings into pieces in a +manner similar to the way input lines are split into fields. For example: + +@smallexample +split("auto-da-fe", a, "-") +@end smallexample + +@noindent +splits the string @samp{auto-da-fe} into three fields using @samp{-} as the +separator. It sets the contents of the array @code{a} as follows: + +@smallexample +a[1] = "auto" +a[2] = "da" +a[3] = "fe" +@end smallexample + +@noindent +The value returned by this call to @code{split} is 3. + +As with input field-splitting, when the value of @var{fieldsep} is +@code{" "}, leading and trailing whitespace is ignored, and the elements +are separated by runs of whitespace. + +@item sprintf(@var{format}, @var{expression1},@dots{}) +@findex sprintf +This returns (without printing) the string that @code{printf} would +have printed out with the same arguments +(@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing}). +For example:@refill + +@smallexample +sprintf("pi = %.2f (approx.)", 22/7) +@end smallexample + +@noindent +returns the string @w{@code{"pi = 3.14 (approx.)"}}. + +@item sub(@var{regexp}, @var{replacement}, @var{target}) +@findex sub +The @code{sub} function alters the value of @var{target}. +It searches this value, which should be a string, for the +leftmost substring matched by the regular expression, @var{regexp}, +extending this match as far as possible. Then the entire string is +changed by replacing the matched text with @var{replacement}. +The modified string becomes the new value of @var{target}. + +This function is peculiar because @var{target} is not simply +used to compute a value, and not just any expression will do: it +must be a variable, field or array reference, so that @code{sub} can +store a modified value there. If this argument is omitted, then the +default is to use and alter @code{$0}. + +For example:@refill + +@smallexample +str = "water, water, everywhere" +sub(/at/, "ith", str) +@end smallexample + +@noindent +sets @code{str} to @w{@code{"wither, water, everywhere"}}, by replacing the +leftmost, longest occurrence of @samp{at} with @samp{ith}. + +The @code{sub} function returns the number of substitutions made (either +one or zero). + +If the special character @samp{&} appears in @var{replacement}, it +stands for the precise substring that was matched by @var{regexp}. (If +the regexp can match more than one string, then this precise substring +may vary.) For example:@refill + +@smallexample +awk '@{ sub(/candidate/, "& and his wife"); print @}' +@end smallexample + +@noindent +changes the first occurrence of @samp{candidate} to @samp{candidate +and his wife} on each input line. + +Here is another example: + +@smallexample +awk 'BEGIN @{ + str = "daabaaa" + sub(/a*/, "c&c", str) + print str +@}' +@end smallexample + +@noindent +prints @samp{dcaacbaaa}. This show how @samp{&} can represent a non-constant +string, and also illustrates the ``leftmost, longest'' rule. + +The effect of this special character (@samp{&}) can be turned off by putting a +backslash before it in the string. As usual, to insert one backslash in +the string, you must write two backslashes. Therefore, write @samp{\\&} +in a string constant to include a literal @samp{&} in the replacement. +For example, here is how to replace the first @samp{|} on each line with +an @samp{&}:@refill + +@smallexample +awk '@{ sub(/\|/, "\\&"); print @}' +@end smallexample + +@strong{Note:} as mentioned above, the third argument to @code{sub} must +be an lvalue. Some versions of @code{awk} allow the third argument to +be an expression which is not an lvalue. In such a case, @code{sub} +would still search for the pattern and return 0 or 1, but the result of +the substitution (if any) would be thrown away because there is no place +to put it. Such versions of @code{awk} accept expressions like +this:@refill + +@smallexample +sub(/USA/, "United States", "the USA and Canada") +@end smallexample + +@noindent +But that is considered erroneous in @code{gawk}. + +@item gsub(@var{regexp}, @var{replacement}, @var{target}) +@findex gsub +This is similar to the @code{sub} function, except @code{gsub} replaces +@emph{all} of the longest, leftmost, @emph{nonoverlapping} matching +substrings it can find. The @samp{g} in @code{gsub} stands for +``global,'' which means replace everywhere. For example:@refill + +@smallexample +awk '@{ gsub(/Britain/, "United Kingdom"); print @}' +@end smallexample + +@noindent +replaces all occurrences of the string @samp{Britain} with @samp{United +Kingdom} for all input records.@refill + +The @code{gsub} function returns the number of substitutions made. If +the variable to be searched and altered, @var{target}, is +omitted, then the entire input record, @code{$0}, is used.@refill + +As in @code{sub}, the characters @samp{&} and @samp{\} are special, and +the third argument must be an lvalue. + +@item substr(@var{string}, @var{start}, @var{length}) +@findex substr +This returns a @var{length}-character-long substring of @var{string}, +starting at character number @var{start}. The first character of a +string is character number one. For example, +@code{substr("washington", 5, 3)} returns @code{"ing"}.@refill + +If @var{length} is not present, this function returns the whole suffix of +@var{string} that begins at character number @var{start}. For example, +@code{substr("washington", 5)} returns @code{"ington"}. This is also +the case if @var{length} is greater than the number of characters remaining +in the string, counting from character number @var{start}. + +@item tolower(@var{string}) +@findex tolower +This returns a copy of @var{string}, with each upper-case character +in the string replaced with its corresponding lower-case character. +Nonalphabetic characters are left unchanged. For example, +@code{tolower("MiXeD cAsE 123")} returns @code{"mixed case 123"}. + +@item toupper(@var{string}) +@findex toupper +This returns a copy of @var{string}, with each lower-case character +in the string replaced with its corresponding upper-case character. +Nonalphabetic characters are left unchanged. For example, +@code{toupper("MiXeD cAsE 123")} returns @code{"MIXED CASE 123"}. +@end table + +@node I/O Functions, Time Functions, String Functions, Built-in +@section Built-in Functions for Input/Output + +@table @code +@item close(@var{filename}) +Close the file @var{filename}, for input or output. The argument may +alternatively be a shell command that was used for redirecting to or +from a pipe; then the pipe is closed. + +@xref{Close Input, ,Closing Input Files and Pipes}, regarding closing +input files and pipes. @xref{Close Output, ,Closing Output Files and Pipes}, +regarding closing output files and pipes.@refill + +@item system(@var{command}) +@findex system +@c the following index entry is an overfull hbox. --mew 30jan1992 +@cindex interaction, @code{awk} and other programs +The system function allows the user to execute operating system commands +and then return to the @code{awk} program. The @code{system} function +executes the command given by the string @var{command}. It returns, as +its value, the status returned by the command that was executed. + +For example, if the following fragment of code is put in your @code{awk} +program: + +@smallexample +END @{ + system("mail -s 'awk run done' operator < /dev/null") +@} +@end smallexample + +@noindent +the system operator will be sent mail when the @code{awk} program +finishes processing input and begins its end-of-input processing. + +Note that much the same result can be obtained by redirecting +@code{print} or @code{printf} into a pipe. However, if your @code{awk} +program is interactive, @code{system} is useful for cranking up large +self-contained programs, such as a shell or an editor.@refill + +Some operating systems cannot implement the @code{system} function. +@code{system} causes a fatal error if it is not supported. +@end table + +@c fakenode --- for prepinfo +@subheading Controlling Output Buffering with @code{system} +@cindex flushing buffers +@cindex buffers, flushing +@cindex buffering output +@cindex output, buffering + +Many utility programs will @dfn{buffer} their output; they save information +to be written to a disk file or terminal in memory, until there is enough +to be written in one operation. This is often more efficient than writing +every little bit of information as soon as it is ready. However, sometimes +it is necessary to force a program to @dfn{flush} its buffers; that is, +write the information to its destination, even if a buffer is not full. +You can do this from your @code{awk} program by calling @code{system} +with a null string as its argument: + +@example +system("") # flush output +@end example + +@noindent +@code{gawk} treats this use of the @code{system} function as a special +case, and is smart enough not to run a shell (or other command +interpreter) with the empty command. Therefore, with @code{gawk}, this +idiom is not only useful, it is efficient. While this idiom should work +with other @code{awk} implementations, it will not necessarily avoid +starting an unnecessary shell. +@ignore +Need a better explanation, perhaps in a separate paragraph. Explain that +for + +awk 'BEGIN { print "hi" + system("echo hello") + print "howdy" }' + +that the output had better be + + hi + hello + howdy + +and not + + hello + hi + howdy + +which it would be if awk did not flush its buffers before calling system. +@end ignore + +@node Time Functions, , I/O Functions, Built-in +@section Functions for Dealing with Time Stamps + +@cindex time stamps +@cindex time of day +A common use for @code{awk} programs is the processing of log files. +Log files often contain time stamp information, indicating when a +particular log record was written. Many programs log their time stamp +in the form returned by the @code{time} system call, which is the +number of seconds since a particular epoch. On @sc{posix} systems, +it is the number of seconds since Midnight, January 1, 1970, @sc{utc}. + +In order to make it easier to process such log files, and to easily produce +useful reports, @code{gawk} provides two functions for working with time +stamps. Both of these are @code{gawk} extensions; they are not specified +in the @sc{posix} standard, nor are they in any other known version +of @code{awk}. + +@table @code +@item systime() +@findex systime +This function returns the current time as the number of seconds since +the system epoch. On @sc{posix} systems, this is the number of seconds +since Midnight, January 1, 1970, @sc{utc}. It may be a different number on +other systems. + +@item strftime(@var{format}, @var{timestamp}) +@findex strftime +This function returns a string. It is similar to the function of the +same name in the @sc{ansi} C standard library. The time specified by +@var{timestamp} is used to produce a string, based on the contents +of the @var{format} string. +@end table + +The @code{systime} function allows you to compare a time stamp from a +log file with the current time of day. In particular, it is easy to +determine how long ago a particular record was logged. It also allows +you to produce log records using the ``seconds since the epoch'' format. + +The @code{strftime} function allows you to easily turn a time stamp +into human-readable information. It is similar in nature to the @code{sprintf} +function, copying non-format specification characters verbatim to the +returned string, and substituting date and time values for format +specifications in the @var{format} string. If no @var{timestamp} argument +is supplied, @code{gawk} will use the current time of day as the +time stamp.@refill + +@code{strftime} is guaranteed by the @sc{ansi} C standard to support +the following date format specifications: + +@table @code +@item %a +The locale's abbreviated weekday name. + +@item %A +The locale's full weekday name. + +@item %b +The locale's abbreviated month name. + +@item %B +The locale's full month name. + +@item %c +The locale's ``appropriate'' date and time representation. + +@item %d +The day of the month as a decimal number (01--31). + +@item %H +The hour (24-hour clock) as a decimal number (00--23). + +@item %I +The hour (12-hour clock) as a decimal number (01--12). + +@item %j +The day of the year as a decimal number (001--366). + +@item %m +The month as a decimal number (01--12). + +@item %M +The minute as a decimal number (00--59). + +@item %p +The locale's equivalent of the AM/PM designations associated +with a 12-hour clock. + +@item %S +The second as a decimal number (00--61). (Occasionally there are +minutes in a year with one or two leap seconds, which is why the +seconds can go from 0 all the way to 61.) + +@item %U +The week number of the year (the first Sunday as the first day of week 1) +as a decimal number (00--53). + +@item %w +The weekday as a decimal number (0--6). Sunday is day 0. + +@item %W +The week number of the year (the first Monday as the first day of week 1) +as a decimal number (00--53). + +@item %x +The locale's ``appropriate'' date representation. + +@item %X +The locale's ``appropriate'' time representation. + +@item %y +The year without century as a decimal number (00--99). + +@item %Y +The year with century as a decimal number. + +@item %Z +The time zone name or abbreviation, or no characters if +no time zone is determinable. + +@item %% +A literal @samp{%}. +@end table + +@c The parenthetical remark here should really be a footnote, but +@c it gave formatting problems at the FSF. So for now put it in +@c parentheses. +If a conversion specifier is not one of the above, the behavior is +undefined. (This is because the @sc{ansi} standard for C leaves the +behavior of the C version of @code{strftime} undefined, and @code{gawk} +will use the system's version of @code{strftime} if it's there. +Typically, the conversion specifier will either not appear in the +returned string, or it will appear literally.) + +Informally, a @dfn{locale} is the geographic place in which a program +is meant to run. For example, a common way to abbreviate the date +September 4, 1991 in the United States would be ``9/4/91''. +In many countries in Europe, however, it would be abbreviated ``4.9.91''. +Thus, the @samp{%x} specification in a @code{"US"} locale might produce +@samp{9/4/91}, while in a @code{"EUROPE"} locale, it might produce +@samp{4.9.91}. The @sc{ansi} C standard defines a default @code{"C"} +locale, which is an environment that is typical of what most C programmers +are used to. + +A public-domain C version of @code{strftime} is shipped with @code{gawk} +for systems that are not yet fully @sc{ansi}-compliant. If that version is +used to compile @code{gawk} (@pxref{Installation, ,Installing @code{gawk}}), +then the following additional format specifications are available:@refill + +@table @code +@item %D +Equivalent to specifying @samp{%m/%d/%y}. + +@item %e +The day of the month, padded with a blank if it is only one digit. + +@item %h +Equivalent to @samp{%b}, above. + +@item %n +A newline character (ASCII LF). + +@item %r +Equivalent to specifying @samp{%I:%M:%S %p}. + +@item %R +Equivalent to specifying @samp{%H:%M}. + +@item %T +Equivalent to specifying @samp{%H:%M:%S}. + +@item %t +A TAB character. + +@item %k +is replaced by the hour (24-hour clock) as a decimal number (0-23). +Single digit numbers are padded with a blank. + +@item %l +is replaced by the hour (12-hour clock) as a decimal number (1-12). +Single digit numbers are padded with a blank. + +@item %C +The century, as a number between 00 and 99. + +@item %u +is replaced by the weekday as a decimal number +[1 (Monday)--7]. + +@item %V +is replaced by the week number of the year (the first Monday as the first +day of week 1) as a decimal number (01--53). +The method for determining the week number is as specified by ISO 8601 +(to wit: if the week containing January 1 has four or more days in the +new year, then it is week 1, otherwise it is week 53 of the previous year +and the next week is week 1).@refill + +@item %Ec %EC %Ex %Ey %EY %Od %Oe %OH %OI +@itemx %Om %OM %OS %Ou %OU %OV %Ow %OW %Oy +These are ``alternate representations'' for the specifications +that use only the second letter (@samp{%c}, @samp{%C}, and so on). +They are recognized, but their normal representations are used. +(These facilitate compliance with the @sc{posix} @code{date} +utility.)@refill + +@item %v +The date in VMS format (e.g. 20-JUN-1991). +@end table + +Here are two examples that use @code{strftime}. The first is an +@code{awk} version of the C @code{ctime} function. (This is a +user defined function, which we have not discussed yet. +@xref{User-defined, ,User-defined Functions}, for more information.) + +@smallexample +# ctime.awk +# +# awk version of C ctime(3) function + +function ctime(ts, format) +@{ + format = "%a %b %e %H:%M:%S %Z %Y" + if (ts == 0) + ts = systime() # use current time as default + return strftime(format, ts) +@} +@end smallexample + +This next example is an @code{awk} implementation of the @sc{posix} +@code{date} utility. Normally, the @code{date} utility prints the +current date and time of day in a well known format. However, if you +provide an argument to it that begins with a @samp{+}, @code{date} +will copy non-format specifier characters to the standard output, and +will interpret the current time according to the format specifiers in +the string. For example: + +@smallexample +date '+Today is %A, %B %d, %Y.' +@end smallexample + +@noindent +might print + +@smallexample +Today is Thursday, July 11, 1991. +@end smallexample + +Here is the @code{awk} version of the @code{date} utility. + +@smallexample +#! /usr/bin/gawk -f +# +# date --- implement the P1003.2 Draft 11 'date' command +# +# Bug: does not recognize the -u argument. + +BEGIN \ +@{ + format = "%a %b %e %H:%M:%S %Z %Y" + exitval = 0 + + if (ARGC > 2) + exitval = 1 + else if (ARGC == 2) @{ + format = ARGV[1] + if (format ~ /^\+/) + format = substr(format, 2) # remove leading + + @} + print strftime(format) + exit exitval +@} +@end smallexample + +@node User-defined, Built-in Variables, Built-in, Top +@chapter User-defined Functions + +@cindex user-defined functions +@cindex functions, user-defined +Complicated @code{awk} programs can often be simplified by defining +your own functions. User-defined functions can be called just like +built-in ones (@pxref{Function Calls}), but it is up to you to define +them---to tell @code{awk} what they should do. + +@menu +* Definition Syntax:: How to write definitions and what they mean. +* Function Example:: An example function definition and + what it does. +* Function Caveats:: Things to watch out for. +* Return Statement:: Specifying the value a function returns. +@end menu + +@node Definition Syntax, Function Example, User-defined, User-defined +@section Syntax of Function Definitions +@cindex defining functions +@cindex function definition + +Definitions of functions can appear anywhere between the rules of the +@code{awk} program. Thus, the general form of an @code{awk} program is +extended to include sequences of rules @emph{and} user-defined function +definitions. + +The definition of a function named @var{name} looks like this: + +@example +function @var{name} (@var{parameter-list}) @{ + @var{body-of-function} +@} +@end example + +@noindent +@var{name} is the name of the function to be defined. A valid function +name is like a valid variable name: a sequence of letters, digits and +underscores, not starting with a digit. Functions share the same pool +of names as variables and arrays. + +@var{parameter-list} is a list of the function's arguments and local +variable names, separated by commas. When the function is called, +the argument names are used to hold the argument values given in +the call. The local variables are initialized to the null string. + +The @var{body-of-function} consists of @code{awk} statements. It is the +most important part of the definition, because it says what the function +should actually @emph{do}. The argument names exist to give the body a +way to talk about the arguments; local variables, to give the body +places to keep temporary values. + +Argument names are not distinguished syntactically from local variable +names; instead, the number of arguments supplied when the function is +called determines how many argument variables there are. Thus, if three +argument values are given, the first three names in @var{parameter-list} +are arguments, and the rest are local variables. + +It follows that if the number of arguments is not the same in all calls +to the function, some of the names in @var{parameter-list} may be +arguments on some occasions and local variables on others. Another +way to think of this is that omitted arguments default to the +null string. + +Usually when you write a function you know how many names you intend to +use for arguments and how many you intend to use as locals. By +convention, you should write an extra space between the arguments and +the locals, so other people can follow how your function is +supposed to be used. + +During execution of the function body, the arguments and local variable +values hide or @dfn{shadow} any variables of the same names used in the +rest of the program. The shadowed variables are not accessible in the +function definition, because there is no way to name them while their +names have been taken away for the local variables. All other variables +used in the @code{awk} program can be referenced or set normally in the +function definition. + +The arguments and local variables last only as long as the function body +is executing. Once the body finishes, the shadowed variables come back. + +The function body can contain expressions which call functions. They +can even call this function, either directly or by way of another +function. When this happens, we say the function is @dfn{recursive}. + +There is no need in @code{awk} to put the definition of a function +before all uses of the function. This is because @code{awk} reads the +entire program before starting to execute any of it. + +In many @code{awk} implementations, the keyword @code{function} may be +abbreviated @code{func}. However, @sc{posix} only specifies the use of +the keyword @code{function}. This actually has some practical implications. +If @code{gawk} is in @sc{posix}-compatibility mode +(@pxref{Command Line, ,Invoking @code{awk}}), then the following +statement will @emph{not} define a function:@refill + +@example +func foo() @{ a = sqrt($1) ; print a @} +@end example + +@noindent +Instead it defines a rule that, for each record, concatenates the value +of the variable @samp{func} with the return value of the function @samp{foo}, +and based on the truth value of the result, executes the corresponding action. +This is probably not what was desired. (@code{awk} accepts this input as +syntactically valid, since functions may be used before they are defined +in @code{awk} programs.) + +@node Function Example, Function Caveats, Definition Syntax, User-defined +@section Function Definition Example + +Here is an example of a user-defined function, called @code{myprint}, that +takes a number and prints it in a specific format. + +@example +function myprint(num) +@{ + printf "%6.3g\n", num +@} +@end example + +@noindent +To illustrate, here is an @code{awk} rule which uses our @code{myprint} +function: + +@example +$3 > 0 @{ myprint($3) @} +@end example + +@noindent +This program prints, in our special format, all the third fields that +contain a positive number in our input. Therefore, when given: + +@example + 1.2 3.4 5.6 7.8 + 9.10 11.12 -13.14 15.16 +17.18 19.20 21.22 23.24 +@end example + +@noindent +this program, using our function to format the results, prints: + +@example + 5.6 + 21.2 +@end example + +Here is a rather contrived example of a recursive function. It prints a +string backwards: + +@example +function rev (str, len) @{ + if (len == 0) @{ + printf "\n" + return + @} + printf "%c", substr(str, len, 1) + rev(str, len - 1) +@} +@end example + +@node Function Caveats, Return Statement, Function Example, User-defined +@section Calling User-defined Functions + +@dfn{Calling a function} means causing the function to run and do its job. +A function call is an expression, and its value is the value returned by +the function. + +A function call consists of the function name followed by the arguments +in parentheses. What you write in the call for the arguments are +@code{awk} expressions; each time the call is executed, these +expressions are evaluated, and the values are the actual arguments. For +example, here is a call to @code{foo} with three arguments (the first +being a string concatenation): + +@example +foo(x y, "lose", 4 * z) +@end example + +@quotation +@strong{Caution:} whitespace characters (spaces and tabs) are not allowed +between the function name and the open-parenthesis of the argument list. +If you write whitespace by mistake, @code{awk} might think that you mean +to concatenate a variable with an expression in parentheses. However, it +notices that you used a function name and not a variable name, and reports +an error. +@end quotation + +@cindex call by value +When a function is called, it is given a @emph{copy} of the values of +its arguments. This is called @dfn{call by value}. The caller may use +a variable as the expression for the argument, but the called function +does not know this: it only knows what value the argument had. For +example, if you write this code: + +@example +foo = "bar" +z = myfunc(foo) +@end example + +@noindent +then you should not think of the argument to @code{myfunc} as being +``the variable @code{foo}.'' Instead, think of the argument as the +string value, @code{"bar"}. + +If the function @code{myfunc} alters the values of its local variables, +this has no effect on any other variables. In particular, if @code{myfunc} +does this: + +@example +function myfunc (win) @{ + print win + win = "zzz" + print win +@} +@end example + +@noindent +to change its first argument variable @code{win}, this @emph{does not} +change the value of @code{foo} in the caller. The role of @code{foo} in +calling @code{myfunc} ended when its value, @code{"bar"}, was computed. +If @code{win} also exists outside of @code{myfunc}, the function body +cannot alter this outer value, because it is shadowed during the +execution of @code{myfunc} and cannot be seen or changed from there. + +@cindex call by reference +However, when arrays are the parameters to functions, they are @emph{not} +copied. Instead, the array itself is made available for direct manipulation +by the function. This is usually called @dfn{call by reference}. +Changes made to an array parameter inside the body of a function @emph{are} +visible outside that function. +@ifinfo +This can be @strong{very} dangerous if you do not watch what you are +doing. For example:@refill +@end ifinfo +@iftex +@emph{This can be very dangerous if you do not watch what you are +doing.} For example:@refill +@end iftex + +@example +function changeit (array, ind, nvalue) @{ + array[ind] = nvalue +@} + +BEGIN @{ + a[1] = 1 ; a[2] = 2 ; a[3] = 3 + changeit(a, 2, "two") + printf "a[1] = %s, a[2] = %s, a[3] = %s\n", a[1], a[2], a[3] + @} +@end example + +@noindent +prints @samp{a[1] = 1, a[2] = two, a[3] = 3}, because calling +@code{changeit} stores @code{"two"} in the second element of @code{a}. + +@node Return Statement, , Function Caveats, User-defined +@section The @code{return} Statement +@cindex @code{return} statement + +The body of a user-defined function can contain a @code{return} statement. +This statement returns control to the rest of the @code{awk} program. It +can also be used to return a value for use in the rest of the @code{awk} +program. It looks like this:@refill + +@example +return @var{expression} +@end example + +The @var{expression} part is optional. If it is omitted, then the returned +value is undefined and, therefore, unpredictable. + +A @code{return} statement with no value expression is assumed at the end of +every function definition. So if control reaches the end of the function +body, then the function returns an unpredictable value. @code{awk} +will not warn you if you use the return value of such a function; you will +simply get unpredictable or unexpected results. + +Here is an example of a user-defined function that returns a value +for the largest number among the elements of an array:@refill + +@example +@group +function maxelt (vec, i, ret) @{ + for (i in vec) @{ + if (ret == "" || vec[i] > ret) + ret = vec[i] + @} + return ret +@} +@end group +@end example + +@noindent +You call @code{maxelt} with one argument, which is an array name. The local +variables @code{i} and @code{ret} are not intended to be arguments; +while there is nothing to stop you from passing two or three arguments +to @code{maxelt}, the results would be strange. The extra space before +@code{i} in the function parameter list is to indicate that @code{i} and +@code{ret} are not supposed to be arguments. This is a convention which +you should follow when you define functions. + +Here is a program that uses our @code{maxelt} function. It loads an +array, calls @code{maxelt}, and then reports the maximum number in that +array:@refill + +@example +@group +awk ' +function maxelt (vec, i, ret) @{ + for (i in vec) @{ + if (ret == "" || vec[i] > ret) + ret = vec[i] + @} + return ret +@} +@end group + +@group +# Load all fields of each record into nums. +@{ + for(i = 1; i <= NF; i++) + nums[NR, i] = $i +@} + +END @{ + print maxelt(nums) +@}' +@end group +@end example + +Given the following input: + +@example +@group + 1 5 23 8 16 +44 3 5 2 8 26 +256 291 1396 2962 100 +-6 467 998 1101 +99385 11 0 225 +@end group +@end example + +@noindent +our program tells us (predictably) that: + +@example +99385 +@end example + +@noindent +is the largest number in our array. + +@node Built-in Variables, Command Line, User-defined, Top +@chapter Built-in Variables +@cindex built-in variables + +Most @code{awk} variables are available for you to use for your own +purposes; they never change except when your program assigns values to +them, and never affect anything except when your program examines them. + +A few variables have special built-in meanings. Some of them @code{awk} +examines automatically, so that they enable you to tell @code{awk} how +to do certain things. Others are set automatically by @code{awk}, so +that they carry information from the internal workings of @code{awk} to +your program. + +This chapter documents all the built-in variables of @code{gawk}. Most +of them are also documented in the chapters where their areas of +activity are described. + +@menu +* User-modified:: Built-in variables that you change + to control @code{awk}. +* Auto-set:: Built-in variables where @code{awk} + gives you information. +@end menu + +@node User-modified, Auto-set, Built-in Variables, Built-in Variables +@section Built-in Variables that Control @code{awk} +@cindex built-in variables, user modifiable + +This is a list of the variables which you can change to control how +@code{awk} does certain things. + +@table @code +@iftex +@vindex CONVFMT +@end iftex +@item CONVFMT +This string is used by @code{awk} to control conversion of numbers to +strings (@pxref{Conversion, ,Conversion of Strings and Numbers}). +It works by being passed, in effect, as the first argument to the +@code{sprintf} function. Its default value is @code{"%.6g"}. +@code{CONVFMT} was introduced by the @sc{posix} standard.@refill + +@iftex +@vindex FIELDWIDTHS +@end iftex +@item FIELDWIDTHS +This is a space separated list of columns that tells @code{gawk} +how to manage input with fixed, columnar boundaries. It is an +experimental feature that is still evolving. Assigning to @code{FIELDWIDTHS} +overrides the use of @code{FS} for field splitting. +@xref{Constant Size, ,Reading Fixed-width Data}, for more information.@refill + +If @code{gawk} is in compatibility mode +(@pxref{Command Line, ,Invoking @code{awk}}), then @code{FIELDWIDTHS} +has no special meaning, and field splitting operations are done based +exclusively on the value of @code{FS}.@refill + +@iftex +@vindex FS +@end iftex +@item FS +@code{FS} is the input field separator +(@pxref{Field Separators, ,Specifying how Fields are Separated}). +The value is a single-character string or a multi-character regular +expression that matches the separations between fields in an input +record.@refill + +The default value is @w{@code{" "}}, a string consisting of a single +space. As a special exception, this value actually means that any +sequence of spaces and tabs is a single separator. It also causes +spaces and tabs at the beginning or end of a line to be ignored. + +You can set the value of @code{FS} on the command line using the +@samp{-F} option: + +@example +awk -F, '@var{program}' @var{input-files} +@end example + +If @code{gawk} is using @code{FIELDWIDTHS} for field-splitting, +assigning a value to @code{FS} will cause @code{gawk} to return to +the normal, regexp-based, field splitting. + +@item IGNORECASE +@iftex +@vindex IGNORECASE +@end iftex +If @code{IGNORECASE} is nonzero, then @emph{all} regular expression +matching is done in a case-independent fashion. In particular, regexp +matching with @samp{~} and @samp{!~}, and the @code{gsub} @code{index}, +@code{match}, @code{split} and @code{sub} functions all ignore case when +doing their particular regexp operations. @strong{Note:} since field +splitting with the value of the @code{FS} variable is also a regular +expression operation, that too is done with case ignored. +@xref{Case-sensitivity, ,Case-sensitivity in Matching}. + +If @code{gawk} is in compatibility mode +(@pxref{Command Line, ,Invoking @code{awk}}), then @code{IGNORECASE} has +no special meaning, and regexp operations are always case-sensitive.@refill + +@item OFMT +@iftex +@vindex OFMT +@end iftex +This string is used by @code{awk} to control conversion of numbers to +strings (@pxref{Conversion, ,Conversion of Strings and Numbers}) for +printing with the @code{print} statement. +It works by being passed, in effect, as the first argument to the +@code{sprintf} function. Its default value is @code{"%.6g"}. +Earlier versions of @code{awk} also used @code{OFMT} to specify the +format for converting numbers to strings in general expressions; this +has been taken over by @code{CONVFMT}.@refill + +@item OFS +@iftex +@vindex OFS +@end iftex +This is the output field separator (@pxref{Output Separators}). It is +output between the fields output by a @code{print} statement. Its +default value is @w{@code{" "}}, a string consisting of a single space. + +@item ORS +@iftex +@vindex ORS +@end iftex +This is the output record separator. It is output at the end of every +@code{print} statement. Its default value is a string containing a +single newline character, which could be written as @code{"\n"}. +(@xref{Output Separators}.)@refill + +@item RS +@iftex +@vindex RS +@end iftex +This is @code{awk}'s input record separator. Its default value is a string +containing a single newline character, which means that an input record +consists of a single line of text. +(@xref{Records, ,How Input is Split into Records}.)@refill + +@item SUBSEP +@iftex +@vindex SUBSEP +@end iftex +@code{SUBSEP} is the subscript separator. It has the default value of +@code{"\034"}, and is used to separate the parts of the name of a +multi-dimensional array. Thus, if you access @code{foo[12,3]}, it +really accesses @code{foo["12\0343"]} +(@pxref{Multi-dimensional, ,Multi-dimensional Arrays}).@refill +@end table + +@node Auto-set, , User-modified, Built-in Variables +@section Built-in Variables that Convey Information + +This is a list of the variables that are set automatically by @code{awk} +on certain occasions so as to provide information to your program. + +@table @code +@item ARGC +@itemx ARGV +@iftex +@vindex ARGC +@vindex ARGV +@end iftex +The command-line arguments available to @code{awk} programs are stored in +an array called @code{ARGV}. @code{ARGC} is the number of command-line +arguments present. @xref{Command Line, ,Invoking @code{awk}}. +@code{ARGV} is indexed from zero to @w{@code{ARGC - 1}}. For example:@refill + +@example +awk 'BEGIN @{ + for (i = 0; i < ARGC; i++) + print ARGV[i] + @}' inventory-shipped BBS-list +@end example + +@noindent +In this example, @code{ARGV[0]} contains @code{"awk"}, @code{ARGV[1]} +contains @code{"inventory-shipped"}, and @code{ARGV[2]} contains +@code{"BBS-list"}. The value of @code{ARGC} is 3, one more than the +index of the last element in @code{ARGV} since the elements are numbered +from zero.@refill + +The names @code{ARGC} and @code{ARGV}, as well the convention of indexing +the array from 0 to @w{@code{ARGC - 1}}, are derived from the C language's +method of accessing command line arguments.@refill + +Notice that the @code{awk} program is not entered in @code{ARGV}. The +other special command line options, with their arguments, are also not +entered. But variable assignments on the command line @emph{are} +treated as arguments, and do show up in the @code{ARGV} array. + +Your program can alter @code{ARGC} and the elements of @code{ARGV}. +Each time @code{awk} reaches the end of an input file, it uses the next +element of @code{ARGV} as the name of the next input file. By storing a +different string there, your program can change which files are read. +You can use @code{"-"} to represent the standard input. By storing +additional elements and incrementing @code{ARGC} you can cause +additional files to be read. + +If you decrease the value of @code{ARGC}, that eliminates input files +from the end of the list. By recording the old value of @code{ARGC} +elsewhere, your program can treat the eliminated arguments as +something other than file names. + +To eliminate a file from the middle of the list, store the null string +(@code{""}) into @code{ARGV} in place of the file's name. As a +special feature, @code{awk} ignores file names that have been +replaced with the null string. + +@ignore +see getopt.awk in the examples... +@end ignore + +@item ARGIND +@vindex ARGIND +The index in @code{ARGV} of the current file being processed. +Every time @code{gawk} opens a new data file for processing, it sets +@code{ARGIND} to the index in @code{ARGV} of the file name. Thus, the +condition @samp{FILENAME == ARGV[ARGIND]} is always true. + +This variable is useful in file processing; it allows you to tell how far +along you are in the list of data files, and to distinguish between +multiple successive instances of the same filename on the command line. + +While you can change the value of @code{ARGIND} within your @code{awk} +program, @code{gawk} will automatically set it to a new value when the +next file is opened. + +This variable is a @code{gawk} extension; in other @code{awk} implementations +it is not special. + +@item ENVIRON +@vindex ENVIRON +This is an array that contains the values of the environment. The array +indices are the environment variable names; the values are the values of +the particular environment variables. For example, +@code{ENVIRON["HOME"]} might be @file{/u/close}. Changing this array +does not affect the environment passed on to any programs that +@code{awk} may spawn via redirection or the @code{system} function. +(In a future version of @code{gawk}, it may do so.) + +Some operating systems may not have environment variables. +On such systems, the array @code{ENVIRON} is empty. + +@item ERRNO +@iftex +@vindex ERRNO +@end iftex +If a system error occurs either doing a redirection for @code{getline}, +during a read for @code{getline}, or during a @code{close} operation, +then @code{ERRNO} will contain a string describing the error. + +This variable is a @code{gawk} extension; in other @code{awk} implementations +it is not special. + +@item FILENAME +@iftex +@vindex FILENAME +@end iftex +This is the name of the file that @code{awk} is currently reading. +If @code{awk} is reading from the standard input (in other words, +there are no files listed on the command line), +@code{FILENAME} is set to @code{"-"}. +@code{FILENAME} is changed each time a new file is read +(@pxref{Reading Files, ,Reading Input Files}).@refill + +@item FNR +@iftex +@vindex FNR +@end iftex +@code{FNR} is the current record number in the current file. @code{FNR} is +incremented each time a new record is read +(@pxref{Getline, ,Explicit Input with @code{getline}}). It is reinitialized +to 0 each time a new input file is started.@refill + +@item NF +@iftex +@vindex NF +@end iftex +@code{NF} is the number of fields in the current input record. +@code{NF} is set each time a new record is read, when a new field is +created, or when @code{$0} changes (@pxref{Fields, ,Examining Fields}).@refill + +@item NR +@iftex +@vindex NR +@end iftex +This is the number of input records @code{awk} has processed since +the beginning of the program's execution. +(@pxref{Records, ,How Input is Split into Records}). +@code{NR} is set each time a new record is read.@refill + +@item RLENGTH +@iftex +@vindex RLENGTH +@end iftex +@code{RLENGTH} is the length of the substring matched by the +@code{match} function +(@pxref{String Functions, ,Built-in Functions for String Manipulation}). +@code{RLENGTH} is set by invoking the @code{match} function. Its value +is the length of the matched string, or @minus{}1 if no match was found.@refill + +@item RSTART +@iftex +@vindex RSTART +@end iftex +@code{RSTART} is the start-index in characters of the substring matched by the +@code{match} function +(@pxref{String Functions, ,Built-in Functions for String Manipulation}). +@code{RSTART} is set by invoking the @code{match} function. Its value +is the position of the string where the matched substring starts, or 0 +if no match was found.@refill +@end table + +@node Command Line, Language History, Built-in Variables, Top +@c node-name, next, previous, up +@chapter Invoking @code{awk} +@cindex command line +@cindex invocation of @code{gawk} +@cindex arguments, command line +@cindex options, command line +@cindex long options +@cindex options, long + +There are two ways to run @code{awk}: with an explicit program, or with +one or more program files. Here are templates for both of them; items +enclosed in @samp{@r{[}@dots{}@r{]}} in these templates are optional. + +Besides traditional one-letter @sc{posix}-style options, @code{gawk} also +supports GNU long named options. + +@example +awk @r{[@var{POSIX or GNU style options}]} -f progfile @r{[@code{--}]} @var{file} @dots{} +awk @r{[@var{POSIX or GNU style options}]} @r{[@code{--}]} '@var{program}' @var{file} @dots{} +@end example + +@menu +* Options:: Command line options and their meanings. +* Other Arguments:: Input file names and variable assignments. +* AWKPATH Variable:: Searching directories for @code{awk} programs. +* Obsolete:: Obsolete Options and/or features. +* Undocumented:: Undocumented Options and Features. +@end menu + +@node Options, Other Arguments, Command Line, Command Line +@section Command Line Options + +Options begin with a minus sign, and consist of a single character. +GNU style long named options consist of two minus signs and +a keyword that can be abbreviated if the abbreviation allows the option +to be uniquely identified. If the option takes an argument, then the +keyword is immediately followed by an equals sign (@samp{=}) and the +argument's value. For brevity, the discussion below only refers to the +traditional short options; however the long and short options are +interchangeable in all contexts. + +Each long named option for @code{gawk} has a corresponding +@sc{posix}-style option. The options and their meanings are as follows: + +@table @code +@item -F @var{fs} +@itemx --field-separator=@var{fs} +@iftex +@cindex @code{-F} option +@end iftex +@cindex @code{--field-separator} option +Sets the @code{FS} variable to @var{fs} +(@pxref{Field Separators, ,Specifying how Fields are Separated}).@refill + +@item -f @var{source-file} +@itemx --file=@var{source-file} +@iftex +@cindex @code{-f} option +@end iftex +@cindex @code{--file} option +Indicates that the @code{awk} program is to be found in @var{source-file} +instead of in the first non-option argument. + +@item -v @var{var}=@var{val} +@itemx --assign=@var{var}=@var{val} +@cindex @samp{-v} option +@cindex @code{--assign} option +Sets the variable @var{var} to the value @var{val} @emph{before} +execution of the program begins. Such variable values are available +inside the @code{BEGIN} rule (see below for a fuller explanation). + +The @samp{-v} option can only set one variable, but you can use +it more than once, setting another variable each time, like this: +@samp{@w{-v foo=1} @w{-v bar=2}}. + +@item -W @var{gawk-opt} +@cindex @samp{-W} option +Following the @sc{posix} standard, options that are implementation +specific are supplied as arguments to the @samp{-W} option. With @code{gawk}, +these arguments may be separated by commas, or quoted and separated by +whitespace. Case is ignored when processing these options. These options +also have corresponding GNU style long named options. The following +@code{gawk}-specific options are available: + +@table @code +@item -W compat +@itemx --compat +@cindex @code{--compat} option +Specifies @dfn{compatibility mode}, in which the GNU extensions in +@code{gawk} are disabled, so that @code{gawk} behaves just like Unix +@code{awk}. +@xref{POSIX/GNU, ,Extensions in @code{gawk} not in POSIX @code{awk}}, +which summarizes the extensions. Also see +@ref{Compatibility Mode, ,Downward Compatibility and Debugging}.@refill + +@item -W copyleft +@itemx -W copyright +@itemx --copyleft +@itemx --copyright +@cindex @code{--copyleft} option +@cindex @code{--copyright} option +Print the short version of the General Public License. +This option may disappear in a future version of @code{gawk}. + +@item -W help +@itemx -W usage +@itemx --help +@itemx --usage +@cindex @code{--help} option +@cindex @code{--usage} option +Print a ``usage'' message summarizing the short and long style options +that @code{gawk} accepts, and then exit. + +@item -W lint +@itemx --lint +@cindex @code{--lint} option +Provide warnings about constructs that are dubious or non-portable to +other @code{awk} implementations. +Some warnings are issued when @code{gawk} first reads your program. Others +are issued at run-time, as your program executes. + +@item -W posix +@itemx --posix +@cindex @code{--posix} option +Operate in strict @sc{posix} mode. This disables all @code{gawk} +extensions (just like @code{-W compat}), and adds the following additional +restrictions: + +@itemize @bullet{} +@item +@code{\x} escape sequences are not recognized +(@pxref{Constants, ,Constant Expressions}).@refill + +@item +The synonym @code{func} for the keyword @code{function} is not +recognized (@pxref{Definition Syntax, ,Syntax of Function Definitions}). + +@item +The operators @samp{**} and @samp{**=} cannot be used in +place of @samp{^} and @samp{^=} (@pxref{Arithmetic Ops, ,Arithmetic Operators}, +and also @pxref{Assignment Ops, ,Assignment Expressions}).@refill + +@item +Specifying @samp{-Ft} on the command line does not set the value +of @code{FS} to be a single tab character +(@pxref{Field Separators, ,Specifying how Fields are Separated}).@refill +@end itemize + +Although you can supply both @samp{-W compat} and @samp{-W posix} on the +command line, @samp{-W posix} will take precedence. + +@item -W source=@var{program-text} +@itemx --source=@var{program-text} +@cindex @code{--source} option +Program source code is taken from the @var{program-text}. This option +allows you to mix @code{awk} source code in files with program source +code that you would enter on the command line. This is particularly useful +when you have library functions that you wish to use from your command line +programs (@pxref{AWKPATH Variable, ,The @code{AWKPATH} Environment Variable}). + +@item -W version +@itemx --version +@cindex @code{--version} option +Prints version information for this particular copy of @code{gawk}. +This is so you can determine if your copy of @code{gawk} is up to date +with respect to whatever the Free Software Foundation is currently +distributing. This option may disappear in a future version of @code{gawk}. +@end table + +@item -- +Signals the end of the command line options. The following arguments +are not treated as options even if they begin with @samp{-}. This +interpretation of @samp{--} follows the @sc{posix} argument parsing +conventions. + +This is useful if you have file names that start with @samp{-}, +or in shell scripts, if you have file names that will be specified +by the user which could start with @samp{-}. +@end table + +Any other options are flagged as invalid with a warning message, but +are otherwise ignored. + +In compatibility mode, as a special case, if the value of @var{fs} supplied +to the @samp{-F} option is @samp{t}, then @code{FS} is set to the tab +character (@code{"\t"}). This is only true for @samp{-W compat}, and not +for @samp{-W posix} +(@pxref{Field Separators, ,Specifying how Fields are Separated}).@refill + +If the @samp{-f} option is @emph{not} used, then the first non-option +command line argument is expected to be the program text. + +The @samp{-f} option may be used more than once on the command line. +If it is, @code{awk} reads its program source from all of the named files, as +if they had been concatenated together into one big file. This is +useful for creating libraries of @code{awk} functions. Useful functions +can be written once, and then retrieved from a standard place, instead +of having to be included into each individual program. You can still +type in a program at the terminal and use library functions, by specifying +@samp{-f /dev/tty}. @code{awk} will read a file from the terminal +to use as part of the @code{awk} program. After typing your program, +type @kbd{Control-d} (the end-of-file character) to terminate it. +(You may also use @samp{-f -} to read program source from the standard +input, but then you will not be able to also use the standard input as a +source of data.) + +Because it is clumsy using the standard @code{awk} mechanisms to mix source +file and command line @code{awk} programs, @code{gawk} provides the +@samp{--source} option. This does not require you to pre-empt the standard +input for your source code, and allows you to easily mix command line +and library source code +(@pxref{AWKPATH Variable, ,The @code{AWKPATH} Environment Variable}). + +If no @samp{-f} or @samp{--source} option is specified, then @code{gawk} +will use the first non-option command line argument as the text of the +program source code. + +@node Other Arguments, AWKPATH Variable, Options, Command Line +@section Other Command Line Arguments + +Any additional arguments on the command line are normally treated as +input files to be processed in the order specified. However, an +argument that has the form @code{@var{var}=@var{value}}, means to assign +the value @var{value} to the variable @var{var}---it does not specify a +file at all. + +@vindex ARGV +All these arguments are made available to your @code{awk} program in the +@code{ARGV} array (@pxref{Built-in Variables}). Command line options +and the program text (if present) are omitted from the @code{ARGV} +array. All other arguments, including variable assignments, are +included. + +The distinction between file name arguments and variable-assignment +arguments is made when @code{awk} is about to open the next input file. +At that point in execution, it checks the ``file name'' to see whether +it is really a variable assignment; if so, @code{awk} sets the variable +instead of reading a file. + +Therefore, the variables actually receive the specified values after all +previously specified files have been read. In particular, the values of +variables assigned in this fashion are @emph{not} available inside a +@code{BEGIN} rule +(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}), +since such rules are run before @code{awk} begins scanning the argument list. +The values given on the command line are processed for escape sequences +(@pxref{Constants, ,Constant Expressions}).@refill + +In some earlier implementations of @code{awk}, when a variable assignment +occurred before any file names, the assignment would happen @emph{before} +the @code{BEGIN} rule was executed. Some applications came to depend +upon this ``feature.'' When @code{awk} was changed to be more consistent, +the @samp{-v} option was added to accommodate applications that depended +upon this old behavior. + +The variable assignment feature is most useful for assigning to variables +such as @code{RS}, @code{OFS}, and @code{ORS}, which control input and +output formats, before scanning the data files. It is also useful for +controlling state if multiple passes are needed over a data file. For +example:@refill + +@cindex multiple passes over data +@cindex passes, multiple +@smallexample +awk 'pass == 1 @{ @var{pass 1 stuff} @} + pass == 2 @{ @var{pass 2 stuff} @}' pass=1 datafile pass=2 datafile +@end smallexample + +Given the variable assignment feature, the @samp{-F} option is not +strictly necessary. It remains for historical compatibility. + +@node AWKPATH Variable, Obsolete, Other Arguments, Command Line +@section The @code{AWKPATH} Environment Variable +@cindex @code{AWKPATH} environment variable +@cindex search path +@cindex directory search +@cindex path, search +@iftex +@cindex differences between @code{gawk} and @code{awk} +@end iftex + +The previous section described how @code{awk} program files can be named +on the command line with the @samp{-f} option. In some @code{awk} +implementations, you must supply a precise path name for each program +file, unless the file is in the current directory. + +But in @code{gawk}, if the file name supplied in the @samp{-f} option +does not contain a @samp{/}, then @code{gawk} searches a list of +directories (called the @dfn{search path}), one by one, looking for a +file with the specified name. + +The search path is actually a string consisting of directory names +separated by colons. @code{gawk} gets its search path from the +@code{AWKPATH} environment variable. If that variable does not exist, +@code{gawk} uses the default path, which is +@samp{.:/usr/lib/awk:/usr/local/lib/awk}. (Programs written by +system administrators should use an @code{AWKPATH} variable that +does not include the current directory, @samp{.}.)@refill + +The search path feature is particularly useful for building up libraries +of useful @code{awk} functions. The library files can be placed in a +standard directory that is in the default path, and then specified on +the command line with a short file name. Otherwise, the full file name +would have to be typed for each file. + +By combining the @samp{--source} and @samp{-f} options, your command line +@code{awk} programs can use facilities in @code{awk} library files. + +Path searching is not done if @code{gawk} is in compatibility mode. +This is true for both @samp{-W compat} and @samp{-W posix}. +@xref{Options, ,Command Line Options}. + +@strong{Note:} if you want files in the current directory to be found, +you must include the current directory in the path, either by writing +@file{.} as an entry in the path, or by writing a null entry in the +path. (A null entry is indicated by starting or ending the path with a +colon, or by placing two colons next to each other (@samp{::}).) If the +current directory is not included in the path, then files cannot be +found in the current directory. This path search mechanism is identical +to the shell's. +@c someday, @cite{The Bourne Again Shell}.... + +@node Obsolete, Undocumented, AWKPATH Variable, Command Line +@section Obsolete Options and/or Features + +@cindex deprecated options +@cindex obsolete options +@cindex deprecated features +@cindex obsolete features +This section describes features and/or command line options from the +previous release of @code{gawk} that are either not available in the +current version, or that are still supported but deprecated (meaning that +they will @emph{not} be in the next release). + +@c update this section for each release! + +For version 2.15 of @code{gawk}, the following command line options +from version 2.11.1 are no longer recognized. + +@table @samp +@ignore +@item -nostalgia +Use @samp{-W nostalgia} instead. +@end ignore + +@item -c +Use @samp{-W compat} instead. + +@item -V +Use @samp{-W version} instead. + +@item -C +Use @samp{-W copyright} instead. + +@item -a +@itemx -e +These options produce an ``unrecognized option'' error message but have +no effect on the execution of @code{gawk}. The @sc{posix} standard now +specifies traditional @code{awk} regular expressions for the @code{awk} utility. +@end table + +The public-domain version of @code{strftime} that is distributed with +@code{gawk} changed for the 2.14 release. The @samp{%V} conversion specifier +that used to generate the date in VMS format was changed to @samp{%v}. +This is because the @sc{posix} standard for the @code{date} utility now +specifies a @samp{%V} conversion specifier. +@xref{Time Functions, ,Functions for Dealing with Time Stamps}, for details. + +@node Undocumented, , Obsolete, Command Line +@section Undocumented Options and Features + +This section intentionally left blank. + +@c Read The Source, Luke! + +@ignore +@c If these came out in the Info file or TeX manual, then they wouldn't +@c be undocumented, would they? + +@code{gawk} has one undocumented option: + +@table @samp +@item -W nostalgia +Print the message @code{"awk: bailing out near line 1"} and dump core. +This option was inspired by the common behavior of very early versions of +Unix @code{awk}, and by a t--shirt. +@end table + +Early versions of @code{awk} used to not require any separator (either +a newline or @samp{;}) between the rules in @code{awk} programs. Thus, +it was common to see one-line programs like: + +@example +awk '@{ sum += $1 @} END @{ print sum @}' +@end example + +@code{gawk} actually supports this, but it is purposely undocumented +since it is considered bad style. The correct way to write such a program +is either + +@example +awk '@{ sum += $1 @} ; END @{ print sum @}' +@end example + +@noindent +or + +@example +awk '@{ sum += $1 @} + END @{ print sum @}' data +@end example + +@noindent +@xref{Statements/Lines, ,@code{awk} Statements versus Lines}, for a fuller +explanation.@refill + +As an accident of the implementation of the original Unix @code{awk}, if +a built-in function used @code{$0} as its default argument, it was possible +to call that function without the parentheses. In particular, it was +common practice to use the @code{length} function in this fashion. +For example, the pipeline: + +@example +echo abcdef | awk '@{ print length @}' +@end example + +@noindent +would print @samp{6}. + +For backwards compatibility with old programs, @code{gawk} supports +this usage, but only for the @code{length} function. New programs should +@emph{not} call the @code{length} function this way. In particular, +this usage will not be portable to other @sc{posix} compliant versions +of @code{awk}. It is also poor style. + +@end ignore + +@node Language History, Installation, Command Line, Top +@chapter The Evolution of the @code{awk} Language + +This manual describes the GNU implementation of @code{awk}, which is patterned +after the @sc{posix} specification. Many @code{awk} users are only familiar +with the original @code{awk} implementation in Version 7 Unix, which is also +the basis for the version in Berkeley Unix (through 4.3--Reno). This chapter +briefly describes the evolution of the @code{awk} language. + +@menu +* V7/S5R3.1:: The major changes between V7 and + System V Release 3.1. +* S5R4:: Minor changes between System V + Releases 3.1 and 4. +* POSIX:: New features from the @sc{posix} standard. +* POSIX/GNU:: The extensions in @code{gawk} + not in @sc{posix} @code{awk}. +@end menu + +@node V7/S5R3.1, S5R4, Language History, Language History +@section Major Changes between V7 and S5R3.1 + +The @code{awk} language evolved considerably between the release of +Version 7 Unix (1978) and the new version first made widely available in +System V Release 3.1 (1987). This section summarizes the changes, with +cross-references to further details. + +@itemize @bullet +@item +The requirement for @samp{;} to separate rules on a line +(@pxref{Statements/Lines, ,@code{awk} Statements versus Lines}). + +@item +User-defined functions, and the @code{return} statement +(@pxref{User-defined, ,User-defined Functions}). + +@item +The @code{delete} statement (@pxref{Delete, ,The @code{delete} Statement}). + +@item +The @code{do}-@code{while} statement +(@pxref{Do Statement, ,The @code{do}-@code{while} Statement}).@refill + +@item +The built-in functions @code{atan2}, @code{cos}, @code{sin}, @code{rand} and +@code{srand} (@pxref{Numeric Functions, ,Numeric Built-in Functions}). + +@item +The built-in functions @code{gsub}, @code{sub}, and @code{match} +(@pxref{String Functions, ,Built-in Functions for String Manipulation}). + +@item +The built-in functions @code{close}, which closes an open file, and +@code{system}, which allows the user to execute operating system +commands (@pxref{I/O Functions, ,Built-in Functions for Input/Output}).@refill +@c Does the above verbiage prevents an overfull hbox? --mew, rjc 24jan1992 + +@item +The @code{ARGC}, @code{ARGV}, @code{FNR}, @code{RLENGTH}, @code{RSTART}, +and @code{SUBSEP} built-in variables (@pxref{Built-in Variables}). + +@item +The conditional expression using the operators @samp{?} and @samp{:} +(@pxref{Conditional Exp, ,Conditional Expressions}).@refill + +@item +The exponentiation operator @samp{^} +(@pxref{Arithmetic Ops, ,Arithmetic Operators}) and its assignment operator +form @samp{^=} (@pxref{Assignment Ops, ,Assignment Expressions}).@refill + +@item +C-compatible operator precedence, which breaks some old @code{awk} +programs (@pxref{Precedence, ,Operator Precedence (How Operators Nest)}). + +@item +Regexps as the value of @code{FS} +(@pxref{Field Separators, ,Specifying how Fields are Separated}), and as the +third argument to the @code{split} function +(@pxref{String Functions, ,Built-in Functions for String Manipulation}).@refill + +@item +Dynamic regexps as operands of the @samp{~} and @samp{!~} operators +(@pxref{Regexp Usage, ,How to Use Regular Expressions}). + +@item +Escape sequences (@pxref{Constants, ,Constant Expressions}) in regexps.@refill + +@item +The escape sequences @samp{\b}, @samp{\f}, and @samp{\r} +(@pxref{Constants, ,Constant Expressions}). + +@item +Redirection of input for the @code{getline} function +(@pxref{Getline, ,Explicit Input with @code{getline}}).@refill + +@item +Multiple @code{BEGIN} and @code{END} rules +(@pxref{BEGIN/END, ,@code{BEGIN} and @code{END} Special Patterns}).@refill + +@item +Simulated multi-dimensional arrays +(@pxref{Multi-dimensional, ,Multi-dimensional Arrays}).@refill +@end itemize + +@node S5R4, POSIX, V7/S5R3.1, Language History +@section Changes between S5R3.1 and S5R4 + +The System V Release 4 version of Unix @code{awk} added these features +(some of which originated in @code{gawk}): + +@itemize @bullet +@item +The @code{ENVIRON} variable (@pxref{Built-in Variables}). + +@item +Multiple @samp{-f} options on the command line +(@pxref{Command Line, ,Invoking @code{awk}}).@refill + +@item +The @samp{-v} option for assigning variables before program execution begins +(@pxref{Command Line, ,Invoking @code{awk}}).@refill + +@item +The @samp{--} option for terminating command line options. + +@item +The @samp{\a}, @samp{\v}, and @samp{\x} escape sequences +(@pxref{Constants, ,Constant Expressions}).@refill + +@item +A defined return value for the @code{srand} built-in function +(@pxref{Numeric Functions, ,Numeric Built-in Functions}). + +@item +The @code{toupper} and @code{tolower} built-in string functions +for case translation +(@pxref{String Functions, ,Built-in Functions for String Manipulation}).@refill + +@item +A cleaner specification for the @samp{%c} format-control letter in the +@code{printf} function +(@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing}).@refill + +@item +The ability to dynamically pass the field width and precision (@code{"%*.*d"}) +in the argument list of the @code{printf} function +(@pxref{Printf, ,Using @code{printf} Statements for Fancier Printing}).@refill + +@item +The use of constant regexps such as @code{/foo/} as expressions, where +they are equivalent to use of the matching operator, as in @code{$0 ~ +/foo/} (@pxref{Constants, ,Constant Expressions}). +@end itemize + +@node POSIX, POSIX/GNU, S5R4, Language History +@section Changes between S5R4 and POSIX @code{awk} + +The @sc{posix} Command Language and Utilities standard for @code{awk} +introduced the following changes into the language: + +@itemize @bullet{} +@item +The use of @samp{-W} for implementation-specific options. + +@item +The use of @code{CONVFMT} for controlling the conversion of numbers +to strings (@pxref{Conversion, ,Conversion of Strings and Numbers}). + +@item +The concept of a numeric string, and tighter comparison rules to go +with it (@pxref{Comparison Ops, ,Comparison Expressions}). + +@item +More complete documentation of many of the previously undocumented +features of the language. +@end itemize + +@node POSIX/GNU, , POSIX, Language History +@section Extensions in @code{gawk} not in POSIX @code{awk} + +The GNU implementation, @code{gawk}, adds these features: + +@itemize @bullet +@item +The @code{AWKPATH} environment variable for specifying a path search for +the @samp{-f} command line option +(@pxref{Command Line, ,Invoking @code{awk}}).@refill + +@item +The various @code{gawk} specific features available via the @samp{-W} +command line option (@pxref{Command Line, ,Invoking @code{awk}}). + +@item +The @code{ARGIND} variable, that tracks the movement of @code{FILENAME} +through @code{ARGV}. (@pxref{Built-in Variables}). + +@item +The @code{ERRNO} variable, that contains the system error message when +@code{getline} returns @minus{}1, or when @code{close} fails. +(@pxref{Built-in Variables}). + +@item +The @code{IGNORECASE} variable and its effects +(@pxref{Case-sensitivity, ,Case-sensitivity in Matching}).@refill + +@item +The @code{FIELDWIDTHS} variable and its effects +(@pxref{Constant Size, ,Reading Fixed-width Data}).@refill + +@item +The @code{next file} statement for skipping to the next data file +(@pxref{Next File Statement, ,The @code{next file} Statement}).@refill + +@item +The @code{systime} and @code{strftime} built-in functions for obtaining +and printing time stamps +(@pxref{Time Functions, ,Functions for Dealing with Time Stamps}).@refill + +@item +The @file{/dev/stdin}, @file{/dev/stdout}, @file{/dev/stderr}, and +@file{/dev/fd/@var{n}} file name interpretation +(@pxref{Special Files, ,Standard I/O Streams}).@refill + +@item +The @samp{-W compat} option to turn off these extensions +(@pxref{Command Line, ,Invoking @code{awk}}).@refill + +@item +The @samp{-W posix} option for full @sc{posix} compliance +(@pxref{Command Line, ,Invoking @code{awk}}).@refill + +@end itemize + +@node Installation, Gawk Summary, Language History, Top +@chapter Installing @code{gawk} + +This chapter provides instructions for installing @code{gawk} on the +various platforms that are supported by the developers. The primary +developers support Unix (and one day, GNU), while the other ports were +contributed. The file @file{ACKNOWLEDGMENT} in the @code{gawk} +distribution lists the electronic mail addresses of the people who did +the respective ports.@refill + +@menu +* Gawk Distribution:: What is in the @code{gawk} distribution. +* Unix Installation:: Installing @code{gawk} under various versions + of Unix. +* VMS Installation:: Installing @code{gawk} on VMS. +* MS-DOS Installation:: Installing @code{gawk} on MS-DOS. +* Atari Installation:: Installing @code{gawk} on the Atari ST. +@end menu + +@node Gawk Distribution, Unix Installation, Installation, Installation +@section The @code{gawk} Distribution + +This section first describes how to get and extract the @code{gawk} +distribution, and then discusses what is in the various files and +subdirectories. + +@menu +* Extracting:: How to get and extract the distribution. +* Distribution contents:: What is in the distribution. +@end menu + +@node Extracting, Distribution contents, Gawk Distribution, Gawk Distribution +@subsection Getting the @code{gawk} Distribution + +@cindex getting gawk +@cindex anonymous ftp +@cindex anonymous uucp +@cindex ftp, anonymous +@cindex uucp, anonymous +@code{gawk} is distributed as a @code{tar} file compressed with the +GNU Zip program, @code{gzip}. You can +get it via anonymous @code{ftp} to the Internet host @code{prep.ai.mit.edu}. +Like all GNU software, it will be archived at other well known systems, +from which it will be possible to use some sort of anonymous @code{uucp} to +obtain the distribution as well. +You can also order @code{gawk} on tape or CD-ROM directly from the +Free Software Foundation. (The address is on the copyright page.) +Doing so directly contributes to the support of the foundation and to +the production of more free software. + +Once you have the distribution (for example, +@file{gawk-2.15.0.tar.z}), first use @code{gzip} to expand the +file, and then use @code{tar} to extract it. You can use the following +pipeline to produce the @code{gawk} distribution: + +@example +# Under System V, add 'o' to the tar flags +gzip -d -c gawk-2.15.0.tar.z | tar -xvpf - +@end example + +@noindent +This will create a directory named @file{gawk-2.15} in the current +directory. + +The distribution file name is of the form @file{gawk-2.15.@var{n}.tar.Z}. +The @var{n} represents a @dfn{patchlevel}, meaning that minor bugs have +been fixed in the major release. The current patchlevel is 0, but when +retrieving distributions, you should get the version with the highest +patchlevel.@refill + +If you are not on a Unix system, you will need to make other arrangements +for getting and extracting the @code{gawk} distribution. You should consult +a local expert. + +@node Distribution contents, , Extracting, Gawk Distribution +@subsection Contents of the @code{gawk} Distribution + +@code{gawk} has a number of C source files, documentation files, +subdirectories and files related to the configuration process +(@pxref{Unix Installation, ,Compiling and Installing @code{gawk} on Unix}), +and several subdirectories related to different, non-Unix, +operating systems.@refill + +@table @asis +@item various @samp{.c}, @samp{.y}, and @samp{.h} files + +The C and YACC source files are the actual @code{gawk} source code. +@end table + +@table @file +@item README +@itemx README.VMS +@itemx README.dos +@itemx README.rs6000 +@itemx README.ultrix +Descriptive files: @file{README} for @code{gawk} under Unix, and the +rest for the various hardware and software combinations. + +@item PORTS +A list of systems to which @code{gawk} has been ported, and which +have successfully run the test suite. + +@item ACKNOWLEDGMENT +A list of the people who contributed major parts of the code or documentation. + +@item NEWS +A list of changes to @code{gawk} since the last release or patch. + +@item COPYING +The GNU General Public License. + +@item FUTURES +A brief list of features and/or changes being contemplated for future +releases, with some indication of the time frame for the feature, based +on its difficulty. + +@item LIMITATIONS +A list of those factors that limit @code{gawk}'s performance. +Most of these depend on the hardware or operating system software, and +are not limits in @code{gawk} itself.@refill + +@item PROBLEMS +A file describing known problems with the current release. + +@item gawk.1 +The @code{troff} source for a manual page describing @code{gawk}. + +@item gawk.texinfo +@ifinfo +The @code{texinfo} source file for this Info file. +It should be processed with @TeX{} to produce a printed manual, and +with @code{makeinfo} to produce the Info file.@refill +@end ifinfo +@iftex +The @code{texinfo} source file for this manual. +It should be processed with @TeX{} to produce a printed manual, and +with @code{makeinfo} to produce the Info file.@refill +@end iftex + +@item Makefile.in +@itemx config +@itemx config.in +@itemx configure +@itemx missing +@itemx mungeconf +These files and subdirectories are used when configuring @code{gawk} +for various Unix systems. They are explained in detail in +@ref{Unix Installation, ,Compiling and Installing @code{gawk} on Unix}.@refill + +@item atari +Files needed for building @code{gawk} on an Atari ST. +@xref{Atari Installation, ,Installing @code{gawk} on the Atari ST}, for details. + +@item pc +Files needed for building @code{gawk} under MS-DOS. +@xref{MS-DOS Installation, ,Installing @code{gawk} on MS-DOS}, for details. + +@item vms +Files needed for building @code{gawk} under VMS. +@xref{VMS Installation, ,Compiling Installing and Running @code{gawk} on VMS}, for details. + +@item test +Many interesting @code{awk} programs, provided as a test suite for +@code{gawk}. You can use @samp{make test} from the top level @code{gawk} +directory to run your version of @code{gawk} against the test suite. +@c There are many programs here that are useful in their own right. +If @code{gawk} successfully passes @samp{make test} then you can +be confident of a successful port.@refill +@end table + +@node Unix Installation, VMS Installation, Gawk Distribution, Installation +@section Compiling and Installing @code{gawk} on Unix + +Often, you can compile and install @code{gawk} by typing only two +commands. However, if you do not use a supported system, you may need +to configure @code{gawk} for your system yourself. + +@menu +* Quick Installation:: Compiling @code{gawk} on a + supported Unix version. +* Configuration Philosophy:: How it's all supposed to work. +* New Configurations:: What to do if there is no supplied + configuration for your system. +@end menu + +@node Quick Installation, Configuration Philosophy, Unix Installation, Unix Installation +@subsection Compiling @code{gawk} for a Supported Unix Version + +@cindex installation, unix +After you have extracted the @code{gawk} distribution, @code{cd} +to @file{gawk-2.15}. Look in the @file{config} subdirectory for a +file that matches your hardware/software combination. In general, +only the software is relevant; for example @code{sunos41} is used +for SunOS 4.1, on both Sun 3 and Sun 4 hardware.@refill + +If you find such a file, run the command: + +@example +# assume you have SunOS 4.1 +./configure sunos41 +@end example + +This produces a @file{Makefile} and @file{config.h} tailored to your +system. You may wish to edit the @file{Makefile} to use a different +C compiler, such as @code{gcc}, the GNU C compiler, if you have it. +You may also wish to change the @code{CFLAGS} variable, which controls +the command line options that are passed to the C compiler (such as +optimization levels, or compiling for debugging).@refill + +After you have configured @file{Makefile} and @file{config.h}, type: + +@example +make +@end example + +@noindent +and shortly thereafter, you should have an executable version of @code{gawk}. +That's all there is to it! + +@node Configuration Philosophy, New Configurations, Quick Installation, Unix Installation +@subsection The Configuration Process + +(This section is of interest only if you know something about using the +C language and the Unix operating system.) + +The source code for @code{gawk} generally attempts to adhere to industry +standards wherever possible. This means that @code{gawk} uses library +routines that are specified by the @sc{ansi} C standard and by the @sc{posix} +operating system interface standard. When using an @sc{ansi} C compiler, +function prototypes are provided to help improve the compile-time checking. + +Many older Unix systems do not support all of either the @sc{ansi} or the +@sc{posix} standards. The @file{missing} subdirectory in the @code{gawk} +distribution contains replacement versions of those subroutines that are +most likely to be missing. + +The @file{config.h} file that is created by the @code{configure} program +contains definitions that describe features of the particular operating +system where you are attempting to compile @code{gawk}. For the most +part, it lists which standard subroutines are @emph{not} available. +For example, if your system lacks the @samp{getopt} routine, then +@samp{GETOPT_MISSING} would be defined. + +@file{config.h} also defines constants that describe facts about your +variant of Unix. For example, there may not be an @samp{st_blksize} +element in the @code{stat} structure. In this case @samp{BLKSIZE_MISSING} +would be defined. + +Based on the list in @file{config.h} of standard subroutines that are +missing, @file{missing.c} will do a @samp{#include} of the appropriate +file(s) from the @file{missing} subdirectory.@refill + +Conditionally compiled code in the other source files relies on the +other definitions in the @file{config.h} file. + +Besides creating @file{config.h}, @code{configure} produces a @file{Makefile} +from @file{Makefile.in}. There are a number of lines in @file{Makefile.in} +that are system or feature specific. For example, there is line that begins +with @samp{##MAKE_ALLOCA_C##}. This is normally a comment line, since +it starts with @samp{#}. If a configuration file has @samp{MAKE_ALLOCA_C} +in it, then @code{configure} will delete the @samp{##MAKE_ALLOCA_C##} +from the beginning of the line. This will enable the rules in the +@file{Makefile} that use a C version of @samp{alloca}. There are several +similar features that work in this fashion.@refill + +@node New Configurations, , Configuration Philosophy, Unix Installation +@subsection Configuring @code{gawk} for a New System + +(This section is of interest only if you know something about using the +C language and the Unix operating system, and if you have to install +@code{gawk} on a system that is not supported by the @code{gawk} distribution. +If you are a C or Unix novice, get help from a local expert.) + +If you need to configure @code{gawk} for a Unix system that is not +supported in the distribution, first see +@ref{Configuration Philosophy, ,The Configuration Process}. +Then, copy @file{config.in} to @file{config.h}, and copy +@file{Makefile.in} to @file{Makefile}.@refill + +Next, edit both files. Both files are liberally commented, and the +necessary changes should be straightforward. + +While editing @file{config.h}, you need to determine what library +routines you do or do not have by consulting your system documentation, or +by perusing your actual libraries using the @code{ar} or @code{nm} utilities. +In the worst case, simply do not define @emph{any} of the macros for missing +subroutines. When you compile @code{gawk}, the final link-editing step +will fail. The link editor will provide you with a list of unresolved external +references---these are the missing subroutines. Edit @file{config.h} again +and recompile, and you should be set.@refill + +Editing the @file{Makefile} should also be straightforward. Enable or +disable the lines that begin with @samp{##MAKE_@var{whatever}##}, as +appropriate. Select the correct C compiler and @code{CFLAGS} for it. +Then run @code{make}. + +Getting a correct configuration is likely to be an iterative process. +Do not be discouraged if it takes you several tries. If you have no +luck whatsoever, please report your system type, and the steps you took. +Once you do have a working configuration, please send it to the maintainers +so that support for your system can be added to the official release. + +@xref{Bugs, ,Reporting Problems and Bugs}, for information on how to report +problems in configuring @code{gawk}. You may also use the same mechanisms +for sending in new configurations.@refill + +@node VMS Installation, MS-DOS Installation, Unix Installation, Installation +@section Compiling, Installing, and Running @code{gawk} on VMS + +@c based on material from +@c Pat Rankin + +@cindex installation, vms +This section describes how to compile and install @code{gawk} under VMS. + +@menu +* VMS Compilation:: How to compile @code{gawk} under VMS. +* VMS Installation Details:: How to install @code{gawk} under VMS. +* VMS Running:: How to run @code{gawk} under VMS. +* VMS POSIX:: Alternate instructions for VMS POSIX. +@end menu + +@node VMS Compilation, VMS Installation Details, VMS Installation, VMS Installation +@subsection Compiling @code{gawk} under VMS + +To compile @code{gawk} under VMS, there is a @code{DCL} command procedure that +will issue all the necessary @code{CC} and @code{LINK} commands, and there is +also a @file{Makefile} for use with the @code{MMS} utility. From the source +directory, use either + +@smallexample +$ @@[.VMS]VMSBUILD.COM +@end smallexample + +@noindent +or + +@smallexample +$ MMS/DESCRIPTION=[.VMS]DECSRIP.MMS GAWK +@end smallexample + +Depending upon which C compiler you are using, follow one of the sets +of instructions in this table: + +@table @asis +@item VAX C V3.x +Use either @file{vmsbuild.com} or @file{descrip.mms} as is. These use +@code{CC/OPTIMIZE=NOLINE}, which is essential for Version 3.0. + +@item VAX C V2.x +You must have Version 2.3 or 2.4; older ones won't work. Edit either +@file{vmsbuild.com} or @file{descrip.mms} according to the comments in them. +For @file{vmsbuild.com}, this just entails removing two @samp{!} delimiters. +Also edit @file{config.h} (which is a copy of file @file{[.config]vms-conf.h}) +and comment out or delete the two lines @samp{#define __STDC__ 0} and +@samp{#define VAXC_BUILTINS} near the end.@refill + +@item GNU C +Edit @file{vmsbuild.com} or @file{descrip.mms}; the changes are different +from those for VAX C V2.x, but equally straightforward. No changes to +@file{config.h} should be needed. + +@item DEC C +Edit @file{vmsbuild.com} or @file{descrip.mms} according to their comments. +No changes to @file{config.h} should be needed. +@end table + +@code{gawk} 2.15 has been tested under VAX/VMS 5.5-1 using VAX C V3.2, +GNU C 1.40 and 2.3. It should work without modifications for VMS V4.6 and up. + +@node VMS Installation Details, VMS Running, VMS Compilation, VMS Installation +@subsection Installing @code{gawk} on VMS + +To install @code{gawk}, all you need is a ``foreign'' command, which is +a @code{DCL} symbol whose value begins with a dollar sign. + +@smallexample +$ GAWK :== $device:[directory]GAWK +@end smallexample + +@noindent +(Substitute the actual location of @code{gawk.exe} for +@samp{device:[directory]}.) The symbol should be placed in the +@file{login.com} of any user who wishes to run @code{gawk}, +so that it will be defined every time the user logs on. +Alternatively, the symbol may be placed in the system-wide +@file{sylogin.com} procedure, which will allow all users +to run @code{gawk}.@refill + +Optionally, the help entry can be loaded into a VMS help library: + +@smallexample +$ LIBRARY/HELP SYS$HELP:HELPLIB [.VMS]GAWK.HLP +@end smallexample + +@noindent +(You may want to substitute a site-specific help library rather than +the standard VMS library @samp{HELPLIB}.) After loading the help text, + +@c this is so tiny, but `should' be smallexample for consistency sake... +@c I didn't because it was so short. --mew 29jan1992 +@example +$ HELP GAWK +@end example + +@noindent +will provide information about both the @code{gawk} implementation and the +@code{awk} programming language. + +The logical name @samp{AWK_LIBRARY} can designate a default location +for @code{awk} program files. For the @samp{-f} option, if the specified +filename has no device or directory path information in it, @code{gawk} +will look in the current directory first, then in the directory specified +by the translation of @samp{AWK_LIBRARY} if the file was not found. +If after searching in both directories, the file still is not found, +then @code{gawk} appends the suffix @samp{.awk} to the filename and the +file search will be re-tried. If @samp{AWK_LIBRARY} is not defined, that +portion of the file search will fail benignly.@refill + +@node VMS Running, VMS POSIX, VMS Installation Details, VMS Installation +@subsection Running @code{gawk} on VMS + +Command line parsing and quoting conventions are significantly different +on VMS, so examples in this manual or from other sources often need minor +changes. They @emph{are} minor though, and all @code{awk} programs +should run correctly. + +Here are a couple of trivial tests: + +@smallexample +$ gawk -- "BEGIN @{print ""Hello, World!""@}" +$ gawk -"W" version ! could also be -"W version" or "-W version" +@end smallexample + +@noindent +Note that upper-case and mixed-case text must be quoted. + +The VMS port of @code{gawk} includes a @code{DCL}-style interface in addition +to the original shell-style interface (see the help entry for details). +One side-effect of dual command line parsing is that if there is only a +single parameter (as in the quoted string program above), the command +becomes ambiguous. To work around this, the normally optional @samp{--} +flag is required to force Unix style rather than @code{DCL} parsing. If any +other dash-type options (or multiple parameters such as data files to be +processed) are present, there is no ambiguity and @samp{--} can be omitted. + +The default search path when looking for @code{awk} program files specified +by the @samp{-f} option is @code{"SYS$DISK:[],AWK_LIBRARY:"}. The logical +name @samp{AWKPATH} can be used to override this default. The format +of @samp{AWKPATH} is a comma-separated list of directory specifications. +When defining it, the value should be quoted so that it retains a single +translation, and not a multi-translation @code{RMS} searchlist. + +@node VMS POSIX, , VMS Running, VMS Installation +@subsection Building and using @code{gawk} under VMS POSIX + +Ignore the instructions above, although @file{vms/gawk.hlp} should still +be made available in a help library. Make sure that the two scripts, +@file{configure} and @file{mungeconf}, are executable; use @samp{chmod +x} +on them if necessary. Then execute the following commands: + +@smallexample +$ POSIX +psx> configure vms-posix +psx> make awktab.c gawk +@end smallexample + +@noindent +The first command will construct files @file{config.h} and @file{Makefile} +out of templates. The second command will compile and link @code{gawk}. +Due to a @code{make} bug in VMS POSIX V1.0 and V1.1, +the file @file{awktab.c} must be given as an explicit target or it will +not be built and the final link step will fail. Ignore the warning +@samp{"Could not find lib m in lib list"}; it is harmless, caused by the +explicit use of @samp{-lm} as a linker option which is not needed +under VMS POSIX. Under V1.1 (but not V1.0) a problem with the @code{yacc} +skeleton @file{/etc/yyparse.c} will cause a compiler warning for +@file{awktab.c}, followed by a linker warning about compilation warnings +in the resulting object module. These warnings can be ignored.@refill + +Once built, @code{gawk} will work like any other shell utility. Unlike +the normal VMS port of @code{gawk}, no special command line manipulation is +needed in the VMS POSIX environment. + +@node MS-DOS Installation, Atari Installation, VMS Installation, Installation +@section Installing @code{gawk} on MS-DOS + +@cindex installation, ms-dos +The first step is to get all the files in the @code{gawk} distribution +onto your PC. Move all the files from the @file{pc} directory into +the main directory where the other files are. Edit the file +@file{make.bat} so that it will be an acceptable MS-DOS batch file. +This means making sure that all lines are terminated with the ASCII +carriage return and line feed characters. +restrictions. + +@code{gawk} has only been compiled with version 5.1 of the Microsoft +C compiler. The file @file{make.bat} from the @file{pc} directory +assumes that you have this compiler. + +Copy the file @file{setargv.obj} from the library directory where it +resides to the @code{gawk} source code directory. + +Run @file{make.bat}. This will compile @code{gawk} for you, and link it. +That's all there is to it! + +@node Atari Installation, , MS-DOS Installation, Installation +@section Installing @code{gawk} on the Atari ST + +@c based on material from +@c Michal Jaegermann + +@cindex installation, atari +This section assumes that you are running TOS. It applies to other Atari +models (STe, TT) as well. + +In order to use @code{gawk}, you need to have a shell, either text or +graphics, that does not map all the characters of a command line to +upper case. Maintaining case distinction in option flags is very +important (@pxref{Command Line, ,Invoking @code{awk}}). Popular shells +like @code{gulam} or @code{gemini} will work, as will newer versions of +@code{desktop}. Support for I/O redirection is necessary to make it easy +to import @code{awk} programs from other environments. Pipes are nice to have, +but not vital. + +If you have received an executable version of @code{gawk}, place it, +as usual, anywhere in your @code{PATH} where your shell will find it. + +While executing, @code{gawk} creates a number of temporary files. +@code{gawk} looks for either of the environment variables @code{TEMP} +or @code{TMPDIR}, in that order. If either one is found, its value +is assumed to be a directory for temporary files. This directory +must exist, and if you can spare the memory, it is a good idea to +put it on a @sc{ram} drive. If neither @code{TEMP} nor @code{TMPDIR} +are found, then @code{gawk} uses the current directory for its +temporary files. + +The ST version of @code{gawk} searches for its program files as +described in @ref{AWKPATH Variable, ,The @code{AWKPATH} Environment Variable}. +On the ST, the default value for the @code{AWKPATH} variable is +@code{@w{".,c:\lib\awk,c:\gnu\lib\awk"}}. +The search path can be modified by explicitly setting @code{AWKPATH} to +whatever you wish. Note that colons cannot be used on the ST to separate +elements in the @code{AWKPATH} variable, since they have another, reserved, +meaning. Instead, you must use a comma to separate elements in the path. +If you are recompiling @code{gawk} on the ST, then you can choose a new +default search path, by setting the value of @samp{DEFPATH} in the file +@file{...\config\atari}. You may choose a different separator character +by setting the value of @samp{ENVSEP} in the same file. The new values will +be used when creating the header file @file{config.h}.@refill + +@ignore +As a last resort, small +adjustments can be made directly on the executable version of @code{gawk} +using a binary editor.@refill +@end ignore + +Although @code{awk} allows great flexibility in doing I/O redirections +from within a program, this facility should be used with care on the ST. +In some circumstances the OS routines for file handle pool processing +lose track of certain events, causing the computer to crash, and requiring +a reboot. Often a warm reboot is sufficient. Fortunately, this happens +infrequently, and in rather esoteric situations. In particular, avoid +having one part of an @code{awk} program using @code{print} +statements explicitly redirected to @code{"/dev/stdout"}, while other +@code{print} statements use the default standard output, and a +calling shell has redirected standard output to a file.@refill +@c whew! + +When @code{gawk} is compiled with the ST version of @code{gcc} and its +usual libraries, it will accept both @samp{/} and @samp{\} as path separators. +While this is convenient, it should be remembered that this removes one, +technically legal, character (@samp{/}) from your file names, and that +it may create problems for external programs, called via the @code{system()} +function, which may not support this convention. Whenever it is possible +that a file created by @code{gawk} will be used by some other program, +use only backslashes. Also remember that in @code{awk}, backslashes in +strings have to be doubled in order to get literal backslashes. + +The initial port of @code{gawk} to the ST was done with @code{gcc}. +If you wish to recompile @code{gawk} from scratch, you will need to use +a compiler that accepts @sc{ansi} standard C (such as @code{gcc}, Turbo C, +or Prospero C). If @code{sizeof(int) != @w{sizeof(int *)}}, the correctness +of the generated code depends heavily on the fact that all function calls +have function prototypes in the current scope. If your compiler does +not accept function prototypes, you will probably have to add a +number of casts to the code.@refill + +If you are using @code{gcc}, make sure that you have up-to-date libraries. +Older versions have problems with some library functions (@code{atan2()}, +@code{strftime()}, the @samp{%g} conversion in @code{sprintf()}) which +may affect the operation of @code{gawk}. + +In the @file{atari} subdirectory of the @code{gawk} distribution is +a version of the @code{system()} function that has been tested with +@code{gulam} and @code{msh}; it should work with other shells as well. +With @code{gulam}, it passes the string to be executed without spawning +an extra copy of a shell. It is possible to replace this version of +@code{system()} with a similar function from a library or from some other +source if that version would be a better choice for the shell you prefer. + +The files needed to recompile @code{gawk} on the ST can be found in +the @file{atari} directory. The provided files and instructions below +assume that you have the GNU C compiler (@code{gcc}), the @code{gulam} shell, +and an ST version of @code{sed}. The @file{Makefile} is set up to use +@file{byacc} as a @file{yacc} replacement. With a different set of tools some +adjustments and/or editing will be needed.@refill + +@code{cd} to the @file{atari} directory. Copy @file{Makefile.st} to +@file{makefile} in the source (parent) directory. Possibly adjust +@file{../config/atari} to suit your system. Execute the script @file{mkconf.g} +which will create the header file @file{../config.h}. Go back to the source +directory. If you are not using @code{gcc}, check the file @file{missing.c}. +It may be necessary to change forward slashes in the references to files +from the @file{atari} subdirectory into backslashes. Type @code{make} and +enjoy.@refill + +Compilation with @code{gcc} of some of the bigger modules, like +@file{awk_tab.c}, may require a full four megabytes of memory. On smaller +machines you would need to cut down on optimizations, or you would have to +switch to another, less memory hungry, compiler.@refill + +@node Gawk Summary, Sample Program, Installation, Top +@appendix @code{gawk} Summary + +This appendix provides a brief summary of the @code{gawk} command line and the +@code{awk} language. It is designed to serve as ``quick reference.'' It is +therefore terse, but complete. + +@menu +* Command Line Summary:: Recapitulation of the command line. +* Language Summary:: A terse review of the language. +* Variables/Fields:: Variables, fields, and arrays. +* Rules Summary:: Patterns and Actions, and their + component parts. +* Functions Summary:: Defining and calling functions. +* Historical Features:: Some undocumented but supported ``features''. +@end menu + +@node Command Line Summary, Language Summary, Gawk Summary, Gawk Summary +@appendixsec Command Line Options Summary + +The command line consists of options to @code{gawk} itself, the +@code{awk} program text (if not supplied via the @samp{-f} option), and +values to be made available in the @code{ARGC} and @code{ARGV} +predefined @code{awk} variables: + +@example +awk @r{[@var{POSIX or GNU style options}]} -f source-file @r{[@code{--}]} @var{file} @dots{} +awk @r{[@var{POSIX or GNU style options}]} @r{[@code{--}]} '@var{program}' @var{file} @dots{} +@end example + +The options that @code{gawk} accepts are: + +@table @code +@item -F @var{fs} +@itemx --field-separator=@var{fs} +Use @var{fs} for the input field separator (the value of the @code{FS} +predefined variable). + +@item -f @var{program-file} +@itemx --file=@var{program-file} +Read the @code{awk} program source from the file @var{program-file}, instead +of from the first command line argument. + +@item -v @var{var}=@var{val} +@itemx --assign=@var{var}=@var{val} +Assign the variable @var{var} the value @var{val} before program execution +begins. + +@item -W compat +@itemx --compat +Specifies compatibility mode, in which @code{gawk} extensions are turned +off. + +@item -W copyleft +@itemx -W copyright +@itemx --copyleft +@itemx --copyright +Print the short version of the General Public License on the error +output. This option may disappear in a future version of @code{gawk}. + +@item -W help +@itemx -W usage +@itemx --help +@itemx --usage +Print a relatively short summary of the available options on the error output. + +@item -W lint +@itemx --lint +Give warnings about dubious or non-portable @code{awk} constructs. + +@item -W posix +@itemx --posix +Specifies @sc{posix} compatibility mode, in which @code{gawk} extensions +are turned off and additional restrictions apply. + +@item -W source=@var{program-text} +@itemx --source=@var{program-text} +Use @var{program-text} as @code{awk} program source code. This option allows +mixing command line source code with source code from files, and is +particularly useful for mixing command line programs with library functions. + +@item -W version +@itemx --version +Print version information for this particular copy of @code{gawk} on the error +output. This option may disappear in a future version of @code{gawk}. + +@item -- +Signal the end of options. This is useful to allow further arguments to the +@code{awk} program itself to start with a @samp{-}. This is mainly for +consistency with the argument parsing conventions of @sc{posix}. +@end table + +Any other options are flagged as invalid, but are otherwise ignored. +@xref{Command Line, ,Invoking @code{awk}}, for more details. + +@node Language Summary, Variables/Fields, Command Line Summary, Gawk Summary +@appendixsec Language Summary + +An @code{awk} program consists of a sequence of pattern-action statements +and optional function definitions. + +@example +@var{pattern} @{ @var{action statements} @} + +function @var{name}(@var{parameter list}) @{ @var{action statements} @} +@end example + +@code{gawk} first reads the program source from the +@var{program-file}(s) if specified, or from the first non-option +argument on the command line. The @samp{-f} option may be used multiple +times on the command line. @code{gawk} reads the program text from all +the @var{program-file} files, effectively concatenating them in the +order they are specified. This is useful for building libraries of +@code{awk} functions, without having to include them in each new +@code{awk} program that uses them. To use a library function in a file +from a program typed in on the command line, specify @samp{-f /dev/tty}; +then type your program, and end it with a @kbd{Control-d}. +@xref{Command Line, ,Invoking @code{awk}}.@refill + +The environment variable @code{AWKPATH} specifies a search path to use +when finding source files named with the @samp{-f} option. The default +path, which is +@samp{.:/usr/lib/awk:/usr/local/lib/awk} is used if @code{AWKPATH} is not set. +If a file name given to the @samp{-f} option contains a @samp{/} character, +no path search is performed. +@xref{AWKPATH Variable, ,The @code{AWKPATH} Environment Variable}, +for a full description of the @code{AWKPATH} environment variable.@refill + +@code{gawk} compiles the program into an internal form, and then proceeds to +read each file named in the @code{ARGV} array. If there are no files named +on the command line, @code{gawk} reads the standard input. + +If a ``file'' named on the command line has the form +@samp{@var{var}=@var{val}}, it is treated as a variable assignment: the +variable @var{var} is assigned the value @var{val}. +If any of the files have a value that is the null string, that +element in the list is skipped.@refill + +For each line in the input, @code{gawk} tests to see if it matches any +@var{pattern} in the @code{awk} program. For each pattern that the line +matches, the associated @var{action} is executed. + +@node Variables/Fields, Rules Summary, Language Summary, Gawk Summary +@appendixsec Variables and Fields + +@code{awk} variables are dynamic; they come into existence when they are +first used. Their values are either floating-point numbers or strings. +@code{awk} also has one-dimension arrays; multiple-dimensional arrays +may be simulated. There are several predefined variables that +@code{awk} sets as a program runs; these are summarized below. + +@menu +* Fields Summary:: Input field splitting. +* Built-in Summary:: @code{awk}'s built-in variables. +* Arrays Summary:: Using arrays. +* Data Type Summary:: Values in @code{awk} are numbers or strings. +@end menu + +@node Fields Summary, Built-in Summary, Variables/Fields, Variables/Fields +@appendixsubsec Fields + +As each input line is read, @code{gawk} splits the line into +@var{fields}, using the value of the @code{FS} variable as the field +separator. If @code{FS} is a single character, fields are separated by +that character. Otherwise, @code{FS} is expected to be a full regular +expression. In the special case that @code{FS} is a single blank, +fields are separated by runs of blanks and/or tabs. Note that the value +of @code{IGNORECASE} (@pxref{Case-sensitivity, ,Case-sensitivity in Matching}) +also affects how fields are split when @code{FS} is a regular expression.@refill + +Each field in the input line may be referenced by its position, @code{$1}, +@code{$2}, and so on. @code{$0} is the whole line. The value of a field may +be assigned to as well. Field numbers need not be constants: + +@example +n = 5 +print $n +@end example + +@noindent +prints the fifth field in the input line. The variable @code{NF} is set to +the total number of fields in the input line. + +References to nonexistent fields (i.e., fields after @code{$NF}) return +the null-string. However, assigning to a nonexistent field (e.g., +@code{$(NF+2) = 5}) increases the value of @code{NF}, creates any +intervening fields with the null string as their value, and causes the +value of @code{$0} to be recomputed, with the fields being separated by +the value of @code{OFS}.@refill + +@xref{Reading Files, ,Reading Input Files}, for a full description of the +way @code{awk} defines and uses fields. + +@node Built-in Summary, Arrays Summary, Fields Summary, Variables/Fields +@appendixsubsec Built-in Variables + +@code{awk}'s built-in variables are: + +@table @code +@item ARGC +The number of command line arguments (not including options or the +@code{awk} program itself). + +@item ARGIND +The index in @code{ARGV} of the current file being processed. +It is always true that @samp{FILENAME == ARGV[ARGIND]}. + +@item ARGV +The array of command line arguments. The array is indexed from 0 to +@code{ARGC} @minus{} 1. Dynamically changing the contents of @code{ARGV} +can control the files used for data.@refill + +@item CONVFMT +The conversion format to use when converting numbers to strings. + +@item FIELDWIDTHS +A space separated list of numbers describing the fixed-width input data. + +@item ENVIRON +An array containing the values of the environment variables. The array +is indexed by variable name, each element being the value of that +variable. Thus, the environment variable @code{HOME} would be in +@code{ENVIRON["HOME"]}. Its value might be @file{/u/close}. + +Changing this array does not affect the environment seen by programs +which @code{gawk} spawns via redirection or the @code{system} function. +(This may change in a future version of @code{gawk}.) + +Some operating systems do not have environment variables. +The array @code{ENVIRON} is empty when running on these systems. + +@item ERRNO +The system error message when an error occurs using @code{getline} +or @code{close}. + +@item FILENAME +The name of the current input file. If no files are specified on the command +line, the value of @code{FILENAME} is @samp{-}. + +@item FNR +The input record number in the current input file. + +@item FS +The input field separator, a blank by default. + +@item IGNORECASE +The case-sensitivity flag for regular expression operations. If +@code{IGNORECASE} has a nonzero value, then pattern matching in rules, +field splitting with @code{FS}, regular expression matching with +@samp{~} and @samp{!~}, and the @code{gsub}, @code{index}, @code{match}, +@code{split} and @code{sub} predefined functions all ignore case +when doing regular expression operations.@refill + +@item NF +The number of fields in the current input record. + +@item NR +The total number of input records seen so far. + +@item OFMT +The output format for numbers for the @code{print} statement, +@code{"%.6g"} by default. + +@item OFS +The output field separator, a blank by default. + +@item ORS +The output record separator, by default a newline. + +@item RS +The input record separator, by default a newline. @code{RS} is exceptional +in that only the first character of its string value is used for separating +records. If @code{RS} is set to the null string, then records are separated by +blank lines. When @code{RS} is set to the null string, then the newline +character always acts as a field separator, in addition to whatever value +@code{FS} may have.@refill + +@item RSTART +The index of the first character matched by @code{match}; 0 if no match. + +@item RLENGTH +The length of the string matched by @code{match}; @minus{}1 if no match. + +@item SUBSEP +The string used to separate multiple subscripts in array elements, by +default @code{"\034"}. +@end table + +@xref{Built-in Variables}, for more information. + +@node Arrays Summary, Data Type Summary, Built-in Summary, Variables/Fields +@appendixsubsec Arrays + +Arrays are subscripted with an expression between square brackets +(@samp{[} and @samp{]}). Array subscripts are @emph{always} strings; +numbers are converted to strings as necessary, following the standard +conversion rules +(@pxref{Conversion, ,Conversion of Strings and Numbers}).@refill + +If you use multiple expressions separated by commas inside the square +brackets, then the array subscript is a string consisting of the +concatenation of the individual subscript values, converted to strings, +separated by the subscript separator (the value of @code{SUBSEP}). + +The special operator @code{in} may be used in an @code{if} or +@code{while} statement to see if an array has an index consisting of a +particular value. + +@example +if (val in array) + print array[val] +@end example + +If the array has multiple subscripts, use @code{(i, j, @dots{}) in array} +to test for existence of an element. + +The @code{in} construct may also be used in a @code{for} loop to iterate +over all the elements of an array. +@xref{Scanning an Array, ,Scanning all Elements of an Array}.@refill + +An element may be deleted from an array using the @code{delete} statement. + +@xref{Arrays, ,Arrays in @code{awk}}, for more detailed information. + +@node Data Type Summary, , Arrays Summary, Variables/Fields +@appendixsubsec Data Types + +The value of an @code{awk} expression is always either a number +or a string. + +Certain contexts (such as arithmetic operators) require numeric +values. They convert strings to numbers by interpreting the text +of the string as a numeral. If the string does not look like a +numeral, it converts to 0. + +Certain contexts (such as concatenation) require string values. +They convert numbers to strings by effectively printing them +with @code{sprintf}. +@xref{Conversion, ,Conversion of Strings and Numbers}, for the details.@refill + +To force conversion of a string value to a number, simply add 0 +to it. If the value you start with is already a number, this +does not change it. + +To force conversion of a numeric value to a string, concatenate it with +the null string. + +The @code{awk} language defines comparisons as being done numerically if +both operands are numeric, or if one is numeric and the other is a numeric +string. Otherwise one or both operands are converted to strings and a +string comparison is performed. + +Uninitialized variables have the string value @code{""} (the null, or +empty, string). In contexts where a number is required, this is +equivalent to 0. + +@xref{Variables}, for more information on variable naming and initialization; +@pxref{Conversion, ,Conversion of Strings and Numbers}, for more information +on how variable values are interpreted.@refill + +@node Rules Summary, Functions Summary, Variables/Fields, Gawk Summary +@appendixsec Patterns and Actions + +@menu +* Pattern Summary:: Quick overview of patterns. +* Regexp Summary:: Quick overview of regular expressions. +* Actions Summary:: Quick overview of actions. +@end menu + +An @code{awk} program is mostly composed of rules, each consisting of a +pattern followed by an action. The action is enclosed in @samp{@{} and +@samp{@}}. Either the pattern may be missing, or the action may be +missing, but, of course, not both. If the pattern is missing, the +action is executed for every single line of input. A missing action is +equivalent to this action, + +@example +@{ print @} +@end example + +@noindent +which prints the entire line. + +Comments begin with the @samp{#} character, and continue until the end of the +line. Blank lines may be used to separate statements. Normally, a statement +ends with a newline, however, this is not the case for lines ending in a +@samp{,}, @samp{@{}, @samp{?}, @samp{:}, @samp{&&}, or @samp{||}. Lines +ending in @code{do} or @code{else} also have their statements automatically +continued on the following line. In other cases, a line can be continued by +ending it with a @samp{\}, in which case the newline is ignored.@refill + +Multiple statements may be put on one line by separating them with a @samp{;}. +This applies to both the statements within the action part of a rule (the +usual case), and to the rule statements. + +@xref{Comments, ,Comments in @code{awk} Programs}, for information on +@code{awk}'s commenting convention; +@pxref{Statements/Lines, ,@code{awk} Statements versus Lines}, for a +description of the line continuation mechanism in @code{awk}.@refill + +@node Pattern Summary, Regexp Summary, Rules Summary, Rules Summary +@appendixsubsec Patterns + +@code{awk} patterns may be one of the following: + +@example +/@var{regular expression}/ +@var{relational expression} +@var{pattern} && @var{pattern} +@var{pattern} || @var{pattern} +@var{pattern} ? @var{pattern} : @var{pattern} +(@var{pattern}) +! @var{pattern} +@var{pattern1}, @var{pattern2} +BEGIN +END +@end example + +@code{BEGIN} and @code{END} are two special kinds of patterns that are not +tested against the input. The action parts of all @code{BEGIN} rules are +merged as if all the statements had been written in a single @code{BEGIN} +rule. They are executed before any of the input is read. Similarly, all the +@code{END} rules are merged, and executed when all the input is exhausted (or +when an @code{exit} statement is executed). @code{BEGIN} and @code{END} +patterns cannot be combined with other patterns in pattern expressions. +@code{BEGIN} and @code{END} rules cannot have missing action parts.@refill + +For @samp{/@var{regular-expression}/} patterns, the associated statement is +executed for each input line that matches the regular expression. Regular +expressions are extensions of those in @code{egrep}, and are summarized below. + +A @var{relational expression} may use any of the operators defined below in +the section on actions. These generally test whether certain fields match +certain regular expressions. + +The @samp{&&}, @samp{||}, and @samp{!} operators are logical ``and,'' +logical ``or,'' and logical ``not,'' respectively, as in C. They do +short-circuit evaluation, also as in C, and are used for combining more +primitive pattern expressions. As in most languages, parentheses may be +used to change the order of evaluation. + +The @samp{?:} operator is like the same operator in C. If the first +pattern matches, then the second pattern is matched against the input +record; otherwise, the third is matched. Only one of the second and +third patterns is matched. + +The @samp{@var{pattern1}, @var{pattern2}} form of a pattern is called a +range pattern. It matches all input lines starting with a line that +matches @var{pattern1}, and continuing until a line that matches +@var{pattern2}, inclusive. A range pattern cannot be used as an operand +to any of the pattern operators. + +@xref{Patterns}, for a full description of the pattern part of @code{awk} +rules. + +@node Regexp Summary, Actions Summary, Pattern Summary, Rules Summary +@appendixsubsec Regular Expressions + +Regular expressions are the extended kind found in @code{egrep}. +They are composed of characters as follows: + +@table @code +@item @var{c} +matches the character @var{c} (assuming @var{c} is a character with no +special meaning in regexps). + +@item \@var{c} +matches the literal character @var{c}. + +@item . +matches any character except newline. + +@item ^ +matches the beginning of a line or a string. + +@item $ +matches the end of a line or a string. + +@item [@var{abc}@dots{}] +matches any of the characters @var{abc}@dots{} (character class). + +@item [^@var{abc}@dots{}] +matches any character except @var{abc}@dots{} and newline (negated +character class). + +@item @var{r1}|@var{r2} +matches either @var{r1} or @var{r2} (alternation). + +@item @var{r1r2} +matches @var{r1}, and then @var{r2} (concatenation). + +@item @var{r}+ +matches one or more @var{r}'s. + +@item @var{r}* +matches zero or more @var{r}'s. + +@item @var{r}? +matches zero or one @var{r}'s. + +@item (@var{r}) +matches @var{r} (grouping). +@end table + +@xref{Regexp, ,Regular Expressions as Patterns}, for a more detailed +explanation of regular expressions. + +The escape sequences allowed in string constants are also valid in +regular expressions (@pxref{Constants, ,Constant Expressions}). + +@node Actions Summary, , Regexp Summary, Rules Summary +@appendixsubsec Actions + +Action statements are enclosed in braces, @samp{@{} and @samp{@}}. +Action statements consist of the usual assignment, conditional, and looping +statements found in most languages. The operators, control statements, +and input/output statements available are patterned after those in C. + +@menu +* Operator Summary:: @code{awk} operators. +* Control Flow Summary:: The control statements. +* I/O Summary:: The I/O statements. +* Printf Summary:: A summary of @code{printf}. +* Special File Summary:: Special file names interpreted internally. +* Numeric Functions Summary:: Built-in numeric functions. +* String Functions Summary:: Built-in string functions. +* Time Functions Summary:: Built-in time functions. +* String Constants Summary:: Escape sequences in strings. +@end menu + +@node Operator Summary, Control Flow Summary, Actions Summary, Actions Summary +@appendixsubsubsec Operators + +The operators in @code{awk}, in order of increasing precedence, are: + +@table @code +@item = += -= *= /= %= ^= +Assignment. Both absolute assignment (@code{@var{var}=@var{value}}) +and operator assignment (the other forms) are supported. + +@item ?: +A conditional expression, as in C. This has the form @code{@var{expr1} ? +@var{expr2} : @var{expr3}}. If @var{expr1} is true, the value of the +expression is @var{expr2}; otherwise it is @var{expr3}. Only one of +@var{expr2} and @var{expr3} is evaluated.@refill + +@item || +Logical ``or''. + +@item && +Logical ``and''. + +@item ~ !~ +Regular expression match, negated match. + +@item < <= > >= != == +The usual relational operators. + +@item @var{blank} +String concatenation. + +@item + - +Addition and subtraction. + +@item * / % +Multiplication, division, and modulus. + +@item + - ! +Unary plus, unary minus, and logical negation. + +@item ^ +Exponentiation (@samp{**} may also be used, and @samp{**=} for the assignment +operator, but they are not specified in the @sc{posix} standard). + +@item ++ -- +Increment and decrement, both prefix and postfix. + +@item $ +Field reference. +@end table + +@xref{Expressions, ,Expressions as Action Statements}, for a full +description of all the operators listed above. +@xref{Fields, ,Examining Fields}, for a description of the field +reference operator.@refill + +@node Control Flow Summary, I/O Summary, Operator Summary, Actions Summary +@appendixsubsubsec Control Statements + +The control statements are as follows: + +@example +if (@var{condition}) @var{statement} @r{[} else @var{statement} @r{]} +while (@var{condition}) @var{statement} +do @var{statement} while (@var{condition}) +for (@var{expr1}; @var{expr2}; @var{expr3}) @var{statement} +for (@var{var} in @var{array}) @var{statement} +break +continue +delete @var{array}[@var{index}] +exit @r{[} @var{expression} @r{]} +@{ @var{statements} @} +@end example + +@xref{Statements, ,Control Statements in Actions}, for a full description +of all the control statements listed above. + +@node I/O Summary, Printf Summary, Control Flow Summary, Actions Summary +@appendixsubsubsec I/O Statements + +The input/output statements are as follows: + +@table @code +@item getline +Set @code{$0} from next input record; set @code{NF}, @code{NR}, @code{FNR}. + +@item getline <@var{file} +Set @code{$0} from next record of @var{file}; set @code{NF}. + +@item getline @var{var} +Set @var{var} from next input record; set @code{NF}, @code{FNR}. + +@item getline @var{var} <@var{file} +Set @var{var} from next record of @var{file}. + +@item next +Stop processing the current input record. The next input record is read and +processing starts over with the first pattern in the @code{awk} program. +If the end of the input data is reached, the @code{END} rule(s), if any, +are executed. + +@item next file +Stop processing the current input file. The next input record read comes +from the next input file. @code{FILENAME} is updated, @code{FNR} is set to 1, +and processing starts over with the first pattern in the @code{awk} program. +If the end of the input data is reached, the @code{END} rule(s), if any, +are executed. + +@item print +Prints the current record. + +@item print @var{expr-list} +Prints expressions. + +@item print @var{expr-list} > @var{file} +Prints expressions on @var{file}. + +@item printf @var{fmt, expr-list} +Format and print. + +@item printf @var{fmt, expr-list} > file +Format and print on @var{file}. +@end table + +Other input/output redirections are also allowed. For @code{print} and +@code{printf}, @samp{>> @var{file}} appends output to the @var{file}, +and @samp{| @var{command}} writes on a pipe. In a similar fashion, +@samp{@var{command} | getline} pipes input into @code{getline}. +@code{getline} returns 0 on end of file, and @minus{}1 on an error.@refill + +@xref{Getline, ,Explicit Input with @code{getline}}, for a full description +of the @code{getline} statement. +@xref{Printing, ,Printing Output}, for a full description of @code{print} and +@code{printf}. Finally, @pxref{Next Statement, ,The @code{next} Statement}, +for a description of how the @code{next} statement works.@refill + +@node Printf Summary, Special File Summary, I/O Summary, Actions Summary +@appendixsubsubsec @code{printf} Summary + +The @code{awk} @code{printf} statement and @code{sprintf} function +accept the following conversion specification formats: + +@table @code +@item %c +An ASCII character. If the argument used for @samp{%c} is numeric, it is +treated as a character and printed. Otherwise, the argument is assumed to +be a string, and the only first character of that string is printed. + +@item %d +@itemx %i +A decimal number (the integer part). + +@item %e +A floating point number of the form +@samp{@r{[}-@r{]}d.ddddddE@r{[}+-@r{]}dd}.@refill + +@item %f +A floating point number of the form +@r{[}@code{-}@r{]}@code{ddd.dddddd}. + +@item %g +Use @samp{%e} or @samp{%f} conversion, whichever produces a shorter string, +with nonsignificant zeros suppressed. + +@item %o +An unsigned octal number (again, an integer). + +@item %s +A character string. + +@item %x +An unsigned hexadecimal number (an integer). + +@item %X +Like @samp{%x}, except use @samp{A} through @samp{F} instead of @samp{a} +through @samp{f} for decimal 10 through 15.@refill + +@item %% +A single @samp{%} character; no argument is converted. +@end table + +There are optional, additional parameters that may lie between the @samp{%} +and the control letter: + +@table @code +@item - +The expression should be left-justified within its field. + +@item @var{width} +The field should be padded to this width. If @var{width} has a leading zero, +then the field is padded with zeros. Otherwise it is padded with blanks. + +@item .@var{prec} +A number indicating the maximum width of strings or digits to the right +of the decimal point. +@end table + +Either or both of the @var{width} and @var{prec} values may be specified +as @samp{*}. In that case, the particular value is taken from the argument +list. + +@xref{Printf, ,Using @code{printf} Statements for Fancier Printing}, for +examples and for a more detailed description. + +@node Special File Summary, Numeric Functions Summary, Printf Summary, Actions Summary +@appendixsubsubsec Special File Names + +When doing I/O redirection from either @code{print} or @code{printf} into a +file, or via @code{getline} from a file, @code{gawk} recognizes certain special +file names internally. These file names allow access to open file descriptors +inherited from @code{gawk}'s parent process (usually the shell). The +file names are: + +@table @file +@item /dev/stdin +The standard input. + +@item /dev/stdout +The standard output. + +@item /dev/stderr +The standard error output. + +@item /dev/fd/@var{n} +The file denoted by the open file descriptor @var{n}. +@end table + +In addition the following files provide process related information +about the running @code{gawk} program. + +@table @file +@item /dev/pid +Reading this file returns the process ID of the current process, +in decimal, terminated with a newline. + +@item /dev/ppid +Reading this file returns the parent process ID of the current process, +in decimal, terminated with a newline. + +@item /dev/pgrpid +Reading this file returns the process group ID of the current process, +in decimal, terminated with a newline. + +@item /dev/user +Reading this file returns a single record terminated with a newline. +The fields are separated with blanks. The fields represent the +following information: + +@table @code +@item $1 +The value of the @code{getuid} system call. + +@item $2 +The value of the @code{geteuid} system call. + +@item $3 +The value of the @code{getgid} system call. + +@item $4 +The value of the @code{getegid} system call. +@end table + +If there are any additional fields, they are the group IDs returned by +@code{getgroups} system call. +(Multiple groups may not be supported on all systems.)@refill +@end table + +@noindent +These file names may also be used on the command line to name data files. +These file names are only recognized internally if you do not +actually have files by these names on your system. + +@xref{Special Files, ,Standard I/O Streams}, for a longer description that +provides the motivation for this feature. + +@node Numeric Functions Summary, String Functions Summary, Special File Summary, Actions Summary +@appendixsubsubsec Numeric Functions + +@code{awk} has the following predefined arithmetic functions: + +@table @code +@item atan2(@var{y}, @var{x}) +returns the arctangent of @var{y/x} in radians. + +@item cos(@var{expr}) +returns the cosine in radians. + +@item exp(@var{expr}) +the exponential function. + +@item int(@var{expr}) +truncates to integer. + +@item log(@var{expr}) +the natural logarithm function. + +@item rand() +returns a random number between 0 and 1. + +@item sin(@var{expr}) +returns the sine in radians. + +@item sqrt(@var{expr}) +the square root function. + +@item srand(@var{expr}) +use @var{expr} as a new seed for the random number generator. If no @var{expr} +is provided, the time of day is used. The return value is the previous +seed for the random number generator. +@end table + +@node String Functions Summary, Time Functions Summary, Numeric Functions Summary, Actions Summary +@appendixsubsubsec String Functions + +@code{awk} has the following predefined string functions: + +@table @code +@item gsub(@var{r}, @var{s}, @var{t}) +for each substring matching the regular expression @var{r} in the string +@var{t}, substitute the string @var{s}, and return the number of substitutions. +If @var{t} is not supplied, use @code{$0}. + +@item index(@var{s}, @var{t}) +returns the index of the string @var{t} in the string @var{s}, or 0 if +@var{t} is not present. + +@item length(@var{s}) +returns the length of the string @var{s}. The length of @code{$0} +is returned if no argument is supplied. + +@item match(@var{s}, @var{r}) +returns the position in @var{s} where the regular expression @var{r} +occurs, or 0 if @var{r} is not present, and sets the values of @code{RSTART} +and @code{RLENGTH}. + +@item split(@var{s}, @var{a}, @var{r}) +splits the string @var{s} into the array @var{a} on the regular expression +@var{r}, and returns the number of fields. If @var{r} is omitted, @code{FS} +is used instead. + +@item sprintf(@var{fmt}, @var{expr-list}) +prints @var{expr-list} according to @var{fmt}, and returns the resulting string. + +@item sub(@var{r}, @var{s}, @var{t}) +this is just like @code{gsub}, but only the first matching substring is +replaced. + +@item substr(@var{s}, @var{i}, @var{n}) +returns the @var{n}-character substring of @var{s} starting at @var{i}. +If @var{n} is omitted, the rest of @var{s} is used. + +@item tolower(@var{str}) +returns a copy of the string @var{str}, with all the upper-case characters in +@var{str} translated to their corresponding lower-case counterparts. +Nonalphabetic characters are left unchanged. + +@item toupper(@var{str}) +returns a copy of the string @var{str}, with all the lower-case characters in +@var{str} translated to their corresponding upper-case counterparts. +Nonalphabetic characters are left unchanged. + +@item system(@var{cmd-line}) +Execute the command @var{cmd-line}, and return the exit status. +@end table + +@node Time Functions Summary, String Constants Summary, String Functions Summary, Actions Summary +@appendixsubsubsec Built-in time functions + +The following two functions are available for getting the current +time of day, and for formatting time stamps. + +@table @code +@item systime() +returns the current time of day as the number of seconds since a particular +epoch (Midnight, January 1, 1970 @sc{utc}, on @sc{posix} systems). + +@item strftime(@var{format}, @var{timestamp}) +formats @var{timestamp} according to the specification in @var{format}. +The current time of day is used if no @var{timestamp} is supplied. +@xref{Time Functions, ,Functions for Dealing with Time Stamps}, for the +details on the conversion specifiers that @code{strftime} accepts.@refill +@end table + +@iftex +@xref{Built-in, ,Built-in Functions}, for a description of all of +@code{awk}'s built-in functions. +@end iftex + +@node String Constants Summary, , Time Functions Summary, Actions Summary +@appendixsubsubsec String Constants + +String constants in @code{awk} are sequences of characters enclosed +between double quotes (@code{"}). Within strings, certain @dfn{escape sequences} +are recognized, as in C. These are: + +@table @code +@item \\ +A literal backslash. + +@item \a +The ``alert'' character; usually the ASCII BEL character. + +@item \b +Backspace. + +@item \f +Formfeed. + +@item \n +Newline. + +@item \r +Carriage return. + +@item \t +Horizontal tab. + +@item \v +Vertical tab. + +@item \x@var{hex digits} +The character represented by the string of hexadecimal digits following +the @samp{\x}. As in @sc{ansi} C, all following hexadecimal digits are +considered part of the escape sequence. (This feature should tell us +something about language design by committee.) E.g., @code{"\x1B"} is a +string containing the ASCII ESC (escape) character. (The @samp{\x} +escape sequence is not in @sc{posix} @code{awk}.) + +@item \@var{ddd} +The character represented by the 1-, 2-, or 3-digit sequence of octal +digits. Thus, @code{"\033"} is also a string containing the ASCII ESC +(escape) character. + +@item \@var{c} +The literal character @var{c}. +@end table + +The escape sequences may also be used inside constant regular expressions +(e.g., the regexp @code{@w{/[@ \t\f\n\r\v]/}} matches whitespace +characters).@refill + +@xref{Constants, ,Constant Expressions}. + +@node Functions Summary, Historical Features, Rules Summary, Gawk Summary +@appendixsec Functions + +Functions in @code{awk} are defined as follows: + +@example +function @var{name}(@var{parameter list}) @{ @var{statements} @} +@end example + +Actual parameters supplied in the function call are used to instantiate +the formal parameters declared in the function. Arrays are passed by +reference, other variables are passed by value. + +If there are fewer arguments passed than there are names in @var{parameter-list}, +the extra names are given the null string as value. Extra names have the +effect of local variables. + +The open-parenthesis in a function call of a user-defined function must +immediately follow the function name, without any intervening white space. +This is to avoid a syntactic ambiguity with the concatenation operator. + +The word @code{func} may be used in place of @code{function} (but not in +@sc{posix} @code{awk}). + +Use the @code{return} statement to return a value from a function. + +@xref{User-defined, ,User-defined Functions}, for a more complete description. + +@node Historical Features, , Functions Summary, Gawk Summary +@appendixsec Historical Features + +There are two features of historical @code{awk} implementations that +@code{gawk} supports. First, it is possible to call the @code{length} +built-in function not only with no arguments, but even without parentheses! + +@example +a = length +@end example + +@noindent +is the same as either of + +@example +a = length() +a = length($0) +@end example + +@noindent +This feature is marked as ``deprecated'' in the @sc{posix} standard, and +@code{gawk} will issue a warning about its use if @samp{-W lint} is +specified on the command line. + +The other feature is the use of the @code{continue} statement outside the +body of a @code{while}, @code{for}, or @code{do} loop. Traditional +@code{awk} implementations have treated such usage as equivalent to the +@code{next} statement. @code{gawk} will support this usage if @samp{-W posix} +has not been specified. + +@node Sample Program, Bugs, Gawk Summary, Top +@appendix Sample Program + +The following example is a complete @code{awk} program, which prints +the number of occurrences of each word in its input. It illustrates the +associative nature of @code{awk} arrays by using strings as subscripts. It +also demonstrates the @samp{for @var{x} in @var{array}} construction. +Finally, it shows how @code{awk} can be used in conjunction with other +utility programs to do a useful task of some complexity with a minimum of +effort. Some explanations follow the program listing.@refill + +@example +awk ' +# Print list of word frequencies +@{ + for (i = 1; i <= NF; i++) + freq[$i]++ +@} + +END @{ + for (word in freq) + printf "%s\t%d\n", word, freq[word] +@}' +@end example + +The first thing to notice about this program is that it has two rules. The +first rule, because it has an empty pattern, is executed on every line of +the input. It uses @code{awk}'s field-accessing mechanism +(@pxref{Fields, ,Examining Fields}) to pick out the individual words from +the line, and the built-in variable @code{NF} (@pxref{Built-in Variables}) +to know how many fields are available.@refill + +For each input word, an element of the array @code{freq} is incremented to +reflect that the word has been seen an additional time.@refill + +The second rule, because it has the pattern @code{END}, is not executed +until the input has been exhausted. It prints out the contents of the +@code{freq} table that has been built up inside the first action.@refill + +Note that this program has several problems that would prevent it from being +useful by itself on real text files:@refill + +@itemize @bullet +@item +Words are detected using the @code{awk} convention that fields are +separated by whitespace and that other characters in the input (except +newlines) don't have any special meaning to @code{awk}. This means that +punctuation characters count as part of words.@refill + +@item +The @code{awk} language considers upper and lower case characters to be +distinct. Therefore, @samp{foo} and @samp{Foo} are not treated by this +program as the same word. This is undesirable since in normal text, words +are capitalized if they begin sentences, and a frequency analyzer should not +be sensitive to that.@refill + +@item +The output does not come out in any useful order. You're more likely to be +interested in which words occur most frequently, or having an alphabetized +table of how frequently each word occurs.@refill +@end itemize + +The way to solve these problems is to use some of the more advanced +features of the @code{awk} language. First, we use @code{tolower} to remove +case distinctions. Next, we use @code{gsub} to remove punctuation +characters. Finally, we use the system @code{sort} utility to process the +output of the @code{awk} script. First, here is the new version of +the program:@refill + +@example +awk ' +# Print list of word frequencies +@{ + $0 = tolower($0) # remove case distinctions + gsub(/[^a-z0-9_ \t]/, "", $0) # remove punctuation + for (i = 1; i <= NF; i++) + freq[$i]++ +@} + +END @{ + for (word in freq) + printf "%s\t%d\n", word, freq[word] +@}' +@end example + +Assuming we have saved this program in a file named @file{frequency.awk}, +and that the data is in @file{file1}, the following pipeline + +@example +awk -f frequency.awk file1 | sort +1 -nr +@end example + +@noindent +produces a table of the words appearing in @file{file1} in order of +decreasing frequency. + +The @code{awk} program suitably massages the data and produces a word +frequency table, which is not ordered. + +The @code{awk} script's output is then sorted by the @code{sort} command and +printed on the terminal. The options given to @code{sort} in this example +specify to sort using the second field of each input line (skipping one field), +that the sort keys should be treated as numeric quantities (otherwise +@samp{15} would come before @samp{5}), and that the sorting should be done +in descending (reverse) order.@refill + +We could have even done the @code{sort} from within the program, by +changing the @code{END} action to: + +@example +END @{ + sort = "sort +1 -nr" + for (word in freq) + printf "%s\t%d\n", word, freq[word] | sort + close(sort) +@}' +@end example + +See the general operating system documentation for more information on how +to use the @code{sort} command.@refill + +@ignore +@strong{ADR: I have some more substantial programs courtesy of Rick Adams +at UUNET. I am planning on incorporating those either in addition to or +instead of this program.} + +@strong{I would also like to incorporate the general @code{translate} +function that I have written.} + +@strong{I have a ton of other sample programs to include too.} +@end ignore + +@node Bugs, Notes, Sample Program, Top +@appendix Reporting Problems and Bugs + +@c This chapter stolen shamelessly from the GNU m4 manual. +@c This chapter has been unshamelessly altered to emulate changes made to +@c make.texi from whence it was originally shamelessly stolen! :-} --mew + +If you have problems with @code{gawk} or think that you have found a bug, +please report it to the developers; we cannot promise to do anything +but we might well want to fix it. + +Before reporting a bug, make sure you have actually found a real bug. +Carefully reread the documentation and see if it really says you can do +what you're trying to do. If it's not clear whether you should be able +to do something or not, report that too; it's a bug in the documentation! + +Before reporting a bug or trying to fix it yourself, try to isolate it +to the smallest possible @code{awk} program and input data file that +reproduces the problem. Then send us the program and data file, +some idea of what kind of Unix system you're using, and the exact results +@code{gawk} gave you. Also say what you expected to occur; this will help +us decide whether the problem was really in the documentation. + +Once you have a precise problem, send e-mail to (Internet) +@samp{bug-gnu-utils@@prep.ai.mit.edu} or (UUCP) +@samp{mit-eddie!prep.ai.mit.edu!bug-gnu-utils}. Please include the +version number of @code{gawk} you are using. You can get this information +with the command @samp{gawk -W version '@{@}' /dev/null}. +You should send carbon copies of your mail to David Trueman at +@samp{david@@cs.dal.ca}, and to Arnold Robbins, who can be reached at +@samp{arnold@@skeeve.atl.ga.us}. David is most likely to fix code +problems, while Arnold is most likely to fix documentation problems.@refill + +Non-bug suggestions are always welcome as well. If you have questions +about things that are unclear in the documentation or are just obscure +features, ask Arnold Robbins; he will try to help you out, although he +may not have the time to fix the problem. You can send him electronic mail at the Internet address +above. + +If you find bugs in one of the non-Unix ports of @code{gawk}, please send +an electronic mail message to the person who maintains that port. They +are listed below, and also in the @file{README} file in the @code{gawk} +distribution. Information in the @code{README} file should be considered +authoritative if it conflicts with this manual. + +The people maintaining the non-Unix ports of @code{gawk} are: + +@table @asis +@item MS-DOS +The port to MS-DOS is maintained by Scott Deifik. +His electronic mail address is @samp{scottd@@amgen.com}. + +@item VMS +The port to VAX VMS is maintained by Pat Rankin. +His electronic mail address is @samp{rankin@@eql.caltech.edu}. + +@item Atari ST +The port to the Atari ST is maintained by Michal Jaegermann. +His electronic mail address is @samp{ntomczak@@vm.ucs.ualberta.ca}. + +@end table + +If your bug is also reproducible under Unix, please send copies of your +report to the general GNU bug list, as well as to Arnold Robbins and David +Trueman, at the addresses listed above. + +@node Notes, Glossary, Bugs, Top +@appendix Implementation Notes + +This appendix contains information mainly of interest to implementors and +maintainers of @code{gawk}. Everything in it applies specifically to +@code{gawk}, and not to other implementations. + +@menu +* Compatibility Mode:: How to disable certain @code{gawk} extensions. +* Future Extensions:: New features we may implement soon. +* Improvements:: Suggestions for improvements by volunteers. +@end menu + +@node Compatibility Mode, Future Extensions, Notes, Notes +@appendixsec Downward Compatibility and Debugging + +@xref{POSIX/GNU, ,Extensions in @code{gawk} not in POSIX @code{awk}}, +for a summary of the GNU extensions to the @code{awk} language and program. +All of these features can be turned off by invoking @code{gawk} with the +@samp{-W compat} option, or with the @samp{-W posix} option.@refill + +If @code{gawk} is compiled for debugging with @samp{-DDEBUG}, then there +is one more option available on the command line: + +@table @samp +@item -W parsedebug +Print out the parse stack information as the program is being parsed. +@end table + +This option is intended only for serious @code{gawk} developers, +and not for the casual user. It probably has not even been compiled into +your version of @code{gawk}, since it slows down execution. + +@node Future Extensions, Improvements, Compatibility Mode, Notes +@appendixsec Probable Future Extensions + +This section briefly lists extensions that indicate the directions we are +currently considering for @code{gawk}. The file @file{FUTURES} in the +@code{gawk} distributions lists these extensions, as well as several others. + +@table @asis +@item @code{RS} as a regexp +The meaning of @code{RS} may be generalized along the lines of @code{FS}. + +@item Control of subprocess environment +Changes made in @code{gawk} to the array @code{ENVIRON} may be +propagated to subprocesses run by @code{gawk}. + +@item Databases +It may be possible to map a GDBM/NDBM/SDBM file into an @code{awk} array. + +@item Single-character fields +The null string, @code{""}, as a field separator, will cause field +splitting and the @code{split} function to separate individual characters. +Thus, @code{split(a, "abcd", "")} would yield @code{a[1] == "a"}, +@code{a[2] == "b"}, and so on. + +@item More @code{lint} warnings +There are more things that could be checked for portability. + +@item @code{RECLEN} variable for fixed length records +Along with @code{FIELDWIDTHS}, this would speed up the processing of +fixed-length records. + +@item @code{RT} variable to hold the record terminator +It is occasionally useful to have access to the actual string of +characters that matched the @code{RS} variable. The @code{RT} +variable would hold these characters. + +@item A @code{restart} keyword +After modifying @code{$0}, @code{restart} would restart the pattern +matching loop, without reading a new record from the input. + +@item A @samp{|&} redirection +The @samp{|&} redirection, in place of @samp{|}, would open a two-way +pipeline for communication with a sub-process (via @code{getline} and +@code{print} and @code{printf}). + +@item @code{IGNORECASE} affecting all comparisons +The effects of the @code{IGNORECASE} variable may be generalized to +all string comparisons, and not just regular expression operations. + +@item A way to mix command line source code and library files +There may be a new option that would make it possible to easily use library +functions from a program entered on the command line. +@c probably a @samp{-s} option... + +@item GNU-style long options +We will add GNU-style long options +to @code{gawk} for compatibility with other GNU programs. +(For example, @samp{--field-separator=:} would be equivalent to +@samp{-F:}.)@refill + +@c this is @emph{very} long term --- not worth including right now. +@ignore +@item The C Comma Operator +We may add the C comma operator, which takes the form +@code{@var{expr1},@var{expr2}}. The first expression is evaluated, and the +result is thrown away. The value of the full expression is the value of +@var{expr2}.@refill +@end ignore +@end table + +@node Improvements, , Future Extensions, Notes +@appendixsec Suggestions for Improvements + +Here are some projects that would-be @code{gawk} hackers might like to take +on. They vary in size from a few days to a few weeks of programming, +depending on which one you choose and how fast a programmer you are. Please +send any improvements you write to the maintainers at the GNU +project.@refill + +@enumerate +@item +Compilation of @code{awk} programs: @code{gawk} uses a Bison (YACC-like) +parser to convert the script given it into a syntax tree; the syntax +tree is then executed by a simple recursive evaluator. This method incurs +a lot of overhead, since the recursive evaluator performs many procedure +calls to do even the simplest things.@refill + +It should be possible for @code{gawk} to convert the script's parse tree +into a C program which the user would then compile, using the normal +C compiler and a special @code{gawk} library to provide all the needed +functions (regexps, fields, associative arrays, type coercion, and so +on).@refill + +An easier possibility might be for an intermediate phase of @code{awk} to +convert the parse tree into a linear byte code form like the one used +in GNU Emacs Lisp. The recursive evaluator would then be replaced by +a straight line byte code interpreter that would be intermediate in speed +between running a compiled program and doing what @code{gawk} does +now.@refill + +This may actually happen for the 3.0 version of @code{gawk}. + +@item +An error message section has not been included in this version of the +manual. Perhaps some nice beta testers will document some of the messages +for the future. + +@item +The programs in the test suite could use documenting in this manual. + +@item +The programs and data files in the manual should be available in +separate files to facilitate experimentation. + +@item +See the @file{FUTURES} file for more ideas. Contact us if you would +seriously like to tackle any of the items listed there. +@end enumerate + +@node Glossary, Index, Notes, Top +@appendix Glossary + +@table @asis +@item Action +A series of @code{awk} statements attached to a rule. If the rule's +pattern matches an input record, the @code{awk} language executes the +rule's action. Actions are always enclosed in curly braces. +@xref{Actions, ,Overview of Actions}.@refill + +@item Amazing @code{awk} Assembler +Henry Spencer at the University of Toronto wrote a retargetable assembler +completely as @code{awk} scripts. It is thousands of lines long, including +machine descriptions for several 8-bit microcomputers. +@c It is distributed with @code{gawk} (as part of the test suite) and +It is a good example of a +program that would have been better written in another language.@refill + +@item @sc{ansi} +The American National Standards Institute. This organization produces +many standards, among them the standard for the C programming language. + +@item Assignment +An @code{awk} expression that changes the value of some @code{awk} +variable or data object. An object that you can assign to is called an +@dfn{lvalue}. @xref{Assignment Ops, ,Assignment Expressions}.@refill + +@item @code{awk} Language +The language in which @code{awk} programs are written. + +@item @code{awk} Program +An @code{awk} program consists of a series of @dfn{patterns} and +@dfn{actions}, collectively known as @dfn{rules}. For each input record +given to the program, the program's rules are all processed in turn. +@code{awk} programs may also contain function definitions.@refill + +@item @code{awk} Script +Another name for an @code{awk} program. + +@item Built-in Function +The @code{awk} language provides built-in functions that perform various +numerical, time stamp related, and string computations. Examples are +@code{sqrt} (for the square root of a number) and @code{substr} (for a +substring of a string). @xref{Built-in, ,Built-in Functions}.@refill + +@item Built-in Variable +@code{ARGC}, @code{ARGIND}, @code{ARGV}, @code{CONVFMT}, @code{ENVIRON}, +@code{ERRNO}, @code{FIELDWIDTHS}, @code{FILENAME}, @code{FNR}, @code{FS}, +@code{IGNORECASE}, @code{NF}, @code{NR}, @code{OFMT}, @code{OFS}, @code{ORS}, +@code{RLENGTH}, @code{RSTART}, @code{RS}, and @code{SUBSEP}, +are the variables that have special +meaning to @code{awk}. Changing some of them affects @code{awk}'s running +environment. @xref{Built-in Variables}.@refill + +@item Braces +See ``Curly Braces.'' + +@item C +The system programming language that most GNU software is written in. The +@code{awk} programming language has C-like syntax, and this manual +points out similarities between @code{awk} and C when appropriate.@refill + +@item CHEM +A preprocessor for @code{pic} that reads descriptions of molecules +and produces @code{pic} input for drawing them. It was written by +Brian Kernighan, and is available from @code{netlib@@research.att.com}.@refill + +@item Compound Statement +A series of @code{awk} statements, enclosed in curly braces. Compound +statements may be nested. +@xref{Statements, ,Control Statements in Actions}.@refill + +@item Concatenation +Concatenating two strings means sticking them together, one after another, +giving a new string. For example, the string @samp{foo} concatenated with +the string @samp{bar} gives the string @samp{foobar}. +@xref{Concatenation, ,String Concatenation}.@refill + +@item Conditional Expression +An expression using the @samp{?:} ternary operator, such as +@code{@var{expr1} ? @var{expr2} : @var{expr3}}. The expression +@var{expr1} is evaluated; if the result is true, the value of the whole +expression is the value of @var{expr2} otherwise the value is +@var{expr3}. In either case, only one of @var{expr2} and @var{expr3} +is evaluated. @xref{Conditional Exp, ,Conditional Expressions}.@refill + +@item Constant Regular Expression +A constant regular expression is a regular expression written within +slashes, such as @samp{/foo/}. This regular expression is chosen +when you write the @code{awk} program, and cannot be changed doing +its execution. @xref{Regexp Usage, ,How to Use Regular Expressions}. + +@item Comparison Expression +A relation that is either true or false, such as @code{(a < b)}. +Comparison expressions are used in @code{if}, @code{while}, and @code{for} +statements, and in patterns to select which input records to process. +@xref{Comparison Ops, ,Comparison Expressions}.@refill + +@item Curly Braces +The characters @samp{@{} and @samp{@}}. Curly braces are used in +@code{awk} for delimiting actions, compound statements, and function +bodies.@refill + +@item Data Objects +These are numbers and strings of characters. Numbers are converted into +strings and vice versa, as needed. +@xref{Conversion, ,Conversion of Strings and Numbers}.@refill + +@item Dynamic Regular Expression +A dynamic regular expression is a regular expression written as an +ordinary expression. It could be a string constant, such as +@code{"foo"}, but it may also be an expression whose value may vary. +@xref{Regexp Usage, ,How to Use Regular Expressions}. + +@item Escape Sequences +A special sequence of characters used for describing nonprinting +characters, such as @samp{\n} for newline, or @samp{\033} for the ASCII +ESC (escape) character. @xref{Constants, ,Constant Expressions}. + +@item Field +When @code{awk} reads an input record, it splits the record into pieces +separated by whitespace (or by a separator regexp which you can +change by setting the built-in variable @code{FS}). Such pieces are +called fields. If the pieces are of fixed length, you can use the built-in +variable @code{FIELDWIDTHS} to describe their lengths. +@xref{Records, ,How Input is Split into Records}.@refill + +@item Format +Format strings are used to control the appearance of output in the +@code{printf} statement. Also, data conversions from numbers to strings +are controlled by the format string contained in the built-in variable +@code{CONVFMT}. @xref{Control Letters, ,Format-Control Letters}.@refill + +@item Function +A specialized group of statements often used to encapsulate general +or program-specific tasks. @code{awk} has a number of built-in +functions, and also allows you to define your own. +@xref{Built-in, ,Built-in Functions}. +Also, see @ref{User-defined, ,User-defined Functions}.@refill + +@item @code{gawk} +The GNU implementation of @code{awk}. + +@item GNU +``GNU's not Unix''. An on-going project of the Free Software Foundation +to create a complete, freely distributable, @sc{posix}-compliant computing +environment. + +@item Input Record +A single chunk of data read in by @code{awk}. Usually, an @code{awk} input +record consists of one line of text. +@xref{Records, ,How Input is Split into Records}.@refill + +@item Keyword +In the @code{awk} language, a keyword is a word that has special +meaning. Keywords are reserved and may not be used as variable names. + +@code{awk}'s keywords are: +@code{if}, +@code{else}, +@code{while}, +@code{do@dots{}while}, +@code{for}, +@code{for@dots{}in}, +@code{break}, +@code{continue}, +@code{delete}, +@code{next}, +@code{function}, +@code{func}, +and @code{exit}.@refill + +@item Lvalue +An expression that can appear on the left side of an assignment +operator. In most languages, lvalues can be variables or array +elements. In @code{awk}, a field designator can also be used as an +lvalue.@refill + +@item Number +A numeric valued data object. The @code{gawk} implementation uses double +precision floating point to represent numbers.@refill + +@item Pattern +Patterns tell @code{awk} which input records are interesting to which +rules. + +A pattern is an arbitrary conditional expression against which input is +tested. If the condition is satisfied, the pattern is said to @dfn{match} +the input record. A typical pattern might compare the input record against +a regular expression. @xref{Patterns}.@refill + +@item @sc{posix} +The name for a series of standards being developed by the @sc{ieee} +that specify a Portable Operating System interface. The ``IX'' denotes +the Unix heritage of these standards. The main standard of interest for +@code{awk} users is P1003.2, the Command Language and Utilities standard. + +@item Range (of input lines) +A sequence of consecutive lines from the input file. A pattern +can specify ranges of input lines for @code{awk} to process, or it can +specify single lines. @xref{Patterns}.@refill + +@item Recursion +When a function calls itself, either directly or indirectly. +If this isn't clear, refer to the entry for ``recursion.'' + +@item Redirection +Redirection means performing input from other than the standard input +stream, or output to other than the standard output stream. + +You can redirect the output of the @code{print} and @code{printf} statements +to a file or a system command, using the @samp{>}, @samp{>>}, and @samp{|} +operators. You can redirect input to the @code{getline} statement using +the @samp{<} and @samp{|} operators. +@xref{Redirection, ,Redirecting Output of @code{print} and @code{printf}}.@refill + +@item Regular Expression +See ``regexp.'' + +@item Regexp +Short for @dfn{regular expression}. A regexp is a pattern that denotes a +set of strings, possibly an infinite set. For example, the regexp +@samp{R.*xp} matches any string starting with the letter @samp{R} +and ending with the letters @samp{xp}. In @code{awk}, regexps are +used in patterns and in conditional expressions. Regexps may contain +escape sequences. @xref{Regexp, ,Regular Expressions as Patterns}.@refill + +@item Rule +A segment of an @code{awk} program, that specifies how to process single +input records. A rule consists of a @dfn{pattern} and an @dfn{action}. +@code{awk} reads an input record; then, for each rule, if the input record +satisfies the rule's pattern, @code{awk} executes the rule's action. +Otherwise, the rule does nothing for that input record.@refill + +@item Side Effect +A side effect occurs when an expression has an effect aside from merely +producing a value. Assignment expressions, increment expressions and +function calls have side effects. @xref{Assignment Ops, ,Assignment Expressions}. + +@item Special File +A file name interpreted internally by @code{gawk}, instead of being handed +directly to the underlying operating system. For example, @file{/dev/stdin}. +@xref{Special Files, ,Standard I/O Streams}. + +@item Stream Editor +A program that reads records from an input stream and processes them one +or more at a time. This is in contrast with batch programs, which may +expect to read their input files in entirety before starting to do +anything, and with interactive programs, which require input from the +user.@refill + +@item String +A datum consisting of a sequence of characters, such as @samp{I am a +string}. Constant strings are written with double-quotes in the +@code{awk} language, and may contain escape sequences. +@xref{Constants, ,Constant Expressions}. + +@item Whitespace +A sequence of blank or tab characters occurring inside an input record or a +string.@refill +@end table + +@node Index, , Glossary, Top +@unnumbered Index +@printindex cp + +@summarycontents +@contents +@bye + +Unresolved Issues: +------------------ +1. From: ntomczak@vm.ucs.ualberta.ca (Michal Jaegermann) + Examples of usage tend to suggest that /../ and ".." delimiters + can be used for regular expressions, even if definition is consistently + using /../. I am not sure what the real rules are and in particular + what of the following is a bug and what is a feature: + # This program matches everything + '"\(" { print }' + # This one complains about mismatched parenthesis + '$0 ~ "\(" { print }' + # This one behaves in an expected manner + '/\(/ { print }' + You may also try to use "\(" as an argument to match() to see what + will happen. + +2. From ADR. + + The posix (and original Unix!) notion of awk values as both number + and string values needs to be put into the manual. This involves + major and minor rewrites of most of the manual, but should help in + clarifying many of the weirder points of the language. + +3. From ADR. + + The manual should be reorganized. Expressions should be introduced + early, building up to regexps as expressions, and from there to their + use as patterns and then in actions. Built-in vars should come earlier + in the manual too. The 'expert info' sections marked with comments + should get their own sections or subsections with nodes and titles. + The manual should be gone over thoroughly for indexing. + +4. From ADR. + + Robert J. Chassell points out that awk programs should have some indication + of how to use them. It would be useful to perhaps have a "programming + style" section of the manual that would include this and other tips. + +5. From ADR in response to moraes@uunet.ca + (This would make the beginnings of a good "puzzles" section...) + + Date: Mon, 2 Dec 91 10:08:05 EST + From: gatech!cc!arnold (Arnold Robbins) + To: cs.dal.ca!david, uunet.ca!moraes + Subject: redirecting to /dev/stderr + Cc: skeeve!arnold, boeing.com!brennan, research.att.com!bwk + + In 2.13.3 the following program no longer dumps core: + + BEGIN { print "hello" > /dev/stderr ; exit(1) } + + Instead, it creates a file named `0' with the word `hello' in it. AWK + semantics strikes again. The meaning of the statement is + + print "hello" > (($0 ~ /dev/) stderr) + + /dev/ tests $0 for the pattern `dev'. This yields a 0. The variable stderr, + having never been used, has a null string in it. The concatenation yields + a string value of "0" which is used as the file name. Sigh. + + I think with some more time I can come up with a decent fix, but it will + probably only print a diagnostic with -Wlint. + + Arnold + diff --git a/gnu/usr.bin/awk/getopt.c b/gnu/usr.bin/awk/getopt.c new file mode 100644 index 0000000000..bbf345c33c --- /dev/null +++ b/gnu/usr.bin/awk/getopt.c @@ -0,0 +1,662 @@ +/* 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, 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 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. */ + +#ifdef GAWK +#include "config.h" +#endif + +#include + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#include +#endif /* GNU C library. */ + + +#ifndef __STDC__ +#define const +#endif + +/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a + long-named option. Because this is not POSIX.2 compliant, it is + being phased out. */ +#define GETOPT_COMPAT + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + 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. */ + +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 + 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__ +#include +#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; + int chr; +{ + while (*string) + { + if (*string == chr) + return string; + string++; + } + 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. */ + +/* 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 **) malloc (nonopts_size); + + /* Interchange the two blocks of data in ARGV. */ + + 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); + + free(temp); + + /* 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 = 0; + extern int strncmp(); + + 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 '?'; + } + } + 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 (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 = 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) + 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 = 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); +} + +#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/awk/getopt.h b/gnu/usr.bin/awk/getopt.h new file mode 100644 index 0000000000..de027434f7 --- /dev/null +++ b/gnu/usr.bin/awk/getopt.h @@ -0,0 +1,128 @@ +/* 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 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 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. */ + +#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; + +/* 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'. */ + +enum _argtype +{ + no_argument, + required_argument, + optional_argument +}; + +#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/awk/getopt1.c b/gnu/usr.bin/awk/getopt1.c new file mode 100644 index 0000000000..e2127cd58d --- /dev/null +++ b/gnu/usr.bin/awk/getopt1.c @@ -0,0 +1,160 @@ +/* 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. */ + +#ifdef LIBC +/* For when compiled as part of the GNU C library. */ +#include +#endif + +#include "getopt.h" + +#ifndef __STDC__ +#define const +#endif + +#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC) +#include +#else /* STDC_HEADERS or __GNU_LIBRARY__ */ +char *getenv (); +#endif /* STDC_HEADERS or __GNU_LIBRARY__ */ + +#if !defined (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); +} + +#ifdef TEST + +#include + +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/awk/io.c b/gnu/usr.bin/awk/io.c new file mode 100644 index 0000000000..7004aedd51 --- /dev/null +++ b/gnu/usr.bin/awk/io.c @@ -0,0 +1,1207 @@ +/* + * io.c --- routines for dealing with input and output and records + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +#ifndef O_RDONLY +#include +#endif + +#if !defined(S_ISDIR) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +#ifndef atarist +#define INVALID_HANDLE (-1) +#else +#define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1) +#endif + +#if defined(MSDOS) || defined(atarist) +#define PIPES_SIMULATED +#endif + +static IOBUF *nextfile P((int skipping)); +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)); +#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 int gawk_pclose P((struct redirect *rp)); +static int do_pathopen P((char *file)); + +extern FILE *fdopen(); +extern FILE *popen(); + +static struct redirect *red_head = NULL; + +extern int output_is_tty; +extern NODE *ARGC_node; +extern NODE *ARGV_node; +extern NODE *ARGIND_node; +extern NODE *ERRNO_node; +extern NODE **fields_arr; + +static jmp_buf filebuf; /* for do_nextfile() */ + +/* do_nextfile --- implement gawk "next file" extension */ + +void +do_nextfile() +{ + (void) nextfile(1); + longjmp(filebuf, 1); +} + +static IOBUF * +nextfile(skipping) +int skipping; +{ + static int i = 1; + static int files = 0; + NODE *arg; + int fd = INVALID_HANDLE; + static IOBUF *curfile = NULL; + + if (skipping) { + if (curfile != NULL) + iop_close(curfile); + curfile = NULL; + return NULL; + } + if (curfile != NULL) { + if (curfile->cnt == EOF) { + (void) iop_close(curfile); + curfile = NULL; + } else + return curfile; + } + for (; i < (int) (ARGC_node->lnode->numbr); i++) { + arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)); + if (arg->stptr[0] == '\0') + continue; + arg->stptr[arg->stlen] = '\0'; + if (! do_unix) { + ARGIND_node->var_value->numbr = i; + ARGIND_node->var_value->flags = NUM|NUMBER; + } + if (!arg_assign(arg->stptr)) { + files++; + curfile = iop_open(arg->stptr, "r"); + if (curfile == NULL) + fatal("cannot open file `%s' for reading (%s)", + arg->stptr, strerror(errno)); + /* NOTREACHED */ + /* This is a kludge. */ + unref(FILENAME_node->var_value); + FILENAME_node->var_value = + dupnode(arg); + FNR = 0; + i++; + break; + } + } + if (files == 0) { + files++; + /* no args. -- use stdin */ + /* FILENAME is init'ed to "-" */ + /* FNR is init'ed to 0 */ + curfile = iop_alloc(fileno(stdin)); + } + return curfile; +} + +void +set_FNR() +{ + FNR = (int) FNR_node->var_value->numbr; +} + +void +set_NR() +{ + NR = (int) NR_node->var_value->numbr; +} + +/* + * This reads in a record from the input file + */ +static int +inrec(iop) +IOBUF *iop; +{ + char *begin; + register int cnt; + int retval = 0; + + cnt = get_a_record(&begin, iop, *RS, NULL); + if (cnt == EOF) { + cnt = 0; + retval = 1; + } else { + NR += 1; + FNR += 1; + } + set_record(begin, cnt, 1); + + return retval; +} + +static int +iop_close(iop) +IOBUF *iop; +{ + int ret; + + if (iop == NULL) + return 0; + errno = 0; + +#ifdef _CRAY + /* Work around bug in UNICOS popen */ + if (iop->fd < 3) + ret = 0; + else +#endif + /* save these for re-use; don't free the storage */ + if ((iop->flag & IOP_IS_INTERNAL) != 0) { + iop->off = iop->buf; + iop->end = iop->buf + strlen(iop->buf); + iop->cnt = 0; + iop->secsiz = 0; + return 0; + } + + /* Don't close standard files or else crufty code elsewhere will lose */ + if (iop->fd == fileno(stdin) || + iop->fd == fileno(stdout) || + iop->fd == fileno(stderr)) + ret = 0; + else + ret = close(iop->fd); + if (ret == -1) + warning("close of fd %d failed (%s)", iop->fd, strerror(errno)); + if ((iop->flag & IOP_NO_FREE) == 0) { + /* + * be careful -- $0 may still reference the buffer even though + * an explicit close is being done; in the future, maybe we + * can do this a bit better + */ + if (iop->buf) { + if ((fields_arr[0]->stptr >= iop->buf) + && (fields_arr[0]->stptr < iop->end)) { + NODE *t; + + t = make_string(fields_arr[0]->stptr, + fields_arr[0]->stlen); + unref(fields_arr[0]); + fields_arr [0] = t; + reset_record (); + } + free(iop->buf); + } + free((char *)iop); + } + return ret == -1 ? 1 : 0; +} + +void +do_input() +{ + IOBUF *iop; + extern int exiting; + + if (setjmp(filebuf) != 0) { + } + while ((iop = nextfile(0)) != NULL) { + if (inrec(iop) == 0) + while (interpret(expression_value) && inrec(iop) == 0) + ; + if (exiting) + break; + } +} + +/* Redirection for printf and print commands */ +struct redirect * +redirect(tree, errflg) +NODE *tree; +int *errflg; +{ + register NODE *tmp; + register struct redirect *rp; + register char *str; + int tflag = 0; + int outflag = 0; + char *direction = "to"; + char *mode; + int fd; + char *what = NULL; + + switch (tree->type) { + case Node_redirect_append: + tflag = RED_APPEND; + /* FALL THROUGH */ + case Node_redirect_output: + outflag = (RED_FILE|RED_WRITE); + tflag |= outflag; + if (tree->type == Node_redirect_output) + what = ">"; + else + what = ">>"; + break; + case Node_redirect_pipe: + tflag = (RED_PIPE|RED_WRITE); + what = "|"; + break; + case Node_redirect_pipein: + tflag = (RED_PIPE|RED_READ); + what = "|"; + break; + case Node_redirect_input: + tflag = (RED_FILE|RED_READ); + what = "<"; + break; + default: + fatal ("invalid tree type %d in redirect()", tree->type); + break; + } + tmp = tree_eval(tree->subnode); + if (do_lint && ! (tmp->flags & STR)) + warning("expression in `%s' redirection only has numeric value", + what); + tmp = force_string(tmp); + str = tmp->stptr; + if (str == NULL || *str == '\0') + fatal("expression for `%s' redirection has null string value", + what); + if (do_lint + && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen))) + warning("filename `%s' for `%s' redirection may be result of logical expression", str, what); + for (rp = red_head; rp != NULL; rp = rp->next) + if (strlen(rp->value) == tmp->stlen + && STREQN(rp->value, str, tmp->stlen) + && ((rp->flag & ~(RED_NOBUF|RED_EOF)) == tflag + || (outflag + && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) + break; + if (rp == NULL) { + emalloc(rp, struct redirect *, sizeof(struct redirect), + "redirect"); + emalloc(str, char *, tmp->stlen+1, "redirect"); + memcpy(str, tmp->stptr, tmp->stlen); + str[tmp->stlen] = '\0'; + rp->value = str; + rp->flag = tflag; + rp->fp = NULL; + rp->iop = NULL; + rp->pid = 0; /* unlikely that we're worried about init */ + rp->status = 0; + /* maintain list in most-recently-used first order */ + if (red_head) + red_head->prev = rp; + rp->prev = NULL; + rp->next = red_head; + red_head = rp; + } + while (rp->fp == NULL && rp->iop == NULL) { + if (rp->flag & RED_EOF) + /* encountered EOF on file or pipe -- must be cleared + * by explicit close() before reading more + */ + return rp; + mode = NULL; + errno = 0; + switch (tree->type) { + case Node_redirect_output: + mode = "w"; + if (rp->flag & RED_USED) + mode = "a"; + break; + case Node_redirect_append: + mode = "a"; + break; + case Node_redirect_pipe: + if ((rp->fp = popen(str, "w")) == NULL) + fatal("can't open pipe (\"%s\") for output (%s)", + str, strerror(errno)); + rp->flag |= RED_NOBUF; + break; + case Node_redirect_pipein: + direction = "from"; + if (gawk_popen(str, rp) == NULL) + fatal("can't open pipe (\"%s\") for input (%s)", + str, strerror(errno)); + break; + case Node_redirect_input: + direction = "from"; + rp->iop = iop_open(str, "r"); + break; + default: + cant_happen(); + } + if (mode != NULL) { + fd = devopen(str, mode); + if (fd > INVALID_HANDLE) { + if (fd == fileno(stdin)) + rp->fp = stdin; + else if (fd == fileno(stdout)) + rp->fp = stdout; + else if (fd == fileno(stderr)) + rp->fp = stderr; + else + rp->fp = fdopen(fd, mode); + if (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) + close_one(); + else { + /* + * Some other reason for failure. + * + * On redirection of input from a file, + * just return an error, so e.g. getline + * can return -1. For output to file, + * complain. The shell will complain on + * a bad command to a pipe. + */ + *errflg = errno; + if (tree->type == Node_redirect_output + || tree->type == Node_redirect_append) + fatal("can't redirect %s `%s' (%s)", + direction, str, strerror(errno)); + else { + free_temp(tmp); + return NULL; + } + } + } + } + free_temp(tmp); + return rp; +} + +static void +close_one() +{ + register struct redirect *rp; + register struct redirect *rplast = NULL; + + /* go to end of list first, to pick up least recently used entry */ + for (rp = red_head; rp != NULL; rp = rp->next) + rplast = rp; + /* now work back up through the list */ + for (rp = rplast; rp != NULL; rp = rp->prev) + if (rp->fp && (rp->flag & RED_FILE)) { + rp->flag |= RED_USED; + errno = 0; + if (fclose(rp->fp)) + warning("close of \"%s\" failed (%s).", + rp->value, strerror(errno)); + rp->fp = NULL; + break; + } + if (rp == NULL) + /* surely this is the only reason ??? */ + fatal("too many pipes or input files open"); +} + +NODE * +do_close(tree) +NODE *tree; +{ + NODE *tmp; + register struct redirect *rp; + + tmp = force_string(tree_eval(tree->subnode)); + for (rp = red_head; rp != NULL; rp = rp->next) { + if (strlen(rp->value) == tmp->stlen + && STREQN(rp->value, tmp->stptr, tmp->stlen)) + break; + } + free_temp(tmp); + if (rp == NULL) /* no match */ + return tmp_number((AWKNUM) 0.0); + fflush(stdout); /* synchronize regular output */ + tmp = tmp_number((AWKNUM)close_redir(rp)); + rp = NULL; + return tmp; +} + +static int +close_redir(rp) +register struct redirect *rp; +{ + int status = 0; + + if (rp == NULL) + return 0; + if (rp->fp == stdout || rp->fp == stderr) + return 0; + errno = 0; + if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) + status = pclose(rp->fp); + else if (rp->fp) + status = fclose(rp->fp); + else if (rp->iop) { + if (rp->flag & RED_PIPE) + status = gawk_pclose(rp); + else { + status = iop_close(rp->iop); + rp->iop = NULL; + } + } + /* 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); + + if (! do_unix) { + /* set ERRNO too so that program can get at it */ + unref(ERRNO_node->var_value); + ERRNO_node->var_value = make_string(s, strlen(s)); + } + } + if (rp->next) + rp->next->prev = rp->prev; + if (rp->prev) + rp->prev->next = rp->next; + else + red_head = rp->next; + free(rp->value); + free((char *)rp); + return status; +} + +int +flush_io () +{ + register struct redirect *rp; + int status = 0; + + errno = 0; + if (fflush(stdout)) { + warning("error writing standard output (%s).", strerror(errno)); + status++; + } + if (fflush(stderr)) { + warning("error writing standard error (%s).", strerror(errno)); + status++; + } + for (rp = red_head; rp != NULL; rp = rp->next) + /* flush both files and pipes, what the heck */ + if ((rp->flag & RED_WRITE) && rp->fp != NULL) { + if (fflush(rp->fp)) { + warning("%s flush of \"%s\" failed (%s).", + (rp->flag & RED_PIPE) ? "pipe" : + "file", rp->value, strerror(errno)); + status++; + } + } + return status; +} + +int +close_io () +{ + register struct redirect *rp; + register struct redirect *next; + int status = 0; + + errno = 0; + if (fclose(stdout)) { + warning("error writing standard output (%s).", strerror(errno)); + status++; + } + if (fclose(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; +} + +/* str2mode --- convert a string mode to an integer mode */ + +static int +str2mode(mode) +char *mode; +{ + int ret; + + switch(mode[0]) { + case 'r': + ret = O_RDONLY; + break; + + case 'w': + ret = O_WRONLY|O_CREAT|O_TRUNC; + break; + + case 'a': + ret = O_WRONLY|O_APPEND|O_CREAT; + break; + default: + cant_happen(); + } + return ret; +} + +/* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */ + +/* + * This separate version is still needed for output, since file and pipe + * output is done with stdio. iop_open() handles input with IOBUFs of + * more "special" files. Those files are not handled here since it makes + * no sense to use them for output. + */ + +int +devopen(name, mode) +char *name, *mode; +{ + int openfd = INVALID_HANDLE; + char *cp, *ptr; + int flag = 0; + struct stat buf; + extern double strtod(); + + flag = str2mode(mode); + + if (do_unix) + goto strictopen; + +#ifdef VMS + if ((openfd = vms_devopen(name, flag)) >= 0) + return openfd; +#endif /* VMS */ + + if (STREQ(name, "-")) + openfd = fileno(stdin); + else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) { + cp = name + 5; + + if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY) + openfd = fileno(stdin); + else if (STREQ(cp, "stdout") && (flag & O_WRONLY) == O_WRONLY) + openfd = fileno(stdout); + else if (STREQ(cp, "stderr") && (flag & O_WRONLY) == O_WRONLY) + openfd = fileno(stderr); + else if (STREQN(cp, "fd/", 3)) { + cp += 3; + openfd = (int)strtod(cp, &ptr); + if (openfd <= INVALID_HANDLE || ptr == cp) + openfd = INVALID_HANDLE; + } + } + +strictopen: + if (openfd == INVALID_HANDLE) + openfd = open(name, flag, 0666); + if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) + if (S_ISDIR(buf.st_mode)) + fatal("file `%s' is a directory", name); + return openfd; +} + + +/* spec_setup --- setup an IOBUF for a special internal file */ + +void +spec_setup(iop, len, allocate) +IOBUF *iop; +int len; +int allocate; +{ + char *cp; + + if (allocate) { + emalloc(cp, char *, len+2, "spec_setup"); + iop->buf = cp; + } else { + len = strlen(iop->buf); + iop->buf[len++] = '\n'; /* get_a_record clobbered it */ + iop->buf[len] = '\0'; /* just in case */ + } + iop->off = iop->buf; + iop->cnt = 0; + iop->secsiz = 0; + iop->size = len; + iop->end = iop->buf + len; + iop->fd = -1; + iop->flag = IOP_IS_INTERNAL; +} + +/* specfdopen --- open a fd special file */ + +int +specfdopen(iop, name, mode) +IOBUF *iop; +char *name, *mode; +{ + int fd; + IOBUF *tp; + + fd = devopen(name, mode); + if (fd == INVALID_HANDLE) + return INVALID_HANDLE; + tp = iop_alloc(fd); + if (tp == NULL) + return INVALID_HANDLE; + *iop = *tp; + iop->flag |= IOP_NO_FREE; + free(tp); + return 0; +} + +/* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */ + +int +pidopen(iop, name, mode) +IOBUF *iop; +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 + else if (name[6] == 'i') + sprintf(tbuf, "%d\n", getpid()); + else + sprintf(tbuf, "%d\n", getppid()); + i = strlen(tbuf); + spec_setup(iop, i, 1); + strcpy(iop->buf, tbuf); + return 0; +} + +/* useropen --- "open" /dev/user */ + +/* + * /dev/user creates a record as follows: + * $1 = getuid() + * $2 = geteuid() + * $3 = getgid() + * $4 = getegid() + * If multiple groups are supported, the $5 through $NF are the + * supplementary group set. + */ + +int +useropen(iop, name, mode) +IOBUF *iop; +char *name, *mode; +{ + char tbuf[BUFSIZ], *cp; + int i; +#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0 + int groupset[NGROUPS_MAX]; + int ngroups; +#endif + + sprintf(tbuf, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid()); + + cp = tbuf + strlen(tbuf); +#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0 + ngroups = getgroups(NGROUPS_MAX, groupset); + if (ngroups == -1) + fatal("could not find groups: %s", strerror(errno)); + + for (i = 0; i < ngroups; i++) { + *cp++ = ' '; + sprintf(cp, "%d", groupset[i]); + cp += strlen(cp); + } +#endif + *cp++ = '\n'; + *cp++ = '\0'; + + + i = strlen(tbuf); + spec_setup(iop, i, 1); + strcpy(iop->buf, tbuf); + return 0; +} + +/* iop_open --- handle special and regular files for input */ + +static IOBUF * +iop_open(name, mode) +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; + int compare; + int (*fp)(); + IOBUF iob; + } table[] = { + { "/dev/fd/", 8, specfdopen }, + { "/dev/stdin", 10, specfdopen }, + { "/dev/stdout", 11, specfdopen }, + { "/dev/stderr", 11, specfdopen }, + { "/dev/pid", 8, pidopen }, + { "/dev/ppid", 9, pidopen }, + { "/dev/pgrpid", 11, pidopen }, + { "/dev/user", 9, useropen }, + }; + int devcount = sizeof(table) / sizeof(table[0]); + + flag = str2mode(mode); + + if (do_unix) + goto strictopen; + + if (STREQ(name, "-")) + openfd = fileno(stdin); + else if (STREQN(name, "/dev/", 5) && stat(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; + + if (iop->buf != NULL) { + spec_setup(iop, 0, 0); + return iop; + } else if ((*table[i].fp)(iop, name, mode) == 0) + return iop; + else { + warning("could not open %s, mode `%s'", + name, mode); + return NULL; + } + } + } + } + +strictopen: + if (openfd == INVALID_HANDLE) + openfd = open(name, flag, 0666); + if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) + if ((buf.st_mode & S_IFMT) == S_IFDIR) + fatal("file `%s' is a directory", name); + iop = iop_alloc(openfd); + return iop; +} + +#ifndef PIPES_SIMULATED + /* real pipes */ +static int +wait_any(interesting) +int interesting; /* pid of interest, if any */ +{ + SIGTYPE (*hstat)(), (*istat)(), (*qstat)(); + int pid; + int status = 0; + struct redirect *redp; + extern int errno; + + hstat = signal(SIGHUP, SIG_IGN); + istat = signal(SIGINT, SIG_IGN); + qstat = signal(SIGQUIT, SIG_IGN); + for (;;) { +#ifdef NeXT + pid = wait((union wait *)&status); +#else + pid = wait(&status); +#endif /* NeXT */ + if (interesting && pid == interesting) { + break; + } else if (pid != -1) { + for (redp = red_head; redp != NULL; redp = redp->next) + if (pid == redp->pid) { + redp->pid = -1; + redp->status = status; + if (redp->fp) { + pclose(redp->fp); + redp->fp = 0; + } + if (redp->iop) { + (void) iop_close(redp->iop); + redp->iop = 0; + } + break; + } + } + if (pid == -1 && errno == ECHILD) + break; + } + signal(SIGHUP, hstat); + signal(SIGINT, istat); + signal(SIGQUIT, qstat); + return(status); +} + +static IOBUF * +gawk_popen(cmd, rp) +char *cmd; +struct redirect *rp; +{ + int p[2]; + register int pid; + + /* used to wait for any children to synchronize input and output, + * but this could cause gawk to hang when it is started in a pipeline + * and thus has a child process feeding it input (shell dependant) + */ + /*(void) wait_any(0);*/ /* wait for outstanding processes */ + + if (pipe(p) < 0) + fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno)); + if ((pid = fork()) == 0) { + if (close(1) == -1) + fatal("close of stdout in child failed (%s)", + strerror(errno)); + if (dup(p[1]) != 1) + fatal("dup of pipe failed (%s)", strerror(errno)); + if (close(p[0]) == -1 || close(p[1]) == -1) + fatal("close of pipe failed (%s)", strerror(errno)); + if (close(0) == -1) + fatal("close of stdin in child failed (%s)", + strerror(errno)); + execl("/bin/sh", "sh", "-c", cmd, 0); + _exit(127); + } + if (pid == -1) + fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno)); + rp->pid = pid; + if (close(p[1]) == -1) + fatal("close of pipe failed (%s)", strerror(errno)); + return (rp->iop = iop_alloc(p[0])); +} + +static int +gawk_pclose(rp) +struct redirect *rp; +{ + (void) iop_close(rp->iop); + rp->iop = NULL; + + /* process previously found, return stored status */ + if (rp->pid == -1) + return (rp->status >> 8) & 0xFF; + rp->status = wait_any(rp->pid); + rp->pid = -1; + return (rp->status >> 8) & 0xFF; +} + +#else /* PIPES_SIMULATED */ + /* use temporary file rather than pipe */ + +#ifdef VMS +static IOBUF * +gawk_popen(cmd, rp) +char *cmd; +struct redirect *rp; +{ + FILE *current; + + if ((current = popen(cmd, "r")) == NULL) + return NULL; + return (rp->iop = iop_alloc(fileno(current))); +} + +static int +gawk_pclose(rp) +struct redirect *rp; +{ + int rval, aval, fd = rp->iop->fd; + FILE *kludge = fdopen(fd, "r"); /* pclose needs FILE* w/ right fileno */ + + rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */ + rval = iop_close(rp->iop); + rp->iop = NULL; + aval = pclose(kludge); + return (rval < 0 ? rval : aval); +} +#else /* VMS */ + +static +struct { + char *command; + char *name; +} pipes[_NFILE]; + +static IOBUF * +gawk_popen(cmd, rp) +char *cmd; +struct redirect *rp; +{ + extern char *strdup(const char *); + int current; + char *name; + static char cmdbuf[256]; + + /* get a name to use. */ + if ((name = tempnam(".", "pip")) == NULL) + return NULL; + sprintf(cmdbuf,"%s > %s", cmd, name); + system(cmdbuf); + if ((current = open(name,O_RDONLY)) == INVALID_HANDLE) + return NULL; + pipes[current].name = name; + pipes[current].command = strdup(cmd); + rp->iop = iop_alloc(current); + return (rp->iop = iop_alloc(current)); +} + +static int +gawk_pclose(rp) +struct redirect *rp; +{ + int cur = rp->iop->fd; + int rval; + + rval = iop_close(rp->iop); + rp->iop = NULL; + + /* check for an open file */ + if (pipes[cur].name == NULL) + return -1; + unlink(pipes[cur].name); + free(pipes[cur].name); + pipes[cur].name = NULL; + free(pipes[cur].command); + return rval; +} +#endif /* VMS */ + +#endif /* PIPES_SIMULATED */ + +NODE * +do_getline(tree) +NODE *tree; +{ + struct redirect *rp = NULL; + IOBUF *iop; + int cnt = EOF; + char *s = NULL; + int errcode; + + while (cnt == EOF) { + if (tree->rnode == NULL) { /* no redirection */ + iop = nextfile(0); + if (iop == NULL) /* end of input */ + return tmp_number((AWKNUM) 0.0); + } else { + int redir_error = 0; + + rp = redirect(tree->rnode, &redir_error); + if (rp == NULL && redir_error) { /* failed redirect */ + if (! do_unix) { + char *s = strerror(redir_error); + + unref(ERRNO_node->var_value); + ERRNO_node->var_value = + make_string(s, strlen(s)); + } + return tmp_number((AWKNUM) -1.0); + } + iop = rp->iop; + if (iop == NULL) /* end of input */ + return tmp_number((AWKNUM) 0.0); + } + errcode = 0; + cnt = get_a_record(&s, iop, *RS, & errcode); + if (! do_unix && errcode != 0) { + char *s = strerror(errcode); + + unref(ERRNO_node->var_value); + ERRNO_node->var_value = make_string(s, strlen(s)); + return tmp_number((AWKNUM) -1.0); + } + if (cnt == EOF) { + if (rp) { + /* + * Don't do iop_close() here if we are + * reading from a pipe; otherwise + * gawk_pclose will not be called. + */ + if (!(rp->flag & RED_PIPE)) { + (void) iop_close(iop); + rp->iop = NULL; + } + rp->flag |= RED_EOF; /* sticky EOF */ + return tmp_number((AWKNUM) 0.0); + } else + continue; /* try another file */ + } + if (!rp) { + NR += 1; + FNR += 1; + } + if (tree->lnode == NULL) /* no optional var. */ + set_record(s, cnt, 1); + else { /* assignment to variable */ + Func_ptr after_assign = NULL; + NODE **lhs; + + lhs = get_lhs(tree->lnode, &after_assign); + unref(*lhs); + *lhs = make_string(s, strlen(s)); + (*lhs)->flags |= MAYBE_NUM; + /* we may have to regenerate $0 here! */ + if (after_assign) + (*after_assign)(); + } + } + return tmp_number((AWKNUM) 1.0); +} + +int +pathopen (file) +char *file; +{ + int fd = do_pathopen(file); + +#ifdef DEFAULT_FILETYPE + if (! do_unix && fd <= INVALID_HANDLE) { + char *file_awk; + int save = errno; +#ifdef VMS + int vms_save = vaxc$errno; +#endif + + /* append ".awk" and try again */ + emalloc(file_awk, char *, strlen(file) + + sizeof(DEFAULT_FILETYPE) + 1, "pathopen"); + sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE); + fd = do_pathopen(file_awk); + free(file_awk); + if (fd <= INVALID_HANDLE) { + errno = save; +#ifdef VMS + vaxc$errno = vms_save; +#endif + } + } +#endif /*DEFAULT_FILETYPE*/ + + return fd; +} + +static int +do_pathopen (file) +char *file; +{ + static char *savepath = DEFPATH; /* defined in config.h */ + static int first = 1; + char *awkpath, *cp; + char trypath[BUFSIZ]; + int fd; + + if (STREQ(file, "-")) + return (0); + + if (do_unix) + return (devopen(file, "r")); + + if (first) { + first = 0; + if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath) + savepath = awkpath; /* used for restarting */ + } + awkpath = savepath; + + /* some kind of path name, no search */ +#ifdef VMS /* (strchr not equal implies either or both not NULL) */ + if (strchr(file, ':') != strchr(file, ']') + || strchr(file, '>') != strchr(file, '/')) +#else /*!VMS*/ +#ifdef MSDOS + if (strchr(file, '/') != strchr(file, '\\') + || strchr(file, ':') != NULL) +#else + if (strchr(file, '/') != NULL) +#endif /*MSDOS*/ +#endif /*VMS*/ + return (devopen(file, "r")); + + do { + trypath[0] = '\0'; + /* this should take into account limits on size of trypath */ + for (cp = trypath; *awkpath && *awkpath != ENVSEP; ) + *cp++ = *awkpath++; + + if (cp != trypath) { /* nun-null element in path */ + /* add directory punctuation only if needed */ +#ifdef VMS + if (strchr(":]>/", *(cp-1)) == NULL) +#else +#ifdef MSDOS + if (strchr(":\\/", *(cp-1)) == NULL) +#else + if (*(cp-1) != '/') +#endif +#endif + *cp++ = '/'; + /* append filename */ + strcpy (cp, file); + } else + strcpy (trypath, file); + if ((fd = devopen(trypath, "r")) >= 0) + return (fd); + + /* no luck, keep going */ + if(*awkpath == ENVSEP && awkpath[1] != '\0') + awkpath++; /* skip colon */ + } while (*awkpath); + /* + * You might have one of the awk + * paths defined, WITHOUT the current working directory in it. + * Therefore try to open the file in the current directory. + */ + return (devopen(file, "r")); +} diff --git a/gnu/usr.bin/awk/iop.c b/gnu/usr.bin/awk/iop.c new file mode 100644 index 0000000000..0d7af1213d --- /dev/null +++ b/gnu/usr.bin/awk/iop.c @@ -0,0 +1,318 @@ +/* + * iop.c - do i/o related things. + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +#ifndef atarist +#define INVALID_HANDLE (-1) +#else +#include +#include +#define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1) +#endif /* atarist */ + + +#ifdef TEST +int bufsize = 8192; + +void +fatal(s) +char *s; +{ + printf("%s\n", s); + exit(1); +} +#endif + +int +optimal_bufsize(fd) +int fd; +{ + struct stat stb; + +#ifdef VMS + /* + * These values correspond with the RMS multi-block count used by + * vms_open() in vms/vms_misc.c. + */ + if (isatty(fd) > 0) + return BUFSIZ; + else if (fstat(fd, &stb) < 0) + return 8*512; /* conservative in case of DECnet access */ + else + return 24*512; + +#else + /* + * System V doesn't have the file system block size in the + * stat structure. So we have to make some sort of reasonable + * guess. We use stdio's BUFSIZ, since that is what it was + * meant for in the first place. + */ +#ifdef BLKSIZE_MISSING +#define DEFBLKSIZE BUFSIZ +#else +#define DEFBLKSIZE (stb.st_blksize ? stb.st_blksize : BUFSIZ) +#endif + +#ifdef TEST + return bufsize; +#else +#ifndef atarist + if (isatty(fd)) +#else + /* + * On ST redirected stdin does not have a name attached + * (this could be hard to do to) and fstat would fail + */ + if (0 == fd || isatty(fd)) +#endif /*atarist */ + return BUFSIZ; +#ifndef BLKSIZE_MISSING + /* VMS POSIX 1.0: st_blksize is never assigned a value, so zero it */ + stb.st_blksize = 0; +#endif + if (fstat(fd, &stb) == -1) + fatal("can't stat fd %d (%s)", fd, strerror(errno)); + if (lseek(fd, (off_t)0, 0) == -1) + return DEFBLKSIZE; + return ((int) (stb.st_size < DEFBLKSIZE ? stb.st_size : DEFBLKSIZE)); +#endif /*! TEST */ +#endif /*! VMS */ +} + +IOBUF * +iop_alloc(fd) +int fd; +{ + IOBUF *iop; + + if (fd == INVALID_HANDLE) + return NULL; + emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc"); + iop->flag = 0; + if (isatty(fd)) + iop->flag |= IOP_IS_TTY; + iop->size = optimal_bufsize(fd); + iop->secsiz = -2; + errno = 0; + iop->fd = fd; + iop->off = iop->buf = NULL; + iop->cnt = 0; + return iop; +} + +/* + * Get the next record. Uses a "split buffer" where the latter part is + * the normal read buffer and the head part is an "overflow" area that is used + * when a record spans the end of the normal buffer, in which case the first + * part of the record is copied into the overflow area just before the + * normal buffer. Thus, the eventual full record can be returned as a + * contiguous area of memory with a minimum of copying. The overflow area + * is expanded as needed, so that records are unlimited in length. + * We also mark both the end of the buffer and the end of the read() with + * a sentinel character (the current record separator) so that the inside + * loop can run as a single test. + */ +int +get_a_record(out, iop, grRS, errcode) +char **out; +IOBUF *iop; +register int grRS; +int *errcode; +{ + register char *bp = iop->off; + char *bufend; + char *start = iop->off; /* beginning of record */ + int saw_newline; + char rs; + int eat_whitespace; + + if (iop->cnt == EOF) /* previous read hit EOF */ + return EOF; + + if (grRS == 0) { /* special case: grRS == "" */ + rs = '\n'; + eat_whitespace = 0; + saw_newline = 0; + } else + rs = (char) grRS; + + /* set up sentinel */ + if (iop->buf) { + bufend = iop->buf + iop->size + iop->secsiz; + *bufend = rs; + } else + bufend = NULL; + + for (;;) { /* break on end of record, read error or EOF */ + + /* Following code is entered on the first call of this routine + * for a new iop, or when we scan to the end of the buffer. + * In the latter case, we copy the current partial record to + * the space preceding the normal read buffer. If necessary, + * we expand this space. This is done so that we can return + * the record as a contiguous area of memory. + */ + if ((iop->flag & IOP_IS_INTERNAL) == 0 && bp >= bufend) { + char *oldbuf = NULL; + 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 */ + if (iop->secsiz == -2) + iop->secsiz = 256; + while (len > iop->secsiz) + iop->secsiz *= 2; + oldbuf = iop->buf; + emalloc(iop->buf, char *, + iop->size+iop->secsiz+2, "get_a_record"); + bufend = iop->buf + iop->size + iop->secsiz; + *bufend = rs; + } + if (len > 0) { + char *newsplit = iop->buf + iop->secsiz; + + if (start < oldsplit) { + memcpy(newsplit - len, start, + oldsplit - start); + memcpy(newsplit - (bp - oldsplit), + oldsplit, bp - oldsplit); + } else + memcpy(newsplit - len, start, len); + } + bp = iop->end = iop->off = iop->buf + iop->secsiz; + start = bp - len; + if (oldbuf) { + free(oldbuf); + oldbuf = NULL; + } + } + /* Following code is entered whenever we have no more data to + * scan. In most cases this will read into the beginning of + * the main buffer, but in some cases (terminal, pipe etc.) + * we may be doing smallish reads into more advanced positions. + */ + if (bp >= iop->end) { + if ((iop->flag & IOP_IS_INTERNAL) != 0) { + iop->cnt = EOF; + break; + } + iop->cnt = read(iop->fd, iop->end, bufend - iop->end); + if (iop->cnt == -1) { + if (! do_unix && errcode != NULL) { + *errcode = errno; + iop->cnt = EOF; + break; + } else + fatal("error reading input: %s", + strerror(errno)); + } else if (iop->cnt == 0) { + iop->cnt = EOF; + break; + } + iop->end += iop->cnt; + *iop->end = rs; + } + if (grRS == 0) { + extern int default_FS; + + if (default_FS && (bp == start || eat_whitespace)) { + while (bp < iop->end && isspace(*bp)) + bp++; + if (bp == iop->end) { + eat_whitespace = 1; + continue; + } else + eat_whitespace = 0; + } + if (saw_newline && *bp == rs) { + bp++; + break; + } + saw_newline = 0; + } + + while (*bp++ != rs) + ; + + if (bp <= iop->end) { + if (grRS == 0) + saw_newline = 1; + else + break; + } else + bp--; + + if ((iop->flag & IOP_IS_INTERNAL) != 0) + iop->cnt = bp - start; + } + if (iop->cnt == EOF + && (((iop->flag & IOP_IS_INTERNAL) != 0) || start == bp)) + return EOF; + + iop->off = bp; + bp--; + if (*bp != rs) + bp++; + *bp = '\0'; + if (grRS == 0) { + if (*--bp == rs) + *bp = '\0'; + else + bp++; + } + + *out = start; + return bp - start; +} + +#ifdef TEST +main(argc, argv) +int argc; +char *argv[]; +{ + IOBUF *iop; + char *out; + int cnt; + char rs[2]; + + rs[0] = 0; + if (argc > 1) + bufsize = atoi(argv[1]); + if (argc > 2) + rs[0] = *argv[2]; + iop = iop_alloc(0); + while ((cnt = get_a_record(&out, iop, rs[0], NULL)) > 0) { + fwrite(out, 1, cnt, stdout); + fwrite(rs, 1, 1, stdout); + } +} +#endif diff --git a/gnu/usr.bin/awk/main.c b/gnu/usr.bin/awk/main.c new file mode 100644 index 0000000000..77d0bf74e1 --- /dev/null +++ b/gnu/usr.bin/awk/main.c @@ -0,0 +1,731 @@ +/* + * main.c -- Expression tree constructors and main program for gawk. + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "getopt.h" +#include "awk.h" +#include "patchlevel.h" + +static void usage P((int exitval)); +static void copyleft P((void)); +static void cmdline_fs P((char *str)); +static void init_args P((int argc0, int argc, char *argv0, char **argv)); +static void init_vars P((void)); +static void pre_assign P((char *v)); +SIGTYPE catchsig P((int sig, int code)); +static void gawk_option P((char *optstr)); +static void nostalgia P((void)); +static void version P((void)); +char *gawk_name P((char *filespec)); + +#ifdef MSDOS +extern int isatty P((int)); +#endif + +extern void resetup P((void)); + +/* These nodes store all the special variables AWK uses */ +NODE *FS_node, *NF_node, *RS_node, *NR_node; +NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node; +NODE *CONVFMT_node; +NODE *ERRNO_node; +NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node; +NODE *ENVIRON_node, *IGNORECASE_node; +NODE *ARGC_node, *ARGV_node, *ARGIND_node; +NODE *FIELDWIDTHS_node; + +int NF; +int NR; +int FNR; +int IGNORECASE; +char *RS; +char *OFS; +char *ORS; +char *OFMT; +char *CONVFMT; + +/* + * The parse tree and field nodes are stored here. Parse_end is a dummy item + * used to free up unneeded fields without freeing the program being run + */ +int errcount = 0; /* error counter, used by yyerror() */ + +/* The global null string */ +NODE *Nnull_string; + +/* The name the program was invoked under, for error messages */ +const char *myname; + +/* A block of AWK code to be run before running the program */ +NODE *begin_block = 0; + +/* A block of AWK code to be run after the last input file */ +NODE *end_block = 0; + +int exiting = 0; /* Was an "exit" statement executed? */ +int exit_val = 0; /* optional exit value */ + +#if defined(YYDEBUG) || defined(DEBUG) +extern int yydebug; +#endif + +struct src *srcfiles = NULL; /* source file name(s) */ +int numfiles = -1; /* how many source files */ + +int do_unix = 0; /* turn off gnu extensions */ +int do_posix = 0; /* turn off gnu and unix extensions */ +int do_lint = 0; /* provide warnings about questionable stuff */ +int do_nostalgia = 0; /* provide a blast from the past */ + +int in_begin_rule = 0; /* we're in a BEGIN rule */ +int in_end_rule = 0; /* we're in a END rule */ + +int output_is_tty = 0; /* control flushing of output */ + +extern char *version_string; /* current version, for printing */ + +NODE *expression_value; + +static struct option optab[] = { + { "compat", no_argument, & do_unix, 1 }, + { "lint", no_argument, & do_lint, 1 }, + { "posix", no_argument, & do_posix, 1 }, + { "nostalgia", no_argument, & do_nostalgia, 1 }, + { "copyleft", no_argument, NULL, 'C' }, + { "copyright", no_argument, NULL, 'C' }, + { "field-separator", required_argument, NULL, 'F' }, + { "file", required_argument, NULL, 'f' }, + { "assign", required_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, + { "usage", no_argument, NULL, 'u' }, + { "help", no_argument, NULL, 'u' }, + { "source", required_argument, NULL, 's' }, +#ifdef DEBUG + { "parsedebug", no_argument, NULL, 'D' }, +#endif + { 0, 0, 0, 0 } +}; + +int +main(argc, argv) +int argc; +char **argv; +{ + int c; + char *scan; + extern int optind; + extern int opterr; + extern char *optarg; + int i; + + (void) signal(SIGFPE, (SIGTYPE (*) P((int))) catchsig); + (void) signal(SIGSEGV, (SIGTYPE (*) P((int))) catchsig); +#ifdef SIGBUS + (void) signal(SIGBUS, (SIGTYPE (*) P((int))) catchsig); +#endif + + myname = gawk_name(argv[0]); + argv[0] = (char *)myname; +#ifdef VMS + vms_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */ +#endif + + /* remove sccs gunk */ + if (strncmp(version_string, "@(#)", 4) == 0) + version_string += 4; + + if (argc < 2) + usage(1); + + /* initialize the null string */ + Nnull_string = make_string("", 0); + Nnull_string->numbr = 0.0; + Nnull_string->type = Node_val; + 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 + */ + init_vars(); + + /* worst case */ + emalloc(srcfiles, struct src *, argc * sizeof(struct src), "main"); + memset(srcfiles, '\0', argc * sizeof(struct src)); + + /* Tell the regex routines how they should work. . . */ + resetup(); + + /* 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) { + if (do_posix) + opterr = 1; + switch (c) { + case 'F': + cmdline_fs(optarg); + break; + + case 'f': + /* + * a la MKS awk, allow multiple -f options. + * this makes function libraries real easy. + * most of the magic is in the scanner. + */ + /* The following is to allow for whitespace at the end + * of a #! /bin/gawk line in an executable file + */ + scan = optarg; + while (isspace(*scan)) + scan++; + ++numfiles; + srcfiles[numfiles].stype = SOURCEFILE; + if (*scan == '\0') + srcfiles[numfiles].val = argv[optind++]; + else + srcfiles[numfiles].val = optarg; + break; + + case 'v': + pre_assign(optarg); + break; + + case 'W': /* gawk specific options */ + gawk_option(optarg); + break; + + /* These can only come from long form options */ + case 'V': + version(); + break; + + case 'C': + copyleft(); + break; + + case 'u': + usage(0); + break; + + case 's': + if (strlen(optarg) == 0) + warning("empty argument to --source ignored"); + else { + srcfiles[++numfiles].stype = CMDLINE; + srcfiles[numfiles].val = optarg; + } + break; + +#ifdef DEBUG + case 'D': + yydebug = 2; + break; +#endif + + case '?': + default: + /* + * New behavior. If not posix, an unrecognized + * 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. + */ + if (! do_posix) + goto out; + /* else + let getopt print error message for us */ + break; + } + } +out: + + if (do_nostalgia) + nostalgia(); + + /* POSIX compliance also implies no Unix extensions either */ + if (do_posix) + do_unix = 1; + +#ifdef DEBUG + setbuf(stdout, (char *) NULL); /* make debugging easier */ +#endif + if (isatty(fileno(stdout))) + output_is_tty = 1; + /* No -f or --source options, use next arg */ + if (numfiles == -1) { + if (optind > argc - 1) /* no args left */ + usage(1); + srcfiles[++numfiles].stype = CMDLINE; + srcfiles[numfiles].val = argv[optind]; + optind++; + } + init_args(optind, argc, (char *) myname, argv); + (void) tokexpand(); + + /* Read in the program */ + if (yyparse() || errcount) + exit(1); + + /* Set up the field variables */ + init_fields(); + + if (begin_block) { + in_begin_rule = 1; + (void) interpret(begin_block); + } + in_begin_rule = 0; + if (!exiting && (expression_value || end_block)) + do_input(); + if (end_block) { + in_end_rule = 1; + (void) interpret(end_block); + } + in_end_rule = 0; + if (close_io() != 0 && exit_val == 0) + exit_val = 1; + exit(exit_val); /* more portable */ + return exit_val; /* to suppress warnings */ +} + +/* usage --- print usage information and exit */ + +static void +usage(exitval) +int exitval; +{ + char *opt1 = " -f progfile [--]"; + char *opt2 = " [--] 'program'"; + char *regops = " [POSIX or GNU style options]"; + + version(); + fprintf(stderr, "usage: %s%s%s file ...\n %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("\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-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 + fputs("\t-W nostalgia\t\t--nostalgia\n", stderr); +#endif +#ifdef DEBUG + fputs("\t-W parsedebug\t\t--parsedebug\n", stderr); +#endif + fputs("\t-W posix\t\t--posix\n", stderr); + fputs("\t-W source=program-text\t--source=program-text\n", stderr); + fputs("\t-W usage\t\t--usage\n", stderr); + fputs("\t-W version\t\t--version\n", stderr); + exit(exitval); +} + +static void +copyleft () +{ + static char blurb_part1[] = +"Copyright (C) 1989, 1991, 1992, Free Software Foundation.\n\ +\n\ +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"; + static char blurb_part2[] = +"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"; + static char blurb_part3[] = +"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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"; + + version(); + fputs(blurb_part1, stderr); + fputs(blurb_part2, stderr); + fputs(blurb_part3, stderr); + fflush(stderr); +} + +static void +cmdline_fs(str) +char *str; +{ + register NODE **tmp; + int len = strlen(str); + + tmp = get_lhs(FS_node, (Func_ptr *) 0); + unref(*tmp); + /* + * Only if in full compatibility mode check for the stupid special + * case so -F\t works as documented in awk even though the shell + * hands us -Ft. Bleah! + * + * Thankfully, Posix didn't propogate this "feature". + */ + if (str[0] == 't' && str[1] == '\0') { + if (do_lint) + warning("-Ft does not set FS to tab in POSIX awk"); + if (do_unix && ! do_posix) + str[0] = '\t'; + } + *tmp = make_str_node(str, len, SCAN); /* do process escapes */ + set_FS(); +} + +static void +init_args(argc0, argc, argv0, argv) +int argc0, argc; +char *argv0; +char **argv; +{ + int i, j; + NODE **aptr; + + ARGV_node = install("ARGV", node(Nnull_string, Node_var, (NODE *)NULL)); + aptr = assoc_lookup(ARGV_node, tmp_number(0.0)); + *aptr = make_string(argv0, strlen(argv0)); + (*aptr)->flags |= MAYBE_NUM; + for (i = argc0, j = 1; i < argc; i++) { + aptr = assoc_lookup(ARGV_node, tmp_number((AWKNUM) j)); + *aptr = make_string(argv[i], strlen(argv[i])); + (*aptr)->flags |= MAYBE_NUM; + j++; + } + ARGC_node = install("ARGC", + node(make_number((AWKNUM) j), Node_var, (NODE *) NULL)); +} + +/* + * Set all the special variables to their initial values. + */ +struct varinit { + NODE **spec; + char *name; + NODETYPE type; + char *strval; + AWKNUM numval; + Func_ptr assign; +}; +static struct varinit varinit[] = { +{&NF_node, "NF", Node_NF, 0, -1, set_NF }, +{&FIELDWIDTHS_node, "FIELDWIDTHS", Node_FIELDWIDTHS, "", 0, 0 }, +{&NR_node, "NR", Node_NR, 0, 0, set_NR }, +{&FNR_node, "FNR", Node_FNR, 0, 0, set_FNR }, +{&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 }, +{&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 }, +{&CONVFMT_node, "CONVFMT", Node_CONVFMT, "%.6g", 0, set_CONVFMT }, +{&RLENGTH_node, "RLENGTH", Node_var, 0, 0, 0 }, +{&RSTART_node, "RSTART", Node_var, 0, 0, 0 }, +{&SUBSEP_node, "SUBSEP", Node_var, "\034", 0, 0 }, +{&ARGIND_node, "ARGIND", Node_var, 0, 0, 0 }, +{&ERRNO_node, "ERRNO", Node_var, 0, 0, 0 }, +{0, 0, Node_illegal, 0, 0, 0 }, +}; + +static void +init_vars() +{ + register struct varinit *vp; + + for (vp = varinit; vp->name; vp++) { + *(vp->spec) = install(vp->name, + node(vp->strval == 0 ? make_number(vp->numval) + : make_string(vp->strval, strlen(vp->strval)), + vp->type, (NODE *) NULL)); + if (vp->assign) + (*(vp->assign))(); + } +} + +void +load_environ() +{ +#if !defined(MSDOS) && !(defined(VMS) && defined(__DECC)) + extern char **environ; +#endif + register char *var, *val; + NODE **aptr; + register int i; + + ENVIRON_node = install("ENVIRON", + node(Nnull_string, Node_var, (NODE *) NULL)); + for (i = 0; environ[i]; i++) { + static char nullstr[] = ""; + + var = environ[i]; + val = strchr(var, '='); + if (val) + *val++ = '\0'; + else + val = nullstr; + aptr = assoc_lookup(ENVIRON_node, tmp_string(var, strlen (var))); + *aptr = make_string(val, strlen (val)); + (*aptr)->flags |= MAYBE_NUM; + + /* restore '=' so that system() gets a valid environment */ + if (val != nullstr) + *--val = '='; + } +} + +/* Process a command-line assignment */ +char * +arg_assign(arg) +char *arg; +{ + char *cp; + Func_ptr after_assign = NULL; + NODE *var; + NODE *it; + NODE **lhs; + + cp = strchr(arg, '='); + if (cp != NULL) { + *cp++ = '\0'; + /* + * Recent versions of nawk expand escapes inside assignments. + * This makes sense, so we do it too. + */ + it = make_str_node(cp, strlen(cp), SCAN); + it->flags |= MAYBE_NUM; + var = variable(arg, 0); + lhs = get_lhs(var, &after_assign); + unref(*lhs); + *lhs = it; + if (after_assign) + (*after_assign)(); + *--cp = '='; /* restore original text of ARGV */ + } + return cp; +} + +static void +pre_assign(v) +char *v; +{ + if (!arg_assign(v)) { + fprintf (stderr, + "%s: '%s' argument to -v not in 'var=value' form\n", + myname, v); + usage(1); + } +} + +SIGTYPE +catchsig(sig, code) +int sig, code; +{ +#ifdef lint + code = 0; sig = code; code = sig; +#endif + if (sig == SIGFPE) { + fatal("floating point exception"); + } else if (sig == SIGSEGV +#ifdef SIGBUS + || sig == SIGBUS +#endif + ) { + msg("fatal error: internal error"); + /* fatal won't abort() if not compiled for debugging */ + abort(); + } else + cant_happen(); + /* NOTREACHED */ +} + +/* gawk_option --- do gawk specific things */ + +static void +gawk_option(optstr) +char *optstr; +{ + char *cp; + + for (cp = optstr; *cp; cp++) { + switch (*cp) { + case ' ': + case '\t': + case ',': + break; + case 'v': + case 'V': + /* print version */ + if (strncasecmp(cp, "version", 7) != 0) + goto unknown; + else + cp += 6; + version(); + break; + case 'c': + case 'C': + if (strncasecmp(cp, "copyright", 9) == 0) { + cp += 8; + copyleft(); + } else if (strncasecmp(cp, "copyleft", 8) == 0) { + cp += 7; + copyleft(); + } else if (strncasecmp(cp, "compat", 6) == 0) { + cp += 5; + do_unix = 1; + } else + goto unknown; + break; + case 'n': + case 'N': + /* + * Undocumented feature, + * inspired by nostalgia, and a T-shirt + */ + if (strncasecmp(cp, "nostalgia", 9) != 0) + goto unknown; + nostalgia(); + break; + case 'p': + case 'P': +#ifdef DEBUG + if (strncasecmp(cp, "parsedebug", 10) == 0) { + cp += 9; + yydebug = 2; + break; + } +#endif + if (strncasecmp(cp, "posix", 5) != 0) + goto unknown; + cp += 4; + do_posix = do_unix = 1; + break; + case 'l': + case 'L': + if (strncasecmp(cp, "lint", 4) != 0) + goto unknown; + cp += 3; + do_lint = 1; + break; + case 'H': + case 'h': + if (strncasecmp(cp, "help", 4) != 0) + goto unknown; + cp += 3; + usage(0); + break; + case 'U': + case 'u': + if (strncasecmp(cp, "usage", 5) != 0) + goto unknown; + cp += 4; + usage(0); + break; + case 's': + case 'S': + if (strncasecmp(cp, "source=", 7) != 0) + goto unknown; + cp += 7; + if (strlen(cp) == 0) + warning("empty argument to -Wsource ignored"); + else { + srcfiles[++numfiles].stype = CMDLINE; + srcfiles[numfiles].val = cp; + return; + } + break; + default: + unknown: + fprintf(stderr, "'%c' -- unknown option, ignored\n", + *cp); + break; + } + } +} + +/* nostalgia --- print the famous error message and die */ + +static void +nostalgia() +{ + fprintf(stderr, "awk: bailing out near line 1\n"); + abort(); +} + +/* version --- print version message */ + +static void +version() +{ + fprintf(stderr, "%s, patchlevel %d\n", version_string, PATCHLEVEL); +} + +/* static */ +char * +gawk_name(filespec) +char *filespec; +{ + char *p; + +#ifdef VMS /* "device:[root.][directory.subdir]GAWK.EXE;n" -> "GAWK" */ + char *q; + + p = strrchr(filespec, ']'); /* directory punctuation */ + q = strrchr(filespec, '>'); /* alternate punct */ + + 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; + + p = filespec; + + if (q = strrchr(p, '\\')) + p = q + 1; + if (q = strchr(p, '.')) + *q = '\0'; + strlwr(p); + + return (p == NULL ? filespec : p); +#endif /* MSDOS || atarist */ + + /* "path/name" -> "name" */ + p = strrchr(filespec, '/'); + return (p == NULL ? filespec : p + 1); +} diff --git a/gnu/usr.bin/awk/msg.c b/gnu/usr.bin/awk/msg.c new file mode 100644 index 0000000000..b60fe9d1e5 --- /dev/null +++ b/gnu/usr.bin/awk/msg.c @@ -0,0 +1,106 @@ +/* + * msg.c - routines for error messages + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +int sourceline = 0; +char *source = NULL; + +/* VARARGS2 */ +void +err(s, emsg, argp) +char *s; +char *emsg; +va_list argp; +{ + char *file; + + (void) fflush(stdout); + (void) fprintf(stderr, "%s: ", myname); + if (sourceline) { + if (source) + (void) fprintf(stderr, "%s:", source); + else + (void) fprintf(stderr, "cmd. line:"); + + (void) fprintf(stderr, "%d: ", sourceline); + } + if (FNR) { + file = FILENAME_node->var_value->stptr; + if (file) + (void) fprintf(stderr, "(FILENAME=%s ", file); + (void) fprintf(stderr, "FNR=%d) ", FNR); + } + (void) fprintf(stderr, s); + vfprintf(stderr, emsg, argp); + (void) fprintf(stderr, "\n"); + (void) fflush(stderr); +} + +/*VARARGS0*/ +void +msg(va_alist) +va_dcl +{ + va_list args; + char *mesg; + + va_start(args); + mesg = va_arg(args, char *); + err("", mesg, args); + va_end(args); +} + +/*VARARGS0*/ +void +warning(va_alist) +va_dcl +{ + va_list args; + char *mesg; + + va_start(args); + mesg = va_arg(args, char *); + err("warning: ", mesg, args); + va_end(args); +} + +/*VARARGS0*/ +void +fatal(va_alist) +va_dcl +{ + va_list args; + char *mesg; + + va_start(args); + mesg = va_arg(args, char *); + err("fatal: ", mesg, args); + va_end(args); +#ifdef DEBUG + abort(); +#endif + exit(2); +} diff --git a/gnu/usr.bin/awk/node.c b/gnu/usr.bin/awk/node.c new file mode 100644 index 0000000000..65ecb0ed17 --- /dev/null +++ b/gnu/usr.bin/awk/node.c @@ -0,0 +1,429 @@ +/* + * node.c -- routines for node management + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +extern double strtod(); + +AWKNUM +r_force_number(n) +register NODE *n; +{ + register char *cp; + register char *cpend; + char save; + char *ptr; + unsigned int newflags = 0; + +#ifdef DEBUG + if (n == NULL) + cant_happen(); + if (n->type != Node_val) + cant_happen(); + if(n->flags == 0) + cant_happen(); + if (n->flags & NUM) + return n->numbr; +#endif + + /* all the conditionals are an attempt to avoid the expensive strtod */ + + n->numbr = 0.0; + n->flags |= NUM; + + if (n->stlen == 0) + return 0.0; + + cp = n->stptr; + if (isalpha(*cp)) + return 0.0; + + cpend = cp + n->stlen; + while (cp < cpend && isspace(*cp)) + cp++; + if (cp == cpend || isalpha(*cp)) + return 0.0; + + if (n->flags & MAYBE_NUM) { + newflags = NUMBER; + n->flags &= ~MAYBE_NUM; + } + if (cpend - cp == 1) { + if (isdigit(*cp)) { + n->numbr = (AWKNUM)(*cp - '0'); + n->flags |= newflags; + } + return n->numbr; + } + + errno = 0; + save = *cpend; + *cpend = '\0'; + n->numbr = (AWKNUM) strtod((const char *)cp, &ptr); + + /* POSIX says trailing space is OK for NUMBER */ + while (isspace(*ptr)) + ptr++; + *cpend = save; + /* the >= should be ==, but for SunOS 3.5 strtod() */ + if (errno == 0 && ptr >= cpend) + n->flags |= newflags; + else + errno = 0; + + return n->numbr; +} + +/* + * the following lookup table is used as an optimization in force_string + * (more complicated) variations on this theme didn't seem to pay off, but + * systematic testing might be in order at some point + */ +static char *values[] = { + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", +}; +#define NVAL (sizeof(values)/sizeof(values[0])) + +NODE * +r_force_string(s) +register NODE *s; +{ + char buf[128]; + register char *sp = buf; + register long num = 0; + +#ifdef DEBUG + if (s == NULL) cant_happen(); + if (s->type != Node_val) cant_happen(); + if (s->flags & STR) return s; + if (!(s->flags & NUM)) cant_happen(); + 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 */ + if (num < NVAL && num >= 0) { + sp = 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); + s->flags |= STR; + return s; +} + +/* + * Duplicate a node. (For strings, "duplicate" means crank up the + * reference count.) + */ +NODE * +dupnode(n) +NODE *n; +{ + register NODE *r; + + if (n->flags & TEMP) { + n->flags &= ~TEMP; + n->flags |= MALLOC; + return n; + } + if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) { + if (n->stref < 255) + n->stref++; + return n; + } + getnode(r); + *r = *n; + r->flags &= ~(PERM|TEMP); + r->flags |= MALLOC; + 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); + } + return r; +} + +/* this allocates a node with defined numbr */ +NODE * +mk_number(x, flags) +AWKNUM x; +unsigned int flags; +{ + register NODE *r; + + getnode(r); + r->type = Node_val; + r->numbr = x; + r->flags = flags; +#ifdef DEBUG + r->stref = 1; + r->stptr = 0; + r->stlen = 0; +#endif + return r; +} + +/* + * Make a string node. + */ +NODE * +make_str_node(s, len, flags) +char *s; +size_t len; +int flags; +{ + register NODE *r; + + getnode(r); + r->type = Node_val; + r->flags = (STRING|STR|MALLOC); + if (flags & ALREADY_MALLOCED) + r->stptr = s; + else { + emalloc(r->stptr, char *, len + 2, s); + memcpy(r->stptr, s, len); + } + r->stptr[len] = '\0'; + + if (flags & SCAN) { /* scan for escape sequences */ + char *pf; + register char *ptm; + register int c; + register char *end; + + end = &(r->stptr[len]); + for (pf = ptm = r->stptr; pf < end;) { + c = *pf++; + if (c == '\\') { + c = parse_escape(&pf); + if (c < 0) { + if (do_lint) + warning("backslash at end of string"); + c = '\\'; + } + *ptm++ = c; + } else + *ptm++ = c; + } + len = ptm - r->stptr; + erealloc(r->stptr, char *, len + 1, "make_str_node"); + r->stptr[len] = '\0'; + r->flags |= PERM; + } + r->stlen = len; + r->stref = 1; + r->stfmt = -1; + + return r; +} + +NODE * +tmp_string(s, len) +char *s; +size_t len; +{ + register NODE *r; + + r = make_string(s, len); + r->flags |= TEMP; + return r; +} + + +#define NODECHUNK 100 + +NODE *nextfree = NULL; + +NODE * +more_nodes() +{ + register NODE *np; + + /* get more nodes and initialize list */ + emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode"); + for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++) + np->nextp = np + 1; + np->nextp = NULL; + np = nextfree; + nextfree = nextfree->nextp; + return np; +} + +#ifdef DEBUG +void +freenode(it) +NODE *it; +{ +#ifdef MPROF + it->stref = 0; + free((char *) it); +#else /* not MPROF */ + /* add it to head of freelist */ + it->nextp = nextfree; + nextfree = it; +#endif /* not MPROF */ +} +#endif /* DEBUG */ + +void +unref(tmp) +register NODE *tmp; +{ + if (tmp == NULL) + return; + if (tmp->flags & PERM) + return; + if (tmp->flags & (MALLOC|TEMP)) { + tmp->flags &= ~TEMP; + if (tmp->flags & STR) { + if (tmp->stref > 1) { + if (tmp->stref != 255) + tmp->stref--; + return; + } + free(tmp->stptr); + } + freenode(tmp); + } +} + +/* + * Parse a C escape sequence. STRING_PTR points to a variable containing a + * pointer to the string to parse. That pointer is updated past the + * characters we use. The value of the escape sequence is returned. + * + * 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. + * + * Posix doesn't allow \x. + */ + +int +parse_escape(string_ptr) +char **string_ptr; +{ + register int c = *(*string_ptr)++; + register int i; + register int count; + + switch (c) { + case 'a': + return BELL; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return -1; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + i = c - '0'; + count = 0; + while (++count < 3) { + if ((c = *(*string_ptr)++) >= '0' && c <= '7') { + i *= 8; + i += c - '0'; + } else { + (*string_ptr)--; + break; + } + } + return i; + case 'x': + if (do_lint) { + static int didwarn; + + if (! didwarn) { + didwarn = 1; + warning("Posix does not allow \"\\x\" escapes"); + } + } + if (do_posix) + return ('x'); + i = 0; + while (1) { + if (isxdigit((c = *(*string_ptr)++))) { + i *= 16; + if (isdigit(c)) + i += c - '0'; + else if (isupper(c)) + i += c - 'A' + 10; + else + i += c - 'a' + 10; + } else { + (*string_ptr)--; + break; + } + } + return i; + default: + return c; + } +} diff --git a/gnu/usr.bin/awk/patchlevel.h b/gnu/usr.bin/awk/patchlevel.h new file mode 100644 index 0000000000..c6161a1f27 --- /dev/null +++ b/gnu/usr.bin/awk/patchlevel.h @@ -0,0 +1 @@ +#define PATCHLEVEL 2 diff --git a/gnu/usr.bin/awk/protos.h b/gnu/usr.bin/awk/protos.h new file mode 100644 index 0000000000..25af32165b --- /dev/null +++ b/gnu/usr.bin/awk/protos.h @@ -0,0 +1,115 @@ +/* + * protos.h -- function prototypes for when the headers don't have them. + */ + +/* + * Copyright (C) 1991, 1992, the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef __STDC__ +#define aptr_t void * /* arbitrary pointer type */ +#else +#define aptr_t char * +#endif +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)); + +extern void free P((aptr_t)); +extern char *getenv P((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)); +#ifndef VMS +extern char *strerror P((int)); +#else +extern char *strerror P((int,...)); +#endif +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 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 *)); +#endif +extern time_t time P((time_t *)); +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(()); +#if !defined(MSDOS) && !defined(__GNU_LIBRARY__) +extern int fwrite P((const char *, int, int, FILE *)); +extern int fputs P((const char *, FILE *)); +extern int unlink P((const char *)); +#endif +extern int fflush P((FILE *)); +extern int fclose P((FILE *)); +extern FILE *popen P((const char *, const char *)); +extern int pclose P((FILE *)); +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 *, ... */)); +#ifndef toupper +extern int toupper P((int)); +#endif +#ifndef tolower +extern int tolower P((int)); +#endif + +extern double pow P((double x, double y)); +extern double atof P((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 pipe P((int *)); +extern int dup P((int)); +extern int dup2 P((int,int)); +extern int fork P(()); +extern int execl P((/* char *, char *, ... */)); +extern int read P((int, char *, int)); +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(); +#else +extern int sprintf(); +#endif /* SPRINTF_INT */ + +#undef aptr_t diff --git a/gnu/usr.bin/awk/re.c b/gnu/usr.bin/awk/re.c new file mode 100644 index 0000000000..495b0963ca --- /dev/null +++ b/gnu/usr.bin/awk/re.c @@ -0,0 +1,208 @@ +/* + * re.c - compile regular expressions. + */ + +/* + * Copyright (C) 1991, 1992 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +/* Generate compiled regular expressions */ + +Regexp * +make_regexp(s, len, ignorecase, dfa) +char *s; +int len; +int ignorecase; +int dfa; +{ + Regexp *rp; + char *err; + char *src = s; + char *temp; + char *end = s + len; + register char *dest; + register int c; + + /* Handle escaped characters first. */ + + /* Build a copy of the string (in dest) with the + escaped characters translated, and generate the regex + from that. + */ + emalloc(dest, char *, len + 2, "make_regexp"); + temp = dest; + + while (src < end) { + if (*src == '\\') { + c = *++src; + switch (c) { + case 'a': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': + case 'x': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + c = parse_escape(&src); + if (c < 0) + cant_happen(); + *dest++ = (char)c; + break; + default: + *dest++ = '\\'; + *dest++ = (char)c; + src++; + break; + } /* switch */ + } else { + *dest++ = *src++; /* not '\\' */ + } + } /* for */ + + *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"); + rp->pat.allocated = 16; + emalloc(rp->pat.fastmap, char *, 256, "make_regexp"); + + if (ignorecase) + rp->pat.translate = casetable; + 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 (dfa && !ignorecase) { + regcompile(temp, len, &(rp->dfareg), 1); + rp->dfa = 1; + } else + rp->dfa = 0; + free(temp); + return rp; +} + +int +research(rp, str, start, len, need_start) +Regexp *rp; +register char *str; +int start; +register int len; +int need_start; +{ + char *ret = str; + + if (rp->dfa) { + char save1; + char save2; + 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, + &count, &try_backref); + str[start+len] = save1; + str[start+len+1] = save2; + } + if (ret) { + if (need_start || rp->dfa == 0) + return re_search(&(rp->pat), str, start+len, start, + len, &(rp->regs)); + else + return 1; + } else + return -1; +} + +void +refree(rp) +Regexp *rp; +{ + free(rp->pat.buffer); + free(rp->pat.fastmap); + if (rp->dfa) + reg_free(&(rp->dfareg)); + free(rp); +} + +void +reg_error(s) +const char *s; +{ + fatal(s); +} + +Regexp * +re_update(t) +NODE *t; +{ + NODE *t1; + +# define CASE 1 + if ((t->re_flags & CASE) == IGNORECASE) { + if (t->re_flags & CONST) + return t->re_reg; + t1 = force_string(tree_eval(t->re_exp)); + if (t->re_text) { + if (cmp_nodes(t->re_text, t1) == 0) { + free_temp(t1); + return t->re_reg; + } + unref(t->re_text); + } + t->re_text = dupnode(t1); + free_temp(t1); + } + if (t->re_reg) + refree(t->re_reg); + if (t->re_cnt) + t->re_cnt++; + if (t->re_cnt > 10) + t->re_cnt = 0; + if (!t->re_text) { + t1 = force_string(tree_eval(t->re_exp)); + 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_flags &= ~CASE; + t->re_flags |= IGNORECASE; + return t->re_reg; +} + +void +resetup() +{ + (void) re_set_syntax(RE_SYNTAX_AWK); + regsyntax(RE_SYNTAX_AWK, 0); +} diff --git a/gnu/usr.bin/awk/regex.c b/gnu/usr.bin/awk/regex.c new file mode 100644 index 0000000000..f4dd4c2cd2 --- /dev/null +++ b/gnu/usr.bin/awk/regex.c @@ -0,0 +1,2854 @@ +/* Extended regular expression matching and search library. + Copyright (C) 1985, 1989-90 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* To test, compile with -Dtest. This Dtestable feature turns this into + a self-contained program which reads a pattern, describes how it + compiles, then reads a string and searches for it. + + On the other hand, if you compile with both -Dtest and -Dcanned you + can run some tests we've already thought of. */ + + +#ifdef emacs + +/* The `emacs' switch turns on certain special matching commands + that make sense only in emacs. */ + +#include "lisp.h" +#include "buffer.h" +#include "syntax.h" + +/* We write fatal error messages on standard error. */ +#include + +/* isalpha(3) etc. are used for the character classes. */ +#include + +#else /* not emacs */ + +#include "awk.h" + +#define NO_ALLOCA /* try it out for now */ +#ifndef NO_ALLOCA +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +#ifndef atarist +#ifndef alloca +#define alloca __builtin_alloca +#endif +#endif /* atarist */ +#else +#if defined(sparc) && !defined(__GNUC__) +#include +#else +char *alloca (); +#endif +#endif /* __GNUC__ */ + +#define FREE_AND_RETURN_VOID(stackb) return +#define FREE_AND_RETURN(stackb,val) return(val) +#define DOUBLE_STACK(stackx,stackb,len) \ + (stackx = (unsigned char **) alloca (2 * len \ + * sizeof (unsigned char *)),\ + /* Only copy what is in use. */ \ + (unsigned char **) memcpy (stackx, stackb, len * sizeof (char *))) +#else /* NO_ALLOCA defined */ +#define FREE_AND_RETURN_VOID(stackb) free(stackb);return +#define FREE_AND_RETURN(stackb,val) free(stackb);return(val) +#define DOUBLE_STACK(stackx,stackb,len) \ + (unsigned char **) realloc (stackb, 2 * len * sizeof (unsigned char *)) +#endif /* NO_ALLOCA */ + +static void store_jump P((char *, int, char *)); +static void insert_jump P((int, char *, char *, char *)); +static void store_jump_n P((char *, int, char *, unsigned)); +static void insert_jump_n P((int, char *, char *, char *, unsigned)); +static void insert_op_2 P((int, char *, char *, int, int )); +static int memcmp_translate P((unsigned char *, unsigned char *, + int, unsigned char *)); +long re_set_syntax P((long)); + +/* Define the syntax stuff, so we can do the \<, \>, etc. */ + +/* This must be nonzero for the wordchar and notwordchar pattern + commands in re_match_2. */ +#ifndef Sword +#define Sword 1 +#endif + +#define SYNTAX(c) re_syntax_table[c] + + +#ifdef SYNTAX_TABLE + +char *re_syntax_table; + +#else /* not SYNTAX_TABLE */ + +static char re_syntax_table[256]; +static void init_syntax_once P((void)); + + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + memset (re_syntax_table, 0, sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + /* Add specific syntax for ISO Latin-1. */ + for (c = 0300; c <= 0377; c++) + re_syntax_table[c] = Sword; + re_syntax_table[0327] = 0; + re_syntax_table[0367] = 0; + + done = 1; +} + +#endif /* SYNTAX_TABLE */ +#undef P +#endif /* emacs */ + + +/* Sequents are missing isgraph. */ +#ifndef isgraph +#define isgraph(c) (isprint((c)) && !isspace((c))) +#endif + +/* Get the interface, including the syntax bits. */ +#include "regex.h" + + +/* These are the command codes that appear in compiled regular + expressions, one per byte. Some command codes are followed by + argument bytes. A command code can specify any interpretation + whatsoever for its arguments. Zero-bytes may appear in the compiled + regular expression. + + The value of `exactn' is needed in search.c (search_buffer) in emacs. + So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of + `exactn' we use here must also be 1. */ + +enum regexpcode + { + unused=0, + exactn=1, /* Followed by one byte giving n, then by n literal bytes. */ + begline, /* Fail unless at beginning of line. */ + endline, /* Fail unless at end of line. */ + jump, /* Followed by two bytes giving relative address to jump to. */ + on_failure_jump, /* Followed by two bytes giving relative address of + place to resume at in case of failure. */ + finalize_jump, /* Throw away latest failure point and then jump to + address. */ + maybe_finalize_jump, /* Like jump but finalize if safe to do so. + This is used to jump back to the beginning + of a repeat. If the command that follows + this jump is clearly incompatible with the + one at the beginning of the repeat, such that + we can be sure that there is no use backtracking + out of repetitions already completed, + then we finalize. */ + dummy_failure_jump, /* Jump, and push a dummy failure point. This + failure point will be thrown away if an attempt + is made to use it for a failure. A + construct + makes this before the first repeat. Also + use it as an intermediary kind of jump when + compiling an or construct. */ + succeed_n, /* Used like on_failure_jump except has to succeed n times; + then gets turned into an on_failure_jump. The relative + address following it is useless until then. The + address is followed by two bytes containing n. */ + jump_n, /* Similar to jump, but jump n times only; also the relative + address following is in turn followed by yet two more bytes + containing n. */ + set_number_at, /* Set the following relative location to the + subsequent number. */ + anychar, /* Matches any (more or less) one character. */ + charset, /* Matches any one char belonging to specified set. + First following byte is number of bitmap bytes. + Then come bytes for a bitmap saying which chars are in. + Bits in each byte are ordered low-bit-first. + A character is in the set if its bit is 1. + A character too large to have a bit in the map + is automatically not in the set. */ + charset_not, /* Same parameters as charset, but match any character + that is not one of those specified. */ + start_memory, /* Start remembering the text that is matched, for + storing in a memory register. Followed by one + byte containing the register number. Register numbers + must be in the range 0 through RE_NREGS. */ + stop_memory, /* Stop remembering the text that is matched + and store it in a memory register. Followed by + one byte containing the register number. Register + numbers must be in the range 0 through RE_NREGS. */ + duplicate, /* Match a duplicate of something remembered. + Followed by one byte containing the index of the memory + register. */ + before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + begbuf, /* Succeeds if at beginning of buffer. */ + endbuf, /* Succeeds if at end of buffer. */ + wordchar, /* Matches any word-constituent character. */ + notwordchar, /* Matches any char that is not a word-constituent. */ + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + wordbound, /* Succeeds if at a word boundary. */ + notwordbound,/* Succeeds if not at a word boundary. */ + syntaxspec, /* Matches any character whose syntax is specified. + followed by a byte which contains a syntax code, + e.g., Sword. */ + notsyntaxspec /* Matches any character whose syntax differs from + that specified. */ + }; + + +/* Number of failure points to allocate space for initially, + when matching. If this number is exceeded, more space is allocated, + so it is not a hard limit. */ + +#ifndef NFAILURES +#define NFAILURES 80 +#endif + +#ifdef CHAR_UNSIGNED +#define SIGN_EXTEND_CHAR(c) ((c)>(char)127?(c)-256:(c)) /* for IBM RT */ +#endif +#ifndef SIGN_EXTEND_CHAR +#define SIGN_EXTEND_CHAR(x) (x) +#endif + + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ +#define STORE_NUMBER(destination, number) \ + { (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; } + +/* Same as STORE_NUMBER, except increment the destination pointer to + the byte after where the number is stored. Watch out that values for + DESTINATION such as p + 1 won't work, whereas p will. */ +#define STORE_NUMBER_AND_INCR(destination, number) \ + { STORE_NUMBER(destination, number); \ + (destination) += 2; } + + +/* Put into DESTINATION a number stored in two contingous bytes starting + at SOURCE. */ +#define EXTRACT_NUMBER(destination, source) \ + { (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*(char *)((source) + 1)) << 8; } + +/* Same as EXTRACT_NUMBER, except increment the pointer for source to + point to second byte of SOURCE. Note that SOURCE has to be a value + such as p, not, e.g., p + 1. */ +#define EXTRACT_NUMBER_AND_INCR(destination, source) \ + { EXTRACT_NUMBER (destination, source); \ + (source) += 2; } + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit-mask comprised of the various bits + defined in regex.h. */ + +long +re_set_syntax (syntax) + long syntax; +{ + long ret; + + ret = obscure_syntax; + obscure_syntax = syntax; + return ret; +} + +/* Set by re_set_syntax to the current regexp syntax to recognize. */ +long obscure_syntax = 0; + + + +/* Macros for re_compile_pattern, which is found below these definitions. */ + +#define CHAR_CLASS_MAX_LENGTH 6 + +/* Fetch the next character in the uncompiled pattern, translating it if + necessary. */ +#define PATFETCH(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; \ + if (translate) c = translate[c]; } + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH_RAW(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; } + +#define PATUNFETCH p-- + + +/* If the buffer isn't allocated when it comes in, use this. */ +#define INIT_BUF_SIZE 28 + +/* Make sure we have at least N more bytes of space in buffer. */ +#define GET_BUFFER_SPACE(n) \ + { \ + while (b - bufp->buffer + (n) >= bufp->allocated) \ + EXTEND_BUFFER; \ + } + +/* Make sure we have one more byte of buffer space and then add CH to it. */ +#define BUFPUSH(ch) \ + { \ + GET_BUFFER_SPACE (1); \ + *b++ = (char) (ch); \ + } + +/* Extend the buffer by twice its current size via reallociation and + reset the pointers that pointed into the old allocation to point to + the correct places in the new allocation. If extending the buffer + results in it being larger than 1 << 16, then flag memory exhausted. */ +#define EXTEND_BUFFER \ + { char *old_buffer = bufp->buffer; \ + if (bufp->allocated == (1L<<16)) goto too_big; \ + bufp->allocated *= 2; \ + if (bufp->allocated > (1L<<16)) bufp->allocated = (1L<<16); \ + bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated); \ + if (bufp->buffer == 0) \ + goto memory_exhausted; \ + b = (b - old_buffer) + bufp->buffer; \ + if (fixup_jump) \ + fixup_jump = (fixup_jump - old_buffer) + bufp->buffer; \ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + } + +/* Set the bit for character C in a character set list. */ +#define SET_LIST_BIT(c) (b[(c) / BYTEWIDTH] |= 1 << ((c) % BYTEWIDTH)) + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + { if (p != pend) \ + { \ + PATFETCH (c); \ + while (isdigit (c)) \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + } \ + } + +/* Subroutines for re_compile_pattern. */ +/* static void store_jump (), insert_jump (), store_jump_n (), + insert_jump_n (), insert_op_2 (); */ + + +/* re_compile_pattern takes a regular-expression string + and converts it into a buffer full of byte commands for matching. + + PATTERN is the address of the pattern string + SIZE is the length of it. + BUFP is a struct re_pattern_buffer * which points to the info + on where to store the byte commands. + This structure contains a char * which points to the + actual space, which should have been obtained with malloc. + re_compile_pattern may use realloc to grow the buffer space. + + The number of bytes of commands can be found out by looking in + the `struct re_pattern_buffer' that bufp pointed to, after + re_compile_pattern returns. */ + +char * +re_compile_pattern (pattern, size, bufp) + char *pattern; + size_t size; + struct re_pattern_buffer *bufp; +{ + register char *b = bufp->buffer; + register char *p = pattern; + char *pend = pattern + size; + register unsigned c, c1; + char *p0; + unsigned char *translate = (unsigned char *) bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell whether a new exact-match + character can be added to that command or requires a new `exactn' + command. */ + + char *pending_exact = 0; + + /* Address of the place where a forward-jump should go to the end of + the containing expression. Each alternative of an `or', except the + last, ends with a forward-jump of this sort. */ + + char *fixup_jump = 0; + + /* Address of start of the most recently finished expression. + This tells postfix * where to find the start of its operand. */ + + char *laststart = 0; + + /* In processing a repeat, 1 means zero matches is allowed. */ + + char zero_times_ok; + + /* In processing a repeat, 1 means many matches is allowed. */ + + char many_times_ok; + + /* Address of beginning of regexp, or inside of last \(. */ + + char *begalt = b; + + /* In processing an interval, at least this many matches must be made. */ + int lower_bound; + + /* In processing an interval, at most this many matches can be made. */ + int upper_bound; + + /* Place in pattern (i.e., the {) to which to go back if the interval + is invalid. */ + char *beg_interval = 0; + + /* Stack of information saved by \( and restored by \). + Four stack elements are pushed by each \(: + First, the value of b. + Second, the value of fixup_jump. + Third, the value of regnum. + Fourth, the value of begalt. */ + + int stackb[40]; + int *stackp = stackb; + int *stacke = stackb + 40; + int *stackt; + + /* Counts \('s as they are encountered. Remembered for the matching \), + where it becomes the register number to put in the stop_memory + command. */ + + int regnum = 1; + + bufp->fastmap_accurate = 0; + +#ifndef emacs +#ifndef SYNTAX_TABLE + /* Initialize the syntax table. */ + init_syntax_once(); +#endif +#endif + + if (bufp->allocated == 0) + { + bufp->allocated = INIT_BUF_SIZE; + if (bufp->buffer) + /* EXTEND_BUFFER loses when bufp->allocated is 0. */ + bufp->buffer = (char *) realloc (bufp->buffer, INIT_BUF_SIZE); + else + /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = (char *) malloc (INIT_BUF_SIZE); + if (!bufp->buffer) goto memory_exhausted; + begalt = b = bufp->buffer; + } + + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '$': + { + char *p1 = p; + /* When testing what follows the $, + look past the \-constructs that don't consume anything. */ + if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + while (p1 != pend) + { + if (*p1 == '\\' && p1 + 1 != pend + && (p1[1] == '<' || p1[1] == '>' + || p1[1] == '`' || p1[1] == '\'' +#ifdef emacs + || p1[1] == '=' +#endif + || p1[1] == 'b' || p1[1] == 'B')) + p1 += 2; + else + break; + } + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p1 != pend) + goto normal_char; + /* Make operand of last vbar end before this `$'. */ + if (fixup_jump) + store_jump (fixup_jump, jump, b); + fixup_jump = 0; + BUFPUSH (endline); + break; + } + /* $ means succeed if at end of line, but only in special contexts. + If validly in the middle of a pattern, it is a normal character. */ + + if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) && p1 != pend) + goto invalid_pattern; + if (p1 == pend || *p1 == '\n' + || (obscure_syntax & RE_CONTEXT_INDEP_OPS) + || (obscure_syntax & RE_NO_BK_PARENS + ? *p1 == ')' + : *p1 == '\\' && p1[1] == ')') + || (obscure_syntax & RE_NO_BK_VBAR + ? *p1 == '|' + : *p1 == '\\' && p1[1] == '|')) + { + BUFPUSH (endline); + break; + } + goto normal_char; + } + case '^': + /* ^ means succeed if at beg of line, but only if no preceding + pattern. */ + + if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) && laststart) + goto invalid_pattern; + if (laststart && p - 2 >= pattern && p[-2] != '\n' + && !(obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (p != pattern + 1 + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + BUFPUSH (begline); + begalt = b; + } + else + BUFPUSH (begline); + break; + + case '+': + case '?': + if ((obscure_syntax & RE_BK_PLUS_QM) + || (obscure_syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern, char not special. */ + if (!laststart) + { + if (obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) + goto invalid_pattern; + else if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + /* If there is a sequence of repetition chars, + collapse it down to just one. */ + zero_times_ok = 0; + many_times_ok = 0; + while (1) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + if (p == pend) + break; + PATFETCH (c); + if (c == '*') + ; + else if (!(obscure_syntax & RE_BK_PLUS_QM) + && (c == '+' || c == '?')) + ; + else if ((obscure_syntax & RE_BK_PLUS_QM) + && c == '\\') + { + /* int c1; */ + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + c = c1; + } + else + { + PATUNFETCH; + break; + } + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { + /* If more than one repetition is allowed, put in at the + end a backward relative jump from b to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). */ + GET_BUFFER_SPACE (3); + store_jump (b, maybe_finalize_jump, laststart - 3); + b += 3; /* Because store_jump put stuff here. */ + } + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + insert_jump (on_failure_jump, laststart, b + 3, b); + pending_exact = 0; + b += 3; + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + dummy-failure before the initial on-failure-jump + instruction of the loop. This effects a skip over that + instruction the first time we hit that loop. */ + GET_BUFFER_SPACE (6); + insert_jump (dummy_failure_jump, laststart, laststart + 6, b); + b += 3; + } + break; + + case '.': + laststart = b; + BUFPUSH (anychar); + break; + + case '[': + if (p == pend) + goto invalid_pattern; + while (b - bufp->buffer + > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH) + EXTEND_BUFFER; + + laststart = b; + if (*p == '^') + { + BUFPUSH (charset_not); + p++; + } + else + BUFPUSH (charset); + p0 = p; + + BUFPUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + /* Clear the whole map */ + memset (b, 0, (1 << BYTEWIDTH) / BYTEWIDTH); + + if ((obscure_syntax & RE_HAT_NOT_NEWLINE) && b[-2] == charset_not) + SET_LIST_BIT ('\n'); + + + /* Read in characters and ranges, setting map bits. */ + while (1) + { + /* Don't translate while fetching, in case it's a range bound. + When we set the bit for the character, we translate it. */ + PATFETCH_RAW (c); + + /* If set, \ escapes characters when inside [...]. */ + if ((obscure_syntax & RE_AWK_CLASS_HACK) && c == '\\') + { + PATFETCH(c1); + SET_LIST_BIT (c1); + continue; + } + if (c == ']') + { + if (p == p0 + 1) + { + /* If this is an empty bracket expression. */ + if ((obscure_syntax & RE_NO_EMPTY_BRACKETS) + && p == pend) + goto invalid_pattern; + } + else + /* Stop if this isn't merely a ] inside a bracket + expression, but rather the end of a bracket + expression. */ + break; + } + /* Get a range. */ + if (p[0] == '-' && p[1] != ']') + { + PATFETCH (c1); + /* Don't translate the range bounds while fetching them. */ + PATFETCH_RAW (c1); + + if ((obscure_syntax & RE_NO_EMPTY_RANGES) && c > c1) + goto invalid_pattern; + + if ((obscure_syntax & RE_NO_HYPHEN_RANGE_END) + && c1 == '-' && *p != ']') + goto invalid_pattern; + + while (c <= c1) + { + /* Translate each char that's in the range. */ + if (translate) + SET_LIST_BIT (translate[c]); + else + SET_LIST_BIT (c); + c++; + } + } + else if ((obscure_syntax & RE_CHAR_CLASSES) + && c == '[' && p[0] == ':') + { + /* Longest valid character class word has six characters. */ + char str[CHAR_CLASS_MAX_LENGTH]; + PATFETCH (c); + c1 = 0; + /* If no ] at end. */ + if (p == pend) + goto invalid_pattern; + while (1) + { + /* Don't translate the ``character class'' characters. */ + PATFETCH_RAW (c); + if (c == ':' || c == ']' || p == pend + || c1 == CHAR_CLASS_MAX_LENGTH) + break; + str[c1++] = c; + } + str[c1] = '\0'; + if (p == pend + || c == ']' /* End of the bracket expression. */ + || p[0] != ']' + || p + 1 == pend + || (strcmp (str, "alpha") != 0 + && strcmp (str, "upper") != 0 + && strcmp (str, "lower") != 0 + && strcmp (str, "digit") != 0 + && strcmp (str, "alnum") != 0 + && strcmp (str, "xdigit") != 0 + && strcmp (str, "space") != 0 + && strcmp (str, "print") != 0 + && strcmp (str, "punct") != 0 + && strcmp (str, "graph") != 0 + && strcmp (str, "cntrl") != 0)) + { + /* Undo the ending character, the letters, and leave + the leading : and [ (but set bits for them). */ + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + } + else + { + /* The ] at the end of the character class. */ + PATFETCH (c); + if (c != ']') + goto invalid_pattern; + for (c = 0; c < (1 << BYTEWIDTH); c++) + { + if ((strcmp (str, "alpha") == 0 && isalpha (c)) + || (strcmp (str, "upper") == 0 && isupper (c)) + || (strcmp (str, "lower") == 0 && islower (c)) + || (strcmp (str, "digit") == 0 && isdigit (c)) + || (strcmp (str, "alnum") == 0 && isalnum (c)) + || (strcmp (str, "xdigit") == 0 && isxdigit (c)) + || (strcmp (str, "space") == 0 && isspace (c)) + || (strcmp (str, "print") == 0 && isprint (c)) + || (strcmp (str, "punct") == 0 && ispunct (c)) + || (strcmp (str, "graph") == 0 && isgraph (c)) + || (strcmp (str, "cntrl") == 0 && iscntrl (c))) + SET_LIST_BIT (c); + } + } + } + else if (translate) + SET_LIST_BIT (translate[c]); + else + SET_LIST_BIT (c); + } + + /* Discard any character set/class bitmap bytes that are all + 0 at the end of the map. Decrement the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + break; + + case '(': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_open; + + case ')': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_close; + + case '\n': + if (! (obscure_syntax & RE_NEWLINE_OR)) + goto normal_char; + else + goto handle_bar; + + case '|': + if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) + && (! laststart || p == pend)) + goto invalid_pattern; + else if (! (obscure_syntax & RE_NO_BK_VBAR)) + goto normal_char; + else + goto handle_bar; + + case '{': + if (! ((obscure_syntax & RE_NO_BK_CURLY_BRACES) + && (obscure_syntax & RE_INTERVALS))) + goto normal_char; + else + goto handle_interval; + + case '\\': + if (p == pend) goto invalid_pattern; + PATFETCH_RAW (c); + switch (c) + { + case '(': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_open: + if (stackp == stacke) goto nesting_too_deep; + + /* Laststart should point to the start_memory that we are about + to push (unless the pattern has RE_NREGS or more ('s). */ + *stackp++ = b - bufp->buffer; + if (regnum < RE_NREGS) + { + BUFPUSH (start_memory); + BUFPUSH (regnum); + } + *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0; + *stackp++ = regnum++; + *stackp++ = begalt - bufp->buffer; + fixup_jump = 0; + laststart = 0; + begalt = b; + break; + + case ')': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_close: + if (stackp == stackb) goto unmatched_close; + begalt = *--stackp + bufp->buffer; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + if (stackp[-1] < RE_NREGS) + { + BUFPUSH (stop_memory); + BUFPUSH (stackp[-1]); + } + stackp -= 2; + fixup_jump = *stackp ? *stackp + bufp->buffer - 1 : 0; + laststart = *--stackp + bufp->buffer; + break; + + case '|': + if ((obscure_syntax & RE_LIMITED_OPS) + || (obscure_syntax & RE_NO_BK_VBAR)) + goto normal_backsl; + handle_bar: + if (obscure_syntax & RE_LIMITED_OPS) + goto normal_char; + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (6); + insert_jump (on_failure_jump, begalt, b + 6, b); + pending_exact = 0; + b += 3; + /* The alternative before the previous alternative has a + jump after it which gets executed if it gets matched. + Adjust that jump so it will jump to the previous + alternative's analogous jump (put in below, which in + turn will jump to the next (if any) alternative's such + jump, etc.). The last such jump jumps to the correct + final destination. */ + if (fixup_jump) + store_jump (fixup_jump, jump, b); + + /* Leave space for a jump after previous alternative---to be + filled in later. */ + fixup_jump = b; + b += 3; + + laststart = 0; + begalt = b; + break; + + case '{': + if (! (obscure_syntax & RE_INTERVALS) + /* Let \{ be a literal. */ + || ((obscure_syntax & RE_INTERVALS) + && (obscure_syntax & RE_NO_BK_CURLY_BRACES)) + /* If it's the string "\{". */ + || (p - 2 == pattern && p == pend)) + goto normal_backsl; + handle_interval: + beg_interval = p - 1; /* The {. */ + /* If there is no previous pattern, this isn't an interval. */ + if (!laststart) + { + if (obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) + goto invalid_pattern; + else + goto normal_backsl; + } + /* It also isn't an interval if not preceded by an re + matching a single character or subexpression, or if + the current type of intervals can't handle back + references and the previous thing is a back reference. */ + if (! (*laststart == anychar + || *laststart == charset + || *laststart == charset_not + || *laststart == start_memory + || (*laststart == exactn && laststart[1] == 1) + || (! (obscure_syntax & RE_NO_BK_REFS) + && *laststart == duplicate))) + { + if (obscure_syntax & RE_NO_BK_CURLY_BRACES) + goto normal_char; + + /* Posix extended syntax is handled in previous + statement; this is for Posix basic syntax. */ + if (obscure_syntax & RE_INTERVALS) + goto invalid_pattern; + + goto normal_backsl; + } + lower_bound = -1; /* So can see if are set. */ + upper_bound = -1; + GET_UNSIGNED_NUMBER (lower_bound); + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) + upper_bound = RE_DUP_MAX; + } + if (upper_bound < 0) + upper_bound = lower_bound; + if (! (obscure_syntax & RE_NO_BK_CURLY_BRACES)) + { + if (c != '\\') + goto invalid_pattern; + PATFETCH (c); + } + if (c != '}' || lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound + || ((obscure_syntax & RE_NO_BK_CURLY_BRACES) + && p != pend && *p == '{')) + { + if (obscure_syntax & RE_NO_BK_CURLY_BRACES) + goto unfetch_interval; + else + goto invalid_pattern; + } + + /* If upper_bound is zero, don't want to succeed at all; + jump from laststart to b + 3, which will be the end of + the buffer after this jump is inserted. */ + + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + insert_jump (jump, laststart, b + 3, b); + b += 3; + } + + /* Otherwise, after lower_bound number of succeeds, jump + to after the jump_n which will be inserted at the end + of the buffer, and insert that jump_n. */ + else + { /* Set to 5 if only one repetition is allowed and + hence no jump_n is inserted at the current end of + the buffer; then only space for the succeed_n is + needed. Otherwise, need space for both the + succeed_n and the jump_n. */ + + unsigned slots_needed = upper_bound == 1 ? 5 : 10; + + GET_BUFFER_SPACE (slots_needed); + /* Initialize the succeed_n to n, even though it will + be set by its attendant set_number_at, because + re_compile_fastmap will need to know it. Jump to + what the end of buffer will be after inserting + this succeed_n and possibly appending a jump_n. */ + insert_jump_n (succeed_n, laststart, b + slots_needed, + b, lower_bound); + b += 5; /* Just increment for the succeed_n here. */ + + /* More than one repetition is allowed, so put in at + the end of the buffer a backward jump from b to the + succeed_n we put in above. By the time we've gotten + to this jump when matching, we'll have matched once + already, so jump back only upper_bound - 1 times. */ + + if (upper_bound > 1) + { + store_jump_n (b, jump_n, laststart, upper_bound - 1); + b += 5; + /* When hit this when matching, reset the + preceding jump_n's n to upper_bound - 1. */ + BUFPUSH (set_number_at); + GET_BUFFER_SPACE (2); + STORE_NUMBER_AND_INCR (b, -5); + STORE_NUMBER_AND_INCR (b, upper_bound - 1); + } + /* When hit this when matching, set the succeed_n's n. */ + GET_BUFFER_SPACE (5); + insert_op_2 (set_number_at, laststart, b, 5, lower_bound); + b += 5; + } + pending_exact = 0; + beg_interval = 0; + break; + + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + if (beg_interval) + p = beg_interval; + else + { + fprintf (stderr, + "regex: no interval beginning to which to backtrack.\n"); + exit (1); + } + + beg_interval = 0; + PATFETCH (c); /* normal_char expects char in `c'. */ + goto normal_char; + break; + +#ifdef emacs + case '=': + BUFPUSH (at_dot); + break; + + case 's': + laststart = b; + BUFPUSH (syntaxspec); + PATFETCH (c); + BUFPUSH (syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + BUFPUSH (notsyntaxspec); + PATFETCH (c); + BUFPUSH (syntax_spec_code[c]); + break; +#endif /* emacs */ + + case 'w': + laststart = b; + BUFPUSH (wordchar); + break; + + case 'W': + laststart = b; + BUFPUSH (notwordchar); + break; + + case '<': + BUFPUSH (wordbeg); + break; + + case '>': + BUFPUSH (wordend); + break; + + case 'b': + BUFPUSH (wordbound); + break; + + case 'B': + BUFPUSH (notwordbound); + break; + + case '`': + BUFPUSH (begbuf); + break; + + case '\'': + BUFPUSH (endbuf); + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (obscure_syntax & RE_NO_BK_REFS) + goto normal_char; + c1 = c - '0'; + if (c1 >= regnum) + { + if (obscure_syntax & RE_NO_EMPTY_BK_REF) + goto invalid_pattern; + else + goto normal_char; + } + /* Can't back reference to a subexpression if inside of it. */ + for (stackt = stackp - 2; stackt > stackb; stackt -= 4) + if (*stackt == c1) + goto normal_char; + laststart = b; + BUFPUSH (duplicate); + BUFPUSH (c1); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backsl; + break; + + default: + normal_backsl: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + if (translate) c = translate[c]; + goto normal_char; + } + break; + + default: + normal_char: /* Expects the character in `c'. */ + if (!pending_exact || pending_exact + *pending_exact + 1 != b + || *pending_exact == 0177 || *p == '*' || *p == '^' + || ((obscure_syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((obscure_syntax & RE_INTERVALS) + && ((obscure_syntax & RE_NO_BK_CURLY_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + laststart = b; + BUFPUSH (exactn); + pending_exact = b; + BUFPUSH (0); + } + BUFPUSH (c); + (*pending_exact)++; + } + } + + if (fixup_jump) + store_jump (fixup_jump, jump, b); + + if (stackp != stackb) goto unmatched_open; + + bufp->used = b - bufp->buffer; + return 0; + + invalid_pattern: + return "Invalid regular expression"; + + unmatched_open: + return "Unmatched \\("; + + unmatched_close: + return "Unmatched \\)"; + + end_of_pattern: + return "Premature end of regular expression"; + + nesting_too_deep: + return "Nesting too deep"; + + too_big: + return "Regular expression too big"; + + memory_exhausted: + return "Memory exhausted"; +} + + +/* Store a jump of the form . + Store in the location FROM a jump operation to jump to relative + address FROM - TO. OPCODE is the opcode to store. */ + +static void +store_jump (from, opcode, to) + char *from, *to; + int opcode; +{ + from[0] = (char)opcode; + STORE_NUMBER(from + 1, to - (from + 3)); +} + + +/* Open up space before char FROM, and insert there a jump to TO. + CURRENT_END gives the end of the storage not in use, so we know + how much data to copy up. OP is the opcode of the jump to insert. + + If you call this function, you must zero out pending_exact. */ + +static void +insert_jump (op, from, to, current_end) + int op; + char *from, *to, *current_end; +{ + register char *pfrom = current_end; /* Copy from here... */ + register char *pto = current_end + 3; /* ...to here. */ + + while (pfrom != from) + *--pto = *--pfrom; + store_jump (from, op, to); +} + + +/* Store a jump of the form . + + Store in the location FROM a jump operation to jump to relative + address FROM - TO. OPCODE is the opcode to store, N is a number the + jump uses, say, to decide how many times to jump. + + If you call this function, you must zero out pending_exact. */ + +static void +store_jump_n (from, opcode, to, n) + char *from, *to; + int opcode; + unsigned n; +{ + from[0] = (char)opcode; + STORE_NUMBER (from + 1, to - (from + 3)); + STORE_NUMBER (from + 3, n); +} + + +/* Similar to insert_jump, but handles a jump which needs an extra + number to handle minimum and maximum cases. Open up space at + location FROM, and insert there a jump to TO. CURRENT_END gives the + end of the storage in use, so we know how much data to copy up. OP is + the opcode of the jump to insert. + + If you call this function, you must zero out pending_exact. */ + +static void +insert_jump_n (op, from, to, current_end, n) + int op; + char *from, *to, *current_end; + unsigned n; +{ + register char *pfrom = current_end; /* Copy from here... */ + register char *pto = current_end + 5; /* ...to here. */ + + while (pfrom != from) + *--pto = *--pfrom; + store_jump_n (from, op, to, n); +} + + +/* Open up space at location THERE, and insert operation OP followed by + NUM_1 and NUM_2. CURRENT_END gives the end of the storage in use, so + we know how much data to copy up. + + If you call this function, you must zero out pending_exact. */ + +static void +insert_op_2 (op, there, current_end, num_1, num_2) + int op; + char *there, *current_end; + int num_1, num_2; +{ + register char *pfrom = current_end; /* Copy from here... */ + register char *pto = current_end + 5; /* ...to here. */ + + while (pfrom != there) + *--pto = *--pfrom; + + there[0] = (char)op; + STORE_NUMBER (there + 1, num_1); + STORE_NUMBER (there + 3, num_2); +} + + + +/* Given a pattern, compute a fastmap from it. The fastmap records + which of the (1 << BYTEWIDTH) possible characters can start a string + that matches the pattern. This fastmap is used by re_search to skip + quickly over totally implausible text. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as bufp->fastmap. + The other components of bufp describe the pattern to be used. */ + +void +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *pattern = (unsigned char *) bufp->buffer; + int size = bufp->used; + register char *fastmap = bufp->fastmap; + register unsigned char *p = pattern; + register unsigned char *pend = pattern + size; + register int j, k; + unsigned char *translate = (unsigned char *) bufp->translate; + unsigned is_a_succeed_n; + +#ifndef NO_ALLOCA + unsigned char *stackb[NFAILURES]; + unsigned char **stackp = stackb; + +#else + unsigned char **stackb; + unsigned char **stackp; + stackb = (unsigned char **) malloc (NFAILURES * sizeof (unsigned char *)); + stackp = stackb; + +#endif /* NO_ALLOCA */ + memset (fastmap, 0, (1 << BYTEWIDTH)); + bufp->fastmap_accurate = 1; + bufp->can_be_null = 0; + + while (p) + { + is_a_succeed_n = 0; + if (p == pend) + { + bufp->can_be_null = 1; + break; + } +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + case exactn: + if (translate) + fastmap[translate[p[1]]] = 1; + else + fastmap[p[1]] = 1; + break; + + case begline: + case before_dot: + case at_dot: + case after_dot: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + continue; + + case endline: + if (translate) + fastmap[translate['\n']] = 1; + else + fastmap['\n'] = 1; + + if (bufp->can_be_null != 1) + bufp->can_be_null = 2; + break; + + case jump_n: + case finalize_jump: + case maybe_finalize_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + /* Jump backward reached implies we just went through + the body of a loop and matched nothing. + Opcode jumped to should be an on_failure_jump. + Just treat it like an ordinary jump. + For a * loop, it has pushed its failure point already; + If so, discard that as redundant. */ + + if ((enum regexpcode) *p != on_failure_jump + && (enum regexpcode) *p != succeed_n) + continue; + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (stackp != stackb && *stackp == p) + stackp--; + continue; + + case on_failure_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + *++stackp = p + j; + if (is_a_succeed_n) + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + continue; + + case succeed_n: + is_a_succeed_n = 1; + /* Get to the number of times to succeed. */ + p += 2; + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 4; + goto handle_on_failure_jump; + } + continue; + + case set_number_at: + p += 4; + continue; + + case start_memory: + case stop_memory: + p++; + continue; + + case duplicate: + bufp->can_be_null = 1; + fastmap['\n'] = 1; + case anychar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (j != '\n') + fastmap[j] = 1; + if (bufp->can_be_null) + { + FREE_AND_RETURN_VOID(stackb); + } + /* Don't return; check the alternative paths + so we can set can_be_null if appropriate. */ + break; + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + +#else /* not emacs */ + case syntaxspec: + case notsyntaxspec: + break; +#endif /* not emacs */ + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + + case charset_not: + /* Chars beyond end of map must be allowed */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + + case unused: /* pacify gcc -Wall */ + break; + } + + /* Get here means we have successfully found the possible starting + characters of one path of the pattern. We need not follow this + path any farther. Instead, look at the next alternative + remembered in the stack. */ + if (stackp != stackb) + p = *stackp--; + else + break; + } + FREE_AND_RETURN_VOID(stackb); +} + + + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (pbufp, string, size, startpos, range, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (pbufp, (char *) 0, 0, string, size, startpos, range, + regs, size); +} + + +/* Using the compiled pattern in PBUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. RANGE is the number of + places to try before giving up. If RANGE is negative, it searches + backwards, i.e., the starting positions tried are STARTPOS, STARTPOS + - 1, etc. STRING1 and STRING2 are of SIZE1 and SIZE2, respectively. + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire PBUFP->buffer and its contained + subexpressions. Do not consider matching one past the index MSTOP in + the virtual concatenation of STRING1 and STRING2. + + The value returned is the position in the strings at which the match + was found, or -1 if no match was found, or -2 if error (such as + failure stack overflow). */ + +int +re_search_2 (pbufp, string1, size1, string2, size2, startpos, range, + regs, mstop) + struct re_pattern_buffer *pbufp; + char *string1, *string2; + int size1, size2; + int startpos; + register int range; + struct re_registers *regs; + int mstop; +{ + register char *fastmap = pbufp->fastmap; + register unsigned char *translate = (unsigned char *) pbufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + int val; + + /* Check for out-of-range starting position. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up range if it would eventually take startpos outside of the + virtual concatenation of string1 and string2. */ + if (endpos < -1) + range = -1 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* Update the fastmap now if not correct already. */ + if (fastmap && !pbufp->fastmap_accurate) + re_compile_fastmap (pbufp); + + /* If the search isn't to be a backwards one, don't waste time in a + long search for a pattern that says it is anchored. */ + if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf + && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + while (1) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot possibly be the start of a match. Note, however, that + if the pattern can possibly match the null string, we must + test it at each starting point so that we take the first null + string we get. */ + + if (fastmap && startpos < total_size && pbufp->can_be_null != 1) + { + if (range > 0) /* Searching forwards. */ + { + register int lim = 0; + register unsigned char *p; + int irange = range; + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + p = ((unsigned char *) + &(startpos >= size1 ? string2 - size1 : string1)[startpos]); + + while (range > lim && !fastmap[translate + ? translate[*p++] + : *p++]) + range--; + startpos += irange - range; + } + else /* Searching backwards. */ + { + register unsigned char c; + + if (string1 == 0 || startpos >= size1) + c = string2[startpos - size1]; + else + c = string1[startpos]; + + c &= 0xff; + if (translate ? !fastmap[translate[c]] : !fastmap[c]) + goto advance; + } + } + + if (range >= 0 && startpos == total_size + && fastmap && pbufp->can_be_null == 0) + return -1; + + val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, + regs, mstop); + if (val >= 0) + return startpos; + if (val == -2) + return -2; + +#ifndef NO_ALLOCA +#ifdef C_ALLOCA + alloca (0); +#endif /* C_ALLOCA */ + +#endif /* NO_ALLOCA */ + advance: + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } + else + { + range++; + startpos--; + } + } + return -1; +} + + + +#ifndef emacs /* emacs never uses this. */ +int +re_match (pbufp, string, size, pos, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, pos; + struct re_registers *regs; +{ + return re_match_2 (pbufp, (char *) 0, 0, string, size, pos, regs, size); +} +#endif /* not emacs */ + + +/* The following are used for re_match_2, defined below: */ + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always pushed MAX_NUM_FAILURE_ITEMS each time we failed. */ + +int re_max_failures = 2000; + +/* Routine used by re_match_2. */ +/* static int memcmp_translate (); *//* already declared */ + + +/* Structure and accessing macros used in re_match_2: */ + +struct register_info +{ + unsigned is_active : 1; + unsigned matched_something : 1; +}; + +#define IS_ACTIVE(R) ((R).is_active) +#define MATCHED_SOMETHING(R) ((R).matched_something) + + +/* Macros used by re_match_2: */ + + +/* I.e., regstart, regend, and reg_info. */ + +#define NUM_REG_ITEMS 3 + +/* We push at most this many things on the stack whenever we + fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are + arguments to the PUSH_FAILURE_POINT macro. */ + +#define MAX_NUM_FAILURE_ITEMS (RE_NREGS * NUM_REG_ITEMS + 2) + + +/* We push this many things on the stack whenever we fail. */ + +#define NUM_FAILURE_ITEMS (last_used_reg * NUM_REG_ITEMS + 2) + + +/* This pushes most of the information about the current state we will want + if we ever fail back to it. */ + +#define PUSH_FAILURE_POINT(pattern_place, string_place) \ + { \ + long last_used_reg, this_reg; \ + \ + /* Find out how many registers are active or have been matched. \ + (Aside from register zero, which is only set at the end.) */ \ + for (last_used_reg = RE_NREGS - 1; last_used_reg > 0; last_used_reg--)\ + if (regstart[last_used_reg] != (unsigned char *)(-1L)) \ + break; \ + \ + if (stacke - stackp < NUM_FAILURE_ITEMS) \ + { \ + unsigned char **stackx; \ + unsigned int len = stacke - stackb; \ + if (len > re_max_failures * MAX_NUM_FAILURE_ITEMS) \ + { \ + FREE_AND_RETURN(stackb,(-2)); \ + } \ + \ + /* Roughly double the size of the stack. */ \ + stackx = DOUBLE_STACK(stackx,stackb,len); \ + /* Rearrange the pointers. */ \ + stackp = stackx + (stackp - stackb); \ + stackb = stackx; \ + stacke = stackb + 2 * len; \ + } \ + \ + /* Now push the info for each of those registers. */ \ + for (this_reg = 1; this_reg <= last_used_reg; this_reg++) \ + { \ + *stackp++ = regstart[this_reg]; \ + *stackp++ = regend[this_reg]; \ + *stackp++ = (unsigned char *) ®_info[this_reg]; \ + } \ + \ + /* Push how many registers we saved. */ \ + *stackp++ = (unsigned char *) last_used_reg; \ + \ + *stackp++ = pattern_place; \ + *stackp++ = string_place; \ + } + + +/* This pops what PUSH_FAILURE_POINT pushes. */ + +#define POP_FAILURE_POINT() \ + { \ + int temp; \ + stackp -= 2; /* Remove failure points. */ \ + temp = (int) *--stackp; /* How many regs pushed. */ \ + temp *= NUM_REG_ITEMS; /* How much to take off the stack. */ \ + stackp -= temp; /* Remove the register info. */ \ + } + + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Is true if there is a first string and if PTR is pointing anywhere + inside it or just past the end. */ + +#define IS_IN_FIRST_STRING(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ + +#define PREFETCH \ + while (d == dend) \ + { \ + /* end of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* end of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + + +/* Call this when have matched something; it sets `matched' flags for the + registers corresponding to the subexpressions of which we currently + are inside. */ +#define SET_REGS_MATCHED \ + { unsigned this_reg; \ + for (this_reg = 0; this_reg < RE_NREGS; this_reg++) \ + { \ + if (IS_ACTIVE(reg_info[this_reg])) \ + MATCHED_SOMETHING(reg_info[this_reg]) = 1; \ + else \ + MATCHED_SOMETHING(reg_info[this_reg]) = 0; \ + } \ + } + +/* Test if at very beginning or at very end of the virtual concatenation + of string1 and string2. If there is only one string, we've put it in + string2. */ + +#define AT_STRINGS_BEG (d == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END (d == end2) + +#define AT_WORD_BOUNDARY \ + (AT_STRINGS_BEG || AT_STRINGS_END || IS_A_LETTER (d - 1) != IS_A_LETTER (d)) + +/* We have two special cases to check for: + 1) if we're past the end of string1, we have to look at the first + character in string2; + 2) if we're before the beginning of string2, we have to look at the + last character in string1; we assume there is a string1, so use + this in conjunction with AT_STRINGS_BEG. */ +#define IS_A_LETTER(d) \ + (SYNTAX ((d) == end1 ? *string2 : (d) == string2 - 1 ? *(end1 - 1) : *(d))\ + == Sword) + + +/* Match the pattern described by PBUFP against the virtual + concatenation of STRING1 and STRING2, which are of SIZE1 and SIZE2, + respectively. Start the match at index POS in the virtual + concatenation of STRING1 and STRING2. In REGS, return the indices of + the virtual concatenation of STRING1 and STRING2 that matched the + entire PBUFP->buffer and its contained subexpressions. Do not + consider matching one past the index MSTOP in the virtual + concatenation of STRING1 and STRING2. + + If pbufp->fastmap is nonzero, then it had better be up to date. + + The reason that the data to match are specified as two components + which are to be regarded as concatenated is so this function can be + used directly on the contents of an Emacs buffer. + + -1 is returned if there is no match. -2 is returned if there is an + error (such as match stack overflow). Otherwise the value is the + length of the substring which was matched. */ + +int +re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop) + struct re_pattern_buffer *pbufp; + char *string1_arg, *string2_arg; + int size1, size2; + int pos; + struct re_registers *regs; + int mstop; +{ + register unsigned char *p = (unsigned char *) pbufp->buffer; + + /* Pointer to beyond end of buffer. */ + register unsigned char *pend = p + pbufp->used; + + unsigned char *string1 = (unsigned char *) string1_arg; + unsigned char *string2 = (unsigned char *) string2_arg; + unsigned char *end1; /* Just past end of first string. */ + unsigned char *end2; /* Just past end of second string. */ + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + unsigned char *end_match_1, *end_match_2; + + register unsigned char *d, *dend; + register int mcnt; /* Multipurpose. */ + unsigned char *translate = (unsigned char *) pbufp->translate; + unsigned is_a_jump_n = 0; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to the + subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where to + resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is a + ``dummy''; if a failure happens and the failure point is a dummy, it + gets discarded and the next next one is tried. */ + +#ifndef NO_ALLOCA + unsigned char *initial_stack[MAX_NUM_FAILURE_ITEMS * NFAILURES]; +#endif + unsigned char **stackb; + unsigned char **stackp; + unsigned char **stacke; + + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ + + unsigned char *regstart[RE_NREGS]; + unsigned char *regend[RE_NREGS]; + + /* The is_active field of reg_info helps us keep track of which (possibly + nested) subexpressions we are currently in. The matched_something + field of reg_info[reg_num] helps us tell whether or not we have + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ + + struct register_info reg_info[RE_NREGS]; + + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + + unsigned best_regs_set = 0; + unsigned char *best_regstart[RE_NREGS]; + unsigned char *best_regend[RE_NREGS]; + + /* Initialize the stack. */ +#ifdef NO_ALLOCA + stackb = (unsigned char **) malloc (MAX_NUM_FAILURE_ITEMS * NFAILURES * sizeof (char *)); +#else + stackb = initial_stack; +#endif + stackp = stackb; + stacke = &stackb[MAX_NUM_FAILURE_ITEMS * NFAILURES]; + +#ifdef DEBUG_REGEX + fprintf (stderr, "Entering re_match_2(%s%s)\n", string1_arg, string2_arg); +#endif + + /* Initialize subexpression text positions to -1 to mark ones that no + \( or ( and \) or ) has been seen for. Also set all registers to + inactive and mark them as not having matched anything or ever + failed. */ + for (mcnt = 0; mcnt < RE_NREGS; mcnt++) + { + regstart[mcnt] = regend[mcnt] = (unsigned char *) (-1L); + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + if (regs) + for (mcnt = 0; mcnt < RE_NREGS; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + + /* Set up pointers to ends of strings. + Don't allow the second string to be empty unless both are empty. */ + if (size2 == 0) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ + if (mstop <= size1) + { + end_match_1 = string1 + mstop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + mstop - size1; + } + + /* `p' scans through the pattern as `d' scans through the data. `dend' + is the end of the input string that `d' points within. `d' is + advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal string2. */ + + if (size1 != 0 && pos <= size1) + d = string1 + pos, dend = end_match_1; + else + d = string2 + pos - size1, dend = end_match_2; + + + /* This loops over pattern commands. It exits by returning from the + function if match is complete, or it drops through if match fails + at this starting point in the input data. */ + + while (1) + { +#ifdef DEBUG_REGEX + fprintf (stderr, + "regex loop(%d): matching 0x%02d\n", + p - (unsigned char *) pbufp->buffer, + *p); +#endif + is_a_jump_n = 0; + /* End of pattern means we might have succeeded. */ + if (p == pend) + { + /* If not end of string, try backtracking. Otherwise done. */ + if (d != end_match_2) + { + if (stackp != stackb) + { + /* More failure points to try. */ + + unsigned in_same_string = + IS_IN_FIRST_STRING (best_regend[0]) + == MATCHING_IN_FIRST_STRING; + + /* If exceeds best match so far, save it. */ + if (! best_regs_set + || (in_same_string && d > best_regend[0]) + || (! in_same_string && ! MATCHING_IN_FIRST_STRING)) + { + best_regs_set = 1; + best_regend[0] = d; /* Never use regstart[0]. */ + + for (mcnt = 1; mcnt < RE_NREGS; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + /* If no failure points, don't restore garbage. */ + else if (best_regs_set) + { + restore_best_regs: + /* Restore best match. */ + d = best_regend[0]; + + for (mcnt = 0; mcnt < RE_NREGS; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } + + /* If caller wants register contents data back, convert it + to indices. */ + if (regs) + { + regs->start[0] = pos; + if (MATCHING_IN_FIRST_STRING) + regs->end[0] = d - string1; + else + regs->end[0] = d - string2 + size1; + for (mcnt = 1; mcnt < RE_NREGS; mcnt++) + { + if (regend[mcnt] == (unsigned char *)(-1L)) + { + regs->start[mcnt] = -1; + regs->end[mcnt] = -1; + continue; + } + if (IS_IN_FIRST_STRING (regstart[mcnt])) + regs->start[mcnt] = regstart[mcnt] - string1; + else + regs->start[mcnt] = regstart[mcnt] - string2 + size1; + + if (IS_IN_FIRST_STRING (regend[mcnt])) + regs->end[mcnt] = regend[mcnt] - string1; + else + regs->end[mcnt] = regend[mcnt] - string2 + size1; + } + } + FREE_AND_RETURN(stackb, + (d - pos - (MATCHING_IN_FIRST_STRING ? + string1 : + string2 - size1))); + } + + /* Otherwise match next pattern command. */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + + /* \( [or `(', as appropriate] is represented by start_memory, + \) by stop_memory. Both of those commands are followed by + a register number in the next byte. The text matched + within the \( and \) is recorded under that number. */ + case start_memory: + regstart[*p] = d; + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + p++; + break; + + case stop_memory: + regend[*p] = d; + IS_ACTIVE (reg_info[*p]) = 0; + + /* If just failed to match something this time around with a sub- + expression that's in a loop, try to force exit from the loop. */ + if ((! MATCHED_SOMETHING (reg_info[*p]) + || (enum regexpcode) p[-3] == start_memory) + && (p + 1) != pend) + { + register unsigned char *p2 = p + 1; + mcnt = 0; + switch (*p2++) + { + case jump_n: + is_a_jump_n = 1; + case finalize_jump: + case maybe_finalize_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p2); + if (is_a_jump_n) + p2 += 2; + break; + } + p2 += mcnt; + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump, exit from the loop by forcing a + failure after pushing on the stack the on_failure_jump's + jump in the pattern, and d. */ + if (mcnt < 0 && (enum regexpcode) *p2++ == on_failure_jump) + { + EXTRACT_NUMBER_AND_INCR (mcnt, p2); + PUSH_FAILURE_POINT (p2 + mcnt, d); + goto fail; + } + } + p++; + break; + + /* \ has been turned into a `duplicate' command which is + followed by the numeric value of as the register number. */ + case duplicate: + { + int regno = *p++; /* Get which register to match against */ + register unsigned char *d2, *dend2; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((IS_IN_FIRST_STRING (regstart[regno]) + == IS_IN_FIRST_STRING (regend[regno])) + ? regend[regno] : end_match_1); + while (1) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */ + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH; + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? memcmp_translate (d, d2, mcnt, translate) + : memcmp ((char *)d, (char *)d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + case anychar: + PREFETCH; /* Fetch a data character. */ + /* Match anything but a newline, maybe even a null. */ + if ((translate ? translate[*d] : *d) == '\n' + || ((obscure_syntax & RE_DOT_NOT_NULL) + && (translate ? translate[*d] : *d) == '\000')) + goto fail; + SET_REGS_MATCHED; + d++; + break; + + case charset: + case charset_not: + { + int not = 0; /* Nonzero for charset_not. */ + register int c; + if (*(p - 1) == (unsigned char) charset_not) + not = 1; + + PREFETCH; /* Fetch a data character. */ + + if (translate) + c = translate[*d]; + else + c = *d; + + if (c < *p * BYTEWIDTH + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + SET_REGS_MATCHED; + d++; + break; + } + + case begline: + if ((size1 != 0 && d == string1) + || (size1 == 0 && size2 != 0 && d == string2) + || (d && d[-1] == '\n') + || (size1 == 0 && size2 == 0)) + break; + else + goto fail; + + case endline: + if (d == end2 + || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n')) + break; + goto fail; + + /* `or' constructs are handled by starting each alternative with + an on_failure_jump that points to the start of the next + alternative. Each alternative except the last ends with a + jump to the joining point. (Actually, each jump except for + the last one really jumps to the following jump, because + tensioning the jumps is a hassle.) */ + + /* The start of a stupid repeat has an on_failure_jump that points + past the end of the repeat text. This makes a failure point so + that on failure to match a repetition, matching restarts past + as many repetitions have been found with no way to fail and + look for another one. */ + + /* A smart repeat is similar but loops back to the on_failure_jump + so that each repetition makes another failure point. */ + + case on_failure_jump: + on_failure: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + PUSH_FAILURE_POINT (p + mcnt, d); + break; + + /* The end of a smart repeat has a maybe_finalize_jump back. + Change it either to a finalize_jump or an ordinary jump. */ + case maybe_finalize_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + { + register unsigned char *p2 = p; + /* Compare what follows with the beginning of the repeat. + If we can establish that there is nothing that they would + both match, we can change to finalize_jump. */ + while (p2 + 1 != pend + && (*p2 == (unsigned char) stop_memory + || *p2 == (unsigned char) start_memory)) + p2 += 2; /* Skip over reg number. */ + if (p2 == pend) + p[-3] = (unsigned char) finalize_jump; + else if (*p2 == (unsigned char) exactn + || *p2 == (unsigned char) endline) + { + register int c = *p2 == (unsigned char) endline ? '\n' : p2[2]; + register unsigned char *p1 = p + mcnt; + /* p1[0] ... p1[2] are an on_failure_jump. + Examine what follows that. */ + if (p1[3] == (unsigned char) exactn && p1[5] != c) + p[-3] = (unsigned char) finalize_jump; + else if (p1[3] == (unsigned char) charset + || p1[3] == (unsigned char) charset_not) + { + int not = p1[3] == (unsigned char) charset_not; + if (c < p1[4] * BYTEWIDTH + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + /* `not' is 1 if c would match. */ + /* That means it is not safe to finalize. */ + if (!not) + p[-3] = (unsigned char) finalize_jump; + } + } + } + p -= 2; /* Point at relative address again. */ + if (p[-1] != (unsigned char) finalize_jump) + { + p[-1] = (unsigned char) jump; + goto nofinalize; + } + /* Note fall through. */ + + /* The end of a stupid repeat has a finalize_jump back to the + start, where another failure point will be made which will + point to after all the repetitions found so far. */ + + /* Take off failure points put on by matching on_failure_jump + because didn't fail. Also remove the register information + put on by the on_failure_jump. */ + case finalize_jump: + POP_FAILURE_POINT (); + /* Note fall through. */ + + /* Jump without taking off any failure points. */ + case jump: + nofinalize: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p += mcnt; + break; + + case dummy_failure_jump: + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at finalize_jump. We will end up at + finalize_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for finalize_jump to pop. */ + PUSH_FAILURE_POINT (0, 0); + goto nofinalize; + + + /* Have to succeed matching what follows at least n times. Then + just handle like an on_failure_jump. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt) + { + mcnt--; + p += 2; + STORE_NUMBER_AND_INCR (p, mcnt); + } + else if (mcnt == 0) + { + p[2] = unused; + p[3] = unused; + goto on_failure; + } + else + { + fprintf (stderr, "regex: the succeed_n's n is not set.\n"); + exit (1); + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER(p + 2, mcnt); + goto nofinalize; /* Do the jump without taking off + any failure points. */ + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + case set_number_at: + { + register unsigned char *p1; + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + STORE_NUMBER (p1, mcnt); + break; + } + + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case unused: + break; + + case wordbound: + if (AT_WORD_BOUNDARY) + break; + goto fail; + + case notwordbound: + if (AT_WORD_BOUNDARY) + goto fail; + break; + + case wordbeg: + if (IS_A_LETTER (d) && (!IS_A_LETTER (d - 1) || AT_STRINGS_BEG)) + break; + goto fail; + + case wordend: + /* Have to check if AT_STRINGS_BEG before looking at d - 1. */ + if (!AT_STRINGS_BEG && IS_A_LETTER (d - 1) + && (!IS_A_LETTER (d) || AT_STRINGS_END)) + break; + goto fail; + +#ifdef emacs + case before_dot: + if (PTR_CHAR_POS (d) >= point) + goto fail; + break; + + case at_dot: + if (PTR_CHAR_POS (d) != point) + goto fail; + break; + + case after_dot: + if (PTR_CHAR_POS (d) <= point) + goto fail; + break; + + case wordchar: + mcnt = (int) Sword; + goto matchsyntax; + + case syntaxspec: + mcnt = *p++; + matchsyntax: + PREFETCH; + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail; + SET_REGS_MATCHED; + break; + + case notwordchar: + mcnt = (int) Sword; + goto matchnotsyntax; + + case notsyntaxspec: + mcnt = *p++; + matchnotsyntax: + PREFETCH; + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail; + SET_REGS_MATCHED; + break; + +#else /* not emacs */ + + case wordchar: + PREFETCH; + if (!IS_A_LETTER (d)) + goto fail; + SET_REGS_MATCHED; + break; + + case notwordchar: + PREFETCH; + if (IS_A_LETTER (d)) + goto fail; + SET_REGS_MATCHED; + break; + + case before_dot: + case at_dot: + case after_dot: + case syntaxspec: + case notsyntaxspec: + break; + +#endif /* not emacs */ + + case begbuf: + if (AT_STRINGS_BEG) + break; + goto fail; + + case endbuf: + if (AT_STRINGS_END) + break; + goto fail; + + case exactn: + /* Match the next few pattern characters exactly. + mcnt is how many characters to match. */ + mcnt = *p++; + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + PREFETCH; + if (translate[*d++] != *p++) goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH; + if (*d++ != *p++) goto fail; + } + while (--mcnt); + } + SET_REGS_MATCHED; + break; + } + continue; /* Successfully executed one pattern command; keep going. */ + + /* Jump here if any matching operation fails. */ + fail: + if (stackp != stackb) + /* A restart point is known. Restart there and pop it. */ + { + short last_used_reg, this_reg; + + /* If this failure point is from a dummy_failure_point, just + skip it. */ + if (!stackp[-2]) + { + POP_FAILURE_POINT (); + goto fail; + } + + d = *--stackp; + p = *--stackp; + if (d >= string1 && d <= end1) + dend = end_match_1; + /* Restore register info. */ + last_used_reg = (long) *--stackp; + + /* Make the ones that weren't saved -1 or 0 again. */ + for (this_reg = RE_NREGS - 1; this_reg > last_used_reg; this_reg--) + { + regend[this_reg] = (unsigned char *) (-1L); + regstart[this_reg] = (unsigned char *) (-1L); + IS_ACTIVE (reg_info[this_reg]) = 0; + MATCHED_SOMETHING (reg_info[this_reg]) = 0; + } + + /* And restore the rest from the stack. */ + for ( ; this_reg > 0; this_reg--) + { + reg_info[this_reg] = *(struct register_info *) *--stackp; + regend[this_reg] = *--stackp; + regstart[this_reg] = *--stackp; + } + } + else + break; /* Matching at this starting point really fails. */ + } + + if (best_regs_set) + goto restore_best_regs; + + FREE_AND_RETURN(stackb,(-1)); /* Failure to match. */ +} + + +static int +memcmp_translate (s1, s2, len, translate) + unsigned char *s1, *s2; + register int len; + unsigned char *translate; +{ + register unsigned char *p1 = s1, *p2 = s2; + while (len) + { + if (translate [*p1++] != translate [*p2++]) return 1; + len--; + } + return 0; +} + + + +/* Entry points compatible with 4.2 BSD regex library. */ + +#if !defined(emacs) && !defined(GAWK) + +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + char *s; +{ + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + if (!(re_comp_buf.buffer = (char *) malloc (200))) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH))) + return "Memory exhausted"; + } + return re_compile_pattern (s, strlen (s), &re_comp_buf); +} + +int +re_exec (s) + char *s; +{ + int len = strlen (s); + return 0 <= re_search (&re_comp_buf, s, len, 0, len, + (struct re_registers *) 0); +} +#endif /* not emacs && not GAWK */ + + + +#ifdef test + +#ifdef atarist +long _stksize = 2L; /* reserve memory for stack */ +#endif +#include + +/* Indexed by a character, gives the upper case equivalent of the + character. */ + +char upcase[0400] = + { 000, 001, 002, 003, 004, 005, 006, 007, + 010, 011, 012, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 024, 025, 026, 027, + 030, 031, 032, 033, 034, 035, 036, 037, + 040, 041, 042, 043, 044, 045, 046, 047, + 050, 051, 052, 053, 054, 055, 056, 057, + 060, 061, 062, 063, 064, 065, 066, 067, + 070, 071, 072, 073, 074, 075, 076, 077, + 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137, + 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177, + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 + }; + +#ifdef canned + +#include "tests.h" + +typedef enum { extended_test, basic_test } test_type; + +/* Use this to run the tests we've thought of. */ + +void +main () +{ + test_type t = extended_test; + + if (t == basic_test) + { + printf ("Running basic tests:\n\n"); + test_posix_basic (); + } + else if (t == extended_test) + { + printf ("Running extended tests:\n\n"); + test_posix_extended (); + } +} + +#else /* not canned */ + +/* Use this to run interactive tests. */ + +void +main (argc, argv) + int argc; + char **argv; +{ + char pat[80]; + struct re_pattern_buffer buf; + int i; + char c; + char fastmap[(1 << BYTEWIDTH)]; + + /* Allow a command argument to specify the style of syntax. */ + if (argc > 1) + obscure_syntax = atol (argv[1]); + + buf.allocated = 40; + buf.buffer = (char *) malloc (buf.allocated); + buf.fastmap = fastmap; + buf.translate = upcase; + + while (1) + { + gets (pat); + + if (*pat) + { + re_compile_pattern (pat, strlen(pat), &buf); + + for (i = 0; i < buf.used; i++) + printchar (buf.buffer[i]); + + putchar ('\n'); + + printf ("%d allocated, %d used.\n", buf.allocated, buf.used); + + re_compile_fastmap (&buf); + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (fastmap[i]) printchar (i); + putchar ('\n'); + } + + gets (pat); /* Now read the string to match against */ + + i = re_match (&buf, pat, strlen (pat), 0, 0); + printf ("Match value %d.\n", i); + } +} + +#endif + + +#ifdef NOTDEF +print_buf (bufp) + struct re_pattern_buffer *bufp; +{ + int i; + + printf ("buf is :\n----------------\n"); + for (i = 0; i < bufp->used; i++) + printchar (bufp->buffer[i]); + + printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used); + + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->fastmap[i]) + printchar (i); + printf ("\nAllowed by translate: "); + if (bufp->translate) + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->translate[i]) + printchar (i); + printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't"); + printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not"); +} +#endif /* NOTDEF */ + +printchar (c) + char c; +{ + if (c < 040 || c >= 0177) + { + putchar ('\\'); + putchar (((c >> 6) & 3) + '0'); + putchar (((c >> 3) & 7) + '0'); + putchar ((c & 7) + '0'); + } + else + putchar (c); +} + +error (string) + char *string; +{ + puts (string); + exit (1); +} +#endif /* test */ diff --git a/gnu/usr.bin/awk/regex.h b/gnu/usr.bin/awk/regex.h new file mode 100644 index 0000000000..fce11c3a97 --- /dev/null +++ b/gnu/usr.bin/awk/regex.h @@ -0,0 +1,260 @@ +/* Definitions for data structures callers pass the regex library. + + Copyright (C) 1985, 1989-90 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#ifndef __REGEXP_LIBRARY +#define __REGEXP_LIBRARY + +/* Define number of parens for which we record the beginnings and ends. + This affects how much space the `struct re_registers' type takes up. */ +#ifndef RE_NREGS +#define RE_NREGS 10 +#endif + +#define BYTEWIDTH 8 + + +/* Maximum number of duplicates an interval can allow. */ +#ifndef RE_DUP_MAX +#define RE_DUP_MAX ((1 << 15) - 1) +#endif + + +/* This defines the various regexp syntaxes. */ +extern long obscure_syntax; + + +/* The following bits are used in the obscure_syntax variable to choose among + alternative regexp syntaxes. */ + +/* If this bit is set, plain parentheses serve as grouping, and backslash + parentheses are needed for literal searching. + If not set, backslash-parentheses are grouping, and plain parentheses + are for literal searching. */ +#define RE_NO_BK_PARENS 1L + +/* If this bit is set, plain | serves as the `or'-operator, and \| is a + literal. + If not set, \| serves as the `or'-operator, and | is a literal. */ +#define RE_NO_BK_VBAR (1L << 1) + +/* If this bit is not set, plain + or ? serves as an operator, and \+, \? are + literals. + If set, \+, \? are operators and plain +, ? are literals. */ +#define RE_BK_PLUS_QM (1L << 2) + +/* If this bit is set, | binds tighter than ^ or $. + If not set, the contrary. */ +#define RE_TIGHT_VBAR (1L << 3) + +/* If this bit is set, then treat newline as an OR operator. + If not set, treat it as a normal character. */ +#define RE_NEWLINE_OR (1L << 4) + +/* If this bit is set, then special characters may act as normal + characters in some contexts. Specifically, this applies to: + ^ -- only special at the beginning, or after ( or |; + $ -- only special at the end, or before ) or |; + *, +, ? -- only special when not after the beginning, (, or |. + If this bit is not set, special characters (such as *, ^, and $) + always have their special meaning regardless of the surrounding + context. */ +#define RE_CONTEXT_INDEP_OPS (1L << 5) + +/* If this bit is not set, then \ before anything inside [ and ] is taken as + a real \. + If set, then such a \ escapes the following character. This is a + special case for awk. */ +#define RE_AWK_CLASS_HACK (1L << 6) + +/* If this bit is set, then \{ and \} or { and } serve as interval operators. + If not set, then \{ and \} and { and } are treated as literals. */ +#define RE_INTERVALS (1L << 7) + +/* If this bit is not set, then \{ and \} serve as interval operators and + { and } are literals. + If set, then { and } serve as interval operators and \{ and \} are + literals. */ +#define RE_NO_BK_CURLY_BRACES (1L << 8) + +/* If this bit is set, then character classes are supported; they are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +#define RE_CHAR_CLASSES (1L << 9) + +/* If this bit is set, then the dot re doesn't match a null byte. + If not set, it does. */ +#define RE_DOT_NOT_NULL (1L << 10) + +/* If this bit is set, then [^...] doesn't match a newline. + If not set, it does. */ +#define RE_HAT_NOT_NEWLINE (1L << 11) + +/* If this bit is set, back references are recognized. + If not set, they aren't. */ +#define RE_NO_BK_REFS (1L << 12) + +/* If this bit is set, back references must refer to a preceding + subexpression. If not set, a back reference to a nonexistent + subexpression is treated as literal characters. */ +#define RE_NO_EMPTY_BK_REF (1L << 13) + +/* If this bit is set, bracket expressions can't be empty. + If it is set, they can be empty. */ +#define RE_NO_EMPTY_BRACKETS (1L << 14) + +/* If this bit is set, then *, +, ? and { cannot be first in an re or + immediately after a |, or a (. Furthermore, a | cannot be first or + last in an re, or immediately follow another | or a (. Also, a ^ + cannot appear in a nonleading position and a $ cannot appear in a + nontrailing position (outside of bracket expressions, that is). */ +#define RE_CONTEXTUAL_INVALID_OPS (1L << 15) + +/* If this bit is set, then +, ? and | aren't recognized as operators. + If it's not, they are. */ +#define RE_LIMITED_OPS (1L << 16) + +/* If this bit is set, then an ending range point has to collate higher + or equal to the starting range point. + If it's not set, then when the ending range point collates higher + than the starting range point, the range is just considered empty. */ +#define RE_NO_EMPTY_RANGES (1L << 17) + +/* If this bit is set, then a hyphen (-) can't be an ending range point. + If it isn't, then it can. */ +#define RE_NO_HYPHEN_RANGE_END (1L << 18) + + +/* Define combinations of bits for the standard possibilities. */ +#define RE_SYNTAX_POSIX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_CONTEXT_INDEP_OPS) +#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_AWK_CLASS_HACK) +#define RE_SYNTAX_EGREP (RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_CONTEXT_INDEP_OPS | RE_NEWLINE_OR) +#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR) +#define RE_SYNTAX_EMACS 0 +#define RE_SYNTAX_POSIX_BASIC (RE_INTERVALS | RE_BK_PLUS_QM \ + | RE_CHAR_CLASSES | RE_DOT_NOT_NULL \ + | RE_HAT_NOT_NEWLINE | RE_NO_EMPTY_BK_REF \ + | RE_NO_EMPTY_BRACKETS | RE_LIMITED_OPS \ + | RE_NO_EMPTY_RANGES | RE_NO_HYPHEN_RANGE_END) + +#define RE_SYNTAX_POSIX_EXTENDED (RE_INTERVALS | RE_NO_BK_CURLY_BRACES \ + | RE_NO_BK_VBAR | RE_NO_BK_PARENS \ + | RE_HAT_NOT_NEWLINE | RE_CHAR_CLASSES \ + | RE_NO_EMPTY_BRACKETS | RE_CONTEXTUAL_INVALID_OPS \ + | RE_NO_BK_REFS | RE_NO_EMPTY_RANGES \ + | RE_NO_HYPHEN_RANGE_END) + + +/* This data structure is used to represent a compiled pattern. */ + +struct re_pattern_buffer + { + char *buffer; /* Space holding the compiled pattern commands. */ + long allocated; /* Size of space that `buffer' points to. */ + long used; /* Length of portion of buffer actually occupied */ + char *fastmap; /* Pointer to fastmap, if any, or zero if none. */ + /* re_search uses the fastmap, if there is one, + to skip over totally implausible characters. */ + char *translate; /* Translate table to apply to all characters before + comparing, or zero for no translation. + The translation is applied to a pattern when it is + compiled and to data when it is matched. */ + char fastmap_accurate; + /* Set to zero when a new pattern is stored, + set to one when the fastmap is updated from it. */ + char can_be_null; /* Set to one by compiling fastmap + if this pattern might match the null string. + It does not necessarily match the null string + in that case, but if this is zero, it cannot. + 2 as value means can match null string + but at end of range or before a character + listed in the fastmap. */ + }; + + +/* search.c (search_buffer) needs this one value. It is defined both in + regex.c and here. */ +#define RE_EXACTN_VALUE 1 + + +/* Structure to store register contents data in. + + Pass the address of such a structure as an argument to re_match, etc., + if you want this information back. + + For i from 1 to RE_NREGS - 1, start[i] records the starting index in + the string of where the ith subexpression matched, and end[i] records + one after the ending index. start[0] and end[0] are analogous, for + the entire pattern. */ + +struct re_registers + { + int start[RE_NREGS]; + int end[RE_NREGS]; + }; + + + +#ifdef __STDC__ + +extern char *re_compile_pattern (char *, size_t, struct re_pattern_buffer *); +/* Is this really advertised? */ +extern void re_compile_fastmap (struct re_pattern_buffer *); +extern int re_search (struct re_pattern_buffer *, char*, int, int, int, + struct re_registers *); +extern int re_search_2 (struct re_pattern_buffer *, char *, int, + char *, int, int, int, + struct re_registers *, int); +extern int re_match (struct re_pattern_buffer *, char *, int, int, + struct re_registers *); +extern int re_match_2 (struct re_pattern_buffer *, char *, int, + char *, int, int, struct re_registers *, int); +extern long re_set_syntax (long syntax); + +#ifndef GAWK +/* 4.2 bsd compatibility. */ +extern char *re_comp (char *); +extern int re_exec (char *); +#endif + +#else /* !__STDC__ */ + +extern char *re_compile_pattern (); +/* Is this really advertised? */ +extern void re_compile_fastmap (); +extern int re_search (), re_search_2 (); +extern int re_match (), re_match_2 (); +extern long re_set_syntax(); + +#ifndef GAWK +/* 4.2 bsd compatibility. */ +extern char *re_comp (); +extern int re_exec (); +#endif + +#endif /* __STDC__ */ + + +#ifdef SYNTAX_TABLE +extern char *re_syntax_table; +#endif + +#endif /* !__REGEXP_LIBRARY */ diff --git a/gnu/usr.bin/awk/version.c b/gnu/usr.bin/awk/version.c new file mode 100644 index 0000000000..adea5fafac --- /dev/null +++ b/gnu/usr.bin/awk/version.c @@ -0,0 +1,46 @@ +char *version_string = "@(#)Gnu Awk (gawk) 2.15"; + +/* 1.02 fixed /= += *= etc to return the new Left Hand Side instead + of the Right Hand Side */ + +/* 1.03 Fixed split() to treat strings of space and tab as FS if + the split char is ' '. + + Added -v option to print version number + + Fixed bug that caused rounding when printing large numbers */ + +/* 2.00beta Incorporated the functionality of the "new" awk as described + the book (reference not handy). Extensively tested, but no + doubt still buggy. Badly needs tuning and cleanup, in + particular in memory management which is currently almost + non-existent. */ + +/* 2.01 JF: Modified to compile under GCC, and fixed a few + bugs while I was at it. I hope I didn't add any more. + I modified parse.y to reduce the number of reduce/reduce + conflicts. There are still a few left. */ + +/* 2.02 Fixed JF's bugs; improved memory management, still needs + lots of work. */ + +/* 2.10 Major grammar rework and lots of bug fixes from David. + Major changes for performance enhancements from David. + A number of minor bug fixes and new features from Arnold. + Changes for MSDOS from Conrad Kwok and Scott Garfinkle. + The gawk.texinfo and info files included! */ + +/* 2.11 Bug fix release to 2.10. Lots of changes for portability, + speed, and configurability. */ + +/* 2.12 Lots of changes for portability, speed, and configurability. + Several bugs fixed. POSIX compliance. Removal of last set + of hard-wired limits. Atari and VMS ports added. */ + +/* 2.13 Public release of 2.12 */ + +/* 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. */ + diff --git a/gnu/usr.bin/groff/BUG-REPORT b/gnu/usr.bin/groff/BUG-REPORT new file mode 100644 index 0000000000..c87c66fe53 --- /dev/null +++ b/gnu/usr.bin/groff/BUG-REPORT @@ -0,0 +1,57 @@ + Groff Bug Report + +Please read the PROBLEMS file before sending in a bug report. + +Please fill in all fields, even if you think they are not relevant. + +Please delete the text in brackets before sending it in. + +Please report separate bugs separately. + +Send the completed form either to bug-groff@prep.ai.mit.edu or +directly to me (jjc@jclark.com). Messages sent to bug-groff can +sometimes take several days to reach me. + +GROFF VERSION: +[The version of groff you are using. For example, `1.05'] + +MACHINE: +[The machine you are using. For example, `Sun SPARCstation 2'] + +OS: +[The operating system you are using. For example, `SunOS 4.1.1'] + +COMPILER: +[The compiler you are used to compile groff. For example, `g++ 1.40.3'] + +INPUT FILES: +[Include all the files necessary to reproduce the problem that are not +part of the standard groff distribution. This includes font +description files, DESC files and macro files (with the exception of +the -ms and -mm macros: I have them). Send them as as a shell archive +or as a uuencoded, compressed tar file. + +It's easier for me if you can provide an example that doesn't depend +on any macro package, but obviously if you're reporting a problem with +a macro package that won't be possible. Also a short example is more +convenient than a long one, but don't worry if you can't find a short +example. Don't say something like ``any file that X'': always send a +definite example.] + +COMMAND LINE: +[The command line that I should run in order to observe the bug. For +example, `gtroff -Tps bug.tr'. If the commmand line uses -ms or -mm, +say whether these refer to the groff versions or the Unix versions of +the macros.] + +DESCRIPTION OF INCORRECT BEHAVIOUR: +[What goes wrong when that command line is run? For example, `gtroff +gets a segmentation fault', or `The output looks bad because the bar +over the x is too long and is too far over to the left.' If you get +an error message, include it here without modification: don't edit it +to make it more readable.] + +SUGGESTED FIX [optional]: +[If you can suggest a fix for the problem, include a context diff +here. But don't delay sending in a bug report in the hope of finding +a fix. Guesses about the cause of the bug are not usually helpful.] diff --git a/gnu/usr.bin/groff/COPYING b/gnu/usr.bin/groff/COPYING new file mode 100644 index 0000000000..c712f50f09 --- /dev/null +++ b/gnu/usr.bin/groff/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the 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. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/usr.bin/groff/ChangeLog b/gnu/usr.bin/groff/ChangeLog new file mode 100644 index 0000000000..5c338d6741 --- /dev/null +++ b/gnu/usr.bin/groff/ChangeLog @@ -0,0 +1,4958 @@ +Mon Apr 19 09:55:57 1993 James Clark (jjc at jclark) + + * Version 1.08 released. + + * Makefile.in (dist): Insert || true after ln -s commands that + might fail. + + * mm: Update to mm 1.16. + + * acgroff.m4 (GROFF_CSH_HACK): New macro. + * configure.in: Call GROFF_CSH_HACK. Substitute for + SH_SCRIPT_SED_CMD. + * Makefile.in (SH_SCRIPT_SED_CMD): New variable. Include in + MDEFINES. + * nroff/Makefile.sub (nroff): New target. + (install_data): Install nroff. + * eqn/Makefile.sub (neqn): Sed with SH_SCRIPT_SED_CMD. + * grog/Makefile.sub (grog): Sed grog.sh with SH_SCRIPT_SED_CMD. + +Sat Apr 17 08:24:28 1993 James Clark (jjc at jclark) + + * eqn/Makefile.sub (neqn): Add chmod +x. + + * grog/Makefile.sub (grog): Remove spurious semi-colon. + +Fri Apr 16 22:41:57 1993 James Clark (jjc at jclark) + + * troff/input.cc (string_iterator::string_iterator()): Initialize + lineno and count. + +Tue Apr 13 10:22:28 1993 James Clark (jjc at jclark) + + * troff/div.cc (macro_diversion::space, + top_level_diversion::space): Don't set high_water_mark. + (macro_diversion::output, top_level_diversion::output): Don't + include post line space in high water mark. + +Wed Apr 7 12:48:18 1993 James Clark (jjc at jclark) + + * eqn/eqn.y: Don't define YYDEBUG. + * pic/pic.y: Likewise. + +Mon Apr 5 10:15:15 1993 James Clark (jjc at jclark) + + * tmac/tmac.e ([3): Add space after comma following editors. + Change double spaces to single spaces. + ([4): Change double spaces to single spaces. + + * grops/ps.h (USE_PS_ADOBE_2_0): New flag for broken_flags. + * grops/ps.cc (ps_printer::~ps_printer): If the USE_PS_ADOBE_2_0 + bit is set in broken_flags, use 2.0 rather than 3.0 as the version + after %!PS-Adobe- (for Newsprint). + + * troff/div.cc (top_level_diversion::begin_page): When + before_first_page is 1, set page_number to 1. + +Sun Apr 4 14:28:53 1993 James Clark (jjc at jclark) + + * eqn/box.cc (box::top_level): Protect equation with \&. + +Sat Apr 3 23:27:25 1993 James Clark (jjc at jclark) + + * groff/groff.cc (possible_command::set_name): Delete old name. + + * groff/groff.cc (possible_command::~possible_command): Use + a_delete. + + * troff/node.cc (troff_output_file::begun_page): New member. + (troff_output_file::troff_output_file): Initialize it. + (troff_output_file::really_begin_page): Only output V command if a + page has been begun. + + * pic/pic.y (placeless_element): Delete argument to PRINT after + use. + +Fri Apr 2 11:31:02 1993 James Clark (jjc at jclark) + + * Make wrapman work. + * troff/div.h (class top_level_diversion): Replace + first_page_begun by before_first_page (with opposite sense). + * Change first_page_begun to before_first_page inverting sense. + * troff/div.cc (class nl_reg): New class. + (init_div_requests): Use class nl_reg for \n(nl. + (top_level_diversion::begin_page): Don't call + output_file::begin_page if before_first_page is 2; + reset before_first_page afterwards. If have_next_page_number is + false, then always increment page_number. + * tmac/tmac.an: Set traps within TH rather than at the top-level. + Restore compatibility mode after loading, and then disable + compatibility mode in TH. + +Thu Apr 1 11:09:34 1993 James Clark (jjc at jclark) + + * grotty/tty.cc (tty_printer::end_page): Don't discard characters + past last line. + * troff/node.h (output_file::trailer): Declare. + * troff/div.cc (cleanup_and_exit): Call output_file::trailer(). + * troff/node.cc (output_file::trailer): New function. + (troff_output_file::~troff_output_file): Move most code into... + (troff_output_file::trailer): New function. + (class troff_output_file): Delete page_length member. Declare + trailer(). + (troff_output_file::really_begin_page): Use current page length + for final V command. + + * tbl/main.cc (struct options): New decimal_point_char member. + (options::options): Initialize this. + (process_options): Implement decimalpoint option. + (process_data): Pass decimal_point_char option to table::table. + * tbl/table.h (class table): New decimal_point_char member. + (table::table): Add additional argument. + * tbl/table.cc (find_dot): Rename to find_decimal_point. Add + second argument specifying decimal point character. Use this + instead of '.'. + (table::table): Initialize decimal_point_char. + (table::add_entry): Change call to find_dot. + + * troff/input.cc (get_copy, token::next): Implement \V. + (interpolate_environment_variable): New function. + +Tue Mar 30 14:41:39 1993 James Clark (jjc at jclark) + + * pic/lex.cc (lookup_keyword): Rename MIN to K_MIN, MAX to K_MAX. + * pic/pic.y: Likewise. + + * grotty/tty.cc (tty_printer::add_char, tty_printer::end_page): + Add casts to int. + * refer/ref.cc (reference::insert_field, reference::delete_field): + Likewise. + * troff/number.cc (parse_term): Likewise. + + * acgroff.m4 (GROFF_PROG_YACC): New macro. + * configure.in: Use GROFF_PROG_YACC. + + * acgroff.m4 (GROFF_PROG_CCC): Don't add -O automatically for gcc + and g++. + * Makefile.in (OPTIMIZE): New define. + (DEBUG): Empty by default. + (CCFLAGS, CFLAGS): Include $(OPTIMIZE). + + * acgroff.m4 (GROFF_SYS_SIGLIST): Don't quote program. + (GROFF_ARRAY_DELETE): Likewise. + (GROFF_CC_COMPILE_CHECK): Quote use of $2 and $3. + + * troff/env.cc (trie::~trie): Make virtual to shut up g++. + + * devps/psstrip.sed: Use different delimiter on last line (so that + it works with BSD 4.4 sed.) + +Mon Mar 29 17:07:14 1993 James Clark (jjc at jclark) + + * devps/psstrip.sed: Delete comments. + + * acgroff.m4 (AC_GETOPT): Don't test whether declares + optind, opterr, optarg. + * lib.h: When UNISTD_H_DECLARES_GETOPT is defined, declare optind, + opterr, optarg. + +Sun Mar 28 17:44:25 1993 James Clark (jjc at jclark) + + * Makefile.in (check): Dummy target. + +Wed Mar 3 04:53:38 1993 James Clark (jjc at jclark) + + * Version 1.07 released. + + * Integrate mm 1.11. + + * tbl/table.cc (alphabetic_block_entry::print): start_row was used + where start_col was meant. + +Thu Feb 25 07:55:36 1993 James Clark (jjc at jclark) + + * grog/grog.sh, grog/grog.pl: Recognize PH and SA as -mm macros. + +Wed Feb 24 10:15:34 1993 James Clark (jjc at jclark) + + * troff/input.cc (token::next): Make \z\o'...' and similar things + work. + + * env.h (MARGIN_CHARACTER_ON, MARGIN_CHARACTER_NEXT): New + constants. + (environment): Add margin_character_flags member. + * env.cc (environment::environment(symbol), + environment::environment(const environment *): Initialize + margin_character_flags. + (margin_character): Rewrite. + (environment::output_line): Add a margin character if + margin_character_flags is non-zero. Turn off the + MARGIN_CHARACTER_NEXT bit. If that makes margin_character_flags + zero, use margin_character_node without copying and then set + margin_character_node to 0. + + * devps/DESC.in: Change minimum size to 1000. + +Tue Feb 23 14:57:49 1993 James Clark (jjc at jclark) + + * troff/symbol.h (symbol::hash): Change return type to unsigned + long. + * troff/dictionary.cc (dictionary::lookup, dictionary::remove): + Add casts to int. + + * test-groff: Use -r rather than -x. + + * grops/psfig.diff: Include in distribution again. + +Mon Feb 22 09:10:44 1993 James Clark (jjc at jclark) + + * Makefile.in (dist): Use gzip. + +Sun Feb 21 11:12:53 1993 James Clark (jjc at jclark) + + * acgroff.m4 (GROFF_GETOPT): Check for declaration of getopt() in + unistd.h as well as in stdlib.h. + * include/lib.h: Include is STDLIB_H_DECLARES_GETOPT is + defined; otherwise include and if + UNISTD_H_DECLARES_GETOPT is defined. + + * configure.in: use builtin(include, ... rather than include(... + * configure: Regenerate with autoconf 1.3. + + * libdriver/print.cc (printer::adjust_arc_center): Use new + algorithm suggested by Andy Fyfe. + + * libdriver/printer.cc (printer::adjust_arc_center): New function. + * include/printer.h: Declare this. + * grops/ps.cc (ps_printer::draw): Use it. + * grodvi/dvi.cc (dvi_printer::draw): Use it. + +Fri Feb 19 23:13:51 1993 James Clark (jjc at jclark) + + * Makefile.comm (.man.n): Replace macrodir by tmacdir. + +Thu Feb 11 16:46:59 1993 James Clark (jjc at jclark) + + * eqn/main.cc (main): Handle "eqn -". + +Mon Jan 4 20:29:56 1993 James Clark (jjc at jclark) + + * tmac/tmac.e (++): Install fix from comp.bugs.4sd. + + * mm: Integrate version 1.08. + + * pic/troff.cc (troff_output::finish_picture): Set + EQN_NO_EXTRA_SPACE reg to 0 rather than removing it. + * eqn/box.cc (box::extra_space): Set EQN_NO_EXTRA_SPACE_REG to 0 + if it's not defined. Check whether the register is non-zero rather + than whether it's not defined. + * tmac.e ({, <): Make argument to \x zero if \n(0x is non-zero. + + * indxbib/indxbib.cc: Move all signal handling into... + * indxbib/signal.c: New file. + * configure.in: Call AC_RETSIGTYPE. + + * acgroff.m4 (GROFF_STRUCT_EXCEPTION): New macro. + * configure.in: Call GROFF_STRUCT_EXCEPTION. + * libgroff/matherr.c: Protect with ifdef HAVE_STRUCT_EXCEPTION. + + * troff/input.cc (token::token, token::operator=): Work round SGI + C++ bug. + * pic/object.cc (position::position): Likewise. + +Mon Dec 28 21:50:21 1992 James Clark (jjc at jclark) + + * pic/pic.h: Move declaration of hypot(). + +Wed Dec 16 12:28:29 1992 James Clark (jjc at jclark) + + * pic/pic.h: Declare hypot(). + + * pic/pic.h: Define M_PI if necessary. + +Thu Dec 10 12:03:29 1992 James Clark (jjc at jclark) + + * tmac/tmac.e (re): Add alternative version that doesn't use groff + `.ta T' feature. + + * devps/prologue.ps (RE): Handle the possibility that the old font + doesn't have a FontName entry. + +Wed Dec 2 10:25:29 1992 James Clark (jjc at jclark) + + * tmac/tmac.e (fam): Redefine to set family in environment 2. + (@C): Use @fam not fam. + +Thu Nov 26 16:01:25 1992 James Clark (jjc at jclark) + + * lookbib/lookbib.cc (main): Change type of start to const char *. + * lkbib/lkbib.cc (main): Likewise. + + * eqn/lex.cc (definition::definition): Don't use member + initializer syntax for members of anonymous unions. + + * troff/input.cc (input_stack::backtrace): Change type of to const + char *. + +Wed Nov 25 13:43:09 1992 James Clark (jjc at jclark) + + * include/stringclass.h (class string): Declare inline friend + functions as inline in class declaration. + * troff/hvunits.h (class hunits, class vunits): Likewise. + * include/refid.h (class reference_id): Likewise + * troff/troff.h (points_to_units(units), scale(units, double)): + Delete declarations. + * libdriver/input.cc (get_char): Delete declaration. + * include/lib.h: Change 2nd argument of getopt from const char ** + to char **. + * troff/symbol.cc (symbol::symbol): Cast `new char *[n]' to `const + char **' before assigning to a `const char **'. + * tbl/table.cc: Delete extra declarations of prints(). + +Tue Nov 24 14:33:13 1992 James Clark (jjc at jclark) + + * libgroff/font.cc (font::load_desc): Cast `new char *[n]' to `const + char **' before assigning to a `const char **'. + + * libgroff/errarg.cc (errarg::errarg): Don't use member + initializer syntax for members of anonymous unions. + +Sat Nov 21 05:02:23 1992 James Clark (jjc at jclark) + + * mm: Integrate version 1.07. + +Tue Nov 17 16:44:27 1992 James Clark (jjc at jclark) + + * troff/input.c (translate2): Rename to + (translate_no_transparent). + (init_input_requests): Rename tr2 to trnt. + +Mon Nov 16 09:49:32 1992 James Clark (jjc at jclark) + + * troff/charinfo.h (class charinfo): Add transparent_translate field. + (charinfo::set_translation, charinfo::set_special_translation): + Add second argument that specifies value for + transparent_translate. + (charinfo::get_translation, charinfo::get_special_translation): + Add optional second argument that specifies whether translation is + being used for transparent throughput. + * troff/input.cc (charinfo::set_translation, + charinfo::set_special_translation): Handle second argument. + (charinfo::charinfo): Initialize transparent_translate. + (translate): Split main part off into + (do_translate): New function. Pass argument saying whether + translation applies to transparent throughput. + (translate2): New request. + (init_input_requests): Bind translate2 to `tr2'. + +Wed Nov 11 11:43:20 1992 James Clark (jjc at jclark) + + * tbl/table.h (class table): Add `nokeep' flag. + * tbl/main.cc (process_options): Handle `nokeep' option. + * tbl/table.cc (table::init_output, table::do_row, table::do_top, + table::do_bottom): Don't output keep/release macro definitions or + calls when `nokeep' option has been specified. + +Sat Nov 7 01:28:33 1992 James Clark (jjc at jclark) + + * tmac/tmac.Xps (Xps-char): Use " as delimiter for \Z. + +Wed Nov 4 16:29:04 1992 James Clark (jjc at jclark) + + * tbl/table.cc (table_entry::divert, block_entry::do_divert, + block_entry::divert, alphabetic_block_entry::divert): Add extra + argument giving column separation. + (table::compute_widths): Pass column separation to + table_entry::divert(). + (block_entry::do_divert): If an entry spans multiple columns and a + minimumum width has been specified for each column, then set the + line length to the sum of the widths (plus possibly the column + separations). + + * troff/input.cc (set_escape_char): Don't set the escape_char + until after calling has_arg(). + +Tue Nov 3 11:23:27 1992 James Clark (jjc at jclark) + + * tbl/table.cc (table::do_top): Add missing \s0 for double box + case. + + * tbl/table.cc (table::print_double_hline): Avoid extra new line + in case where r > nrows - 1. + + * tbl/table.cc (BODY_HEIGHT): Deleted. + (LINE_SEP): New definition. + (table::print_single_hline, table::print_double_hline, + table::compute_vrule_top_adjust, table::compute_vrule_bot_adjust, + table::do_row, table::do_top): Use LINE_SEP space before a line + instead of \n[.v]-BODY_HEIGHT-BODY_DEPTH. + + * tbl/table.cc (text_entry::print_contents): New function. + (text_string_name, right_text_string_name): Deleted. + (TEXT_STRING, RIGHT_TEXT_STRING): Deleted. + (simple_text_entry::do_width, numeric_text_entry::do_width, + alphabetic_text_entry::do_width): Don't store the contents of the + entry in a string. + (left_text_entry::simple_print, right_text_entry::simple_print, + center_text_entry::simple_print, + alphabetic_text_entry::simple_print, + numeric_text_entry::simple_print): Print the entry directly + instead of using the stored string. + +Fri Oct 30 10:39:32 1992 James Clark (jjc at jclark) + + * devps/Makefile: Strip PostScript files. + * devps/prologue: Rename to... + * devps/prologue.ps. + * devps/psstrip.sed: New file. + * devps/download: Use .pfa rather than .ps for installed versions + of fonts. + +Thu Oct 29 09:14:43 1992 James Clark (jjc at jclark) + + * troff/env.cc (input_trap): Give a warning if the argument is out + of range. + + * troff/env.cc (adjust): Treat negative argument as missing. Round + argument > 5 down to 5. + + * troff/env.cc (center, right_justify): Make negative argument zero. + + * troff/div.cc (page_offset, vertical_position_traps): Treat + invalid argument as missing. + * troff/env.cc (line_spacing, line_length, title_length, indent, + underline, hyphen_line_max_request, control_char, + no_break_control_char, widow_control_request, adjust, input_trap, + point_size): Likewise. + * troff/node.cc (ligature, kern_request, bold_font, track_kern, + constant_space): Likewise. + * troff/input.cc (compatible, shift, warn_request, + set_escape_char): Likewise. + + * tbl/main.cc (format::format): Avoid doing `new int[0]'. + * tbl/table.cc (table::table): Likewise. + + * Makefile.dev (install_dev): depends on $(DEVFILES). + +Wed Oct 28 08:30:57 1992 James Clark (jjc at jclark) + + * devX75, devX75-12, devX100, devX100-12: New directories. + * Makefile.in: Add these to DEVDIRS. + + * troff/Makefile.sub, eqn/Makefile.sub, indxbib/Makefile.sub, + afmtodit/Makefile.sub, tmac/Makefile.sub, nroff/Makefile.sub, + grog/Makefile.sub, mm/Makefile.sub (uninstall_sub): New target. + * Makefile.in (uninstall, uninstall_sub, uninstall_dirs): New + targets. + * Makefile.ccpg, Makefile.cpg, Makefile.dev, Makefile.man + (uninstall): New target. + * Makefile.comm (uninstall, uninstall_sub, uninstall_man, + uninstall_prog, uninstall_dev): New targets. + + * troff/div.cc (return_request): Treat an invalid argument as + missing. + +Mon Oct 26 11:33:47 1992 James Clark (jjc at jclark) + + * tmac/tmac.e ((f): Set up the environment even when there's a + current diversion. Transperently throughput a call to @N. + (@N): New macro. + +Thu Oct 22 05:05:59 1992 James Clark (jjc at jclark) + + * tbl/table.cc (table::compute_vrule_top_adjust): Round adjustment + up to vertical resolution. + + * tbl/table.cc (table::do_row): Change row number after printing + stuff list. + + * pic/lex.cc (get_token_after_dot): Make .left and .right work. + +Wed Oct 21 14:46:45 1992 James Clark (jjc at jclark) + + * Rename CHANGES to NEWS. + +Tue Oct 20 23:25:21 1992 James Clark (jjc at jclark) + + * libgroff/new.cc (operator new): Avoid calling malloc(0). + +Mon Oct 19 09:10:13 1992 James Clark (jjc at jclark) + + * man.ultrix: Removed. + +Sun Oct 18 06:35:15 1992 James Clark (jjc at jclark) + + * Makefile.comm (extraclean): Delete files whose names begin with + `='. + + * pic/troff.cc (troff_output::text): Fix typo in implementation of + aligned text. + +Sat Oct 10 09:32:29 1992 James Clark (jjc at jclark) + + * troff/env.cc (hyphenate_request, vertical_spacing, no_number): + * troff/div.cc (page_length, need_space, space_request): Treat + invalid optional argument as missing. + * troff/env.cc (number_lines): If the first argument is present + but not a number, turn on line numbering, don't change the next + line number and parse the remaining arguments. + + * tmac/tmac.e (@q): Do the `ne' before changing to environment 2. + +Thu Oct 8 10:24:40 1992 James Clark (jjc at jclark) + + * eqn/box.h: Change declaration accordingly. + * eqn/box.cc (set_gsize): Change return type to int. Return 0 if + the specified size was bad but don't give an error. Check for + overflow. + * eqn/main.cc (main): Change caller. Leave validation to set_gsize. + * eqn/lex (do_size): Likewise. + +Wed Oct 7 09:48:59 1992 James Clark (jjc at jclark) + + * acgroff.m4 (GROFF_PROG_CCC): Use fopen when checking for C++ + compatible headers. + +Sun Oct 4 18:24:02 1992 James Clark (jjc at jclark) + + * tbl/table.cc (table::init_output): Improve error message when + table won't fit on one page. + +Fri Oct 2 10:41:40 1992 James Clark (jjc at jclark) + + * pic/troff.cc (troff_output::start_picture): Generate line + containing a horizontal motion equal to the width of the picture. + + * groff/groff.cc (main): Allow PROG_PREFIX to be set at runtime + using GROFF_COMMAND_PREFIX environment variable. + +Fri Sep 25 11:40:40 1992 James Clark (jjc at jclark) + + * mdate.sh: Use $NF rather than $(NF). + +Tue Sep 22 09:47:24 1992 James Clark (jjc at jclark) + + * pic/main.cc (main): Use %1 not %c in argument to warning. + + * eqn/main.cc (main): Output code to check that geqn was given the + correct -T option. + +Mon Sep 21 10:59:16 1992 James Clark (jjc at jclark) + + * Makefile.in (dist): Instead of doing `make -f ../Makefile', do + `ln -s ../Makefile .; make; rm -f Makefile'. + + * troff/hyphen: Rename to... + * troff/hyphen.us: + * troff/input.cc (main): Delete -H option. Don't call + read_hyphen_file(). + * troff/env.cc: Include searchpath.h and macropath.h. + (exception_dictionary): Deleted. + (ht): Deleted. + (read_hyphen_file): Deleted. + (hyphenation_language): New struct. + (class trie, class hyphen_trie): Move declarations up. + (trie_node::~trie_node): Deleted. + (trie::delete_trie_node): New function. + (trie::do_delete): New pure virtual function. + (hyphen_trie::do_delete): New function. + (trie::~trie): New function. + (hyphen_trie::~hyphen_trie): New function. + (trie::clear): No need to chcek that tp is not 0. + (current_language, language_dictionary): New variables. + (hyphen_word): Give an error if no current language. Use + exceptions dictionary in current language. + (hyphen_trie::read_patterns_file): Find file using macro_path. + Allow comments (starting with %) in patterns file. Don't make it + a fatal error if the file can't be found. + (hyphenate): Return if no current language. Get the exceptions + dictionary and the hyphenation patterns from the current language. + (set_hyphenation_language): New variable. + (hyphenation_patterns_file): New function. + (hyphenation_language_reg): New class. + (hyphenation_language_reg::get_string): New function. + (init_hyphen_requests): Bind "hla" to set_hyphenation_language and + "hpf" to hyphenation_patterns_file. Initialize `.hla' number + register. + * groff/groff.cc (main, help, synopsis): Delete -H option. + * include/Makefile.sub: Don't define HYPHENFILE. + * Makefile.in: Delete hyphenfile variable and remove from MDEFINES. + * Makefile.comm (.man.n): Don't substitute for HYPHENFILE. + * tmac/troffrc: Set hyphenation language to `us'. Load `hyphen.us' + hyphenation patterns. + +Sun Sep 20 09:33:02 1992 James Clark (jjc at jclark) + + * eqn/neqn.sh: New file. + * eqn/Makefile.sub: Handle neqn.sh. + + * eqn/eqn.h: Declare `nroff' variable. + * eqn/box.cc (param_table): Add `nroff' param. + (nroff): Define it. + * eqn/lex.cc (yylex): Handle TDEFINE and NDEFINE using `nroff' + variable. + * tmac/eqnrc: Set `nroff' to 1 for -Tascii or -Tlatin1. + + * troff/troff.h (WARN_FONT): New warning. + (WARN_TOTAL): Change accordingly. + * troff/input.cc (DEFAULT_WARNING_MASK): Include WARN_FONT. + (warning_table): Add WARN_FONT. + * troff/node.cc (mount_font_no_translate): Pass argument to + font::load_font. If this is non-zero, give a warning. + Don't give an error message when accessing a font that has already + been found to be invalid. + * include/font.h (font::load, font::load_font): Add additional + optional argument which suppresses error message if the font is + not found. + * libgroff/font.cc (font::load_font): Handle additional argument. + (font::load): Add additional argument. If this is non-null, set it + to 1 and don't give error message. + + * include/printer.h (printer::end_page): Add argument giving + length of page. + * libdriver/input.cc (do_file): Pass this. + * grops/ps.cc (ps_printer::end_page): Add argument. + * grodvi/dvi.cc (dvi_printer::end_page, + draw_dvi_printer::end_page): Add argument. + * grotty/tty.cc (class tty_printer): Remove lines_per_page and + columns_per_page members. New member nlines. + (DEFAULT_LINES_PER_PAGE): Deleted. + (tty_printer::tty_printer): Don't compute lines_per_page from + font::paperlength. Don't compute columns_per_page from + font::paperwidth. + (tty_printer::add_char): Don't check horizontal position against + columns_per_page. Grow glyphs vector if neccessary. + (tty_printer::end_page): Add argument giving page_length in units. + Discard lines past end of page. + +Wed Sep 16 06:29:52 1992 James Clark (jjc at jclark) + + * tmac/tmac.tty-char: Fix definition of \(/l. + + * tmac/tmac.X: Define \(en. + +Tue Sep 15 10:37:13 1992 James Clark (jjc at jclark) + + * acgroff.m4 (GROFF_PRINT): If a system has lpr and lp but not + lpq, then use lp rather than lpr. + + * tmac/tmac.s (par@reset): Don't call `ad'. + (par*env-init): Call `ad'. + +Sun Sep 13 18:48:20 1992 James Clark (jjc at jclark) + + * mdate.sh: Use $(NF) instead of $6 to extract year from output of + date. + + * troff/symbol.cc: #undef BLOCK_SIZE if it's defined. + * indxbib/indxbib.cc: Likewise. + +Sun Sep 6 09:44:46 1992 James Clark (jjc at jclark) + + * libgroff/putenv.c: New file. + * libgroff/Makefile.sub: Add putenv.c to CSRCS. + * Makefile.in: Say that putenv.o can be one of LIBOBJS. + * configure.in: Test for putenv with AC_REPLACE_FUNCS. Test for + stdlib.h with AC_HAVE_HEADERS. + +Sat Sep 5 18:11:52 1992 James Clark (jjc at jclark) + + * indxbib/dirnamemax.c: Include only if + does not exist. + +Fri Sep 4 09:43:26 1992 James Clark (jjc at jclark) + + * eqn/box.cc (gsize): Make it an int. + (set_gsize): Parse argument handling increment or decrement. + (box::top_level): Convert gsize to a string. + + * troff/input.cc (exit_troff): Make buf unsigned char []. + Call to make_temp_iterator casts buf to char*. + + * Makefile.in ($(TARGETS), dot): Pass $(MDEFINES) to recursive makes. + + * Makefile.ccpg (depend.temp): Depends on $(YTABC). + * Makefile.cpg (depend.temp): Likewise. + + * Makefile.dep: Remove Makefile.dep from $(REALCLEANFILES). + + * Makefile.comm: Add y.output to MOSTLYCLEANFILES. + +Thu Sep 3 08:01:55 1992 James Clark (jjc at jclark) + + * tmac/tmac.s (B, I, BI, CW): Rewrite avoiding aliases. + +Tue Sep 1 18:24:53 1992 James Clark (jjc at jclark) + + * Version 1.06 released. + + * Integrate mm 1.04. + +Fri Aug 28 11:28:19 1992 James Clark (jjc at jclark) + + * Makefile.comm, Makefile.ccpg, Makefile.cpg: Fix TAGS target. + +Thu Aug 27 11:03:33 1992 James Clark (jjc at jclark) + + * afmtodit/afmtodit.pl: Add -n option that disables generation of + ligatures command. + * devps/generate/Makefile (CR, CB, CI, CBI): Pass -n flag to + afmtodit. Regenerate. + + * tmac/tmac.e ()z): Adjust _b if necessary so as to avoid moving + @f back past the current position. + + * tmac/tmac.e: Change calls to @R so that comments are not part of + arguments. + +Tue Aug 25 10:42:07 1992 James Clark (jjc at jclark) + + * configure.in: Check for mkstemp with AC_HAVE_FUNCS. + + * acgroff.m4 (GROFF_PROG_CCC): Don't check for . Instead + check that we can link a call to a function declared in . + (GROFF_UNISTD_H): New macro. + * configure.in: Call it. + * Makefile.in: Document it. + * include/posix.h: New file. + * troff/troff.h: Don't include + * troff/input.cc: Include posix.h. + * libgroff/new.cc, libgroff/tmpfile.cc: Include posix.h rather than + osfcn.h. + * indxbib/indxbib.cc, libbib/{search.cc,linear.cc,index.cc}: + Include posix.h rather , , , + . + * indxbib/indxbib.cc (S_IRUSR, S_IRGRP, S_IROTH): Delete definitions. + * libbib/index.cc (S_ISREG, O_RDONLY): Delete definitions. + * libbib/search.cc (O_RDONLY): Delete definition. + * refer/refer.cc, include/driver.h, pic/pic.h, groff/groff.cc: + Don't include . + + * acgroff.m4 (GROFF_TIME_T): New macro. + * configure.in: Call it. + * Makefile.in: Document it. + + * acgroff.m4 (GROFF_TRADITIONAL_CPP): New macro. + * configure.in: Call it. + * Makefile.in: Document -DTRADITIONAL_CPP. + * include/ptable.h: Don't include generic.h. + (name2): Define it. + + * tmac/tmac.s (][): Make [T1 and [T2 aliases for [T. + Afterwards remove [T1 and [T2. + (ref*spec!0, ref*spec!2): Use T1 rather than T. + (ref*spec!1, ref*spec!4, ref*spec!4): Use T2 rather than T. + (ref*add-T2): Renamed from ref*add-T. + (ref*add-T1): New macro. + +Mon Aug 24 11:11:11 1992 James Clark (jjc at jclark) + + * acgroff.m4 (AC_PROG_CCC): Use GROFF_EXIT rather than exit 1. + + * libbib/index.cc: Include . + (O_RDONLY): Define if necessary. + (make_index_search_item, index_search_item_iterator::get_tag, + index_search_item::check_files): Use O_RDONLY. + * libbib/seach.cc: Include , , . + (O_RDONLY): Define if necessary. + (search_list::add_file): Use O_RDONLY. + * indxbib/indxbib.cc: Include , , + . + (S_IRUSR, S_IRGRP, S_IROTH): Define if necessary. + (main): Use these. + + * libbib/index.cc (S_ISREG): Define it if necessary. + (index_search_item::load): Use S_ISREG. + + * include/driver.h: Include . + +Sun Aug 23 11:32:18 1992 James Clark (jjc at jclark) + + * eqn/box.cc (body_height): Increase default value to 85. + (body_depth): Increase default value to 35. + +Fri Aug 21 05:34:42 1992 James Clark (jjc at jclark) + + * eqn/pbox.h (SAVE_FONT_STRING): Define it. + * eqn/box.cc (box::top_level): Hide use of \R in a string that is + protected from expansion with \E. + + * acgroff.m4 (GROFF_PAGE): Use `case' to test domain. + + * Makefile (Makefile): New target. + + * Makefile.sub (configure, distfiles): New targets. + + * acgroff.m4 (GROFF_BROKEN_SPOOLER_FLAGS): Avoid using ${var:-val} + construct. + +Thu Aug 20 12:27:26 1992 James Clark (jjc at jclark) + + * eqn/box.cc (param_table): Add body_height and body_depth. + + * eqn/lex.cc (def_table): Make circumflex in hat_def roman. + +Tue Aug 18 16:24:25 1992 James Clark (jjc at jclark) + + * psbb/Makefile.sub: Don't link with libgroff.a. + + * acgroff.m4 (GROFF_PUTENV): New macro. + * configure.in: Call GROFF_PUTENV. + * Makefile.in: Document STDLIB_H_DECLARES_PUTENV. + * groff/groff.cc: Don't declare putenv if STDLIB_H_DECLARES_PUTENV + is defined. + + * troff/env.cc (distribute_space): Rename force_forward argument + to force_reverse. Reverse the list if force_reverse is true. + +Mon Aug 17 17:49:05 1992 James Clark (jjc at jclark) + + * tmac/tmac.an: Don't define a string `T'. Just define Tm. + + * eqn/pile.cc (matrix_box::compute_metrics): Don't allow computed + height or depth to be negative. Guard against SUP_RAISE quantity + being negative. + +Sat Aug 15 08:18:54 1992 James Clark (jjc at jclark) + + * devps/generate/textmap: Add `an' (arrowhorizex). + * tmac/tmac.ps: \(an overlaps horizontally. + * tmac/tmac.dvi, tmac/tmac.tty: Add `an'. + + * devps/symbolchars: Add arrowverttp, arrowvertbt. + * devps/textmap: Add arrowvertex. + * eqn/delim.cc (delim_table): Add uparrow, downarrow and + updownarrow delimiters. + * tmac/tmac.ps, tmac/tmac.X: Add definition of \(va. + + * tbl/table.cc (simple_entry::position_vertically, + block_entry::position_vertically): For a centered entry, perform + the motion in two stages. + + * refer/refer.cc (split_punct): Don't call lookup_token if there + is no token. + +Fri Aug 14 11:14:58 1992 James Clark (jjc at jclark) + + * troff/input.cc (token::next): Delete token_node after copying + token. + + * grodvi/grodvi.cc (dvi_printer::dvi_printer): Initialize + cur_point_size. + + * libdriver/printer.cc (printer::load_font): Delete old_font_table. + + * grops/ps.cc (ps_printer::define_encoding): Delete elements of vec. + +Tue Aug 11 13:50:38 1992 James Clark (jjc at jclark) + + * grops/ps.cc (usage): -b option takes an argument. + + * devps/prologue (PLG): New procedure. + * grops/ps.cc (main, usage): New -g option. + (ps_printer::~ps_printer): If guess_flag is set, guess the paper + length using PLG. + +Mon Aug 10 11:17:53 1992 James Clark (jjc at jclark) + + * include/cset.h: Include if we have it. + + * libgroff/illegal.cc: New file. + * include/lib.h (illegal_input_char): Use table. + * troff/input.cc (ESCAPE_RIGHT_PARENTHESIS): Renumber to 0206. + * pic/lex.cc (ARG1): Renumber to 14. + * eqn/lex.cc (ARG1: Likewise. + + * troff/Makefile.sub (majorminor.cc): Handle 3 part versions + (eg 1.05.90) correctly. + +Sun Aug 9 13:35:43 1992 James Clark (jjc at jclark) + + * tmac/tmac.e (sr): Deleted. Set $r and $R directly. + Rename $r and $R registers to $v and $V. + ($r, $R): Initialize to 0. + (@v, @V): New macros. + (sz): Call @v. + (@M): Call @V. + + * troff/input.cc (main, usage): Add -R option that says not to + load troffrc. + * eqn/main.cc (main, usage): Rename -n to -R. + +Sat Aug 8 00:16:00 1992 James Clark (jjc at jclark) + + * devps/DESC.in: Leave font positions 5-9 blank. + * devdvi/DESC.in: Likewise. + + * grog/grog.pl: Handle `.PS 0. + + * macros/tmac.e (@R, @S): New macros. + Declare @, po, $0, $i, $p, df, so, fu, bt, *, ?a, ?b, ?C, ?e, ?H, + ?I, ?n, ?o, ?R, ?s, ?T, ?W, ?w registers with @R. + Declare $H, $[0-9], .. macros with @S. + Declare |0, |1, |2, |3 strings with @S. + + * macros/tmac.e (@S): Rename to @U. + + * macros/tmac.e (@z): Define @b and bp as empty instead of + deleting them, + + * macros/tmac.e (@m): Deleted. + (@h): Don't call @m. + (@z): Don't set @m trap. + + * macros/tmac.e ($h, $f): Define |z as empty string. + + * macros/tmac.e (@D): Rework to avoid unbalanced .el requests. + (@q): Likewise. + + * macros/tmac.e (@h): Set ?H, ?C , ?s registers to 0 rather than + removing them. + ()f): Likewise for * register. + + * macros/tmac.e (sr): Don't ever scale the arguments. If the third + argument is missing, don't change $R. Call sr with three + arguments when initializing. + +Thu Jul 16 12:17:12 1992 James Clark (jjc at jclark) + + * macros/tmac.e (sr): New macro. + Initialize $r and $R using sr. + + * macros/tmac.e (,): Delete \*(#[. + + * troff/env.c (set_tabs): Read the tab type even if the position + is bad. Allow the position of the first tab stop to be negative. + +Wed Jul 15 13:14:37 1992 James Clark (jjc at jclark) + + * refer/dirnamemax.c: Use pathconf() if defines + _POSIX_VERSION. + * refer/Makefile: Compile dirnamemax.c using -DHAVE_UNISTD_H + rather than -DPATHCONF_MISSING. + * Makefile: Get rid of PATHCONF_MISSING. + + * refer/map.c: New file. + * refer/index.c: Interface to mmap through map.c. Rename map_size + to map_len. + * refer/Makefile: Handle map.c. + * Makefile: Include -DHAVE_MMAP in OLDCFLAGS rather than CFLAGS. + +Tue Jul 14 14:15:20 1992 James Clark (jjc at jclark) + + * Makefile: RANLIB should be `true' if there is no ranlib. + * lib/Makefile (libgroff.a): Simplify. + * driver/Makefile (libdriver.a): Simplify. + + * Makefile: Change -DWAIT_COREDUMP_0200 to -DWCOREFLAG=0200. + * groff.c (WCOREDUMP): Use WCOREFLAG. Define only if not already + defined. + +Sat Jul 11 09:19:17 1992 James Clark (jjc at jclark) + + * troff/env.c (compare_ranges): Declare as extern "C". + + * troff/input.c (init_registers): Use `struct tm' instead of `tm'. + + * macros/tmac.s, macros/tmac.e: Change .nx /dev/null to .nx. + +Wed Jul 8 11:52:27 1992 James Clark (jjc at jclark) + + * pic/troff.c (troff_output::text): Merge in grops_output::text, + but conditionalize use of \X based on \*(.T. + (grops_output::*): Deleted. + * pic/output.h: Delete declaration of make_grops_output. + * pic/main.c (main): Ignore -p and -x. driver_extension_flag is 1 + by default. -n sets it to 0. + (usage): Corresponding changes. + * groff.c (main): Don't pass -x or -p to pic. + * groff.sh: Likewise. + + * ps/ps.c (ps_printer::do_exec, ps_printer::do_file): Force ndefs + to be non-zero. + + * ps/devps/afmtodit: Change calculation of asc_boundary and + desc_boundary. Make these bounds inclusive. + * ps/devps: Regenerate font files. + +Tue Jul 7 13:14:15 1992 James Clark (jjc at jclark) + + * macros/tmac.latin1: New file. + * macros/tmac.tty-char: Use tmac.latin1. + (tmac.tty-tr): Deleted. + * macros/Makefile: Install tmac.latin1. + * macros/tmac.dvi: Use tmac.latin1. + * macros/troffrc: Translate \[char160] onto no-break space here. + * macros/{tmac.dvi,tmac.ps,tmac.tty,tmac.X75}: Don't do it here. + +Mon Jul 6 11:06:52 1992 James Clark (jjc at jclark) + + * macros/tmac.Xps: Use `do' request. + + * macros/tmac.ps: Use `do' request. + + * macros/tmac.e (@C): Use `do' request. + + * macros/tmac.X, macros/tmac.Xps: Moved from xditview. + * macros/Makefile: Install tmac.X*. + + * tty/tmac.tty, tty/tmac.tty-char: Move to macros. + * tty/Makefile: Don't install tmac.tty*. + * macros/Makefile: Install tmac.tty*. + + * dvi/tmac.dvi: Move to macros. + * dvi/Makefile: Don't install tmac.dvi. + * macros/Makefile: Install tmac.dvi. + + * ps/tmac.ps*: Move to macros. + * ps/Makefile: Don't install tmac.ps*. + * macros/Makefile: Install tmac.ps*. + + * eqn/box.c: Provide draw_lines parameter corresponding to -D + option. + * macros/eqnrc: Set draw_lines parameter based on device. + * groff.c: Don't pass -D flag to eqn. + * groff.sh: Likewise. + * eqn/main.c: Warn about use of -D. + + * troff/input.c (process_startup_file): New function. + (main): Call process_startup_file(). + * macros/troffrc: New file. + * macros/Makefile: Install troffrc. + * groff.c (main): Don't pass extra -m option to troff. For a + pseudo device pass the name of the pseudo device to troff using + -d. + * groff.sh: Likewise. + * groff.c (possible_command::prepend_arg): Deleted. + + * troff/input.c (do_request): New function. + (init_input_requests): Bind "do" to do_request. + + * eqn/main.c (main): Instead of loading eqnchar from device directory, + load eqnrc from macro directory. + * macros/eqnrc: New file. + * macros/Makefile: Install eqnrc. + * ps/devps/eqnchar: Deleted. + * ps/devps/Makefile: Don't install eqnchar. + * dvi/devdvi/eqnchar: Deleted. + * dvi/devdvi/Makefile: Don't install eqnchar. + * groff.c (main): Pass -M to eqn. Don't pass -F to eqn. New + variable optM. + + * lib/device.[ch]: New files. + * lib/font.h (font::set_device_name, font::get_device_name): + Deleted. + * lib/fontfile.c: Use device.h. + * lib/Makefile: Handle device.[ch]. Make paths.h define DEVICE. + * troff/input.c: Delete definition of `device'. + (main): Don't initialize device. + * troff/troff.h: Include device.h rather than declaring device. + * troff/Makefile: No need to handle DEVICE. + * driver/input.c: Include device.h. Don't use + font::{set,get}_device_name. + * groff.c, Makefile: Rename device.h to config.h. + * groff.c: Use library device variable. + * eqn/main.c: Use library device variable. + * eqn/Makefile: No need to handle DEVICE. + + * lib/searchpath.[ch]: New files. + * lib/Makefile: Handle searchpath.[ch]. + * troff/input.c (open_file, init_dirs): Deleted. + (macro_dirs): Deleted. + (open_mac_file, macro_source): Use class search_path. + (add_string, struct string_list): Move definition. + (main): Change -M option to use macro_path. Delete call to + init_dirs(). + * lib/fontfile.c (font::command_line_font_dir, font::open_file): + Rewrite to use class search_path. + * lib/font.h, lib/fontfile.c (font::cl_font_dirs): Deleted. + * lib/Makefile: fontfile.c depends on searchpath.h. + * lib/Makefile: Rename fontpath.h to paths.h. Make paths.h define + MACROPATH. + * lib/macropath.[ch]: New files. + * troff/Makefile: No need to handle MACROPATH. + + * troff/input.c: Delete DUMP code. + * lib/fontfile.c, lib/font.h: Delete + font::forget_command_line_font_dirs. + + * troff/input.c (push_token): New function. + (handle_first_page_transition): Use push_token(). + (process_input_stack): Change handling of a space at the beginning + of the line. + +Sun Jul 5 17:11:09 1992 James Clark (jjc at jclark) + + * troff/input.c (font_dirs): Delete unused variable. + + * eqn/lex.c (do_set): Correct error messages. + +Sat Jul 4 10:20:55 1992 James Clark (jjc at jclark) + + * troff/input.c (do_define_string): Allow the string name to be + followed immediately by a tab. + (define_character): Likewise. + +Thu Jul 2 10:59:15 1992 James Clark (jjc at jclark) + + * ps/ps.c (ps_printer::draw): When drawing an arc, don't allow k to + be negative. + + * troff/input.c (input_iterator::is_file): New virtual function. + (file_iterator::is_file): New function. + (input_stack::end_file): New function. + (input_stack::next_file): Handle the situation where there is no + file on the input stack correctly. Avoid making two passes over + the input stack. + (next_file): Make the filename optional; in this case call + input_stack::end_file(). + +Wed Jul 1 10:17:25 1992 James Clark (jjc at jclark) + + * dvi/tmac.dvi: Change the definitions of \(ul and _ so that they + produce a real _ charater when the current font is CW and _ + otherwise. + + * lib/errarg.c (errarg::errarg(const char *)): Invert conditional + expression to work around gcc 2.2 bug. + +Wed Jun 24 08:12:24 1992 James Clark (jjc at jclark) + + * eqn/main.c (main): Don't give an error if we can't find eqnchar. + + * troff/env.c (environment::add_padding): New function. + (environment::add_char): Use add_padding(). + (environment::space): Likewise. + (environment::wrap_up_field): Add some padding if there is none + and there's no current tab. + * troff/env.h: Declare environment::add_padding. + +Mon Jun 22 08:37:45 1992 James Clark (jjc@jclark) + + * pic/pic.y: undef fmod and rand before declaring them. + +Sun Jun 14 11:40:18 1992 James Clark (jjc@jclark) + + * troff/input.c (main): If the DESC file specifies a font name of + 0, then leave the corresponding font position empty. + + * nroff.sh: New file. + * Makefile (install.nobin): Install nroff.sh. + + * tty/devlatin1/R.proto: Add ao as synonym for de. + * tty/tmac.tty-char: Define ao as o. + + * tty/dev{ascii,latin1}/R.proto: Add aq. + * tty/tmac.tty-char: Delete definition of aq. + +Mon Jun 8 11:43:20 1992 James Clark (jjc@jclark) + + * troff/input.c (init_charset_table): Don't translate 0240. + * ps/tmac.ps: Translate char160 to space. + * dvi/tmac.dvi: Likewise. + * tty/tmac.tty: Likewise. + +Sun Jun 7 10:52:35 1992 James Clark (jjc@jclark) + + * dvi/tmac.dvi: Add support for all Latin-1 characters. + + * macros/tmac.s: Delete definitions of \(rg, \(ah, \(ad, \(a-, + \(ao, \(ac, \(ho, \(-D, \(Sd, \(TP, \(Tp, \(ss, \(AE, \(ae, \(OE, + \(oe, \(r?, \(r!. + + * tty/tmac.tty-char: Add \(ah. + + * dvi/tmac.dvi: Add definitions of Tp, TP, Sd, -D, ho. + No need to define \(FM and \(!/. Conditionalize all character + definitions. + + * ps/devps/lgreekmap: Add +h, +f, +p. + + * ps/tmac.psnew: New file. + * ps/Makefile: Install tmac.psnew. + + * troff/input.c (charinfo_to_node_list): Don't ever interpret + character definitions in compatible mode. + + * troff/input.c (remove_character): New function. + (init_input_requests): Bind remove_character to "rchar". + + * ps/tmac.psold: New file. + * ps/Makefile: Install tmac.psold. + * ps/tmac.ps: Load tmac.psold. Move definitions of ISO Latin-1 + characters into tmac.psold. Make these definitions unconditional. + + * tty/tmac.tty-char: Define \n(_C only if it is not already defined. + + * ps/tmac.ps: Don't define \('c and \('C. + + * ps/devps/textmap: Move Greek characters to... + * ps/devps/symbolchars: + +Sat Jun 6 16:41:17 1992 James Clark (jjc@jclark) + + * ps/devps/text.enc: Add quotesingle. + * ps/devps/textmap: Add +h, +f, +p, Fn, Bq, bq, aq, lz. + * tty/tmac.tty-char: Likewise. + * dvi/devdvi/texmi.map: Add +h, +f, +p. + * dvi/devdvi/texi.map: Add Fn. + * dvi/devdvi/msam.map: Add lz. + * dvi/tmac.dvi: Handle Bq, bq, aq. + + * pic/lex.c (get_token): Recognize 'th. + * pic/map.y: Allow `expr'th in contexts where ORDINAL was allowed. + +Fri Jun 5 11:20:46 1992 James Clark (jjc@jclark) + + * ps/devps/textmap: Move di, mu, +- to... + * ps/devps/symbolchars: + + * macros/tmac.s (@XS): Don't call par@reset or fi. + (XA): Call LP. Turn off adjustment. Reduce line length. + + * macros/tmac.s: Initially alias XS to LP. + (XS): Rename to @XS. + (cov*ab-init): Alias XS to @XS. + +Thu Jun 4 09:12:05 1992 James Clark (jjc@jclark) + + * troff/token.h: Delete TOKEN_CHAR_HEIGHT, TOKEN_CHAR_SLANT, + TOKEN_FONT_NAME, TOKEN_FONT_POSITION, TOKEN_SIZE tokens. + (token::is_size, token::changes_env): Deleted. + * troff/number.c (parse_term): No need to process \s explicitly. + Call tok.next() only after scale indicator has been processed. + * troff/input.c (do_overstrike, do_bracket): No need to process \s, + \f etc explicitly. + (token::next): Handle \s, \f, \S, \H immediately rather than + returning them as tokens. + (token::operator==, token::description, token::add_to_node_list, + token::process): Remove handling of deleted tokens. + + * troff/env.c (environment::add_char): When adding padding + indicator character, call start_line() if necessary. + +Wed Jun 3 09:55:50 1992 James Clark (jjc@jclark) + + * ps/devps/afmtodit: Don't output 0 kerns. + + * ps/devps/afmtodit: Remove directory from name of encoding in + font description file. + + * ps/devps/afmtodit: Improve error messages. + + * ps/devps/afmtodit: Allow DESC file to be specified with -d. + + * ps/devps/Makefile: Incorporate FontMakefile. Rework. + * ps/devps/FontMakefile: Deleted. + * ps/devps/afmname: New file. + + * ps/devps/symbol.sed: New file. + * ps/devps/symbol.diff: Deleted. + * ps/devps/FontMakefile: Generate symbol.afm using symbol.sed. + Generate zapfdr.afm from zapfd.afm. + + * tty/tmac.tty (tty-char): Prefix definition with ". + + * macros/tmac.an (TP): Don't start a diversion if one has already + been started. + + * tty/tmac.tty-char: Add Latin-1 characters. + + * tty/tmac.tty-char: Incorporate suggestions from Paul Eggert. + +Tue Jun 2 00:54:34 1992 James Clark (jjc@jclark) + + * tbl/table.c (table::allocate): Delete old_vline, old_entry. + Move declaration of struct horizontal_span. + + * tbl/table.c (table::table): Initialize span_list. + (table::~table): Delete span_list. + + * lib/ptable.h (PTABLE(T)::~PTABLE(T)): Delete v. + + * ps/devps/Makefile: Avoid dependency on GNU make. + + * ps/tmac.ps: Check that character does not already exist before + defining it. + + * tty/tmac.tty: Add definitions of \(ff, \(!=, \(==, \(~=, \(sq, + \(OE, \(oe, \(AE, \(ae, \(lh, \(rh. Delete definitions of \(en, + \(ru, \(ul, \(br, \(bv, \(sl which are in the font description + files. + + * tty/tmac.tty-char: New file. + * tty/Makefile: Install tmac.tty-char. + * tty/tmac.tty: Move definitions of \(ua, \(da, \(uA, \(dA into + tmac.tty-char. + + * tty/tmac.tty: Fix definition of \(34. + + * tty/dev{ascii,latin1}/R.proto: Add ha and ti. Map + bracket-drawing characters onto |. Add *o. + + * troff/env.c (environment::wrap_up_tab): Increment field_spaces + only if current_field. + + * troff/dictionary.c (dictionary::lookup): Free old_table after + rehashing. + +Mon Jun 1 10:15:22 1992 James Clark (jjc@jclark) + + * tty/dev{ascii,latin1}/R.proto: Add uppercase Greek characters + whose glyphs are identical to glyphs of some Roman character. + + * tty/devlatin1/R.proto (bu): Deleted. + * tty/devascii/R.proto (bu): Deleted. + * tty/tmac.tty: Add definition of \(bu. + + * eqn/main.c (do_file): Pass FILE as argument. + (main): Automatically load eqnchar. New options -F and -n. + Pass do_file an opened FILE. + * groff.c: Don't pass eqnchar to eqn. Pass -F options onto eqn. + No need to include font.h. + * groff.sh: Likewise. Don't need to use - for standard input. + Prefix files with -- if first file starts with -. + + * macros/tmac.e: Conditionalize use of \$* on \n(.g. + + * troff/env.c (environment::possibly_break_line): Don't set line + to 0 across call to output_line(). Don't call output_line() until + after discarding nodes after break. + +Sun May 31 10:45:29 1992 James Clark (jjc@jclark) + + * request.h (macro::empty): Declare it. + * input.c (macro::empty): New method. + (interpolate_macro): Don't give a WARN_SPACE if the two-character + macro is empty. + +Sat May 30 10:27:15 1992 James Clark (jjc@jclark) + + * troff/env.c (environment::start_field): Decrement space_total + when a space is frozen. + +Fri May 22 14:34:38 1992 James Clark (jjc@jclark) + + * macros/tmac.an (R): Delete macro. + + * troff/input.c (get_copy, token::next): Support \# (like \" but + newline is ignored). + + * troff/input.c (token::next): Fix error message in 'Y' case. + +Thu May 21 09:26:24 1992 James Clark (jjc@jclark) + + * eqn/delim.c (define_extensible_string): Recognize any prefix of + a delimiter name. + +Fri May 15 10:20:41 1992 James Clark (jjc at jclark) + + * c++test.c: Include . + + * lib/strtol.c, lib/getcwd.c, ps/psbb.c: Declare errno in case + doesn't. + +Fri May 8 09:37:19 1992 James Clark (jjc at jclark) + + * tbl/table.c (table::divide_span): Don't count column separation + if expand was specified. + + * tbl/main.c (process_format): Don't ignore width specs in + continued format. Give warning for changing equal widths or + column separation in continued format. + (process_data): Set column separation, minimum width, equal + columns at end of table. + +Thu May 7 08:50:40 1992 James Clark (jjc at jclark) + + * troff/node.c (kern_pair_node::add_discretionary_hyphen, + node::add_discretionary_hyphen): Use soft_hyphen_char. + (set_soft_hyphen_char): New function. + (init_node_requests): Bind to shc. Initialize soft_hyphen_char. + + * Makefile (c++tested): Give more helpful message if test fails. + +Tue May 5 10:58:39 1992 James Clark (jjc at jclark) + + * troff/input.c (init_charset_table): Translate 0240 to + an unbreakable space. + + * troff/token.h (token::hyphen_indicator): New function. + * troff/charinfo.h (TRANSLATE_HYPHEN_INDICATOR): New special + translation. + * troff/input.c (translate): Allow translation to \%. + * troff/node.c (node::add_char): Handle + TRANSLATE_HYPHEN_INDICATOR. + (make_node): Don't allow TRANSLATE_HYPHEN_INDICATOR here. + + * troff/input.c (init_charset_table): Don't set BREAK_AFTER flag + for \(hy. + + * tty/devlatin1/R.proto: \(hy and - should print as 055. + +Tue Apr 21 09:24:42 1992 James Clark (jjc at jclark) + + * groff.c (run_commands): If the last command gets a SIGPIPE send + a SIGPIPE to all children than haven't yet terminated. When + command terminates, set pid field to -1. + +Fri Apr 17 11:20:48 1992 James Clark (jjc at jclark) + + * groff.c (main): Pass an appropriate -filename option to gxditview. + +Thu Apr 16 15:11:40 1992 James Clark (jjc at jclark) + + * Makefile.bd (install): Remove existing program before copying. + + * Makefile, */Makefile, Makefile.bd, groff.sh, groff.c: Allow + programs which have Unix counterparts to be installed with + user-specified prefix. + + * troff/input.c (exit_troff): Don't check if exit_started. + (exit_request): Don't call exit_troff if exit_started. + + * Makefile.bd (install.mm): Rename to install.dwbmm. + +Tue Apr 14 10:05:10 1992 James Clark (jjc at jclark) + + * driver/input.c (do_file): Add missing break for '#' case. + +Mon Apr 13 10:11:02 1992 James Clark (jjc at jclark) + + * troff/input.c (input_stack::clear): Clear past any boundaries and + then add the boundaries back. + + * troff/input.c (exit_troff): Return immediately if already + exiting. + + * macros/tmac.s (pg@end-text): New macro. Use pg@end-text for the + end macro. + (pg*end-page): If the text has ended and there are no more + footnotes or keeps, exit. + + * macros/doc-ditroff (Lq, Rq): Define as \(lq and \(rq. + + * troff/input.c (init_charset_table): Make \(rq transparent by + default. + + * macros/tmac.an: Define lq and rq strings. + + * macros/tmac.s (Q, U): Define as \(lq and \(rq. + +Sun Apr 12 12:54:37 1992 James Clark (jjc at jclark) + + * troff/env.c (environment::final_break): New function. + (environment::newline): Set prev_line_interrupted to 2 if + exit_started. + * troff/env.h: Declare environment::final_break. + * troff/input.c (exit_troff): Call environment::final_break() + instead of environment::do_break(). + + * macros/Makefile: Install man.local if $(MACRODIR)/man.local + doesn't already exist. + * macros/man.local: New file. + * macros/tmac.an: Load man.local. + * macros/man.ultrix: New file. + +Sat Apr 11 17:32:04 1992 James Clark (jjc at jclark) + + * troff/input.c (exit_groff): Rename to... + (exit_troff): New function. + + * troff/div.c (exit_started, done_end_macro, + seen_last_page_ejector): New global variables. + (began_page_in_end_macro): New static variable. + (exit_flag): Deleted. + (top_level_diversion::top_level_diversion): Initialize + last_page_count. + (top_level_diversion): More elaborate test for whether + cleanup_and_exit() should be called. + Set began_page_in_end_macro if the end macro isn't yet finished. + * troff/div.h (top_level_diversion::last_page_count): New data + member. + (top_level_diversion::set_last_page): New function. + (exit_started, done_end_macro, seen_last_page_ejector): Declare. + * troff/env.c (do_break): Zero prev_line_interrupted. + * troff/input.c (exit_flag): Delete declaration. + (LAST_PAGE_EJECTOR): New magic cookie. + (token::next): Handle LAST_PAGE_EJECTOR. + (exit_groff): Set exit_started and done_end_macro instead of + exit_flag. Call top_level_diversion::set_last_page. Push a + LAST_PAGE_EJECTOR instead of calling push_page_ejector(). Do + another ejection after setting seen_last_page_ejector. + +Thu Apr 9 04:37:11 1992 James Clark (jjc at jclark) + + * etc/grog.sh, etc/grog.sh: Recognize -me sh macro. + + * macros/tmac.e (TH): Make sure there's room for the initial + header. + + * macros/tmac.s (par@init): Make PD and DD at least \n(.V. + Set FVS in points rather than units. + +Mon Apr 6 11:21:32 1992 James Clark (jjc at jclark) + + * troff/div.c (top_level_diversion::add_trap): Don't consider the + position of empty slots. + +Fri Apr 3 10:46:45 1992 James Clark (jjc at jclark) + + * ps/devps/S: Fix height and depth of parenrightex. + * ps/devps/symbol.diff: Regenerate. + +Sat Mar 28 21:17:52 1992 James Clark (jjc at jclark) + + * tmac.e (u): Do underlining as in -mgs. + +Fri Mar 27 09:23:44 1992 James Clark (jjc at jclark) + + * tty/tty.c (tty_printer::end_page): If overstriking is + suppressed, still turn overstruck horizontal and vertical lines + into +. + + * lib/new.c: Back out Feb 24 change; no longer needed with gcc + 2.1. + + * refer/label.y (format_expr::evaluate): Avoid use of %0*d. + +Wed Mar 18 09:29:10 1992 James Clark (jjc at jclark) + + * Version 1.05 released. + +Tue Mar 17 16:50:45 1992 James Clark (jjc at jclark) + + * tty/tty.c: Instead of keeping an array of glyphs and then + sorting it, keep a ordered linked list of glyphs for each line. + + * driver/driver.h: Include stddef.h. + + * tty/tty.c (compare_glyph): + * refer/refer.c (rcompare): + * troff/env.c (compare_ranges): Arguments of qsort comparison + function should be const void *. + + * troff/number.c (parse_term): + * dvi/dvi.c (draw_dvi_printer::draw): Avoid initialization in + switch statement. + + * refer/label.y (consider_authors): Don't access variables + constructed under a condition outside that condition: put braces + round for statement containing declaration; redeclare use of same + variable later. + + * pic/pic.y (text_expr): Delete production that allows + parenthesised text_expr. + (expr): Allow a conditional_expr to appear in parentheses. + (conditional_expr): Rename to any_expr. + + * mm: Install new version 1.01 from jh. + + * lib/font.c (font::get_width): Cache scaled widths. + (font::font): Initialize widths_cache. + (font::~font): Destroy widths_cache. + * lib/font.h: Add font::widths_cache. Declare font_widths_cache. + +Mon Mar 16 10:16:10 1992 James Clark (jjc at jclark) + + * c++test.c, c++test.ref: New files. + * Makefile: Check that the C++ compiler works. + + * ps/tmac.pspic (PSPIC): Do a break. + + * ps/tmac.ps: Move definition of PSPIC into... + * ps/tmac.pspic: New file. + (PSPIC): Draw box around picture, but make it invisible to grops. + * ps/tmac.ps: Load tmac.pspic. + * ps/Makefile: Install tmac.pspic. + +Sun Mar 15 14:18:08 1992 James Clark (jjc at jclark) + + * lib/font.c (scale_round): If n is negative, + subtract .5 before truncating floating point result. + + * lib/fontfile.c: Include . + +Tue Mar 10 14:17:03 1992 James Clark (jjc at jclark) + + * driver/input.c (get_char): Inline. Don't update current_lineno. + Change callers to up date current_lineno if necessary. + Use get_char() instead of getc(current_file). + +Sun Mar 8 18:05:28 1992 James Clark (jjc at jclark) + + * ps/tmac.ps: Fix up spacing of \(mo and \(nm. + +Fri Mar 6 19:38:58 1992 James Clark (jjc at jclark) + + * tty/tty.c (tmac.tty): Define \(rg as (R). + +Tue Mar 3 10:11:25 1992 James Clark (jjc at jclark) + + * lib/lib.h: New define a_delete. + * Use a_delete instead of delete when deleting an array of objects + without destructors. + + * lib/lib.h: Rename adelete to ad_delete. + * Change uses of adelete. + +Mon Mar 2 12:41:05 1992 James Clark (jjc at jclark) + + * eqn/eqn.y: Include lib.h. + + * troff/node.c (grow_font_table): Delete old_font_table. + + * mm: Install new version from jh. + +Fri Feb 28 10:42:23 1992 James Clark (jjc at jclark) + + * tbl/table.h (format_type): Make global instead of local to class + entry_format. Prefix enumerators with FORMAT_. + * tbl/table.c, tbl/main.c: Corresponding changes. + * refer/token.h (token_type): Make global. Prefix enumerators + with TOKEN_. + * refer/token.[ch]: Corresponding changes. + * Makefile: Get rid of -DNO_NESTED_TYPES configuration option. + + * troff/div.c (node::set_vertical_size): Don't name argument. + +Thu Feb 27 10:29:19 1992 James Clark (jjc at jclark) + + * Makefile: New configuration option ARRAY_DELETE_NEEDS_SIZE. + * lib/lib.h: Define adelete accordingly. + * pic/object.c (graphic_object::graphic_object): + * tbl/main.c (format::~format): + * tbl/table.c (table::~table): + * refer/ref.c (reference::~reference, reference::merge, + reference::insert_field, reference::delete_field): Use adelete. + + * Makefile: Change NESTED_TYPES to NO_NESTED_TYPES. + * refer/token.h: + * tbl/table.h: Corresponding changes. + + * common.c (common_output::dashed_arc, common_output::dotted_arc): + Ensure total_angle is positive. + +Wed Feb 26 08:49:26 1992 James Clark (jjc at jclark) + + * refer/ref.c (reference::merge, reference::insert_field, + reference::delete_field): Avoid delete[0]. + + * refer/token.c (init_special_chars): Move calls to cmupper + outside calls to init_two_char_letter to work around bug in gcc + 2.0. + +Mon Feb 24 14:20:00 1992 James Clark (jjc at jclark) + + * lib/new.c (operator new): Use __builtin_new for g++. + + * pic/object.c (graphic_object::~graphic_object): Don't use + delete [] on 0. + + * pic/object.c (output::compute_scale): Initialize max_width and + max_height. + +Sat Feb 15 09:55:20 1992 James Clark (jjc at jclark) + + * troff/input.c (write_request): Call fflush. + + * troff/node.h (class composite_node): Move declaration to node.c + * troff/input.c (charinfo_to_node): Rename to ... + (charinfo_to_node_list): Return node list rather than composite + node. + * troff/node.c (make_composite_node): New function. + (make_node, add_char): Call make_composite_node instead of + charinfo_to_node. + (class composite_node): Add a tfont * member. Delete font_size + member. + (composite_node::composite_node, composite_node::copy, + composite_node::size): Corresponding changes. + (composite_node::tprint): Provide constant spacing, emboldening + and track kerning as specified in tfont. + (composite_node::width): Change width calculation accordingly. + * troff/env.h (environment::composite): New member. + (environment::is_composite, environment::set_composite): New + functions. + * troff/env.c (environment::environment): Initialize composite. + * troff/input.c (charinfo_to_node): Call + environment::set_composite. + * troff/node.c (make_composite_node, make_glyph_node): Use the + plain version of the tfont if the environment is composite. + + * troff/node.c (font_info::get_space_width): Additional argument + giving space_size. Handle constant space correctly. Scale by + space_size unless constant spaced. + (env_sentence_space_width): New function. + * troff/node.h: Declare it. + * troff/env.h (environment::get_space_size, + environment::get_sentence_space_size, + environment::get_narrow_space_width, + environment::get_half_narrow_space_width): Make inline. + (environment::get_space_width): Make inline. Just call + env_space_width. + * troff/env.c: Delete definitions for funtions made inline. + (environment::space_newline, environment::space): Use + env_sentence_space_width(). Don't scale by space_size. + * troff/node.h: Move declarations of env*space_width() functions + into env.h. + +Sat Feb 8 09:30:22 1992 James Clark (jjc at jclark) + + * macros/tmac.s (PS): Don't try to set negative indent. + +Thu Feb 6 09:00:35 1992 James Clark (jjc at jclark) + + * pic/pic.y: Fix min function. + +Tue Jan 28 07:52:29 1992 James Clark (jjc at jclark) + + * man/mdate.sh: Clear LANGUAGE. + +Sun Jan 19 13:02:41 1992 James Clark (jjc at jclark) + + * pic/pic.y, pic/lex.c: Rename COMMAND token to COMMAND_LINE. + * pic/lex.c: New COMMAND keyword. + * pic/pic.y (print_args, print_arg): New rules. + (placeless_element): Use print_args for PRINT. + New COMMAND element. + +Tue Jan 7 13:14:31 1992 James Clark (jjc at jclark) + + * troff/input.c (terminal): Handle missing argument correctly. + + * pic/pic.y (text_expr): New rule. + + * pic/pic.y: Implement := operator. + +Sun Jan 5 10:23:02 1992 James Clark (jjc at jclark) + + * etc/grog.pl, etc/grog.sh: Distinguish old and new versions of + mdoc. + +Sat Jan 4 14:42:26 1992 James Clark (jjc at jclark) + + * ps/devps/dingbatsrmap: Include this in the distribution. + + * macros/tmac.doc: Replace with new version from 2nd Networking + Release. Fix loading of doc-* files. + * macros/{doc-common,doc-ditroff,doc-nroff,doc-syms}: New files. + * macros/tmac.doc.old: New file. Apply fixes that had been + applied to old tmac.doc. + * macros/tmac.andoc: Check that we're running under groff. + * macros/Makefile: Rework. + +Fri Jan 3 13:27:51 1992 James Clark (jjc at jclark) + + * tbl/table.h (format_type): + * refer/token.h (token_type): If NESTED_TYPES is defined, use + typedef to make these types visible at file scope. + * Makefile: Add NESTED_TYPES configuration option. + + * troff/div.c (mark): At the top level use the value of + nl_reg_contents rather than the current vertical position. + +Thu Jan 2 10:34:51 1992 James Clark (jjc at jclark) + + * tty/tty.c: Implement \D for horizontal or vertical lines. + (tty_printer::set_char): Use vec_used+2 as serial number. + Don't allow size of vector to exceed USHRT_MAX-2. + Split off part into... + (tty_printer::add_char): New function. + (tty_printer::draw): New function. + (compare_glyph): Handle equal serial numbers. + (tty_printer::end_page): Handle overstruck characters from \D. + (main, usage): Implement -d option. + +Mon Dec 23 10:37:51 1991 James Clark (jjc at jclark) + + * tbl/main.c (process_format): + * eqn/text.c (split_text): + * troff/input.c (token::next): Use inner block for declarations + with initializers in switch statement. + +Mon Dec 16 20:52:03 1991 James Clark (jjc at jclark) + + * pic/common.c (common_output::dash_line): Cope with zero-length + lines. + +Sun Nov 17 12:04:08 1991 James Clark (jjc at jclark) + + * Version 1.04 released. + +Wed Nov 13 05:27:21 1991 James Clark (jjc at jclark) + + * macros/tmac.an (TH): Define a macro an-init to define variables + based on command line arguments. + (an-header): Call it. + +Sun Nov 3 12:07:34 1991 James Clark (jjc at jclark) + + * Makefile (install.mm): Rename to install.dwbmm. + + * Makefile: Integrate mm. + * mm: New directory. + +Wed Oct 30 10:11:34 1991 James Clark (jjc at jclark) + + * refer/dirnamemax.c: If PATHCONF_MISSING is defined, include + . + + * pic/troff.c (troff_output::simple_spline, + troff_output::simple_polygon): Rename variable `v' to `d' to avoid + shadowing parameter. + + * lib/tmpfile.c (xtmpfile): Declare dir as const char *. + + * lib/ptable.h: Add explicit casts when converting from unsigned + long to unsigned. + + * dvi/devdvi/{SA,SB,msam.map,msbm.map}: New files. + * dvi/devdvi/Makefile: Install SA, SB. + + * refer/indxbib.c: Add declaration of mktemp. + + * refer/lookbib.c: Add declaration of isatty. + +Fri Oct 25 09:00:17 1991 James Clark (jjc at jclark) + + * pic/lex.c (interpolate_macro_with_args): While collecting + arguments, keep track of whether we're in a string. + +Wed Oct 23 08:42:48 1991 James Clark (jjc at jclark) + + * ps/tmac.ps (PSPIC): Do the .sp after the \X, and move the \X + down with \v, so as to avoid problems with top of page trap + setting no space mode. + +Tue Oct 22 17:38:49 1991 James Clark (jjc at jclark) + + * eqn/lex.c (get_delimited_text): Allow tab before macro body. + +Tue Oct 15 17:24:53 1991 James Clark (jjc at jclark) + + * ps/psrm.c (ps_get_line): Fix bug when lines longer than 255. + Improve error message. + +Fri Oct 11 11:09:38 1991 James Clark (jjc at jclark) + + * ps/psrm.c (print_ps_string): Don't pass negative numbers to + printf("%03o"); + +Wed Oct 9 17:50:14 1991 James Clark (jjc at jclark) + + * groff.c (possible_command::execp): Always use _exit() after a + failed exec. + + * Makefile: Add HAVE_UNION_WAIT, HAVE_PID_T, WAIT_COREDUMP_0200, + NO_SYS_WAIT_H configuration options. + * groff.c: Use these options. Use POSIX-style macros to extract + fields from the status returned by wait(). + +Fri Oct 4 12:12:27 1991 James Clark (jjc at jclark) + + * tbl/table.c (table::compute_separation_factor): Allow the + separation factor to drop to 0. + +Tue Oct 1 18:12:38 1991 James Clark (jjc at jclark) + + * refer/search.c: Include . + +Sun Sep 29 08:40:57 1991 James Clark (jjc at jclark) + + * pic/pic.y (YYDEBUG): Don't define for Borland C++. + + * lib/lib.h: #ifdef out declarations of itoa and iftoa for Borland + C++. + + * pic/lex.c (input_stack::bol): Move definition out of class body. + + * pic/main.c: On MSDOS munge argv[0]. + + * lib/ptable.h: Define name2 as _Paste2 for Borland C++. + + * lib/ptable.c (hash_string): Use unsigned long rather than + unsigned. + (next_ptable_size): Use unsigned rather than int. Give an error + message if we've hit the largest table size. + * lib/ptable.c: Corresponding changes. Also use unsigneds for the + table size. + + * pic/object.h (object_spec): Make flags unsigned long. Declare + flags as const unisgned long rather than as enums. + + * pic/output.c: Deleted. + + * pic/troff.c (troff_output::simple_ellipse): Remove spurious %. + + * tbl/table.c (simple_entry::note_double_vrule_on_{left,right}): + Add additional argument. + (line_entry::note_double_vrule_on_{left,right}): Set value of + douvle_vrule_on_{right,left} flag according to argument. + (simple_line_entry::simple_print, + simple_line_entry::double_line_print): If adjacent to double vrule + on a corner extend rather than shorten the rule by half the double + vrule sep. + + * troff/number.c (parse_term): In checking for overflow, handle the + case where the current horizontal position is negative. + +Thu Sep 12 08:26:09 1991 James Clark (jjc at jclark) + + * pic/object.c (draw_arrow): Check for object having zero length. + +Wed Sep 11 10:32:38 1991 James Clark (jjc at jclark) + + * eqn/main.c (do_file): Split off inline equation handling into... + (inline_equation): New function. Search for starting delimiter + using... + (delim_search): New function. Don't recognize a delimiter that + occurs in the name of an escape sequence, number register, string + etc. + +Tue Sep 10 04:01:11 1991 James Clark (jjc at jclark) + + * eqn/delim.c (delim_box::compute_metrics): Don't call + define_extensible_string if left is 0. + (delim_box::output): Don't print the left delimiter if left is 0. + (delim_box::debug_print): Check for left == 0 before calling printf. + +Fri Aug 23 13:02:30 1991 James Clark (jjc at jclark) + + * troff/Makefile (majorminor.c): Include only digits in + minor_version. + +Thu Aug 22 09:35:37 1991 James Clark (jjc at jclark) + + * refer/dirnamemax.c: new file. + * refer/genlimits.c: Deleted. + * refer/indxbib.c (main): Use dir_name_max() instead of NAME_MAX. + Don't check path length. + * refer/Makefile: Add dir_name_max.o; delete genlimits. + * Makefile: Add PATHCONF_MISSING option. + + * refer/indxbib.c (get_cwd): New function. + (main): Use get_cwd(). + * lib/getcwd.c: New file. + * Makefile: Delete -DHAVE_GETWD. Include GETCWD variable. Pass + GETCWD in SUBFLAGS. + * lib/Makefile: Compile getcwd.o. + + * ps/tmac.psatk (psatk-defs): Define showpage after pushing + userdict. + + * refer/indxbib.c (main): Check success of mktemp. + + * lib/tmpfile.c: New file. + * lib/Makefile: Add tmpfile.c. + * lib/lib.h: Declare xtmpfile(); include . + * ps/ps.h: Delete declaration of mktemp(). + * ps/ps.c (ps_printer::ps_printer): Use xtmpfile(). + * refer/refer.c (divert_to_temporary_file): Use xtmpfile(). + * driver/driver.h: No need now to include errno.h. + + * everywhere: Set errno to 0 before calling fopen(). + + * eqn/eqn.h, etc/soelim.c, driver/driver.h, etc/addftinfo.c, + dvi/tfmtodit.c, groff.c, refer/index.c, refer/linear.c, + refer/lookbib.c, refer/refer.h, ps/psbb.c: Include . + +Mon Aug 19 10:52:18 1991 James Clark (jjc at jclark) + + * troff/env.h (translate_space_to_dummy): Declare it. + * troff/env.c (environment::space_newline, environment::space): + If translate_space_to_dummy is set then make the width of spaces 0. + * troff/input.c (translate): If the second character of a + translation is a space, translate to unbreakable space. If the + first character is a space, set or clear translate_space_to_dummy + according to whether the second character is \&. Weird! + +Tue Jul 30 10:03:56 1991 James Clark (jjc at jclark) + + * groff.c (run_commands): Don't use non-zero exit code because a + command gets SIGPIPE. + + * groff.c, groff.sh: Use -mXps with -TXps. + + * ps/ps.c (ps_printer::special): Move call to flush_sbuf() into... + (ps_printer::do_exec, ps_printer::do_file, ps_printer::do_def, + ps_printer::do_mdef, ps_printer::do_import): Call flush_sbuf(). + (ps_printer::special): New specials invis and endinvis. + (ps_printer::do_invis, ps_printer::do_endinvis): New functions. + (ps_printer::set_char, ps_printer::draw): Return if invis_count>0. + (ps_printer::end_page): Check that invis_count == 0. + (ps_printer::invis_count): New member. + (ps_printer::ps_printer): Initialize invis_count to 0. + + * troff/env.c (environment::hyphenate_line): Hyphenation + indicator at beginning of word inhibits splitting after -, \(em + etc. + + * pic/pic.y (element): Allow another element to follow } without + any intervening separator. + +Mon Jul 22 12:27:37 1991 James Clark (jjc at jclark) + + * pic/lex.c (get_delimited): Allow tabs before delimiter. + +Wed Jul 17 10:59:08 1991 James Clark (jjc at jclark) + + * groff.c: Get rid of HAVE_UNION_WAIT stuff. Instead suppress + declaration of wait() in header files. + * Makefile: Get rid of -DHAVE_UNION_WAIT. + + * tbl/table.c (alphabetic_text_entry::add_tab): New function. + + * lib/lib.h: Declare return type of strerror as char *. + + * man/Makefile: Add g flag to sed substitutions. + * Makefile (shgroff, bindist): Likewise. + +Sun Jul 14 11:57:02 1991 James Clark (jjc at jclark) + + * ps/ps.c (ps_printer::do_import): Move push of userdict into... + * ps/devps/prologue (PBEGIN): Define showpage after pushing + userdict. + +Sat Jul 13 20:53:04 1991 James Clark (jjc at jclark) + + * ps/devps/prologue (PBEGIN): Zap any definition of showpage in + userdict. + +Fri Jul 12 07:10:09 1991 James Clark (jjc at jclark) + + * man/mdate.sh: Handle the fact that BSD ls -l does not print the + group. + +Sun Jul 7 08:00:23 1991 James Clark (jjc at jclark) + + * troff/input.c (define_number_reg): If currently undefined, + don't define it if the argument is an invalid expression. + + * Makefile: Ignore return value of `if' commands without `else' + parts. + + * Makefile: Split up CPPDEFINES into a series of separate + configuration options. + + * troff/input.c (init_registers): Use time_t instead of long + unless LONG_FOR_TIME_T is defined. Use returned result rather + than passing pointer. + * Makefile: Document LONG_FOR_TIME_T as a CPPDEFINE. + + * lib/Makefile (fontpath.h): Use gendef. + +Thu Jul 4 09:48:05 1991 James Clark (jjc at jclark) + + * troff/input.c (input_iterator::shift): Delete argument name. + * troff/node.c (suppress_output_file::really_begin_page, + suppress_output_file::really_transparent_char, node::ascii_print, + node::tprint): Delete names of unused arguments. + +Wed Jul 3 17:34:57 1991 James Clark (jjc at jclark) + + * refer/label.y (string): Pass $4 to command_error. + +Tue Jul 2 15:06:01 1991 James Clark (jjc at jclark) + + * Version 1.03 released. + +Sat Jun 29 08:14:01 1991 James Clark (jjc at jclark) + + * Makefile: Pass definition of SHELL in SUBFLAGS. + + * gendef: New file. + * Makefile, eqn/Makefile, refer/Makefile, troff/Makefile, + ps/Makefile: Use gendef to construct header files that are + constructed from the Makefile. + + * macros/Makefile: make all should build stripped version of tmac.e. + + * refer/Makefile (clean): Remove y.output. + +Fri Jun 28 09:44:36 1991 James Clark (jjc at jclark) + + * ps/pfbtops.c (main): Add -v option which prints out a version + number. + * ps/Makefile (pfbtops): Link with libgroff.a. + +Fri Jun 21 07:43:23 1991 James Clark (jjc at jclark) + + * refer/search.h (linear_searcher::get_nkeys): Delete declaration. + * refer/linear.c (linear_searcher::get_nkeys): Delete definition. + + * refer/lkbib.c (main): Always terminate reference with blank + line. + * refer/lookbib.c (main): Likewise. + + * refer/linear.c (file_buffer::load): Check that the file is not a + binary file. + + * refer/Makefile (genlimits): Possibly add -DHAVE_SYS_DIR_H. + (genlimits.c): Include if HAVE_SYS_DIR_H is defined. + Delete second inclusion of . + +Tue Jun 18 01:32:26 1991 James Clark (jjc at jclark) + + * troff/token.h (token::special): Deleted. + + * tbl/main.c (process_format): Rework so that opt->tab_char is + recognized only when appropriate. + + * ps/Makefile (clean): Remove pfbtops. + +Sun Jun 16 09:37:19 1991 James Clark (jjc at jclark) + + * lib/font.c (text_file::next): Don't return if we have got a + blank line. + +Fri Jun 14 09:52:26 1991 James Clark (jjc at jclark) + + * refer/refer.c (store_reference): Get hash code from old_table[i] + when rehashing the table. + +Thu Jun 13 01:26:43 1991 James Clark (jjc at jclark) + + * eqn/box.c (box::top_level): Save size and prev size using \R and + restore it afterwards. Set the size to the size at the beginning + of the line. + * eqn/pbox.h: Declare SAVED_INLINE_PREV_SIZE_REG, + SAVED_INLINE_SIZE_REG, and SAVED_SIZE_REG. + + * refer/Makefile (limits.h): Use ./genlimits. + +Wed Jun 12 16:05:34 1991 James Clark (jjc at jclark) + + * refer/index.c: Delete declarations of stat() and fstat(). + +Tue Jun 11 14:52:49 1991 James Clark (jjc at jclark) + + * tty/tmac.tty: Add character definitions for \(>= and \(<=. + +Mon Jun 10 22:49:48 1991 James Clark (jjc at jclark) + + * etc/grog.sh, etc/grog.pl: Change regex for .PS. + +Fri Jun 7 09:13:06 1991 James Clark (jjc at jclark) + + * troff/input.c (token::get_char): Handle \e. + + * refer/linear.c: Delete declarations of fstat() and stat(). + +Wed Jun 5 09:11:59 1991 James Clark (jjc at jclark) + + * troff/node.c, troff/env.c, troff/input.c, Makefile: Remove + OP_DELETE_BROKEN stuff, since we now have a fix for g++. + +Mon Jun 3 13:41:32 1991 James Clark (jjc at jclark) + + * troff/input.c (do_define_macro): Improve error handling for end + of file while defining macro. + +Sun Jun 2 10:20:24 1991 James Clark (jjc at jclark) + + * eqn/box.h: Fix declaration of set_gsize. + * eqn/box.c (set_gsize): Make argument const char *. + (gsize): Declare as char *. + * eqn/main.c (main): Don't convert gsize to int. + * eqn/lex.c (do_gsize): Pass char * to set_gsize. + + * Version 1.02 released. + +Sat Jun 1 12:19:46 1991 James Clark (jjc at jclark) + + * macros/tmac.andoc: New file. + * macros/Makefile: Install tmac.andoc. + + * troff/node.c, troff/env.c, troff/input.c: Conditionalize use of + operator new and delete on OP_DELETE_BROKEN not being defined. + * Makefile: Mention OP_DELETE_BROKEN. + +Mon May 27 13:49:07 1991 James Clark (jjc at jclark) + + * Makefile (bindist): Pass SUBFLAGS. + +Sun May 26 14:13:22 1991 James Clark (jjc at jclark) + + * Makefile, groff.c: Pass definitions to groff.c via device.h. + + * tty/tty.c (tty_font::load_tty_font): Avoid shadowing + parameter. + + * ps/Makefile, ps.c: Pass BROKEN_SPOOLER_FLAGS via broken.h. + + * ps/ps.h, ps/psrm.c: Make comment_table and + header_comment_table local to resource_manager::process_file. + + * groff.sh: With -TXps pass -printCommand option to gxditview. + + * groff.c (possible_command::print): Implement using + append_arg_to_string. + + * xditview: Merge in new implementation with own ChangeLog. + +Sat May 25 18:33:20 1991 James Clark (jjc at jclark) + + * groff.c (main): Implement PRINT_OPTION. + (append_arg_to_string): New command. + (device_table): Set PRINT_OPTION flag for Xps. + +Fri May 24 09:48:58 1991 James Clark (jjc at jclark) + + * troff/groff.h: Rename to troff.h. + + * pic/lex.c (lookup_keyword, docmp): New functions. + (get_token): Use new lookup_keyword. + Don't include key.h. + * pic/key.[ch], pic/pic.gperf: Deleted. + * pic/Makefile: Remove gperf stuff. + + * pic/Makefile, pic/output.h: Move definition of TEX_SUPPORT + into output.h. + * pic/tex.c: Move include of pic.h before test of TEX_SUPPORT. + + * troff/Makefile, troff/node.c: Move definition of + STORE_WIDTH into node.c. + + * etc/grog.pl, etc/grog.sh: Support -mdoc. + +Thu May 23 12:30:49 1991 James Clark (jjc at jclark) + + * dvi/devdvi/texr.map, dvi.devdvi/texi.map, + dvi/devdvi/texb.map: Add lq and rq. + dvi/devdvi: Regenerate fonts. + * ps/devps/textmap: Add lq and rq. + * ps/devps: Regenerate fonts. + * tty/devascii/R.proto, tty/devlatin1/R.proto: Add lq and rq. + * macros/tmac.e: Define \*(lq and \*(rq to be \(lq and \(rq. + + * pic/object.c (position_rectangle): When checking radius + cope with possiblity that width or height is negative. + (box_object::box_object): Have separate xrad and yrad with + signs matching signs of dim components. + (box_object::{north,south}_{east,west}): Use xrad and yrad. + (box_object::print): With rounded boxes use absolute values + for dim and rad arguments. + + * lib/Makefile, lib/fontfile.o: Pass definition of FONTPATH + in fontpath.h. + + * eqn/Makefile, eqn/main.c: Pass definition of DEVICE in device.h. + + * various files: Add explicit destructors to keep Saber CC +d + happy. + +Wed May 22 11:37:11 1991 James Clark (jjc at jclark) + + * eqn/box.c (box::top_level): Restore fonts correctly after + font changes in line containing inline equation. Also + restore previous font as well as current font. + * eqn/pbox.h: Define necessary string and register names. + + * troff/input.c (token::next): Case 'R' calls do_register. + (do_register): New function. + +Tue May 21 11:28:23 1991 James Clark (jjc at jclark) + + * groff.c, groff.sh: Support Xps device. Allow each device + to have a pseudo_name and a real_name. + + * groff.c (run_commands): Don't print `Broken pipe' messages. + + * ps/pfbtops.c: New file. + * ps/Makefile: Add pfbtops. + + * troff/number.c (parse_term): Improved error message. + +Mon May 20 11:22:14 1991 James Clark (jjc at jclark) + + * groff.c, groff.sh, etc/grog.sh, etc/grog.pl: Support grefer. + + * Makefile: Integrate refer. + * refer: New directory. + * man/grefer.man, man/glookbib.man, man/gindxbib.man, + man/lkbib.man: New files. + * man/Makefile: Support refer man pages. + + * lib/lib.h: Declare is_prime. + * lib/prime.c: New file. + + * troff/input.c (macro_source): New function. + (init_input_requests): Bind "mso" to macro_source. + + * troff/env.c (environment::possibly_break_line): Maintain + pointer to pointer to node to be split in ndp so as to avoid + using address of freed node. + + * troff/env.c (environment::hyphenate_line): Maintain pointer to + pointer to first node to be hyphenated in startp so as to + avoid using address of freed node. + + * troff/env.c (class trie, class hyphen_trie): Make the + elements of the trie be of type char not unsigned char. + Declare arguments to be const char* instead of unsigned char *. + + * troff/env.c (hyphenate): Initialize hbuf[0]. + + * troff/input.c (set_string): Declare p to be char * and cast + *p to unsigned char when necessary. + + * troff/input.c (do_define_macro): Declare s to be const + char*. Cast element to unisgned char when necessary, Declare + d to be an int. Handle EOF better. + + * troff/Makefile, troff/input.c: Different scheme for passing + definitions of MACROPATH, HYPHENFILE and DEVICE. + +Tue May 14 13:41:36 1991 James Clark (jjc at jclark) + + * tty/devascii/R.proto: Delete entry for em. + * tty/devlatin1/R.proto: Likewise. + +Sat May 11 11:13:28 1991 James Clark (jjc at jclark) + + * troff/input.c (translate): Stop when we get a space. Treat eof + like newline. + + * macros/tmac.an (IP): Only pass quoted argument to TP when \n(.$>1. + +Wed Apr 24 19:24:33 1991 James Clark (jjc at jclark) + + * tbl/main.c (process_format): A font name following a `f' + modifier that starts with a digit can be only one character long. + Also deal with EOF on the second character of the font name. + +Wed Apr 17 11:23:43 1991 James Clark (jjc at jclark) + + * troff/input.c (token::next): Turn \~ into an + unbreakable_space_node. + * troff/node.c (unbreakable_space_node): New class. + * troff/node.h: Declare it. + +Tue Apr 16 10:47:12 1991 James Clark (jjc at jclark) + + * dvi/dvi.c (dvi_printer::set_char): Make code an int. Check that + it's >= 0, before outputting it as a single byte. + +Mon Apr 15 11:20:23 1991 James Clark (jjc at jclark) + + * lib/font.c: Make font_char_metric::code an int. + (font::get_code): Change return type to int. + (font::load): Allow code to be arbitrary integer. + * lib/font.h (font::get_code): Change return type to int. + (font::number_to_index): Change argument type to int. + * troff/input.c (token::next): In case 'N', allow any value. + Store value in token::val. + (token::operator==): For TOKEN_NUMBERED_CHAR test equality of val. + (token::get_char, token::add_to_node_list, token::process): Get + number from val. + (charinfo::set_number): Change argument to int. + (charinfo::get_number): Require that NUMBERED flag be set. + (get_charinfo_by_number): Store numbered characters not between 0 + and 255 in a dictionary. + * troff/charinfo.h (get_charinfo_by_number): Change argument type + to int. + (charinfo::number): Change type to int. + (charinfo::set_number): Change type of set_number to int. + * troff/node.c (troff_output_file::put_char_width, + troff_output_file::put_char): Test whether character is numbered + using charinfo::numbered(). + * driver/printer.c (printer::set_numbered_char): Allow arbitrary + values of num. + * lib/nametoindex.c: New implementation to cope with arbitrary + number characters. + + * troff/input.c (token::operator==): Test val for + TOKEN_CHAR_HEIGHT, TOKEN_CHAR_SLANT, TOKEN_FONT_POSITION, and + TOKEN_SIZE. + + * man/Makefile: Add definiton of BROKEN_SPOOLER_FLAGS. + (.man.n): sed out @BROKEN_SPOOLER_FLAGS@. + +Sun Apr 14 12:57:00 1991 James Clark (jjc at jclark) + + * ps/devps/zapfdr.ps: Don't copy UniqueID. Avoid use of newdict + variable. + + * all Makefiles: rm targets of cp and >. + + * xditview/xtotroff.c (MapFont): Unlink troff_name before opening + it. + + * eqn/lex.c (def_table): Add dollar. + +Sat Apr 13 13:02:44 1991 James Clark (jjc at jclark) + + * troff/input.c (do_width): Push back newline before closing delim + like do_bracket. + +Fri Apr 12 15:16:03 1991 James Clark (jjc at jclark) + + * groff.c (possible_command::prepend_arg): New function. + (main): Prepend device -m option. + * groff.sh: Put device -m options before command-line options. + +Tue Apr 9 10:24:43 1991 James Clark (jjc at jclark) + + * macros/tmac.an (IP): Quote argument to TP. + + * ps/ps.c (main): New option -b, which sets... + (broken_flags): New variable. + (ps_printer::~ps_printer): Incorporate the setup section in the + prolog if (broken_flags & NO_SETUP_SECTION). + (ps_printer::begin_page): Generate {Begin,End}PageSetup comments. + (ps_printer::merge_download_fonts, ps_printer::merge_import_fonts, + ps_printer::merge_ps_fonts, ps_printer::print_font_comment, + ps_printer::print_needed_font_comment, + ps_printer::print_supplied_font_comment, + ps_printer::print_include_font_comments, + ps_printer::lookup_doc_font, ps_printer::download_fonts, + ps_printer::read_download_file, read_document_fonts, add_font, + skip_line, parse_fonts_arg, document_font::document_font, + document_font::~document_font, document_font::download, + ps_output::include_file): Deleted. + (ps_printer::~ps_printer): Generate %%EOF. Generate %!PS-Adobe-3.0 + rather than %!PS-Adobe-2.0. Make calls to + resource_manager::need_font for each font that we used. Replace + calls to merge_ps_fonts, merge_download_fonts, print_font_comment, + print_supplied_font_comment, print_needed_font_comment by call to + resource_manager::print_header_comments. Output %%Orientation + comment. Output %%Requirements: numcopies comment if ncopies > 1. + Don't output the prolog directly. Instead call + resource_manager::output_prolog. Only define #copies when ncopies + > 1. Delete calls to print_include_font_comments and + download_fonts. Add call to resource_manager::document_setup. + (ps_printer::do_file): Call resource_manager::import_file instead + of including it ourselves. + (ps_printer::do_import): Likewise. Also don't call + merge_import_fonts. Push userdict on the dictionary stack before + and pop it afterwards. + Move declaration of ps_output into ps.h. + * ps/psrm.c: New file implementing resource_manager class. + * ps/ps.h: New file declaring ps_output and resource_manager + classes. + * ps/devps/zapfdr.ps: + * ps/devps/symbolsl.ps: + * ps/devps/prologue: Use 3.0 conventions. + * ps/Makefile: Pass definition of BROKEN_SPOOLER_FLAGS in DEFINES. + Add default definition of BROKEN_SPOOLER_FLAGS. + * Makefile: New variable BROKEN_SPOOLER_FLAGS. Add + BROKEN_SPOOLER_FLAGS to SUBFLAGS. + +Mon Apr 8 09:26:54 1991 James Clark (jjc at jclark) + + * etc/grog.pl: New file. + * Makefile (GROG): New variable. + Add GROG to SUBFLAGS. + * etc/Makefile (GROG): New variable. + (install.nobin): Install $(GROG) rather than grog.sh. + +Thu Apr 4 11:36:45 1991 James Clark (jjc at jclark) + + * eqn/special.c (special_box::compute_metrics): Make the input and + output strings the same. Get the new height and depth from the + predefined height and depth registers. Also make subscript kern + and skew available. + (special_box::compute_subscript_kern, special_box::compute_skew): + New functions. + + * eqn/box.c (pointer_box::compute_skew, + simple_box::compute_metrics, box::top_level) + * eqn/text.c (prime_box::compute_metrics, + prime_box::comput_subscript_kern) + * eqn/limit.c (limit_box::compute_metrics): + * eqn/delim.c (build_extensible, delim_box::compute_metrics): + * eqn/sqrt.c (sqrt_box::compute_metrics): Protect possibly + negative numbers in `nr' requests with a leading 0. + +Wed Apr 3 15:58:23 1991 James Clark (jjc at jclark) + + * eqn/special.c: New file. + * eqn/eqn.y: Declare token SPECIAL. Make it right associative. + Add new rule for simple. + * eqn/lex.c (token_table): Add SPECIAL. + * eqn/box.h: Declare make_special_box. + * eqn/Makefile: Add special.[co]. + +Sat Mar 30 10:57:53 1991 James Clark (jjc at jclark) + + * ps/devps/prologue: Possibly set packing to true while defining. + Create grops dictionary here. Initialize local variables before + defining procedures. + (PICTURE): Rename to PBEGIN. Also do save, noop showpage, count + the dictionary stack. Set strokeadjust and overprint to false if + the relevant operators are defined. + (PEND): New procedure. + * ps/ps.c (ps_printer::~ps_printer): In the prolog just include + prologue. Do everything else in the setup section. + (ps_printer::do_import): Just call PBEGIN and PEND around the + picture. Also push userdict before, and pop it afterwards. + +Wed Mar 27 07:59:50 1991 James Clark (jjc at jclark) + + * troff/node.c (bracket_node::tprint): Brackets were being printed + 1m too low. + + * macros/tmac.an (SH, SS): Set fill mode. + +Tue Mar 26 07:46:31 1991 James Clark (jjc at jclark) + + * troff/div.c (top_level_diversion::begin_page): Set + high_water_mark to 0. + +Fri Mar 22 09:19:46 1991 James Clark (jjc at jclark) + + * man/mdate.sh: New file. + * man/mdate.c: Deleted. + * man/Makefile: Use mdate.sh instead of mdate. + (mdate): Deleted. + + * eqn/lex.c (do_gsize): Supply missing argument to error message. + +Tue Mar 19 11:06:50 1991 James Clark (jjc at jclark) + + * man/mdate.c: New file. + * man/*.man: Replace modification date by @MDATE@. + * man/Makefile (.man.n): Replace @MDATE@ by `mdate $<`. + (mdate): New target. + + * lib/font.c (text_file::next): Deal with arbitrarily long lines. + Remove illegal input characters. + +Mon Mar 18 08:32:25 1991 James Clark (jjc at jclark) + + * macros/tmac.s (pg*start-col): Do .ns *after* running the hooks. + +Sat Mar 16 03:52:25 1991 James Clark (jjc at jclark) + + * troff/div.c (begin_page): Change behaviour when + !first_page_begun and !break_flag. + + * troff/input.c (do_name_test): Return 0 if argument is empty. + + * troff/input.c (read_long_escape_name): Require closing ] to be + at same input level as opening [. + + * troff/input.c (read_increment_and_escape_name): New function. + (get_copy, process_input_stack): Use this for \n. + +Fri Mar 15 00:31:48 1991 James Clark (jjc at jclark) + + * troff/div.c (top_level_diversion::begin_page): Ignore the + current value of page_number if !first_page_begun. + + * groff.c (main): Fix declaration of buf. + + * troff/input.c (do_name_test): New function. + (token::next): Implement \A. + (token::next): Implement \e by turning it into a TOKEN_ESCAPE. + (token::description, token::add_to_node_list, token::process): + Handle TOKEN_ESCAPE. + * troff/token.h: New token TOKEN_ESCAPE. + +Thu Mar 14 10:22:26 1991 James Clark (jjc at jclark) + + * pic/main.c (do_picture): Allow space before and after filename + following `<'. Check that the filename is not empty. + +Wed Mar 13 12:49:40 1991 James Clark (jjc at jclark) + + * Version 1.01 released. + + * dvi/devdvi/CompileFonts: Add cm*ss10 fonts. + + * dvi/tmac.dvi: ftr HR to H. + + * macros/tmac.e: Round up computation of $r. + + * xditview/tmac.X: Don't give up completely in compatibility mode. + Use \n(.s instead of \n[.s]. + + * dvi/tmac.dvi: Don't give up completely in compatibility mode. + Use \(ci instead of \[ci]. Use \n(.s instead of \n[.s]. + Add u to factors inside \s[...]. Rename frac to dvi-frac. + Translate \(FM onto \[prime] and \(!/ onto \[slashnot]; use these + short names in the char definitions. + + * ps/tmac.ps: Don't give up completely in compatibility mode. + Fix the fraction definitions to use \n(.s and \(f/. Add an extra + quote in front of \n(.s. Add u to factors inside \s[...]. + +Mon Mar 11 12:01:20 1991 James Clark (jjc at jclark) + + * tty/tmac.tty: Call the nroff request. + + * macros/tmac.e ((x, )x): Better definitions that work properly + in a diversion. + (@0, @1): Helper macros for (x. + + * macros/tmac.e ($s, hl): Use \l rather than \D. + + * tty/tmac.tty: Make it work better in compatibility mode. + (pchar): Rename to tty-char. + + * macros/tmac.e (@E): New macro. + (r, i, b, rb, bi): Use @E. + + * macros/tmac.e (@F): Don't use (;...) syntax. + + * macros/tmac.e: Remove mention of \*(||/revisions. Mention that + it was modified for groff. + + * macros/tmac.e: Make sure \n(ps and \n(es are >= \n(.V. + + * macros/tmac.e (<., .>): Removed. + ([., .]): If \n(.V>=1v, use [] instead of superscripting. + + * macros/tmac.e: Remove check that groff is being used. + + * macros/tmac.e (@C): Change families only if using groff; turn + compatibility mode off while changing familes. Save compatibility + mode before changing families and restore it afterwards. + + * macros/tmac.e (@h): Remove test for offset + line length. + + * macros/tmac.e (sorry): Rename to @S. Use \$1 instead of \$0 + (lo, th, ac): Define to call @S instead of using als. + + * macros/tmac.e: Make $r and $R now contain \n(.v*100/\n(.sp, ie + the ratio of the vertical spacing to the point size in units + expressed as a percentage. Use these instead of $10r and $10R, + Delete $10r and $10R. + + * lib/font.c (font::load): In default computation of space_width, + divide by sizescale. Use scale_round. + + * macros/tmac.an (TP): Don't call `nf'. + (an-do-tag): Don't call `fi'. + +Sun Mar 10 09:52:35 1991 James Clark (jjc at jclark) + + * troff/input.c (process_input_stack): Handle the case where + spaces at the beginning of an input line are followed by a + newline. + +Thu Mar 7 20:18:07 1991 James Clark (jjc at jclark) + + * groff.c (device_table): Add PIC_X_OPTION for dvi device. + * groff.sh: Use pic -x with the dvi device. + + * dvi/devdvi/FontMakefile (H): Don't use -s. + + * dvi/devdvi/HI, dvi/devdvi/HB: New files. + * dvi/devdvi/Makefile: Add HI and HB to FONTS. + * dvi/devdvi/FontMakefile: Add rules for HI and HB. Include these + in FONTS. + +Mon Mar 4 13:20:14 1991 James Clark (jjc at jclark) + + * ps/psfig.diff: New file. + * ps/tmac.psfig: New file. + +Sat Mar 2 00:15:09 1991 James Clark (jjc at jclark) + + * macros/tmac.s (]=, ref*do-tl, ref*bib-print): Deleted. + (]-): Don't call ref*do-tl. + + * macros/tmac.s (ref*end-print): Use XP if [F not defined. + + * macros/tmac.s (ref*normal-print): Call FS rather than fn@do-FS. + (fn@do-FS): Rename to fn*do-FS. + + * troff/input.c (transparent_translate): New function. + (process_input_stack): Apply transparent_translate before calling + diversion::transparent_output(unsigned char). + +Wed Feb 27 00:13:25 1991 James Clark (jjc at jclark) + + * troff/input.c (do_define_macro): Define the macro before calling + skip_line. + + * xditview/Makefile: Add DEVICES variable. Change install target + to use this. + +Tue Feb 26 10:46:22 1991 James Clark (jjc at jclark) + + * groff.c (run_commands): Handle the possibility that there are + child processes other than those forked by us. + +Sun Feb 24 21:32:30 1991 James Clark (jjc at jclark) + + * lib/string.c (string::append): New function. + * lib/stringclass.h: Declare it. + +Thu Feb 21 11:49:26 1991 James Clark (jjc at jclark) + + * eqn/main.c (main): New option -N which sets + no_newline_in_delim_flag. + (do_file): If no_newline_in_delim_flag is set don't allow newlines + in delimiters. + * groff.c (main): Pass -N on to eqn. + (help, synopsis): Mention -N. + * groff.sh: Implement -N. + +Wed Feb 20 15:16:10 1991 James Clark (jjc at jclark) + + * macros/tmac.s (]=, ref*bib-print, ref*do-tl): New macros. + (]-): Call ref*do-tl if ref*need-tl is non-zero. + (XP): Allow as initializer. + +Tue Feb 19 14:09:06 1991 James Clark (jjc at jclark) + + * troff/env.c (environment::wrap_up_field): If field_spaces are + non-zero and we have a current_tab, subtract padding from + tab_distance. If this makes tab_distance <= 0, use the next tab + stop instead. If there isn't any next tab or it's a left tab, + wrap up the current tab. + (environment::start_field): Initialize tab_precedes_field. + (environment::wrap_up_tab): If there's a current field, update + pre_field_width, field_distance and tab_precedes_field. + * troff/env.h (environment::tab_precedes_field): New member. + +Fri Feb 15 01:24:00 1991 James Clark (jjc at jclark) + + * ps/ps.c (ps_printer::do_file): New function. + (ps_printer::special): Bind to `file' special. + (ps_printer::do_exec): Set ndefined_styles to 0. + +Sat Feb 9 03:03:04 1991 James Clark (jjc at jclark) + + * eqn/text.c (split_text): Grok \* and similar escapes sequences. + Avoid stripping first character from the start of unrecognized + escapes. Use lex_error instead of error to report errors. + * eqn/lex.c (get_token): Rework handling of escapes. + (lex_error): Move declaration into... + * eqn/eqn.h. + + * xditview/xditview.c (main): Make -page option work. + + * Makefile: Correct comment about -DBROKEN_SPOOLER and pageview. + +Wed Feb 6 12:28:43 1991 James Clark (jjc at jclark) + + * macros/tmac.s (B2): Correct size of box. + +Tue Feb 5 00:37:35 1991 James Clark (jjc at jclark) + + * macros/tmac.s (B2): Postpone drawing the box until in the + top-level diversion. + + * tty/tmac.tty: Add font translations for C, CR, CW. + + * groff.c (synopsis, help): Document -i. + * groff.sh: Implement -i. + + * macros/tmac.s (@NH): Put a `.' after multi-part numbers. + Simplify the construction of SN. + + * troff/number.c (parse_term): Give `|' a higher precedence. + * tbl/table.c (numeric_text_entry::simple_print): Parenthesise + accordingly. + + * macros/tmac.s (B2): Use par@finish instead of par@reset. + +Mon Feb 4 12:36:09 1991 James Clark (jjc at jclark) + + * lib/string.c (string::move): New function. + * lib/stringclass.h: Declare it. + +Sat Feb 2 16:02:16 1991 James Clark (jjc at jclark) + + * troff/env.c (distribute_space): Add optional argument + `force_forward'. + (environment::wrap_up_field): Call distribute_space with + `force_forward' argument of 1. + +Fri Feb 1 19:36:33 1991 James Clark (jjc at jclark) + + * lib/string.c, lib/stringclass.h (string::operator+=(char)): + Inline it. Move reallocation into... + (string::grow1): New function. + * pic/Makefile, tbl/Makefile, eqn/Makefile, ps/Makefile: Redo + dependencies to include library header files. + * lib/Makefile: Make string.c and lf.c depend on stringclass.h. + +Thu Jan 31 15:02:27 1991 James Clark (jjc at jclark) + + * macros/tmac.s (@NH): Use the same number registers than -ms does + for the heading level counters. Use the same string that -ms does + for the number for this heading. + +Wed Jan 30 14:25:40 1991 James Clark (jjc at jclark) + + * lib/new.c (operator new): Cast result of malloc to char *. + + * troff/input.c (spring_trap, lookup_request): Add assert that nm + is not null. + +Tue Jan 29 18:08:05 1991 James Clark (jjc at jclark) + + * groff.c (main): Support -i. + +Sun Jan 27 13:23:17 1991 James Clark (jjc at jclark) + + * pic/pic.h: Include . + + * ps/ps.c: Add declaration of mktemp. + + * Makefile: Add -DHAVE_UNION_WAIT option for CPPDEFINES. + * groff.c: If HAVE_UNION_WAIT is defined, declare wait()'s + argument as union wait *. + (run_commands): If HAVE_UNION_WAIT is defined cast wait()'s + argument to union wait *. + +Sat Jan 26 12:04:52 1991 James Clark (jjc at jclark) + + * tty/tmac.tty: Add definition of \(co. + + * pic/object.c (make_arc): Only increase radius when radius + strictly less than d. + (arc_object::update_bounding_box): May need to add 4.0 to end_quad + more than once. + + * troff/env.c (environment::environment(symbol), + environment::environment(const environment *)): Initialize + input_trap_count. + +Sat Jan 19 08:18:35 1991 James Clark (jjc at jclark) + + * tbl/main.c (main): Add exit(0). + + * ps/ps.c (ps_printer::~ps_printer): Use fseek instead of rewind. + + * pic/main.c (main): + * eqn/main.c (main): + * tbl/main.c (main): + * etc/soelim.c (main): + * driver/printer.c (printer::~printer): + * troff/node.c (real_output_file::~real_output_file, + real_output_file::flush): Check for errors on stdout. + + * most files: Add 1991 to copyright notice. + + * macros/tmac.s: Don't test \n(.x and \n(.y. + + * troff/input.c (token::next): Rename `escape_char' label to + `handle_escape_char' and `normal_char' label to + `handle_normal_char'. + +Thu Jan 17 15:46:35 1991 James Clark (jjc at jclark) + + * groff.c (main, synopsis, help): Support -a option. + * groff.sh: Likewise. Also eliminate Zflag variable by adding -z + to trflags while parsing options. + +Tue Jan 15 13:07:27 1991 James Clark (jjc at jclark) + + * troff/number.c (parse_term): With `m', `M' and `n' scale + indicators, convert scale factor to hunits before scaling. + +Mon Jan 14 12:39:12 1991 James Clark (jjc at jclark) + + * lib/font.c (scale_round): Better test for overflow when n is + negative. + +Thu Jan 10 11:10:56 1991 James Clark (jjc at jclark) + + * tbl/main.c (process_format): Add second argument of type + options*. Change callers. Allow opt->tab_char as well as '\t' + between format items. + +Mon Jan 7 12:30:18 1991 James Clark (jjc at jclark) + + * macros/tmac.an (PD): With no arguments, make sure register PD is + at least \n[.V]. + (TH): Call PD with no argument, instead of setting register PD + directly. + +Sun Jan 6 11:18:39 1991 James Clark (jjc at jclark) + + * Version 1.00 released. + +Sat Jan 5 08:44:30 1991 James Clark (jjc at jclark) + + * ps/tmac.ps, xditview/tmac.X: Add font translation of C to CR. + + * dvi/devdvi/DESC: Mount CW instead of CR. + + * dvi/tmac.dvi: Add definition of \(tm. + + * dvi/devdvi/texsy.map: Add lh, and rh. + * dvi/devdvi/texex.map: Add lt, rt, lb, rb, lk, rk. + * dvi/devdvi/texmi.map: Add *o. Regenerate fonts. + + * dvi/devdvi/FontMakefile: Generate H from cmss10. + * dvi/devdvi/Makefile: Install H. + * dvi/devdvi/H: New file. + +Fri Jan 4 15:04:57 1991 James Clark (jjc at jclark) + + * troff/env.c (vertical_spacing): Don't allow vertical spacing to + be 0. + +Thu Jan 3 13:41:19 1991 James Clark (jjc at jclark) + + * macros/tmac.s (@EN): Add \n(.V to the argument to ds@need. + + * macros/tmac.pic (PS): Avoid attempting to set negative indent. + + * macros/tmac.s (@EN): Handle the case where the equation is empty + but the label is not. + +Wed Jan 2 10:31:44 1991 James Clark (jjc at jclark) + + * troff/groff.h: New warning category WARN_SPACE. + * troff/input.c: Add WARN_SPACE to DEFAULT_WARNING_MASK. Add + WARN_SPACE to warning_table. + (interpolate_macro): Give a warning of type WARN_SPACE if the name + is longer than two characters and is not defined, but the first + two characters do make a defined name. + + * PROBLEMS: New file. + + * CHANGES: New file. + * README-0.6, README-1.00: Deleted. + + * groff.c, groff.sh: Add X75-12 and X100-12 devices. + * xditview/devX75/Makefile: Make devX75-12. + * xditview/devX100/Makefile: Make devX100-12. + + * xditview/devX100/eqnchar, xditview/devX75/eqnchar, + dvi/devdvi/eqnchar, ps/devps/eqnchar: Remove use of \R. + +Tue Jan 1 19:24:01 1991 James Clark (jjc at jclark) + + * README-0.7: Rename to README-1.00. + + * macros/tmac.pic: New file. + * macros/Makefile (install.nobin): Install tmac.pic. + +Mon Dec 31 10:40:53 1990 James Clark (jjc at jclark) + + * troff/env.c (hyphen_word): Correct the test for whether the + token is a hyphen. Reset npos to 0. + + * macros/tmac.s (par@sup-start, par@sup-end): New implementations. + +Sun Dec 30 15:53:13 1990 James Clark (jjc at jclark) + + * macros/tmac.s (ds*common-end): Call par*reset. + (PE): Likewise. + (par@reset-indent): Deleted. + + * macros/tmac.s (@IP): Divert the label. + +Sat Dec 29 14:33:32 1990 James Clark (jjc at jclark) + + * xditview/draw.c (setGC): Use a line width of .1m rather than + .04m by default; round rather than truncate value. + + * tbl/table.c (class empty_entry): New class. + (empty_entry::empty_entry, empty_entry::line_type): New functions. + (table::add_entry): Represent empty entries by objects of type + empty_entry. + (table_entry::line_type): Return -1. + (table::determine_row_type): Ignore entries with line_type 0. + Treat type -1 as non-lines. + +Fri Dec 28 15:04:41 1990 James Clark (jjc at jclark) + + * ps/devps/textmap, xditview/libXdvi/DviChar.c, tty/devlatin1/R.proto, + macros/tmac.s: Rename \(-d to \(Sd. + +Thu Dec 27 12:35:47 1990 James Clark (jjc at jclark) + + * ps/devps/textmap: Add `sd', `/_' and `3d' characters. + * xditview/libXdvi/DviChar.c: Likewise. + * dvi/devdvi/texsy.map: Add `<<', `>>'. + +Wed Dec 26 13:33:23 1990 James Clark (jjc at jclark) + + * troff/div.c (top_level_diversion::begin_page): Call + init_output() if the_output is 0. + +Sat Dec 22 12:35:29 1990 James Clark (jjc at jclark) + + * troff/input.c: Replace ESCAPE_E by ESCAPE_e and ESCAPE_C by + ESCAPE_c. + (get_copy): Turn \E into ESCAPE_E. + (token::process, asciify): Handle ESCAPE_E. + + * macros/tmac.s (ds*common-end, par@reset): Add `.rj 0'. + (RD): New macro. + (DS): Implement `.DS R'. + +Fri Dec 21 11:41:53 1990 James Clark (jjc at jclark) + + * macros/tmac.s (FS): New macro. + + * macros/tmac.s (fn@do-FS): Use @LP instead of LP. + + * macros/tmac.s (cov*tl-init): Remove after first execution + instead of aliasing to @nop. Call top of page macro explicitly + instead of setting trap; call @init first. Set pg@top as top of + page macro. + (cov*auto-init): Deleted. Set cov*tl-init instead of + cov*auto-init as top of page trap. + (TL, LP): Do a break instead of calling cov*tl-init. + (cov*print): With RP format but no TL, alias FS and FE to @FS and + @FE; in this case also give a warning and always start another + page. No need to set pg@top here. + (cov*tl-init): Rename to cov*first-page-init. + + * macros/tmac.s (RP): Do `.pn 0'. + (cov*tl-init): With RP format don't do `.pn 0'. + + * macros/tmac.s (pg@cs-top): Set no space mode. + + * macros/tmac.s (par@TL, par@AU, par@AI): New macros. + (cov*ab-init): Alias TL, AU and AI to these. + +Thu Dec 20 10:10:50 1990 James Clark (jjc at jclark) + + * macros/tmac.s (@EQ): Move the space before the equation into @EN + (@EN): Do nothing unless \n[dl] is > 0. + +Tue Dec 18 12:20:47 1990 James Clark (jjc at jclark) + + * pic/object.c (ellipse_object::radius): New function. + + * VERSION: Change version to 0.7. + + * tbl/table.c (block_entry::do_divert): Declare return type as + void. + (block_entry::divert, alphabetic_block_entry::divert): Return 1. + +Mon Dec 17 12:30:34 1990 James Clark (jjc at jclark) + + * troff/column.c: New file. + * troff/Makefile: Corresponding changes. + + * troff/hvunits.c (scale(vunits, vunits, vunits)): New function. + Friend of vunits. + + * troff/div.c (top_level_diversion::space): If the space causes + the first-page transition and springs a trap, truncate the space + to 0. + +Fri Dec 14 12:30:02 1990 James Clark (jjc at jclark) + + * ps/ps.c (ps_printer::do_import): Add a `clear' after including + the document. + + * pic/troff.c (troff_output::line_thickness, + troff_output::set_fill): Do a horizontal motion to compensate for + the width of the \D escape sequence. + +Thu Dec 13 10:17:14 1990 James Clark (jjc at jclark) + + * xditview/tmac.X: Reinstate definition of \(rn, but only for X100 + (not X75). + + * eqn/sqrt.c (sqrt_box::compute_metrics): Supply missing argument + to printf. + + * tbl/table.c (simple_entry::simply_print): Don't declare as pure. + Supply empty definition. + (text_entry::simple_print, simple_text_entry::simple_print): + Delete declarations. + (table::add_entry): Represent empty entries by objects of type + `simple_entry'. + +Wed Dec 12 08:50:48 1990 James Clark (jjc at jclark) + + * troff/Makefile: Remove -DHYPHEN_CONTROL from DEFINES. + + * tbl/table.c (left_text_entry::add_tab): New function. + + * macros/tmac.s: Make @RT an alias for par@reset. Make RT + initialize like LP. + +Mon Dec 10 11:19:55 1990 James Clark (jjc at jclark) + + * troff/env.c (environment::start_field): Give an error message if + there is no next tab. + +Sun Dec 9 11:46:40 1990 James Clark (jjc at jclark) + + * troff/env.c (hyphenate): Skip initial elements with zero + hyphenation code. + + * macros/tmac.s (par@init): Keep VS in points rather than units. + +Sat Dec 8 23:00:27 1990 James Clark (jjc at jclark) + + * pic/main.c (main): Implement `-c' option. + * pic/output.h: Declare make_tpic_output(). + * pic/tex.c (tex_output::set_pen_size): Make it virtual and + protected. + (tpic_output): New class. + (tpic_output::tpic_output, tpic_output::set_pen_size, + tpic_output::command, make_tpic_output): New functions. + +Fri Dec 7 11:57:41 1990 James Clark (jjc at jclark) + + * tbl/main.c (main): Call `.ab' if \n(.g is false. Define TS/TE + if they're not already defined. + * tbl/table.c (init_output): Don't test \n(.g. + + * troff/input.c (do_if_request): Delete `g' condition. Recognize + `d', `r' and `c' conditions even in compatibility mode. + +Tue Dec 4 09:13:47 1990 James Clark (jjc at jclark) + + * ps/tmac.ps (ps-bb): Protect against negative numbers in bounding + box. + +Mon Dec 3 07:18:26 1990 James Clark (jjc at jclark) + + * troff/env.h (environment::prev_line_interrupted): New member. + (environment::get_prev_line_interrupted): New function. + * troff/env.c (environment::newline): Set prev_line_interrupted. + (environment::environment(const environment *), + environment::environment(symbol)): Initialize + prev_line_interrupted. + * troff/input.c (process_input_stack): Don't give special + treatment to space and newline at the beginning of the line if the + previous line was interrupted. + +Sat Dec 1 15:48:37 1990 James Clark (jjc at jclark) + + * eqn/eqn.y: Disallow PRIME by itself. + * eqn/lex.c (token_table): Bind `opprime' instead of `prime' to + PRIME. + (def_table): Remove definition of '. Define prime to be `. + + * eqn/eqn.y: Split off part of rule `script' into a new rule + `nonsup'. + +Fri Nov 30 10:23:44 1990 James Clark (jjc at jclark) + + * macros/tmac.s ({, }): New string aliases. + +Thu Nov 29 11:34:40 1990 James Clark (jjc at jclark) + + * README-0.7: New file. + +Wed Nov 28 10:09:57 1990 James Clark (jjc at jclark) + + * macros/tmac.s: New file. + * man/groff_ms.man: New file. + * Makefile: Add definition of TMAC_S. Pass TMAC_S in SUBFLAGS. + * Makefile.bd: Similarily. + * man/Makefile: Add groff_ms.n to MAN7PAGES. Replace @TMAC_S@. Add + definition of TMAC_S. + * macros/Makefile: Add definition of TMAC_S. Install tmac.s. + * macros/TODO: New file. + +Sat Nov 24 20:04:54 1990 James Clark (jjc at jclark) + + * troff/env.c (right_justify): New function. + (init_env_requests): Bind this to request "rj". + (center_lines): Set right_justify_lines to 0. If we get a bad + integer, center 1 line. + (environment::environment(symbol), environment::environment(const + environment *)): Initialize right_justify_lines. + (environment::get_right_justify_lines): New function. + (init_env_requests): Bind this to number_register ".rj". + + * troff/env.c (environment::choose_breakpoint): Implement + hyphenation_margin and hyphenation_space. + (environment::get_hyphenation_space, + environment::get_hyphenation_margin): New functions. + (init_env_requests): Bind these to .hys and .hym. + (hyphenation_space_request, hyphenation_margin_request): New + functions + (init_env_requests): Bind these to hys and hym. + (environment::environment(symbol), environment::environment(const + environment *)): Initialize hyphenation_margin and + hyphenation_space. + * troff/env.h: Corresponding changes to class environment. + +Fri Nov 23 09:08:16 1990 James Clark (jjc at jclark) + + * troff/div.c (blank_line): Always do a break. + + * eqn/box.c (do_text): Turn off escapes while appending text to + string. + +Thu Nov 22 10:58:59 1990 James Clark (jjc at jclark) + + * troff/input.c (while_break_request, while_continue_request): New + functions. + (init_input_requests): Bind these to "break" and "continue". + (while_depth, while_break_flag): New variables. + (while_request): Update while_depth. Break out of loop if + while_break_flag is set. + +Wed Nov 21 10:54:40 1990 James Clark (jjc at jclark) + + * tbl/table.c (init_span_reg): Initialize span_width_reg to \n(.H + rather than 0. + +Mon Nov 19 00:45:03 1990 James Clark (jjc at jclark) + + * Makefile: Include -DBROKEN_SPOOLER by default. Expand comment. + + * stringify: New file. + * Makefile (groff.o): Use stringify. + + * xditview/tmac.X: Remove definition of \(rn. + * xditview/libXdvi/DviChar.c: Remove radicalex from + Adobe_symbol_map. + +Sat Nov 17 10:44:58 1990 James Clark (jjc at jclark) + + * tbl/table.c (table::add_entry): Allow alphabetic text blocks. + (alphabetic_block_entry::alphabetic_block_entry, + alphabetic_block_entry::divert, alphabetic_block_entry::print): + New functions. + (block_entry::divert): Split off body into ... + (block_entry::do_divert): If the block is alphabetic, subtract 2n + from the line length; also update the span width to dl+2n, and the + alphabetic span width to dl. + + * driver/input.c (do_file): While reading argument to D command, + when expanding buffer, multiply szp by sizeof(int) rather than 2 + in the argument to memcpy. + + * tbl/table.c (compute_span_width): Add 2n rather than 1n to the + width of alphabetic columns. + +Fri Nov 16 06:34:27 1990 James Clark (jjc at jclark) + + * troff/node.c (lookup_family): Supply second argument to lookup. + + * troff/dictionary.c (dictionary::lookup): After an unsuccesful + search, return immediately if v is 0. + + * pic/troff.c: Define EQN_NO_EXTRA_SPACE_REG. + (troff_output::start_picture): Set this reg. + (troff_output::end_picture): Remove this reg + * eqn/box.c (box::extra_space): Don't produce `\x's if + EQN_NO_EXTRA_SPACE_REG is defined. + + * eqn/eqn.y: Allow just a PRIME to be a `simple'. + * eqn/text.c (split_text): Map ' to \(fm when it's the first + character. + +Thu Nov 15 10:35:06 1990 James Clark (jjc at jclark) + + * macros/tmac.e: Use font 3 instead of B in $c. Remove `bd' + requests. + + * troff/div.c (top_level_diversion::top_level_diversion): + Initialize page_number to 0. + +Wed Nov 14 21:41:58 1990 James Clark (jjc at jclark) + + * groff/troff (environment::environment(const environment *)): + Initialize name to e->name, rather than "anonymous". + +Sat Nov 10 01:59:37 1990 James Clark (jjc at jclark) + + * xditview/libXdvi/Dvi.c (ShowDvi): If eof is encountered, reset + requested_page. Split middle part into ... + (FindPage): New function. + (SetValues): If we don't yet know the last page, and the requested + page is greater than the current page, call FindPage. + Update the font_map_string before doing this. + + * xditview/tmac.X: Add definitions of \(sq, \(ga, \(dg and \(dd. + Translate \(lh and \(rh into left and right double arrows. + + * troff/node.c (class hyphen_inhibitor_node): New class. + (hyphen_inhibitor_node::hyphen_inhibitor_node, + hyphen_inhibitor_node::copy, hyphen_inhibitor_node::same, + hyphen_inhibitor_node::type, + hyphen_inhibitor_node::get_hyphenation_type): New functions. + (node::add_discretionary_hyphen): Use hyphen_inhibitor_node rather + than dbreak_node(0, 0) to represent a `\%' at the beginning of a + word. + +Fri Nov 9 16:05:38 1990 James Clark (jjc at jclark) + + * troff/node.h (dummy_node::get_hyphenation_type, + transparent_dummy_node::get_hyphenation_type): Declare them. + * troff/node.c: (dummy_node::get_hyphenation_type, + transparent_dummy_node::get_hyphenation_type): New functions. + +Wed Nov 7 10:09:06 1990 James Clark (jjc at jclark) + + * xditview/libXdvi/draw.c: If M_PI not defined after including + math.h, then define it. + + * xditview/Makefile: Add definition of AR. Pass it to the submake + in libXdvi. + * xditview/libXdvi/Makefile: Add definitions of AR and RANLIB. + +Tue Nov 6 10:14:27 1990 James Clark (jjc at jclark) + + * troff/dictionary.h (object_dictionary::alias): Declare return + value as int. + * troff/dictionary.c (object_dictionary::alias): Return non-zero + if the old name was defined. + * troff/input.c (alias_macro): Give a warning if the old name was + not defined. + * troff/reg.c (alias_reg): Likewise. + +Mon Nov 5 00:31:39 1990 James Clark (jjc at jclark) + + * troff/input.c (token::next): Delete implementation of \R. + + * macros/Makefile: Strip comments from tmac.e while installing it. + + * troff/input.c: New variable `nroff_mode'. + (troff_request, nroff_request): New functions. + (init_input_requests): Bind `troff' and `nroff' to troff_request + and nroff_request. + (do_if_request): Compute results of t and n conditions from + nroff_mode. + + * text/text.c (split_text): Fix typo in >=. + + * eqn/lex.c: Add definition of `==' to def_table. + +Fri Nov 2 02:49:09 1990 James Clark (jjc at jclark) + + * pic/tex.c (tex_output::start_picture): Change the definitions of + \graph and \graphtemp so that they work properly with Plain TeX. + + * pic/tex.c (tex_output::solid_arc): Ensure that the second angle + argument to `ar' is not less than the first. + + * pic/pic.y: Allow a comma between elements of the variable list + in the argument to `reset'. + + * pic/object.c (arc_object::arc_object): Fix computation of + radius. + + * eqn/main.c (main): Add exit(0). + +Thu Nov 1 02:03:50 1990 James Clark (jjc at jclark) + + * troff/div.c (begin_page): Test no_space_mode after doing the + break, but still push the page ejector cookie before doing the + break. Also set the next page number after doing the break. + + * xditview/xditview.c (NewFile): Don't set the title and icon name + if this is the first file and its name is `-'. + * groff/groff.c: Define a new device flag XT_OPTION. Set it for + the X75 and X100 devices. + (main): If a device has the XT_OPTION flag set and there's exactly + one file argument, pass the driver -xrm and -title options to set + the icon name and window title to the name of the file. + + * troff/env.c (environment_switch): If there was an argument but + it wasn't a valid number or name, then pop an environment but + don't give an error message on underflow. + + * troff/number.c (start_number): Correct spelling in error message. + + * troff/input.c (token::delimiter): Don't print an error message + if err is false. + + * xditview/libXdvi/parse.c (ParseInput): In case 'D', only call + ParseDrawFunction if dw->display_enable is true. + +Wed Oct 31 05:49:50 1990 James Clark (jjc at jclark) + + * pic/pic.y: Parse text positioning like normal attributes, so as + to allow `"text" at 0,0 ljust'. Don't allow `center' as a + positioning attribute. + +Mon Oct 29 22:50:38 1990 James Clark (jjc at jclark) + + * tbl/main.c (process_data): When in state START while reading a + text block, don't change to state MIDDLE if c is a newline. + +Sun Oct 28 21:59:56 1990 James Clark (jjc at jclark) + + * dvi/dvi.c (dvi_printer::begin_page): Rename `i' variable to `j' + so as to avoid shadowing parameter. + +Wed Oct 24 18:35:39 1990 James Clark (jjc at jclark) + + * tbl/table.c (trim_space): Deleted. + (table::add_entry): Don't call trim_space. + +Mon Oct 22 03:48:39 1990 James Clark (jjc at jclark) + + * VERSION: Change version to 0.6. + + * troff/number.c (parse_expr): Make == work. + +Sat Oct 20 11:28:17 1990 James Clark (jjc at jclark) + + * man/grog.man: New file. + * man/Makefile: Add grog.n to MAN1PAGES. + * etc/grog.sh: New file. + * etc/Makefile: Install grog.sh as grog. + +Fri Oct 19 11:17:15 1990 James Clark (jjc at jclark) + + * troff/input.c (token::next): Implement \E. + +Thu Oct 18 11:56:24 1990 James Clark (jjc at jclark) + + * xditview/tmac.X: Change font translations to match tmac.ps. + + * troff/input.c (non_empty_name_warning): Don't give a warning if + `\{' terminates the name. + +Tue Oct 16 10:04:23 1990 James Clark (jjc at jclark) + + * ps/devps/symbol.diff: New file. + * ps/devps/FontMakefile: Mention symbol.diff. + +Sun Oct 14 11:46:46 1990 James Clark (jjc at jclark) + + * troff/node.c (font_position): Use get_long_name to read the + external_name. + + * troff/env.c (environment_switch): If we get a number that's < 0 + or >= NENVIRONMENTS, treat it like a name. + Change NENVIRONMENTS to 10. + + * troff/groff.h: Remove definition of FONTS_MAX. + * troff/node.h (class font_family): Make map a pointer instead of + an array. Add a map_size member. Make it a class. Make nm const + and public. Make invalidate_fontno a friend. + * troff/node.c: Define font_table_size. Make font_info a pointer + rather than an array. + (class troff_output_file): Allocate font_position dynamically. Add + nfont_positions member. + (troff_output_file::set_font): Grow font_position if necessary. + (troff_output_file::~troff_output_file): Delete font_position. + (troff_output_file::troff_output_file): Allocate font_position. + (grow_font_table): New function. + (troff_output_file::really_begin_page, + troff_output_file:really_copy_page): Use nfont_positions rather + than FONTS_MAX. + (mount_font_no_translate, mount_style): Call grow_font_table if + necessary. + (font_family::font_family): Allocate map. + (font_family::make_definite): Grow map if necessary. Use + font_table_size instead of FONTS_MAX. + (font_family::~font_family): New function. + (invalidate_fontno): Use font_family::map_size. + (get_fontno, env_space_width, env_half_narrow_space_width, + env_narrow_space_width, symbol_fotno, is_good_fontno, + get_bold_fontno, make_glyph_node): Use font_table_size rather than + FONTS_MAX. + (next_available_font_position): Never return 0. + +Fri Oct 12 10:17:52 1990 James Clark (jjc at jclark) + + * ps/tmac.ps: Add font translations for compatibility with dpost. + +Thu Oct 11 12:09:03 1990 James Clark (jjc at jclark) + + * eqn/pile.c: Rename default_baseline_sep to baseline_sep. + Move BASELINE_SEP_FORMAT and COLUMN_WIDTH_FORMAT into pbox.h. + Move definitions baseline_sep, shift_down, column_sep, + matrix_side_sep into... + * eqn/box.c: Add them to param_table. + * eqn/pbox.h: Add declarations to pbox.h. + + * troff/input.c (set_string): Cast value to unsigned char *. + + * troff/token.h (process_input_stack): Declare it static before + declaring it a friend. + +Wed Oct 10 09:59:13 1990 James Clark (jjc at jclark) + + * dvi/devdvi/texex.map: Fix positions of extensible brace middle + and bottom. + * dvi/devdvi/EX: Regenerate. + + * troff/input.c (init_charset_table): Make ", ', ), ], *, \(dg + transparent. + +Tue Oct 9 08:34:02 1990 James Clark (jjc at jclark) + + * eqn/lex.c: In defaults_table, make definition of `dot' call + `dot_def'. Don't explicitly make it roman. Similarily for other + accents. + + * pic/lex.c (for_input::for_input): Add by_is_multiplicative + argument. + (for_input::get, for_input::peek): Use this. + (do_for): Add by_is_multiplicative argument. + * pic/pic.y: Change optional_by clause to allow '*' after `by'. + Change semantic value of optional_by to be a double plus a flag + saying whethet the by clause is multiplicative. + + * eqn/lex.c (get_delimited_text): Remember location of start of + definition. Improve error handling when EOF is encountered. + + * lib/font.h: Rename handle_x_command to + handle_unknown_font_command. + * lib/font.c (font::load): Call handle_unknown_font_command for + any unknown command in the font description file. Don't call + handle_x_command. Include the name of the command in the argv. + Improve message for unknown command after kernpairs or charset + command. + * ps/ps.c (ps_font::handle_x_command): Rename to + handle_unknown_font_command. Remove message about `x download' + command. Give error message for wrong number of arguments. + * ps/devps/afmtodit: Generate `encoding' instead of `x encoding'. + * dvi/dvi.c (dvi_font::handle_x_command): Rename to + handle_unknown_font_command. Give an error message for wrong + number of arguments. Rename design_size to designsize. + * dvi/tfmtodit.c (main): Generate `checksum' instead of `x + checksum', `designsize' instead of `design_size'. + +Mon Oct 8 00:38:55 1990 James Clark (jjc at jclark) + + * eqn/*.[chy]: Change underaccent to uaccent. + + * eqn/eqn.y: Add rule for underaccent. Declare UNDERACCENT token; + give it the same precedence as ACCENT. + * eqn/other.c (make_underaccent_box): New function. + * eqn/box.h: Declare it. + * eqn/lex.c: Add UNDERACCENT to token_table. Add utilde to + def_table. + +Sun Oct 7 11:25:16 1990 James Clark (jjc at jclark) + + * pic/pic.y (reset_all): New function. Called in rule for RESET. + (parse_init): Call reset_all. + (define_variable): When defining scale reset only those + pre-defined variables that are scaled. + (defaults_table): Add `scale' as non-scaled value. + + * pic/pic.y: Redo parsing of text adjustments: parse adjustments + together with the text; allow any number of positioning words; + allow center as a positioning word. + + * pic/object.c (output::compute_scale): Get picture maximum height + and width from variables called maxpswid and maxpsht. + * pic/pic.y: Add maxpswid and maxpsht to defaults_table. + +Sat Oct 6 10:16:56 1990 James Clark (jjc at jclark) + + * pic/object.c (object_spec::make_text): Multiply textht by number + of text items. + + * pic/pic.y: Allow `sprintf("string", expr,...)' wherever text can + occur. + (do_sprintf): New function. + (pic.gperf): Add sprintf token. + (text, sprintf): New rules. + + * pic/pic.y: `rand()' with no arguments returns a random number + in the range [0,1). + + * pic/pic.y: Allow a bare expression to be an attribute: change + precedences to support this. Change optional_ordinal rule to + optional_ordinal_last to avoid reduce/reduce conflict. + * pic/object.c (object_spec::object_spec): Initialize direction. + + * pic/pic.y: Implement ^ operator meaning exponentiation. + + * troff/node.h: Add default argument to mount_font. + * troff/node.c (font_position): Read an optional third argument + giving the external_name. + (mount_font): Add optional argument giving the external_name. + (mount_font_not_translate): Have additional argument giving + external name. Use this name to load the font. Pass both names + to font_info::font_info. + (font_info::font_info): Have additional argument giving + external_name. + (class tfont): New member external_name. + (font_info::get_tfont): Use external name to construct tfont_spec. + +Fri Oct 5 04:03:13 1990 James Clark (jjc at jclark) + + * eqn/lex.c (init_table): Add argument giving device. Define + name of device to be "1". + (do_ifdef): Counts as true if the argument has been defined with + `define'. + * eqn/main.c (main): Call init_table with device argument. Make + device local to main. + * eqn/eqn.h: Change declaration of init_table. Remove declaration + of device. + + * pic/lex.c (get_delimited): Allow text to be delimited by + matching {}s. Don't recognize ending delimiter within a string. + + * troff/input.c (get_delim_name): New function. + (token::next): Implement \C. + + * lib/font.c (font::load): Grok ---. Add an alias for each + character based on its code. + (font::get_code_width): Deleted. + * lib/font.h (class font): Declare font::number_to_index(). + Remove declaration of font::get_code_width. + * lib/nametoindex.c (font::name_to_index): Add 512 rather than 256 + to indices of named characters. + (font::number_to_index): New function. + * troff/input.c (font::number_to_index): New function. + (get_charinfo_by_number, charinfo::get_number, + charinfo::set_number): New functions. + (token::next): Turn \N into a TOKEN_NUMBERED_CHAR. + (token::process, token::description, token::get_char, + token::add_to_node_list, token::operator==): Handle + TOKEN_NUMBERED_CHAR. + * troff/charinfo.h: Declare get_charinfo_by_number, + charinfo::get_number, charinfo::set_number. Add NUMBERED flag to + charinfo class. + (charinfo::numbered): New function. + * troff/token.h: Add TOKEN_NUMBERED_CHAR. + * troff/env.h (class environment): Remove declaration of ... + * troff/env.c (environment::make_numbered_char_node): Deleted. + * troff/node.c (make_numbered_node): Deleted. + (class numbered_glyph_node): Remove. + (troff_output_file::put_char_width, troff_output_file::put_char): + Handle numbered chars. + (troff_output_file::numbered_char): Removed. + (tfont::get_code_width): Removed. + (make_glyph_node): Don't search special fonts for numbered + characters. + * troff/node.h: Remove declaration of make_numbered_node. + * driver/input.c (do_file): Handle N command. + * driver/printer.h: Add declaration of ... + * driver/printer.c (printer::set_numbered_char): New function. + * dvi/tfmtodit.c (main): Generate unnamed entries. + * ps/devps/afmtodit: Likewise. + * xditview/xtotroff.c (MapFont): Likewise. + * xditview/libXdvi/parse.c (ParseInput): Grok N command. + + * tbl/main.c (process_format): If multiple widths are specified + for a column but all the widths are the same, don't give an error + message. + + * tbl/table.c (table::do_row): If the current row is all lines and + the stuff doesn't contains a line, mark the top of the row after + printing stuff before the row. If the current row is not all + lines and the stuff doesn't contain a line, don't unnecessarily + mark the top of the row before printing the stuff. + +Mon Oct 1 11:42:00 1990 James Clark (jjc at jclark) + + * troff/groff.h: Remove MAX_PATH. + * troff/input.c (open_file): Dynamically allocate space for the + path. + (open_mac_file, process_macro_file): Corresponding changes. + +Sun Sep 23 18:56:26 1990 James Clark (jjc at jclark) + + * troff/node.h (class output_file): Make copy_file pure. Add + vspace method ifdef COLUMN. Add is_printing method. + * troff/node.c: Add class printing_reg. Add class + real_output_file. Derive other output_file classes from + real_output_file; in these classes rename begin_page to + really_begin_page, print_line to really_print_line, copy_file to + really_copy_file, transparent_char to really_transparent_char. + Move output_file::flush to real_output_file. Add printing member + to class output_file. + * troff/div.h: Remove printing member from top_level_diversion. + Add vspace member function to class diversion ifdef COLUMN. Add + some declarations ifdef COLUMN. + * troff/div.c (top_level_diversion::copy_file, + top_level_diversion::transparent_output, + top_level_diversion::output): Don't test printing member before + output. + * troff/input.c: Handle initial variable_space_request ifdef + COLUMN. + * troff/Makefile: Add column.c but comment it out. Add -DCOLUMN + but comment it out. + +Sat Sep 22 11:32:22 1990 James Clark (jjc at jclark) + + * troff/div.c (diversion::need): Make any space forced. If we + sprung a trap, set truncated_space to minus the distance to the + trap and set needed_space to the amount that was needed. + (top_level_diversion::space): A forced space turns no_space_mode + off. + (class constant_vunits_reg): New class. + (init_div_requests): Implement number registers .trunc and .ne + using constant_vunits_reg. + (class truncated_space_reg): Deleted. + + * troff/div.h: Don't have a no_space_mode member in diversion. + Instead have it in top_level_diversion. + * troff/div.c (diversion::diversion): Don't initialize + no_space_mode. + (top_level_diversion::top_level_diversion): Initialize + no_space_mode. + (no_space, restore_spacing): Do nothing if curdiv != topdiv. + (macro_diversion::output): Don't clear no_space_mode. + + * troff/input.c (diverted_space_node::reread): Don't call + environment::do_break. In fill mode, act like a blank line. + (diverted_copy_file_node::reread): Don't call + environment::do_break. + + * troff/div.c (blank_line): New function. + * troff/div.h: Declare it. + * troff/input.c (process_input_stack): Call it. + + * troff/div.c (truncated_space_reg::get_string): New function. + (init_div_requests): Bind to .trunc. + (space_request, top_level_diversion::space, + top_level_diversion::output, macro_diversion::space, + macro_diversion::output): Update truncated_space. + (macro_diversion::output): Redo calculations when trap sprung. + (macro_diversion::output, macro_diversion::space): No need for + trap_flag. + + * troff/div.c (top_level_diversion::output): Set nl_reg_contents + after truncating post line spacing. + +Fri Sep 21 11:27:25 1990 James Clark (jjc at jclark) + + * ps/devps/prologue (MF, SF): Make them work even if setfont is + defined as a procedure rather than as an operator. + +Thu Sep 20 12:55:05 1990 James Clark (jjc at jclark) + + * troff/div.c (macro_diversion::space): Ignore no_space_mode. + +Wed Sep 19 10:54:37 1990 James Clark (jjc at jclark) + + * troff/div.c (top_level_diversion::output): Merge + output_file::print_line and output_file::end_of_line member + functions. + * troff/div.h (class output_file): + * troff/node.c (troff_output_file::print_line, + troff_output_file::end_of_line, output_file::end_of_line, + ascii_output_file::print_line, suppress_output_file::print_line): + Corresponding changes. + +Tue Sep 18 11:31:47 1990 James Clark (jjc at jclark) + + * troff/input.c (token::next): Don't give a warning for `\.'. + + * troff/env.c (environment::get_center_lines): New function. + (init_env_requests): Bind number register .ce to it. + * troff/env.h: Declare it. + * tbl/table.c (table::init_output): Define reset macro to restore + .ce. If center option not given, store .ce in SAVED_CENTER_REG. + Then do .ce 0. + (table::print): If center option not given, then imply center + option if SAVED_CENTER_REG > 0. + +Mon Sep 17 09:19:19 1990 James Clark (jjc at jclark) + + * ps/devps/Makefile: Remove T from FONTS. Remove TSymbol.ps and + Troff.ps from DOWNLOAD. + + * troff/Makefile: Change comment in DEFINES to avoid confusing + System V make. + + * ps/ps.c (ps_printer::do_exec): Allow newlines within PostScript + code. Don't try to catch errors with stopped. + (check_line_lengths): New function. + * ps/devps/prologue (EXEC): Deleted. + (EBEGIN, EEND): New procedures. + +Sun Sep 16 14:51:15 1990 James Clark (jjc at jclark) + + * troff/input.c: Include request.h before node.h. + * troff/node.c: Likewise. + * troff/env.c: Likewise. + * troff/div.c: Likewise. + * troff/node.h (class special_node): Store argument as a macro + rather than a char *. + * troff/node.c (special_node::special_node, special_node::copy): + Grok this. + (special_node::~special_node): Deleted. + (special_node::tprint): Deleted. + (special_node::tprint_start, special_node::tprint_end, + special_node::tprint_char): New functions. + (troff_output_file::special): Deleted. + (troff_output_file::start_special, troff_output_file::end_special, + troff_output_file::special_char): New functions. + * troff/input.c (special_node::tprint): New function. + (do_special): Use macro not char *. + (do_transparent_macro): Deleted. + (token::next): Don't call do_transparent_macro. + + * troff/input.c (token::next): Add 'Y' case. + (do_transparent_macro): New function. + * troff/node.c (troff_output_file::special): Handle newlines with + argument using new continuation convention. + * driver/input.c (get_string): Cope with continuation convention. + (do_file): Don't call skip_line after calling get_string(1). + * ps/ps.c (ps_printer::special, ps_printer::do_import, + ps_printer::do_def, ps_printer::do_exec): Cope with newlines in + arg. + * xditview/libXdvi/parse.c (ParseInput): Ignore lines starting + with +. + +Sat Sep 15 19:00:10 1990 James Clark (jjc at jclark) + + * troff/input.c (asciify): By default, illegal input characters + should return empty string. + + * troff/input.c (copy_file): Handle first page transition like title. + (token::next, process_input_stack): Grok COPY_FILE_REQUEST. + + * troff/input.c (token::next): Improve error message for EOF after + escape character. + (input_char_description): New function. + (get_char_for_escape_name): Use input_char_description. + (token::next): Warn about unrecognized escape sequences. + (warning_table): Add WARN_ESCAPE. + * troff/groff.h: Declare WARN_ESCAPE. Change WARN_TOTAL + accordingly. + + * troff/token.h: Remove declaration of process_input_stack. + + * troff/input.c: Remove declaration of init_hyphen_requests. + * troff/request.h: Correct spelling in declaration of same. + + * troff/input.c (token::next): Check whether escape_char is 0. + +Fri Sep 14 12:09:25 1990 James Clark (jjc at jclark) + + * groff.c (main, usage, help): Implement -P and -L options. + * groff.sh: Likewise. + + * troff/input.c (token::next): Use some gotos to avoid code + duplication. + + * troff/input.c (get_long_name, get_name, read_long_ecsape_name): + Avoid calling symbol::symbol if name empty. + +Thu Sep 13 06:21:45 1990 James Clark (jjc at jclark) + + * troff/input.c (init_input_requests): Make \n(.x return the major + version number and \n(.y return the minor version number. + * troff/Makefile: Construct file majorminor.c defining + major_version and minor_version automatically from ../VERSION. + + * troff/node.c (class glyph_node): Make operator new and operator + delete public. + (class ligature_node): Similarily. + + * troff/input.c (operator==(const macro &, const macro &)): New + function. + (non_interpreted_node::same): Use this. + (string_iterator::string_iterator): Make macro& argument const. + + * troff/input.c (input_iterator::get): New function. Don't make + asciify_macro or class non_interpreted_node friends of class + input_iterator. + (non_interpreted_node::interpret): Use input_iterator::get. + (asciify_macro): Likewise. + + * troff/input.c (~token_node, ~string_iterator, ~arg_list, + ~non_interpreted_node): Deleted. + * troff/node.c: (~suppress_output_file, ~ascii_output_file): + Deleted. + + * troff/symbol.h: Make all symbol member functions const. + + * lib/strtol.c: New file. + * lib/Makefile: Add strtol.c. + * Makefile: Define STRTOL as strtol.o to include strtol in + libgroff.a. + +Wed Sep 12 10:00:49 1990 James Clark (jjc at jclark) + + * pic/troff.c (troff_output::simple_circle): Divide by scale. + +Tue Sep 11 14:17:16 1990 James Clark (jjc at jclark) + + * troff/input.c (do_special): Use input_level. + + * troff/token.h (TOKEN_BACKSPACE): New token. + (token::backspace): New function. + * troff/input.c (token::description, token::next, token::process): + Grok TOKEN_BACKSPACE. + (do_special): Turn TOKEN_BACKSPACE back into \b. + + * troff/token.h (token::leader): New function. + * troff/input.c (do_special): Turn TOKEN_LEADER back into \001. + + * troff/input.c (do_special): Turn TOKEN_TAB back into \t. + + * troff/input.c (do_special): Use token::description in error + message. + +Mon Sep 10 11:06:27 1990 James Clark (jjc at jclark) + + * troff/input.c (decode_args): Combine quoted and + quote_input_level variables. Make it a for (;;) loop. + + * troff/input.c (get_char_for_escape_name): Check for \001 and \b. + + * troff/input.c (read_long_escape_name): The test for whether to + expand buffer was off by 1. + (read_string): Similarily. + +Fri Sep 7 11:45:50 1990 James Clark (jjc at jclark) + + * troff/input.c: Use `const int' rather than `static const int'. + + * troff/div.h (diversion::copy_file): Declare as pure virtual. + (macro_diversion::copy_file): New function. + * troff/node.h: New class diverted_copy_file_node. + * troff/node.c: Implement it. + * troff/input.c (copy_file): Use diversion::copy_file. Handle + first page transition by pushing a diverted_copy_file_node. + * troff/input.c (token::next, process_input_stack): Don't handle + COPY_FILE_REQUEST. + +Thu Sep 6 13:29:10 1990 James Clark (jjc at jclark) + + * ps/ps.c (flush_sbuf): Remember to add sbuf_kern when checking + whether space widths need adjusting. + + * troff/charinfo.h: Generalize translated_to_space to + special_translation so as to allow translation to \&. + * troff/input.c (translate): Allow translation to \&. + (charinfo::*): Corresponding changes. + * troff/node.c (make_node, node::add_char): Corresponding changes. + * troff/node.h (dummy_node::dummy_node): Allow optional first + argument. + + * lib/lib.h: Make codes 0200 to 0237 illegal input characters. + * troff/token.h: Remove TOKEN_TITLE. Remove token::title. Add + TOKEN_REQUEST. + * troff/input.c (token::next): Turn a TITLE_REQUEST into a + TOKEN_REQUEST with an argument of TITLE_REQUEST. + (token::process): Grok that. + * troff/input.c (copy_file): Handle first page transition like + title by pushing a COPY_FILE_REQUEST cookie. + (token::next, process_input_stack): Grok that. + * troff/node.h (output_file::copy_file): Add x and y arguments. + Make it non-pure. + * troff/div.c (top_level_diversion::copy_file): Supply them. + * troff/node.c (troff_output_file::copy_file): Add x and y + arguments; moveto specified position. Invalidate font_position + array after copying file. + (output_file::copy_file): New function. + (suppressed_output_file::copy_file, ascii_output::copy_file): + Removed. + * troff/input.c (transparent_file): New function. + (init_input_requests): Bind to "trf". + (token::next): Handle TRANSPARENT_FILE_REQUEST cookie. + (process_input_stack): Likewise. + + * troff/Makefile: Add ../lib/lib.h to GROFF_H. + + * troff/node.c (init_node_requests): New number registers .kern + pointing to global_kern_mode, and .lg pointing to + global_ligature_mode. + + * troff/node.c (ligature): Don't change it if we get a bad + integer. + + * troff/input.c (do_define_string): Don't strip tabs. + + * troff/input.c (asciify_macro): Make the string_iterator auto. + + * troff/node.c (init_font_requests): Rename to... + (init_node_requests): + * troff/node.h: Change declaration. + * troff/input.c (main): Change call. + + * troff/input.c (node::reread, diverted_space_node::reread): New + methods. + (process_input_stack): Call reread rather than + get_diverted_space_node. + * troff/node.c (node::get_diverted_space_node, + diverted_space_node::get_diverted_space_node): Removed. + * troff/node.h: Declare reread methods instead of + get_diverted_space_node methods. Make `n' member private. + * troff/input.c: (token::diverted_space): Removed. + * troff/token.h: Removed declaration. + + +Tue Sep 4 00:48:04 1990 James Clark (jjc at jclark) + + * eqn/script.c (script_box::compute_metrics): Don't let + SUP_RAISE_FORMAT become negative. + + * tbl/table.c (table::do_row): Entries that don't end in the + this row shouldn't make the row non-blank. + + * tbl/table.c (table::make_columns_equal): Only set the width of + columns which are marked as equal. + + * tbl/main.c (process_data): Before issuing excess data error, + if last character was a newline unget it; then get it again after + the error. Also include the contents of the entry in the message. + + * groff.c: New file. + * Makefile: Build groff from groff.c. Make it possible to use + either groff.sh or groff.c as groff. + * Makefile.bd: Similarily. + +Mon Sep 3 09:39:49 1990 James Clark (jjc at jclark) + + * groff.sh: Don't delay expansion of $@ in assignment to files. + Remove occurrences of \". + +Sun Sep 2 09:56:59 1990 James Clark (jjc at jclark) + + * all Makefiles: Simplify and rearrange. + + * Makefile: Handle fmod like malloc. + * lib/Makefile: Similarily. + * lib/fmod.c: Remove #ifdef NEED_FMOD. + + * Makefile: Rename OPTIMISE to OPTIMIZE. + + * groff.sh: Remove assignment to PATH. + * Makefile: Remove SHPATH variable. + * Makefile.bd: Similarily. + + * groff.sh: Add -V option to print the pipeline instead of + executing it. + +Fri Aug 31 00:56:46 1990 James Clark (jjc at jclark) + + * lib/font.c: Split off file searching into ... + * lib/fontfile.c: New file. + + * lib/strerror.c (strerror): Use `Error %d' for unknown errors. + +Thu Aug 30 13:13:55 1990 James Clark (jjc at jclark) + + * tbl/table.c (table::do_hspan): Delete assertion that e != 0. + Also change misleading comment. + (table::do_vspan): Change similarily misleading comment. + * tbl/main.c (process_data): A format row with an explicit `s' + uses up a data line, even if all the other columns are `_' or `='. + + * troff/input.c (token::description): Fix description of + TOKEN_DUMMY and TOKEN_EMPTY. + +Wed Aug 29 04:12:08 1990 James Clark (jjc at jclark) + + * groff.sh: Fix description of -Z in help message. + +Tue Aug 28 07:28:33 1990 James Clark (jjc at jclark) + + * pic/object.c (object_spec::make_object): Allow negative and zero + line thicknesses. + * pic/pic.y: Give linethick default value of -1.0. + * pic/troff.c (troff_output::troff_output): Initialize + last_line_thickness to BAD_THICKNESS. + (troff_output::finish_picture): Set thickness to BAD_THICKNESS. + (troff_output::line_thickness): Canonicalize negative thicknesses + to RELATIVE_THICKNESS. + * pic/tex.c (tex_output::set_pen_size): Silently map negative line + thicknesses to DEFAULT_PEN_SIZE. Canonicalize negative pen sizes + to -1.0. + (tex_output::start_picture): Set pen_size to -2.0. + + * ps/ps.c (ps_printer::set_line_thickness): If line_thickness is + 0, then use 0 linewidth. + (ps_printer::ps_printer): Initialize line_thickness to -1. + + * pic/troff.c (troff_output::simple_ellipse): Divide by scale. + + * ps/devps/symbolchars: Remove `or'. + * ps/tmac.ps: Implement \(or with .char. + + * ps/devps/symbolchars: Move most characters into textmap. + * ps/devps/textmap: Add names for troff bracket characters. Remove + ul, ru, br, bv. + + * ps/devps/TSymbol.ps: Removed. + * ps/devps/FontMakefile: Make S from Symbol not TSymbol. + * ps/tmac.ps: Do with .char what TSymbol did. + * ps/devps/download: Remove TSymbol. + + * ps/devps/T: Removed. + * ps/devps/Troff.ps: Removed. + * ps/devps/Troff.afm: Removed. + * ps/tmac.ps: Implement \(ru, \(ul, and \(br with .char. + * ps/devps/download: Remove Troff. + * ps/devps/FontMakefile: Remove T target. + * ps/devps/DESC-A4: Remove T from font list. + * ps/devps/DESC-letter: Likewise. + + * troff/input.c (macro_to_node): Rename to ... + (charinfo_to_node): Don't pass mac argument. Temporarily remove the + character's definition while processing it. + * troff/node.c (node::add_char, make_node): Change calls to + macro_to_node accordingly. + + * troff/input.c (token::next): Translate \_ to \(ul. + + * tty/devascii/R.proto: Add `|'. + * tty/devlatin1/R.proto: Likewise. + +Mon Aug 27 11:25:41 1990 James Clark (jjc at jclark) + + * man: Put the version number in all the man pages. + +Sun Aug 26 11:40:05 1990 James Clark (jjc at jclark) + + * Makefile.bd: New file. + * README.bd: New file. + + * VERSION: New file. + * lib/version.c: Removed. + * lib/Makefile: Create version.c from ../VERSION. Remove version.c + in clean target. + + * troff/input.c (main): Get hyphen_file from GROFF_HYPHEN + environment variable. + + * all Makefiles: Split install target into install.bin for + binaries, and install.nobin for everything else. + * Makefile: Add bindist target. + + * man/afmtodit.man: New file. + * man/Makefile: Add afmtodit.n to MAN1PAGES. + * ps/devps/Makefile: Add textmap to DEVICEFILES. Install afmtodit + in BINDIR. + * ps/Makefile: Pass BINDIR to make install in devps. + + * ps/ps.c (ps_printer::set_char): Do nothing if the character is + the space character. + + * ps/devps/FontMakefile: Rename symbol.afm to tsymbol.afm. + +Sat Aug 25 15:39:03 1990 James Clark (jjc at jclark) + + * ps/ps.c: Redo font downloading. + * ps/devps/download: New file. + * ps/devps/Makefile: Add download to DEVICEFILES. + * ps/devps/afmtodit: Remove -d option. + * ps/devps/FontMakefile: Don't use -d option with afmtodit. + * ps/devps/symbosl.ps: Add %%DocumentFonts comment. + * ps/devps/zapfdr.ps: Likewise. + * ps/devps/TSymbol.ps: Likewise. + +Fri Aug 24 20:10:30 1990 James Clark (jjc at jclark) + + * groff.sh: Initialize dev to ${GROFF_TYPESETTER:-@DEVICE@}. + +Thu Aug 23 10:03:47 1990 James Clark (jjc at yquem) + + * ps/ps.c (ps_output::include_file): If BROKEN_SPOOLER is defined, + then strip the first line if it starts with %. + * Makefile: Add a comment about this. + + * man/tfmtodit.man: New file. + * man/Makefile: Add tfmtodit.n to MAN1PAGES. + * dvi/Makefile: Install tfmtodit in BINDIR. + + * dvi/tfmtodit.c (usage): Mention -v option. + +Wed Aug 22 09:56:36 1990 James Clark (jjc at yquem) + + * troff/node.c (troff_output_file::end_of_line): Call do_motion. + * troff/node.c (troff_output_file::transparent_char): Don't call + flush_tbuf. + + * eqn: Add check_tabs method to most box classes. + * eqn/box.c (box::top_level): Call check_tabs. + + * eqn/script.c (script_box::output): Use \Z. + * eqn/limit.c (limit_box::output): Use \Z. + + * eqn/box.c (box::top_level): Use itoa. + +Tue Aug 21 09:29:28 1990 James Clark (jjc at yquem) + + * dvi/tmac.dvi: Add font translations for CR, C, TT. + * dvi/devdvi/Makefile: Don't make links to CW. + + * ps/tmac.ps: Add font translations for C, CW, CO, CX, CD, H, HO, + HX, HD. + * xditview/tmac.X: Likewise. + + * troff/node.c: Add font translation feature. + (get_font_translation): New function. + (symbol_fontno): Translate the font name. + (mount_font_no_translate): Rename to mount_font to this. + (mount_font): New function. + (font_family::make_definite): Call mount_font_no_translate instead + of mount_font. + (mount_style): Translate the font name. + (font_translate): New function. + (init_font_requests): Bind "ftr" to font_translate. + + * ps/devps/prologue (SN): New procedure that rounds a position to + the nearest (pixel + (.25,.25)). + (DL): Use SN to round endpoints. + + * lib/version.c: Changed version to 0.5. + +Sat Aug 18 04:43:21 1990 James Clark (jjc at yquem) + + * Makefile: Move definition of PAGE to the very beginning, so that + people are less likely to miss it. + +Fri Aug 17 02:15:11 1990 James Clark (jjc at yquem) + + * man/Makefile: Don't need to sed out @UPCASE_PROG_PREFIX@. + + * troff/env.c (environment::choose_breakpoint): Make `can't find + breakpoint' error a warning of type WARN_BREAK. Change message to + `can't break line'. + * troff/groff.h: Declare WARN_BREAK with code 4; change WARN_INPUT to + code 040000. + * troff/input.c: Add WARN_BREAK to warning_table. Include + WARN_BREAK in DEFAULT_WARNING_MASK. + + * tty/tmac.tty: Add definition of \(+-. + + * groff.sh: Remove `--' option to set command. + + * dvi/devdvi/texsy.map: Remove duplicate md entry. + + * ps/devps/eqnchar: Better definition of cdot using md. + * dvi/devdvi/eqnchar: Likewise. + * xditview/devX100/eqnchar: Likewise. + * xditview/devX75/eqnchar: Likewise. + * eqn/lex.c: Add definition of cdot. + +Thu Aug 16 09:33:57 1990 James Clark (jjc at yquem) + + * troff/input.c (get_optional_char): New function. + * troff/input.c (set_page_character): Use get_optional_char(), + rather than has_arg() and tok.get_char(1). + * troff/env.c (tab_character, leader_character, hyphen_char, + field_characters): Likewise. + (margin_character): Likewise. Also always delete the + margin_character_node. + + * troff/input.c (token::get_char): Use token::description. + + * troff/input.c (has_arg): Don't skip over tab and \}. + * troff/number.c (start_number): Give a warning if the number + starts with \} (WARN_RIGHT_BRACE) or tab (WARN_TAB). + +Wed Aug 15 10:04:37 1990 James Clark (jjc at yquem) + + * troff/input.c (empty_name_warning, non_empty_name_warning): New + functions. + (get_name, get_long_name): Use these. Rename `warn' argument to + `required'. + + * troff/node.c (get_fontno): Test that the symbol is not null. + + * troff/input.c (token::description): New function. + * troff/number.c (parse_term): Use token::description in `numeric + expression expected' message. + * troff/groff.h: Add WARN_MISSING. + * troff/number.c (start_number): New function. + * troff/number.c (get_vunits, get_hunits, get_number, get_integer, + get_incr_number): Use start_number(). + * troff/input.c (DEFAULT_WARNING_MASK): Enable WARN_NUMBER by + default. + * troff/input.c (get_name, get_long_name): Use WARN_MISSING. + * troff/reg.c (alter_format): Use WARN_MISSING. Also use + token::descripion. + * troff/input.c (token::get_char): Use WARN_MISSING. + * troff/input.c (token::delimiter): Use token::description. + * troff/env.c (environment_switch): Back out Aug 3 change. + * troff/input.c (has_arg): Skip over \}s and tabs but give a + warning. + * troff/token.h (token::tab): New function. + * troff/node.c (get_fontno): Use tok.skip() rather than has_arg(). + * troff/reg.c (alter_format): Likewise. + * troff/node.c (bold_font): Use has_arg() rather than tok.skip(). + +Tue Aug 14 10:11:21 1990 James Clark (jjc at yquem) + + * troff (most files): Redo warnings. Divide warnings into various + categories; warning() has an additional first argument indicating + the category it falls into. + * troff/input.c (main): -w now takes an argument. New option -W. + (enable_warning, disable_warning): New functions. + + * ps/devps/afmtodit: Add -a option to lie about the italic angle. + * ps/devps/FontMakefile: Pretend TI has an angle of 7. + +Mon Aug 13 10:11:16 1990 James Clark (jjc at yquem) + + * ps/devps/eqnchar: Better definitions of dotdot, vec, dyad, inf. + * xditview/devX100/eqnchar: Likewise. Remove definition of dot. + * xditview/devX75/eqnchar: Likewise. + * dvi/devdvi/eqnchar: Better definitions of vec, dyad, dotdot. + + * eqn/other.c: When bar or over applies to a single character + don't produce an overline_box or an underline_box. Instead produce + an accent_box or an underaccent_box, with the accent a line + whose width is accent_width. New classes underaccent_box, + overline_char_box and underline_char_box. + * eqn/box.h: Move overline_box, underline_box, accent_box class + declarations into eqn/other.c. Add declarations of + make_underline_box, make_overline_box, make_accent_box. + * eqn/eqn.y: Call make_overline_box, make_underline_box + make_accent_box instead of constructors. + * eqn/pbox.h, eqn/box.c: Add accent_width parameter. + + * eqn/other.c: Add accent_box::~accent_box. + * eqn/box.h: Declare it. + + * groff.sh: With -Tps, use eqn -D. + + * eqn/other.c (overline_box::output): Use \Z. If draw_flag use \D + rather than \l. + (underline_box::output): Similarily. + (accent_box::output): Use \Z. + + * xditview/tmac.X: Add definitions of ~ and ^ (so that they are a + bit smaller.) + +Sun Aug 12 09:41:15 1990 James Clark (jjc at yquem) + + * troff/div.c (top_level_diversion::transparent_output(unsigned + char)): Use asciify. + * troff/input.c (asciify): Don't make it static. + * troff/token.h (asciify): Declare it. + + * troff/input.c (get_name, get_long_name, token::get_char, + token::delimiter): Add an extra default argument which says + whether a warning should be printed. + * troff: Pass a non-zero argument to one of these rather than + printing a warning directly. + +Sat Aug 11 09:02:21 1990 James Clark (jjc at yquem) + + * troff: Consistently use symbol::is_null. + + * troff/dictionary.h: Move some inline functions into + dictionary.c. + + * troff/request.h: Move inline functions into input.c. + (request_or_macro::invoke): Make it pure. + + * troff/input.c, troff/reg.h: New class `constant_int_reg'. + * troff/input.c (init_input_requests): Use class constant_int_reg. + (class compatible_reg): Deleted. + * troff/div.c (init_div_requests): Use class constant_int_reg. + (class last_post_line_extra_space_reg): Deleted. + + * troff/env.c (tab_character): Don't change the tab character if + we get an invalid argument. + (hyphen_char): Similarily. + + * troff/reg.c (alter_format): Check that nm is not null. + + * Makefile, groff.sh: Make it possible to customize the commands + used for printing PostScript and dvi files. Also make it possible + to customize the path used by groff.sh. + + * eqn/eqn.y: Make `left' right associative. + +Fri Aug 10 18:20:39 1990 James Clark (jjc at yquem) + + * pic/pic.h: Added definition of M_SQRT2 for those systems that + don't have it. + + * pic/pic.h: Removed definition of INT_MAX. + + * troff/node.c (italic_corrected_node::vertical_extent): Omit + `return'. + + * troff/input.c (token::next): Handle \R like \n. + +Tue Aug 7 09:46:33 1990 James Clark (jjc at yquem) + + * ps/tmac.pc (PSPIC): Simplify. + + * troff/env.c (tab_stops::to_string): + * pic/pic.y (object_type_name): + * pic/troff.c (simple_output::line): + * pic/tex.c (tex_output::spline): + * pic/object.c (object_spec::make_object): + * tbl/main.c (process_data): Add cases to switch statements to + avoid cfront warnings. (Some of these are spurious, since the + switch already has a default case.) + + * ps/tmac.ps (PSPIC): Reformatted. Prefix all local names with + `ps-'. Don't test systat; instead check number of arguments to + ps-bb. + +Mon Aug 6 00:13:07 1990 James Clark (jjc at yquem) + + * macros/tmac.e: Do not decrease the page offset by 0.5i. + + * ps/ps.c (ps_printer::ps_printer): Use mktemp instead of tempnam. + Unlink the file as soon as we have opened it, so that we don't + have to bother with signal handlers. + (handler): Deleted. + (fatal_error_exit): Deleted. + (main): Don't call signal. + + * dvi/tfmtodit.c: Add -k option so that kerns with the skewchar + can be ignored. + * dvi/devdvi/Makefile: Use the -k option with S and MI. + + * pic/pic.y: If there is a label, or an nth construction before + the first `.' in the argument to `with', ignore it and generate a + warning. + * pic/lex.c (lex_warning): New function. + + * tbl/table.c (table::init_output): In section keep and release + macro, use 0 indent when diverting and the correct indent when + rereading. + + * troff/input.c (interpolate_number_format): Do not interpolate + anything if the number register is not defined. + + * tbl/main.c (process_data): Don't add entry when col >= ncolumns. + +Sat Aug 4 08:12:05 1990 James Clark (jjc at yquem) + + * ps/devps/prologue (PICTURE): Set components of graphics state to + their default values. + + * ps/devps/text.enc: Add trademark + * ps/devps/textmap: Add names for club, spade, heart, diamond, + carriagereturn, suchthat. Use Upsilon1 rather than Upsilon. + * ps/devps/symbolchars: Add names for summation and product. + + * dvi/devdvi/texsy.map: Add names for club, spade, heart, diamond, + suchthat. Add pp. Add upper-case letters. + + * xditview/libXdvi/DviChar.c: Add names for club, spade, heart, + diamond, carriagereturn, suchthat. Use Upsilon1 rather than + Upsilon. + + * dvi/devdvi/texsy.map: Rename lA (left angle bracket) to la, and + rA (right angle bracket) to ra. Introduce names for double-headed + arrows and double-barred arrows: <>, va, lA, rA, hA, uA, dA, vA. + * ps/devps/textmap: Likewise for ps device. + * xditview/libXdvi/DviChar.c: Likewise for X100 and X75 devices. + * tty/devascii/R.proto: Rename lA to la and rA to ra. + * tty/devascii/R.proto: Likewise. + * tty/tmac.tty: Provide definitions for \(<>, \(lA, \(rA, \(hA, + \(uA, \(dA. + * eqn/delim.c: In delim_table, rename \(lA to \(la and \(rA to \(ra. + + * xditview/tmac.X: Add definitions for \(fi \(fl \(ff \(Fi \(Fl. + + * eqn/lex.c: Added definitions of `approx', `grad' and `del' to + def_table. + +Fri Aug 3 09:59:27 1990 James Clark (jjc at yquem) + + * troff/div.c (when_request): Use symbol::is_null rather than + has_arg to determine whether we have an argument. + (change_trap): Remove the trap if we get an invalid number. Give + an error if we don't get at least the macro name. + (diversion_trap): Remove trap if we get an invalid name or number. + + * troff/env.c (environment_switch): Pop if we get an invalid + symbol or numeric expression. + + * troff/input.c (do_define_macro): If EOF is encoutered while + defining the macro, do tok.next() before returning. + + * troff/token.h (has_arg): Move definition from here, to ... + * troff/input.c (has_arg): ... here + + * troff/env.c (space_size): Do nothing if we get an invalid argument. + * troff/input.c (shift): Likewise. + + * pic/lex.c (get_token_after_dot): Accept `.center' as a synonym + for `.c'. + + * pic/troff.c (troff_output::start_picture): Comment out calls to + `..'. + + * eqn/main.c (do_file): Subtract 1 from current_lineno if + interpret_lf_args succeeds. + + * eqn/main.c (do_file): Don't recognize delimiter if preceded by + \\. This avoids problems with \$N. + + * groff.sh: Pass -C to preprocessors. + + * lib/lf.c (interpret_lf_args): Be more flexible. + + * tbl/main.c (main): Add -C option. + (table_input::get): Do not recognize TE if followed by character + other than a space or newline unless -C option given. + (process_input_file): Likewise for lf, TS. + (process_data): Likewise for lf in text blocks. + + * eqn/main.c (main): Add -C option. + (do_file): Don't recognize EQ, EN or lf if followed by character + other than space or newline unless -C option given. + * eqn/lex.c (file_input::read_line): Similarily. + * eqn/eqn.h: Declare compatible_flag. + + * etc/soelim.c (main): Add -C option. + (interpret_lf_args): Use version in libgroff. + (do_file): + + * pic/main.c (main): Add -C option, which sets compatible_flag. + (top_input::get), (top_input::peek): If -C option not given, + do not recognize .PS/.PE/.PF/.lf if followed by a character + other than space or newline. + * pic/lex.c (file_input::read_line): Similarily. + * pic/pic.h: Add declaration of compatible_flag. + +Thu Aug 2 11:11:27 1990 James Clark (jjc at yquem) + + * ps/tmac.ps (PSPIC): Avoid use of `echo -n'. + + * troff/node.c, troff/node.h: Add `asciify' methods to classes + derived from node. New class space_char_hmotion_node. + * troff/input.c (asciify_macro): New function. + * troff/input.c (init_input_requests): New request `asciify' bound + to asciify_macro. + * macros/mm.diff: New file. + * Makefile: In install.mm target use `patch' to apply + macros/mm.diff. + + * troff/input.c (macro::print_size): Just print the size in bytes. + + * troff/div.c (return_request): Correct the argument + interpretation. + +Wed Aug 1 12:38:36 1990 James Clark (jjc at yquem) + + * troff/node.h (class composite_node): Add sz member. + * troff/node.c (composite_node::size): Return sz. + * troff/input.c (macro_to_node): Use the initial size in the + environment as the size of the composite_node. + + * troff/node.c (node::zero_width_tprint): Provide a reasonable + default. + +Tue Jul 31 10:07:10 1990 James Clark (jjc at yquem) + + * troff/div.c (change_trap): If we get a bad number expression, + do nothing. + +Mon Jul 30 10:30:49 1990 James Clark (jjc at yquem) + + * lib/matherr.c (matherr): Define this only if math.h defines + TLOSS. + +Sun Jul 29 10:34:27 1990 James Clark (jjc at yquem) + + * troff/div.c (macro_diversion::distance_to_next_trap): If there + no diversion trap return vunits(INT_MAX - vresolution). + +Sat Jul 28 14:28:14 1990 James Clark (jjc at yquem) + + * troff/input.c (do_zero_width): New implementation that doesn't + use a temporary environment. Use instead: + (token::add_to_node_list): New function. + * troff/env.c (environment::get_prev_char_height), + (environment::get_prev_char_height), + (environment::get_prev_char_skew): New functions. + (environment::get_prev_char): New function. + (environment::get_prev_char_width): Change to use get_prev_char. + (init_env_request): Implement new registers .cht, .cdp, .csk. + * eqn/sqrt.c (sqrt_box::output): Don't rely upon the argument to + \Z being processed in a separate environment. + +Fri Jul 27 10:21:25 1990 James Clark (jjc at yquem) + + * tbl/table.c: Removed TABLE_BOTTOM_REG. + + * tbl/table.c (table::init_output): In the section release macro, + give a warning message if the section won't fit on one page. + + * tbl/table.c (table::do_top): Emit table keep only if table is + boxed. + (table::do_bottom): Likewise for table release. + (table::table), (table::add_vertical_rule): Remove reference to + keep member. + * tbl/table.h: Remove keep member. + + * tbl/table.c: New register SUPPRESS_BOTTOM_REG. In + SECTION_RELEASE_MACRO, if there's not enough space before the next + trap to output the diversion, call T# ourselves, set + SUPPRESS_BOTTOM_REG to 1, spring the trap, then set + SUPPRESS_BOTTOM_REG back to 0. In T#, do nothing if + SUPPRESS_BOTTOM_REG is non-zero. In T#, always mark the current + vertical position and return to it before turning traps on again. + +Thu Jul 26 02:54:32 1990 James Clark (jjc at yquem) + + * troff/node.c, troff/node.h: In classes derived from node, + replace prev_char_width method by last_char_node method. + * troff/env.c (environment::get_prev_char_width): Use + node::last_char_node rather than node::get_prev_char_width. + + * Makefile: Added comment about -fno-inline on 68030-based + Apollos. + + * troff/reg.c (number_format_to_ascii), eqn/delim.c (DELIM_TABLE_SIZE), + tty/tty.c (tty_font::load_tty_font), dvi/tfmtodit.c (main): Cast + expressions using sizeof to int. + * dvi/dvi.c (dvi_font::handle_x_command): Avoid long->int warnings. + + * macros/tmac.e (TS): Don't move @f back past the current + position. + +Wed Jul 25 09:11:08 1990 James Clark (jjc at yquem) + + * ps/ps.c (main): Buffer stderr. + * dvi/dvi.c (main): Likewise. + * tty/tty.c (main): Likewise. + + * ps/ps.c (ps_printer::do_import): Improve error handling. + + * troff/input.c (abort_request): Use asciify. + + * driver/printer.h (printer::draw), driver/printer.c (printer::draw), + ps/ps.c (ps_printer::draw), dvi/dvi.c (dvi_printer::draw): Make + type of first argument int rather than char. This works around a + bug on the 68030 based Apollo using g++ 1.37.1. + + * tbl/table.h (class table): Add `keep' member. + * tbl/table.c (table::table): Initialize `keep'. + (table::add_vertical_rule): Set `keep' to 1. + (table::do_top): Only emit table keep macro is `keep' is non-zero. + (table::do_bottom): Likewise for table release macro. + (table::do_row): Emit section keep macro even if the row is 0. + +Tue Jul 24 08:35:07 1990 James Clark (jjc at yquem) + + * macros/tmac.e (@C): Preserve the font family across the change + in environments. + +Mon Jul 23 10:15:23 1990 James Clark (jjc at yquem) + + * lib/font.c: Initialize font::hor and font::vert to 1. + (font::load_desc): Check the values of font::hor and font::vert. + + * lib/lib.h: Added definition of INT_DIGITS. Fix it so that it can + be included in a C compilation. + (iftoa): Use INT_DIGITS. Include lib.h. + (itoa): Likewise. + (as_string): Likewise. + * tbl/table.c: Removed definition of INT_DIGITS. + * eqn/box.c (box::top_level): Use INT_DIGITS + 1 instead of 12. + * troff/input.c (input_input_requests): Likewise. + * ps/ps.c (make_encoding_name): Likewise. + (ps_printer::set_style): Likewise. + (ps_output::put_number): Use 1 + INT_DIGITS + 1 instead of 12. + + * tty/devascii/R.proto: Map fm onto '. + * tty/devlatin1/R.proto: Likewise. + +Sat Jul 21 12:45:07 1990 James Clark (jjc at yquem) + + * tbl/table.c: Use ' instead of DELIMITER_CHAR in places where the + argument to \w is at a different input level. + + * tbl/table.c (table::init_output): Define a new macro + REPEATED_VPT_MACRO, like vpt but if in a diversion also + transparently outputs itself. + (table::define_bottom_macro): Use REPEATED_VPT_MACRO instead of + vpt. + (table::do_row): Likewise. + + * tbl/table.c (vertical_rule::print): Prefix the .sp -1 line with + TRANSPARENT_STRING_NAME. + + * tbl/table.c (table::init_output): In the table release macro + print an error message and don't produce any output if after + issuing the need request the table still will not fit. Also + remove the diversion after bringing it back. + + * tbl/table.c (table::init_output): Define a new macro + REPEATED_MARK_MACRO, like mk but if in a diversion also + transparently outputs itself. + (table::do_row): Mark row_top_reg using REPEATED_MARK_MACRO. This + is necessary because .TH might not call .T#. + (table::do_top): Likewise TOP_REG. + (table::define_bottom_macro): If TOP_REG is no longer valid, use + #T - DOUBLE_LINE_SEP rather than #T. This is necessary because the + table header might contain just the two top rules. + +Fri Jul 20 10:51:42 1990 James Clark (jjc at yquem) + + * troff/div.c: Implement new request `ptr' to print all traps. + + * troff/env.c (init_env_requests): Implement `.tabs' reg with + init_string_env_reg. + * troff/env.c (class tab_reg): Deleted. + +Thu Jul 19 12:07:16 1990 James Clark (jjc at yquem) + + * troff/div.c: New number register .pn returns the number of the + next page as set by the pn request. + + * macros/tmac.an: Redid headers and footers. Number each manual + entry starting from 1 unless \nC is > 0, like Sun. Added an + optional 5th argument to .TH which specifies the manual name and + appears in the center of the header. Understand the X, P and D + registers like Sun. + +Wed Jul 18 10:23:31 1990 James Clark (jjc at yquem) + + * troff/env.c (init_env_requests): New number register `.lt' to + return the title length. + + * troff/node.h (class transparent_dummy_node): New class. + * troff/node.c (class transparent_dummy_node): Provide member + functions. + * troff/env.c (interrupt): Add a transparent_dummy_node, rather + than a dummy_node. + + * troff/input.c (token::next): New escape sequence \). + * troff/input.c (get_copy): Recognize \) in copy mode. + + * troff/input.c (input_stack::clear): New function. + * troff/input.c (exit_request): Use input_stack::clear. + + * troff/token.h: Removed TOKEN_NO_PRINT_CHAR. + * troff/input.c (token::process): Removed case TOKEN_NO_PRINT_CHAR. + + * troff/env.c: Move set_page_character to input.c. Move + page_character to input.c also. + * troff/env.c (title): Split off the reading of the parts of the + title into read_title_parts. + * troff/input.c (read_title_parts): New function. Check the + input_level when testing whether a token matches the delimiter. + + * troff/input.c (exit_request): New function. + * troff/input.c (init_input_requests): Bind ex request to + exit_request rather than exit_groff. + + * troff/input.c (exit_groff): Call tok.next() before + process_input_stack(). + +Mon Jul 16 09:47:23 1990 James Clark (jjc at yquem) + + * troff/env.c: ifdef widow control support on WIDOW_CONTROL. + * troff/env.h: ditto. + * troff/input.c: ditto. + + * troff/env.c (environment::is_empty): Test pending_lines. + + * troff/env.c (environment::have_pending_lines): Removed. + + * troff/input.c: Add request to flush pending lines from the + environment. + + * troff/env.c, troff/env.h: Add automatic widow control feature. + + * troff/input.c (exit_groff): Do process_input_stack() after + do_break() but before setting exit_flag to 2. + + * troff/input.c: Remove FLUSH_PENDING_LINES and + TOKEN_FLUSH_PENDING_LINES. Instead, flush pending lines from + environment after END_TRAP token seen, but only if there aren't + any more traps still unfinished. + * troff/token.h: Remove TOKEN_FLUSH_PENDING_LINES. + +Sun Jul 15 10:50:08 1990 James Clark (jjc at yquem) + + * troff/env.c: Rename the `retain_size' member of class + pending_output_line to `no_fill'. + + * troff/env.c (title): When the line is output, make the + retain_size argument !fill. + + * troff/node.h: Add `hyphenated' member to struct breakpoint. + * troff/node.c (space_node::get_breakpoints), + (dbreak_node::get_breakpoints): Fill this in. + * troff/env.c: Allow specification of maximum number of + consecutive hyphenated lines. + + * troff/env.c (environment::is_empty): Add test for !current_tab. + +Sat Jul 14 11:23:01 1990 James Clark (jjc at yquem) + + * troff/env.c (environment::hyphenate_line): Don't completely give + up if the word is not to be hyphenated; continue so that breaks + can be made at break_char_node's. + + * lib/lib.h: Only define INT_MAX if it's not already defined; + undef INT_MIN if it's already defined. + + * Makefile: Make it easy to define CFRONT_ANSI_BUG. + + * lib/lib.h: If CFRONT_ANSI_BUG is defined, cast INT_MIN to long. + This works around a bug in AT&T C++ 2.0 used with an ANSI C + compiler. + + * macros/tmac.an (an-header): Set no-space mode. + + * macros/tmac.an (TH): Start a new page if necessary. + + * Started using ChangeLog at version 0.4. + +Local Variables: +version-control: never +End: diff --git a/gnu/usr.bin/groff/Makefile b/gnu/usr.bin/groff/Makefile new file mode 100644 index 0000000000..b6d02e1db0 --- /dev/null +++ b/gnu/usr.bin/groff/Makefile @@ -0,0 +1,13 @@ +# Makefile for groff + +SUBDIR= libgroff libdriver libbib\ + groff troff nroff tbl pic eqn grops grotty grodvi\ + refer lookbib indxbib lkbib \ + tfmtodit addftinfo pfbtops psbb \ + devices tmac mm man \ + xditview + +# BSD already provides soelim +MISC= soelim + +.include diff --git a/gnu/usr.bin/groff/Makefile.cfg b/gnu/usr.bin/groff/Makefile.cfg new file mode 100644 index 0000000000..3df6c85e74 --- /dev/null +++ b/gnu/usr.bin/groff/Makefile.cfg @@ -0,0 +1,38 @@ +# Libraries +.if defined(NOOBJ) +LIBGROFF= $(.CURDIR)/../libgroff/libgroff.a +LIBDRIVER= $(.CURDIR)/../libdriver/libdriver.a +LIBBIB= $(.CURDIR)/../libbib/libbib.a +.else +LIBGROFF= $(.CURDIR)/../libgroff/obj/libgroff.a +LIBDRIVER= $(.CURDIR)/../libdriver/obj/libdriver.a +LIBBIB= $(.CURDIR)/../libbib/obj/libbib.a +.endif + +CC= gcc +CFLAGS+= -DHAVE_UNISTD_H=1\ + -DHAVE_DIRENT_H=1\ + -DHAVE_LIMITS_H=1\ + -DHAVE_STDLIB_H=1\ + -DHAVE_SYS_DIR_H=1\ + -DHAVE_CC_LIMITS_H=1\ + -DHAVE_CC_UNISTD_H=1\ + -DSTDLIB_H_DECLARES_GETOPT=1\ + -DUNISTD_H_DECLARES_GETOPT=1\ + -DSTDLIB_H_DECLARES_PUTENV=1\ + -DRETSIGTYPE=void\ + -DHAVE_MMAP=1\ + -DHAVE_RENAME=1\ + -DHAVE_MKSTEMP=1\ + -DHAVE_SYS_SIGLIST=1\ + -DARRAY_DELETE_NEEDS_SIZE=1 + + +.SUFFIXES: .cc +.cc.o: + $(CC) $(CFLAGS) -c $(.IMPSRC) + +.y.cc: + $(YACC) $(YFLAGS) $(.IMPSRC) + mv y.tab.c $(.PREFIX).cc + mv y.tab.h $(.PREFIX).tab.h diff --git a/gnu/usr.bin/groff/NEWS b/gnu/usr.bin/groff/NEWS new file mode 100644 index 0000000000..bbe0c0b510 --- /dev/null +++ b/gnu/usr.bin/groff/NEWS @@ -0,0 +1,662 @@ +This file describes recent user-visible changes in groff. Bug fixes +are not described. There are more details in the man pages. + +VERSION 1.08 +============ + +Troff +----- + +The escape sequence \V[xxx] will interpolate the value of the +environment variable xxx. + +Tbl +--- + +The decimalpoint option can be used to specify the character to be +recognized as the decimal point character in place of the default +period. + +VERSION 1.07 +============ + +Groff +----- + +The environment variable GROFF_COMMAND_PREFIX can be used to control +whether groff looks for `gtroff' or `troff' (similarily for the +preprocessors.) + +Troff +----- + +Multilingual hyphenation is supported by new `hpf' and `hla' requests, +and by a `\n[.hla]' number register. The -H option has been removed. +Files of hyphenation patterns can have comments. + +When a font cannot be found, troff gives a warning (of type `font', +enabled by default) instead of an error. + +There's a new request `trnt' that's like `tr' except that it doesn't +apply to text transparently throughput into a diversion with \!. + +Tbl +--- + +There is a `nokeep' option which tells tbl not to use diversions to +try to keep the table on one page. + +Eqn +--- + +Setting the parameter `nroff' to a non-zero value causes `ndefine' to +behave like `define' and `tdefine' to be ignored. This is done by +eqnrc when the current device is ascii or latin1. There's a `neqn' +script that just does `eqn -Tascii'. + +Grotty +------ + +grotty uses whatever page length was specified using the `pl' request +rather than using the paperlength command in the DESC file. The +paperwidth command in the DESC file is also ignored. + +VERSION 1.06 +============ + +The programs in groff that have Unix counterparts can now be installed +without a leading `g' prefix. See the `g' variable in the Makefile. + +The g?nroff script simulates the nroff command using groff. + +New special characters \(+h, \(+f, \(+p, \(Fn, \(Bq, \(bq, \(aq, \(lz, +\(an. See groff_char(7). + +^L is now a legal input character. + +Groff +----- + +The Xps pseudo-device has disappeared. Instead there is a new -X +option that tells groff to use gxditview instead of the usual +postprocessor. (So instead of -TXps, use -XTps or just -X if your +default device is ps.) + +The postprocessor to be used for a particular device is now specified +by a `postpro' command in the DESC file rather than being compiled +into groff. Similarily the command to be used for printing (with the +-l option) is now specified by a `print' command in the DESC file. + +The groff command no longer specifies eqnchar as an input file for +eqn. Instead eqn automatically loads a file `eqnrc'. The groff +command no longer passes the -D option to eqn. Instead eqnrc sets the +draw_lines parameter. + +The groff command no longer tells troff to load a device-specific +macro file. This is handled instead by the `troffrc' file, which is +always loaded by troff. + +The shell script version of groff has been removed. + +Troff +----- + +The `rchar' request removes a character definition established with `char'. + +Compatibility mode is disabled and the escape character is set to `\' +while a character definition is being processed. + +The `\#' escape sequence is like `\%' except that the terminating +newline is ignored. + +The `shc' request tells troff which character to insert (instead of +the default \(hy) when a word is hyphenated at a line break. + +A font name of 0 (zero) in the DESC file will cause no font to be +mounted on the corresponding font position. This is useful for +arranging that special fonts are mounted on positions on which users +are not likely explicitly to mount fonts. All groff devices now avoid +initially mounting fonts on positions 5-9. + +The `do' request allows a single request or macro to be interpreted +with compatibility mode disabled. + +troff automatically loads a file `troffrc' before any other input file. +This can be prevented with the -R option. This file is responsible +for loading the device-specific macros. + +Pic +--- + +The -x option has been removed and a -n option has been added. By +default, pic now assumes that the postprocessor supports groff +extensions. The -n option tells pic to generate output that works +with ditroff drivers. The -z option now applies only to TeX mode. + +The -p option has been removed. Instead if the -n option is not +specified, pic generates output that uses \X'ps: ...' if the \n(0p +register is non-zero and tmac.ps sets this register to 1. + +In places where you could 1st or 5th you can now say `i'th or `i+1'th +(the quotes are required). + +Eqn +--- + +Eqn now automatically reads a file `eqnrc' from the macro directory. +This performs the same role that the eqnchar files used to. This can +be prevented by the -R option. + +Setting the draw_lines parameter to a non-zero value causes lines to +be drawn using \D rather than \l. The -D option is now obsolete. + +`uparrow', `downarrow' and `updownarrow' can be used with `left' and +`right'. + +The amount of extra space added before and after lines containing +equations can be controlled using the `body_height' and `body_depth' +parameters. + +Grops +----- + +Font description files have been regenerated from newer AFM files. +You can get access to the additional characters present in the text +fonts in newer PostScript printers by using -mpsnew. + +The default value of the -b option is specified by a `broken' command +in the DESC file. + +With the -g option, grops will generate PostScript code that guesses +the page height. This allows documents to be printed on both letter +(8.5x11) and A4 paper without change. + +Grodvi +------ + +ISO Latin-1 characters are available with -Tdvi. Format groff_char(7) +with groff -Tdvi for more information. + +Grotty +------ + +The -mtty-char macros contain additional character definitions for +use with grotty. + +Macros +------ + +In previous releases the groff -me macros treated the $r and $R number +registers in a way that was incompatible with the BSD -me macros. The +reason for this was that the approach used by the BSD -me macros does +not work with low resolution devices such as -TX75 and -TX100. +However, this caused problems with existing -me documents. In this +release, the vertical spacing is controlled by the $v and $V registers +which have the same meaning as $r and $R in earlier groff releases. +In addition, if the $r or $R register is set to a value that would be +correct for for the BSD -me macros and a low resolution device is not +being used, then an appropriate value for the $v or $V register will +be derived from the $r or $R register. + +The groff -me macros work with -C and (I think) with Unix troff. + +For backward compatibility with BSD -me, the \*{ and \*} strings are +also available as \*[ and \*]. Of course, \*[ will only be useable +with -C. + +The \*T string has been deleted. Use \*(Tm instead. + +Xditview +-------- + +The `n', Space and Return keys are bound to the Next Page action. The +`p', BackSpace and Delete keys are bound to the Previous Page action. +The `q' key is bound to the Quit action. + +The `r' key is bound to a rerasterize action that reruns groff, and +redisplays the current page. + +VERSION 1.05 +============ + +Pic +--- + +There is a alternative assignment operator `:=' which interacts +differently with blocks. + +There is a new command `command', which allows the values of variables +to be passed through to troff or TeX. + +The `print' command now accepts multiple arguments. + +String comparison expressions (using `==' or `!=') are allowed in more +contexts. + +Grotty +------ + +Horizontal and vertical lines drawn with \D'l ...' will be rendered +using -, | and + characters. This is intended to give reasonable +results with boxed tables. It won't work well with pic. + +Macros +------ + +The -mdoc macros have been upgraded to the version in the second +Berkeley networking release. This version is not completely +compatible with earlier versions; the old version is still available +as -mdoc.old. The grog script has been enhanced so that it can +usually determine whether a document requires the old or new versions. + +With -TX75, -TX100 and -TXps, the PSPIC macro will produce a box +around where the picture would appear with -Tps. + +VERSION 1.04 +============ + +An implementation of the -mm macros is included. + +The directory in which temporary files are created can be controlled +by setting the GROFF_TMPDIR or TMPDIR environment variables. + +Pic +--- + +Some MS-DOS support (see pic/make-dos-dist). + +Grops +----- + +There are two new \X commands (\X'ps: invis' and \X'ps: endinvis') +which make it possible to have substitute characters that are +displayed when previewing with -TXps but ignored when printing with +grops. + +Xditview +-------- + +Support for scalable fonts. + +VERSION 1.03 +============ + +No changes other than bug fixes. + +VERSION 1.02 +============ + +There is an implementation of refer and associated programs. groff -R +preprocesses with grefer; no mechanism is provided for passing +arguments to grefer because most grefer options have equivalent +commands which can be included in the file. grog also supports refer. + +There is an alternative perl implementation of the grog script. + +The code field in lines in the charset section of font description +files is now allowed to contain an arbitrary integer (previously it +was required to lie between 0 and 255). Currently grops and grodvi +use only the low order 8 bits of the value. Grodvi will use the +complete value; however, this is unlikely to be useful with +traditional TeX tools (.tfm files only allow 8 bit character codes.) + +Left and right double quotes can be obtained with \(lq and \(rq +respectively. + +There is a new program called pfbtops which translates PostScript +fonts in pfb format to ASCII. + +A slightly modified version of the Berkeley tmac.doc is included. + +Troff +----- + +In long escape names the closing ] is now required to be at the same +input level as the opening [. + +The \A'S' escape sequence returns 1 or 0 according as S is or is not +suitable for use as a name. + +\~ produces an unbreakable space that can be stretched when the line +is adjusted. + +The `mso' request is like the `so' request except that it searches for +the file in the same directories in which tmac.X is searched for when +the -mX option is given. + +The escape sequence `\R' is similar to the `nr' request. + +Eqn +--- + +A new `special' primitive allows you to add new types of unary +constructs by writing a troff macro. + +Pic +--- + +The implementation no longer uses gperf. + +Grops +----- + +The compile-time -DBROKEN_SPOOLER option has been replaced by a +BROKEN_SPOOLER_FLAGS option. This allows more precise control over +how grops should workaround broken spoolers and previewers. There is +a new -b option that can change this at run-time. + +Grops now generates PostScript that complies with version 3.0 of the +Document Structuring Convention. + +The resource management component of grops (the part that deals with +imported documents and downloadable fonts) has been rewritten and now +supports version 3.0 of the Document Structuring Conventions. The +%%DocumentFonts comment is no longer supported; you must use the +%%Document{Needed,Supplied}{Fonts,Resources} comments instead +(or as well.) + +tmac.psatk contains some macros that support the mechanism used by the +Andrew Toolkit for including PostScript graphics in troff documents. + +Xditview +-------- + +Parts of xditview have been rewritten so that it can be used with the +output of gtroff -Tps. groff -TXps will run gtroff -Tps with +gxditview. + +There is a new menu entry `Print' which brings up a dialog box for +specifying a command with which the file being previewed should be +printed. + +Xditview now uses imake. + +VERSION 1.01 +============ + +The groff command now understands the gtroff `-a' and `-i' options. + +With the `m' and `n' scale indicators, the scale factor is rounded +horizontally before being applied. This makes (almost) no difference +for devices with `hor' equal to 1, but it makes groff with -Tascii or +-Tlatin1 behave more like nroff in its treatment of these scale +indicators. Accordingly tmac.tty now calls the `nroff' request so +that the `n' condition will be true. + +The device-specific macros (tmac.ps, tmac.dvi, tmac.tty and tmac.X) +have been made to work at least somewhat with -C. In particular the +special characters defined by these macros now work with -C. + +groff -Tdvi -p will now pass pic the -x flag; this will enable filling +of arrowheads and boxes, provided that your dvi driver supports the +latest version of the tpic specials. + +Eqn +--- + +There is a new `-N' option that tells eqn not to allow newlines in +delimiters. This allows eqn to recover better from missing closing +delimiters. The groff command will pass on a `-N' option to eqn. + +Grops +----- + +You can now use psfig with grops. See the file ps/psfig.diff. I do +not recommend using psfig for new documents. + +The command \X'ps: file F' is similar to \X'ps: exec ...' except that +the PostScript code is read from the file F instead of being contained +within the \X command. This was added to support psfig. + +Grodvi +------ + +There are font files HB and HI corresponding to cmsssbx10 and cmssi10. + +Macros +------ + +The groff -me macros now work with the -C option. As a result, they +may also work with Unix nroff/troff. + +In -me, the $r and $R number registers now contain the line spacing as +a percentage of the pointsize expressed in units (normally about 120). +The previous definition was useless with low resolution devices such +as X75 and X100. + +VERSION 1.00 +============ + +A -ms-like macro-package is now included. + +The name for the Icelandic lowercase eth character has been changed +from \(-d to \(Sd. + +Troff +----- + +There is a new request `nroff', which makes the `n' built-in condition +true and the `t' built-in condition false; also a new request `troff' +which undoes the effect of the `nroff' request. This is intended only +for backward compatibility: it is usually better to test \n(.H or +\n(.V or to use the `c' built-in condition. + +The \R escape sequence has been deleted. Use \E instead. + +There are `break' and `continue' requests for use with the `while' +request. + +There is a request `hym' that can ensure that when the current +adjustment mode is not `b' a line will not be hyphenated if it is no +more than a given amount short, and a request `hys' that can ensure +that when the current adjustment mode is `b' a line will not be +hyphenated if it can be justified by adding no more than a given +amount of extra space to each word space. + +There is a request `rj' similar to `ce' that right justifies lines. + +A warning of type `space' will be given when a call is made to an +undefined request or macro with a name longer than two characters, and +the first two characters of the name make a name that is defined. +This is intended to find places where a space has been omitted been a +request or macro and its argument. This type of warning is enabled by +default. + +Pic +--- + +A comma is permitted between the arguments to the `reset' command. + +For use with TeX, there is a new `-c' option that makes gpic treat +lines beginning with `.' in a way that is more compatible with tpic +(but ugly). + +Eqn +--- + +It is no longer necessary to add `space 0' at the beginning of +complicated equations inside pictures. + +`prime' is now treated as an ordinary character, as in Unix eqn. The +previous behaviour of `prime' as an operator can now be obtained using +`opprime'. + +Xditview +-------- + +There are two new devices X75-12 and X100-12 which are the same as X75 +and X100 except that they are optimized for documents that use mostly +12 point text. + +VERSION 0.6 +=========== + +The installation process has been refined to make it easy for you to +share groff with someone who has the same type of machine as you but +does not have a C++ compiler. See the end of the INSTALL file for +details. + +There is a man page for the tfmtodit program which explains how to use +your own fonts with groff -Tdvi. + +There is a man page for afmtodit which explains how to use your own +PostScript fonts with groff -Tps. + +The \N escape sequence is now fully supported. It can now be used to +access any character in a font by its output code, even if it doesn't +have a groff name. This is made possible by a convention in the font +files that a character name of `---' refers to an unnamed character. +The drivers now all support the `N' command required for this. The font +description files have been updated to include unnamed characters. + +The `x' command in font description files has been removed: instead +any unknown commands are automatically made available to the drivers. +If you constructed your own font files with an earlier version of +tfmtodit or afmtodit, you must construct them again using the current +version. + +Characters between 0200 and 0237 octal are no longer legal input +characters. Note that these are not used in ISO 8859. + +A command called `grog' has been added, similar to the `doctype' +command described in Kernighan and Pike. + +Groff +----- + +The groff command has some new options: -V prints the pipeline +instead of executing it; -P passes an argument to the postprocessor, +-L passes an argument to the spooler. + +There is a C++ implementation of the groff command. This handles some +things slightly better than the shell script. In particular, it can +correctly handle arguments containing characters that have a special +meaning to the shell; it can give an error message when child +processes other than the last in the pipeline terminate abnormally; +its exit status can take account of the exit statuses of all its child +processes; it is a little more efficient; when geqn is used, it +searches for the eqnchar file in the same way that font metric files +are searched for, rather than expecting to find it in one particular +directory. + +Gtroff +------ + +There is font translation feature: For example, you can tell gtroff to +use font `HR' whenever font `H' is requested with the line + .ftr H HR +This would be useful for a document that uses `H' to refer to +Helvetica. + +There are some new number registers: `.kern' contains the current kern +mode, `.lg' the current ligature mode, `.x' the major version number, +`.y' the minor version number, `.ce' the number of lines to be +centered in the current environment, `.trunc' the amount of vertical +space truncated by the most recently sprung vertical position trap, +`.ne' the amount of vertical space needed in the last `ne' request +that caused a vertical position trap to be sprung. + +The `cf' request now behaves sensibly in a diversion. If used in a +diversion, it will now arrange for the file to be copied to the output +when the diversion is reread. + +There is a new request `trf' (transparent file) similar to `cf', but +more like `\!'. + +There is a new escape sequence `\Y[xxx]', roughly equivalent to +`\X'\*[xxx]'', except that the contents of string or macro xxx are not +interpreted, and xxx may contain newlines. This requires an output +format extension; the drivers have been modified to understand this. +Grops has also been modified to cope with newlines in the arguments to +\X commands; grops has a new \X command mdef, which is like def except +that it has a first argument giving the number of definitions. + +There is a new warning category `escape' which warns about unknown +escape sequences. + +The `fp' request now takes an optional third argument giving the external +name of the font. + +The `\_' character is now automatically translated to `\(ul' as in troff. + +The environment variable `GROFF_HYPHEN' gives the name of the file +containing the hyphenation patterns. + +There is a `\C'xxx'' escape sequence equivalent to `\[xxx]'. + +Characters ", ', ), ], *, \(dg are now initially transparent for the purposes +of end of sentence recognition. + +There is an anti-recusion feature in the `char' request, so you can +say `.char \(bu \s+2\(bu\s-2'. + +The limit on the number of font positions has been removed. +Accordingly `\n[.fp]' never returns 0. + +The restriction on the number of numbered environments has been removed. + +There is a new escape sequence `\E' that makes it possible to +guarantee that an escape sequence won't get interpreted in copy-mode. +The `\R' escape sequence is accordingly now deprecated. + +Gpic +---- + +Arguments of the form `X anything X' (in the `copy thru', `sh', `for', +`if' and `define' constructs) can now be of the form `{ anything }'. + +If the `linethick' variable is negative (as it now is initially), +lines will be drawn with a thickness proportional to the current point +size. + +The `rand' function now takes no arguments and returns a number between +0 and 1. The old syntax is still supported. + +`^' can be used in expressions to indicate exponentiation. + +In the `for' construct the argument to the by clause can be prefixed +by `*' to indicate that the increment is multiplicative. + +A bare expression may be used as an attribute. If the current +direction is `dir', then an attribute `expr' is equivalent to +`dir expr' + +There is a `sprintf' construct that allows numbers to be formatted and used +wherever a quoted string can be used. + +The height of a text object without an explicit height attribute is +the number of text strings associated with the object times the value +of the `textht' variable. + +The maximum height and width of a picture is controlled by the +`maxpswid' and `maxpsht' variables. + +Gtbl +---- + +Gtbl can now handle gracefully the situation where the `ce' request +has been applied to a table. + +Geqn +---- + +The `ifdef' primitive has been generalized. + +A tilde accent can be put underneath a box using `utilde'. This +defined using a general `uaccent' primitive. + +Grops +----- + +There is a new PostScript font downloading scheme which handles font +downloading for imported illustrations. Previously, the name of the +file containing the font was given in the `x download' line in the +groff font metric file. Now, there is a `download' file which says +for each PostScript font name which file contains that font. Grops +can also now handle inter-font dependencies, where one downloadable +font depends on some other (possibly downloadable) font. + +The `T' font has been removed. The characters it used to provide are +now provided by `char' definitions in tmac.ps. TSymbol.ps has also +been removed, and the tweaks it provided are now provided by `char' +definitions. diff --git a/gnu/usr.bin/groff/PROBLEMS b/gnu/usr.bin/groff/PROBLEMS new file mode 100644 index 0000000000..16e168c86f --- /dev/null +++ b/gnu/usr.bin/groff/PROBLEMS @@ -0,0 +1,458 @@ +This file describes various problems that have been encountered in +compiling, installing and running groff. Suggestions for additions or +other improvements to this file are welcome. + +* gcc 2.3.3 fails to compile pic/object.cc. + +Apply the following patch: + +Thu Apr 1 12:06:03 1993 Brendan Kehoe (brendan@lisa.cygnus.com) + + * cp-init.c (expand_default_init): Don't clear DECL_REGISTER. + +*** cp-init.c.~2~ Mon Mar 29 21:48:36 1993 +--- cp-init.c Thu Apr 1 12:00:33 1993 +*************** expand_default_init (binfo, true_exp, ex +*** 1141,1149 **** + } + +- /* ARM $7.1.1: "[register] may be ignored and in most implementations +- it will be ignored if the address of the variable is taken." +- Since we're likely to do just that in the ctor call, clear this. */ +- DECL_REGISTER (exp) = 0; +- + rval = build_method_call (exp, constructor_name (type), + parms, binfo, flags|xxref_init_possible); +--- 1141,1144 ---- + + +* On a DECstation or other machine using a MIPS cpu, gcc/g++ 2.2.2 +gets a fatal signal while compiling tbl/main.c and tbl/table.c. + +Upgrade to gcc 2.3 or compile those files without -O. + +* I get lots of `numeric overflow' error messages whenever I run +groff; I compiled groff with AT&T C++ 2.0 with an ANSI C compiler. + +Make sure -DCFRONT_ANSI_BUG is included in DEFINES in the top-level +Makefile. If that doesn't solve the problem, define INT_MIN as +-INT_MAX in libgroff/lib.h. + +* I get errors when I try to compile groff with Sun C++. + +Groff requires header files that are moderately compatible with AT&T +C++ and ANSI C. With some versions of Sun C++, the supplied header +files need some of the following changes to meet this requirement: + must declare the mem* functions, (just add `#include +' to ); the first argument to fopen and freopen +should be declared as `const char *'; the first argument to fread +should be declared as `void *'; the first argument to fwrite should be +declared as `const void *'; malloc should be declared to return `void +*'; in , the declaration `extern "C" { void +*__builtin_alloca(int); }' should be added; declarations of getopt(), +optarg, optind and opterr should be added to ; in + the return type and the second argument type of +signal() should be changed to be `void (*)(int)'. + +You can either change them in place, or copy them to some other +directory and include that directory with a -I option. + +* I get errors when I try to compile groff with DEC C++. + +Fix the declaration of write() in so that the second +argument is a const char *. Fix the declaration of open() in + so that the first argument is a const char *. + +* On Ultrix, the make stops with the message + + *** Error code 1 + + Stop. + +for no apparent reason. + +Use GNU make. + +* I'm having problems compiling groff on 386BSD 0.1. + +If you're using ash as /bin/sh, you'll need the following patch. + +*** gendef.sh.org Sun Jun 30 13:30:36 1991 +--- gendef.sh Sun Feb 28 10:23:49 1993 +*************** +*** 3,9 **** + file=$1 + shift + +! defs="#define $1" + shift + for def + do +--- 3,10 ---- + file=$1 + shift + +! x=$1 +! defs="#define $x" + shift + for def + do + +You'll also need to change dirnamemax.c so that it doesn't use +pathconf(). + +* While compiling on Xenix, ranlib libgroff.a fails. + +The system ranlib can't handle externals longer than 40 characters. +Use the ranlib included in demon.co.uk:/pub/xenix/g++-1.40.3a.v1 +instead. + +* Groff can't handle my troff document. It works fine with AT&T troff. + +Read the section on incompatibilities in gtroff(1). Try using the -C +option. Alternatively there's the sed script in tmac/fixmacros.sed +which will attempt to edit a file of macros so that it can be used +with groff without the -C flag. + +* groff -Tdvi produces dvi files that use fonts at weird magnifications. + +Yes, it does. You may need to compile fonts with Metafont at these +magnifications. The CompileFonts script in the devdvi/generate +directory may help you to do this. (It will take a *long* time.) + +* pic output is not centered horizontally; pictures sometimes run off +the bottom of the page. + +The macro package you are using is not supplying appropriate definitions +of PS and PE. Give groff a -mpic option. + +* I'm having problems including PostScript illustrations using the PSPIC +macro. + +A PostScript document must meet three requirements in order to be +included with the PSPIC macro: it must comply with the Adobe Document +Structuring Conventions; it must contain a BoundingBox line; it must +be ``well-behaved''. The BoundingBox line should be of the form: + + %%BoundingBox: llx lly urx ury + +where llx, lly, urx, ury are the coordinates of the lower left x, +lower left y, upper right x, upper right y of the bounding box of +marks on the page expressed as integers in the default PostScript +coordinate system (72 units per inch, origin at bottom left corner). +A useful tactic is to print out the illustration by itself (you may +need to add a `showpage' at the end), and physically measure the +bounding box. For more detail on these requirements, read the +specification of Encapsulated PostScript format. (This is available +from the Adobe file server; send a message with a body of `help' to +ps-file-server@adobe.com.) + +* I've configured groff for A4 paper, but gtroff still seems to think +that the length of a page (as returned by \n(.p) is 11 inches. + +This is intentional. The PAGE option is used only by grops. For +compatibility with ditroff, the default page length in gtroff is +always 11 inches. The page length can be changed with the `pl' +request. + +* Groff doesn't use the font names I'm used to. + +Use the `ftr' request. See gtroff(1). + +* I get errors using the Unix -ms macros with groff -e -C. + +Apply this change: + +*** /usr/lib/ms/ms.eqn Tue Apr 25 02:14:28 1989 +--- ms.eqn Sun Nov 11 10:33:59 1990 +*************** +*** 22,29 **** + .. + . \" EN - end of a displayed equation + .de EN +! .if !\\*(10 .br + .di + .rm EZ + .nr ZN \\n(dn + .if \\n(ZN>0 .if \\n(YE=0 .LP +--- 22,30 ---- + .. + . \" EN - end of a displayed equation + .de EN +! .if \\n(.k>0 .br + .di ++ .ds 10 \\*(EZ\\ + .rm EZ + .nr ZN \\n(dn + .if \\n(ZN>0 .if \\n(YE=0 .LP + + +* gpic doesn't accept the syntax `chop N M' for chopping both ends of a +line. + +The correct syntax is `chop N chop M'. + +* With gpic -t, when I print `line ->; box' using a dvi to ps +program, the arrow head sticks through into the inside of the box. + +The dvi to ps program should be modified to set the line cap and +line join parameters to 1 while printing tpic specials. + +* When I print the output groff -Tps, the output is always shifted up +by about 0.7 inches; I'm using 8.5x11 inch paper. + +Make sure that PAGE is defined to be `letter' in the top-level +Makefile. + +* When I try to print the output of groff -Tps, I get no output at all +from the printer, and the log file shows the error +%%[ error: undefined; offendingcommand: BP ]%% +I using TranScript spooling software. + +This is a bug in the page reversal filter in early versions of +TranScript. Change the `broken' parameter in +/usr/local/lib/groff/font/devps/DESC to 7. + +* When I preview groff -Tps output using the Sun OpenWindows 2.0 pageview +program, all the pages are displayed on top of each other. + +This is a defect in pageview. Change the `broken' parameter in +/usr/local/lib/groff/font/devps/DESC to 2. + +* With groff -TX75, -TX100or -X, I can only view the first page. + +The left mouse button brings up a menu that allows you to view other +pages. + +* When I print the output of groff -Tdvi, I just get a black dot in +upper left corner. + +Some dvi drivers (notably early versions of xtex) do not correctly +handle dvi files that use a resolution different from that used by dvi +files produced by TeX. Try getting a more up to date driver. + +* I get lots of errors when I use groff with the AT&T -mm macros. + +The AT&T -mm macros need a few changes to work with groff; `make +install.dwbmm' will copy your -mm macros to groff's macro directory +and make the necessary changes. You may need to edit the commands for +the install.mm target in the Makefile. Alternatively use the groff +-mm macros. + +* gtroff doesn't understand lines like `.ce99' with no space between +the name of the request or macro and the arguments. + +Gtroff requires a space between macro or request and its arguments +because it allows the use of long names for macros and requests. You +can use the -C option or the `cp' request to put gtroff into a +compatibility mode in which it is not possible to use long names for +macros but in which no space is required between macros and their +arguments. The use of compatibility mode is strongly discouraged. + +* gtroff gives warnings about lines like + .ev \" a comment +(with a tab after the .ev). + +A tab character cannot be used as a substitute for a space character +(except in one case: between a control character at the beginning of a +line and the name of a macro or request). For example, in Unix troff + .ps \" restore the previous point size +(with a tab after the .ps) will NOT restore the previous point-size; +instead it will be silently ignored. Since this is very likely to be +an error, gtroff can give a warning about it. If you want to align +comments, you can do it like this: + .ev\" \" a comment + +* I don't like the page headers and footers produced by groff -man. + +There seem to be many different styles of page header and footer +produced by different versions of the -man macros. You will need to +modify macros/tmac.an to suit your personal taste. For example, if +you want the center of the page header to say + UNIX Programmer's Manual +you will need to change the line + .el .ds an-extra3 \"UNIX Programmer's Manual +to + .el .ds an-extra3 UNIX Programmer's Manual + +* While formatting a manual page, groff complains about not being able to +break lines. The problem seems to be caused by a line like: + .TP \w'label'+2 + +The -man documentation says that the default scale indicator for TP +macro is `n'. The groff -man macros implement this correctly, so that +the argument will be evaluated as if it were + \w'label'n+2n +The Unix -man macros don't implement this correctly (probably because +it's hard to do in Unix troff); they just append `n' to the entire +argument, so that it will be evaluated as if it were + \w'label'u+2n +The solution is to fix the manual page: + .TP \w'label'u+2 + +* I'm having problems formatting Ultrix man pages with groff -man. + +The Ultrix man pages use a number of non-standard extensions to the +Unix man macros. One solution is to use the Ultrix -man macros with +groff. Rename /usr/local/lib/groff/tmac/tmac.an to +/usr/local/lib/groff/tmac/tmac.an.gnu, copy /usr/lib/tmac/tmac.an to +/usr/local/lib/groff/tmac/tmac.an and apply the following patch (from +Frank Wortner): + +*** /usr/local/lib/groff/tmac/tmac.an Wed Sep 9 12:29:28 1992 +--- /usr/lib/tmac/tmac.an Fri Jul 24 19:58:19 1992 +*************** +*** 489,495 **** + . \" make special case of shift out of italic + .de }S + .ds ]F +! .if \\$12 .if !\\$5 .ds ]F \^ + .ie !\\$4 .}S \\$2 \\$1 "\\$3\f\\$1\\$4\\*(]F" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" + .el \\$3 + .}f +--- 489,495 ---- + . \" make special case of shift out of italic + .de }S + .ds ]F +! .if \\$12 .if !\\$5 .ds ]F\^ + .ie !\\$4 .}S \\$2 \\$1 "\\$3\f\\$1\\$4\\*(]F" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" + .el \\$3 + .}f + +Another possible solution is to install tmac/man.ultrix as +/usr/local/lib/groff/tmac/man.local. + +* I'm having problems formatting HP-UX 9.0 man pages with groff -man. + +Rename /usr/local/lib/groff/tmac/tmac.an to (for example) +/usr/local/lib/groff/tmac/tmac.gan, copy HP's tmac.an into +/usr/local/lib/groff/tmac/tmac.an, and either put `.cp 1' at the +beginning or filter it (and any files it .so's) through +tmac/fixmacros.sed. + +* I'm having problems formatting man pages produced by the perl +wrapman script. + +Some versions of wrapman have a superfluous blank line before the .TH +line. This must be deleted. Then either use groff -C, or apply the +following patch: + +*** wrapman.~2~ Sun Jan 19 12:10:24 1992 +--- wrapman Fri Apr 2 12:12:57 1993 +*************** +*** 35,41 **** + $line1 .= if $line1 =~ /eval/; + $line1 .= if $line1 =~ /argv/; + $line2 = ; +! next if $line2 eq "'di';\n"; + + # Pull the old switcheroo. + +--- 35,41 ---- + $line1 .= if $line1 =~ /eval/; + $line1 .= if $line1 =~ /argv/; + $line2 = ; +! next if $line2 eq "'di ';\n"; + + # Pull the old switcheroo. + +*************** +*** 49,56 **** + + print OUT $line1; + print OUT < +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/addftinfo/Makefile.dep b/gnu/usr.bin/groff/addftinfo/Makefile.dep new file mode 100644 index 0000000000..4583de2634 --- /dev/null +++ b/gnu/usr.bin/groff/addftinfo/Makefile.dep @@ -0,0 +1,3 @@ +addftinfo.o : addftinfo.cc ../include/lib.h ../include/errarg.h \ + ../include/error.h ../include/stringclass.h ../include/cset.h guess.h +guess.o : guess.cc guess.h diff --git a/gnu/usr.bin/groff/addftinfo/addftinfo.1 b/gnu/usr.bin/groff/addftinfo/addftinfo.1 new file mode 100644 index 0000000000..9f3eaaee6e --- /dev/null +++ b/gnu/usr.bin/groff/addftinfo/addftinfo.1 @@ -0,0 +1,85 @@ +.\" -*- nroff -*- +.TH ADDFTINFO 1 "6 August 1992" "Groff Version 1.08" +.SH NAME +addftinfo \- add information to troff font files for use with groff +.SH SYNOPSIS +.B addftinfo +[ +.BI \- param\ value\fR.\|.\|. +] +.I res +.I unitwidth +.I font +.SH DESCRIPTION +.B addftinfo +reads a troff font file +and adds some additional font-metric information +that is used by the groff system. +The font file with the information added is written on the +standard output. +The information added is guessed using +some parametric information about the font +and assumptions +about the traditional troff names for characters. +The main information added is the heights and depths of characters. +The +.I res +and +.I unitwidth +arguments should be the same as the corresponding parameters +in the DESC file; +.I font +is the name of the file describing the font; +if +.I font +ends with +.B I +the font will be assumed to be italic. +.SH OPTIONS +Each of the options changes one of the parameters that is used +to derive the heights and depths. +Like the existing quantities in the font +file, each +.I value +is in +.RI inches/ res +for a font whose point size is +.IR unitwidth . +.I param +must be one of: +.TP +.B x-height +The height of lowercase letters without ascenders such as x. +.TP +.B fig-height +The height of figures (digits). +.TP +.B asc-height +The height of characters with ascenders, such as b, d or l. +.TP +.B body-height +The height of characters such as parentheses. +.TP +.B cap-height +The height of uppercase letters such as A. +.TP +.B comma-depth +The depth of a comma. +.TP +.B desc-depth +The depth of characters with descenders, such as p,q, or y. +.TP +.B body-depth +The depth of characters such as parentheses. +.LP +.B addftinfo +makes no attempt to use the specified parameters to guess +the unspecified parameters. +If a parameter is not specified the default will be used. +The defaults are chosen to have the reasonable values for +a Times font. +.SH "SEE ALSO" +.BR font (5) +.BR groff_font (5), +.BR groff (1), +.BR groff_char (7) diff --git a/gnu/usr.bin/groff/addftinfo/addftinfo.cc b/gnu/usr.bin/groff/addftinfo/addftinfo.cc new file mode 100644 index 0000000000..e6d96695c8 --- /dev/null +++ b/gnu/usr.bin/groff/addftinfo/addftinfo.cc @@ -0,0 +1,194 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "stringclass.h" +#include "cset.h" +#include "guess.h" + +static void usage(); +static void convert_font(const font_params &, FILE *, FILE *); + +typedef font_params::*param_t; + +static struct { + const char *name; + param_t par; +} param_table[] = { + "x-height", &font_params::x_height, + "fig-height", &font_params::fig_height, + "asc-height", &font_params::asc_height, + "body-height", &font_params::body_height, + "cap-height", &font_params::cap_height, + "comma-depth", &font_params::comma_depth, + "desc-depth", &font_params::desc_depth, + "body-depth", &font_params::body_depth, +}; + +// These are all in thousandths of an em. +// These values are correct for PostScript Times Roman. + +#define DEFAULT_X_HEIGHT 448 +#define DEFAULT_FIG_HEIGHT 676 +#define DEFAULT_ASC_HEIGHT 682 +#define DEFAULT_BODY_HEIGHT 676 +#define DEFAULT_CAP_HEIGHT 662 +#define DEFAULT_COMMA_DEPTH 143 +#define DEFAULT_DESC_DEPTH 217 +#define DEFAULT_BODY_DEPTH 177 + +int main(int argc, char **argv) +{ + program_name = argv[0]; + if (argc < 4) + usage(); + int resolution; + if (sscanf(argv[argc-3], "%d", &resolution) != 1) + usage(); + if (resolution <= 0) + fatal("resolution must be > 0"); + int unitwidth; + if (sscanf(argv[argc-2], "%d", &unitwidth) != 1) + usage(); + if (unitwidth <= 0) + fatal("unitwidth must be > 0"); + font_params param; + const char *font = argv[argc-1]; + param.italic = (font[0] != '\0' && strchr(font, '\0')[-1] == 'I'); + param.em = (resolution*unitwidth)/72; + param.x_height = DEFAULT_X_HEIGHT; + param.fig_height = DEFAULT_FIG_HEIGHT; + param.asc_height = DEFAULT_ASC_HEIGHT; + param.body_height = DEFAULT_BODY_HEIGHT; + param.cap_height = DEFAULT_CAP_HEIGHT; + param.comma_depth = DEFAULT_COMMA_DEPTH; + param.desc_depth = DEFAULT_DESC_DEPTH; + param.body_depth = DEFAULT_BODY_DEPTH; + for (int i = 1; i < argc && argv[i][0] == '-'; i++) { + if (argv[i][1] == '-' && argv[i][2] == '\0') { + i++; + break; + } + if (i + 1 >= argc) + usage(); + for (int j = 0;; j++) { + if (j >= sizeof(param_table)/sizeof(param_table[0])) + fatal("parameter `%1' not recognized", argv[i] + 1); + if (strcmp(param_table[j].name, argv[i] + 1) == 0) + break; + } + if (sscanf(argv[i+1], "%d", &(param.*(param_table[j].par))) != 1) + fatal("invalid argument `%1'", argv[i+1]); + i++; + } + if (argc - i != 3) + usage(); + errno = 0; + FILE *infp = fopen(font, "r"); + if (infp == 0) + fatal("can't open `%1': %2", font, strerror(errno)); + convert_font(param, infp, stdout); + exit(0); +} + +static void usage() +{ + fprintf(stderr, "usage: %s [-param value] ... resolution unitwidth font\n", + program_name); + exit(1); +} + +static int get_line(FILE *fp, string *p) +{ + int c; + p->clear(); + while ((c = getc(fp)) != EOF) { + *p += char(c); + if (c == '\n') + break; + } + return p->length() > 0; +} + +static void convert_font(const font_params ¶m, FILE *infp, FILE *outfp) +{ + string s; + while (get_line(infp, &s)) { + put_string(s, outfp); + if (s.length() >= 8 + && strncmp(&s[0], "charset", 7)) + break; + } + while (get_line(infp, &s)) { + s += '\0'; + string name; + const char *p = s.contents(); + while (csspace(*p)) + p++; + while (*p != '\0' && !csspace(*p)) + name += *p++; + while (csspace(*p)) + p++; + for (const char *q = s.contents(); q < p; q++) + putc(*q, outfp); + char *next; + char_metric metric; + metric.width = (int)strtol(p, &next, 10); + if (next != p) { + printf("%d", metric.width); + p = next; + metric.type = (int)strtol(p, &next, 10); + if (next != p) { + name += '\0'; + guess(name.contents(), param, &metric); + if (metric.sk == 0) { + if (metric.left_ic == 0) { + if (metric.ic == 0) { + if (metric.depth == 0) { + if (metric.height != 0) + printf(",%d", metric.height); + } + else + printf(",%d,%d", metric.height, metric.depth); + } + else + printf(",%d,%d,%d", metric.height, metric.depth, metric.ic); + } + else + printf(",%d,%d,%d,%d", metric.height, metric.depth, metric.ic, + metric.left_ic); + } + else + printf(",%d,%d,%d,%d,%d", metric.height, metric.depth, metric.ic, + metric.left_ic, metric.sk); + } + } + fputs(p, outfp); + } +} + diff --git a/gnu/usr.bin/groff/addftinfo/guess.cc b/gnu/usr.bin/groff/addftinfo/guess.cc new file mode 100644 index 0000000000..44b5f914b1 --- /dev/null +++ b/gnu/usr.bin/groff/addftinfo/guess.cc @@ -0,0 +1,490 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "guess.h" + +void guess(const char *s, const font_params ¶m, char_metric *metric) +{ + int &height = metric->height; + int &depth = metric->depth; + + metric->ic = 0; + metric->left_ic = 0; + metric->sk = 0; + height = 0; + depth = 0; + if (s[0] == '\0' || (s[1] != '\0' && s[2] != '\0')) + goto do_default; +#define HASH(c1, c2) (((unsigned char)(c1) << 8) | (unsigned char)(c2)) + switch (HASH(s[0], s[1])) { + default: + do_default: + if (metric->type & 01) + depth = param.desc_depth; + if (metric->type & 02) + height = param.asc_height; + else + height = param.x_height; + break; + case HASH('\\', '|'): + case HASH('\\', '^'): + case HASH('\\', '&'): + // these have zero height and depth + break; + case HASH('f', 0): + height = param.asc_height; + if (param.italic) + depth = param.desc_depth; + break; + case HASH('a', 0): + case HASH('c', 0): + case HASH('e', 0): + case HASH('m', 0): + case HASH('n', 0): + case HASH('o', 0): + case HASH('r', 0): + case HASH('s', 0): + case HASH('u', 0): + case HASH('v', 0): + case HASH('w', 0): + case HASH('x', 0): + case HASH('z', 0): + height = param.x_height; + break; + case HASH('i', 0): + height = param.x_height; + break; + case HASH('b', 0): + case HASH('d', 0): + case HASH('h', 0): + case HASH('k', 0): + case HASH('l', 0): + case HASH('F', 'i'): + case HASH('F', 'l'): + case HASH('f', 'f'): + case HASH('f', 'i'): + case HASH('f', 'l'): + height = param.asc_height; + break; + case HASH('t', 0): + height = param.asc_height; + break; + case HASH('g', 0): + case HASH('p', 0): + case HASH('q', 0): + case HASH('y', 0): + height = param.x_height; + depth = param.desc_depth; + break; + case HASH('j', 0): + height = param.x_height; + depth = param.desc_depth; + break; + case HASH('A', 0): + case HASH('B', 0): + case HASH('C', 0): + case HASH('D', 0): + case HASH('E', 0): + case HASH('F', 0): + case HASH('G', 0): + case HASH('H', 0): + case HASH('I', 0): + case HASH('J', 0): + case HASH('K', 0): + case HASH('L', 0): + case HASH('M', 0): + case HASH('N', 0): + case HASH('O', 0): + case HASH('P', 0): + case HASH('Q', 0): + case HASH('R', 0): + case HASH('S', 0): + case HASH('T', 0): + case HASH('U', 0): + case HASH('V', 0): + case HASH('W', 0): + case HASH('X', 0): + case HASH('Y', 0): + case HASH('Z', 0): + height = param.cap_height; + break; + case HASH('*', 'A'): + case HASH('*', 'B'): + case HASH('*', 'C'): + case HASH('*', 'D'): + case HASH('*', 'E'): + case HASH('*', 'F'): + case HASH('*', 'G'): + case HASH('*', 'H'): + case HASH('*', 'I'): + case HASH('*', 'K'): + case HASH('*', 'L'): + case HASH('*', 'M'): + case HASH('*', 'N'): + case HASH('*', 'O'): + case HASH('*', 'P'): + case HASH('*', 'Q'): + case HASH('*', 'R'): + case HASH('*', 'S'): + case HASH('*', 'T'): + case HASH('*', 'U'): + case HASH('*', 'W'): + case HASH('*', 'X'): + case HASH('*', 'Y'): + case HASH('*', 'Z'): + height = param.cap_height; + break; + case HASH('0', 0): + case HASH('1', 0): + case HASH('2', 0): + case HASH('3', 0): + case HASH('4', 0): + case HASH('5', 0): + case HASH('6', 0): + case HASH('7', 0): + case HASH('8', 0): + case HASH('9', 0): + case HASH('1', '2'): + case HASH('1', '4'): + case HASH('3', '4'): + height = param.fig_height; + break; + case HASH('(', 0): + case HASH(')', 0): + case HASH('[', 0): + case HASH(']', 0): + case HASH('{', 0): + case HASH('}', 0): + height = param.body_height; + depth = param.body_depth; + break; + case HASH('i', 's'): + height = (param.em*3)/4; + depth = param.em/4; + break; + case HASH('*', 'a'): + case HASH('*', 'e'): + case HASH('*', 'i'): + case HASH('*', 'k'): + case HASH('*', 'n'): + case HASH('*', 'o'): + case HASH('*', 'p'): + case HASH('*', 's'): + case HASH('*', 't'): + case HASH('*', 'u'): + case HASH('*', 'w'): + height = param.x_height; + break; + case HASH('*', 'd'): + case HASH('*', 'l'): + height = param.asc_height; + break; + case HASH('*', 'g'): + case HASH('*', 'h'): + case HASH('*', 'm'): + case HASH('*', 'r'): + case HASH('*', 'x'): + case HASH('*', 'y'): + height = param.x_height; + depth = param.desc_depth; + break; + case HASH('*', 'b'): + case HASH('*', 'c'): + case HASH('*', 'f'): + case HASH('*', 'q'): + case HASH('*', 'z'): + height = param.asc_height; + depth = param.desc_depth; + break; + case HASH('t', 's'): + height = param.x_height; + depth = param.desc_depth; + break; + case HASH('!', 0): + case HASH('?', 0): + case HASH('"', 0): + case HASH('#', 0): + case HASH('$', 0): + case HASH('%', 0): + case HASH('&', 0): + case HASH('*', 0): + case HASH('+', 0): + height = param.asc_height; + break; + case HASH('`', 0): + case HASH('\'', 0): + height = param.asc_height; + break; + case HASH('~', 0): + case HASH('^', 0): + case HASH('a', 'a'): + case HASH('g', 'a'): + height = param.asc_height; + break; + case HASH('r', 'u'): + case HASH('.', 0): + break; + case HASH(',', 0): + depth = param.comma_depth; + break; + case HASH('m', 'i'): + case HASH('-', 0): + case HASH('h', 'y'): + case HASH('e', 'm'): + height = param.x_height; + break; + case HASH(':', 0): + height = param.x_height; + break; + case HASH(';', 0): + height = param.x_height; + depth = param.comma_depth; + break; + case HASH('=', 0): + case HASH('e', 'q'): + height = param.x_height; + break; + case HASH('<', 0): + case HASH('>', 0): + case HASH('>', '='): + case HASH('<', '='): + case HASH('@', 0): + case HASH('/', 0): + case HASH('|', 0): + case HASH('\\', 0): + height = param.asc_height; + break; + case HASH('_', 0): + case HASH('u', 'l'): + case HASH('\\', '_'): + depth = param.em/4; + break; + case HASH('r', 'n'): + height = (param.em*3)/4; + break; + case HASH('s', 'r'): + height = (param.em*3)/4; + depth = param.em/4; + break; + case HASH('b', 'u'): + case HASH('s', 'q'): + case HASH('d', 'e'): + case HASH('d', 'g'): + case HASH('f', 'm'): + case HASH('c', 't'): + case HASH('r', 'g'): + case HASH('c', 'o'): + case HASH('p', 'l'): + case HASH('*', '*'): + case HASH('s', 'c'): + case HASH('s', 'l'): + case HASH('=', '='): + case HASH('~', '='): + case HASH('a', 'p'): + case HASH('!', '='): + case HASH('-', '>'): + case HASH('<', '-'): + case HASH('u', 'a'): + case HASH('d', 'a'): + case HASH('m', 'u'): + case HASH('d', 'i'): + case HASH('+', '-'): + case HASH('c', 'u'): + case HASH('c', 'a'): + case HASH('s', 'b'): + case HASH('s', 'p'): + case HASH('i', 'b'): + case HASH('i', 'p'): + case HASH('i', 'f'): + case HASH('p', 'd'): + case HASH('g', 'r'): + case HASH('n', 'o'): + case HASH('p', 't'): + case HASH('e', 's'): + case HASH('m', 'o'): + case HASH('b', 'r'): + case HASH('d', 'd'): + case HASH('r', 'h'): + case HASH('l', 'h'): + case HASH('o', 'r'): + case HASH('c', 'i'): + height = param.asc_height; + break; + case HASH('l', 't'): + case HASH('l', 'b'): + case HASH('r', 't'): + case HASH('r', 'b'): + case HASH('l', 'k'): + case HASH('r', 'k'): + case HASH('b', 'v'): + case HASH('l', 'f'): + case HASH('r', 'f'): + case HASH('l', 'c'): + case HASH('r', 'c'): + height = (param.em*3)/4; + depth = param.em/4; + break; +#if 0 + case HASH('%', '0'): + case HASH('-', '+'): + case HASH('-', 'D'): + case HASH('-', 'd'): + case HASH('-', 'd'): + case HASH('-', 'h'): + case HASH('.', 'i'): + case HASH('.', 'j'): + case HASH('/', 'L'): + case HASH('/', 'O'): + case HASH('/', 'l'): + case HASH('/', 'o'): + case HASH('=', '~'): + case HASH('A', 'E'): + case HASH('A', 'h'): + case HASH('A', 'N'): + case HASH('C', 's'): + case HASH('D', 'o'): + case HASH('F', 'c'): + case HASH('F', 'o'): + case HASH('I', 'J'): + case HASH('I', 'm'): + case HASH('O', 'E'): + case HASH('O', 'f'): + case HASH('O', 'K'): + case HASH('O', 'm'): + case HASH('O', 'R'): + case HASH('P', 'o'): + case HASH('R', 'e'): + case HASH('S', '1'): + case HASH('S', '2'): + case HASH('S', '3'): + case HASH('T', 'P'): + case HASH('T', 'p'): + case HASH('Y', 'e'): + case HASH('\\', '-'): + case HASH('a', '"'): + case HASH('a', '-'): + case HASH('a', '.'): + case HASH('a', '^'): + case HASH('a', 'b'): + case HASH('a', 'c'): + case HASH('a', 'd'): + case HASH('a', 'e'): + case HASH('a', 'h'): + case HASH('a', 'o'): + case HASH('a', 't'): + case HASH('a', '~'): + case HASH('b', 'a'): + case HASH('b', 'b'): + case HASH('b', 's'): + case HASH('c', '*'): + case HASH('c', '+'): + case HASH('f', '/'): + case HASH('f', 'a'): + case HASH('f', 'c'): + case HASH('f', 'o'): + case HASH('h', 'a'): + case HASH('h', 'o'): + case HASH('i', 'j'): + case HASH('l', 'A'): + case HASH('l', 'B'): + case HASH('l', 'C'): + case HASH('m', 'd'): + case HASH('n', 'c'): + case HASH('n', 'e'): + case HASH('n', 'm'): + case HASH('o', 'A'): + case HASH('o', 'a'): + case HASH('o', 'e'): + case HASH('o', 'q'): + case HASH('p', 'l'): + case HASH('p', 'p'): + case HASH('p', 's'): + case HASH('r', '!'): + case HASH('r', '?'): + case HASH('r', 'A'): + case HASH('r', 'B'): + case HASH('r', 'C'): + case HASH('r', 's'): + case HASH('s', 'h'): + case HASH('s', 's'): + case HASH('t', 'e'): + case HASH('t', 'f'): + case HASH('t', 'i'): + case HASH('t', 'm'): + case HASH('~', '~'): + case HASH('v', 'S'): + case HASH('v', 'Z'): + case HASH('v', 's'): + case HASH('v', 'z'): + case HASH('^', 'A'): + case HASH('^', 'E'): + case HASH('^', 'I'): + case HASH('^', 'O'): + case HASH('^', 'U'): + case HASH('^', 'a'): + case HASH('^', 'e'): + case HASH('^', 'i'): + case HASH('^', 'o'): + case HASH('^', 'u'): + case HASH('`', 'A'): + case HASH('`', 'E'): + case HASH('`', 'I'): + case HASH('`', 'O'): + case HASH('`', 'U'): + case HASH('`', 'a'): + case HASH('`', 'e'): + case HASH('`', 'i'): + case HASH('`', 'o'): + case HASH('`', 'u'): + case HASH('~', 'A'): + case HASH('~', 'N'): + case HASH('~', 'O'): + case HASH('~', 'a'): + case HASH('~', 'n'): + case HASH('~', 'o'): + case HASH('\'', 'A'): + case HASH('\'', 'C'): + case HASH('\'', 'E'): + case HASH('\'', 'I'): + case HASH('\'', 'O'): + case HASH('\'', 'U'): + case HASH('\'', 'a'): + case HASH('\'', 'c'): + case HASH('\'', 'e'): + case HASH('\'', 'i'): + case HASH('\'', 'o'): + case HASH('\'', 'u') + case HASH(':', 'A'): + case HASH(':', 'E'): + case HASH(':', 'I'): + case HASH(':', 'O'): + case HASH(':', 'U'): + case HASH(':', 'Y'): + case HASH(':', 'a'): + case HASH(':', 'e'): + case HASH(':', 'i'): + case HASH(':', 'o'): + case HASH(':', 'u'): + case HASH(':', 'y'): + case HASH(',', 'C'): + case HASH(',', 'c'): +#endif + } +} diff --git a/gnu/usr.bin/groff/addftinfo/guess.h b/gnu/usr.bin/groff/addftinfo/guess.h new file mode 100644 index 0000000000..6712045e13 --- /dev/null +++ b/gnu/usr.bin/groff/addftinfo/guess.h @@ -0,0 +1,44 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct font_params { + int italic; + int em; + int x_height; + int fig_height; + int cap_height; + int asc_height; + int body_height; + int comma_depth; + int desc_depth; + int body_depth; +}; + +struct char_metric { + int width; + int type; + int height; + int depth; + int ic; + int left_ic; + int sk; +}; + +void guess(const char *s, const font_params ¶m, char_metric *metric); diff --git a/gnu/usr.bin/groff/afmtodit/Makefile b/gnu/usr.bin/groff/afmtodit/Makefile new file mode 100644 index 0000000000..199d16a385 --- /dev/null +++ b/gnu/usr.bin/groff/afmtodit/Makefile @@ -0,0 +1,9 @@ +MAN1= afmtodit.0 + +afterinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + $(.CURDIR)/afmtodit.pl $(DESTDIR)$(BINDIR)/afmtodit + +.include +.include <../../../usr.bin/Makefile.inc> +.include <../Makefile.cfg> diff --git a/gnu/usr.bin/groff/afmtodit/afmtodit.1 b/gnu/usr.bin/groff/afmtodit/afmtodit.1 new file mode 100644 index 0000000000..343a665f34 --- /dev/null +++ b/gnu/usr.bin/groff/afmtodit/afmtodit.1 @@ -0,0 +1,204 @@ +.\" -*- nroff -*- +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH AFMTODIT 1 "23 February 1993" "Groff Version 1.08" +.SH NAME +afmtodit \- create font files for use with groff \-Tps +.SH SYNOPSIS +.B afmtodit +[ +.B \-ns +] +[ +.BI \-d desc_file +] +[ +.BI \-e enc_file +] +[ +.BI \-i n +] +[ +.BI \-a n +] +.I afm_file +.I map_file +.I font +.SH DESCRIPTION +.B afmtodit +creates a font file for use with groff and +.BR grops . +.B afmtodit +is written in perl; +you must have perl version 3 installed in order to run +.BR afmtodit . +.I afm_file +is the AFM (Adobe Font Metric) file for the font. +.I map_file +is a file that says which groff character names map onto +each PostScript character name; +this file should contain a sequence of lines of the form +.IP +.I +ps_char groff_char +.LP +where +.I ps_char +is the PostScript name of the character +and +.I groff_char +is the groff name of the character (as used in the groff font file.) +The same +.I ps_char +can occur multiple times in the file; +each +.I groff_char +must occur at most once. +.I font +is the groff name of the font. +If a PostScript character is in the encoding to be used for the font +but is not mentioned in +.I map_file +then +.B afmtodit +will put it in the groff font file as an unnamed character, +which can be accessed by the +.B \eN +escape sequence in +.BR troff . +The groff font file will be output to a file called +.IR font . +.LP +If there is a downloadable font file for the font, it may be listed in +the file +.BR /usr/share/groff_font/devps/download ; +see +.BR grops (1). +.LP +If the +.B \-i +option is used, +.B afmtodit +will automatically generate an italic correction, +a left italic correction and a subscript correction +for each character +(the significance of these parameters is explained in +.BR groff_font (5)); +these parameters may be specified for individual characters by +adding to the +.I afm_file +lines of the form: +.IP +.BI italicCorrection\ ps_char\ n +.br +.BI leftItalicCorrection\ ps_char\ n +.br +.BI subscriptCorrection\ ps_char\ n +.LP +where +.I ps_char +is the PostScript name of the character, +and +.I n +is the desired value of the corresponding parameter in thousandths of an em. +These parameters are normally needed only for italic (or oblique) fonts. +.SH OPTIONS +.TP +.B \-n +Don't output a +.B ligatures +command for this font. +Use this with constant-width fonts. +.TP +.B \-s +The font is special. +The effect of this option is to add the +.B special +command to the font file. +.TP +.BI \-d desc_file +The device description file is +.I desc_file +rather than the default +.BR DESC . +.TP +.BI \-e enc_file +The PostScript font should be reencoded to use the encoding described +in enc_file. +The format of +.I enc_file +is described in +.BR grops (1). +.TP +.BI \-a n +Use +.I n +as the slant parameter in the font file; +this is used by groff in the positioning of accents. +By default +.B afmtodit +uses the negative of the ItalicAngle specified in the afm file; +with true italic fonts it is sometimes desirable to use +a slant that is less than this. +If you find that characters from an italic font have accents +placed too far to the right over them, +then use the +.B \-a +option to give the font a smaller slant. +.TP +.BI \-i n +Generate an italic correction for each character so that +the character's width plus the character's italic correction +is equal to +.I n +thousandths of an em +plus the amount by which the right edge of the character's bounding +is to the right of the character's origin. +If this would result in a negative italic correction, use a zero +italic correction instead. +.IP +Also generate a subscript correction equal to the +product of the tangent of the slant of the font and +four fifths of the x-height of the font. +If this would result in a subscript correction greater than the italic +correction, use a subscript correction equal to the italic correction +instead. +.IP +Also generate a left italic correction for each character +equal to +.I n +thousandths of an em +plus the amount by which the left edge of the character's bounding box +is to the left of the character's origin. +The left italic correction may be negative. +.IP +This option is normally needed only with italic (or oblique) fonts. +The font files distributed with groff were created using an option of +.B \-i50 +for italic fonts. +.SH FILES +.Tp \w'\fB/usr/share/groff_font/devps/download'u+2n +.B /usr/share/groff_font/devps/DESC +Device desciption file. +.TP +.BI /usr/share/groff_font/devps/ F +Font description file for font +.IR F . +.TP +.B /usr/share/groff_font/devps/download +List of downloadable fonts. +.TP +.B /usr/share/groff_font/devps/text.enc +Encoding used for text fonts. +.TP +.B /usr/share/groff_font/devps/generate/textmap +Standard mapping. +.SH "SEE ALSO" +.BR groff (1), +.BR grops (1), +.BR groff_font (5), +.BR perl (1) diff --git a/gnu/usr.bin/groff/afmtodit/afmtodit.pl b/gnu/usr.bin/groff/afmtodit/afmtodit.pl new file mode 100644 index 0000000000..1d1a249697 --- /dev/null +++ b/gnu/usr.bin/groff/afmtodit/afmtodit.pl @@ -0,0 +1,325 @@ +#! /usr/bin/perl -P- # -*- Perl -*- +#Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. +# Written by James Clark (jjc@jclark.com) +# +#This file is part of groff. +# +#groff is free software; you can redistribute it and/or modify it under +#the terms of the GNU General Public License as published by the Free +#Software Foundation; either version 2, or (at your option) any later +#version. +# +#groff is distributed in the hope that it will be useful, but WITHOUT ANY +#WARRANTY; without even the implied warranty of MERCHANTABILITY or +#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +#for more details. +# +#You should have received a copy of the GNU General Public License along +#with groff; see the file COPYING. If not, write to the Free Software +#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +$prog = $0; +$prog =~ s@.*/@@; + +do 'getopts.pl'; +do Getopts('e:sd:i:a:n'); + +if ($#ARGV != 2) { + die "Usage: $prog [-ns] [-d DESC] [-e encoding] [-i n] [-a angle] afmfile mapfile font\n"; +} + +$afm = $ARGV[0]; +$map = $ARGV[1]; +$font = $ARGV[2]; +$desc = $opt_d || "DESC"; + +# read the afm file + +open(AFM, $afm) || die "$prog: can't open \`$ARGV[0]': $!\n"; + +while () { + chop; + @field = split(' '); + if ($field[0] eq "FontName") { + $psname = $field[1]; + } + elsif($field[0] eq "ItalicAngle") { + $italic_angle = -$field[1]; + } + elsif ($field[0] eq "KPX") { + if ($#field == 3) { + push(kern1, $field[1]); + push(kern2, $field[2]); + push(kernx, $field[3]); + } + } + elsif ($field[0] eq "italicCorrection") { + $italic_correction{$field[1]} = $field[2]; + } + elsif ($field[0] eq "leftItalicCorrection") { + $left_italic_correction{$field[1]} = $field[2]; + } + elsif ($field[0] eq "subscriptCorrection") { + $subscript_correction{$field[1]} = $field[2]; + } + elsif ($field[0] eq "StartCharMetrics") { + while () { + @field = split(' '); + last if ($field[0] eq "EndCharMetrics"); + if ($field[0] eq "C") { + $c = -1; + $wx = 0; + $n = ""; + $lly = 0; + $ury = 0; + $llx = 0; + $urx = 0; + $c = $field[1]; + $i = 2; + while ($i <= $#field) { + if ($field[$i] eq "WX") { + $w = $field[$i + 1]; + $i += 2; + } + elsif ($field[$i] eq "N") { + $n = $field[$i + 1]; + $i += 2; + } + elsif ($field[$i] eq "B") { + $llx = $field[$i + 1]; + $lly = $field[$i + 2]; + $urx = $field[$i + 3]; + $ury = $field[$i + 4]; + $i += 5; + } + elsif ($field[$i] eq "L") { + push(ligatures, $field[$i + 2]); + $i += 3; + } + else { + while ($i <= $#field && $field[$i] ne ";") { + $i++; + } + $i++; + } + } + if (!$opt_e && $c != -1) { + $encoding[$c] = $n; + $in_encoding{$n} = 1; + } + $width{$n} = $w; + $height{$n} = $ury; + $depth{$n} = -$lly; + $left_side_bearing{$n} = -$llx; + $right_side_bearing{$n} = $urx - $w; + } + } + } +} +close(AFM); + +# read the DESC file + +$sizescale = 1; + +open(DESC, $desc) || die "$prog: can't open \`$desc': $!\n"; +while () { + next if /^#/; + chop; + @field = split(' '); + last if $field[0] eq "charset"; + if ($field[0] eq "res") { $resolution = $field[1]; } + if ($field[0] eq "unitwidth") { $unitwidth = $field[1]; } + if ($field[0] eq "sizescale") { $sizescale = $field[1]; } +} +close(DESC); + +if ($opt_e) { + # read the encoding file + + open(ENCODING, $opt_e) || die "$prog: can't open \`$opt_e': $!\n"; + while () { + chop; + @field = split(' '); + if ($#field == 1) { + if ($field[1] >= 0 && defined $width{$field[0]}) { + $encoding[$field[1]] = $field[0]; + $in_encoding{$field[0]} = 1; + } + } + } + close(ENCODING); +} + +# read the map file + +open(MAP, $map) || die "$prog: can't open \`$map': $!\n"; +while () { + next if /^#/; + chop; + @field = split(' '); + if ($#field == 1 && $in_encoding{$field[0]}) { + if (defined $mapped{$field[1]}) { + warn "Both $mapped{$field[1]} and $field[0] map to $field[1]"; + } + elsif ($field[1] eq "space") { + # the PostScript character `space' is automatically mapped + # to the groff character `space'; this is for grops + warn "you are not allowed to map to the groff character `space'"; + } + elsif ($field[0] eq "space") { + warn "you are not allowed to map the PostScript character `space'"; + } + else { + $nmap{$field[0]} += 0; + $map{$field[0],$nmap{$field[0]}} = $field[1]; + $nmap{$field[0]} += 1; + $mapped{$field[1]} = $field[0]; + } + } +} +close(MAP); + +$italic_angle = $opt_a if $opt_a; + +# print it all out + +open(FONT, ">$font") || die "$prog: can't open \`$font' for output: $!\n"; +select(FONT); + +print("name $font\n"); +print("internalname $psname\n") if $psname; +print("special\n") if $opt_s; +printf("slant %g\n", $italic_angle) if $italic_angle != 0; +printf("spacewidth %d\n", do conv($width{"space"})) if defined $width{"space"}; + +if ($opt_e) { + $e = $opt_e; + $e =~ s@.*/@@; + print("encoding $e\n"); +} + +if (!$opt_n && $#ligatures >= 0) { + print("ligatures"); + foreach $lig (@ligatures) { + print(" $lig"); + } + print(" 0\n"); +} + +if ($#kern1 >= 0) { + print("kernpairs\n"); + + for ($i = 0; $i <= $#kern1; $i++) { + $c1 = $kern1[$i]; + $c2 = $kern2[$i]; + if ($in_encoding{$c1} == 1 && $nmap{$c1} != 0 + && $in_encoding{$c2} == 1 && $nmap{$c2} != 0) { + for ($j = 0; $j < $nmap{$c1}; $j++) { + for ($k = 0; $k < $nmap{$c2}; $k++) { + if ($kernx[$i] != 0) { + printf("%s %s %d\n", + $map{$c1,$j}, + $map{$c2,$k}, + do conv($kernx[$i])); + } + } + } + } + } +} + +# characters not shorter than asc_boundary are considered to have ascenders +$asc_boundary = $height{"t"} - 1; + +# likewise for descenders +$desc_boundary = $depth{"g"}; +$desc_boundary = $depth{"j"} if $depth{"j"} < $desc_boundary; +$desc_boundary = $depth{"p"} if $depth{"p"} < $desc_boundary; +$desc_boundary = $depth{"q"} if $depth{"q"} < $desc_boundary; +$desc_boundary = $depth{"y"} if $depth{"y"} < $desc_boundary; +$desc_boundary -= 1; + +if (defined $height{"x"}) { + $xheight = $height{"x"}; +} +elsif (defined $height{"alpha"}) { + $xheight = $height{"alpha"}; +} +else { + $xheight = 450; +} + +$italic_angle = $italic_angle*3.14159265358979323846/180.0; +$slant = sin($italic_angle)/cos($italic_angle); +$slant = 0 if $slant < 0; + +print("charset\n"); +for ($i = 0; $i < 256; $i++) { + $ch = $encoding[$i]; + if ($ch ne "" && $ch ne "space") { + $map{$ch,"0"} = "---" if $nmap{$ch} == 0; + $type = 0; + $h = $height{$ch}; + $h = 0 if $h < 0; + $d = $depth{$ch}; + $d = 0 if $d < 0; + $type = 1 if $d >= $desc_boundary; + $type += 2 if $h >= $asc_boundary; + printf("%s\t%d", $map{$ch,"0"}, do conv($width{$ch})); + $italic_correction = 0; + $left_math_fit = 0; + $subscript_correction = 0; + if (defined $opt_i) { + $italic_correction = $right_side_bearing{$ch} + $opt_i; + $italic_correction = 0 if $italic_correction < 0; + $subscript_correction = $slant * $xheight * .8; + $subscript_correction = $italic_correction if + $subscript_correction > $italic_correction; + $left_math_fit = $left_side_bearing{$ch} + $opt_i; + } + if (defined $italic_correction{$ch}) { + $italic_correction = $italic_correction{$ch}; + } + if (defined $left_italic_correction{$ch}) { + $left_math_fit = $left_italic_correction{$ch}; + } + if (defined $subscript_correction{$ch}) { + $subscript_correction = $subscript_correction{$ch}; + } + if ($subscript_correction != 0) { + printf(",%d,%d", do conv($h), do conv($d)); + printf(",%d,%d,%d", do conv($italic_correction), + do conv($left_math_fit), + do conv($subscript_correction)); + } + elsif ($left_math_fit != 0) { + printf(",%d,%d", do conv($h), do conv($d)); + printf(",%d,%d", do conv($italic_correction), + do conv($left_math_fit)); + } + elsif ($italic_correction != 0) { + printf(",%d,%d", do conv($h), do conv($d)); + printf(",%d", do conv($italic_correction)); + } + elsif ($d != 0) { + printf(",%d,%d", do conv($h), do conv($d)); + } + else { + # always put the height in to stop groff guessing + printf(",%d", do conv($h)); + } + printf("\t%d", $type); + printf("\t0%03o\t%s\n", $i, $ch); + for ($j = 1; $j < $nmap{$ch}; $j++) { + printf("%s\t\"\n", $map{$ch,$j}); + } + } + if ($ch eq "space" && defined $width{"space"}) { + printf("space\t%d\t0\t0%03o\n", do conv($width{"space"}), $i); + } +} + +sub conv { + $_[0]*$unitwidth*$resolution/(72*1000*$sizescale) + ($_[0] < 0 ? -.5 : .5); +} diff --git a/gnu/usr.bin/groff/devices/Makefile b/gnu/usr.bin/groff/devices/Makefile new file mode 100644 index 0000000000..eb10a3478e --- /dev/null +++ b/gnu/usr.bin/groff/devices/Makefile @@ -0,0 +1,10 @@ +# Makefile for groff devices + +SUBDIR= devascii devlatin1 devdvi devps \ + devX100 devX100-12 devX75 devX75-12 + +tags: + +depend: + +.include diff --git a/gnu/usr.bin/groff/devices/Makefile.dev b/gnu/usr.bin/groff/devices/Makefile.dev new file mode 100644 index 0000000000..1792ffcb6b --- /dev/null +++ b/gnu/usr.bin/groff/devices/Makefile.dev @@ -0,0 +1,63 @@ +# @(#)Makefile.dev 6.2 (Berkeley) 3/16/91 + +# Client Makefiles define DEVICE and FONTFILES and provide rules for +# individual font files + +.include "../../Makefile.cfg" + +DESTDIR?= /usr/share/groff_font +DEVICEDIR?= $(fontdir)/dev$(DEVICE) +FONTOWN?= bin +FONTGRP?= bin +FONTMODE?= 444 + +.MAIN: all + +all: $(FONTFILES) + +.if !target(obj) +.if defined(NOOBJ) +obj: +.else +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 +.endif + +.if !target(clean) +clean: + -rm -f $(FONTFILES) +.endif + +.if !target(cleandir) +cleandir: + -rm -f $(FONTFILES) + cd ${.CURDIR}; rm -rf obj; +.endif + +.if !target(install) +install: + -if test ! -d $(DESTDIR)$(DEVICEDIR); then \ + mkdir $(DESTDIR)$(DEVICEDIR); \ + chown $(BINOWN).$(BINGRP) $(DESTDIR)$(DEVICEDIR); \ + chmod 755 $(DESTDIR)$(DEVICEDIR); \ + fi + -if test -d $(.CURDIR)/generate; then \ + if test ! -d $(DESTDIR)$(DEVICEDIR)/generate; then \ + mkdir $(DESTDIR)$(DEVICEDIR)/generate; \ + chown $(BINOWN).$(BINGRP) $(DESTDIR)$(DEVICEDIR)/generate; \ + chmod 755 $(DESTDIR)$(DEVICEDIR)/generate; \ + fi; \ + fi + -for f in $(FONTFILES); do \ + install -c -o $(FONTOWN) -g $(FONTGRP) -m $(FONTMODE) $$f \ + $(DESTDIR)$(DEVICEDIR)/$$f; \ + done +.endif diff --git a/gnu/usr.bin/groff/devices/Makefile.tty b/gnu/usr.bin/groff/devices/Makefile.tty new file mode 100644 index 0000000000..021a7cb226 --- /dev/null +++ b/gnu/usr.bin/groff/devices/Makefile.tty @@ -0,0 +1,52 @@ +# @(#)Makefile.tty 6.1 (Berkeley) 3/3/91 +# +# Modified for Berkeley Unix by Donn Seeley, donn@okeeffe.berkeley.edu +# +#Copyright (C) 1989, 1990 Free Software Foundation, Inc. +# Written by James Clark (jjc@jclark.uucp) +# +#This file is part of groff. +# +#groff is free software; you can redistribute it and/or modify it under +#the terms of the GNU General Public License as published by the Free +#Software Foundation; either version 1, or (at your option) any later +#version. +# +#groff is distributed in the hope that it will be useful, but WITHOUT ANY +#WARRANTY; without even the implied warranty of MERCHANTABILITY or +#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +#for more details. +# +#You should have received a copy of the GNU General Public License along +#with groff; see the file LICENSE. If not, write to the Free Software +#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +.MAIN: all + +RES=240 +CPI=10 +LPI=6 +FONTS=R I B BI + +FONTFILES=$(FONTS) DESC + +$(FONTS): R.proto + @echo Making $@ + @(charwidth=`echo $(RES) / $(CPI) | bc` ; \ + sed -e "s/^name [A-Z]*$$/name $@/" \ + -e "s/^\\([^ ]*\\) [0-9]+ /\\1 $$charwidth /" \ + -e "s/^spacewidth [0-9]+$$/spacewidth $$charwidth/" \ + -e "s/^internalname .*$$/internalname $@/" \ + -e "/^internalname/s/BI/3/" \ + -e "/^internalname/s/B/2/" \ + -e "/^internalname/s/I/1/" \ + -e "/^internalname .*[^ 0-9]/d" \ + $(.CURDIR)/R.proto >$@) + +DESC: DESC.proto + @echo Making $@ + @sed -e "s/^res .*$$/res $(RES)/" \ + -e "s/^hor .*$$/hor `echo $(RES) / $(CPI) | bc`/" \ + -e "s/^vert .*$$/vert `echo $(RES) / $(LPI) | bc`/" \ + -e "s/^fonts .*$$/fonts `set $(FONTS); echo $$#` $(FONTS)/" \ + $(.CURDIR)/DESC.proto >$@ diff --git a/gnu/usr.bin/groff/devices/devX100-12/CB b/gnu/usr.bin/groff/devices/devX100-12/CB new file mode 100644 index 0000000000..3751184aad --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/CB @@ -0,0 +1,306 @@ +name CB +spacewidth 10 +charset +--- 10,1 0 040 +! 10,11 0 041 +" 10,11 0 042 +# 10,11,1 0 043 +sh " +$ 10,12,1 0 044 +Do " +% 10,11 0 045 +& 10,9 0 046 +' 10,11 0 047 +( 10,11,2 0 050 +) 10,11,2 0 051 +* 10,11 0 052 ++ 10,9 0 053 +, 10,2,3 0 054 +\- 10,6 0 055 +. 10,2 0 056 +/ 10,12,2 0 057 +sl " +0 10,11 0 060 +1 10,11 0 061 +2 10,11 0 062 +3 10,11 0 063 +4 10,11 0 064 +5 10,11 0 065 +6 10,11 0 066 +7 10,11 0 067 +8 10,11 0 070 +9 10,11 0 071 +: 10,7 0 072 +; 10,7,3 0 073 +< 10,9 0 074 += 10,7 0 075 +eq " +> 10,9 0 076 +? 10,10 0 077 +@ 10,11,1 0 0100 +at " +A 10,10 0 0101 +B 10,10 0 0102 +C 10,10 0 0103 +D 10,10 0 0104 +E 10,10 0 0105 +F 10,10 0 0106 +G 10,10 0 0107 +H 10,10 0 0110 +I 10,10 0 0111 +J 10,10 0 0112 +K 10,10 0 0113 +L 10,10 0 0114 +M 10,10 0 0115 +N 10,10 0 0116 +O 10,10 0 0117 +P 10,10 0 0120 +Q 10,10,2 0 0121 +R 10,10 0 0122 +S 10,10 0 0123 +T 10,10 0 0124 +U 10,10 0 0125 +V 10,10 0 0126 +W 10,10 0 0127 +X 10,10 0 0130 +Y 10,10 0 0131 +Z 10,10 0 0132 +[ 10,11,2 0 0133 +lB " +\ 10,12,2 0 0134 +rs " +] 10,11,2 0 0135 +rB " +^ 10,11 0 0136 +a^ " +ha " +_ 10,0,3 0 0137 +` 10,11 0 0140 +oq " +a 10,7 0 0141 +b 10,11 0 0142 +c 10,7 0 0143 +d 10,11 0 0144 +e 10,7 0 0145 +f 10,11 0 0146 +g 10,7,3 0 0147 +h 10,11 0 0150 +i 10,10 0 0151 +j 10,10,3 0 0152 +k 10,11 0 0153 +l 10,11 0 0154 +m 10,7 0 0155 +n 10,7 0 0156 +o 10,7 0 0157 +p 10,7,3 0 0160 +q 10,7,3 0 0161 +r 10,7 0 0162 +s 10,7 0 0163 +t 10,9 0 0164 +u 10,7 0 0165 +v 10,7 0 0166 +w 10,7 0 0167 +x 10,7 0 0170 +y 10,7,3 0 0171 +z 10,7 0 0172 +{ 10,11,2 0 0173 +lC " +| 10,11,2 0 0174 +or " +ba " +} 10,11,2 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 10,7,3 0 0241 +¡ " +ct 10,10 0 0242 +¢ " +Po 10,10 0 0243 +£ " +Cs 10,8 0 0244 +¤ " +Ye 10,10 0 0245 +¥ " +bb 10,11,2 0 0246 +¦ " +sc 10,11,1 0 0247 +§ " +ad 10,10 0 0250 +¨ " +co 10,10 0 0251 +© " +Of 10,10 0 0252 +ª " +Fo 10,7 0 0253 +« " +no 10,7 0 0254 +¬ " +- 10,6 0 0255 +hy " +­ " +rg 10,10 0 0256 +® " +a- 10,10 0 0257 +¯ " +de 10,11 0 0260 +° " ++- 10,9 0 0261 +± " +S2 10,11 0 0262 +² " +S3 10,11 0 0263 +³ " +aa 10,11 0 0264 +´ " +µ 10,7,3 0 0265 +ps 10,11,1 0 0266 +¶ " +md 10,6 0 0267 +· " +ac 10,1,3 0 0270 +¸ " +S1 10,11 0 0271 +¹ " +Om 10,10 0 0272 +º " +Fc 10,7 0 0273 +» " +14 10,11 0 0274 +¼ " +12 10,11 0 0275 +½ " +34 10,11 0 0276 +¾ " +r? 10,7,3 0 0277 +¿ " +`A 10,14 0 0300 +À " +'A 10,14 0 0301 +Á " +^A 10,14 0 0302 +Â " +~A 10,13 0 0303 +Ã " +:A 10,13 0 0304 +Ä " +oA 10,14 0 0305 +Å " +AE 10,10 0 0306 +Æ " +,C 10,10,3 0 0307 +Ç " +`E 10,14 0 0310 +È " +'E 10,14 0 0311 +É " +^E 10,14 0 0312 +Ê " +:E 10,13 0 0313 +Ë " +`I 10,14 0 0314 +Ì " +'I 10,14 0 0315 +Í " +^I 10,14 0 0316 +Î " +:I 10,13 0 0317 +Ï " +-D 10,10 0 0320 +Ð " +~N 10,13 0 0321 +Ñ " +`O 10,14 0 0322 +Ò " +'O 10,14 0 0323 +Ó " +^O 10,14 0 0324 +Ô " +~O 10,13 0 0325 +Õ " +:O 10,13 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 10,11,1 0 0330 +Ø " +`U 10,14 0 0331 +Ù " +'U 10,14 0 0332 +Ú " +^U 10,14 0 0333 +Û " +:U 10,13 0 0334 +Ü " +'Y 10,14 0 0335 +Ý " +TP 10,10 0 0336 +Þ " +ss 10,11 0 0337 +ß " +`a 10,11 0 0340 +à " +'a 10,11 0 0341 +á " +^a 10,11 0 0342 +â " +~a 10,10 0 0343 +ã " +:a 10,10 0 0344 +ä " +oa 10,12 0 0345 +å " +ae 10,7 0 0346 +æ " +,c 10,7,3 0 0347 +ç " +`e 10,11 0 0350 +è " +'e 10,11 0 0351 +é " +^e 10,11 0 0352 +ê " +:e 10,10 0 0353 +ë " +`i 10,11 0 0354 +ì " +'i 10,11 0 0355 +í " +^i 10,11 0 0356 +î " +:i 10,10 0 0357 +ï " +Sd 10,12 0 0360 +ð " +~n 10,10 0 0361 +ñ " +`o 10,11 0 0362 +ò " +'o 10,11 0 0363 +ó " +^o 10,11 0 0364 +ô " +~o 10,10 0 0365 +õ " +:o 10,10 0 0366 +ö " +di 10,9 0 0367 +÷ " +/o 10,8,1 0 0370 +ø " +`u 10,11 0 0371 +ù " +'u 10,11 0 0372 +ú " +^u 10,11 0 0373 +û " +:u 10,10 0 0374 +ü " +'y 10,11,3 0 0375 +ý " +Tp 10,11,3 0 0376 +þ " +:y 10,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/CBI b/gnu/usr.bin/groff/devices/devX100-12/CBI new file mode 100644 index 0000000000..d7d0145a09 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/CBI @@ -0,0 +1,306 @@ +name CBI +spacewidth 10 +charset +--- 10,1 0 040 +! 10,11 0 041 +" 10,11 0 042 +# 10,11,1 0 043 +sh " +$ 10,12,1 0 044 +Do " +% 10,11 0 045 +& 10,9 0 046 +' 10,11 0 047 +( 10,11,2 0 050 +) 10,11,2 0 051 +* 10,11 0 052 ++ 10,9 0 053 +, 10,2,3 0 054 +\- 10,6 0 055 +. 10,2 0 056 +/ 10,12,2 0 057 +sl " +0 10,11 0 060 +1 10,11 0 061 +2 10,11 0 062 +3 10,11 0 063 +4 10,11 0 064 +5 10,11 0 065 +6 10,11 0 066 +7 10,11 0 067 +8 10,11 0 070 +9 10,11 0 071 +: 10,7 0 072 +; 10,7,3 0 073 +< 10,9 0 074 += 10,7 0 075 +eq " +> 10,9 0 076 +? 10,10 0 077 +@ 10,11,1 0 0100 +at " +A 10,10 0 0101 +B 10,10 0 0102 +C 10,10 0 0103 +D 10,10 0 0104 +E 10,10 0 0105 +F 10,10 0 0106 +G 10,10 0 0107 +H 10,10 0 0110 +I 10,10 0 0111 +J 10,10 0 0112 +K 10,10 0 0113 +L 10,10 0 0114 +M 10,10 0 0115 +N 10,10 0 0116 +O 10,10 0 0117 +P 10,10 0 0120 +Q 10,10,2 0 0121 +R 10,10 0 0122 +S 10,10 0 0123 +T 10,10 0 0124 +U 10,10 0 0125 +V 10,10 0 0126 +W 10,10 0 0127 +X 10,10 0 0130 +Y 10,10 0 0131 +Z 10,10 0 0132 +[ 10,11,2 0 0133 +lB " +\ 10,12,2 0 0134 +rs " +] 10,11,2 0 0135 +rB " +^ 10,11 0 0136 +a^ " +ha " +_ 10,0,3 0 0137 +` 10,11 0 0140 +oq " +a 10,7 0 0141 +b 10,11 0 0142 +c 10,7 0 0143 +d 10,11 0 0144 +e 10,7 0 0145 +f 10,11 0 0146 +g 10,7,3 0 0147 +h 10,11 0 0150 +i 10,10 0 0151 +j 10,10,3 0 0152 +k 10,11 0 0153 +l 10,11 0 0154 +m 10,7 0 0155 +n 10,7 0 0156 +o 10,7 0 0157 +p 10,7,3 0 0160 +q 10,7,3 0 0161 +r 10,7 0 0162 +s 10,7 0 0163 +t 10,9 0 0164 +u 10,7 0 0165 +v 10,7 0 0166 +w 10,7 0 0167 +x 10,7 0 0170 +y 10,7,3 0 0171 +z 10,7 0 0172 +{ 10,11,2 0 0173 +lC " +| 10,11,2 0 0174 +or " +ba " +} 10,11,2 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 10,7,4 0 0241 +¡ " +ct 10,10 0 0242 +¢ " +Po 10,10 0 0243 +£ " +Cs 10,8 0 0244 +¤ " +Ye 10,10 0 0245 +¥ " +bb 10,11,2 0 0246 +¦ " +sc 10,11,1 0 0247 +§ " +ad 10,10 0 0250 +¨ " +co 10,10 0 0251 +© " +Of 10,10 0 0252 +ª " +Fo 10,7 0 0253 +« " +no 10,7 0 0254 +¬ " +- 10,6 0 0255 +hy " +­ " +rg 10,10 0 0256 +® " +a- 10,9 0 0257 +¯ " +de 10,11 0 0260 +° " ++- 10,10 0 0261 +± " +S2 10,11 0 0262 +² " +S3 10,11 0 0263 +³ " +aa 10,11 0 0264 +´ " +µ 10,7,3 0 0265 +ps 10,11,1 0 0266 +¶ " +md 10,6 0 0267 +· " +ac 10,0,3 0 0270 +¸ " +S1 10,11 0 0271 +¹ " +Om 10,10 0 0272 +º " +Fc 10,7 0 0273 +» " +14 10,11 0 0274 +¼ " +12 10,11 0 0275 +½ " +34 10,11 0 0276 +¾ " +r? 10,7,4 0 0277 +¿ " +`A 10,14 0 0300 +À " +'A 10,14 0 0301 +Á " +^A 10,14 0 0302 +Â " +~A 10,13 0 0303 +Ã " +:A 10,13 0 0304 +Ä " +oA 10,14 0 0305 +Å " +AE 10,10 0 0306 +Æ " +,C 10,10,3 0 0307 +Ç " +`E 10,14 0 0310 +È " +'E 10,14 0 0311 +É " +^E 10,14 0 0312 +Ê " +:E 10,13 0 0313 +Ë " +`I 10,14 0 0314 +Ì " +'I 10,14 0 0315 +Í " +^I 10,14 0 0316 +Î " +:I 10,13 0 0317 +Ï " +-D 10,10 0 0320 +Ð " +~N 10,13 0 0321 +Ñ " +`O 10,14 0 0322 +Ò " +'O 10,14 0 0323 +Ó " +^O 10,14 0 0324 +Ô " +~O 10,13 0 0325 +Õ " +:O 10,13 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 10,10 0 0330 +Ø " +`U 10,14 0 0331 +Ù " +'U 10,14 0 0332 +Ú " +^U 10,14 0 0333 +Û " +:U 10,13 0 0334 +Ü " +'Y 10,14 0 0335 +Ý " +TP 10,10 0 0336 +Þ " +ss 10,11 0 0337 +ß " +`a 10,11 0 0340 +à " +'a 10,11 0 0341 +á " +^a 10,11 0 0342 +â " +~a 10,10 0 0343 +ã " +:a 10,10 0 0344 +ä " +oa 10,11 0 0345 +å " +ae 10,7 0 0346 +æ " +,c 10,7,3 0 0347 +ç " +`e 10,11 0 0350 +è " +'e 10,11 0 0351 +é " +^e 10,11 0 0352 +ê " +:e 10,10 0 0353 +ë " +`i 10,11 0 0354 +ì " +'i 10,11 0 0355 +í " +^i 10,11 0 0356 +î " +:i 10,10 0 0357 +ï " +Sd 10,12 0 0360 +ð " +~n 10,10 0 0361 +ñ " +`o 10,11 0 0362 +ò " +'o 10,11 0 0363 +ó " +^o 10,11 0 0364 +ô " +~o 10,10 0 0365 +õ " +:o 10,10 0 0366 +ö " +di 10,9 0 0367 +÷ " +/o 10,8,1 0 0370 +ø " +`u 10,11 0 0371 +ù " +'u 10,11 0 0372 +ú " +^u 10,11 0 0373 +û " +:u 10,10 0 0374 +ü " +'y 10,11,3 0 0375 +ý " +Tp 10,11,3 0 0376 +þ " +:y 10,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/CI b/gnu/usr.bin/groff/devices/devX100-12/CI new file mode 100644 index 0000000000..804f71f779 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/CI @@ -0,0 +1,306 @@ +name CI +spacewidth 10 +charset +--- 10,1 0 040 +! 10,11 0 041 +" 10,11 0 042 +# 10,11,1 0 043 +sh " +$ 10,12,1 0 044 +Do " +% 10,11 0 045 +& 10,9 0 046 +' 10,11 0 047 +( 10,11,2 0 050 +) 10,11,2 0 051 +* 10,10 0 052 ++ 10,9 0 053 +, 10,2,2 0 054 +\- 10,5 0 055 +. 10,2 0 056 +/ 10,11,2 0 057 +sl " +0 10,11 0 060 +1 10,11 0 061 +2 10,11 0 062 +3 10,11 0 063 +4 10,11 0 064 +5 10,11 0 065 +6 10,11 0 066 +7 10,11 0 067 +8 10,11 0 070 +9 10,11 0 071 +: 10,7 0 072 +; 10,7,2 0 073 +< 10,9 0 074 += 10,7 0 075 +eq " +> 10,9 0 076 +? 10,10 0 077 +@ 10,11,1 0 0100 +at " +A 10,10 0 0101 +B 10,10 0 0102 +C 10,10 0 0103 +D 10,10 0 0104 +E 10,10 0 0105 +F 10,10 0 0106 +G 10,10 0 0107 +H 10,10 0 0110 +I 10,10 0 0111 +J 10,10 0 0112 +K 10,10 0 0113 +L 10,10 0 0114 +M 10,10 0 0115 +N 10,10 0 0116 +O 10,10 0 0117 +P 10,10 0 0120 +Q 10,10,2 0 0121 +R 10,10 0 0122 +S 10,10 0 0123 +T 10,10 0 0124 +U 10,10 0 0125 +V 10,10 0 0126 +W 10,10 0 0127 +X 10,10 0 0130 +Y 10,10 0 0131 +Z 10,10 0 0132 +[ 10,11,2 0 0133 +lB " +\ 10,11,2 0 0134 +rs " +] 10,11,2 0 0135 +rB " +^ 10,11 0 0136 +a^ " +ha " +_ 10,0,3 0 0137 +` 10,11 0 0140 +oq " +a 10,7 0 0141 +b 10,10 0 0142 +c 10,7 0 0143 +d 10,10 0 0144 +e 10,7 0 0145 +f 10,10 0 0146 +g 10,7,3 0 0147 +h 10,10 0 0150 +i 10,11 0 0151 +j 10,11,3 0 0152 +k 10,10 0 0153 +l 10,10 0 0154 +m 10,7 0 0155 +n 10,7 0 0156 +o 10,7 0 0157 +p 10,7,3 0 0160 +q 10,7,3 0 0161 +r 10,7 0 0162 +s 10,7 0 0163 +t 10,9 0 0164 +u 10,7 0 0165 +v 10,7 0 0166 +w 10,7 0 0167 +x 10,7 0 0170 +y 10,7,3 0 0171 +z 10,7 0 0172 +{ 10,11,2 0 0173 +lC " +| 10,10,2 0 0174 +or " +ba " +} 10,11,2 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 10,7,4 0 0241 +¡ " +ct 10,10 0 0242 +¢ " +Po 10,10 0 0243 +£ " +Cs 10,8 0 0244 +¤ " +Ye 10,10 0 0245 +¥ " +bb 10,11,2 0 0246 +¦ " +sc 10,11,1 0 0247 +§ " +ad 10,10 0 0250 +¨ " +co 10,10 0 0251 +© " +Of 10,10 0 0252 +ª " +Fo 10,7 0 0253 +« " +no 10,6 0 0254 +¬ " +- 10,5 0 0255 +hy " +­ " +rg 10,10 0 0256 +® " +a- 10,10 0 0257 +¯ " +de 10,11 0 0260 +° " ++- 10,9 0 0261 +± " +S2 10,11 0 0262 +² " +S3 10,11 0 0263 +³ " +aa 10,11 0 0264 +´ " +µ 10,7,3 0 0265 +ps 10,11,1 0 0266 +¶ " +md 10,6 0 0267 +· " +ac 10,0,3 0 0270 +¸ " +S1 10,11 0 0271 +¹ " +Om 10,10 0 0272 +º " +Fc 10,7 0 0273 +» " +14 10,11 0 0274 +¼ " +12 10,11 0 0275 +½ " +34 10,11 0 0276 +¾ " +r? 10,7,3 0 0277 +¿ " +`A 10,14 0 0300 +À " +'A 10,14 0 0301 +Á " +^A 10,14 0 0302 +Â " +~A 10,13 0 0303 +Ã " +:A 10,13 0 0304 +Ä " +oA 10,14 0 0305 +Å " +AE 10,10 0 0306 +Æ " +,C 10,10,3 0 0307 +Ç " +`E 10,14 0 0310 +È " +'E 10,14 0 0311 +É " +^E 10,14 0 0312 +Ê " +:E 10,13 0 0313 +Ë " +`I 10,14 0 0314 +Ì " +'I 10,14 0 0315 +Í " +^I 10,14 0 0316 +Î " +:I 10,13 0 0317 +Ï " +-D 10,10 0 0320 +Ð " +~N 10,13 0 0321 +Ñ " +`O 10,14 0 0322 +Ò " +'O 10,14 0 0323 +Ó " +^O 10,14 0 0324 +Ô " +~O 10,13 0 0325 +Õ " +:O 10,13 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 10,10 0 0330 +Ø " +`U 10,14 0 0331 +Ù " +'U 10,14 0 0332 +Ú " +^U 10,14 0 0333 +Û " +:U 10,13 0 0334 +Ü " +'Y 10,14 0 0335 +Ý " +TP 10,10 0 0336 +Þ " +ss 10,11 0 0337 +ß " +`a 10,11 0 0340 +à " +'a 10,11 0 0341 +á " +^a 10,11 0 0342 +â " +~a 10,10 0 0343 +ã " +:a 10,10 0 0344 +ä " +oa 10,11 0 0345 +å " +ae 10,7 0 0346 +æ " +,c 10,7,3 0 0347 +ç " +`e 10,11 0 0350 +è " +'e 10,11 0 0351 +é " +^e 10,11 0 0352 +ê " +:e 10,10 0 0353 +ë " +`i 10,11 0 0354 +ì " +'i 10,11 0 0355 +í " +^i 10,11 0 0356 +î " +:i 10,10 0 0357 +ï " +Sd 10,11 0 0360 +ð " +~n 10,10 0 0361 +ñ " +`o 10,11 0 0362 +ò " +'o 10,11 0 0363 +ó " +^o 10,11 0 0364 +ô " +~o 10,10 0 0365 +õ " +:o 10,10 0 0366 +ö " +di 10,8 0 0367 +÷ " +/o 10,8,1 0 0370 +ø " +`u 10,11 0 0371 +ù " +'u 10,11 0 0372 +ú " +^u 10,11 0 0373 +û " +:u 10,10 0 0374 +ü " +'y 10,11,3 0 0375 +ý " +Tp 10,11,3 0 0376 +þ " +:y 10,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/CR b/gnu/usr.bin/groff/devices/devX100-12/CR new file mode 100644 index 0000000000..140ec55d07 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/CR @@ -0,0 +1,306 @@ +name CR +spacewidth 10 +charset +--- 10,1 0 040 +! 10,11 0 041 +" 10,11 0 042 +# 10,11,1 0 043 +sh " +$ 10,12,1 0 044 +Do " +% 10,11 0 045 +& 10,9 0 046 +' 10,11 0 047 +( 10,11,2 0 050 +) 10,11,2 0 051 +* 10,11 0 052 ++ 10,9 0 053 +, 10,2,2 0 054 +\- 10,5 0 055 +. 10,2 0 056 +/ 10,11,2 0 057 +sl " +0 10,11 0 060 +1 10,11 0 061 +2 10,11 0 062 +3 10,11 0 063 +4 10,11 0 064 +5 10,11 0 065 +6 10,11 0 066 +7 10,11 0 067 +8 10,11 0 070 +9 10,11 0 071 +: 10,7 0 072 +; 10,7,2 0 073 +< 10,9 0 074 += 10,7 0 075 +eq " +> 10,9 0 076 +? 10,10 0 077 +@ 10,11,1 0 0100 +at " +A 10,10 0 0101 +B 10,10 0 0102 +C 10,10 0 0103 +D 10,10 0 0104 +E 10,10 0 0105 +F 10,10 0 0106 +G 10,10 0 0107 +H 10,10 0 0110 +I 10,10 0 0111 +J 10,10 0 0112 +K 10,10 0 0113 +L 10,10 0 0114 +M 10,10 0 0115 +N 10,10 0 0116 +O 10,10 0 0117 +P 10,10 0 0120 +Q 10,10,2 0 0121 +R 10,10 0 0122 +S 10,10 0 0123 +T 10,10 0 0124 +U 10,10 0 0125 +V 10,10 0 0126 +W 10,10 0 0127 +X 10,10 0 0130 +Y 10,10 0 0131 +Z 10,10 0 0132 +[ 10,11,2 0 0133 +lB " +\ 10,11,2 0 0134 +rs " +] 10,11,2 0 0135 +rB " +^ 10,11 0 0136 +a^ " +ha " +_ 10,0,3 0 0137 +` 10,11 0 0140 +oq " +a 10,7 0 0141 +b 10,10 0 0142 +c 10,7 0 0143 +d 10,10 0 0144 +e 10,7 0 0145 +f 10,10 0 0146 +g 10,7,3 0 0147 +h 10,10 0 0150 +i 10,10 0 0151 +j 10,10,3 0 0152 +k 10,10 0 0153 +l 10,10 0 0154 +m 10,7 0 0155 +n 10,7 0 0156 +o 10,7 0 0157 +p 10,7,3 0 0160 +q 10,7,3 0 0161 +r 10,7 0 0162 +s 10,7 0 0163 +t 10,9 0 0164 +u 10,7 0 0165 +v 10,7 0 0166 +w 10,7 0 0167 +x 10,7 0 0170 +y 10,7,3 0 0171 +z 10,7 0 0172 +{ 10,11,2 0 0173 +lC " +| 10,10,2 0 0174 +or " +ba " +} 10,11,2 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 10,7,3 0 0241 +¡ " +ct 10,10 0 0242 +¢ " +Po 10,10 0 0243 +£ " +Cs 10,8 0 0244 +¤ " +Ye 10,10 0 0245 +¥ " +bb 10,10,2 0 0246 +¦ " +sc 10,11,1 0 0247 +§ " +ad 10,10 0 0250 +¨ " +co 10,10 0 0251 +© " +Of 10,10 0 0252 +ª " +Fo 10,7 0 0253 +« " +no 10,6 0 0254 +¬ " +- 10,5 0 0255 +hy " +­ " +rg 10,10 0 0256 +® " +a- 10,9 0 0257 +¯ " +de 10,11 0 0260 +° " ++- 10,9 0 0261 +± " +S2 10,11 0 0262 +² " +S3 10,11 0 0263 +³ " +aa 10,11 0 0264 +´ " +µ 10,7,3 0 0265 +ps 10,11,1 0 0266 +¶ " +md 10,6 0 0267 +· " +ac 10,1,3 0 0270 +¸ " +S1 10,11 0 0271 +¹ " +Om 10,10 0 0272 +º " +Fc 10,7 0 0273 +» " +14 10,11 0 0274 +¼ " +12 10,11 0 0275 +½ " +34 10,11 0 0276 +¾ " +r? 10,7,3 0 0277 +¿ " +`A 10,14 0 0300 +À " +'A 10,14 0 0301 +Á " +^A 10,14 0 0302 +Â " +~A 10,13 0 0303 +Ã " +:A 10,13 0 0304 +Ä " +oA 10,14 0 0305 +Å " +AE 10,10 0 0306 +Æ " +,C 10,10,3 0 0307 +Ç " +`E 10,14 0 0310 +È " +'E 10,14 0 0311 +É " +^E 10,14 0 0312 +Ê " +:E 10,13 0 0313 +Ë " +`I 10,14 0 0314 +Ì " +'I 10,14 0 0315 +Í " +^I 10,14 0 0316 +Î " +:I 10,13 0 0317 +Ï " +-D 10,10 0 0320 +Ð " +~N 10,13 0 0321 +Ñ " +`O 10,14 0 0322 +Ò " +'O 10,14 0 0323 +Ó " +^O 10,14 0 0324 +Ô " +~O 10,13 0 0325 +Õ " +:O 10,13 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 10,10 0 0330 +Ø " +`U 10,14 0 0331 +Ù " +'U 10,14 0 0332 +Ú " +^U 10,14 0 0333 +Û " +:U 10,13 0 0334 +Ü " +'Y 10,14 0 0335 +Ý " +TP 10,10 0 0336 +Þ " +ss 10,11 0 0337 +ß " +`a 10,11 0 0340 +à " +'a 10,11 0 0341 +á " +^a 10,11 0 0342 +â " +~a 10,10 0 0343 +ã " +:a 10,10 0 0344 +ä " +oa 10,12 0 0345 +å " +ae 10,7 0 0346 +æ " +,c 10,7,3 0 0347 +ç " +`e 10,11 0 0350 +è " +'e 10,11 0 0351 +é " +^e 10,11 0 0352 +ê " +:e 10,10 0 0353 +ë " +`i 10,11 0 0354 +ì " +'i 10,11 0 0355 +í " +^i 10,11 0 0356 +î " +:i 10,10 0 0357 +ï " +Sd 10,11 0 0360 +ð " +~n 10,10 0 0361 +ñ " +`o 10,11 0 0362 +ò " +'o 10,11 0 0363 +ó " +^o 10,11 0 0364 +ô " +~o 10,10 0 0365 +õ " +:o 10,10 0 0366 +ö " +di 10,8 0 0367 +÷ " +/o 10,8,1 0 0370 +ø " +`u 10,11 0 0371 +ù " +'u 10,11 0 0372 +ú " +^u 10,11 0 0373 +û " +:u 10,10 0 0374 +ü " +'y 10,11,3 0 0375 +ý " +Tp 10,11,3 0 0376 +þ " +:y 10,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/DESC b/gnu/usr.bin/groff/devices/devX100-12/DESC new file mode 100644 index 0000000000..ead70b97f0 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/DESC @@ -0,0 +1,9 @@ +styles R I B BI +fonts 6 0 0 0 0 0 S +sizes 8 10 12 14 18 24 0 +res 100 +X11 +hor 1 +vert 1 +unitwidth 12 +postpro gxditview diff --git a/gnu/usr.bin/groff/devices/devX100-12/HB b/gnu/usr.bin/groff/devices/devX100-12/HB new file mode 100644 index 0000000000..e68615e14a --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/HB @@ -0,0 +1,306 @@ +name HB +spacewidth 5 +charset +--- 5,1 0 040 +! 6,12 0 041 +" 8,12 0 042 +# 9,12 0 043 +sh " +$ 9,13,1 0 044 +Do " +% 14,12 0 045 +& 12,12 0 046 +' 5,12 0 047 +( 6,12,3 0 050 +) 6,12,3 0 051 +* 6,12 0 052 ++ 10,8 0 053 +, 4,2,3 0 054 +\- 10,5 0 055 +. 4,2 0 056 +/ 5,12 0 057 +sl " +0 9,12 0 060 +1 9,12 0 061 +2 9,12 0 062 +3 9,12 0 063 +4 9,12 0 064 +5 9,12 0 065 +6 9,12 0 066 +7 9,12 0 067 +8 9,12 0 070 +9 9,12 0 071 +: 5,8 0 072 +; 5,8,3 0 073 +< 10,8 0 074 += 10,7 0 075 +eq " +> 10,8 0 076 +? 10,12 0 077 +@ 16,12,2 0 0100 +at " +A 12,12 0 0101 +B 12,12 0 0102 +C 12,12 0 0103 +D 12,12 0 0104 +E 11,12 0 0105 +F 10,12 0 0106 +G 13,12 0 0107 +H 12,12 0 0110 +I 4,12 0 0111 +J 9,12 0 0112 +K 12,12 0 0113 +L 10,12 0 0114 +M 13,12 0 0115 +N 12,12 0 0116 +O 13,12 0 0117 +P 11,12 0 0120 +Q 13,12,1 0 0121 +R 12,12 0 0122 +S 11,12 0 0123 +T 10,12 0 0124 +U 12,12 0 0125 +V 11,12 0 0126 +W 15,12 0 0127 +X 11,12 0 0130 +Y 11,12 0 0131 +Z 10,12 0 0132 +[ 6,12,3 0 0133 +lB " +\ 5,12 0 0134 +rs " +] 6,12,3 0 0135 +rB " +^ 10,12 0 0136 +a^ " +ha " +_ 9,0,3 0 0137 +` 5,12 0 0140 +oq " +a 9,9 0 0141 +b 10,12 0 0142 +c 9,9 0 0143 +d 10,12 0 0144 +e 9,9 0 0145 +f 5,12 0 0146 +g 10,9,4 0 0147 +h 10,12 0 0150 +i 4,12 0 0151 +j 5,12,4 0 0152 +k 9,12 0 0153 +l 5,12 0 0154 +m 14,9 0 0155 +n 10,9 0 0156 +o 10,9 0 0157 +p 10,9,4 0 0160 +q 10,9,4 0 0161 +r 6,9 0 0162 +s 9,9 0 0163 +t 6,11 0 0164 +u 10,9 0 0165 +v 9,9 0 0166 +w 13,9 0 0167 +x 9,9 0 0170 +y 9,9,4 0 0171 +z 8,9 0 0172 +{ 6,12,3 0 0173 +lC " +| 4,12,4 0 0174 +or " +ba " +} 6,12,3 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 6,9,3 0 0241 +¡ " +ct 9,10,1 0 0242 +¢ " +Po 9,12 0 0243 +£ " +Cs 9,9 0 0244 +¤ " +Ye 9,12 0 0245 +¥ " +bb 5,12,4 0 0246 +¦ " +sc 9,12,3 0 0247 +§ " +ad 6,12 0 0250 +¨ " +co 12,12 0 0251 +© " +Of 6,12 0 0252 +ª " +Fo 9,8 0 0253 +« " +no 10,7 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,12 0 0256 +® " +a- 6,11 0 0257 +¯ " +de 7,12 0 0260 +° " ++- 10,11 0 0261 +± " +S2 6,12 0 0262 +² " +S3 6,12 0 0263 +³ " +aa 6,13 0 0264 +´ " +µ 10,9,3 0 0265 +ps 9,12,3 0 0266 +¶ " +md 5,6 0 0267 +· " +ac 6,0,4 0 0270 +¸ " +S1 6,12 0 0271 +¹ " +Om 6,12 0 0272 +º " +Fc 9,8 0 0273 +» " +14 14,12 0 0274 +¼ " +12 14,12 0 0275 +½ " +34 14,12 0 0276 +¾ " +r? 10,9,3 0 0277 +¿ " +`A 12,16 0 0300 +À " +'A 12,16 0 0301 +Á " +^A 12,16 0 0302 +Â " +~A 12,15 0 0303 +Ã " +:A 12,15 0 0304 +Ä " +oA 12,16 0 0305 +Å " +AE 16,12 0 0306 +Æ " +,C 12,12,4 0 0307 +Ç " +`E 11,16 0 0310 +È " +'E 11,16 0 0311 +É " +^E 11,16 0 0312 +Ê " +:E 11,15 0 0313 +Ë " +`I 4,16 0 0314 +Ì " +'I 4,16 0 0315 +Í " +^I 4,16 0 0316 +Î " +:I 4,15 0 0317 +Ï " +-D 12,12 0 0320 +Ð " +~N 12,15 0 0321 +Ñ " +`O 13,16 0 0322 +Ò " +'O 13,16 0 0323 +Ó " +^O 13,16 0 0324 +Ô " +~O 13,15 0 0325 +Õ " +:O 13,15 0 0326 +Ö " +mu 10,9 0 0327 +× " +/O 13,12 0 0330 +Ø " +`U 12,16 0 0331 +Ù " +'U 12,16 0 0332 +Ú " +^U 12,16 0 0333 +Û " +:U 12,15 0 0334 +Ü " +'Y 11,16 0 0335 +Ý " +TP 11,12 0 0336 +Þ " +ss 10,12 0 0337 +ß " +`a 9,13 0 0340 +à " +'a 9,13 0 0341 +á " +^a 9,13 0 0342 +â " +~a 9,12 0 0343 +ã " +:a 9,12 0 0344 +ä " +oa 9,13 0 0345 +å " +ae 15,9 0 0346 +æ " +,c 9,9,4 0 0347 +ç " +`e 9,13 0 0350 +è " +'e 9,13 0 0351 +é " +^e 9,13 0 0352 +ê " +:e 9,12 0 0353 +ë " +`i 4,13 0 0354 +ì " +'i 4,13 0 0355 +í " +^i 4,13 0 0356 +î " +:i 4,12 0 0357 +ï " +Sd 10,12 0 0360 +ð " +~n 10,12 0 0361 +ñ " +`o 10,13 0 0362 +ò " +'o 10,13 0 0363 +ó " +^o 10,13 0 0364 +ô " +~o 10,12 0 0365 +õ " +:o 10,12 0 0366 +ö " +di 10,8 0 0367 +÷ " +/o 10,9 0 0370 +ø " +`u 10,13 0 0371 +ù " +'u 10,13 0 0372 +ú " +^u 10,13 0 0373 +û " +:u 10,12 0 0374 +ü " +'y 9,13,4 0 0375 +ý " +Tp 10,12,4 0 0376 +þ " +:y 9,12,4 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/HBI b/gnu/usr.bin/groff/devices/devX100-12/HBI new file mode 100644 index 0000000000..6723ddff12 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/HBI @@ -0,0 +1,306 @@ +name HBI +spacewidth 5 +charset +--- 5,1 0 040 +! 6,12 0 041 +" 8,12 0 042 +# 9,12 0 043 +sh " +$ 9,13,1 0 044 +Do " +% 14,12 0 045 +& 12,12 0 046 +' 5,12 0 047 +( 6,12,3 0 050 +) 6,12,3 0 051 +* 6,12 0 052 ++ 10,8 0 053 +, 4,2,3 0 054 +\- 10,5 0 055 +. 4,2 0 056 +/ 5,12 0 057 +sl " +0 10,12 0 060 +1 9,12 0 061 +2 10,12 0 062 +3 9,12 0 063 +4 9,12 0 064 +5 9,12 0 065 +6 9,12 0 066 +7 9,12 0 067 +8 9,12 0 070 +9 9,12 0 071 +: 5,8 0 072 +; 5,8,3 0 073 +< 10,8 0 074 += 10,7 0 075 +eq " +> 10,8 0 076 +? 10,12 0 077 +@ 16,12,2 0 0100 +at " +A 12,12 0 0101 +B 12,12 0 0102 +C 12,12 0 0103 +D 12,12 0 0104 +E 11,12 0 0105 +F 10,12 0 0106 +G 13,12 0 0107 +H 12,12 0 0110 +I 4,12 0 0111 +J 9,12 0 0112 +K 12,12 0 0113 +L 10,12 0 0114 +M 13,12 0 0115 +N 12,12 0 0116 +O 13,12 0 0117 +P 11,12 0 0120 +Q 13,12,1 0 0121 +R 12,12 0 0122 +S 11,12 0 0123 +T 10,12 0 0124 +U 12,12 0 0125 +V 11,12 0 0126 +W 15,12 0 0127 +X 11,12 0 0130 +Y 11,12 0 0131 +Z 10,12 0 0132 +[ 6,12,3 0 0133 +lB " +\ 5,12 0 0134 +rs " +] 6,12,3 0 0135 +rB " +^ 10,12 0 0136 +a^ " +ha " +_ 9,0,3 0 0137 +` 5,12 0 0140 +oq " +a 9,9 0 0141 +b 10,12 0 0142 +c 9,9 0 0143 +d 10,12 0 0144 +e 9,9 0 0145 +f 5,12 0 0146 +g 10,9,4 0 0147 +h 10,12 0 0150 +i 4,12 0 0151 +j 5,12,4 0 0152 +k 9,12 0 0153 +l 5,12 0 0154 +m 14,9 0 0155 +n 10,9 0 0156 +o 10,9 0 0157 +p 10,9,4 0 0160 +q 10,9,4 0 0161 +r 6,9 0 0162 +s 9,9 0 0163 +t 6,12 0 0164 +u 10,9 0 0165 +v 9,9 0 0166 +w 13,9 0 0167 +x 9,9 0 0170 +y 9,9,4 0 0171 +z 8,9 0 0172 +{ 6,12,3 0 0173 +lC " +| 3,12,4 0 0174 +or " +ba " +} 6,12,3 0 0175 +rC " +~ 10,5 0 0176 +a~ " +ap " +ti " +r! 6,9,3 0 0241 +¡ " +ct 9,10,1 0 0242 +¢ " +Po 9,12 0 0243 +£ " +Cs 9,9 0 0244 +¤ " +Ye 9,12 0 0245 +¥ " +bb 5,12,4 0 0246 +¦ " +sc 9,12,3 0 0247 +§ " +ad 6,12 0 0250 +¨ " +co 12,12 0 0251 +© " +Of 6,12 0 0252 +ª " +Fo 9,8 0 0253 +« " +no 10,7 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,12 0 0256 +® " +a- 6,11 0 0257 +¯ " +de 7,12 0 0260 +° " ++- 10,11 0 0261 +± " +S2 6,12 0 0262 +² " +S3 6,12 0 0263 +³ " +aa 6,13 0 0264 +´ " +µ 10,9,4 0 0265 +ps 9,12,3 0 0266 +¶ " +md 5,6 0 0267 +· " +ac 6,0,4 0 0270 +¸ " +S1 6,12 0 0271 +¹ " +Om 6,12 0 0272 +º " +Fc 9,8 0 0273 +» " +14 14,12 0 0274 +¼ " +12 14,12 0 0275 +½ " +34 14,12 0 0276 +¾ " +r? 10,9,3 0 0277 +¿ " +`A 12,16 0 0300 +À " +'A 12,16 0 0301 +Á " +^A 12,16 0 0302 +Â " +~A 12,15 0 0303 +Ã " +:A 12,15 0 0304 +Ä " +oA 12,15 0 0305 +Å " +AE 17,12 0 0306 +Æ " +,C 12,12,4 0 0307 +Ç " +`E 11,16 0 0310 +È " +'E 11,16 0 0311 +É " +^E 11,16 0 0312 +Ê " +:E 11,15 0 0313 +Ë " +`I 4,16 0 0314 +Ì " +'I 4,16 0 0315 +Í " +^I 4,16 0 0316 +Î " +:I 4,15 0 0317 +Ï " +-D 12,12 0 0320 +Ð " +~N 12,15 0 0321 +Ñ " +`O 13,16 0 0322 +Ò " +'O 13,16 0 0323 +Ó " +^O 13,16 0 0324 +Ô " +~O 13,15 0 0325 +Õ " +:O 13,15 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 13,12 0 0330 +Ø " +`U 12,16 0 0331 +Ù " +'U 12,16 0 0332 +Ú " +^U 12,16 0 0333 +Û " +:U 12,15 0 0334 +Ü " +'Y 11,16 0 0335 +Ý " +TP 11,12 0 0336 +Þ " +ss 10,12 0 0337 +ß " +`a 9,13 0 0340 +à " +'a 9,13 0 0341 +á " +^a 9,13 0 0342 +â " +~a 9,12 0 0343 +ã " +:a 9,12 0 0344 +ä " +oa 9,13 0 0345 +å " +ae 15,9 0 0346 +æ " +,c 9,9,4 0 0347 +ç " +`e 9,13 0 0350 +è " +'e 9,13 0 0351 +é " +^e 9,13 0 0352 +ê " +:e 9,12 0 0353 +ë " +`i 4,13 0 0354 +ì " +'i 4,13 0 0355 +í " +^i 4,13 0 0356 +î " +:i 4,12 0 0357 +ï " +Sd 10,13 0 0360 +ð " +~n 10,12 0 0361 +ñ " +`o 10,13 0 0362 +ò " +'o 10,13 0 0363 +ó " +^o 10,13 0 0364 +ô " +~o 10,12 0 0365 +õ " +:o 10,12 0 0366 +ö " +di 10,8 0 0367 +÷ " +/o 10,9 0 0370 +ø " +`u 10,13 0 0371 +ù " +'u 10,13 0 0372 +ú " +^u 10,13 0 0373 +û " +:u 10,12 0 0374 +ü " +'y 9,13,4 0 0375 +ý " +Tp 10,12,4 0 0376 +þ " +:y 9,12,4 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/HI b/gnu/usr.bin/groff/devices/devX100-12/HI new file mode 100644 index 0000000000..f002cd6304 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/HI @@ -0,0 +1,306 @@ +name HI +spacewidth 5 +charset +--- 5,1 0 040 +! 5,12 0 041 +" 6,12 0 042 +# 9,12 0 043 +sh " +$ 9,13,1 0 044 +Do " +% 14,12 0 045 +& 11,12 0 046 +' 4,12 0 047 +( 6,12,3 0 050 +) 6,12,3 0 051 +* 6,12 0 052 ++ 10,9 0 053 +, 4,2,2 0 054 +\- 10,5 0 055 +. 4,2 0 056 +/ 5,12 0 057 +sl " +0 9,12 0 060 +1 9,12 0 061 +2 9,12 0 062 +3 9,12 0 063 +4 9,12 0 064 +5 9,12 0 065 +6 9,12 0 066 +7 9,12 0 067 +8 9,12 0 070 +9 9,12 0 071 +: 4,9 0 072 +; 4,9,2 0 073 +< 10,9 0 074 += 10,6 0 075 +eq " +> 10,9 0 076 +? 9,12 0 077 +@ 17,12,1 0 0100 +at " +A 11,12 0 0101 +B 11,12 0 0102 +C 12,12 0 0103 +D 12,12 0 0104 +E 11,12 0 0105 +F 10,12 0 0106 +G 13,12 0 0107 +H 12,12 0 0110 +I 4,12 0 0111 +J 8,12 0 0112 +K 11,12 0 0113 +L 9,12 0 0114 +M 13,12 0 0115 +N 12,12 0 0116 +O 13,12 0 0117 +P 11,12 0 0120 +Q 13,12,1 0 0121 +R 12,12 0 0122 +S 11,12 0 0123 +T 10,12 0 0124 +U 12,12 0 0125 +V 11,12 0 0126 +W 16,12 0 0127 +X 11,12 0 0130 +Y 11,12 0 0131 +Z 10,12 0 0132 +[ 5,12,3 0 0133 +lB " +\ 5,12 0 0134 +rs " +] 5,12,3 0 0135 +rB " +^ 8,12 0 0136 +a^ " +ha " +_ 9,0,3 0 0137 +` 4,12 0 0140 +oq " +a 9,9 0 0141 +b 9,12 0 0142 +c 8,9 0 0143 +d 9,12 0 0144 +e 9,9 0 0145 +f 5,12 0 0146 +g 9,9,4 0 0147 +h 9,12 0 0150 +i 3,12 0 0151 +j 4,12,4 0 0152 +k 8,12 0 0153 +l 4,12 0 0154 +m 14,9 0 0155 +n 9,9 0 0156 +o 9,9 0 0157 +p 9,9,4 0 0160 +q 9,9,4 0 0161 +r 5,9 0 0162 +s 8,9 0 0163 +t 5,11 0 0164 +u 9,9 0 0165 +v 8,9 0 0166 +w 12,9 0 0167 +x 8,9 0 0170 +y 8,9,4 0 0171 +z 8,9 0 0172 +{ 6,12,3 0 0173 +lC " +| 3,12,4 0 0174 +or " +ba " +} 6,12,3 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 6,9,3 0 0241 +¡ " +ct 9,10,1 0 0242 +¢ " +Po 9,12 0 0243 +£ " +Cs 9,10 0 0244 +¤ " +Ye 9,12 0 0245 +¥ " +bb 4,12,4 0 0246 +¦ " +sc 9,12,3 0 0247 +§ " +ad 5,12 0 0250 +¨ " +co 12,12 0 0251 +© " +Of 6,12 0 0252 +ª " +Fo 9,8 0 0253 +« " +no 10,6 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,12 0 0256 +® " +a- 6,11 0 0257 +¯ " +de 7,12 0 0260 +° " ++- 10,11 0 0261 +± " +S2 6,12 0 0262 +² " +S3 6,12 0 0263 +³ " +aa 6,13 0 0264 +´ " +µ 9,9,4 0 0265 +ps 9,12,3 0 0266 +¶ " +md 5,7 0 0267 +· " +ac 6,0,4 0 0270 +¸ " +S1 6,12 0 0271 +¹ " +Om 6,12 0 0272 +º " +Fc 9,8 0 0273 +» " +14 14,12 0 0274 +¼ " +12 14,13 0 0275 +½ " +34 14,12 0 0276 +¾ " +r? 10,9,3 0 0277 +¿ " +`A 11,16 0 0300 +À " +'A 11,16 0 0301 +Á " +^A 11,16 0 0302 +Â " +~A 11,15 0 0303 +Ã " +:A 11,15 0 0304 +Ä " +oA 11,15 0 0305 +Å " +AE 16,12 0 0306 +Æ " +,C 12,12,3 0 0307 +Ç " +`E 11,16 0 0310 +È " +'E 11,16 0 0311 +É " +^E 11,16 0 0312 +Ê " +:E 11,15 0 0313 +Ë " +`I 4,16 0 0314 +Ì " +'I 4,16 0 0315 +Í " +^I 4,16 0 0316 +Î " +:I 4,15 0 0317 +Ï " +-D 12,12 0 0320 +Ð " +~N 12,15 0 0321 +Ñ " +`O 13,16 0 0322 +Ò " +'O 13,16 0 0323 +Ó " +^O 13,16 0 0324 +Ô " +~O 13,15 0 0325 +Õ " +:O 13,15 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 13,12 0 0330 +Ø " +`U 12,16 0 0331 +Ù " +'U 12,16 0 0332 +Ú " +^U 12,16 0 0333 +Û " +:U 12,15 0 0334 +Ü " +'Y 11,16 0 0335 +Ý " +TP 11,12 0 0336 +Þ " +ss 10,12 0 0337 +ß " +`a 9,13 0 0340 +à " +'a 9,13 0 0341 +á " +^a 9,13 0 0342 +â " +~a 9,12 0 0343 +ã " +:a 9,12 0 0344 +ä " +oa 9,13 0 0345 +å " +ae 15,9 0 0346 +æ " +,c 8,9,3 0 0347 +ç " +`e 9,13 0 0350 +è " +'e 9,13 0 0351 +é " +^e 9,13 0 0352 +ê " +:e 9,12 0 0353 +ë " +`i 4,13 0 0354 +ì " +'i 4,13 0 0355 +í " +^i 4,13 0 0356 +î " +:i 4,12 0 0357 +ï " +Sd 9,12 0 0360 +ð " +~n 9,12 0 0361 +ñ " +`o 9,13 0 0362 +ò " +'o 9,13 0 0363 +ó " +^o 9,13 0 0364 +ô " +~o 9,12 0 0365 +õ " +:o 9,12 0 0366 +ö " +di 10,9 0 0367 +÷ " +/o 10,9 0 0370 +ø " +`u 9,13 0 0371 +ù " +'u 9,13 0 0372 +ú " +^u 9,13 0 0373 +û " +:u 9,12 0 0374 +ü " +'y 8,13,4 0 0375 +ý " +Tp 9,12,4 0 0376 +þ " +:y 8,12,4 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/HR b/gnu/usr.bin/groff/devices/devX100-12/HR new file mode 100644 index 0000000000..d2b296f64e --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/HR @@ -0,0 +1,306 @@ +name HR +spacewidth 5 +charset +--- 5,1 0 040 +! 5,12 0 041 +" 6,12 0 042 +# 9,11 0 043 +sh " +$ 9,13,2 0 044 +Do " +% 14,12 0 045 +& 11,12 0 046 +' 4,12 0 047 +( 6,12,4 0 050 +) 6,12,4 0 051 +* 6,12 0 052 ++ 10,9 0 053 +, 4,2,2 0 054 +\- 10,5 0 055 +. 4,2 0 056 +/ 5,12 0 057 +sl " +0 9,12 0 060 +1 9,12 0 061 +2 9,12 0 062 +3 9,12 0 063 +4 9,12 0 064 +5 9,12 0 065 +6 9,12 0 066 +7 9,12 0 067 +8 9,12 0 070 +9 9,12 0 071 +: 4,9 0 072 +; 4,9,2 0 073 +< 10,9 0 074 += 10,6 0 075 +eq " +> 10,9 0 076 +? 9,12 0 077 +@ 17,12,2 0 0100 +at " +A 11,12 0 0101 +B 11,12 0 0102 +C 12,12 0 0103 +D 12,12 0 0104 +E 11,12 0 0105 +F 10,12 0 0106 +G 13,12 0 0107 +H 12,12 0 0110 +I 4,12 0 0111 +J 8,12 0 0112 +K 11,12 0 0113 +L 9,12 0 0114 +M 13,12 0 0115 +N 12,12 0 0116 +O 13,12 0 0117 +P 11,12 0 0120 +Q 13,12,1 0 0121 +R 12,12 0 0122 +S 11,12 0 0123 +T 10,12 0 0124 +U 12,12 0 0125 +V 11,12 0 0126 +W 15,12 0 0127 +X 11,12 0 0130 +Y 11,12 0 0131 +Z 10,12 0 0132 +[ 5,12,3 0 0133 +lB " +\ 5,12 0 0134 +rs " +] 5,12,3 0 0135 +rB " +^ 8,12 0 0136 +a^ " +ha " +_ 9,0,3 0 0137 +` 4,12 0 0140 +oq " +a 9,9 0 0141 +b 9,12 0 0142 +c 8,9 0 0143 +d 9,12 0 0144 +e 9,9 0 0145 +f 5,12 0 0146 +g 9,9,4 0 0147 +h 9,12 0 0150 +i 3,12 0 0151 +j 4,12,4 0 0152 +k 8,12 0 0153 +l 3,12 0 0154 +m 14,9 0 0155 +n 9,9 0 0156 +o 9,9 0 0157 +p 9,9,4 0 0160 +q 9,9,4 0 0161 +r 5,9 0 0162 +s 8,9 0 0163 +t 5,11 0 0164 +u 9,9 0 0165 +v 8,9 0 0166 +w 12,9 0 0167 +x 8,9 0 0170 +y 8,9,3 0 0171 +z 8,9 0 0172 +{ 6,12,4 0 0173 +lC " +| 4,12,4 0 0174 +or " +ba " +} 6,12,4 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 6,9,3 0 0241 +¡ " +ct 9,11,2 0 0242 +¢ " +Po 9,12 0 0243 +£ " +Cs 9,10 0 0244 +¤ " +Ye 9,12 0 0245 +¥ " +bb 4,12,4 0 0246 +¦ " +sc 9,12,3 0 0247 +§ " +ad 5,12 0 0250 +¨ " +co 12,12 0 0251 +© " +Of 6,12 0 0252 +ª " +Fo 9,8 0 0253 +« " +no 10,6 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,12 0 0256 +® " +a- 6,11 0 0257 +¯ " +de 7,12 0 0260 +° " ++- 10,11 0 0261 +± " +S2 6,12 0 0262 +² " +S3 6,12 0 0263 +³ " +aa 6,13 0 0264 +´ " +µ 9,9,4 0 0265 +ps 9,12,3 0 0266 +¶ " +md 5,6 0 0267 +· " +ac 6,0,4 0 0270 +¸ " +S1 6,12 0 0271 +¹ " +Om 6,12 0 0272 +º " +Fc 9,8 0 0273 +» " +14 14,12 0 0274 +¼ " +12 14,13 0 0275 +½ " +34 14,12 0 0276 +¾ " +r? 10,9,3 0 0277 +¿ " +`A 11,16 0 0300 +À " +'A 11,16 0 0301 +Á " +^A 11,16 0 0302 +Â " +~A 11,15 0 0303 +Ã " +:A 11,15 0 0304 +Ä " +oA 11,15 0 0305 +Å " +AE 16,12 0 0306 +Æ " +,C 12,12,4 0 0307 +Ç " +`E 11,16 0 0310 +È " +'E 11,16 0 0311 +É " +^E 11,16 0 0312 +Ê " +:E 11,15 0 0313 +Ë " +`I 4,16 0 0314 +Ì " +'I 4,16 0 0315 +Í " +^I 4,16 0 0316 +Î " +:I 4,15 0 0317 +Ï " +-D 12,12 0 0320 +Ð " +~N 12,15 0 0321 +Ñ " +`O 13,16 0 0322 +Ò " +'O 13,16 0 0323 +Ó " +^O 13,16 0 0324 +Ô " +~O 13,15 0 0325 +Õ " +:O 13,15 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 13,13,1 0 0330 +Ø " +`U 12,16 0 0331 +Ù " +'U 12,16 0 0332 +Ú " +^U 12,16 0 0333 +Û " +:U 12,15 0 0334 +Ü " +'Y 11,16 0 0335 +Ý " +TP 11,12 0 0336 +Þ " +ss 10,12 0 0337 +ß " +`a 9,13 0 0340 +à " +'a 9,13 0 0341 +á " +^a 9,13 0 0342 +â " +~a 9,12 0 0343 +ã " +:a 9,12 0 0344 +ä " +oa 9,13 0 0345 +å " +ae 15,9 0 0346 +æ " +,c 8,9,4 0 0347 +ç " +`e 9,13 0 0350 +è " +'e 9,13 0 0351 +é " +^e 9,13 0 0352 +ê " +:e 9,12 0 0353 +ë " +`i 4,13 0 0354 +ì " +'i 4,13 0 0355 +í " +^i 4,13 0 0356 +î " +:i 4,12 0 0357 +ï " +Sd 9,12 0 0360 +ð " +~n 9,12 0 0361 +ñ " +`o 9,13 0 0362 +ò " +'o 9,13 0 0363 +ó " +^o 9,13 0 0364 +ô " +~o 9,12 0 0365 +õ " +:o 9,12 0 0366 +ö " +di 10,9 0 0367 +÷ " +/o 10,10 0 0370 +ø " +`u 9,13 0 0371 +ù " +'u 9,13 0 0372 +ú " +^u 9,13 0 0373 +û " +:u 9,12 0 0374 +ü " +'y 8,13,3 0 0375 +ý " +Tp 9,12,4 0 0376 +þ " +:y 8,12,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/Makefile b/gnu/usr.bin/groff/devices/devX100-12/Makefile new file mode 100644 index 0000000000..4936ceb28a --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/Makefile @@ -0,0 +1,10 @@ +# Makefile for devX100-12 + +DEVICE= X100-12 +FONTFILES= CB CBI CI CR HB HBI HI HR NB NBI NI NR S TB TBI TI TR DESC + +NOOBJ= noobj + +clean cleandir: + +.include "../Makefile.dev" diff --git a/gnu/usr.bin/groff/devices/devX100-12/NB b/gnu/usr.bin/groff/devices/devX100-12/NB new file mode 100644 index 0000000000..f997df5961 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/NB @@ -0,0 +1,306 @@ +name NB +spacewidth 4 +charset +--- 4,1 0 040 +! 5,12 0 041 +" 6,12 0 042 +# 10,12 0 043 +sh " +$ 10,14,1 0 044 +Do " +% 14,12 0 045 +& 14,12 0 046 +' 4,12 0 047 +( 6,12,2 0 050 +) 6,12,2 0 051 +* 8,12 0 052 ++ 10,8 0 053 +, 5,3,3 0 054 +\- 10,5 0 055 +. 5,3 0 056 +/ 5,12 0 057 +sl " +0 10,12 0 060 +1 9,12 0 061 +2 9,12 0 062 +3 10,12 0 063 +4 9,12 0 064 +5 10,12 0 065 +6 9,12 0 066 +7 9,12 0 067 +8 9,12 0 070 +9 10,12 0 071 +: 5,8 0 072 +; 5,8,3 0 073 +< 10,9 0 074 += 10,7 0 075 +eq " +> 10,9 0 076 +? 8,12 0 077 +@ 12,12,1 0 0100 +at " +A 13,12 0 0101 +B 13,12 0 0102 +C 13,12 0 0103 +D 14,12 0 0104 +E 12,12 0 0105 +F 12,12 0 0106 +G 14,12 0 0107 +H 15,12 0 0110 +I 7,12 0 0111 +J 11,12 0 0112 +K 13,12 0 0113 +L 12,12 0 0114 +M 16,12 0 0115 +N 14,12 0 0116 +O 14,12 0 0117 +P 13,12 0 0120 +Q 14,12,3 0 0121 +R 14,12 0 0122 +S 11,12 0 0123 +T 12,12 0 0124 +U 14,12 0 0125 +V 13,12 0 0126 +W 16,12 0 0127 +X 12,12 0 0130 +Y 12,12 0 0131 +Z 11,12 0 0132 +[ 6,12,2 0 0133 +lB " +\ 10,12 0 0134 +rs " +] 7,12,2 0 0135 +rB " +^ 10,12 0 0136 +a^ " +ha " +_ 8,0,2 0 0137 +` 4,12 0 0140 +oq " +a 10,8 0 0141 +b 11,12 0 0142 +c 9,8 0 0143 +d 11,12 0 0144 +e 10,8 0 0145 +f 7,12 0 0146 +g 10,9,3 0 0147 +h 11,12 0 0150 +i 6,12 0 0151 +j 6,12,3 0 0152 +k 11,12 0 0153 +l 6,12 0 0154 +m 16,8 0 0155 +n 11,8 0 0156 +o 11,8 0 0157 +p 11,8,3 0 0160 +q 10,8,3 0 0161 +r 9,8 0 0162 +s 8,8 0 0163 +t 7,11 0 0164 +u 11,8 0 0165 +v 10,8 0 0166 +w 15,8 0 0167 +x 10,8 0 0170 +y 10,8,3 0 0171 +z 9,8 0 0172 +{ 6,12,2 0 0173 +lC " +| 10,12 0 0174 +or " +ba " +} 6,12,2 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 5,9,3 0 0241 +¡ " +ct 10,10,2 0 0242 +¢ " +Po 10,12 0 0243 +£ " +Cs 10,10 0 0244 +¤ " +Ye 10,12 0 0245 +¥ " +bb 10,12 0 0246 +¦ " +sc 9,12,3 0 0247 +§ " +ad 6,11 0 0250 +¨ " +co 12,12 0 0251 +© " +Of 6,12 0 0252 +ª " +Fo 8,7 0 0253 +« " +no 10,7 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,12 0 0256 +® " +a- 6,11 0 0257 +¯ " +de 7,12 0 0260 +° " ++- 10,9 0 0261 +± " +S2 6,12 0 0262 +² " +S3 6,12 0 0263 +³ " +aa 6,12 0 0264 +´ " +µ 11,8,3 0 0265 +ps 12,12 0 0266 +¶ " +md 5,6 0 0267 +· " +ac 6,1,3 0 0270 +¸ " +S1 6,12 0 0271 +¹ " +Om 6,12 0 0272 +º " +Fc 8,7 0 0273 +» " +14 14,12 0 0274 +¼ " +12 14,12 0 0275 +½ " +34 14,12 0 0276 +¾ " +r? 8,9,3 0 0277 +¿ " +`A 13,16 0 0300 +À " +'A 13,16 0 0301 +Á " +^A 13,16 0 0302 +Â " +~A 13,15 0 0303 +Ã " +:A 13,15 0 0304 +Ä " +oA 13,16 0 0305 +Å " +AE 16,12 0 0306 +Æ " +,C 13,12,3 0 0307 +Ç " +`E 12,16 0 0310 +È " +'E 12,16 0 0311 +É " +^E 12,16 0 0312 +Ê " +:E 12,15 0 0313 +Ë " +`I 7,16 0 0314 +Ì " +'I 7,16 0 0315 +Í " +^I 7,16 0 0316 +Î " +:I 7,15 0 0317 +Ï " +-D 14,12 0 0320 +Ð " +~N 14,15 0 0321 +Ñ " +`O 14,16 0 0322 +Ò " +'O 14,16 0 0323 +Ó " +^O 14,16 0 0324 +Ô " +~O 14,15 0 0325 +Õ " +:O 14,15 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 14,13,1 0 0330 +Ø " +`U 14,16 0 0331 +Ù " +'U 14,16 0 0332 +Ú " +^U 14,16 0 0333 +Û " +:U 14,15 0 0334 +Ü " +'Y 12,16 0 0335 +Ý " +TP 13,12 0 0336 +Þ " +ss 10,12 0 0337 +ß " +`a 10,12 0 0340 +à " +'a 10,12 0 0341 +á " +^a 10,12 0 0342 +â " +~a 10,11 0 0343 +ã " +:a 10,11 0 0344 +ä " +oa 10,12 0 0345 +å " +ae 15,8 0 0346 +æ " +,c 9,8,3 0 0347 +ç " +`e 10,12 0 0350 +è " +'e 10,12 0 0351 +é " +^e 10,12 0 0352 +ê " +:e 10,11 0 0353 +ë " +`i 6,12 0 0354 +ì " +'i 6,12 0 0355 +í " +^i 6,12 0 0356 +î " +:i 6,11 0 0357 +ï " +Sd 11,13 0 0360 +ð " +~n 11,11 0 0361 +ñ " +`o 11,12 0 0362 +ò " +'o 11,12 0 0363 +ó " +^o 11,12 0 0364 +ô " +~o 11,11 0 0365 +õ " +:o 11,11 0 0366 +ö " +di 10,8 0 0367 +÷ " +/o 10,10,2 0 0370 +ø " +`u 11,12 0 0371 +ù " +'u 11,12 0 0372 +ú " +^u 11,12 0 0373 +û " +:u 11,11 0 0374 +ü " +'y 10,12,3 0 0375 +ý " +Tp 11,12,3 0 0376 +þ " +:y 10,11,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/NBI b/gnu/usr.bin/groff/devices/devX100-12/NBI new file mode 100644 index 0000000000..38c32819b3 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/NBI @@ -0,0 +1,306 @@ +name NBI +spacewidth 4 +charset +--- 4,1 0 040 +! 6,12 0 041 +" 7,12 0 042 +# 10,12 0 043 +sh " +$ 9,14,1 0 044 +Do " +% 15,12 0 045 +& 15,12 0 046 +' 4,12 0 047 +( 7,12,2 0 050 +) 7,12,2 0 051 +* 8,12 0 052 ++ 10,8 0 053 +, 5,3,3 0 054 +\- 10,5 0 055 +. 5,3 0 056 +/ 5,12 0 057 +sl " +0 9,12 0 060 +1 9,12 0 061 +2 9,12 0 062 +3 9,12 0 063 +4 9,12 0 064 +5 10,12 0 065 +6 10,12 0 066 +7 9,12 0 067 +8 9,12 0 070 +9 9,12 0 071 +: 5,8 0 072 +; 5,8,3 0 073 +< 10,8 0 074 += 10,7 0 075 +eq " +> 10,8 0 076 +? 8,12 0 077 +@ 12,12 0 0100 +at " +A 12,12 0 0101 +B 13,12 0 0102 +C 13,12 0 0103 +D 14,12 0 0104 +E 12,12 0 0105 +F 12,12 0 0106 +G 14,12 0 0107 +H 14,12 0 0110 +I 7,12 0 0111 +J 11,12 0 0112 +K 13,12 0 0113 +L 12,12 0 0114 +M 16,12 0 0115 +N 14,12 0 0116 +O 14,12 0 0117 +P 12,12 0 0120 +Q 14,12,3 0 0121 +R 14,12 0 0122 +S 11,12 0 0123 +T 12,12 0 0124 +U 14,12 0 0125 +V 12,12 0 0126 +W 16,12 0 0127 +X 12,12 0 0130 +Y 12,12 0 0131 +Z 12,12 0 0132 +[ 7,12,2 0 0133 +lB " +\ 10,12 0 0134 +rs " +] 7,12,2 0 0135 +rB " +^ 10,12 0 0136 +a^ " +ha " +_ 8,0,3 0 0137 +` 4,12 0 0140 +oq " +a 11,8 0 0141 +b 10,12 0 0142 +c 9,8 0 0143 +d 11,12 0 0144 +e 9,8 0 0145 +f 6,12,3 0 0146 +g 10,9,3 0 0147 +h 11,12 0 0150 +i 6,12 0 0151 +j 6,12,3 0 0152 +k 11,12 0 0153 +l 6,12 0 0154 +m 15,8 0 0155 +n 11,8 0 0156 +o 10,8 0 0157 +p 11,8,3 0 0160 +q 10,8,3 0 0161 +r 9,8 0 0162 +s 8,8 0 0163 +t 7,11 0 0164 +u 11,8 0 0165 +v 9,8 0 0166 +w 14,8 0 0167 +x 9,8 0 0170 +y 9,8,3 0 0171 +z 9,8 0 0172 +{ 7,12,2 0 0173 +lC " +| 10,12 0 0174 +or " +ba " +} 7,12,2 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 6,9,3 0 0241 +¡ " +ct 10,10,2 0 0242 +¢ " +Po 10,12 0 0243 +£ " +Cs 10,10 0 0244 +¤ " +Ye 10,12 0 0245 +¥ " +bb 10,12 0 0246 +¦ " +sc 9,12,3 0 0247 +§ " +ad 6,11 0 0250 +¨ " +co 12,12 0 0251 +© " +Of 7,12 0 0252 +ª " +Fo 8,7 0 0253 +« " +no 10,7 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,12 0 0256 +® " +a- 6,11 0 0257 +¯ " +de 7,12 0 0260 +° " ++- 10,8 0 0261 +± " +S2 6,12 0 0262 +² " +S3 6,12 0 0263 +³ " +aa 6,12 0 0264 +´ " +µ 11,8,3 0 0265 +ps 11,12 0 0266 +¶ " +md 5,6 0 0267 +· " +ac 5,1,3 0 0270 +¸ " +S1 6,12 0 0271 +¹ " +Om 6,12 0 0272 +º " +Fc 8,7 0 0273 +» " +14 14,12 0 0274 +¼ " +12 14,12 0 0275 +½ " +34 14,12 0 0276 +¾ " +r? 8,9,3 0 0277 +¿ " +`A 12,16 0 0300 +À " +'A 12,16 0 0301 +Á " +^A 12,16 0 0302 +Â " +~A 12,15 0 0303 +Ã " +:A 12,15 0 0304 +Ä " +oA 12,16 0 0305 +Å " +AE 15,12 0 0306 +Æ " +,C 13,12,3 0 0307 +Ç " +`E 12,16 0 0310 +È " +'E 12,16 0 0311 +É " +^E 12,16 0 0312 +Ê " +:E 12,15 0 0313 +Ë " +`I 7,16 0 0314 +Ì " +'I 7,16 0 0315 +Í " +^I 7,16 0 0316 +Î " +:I 7,15 0 0317 +Ï " +-D 14,12 0 0320 +Ð " +~N 14,15 0 0321 +Ñ " +`O 14,16 0 0322 +Ò " +'O 14,16 0 0323 +Ó " +^O 14,16 0 0324 +Ô " +~O 14,15 0 0325 +Õ " +:O 14,15 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 14,13,1 0 0330 +Ø " +`U 14,16 0 0331 +Ù " +'U 14,16 0 0332 +Ú " +^U 14,16 0 0333 +Û " +:U 14,15 0 0334 +Ü " +'Y 12,16 0 0335 +Ý " +TP 12,12 0 0336 +Þ " +ss 10,12,3 0 0337 +ß " +`a 11,12 0 0340 +à " +'a 11,12 0 0341 +á " +^a 11,12 0 0342 +â " +~a 11,11 0 0343 +ã " +:a 11,11 0 0344 +ä " +oa 11,13 0 0345 +å " +ae 14,8 0 0346 +æ " +,c 9,8,3 0 0347 +ç " +`e 9,12 0 0350 +è " +'e 9,12 0 0351 +é " +^e 9,12 0 0352 +ê " +:e 9,11 0 0353 +ë " +`i 6,12 0 0354 +ì " +'i 6,12 0 0355 +í " +^i 6,12 0 0356 +î " +:i 6,11 0 0357 +ï " +Sd 10,13 0 0360 +ð " +~n 11,11 0 0361 +ñ " +`o 10,12 0 0362 +ò " +'o 10,12 0 0363 +ó " +^o 10,12 0 0364 +ô " +~o 10,11 0 0365 +õ " +:o 10,11 0 0366 +ö " +di 10,8 0 0367 +÷ " +/o 10,10,2 0 0370 +ø " +`u 11,12 0 0371 +ù " +'u 11,12 0 0372 +ú " +^u 11,12 0 0373 +û " +:u 11,11 0 0374 +ü " +'y 9,12,3 0 0375 +ý " +Tp 11,11,3 0 0376 +þ " +:y 9,11,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/NI b/gnu/usr.bin/groff/devices/devX100-12/NI new file mode 100644 index 0000000000..7a34f2af98 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/NI @@ -0,0 +1,306 @@ +name NI +spacewidth 4 +charset +--- 4,1 0 040 +! 6,12 0 041 +" 7,12 0 042 +# 9,12 0 043 +sh " +$ 9,14,1 0 044 +Do " +% 14,12 0 045 +& 14,12 0 046 +' 3,12 0 047 +( 6,12,2 0 050 +) 5,12,2 0 051 +* 8,12 0 052 ++ 10,9 0 053 +, 4,2,3 0 054 +\- 10,5 0 055 +. 4,2 0 056 +/ 10,12,2 0 057 +sl " +0 9,12 0 060 +1 9,12 0 061 +2 9,12 0 062 +3 9,12 0 063 +4 9,12 0 064 +5 9,12 0 065 +6 9,12 0 066 +7 9,12 0 067 +8 9,12 0 070 +9 9,12 0 071 +: 5,8 0 072 +; 5,8,3 0 073 +< 10,9 0 074 += 10,6 0 075 +eq " +> 10,9 0 076 +? 7,12 0 077 +@ 12,12 0 0100 +at " +A 12,12 0 0101 +B 12,12 0 0102 +C 12,12 0 0103 +D 13,12 0 0104 +E 12,12 0 0105 +F 11,12 0 0106 +G 13,12 0 0107 +H 14,12 0 0110 +I 7,12 0 0111 +J 10,12 0 0112 +K 12,12 0 0113 +L 11,12 0 0114 +M 16,12 0 0115 +N 13,12 0 0116 +O 13,12 0 0117 +P 11,12 0 0120 +Q 13,12,3 0 0121 +R 13,12 0 0122 +S 11,12 0 0123 +T 11,12 0 0124 +U 13,12 0 0125 +V 11,12 0 0126 +W 15,12 0 0127 +X 12,12 0 0130 +Y 11,12 0 0131 +Z 11,12 0 0132 +[ 6,12,2 0 0133 +lB " +\ 10,12 0 0134 +rs " +] 6,12,2 0 0135 +rB " +^ 10,12 0 0136 +a^ " +ha " +_ 8,0,3 0 0137 +` 3,12 0 0140 +oq " +a 10,8 0 0141 +b 9,12 0 0142 +c 8,8 0 0143 +d 10,12 0 0144 +e 7,8 0 0145 +f 5,12,3 0 0146 +g 9,9,3 0 0147 +h 10,12 0 0150 +i 6,12 0 0151 +j 5,12,3 0 0152 +k 9,12 0 0153 +l 6,12 0 0154 +m 15,8 0 0155 +n 10,8 0 0156 +o 8,8 0 0157 +p 9,8,3 0 0160 +q 9,8,3 0 0161 +r 7,8 0 0162 +s 7,8 0 0163 +t 6,11 0 0164 +u 10,8 0 0165 +v 8,8 0 0166 +w 13,8 0 0167 +x 8,8 0 0170 +y 8,8,3 0 0171 +z 8,8 0 0172 +{ 6,12,2 0 0173 +lC " +| 10,12 0 0174 +or " +ba " +} 6,12,2 0 0175 +rC " +~ 10,5 0 0176 +a~ " +ap " +ti " +r! 6,9,3 0 0241 +¡ " +ct 9,10,2 0 0242 +¢ " +Po 9,12 0 0243 +£ " +Cs 9,10 0 0244 +¤ " +Ye 9,12 0 0245 +¥ " +bb 10,12 0 0246 +¦ " +sc 8,12,3 0 0247 +§ " +ad 6,11 0 0250 +¨ " +co 12,12 0 0251 +© " +Of 7,12 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 10,6 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 12,12 0 0256 +® " +a- 5,10 0 0257 +¯ " +de 7,12 0 0260 +° " ++- 10,9 0 0261 +± " +S2 6,12 0 0262 +² " +S3 6,12 0 0263 +³ " +aa 5,12 0 0264 +´ " +µ 10,8,3 0 0265 +ps 11,12 0 0266 +¶ " +md 5,5 0 0267 +· " +ac 5,1,3 0 0270 +¸ " +S1 6,12 0 0271 +¹ " +Om 6,12 0 0272 +º " +Fc 7,6 0 0273 +» " +14 14,12 0 0274 +¼ " +12 14,12 0 0275 +½ " +34 14,12 0 0276 +¾ " +r? 7,9,3 0 0277 +¿ " +`A 12,16 0 0300 +À " +'A 12,16 0 0301 +Á " +^A 12,16 0 0302 +Â " +~A 12,15 0 0303 +Ã " +:A 12,15 0 0304 +Ä " +oA 12,16 0 0305 +Å " +AE 14,12 0 0306 +Æ " +,C 12,12,3 0 0307 +Ç " +`E 12,16 0 0310 +È " +'E 12,16 0 0311 +É " +^E 12,16 0 0312 +Ê " +:E 12,15 0 0313 +Ë " +`I 7,16 0 0314 +Ì " +'I 7,16 0 0315 +Í " +^I 7,16 0 0316 +Î " +:I 7,15 0 0317 +Ï " +-D 13,12 0 0320 +Ð " +~N 13,15 0 0321 +Ñ " +`O 13,16 0 0322 +Ò " +'O 13,16 0 0323 +Ó " +^O 13,16 0 0324 +Ô " +~O 13,15 0 0325 +Õ " +:O 13,15 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 13,13,1 0 0330 +Ø " +`U 13,16 0 0331 +Ù " +'U 13,16 0 0332 +Ú " +^U 13,16 0 0333 +Û " +:U 13,15 0 0334 +Ü " +'Y 11,16 0 0335 +Ý " +TP 11,12 0 0336 +Þ " +ss 9,12,3 0 0337 +ß " +`a 10,12 0 0340 +à " +'a 10,12 0 0341 +á " +^a 10,12 0 0342 +â " +~a 10,11 0 0343 +ã " +:a 10,11 0 0344 +ä " +oa 10,13 0 0345 +å " +ae 12,8 0 0346 +æ " +,c 8,8,3 0 0347 +ç " +`e 7,12 0 0350 +è " +'e 7,12 0 0351 +é " +^e 7,12 0 0352 +ê " +:e 7,11 0 0353 +ë " +`i 6,12 0 0354 +ì " +'i 6,12 0 0355 +í " +^i 6,12 0 0356 +î " +:i 6,11 0 0357 +ï " +Sd 8,13 0 0360 +ð " +~n 10,11 0 0361 +ñ " +`o 8,12 0 0362 +ò " +'o 8,12 0 0363 +ó " +^o 8,12 0 0364 +ô " +~o 8,11 0 0365 +õ " +:o 8,11 0 0366 +ö " +di 10,8 0 0367 +÷ " +/o 8,10,2 0 0370 +ø " +`u 10,12 0 0371 +ù " +'u 10,12 0 0372 +ú " +^u 10,12 0 0373 +û " +:u 10,11 0 0374 +ü " +'y 8,12,3 0 0375 +ý " +Tp 9,11,3 0 0376 +þ " +:y 8,11,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/NR b/gnu/usr.bin/groff/devices/devX100-12/NR new file mode 100644 index 0000000000..0a9a0cfa82 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/NR @@ -0,0 +1,306 @@ +name NR +spacewidth 4 +charset +--- 4,1 0 040 +! 5,12 0 041 +" 6,12 0 042 +# 9,12 0 043 +sh " +$ 9,13,2 0 044 +Do " +% 14,12 0 045 +& 13,12 0 046 +' 3,12 0 047 +( 6,12,2 0 050 +) 6,12,2 0 051 +* 8,12 0 052 ++ 10,9 0 053 +, 4,2,3 0 054 +\- 10,5 0 055 +. 4,2 0 056 +/ 5,12 0 057 +sl " +0 9,12 0 060 +1 9,12 0 061 +2 9,12 0 062 +3 9,12 0 063 +4 9,12 0 064 +5 9,12 0 065 +6 9,12 0 066 +7 9,12 0 067 +8 9,12 0 070 +9 9,12 0 071 +: 4,8 0 072 +; 4,8,3 0 073 +< 10,8 0 074 += 10,6 0 075 +eq " +> 10,8 0 076 +? 7,12 0 077 +@ 12,12,1 0 0100 +at " +A 12,12 0 0101 +B 12,12 0 0102 +C 12,12 0 0103 +D 13,12 0 0104 +E 12,12 0 0105 +F 11,12 0 0106 +G 13,12 0 0107 +H 14,12 0 0110 +I 7,12 0 0111 +J 9,12 0 0112 +K 13,12 0 0113 +L 11,12 0 0114 +M 16,12 0 0115 +N 13,12 0 0116 +O 13,12 0 0117 +P 11,12 0 0120 +Q 13,12,3 0 0121 +R 12,12 0 0122 +S 10,12 0 0123 +T 11,12 0 0124 +U 13,12 0 0125 +V 12,12 0 0126 +W 16,12 0 0127 +X 11,12 0 0130 +Y 12,12 0 0131 +Z 10,12 0 0132 +[ 6,12,2 0 0133 +lB " +\ 10,12 0 0134 +rs " +] 6,12,2 0 0135 +rB " +^ 10,12 0 0136 +a^ " +ha " +_ 8,0,2 0 0137 +` 3,12 0 0140 +oq " +a 9,8 0 0141 +b 9,12 0 0142 +c 7,8 0 0143 +d 10,12 0 0144 +e 8,8 0 0145 +f 6,12 0 0146 +g 9,8,3 0 0147 +h 10,12 0 0150 +i 5,12 0 0151 +j 5,12,3 0 0152 +k 10,12 0 0153 +l 5,12 0 0154 +m 15,8 0 0155 +n 10,8 0 0156 +o 8,8 0 0157 +p 9,8,3 0 0160 +q 9,8,3 0 0161 +r 7,8 0 0162 +s 8,8 0 0163 +t 7,11 0 0164 +u 10,8 0 0165 +v 9,8 0 0166 +w 13,8 0 0167 +x 9,8 0 0170 +y 9,8,3 0 0171 +z 8,8 0 0172 +{ 6,12,2 0 0173 +lC " +| 10,12 0 0174 +or " +ba " +} 6,12,2 0 0175 +rC " +~ 10,5 0 0176 +a~ " +ap " +ti " +r! 5,9,3 0 0241 +¡ " +ct 9,10,2 0 0242 +¢ " +Po 9,12 0 0243 +£ " +Cs 9,10 0 0244 +¤ " +Ye 9,12 0 0245 +¥ " +bb 10,12 0 0246 +¦ " +sc 8,12,3 0 0247 +§ " +ad 5,11 0 0250 +¨ " +co 12,12 0 0251 +© " +Of 6,12 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 10,6 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 12,12 0 0256 +® " +a- 5,10 0 0257 +¯ " +de 7,12 0 0260 +° " ++- 10,9 0 0261 +± " +S2 6,12 0 0262 +² " +S3 6,12 0 0263 +³ " +aa 5,12 0 0264 +´ " +µ 10,8,3 0 0265 +ps 10,12,3 0 0266 +¶ " +md 5,5 0 0267 +· " +ac 5,1,3 0 0270 +¸ " +S1 6,12 0 0271 +¹ " +Om 5,12 0 0272 +º " +Fc 7,6 0 0273 +» " +14 14,12 0 0274 +¼ " +12 13,12 0 0275 +½ " +34 14,12 0 0276 +¾ " +r? 7,9,3 0 0277 +¿ " +`A 12,16 0 0300 +À " +'A 12,16 0 0301 +Á " +^A 12,16 0 0302 +Â " +~A 12,15 0 0303 +Ã " +:A 12,15 0 0304 +Ä " +oA 12,16 0 0305 +Å " +AE 17,12 0 0306 +Æ " +,C 12,12,3 0 0307 +Ç " +`E 12,16 0 0310 +È " +'E 12,16 0 0311 +É " +^E 12,16 0 0312 +Ê " +:E 12,15 0 0313 +Ë " +`I 7,16 0 0314 +Ì " +'I 7,16 0 0315 +Í " +^I 7,16 0 0316 +Î " +:I 7,15 0 0317 +Ï " +-D 13,12 0 0320 +Ð " +~N 13,15 0 0321 +Ñ " +`O 13,16 0 0322 +Ò " +'O 13,16 0 0323 +Ó " +^O 13,16 0 0324 +Ô " +~O 13,15 0 0325 +Õ " +:O 13,15 0 0326 +Ö " +mu 10,8 0 0327 +× " +/O 13,13,1 0 0330 +Ø " +`U 13,16 0 0331 +Ù " +'U 13,16 0 0332 +Ú " +^U 13,16 0 0333 +Û " +:U 13,15 0 0334 +Ü " +'Y 12,16 0 0335 +Ý " +TP 11,12 0 0336 +Þ " +ss 10,12 0 0337 +ß " +`a 9,12 0 0340 +à " +'a 9,12 0 0341 +á " +^a 9,12 0 0342 +â " +~a 9,11 0 0343 +ã " +:a 9,11 0 0344 +ä " +oa 9,13 0 0345 +å " +ae 13,8 0 0346 +æ " +,c 7,8,3 0 0347 +ç " +`e 8,12 0 0350 +è " +'e 8,12 0 0351 +é " +^e 8,12 0 0352 +ê " +:e 8,11 0 0353 +ë " +`i 5,12 0 0354 +ì " +'i 5,12 0 0355 +í " +^i 5,12 0 0356 +î " +:i 5,11 0 0357 +ï " +Sd 8,13 0 0360 +ð " +~n 10,11 0 0361 +ñ " +`o 8,12 0 0362 +ò " +'o 8,12 0 0363 +ó " +^o 8,12 0 0364 +ô " +~o 8,11 0 0365 +õ " +:o 8,11 0 0366 +ö " +di 10,8 0 0367 +÷ " +/o 8,9,1 0 0370 +ø " +`u 10,12 0 0371 +ù " +'u 10,12 0 0372 +ú " +^u 10,12 0 0373 +û " +:u 10,11 0 0374 +ü " +'y 9,12,3 0 0375 +ý " +Tp 9,11,3 0 0376 +þ " +:y 9,11,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/S b/gnu/usr.bin/groff/devices/devX100-12/S new file mode 100644 index 0000000000..1d235dab52 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/S @@ -0,0 +1,226 @@ +name S +special +spacewidth 4 +charset +--- 4,1 0 040 +! 5,11 0 041 +fa 11,12 0 042 +# 8,11 0 043 +sh " +te 9,12 0 044 +% 13,11,1 0 045 +& 13,11 0 046 +st 7,8 0 047 +( 5,12,2 0 050 +) 5,12,2 0 051 +** 8,8 0 052 ++ 9,9 0 053 +pl " +, 4,3,2 0 054 +\- 9,5 0 055 +mi " +. 4,3 0 056 +/ 5,11 0 057 +sl " +0 8,12 0 060 +1 8,12 0 061 +2 8,12 0 062 +3 8,12 0 063 +4 8,12 0 064 +5 8,12 0 065 +6 8,12 0 066 +7 8,12 0 067 +8 8,12 0 070 +9 8,12 0 071 +: 4,8 0 072 +; 4,8,2 0 073 +< 9,9 0 074 += 9,6 0 075 +eq " +> 9,9 0 076 +? 7,11 0 077 +=~ 9,8 0 0100 +*A 12,11 0 0101 +*B 11,11 0 0102 +*X 12,11 0 0103 +*D 10,11 0 0104 +*E 10,11 0 0105 +*F 12,11 0 0106 +*G 10,11 0 0107 +*Y 12,11 0 0110 +*I 6,11 0 0111 ++h 10,12 0 0112 +*K 12,11 0 0113 +*L 11,11 0 0114 +*M 14,11 0 0115 +*N 11,11 0 0116 +*O 12,11 0 0117 +*P 12,11 0 0120 +*H 12,11 0 0121 +*R 9,11 0 0122 +*S 10,11 0 0123 +*T 10,11 0 0124 +--- 11,11 0 0125 +ts 8,8,4 0 0126 +*W 12,12 0 0127 +*C 11,11 0 0130 +*Q 13,11 0 0131 +*Z 10,11 0 0132 +[ 6,12,2 0 0133 +lB " +tf 14,8 0 0134 +3d " +] 5,12,2 0 0135 +rB " +pp 11,11 0 0136 +_ 8,0,4 0 0137 +rn 8,13 0 0140 +*a 11,9 0 0141 +*b 9,13,4 0 0142 +*x 9,9,3 0 0143 +*d 8,12 0 0144 +*e 7,9 0 0145 +*f 9,11,3 0 0146 +*g 7,9,4 0 0147 +*y 10,9,3 0 0150 +*i 5,9 0 0151 ++f 10,9,3 0 0152 +*k 9,9 0 0153 +*l 9,13 0 0154 +*m 9,9,4 0 0155 +µ " +*n 8,9 0 0156 +*o 9,9 0 0157 +*p 9,9 0 0160 +*h 9,12 0 0161 +*r 9,9,4 0 0162 +*s 10,9 0 0163 +*t 7,9 0 0164 +*u 9,9 0 0165 ++p 11,10 0 0166 +*w 11,9 0 0167 +*c 8,13,4 0 0170 +*q 11,9,4 0 0171 +*z 8,13,4 0 0172 +lC 8,12,2 0 0173 +{ " +ba 3,11,3 0 0174 +or " +| " +rC 8,12,2 0 0175 +} " +ap 9,5 0 0176 +*U 10,11 0 0241 +fm 4,12 0 0242 +<= 9,11 0 0243 +f/ 3,11 0 0244 +if 12,7 0 0245 +Fn 8,12,3 0 0246 +CL 12,9,1 0 0247 +DI 12,9 0 0250 +HE 12,9 0 0251 +SP 12,9,1 0 0252 +<> 17,9 0 0253 +<- 16,9 0 0254 +ua 10,13,2 0 0255 +arrowverttp " +-> 16,9 0 0256 +da 10,13,2 0 0257 +arrowvertbt " +de 6,11 0 0260 +° " ++- 9,11 0 0261 +± " +sd 7,12 0 0262 +>= 9,11 0 0263 +mu 9,9 0 0264 +× " +pt 11,7 0 0265 +pd 8,13,1 0 0266 +bu 8,8 0 0267 +di 9,8 0 0270 +÷ " +!= 9,9,1 0 0271 +== 9,8 0 0272 +~= 9,7 0 0273 +~~ " +--- 16,3 0 0274 +arrowvertex 10,13,4 0 0275 +an 16,5 0 0276 +CR 10,10,1 0 0277 +Ah 13,11 0 0300 +Im 11,13,1 0 0301 +Re 13,13 0 0302 +wp 16,9,4 0 0303 +c* 12,11 0 0304 +c+ 12,11 0 0305 +es 13,12 0 0306 +ca 12,9 0 0307 +cu 12,9 0 0310 +sp 11,8 0 0311 +ip 11,7,3 0 0312 +--- 11,9,1 0 0313 +sb 11,8 0 0314 +ib 11,8,2 0 0315 +mo 11,7 0 0316 +nm 11,8,1 0 0317 +/_ 12,11 0 0320 +gr 11,12 0 0321 +rg 13,11 0 0322 +co 13,11 0 0323 +tm 14,11 0 0324 +--- 13,13,2 0 0325 +sr 9,13,3 0 0326 +md 4,5 0 0327 +no 12,5 0 0330 +¬ " +AN 10,8 0 0331 +OR 10,8 0 0332 +hA 17,9 0 0333 +lA 16,9 0 0334 +uA 10,13,2 0 0335 +rA 16,9 0 0336 +dA 10,13,2 0 0337 +lz 8,12 0 0340 +la 5,13,2 0 0341 +--- 13,11 0 0342 +--- 13,11 0 0343 +--- 13,11 0 0344 +--- 11,13,2 0 0345 +parenlefttp 6,13,4 0 0346 +parenleftex 6,13,4 0 0347 +parenleftbt 6,13,4 0 0350 +bracketlefttp 6,13,4 0 0351 +lc " +bracketleftex 6,13,4 0 0352 +bracketleftbt 6,13,4 0 0353 +lf " +bracelefttp 8,13,4 0 0354 +lt " +braceleftmid 8,13,4 0 0355 +lk " +braceleftbt 8,13,4 0 0356 +lb " +bracerightex 8,13,4 0 0357 +braceleftex " +bv " +--- 13,13 0 0360 +ra 5,13,2 0 0361 +is 5,13,4 0 0362 +--- 11,13,4 0 0363 +--- 11,13,4 0 0364 +--- 11,13,4 0 0365 +parenrighttp 7,13,4 0 0366 +parenrightex 6,13,4 0 0367 +parenrightbt 6,13,4 0 0370 +bracketrighttp 6,13,4 0 0371 +rc " +bracketrightex 6,13,4 0 0372 +bracketrightbt 6,13,4 0 0373 +rf " +bracerighttp 8,13,4 0 0374 +rt " +bracerightmid 8,13,4 0 0375 +rk " +bracerightbt 8,13,4 0 0376 +rb " diff --git a/gnu/usr.bin/groff/devices/devX100-12/TB b/gnu/usr.bin/groff/devices/devX100-12/TB new file mode 100644 index 0000000000..83073d5281 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/TB @@ -0,0 +1,306 @@ +name TB +spacewidth 4 +charset +--- 4,1 0 040 +! 6,11 0 041 +" 9,11 0 042 +# 8,11 0 043 +sh " +$ 8,12,1 0 044 +Do " +% 16,12 0 045 +& 14,11 0 046 +' 6,11 0 047 +( 6,11,3 0 050 +) 6,11,3 0 051 +* 8,11 0 052 ++ 9,8 0 053 +, 4,2,3 0 054 +\- 9,5 0 055 +. 4,2 0 056 +/ 5,11 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 5,7 0 072 +; 5,7,3 0 073 +< 9,8 0 074 += 9,7 0 075 +eq " +> 9,8 0 076 +? 8,11 0 077 +@ 16,11,2 0 0100 +at " +A 12,11 0 0101 +B 11,11 0 0102 +C 12,11 0 0103 +D 12,11 0 0104 +E 11,11 0 0105 +F 10,11 0 0106 +G 13,11 0 0107 +H 13,11 0 0110 +I 6,11 0 0111 +J 8,11,2 0 0112 +K 13,11 0 0113 +L 11,11 0 0114 +M 15,11 0 0115 +N 12,11 0 0116 +O 13,11 0 0117 +P 10,11 0 0120 +Q 13,11,3 0 0121 +R 12,11 0 0122 +S 9,11 0 0123 +T 11,11 0 0124 +U 12,11 0 0125 +V 12,11 0 0126 +W 16,11 0 0127 +X 12,11 0 0130 +Y 12,11 0 0131 +Z 11,11 0 0132 +[ 6,11,3 0 0133 +lB " +\ 5,11 0 0134 +rs " +] 6,11,3 0 0135 +rB " +^ 9,11 0 0136 +a^ " +ha " +_ 8,0,4 0 0137 +` 6,11 0 0140 +oq " +a 8,8 0 0141 +b 9,11 0 0142 +c 7,8 0 0143 +d 9,11 0 0144 +e 7,8 0 0145 +f 6,11 0 0146 +g 8,8,4 0 0147 +h 9,11 0 0150 +i 5,11 0 0151 +j 5,11,4 0 0152 +k 9,11 0 0153 +l 5,11 0 0154 +m 14,8 0 0155 +n 9,8 0 0156 +o 8,8 0 0157 +p 9,8,4 0 0160 +q 9,8,4 0 0161 +r 7,8 0 0162 +s 6,8 0 0163 +t 6,11 0 0164 +u 9,8 0 0165 +v 8,8 0 0166 +w 12,8 0 0167 +x 8,8 0 0170 +y 8,8,4 0 0171 +z 7,8 0 0172 +{ 7,11,3 0 0173 +lC " +| 4,11,3 0 0174 +or " +ba " +} 7,11,3 0 0175 +rC " +~ 9,8 0 0176 +a~ " +ap " +ti " +r! 6,8,4 0 0241 +¡ " +ct 8,10,2 0 0242 +¢ " +Po 8,11 0 0243 +£ " +Cs 8,8 0 0244 +¤ " +Ye 8,11 0 0245 +¥ " +bb 4,12,3 0 0246 +¦ " +sc 8,11,4 0 0247 +§ " +ad 6,11 0 0250 +¨ " +co 12,11 0 0251 +© " +Of 5,11 0 0252 +ª " +Fo 8,7 0 0253 +« " +no 9,7 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,11 0 0256 +® " +a- 6,10 0 0257 +¯ " +de 7,11 0 0260 +° " ++- 9,9 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 6,12 0 0264 +´ " +µ 9,8,3 0 0265 +ps 9,11,4 0 0266 +¶ " +md 4,6 0 0267 +· " +ac 6,0,4 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 6,11 0 0272 +º " +Fc 8,7 0 0273 +» " +14 12,11 0 0274 +¼ " +12 12,11 0 0275 +½ " +34 12,11 0 0276 +¾ " +r? 8,8,3 0 0277 +¿ " +`A 12,15 0 0300 +À " +'A 12,15 0 0301 +Á " +^A 12,15 0 0302 +Â " +~A 12,14 0 0303 +Ã " +:A 12,14 0 0304 +Ä " +oA 12,16 0 0305 +Å " +AE 16,11 0 0306 +Æ " +,C 12,11,4 0 0307 +Ç " +`E 11,15 0 0310 +È " +'E 11,15 0 0311 +É " +^E 11,15 0 0312 +Ê " +:E 11,14 0 0313 +Ë " +`I 6,15 0 0314 +Ì " +'I 6,15 0 0315 +Í " +^I 6,15 0 0316 +Î " +:I 6,14 0 0317 +Ï " +-D 12,11 0 0320 +Ð " +~N 12,14 0 0321 +Ñ " +`O 13,15 0 0322 +Ò " +'O 13,15 0 0323 +Ó " +^O 13,15 0 0324 +Ô " +~O 13,15 0 0325 +Õ " +:O 13,14 0 0326 +Ö " +mu 9,8 0 0327 +× " +/O 13,12,1 0 0330 +Ø " +`U 12,15 0 0331 +Ù " +'U 12,15 0 0332 +Ú " +^U 12,15 0 0333 +Û " +:U 12,14 0 0334 +Ü " +'Y 12,15 0 0335 +Ý " +TP 10,11 0 0336 +Þ " +ss 9,11 0 0337 +ß " +`a 8,12 0 0340 +à " +'a 8,12 0 0341 +á " +^a 8,12 0 0342 +â " +~a 8,11 0 0343 +ã " +:a 8,11 0 0344 +ä " +oa 8,13 0 0345 +å " +ae 12,8 0 0346 +æ " +,c 7,8,4 0 0347 +ç " +`e 7,12 0 0350 +è " +'e 7,12 0 0351 +é " +^e 7,12 0 0352 +ê " +:e 7,11 0 0353 +ë " +`i 5,12 0 0354 +ì " +'i 5,12 0 0355 +í " +^i 5,12 0 0356 +î " +:i 5,11 0 0357 +ï " +Sd 8,11 0 0360 +ð " +~n 9,11 0 0361 +ñ " +`o 8,12 0 0362 +ò " +'o 8,12 0 0363 +ó " +^o 8,12 0 0364 +ô " +~o 8,11 0 0365 +õ " +:o 8,11 0 0366 +ö " +di 9,8 0 0367 +÷ " +/o 8,9,1 0 0370 +ø " +`u 9,12 0 0371 +ù " +'u 9,12 0 0372 +ú " +^u 9,12 0 0373 +û " +:u 9,11 0 0374 +ü " +'y 8,12,4 0 0375 +ý " +Tp 9,11,4 0 0376 +þ " +:y 8,11,4 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/TBI b/gnu/usr.bin/groff/devices/devX100-12/TBI new file mode 100644 index 0000000000..71ca713620 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/TBI @@ -0,0 +1,306 @@ +name TBI +spacewidth 4 +charset +--- 4,1 0 040 +! 6,11 0 041 +" 9,11 0 042 +# 8,11 0 043 +sh " +$ 8,12,1 0 044 +Do " +% 13,11 0 045 +& 13,11 0 046 +' 6,11 0 047 +( 6,11,3 0 050 +) 6,11,3 0 051 +* 8,11 0 052 ++ 10,9 0 053 +, 4,2,3 0 054 +\- 10,6 0 055 +. 4,2 0 056 +/ 5,12 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 5,7 0 072 +; 5,7,3 0 073 +< 10,8 0 074 += 10,7 0 075 +eq " +> 10,8 0 076 +? 8,11 0 077 +@ 14,11,2 0 0100 +at " +A 11,11 0 0101 +B 11,11 0 0102 +C 11,11 0 0103 +D 12,11 0 0104 +E 11,11 0 0105 +F 11,11 0 0106 +G 12,11 0 0107 +H 13,11 0 0110 +I 6,11 0 0111 +J 8,11,2 0 0112 +K 11,11 0 0113 +L 10,11 0 0114 +M 15,11 0 0115 +N 12,11 0 0116 +O 12,11 0 0117 +P 10,11 0 0120 +Q 12,11,4 0 0121 +R 11,11 0 0122 +S 9,11 0 0123 +T 10,11 0 0124 +U 12,11 0 0125 +V 11,11 0 0126 +W 15,11 0 0127 +X 11,11 0 0130 +Y 10,11 0 0131 +Z 10,11 0 0132 +[ 6,12,3 0 0133 +lB " +\ 5,12 0 0134 +rs " +] 6,12,3 0 0135 +rB " +^ 10,11 0 0136 +a^ " +ha " +_ 8,0,2 0 0137 +` 6,11 0 0140 +oq " +a 8,8 0 0141 +b 8,11 0 0142 +c 7,8 0 0143 +d 8,11 0 0144 +e 7,8 0 0145 +f 6,11,3 0 0146 +g 8,8,3 0 0147 +h 9,11 0 0150 +i 5,11 0 0151 +j 5,11,3 0 0152 +k 8,11 0 0153 +l 5,11 0 0154 +m 13,8 0 0155 +n 9,8 0 0156 +o 8,8 0 0157 +p 8,8,3 0 0160 +q 8,8,3 0 0161 +r 6,8 0 0162 +s 6,8 0 0163 +t 5,10 0 0164 +u 9,8 0 0165 +v 7,8 0 0166 +w 11,8 0 0167 +x 8,8 0 0170 +y 7,8,3 0 0171 +z 6,8,1 0 0172 +{ 6,12,3 0 0173 +lC " +| 4,12 0 0174 +or " +ba " +} 6,12,3 0 0175 +rC " +~ 10,6 0 0176 +a~ " +ap " +ti " +r! 6,8,4 0 0241 +¡ " +ct 8,10,2 0 0242 +¢ " +Po 8,11 0 0243 +£ " +Cs 8,9 0 0244 +¤ " +Ye 8,11 0 0245 +¥ " +bb 4,12 0 0246 +¦ " +sc 8,11,3 0 0247 +§ " +ad 6,11 0 0250 +¨ " +co 12,11 0 0251 +© " +Of 4,11 0 0252 +ª " +Fo 8,7 0 0253 +« " +no 10,5 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,11 0 0256 +® " +a- 6,10 0 0257 +¯ " +de 7,11 0 0260 +° " ++- 10,10 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 6,12 0 0264 +´ " +µ 9,8,3 0 0265 +ps 8,11,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 6,1,3 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 5,11 0 0272 +º " +Fc 8,7 0 0273 +» " +14 13,11 0 0274 +¼ " +12 13,11 0 0275 +½ " +34 13,11 0 0276 +¾ " +r? 8,8,4 0 0277 +¿ " +`A 11,15 0 0300 +À " +'A 11,15 0 0301 +Á " +^A 11,15 0 0302 +Â " +~A 11,14 0 0303 +Ã " +:A 11,14 0 0304 +Ä " +oA 11,15 0 0305 +Å " +AE 15,11 0 0306 +Æ " +,C 11,11,3 0 0307 +Ç " +`E 11,15 0 0310 +È " +'E 11,15 0 0311 +É " +^E 11,15 0 0312 +Ê " +:E 11,14 0 0313 +Ë " +`I 6,15 0 0314 +Ì " +'I 6,15 0 0315 +Í " +^I 6,15 0 0316 +Î " +:I 6,14 0 0317 +Ï " +-D 12,11 0 0320 +Ð " +~N 12,14 0 0321 +Ñ " +`O 12,15 0 0322 +Ò " +'O 12,15 0 0323 +Ó " +^O 12,15 0 0324 +Ô " +~O 12,14 0 0325 +Õ " +:O 12,14 0 0326 +Ö " +mu 10,9 0 0327 +× " +/O 12,12,2 0 0330 +Ø " +`U 12,15 0 0331 +Ù " +'U 12,15 0 0332 +Ú " +^U 12,15 0 0333 +Û " +:U 12,14 0 0334 +Ü " +'Y 10,15 0 0335 +Ý " +TP 10,11 0 0336 +Þ " +ss 8,12,3 0 0337 +ß " +`a 8,12 0 0340 +à " +'a 8,12 0 0341 +á " +^a 8,12 0 0342 +â " +~a 8,11 0 0343 +ã " +:a 8,11 0 0344 +ä " +oa 8,12 0 0345 +å " +ae 12,8 0 0346 +æ " +,c 7,8,3 0 0347 +ç " +`e 7,12 0 0350 +è " +'e 7,12 0 0351 +é " +^e 7,12 0 0352 +ê " +:e 7,11 0 0353 +ë " +`i 5,12 0 0354 +ì " +'i 5,12 0 0355 +í " +^i 5,12 0 0356 +î " +:i 5,11 0 0357 +ï " +Sd 8,11 0 0360 +ð " +~n 9,11 0 0361 +ñ " +`o 8,12 0 0362 +ò " +'o 8,12 0 0363 +ó " +^o 8,12 0 0364 +ô " +~o 8,11 0 0365 +õ " +:o 8,11 0 0366 +ö " +di 10,9 0 0367 +÷ " +/o 8,10,2 0 0370 +ø " +`u 9,12 0 0371 +ù " +'u 9,12 0 0372 +ú " +^u 9,12 0 0373 +û " +:u 9,11 0 0374 +ü " +'y 7,12,3 0 0375 +ý " +Tp 8,11,3 0 0376 +þ " +:y 7,11,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/TI b/gnu/usr.bin/groff/devices/devX100-12/TI new file mode 100644 index 0000000000..fad269f925 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100-12/TI @@ -0,0 +1,306 @@ +name TI +spacewidth 4 +charset +--- 4,1 0 040 +! 6,11 0 041 +" 7,10 0 042 +# 8,11 0 043 +sh " +$ 8,12,1 0 044 +Do " +% 13,11 0 045 +& 13,11 0 046 +' 6,10 0 047 +( 6,11,3 0 050 +) 6,11,3 0 051 +* 8,11 0 052 ++ 11,9 0 053 +, 4,2,2 0 054 +\- 11,5 0 055 +. 4,2 0 056 +/ 5,11 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 5,7 0 072 +; 5,7,2 0 073 +< 11,9 0 074 += 11,6 0 075 +eq " +> 11,9 0 076 +? 8,11 0 077 +@ 15,11,3 0 0100 +at " +A 10,11 0 0101 +B 10,11 0 0102 +C 11,11 0 0103 +D 12,11 0 0104 +E 10,11 0 0105 +F 10,11 0 0106 +G 12,11 0 0107 +H 12,11 0 0110 +I 6,11 0 0111 +J 7,11 0 0112 +K 11,11 0 0113 +L 9,11 0 0114 +M 14,11 0 0115 +N 11,11 0 0116 +O 12,11 0 0117 +P 10,11 0 0120 +Q 12,11,3 0 0121 +R 10,11 0 0122 +S 8,11 0 0123 +T 9,11 0 0124 +U 12,11 0 0125 +V 10,11 0 0126 +W 14,11 0 0127 +X 10,11 0 0130 +Y 9,11 0 0131 +Z 9,11 0 0132 +[ 6,11,3 0 0133 +lB " +\ 5,11 0 0134 +rs " +] 6,11,3 0 0135 +rB " +^ 7,11 0 0136 +a^ " +ha " +_ 8,0,4 0 0137 +` 6,10 0 0140 +oq " +a 8,8 0 0141 +b 8,11 0 0142 +c 7,8 0 0143 +d 8,11 0 0144 +e 7,8 0 0145 +f 5,11,4 0 0146 +g 8,8,4 0 0147 +h 8,11 0 0150 +i 5,11 0 0151 +j 5,11,4 0 0152 +k 7,11 0 0153 +l 5,11 0 0154 +m 12,8 0 0155 +n 8,8 0 0156 +o 8,8 0 0157 +p 8,8,4 0 0160 +q 8,8,4 0 0161 +r 6,8 0 0162 +s 6,8 0 0163 +t 5,10 0 0164 +u 8,8 0 0165 +v 7,8 0 0166 +w 11,8 0 0167 +x 7,8 0 0170 +y 7,8,4 0 0171 +z 6,8 0 0172 +{ 7,11,3 0 0173 +lC " +| 5,11,3 0 0174 +or " +ba " +} 7,11,3 0 0175 +rC " +~ 9,6 0 0176 +a~ " +ap " +ti " +r! 6,8,3 0 0241 +¡ " +ct 8,9,1 0 0242 +¢ " +Po 8,11 0 0243 +£ " +Cs 8,9 0 0244 +¤ " +Ye 8,11 0 0245 +¥ " +bb 5,11,3 0 0246 +¦ " +sc 8,12,1 0 0247 +§ " +ad 6,11 0 0250 +¨ " +co 13,11 0 0251 +© " +Of 5,11 0 0252 +ª " +Fo 8,6 0 0253 +« " +no 11,6 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 13,11 0 0256 +® " +a- 6,10 0 0257 +¯ " +de 7,11 0 0260 +° " ++- 11,11 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 6,12 0 0264 +´ " +µ 8,8,4 0 0265 +ps 9,11,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 6,1,3 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 5,11 0 0272 +º " +Fc 8,6 0 0273 +» " +14 13,11 0 0274 +¼ " +12 13,11 0 0275 +½ " +34 13,11 0 0276 +¾ " +r? 8,8,3 0 0277 +¿ " +`A 10,15 0 0300 +À " +'A 10,15 0 0301 +Á " +^A 10,15 0 0302 +Â " +~A 10,14 0 0303 +Ã " +:A 10,14 0 0304 +Ä " +oA 10,15 0 0305 +Å " +AE 15,11 0 0306 +Æ " +,C 11,11,3 0 0307 +Ç " +`E 10,15 0 0310 +È " +'E 10,15 0 0311 +É " +^E 10,15 0 0312 +Ê " +:E 10,14 0 0313 +Ë " +`I 6,15 0 0314 +Ì " +'I 6,15 0 0315 +Í " +^I 6,15 0 0316 +Î " +:I 6,14 0 0317 +Ï " +-D 12,11 0 0320 +Ð " +~N 11,14 0 0321 +Ñ " +`O 12,15 0 0322 +Ò " +'O 12,15 0 0323 +Ó " +^O 12,15 0 0324 +Ô " +~O 12,14 0 0325 +Õ " +:O 12,14 0 0326 +Ö " +mu 11,9 0 0327 +× " +/O 12,12,1 0 0330 +Ø " +`U 12,15 0 0331 +Ù " +'U 12,15 0 0332 +Ú " +^U 12,15 0 0333 +Û " +:U 12,14 0 0334 +Ü " +'Y 9,15 0 0335 +Ý " +TP 10,11 0 0336 +Þ " +ss 8,11,4 0 0337 +ß " +`a 8,12 0 0340 +à " +'a 8,12 0 0341 +á " +^a 8,12 0 0342 +â " +~a 8,11 0 0343 +ã " +:a 8,11 0 0344 +ä " +oa 8,13 0 0345 +å " +ae 11,8 0 0346 +æ " +,c 7,8,3 0 0347 +ç " +`e 7,12 0 0350 +è " +'e 7,12 0 0351 +é " +^e 7,12 0 0352 +ê " +:e 7,11 0 0353 +ë " +`i 5,12 0 0354 +ì " +'i 5,12 0 0355 +í " +^i 5,12 0 0356 +î " +:i 5,11 0 0357 +ï " +Sd 8,12 0 0360 +ð " +~n 8,11 0 0361 +ñ " +`o 8,12 0 0362 +ò " +'o 8,12 0 0363 +ó " +^o 8,12 0 0364 +ô " +~o 8,11 0 0365 +õ " +:o 8,11 0 0366 +ö " +di 11,8 0 0367 +÷ " +/o 8,9,1 0 0370 +ø " +`u 8,12 0 0371 +ù " +'u 8,12 0 0372 +ú " +^u 8,12 0 0373 +û " +:u 8,11 0 0374 +ü " +'y 7,12,4 0 0375 +ý " +Tp 8,11,4 0 0376 +þ " +:y 7,11,4 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100-12/TR b/gnu/usr.bin/groff/devices/devX100-12/TR new file mode 100644 index 0000000000000000000000000000000000000000..85a79be4aaec5fc3a0f064fb308ef8153db8e171 GIT binary patch literal 3302 zcmchYe@qld6vyX&z%8(F$FU;nsc12UVp~XPBBBkjE>O=Ekbtp9t+rgvg{DDwO|e}# zyI#UDJ^jO^{lmXZnx<` z>_0a<^X9!b^ZC9vM;cwe@E8*wGY22$vq>}O3y(A5aab8=u$P-{D77Pmq#SbYEQ~c? z?&K=s<*+$xHDq0X_ah5ZM;MJS0y`qjMJWM1J|f(O$hD-gcuB5sBn$JqG``975p`0> zk)|Ek%aZ2O6n__K-kP#dtnnoai7HaocaZiN5od5)DfVt9%{x+z6&hc);8dHkzK!Gt z{%|Dm-U`y5AfgNBllD0xvN&H=I3$((_ZTwQrhi^IZ~O~lHQc_&y!}a*d`y`Tk;AQA zk`dT&R3`jdtZ~0QTn?h>EF{4;;UNpy%1R) zVP|=hvg{@u9KJwUcDhCyoL~ijD44hm>9Jn z0;dDSm2hO7A8NFzk-4%2)`CXw=IUSi?3U{2+P3|MTm(|-uRk;lJgknmf_I$3DM&&w z$cggqV%%Lq=x?df&4z@z7C$m%RzC(uc(nghx?h-6-`i%D3R-k4P8wG^SW`#r)BV&Y zLv1j)+jZtO2H6k<@U-e(r;}zzxV`KHbD*aNNe#1g3NB^WhX+(2i z2c3Kd69{Y0iu4a)2A^7;*+M29Fh*Cy8U#YHD&^3ec7#BBr=KY93{Z!@l^E-(JaW&L9pcX>TS+`*gjWYnS6(|aRx`d6qkaquuS z#9}|d!4$4T_w_CivqQZ+Kg)9nG>{#Gx!@M%3C|d^E7Za4Ya_KDV-kulI3zg+8>n@Q zPwlfJneh>Ckqv7(b67ArBRpI2fxGm^&x zVAj7s4oX1Xv2dpsd>ZevAfJ(O?S><%L7_lq9<+l}yRC*j@XEmsw-rV6{1!jbuNN&= zkg7}~sZ0N+7-Eg8J1f4+Od^?u=C$ZwuBP?ET%v23_W+XT$}_qiIFeyKhpd`v&rBxm zE+h9VNJw}OVQ?*(I z{yb>l2BO3Uoc&?~zE$Nua-JQ`LTErt^ow(klAwmD2b4MF3}!l@6@@swEcsGqKuI9!JbYW6=Zir?RhfV-cKAva zEbHy37K~dI49a0aux|@f1+#2iF4*6z(i3bRVyz$;NJZH!Y6OBT)hOyr6=1w}=k?23-Qdz= z_2Y*Bjg=wBfmEn2nHvH8&MWPS>g&$n8}v^=q?HHNwq^x_7vD;sU?b33O7MbbIYCm8 z9>MdV#9s3>`S8v3!Mp^QUJB;)y5(R_xYGl33LrmIFatu|o@68anTyT%q<8A* pvGf7u!sV9&I 9,8 0 076 +? 9,9 0 077 +@ 9,9 0 0100 +at " +A 9,9 0 0101 +B 9,9 0 0102 +C 9,9 0 0103 +D 9,9 0 0104 +E 9,9 0 0105 +F 9,9 0 0106 +G 9,9 0 0107 +H 9,9 0 0110 +I 9,9 0 0111 +J 9,9 0 0112 +K 9,9 0 0113 +L 9,9 0 0114 +M 9,9 0 0115 +N 9,9 0 0116 +O 9,9 0 0117 +P 9,9 0 0120 +Q 9,9,2 0 0121 +R 9,9 0 0122 +S 9,9 0 0123 +T 9,9 0 0124 +U 9,9 0 0125 +V 9,9 0 0126 +W 9,9 0 0127 +X 9,9 0 0130 +Y 9,9 0 0131 +Z 9,9 0 0132 +[ 9,9,2 0 0133 +lB " +\ 9,10,2 0 0134 +rs " +] 9,9,2 0 0135 +rB " +^ 9,9 0 0136 +a^ " +ha " +_ 9,0,2 0 0137 +` 9,10 0 0140 +oq " +a 9,7 0 0141 +b 9,10 0 0142 +c 9,7 0 0143 +d 9,10 0 0144 +e 9,7 0 0145 +f 9,10 0 0146 +g 9,7,3 0 0147 +h 9,10 0 0150 +i 9,10 0 0151 +j 9,10,3 0 0152 +k 9,10 0 0153 +l 9,10 0 0154 +m 9,7 0 0155 +n 9,7 0 0156 +o 9,7 0 0157 +p 9,7,3 0 0160 +q 9,7,3 0 0161 +r 9,7 0 0162 +s 9,7 0 0163 +t 9,9 0 0164 +u 9,7 0 0165 +v 9,7 0 0166 +w 9,7 0 0167 +x 9,7 0 0170 +y 9,7,3 0 0171 +z 9,7 0 0172 +{ 9,9,2 0 0173 +lC " +| 9,9,2 0 0174 +or " +ba " +} 9,9,2 0 0175 +rC " +~ 9,6 0 0176 +a~ " +ap " +ti " +r! 9,7,2 0 0241 +¡ " +ct 9,9,1 0 0242 +¢ " +Po 9,9 0 0243 +£ " +Cs 9,7 0 0244 +¤ " +Ye 9,9 0 0245 +¥ " +bb 9,9,2 0 0246 +¦ " +sc 9,10,1 0 0247 +§ " +ad 9,10 0 0250 +¨ " +co 9,9 0 0251 +© " +Of 9,9 0 0252 +ª " +Fo 9,6 0 0253 +« " +no 9,5 0 0254 +¬ " +- 9,5 0 0255 +hy " +­ " +rg 9,9 0 0256 +® " +a- 9,9 0 0257 +¯ " +de 9,9 0 0260 +° " ++- 9,8 0 0261 +± " +S2 9,10 0 0262 +² " +S3 9,10 0 0263 +³ " +aa 9,9 0 0264 +´ " +µ 9,7,3 0 0265 +ps 9,10,1 0 0266 +¶ " +md 9,5 0 0267 +· " +ac 9,1,3 0 0270 +¸ " +S1 9,10 0 0271 +¹ " +Om 9,9 0 0272 +º " +Fc 9,6 0 0273 +» " +14 9,10 0 0274 +¼ " +12 9,10 0 0275 +½ " +34 9,10 0 0276 +¾ " +r? 9,7,2 0 0277 +¿ " +`A 9,12 0 0300 +À " +'A 9,12 0 0301 +Á " +^A 9,12 0 0302 +Â " +~A 9,12 0 0303 +Ã " +:A 9,12 0 0304 +Ä " +oA 9,12 0 0305 +Å " +AE 9,9 0 0306 +Æ " +,C 9,9,4 0 0307 +Ç " +`E 9,12 0 0310 +È " +'E 9,12 0 0311 +É " +^E 9,12 0 0312 +Ê " +:E 9,12 0 0313 +Ë " +`I 9,12 0 0314 +Ì " +'I 9,12 0 0315 +Í " +^I 9,12 0 0316 +Î " +:I 9,12 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 9,12 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,12 0 0326 +Ö " +mu 9,8 0 0327 +× " +/O 9,10 0 0330 +Ø " +`U 9,12 0 0331 +Ù " +'U 9,12 0 0332 +Ú " +^U 9,12 0 0333 +Û " +:U 9,12 0 0334 +Ü " +'Y 9,12 0 0335 +Ý " +TP 9,9 0 0336 +Þ " +ss 9,9 0 0337 +ß " +`a 9,10 0 0340 +à " +'a 9,10 0 0341 +á " +^a 9,10 0 0342 +â " +~a 9,10 0 0343 +ã " +:a 9,10 0 0344 +ä " +oa 9,10 0 0345 +å " +ae 9,7 0 0346 +æ " +,c 9,7,4 0 0347 +ç " +`e 9,10 0 0350 +è " +'e 9,10 0 0351 +é " +^e 9,10 0 0352 +ê " +:e 9,10 0 0353 +ë " +`i 9,10 0 0354 +ì " +'i 9,10 0 0355 +í " +^i 9,10 0 0356 +î " +:i 9,10 0 0357 +ï " +Sd 9,10 0 0360 +ð " +~n 9,10 0 0361 +ñ " +`o 9,10 0 0362 +ò " +'o 9,10 0 0363 +ó " +^o 9,10 0 0364 +ô " +~o 9,10 0 0365 +õ " +:o 9,10 0 0366 +ö " +di 9,8 0 0367 +÷ " +/o 9,7 0 0370 +ø " +`u 9,10 0 0371 +ù " +'u 9,10 0 0372 +ú " +^u 9,10 0 0373 +û " +:u 9,10 0 0374 +ü " +'y 9,10,3 0 0375 +ý " +Tp 9,9,3 0 0376 +þ " +:y 9,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/CBI b/gnu/usr.bin/groff/devices/devX100/CBI new file mode 100644 index 0000000000000000000000000000000000000000..55e27f4065bf31bc7895fe0e52481f173324bb09 GIT binary patch literal 3190 zcmbtWZERCj7{1+Fb{SV%pvn?a8Y5viVnCe?2XP-A_Gc~&$;)mYe9&CCT-6> z_j%v*em?KXDB&8W`B%9f!u@cL^!U(zkjUBl3{m7tkX^f>wH9o*)RRUyB66 zkVisSY9_k`wd89-6om9tXQznotOYFX`ML#v*sf4SGN6x4-@Gm?u*%_|J=t|_ctf`= zyurv}y-$k$tUeY>*7;mQhg6hzm+YC>fuug)V5B3}G=JQR@bz)P?}*KuQZBq7n6n5+}vPNoYMO zlJ$}i4HRtnjOc=b4ZjgBFW4wEqO%J&rs+{X(EPh zvcer3^mZsN=(t|w?P$Ql5-ubAR4(v>kC^XaF+Zz`A-32(cQ73Wpl$s#g8F2TK3j`- z7LtA+v=xeQt3i)+2x=|YR6D1wO3;(*;2&ony(iYa&FyH_z67wbbAz4uWC&ag`9X6925aOT?r=7V1j z??o-%>%N6KtesnVulshqx2*~#hEkMbgPiy3^LVcqffJJTHt+qSC;Vg?c&~np_iCsu z3*PG{Wn^V{vfk#sWfE!JYshW-`rhMCsxO}67T!h za7gG%UE!$6$rX+YJ7l(GBw9EvR?WNnsFhxHqNZDA)bh@K>t24iI7|Ote}fm?9b#$6 zz_nC#A-c_-p+vu!=m-7vi^Qk*x=DZHT2XRQd<0H{P&yT>JIZNf$O?ISCid(ttLRXC zG@EeP2H6*piqtm{HRUdp<#v2`DxABZ%NKStZ4UrJdT2+EyVT{pAGC+;mU5}%?L~2Z zCyxtKa{+pCwCmnNRq-Zpx^6Wd+n*D83R6w|mAu_pA{8$Y$uV-cqPa`IHa$AtSlOk^ zU4iryru>l-cD)!5jG9PaIb>T?1_wZyJE@AAT z$!yXX59h@%u2ALZScD%B(sszfyy{3?EoEAqK8M((5u;g6Hrqhu7pRX^16QfVVKHef z<5Bj;PQzr#*^AV1JUQX^#(v`ukv5RpDXj9`Jc`FrH~-W}-7E{ztIyc>%Q&p(exOpP z(RVp-qg4goo^a4pxoO?JLFNDU_SL>IZyyZOt(IJzu5qGu`U2!zxO~2AobBHL5^>=n z{Q@Ak;8exj-qb<}j5;wR=fo|!S_>g-D9y^bv47r}8w-Ne?YN*8FSY<_>;Rs7_z9pSLISm zdJtG4?ZwrE-?%kNp)br~?D!GfGi;1!6f@D9wicwqg7CYDK0J+IL{^GML}H#z7;&b2 z8LTmaZ$=3RxYA1B&BJW>mk8N+e3tz)I?LX$D(c?v@W 9,8 0 076 +? 9,9 0 077 +@ 9,9 0 0100 +at " +A 9,9 0 0101 +B 9,9 0 0102 +C 9,9 0 0103 +D 9,9 0 0104 +E 9,9 0 0105 +F 9,9 0 0106 +G 9,9 0 0107 +H 9,9 0 0110 +I 9,9 0 0111 +J 9,9 0 0112 +K 9,9 0 0113 +L 9,9 0 0114 +M 9,9 0 0115 +N 9,9 0 0116 +O 9,9 0 0117 +P 9,9 0 0120 +Q 9,9,2 0 0121 +R 9,9 0 0122 +S 9,9 0 0123 +T 9,9 0 0124 +U 9,9 0 0125 +V 9,9 0 0126 +W 9,9 0 0127 +X 9,9 0 0130 +Y 9,9 0 0131 +Z 9,9 0 0132 +[ 9,10,3 0 0133 +lB " +\ 9,10,2 0 0134 +rs " +] 9,10,3 0 0135 +rB " +^ 9,9 0 0136 +a^ " +ha " +_ 9,0,3 0 0137 +` 9,10 0 0140 +oq " +a 9,7 0 0141 +b 9,10 0 0142 +c 9,7 0 0143 +d 9,10 0 0144 +e 9,7 0 0145 +f 9,10 0 0146 +g 9,7,3 0 0147 +h 9,10 0 0150 +i 9,10 0 0151 +j 9,10,3 0 0152 +k 9,10 0 0153 +l 9,10 0 0154 +m 9,7 0 0155 +n 9,7 0 0156 +o 9,7 0 0157 +p 9,7,3 0 0160 +q 9,7,3 0 0161 +r 9,7 0 0162 +s 9,7 0 0163 +t 9,9 0 0164 +u 9,7 0 0165 +v 9,7 0 0166 +w 9,7 0 0167 +x 9,7 0 0170 +y 9,7,3 0 0171 +z 9,7 0 0172 +{ 9,10,3 0 0173 +lC " +| 9,9,2 0 0174 +or " +ba " +} 9,10,3 0 0175 +rC " +~ 9,5 0 0176 +a~ " +ap " +ti " +r! 9,7,2 0 0241 +¡ " +ct 9,10 0 0242 +¢ " +Po 9,9 0 0243 +£ " +Cs 9,7 0 0244 +¤ " +Ye 9,9 0 0245 +¥ " +bb 9,9,2 0 0246 +¦ " +sc 9,9,1 0 0247 +§ " +ad 9,9 0 0250 +¨ " +co 9,9 0 0251 +© " +Of 9,9 0 0252 +ª " +Fo 9,7 0 0253 +« " +no 9,6 0 0254 +¬ " +- 9,5 0 0255 +hy " +­ " +rg 9,9 0 0256 +® " +a- 9,9 0 0257 +¯ " +de 9,10 0 0260 +° " ++- 9,8 0 0261 +± " +S2 9,10 0 0262 +² " +S3 9,10 0 0263 +³ " +aa 9,9 0 0264 +´ " +µ 9,7,3 0 0265 +ps 9,9,1 0 0266 +¶ " +md 9,5 0 0267 +· " +ac 9,1,3 0 0270 +¸ " +S1 9,10 0 0271 +¹ " +Om 9,9 0 0272 +º " +Fc 9,7 0 0273 +» " +14 9,10 0 0274 +¼ " +12 9,10 0 0275 +½ " +34 9,10 0 0276 +¾ " +r? 9,7,2 0 0277 +¿ " +`A 9,12 0 0300 +À " +'A 9,12 0 0301 +Á " +^A 9,12 0 0302 +Â " +~A 9,12 0 0303 +Ã " +:A 9,11 0 0304 +Ä " +oA 9,12 0 0305 +Å " +AE 9,9 0 0306 +Æ " +,C 9,9,3 0 0307 +Ç " +`E 9,12 0 0310 +È " +'E 9,12 0 0311 +É " +^E 9,12 0 0312 +Ê " +:E 9,11 0 0313 +Ë " +`I 9,12 0 0314 +Ì " +'I 9,12 0 0315 +Í " +^I 9,12 0 0316 +Î " +:I 9,11 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 9,12 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,11 0 0326 +Ö " +mu 9,8 0 0327 +× " +/O 9,9 0 0330 +Ø " +`U 9,12 0 0331 +Ù " +'U 9,12 0 0332 +Ú " +^U 9,12 0 0333 +Û " +:U 9,11 0 0334 +Ü " +'Y 9,12 0 0335 +Ý " +TP 9,9 0 0336 +Þ " +ss 9,9 0 0337 +ß " +`a 9,10 0 0340 +à " +'a 9,10 0 0341 +á " +^a 9,10 0 0342 +â " +~a 9,10 0 0343 +ã " +:a 9,9 0 0344 +ä " +oa 9,11 0 0345 +å " +ae 9,7 0 0346 +æ " +,c 9,7,3 0 0347 +ç " +`e 9,10 0 0350 +è " +'e 9,10 0 0351 +é " +^e 9,10 0 0352 +ê " +:e 9,9 0 0353 +ë " +`i 9,10 0 0354 +ì " +'i 9,10 0 0355 +í " +^i 9,10 0 0356 +î " +:i 9,9 0 0357 +ï " +Sd 9,10 0 0360 +ð " +~n 9,10 0 0361 +ñ " +`o 9,10 0 0362 +ò " +'o 9,10 0 0363 +ó " +^o 9,10 0 0364 +ô " +~o 9,10 0 0365 +õ " +:o 9,9 0 0366 +ö " +di 9,8 0 0367 +÷ " +/o 9,7 0 0370 +ø " +`u 9,10 0 0371 +ù " +'u 9,10 0 0372 +ú " +^u 9,10 0 0373 +û " +:u 9,9 0 0374 +ü " +'y 9,10,3 0 0375 +ý " +Tp 9,9,3 0 0376 +þ " +:y 9,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/CR b/gnu/usr.bin/groff/devices/devX100/CR new file mode 100644 index 0000000000..e425fa602b --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/CR @@ -0,0 +1,306 @@ +name CR +spacewidth 9 +charset +--- 9,1 0 040 +! 9,9 0 041 +" 9,10 0 042 +# 9,9,1 0 043 +sh " +$ 9,11,2 0 044 +Do " +% 9,10 0 045 +& 9,8 0 046 +' 9,10 0 047 +( 9,10,2 0 050 +) 9,10,2 0 051 +* 9,9 0 052 ++ 9,8 0 053 +, 9,2,2 0 054 +\- 9,5 0 055 +. 9,2 0 056 +/ 9,10,1 0 057 +sl " +0 9,10 0 060 +1 9,10 0 061 +2 9,10 0 062 +3 9,10 0 063 +4 9,10 0 064 +5 9,10 0 065 +6 9,10 0 066 +7 9,10 0 067 +8 9,10 0 070 +9 9,10 0 071 +: 9,7 0 072 +; 9,7,2 0 073 +< 9,8 0 074 += 9,6 0 075 +eq " +> 9,8 0 076 +? 9,9 0 077 +@ 9,9,1 0 0100 +at " +A 9,9 0 0101 +B 9,9 0 0102 +C 9,9 0 0103 +D 9,9 0 0104 +E 9,9 0 0105 +F 9,9 0 0106 +G 9,9 0 0107 +H 9,9 0 0110 +I 9,9 0 0111 +J 9,9 0 0112 +K 9,9 0 0113 +L 9,9 0 0114 +M 9,9 0 0115 +N 9,9 0 0116 +O 9,9 0 0117 +P 9,9 0 0120 +Q 9,9,2 0 0121 +R 9,9 0 0122 +S 9,9 0 0123 +T 9,9 0 0124 +U 9,9 0 0125 +V 9,9 0 0126 +W 9,9 0 0127 +X 9,9 0 0130 +Y 9,9 0 0131 +Z 9,9 0 0132 +[ 9,10,2 0 0133 +lB " +\ 9,10,1 0 0134 +rs " +] 9,10,2 0 0135 +rB " +^ 9,9 0 0136 +a^ " +ha " +_ 9,0,3 0 0137 +` 9,10 0 0140 +oq " +a 9,7 0 0141 +b 9,10 0 0142 +c 9,7 0 0143 +d 9,10 0 0144 +e 9,7 0 0145 +f 9,10 0 0146 +g 9,7,3 0 0147 +h 9,10 0 0150 +i 9,10 0 0151 +j 9,10,3 0 0152 +k 9,10 0 0153 +l 9,10 0 0154 +m 9,7 0 0155 +n 9,7 0 0156 +o 9,7 0 0157 +p 9,7,3 0 0160 +q 9,7,3 0 0161 +r 9,7 0 0162 +s 9,7 0 0163 +t 9,9 0 0164 +u 9,7 0 0165 +v 9,7 0 0166 +w 9,7 0 0167 +x 9,7 0 0170 +y 9,7,3 0 0171 +z 9,7 0 0172 +{ 9,10,2 0 0173 +lC " +| 9,9,2 0 0174 +or " +ba " +} 9,10,2 0 0175 +rC " +~ 9,5 0 0176 +a~ " +ap " +ti " +r! 9,7,2 0 0241 +¡ " +ct 9,9 0 0242 +¢ " +Po 9,9 0 0243 +£ " +Cs 9,7 0 0244 +¤ " +Ye 9,9 0 0245 +¥ " +bb 9,9,2 0 0246 +¦ " +sc 9,9,1 0 0247 +§ " +ad 9,9 0 0250 +¨ " +co 9,9 0 0251 +© " +Of 9,9 0 0252 +ª " +Fo 9,7 0 0253 +« " +no 9,6 0 0254 +¬ " +- 9,5 0 0255 +hy " +­ " +rg 9,9 0 0256 +® " +a- 9,9 0 0257 +¯ " +de 9,10 0 0260 +° " ++- 9,8 0 0261 +± " +S2 9,10 0 0262 +² " +S3 9,10 0 0263 +³ " +aa 9,10 0 0264 +´ " +µ 9,7,3 0 0265 +ps 9,9,1 0 0266 +¶ " +md 9,5 0 0267 +· " +ac 9,0,3 0 0270 +¸ " +S1 9,10 0 0271 +¹ " +Om 9,9 0 0272 +º " +Fc 9,7 0 0273 +» " +14 9,10 0 0274 +¼ " +12 9,10 0 0275 +½ " +34 9,10 0 0276 +¾ " +r? 9,7,2 0 0277 +¿ " +`A 9,12 0 0300 +À " +'A 9,12 0 0301 +Á " +^A 9,12 0 0302 +Â " +~A 9,12 0 0303 +Ã " +:A 9,11 0 0304 +Ä " +oA 9,12 0 0305 +Å " +AE 9,9 0 0306 +Æ " +,C 9,9,3 0 0307 +Ç " +`E 9,12 0 0310 +È " +'E 9,12 0 0311 +É " +^E 9,12 0 0312 +Ê " +:E 9,11 0 0313 +Ë " +`I 9,12 0 0314 +Ì " +'I 9,12 0 0315 +Í " +^I 9,12 0 0316 +Î " +:I 9,11 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 9,12 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,11 0 0326 +Ö " +mu 9,8 0 0327 +× " +/O 9,9 0 0330 +Ø " +`U 9,12 0 0331 +Ù " +'U 9,12 0 0332 +Ú " +^U 9,12 0 0333 +Û " +:U 9,11 0 0334 +Ü " +'Y 9,12 0 0335 +Ý " +TP 9,9 0 0336 +Þ " +ss 9,9 0 0337 +ß " +`a 9,10 0 0340 +à " +'a 9,10 0 0341 +á " +^a 9,10 0 0342 +â " +~a 9,10 0 0343 +ã " +:a 9,9 0 0344 +ä " +oa 9,10 0 0345 +å " +ae 9,7 0 0346 +æ " +,c 9,7,3 0 0347 +ç " +`e 9,10 0 0350 +è " +'e 9,10 0 0351 +é " +^e 9,10 0 0352 +ê " +:e 9,9 0 0353 +ë " +`i 9,10 0 0354 +ì " +'i 9,10 0 0355 +í " +^i 9,10 0 0356 +î " +:i 9,9 0 0357 +ï " +Sd 9,12 0 0360 +ð " +~n 9,10 0 0361 +ñ " +`o 9,10 0 0362 +ò " +'o 9,10 0 0363 +ó " +^o 9,10 0 0364 +ô " +~o 9,10 0 0365 +õ " +:o 9,9 0 0366 +ö " +di 9,8 0 0367 +÷ " +/o 9,7 0 0370 +ø " +`u 9,10 0 0371 +ù " +'u 9,10 0 0372 +ú " +^u 9,10 0 0373 +û " +:u 9,9 0 0374 +ü " +'y 9,10,3 0 0375 +ý " +Tp 9,9,3 0 0376 +þ " +:y 9,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/DESC b/gnu/usr.bin/groff/devices/devX100/DESC new file mode 100644 index 0000000000..7f63535e0e --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/DESC @@ -0,0 +1,9 @@ +styles R I B BI +fonts 6 0 0 0 0 0 S +sizes 8 10 12 14 18 24 0 +res 100 +X11 +hor 1 +vert 1 +unitwidth 10 +postpro gxditview diff --git a/gnu/usr.bin/groff/devices/devX100/HB b/gnu/usr.bin/groff/devices/devX100/HB new file mode 100644 index 0000000000..d877fd65a0 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/HB @@ -0,0 +1,306 @@ +name HB +spacewidth 4 +charset +--- 4,1 0 040 +! 4,11 0 041 +" 7,11 0 042 +# 9,10 0 043 +sh " +$ 8,12,2 0 044 +Do " +% 13,11 0 045 +& 11,10 0 046 +' 5,11 0 047 +( 5,11,3 0 050 +) 5,11,3 0 051 +* 6,11 0 052 ++ 9,8 0 053 +, 4,2,1 0 054 +\- 9,5 0 055 +. 4,2 0 056 +/ 4,11 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 5,8 0 072 +; 5,8,1 0 073 +< 8,7 0 074 += 9,6 0 075 +eq " +> 8,7 0 076 +? 9,11 0 077 +@ 14,11,1 0 0100 +at " +A 10,11 0 0101 +B 10,11 0 0102 +C 11,11 0 0103 +D 11,11 0 0104 +E 9,11 0 0105 +F 9,11 0 0106 +G 11,11 0 0107 +H 10,11 0 0110 +I 4,11 0 0111 +J 8,11 0 0112 +K 10,11 0 0113 +L 8,11 0 0114 +M 13,11 0 0115 +N 11,11 0 0116 +O 12,11 0 0117 +P 10,11 0 0120 +Q 12,11 0 0121 +R 11,11 0 0122 +S 10,11 0 0123 +T 8,11 0 0124 +U 11,11 0 0125 +V 10,11 0 0126 +W 14,11 0 0127 +X 9,11 0 0130 +Y 10,11 0 0131 +Z 9,11 0 0132 +[ 5,11,3 0 0133 +lB " +\ 4,11 0 0134 +rs " +] 5,11,3 0 0135 +rB " +^ 8,11 0 0136 +a^ " +ha " +_ 8,0,3 0 0137 +` 5,11 0 0140 +oq " +a 8,8 0 0141 +b 9,11 0 0142 +c 8,8 0 0143 +d 9,11 0 0144 +e 8,8 0 0145 +f 4,11 0 0146 +g 9,8,3 0 0147 +h 9,11 0 0150 +i 4,11 0 0151 +j 4,11,3 0 0152 +k 8,11 0 0153 +l 4,11 0 0154 +m 12,8 0 0155 +n 9,8 0 0156 +o 9,8 0 0157 +p 9,8,3 0 0160 +q 9,8,3 0 0161 +r 6,8 0 0162 +s 8,8 0 0163 +t 5,10 0 0164 +u 9,8 0 0165 +v 8,8 0 0166 +w 10,8 0 0167 +x 7,8 0 0170 +y 8,8,3 0 0171 +z 6,8 0 0172 +{ 6,11,3 0 0173 +lC " +| 4,11,3 0 0174 +or " +ba " +} 6,11,3 0 0175 +rC " +~ 9,6 0 0176 +a~ " +ap " +ti " +r! 4,8,3 0 0241 +¡ " +ct 8,9,1 0 0242 +¢ " +Po 8,11 0 0243 +£ " +Cs 8,9 0 0244 +¤ " +Ye 9,11 0 0245 +¥ " +bb 4,11,3 0 0246 +¦ " +sc 8,11,3 0 0247 +§ " +ad 5,11 0 0250 +¨ " +co 12,11 0 0251 +© " +Of 6,11 0 0252 +ª " +Fo 9,7 0 0253 +« " +no 9,6 0 0254 +¬ " +- 4,5 0 0255 +hy " +­ " +rg 12,11 0 0256 +® " +a- 5,10 0 0257 +¯ " +de 6,11 0 0260 +° " ++- 9,9 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 5,11 0 0264 +´ " +µ 9,8,3 0 0265 +ps 8,11,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 4,11 0 0271 +¹ " +Om 6,11 0 0272 +º " +Fc 9,7 0 0273 +» " +14 12,11 0 0274 +¼ " +12 12,11 0 0275 +½ " +34 12,11 0 0276 +¾ " +r? 9,8,3 0 0277 +¿ " +`A 10,14 0 0300 +À " +'A 10,14 0 0301 +Á " +^A 10,14 0 0302 +Â " +~A 10,14 0 0303 +Ã " +:A 10,14 0 0304 +Ä " +oA 10,14 0 0305 +Å " +AE 15,11 0 0306 +Æ " +,C 11,11,3 0 0307 +Ç " +`E 9,14 0 0310 +È " +'E 9,14 0 0311 +É " +^E 9,14 0 0312 +Ê " +:E 9,14 0 0313 +Ë " +`I 4,14 0 0314 +Ì " +'I 4,14 0 0315 +Í " +^I 4,14 0 0316 +Î " +:I 4,14 0 0317 +Ï " +-D 11,11 0 0320 +Ð " +~N 11,14 0 0321 +Ñ " +`O 12,14 0 0322 +Ò " +'O 12,14 0 0323 +Ó " +^O 12,14 0 0324 +Ô " +~O 12,14 0 0325 +Õ " +:O 12,14 0 0326 +Ö " +mu 9,8 0 0327 +× " +/O 12,11 0 0330 +Ø " +`U 11,14 0 0331 +Ù " +'U 11,14 0 0332 +Ú " +^U 11,14 0 0333 +Û " +:U 11,14 0 0334 +Ü " +'Y 10,14 0 0335 +Ý " +TP 10,11 0 0336 +Þ " +ss 8,11 0 0337 +ß " +`a 8,11 0 0340 +à " +'a 8,11 0 0341 +á " +^a 8,11 0 0342 +â " +~a 8,11 0 0343 +ã " +:a 8,11 0 0344 +ä " +oa 8,11 0 0345 +å " +ae 13,8 0 0346 +æ " +,c 9,8,3 0 0347 +ç " +`e 8,11 0 0350 +è " +'e 8,11 0 0351 +é " +^e 8,11 0 0352 +ê " +:e 8,11 0 0353 +ë " +`i 4,11 0 0354 +ì " +'i 4,11 0 0355 +í " +^i 4,11 0 0356 +î " +:i 4,11 0 0357 +ï " +Sd 9,11 0 0360 +ð " +~n 9,11 0 0361 +ñ " +`o 9,11 0 0362 +ò " +'o 9,11 0 0363 +ó " +^o 9,11 0 0364 +ô " +~o 9,11 0 0365 +õ " +:o 9,11 0 0366 +ö " +di 9,8 0 0367 +÷ " +/o 9,8 0 0370 +ø " +`u 9,11 0 0371 +ù " +'u 9,11 0 0372 +ú " +^u 9,11 0 0373 +û " +:u 9,11 0 0374 +ü " +'y 8,11,3 0 0375 +ý " +Tp 9,11,3 0 0376 +þ " +:y 8,11,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/HBI b/gnu/usr.bin/groff/devices/devX100/HBI new file mode 100644 index 0000000000..1cf0e56e63 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/HBI @@ -0,0 +1,306 @@ +name HBI +spacewidth 4 +charset +--- 4,1 0 040 +! 5,11 0 041 +" 7,11 0 042 +# 10,10 0 043 +sh " +$ 8,12,1 0 044 +Do " +% 13,11 0 045 +& 11,10 0 046 +' 5,11 0 047 +( 5,11,3 0 050 +) 6,11,3 0 051 +* 6,11 0 052 ++ 9,8 0 053 +, 4,2,2 0 054 +\- 9,5 0 055 +. 4,2 0 056 +/ 4,11 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 5,8 0 072 +; 5,8,2 0 073 +< 8,7 0 074 += 9,6 0 075 +eq " +> 9,7 0 076 +? 9,11 0 077 +@ 14,11,2 0 0100 +at " +A 9,11 0 0101 +B 10,11 0 0102 +C 11,11 0 0103 +D 11,11 0 0104 +E 9,11 0 0105 +F 8,11 0 0106 +G 11,11 0 0107 +H 10,11 0 0110 +I 4,11 0 0111 +J 8,11 0 0112 +K 10,11 0 0113 +L 8,11 0 0114 +M 13,11 0 0115 +N 11,11 0 0116 +O 12,11 0 0117 +P 10,11 0 0120 +Q 12,11 0 0121 +R 10,11 0 0122 +S 10,11 0 0123 +T 8,11 0 0124 +U 11,11 0 0125 +V 10,11 0 0126 +W 14,11 0 0127 +X 9,11 0 0130 +Y 10,11 0 0131 +Z 9,11 0 0132 +[ 5,11,3 0 0133 +lB " +\ 6,11 0 0134 +rs " +] 5,11,3 0 0135 +rB " +^ 8,11 0 0136 +a^ " +ha " +_ 8,0,3 0 0137 +` 5,11 0 0140 +oq " +a 8,8 0 0141 +b 9,11 0 0142 +c 8,8 0 0143 +d 9,11 0 0144 +e 8,8 0 0145 +f 5,11 0 0146 +g 9,8,3 0 0147 +h 9,11 0 0150 +i 4,11 0 0151 +j 4,11,3 0 0152 +k 8,11 0 0153 +l 4,11 0 0154 +m 12,8 0 0155 +n 9,8 0 0156 +o 8,8 0 0157 +p 9,8,3 0 0160 +q 9,8,3 0 0161 +r 6,8 0 0162 +s 8,8 0 0163 +t 5,10 0 0164 +u 9,8 0 0165 +v 8,8 0 0166 +w 11,8 0 0167 +x 7,8 0 0170 +y 7,8,3 0 0171 +z 6,8 0 0172 +{ 6,11,3 0 0173 +lC " +| 4,11,3 0 0174 +or " +ba " +} 6,11,3 0 0175 +rC " +~ 9,6 0 0176 +a~ " +ap " +ti " +r! 5,8,3 0 0241 +¡ " +ct 8,9,1 0 0242 +¢ " +Po 9,11 0 0243 +£ " +Cs 9,8 0 0244 +¤ " +Ye 9,11 0 0245 +¥ " +bb 4,11,3 0 0246 +¦ " +sc 9,11,3 0 0247 +§ " +ad 5,11 0 0250 +¨ " +co 12,11 0 0251 +© " +Of 6,11 0 0252 +ª " +Fo 11,7 0 0253 +« " +no 9,6 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,11 0 0256 +® " +a- 5,11 0 0257 +¯ " +de 6,11 0 0260 +° " ++- 9,9 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 5,11 0 0264 +´ " +µ 9,8,3 0 0265 +ps 8,11,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 5,1,3 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 6,11 0 0272 +º " +Fc 11,7 0 0273 +» " +14 12,11 0 0274 +¼ " +12 12,11 0 0275 +½ " +34 13,11 0 0276 +¾ " +r? 8,8,3 0 0277 +¿ " +`A 9,14 0 0300 +À " +'A 9,14 0 0301 +Á " +^A 9,14 0 0302 +Â " +~A 9,14 0 0303 +Ã " +:A 9,14 0 0304 +Ä " +oA 9,14 0 0305 +Å " +AE 14,11 0 0306 +Æ " +,C 11,11,3 0 0307 +Ç " +`E 9,14 0 0310 +È " +'E 9,14 0 0311 +É " +^E 9,14 0 0312 +Ê " +:E 9,14 0 0313 +Ë " +`I 4,14 0 0314 +Ì " +'I 4,14 0 0315 +Í " +^I 4,14 0 0316 +Î " +:I 4,14 0 0317 +Ï " +-D 11,11 0 0320 +Ð " +~N 11,14 0 0321 +Ñ " +`O 12,14 0 0322 +Ò " +'O 12,14 0 0323 +Ó " +^O 12,14 0 0324 +Ô " +~O 12,14 0 0325 +Õ " +:O 12,14 0 0326 +Ö " +mu 9,8 0 0327 +× " +/O 12,11 0 0330 +Ø " +`U 11,14 0 0331 +Ù " +'U 11,14 0 0332 +Ú " +^U 11,14 0 0333 +Û " +:U 11,14 0 0334 +Ü " +'Y 10,14 0 0335 +Ý " +TP 10,11 0 0336 +Þ " +ss 9,11 0 0337 +ß " +`a 8,11 0 0340 +à " +'a 8,11 0 0341 +á " +^a 8,11 0 0342 +â " +~a 8,11 0 0343 +ã " +:a 8,11 0 0344 +ä " +oa 8,11 0 0345 +å " +ae 13,8 0 0346 +æ " +,c 8,8,3 0 0347 +ç " +`e 8,11 0 0350 +è " +'e 8,11 0 0351 +é " +^e 8,11 0 0352 +ê " +:e 8,11 0 0353 +ë " +`i 4,11 0 0354 +ì " +'i 4,11 0 0355 +í " +^i 4,11 0 0356 +î " +:i 4,11 0 0357 +ï " +Sd 8,11 0 0360 +ð " +~n 9,11 0 0361 +ñ " +`o 8,11 0 0362 +ò " +'o 8,11 0 0363 +ó " +^o 8,11 0 0364 +ô " +~o 8,11 0 0365 +õ " +:o 8,11 0 0366 +ö " +di 9,8 0 0367 +÷ " +/o 8,8 0 0370 +ø " +`u 9,11 0 0371 +ù " +'u 9,11 0 0372 +ú " +^u 9,11 0 0373 +û " +:u 9,11 0 0374 +ü " +'y 7,11,3 0 0375 +ý " +Tp 9,11,3 0 0376 +þ " +:y 7,11,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/HI b/gnu/usr.bin/groff/devices/devX100/HI new file mode 100644 index 0000000000..7908492d43 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/HI @@ -0,0 +1,306 @@ +name HI +spacewidth 4 +charset +--- 4,1 0 040 +! 4,11 0 041 +" 5,11 0 042 +# 9,10 0 043 +sh " +$ 8,12,2 0 044 +Do " +% 12,11 0 045 +& 10,10 0 046 +' 3,11 0 047 +( 5,11,3 0 050 +) 5,11,3 0 051 +* 8,11 0 052 ++ 9,8 0 053 +, 3,2,2 0 054 +\- 9,5 0 055 +. 3,2 0 056 +/ 4,11 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 4,8 0 072 +; 4,8,2 0 073 +< 9,7 0 074 += 9,6 0 075 +eq " +> 9,7 0 076 +? 8,11 0 077 +@ 13,11,1 0 0100 +at " +A 11,11 0 0101 +B 10,11 0 0102 +C 10,11 0 0103 +D 10,11 0 0104 +E 9,11 0 0105 +F 9,11 0 0106 +G 11,11 0 0107 +H 11,11 0 0110 +I 5,11 0 0111 +J 9,11 0 0112 +K 10,11 0 0113 +L 8,11 0 0114 +M 14,11 0 0115 +N 11,11 0 0116 +O 11,11 0 0117 +P 9,11 0 0120 +Q 11,11 0 0121 +R 10,11 0 0122 +S 9,11 0 0123 +T 8,11 0 0124 +U 11,11 0 0125 +V 11,11 0 0126 +W 14,11 0 0127 +X 10,11 0 0130 +Y 9,11 0 0131 +Z 9,11 0 0132 +[ 5,11,3 0 0133 +lB " +\ 6,11 0 0134 +rs " +] 5,11,3 0 0135 +rB " +^ 7,11 0 0136 +a^ " +ha " +_ 8,0,3 0 0137 +` 3,11 0 0140 +oq " +a 8,8 0 0141 +b 8,11 0 0142 +c 7,8 0 0143 +d 8,11 0 0144 +e 8,8 0 0145 +f 4,11 0 0146 +g 8,8,3 0 0147 +h 8,11 0 0150 +i 4,11 0 0151 +j 3,11,3 0 0152 +k 7,11 0 0153 +l 3,11 0 0154 +m 11,8 0 0155 +n 8,8 0 0156 +o 8,8 0 0157 +p 8,8,3 0 0160 +q 8,8,3 0 0161 +r 5,8 0 0162 +s 7,8 0 0163 +t 4,10 0 0164 +u 8,8 0 0165 +v 7,8 0 0166 +w 10,8 0 0167 +x 7,8 0 0170 +y 7,8,3 0 0171 +z 7,8 0 0172 +{ 5,11,3 0 0173 +lC " +| 4,11,3 0 0174 +or " +ba " +} 5,11,3 0 0175 +rC " +~ 8,6 0 0176 +a~ " +ap " +ti " +r! 4,8,3 0 0241 +¡ " +ct 8,9,1 0 0242 +¢ " +Po 9,11 0 0243 +£ " +Cs 8,8 0 0244 +¤ " +Ye 9,11 0 0245 +¥ " +bb 4,11,3 0 0246 +¦ " +sc 8,11,3 0 0247 +§ " +ad 5,10 0 0250 +¨ " +co 12,11 0 0251 +© " +Of 5,11 0 0252 +ª " +Fo 8,6 0 0253 +« " +no 9,6 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,11 0 0256 +® " +a- 4,10 0 0257 +¯ " +de 6,11 0 0260 +° " ++- 9,9 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 4,11 0 0264 +´ " +µ 8,8,3 0 0265 +ps 8,11,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 3,0,3 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 5,11 0 0272 +º " +Fc 8,6 0 0273 +» " +14 12,11 0 0274 +¼ " +12 12,11 0 0275 +½ " +34 12,11 0 0276 +¾ " +r? 8,8,3 0 0277 +¿ " +`A 11,14 0 0300 +À " +'A 11,14 0 0301 +Á " +^A 11,14 0 0302 +Â " +~A 11,14 0 0303 +Ã " +:A 11,13 0 0304 +Ä " +oA 11,14 0 0305 +Å " +AE 15,11 0 0306 +Æ " +,C 10,11,3 0 0307 +Ç " +`E 9,14 0 0310 +È " +'E 9,14 0 0311 +É " +^E 9,14 0 0312 +Ê " +:E 9,13 0 0313 +Ë " +`I 5,14 0 0314 +Ì " +'I 5,14 0 0315 +Í " +^I 5,14 0 0316 +Î " +:I 5,13 0 0317 +Ï " +-D 10,11 0 0320 +Ð " +~N 11,14 0 0321 +Ñ " +`O 11,14 0 0322 +Ò " +'O 11,14 0 0323 +Ó " +^O 11,14 0 0324 +Ô " +~O 11,14 0 0325 +Õ " +:O 11,13 0 0326 +Ö " +mu 9,8 0 0327 +× " +/O 11,11 0 0330 +Ø " +`U 11,14 0 0331 +Ù " +'U 11,14 0 0332 +Ú " +^U 11,14 0 0333 +Û " +:U 11,13 0 0334 +Ü " +'Y 9,14 0 0335 +Ý " +TP 9,11 0 0336 +Þ " +ss 8,11 0 0337 +ß " +`a 8,11 0 0340 +à " +'a 8,11 0 0341 +á " +^a 8,11 0 0342 +â " +~a 8,11 0 0343 +ã " +:a 8,11 0 0344 +ä " +oa 8,11 0 0345 +å " +ae 12,8 0 0346 +æ " +,c 7,8,3 0 0347 +ç " +`e 8,11 0 0350 +è " +'e 8,11 0 0351 +é " +^e 8,11 0 0352 +ê " +:e 8,11 0 0353 +ë " +`i 3,11 0 0354 +ì " +'i 3,11 0 0355 +í " +^i 3,11 0 0356 +î " +:i 3,11 0 0357 +ï " +Sd 8,11 0 0360 +ð " +~n 8,11 0 0361 +ñ " +`o 8,11 0 0362 +ò " +'o 8,11 0 0363 +ó " +^o 8,11 0 0364 +ô " +~o 8,11 0 0365 +õ " +:o 8,11 0 0366 +ö " +di 9,8 0 0367 +÷ " +/o 8,9,1 0 0370 +ø " +`u 8,11 0 0371 +ù " +'u 8,11 0 0372 +ú " +^u 8,11 0 0373 +û " +:u 8,11 0 0374 +ü " +'y 7,11,3 0 0375 +ý " +Tp 8,11,3 0 0376 +þ " +:y 7,11,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/HR b/gnu/usr.bin/groff/devices/devX100/HR new file mode 100644 index 0000000000..c2f6af3903 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/HR @@ -0,0 +1,306 @@ +name HR +spacewidth 4 +charset +--- 4,1 0 040 +! 4,11 0 041 +" 5,11 0 042 +# 8,10 0 043 +sh " +$ 8,12,2 0 044 +Do " +% 12,11 0 045 +& 10,10 0 046 +' 3,11 0 047 +( 5,11,3 0 050 +) 5,11,3 0 051 +* 7,11 0 052 ++ 9,8 0 053 +, 3,2,2 0 054 +\- 9,5 0 055 +. 3,2 0 056 +/ 4,11 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 3,8 0 072 +; 4,8,2 0 073 +< 8,7 0 074 += 9,6 0 075 +eq " +> 8,7 0 076 +? 8,11 0 077 +@ 13,11,1 0 0100 +at " +A 9,11 0 0101 +B 9,11 0 0102 +C 10,11 0 0103 +D 10,11 0 0104 +E 9,11 0 0105 +F 8,11 0 0106 +G 11,11 0 0107 +H 10,11 0 0110 +I 4,11 0 0111 +J 7,11 0 0112 +K 9,11 0 0113 +L 8,11 0 0114 +M 12,11 0 0115 +N 10,11 0 0116 +O 11,11 0 0117 +P 9,11 0 0120 +Q 11,11 0 0121 +R 10,11 0 0122 +S 9,11 0 0123 +T 9,11 0 0124 +U 10,11 0 0125 +V 9,11 0 0126 +W 13,11 0 0127 +X 9,11 0 0130 +Y 9,11 0 0131 +Z 9,11 0 0132 +[ 4,11,3 0 0133 +lB " +\ 4,11 0 0134 +rs " +] 4,11,3 0 0135 +rB " +^ 7,11 0 0136 +a^ " +ha " +_ 8,0,3 0 0137 +` 3,11 0 0140 +oq " +a 8,8 0 0141 +b 7,11 0 0142 +c 7,8 0 0143 +d 8,11 0 0144 +e 8,8 0 0145 +f 4,11 0 0146 +g 8,8,3 0 0147 +h 8,11 0 0150 +i 3,11 0 0151 +j 3,11,3 0 0152 +k 7,11 0 0153 +l 3,11 0 0154 +m 11,8 0 0155 +n 8,8 0 0156 +o 8,8 0 0157 +p 8,8,3 0 0160 +q 8,8,3 0 0161 +r 5,8 0 0162 +s 7,8 0 0163 +t 4,10 0 0164 +u 7,8 0 0165 +v 7,8 0 0166 +w 10,8 0 0167 +x 7,8 0 0170 +y 7,8,3 0 0171 +z 7,8 0 0172 +{ 5,11,3 0 0173 +lC " +| 3,11,3 0 0174 +or " +ba " +} 5,11,3 0 0175 +rC " +~ 8,6 0 0176 +a~ " +ap " +ti " +r! 4,8,3 0 0241 +¡ " +ct 8,9,1 0 0242 +¢ " +Po 8,11 0 0243 +£ " +Cs 8,8 0 0244 +¤ " +Ye 7,11 0 0245 +¥ " +bb 3,11,3 0 0246 +¦ " +sc 8,11,3 0 0247 +§ " +ad 5,10 0 0250 +¨ " +co 12,11 0 0251 +© " +Of 6,11 0 0252 +ª " +Fo 8,7 0 0253 +« " +no 9,6 0 0254 +¬ " +- 4,5 0 0255 +hy " +­ " +rg 12,11 0 0256 +® " +a- 4,10 0 0257 +¯ " +de 6,11 0 0260 +° " ++- 9,9 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 5,11 0 0264 +´ " +µ 8,8,3 0 0265 +ps 8,11,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 6,11 0 0272 +º " +Fc 8,7 0 0273 +» " +14 12,11 0 0274 +¼ " +12 12,11 0 0275 +½ " +34 12,11 0 0276 +¾ " +r? 8,8,3 0 0277 +¿ " +`A 9,14 0 0300 +À " +'A 9,14 0 0301 +Á " +^A 9,14 0 0302 +Â " +~A 9,13 0 0303 +Ã " +:A 9,14 0 0304 +Ä " +oA 9,14 0 0305 +Å " +AE 14,11 0 0306 +Æ " +,C 10,11,3 0 0307 +Ç " +`E 9,14 0 0310 +È " +'E 9,14 0 0311 +É " +^E 9,14 0 0312 +Ê " +:E 9,13 0 0313 +Ë " +`I 4,14 0 0314 +Ì " +'I 4,14 0 0315 +Í " +^I 4,14 0 0316 +Î " +:I 4,13 0 0317 +Ï " +-D 10,11 0 0320 +Ð " +~N 10,14 0 0321 +Ñ " +`O 11,14 0 0322 +Ò " +'O 11,14 0 0323 +Ó " +^O 11,14 0 0324 +Ô " +~O 11,14 0 0325 +Õ " +:O 11,13 0 0326 +Ö " +mu 9,8 0 0327 +× " +/O 11,11 0 0330 +Ø " +`U 10,14 0 0331 +Ù " +'U 10,14 0 0332 +Ú " +^U 10,14 0 0333 +Û " +:U 10,13 0 0334 +Ü " +'Y 9,14 0 0335 +Ý " +TP 9,11 0 0336 +Þ " +ss 7,11 0 0337 +ß " +`a 8,11 0 0340 +à " +'a 8,11 0 0341 +á " +^a 8,11 0 0342 +â " +~a 8,11 0 0343 +ã " +:a 8,11 0 0344 +ä " +oa 8,12 0 0345 +å " +ae 13,8 0 0346 +æ " +,c 8,8,3 0 0347 +ç " +`e 8,11 0 0350 +è " +'e 8,11 0 0351 +é " +^e 8,11 0 0352 +ê " +:e 8,11 0 0353 +ë " +`i 3,11 0 0354 +ì " +'i 3,11 0 0355 +í " +^i 3,11 0 0356 +î " +:i 3,11 0 0357 +ï " +Sd 8,11 0 0360 +ð " +~n 8,11 0 0361 +ñ " +`o 8,11 0 0362 +ò " +'o 8,11 0 0363 +ó " +^o 8,11 0 0364 +ô " +~o 8,11 0 0365 +õ " +:o 8,11 0 0366 +ö " +di 9,8 0 0367 +÷ " +/o 8,8 0 0370 +ø " +`u 8,11 0 0371 +ù " +'u 8,11 0 0372 +ú " +^u 8,11 0 0373 +û " +:u 8,11 0 0374 +ü " +'y 7,11,3 0 0375 +ý " +Tp 8,11,3 0 0376 +þ " +:y 7,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/Makefile b/gnu/usr.bin/groff/devices/devX100/Makefile new file mode 100644 index 0000000000..0cf8d281d1 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/Makefile @@ -0,0 +1,10 @@ +# Makefile for devX100 + +DEVICE= X100 +FONTFILES= CB CBI CI CR HB HBI HI HR NB NBI NI NR S TB TBI TI TR DESC + +NOOBJ= noobj + +clean cleandir: + +.include "../Makefile.dev" diff --git a/gnu/usr.bin/groff/devices/devX100/NB b/gnu/usr.bin/groff/devices/devX100/NB new file mode 100644 index 0000000000..d47fdb2e1e --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/NB @@ -0,0 +1,306 @@ +name NB +spacewidth 11 +charset +--- 11,1 0 040 +! 4,11 0 041 +" 5,11 0 042 +# 8,10 0 043 +sh " +$ 8,12,1 0 044 +Do " +% 13,11 0 045 +& 13,11 0 046 +' 4,11 0 047 +( 5,11,2 0 050 +) 5,11,2 0 051 +* 6,11 0 052 ++ 8,8 0 053 +, 4,3,2 0 054 +\- 8,5 0 055 +. 4,3 0 056 +/ 5,11 0 057 +sl " +0 8,11 0 060 +1 6,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 4,7 0 072 +; 4,7,2 0 073 +< 8,8 0 074 += 8,6 0 075 +eq " +> 8,8 0 076 +? 7,11 0 077 +@ 14,11 0 0100 +at " +A 11,11 0 0101 +B 10,11 0 0102 +C 11,11 0 0103 +D 12,11 0 0104 +E 10,11 0 0105 +F 10,11 0 0106 +G 12,11 0 0107 +H 12,11 0 0110 +I 7,11 0 0111 +J 9,11 0 0112 +K 12,11 0 0113 +L 10,11 0 0114 +M 14,11 0 0115 +N 12,11 0 0116 +O 12,11 0 0117 +P 10,11 0 0120 +Q 12,11,3 0 0121 +R 12,11 0 0122 +S 10,11 0 0123 +T 11,11 0 0124 +U 12,11 0 0125 +V 11,11 0 0126 +W 14,11 0 0127 +X 12,11 0 0130 +Y 11,11 0 0131 +Z 9,11 0 0132 +[ 5,11,2 0 0133 +lB " +\ 7,11 0 0134 +rs " +] 5,11,2 0 0135 +rB " +^ 8,11 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 4,11 0 0140 +oq " +a 9,7 0 0141 +b 10,11 0 0142 +c 8,7 0 0143 +d 10,11 0 0144 +e 9,7 0 0145 +f 6,11 0 0146 +g 8,8,3 0 0147 +h 10,11 0 0150 +i 5,10 0 0151 +j 5,10,3 0 0152 +k 9,11 0 0153 +l 5,11 0 0154 +m 15,7 0 0155 +n 10,7 0 0156 +o 9,7 0 0157 +p 10,7,3 0 0160 +q 9,7,3 0 0161 +r 7,7 0 0162 +s 7,7 0 0163 +t 6,10 0 0164 +u 10,7 0 0165 +v 7,7 0 0166 +w 12,7 0 0167 +x 9,7 0 0170 +y 7,7,3 0 0171 +z 7,7 0 0172 +{ 6,11,2 0 0173 +lC " +| 8,11 0 0174 +or " +ba " +} 6,11,2 0 0175 +rC " +~ 8,6 0 0176 +a~ " +ap " +ti " +r! 5,8,3 0 0241 +¡ " +ct 8,8,1 0 0242 +¢ " +Po 9,11 0 0243 +£ " +Cs 9,10 0 0244 +¤ " +Ye 11,11 0 0245 +¥ " +bb 8,11 0 0246 +¦ " +sc 7,11,2 0 0247 +§ " +ad 7,10 0 0250 +¨ " +co 12,11 0 0251 +© " +Of 6,11 0 0252 +ª " +Fo 8,6 0 0253 +« " +no 8,6 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,11 0 0256 +® " +a- 7,9 0 0257 +¯ " +de 6,11 0 0260 +° " ++- 8,8 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 6,11 0 0264 +´ " +µ 10,7,3 0 0265 +ps 10,11 0 0266 +¶ " +md 5,6 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 6,11 0 0272 +º " +Fc 8,6 0 0273 +» " +14 12,11 0 0274 +¼ " +12 12,11 0 0275 +½ " +34 12,11 0 0276 +¾ " +r? 7,8,3 0 0277 +¿ " +`A 11,15 0 0300 +À " +'A 11,15 0 0301 +Á " +^A 11,15 0 0302 +Â " +~A 11,14 0 0303 +Ã " +:A 11,14 0 0304 +Ä " +oA 11,15 0 0305 +Å " +AE 15,11 0 0306 +Æ " +,C 11,11,3 0 0307 +Ç " +`E 10,15 0 0310 +È " +'E 10,15 0 0311 +É " +^E 10,15 0 0312 +Ê " +:E 10,14 0 0313 +Ë " +`I 7,15 0 0314 +Ì " +'I 7,15 0 0315 +Í " +^I 7,15 0 0316 +Î " +:I 7,14 0 0317 +Ï " +-D 12,11 0 0320 +Ð " +~N 12,14 0 0321 +Ñ " +`O 12,15 0 0322 +Ò " +'O 12,15 0 0323 +Ó " +^O 12,15 0 0324 +Ô " +~O 12,14 0 0325 +Õ " +:O 12,14 0 0326 +Ö " +mu 8,8 0 0327 +× " +/O 12,11 0 0330 +Ø " +`U 12,15 0 0331 +Ù " +'U 12,15 0 0332 +Ú " +^U 12,15 0 0333 +Û " +:U 12,14 0 0334 +Ü " +'Y 11,14 0 0335 +Ý " +TP 10,11 0 0336 +Þ " +ss 9,11 0 0337 +ß " +`a 9,11 0 0340 +à " +'a 9,11 0 0341 +á " +^a 9,11 0 0342 +â " +~a 9,10 0 0343 +ã " +:a 9,10 0 0344 +ä " +oa 9,11 0 0345 +å " +ae 14,7 0 0346 +æ " +,c 8,7,3 0 0347 +ç " +`e 9,11 0 0350 +è " +'e 9,11 0 0351 +é " +^e 9,11 0 0352 +ê " +:e 9,10 0 0353 +ë " +`i 5,11 0 0354 +ì " +'i 5,11 0 0355 +í " +^i 5,11 0 0356 +î " +:i 5,10 0 0357 +ï " +Sd 9,11 0 0360 +ð " +~n 10,10 0 0361 +ñ " +`o 9,11 0 0362 +ò " +'o 9,11 0 0363 +ó " +^o 9,11 0 0364 +ô " +~o 9,10 0 0365 +õ " +:o 9,10 0 0366 +ö " +di 8,8 0 0367 +÷ " +/o 9,8,1 0 0370 +ø " +`u 10,11 0 0371 +ù " +'u 10,11 0 0372 +ú " +^u 10,11 0 0373 +û " +:u 10,10 0 0374 +ü " +'y 7,11,3 0 0375 +ý " +Tp 10,11,3 0 0376 +þ " +:y 7,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/NBI b/gnu/usr.bin/groff/devices/devX100/NBI new file mode 100644 index 0000000000..c46b945ae8 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/NBI @@ -0,0 +1,306 @@ +name NBI +spacewidth 4 +charset +--- 4,1 0 040 +! 5,11 0 041 +" 6,11 0 042 +# 8,10 0 043 +sh " +$ 8,12,1 0 044 +Do " +% 13,11,1 0 045 +& 13,11 0 046 +' 4,11 0 047 +( 5,11,2 0 050 +) 6,11,2 0 051 +* 7,11 0 052 ++ 8,8 0 053 +, 4,2,3 0 054 +\- 8,5 0 055 +. 4,2 0 056 +/ 5,11 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 4,7 0 072 +; 5,7,3 0 073 +< 9,9 0 074 += 9,7 0 075 +eq " +> 9,9 0 076 +? 7,11 0 077 +@ 13,11 0 0100 +at " +A 11,11 0 0101 +B 10,11 0 0102 +C 11,11 0 0103 +D 12,11 0 0104 +E 10,11 0 0105 +F 10,11 0 0106 +G 11,11 0 0107 +H 12,11 0 0110 +I 6,11 0 0111 +J 8,11 0 0112 +K 12,11 0 0113 +L 10,11 0 0114 +M 15,11 0 0115 +N 13,11 0 0116 +O 12,11 0 0117 +P 11,11 0 0120 +Q 12,11,2 0 0121 +R 12,11 0 0122 +S 10,11 0 0123 +T 11,11 0 0124 +U 12,11 0 0125 +V 11,11 0 0126 +W 15,11 0 0127 +X 11,11 0 0130 +Y 9,11 0 0131 +Z 10,11 0 0132 +[ 7,11,2 0 0133 +lB " +\ 9,11 0 0134 +rs " +] 7,11,2 0 0135 +rB " +^ 8,11 0 0136 +a^ " +ha " +_ 9,0,2 0 0137 +` 4,11 0 0140 +oq " +a 10,7 0 0141 +b 8,11 0 0142 +c 8,7 0 0143 +d 10,11 0 0144 +e 8,7 0 0145 +f 5,11,3 0 0146 +g 8,9,3 0 0147 +h 10,11 0 0150 +i 5,10 0 0151 +j 4,10,3 0 0152 +k 9,11 0 0153 +l 5,11 0 0154 +m 15,7 0 0155 +n 10,7 0 0156 +o 8,7 0 0157 +p 8,7,3 0 0160 +q 9,7,3 0 0161 +r 7,7 0 0162 +s 8,7 0 0163 +t 5,9 0 0164 +u 10,7 0 0165 +v 8,7 0 0166 +w 13,7 0 0167 +x 9,7 0 0170 +y 9,7,3 0 0171 +z 9,7 0 0172 +{ 6,11,2 0 0173 +lC " +| 9,11 0 0174 +or " +ba " +} 6,11,2 0 0175 +rC " +~ 11,6 0 0176 +a~ " +ap " +ti " +r! 5,8,3 0 0241 +¡ " +ct 8,8,1 0 0242 +¢ " +Po 10,11 0 0243 +£ " +Cs 8,9 0 0244 +¤ " +Ye 10,11 0 0245 +¥ " +bb 8,11 0 0246 +¦ " +sc 9,11,2 0 0247 +§ " +ad 6,10 0 0250 +¨ " +co 12,11 0 0251 +© " +Of 8,11 0 0252 +ª " +Fo 10,7 0 0253 +« " +no 9,7 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 12,11 0 0256 +® " +a- 6,9 0 0257 +¯ " +de 6,11 0 0260 +° " ++- 8,8 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 5,11 0 0264 +´ " +µ 10,7,3 0 0265 +ps 9,11 0 0266 +¶ " +md 5,6 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 8,11 0 0272 +º " +Fc 10,7 0 0273 +» " +14 12,11 0 0274 +¼ " +12 12,11 0 0275 +½ " +34 12,11 0 0276 +¾ " +r? 7,8,3 0 0277 +¿ " +`A 11,15 0 0300 +À " +'A 11,15 0 0301 +Á " +^A 11,15 0 0302 +Â " +~A 11,14 0 0303 +Ã " +:A 11,14 0 0304 +Ä " +oA 11,15 0 0305 +Å " +AE 14,11 0 0306 +Æ " +,C 11,11,3 0 0307 +Ç " +`E 10,15 0 0310 +È " +'E 10,15 0 0311 +É " +^E 10,15 0 0312 +Ê " +:E 10,14 0 0313 +Ë " +`I 6,15 0 0314 +Ì " +'I 6,15 0 0315 +Í " +^I 6,15 0 0316 +Î " +:I 6,14 0 0317 +Ï " +-D 12,11 0 0320 +Ð " +~N 13,14 0 0321 +Ñ " +`O 12,15 0 0322 +Ò " +'O 12,15 0 0323 +Ó " +^O 12,15 0 0324 +Ô " +~O 12,14 0 0325 +Õ " +:O 12,14 0 0326 +Ö " +mu 8,8 0 0327 +× " +/O 12,11 0 0330 +Ø " +`U 12,15 0 0331 +Ù " +'U 12,15 0 0332 +Ú " +^U 12,15 0 0333 +Û " +:U 12,14 0 0334 +Ü " +'Y 9,15 0 0335 +Ý " +TP 11,11 0 0336 +Þ " +ss 10,11,3 0 0337 +ß " +`a 10,11 0 0340 +à " +'a 10,11 0 0341 +á " +^a 10,11 0 0342 +â " +~a 10,10 0 0343 +ã " +:a 10,10 0 0344 +ä " +oa 10,11 0 0345 +å " +ae 13,7 0 0346 +æ " +,c 8,7,3 0 0347 +ç " +`e 8,11 0 0350 +è " +'e 8,11 0 0351 +é " +^e 8,11 0 0352 +ê " +:e 8,10 0 0353 +ë " +`i 5,11 0 0354 +ì " +'i 5,11 0 0355 +í " +^i 5,11 0 0356 +î " +:i 5,10 0 0357 +ï " +Sd 8,11 0 0360 +ð " +~n 10,10 0 0361 +ñ " +`o 8,11 0 0362 +ò " +'o 8,11 0 0363 +ó " +^o 8,11 0 0364 +ô " +~o 8,10 0 0365 +õ " +:o 8,10 0 0366 +ö " +di 8,8 0 0367 +÷ " +/o 8,7 0 0370 +ø " +`u 10,11 0 0371 +ù " +'u 10,11 0 0372 +ú " +^u 10,11 0 0373 +û " +:u 10,10 0 0374 +ü " +'y 9,11,3 0 0375 +ý " +Tp 8,11,3 0 0376 +þ " +:y 9,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/NI b/gnu/usr.bin/groff/devices/devX100/NI new file mode 100644 index 0000000000..3216f64a05 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/NI @@ -0,0 +1,306 @@ +name NI +spacewidth 4 +charset +--- 4,1 0 040 +! 5,11 0 041 +" 6,11 0 042 +# 11,10 0 043 +sh " +$ 8,12,1 0 044 +Do " +% 12,11,1 0 045 +& 11,11 0 046 +' 4,11 0 047 +( 5,11,2 0 050 +) 5,11,2 0 051 +* 6,11 0 052 ++ 8,8 0 053 +, 4,2,2 0 054 +\- 9,5 0 055 +. 4,2 0 056 +/ 9,11,3 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 4,7 0 072 +; 4,7,2 0 073 +< 9,8 0 074 += 8,6 0 075 +eq " +> 9,8 0 076 +? 6,11 0 077 +@ 12,11 0 0100 +at " +A 11,11 0 0101 +B 9,11 0 0102 +C 10,11 0 0103 +D 11,11 0 0104 +E 9,11 0 0105 +F 8,11 0 0106 +G 10,11 0 0107 +H 11,11 0 0110 +I 7,11 0 0111 +J 8,11 0 0112 +K 10,11 0 0113 +L 9,11 0 0114 +M 14,11 0 0115 +N 12,11 0 0116 +O 10,11 0 0117 +P 10,11 0 0120 +Q 10,11,2 0 0121 +R 11,11 0 0122 +S 10,11 0 0123 +T 10,11 0 0124 +U 12,11 0 0125 +V 10,11 0 0126 +W 13,11 0 0127 +X 10,11 0 0130 +Y 9,11 0 0131 +Z 10,11 0 0132 +[ 6,11,2 0 0133 +lB " +\ 8,11 0 0134 +rs " +] 6,11,2 0 0135 +rB " +^ 6,11 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 4,11 0 0140 +oq " +a 9,7 0 0141 +b 7,11 0 0142 +c 6,7 0 0143 +d 9,11 0 0144 +e 6,7 0 0145 +f 5,11,3 0 0146 +g 7,8,3 0 0147 +h 9,11 0 0150 +i 4,11 0 0151 +j 4,11,3 0 0152 +k 8,11 0 0153 +l 4,11 0 0154 +m 14,7 0 0155 +n 9,7 0 0156 +o 7,7 0 0157 +p 7,7,3 0 0160 +q 8,7,3 0 0161 +r 7,7 0 0162 +s 7,7 0 0163 +t 5,9 0 0164 +u 9,7 0 0165 +v 7,7 0 0166 +w 11,7 0 0167 +x 8,7 0 0170 +y 7,7,3 0 0171 +z 8,7 0 0172 +{ 6,11,2 0 0173 +lC " +| 9,11 0 0174 +or " +ba " +} 6,11,2 0 0175 +rC " +~ 9,6 0 0176 +a~ " +ap " +ti " +r! 4,8,3 0 0241 +¡ " +ct 8,9,2 0 0242 +¢ " +Po 9,11 0 0243 +£ " +Cs 8,9 0 0244 +¤ " +Ye 9,11 0 0245 +¥ " +bb 8,11 0 0246 +¦ " +sc 7,11,2 0 0247 +§ " +ad 7,10 0 0250 +¨ " +co 13,11 0 0251 +© " +Of 6,11 0 0252 +ª " +Fo 8,7 0 0253 +« " +no 8,6 0 0254 +¬ " +- 5,5 0 0255 +hy " +­ " +rg 13,11 0 0256 +® " +a- 6,9 0 0257 +¯ " +de 6,11 0 0260 +° " ++- 8,8 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 4,11 0 0264 +´ " +µ 9,7,3 0 0265 +ps 9,11 0 0266 +¶ " +md 5,6 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 6,11 0 0272 +º " +Fc 8,7 0 0273 +» " +14 12,11 0 0274 +¼ " +12 12,11 0 0275 +½ " +34 12,11 0 0276 +¾ " +r? 6,8,3 0 0277 +¿ " +`A 11,14 0 0300 +À " +'A 11,14 0 0301 +Á " +^A 11,14 0 0302 +Â " +~A 11,14 0 0303 +Ã " +:A 11,14 0 0304 +Ä " +oA 11,14 0 0305 +Å " +AE 14,11 0 0306 +Æ " +,C 10,11,3 0 0307 +Ç " +`E 9,14 0 0310 +È " +'E 9,14 0 0311 +É " +^E 9,14 0 0312 +Ê " +:E 9,14 0 0313 +Ë " +`I 7,14 0 0314 +Ì " +'I 7,14 0 0315 +Í " +^I 7,14 0 0316 +Î " +:I 7,14 0 0317 +Ï " +-D 11,11 0 0320 +Ð " +~N 12,14 0 0321 +Ñ " +`O 10,14 0 0322 +Ò " +'O 10,14 0 0323 +Ó " +^O 10,14 0 0324 +Ô " +~O 10,14 0 0325 +Õ " +:O 10,14 0 0326 +Ö " +mu 8,8 0 0327 +× " +/O 10,11 0 0330 +Ø " +`U 12,14 0 0331 +Ù " +'U 12,14 0 0332 +Ú " +^U 12,14 0 0333 +Û " +:U 12,14 0 0334 +Ü " +'Y 9,14 0 0335 +Ý " +TP 10,11 0 0336 +Þ " +ss 8,11,3 0 0337 +ß " +`a 9,11 0 0340 +à " +'a 9,11 0 0341 +á " +^a 9,11 0 0342 +â " +~a 9,10 0 0343 +ã " +:a 9,10 0 0344 +ä " +oa 9,11 0 0345 +å " +ae 10,7 0 0346 +æ " +,c 6,7,3 0 0347 +ç " +`e 6,11 0 0350 +è " +'e 6,11 0 0351 +é " +^e 6,11 0 0352 +ê " +:e 6,10 0 0353 +ë " +`i 4,11 0 0354 +ì " +'i 4,11 0 0355 +í " +^i 4,11 0 0356 +î " +:i 4,10 0 0357 +ï " +Sd 7,11 0 0360 +ð " +~n 9,10 0 0361 +ñ " +`o 7,11 0 0362 +ò " +'o 7,11 0 0363 +ó " +^o 7,11 0 0364 +ô " +~o 7,10 0 0365 +õ " +:o 7,10 0 0366 +ö " +di 8,8 0 0367 +÷ " +/o 7,8,1 0 0370 +ø " +`u 9,11 0 0371 +ù " +'u 9,11 0 0372 +ú " +^u 9,11 0 0373 +û " +:u 9,10 0 0374 +ü " +'y 7,11,3 0 0375 +ý " +Tp 7,11,3 0 0376 +þ " +:y 7,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/NR b/gnu/usr.bin/groff/devices/devX100/NR new file mode 100644 index 0000000000..8e6717eef1 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/NR @@ -0,0 +1,306 @@ +name NR +spacewidth 4 +charset +--- 4,1 0 040 +! 3,11 0 041 +" 5,11 0 042 +# 8,11 0 043 +sh " +$ 8,12,2 0 044 +Do " +% 12,11 0 045 +& 13,11 0 046 +' 4,11 0 047 +( 5,11,2 0 050 +) 6,11,2 0 051 +* 7,11 0 052 ++ 9,7 0 053 +, 4,2,2 0 054 +\- 9,4 0 055 +. 4,2 0 056 +/ 4,11 0 057 +sl " +0 8,11 0 060 +1 8,11 0 061 +2 8,11 0 062 +3 8,11 0 063 +4 8,11 0 064 +5 8,11 0 065 +6 8,11 0 066 +7 8,11 0 067 +8 8,11 0 070 +9 8,11 0 071 +: 4,7 0 072 +; 4,7,2 0 073 +< 10,7 0 074 += 9,6 0 075 +eq " +> 10,7 0 076 +? 6,11 0 077 +@ 13,11 0 0100 +at " +A 10,11 0 0101 +B 10,11 0 0102 +C 11,11 0 0103 +D 11,11 0 0104 +E 10,11 0 0105 +F 10,11 0 0106 +G 11,11 0 0107 +H 12,11 0 0110 +I 6,11 0 0111 +J 7,11 0 0112 +K 11,11 0 0113 +L 10,11 0 0114 +M 16,11 0 0115 +N 13,11 0 0116 +O 11,11 0 0117 +P 10,11 0 0120 +Q 11,11,2 0 0121 +R 11,11 0 0122 +S 8,11 0 0123 +T 10,11 0 0124 +U 13,11 0 0125 +V 10,11 0 0126 +W 16,11 0 0127 +X 13,11 0 0130 +Y 10,11 0 0131 +Z 9,11 0 0132 +[ 4,11,2 0 0133 +lB " +\ 8,11 0 0134 +rs " +] 4,11,2 0 0135 +rB " +^ 7,11 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 4,11 0 0140 +oq " +a 8,7 0 0141 +b 7,11 0 0142 +c 7,7 0 0143 +d 8,11 0 0144 +e 7,7 0 0145 +f 5,11 0 0146 +g 8,7,3 0 0147 +h 9,11 0 0150 +i 4,10 0 0151 +j 4,10,3 0 0152 +k 9,11 0 0153 +l 4,11 0 0154 +m 14,7 0 0155 +n 9,7 0 0156 +o 7,7 0 0157 +p 8,7,3 0 0160 +q 7,7,3 0 0161 +r 7,7 0 0162 +s 6,7 0 0163 +t 5,9 0 0164 +u 9,7 0 0165 +v 8,7 0 0166 +w 12,7 0 0167 +x 8,7 0 0170 +y 8,7,3 0 0171 +z 7,7 0 0172 +{ 4,11,2 0 0173 +lC " +| 9,11 0 0174 +or " +ba " +} 5,11,2 0 0175 +rC " +~ 9,5 0 0176 +a~ " +ap " +ti " +r! 4,8,3 0 0241 +¡ " +ct 8,9,2 0 0242 +¢ " +Po 8,11 0 0243 +£ " +Cs 8,9 0 0244 +¤ " +Ye 8,11 0 0245 +¥ " +bb 9,11 0 0246 +¦ " +sc 7,11,2 0 0247 +§ " +ad 6,10 0 0250 +¨ " +co 14,11 0 0251 +© " +Of 6,11 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 9,5 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 14,11 0 0256 +® " +a- 5,9 0 0257 +¯ " +de 6,11 0 0260 +° " ++- 9,7 0 0261 +± " +S2 5,11 0 0262 +² " +S3 5,11 0 0263 +³ " +aa 5,11 0 0264 +´ " +µ 9,7,3 0 0265 +ps 9,11,2 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 5,1,3 0 0270 +¸ " +S1 5,11 0 0271 +¹ " +Om 5,11 0 0272 +º " +Fc 7,6 0 0273 +» " +14 12,11 0 0274 +¼ " +12 12,11 0 0275 +½ " +34 12,11 0 0276 +¾ " +r? 6,8,3 0 0277 +¿ " +`A 10,14 0 0300 +À " +'A 10,14 0 0301 +Á " +^A 10,14 0 0302 +Â " +~A 10,14 0 0303 +Ã " +:A 10,13 0 0304 +Ä " +oA 10,14 0 0305 +Å " +AE 15,11 0 0306 +Æ " +,C 11,11,3 0 0307 +Ç " +`E 10,14 0 0310 +È " +'E 10,14 0 0311 +É " +^E 10,14 0 0312 +Ê " +:E 10,14 0 0313 +Ë " +`I 6,14 0 0314 +Ì " +'I 6,14 0 0315 +Í " +^I 6,14 0 0316 +Î " +:I 6,14 0 0317 +Ï " +-D 11,11 0 0320 +Ð " +~N 13,14 0 0321 +Ñ " +`O 11,14 0 0322 +Ò " +'O 11,14 0 0323 +Ó " +^O 11,14 0 0324 +Ô " +~O 11,14 0 0325 +Õ " +:O 11,14 0 0326 +Ö " +mu 9,7 0 0327 +× " +/O 11,11 0 0330 +Ø " +`U 13,14 0 0331 +Ù " +'U 13,14 0 0332 +Ú " +^U 13,14 0 0333 +Û " +:U 13,14 0 0334 +Ü " +'Y 10,14 0 0335 +Ý " +TP 10,11 0 0336 +Þ " +ss 8,11 0 0337 +ß " +`a 8,11 0 0340 +à " +'a 8,11 0 0341 +á " +^a 8,11 0 0342 +â " +~a 8,10 0 0343 +ã " +:a 8,10 0 0344 +ä " +oa 8,11 0 0345 +å " +ae 12,7 0 0346 +æ " +,c 7,7,3 0 0347 +ç " +`e 7,11 0 0350 +è " +'e 7,11 0 0351 +é " +^e 7,11 0 0352 +ê " +:e 7,10 0 0353 +ë " +`i 4,11 0 0354 +ì " +'i 4,11 0 0355 +í " +^i 4,11 0 0356 +î " +:i 4,10 0 0357 +ï " +Sd 7,11 0 0360 +ð " +~n 9,10 0 0361 +ñ " +`o 7,11 0 0362 +ò " +'o 7,11 0 0363 +ó " +^o 7,11 0 0364 +ô " +~o 7,10 0 0365 +õ " +:o 7,10 0 0366 +ö " +di 9,7 0 0367 +÷ " +/o 7,8,1 0 0370 +ø " +`u 9,11 0 0371 +ù " +'u 9,11 0 0372 +ú " +^u 9,11 0 0373 +û " +:u 9,10 0 0374 +ü " +'y 8,11,3 0 0375 +ý " +Tp 8,11,3 0 0376 +þ " +:y 8,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/S b/gnu/usr.bin/groff/devices/devX100/S new file mode 100644 index 0000000000..5e91412460 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/S @@ -0,0 +1,226 @@ +name S +special +spacewidth 4 +charset +--- 4,1 0 040 +! 5,10 0 041 +fa 9,10 0 042 +# 7,10 0 043 +sh " +te 8,10 0 044 +% 12,10 0 045 +& 11,10 0 046 +st 6,7 0 047 +( 5,10,3 0 050 +) 5,10,3 0 051 +** 7,8 0 052 ++ 8,7 0 053 +pl " +, 3,2,2 0 054 +\- 8,4 0 055 +mi " +. 3,2 0 056 +/ 4,10 0 057 +sl " +0 7,10 0 060 +1 7,10 0 061 +2 7,10 0 062 +3 7,10 0 063 +4 7,10 0 064 +5 7,10 0 065 +6 7,10 0 066 +7 7,10 0 067 +8 7,10 0 070 +9 7,10 0 071 +: 4,7 0 072 +; 4,7,2 0 073 +< 8,7 0 074 += 8,5 0 075 +eq " +> 8,7 0 076 +? 6,10 0 077 +=~ 8,7 0 0100 +*A 11,10 0 0101 +*B 9,10 0 0102 +*X 11,10 0 0103 +*D 9,10 0 0104 +*E 9,10 0 0105 +*F 11,10 0 0106 +*G 9,10 0 0107 +*Y 11,10 0 0110 +*I 5,10 0 0111 ++h 9,10 0 0112 +*K 10,10 0 0113 +*L 10,10 0 0114 +*M 13,10 0 0115 +*N 11,10 0 0116 +*O 10,10 0 0117 +*P 11,10 0 0120 +*H 10,10 0 0121 +*R 8,10 0 0122 +*S 9,10 0 0123 +*T 9,10 0 0124 +--- 9,10 0 0125 +ts 7,7,3 0 0126 +*W 11,10 0 0127 +*C 9,10 0 0130 +*Q 11,10 0 0131 +*Z 9,10 0 0132 +[ 5,10,3 0 0133 +lB " +tf 10,7 0 0134 +3d " +] 5,10,3 0 0135 +rB " +pp 10,10 0 0136 +_ 7,0,3 0 0137 +rn 7,12 0 0140 +*a 9,7 0 0141 +*b 8,11,3 0 0142 +*x 8,7,3 0 0143 +*d 7,11 0 0144 +*e 6,7 0 0145 +*f 9,10,3 0 0146 +*g 6,7,3 0 0147 +*y 8,7,3 0 0150 +*i 5,7 0 0151 ++f 9,7,3 0 0152 +*k 8,7 0 0153 +*l 8,10 0 0154 +*m 8,7,2 0 0155 +µ " +*n 8,7 0 0156 +*o 8,7 0 0157 +*p 8,7 0 0160 +*h 7,10 0 0161 +*r 8,7,3 0 0162 +*s 8,7 0 0163 +*t 6,7 0 0164 +*u 8,7 0 0165 ++p 11,8 0 0166 +*w 11,7 0 0167 +*c 7,12,3 0 0170 +*q 9,7,3 0 0171 +*z 7,11,3 0 0172 +lC 7,10,3 0 0173 +{ " +ba 3,10,3 0 0174 +or " +| " +rC 7,10,3 0 0175 +} " +ap 8,5 0 0176 +*U 9,10 0 0241 +fm 4,10 0 0242 +<= 8,9 0 0243 +f/ 4,10 0 0244 +if 10,6 0 0245 +Fn 7,10,3 0 0246 +CL 11,7 0 0247 +DI 11,7 0 0250 +HE 11,7 0 0251 +SP 11,7 0 0252 +<> 15,7 0 0253 +<- 14,7 0 0254 +ua 9,12,3 0 0255 +arrowverttp " +-> 14,7 0 0256 +da 9,12,3 0 0257 +arrowvertbt " +de 6,10 0 0260 +° " ++- 8,9 0 0261 +± " +sd 6,10 0 0262 +>= 8,9 0 0263 +mu 8,7 0 0264 +× " +pt 10,6 0 0265 +pd 7,11 0 0266 +bu 7,6 0 0267 +di 8,7 0 0270 +÷ " +!= 8,7 0 0271 +== 8,6 0 0272 +~= 8,7 0 0273 +~~ " +--- 15,2 0 0274 +arrowvertex 9,12,3 0 0275 +an 15,4 0 0276 +CR 10,9 0 0277 +Ah 12,10 0 0300 +Im 10,11,1 0 0301 +Re 12,11 0 0302 +wp 12,9,3 0 0303 +c* 11,9 0 0304 +c+ 11,9 0 0305 +es 12,11 0 0306 +ca 10,7 0 0307 +cu 10,7 0 0310 +sp 10,7 0 0311 +ip 10,7,2 0 0312 +--- 10,8,1 0 0313 +sb 10,7 0 0314 +ib 10,7,2 0 0315 +mo 10,7 0 0316 +nm 10,8,1 0 0317 +/_ 11,10 0 0320 +gr 10,11 0 0321 +rg 12,10 0 0322 +co 12,10 0 0323 +tm 11,10 0 0324 +--- 12,11,1 0 0325 +sr 8,12 0 0326 +md 4,5 0 0327 +no 10,5 0 0330 +¬ " +AN 9,7 0 0331 +OR 9,7 0 0332 +hA 15,7 0 0333 +lA 14,7 0 0334 +uA 9,12 0 0335 +rA 14,7 0 0336 +dA 9,12 0 0337 +lz 7,11 0 0340 +la 5,12,3 0 0341 +--- 12,10 0 0342 +--- 12,10 0 0343 +--- 11,10 0 0344 +--- 10,11,1 0 0345 +parenlefttp 6,12,3 0 0346 +parenleftex 6,12,3 0 0347 +parenleftbt 6,12,3 0 0350 +bracketlefttp 6,12,3 0 0351 +lc " +bracketleftex 6,12,3 0 0352 +bracketleftbt 6,12,3 0 0353 +lf " +bracelefttp 7,12,3 0 0354 +lt " +braceleftmid 7,12,3 0 0355 +lk " +braceleftbt 7,12,3 0 0356 +lb " +bracerightex 7,12,3 0 0357 +braceleftex " +bv " +--- 12,12 0 0360 +ra 5,12,3 0 0361 +is 4,12,1 0 0362 +--- 10,12,3 0 0363 +--- 10,12,3 0 0364 +--- 10,12,3 0 0365 +parenrighttp 6,12,3 0 0366 +parenrightex 6,12,3 0 0367 +parenrightbt 6,12,3 0 0370 +bracketrighttp 6,12,3 0 0371 +rc " +bracketrightex 6,12,3 0 0372 +bracketrightbt 6,12,3 0 0373 +rf " +bracerighttp 7,12,3 0 0374 +rt " +bracerightmid 7,12,3 0 0375 +rk " +bracerightbt 7,12,3 0 0376 +rb " diff --git a/gnu/usr.bin/groff/devices/devX100/TB b/gnu/usr.bin/groff/devices/devX100/TB new file mode 100644 index 0000000000..ebafbac74b --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/TB @@ -0,0 +1,306 @@ +name TB +spacewidth 3 +charset +--- 3,1 0 040 +! 4,10 0 041 +" 7,10 0 042 +# 7,10 0 043 +sh " +$ 7,11,1 0 044 +Do " +% 14,10 0 045 +& 12,10 0 046 +' 4,10 0 047 +( 5,10,3 0 050 +) 5,10,3 0 051 +* 7,10 0 052 ++ 8,7 0 053 +, 3,2,2 0 054 +\- 9,4 0 055 +. 3,2 0 056 +/ 4,10 0 057 +sl " +0 7,10 0 060 +1 7,10 0 061 +2 7,10 0 062 +3 7,10 0 063 +4 7,10 0 064 +5 7,10 0 065 +6 7,10 0 066 +7 7,10 0 067 +8 7,10 0 070 +9 7,10 0 071 +: 4,7 0 072 +; 4,7,2 0 073 +< 8,7 0 074 += 8,5 0 075 +eq " +> 8,7 0 076 +? 7,10 0 077 +@ 14,10,2 0 0100 +at " +A 10,10 0 0101 +B 9,10 0 0102 +C 10,10 0 0103 +D 10,10 0 0104 +E 9,10 0 0105 +F 8,10 0 0106 +G 11,10 0 0107 +H 11,10 0 0110 +I 5,10 0 0111 +J 7,10,1 0 0112 +K 11,10 0 0113 +L 9,10 0 0114 +M 13,10 0 0115 +N 10,10 0 0116 +O 11,10 0 0117 +P 9,10 0 0120 +Q 11,10,3 0 0121 +R 10,10 0 0122 +S 8,10 0 0123 +T 9,10 0 0124 +U 10,10 0 0125 +V 10,10 0 0126 +W 14,10 0 0127 +X 10,10 0 0130 +Y 10,10 0 0131 +Z 9,10 0 0132 +[ 5,10,3 0 0133 +lB " +\ 4,10 0 0134 +rs " +] 5,10,3 0 0135 +rB " +^ 8,10 0 0136 +a^ " +ha " +_ 7,0,3 0 0137 +` 4,10 0 0140 +oq " +a 7,7 0 0141 +b 8,10 0 0142 +c 6,7 0 0143 +d 7,10 0 0144 +e 6,7 0 0145 +f 5,10 0 0146 +g 7,7,3 0 0147 +h 8,10 0 0150 +i 4,10 0 0151 +j 4,10,3 0 0152 +k 8,10 0 0153 +l 4,10 0 0154 +m 12,7 0 0155 +n 8,7 0 0156 +o 7,7 0 0157 +p 8,7,3 0 0160 +q 7,7,3 0 0161 +r 6,7 0 0162 +s 6,7 0 0163 +t 5,9 0 0164 +u 7,7 0 0165 +v 7,7 0 0166 +w 10,7 0 0167 +x 7,7 0 0170 +y 7,7,3 0 0171 +z 6,7 0 0172 +{ 7,10,3 0 0173 +lC " +| 3,10,2 0 0174 +or " +ba " +} 7,10,3 0 0175 +rC " +~ 8,7 0 0176 +a~ " +ap " +ti " +r! 4,7,3 0 0241 +¡ " +ct 7,9,2 0 0242 +¢ " +Po 8,10 0 0243 +£ " +Cs 8,8 0 0244 +¤ " +Ye 8,10 0 0245 +¥ " +bb 3,10,2 0 0246 +¦ " +sc 7,10,2 0 0247 +§ " +ad 5,10 0 0250 +¨ " +co 12,10 0 0251 +© " +Of 5,10 0 0252 +ª " +Fo 9,6 0 0253 +« " +no 9,5 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 12,10 0 0256 +® " +a- 5,9 0 0257 +¯ " +de 6,10 0 0260 +° " ++- 8,9 0 0261 +± " +S2 4,10 0 0262 +² " +S3 4,10 0 0263 +³ " +aa 5,11 0 0264 +´ " +µ 7,7,3 0 0265 +ps 8,10,3 0 0266 +¶ " +md 4,6 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 4,10 0 0271 +¹ " +Om 5,10 0 0272 +º " +Fc 9,6 0 0273 +» " +14 10,10 0 0274 +¼ " +12 10,10 0 0275 +½ " +34 10,10 0 0276 +¾ " +r? 7,7,3 0 0277 +¿ " +`A 10,14 0 0300 +À " +'A 10,14 0 0301 +Á " +^A 10,14 0 0302 +Â " +~A 10,13 0 0303 +Ã " +:A 10,13 0 0304 +Ä " +oA 10,14 0 0305 +Å " +AE 14,10 0 0306 +Æ " +,C 10,10,3 0 0307 +Ç " +`E 9,14 0 0310 +È " +'E 9,14 0 0311 +É " +^E 9,14 0 0312 +Ê " +:E 9,13 0 0313 +Ë " +`I 5,14 0 0314 +Ì " +'I 5,14 0 0315 +Í " +^I 5,14 0 0316 +Î " +:I 5,13 0 0317 +Ï " +-D 11,10 0 0320 +Ð " +~N 10,13 0 0321 +Ñ " +`O 11,14 0 0322 +Ò " +'O 11,14 0 0323 +Ó " +^O 11,14 0 0324 +Ô " +~O 11,13 0 0325 +Õ " +:O 11,13 0 0326 +Ö " +mu 8,7 0 0327 +× " +/O 11,11,1 0 0330 +Ø " +`U 10,14 0 0331 +Ù " +'U 10,14 0 0332 +Ú " +^U 10,14 0 0333 +Û " +:U 10,13 0 0334 +Ü " +'Y 10,14 0 0335 +Ý " +TP 9,10 0 0336 +Þ " +ss 8,10 0 0337 +ß " +`a 7,11 0 0340 +à " +'a 7,11 0 0341 +á " +^a 7,11 0 0342 +â " +~a 7,10 0 0343 +ã " +:a 7,10 0 0344 +ä " +oa 7,11 0 0345 +å " +ae 11,7 0 0346 +æ " +,c 7,7,3 0 0347 +ç " +`e 7,11 0 0350 +è " +'e 7,11 0 0351 +é " +^e 7,11 0 0352 +ê " +:e 7,10 0 0353 +ë " +`i 4,11 0 0354 +ì " +'i 4,11 0 0355 +í " +^i 4,11 0 0356 +î " +:i 4,10 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 8,10 0 0361 +ñ " +`o 7,11 0 0362 +ò " +'o 7,11 0 0363 +ó " +^o 7,11 0 0364 +ô " +~o 7,10 0 0365 +õ " +:o 7,10 0 0366 +ö " +di 8,7 0 0367 +÷ " +/o 7,8,1 0 0370 +ø " +`u 7,11 0 0371 +ù " +'u 7,11 0 0372 +ú " +^u 7,11 0 0373 +û " +:u 7,10 0 0374 +ü " +'y 7,11,3 0 0375 +ý " +Tp 8,10,3 0 0376 +þ " +:y 7,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/TBI b/gnu/usr.bin/groff/devices/devX100/TBI new file mode 100644 index 0000000000..2297b4b2b6 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/TBI @@ -0,0 +1,306 @@ +name TBI +spacewidth 3 +charset +--- 3,1 0 040 +! 7,10 0 041 +" 7,10 0 042 +# 8,10 0 043 +sh " +$ 7,11,1 0 044 +Do " +% 14,10 0 045 +& 10,10 0 046 +' 5,10 0 047 +( 6,10,3 0 050 +) 6,10,3 0 051 +* 7,10 0 052 ++ 9,7 0 053 +, 4,2,2 0 054 +\- 9,4 0 055 +. 3,2 0 056 +/ 6,10 0 057 +sl " +0 7,10 0 060 +1 7,10 0 061 +2 7,10 0 062 +3 7,10 0 063 +4 7,10 0 064 +5 7,10 0 065 +6 7,10 0 066 +7 7,10 0 067 +8 7,10 0 070 +9 7,10 0 071 +: 5,7 0 072 +; 4,7,2 0 073 +< 8,6 0 074 += 10,5 0 075 +eq " +> 8,6 0 076 +? 8,10 0 077 +@ 15,10,2 0 0100 +at " +A 9,10 0 0101 +B 9,10 0 0102 +C 9,10 0 0103 +D 10,10 0 0104 +E 10,10 0 0105 +F 9,10 0 0106 +G 10,10 0 0107 +H 11,10 0 0110 +I 5,10 0 0111 +J 7,10,1 0 0112 +K 11,10 0 0113 +L 9,10 0 0114 +M 13,10 0 0115 +N 11,10 0 0116 +O 10,10 0 0117 +P 9,10 0 0120 +Q 10,10,3 0 0121 +R 10,10 0 0122 +S 8,10 0 0123 +T 10,10 0 0124 +U 10,10 0 0125 +V 10,10 0 0126 +W 13,10 0 0127 +X 9,10 0 0130 +Y 8,10 0 0131 +Z 8,10 0 0132 +[ 6,10,3 0 0133 +lB " +\ 6,10 0 0134 +rs " +] 5,10,3 0 0135 +rB " +^ 8,10 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 5,10 0 0140 +oq " +a 8,7 0 0141 +b 7,10 0 0142 +c 6,7 0 0143 +d 7,10 0 0144 +e 7,7 0 0145 +f 5,10,3 0 0146 +g 6,7,3 0 0147 +h 8,10 0 0150 +i 4,10 0 0151 +j 4,10,3 0 0152 +k 7,10 0 0153 +l 4,10 0 0154 +m 11,7 0 0155 +n 8,7 0 0156 +o 7,7 0 0157 +p 7,7,3 0 0160 +q 7,7,3 0 0161 +r 6,7 0 0162 +s 6,7 0 0163 +t 4,9 0 0164 +u 7,7 0 0165 +v 6,7 0 0166 +w 9,7 0 0167 +x 6,7 0 0170 +y 6,7,3 0 0171 +z 6,7 0 0172 +{ 7,10,3 0 0173 +lC " +| 4,10 0 0174 +or " +ba " +} 7,10,3 0 0175 +rC " +~ 10,5 0 0176 +a~ " +ap " +ti " +r! 7,7,3 0 0241 +¡ " +ct 7,8,1 0 0242 +¢ " +Po 7,10 0 0243 +£ " +Cs 8,8 0 0244 +¤ " +Ye 7,10 0 0245 +¥ " +bb 4,10 0 0246 +¦ " +sc 8,10,3 0 0247 +§ " +ad 6,9 0 0250 +¨ " +co 12,10 0 0251 +© " +Of 6,10 0 0252 +ª " +Fo 8,6 0 0253 +« " +no 9,5 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 12,10 0 0256 +® " +a- 6,9 0 0257 +¯ " +de 6,10 0 0260 +° " ++- 9,9 0 0261 +± " +S2 4,10 0 0262 +² " +S3 4,10 0 0263 +³ " +aa 6,10 0 0264 +´ " +µ 7,7,3 0 0265 +ps 8,10,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 4,10 0 0271 +¹ " +Om 6,10 0 0272 +º " +Fc 8,6 0 0273 +» " +14 10,10 0 0274 +¼ " +12 10,10 0 0275 +½ " +34 10,10 0 0276 +¾ " +r? 8,7,3 0 0277 +¿ " +`A 9,13 0 0300 +À " +'A 9,13 0 0301 +Á " +^A 9,13 0 0302 +Â " +~A 9,13 0 0303 +Ã " +:A 9,13 0 0304 +Ä " +oA 9,13 0 0305 +Å " +AE 14,10 0 0306 +Æ " +,C 9,10,3 0 0307 +Ç " +`E 10,13 0 0310 +È " +'E 10,13 0 0311 +É " +^E 10,13 0 0312 +Ê " +:E 10,13 0 0313 +Ë " +`I 5,13 0 0314 +Ì " +'I 5,13 0 0315 +Í " +^I 5,13 0 0316 +Î " +:I 5,13 0 0317 +Ï " +-D 10,10 0 0320 +Ð " +~N 11,13 0 0321 +Ñ " +`O 10,13 0 0322 +Ò " +'O 10,13 0 0323 +Ó " +^O 10,13 0 0324 +Ô " +~O 10,13 0 0325 +Õ " +:O 10,13 0 0326 +Ö " +mu 9,7 0 0327 +× " +/O 10,11,1 0 0330 +Ø " +`U 10,13 0 0331 +Ù " +'U 10,13 0 0332 +Ú " +^U 10,13 0 0333 +Û " +:U 10,13 0 0334 +Ü " +'Y 8,13 0 0335 +Ý " +TP 9,10 0 0336 +Þ " +ss 7,10,3 0 0337 +ß " +`a 8,10 0 0340 +à " +'a 8,10 0 0341 +á " +^a 8,11 0 0342 +â " +~a 8,10 0 0343 +ã " +:a 8,10 0 0344 +ä " +oa 8,11 0 0345 +å " +ae 11,7 0 0346 +æ " +,c 6,7,3 0 0347 +ç " +`e 7,10 0 0350 +è " +'e 7,10 0 0351 +é " +^e 7,11 0 0352 +ê " +:e 7,10 0 0353 +ë " +`i 4,10 0 0354 +ì " +'i 4,10 0 0355 +í " +^i 4,11 0 0356 +î " +:i 4,10 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 8,10 0 0361 +ñ " +`o 7,10 0 0362 +ò " +'o 7,10 0 0363 +ó " +^o 7,11 0 0364 +ô " +~o 7,10 0 0365 +õ " +:o 7,10 0 0366 +ö " +di 9,7 0 0367 +÷ " +/o 7,8,1 0 0370 +ø " +`u 7,10 0 0371 +ù " +'u 7,10 0 0372 +ú " +^u 7,11 0 0373 +û " +:u 7,10 0 0374 +ü " +'y 6,10,2 0 0375 +ý " +Tp 7,10,3 0 0376 +þ " +:y 6,10,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/TI b/gnu/usr.bin/groff/devices/devX100/TI new file mode 100644 index 0000000000..80a2f1c404 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/TI @@ -0,0 +1,306 @@ +name TI +spacewidth 3 +charset +--- 3,1 0 040 +! 5,10 0 041 +" 6,10 0 042 +# 7,10 0 043 +sh " +$ 7,11,1 0 044 +Do " +% 12,10 0 045 +& 11,10 0 046 +' 5,10 0 047 +( 5,10,3 0 050 +) 5,10,3 0 051 +* 7,10 0 052 ++ 10,7 0 053 +, 4,2,1 0 054 +\- 9,4 0 055 +. 3,2 0 056 +/ 4,10 0 057 +sl " +0 7,10 0 060 +1 7,10 0 061 +2 7,10 0 062 +3 7,10 0 063 +4 7,10 0 064 +5 7,10 0 065 +6 7,10 0 066 +7 7,10 0 067 +8 7,10 0 070 +9 7,10 0 071 +: 4,7 0 072 +; 4,7,1 0 073 +< 10,7,1 0 074 += 10,5 0 075 +eq " +> 10,7,1 0 076 +? 7,10 0 077 +@ 13,10,3 0 0100 +at " +A 9,10 0 0101 +B 8,10 0 0102 +C 9,10 0 0103 +D 10,10 0 0104 +E 9,10 0 0105 +F 9,10 0 0106 +G 10,10 0 0107 +H 10,10 0 0110 +I 5,10 0 0111 +J 6,10 0 0112 +K 10,10 0 0113 +L 8,10 0 0114 +M 12,10 0 0115 +N 11,10 0 0116 +O 10,10 0 0117 +P 9,10 0 0120 +Q 10,10,3 0 0121 +R 9,10 0 0122 +S 7,10 0 0123 +T 8,10 0 0124 +U 10,10 0 0125 +V 9,10 0 0126 +W 11,10 0 0127 +X 9,10 0 0130 +Y 8,10 0 0131 +Z 8,10 0 0132 +[ 6,10,3 0 0133 +lB " +\ 4,10 0 0134 +rs " +] 6,10,3 0 0135 +rB " +^ 6,10 0 0136 +a^ " +ha " +_ 7,0,4 0 0137 +` 5,10 0 0140 +oq " +a 7,7 0 0141 +b 7,10 0 0142 +c 6,7 0 0143 +d 7,10 0 0144 +e 7,7 0 0145 +f 5,10,3 0 0146 +g 6,7,3 0 0147 +h 7,10 0 0150 +i 4,10 0 0151 +j 4,10,3 0 0152 +k 7,10 0 0153 +l 4,10 0 0154 +m 10,7 0 0155 +n 7,7 0 0156 +o 7,7 0 0157 +p 7,7,3 0 0160 +q 7,7,3 0 0161 +r 5,7 0 0162 +s 6,7 0 0163 +t 5,9 0 0164 +u 7,7 0 0165 +v 6,7 0 0166 +w 9,7 0 0167 +x 7,7 0 0170 +y 7,7,3 0 0171 +z 6,7 0 0172 +{ 6,10,3 0 0173 +lC " +| 4,10,3 0 0174 +or " +ba " +} 6,10,3 0 0175 +rC " +~ 8,5 0 0176 +a~ " +ap " +ti " +r! 6,7,3 0 0241 +¡ " +ct 7,9,2 0 0242 +¢ " +Po 7,10 0 0243 +£ " +Cs 7,8 0 0244 +¤ " +Ye 7,10 0 0245 +¥ " +bb 4,10,3 0 0246 +¦ " +sc 7,11,2 0 0247 +§ " +ad 5,10 0 0250 +¨ " +co 12,10 0 0251 +© " +Of 5,10 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 9,6 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 12,10 0 0256 +® " +a- 5,10 0 0257 +¯ " +de 6,10 0 0260 +° " ++- 10,9 0 0261 +± " +S2 4,10 0 0262 +² " +S3 4,10 0 0263 +³ " +aa 4,10 0 0264 +´ " +µ 7,7,3 0 0265 +ps 8,10,3 0 0266 +¶ " +md 4,4 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 4,10 0 0271 +¹ " +Om 5,10 0 0272 +º " +Fc 7,6 0 0273 +» " +14 10,10 0 0274 +¼ " +12 10,10 0 0275 +½ " +34 10,10 0 0276 +¾ " +r? 7,7,3 0 0277 +¿ " +`A 9,13 0 0300 +À " +'A 9,13 0 0301 +Á " +^A 9,13 0 0302 +Â " +~A 9,13 0 0303 +Ã " +:A 9,12 0 0304 +Ä " +oA 9,13 0 0305 +Å " +AE 13,10 0 0306 +Æ " +,C 9,10,3 0 0307 +Ç " +`E 9,13 0 0310 +È " +'E 9,13 0 0311 +É " +^E 9,13 0 0312 +Ê " +:E 9,12 0 0313 +Ë " +`I 5,13 0 0314 +Ì " +'I 5,13 0 0315 +Í " +^I 5,13 0 0316 +Î " +:I 5,12 0 0317 +Ï " +-D 10,10 0 0320 +Ð " +~N 11,13 0 0321 +Ñ " +`O 10,13 0 0322 +Ò " +'O 10,13 0 0323 +Ó " +^O 10,13 0 0324 +Ô " +~O 10,13 0 0325 +Õ " +:O 10,12 0 0326 +Ö " +mu 10,7 0 0327 +× " +/O 10,11,1 0 0330 +Ø " +`U 10,13 0 0331 +Ù " +'U 10,13 0 0332 +Ú " +^U 10,13 0 0333 +Û " +:U 10,12 0 0334 +Ü " +'Y 8,13 0 0335 +Ý " +TP 9,10 0 0336 +Þ " +ss 7,10,3 0 0337 +ß " +`a 7,10 0 0340 +à " +'a 7,10 0 0341 +á " +^a 7,11 0 0342 +â " +~a 7,10 0 0343 +ã " +:a 7,9 0 0344 +ä " +oa 7,10 0 0345 +å " +ae 10,7 0 0346 +æ " +,c 6,7,3 0 0347 +ç " +`e 7,10 0 0350 +è " +'e 7,10 0 0351 +é " +^e 7,11 0 0352 +ê " +:e 7,9 0 0353 +ë " +`i 4,10 0 0354 +ì " +'i 4,10 0 0355 +í " +^i 4,11 0 0356 +î " +:i 4,9 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 7,10 0 0361 +ñ " +`o 7,10 0 0362 +ò " +'o 7,10 0 0363 +ó " +^o 7,11 0 0364 +ô " +~o 7,10 0 0365 +õ " +:o 7,9 0 0366 +ö " +di 10,7 0 0367 +÷ " +/o 7,8,1 0 0370 +ø " +`u 7,10 0 0371 +ù " +'u 7,10 0 0372 +ú " +^u 7,11 0 0373 +û " +:u 7,9 0 0374 +ü " +'y 7,10,3 0 0375 +ý " +Tp 7,10,3 0 0376 +þ " +:y 7,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX100/TR b/gnu/usr.bin/groff/devices/devX100/TR new file mode 100644 index 0000000000..eafc811b26 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX100/TR @@ -0,0 +1,306 @@ +name TR +spacewidth 3 +charset +--- 3,1 0 040 +! 5,10 0 041 +" 6,10 0 042 +# 7,10 0 043 +sh " +$ 7,11,1 0 044 +Do " +% 12,10 0 045 +& 11,10 0 046 +' 4,10 0 047 +( 5,10,3 0 050 +) 5,10,3 0 051 +* 7,10 0 052 ++ 8,7 0 053 +, 4,1,2 0 054 +\- 9,4 0 055 +. 4,1 0 056 +/ 4,10,2 0 057 +sl " +0 7,10 0 060 +1 7,10 0 061 +2 7,10 0 062 +3 7,10 0 063 +4 7,10 0 064 +5 7,10 0 065 +6 7,10 0 066 +7 7,10 0 067 +8 7,10 0 070 +9 7,10 0 071 +: 4,7 0 072 +; 4,7,2 0 073 +< 8,7 0 074 += 8,5 0 075 +eq " +> 8,7 0 076 +? 6,10 0 077 +@ 13,10,2 0 0100 +at " +A 11,10 0 0101 +B 9,10 0 0102 +C 10,10 0 0103 +D 10,10 0 0104 +E 9,10 0 0105 +F 8,10 0 0106 +G 11,10 0 0107 +H 10,10 0 0110 +I 5,10 0 0111 +J 6,10 0 0112 +K 10,10 0 0113 +L 9,10 0 0114 +M 13,10 0 0115 +N 11,10 0 0116 +O 10,10 0 0117 +P 8,10 0 0120 +Q 10,10,3 0 0121 +R 9,10 0 0122 +S 8,10 0 0123 +T 9,10 0 0124 +U 10,10 0 0125 +V 9,10 0 0126 +W 13,10 0 0127 +X 10,10 0 0130 +Y 9,10 0 0131 +Z 8,10 0 0132 +[ 5,10,3 0 0133 +lB " +\ 4,10 0 0134 +rs " +] 5,10,3 0 0135 +rB " +^ 7,10 0 0136 +a^ " +ha " +_ 7,0,3 0 0137 +` 4,10 0 0140 +oq " +a 7,7 0 0141 +b 7,10 0 0142 +c 7,7 0 0143 +d 7,10 0 0144 +e 7,7 0 0145 +f 4,10 0 0146 +g 7,7,3 0 0147 +h 7,10 0 0150 +i 3,10 0 0151 +j 4,10,3 0 0152 +k 7,10 0 0153 +l 3,10 0 0154 +m 11,7 0 0155 +n 7,7 0 0156 +o 7,7 0 0157 +p 7,7,3 0 0160 +q 7,7,3 0 0161 +r 5,7 0 0162 +s 6,7 0 0163 +t 4,8 0 0164 +u 7,7 0 0165 +v 7,7 0 0166 +w 11,7 0 0167 +x 7,7 0 0170 +y 7,7,3 0 0171 +z 6,7 0 0172 +{ 7,10,3 0 0173 +lC " +| 3,10 0 0174 +or " +ba " +} 7,10,3 0 0175 +rC " +~ 8,5 0 0176 +a~ " +ap " +ti " +r! 5,7,3 0 0241 +¡ " +ct 7,8,1 0 0242 +¢ " +Po 8,10 0 0243 +£ " +Cs 7,8 0 0244 +¤ " +Ye 7,10 0 0245 +¥ " +bb 3,10 0 0246 +¦ " +sc 7,10,3 0 0247 +§ " +ad 5,10 0 0250 +¨ " +co 12,10 0 0251 +© " +Of 4,10 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 9,6 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 12,10 0 0256 +® " +a- 4,9 0 0257 +¯ " +de 6,10 0 0260 +° " ++- 8,7 0 0261 +± " +S2 4,10 0 0262 +² " +S3 4,10 0 0263 +³ " +aa 5,11 0 0264 +´ " +µ 7,7,3 0 0265 +ps 7,10,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 4,10 0 0271 +¹ " +Om 5,10 0 0272 +º " +Fc 7,6 0 0273 +» " +14 10,10 0 0274 +¼ " +12 10,10 0 0275 +½ " +34 10,10 0 0276 +¾ " +r? 6,7,3 0 0277 +¿ " +`A 11,14 0 0300 +À " +'A 11,14 0 0301 +Á " +^A 11,14 0 0302 +Â " +~A 11,14 0 0303 +Ã " +:A 11,13 0 0304 +Ä " +oA 11,14 0 0305 +Å " +AE 13,10 0 0306 +Æ " +,C 10,10,3 0 0307 +Ç " +`E 9,14 0 0310 +È " +'E 9,14 0 0311 +É " +^E 9,14 0 0312 +Ê " +:E 9,13 0 0313 +Ë " +`I 5,14 0 0314 +Ì " +'I 5,14 0 0315 +Í " +^I 5,14 0 0316 +Î " +:I 5,13 0 0317 +Ï " +-D 10,10 0 0320 +Ð " +~N 11,14 0 0321 +Ñ " +`O 10,14 0 0322 +Ò " +'O 10,14 0 0323 +Ó " +^O 10,14 0 0324 +Ô " +~O 10,14 0 0325 +Õ " +:O 10,13 0 0326 +Ö " +mu 8,7 0 0327 +× " +/O 10,11,1 0 0330 +Ø " +`U 10,14 0 0331 +Ù " +'U 10,14 0 0332 +Ú " +^U 10,14 0 0333 +Û " +:U 10,13 0 0334 +Ü " +'Y 9,14 0 0335 +Ý " +TP 8,10 0 0336 +Þ " +ss 7,10 0 0337 +ß " +`a 7,11 0 0340 +à " +'a 7,11 0 0341 +á " +^a 7,11 0 0342 +â " +~a 7,11 0 0343 +ã " +:a 7,10 0 0344 +ä " +oa 7,11 0 0345 +å " +ae 11,7 0 0346 +æ " +,c 7,7,3 0 0347 +ç " +`e 7,11 0 0350 +è " +'e 7,11 0 0351 +é " +^e 7,11 0 0352 +ê " +:e 7,10 0 0353 +ë " +`i 3,11 0 0354 +ì " +'i 3,11 0 0355 +í " +^i 3,11 0 0356 +î " +:i 3,10 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 7,11 0 0361 +ñ " +`o 7,11 0 0362 +ò " +'o 7,11 0 0363 +ó " +^o 7,11 0 0364 +ô " +~o 7,11 0 0365 +õ " +:o 7,10 0 0366 +ö " +di 8,7 0 0367 +÷ " +/o 7,8,1 0 0370 +ø " +`u 7,11 0 0371 +ù " +'u 7,11 0 0372 +ú " +^u 7,11 0 0373 +û " +:u 7,10 0 0374 +ü " +'y 7,11,3 0 0375 +ý " +Tp 7,10,3 0 0376 +þ " +:y 7,10,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/CB b/gnu/usr.bin/groff/devices/devX75-12/CB new file mode 100644 index 0000000000..a5d1baff22 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/CB @@ -0,0 +1,306 @@ +name CB +spacewidth 7 +charset +--- 7,1 0 040 +! 7,9 0 041 +" 7,8 0 042 +# 7,8 0 043 +sh " +$ 7,10,2 0 044 +Do " +% 7,8 0 045 +& 7,8 0 046 +' 7,8 0 047 +( 7,9,2 0 050 +) 7,9,2 0 051 +* 7,9 0 052 ++ 7,6 0 053 +, 7,2,1 0 054 +\- 7,4 0 055 +. 7,2 0 056 +/ 7,8,2 0 057 +sl " +0 7,9 0 060 +1 7,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 7,6 0 072 +; 7,6,1 0 073 +< 7,7 0 074 += 7,5 0 075 +eq " +> 7,7 0 076 +? 7,8 0 077 +@ 7,8 0 0100 +at " +A 7,8 0 0101 +B 7,8 0 0102 +C 7,8 0 0103 +D 7,8 0 0104 +E 7,8 0 0105 +F 7,8 0 0106 +G 7,8 0 0107 +H 7,8 0 0110 +I 7,8 0 0111 +J 7,8 0 0112 +K 7,8 0 0113 +L 7,8 0 0114 +M 7,8 0 0115 +N 7,8 0 0116 +O 7,8 0 0117 +P 7,8 0 0120 +Q 7,8,2 0 0121 +R 7,8 0 0122 +S 7,8 0 0123 +T 7,8 0 0124 +U 7,8 0 0125 +V 7,8 0 0126 +W 7,8 0 0127 +X 7,8 0 0130 +Y 7,8 0 0131 +Z 7,8 0 0132 +[ 7,9,2 0 0133 +lB " +\ 7,8,2 0 0134 +rs " +] 7,9,2 0 0135 +rB " +^ 7,8 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 7,8 0 0140 +oq " +a 7,6 0 0141 +b 7,9 0 0142 +c 7,6 0 0143 +d 7,9 0 0144 +e 7,6 0 0145 +f 7,9 0 0146 +g 7,6,3 0 0147 +h 7,9 0 0150 +i 7,9 0 0151 +j 7,9,3 0 0152 +k 7,9 0 0153 +l 7,9 0 0154 +m 7,6 0 0155 +n 7,6 0 0156 +o 7,6 0 0157 +p 7,6,3 0 0160 +q 7,6,3 0 0161 +r 7,6 0 0162 +s 7,6 0 0163 +t 7,8 0 0164 +u 7,6 0 0165 +v 7,6 0 0166 +w 7,6 0 0167 +x 7,6 0 0170 +y 7,6,3 0 0171 +z 7,6 0 0172 +{ 7,9,2 0 0173 +lC " +| 7,8,2 0 0174 +or " +ba " +} 7,9,2 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 7,6,3 0 0241 +¡ " +ct 7,8,1 0 0242 +¢ " +Po 7,8 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 7,8 0 0245 +¥ " +bb 7,8,2 0 0246 +¦ " +sc 7,9,1 0 0247 +§ " +ad 7,9 0 0250 +¨ " +co 7,8 0 0251 +© " +Of 7,9 0 0252 +ª " +Fo 7,5 0 0253 +« " +no 7,5 0 0254 +¬ " +- 7,4 0 0255 +hy " +­ " +rg 7,8 0 0256 +® " +a- 7,8 0 0257 +¯ " +de 7,8 0 0260 +° " ++- 7,6 0 0261 +± " +S2 7,8 0 0262 +² " +S3 7,8 0 0263 +³ " +aa 7,9 0 0264 +´ " +µ 7,6,3 0 0265 +ps 7,9,1 0 0266 +¶ " +md 7,5 0 0267 +· " +ac 7,0,3 0 0270 +¸ " +S1 7,8 0 0271 +¹ " +Om 7,9 0 0272 +º " +Fc 7,5 0 0273 +» " +14 7,9,1 0 0274 +¼ " +12 7,9,1 0 0275 +½ " +34 7,9,1 0 0276 +¾ " +r? 7,6,3 0 0277 +¿ " +`A 7,11 0 0300 +À " +'A 7,11 0 0301 +Á " +^A 7,11 0 0302 +Â " +~A 7,11 0 0303 +Ã " +:A 7,10 0 0304 +Ä " +oA 7,11 0 0305 +Å " +AE 7,8 0 0306 +Æ " +,C 7,8,3 0 0307 +Ç " +`E 7,11 0 0310 +È " +'E 7,11 0 0311 +É " +^E 7,11 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 7,11 0 0314 +Ì " +'I 7,11 0 0315 +Í " +^I 7,11 0 0316 +Î " +:I 7,10 0 0317 +Ï " +-D 7,8 0 0320 +Ð " +~N 7,11 0 0321 +Ñ " +`O 7,11 0 0322 +Ò " +'O 7,11 0 0323 +Ó " +^O 7,11 0 0324 +Ô " +~O 7,11 0 0325 +Õ " +:O 7,10 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 7,8 0 0330 +Ø " +`U 7,11 0 0331 +Ù " +'U 7,11 0 0332 +Ú " +^U 7,11 0 0333 +Û " +:U 7,10 0 0334 +Ü " +'Y 7,11 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 7,9 0 0337 +ß " +`a 7,9 0 0340 +à " +'a 7,9 0 0341 +á " +^a 7,9 0 0342 +â " +~a 7,9 0 0343 +ã " +:a 7,8 0 0344 +ä " +oa 7,10 0 0345 +å " +ae 7,6 0 0346 +æ " +,c 7,6,3 0 0347 +ç " +`e 7,9 0 0350 +è " +'e 7,9 0 0351 +é " +^e 7,9 0 0352 +ê " +:e 7,8 0 0353 +ë " +`i 7,9 0 0354 +ì " +'i 7,9 0 0355 +í " +^i 7,9 0 0356 +î " +:i 7,8 0 0357 +ï " +Sd 7,9 0 0360 +ð " +~n 7,9 0 0361 +ñ " +`o 7,9 0 0362 +ò " +'o 7,9 0 0363 +ó " +^o 7,9 0 0364 +ô " +~o 7,9 0 0365 +õ " +:o 7,8 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 7,7,1 0 0370 +ø " +`u 7,9 0 0371 +ù " +'u 7,9 0 0372 +ú " +^u 7,9 0 0373 +û " +:u 7,8 0 0374 +ü " +'y 7,9,3 0 0375 +ý " +Tp 7,8,3 0 0376 +þ " +:y 7,8,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/CBI b/gnu/usr.bin/groff/devices/devX75-12/CBI new file mode 100644 index 0000000000..764eaf7784 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/CBI @@ -0,0 +1,306 @@ +name CBI +spacewidth 7 +charset +--- 7,1 0 040 +! 7,9 0 041 +" 7,8 0 042 +# 7,9 0 043 +sh " +$ 7,10,2 0 044 +Do " +% 7,8 0 045 +& 7,8 0 046 +' 7,8 0 047 +( 7,9,2 0 050 +) 7,9,2 0 051 +* 7,8 0 052 ++ 7,6 0 053 +, 7,2,1 0 054 +\- 7,4 0 055 +. 7,2 0 056 +/ 7,9,1 0 057 +sl " +0 7,9 0 060 +1 7,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 7,6 0 072 +; 7,6,1 0 073 +< 7,6 0 074 += 7,5 0 075 +eq " +> 7,6 0 076 +? 7,8 0 077 +@ 7,8,1 0 0100 +at " +A 7,8 0 0101 +B 7,8 0 0102 +C 7,8 0 0103 +D 7,8 0 0104 +E 7,8 0 0105 +F 7,8 0 0106 +G 7,8 0 0107 +H 7,8 0 0110 +I 7,8 0 0111 +J 7,8 0 0112 +K 7,8 0 0113 +L 7,8 0 0114 +M 7,8 0 0115 +N 7,8 0 0116 +O 7,8 0 0117 +P 7,8 0 0120 +Q 7,8,2 0 0121 +R 7,8 0 0122 +S 7,8 0 0123 +T 7,8 0 0124 +U 7,8 0 0125 +V 7,8 0 0126 +W 7,8 0 0127 +X 7,8 0 0130 +Y 7,8 0 0131 +Z 7,8 0 0132 +[ 7,9,2 0 0133 +lB " +\ 7,9,1 0 0134 +rs " +] 7,9,2 0 0135 +rB " +^ 7,8 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 7,8 0 0140 +oq " +a 7,6 0 0141 +b 7,9 0 0142 +c 7,6 0 0143 +d 7,9 0 0144 +e 7,6 0 0145 +f 7,9 0 0146 +g 7,6,3 0 0147 +h 7,9 0 0150 +i 7,9 0 0151 +j 7,9,3 0 0152 +k 7,9 0 0153 +l 7,9 0 0154 +m 7,6 0 0155 +n 7,6 0 0156 +o 7,6 0 0157 +p 7,6,3 0 0160 +q 7,6,3 0 0161 +r 7,6 0 0162 +s 7,6 0 0163 +t 7,8 0 0164 +u 7,6 0 0165 +v 7,6 0 0166 +w 7,6 0 0167 +x 7,6 0 0170 +y 7,6,3 0 0171 +z 7,6 0 0172 +{ 7,9,2 0 0173 +lC " +| 7,8,1 0 0174 +or " +ba " +} 7,9,2 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 7,6,2 0 0241 +¡ " +ct 7,8,1 0 0242 +¢ " +Po 7,8 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 7,8 0 0245 +¥ " +bb 7,8,1 0 0246 +¦ " +sc 7,9,1 0 0247 +§ " +ad 7,9 0 0250 +¨ " +co 7,8 0 0251 +© " +Of 7,8 0 0252 +ª " +Fo 7,5 0 0253 +« " +no 7,5 0 0254 +¬ " +- 7,4 0 0255 +hy " +­ " +rg 7,8 0 0256 +® " +a- 7,8 0 0257 +¯ " +de 7,8 0 0260 +° " ++- 7,6 0 0261 +± " +S2 7,8 0 0262 +² " +S3 7,8 0 0263 +³ " +aa 7,9 0 0264 +´ " +µ 7,6,3 0 0265 +ps 7,9,1 0 0266 +¶ " +md 7,5 0 0267 +· " +ac 7,0,3 0 0270 +¸ " +S1 7,8 0 0271 +¹ " +Om 7,8 0 0272 +º " +Fc 7,5 0 0273 +» " +14 7,9 0 0274 +¼ " +12 7,9 0 0275 +½ " +34 7,9 0 0276 +¾ " +r? 7,6,2 0 0277 +¿ " +`A 7,11 0 0300 +À " +'A 7,11 0 0301 +Á " +^A 7,11 0 0302 +Â " +~A 7,11 0 0303 +Ã " +:A 7,10 0 0304 +Ä " +oA 7,11 0 0305 +Å " +AE 7,8 0 0306 +Æ " +,C 7,8,3 0 0307 +Ç " +`E 7,11 0 0310 +È " +'E 7,11 0 0311 +É " +^E 7,11 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 7,11 0 0314 +Ì " +'I 7,11 0 0315 +Í " +^I 7,11 0 0316 +Î " +:I 7,10 0 0317 +Ï " +-D 7,8 0 0320 +Ð " +~N 7,11 0 0321 +Ñ " +`O 7,11 0 0322 +Ò " +'O 7,11 0 0323 +Ó " +^O 7,11 0 0324 +Ô " +~O 7,11 0 0325 +Õ " +:O 7,10 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 7,8 0 0330 +Ø " +`U 7,11 0 0331 +Ù " +'U 7,11 0 0332 +Ú " +^U 7,11 0 0333 +Û " +:U 7,10 0 0334 +Ü " +'Y 7,11 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 7,8 0 0337 +ß " +`a 7,9 0 0340 +à " +'a 7,9 0 0341 +á " +^a 7,9 0 0342 +â " +~a 7,9 0 0343 +ã " +:a 7,8 0 0344 +ä " +oa 7,10 0 0345 +å " +ae 7,6 0 0346 +æ " +,c 7,6,3 0 0347 +ç " +`e 7,9 0 0350 +è " +'e 7,9 0 0351 +é " +^e 7,9 0 0352 +ê " +:e 7,8 0 0353 +ë " +`i 7,9 0 0354 +ì " +'i 7,9 0 0355 +í " +^i 7,9 0 0356 +î " +:i 7,8 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 7,9 0 0361 +ñ " +`o 7,9 0 0362 +ò " +'o 7,9 0 0363 +ó " +^o 7,9 0 0364 +ô " +~o 7,9 0 0365 +õ " +:o 7,8 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 7,7,1 0 0370 +ø " +`u 7,9 0 0371 +ù " +'u 7,9 0 0372 +ú " +^u 7,9 0 0373 +û " +:u 7,8 0 0374 +ü " +'y 7,9,3 0 0375 +ý " +Tp 7,8,3 0 0376 +þ " +:y 7,8,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/CI b/gnu/usr.bin/groff/devices/devX75-12/CI new file mode 100644 index 0000000000..acc9ec8647 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/CI @@ -0,0 +1,306 @@ +name CI +spacewidth 7 +charset +--- 7,1 0 040 +! 7,8 0 041 +" 7,8 0 042 +# 7,8 0 043 +sh " +$ 7,10,1 0 044 +Do " +% 7,8 0 045 +& 7,8 0 046 +' 7,8 0 047 +( 7,9,2 0 050 +) 7,9,2 0 051 +* 7,8 0 052 ++ 7,6 0 053 +, 7,2,1 0 054 +\- 7,4 0 055 +. 7,1 0 056 +/ 7,8,1 0 057 +sl " +0 7,9 0 060 +1 7,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 7,5 0 072 +; 7,5,1 0 073 +< 7,7 0 074 += 7,5 0 075 +eq " +> 7,7 0 076 +? 7,8 0 077 +@ 7,8 0 0100 +at " +A 7,8 0 0101 +B 7,8 0 0102 +C 7,8 0 0103 +D 7,8 0 0104 +E 7,8 0 0105 +F 7,8 0 0106 +G 7,8 0 0107 +H 7,8 0 0110 +I 7,8 0 0111 +J 7,8 0 0112 +K 7,8 0 0113 +L 7,8 0 0114 +M 7,8 0 0115 +N 7,8 0 0116 +O 7,8 0 0117 +P 7,8 0 0120 +Q 7,8,2 0 0121 +R 7,8 0 0122 +S 7,8 0 0123 +T 7,8 0 0124 +U 7,8 0 0125 +V 7,8 0 0126 +W 7,8 0 0127 +X 7,8 0 0130 +Y 7,8 0 0131 +Z 7,8 0 0132 +[ 7,9,2 0 0133 +lB " +\ 7,8,1 0 0134 +rs " +] 7,9,2 0 0135 +rB " +^ 7,8 0 0136 +a^ " +ha " +_ 7,0,3 0 0137 +` 7,8 0 0140 +oq " +a 7,6 0 0141 +b 7,9 0 0142 +c 7,6 0 0143 +d 7,9 0 0144 +e 7,6 0 0145 +f 7,9 0 0146 +g 7,6,3 0 0147 +h 7,9 0 0150 +i 7,9 0 0151 +j 7,9,3 0 0152 +k 7,9 0 0153 +l 7,9 0 0154 +m 7,6 0 0155 +n 7,6 0 0156 +o 7,6 0 0157 +p 7,6,3 0 0160 +q 7,6,3 0 0161 +r 7,6 0 0162 +s 7,6 0 0163 +t 7,8 0 0164 +u 7,6 0 0165 +v 7,6 0 0166 +w 7,6 0 0167 +x 7,6 0 0170 +y 7,6,3 0 0171 +z 7,6 0 0172 +{ 7,9,2 0 0173 +lC " +| 7,8,1 0 0174 +or " +ba " +} 7,9,2 0 0175 +rC " +~ 7,4 0 0176 +a~ " +ap " +ti " +r! 7,6,3 0 0241 +¡ " +ct 7,8,1 0 0242 +¢ " +Po 7,8 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 7,8 0 0245 +¥ " +bb 7,8,2 0 0246 +¦ " +sc 7,9,1 0 0247 +§ " +ad 7,8 0 0250 +¨ " +co 7,8 0 0251 +© " +Of 7,8 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 7,5 0 0254 +¬ " +- 7,4 0 0255 +hy " +­ " +rg 7,8 0 0256 +® " +a- 7,8 0 0257 +¯ " +de 7,8 0 0260 +° " ++- 7,6 0 0261 +± " +S2 7,8 0 0262 +² " +S3 7,8 0 0263 +³ " +aa 7,9 0 0264 +´ " +µ 7,6,3 0 0265 +ps 7,9,1 0 0266 +¶ " +md 7,4 0 0267 +· " +ac 7,0,3 0 0270 +¸ " +S1 7,8 0 0271 +¹ " +Om 7,8 0 0272 +º " +Fc 7,6 0 0273 +» " +14 7,9,1 0 0274 +¼ " +12 7,9,1 0 0275 +½ " +34 7,9,1 0 0276 +¾ " +r? 7,6,2 0 0277 +¿ " +`A 7,11 0 0300 +À " +'A 7,11 0 0301 +Á " +^A 7,11 0 0302 +Â " +~A 7,11 0 0303 +Ã " +:A 7,10 0 0304 +Ä " +oA 7,11 0 0305 +Å " +AE 7,8 0 0306 +Æ " +,C 7,8,3 0 0307 +Ç " +`E 7,11 0 0310 +È " +'E 7,11 0 0311 +É " +^E 7,11 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 7,11 0 0314 +Ì " +'I 7,11 0 0315 +Í " +^I 7,11 0 0316 +Î " +:I 7,10 0 0317 +Ï " +-D 7,8 0 0320 +Ð " +~N 7,11 0 0321 +Ñ " +`O 7,11 0 0322 +Ò " +'O 7,11 0 0323 +Ó " +^O 7,11 0 0324 +Ô " +~O 7,11 0 0325 +Õ " +:O 7,10 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 7,8 0 0330 +Ø " +`U 7,11 0 0331 +Ù " +'U 7,11 0 0332 +Ú " +^U 7,11 0 0333 +Û " +:U 7,10 0 0334 +Ü " +'Y 7,11 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 7,9 0 0337 +ß " +`a 7,9 0 0340 +à " +'a 7,9 0 0341 +á " +^a 7,9 0 0342 +â " +~a 7,9 0 0343 +ã " +:a 7,8 0 0344 +ä " +oa 7,10 0 0345 +å " +ae 7,6 0 0346 +æ " +,c 7,6,3 0 0347 +ç " +`e 7,9 0 0350 +è " +'e 7,9 0 0351 +é " +^e 7,9 0 0352 +ê " +:e 7,8 0 0353 +ë " +`i 7,9 0 0354 +ì " +'i 7,9 0 0355 +í " +^i 7,9 0 0356 +î " +:i 7,8 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 7,9 0 0361 +ñ " +`o 7,9 0 0362 +ò " +'o 7,9 0 0363 +ó " +^o 7,9 0 0364 +ô " +~o 7,9 0 0365 +õ " +:o 7,8 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 7,7,1 0 0370 +ø " +`u 7,9 0 0371 +ù " +'u 7,9 0 0372 +ú " +^u 7,9 0 0373 +û " +:u 7,8 0 0374 +ü " +'y 7,9,3 0 0375 +ý " +Tp 7,9,3 0 0376 +þ " +:y 7,8,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/CR b/gnu/usr.bin/groff/devices/devX75-12/CR new file mode 100644 index 0000000000..666e837b43 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/CR @@ -0,0 +1,306 @@ +name CR +spacewidth 7 +charset +--- 7,1 0 040 +! 7,9 0 041 +" 7,8 0 042 +# 7,8 0 043 +sh " +$ 7,9,1 0 044 +Do " +% 7,8 0 045 +& 7,8 0 046 +' 7,8 0 047 +( 7,9,2 0 050 +) 7,9,2 0 051 +* 7,8 0 052 ++ 7,6 0 053 +, 7,2,1 0 054 +\- 7,4 0 055 +. 7,1 0 056 +/ 7,9,1 0 057 +sl " +0 7,9 0 060 +1 7,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 7,5 0 072 +; 7,5,1 0 073 +< 7,7 0 074 += 7,5 0 075 +eq " +> 7,7 0 076 +? 7,8 0 077 +@ 7,8 0 0100 +at " +A 7,8 0 0101 +B 7,8 0 0102 +C 7,8 0 0103 +D 7,8 0 0104 +E 7,8 0 0105 +F 7,8 0 0106 +G 7,8 0 0107 +H 7,8 0 0110 +I 7,8 0 0111 +J 7,8 0 0112 +K 7,8 0 0113 +L 7,8 0 0114 +M 7,8 0 0115 +N 7,8 0 0116 +O 7,8 0 0117 +P 7,8 0 0120 +Q 7,8,1 0 0121 +R 7,8 0 0122 +S 7,8 0 0123 +T 7,8 0 0124 +U 7,8 0 0125 +V 7,8 0 0126 +W 7,8 0 0127 +X 7,8 0 0130 +Y 7,8 0 0131 +Z 7,8 0 0132 +[ 7,9,2 0 0133 +lB " +\ 7,9,1 0 0134 +rs " +] 7,9,2 0 0135 +rB " +^ 7,8 0 0136 +a^ " +ha " +_ 7,0,3 0 0137 +` 7,8 0 0140 +oq " +a 7,6 0 0141 +b 7,9 0 0142 +c 7,6 0 0143 +d 7,9 0 0144 +e 7,6 0 0145 +f 7,9 0 0146 +g 7,6,3 0 0147 +h 7,9 0 0150 +i 7,9 0 0151 +j 7,9,3 0 0152 +k 7,9 0 0153 +l 7,9 0 0154 +m 7,6 0 0155 +n 7,6 0 0156 +o 7,6 0 0157 +p 7,6,3 0 0160 +q 7,6,3 0 0161 +r 7,6 0 0162 +s 7,6 0 0163 +t 7,8 0 0164 +u 7,6 0 0165 +v 7,6 0 0166 +w 7,6 0 0167 +x 7,6 0 0170 +y 7,6,3 0 0171 +z 7,6 0 0172 +{ 7,8,2 0 0173 +lC " +| 7,8,2 0 0174 +or " +ba " +} 7,8,2 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 7,6,3 0 0241 +¡ " +ct 7,8,1 0 0242 +¢ " +Po 7,8 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 7,8 0 0245 +¥ " +bb 7,8,2 0 0246 +¦ " +sc 7,9,1 0 0247 +§ " +ad 7,8 0 0250 +¨ " +co 7,8 0 0251 +© " +Of 7,8 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 7,5 0 0254 +¬ " +- 7,4 0 0255 +hy " +­ " +rg 7,8 0 0256 +® " +a- 7,8 0 0257 +¯ " +de 7,8 0 0260 +° " ++- 7,6 0 0261 +± " +S2 7,8 0 0262 +² " +S3 7,8 0 0263 +³ " +aa 7,9 0 0264 +´ " +µ 7,6,3 0 0265 +ps 7,9,1 0 0266 +¶ " +md 7,4 0 0267 +· " +ac 7,0,3 0 0270 +¸ " +S1 7,8 0 0271 +¹ " +Om 7,8 0 0272 +º " +Fc 7,6 0 0273 +» " +14 7,9,1 0 0274 +¼ " +12 7,9,1 0 0275 +½ " +34 7,9,1 0 0276 +¾ " +r? 7,6,2 0 0277 +¿ " +`A 7,11 0 0300 +À " +'A 7,11 0 0301 +Á " +^A 7,11 0 0302 +Â " +~A 7,11 0 0303 +Ã " +:A 7,10 0 0304 +Ä " +oA 7,11 0 0305 +Å " +AE 7,8 0 0306 +Æ " +,C 7,8,3 0 0307 +Ç " +`E 7,11 0 0310 +È " +'E 7,11 0 0311 +É " +^E 7,11 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 7,11 0 0314 +Ì " +'I 7,11 0 0315 +Í " +^I 7,11 0 0316 +Î " +:I 7,10 0 0317 +Ï " +-D 7,8 0 0320 +Ð " +~N 7,11 0 0321 +Ñ " +`O 7,11 0 0322 +Ò " +'O 7,11 0 0323 +Ó " +^O 7,11 0 0324 +Ô " +~O 7,11 0 0325 +Õ " +:O 7,10 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 7,9,1 0 0330 +Ø " +`U 7,11 0 0331 +Ù " +'U 7,11 0 0332 +Ú " +^U 7,11 0 0333 +Û " +:U 7,10 0 0334 +Ü " +'Y 7,11 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 7,9 0 0337 +ß " +`a 7,9 0 0340 +à " +'a 7,9 0 0341 +á " +^a 7,9 0 0342 +â " +~a 7,9 0 0343 +ã " +:a 7,8 0 0344 +ä " +oa 7,9 0 0345 +å " +ae 7,6 0 0346 +æ " +,c 7,6,3 0 0347 +ç " +`e 7,9 0 0350 +è " +'e 7,9 0 0351 +é " +^e 7,9 0 0352 +ê " +:e 7,8 0 0353 +ë " +`i 7,9 0 0354 +ì " +'i 7,9 0 0355 +í " +^i 7,9 0 0356 +î " +:i 7,8 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 7,9 0 0361 +ñ " +`o 7,9 0 0362 +ò " +'o 7,9 0 0363 +ó " +^o 7,9 0 0364 +ô " +~o 7,9 0 0365 +õ " +:o 7,8 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 7,7,1 0 0370 +ø " +`u 7,9 0 0371 +ù " +'u 7,9 0 0372 +ú " +^u 7,9 0 0373 +û " +:u 7,8 0 0374 +ü " +'y 7,9,3 0 0375 +ý " +Tp 7,9,3 0 0376 +þ " +:y 7,8,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/DESC b/gnu/usr.bin/groff/devices/devX75-12/DESC new file mode 100644 index 0000000000..4793e599e0 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/DESC @@ -0,0 +1,9 @@ +styles R I B BI +fonts 6 0 0 0 0 0 S +sizes 8 10 12 14 18 24 0 +res 75 +X11 +hor 1 +vert 1 +unitwidth 12 +postpro gxditview diff --git a/gnu/usr.bin/groff/devices/devX75-12/HB b/gnu/usr.bin/groff/devices/devX75-12/HB new file mode 100644 index 0000000000..b8cbb6ef55 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/HB @@ -0,0 +1,306 @@ +name HB +spacewidth 4 +charset +--- 4,1 0 040 +! 4,9 0 041 +" 5,9 0 042 +# 8,8 0 043 +sh " +$ 7,9,2 0 044 +Do " +% 12,9 0 045 +& 9,9 0 046 +' 4,9 0 047 +( 6,9,3 0 050 +) 6,9,3 0 051 +* 6,9 0 052 ++ 7,6 0 053 +, 4,2,2 0 054 +\- 8,4 0 055 +. 4,2 0 056 +/ 4,9 0 057 +sl " +0 7,9 0 060 +1 7,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 4,7 0 072 +; 4,7,2 0 073 +< 7,6 0 074 += 7,5 0 075 +eq " +> 7,6 0 076 +? 8,9 0 077 +@ 12,9,1 0 0100 +at " +A 8,9 0 0101 +B 9,9 0 0102 +C 8,9 0 0103 +D 9,9 0 0104 +E 8,9 0 0105 +F 7,9 0 0106 +G 10,9 0 0107 +H 9,9 0 0110 +I 4,9 0 0111 +J 7,9 0 0112 +K 9,9 0 0113 +L 7,9 0 0114 +M 11,9 0 0115 +N 9,9 0 0116 +O 10,9 0 0117 +P 8,9 0 0120 +Q 10,9 0 0121 +R 9,9 0 0122 +S 9,9 0 0123 +T 8,9 0 0124 +U 9,9 0 0125 +V 8,9 0 0126 +W 10,9 0 0127 +X 8,9 0 0130 +Y 8,9 0 0131 +Z 7,9 0 0132 +[ 4,9,3 0 0133 +lB " +\ 4,9 0 0134 +rs " +] 4,9,3 0 0135 +rB " +^ 7,9 0 0136 +a^ " +ha " +_ 7,0,3 0 0137 +` 4,9 0 0140 +oq " +a 7,7 0 0141 +b 7,9 0 0142 +c 7,7 0 0143 +d 7,9 0 0144 +e 7,7 0 0145 +f 5,9 0 0146 +g 7,7,3 0 0147 +h 7,9 0 0150 +i 3,9 0 0151 +j 3,9,3 0 0152 +k 7,9 0 0153 +l 3,9 0 0154 +m 11,7 0 0155 +n 7,7 0 0156 +o 7,7 0 0157 +p 7,7,3 0 0160 +q 7,7,3 0 0161 +r 5,7 0 0162 +s 7,7 0 0163 +t 5,9 0 0164 +u 7,7 0 0165 +v 8,7 0 0166 +w 11,7 0 0167 +x 7,7 0 0170 +y 8,7,3 0 0171 +z 6,7 0 0172 +{ 5,9,3 0 0173 +lC " +| 4,9,3 0 0174 +or " +ba " +} 5,9,3 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 4,7,3 0 0241 +¡ " +ct 7,8,1 0 0242 +¢ " +Po 7,9 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 7,9 0 0245 +¥ " +bb 4,9,2 0 0246 +¦ " +sc 7,9,3 0 0247 +§ " +ad 5,9 0 0250 +¨ " +co 11,9 0 0251 +© " +Of 6,9 0 0252 +ª " +Fo 8,6 0 0253 +« " +no 8,6 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 4,9 0 0257 +¯ " +de 5,8 0 0260 +° " ++- 7,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 4,10 0 0264 +´ " +µ 7,7,3 0 0265 +ps 7,9,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 4,1,3 0 0270 +¸ " +S1 4,9 0 0271 +¹ " +Om 6,9 0 0272 +º " +Fc 8,6 0 0273 +» " +14 10,9 0 0274 +¼ " +12 10,9 0 0275 +½ " +34 10,9 0 0276 +¾ " +r? 8,7,3 0 0277 +¿ " +`A 8,12 0 0300 +À " +'A 8,12 0 0301 +Á " +^A 8,12 0 0302 +Â " +~A 8,12 0 0303 +Ã " +:A 8,11 0 0304 +Ä " +oA 8,12 0 0305 +Å " +AE 13,9 0 0306 +Æ " +,C 8,9,3 0 0307 +Ç " +`E 8,12 0 0310 +È " +'E 8,12 0 0311 +É " +^E 8,12 0 0312 +Ê " +:E 8,11 0 0313 +Ë " +`I 4,12 0 0314 +Ì " +'I 4,12 0 0315 +Í " +^I 4,12 0 0316 +Î " +:I 4,11 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 9,12 0 0321 +Ñ " +`O 10,12 0 0322 +Ò " +'O 10,12 0 0323 +Ó " +^O 10,12 0 0324 +Ô " +~O 10,12 0 0325 +Õ " +:O 10,11 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 10,9,1 0 0330 +Ø " +`U 9,12 0 0331 +Ù " +'U 9,12 0 0332 +Ú " +^U 9,12 0 0333 +Û " +:U 9,11 0 0334 +Ü " +'Y 8,12 0 0335 +Ý " +TP 8,9 0 0336 +Þ " +ss 8,9 0 0337 +ß " +`a 7,10 0 0340 +à " +'a 7,10 0 0341 +á " +^a 7,10 0 0342 +â " +~a 7,10 0 0343 +ã " +:a 7,9 0 0344 +ä " +oa 7,11 0 0345 +å " +ae 11,7 0 0346 +æ " +,c 7,7,3 0 0347 +ç " +`e 7,10 0 0350 +è " +'e 7,10 0 0351 +é " +^e 7,10 0 0352 +ê " +:e 7,9 0 0353 +ë " +`i 3,10 0 0354 +ì " +'i 3,10 0 0355 +í " +^i 3,10 0 0356 +î " +:i 3,9 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 7,10 0 0361 +ñ " +`o 7,10 0 0362 +ò " +'o 7,10 0 0363 +ó " +^o 7,10 0 0364 +ô " +~o 7,10 0 0365 +õ " +:o 7,9 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 7,7 0 0370 +ø " +`u 7,10 0 0371 +ù " +'u 7,10 0 0372 +ú " +^u 7,10 0 0373 +û " +:u 7,9 0 0374 +ü " +'y 8,10,3 0 0375 +ý " +Tp 7,9,3 0 0376 +þ " +:y 8,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/HBI b/gnu/usr.bin/groff/devices/devX75-12/HBI new file mode 100644 index 0000000000..3014c9027d --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/HBI @@ -0,0 +1,306 @@ +name HBI +spacewidth 4 +charset +--- 4,1 0 040 +! 4,9 0 041 +" 6,9 0 042 +# 7,8 0 043 +sh " +$ 7,9,1 0 044 +Do " +% 13,9 0 045 +& 9,9 0 046 +' 4,9 0 047 +( 5,9,3 0 050 +) 5,9,3 0 051 +* 6,9 0 052 ++ 8,6 0 053 +, 3,2,2 0 054 +\- 8,4 0 055 +. 3,2 0 056 +/ 5,9 0 057 +sl " +0 7,9 0 060 +1 7,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 4,7 0 072 +; 4,7,2 0 073 +< 7,6 0 074 += 7,5 0 075 +eq " +> 7,6 0 076 +? 8,9 0 077 +@ 11,9,1 0 0100 +at " +A 8,9 0 0101 +B 9,9 0 0102 +C 8,9 0 0103 +D 9,9 0 0104 +E 8,9 0 0105 +F 7,9 0 0106 +G 9,9 0 0107 +H 10,9 0 0110 +I 5,9 0 0111 +J 7,9 0 0112 +K 9,9 0 0113 +L 7,9 0 0114 +M 12,9 0 0115 +N 10,9 0 0116 +O 9,9 0 0117 +P 8,9 0 0120 +Q 9,9 0 0121 +R 9,9 0 0122 +S 8,9 0 0123 +T 7,9 0 0124 +U 8,9 0 0125 +V 9,9 0 0126 +W 10,9 0 0127 +X 9,9 0 0130 +Y 7,9 0 0131 +Z 7,9 0 0132 +[ 4,9,3 0 0133 +lB " +\ 5,9 0 0134 +rs " +] 4,9,3 0 0135 +rB " +^ 6,9 0 0136 +a^ " +ha " +_ 7,0,3 0 0137 +` 4,9 0 0140 +oq " +a 6,7 0 0141 +b 7,9 0 0142 +c 7,7 0 0143 +d 7,9 0 0144 +e 7,7 0 0145 +f 5,9 0 0146 +g 7,7,3 0 0147 +h 7,9 0 0150 +i 3,9 0 0151 +j 3,9,3 0 0152 +k 7,9 0 0153 +l 3,9 0 0154 +m 11,7 0 0155 +n 7,7 0 0156 +o 7,7 0 0157 +p 7,7,3 0 0160 +q 7,7,3 0 0161 +r 5,7 0 0162 +s 7,7 0 0163 +t 5,9 0 0164 +u 7,7 0 0165 +v 7,7 0 0166 +w 10,7 0 0167 +x 7,7 0 0170 +y 7,7,3 0 0171 +z 6,7 0 0172 +{ 5,9,3 0 0173 +lC " +| 4,9,3 0 0174 +or " +ba " +} 5,9,3 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 4,7,3 0 0241 +¡ " +ct 7,8,1 0 0242 +¢ " +Po 7,9 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 7,9 0 0245 +¥ " +bb 4,9,2 0 0246 +¦ " +sc 7,9,3 0 0247 +§ " +ad 5,9 0 0250 +¨ " +co 11,9 0 0251 +© " +Of 6,9 0 0252 +ª " +Fo 10,6 0 0253 +« " +no 8,5 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 4,9 0 0257 +¯ " +de 5,8 0 0260 +° " ++- 8,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 4,9 0 0264 +´ " +µ 7,7,3 0 0265 +ps 7,9,3 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 4,1,3 0 0270 +¸ " +S1 4,9 0 0271 +¹ " +Om 6,9 0 0272 +º " +Fc 10,6 0 0273 +» " +14 10,9 0 0274 +¼ " +12 10,9 0 0275 +½ " +34 10,9 0 0276 +¾ " +r? 7,7,2 0 0277 +¿ " +`A 8,12 0 0300 +À " +'A 8,12 0 0301 +Á " +^A 8,12 0 0302 +Â " +~A 8,12 0 0303 +Ã " +:A 8,11 0 0304 +Ä " +oA 8,12 0 0305 +Å " +AE 11,9 0 0306 +Æ " +,C 8,9,3 0 0307 +Ç " +`E 8,12 0 0310 +È " +'E 8,12 0 0311 +É " +^E 8,12 0 0312 +Ê " +:E 8,11 0 0313 +Ë " +`I 5,12 0 0314 +Ì " +'I 5,12 0 0315 +Í " +^I 5,12 0 0316 +Î " +:I 5,11 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 10,12 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,11 0 0326 +Ö " +mu 8,6 0 0327 +× " +/O 9,9 0 0330 +Ø " +`U 8,12 0 0331 +Ù " +'U 8,12 0 0332 +Ú " +^U 8,12 0 0333 +Û " +:U 8,11 0 0334 +Ü " +'Y 7,12 0 0335 +Ý " +TP 8,9 0 0336 +Þ " +ss 7,9 0 0337 +ß " +`a 6,10 0 0340 +à " +'a 6,10 0 0341 +á " +^a 6,10 0 0342 +â " +~a 6,10 0 0343 +ã " +:a 6,9 0 0344 +ä " +oa 6,10 0 0345 +å " +ae 10,7 0 0346 +æ " +,c 7,7,3 0 0347 +ç " +`e 7,10 0 0350 +è " +'e 7,10 0 0351 +é " +^e 7,10 0 0352 +ê " +:e 7,9 0 0353 +ë " +`i 3,10 0 0354 +ì " +'i 3,10 0 0355 +í " +^i 3,10 0 0356 +î " +:i 3,9 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 7,10 0 0361 +ñ " +`o 7,10 0 0362 +ò " +'o 7,10 0 0363 +ó " +^o 7,10 0 0364 +ô " +~o 7,10 0 0365 +õ " +:o 7,9 0 0366 +ö " +di 8,6 0 0367 +÷ " +/o 7,8 0 0370 +ø " +`u 7,10 0 0371 +ù " +'u 7,10 0 0372 +ú " +^u 7,10 0 0373 +û " +:u 7,9 0 0374 +ü " +'y 7,10,3 0 0375 +ý " +Tp 7,9,3 0 0376 +þ " +:y 7,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/HI b/gnu/usr.bin/groff/devices/devX75-12/HI new file mode 100644 index 0000000000..587e1451eb --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/HI @@ -0,0 +1,306 @@ +name HI +spacewidth 4 +charset +--- 4,1 0 040 +! 3,9 0 041 +" 5,9 0 042 +# 7,8 0 043 +sh " +$ 7,9,1 0 044 +Do " +% 11,9 0 045 +& 9,9 0 046 +' 3,9 0 047 +( 4,9,3 0 050 +) 4,9,3 0 051 +* 5,9 0 052 ++ 7,6 0 053 +, 3,1,2 0 054 +\- 8,4 0 055 +. 3,1 0 056 +/ 4,9 0 057 +sl " +0 7,9 0 060 +1 7,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 3,6 0 072 +; 3,6,2 0 073 +< 8,6 0 074 += 7,5 0 075 +eq " +> 8,6 0 076 +? 7,9 0 077 +@ 12,9,1 0 0100 +at " +A 9,9 0 0101 +B 8,9 0 0102 +C 8,9 0 0103 +D 9,9 0 0104 +E 8,9 0 0105 +F 8,9 0 0106 +G 8,9 0 0107 +H 10,9 0 0110 +I 4,9 0 0111 +J 8,9 0 0112 +K 8,9 0 0113 +L 7,9 0 0114 +M 12,9 0 0115 +N 10,9 0 0116 +O 9,9 0 0117 +P 8,9 0 0120 +Q 9,9 0 0121 +R 8,9 0 0122 +S 8,9 0 0123 +T 7,9 0 0124 +U 9,9 0 0125 +V 8,9 0 0126 +W 11,9 0 0127 +X 9,9 0 0130 +Y 8,9 0 0131 +Z 9,9 0 0132 +[ 4,9,3 0 0133 +lB " +\ 4,9 0 0134 +rs " +] 4,9,3 0 0135 +rB " +^ 6,8 0 0136 +a^ " +ha " +_ 7,0,3 0 0137 +` 3,9 0 0140 +oq " +a 7,7 0 0141 +b 7,9 0 0142 +c 6,7 0 0143 +d 7,9 0 0144 +e 6,7 0 0145 +f 3,9 0 0146 +g 7,7,3 0 0147 +h 7,9 0 0150 +i 3,9 0 0151 +j 3,9,3 0 0152 +k 6,9 0 0153 +l 3,9 0 0154 +m 9,7 0 0155 +n 7,7 0 0156 +o 7,7 0 0157 +p 7,7,3 0 0160 +q 7,7,3 0 0161 +r 4,7 0 0162 +s 6,7 0 0163 +t 4,9 0 0164 +u 7,7 0 0165 +v 6,7 0 0166 +w 9,7 0 0167 +x 6,7 0 0170 +y 6,7,3 0 0171 +z 6,7 0 0172 +{ 5,9,3 0 0173 +lC " +| 4,9,3 0 0174 +or " +ba " +} 5,9,3 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 4,6,3 0 0241 +¡ " +ct 8,8,1 0 0242 +¢ " +Po 8,9 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 7,9 0 0245 +¥ " +bb 4,9,2 0 0246 +¦ " +sc 7,9,3 0 0247 +§ " +ad 3,9 0 0250 +¨ " +co 11,9 0 0251 +© " +Of 5,9 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 8,6 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 4,9 0 0257 +¯ " +de 5,8 0 0260 +° " ++- 7,7 0 0261 +± " +S2 4,8 0 0262 +² " +S3 4,8 0 0263 +³ " +aa 2,10 0 0264 +´ " +µ 7,7,3 0 0265 +ps 8,9,3 0 0266 +¶ " +md 3,4 0 0267 +· " +ac 3,1,3 0 0270 +¸ " +S1 4,8 0 0271 +¹ " +Om 5,9 0 0272 +º " +Fc 7,6 0 0273 +» " +14 10,9 0 0274 +¼ " +12 10,9 0 0275 +½ " +34 10,9 0 0276 +¾ " +r? 7,6,3 0 0277 +¿ " +`A 9,12 0 0300 +À " +'A 9,12 0 0301 +Á " +^A 9,12 0 0302 +Â " +~A 9,12 0 0303 +Ã " +:A 9,11 0 0304 +Ä " +oA 9,12 0 0305 +Å " +AE 11,9 0 0306 +Æ " +,C 8,9,3 0 0307 +Ç " +`E 8,12 0 0310 +È " +'E 8,12 0 0311 +É " +^E 8,12 0 0312 +Ê " +:E 8,11 0 0313 +Ë " +`I 4,12 0 0314 +Ì " +'I 4,12 0 0315 +Í " +^I 4,12 0 0316 +Î " +:I 4,11 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 10,12 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,11 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 10,9 0 0330 +Ø " +`U 9,12 0 0331 +Ù " +'U 9,12 0 0332 +Ú " +^U 9,12 0 0333 +Û " +:U 9,11 0 0334 +Ü " +'Y 8,12 0 0335 +Ý " +TP 8,9 0 0336 +Þ " +ss 7,9 0 0337 +ß " +`a 7,10 0 0340 +à " +'a 7,10 0 0341 +á " +^a 7,10 0 0342 +â " +~a 7,10 0 0343 +ã " +:a 7,9 0 0344 +ä " +oa 7,10 0 0345 +å " +ae 11,7 0 0346 +æ " +,c 6,7,3 0 0347 +ç " +`e 6,10 0 0350 +è " +'e 6,10 0 0351 +é " +^e 6,10 0 0352 +ê " +:e 6,9 0 0353 +ë " +`i 3,10 0 0354 +ì " +'i 3,10 0 0355 +í " +^i 3,10 0 0356 +î " +:i 3,9 0 0357 +ï " +Sd 7,11 0 0360 +ð " +~n 7,10 0 0361 +ñ " +`o 7,10 0 0362 +ò " +'o 7,10 0 0363 +ó " +^o 7,10 0 0364 +ô " +~o 7,10 0 0365 +õ " +:o 7,9 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 7,7 0 0370 +ø " +`u 7,10 0 0371 +ù " +'u 7,10 0 0372 +ú " +^u 7,10 0 0373 +û " +:u 7,9 0 0374 +ü " +'y 6,10,3 0 0375 +ý " +Tp 7,9,3 0 0376 +þ " +:y 7,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/HR b/gnu/usr.bin/groff/devices/devX75-12/HR new file mode 100644 index 0000000000..86958ed6b5 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/HR @@ -0,0 +1,306 @@ +name HR +spacewidth 4 +charset +--- 4,1 0 040 +! 3,9 0 041 +" 5,9 0 042 +# 7,8 0 043 +sh " +$ 6,9,2 0 044 +Do " +% 11,9 0 045 +& 9,9 0 046 +' 3,9 0 047 +( 4,9,3 0 050 +) 4,9,3 0 051 +* 5,9 0 052 ++ 7,6 0 053 +, 4,1,2 0 054 +\- 8,4 0 055 +. 3,1 0 056 +/ 4,9 0 057 +sl " +0 7,9 0 060 +1 7,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 3,6 0 072 +; 3,6,2 0 073 +< 7,6 0 074 += 7,5 0 075 +eq " +> 7,6 0 076 +? 7,9 0 077 +@ 12,9,1 0 0100 +at " +A 9,9 0 0101 +B 8,9 0 0102 +C 9,9 0 0103 +D 9,9 0 0104 +E 8,9 0 0105 +F 8,9 0 0106 +G 9,9 0 0107 +H 9,9 0 0110 +I 3,9 0 0111 +J 7,9 0 0112 +K 8,9 0 0113 +L 7,9 0 0114 +M 11,9 0 0115 +N 9,9 0 0116 +O 10,9 0 0117 +P 8,9 0 0120 +Q 10,9 0 0121 +R 8,9 0 0122 +S 8,9 0 0123 +T 7,9 0 0124 +U 8,9 0 0125 +V 9,9 0 0126 +W 11,9 0 0127 +X 9,9 0 0130 +Y 9,9 0 0131 +Z 9,9 0 0132 +[ 3,9,3 0 0133 +lB " +\ 4,9 0 0134 +rs " +] 3,9,3 0 0135 +rB " +^ 6,8 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 3,9 0 0140 +oq " +a 7,7 0 0141 +b 7,9 0 0142 +c 7,7 0 0143 +d 7,9 0 0144 +e 7,7 0 0145 +f 3,9 0 0146 +g 7,7,3 0 0147 +h 7,9 0 0150 +i 3,9 0 0151 +j 3,9,3 0 0152 +k 6,9 0 0153 +l 3,9 0 0154 +m 9,7 0 0155 +n 7,7 0 0156 +o 7,7 0 0157 +p 7,7,3 0 0160 +q 7,7,3 0 0161 +r 4,7 0 0162 +s 6,7 0 0163 +t 4,9 0 0164 +u 7,7 0 0165 +v 7,7 0 0166 +w 9,7 0 0167 +x 6,7 0 0170 +y 7,7,3 0 0171 +z 6,7 0 0172 +{ 4,9,3 0 0173 +lC " +| 3,9,3 0 0174 +or " +ba " +} 4,9,3 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 3,7,3 0 0241 +¡ " +ct 7,8,1 0 0242 +¢ " +Po 7,9 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 7,9 0 0245 +¥ " +bb 3,9,2 0 0246 +¦ " +sc 6,9,3 0 0247 +§ " +ad 3,9 0 0250 +¨ " +co 11,9 0 0251 +© " +Of 5,9 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 8,6 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 4,9 0 0257 +¯ " +de 5,8 0 0260 +° " ++- 7,7 0 0261 +± " +S2 4,8 0 0262 +² " +S3 4,8 0 0263 +³ " +aa 2,10 0 0264 +´ " +µ 7,7,3 0 0265 +ps 7,9,3 0 0266 +¶ " +md 3,4 0 0267 +· " +ac 3,1,3 0 0270 +¸ " +S1 4,8 0 0271 +¹ " +Om 5,9 0 0272 +º " +Fc 7,6 0 0273 +» " +14 10,9 0 0274 +¼ " +12 10,9 0 0275 +½ " +34 10,9 0 0276 +¾ " +r? 7,6,3 0 0277 +¿ " +`A 9,12 0 0300 +À " +'A 9,12 0 0301 +Á " +^A 9,12 0 0302 +Â " +~A 9,12 0 0303 +Ã " +:A 9,11 0 0304 +Ä " +oA 9,12 0 0305 +Å " +AE 11,9 0 0306 +Æ " +,C 9,9,3 0 0307 +Ç " +`E 8,12 0 0310 +È " +'E 8,12 0 0311 +É " +^E 8,12 0 0312 +Ê " +:E 8,11 0 0313 +Ë " +`I 3,12 0 0314 +Ì " +'I 3,12 0 0315 +Í " +^I 3,12 0 0316 +Î " +:I 3,11 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 9,12 0 0321 +Ñ " +`O 10,12 0 0322 +Ò " +'O 10,12 0 0323 +Ó " +^O 10,12 0 0324 +Ô " +~O 10,12 0 0325 +Õ " +:O 10,11 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 10,10,1 0 0330 +Ø " +`U 8,12 0 0331 +Ù " +'U 8,12 0 0332 +Ú " +^U 8,12 0 0333 +Û " +:U 8,11 0 0334 +Ü " +'Y 9,12 0 0335 +Ý " +TP 8,9 0 0336 +Þ " +ss 7,9 0 0337 +ß " +`a 7,10 0 0340 +à " +'a 7,10 0 0341 +á " +^a 7,10 0 0342 +â " +~a 7,10 0 0343 +ã " +:a 7,9 0 0344 +ä " +oa 7,10 0 0345 +å " +ae 11,7 0 0346 +æ " +,c 7,7,3 0 0347 +ç " +`e 7,10 0 0350 +è " +'e 7,10 0 0351 +é " +^e 7,10 0 0352 +ê " +:e 7,9 0 0353 +ë " +`i 3,10 0 0354 +ì " +'i 3,10 0 0355 +í " +^i 3,10 0 0356 +î " +:i 3,9 0 0357 +ï " +Sd 7,10 0 0360 +ð " +~n 7,10 0 0361 +ñ " +`o 7,10 0 0362 +ò " +'o 7,10 0 0363 +ó " +^o 7,10 0 0364 +ô " +~o 7,10 0 0365 +õ " +:o 7,9 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 7,7 0 0370 +ø " +`u 7,10 0 0371 +ù " +'u 7,10 0 0372 +ú " +^u 7,10 0 0373 +û " +:u 7,9 0 0374 +ü " +'y 7,10,3 0 0375 +ý " +Tp 7,9,3 0 0376 +þ " +:y 7,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/Makefile b/gnu/usr.bin/groff/devices/devX75-12/Makefile new file mode 100644 index 0000000000..705e3ea2a9 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/Makefile @@ -0,0 +1,10 @@ +# Makefile for devX75-12 + +DEVICE= X75-12 +FONTFILES= CB CBI CI CR HB HBI HI HR NB NBI NI NR S TB TBI TI TR DESC + +NOOBJ= noobj + +clean cleandir: + +.include "../Makefile.dev" diff --git a/gnu/usr.bin/groff/devices/devX75-12/NB b/gnu/usr.bin/groff/devices/devX75-12/NB new file mode 100644 index 0000000000..5fea01717d --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/NB @@ -0,0 +1,306 @@ +name NB +spacewidth 4 +charset +--- 4,1 0 040 +! 4,9 0 041 +" 6,9 0 042 +# 8,9 0 043 +sh " +$ 7,10,1 0 044 +Do " +% 13,9 0 045 +& 11,9 0 046 +' 3,9 0 047 +( 5,9,2 0 050 +) 5,9,2 0 051 +* 6,9 0 052 ++ 8,7 0 053 +, 4,2,2 0 054 +\- 7,4 0 055 +. 4,2 0 056 +/ 4,9 0 057 +sl " +0 7,9 0 060 +1 5,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 4,6 0 072 +; 4,6,2 0 073 +< 7,6 0 074 += 7,5 0 075 +eq " +> 7,6 0 076 +? 7,9 0 077 +@ 11,9 0 0100 +at " +A 11,9 0 0101 +B 9,9 0 0102 +C 9,9 0 0103 +D 10,9 0 0104 +E 9,9 0 0105 +F 9,9 0 0106 +G 10,9 0 0107 +H 11,9 0 0110 +I 5,9 0 0111 +J 8,9 0 0112 +K 10,9 0 0113 +L 9,9 0 0114 +M 12,9 0 0115 +N 11,9 0 0116 +O 10,9 0 0117 +P 9,9 0 0120 +Q 10,9,2 0 0121 +R 10,9 0 0122 +S 8,9 0 0123 +T 9,9 0 0124 +U 10,9 0 0125 +V 11,9 0 0126 +W 14,9 0 0127 +X 10,9 0 0130 +Y 9,9 0 0131 +Z 9,9 0 0132 +[ 5,9,2 0 0133 +lB " +\ 6,9 0 0134 +rs " +] 5,9,2 0 0135 +rB " +^ 6,9 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 3,9 0 0140 +oq " +a 8,6 0 0141 +b 8,9 0 0142 +c 7,6 0 0143 +d 9,9 0 0144 +e 7,6 0 0145 +f 5,9 0 0146 +g 7,7,3 0 0147 +h 9,9 0 0150 +i 5,9 0 0151 +j 3,9,3 0 0152 +k 8,9 0 0153 +l 5,9 0 0154 +m 13,6 0 0155 +n 9,6 0 0156 +o 8,6 0 0157 +p 8,6,3 0 0160 +q 8,6,3 0 0161 +r 6,6 0 0162 +s 6,6 0 0163 +t 5,9 0 0164 +u 9,6 0 0165 +v 7,6 0 0166 +w 11,6 0 0167 +x 8,6 0 0170 +y 7,6,3 0 0171 +z 7,6 0 0172 +{ 5,9,2 0 0173 +lC " +| 8,9 0 0174 +or " +ba " +} 5,9,2 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 4,6,3 0 0241 +¡ " +ct 7,7,1 0 0242 +¢ " +Po 8,9 0 0243 +£ " +Cs 8,8 0 0244 +¤ " +Ye 9,9 0 0245 +¥ " +bb 8,9 0 0246 +¦ " +sc 6,9,1 0 0247 +§ " +ad 5,9 0 0250 +¨ " +co 10,9 0 0251 +© " +Of 6,9 0 0252 +ª " +Fo 8,6 0 0253 +« " +no 7,5 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 6,8 0 0257 +¯ " +de 5,9 0 0260 +° " ++- 8,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 5,9 0 0264 +´ " +µ 9,6,3 0 0265 +ps 10,9 0 0266 +¶ " +md 3,5 0 0267 +· " +ac 5,0,3 0 0270 +¸ " +S1 4,9 0 0271 +¹ " +Om 6,9 0 0272 +º " +Fc 8,6 0 0273 +» " +14 10,9 0 0274 +¼ " +12 10,9 0 0275 +½ " +34 10,9 0 0276 +¾ " +r? 7,6,3 0 0277 +¿ " +`A 11,12 0 0300 +À " +'A 11,12 0 0301 +Á " +^A 11,12 0 0302 +Â " +~A 11,12 0 0303 +Ã " +:A 11,12 0 0304 +Ä " +oA 11,12 0 0305 +Å " +AE 14,9 0 0306 +Æ " +,C 9,9,3 0 0307 +Ç " +`E 9,12 0 0310 +È " +'E 9,12 0 0311 +É " +^E 9,12 0 0312 +Ê " +:E 9,12 0 0313 +Ë " +`I 5,12 0 0314 +Ì " +'I 5,12 0 0315 +Í " +^I 5,12 0 0316 +Î " +:I 5,12 0 0317 +Ï " +-D 10,9 0 0320 +Ð " +~N 11,12 0 0321 +Ñ " +`O 10,12 0 0322 +Ò " +'O 10,12 0 0323 +Ó " +^O 10,12 0 0324 +Ô " +~O 10,12 0 0325 +Õ " +:O 10,12 0 0326 +Ö " +mu 8,7 0 0327 +× " +/O 10,9 0 0330 +Ø " +`U 10,12 0 0331 +Ù " +'U 10,12 0 0332 +Ú " +^U 10,12 0 0333 +Û " +:U 10,12 0 0334 +Ü " +'Y 9,12 0 0335 +Ý " +TP 9,9 0 0336 +Þ " +ss 8,9 0 0337 +ß " +`a 8,9 0 0340 +à " +'a 8,9 0 0341 +á " +^a 8,9 0 0342 +â " +~a 8,9 0 0343 +ã " +:a 8,9 0 0344 +ä " +oa 8,9 0 0345 +å " +ae 11,6 0 0346 +æ " +,c 7,6,3 0 0347 +ç " +`e 7,9 0 0350 +è " +'e 7,9 0 0351 +é " +^e 7,9 0 0352 +ê " +:e 7,9 0 0353 +ë " +`i 5,9 0 0354 +ì " +'i 5,9 0 0355 +í " +^i 5,9 0 0356 +î " +:i 5,9 0 0357 +ï " +Sd 8,9 0 0360 +ð " +~n 9,9 0 0361 +ñ " +`o 8,9 0 0362 +ò " +'o 8,9 0 0363 +ó " +^o 8,9 0 0364 +ô " +~o 8,9 0 0365 +õ " +:o 8,9 0 0366 +ö " +di 8,7 0 0367 +÷ " +/o 8,7,1 0 0370 +ø " +`u 9,9 0 0371 +ù " +'u 9,9 0 0372 +ú " +^u 9,9 0 0373 +û " +:u 9,9 0 0374 +ü " +'y 7,9,3 0 0375 +ý " +Tp 8,9,3 0 0376 +þ " +:y 7,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/NBI b/gnu/usr.bin/groff/devices/devX75-12/NBI new file mode 100644 index 0000000000..0da124adf0 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/NBI @@ -0,0 +1,306 @@ +name NBI +spacewidth 4 +charset +--- 4,1 0 040 +! 5,9 0 041 +" 6,9 0 042 +# 8,8 0 043 +sh " +$ 7,10,1 0 044 +Do " +% 12,9 0 045 +& 12,9 0 046 +' 3,9 0 047 +( 5,9,2 0 050 +) 5,9,2 0 051 +* 6,9 0 052 ++ 8,7 0 053 +, 3,2,2 0 054 +\- 8,4 0 055 +. 3,2 0 056 +/ 6,9 0 057 +sl " +0 7,9 0 060 +1 7,9 0 061 +2 7,9 0 062 +3 7,9 0 063 +4 7,9 0 064 +5 7,9 0 065 +6 7,9 0 066 +7 7,9 0 067 +8 7,9 0 070 +9 7,9 0 071 +: 4,6 0 072 +; 4,6,2 0 073 +< 7,7 0 074 += 7,5 0 075 +eq " +> 7,7 0 076 +? 6,9 0 077 +@ 11,9 0 0100 +at " +A 10,9 0 0101 +B 9,9 0 0102 +C 9,9 0 0103 +D 10,9 0 0104 +E 9,9 0 0105 +F 8,9 0 0106 +G 10,9 0 0107 +H 11,9 0 0110 +I 6,9 0 0111 +J 8,9 0 0112 +K 10,9 0 0113 +L 9,9 0 0114 +M 14,9 0 0115 +N 11,9 0 0116 +O 10,9 0 0117 +P 9,9 0 0120 +Q 10,9,2 0 0121 +R 10,9 0 0122 +S 8,9 0 0123 +T 9,9 0 0124 +U 9,9 0 0125 +V 10,9 0 0126 +W 13,9 0 0127 +X 11,9 0 0130 +Y 9,9 0 0131 +Z 9,9 0 0132 +[ 6,9,2 0 0133 +lB " +\ 6,9 0 0134 +rs " +] 6,9,2 0 0135 +rB " +^ 8,9 0 0136 +a^ " +ha " +_ 8,0,2 0 0137 +` 3,9 0 0140 +oq " +a 8,6 0 0141 +b 7,9 0 0142 +c 6,6 0 0143 +d 8,9 0 0144 +e 7,6 0 0145 +f 5,9,3 0 0146 +g 7,8,3 0 0147 +h 8,9 0 0150 +i 4,9 0 0151 +j 4,9,3 0 0152 +k 8,9 0 0153 +l 4,9 0 0154 +m 12,6 0 0155 +n 8,6 0 0156 +o 7,6 0 0157 +p 8,6,3 0 0160 +q 8,6,3 0 0161 +r 6,6 0 0162 +s 7,6 0 0163 +t 5,8 0 0164 +u 8,6 0 0165 +v 7,6 0 0166 +w 11,6 0 0167 +x 7,6 0 0170 +y 6,6,3 0 0171 +z 7,6 0 0172 +{ 6,9,2 0 0173 +lC " +| 8,9 0 0174 +or " +ba " +} 6,9,2 0 0175 +rC " +~ 8,5 0 0176 +a~ " +ap " +ti " +r! 5,6,3 0 0241 +¡ " +ct 7,7,1 0 0242 +¢ " +Po 9,9 0 0243 +£ " +Cs 8,8 0 0244 +¤ " +Ye 10,9 0 0245 +¥ " +bb 8,9 0 0246 +¦ " +sc 6,9,2 0 0247 +§ " +ad 4,9 0 0250 +¨ " +co 10,9 0 0251 +© " +Of 6,9 0 0252 +ª " +Fo 9,6 0 0253 +« " +no 7,5 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 10,9 0 0256 +® " +a- 5,8 0 0257 +¯ " +de 5,9 0 0260 +° " ++- 8,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 4,9 0 0264 +´ " +µ 8,6,3 0 0265 +ps 8,9 0 0266 +¶ " +md 5,5 0 0267 +· " +ac 4,0,3 0 0270 +¸ " +S1 4,9 0 0271 +¹ " +Om 5,9 0 0272 +º " +Fc 9,6 0 0273 +» " +14 10,9 0 0274 +¼ " +12 10,9 0 0275 +½ " +34 10,9 0 0276 +¾ " +r? 6,6,3 0 0277 +¿ " +`A 10,12 0 0300 +À " +'A 10,12 0 0301 +Á " +^A 10,12 0 0302 +Â " +~A 10,12 0 0303 +Ã " +:A 10,12 0 0304 +Ä " +oA 10,12 0 0305 +Å " +AE 12,9 0 0306 +Æ " +,C 9,9,3 0 0307 +Ç " +`E 9,12 0 0310 +È " +'E 9,12 0 0311 +É " +^E 9,12 0 0312 +Ê " +:E 9,12 0 0313 +Ë " +`I 6,12 0 0314 +Ì " +'I 6,12 0 0315 +Í " +^I 6,12 0 0316 +Î " +:I 6,12 0 0317 +Ï " +-D 10,9 0 0320 +Ð " +~N 11,12 0 0321 +Ñ " +`O 10,12 0 0322 +Ò " +'O 10,12 0 0323 +Ó " +^O 10,12 0 0324 +Ô " +~O 10,12 0 0325 +Õ " +:O 10,12 0 0326 +Ö " +mu 8,7 0 0327 +× " +/O 10,9 0 0330 +Ø " +`U 9,12 0 0331 +Ù " +'U 9,12 0 0332 +Ú " +^U 9,12 0 0333 +Û " +:U 9,12 0 0334 +Ü " +'Y 9,12 0 0335 +Ý " +TP 9,9 0 0336 +Þ " +ss 9,9,2 0 0337 +ß " +`a 8,9 0 0340 +à " +'a 8,9 0 0341 +á " +^a 8,10 0 0342 +â " +~a 8,9 0 0343 +ã " +:a 8,9 0 0344 +ä " +oa 8,10 0 0345 +å " +ae 11,6 0 0346 +æ " +,c 6,6,3 0 0347 +ç " +`e 7,9 0 0350 +è " +'e 7,9 0 0351 +é " +^e 7,10 0 0352 +ê " +:e 7,9 0 0353 +ë " +`i 4,9 0 0354 +ì " +'i 4,9 0 0355 +í " +^i 4,10 0 0356 +î " +:i 4,9 0 0357 +ï " +Sd 7,9 0 0360 +ð " +~n 8,9 0 0361 +ñ " +`o 7,9 0 0362 +ò " +'o 7,9 0 0363 +ó " +^o 7,10 0 0364 +ô " +~o 7,9 0 0365 +õ " +:o 7,9 0 0366 +ö " +di 8,7 0 0367 +÷ " +/o 7,6 0 0370 +ø " +`u 8,9 0 0371 +ù " +'u 8,9 0 0372 +ú " +^u 8,10 0 0373 +û " +:u 8,9 0 0374 +ü " +'y 6,9,3 0 0375 +ý " +Tp 8,9,3 0 0376 +þ " +:y 6,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/NI b/gnu/usr.bin/groff/devices/devX75-12/NI new file mode 100644 index 0000000000..05ee8cdbd8 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/NI @@ -0,0 +1,306 @@ +name NI +spacewidth 3 +charset +--- 3,1 0 040 +! 4,9 0 041 +" 6,9 0 042 +# 8,8 0 043 +sh " +$ 6,10,1 0 044 +Do " +% 10,9 0 045 +& 10,9 0 046 +' 3,9 0 047 +( 5,9,2 0 050 +) 5,9,2 0 051 +* 7,9 0 052 ++ 8,7 0 053 +, 2,2,1 0 054 +\- 7,4 0 055 +. 2,2 0 056 +/ 8,9,1 0 057 +sl " +0 6,9 0 060 +1 6,9 0 061 +2 6,9 0 062 +3 6,9 0 063 +4 6,9 0 064 +5 6,9 0 065 +6 6,9 0 066 +7 6,9 0 067 +8 6,9 0 070 +9 6,9 0 071 +: 3,6 0 072 +; 3,6,1 0 073 +< 7,6 0 074 += 7,5 0 075 +eq " +> 7,6 0 076 +? 5,9 0 077 +@ 11,9 0 0100 +at " +A 8,9 0 0101 +B 8,9 0 0102 +C 9,9 0 0103 +D 10,9 0 0104 +E 9,9 0 0105 +F 9,9 0 0106 +G 9,9 0 0107 +H 10,9 0 0110 +I 5,9 0 0111 +J 7,9 0 0112 +K 9,9 0 0113 +L 8,9 0 0114 +M 13,9 0 0115 +N 11,9 0 0116 +O 9,9 0 0117 +P 8,9 0 0120 +Q 9,9,2 0 0121 +R 10,9 0 0122 +S 9,9 0 0123 +T 8,9 0 0124 +U 8,9 0 0125 +V 9,9 0 0126 +W 13,9 0 0127 +X 10,9 0 0130 +Y 8,9 0 0131 +Z 9,9 0 0132 +[ 6,9,2 0 0133 +lB " +\ 8,9 0 0134 +rs " +] 6,9,2 0 0135 +rB " +^ 6,9 0 0136 +a^ " +ha " +_ 8,0,2 0 0137 +` 3,9 0 0140 +oq " +a 8,6 0 0141 +b 7,9 0 0142 +c 6,6 0 0143 +d 8,9 0 0144 +e 6,6 0 0145 +f 4,9,3 0 0146 +g 6,7,3 0 0147 +h 8,9 0 0150 +i 4,9 0 0151 +j 3,9,3 0 0152 +k 7,9 0 0153 +l 4,9 0 0154 +m 12,6 0 0155 +n 8,6 0 0156 +o 6,6 0 0157 +p 7,6,3 0 0160 +q 7,6,3 0 0161 +r 5,6 0 0162 +s 6,6 0 0163 +t 4,8 0 0164 +u 8,6 0 0165 +v 7,6 0 0166 +w 10,6 0 0167 +x 6,6 0 0170 +y 6,6,3 0 0171 +z 6,6 0 0172 +{ 5,9,2 0 0173 +lC " +| 6,9 0 0174 +or " +ba " +} 5,9,2 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 4,7,2 0 0241 +¡ " +ct 6,7,1 0 0242 +¢ " +Po 8,9 0 0243 +£ " +Cs 9,8 0 0244 +¤ " +Ye 9,9 0 0245 +¥ " +bb 6,9 0 0246 +¦ " +sc 6,9,2 0 0247 +§ " +ad 5,9 0 0250 +¨ " +co 10,9 0 0251 +© " +Of 5,9 0 0252 +ª " +Fo 7,5 0 0253 +« " +no 7,5 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 10,9 0 0256 +® " +a- 5,8 0 0257 +¯ " +de 5,9 0 0260 +° " ++- 8,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 4,9 0 0264 +´ " +µ 8,6,3 0 0265 +ps 9,9 0 0266 +¶ " +md 5,5 0 0267 +· " +ac 4,0,3 0 0270 +¸ " +S1 4,9 0 0271 +¹ " +Om 4,9 0 0272 +º " +Fc 7,5 0 0273 +» " +14 9,9 0 0274 +¼ " +12 9,9 0 0275 +½ " +34 9,9 0 0276 +¾ " +r? 5,7,2 0 0277 +¿ " +`A 8,12 0 0300 +À " +'A 8,12 0 0301 +Á " +^A 8,12 0 0302 +Â " +~A 8,12 0 0303 +Ã " +:A 8,12 0 0304 +Ä " +oA 8,12 0 0305 +Å " +AE 13,9 0 0306 +Æ " +,C 9,9,3 0 0307 +Ç " +`E 9,12 0 0310 +È " +'E 9,12 0 0311 +É " +^E 9,12 0 0312 +Ê " +:E 9,12 0 0313 +Ë " +`I 5,12 0 0314 +Ì " +'I 5,12 0 0315 +Í " +^I 5,12 0 0316 +Î " +:I 5,12 0 0317 +Ï " +-D 10,9 0 0320 +Ð " +~N 11,12 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,12 0 0326 +Ö " +mu 8,7 0 0327 +× " +/O 9,9 0 0330 +Ø " +`U 8,12 0 0331 +Ù " +'U 8,12 0 0332 +Ú " +^U 8,12 0 0333 +Û " +:U 8,12 0 0334 +Ü " +'Y 8,12 0 0335 +Ý " +TP 8,9 0 0336 +Þ " +ss 8,9,3 0 0337 +ß " +`a 8,9 0 0340 +à " +'a 8,9 0 0341 +á " +^a 8,9 0 0342 +â " +~a 8,9 0 0343 +ã " +:a 8,9 0 0344 +ä " +oa 8,10 0 0345 +å " +ae 9,6 0 0346 +æ " +,c 6,6,3 0 0347 +ç " +`e 6,9 0 0350 +è " +'e 6,9 0 0351 +é " +^e 6,9 0 0352 +ê " +:e 6,9 0 0353 +ë " +`i 4,9 0 0354 +ì " +'i 4,9 0 0355 +í " +^i 4,9 0 0356 +î " +:i 4,9 0 0357 +ï " +Sd 6,9 0 0360 +ð " +~n 8,9 0 0361 +ñ " +`o 6,9 0 0362 +ò " +'o 6,9 0 0363 +ó " +^o 6,9 0 0364 +ô " +~o 6,9 0 0365 +õ " +:o 6,9 0 0366 +ö " +di 8,7 0 0367 +÷ " +/o 6,6 0 0370 +ø " +`u 8,9 0 0371 +ù " +'u 8,9 0 0372 +ú " +^u 8,9 0 0373 +û " +:u 8,9 0 0374 +ü " +'y 6,9,3 0 0375 +ý " +Tp 7,9,3 0 0376 +þ " +:y 8,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/NR b/gnu/usr.bin/groff/devices/devX75-12/NR new file mode 100644 index 0000000000..a1df486790 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/NR @@ -0,0 +1,306 @@ +name NR +spacewidth 3 +charset +--- 3,1 0 040 +! 4,9 0 041 +" 6,9 0 042 +# 8,8 0 043 +sh " +$ 6,10,1 0 044 +Do " +% 11,9 0 045 +& 9,9 0 046 +' 4,9 0 047 +( 4,9,2 0 050 +) 4,9,2 0 051 +* 6,9 0 052 ++ 8,7 0 053 +, 4,2,1 0 054 +\- 7,4 0 055 +. 4,2 0 056 +/ 4,9 0 057 +sl " +0 6,9 0 060 +1 6,9 0 061 +2 6,9 0 062 +3 6,9 0 063 +4 6,9 0 064 +5 6,9 0 065 +6 6,9 0 066 +7 6,9 0 067 +8 6,9 0 070 +9 6,9 0 071 +: 4,6 0 072 +; 4,6,1 0 073 +< 7,6 0 074 += 7,5 0 075 +eq " +> 7,6 0 076 +? 5,9 0 077 +@ 10,9 0 0100 +at " +A 10,9 0 0101 +B 8,9 0 0102 +C 9,9 0 0103 +D 9,9 0 0104 +E 8,9 0 0105 +F 8,9 0 0106 +G 10,9 0 0107 +H 10,9 0 0110 +I 6,9 0 0111 +J 7,9 0 0112 +K 9,9 0 0113 +L 8,9 0 0114 +M 12,9 0 0115 +N 10,9 0 0116 +O 9,9 0 0117 +P 8,9 0 0120 +Q 9,9,2 0 0121 +R 9,9 0 0122 +S 7,9 0 0123 +T 8,9 0 0124 +U 10,9 0 0125 +V 10,9 0 0126 +W 12,9 0 0127 +X 9,9 0 0130 +Y 10,9 0 0131 +Z 7,9 0 0132 +[ 4,9,2 0 0133 +lB " +\ 6,9 0 0134 +rs " +] 4,9,2 0 0135 +rB " +^ 6,9 0 0136 +a^ " +ha " +_ 8,0,2 0 0137 +` 4,9 0 0140 +oq " +a 7,6 0 0141 +b 6,9 0 0142 +c 6,6 0 0143 +d 7,9 0 0144 +e 6,6 0 0145 +f 4,9 0 0146 +g 7,7,3 0 0147 +h 8,9 0 0150 +i 4,9 0 0151 +j 4,9,3 0 0152 +k 7,9 0 0153 +l 4,9 0 0154 +m 12,6 0 0155 +n 8,6 0 0156 +o 6,6 0 0157 +p 7,6,3 0 0160 +q 6,6,3 0 0161 +r 6,6 0 0162 +s 6,6 0 0163 +t 4,8 0 0164 +u 8,6 0 0165 +v 6,6 0 0166 +w 10,6 0 0167 +x 7,6 0 0170 +y 6,6,3 0 0171 +z 6,6 0 0172 +{ 4,9,2 0 0173 +lC " +| 8,9 0 0174 +or " +ba " +} 4,9,2 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 4,7,2 0 0241 +¡ " +ct 7,7,1 0 0242 +¢ " +Po 8,9 0 0243 +£ " +Cs 8,8 0 0244 +¤ " +Ye 8,9 0 0245 +¥ " +bb 8,9 0 0246 +¦ " +sc 6,9,2 0 0247 +§ " +ad 4,9 0 0250 +¨ " +co 11,9 0 0251 +© " +Of 5,9 0 0252 +ª " +Fo 7,6 0 0253 +« " +no 7,5 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 5,8 0 0257 +¯ " +de 5,9 0 0260 +° " ++- 8,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 3,9 0 0264 +´ " +µ 8,6,3 0 0265 +ps 8,9,2 0 0266 +¶ " +md 4,5 0 0267 +· " +ac 4,0,3 0 0270 +¸ " +S1 4,9 0 0271 +¹ " +Om 5,9 0 0272 +º " +Fc 7,6 0 0273 +» " +14 9,9 0 0274 +¼ " +12 9,9 0 0275 +½ " +34 9,9 0 0276 +¾ " +r? 5,7,2 0 0277 +¿ " +`A 10,12 0 0300 +À " +'A 10,12 0 0301 +Á " +^A 10,12 0 0302 +Â " +~A 10,12 0 0303 +Ã " +:A 10,12 0 0304 +Ä " +oA 10,12 0 0305 +Å " +AE 13,9 0 0306 +Æ " +,C 9,9,3 0 0307 +Ç " +`E 8,12 0 0310 +È " +'E 8,12 0 0311 +É " +^E 8,12 0 0312 +Ê " +:E 8,12 0 0313 +Ë " +`I 6,12 0 0314 +Ì " +'I 6,12 0 0315 +Í " +^I 6,12 0 0316 +Î " +:I 6,12 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 10,12 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,12 0 0326 +Ö " +mu 8,7 0 0327 +× " +/O 9,9 0 0330 +Ø " +`U 10,12 0 0331 +Ù " +'U 10,12 0 0332 +Ú " +^U 10,12 0 0333 +Û " +:U 10,12 0 0334 +Ü " +'Y 10,12 0 0335 +Ý " +TP 8,9 0 0336 +Þ " +ss 7,9 0 0337 +ß " +`a 7,9 0 0340 +à " +'a 7,9 0 0341 +á " +^a 7,9 0 0342 +â " +~a 7,9 0 0343 +ã " +:a 7,9 0 0344 +ä " +oa 7,9 0 0345 +å " +ae 10,6 0 0346 +æ " +,c 6,6,3 0 0347 +ç " +`e 6,9 0 0350 +è " +'e 6,9 0 0351 +é " +^e 6,9 0 0352 +ê " +:e 6,9 0 0353 +ë " +`i 4,9 0 0354 +ì " +'i 4,9 0 0355 +í " +^i 4,9 0 0356 +î " +:i 4,9 0 0357 +ï " +Sd 6,9 0 0360 +ð " +~n 8,9 0 0361 +ñ " +`o 6,9 0 0362 +ò " +'o 6,9 0 0363 +ó " +^o 6,9 0 0364 +ô " +~o 6,9 0 0365 +õ " +:o 6,8 0 0366 +ö " +di 8,7 0 0367 +÷ " +/o 6,7,1 0 0370 +ø " +`u 8,9 0 0371 +ù " +'u 8,9 0 0372 +ú " +^u 8,9 0 0373 +û " +:u 8,9 0 0374 +ü " +'y 6,9,3 0 0375 +ý " +Tp 7,9,3 0 0376 +þ " +:y 6,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/S b/gnu/usr.bin/groff/devices/devX75-12/S new file mode 100644 index 0000000000..e93a205734 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/S @@ -0,0 +1,226 @@ +name S +special +spacewidth 3 +charset +--- 3,1 0 040 +! 4,9 0 041 +fa 9,9 0 042 +# 7,9 0 043 +sh " +te 7,9 0 044 +% 10,9 0 045 +& 10,9 0 046 +st 6,6 0 047 +( 5,9,3 0 050 +) 5,9,3 0 051 +** 6,7 0 052 ++ 7,6 0 053 +pl " +, 3,1,2 0 054 +\- 7,4 0 055 +mi " +. 3,1 0 056 +/ 3,9 0 057 +sl " +0 6,9 0 060 +1 6,9 0 061 +2 6,9 0 062 +3 6,9 0 063 +4 6,9 0 064 +5 6,9 0 065 +6 6,9 0 066 +7 6,9 0 067 +8 6,9 0 070 +9 6,9 0 071 +: 3,6 0 072 +; 3,6,2 0 073 +< 7,6 0 074 += 7,5 0 075 +eq " +> 7,6 0 076 +? 6,9 0 077 +=~ 7,6 0 0100 +*A 9,9 0 0101 +*B 8,9 0 0102 +*X 9,9 0 0103 +*D 8,9 0 0104 +*E 8,9 0 0105 +*F 10,9 0 0106 +*G 8,9 0 0107 +*Y 9,9 0 0110 +*I 4,9 0 0111 ++h 8,9 0 0112 +*K 9,9 0 0113 +*L 9,9 0 0114 +*M 11,9 0 0115 +*N 9,9 0 0116 +*O 9,9 0 0117 +*P 9,9 0 0120 +*H 9,9 0 0121 +*R 7,9 0 0122 +*S 7,9 0 0123 +*T 8,9 0 0124 +--- 9,9 0 0125 +ts 7,6,3 0 0126 +*W 10,9 0 0127 +*C 8,9 0 0130 +*Q 10,9 0 0131 +*Z 8,9 0 0132 +[ 5,9,3 0 0133 +lB " +tf 9,6 0 0134 +3d " +] 5,9,3 0 0135 +rB " +pp 8,9 0 0136 +_ 6,0,3 0 0137 +rn 6,12 0 0140 +*a 8,6 0 0141 +*b 7,10,3 0 0142 +*x 7,6,3 0 0143 +*d 7,10 0 0144 +*e 6,6 0 0145 +*f 8,8,3 0 0146 +*g 7,6,3 0 0147 +*y 8,6,3 0 0150 +*i 3,6 0 0151 ++f 8,6,3 0 0152 +*k 7,6 0 0153 +*l 7,9 0 0154 +*m 8,6,3 0 0155 +µ " +*n 7,6 0 0156 +*o 7,6 0 0157 +*p 7,6 0 0160 +*h 7,9 0 0161 +*r 7,6,3 0 0162 +*s 8,6 0 0163 +*t 6,6 0 0164 +*u 8,6 0 0165 ++p 9,7 0 0166 +*w 9,6 0 0167 +*c 6,11,3 0 0170 +*q 9,6,3 0 0171 +*z 6,10,3 0 0172 +lC 6,9,3 0 0173 +{ " +ba 3,9,3 0 0174 +or " +| " +rC 6,9,3 0 0175 +} " +ap 7,5 0 0176 +*U 8,9 0 0241 +fm 3,9 0 0242 +<= 7,7 0 0243 +f/ 4,9 0 0244 +if 9,5 0 0245 +Fn 6,9,3 0 0246 +CL 9,6,1 0 0247 +DI 7,6 0 0250 +HE 9,6 0 0251 +SP 9,6,1 0 0252 +<> 13,6 0 0253 +<- 12,6 0 0254 +ua 7,12,4 0 0255 +arrowverttp " +-> 12,6 0 0256 +da 7,12,3 0 0257 +arrowvertbt " +de 5,9 0 0260 +° " ++- 7,7 0 0261 +± " +sd 5,9 0 0262 +>= 7,7 0 0263 +mu 7,6 0 0264 +× " +pt 9,5 0 0265 +pd 6,10 0 0266 +bu 6,5 0 0267 +di 7,6 0 0270 +÷ " +!= 7,7 0 0271 +== 7,6 0 0272 +~= 7,6 0 0273 +~~ " +--- 11,1 0 0274 +arrowvertex 7,12,4 0 0275 +an 13,4 0 0276 +CR 8,8 0 0277 +Ah 10,9 0 0300 +Im 9,10,1 0 0301 +Re 10,10 0 0302 +wp 10,8,3 0 0303 +c* 10,9 0 0304 +c+ 10,9 0 0305 +es 10,9 0 0306 +ca 10,6 0 0307 +cu 10,6 0 0310 +sp 9,6 0 0311 +ip 9,6,2 0 0312 +--- 9,7,1 0 0313 +sb 9,6 0 0314 +ib 9,6,2 0 0315 +mo 8,6 0 0316 +nm 8,7,1 0 0317 +/_ 10,9 0 0320 +gr 9,9 0 0321 +rg 10,9 0 0322 +co 10,9 0 0323 +tm 11,9 0 0324 +--- 10,10,1 0 0325 +sr 7,12 0 0326 +md 3,4 0 0327 +no 9,4 0 0330 +¬ " +AN 8,6 0 0331 +OR 8,6 0 0332 +hA 13,6 0 0333 +lA 12,6 0 0334 +uA 8,11,1 0 0335 +rA 12,6 0 0336 +dA 8,12 0 0337 +lz 6,9 0 0340 +la 4,10,1 0 0341 +--- 10,9 0 0342 +--- 10,9 0 0343 +--- 10,9 0 0344 +--- 9,10,1 0 0345 +parenlefttp 5,12,4 0 0346 +parenleftex 5,12,4 0 0347 +parenleftbt 5,12,4 0 0350 +bracketlefttp 5,12,4 0 0351 +lc " +bracketleftex 5,12,4 0 0352 +bracketleftbt 5,12,3 0 0353 +lf " +bracelefttp 6,12,4 0 0354 +lt " +braceleftmid 6,12,4 0 0355 +lk " +braceleftbt 6,12,3 0 0356 +lb " +bracerightex 6,12,4 0 0357 +braceleftex " +bv " +--- 10,11 0 0360 +ra 4,10,2 0 0361 +is 4,12,3 0 0362 +--- 9,12,4 0 0363 +--- 9,12,4 0 0364 +--- 9,12,3 0 0365 +parenrighttp 5,12,4 0 0366 +parenrightex 5,12,4 0 0367 +parenrightbt 5,12,4 0 0370 +bracketrighttp 5,12,4 0 0371 +rc " +bracketrightex 5,12,4 0 0372 +bracketrightbt 5,12,3 0 0373 +rf " +bracerighttp 6,12,4 0 0374 +rt " +bracerightmid 6,12,4 0 0375 +rk " +bracerightbt 6,12,3 0 0376 +rb " diff --git a/gnu/usr.bin/groff/devices/devX75-12/TB b/gnu/usr.bin/groff/devices/devX75-12/TB new file mode 100644 index 0000000000..348d388104 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/TB @@ -0,0 +1,306 @@ +name TB +spacewidth 3 +charset +--- 3,1 0 040 +! 4,9 0 041 +" 5,9 0 042 +# 6,9 0 043 +sh " +$ 6,10,1 0 044 +Do " +% 12,9 0 045 +& 10,9 0 046 +' 4,9 0 047 +( 4,9,3 0 050 +) 4,9,3 0 051 +* 6,9 0 052 ++ 7,6 0 053 +, 4,2,2 0 054 +\- 8,4 0 055 +. 4,2 0 056 +/ 4,9 0 057 +sl " +0 6,9 0 060 +1 6,9 0 061 +2 6,9 0 062 +3 6,9 0 063 +4 6,9 0 064 +5 6,9 0 065 +6 6,9 0 066 +7 6,9 0 067 +8 6,9 0 070 +9 6,9 0 071 +: 4,6 0 072 +; 4,6,2 0 073 +< 7,6 0 074 += 7,5 0 075 +eq " +> 8,6 0 076 +? 7,9 0 077 +@ 12,9,2 0 0100 +at " +A 9,9 0 0101 +B 9,9 0 0102 +C 8,9 0 0103 +D 9,9 0 0104 +E 8,9 0 0105 +F 8,9 0 0106 +G 9,9 0 0107 +H 10,9 0 0110 +I 5,9 0 0111 +J 7,9,1 0 0112 +K 10,9 0 0113 +L 8,9 0 0114 +M 11,9 0 0115 +N 9,9 0 0116 +O 9,9 0 0117 +P 8,9 0 0120 +Q 9,9,2 0 0121 +R 9,9 0 0122 +S 7,9 0 0123 +T 9,9 0 0124 +U 9,9 0 0125 +V 9,9 0 0126 +W 12,9 0 0127 +X 9,9 0 0130 +Y 9,9 0 0131 +Z 8,9 0 0132 +[ 4,9,3 0 0133 +lB " +\ 3,9 0 0134 +rs " +] 4,9,3 0 0135 +rB " +^ 7,9 0 0136 +a^ " +ha " +_ 6,0,3 0 0137 +` 4,9 0 0140 +oq " +a 7,6 0 0141 +b 6,9 0 0142 +c 6,6 0 0143 +d 6,9 0 0144 +e 7,6 0 0145 +f 4,9 0 0146 +g 6,6,3 0 0147 +h 6,9 0 0150 +i 3,9 0 0151 +j 3,9,3 0 0152 +k 7,9 0 0153 +l 3,9 0 0154 +m 9,6 0 0155 +n 6,6 0 0156 +o 7,6 0 0157 +p 6,6,3 0 0160 +q 6,6,3 0 0161 +r 5,6 0 0162 +s 6,6 0 0163 +t 4,8 0 0164 +u 6,6 0 0165 +v 6,6 0 0166 +w 9,6 0 0167 +x 6,6 0 0170 +y 6,6,3 0 0171 +z 6,6 0 0172 +{ 5,9,3 0 0173 +lC " +| 3,9,3 0 0174 +or " +ba " +} 5,9,3 0 0175 +rC " +~ 7,6 0 0176 +a~ " +ap " +ti " +r! 4,6,3 0 0241 +¡ " +ct 6,7,2 0 0242 +¢ " +Po 6,9 0 0243 +£ " +Cs 7,8 0 0244 +¤ " +Ye 8,9 0 0245 +¥ " +bb 3,9,3 0 0246 +¦ " +sc 6,9,3 0 0247 +§ " +ad 4,9 0 0250 +¨ " +co 11,9 0 0251 +© " +Of 4,9 0 0252 +ª " +Fo 8,6 0 0253 +« " +no 8,5 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 4,8 0 0257 +¯ " +de 5,9 0 0260 +° " ++- 7,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 4,9 0 0264 +´ " +µ 6,6,3 0 0265 +ps 8,9,3 0 0266 +¶ " +md 3,5 0 0267 +· " +ac 4,0,3 0 0270 +¸ " +S1 4,9 0 0271 +¹ " +Om 4,9 0 0272 +º " +Fc 8,6 0 0273 +» " +14 9,9 0 0274 +¼ " +12 9,9 0 0275 +½ " +34 9,9 0 0276 +¾ " +r? 7,6,3 0 0277 +¿ " +`A 9,12 0 0300 +À " +'A 9,12 0 0301 +Á " +^A 9,12 0 0302 +Â " +~A 9,12 0 0303 +Ã " +:A 9,12 0 0304 +Ä " +oA 9,12 0 0305 +Å " +AE 13,9 0 0306 +Æ " +,C 8,9,3 0 0307 +Ç " +`E 8,12 0 0310 +È " +'E 8,12 0 0311 +É " +^E 8,12 0 0312 +Ê " +:E 8,12 0 0313 +Ë " +`I 5,12 0 0314 +Ì " +'I 5,12 0 0315 +Í " +^I 5,12 0 0316 +Î " +:I 5,12 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 9,12 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,12 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 9,10,1 0 0330 +Ø " +`U 9,12 0 0331 +Ù " +'U 9,12 0 0332 +Ú " +^U 9,12 0 0333 +Û " +:U 9,12 0 0334 +Ü " +'Y 9,12 0 0335 +Ý " +TP 8,9 0 0336 +Þ " +ss 8,9 0 0337 +ß " +`a 7,9 0 0340 +à " +'a 7,9 0 0341 +á " +^a 7,9 0 0342 +â " +~a 7,9 0 0343 +ã " +:a 7,9 0 0344 +ä " +oa 7,10 0 0345 +å " +ae 8,6 0 0346 +æ " +,c 6,6,3 0 0347 +ç " +`e 7,9 0 0350 +è " +'e 7,9 0 0351 +é " +^e 7,9 0 0352 +ê " +:e 7,9 0 0353 +ë " +`i 3,9 0 0354 +ì " +'i 3,9 0 0355 +í " +^i 3,9 0 0356 +î " +:i 3,9 0 0357 +ï " +Sd 7,9 0 0360 +ð " +~n 6,9 0 0361 +ñ " +`o 7,9 0 0362 +ò " +'o 7,9 0 0363 +ó " +^o 7,9 0 0364 +ô " +~o 7,9 0 0365 +õ " +:o 7,9 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 7,7,1 0 0370 +ø " +`u 6,9 0 0371 +ù " +'u 6,9 0 0372 +ú " +^u 6,9 0 0373 +û " +:u 6,9 0 0374 +ü " +'y 6,9,3 0 0375 +ý " +Tp 6,9,3 0 0376 +þ " +:y 6,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/TBI b/gnu/usr.bin/groff/devices/devX75-12/TBI new file mode 100644 index 0000000000..02793a5807 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/TBI @@ -0,0 +1,306 @@ +name TBI +spacewidth 3 +charset +--- 3,1 0 040 +! 5,9 0 041 +" 7,9 0 042 +# 7,9 0 043 +sh " +$ 7,10,1 0 044 +Do " +% 12,9 0 045 +& 9,9 0 046 +' 4,9 0 047 +( 6,9,2 0 050 +) 6,9,2 0 051 +* 6,9 0 052 ++ 7,6 0 053 +, 4,2,1 0 054 +\- 8,4 0 055 +. 4,2 0 056 +/ 5,9 0 057 +sl " +0 6,9 0 060 +1 6,9 0 061 +2 6,9 0 062 +3 6,9 0 063 +4 6,9 0 064 +5 6,9 0 065 +6 6,9 0 066 +7 6,9 0 067 +8 6,9 0 070 +9 6,9 0 071 +: 5,6 0 072 +; 5,6,1 0 073 +< 9,7 0 074 += 8,5 0 075 +eq " +> 9,7 0 076 +? 6,9 0 077 +@ 12,9,1 0 0100 +at " +A 8,9 0 0101 +B 8,9 0 0102 +C 8,9 0 0103 +D 9,9 0 0104 +E 8,9 0 0105 +F 8,9 0 0106 +G 9,9 0 0107 +H 10,9 0 0110 +I 5,9 0 0111 +J 6,9,1 0 0112 +K 8,9 0 0113 +L 8,9 0 0114 +M 11,9 0 0115 +N 9,9 0 0116 +O 9,9 0 0117 +P 8,9 0 0120 +Q 9,9,3 0 0121 +R 8,9 0 0122 +S 8,9 0 0123 +T 7,9 0 0124 +U 10,9 0 0125 +V 8,9 0 0126 +W 11,9 0 0127 +X 8,9 0 0130 +Y 7,9 0 0131 +Z 7,9 0 0132 +[ 6,9,2 0 0133 +lB " +\ 5,9 0 0134 +rs " +] 7,9,2 0 0135 +rB " +^ 8,9 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 5,9 0 0140 +oq " +a 7,6 0 0141 +b 6,9 0 0142 +c 5,6 0 0143 +d 6,9 0 0144 +e 6,6 0 0145 +f 3,9,3 0 0146 +g 5,6,3 0 0147 +h 6,9 0 0150 +i 4,9 0 0151 +j 4,9,3 0 0152 +k 6,9 0 0153 +l 4,9 0 0154 +m 9,6 0 0155 +n 6,6 0 0156 +o 6,6 0 0157 +p 6,6,3 0 0160 +q 6,6,3 0 0161 +r 5,6 0 0162 +s 5,6 0 0163 +t 3,7 0 0164 +u 7,6 0 0165 +v 6,6 0 0166 +w 8,6 0 0167 +x 6,6 0 0170 +y 6,6,3 0 0171 +z 6,6,1 0 0172 +{ 6,9,2 0 0173 +lC " +| 4,9 0 0174 +or " +ba " +} 6,9,2 0 0175 +rC " +~ 9,5 0 0176 +a~ " +ap " +ti " +r! 4,6,3 0 0241 +¡ " +ct 6,8,2 0 0242 +¢ " +Po 6,9 0 0243 +£ " +Cs 8,7 0 0244 +¤ " +Ye 6,9 0 0245 +¥ " +bb 4,9 0 0246 +¦ " +sc 7,9,3 0 0247 +§ " +ad 5,9 0 0250 +¨ " +co 11,9 0 0251 +© " +Of 6,9 0 0252 +ª " +Fo 9,6 0 0253 +« " +no 8,6 0 0254 +¬ " +- 6,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 4,8 0 0257 +¯ " +de 5,9 0 0260 +° " ++- 7,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 4,9 0 0264 +´ " +µ 7,6,3 0 0265 +ps 7,9,3 0 0266 +¶ " +md 3,5 0 0267 +· " +ac 4,0,3 0 0270 +¸ " +S1 4,9 0 0271 +¹ " +Om 6,9 0 0272 +º " +Fc 9,6 0 0273 +» " +14 9,9 0 0274 +¼ " +12 9,9 0 0275 +½ " +34 9,9 0 0276 +¾ " +r? 6,6,3 0 0277 +¿ " +`A 8,12 0 0300 +À " +'A 8,12 0 0301 +Á " +^A 8,12 0 0302 +Â " +~A 8,12 0 0303 +Ã " +:A 8,12 0 0304 +Ä " +oA 8,12 0 0305 +Å " +AE 12,9 0 0306 +Æ " +,C 8,9,3 0 0307 +Ç " +`E 8,12 0 0310 +È " +'E 8,12 0 0311 +É " +^E 8,12 0 0312 +Ê " +:E 8,12 0 0313 +Ë " +`I 5,12 0 0314 +Ì " +'I 5,12 0 0315 +Í " +^I 5,12 0 0316 +Î " +:I 5,12 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 9,11 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,12 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 9,10,1 0 0330 +Ø " +`U 10,12 0 0331 +Ù " +'U 10,12 0 0332 +Ú " +^U 10,12 0 0333 +Û " +:U 10,12 0 0334 +Ü " +'Y 7,12 0 0335 +Ý " +TP 8,9 0 0336 +Þ " +ss 7,9,3 0 0337 +ß " +`a 7,9 0 0340 +à " +'a 7,9 0 0341 +á " +^a 7,9 0 0342 +â " +~a 7,9 0 0343 +ã " +:a 7,9 0 0344 +ä " +oa 7,9 0 0345 +å " +ae 10,6 0 0346 +æ " +,c 5,6,3 0 0347 +ç " +`e 6,9 0 0350 +è " +'e 6,9 0 0351 +é " +^e 6,9 0 0352 +ê " +:e 6,9 0 0353 +ë " +`i 3,9 0 0354 +ì " +'i 3,9 0 0355 +í " +^i 3,9 0 0356 +î " +:i 3,9 0 0357 +ï " +Sd 6,9 0 0360 +ð " +~n 7,9 0 0361 +ñ " +`o 6,9 0 0362 +ò " +'o 6,9 0 0363 +ó " +^o 6,9 0 0364 +ô " +~o 6,9 0 0365 +õ " +:o 6,9 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 6,7,1 0 0370 +ø " +`u 7,9 0 0371 +ù " +'u 7,9 0 0372 +ú " +^u 7,9 0 0373 +û " +:u 7,9 0 0374 +ü " +'y 6,9,3 0 0375 +ý " +Tp 6,9,3 0 0376 +þ " +:y 6,9,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/TI b/gnu/usr.bin/groff/devices/devX75-12/TI new file mode 100644 index 0000000000..dd79bd1d53 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/TI @@ -0,0 +1,306 @@ +name TI +spacewidth 3 +charset +--- 3,1 0 040 +! 4,9 0 041 +" 5,9 0 042 +# 6,9 0 043 +sh " +$ 6,10,1 0 044 +Do " +% 10,9 0 045 +& 9,9 0 046 +' 4,9 0 047 +( 4,9,3 0 050 +) 4,9,3 0 051 +* 6,9 0 052 ++ 8,6 0 053 +, 3,1,2 0 054 +\- 8,4 0 055 +. 3,1 0 056 +/ 4,9 0 057 +sl " +0 6,9 0 060 +1 6,9 0 061 +2 6,9 0 062 +3 6,9 0 063 +4 6,9 0 064 +5 6,9 0 065 +6 6,9 0 066 +7 6,9 0 067 +8 6,9 0 070 +9 6,9 0 071 +: 4,6 0 072 +; 4,6,2 0 073 +< 8,7 0 074 += 8,5 0 075 +eq " +> 8,7 0 076 +? 6,9 0 077 +@ 12,9,1 0 0100 +at " +A 8,9 0 0101 +B 8,9 0 0102 +C 7,9 0 0103 +D 9,9 0 0104 +E 8,9 0 0105 +F 8,9 0 0106 +G 8,9 0 0107 +H 9,9 0 0110 +I 5,9 0 0111 +J 5,9 0 0112 +K 8,9 0 0113 +L 7,9 0 0114 +M 11,9 0 0115 +N 9,9 0 0116 +O 7,9 0 0117 +P 8,9 0 0120 +Q 7,9,2 0 0121 +R 8,9 0 0122 +S 6,9 0 0123 +T 7,9 0 0124 +U 8,9 0 0125 +V 7,9 0 0126 +W 10,9 0 0127 +X 8,9 0 0130 +Y 7,9 0 0131 +Z 7,9 0 0132 +[ 5,9,2 0 0133 +lB " +\ 3,9 0 0134 +rs " +] 5,9,2 0 0135 +rB " +^ 5,9 0 0136 +a^ " +ha " +_ 6,0,3 0 0137 +` 4,9 0 0140 +oq " +a 6,6 0 0141 +b 6,9 0 0142 +c 5,6 0 0143 +d 6,9 0 0144 +e 6,6 0 0145 +f 4,9,3 0 0146 +g 5,6,3 0 0147 +h 6,9 0 0150 +i 4,9 0 0151 +j 4,9,3 0 0152 +k 6,9 0 0153 +l 3,9 0 0154 +m 9,6 0 0155 +n 6,6 0 0156 +o 6,6 0 0157 +p 6,6,3 0 0160 +q 6,6,3 0 0161 +r 4,6 0 0162 +s 5,6 0 0163 +t 4,7 0 0164 +u 6,6 0 0165 +v 6,6 0 0166 +w 9,6 0 0167 +x 6,6 0 0170 +y 6,6,3 0 0171 +z 5,6 0 0172 +{ 5,9,3 0 0173 +lC " +| 4,9,3 0 0174 +or " +ba " +} 5,9,3 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 5,6,3 0 0241 +¡ " +ct 6,8,2 0 0242 +¢ " +Po 6,9 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 6,9 0 0245 +¥ " +bb 4,9,3 0 0246 +¦ " +sc 6,9,2 0 0247 +§ " +ad 4,8 0 0250 +¨ " +co 11,9 0 0251 +© " +Of 4,9 0 0252 +ª " +Fo 6,6 0 0253 +« " +no 8,5 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 4,8 0 0257 +¯ " +de 5,9 0 0260 +° " ++- 8,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 4,9 0 0264 +´ " +µ 6,6,3 0 0265 +ps 7,9,2 0 0266 +¶ " +md 3,4 0 0267 +· " +ac 4,0,3 0 0270 +¸ " +S1 3,9 0 0271 +¹ " +Om 4,9 0 0272 +º " +Fc 6,6 0 0273 +» " +14 9,9 0 0274 +¼ " +12 9,9 0 0275 +½ " +34 9,9 0 0276 +¾ " +r? 6,6,3 0 0277 +¿ " +`A 8,12 0 0300 +À " +'A 8,12 0 0301 +Á " +^A 8,12 0 0302 +Â " +~A 8,12 0 0303 +Ã " +:A 8,11 0 0304 +Ä " +oA 8,12 0 0305 +Å " +AE 11,9 0 0306 +Æ " +,C 7,9,3 0 0307 +Ç " +`E 8,12 0 0310 +È " +'E 8,12 0 0311 +É " +^E 8,12 0 0312 +Ê " +:E 8,11 0 0313 +Ë " +`I 5,12 0 0314 +Ì " +'I 5,12 0 0315 +Í " +^I 5,12 0 0316 +Î " +:I 5,11 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 9,12 0 0321 +Ñ " +`O 7,12 0 0322 +Ò " +'O 7,12 0 0323 +Ó " +^O 7,12 0 0324 +Ô " +~O 7,12 0 0325 +Õ " +:O 7,11 0 0326 +Ö " +mu 8,6 0 0327 +× " +/O 7,10,1 0 0330 +Ø " +`U 8,12 0 0331 +Ù " +'U 8,12 0 0332 +Ú " +^U 8,12 0 0333 +Û " +:U 8,11 0 0334 +Ü " +'Y 7,12 0 0335 +Ý " +TP 8,9 0 0336 +Þ " +ss 6,9,3 0 0337 +ß " +`a 7,9 0 0340 +à " +'a 7,9 0 0341 +á " +^a 7,9 0 0342 +â " +~a 7,9 0 0343 +ã " +:a 7,8 0 0344 +ä " +oa 7,9 0 0345 +å " +ae 9,6 0 0346 +æ " +,c 5,6,3 0 0347 +ç " +`e 6,9 0 0350 +è " +'e 6,9 0 0351 +é " +^e 6,9 0 0352 +ê " +:e 6,8 0 0353 +ë " +`i 4,9 0 0354 +ì " +'i 4,9 0 0355 +í " +^i 4,9 0 0356 +î " +:i 4,8 0 0357 +ï " +Sd 6,9 0 0360 +ð " +~n 6,9 0 0361 +ñ " +`o 6,9 0 0362 +ò " +'o 6,9 0 0363 +ó " +^o 6,9 0 0364 +ô " +~o 6,9 0 0365 +õ " +:o 6,8 0 0366 +ö " +di 8,6 0 0367 +÷ " +/o 6,7,1 0 0370 +ø " +`u 6,9 0 0371 +ù " +'u 6,9 0 0372 +ú " +^u 6,9 0 0373 +û " +:u 6,8 0 0374 +ü " +'y 6,9,3 0 0375 +ý " +Tp 6,9,3 0 0376 +þ " +:y 6,8,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75-12/TR b/gnu/usr.bin/groff/devices/devX75-12/TR new file mode 100644 index 0000000000..da7c961a1e --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75-12/TR @@ -0,0 +1,306 @@ +name TR +spacewidth 3 +charset +--- 3,1 0 040 +! 3,9 0 041 +" 5,9 0 042 +# 6,8 0 043 +sh " +$ 6,10,1 0 044 +Do " +% 9,9 0 045 +& 10,9 0 046 +' 4,9 0 047 +( 5,9,3 0 050 +) 5,9,3 0 051 +* 6,9 0 052 ++ 7,6 0 053 +, 3,1,2 0 054 +\- 8,4 0 055 +. 3,1 0 056 +/ 3,9 0 057 +sl " +0 6,9 0 060 +1 6,9 0 061 +2 6,9 0 062 +3 6,9 0 063 +4 6,9 0 064 +5 6,9 0 065 +6 6,9 0 066 +7 6,9 0 067 +8 6,9 0 070 +9 6,9 0 071 +: 3,6 0 072 +; 3,6,2 0 073 +< 8,6 0 074 += 7,5 0 075 +eq " +> 8,6 0 076 +? 5,9 0 077 +@ 11,9,2 0 0100 +at " +A 9,9 0 0101 +B 8,9 0 0102 +C 8,9 0 0103 +D 9,9 0 0104 +E 8,9 0 0105 +F 8,9 0 0106 +G 9,9 0 0107 +H 9,9 0 0110 +I 4,9 0 0111 +J 4,9 0 0112 +K 8,9 0 0113 +L 7,9 0 0114 +M 11,9 0 0115 +N 9,9 0 0116 +O 9,9 0 0117 +P 7,9 0 0120 +Q 9,9,2 0 0121 +R 8,9 0 0122 +S 7,9 0 0123 +T 7,9 0 0124 +U 8,9 0 0125 +V 9,9 0 0126 +W 12,9 0 0127 +X 8,9 0 0130 +Y 9,9 0 0131 +Z 8,9 0 0132 +[ 5,9,3 0 0133 +lB " +\ 3,9 0 0134 +rs " +] 5,9,3 0 0135 +rB " +^ 6,9 0 0136 +a^ " +ha " +_ 6,0,3 0 0137 +` 4,9 0 0140 +oq " +a 6,6 0 0141 +b 6,9 0 0142 +c 5,6 0 0143 +d 6,9 0 0144 +e 6,6 0 0145 +f 3,9 0 0146 +g 6,6,3 0 0147 +h 6,9 0 0150 +i 3,9 0 0151 +j 3,9,3 0 0152 +k 6,9 0 0153 +l 3,9 0 0154 +m 9,6 0 0155 +n 6,6 0 0156 +o 6,6 0 0157 +p 6,6,3 0 0160 +q 6,6,3 0 0161 +r 4,6 0 0162 +s 6,6 0 0163 +t 4,7 0 0164 +u 6,6 0 0165 +v 6,6 0 0166 +w 9,6 0 0167 +x 6,6 0 0170 +y 6,6,3 0 0171 +z 6,6 0 0172 +{ 6,9,3 0 0173 +lC " +| 3,9 0 0174 +or " +ba " +} 6,9,3 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 4,6,3 0 0241 +¡ " +ct 6,7,1 0 0242 +¢ " +Po 6,9 0 0243 +£ " +Cs 7,8 0 0244 +¤ " +Ye 6,9 0 0245 +¥ " +bb 3,9 0 0246 +¦ " +sc 6,9,3 0 0247 +§ " +ad 3,8 0 0250 +¨ " +co 11,9 0 0251 +© " +Of 5,9 0 0252 +ª " +Fo 7,5 0 0253 +« " +no 8,5 0 0254 +¬ " +- 6,4 0 0255 +hy " +­ " +rg 11,9 0 0256 +® " +a- 4,8 0 0257 +¯ " +de 5,9 0 0260 +° " ++- 7,7 0 0261 +± " +S2 4,9 0 0262 +² " +S3 4,9 0 0263 +³ " +aa 4,9 0 0264 +´ " +µ 6,6,3 0 0265 +ps 7,9,3 0 0266 +¶ " +md 3,4 0 0267 +· " +ac 3,0,3 0 0270 +¸ " +S1 4,9 0 0271 +¹ " +Om 5,9 0 0272 +º " +Fc 7,5 0 0273 +» " +14 9,9 0 0274 +¼ " +12 9,9 0 0275 +½ " +34 9,9 0 0276 +¾ " +r? 5,6,3 0 0277 +¿ " +`A 9,12 0 0300 +À " +'A 9,12 0 0301 +Á " +^A 9,12 0 0302 +Â " +~A 9,12 0 0303 +Ã " +:A 9,11 0 0304 +Ä " +oA 9,12 0 0305 +Å " +AE 11,9 0 0306 +Æ " +,C 8,9,3 0 0307 +Ç " +`E 8,12 0 0310 +È " +'E 8,12 0 0311 +É " +^E 8,12 0 0312 +Ê " +:E 8,11 0 0313 +Ë " +`I 4,12 0 0314 +Ì " +'I 4,12 0 0315 +Í " +^I 4,12 0 0316 +Î " +:I 4,11 0 0317 +Ï " +-D 9,9 0 0320 +Ð " +~N 9,12 0 0321 +Ñ " +`O 9,12 0 0322 +Ò " +'O 9,12 0 0323 +Ó " +^O 9,12 0 0324 +Ô " +~O 9,12 0 0325 +Õ " +:O 9,11 0 0326 +Ö " +mu 7,6 0 0327 +× " +/O 9,10 0 0330 +Ø " +`U 8,12 0 0331 +Ù " +'U 8,12 0 0332 +Ú " +^U 8,12 0 0333 +Û " +:U 8,11 0 0334 +Ü " +'Y 9,12 0 0335 +Ý " +TP 7,9 0 0336 +Þ " +ss 6,9 0 0337 +ß " +`a 6,9 0 0340 +à " +'a 6,9 0 0341 +á " +^a 6,9 0 0342 +â " +~a 6,9 0 0343 +ã " +:a 6,8 0 0344 +ä " +oa 6,9 0 0345 +å " +ae 9,6 0 0346 +æ " +,c 5,6,3 0 0347 +ç " +`e 6,9 0 0350 +è " +'e 6,9 0 0351 +é " +^e 6,9 0 0352 +ê " +:e 6,8 0 0353 +ë " +`i 3,9 0 0354 +ì " +'i 3,9 0 0355 +í " +^i 3,9 0 0356 +î " +:i 3,8 0 0357 +ï " +Sd 6,9 0 0360 +ð " +~n 6,9 0 0361 +ñ " +`o 6,9 0 0362 +ò " +'o 6,9 0 0363 +ó " +^o 6,9 0 0364 +ô " +~o 6,9 0 0365 +õ " +:o 6,8 0 0366 +ö " +di 7,6 0 0367 +÷ " +/o 6,6,1 0 0370 +ø " +`u 6,9 0 0371 +ù " +'u 6,9 0 0372 +ú " +^u 6,9 0 0373 +û " +:u 6,8 0 0374 +ü " +'y 6,9,3 0 0375 +ý " +Tp 6,9,3 0 0376 +þ " +:y 6,8,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/CB b/gnu/usr.bin/groff/devices/devX75/CB new file mode 100644 index 0000000000..5583135951 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/CB @@ -0,0 +1,306 @@ +name CB +spacewidth 6 +charset +--- 6,1 0 040 +! 6,7 0 041 +" 6,6 0 042 +# 6,7 0 043 +sh " +$ 6,7,1 0 044 +Do " +% 6,6 0 045 +& 6,6 0 046 +' 6,7 0 047 +( 6,7,1 0 050 +) 6,7,1 0 051 +* 6,7 0 052 ++ 6,6 0 053 +, 6,1,2 0 054 +\- 6,4 0 055 +. 6,1 0 056 +/ 6,7,1 0 057 +sl " +0 6,7 0 060 +1 6,7 0 061 +2 6,7 0 062 +3 6,7 0 063 +4 6,7 0 064 +5 6,7 0 065 +6 6,7 0 066 +7 6,7 0 067 +8 6,7 0 070 +9 6,7 0 071 +: 6,4 0 072 +; 6,4,2 0 073 +< 6,6 0 074 += 6,5 0 075 +eq " +> 6,6 0 076 +? 6,6 0 077 +@ 6,7,1 0 0100 +at " +A 6,6 0 0101 +B 6,6 0 0102 +C 6,6 0 0103 +D 6,6 0 0104 +E 6,6 0 0105 +F 6,6 0 0106 +G 6,6 0 0107 +H 6,6 0 0110 +I 6,6 0 0111 +J 6,6 0 0112 +K 6,6 0 0113 +L 6,6 0 0114 +M 6,6 0 0115 +N 6,6 0 0116 +O 6,6 0 0117 +P 6,6 0 0120 +Q 6,6,1 0 0121 +R 6,6 0 0122 +S 6,6 0 0123 +T 6,6 0 0124 +U 6,6 0 0125 +V 6,6 0 0126 +W 6,6 0 0127 +X 6,6 0 0130 +Y 6,6 0 0131 +Z 6,6 0 0132 +[ 6,7,1 0 0133 +lB " +\ 6,7,1 0 0134 +rs " +] 6,7,1 0 0135 +rB " +^ 6,7 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 6,7 0 0140 +oq " +a 6,5 0 0141 +b 6,7 0 0142 +c 6,5 0 0143 +d 6,7 0 0144 +e 6,5 0 0145 +f 6,7 0 0146 +g 6,5,2 0 0147 +h 6,7 0 0150 +i 6,7 0 0151 +j 6,7,2 0 0152 +k 6,7 0 0153 +l 6,7 0 0154 +m 6,5 0 0155 +n 6,5 0 0156 +o 6,5 0 0157 +p 6,5,2 0 0160 +q 6,5,2 0 0161 +r 6,5 0 0162 +s 6,5 0 0163 +t 6,7 0 0164 +u 6,5 0 0165 +v 6,5 0 0166 +w 6,5 0 0167 +x 6,5 0 0170 +y 6,5,2 0 0171 +z 6,5 0 0172 +{ 6,7,1 0 0173 +lC " +| 6,7,2 0 0174 +or " +ba " +} 6,7,1 0 0175 +rC " +~ 6,5 0 0176 +a~ " +ap " +ti " +r! 6,5,2 0 0241 +¡ " +ct 6,7,1 0 0242 +¢ " +Po 6,7 0 0243 +£ " +Cs 6,6 0 0244 +¤ " +Ye 6,7 0 0245 +¥ " +bb 6,7,2 0 0246 +¦ " +sc 6,7,1 0 0247 +§ " +ad 6,7 0 0250 +¨ " +co 6,7 0 0251 +© " +Of 6,7 0 0252 +ª " +Fo 6,5 0 0253 +« " +no 6,5 0 0254 +¬ " +- 6,4 0 0255 +hy " +­ " +rg 6,7 0 0256 +® " +a- 6,7 0 0257 +¯ " +de 6,7 0 0260 +° " ++- 6,6 0 0261 +± " +S2 6,7 0 0262 +² " +S3 6,7 0 0263 +³ " +aa 6,8 0 0264 +´ " +µ 6,5,2 0 0265 +ps 6,7,1 0 0266 +¶ " +md 6,5 0 0267 +· " +ac 6,1,2 0 0270 +¸ " +S1 6,7 0 0271 +¹ " +Om 6,7 0 0272 +º " +Fc 6,5 0 0273 +» " +14 6,8,1 0 0274 +¼ " +12 6,8,1 0 0275 +½ " +34 6,8,1 0 0276 +¾ " +r? 6,4,2 0 0277 +¿ " +`A 6,9 0 0300 +À " +'A 6,9 0 0301 +Á " +^A 6,9 0 0302 +Â " +~A 6,9 0 0303 +Ã " +:A 6,9 0 0304 +Ä " +oA 6,9 0 0305 +Å " +AE 6,6 0 0306 +Æ " +,C 6,6,2 0 0307 +Ç " +`E 6,9 0 0310 +È " +'E 6,9 0 0311 +É " +^E 6,9 0 0312 +Ê " +:E 6,9 0 0313 +Ë " +`I 6,9 0 0314 +Ì " +'I 6,9 0 0315 +Í " +^I 6,9 0 0316 +Î " +:I 6,9 0 0317 +Ï " +-D 6,6 0 0320 +Ð " +~N 6,9 0 0321 +Ñ " +`O 6,9 0 0322 +Ò " +'O 6,9 0 0323 +Ó " +^O 6,9 0 0324 +Ô " +~O 6,9 0 0325 +Õ " +:O 6,9 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 6,6,1 0 0330 +Ø " +`U 6,9 0 0331 +Ù " +'U 6,9 0 0332 +Ú " +^U 6,9 0 0333 +Û " +:U 6,9 0 0334 +Ü " +'Y 6,9 0 0335 +Ý " +TP 6,6 0 0336 +Þ " +ss 6,7 0 0337 +ß " +`a 6,8 0 0340 +à " +'a 6,8 0 0341 +á " +^a 6,8 0 0342 +â " +~a 6,8 0 0343 +ã " +:a 6,8 0 0344 +ä " +oa 6,9 0 0345 +å " +ae 6,5 0 0346 +æ " +,c 6,5,2 0 0347 +ç " +`e 6,8 0 0350 +è " +'e 6,8 0 0351 +é " +^e 6,8 0 0352 +ê " +:e 6,8 0 0353 +ë " +`i 6,8 0 0354 +ì " +'i 6,8 0 0355 +í " +^i 6,8 0 0356 +î " +:i 6,8 0 0357 +ï " +Sd 6,8 0 0360 +ð " +~n 6,8 0 0361 +ñ " +`o 6,8 0 0362 +ò " +'o 6,8 0 0363 +ó " +^o 6,8 0 0364 +ô " +~o 6,8 0 0365 +õ " +:o 6,8 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 6,6,1 0 0370 +ø " +`u 6,8 0 0371 +ù " +'u 6,8 0 0372 +ú " +^u 6,8 0 0373 +û " +:u 6,8 0 0374 +ü " +'y 6,8,2 0 0375 +ý " +Tp 6,7,2 0 0376 +þ " +:y 6,8,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/CBI b/gnu/usr.bin/groff/devices/devX75/CBI new file mode 100644 index 0000000000..e6281f44b4 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/CBI @@ -0,0 +1,306 @@ +name CBI +spacewidth 6 +charset +--- 6,1 0 040 +! 6,7 0 041 +" 6,7 0 042 +# 6,7 0 043 +sh " +$ 6,7,1 0 044 +Do " +% 6,7 0 045 +& 6,6 0 046 +' 6,7 0 047 +( 6,7,2 0 050 +) 6,7,2 0 051 +* 6,7 0 052 ++ 6,6 0 053 +, 6,1,2 0 054 +\- 6,4 0 055 +. 6,1 0 056 +/ 6,7,1 0 057 +sl " +0 6,7 0 060 +1 6,7 0 061 +2 6,7 0 062 +3 6,7 0 063 +4 6,7 0 064 +5 6,7 0 065 +6 6,7 0 066 +7 6,7 0 067 +8 6,7 0 070 +9 6,7 0 071 +: 6,4 0 072 +; 6,4,2 0 073 +< 6,6 0 074 += 6,5 0 075 +eq " +> 6,6 0 076 +? 6,7 0 077 +@ 6,7,1 0 0100 +at " +A 6,6 0 0101 +B 6,6 0 0102 +C 6,6 0 0103 +D 6,6 0 0104 +E 6,6 0 0105 +F 6,6 0 0106 +G 6,6 0 0107 +H 6,6 0 0110 +I 6,6 0 0111 +J 6,6 0 0112 +K 6,6 0 0113 +L 6,6 0 0114 +M 6,6 0 0115 +N 6,6 0 0116 +O 6,6 0 0117 +P 6,6 0 0120 +Q 6,6,1 0 0121 +R 6,6 0 0122 +S 6,6 0 0123 +T 6,6 0 0124 +U 6,6 0 0125 +V 6,6 0 0126 +W 6,6 0 0127 +X 6,6 0 0130 +Y 6,6 0 0131 +Z 6,6 0 0132 +[ 6,7,2 0 0133 +lB " +\ 6,7,1 0 0134 +rs " +] 6,7,2 0 0135 +rB " +^ 6,7 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 6,7 0 0140 +oq " +a 6,5 0 0141 +b 6,7 0 0142 +c 6,5 0 0143 +d 6,7 0 0144 +e 6,5 0 0145 +f 6,7 0 0146 +g 6,5,2 0 0147 +h 6,7 0 0150 +i 6,7 0 0151 +j 6,7,2 0 0152 +k 6,7 0 0153 +l 6,7 0 0154 +m 6,5 0 0155 +n 6,5 0 0156 +o 6,5 0 0157 +p 6,5,2 0 0160 +q 6,5,2 0 0161 +r 6,5 0 0162 +s 6,5 0 0163 +t 6,7 0 0164 +u 6,5 0 0165 +v 6,5 0 0166 +w 6,5 0 0167 +x 6,5 0 0170 +y 6,5,2 0 0171 +z 6,5 0 0172 +{ 6,7,2 0 0173 +lC " +| 6,7,1 0 0174 +or " +ba " +} 6,7,2 0 0175 +rC " +~ 6,5 0 0176 +a~ " +ap " +ti " +r! 6,5,2 0 0241 +¡ " +ct 6,7,1 0 0242 +¢ " +Po 6,6 0 0243 +£ " +Cs 6,6 0 0244 +¤ " +Ye 6,6 0 0245 +¥ " +bb 6,7,1 0 0246 +¦ " +sc 6,7,1 0 0247 +§ " +ad 6,7 0 0250 +¨ " +co 6,7 0 0251 +© " +Of 6,6 0 0252 +ª " +Fo 6,4 0 0253 +« " +no 6,5 0 0254 +¬ " +- 6,4 0 0255 +hy " +­ " +rg 6,7 0 0256 +® " +a- 6,7 0 0257 +¯ " +de 6,7 0 0260 +° " ++- 6,6 0 0261 +± " +S2 6,7 0 0262 +² " +S3 6,7 0 0263 +³ " +aa 6,8 0 0264 +´ " +µ 6,5,2 0 0265 +ps 6,7,1 0 0266 +¶ " +md 6,4 0 0267 +· " +ac 6,0,2 0 0270 +¸ " +S1 6,7 0 0271 +¹ " +Om 6,6 0 0272 +º " +Fc 6,4 0 0273 +» " +14 6,8,1 0 0274 +¼ " +12 6,8,1 0 0275 +½ " +34 6,8,1 0 0276 +¾ " +r? 6,6,2 0 0277 +¿ " +`A 6,9 0 0300 +À " +'A 6,9 0 0301 +Á " +^A 6,9 0 0302 +Â " +~A 6,9 0 0303 +Ã " +:A 6,8 0 0304 +Ä " +oA 6,9 0 0305 +Å " +AE 6,6 0 0306 +Æ " +,C 6,6,2 0 0307 +Ç " +`E 6,9 0 0310 +È " +'E 6,9 0 0311 +É " +^E 6,9 0 0312 +Ê " +:E 6,8 0 0313 +Ë " +`I 6,9 0 0314 +Ì " +'I 6,9 0 0315 +Í " +^I 6,9 0 0316 +Î " +:I 6,8 0 0317 +Ï " +-D 6,6 0 0320 +Ð " +~N 6,9 0 0321 +Ñ " +`O 6,9 0 0322 +Ò " +'O 6,9 0 0323 +Ó " +^O 6,9 0 0324 +Ô " +~O 6,9 0 0325 +Õ " +:O 6,8 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 6,7 0 0330 +Ø " +`U 6,9 0 0331 +Ù " +'U 6,9 0 0332 +Ú " +^U 6,9 0 0333 +Û " +:U 6,8 0 0334 +Ü " +'Y 6,9 0 0335 +Ý " +TP 6,6 0 0336 +Þ " +ss 6,7 0 0337 +ß " +`a 6,8 0 0340 +à " +'a 6,8 0 0341 +á " +^a 6,8 0 0342 +â " +~a 6,8 0 0343 +ã " +:a 6,7 0 0344 +ä " +oa 6,9 0 0345 +å " +ae 6,5 0 0346 +æ " +,c 6,5,2 0 0347 +ç " +`e 6,8 0 0350 +è " +'e 6,8 0 0351 +é " +^e 6,8 0 0352 +ê " +:e 6,7 0 0353 +ë " +`i 6,8 0 0354 +ì " +'i 6,8 0 0355 +í " +^i 6,8 0 0356 +î " +:i 6,7 0 0357 +ï " +Sd 6,8 0 0360 +ð " +~n 6,8 0 0361 +ñ " +`o 6,8 0 0362 +ò " +'o 6,8 0 0363 +ó " +^o 6,8 0 0364 +ô " +~o 6,8 0 0365 +õ " +:o 6,7 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 6,5 0 0370 +ø " +`u 6,8 0 0371 +ù " +'u 6,8 0 0372 +ú " +^u 6,8 0 0373 +û " +:u 6,7 0 0374 +ü " +'y 6,8,2 0 0375 +ý " +Tp 6,7,2 0 0376 +þ " +:y 6,7,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/CI b/gnu/usr.bin/groff/devices/devX75/CI new file mode 100644 index 0000000000..f19be187d1 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/CI @@ -0,0 +1,306 @@ +name CI +spacewidth 6 +charset +--- 6,1 0 040 +! 6,7 0 041 +" 6,7 0 042 +# 6,7 0 043 +sh " +$ 6,7,1 0 044 +Do " +% 6,7 0 045 +& 6,6 0 046 +' 6,7 0 047 +( 6,7,1 0 050 +) 6,7,1 0 051 +* 6,7 0 052 ++ 6,6 0 053 +, 6,1,2 0 054 +\- 6,4 0 055 +. 6,1 0 056 +/ 6,7,1 0 057 +sl " +0 6,7 0 060 +1 6,7 0 061 +2 6,7 0 062 +3 6,7 0 063 +4 6,7 0 064 +5 6,7 0 065 +6 6,7 0 066 +7 6,7 0 067 +8 6,7 0 070 +9 6,7 0 071 +: 6,4 0 072 +; 6,4,2 0 073 +< 6,6 0 074 += 6,5 0 075 +eq " +> 6,6 0 076 +? 6,6 0 077 +@ 6,7 0 0100 +at " +A 6,6 0 0101 +B 6,6 0 0102 +C 6,6 0 0103 +D 6,6 0 0104 +E 6,6 0 0105 +F 6,6 0 0106 +G 6,6 0 0107 +H 6,6 0 0110 +I 6,6 0 0111 +J 6,6 0 0112 +K 6,6 0 0113 +L 6,6 0 0114 +M 6,6 0 0115 +N 6,6 0 0116 +O 6,6 0 0117 +P 6,6 0 0120 +Q 6,6,2 0 0121 +R 6,6 0 0122 +S 6,6 0 0123 +T 6,6 0 0124 +U 6,6 0 0125 +V 6,6 0 0126 +W 6,6 0 0127 +X 6,6 0 0130 +Y 6,6 0 0131 +Z 6,6 0 0132 +[ 6,7,1 0 0133 +lB " +\ 6,7,1 0 0134 +rs " +] 6,7,1 0 0135 +rB " +^ 6,7 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 6,7 0 0140 +oq " +a 6,5 0 0141 +b 6,7 0 0142 +c 6,5 0 0143 +d 6,7 0 0144 +e 6,5 0 0145 +f 6,7 0 0146 +g 6,5,2 0 0147 +h 6,7 0 0150 +i 6,7 0 0151 +j 6,7,2 0 0152 +k 6,7 0 0153 +l 6,7 0 0154 +m 6,5 0 0155 +n 6,5 0 0156 +o 6,5 0 0157 +p 6,5,2 0 0160 +q 6,5,2 0 0161 +r 6,5 0 0162 +s 6,5 0 0163 +t 6,7 0 0164 +u 6,5 0 0165 +v 6,5 0 0166 +w 6,5 0 0167 +x 6,5 0 0170 +y 6,5,2 0 0171 +z 6,5 0 0172 +{ 6,7,1 0 0173 +lC " +| 6,7,1 0 0174 +or " +ba " +} 6,7,1 0 0175 +rC " +~ 6,5 0 0176 +a~ " +ap " +ti " +r! 6,5,2 0 0241 +¡ " +ct 6,6 0 0242 +¢ " +Po 6,7 0 0243 +£ " +Cs 6,6 0 0244 +¤ " +Ye 6,6 0 0245 +¥ " +bb 6,7,2 0 0246 +¦ " +sc 6,7,1 0 0247 +§ " +ad 6,7 0 0250 +¨ " +co 6,7 0 0251 +© " +Of 6,7 0 0252 +ª " +Fo 6,4 0 0253 +« " +no 6,5 0 0254 +¬ " +- 6,4 0 0255 +hy " +­ " +rg 6,7 0 0256 +® " +a- 6,7 0 0257 +¯ " +de 6,7 0 0260 +° " ++- 6,6 0 0261 +± " +S2 6,7 0 0262 +² " +S3 6,7 0 0263 +³ " +aa 6,8 0 0264 +´ " +µ 6,5,2 0 0265 +ps 6,7,1 0 0266 +¶ " +md 6,4 0 0267 +· " +ac 6,0,2 0 0270 +¸ " +S1 6,7 0 0271 +¹ " +Om 6,7 0 0272 +º " +Fc 6,4 0 0273 +» " +14 6,8,1 0 0274 +¼ " +12 6,8,1 0 0275 +½ " +34 6,8,1 0 0276 +¾ " +r? 6,4,2 0 0277 +¿ " +`A 6,9 0 0300 +À " +'A 6,9 0 0301 +Á " +^A 6,9 0 0302 +Â " +~A 6,9 0 0303 +Ã " +:A 6,8 0 0304 +Ä " +oA 6,9 0 0305 +Å " +AE 6,6 0 0306 +Æ " +,C 6,6,2 0 0307 +Ç " +`E 6,9 0 0310 +È " +'E 6,9 0 0311 +É " +^E 6,9 0 0312 +Ê " +:E 6,8 0 0313 +Ë " +`I 6,9 0 0314 +Ì " +'I 6,9 0 0315 +Í " +^I 6,9 0 0316 +Î " +:I 6,8 0 0317 +Ï " +-D 6,6 0 0320 +Ð " +~N 6,9 0 0321 +Ñ " +`O 6,9 0 0322 +Ò " +'O 6,9 0 0323 +Ó " +^O 6,9 0 0324 +Ô " +~O 6,9 0 0325 +Õ " +:O 6,8 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 6,6 0 0330 +Ø " +`U 6,9 0 0331 +Ù " +'U 6,9 0 0332 +Ú " +^U 6,9 0 0333 +Û " +:U 6,8 0 0334 +Ü " +'Y 6,9 0 0335 +Ý " +TP 6,6 0 0336 +Þ " +ss 6,7 0 0337 +ß " +`a 6,8 0 0340 +à " +'a 6,8 0 0341 +á " +^a 6,8 0 0342 +â " +~a 6,8 0 0343 +ã " +:a 6,7 0 0344 +ä " +oa 6,9 0 0345 +å " +ae 6,5 0 0346 +æ " +,c 6,5,2 0 0347 +ç " +`e 6,8 0 0350 +è " +'e 6,8 0 0351 +é " +^e 6,8 0 0352 +ê " +:e 6,7 0 0353 +ë " +`i 6,8 0 0354 +ì " +'i 6,8 0 0355 +í " +^i 6,8 0 0356 +î " +:i 6,7 0 0357 +ï " +Sd 6,8 0 0360 +ð " +~n 6,8 0 0361 +ñ " +`o 6,8 0 0362 +ò " +'o 6,8 0 0363 +ó " +^o 6,8 0 0364 +ô " +~o 6,8 0 0365 +õ " +:o 6,7 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 6,6,1 0 0370 +ø " +`u 6,8 0 0371 +ù " +'u 6,8 0 0372 +ú " +^u 6,8 0 0373 +û " +:u 6,7 0 0374 +ü " +'y 6,8,2 0 0375 +ý " +Tp 6,7,2 0 0376 +þ " +:y 6,7,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/CR b/gnu/usr.bin/groff/devices/devX75/CR new file mode 100644 index 0000000000..8bb40b2753 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/CR @@ -0,0 +1,306 @@ +name CR +spacewidth 6 +charset +--- 6,1 0 040 +! 6,7 0 041 +" 6,7 0 042 +# 6,7 0 043 +sh " +$ 6,7,1 0 044 +Do " +% 6,6 0 045 +& 6,6 0 046 +' 6,7 0 047 +( 6,7,2 0 050 +) 6,7,2 0 051 +* 6,7 0 052 ++ 6,6 0 053 +, 6,1,2 0 054 +\- 6,4 0 055 +. 6,1 0 056 +/ 6,7,1 0 057 +sl " +0 6,7 0 060 +1 6,7 0 061 +2 6,7 0 062 +3 6,7 0 063 +4 6,7 0 064 +5 6,7 0 065 +6 6,7 0 066 +7 6,7 0 067 +8 6,7 0 070 +9 6,7 0 071 +: 6,4 0 072 +; 6,4,2 0 073 +< 6,6 0 074 += 6,5 0 075 +eq " +> 6,6 0 076 +? 6,6 0 077 +@ 6,7,1 0 0100 +at " +A 6,6 0 0101 +B 6,6 0 0102 +C 6,6 0 0103 +D 6,6 0 0104 +E 6,6 0 0105 +F 6,6 0 0106 +G 6,6 0 0107 +H 6,6 0 0110 +I 6,6 0 0111 +J 6,6 0 0112 +K 6,6 0 0113 +L 6,6 0 0114 +M 6,6 0 0115 +N 6,6 0 0116 +O 6,6 0 0117 +P 6,6 0 0120 +Q 6,6,1 0 0121 +R 6,6 0 0122 +S 6,6 0 0123 +T 6,6 0 0124 +U 6,6 0 0125 +V 6,6 0 0126 +W 6,6 0 0127 +X 6,6 0 0130 +Y 6,6 0 0131 +Z 6,6 0 0132 +[ 6,7,2 0 0133 +lB " +\ 6,7,1 0 0134 +rs " +] 6,7,2 0 0135 +rB " +^ 6,7 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 6,7 0 0140 +oq " +a 6,5 0 0141 +b 6,7 0 0142 +c 6,5 0 0143 +d 6,7 0 0144 +e 6,5 0 0145 +f 6,7 0 0146 +g 6,5,2 0 0147 +h 6,7 0 0150 +i 6,7 0 0151 +j 6,7,2 0 0152 +k 6,7 0 0153 +l 6,7 0 0154 +m 6,5 0 0155 +n 6,5 0 0156 +o 6,5 0 0157 +p 6,5,2 0 0160 +q 6,5,2 0 0161 +r 6,5 0 0162 +s 6,5 0 0163 +t 6,7 0 0164 +u 6,5 0 0165 +v 6,5 0 0166 +w 6,5 0 0167 +x 6,5 0 0170 +y 6,5,2 0 0171 +z 6,5 0 0172 +{ 6,7,2 0 0173 +lC " +| 6,7,2 0 0174 +or " +ba " +} 6,7,2 0 0175 +rC " +~ 6,5 0 0176 +a~ " +ap " +ti " +r! 6,5,2 0 0241 +¡ " +ct 6,7,1 0 0242 +¢ " +Po 6,7 0 0243 +£ " +Cs 6,6 0 0244 +¤ " +Ye 6,7 0 0245 +¥ " +bb 6,7,2 0 0246 +¦ " +sc 6,6,1 0 0247 +§ " +ad 6,7 0 0250 +¨ " +co 6,7 0 0251 +© " +Of 6,6 0 0252 +ª " +Fo 6,4 0 0253 +« " +no 6,5 0 0254 +¬ " +- 6,4 0 0255 +hy " +­ " +rg 6,7 0 0256 +® " +a- 6,7 0 0257 +¯ " +de 6,7 0 0260 +° " ++- 6,6 0 0261 +± " +S2 6,7 0 0262 +² " +S3 6,7 0 0263 +³ " +aa 6,8 0 0264 +´ " +µ 6,5,2 0 0265 +ps 6,6,1 0 0266 +¶ " +md 6,4 0 0267 +· " +ac 6,1,2 0 0270 +¸ " +S1 6,7 0 0271 +¹ " +Om 6,6 0 0272 +º " +Fc 6,4 0 0273 +» " +14 6,8,1 0 0274 +¼ " +12 6,8,1 0 0275 +½ " +34 6,8,1 0 0276 +¾ " +r? 6,4,2 0 0277 +¿ " +`A 6,9 0 0300 +À " +'A 6,9 0 0301 +Á " +^A 6,9 0 0302 +Â " +~A 6,9 0 0303 +Ã " +:A 6,8 0 0304 +Ä " +oA 6,9 0 0305 +Å " +AE 6,6 0 0306 +Æ " +,C 6,6,2 0 0307 +Ç " +`E 6,9 0 0310 +È " +'E 6,9 0 0311 +É " +^E 6,9 0 0312 +Ê " +:E 6,8 0 0313 +Ë " +`I 6,9 0 0314 +Ì " +'I 6,9 0 0315 +Í " +^I 6,9 0 0316 +Î " +:I 6,8 0 0317 +Ï " +-D 6,6 0 0320 +Ð " +~N 6,9 0 0321 +Ñ " +`O 6,9 0 0322 +Ò " +'O 6,9 0 0323 +Ó " +^O 6,9 0 0324 +Ô " +~O 6,9 0 0325 +Õ " +:O 6,8 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 6,6 0 0330 +Ø " +`U 6,9 0 0331 +Ù " +'U 6,9 0 0332 +Ú " +^U 6,9 0 0333 +Û " +:U 6,8 0 0334 +Ü " +'Y 6,9 0 0335 +Ý " +TP 6,6 0 0336 +Þ " +ss 6,7 0 0337 +ß " +`a 6,8 0 0340 +à " +'a 6,8 0 0341 +á " +^a 6,8 0 0342 +â " +~a 6,8 0 0343 +ã " +:a 6,7 0 0344 +ä " +oa 6,9 0 0345 +å " +ae 6,5 0 0346 +æ " +,c 6,5,2 0 0347 +ç " +`e 6,8 0 0350 +è " +'e 6,8 0 0351 +é " +^e 6,8 0 0352 +ê " +:e 6,7 0 0353 +ë " +`i 6,8 0 0354 +ì " +'i 6,8 0 0355 +í " +^i 6,8 0 0356 +î " +:i 6,7 0 0357 +ï " +Sd 6,8 0 0360 +ð " +~n 6,8 0 0361 +ñ " +`o 6,8 0 0362 +ò " +'o 6,8 0 0363 +ó " +^o 6,8 0 0364 +ô " +~o 6,8 0 0365 +õ " +:o 6,7 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 6,5 0 0370 +ø " +`u 6,8 0 0371 +ù " +'u 6,8 0 0372 +ú " +^u 6,8 0 0373 +û " +:u 6,7 0 0374 +ü " +'y 6,8,2 0 0375 +ý " +Tp 6,7,2 0 0376 +þ " +:y 6,7,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/DESC b/gnu/usr.bin/groff/devices/devX75/DESC new file mode 100644 index 0000000000..172170c9c0 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/DESC @@ -0,0 +1,9 @@ +styles R I B BI +fonts 6 0 0 0 0 0 S +sizes 8 10 12 14 18 24 0 +res 75 +X11 +hor 1 +vert 1 +unitwidth 10 +postpro gxditview diff --git a/gnu/usr.bin/groff/devices/devX75/HB b/gnu/usr.bin/groff/devices/devX75/HB new file mode 100644 index 0000000000..26894e07f7 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/HB @@ -0,0 +1,306 @@ +name HB +spacewidth 3 +charset +--- 3,1 0 040 +! 4,8 0 041 +" 5,8 0 042 +# 6,7 0 043 +sh " +$ 6,8,1 0 044 +Do " +% 8,8 0 045 +& 8,8 0 046 +' 3,8 0 047 +( 4,8,2 0 050 +) 4,8,2 0 051 +* 4,8 0 052 ++ 6,6 0 053 +, 3,2,2 0 054 +\- 7,4 0 055 +. 3,2 0 056 +/ 4,8 0 057 +sl " +0 6,8 0 060 +1 6,8 0 061 +2 6,8 0 062 +3 6,8 0 063 +4 6,8 0 064 +5 6,8 0 065 +6 6,8 0 066 +7 6,8 0 067 +8 6,8 0 070 +9 6,8 0 071 +: 3,6 0 072 +; 3,6,2 0 073 +< 5,6 0 074 += 6,5 0 075 +eq " +> 5,6 0 076 +? 6,8 0 077 +@ 11,7,2 0 0100 +at " +A 8,8 0 0101 +B 7,8 0 0102 +C 8,8 0 0103 +D 7,8 0 0104 +E 6,8 0 0105 +F 6,8 0 0106 +G 8,8 0 0107 +H 7,8 0 0110 +I 3,8 0 0111 +J 6,8 0 0112 +K 7,8 0 0113 +L 6,8 0 0114 +M 10,8 0 0115 +N 8,8 0 0116 +O 8,8 0 0117 +P 7,8 0 0120 +Q 8,8,1 0 0121 +R 7,8 0 0122 +S 7,8 0 0123 +T 7,8 0 0124 +U 7,8 0 0125 +V 8,8 0 0126 +W 11,8 0 0127 +X 8,8 0 0130 +Y 9,8 0 0131 +Z 7,8 0 0132 +[ 4,8,2 0 0133 +lB " +\ 4,8 0 0134 +rs " +] 4,8,2 0 0135 +rB " +^ 5,8 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 3,8 0 0140 +oq " +a 6,6 0 0141 +b 6,8 0 0142 +c 5,6 0 0143 +d 6,8 0 0144 +e 6,6 0 0145 +f 4,8 0 0146 +g 6,6,2 0 0147 +h 6,8 0 0150 +i 3,8 0 0151 +j 3,8,2 0 0152 +k 6,8 0 0153 +l 3,8 0 0154 +m 9,6 0 0155 +n 6,6 0 0156 +o 6,6 0 0157 +p 6,6,2 0 0160 +q 6,6,2 0 0161 +r 4,6 0 0162 +s 6,6 0 0163 +t 4,8 0 0164 +u 6,6 0 0165 +v 6,6 0 0166 +w 8,6 0 0167 +x 7,6 0 0170 +y 6,6,2 0 0171 +z 6,6 0 0172 +{ 5,8,2 0 0173 +lC " +| 3,8,2 0 0174 +or " +ba " +} 5,8,2 0 0175 +rC " +~ 6,4 0 0176 +a~ " +ap " +ti " +r! 4,6,2 0 0241 +¡ " +ct 6,7,1 0 0242 +¢ " +Po 6,8 0 0243 +£ " +Cs 6,7 0 0244 +¤ " +Ye 7,8 0 0245 +¥ " +bb 3,8,2 0 0246 +¦ " +sc 6,8,2 0 0247 +§ " +ad 3,8 0 0250 +¨ " +co 10,8 0 0251 +© " +Of 5,8 0 0252 +ª " +Fo 7,4 0 0253 +« " +no 7,5 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 10,8 0 0256 +® " +a- 3,8 0 0257 +¯ " +de 4,7 0 0260 +° " ++- 6,7 0 0261 +± " +S2 3,7 0 0262 +² " +S3 3,7 0 0263 +³ " +aa 3,9 0 0264 +´ " +µ 6,6,2 0 0265 +ps 6,8,2 0 0266 +¶ " +md 3,4 0 0267 +· " +ac 3,0,2 0 0270 +¸ " +S1 3,7 0 0271 +¹ " +Om 5,8 0 0272 +º " +Fc 7,4 0 0273 +» " +14 9,8 0 0274 +¼ " +12 9,8 0 0275 +½ " +34 9,8 0 0276 +¾ " +r? 6,6,2 0 0277 +¿ " +`A 8,11 0 0300 +À " +'A 8,11 0 0301 +Á " +^A 8,11 0 0302 +Â " +~A 8,11 0 0303 +Ã " +:A 8,10 0 0304 +Ä " +oA 8,11 0 0305 +Å " +AE 10,8 0 0306 +Æ " +,C 8,8,2 0 0307 +Ç " +`E 6,11 0 0310 +È " +'E 6,11 0 0311 +É " +^E 6,11 0 0312 +Ê " +:E 6,10 0 0313 +Ë " +`I 3,11 0 0314 +Ì " +'I 3,11 0 0315 +Í " +^I 3,11 0 0316 +Î " +:I 3,10 0 0317 +Ï " +-D 7,8 0 0320 +Ð " +~N 8,11 0 0321 +Ñ " +`O 8,11 0 0322 +Ò " +'O 8,11 0 0323 +Ó " +^O 8,11 0 0324 +Ô " +~O 8,11 0 0325 +Õ " +:O 8,10 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 8,8 0 0330 +Ø " +`U 7,11 0 0331 +Ù " +'U 7,11 0 0332 +Ú " +^U 7,11 0 0333 +Û " +:U 7,10 0 0334 +Ü " +'Y 9,11 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 6,8 0 0337 +ß " +`a 6,9 0 0340 +à " +'a 6,9 0 0341 +á " +^a 6,9 0 0342 +â " +~a 6,9 0 0343 +ã " +:a 6,9 0 0344 +ä " +oa 6,9 0 0345 +å " +ae 9,6 0 0346 +æ " +,c 5,6,2 0 0347 +ç " +`e 6,9 0 0350 +è " +'e 6,9 0 0351 +é " +^e 6,9 0 0352 +ê " +:e 6,9 0 0353 +ë " +`i 3,9 0 0354 +ì " +'i 3,9 0 0355 +í " +^i 3,9 0 0356 +î " +:i 3,9 0 0357 +ï " +Sd 6,9 0 0360 +ð " +~n 6,9 0 0361 +ñ " +`o 6,9 0 0362 +ò " +'o 6,9 0 0363 +ó " +^o 6,9 0 0364 +ô " +~o 6,9 0 0365 +õ " +:o 6,9 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 6,6 0 0370 +ø " +`u 6,9 0 0371 +ù " +'u 6,9 0 0372 +ú " +^u 6,9 0 0373 +û " +:u 6,9 0 0374 +ü " +'y 6,9,2 0 0375 +ý " +Tp 6,8,2 0 0376 +þ " +:y 6,9,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/HBI b/gnu/usr.bin/groff/devices/devX75/HBI new file mode 100644 index 0000000000..6488003417 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/HBI @@ -0,0 +1,306 @@ +name HBI +spacewidth 3 +charset +--- 3,1 0 040 +! 4,8 0 041 +" 6,8 0 042 +# 7,7 0 043 +sh " +$ 6,8,1 0 044 +Do " +% 9,8 0 045 +& 8,8 0 046 +' 3,8 0 047 +( 5,8,2 0 050 +) 5,8,2 0 051 +* 6,8 0 052 ++ 6,6 0 053 +, 3,2,2 0 054 +\- 7,4 0 055 +. 3,2 0 056 +/ 5,8 0 057 +sl " +0 6,8 0 060 +1 6,8 0 061 +2 6,8 0 062 +3 6,8 0 063 +4 6,8 0 064 +5 6,8 0 065 +6 6,8 0 066 +7 6,8 0 067 +8 6,8 0 070 +9 6,8 0 071 +: 3,6 0 072 +; 3,6,2 0 073 +< 6,6 0 074 += 6,5 0 075 +eq " +> 7,6 0 076 +? 6,8 0 077 +@ 10,7,2 0 0100 +at " +A 8,8 0 0101 +B 7,8 0 0102 +C 7,8 0 0103 +D 8,8 0 0104 +E 6,8 0 0105 +F 5,8 0 0106 +G 8,8 0 0107 +H 7,8 0 0110 +I 3,8 0 0111 +J 6,8 0 0112 +K 8,8 0 0113 +L 6,8 0 0114 +M 10,8 0 0115 +N 8,8 0 0116 +O 8,8 0 0117 +P 7,8 0 0120 +Q 8,8 0 0121 +R 8,8 0 0122 +S 7,8 0 0123 +T 6,8 0 0124 +U 7,8 0 0125 +V 8,8 0 0126 +W 10,8 0 0127 +X 7,8 0 0130 +Y 7,8 0 0131 +Z 7,8 0 0132 +[ 4,8,2 0 0133 +lB " +\ 5,8 0 0134 +rs " +] 4,8,2 0 0135 +rB " +^ 6,8 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 4,8 0 0140 +oq " +a 6,6 0 0141 +b 6,8 0 0142 +c 5,6 0 0143 +d 6,8 0 0144 +e 6,6 0 0145 +f 3,8 0 0146 +g 6,6,2 0 0147 +h 6,8 0 0150 +i 3,8 0 0151 +j 3,8,2 0 0152 +k 6,8 0 0153 +l 3,8 0 0154 +m 9,6 0 0155 +n 6,6 0 0156 +o 6,6 0 0157 +p 6,6,2 0 0160 +q 6,6,2 0 0161 +r 4,6 0 0162 +s 6,6 0 0163 +t 4,8 0 0164 +u 6,6 0 0165 +v 6,6 0 0166 +w 8,6 0 0167 +x 5,6 0 0170 +y 6,6,2 0 0171 +z 5,6 0 0172 +{ 5,8,2 0 0173 +lC " +| 4,8,2 0 0174 +or " +ba " +} 5,8,2 0 0175 +rC " +~ 6,5 0 0176 +a~ " +ap " +ti " +r! 4,6,2 0 0241 +¡ " +ct 7,7,1 0 0242 +¢ " +Po 7,7 0 0243 +£ " +Cs 6,7 0 0244 +¤ " +Ye 7,8 0 0245 +¥ " +bb 4,8,1 0 0246 +¦ " +sc 7,8,2 0 0247 +§ " +ad 4,8 0 0250 +¨ " +co 10,8 0 0251 +© " +Of 5,8 0 0252 +ª " +Fo 8,5 0 0253 +« " +no 7,5 0 0254 +¬ " +- 5,4 0 0255 +hy " +­ " +rg 10,8 0 0256 +® " +a- 4,8 0 0257 +¯ " +de 4,7 0 0260 +° " ++- 6,7 0 0261 +± " +S2 3,7 0 0262 +² " +S3 3,7 0 0263 +³ " +aa 3,9 0 0264 +´ " +µ 6,6,2 0 0265 +ps 7,8,2 0 0266 +¶ " +md 3,4 0 0267 +· " +ac 3,1,2 0 0270 +¸ " +S1 3,7 0 0271 +¹ " +Om 5,8 0 0272 +º " +Fc 8,5 0 0273 +» " +14 9,8 0 0274 +¼ " +12 9,8 0 0275 +½ " +34 9,8 0 0276 +¾ " +r? 6,6,2 0 0277 +¿ " +`A 8,11 0 0300 +À " +'A 8,11 0 0301 +Á " +^A 8,11 0 0302 +Â " +~A 8,11 0 0303 +Ã " +:A 8,10 0 0304 +Ä " +oA 8,11 0 0305 +Å " +AE 10,8 0 0306 +Æ " +,C 7,8,2 0 0307 +Ç " +`E 6,11 0 0310 +È " +'E 6,11 0 0311 +É " +^E 6,11 0 0312 +Ê " +:E 6,10 0 0313 +Ë " +`I 3,11 0 0314 +Ì " +'I 3,11 0 0315 +Í " +^I 3,11 0 0316 +Î " +:I 3,10 0 0317 +Ï " +-D 8,8 0 0320 +Ð " +~N 8,11 0 0321 +Ñ " +`O 8,11 0 0322 +Ò " +'O 8,11 0 0323 +Ó " +^O 8,11 0 0324 +Ô " +~O 8,11 0 0325 +Õ " +:O 8,10 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 8,8 0 0330 +Ø " +`U 7,11 0 0331 +Ù " +'U 7,11 0 0332 +Ú " +^U 7,11 0 0333 +Û " +:U 7,10 0 0334 +Ü " +'Y 7,11 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 7,8 0 0337 +ß " +`a 6,9 0 0340 +à " +'a 6,9 0 0341 +á " +^a 6,9 0 0342 +â " +~a 6,9 0 0343 +ã " +:a 6,8 0 0344 +ä " +oa 6,9 0 0345 +å " +ae 9,6 0 0346 +æ " +,c 5,6,2 0 0347 +ç " +`e 6,9 0 0350 +è " +'e 6,9 0 0351 +é " +^e 6,9 0 0352 +ê " +:e 6,8 0 0353 +ë " +`i 3,9 0 0354 +ì " +'i 3,9 0 0355 +í " +^i 3,9 0 0356 +î " +:i 3,8 0 0357 +ï " +Sd 6,9 0 0360 +ð " +~n 6,9 0 0361 +ñ " +`o 6,9 0 0362 +ò " +'o 6,9 0 0363 +ó " +^o 6,9 0 0364 +ô " +~o 6,9 0 0365 +õ " +:o 6,8 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 8,6 0 0370 +ø " +`u 6,9 0 0371 +ù " +'u 6,9 0 0372 +ú " +^u 6,9 0 0373 +û " +:u 6,8 0 0374 +ü " +'y 6,9,2 0 0375 +ý " +Tp 6,8,2 0 0376 +þ " +:y 6,8,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/HI b/gnu/usr.bin/groff/devices/devX75/HI new file mode 100644 index 0000000000..07509511fa --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/HI @@ -0,0 +1,306 @@ +name HI +spacewidth 3 +charset +--- 3,1 0 040 +! 4,8 0 041 +" 4,8 0 042 +# 7,7 0 043 +sh " +$ 6,8,1 0 044 +Do " +% 9,8 0 045 +& 8,8 0 046 +' 3,8 0 047 +( 4,8,2 0 050 +) 4,8,2 0 051 +* 4,8 0 052 ++ 6,6 0 053 +, 3,1,2 0 054 +\- 7,4 0 055 +. 3,1 0 056 +/ 3,8 0 057 +sl " +0 6,8 0 060 +1 6,8 0 061 +2 6,8 0 062 +3 6,8 0 063 +4 6,8 0 064 +5 6,8 0 065 +6 6,8 0 066 +7 6,8 0 067 +8 6,8 0 070 +9 6,8 0 071 +: 3,6 0 072 +; 3,6,2 0 073 +< 6,6 0 074 += 7,5 0 075 +eq " +> 6,6 0 076 +? 6,8 0 077 +@ 11,8,2 0 0100 +at " +A 7,8 0 0101 +B 7,8 0 0102 +C 8,8 0 0103 +D 8,8 0 0104 +E 7,8 0 0105 +F 6,8 0 0106 +G 8,8 0 0107 +H 8,8 0 0110 +I 3,8 0 0111 +J 5,8 0 0112 +K 7,8 0 0113 +L 5,8 0 0114 +M 9,8 0 0115 +N 8,8 0 0116 +O 8,8 0 0117 +P 7,8 0 0120 +Q 8,8,1 0 0121 +R 7,8 0 0122 +S 7,8 0 0123 +T 5,8 0 0124 +U 8,8 0 0125 +V 7,8 0 0126 +W 10,8 0 0127 +X 7,8 0 0130 +Y 7,8 0 0131 +Z 7,8 0 0132 +[ 4,8,2 0 0133 +lB " +\ 3,8 0 0134 +rs " +] 4,8,2 0 0135 +rB " +^ 6,7 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 3,8 0 0140 +oq " +a 5,6 0 0141 +b 5,8 0 0142 +c 5,6 0 0143 +d 5,8 0 0144 +e 5,6 0 0145 +f 4,8 0 0146 +g 5,6,2 0 0147 +h 6,8 0 0150 +i 2,8 0 0151 +j 2,8,2 0 0152 +k 5,8 0 0153 +l 2,8 0 0154 +m 8,6 0 0155 +n 6,6 0 0156 +o 6,6 0 0157 +p 5,6,2 0 0160 +q 5,6,2 0 0161 +r 4,6 0 0162 +s 5,6 0 0163 +t 4,8 0 0164 +u 5,6 0 0165 +v 6,6 0 0166 +w 8,6 0 0167 +x 6,6 0 0170 +y 5,6,2 0 0171 +z 5,6 0 0172 +{ 4,8,2 0 0173 +lC " +| 3,8,2 0 0174 +or " +ba " +} 4,8,2 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 4,6,2 0 0241 +¡ " +ct 7,7,1 0 0242 +¢ " +Po 6,8 0 0243 +£ " +Cs 6,7 0 0244 +¤ " +Ye 6,8 0 0245 +¥ " +bb 3,8,2 0 0246 +¦ " +sc 6,8,2 0 0247 +§ " +ad 3,8 0 0250 +¨ " +co 10,8 0 0251 +© " +Of 5,8 0 0252 +ª " +Fo 8,5 0 0253 +« " +no 7,5 0 0254 +¬ " +- 6,4 0 0255 +hy " +­ " +rg 10,8 0 0256 +® " +a- 3,8 0 0257 +¯ " +de 4,7 0 0260 +° " ++- 6,7 0 0261 +± " +S2 3,8 0 0262 +² " +S3 3,8 0 0263 +³ " +aa 3,9 0 0264 +´ " +µ 5,6,2 0 0265 +ps 6,8,2 0 0266 +¶ " +md 3,5 0 0267 +· " +ac 3,1,2 0 0270 +¸ " +S1 3,8 0 0271 +¹ " +Om 5,8 0 0272 +º " +Fc 8,5 0 0273 +» " +14 9,8,1 0 0274 +¼ " +12 9,8,1 0 0275 +½ " +34 9,8,1 0 0276 +¾ " +r? 6,6,2 0 0277 +¿ " +`A 7,11 0 0300 +À " +'A 7,11 0 0301 +Á " +^A 7,11 0 0302 +Â " +~A 7,11 0 0303 +Ã " +:A 7,10 0 0304 +Ä " +oA 7,11 0 0305 +Å " +AE 10,8 0 0306 +Æ " +,C 8,8,2 0 0307 +Ç " +`E 7,11 0 0310 +È " +'E 7,11 0 0311 +É " +^E 7,11 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 3,11 0 0314 +Ì " +'I 3,11 0 0315 +Í " +^I 3,11 0 0316 +Î " +:I 3,10 0 0317 +Ï " +-D 8,8 0 0320 +Ð " +~N 8,11 0 0321 +Ñ " +`O 8,11 0 0322 +Ò " +'O 8,11 0 0323 +Ó " +^O 8,11 0 0324 +Ô " +~O 8,11 0 0325 +Õ " +:O 8,10 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 8,8 0 0330 +Ø " +`U 8,11 0 0331 +Ù " +'U 8,11 0 0332 +Ú " +^U 8,11 0 0333 +Û " +:U 8,10 0 0334 +Ü " +'Y 7,11 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 6,8 0 0337 +ß " +`a 5,9 0 0340 +à " +'a 5,9 0 0341 +á " +^a 5,9 0 0342 +â " +~a 5,9 0 0343 +ã " +:a 5,8 0 0344 +ä " +oa 5,9 0 0345 +å " +ae 8,6 0 0346 +æ " +,c 5,6,2 0 0347 +ç " +`e 5,9 0 0350 +è " +'e 5,9 0 0351 +é " +^e 5,9 0 0352 +ê " +:e 5,8 0 0353 +ë " +`i 2,9 0 0354 +ì " +'i 2,9 0 0355 +í " +^i 2,9 0 0356 +î " +:i 2,8 0 0357 +ï " +Sd 6,9 0 0360 +ð " +~n 6,9 0 0361 +ñ " +`o 6,9 0 0362 +ò " +'o 6,9 0 0363 +ó " +^o 6,9 0 0364 +ô " +~o 6,9 0 0365 +õ " +:o 6,8 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 6,6 0 0370 +ø " +`u 5,9 0 0371 +ù " +'u 5,9 0 0372 +ú " +^u 5,9 0 0373 +û " +:u 5,8 0 0374 +ü " +'y 5,9,2 0 0375 +ý " +Tp 5,8,2 0 0376 +þ " +:y 5,8,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/HR b/gnu/usr.bin/groff/devices/devX75/HR new file mode 100644 index 0000000000..aeac63ed27 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/HR @@ -0,0 +1,306 @@ +name HR +spacewidth 3 +charset +--- 3,1 0 040 +! 3,8 0 041 +" 4,8 0 042 +# 6,7 0 043 +sh " +$ 6,8,1 0 044 +Do " +% 9,8 0 045 +& 8,8 0 046 +' 3,8 0 047 +( 4,8,2 0 050 +) 4,8,2 0 051 +* 4,8 0 052 ++ 6,6 0 053 +, 3,1,2 0 054 +\- 7,4 0 055 +. 3,1 0 056 +/ 3,8 0 057 +sl " +0 6,8 0 060 +1 6,8 0 061 +2 6,8 0 062 +3 6,8 0 063 +4 6,8 0 064 +5 6,8 0 065 +6 6,8 0 066 +7 6,8 0 067 +8 6,8 0 070 +9 6,8 0 071 +: 3,6 0 072 +; 3,6,2 0 073 +< 6,6 0 074 += 5,5 0 075 +eq " +> 6,6 0 076 +? 6,8 0 077 +@ 11,8,2 0 0100 +at " +A 7,8 0 0101 +B 7,8 0 0102 +C 8,8 0 0103 +D 8,8 0 0104 +E 7,8 0 0105 +F 6,8 0 0106 +G 8,8 0 0107 +H 8,8 0 0110 +I 3,8 0 0111 +J 5,8 0 0112 +K 7,8 0 0113 +L 6,8 0 0114 +M 9,8 0 0115 +N 8,8 0 0116 +O 8,8 0 0117 +P 7,8 0 0120 +Q 8,8,1 0 0121 +R 7,8 0 0122 +S 7,8 0 0123 +T 5,8 0 0124 +U 8,8 0 0125 +V 7,8 0 0126 +W 9,8 0 0127 +X 7,8 0 0130 +Y 7,8 0 0131 +Z 7,8 0 0132 +[ 3,8,2 0 0133 +lB " +\ 3,8 0 0134 +rs " +] 3,8,2 0 0135 +rB " +^ 6,8 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 3,8 0 0140 +oq " +a 5,6 0 0141 +b 6,8 0 0142 +c 5,6 0 0143 +d 6,8 0 0144 +e 5,6 0 0145 +f 4,8 0 0146 +g 6,6,2 0 0147 +h 6,8 0 0150 +i 2,8 0 0151 +j 2,8,1 0 0152 +k 5,8 0 0153 +l 2,8 0 0154 +m 8,6 0 0155 +n 6,6 0 0156 +o 6,6 0 0157 +p 6,6,2 0 0160 +q 6,6,2 0 0161 +r 4,6 0 0162 +s 5,6 0 0163 +t 4,8 0 0164 +u 5,6 0 0165 +v 6,6 0 0166 +w 8,6 0 0167 +x 6,6 0 0170 +y 5,6,2 0 0171 +z 5,6 0 0172 +{ 3,8,2 0 0173 +lC " +| 3,8,2 0 0174 +or " +ba " +} 3,8,2 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 3,6,2 0 0241 +¡ " +ct 6,7,1 0 0242 +¢ " +Po 6,8 0 0243 +£ " +Cs 5,7 0 0244 +¤ " +Ye 6,8 0 0245 +¥ " +bb 3,8,2 0 0246 +¦ " +sc 6,8,2 0 0247 +§ " +ad 3,8 0 0250 +¨ " +co 9,7 0 0251 +© " +Of 4,8 0 0252 +ª " +Fo 6,5 0 0253 +« " +no 7,5 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 9,7 0 0256 +® " +a- 3,8 0 0257 +¯ " +de 4,7 0 0260 +° " ++- 6,7 0 0261 +± " +S2 3,7 0 0262 +² " +S3 3,7 0 0263 +³ " +aa 3,8 0 0264 +´ " +µ 5,6,2 0 0265 +ps 6,8,2 0 0266 +¶ " +md 3,4 0 0267 +· " +ac 3,0,2 0 0270 +¸ " +S1 3,7 0 0271 +¹ " +Om 4,8 0 0272 +º " +Fc 6,5 0 0273 +» " +14 9,8 0 0274 +¼ " +12 9,8 0 0275 +½ " +34 9,8 0 0276 +¾ " +r? 6,6,2 0 0277 +¿ " +`A 7,11 0 0300 +À " +'A 7,11 0 0301 +Á " +^A 7,11 0 0302 +Â " +~A 7,11 0 0303 +Ã " +:A 7,10 0 0304 +Ä " +oA 7,11 0 0305 +Å " +AE 10,8 0 0306 +Æ " +,C 8,8,2 0 0307 +Ç " +`E 7,11 0 0310 +È " +'E 7,11 0 0311 +É " +^E 7,11 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 3,11 0 0314 +Ì " +'I 3,11 0 0315 +Í " +^I 3,11 0 0316 +Î " +:I 3,10 0 0317 +Ï " +-D 8,8 0 0320 +Ð " +~N 8,11 0 0321 +Ñ " +`O 8,11 0 0322 +Ò " +'O 8,11 0 0323 +Ó " +^O 8,11 0 0324 +Ô " +~O 8,11 0 0325 +Õ " +:O 8,10 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 8,9,1 0 0330 +Ø " +`U 8,11 0 0331 +Ù " +'U 8,11 0 0332 +Ú " +^U 8,11 0 0333 +Û " +:U 8,10 0 0334 +Ü " +'Y 7,11 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 5,8 0 0337 +ß " +`a 5,9 0 0340 +à " +'a 5,9 0 0341 +á " +^a 5,9 0 0342 +â " +~a 5,9 0 0343 +ã " +:a 5,8 0 0344 +ä " +oa 5,9 0 0345 +å " +ae 8,6 0 0346 +æ " +,c 5,6,2 0 0347 +ç " +`e 5,9 0 0350 +è " +'e 5,9 0 0351 +é " +^e 5,9 0 0352 +ê " +:e 5,8 0 0353 +ë " +`i 2,9 0 0354 +ì " +'i 2,9 0 0355 +í " +^i 2,9 0 0356 +î " +:i 2,8 0 0357 +ï " +Sd 6,9 0 0360 +ð " +~n 5,9 0 0361 +ñ " +`o 6,9 0 0362 +ò " +'o 6,9 0 0363 +ó " +^o 6,9 0 0364 +ô " +~o 6,9 0 0365 +õ " +:o 6,8 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 6,6 0 0370 +ø " +`u 5,9 0 0371 +ù " +'u 5,9 0 0372 +ú " +^u 5,9 0 0373 +û " +:u 5,8 0 0374 +ü " +'y 5,9,2 0 0375 +ý " +Tp 6,8,2 0 0376 +þ " +:y 5,8,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/Makefile b/gnu/usr.bin/groff/devices/devX75/Makefile new file mode 100644 index 0000000000..e53468a7bb --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/Makefile @@ -0,0 +1,10 @@ +# Makefile for devX75 + +DEVICE= X75 +FONTFILES= CB CBI CI CR HB HBI HI HR NB NBI NI NR S TB TBI TI TR DESC + +NOOBJ= noobj + +clean cleandir: + +.include "../Makefile.dev" diff --git a/gnu/usr.bin/groff/devices/devX75/NB b/gnu/usr.bin/groff/devices/devX75/NB new file mode 100644 index 0000000000..d783d02b78 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/NB @@ -0,0 +1,306 @@ +name NB +spacewidth 2 +charset +--- 2,1 0 040 +! 3,8 0 041 +" 6,8 0 042 +# 8,8 0 043 +sh " +$ 6,9,1 0 044 +Do " +% 11,8 0 045 +& 9,8 0 046 +' 3,8 0 047 +( 5,8,2 0 050 +) 5,8,2 0 051 +* 6,8 0 052 ++ 6,6 0 053 +, 3,2,2 0 054 +\- 6,4 0 055 +. 3,2 0 056 +/ 5,8 0 057 +sl " +0 6,8 0 060 +1 5,8 0 061 +2 6,8 0 062 +3 6,8 0 063 +4 6,8 0 064 +5 6,8 0 065 +6 6,8 0 066 +7 5,8 0 067 +8 6,8 0 070 +9 6,8 0 071 +: 3,5 0 072 +; 3,5,2 0 073 +< 7,6 0 074 += 6,5 0 075 +eq " +> 7,6 0 076 +? 6,8 0 077 +@ 10,8 0 0100 +at " +A 8,8 0 0101 +B 8,8 0 0102 +C 8,8 0 0103 +D 9,8 0 0104 +E 7,8 0 0105 +F 7,8 0 0106 +G 8,8 0 0107 +H 10,8 0 0110 +I 5,8 0 0111 +J 7,8 0 0112 +K 9,8 0 0113 +L 7,8 0 0114 +M 12,8 0 0115 +N 9,8 0 0116 +O 8,8 0 0117 +P 8,8 0 0120 +Q 8,8,1 0 0121 +R 9,8 0 0122 +S 7,8 0 0123 +T 7,8 0 0124 +U 9,8 0 0125 +V 9,8 0 0126 +W 12,8 0 0127 +X 9,8 0 0130 +Y 9,8 0 0131 +Z 7,8 0 0132 +[ 4,8,2 0 0133 +lB " +\ 5,8 0 0134 +rs " +] 4,8,2 0 0135 +rB " +^ 6,8 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 3,8 0 0140 +oq " +a 5,5 0 0141 +b 7,8 0 0142 +c 6,5 0 0143 +d 7,8 0 0144 +e 6,5 0 0145 +f 5,8 0 0146 +g 6,6,2 0 0147 +h 7,8 0 0150 +i 5,8 0 0151 +j 5,8,2 0 0152 +k 6,8 0 0153 +l 5,8 0 0154 +m 11,5 0 0155 +n 7,5 0 0156 +o 7,5 0 0157 +p 7,5,2 0 0160 +q 7,5,2 0 0161 +r 5,5 0 0162 +s 5,5 0 0163 +t 4,7 0 0164 +u 7,5 0 0165 +v 7,5 0 0166 +w 10,5 0 0167 +x 7,5 0 0170 +y 7,5,2 0 0171 +z 6,5 0 0172 +{ 5,8,2 0 0173 +lC " +| 6,8 0 0174 +or " +ba " +} 5,8,2 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 3,6,2 0 0241 +¡ " +ct 6,6,1 0 0242 +¢ " +Po 8,8 0 0243 +£ " +Cs 8,6 0 0244 +¤ " +Ye 9,8 0 0245 +¥ " +bb 6,8 0 0246 +¦ " +sc 5,8,2 0 0247 +§ " +ad 4,8 0 0250 +¨ " +co 9,8 0 0251 +© " +Of 4,8 0 0252 +ª " +Fo 7,5 0 0253 +« " +no 6,5 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 9,8 0 0256 +® " +a- 5,7 0 0257 +¯ " +de 4,8 0 0260 +° " ++- 6,6 0 0261 +± " +S2 3,8 0 0262 +² " +S3 3,8 0 0263 +³ " +aa 4,8 0 0264 +´ " +µ 7,5,2 0 0265 +ps 8,8 0 0266 +¶ " +md 3,5 0 0267 +· " +ac 4,1,2 0 0270 +¸ " +S1 3,8 0 0271 +¹ " +Om 5,8 0 0272 +º " +Fc 7,5 0 0273 +» " +14 9,8 0 0274 +¼ " +12 9,8 0 0275 +½ " +34 9,8 0 0276 +¾ " +r? 6,6,2 0 0277 +¿ " +`A 8,11 0 0300 +À " +'A 8,11 0 0301 +Á " +^A 8,11 0 0302 +Â " +~A 8,11 0 0303 +Ã " +:A 8,11 0 0304 +Ä " +oA 8,11 0 0305 +Å " +AE 11,8 0 0306 +Æ " +,C 8,8,2 0 0307 +Ç " +`E 7,11 0 0310 +È " +'E 7,11 0 0311 +É " +^E 7,11 0 0312 +Ê " +:E 7,11 0 0313 +Ë " +`I 5,11 0 0314 +Ì " +'I 5,11 0 0315 +Í " +^I 5,11 0 0316 +Î " +:I 5,11 0 0317 +Ï " +-D 9,8 0 0320 +Ð " +~N 9,11 0 0321 +Ñ " +`O 8,11 0 0322 +Ò " +'O 8,11 0 0323 +Ó " +^O 8,11 0 0324 +Ô " +~O 8,11 0 0325 +Õ " +:O 8,11 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 8,8 0 0330 +Ø " +`U 9,11 0 0331 +Ù " +'U 9,11 0 0332 +Ú " +^U 9,11 0 0333 +Û " +:U 9,11 0 0334 +Ü " +'Y 9,11 0 0335 +Ý " +TP 8,8 0 0336 +Þ " +ss 8,8 0 0337 +ß " +`a 5,8 0 0340 +à " +'a 5,8 0 0341 +á " +^a 5,9 0 0342 +â " +~a 5,8 0 0343 +ã " +:a 5,8 0 0344 +ä " +oa 5,8 0 0345 +å " +ae 9,5 0 0346 +æ " +,c 6,5,2 0 0347 +ç " +`e 6,8 0 0350 +è " +'e 6,8 0 0351 +é " +^e 6,9 0 0352 +ê " +:e 6,8 0 0353 +ë " +`i 5,8 0 0354 +ì " +'i 5,8 0 0355 +í " +^i 5,9 0 0356 +î " +:i 5,8 0 0357 +ï " +Sd 7,8 0 0360 +ð " +~n 7,8 0 0361 +ñ " +`o 7,8 0 0362 +ò " +'o 7,8 0 0363 +ó " +^o 7,9 0 0364 +ô " +~o 7,8 0 0365 +õ " +:o 7,8 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 7,6,1 0 0370 +ø " +`u 7,8 0 0371 +ù " +'u 7,8 0 0372 +ú " +^u 7,9 0 0373 +û " +:u 7,8 0 0374 +ü " +'y 7,8,2 0 0375 +ý " +Tp 7,8,2 0 0376 +þ " +:y 7,8,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/NBI b/gnu/usr.bin/groff/devices/devX75/NBI new file mode 100644 index 0000000000..bdad105994 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/NBI @@ -0,0 +1,306 @@ +name NBI +spacewidth 2 +charset +--- 2,1 0 040 +! 5,8 0 041 +" 6,8 0 042 +# 8,7 0 043 +sh " +$ 6,9,1 0 044 +Do " +% 11,8 0 045 +& 10,8 0 046 +' 3,8 0 047 +( 4,8,1 0 050 +) 5,8,1 0 051 +* 6,8 0 052 ++ 6,6 0 053 +, 3,2,2 0 054 +\- 7,4 0 055 +. 3,2 0 056 +/ 5,8 0 057 +sl " +0 6,8 0 060 +1 6,8 0 061 +2 6,8 0 062 +3 6,8 0 063 +4 6,8 0 064 +5 6,8 0 065 +6 6,8 0 066 +7 6,8 0 067 +8 6,8 0 070 +9 6,8 0 071 +: 4,5 0 072 +; 4,5,2 0 073 +< 7,6 0 074 += 6,5 0 075 +eq " +> 7,6 0 076 +? 6,8 0 077 +@ 11,8 0 0100 +at " +A 8,8 0 0101 +B 8,8 0 0102 +C 7,8 0 0103 +D 9,8 0 0104 +E 8,8 0 0105 +F 7,8 0 0106 +G 8,8 0 0107 +H 10,8 0 0110 +I 6,8 0 0111 +J 7,8 0 0112 +K 10,8 0 0113 +L 7,8 0 0114 +M 11,8 0 0115 +N 8,8 0 0116 +O 8,8 0 0117 +P 8,8 0 0120 +Q 8,8,2 0 0121 +R 9,8 0 0122 +S 7,8 0 0123 +T 7,8 0 0124 +U 8,8 0 0125 +V 8,8 0 0126 +W 11,8 0 0127 +X 8,8 0 0130 +Y 7,8 0 0131 +Z 8,8 0 0132 +[ 5,8,1 0 0133 +lB " +\ 5,8 0 0134 +rs " +] 5,8,1 0 0135 +rB " +^ 6,8 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 3,8 0 0140 +oq " +a 7,5 0 0141 +b 7,8 0 0142 +c 6,5 0 0143 +d 7,8 0 0144 +e 6,5 0 0145 +f 5,8,2 0 0146 +g 6,6,2 0 0147 +h 7,8 0 0150 +i 4,8 0 0151 +j 4,8,2 0 0152 +k 7,8 0 0153 +l 4,8 0 0154 +m 10,5 0 0155 +n 7,5 0 0156 +o 6,5 0 0157 +p 7,5,2 0 0160 +q 7,5,2 0 0161 +r 5,5 0 0162 +s 4,5 0 0163 +t 4,7 0 0164 +u 7,5 0 0165 +v 6,5 0 0166 +w 10,5 0 0167 +x 7,5 0 0170 +y 7,5,2 0 0171 +z 5,5 0 0172 +{ 5,8,1 0 0173 +lC " +| 6,8 0 0174 +or " +ba " +} 5,8,1 0 0175 +rC " +~ 7,5 0 0176 +a~ " +ap " +ti " +r! 4,6,2 0 0241 +¡ " +ct 6,6,1 0 0242 +¢ " +Po 7,8 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 7,8 0 0245 +¥ " +bb 6,8 0 0246 +¦ " +sc 6,8,2 0 0247 +§ " +ad 4,8 0 0250 +¨ " +co 9,8 0 0251 +© " +Of 6,8 0 0252 +ª " +Fo 8,5 0 0253 +« " +no 6,5 0 0254 +¬ " +- 4,4 0 0255 +hy " +­ " +rg 9,8 0 0256 +® " +a- 5,7 0 0257 +¯ " +de 4,8 0 0260 +° " ++- 6,6 0 0261 +± " +S2 3,8 0 0262 +² " +S3 3,8 0 0263 +³ " +aa 4,8 0 0264 +´ " +µ 7,5,2 0 0265 +ps 8,8 0 0266 +¶ " +md 3,5 0 0267 +· " +ac 4,1,2 0 0270 +¸ " +S1 3,8 0 0271 +¹ " +Om 5,8 0 0272 +º " +Fc 8,5 0 0273 +» " +14 9,8 0 0274 +¼ " +12 9,8 0 0275 +½ " +34 9,8 0 0276 +¾ " +r? 6,6,2 0 0277 +¿ " +`A 8,11 0 0300 +À " +'A 8,11 0 0301 +Á " +^A 8,11 0 0302 +Â " +~A 8,11 0 0303 +Ã " +:A 8,11 0 0304 +Ä " +oA 8,11 0 0305 +Å " +AE 10,8 0 0306 +Æ " +,C 7,8,2 0 0307 +Ç " +`E 8,11 0 0310 +È " +'E 8,11 0 0311 +É " +^E 8,11 0 0312 +Ê " +:E 8,11 0 0313 +Ë " +`I 6,11 0 0314 +Ì " +'I 6,11 0 0315 +Í " +^I 6,11 0 0316 +Î " +:I 6,11 0 0317 +Ï " +-D 9,8 0 0320 +Ð " +~N 8,11 0 0321 +Ñ " +`O 8,11 0 0322 +Ò " +'O 8,11 0 0323 +Ó " +^O 8,11 0 0324 +Ô " +~O 8,11 0 0325 +Õ " +:O 8,11 0 0326 +Ö " +mu 6,6 0 0327 +× " +/O 8,8 0 0330 +Ø " +`U 8,11 0 0331 +Ù " +'U 8,11 0 0332 +Ú " +^U 8,11 0 0333 +Û " +:U 8,11 0 0334 +Ü " +'Y 7,11 0 0335 +Ý " +TP 8,8 0 0336 +Þ " +ss 8,8,2 0 0337 +ß " +`a 7,8 0 0340 +à " +'a 7,8 0 0341 +á " +^a 7,8 0 0342 +â " +~a 7,8 0 0343 +ã " +:a 7,8 0 0344 +ä " +oa 7,9 0 0345 +å " +ae 9,5 0 0346 +æ " +,c 6,5,2 0 0347 +ç " +`e 6,8 0 0350 +è " +'e 6,8 0 0351 +é " +^e 6,8 0 0352 +ê " +:e 6,8 0 0353 +ë " +`i 4,8 0 0354 +ì " +'i 4,8 0 0355 +í " +^i 4,8 0 0356 +î " +:i 4,8 0 0357 +ï " +Sd 6,8 0 0360 +ð " +~n 7,8 0 0361 +ñ " +`o 6,8 0 0362 +ò " +'o 6,8 0 0363 +ó " +^o 6,8 0 0364 +ô " +~o 6,8 0 0365 +õ " +:o 6,8 0 0366 +ö " +di 6,6 0 0367 +÷ " +/o 6,5 0 0370 +ø " +`u 7,8 0 0371 +ù " +'u 7,8 0 0372 +ú " +^u 7,8 0 0373 +û " +:u 7,8 0 0374 +ü " +'y 7,8,2 0 0375 +ý " +Tp 7,8,2 0 0376 +þ " +:y 7,8,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/NI b/gnu/usr.bin/groff/devices/devX75/NI new file mode 100644 index 0000000000..20c2c42469 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/NI @@ -0,0 +1,306 @@ +name NI +spacewidth 2 +charset +--- 2,1 0 040 +! 4,8 0 041 +" 6,8 0 042 +# 8,7 0 043 +sh " +$ 5,9,1 0 044 +Do " +% 9,8 0 045 +& 9,8 0 046 +' 3,8 0 047 +( 5,8,1 0 050 +) 5,8,1 0 051 +* 6,8 0 052 ++ 6,5 0 053 +, 2,2,1 0 054 +\- 6,3 0 055 +. 2,2 0 056 +/ 5,8,1 0 057 +sl " +0 5,8 0 060 +1 5,8 0 061 +2 5,8 0 062 +3 5,8 0 063 +4 5,8 0 064 +5 5,8 0 065 +6 5,8 0 066 +7 5,8 0 067 +8 5,8 0 070 +9 5,8 0 071 +: 3,5 0 072 +; 3,5,1 0 073 +< 7,5 0 074 += 6,4 0 075 +eq " +> 7,5 0 076 +? 6,8 0 077 +@ 9,8 0 0100 +at " +A 8,8 0 0101 +B 7,8 0 0102 +C 6,8 0 0103 +D 8,8 0 0104 +E 7,8 0 0105 +F 7,8 0 0106 +G 8,8 0 0107 +H 9,8 0 0110 +I 5,8 0 0111 +J 5,8 0 0112 +K 8,8 0 0113 +L 7,8 0 0114 +M 12,8 0 0115 +N 9,8 0 0116 +O 7,8 0 0117 +P 7,8 0 0120 +Q 7,8,2 0 0121 +R 8,8 0 0122 +S 7,8 0 0123 +T 7,8 0 0124 +U 7,8 0 0125 +V 8,8 0 0126 +W 11,8 0 0127 +X 8,8 0 0130 +Y 8,8 0 0131 +Z 8,8 0 0132 +[ 5,8,1 0 0133 +lB " +\ 5,8 0 0134 +rs " +] 5,8,1 0 0135 +rB " +^ 6,8 0 0136 +a^ " +ha " +_ 7,0,2 0 0137 +` 3,8 0 0140 +oq " +a 6,5 0 0141 +b 6,8 0 0142 +c 5,5 0 0143 +d 6,8 0 0144 +e 5,5 0 0145 +f 4,8,2 0 0146 +g 5,6,2 0 0147 +h 6,8 0 0150 +i 3,8 0 0151 +j 3,8,2 0 0152 +k 6,8 0 0153 +l 3,8 0 0154 +m 9,5 0 0155 +n 6,5 0 0156 +o 6,5 0 0157 +p 6,5,2 0 0160 +q 6,5,2 0 0161 +r 5,5 0 0162 +s 4,5 0 0163 +t 3,7 0 0164 +u 6,5 0 0165 +v 6,5 0 0166 +w 9,5 0 0167 +x 6,5 0 0170 +y 6,5,2 0 0171 +z 6,5 0 0172 +{ 5,8,1 0 0173 +lC " +| 6,8 0 0174 +or " +ba " +} 5,8,1 0 0175 +rC " +~ 7,4 0 0176 +a~ " +ap " +ti " +r! 4,6,2 0 0241 +¡ " +ct 5,6,1 0 0242 +¢ " +Po 6,8 0 0243 +£ " +Cs 8,8 0 0244 +¤ " +Ye 8,8 0 0245 +¥ " +bb 6,8 0 0246 +¦ " +sc 6,8,1 0 0247 +§ " +ad 4,7 0 0250 +¨ " +co 9,8 0 0251 +© " +Of 5,8 0 0252 +ª " +Fo 6,5 0 0253 +« " +no 6,4 0 0254 +¬ " +- 4,3 0 0255 +hy " +­ " +rg 9,8 0 0256 +® " +a- 4,7 0 0257 +¯ " +de 4,8 0 0260 +° " ++- 6,5 0 0261 +± " +S2 3,8 0 0262 +² " +S3 3,8 0 0263 +³ " +aa 3,8 0 0264 +´ " +µ 6,5,2 0 0265 +ps 8,8 0 0266 +¶ " +md 3,4 0 0267 +· " +ac 4,1,2 0 0270 +¸ " +S1 3,8 0 0271 +¹ " +Om 4,8 0 0272 +º " +Fc 6,5 0 0273 +» " +14 7,8 0 0274 +¼ " +12 7,8 0 0275 +½ " +34 7,8 0 0276 +¾ " +r? 6,6,2 0 0277 +¿ " +`A 8,11 0 0300 +À " +'A 8,11 0 0301 +Á " +^A 8,11 0 0302 +Â " +~A 8,11 0 0303 +Ã " +:A 8,10 0 0304 +Ä " +oA 8,11 0 0305 +Å " +AE 10,8 0 0306 +Æ " +,C 6,8,2 0 0307 +Ç " +`E 7,11 0 0310 +È " +'E 7,11 0 0311 +É " +^E 7,11 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 5,11 0 0314 +Ì " +'I 5,11 0 0315 +Í " +^I 5,11 0 0316 +Î " +:I 5,10 0 0317 +Ï " +-D 8,8 0 0320 +Ð " +~N 9,11 0 0321 +Ñ " +`O 7,11 0 0322 +Ò " +'O 7,11 0 0323 +Ó " +^O 7,11 0 0324 +Ô " +~O 7,11 0 0325 +Õ " +:O 7,10 0 0326 +Ö " +mu 6,5 0 0327 +× " +/O 7,8 0 0330 +Ø " +`U 7,11 0 0331 +Ù " +'U 7,11 0 0332 +Ú " +^U 7,11 0 0333 +Û " +:U 7,10 0 0334 +Ü " +'Y 8,10 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 7,8,2 0 0337 +ß " +`a 6,8 0 0340 +à " +'a 6,8 0 0341 +á " +^a 6,8 0 0342 +â " +~a 6,8 0 0343 +ã " +:a 6,7 0 0344 +ä " +oa 6,9 0 0345 +å " +ae 8,5 0 0346 +æ " +,c 5,5,2 0 0347 +ç " +`e 5,8 0 0350 +è " +'e 5,8 0 0351 +é " +^e 5,8 0 0352 +ê " +:e 5,7 0 0353 +ë " +`i 3,8 0 0354 +ì " +'i 3,8 0 0355 +í " +^i 3,8 0 0356 +î " +:i 3,7 0 0357 +ï " +Sd 6,8 0 0360 +ð " +~n 6,8 0 0361 +ñ " +`o 6,8 0 0362 +ò " +'o 6,8 0 0363 +ó " +^o 6,8 0 0364 +ô " +~o 6,8 0 0365 +õ " +:o 6,7 0 0366 +ö " +di 6,5 0 0367 +÷ " +/o 6,5 0 0370 +ø " +`u 6,8 0 0371 +ù " +'u 6,8 0 0372 +ú " +^u 6,8 0 0373 +û " +:u 6,7 0 0374 +ü " +'y 6,8,2 0 0375 +ý " +Tp 6,8,2 0 0376 +þ " +:y 6,7,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/NR b/gnu/usr.bin/groff/devices/devX75/NR new file mode 100644 index 0000000000..aa05125e75 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/NR @@ -0,0 +1,306 @@ +name NR +spacewidth 2 +charset +--- 2,1 0 040 +! 4,8 0 041 +" 6,8 0 042 +# 8,8 0 043 +sh " +$ 5,9,1 0 044 +Do " +% 9,8 0 045 +& 10,8 0 046 +' 3,8 0 047 +( 4,8,1 0 050 +) 4,8,1 0 051 +* 6,8 0 052 ++ 6,5 0 053 +, 3,2,1 0 054 +\- 6,3 0 055 +. 4,2 0 056 +/ 4,8 0 057 +sl " +0 5,8 0 060 +1 5,8 0 061 +2 5,8 0 062 +3 5,8 0 063 +4 5,8 0 064 +5 5,8 0 065 +6 5,8 0 066 +7 5,8 0 067 +8 5,8 0 070 +9 5,8 0 071 +: 4,5 0 072 +; 4,5,1 0 073 +< 7,5 0 074 += 6,4 0 075 +eq " +> 7,5 0 076 +? 5,8 0 077 +@ 9,8 0 0100 +at " +A 8,8 0 0101 +B 7,8 0 0102 +C 7,8 0 0103 +D 8,8 0 0104 +E 7,8 0 0105 +F 7,8 0 0106 +G 8,8 0 0107 +H 9,8 0 0110 +I 4,8 0 0111 +J 5,8 0 0112 +K 8,8 0 0113 +L 7,8 0 0114 +M 10,8 0 0115 +N 9,8 0 0116 +O 8,8 0 0117 +P 7,8 0 0120 +Q 8,8,1 0 0121 +R 8,8 0 0122 +S 6,8 0 0123 +T 8,8 0 0124 +U 8,8 0 0125 +V 8,8 0 0126 +W 12,8 0 0127 +X 7,8 0 0130 +Y 8,8 0 0131 +Z 6,8 0 0132 +[ 3,8,1 0 0133 +lB " +\ 5,8 0 0134 +rs " +] 3,8,1 0 0135 +rB " +^ 6,8 0 0136 +a^ " +ha " +_ 6,0,2 0 0137 +` 3,8 0 0140 +oq " +a 6,5 0 0141 +b 5,8 0 0142 +c 5,5 0 0143 +d 6,8 0 0144 +e 5,5 0 0145 +f 4,8 0 0146 +g 6,5,2 0 0147 +h 6,8 0 0150 +i 4,7 0 0151 +j 4,7,2 0 0152 +k 7,8 0 0153 +l 4,8 0 0154 +m 10,5 0 0155 +n 7,5 0 0156 +o 5,5 0 0157 +p 5,5,2 0 0160 +q 6,5,2 0 0161 +r 5,5 0 0162 +s 5,5 0 0163 +t 3,7 0 0164 +u 6,5 0 0165 +v 6,5 0 0166 +w 8,5 0 0167 +x 6,5 0 0170 +y 6,5,2 0 0171 +z 5,5 0 0172 +{ 4,8,1 0 0173 +lC " +| 6,8 0 0174 +or " +ba " +} 4,8,1 0 0175 +rC " +~ 7,4 0 0176 +a~ " +ap " +ti " +r! 4,6,2 0 0241 +¡ " +ct 6,6,1 0 0242 +¢ " +Po 7,8 0 0243 +£ " +Cs 7,7 0 0244 +¤ " +Ye 8,8 0 0245 +¥ " +bb 6,8 0 0246 +¦ " +sc 5,8,2 0 0247 +§ " +ad 4,7 0 0250 +¨ " +co 10,8 0 0251 +© " +Of 5,8 0 0252 +ª " +Fo 6,4 0 0253 +« " +no 6,4 0 0254 +¬ " +- 4,3 0 0255 +hy " +­ " +rg 10,8 0 0256 +® " +a- 5,7 0 0257 +¯ " +de 4,8 0 0260 +° " ++- 6,5 0 0261 +± " +S2 3,8 0 0262 +² " +S3 3,8 0 0263 +³ " +aa 3,8 0 0264 +´ " +µ 6,5,2 0 0265 +ps 7,8,2 0 0266 +¶ " +md 4,4 0 0267 +· " +ac 3,1,2 0 0270 +¸ " +S1 3,8 0 0271 +¹ " +Om 5,8 0 0272 +º " +Fc 6,4 0 0273 +» " +14 7,8 0 0274 +¼ " +12 7,8 0 0275 +½ " +34 7,8 0 0276 +¾ " +r? 5,6,2 0 0277 +¿ " +`A 8,11 0 0300 +À " +'A 8,11 0 0301 +Á " +^A 8,11 0 0302 +Â " +~A 8,11 0 0303 +Ã " +:A 8,10 0 0304 +Ä " +oA 8,11 0 0305 +Å " +AE 11,8 0 0306 +Æ " +,C 7,8,2 0 0307 +Ç " +`E 7,11 0 0310 +È " +'E 7,11 0 0311 +É " +^E 7,11 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 4,11 0 0314 +Ì " +'I 4,11 0 0315 +Í " +^I 4,11 0 0316 +Î " +:I 4,10 0 0317 +Ï " +-D 8,8 0 0320 +Ð " +~N 9,11 0 0321 +Ñ " +`O 8,11 0 0322 +Ò " +'O 8,11 0 0323 +Ó " +^O 8,11 0 0324 +Ô " +~O 8,11 0 0325 +Õ " +:O 8,10 0 0326 +Ö " +mu 6,5 0 0327 +× " +/O 8,8 0 0330 +Ø " +`U 8,11 0 0331 +Ù " +'U 8,11 0 0332 +Ú " +^U 8,11 0 0333 +Û " +:U 8,10 0 0334 +Ü " +'Y 8,10 0 0335 +Ý " +TP 7,8 0 0336 +Þ " +ss 7,8 0 0337 +ß " +`a 6,8 0 0340 +à " +'a 6,8 0 0341 +á " +^a 6,8 0 0342 +â " +~a 6,8 0 0343 +ã " +:a 6,7 0 0344 +ä " +oa 6,8 0 0345 +å " +ae 8,5 0 0346 +æ " +,c 5,5,2 0 0347 +ç " +`e 5,8 0 0350 +è " +'e 5,8 0 0351 +é " +^e 5,8 0 0352 +ê " +:e 5,7 0 0353 +ë " +`i 4,8 0 0354 +ì " +'i 4,8 0 0355 +í " +^i 4,8 0 0356 +î " +:i 4,7 0 0357 +ï " +Sd 5,8 0 0360 +ð " +~n 7,8 0 0361 +ñ " +`o 5,8 0 0362 +ò " +'o 5,8 0 0363 +ó " +^o 5,8 0 0364 +ô " +~o 5,8 0 0365 +õ " +:o 5,7 0 0366 +ö " +di 6,5 0 0367 +÷ " +/o 5,5,1 0 0370 +ø " +`u 6,8 0 0371 +ù " +'u 6,8 0 0372 +ú " +^u 6,8 0 0373 +û " +:u 6,7 0 0374 +ü " +'y 6,8,2 0 0375 +ý " +Tp 5,8,2 0 0376 +þ " +:y 6,7,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/S b/gnu/usr.bin/groff/devices/devX75/S new file mode 100644 index 0000000000..77e2f5fb3c --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/S @@ -0,0 +1,226 @@ +name S +special +spacewidth 3 +charset +--- 3,1 0 040 +! 3,7 0 041 +fa 7,7 0 042 +# 5,7 0 043 +sh " +te 6,7 0 044 +% 8,7 0 045 +& 7,7 0 046 +st 5,5 0 047 +( 4,7,2 0 050 +) 4,7,2 0 051 +** 5,6 0 052 ++ 6,5 0 053 +pl " +, 2,1,2 0 054 +\- 6,3 0 055 +mi " +. 2,2 0 056 +/ 3,7 0 057 +sl " +0 5,7 0 060 +1 5,7 0 061 +2 5,7 0 062 +3 5,7 0 063 +4 5,7 0 064 +5 5,7 0 065 +6 5,7 0 066 +7 5,7 0 067 +8 5,7 0 070 +9 5,7 0 071 +: 2,5 0 072 +; 2,5,2 0 073 +< 7,5 0 074 += 6,4 0 075 +eq " +> 6,5 0 076 +? 5,7 0 077 +=~ 6,6 0 0100 +*A 8,7 0 0101 +*B 6,7 0 0102 +*X 8,7 0 0103 +*D 7,7 0 0104 +*E 6,7 0 0105 +*F 8,7 0 0106 +*G 6,7 0 0107 +*Y 8,7 0 0110 +*I 3,7 0 0111 ++h 7,7 0 0112 +*K 7,7 0 0113 +*L 7,7 0 0114 +*M 10,7 0 0115 +*N 8,7 0 0116 +*O 7,7 0 0117 +*P 8,7 0 0120 +*H 7,7 0 0121 +*R 6,7 0 0122 +*S 6,7 0 0123 +*T 6,7 0 0124 +--- 8,7 0 0125 +ts 5,5,2 0 0126 +*W 9,7 0 0127 +*C 7,7 0 0130 +*Q 9,7 0 0131 +*Z 6,7 0 0132 +[ 3,7,2 0 0133 +lB " +tf 7,5 0 0134 +3d " +] 3,7,2 0 0135 +rB " +pp 7,7 0 0136 +_ 5,0,3 0 0137 +rn 5,10 0 0140 +*a 7,5 0 0141 +*b 5,8,2 0 0142 +*x 6,5,2 0 0143 +*d 5,8 0 0144 +*e 5,5 0 0145 +*f 6,7,2 0 0146 +*g 6,5,2 0 0147 +*y 6,5,2 0 0150 +*i 4,5 0 0151 ++f 6,5,2 0 0152 +*k 6,5 0 0153 +*l 6,8 0 0154 +*m 6,5,2 0 0155 +µ " +*n 6,5 0 0156 +*o 5,5 0 0157 +*p 6,5 0 0160 +*h 5,7 0 0161 +*r 5,5,3 0 0162 +*s 6,5 0 0163 +*t 5,5 0 0164 +*u 6,5 0 0165 ++p 8,6 0 0166 +*w 8,5 0 0167 +*c 5,8,2 0 0170 +*q 7,5,2 0 0171 +*z 5,8,2 0 0172 +lC 5,7,2 0 0173 +{ " +ba 2,7,2 0 0174 +or " +| " +rC 5,7,2 0 0175 +} " +ap 6,4 0 0176 +*U 7,7 0 0241 +fm 3,8 0 0242 +<= 6,7 0 0243 +f/ 3,7 0 0244 +if 7,4 0 0245 +Fn 5,7,2 0 0246 +CL 7,5 0 0247 +DI 7,5 0 0250 +HE 7,5 0 0251 +SP 7,5 0 0252 +<> 10,5 0 0253 +<- 10,5 0 0254 +ua 6,10,4 0 0255 +arrowverttp " +-> 10,5 0 0256 +da 6,10,2 0 0257 +arrowvertbt " +de 4,7 0 0260 +° " ++- 6,7 0 0261 +± " +sd 4,8 0 0262 +>= 6,7 0 0263 +mu 6,5 0 0264 +× " +pt 7,4 0 0265 +pd 5,8 0 0266 +bu 5,4 0 0267 +di 6,5 0 0270 +÷ " +!= 6,5 0 0271 +== 6,5 0 0272 +~= 6,5 0 0273 +~~ " +--- 9,1 0 0274 +arrowvertex 6,10,4 0 0275 +an 10,3 0 0276 +CR 7,6 0 0277 +Ah 8,7 0 0300 +Im 7,8,1 0 0301 +Re 8,8 0 0302 +wp 9,6,2 0 0303 +c* 8,7 0 0304 +c+ 8,7 0 0305 +es 8,8,1 0 0306 +ca 8,5 0 0307 +cu 8,5 0 0310 +sp 7,5 0 0311 +ip 7,5,2 0 0312 +--- 7,6,1 0 0313 +sb 7,5 0 0314 +ib 7,5,2 0 0315 +mo 7,5 0 0316 +nm 7,6,1 0 0317 +/_ 8,7 0 0320 +gr 7,7 0 0321 +rg 8,7,1 0 0322 +co 8,7,1 0 0323 +tm 10,7 0 0324 +--- 9,8,1 0 0325 +sr 6,10 0 0326 +md 3,3 0 0327 +no 7,3 0 0330 +¬ " +AN 6,5 0 0331 +OR 6,5 0 0332 +hA 11,5 0 0333 +lA 10,5 0 0334 +uA 6,10 0 0335 +rA 10,5 0 0336 +dA 6,10 0 0337 +lz 7,7 0 0340 +la 3,7,2 0 0341 +--- 8,7,1 0 0342 +--- 8,7,1 0 0343 +--- 9,7 0 0344 +--- 7,8,1 0 0345 +parenlefttp 4,10,4 0 0346 +parenleftex 4,10,4 0 0347 +parenleftbt 4,10,4 0 0350 +bracketlefttp 4,10,4 0 0351 +lc " +bracketleftex 4,10,4 0 0352 +bracketleftbt 4,10,2 0 0353 +lf " +bracelefttp 5,10,4 0 0354 +lt " +braceleftmid 5,10,4 0 0355 +lk " +braceleftbt 5,10,2 0 0356 +lb " +bracerightex 5,10,4 0 0357 +braceleftex " +bv " +--- 8,9 0 0360 +ra 3,7,2 0 0361 +is 3,10,2 0 0362 +--- 7,10,4 0 0363 +--- 7,10,4 0 0364 +--- 7,10,2 0 0365 +parenrighttp 4,10,4 0 0366 +parenrightex 4,10,4 0 0367 +parenrightbt 4,10,4 0 0370 +bracketrighttp 4,10,4 0 0371 +rc " +bracketrightex 4,10,4 0 0372 +bracketrightbt 4,10,2 0 0373 +rf " +bracerighttp 5,10,4 0 0374 +rt " +bracerightmid 5,10,4 0 0375 +rk " +bracerightbt 5,10,2 0 0376 +rb " diff --git a/gnu/usr.bin/groff/devices/devX75/TB b/gnu/usr.bin/groff/devices/devX75/TB new file mode 100644 index 0000000000..090771428f --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/TB @@ -0,0 +1,306 @@ +name TB +spacewidth 2 +charset +--- 2,1 0 040 +! 4,7 0 041 +" 5,7 0 042 +# 6,7 0 043 +sh " +$ 5,8,1 0 044 +Do " +% 9,7 0 045 +& 9,7 0 046 +' 4,7 0 047 +( 4,7,3 0 050 +) 4,7,3 0 051 +* 6,7 0 052 ++ 6,5 0 053 +, 4,2,1 0 054 +\- 7,3 0 055 +. 3,2 0 056 +/ 3,7 0 057 +sl " +0 5,7 0 060 +1 5,7 0 061 +2 5,7 0 062 +3 5,7 0 063 +4 5,7 0 064 +5 5,7 0 065 +6 5,7 0 066 +7 5,7 0 067 +8 5,7 0 070 +9 5,7 0 071 +: 4,5 0 072 +; 4,5,1 0 073 +< 6,5 0 074 += 6,4 0 075 +eq " +> 6,5 0 076 +? 6,7 0 077 +@ 11,7,2 0 0100 +at " +A 7,7 0 0101 +B 7,7 0 0102 +C 7,7 0 0103 +D 8,7 0 0104 +E 7,7 0 0105 +F 7,7 0 0106 +G 7,7 0 0107 +H 9,7 0 0110 +I 5,7 0 0111 +J 5,7,1 0 0112 +K 8,7 0 0113 +L 7,7 0 0114 +M 10,7 0 0115 +N 8,7 0 0116 +O 7,7 0 0117 +P 6,7 0 0120 +Q 7,7,2 0 0121 +R 7,7 0 0122 +S 6,7 0 0123 +T 7,7 0 0124 +U 7,7 0 0125 +V 8,7 0 0126 +W 10,7 0 0127 +X 7,7 0 0130 +Y 8,7 0 0131 +Z 7,7 0 0132 +[ 4,7,3 0 0133 +lB " +\ 3,7 0 0134 +rs " +] 4,7,3 0 0135 +rB " +^ 6,7 0 0136 +a^ " +ha " +_ 5,0,3 0 0137 +` 4,7 0 0140 +oq " +a 5,5 0 0141 +b 5,7 0 0142 +c 5,5 0 0143 +d 6,7 0 0144 +e 5,5 0 0145 +f 3,7 0 0146 +g 5,5,3 0 0147 +h 5,7 0 0150 +i 3,8 0 0151 +j 4,8,2 0 0152 +k 5,7 0 0153 +l 3,7 0 0154 +m 8,5 0 0155 +n 6,5 0 0156 +o 6,5 0 0157 +p 5,5,2 0 0160 +q 5,5,2 0 0161 +r 4,5 0 0162 +s 4,5 0 0163 +t 4,7 0 0164 +u 5,5 0 0165 +v 5,5 0 0166 +w 6,5 0 0167 +x 5,5 0 0170 +y 5,5,2 0 0171 +z 5,5 0 0172 +{ 4,7,3 0 0173 +lC " +| 3,7,2 0 0174 +or " +ba " +} 4,7,3 0 0175 +rC " +~ 6,4 0 0176 +a~ " +ap " +ti " +r! 4,4,3 0 0241 +¡ " +ct 6,6,1 0 0242 +¢ " +Po 6,7 0 0243 +£ " +Cs 6,6 0 0244 +¤ " +Ye 6,7 0 0245 +¥ " +bb 3,7,2 0 0246 +¦ " +sc 5,7,2 0 0247 +§ " +ad 4,8 0 0250 +¨ " +co 9,7 0 0251 +© " +Of 4,7 0 0252 +ª " +Fo 6,5 0 0253 +« " +no 7,5 0 0254 +¬ " +- 3,3 0 0255 +hy " +­ " +rg 9,7 0 0256 +® " +a- 4,7 0 0257 +¯ " +de 4,7 0 0260 +° " ++- 6,7 0 0261 +± " +S2 3,7 0 0262 +² " +S3 3,7 0 0263 +³ " +aa 4,7 0 0264 +´ " +µ 5,5,3 0 0265 +ps 6,7,3 0 0266 +¶ " +md 3,4 0 0267 +· " +ac 3,0,3 0 0270 +¸ " +S1 3,7 0 0271 +¹ " +Om 4,7 0 0272 +º " +Fc 6,5 0 0273 +» " +14 7,7 0 0274 +¼ " +12 7,7 0 0275 +½ " +34 7,7 0 0276 +¾ " +r? 6,4,3 0 0277 +¿ " +`A 7,10 0 0300 +À " +'A 7,10 0 0301 +Á " +^A 7,10 0 0302 +Â " +~A 7,10 0 0303 +Ã " +:A 7,10 0 0304 +Ä " +oA 7,10 0 0305 +Å " +AE 9,7 0 0306 +Æ " +,C 7,7,3 0 0307 +Ç " +`E 7,10 0 0310 +È " +'E 7,10 0 0311 +É " +^E 7,10 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 5,10 0 0314 +Ì " +'I 5,10 0 0315 +Í " +^I 5,10 0 0316 +Î " +:I 5,10 0 0317 +Ï " +-D 8,7 0 0320 +Ð " +~N 8,10 0 0321 +Ñ " +`O 7,10 0 0322 +Ò " +'O 7,10 0 0323 +Ó " +^O 7,10 0 0324 +Ô " +~O 7,10 0 0325 +Õ " +:O 7,10 0 0326 +Ö " +mu 6,5 0 0327 +× " +/O 7,8,1 0 0330 +Ø " +`U 7,10 0 0331 +Ù " +'U 7,10 0 0332 +Ú " +^U 7,10 0 0333 +Û " +:U 7,10 0 0334 +Ü " +'Y 8,10 0 0335 +Ý " +TP 6,7 0 0336 +Þ " +ss 6,7 0 0337 +ß " +`a 5,8 0 0340 +à " +'a 5,8 0 0341 +á " +^a 5,8 0 0342 +â " +~a 5,8 0 0343 +ã " +:a 5,8 0 0344 +ä " +oa 5,8 0 0345 +å " +ae 8,5 0 0346 +æ " +,c 5,5,3 0 0347 +ç " +`e 5,8 0 0350 +è " +'e 5,8 0 0351 +é " +^e 5,8 0 0352 +ê " +:e 5,8 0 0353 +ë " +`i 3,8 0 0354 +ì " +'i 3,8 0 0355 +í " +^i 3,8 0 0356 +î " +:i 3,8 0 0357 +ï " +Sd 6,8 0 0360 +ð " +~n 6,8 0 0361 +ñ " +`o 6,8 0 0362 +ò " +'o 6,8 0 0363 +ó " +^o 6,8 0 0364 +ô " +~o 6,8 0 0365 +õ " +:o 6,8 0 0366 +ö " +di 6,5 0 0367 +÷ " +/o 6,6,1 0 0370 +ø " +`u 5,8 0 0371 +ù " +'u 5,8 0 0372 +ú " +^u 5,8 0 0373 +û " +:u 5,8 0 0374 +ü " +'y 5,8,3 0 0375 +ý " +Tp 5,7,3 0 0376 +þ " +:y 5,8,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/TBI b/gnu/usr.bin/groff/devices/devX75/TBI new file mode 100644 index 0000000000..37d92b0a70 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/TBI @@ -0,0 +1,306 @@ +name TBI +spacewidth 2 +charset +--- 2,1 0 040 +! 6,7 0 041 +" 6,7 0 042 +# 8,7 0 043 +sh " +$ 5,7 0 044 +Do " +% 11,7 0 045 +& 8,7 0 046 +' 4,7 0 047 +( 6,7,2 0 050 +) 6,7,2 0 051 +* 7,8 0 052 ++ 7,5 0 053 +, 4,2,1 0 054 +\- 7,3 0 055 +. 4,2 0 056 +/ 5,7 0 057 +sl " +0 5,7 0 060 +1 5,7 0 061 +2 5,7 0 062 +3 5,7 0 063 +4 5,7 0 064 +5 5,7 0 065 +6 5,7 0 066 +7 5,7 0 067 +8 5,7 0 070 +9 5,7 0 071 +: 3,5 0 072 +; 5,5,1 0 073 +< 6,5 0 074 += 7,4 0 075 +eq " +> 6,5 0 076 +? 5,7 0 077 +@ 11,7,2 0 0100 +at " +A 6,7 0 0101 +B 7,7 0 0102 +C 7,7 0 0103 +D 7,7 0 0104 +E 7,7 0 0105 +F 7,7 0 0106 +G 7,7 0 0107 +H 8,7 0 0110 +I 4,7 0 0111 +J 5,7,1 0 0112 +K 7,7 0 0113 +L 6,7 0 0114 +M 10,7 0 0115 +N 8,7 0 0116 +O 7,7 0 0117 +P 6,7 0 0120 +Q 7,7,2 0 0121 +R 7,7 0 0122 +S 6,7 0 0123 +T 6,7 0 0124 +U 8,7 0 0125 +V 7,7 0 0126 +W 9,7 0 0127 +X 7,7 0 0130 +Y 6,7 0 0131 +Z 6,7 0 0132 +[ 5,7,2 0 0133 +lB " +\ 5,7 0 0134 +rs " +] 5,7,2 0 0135 +rB " +^ 7,7 0 0136 +a^ " +ha " +_ 5,0,2 0 0137 +` 4,7 0 0140 +oq " +a 5,5 0 0141 +b 5,7 0 0142 +c 5,5 0 0143 +d 5,7 0 0144 +e 5,5 0 0145 +f 4,7,3 0 0146 +g 4,5,3 0 0147 +h 5,7 0 0150 +i 3,7 0 0151 +j 3,7,3 0 0152 +k 5,7 0 0153 +l 3,7 0 0154 +m 7,5 0 0155 +n 5,5 0 0156 +o 5,5 0 0157 +p 5,5,3 0 0160 +q 5,5,3 0 0161 +r 4,5 0 0162 +s 4,5 0 0163 +t 4,6 0 0164 +u 5,5 0 0165 +v 4,5 0 0166 +w 7,5 0 0167 +x 4,5 0 0170 +y 5,5,2 0 0171 +z 4,5 0 0172 +{ 5,7,2 0 0173 +lC " +| 3,7 0 0174 +or " +ba " +} 5,7,2 0 0175 +rC " +~ 6,4 0 0176 +a~ " +ap " +ti " +r! 5,5,3 0 0241 +¡ " +ct 5,6,1 0 0242 +¢ " +Po 5,7 0 0243 +£ " +Cs 7,6 0 0244 +¤ " +Ye 5,7 0 0245 +¥ " +bb 3,7 0 0246 +¦ " +sc 5,7,2 0 0247 +§ " +ad 5,7 0 0250 +¨ " +co 9,7 0 0251 +© " +Of 5,7 0 0252 +ª " +Fo 8,5 0 0253 +« " +no 7,5 0 0254 +¬ " +- 3,3 0 0255 +hy " +­ " +rg 9,7 0 0256 +® " +a- 4,7 0 0257 +¯ " +de 4,7 0 0260 +° " ++- 7,7 0 0261 +± " +S2 3,7 0 0262 +² " +S3 3,7 0 0263 +³ " +aa 4,7 0 0264 +´ " +µ 5,5,3 0 0265 +ps 8,7,3 0 0266 +¶ " +md 4,4 0 0267 +· " +ac 3,0,3 0 0270 +¸ " +S1 3,7 0 0271 +¹ " +Om 5,7 0 0272 +º " +Fc 8,5 0 0273 +» " +14 7,7 0 0274 +¼ " +12 7,7 0 0275 +½ " +34 7,7 0 0276 +¾ " +r? 5,5,3 0 0277 +¿ " +`A 6,10 0 0300 +À " +'A 6,10 0 0301 +Á " +^A 6,10 0 0302 +Â " +~A 6,10 0 0303 +Ã " +:A 6,10 0 0304 +Ä " +oA 6,10 0 0305 +Å " +AE 9,7 0 0306 +Æ " +,C 7,7,3 0 0307 +Ç " +`E 7,10 0 0310 +È " +'E 7,10 0 0311 +É " +^E 7,10 0 0312 +Ê " +:E 7,10 0 0313 +Ë " +`I 4,10 0 0314 +Ì " +'I 4,10 0 0315 +Í " +^I 4,10 0 0316 +Î " +:I 4,10 0 0317 +Ï " +-D 7,7 0 0320 +Ð " +~N 8,10 0 0321 +Ñ " +`O 7,10 0 0322 +Ò " +'O 7,10 0 0323 +Ó " +^O 7,10 0 0324 +Ô " +~O 7,10 0 0325 +Õ " +:O 7,10 0 0326 +Ö " +mu 7,5 0 0327 +× " +/O 7,8,1 0 0330 +Ø " +`U 8,10 0 0331 +Ù " +'U 8,10 0 0332 +Ú " +^U 8,10 0 0333 +Û " +:U 8,10 0 0334 +Ü " +'Y 6,10 0 0335 +Ý " +TP 6,7 0 0336 +Þ " +ss 6,7,3 0 0337 +ß " +`a 5,8 0 0340 +à " +'a 5,8 0 0341 +á " +^a 5,8 0 0342 +â " +~a 5,8 0 0343 +ã " +:a 5,8 0 0344 +ä " +oa 5,8 0 0345 +å " +ae 8,5 0 0346 +æ " +,c 5,5,3 0 0347 +ç " +`e 5,8 0 0350 +è " +'e 5,8 0 0351 +é " +^e 5,8 0 0352 +ê " +:e 5,8 0 0353 +ë " +`i 3,8 0 0354 +ì " +'i 3,8 0 0355 +í " +^i 3,8 0 0356 +î " +:i 3,8 0 0357 +ï " +Sd 5,8 0 0360 +ð " +~n 5,8 0 0361 +ñ " +`o 5,8 0 0362 +ò " +'o 5,8 0 0363 +ó " +^o 5,8 0 0364 +ô " +~o 5,8 0 0365 +õ " +:o 5,8 0 0366 +ö " +di 7,5 0 0367 +÷ " +/o 5,6,1 0 0370 +ø " +`u 5,8 0 0371 +ù " +'u 5,8 0 0372 +ú " +^u 5,8 0 0373 +û " +:u 5,8 0 0374 +ü " +'y 5,8,2 0 0375 +ý " +Tp 5,7,3 0 0376 +þ " +:y 5,8,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/TI b/gnu/usr.bin/groff/devices/devX75/TI new file mode 100644 index 0000000000..daa858e2ee --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/TI @@ -0,0 +1,306 @@ +name TI +spacewidth 2 +charset +--- 2,1 0 040 +! 3,7 0 041 +" 4,8 0 042 +# 5,7 0 043 +sh " +$ 5,8,1 0 044 +Do " +% 9,7 0 045 +& 8,7 0 046 +' 3,8 0 047 +( 3,7,2 0 050 +) 4,7,2 0 051 +* 5,7 0 052 ++ 7,5 0 053 +, 3,1,2 0 054 +\- 7,3 0 055 +. 3,1 0 056 +/ 4,7 0 057 +sl " +0 5,7 0 060 +1 5,7 0 061 +2 5,7 0 062 +3 5,7 0 063 +4 5,7 0 064 +5 5,7 0 065 +6 5,7 0 066 +7 5,7 0 067 +8 5,7 0 070 +9 5,7 0 071 +: 3,5 0 072 +; 3,5,2 0 073 +< 5,5 0 074 += 7,4 0 075 +eq " +> 5,5 0 076 +? 5,7 0 077 +@ 10,7,2 0 0100 +at " +A 7,7 0 0101 +B 6,7 0 0102 +C 7,7 0 0103 +D 7,7 0 0104 +E 6,7 0 0105 +F 6,7 0 0106 +G 8,7 0 0107 +H 7,7 0 0110 +I 3,7 0 0111 +J 4,7 0 0112 +K 7,7 0 0113 +L 6,7 0 0114 +M 10,7 0 0115 +N 7,7 0 0116 +O 7,7 0 0117 +P 6,7 0 0120 +Q 7,7,2 0 0121 +R 6,7 0 0122 +S 5,7 0 0123 +T 6,7 0 0124 +U 7,7 0 0125 +V 6,7 0 0126 +W 9,7 0 0127 +X 6,7 0 0130 +Y 6,7 0 0131 +Z 6,7 0 0132 +[ 4,7,2 0 0133 +lB " +\ 5,7 0 0134 +rs " +] 4,7,2 0 0135 +rB " +^ 5,7 0 0136 +a^ " +ha " +_ 5,0,3 0 0137 +` 3,8 0 0140 +oq " +a 5,5 0 0141 +b 5,7 0 0142 +c 5,5 0 0143 +d 5,7 0 0144 +e 5,5 0 0145 +f 3,7,3 0 0146 +g 4,5,3 0 0147 +h 5,7 0 0150 +i 3,7 0 0151 +j 3,7,3 0 0152 +k 5,7 0 0153 +l 3,7 0 0154 +m 7,5 0 0155 +n 5,5 0 0156 +o 5,5 0 0157 +p 5,5,3 0 0160 +q 5,5,3 0 0161 +r 4,5 0 0162 +s 4,5 0 0163 +t 3,6 0 0164 +u 5,5 0 0165 +v 5,5 0 0166 +w 7,5 0 0167 +x 4,5 0 0170 +y 5,5,3 0 0171 +z 4,5 0 0172 +{ 4,7,2 0 0173 +lC " +| 3,7,2 0 0174 +or " +ba " +} 4,7,2 0 0175 +rC " +~ 6,4 0 0176 +a~ " +ap " +ti " +r! 4,5,2 0 0241 +¡ " +ct 5,6,1 0 0242 +¢ " +Po 5,7 0 0243 +£ " +Cs 5,7 0 0244 +¤ " +Ye 7,7 0 0245 +¥ " +bb 3,7,2 0 0246 +¦ " +sc 5,7,2 0 0247 +§ " +ad 3,7 0 0250 +¨ " +co 9,7 0 0251 +© " +Of 4,7 0 0252 +ª " +Fo 5,5 0 0253 +« " +no 7,4 0 0254 +¬ " +- 4,3 0 0255 +hy " +­ " +rg 9,7 0 0256 +® " +a- 3,7 0 0257 +¯ " +de 4,7 0 0260 +° " ++- 7,7 0 0261 +± " +S2 3,7 0 0262 +² " +S3 3,7 0 0263 +³ " +aa 3,8 0 0264 +´ " +µ 5,5,3 0 0265 +ps 6,7,3 0 0266 +¶ " +md 3,3 0 0267 +· " +ac 3,0,2 0 0270 +¸ " +S1 3,7 0 0271 +¹ " +Om 3,7 0 0272 +º " +Fc 5,5 0 0273 +» " +14 7,7 0 0274 +¼ " +12 7,7 0 0275 +½ " +34 7,7 0 0276 +¾ " +r? 5,5,2 0 0277 +¿ " +`A 7,10 0 0300 +À " +'A 7,10 0 0301 +Á " +^A 7,10 0 0302 +Â " +~A 7,10 0 0303 +Ã " +:A 7,9 0 0304 +Ä " +oA 7,10 0 0305 +Å " +AE 8,7 0 0306 +Æ " +,C 7,7,2 0 0307 +Ç " +`E 6,10 0 0310 +È " +'E 6,10 0 0311 +É " +^E 6,10 0 0312 +Ê " +:E 6,9 0 0313 +Ë " +`I 3,10 0 0314 +Ì " +'I 3,10 0 0315 +Í " +^I 3,10 0 0316 +Î " +:I 3,9 0 0317 +Ï " +-D 7,7 0 0320 +Ð " +~N 7,10 0 0321 +Ñ " +`O 7,10 0 0322 +Ò " +'O 7,10 0 0323 +Ó " +^O 7,10 0 0324 +Ô " +~O 7,10 0 0325 +Õ " +:O 7,9 0 0326 +Ö " +mu 7,5 0 0327 +× " +/O 7,8,1 0 0330 +Ø " +`U 7,10 0 0331 +Ù " +'U 7,10 0 0332 +Ú " +^U 7,10 0 0333 +Û " +:U 7,9 0 0334 +Ü " +'Y 6,9 0 0335 +Ý " +TP 6,7 0 0336 +Þ " +ss 6,7,2 0 0337 +ß " +`a 5,8 0 0340 +à " +'a 5,8 0 0341 +á " +^a 5,8 0 0342 +â " +~a 5,8 0 0343 +ã " +:a 5,7 0 0344 +ä " +oa 5,8 0 0345 +å " +ae 7,5 0 0346 +æ " +,c 5,5,2 0 0347 +ç " +`e 5,8 0 0350 +è " +'e 5,8 0 0351 +é " +^e 5,8 0 0352 +ê " +:e 5,7 0 0353 +ë " +`i 3,8 0 0354 +ì " +'i 3,8 0 0355 +í " +^i 3,8 0 0356 +î " +:i 3,7 0 0357 +ï " +Sd 5,8 0 0360 +ð " +~n 5,8 0 0361 +ñ " +`o 5,8 0 0362 +ò " +'o 5,8 0 0363 +ó " +^o 5,8 0 0364 +ô " +~o 5,8 0 0365 +õ " +:o 5,7 0 0366 +ö " +di 7,5 0 0367 +÷ " +/o 5,6,1 0 0370 +ø " +`u 5,8 0 0371 +ù " +'u 5,8 0 0372 +ú " +^u 5,8 0 0373 +û " +:u 5,7 0 0374 +ü " +'y 5,8,3 0 0375 +ý " +Tp 5,7,3 0 0376 +þ " +:y 5,7,3 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devX75/TR b/gnu/usr.bin/groff/devices/devX75/TR new file mode 100644 index 0000000000..c1ac847b40 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devX75/TR @@ -0,0 +1,306 @@ +name TR +spacewidth 2 +charset +--- 2,1 0 040 +! 3,7 0 041 +" 4,7 0 042 +# 5,7 0 043 +sh " +$ 5,8,1 0 044 +Do " +% 8,7 0 045 +& 8,7 0 046 +' 3,7 0 047 +( 4,7,2 0 050 +) 4,7,2 0 051 +* 5,7 0 052 ++ 6,5 0 053 +, 3,1,2 0 054 +\- 7,3 0 055 +. 3,1 0 056 +/ 3,7 0 057 +sl " +0 5,7 0 060 +1 5,7 0 061 +2 5,7 0 062 +3 5,7 0 063 +4 5,7 0 064 +5 5,7 0 065 +6 5,7 0 066 +7 5,7 0 067 +8 5,7 0 070 +9 5,7 0 071 +: 3,5 0 072 +; 3,5,2 0 073 +< 5,5 0 074 += 6,4 0 075 +eq " +> 5,5 0 076 +? 4,7 0 077 +@ 9,7,2 0 0100 +at " +A 8,7 0 0101 +B 6,7 0 0102 +C 7,7 0 0103 +D 7,7 0 0104 +E 6,7 0 0105 +F 6,7 0 0106 +G 7,7 0 0107 +H 8,7 0 0110 +I 4,7 0 0111 +J 4,7 0 0112 +K 7,7 0 0113 +L 6,7 0 0114 +M 10,7 0 0115 +N 8,7 0 0116 +O 7,7 0 0117 +P 6,7 0 0120 +Q 7,7,2 0 0121 +R 7,7 0 0122 +S 5,7 0 0123 +T 6,7 0 0124 +U 8,7 0 0125 +V 8,7 0 0126 +W 10,7 0 0127 +X 8,7 0 0130 +Y 8,7 0 0131 +Z 6,7 0 0132 +[ 3,7,2 0 0133 +lB " +\ 3,7 0 0134 +rs " +] 3,7,2 0 0135 +rB " +^ 5,7 0 0136 +a^ " +ha " +_ 5,0,3 0 0137 +` 3,7 0 0140 +oq " +a 4,5 0 0141 +b 5,7 0 0142 +c 4,5 0 0143 +d 5,7 0 0144 +e 4,5 0 0145 +f 4,7 0 0146 +g 5,5,2 0 0147 +h 5,7 0 0150 +i 3,7 0 0151 +j 3,7,2 0 0152 +k 5,7 0 0153 +l 4,7 0 0154 +m 8,5 0 0155 +n 5,5 0 0156 +o 5,5 0 0157 +p 5,5,2 0 0160 +q 5,5,2 0 0161 +r 4,5 0 0162 +s 4,5 0 0163 +t 4,6 0 0164 +u 5,5 0 0165 +v 5,5 0 0166 +w 8,5 0 0167 +x 6,5 0 0170 +y 5,5,2 0 0171 +z 5,5 0 0172 +{ 4,7,2 0 0173 +lC " +| 2,7,2 0 0174 +or " +ba " +} 4,7,2 0 0175 +rC " +~ 7,4 0 0176 +a~ " +ap " +ti " +r! 3,5,2 0 0241 +¡ " +ct 5,6,1 0 0242 +¢ " +Po 5,7 0 0243 +£ " +Cs 5,7 0 0244 +¤ " +Ye 5,7 0 0245 +¥ " +bb 2,7 0 0246 +¦ " +sc 5,8,1 0 0247 +§ " +ad 5,7 0 0250 +¨ " +co 9,7 0 0251 +© " +Of 4,7 0 0252 +ª " +Fo 5,5 0 0253 +« " +no 7,4 0 0254 +¬ " +- 4,3 0 0255 +hy " +­ " +rg 9,7 0 0256 +® " +a- 4,7 0 0257 +¯ " +de 4,7 0 0260 +° " ++- 6,7 0 0261 +± " +S2 3,7 0 0262 +² " +S3 3,7 0 0263 +³ " +aa 3,7 0 0264 +´ " +µ 5,5,2 0 0265 +ps 6,7,2 0 0266 +¶ " +md 2,3 0 0267 +· " +ac 4,0,3 0 0270 +¸ " +S1 3,7 0 0271 +¹ " +Om 4,7 0 0272 +º " +Fc 5,5 0 0273 +» " +14 8,7 0 0274 +¼ " +12 8,7 0 0275 +½ " +34 8,7 0 0276 +¾ " +r? 4,5,2 0 0277 +¿ " +`A 8,10 0 0300 +À " +'A 8,10 0 0301 +Á " +^A 8,10 0 0302 +Â " +~A 8,10 0 0303 +Ã " +:A 8,9 0 0304 +Ä " +oA 8,10 0 0305 +Å " +AE 9,7 0 0306 +Æ " +,C 7,7,3 0 0307 +Ç " +`E 6,10 0 0310 +È " +'E 6,10 0 0311 +É " +^E 6,10 0 0312 +Ê " +:E 6,9 0 0313 +Ë " +`I 4,10 0 0314 +Ì " +'I 4,10 0 0315 +Í " +^I 4,10 0 0316 +Î " +:I 4,9 0 0317 +Ï " +-D 7,7 0 0320 +Ð " +~N 8,10 0 0321 +Ñ " +`O 7,10 0 0322 +Ò " +'O 7,10 0 0323 +Ó " +^O 7,10 0 0324 +Ô " +~O 7,10 0 0325 +Õ " +:O 7,9 0 0326 +Ö " +mu 6,5 0 0327 +× " +/O 8,8,1 0 0330 +Ø " +`U 8,10 0 0331 +Ù " +'U 8,10 0 0332 +Ú " +^U 8,10 0 0333 +Û " +:U 8,9 0 0334 +Ü " +'Y 8,10 0 0335 +Ý " +TP 6,7 0 0336 +Þ " +ss 5,7 0 0337 +ß " +`a 4,8 0 0340 +à " +'a 4,8 0 0341 +á " +^a 4,8 0 0342 +â " +~a 4,8 0 0343 +ã " +:a 4,7 0 0344 +ä " +oa 4,8 0 0345 +å " +ae 6,5 0 0346 +æ " +,c 4,5,3 0 0347 +ç " +`e 4,8 0 0350 +è " +'e 4,8 0 0351 +é " +^e 4,8 0 0352 +ê " +:e 4,7 0 0353 +ë " +`i 4,8 0 0354 +ì " +'i 4,8 0 0355 +í " +^i 4,8 0 0356 +î " +:i 4,7 0 0357 +ï " +Sd 5,8 0 0360 +ð " +~n 5,8 0 0361 +ñ " +`o 5,8 0 0362 +ò " +'o 5,8 0 0363 +ó " +^o 5,8 0 0364 +ô " +~o 5,8 0 0365 +õ " +:o 5,7 0 0366 +ö " +di 6,5 0 0367 +÷ " +/o 5,6,1 0 0370 +ø " +`u 5,8 0 0371 +ù " +'u 5,8 0 0372 +ú " +^u 5,8 0 0373 +û " +:u 5,7 0 0374 +ü " +'y 5,8,2 0 0375 +ý " +Tp 5,7,2 0 0376 +þ " +:y 5,7,2 0 0377 +ÿ " diff --git a/gnu/usr.bin/groff/devices/devascii/DESC.proto b/gnu/usr.bin/groff/devices/devascii/DESC.proto new file mode 100644 index 0000000000..88399ab16d --- /dev/null +++ b/gnu/usr.bin/groff/devices/devascii/DESC.proto @@ -0,0 +1,8 @@ +res 240 +hor 24 +vert 40 +unitwidth 10 +sizes 10 0 +fonts 4 R I B BI +tcommand +postpro grotty diff --git a/gnu/usr.bin/groff/devices/devascii/Makefile b/gnu/usr.bin/groff/devices/devascii/Makefile new file mode 100644 index 0000000000..47057d87d4 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devascii/Makefile @@ -0,0 +1,6 @@ +# Makefile for devascii + +DEVICE= ascii + +.include "../Makefile.tty" +.include "../Makefile.dev" diff --git a/gnu/usr.bin/groff/devices/devascii/R.proto b/gnu/usr.bin/groff/devices/devascii/R.proto new file mode 100644 index 0000000000..876c74c4a6 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devascii/R.proto @@ -0,0 +1,165 @@ +name R +internalname 0 +spacewidth 24 +charset +! 24 0 0041 +" 24 0 0042 +lq " +rq " +# 24 0 0043 +sh " +$ 24 0 0044 +Do " +% 24 0 0045 +& 24 0 0046 +' 24 0 0047 +aa " +fm " +aq " +( 24 0 0050 +) 24 0 0051 +* 24 0 0052 +** " ++ 24 0 0053 +pl " +, 24 0 0054 +\- 24 0 0055 +hy " +- " +mi " +en " +. 24 0 0056 +/ 24 0 0057 +sl " +f/ " +0 24 0 0060 +1 24 0 0061 +2 24 0 0062 +3 24 0 0063 +4 24 0 0064 +5 24 0 0065 +6 24 0 0066 +7 24 0 0067 +8 24 0 0070 +9 24 0 0071 +: 24 0 0072 +; 24 0 0073 +< 24 0 0074 +la " +fo " += 24 0 0075 +eq " +> 24 0 0076 +ra " +fc " +? 24 0 0077 +@ 24 0 0100 +at " +A 24 0 0101 +*A " +B 24 0 0102 +*B " +C 24 0 0103 +D 24 0 0104 +E 24 0 0105 +*E " +F 24 0 0106 +G 24 0 0107 +H 24 0 0110 +*Y " +I 24 0 0111 +*I " +J 24 0 0112 +K 24 0 0113 +*K " +L 24 0 0114 +M 24 0 0115 +*M " +N 24 0 0116 +*N " +O 24 0 0117 +ci " +*O " +P 24 0 0120 +*R " +Q 24 0 0121 +R 24 0 0122 +S 24 0 0123 +T 24 0 0124 +*T " +U 24 0 0125 +V 24 0 0126 +W 24 0 0127 +X 24 0 0130 +*X " +Y 24 0 0131 +*U " +Z 24 0 0132 +*Z " +[ 24 0 0133 +lB " +\ 24 0 0134 +rs " +] 24 0 0135 +rB " +a^ 24 0 0136 +^ " +ha " +_ 24 0 0137 +ru " +ul " +` 24 0 0140 +oq " +ga " +a 24 0 0141 +b 24 0 0142 +c 24 0 0143 +d 24 0 0144 +e 24 0 0145 +f 24 0 0146 +g 24 0 0147 +h 24 0 0150 +i 24 0 0151 +.i " +j 24 0 0152 +k 24 0 0153 +l 24 0 0154 +m 24 0 0155 +n 24 0 0156 +o 24 0 0157 +*o " +p 24 0 0160 +q 24 0 0161 +r 24 0 0162 +s 24 0 0163 +t 24 0 0164 +u 24 0 0165 +v 24 0 0166 +w 24 0 0167 +x 24 0 0170 +mu " +y 24 0 0171 +z 24 0 0172 +lC 24 0 0173 +{ " +ba 24 0 0174 +or " +bv " +br " +| " +lb " +lc " +lf " +lk " +lt " +rb " +rc " +rf " +rk " +rt " +rC 24 0 0175 +} " +a~ 24 0 0176 +~ " +ap " +ti " diff --git a/gnu/usr.bin/groff/devices/devdvi/B b/gnu/usr.bin/groff/devices/devdvi/B new file mode 100644 index 0000000000..240731a75e --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/B @@ -0,0 +1,347 @@ +name B +internalname cmbx10 +spacewidth 401952 +ligatures ff fi fl ffi ffl 0 +checksum 452076118 +designsize 10485760 +kernpairs +ff ' 114323 +ff ? 114323 +ff ! 114323 +ff ) 114323 +ff rB 114323 +ff ] 114323 +' ' -100488 +' ? 133984 +' ! 133984 +A t -33496 +A C -33496 +A O -33496 +A G -33496 +A U -33496 +A Q -33496 +A T -100488 +A Y -100488 +A V -133984 +A W -133984 +D X -33496 +D W -33496 +D A -33496 +D V -33496 +D Y -33496 +F o -100488 +F e -100488 +F u -100488 +F r -100488 +F a -100488 +F A -133984 +F O -33496 +F C -33496 +F G -33496 +F Q -33496 +I I 33496 +K O -33496 +K C -33496 +K G -33496 +K Q -33496 +L T -100488 +L Y -100488 +L V -133984 +L W -133984 +O X -33496 +O W -33496 +O A -33496 +O V -33496 +O Y -33496 +P A -100488 +P o -33496 +P e -33496 +P a -33496 +P . -100488 +P , -100488 +R t -33496 +R C -33496 +R O -33496 +R G -33496 +R U -33496 +R Q -33496 +R T -100488 +R Y -100488 +R V -133984 +R W -133984 +T y -33496 +T e -100488 +T o -100488 +T r -100488 +T a -100488 +T A -100488 +T u -100488 +V o -100488 +V e -100488 +V u -100488 +V r -100488 +V a -100488 +V A -133984 +V O -33496 +V C -33496 +V G -33496 +V Q -33496 +W o -100488 +W e -100488 +W u -100488 +W r -100488 +W a -100488 +W A -133984 +W O -33496 +W C -33496 +W G -33496 +W Q -33496 +X O -33496 +X C -33496 +X G -33496 +X Q -33496 +Y e -100488 +Y o -100488 +Y r -100488 +Y a -100488 +Y A -100488 +Y u -100488 +oq oq -100488 +oq ` -100488 +` oq -100488 +` ` -100488 +a v -33496 +a j 66992 +a y -33496 +a w -33496 +b e 33496 +b o 33496 +b x -33496 +b d 33496 +b c 33496 +b q 33496 +b v -33496 +b j 66992 +b y -33496 +b w -33496 +c h -33496 +c k -33496 +f ' 114323 +f ? 114323 +f ! 114323 +f ) 114323 +f rB 114323 +f ] 114323 +g j 33496 +h t -33496 +h u -33496 +h b -33496 +h y -33496 +h v -33496 +h w -33496 +k a -66992 +k e -33496 +k a -33496 +k o -33496 +k c -33496 +m t -33496 +m u -33496 +m b -33496 +m y -33496 +m v -33496 +m w -33496 +n t -33496 +n u -33496 +n b -33496 +n y -33496 +n v -33496 +n w -33496 +o e 33496 +o o 33496 +o x -33496 +o d 33496 +o c 33496 +o q 33496 +o v -33496 +o j 66992 +o y -33496 +o w -33496 +p e 33496 +p o 33496 +p x -33496 +p d 33496 +p c 33496 +p q 33496 +p v -33496 +p j 66992 +p y -33496 +p w -33496 +t y -33496 +t w -33496 +u w -33496 +v a -66992 +v e -33496 +v a -33496 +v o -33496 +v c -33496 +w e -33496 +w a -33496 +w o -33496 +w c -33496 +y o -33496 +y e -33496 +y a -33496 +y . -100488 +y , -100488 +charset +*G 725261,719440,0,0,0,-167480 2 0000 +*D 1004880,719440 2 0001 +*H 937888,719440,0,0,-33496,-33496 2 0002 +*L 844682,719440 2 0003 +*C 803904,719440 2 0004 +*P 943714,719440 2 0005 +*S 870896,719440 2 0006 +*U 937888,719440,0,0,-33496,-167480 2 0007 +*F 870896,719440,0,0,-33496 2 0010 +*Q 937888,719440,0,0,-33496,-83741 2 0011 +*W 870896,719440 2 0012 +ff 703416,728178,0,114323 2 0013 +fi 669920,728178 2 0014 +fl 669920,728178 2 0015 +Fi 1004880,728178 2 0016 +Fl 1004880,728178 2 0017 +.i 334960,466034 0 0020 +.j 368456,466034,203890 1 0021 +ga 602928,728178 2 0022 +char180 602928,728178 2 0023 +aa " +ah 602928,662642 2 0024 +ab 602928,728178 2 0025 +char175 602928,625066 2 0026 +a- " +ao 911674,728178 2 0027 +char184 535936,0,178403 1 0030 +ac " +char223 626230,728178 2 0031 +ss " +char230 870896,466034 0 0032 +ae " +oe 937888,466034 0 0033 +char248 602928,567979,101946 3 0034 +/o " +char198 1092261,719440 2 0035 +AE " +OE 1226245,719440 2 0036 +char216 937888,770413,50973 3 0037 +/O " +--- 334960,466034 0 0040 +! 367000,728178 2 0041 +rq 632056,728178 2 0042 +sh 1004880,728178,203888 3 0043 +# " +Do 602928,786432,58254 3 0044 +$ " +% 1004880,786432,58254 3 0045 +& 937888,728178 2 0046 +' 334960,728178 2 0047 +( 468944,786432,262144 3 0050 +) 468944,786432,262144 3 0051 +* 602928,786432 2 0052 ++ 937888,664096,139808 3 0053 +, 334960,163112,203890 1 0054 +char173 401952,466034 0 0055 +hy " +- " +. 334960,163112 0 0056 +sl 602928,786432,262144 3 0057 +/ " +0 602928,675749 2 0060 +1 602928,675749 2 0061 +2 602928,675749 2 0062 +3 602928,675749 2 0063 +4 602928,675749 2 0064 +5 602928,675749 2 0065 +6 602928,675749 2 0066 +7 602928,675749 2 0067 +8 602928,675749 2 0070 +9 602928,675749 2 0071 +: 334960,466034 0 0072 +; 334960,466034,203890 1 0073 +char161 367000,524288,203890 3 0074 +r! " += 937888,410110,-114178 0 0075 +char191 569432,524288,203890 3 0076 +r? " +? 569432,728178 2 0077 +at 937888,728178 2 0100 +@ " +A 911674,719440 2 0101 +B 857789,719440 2 0102 +C 870896,719440,0,0,-33496 2 0103 +D 924781,719440,0,0,0,-33496 2 0104 +E 792253,719440 2 0105 +F 758757,719440,0,0,0,-167480 2 0106 +G 948083,719440,0,0,-33496 2 0107 +H 943714,719440 2 0110 +I 457294,719440 2 0111 +J 623317,719440,0,0,0,-33496 2 0112 +K 945170,719440 2 0113 +L 725261,719440,0,0,0,66992 2 0114 +M 1144690,719440 2 0115 +N 943714,719440 2 0116 +O 905848,719440,0,0,-33496,-33496 2 0117 +P 824293,719440,0,0,0,-167480 2 0120 +Q 905848,719440,203890,0,-33496 3 0121 +R 904392,719440 2 0122 +S 669920,719440 2 0123 +T 838856,719440,0,0,0,-167480 2 0124 +U 927694,719440,0,0,-20389 2 0125 +V 911674,719440,0,16749,50245,-251219 2 0126 +W 1246634,719440,0,16749,50245,-150731 2 0127 +X 911674,719440 2 0130 +Y 911674,719440,0,30146,33496,-237822 2 0131 +Z 736912,719440 2 0132 +lB 334960,786432,262144 3 0133 +[ " +lq 632056,728178 2 0134 +rB 334960,786432,262144 3 0135 +] " +ha 602928,728178 2 0136 +^ " +a^ " +a. 334960,728178 2 0137 +oq 334960,728178 2 0140 +` " +a 586179,466034 0 0141 +b 669920,728178 2 0142 +c 535936,466034 0 0143 +d 669920,728178 2 0144 +e 552685,466034 0 0145 +f 368456,728178,0,114323 2 0146 +g 602928,466034,203890,16749 1 0147 +h 669920,728178 2 0150 +i 334960,728178 2 0151 +j 368456,728178,203890 3 0152 +k 636424,728178 2 0153 +l 334960,728178 2 0154 +m 1004880,466034 0 0155 +n 669920,466034 0 0156 +o 602928,466034 0 0157 +p 669920,466034,203890 1 0160 +q 636424,466034,203890 1 0161 +r 496616,466034 0 0162 +s 475643,466034 0 0163 +t 468944,665763 2 0164 +u 669920,466034 0 0165 +v 636424,466034,0,16749 0 0166 +w 870896,466034,0,16749 0 0167 +x 636424,466034 0 0170 +y 636424,466034,203890,16749 1 0171 +z 535936,466034 0 0172 +en 602928,466034,0,33496 0 0173 +em 1205856,466034,0,33496 0 0174 +a" 602928,728178 2 0175 +~ 602928,728178 2 0176 +a~ " +char168 602928,728178 2 0177 +ad " diff --git a/gnu/usr.bin/groff/devices/devdvi/BI b/gnu/usr.bin/groff/devices/devdvi/BI new file mode 100644 index 0000000000..16d0193c44 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/BI @@ -0,0 +1,352 @@ +name BI +internalname cmbxti10 +spacewidth 434573 +slant 14.036243 +ligatures ff fi fl ffi ffl 0 +checksum 1175274390 +designsize 10485760 +kernpairs +ff ' 111848 +ff ? 111848 +ff ! 111848 +ff ) 111848 +ff rB 111848 +ff ] 111848 +' ' -92624 +' ? 123498 +' ! 123498 +A n -30875 +A l -30875 +A r -30875 +A u -30875 +A m -30875 +A t -30875 +A i -30875 +A C -30875 +A O -30875 +A G -30875 +A h -30875 +A b -30875 +A U -30875 +A k -30875 +A v -30875 +A w -30875 +A Q -30875 +A T -92624 +A Y -92624 +A V -123498 +A W -123498 +A e -61749 +A a -61749 +A o -61749 +A d -61749 +A c -61749 +A g -61749 +A q -61749 +D X -30875 +D W -30875 +D A -30875 +D V -30875 +D Y -30875 +F o -92624 +F e -92624 +F u -92624 +F r -92624 +F a -92624 +F A -123498 +F O -30875 +F C -30875 +F G -30875 +F Q -30875 +K O -30875 +K C -30875 +K G -30875 +K Q -30875 +L T -92624 +L Y -92624 +L V -123498 +L W -123498 +L e -61749 +L a -61749 +L o -61749 +L d -61749 +L c -61749 +L g -61749 +L q -61749 +O X -30875 +O W -30875 +O A -30875 +O V -30875 +O Y -30875 +P A -92624 +R n -30875 +R l -30875 +R r -30875 +R u -30875 +R m -30875 +R t -30875 +R i -30875 +R C -30875 +R O -30875 +R G -30875 +R h -30875 +R b -30875 +R U -30875 +R k -30875 +R v -30875 +R w -30875 +R Q -30875 +R T -92624 +R Y -92624 +R V -123498 +R W -123498 +R e -61749 +R a -61749 +R o -61749 +R d -61749 +R c -61749 +R g -61749 +R q -61749 +T y -92624 +T e -92624 +T o -92624 +T r -92624 +T a -92624 +T u -92624 +T A -92624 +V o -92624 +V e -92624 +V u -92624 +V r -92624 +V a -92624 +V A -123498 +V O -30875 +V C -30875 +V G -30875 +V Q -30875 +W A -92624 +X O -30875 +X C -30875 +X G -30875 +X Q -30875 +Y e -92624 +Y o -92624 +Y r -92624 +Y a -92624 +Y u -92624 +Y A -92624 +oq oq -92624 +oq ` -92624 +` oq -92624 +` ` -92624 +b e -61749 +b a -61749 +b o -61749 +b d -61749 +b c -61749 +b g -61749 +b q -61749 +c e -61749 +c a -61749 +c o -61749 +c d -61749 +c c -61749 +c g -61749 +c q -61749 +d l 61749 +e e -61749 +e a -61749 +e o -61749 +e d -61749 +e c -61749 +e g -61749 +e q -61749 +Fn ' 111848 +f ' 111848 +Fn ? 111848 +f ? 111848 +Fn ! 111848 +f ! 111848 +Fn ) 111848 +f ) 111848 +Fn rB 111848 +Fn ] 111848 +f rB 111848 +f ] 111848 +l l 61749 +n ' -123498 +o e -61749 +o a -61749 +o o -61749 +o d -61749 +o c -61749 +o g -61749 +o q -61749 +p e -61749 +p a -61749 +p o -61749 +p d -61749 +p c -61749 +p g -61749 +p q -61749 +r e -61749 +r a -61749 +r o -61749 +r d -61749 +r c -61749 +r g -61749 +r q -61749 +w l 61749 +charset +*G 731666,719440,0,135298,0,-19075 2 0000 +*D 990312,719440 2 0001 +*H 928563,719440,0,95027,-84834,64152 2 0002 +*L 845843,719440 2 0003 +*C 805066,719440,0,158248,0,79125 2 0004 +*P 939632,719440,0,180443,0,90222 2 0005 +*S 866814,719440,0,119859,0,59930 2 0006 +*U 928563,719440,0,113013,-174763,-41360 2 0007 +*F 866814,719440,0,59054,-120805,59054 2 0010 +*Q 928563,719440,0,113013,-174763,-5243 2 0011 +*W 866814,719440,0,104021,0,52011 2 0012 +ff 792256,728178,203890,228357 3 0013 +fi 707205,728178,203890,113890 3 0014 +fl 738078,728178,203890,113890 3 0015 +Fi 1095466,728178,203890,113890 3 0016 +Fl 1110902,728178,203890,113890 3 0017 +.i 372824,466034,0,98840 0 0020 +.j 403699,466034,203890,48354 1 0021 +ga 619819,728178 2 0022 +char180 619819,728178,0,89421 2 0023 +aa " +ah 619819,662642,0,86728 2 0024 +ab 619819,728178,0,108354 2 0025 +char175 619819,623318,0,109518 2 0026 +a- " +ao 994973,728178 2 0027 +char184 558070,0,178403 1 0030 +ac " +char223 697302,728178,203890,102090 3 0031 +ss " +char230 866814,466034,0,89131 0 0032 +ae " +oe 866814,466034,0,89131 0 0033 +char248 619819,567979,101946,99179 3 0034 +/o " +char198 1072450,719440,0,119859 2 0035 +AE " +OE 1195947,719440,0,119859 2 0036 +char216 928563,770413,50973,95027 3 0037 +/O " +--- 311075,466034 0 0040 +! 404864,728178,0,119714 2 0041 +rq 650696,728178,0,83248 2 0042 +sh 990312,728178,203888,71653 3 0043 +# " +char163 910723,728178 2 0044 +Po " +% 990312,786432,58254,134859 3 0045 +& 928563,728178,0,89421 2 0046 +' 372824,728178,0,135734 2 0047 +( 496322,786432,262144,165733 3 0050 +) 496322,786432,262144,34661 3 0051 +* 619819,786432,0,150296 2 0052 ++ 928563,632637,108349,34661 3 0053 +, 372824,154374,203890 1 0054 +char173 434573,466034,0,27379 0 0055 +hy " +- " +. 372824,154374 0 0056 +sl 619819,786432,262144,165733 3 0057 +/ " +0 619819,675749,0,138062 2 0060 +1 619819,675749,0,138062 2 0061 +2 619819,675749,0,138062 2 0062 +3 619819,675749,0,138062 2 0063 +4 619819,675749,203890,138062 3 0064 +5 619819,675749,0,138062 2 0065 +6 619819,675749,0,138062 2 0066 +7 619819,675749,203890,138062 3 0067 +8 619819,675749,0,138062 2 0070 +9 619819,675749,0,138062 2 0071 +: 372824,466034,0,70198 0 0072 +; 372824,466034,203890,70198 1 0073 +char161 404864,524288,203890,68741 3 0074 +r! " += 928563,410110,-114178,71653 0 0075 +char191 619819,524288,203890 3 0076 +r? " +? 619819,728178,0,120296 2 0077 +at 928563,728178,0,96555 2 0100 +@ " +A 907592,719440 2 0101 +B 856330,719440,0,104021,0,52011 2 0102 +C 866814,719440,0,148986,-84834,74493 2 0103 +D 918078,719440,0,95027,0,64152 2 0104 +E 793414,719440,0,119859,0,59930 2 0105 +F 762541,719440,0,135298,0,-19075 2 0106 +G 938758,719440,0,77042,-84834,77042 2 0107 +H 939632,719440,0,180443,0,90222 2 0110 +I 494576,719440,0,164424,0,82213 2 0111 +J 640208,719440,0,152045,0,45147 2 0112 +K 938467,719440,0,148986,0,74493 2 0113 +L 731666,719440,0,0,0,61749 2 0114 +M 1124878,719440,0,180443,0,59347 2 0115 +N 939632,719440,0,180443,0,59347 2 0116 +O 896523,719440,0,95027,-84834,64152 2 0117 +P 825454,719440,0,104021,0,-50352 2 0120 +Q 896523,719440,203890,95027,-84834,95027 3 0121 +R 901186,719440,0,26835,0,20126 2 0122 +S 681568,719440,0,118112,0,59056 2 0123 +T 834774,719440,0,135298,-134896,-19075 2 0124 +U 923613,719440,0,180443,-136096,59347 2 0125 +V 907592,719440,0,195298,-133549,-51698 2 0126 +W 1216336,719440,0,195298,-133549,40925 2 0127 +X 907592,719440,0,164424,0,82213 2 0130 +Y 907592,719440,0,207648,-148986,-39347 2 0131 +Z 743317,719440,0,148986,0,74493 2 0132 +lB 373408,786432,262144,196608 3 0133 +[ " +lq 650696,728178,0,175869 2 0134 +rB 373408,786432,262144,104568 3 0135 +] " +ha 619819,728178,0,70344 2 0136 +^ " +a^ " +a. 372824,728178,0,135734 2 0137 +oq 372824,728178,0,135734 2 0140 +` " +a 619819,466034,0,98840,-34078,98840 0 0141 +b 558070,728178,0,82430,-34078,82430 2 0142 +c 558070,466034,0,54760,-34078,54760 0 0143 +d 619819,728178,0,113890,-34078,113890 2 0144 +e 558070,466034,0,89131,-34078,89131 0 0145 +Fn 419432,728178,203890,228357,112722,116509 3 0146 +f " +g 558070,466034,203890,110102,-35829,71266 1 0147 +h 619819,728178,0,98840,0,98840 2 0150 +i 372824,726931,0,119403,-17669,119403 2 0151 +j 372824,726931,203890,175326,50973,110102 3 0152 +k 558070,728178,0,116509,0,98840 2 0153 +l 311075,728178,0,113890,-30875,129714 2 0154 +m 990312,466034,0,98840,-17669,98840 0 0155 +n 681568,466034,0,98840,-17669,98840 0 0156 +o 619819,466034,0,82430,-34078,82430 0 0157 +p 619819,466034,203890,82430,-17182,82430 1 0160 +q 558070,466034,203890,110102,-34078,71266 1 0161 +r 526034,466034,0,116509,-17669,85634 0 0162 +s 510595,466034,0,85634,0,85634 0 0163 +t 403699,665763,0,101072,-39323,101072 2 0164 +u 650694,466034,0,98840,-17669,98840 0 0165 +v 558070,466034,0,116509,-17669,77672 0 0166 +w 805066,466034,0,116509,-17669,87382 0 0167 +x 587782,466034,0,131946,0,131946 0 0170 +y 588946,466034,203890,110102,-17669,71266 1 0171 +z 514382,466034,0,145637,0,98840 0 0172 +en 619819,466034,0,102880 0 0173 +em 1239638,466034,0,102880 0 0174 +a" 619819,728178,0,120296 2 0175 +~ 619819,728178,0,120296 2 0176 +a~ " +char168 619819,728178,0,120298 2 0177 +ad " diff --git a/gnu/usr.bin/groff/devices/devdvi/CW b/gnu/usr.bin/groff/devices/devdvi/CW new file mode 100644 index 0000000000..fd94235ce8 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/CW @@ -0,0 +1,158 @@ +name CW +special +internalname cmtt10 +spacewidth 550498 +checksum -538297224 +designsize 10485760 +charset +*G 550498,640797 2 0000 +*D 550498,640797 2 0001 +*H 550498,640797 2 0002 +*L 550498,640797 2 0003 +*C 550498,640797 2 0004 +*P 550498,640797 2 0005 +*S 550498,640797 2 0006 +*U 550498,640797 2 0007 +*F 550498,640797 2 0010 +*Q 550498,640797 2 0011 +*W 550498,640797 2 0012 +ff 550498,640797 2 0013 +fi 550498,640797 2 0014 +fl 550498,640797 2 0015 +Fi 550498,407779,233018 1 0016 +Fl 550498,407779,233018 1 0017 +.i 550498,451470 0 0020 +.j 550498,451470,233018 1 0021 +ga 550498,640797 2 0022 +char180 550498,640797 2 0023 +aa " +ah 550498,593466 2 0024 +ab 550498,640797 2 0025 +char175 550498,593027 2 0026 +a- " +ao 550498,640797 2 0027 +char184 550498,0,203891 1 0030 +ac " +char223 550498,640797 2 0031 +ss " +char230 550498,451470 0 0032 +ae " +oe 550498,451470 0 0033 +char248 550498,567979,116509 3 0034 +/o " +char198 550498,640797 2 0035 +AE " +OE 550498,640797 2 0036 +char216 550498,699051,58254 3 0037 +/O " +--- 550498,230104,116509 1 0040 +! 550498,640797 2 0041 +" 550498,640797 2 0042 +sh 550498,640797 2 0043 +# " +Do 550498,728178,87381 3 0044 +$ " +% 550498,728178,87381 3 0045 +& 550498,640797 2 0046 +' 550498,640797 2 0047 +( 550498,728178,87379 3 0050 +) 550498,728178,87379 3 0051 +* 550498,546134 2 0052 ++ 550498,556326,-84470 2 0053 +, 550498,131072,145635 1 0054 +\- 550498,556326,-84470 2 0055 +- " +. 550498,131072 0 0056 +sl 550498,728178,87379 3 0057 +/ " +0 550498,640797 2 0060 +1 550498,640797 2 0061 +2 550498,640797 2 0062 +3 550498,640797 2 0063 +4 550498,640797 2 0064 +5 550498,640797 2 0065 +6 550498,640797 2 0066 +7 550498,640797 2 0067 +8 550498,640797 2 0070 +9 550498,640797 2 0071 +: 550498,451470 0 0072 +; 550498,451470,145635 1 0073 +< 550498,582542,-58254 2 0074 += 550498,435813,-204984 0 0075 +> 550498,582542,-58254 2 0076 +? 550498,640797 2 0077 +at 550498,640797 2 0100 +@ " +A 550498,640797 2 0101 +B 550498,640797 2 0102 +C 550498,640797 2 0103 +D 550498,640797 2 0104 +E 550498,640797 2 0105 +F 550498,640797 2 0106 +G 550498,640797 2 0107 +H 550498,640797 2 0110 +I 550498,640797 2 0111 +J 550498,640797 2 0112 +K 550498,640797 2 0113 +L 550498,640797 2 0114 +M 550498,640797 2 0115 +N 550498,640797 2 0116 +O 550498,640797 2 0117 +P 550498,640797 2 0120 +Q 550498,640797,145635 3 0121 +R 550498,640797 2 0122 +S 550498,640797 2 0123 +T 550498,640797 2 0124 +U 550498,640797 2 0125 +V 550498,640797 2 0126 +W 550498,640797 2 0127 +X 550498,640797 2 0130 +Y 550498,640797 2 0131 +Z 550498,640797 2 0132 +lB 550498,728178,87379 3 0133 +[ " +rs 550498,728178,87379 3 0134 +\ " +rB 550498,728178,87379 3 0135 +] " +ha 550498,640797 2 0136 +^ " +a^ " +_ 550498,0,99757 1 0137 +oq 550498,640797 2 0140 +` " +a 550498,451470 0 0141 +b 550498,640797 2 0142 +c 550498,451470 0 0143 +d 550498,640797 2 0144 +e 550498,451470 0 0145 +f 550498,640797 2 0146 +g 550498,451470,233018 1 0147 +h 550498,640797 2 0150 +i 550498,640797 2 0151 +j 550498,640797,233018 3 0152 +k 550498,640797 2 0153 +l 550498,640797 2 0154 +m 550498,451470 0 0155 +n 550498,451470 0 0156 +o 550498,451470 0 0157 +p 550498,451470,233018 1 0160 +q 550498,451470,233018 1 0161 +r 550498,451470 0 0162 +s 550498,451470 0 0163 +t 550498,580466 2 0164 +u 550498,451470 0 0165 +v 550498,451470 0 0166 +w 550498,451470 0 0167 +x 550498,451470 0 0170 +y 550498,451470,233018 1 0171 +z 550498,451470 0 0172 +{ 550498,728178,87379 3 0173 +lC " +| 550498,728178,87379 3 0174 +ba " +} 550498,728178,87379 3 0175 +rC " +~ 550498,640797 2 0176 +a~ " +--- 550498,640797 2 0177 diff --git a/gnu/usr.bin/groff/devices/devdvi/DESC b/gnu/usr.bin/groff/devices/devdvi/DESC new file mode 100644 index 0000000000..c1a0e97aa8 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/DESC @@ -0,0 +1,11 @@ +sizescale 100 +unitwidth 131072 +res 57816 +hor 1 +vert 1 +sizes 500 600 700 800 900 1000 1100 1200 1400 1440 1600 1728 1800 +2000 2074 2200 2400 2488 2800 3600 0 +fonts 13 R I B BI 0 0 0 0 0 MI S EX CW +tcommand +postpro grodvi +print lpr -d diff --git a/gnu/usr.bin/groff/devices/devdvi/EX b/gnu/usr.bin/groff/devices/devdvi/EX new file mode 100644 index 0000000000..6e83d02bd6 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/EX @@ -0,0 +1,144 @@ +name EX +special +internalname cmex10 +checksum -89033454 +designsize 10485760 +charset +parenleft0 480600,41942,1216362 1 0000 +parenright0 480600,41942,1216362 1 0001 +bracketleft0 436909,41942,1216362 1 0002 +bracketright0 436909,41942,1216362 1 0003 +floorleft0 495163,41942,1216362 1 0004 +floorright0 495163,41942,1216362 1 0005 +ceilingleft0 495163,41942,1216362 1 0006 +ceilingright0 495163,41942,1216362 1 0007 +braceleft0 611672,41942,1216362 1 0010 +braceright0 611672,41942,1216362 1 0011 +angleleft0 495163,41942,1216362 1 0012 +angleright0 495163,41942,1216362 1 0013 +barex 349526,0,629152 1 0014 +bardblex 582544,0,629152 1 0015 +slash0 605845,41942,1216362 1 0016 +backslash0 605845,41942,1216362 1 0017 +parenleft1 626235,41942,1845514 1 0020 +parenright1 626235,41942,1845514 1 0021 +parenleft2 771872,41942,2474666 1 0022 +parenright2 771872,41942,2474666 1 0023 +bracketleft2 553418,41942,2474666 1 0024 +bracketright2 553418,41942,2474666 1 0025 +floorleft2 611672,41942,2474666 1 0026 +floorright2 611672,41942,2474666 1 0027 +ceilingleft2 611672,41942,2474666 1 0030 +ceilingright2 611672,41942,2474666 1 0031 +braceleft2 786434,41942,2474666 1 0032 +braceright2 786434,41942,2474666 1 0033 +angleleft2 786434,41942,2474666 1 0034 +angleright2 786434,41942,2474666 1 0035 +slash2 1095182,41942,2474666 1 0036 +backslash2 1095182,41942,2474666 1 0037 +parenleft3 830126,41942,3103818 1 0040 +parenright3 830126,41942,3103818 1 0041 +bracketleft3 611672,41942,3103818 1 0042 +bracketright3 611672,41942,3103818 1 0043 +floorleft3 669926,41942,3103818 1 0044 +floorright3 669926,41942,3103818 1 0045 +ceilingleft3 669926,41942,3103818 1 0046 +ceilingright3 669926,41942,3103818 1 0047 +braceleft3 844691,41942,3103818 1 0050 +braceright3 844691,41942,3103818 1 0051 +angleleft3 844691,41942,3103818 1 0052 +angleright3 844691,41942,3103818 1 0053 +slash3 1339851,41942,3103818 1 0054 +backslash3 1339851,41942,3103818 1 0055 +slash1 850515,41942,1845514 1 0056 +backslash1 850515,41942,1845514 1 0057 +parenlefttp 917507,41942,1845514 1 0060 +parenrighttp 917507,41942,1845514 1 0061 +bracketlefttp 699053,41942,1845514 1 0062 +bracketrighttp 699053,41942,1845514 1 0063 +bracketleftbt 699053,41942,1845514 1 0064 +bracketrightbt 699053,41942,1845514 1 0065 +bracketleftex 699053,0,629152 1 0066 +bracketrightex 699053,0,629152 1 0067 +lt 932070,0,943728 1 0070 +bracelefttp " +rt 932070,0,943728 1 0071 +bracerighttp " +lb 932070,0,943728 1 0072 +braceleftbt " +rb 932070,0,943728 1 0073 +bracerightbt " +lk 932070,0,1887456 1 0074 +braceleftmid " +rk 932070,0,1887456 1 0075 +bracerightmid " +braceleftex 932070,0,314576 1 0076 +bracerightex " +braceex " +arrowvertex 699053,0,629152 1 0077 +parenleftbt 917507,41942,1845514 1 0100 +parenrightbt 917507,41942,1845514 1 0101 +parenleftex 917507,0,629152 1 0102 +parenrightex 917507,0,629152 1 0103 +angleleft1 640798,41942,1845514 1 0104 +angleright1 640798,41942,1845514 1 0105 +--- 873816,0,1048590 1 0106 +--- 1165088,104859,1572877 1 0107 +--- 495162,0,1165096,203891 1 0110 +ointegral 582544,0,2330194,466035 1 0111 +ois " +--- 1165088,0,1048590 1 0112 +bigcircledot 1584520,104859,1572877 1 0113 +--- 1165088,0,1048590 1 0114 +bigcircleplus 1584520,104859,1572877 1 0115 +--- 1165088,0,1048590 1 0116 +bigcirclemultiply 1584520,104859,1572877 1 0117 +--- 1106834,0,1048590 1 0120 +--- 990325,0,1048590 1 0121 +--- 495162,0,1165096,203891 1 0122 +--- 873816,0,1048590 1 0123 +--- 873816,0,1048590 1 0124 +--- 873816,0,1048590 1 0125 +--- 873816,0,1048590 1 0126 +--- 873816,0,1048590 1 0127 +sum 1514614,104859,1572877 1 0130 +product 1339851,104859,1572877 1 0131 +integral 582544,0,2330194,466035 1 0132 +is " +bigunion 1165088,104859,1572877 1 0133 +bigintersection 1165088,104859,1572877 1 0134 +bigunionplus 1165088,104859,1572877 1 0135 +biglogicaland 1165088,104859,1572877 1 0136 +biglogicalor 1165088,104859,1572877 1 0137 +--- 990325,0,1048590 1 0140 +coproduct 1339851,104859,1572877 1 0141 +--- 582544,757306 2 0142 +--- 1048579,786432 2 0143 +--- 1514614,786432 2 0144 +--- 582544,757306 2 0145 +--- 1048579,786432 2 0146 +--- 1514614,786432 2 0147 +bracketleft1 495163,41942,1845514 1 0150 +bracketright1 495163,41942,1845514 1 0151 +floorleft1 553418,41942,1845514 1 0152 +floorright1 553418,41942,1845514 1 0153 +ceilingleft1 553418,41942,1845514 1 0154 +ceilingright1 553418,41942,1845514 1 0155 +braceleft1 699053,41942,1845514 1 0156 +braceright1 699053,41942,1845514 1 0157 +sr0 1048579,41942,1216362 1 0160 +sr1 1048579,41942,1845514 1 0161 +sr2 1048579,41942,2474666 1 0162 +sr3 1048579,41942,3103818 1 0163 +--- 1106834,0,1887456 1 0164 +--- 1106834,0,629152 1 0165 +--- 1106834,41942,587210 1 0166 +arrowvertdblex 815562,0,629152 1 0167 +arrowverttp 699053,0,629152 1 0170 +arrowvertbt 699053,0,629152 1 0171 +--- 471864,125827 0 0172 +--- 471864,125827 0 0173 +--- 471864,125827 0 0174 +--- 471864,125827 0 0175 +arrowvertdbltp 815562,0,629152 1 0176 +arrowvertdblbt 815562,0,629152 1 0177 diff --git a/gnu/usr.bin/groff/devices/devdvi/H b/gnu/usr.bin/groff/devices/devdvi/H new file mode 100644 index 0000000000..96ae0f5fe0 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/H @@ -0,0 +1,302 @@ +name H +internalname cmss10 +spacewidth 349526 +ligatures ff fi fl ffi ffl 0 +checksum 1831058770 +designsize 10485760 +kernpairs +ff ' 72818 +ff ? 72818 +ff ! 72818 +ff ) 72818 +ff rB 72818 +ff ] 72818 +' ? 116509 +' ! 116509 +A t -29128 +A C -29128 +A O -29128 +A G -29128 +A U -29128 +A Q -29128 +A T -87382 +A Y -87382 +A V -116509 +A W -116509 +D X -29128 +D W -29128 +D A -29128 +D V -29128 +D Y -29128 +F o -29128 +F e -29128 +F u -29128 +F r -29128 +F a -29128 +F A -87382 +F O -29128 +F C -29128 +F G -29128 +F Q -29128 +I I 29128 +K O -29128 +K C -29128 +K G -29128 +K Q -29128 +L T -87382 +L Y -87382 +L V -116509 +L W -116509 +O X -29128 +O W -29128 +O A -29128 +O V -29128 +O Y -29128 +P A -87382 +P o -29128 +P e -29128 +P a -29128 +P . -87382 +P , -87382 +T y -87382 +T e -87382 +T o -87382 +T r -87382 +T a -87382 +T A -87382 +T u -87382 +V o -29128 +V e -29128 +V u -29128 +V r -29128 +V a -29128 +V A -87382 +V O -29128 +V C -29128 +V G -29128 +V Q -29128 +W o -29128 +W e -29128 +W u -29128 +W r -29128 +W a -29128 +W A -87382 +W O -29128 +W C -29128 +W G -29128 +W Q -29128 +X O -29128 +X C -29128 +X G -29128 +X Q -29128 +Y e -87382 +Y o -87382 +Y r -87382 +Y a -87382 +Y A -87382 +Y u -87382 +a r -29128 +a y -29128 +a w -29128 +b e 29128 +b o 29128 +b x -29128 +b d 29128 +b c 29128 +b q 29128 +b r -29128 +b y -29128 +b w -29128 +f ' 72818 +f ? 72818 +f ! 72818 +f ) 72818 +f rB 72818 +f ] 72818 +g j 29128 +k e -29128 +k a -29128 +k o -29128 +k c -29128 +o e 29128 +o o 29128 +o x -29128 +o d 29128 +o c 29128 +o q 29128 +o r -29128 +o y -29128 +o w -29128 +p e 29128 +p o 29128 +p x -29128 +p d 29128 +p c 29128 +p q 29128 +p r -29128 +p y -29128 +p w -29128 +t y -29128 +t w -29128 +u w -29128 +w e -29128 +w a -29128 +w o -29128 +w c -29128 +y o -29128 +y e -29128 +y a -29128 +y . -87382 +y , -87382 +charset +*G 567981,728178,0,0,0,-145637 2 0000 +*D 873816,728178 2 0001 +*H 815562,728178,0,0,-29128,-29128 2 0002 +*L 640800,728178 2 0003 +*C 699053,728178 2 0004 +*P 742746,728178 2 0005 +*S 757307,728178 2 0006 +*U 815562,728178,0,0,-29128,-145637 2 0007 +*F 757307,728178,0,0,-29128 2 0010 +*Q 815562,728178,0,0,-29128,-72818 2 0011 +*W 757307,728178 2 0012 +ff 611672,728178,0,72818 2 0013 +fi 562155,728178 2 0014 +fl 562155,728178 2 0015 +Fi 853427,728178 2 0016 +Fl 853427,728178 2 0017 +.i 250494,466034 0 0020 +.j 279622,466034,203890 1 0021 +ga 524290,728178 2 0022 +char180 524290,728178 2 0023 +aa " +ah 524290,662642 2 0024 +ab 524290,728178 2 0025 +char175 524290,638464 2 0026 +a- " +ao 699054,728178 2 0027 +char184 466035,0,178403 1 0030 +ac " +char223 503902,728178 2 0031 +ss " +char230 757307,466034 0 0032 +ae " +oe 815562,466034 0 0033 +char248 524290,567979,101946 3 0034 +/o " +char198 902944,728178 2 0035 +AE " +OE 1019453,728178 2 0036 +char216 815562,779150,50973 3 0037 +/O " +--- 250494,466034 0 0040 +! 334963,728178 2 0041 +rq 524290,728178 2 0042 +sh 873816,728178,203888 3 0043 +# " +Do 524290,786432,58254 3 0044 +$ " +% 873816,786432,58254 3 0045 +& 795173,728178 2 0046 +' 291272,728178 2 0047 +( 407781,786432,262144 3 0050 +) 407781,786432,262144 3 0051 +* 524290,786432 2 0052 ++ 815562,611670,87382 3 0053 +, 291272,87381,131072 1 0054 +char173 349526,466034 0 0055 +hy " +- " +. 291272,87381 0 0056 +sl 524290,786432,262144 3 0057 +/ " +0 524290,687400 2 0060 +1 524290,687400 2 0061 +2 524290,687400 2 0062 +3 524290,687400 2 0063 +4 524290,687400 2 0064 +5 524290,687400 2 0065 +6 524290,687400 2 0066 +7 524290,687400 2 0067 +8 524290,687400 2 0070 +9 524290,687400 2 0071 +: 291272,466034 0 0072 +; 291272,466034,131072 1 0073 +char161 334963,524288,203890 3 0074 +r! " += 815562,387973,-136315 0 0075 +char191 495163,524288,203890 3 0076 +r? " +? 495163,728178 2 0077 +at 699053,728178 2 0100 +@ " +A 699054,728178 2 0101 +B 699054,728178 2 0102 +C 669926,728178,0,0,-29128 2 0103 +D 757309,728178,0,0,0,-29128 2 0104 +E 626235,728178 2 0105 +F 597109,728178,0,0,0,-145637 2 0106 +G 699053,728178,0,0,-29128 2 0107 +H 742746,728178 2 0110 +I 291274,728178 2 0111 +J 495163,728178,0,0,0,-29128 2 0112 +K 728182,728178 2 0113 +L 567981,728178,0,0,0,58254 2 0114 +M 917509,728178 2 0115 +N 742746,728178 2 0116 +O 771870,728178,0,0,-29128,-29128 2 0117 +P 669926,728178,0,0,0,-145637 2 0120 +Q 771870,728178,131072,0,-29128 3 0121 +R 677208,728178 2 0122 +S 582544,728178 2 0123 +T 713616,728178,0,0,0,-145637 2 0124 +U 720901,728178,0,0,29126 2 0125 +V 699054,728178,0,14563,43691,-218454 2 0126 +W 990326,728178,0,14563,43691,-131074 2 0127 +X 699054,728178 2 0130 +Y 699054,728178,0,26214,29128,-206803 2 0131 +Z 640798,728178 2 0132 +lB 302923,786432,262144 3 0133 +[ " +lq 524290,728178 2 0134 +rB 302923,786432,262144 3 0135 +] " +ha 524290,728178 2 0136 +^ " +a^ " +a. 291272,712366 2 0137 +oq 291272,728178 2 0140 +` " +a 503901,466034 0 0141 +b 541766,728178 2 0142 +c 466035,466034 0 0143 +d 541766,728178 2 0144 +e 466035,466034 0 0145 +f 320400,728178,0,72818 2 0146 +g 524290,466034,203890,14563 1 0147 +h 541766,728178 2 0150 +i 250494,712366 2 0151 +j 279622,712366,203890 3 0152 +k 512640,728178 2 0153 +l 250494,728178 2 0154 +m 833038,466034 0 0155 +n 541766,466034 0 0156 +o 524290,466034 0 0157 +p 541766,466034,203890 1 0160 +q 541766,466034,203890 1 0161 +r 358266,466034,0,14563 0 0162 +s 401955,466034 0 0163 +t 378653,599189 2 0164 +u 541766,466034 0 0165 +v 483512,466034,0,14563 0 0166 +w 716530,466034,0,14563 0 0167 +x 483512,466034 0 0170 +y 483512,466034,203890,14563 1 0171 +z 455840,466034 0 0172 +en 524290,466034,0,29128 0 0173 +em 1048579,466034,0,29128 0 0174 +a" 524290,728178 2 0175 +~ 524290,709454 2 0176 +a~ " +char168 524290,712366 2 0177 +ad " diff --git a/gnu/usr.bin/groff/devices/devdvi/HB b/gnu/usr.bin/groff/devices/devdvi/HB new file mode 100644 index 0000000000..aaff896811 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/HB @@ -0,0 +1,302 @@ +name HB +internalname cmssbx10 +spacewidth 384480 +ligatures ff fi fl ffi ffl 0 +checksum -244629176 +designsize 10485760 +kernpairs +ff ' 80101 +ff ? 80101 +ff ! 80101 +ff ) 80101 +ff rB 80101 +ff ] 80101 +' ? 128160 +' ! 128160 +A t -32040 +A C -32040 +A O -32040 +A G -32040 +A U -32040 +A Q -32040 +A T -96120 +A Y -96120 +A V -128160 +A W -128160 +D X -32040 +D W -32040 +D A -32040 +D V -32040 +D Y -32040 +F o -32040 +F e -32040 +F u -32040 +F r -32040 +F a -32040 +F A -96120 +F O -32040 +F C -32040 +F G -32040 +F Q -32040 +I I 32040 +K O -32040 +K C -32040 +K G -32040 +K Q -32040 +L T -96120 +L Y -96120 +L V -128160 +L W -128160 +O X -32040 +O W -32040 +O A -32040 +O V -32040 +O Y -32040 +P A -96120 +P o -32040 +P e -32040 +P a -32040 +P . -96120 +P , -96120 +T y -96120 +T e -96120 +T o -96120 +T r -96120 +T a -96120 +T A -96120 +T u -96120 +V o -32040 +V e -32040 +V u -32040 +V r -32040 +V a -32040 +V A -96120 +V O -32040 +V C -32040 +V G -32040 +V Q -32040 +W o -32040 +W e -32040 +W u -32040 +W r -32040 +W a -32040 +W A -96120 +W O -32040 +W C -32040 +W G -32040 +W Q -32040 +X O -32040 +X C -32040 +X G -32040 +X Q -32040 +Y e -96120 +Y o -96120 +Y r -96120 +Y a -96120 +Y A -96120 +Y u -96120 +a r -32040 +a y -32040 +a w -32040 +b e 32040 +b o 32040 +b x -32040 +b d 32040 +b c 32040 +b q 32040 +b r -32040 +b y -32040 +b w -32040 +f ' 80101 +f ? 80101 +f ! 80101 +f ) 80101 +f rB 80101 +f ] 80101 +g j 32040 +k e -32040 +k a -32040 +k o -32040 +k c -32040 +o e 32040 +o o 32040 +o x -32040 +o d 32040 +o c 32040 +o q 32040 +o r -32040 +o y -32040 +o w -32040 +p e 32040 +p o 32040 +p x -32040 +p d 32040 +p c 32040 +p q 32040 +p r -32040 +p y -32040 +p w -32040 +t y -32040 +t w -32040 +u w -32040 +w e -32040 +w a -32040 +w o -32040 +w c -32040 +y o -32040 +y e -32040 +y a -32040 +y . -96120 +y , -96120 +charset +*G 608760,728178,0,0,0,-160200 2 0000 +*D 961200,728178 2 0001 +*H 897120,728178,0,0,-32040,-32040 2 0002 +*L 704880,728178 2 0003 +*C 768960,728178 2 0004 +*P 833040,728178 2 0005 +*S 833040,728178 2 0006 +*U 897120,728178,0,0,-32040,-160200 2 0007 +*F 833040,728178,0,0,-32040 2 0010 +*Q 897120,728178,0,0,-32040,-80101 2 0011 +*W 833040,728178 2 0012 +ff 672840,728178,0,80101 2 0013 +fi 614586,728178 2 0014 +fl 614586,728178 2 0015 +Fi 934986,728178 2 0016 +Fl 934986,728178 2 0017 +.i 267971,480597 0 0020 +.j 300011,480597,203890 1 0021 +ga 576720,728178 2 0022 +char180 576720,728178 2 0023 +aa " +ah 576720,666283 2 0024 +ab 576720,728178 2 0025 +char175 576720,668757 2 0026 +a- " +ao 768960,728178 2 0027 +char184 512640,0,178403 1 0030 +ac " +char223 592739,728178 2 0031 +ss " +char230 833040,480597 0 0032 +ae " +oe 897120,480597 0 0033 +char248 576720,582542,101946 3 0034 +/o " +char198 993240,728178 2 0035 +AE " +OE 1121400,728178 2 0036 +char216 897120,779150,50973 3 0037 +/O " +--- 267971,480597 0 0040 +! 384480,728178 2 0041 +rq 585458,728178 2 0042 +sh 961200,728178,203888 3 0043 +# " +Do 576720,786432,58254 3 0044 +$ " +% 1079109,786432,58254 3 0045 +& 870906,728178 2 0046 +' 320400,728178 2 0047 +( 448560,786432,262144 3 0050 +) 448560,786432,262144 3 0051 +* 576720,786432 2 0052 ++ 897120,646624,122336 3 0053 +, 320400,136898,110683 1 0054 +char173 384480,480597 0 0055 +hy " +- " +. 320400,136898 0 0056 +sl 576720,786432,262144 3 0057 +/ " +0 576720,728178 2 0060 +1 576720,728178 2 0061 +2 576720,728178 2 0062 +3 576720,728178 2 0063 +4 576720,728178 2 0064 +5 576720,728178 2 0065 +6 576720,728178 2 0066 +7 576720,728178 2 0067 +8 576720,728178 2 0070 +9 576720,728178 2 0071 +: 320400,480597 0 0072 +; 320400,480597,110683 1 0073 +char161 384480,524288,203890 3 0074 +r! " += 897120,425984,-98304 0 0075 +char191 544680,524288,203890 3 0076 +r? " +? 544680,728178 2 0077 +at 768960,728178 2 0100 +@ " +A 768960,728178 2 0101 +B 768960,728178 2 0102 +C 736920,728178,0,0,-32040 2 0103 +D 833040,728178,0,0,0,-32040 2 0104 +E 672840,728178 2 0105 +F 640800,728178,0,0,0,-160200 2 0106 +G 768960,728178,0,0,-32040 2 0107 +H 833040,728178 2 0110 +I 346614,728178 2 0111 +J 544680,728178,0,0,0,-32040 2 0112 +K 801000,728178 2 0113 +L 608760,728178,0,0,0,64080 2 0114 +M 1025280,728178 2 0115 +N 833040,728178 2 0116 +O 833040,728178,0,0,-32040,-32040 2 0117 +P 736920,728178,0,0,0,-160200 2 0120 +Q 833040,728178,110683,0,-32040 3 0121 +R 736920,728178 2 0122 +S 640800,728178 2 0123 +T 768960,728178,0,0,0,-160200 2 0124 +U 801000,728178,0,0,32040 2 0125 +V 768960,728178,0,16021,48061,-240299 2 0126 +W 1089360,728178,0,16021,48061,-144179 2 0127 +X 768960,728178 2 0130 +Y 768960,728178,0,28835,32040,-227485 2 0131 +Z 704880,728178 2 0132 +lB 359722,786432,262144 3 0133 +[ " +lq 585458,728178 2 0134 +rB 359722,786432,262144 3 0135 +] " +ha 576720,728178 2 0136 +^ " +a^ " +a. 320400,728178 2 0137 +oq 320400,728178 2 0140 +` " +a 550506,480597 0 0141 +b 588371,728178 2 0142 +c 512640,480597 0 0143 +d 588371,728178 2 0144 +e 535942,480597 0 0145 +f 352440,728178,0,80101 2 0146 +g 576720,480597,203890,16021 1 0147 +h 588371,728178 2 0150 +i 267971,728178 2 0151 +j 300011,728178,203890 3 0152 +k 556331,728178 2 0153 +l 267971,728178 2 0154 +m 908771,480597 0 0155 +n 588371,480597 0 0156 +o 576720,480597 0 0157 +p 588371,480597,203890 1 0160 +q 588371,480597,203890 1 0161 +r 390306,480597,0,16021 0 0162 +s 442152,480597 0 0163 +t 423802,617914 2 0164 +u 588371,480597 0 0165 +v 524291,480597,0,16021 0 0166 +w 780611,480597,0,16021 0 0167 +x 524291,480597 0 0170 +y 524291,480597,203890,16021 1 0171 +z 499533,480597 0 0172 +en 576720,480597,0,32040 0 0173 +em 1153440,480597,0,32040 0 0174 +a" 576720,728178 2 0175 +~ 576720,728178 2 0176 +a~ " +char168 576720,728178 2 0177 +ad " diff --git a/gnu/usr.bin/groff/devices/devdvi/HI b/gnu/usr.bin/groff/devices/devdvi/HI new file mode 100644 index 0000000000..dcfcced1a5 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/HI @@ -0,0 +1,303 @@ +name HI +internalname cmssi10 +spacewidth 349526 +slant 11.999911 +ligatures ff fi fl ffi ffl 0 +checksum -984248855 +designsize 10485760 +kernpairs +ff ' 72818 +ff ? 72818 +ff ! 72818 +ff ) 72818 +ff rB 72818 +ff ] 72818 +' ? 116509 +' ! 116509 +A t -29128 +A C -29128 +A O -29128 +A G -29128 +A U -29128 +A Q -29128 +A T -87382 +A Y -87382 +A V -116509 +A W -116509 +D X -29128 +D W -29128 +D A -29128 +D V -29128 +D Y -29128 +F o -29128 +F e -29128 +F u -29128 +F r -29128 +F a -29128 +F A -87382 +F O -29128 +F C -29128 +F G -29128 +F Q -29128 +I I 29128 +K O -29128 +K C -29128 +K G -29128 +K Q -29128 +L T -87382 +L Y -87382 +L V -116509 +L W -116509 +O X -29128 +O W -29128 +O A -29128 +O V -29128 +O Y -29128 +P A -87382 +P o -29128 +P e -29128 +P a -29128 +P . -87382 +P , -87382 +T y -87382 +T e -87382 +T o -87382 +T r -87382 +T a -87382 +T A -87382 +T u -87382 +V o -29128 +V e -29128 +V u -29128 +V r -29128 +V a -29128 +V A -87382 +V O -29128 +V C -29128 +V G -29128 +V Q -29128 +W o -29128 +W e -29128 +W u -29128 +W r -29128 +W a -29128 +W A -87382 +W O -29128 +W C -29128 +W G -29128 +W Q -29128 +X O -29128 +X C -29128 +X G -29128 +X Q -29128 +Y e -87382 +Y o -87382 +Y r -87382 +Y a -87382 +Y A -87382 +Y u -87382 +a r -29128 +a y -29128 +a w -29128 +b e 29128 +b o 29128 +b x -29128 +b d 29128 +b c 29128 +b q 29128 +b r -29128 +b y -29128 +b w -29128 +f ' 72818 +f ? 72818 +f ! 72818 +f ) 72818 +f rB 72818 +f ] 72818 +g j 29128 +k e -29128 +k a -29128 +k o -29128 +k c -29128 +o e 29128 +o o 29128 +o x -29128 +o d 29128 +o c 29128 +o q 29128 +o r -29128 +o y -29128 +o w -29128 +p e 29128 +p o 29128 +p x -29128 +p d 29128 +p c 29128 +p q 29128 +p r -29128 +p y -29128 +p w -29128 +t y -29128 +t w -29128 +u w -29128 +w e -29128 +w a -29128 +w o -29128 +w c -29128 +y o -29128 +y e -29128 +y a -29128 +y . -87382 +y , -87382 +charset +*G 567981,728178,0,140214,0,-5422 2 0000 +*D 873816,728178 2 0001 +*H 815562,728178,0,79216,-75562,50088 2 0002 +*L 640800,728178 2 0003 +*C 699053,728178,0,134389,0,67195 2 0004 +*P 742746,728178,0,84870,0,42435 2 0005 +*S 757307,728178,0,125650,0,62826 2 0006 +*U 815562,728178,0,94694,-152950,-50942 2 0007 +*F 757307,728178,0,48261,-106517,48261 2 0010 +*Q 815562,728178,0,94694,-152950,-10907 2 0011 +*W 757307,728178,0,86955,0,43478 2 0012 +ff 611672,728178,0,227595 2 0013 +fi 562155,728178,0,102349 2 0014 +fl 562155,728178,0,99435 2 0015 +Fi 853427,728178,0,102349 2 0016 +Fl 853427,728178,0,99435 2 0017 +.i 250494,466034,0,43715 0 0020 +.j 279622,466034,203890,43715 1 0021 +ga 524290,728178 2 0022 +char180 524290,728178,0,96523 2 0023 +aa " +ah 524290,662642,0,88419 2 0024 +ab 524290,728178,0,99435 2 0025 +char175 524290,638464,0,92018 2 0026 +a- " +ao 773347,728178 2 0027 +char184 466035,0,178403 1 0030 +ac " +char223 503902,728178,0,96523 2 0031 +ss " +char230 757307,466034,0,71070 0 0032 +ae " +oe 815562,466034,0,71070 0 0033 +char248 524290,567979,101946,50821 3 0034 +/o " +char198 902944,728178,0,125650 2 0035 +AE " +OE 1019453,728178,0,125650 2 0036 +char216 815562,779150,50973,79216 3 0037 +/O " +--- 250494,466034 0 0040 +! 334963,728178,0,60114 2 0041 +rq 524290,728178,0,3315 2 0042 +sh 873816,728178,203888,53338 3 0043 +# " +Do 524290,786432,58254,116982 3 0044 +$ " +% 873816,786432,58254,32782 3 0045 +& 795173,728178,0,32064 2 0046 +' 291272,728178,0,81960 2 0047 +( 407781,786432,262144,138032 3 0050 +) 407781,786432,262144,26592 3 0051 +* 524290,786432,0,123469 2 0052 ++ 815562,611670,87382,26592 3 0053 +, 291272,87381,131072 1 0054 +char173 349526,466034,0,20402 0 0055 +hy " +- " +. 291272,87381 0 0056 +sl 524290,786432,262144,138032 3 0057 +/ " +0 524290,687400,0,116982 2 0060 +1 524290,687400,0,116982 2 0061 +2 524290,687400,0,116982 2 0062 +3 524290,687400,0,116982 2 0063 +4 524290,687400,0,116982 2 0064 +5 524290,687400,0,116982 2 0065 +6 524290,687400,0,116982 2 0066 +7 524290,687400,0,116982 2 0067 +8 524290,687400,0,116982 2 0070 +9 524290,687400,0,116982 2 0071 +: 291272,466034,0,26240 0 0072 +; 291272,466034,131072,26240 1 0073 +char161 334963,524288,203890,16776 3 0074 +r! " += 815562,387973,-136315,53338 0 0075 +char191 495163,524288,203890 3 0076 +r? " +? 495163,728178,0,123822 2 0077 +at 699053,728178,0,79216 2 0100 +@ " +A 699054,728178 2 0101 +B 699054,728178,0,86955,0,43478 2 0102 +C 669926,728178,0,125650,-75562,62826 2 0103 +D 757309,728178,0,79216,0,50088 2 0104 +E 626235,728178,0,125650,0,62826 2 0105 +F 597109,728178,0,140214,0,-5422 2 0106 +G 699053,728178,0,125650,-75562,62826 2 0107 +H 742746,728178,0,84870,0,42435 2 0110 +I 291274,728178,0,140214,0,70107 2 0111 +J 495163,728178,0,84870,0,13307 2 0112 +K 728182,728178,0,125650,0,62826 2 0113 +L 567981,728178,0,0,0,58254 2 0114 +M 917509,728178,0,84870,0,13307 2 0115 +N 742746,728178,0,84870,0,13307 2 0116 +O 771870,728178,0,79216,-75562,50088 2 0117 +P 669926,728178,0,86955,0,-58682 2 0120 +Q 771870,728178,131072,79216,-75562,79216 3 0121 +R 677208,728178,0,86955,0,65216 2 0122 +S 582544,728178,0,96523,0,48262 2 0123 +T 713616,728178,0,140214,-116083,-5422 2 0124 +U 720901,728178,0,84870,-75562,13307 2 0125 +V 699054,728178,0,169341,-111086,-63677 2 0126 +W 990326,728178,0,169341,-111086,23704 2 0127 +X 699054,728178,0,140214,0,70107 2 0130 +Y 699054,728178,0,180992,-125650,-52026 2 0131 +Z 640798,728178,0,125650,0,62826 2 0132 +lB 302923,786432,262144,167160 3 0133 +[ " +lq 524290,728178,0,148952 2 0134 +rB 302923,786432,262144,91429 3 0135 +] " +ha 524290,728178,0,83776 2 0136 +^ " +a^ " +a. 291272,712366,0,81512 2 0137 +oq 291272,728178,0,81960 2 0140 +` " +a 503901,466034,0,10283 0 0141 +b 541766,728178,0,32053 2 0142 +c 466035,466034,0,87406 0 0143 +d 541766,728178,0,99435 2 0144 +e 466035,466034,0,71070 0 0145 +f 320400,728178,0,227595 2 0146 +g 524290,466034,203890,113621 1 0147 +h 541766,728178,0,18642 2 0150 +i 250494,712366,0,101901 2 0151 +j 279622,712366,203890,96075 3 0152 +k 512640,728178,0,87406 2 0153 +l 250494,728178,0,99435 2 0154 +m 833038,466034,0,18642 0 0155 +n 541766,466034,0,18642 0 0156 +o 524290,466034,0,69341 0 0157 +p 541766,466034,203890,40790 1 0160 +q 541766,466034,203890,43715 1 0161 +r 358266,466034,0,113621 0 0162 +s 401955,466034,0,81581 0 0163 +t 378653,599189,0,75757 2 0164 +u 541766,466034,0,43715 0 0165 +v 483512,466034,0,113621 0 0166 +w 716530,466034,0,113621 0 0167 +x 483512,466034,0,96144 0 0170 +y 483512,466034,203890,113621 1 0171 +z 455840,466034,0,91776 0 0172 +en 524290,466034,0,90349 0 0173 +em 1048579,466034,0,90349 0 0174 +a" 524290,728178,0,96523 2 0175 +~ 524290,709454,0,92544 2 0176 +a~ " +char168 524290,712366,0,66949 2 0177 +ad " diff --git a/gnu/usr.bin/groff/devices/devdvi/I b/gnu/usr.bin/groff/devices/devdvi/I new file mode 100644 index 0000000000..a46501669f --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/I @@ -0,0 +1,353 @@ +name I +special +internalname cmti10 +spacewidth 375155 +slant 14.036243 +ligatures ff fi fl ffi ffl 0 +checksum -50321606 +designsize 10485760 +kernpairs +ff ' 109373 +ff ? 109373 +ff ! 109373 +ff ) 109373 +ff rB 109373 +ff ] 109373 +' ' -80390 +' ? 107187 +' ! 107187 +A n -26797 +A l -26797 +A r -26797 +A u -26797 +A m -26797 +A t -26797 +A i -26797 +A C -26797 +A O -26797 +A G -26797 +A h -26797 +A b -26797 +A U -26797 +A k -26797 +A v -26797 +A w -26797 +A Q -26797 +A T -80390 +A Y -80390 +A V -107187 +A W -107187 +A e -53594 +A a -53594 +A o -53594 +A d -53594 +A c -53594 +A g -53594 +A q -53594 +D X -26797 +D W -26797 +D A -26797 +D V -26797 +D Y -26797 +F o -80390 +F e -80390 +F u -80390 +F r -80390 +F a -80390 +F A -107187 +F O -26797 +F C -26797 +F G -26797 +F Q -26797 +K O -26797 +K C -26797 +K G -26797 +K Q -26797 +L T -80390 +L Y -80390 +L V -107187 +L W -107187 +L e -53594 +L a -53594 +L o -53594 +L d -53594 +L c -53594 +L g -53594 +L q -53594 +O X -26797 +O W -26797 +O A -26797 +O V -26797 +O Y -26797 +P A -80390 +R n -26797 +R l -26797 +R r -26797 +R u -26797 +R m -26797 +R t -26797 +R i -26797 +R C -26797 +R O -26797 +R G -26797 +R h -26797 +R b -26797 +R U -26797 +R k -26797 +R v -26797 +R w -26797 +R Q -26797 +R T -80390 +R Y -80390 +R V -107187 +R W -107187 +R e -53594 +R a -53594 +R o -53594 +R d -53594 +R c -53594 +R g -53594 +R q -53594 +T y -80390 +T e -80390 +T o -80390 +T r -80390 +T a -80390 +T u -80390 +T A -80390 +V o -80390 +V e -80390 +V u -80390 +V r -80390 +V a -80390 +V A -107187 +V O -26797 +V C -26797 +V G -26797 +V Q -26797 +W A -80390 +X O -26797 +X C -26797 +X G -26797 +X Q -26797 +Y e -80390 +Y o -80390 +Y r -80390 +Y a -80390 +Y u -80390 +Y A -80390 +oq oq -80390 +oq ` -80390 +` oq -80390 +` ` -80390 +b e -53594 +b a -53594 +b o -53594 +b d -53594 +b c -53594 +b g -53594 +b q -53594 +c e -53594 +c a -53594 +c o -53594 +c d -53594 +c c -53594 +c g -53594 +c q -53594 +d l 53594 +e e -53594 +e a -53594 +e o -53594 +e d -53594 +e c -53594 +e g -53594 +e q -53594 +Fn ' 109373 +f ' 109373 +Fn ? 109373 +f ? 109373 +Fn ! 109373 +f ! 109373 +Fn ) 109373 +f ) 109373 +Fn rB 109373 +Fn ] 109373 +f rB 109373 +f ] 109373 +l l 53594 +n ' -107187 +o e -53594 +o a -53594 +o o -53594 +o d -53594 +o c -53594 +o g -53594 +o q -53594 +p e -53594 +p a -53594 +p o -53594 +p d -53594 +p c -53594 +p g -53594 +p q -53594 +r e -53594 +r a -53594 +r o -53594 +r d -53594 +r c -53594 +r g -53594 +r q -53594 +w l 53594 +charset +*G 657686,716526,0,139518,0,5534 2 0000 +*D 857498,716526 2 0001 +*H 803904,716526,0,98595,-80538,71798 2 0002 +*L 725843,716526 2 0003 +*C 696717,716526,0,160373,0,80187 2 0004 +*P 779437,716526,0,171851,0,85926 2 0005 +*S 750310,716526,0,126120,0,63061 2 0006 +*U 803904,716526,0,116509,-170102,-17475 2 0007 +*F 750310,716526,0,62770,-116363,62770 2 0010 +*Q 803904,716526,0,116509,-170102,4659 2 0011 +*W 750310,716526,0,107552,0,53776 2 0012 +ff 643123,728178,203890,222240 3 0013 +fi 589530,728178,203890,108354 3 0014 +fl 616326,728178,203890,108354 3 0015 +Fi 924490,728178,203890,108354 3 0016 +Fl 937888,728178,203890,108354 3 0017 +.i 321562,451470,0,80440 0 0020 +.j 348358,451470,203890,39176 1 0021 +ga 535936,728178 2 0022 +char180 535936,728178,0,101654 2 0023 +aa " +ah 535936,659002,0,86982 2 0024 +ab 535936,728178,0,113306 2 0025 +char175 535936,588949,0,108354 2 0026 +a- " +ao 871672,728178 2 0027 +char184 482342,0,178403 1 0030 +ac " +char223 562733,728178,203890,110245 3 0031 +ss " +char230 750310,451470,0,78789 0 0032 +ae " +oe 750310,451470,0,78789 0 0033 +char248 535936,553416,101946,96411 3 0034 +/o " +char198 925654,716526,0,126120 2 0035 +AE " +OE 1032842,716526,0,126120 2 0036 +char216 803904,767499,50973,98595 3 0037 +/O " +--- 267968,451470 0 0040 +! 321562,728178,0,130200 2 0041 +rq 539432,728178,0,72994 2 0042 +sh 857498,728178,203888,69378 3 0043 +# " +char163 806453,728178 2 0044 +Po " +% 857498,786432,58254,143014 3 0045 +& 803904,728178,0,101654 2 0046 +' 321562,728178,0,130200 2 0047 +( 428749,786432,262144,169811 3 0050 +) 428749,786432,262144,38739 3 0051 +* 535936,786432,0,156413 2 0052 ++ 803904,588949,59418,38739 3 0053 +, 321562,110683,203890 1 0054 +char173 375155,451470,0,29637 0 0055 +hy " +- " +. 321562,110683 0 0056 +sl 535936,786432,262144,169811 3 0057 +/ " +0 535936,675749,0,142141 2 0060 +1 535936,675749,0,142141 2 0061 +2 535936,675749,0,142141 2 0062 +3 535936,675749,0,142141 2 0063 +4 535936,675749,203890,142141 3 0064 +5 535936,675749,0,142141 2 0065 +6 535936,675749,0,142141 2 0066 +7 535936,675749,203890,142141 3 0067 +8 535936,675749,0,142141 2 0070 +9 535936,675749,0,142141 2 0071 +: 321562,451470,0,61022 0 0072 +; 321562,451470,203890,61022 1 0073 +char161 321562,524288,203890,79227 3 0074 +r! " += 803904,384696,-139592,69378 0 0075 +char191 535936,524288,203890 3 0076 +r? " +? 535936,728178,0,128451 2 0077 +at 803904,728178,0,100634 2 0100 +@ " +A 779437,716526 2 0101 +B 738077,716526,0,107552,0,53776 2 0102 +C 750310,716526,0,152334,-80538,76168 2 0103 +D 791670,716526,0,98595,0,71798 2 0104 +E 711280,716526,0,126120,0,63061 2 0105 +F 684483,716526,0,139518,0,5534 2 0106 +G 811186,716526,0,91459,-80538,91459 2 0107 +H 779437,716526,0,171851,0,85926 2 0110 +I 404282,716526,0,165733,0,82867 2 0111 +J 550499,716526,0,147093,0,46750 2 0112 +K 806234,716526,0,152334,0,76168 2 0113 +L 657686,716526,0,0,0,53594 2 0114 +M 940218,716526,0,171851,0,59130 2 0115 +N 779437,716526,0,171851,0,59130 2 0116 +O 803904,716526,0,98595,-80538,71798 2 0117 +P 711280,716526,0,107552,0,-26432 2 0120 +Q 803904,716526,203890,98595,-80538,98595 3 0121 +R 764874,716526,0,40560,0,30421 2 0122 +S 589530,716526,0,125538,0,62770 2 0123 +T 750310,716526,0,139518,-134349,5534 2 0124 +U 779437,716526,0,171851,-121898,59130 2 0125 +V 779437,716526,0,192530,-138936,-21845 2 0126 +W 1047405,716526,0,192530,-138936,58546 2 0127 +X 779437,716526,0,165733,0,82867 2 0130 +Y 779437,716526,0,203248,-152334,-11126 2 0131 +Z 643123,716526,0,152334,0,76168 2 0132 +lB 321562,786432,262144,196608 3 0133 +[ " +lq 539432,728178,0,176685 2 0134 +rB 321562,786432,262144,110392 3 0135 +] " +ha 535936,728178,0,69688 2 0136 +^ " +a^ " +a. 321562,700301,0,123230 2 0137 +oq 321562,728178,0,130200 2 0140 +` " +a 535936,451470,0,80440,-46677,80440 0 0141 +b 482342,728178,0,66190,-46677,66190 2 0142 +c 482342,451470,0,59274,-46677,59274 0 0143 +d 535936,728178,0,108354,-46677,108354 2 0144 +e 482342,451470,0,78789,-46677,78789 0 0145 +Fn 321562,728178,203890,222240,104566,112867 3 0146 +f " +g 482342,451470,203890,92770,-21045,55147 1 0147 +h 535936,728178,0,80440,0,80440 2 0150 +i 321562,687194,0,106846,-32427,106846 2 0151 +j 321562,687194,203890,151701,50973,92770 3 0152 +k 482342,728178,0,112867,0,80440 2 0153 +l 267968,728178,0,108354,-26797,107237 2 0154 +m 857498,451470,0,80440,-32427,80440 0 0155 +n 589530,451470,0,80440,-32427,80440 0 0156 +o 535936,451470,0,66190,-46677,66190 0 0157 +p 535936,451470,203890,66190,-22718,66190 1 0160 +q 482342,451470,203890,92770,-46677,55147 1 0161 +r 442147,451470,0,112867,-32427,86070 0 0162 +s 428749,451470,0,86070,0,86070 0 0163 +t 348358,644958,0,99469,-45875,99469 2 0164 +u 562733,451470,0,80440,-32427,80440 0 0165 +v 482342,451470,0,112867,-32427,75245 0 0166 +w 696717,451470,0,112867,-32427,84651 0 0167 +x 486421,451470,0,126266,0,126266 0 0170 +y 509139,451470,203890,92770,-32427,55147 1 0171 +z 428749,451470,0,128888,0,80440 0 0172 +en 535936,451470,0,96552 0 0173 +em 1071872,451470,0,96552 0 0174 +a" 535936,728178,0,128451 2 0175 +~ 535936,700301,0,121482 2 0176 +a~ " +char168 535936,700301,0,109832 2 0177 +ad " diff --git a/gnu/usr.bin/groff/devices/devdvi/MI b/gnu/usr.bin/groff/devices/devdvi/MI new file mode 100644 index 0000000000..2b2e3491ba --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/MI @@ -0,0 +1,136 @@ +name MI +special +internalname cmmi10 +slant 14.036243 +checksum 195060286 +designsize 10485760 +charset +--- 645166,716526,0,145637 2 0000 +--- 873816,716526 2 0001 +--- 799829,716526,0,29128 2 0002 +--- 728179,716526 2 0003 +--- 778424,716526,0,79371 2 0004 +--- 871630,716526,0,85195 2 0005 +--- 817746,716526,0,60438 2 0006 +--- 611669,716526,0,145637 2 0007 +--- 699051,716526 2 0010 +--- 641962,716526,0,115344 2 0011 +--- 809918,716526,0,52610 2 0012 +*a 670776,451470,0,3882 0 0013 +*b 593102,728178,203890,55342 3 0014 +*g 542880,451470,203890,58254 1 0015 +*d 466034,728178,0,39685 2 0016 +*e 425621,451470 0 0017 +*z 458754,728178,203890,77368 3 0020 +*y 520651,451470,203890,37622 1 0021 +*h 492248,728178,0,29128 2 0022 +*i 371130,451470 0 0023 +*k 604147,451470 0 0024 +*l 611672,728178 2 0025 +char181 631819,451470,203890 1 0026 +*m " +*n 517979,451470,0,66750 0 0027 +*c 458754,728178,203890,48242 3 0030 +*p 597717,451470,0,37622 0 0031 +*r 542130,451470,203890 1 0032 +*s 599171,451470,0,37622 0 0033 +*t 458390,451470,0,118694 0 0034 +*u 566525,451470,0,37622 0 0035 +*f 624778,728178,203890 3 0036 +*x 656086,451470,203890 1 0037 +*q 683034,728178,203890,37622 3 0040 +*w 652691,451470,0,37622 0 0041 +--- 488970,451470 0 0042 ++h 620170,728178 2 0043 ++p 868357,451470,0,29128 0 0044 +--- 542130,451470,203890 1 0045 +ts 380474,451470,101946,83739 1 0046 ++f 685944,451470,203890 1 0047 +--- 1048579,384696,-139592 0 0050 +--- 1048579,384696,-139592 0 0051 +--- 1048579,384696,-139592 0 0052 +--- 1048579,384696,-139592 0 0053 +--- 291272,486275,-38013 2 0054 +--- 291272,486275,-38013 2 0055 +--- 524290,487880,-36408 2 0056 +--- 524290,487880,-36408 2 0057 +--- 524290,451470 0 0060 +--- 524290,451470 0 0061 +--- 524290,451470 0 0062 +--- 524290,451470,203890 1 0063 +--- 524290,451470,203890 1 0064 +--- 524290,451470,203890 1 0065 +--- 524290,675749 2 0066 +--- 524290,451470,203890 1 0067 +--- 524290,675749 2 0070 +--- 524290,451470,203890 1 0071 +--- 291272,110683 0 0072 +--- 291272,110683,203890 1 0073 +< 815562,565285,40997 3 0074 +--- 524290,786432,262144 3 0075 +> 815562,565285,40997 3 0076 +--- 524290,487880,-36408 2 0077 +pd 556693,728178,0,58254 2 0100 +--- 786434,716526 2 0101 +--- 795355,716526,0,52610 2 0102 +--- 749440,716526,0,75002 2 0103 +--- 868134,716526,0,29128 2 0104 +--- 774054,716526,0,60438 2 0105 +--- 674294,716526,0,145637 2 0106 +--- 824442,716526 2 0107 +--- 871630,716526,0,85195 2 0110 +--- 460938,716526,0,82283 2 0111 +--- 581450,716526,0,100853 2 0112 +--- 890563,716526,0,75002 2 0113 +--- 713616,716526 2 0114 +--- 1017266,716526,0,114323 2 0115 +--- 842502,716526,0,114323 2 0116 +--- 799829,716526,0,29128 2 0117 +--- 673200,716526,0,145637 2 0120 +--- 828957,716526,203890 3 0121 +--- 796173,716526,0,8101 2 0122 +--- 642982,716526,0,60438 2 0123 +--- 612763,716526,0,145637 2 0124 +--- 715944,716526,0,114323 2 0125 +--- 611670,716526,0,233018 2 0126 +--- 990323,716526,0,145637 2 0127 +--- 868718,716526,0,82283 2 0130 +--- 608758,716526,0,233018 2 0131 +--- 715800,716526,0,75002 2 0132 +--- 407781,786432 2 0133 +--- 407781,728178,203890 3 0134 +--- 407781,728178,203890 3 0135 +--- 1048579,375013,-149275 0 0136 +--- 1048579,375013,-149275 0 0137 +--- 436910,728178 2 0140 +--- 554267,451470 0 0141 +--- 450014,728178 2 0142 +--- 453778,451470 0 0143 +--- 545771,728178 2 0144 +--- 488245,451470 0 0145 +--- 513368,728178,203890,112869 3 0146 +--- 500138,451470,203890,37622 1 0147 +--- 604147,728178 2 0150 +--- 361248,691562 2 0151 +--- 431811,691562,203890,60024 3 0152 +--- 545893,728178,0,33010 2 0153 +--- 312874,728178,0,20634 2 0154 +--- 920664,451470 0 0155 +--- 629392,451470 0 0156 +*o 508269,451470 0 0157 +--- 527566,451470,203890 1 0160 +--- 468099,451470,203890,37622 1 0161 +--- 473075,451470,0,29128 0 0162 +--- 491520,451470 0 0163 +--- 378654,644958 2 0164 +--- 600266,451470 0 0165 +--- 508270,451470,0,37622 0 0166 +--- 750694,451470,0,28216 0 0167 +--- 599291,451470 0 0170 +--- 514098,451470,203890,37622 1 0171 +--- 487640,451470,0,46117 0 0172 +--- 338120,451470 0 0173 +--- 402685,451470,203890 1 0174 +wp 667376,451470,203890 1 0175 +--- 524290,749149,0,161291 2 0176 +--- 291272,728178,0,418866 2 0177 diff --git a/gnu/usr.bin/groff/devices/devdvi/Makefile b/gnu/usr.bin/groff/devices/devdvi/Makefile new file mode 100644 index 0000000000..7bc9246154 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/Makefile @@ -0,0 +1,12 @@ +DEVICE= dvi +FONTFILES= R I B BI CW MI S EX H HI HB SA SB DESC $(DEVGENFILES) +DEVGENFILES= generate/CompileFonts generate/Makefile generate/msam.map\ + generate/msbm.map generate/texb.map generate/texex.map \ + generate/texi.map generate/texmi.map generate/texr.map \ + generate/texsy.map generate/textt.map + +NOOBJ= noobj + +clean cleandir: + +.include "../Makefile.dev" diff --git a/gnu/usr.bin/groff/devices/devdvi/R b/gnu/usr.bin/groff/devices/devdvi/R new file mode 100644 index 0000000000..3e49b938e7 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/R @@ -0,0 +1,430 @@ +name R +special +internalname cmr10 +spacewidth 349526 +ligatures ff fi fl ffi ffl 0 +checksum 1274110073 +designsize 10485760 +kernpairs +ff ' 81557 +ff ? 81557 +ff ! 81557 +ff ) 81557 +ff rB 81557 +ff ] 81557 +' ' -87382 +' ? 116509 +' ! 116509 +*A t -29128 +A t -29128 +*A C -29128 +A C -29128 +*A *O -29128 +*A O -29128 +A *O -29128 +A O -29128 +*A G -29128 +A G -29128 +*A U -29128 +A U -29128 +*A Q -29128 +A Q -29128 +*A *T -87382 +*A T -87382 +A *T -87382 +A T -87382 +*A Y -87382 +A Y -87382 +*A V -116509 +A V -116509 +*A W -116509 +A W -116509 +D *X -29128 +D X -29128 +D W -29128 +D *A -29128 +D A -29128 +D V -29128 +D Y -29128 +F o -87382 +F e -87382 +F u -87382 +F r -87382 +F a -87382 +F *A -116509 +F A -116509 +F *O -29128 +F O -29128 +F C -29128 +F G -29128 +F Q -29128 +*I *I 29128 +*I I 29128 +I *I 29128 +I I 29128 +*K *O -29128 +*K O -29128 +K *O -29128 +K O -29128 +*K C -29128 +K C -29128 +*K G -29128 +K G -29128 +*K Q -29128 +K Q -29128 +L *T -87382 +L T -87382 +L Y -87382 +L V -116509 +L W -116509 +*O *X -29128 +*O X -29128 +O *X -29128 +O X -29128 +*O W -29128 +O W -29128 +*O *A -29128 +*O A -29128 +O *A -29128 +O A -29128 +*O V -29128 +O V -29128 +*O Y -29128 +O Y -29128 +*R *A -87382 +*R A -87382 +P *A -87382 +P A -87382 +*R o -29128 +P o -29128 +*R e -29128 +P e -29128 +*R a -29128 +P a -29128 +*R . -87382 +P . -87382 +*R , -87382 +P , -87382 +R t -29128 +R C -29128 +R *O -29128 +R O -29128 +R G -29128 +R U -29128 +R Q -29128 +R *T -87382 +R T -87382 +R Y -87382 +R V -116509 +R W -116509 +*T y -29128 +T y -29128 +*T e -87382 +T e -87382 +*T o -87382 +T o -87382 +*T r -87382 +T r -87382 +*T a -87382 +T a -87382 +*T *A -87382 +*T A -87382 +T *A -87382 +T A -87382 +*T u -87382 +T u -87382 +V o -87382 +V e -87382 +V u -87382 +V r -87382 +V a -87382 +V *A -116509 +V A -116509 +V *O -29128 +V O -29128 +V C -29128 +V G -29128 +V Q -29128 +W o -87382 +W e -87382 +W u -87382 +W r -87382 +W a -87382 +W *A -116509 +W A -116509 +W *O -29128 +W O -29128 +W C -29128 +W G -29128 +W Q -29128 +*X *O -29128 +*X O -29128 +X *O -29128 +X O -29128 +*X C -29128 +X C -29128 +*X G -29128 +X G -29128 +*X Q -29128 +X Q -29128 +Y e -87382 +Y o -87382 +Y r -87382 +Y a -87382 +Y *A -87382 +Y A -87382 +Y u -87382 +oq oq -87382 +oq ` -87382 +` oq -87382 +` ` -87382 +a v -29128 +a j 58254 +a y -29128 +a w -29128 +b e 29128 +b o 29128 +b x -29128 +b d 29128 +b c 29128 +b q 29128 +b v -29128 +b j 58254 +b y -29128 +b w -29128 +c h -29128 +c k -29128 +f ' 81557 +f ? 81557 +f ! 81557 +f ) 81557 +f rB 81557 +f ] 81557 +g j 29128 +h t -29128 +h u -29128 +h b -29128 +h y -29128 +h v -29128 +h w -29128 +k a -58254 +k e -29128 +k a -29128 +k o -29128 +k c -29128 +m t -29128 +m u -29128 +m b -29128 +m y -29128 +m v -29128 +m w -29128 +n t -29128 +n u -29128 +n b -29128 +n y -29128 +n v -29128 +n w -29128 +o e 29128 +o o 29128 +o x -29128 +o d 29128 +o c 29128 +o q 29128 +o v -29128 +o j 58254 +o y -29128 +o w -29128 +p e 29128 +p o 29128 +p x -29128 +p d 29128 +p c 29128 +p q 29128 +p v -29128 +p j 58254 +p y -29128 +p w -29128 +t y -29128 +t w -29128 +u w -29128 +v a -58254 +v e -29128 +v a -29128 +v o -29128 +v c -29128 +w e -29128 +w a -29128 +w o -29128 +w c -29128 +y o -29128 +y e -29128 +y a -29128 +y . -87382 +y , -87382 +charset +*G 655362,716526,0,0,0,-145637 2 0000 +*D 873816,716526 2 0001 +*H 815562,716526,0,0,-29128,-29128 2 0002 +*L 728179,716526 2 0003 +*C 699053,716526 2 0004 +*P 786434,716526 2 0005 +*S 757307,716526 2 0006 +*U 815562,716526,0,0,-29128,-145637 2 0007 +*F 757307,716526,0,0,-29128 2 0010 +*Q 815562,716526,0,0,-29128,-72818 2 0011 +*W 757307,716526 2 0012 +ff 611672,728178,0,81557 2 0013 +fi 582544,728178 2 0014 +fl 582544,728178 2 0015 +Fi 873816,728178 2 0016 +Fl 873816,728178 2 0017 +.i 291272,451470 0 0020 +.j 320400,451470,203890 1 0021 +ga 524290,728178 2 0022 +char180 524290,728178 2 0023 +aa " +ah 524290,659002 2 0024 +ab 524290,728178 2 0025 +char175 524290,595357 2 0026 +a- " +ao 786434,728178 2 0027 +char184 466035,0,178403 1 0030 +ac " +char223 524291,728178 2 0031 +ss " +char230 757307,451470 0 0032 +ae " +oe 815562,451470 0 0033 +char248 524290,553416,101946 3 0034 +/o " +char198 946634,716526 2 0035 +AE " +OE 1063142,716526 2 0036 +char216 815562,767499,50973 3 0037 +/O " +--- 291272,451470 0 0040 +! 291272,728178 2 0041 +rq 524290,728178 2 0042 +sh 873816,728178,203888 3 0043 +# " +Do 524290,786432,58254 3 0044 +$ " +% 873816,786432,58254 3 0045 +& 815562,728178 2 0046 +' 291272,728178 2 0047 +( 407781,786432,262144 3 0050 +) 407781,786432,262144 3 0051 +* 524290,786432 2 0052 +pl 815562,611670,87382 3 0053 ++ " +, 291272,110683,203890 1 0054 +char173 349526,451470 0 0055 +hy " +- " +. 291272,110683 0 0056 +sl 524290,786432,262144 3 0057 +/ " +0 524290,675749 2 0060 +1 524290,675749 2 0061 +2 524290,675749 2 0062 +3 524290,675749 2 0063 +4 524290,675749 2 0064 +5 524290,675749 2 0065 +6 524290,675749 2 0066 +7 524290,675749 2 0067 +8 524290,675749 2 0070 +9 524290,675749 2 0071 +: 291272,451470 0 0072 +; 291272,451470,203890 1 0073 +char161 291272,524288,203890 3 0074 +r! " +eq 815562,384696,-139592 0 0075 += " +char191 495163,524288,203890 3 0076 +r? " +? 495163,728178 2 0077 +at 815562,728178 2 0100 +@ " +*A 786434,716526 2 0101 +A " +*B 742744,716526 2 0102 +B " +C 757307,716526,0,0,-29128 2 0103 +D 800998,716526,0,0,0,-29128 2 0104 +*E 713616,716526 2 0105 +E " +F 684490,716526,0,0,0,-145637 2 0106 +G 822843,716526,0,0,-29128 2 0107 +*Y 786434,716526 2 0110 +H " +*I 378653,716526 2 0111 +I " +J 538853,716526,0,0,0,-29128 2 0112 +*K 815562,716526 2 0113 +K " +L 655362,716526,0,0,0,58254 2 0114 +*M 961197,716526 2 0115 +M " +*N 786434,716526 2 0116 +N " +*O 815562,716526,0,0,-29128,-29128 2 0117 +O " +*R 713616,716526,0,0,0,-145637 2 0120 +P " +Q 815562,716526,203890,0,-29128 3 0121 +R 771870,716526 2 0122 +S 582544,716526 2 0123 +*T 757307,716526,0,0,0,-145637 2 0124 +T " +U 786434,716526,0,0,-14563 2 0125 +V 786434,716526,0,14563,43691,-218454 2 0126 +W 1077706,716526,0,14563,43691,-131074 2 0127 +*X 786434,716526 2 0130 +X " +Y 786434,716526,0,26214,29128,-206803 2 0131 +*Z 640798,716526 2 0132 +Z " +lB 291272,786432,262144 3 0133 +[ " +lq 524290,728178 2 0134 +rB 291272,786432,262144 3 0135 +] " +ha 524290,728178 2 0136 +^ " +a^ " +a. 291272,700301 2 0137 +oq 291272,728178 2 0140 +` " +a 524290,451470 0 0141 +b 582544,728178 2 0142 +c 466035,451470 0 0143 +d 582544,728178 2 0144 +e 466035,451470 0 0145 +f 320400,728178,0,81557 2 0146 +g 524290,451470,203890,14563 1 0147 +h 582544,728178 2 0150 +i 291272,700301 2 0151 +j 320400,700301,203890 3 0152 +k 553418,728178 2 0153 +l 291272,728178 2 0154 +m 873816,451470 0 0155 +n 582544,451470 0 0156 +o 524290,451470 0 0157 +p 582544,451470,203890 1 0160 +q 553416,451470,203890 1 0161 +r 410694,451470 0 0162 +s 413606,451470 0 0163 +t 407781,644958 2 0164 +u 582544,451470 0 0165 +v 553418,451470,0,14563 0 0166 +w 757307,451470,0,14563 0 0167 +x 553418,451470 0 0170 +y 553418,451470,203890,14563 1 0171 +z 466035,451470 0 0172 +en 524290,451470,0,29128 0 0173 +em 1048579,451470,0,29128 0 0174 +a" 524290,728178 2 0175 +~ 524290,700301 2 0176 +a~ " +char168 524290,700301 2 0177 +ad " diff --git a/gnu/usr.bin/groff/devices/devdvi/S b/gnu/usr.bin/groff/devices/devdvi/S new file mode 100644 index 0000000000..11b79ff9c6 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/S @@ -0,0 +1,152 @@ +name S +special +internalname cmsy10 +slant 14.036243 +checksum 555887770 +designsize 10485760 +charset +mi 815562,611670,87382 3 0000 +\- " +md 291272,466035,-58253 2 0001 +char215 815562,611670,87382 3 0002 +mu " +** 524290,487880,-36408 2 0003 +char247 815562,611670,87382 3 0004 +di " +--- 524290,466035,-58253 2 0005 +char177 815562,611670,87382 3 0006 ++- " +-+ 815562,611670,87382 3 0007 +c+ 815562,611670,87382 3 0010 +--- 815562,611670,87382 3 0011 +c* 815562,611670,87382 3 0012 +--- 815562,611670,87382 3 0013 +--- 815562,611670,87382 3 0014 +ci 1048579,728178,203890 3 0015 +--- 524290,466035,-58253 2 0016 +bu 524290,466035,-58253 2 0017 +--- 815562,486275,-38013 2 0020 +== 815562,486275,-38013 2 0021 +ib 815562,666864,142576 3 0022 +ip 815562,666864,142576 3 0023 +<= 815562,666864,142576 3 0024 +>= 815562,666864,142576 3 0025 +--- 815562,666864,142576 3 0026 +--- 815562,666864,142576 3 0027 +ti 815562,384696,-139592 0 0030 +ap " +~~ 815562,506590,-17698 2 0031 +sb 815562,565285,40997 3 0032 +sp 815562,565285,40997 3 0033 +<< 1048579,565285,40997 3 0034 +>> 1048579,565285,40997 3 0035 +--- 815562,565285,40997 3 0036 +--- 815562,565285,40997 3 0037 +<- 1048579,384696,-139592 0 0040 +-> 1048579,384696,-139592 0 0041 +ua 524290,728178,203888 3 0042 +da 524290,728178,203888 3 0043 +<> 1048579,384696,-139592 0 0044 +--- 1048579,728178,203888 3 0045 +--- 1048579,728178,203888 3 0046 +~= 815562,486275,-38013 2 0047 +lh 1048579,384696,-139592 0 0050 +lA " +rh 1048579,384696,-139592 0 0051 +rA " +uA 640798,728178,203888 3 0052 +dA 640798,728178,203888 3 0053 +hA 1048579,384696,-139592 0 0054 +--- 1048579,728178,203888 3 0055 +--- 1048579,728178,203888 3 0056 +pt 815562,451470 0 0057 +prime 288358,582544 2 0060 +if 1048579,451470 0 0061 +mo 699053,565285,40997 3 0062 +st 699053,565285,40997 3 0063 +--- 932070,728178,203890 3 0064 +--- 932070,728178,203890 3 0065 +slashnot 0,728178,203888 3 0066 +--- 0,384696,-139592 0 0067 +fa 582544,728178 2 0070 +te 582544,728178 2 0071 +char172 699053,451470 0 0072 +no " +es 524290,786432,58254 3 0073 +Re 757307,728178 2 0074 +Im 757307,728178 2 0075 +--- 815562,728178 2 0076 +pp 815562,728178 2 0077 +Ah 640798,728178 2 0100 +A 837258,716526 2 0101 +B 688715,716526,0,31890 2 0102 +C 552106,716526,0,61170 2 0103 +D 808864,716526,0,29128 2 0104 +E 553419,716526,0,93786 2 0105 +F 753662,716526,0,104130 2 0106 +G 623762,716526,101946,62184 3 0107 +H 885541,716526,0,10123 2 0110 +I 570966,716526,0,77408 2 0111 +J 710704,716526,101946,193694 3 0112 +K 798963,716526,0,15147 2 0113 +L 723229,716526 2 0114 +M 1259235,716526 2 0115 +N 860347,716526,0,154518 2 0116 +O 834786,716526,0,29128 2 0117 +P 729347,716526,0,86216 2 0120 +Q 856341,716526,101946 3 0121 +R 888672,716526 2 0122 +S 634974,716526,0,78638 2 0123 +T 571101,716526,0,266514 2 0124 +U 656232,716526,0,104130 2 0125 +V 642549,716526,0,86216 2 0126 +W 1035766,716526,0,86216 2 0127 +X 747946,716526,0,153541 2 0130 +Y 700802,716526,101946,86216 3 0131 +Z 759930,716526,0,83302 2 0132 +cu 699053,582544 2 0133 +ca 699053,582544 2 0134 +--- 699053,582544 2 0135 +AN 699053,582544 2 0136 +OR 699053,582544 2 0137 +--- 640798,728178 2 0140 +--- 640798,728178 2 0141 +lf 466035,786432,262144 3 0142 +rf 466035,786432,262144 3 0143 +lc 466035,786432,262144 3 0144 +rc 466035,786432,262144 3 0145 +{ 524290,786432,262144 3 0146 +lC " +} 524290,786432,262144 3 0147 +rC " +la 407781,786432,262144 3 0150 +ra 407781,786432,262144 3 0151 +bar 291272,786432,262144 3 0152 +or " +bv " +| " +ba " +bardbl 524290,786432,262144 3 0153 +va 524290,786432,262144 3 0154 +vA 640798,786432,262144 3 0155 +rs 524290,786432,262144 3 0156 +\ " +--- 291272,728178,203888 3 0157 +sr 873816,41942,1006634 1 0160 +--- 786434,716526 2 0161 +gr 873816,716526 2 0162 +--- 436909,728178,203890,116509 3 0163 +--- 699053,582544 2 0164 +--- 699053,582544 2 0165 +--- 815562,666864,142576 3 0166 +--- 815562,666864,142576 3 0167 +char167 466037,728178,203890 3 0170 +sc " +dg 466035,728178,203890 3 0171 +dd 466035,728178,203890 3 0172 +char182 640798,728178,203890 3 0173 +ps " +CL 815562,728178,135926 3 0174 +DI 815562,728178,135926 3 0175 +HE 815562,728178,135926 3 0176 +SP 815562,728178,135926 3 0177 diff --git a/gnu/usr.bin/groff/devices/devdvi/SA b/gnu/usr.bin/groff/devices/devdvi/SA new file mode 100644 index 0000000000..f2b258f16f --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/SA @@ -0,0 +1,143 @@ +name SA +special +internalname msam10 +checksum -1749815603 +designsize 10485760 +charset +boxdot 815562,709446 2 0000 +boxplus 815562,709446 2 0001 +boxtimes 815562,709446 2 0002 +square 815562,709446 2 0003 +blacksquare 815562,709446 2 0004 +centerdot 291272,576570 2 0005 +lz 699053,728178,116509 3 0006 +lozenge " +blacklozenge 699053,728178,116509 3 0007 +circlearrowright 815562,610248,85960 3 0010 +circlearrowleft 815562,610248,85960 3 0011 +rightleftharpoons 1048579,547770,14197 3 0012 +leftrightharpoons 1048579,547770,14197 3 0013 +boxminus 815562,709446 2 0014 +Vdash 757307,728178 2 0015 +Vvdash 932070,728178 2 0016 +vDash 640798,728178 2 0017 +twoheadrightarrow 1048579,547770,14197 3 0020 +twoheadleftarrow 1048579,547770,14197 3 0021 +leftleftarrows 1048579,709446,189584 3 0022 +rightrightarrows 1048579,709446,189584 3 0023 +upuparrows 873816,728178,203888 3 0024 +downdownarrows 873816,728178,203888 3 0025 +upharpoonright 436909,728178,203888 3 0026 +downharpoonright 436909,728178,203888 3 0027 +upharpoonleft 436909,728178,203888 3 0030 +downharpoonleft 436909,728178,203888 3 0031 +rightarrowtail 1165088,547770,14197 3 0032 +leftarrowtail 1165088,547770,14197 3 0033 +leftrightarrows 1048579,709446,189584 3 0034 +rightleftarrows 1048579,709446,189584 3 0035 +Lsh 524290,728178 2 0036 +Rsh 524290,728178 2 0037 +rightsquigarrow 1048579,396238,-139592 0 0040 +leftrightsquigarrow 1456360,396238,-139592 0 0041 +looparrowleft 1048579,576570 2 0042 +looparrowright 1048579,576570 2 0043 +circeq 815562,765021,240733 3 0044 +succsim 815562,765021,240733 3 0045 +gtrsim 815562,765021,240733 3 0046 +gtrapprox 815562,792549,268261 3 0047 +multimap 1165088,576570 2 0050 +3d 699053,728178 2 0051 +tf " +therefore " +because 699053,728178 2 0052 +doteqdot 815562,610248,85960 3 0053 +triangleq 815562,961197,85960 3 0054 +precsim 815562,765021,240733 3 0055 +lesssim 815562,765021,240733 3 0056 +lessapprox 815562,792549,268261 3 0057 +eqslantless 815562,667592,143304 3 0060 +eqslantgtr 815562,667592,143304 3 0061 +curlyeqprec 815562,667592,143304 3 0062 +curlyeqsucc 815562,667592,143304 3 0063 +preccurlyeq 815562,667592,143304 3 0064 +leqq 815562,792549,268261 3 0065 +leqslant 815562,667592,143304 3 0066 +lessgtr 815562,709446,189584 3 0067 +backprime 288358,576570 2 0070 +--- 524290,486557,-37731 2 0071 +risingdotseq 815562,610248,85960 3 0072 +fallingdotseq 815562,610248,85960 3 0073 +succcurlyeq 815562,667592,143304 3 0074 +geqq 815562,792549,268261 3 0075 +geqslant 815562,667592,143304 3 0076 +gtrless 815562,709446,189584 3 0077 +sqsubset 815562,576570,36882 3 0100 +sqsupset 815562,576570,36882 3 0101 +vartriangleright 815562,576570,36882 3 0102 +vartriangleleft 815562,576570,36882 3 0103 +trianglerighteq 815562,667592,143304 3 0104 +trianglelefteq 815562,667592,143304 3 0105 +bigstar 990323,728178,203888 3 0106 +between 524290,792549,268261 3 0107 +blacktriangledown 757307,576570 2 0110 +blacktriangleright 815562,576570,36882 3 0111 +blacktriangleleft 815562,576570,36882 3 0112 +--- 524290,486557,-37731 2 0113 +--- 524290,486557,-37731 2 0114 +vartriangle 757307,576570 2 0115 +blacktriangle 757307,576570 2 0116 +triangledown 757307,576570 2 0117 +eqcirc 815562,728178 2 0120 +lesseqgtr 815562,928714,404426 3 0121 +gtreqless 815562,928714,404426 3 0122 +lesseqqgtr 815562,1030294,506006 3 0123 +gtreqqless 815562,1030294,506006 3 0124 +char165 786434,709446,0,26214 2 0125 +Ye " +yen " +Rrightarrow 1048579,667592,143304 3 0126 +Lleftarrow 1048579,667592,143304 3 0127 +OK 873816,728178 2 0130 +checkmark " +veebar 640798,728178,203888 3 0131 +barwedge 640798,728178,203888 3 0132 +doublebarwedge 640798,792549,203888 3 0133 +/_ 757307,728178 2 0134 +angle " +measuredangle 757307,728178 2 0135 +sphericalangle 757307,547770,36882 3 0136 +varpropto 815562,728178 2 0137 +smallsmile 815562,728178,203888 3 0140 +smallfrown 815562,728178,203888 3 0141 +Subset 815562,576570,36882 3 0142 +Supset 815562,576570,36882 3 0143 +Cup 699053,576570 2 0144 +Cap 699053,576570 2 0145 +curlywedge 797355,576570 2 0146 +curlyvee 797355,576570 2 0147 +leftthreetimes 815562,728178 2 0150 +rightthreetimes 815562,728178 2 0151 +subseteqq 815562,792549,268261 3 0152 +supseteqq 815562,792549,268261 3 0153 +bumpeq 815562,576570,63568 3 0154 +Bumpeq 815562,576570,63568 3 0155 +lll 1398106,576570,36882 3 0156 +ggg 1398106,576570,36882 3 0157 +ulcorner 524290,728178 2 0160 +urcorner 524290,728178 2 0161 +rg 992648,709446,159430 3 0162 +char174 " +circledR " +circledS 946045,709446,159430 3 0163 +pitchfork 699053,728178 2 0164 +dotplus 815562,728178,85960 3 0165 +backsim 815562,396238,-139592 0 0166 +backsimeq 815562,486557,-37731 2 0167 +llcorner 524290,396238 0 0170 +lrcorner 524290,396238 0 0171 +maltese 873816,728178 2 0172 +complement 524290,865080 2 0173 +intercal 582544,451470,203888 1 0174 +circledcirc 815562,610248,85960 3 0175 +circledast 815562,610248,85960 3 0176 +circleddash 815562,610248,85960 3 0177 diff --git a/gnu/usr.bin/groff/devices/devdvi/SB b/gnu/usr.bin/groff/devices/devdvi/SB new file mode 100644 index 0000000000..a4be59db29 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/SB @@ -0,0 +1,132 @@ +name SB +special +internalname msbm10 +spacewidth 314576 +slant 87.709390 +checksum -2001332536 +designsize 10485760 +charset +lvertneqq 815562,794042,263635 3 0000 +gvertneqq 815562,794042,263635 3 0001 +nleq 815562,832390,317448 3 0002 +ngeq 815562,832390,317448 3 0003 +nless 815562,740048,215760 3 0004 +ngtr 815562,740048,215760 3 0005 +nprec 815562,740048,215760 3 0006 +nsucc 815562,740048,215760 3 0007 +lneqq 815562,794042,263635 3 0010 +gneqq 815562,794042,263635 3 0011 +nleqslant 815562,832390,317448 3 0012 +ngeqslant 815562,832390,317448 3 0013 +lneq 815562,666864,142576 3 0014 +gneq 815562,666864,142576 3 0015 +npreceq 815562,832390,317448 3 0016 +nsucceq 815562,832390,317448 3 0017 +precnsim 815562,777110,243501 3 0020 +succnsim 815562,777110,243501 3 0021 +lnsim 815562,777110,243501 3 0022 +gnsim 815562,777110,243501 3 0023 +nleqq 815562,964179,439891 3 0024 +ngeqq 815562,964179,439891 3 0025 +precneqq 815562,794042,263635 3 0026 +succneqq 815562,794042,263635 3 0027 +precnapprox 815562,794042,274379 3 0030 +succnapprox 815562,794042,274379 3 0031 +lnapprox 815562,794042,274379 3 0032 +gnapprox 815562,794042,274379 3 0033 +nsim 815562,384696,-139592 0 0034 +ncong 815562,832390,317448 3 0035 +diagup 932070,722352,203888 3 0036 +diagdown 932070,777110,203888 3 0037 +varsubsetneq 815562,666864,142576 3 0040 +varsupsetneq 815562,666864,142576 3 0041 +nsubseteqq 815562,794042,263635 3 0042 +nsupseteqq 815562,794042,263635 3 0043 +subsetneqq 815562,832390,298650 3 0044 +supsetneqq 815562,832390,298650 3 0045 +varsubsetneqq 815562,794042,263635 3 0046 +varsupsetneqq 815562,794042,263635 3 0047 +subsetneq 815562,666864,142576 3 0050 +supsetneq 815562,666864,142576 3 0051 +nsubseteq 815562,832390,317448 3 0052 +nsupseteq 815562,832390,317448 3 0053 +nparallel 524290,777110,263635 3 0054 +nmid 291272,777110,263635 3 0055 +nshortmid 233018,609920,85632 3 0056 +nshortparallel 407781,609920,85632 3 0057 +nvdash 640798,722352 2 0060 +nVdash 757307,722352 2 0061 +nvDash 640798,722352 2 0062 +nVDash 757307,722352 2 0063 +ntrianglerighteq 815562,832390,317448 3 0064 +ntrianglelefteq 815562,832390,317448 3 0065 +ntriangleleft 815562,740048,215760 3 0066 +ntriangleright 815562,740048,215760 3 0067 +nleftarrow 1048579,384696,-139592 0 0070 +nrightarrow 1048579,384696,-139592 0 0071 +nLeftarrow 1048579,384696,-139592 0 0072 +nRightarrow 1048579,384696,-139592 0 0073 +nLeftrightarrow 1048579,384696,-139592 0 0074 +nleftrightarrow 1048579,384696,-139592 0 0075 +divideontimes 815562,609920,85632 3 0076 +varnothing 815562,609920,85632 3 0077 +nexists 582544,722352 2 0100 +BbbA 757307,722352 2 0101 +BbbB 699053,722352 2 0102 +BbbC 757307,722352 2 0103 +BbbD 757307,722352 2 0104 +BbbE 699053,722352 2 0105 +BbbF 640798,722352 2 0106 +BbbG 815562,722352 2 0107 +BbbH 815562,722352 2 0110 +BbbI 407781,722352 2 0111 +BbbJ 524290,722352,174763 3 0112 +BbbK 815562,722352 2 0113 +BbbL 699053,722352 2 0114 +BbbM 990325,722352 2 0115 +BbbN 757307,722352 2 0116 +BbbO 815562,722352,174763 3 0117 +BbbP 640798,722352 2 0120 +BbbQ 815562,722352,174763 3 0121 +BbbR 757307,722352 2 0122 +BbbS 582544,722352 2 0123 +BbbT 699053,722352 2 0124 +BbbU 757307,722352 2 0125 +BbbV 757307,722352 2 0126 +BbbW 1048579,722352 2 0127 +BbbX 757307,722352 2 0130 +BbbY 757307,722352 2 0131 +BbbZ 699053,722352 2 0132 +--- 1980650,865080 2 0133 +--- 2446685,865080 2 0134 +--- 1980650,865080 2 0135 +--- 2446685,943717 2 0136 +Finv 582544,722352 2 0140 +Game 669925,722352 2 0141 +mho 757307,722352 2 0146 +eth 582544,722352 2 0147 +eqsim 815562,486275,-38013 2 0150 +beth 699053,722352 2 0151 +gimel 466035,722352 2 0152 +daleth 699053,722352 2 0153 +lessdot 815562,565285,40997 3 0154 +gtrdot 815562,565285,40997 3 0155 +ltimes 815562,609920,85632 3 0156 +rtimes 815562,609920,85632 3 0157 +shortmid 233018,609920,85632 3 0160 +shortparallel 407781,609920,85632 3 0161 +smallsetminus 815562,609920,85632 3 0162 +thicksim 815562,384696,-139592 0 0163 +thickapprox 815562,506590,-17698 2 0164 +approxeq 815562,609920,85632 3 0165 +succapprox 815562,794042,274379 3 0166 +precapprox 815562,794042,274379 3 0167 +curvearrowleft 1048579,451470 0 0170 +curvearrowright 1048579,451470 0 0171 +digamma 815562,609920,85632 3 0172 +varkappa 699053,451470,0,42235 0 0173 +Bbbk 582544,722352 2 0174 +hslash 566525,722352 2 0175 +-h 566525,722352 2 0176 +hbar " +backepsilon 450016,451470 0 0177 diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/CompileFonts b/gnu/usr.bin/groff/devices/devdvi/generate/CompileFonts new file mode 100644 index 0000000000..8859f8ea86 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/CompileFonts @@ -0,0 +1,15 @@ +#! /bin/sh +# Compile fonts in the sizes needed by groff. +sizes="5 6 7 8 9 10 11 12 14 16 18 20 22 24 28 36" +fonts="cmr10 cmti10 cmbx10 cmbxti10 cmtt10 cmex10 cmmi10 cmsy10 cmss10 cmssbx10 cmssi10" +mode=cx +dpi=300 + +for f in $fonts; do + for s in $sizes; do + virmf "&cm \\mode=$mode; mag=$s/10; batchmode; input $f" >/dev/null + mag=`expr $s \* $dpi / 10` + gftopk $f.${mag}gf >/dev/null + rm $f.${mag}gf + done +done diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/Makefile b/gnu/usr.bin/groff/devices/devdvi/generate/Makefile new file mode 100644 index 0000000000..f133ab6202 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/Makefile @@ -0,0 +1,93 @@ +#Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. +# Written by James Clark (jjc@jclark.com) +# +#This file is part of groff. +# +#groff is free software; you can redistribute it and/or modify it under +#the terms of the GNU General Public License as published by the Free +#Software Foundation; either version 2, or (at your option) any later +#version. +# +#groff is distributed in the hope that it will be useful, but WITHOUT ANY +#WARRANTY; without even the implied warranty of MERCHANTABILITY or +#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +#for more details. +# +#You should have received a copy of the GNU General Public License along +#with groff; see the file COPYING. If not, write to the Free Software +#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# This is set up so you can do: +# make -f generate/Makefile +# in the parent directory of the directory containing this file. + +srcdir=. +tfmdir=/usr/local/lib/groff-tfm +gfdir=/usr/local/lib/groff-gf + +TFMTODIT=tfmtodit +FONTS=R I B BI CW MI S EX H HI HB SA SB +SPECIALFLAG=-s + +all: $(FONTS) + +# R is special because it contains \(pl \(eq + +R: $(srcdir)/texr.map + $(TFMTODIT) $(SPECIALFLAG) -g $(gfdir)/cmr10.300gf \ + $(tfmdir)/cmr10.tfm $(srcdir)/texr.map $@ + +# I is special because it contains \(Po + +I: $(srcdir)/texi.map + $(TFMTODIT) $(SPECIALFLAG) -g $(gfdir)/cmti10.300gf \ + $(tfmdir)/cmti10.tfm $(srcdir)/texi.map $@ + +B: $(srcdir)/texb.map + $(TFMTODIT) -g $(gfdir)/cmbx10.300gf \ + $(tfmdir)/cmbx10.tfm $(srcdir)/texb.map $@ + +BI: $(srcdir)/texi.map + $(TFMTODIT) -g $(gfdir)/cmbxti10.300gf \ + $(tfmdir)/cmbxti10.tfm $(srcdir)/texi.map $@ + +# CW is special because it contains " + +CW: $(srcdir)/textt.map + $(TFMTODIT) $(SPECIALFLAG) $(tfmdir)/cmtt10.tfm $(srcdir)/textt.map $@ + +MI: $(srcdir)/texmi.map + $(TFMTODIT) $(SPECIALFLAG) -k 0177 $(tfmdir)/cmmi10.tfm $(srcdir)/texmi.map $@ + +S: $(srcdir)/texsy.map + $(TFMTODIT) $(SPECIALFLAG) -k 060 $(tfmdir)/cmsy10.tfm $(srcdir)/texsy.map $@ + +EX: $(srcdir)/texex.map + $(TFMTODIT) $(SPECIALFLAG) $(tfmdir)/cmex10.tfm $(srcdir)/texex.map $@ + +H: $(srcdir)/texr.map + $(TFMTODIT) -g $(gfdir)/cmss10.300gf $(tfmdir)/cmss10.tfm $(srcdir)/texb.map $@ + +HB: $(srcdir)/texr.map + $(TFMTODIT) -g $(gfdir)/cmssbx10.300gf \ + $(tfmdir)/cmssbx10.tfm $(srcdir)/texb.map $@ + +HI: $(srcdir)/texr.map + $(TFMTODIT) -g $(gfdir)/cmssi10.300gf \ + $(tfmdir)/cmssi10.tfm $(srcdir)/texb.map $@ + +SA: $(srcdir)/msam.map + $(TFMTODIT) $(SPECIALFLAG) $(tfmdir)/msam10.tfm $(srcdir)/msam.map $@ + +SB: $(srcdir)/msbm.map + $(TFMTODIT) $(SPECIALFLAG) $(tfmdir)/msbm10.tfm $(srcdir)/msbm.map $@ + +clean: + +realclean: + -rm -f $(FONTS) + +extraclean: realclean + -rm -f core *~ \#* + +.PHONY: clean realclean extraclean all diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/msam.map b/gnu/usr.bin/groff/devices/devdvi/generate/msam.map new file mode 100644 index 0000000000..90006c9576 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/msam.map @@ -0,0 +1,127 @@ +# Map for the AMSFonts 2.0 msam font using TeX names. +# Contributed by Zdzislaw Meglicki (Zdzislaw.Meglicki@arp.anu.edu.au). +0 boxdot +1 boxplus +2 boxtimes +3 square +4 blacksquare +5 centerdot +6 lozenge lz +7 blacklozenge +8 circlearrowright +9 circlearrowleft +10 rightleftharpoons +11 leftrightharpoons +12 boxminus +13 Vdash +14 Vvdash +15 vDash +16 twoheadrightarrow +17 twoheadleftarrow +18 leftleftarrows +19 rightrightarrows +20 upuparrows +21 downdownarrows +22 upharpoonright +23 downharpoonright +24 upharpoonleft +25 downharpoonleft +26 rightarrowtail +27 leftarrowtail +28 leftrightarrows +29 rightleftarrows +30 Lsh +31 Rsh +32 rightsquigarrow +33 leftrightsquigarrow +34 looparrowleft +35 looparrowright +36 circeq +37 succsim +38 gtrsim +39 gtrapprox +40 multimap +41 therefore tf 3d +42 because +43 doteqdot +44 triangleq +45 precsim +46 lesssim +47 lessapprox +48 eqslantless +49 eqslantgtr +50 curlyeqprec +51 curlyeqsucc +52 preccurlyeq +53 leqq +54 leqslant +55 lessgtr +56 backprime +58 risingdotseq +59 fallingdotseq +60 succcurlyeq +61 geqq +62 geqslant +63 gtrless +64 sqsubset +65 sqsupset +66 vartriangleright +67 vartriangleleft +68 trianglerighteq +69 trianglelefteq +70 bigstar +71 between +72 blacktriangledown +73 blacktriangleright +74 blacktriangleleft +77 vartriangle +78 blacktriangle +79 triangledown +80 eqcirc +81 lesseqgtr +82 gtreqless +83 lesseqqgtr +84 gtreqqless +85 yen Ye char165 +86 Rrightarrow +87 Lleftarrow +88 checkmark OK +89 veebar +90 barwedge +91 doublebarwedge +92 angle /_ +93 measuredangle +94 sphericalangle +95 varpropto +96 smallsmile +97 smallfrown +98 Subset +99 Supset +100 Cup +101 Cap +102 curlywedge +103 curlyvee +104 leftthreetimes +105 rightthreetimes +106 subseteqq +107 supseteqq +108 bumpeq +109 Bumpeq +110 lll +111 ggg +112 ulcorner +113 urcorner +114 circledR char174 rg +115 circledS +116 pitchfork +117 dotplus +118 backsim +119 backsimeq +120 llcorner +121 lrcorner +122 maltese +123 complement +124 intercal +125 circledcirc +126 circledast +127 circleddash diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/msbm.map b/gnu/usr.bin/groff/devices/devdvi/generate/msbm.map new file mode 100644 index 0000000000..07ee095d41 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/msbm.map @@ -0,0 +1,121 @@ +# Map for the AMSFonts 2.0 msbm font using TeX names. +# Contributed by Zdzislaw Meglicki (Zdzislaw.Meglicki@arp.anu.edu.au). +0 lvertneqq +1 gvertneqq +2 nleq +3 ngeq +4 nless +5 ngtr +6 nprec +7 nsucc +8 lneqq +9 gneqq +10 nleqslant +11 ngeqslant +12 lneq +13 gneq +14 npreceq +15 nsucceq +16 precnsim +17 succnsim +18 lnsim +19 gnsim +20 nleqq +21 ngeqq +22 precneqq +23 succneqq +24 precnapprox +25 succnapprox +26 lnapprox +27 gnapprox +28 nsim +29 ncong +30 diagup +31 diagdown +32 varsubsetneq +33 varsupsetneq +34 nsubseteqq +35 nsupseteqq +36 subsetneqq +37 supsetneqq +38 varsubsetneqq +39 varsupsetneqq +40 subsetneq +41 supsetneq +42 nsubseteq +43 nsupseteq +44 nparallel +45 nmid +46 nshortmid +47 nshortparallel +48 nvdash +49 nVdash +50 nvDash +51 nVDash +52 ntrianglerighteq +53 ntrianglelefteq +54 ntriangleleft +55 ntriangleright +56 nleftarrow +57 nrightarrow +58 nLeftarrow +59 nRightarrow +60 nLeftrightarrow +61 nleftrightarrow +62 divideontimes +63 varnothing +64 nexists +65 BbbA +66 BbbB +67 BbbC +68 BbbD +69 BbbE +70 BbbF +71 BbbG +72 BbbH +73 BbbI +74 BbbJ +75 BbbK +76 BbbL +77 BbbM +78 BbbN +79 BbbO +80 BbbP +81 BbbQ +82 BbbR +83 BbbS +84 BbbT +85 BbbU +86 BbbV +87 BbbW +88 BbbX +89 BbbY +90 BbbZ +96 Finv +97 Game +102 mho +103 eth +104 eqsim +105 beth +106 gimel +107 daleth +108 lessdot +109 gtrdot +110 ltimes +111 rtimes +112 shortmid +113 shortparallel +114 smallsetminus +115 thicksim +116 thickapprox +117 approxeq +118 succapprox +119 precapprox +120 curvearrowleft +121 curvearrowright +122 digamma +123 varkappa +124 Bbbk +125 hslash +126 hbar -h +127 backepsilon diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/texb.map b/gnu/usr.bin/groff/devices/devdvi/generate/texb.map new file mode 100644 index 0000000000..67008339e9 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/texb.map @@ -0,0 +1,127 @@ +0 *G +1 *D +2 *H +3 *L +4 *C +5 *P +6 *S +7 *U +8 *F +9 *Q +10 *W +11 ff +12 fi +13 fl +14 Fi +15 Fl +16 .i +17 .j +18 ga +19 aa char180 +20 ah +21 ab +22 a- char175 +23 ao +24 ac char184 +25 ss char223 +26 ae char230 +27 oe +28 /o char248 +29 AE char198 +30 OE +31 /O char216 +33 ! +34 rq +35 # sh +36 $ Do +37 % +38 & +39 ' +40 ( +41 ) +42 * +43 + +44 , +45 - hy char173 +46 . +47 / sl +48 0 +49 1 +50 2 +51 3 +52 4 +53 5 +54 6 +55 7 +56 8 +57 9 +58 : +59 ; +60 r! char161 +61 = +62 r? char191 +63 ? +64 @ at +65 A +66 B +67 C +68 D +69 E +70 F +71 G +72 H +73 I +74 J +75 K +76 L +77 M +78 N +79 O +80 P +81 Q +82 R +83 S +84 T +85 U +86 V +87 W +88 X +89 Y +90 Z +91 [ lB +92 lq +93 ] rB +94 a^ ^ ha +95 a. +96 ` oq +97 a +98 b +99 c +100 d +101 e +102 f +103 g +104 h +105 i +106 j +107 k +108 l +109 m +110 n +111 o +112 p +113 q +114 r +115 s +116 t +117 u +118 v +119 w +120 x +121 y +122 z +123 en +124 em +125 a" +126 a~ ~ +127 ad char168 diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/texex.map b/gnu/usr.bin/groff/devices/devdvi/generate/texex.map new file mode 100644 index 0000000000..a5b26901da --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/texex.map @@ -0,0 +1,100 @@ +0 parenleft0 +1 parenright0 +2 bracketleft0 +3 bracketright0 +4 floorleft0 +5 floorright0 +6 ceilingleft0 +7 ceilingright0 +8 braceleft0 +9 braceright0 +10 angleleft0 +11 angleright0 +12 barex +13 bardblex +14 slash0 +15 backslash0 +16 parenleft1 +17 parenright1 +18 parenleft2 +19 parenright2 +20 bracketleft2 +21 bracketright2 +22 floorleft2 +23 floorright2 +24 ceilingleft2 +25 ceilingright2 +26 braceleft2 +27 braceright2 +28 angleleft2 +29 angleright2 +30 slash2 +31 backslash2 +32 parenleft3 +33 parenright3 +34 bracketleft3 +35 bracketright3 +36 floorleft3 +37 floorright3 +38 ceilingleft3 +39 ceilingright3 +40 braceleft3 +41 braceright3 +42 angleleft3 +43 angleright3 +44 slash3 +45 backslash3 +46 slash1 +47 backslash1 +48 parenlefttp +49 parenrighttp +50 bracketlefttp +51 bracketrighttp +52 bracketleftbt +53 bracketrightbt +54 bracketleftex +55 bracketrightex +56 bracelefttp lt +57 bracerighttp rt +58 braceleftbt lb +59 bracerightbt rb +60 braceleftmid lk +61 bracerightmid rk +62 braceex bracerightex braceleftex +63 arrowvertex +64 parenleftbt +65 parenrightbt +66 parenleftex +67 parenrightex +68 angleleft1 +69 angleright1 +73 ois ointegral +75 bigcircledot +77 bigcircleplus +79 bigcirclemultiply +88 sum +89 product +90 is integral +91 bigunion +92 bigintersection +93 bigunionplus +94 biglogicaland +95 biglogicalor +97 coproduct +104 bracketleft1 +105 bracketright1 +106 floorleft1 +107 floorright1 +108 ceilingleft1 +109 ceilingright1 +110 braceleft1 +111 braceright1 +112 sr0 +113 sr1 +114 sr2 +115 sr3 +119 arrowvertdblex +120 arrowverttp +121 arrowvertbt +126 arrowvertdbltp +127 arrowvertdblbt diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/texi.map b/gnu/usr.bin/groff/devices/devdvi/generate/texi.map new file mode 100644 index 0000000000..835c6421f6 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/texi.map @@ -0,0 +1,127 @@ +0 *G +1 *D +2 *H +3 *L +4 *C +5 *P +6 *S +7 *U +8 *F +9 *Q +10 *W +11 ff +12 fi +13 fl +14 Fi +15 Fl +16 .i +17 .j +18 ga +19 aa char180 +20 ah +21 ab +22 a- char175 +23 ao +24 ac char184 +25 ss char223 +26 ae char230 +27 oe +28 /o char248 +29 AE char198 +30 OE +31 /O char216 +33 ! +34 rq +35 # sh +36 Po char163 +37 % +38 & +39 ' +40 ( +41 ) +42 * +43 + +44 , +45 - hy char173 +46 . +47 / sl +48 0 +49 1 +50 2 +51 3 +52 4 +53 5 +54 6 +55 7 +56 8 +57 9 +58 : +59 ; +60 r! char161 +61 = +62 r? char191 +63 ? +64 @ at +65 A +66 B +67 C +68 D +69 E +70 F +71 G +72 H +73 I +74 J +75 K +76 L +77 M +78 N +79 O +80 P +81 Q +82 R +83 S +84 T +85 U +86 V +87 W +88 X +89 Y +90 Z +91 [ lB +92 lq +93 ] rB +94 a^ ^ ha +95 a. +96 ` oq +97 a +98 b +99 c +100 d +101 e +102 f Fn +103 g +104 h +105 i +106 j +107 k +108 l +109 m +110 n +111 o +112 p +113 q +114 r +115 s +116 t +117 u +118 v +119 w +120 x +121 y +122 z +123 en +124 em +125 a" +126 a~ ~ +127 ad char168 diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/texmi.map b/gnu/usr.bin/groff/devices/devdvi/generate/texmi.map new file mode 100644 index 0000000000..6d01dc4cf9 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/texmi.map @@ -0,0 +1,32 @@ +11 *a +12 *b +13 *g +14 *d +15 *e +16 *z +17 *y +18 *h +19 *i +20 *k +21 *l +22 *m char181 +23 *n +24 *c +25 *p +26 *r +27 *s +28 *t +29 *u +30 *f +31 *x +32 *q +33 *w +35 +h +36 +p +38 ts +39 +f +60 < +62 > +64 pd +111 *o +125 wp diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/texr.map b/gnu/usr.bin/groff/devices/devdvi/generate/texr.map new file mode 100644 index 0000000000..bebf67b80c --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/texr.map @@ -0,0 +1,127 @@ +0 *G +1 *D +2 *H +3 *L +4 *C +5 *P +6 *S +7 *U +8 *F +9 *Q +10 *W +11 ff +12 fi +13 fl +14 Fi +15 Fl +16 .i +17 .j +18 ga +19 aa char180 +20 ah +21 ab +22 a- char175 +23 ao +24 ac char184 +25 ss char223 +26 ae char230 +27 oe +28 /o char248 +29 AE char198 +30 OE +31 /O char216 +33 ! +34 rq +35 # sh +36 $ Do +37 % +38 & +39 ' +40 ( +41 ) +42 * +43 + pl +44 , +45 - hy char173 +46 . +47 / sl +48 0 +49 1 +50 2 +51 3 +52 4 +53 5 +54 6 +55 7 +56 8 +57 9 +58 : +59 ; +60 r! char161 +61 = eq +62 r? char191 +63 ? +64 @ at +65 A *A +66 B *B +67 C +68 D +69 E *E +70 F +71 G +72 H *Y +73 I *I +74 J +75 K *K +76 L +77 M *M +78 N *N +79 O *O +80 P *R +81 Q +82 R +83 S +84 T *T +85 U +86 V +87 W +88 X *X +89 Y +90 Z *Z +91 [ lB +92 lq +93 ] rB +94 a^ ^ ha +95 a. +96 ` oq +97 a +98 b +99 c +100 d +101 e +102 f +103 g +104 h +105 i +106 j +107 k +108 l +109 m +110 n +111 o +112 p +113 q +114 r +115 s +116 t +117 u +118 v +119 w +120 x +121 y +122 z +123 en +124 em +125 a" +126 a~ ~ +127 ad char168 diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/texsy.map b/gnu/usr.bin/groff/devices/devdvi/generate/texsy.map new file mode 100644 index 0000000000..2c970bc2a4 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/texsy.map @@ -0,0 +1,100 @@ +0 \- mi +1 md +2 mu char215 +3 ** +4 di char247 +6 +- char177 +7 -+ +8 c+ +10 c* +13 ci +15 bu +17 == +18 ib +19 ip +20 <= +21 >= +24 ap ti +25 ~~ +26 sb +27 sp +28 << +29 >> +32 <- +33 -> +34 ua +35 da +36 <> +39 ~= +40 lA lh +41 rA rh +42 uA +43 dA +44 hA +47 pt +48 prime +49 if +50 mo +51 st +54 slashnot +56 fa +57 te +58 no char172 +59 es +60 Re +61 Im +63 pp +64 Ah +65 A +66 B +67 C +68 D +69 E +70 F +71 G +72 H +73 I +74 J +75 K +76 L +77 M +78 N +79 O +80 P +81 Q +82 R +83 S +84 T +85 U +86 V +87 W +88 X +89 Y +90 Z +91 cu +92 ca +94 AN +95 OR +98 lf +99 rf +100 lc +101 rc +102 lC { +103 rC } +104 la +105 ra +106 ba | bv or bar +107 bardbl +108 va +109 vA +110 \ rs +112 sr +114 gr +120 sc char167 +121 dg +122 dd +123 ps char182 +124 CL +125 DI +126 HE +127 SP diff --git a/gnu/usr.bin/groff/devices/devdvi/generate/textt.map b/gnu/usr.bin/groff/devices/devdvi/generate/textt.map new file mode 100644 index 0000000000..1461d0abe9 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devdvi/generate/textt.map @@ -0,0 +1,126 @@ +0 *G +1 *D +2 *H +3 *L +4 *C +5 *P +6 *S +7 *U +8 *F +9 *Q +10 *W +11 ff +12 fi +13 fl +14 Fi +15 Fl +16 .i +17 .j +18 ga +19 aa char180 +20 ah +21 ab +22 a- char175 +23 ao +24 ac char184 +25 ss char223 +26 ae char230 +27 oe +28 /o char248 +29 AE char198 +30 OE +31 /O char216 +33 ! +34 " +35 # sh +36 $ Do +37 % +38 & +39 ' +40 ( +41 ) +42 * +43 + +44 , +45 - \- +46 . +47 / sl +48 0 +49 1 +50 2 +51 3 +52 4 +53 5 +54 6 +55 7 +56 8 +57 9 +58 : +59 ; +60 < +61 = +62 > +63 ? +64 @ at +65 A +66 B +67 C +68 D +69 E +70 F +71 G +72 H +73 I +74 J +75 K +76 L +77 M +78 N +79 O +80 P +81 Q +82 R +83 S +84 T +85 U +86 V +87 W +88 X +89 Y +90 Z +91 [ lB +92 \ rs +93 ] rB +94 a^ ^ ha +95 _ +96 ` oq +97 a +98 b +99 c +100 d +101 e +102 f +103 g +104 h +105 i +106 j +107 k +108 l +109 m +110 n +111 o +112 p +113 q +114 r +115 s +116 t +117 u +118 v +119 w +120 x +121 y +122 z +123 lC { +124 ba | +125 rC } +126 a~ ~ diff --git a/gnu/usr.bin/groff/devices/devlatin1/DESC.proto b/gnu/usr.bin/groff/devices/devlatin1/DESC.proto new file mode 100644 index 0000000000..88399ab16d --- /dev/null +++ b/gnu/usr.bin/groff/devices/devlatin1/DESC.proto @@ -0,0 +1,8 @@ +res 240 +hor 24 +vert 40 +unitwidth 10 +sizes 10 0 +fonts 4 R I B BI +tcommand +postpro grotty diff --git a/gnu/usr.bin/groff/devices/devlatin1/Makefile b/gnu/usr.bin/groff/devices/devlatin1/Makefile new file mode 100644 index 0000000000..040504cd60 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devlatin1/Makefile @@ -0,0 +1,6 @@ +# Makefile for devascii + +DEVICE= latin1 + +.include "../Makefile.tty" +.include "../Makefile.dev" diff --git a/gnu/usr.bin/groff/devices/devlatin1/R.proto b/gnu/usr.bin/groff/devices/devlatin1/R.proto new file mode 100644 index 0000000000..29a88754ba --- /dev/null +++ b/gnu/usr.bin/groff/devices/devlatin1/R.proto @@ -0,0 +1,353 @@ +name R +internalname 0 +spacewidth 24 +charset +! 24 0 0041 +" 24 0 0042 +lq " +rq " +# 24 0 0043 +sh " +$ 24 0 0044 +Do " +% 24 0 0045 +& 24 0 0046 +' 24 0 0047 +fm " +aq " +( 24 0 0050 +) 24 0 0051 +* 24 0 0052 +** " ++ 24 0 0053 +pl " +, 24 0 0054 +\- 24 0 0055 +mi " +- " +hy " +en " +. 24 0 0056 +/ 24 0 0057 +sl " +f/ " +0 24 0 0060 +1 24 0 0061 +2 24 0 0062 +3 24 0 0063 +4 24 0 0064 +5 24 0 0065 +6 24 0 0066 +7 24 0 0067 +8 24 0 0070 +9 24 0 0071 +: 24 0 0072 +; 24 0 0073 +< 24 0 0074 +la " +fo " += 24 0 0075 +eq " +> 24 0 0076 +ra " +fc " +? 24 0 0077 +@ 24 0 0100 +at " +A 24 0 0101 +*A " +B 24 0 0102 +*B " +C 24 0 0103 +D 24 0 0104 +E 24 0 0105 +*E " +F 24 0 0106 +G 24 0 0107 +H 24 0 0110 +*Y " +I 24 0 0111 +*I " +J 24 0 0112 +K 24 0 0113 +*K " +L 24 0 0114 +M 24 0 0115 +*M " +N 24 0 0116 +*N " +O 24 0 0117 +ci " +*O " +P 24 0 0120 +*R " +Q 24 0 0121 +R 24 0 0122 +S 24 0 0123 +T 24 0 0124 +*T " +U 24 0 0125 +V 24 0 0126 +W 24 0 0127 +X 24 0 0130 +*X " +Y 24 0 0131 +*U " +Z 24 0 0132 +*Z " +[ 24 0 0133 +lB " +\ 24 0 0134 +rs " +] 24 0 0135 +rB " +a^ 24 0 0136 +^ " +ha " +_ 24 0 0137 +ru " +ul " +` 24 0 0140 +oq " +ga " +a 24 0 0141 +b 24 0 0142 +c 24 0 0143 +d 24 0 0144 +e 24 0 0145 +f 24 0 0146 +g 24 0 0147 +h 24 0 0150 +i 24 0 0151 +.i " +j 24 0 0152 +k 24 0 0153 +l 24 0 0154 +m 24 0 0155 +n 24 0 0156 +o 24 0 0157 +*o " +p 24 0 0160 +q 24 0 0161 +r 24 0 0162 +s 24 0 0163 +t 24 0 0164 +u 24 0 0165 +v 24 0 0166 +w 24 0 0167 +x 24 0 0170 +y 24 0 0171 +z 24 0 0172 +lC 24 0 0173 +{ " +ba 24 0 0174 +or " +bv " +br " +| " +lb " +lc " +lf " +lk " +lt " +rb " +rc " +rf " +rk " +rt " +rC 24 0 0175 +} " +a~ 24 0 0176 +~ " +ap " +ti " +r! 24 0 0241 +char161 " +ct 24 0 0242 +char162 " +Po 24 0 0243 +char163 " +Cs 24 0 0244 +char164 " +Ye 24 0 0245 +char165 " +bb 24 0 0246 +char166 " +sc 24 0 0247 +char167 " +ad 24 0 0250 +char168 " +co 24 0 0251 +char169 " +Of 24 0 0252 +char170 " +Fo 24 0 0253 +char171 " +no 24 0 0254 +char172 " +char173 24 0 0255 +rg 24 0 0256 +char174 " +a- 24 0 0257 +char175 " +de 24 0 0260 +char176 " +ao " ++- 24 0 0261 +char177 " +S2 24 0 0262 +char178 " +S3 24 0 0263 +char179 " +aa 24 0 0264 +char180 " +*m 24 0 0265 +char181 " +ps 24 0 0266 +char182 " +md 24 0 0267 +char183 " +ac 24 0 0270 +char184 " +S1 24 0 0271 +char185 " +Om 24 0 0272 +char186 " +Fc 24 0 0273 +char187 " +14 24 0 0274 +char188 " +12 24 0 0275 +char189 " +34 24 0 0276 +char190 " +r? 24 0 0277 +char191 " +`A 24 0 0300 +char192 " +'A 24 0 0301 +char193 " +^A 24 0 0302 +char194 " +~A 24 0 0303 +char195 " +:A 24 0 0304 +char196 " +oA 24 0 0305 +char197 " +AE 24 0 0306 +char198 " +,C 24 0 0307 +char199 " +`E 24 0 0310 +char200 " +'E 24 0 0311 +char201 " +^E 24 0 0312 +char202 " +:E 24 0 0313 +char203 " +`I 24 0 0314 +char204 " +'I 24 0 0315 +char205 " +^I 24 0 0316 +char206 " +:I 24 0 0317 +char207 " +-D 24 0 0320 +char208 " +~N 24 0 0321 +char209 " +`O 24 0 0322 +char210 " +'O 24 0 0323 +char211 " +^O 24 0 0324 +char212 " +~O 24 0 0325 +char213 " +:O 24 0 0326 +char214 " +mu 24 0 0327 +char215 " +/O 24 0 0330 +char216 " +`U 24 0 0331 +char217 " +'U 24 0 0332 +char218 " +^U 24 0 0333 +char219 " +:U 24 0 0334 +char220 " +'Y 24 0 0335 +char221 " +TP 24 0 0336 +char222 " +ss 24 0 0337 +char223 " +`a 24 0 0340 +char224 " +'a 24 0 0341 +char225 " +^a 24 0 0342 +char226 " +~a 24 0 0343 +char227 " +:a 24 0 0344 +char228 " +oa 24 0 0345 +char229 " +ae 24 0 0346 +char230 " +,c 24 0 0347 +char231 " +`e 24 0 0350 +char232 " +'e 24 0 0351 +char233 " +^e 24 0 0352 +char234 " +:e 24 0 0353 +char235 " +`i 24 0 0354 +char236 " +'i 24 0 0355 +char237 " +^i 24 0 0356 +char238 " +:i 24 0 0357 +char239 " +Sd 24 0 0360 +char240 " +~n 24 0 0361 +char241 " +`o 24 0 0362 +char242 " +'o 24 0 0363 +char243 " +^o 24 0 0364 +char244 " +~o 24 0 0365 +char245 " +:o 24 0 0366 +char246 " +di 24 0 0367 +char247 " +/o 24 0 0370 +char248 " +`u 24 0 0371 +char249 " +'u 24 0 0372 +char250 " +^u 24 0 0373 +char251 " +:u 24 0 0374 +char252 " +'y 24 0 0375 +char253 " +Tp 24 0 0376 +char254 " +:y 24 0 0377 +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/AB b/gnu/usr.bin/groff/devices/devps/AB new file mode 100644 index 0000000000..d5313f0de4 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/AB @@ -0,0 +1,559 @@ +name AB +internalname AvantGarde-Demi +spacewidth 280 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -50 +A w -65 +A v -70 +A u -20 +A ' -90 +A Y -80 +A W -60 +A V -102 +A U -40 +A T -25 +A Q -50 +A O -50 +A G -40 +A C -40 +B A -10 +C A -40 +D . -20 +D , -20 +D Y -45 +D W -25 +D V -50 +D A -50 +F . -129 +F e -20 +F , -162 +F a -20 +F A -75 +G . -20 +G , -20 +G Y -15 +J . -15 +J a -20 +J A -30 +K y -20 +K u -15 +K o -45 +K e -40 +K O -30 +L y -23 +L ' -30 +L rq -30 +L Y -80 +L W -55 +L V -85 +L T -46 +O . -30 +O , -30 +O Y -30 +O X -30 +O W -20 +O V -45 +O T -15 +O A -60 +P . -200 +P o -20 +P e -20 +P , -220 +P a -20 +P A -100 +Q , 20 +R W 25 +R V -10 +R U 25 +R T 40 +R O 25 +S , 20 +T y -10 +T w -55 +T u -46 +T ; -29 +T r -30 +T . -91 +T o -49 +T - -75 +T hy -75 +T char173 -75 +T e -49 +T , -82 +T : -15 +T a -70 +T O -15 +T A -25 +U . -20 +U , -20 +U A -40 +V u -55 +V ; -33 +V . -145 +V o -101 +V i -15 +V - -75 +V hy -75 +V char173 -75 +V e -101 +V , -145 +V : -18 +V a -95 +V O -45 +V G -20 +V A -102 +W y -15 +W u -30 +W ; -33 +W . -106 +W o -46 +W i -10 +W - -35 +W hy -35 +W char173 -35 +W e -47 +W , -106 +W : -15 +W a -50 +W O -20 +W A -58 +Y u -52 +Y ; -23 +Y . -145 +Y o -89 +Y - -100 +Y hy -100 +Y char173 -100 +Y e -89 +Y , -145 +Y : -10 +Y a -93 +Y O -30 +Y A -80 +a t 5 +a p 20 +a b 5 +b y -20 +b v -20 +c y -20 +c l -15 +c k -15 +, ' -70 +, rq -70 +e y -20 +e x -20 +e w -20 +e v -20 +f . -40 +f o -20 +f l -15 +f i -15 +f f -20 +f .i -15 +f , -40 +f a -15 +g i 25 +g a 15 +h y -30 +k y -5 +k o -30 +k e -40 +m y -20 +m u -20 +n y -15 +n v -30 +o y -20 +o x -30 +o w -20 +o v -30 +p y -20 +. ' -70 +. rq -70 +lq A -50 +` ` -80 +` oq -80 +oq ` -80 +oq oq -80 +` A -50 +oq A -50 +' v -10 +' t 10 +' s -15 +' r -20 +' ' -80 +' d -50 +r y 40 +r v 40 +r u 20 +r t 20 +r s 20 +r q -8 +r . -73 +r p 20 +r o -15 +r n 21 +r m 15 +r l 20 +r k 5 +r i 20 +r - -60 +r hy -60 +r char173 -60 +r g 1 +r e -4 +r d -6 +r , -75 +r c -7 +s . 20 +s , 20 +v . -90 +v o -20 +v e -20 +v , -90 +v a -30 +w . -90 +w o -30 +w e -20 +w , -90 +w a -30 +x e -20 +y . -100 +y o -30 +y e -20 +y , -100 +y c -35 +y a -30 +charset +ha 600,740 2 0000 asciicircum +ti 600,347 0 0001 asciitilde +vS 520,944,15 2 0002 Scaron +vZ 500,944 2 0003 Zcaron +vs 440,774,18 2 0004 scaron +vz 460,774 2 0005 zcaron +:Y 620,939 2 0006 Ydieresis +tm 1000,740 2 0007 trademark +aq 220,740 2 0010 quotesingle +space 280 0 0040 +! 280,740 2 0041 exclam +" 360,740 2 0042 quotedbl +# 560,700 0 0043 numbersign +sh " +$ 560,857,86 2 0044 dollar +Do " +% 860,755,15 2 0045 percent +& 680,755,15 2 0046 ampersand +' 280,740 2 0047 quoteright +( 380,754,157 2 0050 parenleft +) 380,754,157 2 0051 parenright +* 440,755 2 0052 asterisk ++ 600,506 0 0053 plus +, 280,133,141 0 0054 comma +- 420,348 0 0055 hyphen +hy " +char173 " +. 280,133 0 0056 period +/ 460,740,100 2 0057 slash +sl " +0 560,755,15 2 0060 zero +1 560,740 2 0061 one +2 560,755 2 0062 two +3 560,755,15 2 0063 three +4 560,740 2 0064 four +5 560,740,15 2 0065 five +6 560,739,15 2 0066 six +7 560,740 2 0067 seven +8 560,755,15 2 0070 eight +9 560,754 2 0071 nine +: 280,555 0 0072 colon +; 280,555,141 0 0073 semicolon +< 600,514,8 0 0074 less += 600,425 0 0075 equal +> 600,514,8 0 0076 greater +? 560,755 2 0077 question +@ 740,712,12 0 0100 at +at " +A 740,740 2 0101 A +B 580,740 2 0102 B +C 780,755,15 2 0103 C +D 700,740 2 0104 D +E 520,740 2 0105 E +F 480,740 2 0106 F +G 840,755,15 2 0107 G +H 680,740 2 0110 H +I 280,740 2 0111 I +J 480,740,15 2 0112 J +K 620,740 2 0113 K +L 440,740 2 0114 L +M 900,740 2 0115 M +N 740,740 2 0116 N +O 840,755,15 2 0117 O +P 560,740 2 0120 P +Q 840,755,15 2 0121 Q +R 580,740 2 0122 R +S 520,755,15 2 0123 S +T 420,740 2 0124 T +U 640,740,15 2 0125 U +V 700,740 2 0126 V +W 900,740 2 0127 W +X 680,740 2 0130 X +Y 620,740 2 0131 Y +Z 500,740 2 0132 Z +[ 320,754,157 2 0133 bracketleft +lB " +\ 640,740,100 2 0134 backslash +rs " +] 320,754,157 2 0135 bracketright +rB " +a^ 540,774 2 0136 circumflex +^ " +_ 500,0,125 0 0137 underscore +` 280,740 2 0140 quoteleft +oq " +a 660,574,18 0 0141 a +b 660,740,18 2 0142 b +c 640,574,18 0 0143 c +d 660,740,18 2 0144 d +e 640,577,18 0 0145 e +f 280,755 2 0146 f +g 660,574,226 1 0147 g +h 600,740 2 0150 h +i 240,740 2 0151 i +j 260,740,185 3 0152 j +k 580,740 2 0153 k +l 240,740 2 0154 l +m 940,574 0 0155 m +n 600,574 0 0156 n +o 640,574,18 0 0157 o +p 660,574,185 1 0160 p +q 660,574,185 1 0161 q +r 320,574 0 0162 r +s 440,574,18 0 0163 s +t 300,740 2 0164 t +u 600,555,18 0 0165 u +v 560,555 0 0166 v +w 800,555 0 0167 w +x 560,555 0 0170 x +y 580,555,185 1 0171 y +z 460,555 0 0172 z +lC 340,747,191 3 0173 braceleft +{ " +ba 600,740,100 2 0174 bar +| " +rC 340,747,191 3 0175 braceright +} " +a~ 480,767 2 0176 tilde +~ " +bq 280,133,141 0 0200 quotesinglbase +Fo 460,469 0 0201 guillemotleft +char171 " +Fc 460,469 0 0202 guillemotright +char187 " +bu 600,532 0 0203 bullet +Fn 560,824,151 2 0204 florin +f/ 160,740 2 0205 fraction +%0 1280,755,15 2 0206 perthousand +dg 560,740,142 2 0207 dagger +dd 560,740,142 2 0210 daggerdbl +en 500,348 0 0211 endash +em 1000,348 0 0212 emdash +fi 520,755 2 0214 fi +fl 520,755 2 0215 fl +.i 240,555 0 0220 dotlessi +ga 420,851 2 0222 grave +a" 700,862 2 0223 hungarumlaut +a. 280,769 2 0224 dotaccent +ab 480,770 2 0225 breve +ah 540,774 2 0226 caron +ao 360,834 2 0227 ring +ho 340,9,195 1 0230 ogonek +lq 480,740 2 0231 quotedblleft +rq 480,740 2 0232 quotedblright +oe 1080,574,18 0 0233 oe +/l 320,740 2 0234 lslash +Bq 480,133,141 0 0235 quotedblbase +OE 1060,755,15 2 0236 OE +/L 480,740 2 0237 Lslash +r! 280,555,185 1 0241 exclamdown +char161 " +ct 560,715 0 0242 cent +char162 " +Po 560,755 2 0243 sterling +char163 " +Cs 560,577 0 0244 currency +char164 " +Ye 560,740 2 0245 yen +char165 " +bb 600,740,100 2 0246 brokenbar +char166 " +sc 560,755,158 2 0247 section +char167 " +ad 500,769 2 0250 dieresis +char168 " +co 740,752,12 2 0251 copyright +char169 " +Of 360,755 2 0252 ordfeminine +char170 " +fo 240,469 0 0253 guilsinglleft +no 600,425 0 0254 logicalnot +char172 " +\- 600,313 0 0255 minus +rg 740,752,12 2 0256 registered +char174 " +a- 420,759 2 0257 macron +char175 " +de 400,712 0 0260 degree +char176 " +char177 600,556,62 0 0261 plusminus +S2 336,749 2 0262 twosuperior +char178 " +S3 336,749 2 0263 threesuperior +char179 " +aa 420,849 2 0264 acute +char180 " +char181 576,555,187 1 0265 mu +ps 600,740,103 2 0266 paragraph +char182 " +char183 280,320 0 0267 periodcentered +ac 340,6,251 1 0270 cedilla +char184 " +S1 336,740 2 0271 onesuperior +char185 " +Om 360,755 2 0272 ordmasculine +char186 " +fc 240,469 0 0273 guilsinglright +14 840,740 2 0274 onequarter +char188 " +12 840,740 2 0275 onehalf +char189 " +34 840,749 2 0276 threequarters +char190 " +r? 560,555,200 1 0277 questiondown +char191 " +`A 740,1021 2 0300 Agrave +char192 " +'A 740,1019 2 0301 Aacute +char193 " +^A 740,944 2 0302 Acircumflex +char194 " +~A 740,937 2 0303 Atilde +char195 " +:A 740,939 2 0304 Adieresis +char196 " +oA 740,969 2 0305 Aring +char197 " +AE 900,740 2 0306 AE +char198 " +,C 780,755,251 3 0307 Ccedilla +char199 " +`E 520,1021 2 0310 Egrave +char200 " +'E 520,1019 2 0311 Eacute +char201 " +^E 520,944 2 0312 Ecircumflex +char202 " +:E 520,939 2 0313 Edieresis +char203 " +`I 280,1021 2 0314 Igrave +char204 " +'I 280,1019 2 0315 Iacute +char205 " +^I 280,944 2 0316 Icircumflex +char206 " +:I 280,939 2 0317 Idieresis +char207 " +-D 742,740 2 0320 Eth +char208 " +~N 740,937 2 0321 Ntilde +char209 " +`O 840,1021,15 2 0322 Ograve +char210 " +'O 840,1019,15 2 0323 Oacute +char211 " +^O 840,944,15 2 0324 Ocircumflex +char212 " +~O 840,937,15 2 0325 Otilde +char213 " +:O 840,939,15 2 0326 Odieresis +char214 " +char215 600,494 0 0327 multiply +/O 840,814,71 2 0330 Oslash +char216 " +`U 640,1021,15 2 0331 Ugrave +char217 " +'U 640,1019,15 2 0332 Uacute +char218 " +^U 640,944,15 2 0333 Ucircumflex +char219 " +:U 640,939,15 2 0334 Udieresis +char220 " +'Y 620,1019 2 0335 Yacute +char221 " +TP 560,740 2 0336 Thorn +char222 " +ss 600,755,18 2 0337 germandbls +char223 " +`a 660,851,18 2 0340 agrave +char224 " +'a 660,849,18 2 0341 aacute +char225 " +^a 660,774,18 2 0342 acircumflex +char226 " +~a 660,767,18 2 0343 atilde +char227 " +:a 660,769,18 2 0344 adieresis +char228 " +oa 660,834,18 2 0345 aring +char229 " +ae 1080,574,18 0 0346 ae +char230 " +,c 640,574,251 1 0347 ccedilla +char231 " +`e 640,851,18 2 0350 egrave +char232 " +'e 640,849,18 2 0351 eacute +char233 " +^e 640,774,18 2 0352 ecircumflex +char234 " +:e 640,769,18 2 0353 edieresis +char235 " +`i 240,851 2 0354 igrave +char236 " +'i 240,849 2 0355 iacute +char237 " +^i 240,774 2 0356 icircumflex +char238 " +:i 240,769 2 0357 idieresis +char239 " +Sd 640,754,18 2 0360 eth +char240 " +~n 600,767 2 0361 ntilde +char241 " +`o 640,851,18 2 0362 ograve +char242 " +'o 640,849,18 2 0363 oacute +char243 " +^o 640,774,18 2 0364 ocircumflex +char244 " +~o 640,767,18 2 0365 otilde +char245 " +:o 640,769,18 2 0366 odieresis +char246 " +char247 600,526,20 0 0367 divide +/o 660,608,50 0 0370 oslash +char248 " +`u 600,851,18 2 0371 ugrave +char249 " +'u 600,849,18 2 0372 uacute +char250 " +^u 600,774,18 2 0373 ucircumflex +char251 " +:u 600,769,18 2 0374 udieresis +char252 " +'y 580,849,185 3 0375 yacute +char253 " +Tp 660,740,185 3 0376 thorn +char254 " +:y 580,769,185 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/ABI b/gnu/usr.bin/groff/devices/devps/ABI new file mode 100644 index 0000000000..000d958858 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/ABI @@ -0,0 +1,560 @@ +name ABI +internalname AvantGarde-DemiOblique +slant 10.5 +spacewidth 280 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -50 +A w -65 +A v -70 +A u -20 +A ' -90 +A Y -80 +A W -60 +A V -102 +A U -40 +A T -25 +A Q -50 +A O -50 +A G -40 +A C -40 +B A -10 +C A -40 +D . -20 +D , -20 +D Y -45 +D W -25 +D V -50 +D A -50 +F . -129 +F e -20 +F , -162 +F a -20 +F A -75 +G . -20 +G , -20 +G Y -15 +J . -15 +J a -20 +J A -30 +K y -20 +K u -15 +K o -45 +K e -40 +K O -30 +L y -23 +L ' -30 +L rq -30 +L Y -80 +L W -55 +L V -85 +L T -46 +O . -30 +O , -30 +O Y -30 +O X -30 +O W -20 +O V -45 +O T -15 +O A -60 +P . -200 +P o -20 +P e -20 +P , -220 +P a -20 +P A -100 +Q , 20 +R W 25 +R V -10 +R U 25 +R T 40 +R O 25 +S , 20 +T y -10 +T w -55 +T u -46 +T ; -29 +T r -30 +T . -91 +T o -49 +T - -75 +T hy -75 +T char173 -75 +T e -49 +T , -82 +T : -15 +T a -70 +T O -15 +T A -25 +U . -20 +U , -20 +U A -40 +V u -55 +V ; -33 +V . -145 +V o -101 +V i -15 +V - -75 +V hy -75 +V char173 -75 +V e -101 +V , -145 +V : -18 +V a -95 +V O -45 +V G -20 +V A -102 +W y -15 +W u -30 +W ; -33 +W . -106 +W o -46 +W i -10 +W - -35 +W hy -35 +W char173 -35 +W e -47 +W , -106 +W : -15 +W a -50 +W O -20 +W A -58 +Y u -52 +Y ; -23 +Y . -145 +Y o -89 +Y - -100 +Y hy -100 +Y char173 -100 +Y e -89 +Y , -145 +Y : -10 +Y a -93 +Y O -30 +Y A -80 +a t 5 +a p 20 +a b 5 +b y -20 +b v -20 +c y -20 +c l -15 +c k -15 +, ' -70 +, rq -70 +e y -20 +e x -20 +e w -20 +e v -20 +f . -40 +f o -20 +f l -15 +f i -15 +f f -20 +f .i -15 +f , -40 +f a -15 +g i 25 +g a 15 +h y -30 +k y -5 +k o -30 +k e -40 +m y -20 +m u -20 +n y -15 +n v -30 +o y -20 +o x -30 +o w -20 +o v -30 +p y -20 +. ' -70 +. rq -70 +lq A -50 +` ` -80 +` oq -80 +oq ` -80 +oq oq -80 +` A -50 +oq A -50 +' v -10 +' t 10 +' s -15 +' r -20 +' ' -80 +' d -50 +r y 40 +r v 40 +r u 20 +r t 20 +r s 20 +r q -8 +r . -73 +r p 20 +r o -15 +r n 21 +r m 15 +r l 20 +r k 5 +r i 20 +r - -60 +r hy -60 +r char173 -60 +r g 1 +r e -4 +r d -6 +r , -75 +r c -7 +s . 20 +s , 20 +v . -90 +v o -20 +v e -20 +v , -90 +v a -30 +w . -90 +w o -30 +w e -20 +w , -90 +w a -30 +x e -20 +y . -100 +y o -30 +y e -20 +y , -100 +y c -35 +y a -30 +charset +ha 600,740,0,46,-92,46 2 0000 asciicircum +ti 600,347,0,29,-64,29 0 0001 asciitilde +vS 520,944,15,165,1,82 2 0002 Scaron +vZ 500,944,0,200,31,82 2 0003 Zcaron +vs 440,774,18,173,1,82 2 0004 scaron +vz 460,774,0,188,30,82 2 0005 zcaron +:Y 620,939,0,189,-85,82 2 0006 Ydieresis +tm 1000,740,0,8,-81,8 2 0007 trademark +aq 220,740,0,144,-102,82 2 0010 quotesingle +space 280 0 0040 +! 280,740,0,113,-23,82 2 0041 exclam +" 360,740,0,168,-77,82 2 0042 quotedbl +# 560,700,0,108,-16,82 0 0043 numbersign +sh " +$ 560,857,86,72,-49,72 2 0044 dollar +Do " +% 860,755,15,46,-89,46 2 0045 percent +& 680,755,15,112,-21,82 2 0046 ampersand +' 280,740,0,112,-109,82 2 0047 quoteright +( 380,754,157,160,-70,82 2 0050 parenleft +) 380,754,157,48,42,48 2 0051 parenright +* 440,755,0,102,-124,82 2 0052 asterisk ++ 600,506,0,60,-34,60 0 0053 plus +, 280,133,141,1,2,1 0 0054 comma +- 420,348,0,43,-64,43 0 0055 hyphen +hy " +char173 " +. 280,133,0,1,-23,1 0 0056 period +/ 460,740,100,181,63,82 2 0057 slash +sl " +0 560,755,15,118,-20,82 2 0060 zero +1 560,740,0,0,-180 2 0061 one +2 560,755,0,112,6,82 2 0062 two +3 560,755,15,75,-17,75 2 0063 three +4 560,740,0,94,14,82 2 0064 four +5 560,740,15,90,-14,82 2 0065 five +6 560,739,15,77,-14,77 2 0066 six +7 560,740,0,125,-33,82 2 0067 seven +8 560,755,15,80,-21,80 2 0070 eight +9 560,754,0,123,-60,82 2 0071 nine +: 280,555,0,79,-23,79 0 0072 colon +; 280,555,141,79,2,79 0 0073 semicolon +< 600,514,8,99,-34,82 0 0074 less += 600,425,0,81,-13,81 0 0075 equal +> 600,514,8,60,5,60 0 0076 greater +? 560,755,0,83,-85,82 2 0077 question +@ 740,712,12,142,-59,82 0 0100 at +at " +A 740,740,0,42,43,42 2 0101 A +B 580,740,0,80,-20,80 2 0102 B +C 780,755,15,134,-47,82 2 0103 C +D 700,740,0,82,-13,82 2 0104 D +E 520,740,0,126,-11,82 2 0105 E +F 480,740,0,145,-11,82 2 0106 F +G 840,755,15,97,-39,82 2 0107 G +H 680,740,0,117,-21,82 2 0110 H +I 280,740,0,116,-22,82 2 0111 I +J 480,740,15,116,16,82 2 0112 J +K 620,740,0,187,-39,82 2 0113 K +L 440,740,0,69,-22,69 2 0114 L +M 900,740,0,124,-13,82 2 0115 M +N 740,740,0,118,-20,82 2 0116 N +O 840,755,15,92,-45,82 2 0117 O +P 560,740,0,135,-22,82 2 0120 P +Q 840,755,15,92,-44,82 2 0121 Q +R 580,740,0,126,-14,82 2 0122 R +S 520,755,15,108,1,82 2 0123 S +T 420,740,0,185,-69,82 2 0124 T +U 640,740,15,132,-47,82 2 0125 U +V 700,740,0,182,-95,82 2 0126 V +W 900,740,0,186,-94,82 2 0127 W +X 680,740,0,183,46,82 2 0130 X +Y 620,740,0,189,-85,82 2 0131 Y +Z 500,740,0,149,31,82 2 0132 Z +[ 320,754,157,154,-39,82 2 0133 bracketleft +lB " +\ 640,740,100,0,-183 2 0134 backslash +rs " +] 320,754,157,72,43,72 2 0135 bracketright +rB " +a^ 540,774,0,98,-139,82 2 0136 circumflex +^ " +_ 500,0,125,36,73,36 0 0137 underscore +` 280,740,0,111,-108,82 2 0140 quoteleft +oq " +a 660,574,18,106,-23,82 0 0141 a +b 660,740,18,79,3,79 2 0142 b +c 640,574,18,89,-34,82 0 0143 c +d 660,740,18,145,-30,82 2 0144 d +e 640,577,18,77,-27,77 0 0145 e +f 280,755,0,190,-12,82 2 0146 f +g 660,574,226,116,17,82 1 0147 g +h 600,740,0,64,-4,64 2 0150 h +i 240,740,0,133,-3,82 2 0151 i +j 260,740,185,132,68,82 3 0152 j +k 580,740,0,118,-30,82 2 0153 k +l 240,740,0,134,-4,82 2 0154 l +m 940,574,0,64,-4,64 0 0155 m +n 600,574,0,63,-4,63 0 0156 n +o 640,574,18,82,-21,82 0 0157 o +p 660,574,185,76,37,76 1 0160 p +q 660,574,185,106,-28,82 1 0161 q +r 320,574,0,153,-13,82 0 0162 r +s 440,574,18,93,1,82 0 0163 s +t 300,740,0,152,-36,82 2 0164 t +u 600,555,18,97,-37,82 0 0165 u +v 560,555,0,149,-56,82 0 0166 v +w 800,555,0,142,-64,82 0 0167 w +x 560,555,0,122,47,82 0 0170 x +y 580,555,185,144,-25,82 1 0171 y +z 460,555,0,118,30,82 0 0172 z +lC 340,747,191,165,10,82 3 0173 braceleft +{ " +ba 600,740,100,0,-164 2 0174 bar +| " +rC 340,747,191,115,62,82 3 0175 braceright +} " +a~ 480,767,0,134,-128,82 2 0176 tilde +~ " +bq 280,133,141,0,3 0 0200 quotesinglbase +Fo 460,469,0,77,-55,77 0 0201 guillemotleft +char171 " +Fc 460,469,0,53,-31,53 0 0202 guillemotright +char187 " +bu 600,532,0,0,-165 0 0203 bullet +Fn 560,824,151,154,77,82 2 0204 florin +f/ 160,740,0,309,173,82 2 0205 fraction +%0 1280,755,15,26,-89,26 2 0206 perthousand +dg 560,740,142,102,-83,82 2 0207 dagger +dd 560,740,142,108,-13,82 2 0210 daggerdbl +en 500,348,0,79,-28,79 0 0211 endash +em 1000,348,0,79,-28,79 0 0212 emdash +fi 520,755,0,128,-22,82 2 0214 fi +fl 520,755,0,128,-22,82 2 0215 fl +.i 240,555,0,99,-3,82 0 0220 dotlessi +ga 420,851,0,92,-139,82 2 0222 grave +a" 700,862,0,104,-208,82 2 0223 hungarumlaut +a. 280,769,0,120,-142,82 2 0224 dotaccent +ab 480,770,0,152,-135,82 2 0225 breve +ah 540,774,0,123,-164,82 2 0226 caron +ao 360,834,0,114,-156,82 2 0227 ring +ho 340,9,195,0,-9 1 0230 ogonek +lq 480,740,0,116,-106,82 2 0231 quotedblleft +rq 480,740,0,117,-107,82 2 0232 quotedblright +oe 1080,574,18,78,-26,78 0 0233 oe +/l 320,740,0,134,-24,82 2 0234 lslash +Bq 480,133,141,5,5,5 0 0235 quotedblbase +OE 1060,755,15,134,-48,82 2 0236 OE +/L 480,740,0,54,-18,54 2 0237 Lslash +r! 280,555,185,80,10,80 1 0241 exclamdown +char161 " +ct 560,715,0,89,-60,82 0 0242 cent +char162 " +Po 560,755,0,105,12,82 2 0243 sterling +char163 " +Cs 560,577,0,118,-3,82 0 0244 currency +char164 " +Ye 560,740,0,197,-33,82 2 0245 yen +char165 " +bb 600,740,100,0,-164 2 0246 brokenbar +char166 " +sc 560,755,158,92,-15,82 2 0247 section +char167 " +ad 500,769,0,115,-146,82 2 0250 dieresis +char168 " +co 740,752,12,137,0,82 2 0251 copyright +char169 " +Of 360,755,0,162,-77,82 2 0252 ordfeminine +char170 " +fo 240,469,0,87,-44,82 0 0253 guilsinglleft +no 600,425,0,81,-55,81 0 0254 logicalnot +char172 " +\- 600,313,0,60,-34,60 0 0255 minus +rg 740,752,12,137,0,82 2 0256 registered +char174 " +a- 420,759,0,120,-142,82 2 0257 macron +char175 " +de 400,712,0,101,-110,82 0 0260 degree +char176 " +char177 600,556,62,76,13,76 0 0261 plusminus +S2 336,749,0,150,-23,82 2 0262 twosuperior +char178 " +S3 336,749,0,127,-37,82 2 0263 threesuperior +char179 " +aa 420,849,0,138,-174,82 2 0264 acute +char180 " +char181 576,555,187,116,47,82 1 0265 mu +ps 600,740,103,194,-40,82 2 0266 paragraph +char182 " +char183 280,320,0,35,-58,35 0 0267 periodcentered +ac 340,6,251,0,-17 1 0270 cedilla +char184 " +S1 336,740,0,74,-132,74 2 0271 onesuperior +char185 " +Om 360,755,0,141,-81,82 2 0272 ordmasculine +char186 " +fc 240,469,0,63,-20,63 0 0273 guilsinglright +14 840,740,0,0,-137 2 0274 onequarter +char188 " +12 840,740,0,40,-107,40 2 0275 onehalf +char189 " +34 840,749,0,46,-47,46 2 0276 threequarters +char190 " +r? 560,555,200,17,-19,17 1 0277 questiondown +char191 " +`A 740,1021,0,42,43,42 2 0300 Agrave +char192 " +'A 740,1019,0,42,43,42 2 0301 Aacute +char193 " +^A 740,944,0,42,43,42 2 0302 Acircumflex +char194 " +~A 740,937,0,42,43,42 2 0303 Atilde +char195 " +:A 740,939,0,42,43,42 2 0304 Adieresis +char196 " +oA 740,969,0,42,43,42 2 0305 Aring +char197 " +AE 900,740,0,111,55,82 2 0306 AE +char198 " +,C 780,755,251,134,-47,82 3 0307 Ccedilla +char199 " +`E 520,1021,0,126,-11,82 2 0310 Egrave +char200 " +'E 520,1019,0,126,-11,82 2 0311 Eacute +char201 " +^E 520,944,0,139,-11,82 2 0312 Ecircumflex +char202 " +:E 520,939,0,136,-11,82 2 0313 Edieresis +char203 " +`I 280,1021,0,168,-22,82 2 0314 Igrave +char204 " +'I 280,1019,0,264,-22,82 2 0315 Iacute +char205 " +^I 280,944,0,259,-22,82 2 0316 Icircumflex +char206 " +:I 280,939,0,256,-22,82 2 0317 Idieresis +char207 " +-D 742,740,0,74,-33,74 2 0320 Eth +char208 " +~N 740,937,0,118,-20,82 2 0321 Ntilde +char209 " +`O 840,1021,15,92,-45,82 2 0322 Ograve +char210 " +'O 840,1019,15,92,-45,82 2 0323 Oacute +char211 " +^O 840,944,15,92,-45,82 2 0324 Ocircumflex +char212 " +~O 840,937,15,92,-45,82 2 0325 Otilde +char213 " +:O 840,939,15,92,-45,82 2 0326 Odieresis +char214 " +char215 600,494,0,67,-26,67 0 0327 multiply +/O 840,814,71,101,-44,82 2 0330 Oslash +char216 " +`U 640,1021,15,132,-47,82 2 0331 Ugrave +char217 " +'U 640,1019,15,132,-47,82 2 0332 Uacute +char218 " +^U 640,944,15,132,-47,82 2 0333 Ucircumflex +char219 " +:U 640,939,15,132,-47,82 2 0334 Udieresis +char220 " +'Y 620,1019,0,189,-85,82 2 0335 Yacute +char221 " +TP 560,740,0,109,-22,82 2 0336 Thorn +char222 " +ss 600,755,18,79,-1,79 2 0337 germandbls +char223 " +`a 660,851,18,106,-23,82 2 0340 agrave +char224 " +'a 660,849,18,106,-23,82 2 0341 aacute +char225 " +^a 660,774,18,106,-23,82 2 0342 acircumflex +char226 " +~a 660,767,18,106,-23,82 2 0343 atilde +char227 " +:a 660,769,18,106,-23,82 2 0344 adieresis +char228 " +oa 660,834,18,106,-23,82 2 0345 aring +char229 " +ae 1080,574,18,75,-25,75 0 0346 ae +char230 " +,c 640,574,251,89,-33,82 1 0347 ccedilla +char231 " +`e 640,851,18,77,-27,77 2 0350 egrave +char232 " +'e 640,849,18,77,-27,77 2 0351 eacute +char233 " +^e 640,774,18,77,-27,77 2 0352 ecircumflex +char234 " +:e 640,769,18,77,-27,77 2 0353 edieresis +char235 " +`i 240,851,0,157,-3,82 2 0354 igrave +char236 " +'i 240,849,0,253,-3,82 2 0355 iacute +char237 " +^i 240,774,0,248,11,82 2 0356 icircumflex +char238 " +:i 240,769,0,245,-3,82 2 0357 idieresis +char239 " +Sd 640,754,18,109,-23,82 2 0360 eth +char240 " +~n 600,767,0,74,-4,74 2 0361 ntilde +char241 " +`o 640,851,18,82,-21,82 2 0362 ograve +char242 " +'o 640,849,18,82,-21,82 2 0363 oacute +char243 " +^o 640,774,18,82,-21,82 2 0364 ocircumflex +char244 " +~o 640,767,18,82,-21,82 2 0365 otilde +char245 " +:o 640,769,18,82,-21,82 2 0366 odieresis +char246 " +char247 600,526,20,60,-34,60 0 0367 divide +/o 660,608,50,75,-31,75 0 0370 oslash +char248 " +`u 600,851,18,97,-37,82 2 0371 ugrave +char249 " +'u 600,849,18,97,-37,82 2 0372 uacute +char250 " +^u 600,774,18,97,-37,82 2 0373 ucircumflex +char251 " +:u 600,769,18,97,-37,82 2 0374 udieresis +char252 " +'y 580,849,185,144,-25,82 3 0375 yacute +char253 " +Tp 660,740,185,76,37,76 3 0376 thorn +char254 " +:y 580,769,185,144,-25,82 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/AI b/gnu/usr.bin/groff/devices/devps/AI new file mode 100644 index 0000000000..686823706a --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/AI @@ -0,0 +1,559 @@ +name AI +internalname AvantGarde-BookOblique +slant 10.5 +spacewidth 277 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -62 +A w -65 +A v -70 +A u -20 +A ' -100 +A rq -100 +A Y -92 +A W -60 +A V -102 +A U -40 +A T -45 +A Q -40 +A O -50 +A G -40 +A C -40 +B A -10 +C A -40 +D . -20 +D , -20 +D Y -30 +D W -10 +D V -50 +D A -50 +F . -160 +F e -20 +F , -180 +F a -20 +F A -75 +G . -20 +G , -20 +G Y -20 +J . -15 +J a -20 +J A -30 +K o -15 +K e -20 +K O -20 +L y -23 +L ' -130 +L rq -130 +L Y -91 +L W -67 +L V -113 +L T -46 +O . -30 +O , -30 +O Y -30 +O X -30 +O W -20 +O V -60 +O T -30 +O A -60 +P . -300 +P o -60 +P e -20 +P , -280 +P a -20 +P A -114 +Q , 20 +R Y -10 +R W 10 +R V -10 +R T 6 +S , 20 +T y -50 +T w -55 +T u -46 +T ; -29 +T r -30 +T . -91 +T o -70 +T i 10 +T - -75 +T hy -75 +T char173 -75 +T e -49 +T , -82 +T : -15 +T a -90 +T O -30 +T A -45 +U . -20 +U , -20 +U A -40 +V u -40 +V ; -33 +V . -165 +V o -101 +V i -5 +V - -75 +V hy -75 +V char173 -75 +V e -101 +V , -145 +V : -18 +V a -104 +V O -60 +V G -20 +V A -102 +W y -2 +W u -30 +W ; -33 +W . -106 +W o -46 +W i 6 +W - -35 +W hy -35 +W char173 -35 +W e -47 +W , -106 +W : -15 +W a -50 +W O -20 +W A -58 +Y u -52 +Y ; -23 +Y . -175 +Y o -89 +Y - -85 +Y hy -85 +Y char173 -85 +Y e -89 +Y , -145 +Y : -10 +Y a -93 +Y O -30 +Y A -92 +a p 20 +a b 20 +b y -20 +b v -20 +c y -20 +c k -15 +, ' -120 +, rq -120 +e y -20 +e w -20 +e v -20 +f . -50 +f o -40 +f l -30 +f i -34 +f f -60 +f e -20 +f .i -34 +f , -50 +f a -40 +g a -15 +h y -30 +k y -5 +k e -15 +m y -20 +m u -20 +m a -20 +n y -15 +n v -20 +o y -20 +o x -15 +o w -20 +o v -30 +p y -20 +. ' -120 +. rq -120 +lq ` -35 +lq oq -35 +lq A -100 +` ` -203 +` oq -203 +oq ` -203 +oq oq -203 +` A -100 +oq A -100 +' v -30 +' t 10 +' s -15 +' r -20 +' ' -203 +' rq -35 +' d -110 +r y 40 +r v 40 +r u 20 +r t 20 +r s 20 +r q -8 +r . -73 +r p 20 +r o -20 +r n 21 +r m 28 +r l 20 +r k 20 +r i 20 +r - -60 +r hy -60 +r char173 -60 +r g -15 +r e -4 +r d -6 +r , -75 +r c -20 +r a -20 +s . 20 +s , 20 +v . -130 +v o -30 +v e -20 +v , -100 +v a -30 +w . -100 +w o -30 +w h 15 +w e -20 +w , -90 +w a -30 +y . -125 +y o -30 +y e -20 +y , -110 +y a -30 +charset +ha 606,740,0,54,-60,54 2 0000 asciicircum +ti 606,319,0,28,-64,28 0 0001 asciitilde +vS 498,927,13,145,-7,81 2 0002 Scaron +vZ 480,927,0,166,38,81 2 0003 Zcaron +vs 388,764,13,170,1,81 2 0004 scaron +vz 425,764,0,152,40,81 2 0005 zcaron +:Y 592,928,0,187,-88,81 2 0006 Ydieresis +tm 1000,740,0,3,-87,3 2 0007 trademark +aq 198,740,0,129,-103,81 2 0010 quotesingle +space 277 0 0040 +! 295,740,0,77,-61,77 2 0041 exclam +" 309,740,0,151,-80,81 2 0042 quotedbl +# 554,740,0,116,-21,81 2 0043 numbersign +sh " +$ 554,811,70,77,-57,77 2 0044 dollar +Do " +% 775,751,13,62,-74,62 2 0045 percent +& 757,753,12,68,-42,68 2 0046 ampersand +' 351,740,0,92,-145,81 2 0047 quoteright +( 369,757,205,176,-39,81 3 0050 parenleft +) 369,757,205,63,74,63 3 0051 parenright +* 425,740,0,104,-120,81 2 0052 asterisk ++ 606,506,0,52,-42,52 0 0053 plus +, 277,126,67,0,48 0 0054 comma +- 332,315,0,78,-26,78 0 0055 hyphen +hy " +char173 " +. 277,126,0,0,-52 0 0056 period +/ 437,740,100,153,25,81 2 0057 slash +sl " +0 554,753,13,118,-21,81 2 0060 zero +1 554,740,0,0,-210 2 0061 one +2 554,753,0,111,10,81 2 0062 two +3 554,753,13,61,-23,61 2 0063 three +4 554,740,0,94,11,81 2 0064 four +5 554,740,13,101,-19,81 2 0065 five +6 554,739,13,76,-15,76 2 0066 six +7 554,740,0,124,-60,81 2 0067 seven +8 554,753,13,76,-27,76 2 0070 eight +9 554,752,0,122,-61,81 2 0071 nine +: 277,548,0,51,-52,51 0 0072 colon +; 277,548,67,51,48,51 0 0073 semicolon +< 606,514,8,93,-37,81 0 0074 less += 606,388,0,71,-23,71 0 0075 equal +> 606,514,8,57,-1,57 0 0076 greater +? 591,752,0,87,-108,81 2 0077 question +@ 867,753,13,71,-76,71 2 0100 at +at " +A 740,740,0,39,38,39 2 0101 A +B 574,740,0,82,-24,81 2 0102 B +C 813,752,13,107,-55,81 2 0103 C +D 744,740,0,79,-24,79 2 0104 D +E 536,740,0,126,-20,81 2 0105 E +F 485,740,0,146,-20,81 2 0106 F +G 872,753,13,69,-53,69 2 0107 G +H 683,740,0,111,-26,81 2 0110 H +I 226,740,0,111,-26,81 2 0111 I +J 482,740,13,107,13,81 2 0112 J +K 591,740,0,187,-31,81 2 0113 K +L 462,740,0,62,-32,62 2 0114 L +M 919,740,0,111,-26,81 2 0115 M +N 740,740,0,111,-25,81 2 0116 N +O 869,753,13,82,-55,81 2 0117 O +P 592,740,0,122,-25,81 2 0120 P +Q 871,753,13,91,-52,81 2 0121 Q +R 607,740,0,112,-20,81 2 0122 R +S 498,753,13,113,-7,81 2 0123 S +T 426,740,0,180,-81,81 2 0124 T +U 655,740,13,111,-68,81 2 0125 U +V 702,740,0,178,-95,81 2 0126 V +W 960,740,0,177,-98,81 2 0127 W +X 609,740,0,165,42,81 2 0130 X +Y 592,740,0,187,-88,81 2 0131 Y +Z 480,740,0,166,38,81 2 0132 Z +[ 351,753,179,176,-95,81 2 0133 bracketleft +lB " +\ 605,740,100,0,-205 2 0134 backslash +rs " +] 351,753,179,11,69,11 2 0135 bracketright +rB " +a^ 502,764,0,94,-142,81 2 0136 circumflex +^ " +_ 500,0,125,36,73,36 0 0137 underscore +` 351,740,0,57,-182,57 2 0140 quoteleft +oq " +a 683,561,13,89,-38,81 0 0141 a +b 682,740,13,71,-18,71 2 0142 b +c 647,561,13,81,-37,81 0 0143 c +d 685,740,13,120,-35,81 2 0144 d +e 650,561,13,64,-34,64 0 0145 e +f 314,753,0,190,-54,81 2 0146 f +g 673,561,215,84,-6,81 1 0147 g +h 610,740,0,46,-12,46 2 0150 h +i 200,740,0,122,-15,81 2 0151 i +j 203,740,192,121,130,81 3 0152 j +k 502,740,0,136,-20,81 2 0153 k +l 200,740,0,122,-15,81 2 0154 l +m 938,561,0,50,-16,50 0 0155 m +n 610,561,0,49,-15,49 0 0156 n +o 655,561,13,64,-38,64 0 0157 o +p 682,561,192,67,22,67 1 0160 p +q 682,561,192,85,-33,81 1 0161 q +r 301,561,0,144,-15,81 0 0162 r +s 388,561,13,86,1,81 0 0163 s +t 339,740,0,142,-54,81 2 0164 t +u 608,547,13,84,-50,81 0 0165 u +v 554,547,0,143,-58,81 0 0166 v +w 831,547,0,140,-64,81 0 0167 w +x 480,547,0,139,38,81 0 0170 x +y 536,547,192,138,-47,81 1 0171 y +z 425,547,0,123,40,81 0 0172 z +lC 351,740,189,167,-65,81 2 0173 braceleft +{ " +ba 672,740,100,0,-230 2 0174 bar +| " +rC 351,740,189,37,65,37 2 0175 braceright +} " +a~ 439,754,0,131,-129,81 2 0176 tilde +~ " +bq 354,126,68,0,-26 0 0200 quotesinglbase +Fo 425,481,0,94,-42,81 0 0201 guillemotleft +char171 " +Fc 425,481,0,62,-10,62 0 0202 guillemotright +char187 " +bu 606,532,0,0,-167 0 0203 bullet +Fn 554,818,153,165,89,81 2 0204 florin +f/ 166,740,0,301,163,81 2 0205 fraction +%0 1174,751,13,58,-78,58 2 0206 perthousand +dg 553,740,133,90,-96,81 2 0207 dagger +dd 553,740,133,90,-22,81 2 0210 daggerdbl +en 500,315,0,73,-31,73 0 0211 endash +em 1000,315,0,73,-31,73 0 0212 emdash +fi 487,753,0,122,-54,81 2 0214 fi +fl 485,753,0,122,-54,81 2 0215 fl +.i 200,547,0,86,-15,81 0 0220 dotlessi +ga 378,786,0,97,-154,81 2 0222 grave +a" 552,800,0,92,-189,81 2 0223 hungarumlaut +a. 222,765,0,118,-142,81 2 0224 dotaccent +ab 453,754,0,138,-142,81 2 0225 breve +ah 502,764,0,113,-160,81 2 0226 caron +ao 332,807,0,119,-141,81 2 0227 ring +ho 302,0,191,0,-3 1 0230 ogonek +lq 502,740,0,55,-184,55 2 0231 quotedblleft +rq 484,740,0,108,-147,81 2 0232 quotedblright +oe 1137,561,13,73,-30,73 0 0233 oe +/l 300,740,0,104,-45,81 2 0234 lslash +Bq 502,126,68,0,-26 0 0235 quotedblbase +OE 1194,753,13,135,-57,81 2 0236 OE +/L 517,740,0,62,-57,62 2 0237 Lslash +r! 295,548,192,41,-24,41 1 0241 exclamdown +char161 " +ct 554,707,0,92,-65,81 0 0242 cent +char162 " +Po 554,753,0,110,21,81 2 0243 sterling +char163 " +Cs 554,580,0,141,26,81 0 0244 currency +char164 " +Ye 554,740,0,183,-25,81 2 0245 yen +char165 " +bb 672,740,100,0,-230 2 0246 brokenbar +char166 " +sc 615,753,141,32,-68,32 2 0247 section +char167 " +ad 369,765,0,118,-141,81 2 0250 dieresis +char168 " +co 747,752,12,133,-3,81 2 0251 copyright +char169 " +Of 369,753,0,175,-52,81 2 0252 ordfeminine +char170 " +fo 251,481,0,94,-42,81 0 0253 guilsinglleft +no 606,388,0,71,-60,71 0 0254 logicalnot +char172 " +\- 606,287,0,52,-42,52 0 0255 minus +rg 747,752,12,133,-3,81 2 0256 registered +char174 " +a- 485,736,0,112,-147,81 0 0257 macron +char175 " +de 400,709,0,101,-108,81 0 0260 degree +char176 " +char177 606,518,24,62,3,62 0 0261 plusminus +S2 332,747,0,151,-24,81 2 0262 twosuperior +char178 " +S3 332,747,0,126,-48,81 2 0263 threesuperior +char179 " +aa 375,786,0,119,-153,81 2 0264 acute +char180 " +char181 608,547,184,70,4,70 0 0265 mu +ps 564,740,110,174,-69,81 2 0266 paragraph +char182 " +char183 277,316,0,8,-87,8 0 0267 periodcentered +ac 324,0,222,0,-2 1 0270 cedilla +char184 " +S1 332,740,0,53,-140,53 2 0271 onesuperior +char185 " +Om 369,753,0,147,-66,81 2 0272 ordmasculine +char186 " +fc 251,481,0,62,-10,62 0 0273 guilsinglright +14 831,740,0,0,-133 2 0274 onequarter +char188 " +12 831,740,0,29,-114,29 2 0275 onehalf +char189 " +34 831,747,0,44,-76,44 2 0276 threequarters +char190 " +r? 591,548,205,0,-14 1 0277 questiondown +char191 " +`A 740,949,0,39,38,39 2 0300 Agrave +char192 " +'A 740,949,0,39,38,39 2 0301 Aacute +char193 " +^A 740,927,0,39,38,39 2 0302 Acircumflex +char194 " +~A 740,917,0,39,38,39 2 0303 Atilde +char195 " +:A 740,928,0,39,38,39 2 0304 Adieresis +char196 " +oA 740,955,0,39,38,39 2 0305 Aring +char197 " +AE 992,740,0,102,70,81 2 0306 AE +char198 " +,C 813,752,222,107,-55,81 3 0307 Ccedilla +char199 " +`E 536,949,0,126,-20,81 2 0310 Egrave +char200 " +'E 536,949,0,126,-20,81 2 0311 Eacute +char201 " +^E 536,927,0,126,-20,81 2 0312 Ecircumflex +char202 " +:E 536,928,0,126,-20,81 2 0313 Edieresis +char203 " +`I 226,949,0,164,-26,81 2 0314 Igrave +char204 " +'I 226,949,0,264,-26,81 2 0315 Iacute +char205 " +^I 226,927,0,263,-26,81 2 0316 Icircumflex +char206 " +:I 226,928,0,220,-26,81 2 0317 Idieresis +char207 " +-D 790,740,0,73,-54,73 2 0320 Eth +char208 " +~N 740,917,0,111,-25,81 2 0321 Ntilde +char209 " +`O 869,949,13,82,-55,81 2 0322 Ograve +char210 " +'O 869,949,13,82,-55,81 2 0323 Oacute +char211 " +^O 869,927,13,82,-55,81 2 0324 Ocircumflex +char212 " +~O 869,917,13,82,-55,81 2 0325 Otilde +char213 " +:O 869,928,13,82,-55,81 2 0326 Odieresis +char214 " +char215 606,482,0,56,-37,56 0 0327 multiply +/O 868,819,83,111,-26,81 2 0330 Oslash +char216 " +`U 655,949,13,111,-68,81 2 0331 Ugrave +char217 " +'U 655,949,13,111,-68,81 2 0332 Uacute +char218 " +^U 655,927,13,111,-68,81 2 0333 Ucircumflex +char219 " +:U 655,928,13,111,-68,81 2 0334 Udieresis +char220 " +'Y 592,949,0,187,-88,81 2 0335 Yacute +char221 " +TP 592,740,0,79,-10,79 2 0336 Thorn +char222 " +ss 554,753,13,74,-11,74 2 0337 germandbls +char223 " +`a 683,786,13,89,-38,81 2 0340 agrave +char224 " +'a 683,786,13,89,-38,81 2 0341 aacute +char225 " +^a 683,764,13,89,-38,81 2 0342 acircumflex +char226 " +~a 683,754,13,89,-38,81 2 0343 atilde +char227 " +:a 683,765,13,89,-38,81 2 0344 adieresis +char228 " +oa 683,807,13,89,-38,81 2 0345 aring +char229 " +ae 1157,561,13,62,-30,62 0 0346 ae +char230 " +,c 647,561,222,81,-37,81 1 0347 ccedilla +char231 " +`e 650,786,13,64,-34,64 2 0350 egrave +char232 " +'e 650,786,13,64,-34,64 2 0351 eacute +char233 " +^e 650,764,13,64,-34,64 2 0352 ecircumflex +char234 " +:e 650,765,13,64,-34,64 2 0353 edieresis +char235 " +`i 200,786,0,146,-15,81 2 0354 igrave +char236 " +'i 200,786,0,247,-15,81 2 0355 iacute +char237 " +^i 200,764,0,245,9,81 2 0356 icircumflex +char238 " +:i 200,765,0,203,-15,81 2 0357 idieresis +char239 " +Sd 655,753,12,70,-38,70 2 0360 eth +char240 " +~n 610,754,0,49,-15,49 2 0361 ntilde +char241 " +`o 655,786,13,64,-38,64 2 0362 ograve +char242 " +'o 655,786,13,64,-38,64 2 0363 oacute +char243 " +^o 655,764,13,64,-38,64 2 0364 ocircumflex +char244 " +~o 655,754,13,64,-38,64 2 0365 otilde +char245 " +:o 655,765,13,64,-38,64 2 0366 odieresis +char246 " +char247 606,519,13,52,-42,52 0 0367 divide +/o 653,614,64,100,-1,81 0 0370 oslash +char248 " +`u 608,786,13,84,-50,81 2 0371 ugrave +char249 " +'u 608,786,13,84,-50,81 2 0372 uacute +char250 " +^u 608,764,13,84,-50,81 2 0373 ucircumflex +char251 " +:u 608,765,13,84,-50,81 2 0374 udieresis +char252 " +'y 536,786,192,138,-47,81 3 0375 yacute +char253 " +Tp 682,740,192,67,22,67 3 0376 thorn +char254 " +:y 536,765,192,138,-47,81 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/AR b/gnu/usr.bin/groff/devices/devps/AR new file mode 100644 index 0000000000..00fd6320b1 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/AR @@ -0,0 +1,558 @@ +name AR +internalname AvantGarde-Book +spacewidth 277 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -62 +A w -65 +A v -70 +A u -20 +A ' -100 +A rq -100 +A Y -92 +A W -60 +A V -102 +A U -40 +A T -45 +A Q -40 +A O -50 +A G -40 +A C -40 +B A -10 +C A -40 +D . -20 +D , -20 +D Y -30 +D W -10 +D V -50 +D A -50 +F . -160 +F e -20 +F , -180 +F a -20 +F A -75 +G . -20 +G , -20 +G Y -20 +J . -15 +J a -20 +J A -30 +K o -15 +K e -20 +K O -20 +L y -23 +L ' -130 +L rq -130 +L Y -91 +L W -67 +L V -113 +L T -46 +O . -30 +O , -30 +O Y -30 +O X -30 +O W -20 +O V -60 +O T -30 +O A -60 +P . -300 +P o -60 +P e -20 +P , -280 +P a -20 +P A -114 +Q , 20 +R Y -10 +R W 10 +R V -10 +R T 6 +S , 20 +T y -50 +T w -55 +T u -46 +T ; -29 +T r -30 +T . -91 +T o -70 +T i 10 +T - -75 +T hy -75 +T char173 -75 +T e -49 +T , -82 +T : -15 +T a -90 +T O -30 +T A -45 +U . -20 +U , -20 +U A -40 +V u -40 +V ; -33 +V . -165 +V o -101 +V i -5 +V - -75 +V hy -75 +V char173 -75 +V e -101 +V , -145 +V : -18 +V a -104 +V O -60 +V G -20 +V A -102 +W y -2 +W u -30 +W ; -33 +W . -106 +W o -46 +W i 6 +W - -35 +W hy -35 +W char173 -35 +W e -47 +W , -106 +W : -15 +W a -50 +W O -20 +W A -58 +Y u -52 +Y ; -23 +Y . -175 +Y o -89 +Y - -85 +Y hy -85 +Y char173 -85 +Y e -89 +Y , -145 +Y : -10 +Y a -93 +Y O -30 +Y A -92 +a p 20 +a b 20 +b y -20 +b v -20 +c y -20 +c k -15 +, ' -120 +, rq -120 +e y -20 +e w -20 +e v -20 +f . -50 +f o -40 +f l -30 +f i -34 +f f -60 +f e -20 +f .i -34 +f , -50 +f a -40 +g a -15 +h y -30 +k y -5 +k e -15 +m y -20 +m u -20 +m a -20 +n y -15 +n v -20 +o y -20 +o x -15 +o w -20 +o v -30 +p y -20 +. ' -120 +. rq -120 +lq ` -35 +lq oq -35 +lq A -100 +` ` -203 +` oq -203 +oq ` -203 +oq oq -203 +` A -100 +oq A -100 +' v -30 +' t 10 +' s -15 +' r -20 +' ' -203 +' rq -35 +' d -110 +r y 40 +r v 40 +r u 20 +r t 20 +r s 20 +r q -8 +r . -73 +r p 20 +r o -20 +r n 21 +r m 28 +r l 20 +r k 20 +r i 20 +r - -60 +r hy -60 +r char173 -60 +r g -15 +r e -4 +r d -6 +r , -75 +r c -20 +r a -20 +s . 20 +s , 20 +v . -130 +v o -30 +v e -20 +v , -100 +v a -30 +w . -100 +w o -30 +w h 15 +w e -20 +w , -90 +w a -30 +y . -125 +y o -30 +y e -20 +y , -110 +y a -30 +charset +ha 606,740 2 0000 asciicircum +ti 606,319 0 0001 asciitilde +vS 498,927,13 2 0002 Scaron +vZ 480,927 2 0003 Zcaron +vs 388,764,13 2 0004 scaron +vz 425,764 2 0005 zcaron +:Y 592,928 2 0006 Ydieresis +tm 1000,740 2 0007 trademark +aq 198,740 2 0010 quotesingle +space 277 0 0040 +! 295,740 2 0041 exclam +" 309,740 2 0042 quotedbl +# 554,740 2 0043 numbersign +sh " +$ 554,811,70 2 0044 dollar +Do " +% 775,751,13 2 0045 percent +& 757,753,12 2 0046 ampersand +' 351,740 2 0047 quoteright +( 369,757,205 3 0050 parenleft +) 369,757,205 3 0051 parenright +* 425,740 2 0052 asterisk ++ 606,506 0 0053 plus +, 277,126,67 0 0054 comma +- 332,315 0 0055 hyphen +hy " +char173 " +. 277,126 0 0056 period +/ 437,740,100 2 0057 slash +sl " +0 554,753,13 2 0060 zero +1 554,740 2 0061 one +2 554,753 2 0062 two +3 554,753,13 2 0063 three +4 554,740 2 0064 four +5 554,740,13 2 0065 five +6 554,739,13 2 0066 six +7 554,740 2 0067 seven +8 554,753,13 2 0070 eight +9 554,752 2 0071 nine +: 277,548 0 0072 colon +; 277,548,67 0 0073 semicolon +< 606,514,8 0 0074 less += 606,388 0 0075 equal +> 606,514,8 0 0076 greater +? 591,752 2 0077 question +@ 867,753,13 2 0100 at +at " +A 740,740 2 0101 A +B 574,740 2 0102 B +C 813,752,13 2 0103 C +D 744,740 2 0104 D +E 536,740 2 0105 E +F 485,740 2 0106 F +G 872,753,13 2 0107 G +H 683,740 2 0110 H +I 226,740 2 0111 I +J 482,740,13 2 0112 J +K 591,740 2 0113 K +L 462,740 2 0114 L +M 919,740 2 0115 M +N 740,740 2 0116 N +O 869,753,13 2 0117 O +P 592,740 2 0120 P +Q 871,753,13 2 0121 Q +R 607,740 2 0122 R +S 498,753,13 2 0123 S +T 426,740 2 0124 T +U 655,740,13 2 0125 U +V 702,740 2 0126 V +W 960,740 2 0127 W +X 609,740 2 0130 X +Y 592,740 2 0131 Y +Z 480,740 2 0132 Z +[ 351,753,179 2 0133 bracketleft +lB " +\ 605,740,100 2 0134 backslash +rs " +] 351,753,179 2 0135 bracketright +rB " +a^ 502,764 2 0136 circumflex +^ " +_ 500,0,125 0 0137 underscore +` 351,740 2 0140 quoteleft +oq " +a 683,561,13 0 0141 a +b 682,740,13 2 0142 b +c 647,561,13 0 0143 c +d 685,740,13 2 0144 d +e 650,561,13 0 0145 e +f 314,753 2 0146 f +g 673,561,215 1 0147 g +h 610,740 2 0150 h +i 200,740 2 0151 i +j 203,740,192 3 0152 j +k 502,740 2 0153 k +l 200,740 2 0154 l +m 938,561 0 0155 m +n 610,561 0 0156 n +o 655,561,13 0 0157 o +p 682,561,192 1 0160 p +q 682,561,192 1 0161 q +r 301,561 0 0162 r +s 388,561,13 0 0163 s +t 339,740 2 0164 t +u 608,547,13 0 0165 u +v 554,547 0 0166 v +w 831,547 0 0167 w +x 480,547 0 0170 x +y 536,547,192 1 0171 y +z 425,547 0 0172 z +lC 351,740,189 2 0173 braceleft +{ " +ba 672,740,100 2 0174 bar +| " +rC 351,740,189 2 0175 braceright +} " +a~ 439,754 2 0176 tilde +~ " +bq 354,126,68 0 0200 quotesinglbase +Fo 425,481 0 0201 guillemotleft +char171 " +Fc 425,481 0 0202 guillemotright +char187 " +bu 606,532 0 0203 bullet +Fn 554,818,153 2 0204 florin +f/ 166,740 2 0205 fraction +%0 1174,751,13 2 0206 perthousand +dg 553,740,133 2 0207 dagger +dd 553,740,133 2 0210 daggerdbl +en 500,315 0 0211 endash +em 1000,315 0 0212 emdash +fi 487,753 2 0214 fi +fl 485,753 2 0215 fl +.i 200,547 0 0220 dotlessi +ga 378,786 2 0222 grave +a" 552,800 2 0223 hungarumlaut +a. 222,765 2 0224 dotaccent +ab 453,754 2 0225 breve +ah 502,764 2 0226 caron +ao 332,807 2 0227 ring +ho 302,0,191 1 0230 ogonek +lq 502,740 2 0231 quotedblleft +rq 484,740 2 0232 quotedblright +oe 1137,561,13 0 0233 oe +/l 300,740 2 0234 lslash +Bq 502,126,68 0 0235 quotedblbase +OE 1194,753,13 2 0236 OE +/L 517,740 2 0237 Lslash +r! 295,548,192 1 0241 exclamdown +char161 " +ct 554,707 0 0242 cent +char162 " +Po 554,753 2 0243 sterling +char163 " +Cs 554,580 0 0244 currency +char164 " +Ye 554,740 2 0245 yen +char165 " +bb 672,740,100 2 0246 brokenbar +char166 " +sc 615,753,141 2 0247 section +char167 " +ad 369,765 2 0250 dieresis +char168 " +co 747,752,12 2 0251 copyright +char169 " +Of 369,753 2 0252 ordfeminine +char170 " +fo 251,481 0 0253 guilsinglleft +no 606,388 0 0254 logicalnot +char172 " +\- 606,287 0 0255 minus +rg 747,752,12 2 0256 registered +char174 " +a- 485,736 0 0257 macron +char175 " +de 400,709 0 0260 degree +char176 " +char177 606,518,24 0 0261 plusminus +S2 332,747 2 0262 twosuperior +char178 " +S3 332,747 2 0263 threesuperior +char179 " +aa 375,786 2 0264 acute +char180 " +char181 608,547,184 0 0265 mu +ps 564,740,110 2 0266 paragraph +char182 " +char183 277,316 0 0267 periodcentered +ac 324,0,222 1 0270 cedilla +char184 " +S1 332,740 2 0271 onesuperior +char185 " +Om 369,753 2 0272 ordmasculine +char186 " +fc 251,481 0 0273 guilsinglright +14 831,740 2 0274 onequarter +char188 " +12 831,740 2 0275 onehalf +char189 " +34 831,747 2 0276 threequarters +char190 " +r? 591,548,205 1 0277 questiondown +char191 " +`A 740,949 2 0300 Agrave +char192 " +'A 740,949 2 0301 Aacute +char193 " +^A 740,927 2 0302 Acircumflex +char194 " +~A 740,917 2 0303 Atilde +char195 " +:A 740,928 2 0304 Adieresis +char196 " +oA 740,955 2 0305 Aring +char197 " +AE 992,740 2 0306 AE +char198 " +,C 813,752,222 3 0307 Ccedilla +char199 " +`E 536,949 2 0310 Egrave +char200 " +'E 536,949 2 0311 Eacute +char201 " +^E 536,927 2 0312 Ecircumflex +char202 " +:E 536,928 2 0313 Edieresis +char203 " +`I 226,949 2 0314 Igrave +char204 " +'I 226,949 2 0315 Iacute +char205 " +^I 226,927 2 0316 Icircumflex +char206 " +:I 226,928 2 0317 Idieresis +char207 " +-D 790,740 2 0320 Eth +char208 " +~N 740,917 2 0321 Ntilde +char209 " +`O 869,949,13 2 0322 Ograve +char210 " +'O 869,949,13 2 0323 Oacute +char211 " +^O 869,927,13 2 0324 Ocircumflex +char212 " +~O 869,917,13 2 0325 Otilde +char213 " +:O 869,928,13 2 0326 Odieresis +char214 " +char215 606,482 0 0327 multiply +/O 868,819,83 2 0330 Oslash +char216 " +`U 655,949,13 2 0331 Ugrave +char217 " +'U 655,949,13 2 0332 Uacute +char218 " +^U 655,927,13 2 0333 Ucircumflex +char219 " +:U 655,928,13 2 0334 Udieresis +char220 " +'Y 592,949 2 0335 Yacute +char221 " +TP 592,740 2 0336 Thorn +char222 " +ss 554,753,13 2 0337 germandbls +char223 " +`a 683,786,13 2 0340 agrave +char224 " +'a 683,786,13 2 0341 aacute +char225 " +^a 683,764,13 2 0342 acircumflex +char226 " +~a 683,754,13 2 0343 atilde +char227 " +:a 683,765,13 2 0344 adieresis +char228 " +oa 683,807,13 2 0345 aring +char229 " +ae 1157,561,13 0 0346 ae +char230 " +,c 647,561,222 1 0347 ccedilla +char231 " +`e 650,786,13 2 0350 egrave +char232 " +'e 650,786,13 2 0351 eacute +char233 " +^e 650,764,13 2 0352 ecircumflex +char234 " +:e 650,765,13 2 0353 edieresis +char235 " +`i 200,786 2 0354 igrave +char236 " +'i 200,786 2 0355 iacute +char237 " +^i 200,764 2 0356 icircumflex +char238 " +:i 200,765 2 0357 idieresis +char239 " +Sd 655,753,12 2 0360 eth +char240 " +~n 610,754 2 0361 ntilde +char241 " +`o 655,786,13 2 0362 ograve +char242 " +'o 655,786,13 2 0363 oacute +char243 " +^o 655,764,13 2 0364 ocircumflex +char244 " +~o 655,754,13 2 0365 otilde +char245 " +:o 655,765,13 2 0366 odieresis +char246 " +char247 606,519,13 0 0367 divide +/o 653,614,64 0 0370 oslash +char248 " +`u 608,786,13 2 0371 ugrave +char249 " +'u 608,786,13 2 0372 uacute +char250 " +^u 608,764,13 2 0373 ucircumflex +char251 " +:u 608,765,13 2 0374 udieresis +char252 " +'y 536,786,192 3 0375 yacute +char253 " +Tp 682,740,192 3 0376 thorn +char254 " +:y 536,765,192 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/BMB b/gnu/usr.bin/groff/devices/devps/BMB new file mode 100644 index 0000000000..270f7db562 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/BMB @@ -0,0 +1,438 @@ +name BMB +internalname Bookman-Demi +spacewidth 340 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -1 +A w -9 +A v -8 +A Y -52 +A W -20 +A V -68 +A T -40 +F . -132 +F , -130 +F A -59 +L y 19 +L Y -35 +L W -41 +L V -50 +L T -4 +P . -128 +P , -129 +P A -46 +R y -8 +R Y -20 +R W -24 +R V -29 +R T -4 +T ; 5 +T s -10 +T r 27 +T . -122 +T o -28 +T i 27 +T - -10 +T hy -10 +T char173 -10 +T e -29 +T , -122 +T : 7 +T c -29 +T a -24 +T A -42 +V y 12 +V u -11 +V ; -38 +V r -15 +V . -105 +V o -79 +V i 15 +V - -10 +V hy -10 +V char173 -10 +V e -80 +V , -103 +V : -37 +V a -74 +V A -88 +W y 12 +W u -11 +W ; -38 +W r -15 +W . -105 +W o -78 +W i 15 +W - -10 +W hy -10 +W char173 -10 +W e -79 +W , -103 +W : -37 +W a -73 +W A -60 +Y v 24 +Y u -13 +Y ; -34 +Y q -66 +Y . -105 +Y p -23 +Y o -66 +Y i 2 +Y - -10 +Y hy -10 +Y char173 -10 +Y e -67 +Y , -103 +Y : -32 +Y a -60 +Y A -56 +f f 21 +r q -9 +r . -102 +r o -9 +r n 20 +r m 20 +r - -10 +r hy -10 +r char173 -10 +r h -23 +r g -9 +r f 20 +r e -10 +r d -10 +r , -101 +r c -9 +charset +ha 600,681 2 0000 asciicircum +ti 600,368 0 0001 asciitilde +vS 660,896,17 2 0002 Scaron +vZ 640,896 2 0003 Zcaron +vs 520,717,8 2 0004 scaron +vz 560,717 2 0005 zcaron +:Y 700,877 2 0006 Ydieresis +tm 980,681 2 0007 trademark +aq 240,698 2 0010 quotesingle +space 340 0 0040 +! 360,698,8 2 0041 exclam +" 420,698 2 0042 quotedbl +# 660,681 2 0043 numbersign +sh " +$ 660,805,119 2 0044 dollar +Do " +% 940,698,8 2 0045 percent +& 800,698,17 2 0046 ampersand +' 320,698 2 0047 quoteright +( 320,749,150 2 0050 parenleft +) 320,749,150 2 0051 parenright +* 460,697 2 0052 asterisk ++ 600,514 0 0053 plus +, 340,162,124 0 0054 comma +- 360,318 0 0055 hyphen +hy " +char173 " +. 340,172,8 0 0056 period +/ 600,725,149 2 0057 slash +sl " +0 660,698,17 2 0060 zero +1 660,681 2 0061 one +2 660,698 2 0062 two +3 660,698,17 2 0063 three +4 660,681 2 0064 four +5 660,723,17 2 0065 five +6 660,698,17 2 0066 six +7 660,681 2 0067 seven +8 660,698,17 2 0070 eight +9 660,698,17 2 0071 nine +: 340,515,8 0 0072 colon +; 340,515,124 0 0073 semicolon +< 600,542,9 0 0074 less += 600,421 0 0075 equal +> 600,542,9 0 0076 greater +? 660,698,8 2 0077 question +@ 820,698,17 2 0100 at +at " +A 720,681 2 0101 A +B 720,681 2 0102 B +C 740,698,17 2 0103 C +D 780,681 2 0104 D +E 720,681 2 0105 E +F 680,681 2 0106 F +G 780,698,17 2 0107 G +H 820,681 2 0110 H +I 400,681 2 0111 I +J 640,681,17 2 0112 J +K 800,681 2 0113 K +L 640,681 2 0114 L +M 940,681 2 0115 M +N 740,681 2 0116 N +O 800,698,17 2 0117 O +P 660,681 2 0120 P +Q 800,698,226 3 0121 Q +R 780,681 2 0122 R +S 660,698,17 2 0123 S +T 700,681 2 0124 T +U 740,681,17 2 0125 U +V 720,681 2 0126 V +W 940,681 2 0127 W +X 780,681 2 0130 X +Y 700,681 2 0131 Y +Z 640,681 2 0132 Z +[ 300,725,138 2 0133 bracketleft +lB " +\ 600,725 2 0134 backslash +rs " +] 300,725,138 2 0135 bracketright +rB " +a^ 500,731 2 0136 circumflex +^ " +_ 500,0,155 0 0137 underscore +` 320,698 2 0140 quoteleft +oq " +a 580,515,8 0 0141 a +b 600,725,8 2 0142 b +c 580,515,8 0 0143 c +d 640,725,8 2 0144 d +e 580,515,8 0 0145 e +f 380,741 2 0146 f +g 580,595,243 1 0147 g +h 680,725 2 0150 h +i 360,729 2 0151 i +j 340,729,221 3 0152 j +k 660,725 2 0153 k +l 340,725 2 0154 l +m 1000,515 0 0155 m +n 680,515 0 0156 n +o 620,515,8 0 0157 o +p 640,515,212 1 0160 p +q 620,515,212 1 0161 q +r 460,502 0 0162 r +s 520,515,8 0 0163 s +t 460,660,8 2 0164 t +u 660,502,8 0 0165 u +v 600,502 0 0166 v +w 800,502 0 0167 w +x 600,502 0 0170 x +y 620,502,221 1 0171 y +z 560,502 0 0172 z +lC 320,726,139 2 0173 braceleft +{ " +ba 600,725 2 0174 bar +| " +rC 320,726,139 2 0175 braceright +} " +a~ 480,691 2 0176 tilde +~ " +bq 320,144,114 0 0200 quotesinglbase +Fo 400,457 0 0201 guillemotleft +char171 " +Fc 400,457 0 0202 guillemotright +char187 " +bu 460,511 0 0203 bullet +Fn 660,749,209 2 0204 florin +f/ 120,681 2 0205 fraction +%0 1360,698,8 2 0206 perthousand +dg 440,698,156 2 0207 dagger +dd 380,698,156 2 0210 daggerdbl +en 500,318 0 0211 endash +em 1000,318 0 0212 emdash +fi 740,741 2 0214 fi +fl 740,741 2 0215 fl +.i 360,502 0 0220 dotlessi +ga 400,730 2 0222 grave +a" 440,741 2 0223 hungarumlaut +a. 320,730 2 0224 dotaccent +ab 500,722 2 0225 breve +ah 500,717 2 0226 caron +ao 340,755 2 0227 ring +ho 320,0,163 0 0230 ogonek +lq 540,698 2 0231 quotedblleft +rq 540,698 2 0232 quotedblright +oe 940,515,8 0 0233 oe +/l 340,725 2 0234 lslash +Bq 540,144,114 0 0235 quotedblbase +OE 1220,698,17 2 0236 OE +/L 640,681 2 0237 Lslash +r! 360,515,191 0 0241 exclamdown +char161 " +ct 660,674 2 0242 cent +char162 " +Po 660,698,17 2 0243 sterling +char163 " +Cs 660,593 0 0244 currency +char164 " +Ye 660,681 2 0245 yen +char165 " +bb 600,725 2 0246 brokenbar +char166 " +sc 600,698,153 2 0247 section +char167 " +ad 500,698 2 0250 dieresis +char168 " +co 740,698,17 2 0251 copyright +char169 " +Of 400,698 2 0252 ordfeminine +char170 " +fo 220,457 0 0253 guilsinglleft +no 600,421 0 0254 logicalnot +char172 " +\- 600,323 0 0255 minus +rg 740,698,17 2 0256 registered +char174 " +a- 460,663 2 0257 macron +char175 " +de 400,698 2 0260 degree +char176 " +char177 600,514 0 0261 plusminus +S2 396,698 2 0262 twosuperior +char178 " +S3 396,698 2 0263 threesuperior +char179 " +aa 400,731 2 0264 acute +char180 " +char181 660,502,221 1 0265 mu +ps 800,681,101 2 0266 paragraph +char182 " +char183 340,355 0 0267 periodcentered +ac 360,0,213 1 0270 cedilla +char184 " +S1 396,687 2 0271 onesuperior +char185 " +Om 400,698 2 0272 ordmasculine +char186 " +fc 220,457 0 0273 guilsinglright +14 990,681 2 0274 onequarter +char188 " +12 990,681 2 0275 onehalf +char189 " +34 990,692 2 0276 threequarters +char190 " +r? 660,515,191 0 0277 questiondown +char191 " +`A 720,909 2 0300 Agrave +char192 " +'A 720,910 2 0301 Aacute +char193 " +^A 720,910 2 0302 Acircumflex +char194 " +~A 720,870 2 0303 Atilde +char195 " +:A 720,877 2 0304 Adieresis +char196 " +oA 720,934 2 0305 Aring +char197 " +AE 1140,681 2 0306 AE +char198 " +,C 740,698,213 3 0307 Ccedilla +char199 " +`E 720,909 2 0310 Egrave +char200 " +'E 720,910 2 0311 Eacute +char201 " +^E 720,910 2 0312 Ecircumflex +char202 " +:E 720,877 2 0313 Edieresis +char203 " +`I 400,909 2 0314 Igrave +char204 " +'I 400,910 2 0315 Iacute +char205 " +^I 400,910 2 0316 Icircumflex +char206 " +:I 400,877 2 0317 Idieresis +char207 " +-D 780,681 2 0320 Eth +char208 " +~N 740,870 2 0321 Ntilde +char209 " +`O 800,909,17 2 0322 Ograve +char210 " +'O 800,910,17 2 0323 Oacute +char211 " +^O 800,910,17 2 0324 Ocircumflex +char212 " +~O 800,870,17 2 0325 Otilde +char213 " +:O 800,877,17 2 0326 Odieresis +char214 " +char215 600,514 0 0327 multiply +/O 800,781,110 2 0330 Oslash +char216 " +`U 740,909,17 2 0331 Ugrave +char217 " +'U 740,910,17 2 0332 Uacute +char218 " +^U 740,910,17 2 0333 Ucircumflex +char219 " +:U 740,877,17 2 0334 Udieresis +char220 " +'Y 700,910 2 0335 Yacute +char221 " +TP 660,681 2 0336 Thorn +char222 " +ss 660,699,91 2 0337 germandbls +char223 " +`a 580,730,8 2 0340 agrave +char224 " +'a 580,731,8 2 0341 aacute +char225 " +^a 580,731,8 2 0342 acircumflex +char226 " +~a 580,691,8 2 0343 atilde +char227 " +:a 580,698,8 2 0344 adieresis +char228 " +oa 580,755,8 2 0345 aring +char229 " +ae 880,515,8 0 0346 ae +char230 " +,c 580,515,213 1 0347 ccedilla +char231 " +`e 580,730,8 2 0350 egrave +char232 " +'e 580,731,8 2 0351 eacute +char233 " +^e 580,731,8 2 0352 ecircumflex +char234 " +:e 580,698,8 2 0353 edieresis +char235 " +`i 360,730 2 0354 igrave +char236 " +'i 360,731 2 0355 iacute +char237 " +^i 360,731 2 0356 icircumflex +char238 " +:i 360,698 2 0357 idieresis +char239 " +Sd 620,741,8 2 0360 eth +char240 " +~n 680,691 2 0361 ntilde +char241 " +`o 620,730,8 2 0362 ograve +char242 " +'o 620,731,8 2 0363 oacute +char243 " +^o 620,731,8 2 0364 ocircumflex +char244 " +~o 620,691,8 2 0365 otilde +char245 " +:o 620,698,8 2 0366 odieresis +char246 " +char247 600,521 0 0367 divide +/o 620,551,40 0 0370 oslash +char248 " +`u 660,730,8 2 0371 ugrave +char249 " +'u 660,731,8 2 0372 uacute +char250 " +^u 660,731,8 2 0373 ucircumflex +char251 " +:u 660,698,8 2 0374 udieresis +char252 " +'y 620,731,221 3 0375 yacute +char253 " +Tp 640,725,212 3 0376 thorn +char254 " +:y 620,698,221 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/BMBI b/gnu/usr.bin/groff/devices/devps/BMBI new file mode 100644 index 0000000000..0670451a9a --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/BMBI @@ -0,0 +1,441 @@ +name BMBI +internalname Bookman-DemiItalic +slant 10 +spacewidth 340 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y 20 +A w 20 +A v 20 +A Y -25 +A W -35 +A V -40 +A T -17 +F . -105 +F , -98 +F A -35 +L y 62 +L Y -5 +L W -15 +L V -19 +L T -26 +P . -105 +P , -98 +P A -31 +R y 27 +R Y 4 +R W -4 +R V -8 +R T -3 +T y 56 +T w 69 +T u 42 +T ; 31 +T s -1 +T r 41 +T . -107 +T o -5 +T i 42 +T - -20 +T hy -20 +T char173 -20 +T e -10 +T , -100 +T : 26 +T c -8 +T a -8 +T A -42 +V y 17 +V u -1 +V ; -22 +V r 2 +V . -115 +V o -50 +V i 32 +V - -20 +V hy -20 +V char173 -20 +V e -50 +V , -137 +V : -28 +V a -50 +V A -50 +W y -51 +W u -69 +W ; -81 +W r -66 +W . -183 +W o -100 +W i -36 +W - -22 +W hy -22 +W char173 -22 +W e -100 +W , -201 +W : -86 +W a -100 +W A -77 +Y v 26 +Y u -1 +Y ; -4 +Y q -43 +Y . -113 +Y o -41 +Y i 20 +Y - -20 +Y hy -20 +Y char173 -20 +Y e -46 +Y , -106 +Y : -9 +Y a -45 +Y A -30 +f f 10 +r q -3 +r . -120 +r o -1 +r n 39 +r m 39 +r - -20 +r hy -20 +r char173 -20 +r h -35 +r g -23 +r f 42 +r e -6 +r d -3 +r , -113 +r c -5 +charset +ha 620,681,0,24,-42,24 2 0000 asciicircum +ti 620,368,0,35,-51,35 0 0001 asciitilde +vS 700,915,17,81,-9,73 2 0002 Scaron +vZ 680,915,0,110,27,73 2 0003 Zcaron +vs 540,749,8,83,18,73 2 0004 scaron +vz 560,749,8,76,14,73 2 0005 zcaron +:Y 660,900,0,207,-22,73 2 0006 Ydieresis +tm 940,681,0,92,8,73 2 0007 trademark +aq 180,696,0,165,-76,73 2 0010 quotesingle +space 340 0 0040 +! 320,698,8,96,-36,73 2 0041 exclam +" 380,697,0,177,-90,73 2 0042 quotedbl +# 680,681,0,19,-107,19 2 0043 numbersign +sh " +$ 680,790,164,67,5,67 2 0044 dollar +Do " +% 880,698,17,69,-56,69 2 0045 percent +& 980,698,17,86,2,73 2 0046 ampersand +' 320,698,0,79,-121,73 2 0047 quoteright +( 260,741,134,178,19,73 2 0050 parenleft +) 260,741,134,112,85,73 2 0051 parenright +* 460,698,0,98,-76,73 2 0052 asterisk ++ 600,514,0,45,-41,45 0 0053 plus +, 340,185,124,8,-50,8 0 0054 comma +- 280,313,0,89,-9,73 0 0055 hyphen +hy " +char173 " +. 340,177,8,6,-56,6 0 0056 period +/ 360,742,106,192,41,73 2 0057 slash +sl " +0 680,698,17,73,-37,73 2 0060 zero +1 680,681,0,0,-73 2 0061 one +2 680,698,0,44,-17,44 2 0062 two +3 680,698,17,53,-22,53 2 0063 three +4 680,681,0,78,-13,73 2 0064 four +5 680,681,17,39,-28,39 2 0065 five +6 680,698,17,74,-38,73 2 0066 six +7 680,681,0,109,-73,73 2 0067 seven +8 680,698,17,56,-18,56 2 0070 eight +9 680,698,17,82,-21,73 2 0071 nine +: 340,515,8,66,-56,66 0 0072 colon +; 340,515,124,62,-50,62 0 0073 semicolon +< 620,540,9,18,-29,18 0 0074 less += 600,421,0,45,-41,45 0 0075 equal +> 620,540,9,28,-39,28 0 0076 greater +? 620,698,8,98,-95,73 2 0077 question +@ 780,698,17,60,-30,60 2 0100 at +at " +A 720,681,0,99,77,73 2 0101 A +B 720,681,0,92,36,73 2 0102 B +C 700,698,17,104,-28,73 2 0103 C +D 760,681,0,95,36,73 2 0104 D +E 720,681,0,107,36,73 2 0105 E +F 660,681,0,153,36,73 2 0106 F +G 760,698,17,118,-27,73 2 0107 G +H 800,681,0,160,36,73 2 0110 H +I 380,681,0,155,36,73 2 0111 I +J 620,681,17,151,42,73 2 0112 J +K 780,681,0,149,36,73 2 0113 K +L 640,681,0,135,36,73 2 0114 L +M 860,681,0,160,36,73 2 0115 M +N 740,681,0,155,36,73 2 0116 N +O 760,698,17,96,-28,73 2 0117 O +P 640,681,0,134,56,73 2 0120 P +Q 760,698,213,95,13,73 3 0121 Q +R 740,681,0,75,36,73 2 0122 R +S 700,698,17,81,-9,73 2 0123 S +T 700,681,0,152,-20,73 2 0124 T +U 740,681,17,165,-62,73 2 0125 U +V 660,681,0,209,-22,73 2 0126 V +W 1000,681,0,140,-22,73 2 0127 W +X 740,681,0,145,57,73 2 0130 X +Y 660,681,0,207,-22,73 2 0131 Y +Z 680,681,0,110,27,73 2 0132 Z +[ 260,741,118,164,41,73 2 0133 bracketleft +lB " +\ 580,741,0,45,-23,45 2 0134 backslash +rs " +] 260,741,118,137,68,73 2 0135 bracketright +rB " +a^ 480,749,0,93,-133,73 2 0136 circumflex +^ " +_ 500,0,155,50,50,50 0 0137 underscore +` 320,698,0,63,-105,63 2 0140 quoteleft +oq " +a 680,515,8,105,-34,73 0 0141 a +b 600,732,8,83,-7,73 2 0142 b +c 560,515,8,87,-8,73 0 0143 c +d 680,732,8,84,-10,73 2 0144 d +e 560,515,8,86,-9,73 0 0145 e +f 420,741,213,271,242,73 3 0146 f +g 620,515,213,99,29,73 1 0147 g +h 700,732,8,86,-43,73 2 0150 h +i 380,755,8,90,-33,73 2 0151 i +j 320,755,213,122,210,73 3 0152 j +k 700,732,8,82,-47,73 2 0153 k +l 380,732,8,80,-59,73 2 0154 l +m 960,515,8,86,-33,73 0 0155 m +n 680,515,8,85,-33,73 0 0156 n +o 600,515,8,77,-9,73 0 0157 o +p 660,515,213,72,74,72 1 0160 p +q 620,515,213,70,-10,70 1 0161 q +r 500,515,0,132,-34,73 0 0162 r +s 540,515,8,83,18,73 0 0163 s +t 440,658,8,98,-56,73 2 0164 t +u 680,507,8,90,-33,73 0 0165 u +v 540,515,8,82,-6,73 0 0166 v +w 860,515,8,81,-6,73 0 0167 w +x 620,515,8,84,40,73 0 0170 x +y 600,507,213,92,25,73 1 0171 y +z 560,515,8,76,14,73 0 0172 z +lC 300,742,123,159,-3,73 2 0173 braceleft +{ " +ba 620,741,0,0,-253 2 0174 bar +| " +rC 300,742,123,102,54,73 2 0175 braceright +} " +a~ 480,709,0,103,-128,73 2 0176 tilde +~ " +bq 300,166,112,34,-56,34 0 0200 quotesinglbase +Fo 380,503,0,76,-12,73 0 0201 guillemotleft +char171 " +Fc 380,503,0,76,-12,73 0 0202 guillemotright +char187 " +bu 360,511,0,94,-10,73 0 0203 bullet +Fn 680,741,199,113,78,73 2 0204 florin +f/ 120,681,0,312,194,73 2 0205 fraction +%0 1360,698,17,23,-56,23 2 0206 perthousand +dg 420,698,137,96,-39,73 2 0207 dagger +dd 420,698,137,116,-29,73 2 0210 daggerdbl +en 500,311,0,123,10,73 0 0211 endash +em 1000,311,0,123,10,73 0 0212 emdash +fi 820,741,213,80,241,73 3 0214 fi +fl 820,741,213,80,241,73 3 0215 fl +.i 380,507,8,90,-33,73 0 0220 dotlessi +ga 380,771,0,94,-143,73 2 0222 grave +a" 560,775,0,106,-131,73 2 0223 hungarumlaut +a. 380,734,0,15,-130,15 2 0224 dotaccent +ab 460,707,0,106,-127,73 2 0225 breve +ah 480,749,0,93,-133,73 2 0226 caron +ao 360,775,0,96,-135,73 2 0227 ring +ho 320,0,182,0,-18 0 0230 ogonek +lq 520,698,0,75,-106,73 2 0231 quotedblleft +rq 520,698,0,90,-121,73 2 0232 quotedblright +oe 920,515,8,91,2,73 0 0233 oe +/l 380,732,8,82,-13,73 2 0234 lslash +Bq 520,166,112,25,-56,25 0 0235 quotedblbase +OE 1180,698,17,115,-44,73 2 0236 OE +/L 640,681,0,134,36,73 2 0237 Lslash +r! 320,515,191,74,-14,73 0 0241 exclamdown +char161 " +ct 680,718,0,0,-111 2 0242 cent +char162 " +Po 680,698,17,157,50,73 2 0243 sterling +char163 " +Cs 680,571,0,7,-98,7 0 0244 currency +char164 " +Ye 680,681,0,152,-42,73 2 0245 yen +char165 " +bb 620,741,0,0,-253 2 0246 brokenbar +char166 " +sc 620,698,137,68,4,68 2 0247 section +char167 " +ad 520,734,0,99,-130,73 2 0250 dieresis +char168 " +co 780,698,17,53,-33,53 2 0251 copyright +char169 " +Of 440,685,0,105,-5,73 2 0252 ordfeminine +char170 " +fo 220,503,0,79,-12,73 0 0253 guilsinglleft +no 620,421,0,15,-31,15 0 0254 logicalnot +char172 " +\- 600,323,0,45,-41,45 0 0255 minus +rg 780,698,17,53,-33,53 2 0256 registered +char174 " +a- 480,691,0,101,-127,73 2 0257 macron +char175 " +de 400,698,0,80,-80,73 2 0260 degree +char176 " +char177 600,514,0,45,-41,45 0 0261 plusminus +S2 408,698,0,127,-41,73 2 0262 twosuperior +char178 " +S3 408,698,0,125,-36,73 2 0263 threesuperior +char179 " +aa 340,771,0,117,-126,73 2 0264 acute +char180 " +char181 680,507,213,90,-4,73 1 0265 mu +ps 680,681,204,96,-20,73 2 0266 paragraph +char182 " +char183 340,358,0,26,-76,26 0 0267 periodcentered +ac 360,0,220,0,-18 1 0270 cedilla +char184 " +S1 408,688,0,48,-68,48 2 0271 onesuperior +char185 " +Om 440,685,0,77,3,73 2 0272 ordmasculine +char186 " +fc 220,503,0,79,-12,73 0 0273 guilsinglright +14 1020,681,0,84,-68,73 2 0274 onequarter +char188 " +12 1020,681,0,66,-68,66 2 0275 onehalf +char189 " +34 1020,691,0,84,-36,73 2 0276 threequarters +char190 " +r? 620,515,189,36,-33,36 0 0277 questiondown +char191 " +`A 720,937,0,99,77,73 2 0300 Agrave +char192 " +'A 720,937,0,99,77,73 2 0301 Aacute +char193 " +^A 720,915,0,99,77,73 2 0302 Acircumflex +char194 " +~A 720,875,0,99,77,73 2 0303 Atilde +char195 " +:A 720,900,0,99,77,73 2 0304 Adieresis +char196 " +oA 720,941,0,99,77,73 2 0305 Aring +char197 " +AE 1140,681,0,117,77,73 2 0306 AE +char198 " +,C 700,698,220,104,-28,73 3 0307 Ccedilla +char199 " +`E 720,937,0,107,36,73 2 0310 Egrave +char200 " +'E 720,937,0,107,36,73 2 0311 Eacute +char201 " +^E 720,915,0,107,36,73 2 0312 Ecircumflex +char202 " +:E 720,900,0,107,36,73 2 0313 Edieresis +char203 " +`I 380,937,0,155,36,73 2 0314 Igrave +char204 " +'I 380,937,0,155,36,73 2 0315 Iacute +char205 " +^I 380,915,0,163,36,73 2 0316 Icircumflex +char206 " +:I 380,900,0,169,36,73 2 0317 Idieresis +char207 " +-D 760,681,0,95,36,73 2 0320 Eth +char208 " +~N 740,875,0,155,36,73 2 0321 Ntilde +char209 " +`O 760,937,17,96,-28,73 2 0322 Ograve +char210 " +'O 760,937,17,96,-28,73 2 0323 Oacute +char211 " +^O 760,915,17,96,-28,73 2 0324 Ocircumflex +char212 " +~O 760,875,17,96,-28,73 2 0325 Otilde +char213 " +:O 760,900,17,96,-28,73 2 0326 Odieresis +char214 " +char215 600,514,0,45,-41,45 0 0327 multiply +/O 760,725,29,137,29,73 2 0330 Oslash +char216 " +`U 740,937,17,165,-62,73 2 0331 Ugrave +char217 " +'U 740,937,17,165,-62,73 2 0332 Uacute +char218 " +^U 740,915,17,165,-62,73 2 0333 Ucircumflex +char219 " +:U 740,900,17,165,-62,73 2 0334 Udieresis +char220 " +'Y 660,937,0,207,-22,73 2 0335 Yacute +char221 " +TP 640,681,0,111,56,73 2 0336 Thorn +char222 " +ss 660,741,213,92,281,73 3 0337 germandbls +char223 " +`a 680,771,8,105,-34,73 2 0340 agrave +char224 " +'a 680,771,8,105,-34,73 2 0341 aacute +char225 " +^a 680,749,8,105,-34,73 2 0342 acircumflex +char226 " +~a 680,709,8,105,-34,73 2 0343 atilde +char227 " +:a 680,734,8,105,-34,73 2 0344 adieresis +char228 " +oa 680,775,8,105,-34,73 2 0345 aring +char229 " +ae 880,515,8,83,11,73 0 0346 ae +char230 " +,c 560,515,220,87,-8,73 1 0347 ccedilla +char231 " +`e 560,771,8,86,-9,73 2 0350 egrave +char232 " +'e 560,771,8,86,-9,73 2 0351 eacute +char233 " +^e 560,749,8,86,-9,73 2 0352 ecircumflex +char234 " +:e 560,734,8,86,-9,73 2 0353 edieresis +char235 " +`i 380,771,8,94,-33,73 2 0354 igrave +char236 " +'i 380,771,8,90,-33,73 2 0355 iacute +char237 " +^i 380,749,8,103,-33,73 2 0356 icircumflex +char238 " +:i 380,734,8,149,-33,73 2 0357 idieresis +char239 " +Sd 600,741,8,112,-9,73 2 0360 eth +char240 " +~n 680,709,8,85,-33,73 2 0361 ntilde +char241 " +`o 600,771,8,77,-9,73 2 0362 ograve +char242 " +'o 600,771,8,77,-9,73 2 0363 oacute +char243 " +^o 600,749,8,77,-9,73 2 0364 ocircumflex +char244 " +~o 600,709,8,77,-9,73 2 0365 otilde +char245 " +:o 600,734,8,77,-9,73 2 0366 odieresis +char246 " +char247 600,521,0,45,-41,45 0 0367 divide +/o 600,571,54,111,33,73 0 0370 oslash +char248 " +`u 680,771,8,90,-33,73 2 0371 ugrave +char249 " +'u 680,771,8,90,-33,73 2 0372 uacute +char250 " +^u 680,749,8,90,-33,73 2 0373 ucircumflex +char251 " +:u 680,734,8,90,-33,73 2 0374 udieresis +char252 " +'y 600,771,213,92,25,73 3 0375 yacute +char253 " +Tp 660,732,213,72,74,72 3 0376 thorn +char254 " +:y 600,734,213,92,25,73 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/BMI b/gnu/usr.bin/groff/devices/devps/BMI new file mode 100644 index 0000000000..7eaa3f1f6b --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/BMI @@ -0,0 +1,434 @@ +name BMI +internalname Bookman-LightItalic +slant 10 +spacewidth 300 +encoding text.enc +ligatures fi fl 0 +kernpairs +A Y -62 +A W -73 +A V -78 +A T -5 +F . -97 +F , -98 +F A -16 +L y 20 +L Y 7 +L W 9 +L V 4 +P . -105 +P , -106 +P A -30 +R Y 11 +R W 2 +R V 2 +R T 65 +T ; 48 +T s -7 +T r 67 +T . -78 +T o 14 +T i 71 +T - 20 +T hy 20 +T char173 20 +T e 10 +T , -79 +T : 48 +T c 16 +T a 9 +T A -14 +V y -14 +V u -10 +V ; -44 +V r -20 +V . -100 +V o -70 +V i 3 +V - 20 +V hy 20 +V char173 20 +V e -70 +V , -109 +V : -35 +V a -70 +V A -70 +W y -14 +W u -20 +W ; -42 +W r -30 +W . -100 +W o -60 +W i 3 +W - 20 +W hy 20 +W char173 20 +W e -60 +W , -109 +W : -35 +W a -60 +W A -60 +Y v -19 +Y u -31 +Y ; -40 +Y q -72 +Y . -100 +Y p -37 +Y o -75 +Y i -11 +Y - 20 +Y hy 20 +Y char173 20 +Y e -78 +Y , -109 +Y : -35 +Y a -79 +Y A -82 +f f -19 +r q -14 +r . -134 +r o -10 +r n 38 +r m 37 +r - 20 +r hy 20 +r char173 20 +r h -20 +r g -3 +r f -9 +r e -15 +r d -9 +r , -143 +r c -8 +charset +ha 600,681,0,49,-47,49 2 0000 asciicircum +ti 600,386,0,45,-41,45 0 0001 asciitilde +vS 640,871,17,78,-11,70 2 0002 Scaron +vZ 580,871,0,165,42,70 2 0003 Zcaron +vs 540,684,8,57,-15,57 2 0004 scaron +vz 520,684,8,91,12,70 2 0005 zcaron +:Y 660,875,0,199,-37,70 2 0006 Ydieresis +tm 980,681,0,35,-19,35 2 0007 trademark +aq 200,698,0,97,-49,70 2 0010 quotesingle +space 300 0 0040 +! 320,698,8,72,-53,70 2 0041 exclam +" 360,698,0,92,-57,70 2 0042 quotedbl +# 620,681,0,28,-57,28 2 0043 numbersign +sh " +$ 620,762,85,49,-28,49 2 0044 dollar +Do " +% 800,691,8,61,-6,61 2 0045 percent +& 820,698,18,78,-15,70 2 0046 ampersand +' 280,698,0,58,-98,58 2 0047 quoteright +( 280,727,146,153,-46,70 2 0050 parenleft +) 280,727,146,49,58,49 2 0051 parenright +* 440,698,0,115,-89,70 2 0052 asterisk ++ 600,548,0,45,-41,45 0 0053 plus +, 300,112,115,0,-38 0 0054 comma +- 320,325,0,66,-28,66 0 0055 hyphen +hy " +char173 " +. 300,127,8,0,-46 0 0056 period +/ 600,717,149,12,-54,12 2 0057 slash +sl " +0 620,698,17,76,-36,70 2 0060 zero +1 620,681,0,0,-104 2 0061 one +2 620,698,0,66,-16,66 2 0062 two +3 620,698,17,52,-5,52 2 0063 three +4 620,681,0,64,-19,64 2 0064 four +5 620,681,17,44,-20,44 2 0065 five +6 620,698,17,87,-39,70 2 0066 six +7 620,681,0,102,-93,70 2 0067 seven +8 620,698,17,85,-11,70 2 0070 eight +9 620,698,17,79,-27,70 2 0071 nine +: 300,494,8,42,-46,42 0 0072 colon +; 300,494,114,42,-38,42 0 0073 semicolon +< 600,561,0,38,-29,38 0 0074 less += 600,433,0,45,-41,45 0 0075 equal +> 600,561,0,52,-43,52 0 0076 greater +? 540,698,8,114,-64,70 2 0077 question +@ 780,698,17,72,-52,70 2 0100 at +at " +A 700,681,0,70,75,70 2 0101 A +B 720,681,0,76,29,70 2 0102 B +C 720,698,17,76,-38,70 2 0103 C +D 740,681,0,92,29,70 2 0104 D +E 680,681,0,106,29,70 2 0105 E +F 620,681,0,173,29,70 2 0106 F +G 760,698,17,103,-38,70 2 0107 G +H 800,681,0,138,29,70 2 0110 H +I 320,681,0,142,29,70 2 0111 I +J 560,681,17,156,52,70 2 0112 J +K 720,681,0,134,29,70 2 0113 K +L 580,681,0,126,29,70 2 0114 L +M 860,681,0,146,32,70 2 0115 M +N 720,681,0,153,32,70 2 0116 N +O 760,698,17,89,-38,70 2 0117 O +P 600,681,0,131,29,70 2 0120 P +Q 780,698,191,82,-11,70 2 0121 Q +R 700,681,0,86,29,70 2 0122 R +S 640,698,17,78,-11,70 2 0123 S +T 600,681,0,175,0,70 2 0124 T +U 720,681,17,172,-68,70 2 0125 U +V 680,681,0,185,-37,70 2 0126 V +W 960,681,0,185,-37,70 2 0127 W +X 700,681,0,165,75,70 2 0130 X +Y 660,681,0,199,-37,70 2 0131 Y +Z 580,681,0,165,42,70 2 0132 Z +[ 260,717,136,141,-6,70 2 0133 bracketleft +lB " +\ 600,717,0,0,-34 2 0134 backslash +rs " +] 260,717,136,99,35,70 2 0135 bracketright +rB " +a^ 440,685,0,89,-126,70 2 0136 circumflex +^ " +_ 500,0,155,50,50,50 0 0137 underscore +` 280,698,0,100,-141,70 2 0140 quoteleft +oq " +a 620,494,8,116,-21,70 0 0141 a +b 600,717,8,71,-38,70 2 0142 b +c 480,494,8,92,-15,70 0 0143 c +d 640,717,8,105,-15,70 2 0144 d +e 540,494,8,85,-15,70 0 0145 e +f 340,725,218,267,210,70 3 0146 f +g 560,494,221,71,46,70 1 0147 g +h 620,717,8,119,-38,70 2 0150 h +i 280,663,8,121,-38,70 2 0151 i +j 280,663,221,78,250,70 3 0152 j +k 600,717,8,107,-38,70 2 0153 k +l 280,717,8,112,-50,70 2 0154 l +m 880,494,8,122,-38,70 0 0155 m +n 620,494,8,103,-38,70 0 0156 n +o 540,494,8,82,-15,70 0 0157 o +p 600,494,212,70,74,70 1 0160 p +q 560,494,212,74,-15,70 1 0161 q +r 400,494,0,131,-38,70 0 0162 r +s 540,494,8,57,-15,57 0 0163 s +t 340,664,8,121,-38,70 2 0164 t +u 620,484,8,116,-38,70 0 0165 u +v 540,494,8,72,-38,70 0 0166 v +w 880,494,8,63,-38,63 0 0167 w +x 540,494,8,136,41,70 0 0170 x +y 600,484,221,59,-10,59 1 0171 y +z 520,494,8,91,12,70 0 0172 z +lC 360,717,191,129,-75,70 2 0173 braceleft +{ " +ba 600,717,0,0,-244 2 0174 bar +| " +rC 380,717,191,0,35 2 0175 braceright +} " +a~ 440,671,0,98,-130,70 2 0176 tilde +~ " +bq 320,113,114,0,-37 0 0200 quotesinglbase +Fo 300,434,0,63,-20,63 0 0201 guillemotleft +char171 " +Fc 300,434,0,53,-10,53 0 0202 guillemotright +char187 " +bu 460,511,0,34,-50,34 0 0203 bullet +Fn 620,725,218,122,76,70 3 0204 florin +f/ 20,681,0,353,278,70 2 0205 fraction +%0 1180,691,8,69,-6,69 2 0206 perthousand +dg 620,698,130,0,-142 2 0207 dagger +dd 620,698,122,0,-94 2 0210 daggerdbl +en 500,325,0,111,17,70 0 0211 endash +em 1000,325,0,111,17,70 0 0212 emdash +fi 640,725,222,119,209,70 3 0214 fi +fl 660,725,218,103,209,70 3 0215 fl +.i 280,484,8,121,-38,70 0 0220 dotlessi +ga 340,706,0,87,-132,70 2 0222 grave +a" 340,738,0,112,-117,70 2 0223 hungarumlaut +a. 260,664,0,80,-119,70 2 0224 dotaccent +ab 440,680,0,110,-141,70 2 0225 breve +ah 440,684,0,91,-128,70 2 0226 caron +ao 300,706,0,84,-128,70 2 0227 ring +ho 260,0,173,0,-1 0 0230 ogonek +lq 440,698,0,103,-141,70 2 0231 quotedblleft +rq 440,698,0,61,-98,61 2 0232 quotedblright +oe 900,494,8,98,-15,70 0 0233 oe +/l 340,717,8,108,0,70 2 0234 lslash +Bq 480,113,114,0,-37 0 0235 quotedblbase +OE 1180,698,17,107,-38,70 2 0236 OE +/L 580,681,0,126,29,70 2 0237 Lslash +r! 320,494,213,31,-23,31 1 0241 exclamdown +char161 " +ct 620,715,29,26,-98,26 2 0242 cent +char162 " +Po 620,698,17,132,46,70 2 0243 sterling +char163 " +Cs 620,591,0,35,-50,35 0 0244 currency +char164 " +Ye 620,681,0,165,-21,70 2 0245 yen +char165 " +bb 600,717,0,0,-244 2 0246 brokenbar +char166 " +sc 620,698,178,68,12,68 2 0247 section +char167 " +ad 420,688,0,97,-135,70 2 0250 dieresis +char168 " +co 740,698,17,94,-34,70 2 0251 copyright +char169 " +Of 440,698,0,123,-44,70 2 0252 ordfeminine +char170 " +fo 180,434,0,78,-25,70 0 0253 guilsinglleft +no 600,433,0,45,-41,45 0 0254 logicalnot +char172 " +\- 600,335,0,45,-41,45 0 0255 minus +rg 740,698,17,94,-34,70 2 0256 registered +char174 " +a- 440,658,0,94,-128,70 0 0257 macron +char175 " +de 400,698,0,70,-70,70 2 0260 degree +char176 " +char177 600,548,0,45,-41,45 0 0261 plusminus +S2 372,698,0,117,-18,70 2 0262 twosuperior +char178 " +S3 372,698,0,117,-20,70 2 0263 threesuperior +char179 " +aa 320,706,0,103,-128,70 2 0264 acute +char180 " +char181 620,484,221,116,-3,70 1 0265 mu +ps 620,681,0,148,-62,70 2 0266 paragraph +char182 " +char183 300,364,0,22,-87,22 0 0267 periodcentered +ac 320,0,178,0,5 0 0270 cedilla +char184 " +S1 372,688,0,17,-64,17 2 0271 onesuperior +char185 " +Om 400,698,0,105,-44,70 2 0272 ordmasculine +char186 " +fc 180,434,0,73,-20,70 0 0273 guilsinglright +14 930,681,0,33,-41,33 2 0274 onequarter +char188 " +12 930,681,0,45,-41,45 2 0275 onehalf +char189 " +34 930,691,0,33,-49,33 2 0276 threequarters +char190 " +r? 540,494,212,18,32,18 1 0277 questiondown +char191 " +`A 700,893,0,70,75,70 2 0300 Agrave +char192 " +'A 700,893,0,70,75,70 2 0301 Aacute +char193 " +^A 700,872,0,70,75,70 2 0302 Acircumflex +char194 " +~A 700,858,0,70,75,70 2 0303 Atilde +char195 " +:A 700,875,0,70,75,70 2 0304 Adieresis +char196 " +oA 700,893,0,70,75,70 2 0305 Aring +char197 " +AE 1220,681,0,99,95,70 2 0306 AE +char198 " +,C 720,698,178,76,-38,70 2 0307 Ccedilla +char199 " +`E 680,893,0,106,29,70 2 0310 Egrave +char200 " +'E 680,893,0,106,29,70 2 0311 Eacute +char201 " +^E 680,872,0,106,29,70 2 0312 Ecircumflex +char202 " +:E 680,875,0,106,29,70 2 0313 Edieresis +char203 " +`I 320,893,0,142,29,70 2 0314 Igrave +char204 " +'I 320,893,0,142,29,70 2 0315 Iacute +char205 " +^I 320,872,0,149,29,70 2 0316 Icircumflex +char206 " +:I 320,875,0,147,29,70 2 0317 Idieresis +char207 " +-D 740,681,0,92,29,70 2 0320 Eth +char208 " +~N 720,858,0,153,32,70 2 0321 Ntilde +char209 " +`O 760,893,17,89,-38,70 2 0322 Ograve +char210 " +'O 760,893,17,89,-38,70 2 0323 Oacute +char211 " +^O 760,872,17,89,-38,70 2 0324 Ocircumflex +char212 " +~O 760,858,17,89,-38,70 2 0325 Otilde +char213 " +:O 760,875,17,89,-38,70 2 0326 Odieresis +char214 " +char215 600,548,0,45,-41,45 0 0327 multiply +/O 760,777,95,89,-38,70 2 0330 Oslash +char216 " +`U 720,893,17,172,-68,70 2 0331 Ugrave +char217 " +'U 720,893,17,172,-68,70 2 0332 Uacute +char218 " +^U 720,872,17,172,-68,70 2 0333 Ucircumflex +char219 " +:U 720,875,17,172,-68,70 2 0334 Udieresis +char220 " +'Y 660,893,0,199,-37,70 2 0335 Yacute +char221 " +TP 600,681,0,106,29,70 2 0336 Thorn +char222 " +ss 620,698,111,83,171,70 2 0337 germandbls +char223 " +`a 620,706,8,116,-21,70 2 0340 agrave +char224 " +'a 620,706,8,116,-21,70 2 0341 aacute +char225 " +^a 620,685,8,116,-21,70 2 0342 acircumflex +char226 " +~a 620,671,8,116,-21,70 2 0343 atilde +char227 " +:a 620,688,8,116,-21,70 2 0344 adieresis +char228 " +oa 620,706,8,116,-21,70 2 0345 aring +char229 " +ae 880,494,8,88,-21,70 0 0346 ae +char230 " +,c 480,494,178,92,-15,70 0 0347 ccedilla +char231 " +`e 540,706,8,85,-15,70 2 0350 egrave +char232 " +'e 540,706,8,85,-15,70 2 0351 eacute +char233 " +^e 540,685,8,85,-15,70 2 0352 ecircumflex +char234 " +:e 540,688,8,85,-15,70 2 0353 edieresis +char235 " +`i 280,706,8,121,-38,70 2 0354 igrave +char236 " +'i 280,706,8,121,-38,70 2 0355 iacute +char237 " +^i 280,685,8,149,-26,70 2 0356 icircumflex +char238 " +:i 280,688,8,147,-38,70 2 0357 idieresis +char239 " +Sd 540,725,8,152,-15,70 2 0360 eth +char240 " +~n 620,671,8,103,-38,70 2 0361 ntilde +char241 " +`o 540,706,8,82,-15,70 2 0362 ograve +char242 " +'o 540,706,8,82,-15,70 2 0363 oacute +char243 " +^o 540,685,8,82,-15,70 2 0364 ocircumflex +char244 " +~o 540,671,8,82,-15,70 2 0365 otilde +char245 " +:o 540,688,8,82,-15,70 2 0366 odieresis +char246 " +char247 600,548,0,45,-41,45 0 0367 divide +/o 540,532,49,81,-15,70 0 0370 oslash +char248 " +`u 620,706,8,116,-38,70 2 0371 ugrave +char249 " +'u 620,706,8,116,-38,70 2 0372 uacute +char250 " +^u 620,685,8,116,-38,70 2 0373 ucircumflex +char251 " +:u 620,688,8,116,-38,70 2 0374 udieresis +char252 " +'y 600,706,221,59,-10,59 3 0375 yacute +char253 " +Tp 600,717,212,70,74,70 3 0376 thorn +char254 " +:y 600,688,221,59,-10,59 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/BMR b/gnu/usr.bin/groff/devices/devps/BMR new file mode 100644 index 0000000000..8e90c10009 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/BMR @@ -0,0 +1,430 @@ +name BMR +internalname Bookman-Light +spacewidth 320 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y 32 +A w 4 +A v 7 +A Y -35 +A W -40 +A V -56 +A T 1 +F . -46 +F , -41 +F A -21 +L y 79 +L Y 13 +L W 1 +L V -4 +L T 28 +P . -60 +P , -55 +P A -8 +R y 59 +R Y 26 +R W 13 +R V 8 +R T 71 +T s 16 +T r 38 +T . -33 +T o 15 +T i 42 +T - 90 +T hy 90 +T char173 90 +T e 13 +T , -28 +T c 14 +T a 17 +T A 1 +V y 15 +V u -38 +V r -41 +V . -40 +V o -71 +V i -20 +V - 11 +V hy 11 +V char173 11 +V e -72 +V , -34 +V a -69 +V A -66 +W y 15 +W u -38 +W r -41 +W . -40 +W o -68 +W i -20 +W - 11 +W hy 11 +W char173 11 +W e -69 +W , -34 +W a -66 +W A -64 +Y v 15 +Y u -38 +Y q -55 +Y . -40 +Y p -31 +Y o -57 +Y i -37 +Y - 11 +Y hy 11 +Y char173 11 +Y e -58 +Y , -34 +Y a -54 +Y A -53 +f f 29 +r q 9 +r . -64 +r o 8 +r n 31 +r m 31 +r - 70 +r hy 70 +r char173 70 +r h -21 +r g -4 +r f 33 +r e 7 +r d 7 +r , -58 +r c 7 +charset +ha 600,681 2 0000 asciicircum +ti 600,352 0 0001 asciitilde +vS 660,869,17 2 0002 Scaron +vZ 640,869 2 0003 Zcaron +vs 520,672,8 2 0004 scaron +vz 480,672 2 0005 zcaron +:Y 640,871 2 0006 Ydieresis +tm 980,681 2 0007 trademark +aq 220,698 2 0010 quotesingle +space 320 0 0040 +! 300,698,8 2 0041 exclam +" 380,698 2 0042 quotedbl +# 620,681 2 0043 numbersign +sh " +$ 620,791,109 2 0044 dollar +Do " +% 900,698,8 2 0045 percent +& 800,698,17 2 0046 ampersand +' 220,698 2 0047 quoteright +( 300,727,145 2 0050 parenleft +) 300,727,146 2 0051 parenright +* 440,698 2 0052 asterisk ++ 600,513 0 0053 plus +, 320,114,114 0 0054 comma +- 400,292 0 0055 hyphen +hy " +char173 " +. 320,123,8 0 0056 period +/ 600,717,149 2 0057 slash +sl " +0 620,698,17 2 0060 zero +1 620,681 2 0061 one +2 620,698 2 0062 two +3 620,698,17 2 0063 three +4 620,681 2 0064 four +5 620,717,17 2 0065 five +6 620,698,17 2 0066 six +7 620,681 2 0067 seven +8 620,698,17 2 0070 eight +9 620,698,17 2 0071 nine +: 320,494,8 0 0072 colon +; 320,494,114 0 0073 semicolon +< 600,526,2 0 0074 less += 600,398 0 0075 equal +> 600,526,2 0 0076 greater +? 540,698,8 2 0077 question +@ 820,698,17 2 0100 at +at " +A 680,681 2 0101 A +B 740,681 2 0102 B +C 740,698,17 2 0103 C +D 800,681 2 0104 D +E 720,681 2 0105 E +F 640,681 2 0106 F +G 800,698,17 2 0107 G +H 800,681 2 0110 H +I 340,681 2 0111 I +J 600,681,17 2 0112 J +K 720,681 2 0113 K +L 600,681 2 0114 L +M 920,681 2 0115 M +N 740,681 2 0116 N +O 800,698,17 2 0117 O +P 620,681 2 0120 P +Q 820,698,189 2 0121 Q +R 720,681 2 0122 R +S 660,698,17 2 0123 S +T 620,681 2 0124 T +U 780,681,17 2 0125 U +V 700,681 2 0126 V +W 960,681 2 0127 W +X 720,681 2 0130 X +Y 640,681 2 0131 Y +Z 640,681 2 0132 Z +[ 300,717,136 2 0133 bracketleft +lB " +\ 600,717 2 0134 backslash +rs " +] 300,717,136 2 0135 bracketright +rB " +a^ 420,685 2 0136 circumflex +^ " +_ 500,0,155 0 0137 underscore +` 220,698 2 0140 quoteleft +oq " +a 580,494,8 0 0141 a +b 620,717,8 2 0142 b +c 520,494,8 0 0143 c +d 620,717,8 2 0144 d +e 520,494,8 0 0145 e +f 320,734 2 0146 f +g 540,567,243 1 0147 g +h 660,717 2 0150 h +i 300,654 0 0151 i +j 300,654,251 1 0152 j +k 620,717 2 0153 k +l 300,717 2 0154 l +m 940,494 0 0155 m +n 660,494 0 0156 n +o 560,494,8 0 0157 o +p 620,494,228 1 0160 p +q 580,494,228 1 0161 q +r 440,494 0 0162 r +s 520,494,8 0 0163 s +t 380,667,8 2 0164 t +u 680,484,8 0 0165 u +v 520,484 0 0166 v +w 780,484 0 0167 w +x 560,484 0 0170 x +y 540,484,236 1 0171 y +z 480,484 0 0172 z +lC 280,717,136 2 0173 braceleft +{ " +ba 600,717 2 0174 bar +| " +rC 280,717,136 2 0175 braceright +} " +a~ 440,661 0 0176 tilde +~ " +bq 220,110,108 0 0200 quotesinglbase +Fo 360,437 0 0201 guillemotleft +char171 " +Fc 360,437 0 0202 guillemotright +char187 " +bu 460,511 0 0203 bullet +Fn 620,749,155 2 0204 florin +f/ 140,681 2 0205 fraction +%0 1280,698,8 2 0206 perthousand +dg 540,698,156 2 0207 dagger +dd 540,698,156 2 0210 daggerdbl +en 500,292 0 0211 endash +em 1000,292 0 0212 emdash +fi 620,734 2 0214 fi +fl 620,734 2 0215 fl +.i 300,484 0 0220 dotlessi +ga 340,689 2 0222 grave +a" 380,699 2 0223 hungarumlaut +a. 260,672 2 0224 dotaccent +ab 460,687 2 0225 breve +ah 420,672 2 0226 caron +ao 320,731 2 0227 ring +ho 320,0,145 0 0230 ogonek +lq 400,698 2 0231 quotedblleft +rq 400,698 2 0232 quotedblright +oe 900,494,8 0 0233 oe +/l 320,717 2 0234 lslash +Bq 400,110,108 0 0235 quotedblbase +OE 1240,698,17 2 0236 OE +/L 600,681 2 0237 Lslash +r! 300,494,214 0 0241 exclamdown +char161 " +ct 620,651 0 0242 cent +char162 " +Po 620,698,17 2 0243 sterling +char163 " +Cs 620,591 0 0244 currency +char164 " +Ye 620,681 2 0245 yen +char165 " +bb 600,717 2 0246 brokenbar +char166 " +sc 520,698,178 2 0247 section +char167 " +ad 420,674 2 0250 dieresis +char168 " +co 740,698,17 2 0251 copyright +char169 " +Of 420,698 2 0252 ordfeminine +char170 " +fo 240,437 0 0253 guilsinglleft +no 600,398 0 0254 logicalnot +char172 " +\- 600,300 0 0255 minus +rg 740,698,17 2 0256 registered +char174 " +a- 440,635 0 0257 macron +char175 " +de 400,698 2 0260 degree +char176 " +char177 600,513 0 0261 plusminus +S2 372,698 2 0262 twosuperior +char178 " +S3 372,698 2 0263 threesuperior +char179 " +aa 340,689 2 0264 acute +char180 " +char181 680,484,251 1 0265 mu +ps 600,681 2 0266 paragraph +char182 " +char183 320,327 0 0267 periodcentered +ac 320,0,200 0 0270 cedilla +char184 " +S1 372,688 2 0271 onesuperior +char185 " +Om 420,698 2 0272 ordmasculine +char186 " +fc 240,437 0 0273 guilsinglright +14 930,681 2 0274 onequarter +char188 " +12 930,681 2 0275 onehalf +char189 " +34 930,691 2 0276 threequarters +char190 " +r? 540,494,217 0 0277 questiondown +char191 " +`A 680,886 2 0300 Agrave +char192 " +'A 680,886 2 0301 Aacute +char193 " +^A 680,882 2 0302 Acircumflex +char194 " +~A 680,858 2 0303 Atilde +char195 " +:A 680,871 2 0304 Adieresis +char196 " +oA 680,928 2 0305 Aring +char197 " +AE 1260,681 2 0306 AE +char198 " +,C 740,698,200 2 0307 Ccedilla +char199 " +`E 720,886 2 0310 Egrave +char200 " +'E 720,886 2 0311 Eacute +char201 " +^E 720,882 2 0312 Ecircumflex +char202 " +:E 720,871 2 0313 Edieresis +char203 " +`I 340,886 2 0314 Igrave +char204 " +'I 340,886 2 0315 Iacute +char205 " +^I 340,882 2 0316 Icircumflex +char206 " +:I 340,871 2 0317 Idieresis +char207 " +-D 800,681 2 0320 Eth +char208 " +~N 740,858 2 0321 Ntilde +char209 " +`O 800,886,17 2 0322 Ograve +char210 " +'O 800,886,17 2 0323 Oacute +char211 " +^O 800,882,17 2 0324 Ocircumflex +char212 " +~O 800,858,17 2 0325 Otilde +char213 " +:O 800,871,17 2 0326 Odieresis +char214 " +char215 600,513 0 0327 multiply +/O 800,733,53 2 0330 Oslash +char216 " +`U 780,886,17 2 0331 Ugrave +char217 " +'U 780,886,17 2 0332 Uacute +char218 " +^U 780,882,17 2 0333 Ucircumflex +char219 " +:U 780,871,17 2 0334 Udieresis +char220 " +'Y 640,886 2 0335 Yacute +char221 " +TP 620,681 2 0336 Thorn +char222 " +ss 660,698,110 2 0337 germandbls +char223 " +`a 580,689,8 2 0340 agrave +char224 " +'a 580,689,8 2 0341 aacute +char225 " +^a 580,685,8 2 0342 acircumflex +char226 " +~a 580,661,8 0 0343 atilde +char227 " +:a 580,674,8 2 0344 adieresis +char228 " +oa 580,731,8 2 0345 aring +char229 " +ae 860,494,8 0 0346 ae +char230 " +,c 520,494,200 0 0347 ccedilla +char231 " +`e 520,689,8 2 0350 egrave +char232 " +'e 520,689,8 2 0351 eacute +char233 " +^e 520,685,8 2 0352 ecircumflex +char234 " +:e 520,674,8 2 0353 edieresis +char235 " +`i 300,689 2 0354 igrave +char236 " +'i 300,689 2 0355 iacute +char237 " +^i 300,685 2 0356 icircumflex +char238 " +:i 300,674 2 0357 idieresis +char239 " +Sd 560,734,8 2 0360 eth +char240 " +~n 660,661 0 0361 ntilde +char241 " +`o 560,689,8 2 0362 ograve +char242 " +'o 560,689,8 2 0363 oacute +char243 " +^o 560,685,8 2 0364 ocircumflex +char244 " +~o 560,661,8 0 0365 otilde +char245 " +:o 560,674,8 2 0366 odieresis +char246 " +char247 600,514 0 0367 divide +/o 560,534,40 0 0370 oslash +char248 " +`u 680,689,8 2 0371 ugrave +char249 " +'u 680,689,8 2 0372 uacute +char250 " +^u 680,685,8 2 0373 ucircumflex +char251 " +:u 680,674,8 2 0374 udieresis +char252 " +'y 540,689,236 3 0375 yacute +char253 " +Tp 620,717,228 3 0376 thorn +char254 " +:y 540,674,236 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/CB b/gnu/usr.bin/groff/devices/devps/CB new file mode 100644 index 0000000000..c199fd93f9 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/CB @@ -0,0 +1,336 @@ +name CB +internalname Courier-Bold +spacewidth 600 +encoding text.enc +charset +ha 600,616 2 0000 asciicircum +ti 600,356 0 0001 asciitilde +vS 600,790,22 2 0002 Scaron +vZ 600,790 2 0003 Zcaron +vs 600,667,17 2 0004 scaron +vz 600,667 2 0005 zcaron +:Y 600,748 2 0006 Ydieresis +tm 600,562 2 0007 trademark +aq 600,562 2 0010 quotesingle +space 600 0 0040 +! 600,572,15 2 0041 exclam +" 600,562 2 0042 quotedbl +# 600,651,45 2 0043 numbersign +sh " +$ 600,666,126 2 0044 dollar +Do " +% 600,616,15 2 0045 percent +& 600,543,15 0 0046 ampersand +' 600,562 2 0047 quoteright +( 600,616,102 2 0050 parenleft +) 600,616,102 2 0051 parenright +* 600,601 2 0052 asterisk ++ 600,478 0 0053 plus +, 600,174,111 0 0054 comma +- 600,313 0 0055 hyphen +hy " +char173 " +. 600,171,15 0 0056 period +/ 600,626,77 2 0057 slash +sl " +0 600,616,15 2 0060 zero +1 600,616 2 0061 one +2 600,616 2 0062 two +3 600,616,15 2 0063 three +4 600,616 2 0064 four +5 600,601,15 2 0065 five +6 600,616,15 2 0066 six +7 600,601 2 0067 seven +8 600,616,15 2 0070 eight +9 600,616,15 2 0071 nine +: 600,425,15 0 0072 colon +; 600,425,111 0 0073 semicolon +< 600,501 0 0074 less += 600,398 0 0075 equal +> 600,501 0 0076 greater +? 600,580,14 2 0077 question +@ 600,616,15 2 0100 at +at " +A 600,562 2 0101 A +B 600,562 2 0102 B +C 600,580,18 2 0103 C +D 600,562 2 0104 D +E 600,562 2 0105 E +F 600,562 2 0106 F +G 600,580,18 2 0107 G +H 600,562 2 0110 H +I 600,562 2 0111 I +J 600,562,18 2 0112 J +K 600,562 2 0113 K +L 600,562 2 0114 L +M 600,562 2 0115 M +N 600,562,12 2 0116 N +O 600,580,18 2 0117 O +P 600,562 2 0120 P +Q 600,580,138 2 0121 Q +R 600,562 2 0122 R +S 600,582,22 2 0123 S +T 600,562 2 0124 T +U 600,562,18 2 0125 U +V 600,562 2 0126 V +W 600,562 2 0127 W +X 600,562 2 0130 X +Y 600,562 2 0131 Y +Z 600,562 2 0132 Z +[ 600,616,102 2 0133 bracketleft +lB " +\ 600,626,77 2 0134 backslash +rs " +] 600,616,102 2 0135 bracketright +rB " +a^ 600,657 2 0136 circumflex +^ " +_ 600,0,125 0 0137 underscore +` 600,562 2 0140 quoteleft +oq " +a 600,454,15 0 0141 a +b 600,626,15 2 0142 b +c 600,459,15 0 0143 c +d 600,626,15 2 0144 d +e 600,454,15 0 0145 e +f 600,626 2 0146 f +g 600,454,146 1 0147 g +h 600,626 2 0150 h +i 600,658 2 0151 i +j 600,658,146 3 0152 j +k 600,626 2 0153 k +l 600,626 2 0154 l +m 600,454 0 0155 m +n 600,454 0 0156 n +o 600,454,15 0 0157 o +p 600,454,142 1 0160 p +q 600,454,142 1 0161 q +r 600,454 0 0162 r +s 600,459,17 0 0163 s +t 600,562,15 2 0164 t +u 600,439,15 0 0165 u +v 600,439 0 0166 v +w 600,439 0 0167 w +x 600,439 0 0170 x +y 600,439,142 1 0171 y +z 600,439 0 0172 z +lC 600,616,102 2 0173 braceleft +{ " +ba 600,750,250 3 0174 bar +| " +rC 600,616,102 2 0175 braceright +} " +a~ 600,636 2 0176 tilde +~ " +bq 600,143,142 1 0200 quotesinglbase +Fo 600,446 0 0201 guillemotleft +char171 " +Fc 600,446 0 0202 guillemotright +char187 " +bu 600,430 0 0203 bullet +Fn 600,616,131 2 0204 florin +f/ 600,661,60 2 0205 fraction +%0 600,616,15 2 0206 perthousand +dg 600,580,70 2 0207 dagger +dd 600,580,70 2 0210 daggerdbl +en 600,313 0 0211 endash +em 600,313 0 0212 emdash +fi 600,626 2 0214 fi +fl 600,626 2 0215 fl +.i 600,439 0 0220 dotlessi +ga 600,661 2 0222 grave +a" 600,661 2 0223 hungarumlaut +a. 600,625 2 0224 dotaccent +ab 600,631 2 0225 breve +ah 600,667 2 0226 caron +ao 600,678 2 0227 ring +ho 600,0,199 1 0230 ogonek +lq 600,562 2 0231 quotedblleft +rq 600,562 2 0232 quotedblright +oe 600,454,15 0 0233 oe +/l 600,626 2 0234 lslash +Bq 600,143,142 1 0235 quotedblbase +OE 600,562 2 0236 OE +/L 600,562 2 0237 Lslash +r! 600,449,146 1 0241 exclamdown +char161 " +ct 600,614,49 2 0242 cent +char162 " +Po 600,611,28 2 0243 sterling +char163 " +Cs 600,517 0 0244 currency +char164 " +Ye 600,562 2 0245 yen +char165 " +bb 600,675,175 3 0246 brokenbar +char166 " +sc 600,580,70 2 0247 section +char167 " +ad 600,625 2 0250 dieresis +char168 " +co 600,580,18 2 0251 copyright +char169 " +Of 600,580 2 0252 ordfeminine +char170 " +fo 600,446 0 0253 guilsinglleft +no 600,413 0 0254 logicalnot +char172 " +\- 600,313 0 0255 minus +rg 600,580,18 2 0256 registered +char174 " +a- 600,585 2 0257 macron +char175 " +de 600,616 2 0260 degree +char176 " +char177 600,515 0 0261 plusminus +S2 600,616 2 0262 twosuperior +char178 " +S3 600,616 2 0263 threesuperior +char179 " +aa 600,661 2 0264 acute +char180 " +char181 600,439,142 1 0265 mu +ps 600,580,70 2 0266 paragraph +char182 " +char183 600,351 0 0267 periodcentered +ac 600,0,206 1 0270 cedilla +char184 " +S1 600,616 2 0271 onesuperior +char185 " +Om 600,580 2 0272 ordmasculine +char186 " +fc 600,446 0 0273 guilsinglright +14 600,661,60 2 0274 onequarter +char188 " +12 600,661,60 2 0275 onehalf +char189 " +34 600,661,60 2 0276 threequarters +char190 " +r? 600,449,146 1 0277 questiondown +char191 " +`A 600,784 2 0300 Agrave +char192 " +'A 600,784 2 0301 Aacute +char193 " +^A 600,780 2 0302 Acircumflex +char194 " +~A 600,759 2 0303 Atilde +char195 " +:A 600,748 2 0304 Adieresis +char196 " +oA 600,801 2 0305 Aring +char197 " +AE 600,562 2 0306 AE +char198 " +,C 600,580,206 3 0307 Ccedilla +char199 " +`E 600,784 2 0310 Egrave +char200 " +'E 600,784 2 0311 Eacute +char201 " +^E 600,780 2 0312 Ecircumflex +char202 " +:E 600,748 2 0313 Edieresis +char203 " +`I 600,784 2 0314 Igrave +char204 " +'I 600,784 2 0315 Iacute +char205 " +^I 600,780 2 0316 Icircumflex +char206 " +:I 600,748 2 0317 Idieresis +char207 " +-D 600,562 2 0320 Eth +char208 " +~N 600,759,12 2 0321 Ntilde +char209 " +`O 600,784,18 2 0322 Ograve +char210 " +'O 600,784,18 2 0323 Oacute +char211 " +^O 600,780,18 2 0324 Ocircumflex +char212 " +~O 600,759,18 2 0325 Otilde +char213 " +:O 600,748,18 2 0326 Odieresis +char214 " +char215 600,478 0 0327 multiply +/O 600,584,22 2 0330 Oslash +char216 " +`U 600,784,18 2 0331 Ugrave +char217 " +'U 600,784,18 2 0332 Uacute +char218 " +^U 600,780,18 2 0333 Ucircumflex +char219 " +:U 600,748,18 2 0334 Udieresis +char220 " +'Y 600,784 2 0335 Yacute +char221 " +TP 600,562 2 0336 Thorn +char222 " +ss 600,626,15 2 0337 germandbls +char223 " +`a 600,661,15 2 0340 agrave +char224 " +'a 600,661,15 2 0341 aacute +char225 " +^a 600,657,15 2 0342 acircumflex +char226 " +~a 600,636,15 2 0343 atilde +char227 " +:a 600,625,15 2 0344 adieresis +char228 " +oa 600,678,15 2 0345 aring +char229 " +ae 600,454,15 0 0346 ae +char230 " +,c 600,459,206 1 0347 ccedilla +char231 " +`e 600,661,15 2 0350 egrave +char232 " +'e 600,661,15 2 0351 eacute +char233 " +^e 600,657,15 2 0352 ecircumflex +char234 " +:e 600,625,15 2 0353 edieresis +char235 " +`i 600,661 2 0354 igrave +char236 " +'i 600,661 2 0355 iacute +char237 " +^i 600,657 2 0356 icircumflex +char238 " +:i 600,625 2 0357 idieresis +char239 " +Sd 600,626,27 2 0360 eth +char240 " +~n 600,636 2 0361 ntilde +char241 " +`o 600,661,15 2 0362 ograve +char242 " +'o 600,661,15 2 0363 oacute +char243 " +^o 600,657,15 2 0364 ocircumflex +char244 " +~o 600,636,15 2 0365 otilde +char245 " +:o 600,625,15 2 0366 odieresis +char246 " +char247 600,500 0 0367 divide +/o 600,463,24 0 0370 oslash +char248 " +`u 600,661,15 2 0371 ugrave +char249 " +'u 600,661,15 2 0372 uacute +char250 " +^u 600,657,15 2 0373 ucircumflex +char251 " +:u 600,625,15 2 0374 udieresis +char252 " +'y 600,661,142 3 0375 yacute +char253 " +Tp 600,626,142 3 0376 thorn +char254 " +:y 600,625,142 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/CBI b/gnu/usr.bin/groff/devices/devps/CBI new file mode 100644 index 0000000000..802e3366d7 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/CBI @@ -0,0 +1,337 @@ +name CBI +internalname Courier-BoldOblique +slant 12 +spacewidth 600 +encoding text.enc +charset +ha 600,616,0,5,-121,5 2 0000 asciicircum +ti 600,356,0,39,-70,39 0 0001 asciitilde +vS 600,790,22,122,-4,75 2 0002 Scaron +vZ 600,790,0,109,-12,75 2 0003 Zcaron +vs 600,667,17,82,-17,75 2 0004 scaron +vz 600,667,0,82,-31,75 2 0005 zcaron +:Y 600,748,0,158,-59,75 2 0006 Ydieresis +tm 600,562,0,318,-36,75 2 0007 trademark +aq 600,562,0,0,-254 2 0010 quotesingle +space 600 0 0040 +! 600,572,15,0,-166 2 0041 exclam +" 600,562,0,34,-162,34 2 0042 quotedbl +# 600,651,45,90,-38,75 2 0043 numbersign +sh " +$ 600,666,126,79,-37,75 2 0044 dollar +Do " +% 600,616,15,74,-52,74 2 0045 percent +& 600,543,15,44,-12,44 0 0046 ampersand +' 600,562,0,0,-180 2 0047 quoteright +( 600,616,102,42,-216,42 2 0050 parenleft +) 600,616,102,0,-67 2 0051 parenright +* 600,601,0,47,-129,47 2 0052 asterisk ++ 600,478,0,46,-64,46 0 0053 plus +, 600,174,111,0,-49 0 0054 comma +- 600,313,0,17,-93,17 0 0055 hyphen +hy " +char173 " +. 600,171,15,0,-157 0 0056 period +/ 600,626,77,76,-41,75 2 0057 slash +sl " +0 600,616,15,42,-86,42 2 0060 zero +1 600,616,0,11,-43,11 2 0061 one +2 600,616,0,43,-11,43 2 0062 two +3 600,616,15,21,-22,21 2 0063 three +4 600,616,0,8,-32,8 2 0064 four +5 600,601,15,71,-27,71 2 0065 five +6 600,616,15,102,-86,75 2 0066 six +7 600,601,0,72,-97,72 2 0067 seven +8 600,616,15,54,-65,54 2 0070 eight +9 600,616,15,42,-26,42 2 0071 nine +: 600,425,15,0,-156 0 0072 colon +; 600,425,111,0,-49 0 0073 semicolon +< 600,501,0,62,-71,62 0 0074 less += 600,398,0,64,-46,64 0 0075 equal +> 600,501,0,39,-47,39 0 0076 greater +? 600,580,14,41,-133,41 2 0077 question +@ 600,616,15,91,-16,75 2 0100 at +at " +A 600,562,0,81,59,75 2 0101 A +B 600,562,0,79,20,75 2 0102 B +C 600,580,18,124,-25,75 2 0103 C +D 600,562,0,114,20,75 2 0104 D +E 600,562,0,119,25,75 2 0105 E +F 600,562,0,133,11,75 2 0106 F +G 600,580,18,124,-25,75 2 0107 G +H 600,562,0,149,30,75 2 0110 H +I 600,562,0,92,-27,75 2 0111 I +J 600,562,18,170,-9,75 2 0112 J +K 600,562,0,141,29,75 2 0113 K +L 600,562,0,85,11,75 2 0114 L +M 600,562,0,171,52,75 2 0115 M +N 600,562,12,179,42,75 2 0116 N +O 600,580,18,95,-24,75 2 0117 O +P 600,562,0,92,2,75 2 0120 P +Q 600,580,138,86,-34,75 2 0121 Q +R 600,562,0,67,26,67 2 0122 R +S 600,582,22,122,-4,75 2 0123 S +T 600,562,0,128,-36,75 2 0124 T +U 600,562,18,165,-51,75 2 0125 U +V 600,562,0,182,-34,75 2 0126 V +W 600,562,0,187,-34,75 2 0127 W +X 600,562,0,139,38,75 2 0130 X +Y 600,562,0,158,-59,75 2 0131 Y +Z 600,562,0,86,-12,75 2 0132 Z +[ 600,616,102,56,-173,56 2 0133 bracketleft +lB " +\ 600,626,77,0,-173 2 0134 backslash +rs " +] 600,616,102,0,-53 2 0135 bracketright +rB " +a^ 600,657,0,56,-162,56 2 0136 circumflex +^ " +_ 600,0,125,34,77,34 0 0137 underscore +` 600,562,0,0,-247 2 0140 quoteleft +oq " +a 600,454,15,42,-12,42 0 0141 a +b 600,626,15,86,37,75 2 0142 b +c 600,459,15,81,-31,75 0 0143 c +d 600,626,15,94,-11,75 2 0144 d +e 600,454,15,54,-31,54 0 0145 e +f 600,626,0,127,-33,75 2 0146 f +g 600,454,146,123,9,75 1 0147 g +h 600,626,0,64,32,64 2 0150 h +i 600,658,0,0,-27 2 0151 i +j 600,658,146,30,13,30 3 0152 j +k 600,626,0,92,17,75 2 0153 k +l 600,626,0,0,-27 2 0154 l +m 600,454,0,98,72,75 0 0155 m +n 600,454,0,64,32,64 0 0156 n +o 600,454,15,72,-21,72 0 0157 o +p 600,454,142,72,81,72 1 0160 p +q 600,454,142,134,-11,75 1 0161 q +r 600,454,0,104,3,75 0 0162 r +s 600,459,17,57,-17,57 0 0163 s +t 600,562,15,16,-68,16 2 0164 t +u 600,439,15,41,-20,41 0 0165 u +v 600,439,0,144,-20,75 0 0166 v +w 600,439,0,161,-3,75 0 0167 w +x 600,439,0,120,44,75 0 0170 x +y 600,439,142,144,70,75 1 0171 y +z 600,439,0,63,-31,63 0 0172 z +lC 600,616,102,45,-154,45 2 0173 braceleft +{ " +ba 600,750,250,0,-152 3 0174 bar +| " +rC 600,616,102,0,-64 2 0175 braceright +} " +a~ 600,636,0,92,-150,75 2 0176 tilde +~ " +bq 600,143,142,0,-95 1 0200 quotesinglbase +Fo 600,446,0,88,-13,75 0 0201 guillemotleft +char171 " +Fc 600,446,0,97,-22,75 0 0202 guillemotright +char187 " +bu 600,430,0,0,-147 0 0203 bullet +Fn 600,616,131,151,106,75 2 0204 florin +f/ 600,661,60,157,28,75 2 0205 fraction +%0 600,616,15,192,94,75 2 0206 perthousand +dg 600,580,70,36,-126,36 2 0207 dagger +dd 600,580,70,36,-72,36 2 0210 daggerdbl +en 600,313,0,52,-58,52 0 0211 endash +em 600,313,0,127,17,75 0 0212 emdash +fi 600,626,0,93,38,75 2 0214 fi +fl 600,626,0,93,38,75 2 0215 fl +.i 600,439,0,0,-27 0 0220 dotlessi +ga 600,661,0,0,-222 2 0222 grave +a" 600,661,0,178,-122,75 2 0223 hungarumlaut +a. 600,625,0,0,-296 2 0224 dotaccent +ab 600,631,0,101,-167,75 2 0225 breve +ah 600,667,0,82,-188,75 2 0226 caron +ao 600,678,0,0,-269 2 0227 ring +ho 600,0,199,0,-94 1 0230 ogonek +lq 600,562,0,44,-140,44 2 0231 quotedblleft +rq 600,562,0,94,-70,75 2 0232 quotedblright +oe 600,454,15,111,31,75 0 0233 oe +/l 600,626,0,28,-27,28 2 0234 lslash +Bq 600,143,142,9,15,9 1 0235 quotedblbase +OE 600,562,0,150,24,75 2 0236 OE +/L 600,562,0,85,11,75 2 0237 Lslash +r! 600,449,146,0,-147 1 0241 exclamdown +char161 " +ct 600,614,49,54,-71,54 2 0242 cent +char162 " +Po 600,611,28,100,-57,75 2 0243 sterling +char163 " +Cs 600,517,0,93,-27,75 0 0244 currency +char164 " +Ye 600,562,0,159,-48,75 2 0245 yen +char165 " +bb 600,675,175,0,-168 3 0246 brokenbar +char166 " +sc 600,580,70,69,-24,69 2 0247 section +char167 " +ad 600,625,0,42,-194,42 2 0250 dieresis +char168 " +co 600,580,18,117,-3,75 2 0251 copyright +char169 " +Of 600,580,0,0,-139 2 0252 ordfeminine +char170 " +fo 600,446,0,0,-146 0 0253 guilsinglleft +no 600,413,0,67,-85,67 0 0254 logicalnot +char172 " +\- 600,313,0,46,-64,46 0 0255 minus +rg 600,580,18,117,-3,75 2 0256 registered +char174 " +a- 600,585,0,86,-145,75 2 0257 macron +char175 " +de 600,616,0,19,-123,19 2 0260 degree +char176 " +char177 600,515,0,64,-26,64 0 0261 plusminus +S2 600,616,0,0,-142 2 0262 twosuperior +char178 " +S3 600,616,0,0,-143 2 0263 threesuperior +char179 " +aa 600,661,0,58,-263,58 2 0264 acute +char180 " +char181 600,439,142,41,0,41 1 0265 mu +ps 600,580,70,149,-11,75 2 0266 paragraph +char182 " +char183 600,351,0,0,-199 0 0267 periodcentered +ac 600,0,206,0,-119 1 0270 cedilla +char184 " +S1 600,616,0,0,-163 2 0271 onesuperior +char185 " +Om 600,580,0,0,-139 2 0272 ordmasculine +char186 " +fc 600,446,0,0,-116 0 0273 guilsinglright +14 600,661,60,156,36,75 2 0274 onequarter +char188 " +12 600,661,60,165,27,75 2 0275 onehalf +char189 " +34 600,661,60,148,42,75 2 0276 threequarters +char190 " +r? 600,449,146,0,-51 1 0277 questiondown +char191 " +`A 600,784,0,81,59,75 2 0300 Agrave +char192 " +'A 600,784,0,115,59,75 2 0301 Aacute +char193 " +^A 600,780,0,81,59,75 2 0302 Acircumflex +char194 " +~A 600,759,0,88,59,75 2 0303 Atilde +char195 " +:A 600,748,0,81,59,75 2 0304 Adieresis +char196 " +oA 600,801,0,81,59,75 2 0305 Aring +char197 " +AE 600,562,0,157,79,75 2 0306 AE +char198 " +,C 600,580,206,124,-24,75 3 0307 Ccedilla +char199 " +`E 600,784,0,119,25,75 2 0310 Egrave +char200 " +'E 600,784,0,119,25,75 2 0311 Eacute +char201 " +^E 600,780,0,119,25,75 2 0312 Ecircumflex +char202 " +:E 600,748,0,119,25,75 2 0313 Edieresis +char203 " +`I 600,784,0,92,-27,75 2 0314 Igrave +char204 " +'I 600,784,0,92,-27,75 2 0315 Iacute +char205 " +^I 600,780,0,92,-27,75 2 0316 Icircumflex +char206 " +:I 600,748,0,92,-27,75 2 0317 Idieresis +char207 " +-D 600,562,0,114,20,75 2 0320 Eth +char208 " +~N 600,759,12,179,42,75 2 0321 Ntilde +char209 " +`O 600,784,18,95,-24,75 2 0322 Ograve +char210 " +'O 600,784,18,95,-24,75 2 0323 Oacute +char211 " +^O 600,780,18,95,-24,75 2 0324 Ocircumflex +char212 " +~O 600,759,18,118,-24,75 2 0325 Otilde +char213 " +:O 600,748,18,95,-24,75 2 0326 Odieresis +char214 " +char215 600,478,0,56,-55,56 0 0327 multiply +/O 600,584,22,122,2,75 2 0330 Oslash +char216 " +`U 600,784,18,165,-51,75 2 0331 Ugrave +char217 " +'U 600,784,18,165,-51,75 2 0332 Uacute +char218 " +^U 600,780,18,165,-51,75 2 0333 Ucircumflex +char219 " +:U 600,748,18,165,-51,75 2 0334 Udieresis +char220 " +'Y 600,784,0,158,-59,75 2 0335 Yacute +char221 " +TP 600,562,0,69,2,69 2 0336 Thorn +char222 " +ss 600,626,15,78,28,75 2 0337 germandbls +char223 " +`a 600,661,15,42,-12,42 2 0340 agrave +char224 " +'a 600,661,15,58,-12,58 2 0341 aacute +char225 " +^a 600,657,15,42,-12,42 2 0342 acircumflex +char226 " +~a 600,636,15,92,-12,75 2 0343 atilde +char227 " +:a 600,625,15,42,-12,42 2 0344 adieresis +char228 " +oa 600,678,15,42,-12,42 2 0345 aring +char229 " +ae 600,454,15,101,29,75 0 0346 ae +char230 " +,c 600,459,206,81,-31,75 1 0347 ccedilla +char231 " +`e 600,661,15,54,-31,54 2 0350 egrave +char232 " +'e 600,661,15,58,-31,58 2 0351 eacute +char233 " +^e 600,657,15,56,-31,56 2 0352 ecircumflex +char234 " +:e 600,625,15,54,-31,54 2 0353 edieresis +char235 " +`i 600,661,0,0,-27 2 0354 igrave +char236 " +'i 600,661,0,58,-27,58 2 0355 iacute +char237 " +^i 600,657,0,16,-27,16 2 0356 icircumflex +char238 " +:i 600,625,0,2,-27,2 2 0357 idieresis +char239 " +Sd 600,626,27,111,-43,75 2 0360 eth +char240 " +~n 600,636,0,92,32,75 2 0361 ntilde +char241 " +`o 600,661,15,72,-21,72 2 0362 ograve +char242 " +'o 600,661,15,72,-21,72 2 0363 oacute +char243 " +^o 600,657,15,72,-21,72 2 0364 ocircumflex +char244 " +~o 600,636,15,92,-21,75 2 0365 otilde +char245 " +:o 600,625,15,72,-21,72 2 0366 odieresis +char246 " +char247 600,500,0,46,-64,46 0 0367 divide +/o 600,463,24,87,-5,75 0 0370 oslash +char248 " +`u 600,661,15,41,-20,41 2 0371 ugrave +char249 " +'u 600,661,15,58,-20,58 2 0372 uacute +char250 " +^u 600,657,15,41,-20,41 2 0373 ucircumflex +char251 " +:u 600,625,15,41,-20,41 2 0374 udieresis +char252 " +'y 600,661,142,144,70,75 3 0375 yacute +char253 " +Tp 600,626,142,72,81,72 3 0376 thorn +char254 " +:y 600,625,142,144,70,75 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/CI b/gnu/usr.bin/groff/devices/devps/CI new file mode 100644 index 0000000000..f63f1931e1 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/CI @@ -0,0 +1,337 @@ +name CI +internalname Courier-Oblique +slant 12 +spacewidth 600 +encoding text.enc +charset +ha 600,622,0,37,-125,37 2 0000 asciicircum +ti 600,320,0,50,-66,50 0 0001 asciitilde +vS 600,805,20,123,-26,72 2 0002 Scaron +vZ 600,805,0,93,-36,72 2 0003 Zcaron +vs 600,669,15,64,-28,64 2 0004 scaron +vz 600,669,0,74,-49,72 2 0005 zcaron +:Y 600,731,0,145,-83,72 2 0006 Ydieresis +tm 600,562,0,192,-25,72 2 0007 trademark +aq 600,562,0,0,-295 2 0010 quotesingle +space 600 0 0040 +! 600,572,15,0,-193 2 0041 exclam +" 600,562,0,0,-223 2 0042 quotedbl +# 600,639,32,46,-83,46 2 0043 numbersign +sh " +$ 600,662,126,46,-58,46 2 0044 dollar +Do " +% 600,622,15,49,-84,49 2 0045 percent +& 600,543,15,30,-37,30 0 0046 ampersand +' 600,562,0,0,-233 2 0047 quoteright +( 600,622,108,22,-263,22 2 0050 parenleft +) 600,622,108,0,-87 2 0051 parenright +* 600,607,0,30,-162,30 2 0052 asterisk ++ 600,470,0,30,-79,30 0 0053 plus +, 600,122,112,0,-107 0 0054 comma +- 600,285,0,8,-102,8 0 0055 hyphen +hy " +char173 " +. 600,109,15,0,-188 0 0056 period +/ 600,629,80,54,-62,54 2 0057 slash +sl " +0 600,622,15,25,-104,25 2 0060 zero +1 600,622,0,0,-48 2 0061 one +2 600,622,0,18,-20,18 2 0062 two +3 600,622,15,0,-32 2 0063 three +4 600,622,0,0,-58 2 0064 four +5 600,607,15,39,-49,39 2 0065 five +6 600,622,15,79,-105,72 2 0066 six +7 600,607,0,62,-132,62 2 0067 seven +8 600,622,15,38,-82,38 2 0070 eight +9 600,622,15,24,-43,24 2 0071 nine +: 600,385,15,0,-188 0 0072 colon +; 600,385,112,0,-107 0 0073 semicolon +< 600,472,0,60,-46,60 0 0074 less += 600,376,0,50,-59,50 0 0075 equal +> 600,472,0,49,-35,49 0 0076 greater +? 600,572,15,33,-172,33 2 0077 question +@ 600,622,15,32,-77,32 2 0100 at +at " +A 600,562,0,57,47,57 2 0101 A +B 600,562,0,66,7,66 2 0102 B +C 600,580,18,105,-43,72 2 0103 C +D 600,562,0,95,7,72 2 0104 D +E 600,562,0,110,-3,72 2 0105 E +F 600,562,0,110,-3,72 2 0106 F +G 600,580,18,95,-33,72 2 0107 G +H 600,562,0,137,18,72 2 0110 H +I 600,562,0,73,-46,72 2 0111 I +J 600,562,18,135,-2,72 2 0112 J +K 600,562,0,121,12,72 2 0113 K +L 600,562,0,57,3,57 2 0114 L +M 600,562,0,165,46,72 2 0115 M +N 600,562,13,162,43,72 2 0116 N +O 600,580,18,75,-44,72 2 0117 O +P 600,562,0,94,-29,72 2 0120 P +Q 600,580,138,75,-45,72 2 0121 Q +R 600,562,0,48,12,48 2 0122 R +S 600,580,20,100,-26,72 2 0123 S +T 600,562,0,115,-58,72 2 0124 T +U 600,562,18,152,-75,72 2 0125 U +V 600,562,13,173,-55,72 2 0126 V +W 600,562,13,172,-56,72 2 0127 W +X 600,562,0,125,27,72 2 0130 X +Y 600,562,0,145,-83,72 2 0131 Y +Z 600,562,0,60,-36,60 2 0132 Z +[ 600,622,108,24,-196,24 2 0133 bracketleft +lB " +\ 600,629,80,0,-199 2 0134 backslash +rs " +] 600,622,108,0,-85 2 0135 bracketright +rB " +a^ 600,654,0,31,-179,31 2 0136 circumflex +^ " +_ 600,0,125,34,77,34 0 0137 underscore +` 600,562,0,0,-293 2 0140 quoteleft +oq " +a 600,441,15,19,-26,19 0 0141 a +b 600,629,15,75,21,72 2 0142 b +c 600,441,15,58,-56,58 0 0143 c +d 600,629,15,90,-35,72 2 0144 d +e 600,441,15,48,-56,48 0 0145 e +f 600,629,0,112,-64,72 2 0146 f +g 600,441,157,107,-11,72 1 0147 g +h 600,629,0,42,17,42 2 0150 h +i 600,657,0,0,-45 2 0151 i +j 600,657,157,0,-2 3 0152 j +k 600,629,0,83,-8,72 2 0153 k +l 600,629,0,0,-45 2 0154 l +m 600,441,0,65,55,65 0 0155 m +n 600,441,0,35,24,35 0 0156 n +o 600,441,15,38,-52,38 0 0157 o +p 600,441,157,55,74,55 1 0160 p +q 600,441,157,132,-35,72 1 0161 q +r 600,441,0,86,-10,72 0 0162 r +s 600,441,15,34,-28,34 0 0163 s +t 600,561,15,11,-117,11 2 0164 t +u 600,426,15,22,-51,22 0 0165 u +v 600,426,10,131,-40,72 0 0166 v +w 600,426,10,145,-26,72 0 0167 w +x 600,426,0,105,30,72 0 0170 x +y 600,426,157,133,54,72 1 0171 y +z 600,426,0,43,-49,43 0 0172 z +lC 600,622,108,19,-183,19 2 0173 braceleft +{ " +ba 600,750,250,0,-172 3 0174 bar +| " +rC 600,622,108,0,-90 2 0175 braceright +} " +a~ 600,606,0,79,-162,72 2 0176 tilde +~ " +bq 600,100,134,0,-135 0 0200 quotesinglbase +Fo 600,446,0,102,-42,72 0 0201 guillemotleft +char171 " +Fc 600,446,0,68,-8,68 0 0202 guillemotright +char187 " +bu 600,383,0,0,-174 0 0203 bullet +Fn 600,622,143,121,76,72 2 0204 florin +f/ 600,665,57,96,-34,72 2 0205 fraction +%0 600,622,15,77,-9,72 2 0206 perthousand +dg 600,580,78,0,-167 2 0207 dagger +dd 600,580,78,0,-113 2 0210 daggerdbl +en 600,285,0,36,-74,36 0 0211 endash +em 600,285,0,111,1,72 0 0212 emdash +fi 600,629,0,69,47,69 2 0214 fi +fl 600,629,0,69,47,69 2 0215 fl +.i 600,426,0,0,-45 0 0220 dotlessi +ga 600,672,0,0,-244 2 0222 grave +a" 600,672,0,133,-189,72 2 0223 hungarumlaut +a. 600,580,0,0,-310 2 0224 dotaccent +ab 600,609,0,26,-229,26 2 0225 breve +ah 600,669,0,64,-212,64 2 0226 caron +ao 600,627,0,0,-282 2 0227 ring +ho 600,0,151,0,-157 0 0230 ogonek +lq 600,562,0,0,-212 2 0231 quotedblleft +rq 600,562,0,26,-163,26 2 0232 quotedblright +oe 600,441,15,65,-4,65 0 0233 oe +/l 600,629,0,33,-45,33 2 0234 lslash +Bq 600,100,134,0,-65 0 0235 quotedblbase +OE 600,562,0,122,-9,72 2 0236 OE +/L 600,562,0,57,3,57 2 0237 Lslash +r! 600,430,157,0,-175 1 0241 exclamdown +char161 " +ct 600,614,49,38,-101,38 2 0242 cent +char162 " +Po 600,611,21,71,-74,71 2 0243 sterling +char163 " +Cs 600,506,0,78,-44,72 0 0244 currency +char164 " +Ye 600,562,0,143,-70,72 2 0245 yen +char165 " +bb 600,675,175,0,-188 3 0246 brokenbar +char166 " +sc 600,580,78,40,-54,40 2 0247 section +char167 " +ad 600,595,0,20,-212,20 2 0250 dieresis +char168 " +co 600,580,18,117,-3,72 2 0251 copyright +char169 " +Of 600,580,0,0,-159 2 0252 ordfeminine +char170 " +fo 600,446,0,0,-154 0 0253 guilsinglleft +no 600,369,0,41,-105,41 0 0254 logicalnot +char172 " +\- 600,283,0,30,-79,30 0 0255 minus +rg 600,580,18,117,-3,72 2 0256 registered +char174 " +a- 600,565,0,50,-182,50 2 0257 macron +char175 " +de 600,622,0,26,-164,26 2 0260 degree +char176 " +char177 600,558,0,44,-46,44 0 0261 plusminus +S2 600,622,0,0,-180 2 0262 twosuperior +char178 " +S3 600,622,0,0,-163 2 0263 threesuperior +char179 " +aa 600,672,0,62,-298,62 2 0264 acute +char180 " +char181 600,426,157,22,-22,22 1 0265 mu +ps 600,562,78,80,-50,72 2 0266 paragraph +char182 " +char183 600,327,0,0,-225 0 0267 periodcentered +ac 600,10,151,0,-147 0 0270 cedilla +char184 " +S1 600,622,0,0,-181 2 0271 onesuperior +char185 " +Om 600,580,0,0,-160 2 0272 ordmasculine +char186 " +fc 600,446,0,0,-120 0 0273 guilsinglright +14 600,665,57,124,-15,72 2 0274 onequarter +char188 " +12 600,665,57,119,-15,72 2 0275 onehalf +char189 " +34 600,666,56,109,-23,72 2 0276 threequarters +char190 " +r? 600,430,157,0,-55 1 0277 questiondown +char191 " +`A 600,793,0,57,47,57 2 0300 Agrave +char192 " +'A 600,793,0,108,47,72 2 0301 Aacute +char193 " +^A 600,775,0,57,47,57 2 0302 Acircumflex +char194 " +~A 600,732,0,106,47,72 2 0303 Atilde +char195 " +:A 600,731,0,57,47,57 2 0304 Adieresis +char196 " +oA 600,753,0,57,47,57 2 0305 Aring +char197 " +AE 600,562,0,105,47,72 2 0306 AE +char198 " +,C 600,580,151,108,-43,72 2 0307 Ccedilla +char199 " +`E 600,793,0,110,-3,72 2 0310 Egrave +char200 " +'E 600,793,0,118,-3,72 2 0311 Eacute +char201 " +^E 600,775,0,110,-3,72 2 0312 Ecircumflex +char202 " +:E 600,731,0,110,-3,72 2 0313 Edieresis +char203 " +`I 600,793,0,73,-46,72 2 0314 Igrave +char204 " +'I 600,793,0,88,-46,72 2 0315 Iacute +char205 " +^I 600,775,0,73,-46,72 2 0316 Icircumflex +char206 " +:I 600,731,0,73,-46,72 2 0317 Idieresis +char207 " +-D 600,562,0,95,7,72 2 0320 Eth +char208 " +~N 600,732,13,162,43,72 2 0321 Ntilde +char209 " +`O 600,793,18,75,-44,72 2 0322 Ograve +char210 " +'O 600,793,18,88,-44,72 2 0323 Oacute +char211 " +^O 600,775,18,75,-44,72 2 0324 Ocircumflex +char212 " +~O 600,732,18,106,-44,72 2 0325 Otilde +char213 " +:O 600,731,18,75,-44,72 2 0326 Odieresis +char214 " +char215 600,470,0,57,-53,57 0 0327 multiply +/O 600,629,80,75,-44,72 2 0330 Oslash +char216 " +`U 600,793,18,152,-75,72 2 0331 Ugrave +char217 " +'U 600,793,18,152,-75,72 2 0332 Uacute +char218 " +^U 600,775,18,152,-75,72 2 0333 Ucircumflex +char219 " +:U 600,731,18,152,-75,72 2 0334 Udieresis +char220 " +'Y 600,793,0,145,-83,72 2 0335 Yacute +char221 " +TP 600,562,0,56,-29,56 2 0336 Thorn +char222 " +ss 600,629,15,67,2,67 2 0337 germandbls +char223 " +`a 600,672,15,19,-26,19 2 0340 agrave +char224 " +'a 600,672,15,62,-26,62 2 0341 aacute +char225 " +^a 600,654,15,31,-26,31 2 0342 acircumflex +char226 " +~a 600,606,15,79,-26,72 2 0343 atilde +char227 " +:a 600,595,15,20,-26,20 2 0344 adieresis +char228 " +oa 600,627,15,19,-26,19 2 0345 aring +char229 " +ae 600,441,15,76,9,72 0 0346 ae +char230 " +,c 600,441,151,64,-56,64 0 0347 ccedilla +char231 " +`e 600,672,15,48,-56,48 2 0350 egrave +char232 " +'e 600,672,15,62,-56,62 2 0351 eacute +char233 " +^e 600,654,15,48,-56,48 2 0352 ecircumflex +char234 " +:e 600,595,15,48,-56,48 2 0353 edieresis +char235 " +`i 600,672,0,0,-45 2 0354 igrave +char236 " +'i 600,672,0,62,-45,62 2 0355 iacute +char237 " +^i 600,654,0,1,-45,1 2 0356 icircumflex +char238 " +:i 600,595,0,0,-45 2 0357 idieresis +char239 " +Sd 600,629,15,89,-52,72 2 0360 eth +char240 " +~n 600,606,0,79,24,72 2 0361 ntilde +char241 " +`o 600,672,15,38,-52,38 2 0362 ograve +char242 " +'o 600,672,15,62,-52,62 2 0363 oacute +char243 " +^o 600,654,15,38,-52,38 2 0364 ocircumflex +char244 " +~o 600,606,15,79,-52,72 2 0365 otilde +char245 " +:o 600,595,15,38,-52,38 2 0366 odieresis +char246 " +char247 600,467,0,23,-86,23 0 0367 divide +/o 600,506,80,38,-52,38 0 0370 oslash +char248 " +`u 600,672,15,22,-51,22 2 0371 ugrave +char249 " +'u 600,672,15,52,-51,52 2 0372 uacute +char250 " +^u 600,654,15,22,-51,22 2 0373 ucircumflex +char251 " +:u 600,595,15,22,-51,22 2 0374 udieresis +char252 " +'y 600,672,157,133,54,72 3 0375 yacute +char253 " +Tp 600,629,157,55,74,55 3 0376 thorn +char254 " +:y 600,595,157,133,54,72 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/CR b/gnu/usr.bin/groff/devices/devps/CR new file mode 100644 index 0000000000..c6a92a16d9 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/CR @@ -0,0 +1,336 @@ +name CR +internalname Courier +spacewidth 600 +encoding text.enc +charset +ha 600,622 2 0000 asciicircum +ti 600,320 0 0001 asciitilde +vS 600,805,20 2 0002 Scaron +vZ 600,805 2 0003 Zcaron +vs 600,669,15 2 0004 scaron +vz 600,669 2 0005 zcaron +:Y 600,731 2 0006 Ydieresis +tm 600,562 2 0007 trademark +aq 600,562 2 0010 quotesingle +space 600 0 0040 +! 600,572,15 2 0041 exclam +" 600,562 2 0042 quotedbl +# 600,639,32 2 0043 numbersign +sh " +$ 600,662,126 2 0044 dollar +Do " +% 600,622,15 2 0045 percent +& 600,543,15 0 0046 ampersand +' 600,562 2 0047 quoteright +( 600,622,108 2 0050 parenleft +) 600,622,108 2 0051 parenright +* 600,607 2 0052 asterisk ++ 600,470 0 0053 plus +, 600,122,112 0 0054 comma +- 600,285 0 0055 hyphen +hy " +char173 " +. 600,109,15 0 0056 period +/ 600,629,80 2 0057 slash +sl " +0 600,622,15 2 0060 zero +1 600,622 2 0061 one +2 600,622 2 0062 two +3 600,622,15 2 0063 three +4 600,622 2 0064 four +5 600,607,15 2 0065 five +6 600,622,15 2 0066 six +7 600,607 2 0067 seven +8 600,622,15 2 0070 eight +9 600,622,15 2 0071 nine +: 600,385,15 0 0072 colon +; 600,385,112 0 0073 semicolon +< 600,472 0 0074 less += 600,376 0 0075 equal +> 600,472 0 0076 greater +? 600,572,15 2 0077 question +@ 600,622,15 2 0100 at +at " +A 600,562 2 0101 A +B 600,562 2 0102 B +C 600,580,18 2 0103 C +D 600,562 2 0104 D +E 600,562 2 0105 E +F 600,562 2 0106 F +G 600,580,18 2 0107 G +H 600,562 2 0110 H +I 600,562 2 0111 I +J 600,562,18 2 0112 J +K 600,562 2 0113 K +L 600,562 2 0114 L +M 600,562 2 0115 M +N 600,562,13 2 0116 N +O 600,580,18 2 0117 O +P 600,562 2 0120 P +Q 600,580,138 2 0121 Q +R 600,562 2 0122 R +S 600,580,20 2 0123 S +T 600,562 2 0124 T +U 600,562,18 2 0125 U +V 600,562,13 2 0126 V +W 600,562,13 2 0127 W +X 600,562 2 0130 X +Y 600,562 2 0131 Y +Z 600,562 2 0132 Z +[ 600,622,108 2 0133 bracketleft +lB " +\ 600,629,80 2 0134 backslash +rs " +] 600,622,108 2 0135 bracketright +rB " +a^ 600,654 2 0136 circumflex +^ " +_ 600,0,125 0 0137 underscore +` 600,562 2 0140 quoteleft +oq " +a 600,441,15 0 0141 a +b 600,629,15 2 0142 b +c 600,441,15 0 0143 c +d 600,629,15 2 0144 d +e 600,441,15 0 0145 e +f 600,629 2 0146 f +g 600,441,157 1 0147 g +h 600,629 2 0150 h +i 600,657 2 0151 i +j 600,657,157 3 0152 j +k 600,629 2 0153 k +l 600,629 2 0154 l +m 600,441 0 0155 m +n 600,441 0 0156 n +o 600,441,15 0 0157 o +p 600,441,157 1 0160 p +q 600,441,157 1 0161 q +r 600,441 0 0162 r +s 600,441,15 0 0163 s +t 600,561,15 2 0164 t +u 600,426,15 0 0165 u +v 600,426,10 0 0166 v +w 600,426,10 0 0167 w +x 600,426 0 0170 x +y 600,426,157 1 0171 y +z 600,426 0 0172 z +lC 600,622,108 2 0173 braceleft +{ " +ba 600,750,250 3 0174 bar +| " +rC 600,622,108 2 0175 braceright +} " +a~ 600,606 2 0176 tilde +~ " +bq 600,100,134 0 0200 quotesinglbase +Fo 600,446 0 0201 guillemotleft +char171 " +Fc 600,446 0 0202 guillemotright +char187 " +bu 600,383 0 0203 bullet +Fn 600,622,143 2 0204 florin +f/ 600,665,57 2 0205 fraction +%0 600,622,15 2 0206 perthousand +dg 600,580,78 2 0207 dagger +dd 600,580,78 2 0210 daggerdbl +en 600,285 0 0211 endash +em 600,285 0 0212 emdash +fi 600,629 2 0214 fi +fl 600,629 2 0215 fl +.i 600,426 0 0220 dotlessi +ga 600,672 2 0222 grave +a" 600,672 2 0223 hungarumlaut +a. 600,580 2 0224 dotaccent +ab 600,609 2 0225 breve +ah 600,669 2 0226 caron +ao 600,627 2 0227 ring +ho 600,0,151 0 0230 ogonek +lq 600,562 2 0231 quotedblleft +rq 600,562 2 0232 quotedblright +oe 600,441,15 0 0233 oe +/l 600,629 2 0234 lslash +Bq 600,100,134 0 0235 quotedblbase +OE 600,562 2 0236 OE +/L 600,562 2 0237 Lslash +r! 600,430,157 1 0241 exclamdown +char161 " +ct 600,614,49 2 0242 cent +char162 " +Po 600,611,21 2 0243 sterling +char163 " +Cs 600,506 0 0244 currency +char164 " +Ye 600,562 2 0245 yen +char165 " +bb 600,675,175 3 0246 brokenbar +char166 " +sc 600,580,78 2 0247 section +char167 " +ad 600,595 2 0250 dieresis +char168 " +co 600,580,18 2 0251 copyright +char169 " +Of 600,580 2 0252 ordfeminine +char170 " +fo 600,446 0 0253 guilsinglleft +no 600,369 0 0254 logicalnot +char172 " +\- 600,283 0 0255 minus +rg 600,580,18 2 0256 registered +char174 " +a- 600,565 2 0257 macron +char175 " +de 600,622 2 0260 degree +char176 " +char177 600,558 0 0261 plusminus +S2 600,622 2 0262 twosuperior +char178 " +S3 600,622 2 0263 threesuperior +char179 " +aa 600,672 2 0264 acute +char180 " +char181 600,426,157 1 0265 mu +ps 600,562,78 2 0266 paragraph +char182 " +char183 600,327 0 0267 periodcentered +ac 600,10,151 0 0270 cedilla +char184 " +S1 600,622 2 0271 onesuperior +char185 " +Om 600,580 2 0272 ordmasculine +char186 " +fc 600,446 0 0273 guilsinglright +14 600,665,57 2 0274 onequarter +char188 " +12 600,665,57 2 0275 onehalf +char189 " +34 600,666,56 2 0276 threequarters +char190 " +r? 600,430,157 1 0277 questiondown +char191 " +`A 600,793 2 0300 Agrave +char192 " +'A 600,793 2 0301 Aacute +char193 " +^A 600,775 2 0302 Acircumflex +char194 " +~A 600,732 2 0303 Atilde +char195 " +:A 600,731 2 0304 Adieresis +char196 " +oA 600,753 2 0305 Aring +char197 " +AE 600,562 2 0306 AE +char198 " +,C 600,580,151 2 0307 Ccedilla +char199 " +`E 600,793 2 0310 Egrave +char200 " +'E 600,793 2 0311 Eacute +char201 " +^E 600,775 2 0312 Ecircumflex +char202 " +:E 600,731 2 0313 Edieresis +char203 " +`I 600,793 2 0314 Igrave +char204 " +'I 600,793 2 0315 Iacute +char205 " +^I 600,775 2 0316 Icircumflex +char206 " +:I 600,731 2 0317 Idieresis +char207 " +-D 600,562 2 0320 Eth +char208 " +~N 600,732,13 2 0321 Ntilde +char209 " +`O 600,793,18 2 0322 Ograve +char210 " +'O 600,793,18 2 0323 Oacute +char211 " +^O 600,775,18 2 0324 Ocircumflex +char212 " +~O 600,732,18 2 0325 Otilde +char213 " +:O 600,731,18 2 0326 Odieresis +char214 " +char215 600,470 0 0327 multiply +/O 600,629,80 2 0330 Oslash +char216 " +`U 600,793,18 2 0331 Ugrave +char217 " +'U 600,793,18 2 0332 Uacute +char218 " +^U 600,775,18 2 0333 Ucircumflex +char219 " +:U 600,731,18 2 0334 Udieresis +char220 " +'Y 600,793 2 0335 Yacute +char221 " +TP 600,562 2 0336 Thorn +char222 " +ss 600,629,15 2 0337 germandbls +char223 " +`a 600,672,15 2 0340 agrave +char224 " +'a 600,672,15 2 0341 aacute +char225 " +^a 600,654,15 2 0342 acircumflex +char226 " +~a 600,606,15 2 0343 atilde +char227 " +:a 600,595,15 2 0344 adieresis +char228 " +oa 600,627,15 2 0345 aring +char229 " +ae 600,441,15 0 0346 ae +char230 " +,c 600,441,151 0 0347 ccedilla +char231 " +`e 600,672,15 2 0350 egrave +char232 " +'e 600,672,15 2 0351 eacute +char233 " +^e 600,654,15 2 0352 ecircumflex +char234 " +:e 600,595,15 2 0353 edieresis +char235 " +`i 600,672 2 0354 igrave +char236 " +'i 600,672 2 0355 iacute +char237 " +^i 600,654 2 0356 icircumflex +char238 " +:i 600,595 2 0357 idieresis +char239 " +Sd 600,629,15 2 0360 eth +char240 " +~n 600,606 2 0361 ntilde +char241 " +`o 600,672,15 2 0362 ograve +char242 " +'o 600,672,15 2 0363 oacute +char243 " +^o 600,654,15 2 0364 ocircumflex +char244 " +~o 600,606,15 2 0365 otilde +char245 " +:o 600,595,15 2 0366 odieresis +char246 " +char247 600,467 0 0367 divide +/o 600,506,80 0 0370 oslash +char248 " +`u 600,672,15 2 0371 ugrave +char249 " +'u 600,672,15 2 0372 uacute +char250 " +^u 600,654,15 2 0373 ucircumflex +char251 " +:u 600,595,15 2 0374 udieresis +char252 " +'y 600,672,157 3 0375 yacute +char253 " +Tp 600,629,157 3 0376 thorn +char254 " +:y 600,595,157 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/DESC b/gnu/usr.bin/groff/devices/devps/DESC new file mode 100644 index 0000000000..1aba05961e --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/DESC @@ -0,0 +1,14 @@ +res 72000 +hor 1 +vert 1 +sizescale 1000 +unitwidth 1000 +sizes 1000-10000000 0 +styles R I B BI +family T +fonts 9 0 0 0 0 0 SS S ZD ZDR +tcommand +postpro grops +broken 0 +paperlength 792000 +print lpr diff --git a/gnu/usr.bin/groff/devices/devps/DESC-A4 b/gnu/usr.bin/groff/devices/devps/DESC-A4 new file mode 100644 index 0000000000..9e842c94de --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/DESC-A4 @@ -0,0 +1,14 @@ +res 72000 +hor 1 +vert 1 +sizescale 1000 +unitwidth 1000 +sizes 1000-10000000 0 +styles R I B BI +family T +fonts 9 0 0 0 0 0 SS S ZD ZDR +tcommand +postpro grops +broken 0 +paperlength 841890 +print lpr diff --git a/gnu/usr.bin/groff/devices/devps/DESC-letter b/gnu/usr.bin/groff/devices/devps/DESC-letter new file mode 100644 index 0000000000..1aba05961e --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/DESC-letter @@ -0,0 +1,14 @@ +res 72000 +hor 1 +vert 1 +sizescale 1000 +unitwidth 1000 +sizes 1000-10000000 0 +styles R I B BI +family T +fonts 9 0 0 0 0 0 SS S ZD ZDR +tcommand +postpro grops +broken 0 +paperlength 792000 +print lpr diff --git a/gnu/usr.bin/groff/devices/devps/HB b/gnu/usr.bin/groff/devices/devps/HB new file mode 100644 index 0000000000..8c2ed083a3 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/HB @@ -0,0 +1,546 @@ +name HB +internalname Helvetica-Bold +spacewidth 278 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -30 +A w -30 +A v -40 +A u -30 +A Y -110 +A W -60 +A V -80 +A U -50 +A T -90 +A Q -40 +A O -40 +A G -50 +A C -40 +B U -10 +B A -30 +D . -30 +D , -30 +D Y -70 +D W -40 +D V -40 +D A -40 +F . -100 +F , -100 +F a -20 +F A -80 +J u -20 +J . -20 +J , -20 +J A -20 +K y -40 +K u -30 +K o -35 +K e -15 +K O -30 +L y -30 +L ' -140 +L rq -140 +L Y -120 +L W -80 +L V -110 +L T -90 +O . -40 +O , -40 +O Y -70 +O X -50 +O W -50 +O V -50 +O T -40 +O A -50 +P . -120 +P o -40 +P e -30 +P , -120 +P a -30 +P A -100 +Q . 20 +Q , 20 +Q U -10 +R Y -50 +R W -40 +R V -50 +R U -20 +R T -20 +R O -20 +T y -60 +T w -60 +T u -90 +T ; -40 +T r -80 +T . -80 +T o -80 +T - -120 +T hy -120 +T char173 -120 +T e -60 +T , -80 +T : -40 +T a -80 +T O -40 +T A -90 +U . -30 +U , -30 +U A -50 +V u -60 +V ; -40 +V . -120 +V o -90 +V - -80 +V hy -80 +V char173 -80 +V e -50 +V , -120 +V : -40 +V a -60 +V O -50 +V G -50 +V A -80 +W y -20 +W u -45 +W ; -10 +W . -80 +W o -60 +W - -40 +W hy -40 +W char173 -40 +W e -35 +W , -80 +W : -10 +W a -40 +W O -20 +W A -60 +Y u -100 +Y ; -50 +Y . -100 +Y o -100 +Y e -80 +Y , -100 +Y : -50 +Y a -90 +Y O -70 +Y A -110 +a y -20 +a w -15 +a v -15 +a g -10 +b y -20 +b v -20 +b u -20 +b l -10 +c y -10 +c l -20 +c k -20 +c h -10 +, ' -120 +, rq -120 +d y -15 +d w -15 +d v -15 +d d -10 +e y -15 +e x -15 +e w -15 +e v -15 +e . 20 +e , 10 +f ' 30 +f rq 30 +f . -10 +f o -20 +f e -10 +f , -10 +g g -10 +g e 10 +h y -20 +k o -15 +l y -15 +l w -15 +m y -30 +m u -20 +n y -20 +n v -40 +n u -10 +o y -20 +o x -30 +o w -15 +o v -20 +p y -15 +. ' -120 +. rq -120 +` ` -46 +` oq -46 +oq ` -46 +oq oq -46 +' v -20 +' s -60 +' r -40 +' ' -46 +' l -20 +' d -80 +r y 10 +r v 10 +r t 20 +r s -15 +r q -20 +r . -60 +r o -20 +r - -20 +r hy -20 +r char173 -20 +r g -15 +r d -20 +r , -60 +r c -20 +s w -15 +v . -80 +v o -30 +v , -80 +v a -20 +w . -40 +w o -20 +w , -40 +x e -10 +y . -80 +y o -25 +y e -10 +y , -80 +y a -30 +z e 10 +charset +ha 584,698 2 0000 asciicircum +ti 584,343 0 0001 asciitilde +vS 667,936,19 2 0002 Scaron +vZ 611,936 2 0003 Zcaron +vs 556,750,14 2 0004 scaron +vz 500,750 2 0005 zcaron +:Y 667,915 2 0006 Ydieresis +tm 1000,718 2 0007 trademark +aq 238,718 2 0010 quotesingle +space 278 0 0040 +! 333,718 2 0041 exclam +" 474,718 2 0042 quotedbl +# 556,698 2 0043 numbersign +sh " +$ 556,775,115 2 0044 dollar +Do " +% 889,710,19 2 0045 percent +& 722,718,19 2 0046 ampersand +' 278,718 2 0047 quoteright +( 333,734,208 3 0050 parenleft +) 333,734,208 3 0051 parenright +* 389,718 2 0052 asterisk ++ 584,506 0 0053 plus +, 278,146,168 0 0054 comma +- 333,345 0 0055 hyphen +hy " +char173 " +. 278,146 0 0056 period +/ 278,737,19 2 0057 slash +sl " +0 556,710,19 2 0060 zero +1 556,710 2 0061 one +2 556,710 2 0062 two +3 556,710,19 2 0063 three +4 556,710 2 0064 four +5 556,698,19 2 0065 five +6 556,710,19 2 0066 six +7 556,698 2 0067 seven +8 556,710,19 2 0070 eight +9 556,710,19 2 0071 nine +: 333,512 0 0072 colon +; 333,512,168 0 0073 semicolon +< 584,514,8 0 0074 less += 584,419 0 0075 equal +> 584,514,8 0 0076 greater +? 611,727 2 0077 question +@ 975,737,19 2 0100 at +at " +A 722,718 2 0101 A +B 722,718 2 0102 B +C 722,737,19 2 0103 C +D 722,718 2 0104 D +E 667,718 2 0105 E +F 611,718 2 0106 F +G 778,737,19 2 0107 G +H 722,718 2 0110 H +I 278,718 2 0111 I +J 556,718,18 2 0112 J +K 722,718 2 0113 K +L 611,718 2 0114 L +M 833,718 2 0115 M +N 722,718 2 0116 N +O 778,737,19 2 0117 O +P 667,718 2 0120 P +Q 778,737,52 2 0121 Q +R 722,718 2 0122 R +S 667,737,19 2 0123 S +T 611,718 2 0124 T +U 722,718,19 2 0125 U +V 667,718 2 0126 V +W 944,718 2 0127 W +X 667,718 2 0130 X +Y 667,718 2 0131 Y +Z 611,718 2 0132 Z +[ 333,722,196 2 0133 bracketleft +lB " +\ 278,737,19 2 0134 backslash +rs " +] 333,722,196 2 0135 bracketright +rB " +a^ 333,750 2 0136 circumflex +^ " +_ 556,0,125 0 0137 underscore +` 278,727 2 0140 quoteleft +oq " +a 556,546,14 0 0141 a +b 611,718,14 2 0142 b +c 556,546,14 0 0143 c +d 611,718,14 2 0144 d +e 556,546,14 0 0145 e +f 333,727 2 0146 f +g 611,546,217 1 0147 g +h 611,718 2 0150 h +i 278,725 2 0151 i +j 278,725,214 3 0152 j +k 556,718 2 0153 k +l 278,718 2 0154 l +m 889,546 0 0155 m +n 611,546 0 0156 n +o 611,546,14 0 0157 o +p 611,546,207 1 0160 p +q 611,546,207 1 0161 q +r 389,546 0 0162 r +s 556,546,14 0 0163 s +t 333,676,6 2 0164 t +u 611,532,14 0 0165 u +v 556,532 0 0166 v +w 778,532 0 0167 w +x 556,532 0 0170 x +y 556,532,214 1 0171 y +z 500,532 0 0172 z +lC 389,722,196 2 0173 braceleft +{ " +ba 280,737,19 2 0174 bar +| " +rC 389,722,196 2 0175 braceright +} " +a~ 333,737 2 0176 tilde +~ " +bq 278,127,146 0 0200 quotesinglbase +Fo 556,484 0 0201 guillemotleft +char171 " +Fc 556,484 0 0202 guillemotright +char187 " +bu 350,524 0 0203 bullet +Fn 556,737,210 3 0204 florin +f/ 167,710,19 2 0205 fraction +%0 1000,710,19 2 0206 perthousand +dg 556,718,171 2 0207 dagger +dd 556,718,171 2 0210 daggerdbl +en 556,333 0 0211 endash +em 1000,333 0 0212 emdash +fi 611,727 2 0214 fi +fl 611,727 2 0215 fl +.i 278,532 0 0220 dotlessi +ga 333,750 2 0222 grave +a" 333,750 2 0223 hungarumlaut +a. 333,729 2 0224 dotaccent +ab 333,750 2 0225 breve +ah 333,750 2 0226 caron +ao 333,776 2 0227 ring +ho 333,0,228 1 0230 ogonek +lq 500,727 2 0231 quotedblleft +rq 500,718 2 0232 quotedblright +oe 944,546,14 0 0233 oe +/l 278,718 2 0234 lslash +Bq 500,127,146 0 0235 quotedblbase +OE 1000,737,19 2 0236 OE +/L 611,718 2 0237 Lslash +r! 333,532,186 0 0241 exclamdown +char161 " +ct 556,628,118 0 0242 cent +char162 " +Po 556,718,16 2 0243 sterling +char163 " +Cs 556,636 0 0244 currency +char164 " +Ye 556,698 2 0245 yen +char165 " +bb 280,737,19 2 0246 brokenbar +char166 " +sc 556,727,184 2 0247 section +char167 " +ad 333,729 2 0250 dieresis +char168 " +co 737,737,19 2 0251 copyright +char169 " +Of 370,737 2 0252 ordfeminine +char170 " +fo 333,484 0 0253 guilsinglleft +no 584,419 0 0254 logicalnot +char172 " +\- 584,309 0 0255 minus +rg 737,737,19 2 0256 registered +char174 " +a- 333,678 2 0257 macron +char175 " +de 400,712 2 0260 degree +char176 " +char177 584,506 0 0261 plusminus +S2 333,710 2 0262 twosuperior +char178 " +S3 333,710 2 0263 threesuperior +char179 " +aa 333,750 2 0264 acute +char180 " +char181 611,532,207 1 0265 mu +ps 556,700,191 2 0266 paragraph +char182 " +char183 278,334 0 0267 periodcentered +ac 333,0,228 1 0270 cedilla +char184 " +S1 333,710 2 0271 onesuperior +char185 " +Om 365,737 2 0272 ordmasculine +char186 " +fc 333,484 0 0273 guilsinglright +14 834,710,19 2 0274 onequarter +char188 " +12 834,710,19 2 0275 onehalf +char189 " +34 834,710,19 2 0276 threequarters +char190 " +r? 611,532,195 0 0277 questiondown +char191 " +`A 722,936 2 0300 Agrave +char192 " +'A 722,936 2 0301 Aacute +char193 " +^A 722,936 2 0302 Acircumflex +char194 " +~A 722,923 2 0303 Atilde +char195 " +:A 722,915 2 0304 Adieresis +char196 " +oA 722,962 2 0305 Aring +char197 " +AE 1000,718 2 0306 AE +char198 " +,C 722,737,228 3 0307 Ccedilla +char199 " +`E 667,936 2 0310 Egrave +char200 " +'E 667,936 2 0311 Eacute +char201 " +^E 667,936 2 0312 Ecircumflex +char202 " +:E 667,915 2 0313 Edieresis +char203 " +`I 278,936 2 0314 Igrave +char204 " +'I 278,936 2 0315 Iacute +char205 " +^I 278,936 2 0316 Icircumflex +char206 " +:I 278,915 2 0317 Idieresis +char207 " +-D 722,718 2 0320 Eth +char208 " +~N 722,923 2 0321 Ntilde +char209 " +`O 778,936,19 2 0322 Ograve +char210 " +'O 778,936,19 2 0323 Oacute +char211 " +^O 778,936,19 2 0324 Ocircumflex +char212 " +~O 778,923,19 2 0325 Otilde +char213 " +:O 778,915,19 2 0326 Odieresis +char214 " +char215 584,505 0 0327 multiply +/O 778,745,27 2 0330 Oslash +char216 " +`U 722,936,19 2 0331 Ugrave +char217 " +'U 722,936,19 2 0332 Uacute +char218 " +^U 722,936,19 2 0333 Ucircumflex +char219 " +:U 722,915,19 2 0334 Udieresis +char220 " +'Y 667,936 2 0335 Yacute +char221 " +TP 667,718 2 0336 Thorn +char222 " +ss 611,731,14 2 0337 germandbls +char223 " +`a 556,750,14 2 0340 agrave +char224 " +'a 556,750,14 2 0341 aacute +char225 " +^a 556,750,14 2 0342 acircumflex +char226 " +~a 556,737,14 2 0343 atilde +char227 " +:a 556,729,14 2 0344 adieresis +char228 " +oa 556,776,14 2 0345 aring +char229 " +ae 889,546,14 0 0346 ae +char230 " +,c 556,546,228 1 0347 ccedilla +char231 " +`e 556,750,14 2 0350 egrave +char232 " +'e 556,750,14 2 0351 eacute +char233 " +^e 556,750,14 2 0352 ecircumflex +char234 " +:e 556,729,14 2 0353 edieresis +char235 " +`i 278,750 2 0354 igrave +char236 " +'i 278,750 2 0355 iacute +char237 " +^i 278,750 2 0356 icircumflex +char238 " +:i 278,729 2 0357 idieresis +char239 " +Sd 611,737,14 2 0360 eth +char240 " +~n 611,737 2 0361 ntilde +char241 " +`o 611,750,14 2 0362 ograve +char242 " +'o 611,750,14 2 0363 oacute +char243 " +^o 611,750,14 2 0364 ocircumflex +char244 " +~o 611,737,14 2 0365 otilde +char245 " +:o 611,729,14 2 0366 odieresis +char246 " +char247 584,548,42 0 0367 divide +/o 611,560,29 0 0370 oslash +char248 " +`u 611,750,14 2 0371 ugrave +char249 " +'u 611,750,14 2 0372 uacute +char250 " +^u 611,750,14 2 0373 ucircumflex +char251 " +:u 611,729,14 2 0374 udieresis +char252 " +'y 556,750,214 3 0375 yacute +char253 " +Tp 611,718,208 3 0376 thorn +char254 " +:y 556,729,214 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/HBI b/gnu/usr.bin/groff/devices/devps/HBI new file mode 100644 index 0000000000..595e58f90f --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/HBI @@ -0,0 +1,547 @@ +name HBI +internalname Helvetica-BoldOblique +slant 12 +spacewidth 278 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -30 +A w -30 +A v -40 +A u -30 +A Y -110 +A W -60 +A V -80 +A U -50 +A T -90 +A Q -40 +A O -40 +A G -50 +A C -40 +B U -10 +B A -30 +D . -30 +D , -30 +D Y -70 +D W -40 +D V -40 +D A -40 +F . -100 +F , -100 +F a -20 +F A -80 +J u -20 +J . -20 +J , -20 +J A -20 +K y -40 +K u -30 +K o -35 +K e -15 +K O -30 +L y -30 +L ' -140 +L rq -140 +L Y -120 +L W -80 +L V -110 +L T -90 +O . -40 +O , -40 +O Y -70 +O X -50 +O W -50 +O V -50 +O T -40 +O A -50 +P . -120 +P o -40 +P e -30 +P , -120 +P a -30 +P A -100 +Q . 20 +Q , 20 +Q U -10 +R Y -50 +R W -40 +R V -50 +R U -20 +R T -20 +R O -20 +T y -60 +T w -60 +T u -90 +T ; -40 +T r -80 +T . -80 +T o -80 +T - -120 +T hy -120 +T char173 -120 +T e -60 +T , -80 +T : -40 +T a -80 +T O -40 +T A -90 +U . -30 +U , -30 +U A -50 +V u -60 +V ; -40 +V . -120 +V o -90 +V - -80 +V hy -80 +V char173 -80 +V e -50 +V , -120 +V : -40 +V a -60 +V O -50 +V G -50 +V A -80 +W y -20 +W u -45 +W ; -10 +W . -80 +W o -60 +W - -40 +W hy -40 +W char173 -40 +W e -35 +W , -80 +W : -10 +W a -40 +W O -20 +W A -60 +Y u -100 +Y ; -50 +Y . -100 +Y o -100 +Y e -80 +Y , -100 +Y : -50 +Y a -90 +Y O -70 +Y A -110 +a y -20 +a w -15 +a v -15 +a g -10 +b y -20 +b v -20 +b u -20 +b l -10 +c y -10 +c l -20 +c k -20 +c h -10 +, ' -120 +, rq -120 +d y -15 +d w -15 +d v -15 +d d -10 +e y -15 +e x -15 +e w -15 +e v -15 +e . 20 +e , 10 +f ' 30 +f rq 30 +f . -10 +f o -20 +f e -10 +f , -10 +g g -10 +g e 10 +h y -20 +k o -15 +l y -15 +l w -15 +m y -30 +m u -20 +n y -20 +n v -40 +n u -10 +o y -20 +o x -30 +o w -15 +o v -20 +p y -15 +. ' -120 +. rq -120 +` ` -46 +` oq -46 +oq ` -46 +oq oq -46 +' v -20 +' s -60 +' r -40 +' ' -46 +' l -20 +' d -80 +r y 10 +r v 10 +r t 20 +r s -15 +r q -20 +r . -60 +r o -20 +r - -20 +r hy -20 +r char173 -20 +r g -15 +r d -20 +r , -60 +r c -20 +s w -15 +v . -80 +v o -30 +v , -80 +v a -20 +w . -40 +w o -20 +w , -40 +x e -10 +y . -80 +y o -25 +y e -10 +y , -80 +y a -30 +z e 10 +charset +ha 584,698,0,57,-81,57 2 0000 asciicircum +ti 584,343,0,43,-65,43 0 0001 asciitilde +vS 667,936,19,101,-31,90 2 0002 Scaron +vZ 611,936,0,176,25,90 2 0003 Zcaron +vs 556,750,14,108,-13,90 2 0004 scaron +vz 500,750,0,136,30,90 2 0005 zcaron +:Y 667,915,0,189,-118,90 2 0006 Ydieresis +tm 1000,718,0,159,-129,90 2 0007 trademark +aq 238,718,0,133,-115,90 2 0010 quotesingle +space 278 0 0040 +! 333,718,0,114,-44,90 2 0041 exclam +" 474,718,0,105,-143,90 2 0042 quotedbl +# 556,698,0,138,-10,90 2 0043 numbersign +sh " +$ 556,775,115,116,-17,90 2 0044 dollar +Do " +% 889,710,19,62,-86,62 2 0045 percent +& 722,718,19,60,-39,60 2 0046 ampersand +' 278,718,0,134,-117,90 2 0047 quoteright +( 333,734,208,187,-26,90 3 0050 parenleft +) 333,734,208,86,75,86 3 0051 parenright +* 389,718,0,142,-96,90 2 0052 asterisk ++ 584,506,0,76,-32,76 0 0053 plus +, 278,146,168,17,22,17 0 0054 comma +- 333,345,0,96,-23,90 0 0055 hyphen +hy " +char173 " +. 278,146,0,17,-14,17 0 0056 period +/ 278,737,19,240,87,90 2 0057 slash +sl " +0 556,710,19,111,-36,90 2 0060 zero +1 556,710,0,23,-123,23 2 0061 one +2 556,710,0,113,24,90 2 0062 two +3 556,710,19,102,-15,90 2 0063 three +4 556,710,0,92,-10,90 2 0064 four +5 556,698,19,130,-14,90 2 0065 five +6 556,710,19,113,-35,90 2 0066 six +7 556,698,0,170,-75,90 2 0067 seven +8 556,710,19,110,-19,90 2 0070 eight +9 556,710,19,109,-28,90 2 0071 nine +: 333,512,0,68,-42,68 0 0072 colon +; 333,512,168,68,-6,68 0 0073 semicolon +< 584,514,8,121,-32,90 0 0074 less += 584,419,0,99,-8,90 0 0075 equal +> 584,514,8,75,14,75 0 0076 greater +? 611,727,0,110,-115,90 2 0077 question +@ 975,737,19,29,-136,29 2 0100 at +at " +A 722,718,0,30,30,30 2 0101 A +B 722,718,0,92,-26,90 2 0102 B +C 722,737,19,117,-57,90 2 0103 C +D 722,718,0,105,-26,90 2 0104 D +E 667,718,0,140,-26,90 2 0105 E +F 611,718,0,179,-26,90 2 0106 F +G 778,737,19,89,-58,89 2 0107 G +H 722,718,0,132,-21,90 2 0110 H +I 278,718,0,139,-14,90 2 0111 I +J 556,718,18,131,-10,90 2 0112 J +K 722,718,0,186,-37,90 2 0113 K +L 611,718,0,50,-26,50 2 0114 L +M 833,718,0,135,-19,90 2 0115 M +N 722,718,0,135,-19,90 2 0116 N +O 778,737,19,95,-57,90 2 0117 O +P 667,718,0,121,-26,90 2 0120 P +Q 778,737,52,95,-57,90 2 0121 Q +R 722,718,0,106,-26,90 2 0122 R +S 667,737,19,101,-31,90 2 0123 S +T 611,718,0,190,-90,90 2 0124 T +U 722,718,19,132,-66,90 2 0125 U +V 667,718,0,184,-122,90 2 0126 V +W 944,718,0,188,-119,90 2 0127 W +X 667,718,0,174,36,90 2 0130 X +Y 667,718,0,189,-118,90 2 0131 Y +Z 611,718,0,176,25,90 2 0132 Z +[ 333,722,196,179,29,90 2 0133 bracketleft +lB " +\ 278,737,19,79,-74,79 2 0134 backslash +rs " +] 333,722,196,140,68,90 2 0135 bracketright +rB " +a^ 333,750,0,188,-68,90 2 0136 circumflex +^ " +_ 556,0,125,34,77,34 0 0137 underscore +` 278,727,0,133,-115,90 2 0140 quoteleft +oq " +a 556,546,14,77,-5,77 0 0141 a +b 611,718,14,84,-11,84 2 0142 b +c 556,546,14,93,-29,90 0 0143 c +d 611,718,14,143,-32,90 2 0144 d +e 556,546,14,87,-20,87 0 0145 e +f 333,727,0,186,-37,90 2 0146 f +g 611,546,217,105,12,90 1 0147 g +h 611,718,0,68,-15,68 2 0150 h +i 278,725,0,135,-19,90 2 0151 i +j 278,725,214,135,92,90 3 0152 j +k 556,718,0,164,-19,90 2 0153 k +l 278,718,0,134,-19,90 2 0154 l +m 889,546,0,70,-14,70 0 0155 m +n 611,546,0,68,-15,68 0 0156 n +o 611,546,14,82,-32,82 0 0157 o +p 611,546,207,84,32,84 1 0160 p +q 611,546,207,104,-30,90 1 0161 q +r 389,546,0,150,-14,90 0 0162 r +s 556,546,14,78,-13,78 0 0163 s +t 333,676,6,139,-50,90 2 0164 t +u 611,532,14,97,-48,90 0 0165 u +v 556,532,0,150,-76,90 0 0166 v +w 778,532,0,154,-73,90 0 0167 w +x 556,532,0,142,35,90 0 0170 x +y 556,532,214,146,8,90 1 0171 y +z 500,532,0,133,30,90 0 0172 z +lC 389,722,196,179,-44,90 2 0173 braceleft +{ " +ba 280,737,19,123,-30,90 2 0174 bar +| " +rC 389,722,196,68,68,68 2 0175 braceright +} " +a~ 333,737,0,224,-63,90 2 0176 tilde +~ " +bq 278,127,146,8,9,8 0 0200 quotesinglbase +Fo 556,484,0,65,-85,65 0 0201 guillemotleft +char171 " +Fc 556,484,0,34,-54,34 0 0202 guillemotright +char187 " +bu 350,524,0,120,-33,90 0 0203 bullet +Fn 556,737,210,163,100,90 3 0204 florin +f/ 167,710,19,370,224,90 2 0205 fraction +%0 1000,710,19,88,-26,88 2 0206 perthousand +dg 556,718,171,120,-68,90 2 0207 dagger +dd 556,718,171,122,4,90 2 0210 daggerdbl +en 556,333,0,121,2,90 0 0211 endash +em 1000,333,0,121,2,90 0 0212 emdash +fi 611,727,0,135,-37,90 2 0214 fi +fl 611,727,0,134,-37,90 2 0215 fl +.i 278,532,0,94,-19,90 0 0220 dotlessi +ga 333,750,0,70,-86,70 2 0222 grave +a" 333,750,0,362,-87,90 2 0223 hungarumlaut +a. 333,729,0,102,-185,90 2 0224 dotaccent +ab 333,750,0,211,-106,90 2 0225 breve +ah 333,750,0,219,-99,90 2 0226 caron +ao 333,776,0,137,-150,90 2 0227 ring +ho 333,0,228,0,9 1 0230 ogonek +lq 500,727,0,138,-110,90 2 0231 quotedblleft +rq 500,718,0,139,-112,90 2 0232 quotedblright +oe 944,546,14,83,-32,83 0 0233 oe +/l 278,718,0,179,10,90 2 0234 lslash +Bq 500,127,146,13,14,13 0 0235 quotedblbase +OE 1000,737,19,164,-49,90 2 0236 OE +/L 611,718,0,50,16,50 2 0237 Lslash +r! 333,532,186,70,0,70 0 0241 exclamdown +char161 " +ct 556,628,118,93,-29,90 0 0242 cent +char162 " +Po 556,718,16,129,0,90 2 0243 sterling +char163 " +Cs 556,636,0,174,23,90 0 0244 currency +char164 " +Ye 556,698,0,207,-10,90 2 0245 yen +char165 " +bb 280,737,19,123,-30,90 2 0246 brokenbar +char166 " +sc 556,727,184,92,-11,90 2 0247 section +char167 " +ad 333,729,0,199,-87,90 2 0250 dieresis +char168 " +co 737,737,19,148,-6,90 2 0251 copyright +char169 " +Of 370,737,0,145,-42,90 2 0252 ordfeminine +char170 " +fo 333,484,0,70,-80,70 0 0253 guilsinglleft +no 584,419,0,99,-55,90 0 0254 logicalnot +char172 " +\- 584,309,0,76,-32,76 0 0255 minus +rg 737,737,19,147,-5,90 2 0256 registered +char174 " +a- 333,678,0,200,-72,90 2 0257 macron +char175 " +de 400,712,0,117,-125,90 2 0260 degree +char176 " +char177 584,506,0,91,10,90 0 0261 plusminus +S2 333,710,0,166,-19,90 2 0262 twosuperior +char178 " +S3 333,710,0,158,-41,90 2 0263 threesuperior +char179 " +aa 333,750,0,232,-186,90 2 0264 acute +char180 " +char181 611,532,207,97,28,90 1 0265 mu +ps 556,700,191,182,-48,90 2 0266 paragraph +char182 " +char183 278,334,0,48,-60,48 0 0267 periodcentered +ac 333,0,228,0,87 1 0270 cedilla +char184 " +S1 333,710,0,105,-98,90 2 0271 onesuperior +char185 " +Om 365,737,0,170,-42,90 2 0272 ordmasculine +char186 " +fc 333,484,0,39,-49,39 0 0273 guilsinglright +14 834,710,19,22,-82,22 2 0274 onequarter +char188 " +12 834,710,19,74,-82,74 2 0275 onehalf +char189 " +34 834,710,19,55,-49,55 2 0276 threequarters +char190 " +r? 611,532,195,0,-3 0 0277 questiondown +char191 " +`A 722,936,0,30,30,30 2 0300 Agrave +char192 " +'A 722,936,0,78,30,78 2 0301 Aacute +char193 " +^A 722,936,0,34,30,34 2 0302 Acircumflex +char194 " +~A 722,923,0,69,30,69 2 0303 Atilde +char195 " +:A 722,915,0,44,30,44 2 0304 Adieresis +char196 " +oA 722,962,0,30,30,30 2 0305 Aring +char197 " +AE 1000,718,0,150,45,90 2 0306 AE +char198 " +,C 722,737,228,117,-57,90 3 0307 Ccedilla +char199 " +`E 667,936,0,140,-26,90 2 0310 Egrave +char200 " +'E 667,936,0,140,-26,90 2 0311 Eacute +char201 " +^E 667,936,0,140,-26,90 2 0312 Ecircumflex +char202 " +:E 667,915,0,140,-26,90 2 0313 Edieresis +char203 " +`I 278,936,0,139,-14,90 2 0314 Igrave +char204 " +'I 278,936,0,300,-14,90 2 0315 Iacute +char205 " +^I 278,936,0,256,-14,90 2 0316 Icircumflex +char206 " +:I 278,915,0,266,-14,90 2 0317 Idieresis +char207 " +-D 722,718,0,105,-12,90 2 0320 Eth +char208 " +~N 722,923,0,135,-19,90 2 0321 Ntilde +char209 " +`O 778,936,19,95,-57,90 2 0322 Ograve +char210 " +'O 778,936,19,95,-57,90 2 0323 Oacute +char211 " +^O 778,936,19,95,-57,90 2 0324 Ocircumflex +char212 " +~O 778,923,19,95,-57,90 2 0325 Otilde +char213 " +:O 778,915,19,95,-57,90 2 0326 Odieresis +char214 " +char215 584,505,0,101,-7,90 0 0327 multiply +/O 778,745,27,166,15,90 2 0330 Oslash +char216 " +`U 722,936,19,132,-66,90 2 0331 Ugrave +char217 " +'U 722,936,19,132,-66,90 2 0332 Uacute +char218 " +^U 722,936,19,132,-66,90 2 0333 Ucircumflex +char219 " +:U 722,915,19,132,-66,90 2 0334 Udieresis +char220 " +'Y 667,936,0,189,-118,90 2 0335 Yacute +char221 " +TP 667,718,0,99,-26,90 2 0336 Thorn +char222 " +ss 611,731,14,96,-19,90 2 0337 germandbls +char223 " +`a 556,750,14,77,-5,77 2 0340 agrave +char224 " +'a 556,750,14,121,-5,90 2 0341 aacute +char225 " +^a 556,750,14,77,-5,77 2 0342 acircumflex +char226 " +~a 556,737,14,113,-5,90 2 0343 atilde +char227 " +:a 556,729,14,88,-5,88 2 0344 adieresis +char228 " +oa 556,776,14,77,-5,77 2 0345 aring +char229 " +ae 889,546,14,84,-6,84 0 0346 ae +char230 " +,c 556,546,228,93,-29,90 1 0347 ccedilla +char231 " +`e 556,750,14,87,-20,87 2 0350 egrave +char232 " +'e 556,750,14,121,-20,90 2 0351 eacute +char233 " +^e 556,750,14,87,-20,87 2 0352 ecircumflex +char234 " +:e 556,729,14,88,-20,88 2 0353 edieresis +char235 " +`i 278,750,0,98,-19,90 2 0354 igrave +char236 " +'i 278,750,0,260,-19,90 2 0355 iacute +char237 " +^i 278,750,0,216,-19,90 2 0356 icircumflex +char238 " +:i 278,729,0,227,-19,90 2 0357 idieresis +char239 " +Sd 611,737,14,109,-32,90 2 0360 eth +char240 " +~n 611,737,0,85,-15,85 2 0361 ntilde +char241 " +`o 611,750,14,82,-32,82 2 0362 ograve +char242 " +'o 611,750,14,93,-32,90 2 0363 oacute +char243 " +^o 611,750,14,82,-32,82 2 0364 ocircumflex +char244 " +~o 611,737,14,85,-32,85 2 0365 otilde +char245 " +:o 611,729,14,82,-32,82 2 0366 odieresis +char246 " +char247 584,548,42,76,-32,76 0 0367 divide +/o 611,560,29,140,28,90 0 0370 oslash +char248 " +`u 611,750,14,97,-48,90 2 0371 ugrave +char249 " +'u 611,750,14,97,-48,90 2 0372 uacute +char250 " +^u 611,750,14,97,-48,90 2 0373 ucircumflex +char251 " +:u 611,729,14,97,-48,90 2 0374 udieresis +char252 " +'y 556,750,214,146,8,90 3 0375 yacute +char253 " +Tp 611,718,208,84,32,84 3 0376 thorn +char254 " +:y 556,729,214,146,8,90 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/HI b/gnu/usr.bin/groff/devices/devps/HI new file mode 100644 index 0000000000..bfdcb32808 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/HI @@ -0,0 +1,617 @@ +name HI +internalname Helvetica-Oblique +slant 12 +spacewidth 278 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -40 +A w -40 +A v -40 +A u -30 +A Y -100 +A W -50 +A V -70 +A U -50 +A T -120 +A Q -30 +A O -30 +A G -30 +A C -30 +B . -20 +B , -20 +B U -10 +C . -30 +C , -30 +D . -70 +D , -70 +D Y -90 +D W -40 +D V -70 +D A -40 +F r -45 +F . -150 +F o -30 +F e -30 +F , -150 +F a -50 +F A -80 +J u -20 +J . -30 +J , -30 +J a -20 +J A -20 +K y -50 +K u -30 +K o -40 +K e -40 +K O -50 +L y -30 +L ' -160 +L rq -140 +L Y -140 +L W -70 +L V -110 +L T -110 +O . -40 +O , -40 +O Y -70 +O X -60 +O W -30 +O V -50 +O T -40 +O A -20 +P . -180 +P o -50 +P e -50 +P , -180 +P a -40 +P A -120 +Q U -10 +R Y -50 +R W -30 +R V -50 +R U -40 +R T -30 +R O -20 +S . -20 +S , -20 +T y -120 +T w -120 +T u -120 +T ; -20 +T r -120 +T . -120 +T o -120 +T - -140 +T hy -140 +T char173 -140 +T e -120 +T , -120 +T : -20 +T a -120 +T O -40 +T A -120 +U . -40 +U , -40 +U A -40 +V u -70 +V ; -40 +V . -125 +V o -80 +V - -80 +V hy -80 +V char173 -80 +V e -80 +V , -125 +V : -40 +V a -70 +V O -40 +V G -40 +V A -80 +W y -20 +W u -30 +W . -80 +W o -30 +W - -40 +W hy -40 +W char173 -40 +W e -30 +W , -80 +W a -40 +W O -20 +W A -50 +Y u -110 +Y ; -60 +Y . -140 +Y o -140 +Y i -20 +Y - -140 +Y hy -140 +Y char173 -140 +Y e -140 +Y , -140 +Y : -60 +Y a -140 +Y O -85 +Y A -110 +a y -30 +a w -20 +a v -20 +b y -20 +b v -20 +b u -20 +b . -40 +b l -20 +b , -40 +b b -10 +c k -20 +c , -15 +, ' -100 +, rq -100 +e y -20 +e x -30 +e w -20 +e v -30 +e . -15 +e , -15 +f ' 50 +f rq 60 +f . -30 +f o -30 +f e -30 +f .i -28 +f , -30 +f a -30 +g r -10 +h y -30 +k o -20 +k e -20 +m y -15 +m u -10 +n y -15 +n v -20 +n u -10 +o y -30 +o x -30 +o w -15 +o v -15 +o . -40 +o , -40 +/o z -55 +char248 z -55 +/o y -70 +char248 y -70 +/o x -85 +char248 x -85 +/o w -70 +char248 w -70 +/o v -70 +char248 v -70 +/o u -55 +char248 u -55 +/o t -55 +char248 t -55 +/o s -55 +char248 s -55 +/o r -55 +char248 r -55 +/o q -55 +char248 q -55 +/o . -95 +char248 . -95 +/o p -55 +char248 p -55 +/o o -55 +char248 o -55 +/o n -55 +char248 n -55 +/o m -55 +char248 m -55 +/o l -55 +char248 l -55 +/o k -55 +char248 k -55 +/o j -55 +char248 j -55 +/o i -55 +char248 i -55 +/o h -55 +char248 h -55 +/o g -55 +char248 g -55 +/o f -55 +char248 f -55 +/o e -55 +char248 e -55 +/o d -55 +char248 d -55 +/o , -95 +char248 , -95 +/o c -55 +char248 c -55 +/o b -55 +char248 b -55 +/o a -55 +char248 a -55 +p y -30 +p . -35 +p , -35 +. ' -100 +. rq -100 +` ` -57 +` oq -57 +oq ` -57 +oq oq -57 +' s -50 +' r -50 +' ' -57 +' d -50 +r y 30 +r v 30 +r u 15 +r t 40 +r ; 30 +r . -50 +r p 30 +r n 25 +r m 25 +r l 15 +r k 15 +r i 15 +r , -50 +r : 30 +r a -10 +s w -30 +s . -15 +s , -15 +v . -80 +v o -25 +v e -25 +v , -80 +v a -25 +w . -60 +w o -10 +w e -10 +w , -60 +w a -15 +x e -30 +y . -100 +y o -20 +y e -20 +y , -100 +y a -20 +z o -15 +z e -15 +charset +ha 469,688,0,120,8,89 2 0000 asciicircum +ti 584,326,0,46,-61,46 0 0001 asciitilde +vS 667,929,19,96,-40,89 2 0002 Scaron +vZ 611,929,0,180,27,89 2 0003 Zcaron +vs 500,734,15,102,-13,89 2 0004 scaron +vz 500,734,0,121,19,89 2 0005 zcaron +:Y 667,901,0,189,-117,89 2 0006 Ydieresis +tm 1000,718,0,106,-136,89 2 0007 trademark +aq 191,718,0,144,-107,89 2 0010 quotesingle +space 278 0 0040 +! 278,718,0,112,-40,89 2 0041 exclam +" 355,718,0,133,-118,89 2 0042 quotedbl +# 556,688,0,125,-23,89 2 0043 numbersign +sh " +$ 556,775,115,111,-19,89 2 0044 dollar +Do " +% 889,703,19,50,-97,50 2 0045 percent +& 667,718,15,30,-27,30 2 0046 ampersand +' 222,718,0,138,-101,89 2 0047 quoteright +( 333,733,207,171,-58,89 3 0050 parenleft +) 333,733,207,54,59,54 3 0051 parenright +* 389,718,0,136,-115,89 2 0052 asterisk ++ 584,505,0,72,-35,72 0 0053 plus +, 278,106,147,0,-6 0 0054 comma +- 333,322,0,74,-43,74 0 0055 hyphen +hy " +char173 " +. 278,106,0,0,-37 0 0056 period +/ 278,737,19,224,71,89 2 0057 slash +sl " +0 556,703,19,102,-43,89 2 0060 zero +1 556,703,0,2,-157,2 2 0061 one +2 556,703,0,111,24,89 2 0062 two +3 556,703,19,104,-25,89 2 0063 three +4 556,703,0,70,-11,70 2 0064 four +5 556,688,19,115,-18,89 2 0065 five +6 556,703,19,109,-41,89 2 0066 six +7 556,688,0,163,-87,89 2 0067 seven +8 556,703,19,101,-24,89 2 0070 eight +9 556,703,19,103,-32,89 2 0071 nine +: 278,516,0,73,-37,73 0 0072 colon +; 278,516,147,73,-6,73 0 0073 semicolon +< 584,495,0,107,-44,89 0 0074 less += 584,390,0,94,-13,89 0 0075 equal +> 584,495,0,63,0,63 0 0076 greater +? 556,727,0,104,-111,89 2 0077 question +@ 1015,737,19,0,-165 2 0100 at +at " +A 667,718,0,37,36,37 2 0101 A +B 667,718,0,95,-24,89 2 0102 B +C 722,737,19,110,-58,89 2 0103 C +D 722,718,0,92,-31,89 2 0104 D +E 667,718,0,145,-36,89 2 0105 E +F 611,718,0,175,-36,89 2 0106 F +G 778,737,19,71,-61,71 2 0107 G +H 722,718,0,127,-27,89 2 0110 H +I 278,718,0,113,-41,89 2 0111 I +J 500,718,19,131,3,89 2 0112 J +K 667,718,0,191,-26,89 2 0113 K +L 556,718,0,49,-26,49 2 0114 L +M 833,718,0,131,-23,89 2 0115 M +N 722,718,0,127,-26,89 2 0116 N +O 778,737,19,98,-55,89 2 0117 O +P 667,718,0,120,-36,89 2 0120 P +Q 778,737,56,98,-55,89 2 0121 Q +R 722,718,0,101,-38,89 2 0122 R +S 667,737,19,96,-40,89 2 0123 S +T 611,718,0,189,-98,89 2 0124 T +U 722,718,19,125,-73,89 2 0125 U +V 667,718,0,183,-123,89 2 0126 V +W 944,718,0,187,-119,89 2 0127 W +X 667,718,0,173,31,89 2 0130 X +Y 667,718,0,189,-117,89 2 0131 Y +Z 611,718,0,180,27,89 2 0132 Z +[ 278,722,196,175,29,89 2 0133 bracketleft +lB " +\ 278,737,19,63,-90,63 2 0134 backslash +rs " +] 278,722,196,140,64,89 2 0135 bracketright +rB " +a^ 333,734,0,155,-97,89 2 0136 circumflex +^ " +_ 556,0,125,34,77,34 0 0137 underscore +` 222,725,0,151,-115,89 2 0140 quoteleft +oq " +a 556,538,15,53,-11,53 0 0141 a +b 556,718,15,78,-8,78 2 0142 b +c 500,538,15,103,-24,89 0 0143 c +d 556,718,15,146,-34,89 2 0144 d +e 556,538,15,72,-34,72 0 0145 e +f 278,728,0,188,-36,89 2 0146 f +g 556,538,220,104,8,89 1 0147 g +h 556,718,0,67,-15,67 2 0150 h +i 222,718,0,136,-17,89 2 0151 i +j 222,718,210,136,110,89 3 0152 j +k 500,718,0,150,-17,89 2 0153 k +l 222,718,0,136,-17,89 2 0154 l +m 833,538,0,69,-15,69 0 0155 m +n 556,538,0,67,-15,67 0 0156 n +o 556,538,14,79,-33,79 0 0157 o +p 556,538,207,78,36,78 1 0160 p +q 556,538,207,99,-34,89 1 0161 q +r 333,538,0,163,-27,89 0 0162 r +s 500,538,15,79,-13,79 0 0163 s +t 278,669,7,140,-52,89 2 0164 t +u 556,523,15,94,-44,89 0 0165 u +v 500,523,0,153,-69,89 0 0166 v +w 722,523,0,148,-75,89 0 0167 w +x 500,523,0,144,39,89 0 0170 x +y 500,523,214,150,35,89 1 0171 y +z 500,523,0,121,19,89 0 0172 z +lC 334,722,196,161,-42,89 2 0173 braceleft +{ " +ba 260,737,19,114,-40,89 2 0174 bar +| " +rC 334,722,196,70,50,70 2 0175 braceright +} " +a~ 333,722,0,207,-75,89 2 0176 tilde +~ " +bq 222,106,149,8,29,8 0 0200 quotesinglbase +Fo 556,446,0,48,-96,48 0 0201 guillemotleft +char171 " +Fc 556,446,0,22,-70,22 0 0202 guillemotright +char187 " +bu 350,517,0,113,-41,89 0 0203 bullet +Fn 556,737,207,148,102,89 3 0204 florin +f/ 167,703,19,365,220,89 2 0205 fraction +%0 1000,703,19,79,-38,79 2 0206 perthousand +dg 556,718,159,116,-85,89 2 0207 dagger +dd 556,718,159,117,-2,89 2 0210 daggerdbl +en 556,313,0,117,-1,89 0 0211 endash +em 1000,313,0,117,-1,89 0 0212 emdash +fi 500,728,0,137,-36,89 2 0214 fi +fl 500,728,0,135,-36,89 2 0215 fl +.i 278,523,0,66,-45,66 0 0220 dotlessi +ga 333,734,0,54,-120,54 2 0222 grave +a" 333,734,0,282,-107,89 2 0223 hungarumlaut +a. 333,706,0,79,-199,79 2 0224 dotaccent +ab 333,731,0,193,-117,89 2 0225 breve +ah 333,734,0,185,-127,89 2 0226 caron +ao 333,756,0,119,-164,89 2 0227 ring +ho 333,0,225,0,7 1 0230 ogonek +lq 333,725,0,178,-88,89 2 0231 quotedblleft +rq 333,718,0,165,-74,89 2 0232 quotedblright +oe 944,538,15,70,-33,70 0 0233 oe +/l 222,718,0,175,9,89 2 0234 lslash +Bq 333,106,149,35,56,35 0 0235 quotedblbase +OE 1000,737,19,166,-48,89 2 0236 OE +/L 556,718,0,49,9,49 2 0237 Lslash +r! 333,523,195,43,-27,43 0 0241 exclamdown +char161 " +ct 556,623,115,78,-45,78 0 0242 cent +char162 " +Po 556,718,16,128,1,89 2 0243 sterling +char163 " +Cs 556,603,0,140,-10,89 0 0244 currency +char164 " +Ye 556,688,0,193,-31,89 2 0245 yen +char165 " +bb 260,737,19,114,-40,89 2 0246 brokenbar +char166 " +sc 556,737,191,78,-26,78 2 0247 section +char167 " +ad 333,706,0,160,-118,89 2 0250 dieresis +char168 " +co 737,737,19,150,-4,89 2 0251 copyright +char169 " +Of 370,737,0,129,-50,89 2 0252 ordfeminine +char170 " +fo 333,446,0,57,-87,57 0 0253 guilsinglleft +no 584,390,0,94,-56,89 0 0254 logicalnot +char172 " +\- 584,289,0,72,-35,72 0 0255 minus +rg 737,737,19,150,-4,89 2 0256 registered +char174 " +a- 333,684,0,185,-93,89 2 0257 macron +char175 " +de 400,703,0,118,-119,89 2 0260 degree +char176 " +char177 584,506,0,84,11,84 0 0261 plusminus +S2 333,703,0,166,-14,89 2 0262 twosuperior +char178 " +S3 333,703,0,153,-40,89 2 0263 threesuperior +char179 " +aa 333,734,0,192,-198,89 2 0264 acute +char180 " +char181 556,523,207,94,26,89 1 0265 mu +ps 537,718,173,163,-76,89 2 0266 paragraph +char182 " +char183 278,315,0,29,-79,29 0 0267 periodcentered +ac 333,0,225,0,48 1 0270 cedilla +char184 " +S1 333,703,0,88,-116,88 2 0271 onesuperior +char185 " +Om 365,737,0,153,-50,89 2 0272 ordmasculine +char186 " +fc 333,446,0,31,-61,31 0 0273 guilsinglright +14 834,703,19,18,-100,18 2 0274 onequarter +char188 " +12 834,703,19,55,-64,55 2 0275 onehalf +char189 " +34 834,703,19,77,-80,77 2 0276 threequarters +char190 " +r? 611,525,201,0,-35 0 0277 questiondown +char191 " +`A 667,929,0,37,36,37 2 0300 Agrave +char192 " +'A 667,929,0,66,36,66 2 0301 Aacute +char193 " +^A 667,929,0,37,36,37 2 0302 Acircumflex +char194 " +~A 667,917,0,82,36,82 2 0303 Atilde +char195 " +:A 667,901,0,37,36,37 2 0304 Adieresis +char196 " +oA 667,931,0,37,36,37 2 0305 Aring +char197 " +AE 1000,718,0,147,42,89 2 0306 AE +char198 " +,C 722,737,225,110,-58,89 3 0307 Ccedilla +char199 " +`E 667,929,0,145,-36,89 2 0310 Egrave +char200 " +'E 667,929,0,145,-36,89 2 0311 Eacute +char201 " +^E 667,929,0,145,-36,89 2 0312 Ecircumflex +char202 " +:E 667,901,0,145,-36,89 2 0313 Edieresis +char203 " +`I 278,929,0,123,-41,89 2 0314 Igrave +char204 " +'I 278,929,0,261,-41,89 2 0315 Iacute +char205 " +^I 278,929,0,224,-41,89 2 0316 Icircumflex +char206 " +:I 278,901,0,230,-41,89 2 0317 Idieresis +char207 " +-D 722,718,0,92,-19,89 2 0320 Eth +char208 " +~N 722,917,0,127,-26,89 2 0321 Ntilde +char209 " +`O 778,929,19,98,-55,89 2 0322 Ograve +char210 " +'O 778,929,19,98,-55,89 2 0323 Oacute +char211 " +^O 778,929,19,98,-55,89 2 0324 Ocircumflex +char212 " +~O 778,917,19,98,-55,89 2 0325 Otilde +char213 " +:O 778,901,19,98,-55,89 2 0326 Odieresis +char214 " +char215 584,506,0,108,0,89 0 0327 multiply +/O 778,737,19,162,7,89 2 0330 Oslash +char216 " +`U 722,929,19,125,-73,89 2 0331 Ugrave +char217 " +'U 722,929,19,125,-73,89 2 0332 Uacute +char218 " +^U 722,929,19,125,-73,89 2 0333 Ucircumflex +char219 " +:U 722,901,19,125,-73,89 2 0334 Udieresis +char220 " +'Y 667,929,0,189,-117,89 2 0335 Yacute +char221 " +TP 667,718,0,95,-36,89 2 0336 Thorn +char222 " +ss 611,728,15,97,-17,89 2 0337 germandbls +char223 " +`a 556,734,15,53,-11,53 2 0340 agrave +char224 " +'a 556,734,15,81,-11,81 2 0341 aacute +char225 " +^a 556,734,15,53,-11,53 2 0342 acircumflex +char226 " +~a 556,722,15,86,-11,86 2 0343 atilde +char227 " +:a 556,706,15,53,-11,53 2 0344 adieresis +char228 " +oa 556,756,15,53,-11,53 2 0345 aring +char229 " +ae 889,538,15,70,-11,70 0 0346 ae +char230 " +,c 500,538,225,103,-24,89 1 0347 ccedilla +char231 " +`e 556,734,15,72,-34,72 2 0350 egrave +char232 " +'e 556,734,15,81,-34,81 2 0351 eacute +char233 " +^e 556,734,15,72,-34,72 2 0352 ecircumflex +char234 " +:e 556,706,15,72,-34,72 2 0353 edieresis +char235 " +`i 278,734,0,82,-45,82 2 0354 igrave +char236 " +'i 278,734,0,220,-45,89 2 0355 iacute +char237 " +^i 278,734,0,183,-45,89 2 0356 icircumflex +char238 " +:i 278,706,0,188,-45,89 2 0357 idieresis +char239 " +Sd 556,737,15,111,-31,89 2 0360 eth +char240 " +~n 556,722,0,86,-15,86 2 0361 ntilde +char241 " +`o 556,734,14,79,-33,79 2 0362 ograve +char242 " +'o 556,734,14,81,-33,81 2 0363 oacute +char243 " +^o 556,734,14,79,-33,79 2 0364 ocircumflex +char244 " +~o 556,722,14,96,-33,89 2 0365 otilde +char245 " +:o 556,706,14,79,-33,79 2 0366 odieresis +char246 " +char247 584,524,19,72,-35,72 0 0367 divide +/o 611,545,22,86,21,86 0 0370 oslash +char248 " +`u 556,734,15,94,-44,89 2 0371 ugrave +char249 " +'u 556,734,15,94,-44,89 2 0372 uacute +char250 " +^u 556,734,15,94,-44,89 2 0373 ucircumflex +char251 " +:u 556,706,15,94,-44,89 2 0374 udieresis +char252 " +'y 500,734,214,150,35,89 3 0375 yacute +char253 " +Tp 556,718,207,78,36,78 3 0376 thorn +char254 " +:y 500,706,214,150,35,89 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/HNB b/gnu/usr.bin/groff/devices/devps/HNB new file mode 100644 index 0000000000..6e64674277 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/HNB @@ -0,0 +1,546 @@ +name HNB +internalname Helvetica-Narrow-Bold +spacewidth 228 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -24 +A w -24 +A v -32 +A u -24 +A Y -89 +A W -48 +A V -65 +A U -40 +A T -73 +A Q -32 +A O -32 +A G -40 +A C -32 +B U -7 +B A -24 +D . -24 +D , -24 +D Y -56 +D W -32 +D V -32 +D A -32 +F . -81 +F , -81 +F a -15 +F A -65 +J u -15 +J . -15 +J , -15 +J A -15 +K y -32 +K u -24 +K o -28 +K e -11 +K O -24 +L y -24 +L ' -114 +L rq -114 +L Y -97 +L W -65 +L V -89 +L T -73 +O . -32 +O , -32 +O Y -56 +O X -40 +O W -40 +O V -40 +O T -32 +O A -40 +P . -97 +P o -32 +P e -24 +P , -97 +P a -24 +P A -81 +Q . 16 +Q , 16 +Q U -7 +R Y -40 +R W -32 +R V -40 +R U -15 +R T -15 +R O -15 +T y -48 +T w -48 +T u -73 +T ; -32 +T r -65 +T . -65 +T o -65 +T - -97 +T hy -97 +T char173 -97 +T e -48 +T , -65 +T : -32 +T a -65 +T O -32 +T A -73 +U . -24 +U , -24 +U A -40 +V u -48 +V ; -32 +V . -97 +V o -73 +V - -65 +V hy -65 +V char173 -65 +V e -40 +V , -97 +V : -32 +V a -48 +V O -40 +V G -40 +V A -65 +W y -15 +W u -36 +W ; -7 +W . -65 +W o -48 +W - -32 +W hy -32 +W char173 -32 +W e -28 +W , -65 +W : -7 +W a -32 +W O -15 +W A -48 +Y u -81 +Y ; -40 +Y . -81 +Y o -81 +Y e -65 +Y , -81 +Y : -40 +Y a -73 +Y O -56 +Y A -89 +a y -15 +a w -11 +a v -11 +a g -7 +b y -15 +b v -15 +b u -15 +b l -7 +c y -7 +c l -15 +c k -15 +c h -7 +, ' -97 +, rq -97 +d y -11 +d w -11 +d v -11 +d d -7 +e y -11 +e x -11 +e w -11 +e v -11 +e . 16 +e , 8 +f ' 25 +f rq 25 +f . -7 +f o -15 +f e -7 +f , -7 +g g -7 +g e 8 +h y -15 +k o -11 +l y -11 +l w -11 +m y -24 +m u -15 +n y -15 +n v -32 +n u -7 +o y -15 +o x -24 +o w -11 +o v -15 +p y -11 +. ' -97 +. rq -97 +` ` -37 +` oq -37 +oq ` -37 +oq oq -37 +' v -15 +' s -48 +' r -32 +' ' -37 +' l -15 +' d -65 +r y 8 +r v 8 +r t 16 +r s -11 +r q -15 +r . -48 +r o -15 +r - -15 +r hy -15 +r char173 -15 +r g -11 +r d -15 +r , -48 +r c -15 +s w -11 +v . -65 +v o -24 +v , -65 +v a -15 +w . -32 +w o -15 +w , -32 +x e -7 +y . -65 +y o -20 +y e -7 +y , -65 +y a -24 +z e 8 +charset +ha 479,698 2 0000 asciicircum +ti 479,343 0 0001 asciitilde +vS 547,936,19 2 0002 Scaron +vZ 501,936 2 0003 Zcaron +vs 456,750,14 2 0004 scaron +vz 410,750 2 0005 zcaron +:Y 547,915 2 0006 Ydieresis +tm 820,718 2 0007 trademark +aq 195,718 2 0010 quotesingle +space 228 0 0040 +! 273,718 2 0041 exclam +" 389,718 2 0042 quotedbl +# 456,698 2 0043 numbersign +sh " +$ 456,775,115 2 0044 dollar +Do " +% 729,710,19 2 0045 percent +& 592,718,19 2 0046 ampersand +' 228,718 2 0047 quoteright +( 273,734,208 3 0050 parenleft +) 273,734,208 3 0051 parenright +* 319,718 2 0052 asterisk ++ 479,506 0 0053 plus +, 228,146,168 0 0054 comma +- 273,345 0 0055 hyphen +hy " +char173 " +. 228,146 0 0056 period +/ 228,737,19 2 0057 slash +sl " +0 456,710,19 2 0060 zero +1 456,710 2 0061 one +2 456,710 2 0062 two +3 456,710,19 2 0063 three +4 456,710 2 0064 four +5 456,698,19 2 0065 five +6 456,710,19 2 0066 six +7 456,698 2 0067 seven +8 456,710,19 2 0070 eight +9 456,710,19 2 0071 nine +: 273,512 0 0072 colon +; 273,512,168 0 0073 semicolon +< 479,514,8 0 0074 less += 479,419 0 0075 equal +> 479,514,8 0 0076 greater +? 501,727 2 0077 question +@ 800,737,19 2 0100 at +at " +A 592,718 2 0101 A +B 592,718 2 0102 B +C 592,737,19 2 0103 C +D 592,718 2 0104 D +E 547,718 2 0105 E +F 501,718 2 0106 F +G 638,737,19 2 0107 G +H 592,718 2 0110 H +I 228,718 2 0111 I +J 456,718,18 2 0112 J +K 592,718 2 0113 K +L 501,718 2 0114 L +M 683,718 2 0115 M +N 592,718 2 0116 N +O 638,737,19 2 0117 O +P 547,718 2 0120 P +Q 638,737,52 2 0121 Q +R 592,718 2 0122 R +S 547,737,19 2 0123 S +T 501,718 2 0124 T +U 592,718,19 2 0125 U +V 547,718 2 0126 V +W 774,718 2 0127 W +X 547,718 2 0130 X +Y 547,718 2 0131 Y +Z 501,718 2 0132 Z +[ 273,722,196 2 0133 bracketleft +lB " +\ 228,737,19 2 0134 backslash +rs " +] 273,722,196 2 0135 bracketright +rB " +a^ 273,750 2 0136 circumflex +^ " +_ 456,0,125 0 0137 underscore +` 228,727 2 0140 quoteleft +oq " +a 456,546,14 0 0141 a +b 501,718,14 2 0142 b +c 456,546,14 0 0143 c +d 501,718,14 2 0144 d +e 456,546,14 0 0145 e +f 273,727 2 0146 f +g 501,546,217 1 0147 g +h 501,718 2 0150 h +i 228,725 2 0151 i +j 228,725,214 3 0152 j +k 456,718 2 0153 k +l 228,718 2 0154 l +m 729,546 0 0155 m +n 501,546 0 0156 n +o 501,546,14 0 0157 o +p 501,546,207 1 0160 p +q 501,546,207 1 0161 q +r 319,546 0 0162 r +s 456,546,14 0 0163 s +t 273,676,6 2 0164 t +u 501,532,14 0 0165 u +v 456,532 0 0166 v +w 638,532 0 0167 w +x 456,532 0 0170 x +y 456,532,214 1 0171 y +z 410,532 0 0172 z +lC 319,722,196 2 0173 braceleft +{ " +ba 230,737,19 2 0174 bar +| " +rC 319,722,196 2 0175 braceright +} " +a~ 273,737 2 0176 tilde +~ " +bq 228,127,146 0 0200 quotesinglbase +Fo 456,484 0 0201 guillemotleft +char171 " +Fc 456,484 0 0202 guillemotright +char187 " +bu 287,524 0 0203 bullet +Fn 456,737,210 3 0204 florin +f/ 137,710,19 2 0205 fraction +%0 820,710,19 2 0206 perthousand +dg 456,718,171 2 0207 dagger +dd 456,718,171 2 0210 daggerdbl +en 456,333 0 0211 endash +em 820,333 0 0212 emdash +fi 501,727 2 0214 fi +fl 501,727 2 0215 fl +.i 228,532 0 0220 dotlessi +ga 273,750 2 0222 grave +a" 273,750 2 0223 hungarumlaut +a. 273,729 2 0224 dotaccent +ab 273,750 2 0225 breve +ah 273,750 2 0226 caron +ao 273,776 2 0227 ring +ho 273,0,228 1 0230 ogonek +lq 410,727 2 0231 quotedblleft +rq 410,718 2 0232 quotedblright +oe 774,546,14 0 0233 oe +/l 228,718 2 0234 lslash +Bq 410,127,146 0 0235 quotedblbase +OE 820,737,19 2 0236 OE +/L 501,718 2 0237 Lslash +r! 273,532,186 0 0241 exclamdown +char161 " +ct 456,628,118 0 0242 cent +char162 " +Po 456,718,16 2 0243 sterling +char163 " +Cs 456,636 0 0244 currency +char164 " +Ye 456,698 2 0245 yen +char165 " +bb 230,737,19 2 0246 brokenbar +char166 " +sc 456,727,184 2 0247 section +char167 " +ad 273,729 2 0250 dieresis +char168 " +co 604,737,19 2 0251 copyright +char169 " +Of 303,737 2 0252 ordfeminine +char170 " +fo 273,484 0 0253 guilsinglleft +no 479,419 0 0254 logicalnot +char172 " +\- 479,309 0 0255 minus +rg 604,737,19 2 0256 registered +char174 " +a- 273,678 2 0257 macron +char175 " +de 328,712 2 0260 degree +char176 " +char177 479,506 0 0261 plusminus +S2 273,710 2 0262 twosuperior +char178 " +S3 273,710 2 0263 threesuperior +char179 " +aa 273,750 2 0264 acute +char180 " +char181 501,532,207 1 0265 mu +ps 456,700,191 2 0266 paragraph +char182 " +char183 228,334 0 0267 periodcentered +ac 273,0,228 1 0270 cedilla +char184 " +S1 273,710 2 0271 onesuperior +char185 " +Om 299,737 2 0272 ordmasculine +char186 " +fc 273,484 0 0273 guilsinglright +14 684,710,19 2 0274 onequarter +char188 " +12 684,710,19 2 0275 onehalf +char189 " +34 684,710,19 2 0276 threequarters +char190 " +r? 501,532,195 0 0277 questiondown +char191 " +`A 592,936 2 0300 Agrave +char192 " +'A 592,936 2 0301 Aacute +char193 " +^A 592,936 2 0302 Acircumflex +char194 " +~A 592,923 2 0303 Atilde +char195 " +:A 592,915 2 0304 Adieresis +char196 " +oA 592,962 2 0305 Aring +char197 " +AE 820,718 2 0306 AE +char198 " +,C 592,737,228 3 0307 Ccedilla +char199 " +`E 547,936 2 0310 Egrave +char200 " +'E 547,936 2 0311 Eacute +char201 " +^E 547,936 2 0312 Ecircumflex +char202 " +:E 547,915 2 0313 Edieresis +char203 " +`I 228,936 2 0314 Igrave +char204 " +'I 228,936 2 0315 Iacute +char205 " +^I 228,936 2 0316 Icircumflex +char206 " +:I 228,915 2 0317 Idieresis +char207 " +-D 592,718 2 0320 Eth +char208 " +~N 592,923 2 0321 Ntilde +char209 " +`O 638,936,19 2 0322 Ograve +char210 " +'O 638,936,19 2 0323 Oacute +char211 " +^O 638,936,19 2 0324 Ocircumflex +char212 " +~O 638,923,19 2 0325 Otilde +char213 " +:O 638,915,19 2 0326 Odieresis +char214 " +char215 479,505 0 0327 multiply +/O 638,745,27 2 0330 Oslash +char216 " +`U 592,936,19 2 0331 Ugrave +char217 " +'U 592,936,19 2 0332 Uacute +char218 " +^U 592,936,19 2 0333 Ucircumflex +char219 " +:U 592,915,19 2 0334 Udieresis +char220 " +'Y 547,936 2 0335 Yacute +char221 " +TP 547,718 2 0336 Thorn +char222 " +ss 501,731,14 2 0337 germandbls +char223 " +`a 456,750,14 2 0340 agrave +char224 " +'a 456,750,14 2 0341 aacute +char225 " +^a 456,750,14 2 0342 acircumflex +char226 " +~a 456,737,14 2 0343 atilde +char227 " +:a 456,729,14 2 0344 adieresis +char228 " +oa 456,776,14 2 0345 aring +char229 " +ae 729,546,14 0 0346 ae +char230 " +,c 456,546,228 1 0347 ccedilla +char231 " +`e 456,750,14 2 0350 egrave +char232 " +'e 456,750,14 2 0351 eacute +char233 " +^e 456,750,14 2 0352 ecircumflex +char234 " +:e 456,729,14 2 0353 edieresis +char235 " +`i 228,750 2 0354 igrave +char236 " +'i 228,750 2 0355 iacute +char237 " +^i 228,750 2 0356 icircumflex +char238 " +:i 228,729 2 0357 idieresis +char239 " +Sd 501,737,14 2 0360 eth +char240 " +~n 501,737 2 0361 ntilde +char241 " +`o 501,750,14 2 0362 ograve +char242 " +'o 501,750,14 2 0363 oacute +char243 " +^o 501,750,14 2 0364 ocircumflex +char244 " +~o 501,737,14 2 0365 otilde +char245 " +:o 501,729,14 2 0366 odieresis +char246 " +char247 479,548,42 0 0367 divide +/o 501,560,29 0 0370 oslash +char248 " +`u 501,750,14 2 0371 ugrave +char249 " +'u 501,750,14 2 0372 uacute +char250 " +^u 501,750,14 2 0373 ucircumflex +char251 " +:u 501,729,14 2 0374 udieresis +char252 " +'y 456,750,214 3 0375 yacute +char253 " +Tp 501,718,208 3 0376 thorn +char254 " +:y 456,729,214 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/HNBI b/gnu/usr.bin/groff/devices/devps/HNBI new file mode 100644 index 0000000000..c0bb37eea4 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/HNBI @@ -0,0 +1,547 @@ +name HNBI +internalname Helvetica-Narrow-BoldOblique +slant 12 +spacewidth 228 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -30 +A w -30 +A v -40 +A u -30 +A Y -110 +A W -60 +A V -80 +A U -50 +A T -90 +A Q -40 +A O -40 +A G -50 +A C -40 +B U -10 +B A -30 +D . -30 +D , -30 +D Y -70 +D W -40 +D V -40 +D A -40 +F . -100 +F , -100 +F a -20 +F A -80 +J u -20 +J . -20 +J , -20 +J A -20 +K y -40 +K u -30 +K o -35 +K e -15 +K O -30 +L y -30 +L ' -140 +L rq -140 +L Y -120 +L W -80 +L V -110 +L T -90 +O . -40 +O , -40 +O Y -70 +O X -50 +O W -50 +O V -50 +O T -40 +O A -50 +P . -120 +P o -40 +P e -30 +P , -120 +P a -30 +P A -100 +Q . 20 +Q , 20 +Q U -10 +R Y -50 +R W -40 +R V -50 +R U -20 +R T -20 +R O -20 +T y -60 +T w -60 +T u -90 +T ; -40 +T r -80 +T . -80 +T o -80 +T - -120 +T hy -120 +T char173 -120 +T e -60 +T , -80 +T : -40 +T a -80 +T O -40 +T A -90 +U . -30 +U , -30 +U A -50 +V u -60 +V ; -40 +V . -120 +V o -90 +V - -80 +V hy -80 +V char173 -80 +V e -50 +V , -120 +V : -40 +V a -60 +V O -50 +V G -50 +V A -80 +W y -20 +W u -45 +W ; -10 +W . -80 +W o -60 +W - -40 +W hy -40 +W char173 -40 +W e -35 +W , -80 +W : -10 +W a -40 +W O -20 +W A -60 +Y u -100 +Y ; -50 +Y . -100 +Y o -100 +Y e -80 +Y , -100 +Y : -50 +Y a -90 +Y O -70 +Y A -110 +a y -20 +a w -15 +a v -15 +a g -10 +b y -20 +b v -20 +b u -20 +b l -10 +c y -10 +c l -20 +c k -20 +c h -10 +, ' -120 +, rq -120 +d y -15 +d w -15 +d v -15 +d d -10 +e y -15 +e x -15 +e w -15 +e v -15 +e . 20 +e , 10 +f ' 30 +f rq 30 +f . -10 +f o -20 +f e -10 +f , -10 +g g -10 +g e 10 +h y -20 +k o -15 +l y -15 +l w -15 +m y -30 +m u -20 +n y -20 +n v -40 +n u -10 +o y -20 +o x -30 +o w -15 +o v -20 +p y -15 +. ' -120 +. rq -120 +` ` -46 +` oq -46 +oq ` -46 +oq oq -46 +' v -20 +' s -60 +' r -40 +' ' -46 +' l -20 +' d -80 +r y 10 +r v 10 +r t 20 +r s -15 +r q -20 +r . -60 +r o -20 +r - -20 +r hy -20 +r char173 -20 +r g -15 +r d -20 +r , -60 +r c -20 +s w -15 +v . -80 +v o -30 +v , -80 +v a -20 +w . -40 +w o -20 +w , -40 +x e -10 +y . -80 +y o -25 +y e -10 +y , -80 +y a -30 +z e 10 +charset +ha 479,698,0,55,-57,55 2 0000 asciicircum +ti 479,343,0,44,-44,44 0 0001 asciitilde +vS 547,936,19,91,-16,90 2 0002 Scaron +vZ 501,936,0,153,30,90 2 0003 Zcaron +vs 456,750,14,98,-2,90 2 0004 scaron +vz 410,750,0,121,34,90 2 0005 zcaron +:Y 547,915,0,164,-87,90 2 0006 Ydieresis +tm 820,718,0,139,-96,90 2 0007 trademark +aq 195,718,0,118,-85,90 2 0010 quotesingle +space 228 0 0040 +! 273,718,0,102,-27,90 2 0041 exclam +" 389,718,0,94,-108,90 2 0042 quotedbl +# 456,698,0,122,1,90 2 0043 numbersign +sh " +$ 456,775,115,104,-5,90 2 0044 dollar +Do " +% 729,710,19,60,-62,60 2 0045 percent +& 592,718,19,58,-23,58 2 0046 ampersand +' 228,718,0,119,-87,90 2 0047 quoteright +( 273,734,208,162,-12,90 3 0050 parenleft +) 273,734,208,79,71,79 3 0051 parenright +* 319,718,0,125,-70,90 2 0052 asterisk ++ 479,506,0,71,-17,71 0 0053 plus +, 228,146,168,23,27,23 0 0054 comma +- 273,345,0,88,-10,88 0 0055 hyphen +hy " +char173 " +. 228,146,0,23,-2,23 0 0056 period +/ 228,737,19,205,80,90 2 0057 slash +sl " +0 456,710,19,100,-21,90 2 0060 zero +1 456,710,0,28,-92,28 2 0061 one +2 456,710,0,102,29,90 2 0062 two +3 456,710,19,93,-4,90 2 0063 three +4 456,710,0,84,0,84 2 0064 four +5 456,698,19,116,-3,90 2 0065 five +6 456,710,19,101,-20,90 2 0066 six +7 456,698,0,149,-52,90 2 0067 seven +8 456,710,19,99,-7,90 2 0070 eight +9 456,710,19,98,-14,90 2 0071 nine +: 273,512,0,65,-25,65 0 0072 colon +; 273,512,168,65,4,65 0 0073 semicolon +< 479,514,8,108,-17,90 0 0074 less += 479,419,0,90,2,90 0 0075 equal +> 479,514,8,71,20,71 0 0076 greater +? 501,727,0,99,-85,90 2 0077 question +@ 800,737,19,32,-102,32 2 0100 at +at " +A 592,718,0,34,34,34 2 0101 A +B 592,718,0,84,-12,84 2 0102 B +C 592,737,19,105,-38,90 2 0103 C +D 592,718,0,95,-12,90 2 0104 D +E 547,718,0,123,-12,90 2 0105 E +F 501,718,0,155,-12,90 2 0106 F +G 638,737,19,82,-39,82 2 0107 G +H 592,718,0,117,-8,90 2 0110 H +I 228,718,0,123,-2,90 2 0111 I +J 456,718,18,116,1,90 2 0112 J +K 592,718,0,161,-21,90 2 0113 K +L 501,718,0,50,-12,50 2 0114 L +M 683,718,0,119,-7,90 2 0115 M +N 592,718,0,119,-7,90 2 0116 N +O 638,737,19,87,-38,87 2 0117 O +P 547,718,0,108,-12,90 2 0120 P +Q 638,737,52,87,-38,87 2 0121 Q +R 592,718,0,96,-12,90 2 0122 R +S 547,737,19,91,-16,90 2 0123 S +T 501,718,0,164,-64,90 2 0124 T +U 592,718,19,117,-46,90 2 0125 U +V 547,718,0,159,-91,90 2 0126 V +W 774,718,0,163,-88,90 2 0127 W +X 547,718,0,151,39,90 2 0130 X +Y 547,718,0,164,-87,90 2 0131 Y +Z 501,718,0,153,30,90 2 0132 Z +[ 273,722,196,156,33,90 2 0133 bracketleft +lB " +\ 228,737,19,74,-51,74 2 0134 backslash +rs " +] 273,722,196,124,64,90 2 0135 bracketright +rB " +a^ 273,750,0,164,-47,90 2 0136 circumflex +^ " +_ 456,0,125,37,72,37 0 0137 underscore +` 228,727,0,118,-86,90 2 0140 quoteleft +oq " +a 456,546,14,72,5,72 0 0141 a +b 501,718,14,78,0,78 2 0142 b +c 456,546,14,85,-15,85 0 0143 c +d 501,718,14,126,-17,90 2 0144 d +e 456,546,14,80,-8,80 0 0145 e +f 273,727,0,162,-21,90 2 0146 f +g 501,546,217,95,19,90 1 0147 g +h 501,718,0,65,-3,65 2 0150 h +i 228,725,0,120,-7,90 2 0151 i +j 228,725,214,120,85,90 3 0152 j +k 456,718,0,143,-7,90 2 0153 k +l 228,718,0,119,-7,90 2 0154 l +m 729,546,0,67,-2,67 0 0155 m +n 501,546,0,65,-3,65 0 0156 n +o 501,546,14,76,-17,76 0 0157 o +p 501,546,207,78,35,78 1 0160 p +q 501,546,207,94,-16,90 1 0161 q +r 319,546,0,132,-2,90 0 0162 r +s 456,546,14,73,-2,73 0 0163 s +t 273,676,6,123,-32,90 2 0164 t +u 501,532,14,89,-30,89 0 0165 u +v 456,532,0,132,-53,90 0 0166 v +w 638,532,0,135,-51,90 0 0167 w +x 456,532,0,125,38,90 0 0170 x +y 456,532,214,129,16,90 1 0171 y +z 410,532,0,118,34,90 0 0172 z +lC 319,722,196,156,-27,90 2 0173 braceleft +{ " +ba 230,737,19,109,-16,90 2 0174 bar +| " +rC 319,722,196,64,64,64 2 0175 braceright +} " +a~ 273,737,0,192,-42,90 2 0176 tilde +~ " +bq 228,127,146,16,16,16 0 0200 quotesinglbase +Fo 456,484,0,62,-61,62 0 0201 guillemotleft +char171 " +Fc 456,484,0,37,-35,37 0 0202 guillemotright +char187 " +bu 287,524,0,108,-18,90 0 0203 bullet +Fn 456,737,210,142,91,90 3 0204 florin +f/ 137,710,19,312,193,90 2 0205 fraction +%0 820,710,19,81,-12,81 2 0206 perthousand +dg 456,718,171,107,-47,90 2 0207 dagger +dd 456,718,171,109,12,90 2 0210 daggerdbl +en 456,333,0,108,10,90 0 0211 endash +em 820,333,0,108,10,90 0 0212 emdash +fi 501,727,0,120,-21,90 2 0214 fi +fl 501,727,0,119,-21,90 2 0215 fl +.i 228,532,0,86,-7,86 0 0220 dotlessi +ga 273,750,0,67,-62,67 2 0222 grave +a" 273,750,0,306,-63,90 2 0223 hungarumlaut +a. 273,729,0,93,-142,90 2 0224 dotaccent +ab 273,750,0,182,-78,90 2 0225 breve +ah 273,750,0,189,-73,90 2 0226 caron +ao 273,776,0,121,-114,90 2 0227 ring +ho 273,0,228,0,17 1 0230 ogonek +lq 410,727,0,122,-82,90 2 0231 quotedblleft +rq 410,718,0,123,-82,90 2 0232 quotedblright +oe 774,546,14,77,-17,77 0 0233 oe +/l 228,718,0,156,17,90 2 0234 lslash +Bq 410,127,146,20,21,20 0 0235 quotedblbase +OE 820,737,19,143,-31,90 2 0236 OE +/L 501,718,0,50,22,50 2 0237 Lslash +r! 273,532,186,67,9,67 0 0241 exclamdown +char161 " +ct 456,628,118,85,-15,85 0 0242 cent +char162 " +Po 456,718,16,114,9,90 2 0243 sterling +char163 " +Cs 456,636,0,152,28,90 0 0244 currency +char164 " +Ye 456,698,0,179,1,90 2 0245 yen +char165 " +bb 230,737,19,109,-16,90 2 0246 brokenbar +char166 " +sc 456,727,184,85,0,85 2 0247 section +char167 " +ad 273,729,0,172,-62,90 2 0250 dieresis +char168 " +co 604,737,19,131,4,90 2 0251 copyright +char169 " +Of 303,737,0,128,-25,90 2 0252 ordfeminine +char170 " +fo 273,484,0,66,-56,66 0 0253 guilsinglleft +no 479,419,0,90,-36,90 0 0254 logicalnot +char172 " +\- 479,309,0,71,-17,71 0 0255 minus +rg 604,737,19,130,5,90 2 0256 registered +char174 " +a- 273,678,0,173,-50,90 2 0257 macron +char175 " +de 328,712,0,105,-93,90 2 0260 degree +char176 " +char177 479,506,0,83,17,83 0 0261 plusminus +S2 273,710,0,145,-7,90 2 0262 twosuperior +char178 " +S3 273,710,0,138,-25,90 2 0263 threesuperior +char179 " +aa 273,750,0,200,-144,90 2 0264 acute +char180 " +char181 501,532,207,89,32,89 1 0265 mu +ps 456,700,191,158,-30,90 2 0266 paragraph +char182 " +char183 228,334,0,48,-40,48 0 0267 periodcentered +ac 273,0,228,0,80 1 0270 cedilla +char184 " +S1 273,710,0,95,-71,90 2 0271 onesuperior +char185 " +Om 299,737,0,149,-25,90 2 0272 ordmasculine +char186 " +fc 273,484,0,41,-31,41 0 0273 guilsinglright +14 684,710,19,27,-58,27 2 0274 onequarter +char188 " +12 684,710,19,70,-58,70 2 0275 onehalf +char189 " +34 684,710,19,54,-32,54 2 0276 threequarters +char190 " +r? 501,532,195,8,6,8 0 0277 questiondown +char191 " +`A 592,936,0,34,34,34 2 0300 Agrave +char192 " +'A 592,936,0,73,34,73 2 0301 Aacute +char193 " +^A 592,936,0,37,34,37 2 0302 Acircumflex +char194 " +~A 592,923,0,66,34,66 2 0303 Atilde +char195 " +:A 592,915,0,46,34,46 2 0304 Adieresis +char196 " +oA 592,962,0,34,34,34 2 0305 Aring +char197 " +AE 820,718,0,132,46,90 2 0306 AE +char198 " +,C 592,737,228,105,-38,90 3 0307 Ccedilla +char199 " +`E 547,936,0,123,-12,90 2 0310 Egrave +char200 " +'E 547,936,0,123,-12,90 2 0311 Eacute +char201 " +^E 547,936,0,123,-12,90 2 0312 Ecircumflex +char202 " +:E 547,915,0,123,-12,90 2 0313 Edieresis +char203 " +`I 228,936,0,123,-2,90 2 0314 Igrave +char204 " +'I 228,936,0,255,-2,90 2 0315 Iacute +char205 " +^I 228,936,0,219,-2,90 2 0316 Icircumflex +char206 " +:I 228,915,0,227,-2,90 2 0317 Idieresis +char207 " +-D 592,718,0,95,-1,90 2 0320 Eth +char208 " +~N 592,923,0,119,-7,90 2 0321 Ntilde +char209 " +`O 638,936,19,87,-38,87 2 0322 Ograve +char210 " +'O 638,936,19,87,-38,87 2 0323 Oacute +char211 " +^O 638,936,19,87,-38,87 2 0324 Ocircumflex +char212 " +~O 638,923,19,87,-38,87 2 0325 Otilde +char213 " +:O 638,915,19,87,-38,87 2 0326 Odieresis +char214 " +char215 479,505,0,91,3,90 0 0327 multiply +/O 638,745,27,145,21,90 2 0330 Oslash +char216 " +`U 592,936,19,117,-46,90 2 0331 Ugrave +char217 " +'U 592,936,19,117,-46,90 2 0332 Uacute +char218 " +^U 592,936,19,117,-46,90 2 0333 Ucircumflex +char219 " +:U 592,915,19,117,-46,90 2 0334 Udieresis +char220 " +'Y 547,936,0,164,-87,90 2 0335 Yacute +char221 " +TP 547,718,0,91,-12,90 2 0336 Thorn +char222 " +ss 501,731,14,88,-7,88 2 0337 germandbls +char223 " +`a 456,750,14,72,5,72 2 0340 agrave +char224 " +'a 456,750,14,108,5,90 2 0341 aacute +char225 " +^a 456,750,14,72,5,72 2 0342 acircumflex +char226 " +~a 456,737,14,101,5,90 2 0343 atilde +char227 " +:a 456,729,14,81,5,81 2 0344 adieresis +char228 " +oa 456,776,14,72,5,72 2 0345 aring +char229 " +ae 729,546,14,78,4,78 0 0346 ae +char230 " +,c 456,546,228,85,-15,85 1 0347 ccedilla +char231 " +`e 456,750,14,80,-8,80 2 0350 egrave +char232 " +'e 456,750,14,108,-8,90 2 0351 eacute +char233 " +^e 456,750,14,80,-8,80 2 0352 ecircumflex +char234 " +:e 456,729,14,81,-8,81 2 0353 edieresis +char235 " +`i 228,750,0,90,-7,90 2 0354 igrave +char236 " +'i 228,750,0,222,-7,90 2 0355 iacute +char237 " +^i 228,750,0,186,-7,90 2 0356 icircumflex +char238 " +:i 228,729,0,195,-7,90 2 0357 idieresis +char239 " +Sd 501,737,14,98,-17,90 2 0360 eth +char240 " +~n 501,737,0,78,-3,78 2 0361 ntilde +char241 " +`o 501,750,14,76,-17,76 2 0362 ograve +char242 " +'o 501,750,14,86,-17,86 2 0363 oacute +char243 " +^o 501,750,14,76,-17,76 2 0364 ocircumflex +char244 " +~o 501,737,14,78,-17,78 2 0365 otilde +char245 " +:o 501,729,14,76,-17,76 2 0366 odieresis +char246 " +char247 479,548,42,71,-17,71 0 0367 divide +/o 501,560,29,124,32,90 0 0370 oslash +char248 " +`u 501,750,14,89,-30,89 2 0371 ugrave +char249 " +'u 501,750,14,89,-30,89 2 0372 uacute +char250 " +^u 501,750,14,89,-30,89 2 0373 ucircumflex +char251 " +:u 501,729,14,89,-30,89 2 0374 udieresis +char252 " +'y 456,750,214,129,16,90 3 0375 yacute +char253 " +Tp 501,718,208,78,35,78 3 0376 thorn +char254 " +:y 456,729,214,129,16,90 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/HNI b/gnu/usr.bin/groff/devices/devps/HNI new file mode 100644 index 0000000000..e9ded2f04d --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/HNI @@ -0,0 +1,617 @@ +name HNI +internalname Helvetica-Narrow-Oblique +slant 12 +spacewidth 228 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -40 +A w -40 +A v -40 +A u -30 +A Y -100 +A W -50 +A V -70 +A U -50 +A T -120 +A Q -30 +A O -30 +A G -30 +A C -30 +B . -20 +B , -20 +B U -10 +C . -30 +C , -30 +D . -70 +D , -70 +D Y -90 +D W -40 +D V -70 +D A -40 +F r -45 +F . -150 +F o -30 +F e -30 +F , -150 +F a -50 +F A -80 +J u -20 +J . -30 +J , -30 +J a -20 +J A -20 +K y -50 +K u -30 +K o -40 +K e -40 +K O -50 +L y -30 +L ' -160 +L rq -140 +L Y -140 +L W -70 +L V -110 +L T -110 +O . -40 +O , -40 +O Y -70 +O X -60 +O W -30 +O V -50 +O T -40 +O A -20 +P . -180 +P o -50 +P e -50 +P , -180 +P a -40 +P A -120 +Q U -10 +R Y -50 +R W -30 +R V -50 +R U -40 +R T -30 +R O -20 +S . -20 +S , -20 +T y -120 +T w -120 +T u -120 +T ; -20 +T r -120 +T . -120 +T o -120 +T - -140 +T hy -140 +T char173 -140 +T e -120 +T , -120 +T : -20 +T a -120 +T O -40 +T A -120 +U . -40 +U , -40 +U A -40 +V u -70 +V ; -40 +V . -125 +V o -80 +V - -80 +V hy -80 +V char173 -80 +V e -80 +V , -125 +V : -40 +V a -70 +V O -40 +V G -40 +V A -80 +W y -20 +W u -30 +W . -80 +W o -30 +W - -40 +W hy -40 +W char173 -40 +W e -30 +W , -80 +W a -40 +W O -20 +W A -50 +Y u -110 +Y ; -60 +Y . -140 +Y o -140 +Y i -20 +Y - -140 +Y hy -140 +Y char173 -140 +Y e -140 +Y , -140 +Y : -60 +Y a -140 +Y O -85 +Y A -110 +a y -30 +a w -20 +a v -20 +b y -20 +b v -20 +b u -20 +b . -40 +b l -20 +b , -40 +b b -10 +c k -20 +c , -15 +, ' -100 +, rq -100 +e y -20 +e x -30 +e w -20 +e v -30 +e . -15 +e , -15 +f ' 50 +f rq 60 +f . -30 +f o -30 +f e -30 +f .i -28 +f , -30 +f a -30 +g r -10 +h y -30 +k o -20 +k e -20 +m y -15 +m u -10 +n y -15 +n v -20 +n u -10 +o y -30 +o x -30 +o w -15 +o v -15 +o . -40 +o , -40 +/o z -55 +char248 z -55 +/o y -70 +char248 y -70 +/o x -85 +char248 x -85 +/o w -70 +char248 w -70 +/o v -70 +char248 v -70 +/o u -55 +char248 u -55 +/o t -55 +char248 t -55 +/o s -55 +char248 s -55 +/o r -55 +char248 r -55 +/o q -55 +char248 q -55 +/o . -95 +char248 . -95 +/o p -55 +char248 p -55 +/o o -55 +char248 o -55 +/o n -55 +char248 n -55 +/o m -55 +char248 m -55 +/o l -55 +char248 l -55 +/o k -55 +char248 k -55 +/o j -55 +char248 j -55 +/o i -55 +char248 i -55 +/o h -55 +char248 h -55 +/o g -55 +char248 g -55 +/o f -55 +char248 f -55 +/o e -55 +char248 e -55 +/o d -55 +char248 d -55 +/o , -95 +char248 , -95 +/o c -55 +char248 c -55 +/o b -55 +char248 b -55 +/o a -55 +char248 a -55 +p y -30 +p . -35 +p , -35 +. ' -100 +. rq -100 +` ` -57 +` oq -57 +oq ` -57 +oq oq -57 +' s -50 +' r -50 +' ' -57 +' d -50 +r y 30 +r v 30 +r u 15 +r t 40 +r ; 30 +r . -50 +r p 30 +r n 25 +r m 25 +r l 15 +r k 15 +r i 15 +r , -50 +r : 30 +r a -10 +s w -30 +s . -15 +s , -15 +v . -80 +v o -25 +v e -25 +v , -80 +v a -25 +w . -60 +w o -10 +w e -10 +w , -60 +w a -15 +x e -30 +y . -100 +y o -20 +y e -20 +y , -100 +y a -20 +z o -15 +z e -15 +charset +ha 385,688,0,107,15,89 2 0000 asciicircum +ti 479,326,0,47,-41,47 0 0001 asciitilde +vS 547,929,19,87,-24,87 2 0002 Scaron +vZ 501,929,0,156,31,89 2 0003 Zcaron +vs 410,734,15,93,-2,89 2 0004 scaron +vz 410,734,0,108,25,89 2 0005 zcaron +:Y 547,901,0,164,-87,89 2 0006 Ydieresis +tm 820,718,0,96,-102,89 2 0007 trademark +aq 157,718,0,126,-79,89 2 0010 quotesingle +space 228 0 0040 +! 228,718,0,100,-24,89 2 0041 exclam +" 291,718,0,118,-88,89 2 0042 quotedbl +# 456,688,0,111,-10,89 2 0043 numbersign +sh " +$ 456,775,115,100,-7,89 2 0044 dollar +Do " +% 729,703,19,50,-70,50 2 0045 percent +& 547,718,15,33,-13,33 2 0046 ampersand +' 182,718,0,122,-74,89 2 0047 quoteright +( 273,733,207,149,-39,89 3 0050 parenleft +) 273,733,207,53,57,53 3 0051 parenright +* 319,718,0,120,-85,89 2 0052 asterisk ++ 479,505,0,68,-20,68 0 0053 plus +, 228,106,147,0,4 0 0054 comma +- 273,322,0,70,-27,70 0 0055 hyphen +hy " +char173 " +. 228,106,0,0,-21 0 0056 period +/ 228,737,19,192,67,89 2 0057 slash +sl " +0 456,703,19,93,-27,89 2 0060 zero +1 456,703,0,11,-120,11 2 0061 one +2 456,703,0,100,29,89 2 0062 two +3 456,703,19,94,-11,89 2 0063 three +4 456,703,0,66,0,66 2 0064 four +5 456,688,19,103,-5,89 2 0065 five +6 456,703,19,98,-24,89 2 0066 six +7 456,688,0,143,-62,89 2 0067 seven +8 456,703,19,91,-10,89 2 0070 eight +9 456,703,19,93,-17,89 2 0071 nine +: 228,516,0,69,-21,69 0 0072 colon +; 228,516,147,69,4,69 0 0073 semicolon +< 479,495,0,97,-27,89 0 0074 less += 479,390,0,86,-2,86 0 0075 equal +> 479,495,0,61,9,61 0 0076 greater +? 456,727,0,94,-82,89 2 0077 question +@ 832,737,19,9,-126,9 2 0100 at +at " +A 547,718,0,39,39,39 2 0101 A +B 547,718,0,86,-11,86 2 0102 B +C 592,737,19,98,-38,89 2 0103 C +D 592,718,0,84,-16,84 2 0104 D +E 547,718,0,128,-21,89 2 0105 E +F 501,718,0,152,-21,89 2 0106 F +G 638,737,19,67,-41,67 2 0107 G +H 592,718,0,113,-13,89 2 0110 H +I 228,718,0,101,-25,89 2 0111 I +J 410,718,19,116,11,89 2 0112 J +K 547,718,0,165,-12,89 2 0113 K +L 456,718,0,49,-12,49 2 0114 L +M 683,718,0,116,-10,89 2 0115 M +N 592,718,0,113,-12,89 2 0116 N +O 638,737,19,89,-36,89 2 0117 O +P 547,718,0,107,-21,89 2 0120 P +Q 638,737,56,89,-36,89 2 0121 Q +R 592,718,0,92,-22,89 2 0122 R +S 547,737,19,87,-24,87 2 0123 S +T 501,718,0,164,-72,89 2 0124 T +U 592,718,19,111,-51,89 2 0125 U +V 547,718,0,159,-92,89 2 0126 V +W 774,718,0,162,-88,89 2 0127 W +X 547,718,0,150,34,89 2 0130 X +Y 547,718,0,164,-87,89 2 0131 Y +Z 501,718,0,156,31,89 2 0132 Z +[ 228,722,196,153,33,89 2 0133 bracketleft +lB " +\ 228,737,19,61,-65,61 2 0134 backslash +rs " +] 228,722,196,124,61,89 2 0135 bracketright +rB " +a^ 273,734,0,136,-71,89 2 0136 circumflex +^ " +_ 456,0,125,37,72,37 0 0137 underscore +` 182,725,0,133,-85,89 2 0140 quoteleft +oq " +a 456,538,15,52,0,52 0 0141 a +b 456,718,15,73,2,73 2 0142 b +c 410,538,15,94,-11,89 0 0143 c +d 456,718,15,128,-19,89 2 0144 d +e 456,538,15,68,-19,68 0 0145 e +f 228,728,0,163,-21,89 2 0146 f +g 456,538,220,94,16,89 1 0147 g +h 456,718,0,64,-3,64 2 0150 h +i 182,718,0,120,-5,89 2 0151 i +j 182,718,210,120,99,89 3 0152 j +k 410,718,0,132,-5,89 2 0153 k +l 182,718,0,120,-5,89 2 0154 l +m 683,538,0,66,-3,66 0 0155 m +n 456,538,0,64,-3,64 0 0156 n +o 456,538,14,73,-18,73 0 0157 o +p 456,538,207,73,39,73 1 0160 p +q 456,538,207,90,-19,89 1 0161 q +r 273,538,0,142,-13,89 0 0162 r +s 410,538,15,74,-2,74 0 0163 s +t 228,669,7,124,-34,89 2 0164 t +u 456,523,15,86,-27,86 0 0165 u +v 410,523,0,135,-48,89 0 0166 v +w 592,523,0,131,-53,89 0 0167 w +x 410,523,0,127,41,89 0 0170 x +y 410,523,214,132,38,89 1 0171 y +z 410,523,0,108,25,89 0 0172 z +lC 274,722,196,141,-25,89 2 0173 braceleft +{ " +ba 213,737,19,102,-24,89 2 0174 bar +| " +rC 274,722,196,67,50,67 2 0175 braceright +} " +a~ 273,722,0,179,-52,89 2 0176 tilde +~ " +bq 182,106,149,15,33,15 0 0200 quotesinglbase +Fo 456,446,0,48,-70,48 0 0201 guillemotleft +char171 " +Fc 456,446,0,27,-48,27 0 0202 guillemotright +char187 " +bu 287,517,0,102,-24,89 0 0203 bullet +Fn 456,737,207,131,93,89 3 0204 florin +f/ 137,703,19,309,189,89 2 0205 fraction +%0 820,703,19,74,-22,74 2 0206 perthousand +dg 456,718,159,104,-60,89 2 0207 dagger +dd 456,718,159,105,7,89 2 0210 daggerdbl +en 456,313,0,104,8,89 0 0211 endash +em 820,313,0,105,8,89 0 0212 emdash +fi 410,728,0,121,-21,89 2 0214 fi +fl 410,728,0,119,-21,89 2 0215 fl +.i 228,523,0,63,-28,63 0 0220 dotlessi +ga 273,734,0,53,-89,53 2 0222 grave +a" 273,734,0,240,-79,89 2 0223 hungarumlaut +a. 273,706,0,74,-154,74 2 0224 dotaccent +ab 273,731,0,168,-87,89 2 0225 breve +ah 273,734,0,161,-95,89 2 0226 caron +ao 273,756,0,107,-125,89 2 0227 ring +ho 273,0,225,0,15 1 0230 ogonek +lq 273,725,0,155,-63,89 2 0231 quotedblleft +rq 273,718,0,144,-52,89 2 0232 quotedblright +oe 774,538,15,67,-18,67 0 0233 oe +/l 182,718,0,152,16,89 2 0234 lslash +Bq 273,106,149,37,55,37 0 0235 quotedblbase +OE 820,737,19,145,-30,89 2 0236 OE +/L 456,718,0,49,16,49 2 0237 Lslash +r! 273,523,195,44,-13,44 0 0241 exclamdown +char161 " +ct 456,623,115,73,-28,73 0 0242 cent +char162 " +Po 456,718,16,114,10,89 2 0243 sterling +char163 " +Cs 456,603,0,124,1,89 0 0244 currency +char164 " +Ye 456,688,0,167,-17,89 2 0245 yen +char165 " +bb 213,737,19,102,-24,89 2 0246 brokenbar +char166 " +sc 456,737,191,73,-13,73 2 0247 section +char167 " +ad 273,706,0,140,-88,89 2 0250 dieresis +char168 " +co 604,737,19,133,6,89 2 0251 copyright +char169 " +Of 303,737,0,115,-32,89 2 0252 ordfeminine +char170 " +fo 273,446,0,56,-62,56 0 0253 guilsinglleft +no 479,390,0,86,-37,86 0 0254 logicalnot +char172 " +\- 479,289,0,68,-20,68 0 0255 minus +rg 604,737,19,133,6,89 2 0256 registered +char174 " +a- 273,684,0,161,-67,89 2 0257 macron +char175 " +de 328,703,0,106,-88,89 2 0260 degree +char176 " +char177 479,506,0,78,18,78 0 0261 plusminus +S2 273,703,0,145,-2,89 2 0262 twosuperior +char178 " +S3 273,703,0,135,-24,89 2 0263 threesuperior +char179 " +aa 273,734,0,167,-153,89 2 0264 acute +char180 " +char181 456,523,207,86,30,86 1 0265 mu +ps 440,718,173,143,-53,89 2 0266 paragraph +char182 " +char183 228,315,0,33,-56,33 0 0267 periodcentered +ac 273,0,225,0,48 1 0270 cedilla +char184 " +S1 273,703,0,82,-86,82 2 0271 onesuperior +char185 " +Om 299,737,0,135,-32,89 2 0272 ordmasculine +char186 " +fc 273,446,0,34,-41,34 0 0273 guilsinglright +14 684,703,19,24,-73,24 2 0274 onequarter +char188 " +12 684,703,19,54,-43,54 2 0275 onehalf +char189 " +34 684,703,19,72,-56,72 2 0276 threequarters +char190 " +r? 501,525,201,0,-20 0 0277 questiondown +char191 " +`A 547,929,0,39,39,39 2 0300 Agrave +char192 " +'A 547,929,0,63,39,63 2 0301 Aacute +char193 " +^A 547,929,0,39,39,39 2 0302 Acircumflex +char194 " +~A 547,917,0,76,39,76 2 0303 Atilde +char195 " +:A 547,901,0,39,39,39 2 0304 Adieresis +char196 " +oA 547,931,0,39,39,39 2 0305 Aring +char197 " +AE 820,718,0,129,43,89 2 0306 AE +char198 " +,C 592,737,225,98,-38,89 3 0307 Ccedilla +char199 " +`E 547,929,0,128,-21,89 2 0310 Egrave +char200 " +'E 547,929,0,128,-21,89 2 0311 Eacute +char201 " +^E 547,929,0,128,-21,89 2 0312 Ecircumflex +char202 " +:E 547,901,0,128,-21,89 2 0313 Edieresis +char203 " +`I 228,929,0,110,-25,89 2 0314 Igrave +char204 " +'I 228,929,0,223,-25,89 2 0315 Iacute +char205 " +^I 228,929,0,193,-25,89 2 0316 Icircumflex +char206 " +:I 228,901,0,197,-25,89 2 0317 Idieresis +char207 " +-D 592,718,0,84,-7,84 2 0320 Eth +char208 " +~N 592,917,0,113,-12,89 2 0321 Ntilde +char209 " +`O 638,929,19,89,-36,89 2 0322 Ograve +char210 " +'O 638,929,19,89,-36,89 2 0323 Oacute +char211 " +^O 638,929,19,89,-36,89 2 0324 Ocircumflex +char212 " +~O 638,917,19,89,-36,89 2 0325 Otilde +char213 " +:O 638,901,19,89,-36,89 2 0326 Odieresis +char214 " +char215 479,506,0,97,9,89 0 0327 multiply +/O 638,737,19,142,15,89 2 0330 Oslash +char216 " +`U 592,929,19,111,-51,89 2 0331 Ugrave +char217 " +'U 592,929,19,111,-51,89 2 0332 Uacute +char218 " +^U 592,929,19,111,-51,89 2 0333 Ucircumflex +char219 " +:U 592,901,19,111,-51,89 2 0334 Udieresis +char220 " +'Y 547,929,0,164,-87,89 2 0335 Yacute +char221 " +TP 547,718,0,87,-21,87 2 0336 Thorn +char222 " +ss 501,728,15,88,-5,88 2 0337 germandbls +char223 " +`a 456,734,15,52,0,52 2 0340 agrave +char224 " +'a 456,734,15,75,0,75 2 0341 aacute +char225 " +^a 456,734,15,52,0,52 2 0342 acircumflex +char226 " +~a 456,722,15,80,0,80 2 0343 atilde +char227 " +:a 456,706,15,52,0,52 2 0344 adieresis +char228 " +oa 456,756,15,52,0,52 2 0345 aring +char229 " +ae 729,538,15,67,0,67 0 0346 ae +char230 " +,c 410,538,225,94,-11,89 1 0347 ccedilla +char231 " +`e 456,734,15,68,-19,68 2 0350 egrave +char232 " +'e 456,734,15,75,-19,75 2 0351 eacute +char233 " +^e 456,734,15,68,-19,68 2 0352 ecircumflex +char234 " +:e 456,706,15,68,-19,68 2 0353 edieresis +char235 " +`i 228,734,0,76,-28,76 2 0354 igrave +char236 " +'i 228,734,0,189,-28,89 2 0355 iacute +char237 " +^i 228,734,0,159,-28,89 2 0356 icircumflex +char238 " +:i 228,706,0,163,-28,89 2 0357 idieresis +char239 " +Sd 456,737,15,100,-17,89 2 0360 eth +char240 " +~n 456,722,0,80,-3,80 2 0361 ntilde +char241 " +`o 456,734,14,73,-18,73 2 0362 ograve +char242 " +'o 456,734,14,75,-18,75 2 0363 oacute +char243 " +^o 456,734,14,73,-18,73 2 0364 ocircumflex +char244 " +~o 456,722,14,88,-18,88 2 0365 otilde +char245 " +:o 456,706,14,73,-18,73 2 0366 odieresis +char246 " +char247 479,524,19,68,-20,68 0 0367 divide +/o 501,545,22,80,26,80 0 0370 oslash +char248 " +`u 456,734,15,86,-27,86 2 0371 ugrave +char249 " +'u 456,734,15,86,-27,86 2 0372 uacute +char250 " +^u 456,734,15,86,-27,86 2 0373 ucircumflex +char251 " +:u 456,706,15,86,-27,86 2 0374 udieresis +char252 " +'y 410,734,214,132,38,89 3 0375 yacute +char253 " +Tp 456,718,207,73,39,73 3 0376 thorn +char254 " +:y 410,706,214,132,38,89 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/HNR b/gnu/usr.bin/groff/devices/devps/HNR new file mode 100644 index 0000000000..ecd911561f --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/HNR @@ -0,0 +1,616 @@ +name HNR +internalname Helvetica-Narrow +spacewidth 228 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -32 +A w -32 +A v -32 +A u -24 +A Y -81 +A W -40 +A V -56 +A U -40 +A T -97 +A Q -24 +A O -24 +A G -24 +A C -24 +B . -15 +B , -15 +B U -7 +C . -24 +C , -24 +D . -56 +D , -56 +D Y -73 +D W -32 +D V -56 +D A -32 +F r -36 +F . -122 +F o -24 +F e -24 +F , -122 +F a -40 +F A -65 +J u -15 +J . -24 +J , -24 +J a -15 +J A -15 +K y -40 +K u -24 +K o -32 +K e -32 +K O -40 +L y -24 +L ' -130 +L rq -114 +L Y -114 +L W -56 +L V -89 +L T -89 +O . -32 +O , -32 +O Y -56 +O X -48 +O W -24 +O V -40 +O T -32 +O A -15 +P . -147 +P o -40 +P e -40 +P , -147 +P a -32 +P A -97 +Q U -7 +R Y -40 +R W -24 +R V -40 +R U -32 +R T -24 +R O -15 +S . -15 +S , -15 +T y -97 +T w -97 +T u -97 +T ; -15 +T r -97 +T . -97 +T o -97 +T - -114 +T hy -114 +T char173 -114 +T e -97 +T , -97 +T : -15 +T a -97 +T O -32 +T A -97 +U . -32 +U , -32 +U A -32 +V u -56 +V ; -32 +V . -102 +V o -65 +V - -65 +V hy -65 +V char173 -65 +V e -65 +V , -102 +V : -32 +V a -56 +V O -32 +V G -32 +V A -65 +W y -15 +W u -24 +W . -65 +W o -24 +W - -32 +W hy -32 +W char173 -32 +W e -24 +W , -65 +W a -32 +W O -15 +W A -40 +Y u -89 +Y ; -48 +Y . -114 +Y o -114 +Y i -15 +Y - -114 +Y hy -114 +Y char173 -114 +Y e -114 +Y , -114 +Y : -48 +Y a -114 +Y O -69 +Y A -89 +a y -24 +a w -15 +a v -15 +b y -15 +b v -15 +b u -15 +b . -32 +b l -15 +b , -32 +b b -7 +c k -15 +c , -11 +, ' -81 +, rq -81 +e y -15 +e x -24 +e w -15 +e v -24 +e . -11 +e , -11 +f ' 41 +f rq 49 +f . -24 +f o -24 +f e -24 +f .i -22 +f , -24 +f a -24 +g r -7 +h y -24 +k o -15 +k e -15 +m y -11 +m u -7 +n y -11 +n v -15 +n u -7 +o y -24 +o x -24 +o w -11 +o v -11 +o . -32 +o , -32 +/o z -44 +char248 z -44 +/o y -56 +char248 y -56 +/o x -69 +char248 x -69 +/o w -56 +char248 w -56 +/o v -56 +char248 v -56 +/o u -44 +char248 u -44 +/o t -44 +char248 t -44 +/o s -44 +char248 s -44 +/o r -44 +char248 r -44 +/o q -44 +char248 q -44 +/o . -77 +char248 . -77 +/o p -44 +char248 p -44 +/o o -44 +char248 o -44 +/o n -44 +char248 n -44 +/o m -44 +char248 m -44 +/o l -44 +char248 l -44 +/o k -44 +char248 k -44 +/o j -44 +char248 j -44 +/o i -44 +char248 i -44 +/o h -44 +char248 h -44 +/o g -44 +char248 g -44 +/o f -44 +char248 f -44 +/o e -44 +char248 e -44 +/o d -44 +char248 d -44 +/o , -77 +char248 , -77 +/o c -44 +char248 c -44 +/o b -44 +char248 b -44 +/o a -44 +char248 a -44 +p y -24 +p . -28 +p , -28 +. ' -81 +. rq -81 +` ` -46 +` oq -46 +oq ` -46 +oq oq -46 +' s -40 +' r -40 +' ' -46 +' d -40 +r y 25 +r v 25 +r u 12 +r t 33 +r ; 25 +r . -40 +r p 25 +r n 21 +r m 21 +r l 12 +r k 12 +r i 12 +r , -40 +r : 25 +r a -7 +s w -24 +s . -11 +s , -11 +v . -65 +v o -20 +v e -20 +v , -65 +v a -20 +w . -48 +w o -7 +w e -7 +w , -48 +w a -11 +x e -24 +y . -81 +y o -15 +y e -15 +y , -81 +y a -15 +z o -11 +z e -11 +charset +ha 385,688 2 0000 asciicircum +ti 479,326 0 0001 asciitilde +vS 547,929,19 2 0002 Scaron +vZ 501,929 2 0003 Zcaron +vs 410,734,15 2 0004 scaron +vz 410,734 2 0005 zcaron +:Y 547,901 2 0006 Ydieresis +tm 820,718 2 0007 trademark +aq 157,718 2 0010 quotesingle +space 228 0 0040 +! 228,718 2 0041 exclam +" 291,718 2 0042 quotedbl +# 456,688 2 0043 numbersign +sh " +$ 456,775,115 2 0044 dollar +Do " +% 729,703,19 2 0045 percent +& 547,718,15 2 0046 ampersand +' 182,718 2 0047 quoteright +( 273,733,207 3 0050 parenleft +) 273,733,207 3 0051 parenright +* 319,718 2 0052 asterisk ++ 479,505 0 0053 plus +, 228,106,147 0 0054 comma +- 273,322 0 0055 hyphen +hy " +char173 " +. 228,106 0 0056 period +/ 228,737,19 2 0057 slash +sl " +0 456,703,19 2 0060 zero +1 456,703 2 0061 one +2 456,703 2 0062 two +3 456,703,19 2 0063 three +4 456,703 2 0064 four +5 456,688,19 2 0065 five +6 456,703,19 2 0066 six +7 456,688 2 0067 seven +8 456,703,19 2 0070 eight +9 456,703,19 2 0071 nine +: 228,516 0 0072 colon +; 228,516,147 0 0073 semicolon +< 479,495 0 0074 less += 479,390 0 0075 equal +> 479,495 0 0076 greater +? 456,727 2 0077 question +@ 832,737,19 2 0100 at +at " +A 547,718 2 0101 A +B 547,718 2 0102 B +C 592,737,19 2 0103 C +D 592,718 2 0104 D +E 547,718 2 0105 E +F 501,718 2 0106 F +G 638,737,19 2 0107 G +H 592,718 2 0110 H +I 228,718 2 0111 I +J 410,718,19 2 0112 J +K 547,718 2 0113 K +L 456,718 2 0114 L +M 683,718 2 0115 M +N 592,718 2 0116 N +O 638,737,19 2 0117 O +P 547,718 2 0120 P +Q 638,737,56 2 0121 Q +R 592,718 2 0122 R +S 547,737,19 2 0123 S +T 501,718 2 0124 T +U 592,718,19 2 0125 U +V 547,718 2 0126 V +W 774,718 2 0127 W +X 547,718 2 0130 X +Y 547,718 2 0131 Y +Z 501,718 2 0132 Z +[ 228,722,196 2 0133 bracketleft +lB " +\ 228,737,19 2 0134 backslash +rs " +] 228,722,196 2 0135 bracketright +rB " +a^ 273,734 2 0136 circumflex +^ " +_ 456,0,125 0 0137 underscore +` 182,725 2 0140 quoteleft +oq " +a 456,538,15 0 0141 a +b 456,718,15 2 0142 b +c 410,538,15 0 0143 c +d 456,718,15 2 0144 d +e 456,538,15 0 0145 e +f 228,728 2 0146 f +g 456,538,220 1 0147 g +h 456,718 2 0150 h +i 182,718 2 0151 i +j 182,718,210 3 0152 j +k 410,718 2 0153 k +l 182,718 2 0154 l +m 683,538 0 0155 m +n 456,538 0 0156 n +o 456,538,14 0 0157 o +p 456,538,207 1 0160 p +q 456,538,207 1 0161 q +r 273,538 0 0162 r +s 410,538,15 0 0163 s +t 228,669,7 2 0164 t +u 456,523,15 0 0165 u +v 410,523 0 0166 v +w 592,523 0 0167 w +x 410,523 0 0170 x +y 410,523,214 1 0171 y +z 410,523 0 0172 z +lC 274,722,196 2 0173 braceleft +{ " +ba 213,737,19 2 0174 bar +| " +rC 274,722,196 2 0175 braceright +} " +a~ 273,722 2 0176 tilde +~ " +bq 182,106,149 0 0200 quotesinglbase +Fo 456,446 0 0201 guillemotleft +char171 " +Fc 456,446 0 0202 guillemotright +char187 " +bu 287,517 0 0203 bullet +Fn 456,737,207 3 0204 florin +f/ 137,703,19 2 0205 fraction +%0 820,703,19 2 0206 perthousand +dg 456,718,159 2 0207 dagger +dd 456,718,159 2 0210 daggerdbl +en 456,313 0 0211 endash +em 820,313 0 0212 emdash +fi 410,728 2 0214 fi +fl 410,728 2 0215 fl +.i 228,523 0 0220 dotlessi +ga 273,734 2 0222 grave +a" 273,734 2 0223 hungarumlaut +a. 273,706 2 0224 dotaccent +ab 273,731 2 0225 breve +ah 273,734 2 0226 caron +ao 273,756 2 0227 ring +ho 273,0,225 1 0230 ogonek +lq 273,725 2 0231 quotedblleft +rq 273,718 2 0232 quotedblright +oe 774,538,15 0 0233 oe +/l 182,718 2 0234 lslash +Bq 273,106,149 0 0235 quotedblbase +OE 820,737,19 2 0236 OE +/L 456,718 2 0237 Lslash +r! 273,523,195 0 0241 exclamdown +char161 " +ct 456,623,115 0 0242 cent +char162 " +Po 456,718,16 2 0243 sterling +char163 " +Cs 456,603 0 0244 currency +char164 " +Ye 456,688 2 0245 yen +char165 " +bb 213,737,19 2 0246 brokenbar +char166 " +sc 456,737,191 2 0247 section +char167 " +ad 273,706 2 0250 dieresis +char168 " +co 604,737,19 2 0251 copyright +char169 " +Of 303,737 2 0252 ordfeminine +char170 " +fo 273,446 0 0253 guilsinglleft +no 479,390 0 0254 logicalnot +char172 " +\- 479,289 0 0255 minus +rg 604,737,19 2 0256 registered +char174 " +a- 273,684 2 0257 macron +char175 " +de 328,703 2 0260 degree +char176 " +char177 479,506 0 0261 plusminus +S2 273,703 2 0262 twosuperior +char178 " +S3 273,703 2 0263 threesuperior +char179 " +aa 273,734 2 0264 acute +char180 " +char181 456,523,207 1 0265 mu +ps 440,718,173 2 0266 paragraph +char182 " +char183 228,315 0 0267 periodcentered +ac 273,0,225 1 0270 cedilla +char184 " +S1 273,703 2 0271 onesuperior +char185 " +Om 299,737 2 0272 ordmasculine +char186 " +fc 273,446 0 0273 guilsinglright +14 684,703,19 2 0274 onequarter +char188 " +12 684,703,19 2 0275 onehalf +char189 " +34 684,703,19 2 0276 threequarters +char190 " +r? 501,525,201 0 0277 questiondown +char191 " +`A 547,929 2 0300 Agrave +char192 " +'A 547,929 2 0301 Aacute +char193 " +^A 547,929 2 0302 Acircumflex +char194 " +~A 547,917 2 0303 Atilde +char195 " +:A 547,901 2 0304 Adieresis +char196 " +oA 547,931 2 0305 Aring +char197 " +AE 820,718 2 0306 AE +char198 " +,C 592,737,225 3 0307 Ccedilla +char199 " +`E 547,929 2 0310 Egrave +char200 " +'E 547,929 2 0311 Eacute +char201 " +^E 547,929 2 0312 Ecircumflex +char202 " +:E 547,901 2 0313 Edieresis +char203 " +`I 228,929 2 0314 Igrave +char204 " +'I 228,929 2 0315 Iacute +char205 " +^I 228,929 2 0316 Icircumflex +char206 " +:I 228,901 2 0317 Idieresis +char207 " +-D 592,718 2 0320 Eth +char208 " +~N 592,917 2 0321 Ntilde +char209 " +`O 638,929,19 2 0322 Ograve +char210 " +'O 638,929,19 2 0323 Oacute +char211 " +^O 638,929,19 2 0324 Ocircumflex +char212 " +~O 638,917,19 2 0325 Otilde +char213 " +:O 638,901,19 2 0326 Odieresis +char214 " +char215 479,506 0 0327 multiply +/O 638,737,19 2 0330 Oslash +char216 " +`U 592,929,19 2 0331 Ugrave +char217 " +'U 592,929,19 2 0332 Uacute +char218 " +^U 592,929,19 2 0333 Ucircumflex +char219 " +:U 592,901,19 2 0334 Udieresis +char220 " +'Y 547,929 2 0335 Yacute +char221 " +TP 547,718 2 0336 Thorn +char222 " +ss 501,728,15 2 0337 germandbls +char223 " +`a 456,734,15 2 0340 agrave +char224 " +'a 456,734,15 2 0341 aacute +char225 " +^a 456,734,15 2 0342 acircumflex +char226 " +~a 456,722,15 2 0343 atilde +char227 " +:a 456,706,15 2 0344 adieresis +char228 " +oa 456,756,15 2 0345 aring +char229 " +ae 729,538,15 0 0346 ae +char230 " +,c 410,538,225 1 0347 ccedilla +char231 " +`e 456,734,15 2 0350 egrave +char232 " +'e 456,734,15 2 0351 eacute +char233 " +^e 456,734,15 2 0352 ecircumflex +char234 " +:e 456,706,15 2 0353 edieresis +char235 " +`i 228,734 2 0354 igrave +char236 " +'i 228,734 2 0355 iacute +char237 " +^i 228,734 2 0356 icircumflex +char238 " +:i 228,706 2 0357 idieresis +char239 " +Sd 456,737,15 2 0360 eth +char240 " +~n 456,722 2 0361 ntilde +char241 " +`o 456,734,14 2 0362 ograve +char242 " +'o 456,734,14 2 0363 oacute +char243 " +^o 456,734,14 2 0364 ocircumflex +char244 " +~o 456,722,14 2 0365 otilde +char245 " +:o 456,706,14 2 0366 odieresis +char246 " +char247 479,524,19 0 0367 divide +/o 501,545,22 0 0370 oslash +char248 " +`u 456,734,15 2 0371 ugrave +char249 " +'u 456,734,15 2 0372 uacute +char250 " +^u 456,734,15 2 0373 ucircumflex +char251 " +:u 456,706,15 2 0374 udieresis +char252 " +'y 410,734,214 3 0375 yacute +char253 " +Tp 456,718,207 3 0376 thorn +char254 " +:y 410,706,214 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/HR b/gnu/usr.bin/groff/devices/devps/HR new file mode 100644 index 0000000000..9dd2687e39 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/HR @@ -0,0 +1,616 @@ +name HR +internalname Helvetica +spacewidth 278 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -40 +A w -40 +A v -40 +A u -30 +A Y -100 +A W -50 +A V -70 +A U -50 +A T -120 +A Q -30 +A O -30 +A G -30 +A C -30 +B . -20 +B , -20 +B U -10 +C . -30 +C , -30 +D . -70 +D , -70 +D Y -90 +D W -40 +D V -70 +D A -40 +F r -45 +F . -150 +F o -30 +F e -30 +F , -150 +F a -50 +F A -80 +J u -20 +J . -30 +J , -30 +J a -20 +J A -20 +K y -50 +K u -30 +K o -40 +K e -40 +K O -50 +L y -30 +L ' -160 +L rq -140 +L Y -140 +L W -70 +L V -110 +L T -110 +O . -40 +O , -40 +O Y -70 +O X -60 +O W -30 +O V -50 +O T -40 +O A -20 +P . -180 +P o -50 +P e -50 +P , -180 +P a -40 +P A -120 +Q U -10 +R Y -50 +R W -30 +R V -50 +R U -40 +R T -30 +R O -20 +S . -20 +S , -20 +T y -120 +T w -120 +T u -120 +T ; -20 +T r -120 +T . -120 +T o -120 +T - -140 +T hy -140 +T char173 -140 +T e -120 +T , -120 +T : -20 +T a -120 +T O -40 +T A -120 +U . -40 +U , -40 +U A -40 +V u -70 +V ; -40 +V . -125 +V o -80 +V - -80 +V hy -80 +V char173 -80 +V e -80 +V , -125 +V : -40 +V a -70 +V O -40 +V G -40 +V A -80 +W y -20 +W u -30 +W . -80 +W o -30 +W - -40 +W hy -40 +W char173 -40 +W e -30 +W , -80 +W a -40 +W O -20 +W A -50 +Y u -110 +Y ; -60 +Y . -140 +Y o -140 +Y i -20 +Y - -140 +Y hy -140 +Y char173 -140 +Y e -140 +Y , -140 +Y : -60 +Y a -140 +Y O -85 +Y A -110 +a y -30 +a w -20 +a v -20 +b y -20 +b v -20 +b u -20 +b . -40 +b l -20 +b , -40 +b b -10 +c k -20 +c , -15 +, ' -100 +, rq -100 +e y -20 +e x -30 +e w -20 +e v -30 +e . -15 +e , -15 +f ' 50 +f rq 60 +f . -30 +f o -30 +f e -30 +f .i -28 +f , -30 +f a -30 +g r -10 +h y -30 +k o -20 +k e -20 +m y -15 +m u -10 +n y -15 +n v -20 +n u -10 +o y -30 +o x -30 +o w -15 +o v -15 +o . -40 +o , -40 +/o z -55 +char248 z -55 +/o y -70 +char248 y -70 +/o x -85 +char248 x -85 +/o w -70 +char248 w -70 +/o v -70 +char248 v -70 +/o u -55 +char248 u -55 +/o t -55 +char248 t -55 +/o s -55 +char248 s -55 +/o r -55 +char248 r -55 +/o q -55 +char248 q -55 +/o . -95 +char248 . -95 +/o p -55 +char248 p -55 +/o o -55 +char248 o -55 +/o n -55 +char248 n -55 +/o m -55 +char248 m -55 +/o l -55 +char248 l -55 +/o k -55 +char248 k -55 +/o j -55 +char248 j -55 +/o i -55 +char248 i -55 +/o h -55 +char248 h -55 +/o g -55 +char248 g -55 +/o f -55 +char248 f -55 +/o e -55 +char248 e -55 +/o d -55 +char248 d -55 +/o , -95 +char248 , -95 +/o c -55 +char248 c -55 +/o b -55 +char248 b -55 +/o a -55 +char248 a -55 +p y -30 +p . -35 +p , -35 +. ' -100 +. rq -100 +` ` -57 +` oq -57 +oq ` -57 +oq oq -57 +' s -50 +' r -50 +' ' -57 +' d -50 +r y 30 +r v 30 +r u 15 +r t 40 +r ; 30 +r . -50 +r p 30 +r n 25 +r m 25 +r l 15 +r k 15 +r i 15 +r , -50 +r : 30 +r a -10 +s w -30 +s . -15 +s , -15 +v . -80 +v o -25 +v e -25 +v , -80 +v a -25 +w . -60 +w o -10 +w e -10 +w , -60 +w a -15 +x e -30 +y . -100 +y o -20 +y e -20 +y , -100 +y a -20 +z o -15 +z e -15 +charset +ha 469,688 2 0000 asciicircum +ti 584,326 0 0001 asciitilde +vS 667,929,19 2 0002 Scaron +vZ 611,929 2 0003 Zcaron +vs 500,734,15 2 0004 scaron +vz 500,734 2 0005 zcaron +:Y 667,901 2 0006 Ydieresis +tm 1000,718 2 0007 trademark +aq 191,718 2 0010 quotesingle +space 278 0 0040 +! 278,718 2 0041 exclam +" 355,718 2 0042 quotedbl +# 556,688 2 0043 numbersign +sh " +$ 556,775,115 2 0044 dollar +Do " +% 889,703,19 2 0045 percent +& 667,718,15 2 0046 ampersand +' 222,718 2 0047 quoteright +( 333,733,207 3 0050 parenleft +) 333,733,207 3 0051 parenright +* 389,718 2 0052 asterisk ++ 584,505 0 0053 plus +, 278,106,147 0 0054 comma +- 333,322 0 0055 hyphen +hy " +char173 " +. 278,106 0 0056 period +/ 278,737,19 2 0057 slash +sl " +0 556,703,19 2 0060 zero +1 556,703 2 0061 one +2 556,703 2 0062 two +3 556,703,19 2 0063 three +4 556,703 2 0064 four +5 556,688,19 2 0065 five +6 556,703,19 2 0066 six +7 556,688 2 0067 seven +8 556,703,19 2 0070 eight +9 556,703,19 2 0071 nine +: 278,516 0 0072 colon +; 278,516,147 0 0073 semicolon +< 584,495 0 0074 less += 584,390 0 0075 equal +> 584,495 0 0076 greater +? 556,727 2 0077 question +@ 1015,737,19 2 0100 at +at " +A 667,718 2 0101 A +B 667,718 2 0102 B +C 722,737,19 2 0103 C +D 722,718 2 0104 D +E 667,718 2 0105 E +F 611,718 2 0106 F +G 778,737,19 2 0107 G +H 722,718 2 0110 H +I 278,718 2 0111 I +J 500,718,19 2 0112 J +K 667,718 2 0113 K +L 556,718 2 0114 L +M 833,718 2 0115 M +N 722,718 2 0116 N +O 778,737,19 2 0117 O +P 667,718 2 0120 P +Q 778,737,56 2 0121 Q +R 722,718 2 0122 R +S 667,737,19 2 0123 S +T 611,718 2 0124 T +U 722,718,19 2 0125 U +V 667,718 2 0126 V +W 944,718 2 0127 W +X 667,718 2 0130 X +Y 667,718 2 0131 Y +Z 611,718 2 0132 Z +[ 278,722,196 2 0133 bracketleft +lB " +\ 278,737,19 2 0134 backslash +rs " +] 278,722,196 2 0135 bracketright +rB " +a^ 333,734 2 0136 circumflex +^ " +_ 556,0,125 0 0137 underscore +` 222,725 2 0140 quoteleft +oq " +a 556,538,15 0 0141 a +b 556,718,15 2 0142 b +c 500,538,15 0 0143 c +d 556,718,15 2 0144 d +e 556,538,15 0 0145 e +f 278,728 2 0146 f +g 556,538,220 1 0147 g +h 556,718 2 0150 h +i 222,718 2 0151 i +j 222,718,210 3 0152 j +k 500,718 2 0153 k +l 222,718 2 0154 l +m 833,538 0 0155 m +n 556,538 0 0156 n +o 556,538,14 0 0157 o +p 556,538,207 1 0160 p +q 556,538,207 1 0161 q +r 333,538 0 0162 r +s 500,538,15 0 0163 s +t 278,669,7 2 0164 t +u 556,523,15 0 0165 u +v 500,523 0 0166 v +w 722,523 0 0167 w +x 500,523 0 0170 x +y 500,523,214 1 0171 y +z 500,523 0 0172 z +lC 334,722,196 2 0173 braceleft +{ " +ba 260,737,19 2 0174 bar +| " +rC 334,722,196 2 0175 braceright +} " +a~ 333,722 2 0176 tilde +~ " +bq 222,106,149 0 0200 quotesinglbase +Fo 556,446 0 0201 guillemotleft +char171 " +Fc 556,446 0 0202 guillemotright +char187 " +bu 350,517 0 0203 bullet +Fn 556,737,207 3 0204 florin +f/ 167,703,19 2 0205 fraction +%0 1000,703,19 2 0206 perthousand +dg 556,718,159 2 0207 dagger +dd 556,718,159 2 0210 daggerdbl +en 556,313 0 0211 endash +em 1000,313 0 0212 emdash +fi 500,728 2 0214 fi +fl 500,728 2 0215 fl +.i 278,523 0 0220 dotlessi +ga 333,734 2 0222 grave +a" 333,734 2 0223 hungarumlaut +a. 333,706 2 0224 dotaccent +ab 333,731 2 0225 breve +ah 333,734 2 0226 caron +ao 333,756 2 0227 ring +ho 333,0,225 1 0230 ogonek +lq 333,725 2 0231 quotedblleft +rq 333,718 2 0232 quotedblright +oe 944,538,15 0 0233 oe +/l 222,718 2 0234 lslash +Bq 333,106,149 0 0235 quotedblbase +OE 1000,737,19 2 0236 OE +/L 556,718 2 0237 Lslash +r! 333,523,195 0 0241 exclamdown +char161 " +ct 556,623,115 0 0242 cent +char162 " +Po 556,718,16 2 0243 sterling +char163 " +Cs 556,603 0 0244 currency +char164 " +Ye 556,688 2 0245 yen +char165 " +bb 260,737,19 2 0246 brokenbar +char166 " +sc 556,737,191 2 0247 section +char167 " +ad 333,706 2 0250 dieresis +char168 " +co 737,737,19 2 0251 copyright +char169 " +Of 370,737 2 0252 ordfeminine +char170 " +fo 333,446 0 0253 guilsinglleft +no 584,390 0 0254 logicalnot +char172 " +\- 584,289 0 0255 minus +rg 737,737,19 2 0256 registered +char174 " +a- 333,684 2 0257 macron +char175 " +de 400,703 2 0260 degree +char176 " +char177 584,506 0 0261 plusminus +S2 333,703 2 0262 twosuperior +char178 " +S3 333,703 2 0263 threesuperior +char179 " +aa 333,734 2 0264 acute +char180 " +char181 556,523,207 1 0265 mu +ps 537,718,173 2 0266 paragraph +char182 " +char183 278,315 0 0267 periodcentered +ac 333,0,225 1 0270 cedilla +char184 " +S1 333,703 2 0271 onesuperior +char185 " +Om 365,737 2 0272 ordmasculine +char186 " +fc 333,446 0 0273 guilsinglright +14 834,703,19 2 0274 onequarter +char188 " +12 834,703,19 2 0275 onehalf +char189 " +34 834,703,19 2 0276 threequarters +char190 " +r? 611,525,201 0 0277 questiondown +char191 " +`A 667,929 2 0300 Agrave +char192 " +'A 667,929 2 0301 Aacute +char193 " +^A 667,929 2 0302 Acircumflex +char194 " +~A 667,917 2 0303 Atilde +char195 " +:A 667,901 2 0304 Adieresis +char196 " +oA 667,931 2 0305 Aring +char197 " +AE 1000,718 2 0306 AE +char198 " +,C 722,737,225 3 0307 Ccedilla +char199 " +`E 667,929 2 0310 Egrave +char200 " +'E 667,929 2 0311 Eacute +char201 " +^E 667,929 2 0312 Ecircumflex +char202 " +:E 667,901 2 0313 Edieresis +char203 " +`I 278,929 2 0314 Igrave +char204 " +'I 278,929 2 0315 Iacute +char205 " +^I 278,929 2 0316 Icircumflex +char206 " +:I 278,901 2 0317 Idieresis +char207 " +-D 722,718 2 0320 Eth +char208 " +~N 722,917 2 0321 Ntilde +char209 " +`O 778,929,19 2 0322 Ograve +char210 " +'O 778,929,19 2 0323 Oacute +char211 " +^O 778,929,19 2 0324 Ocircumflex +char212 " +~O 778,917,19 2 0325 Otilde +char213 " +:O 778,901,19 2 0326 Odieresis +char214 " +char215 584,506 0 0327 multiply +/O 778,737,19 2 0330 Oslash +char216 " +`U 722,929,19 2 0331 Ugrave +char217 " +'U 722,929,19 2 0332 Uacute +char218 " +^U 722,929,19 2 0333 Ucircumflex +char219 " +:U 722,901,19 2 0334 Udieresis +char220 " +'Y 667,929 2 0335 Yacute +char221 " +TP 667,718 2 0336 Thorn +char222 " +ss 611,728,15 2 0337 germandbls +char223 " +`a 556,734,15 2 0340 agrave +char224 " +'a 556,734,15 2 0341 aacute +char225 " +^a 556,734,15 2 0342 acircumflex +char226 " +~a 556,722,15 2 0343 atilde +char227 " +:a 556,706,15 2 0344 adieresis +char228 " +oa 556,756,15 2 0345 aring +char229 " +ae 889,538,15 0 0346 ae +char230 " +,c 500,538,225 1 0347 ccedilla +char231 " +`e 556,734,15 2 0350 egrave +char232 " +'e 556,734,15 2 0351 eacute +char233 " +^e 556,734,15 2 0352 ecircumflex +char234 " +:e 556,706,15 2 0353 edieresis +char235 " +`i 278,734 2 0354 igrave +char236 " +'i 278,734 2 0355 iacute +char237 " +^i 278,734 2 0356 icircumflex +char238 " +:i 278,706 2 0357 idieresis +char239 " +Sd 556,737,15 2 0360 eth +char240 " +~n 556,722 2 0361 ntilde +char241 " +`o 556,734,14 2 0362 ograve +char242 " +'o 556,734,14 2 0363 oacute +char243 " +^o 556,734,14 2 0364 ocircumflex +char244 " +~o 556,722,14 2 0365 otilde +char245 " +:o 556,706,14 2 0366 odieresis +char246 " +char247 584,524,19 0 0367 divide +/o 611,545,22 0 0370 oslash +char248 " +`u 556,734,15 2 0371 ugrave +char249 " +'u 556,734,15 2 0372 uacute +char250 " +^u 556,734,15 2 0373 ucircumflex +char251 " +:u 556,706,15 2 0374 udieresis +char252 " +'y 500,734,214 3 0375 yacute +char253 " +Tp 556,718,207 3 0376 thorn +char254 " +:y 500,706,214 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/Makefile b/gnu/usr.bin/groff/devices/devps/Makefile new file mode 100644 index 0000000000..7e47f06bb8 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/Makefile @@ -0,0 +1,15 @@ +DEVICE= ps +FONTFILES= $(FONTS) $(SUPPORT) $(DEVGENFILES) DESC +FONTS= S ZD ZDR SS AB ABI AI AR BMB BMBI BMI BMR \ + CB CBI CI CR HB HBI HI HR HNB HNBI HNI HNR \ + NB NBI NI NR PB PBI PI PR TB TBI TI TR ZCMI +SUPPORT= download prologue symbolsl.pfa text.enc zapfdr.pfa +DEVGENFILES= generate/Makefile generate/afmname generate/dingbatsmap \ + generate/dingbatsrmap generate/lgreekmap generate/symbol.sed \ + generate/symbolchars generate/symbolsl.afm generate/textmap + +NOOBJ= noobj + +clean cleandir: + +.include "../Makefile.dev" diff --git a/gnu/usr.bin/groff/devices/devps/NB b/gnu/usr.bin/groff/devices/devps/NB new file mode 100644 index 0000000000..2805367abe --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/NB @@ -0,0 +1,446 @@ +name NB +internalname NewCenturySchlbk-Bold +spacewidth 287 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -74 +A w -74 +A v -74 +A ' -74 +A Y -92 +A W -74 +A V -92 +A T -55 +F . -111 +F , -111 +F A -74 +L y -55 +L ' -55 +L Y -92 +L W -74 +L V -92 +L T -55 +P . -129 +P , -129 +P A -74 +R y -18 +R Y -37 +R W -37 +R V -37 +T y -52 +T w -71 +T u -71 +T ; -55 +T s -62 +T r -62 +T . -92 +T o -92 +T i -25 +T - -92 +T hy -92 +T char173 -92 +T e -92 +T , -92 +T : -55 +T c -81 +T a -62 +T A -55 +V y -92 +V u -74 +V ; -74 +V r -74 +V . -129 +V o -92 +V i -44 +V - -92 +V hy -92 +V char173 -92 +V e -92 +V : -74 +V a -92 +V A -92 +W y -74 +W u -55 +W ; -37 +W r -55 +W . -111 +W o -55 +W i -37 +W - -37 +W hy -37 +W char173 -37 +W e -55 +W , -111 +W : -37 +W a -74 +W A -74 +Y v -81 +Y u -92 +Y ; -92 +Y q -111 +Y . -111 +Y p -81 +Y o -111 +Y i -44 +Y - -111 +Y hy -111 +Y char173 -111 +Y e -111 +Y , -111 +Y : -92 +Y a -111 +Y A -92 +f ' 94 +1 1 -55 +` ` -18 +` oq -18 +oq ` -18 +oq oq -18 +' t -18 +' s -37 +' ' -18 +r ' 55 +r . -74 +r - -18 +r hy -18 +r char173 -18 +r , -74 +v . -111 +v , -111 +w . -92 +w , -92 +y . -111 +y , -111 +charset +ha 606,722 2 0000 asciicircum +ti 606,347 0 0001 asciitilde +vS 667,970,15 2 0002 Scaron +vZ 667,970 2 0003 Zcaron +vs 500,723,15 2 0004 scaron +vz 537,723 2 0005 zcaron +:Y 722,940 2 0006 Ydieresis +tm 1000,722 2 0007 trademark +aq 241,737 2 0010 quotesingle +space 287 0 0040 +! 296,737,15 2 0041 exclam +" 333,737 2 0042 quotedbl +# 574,705 2 0043 numbersign +sh " +$ 574,801,140 2 0044 dollar +Do " +% 833,704,18 2 0045 percent +& 852,737,15 2 0046 ampersand +' 241,737 2 0047 quoteright +( 389,737,122 2 0050 parenleft +) 389,737,122 2 0051 parenright +* 500,738 2 0052 asterisk ++ 606,514 0 0053 plus +, 278,169,189 0 0054 comma +- 333,309 0 0055 hyphen +hy " +char173 " +. 278,172,15 0 0056 period +/ 278,737,15 2 0057 slash +sl " +0 574,705,15 2 0060 zero +1 574,705 2 0061 one +2 574,705,4 2 0062 two +3 574,705,15 2 0063 three +4 574,705 2 0064 four +5 574,705,15 2 0065 five +6 574,705,15 2 0066 six +7 574,705,15 2 0067 seven +8 574,705,15 2 0070 eight +9 574,705,15 2 0071 nine +: 278,485,15 0 0072 colon +; 278,485,189 0 0073 semicolon +< 606,538,13 0 0074 less += 606,399 0 0075 equal +> 606,538,13 0 0076 greater +? 500,737,15 2 0077 question +@ 747,737,15 2 0100 at +at " +A 759,737 2 0101 A +B 778,722 2 0102 B +C 778,737,15 2 0103 C +D 833,722 2 0104 D +E 759,722 2 0105 E +F 722,722 2 0106 F +G 833,737,15 2 0107 G +H 870,722 2 0110 H +I 444,722 2 0111 I +J 648,722,15 2 0112 J +K 815,722 2 0113 K +L 722,722 2 0114 L +M 981,722 2 0115 M +N 833,722,8 2 0116 N +O 833,737,15 2 0117 O +P 759,722 2 0120 P +Q 833,737,189 2 0121 Q +R 815,722,15 2 0122 R +S 667,737,15 2 0123 S +T 722,722 2 0124 T +U 833,722,15 2 0125 U +V 759,722,15 2 0126 V +W 981,722,15 2 0127 W +X 722,722 2 0130 X +Y 722,722 2 0131 Y +Z 667,722 2 0132 Z +[ 389,722,113 2 0133 bracketleft +lB " +\ 606,737 2 0134 backslash +rs " +] 389,722,113 2 0135 bracketright +rB " +a^ 333,723 2 0136 circumflex +^ " +_ 500,0,148 0 0137 underscore +` 241,747 2 0140 quoteleft +oq " +a 611,485,15 0 0141 a +b 648,737,15 2 0142 b +c 556,485,15 0 0143 c +d 667,737,15 2 0144 d +e 574,485,15 0 0145 e +f 389,737 2 0146 f +g 611,536,205 1 0147 g +h 685,737 2 0150 h +i 370,737 2 0151 i +j 352,737,205 3 0152 j +k 667,737 2 0153 k +l 352,737 2 0154 l +m 963,485 0 0155 m +n 685,485 0 0156 n +o 611,485,15 0 0157 o +p 667,485,205 1 0160 p +q 648,485,205 1 0161 q +r 519,485 0 0162 r +s 500,485,15 0 0163 s +t 426,675,15 2 0164 t +u 685,475,15 0 0165 u +v 611,475,8 0 0166 v +w 889,475,8 0 0167 w +x 611,475 0 0170 x +y 611,475,207 1 0171 y +z 537,475 0 0172 z +lC 389,723,111 2 0173 braceleft +{ " +ba 606,737 2 0174 bar +| " +rC 389,723,111 2 0175 braceright +} " +a~ 333,704 2 0176 tilde +~ " +bq 241,169,189 0 0200 quotesinglbase +Fo 500,405 0 0201 guillemotleft +char171 " +Fc 500,405 0 0202 guillemotright +char187 " +bu 606,511 0 0203 bullet +Fn 574,737,205 3 0204 florin +f/ 167,705 2 0205 fraction +%0 1000,694,27 2 0206 perthousand +dg 500,737,88 2 0207 dagger +dd 500,736,89 2 0210 daggerdbl +en 500,296 0 0211 endash +em 1000,296 0 0212 emdash +fi 685,737 2 0214 fi +fl 685,737 2 0215 fl +.i 370,475 0 0220 dotlessi +ga 333,734 2 0222 grave +a" 333,737 2 0223 hungarumlaut +a. 333,693 2 0224 dotaccent +ab 333,712 2 0225 breve +ah 333,723 2 0226 caron +ao 333,760 2 0227 ring +ho 333,0,163 0 0230 ogonek +lq 481,747 2 0231 quotedblleft +rq 481,737 2 0232 quotedblright +oe 907,485,15 0 0233 oe +/l 352,737 2 0234 lslash +Bq 481,169,189 0 0235 quotedblbase +OE 1000,722 2 0236 OE +/L 722,722 2 0237 Lslash +r! 296,547,205 1 0241 exclamdown +char161 " +ct 574,566,108 0 0242 cent +char162 " +Po 574,705,15 2 0243 sterling +char163 " +Cs 574,591 0 0244 currency +char164 " +Ye 574,705 2 0245 yen +char165 " +bb 606,737 2 0246 brokenbar +char166 " +sc 500,737,86 2 0247 section +char167 " +ad 333,693 2 0250 dieresis +char168 " +co 747,737,15 2 0251 copyright +char169 " +Of 367,737 2 0252 ordfeminine +char170 " +fo 333,405 0 0253 guilsinglleft +no 606,399 0 0254 logicalnot +char172 " +\- 606,302 0 0255 minus +rg 747,737,15 2 0256 registered +char174 " +a- 333,663 0 0257 macron +char175 " +de 400,705 2 0260 degree +char176 " +char177 606,514 0 0261 plusminus +S2 344,705 2 0262 twosuperior +char178 " +S3 344,705 2 0263 threesuperior +char179 " +aa 333,737 2 0264 acute +char180 " +char181 685,475,205 1 0265 mu +ps 747,722 2 0266 paragraph +char182 " +char183 278,338 0 0267 periodcentered +ac 333,0,221 1 0270 cedilla +char184 " +S1 344,705 2 0271 onesuperior +char185 " +Om 367,737 2 0272 ordmasculine +char186 " +fc 333,408 0 0273 guilsinglright +14 861,705 2 0274 onequarter +char188 " +12 861,705,2 2 0275 onehalf +char189 " +34 861,705 2 0276 threequarters +char190 " +r? 500,547,205 1 0277 questiondown +char191 " +`A 759,981 2 0300 Agrave +char192 " +'A 759,984 2 0301 Aacute +char193 " +^A 759,970 2 0302 Acircumflex +char194 " +~A 759,951 2 0303 Atilde +char195 " +:A 759,940 2 0304 Adieresis +char196 " +oA 759,1007 2 0305 Aring +char197 " +AE 981,722 2 0306 AE +char198 " +,C 778,737,221 3 0307 Ccedilla +char199 " +`E 759,981 2 0310 Egrave +char200 " +'E 759,984 2 0311 Eacute +char201 " +^E 759,970 2 0312 Ecircumflex +char202 " +:E 759,940 2 0313 Edieresis +char203 " +`I 444,981 2 0314 Igrave +char204 " +'I 444,984 2 0315 Iacute +char205 " +^I 444,970 2 0316 Icircumflex +char206 " +:I 444,940 2 0317 Idieresis +char207 " +-D 833,722 2 0320 Eth +char208 " +~N 833,951,8 2 0321 Ntilde +char209 " +`O 833,981,15 2 0322 Ograve +char210 " +'O 833,984,15 2 0323 Oacute +char211 " +^O 833,970,15 2 0324 Ocircumflex +char212 " +~O 833,951,15 2 0325 Otilde +char213 " +:O 833,940,15 2 0326 Odieresis +char214 " +char215 606,504 0 0327 multiply +/O 833,768,60 2 0330 Oslash +char216 " +`U 833,981,15 2 0331 Ugrave +char217 " +'U 833,984,15 2 0332 Uacute +char218 " +^U 833,970,15 2 0333 Ucircumflex +char219 " +:U 833,940,15 2 0334 Udieresis +char220 " +'Y 722,984 2 0335 Yacute +char221 " +TP 759,722 2 0336 Thorn +char222 " +ss 611,737,15 2 0337 germandbls +char223 " +`a 611,734,15 2 0340 agrave +char224 " +'a 611,737,15 2 0341 aacute +char225 " +^a 611,723,15 2 0342 acircumflex +char226 " +~a 611,704,15 2 0343 atilde +char227 " +:a 611,693,15 2 0344 adieresis +char228 " +oa 611,760,15 2 0345 aring +char229 " +ae 870,485,15 0 0346 ae +char230 " +,c 556,485,221 1 0347 ccedilla +char231 " +`e 574,734,15 2 0350 egrave +char232 " +'e 574,737,15 2 0351 eacute +char233 " +^e 574,723,15 2 0352 ecircumflex +char234 " +:e 574,693,15 2 0353 edieresis +char235 " +`i 370,734 2 0354 igrave +char236 " +'i 370,737 2 0355 iacute +char237 " +^i 370,723 2 0356 icircumflex +char238 " +:i 370,693 2 0357 idieresis +char239 " +Sd 611,737,15 2 0360 eth +char240 " +~n 685,704 2 0361 ntilde +char241 " +`o 611,734,15 2 0362 ograve +char242 " +'o 611,737,15 2 0363 oacute +char243 " +^o 611,723,15 2 0364 ocircumflex +char244 " +~o 611,704,15 2 0365 otilde +char245 " +:o 611,693,15 2 0366 odieresis +char246 " +char247 606,514 0 0367 divide +/o 611,565,111 0 0370 oslash +char248 " +`u 685,734,15 2 0371 ugrave +char249 " +'u 685,737,15 2 0372 uacute +char250 " +^u 685,723,15 2 0373 ucircumflex +char251 " +:u 685,693,15 2 0374 udieresis +char252 " +'y 611,737,207 3 0375 yacute +char253 " +Tp 667,675,205 3 0376 thorn +char254 " +:y 611,693,207 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/NBI b/gnu/usr.bin/groff/devices/devps/NBI new file mode 100644 index 0000000000..3471b41e75 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/NBI @@ -0,0 +1,447 @@ +name NBI +internalname NewCenturySchlbk-BoldItalic +slant 16 +spacewidth 287 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -50 +A w -20 +A v -20 +A ' -74 +A Y -74 +A W -92 +A V -111 +A T -74 +F . -129 +F f -18 +F , -129 +F A -74 +L y -55 +L ' -55 +L Y -55 +L W -55 +L V -74 +L T -55 +P . -129 +P , -129 +P A -92 +R y -50 +R Y -20 +R W -20 +R V -20 +R T -20 +T y -89 +T w -89 +T u -89 +T ; -72 +T s -89 +T r -89 +T . -111 +T o -109 +T i -71 +T - -129 +T hy -129 +T char173 -129 +T e -109 +T , -111 +T : -62 +T c -89 +T a -74 +T A -50 +V y -89 +V u -89 +V ; -74 +V r -109 +V . -111 +V o -129 +V i -72 +V - -74 +V hy -74 +V char173 -74 +V e -129 +V , -111 +V : -74 +V a -129 +V A -129 +W y -74 +W u -74 +W ; -37 +W r -74 +W . -55 +W o -74 +W i -74 +W - -37 +W hy -37 +W char173 -37 +W e -74 +W , -55 +W : -37 +W a -74 +W A -89 +Y v -129 +Y u -129 +Y ; -111 +Y q -129 +Y . -129 +Y p -129 +Y o -129 +Y i -90 +Y - -129 +Y hy -129 +Y char173 -129 +Y e -129 +Y , -129 +Y : -111 +Y a -129 +Y A -111 +f ' 74 +1 1 -74 +` ` -18 +` oq -18 +oq ` -18 +oq oq -18 +' t -37 +' s -37 +' ' -18 +r ' 55 +r . -129 +r , -129 +v . -37 +v , -37 +w . -37 +w , -37 +y . -55 +y , -55 +charset +ha 606,722,0,0,-2 2 0000 asciicircum +ti 606,353,0,0,-1 0 0001 asciitilde +vS 685,954,15,31,49,31 2 0002 Scaron +vZ 704,954,0,61,79,61 2 0003 Zcaron +vs 481,709,15,46,48,46 2 0004 scaron +vz 519,709,15,27,69,27 2 0005 zcaron +:Y 704,930,0,123,35,109 2 0006 Ydieresis +tm 950,722,0,82,8,82 2 0007 trademark +aq 287,736,0,32,-50,32 2 0010 quotesingle +space 287 0 0040 +! 333,737,15,53,47,53 2 0041 exclam +" 400,737,0,157,-50,109 2 0042 quotedbl +# 574,705,0,9,9,9 2 0043 numbersign +sh " +$ 574,799,143,35,47,35 2 0044 dollar +Do " +% 889,721,34,0,-1 2 0045 percent +& 889,737,15,0,19 2 0046 ampersand +' 259,739,0,92,-20,92 2 0047 quoteright +( 407,740,123,95,-21,95 2 0050 parenleft +) 407,740,123,0,120 2 0051 parenright +* 500,704,0,22,18,22 2 0052 asterisk ++ 606,505,0,0,9 0 0053 plus +, 287,159,190,0,98 0 0054 comma +- 333,297,0,0,40 0 0055 hyphen +hy " +char173 " +. 287,159,15,0,38 0 0056 period +/ 278,737,15,83,75,83 2 0057 slash +sl " +0 574,705,15,29,29,29 2 0060 zero +1 574,705,0,0,25 2 0061 one +2 574,705,0,14,90,14 2 0062 two +3 574,705,15,14,55,14 2 0063 three +4 574,705,0,20,63,20 2 0064 four +5 574,705,15,49,50,49 2 0065 five +6 574,705,15,49,20,49 2 0066 six +7 574,705,15,69,-14,69 2 0067 seven +8 574,705,15,27,50,27 2 0070 eight +9 574,705,15,20,49,20 2 0071 nine +: 287,477,15,20,52,20 0 0072 colon +; 287,477,190,20,89,20 0 0073 semicolon +< 606,524,14,0,36 0 0074 less += 606,402,0,0,9 0 0075 equal +> 606,524,14,0,12 0 0076 greater +? 481,737,15,21,-29,21 2 0077 question +@ 747,737,15,25,28,25 2 0100 at +at " +A 741,737,0,25,125,25 2 0101 A +B 759,722,0,11,100,11 2 0102 B +C 759,737,15,50,15,50 2 0103 C +D 833,722,0,13,99,13 2 0104 D +E 741,722,0,37,91,37 2 0105 E +F 704,722,0,72,91,72 2 0106 F +G 815,737,15,37,16,37 2 0107 G +H 870,722,0,92,91,92 2 0110 H +I 444,722,0,92,91,92 2 0111 I +J 667,722,15,101,59,101 2 0112 J +K 778,722,0,104,91,104 2 0113 K +L 704,722,0,16,91,16 2 0114 L +M 944,722,0,94,74,94 2 0115 M +N 852,722,16,110,107,109 2 0116 N +O 833,737,15,14,14,14 2 0117 O +P 741,722,0,40,88,40 2 0120 P +Q 833,737,186,13,15,13 2 0121 Q +R 796,722,15,5,91,5 2 0122 R +S 685,737,15,31,49,31 2 0123 S +T 722,722,0,90,6,90 2 0124 T +U 833,722,15,112,-38,109 2 0125 U +V 741,722,15,111,18,109 2 0126 V +W 944,722,15,100,10,100 2 0127 W +X 741,722,0,120,122,109 2 0130 X +Y 704,722,0,123,35,109 2 0131 Y +Z 704,722,0,61,79,61 2 0132 Z +[ 407,737,110,75,81,75 2 0133 bracketleft +lB " +\ 606,737,0,0,-31 2 0134 backslash +rs " +] 407,737,110,57,99,57 2 0135 bracketright +rB " +a^ 333,709,0,82,27,82 2 0136 circumflex +^ " +_ 500,0,129,50,50,50 0 0137 underscore +` 259,747,0,61,11,61 2 0140 quoteleft +oq " +a 667,477,15,29,35,29 0 0141 a +b 611,737,15,0,22 2 0142 b +c 537,477,15,0,47 0 0143 c +d 667,737,15,46,50,46 2 0144 d +e 519,477,15,9,52,9 0 0145 e +f 389,737,205,211,98,109 3 0146 f +g 611,529,205,41,116,41 1 0147 g +h 685,737,15,2,50,2 2 0150 h +i 389,737,15,4,22,4 2 0151 i +j 370,737,205,61,220,61 3 0152 j +k 648,737,15,0,55 2 0153 k +l 389,737,15,31,24,31 2 0154 l +m 944,477,15,26,41,26 0 0155 m +n 685,477,15,7,47,7 0 0156 n +o 574,477,15,16,40,16 0 0157 o +p 648,477,205,0,168 1 0160 p +q 630,477,205,7,50,7 1 0161 q +r 519,486,0,55,47,55 0 0162 r +s 481,477,15,6,48,6 0 0163 s +t 407,650,15,47,26,47 2 0164 t +u 685,477,15,4,12,4 0 0165 u +v 556,477,15,0,18 0 0166 v +w 833,477,15,5,28,5 0 0167 w +x 574,477,15,47,99,47 0 0170 x +y 519,477,205,23,116,23 1 0171 y +z 519,477,15,2,69,2 0 0172 z +lC 407,738,115,45,-2,45 2 0173 braceleft +{ " +ba 606,737,0,0,-212 2 0174 bar +| " +rC 407,738,115,0,80 2 0175 braceright +} " +a~ 333,683,0,121,16,109 2 0176 tilde +~ " +bq 259,159,191,0,93 0 0200 quotesinglbase +Fo 481,409,0,0,85 0 0201 guillemotleft +char171 " +Fc 481,408,0,25,56,25 0 0202 guillemotright +char187 " +bu 606,537,0,0,-59 0 0203 bullet +Fn 574,737,205,64,77,64 3 0204 florin +f/ 167,705,15,216,216,109 2 0205 fraction +%0 1167,721,34,34,24,34 2 0206 perthousand +dg 500,737,146,60,0,60 2 0207 dagger +dd 500,737,147,64,98,64 2 0210 daggerdbl +en 500,286,0,68,68,68 0 0211 endash +em 1000,286,0,68,68,68 0 0212 emdash +fi 685,737,205,11,120,11 3 0214 fi +fl 685,737,205,46,120,46 3 0215 fl +.i 389,477,15,14,12,14 0 0220 dotlessi +ga 333,719,0,11,-24,11 2 0222 grave +a" 333,719,0,189,27,109 2 0223 hungarumlaut +a. 333,685,0,5,-95,5 2 0224 dotaccent +ab 333,698,0,107,-17,107 2 0225 breve +ah 333,709,0,120,-10,109 2 0226 caron +ao 333,745,0,149,-167,109 2 0227 ring +ho 333,0,155,0,-18 0 0230 ogonek +lq 481,747,0,91,-2,91 2 0231 quotedblleft +rq 481,739,0,102,-11,102 2 0232 quotedblright +oe 852,477,15,8,55,8 0 0233 oe +/l 389,737,15,58,24,58 2 0234 lslash +Bq 481,159,191,0,120 0 0235 quotedblbase +OE 963,722,0,67,31,67 2 0236 OE +/L 704,722,0,16,91,16 2 0237 Lslash +r! 333,544,205,6,89,6 1 0241 exclamdown +char161 " +ct 574,600,124,0,20 0 0242 cent +char162 " +Po 574,705,15,42,68,42 2 0243 sterling +char163 " +Cs 574,612,0,22,10,22 0 0244 currency +char164 " +Ye 574,705,0,111,27,109 2 0245 yen +char165 " +bb 606,737,0,0,-212 2 0246 brokenbar +char166 " +sc 500,737,145,55,90,55 2 0247 section +char167 " +ad 333,685,0,109,16,109 2 0250 dieresis +char168 " +co 747,737,15,26,27,26 2 0251 copyright +char169 " +Of 412,737,0,87,21,87 2 0252 ordfeminine +char170 " +fo 278,409,0,0,85 0 0253 guilsinglleft +no 606,402,0,0,9 0 0254 logicalnot +char172 " +\- 606,304,0,0,9 0 0255 minus +rg 747,737,15,26,27,26 2 0256 registered +char174 " +a- 333,649,0,104,18,104 2 0257 macron +char175 " +de 400,705,0,20,-20,20 2 0260 degree +char176 " +char177 606,505,0,0,9 0 0261 plusminus +S2 344,705,0,66,66,66 2 0262 twosuperior +char178 " +S3 344,705,0,54,54,54 2 0263 threesuperior +char179 " +aa 333,719,0,88,-73,88 2 0264 acute +char180 " +char181 685,477,205,4,140,4 1 0265 mu +ps 650,737,0,61,-17,61 2 0266 paragraph +char182 " +char183 287,342,0,0,9 0 0267 periodcentered +ac 333,3,220,0,137 1 0270 cedilla +char184 " +S1 344,705,0,29,29,29 2 0271 onesuperior +char185 " +Om 356,737,0,77,21,77 2 0272 ordmasculine +char186 " +fc 278,408,0,25,56,25 0 0273 guilsinglright +14 861,705,15,15,29,15 2 0274 onequarter +char188 " +12 861,705,15,46,29,46 2 0275 onehalf +char189 " +34 861,705,15,15,54,15 2 0276 threequarters +char190 " +r? 481,544,205,0,49 1 0277 questiondown +char191 " +`A 741,964,0,25,125,25 2 0300 Agrave +char192 " +'A 741,964,0,25,125,25 2 0301 Aacute +char193 " +^A 741,954,0,25,125,25 2 0302 Acircumflex +char194 " +~A 741,928,0,25,125,25 2 0303 Atilde +char195 " +:A 741,930,0,25,125,25 2 0304 Adieresis +char196 " +oA 741,990,0,25,125,25 2 0305 Aring +char197 " +AE 889,722,0,64,131,64 2 0306 AE +char198 " +,C 759,737,220,50,15,50 3 0307 Ccedilla +char199 " +`E 741,964,0,37,91,37 2 0310 Egrave +char200 " +'E 741,964,0,37,91,37 2 0311 Eacute +char201 " +^E 741,954,0,37,91,37 2 0312 Ecircumflex +char202 " +:E 741,930,0,37,91,37 2 0313 Edieresis +char203 " +`I 444,964,0,92,91,92 2 0314 Igrave +char204 " +'I 444,964,0,92,91,92 2 0315 Iacute +char205 " +^I 444,954,0,92,91,92 2 0316 Icircumflex +char206 " +:I 444,930,0,104,91,104 2 0317 Idieresis +char207 " +-D 833,722,0,13,99,13 2 0320 Eth +char208 " +~N 852,928,16,110,107,109 2 0321 Ntilde +char209 " +`O 833,964,15,14,14,14 2 0322 Ograve +char210 " +'O 833,964,15,14,14,14 2 0323 Oacute +char211 " +^O 833,954,15,14,14,14 2 0324 Ocircumflex +char212 " +~O 833,928,15,14,14,14 2 0325 Otilde +char213 " +:O 833,930,15,14,14,14 2 0326 Odieresis +char214 " +char215 606,507,0,0,9 0 0327 multiply +/O 833,775,82,14,33,14 2 0330 Oslash +char216 " +`U 833,964,15,112,-38,109 2 0331 Ugrave +char217 " +'U 833,964,15,112,-38,109 2 0332 Uacute +char218 " +^U 833,954,15,112,-38,109 2 0333 Ucircumflex +char219 " +:U 833,930,15,112,-38,109 2 0334 Udieresis +char220 " +'Y 704,964,0,123,35,109 2 0335 Yacute +char221 " +TP 741,722,0,0,88 2 0336 Thorn +char222 " +ss 574,737,205,0,116 3 0337 germandbls +char223 " +`a 667,719,15,29,35,29 2 0340 agrave +char224 " +'a 667,719,15,29,35,29 2 0341 aacute +char225 " +^a 667,709,15,29,35,29 2 0342 acircumflex +char226 " +~a 667,683,15,29,35,29 2 0343 atilde +char227 " +:a 667,685,15,29,35,29 2 0344 adieresis +char228 " +oa 667,745,15,29,35,29 2 0345 aring +char229 " +ae 815,477,15,9,69,9 0 0346 ae +char230 " +,c 537,477,220,0,47 1 0347 ccedilla +char231 " +`e 519,719,15,9,52,9 2 0350 egrave +char232 " +'e 519,719,15,9,52,9 2 0351 eacute +char233 " +^e 519,709,15,9,52,9 2 0352 ecircumflex +char234 " +:e 519,685,15,26,52,26 2 0353 edieresis +char235 " +`i 389,719,15,14,12,14 2 0354 igrave +char236 " +'i 389,719,15,60,12,60 2 0355 iacute +char237 " +^i 389,709,15,44,12,44 2 0356 icircumflex +char238 " +:i 389,685,15,71,12,71 2 0357 idieresis +char239 " +Sd 574,737,15,16,40,16 2 0360 eth +char240 " +~n 685,683,15,7,47,7 2 0361 ntilde +char241 " +`o 574,719,15,16,40,16 2 0362 ograve +char242 " +'o 574,719,15,16,40,16 2 0363 oacute +char243 " +^o 574,709,15,16,40,16 2 0364 ocircumflex +char244 " +~o 574,683,15,16,40,16 2 0365 otilde +char245 " +:o 574,685,15,16,40,16 2 0366 odieresis +char246 " +char247 606,505,0,0,9 0 0367 divide +/o 574,578,126,16,40,16 0 0370 oslash +char248 " +`u 685,719,15,4,12,4 2 0371 ugrave +char249 " +'u 685,719,15,4,12,4 2 0372 uacute +char250 " +^u 685,709,15,4,12,4 2 0373 ucircumflex +char251 " +:u 685,685,15,4,12,4 2 0374 udieresis +char252 " +'y 519,719,205,23,116,23 3 0375 yacute +char253 " +Tp 648,650,205,0,168 3 0376 thorn +char254 " +:y 519,685,205,23,116,23 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/NI b/gnu/usr.bin/groff/devices/devps/NI new file mode 100644 index 0000000000..eb250d77d1 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/NI @@ -0,0 +1,447 @@ +name NI +internalname NewCenturySchlbk-Italic +slant 16 +spacewidth 278 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -54 +A w -20 +A v -20 +A ' -74 +A Y -74 +A W -92 +A V -111 +A T -74 +F . -129 +F f -18 +F , -129 +F A -74 +L y -55 +L ' -55 +L Y -55 +L W -55 +L V -74 +L T -55 +P . -129 +P , -129 +P A -92 +R y -54 +R Y -74 +R W -55 +R V -20 +R T -20 +T y -89 +T w -89 +T u -89 +T ; -92 +T s -89 +T r -89 +T . -111 +T o -89 +T i -71 +T - -129 +T hy -129 +T char173 -129 +T e -89 +T , -111 +T : -92 +T c -89 +T a -74 +T A -18 +V y -109 +V u -109 +V ; -74 +V r -109 +V . -111 +V o -129 +V i -62 +V - -74 +V hy -74 +V char173 -74 +V e -129 +V , -140 +V : -74 +V a -129 +V A -111 +W y -74 +W u -74 +W ; -37 +W r -74 +W . -55 +W o -74 +W i -74 +W - -37 +W hy -37 +W char173 -37 +W e -74 +W , -55 +W : -37 +W a -74 +W A -74 +Y v -99 +Y u -99 +Y ; -111 +Y q -129 +Y . -129 +Y p -129 +Y o -129 +Y i -70 +Y - -129 +Y hy -129 +Y char173 -129 +Y e -129 +Y , -129 +Y : -111 +Y a -129 +Y A -74 +f ' 94 +1 1 -74 +` ` -18 +` oq -18 +oq ` -18 +oq oq -18 +' t -37 +' s -37 +' ' -18 +r ' 55 +r . -129 +r , -129 +v . -37 +v , -37 +w . -37 +w , -37 +y . -55 +y , -55 +charset +ha 606,722,0,0,-2 2 0000 asciicircum +ti 606,335,0,0,9 0 0001 asciitilde +vS 667,944,15,15,50,15 2 0002 Scaron +vZ 667,944,0,50,75,50 2 0003 Zcaron +vs 444,688,15,40,51,40 2 0004 scaron +vz 463,688,15,30,83,30 2 0005 zcaron +:Y 685,900,0,123,18,107 2 0006 Ydieresis +tm 950,722,0,71,2,71 2 0007 trademark +aq 278,737,0,34,-64,34 2 0010 quotesingle +space 278 0 0040 +! 333,737,15,33,20,33 2 0041 exclam +" 400,737,0,45,-50,45 2 0042 quotedbl +# 556,705,0,18,17,18 2 0043 numbersign +sh " +$ 556,800,133,30,47,30 2 0044 dollar +Do " +% 833,705,17,9,4,9 2 0045 percent +& 852,737,15,0,26 2 0046 ampersand +' 204,737,0,76,11,76 2 0047 quoteright +( 333,737,124,116,10,107 2 0050 parenleft +) 333,737,124,0,143 2 0051 parenright +* 500,705,0,2,16,2 2 0052 asterisk ++ 606,504,0,0,13 0 0053 plus +, 278,109,165,0,89 0 0054 comma +- 333,273,0,0,18 0 0055 hyphen +hy " +char173 " +. 278,109,15,0,33 0 0056 period +/ 606,737,102,0,-90 2 0057 slash +sl " +0 556,705,15,21,21,21 2 0060 zero +1 556,705 2 0061 one +2 556,705,0,2,85,2 2 0062 two +3 556,705,15,0,52 2 0063 three +4 556,705,0,6,58,6 2 0064 four +5 556,705,15,34,46,34 2 0065 five +6 556,705,15,41,14,41 2 0066 six +7 556,705,15,55,-19,55 2 0067 seven +8 556,705,15,21,42,21 2 0070 eight +9 556,705,15,13,43,13 2 0071 nine +: 278,466,15,26,8,26 0 0072 colon +; 278,466,165,33,64,33 0 0073 semicolon +< 606,518,10,0,16 0 0074 less += 606,381,0,0,14 0 0075 equal +> 606,518,10,6,-3,6 0 0076 greater +? 444,737,15,23,-52,23 2 0077 question +@ 747,737,15,31,22,31 2 0100 at +at " +A 704,737,0,14,132,14 2 0101 A +B 722,722,0,0,81 2 0102 B +C 722,737,15,41,10,41 2 0103 C +D 778,722,0,7,88,7 2 0104 D +E 722,722,0,29,87,29 2 0105 E +F 667,722,0,81,84,81 2 0106 F +G 778,737,15,35,11,35 2 0107 G +H 833,722,0,84,88,84 2 0110 H +I 407,722,0,74,83,74 2 0111 I +J 611,722,17,85,63,85 2 0112 J +K 741,722,0,123,90,107 2 0113 K +L 667,722,0,13,87,13 2 0114 L +M 944,722,0,79,76,79 2 0115 M +N 815,722,17,94,98,94 2 0116 N +O 778,737,15,7,10,7 2 0117 O +P 667,722,0,46,83,46 2 0120 P +Q 778,737,190,7,10,7 2 0121 Q +R 741,722,17,0,91 2 0122 R +S 667,737,15,15,50,15 2 0123 S +T 685,722,0,91,10,91 2 0124 T +U 815,722,15,95,-43,95 2 0125 U +V 704,722,15,118,14,107 2 0126 V +W 926,722,15,97,-3,97 2 0127 W +X 704,722,0,116,123,107 2 0130 X +Y 685,722,0,123,18,107 2 0131 Y +Z 667,722,0,50,75,50 2 0132 Z +[ 333,737,109,127,83,107 2 0133 bracketleft +lB " +\ 606,737,0,0,-39 2 0134 backslash +rs " +] 333,737,109,76,133,76 2 0135 bracketright +rB " +a^ 333,688,0,48,13,48 2 0136 circumflex +^ " +_ 500,0,123,50,50,50 0 0137 underscore +` 204,749,0,98,-11,98 2 0140 quoteleft +oq " +a 574,466,15,0,49 0 0141 a +b 556,737,15,0,18 2 0142 b +c 444,466,15,7,45,7 0 0143 c +d 611,737,15,25,47,25 2 0144 d +e 444,466,15,0,56 0 0145 e +f 333,737,205,187,118,107 3 0146 f +g 537,499,205,36,129,36 1 0147 g +h 611,737,15,0,50 2 0150 h +i 333,715,15,0,23 2 0151 i +j 315,715,205,52,216,52 3 0152 j +k 556,737,15,0,55 2 0153 k +l 333,737,15,11,34,11 2 0154 l +m 889,466,15,0,35 0 0155 m +n 611,466,15,1,36,1 0 0156 n +o 500,466,15,0,45 0 0157 o +p 574,466,205,0,151 1 0160 p +q 556,466,205,0,50 1 0161 q +r 444,466,0,39,41,39 0 0162 r +s 444,466,15,0,51 0 0163 s +t 352,619,15,27,25,27 2 0164 t +u 611,466,15,0,9 0 0165 u +v 519,466,15,0,16 0 0166 v +w 778,466,15,0,18 0 0167 w +x 500,466,15,21,83,21 0 0170 x +y 500,466,205,4,129,4 1 0171 y +z 463,466,15,4,83,4 0 0172 z +lC 333,737,116,98,-2,98 2 0173 braceleft +{ " +ba 606,737,0,0,-219 2 0174 bar +| " +rC 333,737,116,0,148 2 0175 braceright +} " +a~ 333,650,0,97,-2,97 2 0176 tilde +~ " +bq 204,109,167,0,129 0 0200 quotesinglbase +Fo 426,399,0,26,65,26 0 0201 guillemotleft +char171 " +Fc 426,394,0,24,67,24 0 0202 guillemotright +char187 " +bu 606,537,0,0,-64 0 0203 bullet +Fn 556,737,205,57,107,57 3 0204 florin +f/ 167,705,17,216,154,107 2 0205 fraction +%0 1000,705,15,53,56,53 2 0206 perthousand +dg 500,737,147,68,-14,68 2 0207 dagger +dd 500,737,148,78,80,78 2 0210 daggerdbl +en 500,260,0,68,68,68 0 0211 endash +em 1000,260,0,68,68,68 0 0212 emdash +fi 611,737,205,3,110,3 3 0214 fi +fl 611,737,205,33,110,33 3 0215 fl +.i 333,466,15,0,23 0 0220 dotlessi +ga 333,691,0,0,-23 2 0222 grave +a" 333,689,0,237,-84,107 2 0223 hungarumlaut +a. 333,644,0,0,-68 2 0224 dotaccent +ab 333,677,0,87,-19,87 2 0225 breve +ah 333,688,0,95,-23,95 2 0226 caron +ao 333,712,0,146,-180,107 2 0227 ring +ho 333,0,155,0,-18 0 0230 ogonek +lq 389,749,0,93,-13,93 2 0231 quotedblleft +rq 389,737,0,68,12,68 2 0232 quotedblright +oe 778,466,17,0,50 0 0233 oe +/l 333,737,15,59,34,59 2 0234 lslash +Bq 389,109,167,0,129 0 0235 quotedblbase +OE 981,722,0,32,14,32 2 0236 OE +/L 667,722,0,13,87,13 2 0237 Lslash +r! 333,542,205,0,57 1 0241 exclamdown +char161 " +ct 556,595,129,0,-11 0 0242 cent +char162 " +Po 556,705,15,39,58,39 2 0243 sterling +char163 " +Cs 556,603,0,24,25,24 0 0244 currency +char164 " +Ye 556,705,0,117,10,107 2 0245 yen +char165 " +bb 606,737,0,0,-219 2 0246 brokenbar +char166 " +sc 500,737,147,30,61,30 2 0247 section +char167 " +ad 333,644,0,76,-9,76 2 0250 dieresis +char168 " +co 747,737,15,27,26,27 2 0251 copyright +char169 " +Of 422,737,0,50,-33,50 2 0252 ordfeminine +char170 " +fo 333,399,0,0,8 0 0253 guilsinglleft +no 606,381,0,0,9 0 0254 logicalnot +char172 " +\- 606,287,0,0,9 0 0255 minus +rg 747,737,15,26,27,26 2 0256 registered +char174 " +a- 333,610,0,80,-1,80 0 0257 macron +char175 " +de 400,705,0,20,-20,20 2 0260 degree +char176 " +char177 606,504,0,0,13 0 0261 plusminus +S2 333,705,0,70,50,70 2 0262 twosuperior +char178 " +S3 333,705,0,48,49,48 2 0263 threesuperior +char179 " +aa 333,689,0,72,-82,72 2 0264 acute +char180 " +char181 611,466,205,0,120 1 0265 mu +ps 650,737,0,45,-38,45 2 0266 paragraph +char182 " +char183 278,316,0,0,-27 0 0267 periodcentered +ac 333,0,227,0,47 1 0270 cedilla +char184 " +S1 333,705,0,26,7,26 2 0271 onesuperior +char185 " +Om 372,738,0,50,-33,50 2 0272 ordmasculine +char186 " +fc 333,394,0,0,10 0 0273 guilsinglright +14 834,705,17,49,17,49 2 0274 onequarter +char188 " +12 834,705,17,60,17,60 2 0275 onehalf +char189 " +34 834,705,17,49,49,49 2 0276 threequarters +char190 " +r? 444,542,205,0,43 1 0277 questiondown +char191 " +`A 704,947,0,14,132,14 2 0300 Agrave +char192 " +'A 704,945,0,14,132,14 2 0301 Aacute +char193 " +^A 704,944,0,14,132,14 2 0302 Acircumflex +char194 " +~A 704,906,0,14,132,14 2 0303 Atilde +char195 " +:A 704,900,0,14,132,14 2 0304 Adieresis +char196 " +oA 704,968,0,14,132,14 2 0305 Aring +char197 " +AE 870,722,0,50,142,50 2 0306 AE +char198 " +,C 722,737,227,41,10,41 3 0307 Ccedilla +char199 " +`E 722,947,0,29,87,29 2 0310 Egrave +char200 " +'E 722,945,0,29,87,29 2 0311 Eacute +char201 " +^E 722,944,0,29,87,29 2 0312 Ecircumflex +char202 " +:E 722,900,0,29,87,29 2 0313 Edieresis +char203 " +`I 407,947,0,74,83,74 2 0314 Igrave +char204 " +'I 407,945,0,74,83,74 2 0315 Iacute +char205 " +^I 407,944,0,74,83,74 2 0316 Icircumflex +char206 " +:I 407,900,0,89,83,89 2 0317 Idieresis +char207 " +-D 778,722,0,7,88,7 2 0320 Eth +char208 " +~N 815,906,17,94,98,94 2 0321 Ntilde +char209 " +`O 778,947,15,7,10,7 2 0322 Ograve +char210 " +'O 778,945,15,7,10,7 2 0323 Oacute +char211 " +^O 778,944,15,7,10,7 2 0324 Ocircumflex +char212 " +~O 778,906,15,7,10,7 2 0325 Otilde +char213 " +:O 778,900,15,7,10,7 2 0326 Odieresis +char214 " +char215 606,504,0,0,13 0 0327 multiply +/O 778,755,87,7,49,7 2 0330 Oslash +char216 " +`U 815,947,15,95,-43,95 2 0331 Ugrave +char217 " +'U 815,945,15,95,-43,95 2 0332 Uacute +char218 " +^U 815,944,15,95,-43,95 2 0333 Ucircumflex +char219 " +:U 815,900,15,95,-43,95 2 0334 Udieresis +char220 " +'Y 685,945,0,123,18,107 2 0335 Yacute +char221 " +TP 667,722,0,7,83,7 2 0336 Thorn +char222 " +ss 556,737,205,19,126,19 3 0337 germandbls +char223 " +`a 574,691,15,0,49 2 0340 agrave +char224 " +'a 574,689,15,0,49 2 0341 aacute +char225 " +^a 574,688,15,0,49 2 0342 acircumflex +char226 " +~a 574,650,15,0,49 2 0343 atilde +char227 " +:a 574,644,15,0,49 2 0344 adieresis +char228 " +oa 574,712,15,0,49 2 0345 aring +char229 " +ae 722,466,15,0,68 0 0346 ae +char230 " +,c 444,466,227,7,45,7 1 0347 ccedilla +char231 " +`e 444,691,15,0,56 2 0350 egrave +char232 " +'e 444,689,15,17,56,17 2 0351 eacute +char233 " +^e 444,688,15,0,56 2 0352 ecircumflex +char234 " +:e 444,644,15,11,56,11 2 0353 edieresis +char235 " +`i 333,691,15,0,23 2 0354 igrave +char236 " +'i 333,689,15,72,23,72 2 0355 iacute +char237 " +^i 333,688,15,8,53,8 2 0356 icircumflex +char238 " +:i 333,644,15,66,23,66 2 0357 idieresis +char239 " +Sd 500,737,15,0,45 2 0360 eth +char240 " +~n 611,650,15,1,36,1 2 0361 ntilde +char241 " +`o 500,691,15,0,45 2 0362 ograve +char242 " +'o 500,689,15,0,45 2 0363 oacute +char243 " +^o 500,688,15,0,45 2 0364 ocircumflex +char244 " +~o 500,650,15,4,45,4 2 0365 otilde +char245 " +:o 500,644,15,0,45 2 0366 odieresis +char246 " +char247 606,504,0,0,13 0 0367 divide +/o 500,549,121,0,55 0 0370 oslash +char248 " +`u 611,691,15,0,9 2 0371 ugrave +char249 " +'u 611,689,15,0,9 2 0372 uacute +char250 " +^u 611,688,15,0,9 2 0373 ucircumflex +char251 " +:u 611,644,15,0,9 2 0374 udieresis +char252 " +'y 500,689,205,4,129,4 3 0375 yacute +char253 " +Tp 574,656,205,0,151 3 0376 thorn +char254 " +:y 500,644,205,4,129,4 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/NR b/gnu/usr.bin/groff/devices/devps/NR new file mode 100644 index 0000000000..d545b2ab82 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/NR @@ -0,0 +1,447 @@ +name NR +internalname NewCenturySchlbk-Roman +spacewidth 278 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -74 +A w -74 +A v -74 +A ' -74 +A Y -92 +A W -92 +A V -111 +A T -55 +F . -111 +F , -111 +F A -74 +L y -55 +L ' -55 +L Y -92 +L W -74 +L V -92 +L T -55 +P . -129 +P , -129 +P A -74 +R y -18 +R Y -37 +R W -37 +R V -37 +T y -52 +T w -71 +T u -71 +T ; -55 +T s -62 +T r -62 +T . -92 +T o -92 +T i -25 +T - -92 +T hy -92 +T char173 -92 +T e -92 +T , -92 +T : -55 +T c -81 +T a -62 +T A -55 +V y -92 +V u -74 +V ; -74 +V r -74 +V . -129 +V o -92 +V i -44 +V - -92 +V hy -92 +V char173 -92 +V e -92 +V , -129 +V : -74 +V a -92 +V A -111 +W y -74 +W u -55 +W ; -37 +W r -55 +W . -111 +W o -55 +W i -37 +W - -37 +W hy -37 +W char173 -37 +W e -55 +W , -111 +W : -37 +W a -74 +W A -92 +Y v -111 +Y u -92 +Y ; -92 +Y q -111 +Y . -111 +Y p -111 +Y o -111 +Y i -44 +Y - -111 +Y hy -111 +Y char173 -111 +Y e -111 +Y , -111 +Y : -92 +Y a -111 +Y A -92 +f ' 114 +1 1 -55 +` ` -18 +` oq -18 +oq ` -18 +oq oq -18 +' t -18 +' s -37 +' ' -18 +r ' 55 +r . -74 +r - -18 +r hy -18 +r char173 -18 +r , -74 +v . -111 +v , -111 +w . -92 +w , -92 +y . -111 +y , -111 +charset +ha 606,722 2 0000 asciicircum +ti 606,329 0 0001 asciitilde +vS 630,952,15 2 0002 Scaron +vZ 611,952 2 0003 Zcaron +vs 463,694,15 2 0004 scaron +vz 481,694 2 0005 zcaron +:Y 704,902 2 0006 Ydieresis +tm 1000,737 2 0007 trademark +aq 204,737 2 0010 quotesingle +space 278 0 0040 +! 296,737,15 2 0041 exclam +" 389,737 2 0042 quotedbl +# 556,690 2 0043 numbersign +sh " +$ 556,804,129 2 0044 dollar +Do " +% 833,707,18 2 0045 percent +& 815,737,15 2 0046 ampersand +' 204,737 2 0047 quoteright +( 333,737,124 2 0050 parenleft +) 333,737,124 2 0051 parenright +* 500,737 2 0052 asterisk ++ 606,492,13 0 0053 plus +, 278,109,184 0 0054 comma +- 333,279 0 0055 hyphen +hy " +char173 " +. 278,109,15 0 0056 period +/ 278,737,15 2 0057 slash +sl " +0 556,705,15 2 0060 zero +1 556,705 2 0061 one +2 556,705,4 2 0062 two +3 556,705,15 2 0063 three +4 556,705 2 0064 four +5 556,705,15 2 0065 five +6 556,705,15 2 0066 six +7 556,705,15 2 0067 seven +8 556,705,15 2 0070 eight +9 556,705,15 2 0071 nine +: 278,475,15 0 0072 colon +; 278,475,189 0 0073 semicolon +< 606,503,25 0 0074 less += 606,374 0 0075 equal +> 606,503,25 0 0076 greater +? 444,737,15 2 0077 question +@ 737,737,15 2 0100 at +at " +A 722,737 2 0101 A +B 722,722 2 0102 B +C 722,737,15 2 0103 C +D 778,722 2 0104 D +E 722,722 2 0105 E +F 667,722 2 0106 F +G 778,737,15 2 0107 G +H 833,722 2 0110 H +I 407,722 2 0111 I +J 556,722,15 2 0112 J +K 778,722 2 0113 K +L 667,722 2 0114 L +M 944,722 2 0115 M +N 815,722,15 2 0116 N +O 778,737,15 2 0117 O +P 667,722 2 0120 P +Q 778,737,189 2 0121 Q +R 722,722,15 2 0122 R +S 630,737,15 2 0123 S +T 667,722 2 0124 T +U 815,722,15 2 0125 U +V 722,722,15 2 0126 V +W 981,722,15 2 0127 W +X 704,722 2 0130 X +Y 704,722 2 0131 Y +Z 611,722 2 0132 Z +[ 333,722,109 2 0133 bracketleft +lB " +\ 606,737 2 0134 backslash +rs " +] 333,723,108 2 0135 bracketright +rB " +a^ 333,694 2 0136 circumflex +^ " +_ 500,0,134 0 0137 underscore +` 204,737 2 0140 quoteleft +oq " +a 556,479,15 0 0141 a +b 556,737,15 2 0142 b +c 444,479,15 0 0143 c +d 574,737,15 2 0144 d +e 500,479,15 0 0145 e +f 333,737 2 0146 f +g 537,494,205 1 0147 g +h 611,737 2 0150 h +i 315,716 2 0151 i +j 296,716,205 3 0152 j +k 593,737 2 0153 k +l 315,737 2 0154 l +m 889,479 0 0155 m +n 611,479 0 0156 n +o 500,479,15 0 0157 o +p 574,479,205 1 0160 p +q 556,479,205 1 0161 q +r 444,479 0 0162 r +s 463,479,15 0 0163 s +t 389,666,15 2 0164 t +u 611,464,15 0 0165 u +v 537,464,15 0 0166 v +w 778,464,15 0 0167 w +x 537,464 0 0170 x +y 537,464,205 1 0171 y +z 481,464 0 0172 z +lC 333,722,109 2 0173 braceleft +{ " +ba 606,737 2 0174 bar +| " +rC 333,722,109 2 0175 braceright +} " +a~ 333,659 0 0176 tilde +~ " +bq 204,104,189 0 0200 quotesinglbase +Fo 426,397 0 0201 guillemotleft +char171 " +Fc 426,399 0 0202 guillemotright +char187 " +bu 606,554 0 0203 bullet +Fn 556,737,205 3 0204 florin +f/ 167,705 2 0205 fraction +%0 1000,699,1 2 0206 perthousand +dg 500,737,147 2 0207 dagger +dd 500,737,151 2 0210 daggerdbl +en 556,269 0 0211 endash +em 1000,269 0 0212 emdash +fi 611,737 2 0214 fi +fl 611,737 2 0215 fl +.i 315,464 0 0220 dotlessi +ga 333,699 2 0222 grave +a" 333,714 2 0223 hungarumlaut +a. 333,644 0 0224 dotaccent +ab 333,685 2 0225 breve +ah 333,694 2 0226 caron +ao 333,722 2 0227 ring +ho 333,0,163 0 0230 ogonek +lq 389,737 2 0231 quotedblleft +rq 389,737 2 0232 quotedblright +oe 833,479,15 0 0233 oe +/l 315,737 2 0234 lslash +Bq 389,104,189 0 0235 quotedblbase +OE 1000,722 2 0236 OE +/L 667,722 2 0237 Lslash +r! 296,547,205 1 0241 exclamdown +char161 " +ct 556,584,141 0 0242 cent +char162 " +Po 556,705,15 2 0243 sterling +char163 " +Cs 556,603 0 0244 currency +char164 " +Ye 556,705 2 0245 yen +char165 " +bb 606,737 2 0246 brokenbar +char166 " +sc 500,737,147 2 0247 section +char167 " +ad 333,644 0 0250 dieresis +char168 " +co 737,737,15 2 0251 copyright +char169 " +Of 334,722 2 0252 ordfeminine +char170 " +fo 259,397 0 0253 guilsinglleft +no 606,374 0 0254 logicalnot +char172 " +\- 606,277 0 0255 minus +rg 737,737,15 2 0256 registered +char174 " +a- 333,622 0 0257 macron +char175 " +de 400,705 2 0260 degree +char176 " +char177 606,492 0 0261 plusminus +S2 333,705 2 0262 twosuperior +char178 " +S3 333,705 2 0263 threesuperior +char179 " +aa 333,699 2 0264 acute +char180 " +char181 611,464,205 1 0265 mu +ps 606,722,147 2 0266 paragraph +char182 " +char183 278,302 0 0267 periodcentered +ac 333,0,215 1 0270 cedilla +char184 " +S1 333,705 2 0271 onesuperior +char185 " +Om 300,722 2 0272 ordmasculine +char186 " +fc 259,399 0 0273 guilsinglright +14 834,705 2 0274 onequarter +char188 " +12 834,705,2 2 0275 onehalf +char189 " +34 834,705 2 0276 threequarters +char190 " +r? 444,547,205 1 0277 questiondown +char191 " +`A 722,957 2 0300 Agrave +char192 " +'A 722,957 2 0301 Aacute +char193 " +^A 722,952 2 0302 Acircumflex +char194 " +~A 722,917 2 0303 Atilde +char195 " +:A 722,902 2 0304 Adieresis +char196 " +oA 722,980 2 0305 Aring +char197 " +AE 1000,722 2 0306 AE +char198 " +,C 722,737,215 3 0307 Ccedilla +char199 " +`E 722,957 2 0310 Egrave +char200 " +'E 722,957 2 0311 Eacute +char201 " +^E 722,952 2 0312 Ecircumflex +char202 " +:E 722,902 2 0313 Edieresis +char203 " +`I 407,957 2 0314 Igrave +char204 " +'I 407,957 2 0315 Iacute +char205 " +^I 407,952 2 0316 Icircumflex +char206 " +:I 407,902 2 0317 Idieresis +char207 " +-D 778,722 2 0320 Eth +char208 " +~N 815,917,15 2 0321 Ntilde +char209 " +`O 778,957,15 2 0322 Ograve +char210 " +'O 778,957,15 2 0323 Oacute +char211 " +^O 778,952,15 2 0324 Ocircumflex +char212 " +~O 778,917,15 2 0325 Otilde +char213 " +:O 778,902,15 2 0326 Odieresis +char214 " +char215 606,491,13 0 0327 multiply +/O 778,760,74 2 0330 Oslash +char216 " +`U 815,957,15 2 0331 Ugrave +char217 " +'U 815,957,15 2 0332 Uacute +char218 " +^U 815,952,15 2 0333 Ucircumflex +char219 " +:U 815,902,15 2 0334 Udieresis +char220 " +'Y 704,957 2 0335 Yacute +char221 " +TP 667,722 2 0336 Thorn +char222 " +ss 574,737,15 2 0337 germandbls +char223 " +`a 556,699,15 2 0340 agrave +char224 " +'a 556,699,15 2 0341 aacute +char225 " +^a 556,694,15 2 0342 acircumflex +char226 " +~a 556,659,15 0 0343 atilde +char227 " +:a 556,644,15 0 0344 adieresis +char228 " +oa 556,722,15 2 0345 aring +char229 " +ae 796,479,15 0 0346 ae +char230 " +,c 444,479,215 1 0347 ccedilla +char231 " +`e 500,699,15 2 0350 egrave +char232 " +'e 500,699,15 2 0351 eacute +char233 " +^e 500,694,15 2 0352 ecircumflex +char234 " +:e 500,644,15 0 0353 edieresis +char235 " +`i 315,699 2 0354 igrave +char236 " +'i 315,699 2 0355 iacute +char237 " +^i 315,694 2 0356 icircumflex +char238 " +:i 315,644 0 0357 idieresis +char239 " +Sd 500,740,15 2 0360 eth +char240 " +~n 611,659 0 0361 ntilde +char241 " +`o 500,699,15 2 0362 ograve +char242 " +'o 500,699,15 2 0363 oacute +char243 " +^o 500,694,15 2 0364 ocircumflex +char244 " +~o 500,659,15 0 0365 otilde +char245 " +:o 500,644,15 0 0366 odieresis +char246 " +char247 606,493,11 0 0367 divide +/o 500,556,102 0 0370 oslash +char248 " +`u 611,699,15 2 0371 ugrave +char249 " +'u 611,699,15 2 0372 uacute +char250 " +^u 611,694,15 2 0373 ucircumflex +char251 " +:u 611,644,15 0 0374 udieresis +char252 " +'y 537,699,205 3 0375 yacute +char253 " +Tp 574,737,205 3 0376 thorn +char254 " +:y 537,644,205 1 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/PB b/gnu/usr.bin/groff/devices/devps/PB new file mode 100644 index 0000000000..348281ad3d --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/PB @@ -0,0 +1,449 @@ +name PB +internalname Palatino-Bold +spacewidth 250 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -70 +A w -70 +A v -70 +A ' -92 +A Y -111 +A W -90 +A V -129 +A T -92 +F . -111 +F , -111 +F A -55 +L y -74 +L ' -74 +L Y -92 +L W -92 +L V -92 +L T -74 +P . -129 +P , -129 +P A -74 +R y -30 +R Y -55 +R W -37 +R V -74 +R T -55 +T y -90 +T w -90 +T u -129 +T ; -74 +T s -111 +T r -111 +T . -92 +T o -111 +T i -55 +T - -92 +T hy -92 +T char173 -92 +T e -111 +T , -92 +T : -74 +T c -129 +T a -111 +T A -92 +V y -90 +V u -92 +V ; -74 +V r -111 +V . -129 +V o -111 +V i -55 +V - -92 +V hy -92 +V char173 -92 +V e -111 +V , -129 +V : -74 +V a -111 +V A -129 +W y -74 +W u -74 +W ; -37 +W r -74 +W . -37 +W o -74 +W i -37 +W - -37 +W hy -37 +W char173 -37 +W e -74 +W , -92 +W : -37 +W a -74 +W A -90 +Y v -74 +Y u -74 +Y ; -55 +Y q -92 +Y . -74 +Y p -74 +Y o -74 +Y i -55 +Y - -74 +Y hy -74 +Y char173 -74 +Y e -74 +Y , -74 +Y : -55 +Y a -74 +Y A -55 +f ' 37 +f f -18 +1 1 -37 +` ` -55 +` oq -55 +oq ` -55 +oq oq -55 +' t -18 +' s -55 +' ' -55 +r ' 55 +r . -55 +r - -18 +r hy -18 +r char173 -18 +r , -55 +v . -111 +v , -111 +w . -92 +w , -92 +y . -92 +y , -92 +charset +ha 606,678 2 0000 asciicircum +ti 606,342 0 0001 asciitilde +vS 611,909,17 2 0002 Scaron +vZ 667,909,3 2 0003 Zcaron +vs 444,693,17 2 0004 scaron +vz 500,693,3 2 0005 zcaron +:Y 667,895,3 2 0006 Ydieresis +tm 998,678 2 0007 trademark +aq 227,695 2 0010 quotesingle +space 250 0 0040 +! 278,688,12 2 0041 exclam +" 402,695 2 0042 quotedbl +# 500,673 2 0043 numbersign +sh " +$ 500,721,114 2 0044 dollar +Do " +% 889,714,9 2 0045 percent +& 833,684,17 2 0046 ampersand +' 278,695 2 0047 quoteright +( 333,723,104 2 0050 parenleft +) 333,723,104 2 0051 parenright +* 444,695 2 0052 asterisk ++ 606,505 0 0053 plus +, 250,141,166 0 0054 comma +- 333,305 0 0055 hyphen +hy " +char173 " +. 250,144,12 0 0056 period +/ 296,720,17 2 0057 slash +sl " +0 500,660,17 2 0060 zero +1 500,670,3 2 0061 one +2 500,660,3 2 0062 two +3 500,660,17 2 0063 three +4 500,672,3 2 0064 four +5 500,656,17 2 0065 five +6 500,660,17 2 0066 six +7 500,656,3 2 0067 seven +8 500,660,17 2 0070 eight +9 500,660,17 2 0071 nine +: 250,454,12 0 0072 colon +; 250,454,166 0 0073 semicolon +< 606,519,15 0 0074 less += 606,396 0 0075 equal +> 606,519,15 0 0076 greater +? 444,687,12 2 0077 question +@ 747,681,12 2 0100 at +at " +A 778,686,3 2 0101 A +B 667,681,3 2 0102 B +C 722,695,17 2 0103 C +D 833,681,3 2 0104 D +E 611,681,4 2 0105 E +F 556,681,3 2 0106 F +G 833,695,17 2 0107 G +H 833,681,3 2 0110 H +I 389,681,3 2 0111 I +J 389,681,213 2 0112 J +K 778,681,3 2 0113 K +L 611,681,4 2 0114 L +M 1000,681,10 2 0115 M +N 833,681,16 2 0116 N +O 833,695,17 2 0117 O +P 611,681,3 2 0120 P +Q 833,695,184 2 0121 Q +R 722,681,3 2 0122 R +S 611,695,17 2 0123 S +T 667,681,3 2 0124 T +U 778,681,17 2 0125 U +V 778,681,3 2 0126 V +W 1000,686,3 2 0127 W +X 667,695,3 2 0130 X +Y 667,695,3 2 0131 Y +Z 667,681,3 2 0132 Z +[ 333,720,104 2 0133 bracketleft +lB " +\ 606,720 2 0134 backslash +rs " +] 333,720,104 2 0135 bracketright +rB " +a^ 333,681 2 0136 circumflex +^ " +_ 500,0,125 0 0137 underscore +` 278,695 2 0140 quoteleft +oq " +a 500,471,17 0 0141 a +b 611,720,17 2 0142 b +c 444,471,17 0 0143 c +d 611,720,17 2 0144 d +e 500,471,17 0 0145 e +f 389,720,3 2 0146 f +g 556,471,266 1 0147 g +h 611,720,3 2 0150 h +i 333,706,3 2 0151 i +j 333,706,266 3 0152 j +k 611,720,3 2 0153 k +l 333,720,3 2 0154 l +m 889,471,3 0 0155 m +n 611,471,3 0 0156 n +o 556,471,17 0 0157 o +p 611,471,258 1 0160 p +q 611,471,258 1 0161 q +r 389,471,3 0 0162 r +s 444,471,17 0 0163 s +t 333,632,17 2 0164 t +u 611,471,17 0 0165 u +v 556,459,3 0 0166 v +w 833,471,3 0 0167 w +x 500,471,3 0 0170 x +y 556,459,266 1 0171 y +z 500,459,3 0 0172 z +lC 310,725,117 2 0173 braceleft +{ " +ba 606,720 2 0174 bar +| " +rC 310,725,117 2 0175 braceright +} " +a~ 333,661 2 0176 tilde +~ " +bq 333,130,160 0 0200 quotesinglbase +Fo 500,438 0 0201 guillemotleft +char171 " +Fc 500,438 0 0202 guillemotright +char187 " +bu 606,516 0 0203 bullet +Fn 500,703,242 2 0204 florin +f/ 167,660 2 0205 fraction +%0 1000,724,9 2 0206 perthousand +dg 500,682,6 2 0207 dagger +dd 500,682,245 2 0210 daggerdbl +en 500,291 0 0211 endash +em 1000,291 0 0212 emdash +fi 611,720,3 2 0214 fi +fl 611,720,3 2 0215 fl +.i 333,471,3 0 0220 dotlessi +ga 333,691 2 0222 grave +a" 333,691 2 0223 hungarumlaut +a. 333,671 2 0224 dotaccent +ab 333,669 2 0225 breve +ah 333,685 2 0226 caron +ao 333,700 2 0227 ring +ho 333,0,246 0 0230 ogonek +lq 500,695 2 0231 quotedblleft +rq 500,695 2 0232 quotedblright +oe 833,471,17 0 0233 oe +/l 333,720,3 2 0234 lslash +Bq 500,130,160 0 0235 quotedblbase +OE 1000,695,17 2 0236 OE +/L 611,681,4 2 0237 Lslash +r! 278,471,227 0 0241 exclamdown +char161 " +ct 500,554,106 0 0242 cent +char162 " +Po 500,676,19 2 0243 sterling +char163 " +Cs 500,533 0 0244 currency +char164 " +Ye 500,695,3 2 0245 yen +char165 " +bb 606,720 2 0246 brokenbar +char166 " +sc 500,695,217 2 0247 section +char167 " +ad 333,671 2 0250 dieresis +char168 " +co 747,695,17 2 0251 copyright +char169 " +Of 438,660 2 0252 ordfeminine +char170 " +fo 389,438 0 0253 guilsinglleft +no 606,396 0 0254 logicalnot +char172 " +\- 606,298 0 0255 minus +rg 747,695,17 2 0256 registered +char174 " +a- 333,609 0 0257 macron +char175 " +de 400,660 2 0260 degree +char176 " +char177 606,505 0 0261 plusminus +S2 300,660 2 0262 twosuperior +char178 " +S3 300,667 2 0263 threesuperior +char179 " +aa 333,691 2 0264 acute +char180 " +char181 611,471,225 0 0265 mu +ps 641,683,161 2 0266 paragraph +char182 " +char183 250,335 0 0267 periodcentered +ac 333,0,225 0 0270 cedilla +char184 " +S1 300,665 2 0271 onesuperior +char185 " +Om 488,660 2 0272 ordmasculine +char186 " +fc 389,438 0 0273 guilsinglright +14 750,665,2 2 0274 onequarter +char188 " +12 750,665,2 2 0275 onehalf +char189 " +34 750,667,2 2 0276 threequarters +char190 " +r? 444,471,231 0 0277 questiondown +char191 " +`A 778,915,3 2 0300 Agrave +char192 " +'A 778,915,3 2 0301 Aacute +char193 " +^A 778,905,3 2 0302 Acircumflex +char194 " +~A 778,885,3 2 0303 Atilde +char195 " +:A 778,895,3 2 0304 Adieresis +char196 " +oA 778,924,3 2 0305 Aring +char197 " +AE 1000,681,4 2 0306 AE +char198 " +,C 722,695,225 2 0307 Ccedilla +char199 " +`E 611,915,4 2 0310 Egrave +char200 " +'E 611,915,4 2 0311 Eacute +char201 " +^E 611,905,4 2 0312 Ecircumflex +char202 " +:E 611,895,4 2 0313 Edieresis +char203 " +`I 389,915,3 2 0314 Igrave +char204 " +'I 389,915,3 2 0315 Iacute +char205 " +^I 389,905,3 2 0316 Icircumflex +char206 " +:I 389,895,3 2 0317 Idieresis +char207 " +-D 833,681,3 2 0320 Eth +char208 " +~N 833,885,16 2 0321 Ntilde +char209 " +`O 833,915,17 2 0322 Ograve +char210 " +'O 833,915,17 2 0323 Oacute +char211 " +^O 833,905,17 2 0324 Ocircumflex +char212 " +~O 833,885,17 2 0325 Otilde +char213 " +:O 833,895,17 2 0326 Odieresis +char214 " +char215 606,483 0 0327 multiply +/O 833,698,20 2 0330 Oslash +char216 " +`U 778,915,17 2 0331 Ugrave +char217 " +'U 778,915,17 2 0332 Uacute +char218 " +^U 778,905,17 2 0333 Ucircumflex +char219 " +:U 778,895,17 2 0334 Udieresis +char220 " +'Y 667,915,3 2 0335 Yacute +char221 " +TP 611,681,3 2 0336 Thorn +char222 " +ss 611,720,17 2 0337 germandbls +char223 " +`a 500,711,17 2 0340 agrave +char224 " +'a 500,711,17 2 0341 aacute +char225 " +^a 500,701,17 2 0342 acircumflex +char226 " +~a 500,673,17 2 0343 atilde +char227 " +:a 500,691,17 2 0344 adieresis +char228 " +oa 500,700,17 2 0345 aring +char229 " +ae 778,471,17 0 0346 ae +char230 " +,c 444,471,225 0 0347 ccedilla +char231 " +`e 500,711,17 2 0350 egrave +char232 " +'e 500,711,17 2 0351 eacute +char233 " +^e 500,701,17 2 0352 ecircumflex +char234 " +:e 500,691,17 2 0353 edieresis +char235 " +`i 333,711,3 2 0354 igrave +char236 " +'i 333,711,3 2 0355 iacute +char237 " +^i 333,701,3 2 0356 icircumflex +char238 " +:i 333,691,3 2 0357 idieresis +char239 " +Sd 556,720,17 2 0360 eth +char240 " +~n 611,673,3 2 0361 ntilde +char241 " +`o 556,711,17 2 0362 ograve +char242 " +'o 556,711,17 2 0363 oacute +char243 " +^o 556,701,17 2 0364 ocircumflex +char244 " +~o 556,673,17 2 0365 otilde +char245 " +:o 556,691,17 2 0366 odieresis +char246 " +char247 606,510 0 0367 divide +/o 556,471,18 0 0370 oslash +char248 " +`u 611,711,17 2 0371 ugrave +char249 " +'u 611,711,17 2 0372 uacute +char250 " +^u 611,701,17 2 0373 ucircumflex +char251 " +:u 611,691,17 2 0374 udieresis +char252 " +'y 556,711,266 3 0375 yacute +char253 " +Tp 611,720,258 3 0376 thorn +char254 " +:y 556,691,266 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/PBI b/gnu/usr.bin/groff/devices/devps/PBI new file mode 100644 index 0000000000..37facbe948 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/PBI @@ -0,0 +1,451 @@ +name PBI +internalname Palatino-BoldItalic +slant 10 +spacewidth 250 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -55 +A w -37 +A v -55 +A ' -55 +A Y -74 +A W -74 +A V -74 +A T -55 +F . -111 +F , -111 +F A -74 +L y -37 +L ' -55 +L Y -74 +L W -74 +L V -74 +L T -74 +P . -129 +P , -129 +P A -92 +R y -20 +R Y -37 +R W -55 +R V -55 +R T -37 +T y -80 +T w -50 +T u -92 +T ; -55 +T s -92 +T r -92 +T . -55 +T o -111 +T i -74 +T - -92 +T hy -92 +T char173 -92 +T e -111 +T , -55 +T : -55 +T c -92 +T a -111 +T O -18 +T A -55 +V y -50 +V u -50 +V ; -37 +V r -74 +V . -111 +V o -74 +V i -50 +V - -37 +V hy -37 +V char173 -37 +V e -74 +V , -111 +V : -37 +V a -92 +V A -74 +W y -30 +W u -30 +W ; -18 +W r -30 +W . -55 +W o -55 +W i -30 +W e -55 +W , -55 +W : -28 +W a -74 +W A -74 +Y v -30 +Y u -50 +Y ; -55 +Y q -92 +Y . -55 +Y p -74 +Y o -111 +Y i -54 +Y - -55 +Y hy -55 +Y char173 -55 +Y e -92 +Y , -55 +Y : -55 +Y a -111 +Y A -55 +f ' 37 +f f -37 +1 1 -55 +` ` -55 +` oq -55 +oq ` -55 +oq oq -55 +' t -18 +' s -37 +' ' -55 +r ' 55 +r q -18 +r . -55 +r o -18 +r h -18 +r g -18 +r e -18 +r , -55 +r c -18 +v . -55 +v , -55 +w . -55 +w , -55 +y . -37 +y , -37 +charset +ha 606,678,0,0,-13 2 0000 asciicircum +ti 606,346,0,0,-1 0 0001 asciitilde +vS 556,896,17,51,0,51 2 0002 Scaron +vZ 667,896,3,59,49,59 2 0003 Zcaron +vs 444,692,17,95,25,66 2 0004 scaron +vz 500,692,17,67,19,66 2 0005 zcaron +:Y 611,880,3,114,-4,66 2 0006 Ydieresis +tm 1000,678,0,11,12,11 2 0007 trademark +aq 250,720,0,93,-77,66 2 0010 quotesingle +space 250 0 0040 +! 333,695,17,39,-8,39 2 0041 exclam +" 500,720,0,43,-87,43 2 0042 quotedbl +# 500,673,0,46,46,46 2 0043 numbersign +sh " +$ 500,737,108,27,30,27 2 0044 dollar +Do " +% 889,697,17,0,-6 2 0045 percent +& 833,695,17,28,-24,28 2 0046 ampersand +' 278,720,0,74,-26,66 2 0047 quoteright +( 333,723,129,85,-8,66 2 0050 parenleft +) 333,723,129,15,62,15 2 0051 parenright +* 444,695,0,45,-34,45 2 0052 asterisk ++ 606,501,5 0 0053 plus +, 250,147,164,8,83,8 0 0054 comma +- 389,300,0,23,13,23 0 0055 hyphen +hy " +char173 " +. 250,135,17,0,2 0 0056 period +/ 315,720,17,50,49,50 2 0057 slash +sl " +0 500,683,17,40,8,40 2 0060 zero +1 500,678,3,0,9 2 0061 one +2 500,683,3,4,49,4 2 0062 two +3 500,683,17,0,42 2 0063 three +4 500,683,3,37,47,37 2 0064 four +5 500,675,17,31,36,31 2 0065 five +6 500,683,17,38,11,38 2 0066 six +7 500,674,3,94,-19,66 2 0067 seven +8 500,683,17,34,24,34 2 0070 eight +9 500,683,17,41,23,41 2 0071 nine +: 250,452,17,36,12,36 0 0072 colon +; 250,452,164,47,83,47 0 0073 semicolon +< 606,517,21,2,1,2 0 0074 less += 606,390,0,0,-1 0 0075 equal +> 606,517,21,1,2,1 0 0076 greater +? 444,695,17,56,-41,56 2 0077 question +@ 833,681,12,0,-32 2 0100 at +at " +A 722,683,3,13,85,13 2 0101 A +B 667,681,3,12,42,12 2 0102 B +C 685,695,17,60,-19,60 2 0103 C +D 778,682,3,19,50,19 2 0104 D +E 611,681,3,45,39,45 2 0105 E +F 556,681,3,87,56,66 2 0106 F +G 778,695,17,22,-22,22 2 0107 G +H 778,681,3,98,62,66 2 0110 H +I 389,681,3,73,51,66 2 0111 I +J 389,681,207,78,79,66 2 0112 J +K 722,681,3,74,60,66 2 0113 K +L 611,681,3,17,24,17 2 0114 L +M 944,681,17,91,73,66 2 0115 M +N 778,681,3,101,52,66 2 0116 N +O 833,695,17,11,-26,11 2 0117 O +P 667,681,3,56,39,56 2 0120 P +Q 833,695,222,11,-26,11 2 0121 Q +R 722,681,3,25,46,25 2 0122 R +S 556,695,17,11,0,11 2 0123 S +T 611,681,3,113,-6,66 2 0124 T +U 778,681,17,97,-33,66 2 0125 U +V 667,681,3,128,-17,66 2 0126 V +W 1000,689,3,123,-17,66 2 0127 W +X 722,681,3,100,59,66 2 0130 X +Y 611,695,3,114,-4,66 2 0131 Y +Z 667,681,3,59,49,59 2 0132 Z +[ 333,723,102,98,5,66 2 0133 bracketleft +lB " +\ 606,720,0,0,-22 2 0134 backslash +rs " +] 333,723,102,32,71,32 2 0135 bracketright +rB " +a^ 333,684,0,132,-38,66 2 0136 circumflex +^ " +_ 500,0,125,50,50,50 0 0137 underscore +` 278,720,0,63,-15,63 2 0140 quoteleft +oq " +a 556,470,17,13,6,13 0 0141 a +b 537,726,17,7,6,7 2 0142 b +c 444,469,17,42,18,42 0 0143 c +d 556,726,17,44,12,44 2 0144 d +e 444,469,17,24,22,24 0 0145 e +f 333,726,271,166,180,66 3 0146 f +g 500,469,271,79,100,66 1 0147 g +h 556,726,17,16,28,16 2 0150 h +i 333,695,17,29,24,29 2 0151 i +j 333,695,271,40,114,40 3 0152 j +k 556,726,17,22,16,22 2 0153 k +l 333,726,17,35,-14,35 2 0154 l +m 833,469,17,20,31,20 0 0155 m +n 556,469,17,15,33,15 0 0156 n +o 556,469,17,0,2 0 0157 o +p 556,469,271,10,71,10 1 0160 p +q 537,469,271,26,18,26 1 0161 q +r 389,469,17,72,30,66 0 0162 r +s 444,469,17,12,25,12 0 0163 s +t 389,636,17,70,8,66 2 0164 t +u 556,469,17,15,28,15 0 0165 u +v 556,469,17,7,31,7 0 0166 v +w 833,469,17,19,23,19 0 0167 w +x 500,469,17,50,58,50 0 0170 x +y 556,469,271,35,37,35 1 0171 y +z 500,469,17,20,19,20 0 0172 z +lC 333,720,105,51,32,51 2 0173 braceleft +{ " +ba 606,720,0,0,-209 2 0174 bar +| " +rC 333,720,105,32,51,32 2 0175 braceright +} " +a~ 333,654,0,158,-32,66 2 0176 tilde +~ " +bq 250,145,144,20,53,20 0 0200 quotesinglbase +Fo 500,446,0,8,15,8 0 0201 guillemotleft +char171 " +Fc 500,443,0,8,15,8 0 0202 guillemotright +char187 " +bu 606,516,0,0,-81 0 0203 bullet +Fn 500,690,242,29,42,29 2 0204 florin +f/ 167,683,0,221,220,66 2 0205 fraction +%0 1000,691,17,0,-15 2 0206 perthousand +dg 556,685,3,0,-17 2 0207 dagger +dd 556,693,153,31,17,31 2 0210 daggerdbl +en 500,282,0,62,62,62 0 0211 endash +em 1000,282,0,62,62,62 0 0212 emdash +fi 611,726,271,27,180,27 3 0214 fi +fl 611,726,271,70,180,66 3 0215 fl +.i 333,469,17,10,24,10 0 0220 dotlessi +ga 333,699,0,39,-60,39 2 0222 grave +a" 333,699,0,126,78,66 2 0223 hungarumlaut +a. 333,668,0,42,-152,42 2 0224 dotaccent +ab 333,680,0,129,-46,66 2 0225 breve +ah 333,684,0,162,-63,66 2 0226 caron +ao 556,714,0,0,-227 2 0227 ring +ho 333,0,206,0,18 0 0230 ogonek +lq 500,720,0,61,-15,61 2 0231 quotedblleft +rq 500,720,0,69,-23,66 2 0232 quotedblright +oe 778,469,17,27,2,27 0 0233 oe +/l 333,726,17,82,37,66 2 0234 lslash +Bq 500,145,144,0,68 0 0235 quotedblbase +OE 944,695,17,67,11,66 2 0236 OE +/L 611,681,3,17,44,17 2 0237 Lslash +r! 333,479,225,0,48 0 0241 exclamdown +char161 " +ct 500,547,105,6,-2,6 0 0242 cent +char162 " +Po 500,683,5,51,29,51 2 0243 sterling +char163 " +Cs 500,533,0,18,18,18 0 0244 currency +char164 " +Ye 500,695,3,88,39,66 2 0245 yen +char165 " +bb 606,720,0,0,-209 2 0246 brokenbar +char166 " +sc 556,695,151,0,3 2 0247 section +char167 " +ad 333,668,0,143,-40,66 2 0250 dieresis +char168 " +co 747,695,17,23,24,23 2 0251 copyright +char169 " +Of 333,684,0,72,3,66 2 0252 ordfeminine +char170 " +fo 333,446,0,9,-10,9 0 0253 guilsinglleft +no 606,390,0,0,-1 0 0254 logicalnot +char172 " +\- 606,292,0,0,-1 0 0255 minus +rg 747,695,17,23,24,23 2 0256 registered +char174 " +a- 333,608,0,135,-26,66 0 0257 macron +char175 " +de 400,683 2 0260 degree +char176 " +char177 606,501 0 0261 plusminus +S2 300,683,0,71,24,66 2 0262 twosuperior +char178 " +S3 300,683,0,60,27,60 2 0263 threesuperior +char179 " +aa 333,699,0,109,-103,66 2 0264 acute +char180 " +char181 556,469,232,15,65,15 0 0265 mu +ps 556,681,204,123,36,66 2 0266 paragraph +char182 " +char183 250,324,0,6,-17,6 0 0267 periodcentered +ac 333,5,218,0,38 0 0270 cedilla +char184 " +S1 300,680,0,48,9,48 2 0271 onesuperior +char185 " +Om 333,683,0,63,-1,63 2 0272 ordmasculine +char186 " +fc 333,443,0,0,15 0 0273 guilsinglright +14 750,683,2,32,32,32 2 0274 onequarter +char188 " +12 750,683,2,36,36,36 2 0275 onehalf +char189 " +34 750,683,2,32,32,32 2 0276 threequarters +char190 " +r? 444,479,226,0,62 0 0277 questiondown +char191 " +`A 722,911,3,13,85,13 2 0300 Agrave +char192 " +'A 722,911,3,13,85,13 2 0301 Aacute +char193 " +^A 722,896,3,13,85,13 2 0302 Acircumflex +char194 " +~A 722,866,3,13,85,13 2 0303 Atilde +char195 " +:A 722,880,3,13,85,13 2 0304 Adieresis +char196 " +oA 722,926,3,13,85,13 2 0305 Aring +char197 " +AE 944,681,3,33,79,33 2 0306 AE +char198 " +,C 685,695,218,60,-19,60 2 0307 Ccedilla +char199 " +`E 611,911,3,45,39,45 2 0310 Egrave +char200 " +'E 611,911,3,45,39,45 2 0311 Eacute +char201 " +^E 611,896,3,45,39,45 2 0312 Ecircumflex +char202 " +:E 611,880,3,45,39,45 2 0313 Edieresis +char203 " +`I 389,911,3,73,51,66 2 0314 Igrave +char204 " +'I 389,911,3,81,51,66 2 0315 Iacute +char205 " +^I 389,896,3,104,51,66 2 0316 Icircumflex +char206 " +:I 389,880,3,115,51,66 2 0317 Idieresis +char207 " +-D 778,682,3,19,50,19 2 0320 Eth +char208 " +~N 778,866,3,101,52,66 2 0321 Ntilde +char209 " +`O 833,911,17,11,-26,11 2 0322 Ograve +char210 " +'O 833,911,17,11,-26,11 2 0323 Oacute +char211 " +^O 833,896,17,11,-26,11 2 0324 Ocircumflex +char212 " +~O 833,866,17,11,-26,11 2 0325 Otilde +char213 " +:O 833,880,17,11,-26,11 2 0326 Odieresis +char214 " +char215 606,479,0,0,-22 0 0327 multiply +/O 833,730,54,14,-7,14 2 0330 Oslash +char216 " +`U 778,911,17,97,-33,66 2 0331 Ugrave +char217 " +'U 778,911,17,97,-33,66 2 0332 Uacute +char218 " +^U 778,896,17,97,-33,66 2 0333 Ucircumflex +char219 " +:U 778,880,17,97,-33,66 2 0334 Udieresis +char220 " +'Y 611,911,3,114,-4,66 2 0335 Yacute +char221 " +TP 667,681,3,27,39,27 2 0336 Thorn +char222 " +ss 556,726,271,43,181,43 3 0337 germandbls +char223 " +`a 556,719,17,13,6,13 2 0340 agrave +char224 " +'a 556,719,17,13,6,13 2 0341 aacute +char225 " +^a 556,704,17,21,6,21 2 0342 acircumflex +char226 " +~a 556,666,17,47,6,47 2 0343 atilde +char227 " +:a 556,688,17,32,6,32 2 0344 adieresis +char228 " +oa 556,714,17,13,6,13 2 0345 aring +char229 " +ae 738,469,17,23,6,23 0 0346 ae +char230 " +,c 444,469,218,42,18,42 0 0347 ccedilla +char231 " +`e 444,719,17,24,22,24 2 0350 egrave +char232 " +'e 444,719,17,54,22,54 2 0351 eacute +char233 " +^e 444,704,17,77,22,66 2 0352 ecircumflex +char234 " +:e 444,688,17,88,22,66 2 0353 edieresis +char235 " +`i 333,719,17,39,24,39 2 0354 igrave +char236 " +'i 333,719,17,109,24,66 2 0355 iacute +char237 " +^i 333,704,17,120,24,66 2 0356 icircumflex +char238 " +:i 333,688,17,143,24,66 2 0357 idieresis +char239 " +Sd 556,726,17,40,2,40 2 0360 eth +char240 " +~n 556,666,17,47,33,47 2 0361 ntilde +char241 " +`o 556,719,17,0,2 2 0362 ograve +char242 " +'o 556,719,17,0,2 2 0363 oacute +char243 " +^o 556,704,17,9,2,9 2 0364 ocircumflex +char244 " +~o 556,666,17,47,2,47 2 0365 otilde +char245 " +:o 556,688,17,32,2,32 2 0366 odieresis +char246 " +char247 606,501,5 0 0367 divide +/o 556,506,50,16,36,16 0 0370 oslash +char248 " +`u 556,719,17,15,28,15 2 0371 ugrave +char249 " +'u 556,719,17,15,28,15 2 0372 uacute +char250 " +^u 556,704,17,15,28,15 2 0373 ucircumflex +char251 " +:u 556,688,17,32,28,32 2 0374 udieresis +char252 " +'y 556,719,271,35,37,35 3 0375 yacute +char253 " +Tp 556,726,271,10,71,10 3 0376 thorn +char254 " +:y 556,688,271,35,37,35 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/PI b/gnu/usr.bin/groff/devices/devps/PI new file mode 100644 index 0000000000..7839606f49 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/PI @@ -0,0 +1,453 @@ +name PI +internalname Palatino-Italic +slant 10 +spacewidth 250 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -55 +A w -37 +A v -37 +A ' -55 +A Y -55 +A W -55 +A V -74 +A T -55 +F . -111 +F , -111 +F A -111 +L y -37 +L ' -37 +L Y -74 +L W -74 +L V -74 +L T -74 +P . -129 +P , -129 +P A -129 +R y -37 +R Y -55 +R W -55 +R V -74 +R T -55 +T y -92 +T w -92 +T u -111 +T ; -74 +T s -111 +T r -111 +T . -74 +T o -111 +T i -55 +T - -55 +T hy -55 +T char173 -55 +T e -111 +T , -74 +T : -74 +T c -111 +T a -111 +T O -18 +T A -92 +V y -74 +V u -74 +V ; -37 +V r -92 +V . -129 +V o -74 +V i -74 +V - -55 +V hy -55 +V char173 -55 +V e -92 +V , -129 +V : -37 +V a -74 +V A -210 +W y -20 +W u -20 +W ; -18 +W r -20 +W . -55 +W o -20 +W i -20 +W - -18 +W hy -18 +W char173 -18 +W e -20 +W , -55 +W : -18 +W a -20 +W A -92 +Y v -74 +Y u -92 +Y ; -74 +Y q -92 +Y . -92 +Y p -74 +Y o -111 +Y i -55 +Y - -74 +Y hy -74 +Y char173 -74 +Y e -111 +Y , -92 +Y : -74 +Y a -92 +Y A -92 +f ' 55 +1 1 -55 +` ` -74 +` oq -74 +oq ` -74 +oq oq -74 +' t -37 +' s -55 +' ' -74 +r ' 37 +r q -18 +r . -74 +r o -18 +r h -18 +r g -18 +r e -18 +r , -74 +r c -18 +v . -55 +v , -55 +w . -55 +w , -55 +y . -37 +y , -37 +charset +ha 606,689,0,0,-1 2 0000 asciicircum +ti 606,339,0,0,-1 0 0001 asciitilde +vS 556,907,18,33,8,33 2 0002 Scaron +vZ 667,907,3,20,30,20 2 0003 Zcaron +vs 389,687,11,80,41,68 2 0004 scaron +vz 444,687,11,53,51,53 2 0005 zcaron +:Y 667,847,3,58,-2,58 2 0006 Ydieresis +tm 1000,689,0,1,-2,1 2 0007 trademark +aq 333,733,0,5,-90,5 2 0010 quotesingle +space 250 0 0040 +! 333,733,8,9,-26,9 2 0041 exclam +" 500,733,0,5,-90,5 2 0042 quotedbl +# 500,692,0,45,46,45 2 0043 numbersign +sh " +$ 500,733,113,2,35,2 2 0044 dollar +Do " +% 889,710,7,0,-24 2 0045 percent +& 778,692,18,38,3,38 2 0046 ampersand +' 278,733,0,30,-28,30 2 0047 quoteright +( 333,733,106,48,-4,48 2 0050 parenleft +) 333,733,106,0,48 2 0051 parenright +* 389,706,0,61,-26,61 2 0052 asterisk ++ 606,504,0,0,-1 0 0053 plus +, 250,123,143,3,42,3 0 0054 comma +- 333,281,0,21,31,21 0 0055 hyphen +hy " +char173 " +. 250,112,5,0,-3 0 0056 period +/ 296,733,119,146,90,68 2 0057 slash +sl " +0 500,699,11,30,14,30 2 0060 zero +1 500,699,3,0,-4 2 0061 one +2 500,699,3,0,38 2 0062 two +3 500,699,11,0,28 2 0063 three +4 500,699,3,28,35,28 2 0064 four +5 500,693,11,41,36,41 2 0065 five +6 500,699,11,19,1,19 2 0066 six +7 500,692,3,52,-3,52 2 0067 seven +8 500,699,11,19,14,19 2 0070 eight +9 500,699,11,18,18,18 2 0071 nine +: 250,458,5,7,6,7 0 0072 colon +; 250,456,146,19,59,19 0 0073 semicolon +< 606,516,6,0,-3 0 0074 less += 606,378,0,0,-1 0 0075 equal +> 606,516,6,0,-3 0 0076 greater +? 500,706,8,0,-64 2 0077 question +@ 747,706,18,21,23,21 2 0100 at +at " +A 722,705,3,5,69,5 2 0101 A +B 611,692,6,0,24 2 0102 B +C 667,706,18,34,5,34 2 0103 C +D 778,692,3,13,22,13 2 0104 D +E 611,692,3,9,20,9 2 0105 E +F 556,692,3,42,50,42 2 0106 F +G 722,706,18,22,0,22 2 0107 G +H 778,692,3,72,53,68 2 0110 H +I 333,692,3,71,43,68 2 0111 I +J 333,692,206,75,85,68 2 0112 J +K 667,692,3,66,37,66 2 0113 K +L 556,692,3,17,34,17 2 0114 L +M 944,692,18,46,69,46 2 0115 M +N 778,692,11,76,48,68 2 0116 N +O 778,706,18,20,-3,20 2 0117 O +P 611,692,3,33,41,33 2 0120 P +Q 778,706,201,20,-3,20 2 0121 Q +R 667,692,3,22,41,22 2 0122 R +S 556,706,18,0,8 2 0123 S +T 611,692,3,74,-3,68 2 0124 T +U 778,692,18,70,-38,68 2 0125 U +V 722,692,8,82,-25,68 2 0126 V +W 944,700,8,86,-21,68 2 0127 W +X 722,692,3,62,30,62 2 0130 X +Y 667,705,3,58,-2,58 2 0131 Y +Z 667,692,3,20,30,20 2 0132 Z +[ 333,733,100,43,32,43 2 0133 bracketleft +lB " +\ 606,733,0,0,-31 2 0134 backslash +rs " +] 333,733,100,32,43,32 2 0135 bracketright +rB " +a^ 333,679,0,67,-6,67 2 0136 circumflex +^ " +_ 500,0,125,50,50,50 0 0137 underscore +` 278,733,0,30,-28,30 2 0140 quoteleft +oq " +a 444,482,11,12,46,12 0 0141 a +b 463,733,11,20,13,20 2 0142 b +c 407,482,11,32,25,32 0 0143 c +d 500,733,11,33,33,33 2 0144 d +e 389,482,11,35,35,35 0 0145 e +f 278,733,276,185,212,68 3 0146 f +g 500,482,276,48,87,48 1 0147 g +h 500,733,9,21,40,21 2 0150 h +i 278,712,9,36,16,36 2 0151 i +j 278,712,276,37,120,37 3 0152 j +k 444,733,9,55,42,55 2 0153 k +l 278,733,9,23,14,23 2 0154 l +m 778,482,9,12,26,12 0 0155 m +n 556,482,9,8,26,8 0 0156 n +o 444,482,11,17,33,17 0 0157 o +p 500,482,276,15,57,15 1 0160 p +q 463,482,276,19,26,19 1 0161 q +r 389,482,9,45,24,45 0 0162 r +s 389,482,11,6,41,6 0 0163 s +t 333,646,9,27,9,27 2 0164 t +u 556,482,11,6,18,6 0 0165 u +v 500,482,11,27,29,27 0 0166 v +w 722,482,11,27,29,27 0 0167 w +x 500,482,11,34,41,34 0 0170 x +y 500,482,276,40,58,40 1 0171 y +z 444,482,11,22,51,22 0 0172 z +lC 333,733,100,36,35,36 2 0173 braceleft +{ " +ba 606,733,0,0,-225 2 0174 bar +| " +rC 333,733,100,35,36,35 2 0175 braceright +} " +a~ 333,638,0,107,-13,68 0 0176 tilde +~ " +bq 278,120,122,0,23 0 0200 quotesinglbase +Fo 500,440,0,0,-7 0 0201 guillemotleft +char171 " +Fc 500,440,0,0,-13 0 0202 guillemotright +char187 " +bu 500,526,0,0,-36 0 0203 bullet +Fn 500,708,276,20,45,20 3 0204 florin +f/ 167,699,0,220,220,68 2 0205 fraction +%0 1000,717,6,0,-22 2 0206 perthousand +dg 500,692,0,19,2,19 2 0207 dagger +dd 500,692,162,44,40,44 2 0210 daggerdbl +en 500,278,0,60,60,60 0 0211 endash +em 1000,278,0,60,60,60 0 0212 emdash +fi 528,733,276,24,212,24 3 0214 fi +fl 545,733,276,25,212,25 3 0215 fl +.i 278,482,9,13,16,13 0 0220 dotlessi +ga 333,687,0,27,-36,27 2 0222 grave +a" 333,730,0,102,4,68 2 0223 hungarumlaut +a. 333,645,0,0,-125 2 0224 dotaccent +ab 333,677,0,110,-42,68 2 0225 breve +ah 333,679,0,126,-54,68 2 0226 caron +ao 333,708,0,76,-109,68 2 0227 ring +ho 333,0,207,0,12 0 0230 ogonek +lq 500,733,0,25,-48,25 2 0231 quotedblleft +rq 500,733,0,25,-48,25 2 0232 quotedblright +oe 669,482,11,35,33,35 0 0233 oe +/l 278,733,9,74,60,68 2 0234 lslash +Bq 500,120,122,0,7 0 0235 quotedblbase +OE 1028,706,18,11,-6,11 2 0236 OE +/L 556,692,3,17,66,17 2 0237 Lslash +r! 333,467,276,0,35 1 0241 exclamdown +char161 " +ct 500,551,96,0,-6 0 0242 cent +char162 " +Po 500,708,18,29,48,29 2 0243 sterling +char163 " +Cs 500,577,0,36,36,36 0 0244 currency +char164 " +Ye 500,699,3,62,15,62 2 0245 yen +char165 " +bb 606,733,0,0,-225 2 0246 brokenbar +char166 " +sc 500,706,220,13,36,13 2 0247 section +char167 " +ad 333,637,0,95,-28,68 0 0250 dieresis +char168 " +co 747,706,18,39,39,39 2 0251 copyright +char169 " +Of 333,699,0,38,-10,38 2 0252 ordfeminine +char170 " +fo 333,440,0,0,-7 0 0253 guilsinglleft +no 606,378,0,0,-1 0 0254 logicalnot +char172 " +\- 606,280,0,0,-1 0 0255 minus +rg 747,706,18,39,39,39 2 0256 registered +char174 " +a- 333,589,0,103,-24,68 0 0257 macron +char175 " +de 400,689,0,40,-40,40 2 0260 degree +char176 " +char177 606,504,0,0,-1 0 0261 plusminus +S2 300,699,0,40,37,40 2 0262 twosuperior +char178 " +S3 300,699,0,54,22,54 2 0263 threesuperior +char179 " +aa 333,687,0,63,-72,63 2 0264 acute +char180 " +char181 556,482,226,6,35,6 0 0265 mu +ps 500,692,224,161,17,68 2 0266 paragraph +char182 " +char183 250,312,0,0,-3 0 0267 periodcentered +ac 333,0,216,0,59 0 0270 cedilla +char184 " +S1 300,699,0,35,-11,35 2 0271 onesuperior +char185 " +Om 333,699,0,39,-16,39 2 0272 ordmasculine +char186 " +fc 333,440,0,0,-13 0 0273 guilsinglright +14 750,699,2,15,19,15 2 0274 onequarter +char188 " +12 750,699,2,21,19,21 2 0275 onehalf +char189 " +34 750,699,2,15,15,15 2 0276 threequarters +char190 " +r? 500,467,246,0,-7 0 0277 questiondown +char191 " +`A 722,897,3,5,69,5 2 0300 Agrave +char192 " +'A 722,897,3,5,69,5 2 0301 Aacute +char193 " +^A 722,889,3,5,69,5 2 0302 Acircumflex +char194 " +~A 722,866,3,5,69,5 2 0303 Atilde +char195 " +:A 722,847,3,5,69,5 2 0304 Adieresis +char196 " +oA 722,918,3,5,69,5 2 0305 Aring +char197 " +AE 941,692,3,11,54,11 2 0306 AE +char198 " +,C 667,706,216,34,5,34 2 0307 Ccedilla +char199 " +`E 611,897,3,9,20,9 2 0310 Egrave +char200 " +'E 611,897,3,9,20,9 2 0311 Eacute +char201 " +^E 611,889,3,9,20,9 2 0312 Ecircumflex +char202 " +:E 611,847,3,9,20,9 2 0313 Edieresis +char203 " +`I 333,897,3,71,43,68 2 0314 Igrave +char204 " +'I 333,897,3,123,43,68 2 0315 Iacute +char205 " +^I 333,889,3,107,43,68 2 0316 Icircumflex +char206 " +:I 333,847,3,135,43,68 2 0317 Idieresis +char207 " +-D 778,692,3,13,31,13 2 0320 Eth +char208 " +~N 778,866,11,76,48,68 2 0321 Ntilde +char209 " +`O 778,897,18,20,-3,20 2 0322 Ograve +char210 " +'O 778,897,18,20,-3,20 2 0323 Oacute +char211 " +^O 778,889,18,20,-3,20 2 0324 Ocircumflex +char212 " +~O 778,866,18,20,-3,20 2 0325 Otilde +char213 " +:O 778,847,18,20,-3,20 2 0326 Odieresis +char214 " +char215 606,474,0,0,-33 0 0327 multiply +/O 778,721,39,34,18,34 2 0330 Oslash +char216 " +`U 778,897,18,70,-38,68 2 0331 Ugrave +char217 " +'U 778,897,18,70,-38,68 2 0332 Uacute +char218 " +^U 778,889,18,70,-38,68 2 0333 Ucircumflex +char219 " +:U 778,847,18,70,-38,68 2 0334 Udieresis +char220 " +'Y 667,897,3,58,-2,58 2 0335 Yacute +char221 " +TP 611,692,3,9,41,9 2 0336 Thorn +char222 " +ss 500,733,276,38,210,38 3 0337 germandbls +char223 " +`a 444,707,11,12,46,12 2 0340 agrave +char224 " +'a 444,707,11,20,46,20 2 0341 aacute +char225 " +^a 444,699,11,12,46,12 2 0342 acircumflex +char226 " +~a 444,650,11,52,46,52 2 0343 atilde +char227 " +:a 444,657,11,40,46,40 2 0344 adieresis +char228 " +oa 444,728,11,12,46,12 2 0345 aring +char229 " +ae 638,482,11,35,49,35 0 0346 ae +char230 " +,c 407,482,216,32,25,32 0 0347 ccedilla +char231 " +`e 389,707,11,35,35,35 2 0350 egrave +char232 " +'e 389,707,11,55,35,55 2 0351 eacute +char233 " +^e 389,699,11,59,35,59 2 0352 ecircumflex +char234 " +:e 389,657,11,67,35,67 2 0353 edieresis +char235 " +`i 278,707,9,43,16,43 2 0354 igrave +char236 " +'i 278,707,9,103,16,68 2 0355 iacute +char237 " +^i 278,699,9,95,21,68 2 0356 icircumflex +char238 " +:i 278,657,9,123,16,68 2 0357 idieresis +char239 " +Sd 444,733,11,84,33,68 2 0360 eth +char240 " +~n 556,650,9,8,26,8 2 0361 ntilde +char241 " +`o 444,707,11,17,33,17 2 0362 ograve +char242 " +'o 444,707,11,20,33,20 2 0363 oacute +char243 " +^o 444,699,11,17,33,17 2 0364 ocircumflex +char244 " +~o 444,650,11,52,33,52 2 0365 otilde +char245 " +:o 444,657,11,40,33,40 2 0366 odieresis +char246 " +char247 606,504,0,0,-1 0 0367 divide +/o 444,510,24,66,68,66 0 0370 oslash +char248 " +`u 556,707,11,6,18,6 2 0371 ugrave +char249 " +'u 556,707,11,6,18,6 2 0372 uacute +char250 " +^u 556,699,11,6,18,6 2 0373 ucircumflex +char251 " +:u 556,657,11,6,18,6 2 0374 udieresis +char252 " +'y 500,707,276,40,58,40 3 0375 yacute +char253 " +Tp 500,733,276,0,89 3 0376 thorn +char254 " +:y 500,657,276,40,58,40 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/PR b/gnu/usr.bin/groff/devices/devps/PR new file mode 100644 index 0000000000..4dd5626d4e --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/PR @@ -0,0 +1,456 @@ +name PR +internalname Palatino-Roman +spacewidth 250 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -74 +A w -74 +A v -92 +A ' -74 +A Y -111 +A W -74 +A V -111 +A T -74 +F . -92 +F , -92 +F A -74 +L y -55 +L ' -74 +L Y -92 +L W -74 +L V -92 +L T -74 +P . -129 +P , -129 +P A -92 +R y -37 +R Y -37 +R W -37 +R V -55 +R T -37 +T y -90 +T w -90 +T u -90 +T ; -55 +T s -90 +T r -90 +T . -74 +T o -92 +T i -55 +T - -55 +T hy -55 +T char173 -55 +T e -92 +T , -74 +T : -55 +T c -111 +T a -92 +T O -18 +T A -74 +V y -92 +V u -92 +V ; -55 +V r -92 +V . -129 +V o -111 +V i -55 +V - -74 +V hy -74 +V char173 -74 +V e -111 +V , -129 +V : -55 +V a -92 +V A -111 +W y -50 +W u -50 +W ; -18 +W r -74 +W . -92 +W o -92 +W i -55 +W - -55 +W hy -55 +W char173 -55 +W e -92 +W , -92 +W : -18 +W a -92 +W A -92 +Y v -90 +Y u -90 +Y ; -74 +Y q -90 +Y . -111 +Y p -111 +Y o -92 +Y i -55 +Y - -92 +Y hy -92 +Y char173 -92 +Y e -92 +Y , -111 +Y : -74 +Y a -92 +Y A -92 +f ' 55 +f f -18 +1 1 -55 +` ` -37 +` oq -37 +oq ` -37 +oq oq -37 +' ' -37 +r u -8 +r ' 74 +r q -18 +r . -74 +r o -18 +r - -18 +r hy -18 +r char173 -18 +r h -18 +r g -18 +r e -18 +r d -18 +r , -74 +r c -18 +v . -111 +v , -111 +w . -92 +w , -92 +y . -111 +y , -111 +charset +ha 606,689 2 0000 asciicircum +ti 606,347 0 0001 asciitilde +vS 525,908,20 2 0002 Scaron +vZ 667,908,3 2 0003 Zcaron +vs 424,685,20 2 0004 scaron +vz 500,685,3 2 0005 zcaron +:Y 667,868,3 2 0006 Ydieresis +tm 979,689 2 0007 trademark +aq 208,709 2 0010 quotesingle +space 250 0 0040 +! 278,694,5 2 0041 exclam +" 371,709 2 0042 quotedbl +# 500,684 2 0043 numbersign +sh " +$ 500,731,116 2 0044 dollar +Do " +% 840,709,20 2 0045 percent +& 778,689,20 2 0046 ampersand +' 278,709 2 0047 quoteright +( 333,726,215 2 0050 parenleft +) 333,726,215 2 0051 parenright +* 389,689 2 0052 asterisk ++ 606,512 0 0053 plus +, 250,123,155 0 0054 comma +- 333,287 0 0055 hyphen +hy " +char173 " +. 250,111,5 0 0056 period +/ 606,726,119 2 0057 slash +sl " +0 500,689,20 2 0060 zero +1 500,694,3 2 0061 one +2 500,689,3 2 0062 two +3 500,689,20 2 0063 three +4 500,694,3 2 0064 four +5 500,689,20 2 0065 five +6 500,689,20 2 0066 six +7 500,689,3 2 0067 seven +8 500,689,20 2 0070 eight +9 500,689,20 2 0071 nine +: 250,456,5 0 0072 colon +; 250,456,153 0 0073 semicolon +< 606,522 0 0074 less += 606,386 0 0075 equal +> 606,522 0 0076 greater +? 444,694,5 2 0077 question +@ 747,694,20 2 0100 at +at " +A 778,700,3 2 0101 A +B 611,692,3 2 0102 B +C 709,709,20 2 0103 C +D 774,692,3 2 0104 D +E 611,692,3 2 0105 E +F 556,692,3 2 0106 F +G 763,709,20 2 0107 G +H 832,692,3 2 0110 H +I 337,692,3 2 0111 I +J 333,692,194 2 0112 J +K 726,692,3 2 0113 K +L 611,692,3 2 0114 L +M 946,692,13 2 0115 M +N 831,692,20 2 0116 N +O 786,709,20 2 0117 O +P 604,692,3 2 0120 P +Q 786,709,176 2 0121 Q +R 668,692,3 2 0122 R +S 525,709,20 2 0123 S +T 613,692,3 2 0124 T +U 778,692,20 2 0125 U +V 722,692,9 2 0126 V +W 1000,700,9 2 0127 W +X 667,700,3 2 0130 X +Y 667,704,3 2 0131 Y +Z 667,692,3 2 0132 Z +[ 333,726,184 2 0133 bracketleft +lB " +\ 606,726 2 0134 backslash +rs " +] 333,726,184 2 0135 bracketright +rB " +a^ 333,677 2 0136 circumflex +^ " +_ 500,0,125 0 0137 underscore +` 278,709 2 0140 quoteleft +oq " +a 500,469,12 0 0141 a +b 553,726,12 2 0142 b +c 444,469,20 0 0143 c +d 611,726,12 2 0144 d +e 479,469,20 0 0145 e +f 333,728,3 2 0146 f +g 556,469,283 1 0147 g +h 582,726,3 2 0150 h +i 291,687,3 2 0151 i +j 234,688,283 3 0152 j +k 556,726,12 2 0153 k +l 291,726,3 2 0154 l +m 883,469,3 0 0155 m +n 582,469,3 0 0156 n +o 546,469,20 0 0157 o +p 601,469,281 1 0160 p +q 560,469,281 1 0161 q +r 395,469,3 0 0162 r +s 424,469,20 0 0163 s +t 326,621,12 2 0164 t +u 603,469,12 0 0165 u +v 565,459,7 0 0166 v +w 834,469,7 0 0167 w +x 516,469,3 0 0170 x +y 556,459,283 1 0171 y +z 500,462,3 0 0172 z +lC 333,726,175 2 0173 braceleft +{ " +ba 606,726 2 0174 bar +| " +rC 333,726,175 2 0175 braceright +} " +a~ 333,640 2 0176 tilde +~ " +bq 278,110,153 0 0200 quotesinglbase +Fo 500,428 0 0201 guillemotleft +char171 " +Fc 500,428 0 0202 guillemotright +char187 " +bu 606,516 0 0203 bullet +Fn 500,706,262 2 0204 florin +f/ 167,689 2 0205 fraction +%0 1144,709,20 2 0206 perthousand +dg 500,694,5 2 0207 dagger +dd 500,694,249 2 0210 daggerdbl +en 500,277 0 0211 endash +em 1000,277 0 0212 emdash +fi 605,728,3 2 0214 fi +fl 608,728,3 2 0215 fl +.i 287,469,3 0 0220 dotlessi +ga 333,677 2 0222 grave +a" 380,687 2 0223 hungarumlaut +a. 250,637 2 0224 dotaccent +ab 333,664 2 0225 breve +ah 333,677 2 0226 caron +ao 333,696 2 0227 ring +ho 313,0,165 0 0230 ogonek +lq 500,709 2 0231 quotedblleft +rq 500,709 2 0232 quotedblright +oe 827,469,20 0 0233 oe +/l 291,726,3 2 0234 lslash +Bq 500,110,153 0 0235 quotedblbase +OE 998,709,20 2 0236 OE +/L 611,692,3 2 0237 Lslash +r! 278,469,225 0 0241 exclamdown +char161 " +ct 500,562,101 0 0242 cent +char162 " +Po 500,694,13 2 0243 sterling +char163 " +Cs 500,531 0 0244 currency +char164 " +Ye 500,701,3 2 0245 yen +char165 " +bb 606,726 2 0246 brokenbar +char166 " +sc 500,709,219 2 0247 section +char167 " +ad 333,637 2 0250 dieresis +char168 " +co 747,706,18 2 0251 copyright +char169 " +Of 333,709 2 0252 ordfeminine +char170 " +fo 331,428 0 0253 guilsinglleft +no 606,386 0 0254 logicalnot +char172 " +\- 606,289 0 0255 minus +rg 747,706,18 2 0256 registered +char174 " +a- 333,591 0 0257 macron +char175 " +de 400,689 2 0260 degree +char176 " +char177 606,512 0 0261 plusminus +S2 300,689 2 0262 twosuperior +char178 " +S3 300,689 2 0263 threesuperior +char179 " +aa 333,677 2 0264 acute +char180 " +char181 603,469,236 0 0265 mu +ps 628,694,150 2 0266 paragraph +char182 " +char183 250,319 0 0267 periodcentered +ac 333,0,225 0 0270 cedilla +char184 " +S1 300,692 2 0271 onesuperior +char185 " +Om 333,709 2 0272 ordmasculine +char186 " +fc 331,428 0 0273 guilsinglright +14 750,692,3 2 0274 onequarter +char188 " +12 750,692,3 2 0275 onehalf +char189 " +34 750,689,3 2 0276 threequarters +char190 " +r? 444,469,231 0 0277 questiondown +char191 " +`A 778,908,3 2 0300 Agrave +char192 " +'A 778,908,3 2 0301 Aacute +char193 " +^A 778,908,3 2 0302 Acircumflex +char194 " +~A 778,871,3 2 0303 Atilde +char195 " +:A 778,868,3 2 0304 Adieresis +char196 " +oA 778,927,3 2 0305 Aring +char197 " +AE 944,692,3 2 0306 AE +char198 " +,C 709,709,225 2 0307 Ccedilla +char199 " +`E 611,908,3 2 0310 Egrave +char200 " +'E 611,908,3 2 0311 Eacute +char201 " +^E 611,908,3 2 0312 Ecircumflex +char202 " +:E 611,868,3 2 0313 Edieresis +char203 " +`I 337,908,3 2 0314 Igrave +char204 " +'I 337,908,3 2 0315 Iacute +char205 " +^I 337,908,3 2 0316 Icircumflex +char206 " +:I 337,868,3 2 0317 Idieresis +char207 " +-D 774,692,3 2 0320 Eth +char208 " +~N 831,871,20 2 0321 Ntilde +char209 " +`O 786,908,20 2 0322 Ograve +char210 " +'O 786,908,20 2 0323 Oacute +char211 " +^O 786,908,20 2 0324 Ocircumflex +char212 " +~O 786,883,20 2 0325 Otilde +char213 " +:O 786,868,20 2 0326 Odieresis +char214 " +char215 606,474 0 0327 multiply +/O 833,709,20 2 0330 Oslash +char216 " +`U 778,908,20 2 0331 Ugrave +char217 " +'U 778,908,20 2 0332 Uacute +char218 " +^U 778,908,20 2 0333 Ucircumflex +char219 " +:U 778,868,20 2 0334 Udieresis +char220 " +'Y 667,908,3 2 0335 Yacute +char221 " +TP 604,692,3 2 0336 Thorn +char222 " +ss 556,731,9 2 0337 germandbls +char223 " +`a 500,697,12 2 0340 agrave +char224 " +'a 500,697,12 2 0341 aacute +char225 " +^a 500,697,12 2 0342 acircumflex +char226 " +~a 500,652,12 2 0343 atilde +char227 " +:a 500,657,12 2 0344 adieresis +char228 " +oa 500,716,12 2 0345 aring +char229 " +ae 758,469,20 0 0346 ae +char230 " +,c 444,469,225 0 0347 ccedilla +char231 " +`e 479,697,20 2 0350 egrave +char232 " +'e 479,697,20 2 0351 eacute +char233 " +^e 479,697,20 2 0352 ecircumflex +char234 " +:e 479,657,20 2 0353 edieresis +char235 " +`i 287,697,3 2 0354 igrave +char236 " +'i 287,697,3 2 0355 iacute +char237 " +^i 287,697,3 2 0356 icircumflex +char238 " +:i 287,657,3 2 0357 idieresis +char239 " +Sd 546,728,20 2 0360 eth +char240 " +~n 582,652,3 2 0361 ntilde +char241 " +`o 546,697,20 2 0362 ograve +char242 " +'o 546,697,20 2 0363 oacute +char243 " +^o 546,697,20 2 0364 ocircumflex +char244 " +~o 546,652,20 2 0365 otilde +char245 " +:o 546,657,20 2 0366 odieresis +char246 " +char247 606,512 0 0367 divide +/o 556,474,23 0 0370 oslash +char248 " +`u 603,697,12 2 0371 ugrave +char249 " +'u 603,697,12 2 0372 uacute +char250 " +^u 603,697,12 2 0373 ucircumflex +char251 " +:u 603,657,12 2 0374 udieresis +char252 " +'y 556,697,283 3 0375 yacute +char253 " +Tp 601,726,281 3 0376 thorn +char254 " +:y 556,657,283 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/S b/gnu/usr.bin/groff/devices/devps/S new file mode 100644 index 0000000000..4c58752ed3 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/S @@ -0,0 +1,227 @@ +name S +internalname Symbol +special +spacewidth 250 +charset +space 250 0 0040 +! 333,672,17 3 0041 exclam +fa 713,705 3 0042 universal +# 500,673,16 3 0043 numbersign +sh " +te 549,707 3 0044 existential +% 833,655,36 3 0045 percent +& 778,661,18 3 0046 ampersand +st 439,500,17 3 0047 suchthat +( 333,673,191 3 0050 parenleft +) 333,673,191 3 0051 parenright +** 500,551 3 0052 asteriskmath ++ 549,533 3 0053 plus +pl " +, 250,104,152 3 0054 comma +\- 549,288 3 0055 minus +mi " +. 250,95,17 3 0056 period +/ 278,646,18 3 0057 slash +sl " +0 500,685,17 3 0060 zero +1 500,673 3 0061 one +2 500,686 3 0062 two +3 500,685,17 3 0063 three +4 500,685 3 0064 four +5 500,685,17 3 0065 five +6 500,685,17 3 0066 six +7 500,673,16 3 0067 seven +8 500,685,18 3 0070 eight +9 500,685,18 3 0071 nine +: 278,460,17 3 0072 colon +; 278,460,152 3 0073 semicolon +< 549,522 3 0074 less += 549,390 3 0075 equal +eq " +> 549,522 3 0076 greater +? 444,686,17 3 0077 question +=~ 549,475 3 0100 congruent +*A 722,673 3 0101 Alpha +*B 667,673 3 0102 Beta +*X 722,673 3 0103 Chi +*D 612,688 3 0104 Delta +*E 611,673 3 0105 Epsilon +*F 763,673 3 0106 Phi +*G 603,673 3 0107 Gamma +*Y 722,673 3 0110 Eta +*I 333,673 3 0111 Iota ++h 631,689,18 3 0112 theta1 +*K 722,673 3 0113 Kappa +*L 686,688 3 0114 Lambda +*M 889,673 3 0115 Mu +*N 722,673,8 3 0116 Nu +*O 722,685,17 3 0117 Omicron +*P 768,673 3 0120 Pi +*H 741,685,17 3 0121 Theta +*R 556,673 3 0122 Rho +*S 592,673 3 0123 Sigma +*T 611,673 3 0124 Tau +--- 690,673 3 0125 Upsilon +ts 439,500,233 3 0126 sigma1 +*W 768,688 3 0127 Omega +*C 645,673 3 0130 Xi +*Q 795,684 3 0131 Psi +*Z 611,673 3 0132 Zeta +[ 333,674,155 3 0133 bracketleft +lB " +3d 863,478 3 0134 therefore +tf " +] 333,674,155 3 0135 bracketright +rB " +pp 658,674 3 0136 perpendicular +_ 500,0,252 3 0137 underscore +rn 500,917 3 0140 radicalex +*a 631,500,18 3 0141 alpha +*b 549,741,223 3 0142 beta +*x 549,499,231 3 0143 chi +*d 494,740,19 3 0144 delta +*e 439,502,19 3 0145 epsilon +*f 521,671,224 3 0146 phi +*g 411,499,225 3 0147 gamma +*y 603,514,202 3 0150 eta +*i 329,503,17 3 0151 iota ++f 603,499,224 3 0152 phi1 +*k 549,501 3 0153 kappa +*l 549,739,17 3 0154 lambda +char181 576,500,223 3 0155 mu +*m " +*n 521,507,16 3 0156 nu +*o 549,499,19 3 0157 omicron +*p 549,487,19 3 0160 pi +*h 521,690,17 3 0161 theta +*r 549,499,230 3 0162 rho +*s 603,500,21 3 0163 sigma +*t 439,500,19 3 0164 tau +*u 576,507,18 3 0165 upsilon ++p 713,583,18 3 0166 omega1 +*w 686,500,17 3 0167 omega +*c 493,766,224 3 0170 xi +*q 686,500,228 3 0171 psi +*z 494,756,225 3 0172 zeta +lC 480,673,183 3 0173 braceleft +{ " +ba 200,673,177 3 0174 bar +| " +rC 480,673,183 3 0175 braceright +} " +ap 549,307 3 0176 similar +*U 620,685 3 0241 Upsilon1 +fm 247,735 3 0242 minute +<= 549,639 3 0243 lessequal +f/ 167,677,12 3 0244 fraction +if 713,404 3 0245 infinity +Fn 500,686,193 3 0246 florin +CL 753,533,26 3 0247 club +DI 753,550,36 3 0250 diamond +HE 753,532,33 3 0251 heart +SP 753,548,36 3 0252 spade +<> 1042,511,15 3 0253 arrowboth +<- 987,511,15 3 0254 arrowleft +ua 603,910 3 0255 arrowup +arrowverttp " +-> 987,511,15 3 0256 arrowright +da 603,888,22 3 0257 arrowdown +arrowvertbt " +de 400,685 3 0260 degree +char176 " +char177 549,645 3 0261 plusminus ++- " +sd 411,737 3 0262 second +>= 549,639 3 0263 greaterequal +char215 549,524 3 0264 multiply +mu " +pt 713,404 3 0265 proportional +pd 494,746,20 3 0266 partialdiff +bu 460,473 3 0267 bullet +char247 549,456 3 0270 divide +di " +!= 549,549,25 3 0271 notequal +== 549,443 3 0272 equivalence +~~ 549,394 3 0273 approxequal +~= " +--- 1000,95,17 3 0274 ellipsis +arrowvertex 603,1010,120 3 0275 arrowvertex +--- 1000,276 3 0276 arrowhorizex +CR 658,629,16 3 0277 carriagereturn +Ah 823,658,18 3 0300 aleph +Im 686,740,53 3 0301 Ifraktur +Re 795,734,15 3 0302 Rfraktur +wp 987,573,211 3 0303 weierstrass +c* 768,673,17 3 0304 circlemultiply +c+ 768,675,15 3 0305 circleplus +es 823,719,24 3 0306 emptyset +ca 768,509 3 0307 intersection +cu 768,492,17 3 0310 union +sp 713,470 3 0311 propersuperset +ip 713,470,125 3 0312 reflexsuperset +--- 713,540,70 3 0313 notsubset +sb 713,470 3 0314 propersubset +ib 713,470,125 3 0315 reflexsubset +mo 713,468 3 0316 element +nm 713,555,58 3 0317 notelement +/_ 768,673 3 0320 angle +gr 713,718,19 3 0321 gradient +--- 790,673,17 3 0322 registerserif +--- 790,675,15 3 0323 copyrightserif +--- 890,673 3 0324 trademarkserif +product 823,751,101 3 0325 product +sr 549,917,38 3 0326 radical +md 250,310 3 0327 dotmath +no 713,288 3 0330 logicalnot +char172 " +AN 603,454 3 0331 logicaland +OR 603,477 3 0332 logicalor +hA 1042,510,20 3 0333 arrowdblboth +lA 987,513,15 3 0334 arrowdblleft +uA 603,911 3 0335 arrowdblup +rA 987,508,20 3 0336 arrowdblright +dA 603,890,19 3 0337 arrowdbldown +lz 494,745 3 0340 lozenge +la 329,746,198 3 0341 angleleft +--- 790,670,20 3 0342 registersans +--- 790,675,15 3 0343 copyrightsans +--- 786,673 3 0344 trademarksans +sum 713,752,108 3 0345 summation +parenlefttp 384,926,293 3 0346 parenlefttp +parenleftex 384,920,80 3 0347 parenleftex +parenleftbt 384,920,293 3 0350 parenleftbt +bracketlefttp 384,925,75 3 0351 bracketlefttp +lc " +bracketleftex 384,925,75 3 0352 bracketleftex +bracketleftbt 384,925,75 3 0353 bracketleftbt +lf " +bracelefttp 494,925,75 3 0354 bracelefttp +lt " +braceleftmid 494,925,75 3 0355 braceleftmid +lk " +braceleftbt 494,925,75 3 0356 braceleftbt +lb " +braceex 494,925,75 3 0357 braceex +bracerightex " +braceleftex " +barex " +bv " +ra 329,746,198 3 0361 angleright +is 274,916,107,67,52,-10 3 0362 integral +--- 686,921,83 3 0363 integraltp +--- 686,975,88 3 0364 integralex +--- 686,921,81 3 0365 integralbt +parenrighttp 384,926,293 3 0366 parenrighttp +parenrightex 384,920,80 3 0367 parenrightex +parenrightbt 384,920,293 3 0370 parenrightbt +bracketrighttp 384,925,75 3 0371 bracketrighttp +rc " +bracketrightex 384,925,75 3 0372 bracketrightex +bracketrightbt 384,925,75 3 0373 bracketrightbt +rf " +bracerighttp 494,925,75 3 0374 bracerighttp +rt " +bracerightmid 494,925,75 3 0375 bracerightmid +rk " +bracerightbt 494,925,75 3 0376 bracerightbt +rb " diff --git a/gnu/usr.bin/groff/devices/devps/SS b/gnu/usr.bin/groff/devices/devps/SS new file mode 100644 index 0000000000..02b999c17b --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/SS @@ -0,0 +1,194 @@ +name SS +internalname Symbol-Slanted +special +slant 15.5 +spacewidth 223 +charset +space 223 0 0040 +--- 296,599,15,137,-72,99 3 0041 exclam +--- 635,627,0,216,-173,99 3 0042 universal +--- 445,599,15,162,-21,99 3 0043 numbersign +--- 489,629,0,183,28,99 3 0044 existential +--- 741,583,32,75,-97,75 3 0045 percent +--- 692,589,16,103,-18,99 3 0046 ampersand +--- 391,444,15,109,6,99 3 0047 suchthat +--- 296,599,170,203,-39,99 3 0050 parenleft +--- 296,600,170,93,72,93 3 0051 parenright +--- 445,490,0,105,-76,99 3 0052 asteriskmath +--- 489,474,0,123,-26,99 3 0053 plus +--- 223,93,136,10,41,10 3 0054 comma +--- 489,256,0,117,-24,99 3 0055 minus +--- 223,85,15,1,-20,1 3 0056 period +--- 247,575,15,208,55,99 3 0057 slash +--- 445,610,15,142,-40,99 3 0060 zero +--- 445,599,0,56,-57,56 3 0061 one +--- 445,611,0,129,28,99 3 0062 two +--- 445,611,16,115,-6,99 3 0063 three +--- 445,610,0,135,-8,99 3 0064 four +--- 445,610,15,188,14,99 3 0065 five +--- 445,610,16,193,-37,99 3 0066 six +--- 445,599,15,190,-101,99 3 0067 seven +--- 445,611,16,141,-32,99 3 0070 eight +--- 445,609,15,140,-2,99 3 0071 nine +--- 247,409,15,89,-31,89 3 0072 colon +--- 247,409,136,99,17,99 3 0073 semicolon +--- 489,464,0,171,-37,99 3 0074 less +--- 489,347,0,147,1,99 3 0075 equal +--- 489,464,0,108,27,99 3 0076 greater +--- 395,610,15,172,-113,99 3 0077 question +--- 489,423,0,158,40,99 3 0100 congruent +--- 643,599,0,21,47,21 3 0101 Alpha +--- 594,598,0,101,24,99 3 0102 Beta +--- 643,599,0,205,58,99 3 0103 Chi +--- 545,612,0,46,45,46 3 0104 Delta +--- 544,599,0,194,22,99 3 0105 Epsilon +--- 679,598,0,132,-55,99 3 0106 Phi +--- 537,599,0,227,19,99 3 0107 Gamma +--- 643,599,0,243,15,99 3 0110 Eta +--- 296,599,0,222,22,99 3 0111 Iota ++h 562,614,15,133,-58,99 3 0112 theta1 +--- 643,598,0,185,19,99 3 0113 Kappa +--- 611,612,0,49,45,49 3 0114 Lambda +--- 791,599,0,233,22,99 3 0115 Mu +--- 643,599,7,234,24,99 3 0116 Nu +--- 643,610,15,154,-62,99 3 0117 Omicron +--- 684,599,0,213,28,99 3 0120 Pi +--- 659,610,15,138,-62,99 3 0121 Theta +--- 495,599,0,200,25,99 3 0122 Rho +--- 527,599,0,186,45,99 3 0123 Sigma +--- 544,599,0,229,-109,99 3 0124 Tau +--- 614,599,0,240,-125,99 3 0125 Upsilon +ts 391,445,208,151,-28,99 3 0126 sigma1 +--- 684,612,0,126,20,99 3 0127 Omega +--- 574,598,0,176,14,99 3 0130 Xi +--- 708,608,0,227,-138,99 3 0131 Psi +--- 544,599,0,231,11,99 3 0132 Zeta +--- 296,599,138,207,16,99 3 0133 bracketleft +--- 768,426,0,0,-110 3 0134 therefore +--- 296,599,138,159,64,99 3 0135 bracketright +--- 586,600,0,60,37,60 3 0136 perpendicular +--- 445,0,224,0,122 3 0137 underscore +--- 445,816,0,829,-622,99 3 0140 radicalex +*a 562,445,15,146,-34,99 3 0141 alpha +*b 489,659,198,139,57,99 3 0142 beta +*x 489,445,206,134,98,99 3 0143 chi +*d 440,658,16,181,-33,99 3 0144 delta +*e 391,447,17,127,1,99 3 0145 epsilon +*f 464,596,200,103,-28,99 3 0146 phi +*g 366,444,200,252,-42,99 3 0147 gamma +*y 537,457,180,68,-50,68 3 0150 eta +*i 293,448,16,53,-47,53 3 0151 iota ++f 537,444,199,117,-42,99 3 0152 phi1 +*k 489,447,0,182,-56,99 3 0153 kappa +*l 489,658,16,91,29,91 3 0154 lambda +*m 513,445,198,70,68,70 3 0155 mu +*n 464,451,15,134,-69,99 3 0156 nu +*o 489,444,17,87,-36,87 3 0157 omicron +*p 489,433,18,160,-8,99 3 0160 pi +*h 464,614,16,140,-53,99 3 0161 theta +*r 489,444,205,82,69,82 3 0162 rho +*s 537,445,19,175,-37,99 3 0163 sigma +*t 391,445,16,170,-45,99 3 0164 tau +*u 513,451,15,95,-55,95 3 0165 upsilon ++p 635,519,15,173,-28,99 3 0166 omega1 +*w 611,445,16,126,-35,99 3 0167 omega +*c 439,681,200,126,-20,99 3 0170 xi +*q 611,445,203,198,-91,99 3 0171 psi +*z 440,673,200,190,-50,99 3 0172 zeta +--- 427,599,163,163,-66,99 3 0173 braceleft +--- 178,599,158,179,41,99 3 0174 bar +--- 427,599,163,67,31,67 3 0175 braceright +--- 489,273,0,110,-28,99 3 0176 similar +--- 552,609,0,208,-84,99 3 0241 Upsilon1 +--- 220,654,0,223,-106,99 3 0242 minute +--- 489,569,0,206,24,99 3 0243 lessequal +--- 149,603,11,391,214,99 3 0244 fraction +--- 635,360,0,107,-41,99 3 0245 infinity +--- 445,612,172,219,86,99 3 0246 florin +--- 670,474,23,25,-69,25 3 0247 club +--- 670,490,32,0,-148 3 0250 diamond +--- 670,473,29,59,-155,59 3 0251 heart +--- 670,488,32,0,-82 3 0252 spade +--- 927,455,13,103,-40,99 3 0253 arrowboth +--- 878,455,13,87,-47,87 3 0254 arrowleft +--- 537,810,0,204,-173,99 3 0255 arrowup +--- 878,455,13,94,-55,94 3 0256 arrowright +--- 537,790,20,85,-54,85 3 0257 arrowdown +--- 356,609,0,160,-137,99 3 0260 degree +--- 489,574,0,154,41,99 3 0261 plusminus +--- 366,656,0,244,-100,99 3 0262 second +--- 489,569,0,143,24,99 3 0263 greaterequal +--- 489,466,0,170,22,99 3 0264 multiply +--- 635,360,0,82,-40,82 3 0265 proportional +--- 440,664,18,152,-12,99 3 0266 partialdiff +--- 409,421,0,95,-68,95 3 0267 bullet +--- 489,406,0,119,-24,99 3 0270 divide +--- 489,489,22,148,-1,99 3 0271 notequal +--- 489,394,0,163,15,99 3 0272 equivalence +--- 489,351,0,133,-7,99 3 0273 approxequal +--- 890,85,15,0,-57 3 0274 ellipsis +--- 537,899,107,92,-166,92 3 0275 arrowvertex +--- 890,246,0,171,42,99 3 0276 arrowhorizex +--- 586,560,14,174,10,99 3 0277 carriagereturn +--- 732,586,16,58,-109,58 3 0300 aleph +--- 611,659,47,123,24,99 3 0301 Ifraktur +--- 708,653,13,175,-21,99 3 0302 Rfraktur +--- 878,510,188,50,-62,50 3 0303 weierstrass +--- 684,599,15,124,-64,99 3 0304 circlemultiply +--- 684,601,13,125,-65,99 3 0305 circleplus +--- 732,640,21,202,12,99 3 0306 emptyset +--- 684,453,0,80,14,80 3 0307 intersection +--- 684,438,15,154,-60,99 3 0310 union +--- 635,418,0,90,32,90 3 0311 propersuperset +--- 635,418,111,89,67,89 3 0312 reflexsuperset +--- 635,481,62,159,-37,99 3 0313 notsubset +--- 635,418,0,159,-37,99 3 0314 propersubset +--- 635,418,111,159,34,99 3 0315 reflexsubset +--- 635,417,0,0,-43 3 0316 element +--- 635,494,52,0,-24 3 0317 notelement +--- 684,599,0,199,27,99 3 0320 angle +--- 635,639,17,220,-181,99 3 0321 gradient +--- 703,596,18,110,-70,99 3 0322 registerserif +--- 703,601,13,113,-72,99 3 0323 copyrightserif +--- 792,599,0,205,-119,99 3 0324 trademarkserif +--- 732,668,90,238,56,99 3 0325 product +--- 489,816,34,272,-84,99 3 0326 radical +--- 223,276,0,52,-81,52 3 0327 dotmath +--- 635,256,0,100,-28,99 3 0330 logicalnot +--- 537,404,0,32,29,32 3 0331 logicaland +--- 537,424,0,152,-101,99 3 0332 logicalor +--- 927,454,18,101,-42,99 3 0333 arrowdblboth +--- 878,457,13,114,-46,99 3 0334 arrowdblleft +--- 537,811,0,201,-102,99 3 0335 arrowdblup +--- 878,452,18,89,-21,89 3 0336 arrowdblright +--- 537,792,17,152,-53,99 3 0337 arrowdbldown +--- 440,663,0,129,-71,99 3 0340 lozenge +--- 293,664,176,229,-48,99 3 0341 angleleft +--- 703,596,18,110,-70,99 3 0342 registersans +--- 703,601,13,111,-70,99 3 0343 copyrightsans +--- 700,599,0,182,-129,99 3 0344 trademarksans +--- 635,669,96,171,65,99 3 0345 summation +--- 342,824,261,350,96,99 3 0346 parenlefttp +--- 342,823,76,46,38,46 3 0347 parenleftex +--- 342,824,261,47,-63,47 3 0350 parenleftbt +--- 342,824,71,268,72,99 3 0351 bracketlefttp +--- 342,823,70,13,72,13 3 0352 bracketleftex +--- 342,824,71,14,72,14 3 0353 bracketleftbt +--- 440,824,67,258,-108,99 3 0354 bracelefttp +--- 440,832,76,96,-76,96 3 0355 braceleftmid +--- 440,824,62,94,-169,94 3 0356 braceleftbt +--- 440,832,71,96,-107,96 3 0357 braceex +--- 293,664,176,102,79,99 3 0361 angleright +--- 244,815,95,305,63,99 3 0362 integral +--- 611,820,74,312,-222,99 3 0363 integraltp +--- 611,868,78,79,-221,79 3 0364 integralex +--- 611,820,72,64,20,64 3 0365 integralbt +--- 342,824,261,206,-223,99 3 0366 parenrighttp +--- 342,823,76,365,-281,99 3 0367 parenrightex +--- 342,824,261,365,80,99 3 0370 parenrightbt +--- 342,824,71,285,-199,99 3 0371 bracketrighttp +--- 342,823,70,285,-200,99 3 0372 bracketrightex +--- 342,824,71,285,54,99 3 0373 bracketrightbt +--- 440,824,67,35,-108,35 3 0374 bracerighttp +--- 440,832,76,127,-105,99 3 0375 bracerightmid +--- 440,824,62,94,54,94 3 0376 bracerightbt diff --git a/gnu/usr.bin/groff/devices/devps/TB b/gnu/usr.bin/groff/devices/devps/TB new file mode 100644 index 0000000000..9dae3ad182 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/TB @@ -0,0 +1,533 @@ +name TB +internalname Times-Bold +spacewidth 250 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -74 +A w -90 +A v -100 +A u -50 +A ' -74 +A p -25 +A Y -100 +A W -130 +A V -145 +A U -50 +A T -95 +A Q -45 +A O -45 +A G -55 +A C -55 +B U -10 +B A -30 +D . -20 +D Y -40 +D W -40 +D V -40 +D A -35 +F . -110 +F o -25 +F e -25 +F , -92 +F a -25 +F A -90 +J u -15 +J . -20 +J o -15 +J e -15 +J a -15 +J A -30 +K y -45 +K u -15 +K o -25 +K e -25 +K O -30 +L y -55 +L ' -110 +L rq -20 +L Y -92 +L W -92 +L V -92 +L T -92 +N A -20 +O Y -50 +O X -40 +O W -50 +O V -50 +O T -40 +O A -40 +P . -110 +P o -20 +P e -20 +P , -92 +P a -10 +P A -74 +Q . -20 +Q U -10 +R Y -35 +R W -35 +R V -55 +R U -30 +R T -40 +R O -30 +T y -74 +T w -74 +T u -92 +T ; -74 +T r -74 +T . -90 +T o -92 +T i -18 +T - -92 +T hy -92 +T char173 -92 +T e -92 +T , -74 +T : -74 +T a -92 +T O -18 +T A -90 +U . -50 +U , -50 +U A -60 +V u -92 +V ; -92 +V . -145 +V o -100 +V i -37 +V - -74 +V hy -74 +V char173 -74 +V e -100 +V , -129 +V : -92 +V a -92 +V O -45 +V G -30 +V A -135 +W y -60 +W u -50 +W ; -55 +W . -92 +W o -75 +W i -18 +W - -37 +W hy -37 +W char173 -37 +W e -65 +W , -92 +W : -55 +W a -65 +W O -10 +W A -120 +Y u -92 +Y ; -92 +Y . -92 +Y o -111 +Y i -37 +Y - -92 +Y hy -92 +Y char173 -92 +Y e -111 +Y , -92 +Y : -92 +Y a -85 +Y O -35 +Y A -110 +a v -25 +b v -15 +b u -20 +b . -40 +b b -10 +, ' -55 +, rq -45 +d w -15 +e v -15 +f ' 55 +f rq 50 +f . -15 +f o -25 +f i -25 +f .i -35 +f , -15 +g . -15 +h y -15 +i v -10 +k y -15 +k o -15 +k e -10 +n v -40 +o w -10 +o v -10 +. ' -55 +. rq -55 +lq A -10 +` ` -63 +` oq -63 +oq ` -63 +oq oq -63 +` A -10 +oq A -10 +' v -20 +' s -37 +' r -20 +' ' -63 +' d -20 +r v -10 +r q -18 +r . -100 +r p -10 +r o -18 +r n -15 +r - -37 +r hy -37 +r char173 -37 +r g -10 +r e -18 +r , -92 +r c -18 +v . -70 +v o -10 +v e -10 +v , -55 +v a -10 +w . -70 +w o -10 +w , -55 +y . -70 +y o -25 +y e -10 +y , -55 +charset +ha 581,676 2 0000 asciicircum +ti 520,333 0 0001 asciitilde +vS 556,914,19 2 0002 Scaron +vZ 667,914 2 0003 Zcaron +vs 389,704,14 2 0004 scaron +vz 444,704 2 0005 zcaron +:Y 722,877 2 0006 Ydieresis +tm 1000,676 2 0007 trademark +aq 278,691 2 0010 quotesingle +space 250 0 0040 +! 333,691,13 2 0041 exclam +" 555,691 2 0042 quotedbl +# 500,700 2 0043 numbersign +sh " +$ 500,750,99 2 0044 dollar +Do " +% 1000,692,14 2 0045 percent +& 833,691,16 2 0046 ampersand +' 333,691 2 0047 quoteright +( 333,694,168 2 0050 parenleft +) 333,694,168 2 0051 parenright +* 500,691 2 0052 asterisk ++ 570,506 0 0053 plus +, 250,155,180 0 0054 comma +- 333,287 0 0055 hyphen +hy " +char173 " +. 250,156,13 0 0056 period +/ 278,691,19 2 0057 slash +sl " +0 500,688,13 2 0060 zero +1 500,688 2 0061 one +2 500,688 2 0062 two +3 500,688,14 2 0063 three +4 500,688 2 0064 four +5 500,676,8 2 0065 five +6 500,688,13 2 0066 six +7 500,676 2 0067 seven +8 500,688,13 2 0070 eight +9 500,688,13 2 0071 nine +: 333,472,13 0 0072 colon +; 333,472,180 0 0073 semicolon +< 570,514,8 0 0074 less += 570,399 0 0075 equal +> 570,514,8 0 0076 greater +? 500,689,13 2 0077 question +@ 930,691,19 2 0100 at +at " +A 722,690 2 0101 A +B 667,676 2 0102 B +C 722,691,19 2 0103 C +D 722,676 2 0104 D +E 667,676 2 0105 E +F 611,676 2 0106 F +G 778,691,19 2 0107 G +H 778,676 2 0110 H +I 389,676 2 0111 I +J 500,676,96 2 0112 J +K 778,676 2 0113 K +L 667,676 2 0114 L +M 944,676 2 0115 M +N 722,676,18 2 0116 N +O 778,691,19 2 0117 O +P 611,676 2 0120 P +Q 778,691,176 2 0121 Q +R 722,676 2 0122 R +S 556,692,19 2 0123 S +T 667,676 2 0124 T +U 722,676,19 2 0125 U +V 722,676,18 2 0126 V +W 1000,676,15 2 0127 W +X 722,676 2 0130 X +Y 722,676 2 0131 Y +Z 667,676 2 0132 Z +[ 333,678,149 2 0133 bracketleft +lB " +\ 278,691,19 2 0134 backslash +rs " +] 333,678,149 2 0135 bracketright +rB " +a^ 333,704 2 0136 circumflex +^ " +_ 500,0,125 0 0137 underscore +` 333,691 2 0140 quoteleft +oq " +a 500,473,14 0 0141 a +b 556,676,14 2 0142 b +c 444,473,14 0 0143 c +d 556,676,14 2 0144 d +e 444,473,14 0 0145 e +f 333,691 2 0146 f +g 500,473,206 1 0147 g +h 556,676 2 0150 h +i 278,691 2 0151 i +j 333,691,203 3 0152 j +k 556,676 2 0153 k +l 278,676 2 0154 l +m 833,473 0 0155 m +n 556,473 0 0156 n +o 500,473,14 0 0157 o +p 556,473,205 1 0160 p +q 556,473,205 1 0161 q +r 444,473 0 0162 r +s 389,473,14 0 0163 s +t 333,630,12 2 0164 t +u 556,461,14 0 0165 u +v 500,461,14 0 0166 v +w 722,461,14 0 0167 w +x 500,461 0 0170 x +y 500,461,205 1 0171 y +z 444,461 0 0172 z +lC 394,698,175 2 0173 braceleft +{ " +ba 220,691,19 2 0174 bar +| " +rC 394,698,175 2 0175 braceright +} " +a~ 333,674 2 0176 tilde +~ " +bq 333,155,180 0 0200 quotesinglbase +Fo 500,415 0 0201 guillemotleft +char171 " +Fc 500,415 0 0202 guillemotright +char187 " +bu 350,478 0 0203 bullet +Fn 500,706,155 2 0204 florin +f/ 167,688,12 2 0205 fraction +%0 1000,706,29 2 0206 perthousand +dg 500,691,134 2 0207 dagger +dd 500,691,132 2 0210 daggerdbl +en 500,271 0 0211 endash +em 1000,271 0 0212 emdash +fi 556,691 2 0214 fi +fl 556,691 2 0215 fl +.i 278,461 0 0220 dotlessi +ga 333,713 2 0222 grave +a" 333,713 2 0223 hungarumlaut +a. 333,667 2 0224 dotaccent +ab 333,691 2 0225 breve +ah 333,704 2 0226 caron +ao 333,740 2 0227 ring +ho 333,44,173 0 0230 ogonek +lq 500,691 2 0231 quotedblleft +rq 500,691 2 0232 quotedblright +oe 722,473,14 0 0233 oe +/l 278,676 2 0234 lslash +Bq 500,155,180 0 0235 quotedblbase +OE 1000,684,5 2 0236 OE +/L 667,676 2 0237 Lslash +r! 333,501,203 1 0241 exclamdown +char161 " +ct 500,588,140 0 0242 cent +char162 " +Po 500,684,14 2 0243 sterling +char163 " +Cs 500,613 0 0244 currency +char164 " +Ye 500,676 2 0245 yen +char165 " +bb 220,691,19 2 0246 brokenbar +char166 " +sc 500,691,132 2 0247 section +char167 " +ad 333,667 2 0250 dieresis +char168 " +co 747,691,19 2 0251 copyright +char169 " +Of 300,688 2 0252 ordfeminine +char170 " +fo 333,415 0 0253 guilsinglleft +no 570,399 0 0254 logicalnot +char172 " +\- 570,297 0 0255 minus +rg 747,691,19 2 0256 registered +char174 " +a- 333,637 2 0257 macron +char175 " +de 400,688 2 0260 degree +char176 " +char177 570,506 0 0261 plusminus +S2 300,688 2 0262 twosuperior +char178 " +S3 300,688 2 0263 threesuperior +char179 " +aa 333,713 2 0264 acute +char180 " +char181 556,461,206 1 0265 mu +ps 540,676,186 2 0266 paragraph +char182 " +char183 250,417 0 0267 periodcentered +ac 333,0,218 1 0270 cedilla +char184 " +S1 300,688 2 0271 onesuperior +char185 " +Om 330,688 2 0272 ordmasculine +char186 " +fc 333,415 0 0273 guilsinglright +14 750,688,12 2 0274 onequarter +char188 " +12 750,688,12 2 0275 onehalf +char189 " +34 750,688,12 2 0276 threequarters +char190 " +r? 500,501,201 0 0277 questiondown +char191 " +`A 722,923 2 0300 Agrave +char192 " +'A 722,923 2 0301 Aacute +char193 " +^A 722,914 2 0302 Acircumflex +char194 " +~A 722,884 2 0303 Atilde +char195 " +:A 722,877 2 0304 Adieresis +char196 " +oA 722,935 2 0305 Aring +char197 " +AE 1000,676 2 0306 AE +char198 " +,C 722,691,218 3 0307 Ccedilla +char199 " +`E 667,923 2 0310 Egrave +char200 " +'E 667,923 2 0311 Eacute +char201 " +^E 667,914 2 0312 Ecircumflex +char202 " +:E 667,877 2 0313 Edieresis +char203 " +`I 389,923 2 0314 Igrave +char204 " +'I 389,923 2 0315 Iacute +char205 " +^I 389,914 2 0316 Icircumflex +char206 " +:I 389,877 2 0317 Idieresis +char207 " +-D 722,676 2 0320 Eth +char208 " +~N 722,884,18 2 0321 Ntilde +char209 " +`O 778,923,19 2 0322 Ograve +char210 " +'O 778,923,19 2 0323 Oacute +char211 " +^O 778,914,19 2 0324 Ocircumflex +char212 " +~O 778,884,19 2 0325 Otilde +char213 " +:O 778,877,19 2 0326 Odieresis +char214 " +char215 570,490 0 0327 multiply +/O 778,737,74 2 0330 Oslash +char216 " +`U 722,923,19 2 0331 Ugrave +char217 " +'U 722,923,19 2 0332 Uacute +char218 " +^U 722,914,19 2 0333 Ucircumflex +char219 " +:U 722,877,19 2 0334 Udieresis +char220 " +'Y 722,928 2 0335 Yacute +char221 " +TP 611,676 2 0336 Thorn +char222 " +ss 556,691,12 2 0337 germandbls +char223 " +`a 500,713,14 2 0340 agrave +char224 " +'a 500,713,14 2 0341 aacute +char225 " +^a 500,704,14 2 0342 acircumflex +char226 " +~a 500,674,14 2 0343 atilde +char227 " +:a 500,667,14 2 0344 adieresis +char228 " +oa 500,740,14 2 0345 aring +char229 " +ae 722,473,14 0 0346 ae +char230 " +,c 444,473,218 1 0347 ccedilla +char231 " +`e 444,713,14 2 0350 egrave +char232 " +'e 444,713,14 2 0351 eacute +char233 " +^e 444,704,14 2 0352 ecircumflex +char234 " +:e 444,667,14 2 0353 edieresis +char235 " +`i 278,713 2 0354 igrave +char236 " +'i 278,713 2 0355 iacute +char237 " +^i 278,704 2 0356 icircumflex +char238 " +:i 278,667 2 0357 idieresis +char239 " +Sd 500,691,14 2 0360 eth +char240 " +~n 556,674 2 0361 ntilde +char241 " +`o 500,713,14 2 0362 ograve +char242 " +'o 500,713,14 2 0363 oacute +char243 " +^o 500,704,14 2 0364 ocircumflex +char244 " +~o 500,674,14 2 0365 otilde +char245 " +:o 500,667,14 2 0366 odieresis +char246 " +char247 570,537,31 0 0367 divide +/o 500,549,92 0 0370 oslash +char248 " +`u 556,713,14 2 0371 ugrave +char249 " +'u 556,713,14 2 0372 uacute +char250 " +^u 556,704,14 2 0373 ucircumflex +char251 " +:u 556,667,14 2 0374 udieresis +char252 " +'y 500,713,205 3 0375 yacute +char253 " +Tp 556,676,205 3 0376 thorn +char254 " +:y 500,667,205 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/TBI b/gnu/usr.bin/groff/devices/devps/TBI new file mode 100644 index 0000000000..ba58a3af37 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/TBI @@ -0,0 +1,515 @@ +name TBI +internalname Times-BoldItalic +slant 15 +spacewidth 250 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -74 +A w -74 +A v -74 +A u -30 +A ' -74 +A Y -70 +A W -100 +A V -95 +A U -50 +A T -55 +A Q -55 +A O -50 +A G -60 +A C -65 +B U -10 +B A -25 +D Y -50 +D W -40 +D V -50 +D A -25 +F r -50 +F . -129 +F o -70 +F i -40 +F e -100 +F , -129 +F a -95 +F A -100 +J u -40 +J . -10 +J o -40 +J e -40 +J , -10 +J a -40 +J A -25 +K y -20 +K u -20 +K o -25 +K e -25 +K O -30 +L y -37 +L ' -55 +L Y -37 +L W -37 +L V -37 +L T -18 +N A -30 +O Y -50 +O X -40 +O W -50 +O V -50 +O T -40 +O A -40 +P . -129 +P o -55 +P e -50 +P , -129 +P a -40 +P A -85 +Q U -10 +R Y -18 +R W -18 +R V -18 +R U -40 +R T -30 +R O -40 +T y -37 +T w -37 +T u -37 +T ; -74 +T r -37 +T . -92 +T o -95 +T i -37 +T - -92 +T hy -92 +T char173 -92 +T e -92 +T , -92 +T : -74 +T a -92 +T O -18 +T A -55 +U A -45 +V u -55 +V ; -74 +V . -129 +V o -111 +V i -55 +V - -70 +V hy -70 +V char173 -70 +V e -111 +V , -129 +V : -74 +V a -111 +V O -30 +V G -10 +V A -85 +W y -55 +W u -55 +W ; -55 +W . -74 +W o -80 +W i -37 +W - -50 +W hy -50 +W char173 -50 +W e -90 +W , -74 +W : -55 +W a -85 +W O -15 +W A -74 +Y u -92 +Y ; -92 +Y . -74 +Y o -111 +Y i -55 +Y - -92 +Y hy -92 +Y char173 -92 +Y e -111 +Y , -92 +Y : -92 +Y a -92 +Y O -25 +Y A -74 +b u -20 +b . -40 +b b -10 +c k -10 +c h -10 +, ' -95 +, rq -95 +e b -10 +f ' 55 +f . -10 +f o -10 +f f -18 +f e -10 +f .i -30 +f , -10 +k o -10 +k e -30 +n v -40 +o y -10 +o x -10 +o w -25 +o v -15 +. ' -95 +. rq -95 +` ` -74 +` oq -74 +oq ` -74 +oq oq -74 +' v -15 +' t -37 +' s -74 +' r -15 +' ' -74 +' d -15 +r . -65 +r , -65 +v . -37 +v o -15 +v e -15 +v , -37 +w . -37 +w o -15 +w e -10 +w , -37 +w a -10 +x e -10 +y . -37 +y , -37 +charset +ha 570,669,0,0,-17 2 0000 asciicircum +ti 570,333,0,0,-4 0 0001 asciitilde +vS 556,897,18,20,48,20 2 0002 Scaron +vZ 611,897,0,29,61,29 2 0003 Zcaron +vs 389,690,13,100,69,99 2 0004 scaron +vz 389,690,78,85,93,85 2 0005 zcaron +:Y 611,862,0,98,-23,98 2 0006 Ydieresis +tm 1000,669,0,18,18,18 2 0007 trademark +aq 278,685,0,40,-78,40 2 0010 quotesingle +space 250 0 0040 +! 389,684,13,31,-17,31 2 0041 exclam +" 555,685,0,31,-86,31 2 0042 quotedbl +# 500,700,0,83,83,83 2 0043 numbersign +sh " +$ 500,733,100,47,70,47 2 0044 dollar +Do " +% 833,692,10,10,11,10 2 0045 percent +& 778,682,19,0,45 2 0046 ampersand +' 333,685,0,19,-48,19 2 0047 quoteright +( 333,685,179,61,22,61 2 0050 parenleft +) 333,685,179,0,94 2 0051 parenright +* 500,685,0,6,-15,6 2 0052 asterisk ++ 570,506,0,17,17,17 0 0053 plus +, 250,134,182,0,110 0 0054 comma +- 333,282,0,0,48 0 0055 hyphen +hy " +char173 " +. 250,135,13,0,59 0 0056 period +/ 278,685,18,114,114,99 2 0057 slash +sl " +0 500,683,14,27,33,27 2 0060 zero +1 500,683,0,0,45 2 0061 one +2 500,683,0,0,77 2 0062 two +3 500,683,13,0,65 2 0063 three +4 500,683,0,53,65,53 2 0064 four +5 500,669,13,37,61,37 2 0065 five +6 500,679,15,59,27,59 2 0066 six +7 500,669,0,75,-2,75 2 0067 seven +8 500,683,13,26,47,26 2 0070 eight +9 500,683,10,25,62,25 2 0071 nine +: 333,459,13,0,27 0 0072 colon +; 333,459,183,0,75 0 0073 semicolon +< 570,514,8,19,19,19 0 0074 less += 570,399,0,17,17,17 0 0075 equal +> 570,514,8,19,19,19 0 0076 greater +? 500,684,13,20,-29,20 2 0077 question +@ 832,685,18,0,-13 2 0100 at +at " +A 667,683,0,0,117 2 0101 A +B 667,669,0,7,74,7 2 0102 B +C 667,685,18,60,18,60 2 0103 C +D 722,669,0,13,96,13 2 0104 D +E 667,669,0,36,77,36 2 0105 E +F 667,669,0,43,63,43 2 0106 F +G 722,685,18,34,29,34 2 0107 G +H 778,669,0,71,74,71 2 0110 H +I 389,669,0,67,82,67 2 0111 I +J 500,669,99,74,96,74 2 0112 J +K 667,669,0,85,71,85 2 0113 K +L 611,669,0,29,72,29 2 0114 L +M 889,669,12,78,79,78 2 0115 M +N 722,669,15,76,77,76 2 0116 N +O 722,685,18,19,23,19 2 0117 O +P 611,669,0,52,77,52 2 0120 P +Q 722,685,208,19,23,19 3 0121 Q +R 667,669,0,6,79,6 2 0122 R +S 556,685,18,20,48,20 2 0123 S +T 611,669,0,89,0,89 2 0124 T +U 722,669,18,72,-17,72 2 0125 U +V 667,669,18,98,-15,98 2 0126 V +W 889,669,18,101,-15,99 2 0127 W +X 667,669,0,77,74,77 2 0130 X +Y 611,669,0,98,-23,98 2 0131 Y +Z 611,669,0,29,61,29 2 0132 Z +[ 333,674,159,79,87,79 2 0133 bracketleft +lB " +\ 278,685,18,51,51,51 2 0134 backslash +rs " +] 333,674,157,60,106,60 2 0135 bracketright +rB " +a^ 333,690,0,84,10,84 2 0136 circumflex +^ " +_ 500,0,125,50,50,50 0 0137 underscore +` 333,685,0,49,-78,49 2 0140 quoteleft +oq " +a 500,462,14,5,71,5 0 0141 a +b 500,699,13,0,64 2 0142 b +c 444,462,13,0,55 0 0143 c +d 500,699,13,67,71,67 2 0144 d +e 444,462,13,4,45,4 0 0145 e +f 333,698,205,163,219,99 3 0146 f +g 500,462,203,28,102,28 1 0147 g +h 556,699,9,0,63 2 0150 h +i 278,684,9,35,48,35 2 0151 i +j 278,684,207,51,239,51 3 0152 j +k 500,699,8,33,73,33 2 0153 k +l 278,699,9,62,48,62 2 0154 l +m 778,462,9,0,64 0 0155 m +n 556,462,9,0,56 0 0156 n +o 500,462,13,0,53 0 0157 o +p 500,462,205,0,170 1 0160 p +q 500,462,205,21,49,21 1 0161 q +r 389,462,0,50,71,50 0 0162 r +s 389,462,13,0,69 0 0163 s +t 278,594,9,53,61,53 2 0164 t +u 556,462,9,0,35 0 0165 u +v 444,462,13,7,34,7 0 0166 v +w 667,462,13,0,34 0 0167 w +x 500,462,13,19,96,19 0 0170 x +y 444,462,205,0,144 1 0171 y +z 389,449,78,29,93,29 0 0172 z +lC 348,686,187,138,45,99 2 0173 braceleft +{ " +ba 220,685,18,0,-16 2 0174 bar +| " +rC 348,686,187,4,179,4 2 0175 braceright +} " +a~ 333,655,0,124,2,99 2 0176 tilde +~ " +bq 333,134,182,0,55 0 0200 quotesinglbase +Fo 500,415,0,18,38,18 0 0201 guillemotleft +char171 " +Fc 500,415,0,18,38,18 0 0202 guillemotright +char187 " +bu 350,525,0,50,50,50 0 0203 bullet +Fn 500,707,156,87,137,87 2 0204 florin +f/ 167,683,14,207,219,99 2 0205 fraction +%0 1000,706,29,46,43,46 2 0206 perthousand +dg 500,685,145,44,-41,44 2 0207 dagger +dd 500,685,139,43,40,43 2 0210 daggerdbl +en 500,269,0,27,90,27 0 0211 endash +em 1000,269,0,27,90,27 0 0212 emdash +fi 556,703,205,8,238,8 3 0214 fi +fl 556,704,205,47,236,47 3 0215 fl +.i 278,462,9,10,48,10 0 0220 dotlessi +ga 333,697,0,14,-35,14 2 0222 grave +a" 333,697,0,215,-19,99 2 0223 hungarumlaut +a. 333,655,0,10,-113,10 2 0224 dotaccent +ab 333,678,0,104,-21,99 2 0225 breve +ah 333,690,0,128,-29,99 2 0226 caron +ao 333,729,0,57,-77,57 2 0227 ring +ho 333,44,173,0,90 0 0230 ogonek +lq 500,685,0,63,-3,63 2 0231 quotedblleft +rq 500,685,0,63,-3,63 2 0232 quotedblright +oe 722,462,13,2,44,2 0 0233 oe +/l 278,699,9,73,63,73 2 0234 lslash +Bq 500,134,182,0,107 0 0235 quotedblbase +OE 944,677,8,52,27,52 2 0236 OE +/L 611,669,0,29,72,29 2 0237 Lslash +r! 389,492,205,0,31 1 0241 exclamdown +char161 " +ct 500,576,143,0,8 0 0242 cent +char162 " +Po 500,683,12,60,82,60 2 0243 sterling +char163 " +Cs 500,586,0,76,76,76 0 0244 currency +char164 " +Ye 500,669,0,178,17,99 2 0245 yen +char165 " +bb 220,685,18,0,-16 2 0246 brokenbar +char166 " +sc 500,685,143,9,14,9 2 0247 section +char167 " +ad 333,655,0,114,-5,99 2 0250 dieresis +char168 " +co 747,685,18,21,20,21 2 0251 copyright +char169 " +Of 266,685,0,114,34,99 2 0252 ordfeminine +char170 " +fo 333,415,0,20,18,20 0 0253 guilsinglleft +no 606,399,0,0,-1 0 0254 logicalnot +char172 " +\- 606,297,0,0,-1 0 0255 minus +rg 747,685,18,21,20,21 2 0256 registered +char174 " +a- 333,623,0,110,-1,99 2 0257 macron +char175 " +de 400,683,0,19,-33,19 2 0260 degree +char176 " +char177 570,506,0,17,17,17 0 0261 plusminus +S2 300,683,0,63,48,63 2 0262 twosuperior +char178 " +S3 300,683,0,71,33,71 2 0263 threesuperior +char179 " +aa 333,697,0,96,-89,96 2 0264 acute +char180 " +char181 576,449,207,0,110 1 0265 mu +ps 500,669,193,112,107,99 2 0266 paragraph +char182 " +char183 250,405,0,0,-1 0 0267 periodcentered +ac 333,5,218,0,130 1 0270 cedilla +char184 " +S1 300,683,0,51,20,51 2 0271 onesuperior +char185 " +Om 300,685,0,97,-6,97 2 0272 ordmasculine +char186 " +fc 333,415,0,0,40 0 0273 guilsinglright +14 750,683,14,21,43,21 2 0274 onequarter +char188 " +12 750,683,14,23,59,23 2 0275 onehalf +char189 " +34 750,683,14,26,43,26 2 0276 threequarters +char190 " +r? 500,492,205,0,20 1 0277 questiondown +char191 " +`A 667,904,0,0,117 2 0300 Agrave +char192 " +'A 667,904,0,0,117 2 0301 Aacute +char193 " +^A 667,897,0,0,117 2 0302 Acircumflex +char194 " +~A 667,862,0,0,117 2 0303 Atilde +char195 " +:A 667,862,0,0,117 2 0304 Adieresis +char196 " +oA 667,921,0,0,117 2 0305 Aring +char197 " +AE 944,669,0,24,114,24 2 0306 AE +char198 " +,C 667,685,218,60,18,60 3 0307 Ccedilla +char199 " +`E 667,904,0,36,77,36 2 0310 Egrave +char200 " +'E 667,904,0,36,77,36 2 0311 Eacute +char201 " +^E 667,897,0,36,77,36 2 0312 Ecircumflex +char202 " +:E 667,862,0,36,77,36 2 0313 Edieresis +char203 " +`I 389,904,0,67,82,67 2 0314 Igrave +char204 " +'I 389,904,0,73,82,73 2 0315 Iacute +char205 " +^I 389,897,0,81,82,81 2 0316 Icircumflex +char206 " +:I 389,862,0,106,82,99 2 0317 Idieresis +char207 " +-D 722,669,0,28,81,28 2 0320 Eth +char208 " +~N 722,862,15,76,77,76 2 0321 Ntilde +char209 " +`O 722,904,18,19,23,19 2 0322 Ograve +char210 " +'O 722,904,18,19,23,19 2 0323 Oacute +char211 " +^O 722,897,18,19,23,19 2 0324 Ocircumflex +char212 " +~O 722,862,18,19,23,19 2 0325 Otilde +char213 " +:O 722,862,18,19,23,19 2 0326 Odieresis +char214 " +char215 570,490,0,2,2,2 0 0327 multiply +/O 722,764,125,19,23,19 2 0330 Oslash +char216 " +`U 722,904,18,72,-17,72 2 0331 Ugrave +char217 " +'U 722,904,18,72,-17,72 2 0332 Uacute +char218 " +^U 722,897,18,72,-17,72 2 0333 Ucircumflex +char219 " +:U 722,862,18,72,-17,72 2 0334 Udieresis +char220 " +'Y 611,904,0,98,-23,98 2 0335 Yacute +char221 " +TP 611,669,0,12,77,12 2 0336 Thorn +char222 " +ss 500,705,200,23,250,23 2 0337 germandbls +char223 " +`a 500,697,14,5,71,5 2 0340 agrave +char224 " +'a 500,697,14,13,71,13 2 0341 aacute +char225 " +^a 500,690,14,5,71,5 2 0342 acircumflex +char226 " +~a 500,655,14,41,71,41 2 0343 atilde +char227 " +:a 500,655,14,21,71,21 2 0344 adieresis +char228 " +oa 500,729,14,5,71,5 2 0345 aring +char229 " +ae 722,462,13,1,55,1 0 0346 ae +char230 " +,c 444,462,218,0,74 1 0347 ccedilla +char231 " +`e 444,697,13,4,45,4 2 0350 egrave +char232 " +'e 444,697,13,41,45,41 2 0351 eacute +char233 " +^e 444,690,13,29,45,29 2 0352 ecircumflex +char234 " +:e 444,655,13,49,45,49 2 0353 edieresis +char235 " +`i 278,697,9,32,48,32 2 0354 igrave +char236 " +'i 278,697,9,124,48,99 2 0355 iacute +char237 " +^i 278,690,9,97,52,97 2 0356 icircumflex +char238 " +:i 278,655,9,132,48,99 2 0357 idieresis +char239 " +Sd 500,699,13,4,53,4 2 0360 eth +char240 " +~n 556,655,9,0,56 2 0361 ntilde +char241 " +`o 500,697,13,0,53 2 0362 ograve +char242 " +'o 500,697,13,13,53,13 2 0363 oacute +char243 " +^o 500,690,13,1,53,1 2 0364 ocircumflex +char244 " +~o 500,655,13,41,53,41 2 0365 otilde +char245 " +:o 500,655,13,16,53,16 2 0366 odieresis +char246 " +char247 570,535,29,17,17,17 0 0367 divide +/o 500,560,119,0,53 0 0370 oslash +char248 " +`u 556,697,9,0,35 2 0371 ugrave +char249 " +'u 556,697,9,0,35 2 0372 uacute +char250 " +^u 556,690,9,0,35 2 0373 ucircumflex +char251 " +:u 556,655,9,0,35 2 0374 udieresis +char252 " +'y 444,697,205,41,144,41 3 0375 yacute +char253 " +Tp 500,699,205,0,170 3 0376 thorn +char254 " +:y 444,655,205,44,144,44 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/TI b/gnu/usr.bin/groff/devices/devps/TI new file mode 100644 index 0000000000..156cba7967 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/TI @@ -0,0 +1,528 @@ +name TI +internalname Times-Italic +slant 7 +spacewidth 250 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -55 +A w -55 +A v -55 +A u -20 +A ' -37 +A Y -55 +A W -95 +A V -105 +A U -50 +A T -37 +A Q -40 +A O -40 +A G -35 +A C -30 +B U -10 +B A -25 +D Y -40 +D W -40 +D V -40 +D A -35 +F r -55 +F . -135 +F o -105 +F i -45 +F e -75 +F , -135 +F a -75 +F A -115 +J u -35 +J . -25 +J o -25 +J e -25 +J , -25 +J a -35 +J A -40 +K y -40 +K u -40 +K o -40 +K e -35 +K O -50 +L y -30 +L ' -37 +L Y -20 +L W -55 +L V -55 +L T -20 +N A -27 +O Y -50 +O X -40 +O W -50 +O V -50 +O T -40 +O A -55 +P . -135 +P o -80 +P e -80 +P , -135 +P a -80 +P A -90 +Q U -10 +R Y -18 +R W -18 +R V -18 +R U -40 +R O -40 +T y -74 +T w -74 +T u -55 +T ; -65 +T r -55 +T . -74 +T o -92 +T i -55 +T - -74 +T hy -74 +T char173 -74 +T e -92 +T , -74 +T : -55 +T a -92 +T O -18 +T A -50 +U . -25 +U , -25 +U A -40 +V u -74 +V ; -74 +V . -129 +V o -111 +V i -74 +V - -55 +V hy -55 +V char173 -55 +V e -111 +V , -129 +V : -65 +V a -111 +V O -30 +V A -60 +W y -70 +W u -55 +W ; -65 +W . -92 +W o -92 +W i -55 +W - -37 +W hy -37 +W char173 -37 +W e -92 +W , -92 +W : -65 +W a -92 +W O -25 +W A -60 +Y u -92 +Y ; -65 +Y . -92 +Y o -92 +Y i -74 +Y - -74 +Y hy -74 +Y char173 -74 +Y e -92 +Y , -92 +Y : -65 +Y a -92 +Y O -15 +Y A -50 +a g -10 +b u -20 +b . -40 +c k -20 +c h -15 +, ' -140 +, rq -140 +e y -30 +e x -20 +e w -15 +e v -15 +e . -15 +e g -40 +e , -10 +f ' 92 +f . -15 +f i -20 +f f -18 +f .i -60 +f , -10 +g . -15 +g g -10 +g e -10 +g , -10 +k y -10 +k o -10 +k e -10 +n v -40 +o v -10 +o g -10 +. ' -140 +. rq -140 +` ` -111 +` oq -111 +oq ` -111 +oq oq -111 +' v -10 +' t -30 +' s -40 +' r -25 +' ' -111 +' d -25 +r s -10 +r q -37 +r . -111 +r o -45 +r - -20 +r hy -20 +r char173 -20 +r g -37 +r e -37 +r d -37 +r , -111 +r c -37 +r a -15 +v . -74 +v , -74 +w . -74 +w , -74 +y . -55 +y , -55 +charset +ha 422,666,0,50,50,43 2 0000 asciicircum +ti 541,323,0,11,10,11 0 0001 asciitilde +vS 500,873,18,70,33,43 2 0002 Scaron +vZ 556,873,0,100,56,43 2 0003 Zcaron +vs 389,661,13,115,34,43 2 0004 scaron +vz 389,661,81,95,52,43 2 0005 zcaron +:Y 556,818,0,127,-28,43 2 0006 Ydieresis +tm 980,653,0,27,20,27 2 0007 trademark +aq 214,666,0,77,-82,43 2 0010 quotesingle +space 250 0 0040 +! 333,667,11,19,11,19 2 0041 exclam +" 420,666,0,62,-94,43 2 0042 quotedbl +# 500,676,0,90,48,43 2 0043 numbersign +sh " +$ 500,731,89,47,19,43 2 0044 dollar +Do " +% 833,676,13,7,-29,7 2 0045 percent +& 778,666,18,0,-26 2 0046 ampersand +' 333,666,0,7,-101,7 2 0047 quoteright +( 333,669,181,32,8,32 2 0050 parenleft +) 333,669,180,6,34,6 2 0051 parenright +* 500,666,0,42,-78,42 2 0052 asterisk ++ 675,506,0,0,-36 0 0053 plus +, 250,101,129,0,54 0 0054 comma +- 333,255,0,0,1 0 0055 hyphen +hy " +char173 " +. 250,100,11,0,23 0 0056 period +/ 278,666,18,158,115,43 2 0057 slash +sl " +0 500,676,7,47,18,43 2 0060 zero +1 500,676,0,0,1 2 0061 one +2 500,676,0,2,38,2 2 0062 two +3 500,676,7,15,35,15 2 0063 three +4 500,676,0,29,49,29 2 0064 four +5 500,666,7,41,35,41 2 0065 five +6 500,686,7,71,20,43 2 0066 six +7 500,666,8,87,-25,43 2 0067 seven +8 500,676,7,43,20,43 2 0070 eight +9 500,676,17,42,27,42 2 0071 nine +: 333,441,11 0 0072 colon +; 333,441,129,0,23 0 0073 semicolon +< 675,514,8,0,-34 0 0074 less += 675,386,0,0,-36 0 0075 equal +> 675,514,8,0,-34 0 0076 greater +? 500,664,12,22,-82,22 2 0077 question +@ 920,666,18,0,-68 2 0100 at +at " +A 611,668,0,3,101,3 2 0101 A +B 611,653,0,27,58,27 2 0102 B +C 667,666,18,72,-16,43 2 0103 C +D 722,653,0,28,58,28 2 0104 D +E 611,653,0,73,51,43 2 0105 E +F 611,653,0,84,42,43 2 0106 F +G 722,666,18,50,-2,43 2 0107 G +H 722,653,0,95,58,43 2 0110 H +I 333,653,0,101,58,43 2 0111 I +J 444,653,18,97,56,43 2 0112 J +K 667,653,0,105,43,43 2 0113 K +L 556,653,0,53,58,43 2 0114 L +M 833,653,0,90,68,43 2 0115 M +N 667,653,15,110,70,43 2 0116 N +O 722,666,18,27,-10,27 2 0117 O +P 611,653,0,44,50,43 2 0120 P +Q 722,666,182,27,-9,27 2 0121 Q +R 611,653,0,27,63,27 2 0122 R +S 500,667,18,58,33,43 2 0123 S +T 556,653,0,127,-9,43 2 0124 T +U 722,653,18,93,-52,43 2 0125 U +V 611,653,18,127,-26,43 2 0126 V +W 833,653,18,123,-21,43 2 0127 W +X 611,653,0,94,79,43 2 0130 X +Y 556,653,0,127,-28,43 2 0131 Y +Z 556,653,0,100,56,43 2 0132 Z +[ 389,663,153,52,29,43 2 0133 bracketleft +lB " +\ 278,666,18,91,91,43 2 0134 backslash +rs " +] 389,663,153,43,38,43 2 0135 bracketright +rB " +a^ 333,661,0,102,-41,43 2 0136 circumflex +^ " +_ 500,0,125,50,50,43 0 0137 underscore +` 333,666,0,27,-121,27 2 0140 quoteleft +oq " +a 500,441,11,26,33,26 0 0141 a +b 500,683,11,23,27,23 2 0142 b +c 444,441,11,31,20,31 0 0143 c +d 500,683,13,77,35,43 2 0144 d +e 444,441,11,18,19,18 0 0145 e +f 278,678,207,196,197,43 3 0146 f +g 500,441,206,22,42,22 1 0147 g +h 500,683,9,28,31,28 2 0150 h +i 278,654,11,36,1,36 2 0151 i +j 278,654,207,48,174,43 3 0152 j +k 444,683,11,67,36,43 2 0153 k +l 278,683,11,51,9,43 2 0154 l +m 722,441,9,32,38,32 0 0155 m +n 500,441,9,24,36,24 0 0156 n +o 500,441,11,18,23,18 0 0157 o +p 500,441,205,19,125,19 1 0160 p +q 500,441,209,33,25,33 1 0161 q +r 389,441,0,73,5,43 0 0162 r +s 389,442,13,27,34,27 0 0163 s +t 278,546,11,68,13,43 2 0164 t +u 500,441,11,25,8,25 0 0165 u +v 444,441,18,32,29,32 0 0166 v +w 667,441,18,31,34,31 0 0167 w +x 444,441,11,53,77,43 0 0170 x +y 444,441,206,32,74,32 1 0171 y +z 389,428,81,41,52,41 0 0172 z +lC 400,687,177,57,-1,43 2 0173 braceleft +{ " +ba 275,666,18,0,-55 2 0174 bar +| " +rC 400,687,177,0,57 2 0175 braceright +} " +a~ 333,624,0,144,-50,43 2 0176 tilde +~ " +bq 333,101,129,0,6 0 0200 quotesinglbase +Fo 500,403,0,0,-3 0 0201 guillemotleft +char171 " +Fc 500,403,0,0,-5 0 0202 guillemotright +char187 " +bu 350,461,0,10,10,10 0 0203 bullet +Fn 500,682,182,57,25,43 2 0204 florin +f/ 167,676,10,220,219,43 2 0205 fraction +%0 1000,706,19,60,25,43 2 0206 perthousand +dg 500,666,159,38,-51,38 2 0207 dagger +dd 500,666,143,41,28,41 2 0210 daggerdbl +en 500,243,0,55,56,43 0 0211 endash +em 889,243,0,55,56,43 0 0212 emdash +fi 500,681,207,31,191,31 3 0214 fi +fl 500,682,204,68,191,43 3 0215 fl +.i 278,441,11,7,1,7 0 0220 dotlessi +ga 333,664,0,28,-71,28 2 0222 grave +a" 333,664,0,203,-43,43 2 0223 hungarumlaut +a. 333,606,0,22,-157,22 2 0224 dotaccent +ab 333,650,0,135,-67,43 2 0225 breve +ah 333,661,0,143,-71,43 2 0226 caron +ao 333,691,0,72,-105,43 2 0227 ring +ho 333,40,169,0,70 0 0230 ogonek +lq 556,666,0,8,-116,8 2 0231 quotedblleft +rq 556,666,0,0,-101 2 0232 quotedblright +oe 667,441,12,29,30,29 0 0233 oe +/l 278,683,11,79,13,43 2 0234 lslash +Bq 556,101,129,0,-7 0 0235 quotedblbase +OE 944,666,8,70,1,43 2 0236 OE +/L 556,653,0,53,58,43 2 0237 Lslash +r! 389,473,205,0,-9 1 0241 exclamdown +char161 " +ct 500,560,143,22,-27,22 2 0242 cent +char162 " +Po 500,670,6,67,40,43 2 0243 sterling +char163 " +Cs 500,597,0,72,72,43 2 0244 currency +char164 " +Ye 500,653,0,153,23,43 2 0245 yen +char165 " +bb 275,666,18,0,-55 2 0246 brokenbar +char166 " +sc 500,666,162,11,-3,11 2 0247 section +char167 " +ad 333,606,0,122,-57,43 2 0250 dieresis +char168 " +co 760,666,18,9,9,9 2 0251 copyright +char169 " +Of 276,676,0,126,8,43 2 0252 ordfeminine +char170 " +fo 333,403,0,0,-1 0 0253 guilsinglleft +no 675,386,0,0,-36 0 0254 logicalnot +char172 " +\- 675,286,0,0,-36 0 0255 minus +rg 760,666,18,9,9,9 2 0256 registered +char174 " +a- 333,583,0,128,-49,43 2 0257 macron +char175 " +de 400,676,0,37,-51,37 2 0260 degree +char176 " +char177 675,506,0,0,-36 0 0261 plusminus +S2 300,676,0,74,17,43 2 0262 twosuperior +char178 " +S3 300,676,0,89,7,43 2 0263 threesuperior +char179 " +aa 333,664,0,120,-130,43 2 0264 acute +char180 " +char181 500,428,209,47,80,43 1 0265 mu +ps 523,653,123,143,-5,43 2 0266 paragraph +char182 " +char183 250,310,0,0,-20 0 0267 periodcentered +ac 333,0,217,0,80 1 0270 cedilla +char184 " +S1 300,676,0,34,7,34 2 0271 onesuperior +char185 " +Om 310,676,0,102,-17,43 2 0272 ordmasculine +char186 " +fc 333,403,0,0,-2 0 0273 guilsinglright +14 750,676,10,36,17,36 2 0274 onequarter +char188 " +12 750,676,10,49,16,43 2 0275 onehalf +char189 " +34 750,676,10,36,27,36 2 0276 threequarters +char190 " +r? 500,471,205,0,22 1 0277 questiondown +char191 " +`A 611,876,0,3,101,3 2 0300 Agrave +char192 " +'A 611,876,0,3,101,3 2 0301 Aacute +char193 " +^A 611,873,0,3,101,3 2 0302 Acircumflex +char194 " +~A 611,836,0,5,101,5 2 0303 Atilde +char195 " +:A 611,818,0,3,101,3 2 0304 Adieresis +char196 " +oA 611,883,0,3,101,3 2 0305 Aring +char197 " +AE 889,653,0,72,77,43 2 0306 AE +char198 " +,C 667,666,217,72,-16,43 3 0307 Ccedilla +char199 " +`E 611,876,0,73,51,43 2 0310 Egrave +char200 " +'E 611,876,0,73,51,43 2 0311 Eacute +char201 " +^E 611,873,0,73,51,43 2 0312 Ecircumflex +char202 " +:E 611,818,0,73,51,43 2 0313 Edieresis +char203 " +`I 333,876,0,101,58,43 2 0314 Igrave +char204 " +'I 333,876,0,130,58,43 2 0315 Iacute +char205 " +^I 333,873,0,142,58,43 2 0316 Icircumflex +char206 " +:I 333,818,0,152,58,43 2 0317 Idieresis +char207 " +-D 722,653,0,28,58,28 2 0320 Eth +char208 " +~N 667,836,15,110,70,43 2 0321 Ntilde +char209 " +`O 722,876,18,27,-10,27 2 0322 Ograve +char210 " +'O 722,876,18,27,-10,27 2 0323 Oacute +char211 " +^O 722,873,18,27,-10,27 2 0324 Ocircumflex +char212 " +~O 722,836,18,27,-10,27 2 0325 Otilde +char213 " +:O 722,818,18,27,-10,27 2 0326 Odieresis +char214 " +char215 675,497,0,0,-43 0 0327 multiply +/O 722,722,105,27,-10,27 2 0330 Oslash +char216 " +`U 722,876,18,93,-52,43 2 0331 Ugrave +char217 " +'U 722,876,18,93,-52,43 2 0332 Uacute +char218 " +^U 722,873,18,93,-52,43 2 0333 Ucircumflex +char219 " +:U 722,818,18,93,-52,43 2 0334 Udieresis +char220 " +'Y 556,876,0,127,-28,43 2 0335 Yacute +char221 " +TP 611,653,0,8,50,8 2 0336 Thorn +char222 " +ss 500,679,207,43,218,43 3 0337 germandbls +char223 " +`a 500,664,11,26,33,26 2 0340 agrave +char224 " +'a 500,664,11,37,33,37 2 0341 aacute +char225 " +^a 500,661,11,26,33,26 2 0342 acircumflex +char226 " +~a 500,624,11,61,33,43 2 0343 atilde +char227 " +:a 500,606,11,39,33,39 2 0344 adieresis +char228 " +oa 500,691,11,26,33,26 2 0345 aring +char229 " +ae 667,441,11,23,27,23 0 0346 ae +char230 " +,c 444,441,217,31,24,31 1 0347 ccedilla +char231 " +`e 444,664,11,18,19,18 2 0350 egrave +char232 " +'e 444,664,11,65,19,43 2 0351 eacute +char233 " +^e 444,661,11,47,19,43 2 0352 ecircumflex +char234 " +:e 444,606,11,57,19,43 2 0353 edieresis +char235 " +`i 278,664,11,56,1,43 2 0354 igrave +char236 " +'i 278,664,11,128,1,43 2 0355 iacute +char237 " +^i 278,661,11,100,16,43 2 0356 icircumflex +char238 " +:i 278,606,11,125,1,43 2 0357 idieresis +char239 " +Sd 500,683,11,32,23,32 2 0360 eth +char240 " +~n 500,624,9,26,36,26 2 0361 ntilde +char241 " +`o 500,664,11,18,23,18 2 0362 ograve +char242 " +'o 500,664,11,37,23,37 2 0363 oacute +char243 " +^o 500,661,11,18,23,18 2 0364 ocircumflex +char244 " +~o 500,624,11,46,23,43 2 0365 otilde +char245 " +:o 500,606,11,39,23,39 2 0366 odieresis +char246 " +char247 675,517,11,0,-36 0 0367 divide +/o 500,554,135,19,22,19 2 0370 oslash +char248 " +`u 500,664,11,25,8,25 2 0371 ugrave +char249 " +'u 500,664,11,27,8,27 2 0372 uacute +char250 " +^u 500,661,11,25,8,25 2 0373 ucircumflex +char251 " +:u 500,606,11,29,8,29 2 0374 udieresis +char252 " +'y 444,664,206,65,74,43 3 0375 yacute +char253 " +Tp 500,683,205,19,125,19 3 0376 thorn +char254 " +:y 444,606,206,47,74,43 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/TR b/gnu/usr.bin/groff/devices/devps/TR new file mode 100644 index 0000000000..25232c6d1a --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/TR @@ -0,0 +1,519 @@ +name TR +internalname Times-Roman +spacewidth 250 +encoding text.enc +ligatures fi fl 0 +kernpairs +A y -92 +A w -92 +A v -74 +A ' -111 +A Y -105 +A W -90 +A V -135 +A U -55 +A T -111 +A Q -55 +A O -55 +A G -40 +A C -40 +B U -10 +B A -35 +D Y -55 +D W -30 +D V -40 +D A -40 +F . -80 +F o -15 +F , -80 +F a -15 +F A -74 +J A -60 +K y -25 +K u -15 +K o -35 +K e -25 +K O -30 +L y -55 +L ' -92 +L Y -100 +L W -74 +L V -100 +L T -92 +N A -35 +O Y -50 +O X -40 +O W -35 +O V -50 +O T -40 +O A -35 +P . -111 +P , -111 +P a -15 +P A -92 +Q U -10 +R Y -65 +R W -55 +R V -80 +R U -40 +R T -60 +R O -40 +T y -80 +T w -80 +T u -45 +T ; -55 +T r -35 +T . -74 +T o -80 +T i -35 +T - -92 +T hy -92 +T char173 -92 +T e -70 +T , -74 +T : -50 +T a -80 +T O -18 +T A -93 +U A -40 +V u -75 +V ; -74 +V . -129 +V o -129 +V i -60 +V - -100 +V hy -100 +V char173 -100 +V e -111 +V , -129 +V : -74 +V a -111 +V O -40 +V G -15 +V A -135 +W y -73 +W u -50 +W ; -37 +W . -92 +W o -80 +W i -40 +W - -65 +W hy -65 +W char173 -65 +W e -80 +W , -92 +W : -37 +W a -80 +W O -10 +W A -120 +Y u -111 +Y ; -92 +Y . -129 +Y o -110 +Y i -55 +Y - -111 +Y hy -111 +Y char173 -111 +Y e -100 +Y , -129 +Y : -92 +Y a -100 +Y O -30 +Y A -120 +a w -15 +a v -20 +b v -15 +b u -20 +b . -40 +c y -15 +, ' -70 +, rq -70 +e y -15 +e x -15 +e w -25 +e v -25 +e g -15 +f ' 55 +f i -20 +f f -25 +f .i -50 +f a -10 +g a -5 +h y -5 +i v -25 +k y -15 +k o -10 +k e -10 +l w -10 +n y -15 +n v -40 +o y -10 +o w -25 +o v -15 +p y -10 +. ' -70 +. rq -70 +lq A -80 +` ` -74 +` oq -74 +oq ` -74 +oq oq -74 +` A -80 +oq A -80 +' v -50 +' t -18 +' s -55 +' r -50 +' ' -74 +' l -10 +' d -50 +r . -55 +r - -20 +r hy -20 +r char173 -20 +r g -18 +r , -40 +v . -65 +v o -20 +v e -15 +v , -65 +v a -25 +w . -65 +w o -10 +w , -65 +w a -10 +x e -15 +y . -65 +y , -65 +charset +ha 469,662 2 0000 asciicircum +ti 541,323 0 0001 asciitilde +vS 556,886,14 2 0002 Scaron +vZ 611,886 2 0003 Zcaron +vs 389,674,10 2 0004 scaron +vz 444,674 2 0005 zcaron +:Y 722,835 2 0006 Ydieresis +tm 980,662 2 0007 trademark +aq 180,676 2 0010 quotesingle +space 250 0 0040 +! 333,676,9 2 0041 exclam +" 408,676 2 0042 quotedbl +# 500,662 2 0043 numbersign +sh " +$ 500,727,87 2 0044 dollar +Do " +% 833,676,13 2 0045 percent +& 778,676,13 2 0046 ampersand +' 333,676 2 0047 quoteright +( 333,676,177 2 0050 parenleft +) 333,676,177 2 0051 parenright +* 500,676 2 0052 asterisk ++ 564,506 0 0053 plus +, 250,102,141 0 0054 comma +- 333,257 0 0055 hyphen +hy " +char173 " +. 250,100,11 0 0056 period +/ 278,676,14 2 0057 slash +sl " +0 500,676,14 2 0060 zero +1 500,676 2 0061 one +2 500,676 2 0062 two +3 500,676,14 2 0063 three +4 500,676 2 0064 four +5 500,688,14 2 0065 five +6 500,684,14 2 0066 six +7 500,662,8 2 0067 seven +8 500,676,14 2 0070 eight +9 500,676,22 2 0071 nine +: 278,459,11 0 0072 colon +; 278,459,141 0 0073 semicolon +< 564,514,8 0 0074 less += 564,386 0 0075 equal +> 564,514,8 0 0076 greater +? 444,676,8 2 0077 question +@ 921,676,14 2 0100 at +at " +A 722,674 2 0101 A +B 667,662 2 0102 B +C 667,676,14 2 0103 C +D 722,662 2 0104 D +E 611,662 2 0105 E +F 556,662 2 0106 F +G 722,676,14 2 0107 G +H 722,662 2 0110 H +I 333,662 2 0111 I +J 389,662,14 2 0112 J +K 722,662 2 0113 K +L 611,662 2 0114 L +M 889,662 2 0115 M +N 722,662,11 2 0116 N +O 722,676,14 2 0117 O +P 556,662 2 0120 P +Q 722,676,178 2 0121 Q +R 667,662 2 0122 R +S 556,676,14 2 0123 S +T 611,662 2 0124 T +U 722,662,14 2 0125 U +V 722,662,11 2 0126 V +W 944,662,11 2 0127 W +X 722,662 2 0130 X +Y 722,662 2 0131 Y +Z 611,662 2 0132 Z +[ 333,662,156 2 0133 bracketleft +lB " +\ 278,676,14 2 0134 backslash +rs " +] 333,662,156 2 0135 bracketright +rB " +a^ 333,674 2 0136 circumflex +^ " +_ 500,0,125 0 0137 underscore +` 333,676 2 0140 quoteleft +oq " +a 444,460,10 0 0141 a +b 500,683,10 2 0142 b +c 444,460,10 0 0143 c +d 500,683,10 2 0144 d +e 444,460,10 0 0145 e +f 333,683 2 0146 f +g 500,460,218 1 0147 g +h 500,683 2 0150 h +i 278,683 2 0151 i +j 278,683,218 3 0152 j +k 500,683 2 0153 k +l 278,683 2 0154 l +m 778,460 0 0155 m +n 500,460 0 0156 n +o 500,460,10 0 0157 o +p 500,460,217 1 0160 p +q 500,460,217 1 0161 q +r 333,460 0 0162 r +s 389,460,10 0 0163 s +t 278,579,10 2 0164 t +u 500,450,10 0 0165 u +v 500,450,14 0 0166 v +w 722,450,14 0 0167 w +x 500,450 0 0170 x +y 500,450,218 1 0171 y +z 444,450 0 0172 z +lC 480,680,181 2 0173 braceleft +{ " +ba 200,676,14 2 0174 bar +| " +rC 480,680,181 2 0175 braceright +} " +a~ 333,638 2 0176 tilde +~ " +bq 333,102,141 0 0200 quotesinglbase +Fo 500,416 0 0201 guillemotleft +char171 " +Fc 500,416 0 0202 guillemotright +char187 " +bu 350,466 0 0203 bullet +Fn 500,676,189 2 0204 florin +f/ 167,676,14 2 0205 fraction +%0 1000,706,19 2 0206 perthousand +dg 500,676,149 2 0207 dagger +dd 500,676,153 2 0210 daggerdbl +en 500,250 0 0211 endash +em 1000,250 0 0212 emdash +fi 556,683 2 0214 fi +fl 556,683 2 0215 fl +.i 278,460 0 0220 dotlessi +ga 333,678 2 0222 grave +a" 333,678 2 0223 hungarumlaut +a. 333,623 2 0224 dotaccent +ab 333,664 2 0225 breve +ah 333,674 2 0226 caron +ao 333,711 2 0227 ring +ho 333,0,165 0 0230 ogonek +lq 444,676 2 0231 quotedblleft +rq 444,676 2 0232 quotedblright +oe 722,460,10 0 0233 oe +/l 278,683 2 0234 lslash +Bq 444,102,141 0 0235 quotedblbase +OE 889,668,6 2 0236 OE +/L 611,662 2 0237 Lslash +r! 333,467,218 1 0241 exclamdown +char161 " +ct 500,579,138 2 0242 cent +char162 " +Po 500,676,8 2 0243 sterling +char163 " +Cs 500,602 2 0244 currency +char164 " +Ye 500,662 2 0245 yen +char165 " +bb 200,676,14 2 0246 brokenbar +char166 " +sc 500,676,148 2 0247 section +char167 " +ad 333,623 2 0250 dieresis +char168 " +co 760,676,14 2 0251 copyright +char169 " +Of 276,676 2 0252 ordfeminine +char170 " +fo 333,416 0 0253 guilsinglleft +no 564,386 0 0254 logicalnot +char172 " +\- 564,286 0 0255 minus +rg 760,676,14 2 0256 registered +char174 " +a- 333,601 2 0257 macron +char175 " +de 400,676 2 0260 degree +char176 " +char177 564,506 0 0261 plusminus +S2 300,676 2 0262 twosuperior +char178 " +S3 300,676 2 0263 threesuperior +char179 " +aa 333,678 2 0264 acute +char180 " +char181 500,450,218 1 0265 mu +ps 453,662,154 2 0266 paragraph +char182 " +char183 250,310 0 0267 periodcentered +ac 333,0,215 0 0270 cedilla +char184 " +S1 300,676 2 0271 onesuperior +char185 " +Om 310,676 2 0272 ordmasculine +char186 " +fc 333,416 0 0273 guilsinglright +14 750,676,14 2 0274 onequarter +char188 " +12 750,676,14 2 0275 onehalf +char189 " +34 750,676,14 2 0276 threequarters +char190 " +r? 444,466,218 1 0277 questiondown +char191 " +`A 722,890 2 0300 Agrave +char192 " +'A 722,890 2 0301 Aacute +char193 " +^A 722,886 2 0302 Acircumflex +char194 " +~A 722,850 2 0303 Atilde +char195 " +:A 722,835 2 0304 Adieresis +char196 " +oA 722,898 2 0305 Aring +char197 " +AE 889,662 2 0306 AE +char198 " +,C 667,676,215 2 0307 Ccedilla +char199 " +`E 611,890 2 0310 Egrave +char200 " +'E 611,890 2 0311 Eacute +char201 " +^E 611,886 2 0312 Ecircumflex +char202 " +:E 611,835 2 0313 Edieresis +char203 " +`I 333,890 2 0314 Igrave +char204 " +'I 333,890 2 0315 Iacute +char205 " +^I 333,886 2 0316 Icircumflex +char206 " +:I 333,835 2 0317 Idieresis +char207 " +-D 722,662 2 0320 Eth +char208 " +~N 722,850,11 2 0321 Ntilde +char209 " +`O 722,890,14 2 0322 Ograve +char210 " +'O 722,890,14 2 0323 Oacute +char211 " +^O 722,886,14 2 0324 Ocircumflex +char212 " +~O 722,850,14 2 0325 Otilde +char213 " +:O 722,835,14 2 0326 Odieresis +char214 " +char215 564,497 0 0327 multiply +/O 722,734,80 2 0330 Oslash +char216 " +`U 722,890,14 2 0331 Ugrave +char217 " +'U 722,890,14 2 0332 Uacute +char218 " +^U 722,886,14 2 0333 Ucircumflex +char219 " +:U 722,835,14 2 0334 Udieresis +char220 " +'Y 722,890 2 0335 Yacute +char221 " +TP 556,662 2 0336 Thorn +char222 " +ss 500,683,9 2 0337 germandbls +char223 " +`a 444,678,10 2 0340 agrave +char224 " +'a 444,678,10 2 0341 aacute +char225 " +^a 444,674,10 2 0342 acircumflex +char226 " +~a 444,638,10 2 0343 atilde +char227 " +:a 444,623,10 2 0344 adieresis +char228 " +oa 444,711,10 2 0345 aring +char229 " +ae 667,460,10 0 0346 ae +char230 " +,c 444,460,215 0 0347 ccedilla +char231 " +`e 444,678,10 2 0350 egrave +char232 " +'e 444,678,10 2 0351 eacute +char233 " +^e 444,674,10 2 0352 ecircumflex +char234 " +:e 444,623,10 2 0353 edieresis +char235 " +`i 278,678 2 0354 igrave +char236 " +'i 278,678 2 0355 iacute +char237 " +^i 278,674 2 0356 icircumflex +char238 " +:i 278,623 2 0357 idieresis +char239 " +Sd 500,686,10 2 0360 eth +char240 " +~n 500,638 2 0361 ntilde +char241 " +`o 500,678,10 2 0362 ograve +char242 " +'o 500,678,10 2 0363 oacute +char243 " +^o 500,674,10 2 0364 ocircumflex +char244 " +~o 500,638,10 2 0365 otilde +char245 " +:o 500,623,10 2 0366 odieresis +char246 " +char247 564,516,10 0 0367 divide +/o 500,551,112 0 0370 oslash +char248 " +`u 500,678,10 2 0371 ugrave +char249 " +'u 500,678,10 2 0372 uacute +char250 " +^u 500,674,10 2 0373 ucircumflex +char251 " +:u 500,623,10 2 0374 udieresis +char252 " +'y 500,678,218 3 0375 yacute +char253 " +Tp 500,683,217 3 0376 thorn +char254 " +:y 500,623,218 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/ZCMI b/gnu/usr.bin/groff/devices/devps/ZCMI new file mode 100644 index 0000000000..53e56fd717 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/ZCMI @@ -0,0 +1,477 @@ +name ZCMI +internalname ZapfChancery-MediumItalic +slant 14 +spacewidth 220 +encoding text.enc +ligatures fi fl 0 +kernpairs +A ' -40 +A rq -40 +A U -10 +A T 10 +A Q 10 +A O 10 +A G -30 +A C 20 +D . -30 +D , -20 +D Y 10 +D A -10 +F . -40 +F i 10 +F , -30 +G . -20 +G , -10 +J . -20 +J , -10 +K u -20 +K o -20 +K e -20 +L y -10 +L ' -25 +L rq -25 +L W -10 +L V -20 +O . -20 +O , -10 +O Y 10 +O T 20 +O A -20 +P . -50 +P o -10 +P e -10 +P , -40 +P a -20 +P A -10 +Q U -10 +R Y 10 +R W 10 +R T 20 +T o -20 +T i 20 +T - -20 +T hy -20 +T char173 -20 +T h 20 +T e -20 +T a -20 +T O 30 +T A 10 +V . -100 +V o -20 +V e -20 +V , -90 +V a -20 +V O 10 +V G -20 +W . -50 +W o -20 +W i 10 +W h 10 +W e -20 +W , -40 +W a -20 +W O 10 +Y u -20 +Y . -50 +Y o -50 +Y i 10 +Y e -40 +Y , -40 +Y a -60 +b . -30 +b l -20 +b , -20 +b b -20 +c k -10 +, ' -70 +, rq -70 +d w -20 +d v -10 +d d -40 +e y 10 +f ' 30 +f rq 30 +f . -50 +f f -50 +f e -10 +f , -40 +f a -20 +g y 10 +g . -30 +g i 10 +g e 10 +g , -20 +g a 10 +k y 10 +k o -10 +k e -20 +m y 10 +m u 10 +n y 20 +o . -30 +o , -20 +p . -30 +p p -10 +p , -20 +. ' -80 +. rq -80 +lq ` 20 +lq oq 20 +lq A 10 +` ` -115 +` oq -115 +oq ` -115 +oq oq -115 +` A 10 +oq A 10 +' v 30 +' t 20 +' s -25 +' r 30 +' ' -115 +' rq 20 +' l 20 +r . -50 +r i 10 +r , -40 +s . -20 +s , -10 +v . -30 +v , -20 +w . -30 +w o 10 +w h 20 +w , -20 +charset +ha 520,594,0,62,-82,62 2 0000 asciicircum +ti 520,320,0,69,-73,69 0 0001 asciitilde +vS 460,831,81,184,5,87 2 0002 Scaron +vZ 620,831,19,99,8,87 2 0003 Zcaron +vs 320,659,14,194,4,87 2 0004 scaron +vz 440,659,14,124,24,87 2 0005 zcaron +:Y 560,762,168,264,9,87 2 0006 Ydieresis +tm 1000,594,0,96,-77,87 2 0007 trademark +aq 160,610,0,105,-95,87 2 0010 quotesingle +space 220 0 0040 +! 280,610,14,123,-69,87 2 0041 exclam +" 220,610,0,163,-70,87 2 0042 quotedbl +# 440,594,0,131,-33,87 2 0043 numbersign +sh " +$ 440,709,144,118,-10,87 2 0044 dollar +Do " +% 680,700,160,80,-82,80 2 0045 percent +& 780,610,16,185,-76,87 2 0046 ampersand +' 240,610,0,148,-118,87 2 0047 quoteright +( 260,664,216,201,-46,87 2 0050 parenleft +) 220,664,216,132,63,87 2 0051 parenright +* 420,610,0,109,-89,87 2 0052 asterisk ++ 520,426,0,73,-67,73 0 0053 plus +, 220,148,140,43,25,43 0 0054 comma +- 280,248,0,104,-19,87 0 0055 hyphen +hy " +char173 " +. 220,128,14,58,-52,58 0 0056 period +/ 340,610,16,168,-24,87 2 0057 slash +sl " +0 440,610,16,148,-29,87 2 0060 zero +1 440,610,0,38,9,38 2 0061 one +2 440,610,16,95,33,87 2 0062 two +3 440,610,16,95,49,87 2 0063 three +4 440,610,35,109,-27,87 2 0064 four +5 440,679,16,205,-10,87 2 0065 five +6 440,610,16,166,-40,87 2 0066 six +7 440,645,33,171,-107,87 2 0067 seven +8 440,610,16,139,-15,87 2 0070 eight +9 440,610,16,127,18,87 2 0071 nine +: 260,438,14,86,-48,86 0 0072 colon +; 240,438,140,109,21,87 0 0073 semicolon +< 520,468,0,57,-89,57 0 0074 less += 520,340,0,73,-67,73 0 0075 equal +> 520,468,0,57,-89,57 0 0076 greater +? 380,610,14,125,-100,87 2 0077 question +@ 700,610,16,103,-77,87 2 0100 at +at " +A 620,632,16,127,37,87 2 0101 A +B 600,640,6,124,-35,87 2 0102 B +C 520,610,16,161,-43,87 2 0103 C +D 700,640,6,118,-36,87 2 0104 D +E 620,618,12,139,-41,87 2 0105 E +F 580,629,118,263,-70,87 2 0106 F +G 620,610,242,139,-98,87 2 0107 G +H 680,708,16,248,32,87 2 0110 H +I 380,594,0,174,-49,87 2 0111 I +J 400,594,147,188,64,87 2 0112 J +K 660,610,153,234,-3,87 2 0113 K +L 580,610,16,127,-3,87 2 0114 L +M 840,722,16,230,-8,87 2 0115 M +N 700,708,168,265,-35,87 2 0116 N +O 600,610,16,110,-44,87 2 0117 O +P 540,628,0,168,8,87 2 0120 P +Q 600,610,177,225,-34,87 2 0121 Q +R 600,640,168,255,-8,87 2 0122 R +S 460,610,81,148,5,87 2 0123 S +T 500,667,0,294,-13,87 2 0124 T +U 740,617,16,102,-76,87 2 0125 U +V 640,714,16,220,-74,87 2 0126 V +W 880,723,16,216,-44,87 2 0127 W +X 560,610,16,189,80,87 2 0130 X +Y 560,647,168,264,9,87 2 0131 Y +Z 620,624,19,99,8,87 2 0132 Z +[ 240,655,207,215,63,87 2 0133 bracketleft +lB " +\ 480,610,16,94,-90,87 2 0134 backslash +rs " +] 320,655,207,121,77,87 2 0135 bracketright +rB " +a^ 340,649,0,153,-173,87 2 0136 circumflex +^ " +_ 500,0,125,50,50,50 0 0137 underscore +` 240,610,0,149,-119,87 2 0140 quoteleft +oq " +a 420,438,15,115,-42,87 0 0141 a +b 420,714,23,122,-32,87 2 0142 b +c 340,438,14,116,-37,87 0 0143 c +d 440,714,14,261,-52,87 2 0144 d +e 340,438,14,113,-37,87 0 0145 e +f 320,714,314,277,169,87 3 0146 f +g 400,438,314,153,158,87 1 0147 g +h 440,714,14,134,-5,87 2 0150 h +i 240,635,14,151,-50,87 2 0151 i +j 220,635,314,162,162,87 3 0152 j +k 440,714,184,238,-37,87 2 0153 k +l 240,714,14,290,-52,87 2 0154 l +m 620,438,14,134,-36,87 0 0155 m +n 460,438,14,134,-51,87 0 0156 n +o 400,438,14,99,-37,87 0 0157 o +p 440,432,314,94,73,87 1 0160 p +q 400,510,300,140,-37,87 1 0161 q +r 300,438,14,174,-51,87 0 0162 r +s 320,438,14,133,4,87 0 0163 s +t 320,539,14,156,-56,87 2 0164 t +u 460,438,14,118,-52,87 0 0165 u +v 440,488,14,143,-37,87 0 0166 v +w 680,488,14,152,-37,87 0 0167 w +x 420,438,195,219,-20,87 0 0170 x +y 400,438,314,133,74,87 1 0171 y +z 440,445,14,118,24,87 0 0172 z +lC 240,655,207,193,-5,87 2 0173 braceleft +{ " +ba 520,714,16,0,-270 2 0174 bar +| " +rC 240,655,207,128,60,87 2 0175 braceright +} " +a~ 440,619,0,132,-193,87 2 0176 tilde +~ " +bq 180,146,121,61,29,61 0 0200 quotesinglbase +Fo 340,414,0,66,-48,66 0 0201 guillemotleft +char171 " +Fc 380,414,0,45,-67,45 0 0202 guillemotright +char187 " +bu 600,445,0,0,-178 0 0203 bullet +Fn 440,610,314,192,114,87 3 0204 florin +f/ 60,610,16,310,231,87 2 0205 fraction +%0 960,700,160,95,-62,87 2 0206 perthousand +dg 460,610,37,158,-88,87 2 0207 dagger +dd 480,610,59,103,-88,87 2 0210 daggerdbl +en 500,239,0,115,-1,87 0 0211 endash +em 1000,239,0,115,-1,87 0 0212 emdash +fi 520,714,314,135,174,87 3 0214 fi +fl 520,714,314,200,174,87 3 0215 fl +.i 240,438,14,116,-50,87 0 0220 dotlessi +ga 220,659,0,169,-143,87 2 0222 grave +a" 400,659,0,145,-158,87 2 0223 hungarumlaut +a. 220,610,0,158,-186,87 2 0224 dotaccent +ab 440,631,0,111,-203,87 2 0225 breve +ah 340,659,0,184,-204,87 2 0226 caron +ao 300,659,0,166,-190,87 2 0227 ring +ho 280,6,191,3,12,3 0 0230 ogonek +lq 340,610,0,174,-119,87 2 0231 quotedblleft +rq 360,610,0,143,-108,87 2 0232 quotedblright +oe 560,438,14,118,-28,87 0 0233 oe +/l 300,714,14,265,-71,87 2 0234 lslash +Bq 280,146,121,51,64,51 0 0235 quotedblbase +OE 820,610,16,139,-13,87 2 0236 OE +/L 580,610,16,127,1,87 2 0237 Lslash +r! 280,438,186,76,-22,76 0 0241 exclamdown +char161 " +ct 440,543,134,86,-72,86 2 0242 cent +char162 " +Po 440,610,52,116,66,87 2 0243 sterling +char163 " +Cs 440,509,0,84,0,84 0 0244 currency +char164 " +Ye 440,647,168,223,51,87 2 0245 yen +char165 " +bb 520,714,16,0,-270 2 0246 brokenbar +char166 " +sc 420,610,215,144,-3,87 2 0247 section +char167 " +ad 360,610,0,159,-193,87 2 0250 dieresis +char168 " +co 740,610,16,73,-87,73 2 0251 copyright +char169 " +Of 260,610,0,176,-61,87 2 0252 ordfeminine +char170 " +fo 240,414,0,68,-48,68 0 0253 guilsinglleft +no 520,340,0,73,-67,73 0 0254 logicalnot +char172 " +\- 520,242,0,73,-67,73 0 0255 minus +rg 740,610,16,73,-87,73 2 0256 registered +char174 " +a- 440,578,0,75,-172,75 2 0257 macron +char175 " +de 400,610,0,107,-121,87 2 0260 degree +char176 " +char177 520,436,0,73,-67,73 0 0261 plusminus +S2 264,610,0,140,-22,87 2 0262 twosuperior +char178 " +S3 264,610,0,134,-9,87 2 0263 threesuperior +char179 " +aa 300,659,0,172,-215,87 2 0264 acute +char180 " +char181 460,438,314,113,43,87 1 0265 mu +ps 500,594,199,188,-55,87 2 0266 paragraph +char182 " +char183 220,310,0,71,-89,71 0 0267 periodcentered +ac 300,6,191,0,38 0 0270 cedilla +char184 " +S1 264,610,0,97,-33,87 2 0271 onesuperior +char185 " +Om 260,610,0,163,-78,87 2 0272 ordmasculine +char186 " +fc 260,414,0,56,-56,56 0 0273 guilsinglright +14 660,610,16,92,-6,87 2 0274 onequarter +char188 " +12 660,610,16,92,-6,87 2 0275 onehalf +char189 " +34 660,610,16,96,11,87 2 0276 threequarters +char190 " +r? 400,438,186,37,-32,37 0 0277 questiondown +char191 " +`A 620,821,16,127,37,87 2 0300 Agrave +char192 " +'A 620,821,16,132,37,87 2 0301 Aacute +char193 " +^A 620,821,16,127,37,87 2 0302 Acircumflex +char194 " +~A 620,771,16,132,37,87 2 0303 Atilde +char195 " +:A 620,762,16,139,37,87 2 0304 Adieresis +char196 " +oA 620,831,16,127,37,87 2 0305 Aring +char197 " +AE 740,594,16,109,71,87 2 0306 AE +char198 " +,C 520,610,191,161,-43,87 2 0307 Ccedilla +char199 " +`E 620,821,12,139,-41,87 2 0310 Egrave +char200 " +'E 620,821,12,139,-41,87 2 0311 Eacute +char201 " +^E 620,821,12,139,-41,87 2 0312 Ecircumflex +char202 " +:E 620,762,12,139,-41,87 2 0313 Edieresis +char203 " +`I 380,821,0,174,-49,87 2 0314 Igrave +char204 " +'I 380,821,0,202,-49,87 2 0315 Iacute +char205 " +^I 380,821,0,174,-49,87 2 0316 Icircumflex +char206 " +:I 380,762,0,189,-49,87 2 0317 Idieresis +char207 " +-D 700,640,6,118,-36,87 2 0320 Eth +char208 " +~N 700,761,168,265,-35,87 2 0321 Ntilde +char209 " +`O 600,821,16,110,-44,87 2 0322 Ograve +char210 " +'O 600,821,16,110,-44,87 2 0323 Oacute +char211 " +^O 600,821,16,110,-44,87 2 0324 Ocircumflex +char212 " +~O 600,761,16,110,-44,87 2 0325 Otilde +char213 " +:O 600,762,16,110,-44,87 2 0326 Odieresis +char214 " +char215 520,410,0,57,-83,57 0 0327 multiply +/O 660,672,78,141,-33,87 2 0330 Oslash +char216 " +`U 740,821,16,102,-76,87 2 0331 Ugrave +char217 " +'U 740,821,16,102,-76,87 2 0332 Uacute +char218 " +^U 740,821,16,102,-76,87 2 0333 Ucircumflex +char219 " +:U 740,762,16,102,-76,87 2 0334 Udieresis +char220 " +'Y 560,821,168,264,9,87 2 0335 Yacute +char221 " +TP 540,623,0,157,-2,87 2 0336 Thorn +char222 " +ss 420,714,314,172,177,87 3 0337 germandbls +char223 " +`a 420,659,15,115,-42,87 2 0340 agrave +char224 " +'a 420,659,15,122,-42,87 2 0341 aacute +char225 " +^a 420,649,15,115,-42,87 2 0342 acircumflex +char226 " +~a 420,619,15,152,-42,87 2 0343 atilde +char227 " +:a 420,610,15,115,-42,87 2 0344 adieresis +char228 " +oa 420,659,15,115,-42,87 2 0345 aring +char229 " +ae 540,468,14,134,-17,87 0 0346 ae +char230 " +,c 340,438,191,116,-12,87 0 0347 ccedilla +char231 " +`e 340,659,14,113,-37,87 2 0350 egrave +char232 " +'e 340,659,14,172,-37,87 2 0351 eacute +char233 " +^e 340,649,14,143,-37,87 2 0352 ecircumflex +char234 " +:e 340,610,14,159,-37,87 2 0353 edieresis +char235 " +`i 240,659,14,116,-50,87 2 0354 igrave +char236 " +'i 240,659,14,202,-50,87 2 0355 iacute +char237 " +^i 240,649,14,173,-50,87 2 0356 icircumflex +char238 " +:i 240,610,14,179,-50,87 2 0357 idieresis +char239 " +Sd 400,714,14,172,-37,87 2 0360 eth +char240 " +~n 460,619,14,134,-51,87 2 0361 ntilde +char241 " +`o 400,659,14,99,-37,87 2 0362 ograve +char242 " +'o 400,659,14,132,-37,87 2 0363 oacute +char243 " +^o 400,649,14,103,-37,87 2 0364 ocircumflex +char244 " +~o 400,619,14,152,-37,87 2 0365 otilde +char245 " +:o 400,610,14,129,-37,87 2 0366 odieresis +char246 " +char247 520,440,14,73,-67,73 0 0367 divide +/o 440,488,64,150,4,87 0 0370 oslash +char248 " +`u 460,659,14,118,-52,87 2 0371 ugrave +char249 " +'u 460,659,14,118,-52,87 2 0372 uacute +char250 " +^u 460,649,14,118,-52,87 2 0373 ucircumflex +char251 " +:u 460,610,14,118,-52,87 2 0374 udieresis +char252 " +'y 400,659,314,133,74,87 3 0375 yacute +char253 " +Tp 440,714,314,115,88,87 3 0376 thorn +char254 " +:y 400,610,314,133,74,87 3 0377 ydieresis +char255 " diff --git a/gnu/usr.bin/groff/devices/devps/ZD b/gnu/usr.bin/groff/devices/devps/ZD new file mode 100644 index 0000000000..c2bd4eb8ff --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/ZD @@ -0,0 +1,193 @@ +name ZD +internalname ZapfDingbats +special +spacewidth 278 +charset +space 278 0 0040 +--- 974,621 3 0041 a1 +--- 961,611 3 0042 a2 +--- 974,621 3 0043 a202 +--- 980,692 3 0044 a3 +--- 719,566 3 0045 a4 +--- 789,705,14 3 0046 a5 +--- 790,705,14 3 0047 a119 +--- 791,705,13 3 0050 a118 +--- 690,553 3 0051 a117 +--- 960,568 3 0052 a11 +rh 939,559 3 0053 a12 +--- 549,705,11 3 0054 a13 +--- 855,632 3 0055 a14 +--- 911,642 3 0056 a15 +--- 933,550 3 0057 a16 +--- 911,642 3 0060 a105 +--- 945,553 3 0061 a17 +--- 974,587 3 0062 a18 +OK 755,705,13 3 0063 a19 +--- 846,705,14 3 0064 a20 +--- 762,692 3 0065 a21 +--- 761,692 3 0066 a22 +--- 571,661,68 3 0067 a23 +--- 677,705,13 3 0070 a24 +--- 763,692 3 0071 a25 +--- 760,692 3 0072 a26 +--- 759,692 3 0073 a27 +--- 754,692 3 0074 a28 +--- 494,692 3 0075 a6 +--- 552,692 3 0076 a7 +--- 537,692 3 0077 a8 +--- 577,596 3 0100 a9 +--- 692,705,14 3 0101 a10 +--- 786,705,14 3 0102 a29 +--- 788,705,14 3 0103 a30 +--- 788,705,14 3 0104 a31 +--- 790,705,14 3 0105 a32 +--- 793,705,13 3 0106 a33 +--- 794,705,13 3 0107 a34 +--- 816,705,14 3 0110 a35 +--- 823,705,14 3 0111 a36 +--- 789,705,14 3 0112 a37 +--- 841,705,14 3 0113 a38 +--- 823,705,14 3 0114 a39 +--- 833,705,14 3 0115 a40 +--- 816,705,13 3 0116 a41 +--- 831,705,14 3 0117 a42 +--- 923,705,14 3 0120 a43 +--- 744,692 3 0121 a44 +--- 723,692 3 0122 a45 +--- 749,692 3 0123 a46 +--- 790,705,14 3 0124 a47 +--- 792,705,14 3 0125 a48 +--- 695,706,14 3 0126 a49 +--- 776,699,6 3 0127 a50 +--- 768,699,7 3 0130 a51 +--- 792,705,14 3 0131 a52 +--- 759,692 3 0132 a53 +--- 707,704,13 3 0133 a54 +--- 708,705,14 3 0134 a55 +--- 682,705,14 3 0135 a56 +--- 701,705,14 3 0136 a57 +--- 826,705,14 3 0137 a58 +--- 815,705,14 3 0140 a59 +--- 789,705,14 3 0141 a60 +--- 789,705,14 3 0142 a61 +--- 707,705,14 3 0143 a62 +--- 687,692 3 0144 a63 +--- 696,691 3 0145 a64 +--- 689,692 3 0146 a65 +--- 786,705,14 3 0147 a66 +--- 787,705,14 3 0150 a67 +--- 713,705,14 3 0151 a68 +--- 791,705,14 3 0152 a69 +--- 785,705,14 3 0153 a70 +--- 791,705,14 3 0154 a71 +--- 873,705,14 3 0155 a72 +--- 761,692 3 0156 a73 +--- 762,692 3 0157 a74 +--- 762,692 3 0160 a203 +--- 759,692 3 0161 a75 +--- 759,692 3 0162 a204 +--- 892,705 3 0163 a76 +--- 892,692,14 3 0164 a77 +--- 788,705,14 3 0165 a78 +--- 784,705,14 3 0166 a79 +--- 438,705,14 3 0167 a81 +--- 138,692 3 0170 a82 +--- 277,692 3 0171 a83 +--- 415,692 3 0172 a84 +--- 392,705 3 0173 a97 +--- 392,705 3 0174 a98 +--- 668,705 3 0175 a99 +--- 668,705 3 0176 a100 +--- 732,806,143 3 0241 a101 +--- 544,706,14 3 0242 a102 +--- 544,705,14 3 0243 a103 +--- 910,651 3 0244 a104 +--- 667,705,14 3 0245 a106 +--- 760,705,14 3 0246 a107 +--- 760,569 3 0247 a108 +--- 776,705 3 0250 a112 +--- 595,705,14 3 0251 a111 +--- 694,705,14 3 0252 a110 +--- 626,705 3 0253 a109 +--- 788,705,14 3 0254 a120 +--- 788,705,14 3 0255 a121 +--- 788,705,14 3 0256 a122 +--- 788,705,14 3 0257 a123 +--- 788,705,14 3 0260 a124 +--- 788,705,14 3 0261 a125 +--- 788,705,14 3 0262 a126 +--- 788,705,14 3 0263 a127 +--- 788,705,14 3 0264 a128 +--- 788,705,14 3 0265 a129 +--- 788,705,14 3 0266 a130 +--- 788,705,14 3 0267 a131 +--- 788,705,14 3 0270 a132 +--- 788,705,14 3 0271 a133 +--- 788,705,14 3 0272 a134 +--- 788,705,14 3 0273 a135 +--- 788,705,14 3 0274 a136 +--- 788,705,14 3 0275 a137 +--- 788,705,14 3 0276 a138 +--- 788,705,14 3 0277 a139 +--- 788,705,14 3 0300 a140 +--- 788,705,14 3 0301 a141 +--- 788,705,14 3 0302 a142 +--- 788,705,14 3 0303 a143 +--- 788,705,14 3 0304 a144 +--- 788,705,14 3 0305 a145 +--- 788,705,14 3 0306 a146 +--- 788,705,14 3 0307 a147 +--- 788,705,14 3 0310 a148 +--- 788,705,14 3 0311 a149 +--- 788,705,14 3 0312 a150 +--- 788,705,14 3 0313 a151 +--- 788,705,14 3 0314 a152 +--- 788,705,14 3 0315 a153 +--- 788,705,14 3 0316 a154 +--- 788,705,14 3 0317 a155 +--- 788,705,14 3 0320 a156 +--- 788,705,14 3 0321 a157 +--- 788,705,14 3 0322 a158 +--- 788,705,14 3 0323 a159 +--- 894,634 3 0324 a160 +--- 838,540 3 0325 a161 +--- 1016,540 3 0326 a163 +--- 458,820,127 3 0327 a164 +--- 748,597 3 0330 a196 +--- 924,552 3 0331 a165 +--- 748,597 3 0332 a192 +--- 918,526 3 0333 a166 +--- 927,660 3 0334 a167 +--- 928,562 3 0335 a168 +--- 928,563 3 0336 a169 +--- 834,537 3 0337 a170 +--- 873,599 3 0340 a171 +--- 828,588 3 0341 a172 +--- 924,594 3 0342 a173 +--- 924,594 3 0343 a162 +--- 917,692 3 0344 a174 +--- 930,608 3 0345 a175 +--- 931,608 3 0346 a176 +--- 463,791,99 3 0347 a177 +--- 883,623 3 0350 a178 +--- 836,648 3 0351 a179 +--- 836,648 3 0352 a193 +--- 867,591 3 0353 a180 +--- 867,591 3 0354 a199 +--- 696,648 3 0355 a181 +--- 696,648 3 0356 a200 +--- 874,619 3 0357 a182 +--- 874,615 3 0361 a201 +--- 760,692 3 0362 a183 +--- 946,533 3 0363 a184 +--- 771,655 3 0364 a197 +--- 865,481 3 0365 a185 +--- 771,655 3 0366 a194 +--- 888,712,19 3 0367 a198 +--- 967,568 3 0370 a186 +--- 888,712,19 3 0371 a195 +--- 831,579 3 0372 a187 +--- 873,578 3 0373 a188 +--- 927,542 3 0374 a189 +--- 970,616 3 0375 a190 +--- 918,593 3 0376 a191 diff --git a/gnu/usr.bin/groff/devices/devps/ZDR b/gnu/usr.bin/groff/devices/devps/ZDR new file mode 100644 index 0000000000..3b7f0a64cd --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/ZDR @@ -0,0 +1,193 @@ +name ZDR +internalname ZapfDingbats-Reverse +special +spacewidth 278 +charset +space 278 0 0040 +--- 974,621 3 0041 a1 +--- 961,611 3 0042 a2 +--- 974,621 3 0043 a202 +--- 980,692 3 0044 a3 +--- 719,566 3 0045 a4 +--- 789,705,14 3 0046 a5 +--- 790,705,14 3 0047 a119 +--- 791,705,13 3 0050 a118 +--- 690,553 3 0051 a117 +--- 960,568 3 0052 a11 +lh 939,559 3 0053 a12 +--- 549,705,11 3 0054 a13 +--- 855,632 3 0055 a14 +--- 911,642 3 0056 a15 +--- 933,550 3 0057 a16 +--- 911,642 3 0060 a105 +--- 945,553 3 0061 a17 +--- 974,587 3 0062 a18 +--- 755,705,13 3 0063 a19 +--- 846,705,14 3 0064 a20 +--- 762,692 3 0065 a21 +--- 761,692 3 0066 a22 +--- 571,661,68 3 0067 a23 +--- 677,705,13 3 0070 a24 +--- 763,692 3 0071 a25 +--- 760,692 3 0072 a26 +--- 759,692 3 0073 a27 +--- 754,692 3 0074 a28 +--- 494,692 3 0075 a6 +--- 552,692 3 0076 a7 +--- 537,692 3 0077 a8 +--- 577,596 3 0100 a9 +--- 692,705,14 3 0101 a10 +--- 786,705,14 3 0102 a29 +--- 788,705,14 3 0103 a30 +--- 788,705,14 3 0104 a31 +--- 790,705,14 3 0105 a32 +--- 793,705,13 3 0106 a33 +--- 794,705,13 3 0107 a34 +--- 816,705,14 3 0110 a35 +--- 823,705,14 3 0111 a36 +--- 789,705,14 3 0112 a37 +--- 841,705,14 3 0113 a38 +--- 823,705,14 3 0114 a39 +--- 833,705,14 3 0115 a40 +--- 816,705,13 3 0116 a41 +--- 831,705,14 3 0117 a42 +--- 923,705,14 3 0120 a43 +--- 744,692 3 0121 a44 +--- 723,692 3 0122 a45 +--- 749,692 3 0123 a46 +--- 790,705,14 3 0124 a47 +--- 792,705,14 3 0125 a48 +--- 695,706,14 3 0126 a49 +--- 776,699,6 3 0127 a50 +--- 768,699,7 3 0130 a51 +--- 792,705,14 3 0131 a52 +--- 759,692 3 0132 a53 +--- 707,704,13 3 0133 a54 +--- 708,705,14 3 0134 a55 +--- 682,705,14 3 0135 a56 +--- 701,705,14 3 0136 a57 +--- 826,705,14 3 0137 a58 +--- 815,705,14 3 0140 a59 +--- 789,705,14 3 0141 a60 +--- 789,705,14 3 0142 a61 +--- 707,705,14 3 0143 a62 +--- 687,692 3 0144 a63 +--- 696,691 3 0145 a64 +--- 689,692 3 0146 a65 +--- 786,705,14 3 0147 a66 +--- 787,705,14 3 0150 a67 +--- 713,705,14 3 0151 a68 +--- 791,705,14 3 0152 a69 +--- 785,705,14 3 0153 a70 +--- 791,705,14 3 0154 a71 +--- 873,705,14 3 0155 a72 +--- 761,692 3 0156 a73 +--- 762,692 3 0157 a74 +--- 762,692 3 0160 a203 +--- 759,692 3 0161 a75 +--- 759,692 3 0162 a204 +--- 892,705 3 0163 a76 +--- 892,692,14 3 0164 a77 +--- 788,705,14 3 0165 a78 +--- 784,705,14 3 0166 a79 +--- 438,705,14 3 0167 a81 +--- 138,692 3 0170 a82 +--- 277,692 3 0171 a83 +--- 415,692 3 0172 a84 +--- 392,705 3 0173 a97 +--- 392,705 3 0174 a98 +--- 668,705 3 0175 a99 +--- 668,705 3 0176 a100 +--- 732,806,143 3 0241 a101 +--- 544,706,14 3 0242 a102 +--- 544,705,14 3 0243 a103 +--- 910,651 3 0244 a104 +--- 667,705,14 3 0245 a106 +--- 760,705,14 3 0246 a107 +--- 760,569 3 0247 a108 +--- 776,705 3 0250 a112 +--- 595,705,14 3 0251 a111 +--- 694,705,14 3 0252 a110 +--- 626,705 3 0253 a109 +--- 788,705,14 3 0254 a120 +--- 788,705,14 3 0255 a121 +--- 788,705,14 3 0256 a122 +--- 788,705,14 3 0257 a123 +--- 788,705,14 3 0260 a124 +--- 788,705,14 3 0261 a125 +--- 788,705,14 3 0262 a126 +--- 788,705,14 3 0263 a127 +--- 788,705,14 3 0264 a128 +--- 788,705,14 3 0265 a129 +--- 788,705,14 3 0266 a130 +--- 788,705,14 3 0267 a131 +--- 788,705,14 3 0270 a132 +--- 788,705,14 3 0271 a133 +--- 788,705,14 3 0272 a134 +--- 788,705,14 3 0273 a135 +--- 788,705,14 3 0274 a136 +--- 788,705,14 3 0275 a137 +--- 788,705,14 3 0276 a138 +--- 788,705,14 3 0277 a139 +--- 788,705,14 3 0300 a140 +--- 788,705,14 3 0301 a141 +--- 788,705,14 3 0302 a142 +--- 788,705,14 3 0303 a143 +--- 788,705,14 3 0304 a144 +--- 788,705,14 3 0305 a145 +--- 788,705,14 3 0306 a146 +--- 788,705,14 3 0307 a147 +--- 788,705,14 3 0310 a148 +--- 788,705,14 3 0311 a149 +--- 788,705,14 3 0312 a150 +--- 788,705,14 3 0313 a151 +--- 788,705,14 3 0314 a152 +--- 788,705,14 3 0315 a153 +--- 788,705,14 3 0316 a154 +--- 788,705,14 3 0317 a155 +--- 788,705,14 3 0320 a156 +--- 788,705,14 3 0321 a157 +--- 788,705,14 3 0322 a158 +--- 788,705,14 3 0323 a159 +--- 894,634 3 0324 a160 +--- 838,540 3 0325 a161 +--- 1016,540 3 0326 a163 +--- 458,820,127 3 0327 a164 +--- 748,597 3 0330 a196 +--- 924,552 3 0331 a165 +--- 748,597 3 0332 a192 +--- 918,526 3 0333 a166 +--- 927,660 3 0334 a167 +--- 928,562 3 0335 a168 +--- 928,563 3 0336 a169 +--- 834,537 3 0337 a170 +--- 873,599 3 0340 a171 +--- 828,588 3 0341 a172 +--- 924,594 3 0342 a173 +--- 924,594 3 0343 a162 +--- 917,692 3 0344 a174 +--- 930,608 3 0345 a175 +--- 931,608 3 0346 a176 +--- 463,791,99 3 0347 a177 +--- 883,623 3 0350 a178 +--- 836,648 3 0351 a179 +--- 836,648 3 0352 a193 +--- 867,591 3 0353 a180 +--- 867,591 3 0354 a199 +--- 696,648 3 0355 a181 +--- 696,648 3 0356 a200 +--- 874,619 3 0357 a182 +--- 874,615 3 0361 a201 +--- 760,692 3 0362 a183 +--- 946,533 3 0363 a184 +--- 771,655 3 0364 a197 +--- 865,481 3 0365 a185 +--- 771,655 3 0366 a194 +--- 888,712,19 3 0367 a198 +--- 967,568 3 0370 a186 +--- 888,712,19 3 0371 a195 +--- 831,579 3 0372 a187 +--- 873,578 3 0373 a188 +--- 927,542 3 0374 a189 +--- 970,616 3 0375 a190 +--- 918,593 3 0376 a191 diff --git a/gnu/usr.bin/groff/devices/devps/download b/gnu/usr.bin/groff/devices/devps/download new file mode 100644 index 0000000000..b98885cdbb --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/download @@ -0,0 +1,5 @@ +# List of downloadable fonts +# PostScript-name Filename + +Symbol-Slanted symbolsl.pfa +ZapfDingbats-Reverse zapfdr.pfa diff --git a/gnu/usr.bin/groff/devices/devps/generate/Makefile b/gnu/usr.bin/groff/devices/devps/generate/Makefile new file mode 100644 index 0000000000..3382cc60a9 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/generate/Makefile @@ -0,0 +1,224 @@ +#Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. +# Written by James Clark (jjc@jclark.com) +# +#This file is part of groff. +# +#groff is free software; you can redistribute it and/or modify it under +#the terms of the GNU General Public License as published by the Free +#Software Foundation; either version 2, or (at your option) any later +#version. +# +#groff is distributed in the hope that it will be useful, but WITHOUT ANY +#WARRANTY; without even the implied warranty of MERCHANTABILITY or +#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +#for more details. +# +#You should have received a copy of the GNU General Public License along +#with groff; see the file COPYING. If not, write to the Free Software +#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# This is set up so you can do +# make -f generate/Makefile +# in the parent directory of this directory. + +# Directory containing AFM files. Must not be current directory. +# Either long names (eg Times-Roman.afm) or short names (eg timesr.afm) +# may be used. See the afmname script. +afmdir=/usr/local/afm +srcdir=generate + +SPECIALFONTS=S +DINGBATSFONTS=ZD ZDR +GREEKFONTS=SS +TEXTFONTS=AB ABI AI AR BMB BMBI BMI BMR CB CBI CI CR HB HBI HI HR HNB HNBI \ + HNI HNR NB NBI NI NR PB PBI PI PR TB TBI TI TR ZCMI + +FONTS=$(TEXTFONTS) $(SPECIALFONTS) $(GREEKFONTS) $(DINGBATSFONTS) + +DESC=$(srcdir)/../DESC +AFMTODIT=afmtodit -d$(DESC) +IFLAG=-i 50 +NOLIGFLAG=-n +TEXTENC=$(srcdir)/../text.enc +EFLAG=-e $(TEXTENC) +TEXTMAP=$(srcdir)/textmap +SHELL=/bin/sh +AFMNAME=$(SHELL) $(srcdir)/afmname + +all: $(FONTS) + +TR: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Times-Roman.afm` $(TEXTMAP) $@ + +TB: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Times-Bold.afm` $(TEXTMAP) $@ + +TI: + $(AFMTODIT) $(EFLAG) $(IFLAG) -a 7 \ + `$(AFMNAME) $(afmdir)/Times-Italic.afm` $(TEXTMAP) $@ + +TBI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Times-BoldItalic.afm` $(TEXTMAP) $@ + +HR: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Helvetica.afm` $(TEXTMAP) $@ + +HB: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Helvetica-Bold.afm` $(TEXTMAP) $@ + +HI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Helvetica-Oblique.afm` $(TEXTMAP) $@ + +HBI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Helvetica-BoldOblique.afm` $(TEXTMAP) $@ + +CR: + $(AFMTODIT) $(NOLIGFLAG) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Courier.afm` $(TEXTMAP) $@ + +CB: + $(AFMTODIT) $(NOLIGFLAG) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Courier-Bold.afm` $(TEXTMAP) $@ + +CI: + $(AFMTODIT) $(NOLIGFLAG) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Courier-Oblique.afm` $(TEXTMAP) $@ + +CBI: + $(AFMTODIT) $(NOLIGFLAG) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Courier-BoldOblique.afm` $(TEXTMAP) $@ + +PR: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Palatino-Roman.afm` $(TEXTMAP) $@ + +PB: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Palatino-Bold.afm` $(TEXTMAP) $@ + +PI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Palatino-Italic.afm` $(TEXTMAP) $@ + +PBI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Palatino-BoldItalic.afm` $(TEXTMAP) $@ + +NR: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/NewCenturySchlbk-Roman.afm` $(TEXTMAP) $@ + +NB: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/NewCenturySchlbk-Bold.afm` $(TEXTMAP) $@ + +NI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/NewCenturySchlbk-Italic.afm` $(TEXTMAP) $@ + +NBI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/NewCenturySchlbk-BoldItalic.afm` $(TEXTMAP) $@ + +BMR: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Bookman-Light.afm` $(TEXTMAP) $@ + +BMB: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Bookman-Demi.afm` $(TEXTMAP) $@ + +BMI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Bookman-LightItalic.afm` $(TEXTMAP) $@ + +BMBI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Bookman-DemiItalic.afm` $(TEXTMAP) $@ + +AR: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/AvantGarde-Book.afm` $(TEXTMAP) $@ + +AB: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/AvantGarde-Demi.afm` $(TEXTMAP) $@ + +AI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/AvantGarde-BookOblique.afm` $(TEXTMAP) $@ + +ABI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/AvantGarde-DemiOblique.afm` $(TEXTMAP) $@ + +HNR: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Helvetica-Narrow.afm` $(TEXTMAP) $@ + +HNB: + $(AFMTODIT) $(EFLAG) \ + `$(AFMNAME) $(afmdir)/Helvetica-Narrow-Bold.afm` $(TEXTMAP) $@ + +HNI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Helvetica-Narrow-Oblique.afm` $(TEXTMAP) $@ + +HNBI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/Helvetica-Narrow-BoldOblique.afm` $(TEXTMAP) $@ + +ZCMI: + $(AFMTODIT) $(EFLAG) $(IFLAG) \ + `$(AFMNAME) $(afmdir)/ZapfChancery-MediumItalic.afm` $(TEXTMAP) $@ + +ZD: + $(AFMTODIT) -s \ + `$(AFMNAME) $(afmdir)/ZapfDingbats.afm` $(srcdir)/dingbatsmap $@ + +SS: $(srcdir)/symbolsl.afm + $(AFMTODIT) -s $(IFLAG) $(srcdir)/symbolsl.afm $(srcdir)/lgreekmap $@ + +S: symbol.afm + $(AFMTODIT) -s symbol.afm symbolmap $@ + +ZDR: zapfdr.afm + $(AFMTODIT) -s zapfdr.afm $(srcdir)/dingbatsrmap $@ + +symbol.afm: $(srcdir)/symbol.sed + -rm -f $@ + sed -f $(srcdir)/symbol.sed `$(AFMNAME) $(afmdir)/Symbol.afm` >$@ + +zapfdr.afm: + -rm -f $@ + sed -e '/^FontName /s/ZapfDingbats/ZapfDingbats-Reverse/' \ + `$(AFMNAME) $(afmdir)/ZapfDingbats.afm` >$@ + +ZD: $(srcdir)/dingbatsmap +ZDR: $(srcdir)/dingbatsrmap +$(TEXTFONTS): $(TEXTMAP) $(TEXTENC) +$(SPECIALFONTS): symbolmap +$(GREEKFONTS): $(srcdir)/lgreekmap +$(FONTS): $(DESC) + +symbolmap: $(TEXTMAP) $(srcdir)/symbolchars + cat $(TEXTMAP) $(srcdir)/symbolchars >$@ + +clean: + -rm -f symbolmap symbol.afm zapfdr.afm + +realclean: clean + -rm -f $(FONTS) + +extraclean: realclean + -rm -f core *~ \#* + +.PHONY: all clean realclean extraclean + diff --git a/gnu/usr.bin/groff/devices/devps/generate/afmname b/gnu/usr.bin/groff/devices/devps/generate/afmname new file mode 100644 index 0000000000..8503d46d8b --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/generate/afmname @@ -0,0 +1,44 @@ +#!/bin/sh +# Fix the path name of an AFM file. +if test -f "$1" +then + echo "$1" +else + echo `dirname $1`/`basename $1 .afm | awk -e ' +/^AvantGarde-Book$/ { print "avangbk" } +/^AvantGarde-BookOblique$/ { print "avangbko" } +/^AvantGarde-Demi$/ { print "avangd" } +/^AvantGarde-DemiOblique$/ { print "avangdo" } +/^Bookman-Demi$/ { print "bookmd" } +/^Bookman-DemiItalic$/ { print "bookmdi" } +/^Bookman-Light$/ { print "bookml" } +/^Bookman-LightItalic$/ { print "bookmli" } +/^Courier$/ { print "couri" } +/^Courier-Bold$/ { print "courib" } +/^Courier-BoldOblique$/ { print "couribo" } +/^Courier-Oblique$/ { print "courio" } +/^Helvetica$/ { print "helve" } +/^Helvetica-Bold$/ { print "helveb" } +/^Helvetica-BoldOblique$/ { print "helvebo" } +/^Helvetica-Narrow$/ { print "helven" } +/^Helvetica-Narrow-Bold$/ { print "helvenb" } +/^Helvetica-Narrow-BoldOblique$/ { print "helvenbo" } +/^Helvetica-Narrow-Oblique$/ { print "helveno" } +/^Helvetica-Oblique$/ { print "helveo" } +/^NewCenturySchlbk-Bold$/ { print "newcsb" } +/^NewCenturySchlbk-BoldItalic$/ { print "newcsbi" } +/^NewCenturySchlbk-Italic$/ { print "newcsi" } +/^NewCenturySchlbk-Roman$/ { print "newcsr" } +/^Palatino-Bold$/ { print "palatb" } +/^Palatino-BoldItalic$/ { print "palatbi" } +/^Palatino-Italic$/ { print "palati" } +/^Palatino-Roman$/ { print "palatr" } +/^Symbol$/ { print "symbol" } +/^Times-Bold$/ { print "timesb" } +/^Times-BoldItalic$/ { print "timesbi" } +/^Times-Italic$/ { print "timesi" } +/^Times-Roman$/ { print "timesr" } +/^ZapfChancery-MediumItalic$/ { print "zapfcmi" } +/^ZapfDingbats$/ { print "zapfd" } +' `.afm +fi diff --git a/gnu/usr.bin/groff/devices/devps/generate/dingbatsmap b/gnu/usr.bin/groff/devices/devps/generate/dingbatsmap new file mode 100644 index 0000000000..3a97fa99b0 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/generate/dingbatsmap @@ -0,0 +1,2 @@ +a19 OK +a12 rh diff --git a/gnu/usr.bin/groff/devices/devps/generate/dingbatsrmap b/gnu/usr.bin/groff/devices/devps/generate/dingbatsrmap new file mode 100644 index 0000000000..ccc14cb2df --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/generate/dingbatsrmap @@ -0,0 +1 @@ +a12 lh diff --git a/gnu/usr.bin/groff/devices/devps/generate/lgreekmap b/gnu/usr.bin/groff/devices/devps/generate/lgreekmap new file mode 100644 index 0000000000..0b0c197808 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/generate/lgreekmap @@ -0,0 +1,28 @@ +alpha *a +beta *b +chi *x +delta *d +epsilon *e +eta *y +gamma *g +iota *i +kappa *k +lambda *l +mu *m +nu *n +omega *w +omega1 +p +omicron *o +phi *f +phi1 +f +pi *p +psi *q +rho *r +sigma *s +tau *t +theta *h +theta1 +h +upsilon *u +xi *c +zeta *z +sigma1 ts diff --git a/gnu/usr.bin/groff/devices/devps/generate/symbol.sed b/gnu/usr.bin/groff/devices/devps/generate/symbol.sed new file mode 100644 index 0000000000..b4b02aba6a --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/generate/symbol.sed @@ -0,0 +1,33 @@ +#! /bin/sed -f +# Tweak the AFM file for the Symbol font. +/^C .*[ ;]N bracketlefttp[ ;]/bx +/^C .*[ ;]N bracketleftex[ ;]/bx +/^C .*[ ;]N bracketleftbt[ ;]/bx +/^C .*[ ;]N bracketrighttp[ ;]/bx +/^C .*[ ;]N bracketrightex[ ;]/bx +/^C .*[ ;]N bracketrightbt[ ;]/bx +/^C .*[ ;]N bracelefttp[ ;]/bx +/^C .*[ ;]N braceleftmid[ ;]/bx +/^C .*[ ;]N braceleftbt[ ;]/bx +/^C .*[ ;]N bracerighttp[ ;]/bx +/^C .*[ ;]N bracerightmid[ ;]/bx +/^C .*[ ;]N bracerightbt[ ;]/bx +/^C .*[ ;]N braceex[ ;]/bx +/^C .*[ ;]N parenleftex[ ;]/by +/^C .*[ ;]N parenrightex[ ;]/by +/^C .*[ ;]N parenleftbt[ ;]/bz +/^C .*[ ;]N parenrightbt[ ;]/bz +/^EndCharMetrics/a\ +italicCorrection integral 67\ +leftItalicCorrection integral 52\ +subscriptCorrection integral -10 +b +:x +s/B \([-0-9][0-9]*\) [-0-9][0-9]* \([-0-9][0-9]*\) [-0-9][0-9]*/B \1 -75 \2 925/ +b +:y +s/B \([-0-9][0-9]*\) [-0-9][0-9]* \([-0-9][0-9]*\) [-0-9][0-9]*/B \1 -80 \2 920/ +b +:z +s/B \([-0-9][0-9]*\) \([-0-9][0-9]*\) \([-0-9][0-9]*\) [-0-9][0-9]*/B \1 \2 \3 920/ +b diff --git a/gnu/usr.bin/groff/devices/devps/generate/symbolchars b/gnu/usr.bin/groff/devices/devps/generate/symbolchars new file mode 100644 index 0000000000..41ec3e4663 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/generate/symbolchars @@ -0,0 +1,60 @@ +plus pl +minus mi +plusminus +- +equal eq +divide di +multiply mu +arrowup arrowverttp +arrowdown arrowvertbt +Alpha *A +Beta *B +Chi *X +Delta *D +Epsilon *E +Eta *Y +Gamma *G +Iota *I +Kappa *K +Lambda *L +Mu *M +Nu *N +Omega *W +Omicron *O +Phi *F +Pi *P +Psi *Q +Rho *R +Sigma *S +Tau *T +Theta *H +Upsilon1 *U +Xi *C +Zeta *Z +alpha *a +beta *b +chi *x +delta *d +epsilon *e +eta *y +gamma *g +iota *i +kappa *k +lambda *l +mu *m +nu *n +omega *w +omega1 +p +omicron *o +phi *f +phi1 +f +pi *p +psi *q +rho *r +sigma *s +sigma1 ts +tau *t +theta *h +theta1 +h +upsilon *u +xi *c +zeta *z diff --git a/gnu/usr.bin/groff/devices/devps/generate/symbolsl.afm b/gnu/usr.bin/groff/devices/devps/generate/symbolsl.afm new file mode 100644 index 0000000000..90939ada96 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/generate/symbolsl.afm @@ -0,0 +1,203 @@ +StartFontMetrics 2.0 +FontName Symbol-Slanted +Version 001.001 +FamilyName Symbol +ItalicAngle -15.5 +IsFixedPitch false +UnderlineThickness 54 +Weight Medium +UnderlinePosition -98 +FullName Symbol +FontBBox -241 -261 1250 899 +StartCharMetrics 189 +C 32 ; WX 223 ; N space ; B 223 0 223 0 ; +C 33 ; WX 296 ; N exclam ; B 122 -15 383 599 ; +C 34 ; WX 635 ; N universal ; B 223 0 801 627 ; +C 35 ; WX 445 ; N numbersign ; B 71 -15 557 599 ; +C 36 ; WX 489 ; N existential ; B 22 0 622 629 ; +C 37 ; WX 741 ; N percent ; B 147 -32 766 583 ; +C 38 ; WX 692 ; N ampersand ; B 68 -16 745 589 ; +C 39 ; WX 391 ; N suchthat ; B 44 -15 450 444 ; +C 40 ; WX 296 ; N parenleft ; B 89 -170 449 599 ; +C 41 ; WX 296 ; N parenright ; B -22 -170 339 600 ; +C 42 ; WX 445 ; N asteriskmath ; B 126 119 500 490 ; +C 43 ; WX 489 ; N plus ; B 76 0 562 474 ; +C 44 ; WX 223 ; N comma ; B 9 -136 183 93 ; +C 45 ; WX 489 ; N minus ; B 74 207 556 256 ; +C 46 ; WX 223 ; N period ; B 70 -15 174 85 ; +C 47 ; WX 247 ; N slash ; B -5 -15 405 575 ; +C 48 ; WX 445 ; N zero ; B 90 -15 537 610 ; +C 49 ; WX 445 ; N one ; B 107 0 451 599 ; +C 50 ; WX 445 ; N two ; B 22 0 524 611 ; +C 51 ; WX 445 ; N three ; B 56 -16 510 611 ; +C 52 ; WX 445 ; N four ; B 58 0 530 610 ; +C 53 ; WX 445 ; N five ; B 36 -15 583 610 ; +C 54 ; WX 445 ; N six ; B 87 -16 588 610 ; +C 55 ; WX 445 ; N seven ; B 151 -15 585 599 ; +C 56 ; WX 445 ; N eight ; B 82 -16 536 611 ; +C 57 ; WX 445 ; N nine ; B 52 -15 535 609 ; +C 58 ; WX 247 ; N colon ; B 81 -15 286 409 ; +C 59 ; WX 247 ; N semicolon ; B 33 -136 296 409 ; +C 60 ; WX 489 ; N less ; B 87 0 610 464 ; +C 61 ; WX 489 ; N equal ; B 49 126 586 347 ; +C 62 ; WX 489 ; N greater ; B 23 0 547 464 ; +C 63 ; WX 395 ; N question ; B 163 -15 517 610 ; +C 64 ; WX 489 ; N congruent ; B 10 0 597 423 ; +C 65 ; WX 643 ; N Alpha ; B 3 0 614 599 ; +C 66 ; WX 594 ; N Beta ; B 26 0 645 598 ; +C 67 ; WX 643 ; N Chi ; B -8 0 798 599 ; +C 68 ; WX 545 ; N Delta ; B 5 0 541 612 ; +C 69 ; WX 544 ; N Epsilon ; B 28 0 688 599 ; +C 70 ; WX 679 ; N Phi ; B 105 0 761 598 ; +C 71 ; WX 537 ; N Gamma ; B 31 0 714 599 ; +C 72 ; WX 643 ; N Eta ; B 35 0 836 599 ; +C 73 ; WX 296 ; N Iota ; B 28 0 468 599 ; +C 74 ; WX 562 ; N theta1 ; B 108 -15 645 614 ; +C 75 ; WX 643 ; N Kappa ; B 31 0 778 598 ; +C 76 ; WX 611 ; N Lambda ; B 5 0 610 612 ; +C 77 ; WX 791 ; N Mu ; B 28 0 974 599 ; +C 78 ; WX 643 ; N Nu ; B 26 -7 827 599 ; +C 79 ; WX 643 ; N Omicron ; B 112 -15 747 610 ; +C 80 ; WX 684 ; N Pi ; B 22 0 847 599 ; +C 81 ; WX 659 ; N Theta ; B 112 -15 747 610 ; +C 82 ; WX 495 ; N Rho ; B 25 0 645 599 ; +C 83 ; WX 527 ; N Sigma ; B 5 0 663 599 ; +C 84 ; WX 544 ; N Tau ; B 159 0 723 599 ; +C 85 ; WX 614 ; N Upsilon ; B 175 0 804 599 ; +C 86 ; WX 391 ; N sigma1 ; B 78 -208 492 445 ; +C 87 ; WX 684 ; N Omega ; B 30 0 760 612 ; +C 88 ; WX 574 ; N Xi ; B 36 0 700 598 ; +C 89 ; WX 708 ; N Psi ; B 188 0 885 608 ; +C 90 ; WX 544 ; N Zeta ; B 39 0 725 599 ; +C 91 ; WX 296 ; N bracketleft ; B 34 -138 453 599 ; +C 92 ; WX 768 ; N therefore ; B 160 0 645 426 ; +C 93 ; WX 296 ; N bracketright ; B -14 -138 405 599 ; +C 94 ; WX 586 ; N perpendicular ; B 13 0 596 600 ; +C 95 ; WX 445 ; N underscore ; B -72 -224 390 -183 ; +C 96 ; WX 445 ; N radicalex ; B 672 784 1224 816 ; +C 97 ; WX 562 ; N alpha ; B 84 -15 658 445 ; +C 98 ; WX 489 ; N beta ; B -7 -198 578 659 ; +C 99 ; WX 489 ; N chi ; B -48 -206 573 445 ; +C 100 ; WX 440 ; N delta ; B 83 -16 571 658 ; +C 101 ; WX 391 ; N epsilon ; B 49 -17 468 447 ; +C 102 ; WX 464 ; N phi ; B 78 -200 517 596 ; +C 103 ; WX 366 ; N gamma ; B 92 -200 568 444 ; +C 104 ; WX 537 ; N eta ; B 100 -180 555 457 ; +C 105 ; WX 293 ; N iota ; B 97 -16 296 448 ; +C 106 ; WX 537 ; N phi1 ; B 92 -199 604 444 ; +C 107 ; WX 489 ; N kappa ; B 106 0 621 447 ; +C 108 ; WX 489 ; N lambda ; B 21 -16 530 658 ; +C 109 ; WX 513 ; N mu ; B -18 -198 533 445 ; +C 110 ; WX 464 ; N nu ; B 119 -15 548 451 ; +C 111 ; WX 489 ; N omicron ; B 86 -17 526 444 ; +C 112 ; WX 489 ; N pi ; B 58 -18 599 433 ; +C 113 ; WX 464 ; N theta ; B 103 -16 554 614 ; +C 114 ; WX 489 ; N rho ; B -19 -205 521 444 ; +C 115 ; WX 537 ; N sigma ; B 87 -19 662 445 ; +C 116 ; WX 391 ; N tau ; B 95 -16 511 445 ; +C 117 ; WX 513 ; N upsilon ; B 105 -15 558 451 ; +C 118 ; WX 635 ; N omega1 ; B 78 -15 758 519 ; +C 119 ; WX 611 ; N omega ; B 85 -16 687 445 ; +C 120 ; WX 439 ; N xi ; B 70 -200 515 681 ; +C 121 ; WX 611 ; N psi ; B 141 -203 759 445 ; +C 122 ; WX 440 ; N zeta ; B 100 -200 580 673 ; +C 123 ; WX 427 ; N braceleft ; B 116 -163 540 599 ; +C 124 ; WX 178 ; N bar ; B 9 -158 307 599 ; +C 125 ; WX 427 ; N braceright ; B 19 -163 444 599 ; +C 126 ; WX 489 ; N similar ; B 78 181 549 273 ; +C 161 ; WX 552 ; N Upsilon1 ; B 134 0 710 609 ; +C 162 ; WX 220 ; N minute ; B 156 408 393 654 ; +C 163 ; WX 489 ; N lessequal ; B 26 0 645 569 ; +C 164 ; WX 149 ; N fraction ; B -164 -11 490 603 ; +C 165 ; WX 635 ; N infinity ; B 91 111 692 360 ; +C 166 ; WX 445 ; N florin ; B -36 -172 614 612 ; +C 167 ; WX 670 ; N club ; B 119 -23 645 474 ; +C 168 ; WX 670 ; N diamond ; B 198 -32 605 490 ; +C 169 ; WX 670 ; N heart ; B 205 -29 679 473 ; +C 170 ; WX 670 ; N spade ; B 132 -32 604 488 ; +C 171 ; WX 927 ; N arrowboth ; B 90 -13 980 455 ; +C 172 ; WX 878 ; N arrowleft ; B 97 -13 915 455 ; +C 173 ; WX 537 ; N arrowup ; B 223 0 691 810 ; +C 174 ; WX 878 ; N arrowright ; B 105 -13 922 455 ; +C 175 ; WX 537 ; N arrowdown ; B 104 -20 572 790 ; +C 176 ; WX 356 ; N degree ; B 187 343 466 609 ; +C 177 ; WX 489 ; N plusminus ; B 9 0 593 574 ; +C 178 ; WX 366 ; N second ; B 150 408 560 656 ; +C 179 ; WX 489 ; N greaterequal ; B 26 0 582 569 ; +C 180 ; WX 489 ; N multiply ; B 28 7 609 466 ; +C 181 ; WX 635 ; N proportional ; B 90 110 667 360 ; +C 182 ; WX 440 ; N partialdiff ; B 62 -18 542 664 ; +C 183 ; WX 409 ; N bullet ; B 118 101 454 421 ; +C 184 ; WX 489 ; N divide ; B 74 63 558 406 ; +C 185 ; WX 489 ; N notequal ; B 51 -22 587 489 ; +C 186 ; WX 489 ; N equivalence ; B 35 73 602 394 ; +C 187 ; WX 489 ; N approxequal ; B 57 120 572 351 ; +C 188 ; WX 890 ; N ellipsis ; B 107 -15 804 85 ; +C 189 ; WX 537 ; N arrowvertex ; B 216 -107 579 899 ; +C 190 ; WX 890 ; N arrowhorizex ; B 8 196 1011 246 ; +C 191 ; WX 586 ; N carriagereturn ; B 40 -14 710 560 ; +C 192 ; WX 732 ; N aleph ; B 159 -16 740 586 ; +C 193 ; WX 611 ; N Ifraktur ; B 26 -47 684 659 ; +C 194 ; WX 708 ; N Rfraktur ; B 71 -13 833 653 ; +C 195 ; WX 878 ; N weierstrass ; B 112 -188 878 510 ; +C 196 ; WX 684 ; N circlemultiply ; B 114 -15 758 599 ; +C 197 ; WX 684 ; N circleplus ; B 115 -13 759 601 ; +C 198 ; WX 732 ; N emptyset ; B 38 -21 884 640 ; +C 199 ; WX 684 ; N intersection ; B 36 0 714 453 ; +C 200 ; WX 684 ; N union ; B 110 -15 788 438 ; +C 201 ; WX 635 ; N propersuperset ; B 18 0 675 418 ; +C 202 ; WX 635 ; N reflexsuperset ; B -17 -111 674 418 ; +C 203 ; WX 635 ; N notsubset ; B 87 -62 744 481 ; +C 204 ; WX 635 ; N propersubset ; B 87 0 744 418 ; +C 205 ; WX 635 ; N reflexsubset ; B 16 -111 744 418 ; +C 206 ; WX 635 ; N element ; B 93 0 579 417 ; +C 207 ; WX 635 ; N notelement ; B 74 -52 579 494 ; +C 208 ; WX 684 ; N angle ; B 23 0 833 599 ; +C 209 ; WX 635 ; N gradient ; B 231 -17 805 639 ; +C 210 ; WX 703 ; N registerserif ; B 120 -18 763 596 ; +C 211 ; WX 703 ; N copyrightserif ; B 122 -13 766 601 ; +C 212 ; WX 792 ; N trademarkserif ; B 169 261 947 599 ; +C 213 ; WX 732 ; N product ; B -6 -90 920 668 ; +C 214 ; WX 489 ; N radical ; B 134 -34 711 816 ; +C 215 ; WX 223 ; N dotmath ; B 131 187 225 276 ; +C 216 ; WX 635 ; N logicalnot ; B 78 0 685 256 ; +C 217 ; WX 537 ; N logicaland ; B 21 0 519 404 ; +C 218 ; WX 537 ; N logicalor ; B 151 0 639 424 ; +C 219 ; WX 927 ; N arrowdblboth ; B 92 -18 978 454 ; +C 220 ; WX 878 ; N arrowdblleft ; B 96 -13 942 457 ; +C 221 ; WX 537 ; N arrowdblup ; B 152 2 688 811 ; +C 222 ; WX 878 ; N arrowdblright ; B 71 -18 917 452 ; +C 223 ; WX 537 ; N arrowdbldown ; B 103 -17 639 792 ; +C 224 ; WX 440 ; N lozenge ; B 121 0 519 663 ; +C 225 ; WX 293 ; N angleleft ; B 98 -176 472 664 ; +C 226 ; WX 703 ; N registersans ; B 120 -18 763 596 ; +C 227 ; WX 703 ; N copyrightsans ; B 120 -13 764 601 ; +C 228 ; WX 700 ; N trademarksans ; B 179 261 832 599 ; +C 229 ; WX 635 ; N summation ; B -15 -96 756 669 ; +C 230 ; WX 342 ; N parenlefttp ; B -46 -261 642 824 ; +C 231 ; WX 342 ; N parenleftex ; B 12 -76 338 823 ; +C 232 ; WX 342 ; N parenleftbt ; B 113 -261 339 824 ; +C 233 ; WX 342 ; N bracketlefttp ; B -22 -71 560 824 ; +C 234 ; WX 342 ; N bracketleftex ; B -22 -70 305 823 ; +C 235 ; WX 342 ; N bracketleftbt ; B -22 -71 306 824 ; +C 236 ; WX 440 ; N bracelefttp ; B 158 -67 648 824 ; +C 237 ; WX 440 ; N braceleftmid ; B 126 -76 486 832 ; +C 238 ; WX 440 ; N braceleftbt ; B 219 -62 484 824 ; +C 239 ; WX 440 ; N braceex ; B 157 -71 486 832 ; +C 241 ; WX 293 ; N angleright ; B -29 -176 345 664 ; +C 242 ; WX 244 ; N integral ; B -13 -95 499 815 ; +C 243 ; WX 611 ; N integraltp ; B 272 -74 873 820 ; +C 244 ; WX 611 ; N integralex ; B 271 -78 640 868 ; +C 245 ; WX 611 ; N integralbt ; B 30 -72 625 820 ; +C 246 ; WX 342 ; N parenrighttp ; B 273 -261 498 824 ; +C 247 ; WX 342 ; N parenrightex ; B 331 -76 657 823 ; +C 248 ; WX 342 ; N parenrightbt ; B -30 -261 657 824 ; +C 249 ; WX 342 ; N bracketrighttp ; B 249 -71 577 824 ; +C 250 ; WX 342 ; N bracketrightex ; B 250 -70 577 823 ; +C 251 ; WX 342 ; N bracketrightbt ; B -4 -71 577 824 ; +C 252 ; WX 440 ; N bracerighttp ; B 158 -67 425 824 ; +C 253 ; WX 440 ; N bracerightmid ; B 155 -76 517 832 ; +C 254 ; WX 440 ; N bracerightbt ; B -4 -62 484 824 ; +C -1 ; WX 703 ; N apple ; B 136 -2 784 719 ; +EndCharMetrics +EndFontMetrics diff --git a/gnu/usr.bin/groff/devices/devps/generate/textmap b/gnu/usr.bin/groff/devices/devps/generate/textmap new file mode 100644 index 0000000000..9001d3657e --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/generate/textmap @@ -0,0 +1,449 @@ +a a +b b +c c +d d +e e +f f +g g +h h +i i +j j +k k +l l +m m +n n +o o +p p +q q +r r +s s +t t +u u +v v +w w +x x +y y +z z +A A +B B +C C +D D +E E +F F +G G +H H +I I +J J +K K +L L +M M +N N +O O +P P +Q Q +R R +S S +T T +U U +V V +W W +X X +Y Y +Z Z +AE AE +Aacute 'A +Acircumflex ^A +Adieresis :A +Agrave `A +Aring oA +Atilde ~A +Cacute 'C +Ccedilla ,C +Eacute 'E +Ecircumflex ^E +Edieresis :E +Egrave `E +Eth -D +IJ IJ +Iacute 'I +Icircumflex ^I +Idieresis :I +Ifraktur Im +Igrave `I +Lslash /L +Ntilde ~N +OE OE +Oacute 'O +Ocircumflex ^O +Odieresis :O +Ograve `O +Oslash /O +Otilde ~O +Rfraktur Re +Scaron vS +Thorn TP +Uacute 'U +Ucircumflex ^U +Udieresis :U +Ugrave `U +Yacute 'Y +Ydieresis :Y +Zcaron vZ +aacute 'a +acircumflex ^a +acute aa +adieresis :a +ae ae +agrave `a +angle /_ +angleleft la +angleright ra +aleph Ah +ampersand & +approxequal ~~ +aring oa +arrowboth <> +arrowdblboth hA +arrowdbldown dA +arrowdblleft lA +arrowdblright rA +arrowdblup uA +arrowdown da +arrowleft <- +arrowright -> +arrowup ua +asciicircum ha +asciitilde ti +asterisk * +asteriskmath ** +at @ +at at +atilde ~a +backslash \ +backslash rs +bar ba +bar | +bell bs +braceleft lC +braceleft { +braceright rC +braceright } +bracketleft [ +bracketleft lB +bracketright ] +bracketright rB +breve ab +brokenbar bb +bullet bu +cacute 'c +caron ah +ccedilla ,c +cedilla ac +cent ct +checkmark OK +circle ci +circlemultiply c* +circleplus c+ +circumflex a^ +circumflex ^ +colon : +comma , +congruent =~ +copyright co +currency Cs +dagger dg +daggerdbl dd +degree de +dieresis ad +dollar $ +dollar Do +dotaccent a. +dotlessi .i +dotlessj .j +dotmath md +eacute 'e +ecircumflex ^e +edieresis :e +egrave `e +eight 8 +element mo +emdash em +emptyset es +endash en +equal = +equalmath eq +equivalence == +eth Sd +exclam ! +exclamdown r! +existential te +ff ff +ffi Fi +ffl Fl +fi fi +five 5 +fl fl +florin Fn +four 4 +germandbls ss +gradient gr +grave ga +greater > +greaterequal >= +guillemotleft Fo +guillemotright Fc +guilsinglleft fo +guilsinglright fc +handleft lh +handright rh +hbar -h +hungarumlaut a" +hyphen - +hyphen hy +iacute 'i +icircumflex ^i +idieresis :i +igrave `i +ij ij +infinity if +integral is +intersection ca +less < +lessequal <= +logicaland AN +logicalnot no +logicalor OR +lozenge lz +lslash /l +macron a- +minus \- +minusplus -+ +minute fm +nine 9 +notelement nm +notequal != +notequivalence ne +notpropersuperset nc +ntilde ~n +numbersign # +numbersign sh +oacute 'o +ocircumflex ^o +odieresis :o +oe oe +ogonek ho +ograve `o +one 1 +onehalf 12 +onequarter 14 +onesuperior S1 +ordfeminine Of +ordmasculine Om +oslash /o +otilde ~o +paragraph ps +parenleft ( +parenright ) +partialdiff pd +percent % +period . +perthousand %0 +perpendicular pp +plus + +plusmath pl +propersubset sb +propersuperset sp +proportional pt +question ? +questiondown r? +quotedbl " +quotedblbase Bq +quotedblleft lq +quotedblright rq +quoteleft ` +quoteleft oq +quoteright ' +quotesingle aq +quotesinglbase bq +reflexsubset ib +reflexsuperset ip +registered rg +ring ao +scaron vs +second sd +section sc +semicolon ; +seven 7 +similar ap +similarequal ~= +six 6 +slash / +slash sl +square sq +sterling Po +therefore 3d +therefore tf +thorn Tp +three 3 +threequarters 34 +threesuperior S3 +tilde a~ +tilde ~ +trademark tm +two 2 +twosuperior S2 +uacute 'u +ucircumflex ^u +udieresis :u +ugrave `u +underscore _ +union cu +universal fa +weierstrass wp +yacute 'y +ydieresis :y +yen Ye +zcaron vz +zero 0 +exclamdown char161 +cent char162 +sterling char163 +currency char164 +yen char165 +brokenbar char166 +section char167 +dieresis char168 +copyright char169 +ordfeminine char170 +guillemotleft char171 +logicalnot char172 +hyphen char173 +registered char174 +macron char175 +degree char176 +plusminus char177 +twosuperior char178 +threesuperior char179 +acute char180 +mu char181 +paragraph char182 +periodcentered char183 +cedilla char184 +onesuperior char185 +ordmasculine char186 +guillemotright char187 +onequarter char188 +onehalf char189 +threequarters char190 +questiondown char191 +Agrave char192 +Aacute char193 +Acircumflex char194 +Atilde char195 +Adieresis char196 +Aring char197 +AE char198 +Ccedilla char199 +Egrave char200 +Eacute char201 +Ecircumflex char202 +Edieresis char203 +Igrave char204 +Iacute char205 +Icircumflex char206 +Idieresis char207 +Eth char208 +Ntilde char209 +Ograve char210 +Oacute char211 +Ocircumflex char212 +Otilde char213 +Odieresis char214 +multiply char215 +Oslash char216 +Ugrave char217 +Uacute char218 +Ucircumflex char219 +Udieresis char220 +Yacute char221 +Thorn char222 +germandbls char223 +agrave char224 +aacute char225 +acircumflex char226 +atilde char227 +adieresis char228 +aring char229 +ae char230 +ccedilla char231 +egrave char232 +eacute char233 +ecircumflex char234 +edieresis char235 +igrave char236 +iacute char237 +icircumflex char238 +idieresis char239 +eth char240 +ntilde char241 +ograve char242 +oacute char243 +ocircumflex char244 +otilde char245 +odieresis char246 +divide char247 +oslash char248 +ugrave char249 +uacute char250 +ucircumflex char251 +udieresis char252 +yacute char253 +thorn char254 +ydieresis char255 +fraction f/ +club CL +diamond DI +heart HE +spade SP +carriagereturn CR +suchthat st +bracelefttp bracelefttp +braceleftmid braceleftmid +braceleftbt braceleftbt +braceex braceex +braceex bracerightex +braceex braceleftex +braceex barex +bracerighttp bracerighttp +bracerightmid bracerightmid +bracerightbt bracerightbt +parenlefttp parenlefttp +parenleftbt parenleftbt +parenleftex parenleftex +parenrighttp parenrighttp +parenrightbt parenrightbt +parenrightex parenrightex +bracketlefttp bracketlefttp +bracketleftbt bracketleftbt +bracketleftex bracketleftex +bracketrighttp bracketrighttp +bracketrightbt bracketrightbt +bracketrightex bracketrightex +radical sr +radicalex rn +approxequal ~= +bracketlefttp lc +bracketleftbt lf +bracketrighttp rc +bracketrightbt rf +bracelefttp lt +braceleftmid lk +braceleftbt lb +braceex bv +bracerighttp rt +bracerightmid rk +bracerightbt rb +summation sum +product product +arrowvertex arrowvertex +arrowhorizex an diff --git a/gnu/usr.bin/groff/devices/devps/prologue b/gnu/usr.bin/groff/devices/devps/prologue new file mode 100644 index 0000000000..1f984c5067 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/prologue @@ -0,0 +1,152 @@ +%!PS-Adobe-3.0 Resource-ProcSet +/setpacking where{ +pop +currentpacking +true setpacking +}if +/grops 120 dict dup begin +/SC 32 def +/A/show load def +/B{0 SC 3 -1 roll widthshow}bind def +/C{0 exch ashow}bind def +/D{0 exch 0 SC 5 2 roll awidthshow}bind def +/E{0 rmoveto show}bind def +/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def +/G{0 rmoveto 0 exch ashow}bind def +/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/I{0 exch rmoveto show}bind def +/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def +/K{0 exch rmoveto 0 exch ashow}bind def +/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/M{rmoveto show}bind def +/N{rmoveto 0 SC 3 -1 roll widthshow}bind def +/O{rmoveto 0 exch ashow}bind def +/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/Q{moveto show}bind def +/R{moveto 0 SC 3 -1 roll widthshow}bind def +/S{moveto 0 exch ashow}bind def +/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/SF{ +findfont exch +[exch dup 0 exch 0 exch neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/MF{ +findfont +[5 2 roll +0 3 1 roll +neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/level0 0 def +/RES 0 def +/PL 0 def +/LS 0 def +/PLG{ +gsave newpath clippath pathbbox grestore +exch pop add exch pop +}bind def +/BP{ +/level0 save def +1 setlinecap +1 setlinejoin +72 RES div dup scale +LS{ +90 rotate +}{ +0 PL translate +}ifelse +1 -1 scale +}bind def +/EP{ +level0 restore +showpage +}bind def +/DA{ +newpath arcn stroke +}bind def +/SN{ +transform +.25 sub exch .25 sub exch +round .25 add exch round .25 add exch +itransform +}bind def +/DL{ +SN +moveto +SN +lineto stroke +}bind def +/DC{ +newpath 0 360 arc closepath +}bind def +/TM matrix def +/DE{ +TM currentmatrix pop +translate scale newpath 0 0 .5 0 360 arc closepath +TM setmatrix +}bind def +/RC/rcurveto load def +/RL/rlineto load def +/ST/stroke load def +/MT/moveto load def +/CL/closepath load def +/FL{ +currentgray exch setgray fill setgray +}bind def +/BL/fill load def +/LW/setlinewidth load def +/RE{ +findfont +dup maxlength 1 index/FontName known not{1 add}if dict begin +{ +1 index/FID ne{def}{pop pop}ifelse +}forall +/Encoding exch def +dup/FontName exch def +currentdict end definefont pop +}bind def +/DEFS 0 def +/EBEGIN{ +moveto +DEFS begin +}bind def +/EEND/end load def +/CNT 0 def +/level1 0 def +/PBEGIN{ +/level1 save def +translate +div 3 1 roll div exch scale +neg exch neg exch translate +0 setgray +0 setlinecap +1 setlinewidth +0 setlinejoin +10 setmiterlimit +[]0 setdash +/setstrokeadjust where{ +pop +false setstrokeadjust +}if +/setoverprint where{ +pop +false setoverprint +}if +newpath +/CNT countdictstack def +userdict begin +/showpage{}def +}bind def +/PEND{ +clear +countdictstack CNT sub{end}repeat +level1 restore +}bind def +end def +/setpacking where{ +pop +setpacking +}if diff --git a/gnu/usr.bin/groff/devices/devps/symbol.afm b/gnu/usr.bin/groff/devices/devps/symbol.afm new file mode 100644 index 0000000000..eccf6c2aac --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/symbol.afm @@ -0,0 +1,215 @@ +(c) 1987, 1988, 1989, 1990, 1991 Adobe Systems Incorporated. +All rights reserved. + +StartFontMetrics 2.0 +Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved. +Comment Creation Date: Wed Jan 17 21:48:26 1990 +Comment UniqueID 27004 +Comment VMusage 28489 37622 +FontName Symbol +FullName Symbol +FamilyName Symbol +Weight Medium +ItalicAngle 0 +IsFixedPitch false +FontBBox -180 -293 1090 1010 +UnderlinePosition -98 +UnderlineThickness 54 +Version 001.007 +Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved. +EncodingScheme FontSpecific +StartCharMetrics 189 +C 32 ; WX 250 ; N space ; B 0 0 0 0 ; +C 33 ; WX 333 ; N exclam ; B 128 -17 240 672 ; +C 34 ; WX 713 ; N universal ; B 31 0 681 705 ; +C 35 ; WX 500 ; N numbersign ; B 20 -16 481 673 ; +C 36 ; WX 549 ; N existential ; B 25 0 478 707 ; +C 37 ; WX 833 ; N percent ; B 63 -36 771 655 ; +C 38 ; WX 778 ; N ampersand ; B 41 -18 750 661 ; +C 39 ; WX 439 ; N suchthat ; B 48 -17 414 500 ; +C 40 ; WX 333 ; N parenleft ; B 53 -191 300 673 ; +C 41 ; WX 333 ; N parenright ; B 30 -191 277 673 ; +C 42 ; WX 500 ; N asteriskmath ; B 65 134 427 551 ; +C 43 ; WX 549 ; N plus ; B 10 0 539 533 ; +C 44 ; WX 250 ; N comma ; B 56 -152 194 104 ; +C 45 ; WX 549 ; N minus ; B 11 233 535 288 ; +C 46 ; WX 250 ; N period ; B 69 -17 181 95 ; +C 47 ; WX 278 ; N slash ; B 0 -18 254 646 ; +C 48 ; WX 500 ; N zero ; B 23 -17 471 685 ; +C 49 ; WX 500 ; N one ; B 117 0 390 673 ; +C 50 ; WX 500 ; N two ; B 25 0 475 686 ; +C 51 ; WX 500 ; N three ; B 39 -17 435 685 ; +C 52 ; WX 500 ; N four ; B 16 0 469 685 ; +C 53 ; WX 500 ; N five ; B 29 -17 443 685 ; +C 54 ; WX 500 ; N six ; B 36 -17 467 685 ; +C 55 ; WX 500 ; N seven ; B 24 -16 448 673 ; +C 56 ; WX 500 ; N eight ; B 54 -18 440 685 ; +C 57 ; WX 500 ; N nine ; B 31 -18 460 685 ; +C 58 ; WX 278 ; N colon ; B 81 -17 193 460 ; +C 59 ; WX 278 ; N semicolon ; B 83 -152 221 460 ; +C 60 ; WX 549 ; N less ; B 26 0 523 522 ; +C 61 ; WX 549 ; N equal ; B 11 141 537 390 ; +C 62 ; WX 549 ; N greater ; B 26 0 523 522 ; +C 63 ; WX 444 ; N question ; B 70 -17 412 686 ; +C 64 ; WX 549 ; N congruent ; B 11 0 537 475 ; +C 65 ; WX 722 ; N Alpha ; B 4 0 684 673 ; +C 66 ; WX 667 ; N Beta ; B 29 0 592 673 ; +C 67 ; WX 722 ; N Chi ; B -9 0 704 673 ; +C 68 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C 69 ; WX 611 ; N Epsilon ; B 32 0 617 673 ; +C 70 ; WX 763 ; N Phi ; B 26 0 741 673 ; +C 71 ; WX 603 ; N Gamma ; B 24 0 609 673 ; +C 72 ; WX 722 ; N Eta ; B 39 0 729 673 ; +C 73 ; WX 333 ; N Iota ; B 32 0 316 673 ; +C 74 ; WX 631 ; N theta1 ; B 18 -18 623 689 ; +C 75 ; WX 722 ; N Kappa ; B 35 0 722 673 ; +C 76 ; WX 686 ; N Lambda ; B 6 0 680 688 ; +C 77 ; WX 889 ; N Mu ; B 28 0 887 673 ; +C 78 ; WX 722 ; N Nu ; B 29 -8 720 673 ; +C 79 ; WX 722 ; N Omicron ; B 41 -17 715 685 ; +C 80 ; WX 768 ; N Pi ; B 25 0 745 673 ; +C 81 ; WX 741 ; N Theta ; B 41 -17 715 685 ; +C 82 ; WX 556 ; N Rho ; B 28 0 563 673 ; +C 83 ; WX 592 ; N Sigma ; B 5 0 589 673 ; +C 84 ; WX 611 ; N Tau ; B 33 0 607 673 ; +C 85 ; WX 690 ; N Upsilon ; B -8 0 694 673 ; +C 86 ; WX 439 ; N sigma1 ; B 40 -233 436 500 ; +C 87 ; WX 768 ; N Omega ; B 34 0 736 688 ; +C 88 ; WX 645 ; N Xi ; B 40 0 599 673 ; +C 89 ; WX 795 ; N Psi ; B 15 0 781 684 ; +C 90 ; WX 611 ; N Zeta ; B 44 0 636 673 ; +C 91 ; WX 333 ; N bracketleft ; B 86 -155 299 674 ; +C 92 ; WX 863 ; N therefore ; B 163 0 701 478 ; +C 93 ; WX 333 ; N bracketright ; B 33 -155 246 674 ; +C 94 ; WX 658 ; N perpendicular ; B 15 0 652 674 ; +C 95 ; WX 500 ; N underscore ; B -2 -252 502 -206 ; +C 96 ; WX 500 ; N radicalex ; B 480 881 1090 917 ; +C 97 ; WX 631 ; N alpha ; B 41 -18 622 500 ; +C 98 ; WX 549 ; N beta ; B 61 -223 515 741 ; +C 99 ; WX 549 ; N chi ; B 12 -231 522 499 ; +C 100 ; WX 494 ; N delta ; B 40 -19 481 740 ; +C 101 ; WX 439 ; N epsilon ; B 22 -19 427 502 ; +C 102 ; WX 521 ; N phi ; B 27 -224 490 671 ; +C 103 ; WX 411 ; N gamma ; B 5 -225 484 499 ; +C 104 ; WX 603 ; N eta ; B 0 -202 527 514 ; +C 105 ; WX 329 ; N iota ; B 0 -17 301 503 ; +C 106 ; WX 603 ; N phi1 ; B 36 -224 587 499 ; +C 107 ; WX 549 ; N kappa ; B 33 0 558 501 ; +C 108 ; WX 549 ; N lambda ; B 24 -17 548 739 ; +C 109 ; WX 576 ; N mu ; B 33 -223 567 500 ; +C 110 ; WX 521 ; N nu ; B -9 -16 475 507 ; +C 111 ; WX 549 ; N omicron ; B 35 -19 501 499 ; +C 112 ; WX 549 ; N pi ; B 10 -19 530 487 ; +C 113 ; WX 521 ; N theta ; B 43 -17 485 690 ; +C 114 ; WX 549 ; N rho ; B 50 -230 490 499 ; +C 115 ; WX 603 ; N sigma ; B 30 -21 588 500 ; +C 116 ; WX 439 ; N tau ; B 10 -19 418 500 ; +C 117 ; WX 576 ; N upsilon ; B 7 -18 535 507 ; +C 118 ; WX 713 ; N omega1 ; B 12 -18 671 583 ; +C 119 ; WX 686 ; N omega ; B 42 -17 684 500 ; +C 120 ; WX 493 ; N xi ; B 27 -224 469 766 ; +C 121 ; WX 686 ; N psi ; B 12 -228 701 500 ; +C 122 ; WX 494 ; N zeta ; B 60 -225 467 756 ; +C 123 ; WX 480 ; N braceleft ; B 58 -183 397 673 ; +C 124 ; WX 200 ; N bar ; B 65 -177 135 673 ; +C 125 ; WX 480 ; N braceright ; B 79 -183 418 673 ; +C 126 ; WX 549 ; N similar ; B 17 203 529 307 ; +C 161 ; WX 620 ; N Upsilon1 ; B -2 0 610 685 ; +C 162 ; WX 247 ; N minute ; B 27 459 228 735 ; +C 163 ; WX 549 ; N lessequal ; B 29 0 526 639 ; +C 164 ; WX 167 ; N fraction ; B -180 -12 340 677 ; +C 165 ; WX 713 ; N infinity ; B 26 124 688 404 ; +C 166 ; WX 500 ; N florin ; B 2 -193 494 686 ; +C 167 ; WX 753 ; N club ; B 86 -26 660 533 ; +C 168 ; WX 753 ; N diamond ; B 142 -36 600 550 ; +C 169 ; WX 753 ; N heart ; B 117 -33 631 532 ; +C 170 ; WX 753 ; N spade ; B 113 -36 629 548 ; +C 171 ; WX 1042 ; N arrowboth ; B 24 -15 1024 511 ; +C 172 ; WX 987 ; N arrowleft ; B 32 -15 942 511 ; +C 173 ; WX 603 ; N arrowup ; B 45 0 571 910 ; +C 174 ; WX 987 ; N arrowright ; B 49 -15 959 511 ; +C 175 ; WX 603 ; N arrowdown ; B 45 -22 571 888 ; +C 176 ; WX 400 ; N degree ; B 50 385 350 685 ; +C 177 ; WX 549 ; N plusminus ; B 10 0 539 645 ; +C 178 ; WX 411 ; N second ; B 20 459 413 737 ; +C 179 ; WX 549 ; N greaterequal ; B 29 0 526 639 ; +C 180 ; WX 549 ; N multiply ; B 17 8 533 524 ; +C 181 ; WX 713 ; N proportional ; B 27 123 639 404 ; +C 182 ; WX 494 ; N partialdiff ; B 26 -20 462 746 ; +C 183 ; WX 460 ; N bullet ; B 50 113 410 473 ; +C 184 ; WX 549 ; N divide ; B 10 71 536 456 ; +C 185 ; WX 549 ; N notequal ; B 15 -25 540 549 ; +C 186 ; WX 549 ; N equivalence ; B 14 82 538 443 ; +C 187 ; WX 549 ; N approxequal ; B 14 135 527 394 ; +C 188 ; WX 1000 ; N ellipsis ; B 111 -17 889 95 ; +C 189 ; WX 603 ; N arrowvertex ; B 280 -120 336 1010 ; +C 190 ; WX 1000 ; N arrowhorizex ; B -60 220 1050 276 ; +C 191 ; WX 658 ; N carriagereturn ; B 15 -16 602 629 ; +C 192 ; WX 823 ; N aleph ; B 175 -18 661 658 ; +C 193 ; WX 686 ; N Ifraktur ; B 10 -53 578 740 ; +C 194 ; WX 795 ; N Rfraktur ; B 26 -15 759 734 ; +C 195 ; WX 987 ; N weierstrass ; B 159 -211 870 573 ; +C 196 ; WX 768 ; N circlemultiply ; B 43 -17 733 673 ; +C 197 ; WX 768 ; N circleplus ; B 43 -15 733 675 ; +C 198 ; WX 823 ; N emptyset ; B 39 -24 781 719 ; +C 199 ; WX 768 ; N intersection ; B 40 0 732 509 ; +C 200 ; WX 768 ; N union ; B 40 -17 732 492 ; +C 201 ; WX 713 ; N propersuperset ; B 20 0 673 470 ; +C 202 ; WX 713 ; N reflexsuperset ; B 20 -125 673 470 ; +C 203 ; WX 713 ; N notsubset ; B 36 -70 690 540 ; +C 204 ; WX 713 ; N propersubset ; B 37 0 690 470 ; +C 205 ; WX 713 ; N reflexsubset ; B 37 -125 690 470 ; +C 206 ; WX 713 ; N element ; B 45 0 505 468 ; +C 207 ; WX 713 ; N notelement ; B 45 -58 505 555 ; +C 208 ; WX 768 ; N angle ; B 26 0 738 673 ; +C 209 ; WX 713 ; N gradient ; B 36 -19 681 718 ; +C 210 ; WX 790 ; N registerserif ; B 50 -17 740 673 ; +C 211 ; WX 790 ; N copyrightserif ; B 51 -15 741 675 ; +C 212 ; WX 890 ; N trademarkserif ; B 18 293 855 673 ; +C 213 ; WX 823 ; N product ; B 25 -101 803 751 ; +C 214 ; WX 549 ; N radical ; B 10 -38 515 917 ; +C 215 ; WX 250 ; N dotmath ; B 69 210 169 310 ; +C 216 ; WX 713 ; N logicalnot ; B 15 0 680 288 ; +C 217 ; WX 603 ; N logicaland ; B 23 0 583 454 ; +C 218 ; WX 603 ; N logicalor ; B 30 0 578 477 ; +C 219 ; WX 1042 ; N arrowdblboth ; B 27 -20 1023 510 ; +C 220 ; WX 987 ; N arrowdblleft ; B 30 -15 939 513 ; +C 221 ; WX 603 ; N arrowdblup ; B 39 2 567 911 ; +C 222 ; WX 987 ; N arrowdblright ; B 45 -20 954 508 ; +C 223 ; WX 603 ; N arrowdbldown ; B 44 -19 572 890 ; +C 224 ; WX 494 ; N lozenge ; B 18 0 466 745 ; +C 225 ; WX 329 ; N angleleft ; B 25 -198 306 746 ; +C 226 ; WX 790 ; N registersans ; B 50 -20 740 670 ; +C 227 ; WX 790 ; N copyrightsans ; B 49 -15 739 675 ; +C 228 ; WX 786 ; N trademarksans ; B 5 293 725 673 ; +C 229 ; WX 713 ; N summation ; B 14 -108 695 752 ; +C 230 ; WX 384 ; N parenlefttp ; B 40 -293 436 926 ; +C 231 ; WX 384 ; N parenleftex ; B 40 -80 92 920 ; +C 232 ; WX 384 ; N parenleftbt ; B 40 -293 436 920 ; +C 233 ; WX 384 ; N bracketlefttp ; B 0 -75 341 925 ; +C 234 ; WX 384 ; N bracketleftex ; B 0 -75 55 925 ; +C 235 ; WX 384 ; N bracketleftbt ; B 0 -75 340 925 ; +C 236 ; WX 494 ; N bracelefttp ; B 201 -75 439 925 ; +C 237 ; WX 494 ; N braceleftmid ; B 14 -75 255 925 ; +C 238 ; WX 494 ; N braceleftbt ; B 201 -75 439 925 ; +C 239 ; WX 494 ; N braceex ; B 201 -75 255 925 ; +C 241 ; WX 329 ; N angleright ; B 21 -198 302 746 ; +C 242 ; WX 274 ; N integral ; B 2 -107 291 916 ; +C 243 ; WX 686 ; N integraltp ; B 332 -83 715 921 ; +C 244 ; WX 686 ; N integralex ; B 332 -88 415 975 ; +C 245 ; WX 686 ; N integralbt ; B 39 -81 415 921 ; +C 246 ; WX 384 ; N parenrighttp ; B 54 -293 450 926 ; +C 247 ; WX 384 ; N parenrightex ; B 398 -80 450 920 ; +C 248 ; WX 384 ; N parenrightbt ; B 54 -293 450 920 ; +C 249 ; WX 384 ; N bracketrighttp ; B 22 -75 360 925 ; +C 250 ; WX 384 ; N bracketrightex ; B 305 -75 360 925 ; +C 251 ; WX 384 ; N bracketrightbt ; B 20 -75 360 925 ; +C 252 ; WX 494 ; N bracerighttp ; B 17 -75 255 925 ; +C 253 ; WX 494 ; N bracerightmid ; B 201 -75 442 925 ; +C 254 ; WX 494 ; N bracerightbt ; B 17 -75 255 925 ; +C -1 ; WX 790 ; N apple ; B 56 -3 733 808 ; +EndCharMetrics +italicCorrection integral 67 +leftItalicCorrection integral 52 +subscriptCorrection integral -10 +EndFontMetrics diff --git a/gnu/usr.bin/groff/devices/devps/symbolsl.pfa b/gnu/usr.bin/groff/devices/devps/symbolsl.pfa new file mode 100644 index 0000000000..5b335ca0ce --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/symbolsl.pfa @@ -0,0 +1,29 @@ +%!PS-Adobe-3.0 Resource-Font +%%DocumentNeededResources: font Symbol +/MakeTransformedFont{ +findfont dup maxlength dict begin +{ +exch dup dup/FID ne exch/UniqueID ne and{ +exch def +}{ +pop pop +}ifelse +}forall +/FontBBox +currentdict/FontBBox get +4 array copy def +FontBBox aload pop +4 index transform 4 2 roll +4 index transform 4 2 roll +FontBBox astore pop +FontMatrix exch matrix concatmatrix +/FontMatrix exch def +dup/FontName exch def +currentdict end +definefont pop +}bind def +%%IncludeResource: font Symbol +/Symbol-Slanted +[.89 0.0 15.5 dup sin exch cos div .89 0.0 0.0] +/Symbol +MakeTransformedFont diff --git a/gnu/usr.bin/groff/devices/devps/text.enc b/gnu/usr.bin/groff/devices/devps/text.enc new file mode 100644 index 0000000000..dde5bb7c04 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/text.enc @@ -0,0 +1,231 @@ +asciicircum 0 +asciitilde 1 +Scaron 2 +Zcaron 3 +scaron 4 +zcaron 5 +Ydieresis 6 +trademark 7 +quotesingle 8 +space 32 +exclam 33 +quotedbl 34 +numbersign 35 +dollar 36 +percent 37 +ampersand 38 +quoteright 39 +parenleft 40 +parenright 41 +asterisk 42 +plus 43 +comma 44 +hyphen 45 +period 46 +slash 47 +zero 48 +one 49 +two 50 +three 51 +four 52 +five 53 +six 54 +seven 55 +eight 56 +nine 57 +colon 58 +semicolon 59 +less 60 +equal 61 +greater 62 +question 63 +at 64 +A 65 +B 66 +C 67 +D 68 +E 69 +F 70 +G 71 +H 72 +I 73 +J 74 +K 75 +L 76 +M 77 +N 78 +O 79 +P 80 +Q 81 +R 82 +S 83 +T 84 +U 85 +V 86 +W 87 +X 88 +Y 89 +Z 90 +bracketleft 91 +backslash 92 +bracketright 93 +circumflex 94 +underscore 95 +quoteleft 96 +a 97 +b 98 +c 99 +d 100 +e 101 +f 102 +g 103 +h 104 +i 105 +j 106 +k 107 +l 108 +m 109 +n 110 +o 111 +p 112 +q 113 +r 114 +s 115 +t 116 +u 117 +v 118 +w 119 +x 120 +y 121 +z 122 +braceleft 123 +bar 124 +braceright 125 +tilde 126 +quotesinglbase 128 +guillemotleft 129 +guillemotright 130 +bullet 131 +florin 132 +fraction 133 +perthousand 134 +dagger 135 +daggerdbl 136 +endash 137 +emdash 138 +ff 139 +fi 140 +fl 141 +ffi 142 +ffl 143 +dotlessi 144 +dotlessj 145 +grave 146 +hungarumlaut 147 +dotaccent 148 +breve 149 +caron 150 +ring 151 +ogonek 152 +quotedblleft 153 +quotedblright 154 +oe 155 +lslash 156 +quotedblbase 157 +OE 158 +Lslash 159 +exclamdown 161 +cent 162 +sterling 163 +currency 164 +yen 165 +brokenbar 166 +section 167 +dieresis 168 +copyright 169 +ordfeminine 170 +guilsinglleft 171 +logicalnot 172 +registered 174 +minus 173 +macron 175 +degree 176 +plusminus 177 +twosuperior 178 +threesuperior 179 +acute 180 +mu 181 +paragraph 182 +periodcentered 183 +cedilla 184 +onesuperior 185 +ordmasculine 186 +guilsinglright 187 +onequarter 188 +onehalf 189 +threequarters 190 +questiondown 191 +Agrave 192 +Aacute 193 +Acircumflex 194 +Atilde 195 +Adieresis 196 +Aring 197 +AE 198 +Ccedilla 199 +Egrave 200 +Eacute 201 +Ecircumflex 202 +Edieresis 203 +Igrave 204 +Iacute 205 +Icircumflex 206 +Idieresis 207 +Eth 208 +Ntilde 209 +Ograve 210 +Oacute 211 +Ocircumflex 212 +Otilde 213 +Odieresis 214 +multiply 215 +Oslash 216 +Ugrave 217 +Uacute 218 +Ucircumflex 219 +Udieresis 220 +Yacute 221 +Thorn 222 +germandbls 223 +agrave 224 +aacute 225 +acircumflex 226 +atilde 227 +adieresis 228 +aring 229 +ae 230 +ccedilla 231 +egrave 232 +eacute 233 +ecircumflex 234 +edieresis 235 +igrave 236 +iacute 237 +icircumflex 238 +idieresis 239 +eth 240 +ntilde 241 +ograve 242 +oacute 243 +ocircumflex 244 +otilde 245 +odieresis 246 +divide 247 +oslash 248 +ugrave 249 +uacute 250 +ucircumflex 251 +udieresis 252 +yacute 253 +thorn 254 +ydieresis 255 diff --git a/gnu/usr.bin/groff/devices/devps/zapfdr.afm b/gnu/usr.bin/groff/devices/devps/zapfdr.afm new file mode 100644 index 0000000000..ce216de44a --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/zapfdr.afm @@ -0,0 +1,222 @@ +StartFontMetrics 2.0 +Comment Copyright (c) 1985, 1987, 1988, 1989 Adobe Systems Incorporated. All rights reserved. +Comment Creation Date: Fri Dec 1 12:57:42 1989 +Comment UniqueID 26200 +Comment VMusage 39281 49041 +FontName ZapfDingbats-Reverse +FullName ITC Zapf Dingbats +FamilyName ITC Zapf Dingbats +Weight Medium +ItalicAngle 0 +IsFixedPitch false +FontBBox -1 -143 981 820 +UnderlinePosition -98 +UnderlineThickness 54 +Version 001.004 +Notice Copyright (c) 1985, 1987, 1988, 1989 Adobe Systems Incorporated. All rights reserved.ITC Zapf Dingbats is a registered trademark of International Typeface Corporation. +EncodingScheme FontSpecific +StartCharMetrics 202 +C 32 ; WX 278 ; N space ; B 0 0 0 0 ; +C 33 ; WX 974 ; N a1 ; B 35 72 939 621 ; +C 34 ; WX 961 ; N a2 ; B 35 81 927 611 ; +C 35 ; WX 974 ; N a202 ; B 35 72 939 621 ; +C 36 ; WX 980 ; N a3 ; B 35 0 945 692 ; +C 37 ; WX 719 ; N a4 ; B 34 139 685 566 ; +C 38 ; WX 789 ; N a5 ; B 35 -14 755 705 ; +C 39 ; WX 790 ; N a119 ; B 35 -14 755 705 ; +C 40 ; WX 791 ; N a118 ; B 35 -13 761 705 ; +C 41 ; WX 690 ; N a117 ; B 35 138 655 553 ; +C 42 ; WX 960 ; N a11 ; B 35 123 925 568 ; +C 43 ; WX 939 ; N a12 ; B 35 134 904 559 ; +C 44 ; WX 549 ; N a13 ; B 29 -11 516 705 ; +C 45 ; WX 855 ; N a14 ; B 34 59 820 632 ; +C 46 ; WX 911 ; N a15 ; B 35 50 876 642 ; +C 47 ; WX 933 ; N a16 ; B 35 139 899 550 ; +C 48 ; WX 911 ; N a105 ; B 35 50 876 642 ; +C 49 ; WX 945 ; N a17 ; B 35 139 909 553 ; +C 50 ; WX 974 ; N a18 ; B 35 104 938 587 ; +C 51 ; WX 755 ; N a19 ; B 34 -13 721 705 ; +C 52 ; WX 846 ; N a20 ; B 36 -14 811 705 ; +C 53 ; WX 762 ; N a21 ; B 35 0 727 692 ; +C 54 ; WX 761 ; N a22 ; B 35 0 727 692 ; +C 55 ; WX 571 ; N a23 ; B -1 -68 571 661 ; +C 56 ; WX 677 ; N a24 ; B 36 -13 642 705 ; +C 57 ; WX 763 ; N a25 ; B 35 0 728 692 ; +C 58 ; WX 760 ; N a26 ; B 35 0 726 692 ; +C 59 ; WX 759 ; N a27 ; B 35 0 725 692 ; +C 60 ; WX 754 ; N a28 ; B 35 0 720 692 ; +C 61 ; WX 494 ; N a6 ; B 35 0 460 692 ; +C 62 ; WX 552 ; N a7 ; B 35 0 517 692 ; +C 63 ; WX 537 ; N a8 ; B 35 0 503 692 ; +C 64 ; WX 577 ; N a9 ; B 35 96 542 596 ; +C 65 ; WX 692 ; N a10 ; B 35 -14 657 705 ; +C 66 ; WX 786 ; N a29 ; B 35 -14 751 705 ; +C 67 ; WX 788 ; N a30 ; B 35 -14 752 705 ; +C 68 ; WX 788 ; N a31 ; B 35 -14 753 705 ; +C 69 ; WX 790 ; N a32 ; B 35 -14 756 705 ; +C 70 ; WX 793 ; N a33 ; B 35 -13 759 705 ; +C 71 ; WX 794 ; N a34 ; B 35 -13 759 705 ; +C 72 ; WX 816 ; N a35 ; B 35 -14 782 705 ; +C 73 ; WX 823 ; N a36 ; B 35 -14 787 705 ; +C 74 ; WX 789 ; N a37 ; B 35 -14 754 705 ; +C 75 ; WX 841 ; N a38 ; B 35 -14 807 705 ; +C 76 ; WX 823 ; N a39 ; B 35 -14 789 705 ; +C 77 ; WX 833 ; N a40 ; B 35 -14 798 705 ; +C 78 ; WX 816 ; N a41 ; B 35 -13 782 705 ; +C 79 ; WX 831 ; N a42 ; B 35 -14 796 705 ; +C 80 ; WX 923 ; N a43 ; B 35 -14 888 705 ; +C 81 ; WX 744 ; N a44 ; B 35 0 710 692 ; +C 82 ; WX 723 ; N a45 ; B 35 0 688 692 ; +C 83 ; WX 749 ; N a46 ; B 35 0 714 692 ; +C 84 ; WX 790 ; N a47 ; B 34 -14 756 705 ; +C 85 ; WX 792 ; N a48 ; B 35 -14 758 705 ; +C 86 ; WX 695 ; N a49 ; B 35 -14 661 706 ; +C 87 ; WX 776 ; N a50 ; B 35 -6 741 699 ; +C 88 ; WX 768 ; N a51 ; B 35 -7 734 699 ; +C 89 ; WX 792 ; N a52 ; B 35 -14 757 705 ; +C 90 ; WX 759 ; N a53 ; B 35 0 725 692 ; +C 91 ; WX 707 ; N a54 ; B 35 -13 672 704 ; +C 92 ; WX 708 ; N a55 ; B 35 -14 672 705 ; +C 93 ; WX 682 ; N a56 ; B 35 -14 647 705 ; +C 94 ; WX 701 ; N a57 ; B 35 -14 666 705 ; +C 95 ; WX 826 ; N a58 ; B 35 -14 791 705 ; +C 96 ; WX 815 ; N a59 ; B 35 -14 780 705 ; +C 97 ; WX 789 ; N a60 ; B 35 -14 754 705 ; +C 98 ; WX 789 ; N a61 ; B 35 -14 754 705 ; +C 99 ; WX 707 ; N a62 ; B 34 -14 673 705 ; +C 100 ; WX 687 ; N a63 ; B 36 0 651 692 ; +C 101 ; WX 696 ; N a64 ; B 35 0 661 691 ; +C 102 ; WX 689 ; N a65 ; B 35 0 655 692 ; +C 103 ; WX 786 ; N a66 ; B 34 -14 751 705 ; +C 104 ; WX 787 ; N a67 ; B 35 -14 752 705 ; +C 105 ; WX 713 ; N a68 ; B 35 -14 678 705 ; +C 106 ; WX 791 ; N a69 ; B 35 -14 756 705 ; +C 107 ; WX 785 ; N a70 ; B 36 -14 751 705 ; +C 108 ; WX 791 ; N a71 ; B 35 -14 757 705 ; +C 109 ; WX 873 ; N a72 ; B 35 -14 838 705 ; +C 110 ; WX 761 ; N a73 ; B 35 0 726 692 ; +C 111 ; WX 762 ; N a74 ; B 35 0 727 692 ; +C 112 ; WX 762 ; N a203 ; B 35 0 727 692 ; +C 113 ; WX 759 ; N a75 ; B 35 0 725 692 ; +C 114 ; WX 759 ; N a204 ; B 35 0 725 692 ; +C 115 ; WX 892 ; N a76 ; B 35 0 858 705 ; +C 116 ; WX 892 ; N a77 ; B 35 -14 858 692 ; +C 117 ; WX 788 ; N a78 ; B 35 -14 754 705 ; +C 118 ; WX 784 ; N a79 ; B 35 -14 749 705 ; +C 119 ; WX 438 ; N a81 ; B 35 -14 403 705 ; +C 120 ; WX 138 ; N a82 ; B 35 0 104 692 ; +C 121 ; WX 277 ; N a83 ; B 35 0 242 692 ; +C 122 ; WX 415 ; N a84 ; B 35 0 380 692 ; +C 123 ; WX 392 ; N a97 ; B 35 263 357 705 ; +C 124 ; WX 392 ; N a98 ; B 34 263 357 705 ; +C 125 ; WX 668 ; N a99 ; B 35 263 633 705 ; +C 126 ; WX 668 ; N a100 ; B 36 263 634 705 ; +C 161 ; WX 732 ; N a101 ; B 35 -143 697 806 ; +C 162 ; WX 544 ; N a102 ; B 56 -14 488 706 ; +C 163 ; WX 544 ; N a103 ; B 34 -14 508 705 ; +C 164 ; WX 910 ; N a104 ; B 35 40 875 651 ; +C 165 ; WX 667 ; N a106 ; B 35 -14 633 705 ; +C 166 ; WX 760 ; N a107 ; B 35 -14 726 705 ; +C 167 ; WX 760 ; N a108 ; B 0 121 758 569 ; +C 168 ; WX 776 ; N a112 ; B 35 0 741 705 ; +C 169 ; WX 595 ; N a111 ; B 34 -14 560 705 ; +C 170 ; WX 694 ; N a110 ; B 35 -14 659 705 ; +C 171 ; WX 626 ; N a109 ; B 34 0 591 705 ; +C 172 ; WX 788 ; N a120 ; B 35 -14 754 705 ; +C 173 ; WX 788 ; N a121 ; B 35 -14 754 705 ; +C 174 ; WX 788 ; N a122 ; B 35 -14 754 705 ; +C 175 ; WX 788 ; N a123 ; B 35 -14 754 705 ; +C 176 ; WX 788 ; N a124 ; B 35 -14 754 705 ; +C 177 ; WX 788 ; N a125 ; B 35 -14 754 705 ; +C 178 ; WX 788 ; N a126 ; B 35 -14 754 705 ; +C 179 ; WX 788 ; N a127 ; B 35 -14 754 705 ; +C 180 ; WX 788 ; N a128 ; B 35 -14 754 705 ; +C 181 ; WX 788 ; N a129 ; B 35 -14 754 705 ; +C 182 ; WX 788 ; N a130 ; B 35 -14 754 705 ; +C 183 ; WX 788 ; N a131 ; B 35 -14 754 705 ; +C 184 ; WX 788 ; N a132 ; B 35 -14 754 705 ; +C 185 ; WX 788 ; N a133 ; B 35 -14 754 705 ; +C 186 ; WX 788 ; N a134 ; B 35 -14 754 705 ; +C 187 ; WX 788 ; N a135 ; B 35 -14 754 705 ; +C 188 ; WX 788 ; N a136 ; B 35 -14 754 705 ; +C 189 ; WX 788 ; N a137 ; B 35 -14 754 705 ; +C 190 ; WX 788 ; N a138 ; B 35 -14 754 705 ; +C 191 ; WX 788 ; N a139 ; B 35 -14 754 705 ; +C 192 ; WX 788 ; N a140 ; B 35 -14 754 705 ; +C 193 ; WX 788 ; N a141 ; B 35 -14 754 705 ; +C 194 ; WX 788 ; N a142 ; B 35 -14 754 705 ; +C 195 ; WX 788 ; N a143 ; B 35 -14 754 705 ; +C 196 ; WX 788 ; N a144 ; B 35 -14 754 705 ; +C 197 ; WX 788 ; N a145 ; B 35 -14 754 705 ; +C 198 ; WX 788 ; N a146 ; B 35 -14 754 705 ; +C 199 ; WX 788 ; N a147 ; B 35 -14 754 705 ; +C 200 ; WX 788 ; N a148 ; B 35 -14 754 705 ; +C 201 ; WX 788 ; N a149 ; B 35 -14 754 705 ; +C 202 ; WX 788 ; N a150 ; B 35 -14 754 705 ; +C 203 ; WX 788 ; N a151 ; B 35 -14 754 705 ; +C 204 ; WX 788 ; N a152 ; B 35 -14 754 705 ; +C 205 ; WX 788 ; N a153 ; B 35 -14 754 705 ; +C 206 ; WX 788 ; N a154 ; B 35 -14 754 705 ; +C 207 ; WX 788 ; N a155 ; B 35 -14 754 705 ; +C 208 ; WX 788 ; N a156 ; B 35 -14 754 705 ; +C 209 ; WX 788 ; N a157 ; B 35 -14 754 705 ; +C 210 ; WX 788 ; N a158 ; B 35 -14 754 705 ; +C 211 ; WX 788 ; N a159 ; B 35 -14 754 705 ; +C 212 ; WX 894 ; N a160 ; B 35 58 860 634 ; +C 213 ; WX 838 ; N a161 ; B 35 152 803 540 ; +C 214 ; WX 1016 ; N a163 ; B 34 152 981 540 ; +C 215 ; WX 458 ; N a164 ; B 35 -127 422 820 ; +C 216 ; WX 748 ; N a196 ; B 35 94 698 597 ; +C 217 ; WX 924 ; N a165 ; B 35 140 890 552 ; +C 218 ; WX 748 ; N a192 ; B 35 94 698 597 ; +C 219 ; WX 918 ; N a166 ; B 35 166 884 526 ; +C 220 ; WX 927 ; N a167 ; B 35 32 892 660 ; +C 221 ; WX 928 ; N a168 ; B 35 129 891 562 ; +C 222 ; WX 928 ; N a169 ; B 35 128 893 563 ; +C 223 ; WX 834 ; N a170 ; B 35 155 799 537 ; +C 224 ; WX 873 ; N a171 ; B 35 93 838 599 ; +C 225 ; WX 828 ; N a172 ; B 35 104 791 588 ; +C 226 ; WX 924 ; N a173 ; B 35 98 889 594 ; +C 227 ; WX 924 ; N a162 ; B 35 98 889 594 ; +C 228 ; WX 917 ; N a174 ; B 35 0 882 692 ; +C 229 ; WX 930 ; N a175 ; B 35 84 896 608 ; +C 230 ; WX 931 ; N a176 ; B 35 84 896 608 ; +C 231 ; WX 463 ; N a177 ; B 35 -99 429 791 ; +C 232 ; WX 883 ; N a178 ; B 35 71 848 623 ; +C 233 ; WX 836 ; N a179 ; B 35 44 802 648 ; +C 234 ; WX 836 ; N a193 ; B 35 44 802 648 ; +C 235 ; WX 867 ; N a180 ; B 35 101 832 591 ; +C 236 ; WX 867 ; N a199 ; B 35 101 832 591 ; +C 237 ; WX 696 ; N a181 ; B 35 44 661 648 ; +C 238 ; WX 696 ; N a200 ; B 35 44 661 648 ; +C 239 ; WX 874 ; N a182 ; B 35 77 840 619 ; +C 241 ; WX 874 ; N a201 ; B 35 73 840 615 ; +C 242 ; WX 760 ; N a183 ; B 35 0 725 692 ; +C 243 ; WX 946 ; N a184 ; B 35 160 911 533 ; +C 244 ; WX 771 ; N a197 ; B 34 37 736 655 ; +C 245 ; WX 865 ; N a185 ; B 35 207 830 481 ; +C 246 ; WX 771 ; N a194 ; B 34 37 736 655 ; +C 247 ; WX 888 ; N a198 ; B 34 -19 853 712 ; +C 248 ; WX 967 ; N a186 ; B 35 124 932 568 ; +C 249 ; WX 888 ; N a195 ; B 34 -19 853 712 ; +C 250 ; WX 831 ; N a187 ; B 35 113 796 579 ; +C 251 ; WX 873 ; N a188 ; B 36 118 838 578 ; +C 252 ; WX 927 ; N a189 ; B 35 150 891 542 ; +C 253 ; WX 970 ; N a190 ; B 35 76 931 616 ; +C 254 ; WX 918 ; N a191 ; B 34 99 884 593 ; +C -1 ; WX 410 ; N a86 ; B 35 0 375 692 ; +C -1 ; WX 509 ; N a85 ; B 35 0 475 692 ; +C -1 ; WX 334 ; N a95 ; B 35 0 299 692 ; +C -1 ; WX 509 ; N a205 ; B 35 0 475 692 ; +C -1 ; WX 390 ; N a89 ; B 35 -14 356 705 ; +C -1 ; WX 234 ; N a87 ; B 35 -14 199 705 ; +C -1 ; WX 276 ; N a91 ; B 35 0 242 692 ; +C -1 ; WX 390 ; N a90 ; B 35 -14 355 705 ; +C -1 ; WX 410 ; N a206 ; B 35 0 375 692 ; +C -1 ; WX 317 ; N a94 ; B 35 0 283 692 ; +C -1 ; WX 317 ; N a93 ; B 35 0 283 692 ; +C -1 ; WX 276 ; N a92 ; B 35 0 242 692 ; +C -1 ; WX 334 ; N a96 ; B 35 0 299 692 ; +C -1 ; WX 234 ; N a88 ; B 35 -14 199 705 ; +EndCharMetrics +EndFontMetrics diff --git a/gnu/usr.bin/groff/devices/devps/zapfdr.pfa b/gnu/usr.bin/groff/devices/devps/zapfdr.pfa new file mode 100644 index 0000000000..51df4cb4f9 --- /dev/null +++ b/gnu/usr.bin/groff/devices/devps/zapfdr.pfa @@ -0,0 +1,218 @@ +%!PS-Adobe-3.0 Resource-Font +%%DocumentNeededResources: font ZapfDingbats +%%IncludeResource: font ZapfDingbats +/ZapfDingbats findfont[-1 0 0 1 0 0]makefont +dup length 1 add dict begin +{ +exch dup dup/FID ne exch/UniqueID ne and{ +exch def +}{ +pop pop +}ifelse +}forall +/FontName/ZapfDingbats-Reverse def +/Metrics 202 dict dup begin +/space[0 -278]def +/a1[-939 -974]def +/a2[-926 -961]def +/a202[-939 -974]def +/a3[-945 -980]def +/a4[-685 -719]def +/a5[-754 -789]def +/a119[-755 -790]def +/a118[-756 -791]def +/a117[-655 -690]def +/a11[-925 -960]def +/a12[-904 -939]def +/a13[-520 -549]def +/a14[-821 -855]def +/a15[-876 -911]def +/a16[-898 -933]def +/a105[-876 -911]def +/a17[-910 -945]def +/a18[-939 -974]def +/a19[-721 -755]def +/a20[-811 -846]def +/a21[-727 -762]def +/a22[-726 -761]def +/a23[-572 -571]def +/a24[-641 -677]def +/a25[-728 -763]def +/a26[-725 -760]def +/a27[-724 -759]def +/a28[-719 -754]def +/a6[-459 -494]def +/a7[-517 -552]def +/a8[-502 -537]def +/a9[-542 -577]def +/a10[-657 -692]def +/a29[-751 -786]def +/a30[-753 -788]def +/a31[-753 -788]def +/a32[-755 -790]def +/a33[-758 -793]def +/a34[-759 -794]def +/a35[-781 -816]def +/a36[-788 -823]def +/a37[-754 -789]def +/a38[-806 -841]def +/a39[-788 -823]def +/a40[-798 -833]def +/a41[-781 -816]def +/a42[-796 -831]def +/a43[-888 -923]def +/a44[-709 -744]def +/a45[-688 -723]def +/a46[-714 -749]def +/a47[-756 -790]def +/a48[-757 -792]def +/a49[-660 -695]def +/a50[-741 -776]def +/a51[-733 -768]def +/a52[-757 -792]def +/a53[-724 -759]def +/a54[-672 -707]def +/a55[-673 -708]def +/a56[-647 -682]def +/a57[-666 -701]def +/a58[-791 -826]def +/a59[-780 -815]def +/a60[-754 -789]def +/a61[-754 -789]def +/a62[-673 -707]def +/a63[-651 -687]def +/a64[-661 -696]def +/a65[-654 -689]def +/a66[-752 -786]def +/a67[-752 -787]def +/a68[-678 -713]def +/a69[-756 -791]def +/a70[-749 -785]def +/a71[-756 -791]def +/a72[-838 -873]def +/a73[-726 -761]def +/a74[-727 -762]def +/a203[-727 -762]def +/a75[-724 -759]def +/a204[-724 -759]def +/a76[-857 -892]def +/a77[-857 -892]def +/a78[-753 -788]def +/a79[-749 -784]def +/a81[-403 -438]def +/a82[-103 -138]def +/a83[-242 -277]def +/a84[-380 -415]def +/a97[-357 -392]def +/a98[-358 -392]def +/a99[-633 -668]def +/a100[-632 -668]def +/a101[-697 -732]def +/a102[-488 -544]def +/a103[-510 -544]def +/a104[-875 -910]def +/a106[-632 -667]def +/a107[-725 -760]def +/a108[-760 -760]def +/a112[-741 -776]def +/a111[-561 -595]def +/a110[-659 -694]def +/a109[-592 -626]def +/a120[-753 -788]def +/a121[-753 -788]def +/a122[-753 -788]def +/a123[-753 -788]def +/a124[-753 -788]def +/a125[-753 -788]def +/a126[-753 -788]def +/a127[-753 -788]def +/a128[-753 -788]def +/a129[-753 -788]def +/a130[-753 -788]def +/a131[-753 -788]def +/a132[-753 -788]def +/a133[-753 -788]def +/a134[-753 -788]def +/a135[-753 -788]def +/a136[-753 -788]def +/a137[-753 -788]def +/a138[-753 -788]def +/a139[-753 -788]def +/a140[-753 -788]def +/a141[-753 -788]def +/a142[-753 -788]def +/a143[-753 -788]def +/a144[-753 -788]def +/a145[-753 -788]def +/a146[-753 -788]def +/a147[-753 -788]def +/a148[-753 -788]def +/a149[-753 -788]def +/a150[-753 -788]def +/a151[-753 -788]def +/a152[-753 -788]def +/a153[-753 -788]def +/a154[-753 -788]def +/a155[-753 -788]def +/a156[-753 -788]def +/a157[-753 -788]def +/a158[-753 -788]def +/a159[-753 -788]def +/a160[-859 -894]def +/a161[-803 -838]def +/a163[-982 -1016]def +/a164[-423 -458]def +/a196[-713 -748]def +/a165[-889 -924]def +/a192[-713 -748]def +/a166[-883 -918]def +/a167[-892 -927]def +/a168[-893 -928]def +/a169[-893 -928]def +/a170[-799 -834]def +/a171[-838 -873]def +/a172[-793 -828]def +/a173[-889 -924]def +/a162[-889 -924]def +/a174[-882 -917]def +/a175[-895 -930]def +/a176[-896 -931]def +/a177[-428 -463]def +/a178[-848 -883]def +/a179[-801 -836]def +/a193[-801 -836]def +/a180[-832 -867]def +/a199[-832 -867]def +/a181[-661 -696]def +/a200[-661 -696]def +/a182[-839 -874]def +/a201[-839 -874]def +/a183[-725 -760]def +/a184[-911 -946]def +/a197[-737 -771]def +/a185[-830 -865]def +/a194[-737 -771]def +/a198[-854 -888]def +/a186[-932 -967]def +/a195[-854 -888]def +/a187[-796 -831]def +/a188[-837 -873]def +/a189[-892 -927]def +/a190[-935 -970]def +/a191[-884 -918]def +/a205[-474 -509]def +/a206[-375 -410]def +/a85[-474 -509]def +/a86[-375 -410]def +/a87[-199 -234]def +/a88[-199 -234]def +/a89[-355 -390]def +/a90[-355 -390]def +/a91[-241 -276]def +/a92[-241 -276]def +/a93[-282 -317]def +/a94[-282 -317]def +/a95[-299 -334]def +/a96[-299 -334]def +end def +/ZapfDingbats-Reverse currentdict end definefont pop diff --git a/gnu/usr.bin/groff/doc/Makefile b/gnu/usr.bin/groff/doc/Makefile new file mode 100644 index 0000000000..0d4088decf --- /dev/null +++ b/gnu/usr.bin/groff/doc/Makefile @@ -0,0 +1,55 @@ +#Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. +# Written by James Clark (jjc@jclark.com) +# +#This file is part of groff. +# +#groff is free software; you can redistribute it and/or modify it under +#the terms of the GNU General Public License as published by the Free +#Software Foundation; either version 2, or (at your option) any later +#version. +# +#groff is distributed in the hope that it will be useful, but WITHOUT ANY +#WARRANTY; without even the implied warranty of MERCHANTABILITY or +#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +#for more details. +# +#You should have received a copy of the GNU General Public License along +#with groff; see the file COPYING. If not, write to the Free Software +#Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +FFLAG=-F.. +TROFF=../troff/troff -M../tmac $(FFLAG) +GROPS=../grops/grops $(FFLAG) +DOCS=meref.PS meintro.PS +MEMACROS=../macros/tmac.e +SOELIM=../soelim/soelim + +all: $(DOCS) + +.SUFFIXES: .tr .me .PS .dit + +.dit.PS: + $(GROPS) $< >$@ + +.me.dit: + $(SOELIM) $< \ + | sed -e "s;@VERSION@;`cat ../VERSION`;" \ + | $(TROFF) -Tps $(FFLAG) -me >$@ + +.tr.dit: + $(TROFF) -Tps $< >$@ + +meref.PS: meref.dit +meintro.PS: meintro.dit + +install: + +clean: + -rm -f *.PS *.dit core + +distclean: clean + +realclean: distclean + +extraclean: clean + -rm -f core *~ \#* junk temp grot diff --git a/gnu/usr.bin/groff/doc/meintro.me b/gnu/usr.bin/groff/doc/meintro.me new file mode 100644 index 0000000000..192edb7b77 --- /dev/null +++ b/gnu/usr.bin/groff/doc/meintro.me @@ -0,0 +1,2246 @@ +.\" Copyright (c) 1986 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)intro.me 6.4 (Berkeley) 7/17/89 +.\" +.\" Modified for groff by jjc@jclark.com. +.\"UC 7 +.ll 6.5i +.lt 6.5i +.ds MO @VERSION@ +.nr si 3n +.he 'USING GROFF AND \-ME''%' +.\"eh 'USD:22-%''Writing Papers with NROFF using \-me' +.\"oh 'Writing Papers with NROFF using \-me''USD:22-%' +.ds U \s-1UNIX\s0 +.ds N \s-1NROFF\s0 +.ds T \s-1TROFF\s0 +.ds G \s-1GROFF\s0 +.+c +.(l C +.sz 14 +.b "Writing Papers with GROFF using \-me" +.sz +.sp 2 +.ul +Eric P. Allman* +.(f +*Author's current address: +Britton Lee, Inc., +1919 Addison Suite 105, +Berkeley, California 94704. +.)f +.sp +Project INGRES +Electronics Research Laboratory +University of California, Berkeley +Berkeley, California 94720 +.sp 2 +.i "Modified for \*G by James Clark" +.)l +.sp 4 +.pp +This document describes +the text processing facilities +available on the \*U\(dg +.(f +\(dg\*U is a trademark +of AT&T Bell Laboratories +.)f +operating system +via \*G and the +\-me +macro package. +It is assumed +that the reader +already is generally familiar +with the \*U operating system +and a text editor +such as +.b ex . +This is intended to be a casual introduction, +and +as such not all material is covered. +In particular, +many variations and additional features +of the \-me macro package +are not explained. +For a complete discussion of this +and other issues, +see +.ul +The \-me Reference Manual +and +.ul +The \*N/\*T Reference Manual. +.pp +\*G, a computer program +that runs on the \*U operating system, +reads an input file +prepared by the user +and outputs a formatted paper +suitable for publication or framing. +The input consists of +.i text , +or words to be printed, +and +.i requests , +which give instructions +to the \*G program +telling how to format the printed copy. +.pp +Section 1 +describes the basics +of text processing. +Section 2 +describes the basic requests. +Section 3 +introduces displays. +Annotations, +such as footnotes, +are handled in +section 4. +The more complex requests +which are not discussed in section 2 +are covered in section 5. +Finally, +section 6 +discusses things you will need +to know +if you want to typeset documents. +If you are a novice, +you probably won't want to read beyond section 4 +until you have tried some of the basic features out. +.pp +When you have your raw text ready, +call the \*G formatter by typing +as a request to the \*U shell: +.(b +groff \-me \-T\c +.i "type files" +.)b +where +.i type +describes the type of +output device you are using. +A complete description of options +to the \*G command can be found in +.b groff (1). +.pp +The word +.i argument +is used in this manual +to mean a word or number +which appears on the same line +as a request +which modifies the meaning +of that request. +For example, +the request +.(b +\&.sp +.)b +spaces one line, +but +.(b +\&.sp 4 +.)b +spaces four lines. +The number +.b 4 +is an +.i argument +to the +.b .sp +request +which says to space four lines +instead of one. +Arguments are separated from the request +and from each other +by spaces. +.sh 1 "Basics of Text Processing" +.pp +The primary function +of \*G +is to +.i collect +words from input lines, +.i fill +output lines with those words, +.i justify +the right hand margin by inserting extra spaces +in the line, +and output the result. +For example, +the input: +.(b +Now is the time +for all good men +to come to the aid +of their party. +Four score and seven +years ago,... +.)b +will be read, +packed onto output lines, +and justified +to produce: +.(b F +Now is the time +for all good men +to come to the aid +of their party. +Four score and seven +years ago,... +.)b +Sometimes you may want to start a new output line +even though the line you are on +is not yet full; +for example, +at the end of a paragraph. +To do this +you can cause a +.i break , +which +starts a new output line. +Some requests +cause a break automatically, +as do blank input lines +and input lines beginning with a space. +.pp +Not all input lines +are text to be formatted. +Some of the input lines +are +.i requests +which describe +how to format the text. +Requests always have a period +or an apostrophe +(\c +.q "\|\(aa\|" ) +as the first character +of the input line. +.pp +The text formatter +also does more complex things, +such as automatically numbering pages, +skipping over page folds, +putting footnotes in the correct place, +and so forth. +.pp +I can offer you a few hints +for preparing text +for input to \*G. +First, +keep the input lines short. +Short input lines are easier to edit, +and \*G will pack words onto longer lines +for you anyhow. +In keeping with this, +it is helpful +to begin a new line +after every period, +comma, +or phrase, +since common corrections +are to add or delete sentences +or phrases. +Second, +do not put spaces at the end of lines, +since this can sometimes confuse the \*N +processor. +Third, +do not hyphenate words at the end of lines +(except words that should have hyphens in them, +such as +.q mother-in-law ); +\*G is smart enough to hyphenate words +for you as needed, +but is not smart enough +to take hyphens out +and join a word back together. +Also, +words such as +.q mother-in-law +should not be broken +over a line, +since then you will get a space +where not wanted, +such as +.tr @- +.nh +.q "mother@\ in@law" . +.br +.tr @@ +.hy 14 +.sh 1 "Basic Requests" +.sh 2 "Paragraphs" +.pp +Paragraphs are begun +by using the +.b .pp +request. +For example, +the input: +.(b +\&.pp +Now is the time for all good men +to come to the aid of their party. +Four score and seven years ago,... +.)b +produces a blank line +followed by an indented first line. +The result is: +.(b F +.ti +\n(piu +Now is the time for all good men +to come to the aid of their party. +Four score and seven years ago,... +.)b +.pp +Notice that the sentences +of the paragraphs +.i "must not" +begin with a space, +since blank lines +and lines beginning with spaces +cause a break. +For example, +if I had typed: +.(b +\&.pp +Now is the time for all good men + to come to the aid of their party. +Four score and seven years ago,... +.)b +The output would be: +.(b F +.ti +\n(piu +Now is the time for all good men + to come to the aid of their party. +Four score and seven years ago,... +.)b +A new line begins after the word +.q men +because the second line began with a space character. +.pp +There are many +fancier +types of paragraphs, +which will be described later. +.sh 2 "Headers and Footers" +.pp +Arbitrary headers and footers +can be put +at the top and bottom +of every page. +Two requests +of the form +.b .he \ \c +.i title +and +.b .fo \ \c +.i title +define the titles to put at the head and the foot +of every page, +respectively. +The titles are called +.i three-part +titles, +that is, +there is a left-justified part, +a centered part, +and a right-justified part. +To separate these three parts +the first character of +.i title +(whatever it may be) +is used as a delimiter. +Any character may be used, +but +backslash +and double quote marks +should be avoided. +The percent sign +is replaced by the current page number +whenever found in the title. +For example, +the input: +.(b +\&.he \(aa\(aa%\(aa\(aa +\&.fo \(aaJane Jones\(aa\(aaMy Book\(aa +.)b +results in the page number +centered at the top +of each page, +.q "Jane Jones" +in the lower left corner, +and +.q "My Book" +in the lower right corner. +.sh 2 "Double Spacing" +.pp +.ls 2 +\*G will double space output text automatically if you +use the request +.b ".ls\ 2" , +as is done in this section. +You can revert to single spaced mode +by typing +.b ".ls\ 1" . +.ls 1 +.sh 2 "Page Layout" +.pp +A number of requests allow +you to change the way the printed copy looks, +sometimes called the +.i layout +of the output page. +Most of these requests adjust the placing +of +.q "white space" +(blank lines or spaces). +In these explanations, +characters in italics +should be replaced with values you wish to use; +bold characters +represent characters which should actually be typed. +.pp +The +.b .bp +request +starts a new page. +.pp +The request +.b .sp \ \c +.i N +leaves +.i N +lines of blank space. +.i N +can be omitted +(meaning skip a single line) +or can be of the form +.i N \^\c +.b i +(for +.i N +inches) +or +.i N \^\c +.b c +(for +.i N +centimeters). +For example, the input: +.(b +\&.sp 1.5i +My thoughts on the subject +\&.sp +.)b +leaves one and a half inches of space, +followed by the line +.q "My thoughts on the subject" , +followed by a single blank line. +.pp +The +.b .in \ \c +.i +N +request +changes the amount of white space +on the left of the page +(the +.i indent ). +The argument +.i N +can be of the form +.b + \c +.i N +(meaning leave +.i N +spaces more than you are already leaving), +.b \- \c +.i N +(meaning leave less than you do now), +or just +.i N +(meaning leave exactly +.i N +spaces). +.i N +can be of the form +.i N \^\c +.b i +or +.i N \^\c +.b c +also. +For example, +the input: +.(b +initial text +\&.in 5 +some text +\&.in +1i +more text +\&.in \-2c +final text +.)b +produces +.q "some text" +indented exactly five spaces +from the left margin, +.q "more text" +indented five spaces +plus one inch +from the left margin +(fifteen spaces +on a pica typewriter), +and +.q "final text" +indented five spaces +plus one inch +minus two centimeters +from the margin. +That is, +the output is: +.(b +initial text +.in +5 +some text +.in +1i +more text +.in -2c +final text +.)b +.pp +The +.b .ti \ \c +.i +N +(temporary indent) +request is used like +.b .in \ \c +.i +N +when the indent +should apply to one line only, +after which it should revert +to the previous indent. +For example, +the input: +.(b +\&.in 1i +\&.ti 0 +Ware, James R. The Best of Confucius, +Halcyon House, 1950. +An excellent book containing translations of +most of Confucius\(aa most delightful sayings. +A definite must for anyone interested in the early foundations +of Chinese philosophy. +.)b +produces: +.in 1i+\n($iu +.ti \n($iu +Ware, James R. The Best of Confucius, +Halcyon House, 1950. +An excellent book containing translations of +most of Confucius' most delightful sayings. +A definite must for anyone interested in the early foundations +of Chinese philosophy. +.pp +Text lines can be centered +by using the +.b .ce +request. +The line after the +.b .ce +is centered +(horizontally) +on the page. +To center more than one line, +use +.b .ce \ \c +.i N +(where +.i N +is the number of lines to center), +followed by the +.i N +lines. +If you want to center many lines +but don't want to count them, +type: +.(b +\&.ce 1000 +lines to center +\&.ce 0 +.)b +The +.b ".ce\ 0" +request tells \*G to center zero more lines, +in other words, +stop centering. +.pp +All of these requests +cause a break; +that is, +they always start +a new line. +If you want to start a new line +without performing any other action, +use +.b .br . +.sh 1 "Displays" +.pp +Displays are sections of text +to be set off +from the body of the paper. +Major quotes, +tables, +and figures +are types of displays, +as are all the examples +used in this document. +All displays +except centered blocks +are output +single spaced. +.sh 2 "Major Quotes" +.pp +Major quotes +are quotes which are several lines long, +and hence are set in from the rest +of the text +without quote marks +around them. +These can be generated +using the commands +.b .(q +and +.b .)q +to surround the quote. +For example, +the input: +.(b +As Weizenbaum points out: +\&.(q +It is said that to explain is to explain away. +This maxim is nowhere so well fulfilled +as in the areas of computer programming,... +\&.)q +.)b +generates as output: +.lp +As Weizenbaum points out: +.(q +It is said that to explain is to explain away. +This maxim is nowhere so well fulfilled +as in the areas of computer programming,... +.)q +.sh 2 "Lists" +.pp +A +.i list +is an indented, +single spaced, +unfilled display. +Lists should be used +when the material to be printed +should not be filled and justified +like normal text, +such as columns of figures +or the examples used in this paper. +Lists are surrounded +by the requests +.b .(l +and +.b .)l . +For example, +type: +.(b +Alternatives to avoid deadlock are: +\&.(l +Lock in a specified order +Detect deadlock and back out one process +Lock all resources needed before proceeding +\&.)l +.)b +will produce: +.br +Alternatives to avoid deadlock are: +.(l +Lock in a specified order +Detect deadlock and back out one process +Lock all resources needed before proceeding +.)l +.sh 2 "Keeps" +.pp +A +.i keep +is a display of lines +which are kept on a single page +if possible. +An example of where you would use a keep +might be a diagram. +Keeps differ from lists +in that lists may be broken +over a page boundary +whereas keeps will not. +.pp +Blocks are the basic kind of keep. +They begin with the request +.b .(b +and end with the request +.b .)b . +If there is not room on the current page +for everything in the block, +a new page is begun. +This has the unpleasant effect +of leaving blank space +at the bottom of the page. +When this is not appropriate, +you can use the alternative, +called +.i "floating keeps" . +.pp +.i "Floating keeps" +move relative to the text. +Hence, +they are good for things +which will be referred to +by name, +such as +.q "See figure 3" . +A floating keep will appear +at the bottom of the current page +if it will fit; +otherwise, +it will appear at the top +of the next page. +Floating keeps begin with the line +.b .(z +and end with the line +.b .)z . +For an example of a floating keep, +see figure 1. +.(z +.in 1i +.xl -1i +.hl +\&.(z +\&.hl +Text of keep to be floated. +\&.sp +\&.ce +Figure 1. Example of a Floating Keep. +\&.hl +\&.)z +.sp +.ce +Figure 1. Example of a Floating Keep. +.hl +.)z +The +.b .hl +request is used +to draw a horizontal line +so that the figure +stands out from the text. +.sh 2 "Fancier Displays" +.pp +Keeps and lists are normally collected in +.i nofill +mode, +so that they are good for tables and such. +If you want a display +in fill mode +(for text), +type +.b ".(l\ F" +(Throughout this section, +comments applied to +.b .(l +also apply to +.b .(b +and +.b .(z ). +This kind of display +will be indented from both margins. +For example, +the input: +.(b +\&.(l F +And now boys and girls, +a newer, bigger, better toy than ever before! +Be the first on your block to have your own computer! +Yes kids, you too can have one of these modern +data processing devices. +You too can produce beautifully formatted papers +without even batting an eye! +\&.)l +.)b +will be output as: +.(b F +And now boys and girls, +a newer, bigger, better toy than ever before! +Be the first on your block to have your own computer! +Yes kids, you too can have one of these modern +data processing devices. +You too can produce beautifully formatted papers +without even batting an eye! +.)b +.pp +Lists and blocks are also normally indented +(floating keeps are normally left justified). +To get a left-justified list, +type +.b ".(l\ L" . +To get a list centered +line-for-line, +type +.b ".(l C" . +For example, +to get a filled, +left justified list, enter: +.(b +\&.(l L F +text of block +\&.)l +.)b +The input: +.(b +\&.(l +first line of unfilled display +more lines +\&.)l +.)b +produces the indented text: +.(b +first line of unfilled display +more lines +.)b +Typing the character +.b L +after the +.b .(l +request produces the left justified result: +.(b L +first line of unfilled display +more lines +.)b +Using +.b C +instead of +.b L +produces the line-at-a-time centered output: +.(b C +first line of unfilled display +more lines +.)b +.pp +Sometimes it may be +that you want to center several lines +as a group, +rather than centering them +one line at a time. +To do this +use centered blocks, +which are surrounded by the requests +.b .(c +and +.b .)c . +All the lines are centered as a unit, +such that the longest line is centered +and the rest are +lined up around that line. +Notice that lines +do not move +relative to each other +using centered blocks, +whereas they do +using the +.b C +argument to keeps. +.pp +Centered blocks are +.i not +keeps, +and may be used +in conjunction +with keeps. +For example, +to center a group of lines +as a unit +and keep them +on one page, +use: +.(b +\&.(b L +\&.(c +first line of unfilled display +more lines +\&.)c +\&.)b +.)b +to produce: +.(b L +.(c +first line of unfilled display +more lines +.)c +.)b +If the block requests +(\c +.b .(b +and +.b .)b ) +had been omitted +the result would have been the same, +but with no guarantee +that the lines of the centered block +would have all been on one page. +Note the use of the +.b L +argument to +.b .(b ; +this causes the centered block +to center within the entire line +rather than within the line +minus the indent. +Also, +the center requests +must +be nested +.i inside +the keep requests. +.sh 1 "Annotations" +.pp +There are a number of requests +to save text +for later printing. +.i Footnotes +are printed at the bottom of the current page. +.i "Delayed text" +is intended to be a variant form +of footnote; +the text is printed only +when explicitly called for, +such as at the end of each chapter. +.i Indexes +are a type of delayed text +having a tag +(usually the page number) +attached to each entry +after a row of dots. +Indexes are also saved +until called for explicitly. +.sh 2 "Footnotes" +.pp +Footnotes begin with the request +.b .(f +and end with the request +.b .)f . +The current footnote number is maintained +automatically, +and can be used by typing \e**, +to produce a footnote number\**. +.(f +\**Like this. +.)f +The number is automatically incremented +after every footnote. +For example, +the input: +.(b +\&.(q +A man who is not upright +and at the same time is presumptuous; +one who is not diligent and at the same time is ignorant; +one who is untruthful and at the same time is incompetent; +such men I do not count among acquaintances.\e** +\&.(f +\e**James R. Ware, +\&.ul +The Best of Confucius, +Halcyon House, 1950. +Page 77. +\&.)f +\&.)q +.)b +generates the result: +.(q +A man who is not upright +and at the same time is presumptuous; +one who is not diligent and at the same time is ignorant; +one who is untruthful and at the same time is incompetent; +such men I do not count among acquaintances.\** +.(f +\**James R. Ware, +.ul +The Best of Confucius, +Halcyon House, 1950. +Page 77. +.)f +.)q +It is important +that the footnote +appears +.i inside +the quote, +so that you can be sure +that the footnote +will appear +on the same page +as the quote. +.sh 2 "Delayed Text" +.pp +Delayed text +is very similar to a footnote +except that it is printed +when called for explicitly. +This allows a list of +references to +appear +(for example) +at the end of each chapter, +as is the convention in some disciplines. +Use +.b \e*# +on delayed text +instead of +.b \e** +as on footnotes. +.pp +If you are using delayed text +as your standard reference mechanism, +you can still use footnotes, +except that you may want to reference them +with special characters* +.(f +*Such as an asterisk. +.)f +rather than numbers. +.sh 2 "Indexes" +.pp +An +.q index +(actually more like a table of contents, +since the entries are not sorted alphabetically) +resembles delayed text, +in that it is saved until called for. +However, +each entry has the page number +(or some other tag) +appended to the last line +of the index entry +after a row of dots. +.pp +Index entries begin with the request +.b .(x +and end with +.b .)x . +The +.b .)x +request may have a argument, +which is the value to print +as the +.q "page number" . +It defaults to the current page number. +If the page number given is an underscore +(\c +.q _ ) +no page number +or line of dots +is printed at all. +To get the line of dots +without a page number, +type +.b ".)x """"" , +which specifies an explicitly null page number. +.pp +The +.b .xp +request prints the index. +.pp +For example, +the input: +.(b +\&.(x +Sealing wax +\&.)x +\&.(x +Cabbages and kings +\&.)x _ +\&.(x +Why the sea is boiling hot +\&.)x 2.5a +\&.(x +Whether pigs have wings +\&.)x "" +\&.(x +This is a terribly long index entry, such as might be used +for a list of illustrations, tables, or figures; I expect it to +take at least two lines. +\&.)x +\&.xp +.)b +generates: +.(x +Sealing wax +.)x +.(x +Cabbages and kings +.)x _ +.(x +Why the sea is boiling hot +.)x 2.5a +.(x +Whether pigs have wings +.)x "" +.(x +This is a terribly long index entry, such as might be used +for a list of illustrations, tables, or figures; I expect it to +take at least two lines. +.)x +.xp +.pp +The +.b .(x +request may have a single character +argument, +specifying the +.q name +of the index; +the normal index is +.b x . +Thus, +several +.q indices +may be maintained simultaneously +(such as a list of tables, table of contents, etc.). +.pp +Notice that the index must be printed +at the +.i end +of the paper, +rather than at the beginning +where it will probably appear +(as a table of contents); +the pages may have to be physically rearranged +after printing. +.sh 1 "Fancier Features" +.pp +A large number of fancier requests +exist, +notably requests to provide other sorts of paragraphs, +numbered sections of the form +.b 1.2.3 +(such as used in this document), +and multicolumn output. +.sh 2 "More Paragraphs" +.pp +Paragraphs generally start with +a blank line +and with the first line +indented. +It is possible to get +left-justified block-style paragraphs +by using +.b .lp +instead of +.b .pp , +as demonstrated by the next paragraph. +.lp +Sometimes you want to use paragraphs +that have the +.i body +indented, +and the first line +exdented +(opposite of indented) +with a label. +This can be done with the +.b .ip +request. +A word specified on the same line as +.b .ip +is printed in the margin, +and the body is lined up +at a prespecified position +(normally five spaces). +For example, +the input: +.(b +\&.ip one +This is the first paragraph. +Notice how the first line +of the resulting paragraph lines up +with the other lines in the paragraph. +\&.ip two +And here we are at the second paragraph already. +You may notice that the argument to \c +.b .ip +appears +in the margin. +\&.lp +We can continue text... +.)b +produces as output: +.ip one +This is the first paragraph. +Notice how the first line of the resulting paragraph lines up +with the other lines in the paragraph. +.ip two +And here we are at the second paragraph already. +You may notice that the argument to +.b .ip +appears +in the margin. +.lp +We can continue text without starting a new indented +paragraph +by using the +.b .lp +request. +.pp +If you have spaces in the label of a +.b .ip +request, +you must use an +.q "unpaddable space" +instead of a regular space. +This is typed as a backslash character +(\c +.q \e ) +followed by a space. +For example, +to print the label +.q "Part 1" , +enter: +.(b +\&.ip "Part\e 1" +.)b +.pp +If a label of an indented paragraph +(that is, the argument to +.b .ip ) +is longer than the space allocated for the label, +.b .ip +will begin a new line after the label. +For example, +the input: +.(b +\&.ip longlabel +This paragraph had a long label. +The first character of text on the first line +will not line up with the text on second and subsequent lines, +although they will line up with each other. +.)b +will produce: +.ip longlabel +This paragraph had a long label. +The first character of text on the first line +will not line up with the text on second and subsequent lines, +although they will line up with each other. +.pp +It is possible to change the size of the label +by using a second argument +which is the size of the label. +For example, +the above example could be done correctly +by saying: +.(b +\&.ip longlabel 10 +.)b +which will make the paragraph indent +10 spaces for this paragraph only. +If you have many paragraphs to indent +all the same amount, +use the +.i "number register" +.b ii . +For example, to leave one inch of space +for the label, +type: +.(b +\&.nr ii 1i +.)b +somewhere before the first call to +.b .ip . +Refer to the reference manual +for more information. +.pp +If +.b .ip +is used +with no argument at all +no hanging tag will be printed. +For example, +the input: +.(b +\&.ip [a] +This is the first paragraph of the example. +We have seen this sort of example before. +\&.ip +This paragraph is lined up with the previous paragraph, +but it has no tag in the margin. +.)b +produces as output: +.ip [a] +This is the first paragraph of the example. +We have seen this sort of example before. +.ip +This paragraph is lined up with the previous paragraph, +but it has no tag in the margin. +.pp +A special case of +.b .ip +is +.b .np , +which automatically +numbers paragraphs sequentially from 1. +The numbering is reset at the next +.b .pp , +.b .lp , +or +.b .sh +(to be described in the next section) +request. +For example, +the input: +.(b +\&.np +This is the first point. +\&.np +This is the second point. +Points are just regular paragraphs +which are given sequence numbers automatically +by the .np request. +\&.pp +This paragraph will reset numbering by .np. +\&.np +For example, +we have reverted to numbering from one now. +.)b +generates: +.np +This is the first point. +.np +This is the second point. +Points are just regular paragraphs +which are given sequence numbers automatically +by the .np request. +.pp +This paragraph will reset numbering by .np. +.np +For example, +we have reverted to numbering from one now. +.pp +The +.b .bu +request gives lists of this sort that are identified with +bullets rather than numbers. +The paragraphs are also crunched together. +For example, +the input: +.(b +\&.bu +\&One egg yolk +\&.bu +\&One tablespoon cream or top milk +\&.bu +\&Salt, cayenne, and lemon juice to taste +\&.bu +\&A generous two tablespoonfuls of butter +.)b +produces\**: +.(f +\**By the way, +if you put the first three ingredients in a a heavy, deep pan +and whisk the ingredients madly over a medium flame +(never taking your hand off the handle of the pot) +until the mixture reaches the consistency of custard +(just a minute or two), +then mix in the butter off-heat, +you will have a wonderful Hollandaise sauce. +.)f +.bu +One egg yolk +.bu +One tablespoon cream or top milk +.bu +Salt, cayenne, and lemon juice to taste +.bu +A generous two tablespoonfuls of butter +.sh 2 "Section Headings" +.pp +Section numbers +(such as the ones used in this document) +can be automatically generated +using the +.b .sh +request. +You must tell +.b .sh +the +.i depth +of the section number +and a section title. +The depth +specifies how many numbers +are to appear +(separated by decimal points) +in the section number. +For example, +the section number +.b 4.2.5 +has a depth of three. +.pp +Section numbers +are incremented +in a fairly intuitive fashion. +If you add a number +(increase the depth), +the new number starts out +at one. +If you subtract section numbers +(or keep the same number) +the final number is incremented. +For example, +the input: +.(b +\&.sh 1 "The Preprocessor" +\&.sh 2 "Basic Concepts" +\&.sh 2 "Control Inputs" +\&.sh 3 +\&.sh 3 +\&.sh 1 "Code Generation" +\&.sh 3 +.)b +produces as output the result: +.(b +.b +1. The Preprocessor +1.1. Basic Concepts +1.2. Control Inputs +1.2.1. +1.2.2. +2. Code Generation +2.1.1. +.)b +.pp +You can specify the section number to begin +by placing the section number after the section title, +using spaces instead of dots. +For example, +the request: +.(b +\&.sh 3 "Another section" 7 3 4 +.)b +will begin the section numbered +.b 7.3.4 ; +all subsequent +.b .sh +requests will number relative to this number. +.pp +There are more complex features +which will cause each section to be indented +proportionally to the depth of the section. +For example, if you enter: +.(b +\&.nr si \c +.i N +.)b +each section will be indented by an amount +.i N . +.i N +must have a scaling factor attached, +that is, it must be of the form +.i Nx , +where +.i x +is a character telling what units +.i N +is in. +Common values for +.i x +are +.b i +for inches, +.b c +for centimeters, +and +.b n +for +.i ens +(the width of a single character). +For example, +to indent each section +one-half inch, +type: +.(b +\&.nr si 0.5i +.)b +After this, +sections will be indented by +one-half inch +per level of depth in the section number. +For example, +this document was produced +using the request +.(b +\&.nr si 3n +.)b +at the beginning of the input file, +giving three spaces of indent +per section depth. +.pp +Section headers without automatically generated numbers +can be done using: +.(b +\&.uh "Title" +.)b +which will do a section heading, +but will put no number on the section. +.sh 2 "Parts of the Basic Paper" +.pp +There are some requests +which assist in setting up +papers. +The +.b .tp +request +initializes for a title page. +There are no headers or footers +on a title page, +and unlike other pages +you can space down +and leave blank space +at the top. +For example, +a typical title page might appear as: +.(b +\&.tp +\&.sp 2i +\&.(l C +THE GROWTH OF TOENAILS +IN UPPER PRIMATES +\&.sp +by +\&.sp +Frank N. Furter +\&.)l +\&.bp +.)b +.pp +The +.b .+c \ \c +.i T +request can be used +to start chapters. +Each chapter is automatically numbered +from one, +and a heading is printed at the top of each chapter +with the chapter number +and the chapter name +.i T . +For example, +to begin a chapter called +.q Conclusions , +use the request: +.(b +\&.+c "CONCLUSIONS" +.)b +which will produce, +on a new page, +the lines +.(b C +CHAPTER 5 +CONCLUSIONS +.)b +with appropriate spacing for a thesis. +Also, the header is moved to the foot of the page +on the first page of a chapter. +Although the +.b .+c +request was not designed to work only with the +.b .th +request, +it is tuned for the format acceptable +for a PhD thesis +at Berkeley. +.pp +If the +title parameter +.i T +is omitted from the +.b .+c +request, +the result is a chapter with no heading. +This can also be used at the beginning +of a paper; +for example, +.b .+c +was used to generate page one +of this document. +.pp +Although +papers traditionally have the abstract, +table of contents, +and so forth at the front of the paper, +it is more convenient to format +and print them last +when using \*G. +This is so that index entries +can be collected and then printed +for the table of contents +(or whatever). +At the end of the paper, +issue the +.b ".++ P" +request, +which begins the preliminary part +of the paper. +After issuing this request, +the +.b .+c +request will begin a preliminary section +of the paper. +Most notably, +this prints the page number +restarted from one +in lower case Roman numbers. +.b .+c +may be used repeatedly +to begin different parts of the +front material +for example, +the abstract, +the table of contents, +acknowledgments, +list of illustrations, +etc. +The request +.b ".++ B" +may also be used +to begin the bibliographic section +at the end of the paper. +For example, +the paper might appear +as outlined in figure 2. +(In this figure, +comments begin with the sequence +.b \e" .) +.(z +.hl +.if t .in 0.5i +.if t .ta 2i +.if n .ta 3i +\&.th \e" set for thesis mode +\&.fo \(aa\(aaDRAFT\(aa\(aa \e" define footer for each page +\&.tp \e" begin title page +\&.(l C \e" center a large block +THE GROWTH OF TOENAILS +IN UPPER PRIMATES +\&.sp +by +\&.sp +Frank Furter +\&.)l \e" end centered part +\&.+c INTRODUCTION \e" begin chapter named "INTRODUCTION" +\&.(x t \e" make an entry into index `t' +Introduction +\&.)x \e" end of index entry +text of chapter one +\&.+c "NEXT CHAPTER" \e" begin another chapter +\&.(x t \e" enter into index `t' again +Next Chapter +\&.)x +text of chapter two +\&.+c CONCLUSIONS +\&.(x t +Conclusions +\&.)x +text of chapter three +\&.++ B \e" begin bibliographic information +\&.+c BIBLIOGRAPHY \e" begin another `chapter' +\&.(x t +Bibliography +\&.)x +text of bibliography +\&.++ P \e" begin preliminary material +\&.+c "TABLE OF CONTENTS" +\&.xp t \e" print index `t' collected above +\&.+c PREFACE \e" begin another preliminary section +text of preface +.sp 2 +.in 0 +.ce +Figure 2. Outline of a Sample Paper +.hl +.)z +.sh 2 "Equations and Tables" +.pp +Two special \*U programs exist +to format special types of material. +.b Eqn +sets equations. +.b Tbl +arranges to print +extremely pretty tables +in a variety of formats. +This document will only describe +the embellishments +to the standard features; +consult the reference manuals +for those processors +for a description of their use. +.pp +The +.b eqn +program is described fully +in the document +.ul +Typesetting Mathematics \- User's Guide +by Brian W. Kernighan +and Lorinda L. Cherry. +Equations are centered, +and are kept on one page. +They are introduced by the +.b .EQ +request and terminated by the +.b .EN +request. +.pp +The +.b .EQ +request may take an +equation number as an +optional argument, +which is printed vertically centered +on the right hand side +of the equation. +If the equation becomes too long +it should be split +between two lines. +To do this, type: +.(b +\&.EQ (eq 34) +text of equation 34 +\&.EN C +\&.EQ +continuation of equation 34 +\&.EN +.)b +The +.b C +on the +.b .EN +request +specifies that the equation +will be continued. +.pp +The +.b tbl +program produces tables. +It is fully described +(including numerous examples) +in the document +.ul +Tbl \- A Program to Format Tables +by M. E. Lesk. +Tables begin with the +.b .TS +request +and end with the +.b .TE +request. +Tables are normally kept on a single page. +If you have a table which is too big +to fit on a single page, +so that you know it will extend +to several pages, +begin the table with the request +.b ".TS\ H" +and put the request +.b .TH +after the part of the table +which you want +duplicated at the top of every page +that the table is printed on. +For example, a table definition +for a long table might look like: +.ds TA \|\h'.4n'\v'-.2n'\s-4\zT\s0\v'.2n'\h'-.4n'\(ci\| +.if n .ds TA \ \o'-T'\ \" +.(b +\&.TS H +c s s +n n n. +THE TABLE TITLE +\&.TH +text of the table +\&.TE +.)b +.pp +.sh 2 "Two Column Output" +.pp +You can get two column output +automatically +by using the request +.b .2c . +This causes everything after it +to be output in two-column form. +The request +.b .bc +will start a new column; +it differs from +.b .bp +in that +.b .bp +may leave a totally blank column +when it starts a new page. +To revert to single column output, +use +.b .1c . +.sh 2 "Defining Macros" +.pp +A +.i macro +is a collection of requests and text +which may be used +by stating a simple request. +Macros begin with the line +.b ".de" \ \c +.i xx +(where +.i xx +is the name of the macro to be defined) +and end with the line consisting of two dots. +After defining the macro, +stating the line +.b . \c +.i xx +is the same as stating all the other lines. +For example, +to define a macro +that spaces 3 lines +and then centers the next input line, +enter: +.(b +\&.de SS +\&.sp 3 +\&.ce +\&.. +.)b +and use it by typing: +.(b +\&.SS +\&Title Line +(beginning of text) +.)b +.pp +Macro names may be one or two characters. +In order to avoid conflicts +with names in \-me, +always use upper case letters as names. +The only names to avoid are +.b TS , +.b TH , +.b TE , +.b EQ , +and +.b EN . +.sh 2 "Annotations Inside Keeps" +.pp +Sometimes you may want to put +a footnote +or index entry inside a keep. +For example, +if you want to maintain a +.q "list of figures" +you will want to do something like: +.(b +\&.(z +\&.(c +text of figure +\&.)c +\&.ce +Figure 5. +\&.(x f +Figure 5 +\&.)x +\&.)z +.)b +which you may hope +will give you a figure +with a label +and an entry in the index +.b f +(presumably a list of figures index). +Unfortunately, +the +index entry +is read and interpreted +when the keep is read, +not when it is printed, +so the page number in the index is likely to be wrong. +The solution is to use the magic string +.b \e! +at the beginning of all the lines dealing with the index. +In other words, +you should use: +.(b +\&.(z +\&.(c +Text of figure +\&.)c +\&.ce +Figure 5. +\e!.(x f +\e!Figure 5 +\e!.)x +\&.)z +.)b +which will defer the processing of the index +until the figure is output. +This will guarantee +that the page number in the index +is correct. +The same comments apply +to +blocks +(with +.b .(b +and +.b .)b ) +as well. +.sh 1 "\*T and the Photosetter" +.pp +With a little care, +you can prepare +documents that +will print nicely +on either a regular terminal +or when phototypeset +using the \*T formatting program. +.sh 2 "Fonts" +.pp +A +.i font +is a style of type. +There are three fonts +that are available simultaneously, +Times Roman, +Times Italic, +and Times Bold, +plus the special math font. +The normal font is Roman. +.pp +There are ways of switching between fonts. +The requests +.b .r , +.b .i , +.b .b , +and +.b .bi +switch to Roman, +italic, +bold, +and bold-italic fonts respectively. +You can set a single word +in some font +by typing (for example): +.(b +\&.i word +.)b +which will set +.i word +in italics +but does not affect the surrounding text. +.pp +Notice that if you are setting more than one word +in whatever font, +you must surround that word with double quote marks +(`\|"\|') +so that it will appear to the \*G processor as a single word. +The quote marks will not appear in the formatted text. +If you do want a quote mark to appear, +you should quote the entire string +(even if a single word), +and use +.i two +quote marks where you want one to appear. +For example, +if you want to produce the text: +.(b +.i """Master Control\|""" +.)b +in italics, you must type: +.(b +\&.i """Master Control\e|""" +.)b +The +.b \e| +produces a very narrow space +so that the +.q l +does not overlap the quote sign in \*G, +like this: +.(b +.i """Master Control""" +.)b +.pp +There are also some +.q pseudo-fonts +available. +The input: +.(b +\&.(b +\&.u underlined +\&.bx "words in a box" +\&.)b +.)b +generates +.(b +.u underlined +.bx "words in a box" +.)b +Notice that pseudo font requests +set only the single parameter in the pseudo font; +ordinary font requests will begin setting all text +in the special font +if you do not provide a parameter. +No more than one word +should appear +with these three font requests +in the middle of lines. +This is because +of the way \*G justifies text. +For example, +if you were to issue the requests: +.(b +\&.u "some bold italics" +and +\&.bx "words in a box" +.)b +in the middle of a line +\*G would produce +.u "some bold italics" +and +.bx "words in a box" ,\p +which I think you will agree does not look good. +.pp +The second parameter +of all font requests +is set in the original font. +For example, +the font request: +.(b +\&.b bold face +.)b +generates +.q bold +in bold font, +but sets +.q face +in the font of the surrounding text, +resulting in: +.(b +.b bold face. +.)b +To set the two words +.b bold +and +.b face +both in +.b "bold face" , +type: +.(b +\&.b "bold face" +.)b +.pp +You can mix fonts in a word by using the +special sequence +.b \ec +at the end of a line +to indicate +.q "continue text processing" ; +this allows input lines +to be joined together +without a space between them. +For example, the input: +.(b +\&.u under \ec +\&.i italics +.)b +generates +.u under \c +.i italics , +but if we had typed: +.(b +\&.u under +\&.i italics +.)b +the result would have been +.u under +.i italics +as two words. +.sh 2 "Point Sizes" +.pp +The phototypesetter +supports different sizes of type, +measured in points. +The default point size +is 10 points +for most text, +8 points for footnotes. +To change the pointsize, +type: +.(b +\&.sz \c +.i +N +.)b +where +.i N +is the size wanted in points. +The +.i "vertical spacing" +(distance between the bottom of most letters +(the +.i baseline ) +between adjacent lines) +is set to be proportional +to the type size. +.pp +These pointsize changes are +.i temporary !!! +For example, +to reset the pointsize of basic text to twelve point, use: +.(b +\&.nr pp 12 +\&.nr sp 12 +\&.nr tp 12 +.)b +to reset the default pointsize of +paragraphs, +section headers, +and titles respectively. +If you only want to set the names of sections in a larger pointsize, +use: +.(b +\&.nr sp 11 +.)b +alone \*- this sets section titles +(e.g., +.b "Point Sizes" +above) +in a larger font than the default. +.pp +A single word or phrase can be set in a smaller pointsize +than the surrounding text +using the +.b .sm +request. +This is especially convenient for words that are all capitals, +due to the optical illusion that makes them look even larger +than they actually are. +For example: +.(b +\&.sm UNIX +.)b +prints as +.sm UNIX +rather than +UNIX. +.pp +Warning: +changing point sizes +on the phototypesetter +is a slow mechanical operation. +On laser printers it may require loading new fonts. +Size changes +should be considered carefully. +.sh 2 "Quotes" +.pp +It is conventional when using +the typesetter to +use pairs of grave and acute accents +to generate double quotes, +rather than the +double quote character +(`\|"\|'). +This is because it looks better +to use grave and acute accents; +for example, compare +"quote" to +``quote''. +.pp +You may use the sequences +.b \e*(lq +and +.b \e*(rq +to stand for the left and right quote +respectively. +For example, +use: +.(b +\e*(lqSome things aren\(aat true +even if they did happen.\e*(rq +.)b +to generate the result: +.(b +.q "Some things aren't true even if they did happen." +.)b +As a shorthand, +the special font request: +.(b +\&.q "quoted text" +.)b +will generate +.q "quoted text" . +Notice that you must surround +the material to be quoted +with double quote marks +if it is more than one word. +.sh 0 +.sp 1i +.b Acknowledgments +.pp +I would like to thank +Bob Epstein, +Bill Joy, +and Larry Rowe +for having the courage +to use the \-me macros +to produce non-trivial papers +during the development stages; +Ricki Blau, +Pamela Humphrey, +and Jim Joyce +for their help with the documentation phase; +peter kessler +for numerous complaints years after I was +.q done +with this project, +most accompanied by fixes +(hence forcing me to fix several small bugs); +and the plethora of people who have contributed ideas +and have given support for the project. +.sp 1i +This document was +\*G'ed +on \*(td +and applies to the version of the \-me macros +included with \*G version \*(MO. diff --git a/gnu/usr.bin/groff/doc/meref.me b/gnu/usr.bin/groff/doc/meref.me new file mode 100644 index 0000000000..9cc2c76e82 --- /dev/null +++ b/gnu/usr.bin/groff/doc/meref.me @@ -0,0 +1,2194 @@ +.\" Copyright (c) 1986 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)ref.me 6.4 (Berkeley) 7/17/89 +.\" +.\" Modified by jjc@jclark.com for groff. +.\"UC 7 +.ll 6.5i +.lt 6.5i +.\"pn 0 +.ds MO @VERSION@ +.de TL \" *** title line +.lp +.di XX +.. +.ie \n(.g \{\ +.de DE +\?\h'|\\n(DIu'\c\? +.. +.\} +.el \{\ +.de DE +\\\\h'|\\\\n(DIu'\\\\c +.. +.\} +.am DE +.br +.di +.in +\\n(DIu +.ti 0 +.cu 1000 +.XX +.rm XX +.cu 0 +.. +.ds G \s-1GROFF\s0 +.ds N \s-1NROFF\s0 +.ds T \s-1TROFF\s0 +.nr DI 1.5i +.he '\-ME REFERENCE MANUAL''%' +.de NR +.b "\en\\$1" "\\$2" +.. +.de ST +.b "\e*\\$1" "\\$2" +.. +.\"sc +.\"eh 'USD:23-%''\-me Reference Manual' +.\"oh '\-me Reference Manual''USD:23-%' +.+c +.ce 20 +.sz 14 +.b "\-ME REFERENCE MANUAL" +.sz +.sp +.i "\*G Version \*(MO\(dg" +.(f +\(dgBased on Berkeley Release 2.31. +.)f +.sp 2 +.ul +Eric P. Allman* +.(f +*Author's current address: +Britton Lee, Inc., +1919 Addison Suite 105, +Berkeley, California 94704. +.)f +.sp +Project INGRES +Electronics Research Laboratory +University of California, Berkeley +Berkeley, California 94720 +.sp 2 +.i "Modified for \*G by James Clark" +.ce 0 +.sp 4 +.pp +This document describes +in extremely terse form +the features +of the +.b \-me +macro package +for \*G. +Some familiarity is assumed +with +\*G. +Specifically, +the reader should understand +breaks, +fonts, +pointsizes, +the use and definition of number registers +and strings, +how to define macros, +and scaling factors for ens, points, +.b v 's +(vertical line spaces), +etc. +.pp +For a more casual introduction +to text processing +using \*G, +refer to the document +.ul +Writing Papers with \*G using \-me. +.pp +There are a number of macro parameters +that may be adjusted. +Fonts may be set to a font number only. +Font 0 is no font change; +the font of the surrounding text +is used instead. +Notice that font 0 is a +.q pseudo-font ; +that is, +it is simulated by the macros. +This means that although it is legal to set a font register +to zero, +it is not legal to use the escape character form, +such as: +.(b +\ef0 +.)b +.pp +All distances +are in basic units, +so it is nearly always necessary +to use a scaling factor. +For example, +the request +to set the paragraph indent +to eight one-en spaces is: +.(b +\&.nr pi 8n +.)b +and not +.(b +\&.nr pi 8 +.)b +which would set the paragraph indent to eight basic units, +or about 0.02 inch. +Default parameter values are given in brackets +in the remainder of this document. +.pp +Registers and strings +of the form +.b $ \c +.i x +may be used in expressions +but should not be changed. +Macros of the form +.b $ \c +.i x +perform some function +(as described) +and may be redefined +to change this function. +This may be a sensitive operation; +look at the body of the original macro +before changing it. +.pp +All names in \-me +follow a rigid naming convention. +The user may define number registers, +strings, +and macros, +provided that s/he +uses single character upper case names +or double character names +consisting of letters and digits, +with at least one upper case letter. +In no case should special characters +be used in user-defined names. +Locally defined macros +should all be of the form +.b .* \c +.i X , +where +.i X +is any letter +(upper or lower case) +or digit. +.pp +This documentation was \*G'ed +on \*(td +and applies to \*G version +\*(MO +of the \-me macros. +.sh 1 "Paragraphing" +.pp +These macros are used +to begin paragraphs. +The standard paragraph macro +is +.b .pp ; +the others are all variants +to be used for special purposes. +.pp +After the first call to one of the paragraphing macros +defined in this section +or the +.b .sh +macro +(defined in the next session), +the effects of changing parameters +which will have a global effect +on the format of the page +(notably page length and header and footer margins) +are not well defined +and should be avoided. +.TL +.b .lp +.DE +Begin left-justified paragraph. +Centering and underlining +are turned off if they were on, +the font is set to +.NR (pf +[1] +the type size +is set to +.NR (pp +[10p], +and a +.NR (ps +space is inserted +before the paragraph +[0.35v] +The indent is reset +to +.NR ($i +[0] +plus +.NR (po +[0] +unless the paragraph +is inside a display. +(see +.b .ba ). +At least +the first two lines +of the paragraph +are kept together +on a page. +.TL +.b .pp +.DE +Like +.b .lp , +except that it puts +.NR (pi +[5n] +units of indent. +This is the standard paragraph macro. +.TL +.b .ip +.i T +.i I +.DE +Indented paragraph +with hanging tag. +The body of the following paragraph +is indented +.i I +spaces +(or +.NR (ii +[5n] +spaces +if +.i I +is not specified) +more than a non-indented paragraph +(such as with +.b .pp ) +is. +The title +.i T +is exdented (opposite of indented). +The result is a paragraph +with an even left edge +and +.i T +printed in the margin. +Any spaces in +.i T +must be unpaddable. +If +.i T +will not fit in the space provided, +.b .ip +will start a new line. +.TL +.b .np +.DE +A variant of .ip which numbers paragraphs. +Numbering is reset +after a +.b .lp , +.b .pp , +or +.b .sh . +The current paragraph number +is in +.NR ($p . +.TL +.b .bu +.DE +Like +.b .np +except that paragraphs are marked with bullets (\(bu). +Leading space is eliminated to create compact lists. +.sh 1 "Section Headings" +.pp +Numbered sections +are similar to paragraphs +except that a +section number +is automatically +generated for each one. +The section numbers are of the form +.b 1.2.3 . +The +.i depth +of the section +is the count of numbers +(separated by decimal points) +in the section number. +.pp +Unnumbered section headings are similar, +except that no number is attached +to the heading. +.TL +.b .sh +.i +N +.i T +.i "a b c d e f" +.DE +Begin numbered section +of depth +.i N . +If +.i N +is missing +the current depth +(maintained in +the number register +.NR ($0 ) +is used. +The values of +the individual parts of the section number +are maintained in +.NR ($1 +through +.NR ($6 . +There is a +.NR (ss +[1v] +space before the section. +.i T +is printed +as a section title +in font +.NR (sf +[8] +and size +.NR (sp +[10p]. +The +.q name +of the section may be accessed via +.ST ($n . +If +.NR (si +is non-zero, +the base indent +is set to +.NR (si +times the section depth, +and the section title +is exdented. +(See +.b .ba .) +Also, +an additional indent of +.NR (so +[0] +is added to the section title +(but not to the body of the section). +The font is then set +to the paragraph font, +so that more information may occur +on the line +with the section number +and title. +.b .sh +insures that there is enough room +to print the section head +plus the beginning of a paragraph +(about 3 lines total). +If +.i a +through +.i f +are specified, +the section number is set to that number +rather than incremented automatically. +If any of +.i a +through +.i f +are a hyphen +that number is not reset. +If +.i T +is a single underscore +(\c +.q _ ) +then the section depth and numbering is reset, +but the base indent is not reset +and nothing is printed out. +This is useful to automatically +coordinate section numbers with +chapter numbers. +.TL +.b .sx +.i +N +.DE +Go to section depth +.i N +[\c +.b \-1 ], +but do not print the number +and title, +and do not increment the section number +at level +.i N . +This has the effect +of starting a new paragraph +at level +.i N . +.TL +.b .uh +.i T +.DE +Unnumbered section heading. +The title +.i T +is printed +with the same rules for spacing, +font, etc., +as for +.b .sh . +.TL +.b .$p +.i T +.i B +.i N +.DE +Print section heading. +May be redefined +to get fancier headings. +.i T +is the title passed on the +.b .sh +or +.b .uh +line; +.i B +is the section number for this section, +and +.i N +is the depth of this section. +These parameters are not always present; +in particular, +.b .sh +passes all three, +.b .uh +passes only the first, +and +.b .sx +passes three, +but the first two +are null strings. +Care should be taken if this macro +is redefined; +it is quite complex and subtle. +.TL +.b .$0 +.i T +.i B +.i N +.DE +This macro is called automatically +after every call to +.b .$p . +It is normally undefined, +but may be used +to automatically put +every section title +into the table of contents +or for some similar function. +.i T +is the section title +for the section title which was just printed, +.i B +is the section number, +and +.i N +is the section depth. +.TL +.b .$1 +\- +.b .$6 +.DE +Traps called just before printing that depth section. +May be defined to +(for example) +give variable spacing +before sections. +These macros are called from +.b .$p , +so if you redefine that macro +you may lose this feature. +.sh 1 "Headers and Footers" +.ds TP \fI\(aal\|\(aam\^\(aar\^\(aa\fP +.pp +Headers and footers +are put at the top and bottom +of every page +automatically. +They are set in font +.NR (tf +[3] +and size +.NR (tp +[10p]. +Each of the definitions +apply as of the +.i next +page. +Three-part titles +must be quoted +if there are two blanks adjacent +anywhere in the title +or more than eight blanks total. +.pp +The spacing +of headers and footers +are controlled by three number registers. +.NR (hm +[4v] +is the distance from the top of the page +to the top of the header, +.NR (fm +[3v] +is the distance from the bottom of the page +to the bottom of the footer, +.NR (tm +[7v] +is the distance from the top of the page +to the top of the text, +and +.NR (bm +[6v] +is the distance from the bottom of the page +to the bottom of the text +(nominal). +The macros +.b .m1 , +.b .m2 , +.b .m3 , +and +.b .m4 +are also supplied for compatibility +with +\s-1ROFF\s0 documents. +.TL +.b .he +\*(TP +.DE +Define three-part header, +to be printed on the top +of every page. +.TL +.b .fo +\*(TP +.DE +Define footer, +to be printed at the bottom +of every page. +.TL +.b .eh +\*(TP +.DE +Define header, +to be printed at the top of every +even-numbered page. +.TL +.b .oh +\*(TP +.DE +Define header, +to be printed at the top of every +odd-numbered page. +.TL +.b .ef +\*(TP +.DE +Define footer, +to be printed at the bottom +of every even-numbered page. +.TL +.b .of +\*(TP +.DE +Define footer, +to be printed at the bottom +of every odd-numbered page. +.TL +.b .hx +.DE +Suppress headers and footers +on the next page. +.TL +.b .m1 +.i +N +.DE +Set the space between the top of the page +and the header +[4v]. +.TL +.b .m2 +.i +N +.DE +Set the space between the header +and the first line of text +[2v]. +.TL +.b .m3 +.i +N +.DE +Set the space +between the bottom of the text +and the footer +[2v]. +.TL +.b .m4 +.i +N +.DE +Set the space +between the footer +and the bottom of the page +[4v]. +.TL +.b .ep +.DE +End this page, +but do not begin the next page. +Useful for forcing out footnotes, +but other than +that hardly every used. +Must be followed by a +.b .bp +or the end of input. +.TL +.b .$h +.DE +Called at every page +to print the header. +May be redefined +to provide fancy +(e.g., +multi-line) +headers, +but doing so +loses the function of the +.b .he , +.b .fo , +.b .eh , +.b .oh , +.b .ef , +and +.b .of +requests, +as well as the chapter-style title feature +of +.b .+c . +.TL +.b .$f +.DE +Print footer; +same comments apply +as in +.b .$h . +.TL +.b .$H +.DE +A normally undefined macro +which is called +at the top of each page +(after putting out +the header, +initial saved floating keeps, +etc.); +in other words, +this macro is called immediately before +printing text +on a page. +It can be used for column headings +and the like. +.sh 1 "Displays" +.pp +All displays except centered blocks +and block quotes +are preceded and followed +by an extra +.NR (bs +[same as +.NR (ps ] +space. +Quote spacing is stored in a separate register; +centered blocks have no default initial or trailing space. +The vertical spacing of all displays except quotes +and centered blocks +is stored in register +.NR ($V +instead of +.NR ($v . +.TL +.b .(l +.i m +.i f +.DE +Begin list. +Lists are single spaced, +unfilled text. +If +.i f +is +.b F , +the list will be filled. +If +.i m +[\c +.b I ] +is +.b I +the list is indented by +.NR (bi +[4m]; +if +.b M +the list is indented to the left margin; +if +.b L +the list is left justified with respect to the text +(different from +.b M +only if the base indent +(stored in +.NR ($i +and set with +.b .ba ) +is not zero); +and if +.b C +the list is centered on a line-by-line basis. +The list is set in font +.NR (df +[0]. +Must be matched by a +.b .)l . +This macro is almost like +.b .(b +except that no attempt is made +to keep the display on one page. +.TL +.b .)l +.DE +End list. +.TL +.b .(q +.DE +Begin major quote. +These are single spaced, +filled, +moved in from the text +on both sides +by +.NR (qi +[4n], +preceded and followed +by +.NR (qs +[same as +.NR (bs ] +space, +and are set in point size +.NR (qp +[one point smaller than surrounding text]. +.TL +.b .)q +.DE +End major quote. +.TL +.b .(b +.i m +.i f +.DE +Begin block. +Blocks are a form of +.i keep , +where the text of a keep +is kept together on one page +if possible +(keeps are useful +for tables and figures +which should not be broken +over a page). +If the block will not fit +on the current page +a new page is begun, +.i unless +that would leave more than +.NR (bt +[0] +white space +at the bottom of the text. +If +.NR (bt +is zero, the threshold feature +is turned off. +Blocks are not filled +unless +.i f +is +.b F , +when they are filled. +The block will be left-justified +if +.i m +is +.b L , +indented by +.NR (bi +[4m] +if +.i m +is +.b I +or absent, +centered +(line-for-line) +if +.i m +is +.b C , +and left justified to the margin +(not to the base indent) +if +.i m +is +.b M . +The block is set in font +.NR (df +[0]. +.TL +.b .)b +.DE +End block. +.TL +.b .(z +.i m +.i f +.DE +Begin floating keep. +Like +.b .(b +except that the keep is +.i floated +to the bottom of the page +or the top of the next page. +Therefore, +its position relative to the text changes. +The floating keep is preceded and followed +by +.NR (zs +[1v] +space. +Also, +it defaults to mode +.b M . +.TL +.b .)z +.DE +End floating keep. +.TL +.b .(c +.DE +Begin centered block. +The next keep +is centered as a block, +rather than on a line-by-line basis +as with +.b ".(b C" . +This call may be nested +inside keeps. +.TL +.b .)c +.DE +End centered block. +.sh 1 Annotations +.TL +.b .(d +.DE +Begin delayed text. +Everything in the next keep +is saved for output +later with +.b .pd , +in a manner +similar to footnotes. +.TL +.b .)d +.i n +.DE +End delayed text. +The delayed text number register +.NR ($d +and the associated string +.ST # +are incremented if +.ST # +has been referenced. +.TL +.b .pd +.DE +Print delayed text. +Everything diverted via +.b .(d +is printed and truncated. +This might be used +at the end of each chapter. +.TL +.b .(f +.DE +Begin footnote. +The text of the footnote +is floated to the bottom +of the page +and set in font +.NR (ff +[1] +and size +.NR (fp +[8p]. +Each entry +is preceded by +.NR (fs +[0.2v] +space, +is indented +.NR (fi +[3n] +on the first line, +and is indented +.NR (fu +[0] +from the right margin. +Footnotes line up underneath +two column output. +If the text of the footnote +will not all fit on one page +it will be carried over +to the next page. +.TL +.b .)f +.i n +.DE +End footnote. +The number register +.NR ($f +and the associated string +.ST * +are incremented +if they have been referenced. +.TL +.b .$s +.DE +The macro to output the footnote separator. +This macro may be redefined +to give other size lines or other types +of separators. +Currently +it draws a 1.5i line. +.TL +.b .(x +.i x +.DE +Begin index entry. +Index entries are saved in the index +.i x +[\c +.b x ] +until called up with +.b .xp. +Each entry is preceded +by a +.NR (xs +[0.2v] +space. +Each entry is +.q undented +by +.NR (xu +[0.5i]; +this register tells how far the page number +extends into the right margin. +.TL +.b .)x +.i P +.i A +.DE +End index entry. +The index entry +is finished with a row of dots +with +.i A +[null] +right justified on the last line +(such as for an author's name), +followed by P +[\c +.NR % ]. +If +.i A +is specified, +.i P +must be specified; +.NR % +can be used to print the current page number. +If +.i P +is an underscore, +no page number +and no row of dots +are printed. +.TL +.b .xp +.i x +.DE +Print index +.i x +[\c +.b x ]. +The index is formatted in the font, size, and so forth +in effect at the time it is printed, +rather than at the time it is collected. +.sh 1 "Columned Output" +.TL +.b .2c +.i +S +.i N +.DE +Enter two-column mode. +The column separation is set to +.i +S +[4n, 0.5i in ACM mode] +(saved in +.NR ($s ). +The column width, +calculated to fill the single column line length +with both columns, +is stored in +.NR ($l . +The current column +is in +.NR ($c . +You can test register +.NR ($m +[1] +to see if you are in single column +or double column mode. +Actually, +the request enters +.i N +[2] +column output. +.TL +.b .1c +.DE +Revert to single-column mode. +.TL +.b .bc +.DE +Begin column. +This is like +.b .bp +except that it begins a new column +on a new page +only if necessary, +rather than forcing a whole new page +if there is another column left +on the current page. +.sh 1 "Fonts and Sizes" +.TL +.b .sz +.i +P +.DE +The pointsize is set to +.i P +[10p], +and the line spacing is set proportionally. +The line spacing as a percentage of the pointsize expressed in units +is stored in +.NR ($v . +The percentage used internally +by displays and annotations +is stored in +.NR ($V +(although this is not used by +.b .sz ). +This size is +.i not +sticky beyond many macros: +in particular, +.NR (pp +(paragraph pointsize) +modifies the pointsize every time a new paragraph is begun +using the +.b \&.pp , +.b \&.lp , +.b \&.ip , +.b \&.np , +or +.b \&.bu +macros. +Also, +.NR (fp +(footnote pointsize), +.NR (qp +(quote pointsize), +.NR (sp +(section header pointsize), +and +.NR (tp +(title pointsize) +may modify the pointsize. +.TL +.b .r +.i W +.i X +.DE +Set +.i W +in roman font, +appending +.i X +in the previous font. +To append different font requests, +use +.i X += +.b \ec . +If no parameters, +change to roman font. +.TL +.b .i +.i W +.i X +.DE +Set +.i W +in italics, +appending +.i X +in the previous font. +If no parameters, +change to italic font. +.TL +.b .b +.i W +.i X +.DE +Set +.i W +in bold font +and append +.i X +in the previous font. +If no parameters, +switch to bold font. +.TL +.b .u +.i W +.i X +.DE +Underline +.i W +and append +.i X . +This is a true underlining, +as opposed to the +.b .ul +request, +which changes to +.q "underline font" +(usually italics in \*G). +It won't work right +if +.i W +is spread or broken (including hyphenated). +In other words, +it is safe in nofill mode only. +.TL +.b .q +.i W +.i X +.DE +Quote +.i W +and append +.i X . +In \*G +this surrounds +.i W +with +.b \*(lq , +and +.b \*(rq . +.TL +.b .bi +.i W +.i X +.DE +Set +.i W +in bold italics +and append +.i X . +.TL +.b .bx +.i W +.i X +.DE +Sets +.i W +in a box, +with +.i X +appended. +It won't work right +if +.i W +is spread or broken (including hyphenated). +In other words, +it is safe in nofill mode only. +.TL +.b sm +.i W +.i X +.DE +Sets +.i W +in a smaller pointsize, +with +.i X +appended. +.sh 1 "Roff Support" +.TL +.b .ix +.i +N +.DE +Indent, +no break. +Equivalent to +.b \(aain +.i N . +.TL +.b .bl +.i N +.DE +Leave +.i N +contiguous white space, +on the next page if not enough room +on this page. +Equivalent to a +.b .sp +.i N +inside a block. +.TL +.b .pa +.i +N +.DE +Equivalent to +.b .bp . +.TL +.b .ro +.DE +Set page number +in roman numerals. +Equivalent to +.b ".af % i" . +.TL +.b .ar +.DE +Set page number in Arabic. +Equivalent to +.b ".af % 1" . +.TL +.b .n1 +.DE +Number lines in margin from one +on each page. +.TL +.b .n2 +.i N +.DE +Number lines from +.i N , +stop if +.i N += 0. +.TL +.b .sk +.DE +Leave the next output page blank, +except for headers and footers. +This is used to leave space +for a full-page diagram +which is produced externally +and pasted in later. +To get a partial-page paste-in display, +say +.b .sv \ \c +.i N , +where +.i N +is the amount of space +to leave; +this space will be output immediately +if there is room, +and will otherwise be output +at the top of the next page. +However, be warned: +if +.i N +is greater than the amount of available space +on an empty page, +no space will ever be output. +.sh 1 "Preprocessor Support" +.TL +.b .EQ +.i m +.i T +.DE +Begin equation. +The equation is centered +if +.i m +is +.b C +or omitted, +indented +.NR (bi +[4m] +if +.i m +is +.b I , +and left justified if +.i m +is +.b L . +.i T +is a title printed on the right margin +next to the equation. +See +.i "Typesetting Mathematics \- User's Guide" +by Brian W. Kernighan +and Lorinda L. Cherry. +.TL +.b .EN +.i c +.DE +End equation. +If +.i c +is +.b C +the equation must be continued +by immediately following +with another +.b .EQ , +the text of which +can be centered +along with this one. +Otherwise, +the equation is printed, +always on one page, +with +.NR (es +[0.5v] +space +above and below it. +.TL +.b .TS +.i h +.DE +Table start. +Tables are single spaced +and kept on one page +if possible. +If you have a large table +which will not fit on one page, +use +.i h += +.b H +and follow the header part +(to be printed on every page of the table) +with a +.b .TH . +See +.i "Tbl \- A Program to Format Tables" +by M. E. Lesk. +.TL +.b .TH +.DE +With +.b ".TS H" , +ends the header portion of the table. +.TL +.b .TE +.DE +Table end. +Note that this table +does not float, +in fact, +it is not even guaranteed to stay on one page +if you use requests such as +.b .sp +intermixed with the text +of the table. +If you want it to float +(or if you use requests +inside the table), +surround the entire table +(including the +.b .TS +and +.b .TE +requests) +with the requests +.b .(z +and +.b .)z . +.TL +.b .PS +.i h +.i w +.DE +Begin +.i pic +picture. +.i H +is the height and +.i w +is the width, +both in basic units. +.TL +.b .PE +.DE +End picture. +.TL +.b .IS +.DE +Begin +.i ideal +picture. +.TL +.b .IE +.DE +End +.i ideal +picture. +.TL +.b .IF +.DE +End +.i ideal +picture (alternate form). +.TL +.b .GS +.DE +Begin +.i gremlin +picture. +.TL +.b .GE +.DE +End +.i gremlin +picture. +.TL +.b .GF +.DE +End +.i gremlin +picture (alternate form). +.sh 1 "Miscellaneous" +.TL +.b .re +.DE +Reset tabs every 0.5i. +.TL +.b .ba +.i +N +.DE +Set the base indent +to +.i +N +[0] +(saved in +.NR ($i ). +All paragraphs, +sections, +and displays +come out indented by this amount. +Titles and footnotes +are unaffected. +The +.b .sh +request performs a +.b .ba +request +if +.NR (si +[0] is not zero, +and sets the base indent to +.NR (si \c +.b * \c +.NR ($0 . +.TL +.b .xl +.i +N +.DE +Set the line length to +.i N +[6.0i]. +This differs +from +.b .ll +because it only affects the current environment. +.TL +.b .ll +.i +N +.DE +Set line length in all environments +to +.i N +[6.0i]. +This should not be used +after output has begun, +and particularly not in two-column output. +The current line length is stored in +.NR ($l . +.TL +.b .hl +.DE +Draws a horizontal line +the length of the page. +This is useful +inside floating keeps +to differentiate +between the text +and the figure. +.sh 1 "Standard Papers" +.TL +.b .tp +.DE +Begin title page. +Spacing at the top of the page +can occur, +and headers and footers are suppressed. +Also, +the page number +is not incremented +for this page. +.TL +.b .++ +.i m +.i H +.DE +This request defines the section of the paper +which we are entering. +The section type is defined by +.i m . +.b C +means that we are entering the chapter portion +of the paper, +.b A +means that we are entering the appendix portion +of the paper, +.b P +means that the material following +should be the preliminary portion +(abstract, table of contents, etc.) +portion of the paper, +.b AB +means that we are entering the abstract +(numbered independently from 1 +in Arabic numerals), +and +.b B +means that we are entering the bibliographic +portion at the end of the paper. +Also, the variants +.b RC +and +.b RA +are allowed, +which specify renumbering of pages +from one at the beginning of each +chapter or appendix, +respectively. +The +.i H +parameter defines the new header. +If there are any spaces in it, +the entire header must be quoted. +If you want the header to have the chapter number +in it, +Use the string +.b "\e\e\e\en(ch" . +For example, to number appendixes +.b A.1 +etc., +type +.b ".++ RA \(aa\(aa\(aa\e\e\e\en(ch.%\(aa" . +Each section +(chapter, appendix, etc.) +should be preceded by the +.b .+c +request. +It should be mentioned +that it is easier when using +\*T to put the front material +at the end of the paper, +so that the table of contents +can be collected and put out; +this material can then be physically +moved to the beginning of the paper. +.TL +.b .+c +.i T +.DE +Begin chapter with title +.i T . +The chapter number +is maintained in +.NR (ch . +This register is incremented +every time +.b .+c +is called with a parameter. +The title and chapter number +are printed by +.b .$c . +The header is moved to the footer +on the first page +of each chapter. +If +.i T +is omitted, +.b .$c +is not called; +this is useful for doing your own +.q "title page" +at the beginning of papers +without a title page proper. +.b .$c +calls +.b .$C +as a hook so that chapter titles can be inserted +into a table of contents automatically. +The footnote numbering is reset to one. +.TL +.b .$c +.i T +.DE +Print chapter number +(from +.NR (ch ) +and +.i T . +This macro can be redefined to your liking. +It is defined by default +to be acceptable +for a PhD thesis +at Berkeley. +This macro calls +.b $C , +which can be defined to make index entries, +or whatever. +.TL +.b .$C +.i K +.i N +.i T +.DE +This macro is called by +.b .$c . +It is normally undefined, +but can be used to automatically insert +index entries, +or whatever. +.i K +is a keyword, +either +.q Chapter +or +.q Appendix +(depending on the +.b .++ +mode); +.i N +is the chapter or appendix number, +and +.i T +is the chapter or appendix title. +.sh 1 "Predefined Strings" +.TL +.ST * +.DE +Footnote number, actually +.ST [ \c +.NR ($f \c +.ST ] . +This macro is incremented +after each call to +.b .)f . +.TL +.ST # +.DE +Delayed text number. +Actually +[\c +.NR ($d ]. +.TL +.ST { +.DE +Superscript. +This string gives upward movement +and a change to a smaller point size. +Extra space is left above the line +to allow room for the superscript. +.TL +.ST } +.DE +Unsuperscript. +Inverse to +.ST { . +For example, +to produce a superscript +you might type +.b x \c +.ST { \c +.b 2 \c +.ST } , +which will produce +.b x\*{2\*} . +.TL +.ST < +.DE +Subscript. +Extra space is left below the line +to allow for the subscript. +.TL +.ST > +.DE +Inverse to +.ST < . +.TL +.ST (dw +.DE +The day of the week, +as a word. +.TL +.ST (mo +.DE +The month, +as a word. +.TL +.ST (td +.DE +Today's date, +directly printable. +The date is of the form \*(td. +Other forms of the date can be used +by using +.NR (dy +(the day of the month; +for example, \n(dy), +.ST (mo +(as noted above) +or +.NR (mo +(the same, +but as an ordinal number; +for example, \*(mo is \n(mo), +and +.NR (yr +(the last two digits of the current year). +.TL +.ST (lq +.DE +Left quote marks. +.TL +.ST (rq +.DE +Right quote. +.TL +.ST \- +.DE +.ie \w'\(34'>0 \(34 +.el 3/4 +em dash. +.sh 1 "Special Characters and Marks" +.pp +There are a number of special characters +and diacritical marks +(such as accents) +available through \-me. +.ta 15 +5 +6 +.nf +Name Usage Example +Acute accent \e*\(aa a\e*\(aa a\*' +Grave accent \e*\(ga e\e*\(ga e\*` +Umlaut \e*: u\e*: u\*: +Tilde \e*~ n\e*~ n\*~ +Caret \e*^ e\e*^ e\*^ +Cedilla \e*, c\e*, c\*, +Czech \e*v e\e*v e\*v +Circle \e*o A\e*o A\*o +There exists \e*(qe \*(qe +For all \e*(qa \*(qa +.fi +.sp 1i +.b Acknowledgments +.pp +I would like to thank +Bob Epstein, +Bill Joy, +and Larry Rowe +for having the courage +to use the \-me macros +to produce non-trivial papers +during the development stages; +Ricki Blau, +Pamela Humphrey, +and Jim Joyce +for their help with the documentation phase; +peter kessler +for numerous complaints, +most accompanied by fixes; +and the plethora of people who have contributed ideas +and have given support for the project. +.bp +.b Summary +.pp +This alphabetical list summarizes all macros, strings, and number registers +available in the \-me macros. +Selected +.i troff +commands, registers, and functions are included as well; +those listed can generally be used with impunity. +.pp +The columns are the name of the +command, macro, register, or string; +the type of the object, +and the description. +Types are +.b M +for macro or builtin command +(invoked with +.b \&. +or +.b \&\' +in the first input column), +.b S +for a string +(invoked with +.b \e* +or +.b \e*( ), +.b R +for a number register +(invoked with +.b \en +or +.b \en( ), +and +.b F +for a +.i troff +builtin function +(invoked by preceding it with a single backslash). +.pp +Lines marked with \(sc are +.i troff +internal codes. +Lines marked with \(dg or \(dd +may be defined by the user to get special functions; +\(dd indicates that these are defined by default +and changing them may have unexpected side effects. +Lines marked with \(de +are specific to +.i ditroff +(device-independent +.i troff ). +.de $H +.ev 1 +.ta \w'\e(space)\(sc\ 'u +\w'TYPE 'u +NAME TYPE DESCRIPTION +.ev +.. +.(l +.$H +\e(space) F\(sc unpaddable space +\e" F\(sc comment (to end of line) +\e*# S optional delayed text tag string +\e$\fI\&N\fP F\(sc interpolate argument \fI\&N\fP +\en($0 R section depth +\&.$0 M\(dg invoked after section title printed +\en($1 R first section number +\&.$1 M\(dg invoked before printing depth 1 section +\en($2 R second section number +\&.$2 M\(dg invoked before printing depth 2 section +\en($3 R third section number +\&.$3 M\(dg invoked before printing depth 3 section +\en($4 R fourth section number +\&.$4 M\(dg invoked before printing depth 4 section +\en($5 R fifth section number +\&.$5 M\(dg invoked before printing depth 5 section +\en($6 R sixth section number +\&.$6 M\(dg invoked before printing depth 6 section +\&.$C M\(dg called at beginning of chapter +\&.$H M\(dg text header +\en($V R\(dd relative vertical spacing in displays +\en($c R current column number +\&.$c M\(dd print chapter title +\en($d R delayed text number +\en($f R footnote number +\&.$f M\(dd print footer +\&.$h M\(dd print header +\en($i R paragraph base indent +\en($l R column width +\en($m R number of columns in effect +\e*($n S section name +\en($p R numbered paragraph number +\&.$p M\(dd print section heading (internal macro) +\en($s R column indent +\&.$s M\(dd footnote separator (from text) +\en($v R\(dd relative vertical spacing in text +\en% R\(sc current page number +\e& F\(sc zero width character, useful for hiding controls +\e(\fI\&xx\fP F\(sc interpolate special character \fI\&xx\fP +\&.(b M begin block +\&.(c M begin centered block +\&.(d M begin delayed text +\&.(f M begin footnote +\&.(l M begin list +\&.(q M begin quote +\&.(x M begin index entry +\&.(z M begin floating keep +\&.)b M end block +\&.)c M end centered block +\&.)d M end delayed text +\&.)f M end footnote +\&.)l M end list +\&.)q M end quote +\&.)x M end index entry +\&.)z M end floating keep +\e*\fI\&x\fP F\(sc interpolate string \fI\&x\fP +\e*(\fI\&xx\fP F\(sc interpolate string \fI\&xx\fP +\e** S optional footnote tag string +\&.++ M set paper section type +\&.+c M begin chapter +\e*, S cedilla +\e\- F\(sc minus sign +\e*\- S 3/4 em dash +\e0 F\(sc unpaddable digit-width space +\&.1c M revert to single column output +\&.2c M begin two column output +\e*: S umlat +\e*< S begin subscript +\e*> S end subscript +\&.EN M end equation +\&.EQ M begin equation +\eL\'\fI\&d\fP\' F\(sc vertical line drawing function for distance \fI\&d\fP +\&.GE M\(de end \fIgremlin\fP picture +\&.GF M\(de end \fIgremlin\fP picture (with flyback) +\&.GS M\(de start \fIgremlin\fP picture +\&.IE M\(de end \fIideal\fP picture +\&.IF M\(de end \fIideal\fP picture (with flyback) +\&.IS M\(de start \fIideal\fP picture +\&.PE M\(de end \fIpic\fP picture +\&.PF M\(de end \fIpic\fP picture (with flyback) +\&.PS M\(de start \fIpic\fP picture +\&.TE M end table +\&.TH M end header of table +\&.TS M begin table +\e*{ S begin superscript +\en(\&.$ R\(sc number of arguments to macro +\en(\&.i R\(sc current indent +\en(\&.l R\(sc current line length +\en(\&.s R\(sc current point size +\e*(\&\' S acute accent +\e*(\&\` S grave accent +\e(\' F\(sc acute accent +\e(\` F\(sc grave accent +\e*} S end superscript +\e^ F\(sc 1/12 em narrow space +\e*^ S caret +\&.ad M\(sc set text adjustment +\&.af M\(sc assign format to register +\&.am M\(sc append to macro +\&.ar M set page numbers in Arabic +\&.as M\(sc append to string +\&.b M bold font +\&.ba M set base indent +\&.bc M begin new column +\&.bi M bold italic +\en(bi R display (block) indent +\&.bl M blank lines (even at top of page) +\en(bm R bottom title margin +\&.bp M\(sc begin page +\&.br M\(sc break (start new line) +\en(bs R display (block) pre/post spacing +\en(bt R block keep threshold +\&.bx M boxed +\ec F\(sc continue input +\&.ce M\(sc center lines +\en(ch R current chapter number +\&.de M\(sc define macro +\en(df R display font +\&.ds M\(sc define string +\en(dw R\(sc current day of week +\e*(dw S current day of week +\en(dy R\(sc day of month +\ee F\(sc printable version of \e +\&.ef M set footer (even numbered pages only) +\&.eh M set header (even numbered pages only) +\&.el M\(sc else part of conditional +\&.ep M end page +\en(es R equation pre/post space +\ef\fI\&f\fP F\(sc inline font change to font \fI\&f\fP +\ef(\fI\&ff\fP F\(sc inline font change to font \fI\&ff\fP +\&.fc M\(sc set field characters +\en(ff R footnote font +\&.fi M\(sc fill output lines +\en(fi R footnote indent (first line only) +\en(fm R footer margin +\&.fo M set footer +\en(fp R footnote pointsize +\en(fs R footnote prespace +\en(fu R footnote undent (from right margin) +\eh\'\fI\&d\fP\' F\(sc local horizontal motion for distance \fI\&d\fP +\&.hc M\(sc set hyphenation character +\&.he M set header +\&.hl M draw horizontal line +\en(hm R header margin +\&.hx M suppress headers and footers on next page +\&.hy M\(sc set hyphenation mode +\&.i M italic font +\&.ie M\(sc conditional with else +\&.if M\(sc conditional +\en(ii R indented paragraph indent +\&.in M\(sc indent (transient, use .ba for pervasive) +\&.ip M begin indented paragraph +\&.ix M indent, no break +\el\'\fI\&d\fP\' F\(sc horizontal line drawing function for distance \fI\&d\fP +\&.lc M\(sc set leader repetition character +\&.ll M set line length +\&.lp M begin left justified paragraph +\e*(lq S left quote marks +\&.ls M\(sc set multi-line spacing +\&.m1 M set space from top of page to header +\&.m2 M set space from header to text +\&.m3 M set space from text to footer +\&.m4 M set space from footer to bottom of page +\&.mc M\(sc insert margin character +\&.mk M\(sc mark vertical position +\en(mo R\(sc month of year +\e*(mo S current month +\en\fI\&x\fP F\(sc interpolate number register \fI\&x\fP +\en(\fI\&xx\fP F\(sc interpolate number register \fI\&xx\fP +\&.n1 M number lines in margin +\&.n2 M number lines in margin +\&.na M\(sc turn off text adjustment +\&.ne M\(sc need vertical space +\&.nf M\(sc don't fill output lines +\&.nh M\(sc turn off hyphenation +\&.np M begin numbered paragraph +\&.nr M\(sc set number register +\&.ns M\(sc no space mode +\e*o S circle (e.g., for Norse A\*o) +\&.of M set footer (odd numbered pages only) +\&.oh M set header (odd numbered pages only) +\&.pa M begin page +\&.pd M print delayed text +\en(pf R paragraph font +\en(pi R paragraph indent +\&.pl M\(sc set page length +\&.pn M\(sc set next page number +\&.po M\(sc page offset +\en(po R simulated page offset +\&.pp M begin paragraph +\en(pp R paragraph pointsize +\en(ps R paragraph prespace +\&.q M quoted +\e*(qa S for all +\e*(qe S there exists +\en(qi R quote indent (also shortens line) +\en(qp R quote pointsize +\en(qs R quote pre/post space +\&.r M roman font +\&.rb M real bold font +\&.re M reset tabs +\&.rm M\(sc remove macro or string +\&.rn M\(sc rename macro or string +\&.ro M set page numbers in roman +\e*(rq S right quote marks +\&.rr M\(sc remove register +\&.rs M\(sc restore spacing +\&.rt M\(sc return to vertical position +\es\fI\&S\fP F\(sc inline size change to size \fI\&S\fP +\en(sf R section title font +\&.sh M begin numbered section +\en(si R relative base indent per section depth +\&.sk M skip next page +\&.sm M set argument in a smaller pointsize +\&.so M\(sc source input file +\en(so R additional section title offset +\&.sp M\(sc vertical space +\en(sp R section title pointsize +\en(ss R section prespace +\&.sx M change section depth +\&.sz M set pointsize and vertical spacing +\&.ta M\(sc set tab stops +\&.tc M\(sc set tab repetition character +\e*(td S today's date +\en(tf R title font +\&.ti M\(sc temporary indent (next line only) +\&.tl M\(sc three part title +\en(tm R top title margin +\&.tp M begin title page +\en(tp R title pointsize +\&.tr M\(sc translate +\&.u M underlined +\&.uh M unnumbered section +\&.ul M\(sc underline next line +\ev\'\fI\&d\fP\' F\(sc local vertical motion for distance \fI\&d\fP +\e*v S inverted `v' for czeck ``e\*v'' +\ew\'\fI\&S\fP\' F\(sc return width of string \fI\&S\fP +\&.xl M set line length (local) +\&.xp M print index +\en(xs R index entry prespace +\en(xu R index undent (from right margin) +\en(yr R\(sc year (last two digits only) +\en(zs R floating keep pre/post space +\e{ F\(sc begin conditional group +\e| F\(sc 1/6 em narrow space +\e} F\(sc end conditional group +\e*~ S tilde +.)l +.rm $H diff --git a/gnu/usr.bin/groff/eqn/Makefile b/gnu/usr.bin/groff/eqn/Makefile new file mode 100644 index 0000000000..263aa8f099 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/Makefile @@ -0,0 +1,21 @@ +# Makefile for eqn + +PROG= eqn +SRCS= main.cc lex.cc box.cc limit.cc list.cc over.cc text.cc\ + script.cc mark.cc other.cc delim.cc sqrt.cc pile.cc special.cc +OBJS= eqn.o +CFLAGS+= -I. -I$(.CURDIR)/../include +LDADD+= $(LIBGROFF) +DPADD+= $(LIBGROFF) + +CLEANFILES+= eqn.cc eqn.tab.h + +afterinstall: + sed -e 's/@g@/$(g)/g' $(.CURDIR)/neqn.sh > $(DESTDIR)$(BINDIR)/neqn + chown ${BINOWN}.${BINGRP} $(DESTDIR)$(BINDIR)/neqn + chmod ${BINMODE} $(DESTDIR)$(BINDIR)/neqn + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/eqn/Makefile.dep b/gnu/usr.bin/groff/eqn/Makefile.dep new file mode 100644 index 0000000000..4fccfeec53 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/Makefile.dep @@ -0,0 +1,31 @@ +main.o : main.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h ../include/stringclass.h \ + ../include/device.h ../include/searchpath.h ../include/macropath.h +lex.o : lex.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h eqn.cc \ + ../include/stringclass.h ../include/ptable.h +box.o : box.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +limit.o : limit.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +list.o : list.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +over.o : over.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +text.o : text.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h ../include/ptable.h +script.o : script.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +mark.o : mark.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +other.o : other.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +delim.o : delim.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +sqrt.o : sqrt.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +pile.o : pile.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +special.o : special.cc eqn.h ../include/cset.h ../include/errarg.h \ + ../include/error.h ../include/lib.h box.h pbox.h +eqn.o : eqn.cc ../include/lib.h box.h diff --git a/gnu/usr.bin/groff/eqn/TODO b/gnu/usr.bin/groff/eqn/TODO new file mode 100644 index 0000000000..89b158e8a4 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/TODO @@ -0,0 +1,41 @@ +Use the same size increases for sum prod int as eqn does. + +Perhaps chartype should be renamed. + +TeX makes {sub,super}script on a single character with an accent +into an accent onto the (character with the script). Should we do this? + +Implement mark and lineups within scripts, matrices and piles, and accents. +(Why would this be useful?) + +Perhaps push hmotions down through lists to avoid upsetting spacing +adjustments. + +Possibly generate .lf commands during compute_metrics phase. + +Consider whether there shuld be extra space at the side of piles. + +Provide scriptstyle displaystyle etc. + +Provide a nicer matrix syntax, eg +matrix ccc { +a then b then c above +e then f then g above +h then i then k +} + +Perhaps generate syntax error messages using the style of gpic. + +Wide accents. + +More use of \Z. + +Extensible square roots. + +Vphantom + +Smash. + +Provide a variant of vec that extends over the length of the accentee. + +Support vertical arrow delimiters. diff --git a/gnu/usr.bin/groff/eqn/box.cc b/gnu/usr.bin/groff/eqn/box.cc new file mode 100644 index 0000000000..08dbe07978 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/box.cc @@ -0,0 +1,611 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + +const char *current_roman_font; + +char *gfont = 0; +char *grfont = 0; +char *gbfont = 0; +int gsize = 0; + +int script_size_reduction = -1; // negative means reduce by a percentage + +int positive_space = -1; +int negative_space = -1; + +int minimum_size = 5; + +int fat_offset = 4; +int body_height = 85; +int body_depth = 35; + +int over_hang = 0; +int accent_width = 31; +int delimiter_factor = 900; +int delimiter_shortfall = 50; + +int null_delimiter_space = 12; +int script_space = 5; +int thin_space = 17; +int medium_space = 22; +int thick_space = 28; + +int num1 = 70; +int num2 = 40; +// we don't use num3, because we don't have \atop +int denom1 = 70; +int denom2 = 36; +int axis_height = 26; // in 100ths of an em +int sup1 = 42; +int sup2 = 37; +int sup3 = 28; +int default_rule_thickness = 4; +int sub1 = 20; +int sub2 = 23; +int sup_drop = 38; +int sub_drop = 5; +int x_height = 45; +int big_op_spacing1 = 11; +int big_op_spacing2 = 17; +int big_op_spacing3 = 20; +int big_op_spacing4 = 60; +int big_op_spacing5 = 10; + +// These are for piles and matrices. + +int baseline_sep = 140; // = num1 + denom1 +int shift_down = 26; // = axis_height +int column_sep = 100; // = em space +int matrix_side_sep = 17; // = thin space + +int nroff = 0; // should we grok ndefine or tdefine? + +struct { + const char *name; + int *ptr; +} param_table[] = { +"fat_offset", &fat_offset, +"over_hang", &over_hang, +"accent_width", &accent_width, +"delimiter_factor", &delimiter_factor, +"delimiter_shortfall", &delimiter_shortfall, +"null_delimiter_space", &null_delimiter_space, +"script_space", &script_space, +"thin_space", &thin_space, +"medium_space", &medium_space, +"thick_space", &thick_space, +"num1", &num1, +"num2", &num2, +"denom1", &denom1, +"denom2", &denom2, +"axis_height", &axis_height, +"sup1", ¹, +"sup2", ², +"sup3", ³, +"default_rule_thickness", &default_rule_thickness, +"sub1", &sub1, +"sub2", &sub2, +"sup_drop", &sup_drop, +"sub_drop", &sub_drop, +"x_height", &x_height, +"big_op_spacing1", &big_op_spacing1, +"big_op_spacing2", &big_op_spacing2, +"big_op_spacing3", &big_op_spacing3, +"big_op_spacing4", &big_op_spacing4, +"big_op_spacing5", &big_op_spacing5, +"minimum_size", &minimum_size, +"baseline_sep", &baseline_sep, +"shift_down", &shift_down, +"column_sep", &column_sep, +"matrix_side_sep", &matrix_side_sep, +"draw_lines", &draw_flag, +"body_height", &body_height, +"body_depth", &body_depth, +"nroff", &nroff, +0, 0 +}; + +void set_param(const char *name, int value) +{ + for (int i = 0; param_table[i].name != 0; i++) + if (strcmp(param_table[i].name, name) == 0) { + *param_table[i].ptr = value; + return; + } + error("unrecognised parameter `%1'", name); +} + +int script_style(int style) +{ + return style > SCRIPT_STYLE ? style - 2 : style; +} + +int cramped_style(int style) +{ + return (style & 1) ? style - 1 : style; +} + +void set_space(int n) +{ + if (n < 0) + negative_space = -n; + else + positive_space = n; +} + +// Return 0 if the specified size is bad. +// The caller is responsible for giving the error message. + +int set_gsize(const char *s) +{ + const char *p = (*s == '+' || *s == '-') ? s + 1 : s; + char *end; + long n = strtol(p, &end, 10); + if (n <= 0 || *end != '\0' || n > INT_MAX) + return 0; + if (p > s) { + if (!gsize) + gsize = 10; + if (*s == '+') { + if (gsize > INT_MAX - n) + return 0; + gsize += int(n); + } + else { + if (gsize - n <= 0) + return 0; + gsize -= int(n); + } + } + else + gsize = int(n); + return 1; +} + +void set_script_reduction(int n) +{ + script_size_reduction = n; +} + +const char *get_gfont() +{ + return gfont ? gfont : "I"; +} + +const char *get_grfont() +{ + return grfont ? grfont : "R"; +} + +const char *get_gbfont() +{ + return gbfont ? gbfont : "B"; +} + +void set_gfont(const char *s) +{ + a_delete gfont; + gfont = strsave(s); +} + +void set_grfont(const char *s) +{ + a_delete grfont; + grfont = strsave(s); +} + +void set_gbfont(const char *s) +{ + a_delete gbfont; + gbfont = strsave(s); +} + +// this must be precisely 2 characters in length +#define COMPATIBLE_REG "0C" + +void start_string() +{ + printf(".nr " COMPATIBLE_REG " \\n(.C\n"); + printf(".cp 0\n"); + printf(".ds " LINE_STRING "\n"); +} + +void output_string() +{ + printf("\\*[" LINE_STRING "]\n"); +} + +void restore_compatibility() +{ + printf(".cp \\n(" COMPATIBLE_REG "\n"); +} + +void do_text(const char *s) +{ + printf(".eo\n"); + printf(".as " LINE_STRING " \"%s\n", s); + printf(".ec\n"); +} + +void set_minimum_size(int n) +{ + minimum_size = n; +} + +void set_script_size() +{ + if (minimum_size < 0) + minimum_size = 0; + if (script_size_reduction >= 0) + printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size); + else + printf(".ps (u;\\n[.s]*7+5/10>?%d)*1z\n", minimum_size); +} + +int box::next_uid = 0; + +box::box() : uid(next_uid++), spacing_type(ORDINARY_TYPE) +{ +} + +box::~box() +{ +} + +void box::top_level() +{ + // debug_print(); + // putc('\n', stderr); + box *b = this; + printf(".nr " SAVED_FONT_REG " \\n[.f]\n"); + printf(".ft\n"); + printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n"); + printf(".ft %s\n", get_gfont()); + printf(".nr " SAVED_SIZE_REG " \\n[.s]z\n"); + if (gsize > 0) { + char buf[INT_DIGITS + 1]; + sprintf(buf, "%d", gsize); + b = new size_box(strsave(buf), b); + } + current_roman_font = get_grfont(); + // This catches tabs used within \Z (which aren't allowed). + b->check_tabs(0); + int r = b->compute_metrics(DISPLAY_STYLE); + printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n"); + printf(".ft \\n[" SAVED_FONT_REG "]\n"); + printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r); + if (r == FOUND_MARK) { + printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n"); + printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid); + } + else if (r == FOUND_LINEUP) + printf(".if r" SAVED_MARK_REG " .as " LINE_STRING " \\h'\\n[" + SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n"); + else + assert(r == FOUND_NOTHING); + // The problem here is that the argument to \f is read in copy mode, + // so we cannot use \E there; so we hide it in a string instead. + // Another problem is that if we use \R directly, then the space will + // prevent it working in a macro argument. + printf(".ds " SAVE_FONT_STRING " " + "\\R'" SAVED_INLINE_FONT_REG " \\\\n[.f]'" + "\\fP" + "\\R'" SAVED_INLINE_PREV_FONT_REG " \\\\n[.f]'" + "\\R'" SAVED_INLINE_SIZE_REG " \\\\n[.s]z'" + "\\s0" + "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.s]z'" + "\n" + ".ds " RESTORE_FONT_STRING " " + "\\f[\\\\n[" SAVED_INLINE_PREV_FONT_REG "]]" + "\\f[\\\\n[" SAVED_INLINE_FONT_REG "]]" + "\\s'\\\\n[" SAVED_INLINE_PREV_SIZE_REG "]u'" + "\\s'\\\\n[" SAVED_INLINE_SIZE_REG "]u'" + "\n"); + printf(".as " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]"); + printf("\\f[%s]", get_gfont()); + printf("\\s'\\En[" SAVED_SIZE_REG "]u'"); + current_roman_font = get_grfont(); + b->output(); + printf("\\E*[" RESTORE_FONT_STRING "]\n"); + if (r == FOUND_LINEUP) + printf(".if r" SAVED_MARK_REG " .as " LINE_STRING " \\h'\\n[" + MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n[" + WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n", + b->uid); + b->extra_space(); + if (!inline_flag) + printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n[" + DEPTH_FORMAT "]u-%dM>?0)\n", + b->uid, body_height, b->uid, body_depth); + delete b; + next_uid = 0; +} + +// gpic defines this register so as to make geqn not produce `\x's +#define EQN_NO_EXTRA_SPACE_REG "0x" + +void box::extra_space() +{ + printf(".if !r" EQN_NO_EXTRA_SPACE_REG " " + ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n"); + if (positive_space >= 0 || negative_space >= 0) { + if (positive_space > 0) + printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] " + ".as " LINE_STRING " \\x'-%dM'\n", positive_space); + if (negative_space > 0) + printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] " + ".as " LINE_STRING " \\x'%dM'\n", negative_space); + positive_space = negative_space = -1; + } + else { + printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] " + ".if \\n[" HEIGHT_FORMAT "]>%dM .as " LINE_STRING + " \\x'-(\\n[" HEIGHT_FORMAT + "]u-%dM)'\n", + uid, body_height, uid, body_height); + printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] " + ".if \\n[" DEPTH_FORMAT "]>%dM .as " LINE_STRING + " \\x'\\n[" DEPTH_FORMAT + "]u-%dM'\n", + uid, body_depth, uid, body_depth); + } +} + +int box::compute_metrics(int) +{ + printf(".nr " WIDTH_FORMAT " 0\n", uid); + printf(".nr " HEIGHT_FORMAT " 0\n", uid); + printf(".nr " DEPTH_FORMAT " 0\n", uid); + return FOUND_NOTHING; +} + +void box::compute_subscript_kern() +{ + printf(".nr " SUB_KERN_FORMAT " 0\n", uid); +} + +void box::compute_skew() +{ + printf(".nr " SKEW_FORMAT " 0\n", uid); +} + +void box::output() +{ +} + +void box::check_tabs(int) +{ +} + +int box::is_char() +{ + return 0; +} + +int box::left_is_italic() +{ + return 0; +} + +int box::right_is_italic() +{ + return 0; +} + +void box::hint(unsigned) +{ +} + +void box::handle_char_type(int, int) +{ +} + + +box_list::box_list(box *pp) +{ + p = new box*[10]; + for (int i = 0; i < 10; i++) + p[i] = 0; + maxlen = 10; + len = 1; + p[0] = pp; +} + +void box_list::append(box *pp) +{ + if (len + 1 > maxlen) { + box **oldp = p; + maxlen *= 2; + p = new box*[maxlen]; + memcpy(p, oldp, sizeof(box*)*len); + a_delete oldp; + } + p[len++] = pp; +} + +box_list::~box_list() +{ + for (int i = 0; i < len; i++) + delete p[i]; + a_delete p; +} + +void box_list::list_check_tabs(int level) +{ + for (int i = 0; i < len; i++) + p[i]->check_tabs(level); +} + + +pointer_box::pointer_box(box *pp) : p(pp) +{ + spacing_type = p->spacing_type; +} + +pointer_box::~pointer_box() +{ + delete p; +} + +int pointer_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + return r; +} + +void pointer_box::compute_subscript_kern() +{ + p->compute_subscript_kern(); + printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid); +} + +void pointer_box::compute_skew() +{ + p->compute_skew(); + printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n", + uid, p->uid); +} + +void pointer_box::check_tabs(int level) +{ + p->check_tabs(level); +} + +int simple_box::compute_metrics(int) +{ + printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid); + output(); + printf(DELIMITER_CHAR "\n"); + printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid); + printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid); + printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid); + printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid); + return FOUND_NOTHING; +} + +void simple_box::compute_subscript_kern() +{ + // do nothing, we already computed it in do_metrics +} + +void simple_box::compute_skew() +{ + // do nothing, we already computed it in do_metrics +} + +int box::is_simple() +{ + return 0; +} + +int simple_box::is_simple() +{ + return 1; +} + +quoted_text_box::quoted_text_box(char *s) : text(s) +{ +} + +quoted_text_box::~quoted_text_box() +{ + a_delete text; +} + +void quoted_text_box::output() +{ + if (text) + fputs(text, stdout); +} + +tab_box::tab_box() : disabled(0) +{ +} + +// We treat a tab_box as having width 0 for width computations. + +void tab_box::output() +{ + if (!disabled) + printf("\\t"); +} + +void tab_box::check_tabs(int level) +{ + if (level > 0) { + error("tabs allowed only at outermost level"); + disabled = 1; + } +} + +space_box::space_box() +{ + spacing_type = SUPPRESS_TYPE; +} + +void space_box::output() +{ + printf("\\h'%dM'", thick_space); +} + +half_space_box::half_space_box() +{ + spacing_type = SUPPRESS_TYPE; +} + +void half_space_box::output() +{ + printf("\\h'%dM'", thin_space); +} + +void box_list::list_debug_print(const char *sep) +{ + p[0]->debug_print(); + for (int i = 1; i < len; i++) { + fprintf(stderr, "%s", sep); + p[i]->debug_print(); + } +} + +void quoted_text_box::debug_print() +{ + fprintf(stderr, "\"%s\"", (text ? text : "")); +} + +void half_space_box::debug_print() +{ + fprintf(stderr, "^"); +} + +void space_box::debug_print() +{ + fprintf(stderr, "~"); +} + +void tab_box::debug_print() +{ + fprintf(stderr, ""); +} diff --git a/gnu/usr.bin/groff/eqn/box.h b/gnu/usr.bin/groff/eqn/box.h new file mode 100644 index 0000000000..a6da83eca9 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/box.h @@ -0,0 +1,277 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct list_box; + +class box { +private: + static int next_uid; +public: + int spacing_type; + const int uid; + box(); + virtual void debug_print() = 0; + virtual ~box(); + void top_level(); + virtual int compute_metrics(int); + virtual void compute_subscript_kern(); + virtual void compute_skew(); + virtual void output(); + void extra_space(); + virtual list_box *to_list_box(); + virtual int is_simple(); + virtual int is_char(); + virtual int left_is_italic(); + virtual int right_is_italic(); + virtual void handle_char_type(int, int); + enum { FOUND_NOTHING = 0, FOUND_MARK = 1, FOUND_LINEUP = 2 }; + void set_spacing_type(char *type); + virtual void hint(unsigned); + virtual void check_tabs(int); +}; + +class box_list { +private: + int maxlen; +public: + box **p; + int len; + + box_list(box *); + ~box_list(); + void append(box *); + void list_check_tabs(int); + void list_debug_print(const char *sep); + friend class list_box; +}; + +class list_box : public box { + int is_script; + box_list list; + int sty; +public: + list_box(box *); + void debug_print(); + int compute_metrics(int); + void compute_subscript_kern(); + void output(); + void check_tabs(int); + void append(box *); + list_box *to_list_box(); + void handle_char_type(int, int); + void compute_sublist_width(int n); + friend box *make_script_box(box *, box *, box *); + friend box *make_mark_box(box *); + friend box *make_lineup_box(box *); +}; + +enum alignment { LEFT_ALIGN, RIGHT_ALIGN, CENTER_ALIGN }; + +class column : public box_list { + alignment align; + int space; +public: + column(box *); + void set_alignment(alignment); + void set_space(int); + void debug_print(const char *); + + friend class matrix_box; + friend class pile_box; +}; + +class pile_box : public box { + column col; +public: + pile_box(box *); + int compute_metrics(int); + void output(); + void debug_print(); + void check_tabs(int); + void set_alignment(alignment a) { col.set_alignment(a); } + void set_space(int n) { col.set_space(n); } + void append(box *p) { col.append(p); } +}; + +class matrix_box : public box { +private: + int len; + int maxlen; + column **p; +public: + matrix_box(column *); + ~matrix_box(); + void append(column *); + int compute_metrics(int); + void output(); + void check_tabs(int); + void debug_print(); +}; + +class pointer_box : public box { +protected: + box *p; +public: + pointer_box(box *); + ~pointer_box(); + int compute_metrics(int); + void compute_subscript_kern(); + void compute_skew(); + void debug_print() = 0; + void check_tabs(int); +}; + +class vcenter_box : public pointer_box { +public: + vcenter_box(box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class simple_box : public box { +public: + int compute_metrics(int); + void compute_subscript_kern(); + void compute_skew(); + void output() = 0; + void debug_print() = 0; + int is_simple(); +}; + +class quoted_text_box : public simple_box { + char *text; +public: + quoted_text_box(char *); + ~quoted_text_box(); + void debug_print(); + void output(); +}; + +class half_space_box : public simple_box { +public: + half_space_box(); + void output(); + void debug_print(); +}; + +class space_box : public simple_box { +public: + space_box(); + void output(); + void debug_print(); +}; + +class tab_box : public box { + int disabled; +public: + tab_box(); + void output(); + void debug_print(); + void check_tabs(int); +}; + +class size_box : public pointer_box { +private: + char *size; +public: + size_box(char *, box *); + ~size_box(); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class font_box : public pointer_box { +private: + char *f; +public: + font_box(char *, box *); + ~font_box(); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class fat_box : public pointer_box { +public: + fat_box(box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class vmotion_box : public pointer_box { +private: + int n; // up is >= 0 +public: + vmotion_box(int, box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class hmotion_box : public pointer_box { + int n; +public: + hmotion_box(int, box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +box *split_text(char *); +box *make_script_box(box *, box *, box *); +box *make_mark_box(box *); +box *make_lineup_box(box *); +box *make_delim_box(char *, box *, char *); +box *make_sqrt_box(box *); +box *make_prime_box(box *); +box *make_over_box(box *, box *); +box *make_small_over_box(box *, box *); +box *make_limit_box(box *, box *, box *); +box *make_accent_box(box *, box *); +box *make_uaccent_box(box *, box *); +box *make_overline_box(box *); +box *make_underline_box(box *); +box *make_special_box(char *, box *); + +void set_space(int); +int set_gsize(const char *); +void set_gfont(const char *); +void set_grfont(const char *); +void set_gbfont(const char *); +const char *get_gfont(); +const char *get_grfont(); +const char *get_gbfont(); +void start_string(); +void output_string(); +void do_text(const char *); +void restore_compatibility(); +void set_script_reduction(int n); +void set_minimum_size(int n); +void set_param(const char *name, int value); + +void set_char_type(const char *type, char *ch); + +void init_char_table(); +void init_extensible(); +void define_extensible(const char *name, const char *ext, const char *top = 0, + const char *mid = 0, const char *bot = 0); diff --git a/gnu/usr.bin/groff/eqn/delim.cc b/gnu/usr.bin/groff/eqn/delim.cc new file mode 100644 index 0000000000..ecf9c557e0 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/delim.cc @@ -0,0 +1,380 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + +enum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 }; + +// Small must be none-zero and must exist in each device. +// Small will be put in the roman font, others are assumed to be +// on the special font (so no font change will be necessary.) + +struct delimiter { + const char *name; + int flags; + const char *small; + const char *chain_format; + const char *ext; + const char *top; + const char *mid; + const char *bot; +} delim_table[] = { + { + "(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]", + "\\[parenleftex]", + "\\[parenlefttp]", + 0, + "\\[parenleftbt]", + }, + { + ")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]", + "\\[parenrightex]", + "\\[parenrighttp]", + 0, + "\\[parenrightbt]", + }, + { + "[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]", + "\\[bracketleftex]", + "\\[bracketlefttp]", + 0, + "\\[bracketleftbt]", + }, + { + "]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]", + "\\[bracketrightex]", + "\\[bracketrighttp]", + 0, + "\\[bracketrightbt]", + }, + { + "{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]", + "\\[braceleftex]", + "\\[bracelefttp]", + "\\[braceleftmid]", + "\\[braceleftbt]", + }, + { + "}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]", + "\\[bracerightex]", + "\\[bracerighttp]", + "\\[bracerightmid]", + "\\[bracerightbt]", + }, + { + "|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]", + "\\[barex]", + }, + { + "floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]", + "\\[bracketleftex]", + 0, + 0, + "\\[bracketleftbt]", + }, + { + "floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]", + "\\[bracketrightex]", + 0, + 0, + "\\[bracketrightbt]", + }, + { + "ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]", + "\\[bracketleftex]", + "\\[bracketlefttp]", + }, + { + "ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]", + "\\[bracketrightex]", + "\\[bracketrighttp]", + }, + { + "||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]", + "\\[bardblex]", + }, + { + "<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]", + }, + { + ">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]", + }, + { + "uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]", + "\\[arrowvertex]", + "\\[arrowverttp]", + }, + { + "downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]", + "\\[arrowvertex]", + 0, + 0, + "\\[arrowvertbt]", + }, + { + "updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]", + "\\[arrowvertex]", + "\\[arrowverttp]", + 0, + "\\[arrowvertbt]", + }, +}; + +const int DELIM_TABLE_SIZE = int(sizeof(delim_table)/sizeof(delim_table[0])); + +class delim_box : public box { +private: + char *left; + char *right; + box *p; +public: + delim_box(char *, box *, char *); + ~delim_box(); + int compute_metrics(int); + void output(); + void check_tabs(int); + void debug_print(); +}; + +box *make_delim_box(char *l, box *pp, char *r) +{ + if (l != 0 && *l == '\0') { + a_delete l; + l = 0; + } + if (r != 0 && *r == '\0') { + a_delete r; + r = 0; + } + return new delim_box(l, pp, r); +} + +delim_box::delim_box(char *l, box *pp, char *r) +: left(l), right(r), p(pp) +{ +} + +delim_box::~delim_box() +{ + a_delete left; + a_delete right; + delete p; +} + +static void build_extensible(const char *ext, const char *top, const char *mid, + const char *bot) +{ + assert(ext != 0); + printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", + ext); + printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n"); + printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n"); + if (top) { + printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]" + ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", + top); + printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n"); + printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n"); + } + if (mid) { + printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]" + ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", + mid); + printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n"); + printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n"); + } + if (bot) { + printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]" + ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", + bot); + printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n"); + printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n"); + } + printf(".nr " TOTAL_HEIGHT_REG " 0"); + if (top) + printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]"); + if (bot) + printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]"); + if (mid) + printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]"); + printf("\n"); + // determine how many extensible characters we need + printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]"); + if (mid) + printf("/2"); + printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n[" + EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n"); + + printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n[" + EXT_DEPTH_REG "]*\\n[" TEMP_REG "]"); + if (mid) + printf("*2"); + printf(")\n"); + printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR + "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n", + axis_height); + if (top) + printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'" + "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR + "\\v'\\n[" TOP_DEPTH_REG "]u'\n", + top); + + // this macro appends $2 copies of $3 to string $1 + printf(".de " REPEAT_APPEND_STRING_MACRO "\n" + ".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n" + "." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n" + ".\\}\n" + "..\n"); + + printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] " + "\\v'\\n[" EXT_HEIGHT_REG "]u'" + "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR + "\\v'\\n[" EXT_DEPTH_REG "]u'\n", + ext); + + if (mid) { + printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'" + "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR + "\\v'\\n[" MID_DEPTH_REG "]u'\n", + mid); + printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING + " \\n[" TEMP_REG "] " + "\\v'\\n[" EXT_HEIGHT_REG "]u'" + "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR + "\\v'\\n[" EXT_DEPTH_REG "]u'\n", + ext); + } + if (bot) + printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'" + "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR + "\\v'\\n[" BOT_DEPTH_REG "]u'\n", + bot); + printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n"); +} + +static void define_extensible_string(char *delim, int uid, + left_or_right_t left_or_right) +{ + printf(".ds " DELIM_STRING "\n"); + delimiter *d = delim_table; + int delim_len = strlen(delim); + for (int i = 0; i < DELIM_TABLE_SIZE; i++, d++) + if (strncmp(delim, d->name, delim_len) == 0 + && (left_or_right & d->flags) != 0) + break; + if (i >= DELIM_TABLE_SIZE) { + error("there is no `%1' delimiter", delim); + printf(".nr " DELIM_WIDTH_REG " 0\n"); + return; + } + + printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n" + ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR + "\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n" + ".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n" + ".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] " + "\\{", + current_roman_font, d->small, axis_height, + current_roman_font, d->small); + + char buf[256]; + sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]"); + printf(".nr " INDEX_REG " 0\n" + ".de " TEMP_MACRO "\n" + ".ie c%s \\{\\\n" + ".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n" + ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR + "\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n" + ".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n" + ".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] " + "\\{.nr " INDEX_REG " +1\n" + "." TEMP_MACRO "\n" + ".\\}\\}\n" + ".el .nr " INDEX_REG " 0-1\n" + "..\n" + "." TEMP_MACRO "\n", + buf, buf, axis_height, buf); + if (d->ext) { + printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext); + build_extensible(d->ext, d->top, d->mid, d->bot); + printf(".\\}\\}\n"); + } + printf(".\\}\n"); + printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n"); + printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]" + ">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n", + uid, uid, axis_height); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]" + ">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n", + uid, uid, axis_height); +} + +int delim_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM" + ">?(\\n[" DEPTH_FORMAT "]+%dM)\n", + p->uid, axis_height, p->uid, axis_height); + printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500" + ">?(\\n[" DELTA_REG "]*2-%dM)\n", + delimiter_factor, delimiter_shortfall); + if (left) { + define_extensible_string(left, uid, LEFT_DELIM); + printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n", + uid); + } + if (r) + printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n"); + if (right) { + define_extensible_string(right, uid, RIGHT_DELIM); + printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n", + uid); + } + return r; +} + +void delim_box::output() +{ + if (left) + printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid); + p->output(); + if (right) + printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid); +} + +void delim_box::check_tabs(int level) +{ + p->check_tabs(level); +} + +void delim_box::debug_print() +{ + fprintf(stderr, "left \"%s\" { ", left ? left : ""); + p->debug_print(); + fprintf(stderr, " }"); + if (right) + fprintf(stderr, " right \"%s\"", right); +} + diff --git a/gnu/usr.bin/groff/eqn/eqn.1 b/gnu/usr.bin/groff/eqn/eqn.1 new file mode 100644 index 0000000000..1b9aa78fb6 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/eqn.1 @@ -0,0 +1,862 @@ +.\" -*- nroff -*- +.ie \n(.V<\n(.v .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X +.el .ds tx TeX +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.\" The BSD man macros can't handle " in arguments to font change macros, +.\" so use \(ts instead of ". +.tr \(ts" +.TH EQN 1 "6 October 1992" "Groff Version 1.08" +.SH NAME +eqn \- format equations for troff +.SH SYNOPSIS +.B eqn +[ +.B \-rvCNR +] +[ +.BI \-d cc +] +[ +.BI \-T name +] +[ +.BI \-M dir +] +[ +.BI \-f F +] +[ +.BI \-s n +] +[ +.BI \-p n +] +[ +.BI \-m n +] +[ +.IR files \|.\|.\|. +] +.SH DESCRIPTION +This manual page describes the GNU version of +.BR eqn , +which is part of the groff document formatting system. +.B eqn +compiles descriptions of equations embedded within +.B troff +input files into commands that are understood by +.BR troff . +Normally, it should be invoked using the +.B \-e +option of +.BR groff . +The syntax is quite compatible with Unix eqn. +The output of GNU eqn cannot be processed with Unix troff; +it must be processed with GNU troff. +If no files are given on the command line, the standard input +will be read. +A filename of +.B \- +will cause the standard input to be read. +.LP +.B eqn +searches for the file +.B eqnrc +using the path +.BR /usr/share/tmac . +If it exists, eqn will process it before the other input files. +The +.B \-R +option prevents this. +.LP +GNU eqn does not provide the functionality of neqn: +it does not support low-resolution, typewriter-like devices +(although it may work adequately for very simple input). +.SH OPTIONS +.TP +.B \-C +Recognize +.B .EQ +and +.B .EN +even when followed by a character other than space or newline. +.TP +.B \-N +Don't allow newlines within delimiters. +This option allows +.B eqn +to recover better from missing closing delimiters. +.TP +.B \-v +Print the version number. +.TP +.B \-r +Only one size reduction. +.TP +.BI \-m n +The minimum point-size is +.IR n . +eqn will not reduce the size of subscripts or superscripts to +a smaller size than +.IR n . +.TP +.BI \-T name +The output is for device +.IR name . +The only effect of this is to define a macro +.I name +with a value of +.BR 1 . +Typically +.B eqnrc +will use this to provide definitions appropriate for the output device. +The default output device is +.BR ps . +.TP +.BI \-M dir +Search +.I dir +for +.B eqnrc +before the default directories. +.TP +.B \-R +Don't load +.BR eqnrc . +.TP +.BI \-f F +This is equivalent to a +.BI gfont\ F +command. +.TP +.BI \-s n +This is equivalent to a +.BI gsize\ n +command. +This option is deprecated. +eqn will normally set equations at whatever the current point size +is when the equation is encountered. +.TP +.BI \-p n +This says that subscripts and superscripts should be +.I n +points smaller than the surrounding text. +This option is deprecated. +Normally eqn makes sets subscripts and superscripts at 70% +of the size of the surrounding text. +.SH USAGE +Only the differences between GNU eqn and Unix eqn are described here. +.LP +Most of the new features of GNU eqn +are based on \*(tx. +There are some references to the differences between \*(tx and GNU eqn below; +these may safely be ignored if you do not know \*(tx. +.SS Automatic spacing +.LP +.B eqn +gives each component of an equation a type, and adjusts the spacing +between components using that type. +Possible types are: +.TP \w'punctuation'u+2n +ordinary +an ordinary character such as 1 or +.IR x ; +.TP +operator +a large operator such as +.ds Su \s+5\(*S\s0 +.if \n(.g .if !c\(*S .ds Su the summation operator +\*(Su; +.TP +binary +a binary operator such as +; +.TP +relation +a relation such as =; +.TP +opening +a opening bracket such as (; +.TP +closing +a closing bracket such as ); +.TP +punctuation +a punctutation character such as ,; +.TP +inner +a subformula contained within brackets; +.TP +suppress +spacing that suppresses automatic spacing adjustment. +.LP +Components of an equation get a type in one of two ways. +.TP +.BI type\ t\ e +This yields an equation component that contains +.I e +but that has type +.IR t , +where +.I t +is one of the types mentioned above. +For example, +.B times +is defined as +.RS +.IP +.B +type "binary" \e(mu +.RE +.IP +The name of the type doesn't have to be quoted, but quoting protects +from macro expansion. +.TP +.BI chartype\ t\ text +Unquoted groups of characters are split up into individual characters, +and the type of each character is looked up; +this changes the type that is stored for each character; +it says that the characters in +.I text +from now on have type +.IR t . +For example, +.RS +.IP +.B +chartype "punctuation" .,;: +.RE +.IP +would make the characters +.B .,;: +have type punctuation +whenever they subsequently appeared in an equation. +The type +.I t +can also be +.B letter +or +.BR digit ; +in these cases +.B chartype +changes the font type of the characters. +See the Fonts subsection. +.SS New primitives +.TP +.IB e1\ smallover\ e2 +This is similar to +.BR over ; +.B smallover +reduces the size of +.I e1 +and +.IR e2 ; +it also puts less vertical space between +.I e1 +or +.I e2 +and the fraction bar. +The +.B over +primitive corresponds to the \*(tx +.B \eover +primitive in display styles; +.B smallover +corresponds to +.B \eover +in non-display styles. +.TP +.BI vcenter\ e +This vertically centers +.I e +about the math axis. +The math axis is the vertical position about which characters +such as + and - are centered; also it is the vertical position +used for the bar of fractions. +For example, +.B sum +is defined as +.RS +.IP +.B +{ type "operator" vcenter size +5 \e(*S } +.RE +.TP +.IB e1\ accent\ e2 +This sets +.I e2 +as an accent over +.IR e1 . +.I e2 +is assumed to be at the correct height for a lowercase letter; +.I e2 +will be moved down according if +.I e1 +is taller or shorter than a lowercase letter. +For example, +.B hat +is defined as +.RS +.IP +.B +accent { "^" } +.RE +.IP +.BR dotdot , +.BR dot , +.BR tilde , +.B vec +and +.B dyad +are also defined using the +.B accent +primitive. +.TP +.IB e1\ uaccent\ e2 +This sets +.I e2 +as an accent under +.IR e1 . +.I e2 +is assumed to be at the correct height for a character without a descender; +.I e2 +will be moved down if +.I e1 +has a descender. +.B utilde +is pre-defined using +.B uaccent +as a tilde accent below the baseline. +.TP +.BI split\ \(ts text \(ts +This has the same effect as simply +.RS +.IP +.I text +.RE +.IP +but +.I text +is not subject to macro expansion because it is quoted; +.I text +will be split up and the spacing between individual characters +will be adjusted. +.TP +.BI nosplit\ text +This has the same effect as +.RS +.IP +.BI \(ts text \(ts +.RE +.IP +but because +.I text +is not quoted it will be subject to macro expansion; +.I text +will not be split up +and the spacing between individual characters will not be adjusted. +.TP +.IB e\ opprime +This is a variant of +.B prime +that acts as an operator on +.IR e . +It produces a different result from +.B prime +in a case such as +.BR A\ opprime\ sub\ 1 : +with +.B opprime +the +.B 1 +will be tucked under the prime as a subscript to the +.B A +(as is conventional in mathematical typesetting), +whereas with +.B prime +the +.B 1 +will be a subscript to the prime character. +The precedence of +.B opprime +is the same as that of +.B bar +and +.BR under , +which is higher than that of everything except +.B accent +and +.BR uaccent . +In unquoted text a +.B ' +that is not the first character will be treated like +.BR opprime . +.TP +.BI special\ text\ e +This constructs a new object from +.I e +using a +.BR troff (1) +macro named +.IR text . +When the macro is called, +the string +.B 0s +will contain the output for +.IR e , +and the number registers +.BR 0w , +.BR 0h , +.BR 0d , +.BR 0skern +and +.BR 0skew +will contain the width, height, depth, subscript kern, and skew of +.IR e . +(The +.I "subscript kern" +of an object says how much a subscript on that object should be tucked in; +the +.I skew +of an object says how far to the right of the center of the object an +accent over the object should be placed.) +The macro must modify +.B 0s +so that it will output the desired result with its origin at the current +point, and increase the current horizontal position by the width +of the object. +The number registers must also be modified so that they correspond to the +result. +.RS +.LP +For example, suppose you wanted a construct that `cancels' an expression +by drawing a diagonal line through it. +.IP +.nf +.ft B +.ne 6+\n(.Vu +\&.EQ +define cancel 'special Ca' +\&.EN +\&.de Ca +\&.ds 0s \eZ'\e\e*(0s'\ev'\e\en(0du'\eD'l \e\en(0wu -\e\en(0hu-\e\en(0du'\ev'\e\en(0hu' +\&.. +.ft +.fi +.LP +Then you could cancel an expression +.I e +with +.BI cancel\ {\ e\ } +.LP +Here's a more complicated construct that draws a box round an expression: +.IP +.nf +.ft B +.ne 11+\n(.Vu +\&.EQ +define box 'special Bx' +\&.EN +\&.de Bx +\&.ds 0s \eZ'\eh'1n'\e\e*(0s'\e +\eZ'\ev'\e\en(0du+1n'\eD'l \e\en(0wu+2n 0'\eD'l 0 -\e\en(0hu-\e\en(0du-2n'\e +\eD'l -\e\en(0wu-2n 0'\eD'l 0 \e\en(0hu+\e\en(0du+2n''\eh'\e\en(0wu+2n' +\&.nr 0w +2n +\&.nr 0d +1n +\&.nr 0h +1n +\&.. +.ft +.fi +.RE +.SS Customization +The appearance of equations is controlled by +a large number of parameters. These can be set using +the +.B set +command. +.TP +.BI set\ p\ n +This sets parameter +.I p +to value +.I n ; +.I n +is an integer. +For example, +.RS +.IP +.B +set x_height 45 +.RE +.IP +says that +.B eqn +should assume an x height of 0.45 ems. +.RS +.LP +Possible parameters are as follows. +Values are in units of hundredths of an em unless otherwise stated. +These descriptions are intended to be expository rather than +definitive. +.TP \w'\fBdefault_rule_thickness'u+2n +.B minimum_size +.B eqn +will not set anything at a smaller point-size than this. +The value is in points. +.TP +.B fat_offset +The +.B fat +primitive emboldens an equation +by overprinting two copies of the equation +horizontally offset by this amount. +.TP +.B over_hang +A fraction bar will be longer by twice this amount than +the maximum of the widths of the numerator and denominator; +in other words, it will overhang the numerator and +denominator by at least this amount. +.TP +.B accent_width +When +.B bar +or +.B under +is applied to a single character, +the line will be this long. +Normally, +.B bar +or +.B under +produces a line whose length is the width of the object to which it applies; +in the case of a single character, +this tends to produce a line that looks too long. +.TP +.B delimiter_factor +Extensible delimiters produced with the +.B left +and +.B right +primitives will have a combined height and depth of at least this many +thousandths of twice the maximum amount by which the sub-equation that +the delimiters enclose extends away from the axis. +.TP +.B delimiter_shortfall +Extensible delimiters produced with the +.B left +and +.B right +primitives will have a combined height and depth +not less than the difference of +twice the maximum amount by which the sub-equation that +the delimiters enclose extends away from the axis +and this amount. +.TP +.B null_delimiter_space +This much horizontal space is inserted +on each side of a fraction. +.TP +.B script_space +The width of subscripts and superscripts is increased by this amount. +.TP +.B thin_space +This amount of space is automatically inserted after punctuation +characters. +.TP +.B medium_space +This amount of space is automatically inserted on either side +of binary operators. +.TP +.B thick_space +This amount of space is automatically inserted on either side of +relations. +.TP +.B x_height +The height of lowercase letters without ascenders such as x. +.TP +.B axis_height +The height above the baseline of the center of characters +such as \(pl and \(mi. +It is important that this value is correct for the font +you are using. +.TP +.B default_rule_thickness +This should set to the thickness of the +.B \e(ru +character, or the thickness of horizontal lines produced with the +.B \eD +escape sequence. +.TP +.B num1 +The +.B over +command will shift up the numerator by at least this amount. +.TP +.B num2 +The +.B smallover +command will shift up the numerator by at least this amount. +.TP +.B denom1 +The +.B over +command will shift down the denominator by at least this amount. +.TP +.B denom2 +The +.B smallover +command will shift down the denominator by at least this amount. +.TP +.B sup1 +Normally superscripts will be shifted up by at least this amount. +.TP +.B sup2 +Superscripts within superscripts or upper limits +or numerators of +.B smallover +fractions +will be shifted up by at least this amount. +This is usually less than sup1. +.TP +.B sup3 +Superscripts within denominators or square roots +or subscripts or lower limits will be shifted up by at least +this amount. +This is usually less than sup2. +.TP +.B sub1 +Subscripts will normally be shifted down by at least this amount. +.TP +.B sub2 +When there is both a subscript and a superscript, the subscript +will be shifted down by at least this amount. +.TP +.B sup_drop +The baseline of a superscript will be no more +than this much amount below the top of the object on +which the superscript is set. +.TP +.B sub_drop +The baseline of a subscript will be at least this much below +the bottom of the object on which the subscript is set. +.TP +.B big_op_spacing1 +The baseline of an upper limit will be at least this +much above the top of the object on which the limit is set. +.TP +.B big_op_spacing2 +The baseline of a lower limit will be at least this +much below the bottom of the object on which the limit is set. +.TP +.B big_op_spacing3 +The bottom of an upper limit will be at least this much above the +top of the object on which the limit is set. +.TP +.B big_op_spacing4 +The top of a lower limit will be at least this much below +the bottom of the object on which the limit is set. +.TP +.B big_op_spacing5 +This much vertical space will be added above and below limits. +.TP +.B baseline_sep +The baselines of the rows in a pile or matrix will normally be +this far apart. +In most cases this should be equal to the sum of +.B num1 +and +.BR denom1 . +.TP +.B shift_down +The midpoint between the top baseline and the bottom baseline +in a matrix or pile will be shifted down by this much from the axis. +In most cases this should be equal to +.BR axis_height . +.TP +.B column_sep +This much space will be added between columns in a matrix. +.TP +.B matrix_side_sep +This much space will be added at each side of a matrix. +.TP +.B draw_lines +If this is non-zero, lines will be drawn using the +.B \eD +escape sequence, rather than with the +.B \el +escape sequence and the +.B \e(ru +character. +.TP +.B body_height +The amount by which the height of the equation exceeds this +will be added as extra space before the line containing the equation +(using +.BR \ex .) +The default value is 85. +.TP +.B body_depth +The amount by which the depth of the equation exceeds this +will be added as extra space after the line containing the equation +(using +.BR \ex .) +The default value is 35. +.TP +.B nroff +If this is non-zero, +then +.B ndefine +will behave like +.B define +and +.B tdefine +will be ignored, +otherwise +.B tdefine +will behave like +.B define +and +.B ndefine +will be ignored. +The default value is 0 +(This is typically changed to 1 by the +.B eqnrc +file for the +.B ascii +and +.B latin1 +devices.) +.LP +A more precise description of the role of many of these +parameters can be found in Appendix H of +.IR The\ \*(txbook . +.RE +.SS Macros +Macros can take arguments. +In a macro body, +.BI $ n +where +.I n +is between 1 and 9, +will be replaced by the +.IR n-th +argument if the macro is called with arguments; +if there are fewer than +.I n +arguments, it will be replaced by nothing. +A word containing a left parenthesis where the part of the word +before the left parenthesis has been defined using the +.B define +command +will be recognized as a macro call with arguments; +characters following the left parenthesis +up to a matching right parenthesis will be treated as comma-separated +arguments; +commas inside nested parentheses do not terminate an argument. +.TP +.BI sdefine\ name\ X\ anything\ X +This is like the +.B define +command, but +.I name +will not be recognized if called with arguments. +.TP +.BI include\ \(ts file \(ts +Include the contents of +.IR file . +Lines of +.I file +beginning with +.B .EQ +or +.B .EN +will be ignored. +.TP +.BI ifdef\ name\ X\ anything\ X +If +.I name +has been defined by +.B define +(or has been automatically defined because +.I name +is the output device) +process +.IR anything ; +otherwise ignore +.IR anything . +.I X +can be any character not appearing in +.IR anything . +.SS Fonts +.B eqn +normally uses at least two fonts to set an equation: +an italic font for letters, +and a roman font for everything else. +The existing +.B gfont +command +changes the font that is used as the italic font. +By default this is +.BR I . +The font that is used as the roman font can be changed +using the new +.B grfont +command. +.TP +.BI grfont\ f +Set the roman font to +.IR f . +.LP +The +.B italic +primitive uses the current italic font set by +.BR gfont ; +the +.B roman +primitive uses the current roman font set by +.BR grfont . +There is also a new +.B gbfont +command, which changes the font used by the +.B bold +primitive. +If you only use the +.BR roman , +.B italic +and +.B bold +primitives to changes fonts within an equation, +you can change all the fonts used by your equations +just by using +.BR gfont , +.B grfont +and +.B gbfont +commands. +.LP +You can control which characters are treated as letters +(and therefore set in italics) by using the +.B chartype +command described above. +A type of +.B letter +will cause a character to be set in italic type. +A type of +.B digit +will cause a character to be set in roman type. +.SH FILES +.Tp \w'\fB/usr/share/tmac/eqnrc'u+2n +.B /usr/share/tmac/eqnrc +Initialization file. +.SH BUGS +Inline equations will be set at the point size that is current at the +beginning of the input line. +.SH "SEE ALSO" +.BR groff (1), +.BR troff (1), +.BR groff_font (5), +.I The\ \*(txbook diff --git a/gnu/usr.bin/groff/eqn/eqn.h b/gnu/usr.bin/groff/eqn/eqn.h new file mode 100644 index 0000000000..e854a6be2e --- /dev/null +++ b/gnu/usr.bin/groff/eqn/eqn.h @@ -0,0 +1,51 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include "cset.h" +#include "errarg.h" +#include "error.h" +#include "lib.h" + +#include "box.h" + +extern char start_delim; +extern char end_delim; +extern int non_empty_flag; +extern int inline_flag; +extern int draw_flag; +extern int one_size_reduction_flag; +extern int compatible_flag; +extern int nroff; + +void init_lex(const char *str, const char *filename, int lineno); +void lex_error(const char *message, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +void init_table(const char *device); + +// prefix for all registers, strings, macros +#define PREFIX "0" diff --git a/gnu/usr.bin/groff/eqn/eqn.y b/gnu/usr.bin/groff/eqn/eqn.y new file mode 100644 index 0000000000..28011fbd9f --- /dev/null +++ b/gnu/usr.bin/groff/eqn/eqn.y @@ -0,0 +1,331 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +%{ +#include +#include +#include + +#include "lib.h" +#include "box.h" +extern int non_empty_flag; +char *strsave(const char *); +int yylex(); +void yyerror(const char *); +%} + +%union { + char *str; + box *b; + pile_box *pb; + matrix_box *mb; + int n; + column *col; +} + +%token OVER +%token SMALLOVER +%token SQRT +%token SUB +%token SUP +%token LPILE +%token RPILE +%token CPILE +%token PILE +%token LEFT +%token RIGHT +%token TO +%token FROM +%token SIZE +%token FONT +%token ROMAN +%token BOLD +%token ITALIC +%token FAT +%token ACCENT +%token BAR +%token UNDER +%token ABOVE +%token TEXT +%token QUOTED_TEXT +%token FWD +%token BACK +%token DOWN +%token UP +%token MATRIX +%token COL +%token LCOL +%token RCOL +%token CCOL +%token MARK +%token LINEUP +%token TYPE +%token VCENTER +%token PRIME +%token SPLIT +%token NOSPLIT +%token UACCENT +%token SPECIAL + +/* these are handled in the lexer */ +%token SPACE +%token GFONT +%token GSIZE +%token DEFINE +%token NDEFINE +%token TDEFINE +%token SDEFINE +%token UNDEF +%token IFDEF +%token INCLUDE +%token DELIM +%token CHARTYPE +%token SET +%token GRFONT +%token GBFONT + +/* The original eqn manual says that `left' is right associative. It's lying. +Consider `left ( ~ left ( ~ right ) right )'. */ + +%right LEFT +%left RIGHT +%right LPILE RPILE CPILE PILE TEXT QUOTED_TEXT MATRIX MARK LINEUP '^' '~' '\t' '{' SPLIT NOSPLIT +%right FROM TO +%left SQRT OVER SMALLOVER +%right SUB SUP +%right ROMAN BOLD ITALIC FAT FONT SIZE FWD BACK DOWN UP TYPE VCENTER SPECIAL +%right BAR UNDER PRIME +%left ACCENT UACCENT + +%type mark from_to sqrt_over script simple equation nonsup +%type number +%type text delim +%type pile_element_list pile_arg +%type column_list +%type column column_arg column_element_list + +%% +top: + /* empty */ + | equation + { $1->top_level(); non_empty_flag = 1; } + ; + +equation: + mark + { $$ = $1; } + | equation mark + { + list_box *lb = $1->to_list_box(); + if (!lb) + lb = new list_box($1); + lb->append($2); + $$ = lb; + } + ; + +mark: + from_to + { $$ = $1; } + | MARK mark + { $$ = make_mark_box($2); } + | LINEUP mark + { $$ = make_lineup_box($2); } + ; + +from_to: + sqrt_over %prec FROM + { $$ = $1; } + | sqrt_over TO from_to + { $$ = make_limit_box($1, 0, $3); } + | sqrt_over FROM sqrt_over + { $$ = make_limit_box($1, $3, 0); } + | sqrt_over FROM sqrt_over TO from_to + { $$ = make_limit_box($1, $3, $5); } + | sqrt_over FROM sqrt_over FROM from_to + { $$ = make_limit_box($1, make_limit_box($3, $5, 0), 0); } + ; + +sqrt_over: + script + { $$ = $1; } + | SQRT sqrt_over + { $$ = make_sqrt_box($2); } + | sqrt_over OVER sqrt_over + { $$ = make_over_box($1, $3); } + | sqrt_over SMALLOVER sqrt_over + { $$ = make_small_over_box($1, $3); } + ; + +script: + nonsup + { $$ = $1; } + | simple SUP script + { $$ = make_script_box($1, 0, $3); } + ; + +nonsup: + simple %prec SUP + { $$ = $1; } + | simple SUB nonsup + { $$ = make_script_box($1, $3, 0); } + | simple SUB simple SUP script + { $$ = make_script_box($1, $3, $5); } + ; + +simple: + TEXT + { $$ = split_text($1); } + | QUOTED_TEXT + { $$ = new quoted_text_box($1); } + | SPLIT QUOTED_TEXT + { $$ = split_text($2); } + | NOSPLIT TEXT + { $$ = new quoted_text_box($2); } + | '^' + { $$ = new half_space_box; } + | '~' + { $$ = new space_box; } + | '\t' + { $$ = new tab_box; } + | '{' equation '}' + { $$ = $2; } + | PILE pile_arg + { $2->set_alignment(CENTER_ALIGN); $$ = $2; } + | LPILE pile_arg + { $2->set_alignment(LEFT_ALIGN); $$ = $2; } + | RPILE pile_arg + { $2->set_alignment(RIGHT_ALIGN); $$ = $2; } + | CPILE pile_arg + { $2->set_alignment(CENTER_ALIGN); $$ = $2; } + | MATRIX '{' column_list '}' + { $$ = $3; } + | LEFT delim equation RIGHT delim + { $$ = make_delim_box($2, $3, $5); } + | LEFT delim equation + { $$ = make_delim_box($2, $3, 0); } + | simple BAR + { $$ = make_overline_box($1); } + | simple UNDER + { $$ = make_underline_box($1); } + | simple PRIME + { $$ = make_prime_box($1); } + | simple ACCENT simple + { $$ = make_accent_box($1, $3); } + | simple UACCENT simple + { $$ = make_uaccent_box($1, $3); } + | ROMAN simple + { $$ = new font_box(strsave(get_grfont()), $2); } + | BOLD simple + { $$ = new font_box(strsave(get_gbfont()), $2); } + | ITALIC simple + { $$ = new font_box(strsave(get_gfont()), $2); } + | FAT simple + { $$ = new fat_box($2); } + | FONT text simple + { $$ = new font_box($2, $3); } + | SIZE text simple + { $$ = new size_box($2, $3); } + | FWD number simple + { $$ = new hmotion_box($2, $3); } + | BACK number simple + { $$ = new hmotion_box(-$2, $3); } + | UP number simple + { $$ = new vmotion_box($2, $3); } + | DOWN number simple + { $$ = new vmotion_box(-$2, $3); } + | TYPE text simple + { $3->set_spacing_type($2); $$ = $3; } + | VCENTER simple + { $$ = new vcenter_box($2); } + | SPECIAL text simple + { $$ = make_special_box($2, $3); } + ; + +number: + text + { + int n; + if (sscanf($1, "%d", &n) == 1) + $$ = n; + a_delete $1; + } + ; + +pile_element_list: + equation + { $$ = new pile_box($1); } + | pile_element_list ABOVE equation + { $1->append($3); $$ = $1; } + ; + +pile_arg: + '{' pile_element_list '}' + { $$ = $2; } + | number '{' pile_element_list '}' + { $3->set_space($1); $$ = $3; } + ; + +column_list: + column + { $$ = new matrix_box($1); } + | column_list column + { $1->append($2); $$ = $1; } + ; + +column_element_list: + equation + { $$ = new column($1); } + | column_element_list ABOVE equation + { $1->append($3); $$ = $1; } + ; + +column_arg: + '{' column_element_list '}' + { $$ = $2; } + | number '{' column_element_list '}' + { $3->set_space($1); $$ = $3; } + ; + +column: + COL column_arg + { $2->set_alignment(CENTER_ALIGN); $$ = $2; } + | LCOL column_arg + { $2->set_alignment(LEFT_ALIGN); $$ = $2; } + | RCOL column_arg + { $2->set_alignment(RIGHT_ALIGN); $$ = $2; } + | CCOL column_arg + { $2->set_alignment(CENTER_ALIGN); $$ = $2; } + ; + +text: TEXT + { $$ = $1; } + | QUOTED_TEXT + { $$ = $1; } + ; + +delim: + text + { $$ = $1; } + | '{' + { $$ = strsave("{"); } + | '}' + { $$ = strsave("}"); } + ; + +%% diff --git a/gnu/usr.bin/groff/eqn/lex.cc b/gnu/usr.bin/groff/eqn/lex.cc new file mode 100644 index 0000000000..910db77f56 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/lex.cc @@ -0,0 +1,1160 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "eqn.tab.h" +#include "stringclass.h" +#include "ptable.h" + +struct definition { + char is_macro; + char is_simple; + union { + int tok; + char *contents; + }; + definition(); + ~definition(); +}; + +definition::definition() : is_macro(1), is_simple(0) +{ + contents = 0; +} + +definition::~definition() +{ + if (is_macro) + a_delete contents; +} + +declare_ptable(definition) +implement_ptable(definition) + +PTABLE(definition) macro_table; + +static struct { + const char *name; + int token; +} token_table[] = { + "over", OVER, + "smallover", SMALLOVER, + "sqrt", SQRT, + "sub", SUB, + "sup", SUP, + "lpile", LPILE, + "rpile", RPILE, + "cpile", CPILE, + "pile", PILE, + "left", LEFT, + "right", RIGHT, + "to", TO, + "from", FROM, + "size", SIZE, + "font", FONT, + "roman", ROMAN, + "bold", BOLD, + "italic", ITALIC, + "fat", FAT, + "bar", BAR, + "under", UNDER, + "accent", ACCENT, + "uaccent", UACCENT, + "above", ABOVE, + "fwd", FWD, + "back", BACK, + "down", DOWN, + "up", UP, + "matrix", MATRIX, + "col", COL, + "lcol", LCOL, + "rcol", RCOL, + "ccol", CCOL, + "mark", MARK, + "lineup", LINEUP, + "space", SPACE, + "gfont", GFONT, + "gsize", GSIZE, + "define", DEFINE, + "sdefine", SDEFINE, + "ndefine", NDEFINE, + "tdefine", TDEFINE, + "undef", UNDEF, + "ifdef", IFDEF, + "include", INCLUDE, + "copy", INCLUDE, + "delim", DELIM, + "chartype", CHARTYPE, + "type", TYPE, + "vcenter", VCENTER, + "set", SET, + "opprime", PRIME, + "grfont", GRFONT, + "gbfont", GBFONT, + "split", SPLIT, + "nosplit", NOSPLIT, + "special", SPECIAL, +}; + +static struct { + const char *name; + const char *def; +} def_table[] = { + "ALPHA", "\\(*A", + "BETA", "\\(*B", + "CHI", "\\(*X", + "DELTA", "\\(*D", + "EPSILON", "\\(*E", + "ETA", "\\(*Y", + "GAMMA", "\\(*G", + "IOTA", "\\(*I", + "KAPPA", "\\(*K", + "LAMBDA", "\\(*L", + "MU", "\\(*M", + "NU", "\\(*N", + "OMEGA", "\\(*W", + "OMICRON", "\\(*O", + "PHI", "\\(*F", + "PI", "\\(*P", + "PSI", "\\(*Q", + "RHO", "\\(*R", + "SIGMA", "\\(*S", + "TAU", "\\(*T", + "THETA", "\\(*H", + "UPSILON", "\\(*U", + "XI", "\\(*C", + "ZETA", "\\(*Z", + "Alpha", "\\(*A", + "Beta", "\\(*B", + "Chi", "\\(*X", + "Delta", "\\(*D", + "Epsilon", "\\(*E", + "Eta", "\\(*Y", + "Gamma", "\\(*G", + "Iota", "\\(*I", + "Kappa", "\\(*K", + "Lambda", "\\(*L", + "Mu", "\\(*M", + "Nu", "\\(*N", + "Omega", "\\(*W", + "Omicron", "\\(*O", + "Phi", "\\(*F", + "Pi", "\\(*P", + "Psi", "\\(*Q", + "Rho", "\\(*R", + "Sigma", "\\(*S", + "Tau", "\\(*T", + "Theta", "\\(*H", + "Upsilon", "\\(*U", + "Xi", "\\(*C", + "Zeta", "\\(*Z", + "alpha", "\\(*a", + "beta", "\\(*b", + "chi", "\\(*x", + "delta", "\\(*d", + "epsilon", "\\(*e", + "eta", "\\(*y", + "gamma", "\\(*g", + "iota", "\\(*i", + "kappa", "\\(*k", + "lambda", "\\(*l", + "mu", "\\(*m", + "nu", "\\(*n", + "omega", "\\(*w", + "omicron", "\\(*o", + "phi", "\\(*f", + "pi", "\\(*p", + "psi", "\\(*q", + "rho", "\\(*r", + "sigma", "\\(*s", + "tau", "\\(*t", + "theta", "\\(*h", + "upsilon", "\\(*u", + "xi", "\\(*c", + "zeta", "\\(*z", + "max", "{type \"operator\" roman \"max\"}", + "min", "{type \"operator\" roman \"min\"}", + "lim", "{type \"operator\" roman \"lim\"}", + "sin", "{type \"operator\" roman \"sin\"}", + "cos", "{type \"operator\" roman \"cos\"}", + "tan", "{type \"operator\" roman \"tan\"}", + "sinh", "{type \"operator\" roman \"sinh\"}", + "cosh", "{type \"operator\" roman \"cosh\"}", + "tanh", "{type \"operator\" roman \"tanh\"}", + "arc", "{type \"operator\" roman \"arc\"}", + "log", "{type \"operator\" roman \"log\"}", + "ln", "{type \"operator\" roman \"ln\"}", + "exp", "{type \"operator\" roman \"exp\"}", + "Re", "{type \"operator\" roman \"Re\"}", + "Im", "{type \"operator\" roman \"Im\"}", + "det", "{type \"operator\" roman \"det\"}", + "and", "{roman \"and\"}", + "if", "{roman \"if\"}", + "for", "{roman \"for\"}", + "sum", "{type \"operator\" vcenter size +5 \\(*S}", + "prod", "{type \"operator\" vcenter size +5 \\(*P}", + "int", "{type \"operator\" vcenter size +8 \\(is}", + "union", "{type \"operator\" vcenter size +5 \\(cu}", + "inter", "{type \"operator\" vcenter size +5 \\(ca}", + "times", "type \"binary\" \\(mu", + "ldots", "type \"inner\" { . . . }", + "inf", "\\(if", + "partial", "\\(pd", + "nothing", "\"\"", + "half", "{1 smallover 2}", + "hat_def", "roman \"^\"", + "hat", "accent { hat_def }", + "dot_def", "back 15 \"\\v'-52M'.\\v'52M'\"", + "dot", "accent { dot_def }", + "dotdot_def", "back 25 \"\\v'-52M'..\\v'52M'\"", + "dotdot", "accent { dotdot_def }", + "tilde_def", "\"~\"", + "tilde", "accent { tilde_def }", + "utilde_def", "\"\\v'75M'~\\v'-75M'\"", + "utilde", "uaccent { utilde_def }", + "vec_def", "up 52 size -5 \\(->", + "vec", "accent { vec_def }", + "dyad_def", "up 52 size -5 {\\(<- back 60 \\(->}", + "dyad", "accent { dyad_def }", + "==", "type \"relation\" \\(==", + "!=", "type \"relation\" \\(!=", + "+-", "type \"binary\" \\(+-", + "->", "type \"relation\" \\(->", + "<-", "type \"relation\" \\(<-", + "<<", "{ < back 20 < }", + ">>", "{ > back 20 > }", + "...", "type \"inner\" vcenter { . . . }", + "prime", "'", + "approx", "type \"relation\" \"\\(~=\"", + "grad", "\\(gr", + "del", "\\(gr", + "cdot", "type \"binary\" vcenter .", + "dollar", "$", +}; + +void init_table(const char *device) +{ + for (int i = 0; i < sizeof(token_table)/sizeof(token_table[0]); i++) { + definition *def = new definition; + def->is_macro = 0; + def->tok = token_table[i].token; + macro_table.define(token_table[i].name, def); + } + for (i = 0; i < sizeof(def_table)/sizeof(def_table[0]); i++) { + definition *def = new definition; + def->is_macro = 1; + def->contents = strsave(def_table[i].def); + def->is_simple = 1; + macro_table.define(def_table[i].name, def); + } + definition *def = new definition; + def->is_macro = 1; + def->contents = strsave("1"); + macro_table.define(device, def); +} + +class input { + input *next; +public: + input(input *p); + virtual ~input(); + virtual int get() = 0; + virtual int peek() = 0; + virtual int get_location(char **, int *); + + friend int get_char(); + friend int peek_char(); + friend int get_location(char **, int *); + friend void init_lex(const char *str, const char *filename, int lineno); +}; + +class file_input : public input { + FILE *fp; + char *filename; + int lineno; + string line; + const char *ptr; + int read_line(); +public: + file_input(FILE *, const char *, input *); + ~file_input(); + int get(); + int peek(); + int get_location(char **, int *); +}; + + +class macro_input : public input { + char *s; + char *p; +public: + macro_input(const char *, input *); + ~macro_input(); + int get(); + int peek(); +}; + +class top_input : public macro_input { + char *filename; + int lineno; + public: + top_input(const char *, const char *, int, input *); + ~top_input(); + int get(); + int get_location(char **, int *); +}; + +class argument_macro_input: public input { + char *s; + char *p; + char *ap; + int argc; + char *argv[9]; +public: + argument_macro_input(const char *, int, char **, input *); + ~argument_macro_input(); + int get(); + int peek(); +}; + +input::input(input *x) : next(x) +{ +} + +input::~input() +{ +} + +int input::get_location(char **, int *) +{ + return 0; +} + +file_input::file_input(FILE *f, const char *fn, input *p) +: input(p), lineno(0), ptr("") +{ + fp = f; + filename = strsave(fn); +} + +file_input::~file_input() +{ + a_delete filename; + fclose(fp); +} + +int file_input::read_line() +{ + for (;;) { + line.clear(); + lineno++; + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + else if (illegal_input_char(c)) + lex_error("illegal input character code %1", c); + else { + line += char(c); + if (c == '\n') + break; + } + } + if (line.length() == 0) + return 0; + if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'E' + && (line[2] == 'Q' || line[2] == 'N') + && (line.length() == 3 || line[3] == ' ' || line[3] == '\n' + || compatible_flag))) { + line += '\0'; + ptr = line.contents(); + return 1; + } + } +} + +int file_input::get() +{ + if (*ptr != '\0' || read_line()) + return *ptr++ & 0377; + else + return EOF; +} + +int file_input::peek() +{ + if (*ptr != '\0' || read_line()) + return *ptr; + else + return EOF; +} + +int file_input::get_location(char **fnp, int *lnp) +{ + *fnp = filename; + *lnp = lineno; + return 1; +} + +macro_input::macro_input(const char *str, input *x) : input(x) +{ + p = s = strsave(str); +} + +macro_input::~macro_input() +{ + a_delete s; +} + +int macro_input::get() +{ + if (p == 0 || *p == '\0') + return EOF; + else + return *p++ & 0377; +} + +int macro_input::peek() +{ + if (p == 0 || *p == '\0') + return EOF; + else + return *p & 0377; +} + +top_input::top_input(const char *str, const char *fn, int ln, input *x) +: macro_input(str, x), lineno(ln) +{ + filename = strsave(fn); +} + +top_input::~top_input() +{ + a_delete filename; +} + +int top_input::get() +{ + int c = macro_input::get(); + if (c == '\n') + lineno++; + return c; +} + +int top_input::get_location(char **fnp, int *lnp) +{ + *fnp = filename; + *lnp = lineno; + return 1; +} + +// Character respresenting $1. Must be illegal input character. +#define ARG1 14 + +argument_macro_input::argument_macro_input(const char *body, int ac, + char **av, input *x) +: input(x), argc(ac), ap(0) +{ + for (int i = 0; i < argc; i++) + argv[i] = av[i]; + p = s = strsave(body); + int j = 0; + for (i = 0; s[i] != '\0'; i++) + if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') { + if (s[i+1] != '0') + s[j++] = ARG1 + s[++i] - '1'; + } + else + s[j++] = s[i]; + s[j] = '\0'; +} + + +argument_macro_input::~argument_macro_input() +{ + for (int i = 0; i < argc; i++) + a_delete argv[i]; + a_delete s; +} + +int argument_macro_input::get() +{ + if (ap) { + if (*ap != '\0') + return *ap++ & 0377; + ap = 0; + } + if (p == 0) + return EOF; + while (*p >= ARG1 && *p <= ARG1 + 8) { + int i = *p++ - ARG1; + if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { + ap = argv[i]; + return *ap++ & 0377; + } + } + if (*p == '\0') + return EOF; + return *p++ & 0377; +} + +int argument_macro_input::peek() +{ + if (ap) { + if (*ap != '\0') + return *ap & 0377; + ap = 0; + } + if (p == 0) + return EOF; + while (*p >= ARG1 && *p <= ARG1 + 8) { + int i = *p++ - ARG1; + if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { + ap = argv[i]; + return *ap & 0377; + } + } + if (*p == '\0') + return EOF; + return *p & 0377; +} + +static input *current_input = 0; + +/* we insert a newline between input from different levels */ + +int get_char() +{ + if (current_input == 0) + return EOF; + else { + int c = current_input->get(); + if (c != EOF) + return c; + else { + input *tem = current_input; + current_input = current_input->next; + delete tem; + return '\n'; + } + } +} + +int peek_char() +{ + if (current_input == 0) + return EOF; + else { + int c = current_input->peek(); + if (c != EOF) + return c; + else + return '\n'; + } +} + +int get_location(char **fnp, int *lnp) +{ + for (input *p = current_input; p; p = p->next) + if (p->get_location(fnp, lnp)) + return 1; + return 0; +} + +string token_buffer; +const int NCONTEXT = 4; +string context_ring[NCONTEXT]; +int context_index = 0; + +void flush_context() +{ + for (int i = 0; i < NCONTEXT; i++) + context_ring[i] = ""; + context_index = 0; +} + +void show_context() +{ + int i = context_index; + fputs(" context is\n\t", stderr); + for (;;) { + int j = (i + 1) % NCONTEXT; + if (j == context_index) { + fputs(">>> ", stderr); + put_string(context_ring[i], stderr); + fputs(" <<<", stderr); + break; + } + else if (context_ring[i].length() > 0) { + put_string(context_ring[i], stderr); + putc(' ', stderr); + } + i = j; + } + putc('\n', stderr); +} + +void add_context(const string &s) +{ + context_ring[context_index] = s; + context_index = (context_index + 1) % NCONTEXT; +} + +void add_context(char c) +{ + context_ring[context_index] = c; + context_index = (context_index + 1) % NCONTEXT; +} + +void add_quoted_context(const string &s) +{ + string &r = context_ring[context_index]; + r = '"'; + for (int i = 0; i < s.length(); i++) + if (s[i] == '"') + r += "\\\""; + else + r += s[i]; + r += '"'; + context_index = (context_index + 1) % NCONTEXT; +} + +void init_lex(const char *str, const char *filename, int lineno) +{ + while (current_input != 0) { + input *tem = current_input; + current_input = current_input->next; + delete tem; + } + current_input = new top_input(str, filename, lineno, 0); + flush_context(); +} + + +void get_delimited_text() +{ + char *filename; + int lineno; + int got_location = get_location(&filename, &lineno); + int start = get_char(); + while (start == ' ' || start == '\t' || start == '\n') + start = get_char(); + token_buffer.clear(); + if (start == EOF) { + if (got_location) + error_with_file_and_line(filename, lineno, + "end of input while defining macro"); + else + error("end of input while defining macro"); + return; + } + for (;;) { + int c = get_char(); + if (c == EOF) { + if (got_location) + error_with_file_and_line(filename, lineno, + "end of input while defining macro"); + else + error("end of input while defining macro"); + add_context(start + token_buffer); + return; + } + if (c == start) + break; + token_buffer += char(c); + } + add_context(start + token_buffer + start); +} + +void interpolate_macro_with_args(const char *body) +{ + char *argv[9]; + int argc = 0; + for (int i = 0; i < 9; i++) + argv[i] = 0; + int level = 0; + int c; + do { + token_buffer.clear(); + for (;;) { + c = get_char(); + if (c == EOF) { + lex_error("end of input while scanning macro arguments"); + break; + } + if (level == 0 && (c == ',' || c == ')')) { + if (token_buffer.length() > 0) { + token_buffer += '\0'; + argv[argc] = strsave(token_buffer.contents()); + } + // for `foo()', argc = 0 + if (argc > 0 || c != ')' || i > 0) + argc++; + break; + } + token_buffer += char(c); + if (c == '(') + level++; + else if (c == ')') + level--; + } + } while (c != ')' && c != EOF); + current_input = new argument_macro_input(body, argc, argv, current_input); +} + +/* If lookup flag is non-zero the token will be looked up to see +if it is macro. If it's 1, it will looked up to see if it's a token. +*/ + +int get_token(int lookup_flag = 0) +{ + for (;;) { + int c = get_char(); + while (c == ' ' || c == '\n') + c = get_char(); + switch (c) { + case EOF: + add_context("end of input"); + return 0; + case '"': + { + int quoted = 0; + token_buffer.clear(); + for (;;) { + c = get_char(); + if (c == EOF) { + lex_error("missing \""); + break; + } + else if (c == '\n') { + lex_error("newline before end of quoted text"); + break; + } + else if (c == '"') { + if (!quoted) + break; + token_buffer[token_buffer.length() - 1] = '"'; + quoted = 0; + } + else { + token_buffer += c; + quoted = quoted ? 0 : c == '\\'; + } + } + } + add_quoted_context(token_buffer); + return QUOTED_TEXT; + case '{': + case '}': + case '^': + case '~': + case '\t': + add_context(c); + return c; + default: + { + int break_flag = 0; + int quoted = 0; + token_buffer.clear(); + if (c == '\\') + quoted = 1; + else + token_buffer += c; + int done = 0; + while (!done) { + c = peek_char(); + if (!quoted && lookup_flag != 0 && c == '(') { + token_buffer += '\0'; + definition *def = macro_table.lookup(token_buffer.contents()); + if (def && def->is_macro && !def->is_simple) { + (void)get_char(); // skip initial '(' + interpolate_macro_with_args(def->contents); + break_flag = 1; + break; + } + token_buffer.set_length(token_buffer.length() - 1); + } + if (quoted) { + quoted = 0; + switch (c) { + case EOF: + lex_error("`\\' ignored at end of equation"); + done = 1; + break; + case '\n': + lex_error("`\\' ignored because followed by newline"); + done = 1; + break; + case '\t': + lex_error("`\\' ignored because followed by tab"); + done = 1; + break; + case '"': + (void)get_char(); + token_buffer += '"'; + break; + default: + (void)get_char(); + token_buffer += '\\'; + token_buffer += c; + break; + } + } + else { + switch (c) { + case EOF: + case '{': + case '}': + case '^': + case '~': + case '"': + case ' ': + case '\t': + case '\n': + done = 1; + break; + case '\\': + (void)get_char(); + quoted = 1; + break; + default: + (void)get_char(); + token_buffer += char(c); + break; + } + } + } + if (break_flag || token_buffer.length() == 0) + break; + if (lookup_flag != 0) { + token_buffer += '\0'; + definition *def = macro_table.lookup(token_buffer.contents()); + token_buffer.set_length(token_buffer.length() - 1); + if (def) { + if (def->is_macro) { + current_input = new macro_input(def->contents, current_input); + break; + } + else if (lookup_flag == 1) { + add_context(token_buffer); + return def->tok; + } + } + } + add_context(token_buffer); + return TEXT; + } + } + } +} + +void do_include() +{ + int t = get_token(2); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad filename for include"); + return; + } + token_buffer += '\0'; + const char *filename = token_buffer.contents(); + errno = 0; + FILE *fp = fopen(filename, "r"); + if (fp == 0) { + lex_error("can't open included file `%1'", filename); + return; + } + current_input = new file_input(fp, filename, current_input); +} + +void ignore_definition() +{ + int t = get_token(); + if (t != TEXT) { + lex_error("bad definition"); + return; + } + get_delimited_text(); +} + +void do_definition(int is_simple) +{ + int t = get_token(); + if (t != TEXT) { + lex_error("bad definition"); + return; + } + token_buffer += '\0'; + const char *name = token_buffer.contents(); + definition *def = macro_table.lookup(name); + if (def == 0) { + def = new definition; + macro_table.define(name, def); + } + else if (def->is_macro) { + a_delete def->contents; + } + get_delimited_text(); + token_buffer += '\0'; + def->is_macro = 1; + def->contents = strsave(token_buffer.contents()); + def->is_simple = is_simple; +} + +void do_undef() +{ + int t = get_token(); + if (t != TEXT) { + lex_error("bad undef command"); + return; + } + token_buffer += '\0'; + macro_table.define(token_buffer.contents(), 0); +} + +void do_gsize() +{ + int t = get_token(2); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad argument to gsize command"); + return; + } + token_buffer += '\0'; + if (!set_gsize(token_buffer.contents())) + lex_error("invalid size `%1'", token_buffer.contents()); +} + +void do_gfont() +{ + int t = get_token(2); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad argument to gfont command"); + return; + } + token_buffer += '\0'; + set_gfont(token_buffer.contents()); +} + +void do_grfont() +{ + int t = get_token(2); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad argument to grfont command"); + return; + } + token_buffer += '\0'; + set_grfont(token_buffer.contents()); +} + +void do_gbfont() +{ + int t = get_token(2); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad argument to gbfont command"); + return; + } + token_buffer += '\0'; + set_gbfont(token_buffer.contents()); +} + +void do_space() +{ + int t = get_token(2); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad argument to space command"); + return; + } + token_buffer += '\0'; + char *ptr; + long n = strtol(token_buffer.contents(), &ptr, 10); + if (n == 0 && ptr == token_buffer.contents()) + lex_error("bad argument `%1' to space command"); + else + set_space(int(n)); +} + +void do_ifdef() +{ + int t = get_token(); + if (t != TEXT) { + lex_error("bad ifdef"); + return; + } + token_buffer += '\0'; + definition *def = macro_table.lookup(token_buffer.contents()); + int result = def && def->is_macro && !def->is_simple; + get_delimited_text(); + if (result) { + token_buffer += '\0'; + current_input = new macro_input(token_buffer.contents(), current_input); + } +} + +void do_delim() +{ + int c = get_char(); + while (c == ' ' || c == '\n') + c = get_char(); + int d; + if (c == EOF || (d = get_char()) == EOF) + lex_error("end of file while reading argument to `delim'"); + else { + if (c == 'o' && d == 'f' && peek_char() == 'f') { + (void)get_char(); + start_delim = end_delim = '\0'; + } + else { + start_delim = c; + end_delim = d; + } + } +} + +void do_chartype() +{ + int t = get_token(2); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad chartype"); + return; + } + token_buffer += '\0'; + string type = token_buffer; + t = get_token(); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad chartype"); + return; + } + token_buffer += '\0'; + set_char_type(type.contents(), strsave(token_buffer.contents())); +} + +void do_set() +{ + int t = get_token(2); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad set"); + return; + } + token_buffer += '\0'; + string param = token_buffer; + t = get_token(); + if (t != TEXT && t != QUOTED_TEXT) { + lex_error("bad set"); + return; + } + token_buffer += '\0'; + int n; + if (sscanf(&token_buffer[0], "%d", &n) != 1) { + lex_error("bad number `%1'", token_buffer.contents()); + return; + } + set_param(param.contents(), n); +} + +int yylex() +{ + for (;;) { + int tk = get_token(1); + switch(tk) { + case UNDEF: + do_undef(); + break; + case SDEFINE: + do_definition(1); + break; + case DEFINE: + do_definition(0); + break; + case TDEFINE: + if (!nroff) + do_definition(0); + else + ignore_definition(); + break; + case NDEFINE: + if (nroff) + do_definition(0); + else + ignore_definition(); + break; + case GSIZE: + do_gsize(); + break; + case GFONT: + do_gfont(); + break; + case GRFONT: + do_grfont(); + break; + case GBFONT: + do_gbfont(); + break; + case SPACE: + do_space(); + break; + case INCLUDE: + do_include(); + break; + case IFDEF: + do_ifdef(); + break; + case DELIM: + do_delim(); + break; + case CHARTYPE: + do_chartype(); + break; + case SET: + do_set(); + break; + case QUOTED_TEXT: + case TEXT: + token_buffer += '\0'; + yylval.str = strsave(token_buffer.contents()); + // fall through + default: + return tk; + } + } +} + +void lex_error(const char *message, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + char *filename; + int lineno; + if (!get_location(&filename, &lineno)) + error(message, arg1, arg2, arg3); + else + error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3); +} + +void yyerror(const char *s) +{ + char *filename; + int lineno; + if (!get_location(&filename, &lineno)) + error(s); + else + error_with_file_and_line(filename, lineno, s); + show_context(); +} + diff --git a/gnu/usr.bin/groff/eqn/limit.cc b/gnu/usr.bin/groff/eqn/limit.cc new file mode 100644 index 0000000000..04abced892 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/limit.cc @@ -0,0 +1,195 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + +class limit_box : public box { +private: + box *p; + box *from; + box *to; +public: + limit_box(box *, box *, box *); + ~limit_box(); + int compute_metrics(int); + void output(); + void debug_print(); + void check_tabs(int); +}; + +box *make_limit_box(box *pp, box *qq, box *rr) +{ + return new limit_box(pp, qq, rr); +} + +limit_box::limit_box(box *pp, box *qq, box *rr) +: p(pp), from(qq), to(rr) +{ + spacing_type = p->spacing_type; +} + +limit_box::~limit_box() +{ + delete p; + delete from; + delete to; +} + +int limit_box::compute_metrics(int style) +{ + printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid); + if (!(style <= SCRIPT_STYLE && one_size_reduction_flag)) + set_script_size(); + printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid); + int res = 0; + int mark_uid = -1; + if (from != 0) { + res = from->compute_metrics(cramped_style(script_style(style))); + if (res) + mark_uid = from->uid; + } + if (to != 0) { + int r = to->compute_metrics(script_style(style)); + if (res && r) + error("multiple marks and lineups"); + else { + mark_uid = to->uid; + res = r; + } + } + printf(".ps \\n[" SIZE_FORMAT "]\n", uid); + int r = p->compute_metrics(style); + p->compute_subscript_kern(); + if (res && r) + error("multiple marks and lineups"); + else { + mark_uid = p->uid; + res = r; + } + printf(".nr " LEFT_WIDTH_FORMAT " " + "0\\n[" WIDTH_FORMAT "]", + uid, p->uid); + if (from != 0) + printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])", + p->uid, from->uid); + if (to != 0) + printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])", + p->uid, to->uid); + printf("/2\n"); + printf(".nr " WIDTH_FORMAT " " + "0\\n[" WIDTH_FORMAT "]", + uid, p->uid); + if (from != 0) + printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])", + p->uid, from->uid); + if (to != 0) + printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])", + p->uid, to->uid); + printf("/2+\\n[" LEFT_WIDTH_FORMAT "]\n", uid); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid); + if (to != 0) + printf(">?\\n[" WIDTH_FORMAT "]", to->uid); + if (from != 0) + printf(">?\\n[" WIDTH_FORMAT "]", from->uid); + printf("\n"); + if (res) + printf(".nr " MARK_REG " +(\\n[" LEFT_WIDTH_FORMAT "]" + "-(\\n[" WIDTH_FORMAT "]/2))\n", + uid, mark_uid); + if (to != 0) { + printf(".nr " SUP_RAISE_FORMAT " %dM+\\n[" DEPTH_FORMAT + "]>?%dM+\\n[" HEIGHT_FORMAT "]\n", + uid, big_op_spacing1, to->uid, big_op_spacing3, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n[" + HEIGHT_FORMAT "]+%dM\n", + uid, uid, to->uid, big_op_spacing5); + } + else + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + if (from != 0) { + printf(".nr " SUB_LOWER_FORMAT " %dM+\\n[" HEIGHT_FORMAT + "]>?%dM+\\n[" DEPTH_FORMAT "]\n", + uid, big_op_spacing2, from->uid, big_op_spacing4, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n[" + DEPTH_FORMAT "]+%dM\n", + uid, uid, from->uid, big_op_spacing5); + } + else + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + return res; +} + +void limit_box::output() +{ + printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid); + if (to != 0) { + printf("\\Z" DELIMITER_CHAR); + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u" + "+(-\\n[" WIDTH_FORMAT "]u+\\n[" SUB_KERN_FORMAT "]u/2u)'", + uid, to->uid, p->uid); + to->output(); + printf(DELIMITER_CHAR); + } + if (from != 0) { + printf("\\Z" DELIMITER_CHAR); + printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid); + printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u" + "+(-\\n[" SUB_KERN_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'", + uid, p->uid, from->uid); + from->output(); + printf(DELIMITER_CHAR); + } + printf("\\s[\\n[" SIZE_FORMAT "]]", uid); + printf("\\Z" DELIMITER_CHAR); + printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u" + "-(\\n[" WIDTH_FORMAT "]u/2u)'", + uid, p->uid); + p->output(); + printf(DELIMITER_CHAR); + printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); +} + +void limit_box::debug_print() +{ + fprintf(stderr, "{ "); + p->debug_print(); + fprintf(stderr, " }"); + if (from) { + fprintf(stderr, " from { "); + from->debug_print(); + fprintf(stderr, " }"); + } + if (to) { + fprintf(stderr, " to { "); + to->debug_print(); + fprintf(stderr, " }"); + } +} + +void limit_box::check_tabs(int level) +{ + if (to) + to->check_tabs(level + 1); + if (from) + from->check_tabs(level + 1); + p->check_tabs(level + 1); +} diff --git a/gnu/usr.bin/groff/eqn/list.cc b/gnu/usr.bin/groff/eqn/list.cc new file mode 100644 index 0000000000..7c8d1d617d --- /dev/null +++ b/gnu/usr.bin/groff/eqn/list.cc @@ -0,0 +1,236 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + +list_box *box::to_list_box() +{ + return 0; +} + +list_box *list_box::to_list_box() +{ + return this; +} + +void list_box::append(box *pp) +{ + list_box *q = pp->to_list_box(); + if (q == 0) + list.append(pp); + else { + for (int i = 0; i < q->list.len; i++) { + list.append(q->list.p[i]); + q->list.p[i] = 0; + } + q->list.len = 0; + delete q; + } +} + +list_box::list_box(box *pp) : list(pp), sty(-1) +{ + list_box *q = pp->to_list_box(); + if (q != 0) { + // flatten it + list.p[0] = q->list.p[0]; + for (int i = 1; i < q->list.len; i++) { + list.append(q->list.p[i]); + q->list.p[i] = 0; + } + q->list.len = 0; + delete q; + } +} + +static int compute_spacing(int is_script, int left, int right) +{ + if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE) + return 0; + if (left == PUNCTUATION_TYPE) + return is_script ? 0 : thin_space; + if (left == OPENING_TYPE || right == CLOSING_TYPE) + return 0; + if (right == BINARY_TYPE || left == BINARY_TYPE) + return is_script ? 0 : medium_space; + if (right == RELATION_TYPE) { + if (left == RELATION_TYPE) + return 0; + else + return is_script ? 0 : thick_space; + } + if (left == RELATION_TYPE) + return is_script ? 0 : thick_space; + if (right == OPERATOR_TYPE) + return thin_space; + if (left == INNER_TYPE || right == INNER_TYPE) + return is_script ? 0 : thin_space; + if (left == OPERATOR_TYPE && right == ORDINARY_TYPE) + return thin_space; + return 0; +} + +int list_box::compute_metrics(int style) +{ + sty = style; + int i; + for (i = 0; i < list.len; i++) { + int t = list.p[i]->spacing_type; + // 5 + if (t == BINARY_TYPE) { + int prevt; + if (i == 0 + || (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE + || prevt == OPERATOR_TYPE + || prevt == RELATION_TYPE + || prevt == OPENING_TYPE + || prevt == PUNCTUATION_TYPE) + list.p[i]->spacing_type = ORDINARY_TYPE; + } + // 7 + else if ((t == RELATION_TYPE || t == CLOSING_TYPE + || t == PUNCTUATION_TYPE) + && i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE) + list.p[i-1]->spacing_type = ORDINARY_TYPE; + } + for (i = 0; i < list.len; i++) { + unsigned flags = 0; + if (i - 1 >= 0 && list.p[i - 1]->right_is_italic()) + flags |= HINT_PREV_IS_ITALIC; + if (i + 1 < list.len && list.p[i + 1]->left_is_italic()) + flags |= HINT_NEXT_IS_ITALIC; + if (flags) + list.p[i]->hint(flags); + } + is_script = (style <= SCRIPT_STYLE); + int total_spacing = 0; + for (i = 1; i < list.len; i++) + total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type, + list.p[i]->spacing_type); + int res = 0; + for (i = 0; i < list.len; i++) + if (!list.p[i]->is_simple()) { + int r = list.p[i]->compute_metrics(style); + if (r) { + if (res) + error("multiple marks and lineups"); + else { + compute_sublist_width(i); + printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n"); + res = r; + } + } + } + printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing); + for (i = 0; i < list.len; i++) + if (!list.p[i]->is_simple()) + printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid); + printf("\n"); + printf(".nr " HEIGHT_FORMAT " 0", uid); + for (i = 0; i < list.len; i++) + if (!list.p[i]->is_simple()) + printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid); + printf("\n"); + printf(".nr " DEPTH_FORMAT " 0", uid); + for (i = 0; i < list.len; i++) + if (!list.p[i]->is_simple()) + printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid); + printf("\n"); + int have_simple = 0; + for (i = 0; i < list.len && !have_simple; i++) + have_simple = list.p[i]->is_simple(); + if (have_simple) { + printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid); + for (int i = 0; i < list.len; i++) + if (list.p[i]->is_simple()) + list.p[i]->output(); + printf(DELIMITER_CHAR "\n"); + printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n", + uid, uid); + printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n", + uid, uid); + } + return res; +} + +void list_box::compute_sublist_width(int n) +{ + int total_spacing = 0; + for (int i = 1; i < n + 1 && i < list.len; i++) + total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type, + list.p[i]->spacing_type); + printf(".nr " TEMP_REG " %dM", total_spacing); + for (i = 0; i < n; i++) + if (!list.p[i]->is_simple()) + printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid); + int have_simple = 0; + for (i = 0; i < n && !have_simple; i++) + have_simple = list.p[i]->is_simple(); + if (have_simple) { + printf("+\\w" DELIMITER_CHAR); + for (int i = 0; i < n; i++) + if (list.p[i]->is_simple()) + list.p[i]->output(); + printf(DELIMITER_CHAR); + } + printf("\n"); +} + +void list_box::compute_subscript_kern() +{ + // We can only call compute_subscript_kern if we have called + // compute_metrics first. + if (list.p[list.len-1]->is_simple()) + list.p[list.len-1]->compute_metrics(sty); + list.p[list.len-1]->compute_subscript_kern(); + printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", + uid, list.p[list.len-1]->uid); +} + +void list_box::output() +{ + for (int i = 0; i < list.len; i++) { + if (i > 0) { + int n = compute_spacing(is_script, + list.p[i-1]->spacing_type, + list.p[i]->spacing_type); + if (n > 0) + printf("\\h'%dM'", n); + } + list.p[i]->output(); + } +} + +void list_box::handle_char_type(int st, int ft) +{ + for (int i = 0; i < list.len; i++) + list.p[i]->handle_char_type(st, ft); +} + +void list_box::debug_print() +{ + list.list_debug_print(" "); +} + +void list_box::check_tabs(int level) +{ + list.list_check_tabs(level); +} diff --git a/gnu/usr.bin/groff/eqn/main.cc b/gnu/usr.bin/groff/eqn/main.cc new file mode 100644 index 0000000000..cfc25f2368 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/main.cc @@ -0,0 +1,352 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "stringclass.h" +#include "device.h" +#include "searchpath.h" +#include "macropath.h" + +#define STARTUP_FILE "eqnrc" + +extern int yyparse(); + +static char *delim_search(char *, int); +static int inline_equation(FILE *, string &, string &); + +char start_delim = '\0'; +char end_delim = '\0'; +int non_empty_flag; +int inline_flag; +int draw_flag = 0; +int one_size_reduction_flag = 0; +int compatible_flag = 0; +int no_newline_in_delim_flag = 0; + +int read_line(FILE *fp, string *p) +{ + p->clear(); + int c = -1; + while ((c = getc(fp)) != EOF) { + if (!illegal_input_char(c)) + *p += char(c); + else + error("illegal input character code `%1'", c); + if (c == '\n') + break; + } + current_lineno++; + return p->length() > 0; +} + +void do_file(FILE *fp, const char *filename) +{ + string linebuf; + string str; + printf(".lf 1 %s\n", filename); + current_filename = filename; + current_lineno = 0; + while (read_line(fp, &linebuf)) { + if (linebuf.length() >= 4 + && linebuf[0] == '.' && linebuf[1] == 'l' && linebuf[2] == 'f' + && (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) { + put_string(linebuf, stdout); + linebuf += '\0'; + if (interpret_lf_args(linebuf.contents() + 3)) + current_lineno--; + } + else if (linebuf.length() >= 4 + && linebuf[0] == '.' + && linebuf[1] == 'E' + && linebuf[2] == 'Q' + && (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) { + put_string(linebuf, stdout); + int start_lineno = current_lineno + 1; + str.clear(); + for (;;) { + if (!read_line(fp, &linebuf)) + fatal("end of file before .EN"); + if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') { + if (linebuf[2] == 'N' + && (linebuf.length() == 3 || linebuf[3] == ' ' + || linebuf[3] == '\n' || compatible_flag)) + break; + else if (linebuf[2] == 'Q' && linebuf.length() > 3 + && (linebuf[3] == ' ' || linebuf[3] == '\n' + || compatible_flag)) + fatal("nested .EQ"); + } + str += linebuf; + } + str += '\0'; + start_string(); + init_lex(str.contents(), current_filename, start_lineno); + non_empty_flag = 0; + inline_flag = 0; + yyparse(); + if (non_empty_flag) { + printf(".lf %d\n", current_lineno - 1); + output_string(); + } + restore_compatibility(); + printf(".lf %d\n", current_lineno); + put_string(linebuf, stdout); + } + else if (start_delim != '\0' && linebuf.search(start_delim) >= 0 + && inline_equation(fp, linebuf, str)) + ; + else + put_string(linebuf, stdout); + } + current_filename = 0; + current_lineno = 0; +} + +/* Handle an inline equation. Return 1 if it was an inline equation, +0 otherwise. */ + +static int inline_equation(FILE *fp, string &linebuf, string &str) +{ + linebuf += '\0'; + char *ptr = &linebuf[0]; + char *start = delim_search(ptr, start_delim); + if (!start) { + // It wasn't a delimiter after all. + linebuf.set_length(linebuf.length() - 1); // strip the '\0' + return 0; + } + start_string(); + inline_flag = 1; + for (;;) { + if (no_newline_in_delim_flag && strchr(start + 1, end_delim) == 0) { + error("missing `%1'", end_delim); + char *nl = strchr(start + 1, '\n'); + if (nl != 0) + *nl = '\0'; + do_text(ptr); + break; + } + int start_lineno = current_lineno; + *start = '\0'; + do_text(ptr); + ptr = start + 1; + str.clear(); + for (;;) { + char *end = strchr(ptr, end_delim); + if (end != 0) { + *end = '\0'; + str += ptr; + ptr = end + 1; + break; + } + str += ptr; + if (!read_line(fp, &linebuf)) + fatal("end of file before `%1'", end_delim); + linebuf += '\0'; + ptr = &linebuf[0]; + } + str += '\0'; + init_lex(str.contents(), current_filename, start_lineno); + yyparse(); + start = delim_search(ptr, start_delim); + if (start == 0) { + char *nl = strchr(ptr, '\n'); + if (nl != 0) + *nl = '\0'; + do_text(ptr); + break; + } + } + printf(".lf %d\n", current_lineno); + output_string(); + restore_compatibility(); + printf(".lf %d\n", current_lineno + 1); + return 1; +} + +/* Search for delim. Skip over number register and string names etc. */ + +static char *delim_search(char *ptr, int delim) +{ + while (*ptr) { + if (*ptr == delim) + return ptr; + if (*ptr++ == '\\') { + switch (*ptr) { + case 'n': + case '*': + case 'f': + case 'g': + case 'k': + switch (*++ptr) { + case '\0': + case '\\': + break; + case '(': + if (*++ptr != '\\' && *ptr != '\0' && *++ptr != '\\' && *ptr != '\0') + ptr++; + break; + case '[': + while (*++ptr != '\0') + if (*ptr == ']') { + ptr++; + break; + } + break; + default: + ptr++; + break; + } + break; + case '\\': + case '\0': + break; + default: + ptr++; + break; + } + } + } + return 0; +} + +void usage() +{ + fprintf(stderr, + "usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n", + program_name); + exit(1); +} + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int opt; + int load_startup_file = 1; + while ((opt = getopt(argc, argv, "DCRvd:f:p:s:m:T:M:rN")) != EOF) + switch (opt) { + case 'C': + compatible_flag = 1; + break; + case 'R': // don't load eqnchar + load_startup_file = 0; + break; + case 'M': + macro_path.command_line_dir(optarg); + break; + case 'v': + { + extern const char *version_string; + fprintf(stderr, "GNU eqn version %s\n", version_string); + fflush(stderr); + break; + } + case 'd': + if (optarg[0] == '\0' || optarg[1] == '\0') + error("-d requires two character argument"); + else if (illegal_input_char(optarg[0])) + error("bad delimiter `%1'", optarg[0]); + else if (illegal_input_char(optarg[1])) + error("bad delimiter `%1'", optarg[1]); + else { + start_delim = optarg[0]; + end_delim = optarg[1]; + } + break; + case 'f': + set_gfont(optarg); + break; + case 'T': + device = optarg; + break; + case 's': + if (!set_gsize(optarg)) + error("invalid size `%1'", optarg); + break; + case 'p': + { + int n; + if (sscanf(optarg, "%d", &n) == 1) + set_script_reduction(n); + else + error("bad size `%1'", optarg); + } + break; + case 'm': + { + int n; + if (sscanf(optarg, "%d", &n) == 1) + set_minimum_size(n); + else + error("bad size `%1'", optarg); + } + break; + case 'r': + one_size_reduction_flag = 1; + break; + case 'D': + warning("-D option is obsolete: use `set draw_lines 1' instead"); + draw_flag = 1; + break; + case 'N': + no_newline_in_delim_flag = 1; + break; + case '?': + usage(); + break; + default: + assert(0); + } + init_table(device); + init_char_table(); + printf(".if !'\\*(.T'%s' " + ".tm warning: %s should have been given a `-T\\*(.T' option\n", + device, program_name); + if (load_startup_file) { + char *path; + FILE *fp = macro_path.open_file(STARTUP_FILE, &path); + if (fp) { + do_file(fp, path); + fclose(fp); + a_delete path; + } + } + if (optind >= argc) + do_file(stdin, "-"); + else + for (int i = optind; i < argc; i++) + if (strcmp(argv[i], "-") == 0) + do_file(stdin, "-"); + else { + errno = 0; + FILE *fp = fopen(argv[i], "r"); + if (!fp) + fatal("can't open `%1': %2", argv[i], strerror(errno)); + else { + do_file(fp, argv[i]); + fclose(fp); + } + } + if (ferror(stdout) || fflush(stdout) < 0) + fatal("output error"); + exit(0); +} diff --git a/gnu/usr.bin/groff/eqn/mark.cc b/gnu/usr.bin/groff/eqn/mark.cc new file mode 100644 index 0000000000..fa5916d3d1 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/mark.cc @@ -0,0 +1,121 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + +class mark_box : public pointer_box { +public: + mark_box(box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +// we push down marks so that they don't interfere with spacing + +box *make_mark_box(box *p) +{ + list_box *b = p->to_list_box(); + if (b != 0) { + b->list.p[0] = make_mark_box(b->list.p[0]); + return b; + } + else + return new mark_box(p); +} + +mark_box::mark_box(box *pp) : pointer_box(pp) +{ +} + +void mark_box::output() +{ + p->output(); +} + +int mark_box::compute_metrics(int style) +{ + int res = p->compute_metrics(style); + if (res) + error("multiple marks and lineups"); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + printf(".nr " MARK_REG " 0\n"); + return FOUND_MARK; +} + +void mark_box::debug_print() +{ + fprintf(stderr, "mark { "); + p->debug_print(); + fprintf(stderr, " }"); +} + + +class lineup_box : public pointer_box { +public: + lineup_box(box *); + void output(); + int compute_metrics(int style); + void debug_print(); +}; + +// we push down lineups so that they don't interfere with spacing + +box *make_lineup_box(box *p) +{ + list_box *b = p->to_list_box(); + if (b != 0) { + b->list.p[0] = make_lineup_box(b->list.p[0]); + return b; + } + else + return new lineup_box(p); +} + +lineup_box::lineup_box(box *pp) : pointer_box(pp) +{ +} + +void lineup_box::output() +{ + p->output(); +} + +int lineup_box::compute_metrics(int style) +{ + int res = p->compute_metrics(style); + if (res) + error("multiple marks and lineups"); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + printf(".nr " MARK_REG " 0\n"); + return FOUND_LINEUP; +} + +void lineup_box::debug_print() +{ + fprintf(stderr, "lineup { "); + p->debug_print(); + fprintf(stderr, " }"); +} diff --git a/gnu/usr.bin/groff/eqn/neqn.sh b/gnu/usr.bin/groff/eqn/neqn.sh new file mode 100644 index 0000000000..770376732b --- /dev/null +++ b/gnu/usr.bin/groff/eqn/neqn.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# Provision of this shell script should not be taken to imply that use of +# GNU eqn with groff -Tascii|-Tlatin1 is supported. + +exec @g@eqn -Tascii ${1+"$@"} diff --git a/gnu/usr.bin/groff/eqn/other.cc b/gnu/usr.bin/groff/eqn/other.cc new file mode 100644 index 0000000000..5b8b9c2699 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/other.cc @@ -0,0 +1,601 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + +class accent_box : public pointer_box { +private: + box *ab; +public: + accent_box(box *, box *); + ~accent_box(); + int compute_metrics(int); + void output(); + void debug_print(); + void check_tabs(int); +}; + +box *make_accent_box(box *p, box *q) +{ + return new accent_box(p, q); +} + +accent_box::accent_box(box *pp, box *qq) : ab(qq), pointer_box(pp) +{ +} + +accent_box::~accent_box() +{ + delete ab; +} + +#if 0 +int accent_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + p->compute_skew(); + ab->compute_metrics(style); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n", + uid, p->uid, x_height); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n[" + SUP_RAISE_FORMAT "]\n", + uid, ab->uid, uid); + return r; +} + +void accent_box::output() +{ + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n[" + SKEW_FORMAT "]u'", + p->uid, ab->uid, p->uid); + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + ab->output(); + printf("\\h'-\\n[" WIDTH_FORMAT "]u'", ab->uid); + printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); + printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n[" + SKEW_FORMAT "]u)'", + p->uid, ab->uid, p->uid); + p->output(); +} +#endif + +/* This version copes with the possibility of an accent's being wider +than its accentee. LEFT_WIDTH_FORMAT gives the distance from the +left edge of the resulting box to the middle of the accentee's box.*/ + +int accent_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + p->compute_skew(); + ab->compute_metrics(style); + printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2" + ">?(\\n[" WIDTH_FORMAT "]/2-\\n[" SKEW_FORMAT "])\n", + uid, p->uid, ab->uid, p->uid); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2" + ">?(\\n[" WIDTH_FORMAT "]/2+\\n[" SKEW_FORMAT "])" + "+\\n[" LEFT_WIDTH_FORMAT "]\n", + uid, p->uid, ab->uid, p->uid, uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n", + uid, p->uid, x_height); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n[" + SUP_RAISE_FORMAT "]\n", + uid, ab->uid, uid); + if (r) + printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]" + "-(\\n[" WIDTH_FORMAT "]/2)'\n", + uid, p->uid); + return r; +} + +void accent_box::output() +{ + printf("\\Z" DELIMITER_CHAR); + printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u+\\n[" SKEW_FORMAT "]u" + "-(\\n[" WIDTH_FORMAT "]u/2u)'", + uid, p->uid, ab->uid); + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + ab->output(); + printf(DELIMITER_CHAR); + printf("\\Z" DELIMITER_CHAR); + printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'", + uid, p->uid); + p->output(); + printf(DELIMITER_CHAR); + printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); +} + +void accent_box::check_tabs(int level) +{ + ab->check_tabs(level + 1); + p->check_tabs(level + 1); +} + +void accent_box::debug_print() +{ + fprintf(stderr, "{ "); + p->debug_print(); + fprintf(stderr, " } accent { "); + ab->debug_print(); + fprintf(stderr, " }"); +} + +class overline_char_box : public simple_box { +public: + overline_char_box(); + void output(); + void debug_print(); +}; + +overline_char_box::overline_char_box() +{ +} + +void overline_char_box::output() +{ + printf("\\v'-%dM/2u-%dM'", 7*default_rule_thickness, x_height); + printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"), + accent_width); + printf("\\v'%dM/2u+%dM'", 7*default_rule_thickness, x_height); +} + +void overline_char_box::debug_print() +{ + fprintf(stderr, ""); +} + +class overline_box : public pointer_box { +public: + overline_box(box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +box *make_overline_box(box *p) +{ + if (p->is_char()) + return new accent_box(p, new overline_char_box); + else + return new overline_box(p); +} + +overline_box::overline_box(box *pp) : pointer_box(pp) +{ +} + +int overline_box::compute_metrics(int style) +{ + int r = p->compute_metrics(cramped_style(style)); + // 9 + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+%dM\n", + uid, p->uid, default_rule_thickness*5); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + return r; +} + +void overline_box::output() +{ + // 9 + printf("\\Z" DELIMITER_CHAR); + printf("\\v'-\\n[" HEIGHT_FORMAT "]u-(%dM/2u)'", + p->uid, 7*default_rule_thickness); + if (draw_flag) + printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid); + else + printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid); + printf(DELIMITER_CHAR); + p->output(); +} + +void overline_box::debug_print() +{ + fprintf(stderr, "{ "); + p->debug_print(); + fprintf(stderr, " } bar"); +} + +class uaccent_box : public pointer_box { + box *ab; +public: + uaccent_box(box *, box *); + ~uaccent_box(); + int compute_metrics(int); + void output(); + void compute_subscript_kern(); + void check_tabs(int); + void debug_print(); +}; + +box *make_uaccent_box(box *p, box *q) +{ + return new uaccent_box(p, q); +} + +uaccent_box::uaccent_box(box *pp, box *qq) +: pointer_box(pp), ab(qq) +{ +} + +uaccent_box::~uaccent_box() +{ + delete ab; +} + +int uaccent_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + ab->compute_metrics(style); + printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2" + ">?(\\n[" WIDTH_FORMAT "]/2)\n", + uid, p->uid, ab->uid); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2" + ">?(\\n[" WIDTH_FORMAT "]/2)" + "+\\n[" LEFT_WIDTH_FORMAT "]\n", + uid, p->uid, ab->uid, uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]" + "+\\n[" DEPTH_FORMAT "]\n", + uid, p->uid, ab->uid); + if (r) + printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]" + "-(\\n[" WIDTH_FORMAT "]/2)'\n", + uid, p->uid); + return r; +} + +void uaccent_box::output() +{ + printf("\\Z" DELIMITER_CHAR); + printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'", + uid, ab->uid); + printf("\\v'\\n[" DEPTH_FORMAT "]u'", p->uid); + ab->output(); + printf(DELIMITER_CHAR); + printf("\\Z" DELIMITER_CHAR); + printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'", + uid, p->uid); + p->output(); + printf(DELIMITER_CHAR); + printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); +} + +void uaccent_box::check_tabs(int level) +{ + ab->check_tabs(level + 1); + p->check_tabs(level + 1); +} + +void uaccent_box::compute_subscript_kern() +{ + box::compute_subscript_kern(); // want 0 subscript kern +} + +void uaccent_box::debug_print() +{ + fprintf(stderr, "{ "); + p->debug_print(); + fprintf(stderr, " } uaccent { "); + ab->debug_print(); + fprintf(stderr, " }"); +} + +class underline_char_box : public simple_box { +public: + underline_char_box(); + void output(); + void debug_print(); +}; + +underline_char_box::underline_char_box() +{ +} + +void underline_char_box::output() +{ + printf("\\v'%dM/2u'", 7*default_rule_thickness); + printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"), + accent_width); + printf("\\v'-%dM/2u'", 7*default_rule_thickness); +} + +void underline_char_box::debug_print() +{ + fprintf(stderr, ""); +} + + +class underline_box : public pointer_box { +public: + underline_box(box *); + int compute_metrics(int); + void output(); + void compute_subscript_kern(); + void debug_print(); +}; + +box *make_underline_box(box *p) +{ + if (p->is_char()) + return new uaccent_box(p, new underline_char_box); + else + return new underline_box(p); +} + +underline_box::underline_box(box *pp) : pointer_box(pp) +{ +} + +int underline_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + // 10 + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n", + uid, p->uid, default_rule_thickness*5); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + return r; +} + +void underline_box::output() +{ + // 10 + printf("\\Z" DELIMITER_CHAR); + printf("\\v'\\n[" DEPTH_FORMAT "]u+(%dM/2u)'", + p->uid, 7*default_rule_thickness); + if (draw_flag) + printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid); + else + printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid); + printf(DELIMITER_CHAR); + p->output(); +} + +// we want an underline box to have 0 subscript kern + +void underline_box::compute_subscript_kern() +{ + box::compute_subscript_kern(); +} + +void underline_box::debug_print() +{ + fprintf(stderr, "{ "); + p->debug_print(); + fprintf(stderr, " } under"); +} + +size_box::size_box(char *s, box *pp) : size(s), pointer_box(pp) +{ +} + +int size_box::compute_metrics(int style) +{ + printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid); + printf(".ps %s\n", size); + printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid); + int r = p->compute_metrics(style); + printf(".ps \\n[" SIZE_FORMAT "]\n", uid); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + return r; +} + +void size_box::output() +{ + printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid); + p->output(); + printf("\\s[\\n[" SIZE_FORMAT "]]", uid); +} + +size_box::~size_box() +{ + a_delete size; +} + +void size_box::debug_print() +{ + fprintf(stderr, "size %s { ", size); + p->debug_print(); + fprintf(stderr, " }"); +} + + +font_box::font_box(char *s, box *pp) : pointer_box(pp), f(s) +{ +} + +font_box::~font_box() +{ + a_delete f; +} + +int font_box::compute_metrics(int style) +{ + const char *old_roman_font = current_roman_font; + current_roman_font = f; + printf(".nr " FONT_FORMAT " \\n[.f]\n", uid); + printf(".ft %s\n", f); + int r = p->compute_metrics(style); + current_roman_font = old_roman_font; + printf(".ft \\n[" FONT_FORMAT "]\n", uid); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + return r; +} + +void font_box::output() +{ + printf("\\f[%s]", f); + const char *old_roman_font = current_roman_font; + current_roman_font = f; + p->output(); + current_roman_font = old_roman_font; + printf("\\f[\\n[" FONT_FORMAT "]]", uid); +} + +void font_box::debug_print() +{ + fprintf(stderr, "font %s { ", f); + p->debug_print(); + fprintf(stderr, " }"); +} + +fat_box::fat_box(box *pp) : pointer_box(pp) +{ +} + +int fat_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n", + uid, p->uid, fat_offset); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + return r; +} + +void fat_box::output() +{ + p->output(); + printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p->uid); + printf("\\h'%dM'", fat_offset); + p->output(); +} + + +void fat_box::debug_print() +{ + fprintf(stderr, "fat { "); + p->debug_print(); + fprintf(stderr, " }"); +} + + +vmotion_box::vmotion_box(int i, box *pp) : n(i), pointer_box(pp) +{ +} + +int vmotion_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + if (n > 0) { + printf(".nr " HEIGHT_FORMAT " %dM+\\n[" HEIGHT_FORMAT "]\n", + uid, n, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + } + else { + printf(".nr " DEPTH_FORMAT " %dM+\\n[" DEPTH_FORMAT "]>?0\n", + uid, -n, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", + uid, p->uid); + } + return r; +} + +void vmotion_box::output() +{ + printf("\\v'%dM'", -n); + p->output(); + printf("\\v'%dM'", n); +} + +void vmotion_box::debug_print() +{ + if (n >= 0) + fprintf(stderr, "up %d { ", n); + else + fprintf(stderr, "down %d { ", -n); + p->debug_print(); + fprintf(stderr, " }"); +} + +hmotion_box::hmotion_box(int i, box *pp) : n(i), pointer_box(pp) +{ +} + +int hmotion_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n", + uid, p->uid, n); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); + if (r) + printf(".nr " MARK_REG " +%dM\n", n); + return r; +} + +void hmotion_box::output() +{ + printf("\\h'%dM'", n); + p->output(); +} + +void hmotion_box::debug_print() +{ + if (n >= 0) + fprintf(stderr, "fwd %d { ", n); + else + fprintf(stderr, "back %d { ", -n); + p->debug_print(); + fprintf(stderr, " }"); +} + +vcenter_box::vcenter_box(box *pp) : pointer_box(pp) +{ +} + +int vcenter_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); + printf(".nr " SUP_RAISE_FORMAT " \\n[" DEPTH_FORMAT "]-\\n[" + HEIGHT_FORMAT "]/2+%dM\n", + uid, p->uid, p->uid, axis_height); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n[" + SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]-\\n[" + SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid); + + return r; +} + +void vcenter_box::output() +{ + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + p->output(); + printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); +} + +void vcenter_box::debug_print() +{ + fprintf(stderr, "vcenter { "); + p->debug_print(); + fprintf(stderr, " }"); +} + diff --git a/gnu/usr.bin/groff/eqn/over.cc b/gnu/usr.bin/groff/eqn/over.cc new file mode 100644 index 0000000000..5ea0121eb0 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/over.cc @@ -0,0 +1,196 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + +class over_box : public box { +private: + int reduce_size; + box *num; + box *den; +public: + over_box(int small, box *, box *); + ~over_box(); + void debug_print(); + int compute_metrics(int); + void output(); + void check_tabs(int); +}; + +box *make_over_box(box *pp, box *qq) +{ + return new over_box(0, pp, qq); +} + +box *make_small_over_box(box *pp, box *qq) +{ + return new over_box(1, pp, qq); +} + +over_box::over_box(int is_small, box *pp, box *qq) +: num(pp), den(qq), reduce_size(is_small) +{ + spacing_type = INNER_TYPE; +} + +over_box::~over_box() +{ + delete num; + delete den; +} + +int over_box::compute_metrics(int style) +{ + if (reduce_size) { + style = script_style(style); + printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid); + set_script_size(); + printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid); + } + int mark_uid; + int res = num->compute_metrics(style); + if (res) + mark_uid = num->uid; + int r = den->compute_metrics(cramped_style(style)); + if (r && res) + error("multiple marks and lineups"); + else { + mark_uid = den->uid; + res = r; + } + if (reduce_size) + printf(".ps \\n[" SIZE_FORMAT "]\n", uid); + printf(".nr " WIDTH_FORMAT " (\\n[" WIDTH_FORMAT "]>?\\n[" WIDTH_FORMAT "]", + uid, num->uid, den->uid); + // allow for \(ru being wider than both the numerator and denominator + if (!draw_flag) + fputs(">?\\w" DELIMITER_CHAR "\\(ru" DELIMITER_CHAR, stdout); + printf(")+%dM\n", null_delimiter_space*2 + over_hang*2); + // 15b + printf(".nr " SUP_RAISE_FORMAT " %dM\n", + uid, (reduce_size ? num2 : num1)); + printf(".nr " SUB_LOWER_FORMAT " %dM\n", + uid, (reduce_size ? denom2 : denom1)); + + // 15d + printf(".nr " SUP_RAISE_FORMAT " +(\\n[" DEPTH_FORMAT + "]-\\n[" SUP_RAISE_FORMAT "]+%dM+(%dM/2)+%dM)>?0\n", + uid, num->uid, uid, axis_height, default_rule_thickness, + default_rule_thickness*(reduce_size ? 1 : 3)); + printf(".nr " SUB_LOWER_FORMAT " +(\\n[" HEIGHT_FORMAT + "]-\\n[" SUB_LOWER_FORMAT "]-%dM+(%dM/2)+%dM)>?0\n", + uid, den->uid, uid, axis_height, default_rule_thickness, + default_rule_thickness*(reduce_size ? 1 : 3)); + + + printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n[" + HEIGHT_FORMAT "]\n", + uid, uid, num->uid); + printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n[" + DEPTH_FORMAT "]\n", + uid, uid, den->uid); + if (res) + printf(".nr " MARK_REG " +(\\n[" WIDTH_FORMAT "]-\\n[" + WIDTH_FORMAT "]/2)\n", uid, mark_uid); + return res; +} + +#define USE_Z + +void over_box::output() +{ + if (reduce_size) + printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid); +#ifdef USE_Z + printf("\\Z" DELIMITER_CHAR); +#endif + // move up to the numerator baseline + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + // move across so that it's centered + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", + uid, num->uid); + + // print the numerator + num->output(); + +#ifdef USE_Z + printf(DELIMITER_CHAR); +#else + // back again + printf("\\h'-\\n[" WIDTH_FORMAT "]u'", num->uid); + printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'", + uid, num->uid); + // down again + printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); +#endif +#ifdef USE_Z + printf("\\Z" DELIMITER_CHAR); +#endif + // move down to the denominator baseline + printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid); + + // move across so that it's centered + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", + uid, den->uid); + + // print the the denominator + den->output(); + +#ifdef USE_Z + printf(DELIMITER_CHAR); +#else + // back again + printf("\\h'-\\n[" WIDTH_FORMAT "]u'", den->uid); + printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'", + uid, den->uid); + // up again + printf("\\v'-\\n[" SUB_LOWER_FORMAT "]u'", uid); +#endif + if (reduce_size) + printf("\\s[\\n[" SIZE_FORMAT "]]", uid); + // draw the line + printf("\\h'%dM'", null_delimiter_space); + printf("\\v'-%dM'", axis_height); + fputs(draw_flag ? "\\D'l" : "\\l'", stdout); + printf("\\n[" WIDTH_FORMAT "]u-%dM", + uid, 2*null_delimiter_space); + fputs(draw_flag ? " 0'" : "\\&\\(ru'", stdout); + printf("\\v'%dM'", axis_height); + printf("\\h'%dM'", null_delimiter_space); +} + +void over_box::debug_print() +{ + fprintf(stderr, "{ "); + num->debug_print(); + if (reduce_size) + fprintf(stderr, " } smallover { "); + else + fprintf(stderr, " } over { "); + den->debug_print(); + fprintf(stderr, " }"); +} + +void over_box::check_tabs(int level) +{ + num->check_tabs(level + 1); + den->check_tabs(level + 1); +} diff --git a/gnu/usr.bin/groff/eqn/pbox.h b/gnu/usr.bin/groff/eqn/pbox.h new file mode 100644 index 0000000000..adee780cf9 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/pbox.h @@ -0,0 +1,141 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern int fat_offset; + +extern int over_hang; +extern int accent_width; + +extern int delimiter_factor; +extern int delimiter_shortfall; + +extern int null_delimiter_space; +extern int script_space; +extern int thin_space; +extern int medium_space; +extern int thick_space; + +extern int num1; +extern int num2; +// we don't use num3, because we don't have \atop +extern int denom1; +extern int denom2; +extern int axis_height; +extern int sup1; +extern int sup2; +extern int sup3; +extern int default_rule_thickness; +extern int sub1; +extern int sub2; +extern int sup_drop; +extern int sub_drop; +extern int x_height; +extern int big_op_spacing1; +extern int big_op_spacing2; +extern int big_op_spacing3; +extern int big_op_spacing4; +extern int big_op_spacing5; + +extern int baseline_sep; +extern int shift_down; +extern int column_sep; +extern int matrix_side_sep; + +// ms.eqn relies on this! + +#define LINE_STRING "10" +#define MARK_OR_LINEUP_FLAG_REG "MK" + +#define WIDTH_FORMAT PREFIX "w%d" +#define HEIGHT_FORMAT PREFIX "h%d" +#define DEPTH_FORMAT PREFIX "d%d" +#define TOTAL_FORMAT PREFIX "t%d" +#define SIZE_FORMAT PREFIX "z%d" +#define SMALL_SIZE_FORMAT PREFIX "Z%d" +#define SUP_RAISE_FORMAT PREFIX "p%d" +#define SUB_LOWER_FORMAT PREFIX "b%d" +#define SUB_KERN_FORMAT PREFIX "k%d" +#define FONT_FORMAT PREFIX "f%d" +#define SKEW_FORMAT PREFIX "s%d" +#define LEFT_WIDTH_FORMAT PREFIX "lw%d" +#define LEFT_DELIM_STRING_FORMAT PREFIX "l%d" +#define RIGHT_DELIM_STRING_FORMAT PREFIX "r%d" +#define SQRT_STRING_FORMAT PREFIX "sqr%d" +#define SQRT_WIDTH_FORMAT PREFIX "sq%d" +#define BASELINE_SEP_FORMAT PREFIX "bs%d" +// this needs two parameters, the uid and the column index +#define COLUMN_WIDTH_FORMAT PREFIX "cw%d,%d" + +#define BAR_STRING PREFIX "sqb" +#define TEMP_REG PREFIX "temp" +#define MARK_REG PREFIX "mark" +#define MARK_WIDTH_REG PREFIX "mwidth" +#define SAVED_MARK_REG PREFIX "smark" +#define MAX_SIZE_REG PREFIX "mxsz" +#define REPEAT_APPEND_STRING_MACRO PREFIX "ras" +#define TOP_HEIGHT_REG PREFIX "th" +#define TOP_DEPTH_REG PREFIX "td" +#define MID_HEIGHT_REG PREFIX "mh" +#define MID_DEPTH_REG PREFIX "md" +#define BOT_HEIGHT_REG PREFIX "bh" +#define BOT_DEPTH_REG PREFIX "bd" +#define EXT_HEIGHT_REG PREFIX "eh" +#define EXT_DEPTH_REG PREFIX "ed" +#define TOTAL_HEIGHT_REG PREFIX "tot" +#define DELTA_REG PREFIX "delta" +#define DELIM_STRING PREFIX "delim" +#define DELIM_WIDTH_REG PREFIX "dwidth" +#define SAVED_FONT_REG PREFIX "sfont" +#define SAVED_PREV_FONT_REG PREFIX "spfont" +#define SAVED_INLINE_FONT_REG PREFIX "sifont" +#define SAVED_INLINE_PREV_FONT_REG PREFIX "sipfont" +#define SAVED_SIZE_REG PREFIX "ssize" +#define SAVED_INLINE_SIZE_REG PREFIX "sisize" +#define SAVED_INLINE_PREV_SIZE_REG PREFIX "sipsize" +#define SAVE_FONT_STRING PREFIX "sfont" +#define RESTORE_FONT_STRING PREFIX "rfont" +#define INDEX_REG PREFIX "i" +#define TEMP_MACRO PREFIX "tempmac" + +#define DELIMITER_CHAR "\\(EQ" + +const int CRAMPED_SCRIPT_STYLE = 0; +const int SCRIPT_STYLE = 1; +const int CRAMPED_DISPLAY_STYLE = 2; +const int DISPLAY_STYLE = 3; + +extern int script_style(int); +extern int cramped_style(int); + +const int ORDINARY_TYPE = 0; +const int OPERATOR_TYPE = 1; +const int BINARY_TYPE = 2; +const int RELATION_TYPE = 3; +const int OPENING_TYPE = 4; +const int CLOSING_TYPE = 5; +const int PUNCTUATION_TYPE = 6; +const int INNER_TYPE = 7; +const int SUPPRESS_TYPE = 8; + +void set_script_size(); + +enum { HINT_PREV_IS_ITALIC = 01, HINT_NEXT_IS_ITALIC = 02 }; + +extern const char *current_roman_font; diff --git a/gnu/usr.bin/groff/eqn/pile.cc b/gnu/usr.bin/groff/eqn/pile.cc new file mode 100644 index 0000000000..9aa43068ce --- /dev/null +++ b/gnu/usr.bin/groff/eqn/pile.cc @@ -0,0 +1,293 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +// piles and matrices + +#include "eqn.h" +#include "pbox.h" + +// SUP_RAISE_FORMAT gives the first baseline +// BASELINE_SEP_FORMAT gives the separation between baselines + +int pile_box::compute_metrics(int style) +{ + int i; + for (i = 0; i < col.len; i++) + col.p[i]->compute_metrics(style); + printf(".nr " WIDTH_FORMAT " 0", uid); + for (i = 0; i < col.len; i++) + printf(">?\\n[" WIDTH_FORMAT "]", col.p[i]->uid); + printf("\n"); + printf(".nr " BASELINE_SEP_FORMAT " %dM", + uid, baseline_sep+col.space); + for (i = 1; i < col.len; i++) + printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)", + col.p[i-1]->uid, col.p[i]->uid, default_rule_thickness*5); + // round it so that it's a multiple of the vertical resolution + printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n"); + + printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2" + "+%dM\n", + uid, uid, col.len-1, axis_height - shift_down); + printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n[" + HEIGHT_FORMAT "]\n", + uid, uid, col.p[0]->uid); + printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d+\\n[" + DEPTH_FORMAT "]-\\n[" SUP_RAISE_FORMAT "]\n", + uid, uid, col.len-1, col.p[col.len-1]->uid, uid); + return FOUND_NOTHING; +} + +void pile_box::output() +{ + int i; + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + for (i = 0; i < col.len; i++) { + switch (col.align) { + case LEFT_ALIGN: + break; + case CENTER_ALIGN: + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", + uid, col.p[i]->uid); + break; + case RIGHT_ALIGN: + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", + uid, col.p[i]->uid); + break; + default: + assert(0); + } + col.p[i]->output(); + printf("\\h'-\\n[" WIDTH_FORMAT "]u'", col.p[i]->uid); + switch (col.align) { + case LEFT_ALIGN: + break; + case CENTER_ALIGN: + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", + col.p[i]->uid, uid); + break; + case RIGHT_ALIGN: + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", + col.p[i]->uid, uid); + break; + default: + assert(0); + } + if (i != col.len - 1) + printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid); + } + printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); + printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", col.len - 1, uid); + printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); +} + +pile_box::pile_box(box *pp) : col(pp) +{ +} + +void pile_box::check_tabs(int level) +{ + col.list_check_tabs(level); +} + +void pile_box::debug_print() +{ + col.debug_print("pile"); +} + +int matrix_box::compute_metrics(int style) +{ + int i, j; + int maxlen = 0; + int space = 0; + for (i = 0; i < len; i++) { + for (j = 0; j < p[i]->len; j++) + p[i]->p[j]->compute_metrics(style); + if (p[i]->len > maxlen) + maxlen = p[i]->len; + if (p[i]->space > space) + space = p[i]->space; + } + for (i = 0; i < len; i++) { + printf(".nr " COLUMN_WIDTH_FORMAT " 0", uid, i); + for (j = 0; j < p[i]->len; j++) + printf(">?\\n[" WIDTH_FORMAT "]", p[i]->p[j]->uid); + printf("\n"); + } + printf(".nr " WIDTH_FORMAT " %dM", + uid, column_sep*(len-1)+2*matrix_side_sep); + for (i = 0; i < len; i++) + printf("+\\n[" COLUMN_WIDTH_FORMAT "]", uid, i); + printf("\n"); + printf(".nr " BASELINE_SEP_FORMAT " %dM", + uid, baseline_sep+space); + for (i = 0; i < len; i++) + for (j = 1; j < p[i]->len; j++) + printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)", + p[i]->p[j-1]->uid, p[i]->p[j]->uid, default_rule_thickness*5); + // round it so that it's a multiple of the vertical resolution + printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n"); + printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2" + "+%dM\n", + uid, uid, maxlen-1, axis_height - shift_down); + printf(".nr " HEIGHT_FORMAT " 0\\n[" SUP_RAISE_FORMAT "]+(0", + uid, uid); + for (i = 0; i < len; i++) + printf(">?\\n[" HEIGHT_FORMAT "]", p[i]->p[0]->uid); + printf(")>?0\n"); + printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d-\\n[" + SUP_RAISE_FORMAT "]+(0", + uid, uid, maxlen-1, uid); + for (i = 0; i < len; i++) + if (p[i]->len == maxlen) + printf(">?\\n[" DEPTH_FORMAT "]", p[i]->p[maxlen-1]->uid); + printf(")>?0\n"); + return FOUND_NOTHING; +} + +void matrix_box::output() +{ + printf("\\h'%dM'", matrix_side_sep); + for (int i = 0; i < len; i++) { + int j; + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + for (j = 0; j < p[i]->len; j++) { + switch (p[i]->align) { + case LEFT_ALIGN: + break; + case CENTER_ALIGN: + printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", + uid, i, p[i]->p[j]->uid); + break; + case RIGHT_ALIGN: + printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", + uid, i, p[i]->p[j]->uid); + break; + default: + assert(0); + } + p[i]->p[j]->output(); + printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p[i]->p[j]->uid); + switch (p[i]->align) { + case LEFT_ALIGN: + break; + case CENTER_ALIGN: + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u/2u'", + p[i]->p[j]->uid, uid, i); + break; + case RIGHT_ALIGN: + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u'", + p[i]->p[j]->uid, uid, i); + break; + default: + assert(0); + } + if (j != p[i]->len - 1) + printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid); + } + printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); + printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", p[i]->len - 1, uid); + printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u'", uid, i); + if (i != len - 1) + printf("\\h'%dM'", column_sep); + } + printf("\\h'%dM'", matrix_side_sep); +} + +matrix_box::matrix_box(column *pp) +{ + p = new column*[10]; + for (int i = 0; i < 10; i++) + p[i] = 0; + maxlen = 10; + len = 1; + p[0] = pp; +} + +matrix_box::~matrix_box() +{ + for (int i = 0; i < len; i++) + delete p[i]; + a_delete p; +} + +void matrix_box::append(column *pp) +{ + if (len + 1 > maxlen) { + column **oldp = p; + maxlen *= 2; + p = new column*[maxlen]; + memcpy(p, oldp, sizeof(column*)*len); + a_delete oldp; + } + p[len++] = pp; +} + +void matrix_box::check_tabs(int level) +{ + for (int i = 0; i < len; i++) + p[i]->list_check_tabs(level); +} + +void matrix_box::debug_print() +{ + fprintf(stderr, "matrix { "); + p[0]->debug_print("col"); + for (int i = 1; i < len; i++) { + fprintf(stderr, " "); + p[i]->debug_print("col"); + } + fprintf(stderr, " }"); +} + +column::column(box *pp) : box_list(pp), align(CENTER_ALIGN), space(0) +{ +} + +void column::set_alignment(alignment a) +{ + align = a; +} + +void column::set_space(int n) +{ + space = n; +} + +void column::debug_print(const char *s) +{ + char c = '\0'; // shut up -Wall + switch (align) { + case LEFT_ALIGN: + c = 'l'; + break; + case RIGHT_ALIGN: + c = 'r'; + break; + case CENTER_ALIGN: + c = 'c'; + break; + default: + assert(0); + } + fprintf(stderr, "%c%s %d { ", c, s, space); + list_debug_print(" above "); + fprintf(stderr, " }"); +} + diff --git a/gnu/usr.bin/groff/eqn/script.cc b/gnu/usr.bin/groff/eqn/script.cc new file mode 100644 index 0000000000..3ee83ba52f --- /dev/null +++ b/gnu/usr.bin/groff/eqn/script.cc @@ -0,0 +1,221 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + +class script_box : public pointer_box { +private: + box *sub; + box *sup; +public: + script_box(box *, box *, box *); + ~script_box(); + int compute_metrics(int); + void output(); + void debug_print(); + int left_is_italic(); + void hint(unsigned); + void check_tabs(int); +}; + +/* The idea is that the script should attach to the rightmost box +of a list. For example, given `2x sup 3', the superscript should +attach to `x' rather than `2x'. */ + +box *make_script_box(box *nuc, box *sub, box *sup) +{ + list_box *b = nuc->to_list_box(); + if (b != 0) { + b->list.p[b->list.len-1] = make_script_box(b->list.p[b->list.len - 1], + sub, + sup); + return b; + } + else + return new script_box(nuc, sub, sup); +} + +script_box::script_box(box *pp, box *qq, box *rr) +: pointer_box(pp), sub(qq), sup(rr) +{ +} + +script_box::~script_box() +{ + delete sub; + delete sup; +} + +int script_box::left_is_italic() +{ + return p->left_is_italic(); +} + +int script_box::compute_metrics(int style) +{ + int res = p->compute_metrics(style); + p->compute_subscript_kern(); + printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid); + if (!(style <= SCRIPT_STYLE && one_size_reduction_flag)) + set_script_size(); + printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid); + if (sub != 0) + sub->compute_metrics(cramped_style(script_style(style))); + if (sup != 0) + sup->compute_metrics(script_style(style)); + // 18a + if (p->is_char()) { + printf(".nr " SUP_RAISE_FORMAT " 0\n", uid); + printf(".nr " SUB_LOWER_FORMAT " 0\n", uid); + } + else { + printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n", + uid, p->uid, sup_drop); + printf(".nr " SUB_LOWER_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n", + uid, p->uid, sub_drop); + } + printf(".ps \\n[" SIZE_FORMAT "]\n", uid); + if (sup == 0) { + assert(sub != 0); + // 18b + printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM>?(\\n[" + HEIGHT_FORMAT "]-(%dM*4/5))\n", + uid, uid, sub1, sub->uid, x_height); + } + else { + // sup != 0 + // 18c + int p; + if (style == DISPLAY_STYLE) + p = sup1; + else if (style & 1) // not cramped + p = sup2; + else + p = sup3; + printf(".nr " SUP_RAISE_FORMAT " \\n[" SUP_RAISE_FORMAT + "]>?%dM>?(\\n[" DEPTH_FORMAT "]+(%dM/4))\n", + uid, uid, p, sup->uid, x_height); + // 18d + if (sub != 0) { + printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM\n", + uid, uid, sub2); + // 18e + printf(".nr " TEMP_REG " \\n[" DEPTH_FORMAT "]-\\n[" + SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]-\\n[" + SUB_LOWER_FORMAT "]+(4*%dM)\n", + sup->uid, uid, sub->uid, uid, default_rule_thickness); + printf(".if \\n[" TEMP_REG "] \\{"); + printf(".nr " SUB_LOWER_FORMAT " +\\n[" TEMP_REG "]\n", uid); + printf(".nr " TEMP_REG " (%dM*4/5)-\\n[" SUP_RAISE_FORMAT + "]+\\n[" DEPTH_FORMAT "]>?0\n", + x_height, uid, sup->uid); + printf(".nr " SUP_RAISE_FORMAT " +\\n[" TEMP_REG "]\n", uid); + printf(".nr " SUB_LOWER_FORMAT " -\\n[" TEMP_REG "]\n", uid); + printf(".\\}\n"); + } + } + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid); + if (sub != 0 && sup != 0) + printf("+((\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]>?\\n[" + WIDTH_FORMAT "])+%dM)>?0\n", + sub->uid, p->uid, sup->uid, script_space); + else if (sub != 0) + printf("+(\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]+%dM)>?0\n", + sub->uid, p->uid, script_space); + else if (sup != 0) + printf("+(\\n[" WIDTH_FORMAT "]+%dM)>?0\n", sup->uid, script_space); + else + printf("\n"); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]", + uid, p->uid); + if (sup != 0) + printf(">?(\\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "])", + uid, sup->uid); + if (sub != 0) + printf(">?(-\\n[" SUB_LOWER_FORMAT "]+\\n[" HEIGHT_FORMAT "])", + uid, sub->uid); + printf("\n"); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]", + uid, p->uid); + if (sub != 0) + printf(">?(\\n[" SUB_LOWER_FORMAT "]+\\n[" DEPTH_FORMAT "])", + uid, sub->uid); + if (sup != 0) + printf(">?(-\\n[" SUP_RAISE_FORMAT "]+\\n[" DEPTH_FORMAT "])", + uid, sup->uid); + printf("\n"); + return res; +} + +void script_box::output() +{ + p->output(); + if (sup != 0) { + printf("\\Z" DELIMITER_CHAR); + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid); + sup->output(); + printf("\\s[\\n[" SIZE_FORMAT "]]", uid); + printf(DELIMITER_CHAR); + } + if (sub != 0) { + printf("\\Z" DELIMITER_CHAR); + printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid); + printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid); + printf("\\h'-\\n[" SUB_KERN_FORMAT "]u'", p->uid); + sub->output(); + printf("\\s[\\n[" SIZE_FORMAT "]]", uid); + printf(DELIMITER_CHAR); + } + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", + uid, p->uid); +} + +void script_box::hint(unsigned flags) +{ + p->hint(flags & ~HINT_NEXT_IS_ITALIC); +} + +void script_box::debug_print() +{ + fprintf(stderr, "{ "); + p->debug_print(); + fprintf(stderr, " }"); + if (sub) { + fprintf(stderr, " sub { "); + sub->debug_print(); + fprintf(stderr, " }"); + } + if (sup) { + fprintf(stderr, " sup { "); + sup->debug_print(); + fprintf(stderr, " }"); + } +} + +void script_box::check_tabs(int level) +{ + if (sup) + sup->check_tabs(level + 1); + if (sub) + sub->check_tabs(level + 1); + p->check_tabs(level); +} diff --git a/gnu/usr.bin/groff/eqn/special.cc b/gnu/usr.bin/groff/eqn/special.cc new file mode 100644 index 0000000000..be73543655 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/special.cc @@ -0,0 +1,115 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + +#define STRING_FORMAT PREFIX "str%d" + +#define SPECIAL_STRING "0s" +#define SPECIAL_WIDTH_REG "0w" +#define SPECIAL_HEIGHT_REG "0h" +#define SPECIAL_DEPTH_REG "0d" +#define SPECIAL_SUB_KERN_REG "0skern" +#define SPECIAL_SKEW_REG "0skew" + +/* +For example: + +.de Cl +.ds 0s \Z'\\*[0s]'\v'\\n(0du'\D'l \\n(0wu -\\n(0hu-\\n(0du'\v'\\n(0hu' +.. +.EQ +define cancel 'special Cl' +.EN +*/ + + +class special_box : public pointer_box { + char *macro_name; +public: + special_box(char *, box *); + ~special_box(); + int compute_metrics(int); + void compute_subscript_kern(); + void compute_skew(); + void output(); + void debug_print(); +}; + +box *make_special_box(char *s, box *p) +{ + return new special_box(s, p); +} + +special_box::special_box(char *s, box *pp) :macro_name(s), pointer_box(pp) +{ +} + +special_box::~special_box() +{ + a_delete macro_name; +} + +int special_box::compute_metrics(int style) +{ + int r = p->compute_metrics(style); + p->compute_subscript_kern(); + p->compute_skew(); + printf(".ds " SPECIAL_STRING " \""); + p->output(); + printf("\n"); + printf(".nr " SPECIAL_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", p->uid); + printf(".nr " SPECIAL_HEIGHT_REG " \\n[" HEIGHT_FORMAT "]\n", p->uid); + printf(".nr " SPECIAL_DEPTH_REG " \\n[" DEPTH_FORMAT "]\n", p->uid); + printf(".nr " SPECIAL_SUB_KERN_REG " \\n[" SUB_KERN_FORMAT "]\n", p->uid); + printf(".nr " SPECIAL_SKEW_REG " 0\\n[" SKEW_FORMAT "]\n", p->uid); + printf(".%s\n", macro_name); + printf(".rn " SPECIAL_STRING " " STRING_FORMAT "\n", uid); + printf(".nr " WIDTH_FORMAT " 0\\n[" SPECIAL_WIDTH_REG "]\n", uid); + printf(".nr " HEIGHT_FORMAT " 0>?\\n[" SPECIAL_HEIGHT_REG "]\n", uid); + printf(".nr " DEPTH_FORMAT " 0>?\\n[" SPECIAL_DEPTH_REG "]\n", uid); + printf(".nr " SUB_KERN_FORMAT " 0>?\\n[" SPECIAL_SUB_KERN_REG "]\n", uid); + printf(".nr " SKEW_FORMAT " 0\\n[" SPECIAL_SKEW_REG "]\n", uid); + // User will have to change MARK_REG if appropriate. + return r; +} + +void special_box::compute_subscript_kern() +{ + // Already computed in compute_metrics(), so do nothing. +} + +void special_box::compute_skew() +{ + // Already computed in compute_metrics(), so do nothing. +} + +void special_box::output() +{ + printf("\\*[" STRING_FORMAT "]", uid); +} + +void special_box::debug_print() +{ + fprintf(stderr, "special %s { ", macro_name); + p->debug_print(); + fprintf(stderr, " }"); +} diff --git a/gnu/usr.bin/groff/eqn/sqrt.cc b/gnu/usr.bin/groff/eqn/sqrt.cc new file mode 100644 index 0000000000..5ec05a0986 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/sqrt.cc @@ -0,0 +1,179 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" + + +class sqrt_box : public pointer_box { +public: + sqrt_box(box *); + int compute_metrics(int style); + void output(); + void debug_print(); + void check_tabs(int); +}; + +box *make_sqrt_box(box *pp) +{ + return new sqrt_box(pp); +} + +sqrt_box::sqrt_box(box *pp) : pointer_box(pp) +{ +} + +#define SQRT_CHAR "\\(sr" +#define RADICAL_EXTENSION_CHAR "\\(rn" + +#define SQRT_CHAIN "\\[sr\\\\n[" INDEX_REG "]]" +#define BAR_CHAIN "\\[rn\\\\n[" INDEX_REG "]]" + +int sqrt_box::compute_metrics(int style) +{ + // 11 + int r = p->compute_metrics(cramped_style(style)); + printf(".nr " TEMP_REG " \\n[" HEIGHT_FORMAT "]+\\n[" DEPTH_FORMAT + "]+%dM+(%dM/4)\n", + p->uid, p->uid, default_rule_thickness, + (style > SCRIPT_STYLE ? x_height : default_rule_thickness)); + printf(".nr " SIZE_FORMAT " \\n[.s]\n", uid); + printf(".ds " SQRT_STRING_FORMAT " " SQRT_CHAR "\n", uid); + printf(".ds " BAR_STRING " " RADICAL_EXTENSION_CHAR "\n"); + printf(".nr " SQRT_WIDTH_FORMAT + " 0\\w" DELIMITER_CHAR SQRT_CHAR DELIMITER_CHAR "\n", + uid); + printf(".if \\n[rst]-\\n[rsb]-%dM<\\n[" TEMP_REG "] \\{", + default_rule_thickness); + + printf(".nr " INDEX_REG " 0\n" + ".de " TEMP_MACRO "\n" + ".ie c" SQRT_CHAIN " \\{" + ".ds " SQRT_STRING_FORMAT " " SQRT_CHAIN "\n" + ".ie c" BAR_CHAIN " .ds " BAR_STRING " " BAR_CHAIN "\n" + ".el .ds " BAR_STRING " " RADICAL_EXTENSION_CHAR "\n" + ".nr " SQRT_WIDTH_FORMAT + " 0\\w" DELIMITER_CHAR SQRT_CHAIN DELIMITER_CHAR "\n" + ".if \\\\n[rst]-\\\\n[rsb]-%dM<\\n[" TEMP_REG "] \\{" + ".nr " INDEX_REG " +1\n" + "." TEMP_MACRO "\n" + ".\\}\\}\n" + ".el .nr " INDEX_REG " 0-1\n" + "..\n" + "." TEMP_MACRO "\n", + uid, uid, default_rule_thickness); + + printf(".if \\n[" INDEX_REG "]<0 \\{"); + + // Determine the maximum point size + printf(".ps 1000\n"); + printf(".nr " MAX_SIZE_REG " \\n[.s]\n"); + printf(".ps \\n[" SIZE_FORMAT "]\n", uid); + // We define a macro that will increase the current point size + // until we get a radical sign that's tall enough or we reach + // the maximum point size. + printf(".de " TEMP_MACRO "\n" + ".nr " SQRT_WIDTH_FORMAT + " 0\\w" DELIMITER_CHAR "\\*[" SQRT_STRING_FORMAT "]" DELIMITER_CHAR "\n" + ".if \\\\n[rst]-\\\\n[rsb]-%dM<\\n[" TEMP_REG "]" + "&(\\\\n[.s]<\\n[" MAX_SIZE_REG "]) \\{" + ".ps +1\n" + "." TEMP_MACRO "\n" + ".\\}\n" + "..\n" + "." TEMP_MACRO "\n", + uid, uid, default_rule_thickness); + + printf(".\\}\\}\n"); + + printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid); + // set TEMP_REG to the amount by which the radical sign is too big + printf(".nr " TEMP_REG " \\n[rst]-\\n[rsb]-%dM-\\n[" TEMP_REG "]\n", + default_rule_thickness); + // If TEMP_REG is negative, the bottom of the radical sign should + // be -TEMP_REG above the bottom of p. If it's positive, the bottom + // of the radical sign should be TEMP_REG/2 below the bottom of p. + // This calculates the amount by which the baseline of the radical + // should be raised. + printf(".nr " SUP_RAISE_FORMAT " (-\\n[" TEMP_REG "]>?(-\\n[" TEMP_REG "]/2))" + "-\\n[rsb]-\\n[" DEPTH_FORMAT "]\n", uid, p->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]" + ">?(\\n[" SUP_RAISE_FORMAT "]+\\n[rst])\n", + uid, p->uid, uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]" + ">?(-\\n[" SUP_RAISE_FORMAT "]-\\n[rsb])\n", + uid, p->uid, uid); + // Do this last, so we don't lose height and depth information on + // the radical sign. + // Remember that the width of the bar might be greater than the width of p. + + printf(".nr " TEMP_REG " " + "\\n[" WIDTH_FORMAT "]" + ">?\\w" DELIMITER_CHAR "\\*[" BAR_STRING "]" DELIMITER_CHAR "\n", + p->uid); + printf(".as " SQRT_STRING_FORMAT " " + "\\l'\\n[" TEMP_REG "]u\\&\\*[" BAR_STRING "]'\n", + uid); + printf(".nr " WIDTH_FORMAT " \\n[" TEMP_REG "]" + "+\\n[" SQRT_WIDTH_FORMAT "]\n", + uid, uid); + + if (r) + printf(".nr " MARK_REG " +\\n[" SQRT_WIDTH_FORMAT "]\n", uid); + // the top of the bar might be higher than the top of the radical sign + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]" + ">?(\\n[" SUP_RAISE_FORMAT "]+\\n[rst])\n", + uid, p->uid, uid); + // put a bit of extra space above the bar + printf(".nr " HEIGHT_FORMAT " +%dM\n", uid, default_rule_thickness); + printf(".ps \\n[" SIZE_FORMAT "]\n", uid); + return r; +} + +void sqrt_box::output() +{ + printf("\\Z" DELIMITER_CHAR); + printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid); + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + printf("\\*[" SQRT_STRING_FORMAT "]", uid); + printf("\\s[\\n[" SIZE_FORMAT "]]", uid); + printf(DELIMITER_CHAR); + + printf("\\Z" DELIMITER_CHAR); + printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u" + "+\\n[" SQRT_WIDTH_FORMAT "]u/2u'", + uid, p->uid, uid); + p->output(); + printf(DELIMITER_CHAR); + + printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); +} + +void sqrt_box::debug_print() +{ + fprintf(stderr, "sqrt { "); + p->debug_print(); + fprintf(stderr, " }"); +} + +void sqrt_box::check_tabs(int level) +{ + p->check_tabs(level + 1); +} diff --git a/gnu/usr.bin/groff/eqn/text.cc b/gnu/usr.bin/groff/eqn/text.cc new file mode 100644 index 0000000000..ee6618f8c2 --- /dev/null +++ b/gnu/usr.bin/groff/eqn/text.cc @@ -0,0 +1,528 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "eqn.h" +#include "pbox.h" +#include "ptable.h" + +class char_box : public simple_box { + unsigned char c; + char next_is_italic; + char prev_is_italic; +public: + char_box(unsigned char); + void debug_print(); + void output(); + int is_char(); + int left_is_italic(); + int right_is_italic(); + void hint(unsigned); + void handle_char_type(int, int); +}; + +class special_char_box : public simple_box { + char *s; +public: + special_char_box(const char *); + ~special_char_box(); + void output(); + void debug_print(); + int is_char(); + void handle_char_type(int, int); +}; + +const char *spacing_type_table[] = { + "ordinary", + "operator", + "binary", + "relation", + "opening", + "closing", + "punctuation", + "inner", + "suppress", + 0, +}; + +const int DIGIT_TYPE = 0; +const int LETTER_TYPE = 1; + +const char *font_type_table[] = { + "digit", + "letter", + 0, +}; + +struct char_info { + int spacing_type; + int font_type; + char_info(); +}; + +char_info::char_info() +: spacing_type(ORDINARY_TYPE), font_type(DIGIT_TYPE) +{ +} + +static char_info char_table[256]; + +declare_ptable(char_info) +implement_ptable(char_info) + +PTABLE(char_info) special_char_table; + +static int get_special_char_spacing_type(const char *ch) +{ + char_info *p = special_char_table.lookup(ch); + return p ? p->spacing_type : ORDINARY_TYPE; +} + +static int get_special_char_font_type(const char *ch) +{ + char_info *p = special_char_table.lookup(ch); + return p ? p->font_type : DIGIT_TYPE; +} + +static void set_special_char_type(const char *ch, int st, int ft) +{ + char_info *p = special_char_table.lookup(ch); + if (!p) { + p = new char_info; + special_char_table.define(ch, p); + } + if (st >= 0) + p->spacing_type = st; + if (ft >= 0) + p->font_type = ft; +} + +void init_char_table() +{ + set_special_char_type("pl", 2, -1); // binary + set_special_char_type("mi", 2, -1); + set_special_char_type("eq", 3, -1); // relation + set_special_char_type("<=", 3, -1); + set_special_char_type(">=", 3, -1); + char_table['}'].spacing_type = 5; // closing + char_table[')'].spacing_type = 5; + char_table[']'].spacing_type = 5; + char_table['{'].spacing_type = 4; // opening + char_table['('].spacing_type = 4; + char_table['['].spacing_type = 4; + char_table[','].spacing_type = 6; // punctuation + char_table[';'].spacing_type = 6; + char_table[':'].spacing_type = 6; + char_table['.'].spacing_type = 6; + char_table['>'].spacing_type = 3; + char_table['<'].spacing_type = 3; + char_table['*'].spacing_type = 2; // binary + for (int i = 0; i < 256; i++) + if (csalpha(i)) + char_table[i].font_type = LETTER_TYPE; +} + +static int lookup_spacing_type(const char *type) +{ + for (int i = 0; spacing_type_table[i] != 0; i++) + if (strcmp(spacing_type_table[i], type) == 0) + return i; + return -1; +} + +static int lookup_font_type(const char *type) +{ + for (int i = 0; font_type_table[i] != 0; i++) + if (strcmp(font_type_table[i], type) == 0) + return i; + return -1; +} + +void box::set_spacing_type(char *type) +{ + int t = lookup_spacing_type(type); + if (t < 0) + error("unrecognised type `%1'", type); + else + spacing_type = t; + a_delete type; +} + +char_box::char_box(unsigned char cc) +: c(cc), prev_is_italic(0), next_is_italic(0) +{ + spacing_type = char_table[c].spacing_type; +} + +void char_box::hint(unsigned flags) +{ + if (flags & HINT_PREV_IS_ITALIC) + prev_is_italic = 1; + if (flags & HINT_NEXT_IS_ITALIC) + next_is_italic = 1; +} + +void char_box::output() +{ + int font_type = char_table[c].font_type; + if (font_type != LETTER_TYPE) + printf("\\f[%s]", current_roman_font); + if (!prev_is_italic) + fputs("\\,", stdout); + if (c == '\\') + fputs("\\e", stdout); + else + putchar(c); + if (!next_is_italic) + fputs("\\/", stdout); + else + fputs("\\&", stdout); // suppress ligaturing and kerning + if (font_type != LETTER_TYPE) + fputs("\\fP", stdout); +} + +int char_box::left_is_italic() +{ + int font_type = char_table[c].font_type; + return font_type == LETTER_TYPE; +} + +int char_box::right_is_italic() +{ + int font_type = char_table[c].font_type; + return font_type == LETTER_TYPE; +} + +int char_box::is_char() +{ + return 1; +} + +void char_box::debug_print() +{ + if (c == '\\') { + putc('\\', stderr); + putc('\\', stderr); + } + else + putc(c, stderr); +} + +special_char_box::special_char_box(const char *t) +{ + s = strsave(t); + spacing_type = get_special_char_spacing_type(s); +} + +special_char_box::~special_char_box() +{ + a_delete s; +} + +void special_char_box::output() +{ + int font_type = get_special_char_font_type(s); + if (font_type != LETTER_TYPE) + printf("\\f[%s]", current_roman_font); + printf("\\,\\[%s]\\/", s); + if (font_type != LETTER_TYPE) + printf("\\fP"); +} + +int special_char_box::is_char() +{ + return 1; +} + +void special_char_box::debug_print() +{ + fprintf(stderr, "\\[%s]", s); +} + + +void char_box::handle_char_type(int st, int ft) +{ + if (st >= 0) + char_table[c].spacing_type = st; + if (ft >= 0) + char_table[c].font_type = ft; +} + +void special_char_box::handle_char_type(int st, int ft) +{ + set_special_char_type(s, st, ft); +} + +void set_char_type(const char *type, char *ch) +{ + assert(ch != 0); + int st = lookup_spacing_type(type); + int ft = lookup_font_type(type); + if (st < 0 && ft < 0) { + error("bad character type `%1'", type); + a_delete ch; + return; + } + box *b = split_text(ch); + b->handle_char_type(st, ft); + delete b; +} + +/* We give primes special treatment so that in ``x' sub 2'', the ``2'' +will be tucked under the prime */ + +class prime_box : public pointer_box { + box *pb; +public: + prime_box(box *); + ~prime_box(); + int compute_metrics(int style); + void output(); + void compute_subscript_kern(); + void debug_print(); + void handle_char_type(int, int); +}; + +box *make_prime_box(box *pp) +{ + return new prime_box(pp); +} + +prime_box::prime_box(box *pp) : pointer_box(pp) +{ + pb = new special_char_box("fm"); +} + +prime_box::~prime_box() +{ + delete pb; +} + +int prime_box::compute_metrics(int style) +{ + int res = p->compute_metrics(style); + pb->compute_metrics(style); + printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]" + "+\\n[" WIDTH_FORMAT "]\n", + uid, p->uid, pb->uid); + printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]" + ">?\\n[" HEIGHT_FORMAT "]\n", + uid, p->uid, pb->uid); + printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]" + ">?\\n[" DEPTH_FORMAT "]\n", + uid, p->uid, pb->uid); + return res; +} + +void prime_box::compute_subscript_kern() +{ + p->compute_subscript_kern(); + printf(".nr " SUB_KERN_FORMAT " 0\\n[" WIDTH_FORMAT "]" + "+\\n[" SUB_KERN_FORMAT "]>?0\n", + uid, pb->uid, p->uid); +} + +void prime_box::output() +{ + p->output(); + pb->output(); +} + +void prime_box::handle_char_type(int st, int ft) +{ + p->handle_char_type(st, ft); + pb->handle_char_type(st, ft); +} + +void prime_box::debug_print() +{ + p->debug_print(); + putc('\'', stderr); +} + +box *split_text(char *text) +{ + list_box *lb = 0; + box *fb = 0; + char *s = text; + while (*s != '\0') { + char c = *s++; + box *b = 0; + switch (c) { + case '+': + b = new special_char_box("pl"); + break; + case '-': + b = new special_char_box("mi"); + break; + case '=': + b = new special_char_box("eq"); + break; + case '\'': + b = new special_char_box("fm"); + break; + case '<': + if (*s == '=') { + b = new special_char_box("<="); + s++; + break; + } + goto normal_char; + case '>': + if (*s == '=') { + b = new special_char_box(">="); + s++; + break; + } + goto normal_char; + case '\\': + if (*s == '\0') { + lex_error("bad escape"); + break; + } + c = *s++; + switch (c) { + case '(': + { + char buf[3]; + if (*s != '\0') { + buf[0] = *s++; + if (*s != '\0') { + buf[1] = *s++; + buf[2] = '\0'; + b = new special_char_box(buf); + } + else { + lex_error("bad escape"); + } + } + else { + lex_error("bad escape"); + } + } + break; + case '[': + { + char *ch = s; + while (*s != ']' && *s != '\0') + s++; + if (*s == '\0') + lex_error("bad escape"); + else { + *s++ = '\0'; + b = new special_char_box(ch); + } + } + break; + case 'f': + case 'g': + case 'k': + case 'n': + case '*': + { + char *escape_start = s - 2; + switch (*s) { + case '(': + if (*++s != '\0') + ++s; + break; + case '[': + for (++s; *s != '\0' && *s != ']'; s++) + ; + break; + } + if (*s == '\0') + lex_error("bad escape"); + else { + ++s; + char *buf = new char[s - escape_start + 1]; + memcpy(buf, escape_start, s - escape_start); + buf[s - escape_start] = '\0'; + b = new quoted_text_box(buf); + } + } + break; + case '-': + case '_': + { + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + b = new special_char_box(buf); + } + break; + case '`': + b = new special_char_box("ga"); + break; + case '\'': + b = new special_char_box("aa"); + break; + case 'e': + case '\\': + b = new char_box('\\'); + break; + case '^': + case '|': + case '0': + { + char buf[3]; + buf[0] = '\\'; + buf[1] = c; + buf[2] = '\0'; + b = new quoted_text_box(strsave(buf)); + break; + } + default: + lex_error("unquoted escape"); + b = new quoted_text_box(strsave(s - 2)); + s = strchr(s, '\0'); + break; + } + break; + default: + normal_char: + b = new char_box(c); + break; + } + while (*s == '\'') { + if (b == 0) + b = new quoted_text_box(0); + b = new prime_box(b); + s++; + } + if (b != 0) { + if (lb != 0) + lb->append(b); + else if (fb != 0) { + lb = new list_box(fb); + lb->append(b); + } + else + fb = b; + } + } + delete text; + if (lb != 0) + return lb; + else if (fb != 0) + return fb; + else + return new quoted_text_box(0); +} + diff --git a/gnu/usr.bin/groff/grodvi/Makefile b/gnu/usr.bin/groff/grodvi/Makefile new file mode 100644 index 0000000000..11a8d761d4 --- /dev/null +++ b/gnu/usr.bin/groff/grodvi/Makefile @@ -0,0 +1,12 @@ +# Makefile for grodvi + +PROG= grodvi +SRCS= dvi.cc +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBDRIVER) $(LIBGROFF) -lm +DPADD+= $(LIBDRIVER) $(LIBGROFF) $(LIBMATH) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/grodvi/Makefile.dep b/gnu/usr.bin/groff/grodvi/Makefile.dep new file mode 100644 index 0000000000..6f9489e31c --- /dev/null +++ b/gnu/usr.bin/groff/grodvi/Makefile.dep @@ -0,0 +1,2 @@ +dvi.o : dvi.cc ../include/driver.h ../include/errarg.h ../include/error.h \ + ../include/font.h ../include/printer.h ../include/lib.h diff --git a/gnu/usr.bin/groff/grodvi/dvi.cc b/gnu/usr.bin/groff/grodvi/dvi.cc new file mode 100644 index 0000000000..c3ae76ee6c --- /dev/null +++ b/gnu/usr.bin/groff/grodvi/dvi.cc @@ -0,0 +1,895 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "driver.h" + +#define DEFAULT_LINEWIDTH 40 +static int linewidth = DEFAULT_LINEWIDTH; + +static int draw_flag = 1; + +/* These values were chosen because: + +(MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27) + +and 57816 is an exact multiple of both 72.27*SIZESCALE and 72. + +The width in the groff font file is the product of MULTIPLIER and the +width in the tfm file. */ + +#define RES 57816 +#define RES_7227 (RES/7227) +#define UNITWIDTH 131072 +#define SIZESCALE 100 +#define MULTIPLIER 1 + +#define FILL_MAX 1000 + +class dvi_font : public font { + dvi_font(const char *); +public: + int checksum; + int design_size; + ~dvi_font(); + void handle_unknown_font_command(const char *command, const char *arg, + const char *filename, int lineno); + static dvi_font *load_dvi_font(const char *); +}; + +dvi_font *dvi_font::load_dvi_font(const char *s) +{ + dvi_font *f = new dvi_font(s); + if (!f->load()) { + delete f; + return 0; + } + return f; +} + +dvi_font::dvi_font(const char *nm) +: font(nm), checksum(0), design_size(0) +{ +} + +dvi_font::~dvi_font() +{ +} + +void dvi_font::handle_unknown_font_command(const char *command, + const char *arg, + const char *filename, int lineno) +{ + char *ptr; + if (strcmp(command, "checksum") == 0) { + if (arg == 0) + fatal_with_file_and_line(filename, lineno, + "`checksum' command requires an argument"); + checksum = int(strtol(arg, &ptr, 10)); + if (checksum == 0 && ptr == arg) { + fatal_with_file_and_line(filename, lineno, "bad checksum"); + } + } + else if (strcmp(command, "designsize") == 0) { + if (arg == 0) + fatal_with_file_and_line(filename, lineno, + "`designsize' command requires an argument"); + design_size = int(strtol(arg, &ptr, 10)); + if (design_size == 0 && ptr == arg) { + fatal_with_file_and_line(filename, lineno, "bad design size"); + } + } +} + +#define FONTS_MAX 256 + +struct output_font { + dvi_font *f; + int point_size; + output_font() : f(0) { } +}; + +class dvi_printer : public printer { + FILE *fp; + int max_drift; + int byte_count; + int last_bop; + int page_count; + int cur_h; + int cur_v; + int end_h; + int max_h; + int max_v; + output_font output_font_table[FONTS_MAX]; + font *cur_font; + int cur_point_size; + int pushed; + int pushed_h; + int pushed_v; + int have_pushed; + void preamble(); + void postamble(); + void define_font(int); + void set_font(int); + void possibly_begin_line(); +protected: + enum { + id_byte = 2, + set1 = 128, + put1 = 133, + put_rule = 137, + bop = 139, + eop = 140, + push = 141, + pop = 142, + right1 = 143, + down1 = 157, + fnt_num_0 = 171, + fnt1 = 235, + xxx1 = 239, + fnt_def1 = 243, + pre = 247, + post = 248, + post_post = 249, + filler = 223 + }; + int line_thickness; + + void out1(int); + void out2(int); + void out3(int); + void out4(int); + void moveto(int, int); + void out_string(const char *); + void out_signed(unsigned char, int); + void out_unsigned(unsigned char, int); + void do_special(const char *); +public: + dvi_printer(); + ~dvi_printer(); + font *make_font(const char *); + void begin_page(int); + void end_page(int); + void set_char(int, font *, const environment *, int w); + void special(char *arg, const environment *env); + void end_of_line(); + void draw(int code, int *p, int np, const environment *env); +}; + + +class draw_dvi_printer : public dvi_printer { + int output_pen_size; + int fill; + void set_line_thickness(const environment *); + void fill_next(); +public: + draw_dvi_printer(); + ~draw_dvi_printer(); + void draw(int code, int *p, int np, const environment *env); + void end_page(int); +}; + +dvi_printer::dvi_printer() +: byte_count(0), last_bop(-1), page_count(0), cur_font(0), fp(stdout), + max_h(0), max_v(0), pushed(0), line_thickness(-1), cur_point_size(-1) +{ + if (font::res != RES) + fatal("resolution must be %1", RES); + if (font::unitwidth != UNITWIDTH) + fatal("unitwidth must be %1", UNITWIDTH); + if (font::hor != 1) + fatal("hor must be equal to 1"); + if (font::vert != 1) + fatal("vert must be equal to 1"); + if (font::sizescale != SIZESCALE) + fatal("sizescale must be equal to %1", SIZESCALE); + max_drift = font::res/1000; // this is fairly arbitrary + preamble(); +} + +dvi_printer::~dvi_printer() +{ + postamble(); +} + + +draw_dvi_printer::draw_dvi_printer() +: output_pen_size(-1), fill(FILL_MAX) +{ +} + +draw_dvi_printer::~draw_dvi_printer() +{ +} + + +void dvi_printer::out1(int n) +{ + byte_count += 1; + putc(n & 0xff, fp); +} + +void dvi_printer::out2(int n) +{ + byte_count += 2; + putc((n >> 8) & 0xff, fp); + putc(n & 0xff, fp); +} + +void dvi_printer::out3(int n) +{ + byte_count += 3; + putc((n >> 16) & 0xff, fp); + putc((n >> 8) & 0xff, fp); + putc(n & 0xff, fp); +} + +void dvi_printer::out4(int n) +{ + byte_count += 4; + putc((n >> 24) & 0xff, fp); + putc((n >> 16) & 0xff, fp); + putc((n >> 8) & 0xff, fp); + putc(n & 0xff, fp); +} + +void dvi_printer::out_string(const char *s) +{ + out1(strlen(s)); + while (*s != 0) + out1(*s++); +} + + +void dvi_printer::end_of_line() +{ + if (pushed) { + out1(pop); + pushed = 0; + cur_h = pushed_h; + cur_v = pushed_v; + } +} + +void dvi_printer::possibly_begin_line() +{ + if (!pushed) { + have_pushed = pushed = 1; + pushed_h = cur_h; + pushed_v = cur_v; + out1(push); + } +} + +int scale(int x, int z) +{ + int sw; + int a, b, c, d; + int alpha, beta; + alpha = 16*z; beta = 16; + while (z >= 040000000L) { + z /= 2; beta /= 2; + } + d = x & 255; + c = (x >> 8) & 255; + b = (x >> 16) & 255; + a = (x >> 24) & 255; + sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta; + if (a == 255) + sw -= alpha; + else + assert(a == 0); + return sw; +} + + +void dvi_printer::set_char(int index, font *f, const environment *env, int w) +{ + int code = f->get_code(index); + if (env->size != cur_point_size || f != cur_font) { + cur_font = f; + cur_point_size = env->size; + for (int i = 0;; i++) { + if (i >= FONTS_MAX) { + fatal("too many output fonts required"); + } + if (output_font_table[i].f == 0) { + output_font_table[i].f = (dvi_font *)cur_font; + output_font_table[i].point_size = cur_point_size; + define_font(i); + } + if (output_font_table[i].f == cur_font + && output_font_table[i].point_size == cur_point_size) + break; + } + set_font(i); + } + int distance = env->hpos - cur_h; + if (env->hpos != end_h && distance != 0) { + out_signed(right1, distance); + cur_h = env->hpos; + } + else if (distance > max_drift) { + out_signed(right1, distance - max_drift); + cur_h = env->hpos - max_drift; + } + else if (distance < -max_drift) { + out_signed(right1, distance + max_drift); + cur_h = env->hpos + max_drift; + } + if (env->vpos != cur_v) { + out_signed(down1, env->vpos - cur_v); + cur_v = env->vpos; + } + possibly_begin_line(); + end_h = env->hpos + w; + cur_h += scale(f->get_width(index, UNITWIDTH)/MULTIPLIER, + cur_point_size*RES_7227); + if (cur_h > max_h) + max_h = cur_h; + if (cur_v > max_v) + max_v = cur_v; + if (code >= 0 && code <= 127) + out1(code); + else + out_unsigned(set1, code); +} + +void dvi_printer::define_font(int i) +{ + out_unsigned(fnt_def1, i); + dvi_font *f = output_font_table[i].f; + out4(f->checksum); + out4(output_font_table[i].point_size*RES_7227); + out4(int((double(f->design_size)/(1<<20))*RES_7227*100 + .5)); + const char *nm = f->get_internal_name(); + out1(0); + out_string(nm); +} + +void dvi_printer::set_font(int i) +{ + if (i >= 0 && i <= 63) + out1(fnt_num_0 + i); + else + out_unsigned(fnt1, i); +} + +void dvi_printer::out_signed(unsigned char base, int param) +{ + if (-128 <= param && param < 128) { + out1(base); + out1(param); + } + else if (-32768 <= param && param < 32768) { + out1(base+1); + out2(param); + } + else if (-(1 << 23) <= param && param < (1 << 23)) { + out1(base+2); + out3(param); + } + else { + out1(base+3); + out4(param); + } +} + +void dvi_printer::out_unsigned(unsigned char base, int param) +{ + if (param >= 0) { + if (param < 256) { + out1(base); + out1(param); + } + else if (param < 65536) { + out1(base+1); + out2(param); + } + else if (param < (1 << 24)) { + out1(base+2); + out3(param); + } + else { + out1(base+3); + out4(param); + } + } + else { + out1(base+3); + out4(param); + } +} + +void dvi_printer::preamble() +{ + out1(pre); + out1(id_byte); + out4(254000); + out4(font::res); + out4(1000); + out1(0); +} + +void dvi_printer::postamble() +{ + int tem = byte_count; + out1(post); + out4(last_bop); + out4(254000); + out4(font::res); + out4(1000); + out4(max_v); + out4(max_h); + out2(have_pushed); // stack depth + out2(page_count); + int i; + for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++) + define_font(i); + out1(post_post); + out4(tem); + out1(id_byte); + for (i = 0; i < 4 || byte_count % 4 != 0; i++) + out1(filler); +} + +void dvi_printer::begin_page(int i) +{ + page_count++; + int tem = byte_count; + out1(bop); + out4(i); + for (int j = 1; j < 10; j++) + out4(0); + out4(last_bop); + last_bop = tem; + // By convention position (0,0) in a dvi file is placed at (1in, 1in). + cur_h = font::res; + cur_v = font::res; + end_h = 0; +} + +void dvi_printer::end_page(int) +{ + if (pushed) + end_of_line(); + out1(eop); + cur_font = 0; +} + +void draw_dvi_printer::end_page(int len) +{ + dvi_printer::end_page(len); + output_pen_size = -1; +} + +void dvi_printer::do_special(const char *s) +{ + int len = strlen(s); + if (len == 0) + return; + possibly_begin_line(); + out_unsigned(xxx1, len); + while (*s) + out1(*s++); +} + +void dvi_printer::special(char *arg, const environment *env) +{ + moveto(env->hpos, env->vpos); + do_special(arg); +} + +void dvi_printer::moveto(int h, int v) +{ + if (h != cur_h) { + out_signed(right1, h - cur_h); + cur_h = h; + if (cur_h > max_h) + max_h = cur_h; + } + if (v != cur_v) { + out_signed(down1, v - cur_v); + cur_v = v; + if (cur_v > max_v) + max_v = cur_v; + } + end_h = 0; +} + +void dvi_printer::draw(int code, int *p, int np, const environment *env) +{ + if (code == 'l') { + int x, y; + int height = 0, width; + int thickness; + if (line_thickness < 0) + thickness = env->size*RES_7227*linewidth/1000; + else if (line_thickness > 0) + thickness = line_thickness; + else + thickness = 1; + if (np != 2) { + error("2 arguments required for line"); + } + else if (p[0] == 0) { + // vertical rule + if (p[1] > 0) { + x = env->hpos - thickness/2; + y = env->vpos + p[1] + thickness/2; + height = p[1] + thickness; + width = thickness; + } + else if (p[1] < 0) { + x = env->hpos - thickness/2; + y = env->vpos + thickness/2; + height = thickness - p[1]; + width = thickness; + } + } + else if (p[1] == 0) { + if (p[0] > 0) { + x = env->hpos - thickness/2; + y = env->vpos + thickness/2; + height = thickness; + width = p[0] + thickness; + } + else if (p[0] < 0) { + x = env->hpos - p[0] - thickness/2; + y = env->vpos + thickness/2; + height = thickness; + width = thickness - p[0]; + } + } + if (height != 0) { + moveto(x, y); + out1(put_rule); + out4(height); + out4(width); + } + } + else if (code == 't') { + if (np == 0) { + line_thickness = -1; + } + else { + // troff gratuitously adds an extra 0 + if (np != 1 && np != 2) + error("0 or 1 argument required for thickness"); + else + line_thickness = p[0]; + } + } + else if (code == 'R') { + if (np != 2) + error("2 arguments required for rule"); + else if (p[0] != 0 || p[1] != 0) { + int dh = p[0]; + int dv = p[1]; + int oh = env->hpos; + int ov = env->vpos; + if (dv > 0) { + ov += dv; + dv = -dv; + } + if (dh < 0) { + oh += dh; + dh = -dh; + } + moveto(oh, ov); + out1(put_rule); + out4(-dv); + out4(dh); + } + } +} + +// XXX Will this overflow? + +inline int milliinches(int n) +{ + return (n*1000 + font::res/2)/font::res; +} + +void draw_dvi_printer::set_line_thickness(const environment *env) +{ + int desired_pen_size + = milliinches(line_thickness < 0 + // Will this overflow? + ? env->size*RES_7227*linewidth/1000 + : line_thickness); + if (desired_pen_size != output_pen_size) { + char buf[256]; + sprintf(buf, "pn %d", desired_pen_size); + do_special(buf); + output_pen_size = desired_pen_size; + } +} + +void draw_dvi_printer::fill_next() +{ + char buf[256]; + sprintf(buf, "sh %.3f", double(fill)/FILL_MAX); + do_special(buf); +} + +void draw_dvi_printer::draw(int code, int *p, int np, const environment *env) +{ + char buf[1024]; + int fill_flag = 0; + switch (code) { + case 'C': + fill_flag = 1; + // fall through + case 'c': + // troff adds an extra argument to C + if (np != 1 && !(code == 'C' && np == 2)) { + error("1 argument required for circle"); + break; + } + moveto(env->hpos+p[0]/2, env->vpos); + if (fill_flag) + fill_next(); + else + set_line_thickness(env); + int rad; + rad = milliinches(p[0]/2); + sprintf(buf, "%s 0 0 %d %d 0 6.28319", + (fill_flag ? "ia" : "ar"), + rad, + rad); + do_special(buf); + break; + case 'l': + if (np != 2) { + error("2 arguments required for line"); + break; + } + moveto(env->hpos, env->vpos); + set_line_thickness(env); + do_special("pa 0 0"); + sprintf(buf, "pa %d %d", milliinches(p[0]), milliinches(p[1])); + do_special(buf); + do_special("fp"); + break; + case 'E': + fill_flag = 1; + // fall through + case 'e': + if (np != 2) { + error("2 arguments required for ellipse"); + break; + } + moveto(env->hpos+p[0]/2, env->vpos); + if (fill_flag) + fill_next(); + sprintf(buf, "%s 0 0 %d %d 0 6.28319", + (fill_flag ? "ia" : "ar"), + milliinches(p[0]/2), + milliinches(p[1]/2)); + do_special(buf); + break; + case 'P': + fill_flag = 1; + // fall through + case 'p': + { + if (np & 1) { + error("even number of arguments required for polygon"); + break; + } + if (np == 0) { + error("no arguments for polygon"); + break; + } + moveto(env->hpos, env->vpos); + if (fill_flag) + fill_next(); + else + set_line_thickness(env); + do_special("pa 0 0"); + int h = 0, v = 0; + for (int i = 0; i < np; i += 2) { + h += p[i]; + v += p[i+1]; + sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); + do_special(buf); + } + do_special("pa 0 0"); + do_special(fill_flag ? "ip" : "fp"); + break; + } + case '~': + { + if (np & 1) { + error("even number of arguments required for spline"); + break; + } + if (np == 0) { + error("no arguments for spline"); + break; + } + moveto(env->hpos, env->vpos); + set_line_thickness(env); + do_special("pa 0 0"); + int h = 0, v = 0; + for (int i = 0; i < np; i += 2) { + h += p[i]; + v += p[i+1]; + sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); + do_special(buf); + } + do_special("sp"); + break; + } + case 'a': + { + if (np != 4) { + error("4 arguments required for arc"); + break; + } + set_line_thickness(env); + double c[2]; + if (adjust_arc_center(p, c)) { + int rad = milliinches(int(sqrt(c[0]*c[0] + c[1]*c[1]) + .5)); + moveto(env->hpos + int(c[0]), env->vpos + int(c[1])); + sprintf(buf, "ar 0 0 %d %d %f %f", + rad, + rad, + atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]), + atan2(-c[1], -c[0])); + do_special(buf); + } + else { + moveto(env->hpos, env->vpos); + do_special("pa 0 0"); + sprintf(buf, + "pa %d %d", + milliinches(p[0] + p[2]), + milliinches(p[1] + p[3])); + do_special(buf); + do_special("fp"); + } + break; + } + case 't': + { + if (np == 0) { + line_thickness = -1; + } + else { + // troff gratuitously adds an extra 0 + if (np != 1 && np != 2) { + error("0 or 1 argument required for thickness"); + break; + } + line_thickness = p[0]; + } + break; + } + case 'f': + { + if (np != 1 && np != 2) { + error("1 argument required for fill"); + break; + } + fill = p[0]; + if (fill < 0 || fill > FILL_MAX) + fill = FILL_MAX; + break; + } + case 'R': + { + if (np != 2) { + error("2 arguments required for rule"); + break; + } + int dh = p[0]; + if (dh == 0) + break; + int dv = p[1]; + if (dv == 0) + break; + int oh = env->hpos; + int ov = env->vpos; + if (dv > 0) { + ov += dv; + dv = -dv; + } + if (dh < 0) { + oh += dh; + dh = -dh; + } + moveto(oh, ov); + out1(put_rule); + out4(-dv); + out4(dh); + break; + } + default: + error("unrecognised drawing command `%1'", char(code)); + break; + } +} + +font *dvi_printer::make_font(const char *nm) +{ + return dvi_font::load_dvi_font(nm); +} + +printer *make_printer() +{ + if (draw_flag) + return new draw_dvi_printer; + else + return new dvi_printer; +} + +static void usage(); + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int c; + while ((c = getopt(argc, argv, "F:vw:d")) != EOF) + switch(c) { + case 'v': + { + extern const char *version_string; + fprintf(stderr, "grodvi version %s\n", version_string); + fflush(stderr); + break; + } + case 'w': + if (sscanf(optarg, "%d", &linewidth) != 1 + || linewidth < 0 || linewidth > 1000) { + error("bad line width"); + linewidth = DEFAULT_LINEWIDTH; + } + break; + case 'd': + draw_flag = 0; + break; + case 'F': + font::command_line_font_dir(optarg); + break; + case '?': + usage(); + break; + default: + assert(0); + } + if (optind >= argc) + do_file("-"); + else { + for (int i = optind; i < argc; i++) + do_file(argv[i]); + } + delete pr; + exit(0); +} + +static void usage() +{ + fprintf(stderr, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n", + program_name); + exit(1); +} diff --git a/gnu/usr.bin/groff/grodvi/grodvi.1 b/gnu/usr.bin/groff/grodvi/grodvi.1 new file mode 100644 index 0000000000..e2fbd2d423 --- /dev/null +++ b/gnu/usr.bin/groff/grodvi/grodvi.1 @@ -0,0 +1,154 @@ +.\" -*- nroff -*- +.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X +.el .ds tx TeX +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH GRODVI 1 "6 August 1992" "Groff Version 1.08" +.SH NAME +grodvi \- convert groff output to TeX dvi format +.SH SYNOPSIS +.B grodvi +[ +.B \-dv +] [ +.BI \-w n +] [ +.BI \-F dir +] [ +.IR files \|.\|.\|. +] +.SH DESCRIPTION +.B grodvi +is a driver for +.B groff +that produces \*(tx dvi format. +Normally it should be run by +.BR groff\ \-Tdvi . +This will run +.BR troff\ \-Tdvi ; +it will also input the macros +.BR /usr/share/tmac/tmac.dvi ; +if the input is being preprocessed with +.B eqn +it will also input +.BR /usr/share/groff_font/devdvi/eqnchar . +.LP +The dvi file generated by +.B grodvi +can be printed by any correctly-written dvi driver. +The troff drawing primitives are implemented +using the tpic version 2 specials. +If the driver does not support these, the +.B \eD +commands will not produce any output. +.LP +There is an additional drawing command available: +.TP +.BI \eD'R\ dh\ dv ' +Draw a rule (solid black rectangle), with one corner +at the current position, and the diagonally opposite corner +at the current position +.RI +( dh , dv ). +Afterwards the current position will be at the opposite corner. This +produces a rule in the dvi file and so can be printed even with a +driver that does not support the tpic specials unlike the other +.B \eD +commands. +.LP +The groff command +.BI \eX' anything ' +is translated into the same command in the dvi file as would be +produced by +.BI \especial{ anything } +in \*(tx; +.I anything may not contain a newline. +.LP +Font files for +.B grodvi +can be created from tfm files using +.BR tfmtodit (1). +The font description file should contain the following +additional commands: +.Tp \w'\fBinternalname'u+2n +.BI internalname\ name +The name of the tfm file (without the +.B .tfm +extension) is +.IR name . +.TP +.BI checksum\ n +The checksum in the tfm file is +.IR n . +.TP +.BI designsize\ n +The designsize in the tfm file is +.IR n . +.LP +These are automatically generated by +.B tfmtodit. +.LP +In +.B troff +the +.B \eN +escape sequence can be used to access characters by their position +in the corresponding tfm file; +all characters in the tfm file can be accessed this way. +.SH OPTIONS +.TP +.B \-d +Do not use tpic specials to implement drawing commands. +Horizontal and vertical lines will be implemented by rules. +Other drawing commands will be ignored. +.TP +.B \-v +Print the version number. +.TP +.BI \-w n +Set the default line thickness to +.I n +thousandths of an em. +.TP +.BI \-F dir +Search directory +.IB dir /devdvi +for font and device description files. +.SH FILES +.TP +.B /usr/share/groff_font/devdvi/DESC +Device desciption file. +.TP +.B /usr/share/groff_font/devdvi/ F +Font description file for font +.IR F . +.TP +.B /usr/share/tmac/tmac.dvi +Macros for use with +.BR grodvi . +.SH BUGS +Dvi files produced by +.B grodvi +use a different resolution (57816 units per inch) to those produced by +\*(tx. +Incorrectly written drivers which assume the resolution used by \*(tx, +rather than using the resolution specified in the dvi file will not +work with grodvi. +.LP +When using the +.B \-d +option with boxed tables, +vertical and horizontal lines can sometimes protrude by one pixel. +This is a consequence of the way \*(tx requires that the heights +and widths of rules be rounded. +.SH "SEE ALSO" +.BR tfmtodit (1), +.BR groff (1), +.BR troff (1), +.BR eqn (1), +.BR groff_out (5), +.BR groff_font (5), +.BR groff_char (7) diff --git a/gnu/usr.bin/groff/groff/Makefile b/gnu/usr.bin/groff/groff/Makefile new file mode 100644 index 0000000000..b75af46da6 --- /dev/null +++ b/gnu/usr.bin/groff/groff/Makefile @@ -0,0 +1,12 @@ +# Makefile for groff + +PROG= groff +SRCS= groff.cc pipeline.c +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBGROFF) -lm +DPADD+= $(LIBGROFF) $(LIBMATH) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/groff/Makefile.dep b/gnu/usr.bin/groff/groff/Makefile.dep new file mode 100644 index 0000000000..e333ea2761 --- /dev/null +++ b/gnu/usr.bin/groff/groff/Makefile.dep @@ -0,0 +1,4 @@ +groff.o : groff.cc ../include/lib.h ../include/assert.h ../include/errarg.h \ + ../include/error.h ../include/stringclass.h ../include/cset.h \ + ../include/font.h ../include/device.h pipeline.h ../include/defs.h +pipeline.o : pipeline.c pipeline.h diff --git a/gnu/usr.bin/groff/groff/groff.1 b/gnu/usr.bin/groff/groff/groff.1 new file mode 100644 index 0000000000..8a63a9669a --- /dev/null +++ b/gnu/usr.bin/groff/groff/groff.1 @@ -0,0 +1,362 @@ +.\" -*- nroff -*- +.de TQ +.br +.ns +.TP \\$1 +.. +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH GROFF 1 "29 October 1992" "Groff Version 1.08" +.SH NAME +groff \- front end for the groff document formatting system +.SH SYNOPSIS +.B groff +[ +.B \-tpeszaivhblCENRVXZ +] +[ +.BI \-w name +] +[ +.BI \-W name +] +[ +.BI \-m name +] +[ +.BI \-F dir +] +[ +.BI \-T dev +] +[ +.BI \-f fam +] +[ +.BI \-M dir +] +[ +.BI \-d cs +] +[ +.BI \-r cn +] +[ +.BI \-n num +] +[ +.BI \-o list +] +[ +.BI \-P arg +] +[ +.IR files \|.\|.\|.\| +] +.SH DESCRIPTION +.B groff +is a front-end to the groff document formatting system. +Normally it runs the +.B troff +program and a postprocessor appropriate for the selected +device. +Available devices are: +.TP +.B ps +For PostScript printers and previewers +.TP +.B dvi +For TeX dvi format +.TP +.B X75 +For a 75 dpi X11 previewer +.TP +.B X100 +For a 100dpi X11 previewer +.TP +.B ascii +For typewriter-like devices +.TP +.B latin1 +For typewriter-like devices using the ISO Latin-1 character set. +.LP +The postprocessor to be used for a device is specified by the +.B postpro +command in the device description file. +This can be overridden with the +.B \-X +option. +.LP +The default device is +.BR ps . +It can optionally preprocess with any of +.BR pic , +.BR eqn , +.BR tbl , +.BR refer , +or +.B soelim. +.LP +Options without an argument can be grouped behind a single +.BR \- . +A filename of +.B \- +denotes the standard input. +.LP +The +.B grog +command can be used to guess the correct groff command to use to +format a file. +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.B \-e +Preprocess with eqn. +.TP +.B \-t +Preprocess with tbl. +.TP +.B \-p +Preprocess with pic. +.TP +.B \-s +Preprocess with soelim. +.TP +.B \-R +Preprocess with refer. +No mechanism is provided for passing arguments to +.B refer +because most refer options have equivalent commands +which can be included in the file. +See +.BR refer (1) +for more details. +.TP +.B \-v +Make programs run by +.B groff +print out their version number. +.TP +.B \-V +Print the pipeline on stdout instead of executing it. +.TP +.B \-z +Suppress output from +.BR troff . +Only error messages will be printed. +.TP +.B \-Z +Do not postprocess the output of +.BR troff . +Normally +.B groff +will automatically run the appropriate postprocessor. +.TP +.BI \-P arg +Pass +.I arg +to the postprocessor. +Each argument should be passed with a separate +.B \-P +option. +Note that +.B groff +does not prepend +.B \- +to +.I arg +before passing it to the postprocessor. +.TP +.B \-l +Send the output to a printer. +The command used for this is specified by the +.B print +command in the device description file. +.TP +.BI \-L arg +Pass +.I arg +to the spooler. +Each argument should be passed with a separate +.B \-L +option. +Note that +.B groff +does not prepend +.B \- +to +.I arg +before passing it to the postprocessor. +.TP +.BI \-T dev +Prepare output for device +.IR dev . +The default device is +.BR ps . +.TP +.B \-X +Preview with +.B gxditview +instead of using the usual postprocessor. +This is unlikely to produce good results except with +.BR \-Tps . +.TP +.B \-N +Don't allow newlines with eqn delimiters. +This is the same as the +.B \-N +option in +.BR eqn . +.TP +.B \-a +.TQ +.B \-b +.TQ +.B \-i +.TQ +.B \-C +.TQ +.B \-E +.TQ +.BI \-w name +.TQ +.BI \-W name +.TQ +.BI \-m name +.TQ +.BI \-o list +.TQ +.BI \-d cs +.TQ +.BI \-r cn +.TQ +.BI \-F dir +.TQ +.BI \-M dir +.TQ +.BI \-f fam +.TQ +.BI \-n num +These are as described in +.BR troff (1) . +.SH ENVIRONMENT +.TP +.SM +.B GROFF_COMMAND_PREFIX +If this is set +.IR X , +then +.B groff +will run +.IB X troff +instead of +.BR troff . +This also applies to +.BR tbl , +.BR pic , +.BR eqn , +.B refer +and +.BR soelim . +It does not apply to +.BR grops , +.BR grodvi , +.BR grotty +and +.BR gxditview . +.TP +.SM +.B GROFF_TMAC_PATH +A colon separated list of directories in which to search for +macro files. +.TP +.SM +.B GROFF_TYPESETTER +Default device. +.TP +.SM +.B GROFF_FONT_PATH +A colon separated list of directories in which to search for the +.BI dev name +directory. +.TP +.SM +.B PATH +The search path for commands executed by +.BR groff . +.TP +.SM +.B GROFF_TMPDIR +The directory in which temporary files will be created. +If this is not set and +.B +.SM TMPDIR +is set, temporary files will be created in that directory. +Otherwise temporary files will be created in +.BR /tmp . +The +.BR grops (1) +and +.BR refer (1) +commands can create temporary files. +.SH FILES +.Tp \w'\fB/usr/share/groff_font/dev\fIname\fB/DESC'u+3n +.BI /usr/share/groff_font/dev name /DESC +Device description file for device +.IR name . +.TP +.BI /usr/share/groff_font/dev name / F +Font file for font +.I F +of device +.IR name . +.SH AUTHOR +James Clark +.SH BUGS +Report bugs to bug-groff@prep.ai.mit.edu. +Include a complete, self-contained example +that will allow the bug to be reproduced, +and say which version of groff you are using. +.SH COPYRIGHT +Copyright \(co 1989, 1990, 1991, 1992 Free Software Foundation, Inc. +.LP +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. +.LP +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. +.LP +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +.SH AVAILABILITY +The most recent released version of groff is always available for +anonymous ftp from prep.ai.mit.edu (18.71.0.38) in the directory +pub/gnu. +.SH "SEE ALSO" +.BR grog (1), +.BR troff (1), +.BR tbl (1), +.BR pic (1), +.BR eqn (1), +.BR soelim (1) , +.BR refer (1), +.BR grops (1), +.BR grodvi (1), +.BR grotty (1), +.BR gxditview (1), +.BR groff_font (5), +.BR groff_out (5), +.BR groff_ms (7), +.BR groff_me (7), +.BR groff_char (7) diff --git a/gnu/usr.bin/groff/groff/groff.cc b/gnu/usr.bin/groff/groff/groff.cc new file mode 100644 index 0000000000..0780913157 --- /dev/null +++ b/gnu/usr.bin/groff/groff/groff.cc @@ -0,0 +1,590 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +// A front end for groff. + +#include +#include +#include +#include +#include + +#include "lib.h" +#include "assert.h" +#include "errarg.h" +#include "error.h" +#include "stringclass.h" +#include "cset.h" +#include "font.h" +#include "device.h" +#include "pipeline.h" +#include "defs.h" + +#define BSHELL "/bin/sh" +#define GXDITVIEW "gxditview" + +// troff will be passed an argument of -rXREG=1 if the -X option is +// specified +#define XREG ".X" + +#ifndef STDLIB_H_DECLARES_PUTENV +extern "C" { + int putenv(const char *); +} +#endif /* not STDLIB_H_DECLARES_PUTENV */ + +const char *strsignal(int); + +const int SOELIM_INDEX = 0; +const int REFER_INDEX = SOELIM_INDEX + 1; +const int PIC_INDEX = REFER_INDEX + 1; +const int TBL_INDEX = PIC_INDEX + 1; +const int EQN_INDEX = TBL_INDEX + 1; +const int TROFF_INDEX = EQN_INDEX + 1; +const int POST_INDEX = TROFF_INDEX + 1; +const int SPOOL_INDEX = POST_INDEX + 1; + +const int NCOMMANDS = SPOOL_INDEX + 1; + +class possible_command { + char *name; + string args; + char **argv; + + void build_argv(); +public: + possible_command(); + ~possible_command(); + void set_name(const char *); + void set_name(const char *, const char *); + const char *get_name(); + void append_arg(const char *, const char * = 0); + void clear_args(); + char **get_argv(); + void print(int is_last, FILE *fp); +}; + +int lflag = 0; +char *spooler = 0; +char *driver = 0; + +possible_command commands[NCOMMANDS]; + +int run_commands(); +void print_commands(); +void append_arg_to_string(const char *arg, string &str); +void handle_unknown_desc_command(const char *command, const char *arg, + const char *filename, int lineno); +const char *basename(const char *); + +void usage(); +void help(); + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + assert(NCOMMANDS <= MAX_COMMANDS); + string Pargs, Largs, Fargs; + int Vflag = 0; + int zflag = 0; + int iflag = 0; + int Xflag = 0; + int opt; + const char *command_prefix = getenv("GROFF_COMMAND_PREFIX"); + if (!command_prefix) + command_prefix = PROG_PREFIX; + commands[TROFF_INDEX].set_name(command_prefix, "troff"); + while ((opt = getopt(argc, argv, + "itpeRszavVhblCENXZF:m:T:f:w:W:M:d:r:n:o:P:L:")) + != EOF) { + char buf[3]; + buf[0] = '-'; + buf[1] = opt; + buf[2] = '\0'; + switch (opt) { + case 'i': + iflag = 1; + break; + case 't': + commands[TBL_INDEX].set_name(command_prefix, "tbl"); + break; + case 'p': + commands[PIC_INDEX].set_name(command_prefix, "pic"); + break; + case 'e': + commands[EQN_INDEX].set_name(command_prefix, "eqn"); + break; + case 's': + commands[SOELIM_INDEX].set_name(command_prefix, "soelim"); + break; + case 'R': + commands[REFER_INDEX].set_name(command_prefix, "refer"); + break; + case 'z': + case 'a': + commands[TROFF_INDEX].append_arg(buf); + // fall through + case 'Z': + zflag++; + break; + case 'l': + lflag++; + break; + case 'V': + Vflag++; + break; + case 'v': + case 'C': + commands[SOELIM_INDEX].append_arg(buf); + commands[PIC_INDEX].append_arg(buf); + commands[TBL_INDEX].append_arg(buf); + commands[EQN_INDEX].append_arg(buf); + commands[TROFF_INDEX].append_arg(buf); + break; + case 'N': + commands[EQN_INDEX].append_arg(buf); + break; + case 'h': + help(); + break; + case 'E': + case 'b': + commands[TROFF_INDEX].append_arg(buf); + break; + case 'T': + if (strcmp(optarg, "Xps") == 0) { + warning("-TXps option is obsolete: use -X -Tps instead"); + device = "ps"; + Xflag++; + } + else + device = optarg; + break; + case 'F': + font::command_line_font_dir(optarg); + if (Fargs.length() > 0) { + Fargs += ':'; + Fargs += optarg; + } + else + Fargs = optarg; + break; + case 'f': + case 'o': + case 'm': + case 'r': + case 'd': + case 'n': + case 'w': + case 'W': + commands[TROFF_INDEX].append_arg(buf, optarg); + break; + case 'M': + commands[EQN_INDEX].append_arg(buf, optarg); + commands[TROFF_INDEX].append_arg(buf, optarg); + break; + case 'P': + Pargs += optarg; + Pargs += '\0'; + break; + case 'L': + append_arg_to_string(optarg, Largs); + break; + case 'X': + Xflag++; + break; + case '?': + usage(); + break; + default: + assert(0); + break; + } + } + font::set_unknown_desc_command_handler(handle_unknown_desc_command); + if (!font::load_desc()) + fatal("invalid device `%1'", device); + if (!driver) + fatal("no `postpro' command in DESC file for device `%1'", device); + const char *real_driver = 0; + if (Xflag) { + real_driver = driver; + driver = GXDITVIEW; + commands[TROFF_INDEX].append_arg("-r" XREG "=", "1"); + } + if (driver) + commands[POST_INDEX].set_name(driver); + int gxditview_flag = driver && strcmp(basename(driver), GXDITVIEW) == 0; + if (gxditview_flag && argc - optind == 1) { + commands[POST_INDEX].append_arg("-title"); + commands[POST_INDEX].append_arg(argv[optind]); + commands[POST_INDEX].append_arg("-xrm"); + commands[POST_INDEX].append_arg("*iconName:", argv[optind]); + string filename_string("|"); + append_arg_to_string(argv[0], filename_string); + append_arg_to_string("-Z", filename_string); + for (int i = 1; i < argc; i++) + append_arg_to_string(argv[i], filename_string); + filename_string += '\0'; + commands[POST_INDEX].append_arg("-filename"); + commands[POST_INDEX].append_arg(filename_string.contents()); + } + if (gxditview_flag && Xflag) { + string print_string(real_driver); + if (spooler) { + print_string += " | "; + print_string += spooler; + print_string += Largs; + } + print_string += '\0'; + commands[POST_INDEX].append_arg("-printCommand"); + commands[POST_INDEX].append_arg(print_string.contents()); + } + const char *p = Pargs.contents(); + const char *end = p + Pargs.length(); + while (p < end) { + commands[POST_INDEX].append_arg(p); + p = strchr(p, '\0') + 1; + } + if (gxditview_flag) + commands[POST_INDEX].append_arg("-"); + if (lflag && !Xflag && spooler) { + commands[SPOOL_INDEX].set_name(BSHELL); + commands[SPOOL_INDEX].append_arg("-c"); + Largs += '\0'; + Largs = spooler + Largs; + commands[SPOOL_INDEX].append_arg(Largs.contents()); + } + if (zflag) { + commands[POST_INDEX].set_name(0); + commands[SPOOL_INDEX].set_name(0); + } + commands[TROFF_INDEX].append_arg("-T", device); + commands[EQN_INDEX].append_arg("-T", device); + + for (int first_index = 0; first_index < TROFF_INDEX; first_index++) + if (commands[first_index].get_name() != 0) + break; + if (optind < argc) { + if (argv[optind][0] == '-' && argv[optind][1] != '\0') + commands[first_index].append_arg("--"); + for (int i = optind; i < argc; i++) + commands[first_index].append_arg(argv[i]); + if (iflag) + commands[first_index].append_arg("-"); + } + if (Fargs.length() > 0) { + string e = "GROFF_FONT_PATH"; + e += '='; + e += Fargs; + char *fontpath = getenv("GROFF_FONT_PATH"); + if (fontpath && *fontpath) { + e += ':'; + e += fontpath; + } + e += '\0'; + if (putenv(strsave(e.contents()))) + fatal("putenv failed"); + } + if (Vflag) { + print_commands(); + exit(0); + } + exit(run_commands()); +} + +const char *basename(const char *s) +{ + if (!s) + return 0; + const char *p = strrchr(s, '/'); + return p ? p + 1 : s; +} + +void handle_unknown_desc_command(const char *command, const char *arg, + const char *filename, int lineno) +{ + if (strcmp(command, "print") == 0) { + if (arg == 0) + error_with_file_and_line(filename, lineno, + "`print' command requires an argument"); + else + spooler = strsave(arg); + } + if (strcmp(command, "postpro") == 0) { + if (arg == 0) + error_with_file_and_line(filename, lineno, + "`postpro' command requires an argument"); + else { + for (const char *p = arg; *p; p++) + if (csspace(*p)) { + error_with_file_and_line(filename, lineno, + "invalid `postpro' argument `%1'" + ": program name required", arg); + return; + } + driver = strsave(arg); + } + } +} + +void print_commands() +{ + for (int last = SPOOL_INDEX; last >= 0; last--) + if (commands[last].get_name() != 0) + break; + for (int i = 0; i <= last; i++) + if (commands[i].get_name() != 0) + commands[i].print(i == last, stdout); +} + +// Run the commands. Return the code with which to exit. + +int run_commands() +{ + char **v[NCOMMANDS]; + int j = 0; + for (int i = 0; i < NCOMMANDS; i++) + if (commands[i].get_name() != 0) + v[j++] = commands[i].get_argv(); + return run_pipeline(j, v); +} + +possible_command::possible_command() +: name(0), argv(0) +{ +} + +possible_command::~possible_command() +{ + a_delete name; + a_delete argv; +} + +void possible_command::set_name(const char *s) +{ + a_delete name; + name = strsave(s); +} + +void possible_command::set_name(const char *s1, const char *s2) +{ + a_delete name; + name = new char[strlen(s1) + strlen(s2) + 1]; + strcpy(name, s1); + strcat(name, s2); +} + +const char *possible_command::get_name() +{ + return name; +} + +void possible_command::clear_args() +{ + args.clear(); +} + +void possible_command::append_arg(const char *s, const char *t) +{ + args += s; + if (t) + args += t; + args += '\0'; +} + +void possible_command::build_argv() +{ + if (argv) + return; + // Count the number of arguments. + int len = args.length(); + int argc = 1; + char *p = 0; + if (len > 0) { + p = &args[0]; + for (int i = 0; i < len; i++) + if (p[i] == '\0') + argc++; + } + // Build an argument vector. + argv = new char *[argc + 1]; + argv[0] = name; + for (int i = 1; i < argc; i++) { + argv[i] = p; + p = strchr(p, '\0') + 1; + } + argv[argc] = 0; +} + +void possible_command::print(int is_last, FILE *fp) +{ + build_argv(); + if (argv[0] != 0 && strcmp(argv[0], BSHELL) == 0 + && argv[1] != 0 && strcmp(argv[1], "-c") == 0 + && argv[2] != 0 && argv[3] == 0) + fputs(argv[2], fp); + else { + fputs(argv[0], fp); + string str; + for (int i = 1; argv[i] != 0; i++) { + str.clear(); + append_arg_to_string(argv[i], str); + put_string(str, fp); + } + } + if (is_last) + putc('\n', fp); + else + fputs(" | ", fp); +} + +void append_arg_to_string(const char *arg, string &str) +{ + str += ' '; + int needs_quoting = 0; + int contains_single_quote = 0; + for (const char *p = arg; *p != '\0'; p++) + switch (*p) { + case ';': + case '&': + case '(': + case ')': + case '|': + case '^': + case '<': + case '>': + case '\n': + case ' ': + case '\t': + case '\\': + case '"': + case '$': + case '?': + case '*': + needs_quoting = 1; + break; + case '\'': + contains_single_quote = 1; + break; + } + if (contains_single_quote || arg[0] == '\0') { + str += '"'; + for (p = arg; *p != '\0'; p++) + switch (*p) { + case '"': + case '\\': + case '$': + str += '\\'; + // fall through + default: + str += *p; + break; + } + str += '"'; + } + else if (needs_quoting) { + str += '\''; + str += arg; + str += '\''; + } + else + str += arg; +} + +char **possible_command::get_argv() +{ + build_argv(); + return argv; +} + +void synopsis() +{ + fprintf(stderr, +"usage: %s [-abehilpstvzCENRVXZ] [-Fdir] [-mname] [-Tdev] [-ffam] [-wname]\n" +" [-Wname] [ -Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg] [-Larg]\n" +" [files...]\n", + program_name); +} + +void help() +{ + synopsis(); + fputs("\n" +"-h\tprint this message\n" +"-t\tpreprocess with tbl\n" +"-p\tpreprocess with pic\n" +"-e\tpreprocess with eqn\n" +"-s\tpreprocess with soelim\n" +"-R\tpreprocess with refer\n" +"-Tdev\tuse device dev\n" +"-X\tuse X11 previewer rather than usual postprocessor\n" +"-mname\tread macros tmac.name\n" +"-dcs\tdefine a string c as s\n" +"-rcn\tdefine a number register c as n\n" +"-nnum\tnumber first page n\n" +"-olist\toutput only pages in list\n" +"-ffam\tuse fam as the default font family\n" +"-Fdir\tsearch directory dir for device directories\n" +"-Mdir\tsearch dir for macro files\n" +"-v\tprint version number\n" +"-z\tsuppress formatted output\n" +"-Z\tdon't postprocess\n" +"-a\tproduce ASCII description of output\n" +"-i\tread standard input after named input files\n" +"-wname\tenable warning name\n" +"-Wname\tinhibit warning name\n" +"-E\tinhibit all errors\n" +"-b\tprint backtraces with errors or warnings\n" +"-l\tspool the output\n" +"-C\tenable compatibility mode\n" +"-V\tprint commands on stdout instead of running them\n" +"-Parg\tpass arg to the postprocessor\n" +"-Larg\tpass arg to the spooler\n" +"-N\tdon't allow newlines within eqn delimiters\n" +"\n", + stderr); + exit(0); +} + +void usage() +{ + synopsis(); + fprintf(stderr, "%s -h gives more help\n", program_name); + exit(1); +} + +extern "C" { + +void c_error(const char *format, const char *arg1, const char *arg2, + const char *arg3) +{ + error(format, arg1, arg2, arg3); +} + +void c_fatal(const char *format, const char *arg1, const char *arg2, + const char *arg3) +{ + fatal(format, arg1, arg2, arg3); +} + +} diff --git a/gnu/usr.bin/groff/groff/pipeline.c b/gnu/usr.bin/groff/groff/pipeline.c new file mode 100644 index 0000000000..0172a1745a --- /dev/null +++ b/gnu/usr.bin/groff/groff/pipeline.c @@ -0,0 +1,240 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* +Compile options are: + +-DWCOREFLAG=0200 (or whatever) +-DHAVE_VFORK_H +-Dvfork=fork +-DHAVE_SYS_SIGLIST +-DHAVE_UNISTD_H +*/ + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_VFORK_H +#include +#endif + +#ifndef errno +extern int errno; +#endif + +extern char *strerror(); + +#ifdef _POSIX_VERSION + +#include + +#define PID_T pid_t + +#else /* not _POSIX_VERSION */ + +/* traditional Unix */ + +#define WIFEXITED(s) (((s) & 0377) == 0) +#define WIFSTOPPED(s) (((s) & 0377) == 0177) +#define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177)) +#define WEXITSTATUS(s) (((s) >> 8) & 0377) +#define WTERMSIG(s) ((s) & 0177) +#define WSTOPSIG(s) (((s) >> 8) & 0377) + +#ifndef WCOREFLAG +#define WCOREFLAG 0200 +#endif + +#define PID_T int + +#endif /* not _POSIX_VERSION */ + +/* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */ +#ifndef WCOREFLAG +#ifdef WCOREFLG +#define WCOREFLAG WCOREFLG +#endif /* WCOREFLG */ +#endif /* not WCOREFLAG */ + +#ifndef WCOREDUMP +#ifdef WCOREFLAG +#define WCOREDUMP(s) ((s) & WCOREFLAG) +#else /* not WCOREFLAG */ +#define WCOREDUMP(s) (0) +#endif /* WCOREFLAG */ +#endif /* not WCOREDUMP */ + +#include "pipeline.h" + +#ifdef __STDC__ +#define P(parms) parms +#else +#define P(parms) () +#endif + +#define error c_error +extern void error P((char *, char *, char *, char *)); + +static void sys_fatal P((char *)); +static char *strsignal P((int)); +static char *itoa P((int)); + +int run_pipeline(ncommands, commands) + int ncommands; + char ***commands; +{ + int i; + int last_input = 0; + PID_T pids[MAX_COMMANDS]; + int ret = 0; + int proc_count = ncommands; + + for (i = 0; i < ncommands; i++) { + int pdes[2]; + PID_T pid; + if (i != ncommands - 1) { + if (pipe(pdes) < 0) + sys_fatal("pipe"); + } + pid = vfork(); + if (pid < 0) + sys_fatal("fork"); + if (pid == 0) { + /* child */ + if (last_input != 0) { + if (close(0) < 0) + sys_fatal("close"); + if (dup(last_input) < 0) + sys_fatal("dup"); + if (close(last_input) < 0) + sys_fatal("close"); + } + if (i != ncommands - 1) { + if (close(1) < 0) + sys_fatal("close"); + if (dup(pdes[1]) < 0) + sys_fatal("dup"); + if (close(pdes[1]) < 0) + sys_fatal("close"); + if (close(pdes[0])) + sys_fatal("close"); + } + execvp(commands[i][0], commands[i]); + error("couldn't exec %1: %2", commands[i][0], + strerror(errno), (char *)0); + fflush(stderr); /* just in case error() doesn't */ + _exit(EXEC_FAILED_EXIT_STATUS); + } + /* in the parent */ + if (last_input != 0) { + if (close(last_input) < 0) + sys_fatal("close"); + } + if (i != ncommands - 1) { + if (close(pdes[1]) < 0) + sys_fatal("close"); + last_input = pdes[0]; + } + pids[i] = pid; + } + while (proc_count > 0) { + int status; + PID_T pid = wait(&status); + if (pid < 0) + sys_fatal("wait"); + for (i = 0; i < ncommands; i++) + if (pids[i] == pid) { + pids[i] = -1; + --proc_count; + if (WIFSIGNALED(status)) { + int sig = WTERMSIG(status); +#ifdef SIGPIPE + if (sig == SIGPIPE) { + if (i == ncommands - 1) { + + /* This works around a problem that occurred when using the + rerasterize action in gxditview. What seemed to be + happening (on SunOS 4.1.1) was that pclose() closed the + pipe and waited for groff, gtroff got a SIGPIPE, but + gpic blocked writing to gtroff, and so groff blocked + waiting for gpic and gxditview blocked waiting for + groff. I don't understand why gpic wasn't getting a + SIGPIPE. */ + int j; + for (j = 0; j < ncommands; j++) + if (pids[j] > 0) + (void)kill(pids[j], SIGPIPE); + } + } + else +#endif /* SIGPIPE */ + { + error("%1: %2%3", + commands[i][0], + strsignal(sig), + WCOREDUMP(status) ? " (core dumped)" : ""); + ret |= 2; + } + } + else if (WIFEXITED(status)) { + int exit_status = WEXITSTATUS(status); + if (exit_status == EXEC_FAILED_EXIT_STATUS) + ret |= 4; + else if (exit_status != 0) + ret |= 1; + } + else + error("unexpected status %1", + itoa(status), (char *)0, (char *)0); + break; + } + } + return ret; +} + +static void sys_fatal(s) + char *s; +{ + c_fatal("%1: %2", s, strerror(errno), (char *)0); +} + +static char *itoa(n) + int n; +{ + static char buf[12]; + sprintf(buf, "%d", n); + return buf; +} + +static char *strsignal(n) + int n; +{ + static char buf[sizeof("Signal ") + 1 + sizeof(int)*3]; +#ifdef HAVE_SYS_SIGLIST + extern char *sys_siglist[]; + if (n >= 0 && n < NSIG && sys_siglist[n] != 0) + return sys_siglist[n]; +#endif /* HAVE_SYS_SIGLIST */ + sprintf(buf, "Signal %d", n); + return buf; +} diff --git a/gnu/usr.bin/groff/groff/pipeline.h b/gnu/usr.bin/groff/groff/pipeline.h new file mode 100644 index 0000000000..032b0bba68 --- /dev/null +++ b/gnu/usr.bin/groff/groff/pipeline.h @@ -0,0 +1,30 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef __cplusplus +extern "C" { + int run_pipeline(int, char ***); +} +#endif + +/* run_pipeline can handle at most this many commands */ +#define MAX_COMMANDS 10 + +/* Children exit with this status if execvp fails. */ +#define EXEC_FAILED_EXIT_STATUS 0xff diff --git a/gnu/usr.bin/groff/grog/Makefile b/gnu/usr.bin/groff/grog/Makefile new file mode 100644 index 0000000000..4c134f2254 --- /dev/null +++ b/gnu/usr.bin/groff/grog/Makefile @@ -0,0 +1,8 @@ +MAN1= grog.0 + +afterinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + $(.CURDIR)/grog.pl $(DESTDIR)$(BINDIR)/grog + +.include +.include <../../../usr.bin/Makefile.inc> diff --git a/gnu/usr.bin/groff/grog/grog.1 b/gnu/usr.bin/groff/grog/grog.1 new file mode 100644 index 0000000000..57f1f85d26 --- /dev/null +++ b/gnu/usr.bin/groff/grog/grog.1 @@ -0,0 +1,54 @@ +.TH GROG 1 "6 August 1992" "Groff Version 1.08" +.SH NAME +grog \- guess options for groff command +.SH SYNOPSIS +.B grog +[ +.BI \- option +\|.\|.\|. +] +[ +.IR files \|.\|.\|. +] +.SH DESCRIPTION +.B grog +reads +.I files +and guesses which of the +.BR groff (1) +options +.BR \-e , +.BR \-man , +.BR \-me , +.BR \-mm , +.BR \-ms , +.BR \-p , +.BR \-s , +and +.BR \-t +are required for printing +.IR files , +and prints the groff command including those options on the standard output. +A filename of +.B \- +is taken to refer to the standard input. +If no files are specified the standard input will be read. +Any specified options will be included in the printed command. +No space is allowed between options and their arguments. +For example, +.IP +.B `grog \-Tdvi paper.ms` +.LP +will guess the approriate command to print +.B paper.ms +and then run it after adding the +.B \-Tdvi +option. +.SH "SEE ALSO" +.BR doctype (1), +.BR groff (1), +.BR troff (1), +.BR tbl (1), +.BR pic (1), +.BR eqn (1), +.BR soelim (1) diff --git a/gnu/usr.bin/groff/grog/grog.pl b/gnu/usr.bin/groff/grog/grog.pl new file mode 100644 index 0000000000..b131da64b2 --- /dev/null +++ b/gnu/usr.bin/groff/grog/grog.pl @@ -0,0 +1,149 @@ +#!/usr/bin/perl +# grog -- guess options for groff command +# Inspired by doctype script in Kernighan & Pike, Unix Programming +# Environment, pp 306-8. + +$prog = $0; +$prog =~ s@.*/@@; + +push(@command, "groff"); + +while ($ARGV[0] =~ /^-./) { + $arg = shift(@ARGV); + last if $arg eq "--"; + push(@command, $arg); +} + +if (@ARGV) { + foreach $arg (@ARGV) { + &process($arg, 0); + } +} +else { + &process("-", 0); +} + +sub process { + local($filename, $level) = @_; + local(*FILE); + + if (!open(FILE, $filename eq "-" ? $filename : "< $filename")) { + print STDERR "$prog: can't open \`$filename': $!\n"; + exit 1 unless $level; + return; + } + while () { + if (/^\.TS/) { + $_ = ; + if (!/^\./) { + $tbl++; + $soelim++ if $level; + } + } + elsif (/^\.EQ/) { + $_ = ; + if (!/^\./ || /^\.[0-9]/) { + $eqn++; + $soelim++ if $level; + } + } + elsif (/^\.PS([ 0-9.<].*)?$/) { + if (/^\.PS\s*<\s*(\S+)/) { + $pic++; + $soelim++ if $level; + &process($1, $level); + } + else { + $_ = ; + if (!/^\./ || /^\.ps/) { + $pic++; + $soelim++ if $level; + } + } + } + elsif (/^\.R1/ || /^\.\[/) { + $refer++; + $soelim++ if $level; + } + elsif (/^\.[PLI]P/) { + $PP++; + } + elsif (/^\.P$/) { + $P++; + } + elsif (/^\.(PH|SA)/) { + $mm++; + } + elsif (/^\.TH/) { + $TH++; + } + elsif (/^\.SH/) { + $SH++; + } + elsif (/^\.([pnil]p|sh)/) { + $me++; + } + elsif (/^\.Dd/) { + $mdoc++; + } + elsif (/^\.(Tp|Dp|De|Cx|Cl)/) { + $mdoc_old = 1; + } + # In the old version of -mdoc `Oo' is a toggle, in the new it's + # closed by `Oc'. + elsif (/^\.Oo/) { + $Oo++; + } + elsif (/^\.Oc/) { + $Oo--; + } + if (/^\.so/) { + chop; + s/^.so *//; + s/\\\".*//; + s/ .*$//; + &process($_, $level + 1) unless /\\/ || $_ eq ""; + } + } + close(FILE); +} + +if ($pic || $tbl || $eqn || $refer) { + $s = "-"; + $s .= "s" if $soelim; + $s .= "R" if $refer; + $s .= "p" if $pic; + $s .= "t" if $tbl; + $s .= "e" if $eqn; + push(@command, $s); +} + +if ($me > 0) { + push(@command, "-me"); +} +elsif ($SH > 0 && $TH > 0) { + push(@command, "-man"); +} +elsif ($PP > 0) { + push(@command, "-ms"); +} +elsif ($P > 0 || $mm > 0) { + push(@command, "-mm"); +} +elsif ($mdoc > 0) { + push(@command, ($mdoc_old || $Oo > 0) ? "-mdoc.old" : "-mdoc"); +} + +push(@command, "--") if @ARGV && $ARGV[0] =~ /^-./; + +push(@command, @ARGV); + +# We could implement an option to execute the command here. + +foreach (@command) { + next unless /[\$\\\"\';&()|<> \t\n]/; + s/\'/\'\\\'\'/; + $_ = "'" . $_ . "'"; +} + +print join(' ', @command), "\n"; diff --git a/gnu/usr.bin/groff/grog/grog.sh b/gnu/usr.bin/groff/grog/grog.sh new file mode 100644 index 0000000000..755c891ce6 --- /dev/null +++ b/gnu/usr.bin/groff/grog/grog.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# grog -- guess options for groff command +# Like doctype in Kernighan & Pike, Unix Programming Environment, pp 306-8. + +soelim=gsoelim + +opts= + +for arg +do + case "$arg" in + --) + shift; break;; + -) + break;; + -*) + opts="$opts $arg"; shift;; + *) + break;; + esac +done + +egrep -h '^\.(P|[LI]P|[pnil]p|sh|Dd|Tp|Dp|De|Cx|Cl|Oo|Oc|TS|EQ|TH|SH|so|\[|R1|PH|SA)' $* \ +| sed -e '/^\.so/s/^.*$/.SO_START\ +&\ +.SO_END/' \ +| $soelim \ +| egrep '^\.(P|[LI]P|[pnil]p|sh|Dd|Tp|Dp|De|Cx|Cl|Oo|Oc|TS|EQ|TH|SH|\[|R1|PH|SA|SO_START|SO_END)' \ +| awk ' +/^\.SO_START$/ { so = 1 } +/^\.SO_END$/ { so = 0 } +/^\.TS/ { tbl++; if (so > 0) soelim++ } +/^\.PS([ 0-9.<].*)?$/ { pic++; if (so > 0) soelim++ } +/^\.EQ/ { eqn++; if (so > 0) soelim++ } +/^\.(R1|\[)/ { refer++; if (so > 0) soelim++ } +/^\.TH/ { TH++ } +/^\.[PLI]P/ { PP++ } +/^\.P$/ { P++ } +/^\.SH/ { SH++ } +/^\.(PH|SA)/ { mm++ } +/^\.([pnil]p|sh)/ { me++ } +/^\.Dd/ { mdoc++ } +/^\.(Tp|Dp|De|Cx|Cl)/ { mdoc_old++ } +/^\.Oo/ { Oo++ } +/^\.Oc/ { Oo-- } + +END { + if (files ~ /^-/) + files = "-- " files + printf "groff" + if (pic > 0 || tbl > 0 || eqn > 0 || refer > 0) { + printf " -" + if (soelim > 0) printf "s" + if (refer > 0) printf "R" + if (pic > 0) printf "p" + if (tbl > 0) printf "t" + if (eqn > 0) printf "e" + } + if (me > 0) + printf " -me" + else if (SH > 0 && TH > 0) + printf " -man" + else if (PP > 0) + printf " -ms" + else if (P > 0 || mm > 0) + printf " -mm" + else if (mdoc > 0) { + if (mdoc_old > 0 || Oo > 0) + printf " -mdoc.old" + else + printf " -mdoc" + } + if (opts != "") + printf "%s", opts + if (files != "") + printf " %s", files + print +}' "opts=$opts" "files=$*" - diff --git a/gnu/usr.bin/groff/grops/Makefile b/gnu/usr.bin/groff/grops/Makefile new file mode 100644 index 0000000000..4d56054e31 --- /dev/null +++ b/gnu/usr.bin/groff/grops/Makefile @@ -0,0 +1,12 @@ +# Makefile for grops + +PROG= grops +SRCS= ps.cc psrm.cc +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBDRIVER) $(LIBGROFF) -lm +DPADD+= $(LIBDRIVER) $(LIBGROFF) $(LIBMATH) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/grops/Makefile.dep b/gnu/usr.bin/groff/grops/Makefile.dep new file mode 100644 index 0000000000..2320a9ecd1 --- /dev/null +++ b/gnu/usr.bin/groff/grops/Makefile.dep @@ -0,0 +1,6 @@ +ps.o : ps.cc ../include/driver.h ../include/errarg.h ../include/error.h \ + ../include/font.h ../include/printer.h ../include/lib.h \ + ../include/stringclass.h ../include/cset.h ps.h +psrm.o : psrm.cc ../include/driver.h ../include/errarg.h ../include/error.h \ + ../include/font.h ../include/printer.h ../include/lib.h \ + ../include/stringclass.h ../include/cset.h ps.h diff --git a/gnu/usr.bin/groff/grops/TODO b/gnu/usr.bin/groff/grops/TODO new file mode 100644 index 0000000000..4d1e5fd618 --- /dev/null +++ b/gnu/usr.bin/groff/grops/TODO @@ -0,0 +1,25 @@ +Read PFB files directly. + +Generate %%DocumentMedia comment. + +For efficiency it might be better to have the printer interface have +support for the t and u commands. + +Angles in arc command: don't generate more digits after the decimal +point than are necessary. + +Possibly generate BoundingBox comment. + +Per font composite character mechanism (sufficient for fractions). + +Consider whether we ought to do rounding of graphical objects other +than lines. What's the point? + +Error messages should refer to output page number. + +Search for downloadable fonts using their PostScript names if not +found in download file. + +Separate path for searching for downloadable font files. + +Clip to the BoundingBox when importing documents. diff --git a/gnu/usr.bin/groff/grops/grops.1 b/gnu/usr.bin/groff/grops/grops.1 new file mode 100644 index 0000000000..2a584d6d68 --- /dev/null +++ b/gnu/usr.bin/groff/grops/grops.1 @@ -0,0 +1,797 @@ +.\" -*- nroff -*- +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH GROPS 1 "5 April 1993" "Groff Version 1.08" +.SH NAME +grops \- PostScript driver for groff +.SH SYNOPSIS +.B grops +[ +.B \-glv +] [ +.BI \-b n +] [ +.BI \-c n +] [ +.BI \-w n +] [ +.BI \-F dir +] [ +.IR files \|.\|.\|. +] +.SH DESCRIPTION +.B grops +translates the output of GNU +.B troff +to PostScript. +Normally +.B grops +should be invoked by using the groff command +with a +.B \-Tps +option. +.if 'ps'ps' (Actually, this is the default for groff.) +If no files are given, +.B grops +will read the standard input. +A filename of +.B \- +will also cause +.B grops +to read the standard input. +PostScript output is written to the standard output. +When +.B grops +is run by +.B groff +options can be passed to +.B grops +using the +.B groff +.B \-P +option. +.SH OPTIONS +.TP +.BI \-b n +Workaround broken spoolers and previewers. +Normally +.B grops +produces output that conforms +the Document Structuring Conventions version 3.0. +Unfortunately some spoolers and previewers can't handle such output. +The value of +.I n +controls what +.B grops +does to its output acceptable to such programs. +A value of 0 will cause grops not to employ any workarounds. +Add 1 if no +.B %%BeginDocumentSetup +and +.B %%EndDocumentSetup +comments should be generated; +this is needed for early versions of TranScript that get confused by +anything between the +.B %%EndProlog +comment and the first +.B %%Page +comment. +Add 2 if lines in included files beginning with +.B %! +should be stripped out; this is needed for Sun's pageview previewer. +Add 4 if +.BR %%Page , +.BR %%Trailer +and +.B %%EndProlog +comments should be +stripped out of included files; this is needed for spoolers that +don't understand the +.B %%BeginDocument +and +.B %%EndDocument +comments. +Add 8 if the first line of the PostScript output should be +.B %!PS-Adobe-2.0 +rather than +.BR %!PS-Adobe-3.0 ; +this is needed when using Sun's Newsprint with a printer that requires +page reversal. +The default value can be specified by a +.RS +.IP +.BI broken\ n +.LP +command in the DESC file. +Otherwise the default value is 0. +.RE +.TP +.BI \-c n +Print +.I n +copies of each page. +.TP +.BI \-g +Guess the page length. +This generates PostScript code that guesses the page length. +The guess will be correct only if the imageable area is vertically +centered on the page. +This option allows you to generate documents that can be printed +both on letter (8.5\(mu11) paper and on A4 paper without change. +.TP +.BI \-l +Print the document in landscape format. +.TP +.BI \-F dir +Search the directory +.IB dir /dev name +for font and device description files; +.I name +is the name of the device, usually +.BR ps . +.TP +.BI \-w n +Lines should be drawn using a thickness of +.I n +thousandths of an em. +.TP +.B \-v +Print the version number. +.SH USAGE +There are styles called +.BR R , +.BR I , +.BR B , +and +.B BI +mounted at font positions 1 to 4. +The fonts are grouped into families +.BR A , +.BR BM , +.BR C , +.BR H , +.BR HN , +.BR N , +.B P +and +.B T +having members in each of these styles: +.de FT +.if '\\*(.T'ps' .ft \\$1 +.. +.TP +.B AR +.FT AR +AvantGarde-Book +.FT +.TP +.B AI +.FT AI +AvantGarde-BookOblique +.FT +.TP +.B AB +.FT AB +AvantGarde-Demi +.FT +.TP +.B ABI +.FT ABI +AvantGarde-DemiOblique +.FT +.TP +.B BMR +.FT BMR +Bookman-Light +.FT +.TP +.B BMI +.FT BMI +Bookman-LightItalic +.FT +.TP +.B BMB +.FT BMB +Bookman-Demi +.FT +.TP +.B BMBI +.FT BMBI +Bookman-DemiItalic +.FT +.TP +.B CR +.FT CR +Courier +.FT +.TP +.B CI +.FT CI +Courier-Oblique +.FT +.TP +.B CB +.FT CB +Courier-Bold +.FT +.TP +.B CBI +.FT CBI +Courier-BoldOblique +.FT +.TP +.B HR +.FT HR +Helvetica +.FT +.TP +.B HI +.FT HI +Helvetica-Oblique +.FT +.TP +.B HB +.FT HB +Helvetica-Bold +.FT +.TP +.B HBI +.FT HBI +Helvetica-BoldOblique +.FT +.TP +.B HNR +.FT HNR +Helvetica-Narrow +.FT +.TP +.B HNI +.FT HNI +Helvetica-Narrow-Oblique +.FT +.TP +.B HNB +.FT HNB +Helvetica-Narrow-Bold +.FT +.TP +.B HNBI +.FT HNBI +Helvetica-Narrow-BoldOblique +.FT +.TP +.B NR +.FT NR +NewCenturySchlbk-Roman +.FT +.TP +.B NI +.FT NI +NewCenturySchlbk-Italic +.FT +.TP +.B NB +.FT NB +NewCenturySchlbk-Bold +.FT +.TP +.B NBI +.FT NBI +NewCenturySchlbk-BoldItalic +.FT +.TP +.B PR +.FT PR +Palatino-Roman +.FT +.TP +.B PI +.FT PI +Palatino-Italic +.FT +.TP +.B PB +.FT PB +Palatino-Bold +.FT +.TP +.B PBI +.FT PBI +Palatino-BoldItalic +.FT +.TP +.B TR +.FT TR +Times-Roman +.FT +.TP +.B TI +.FT TI +Times-Italic +.FT +.TP +.B TB +.FT TB +Times-Bold +.FT +.TP +.B TBI +.FT TBI +Times-BoldItalic +.FT +.LP +There is also the following font which is not a member of a family: +.TP +.B ZCMI +.FT ZCMI +ZapfChancery-MediumItalic +.FT +.LP +There are also some special fonts called +.B SS +and +.BR S . +Zapf Dingbats is avilable as +.BR ZD +and a reversed version of ZapfDingbats (with symbols pointing in the opposite +direction) is available as +.BR ZDR ; +most characters in these fonts are unnamed and must be accessed using +.BR \eN . +.LP +.B grops +understands various X commands produced using the +.B \eX +escape sequence; +.B grops +will only interpret commands that begin with a +.B ps: +tag. +.TP +.BI \eX'ps:\ exec\ code ' +This executes the arbitrary PostScript commands in +.IR code . +The PostScript currentpoint will be set to the position of the +.B \eX +command before executing +.IR code . +The origin will be at the top left corner of the page, +and y coordinates will increase down the page. +A procedure +.B u +will be defined that converts groff units +to the coordinate system in effect. +For example, +.RS +.IP +.B +\&.nr x 1i +.br +.B +\eX'ps: exec \enx u 0 rlineto stroke' +.br +.RE +.IP +will draw a horizontal line one inch long. +.I code +may make changes to the graphics state, +but any changes will persist only to the +end of the page. +Any definitions will also persist only until the end of the page. +If you use the +.B \eY +escape sequence with an argument that names a macro, +.I code +can extend over multiple lines. +For example, +.RS +.IP +.nf +.ft B +\&.nr x 1i +\&.de y +\&ps: exec +\&\enx u 0 rlineto +\&stroke +\&.. +\&\eYy +.fi +.ft R +.LP +is another way to draw a horizontal line one inch long. +.RE +.TP +.BI \eX'ps:\ file\ name ' +This is the same as the +.B exec +command except that the PostScript code is read from file +.IR name . +.TP +.BI \eX'ps:\ def\ code ' +Place a PostScript definition contained in +.I code +in the prologue. +There should be at most one definition per +.B \eX +command. +Long definitions can be split over several +.B \eX +commands; +all the +.I code +arguments are simply joined together separated by newlines. +The definitions are placed in a dictionary which is automatically +pushed on the dictionary stack when an +.B exec +command is executed. +If you use the +.B \eY +escape sequence with an argument that names a macro, +.I code +can extend over multiple lines. +.TP +.BI \eX'ps:\ mdef\ n\ code ' +Like +.BR def , +except that +.I code +may contain up to +.I n +definitions. +.B grops +needs to know how many definitions +.I code +contains +so that it can create an apppropriately sized PostScript dictionary +to contain them. +.TP +.BI \eX'ps:\ import\ file\ llx\ lly\ urx\ ury\ width\ \fR[\fP\ height\ \fR]\fP ' +Import a PostScript graphic from +.IR file . +The arguments +.IR llx , +.IR lly , +.IR urx , +and +.I ury +give the bounding box of the graphic in the default PostScript +coordinate system; they should all be integers; +.I llx +and +.I lly +are the x and y coordinates of the lower left +corner of the graphic; +.I urx +and +.I ury +are the x and y coordinates of the upper right corner of the graphic; +.I width +and +.I height +are integers that give the desired width and height in groff +units of the graphic. +The graphic will be scaled so that it has this width and height +and translated so that the lower left corner of the graphic is +located at the position associated with +.B \eX +command. +If the height argument is omitted it will be scaled uniformly in the +x and y directions so that it has the specified width. +Note that the contents of the +.B \eX +command are not interpreted by +.BR troff ; +so vertical space for the graphic is not automatically added, +and the +.I width +and +.I height +arguments are not allowed to have attached scaling indicators. +If the PostScript file complies with the Adobe Document Structuring +Conventions and contains a +.B %%BoundingBox +comment, then the bounding box can be automatically +extracted from within groff by using the +.B sy +request to run the +.B psbb +command. +.RS +.LP +The +.B \-mps +macros (which are automatically loaded when +.B grops +is run by the groff command) include a +.B PSPIC +macro which allows a picture to be easily imported. +This has the format +.IP +.BI .PSPIC\ file\ \fR[ width\ \fR[ height \fR]] +.LP +.I file +is the name of the file containing the illustration; +.I width +and +.I height +give the desired width and height of the graphic. +The +.I width +and +.I height +arguments may have scaling indicators attached; +the default scaling indicator is +.BR i . +This macro will scale the graphic uniformly +in the x and y directions so that it is no more than +.I width +wide +and +.I height +high. +.RE +.TP +.B \eX'ps:\ invis' +.br +.ns +.TP +.B \eX'ps:\ endinvis' +No output will be generated for text and drawing commands +that are bracketed with these +.B \eX +commands. +These commands are intended for use when output from +.B troff +will be previewed before being processed with +.BR grops ; +if the previewer is unable to display certain characters +or other constructs, then other substitute characters or constructs +can be used for previewing by bracketing them with these +.B \eX +commands. +.RS +.LP +For example, +.B gxditview +is not able to display a proper +.B \e(em +character because the standard X11 fonts do not provide it; +this problem can be overcome by executing the following +request +.IP +.ft B +.nf +\&.char \e(em \eX'ps: invis'\e +\eZ'\ev'-.25m'\eh'.05m'\eD'l .9m 0'\eh'.05m''\e +\eX'ps: endinvis'\e(em +.ft +.fi +.LP +In this case, +.B gxditview +will be unable to display the +.B \e(em +character and will draw the line, +whereas +.B grops +will print the +.B \e(em +character +and ignore the line. +.RE +.LP +The input to +.B grops +must be in the format output by +.BR troff (1). +This is described in +.BR groff_out (1). +In addition the device and font description files for the device used +must meet certain requirements. +The device and font description files supplied for +.B ps +device meet all these requirements. +.BR afmtodit (1) +can be used to create font files from AFM files. +The resolution must be an integer multiple of 72 times the +.BR sizescale . +The +.B ps +device uses a resolution of 72000 and a sizescale of 1000. +The device description file should contain a command +.IP +.BI paperlength\ n +.LP +which says that output should be generated which is suitable for +printing on a page whose length is +.I n +machine units. +Each font description file must contain a command +.IP +.BI internalname\ psname +.LP +which says that the PostScript name of the font is +.IR psname . +It may also contain a command +.IP +.BI encoding\ enc_file +.LP +which says that +the PostScript font should be reencoded using the encoding described in +.IR enc_file ; +this file should consist of a sequence of lines of the form: +.IP +.I +pschar code +.LP +where +.I pschar +is the PostScript name of the character, +and +.I code +is its position in the encoding expressed as a decimal integer. +The code for each character given in the font file must correspond +to the code for the character in encoding file, or to the code in the default +encoding for the font if the PostScript font is not to be reencoded. +This code can be used with the +.B \eN +escape sequence in +.B troff +to select the character, +even if the character does not have a groff name. +Every character in the font file must exist in the PostScript font, and +the widths given in the font file must match the widths used +in the PostScript font. +.B grops +will assume that a character with a groff name of +.B space +is blank (makes no marks on the page); +it can make use of such a character to generate more efficient and +compact PostScript output. +.LP +.B grops +can automatically include the downloadable fonts necessary +to print the document. +Any downloadable fonts which should, when required, be included by +.B grops +must be listed in the file +.BR /usr/share/groff_font/devps/download ; +this should consist of lines of the form +.IP +.I +font filename +.LP +where +.I font +is the PostScript name of the font, +and +.I filename +is the name of the file containing the font; +lines beginning with +.B # +and blank lines are ignored; +fields may be separated by tabs or spaces; +.I filename +will be searched for using the same mechanism that is used +for groff font metric files. +The +.B download +file itself will also be searched for using this mechanism. +.LP +If the file containing a downloadable font or imported document +conforms to the Adobe Document Structuring Conventions, +then +.B grops +will interpret any comments in the files sufficiently to ensure that its +own output is conforming. +It will also supply any needed font resources that are listed in the +.B download +file +as well as any needed file resources. +It is also able to handle inter-resource dependencies. +For example, suppose that you have a downloadable font called Garamond, +and also a downloadable font called Garamond-Outline +which depends on Garamond +(typically it would be defined to copy Garamond's font dictionary, +and change the PaintType), +then it is necessary for Garamond to be appear before Garamond-Outline +in the PostScript document. +.B grops +will handle this automatically +provided that the downloadable font file for Garamond-Outline +indicates its dependence on Garamond by means of +the Document Structuring Conventions, +for example by beginning with the following lines +.IP +.B +%!PS-Adobe-3.0 Resource-Font +.br +.B +%%DocumentNeededResources: font Garamond +.br +.B +%%EndComments +.br +.B +%%IncludeResource: font Garamond +.LP +In this case both Garamond and Garamond-Outline would need to be listed +in the +.B download +file. +A downloadable font should not include its own name in a +.B %%DocumentSuppliedResources +comment. +.LP +.B grops +will not interpret +.B %%DocumentFonts +comments. +The +.BR %%DocumentNeededResources , +.BR %%DocumentSuppliedResources , +.BR %%IncludeResource , +.BR %%BeginResource +and +.BR %%EndResource +comments +(or possibly the old +.BR %%DocumentNeededFonts , +.BR %%DocumentSuppliedFonts , +.BR %%IncludeFont , +.BR %%BeginFont +and +.BR %%EndFont +comments) +should be used. +.SH FILES +.Tp \w'\fB/usr/share/groff_font/devps/download'u+2n +.B /usr/share/groff_font/devps/DESC +Device desciption file. +.TP +.BI /usr/share/groff_font/devps/ F +Font description file for font +.IR F . +.TP +.B /usr/share/groff_font/devps/download +List of downloadable fonts. +.TP +.B /usr/share/groff_font/devps/text.enc +Encoding used for text fonts. +.TP +.B /usr/share/tmac/tmac.ps +Macros for use with +.BR grops ; +automatically loaded by +.BR troffrc +.TP +.B /usr/share/tmac/tmac.pspic +Definition of +.B PSPIC +macro, +automatically loaded by +.BR tmac.ps . +.TP +.B /usr/share/tmac/tmac.psold +Macros to disable use of characters not present in older +PostScript printers; automatically loaded by +.BR tmac.ps . +.TP +.B /usr/share/tmac/tmac.psnew +Macros to undo the effect of +.BR tmac.psold . +.TP +.BI /tmp/grops XXXXXX +Temporary file. +.SH "SEE ALSO" +.BR afmtodit (1), +.BR groff (1), +.BR troff (1), +.BR psbb (1), +.BR groff_out (5), +.BR groff_font (5), +.BR groff_char (7) diff --git a/gnu/usr.bin/groff/grops/ps.cc b/gnu/usr.bin/groff/grops/ps.cc new file mode 100644 index 0000000000..1dd5d8c77f --- /dev/null +++ b/gnu/usr.bin/groff/grops/ps.cc @@ -0,0 +1,1507 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "driver.h" +#include "stringclass.h" +#include "cset.h" + +#include "ps.h" + +static int landscape_flag = 0; +static int ncopies = 1; +static int linewidth = -1; +// Non-zero means generate PostScript code that guesses the paper +// length using the imageable area. +static int guess_flag = 0; + +// Non-zero if -b was specified on the command line. +static int bflag = 0; +unsigned broken_flags = 0; + +#define DEFAULT_LINEWIDTH 40 /* in ems/1000 */ +#define FILL_MAX 1000 + +const char *const dict_name = "grops"; +const char *const defs_dict_name = "DEFS"; +const int DEFS_DICT_SPARE = 50; + +double degrees(double r) +{ + return r*180.0/M_PI; +} + +double radians(double d) +{ + return d*M_PI/180.0; +} + +inline double transform_fill(int fill) +{ + return 1 - fill/double(FILL_MAX); +} + +ps_output::ps_output(FILE *f, int n) +: fp(f), max_line_length(n), col(0), need_space(0), fixed_point(0) +{ +} + +ps_output &ps_output::set_file(FILE *f) +{ + fp = f; + col = 0; + return *this; +} + +ps_output &ps_output::copy_file(FILE *infp) +{ + int c; + while ((c = getc(infp)) != EOF) + putc(c, fp); + return *this; +} + +ps_output &ps_output::end_line() +{ + if (col != 0) { + putc('\n', fp); + col = 0; + need_space = 0; + } + return *this; +} + +ps_output &ps_output::special(const char *s) +{ + if (s == 0 || *s == '\0') + return *this; + if (col != 0) { + putc('\n', fp); + col = 0; + } + fputs(s, fp); + if (strchr(s, '\0')[-1] != '\n') + putc('\n', fp); + need_space = 0; + return *this; +} + +ps_output &ps_output::simple_comment(const char *s) +{ + if (col != 0) + putc('\n', fp); + putc('%', fp); + putc('%', fp); + fputs(s, fp); + putc('\n', fp); + col = 0; + need_space = 0; + return *this; +} + +ps_output &ps_output::begin_comment(const char *s) +{ + if (col != 0) + putc('\n', fp); + putc('%', fp); + putc('%', fp); + fputs(s, fp); + col = 2 + strlen(s); + return *this; +} + +ps_output &ps_output::end_comment() +{ + if (col != 0) { + putc('\n', fp); + col = 0; + } + need_space = 0; + return *this; +} + +ps_output &ps_output::comment_arg(const char *s) +{ + int len = strlen(s); + if (col + len + 1 > max_line_length) { + putc('\n', fp); + fputs("%%+", fp); + col = 3; + } + putc(' ', fp); + fputs(s, fp); + col += len + 1; + return *this; +} + +ps_output &ps_output::set_fixed_point(int n) +{ + assert(n >= 0 && n <= 10); + fixed_point = n; + return *this; +} + +ps_output &ps_output::put_delimiter(char c) +{ + if (col + 1 > max_line_length) { + putc('\n', fp); + col = 0; + } + putc(c, fp); + col++; + need_space = 0; + return *this; +} + +ps_output &ps_output::put_string(const char *s, int n) +{ + int len = 0; + for (int i = 0; i < n; i++) { + char c = s[i]; + if (isascii(c) && isprint(c)) { + if (c == '(' || c == ')' || c == '\\') + len += 2; + else + len += 1; + } + else + len += 4; + } + if (len > n*2) { + if (col + n*2 + 2 > max_line_length && n*2 + 2 <= max_line_length) { + putc('\n', fp); + col = 0; + } + if (col + 1 > max_line_length) { + putc('\n', fp); + col = 0; + } + putc('<', fp); + col++; + for (i = 0; i < n; i++) { + if (col + 2 > max_line_length) { + putc('\n', fp); + col = 0; + } + fprintf(fp, "%02x", s[i] & 0377); + col += 2; + } + putc('>', fp); + col++; + } + else { + if (col + len + 2 > max_line_length && len + 2 <= max_line_length) { + putc('\n', fp); + col = 0; + } + if (col + 2 > max_line_length) { + putc('\n', fp); + col = 0; + } + putc('(', fp); + col++; + for (i = 0; i < n; i++) { + char c = s[i]; + if (isascii(c) && isprint(c)) { + if (c == '(' || c == ')' || c == '\\') + len = 2; + else + len = 1; + } + else + len = 4; + if (col + len + 1 > max_line_length) { + putc('\\', fp); + putc('\n', fp); + col = 0; + } + switch (len) { + case 1: + putc(c, fp); + break; + case 2: + putc('\\', fp); + putc(c, fp); + break; + case 4: + fprintf(fp, "\\%03o", c & 0377); + break; + default: + assert(0); + } + col += len; + } + putc(')', fp); + col++; + } + need_space = 0; + return *this; +} + +ps_output &ps_output::put_number(int n) +{ + char buf[1 + INT_DIGITS + 1]; + sprintf(buf, "%d", n); + int len = strlen(buf); + if (col > 0 && col + len + need_space > max_line_length) { + putc('\n', fp); + col = 0; + need_space = 0; + } + if (need_space) { + putc(' ', fp); + col++; + } + fputs(buf, fp); + col += len; + need_space = 1; + return *this; +} + +ps_output &ps_output::put_fix_number(int i) +{ + const char *p = iftoa(i, fixed_point); + int len = strlen(p); + if (col > 0 && col + len + need_space > max_line_length) { + putc('\n', fp); + col = 0; + need_space = 0; + } + if (need_space) { + putc(' ', fp); + col++; + } + fputs(p, fp); + col += len; + need_space = 1; + return *this; +} + +ps_output &ps_output::put_float(double d) +{ + char buf[128]; + sprintf(buf, "%.4f", d); + int len = strlen(buf); + if (col > 0 && col + len + need_space > max_line_length) { + putc('\n', fp); + col = 0; + need_space = 0; + } + if (need_space) { + putc(' ', fp); + col++; + } + fputs(buf, fp); + col += len; + need_space = 1; + return *this; +} + +ps_output &ps_output::put_symbol(const char *s) +{ + int len = strlen(s); + if (col > 0 && col + len + need_space > max_line_length) { + putc('\n', fp); + col = 0; + need_space = 0; + } + if (need_space) { + putc(' ', fp); + col++; + } + fputs(s, fp); + col += len; + need_space = 1; + return *this; +} + +ps_output &ps_output::put_literal_symbol(const char *s) +{ + int len = strlen(s); + if (col > 0 && col + len + 1 > max_line_length) { + putc('\n', fp); + col = 0; + } + putc('/', fp); + fputs(s, fp); + col += len + 1; + need_space = 1; + return *this; +} + +class ps_font : public font { + ps_font(const char *); +public: + int encoding_index; + char *encoding; + char *reencoded_name; + ~ps_font(); + void handle_unknown_font_command(const char *command, const char *arg, + const char *filename, int lineno); + static ps_font *load_ps_font(const char *); +}; + +ps_font *ps_font::load_ps_font(const char *s) +{ + ps_font *f = new ps_font(s); + if (!f->load()) { + delete f; + return 0; + } + return f; +} + +ps_font::ps_font(const char *nm) +: font(nm), encoding(0), reencoded_name(0), encoding_index(-1) +{ +} + +ps_font::~ps_font() +{ + a_delete encoding; + a_delete reencoded_name; +} + +void ps_font::handle_unknown_font_command(const char *command, const char *arg, + const char *filename, int lineno) +{ + if (strcmp(command, "encoding") == 0) { + if (arg == 0) + error_with_file_and_line(filename, lineno, + "`encoding' command requires an argument"); + else + encoding = strsave(arg); + } +} + +static void handle_unknown_desc_command(const char *command, const char *arg, + const char *filename, int lineno) +{ + if (strcmp(command, "broken") == 0) { + if (arg == 0) + error_with_file_and_line(filename, lineno, + "`broken' command requires an argument"); + else if (!bflag) + broken_flags = atoi(arg); + } +} + +struct style { + font *f; + int point_size; + int height; + int slant; + style(); + style(font *, int, int, int); + int operator==(const style &) const; + int operator!=(const style &) const; +}; + +style::style() : f(0) +{ +} + +style::style(font *p, int sz, int h, int sl) +: f(p), point_size(sz), height(h), slant(sl) +{ +} + +int style::operator==(const style &s) const +{ + return (f == s.f && point_size == s.point_size + && height == s.height && slant == s.slant); +} + +int style::operator!=(const style &s) const +{ + return !(*this == s); +} + +class ps_printer : public printer { + FILE *tempfp; + ps_output out; + int res; + int space_char_index; + int pages_output; + int paper_length; + int equalise_spaces; + enum { SBUF_SIZE = 256 }; + char sbuf[SBUF_SIZE]; + int sbuf_len; + int sbuf_start_hpos; + int sbuf_vpos; + int sbuf_end_hpos; + int sbuf_space_width; + int sbuf_space_count; + int sbuf_space_diff_count; + int sbuf_space_code; + int sbuf_kern; + style sbuf_style; + style output_style; + int output_hpos; + int output_vpos; + int output_draw_point_size; + int line_thickness; + int output_line_thickness; + int fill; + unsigned char output_space_code; + enum { MAX_DEFINED_STYLES = 50 }; + style defined_styles[MAX_DEFINED_STYLES]; + int ndefined_styles; + int next_encoding_index; + string defs; + int ndefs; + resource_manager rm; + int invis_count; + + void flush_sbuf(); + void set_style(const style &); + void set_space_code(unsigned char c); + int set_encoding_index(ps_font *); + void do_exec(char *, const environment *); + void do_import(char *, const environment *); + void do_def(char *, const environment *); + void do_mdef(char *, const environment *); + void do_file(char *, const environment *); + void do_invis(char *, const environment *); + void do_endinvis(char *, const environment *); + void set_line_thickness(const environment *); + void fill_path(); + void encode_fonts(); + void define_encoding(const char *, int); + void reencode_font(ps_font *); +public: + ps_printer(); + ~ps_printer(); + void set_char(int i, font *f, const environment *env, int w); + void draw(int code, int *p, int np, const environment *env); + void begin_page(int); + void end_page(int); + void special(char *arg, const environment *env); + font *make_font(const char *); + void end_of_line(); +}; + +ps_printer::ps_printer() +: pages_output(0), + sbuf_len(0), + output_hpos(-1), + output_vpos(-1), + out(0, 79), + ndefined_styles(0), + next_encoding_index(0), + line_thickness(-1), + fill(FILL_MAX + 1), + ndefs(0), + invis_count(0) +{ + tempfp = xtmpfile(); + out.set_file(tempfp); + if (linewidth < 0) + linewidth = DEFAULT_LINEWIDTH; + if (font::hor != 1) + fatal("horizontal resolution must be 1"); + if (font::vert != 1) + fatal("vertical resolution must be 1"); + if (font::res % (font::sizescale*72) != 0) + fatal("res must be a multiple of 72*sizescale"); + int r = font::res; + int point = 0; + while (r % 10 == 0) { + r /= 10; + point++; + } + res = r; + out.set_fixed_point(point); + space_char_index = font::name_to_index("space"); + paper_length = font::paperlength; + if (paper_length == 0) + paper_length = 11*font::res; + equalise_spaces = font::res >= 72000; +} + +int ps_printer::set_encoding_index(ps_font *f) +{ + if (f->encoding_index >= 0) + return f->encoding_index; + for (font_pointer_list *p = font_list; p; p = p->next) + if (p->p != f) { + char *encoding = ((ps_font *)p->p)->encoding; + int encoding_index = ((ps_font *)p->p)->encoding_index; + if (encoding != 0 && encoding_index >= 0 + && strcmp(f->encoding, encoding) == 0) { + return f->encoding_index = encoding_index; + } + } + return f->encoding_index = next_encoding_index++; +} + +void ps_printer::set_char(int i, font *f, const environment *env, int w) +{ + if (i == space_char_index || invis_count > 0) + return; + unsigned char code = f->get_code(i); + style sty(f, env->size, env->height, env->slant); + if (sty.slant != 0) { + if (sty.slant > 80 || sty.slant < -80) { + error("silly slant `%1' degrees", sty.slant); + sty.slant = 0; + } + } + if (sbuf_len > 0) { + if (sbuf_len < SBUF_SIZE + && sty == sbuf_style + && sbuf_vpos == env->vpos) { + if (sbuf_end_hpos == env->hpos) { + sbuf[sbuf_len++] = code; + sbuf_end_hpos += w + sbuf_kern; + return; + } + if (sbuf_len == 1 && sbuf_kern == 0) { + sbuf_kern = env->hpos - sbuf_end_hpos; + sbuf_end_hpos = env->hpos + sbuf_kern + w; + sbuf[sbuf_len++] = code; + return; + } + /* If sbuf_end_hpos - sbuf_kern == env->hpos, we are better off + starting a new string. */ + if (sbuf_len < SBUF_SIZE - 1 && env->hpos >= sbuf_end_hpos + && (sbuf_kern == 0 || sbuf_end_hpos - sbuf_kern != env->hpos)) { + if (sbuf_space_code < 0) { + if (f->contains(space_char_index)) { + sbuf_space_code = f->get_code(space_char_index); + sbuf_space_width = env->hpos - sbuf_end_hpos; + sbuf_end_hpos = env->hpos + w + sbuf_kern; + sbuf[sbuf_len++] = sbuf_space_code; + sbuf[sbuf_len++] = code; + sbuf_space_count++; + return; + } + } + else { + int diff = env->hpos - sbuf_end_hpos - sbuf_space_width; + if (diff == 0 || (equalise_spaces && (diff == 1 || diff == -1))) { + sbuf_end_hpos = env->hpos + w + sbuf_kern; + sbuf[sbuf_len++] = sbuf_space_code; + sbuf[sbuf_len++] = code; + sbuf_space_count++; + if (diff == 1) + sbuf_space_diff_count++; + else if (diff == -1) + sbuf_space_diff_count--; + return; + } + } + } + } + flush_sbuf(); + } + sbuf_len = 1; + sbuf[0] = code; + sbuf_end_hpos = env->hpos + w; + sbuf_start_hpos = env->hpos; + sbuf_vpos = env->vpos; + sbuf_style = sty; + sbuf_space_code = -1; + sbuf_space_width = 0; + sbuf_space_count = sbuf_space_diff_count = 0; + sbuf_kern = 0; +} + +int is_small_h(int n) +{ + return n < (font::res*2)/72 && n > -(font::res*10)/72; +} + +int is_small_v(int n) +{ + return n < (font::res*4)/72 && n > -(font::res*4)/72; +} + +static char *make_encoding_name(int encoding_index) +{ + static char buf[3 + INT_DIGITS + 1]; + sprintf(buf, "ENC%d", encoding_index); + return buf; +} + +const char *const WS = " \t\n\r"; + +void ps_printer::define_encoding(const char *encoding, int encoding_index) +{ + char *vec[256]; + for (int i = 0; i < 256; i++) + vec[i] = 0; + char *path; + FILE *fp = font::open_file(encoding, &path); + if (fp == 0) + fatal("can't open encoding file `%1'", encoding); + int lineno = 1; + char buf[256]; + while (fgets(buf, 512, fp) != 0) { + char *p = buf; + while (isascii(*p) && isspace(*p)) + p++; + if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) { + char *q = strtok(0, WS); + int n; + if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256) + fatal_with_file_and_line(path, lineno, "bad second field"); + vec[n] = new char[strlen(p) + 1]; + strcpy(vec[n], p); + } + lineno++; + } + a_delete path; + out.put_literal_symbol(make_encoding_name(encoding_index)); + out.put_delimiter('['); + for (i = 0; i < 256; i++) { + if (vec[i] == 0) + out.put_literal_symbol(".notdef"); + else { + out.put_literal_symbol(vec[i]); + a_delete vec[i]; + } + } + out.put_delimiter(']').put_symbol("def"); +} + +void ps_printer::reencode_font(ps_font *f) +{ + out.put_literal_symbol(f->reencoded_name) + .put_symbol(make_encoding_name(f->encoding_index)) + .put_literal_symbol(f->get_internal_name()) + .put_symbol("RE"); +} + +void ps_printer::encode_fonts() +{ + if (next_encoding_index == 0) + return; + char *done_encoding = new char[next_encoding_index]; + for (int i = 0; i < next_encoding_index; i++) + done_encoding[i] = 0; + for (font_pointer_list *f = font_list; f; f = f->next) { + int encoding_index = ((ps_font *)f->p)->encoding_index; + if (encoding_index >= 0) { + assert(encoding_index < next_encoding_index); + if (!done_encoding[encoding_index]) { + done_encoding[encoding_index] = 1; + define_encoding(((ps_font *)f->p)->encoding, encoding_index); + } + reencode_font((ps_font *)f->p); + } + } + a_delete done_encoding; +} + +void ps_printer::set_style(const style &sty) +{ + char buf[1 + INT_DIGITS + 1]; + for (int i = 0; i < ndefined_styles; i++) + if (sty == defined_styles[i]) { + sprintf(buf, "F%d", i); + out.put_symbol(buf); + return; + } + if (ndefined_styles >= MAX_DEFINED_STYLES) + ndefined_styles = 0; + sprintf(buf, "F%d", ndefined_styles); + out.put_literal_symbol(buf); + const char *psname = sty.f->get_internal_name(); + if (psname == 0) + fatal("no internalname specified for font `%1'", sty.f->get_name()); + char *encoding = ((ps_font *)sty.f)->encoding; + if (encoding != 0) { + char *s = ((ps_font *)sty.f)->reencoded_name; + if (s == 0) { + int ei = set_encoding_index((ps_font *)sty.f); + char *tem = new char[strlen(psname) + 1 + INT_DIGITS + 1]; + sprintf(tem, "%s@%d", psname, ei); + psname = tem; + ((ps_font *)sty.f)->reencoded_name = tem; + } + else + psname = s; + } + out.put_fix_number((font::res/(72*font::sizescale))*sty.point_size); + if (sty.height != 0 || sty.slant != 0) { + int h = sty.height == 0 ? sty.point_size : sty.height; + h *= font::res/(72*font::sizescale); + int c = int(h*tan(radians(sty.slant)) + .5); + out.put_fix_number(c).put_fix_number(h).put_literal_symbol(psname) + .put_symbol("MF"); + } + else { + out.put_literal_symbol(psname).put_symbol("SF"); + } + defined_styles[ndefined_styles++] = sty; +} + +void ps_printer::set_space_code(unsigned char c) +{ + out.put_literal_symbol("SC").put_number(c).put_symbol("def"); +} + +void ps_printer::end_of_line() +{ + flush_sbuf(); + // this ensures that we do an absolute motion to the beginning of a line + output_vpos = output_hpos = -1; +} + +void ps_printer::flush_sbuf() +{ + enum { + NONE, + RELATIVE_H, + RELATIVE_V, + RELATIVE_HV, + ABSOLUTE + } motion = NONE; + int space_flag = 0; + if (sbuf_len == 0) + return; + if (output_style != sbuf_style) { + set_style(sbuf_style); + output_style = sbuf_style; + } + int extra_space = 0; + if (output_hpos < 0 || output_vpos < 0 + || !is_small_h(output_hpos - sbuf_start_hpos) + || !is_small_v(output_vpos - sbuf_vpos)) + motion = ABSOLUTE; + else { + if (output_hpos != sbuf_start_hpos) + motion = RELATIVE_H; + if (output_vpos != sbuf_vpos) { + if (motion != NONE) + motion = RELATIVE_HV; + else + motion = RELATIVE_V; + } + } + if (sbuf_space_code >= 0) { + int w = sbuf_style.f->get_width(space_char_index, sbuf_style.point_size); + if (w + sbuf_kern != sbuf_space_width) { + if (sbuf_space_code != output_space_code) { + set_space_code(sbuf_space_code); + output_space_code = sbuf_space_code; + } + space_flag = 1; + extra_space = sbuf_space_width - w - sbuf_kern; + if (sbuf_space_diff_count > sbuf_space_count/2) + extra_space++; + else if (sbuf_space_diff_count < -(sbuf_space_count/2)) + extra_space--; + } + } + if (space_flag) + out.put_fix_number(extra_space); + if (sbuf_kern != 0) + out.put_fix_number(sbuf_kern); + out.put_string(sbuf, sbuf_len); + char sym[2]; + sym[0] = 'A' + motion*4 + space_flag + 2*(sbuf_kern != 0); + sym[1] = '\0'; + switch (motion) { + case NONE: + break; + case ABSOLUTE: + out.put_fix_number(sbuf_start_hpos) + .put_fix_number(sbuf_vpos); + break; + case RELATIVE_H: + out.put_fix_number(sbuf_start_hpos - output_hpos); + break; + case RELATIVE_V: + out.put_fix_number(sbuf_vpos - output_vpos); + break; + case RELATIVE_HV: + out.put_fix_number(sbuf_start_hpos - output_hpos) + .put_fix_number(sbuf_vpos - output_vpos); + break; + default: + assert(0); + } + out.put_symbol(sym); + output_hpos = sbuf_end_hpos; + output_vpos = sbuf_vpos; + sbuf_len = 0; +} + + +void ps_printer::set_line_thickness(const environment *env) +{ + if (line_thickness < 0) { + if (output_draw_point_size != env->size) { + // we ought to check for overflow here + int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000; + out.put_fix_number(lw).put_symbol("LW"); + output_draw_point_size = env->size; + output_line_thickness = -1; + } + } + else { + if (output_line_thickness != line_thickness) { + out.put_fix_number(line_thickness).put_symbol("LW"); + output_line_thickness = line_thickness; + output_draw_point_size = -1; + } + } +} + +void ps_printer::fill_path() +{ + if (fill > FILL_MAX) + out.put_symbol("BL"); + else + out.put_float(transform_fill(fill)).put_symbol("FL"); +} + +void ps_printer::draw(int code, int *p, int np, const environment *env) +{ + if (invis_count > 0) + return; + int fill_flag = 0; + switch (code) { + case 'C': + fill_flag = 1; + // fall through + case 'c': + // troff adds an extra argument to C + if (np != 1 && !(code == 'C' && np == 2)) { + error("1 argument required for circle"); + break; + } + out.put_fix_number(env->hpos + p[0]/2) + .put_fix_number(env->vpos) + .put_fix_number(p[0]/2) + .put_symbol("DC"); + if (fill_flag) { + fill_path(); + } + else { + set_line_thickness(env); + out.put_symbol("ST"); + } + break; + case 'l': + if (np != 2) { + error("2 arguments required for line"); + break; + } + set_line_thickness(env); + out.put_fix_number(p[0] + env->hpos) + .put_fix_number(p[1] + env->vpos) + .put_fix_number(env->hpos) + .put_fix_number(env->vpos) + .put_symbol("DL"); + break; + case 'E': + fill_flag = 1; + // fall through + case 'e': + if (np != 2) { + error("2 arguments required for ellipse"); + break; + } + out.put_fix_number(p[0]) + .put_fix_number(p[1]) + .put_fix_number(env->hpos + p[0]/2) + .put_fix_number(env->vpos) + .put_symbol("DE"); + if (fill_flag) { + fill_path(); + } + else { + set_line_thickness(env); + out.put_symbol("ST"); + } + break; + case 'P': + fill_flag = 1; + // fall through + case 'p': + { + if (np & 1) { + error("even number of arguments required for polygon"); + break; + } + if (np == 0) { + error("no arguments for polygon"); + break; + } + out.put_fix_number(env->hpos) + .put_fix_number(env->vpos) + .put_symbol("MT"); + for (int i = 0; i < np; i += 2) + out.put_fix_number(p[i]) + .put_fix_number(p[i+1]) + .put_symbol("RL"); + out.put_symbol("CL"); + if (fill_flag) { + fill_path(); + } + else { + set_line_thickness(env); + out.put_symbol("ST"); + } + break; + } + case '~': + { + if (np & 1) { + error("even number of arguments required for spline"); + break; + } + if (np == 0) { + error("no arguments for spline"); + break; + } + out.put_fix_number(env->hpos) + .put_fix_number(env->vpos) + .put_symbol("MT"); + out.put_fix_number(p[0]/2) + .put_fix_number(p[1]/2) + .put_symbol("RL"); + /* tnum/tden should be between 0 and 1; the closer it is to 1 + the tighter the curve will be to the guiding lines; 2/3 + is the standard value */ + const int tnum = 2; + const int tden = 3; + for (int i = 0; i < np - 2; i += 2) { + out.put_fix_number((p[i]*tnum)/(2*tden)) + .put_fix_number((p[i + 1]*tnum)/(2*tden)) + .put_fix_number(p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden)) + .put_fix_number(p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden)) + .put_fix_number((p[i] - p[i]/2) + p[i + 2]/2) + .put_fix_number((p[i + 1] - p[i + 1]/2) + p[i + 3]/2) + .put_symbol("RC"); + } + out.put_fix_number(p[np - 2] - p[np - 2]/2) + .put_fix_number(p[np - 1] - p[np - 1]/2) + .put_symbol("RL"); + set_line_thickness(env); + out.put_symbol("ST"); + } + break; + case 'a': + { + if (np != 4) { + error("4 arguments required for arc"); + break; + } + set_line_thickness(env); + double c[2]; + if (adjust_arc_center(p, c)) + out.put_fix_number(env->hpos + int(c[0])) + .put_fix_number(env->vpos + int(c[1])) + .put_fix_number(int(sqrt(c[0]*c[0] + c[1]*c[1]))) + .put_float(degrees(atan2(-c[1], -c[0]))) + .put_float(degrees(atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]))) + .put_symbol("DA"); + else + out.put_fix_number(p[0] + p[2] + env->hpos) + .put_fix_number(p[1] + p[3] + env->vpos) + .put_fix_number(env->hpos) + .put_fix_number(env->vpos) + .put_symbol("DL"); + } + break; + case 't': + { + if (np == 0) { + line_thickness = -1; + } + else { + // troff gratuitously adds an extra 0 + if (np != 1 && np != 2) { + error("0 or 1 argument required for thickness"); + break; + } + line_thickness = p[0]; + } + break; + } + case 'f': + { + if (np != 1 && np != 2) { + error("1 argument required for fill"); + break; + } + fill = p[0]; + if (fill < 0 || fill > FILL_MAX) { + // This means fill with the current color. + fill = FILL_MAX + 1; + } + break; + } + default: + error("unrecognised drawing command `%1'", char(code)); + break; + } + + output_hpos = output_vpos = -1; +} + + +void ps_printer::begin_page(int n) +{ + out.begin_comment("Page:").comment_arg(itoa(n)); + out.comment_arg(itoa(++pages_output)).end_comment(); + output_style.f = 0; + output_space_code = 32; + output_draw_point_size = -1; + output_line_thickness = -1; + output_hpos = output_vpos = -1; + ndefined_styles = 0; + out.simple_comment("BeginPageSetup"); + out.put_symbol("BP"); + out.simple_comment("EndPageSetup"); +} + +void ps_printer::end_page(int) +{ + flush_sbuf(); + out.put_symbol("EP"); + if (invis_count != 0) { + error("missing `endinvis' command"); + invis_count = 0; + } +} + +font *ps_printer::make_font(const char *nm) +{ + return ps_font::load_ps_font(nm); +} + +ps_printer::~ps_printer() +{ + out.simple_comment("Trailer"); + out.put_symbol("end"); + out.simple_comment("EOF"); + if (fseek(tempfp, 0L, 0) < 0) + fatal("fseek on temporary file failed"); + fputs("%!PS-Adobe-", stdout); + fputs((broken_flags & USE_PS_ADOBE_2_0) ? "2.0" : "3.0", stdout); + putchar('\n'); + out.set_file(stdout); + { + extern const char *version_string; + out.begin_comment("Creator:") + .comment_arg("groff") + .comment_arg("version") + .comment_arg(version_string) + .end_comment(); + } + for (font_pointer_list *f = font_list; f; f = f->next) { + ps_font *psf = (ps_font *)(f->p); + rm.need_font(psf->get_internal_name()); + } + rm.print_header_comments(out); + out.begin_comment("Pages:").comment_arg(itoa(pages_output)).end_comment(); + out.begin_comment("PageOrder:").comment_arg("Ascend").end_comment(); +#if 0 + fprintf(out.get_file(), "%%%%DocumentMedia: () %g %g 0 () ()\n", + font::paperwidth*72.0/font::res, + paper_length*72.0/font::res); +#endif + out.begin_comment("Orientation:") + .comment_arg(landscape_flag ? "Landscape" : "Portrait") + .end_comment(); + if (ncopies != 1) { + out.end_line(); + fprintf(out.get_file(), "%%%%Requirements: numcopies(%d)\n", ncopies); + } + out.simple_comment("EndComments"); + out.simple_comment("BeginProlog"); + rm.output_prolog(out); + if (!(broken_flags & NO_SETUP_SECTION)) { + out.simple_comment("EndProlog"); + out.simple_comment("BeginSetup"); + } + rm.document_setup(out); + out.put_symbol(dict_name).put_symbol("begin"); + if (ndefs > 0) + ndefs += DEFS_DICT_SPARE; + out.put_literal_symbol(defs_dict_name) + .put_number(ndefs + 1) + .put_symbol("dict") + .put_symbol("def"); + out.put_symbol(defs_dict_name) + .put_symbol("begin"); + out.put_literal_symbol("u") + .put_delimiter('{') + .put_fix_number(1) + .put_symbol("mul") + .put_delimiter('}') + .put_symbol("bind") + .put_symbol("def"); + defs += '\0'; + out.special(defs.contents()); + out.put_symbol("end"); + if (ncopies != 1) + out.put_literal_symbol("#copies").put_number(ncopies).put_symbol("def"); + out.put_literal_symbol("RES").put_number(res).put_symbol("def"); + out.put_literal_symbol("PL"); + if (guess_flag) + out.put_symbol("PLG"); + else + out.put_fix_number(paper_length); + out.put_symbol("def"); + out.put_literal_symbol("LS") + .put_symbol(landscape_flag ? "true" : "false") + .put_symbol("def"); + encode_fonts(); + out.simple_comment((broken_flags & NO_SETUP_SECTION) + ? "EndProlog" + : "EndSetup"); + out.end_line(); + out.copy_file(tempfp); + fclose(tempfp); +} + +void ps_printer::special(char *arg, const environment *env) +{ + typedef void (ps_printer::*SPECIAL_PROCP)(char *, const environment *); + static struct { + const char *name; + SPECIAL_PROCP proc; + } proc_table[] = { + "exec", &ps_printer::do_exec, + "def", &ps_printer::do_def, + "mdef", &ps_printer::do_mdef, + "import", &ps_printer::do_import, + "file", &ps_printer::do_file, + "invis", &ps_printer::do_invis, + "endinvis", &ps_printer::do_endinvis, + }; + for (char *p = arg; *p == ' ' || *p == '\n'; p++) + ; + char *tag = p; + for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++) + ; + if (*p == '\0' || strncmp(tag, "ps", p - tag) != 0) { + error("X command without `ps:' tag ignored"); + return; + } + p++; + for (; *p == ' ' || *p == '\n'; p++) + ; + char *command = p; + for (; *p != '\0' && *p != ' ' && *p != '\n'; p++) + ; + if (*command == '\0') { + error("X command without `ps:' tag ignored"); + return; + } + for (int i = 0; i < sizeof(proc_table)/sizeof(proc_table[0]); i++) + if (strncmp(command, proc_table[i].name, p - command) == 0) { + (this->*(proc_table[i].proc))(p, env); + return; + } + error("X command `%1' not recognised", command); +} + +// A conforming PostScript document must not have lines longer +// than 255 characters (excluding line termination characters). + +static int check_line_lengths(const char *p) +{ + for (;;) { + const char *end = strchr(p, '\n'); + if (end == 0) + end = strchr(p, '\0'); + if (end - p > 255) + return 0; + if (*end == '\0') + break; + p = end + 1; + } + return 1; +} + +void ps_printer::do_exec(char *arg, const environment *env) +{ + flush_sbuf(); + while (csspace(*arg)) + arg++; + if (*arg == '\0') { + error("missing argument to X exec command"); + return; + } + if (!check_line_lengths(arg)) { + error("lines in X exec command must not be more than 255 characters long"); + return; + } + out.put_fix_number(env->hpos) + .put_fix_number(env->vpos) + .put_symbol("EBEGIN") + .special(arg) + .put_symbol("EEND"); + output_hpos = output_vpos = -1; + output_style.f = 0; + output_draw_point_size = -1; + output_line_thickness = -1; + ndefined_styles = 0; + if (!ndefs) + ndefs = 1; +} + +void ps_printer::do_file(char *arg, const environment *env) +{ + flush_sbuf(); + while (csspace(*arg)) + arg++; + if (*arg == '\0') { + error("missing argument to X file command"); + return; + } + const char *filename = arg; + do { + ++arg; + } while (*arg != '\0' && *arg != ' ' && *arg != '\n'); + out.put_fix_number(env->hpos) + .put_fix_number(env->vpos) + .put_symbol("EBEGIN"); + rm.import_file(filename, out); + out.put_symbol("EEND"); + output_hpos = output_vpos = -1; + output_style.f = 0; + output_draw_point_size = -1; + output_line_thickness = -1; + ndefined_styles = 0; + if (!ndefs) + ndefs = 1; +} + +void ps_printer::do_def(char *arg, const environment *) +{ + flush_sbuf(); + while (csspace(*arg)) + arg++; + if (!check_line_lengths(arg)) { + error("lines in X def command must not be more than 255 characters long"); + return; + } + defs += arg; + if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n') + defs += '\n'; + ndefs++; +} + +// Like def, but the first argument says how many definitions it contains. + +void ps_printer::do_mdef(char *arg, const environment *) +{ + flush_sbuf(); + char *p; + int n = (int)strtol(arg, &p, 10); + if (n == 0 && p == arg) { + error("first argument to X mdef must be an integer"); + return; + } + if (n < 0) { + error("out of range argument `%1' to X mdef command", int(n)); + return; + } + arg = p; + while (csspace(*arg)) + arg++; + if (!check_line_lengths(arg)) { + error("lines in X mdef command must not be more than 255 characters long"); + return; + } + defs += arg; + if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n') + defs += '\n'; + ndefs += n; +} + +void ps_printer::do_import(char *arg, const environment *env) +{ + flush_sbuf(); + while (*arg == ' ' || *arg == '\n') + arg++; + for (char *p = arg; *p != '\0' && *p != ' ' && *p != '\n'; p++) + ; + if (*p != '\0') + *p++ = '\0'; + int parms[6]; + int nparms = 0; + while (nparms < 6) { + char *end; + long n = strtol(p, &end, 10); + if (n == 0 && end == p) + break; + parms[nparms++] = int(n); + p = end; + } + if (csalpha(*p) && (p[1] == '\0' || p[1] == ' ' || p[1] == '\n')) { + error("scaling indicators not allowed in arguments for X import command"); + return; + } + while (*p == ' ' || *p == '\n') + p++; + if (nparms < 5) { + if (*p == '\0') + error("too few arguments for X import command"); + else + error("invalid argument `%1' for X import command", p); + return; + } + if (*p != '\0') { + error("superflous argument `%1' for X import command", p); + return; + } + int llx = parms[0]; + int lly = parms[1]; + int urx = parms[2]; + int ury = parms[3]; + int desired_width = parms[4]; + int desired_height = parms[5]; + if (desired_width <= 0) { + error("bad width argument `%1' for X import command: must be > 0", + desired_width); + return; + } + if (nparms == 6 && desired_height <= 0) { + error("bad height argument `%1' for X import command: must be > 0", + desired_height); + return; + } + if (llx == urx) { + error("llx and urx arguments for X import command must not be equal"); + return; + } + if (lly == ury) { + error("lly and ury arguments for X import command must not be equal"); + return; + } + if (nparms == 5) { + int old_wid = urx - llx; + int old_ht = ury - lly; + if (old_wid < 0) + old_wid = -old_wid; + if (old_ht < 0) + old_ht = -old_ht; + desired_height = int(desired_width*(double(old_ht)/double(old_wid)) + .5); + } + if (env->vpos - desired_height < 0) + warning("top of imported graphic is above the top of the page"); + out.put_number(llx) + .put_number(lly) + .put_fix_number(desired_width) + .put_number(urx - llx) + .put_fix_number(-desired_height) + .put_number(ury - lly) + .put_fix_number(env->hpos) + .put_fix_number(env->vpos) + .put_symbol("PBEGIN"); + rm.import_file(arg, out); + // do this here just in case application defines PEND + out.put_symbol("end"); + out.put_symbol("PEND"); +} + +void ps_printer::do_invis(char *, const environment *) +{ + invis_count++; +} + +void ps_printer::do_endinvis(char *, const environment *) +{ + if (invis_count == 0) + error("unbalanced `endinvis' command"); + else + --invis_count; +} + +printer *make_printer() +{ + return new ps_printer; +} + +static void usage(); + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int c; + while ((c = getopt(argc, argv, "F:glc:w:vb:")) != EOF) + switch(c) { + case 'v': + { + extern const char *version_string; + fprintf(stderr, "grops version %s\n", version_string); + fflush(stderr); + break; + } + case 'c': + if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) { + error("bad number of copies `%s'", optarg); + ncopies = 1; + } + break; + case 'g': + guess_flag = 1; + break; + case 'l': + landscape_flag = 1; + break; + case 'F': + font::command_line_font_dir(optarg); + break; + case 'w': + if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) { + error("bad linewidth `%s'", optarg); + linewidth = -1; + } + break; + case 'b': + // XXX check this + broken_flags = atoi(optarg); + bflag = 1; + break; + case '?': + usage(); + break; + default: + assert(0); + } + font::set_unknown_desc_command_handler(handle_unknown_desc_command); + if (optind >= argc) + do_file("-"); + else { + for (int i = optind; i < argc; i++) + do_file(argv[i]); + } + delete pr; + exit(0); +} + +static void usage() +{ + fprintf(stderr, "usage: %s [-glv] [-b n] [-c n] [-w n] [-F dir] [files ...]\n", + program_name); + exit(1); +} diff --git a/gnu/usr.bin/groff/grops/ps.h b/gnu/usr.bin/groff/grops/ps.h new file mode 100644 index 0000000000..50be4e8ba4 --- /dev/null +++ b/gnu/usr.bin/groff/grops/ps.h @@ -0,0 +1,122 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +class ps_output { +public: + ps_output(FILE *, int max_line_length); + ps_output &put_string(const char *, int); + ps_output &put_number(int); + ps_output &put_fix_number(int); + ps_output &put_float(double); + ps_output &put_symbol(const char *); + ps_output &put_literal_symbol(const char *); + ps_output &set_fixed_point(int); + ps_output &simple_comment(const char *); + ps_output &begin_comment(const char *); + ps_output &comment_arg(const char *); + ps_output &end_comment(); + ps_output &set_file(FILE *); + ps_output &include_file(FILE *); + ps_output ©_file(FILE *); + ps_output &end_line(); + ps_output &put_delimiter(char); + ps_output &special(const char *); + FILE *get_file(); +private: + FILE *fp; + int col; + int max_line_length; // not including newline + int need_space; + int fixed_point; +}; + +inline FILE *ps_output::get_file() +{ + return fp; +} + +enum resource_type { + RESOURCE_FONT, + RESOURCE_PROCSET, + RESOURCE_FILE, + RESOURCE_ENCODING, + RESOURCE_FORM, + RESOURCE_PATTERN + }; + +struct resource; + +extern string an_empty_string; + +class resource_manager { +public: + resource_manager(); + ~resource_manager(); + void import_file(const char *filename, ps_output &); + void need_font(const char *name); + void print_header_comments(ps_output &); + void document_setup(ps_output &); + void output_prolog(ps_output &); +private: + unsigned extensions; + unsigned language_level; + resource *procset_resource; + resource *resource_list; + resource *lookup_resource(resource_type type, string &name, + string &version = an_empty_string, + unsigned revision = 0); + resource *lookup_font(const char *name); + void read_download_file(); + void supply_resource(resource *r, int rank, FILE *outfp, + int is_document = 0); + void process_file(int rank, FILE *fp, const char *filename, FILE *outfp); + resource *read_file_arg(const char **); + resource *read_procset_arg(const char **); + resource *read_font_arg(const char **); + resource *read_resource_arg(const char **); + void print_resources_comment(unsigned flag, FILE *outfp); + void print_extensions_comment(FILE *outfp); + void print_language_level_comment(FILE *outfp); + int do_begin_resource(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_include_resource(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_begin_document(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_include_document(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_begin_procset(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_include_procset(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_begin_font(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_include_font(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_begin_file(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_include_file(const char *ptr, int rank, FILE *fp, FILE *outfp); + int change_to_end_resource(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_begin_preview(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_begin_data(const char *ptr, int rank, FILE *fp, FILE *outfp); + int do_begin_binary(const char *ptr, int rank, FILE *fp, FILE *outfp); +}; + +extern unsigned broken_flags; + +// broken_flags is ored from these + +enum { + NO_SETUP_SECTION = 01, + STRIP_PERCENT_BANG = 02, + STRIP_STRUCTURE_COMMENTS = 04, + USE_PS_ADOBE_2_0 = 010 +}; diff --git a/gnu/usr.bin/groff/grops/psfig.diff b/gnu/usr.bin/groff/grops/psfig.diff new file mode 100644 index 0000000000..77217742dc --- /dev/null +++ b/gnu/usr.bin/groff/grops/psfig.diff @@ -0,0 +1,106 @@ +These are patches to makes psfig work with groff. They apply to the +version of psfig in comp.sources.unix/Volume11. After applying them, +psfig should be recompiled with -DGROFF. The resulting psfig will +work only with groff, so you might want to install it under a +different name. The output of this psfig must be processed using the +macros in the file ../macros/tmac.psfig. These will automatically add +the necessary PostScript code to the prologue output by grops. Use of +the `global' feature in psfig will result in non-conformant PostScript +which will fail if processed by a page reversal program. Note that +psfig is unsupported by me (I'm not interested in hearing about psfig +problems.) For new documents, I recommend using the PostScript +inclusion features provided by grops. + +James Clark +jjc@jclark.com + +*** cmds.c.~1~ Thu Feb 14 16:09:45 1991 +--- cmds.c Mon Mar 4 12:49:26 1991 +*************** +*** 245,253 **** +--- 245,261 ---- + (void) sprintf(x, "%.2fp", fx); + (void) sprintf(y, "%.2fp", fy); + } else if (!*x) { ++ #ifndef GROFF + (void) sprintf(x,"(%.2fp*%s/%.2fp)", fx, y, fy); ++ #else /* GROFF */ ++ (void) sprintf(x,"(%.0fu*%s/%.0fu)", fx, y, fy); ++ #endif /* GROFF */ + } else if (!*y) { ++ #ifndef GROFF + (void) sprintf(y,"(%.2fp*%s/%.2fp)", fy, x, fx); ++ #else /* GROFF */ ++ (void) sprintf(y,"(%.0fu*%s/%.0fu)", fy, x, fx); ++ #endif /* GROFF */ + } + + /* +*** troff.c.~1~ Thu Feb 14 16:09:48 1991 +--- troff.c Mon Mar 4 12:48:46 1991 +*************** +*** 26,32 **** +--- 26,36 ---- + } + + ++ #ifndef GROFF + char incl_file_s[] = "\\X'f%s'"; ++ #else /* GROFF */ ++ char incl_file_s[] = "\\X'ps: file %s'"; ++ #endif /* GROFF */ + includeFile(filenm) + char *filenm; { + printf(incl_file_s, filenm); +*************** +*** 40,52 **** +--- 44,64 ---- + error("buffer overflow"); + } + ++ #ifndef GROFF + char endfig_s[] = "\\X'pendFig'"; ++ #else /* GROFF */ ++ char endfig_s[] = "\\X'ps: exec psfigend'"; ++ #endif /* GROFF */ + endfig() { + printf(endfig_s); + } + + char startfig_s[] = ++ #ifndef GROFF + "\\X'p\\w@\\h@%s@@'\\X'p\\w@\\h@%s@@'\\X'p%.2f'\\X'p%.2f'\\X'p%.2f'\\X'p%.2f'\\X'pstartFig'"; ++ #else /* GROFF */ ++ "\\X'ps: exec \\w@\\h@%s@@ \\w@\\h@%s@@ %.2f %.2f %.2f %.2f psfigstart'"; ++ #endif /* GROFF */ + + startfig(x, y, llx, lly, urx, ury) + char *x, *y; +*************** +*** 57,63 **** +--- 69,79 ---- + } + + emitDoClip() { ++ #ifndef GROFF + printf("\\X'pdoclip'"); ++ #else /* GROFF */ ++ printf("\\X'ps: exec psfigclip'"); ++ #endif /* GROFF */ + } + + flushX() +*************** +*** 116,122 **** +--- 132,142 ---- + + #define isWhite(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n') + ++ #ifndef GROFF + char literal_s[] = "\\X'p%s'"; ++ #else /* GROFF */ ++ char literal_s[] = "\\X'ps: exec %s'"; ++ #endif /* GROFF */ + emitLiteral(text) + char *text; { + static char litbuf[BUFSZ]; diff --git a/gnu/usr.bin/groff/grops/psrm.cc b/gnu/usr.bin/groff/grops/psrm.cc new file mode 100644 index 0000000000..e26acf4b15 --- /dev/null +++ b/gnu/usr.bin/groff/grops/psrm.cc @@ -0,0 +1,1091 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "driver.h" +#include "stringclass.h" +#include "cset.h" + +#include "ps.h" + +#define PROLOGUE "prologue" + +static void print_ps_string(const string &s, FILE *outfp); + +cset white_space("\n\r \t"); +string an_empty_string; + +const char *extension_table[] = { + "DPS", + "CMYK", + "Composite", + "FileSystem", +}; + +const int NEXTENSIONS = sizeof(extension_table)/sizeof(extension_table[0]); + +const char *resource_table[] = { + "font", + "procset", + "file", + "encoding", + "form", + "pattern", +}; + +const int NRESOURCES = sizeof(resource_table)/sizeof(resource_table[0]); + +struct resource { + resource *next; + resource_type type; + string name; + enum { NEEDED = 01, SUPPLIED = 02, FONT_NEEDED = 04, BUSY = 010 }; + unsigned flags; + string version; + unsigned revision; + char *filename; + int rank; + resource(resource_type, string &, string & = an_empty_string, unsigned = 0); + ~resource(); + void print_type_and_name(FILE *outfp); +}; + +resource::resource(resource_type t, string &n, string &v, unsigned r) +: type(t), revision(r), flags (0), filename(0), rank(-1), next(0) +{ + name.move(n); + version.move(v); + if (type == RESOURCE_FILE) { + if (name.search('\0') >= 0) + error("filename contains a character with code 0"); + filename = name.extract(); + } +} + +resource::~resource() +{ + a_delete filename; +} + +void resource::print_type_and_name(FILE *outfp) +{ + fputs(resource_table[type], outfp); + putc(' ', outfp); + print_ps_string(name, outfp); + if (type == RESOURCE_PROCSET) { + putc(' ', outfp); + print_ps_string(version, outfp); + fprintf(outfp, " %u", revision); + } +} + +resource_manager::resource_manager() +: resource_list(0), extensions(0), language_level(0) +{ + read_download_file(); + string procset_name("grops"); + extern const char *version_string; + string procset_version(version_string); + procset_resource = lookup_resource(RESOURCE_PROCSET, procset_name, + procset_version, 0); + procset_resource->flags |= resource::SUPPLIED; +} + +resource_manager::~resource_manager() +{ + while (resource_list) { + resource *tem = resource_list; + resource_list = resource_list->next; + delete tem; + } +} + +resource *resource_manager::lookup_resource(resource_type type, + string &name, + string &version, + unsigned revision) +{ + for (resource *r = resource_list; r; r = r->next) + if (r->type == type + && r->name == name + && r->version == version + && r->revision == revision) + return r; + r = new resource(type, name, version, revision); + r->next = resource_list; + resource_list = r; + return r; +} + +// Just a specialized version of lookup_resource(). + +resource *resource_manager::lookup_font(const char *name) +{ + for (resource *r = resource_list; r; r = r->next) + if (r->type == RESOURCE_FONT + && strlen(name) == r->name.length() + && memcmp(name, r->name.contents(), r->name.length()) == 0) + return r; + string s(name); + r = new resource(RESOURCE_FONT, s); + r->next = resource_list; + resource_list = r; + return r; +} + +void resource_manager::need_font(const char *name) +{ + lookup_font(name)->flags |= resource::FONT_NEEDED; +} + +typedef resource *Presource; // Work around g++ bug. + +void resource_manager::document_setup(ps_output &out) +{ + int nranks = 0; + for (resource *r = resource_list; r; r = r->next) + if (r->rank >= nranks) + nranks = r->rank + 1; + if (nranks > 0) { + // Sort resource_list in reverse order of rank. + Presource *head = new Presource[nranks + 1]; + Presource **tail = new Presource *[nranks + 1]; + for (int i = 0; i < nranks + 1; i++) { + head[i] = 0; + tail[i] = &head[i]; + } + for (r = resource_list; r; r = r->next) { + i = r->rank < 0 ? 0 : r->rank + 1; + *tail[i] = r; + tail[i] = &(*tail[i])->next; + } + resource_list = 0; + for (i = 0; i < nranks + 1; i++) + if (head[i]) { + *tail[i] = resource_list; + resource_list = head[i]; + } + a_delete head; + a_delete tail; + // check it + for (r = resource_list; r; r = r->next) + if (r->next) + assert(r->rank >= r->next->rank); + for (r = resource_list; r; r = r->next) + if (r->type == RESOURCE_FONT && r->rank >= 0) + supply_resource(r, -1, out.get_file()); + } +} + +void resource_manager::print_resources_comment(unsigned flag, FILE *outfp) +{ + int continued = 0; + for (resource *r = resource_list; r; r = r->next) + if (r->flags & flag) { + if (continued) + fputs("%%+ ", outfp); + else { + fputs(flag == resource::NEEDED + ? "%%DocumentNeededResources: " + : "%%DocumentSuppliedResources: ", + outfp); + continued = 1; + } + r->print_type_and_name(outfp); + putc('\n', outfp); + } +} + +void resource_manager::print_header_comments(ps_output &out) +{ + for (resource *r = resource_list; r; r = r->next) + if (r->type == RESOURCE_FONT && (r->flags & resource::FONT_NEEDED)) + supply_resource(r, 0, 0); + print_resources_comment(resource::NEEDED, out.get_file()); + print_resources_comment(resource::SUPPLIED, out.get_file()); + print_language_level_comment(out.get_file()); + print_extensions_comment(out.get_file()); +} + +void resource_manager::output_prolog(ps_output &out) +{ + FILE *outfp = out.get_file(); + out.end_line(); + char *path; + FILE *fp = font::open_file(PROLOGUE, &path); + if (!fp) + fatal("can't find `%1'", PROLOGUE); + fputs("%%BeginResource: ", outfp); + procset_resource->print_type_and_name(outfp); + putc('\n', outfp); + process_file(-1, fp, path, outfp); + fclose(fp); + a_delete path; + fputs("%%EndResource\n", outfp); +} + +void resource_manager::import_file(const char *filename, ps_output &out) +{ + out.end_line(); + string name(filename); + resource *r = lookup_resource(RESOURCE_FILE, name); + supply_resource(r, -1, out.get_file(), 1); +} + +void resource_manager::supply_resource(resource *r, int rank, FILE *outfp, + int is_document) +{ + if (r->flags & resource::BUSY) { + r->name += '\0'; + fatal("loop detected in dependency graph for %1 `%2'", + resource_table[r->type], + r->name.contents()); + } + r->flags |= resource::BUSY; + if (rank > r->rank) + r->rank = rank; + char *path; + FILE *fp = 0; + if (r->filename != 0) { + if (r->type == RESOURCE_FONT) { + fp = font::open_file(r->filename, &path); + if (!fp) { + error("can't find `%1'", r->filename); + a_delete r->filename; + r->filename = 0; + } + } + else { + errno = 0; + fp = fopen(r->filename, "r"); + if (!fp) { + error("can't open `%1': %2", r->filename, strerror(errno)); + a_delete r->filename; + r->filename = 0; + } + else + path = r->filename; + } + } + if (fp) { + if (outfp) { + if (r->type == RESOURCE_FILE && is_document) { + fputs("%%BeginDocument: ", outfp); + print_ps_string(r->name, outfp); + putc('\n', outfp); + } + else { + fputs("%%BeginResource: ", outfp); + r->print_type_and_name(outfp); + putc('\n', outfp); + } + } + process_file(rank, fp, path, outfp); + fclose(fp); + if (r->type == RESOURCE_FONT) + a_delete path; + if (outfp) { + if (r->type == RESOURCE_FILE && is_document) + fputs("%%EndDocument\n", outfp); + else + fputs("%%EndResource\n", outfp); + } + r->flags |= resource::SUPPLIED; + } + else { + if (outfp) { + if (r->type == RESOURCE_FILE && is_document) { + fputs("%%IncludeDocument: ", outfp); + print_ps_string(r->name, outfp); + putc('\n', outfp); + } + else { + fputs("%%IncludeResource: ", outfp); + r->print_type_and_name(outfp); + putc('\n', outfp); + } + } + r->flags |= resource::NEEDED; + } + r->flags &= ~resource::BUSY; +} + + +#define PS_LINE_MAX 255 +#define PS_MAGIC "%!PS-Adobe-" + +static int ps_get_line(char *buf, FILE *fp) +{ + int c = getc(fp); + if (c == EOF) { + buf[0] = '\0'; + return 0; + } + current_lineno++; + int i = 0; + int err = 0; + while (c != '\r' && c != '\n' && c != EOF) { + if ((c < 0x1b && !white_space(c)) || c == 0x7f) + error("illegal input character code %1", int(c)); + else if (i < PS_LINE_MAX) + buf[i++] = c; + else if (!err) { + err = 1; + error("PostScript file non-conforming " + "because length of line exceeds 255"); + } + c = getc(fp); + } + buf[i++] = '\n'; + buf[i] = '\0'; + if (c == '\r') { + c = getc(fp); + if (c != EOF && c != '\n') + ungetc(c, fp); + } + return 1; +} + +static int read_text_arg(const char **pp, string &res) +{ + res.clear(); + while (white_space(**pp)) + *pp += 1; + if (**pp == '\0') { + error("missing argument"); + return 0; + } + if (**pp != '(') { + for (; **pp != '\0' && !white_space(**pp); *pp += 1) + res += **pp; + return 1; + } + *pp += 1; + res.clear(); + int level = 0; + for (;;) { + if (**pp == '\0' || **pp == '\r' || **pp == '\n') { + error("missing ')'"); + return 0; + } + if (**pp == ')') { + if (level == 0) { + *pp += 1; + break; + } + res += **pp; + level--; + } + else if (**pp == '(') { + level++; + res += **pp; + } + else if (**pp == '\\') { + *pp += 1; + switch (**pp) { + case 'n': + res += '\n'; + break; + case 'r': + res += '\n'; + break; + case 't': + res += '\t'; + break; + case 'b': + res += '\b'; + break; + case 'f': + res += '\f'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int val = **pp - '0'; + if ((*pp)[1] >= '0' && (*pp)[1] <= '7') { + *pp += 1; + val = val*8 + (**pp - '0'); + if ((*pp)[1] >= '0' && (*pp)[1] <= '7') { + *pp += 1; + val = val*8 + (**pp - '0'); + } + } + } + break; + default: + res += **pp; + break; + } + } + else + res += **pp; + *pp += 1; + } + return 1; +} + +static int read_uint_arg(const char **pp, unsigned *res) +{ + while (white_space(**pp)) + *pp += 1; + if (**pp == '\0') { + error("missing argument"); + return 0; + } + const char *start = *pp; + // XXX use strtoul + long n = strtol(start, (char **)pp, 10); + if (n == 0 && *pp == start) { + error("not an integer"); + return 0; + } + if (n < 0) { + error("argument must not be negative"); + return 0; + } + *res = unsigned(n); + return 1; +} + +resource *resource_manager::read_file_arg(const char **ptr) +{ + string arg; + if (!read_text_arg(ptr, arg)) + return 0; + return lookup_resource(RESOURCE_FILE, arg); +} + +resource *resource_manager::read_font_arg(const char **ptr) +{ + string arg; + if (!read_text_arg(ptr, arg)) + return 0; + return lookup_resource(RESOURCE_FONT, arg); +} + +resource *resource_manager::read_procset_arg(const char **ptr) +{ + string arg; + if (!read_text_arg(ptr, arg)) + return 0; + string version; + if (!read_text_arg(ptr, version)) + return 0; + unsigned revision; + if (!read_uint_arg(ptr, &revision)) + return 0; + return lookup_resource(RESOURCE_PROCSET, arg, version, revision); +} + +resource *resource_manager::read_resource_arg(const char **ptr) +{ + while (white_space(**ptr)) + *ptr += 1; + const char *name = *ptr; + while (**ptr != '\0' && !white_space(**ptr)) + *ptr += 1; + if (name == *ptr) { + error("missing resource type"); + return 0; + } + for (int ri = 0; ri < NRESOURCES; ri++) + if (strlen(resource_table[ri]) == *ptr - name + && memcmp(resource_table[ri], name, *ptr - name) == 0) + break; + if (ri >= NRESOURCES) { + error("unknown resource type"); + return 0; + } + if (ri == RESOURCE_PROCSET) + return read_procset_arg(ptr); + string arg; + if (!read_text_arg(ptr, arg)) + return 0; + return lookup_resource(resource_type(ri), arg); +} + +static const char *matches_comment(const char *buf, const char *comment) +{ + if (buf[0] != '%' || buf[1] != '%') + return 0; + for (buf += 2; *comment; comment++, buf++) + if (*buf != *comment) + return 0; + if (comment[-1] == ':') + return buf; + if (*buf == '\0' || white_space(*buf)) + return buf; + return 0; +} + +// Return 1 if the line should be copied out. + +int resource_manager::do_begin_resource(const char *ptr, int, FILE *, + FILE *) +{ + resource *r = read_resource_arg(&ptr); + if (r) + r->flags |= resource::SUPPLIED; + return 1; +} + +int resource_manager::do_include_resource(const char *ptr, int rank, FILE *, + FILE *outfp) +{ + resource *r = read_resource_arg(&ptr); + if (r) { + if (r->type == RESOURCE_FONT) { + if (rank >= 0) + supply_resource(r, rank + 1, outfp); + else + r->flags |= resource::FONT_NEEDED; + } + else + supply_resource(r, rank, outfp); + } + return 0; +} + +int resource_manager::do_begin_document(const char *ptr, int, FILE *, + FILE *) +{ + resource *r = read_file_arg(&ptr); + if (r) + r->flags |= resource::SUPPLIED; + return 1; +} + +int resource_manager::do_include_document(const char *ptr, int rank, FILE *, + FILE *outfp) +{ + resource *r = read_file_arg(&ptr); + if (r) + supply_resource(r, rank, outfp, 1); + return 0; +} + +int resource_manager::do_begin_procset(const char *ptr, int, FILE *, + FILE *outfp) +{ + resource *r = read_procset_arg(&ptr); + if (r) { + r->flags |= resource::SUPPLIED; + if (outfp) { + fputs("%%BeginResource: ", outfp); + r->print_type_and_name(outfp); + putc('\n', outfp); + } + } + return 0; +} + +int resource_manager::do_include_procset(const char *ptr, int rank, FILE *, + FILE *outfp) +{ + resource *r = read_procset_arg(&ptr); + if (r) + supply_resource(r, rank, outfp); + return 0; +} + +int resource_manager::do_begin_file(const char *ptr, int, FILE *, + FILE *outfp) +{ + resource *r = read_file_arg(&ptr); + if (r) { + r->flags |= resource::SUPPLIED; + if (outfp) { + fputs("%%BeginResource: ", outfp); + r->print_type_and_name(outfp); + putc('\n', outfp); + } + } + return 0; +} + +int resource_manager::do_include_file(const char *ptr, int rank, FILE *, + FILE *outfp) +{ + resource *r = read_file_arg(&ptr); + if (r) + supply_resource(r, rank, outfp); + return 0; +} + +int resource_manager::do_begin_font(const char *ptr, int, FILE *, + FILE *outfp) +{ + resource *r = read_font_arg(&ptr); + if (r) { + r->flags |= resource::SUPPLIED; + if (outfp) { + fputs("%%BeginResource: ", outfp); + r->print_type_and_name(outfp); + putc('\n', outfp); + } + } + return 0; +} + +int resource_manager::do_include_font(const char *ptr, int rank, FILE *, + FILE *outfp) +{ + resource *r = read_font_arg(&ptr); + if (r) { + if (rank >= 0) + supply_resource(r, rank + 1, outfp); + else + r->flags |= resource::FONT_NEEDED; + } + return 0; +} + +int resource_manager::change_to_end_resource(const char *, int, FILE *, + FILE *outfp) +{ + if (outfp) + fputs("%%EndResource\n", outfp); + return 0; +} + +int resource_manager::do_begin_preview(const char *, int, FILE *fp, FILE *) +{ + char buf[PS_LINE_MAX + 2]; + do { + if (!ps_get_line(buf, fp)) { + error("end of file in preview section"); + break; + } + } while (!matches_comment(buf, "EndPreview")); + return 0; +} + +int read_one_of(const char **ptr, const char **s, int n) +{ + while (white_space(**ptr)) + *ptr += 1; + if (**ptr == '\0') + return -1; + const char *start = *ptr; + do { + ++ptr; + } while (**ptr != '\0' && !white_space(**ptr)); + for (int i = 0; i < n; i++) + if (strlen(s[i]) == *ptr - start + && memcmp(s[i], start, *ptr - start) == 0) + return i; + return -1; +} + +int resource_manager::do_begin_data(const char *ptr, int, FILE *fp, + FILE *outfp) +{ + while (white_space(*ptr)) + ptr++; + const char *start = ptr; + unsigned numberof; + if (!read_uint_arg(&ptr, &numberof)) + return 0; + static const char *types[] = { "Binary", "Hex", "ASCII" }; + const int Binary = 0; + int type = 0; + static const char *units[] = { "Bytes", "Lines" }; + const int Bytes = 0; + int unit = Bytes; + while (white_space(*ptr)) + ptr++; + if (*ptr != '\0') { + type = read_one_of(&ptr, types, 3); + if (type < 0) { + error("bad data type"); + return 0; + } + while (white_space(*ptr)) + ptr++; + if (*ptr != '\0') { + unit = read_one_of(&ptr, units, 2); + if (unit < 0) { + error("expected `Bytes' or `Lines'"); + return 0; + } + } + } + if (type != Binary) + return 1; + if (outfp) { + fputs("%%BeginData: ", outfp); + fputs(start, outfp); + } + if (numberof > 0) { + unsigned bytecount = 0; + unsigned linecount = 0; + do { + int c = getc(fp); + if (c == EOF) { + error("end of file within data section"); + return 0; + } + if (outfp) + putc(c, outfp); + bytecount++; + if (c == '\r') { + int cc = getc(fp); + if (cc != '\n') { + linecount++; + current_lineno++; + } + if (cc != EOF) + ungetc(c, fp); + } + else if (c == '\n') { + linecount++; + current_lineno++; + } + } while ((unit == Bytes ? bytecount : linecount) < numberof); + } + char buf[PS_LINE_MAX + 2]; + if (!ps_get_line(buf, fp)) { + error("missing %%%%EndData line"); + return 0; + } + if (!matches_comment(buf, "EndData")) + error("bad %%%%EndData line"); + if (outfp) + fputs(buf, outfp); + return 0; +} + +int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp, + FILE *outfp) +{ + if (!outfp) + return 0; + unsigned count; + if (!read_uint_arg(&ptr, &count)) + return 0; + if (outfp) + fprintf(outfp, "%%%%BeginData: %u Binary Bytes\n", count); + while (count != 0) { + int c = getc(fp); + if (c == EOF) { + error("end of file within binary section"); + return 0; + } + if (outfp) + putc(c, outfp); + --count; + if (c == '\r') { + int cc = getc(fp); + if (cc != '\n') + current_lineno++; + if (cc != EOF) + ungetc(c, fp); + } + else if (c == '\n') + current_lineno++; + } + char buf[PS_LINE_MAX + 2]; + if (!ps_get_line(buf, fp)) { + error("missing %%%%EndBinary line"); + return 0; + } + if (!matches_comment(buf, "EndBinary")) { + error("bad %%%%EndBinary line"); + if (outfp) + fputs(buf, outfp); + } + else if (outfp) + fputs("%%EndData\n", outfp); + return 0; +} + +static unsigned parse_extensions(const char *ptr) +{ + unsigned flags = 0; + for (;;) { + while (white_space(*ptr)) + ptr++; + if (*ptr == '\0') + break; + const char *name = ptr; + do { + ++ptr; + } while (*ptr != '\0' && !white_space(*ptr)); + for (int i = 0; i < NEXTENSIONS; i++) + if (strlen(extension_table[i]) == ptr - name + && memcmp(extension_table[i], name, ptr - name) == 0) { + flags |= (1 << i); + break; + } + if (i >= NEXTENSIONS) { + string s(name, ptr - name); + s += '\0'; + error("unknown extension `%1'", s.contents()); + } + } + return flags; +} + +// XXX if it has not been surrounded with {Begin,End}Document need to strip +// out Page: Trailer {Begin,End}Prolog {Begin,End}Setup sections. + +// XXX Perhaps the decision whether to use BeginDocument or +// BeginResource: file should be postponed till we have seen +// the first line of the file. + +void resource_manager::process_file(int rank, FILE *fp, const char *filename, + FILE *outfp) +{ + // If none of these comments appear in the header section, and we are + // just analyzing the file (ie outfp is 0), then we can return immediately. + static const char *header_comment_table[] = { + "DocumentNeededResources:", + "DocumentSuppliedResources:", + "DocumentNeededFonts:", + "DocumentSuppliedFonts:", + "DocumentNeededProcSets:", + "DocumentSuppliedProcSets:", + "DocumentNeededFiles:", + "DocumentSuppliedFiles:", + }; + + const int NHEADER_COMMENTS = (sizeof(header_comment_table) + / sizeof(header_comment_table[0])); + struct comment_info { + const char *name; + int (resource_manager::*proc)(const char *, int, FILE *, FILE *); + }; + + static comment_info comment_table[] = { + "BeginResource:", &resource_manager::do_begin_resource, + "IncludeResource:", &resource_manager::do_include_resource, + "BeginDocument:", &resource_manager::do_begin_document, + "IncludeDocument:", &resource_manager::do_include_document, + "BeginProcSet:", &resource_manager::do_begin_procset, + "IncludeProcSet:", &resource_manager::do_include_procset, + "BeginFont:", &resource_manager::do_begin_font, + "IncludeFont:", &resource_manager::do_include_font, + "BeginFile:", &resource_manager::do_begin_file, + "IncludeFile:", &resource_manager::do_include_file, + "EndProcSet", &resource_manager::change_to_end_resource, + "EndFont", &resource_manager::change_to_end_resource, + "EndFile", &resource_manager::change_to_end_resource, + "BeginPreview:", &resource_manager::do_begin_preview, + "BeginData:", &resource_manager::do_begin_data, + "BeginBinary:", &resource_manager::do_begin_binary, + }; + + const int NCOMMENTS = sizeof(comment_table)/sizeof(comment_table[0]); + char buf[PS_LINE_MAX + 2]; + int saved_lineno = current_lineno; + const char *saved_filename = current_filename; + current_filename = filename; + current_lineno = 0; + if (!ps_get_line(buf, fp)) { + current_filename = saved_filename; + current_lineno = saved_lineno; + return; + } + if (strlen(buf) < sizeof(PS_MAGIC) - 1 + || memcmp(buf, PS_MAGIC, sizeof(PS_MAGIC) - 1) != 0) { + if (outfp) { + do { + if (!(broken_flags & STRIP_PERCENT_BANG) + || buf[0] != '%' || buf[1] != '!') + fputs(buf, outfp); + } while (ps_get_line(buf, fp)); + } + } + else { + if (!(broken_flags & STRIP_PERCENT_BANG) && outfp) + fputs(buf, outfp); + int in_header = 1; + int interesting = 0; + int had_extensions_comment = 0; + int had_language_level_comment = 0; + for (;;) { + if (!ps_get_line(buf, fp)) + break; + int copy_this_line = 1; + if (buf[0] == '%') { + if (buf[1] == '%') { + const char *ptr; + for (int i = 0; i < NCOMMENTS; i++) + if (ptr = matches_comment(buf, comment_table[i].name)) { + copy_this_line + = (this->*(comment_table[i].proc))(ptr, rank, fp, outfp); + break; + } + if (i >= NCOMMENTS && in_header) { + if (ptr = matches_comment(buf, "EndComments")) + in_header = 0; + else if (!had_extensions_comment + && (ptr = matches_comment(buf, "Extensions:"))) { + extensions |= parse_extensions(ptr); + // XXX handle possibility that next line is %%+ + had_extensions_comment = 1; + } + else if (!had_language_level_comment + && (ptr = matches_comment(buf, "LanguageLevel:"))) { + unsigned ll; + if (read_uint_arg(&ptr, &ll) && ll > language_level) + language_level = ll; + had_language_level_comment = 1; + } + else { + for (int i = 0; i < NHEADER_COMMENTS; i++) + if (matches_comment(buf, header_comment_table[i])) { + interesting = 1; + break; + } + } + } + if ((broken_flags & STRIP_STRUCTURE_COMMENTS) + && (matches_comment(buf, "EndProlog") + || matches_comment(buf, "Page:") + || matches_comment(buf, "Trailer"))) + copy_this_line = 0; + } + else if (buf[1] == '!') { + if (broken_flags & STRIP_PERCENT_BANG) + copy_this_line = 0; + } + } + else + in_header = 0; + if (!outfp && !in_header && !interesting) + break; + if (copy_this_line && outfp) + fputs(buf, outfp); + } + } + current_filename = saved_filename; + current_lineno = saved_lineno; +} + +void resource_manager::read_download_file() +{ + char *path = 0; + FILE *fp = font::open_file("download", &path); + if (!fp) + fatal("can't find `download'"); + char buf[512]; + int lineno = 0; + while (fgets(buf, sizeof(buf), fp)) { + lineno++; + char *p = strtok(buf, " \t\r\n"); + if (p == 0 || *p == '#') + continue; + char *q = strtok(0, " \t\r\n"); + if (!q) + fatal_with_file_and_line(path, lineno, "missing filename"); + lookup_font(p)->filename = strsave(q); + } + a_delete path; + fclose(fp); +} + +// XXX Can we share some code with ps_output::put_string()? + +static void print_ps_string(const string &s, FILE *outfp) +{ + int len = s.length(); + const char *str = s.contents(); + int funny = 0; + if (str[0] == '(') + funny = 1; + else { + for (int i = 0; i < len; i++) + if (str[i] <= 040 || str[i] > 0176) { + funny = 1; + break; + } + } + if (!funny) { + put_string(s, outfp); + return; + } + int level = 0; + for (int i = 0; i < len; i++) + if (str[i] == '(') + level++; + else if (str[i] == ')' && --level < 0) + break; + putc('(', outfp); + for (i = 0; i < len; i++) + switch (str[i]) { + case '(': + case ')': + if (level != 0) + putc('\\', outfp); + putc(str[i], outfp); + break; + case '\\': + fputs("\\\\", outfp); + break; + case '\n': + fputs("\\n", outfp); + break; + case '\r': + fputs("\\r", outfp); + break; + case '\t': + fputs("\\t", outfp); + break; + case '\b': + fputs("\\b", outfp); + break; + case '\f': + fputs("\\f", outfp); + break; + default: + if (str[i] < 040 || str[i] > 0176) + fprintf(outfp, "\\%03o", str[i] & 0377); + else + putc(str[i], outfp); + break; + } + putc(')', outfp); +} + +void resource_manager::print_extensions_comment(FILE *outfp) +{ + if (extensions) { + fputs("%%Extensions:", outfp); + for (int i = 0; i < NEXTENSIONS; i++) + if (extensions & (1 << i)) { + putc(' ', outfp); + fputs(extension_table[i], outfp); + } + putc('\n', outfp); + } +} + +void resource_manager::print_language_level_comment(FILE *outfp) +{ + if (language_level) + fprintf(outfp, "%%%%LanguageLevel: %u\n", language_level); +} + diff --git a/gnu/usr.bin/groff/grotty/Makefile b/gnu/usr.bin/groff/grotty/Makefile new file mode 100644 index 0000000000..359112aafe --- /dev/null +++ b/gnu/usr.bin/groff/grotty/Makefile @@ -0,0 +1,12 @@ +# Makefile for grotty + +PROG= grotty +SRCS= tty.cc +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBDRIVER) $(LIBGROFF) -lm +DPADD+= $(LIBDRIVER) $(LIBGROFF) $(LIBMATH) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/grotty/Makefile.dep b/gnu/usr.bin/groff/grotty/Makefile.dep new file mode 100644 index 0000000000..eca128ef1c --- /dev/null +++ b/gnu/usr.bin/groff/grotty/Makefile.dep @@ -0,0 +1,2 @@ +tty.o : tty.cc ../include/driver.h ../include/errarg.h ../include/error.h \ + ../include/font.h ../include/printer.h ../include/lib.h diff --git a/gnu/usr.bin/groff/grotty/TODO b/gnu/usr.bin/groff/grotty/TODO new file mode 100644 index 0000000000..3f23dc35d5 --- /dev/null +++ b/gnu/usr.bin/groff/grotty/TODO @@ -0,0 +1,3 @@ +Document font and device description file usage of grotty. + +With -h avoid using a tab when a single space will do. diff --git a/gnu/usr.bin/groff/grotty/grotty.1 b/gnu/usr.bin/groff/grotty/grotty.1 new file mode 100644 index 0000000000..d425655485 --- /dev/null +++ b/gnu/usr.bin/groff/grotty/grotty.1 @@ -0,0 +1,204 @@ +.\" -*- nroff -*- +.TH GROTTY 1 "11 August 1992" "Groff Version 1.08" +.SH NAME +grotty \- groff driver for typewriter-like devices +.SH SYNOPSIS +.B grotty +[ +.B \-hfbuodBUv +] [ +.BI \-F dir +] [ +.IR files \|.\|.\|. +] +.SH DESCRIPTION +.B grotty +translates the output of GNU +.B troff +into a form suitable for typewriter-like devices. +Normally +.B grotty +should invoked by using the +.B groff +command +with a +.B \-Tascii +or +.B \-Tlatin1 +option. +If no files are given, +.B grotty +will read the standard input. +A filename of +.B \- +will also cause +.B grotty +to read the standard input. +Output is written to the standard output. +.LP +Normally +.B grotty +prints a bold character +.I c +using the sequence +.RI ` c +.SM BACKSPACE +.IR c ' +and a italic character +.I c +by the sequence +.RB ` _ +.SM BACKSPACE +.IR c '. +These sequences can be displayed on a terminal +by piping through +.BR ul (1). +Pagers such as +.BR more (1) +or +.BR less (1) +are also able to display these sequences. +Use either +.B \-B +or +.B \-U +when piping into +.BR less (1); +use +.B \-b +when piping into +.BR more (1). +There is no need to filter the output through +.BR col (1) +since +.B grotty +never outputs reverse line feeds. +.LP +The font description file may contain a command +.IP +.BI internalname\ n +.LP +where +.I n +is a decimal integer. +If the 01 bit in +.I n +is set, +then the font will be treated as an italic font; +if the 02 bit is set, +then it will be treated as a bold font. +The code field in the font description field gives the +code which will be used to output the character. +This code can also be used in the +.B \eN +escape sequence in +.BR troff . +.SH OPTIONS +.TP +.BI \-F dir +Search the directory +.IB dir /dev name +for font and device description files; +.I name +is the name of the device, usually +.B ascii +or +.BR latin1 . +.TP +.B \-h +Use horizontal tabs in the output. +Tabs are assumed to be set every 8 columns. +.TP +.B \-f +Use form feeds in the output. +A form feed will be output at the end of each page that has no output +on its last line. +.TP +.B \-b +Suppress the use of overstriking for bold characters. +.TP +.B \-u +Suppress the use of underlining for italic characters. +.TP +.B \-B +Use only overstriking for bold-italic characters. +.TP +.B \-U +Use only underlining for bold-italic characters. +.TP +.B \-o +Suppress overstriking (other than for bold or underlined characters). +.TP +.B \-d +Ignore all +.B \eD +commands. +Without this +.B grotty +will render +.B \eD'l\|.\|.\|.' +commands that have at least at least one zero argument +(and so are either horizontal or vertical) +using +.BR \- , +.B | +and +.B + +characters. +.TP +.B \-v +Print the version number. +.SH FILES +.TP +.B /usr/share/groff_font/devascii/DESC +Device desciption file for +.B ascii +device. +.TP +.B /usr/share/groff_font/devascii/ F +Font description file for font +.I F +of +.B ascii device. +.TP +.B /usr/share/groff_font/devlatin1/DESC +Device desciption file for +.B latin1 +device. +.TP +.B /usr/share/groff_font/devlatin1/ F +Font description file for font +.I F +of +.B latin1 device. +.TP +.B /usr/share/tmac/tmac.tty +Macros for use with +.BR grotty . +.TP +.B /usr/share/tmac/tmac.tty-char +Additional klugey character definitions for use with +.BR grotty . +.SH BUGS +.LP +.B grotty +is intended only for simple documents. +.LP +There is no support for fractional horizontal or vertical motions. +.LP +There is no support for +.B \eD +commands +other than horizontal and vertical lines. +.LP +Characters above the first line (ie with a vertical position of 0) +cannot be printed. +.SH "SEE ALSO" +.BR groff (1), +.BR troff (1), +.BR groff_out (5), +.BR groff_font (5), +.BR groff_char (7), +.BR ul (1), +.BR more (1), +.BR less (1) diff --git a/gnu/usr.bin/groff/grotty/tty.cc b/gnu/usr.bin/groff/grotty/tty.cc new file mode 100644 index 0000000000..b447599349 --- /dev/null +++ b/gnu/usr.bin/groff/grotty/tty.cc @@ -0,0 +1,439 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "driver.h" + +#ifndef USHRT_MAX +#define USHRT_MAX 65535 +#endif + +#define TAB_WIDTH 8 + +static int horizontal_tab_flag = 0; +static int form_feed_flag = 0; +static int bold_flag = 1; +static int underline_flag = 1; +static int overstrike_flag = 1; +static int draw_flag = 1; + +enum { + UNDERLINE_MODE = 01, + BOLD_MODE = 02, + VDRAW_MODE = 04, + HDRAW_MODE = 010 +}; + +// Mode to use for bold-underlining. +static unsigned char bold_underline_mode = BOLD_MODE|UNDERLINE_MODE; + +class tty_font : public font { + tty_font(const char *); + unsigned char mode; +public: + ~tty_font(); + unsigned char get_mode() { return mode; } +#if 0 + void handle_x_command(int argc, const char **argv); +#endif + static tty_font *load_tty_font(const char *); +}; + +tty_font *tty_font::load_tty_font(const char *s) +{ + tty_font *f = new tty_font(s); + if (!f->load()) { + delete f; + return 0; + } + const char *num = f->get_internal_name(); + long n; + if (num != 0 && (n = strtol(num, 0, 0)) != 0) + f->mode = int(n & (BOLD_MODE|UNDERLINE_MODE)); + if (!underline_flag) + f->mode &= ~UNDERLINE_MODE; + if (!bold_flag) + f->mode &= ~BOLD_MODE; + if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE)) + f->mode = (f->mode & ~(BOLD_MODE|UNDERLINE_MODE)) | bold_underline_mode; + return f; +} + +tty_font::tty_font(const char *nm) +: font(nm), mode(0) +{ +} + +tty_font::~tty_font() +{ +} + +#if 0 +void tty_font::handle_x_command(int argc, const char **argv) +{ + if (argc >= 1 && strcmp(argv[0], "bold") == 0) + mode |= BOLD_MODE; + else if (argc >= 1 && strcmp(argv[0], "underline") == 0) + mode |= UNDERLINE_MODE; +} +#endif + +class glyph { + static glyph *free_list; +public: + glyph *next; + unsigned short hpos; + unsigned char code; + unsigned char mode; + void *operator new(size_t); + void operator delete(void *); + inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); } +}; + +glyph *glyph::free_list = 0; + +void *glyph::operator new(size_t) +{ + if (!free_list) { + const int BLOCK = 1024; + free_list = (glyph *)new char[sizeof(glyph)*BLOCK]; + for (int i = 0; i < BLOCK - 1; i++) + free_list[i].next = free_list + i + 1; + free_list[BLOCK - 1].next = 0; + } + glyph *p = free_list; + free_list = free_list->next; + p->next = 0; + return p; +} + +void glyph::operator delete(void *p) +{ + if (p) { + ((glyph *)p)->next = free_list; + free_list = (glyph *)p; + } +} + +class tty_printer : public printer { + glyph **lines; + int nlines; + int cached_v; + int cached_vpos; + void add_char(unsigned char, int, int, unsigned char); +public: + tty_printer(); + ~tty_printer(); + void set_char(int, font *, const environment *, int); + void draw(int code, int *p, int np, const environment *env); + void begin_page(int) { } + void end_page(int page_length); + font *make_font(const char *); +}; + +tty_printer::tty_printer() : cached_v(0) +{ + nlines = 66; + lines = new glyph *[nlines]; + for (int i = 0; i < nlines; i++) + lines[i] = 0; +} + +tty_printer::~tty_printer() +{ + a_delete lines; +} + +void tty_printer::set_char(int i, font *f, const environment *env, int w) +{ + if (w != font::hor) + fatal("width of character not equal to horizontal resolution"); + add_char(f->get_code(i), env->hpos, env->vpos, ((tty_font *)f)->get_mode()); +} + +void tty_printer::add_char(unsigned char c, int h, int v, unsigned char mode) +{ +#if 0 + // This is too expensive. + if (h % font::hor != 0) + fatal("horizontal position not a multiple of horizontal resolution"); +#endif + int hpos = h / font::hor; + if (hpos < 0) { + error("character to the left of first column discarded"); + return; + } + if (hpos > USHRT_MAX) { + error("character with ridiculously large horizontal position discarded"); + return; + } + int vpos; + if (v == cached_v && cached_v != 0) + vpos = cached_vpos; + else { + if (v % font::vert != 0) + fatal("vertical position not a multiple of vertical resolution"); + vpos = v / font::vert; + if (vpos > nlines) { + glyph **old_lines = lines; + lines = new glyph *[vpos + 1]; + memcpy(lines, old_lines, nlines*sizeof(glyph *)); + for (int i = nlines; i <= vpos; i++) + lines[i] = 0; + a_delete old_lines; + nlines = vpos + 1; + } + // Note that the first output line corresponds to groff + // position font::vert. + if (vpos <= 0) { + error("character above first line discarded"); + return; + } + cached_v = v; + cached_vpos = vpos; + } + glyph *g = new glyph; + g->hpos = hpos; + g->code = c; + g->mode = mode; + + // The list will be reversed later. After reversal, it must be in + // increasing order of hpos, with HDRAW characters before VDRAW + // characters before normal characters at each hpos, and otherwise + // in order of occurrence. + + for (glyph **pp = lines + (vpos - 1); *pp; pp = &(*pp)->next) + if (int((*pp)->hpos) < hpos + || ((*pp)->hpos == hpos && (*pp)->draw_mode() >= g->draw_mode())) + break; + + g->next = *pp; + *pp = g; +} + +void tty_printer::draw(int code, int *p, int np, const environment *env) +{ + if (code != 'l' || !draw_flag) + return; + if (np != 2) { + error("2 arguments required for line"); + return; + } + if (p[0] == 0) { + // vertical line + int v = env->vpos; + int len = p[1]; + if (len < 0) { + v += len; + len = -len; + } + while (len >= 0) { + add_char('|', env->hpos, v, VDRAW_MODE); + len -= font::vert; + v += font::vert; + } + } + if (p[1] == 0) { + // horizontal line + int h = env->hpos; + int len = p[0]; + if (len < 0) { + h += len; + len = -len; + } + while (len >= 0) { + add_char('-', h, env->vpos, HDRAW_MODE); + len -= font::hor; + h += font::hor; + } + } +} + +void tty_printer::end_page(int page_length) +{ + if (page_length % font::vert != 0) + error("vertical position at end of page not multiple of vertical resolution"); + int lines_per_page = page_length / font::vert; + for (int last_line = nlines; last_line > 0; last_line--) + if (lines[last_line - 1]) + break; +#if 0 + if (last_line > lines_per_page) { + error("characters past last line discarded"); + do { + --last_line; + while (lines[last_line]) { + glyph *tem = lines[last_line]; + lines[last_line] = tem->next; + delete tem; + } + } while (last_line > lines_per_page); + } +#endif + for (int i = 0; i < last_line; i++) { + glyph *p = lines[i]; + lines[i] = 0; + glyph *g = 0; + while (p) { + glyph *tem = p->next; + p->next = g; + g = p; + p = tem; + } + int hpos = 0; + + glyph *nextp; + for (p = g; p; delete p, p = nextp) { + nextp = p->next; + if (nextp && p->hpos == nextp->hpos) { + if (p->draw_mode() == HDRAW_MODE && nextp->draw_mode() == VDRAW_MODE) { + nextp->code = '+'; + continue; + } + if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) { + nextp->code = p->code; + continue; + } + if (!overstrike_flag) + continue; + } + if (hpos > int(p->hpos)) { + putchar('\b'); + hpos--; + } + else { + if (horizontal_tab_flag) { + for (;;) { + int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH; + if (next_tab_pos > int(p->hpos)) + break; + putchar('\t'); + hpos = next_tab_pos; + } + } + for (; hpos < int(p->hpos); hpos++) + putchar(' '); + } + assert(hpos == p->hpos); + if (p->mode & UNDERLINE_MODE) { + putchar('_'); + putchar('\b'); + } + if (p->mode & BOLD_MODE) { + putchar(p->code); + putchar('\b'); + } + putchar(p->code); + hpos++; + } + putchar('\n'); + } + if (form_feed_flag) { + if (last_line < lines_per_page) + putchar('\f'); + } + else { + for (; last_line < lines_per_page; last_line++) + putchar('\n'); + } +} + +font *tty_printer::make_font(const char *nm) +{ + return tty_font::load_tty_font(nm); +} + +printer *make_printer() +{ + return new tty_printer; +} + +static void usage(); + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int c; + while ((c = getopt(argc, argv, "F:vhfbuoBUd")) != EOF) + switch(c) { + case 'v': + { + extern const char *version_string; + fprintf(stderr, "grotty version %s\n", version_string); + fflush(stderr); + break; + } + case 'b': + // Do not embolden by overstriking. + bold_flag = 0; + break; + case 'u': + // Do not underline. + underline_flag = 0; + break; + case 'o': + // Do not overstrike (other than emboldening and underlining). + overstrike_flag = 0; + break; + case 'B': + // Do bold-underlining as bold. + bold_underline_mode = BOLD_MODE; + break; + case 'U': + // Do bold-underlining as underlining. + bold_underline_mode = UNDERLINE_MODE; + break; + case 'h': + // Use horizontal tabs. + horizontal_tab_flag = 1; + break; + case 'f': + form_feed_flag = 1; + break; + case 'F': + font::command_line_font_dir(optarg); + break; + case 'd': + // Ignore \D commands. + draw_flag = 0; + break; + case '?': + usage(); + break; + default: + assert(0); + } + if (optind >= argc) + do_file("-"); + else { + for (int i = optind; i < argc; i++) + do_file(argv[i]); + } + delete pr; + exit(0); +} + +static void usage() +{ + fprintf(stderr, "usage: %s [-hfvbuodBU] [-F dir] [files ...]\n", + program_name); + exit(1); +} diff --git a/gnu/usr.bin/groff/include/assert.h b/gnu/usr.bin/groff/include/assert.h new file mode 100644 index 0000000000..3963b4fb4b --- /dev/null +++ b/gnu/usr.bin/groff/include/assert.h @@ -0,0 +1,41 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef ASSERT_H +#define ASSERT_H +#ifdef __GNUG__ +volatile +#endif +void assertion_failed(int, const char *); + +inline void do_assert(int expr, int line, const char *file) +{ + if (!expr) + assertion_failed(line, file); +} +#endif /* ASSERT_H */ + +#undef assert + +#ifdef NDEBUG +#define assert(ignore) /* as nothing */ +#else +#define assert(expr) do_assert(expr, __LINE__, __FILE__) +#endif diff --git a/gnu/usr.bin/groff/include/cmap.h b/gnu/usr.bin/groff/include/cmap.h new file mode 100644 index 0000000000..18c88fb262 --- /dev/null +++ b/gnu/usr.bin/groff/include/cmap.h @@ -0,0 +1,56 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef UCHAR_MAX +#define UCHAR_MAX 255 +#endif + +enum cmap_builtin { CMAP_BUILTIN }; + +class cmap { +public: + cmap(); + cmap(cmap_builtin); + int operator()(unsigned char) const; + unsigned char &operator[](unsigned char); + + friend class cmap_init; +private: + unsigned char v[UCHAR_MAX+1]; +}; + +inline int cmap::operator()(unsigned char c) const +{ + return v[c]; +} + +inline unsigned char &cmap::operator[](unsigned char c) +{ + return v[c]; +} + +extern cmap cmlower; +extern cmap cmupper; + +static class cmap_init { + static int initialised; +public: + cmap_init(); +} _cmap_init; diff --git a/gnu/usr.bin/groff/include/cset.h b/gnu/usr.bin/groff/include/cset.h new file mode 100644 index 0000000000..f454cc5114 --- /dev/null +++ b/gnu/usr.bin/groff/include/cset.h @@ -0,0 +1,75 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CC_LIMITS_H +#include +#else /* not HAVE_CC_LIMITS_H */ +#ifndef UCHAR_MAX +#define UCHAR_MAX 255 +#endif +#endif /* not HAVE_CC_LIMITS_H */ + +enum cset_builtin { CSET_BUILTIN }; + +class cset { +public: + cset(); + cset(cset_builtin); + cset(const char *); + cset(const unsigned char *); + int operator()(unsigned char) const; + + cset &operator|=(const cset &); + cset &operator|=(unsigned char); + + friend class cset_init; +private: + char v[UCHAR_MAX+1]; + void clear(); +}; + +inline int cset::operator()(unsigned char c) const +{ + return v[c]; +} + +inline cset &cset::operator|=(unsigned char c) +{ + v[c] = 1; + return *this; +} + +extern cset csalpha; +extern cset csupper; +extern cset cslower; +extern cset csdigit; +extern cset csxdigit; +extern cset csspace; +extern cset cspunct; +extern cset csalnum; +extern cset csprint; +extern cset csgraph; +extern cset cscntrl; + +static class cset_init { + static int initialised; +public: + cset_init(); +} _cset_init; diff --git a/gnu/usr.bin/groff/include/defs.h b/gnu/usr.bin/groff/include/defs.h new file mode 100644 index 0000000000..df2efba57e --- /dev/null +++ b/gnu/usr.bin/groff/include/defs.h @@ -0,0 +1,9 @@ +#define PROG_PREFIX "" +#define DEVICE "ps" +#define FONTPATH "/usr/share/groff_font" +#define MACROPATH "/usr/share/tmac" +#define INDEX_SUFFIX ".i" +#define COMMON_WORDS_FILE "/usr/share/dict/eign" +#define DEFAULT_INDEX_DIR "/usr/share/dict/papers" +#define DEFAULT_INDEX_NAME "Ind" +#define DEFAULT_INDEX "/usr/share/dict/papers/Ind" diff --git a/gnu/usr.bin/groff/include/device.h b/gnu/usr.bin/groff/include/device.h new file mode 100644 index 0000000000..76be133417 --- /dev/null +++ b/gnu/usr.bin/groff/include/device.h @@ -0,0 +1,21 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern const char *device; diff --git a/gnu/usr.bin/groff/include/driver.h b/gnu/usr.bin/groff/include/driver.h new file mode 100644 index 0000000000..be7a6dc6a1 --- /dev/null +++ b/gnu/usr.bin/groff/include/driver.h @@ -0,0 +1,36 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "errarg.h" +#include "error.h" +#include "font.h" +#include "printer.h" +#include "lib.h" + +void do_file(const char *); +extern printer *pr; diff --git a/gnu/usr.bin/groff/include/errarg.h b/gnu/usr.bin/groff/include/errarg.h new file mode 100644 index 0000000000..2f5ea5fc9f --- /dev/null +++ b/gnu/usr.bin/groff/include/errarg.h @@ -0,0 +1,46 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +class errarg { + enum { EMPTY, STRING, CHAR, INTEGER, DOUBLE } type; + union { + const char *s; + int n; + char c; + double d; + }; + public: + errarg(); + errarg(const char *); + errarg(char); + errarg(unsigned char); + errarg(int); + errarg(double); + int empty() const; + void print() const; +}; + +extern errarg empty_errarg; + +extern void errprint(const char *, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + diff --git a/gnu/usr.bin/groff/include/error.h b/gnu/usr.bin/groff/include/error.h new file mode 100644 index 0000000000..7a687127a3 --- /dev/null +++ b/gnu/usr.bin/groff/include/error.h @@ -0,0 +1,58 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern void fatal_with_file_and_line(const char *filename, int lineno, + const char *format, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +extern void error_with_file_and_line(const char *filename, int lineno, + const char *format, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +extern void warning_with_file_and_line(const char *filename, int lineno, + const char *format, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +extern void fatal(const char *, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +extern void error(const char *, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +extern void warning(const char *, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + + +extern const char *program_name; +extern int current_lineno; +extern const char *current_filename; + diff --git a/gnu/usr.bin/groff/include/font.h b/gnu/usr.bin/groff/include/font.h new file mode 100644 index 0000000000..6470b65a4c --- /dev/null +++ b/gnu/usr.bin/groff/include/font.h @@ -0,0 +1,113 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +typedef void (*FONT_COMMAND_HANDLER)(const char *, const char *, + const char *, int); + +struct font_kern_list; +struct font_char_metric; +struct font_widths_cache; + +class font { +public: + enum { + LIG_ff = 1, + LIG_fi = 2, + LIG_fl = 4, + LIG_ffi = 8, + LIG_ffl = 16 + }; + + virtual ~font(); + int contains(int index); + int is_special(); + int get_width(int index, int point_size); + int get_height(int index, int point_size); + int get_depth(int index, int point_size); + int get_space_width(int point_size); + int get_character_type(int index); + int get_kern(int index1, int index2, int point_size); + int get_skew(int index, int point_size, int slant); + int has_ligature(int); + int get_italic_correction(int index, int point_size); + int get_left_italic_correction(int index, int point_size); + int get_subscript_correction(int index, int point_size); + int get_code(int i); + const char *get_name(); + const char *get_internal_name(); + + static font *load_font(const char *, int *not_found = 0); + static void command_line_font_dir(const char *path); + static FILE *open_file(const char *name, char **pathp); + static int load_desc(); + static int name_to_index(const char *); + static int number_to_index(int); + static FONT_COMMAND_HANDLER + set_unknown_desc_command_handler(FONT_COMMAND_HANDLER); + + static int res; + static int hor; + static int vert; + static int unitwidth; + static int paperwidth; + static int paperlength; + static int biggestfont; + static int spare2; + static int sizescale; + static int tcommand; + + static const char **font_name_table; + static const char **style_table; + static const char *family; + static int *sizes; +private: + unsigned ligatures; + font_kern_list **kern_hash_table; + int space_width; + short *ch_index; + int nindices; + font_char_metric *ch; + int ch_used; + int ch_size; + int special; + char *name; + char *internalname; + double slant; + font_widths_cache *widths_cache; + static FONT_COMMAND_HANDLER unknown_desc_command_handler; + + enum { KERN_HASH_TABLE_SIZE = 503 }; + + void add_entry(int index, const font_char_metric &); + void copy_entry(int new_index, int old_index); + void add_kern(int index1, int index2, int amount); + static int hash_kern(int i1, int i2); + void alloc_ch_index(int); + void extend_ch(); + void compact(); + + static int scale(int w, int pointsize); + virtual void handle_unknown_font_command(const char *command, + const char *arg, + const char *file, int lineno); +protected: + font(const char *); + int load(int *not_found = 0); +}; diff --git a/gnu/usr.bin/groff/include/index.h b/gnu/usr.bin/groff/include/index.h new file mode 100644 index 0000000000..719b0266b2 --- /dev/null +++ b/gnu/usr.bin/groff/include/index.h @@ -0,0 +1,42 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define INDEX_MAGIC 0x23021964 +#define INDEX_VERSION 1 + +struct index_header { + int magic; + int version; + int tags_size; + int table_size; + int lists_size; + int strings_size; + int truncate; + int shortest; + int common; +}; + +struct tag { + int filename_index; + int start; + int length; +}; + +unsigned hash(const char *s, int len); diff --git a/gnu/usr.bin/groff/include/lib.h b/gnu/usr.bin/groff/include/lib.h new file mode 100644 index 0000000000..2cee567192 --- /dev/null +++ b/gnu/usr.bin/groff/include/lib.h @@ -0,0 +1,105 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { + char *strerror(int); +#ifndef __BORLANDC__ + const char *itoa(int); + const char *iftoa(int, int); +#endif /* __BORLANDC__ */ +}; + +#ifdef STDLIB_H_DECLARES_GETOPT +#include +#else /* not STDLIB_H_DECLARES_GETOPT */ +#ifdef UNISTD_H_DECLARES_GETOPT +#include +#include +#else /* not UNISTD_H_DECLARES_GETOPT */ +extern "C" { + int getopt(int, char **, const char *); +} +#endif /* not UNISTD_H_DECLARES_GETOPT */ + +extern "C" { + extern char *optarg; + extern int optind; + extern int opterr; +} + +#endif /* not STDLIB_H_DECLARES_GETOPT */ + +char *strsave(const char *s); +int is_prime(unsigned); + +#include + +FILE *xtmpfile(); + +int interpret_lf_args(const char *p); + +extern char illegal_char_table[]; + +inline int illegal_input_char(int c) +{ + return c >= 0 && illegal_char_table[c]; +} + +#ifdef HAVE_CC_LIMITS_H +#include +#else /* not HAVE_CC_LIMITS_H */ +#define INT_MAX 2147483647 +#endif /* not HAVE_CC_LIMITS_H */ + +/* It's not safe to rely on people getting INT_MIN right (ie signed). */ + +#ifdef INT_MIN +#undef INT_MIN +#endif + +#ifdef CFRONT_ANSI_BUG + +/* This works around a bug in cfront 2.0 used with ANSI C compilers. */ + +#define INT_MIN ((long)(-INT_MAX-1)) + +#else /* not CFRONT_ANSI_BUG */ + +#define INT_MIN (-INT_MAX-1) + +#endif /* not CFRONT_ANSI_BUG */ + +/* Maximum number of digits in the decimal representation of an int +(not including the -). */ + +#define INT_DIGITS 10 + +/* ad_delete deletes an array of objects with destructors; +a_delete deletes an array of objects without destructors */ + +#ifdef ARRAY_DELETE_NEEDS_SIZE +/* for 2.0 systems */ +#define ad_delete(size) delete [size] +#define a_delete delete +#else /* not ARRAY_DELETE_NEEDS_SIZE */ +/* for ARM systems */ +#define ad_delete(size) delete [] +#define a_delete delete [] +#endif /* not ARRAY_DELETE_NEEDS_SIZE */ diff --git a/gnu/usr.bin/groff/include/macropath.h b/gnu/usr.bin/groff/include/macropath.h new file mode 100644 index 0000000000..0b0f5c307e --- /dev/null +++ b/gnu/usr.bin/groff/include/macropath.h @@ -0,0 +1,21 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern search_path macro_path; diff --git a/gnu/usr.bin/groff/include/posix.h b/gnu/usr.bin/groff/include/posix.h new file mode 100644 index 0000000000..fc76d90bfb --- /dev/null +++ b/gnu/usr.bin/groff/include/posix.h @@ -0,0 +1,49 @@ +// -*- C++ -*- +/* Copyright (C) 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include + +#ifdef HAVE_CC_UNISTD_H +#include +#else +#include +#endif + +#ifndef S_IRUSR +#define S_IRUSR 0400 +#endif + +#ifndef S_IRGRP +#define S_IRGRP 0040 +#endif + +#ifndef S_IROTH +#define S_IROTH 0004 +#endif + +#ifndef S_ISREG +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif diff --git a/gnu/usr.bin/groff/include/printer.h b/gnu/usr.bin/groff/include/printer.h new file mode 100644 index 0000000000..d517addb72 --- /dev/null +++ b/gnu/usr.bin/groff/include/printer.h @@ -0,0 +1,66 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct environment { + int fontno; + int size; + int hpos; + int vpos; + int height; + int slant; +}; + +struct font; + +struct font_pointer_list { + font *p; + font_pointer_list *next; + + font_pointer_list(font *, font_pointer_list *); +}; + +class printer { +public: + printer(); + virtual ~printer(); + void load_font(int i, const char *name); + void set_ascii_char(unsigned char c, const environment *env, + int *widthp = 0); + void set_special_char(const char *nm, const environment *env, + int *widthp = 0); + void set_numbered_char(int n, const environment *env, int *widthp = 0); + virtual void draw(int code, int *p, int np, const environment *env); + virtual void begin_page(int) = 0; + virtual void end_page(int page_length) = 0; + virtual font *make_font(const char *nm); + virtual void end_of_line(); + virtual void special(char *arg, const environment *env); + static int adjust_arc_center(const int *, double *); +protected: + font_pointer_list *font_list; +private: + font **font_table; + int nfonts; + font *find_font(const char *); + virtual void set_char(int index, font *f, const environment *env, + int w) = 0; +}; + +printer *make_printer(); diff --git a/gnu/usr.bin/groff/include/ptable.h b/gnu/usr.bin/groff/include/ptable.h new file mode 100644 index 0000000000..0e7c1996a8 --- /dev/null +++ b/gnu/usr.bin/groff/include/ptable.h @@ -0,0 +1,166 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include + +#ifdef TRADITIONAL_CPP +#define name2(a,b) a/**/b +#else /* not TRADITIONAL_CPP */ +#define name2(a,b) name2x(a,b) +#define name2x(a,b) a ## b +#endif /* not TRADITIONAL_CPP */ + +#define PTABLE(T) name2(T,_ptable) +#define PASSOC(T) name2(T,_passoc) +#define PTABLE_ITERATOR(T) name2(T,_ptable_iterator) + +extern unsigned next_ptable_size(unsigned); +extern unsigned long hash_string(const char *); + +#define declare_ptable(T) \ + \ +struct PASSOC(T) { \ + char *key; \ + T *val; \ + PASSOC(T)(); \ +}; \ + \ +struct PTABLE(T); \ + \ +class PTABLE_ITERATOR(T) { \ + PTABLE(T) *p; \ + unsigned i; \ +public: \ + PTABLE_ITERATOR(T)(PTABLE(T) *); \ + int next(const char **, T **); \ +}; \ + \ +class PTABLE(T) { \ + PASSOC(T) *v; \ + unsigned size; \ + unsigned used; \ + enum { FULL_NUM = 2, FULL_DEN = 3, INITIAL_SIZE = 17 }; \ +public: \ + PTABLE(T)(); \ + ~PTABLE(T)(); \ + void define(const char *, T *); \ + T *lookup(const char *); \ + friend class PTABLE_ITERATOR(T); \ +}; + + +#define implement_ptable(T) \ + \ +PASSOC(T)::PASSOC(T)() \ +: key(0), val(0) \ +{ \ +} \ + \ +PTABLE(T)::PTABLE(T)() \ +{ \ + v = new PASSOC(T)[size = INITIAL_SIZE]; \ + used = 0; \ +} \ + \ +PTABLE(T)::~PTABLE(T)() \ +{ \ + for (unsigned i = 0; i < size; i++) { \ + a_delete v[i].key; \ + delete v[i].val; \ + } \ + a_delete v; \ +} \ + \ +void PTABLE(T)::define(const char *key, T *val) \ +{ \ + assert(key != 0); \ + unsigned long h = hash_string(key); \ + for (unsigned n = unsigned(h % size); \ + v[n].key != 0; \ + n = (n == 0 ? size - 1 : n - 1)) \ + if (strcmp(v[n].key, key) == 0) { \ + delete v[n].val; \ + v[n].val = val; \ + return; \ + } \ + if (val == 0) \ + return; \ + if (used*FULL_DEN >= size*FULL_NUM) { \ + PASSOC(T) *oldv = v; \ + unsigned old_size = size; \ + size = next_ptable_size(size); \ + v = new PASSOC(T)[size]; \ + for (unsigned i = 0; i < old_size; i++) \ + if (oldv[i].key != 0) { \ + if (oldv[i].val == 0) \ + a_delete oldv[i].key; \ + else { \ + for (unsigned j = unsigned(hash_string(oldv[i].key) % size); \ + v[j].key != 0; \ + j = (j == 0 ? size - 1 : j - 1)) \ + ; \ + v[j].key = oldv[i].key; \ + v[j].val = oldv[i].val; \ + } \ + } \ + for (n = unsigned(h % size); \ + v[n].key != 0; \ + n = (n == 0 ? size - 1 : n - 1)) \ + ; \ + a_delete oldv; \ + } \ + char *temp = new char[strlen(key)+1]; \ + strcpy(temp, key); \ + v[n].key = temp; \ + v[n].val = val; \ + used++; \ +} \ + \ +T *PTABLE(T)::lookup(const char *key) \ +{ \ + assert(key != 0); \ + for (unsigned n = unsigned(hash_string(key) % size); \ + v[n].key != 0; \ + n = (n == 0 ? size - 1 : n - 1)) \ + if (strcmp(v[n].key, key) == 0) \ + return v[n].val; \ + return 0; \ +} \ + \ +PTABLE_ITERATOR(T)::PTABLE_ITERATOR(T)(PTABLE(T) *t) \ +: p(t), i(0) \ +{ \ +} \ + \ +int PTABLE_ITERATOR(T)::next(const char **keyp, T **valp) \ +{ \ + unsigned size = p->size; \ + PASSOC(T) *v = p->v; \ + for (; i < size; i++) \ + if (v[i].key != 0) { \ + *keyp = v[i].key; \ + *valp = v[i].val; \ + i++; \ + return 1; \ + } \ + return 0; \ +} + diff --git a/gnu/usr.bin/groff/include/refid.h b/gnu/usr.bin/groff/include/refid.h new file mode 100644 index 0000000000..a0e86a31f8 --- /dev/null +++ b/gnu/usr.bin/groff/include/refid.h @@ -0,0 +1,35 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +class reference_id { + int filename_id; + int pos; +public: + reference_id() : filename_id(-1) { } + reference_id(int fid, int off) : filename_id(fid), pos(off) { } + unsigned hash() const { return (filename_id << 4) + pos; } + int is_null() const { return filename_id < 0; } + friend inline int operator==(const reference_id &, const reference_id &); +}; + +inline int operator==(const reference_id &r1, const reference_id &r2) +{ + return r1.filename_id == r2.filename_id && r1.pos == r2.pos; +} diff --git a/gnu/usr.bin/groff/include/search.h b/gnu/usr.bin/groff/include/search.h new file mode 100644 index 0000000000..e1fdb84530 --- /dev/null +++ b/gnu/usr.bin/groff/include/search.h @@ -0,0 +1,96 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct search_item; +struct search_item_iterator; + +class search_list { +public: + search_list(); + ~search_list(); + void add_file(const char *fn, int silent = 0); + int nfiles() const; +private: + search_item *list; + int niterators; + int next_fid; + friend class search_list_iterator; +}; + +struct bmpattern; + +class linear_searcher { + const char *ignore_fields; + int truncate_len; + bmpattern **keys; + int nkeys; + const char *search_and_check(const bmpattern *key, const char *buf, + const char *bufend, const char **start = 0) + const; + int check_match(const char *buf, const char *bufend, const char *match, + int matchlen, const char **cont, const char **start) + const; +public: + linear_searcher(const char *query, int query_len, + const char *ign, int trunc); + ~linear_searcher(); + int search(const char *buf, const char *bufend, + const char **startp, int *lengthp) const; +}; + +class search_list_iterator { + search_list *list; + search_item *ptr; + search_item_iterator *iter; + char *query; + linear_searcher searcher; +public: + search_list_iterator(search_list *, const char *query); + ~search_list_iterator(); + int next(const char **, int *, reference_id * = 0); +}; + +class search_item { +protected: + char *name; + int filename_id; +public: + search_item *next; + search_item(const char *nm, int fid); + virtual search_item_iterator *make_search_item_iterator(const char *) = 0; + virtual ~search_item(); + int is_named(const char *) const; + virtual int next_filename_id() const; +}; + +class search_item_iterator { + char shut_g_plus_plus_up; +public: + virtual ~search_item_iterator(); + virtual int next(const linear_searcher &, const char **ptr, int *lenp, + reference_id *) = 0; +}; + +search_item *make_index_search_item(const char *filename, int fid); +search_item *make_linear_search_item(int fd, const char *filename, int fid); + +extern int linear_truncate_len; +extern const char *linear_ignore_fields; +extern int verify_flag; diff --git a/gnu/usr.bin/groff/include/searchpath.h b/gnu/usr.bin/groff/include/searchpath.h new file mode 100644 index 0000000000..14a74f672d --- /dev/null +++ b/gnu/usr.bin/groff/include/searchpath.h @@ -0,0 +1,29 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +class search_path { + char *dirs; + unsigned init_len; +public: + search_path(const char *envvar, const char *standard); + ~search_path(); + void command_line_dir(const char *); + FILE *open_file(const char *, char **); +}; diff --git a/gnu/usr.bin/groff/include/stringclass.h b/gnu/usr.bin/groff/include/stringclass.h new file mode 100644 index 0000000000..570f47ac71 --- /dev/null +++ b/gnu/usr.bin/groff/include/stringclass.h @@ -0,0 +1,174 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include + +class string { +public: + string(); + string(const string &); + string(const char *); + string(const char *, int); + string(char); + + ~string(); + + string &operator=(const string &); + string &operator=(const char *); + string &operator=(char); + + string &operator+=(const string &); + string &operator+=(const char *); + string &operator+=(char); + void append(const char *, int); + + int length() const; + int empty() const; + int operator*() const; + + string substring(int i, int n) const; + + char &operator[](int); + char operator[](int) const; + + void set_length(int i); + const char *contents() const; + int search(char) const; + char *extract() const; + void clear(); + void move(string &); + + friend inline string operator+(const string &, const string &); + friend inline string operator+(const string &, const char *); + friend inline string operator+(const char *, const string &); + friend inline string operator+(const string &, char); + friend inline string operator+(char, const string &); + + friend inline int operator==(const string &, const string &); + friend inline int operator!=(const string &, const string &); + friend int operator<=(const string &, const string &); + friend int operator<(const string &, const string &); + friend int operator>=(const string &, const string &); + friend int operator>(const string &, const string &); + +private: + char *ptr; + int len; + int sz; + + string(const char *, int, const char *, int); // for use by operator+ + void grow1(); +}; + + +inline char &string::operator[](int i) +{ + assert(i >= 0 && i < len); + return ptr[i]; +} + +inline char string::operator[](int i) const +{ + assert(i >= 0 && i < len); + return ptr[i]; +} + +inline int string::length() const +{ + return len; +} + +inline int string::empty() const +{ + return len == 0; +} + +inline int string::operator*() const +{ + return len; +} + +inline const char *string::contents() const +{ + return ptr; +} + +inline string operator+(const string &s1, const string &s2) +{ + return string(s1.ptr, s1.len, s2.ptr, s2.len); +} + +inline string operator+(const string &s1, const char *s2) +{ + if (s2 == 0) + return s1; + else + return string(s1.ptr, s1.len, s2, strlen(s2)); +} + +inline string operator+(const char *s1, const string &s2) +{ + if (s1 == 0) + return s2; + else + return string(s1, strlen(s1), s2.ptr, s2.len); +} + +inline string operator+(const string &s, char c) +{ + return string(s.ptr, s.len, &c, 1); +} + +inline string operator+(char c, const string &s) +{ + return string(&c, 1, s.ptr, s.len); +} + +inline int operator==(const string &s1, const string &s2) +{ + return (s1.len == s2.len + && (s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) == 0)); +} + +inline int operator!=(const string &s1, const string &s2) +{ + return (s1.len != s2.len + || (s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) != 0)); +} + +inline string string::substring(int i, int n) const +{ + assert(i >= 0 && i + n <= len); + return string(ptr + i, n); +} + +inline string &string::operator+=(char c) +{ + if (len >= sz) + grow1(); + ptr[len++] = c; + return *this; +} + +void put_string(const string &, FILE *); + +string as_string(int); diff --git a/gnu/usr.bin/groff/include/unix.h b/gnu/usr.bin/groff/include/unix.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gnu/usr.bin/groff/indxbib/Makefile b/gnu/usr.bin/groff/indxbib/Makefile new file mode 100644 index 0000000000..ccf17ea698 --- /dev/null +++ b/gnu/usr.bin/groff/indxbib/Makefile @@ -0,0 +1,20 @@ +# Makefile for indxbib + +PROG= indxbib +SRCS= indxbib.cc dirnamemax.c signal.c +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBBIB) $(LIBGROFF) -lm +DPADD+= $(LIBBIB) $(LIBGROFF) $(LIBMATH) + +# Ugh - I can't grab /usr/share from ../../../share/Makefile.inc +# since I've already grabbed a BINDIR file for installing indxbib. +# Sigh... Hardcode it. - jkh +# +afterinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/eign \ + /usr/share/${common_words_file} + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/indxbib/Makefile.dep b/gnu/usr.bin/groff/indxbib/Makefile.dep new file mode 100644 index 0000000000..0b1d969024 --- /dev/null +++ b/gnu/usr.bin/groff/indxbib/Makefile.dep @@ -0,0 +1,5 @@ +indxbib.o : indxbib.cc ../include/posix.h ../include/lib.h \ + ../include/errarg.h ../include/error.h ../include/stringclass.h \ + ../include/cset.h ../include/cmap.h ../include/defs.h ../include/index.h +dirnamemax.o : dirnamemax.c +signal.o : signal.c diff --git a/gnu/usr.bin/groff/indxbib/dirnamemax.c b/gnu/usr.bin/groff/indxbib/dirnamemax.c new file mode 100644 index 0000000000..c3b427e47e --- /dev/null +++ b/gnu/usr.bin/groff/indxbib/dirnamemax.c @@ -0,0 +1,49 @@ +/* dir_name_max(dir) does the same as pathconf(dir, _PC_NAME_MAX) */ + +#include + +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + +#if defined(_POSIX_VERSION) && !defined(__386BSD__) + +long dir_name_max(dir) + char *dir; +{ + return pathconf(dir, _PC_NAME_MAX); +} + +#else /* not _POSIX_VERSION */ + +#ifdef HAVE_LIMITS_H +#include +#endif /* HAVE_LIMITS_H */ + +#ifdef HAVE_DIRENT_H +#include +#else /* not HAVE_DIRENT_H */ +#ifdef HAVE_SYS_DIR_H +#include +#endif /* HAVE_SYS_DIR_H */ +#endif /* not HAVE_DIRENT_H */ + +#ifndef NAME_MAX +#ifdef MAXNAMLEN +#define NAME_MAX MAXNAMLEN +#else /* !MAXNAMLEN */ +#ifdef MAXNAMELEN +#define NAME_MAX MAXNAMELEN +#else /* !MAXNAMELEN */ +#define NAME_MAX 14 +#endif /* !MAXNAMELEN */ +#endif /* !MAXNAMLEN */ +#endif /* !NAME_MAX */ + +long dir_name_max(dir) + char *dir; +{ + return NAME_MAX; +} + +#endif /* not _POSIX_VERSION */ diff --git a/gnu/usr.bin/groff/indxbib/eign b/gnu/usr.bin/groff/indxbib/eign new file mode 100644 index 0000000000..7718c8b112 --- /dev/null +++ b/gnu/usr.bin/groff/indxbib/eign @@ -0,0 +1,133 @@ +a +i +the +to +of +and +in +is +it +for +that +if +you +this +be +on +with +not +have +are +or +as +from +can +but +by +at +an +will +no +all +was +do +there +my +one +so +we +they +what +would +any +which +about +get +your +use +some +me +then +name +like +out +when +up +time +other +more +only +just +end +also +know +how +new +should +been +than +them +he +who +make +may +people +these +now +their +here +into +first +could +way +had +see +work +well +were +two +very +where +while +us +because +good +same +even +much +most +many +such +long +his +over +last +since +right +before +our +without +too +those +why +must +part +being +current +back +still +go +point +value +each +did +both +true +off +say +another +state +might +under +start +try diff --git a/gnu/usr.bin/groff/indxbib/indxbib.1 b/gnu/usr.bin/groff/indxbib/indxbib.1 new file mode 100644 index 0000000000..54114bf123 --- /dev/null +++ b/gnu/usr.bin/groff/indxbib/indxbib.1 @@ -0,0 +1,187 @@ +.\" -*- nroff -*- +.TH INDXBIB 1 "16 April 1993" "Groff Version 1.08" +.SH NAME +indxbib \- make inverted index for bibliographic databases +.SH SYNOPSIS +.nr a \n(.j +.ad l +.nr i \n(.i +.in +\w'\fBindxbib 'u +.ti \niu +.B indxbib +.de OP +.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]" +.el .RB "[\ " "\\$1" "\ ]" +.. +.OP \-vw +.OP \-c file +.OP \-d dir +.OP \-f file +.OP \-h n +.OP \-i string +.OP \-k n +.OP \-l n +.OP \-n n +.OP \-o file +.OP \-t n +.RI [\ filename \|.\|.\|.\ ] +.ad \na +.SH DESCRIPTION +.B indxbib +makes an inverted index for the bibliographic databases in +.IR filename \|.\|.\|. +for use with +.BR refer (1), +.BR lookbib (1), +and +.BR lkbib (1). +The index will be named +.IB filename .i\fR; +the index is written to a temporary file which is then renamed to this. +If no filenames are given on the command line because the +.B \-f +option has been used, and no +.B \-o +option is given, the index will be named +.BR Ind.i . +.LP +Bibliographic databases are divided into records by blank lines. +Within a record, each fields starts with a +.B % +character at the beginning of a line. +Fields have a one letter name which follows the +.B % +character. +.LP +The values set by the +.BR \-c , +.BR \-n , +.BR \-l +and +.B \-t +options are stored in the index; +when the index is searched, keys will be discarded and truncated in a +manner appropriate to these options; +the original keys will be used for verifying that any record +found using the index actually contains the keys. +This means that a user of an index need not know whether these +options were used in the creation of the index, +provided that not all the keys to be searched for +would have been discarded during indexing +and that the user supplies at least the part of each key +that would have remained after being truncated during indexing. +The value set by the +.B \-i +option is also stored in the index +and will be used in verifying records found using the index. +.SH OPTIONS +.TP +.B \-v +Print the version number. +.TP +.B \-w +Index whole files. +Each file is a separate record. +.TP +.BI \-c file +Read the list of common words from +.I file +instead of +.BR /usr/share/dict/eign . +.TP +.BI \-d dir +Use +.I dir +as the pathname of the current working directory to store in the index, +instead of the path printed by +.BR pwd (1). +Usually +.I dir +will be a symbolic link that points to the directory printed by +.BR pwd (1). +.TP +.BI \-f file +Read the files to be indexed from +.IR file . +If +.I file +is +.BR \- , +files will be read from the standard input. +The +.B \-f +option can be given at most once. +.TP +.BI \-i string +Don't index the contents of fields whose names are in +.IR string . +Initially +.I string +is +.BR XYZ . +.TP +.BI \-h n +Use the first prime greater than or equal to +.I n +for the size of the hash table. +Larger values of +.I n +will usually make searching faster, +but will make the index larger +and +.B indxbib +use more memory. +Initially +.I n +is 997. +.TP +.BI \-k n +Use at most +.I n +keys per input record. +Initially +.I n +is 100. +.TP +.BI \-l n +Discard keys that are shorter than +.IR n . +Initially +.I n +is 3. +.TP +.BI \-n n +Discard the +.I n +most common words. +Initially +.I n +is 100. +.TP +.BI \-o basename +The index should be named +.IB basename .i\fR. +.TP +.BI \-t n +Truncate keys to +.IR n . +Initially +.I n +is 6. +.SH FILES +.TP \w'\fBindxbib\fIXXXXXX'u+2n +.IB filename .i +Index. +.TP +.B Ind.i +Default index name. +.TP +.B /usr/share/dict/eign +List of common words. +.TP +.BI indxbib XXXXXX +Temporary file. +.SH "SEE ALSO" +.BR refer (1), +.BR lkbib (1), +.BR lookbib (1) diff --git a/gnu/usr.bin/groff/indxbib/indxbib.cc b/gnu/usr.bin/groff/indxbib/indxbib.cc new file mode 100644 index 0000000000..b2d1a263af --- /dev/null +++ b/gnu/usr.bin/groff/indxbib/indxbib.cc @@ -0,0 +1,742 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +#include "posix.h" +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "stringclass.h" +#include "cset.h" +#include "cmap.h" + +#include "defs.h" +#include "index.h" + +extern "C" { + // Sun's stdlib.h fails to declare this. + char *mktemp(char *); +} + +#define DEFAULT_HASH_TABLE_SIZE 997 +#define TEMP_INDEX_TEMPLATE "indxbibXXXXXX" + +// (2^n - MALLOC_OVERHEAD) should be a good argument for malloc(). + +#define MALLOC_OVERHEAD 16 + +#ifdef BLOCK_SIZE +#undef BLOCK_SIZE +#endif + +const int BLOCK_SIZE = ((1024 - MALLOC_OVERHEAD - sizeof(struct block *) + - sizeof(int)) / sizeof(int)); +struct block { + block *next; + int used; + int v[BLOCK_SIZE]; + + block(block *p = 0) : next(p), used(0) { } +}; + +struct block; + +union table_entry { + block *ptr; + int count; +}; + +struct word_list { + word_list *next; + char *str; + int len; + word_list(const char *, int, word_list *); +}; + +table_entry *hash_table; +int hash_table_size = DEFAULT_HASH_TABLE_SIZE; +// We make this the same size as hash_table so we only have to do one +// mod per key. +static word_list **common_words_table = 0; +char *key_buffer; + +FILE *indxfp; +int ntags = 0; +string filenames; +char *temp_index_file = 0; + +const char *ignore_fields = "XYZ"; +const char *common_words_file = COMMON_WORDS_FILE; +int n_ignore_words = 100; +int truncate_len = 6; +int shortest_len = 3; +int max_keys_per_item = 100; + +static void usage(); +static void write_hash_table(); +static void init_hash_table(); +static void read_common_words_file(); +static int store_key(char *s, int len); +static void possibly_store_key(char *s, int len); +static int do_whole_file(const char *filename); +static int do_file(const char *filename); +static void store_reference(int filename_index, int pos, int len); +static void check_integer_arg(char opt, const char *arg, int min, int *res); +static void store_filename(const char *); +static void fwrite_or_die(const void *ptr, int size, int nitems, FILE *fp); +static char *get_cwd(); + +extern "C" { + void cleanup(); + long dir_name_max(const char *); + void catch_fatal_signals(); + void ignore_fatal_signals(); +} + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + + const char *basename = 0; + typedef int (*parser_t)(const char *); + parser_t parser = do_file; + const char *directory = 0; + const char *foption = 0; + int opt; + while ((opt = getopt(argc, argv, "c:o:h:i:k:l:t:n:c:d:f:vw")) != EOF) + switch (opt) { + case 'c': + common_words_file = optarg; + break; + case 'd': + directory = optarg; + break; + case 'f': + foption = optarg; + break; + case 'h': + check_integer_arg('h', optarg, 1, &hash_table_size); + if (!is_prime(hash_table_size)) { + while (!is_prime(++hash_table_size)) + ; + warning("%1 not prime: using %2 instead", optarg, hash_table_size); + } + break; + case 'i': + ignore_fields = optarg; + break; + case 'k': + check_integer_arg('k', optarg, 1, &max_keys_per_item); + break; + case 'l': + check_integer_arg('l', optarg, 0, &shortest_len); + break; + case 'n': + check_integer_arg('n', optarg, 0, &n_ignore_words); + break; + case 'o': + basename = optarg; + break; + case 't': + check_integer_arg('t', optarg, 1, &truncate_len); + break; + case 'w': + parser = do_whole_file; + break; + case 'v': + { + extern const char *version_string; + fprintf(stderr, "GNU indxbib version %s\n", version_string); + fflush(stderr); + break; + } + case '?': + usage(); + break; + default: + assert(0); + break; + } + if (optind >= argc && foption == 0) + fatal("no files and no -f option"); + if (!directory) { + char *path = get_cwd(); + store_filename(path); + a_delete path; + } + else + store_filename(directory); + init_hash_table(); + store_filename(common_words_file); + store_filename(ignore_fields); + key_buffer = new char[truncate_len]; + read_common_words_file(); + if (!basename) + basename = optind < argc ? argv[optind] : DEFAULT_INDEX_NAME; + const char *p = strrchr(basename, '/'); + long name_max; + if (p) { + char *dir = strsave(basename); + dir[p - basename] = '\0'; + name_max = dir_name_max(dir); + a_delete dir; + } + else + name_max = dir_name_max("."); + const char *filename = p ? p + 1 : basename; + if (name_max >= 0 && strlen(filename) + sizeof(INDEX_SUFFIX) - 1 > name_max) + fatal("`%1.%2' is too long for a filename", filename, INDEX_SUFFIX); + if (p) { + p++; + temp_index_file = new char[p - basename + sizeof(TEMP_INDEX_TEMPLATE)]; + memcpy(temp_index_file, basename, p - basename); + strcpy(temp_index_file + (p - basename), TEMP_INDEX_TEMPLATE); + } + else { + temp_index_file = strsave(TEMP_INDEX_TEMPLATE); + } + if (!mktemp(temp_index_file) || !temp_index_file[0]) + fatal("cannot create file name for temporary file"); + catch_fatal_signals(); + int fd = creat(temp_index_file, S_IRUSR|S_IRGRP|S_IROTH); + if (fd < 0) + fatal("can't create temporary index file: %1", strerror(errno)); + indxfp = fdopen(fd, "w"); + if (indxfp == 0) + fatal("fdopen failed"); + if (fseek(indxfp, sizeof(index_header), 0) < 0) + fatal("can't seek past index header: %1", strerror(errno)); + int failed = 0; + if (foption) { + FILE *fp = stdin; + if (strcmp(foption, "-") != 0) { + errno = 0; + fp = fopen(foption, "r"); + if (!fp) + fatal("can't open `%1': %2", foption, strerror(errno)); + } + string path; + int lineno = 1; + for (;;) { + for (int c = getc(fp); c != '\n' && c != EOF; c = getc(fp)) { + if (c == '\0') + error_with_file_and_line(foption, lineno, + "nul character in pathname ignored"); + else + path += c; + } + if (path.length() > 0) { + path += '\0'; + if (!(*parser)(path.contents())) + failed = 1; + path.clear(); + } + if (c == EOF) + break; + lineno++; + } + if (fp != stdin) + fclose(fp); + } + for (int i = optind; i < argc; i++) + if (!(*parser)(argv[i])) + failed = 1; + write_hash_table(); + if (fclose(indxfp) < 0) + fatal("error closing temporary index file: %1", strerror(errno)); + char *index_file = new char[strlen(basename) + sizeof(INDEX_SUFFIX)]; + strcpy(index_file, basename); + strcat(index_file, INDEX_SUFFIX); +#ifdef HAVE_RENAME + if (rename(temp_index_file, index_file) < 0) + fatal("can't rename temporary index file: %1", strerror(errno)); +#else /* not HAVE_RENAME */ + ignore_fatal_signals(); + if (unlink(index_file) < 0) { + if (errno != ENOENT) + fatal("can't unlink `%1': %2", index_file, strerror(errno)); + } + if (link(temp_index_file, index_file) < 0) + fatal("can't link temporary index file: %1", strerror(errno)); + if (unlink(temp_index_file) < 0) + fatal("can't unlink temporary index file: %1", strerror(errno)); +#endif /* not HAVE_RENAME */ + temp_index_file = 0; + exit(failed); +} + +static void usage() +{ + fprintf(stderr, +"usage: %s [-vw] [-c file] [-d dir] [-f file] [-h n] [-i XYZ] [-k n]\n" +" [-l n] [-n n] [-o base] [-t n] [files...]\n", + program_name); + exit(1); +} + +static void check_integer_arg(char opt, const char *arg, int min, int *res) +{ + char *ptr; + long n = strtol(arg, &ptr, 10); + if (n == 0 && ptr == arg) + error("argument to -%1 not an integer", opt); + else if (n < min) + error("argument to -%1 must not be less than %2", opt, min); + else { + if (n > INT_MAX) + error("argument to -%1 greater than maximum integer", opt); + else if (*ptr != '\0') + error("junk after integer argument to -%1", opt); + *res = int(n); + } +} + +static char *get_cwd() +{ + char *buf; + int size = 12; + + for (;;) { + buf = new char[size]; + if (getcwd(buf, size)) + break; + if (errno != ERANGE) + fatal("cannot get current working directory: %1", strerror(errno)); + a_delete buf; + if (size == INT_MAX) + fatal("current working directory longer than INT_MAX"); + if (size > INT_MAX/2) + size = INT_MAX; + else + size *= 2; + } + return buf; +} + +word_list::word_list(const char *s, int n, word_list *p) +: next(p), len(n) +{ + str = new char[n]; + memcpy(str, s, n); +} + +static void read_common_words_file() +{ + if (n_ignore_words <= 0) + return; + errno = 0; + FILE *fp = fopen(common_words_file, "r"); + if (!fp) + fatal("can't open `%1': %2", common_words_file, strerror(errno)); + common_words_table = new word_list * [hash_table_size]; + for (int i = 0; i < hash_table_size; i++) + common_words_table[i] = 0; + int count = 0; + int key_len = 0; + for (;;) { + int c = getc(fp); + while (c != EOF && !csalnum(c)) + c = getc(fp); + if (c == EOF) + break; + do { + if (key_len < truncate_len) + key_buffer[key_len++] = cmlower(c); + c = getc(fp); + } while (c != EOF && csalnum(c)); + if (key_len >= shortest_len) { + int h = hash(key_buffer, key_len) % hash_table_size; + common_words_table[h] = new word_list(key_buffer, key_len, + common_words_table[h]); + } + if (++count >= n_ignore_words) + break; + key_len = 0; + if (c == EOF) + break; + } + n_ignore_words = count; + fclose(fp); +} + +static int do_whole_file(const char *filename) +{ + errno = 0; + FILE *fp = fopen(filename, "r"); + if (!fp) { + error("can't open `%1': %2", filename, strerror(errno)); + return 0; + } + int count = 0; + int key_len = 0; + int c; + while ((c = getc(fp)) != EOF) { + if (csalnum(c)) { + key_len = 1; + key_buffer[0] = c; + while ((c = getc(fp)) != EOF) { + if (!csalnum(c)) + break; + if (key_len < truncate_len) + key_buffer[key_len++] = c; + } + if (store_key(key_buffer, key_len)) { + if (++count >= max_keys_per_item) + break; + } + if (c == EOF) + break; + } + } + store_reference(filenames.length(), 0, 0); + store_filename(filename); + fclose(fp); + return 1; +} + +static int do_file(const char *filename) +{ + errno = 0; + FILE *fp = fopen(filename, "r"); + if (fp == 0) { + error("can't open `%1': %2", filename, strerror(errno)); + return 0; + } + int filename_index = filenames.length(); + store_filename(filename); + + enum { + START, // at the start of the file; also in between references + BOL, // in the middle of a reference, at the beginning of the line + PERCENT, // seen a percent at the beginning of the line + IGNORE, // ignoring a field + IGNORE_BOL, // at the beginning of a line ignoring a field + KEY, // in the middle of a key + DISCARD, // after truncate_len bytes of a key + MIDDLE // in between keys + } state = START; + + // In states START, BOL, IGNORE_BOL, space_count how many spaces at + // the beginning have been seen. In states PERCENT, IGNORE, KEY, + // MIDDLE space_count must be 0. + int space_count = 0; + int byte_count = 0; // bytes read + int key_len = 0; + int ref_start = -1; // position of start of current reference + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + byte_count++; + switch (state) { + case START: + if (c == ' ' || c == '\t') { + space_count++; + break; + } + if (c == '\n') { + space_count = 0; + break; + } + ref_start = byte_count - space_count - 1; + space_count = 0; + if (c == '%') + state = PERCENT; + else if (csalnum(c)) { + state = KEY; + key_buffer[0] = c; + key_len = 1; + } + else + state = MIDDLE; + break; + case BOL: + switch (c) { + case '%': + if (space_count > 0) { + space_count = 0; + state = MIDDLE; + } + else + state = PERCENT; + break; + case ' ': + case '\t': + space_count++; + break; + case '\n': + store_reference(filename_index, ref_start, + byte_count - 1 - space_count - ref_start); + state = START; + space_count = 0; + break; + default: + space_count = 0; + if (csalnum(c)) { + state = KEY; + key_buffer[0] = c; + key_len = 1; + } + else + state = MIDDLE; + } + break; + case PERCENT: + if (strchr(ignore_fields, c) != 0) + state = IGNORE; + else if (c == '\n') + state = BOL; + else + state = MIDDLE; + break; + case IGNORE: + if (c == '\n') + state = IGNORE_BOL; + break; + case IGNORE_BOL: + switch (c) { + case '%': + if (space_count > 0) { + state = IGNORE; + space_count = 0; + } + else + state = PERCENT; + break; + case ' ': + case '\t': + space_count++; + break; + case '\n': + store_reference(filename_index, ref_start, + byte_count - 1 - space_count - ref_start); + state = START; + space_count = 0; + break; + default: + space_count = 0; + state = IGNORE; + } + break; + case KEY: + if (csalnum(c)) { + if (key_len < truncate_len) + key_buffer[key_len++] = c; + else + state = DISCARD; + } + else { + possibly_store_key(key_buffer, key_len); + key_len = 0; + if (c == '\n') + state = BOL; + else + state = MIDDLE; + } + break; + case DISCARD: + if (!csalnum(c)) { + possibly_store_key(key_buffer, key_len); + key_len = 0; + if (c == '\n') + state = BOL; + else + state = MIDDLE; + } + break; + case MIDDLE: + if (csalnum(c)) { + state = KEY; + key_buffer[0] = c; + key_len = 1; + } + else if (c == '\n') + state = BOL; + break; + default: + assert(0); + } + } + switch (state) { + case START: + break; + case DISCARD: + case KEY: + possibly_store_key(key_buffer, key_len); + // fall through + case BOL: + case PERCENT: + case IGNORE_BOL: + case IGNORE: + case MIDDLE: + store_reference(filename_index, ref_start, + byte_count - ref_start - space_count); + break; + default: + assert(0); + } + fclose(fp); + return 1; +} + +static void store_reference(int filename_index, int pos, int len) +{ + tag t; + t.filename_index = filename_index; + t.start = pos; + t.length = len; + fwrite_or_die(&t, sizeof(t), 1, indxfp); + ntags++; +} + +static void store_filename(const char *fn) +{ + filenames += fn; + filenames += '\0'; +} + +static void init_hash_table() +{ + hash_table = new table_entry[hash_table_size]; + for (int i = 0; i < hash_table_size; i++) + hash_table[i].ptr = 0; +} + +static void possibly_store_key(char *s, int len) +{ + static int last_tagno = -1; + static int key_count; + if (last_tagno != ntags) { + last_tagno = ntags; + key_count = 0; + } + if (key_count < max_keys_per_item) { + if (store_key(s, len)) + key_count++; + } +} + +static int store_key(char *s, int len) +{ + if (len < shortest_len) + return 0; + int is_number = 1; + for (int i = 0; i < len; i++) + if (!csdigit(s[i])) { + is_number = 0; + s[i] = cmlower(s[i]); + } + if (is_number && !(len == 4 && s[0] == '1' && s[1] == '9')) + return 0; + int h = hash(s, len) % hash_table_size; + if (common_words_table) { + for (word_list *ptr = common_words_table[h]; ptr; ptr = ptr->next) + if (len == ptr->len && memcmp(s, ptr->str, len) == 0) + return 0; + } + table_entry *pp = hash_table + h; + if (!pp->ptr) + pp->ptr = new block; + else if (pp->ptr->v[pp->ptr->used - 1] == ntags) + return 1; + else if (pp->ptr->used >= BLOCK_SIZE) + pp->ptr = new block(pp->ptr); + pp->ptr->v[(pp->ptr->used)++] = ntags; + return 1; +} + +static void write_hash_table() +{ + const int minus_one = -1; + int li = 0; + for (int i = 0; i < hash_table_size; i++) { + block *ptr = hash_table[i].ptr; + if (!ptr) + hash_table[i].count = -1; + else { + hash_table[i].count = li; + block *rev = 0; + while (ptr) { + block *tem = ptr; + ptr = ptr->next; + tem->next = rev; + rev = tem; + } + while (rev) { + fwrite_or_die(rev->v, sizeof(int), rev->used, indxfp); + li += rev->used; + block *tem = rev; + rev = rev->next; + delete tem; + } + fwrite_or_die(&minus_one, sizeof(int), 1, indxfp); + li += 1; + } + } + if (sizeof(table_entry) == sizeof(int)) + fwrite_or_die(hash_table, sizeof(int), hash_table_size, indxfp); + else { + assert(0); + // write it out word by word + } + fwrite_or_die(filenames.contents(), 1, filenames.length(), indxfp); + if (fseek(indxfp, 0, 0) < 0) + fatal("error seeking on index file: %1", strerror(errno)); + index_header h; + h.magic = INDEX_MAGIC; + h.version = INDEX_VERSION; + h.tags_size = ntags; + h.lists_size = li; + h.table_size = hash_table_size; + h.strings_size = filenames.length(); + h.truncate = truncate_len; + h.shortest = shortest_len; + h.common = n_ignore_words; + fwrite_or_die(&h, sizeof(h), 1, indxfp); +} + +static void fwrite_or_die(const void *ptr, int size, int nitems, FILE *fp) +{ + if (fwrite(ptr, size, nitems, fp) != nitems) + fatal("fwrite failed: %1", strerror(errno)); +} + +void fatal_error_exit() +{ + cleanup(); + exit(3); +} + +extern "C" { + +void cleanup() +{ + if (temp_index_file) + unlink(temp_index_file); +} + +} diff --git a/gnu/usr.bin/groff/indxbib/signal.c b/gnu/usr.bin/groff/indxbib/signal.c new file mode 100644 index 0000000000..7c81f9157f --- /dev/null +++ b/gnu/usr.bin/groff/indxbib/signal.c @@ -0,0 +1,63 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Unfortunately vendors seem to have problems writing a +that is correct for C++, so we implement all signal handling in C. */ + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef RETSIGTYPE +#define RETSIGTYPE void +#endif + +extern void cleanup(); + +static RETSIGTYPE handle_fatal_signal(signum) + int signum; +{ + signal(signum, SIG_DFL); + cleanup(); + kill(getpid(), signum); +} + +void catch_fatal_signals() +{ +#ifdef SIGHUP + signal(SIGHUP, handle_fatal_signal); +#endif + signal(SIGINT, handle_fatal_signal); + signal(SIGTERM, handle_fatal_signal); +} + +#ifndef HAVE_RENAME + +void ignore_fatal_signals() +{ +#ifdef SIGHUP + signal(SIGHUP, SIG_IGN); +#endif + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); +} + +#endif /* not HAVE_RENAME */ diff --git a/gnu/usr.bin/groff/libbib/Makefile b/gnu/usr.bin/groff/libbib/Makefile new file mode 100644 index 0000000000..b0d9f3ecd0 --- /dev/null +++ b/gnu/usr.bin/groff/libbib/Makefile @@ -0,0 +1,14 @@ +# Makefile for libbib + +LIB= bib +SRCS= common.cc index.cc linear.cc search.cc map.c +CFLAGS+= -I$(.CURDIR)/../include + +NOMAN= noman +NOPROFILE= noprofile + +install: + +.include +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/libbib/Makefile.dep b/gnu/usr.bin/groff/libbib/Makefile.dep new file mode 100644 index 0000000000..906a38ad7c --- /dev/null +++ b/gnu/usr.bin/groff/libbib/Makefile.dep @@ -0,0 +1,12 @@ +common.o : common.cc +index.o : index.cc ../include/posix.h ../include/lib.h ../include/cset.h \ + ../include/cmap.h ../include/errarg.h ../include/error.h \ + ../include/refid.h ../include/search.h ../include/index.h \ + ../include/defs.h +linear.o : linear.cc ../include/posix.h ../include/lib.h \ + ../include/errarg.h ../include/error.h ../include/cset.h \ + ../include/cmap.h ../include/refid.h ../include/search.h +search.o : search.cc ../include/posix.h ../include/lib.h \ + ../include/errarg.h ../include/error.h ../include/refid.h \ + ../include/search.h +map.o : map.c diff --git a/gnu/usr.bin/groff/libbib/common.cc b/gnu/usr.bin/groff/libbib/common.cc new file mode 100644 index 0000000000..25f4078b8f --- /dev/null +++ b/gnu/usr.bin/groff/libbib/common.cc @@ -0,0 +1,38 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +unsigned hash(const char *s, int len) +{ +#if 0 + unsigned h = 0, g; + while (*s != '\0') { + h <<= 4; + h += *s++; + if ((g = h & 0xf0000000) != 0) { + h ^= g >> 24; + h ^= g; + } + } +#endif + unsigned h = 0; + while (--len >= 0) + h = *s++ + 65587*h; + return h; +} + diff --git a/gnu/usr.bin/groff/libbib/index.cc b/gnu/usr.bin/groff/libbib/index.cc new file mode 100644 index 0000000000..8fe5acdae7 --- /dev/null +++ b/gnu/usr.bin/groff/libbib/index.cc @@ -0,0 +1,614 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include + +#include "posix.h" +#include "lib.h" +#include "cset.h" +#include "cmap.h" +#include "errarg.h" +#include "error.h" + +#include "refid.h" +#include "search.h" +#include "index.h" +#include "defs.h" + +// Interface to mmap. +extern "C" { + void *mapread(int fd, int len); + int unmap(void *, int len); +} + +const int minus_one = -1; + +int verify_flag = 0; + +struct word_list; + +class index_search_item : public search_item { + search_item *out_of_date_files; + index_header header; + char *buffer; + void *map_addr; + int map_len; + tag *tags; + int *table; + int *lists; + char *pool; + char *key_buffer; + char *filename_buffer; + int filename_buflen; + char **common_words_table; + int common_words_table_size; + const char *ignore_fields; + time_t mtime; + + const char *do_verify(); + const int *search1(const char **pp, const char *end); + const int *search(const char *ptr, int length, int **temp_listp); + const char *munge_filename(const char *); + void read_common_words_file(); + void add_out_of_date_file(int fd, const char *filename, int fid); +public: + index_search_item(const char *, int); + ~index_search_item(); + int load(int fd); + search_item_iterator *make_search_item_iterator(const char *); + int verify(); + void check_files(); + int next_filename_id() const; + friend class index_search_item_iterator; +}; + +class index_search_item_iterator : public search_item_iterator { + index_search_item *indx; + search_item_iterator *out_of_date_files_iter; + search_item *next_out_of_date_file; + const int *found_list; + int *temp_list; + char *buf; + int buflen; + linear_searcher searcher; + char *query; + int get_tag(int tagno, const linear_searcher &, const char **, int *, + reference_id *); +public: + index_search_item_iterator(index_search_item *, const char *); + ~index_search_item_iterator(); + int next(const linear_searcher &, const char **, int *, reference_id *); +}; + + +index_search_item::index_search_item(const char *filename, int fid) +: search_item(filename, fid), out_of_date_files(0), key_buffer(0), + filename_buffer(0), filename_buflen(0), common_words_table(0), + map_addr(0), map_len(0), buffer(0) +{ +} + +index_search_item::~index_search_item() +{ + if (buffer) + free(buffer); + if (map_addr) { + if (unmap(map_addr, map_len) < 0) + error("unmap: %1", strerror(errno)); + } + while (out_of_date_files) { + search_item *tem = out_of_date_files; + out_of_date_files = out_of_date_files->next; + delete tem; + } + a_delete filename_buffer; + a_delete key_buffer; + if (common_words_table) { + for (int i = 0; i < common_words_table_size; i++) + a_delete common_words_table[i]; + a_delete common_words_table; + } +} + +class file_closer { + int *fdp; +public: + file_closer(int &fd) : fdp(&fd) { } + ~file_closer() { close(*fdp); } +}; + +int index_search_item::load(int fd) +{ + file_closer fd_closer(fd); // close fd on return + struct stat sb; + if (fstat(fd, &sb) < 0) { + error("can't fstat `%1': %2", name, strerror(errno)); + return 0; + } + if (!S_ISREG(sb.st_mode)) { + error("`%1' is not a regular file", name); + return 0; + } + mtime = sb.st_mtime; + int size = int(sb.st_size); + char *addr; + map_addr = mapread(fd, size); + if (map_addr) { + addr = (char *)map_addr; + map_len = size; + } + else { + addr = buffer = (char *)malloc(size); + if (buffer == 0) { + error("can't allocate buffer for `%1'", name); + return 0; + } + char *ptr = buffer; + int bytes_to_read = size; + while (bytes_to_read > 0) { + int nread = read(fd, ptr, bytes_to_read); + if (nread == 0) { + error("unexpected EOF on `%1'", name); + return 0; + } + if (nread < 0) { + error("read error on `%1': %2", name, strerror(errno)); + return 0; + } + bytes_to_read -= nread; + ptr += nread; + } + } + header = *(index_header *)addr; + if (header.magic != INDEX_MAGIC) { + error("`%1' is not an index file: wrong magic number", name); + return 0; + } + if (header.version != INDEX_VERSION) { + error("version number in `%1' is wrong: was %2, should be %3", + name, header.version, INDEX_VERSION); + return 0; + } + int sz = (header.tags_size * sizeof(tag) + + header.lists_size * sizeof(int) + + header.table_size * sizeof(int) + + header.strings_size + + sizeof(header)); + if (sz != size) { + error("size of `%1' is wrong: was %2, should be %3", + name, size, sz); + return 0; + } + tags = (tag *)(addr + sizeof(header)); + lists = (int *)(tags + header.tags_size); + table = (int *)(lists + header.lists_size); + pool = (char *)(table + header.table_size); + ignore_fields = strchr(strchr(pool, '\0') + 1, '\0') + 1; + key_buffer = new char[header.truncate]; + read_common_words_file(); + return 1; +} + +const char *index_search_item::do_verify() +{ + if (tags == 0) + return "not loaded"; + if (lists[header.lists_size - 1] >= 0) + return "last list element not negative"; + int i; + for (i = 0; i < header.table_size; i++) { + int li = table[i]; + if (li >= header.lists_size) + return "bad list index"; + if (li >= 0) { + for (int *ptr = lists + li; *ptr >= 0; ptr++) { + if (*ptr >= header.tags_size) + return "bad tag index"; + if (*ptr >= ptr[1] && ptr[1] >= 0) + return "list not ordered"; + } + } + } + for (i = 0; i < header.tags_size; i++) { + if (tags[i].filename_index >= header.strings_size) + return "bad index in tags"; + if (tags[i].length < 0) + return "bad length in tags"; + if (tags[i].start < 0) + return "bad start in tags"; + } + if (pool[header.strings_size - 1] != '\0') + return "last character in pool not nul"; + return 0; +} + +int index_search_item::verify() +{ + const char *reason = do_verify(); + if (!reason) + return 1; + error("`%1' is bad: %2", name, reason); + return 0; +} + +int index_search_item::next_filename_id() const +{ + return filename_id + header.strings_size + 1; +} + +search_item_iterator *index_search_item::make_search_item_iterator( + const char *query) +{ + return new index_search_item_iterator(this, query); +} + +search_item *make_index_search_item(const char *filename, int fid) +{ + char *index_filename = new char[strlen(filename) + sizeof(INDEX_SUFFIX)]; + strcpy(index_filename, filename); + strcat(index_filename, INDEX_SUFFIX); + int fd = open(index_filename, O_RDONLY); + if (fd < 0) + return 0; + index_search_item *item = new index_search_item(index_filename, fid); + a_delete index_filename; + if (!item->load(fd)) { + close(fd); + delete item; + return 0; + } + else if (verify_flag && !item->verify()) { + delete item; + return 0; + } + else { + item->check_files(); + return item; + } +} + + +index_search_item_iterator::index_search_item_iterator(index_search_item *ind, + const char *q) +: indx(ind), buf(0), buflen(0), temp_list(0), query(strsave(q)), + searcher(q, strlen(q), ind->ignore_fields, ind->header.truncate), + out_of_date_files_iter(0), next_out_of_date_file(0) +{ + found_list = indx->search(q, strlen(q), &temp_list); + if (!found_list) { + found_list = &minus_one; + warning("all keys would have been discarded in constructing index `%1'", + indx->name); + } +} + +index_search_item_iterator::~index_search_item_iterator() +{ + a_delete temp_list; + a_delete buf; + a_delete query; + delete out_of_date_files_iter; +} + +int index_search_item_iterator::next(const linear_searcher &, + const char **pp, int *lenp, + reference_id *ridp) +{ + if (found_list) { + for (;;) { + int tagno = *found_list; + if (tagno == -1) + break; + found_list++; + if (get_tag(tagno, searcher, pp, lenp, ridp)) + return 1; + } + found_list = 0; + next_out_of_date_file = indx->out_of_date_files; + } + while (next_out_of_date_file) { + if (out_of_date_files_iter == 0) + out_of_date_files_iter + = next_out_of_date_file->make_search_item_iterator(query); + if (out_of_date_files_iter->next(searcher, pp, lenp, ridp)) + return 1; + delete out_of_date_files_iter; + out_of_date_files_iter = 0; + next_out_of_date_file = next_out_of_date_file->next; + } + return 0; +} + +int index_search_item_iterator::get_tag(int tagno, + const linear_searcher &searcher, + const char **pp, int *lenp, + reference_id *ridp) +{ + if (tagno < 0 || tagno >= indx->header.tags_size) { + error("bad tag number"); + return 0; + } + tag *tp = indx->tags + tagno; + const char *filename = indx->munge_filename(indx->pool + tp->filename_index); + int fd = open(filename, O_RDONLY); + if (fd < 0) { + error("can't open `%1': %2", filename, strerror(errno)); + return 0; + } + struct stat sb; + if (fstat(fd, &sb) < 0) { + error("can't fstat: %1", strerror(errno)); + close(fd); + return 0; + } + time_t mtime = sb.st_mtime; + if (mtime > indx->mtime) { + indx->add_out_of_date_file(fd, filename, + indx->filename_id + tp->filename_index); + return 0; + } + int res = 0; + FILE *fp = fdopen(fd, "r"); + if (!fp) { + error("fdopen failed"); + close(fd); + return 0; + } + if (tp->start != 0 && fseek(fp, long(tp->start), 0) < 0) + error("can't seek on `%1': %2", filename, strerror(errno)); + else { + int length = tp->length; + int err = 0; + if (length == 0) { + struct stat sb; + if (fstat(fileno(fp), &sb) < 0) { + error("can't stat `%1': %2", filename, strerror(errno)); + err = 1; + } + else if ((sb.st_mode & S_IFMT) != S_IFREG) { + error("`%1' is not a regular file", filename); + err = 1; + } + else + length = int(sb.st_size); + } + if (!err) { + if (length + 2 > buflen) { + a_delete buf; + buflen = length + 2; + buf = new char[buflen]; + } + if (fread(buf + 1, 1, length, fp) != length) + error("fread on `%1' failed: %2", filename, strerror(errno)); + else { + buf[0] = '\n'; + buf[length + 1] = '\n'; + res = searcher.search(buf + 1, buf + 2 + length, pp, lenp); + if (res && ridp) + *ridp = reference_id(indx->filename_id + tp->filename_index, + tp->start); + } + } + } + fclose(fp); + return res; +} + +const char *index_search_item::munge_filename(const char *filename) +{ + if (filename[0] == '/') + return filename; + const char *cwd = pool; + int need_slash = (cwd[0] != 0 && strchr(cwd, '\0')[-1] != '/'); + int len = strlen(cwd) + strlen(filename) + need_slash + 1; + if (len > filename_buflen) { + a_delete filename_buffer; + filename_buflen = len; + filename_buffer = new char[len]; + } + strcpy(filename_buffer, cwd); + if (need_slash) + strcat(filename_buffer, "/"); + strcat(filename_buffer, filename); + return filename_buffer; +} + +const int *index_search_item::search1(const char **pp, const char *end) +{ + while (*pp < end && !csalnum(**pp)) + *pp += 1; + if (*pp >= end) + return 0; + const char *start = *pp; + while (*pp < end && csalnum(**pp)) + *pp += 1; + int len = *pp - start; + if (len < header.shortest) + return 0; + if (len > header.truncate) + len = header.truncate; + int is_number = 1; + for (int i = 0; i < len; i++) + if (csdigit(start[i])) + key_buffer[i] = start[i]; + else { + key_buffer[i] = cmlower(start[i]); + is_number = 0; + } + if (is_number && !(len == 4 && start[0] == '1' && start[1] == '9')) + return 0; + unsigned hc = hash(key_buffer, len); + if (common_words_table) { + for (int h = hc % common_words_table_size; + common_words_table[h]; + --h) { + if (strlen(common_words_table[h]) == len + && memcmp(common_words_table[h], key_buffer, len) == 0) + return 0; + if (h == 0) + h = common_words_table_size; + } + } + int li = table[int(hc % header.table_size)]; + return li < 0 ? &minus_one : lists + li; +} + +static void merge(int *result, const int *s1, const int *s2) +{ + for (; *s1 >= 0; s1++) { + while (*s2 >= 0 && *s2 < *s1) + s2++; + if (*s2 == *s1) + *result++ = *s2; + } + *result++ = -1; +} + +const int *index_search_item::search(const char *ptr, int length, + int **temp_listp) +{ + const char *end = ptr + length; + if (*temp_listp) { + a_delete *temp_listp; + *temp_listp = 0; + } + const int *first_list = 0; + while (ptr < end && (first_list = search1(&ptr, end)) == 0) + ; + if (!first_list) + return 0; + if (*first_list < 0) + return first_list; + const int *second_list = 0; + while (ptr < end && (second_list = search1(&ptr, end)) == 0) + ; + if (!second_list) + return first_list; + if (*second_list < 0) + return second_list; + for (const int *p = first_list; *p >= 0; p++) + ; + int len = p - first_list; + for (p = second_list; *p >= 0; p++) + ; + if (p - second_list < len) + len = p - second_list; + int *matches = new int[len + 1]; + merge(matches, first_list, second_list); + while (ptr < end) { + const int *list = search1(&ptr, end); + if (list != 0) { + if (*list < 0) { + a_delete matches; + return list; + } + merge(matches, matches, list); + if (*matches < 0) { + a_delete matches; + return &minus_one; + } + } + } + *temp_listp = matches; + return matches; +} + +void index_search_item::read_common_words_file() +{ + if (header.common <= 0) + return; + const char *common_words_file = munge_filename(strchr(pool, '\0') + 1); + errno = 0; + FILE *fp = fopen(common_words_file, "r"); + if (!fp) { + error("can't open `%1': %2", common_words_file, strerror(errno)); + return; + } + common_words_table_size = 2*header.common + 1; + while (!is_prime(common_words_table_size)) + common_words_table_size++; + common_words_table = new char *[common_words_table_size]; + for (int i = 0; i < common_words_table_size; i++) + common_words_table[i] = 0; + int count = 0; + int key_len = 0; + for (;;) { + int c = getc(fp); + while (c != EOF && !csalnum(c)) + c = getc(fp); + if (c == EOF) + break; + do { + if (key_len < header.truncate) + key_buffer[key_len++] = cmlower(c); + c = getc(fp); + } while (c != EOF && csalnum(c)); + if (key_len >= header.shortest) { + int h = hash(key_buffer, key_len) % common_words_table_size; + while (common_words_table[h]) { + if (h == 0) + h = common_words_table_size; + --h; + } + common_words_table[h] = new char[key_len + 1]; + memcpy(common_words_table[h], key_buffer, key_len); + common_words_table[h][key_len] = '\0'; + } + if (++count >= header.common) + break; + key_len = 0; + if (c == EOF) + break; + } + fclose(fp); +} + +void index_search_item::add_out_of_date_file(int fd, const char *filename, + int fid) +{ + for (search_item **pp = &out_of_date_files; *pp; pp = &(*pp)->next) + if ((*pp)->is_named(filename)) + return; + *pp = make_linear_search_item(fd, filename, fid); + warning("`%1' modified since `%2' created", filename, name); +} + +void index_search_item::check_files() +{ + const char *pool_end = pool + header.strings_size; + for (const char *ptr = strchr(ignore_fields, '\0') + 1; + ptr < pool_end; + ptr = strchr(ptr, '\0') + 1) { + const char *path = munge_filename(ptr); + struct stat sb; + if (stat(path, &sb) < 0) + error("can't stat `%1': %2", path, strerror(errno)); + else if (sb.st_mtime > mtime) { + int fd = open(path, O_RDONLY); + if (fd < 0) + error("can't open `%1': %2", path, strerror(errno)); + else + add_out_of_date_file(fd, path, filename_id + (ptr - pool)); + } + } +} diff --git a/gnu/usr.bin/groff/libbib/linear.cc b/gnu/usr.bin/groff/libbib/linear.cc new file mode 100644 index 0000000000..0798008210 --- /dev/null +++ b/gnu/usr.bin/groff/libbib/linear.cc @@ -0,0 +1,484 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include +#include +#include +#include + +#include "posix.h" +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "cset.h" +#include "cmap.h" + +#include "refid.h" +#include "search.h" + +class file_buffer { + char *buffer; + char *bufend; +public: + file_buffer(); + ~file_buffer(); + int load(int fd, const char *filename); + const char *get_start() const; + const char *get_end() const; +}; + +typedef unsigned char uchar; + +static uchar map[256]; +static uchar inv_map[256][3]; + +struct map_init { + map_init(); +}; + +static map_init the_map_init; + +map_init::map_init() +{ + for (int i = 0; i < 256; i++) + map[i] = csalnum(i) ? cmlower(i) : '\0'; + for (i = 0; i < 256; i++) { + if (cslower(i)) { + inv_map[i][0] = i; + inv_map[i][1] = cmupper(i); + inv_map[i][2] = '\0'; + } + else if (csdigit(i)) { + inv_map[i][0] = i; + inv_map[i][1] = 0; + } + else + inv_map[i][0] = '\0'; + } +} + + +class bmpattern { + char *pat; + int len; + int delta[256]; +public: + bmpattern(const char *pattern, int pattern_length); + ~bmpattern(); + const char *search(const char *p, const char *end) const; + int length() const; +}; + +bmpattern::bmpattern(const char *pattern, int pattern_length) +: len(pattern_length) +{ + pat = new char[len]; + int i; + for (i = 0; i < len; i++) + pat[i] = map[uchar(pattern[i])]; + for (i = 0; i < 256; i++) + delta[i] = len; + for (i = 0; i < len; i++) + for (const unsigned char *inv = inv_map[uchar(pat[i])]; *inv; inv++) + delta[*inv] = len - i - 1; +} + +const char *bmpattern::search(const char *buf, const char *end) const +{ + int buflen = end - buf; + if (len > buflen) + return 0; + const char *strend; + if (buflen > len*4) + strend = end - len*4; + else + strend = buf; + const char *k = buf + len - 1; + const int *del = delta; + const char *pattern = pat; + for (;;) { + while (k < strend) { + int t = del[uchar(*k)]; + if (!t) + break; + k += t; + k += del[uchar(*k)]; + k += del[uchar(*k)]; + } + while (k < end && del[uchar(*k)] != 0) + k++; + if (k == end) + break; + int j = len - 1; + const char *s = k; + for (;;) { + if (j == 0) + return s; + if (map[uchar(*--s)] != pattern[--j]) + break; + } + k++; + } + return 0; +} + +bmpattern::~bmpattern() +{ + a_delete pat; +} + +inline int bmpattern::length() const +{ + return len; +} + + +static const char *find_end(const char *bufend, const char *p); + +const char *linear_searcher::search_and_check(const bmpattern *key, + const char *buf, const char *bufend, const char **start) const +{ + assert(buf[-1] == '\n'); + assert(bufend[-1] == '\n'); + const char *ptr = buf; + for (;;) { + const char *found = key->search(ptr, bufend); + if (!found) + break; + if (check_match(buf, bufend, found, key->length(), &ptr, start)) + return found; + } + return 0; +} + +static const char *skip_field(const char *end, const char *p) +{ + for (;;) + if (*p++ == '\n') { + if (p == end || *p == '%') + break; + for (const char *q = p; *q == ' ' || *q == '\t'; q++) + ; + if (*q == '\n') + break; + p = q + 1; + } + return p; +} + +static const char *find_end(const char *bufend, const char *p) +{ + for (;;) + if (*p++ == '\n') { + if (p == bufend) + break; + for (const char *q = p; *q == ' ' || *q == '\t'; q++) + ; + if (*q == '\n') + break; + p = q + 1; + } + return p; +} + + +int linear_searcher::check_match(const char *buf, const char *bufend, + const char *match, int matchlen, + const char **cont, const char **start) const +{ + *cont = match + 1; + // The user is required to supply only the first truncate_len characters + // of the key. If truncate_len <= 0, he must supply all the key. + if ((truncate_len <= 0 || matchlen < truncate_len) + && map[uchar(match[matchlen])] != '\0') + return 0; + + // The character before the match must not be an alphanumeric + // character (unless the alphanumeric character follows one or two + // percent characters at the beginning of the line), nor must it be + // a percent character at the beginning of a line, nor a percent + // character following a percent character at the beginning of a + // line. + + switch (match - buf) { + case 0: + break; + case 1: + if (match[-1] == '%' || map[uchar(match[-1])] != '\0') + return 0; + break; + case 2: + if (map[uchar(match[-1])] != '\0' && match[-2] != '%') + return 0; + if (match[-1] == '%' + && (match[-2] == '\n' || match[-2] == '%')) + return 0; + break; + default: + if (map[uchar(match[-1])] != '\0' + && !(match[-2] == '%' + && (match[-3] == '\n' + || (match[-3] == '%' && match[-4] == '\n')))) + return 0; + if (match[-1] == '%' + && (match[-2] == '\n' + || (match[-2] == '%' && match[-3] == '\n'))) + return 0; + } + + const char *p = match; + int had_percent = 0; + for (;;) { + if (*p == '\n') { + if (!had_percent && p[1] == '%') { + if (p[2] != '\0' && strchr(ignore_fields, p[2]) != 0) { + *cont = skip_field(bufend, match + matchlen); + return 0; + } + if (!start) + break; + had_percent = 1; + } + if (p <= buf) { + if (start) + *start = p + 1; + return 1; + } + for (const char *q = p - 1; *q == ' ' || *q == '\t'; q--) + ; + if (*q == '\n') { + if (start) + *start = p + 1; + break; + } + p = q; + } + p--; + } + return 1; +} + +file_buffer::file_buffer() +: buffer(0), bufend(0) +{ +} + +file_buffer::~file_buffer() +{ + a_delete buffer; +} + +const char *file_buffer::get_start() const +{ + return buffer ? buffer + 4 : 0; +} + +const char *file_buffer::get_end() const +{ + return bufend; +} + +int file_buffer::load(int fd, const char *filename) +{ + struct stat sb; + if (fstat(fd, &sb) < 0) + error("can't fstat `%1': %2", filename, strerror(errno)); + else if ((sb.st_mode & S_IFMT) != S_IFREG) + error("`%1' is not a regular file", filename); + else { + // We need one character extra at the beginning for an additional newline + // used as a sentinel. We get 4 instead so that the read buffer will be + // word-aligned. This seems to make the read slightly faster. We also + // need one character at the end also for an addional newline used as a + // sentinel. + int size = int(sb.st_size); + buffer = new char[size + 4 + 1]; + int nread = read(fd, buffer + 4, size); + if (nread < 0) + error("error reading `%1': %2", filename, strerror(errno)); + else if (nread != size) + error("size of `%1' decreased", filename); + else { + char c; + nread = read(fd, &c, 1); + if (nread != 0) + error("size of `%1' increased", filename); + else if (memchr(buffer + 4, '\0', size < 1024 ? size : 1024) != 0) + error("database `%1' is a binary file", filename); + else { + close(fd); + buffer[3] = '\n'; + bufend = buffer + 4 + size; + if (bufend[-1] != '\n') + *bufend++ = '\n'; + return 1; + } + } + a_delete buffer; + buffer = 0; + } + close(fd); + return 0; +} + +linear_searcher::linear_searcher(const char *query, int query_len, + const char *ign, int trunc) +: keys(0), nkeys(0), truncate_len(trunc), ignore_fields(ign) +{ + const char *query_end = query + query_len; + int nk = 0; + const char *p; + for (p = query; p < query_end; p++) + if (map[uchar(*p)] != '\0' + && (p[1] == '\0' || map[uchar(p[1])] == '\0')) + nk++; + if (nk == 0) + return; + keys = new bmpattern*[nk]; + p = query; + for (;;) { + while (p < query_end && map[uchar(*p)] == '\0') + p++; + if (p == query_end) + break; + const char *start = p; + while (p < query_end && map[uchar(*p)] != '\0') + p++; + keys[nkeys++] = new bmpattern(start, p - start); + } + assert(nkeys <= nk); + if (nkeys == 0) { + a_delete keys; + keys = 0; + } +} + +linear_searcher::~linear_searcher() +{ + for (int i = 0; i < nkeys; i++) + delete keys[i]; + a_delete keys; +} + +int linear_searcher::search(const char *buffer, const char *bufend, + const char **startp, int *lengthp) const +{ + assert(bufend - buffer > 0); + assert(buffer[-1] == '\n'); + assert(bufend[-1] == '\n'); + if (nkeys == 0) + return 0; + for (;;) { + const char *refstart; + const char *found = search_and_check(keys[0], buffer, bufend, &refstart); + if (!found) + break; + const char *refend = find_end(bufend, found + keys[0]->length()); + for (int i = 1; i < nkeys; i++) + if (!search_and_check(keys[i], refstart, refend)) + break; + if (i >= nkeys) { + *startp = refstart; + *lengthp = refend - refstart; + return 1; + } + buffer = refend; + } + return 0; +} + +class linear_search_item : public search_item { + file_buffer fbuf; +public: + linear_search_item(const char *filename, int fid); + ~linear_search_item(); + int load(int fd); + search_item_iterator *make_search_item_iterator(const char *); + friend class linear_search_item_iterator; +}; + +class linear_search_item_iterator : public search_item_iterator { + linear_search_item *lsi; + int pos; +public: + linear_search_item_iterator(linear_search_item *, const char *query); + ~linear_search_item_iterator(); + int next(const linear_searcher &, const char **ptr, int *lenp, + reference_id *ridp); +}; + +search_item *make_linear_search_item(int fd, const char *filename, int fid) +{ + linear_search_item *item = new linear_search_item(filename, fid); + if (!item->load(fd)) { + delete item; + return 0; + } + else + return item; +} + +linear_search_item::linear_search_item(const char *filename, int fid) +: search_item(filename, fid) +{ +} + +linear_search_item::~linear_search_item() +{ +} + +int linear_search_item::load(int fd) +{ + return fbuf.load(fd, name); +} + +search_item_iterator *linear_search_item::make_search_item_iterator( + const char *query) +{ + return new linear_search_item_iterator(this, query); +} + +linear_search_item_iterator::linear_search_item_iterator( + linear_search_item *p, const char *) +: lsi(p), pos(0) +{ +} + +linear_search_item_iterator::~linear_search_item_iterator() +{ +} + +int linear_search_item_iterator::next(const linear_searcher &searcher, + const char **startp, int *lengthp, + reference_id *ridp) +{ + const char *bufstart = lsi->fbuf.get_start(); + const char *bufend = lsi->fbuf.get_end(); + const char *ptr = bufstart + pos; + if (ptr < bufend && searcher.search(ptr, bufend, startp, lengthp)) { + pos = *startp + *lengthp - bufstart; + if (ridp) + *ridp = reference_id(lsi->filename_id, *startp - bufstart); + return 1; + } + else + return 0; +} diff --git a/gnu/usr.bin/groff/libbib/map.c b/gnu/usr.bin/groff/libbib/map.c new file mode 100644 index 0000000000..9d0f13f893 --- /dev/null +++ b/gnu/usr.bin/groff/libbib/map.c @@ -0,0 +1,75 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_MMAP + +#include +#include + +/* The Net-2 man pages says that a MAP_FILE flag is required. */ +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +char *mapread(fd, nbytes) + int fd; + int nbytes; +{ + char *p = (char *)mmap((caddr_t)0, (size_t)nbytes, PROT_READ, + MAP_FILE|MAP_PRIVATE, fd, (off_t)0); + if (p == (char *)-1) + return 0; + /* mmap() shouldn't return 0 since MAP_FIXED wasn't specified. */ + if (p == 0) + abort(); + return p; +} + +int unmap(p, len) + char *p; + int len; +{ + return munmap((caddr_t)p, len); +} + +#else /* not HAVE_MMAP */ + +#include + +#ifndef errno +extern int errno; +#endif + +char *mapread(fd, nbytes) + int fd; + int nbytes; +{ + errno = ENODEV; + return 0; +} + +int unmap(p, len) + char *p; + int len; +{ + errno = EINVAL; + return -1; +} + +#endif /* not HAVE_MMAP */ diff --git a/gnu/usr.bin/groff/libbib/search.cc b/gnu/usr.bin/groff/libbib/search.cc new file mode 100644 index 0000000000..ffdd872123 --- /dev/null +++ b/gnu/usr.bin/groff/libbib/search.cc @@ -0,0 +1,130 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include + +#include "posix.h" +#include "lib.h" +#include "errarg.h" +#include "error.h" + +#include "refid.h" +#include "search.h" + +int linear_truncate_len = 6; +const char *linear_ignore_fields = "XYZ"; + +search_list::search_list() +: list(0), niterators(0), next_fid(1) +{ +} + +search_list::~search_list() +{ + assert(niterators == 0); + while (list) { + search_item *tem = list->next; + delete list; + list = tem; + } +} + +void search_list::add_file(const char *filename, int silent) +{ + search_item *p = make_index_search_item(filename, next_fid); + if (!p) { + int fd = open(filename, O_RDONLY); + if (fd < 0) { + if (!silent) + error("can't open `%1': %2", filename, strerror(errno)); + } + else + p = make_linear_search_item(fd, filename, next_fid); + } + if (p) { + for (search_item **pp = &list; *pp; pp = &(*pp)->next) + ; + *pp = p; + next_fid = p->next_filename_id(); + } +} + +int search_list::nfiles() const +{ + int n = 0; + for (search_item *ptr = list; ptr; ptr = ptr->next) + n++; + return n; +} + +search_list_iterator::search_list_iterator(search_list *p, const char *q) +: list(p), ptr(p->list), iter(0), query(strsave(q)), + searcher(q, strlen(q), linear_ignore_fields, linear_truncate_len) +{ + list->niterators += 1; +} + +search_list_iterator::~search_list_iterator() +{ + list->niterators -= 1; + a_delete query; + delete iter; +} + +int search_list_iterator::next(const char **pp, int *lenp, reference_id *ridp) +{ + while (ptr) { + if (iter == 0) + iter = ptr->make_search_item_iterator(query); + if (iter->next(searcher, pp, lenp, ridp)) + return 1; + delete iter; + iter = 0; + ptr = ptr->next; + } + return 0; +} + +search_item::search_item(const char *nm, int fid) +: next(0), name(strsave(nm)), filename_id(fid) +{ +} + +search_item::~search_item() +{ + a_delete name; +} + +int search_item::is_named(const char *nm) const +{ + return strcmp(name, nm) == 0; +} + +int search_item::next_filename_id() const +{ + return filename_id + 1; +} + +search_item_iterator::~search_item_iterator() +{ +} diff --git a/gnu/usr.bin/groff/libdriver/Makefile b/gnu/usr.bin/groff/libdriver/Makefile new file mode 100644 index 0000000000..926e0679f0 --- /dev/null +++ b/gnu/usr.bin/groff/libdriver/Makefile @@ -0,0 +1,14 @@ +# Makefile for libdriver + +LIB= driver +SRCS= input.cc printer.cc +CFLAGS+= -I$(.CURDIR)/../include + +NOMAN= noman +NOPROFILE= noprofile + +install: + +.include +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/libdriver/Makefile.dep b/gnu/usr.bin/groff/libdriver/Makefile.dep new file mode 100644 index 0000000000..0a675855cd --- /dev/null +++ b/gnu/usr.bin/groff/libdriver/Makefile.dep @@ -0,0 +1,6 @@ +input.o : input.cc ../include/driver.h ../include/errarg.h \ + ../include/error.h ../include/font.h ../include/printer.h \ + ../include/lib.h ../include/device.h +printer.o : printer.cc ../include/driver.h ../include/errarg.h \ + ../include/error.h ../include/font.h ../include/printer.h \ + ../include/lib.h diff --git a/gnu/usr.bin/groff/libdriver/input.cc b/gnu/usr.bin/groff/libdriver/input.cc new file mode 100644 index 0000000000..d046e864e1 --- /dev/null +++ b/gnu/usr.bin/groff/libdriver/input.cc @@ -0,0 +1,473 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "driver.h" +#include "device.h" + +const char *current_filename; +int current_lineno; +const char *device = 0; +FILE *current_file; + +int get_integer(); // don't read the newline +int possibly_get_integer(int *); +char *get_string(int is_long = 0); +void skip_line(); + +struct environment_list { + environment env; + environment_list *next; + + environment_list(const environment &, environment_list *); +}; + +environment_list::environment_list(const environment &e, environment_list *p) +: env(e), next(p) +{ +} + +inline int get_char() +{ + return getc(current_file); +} + +void do_file(const char *filename) +{ + int npages = 0; + if (filename[0] == '-' && filename[1] == '\0') { + current_filename = ""; + current_file = stdin; + } + else { + errno = 0; + current_file = fopen(filename, "r"); + if (current_file == 0) { + error("can't open `%1'", filename); + return; + } + current_filename = filename; + } + environment env; + env.vpos = -1; + env.hpos = -1; + env.fontno = -1; + env.height = 0; + env.slant = 0; + environment_list *env_list = 0; + current_lineno = 1; + int command; + char *s; + command = get_char(); + if (command == EOF) + return; + if (command != 'x') + fatal("the first command must be `x T'"); + s = get_string(); + if (s[0] != 'T') + fatal("the first command must be `x T'"); + char *dev = get_string(); + if (pr == 0) { + device = strsave(dev); + if (!font::load_desc()) + fatal("sorry, I can't continue"); + } + else { + if (device == 0 || strcmp(device, dev) != 0) + fatal("all files must use the same device"); + } + skip_line(); + env.size = 10*font::sizescale; + command = get_char(); + if (command != 'x') + fatal("the second command must be `x res'"); + s = get_string(); + if (s[0] != 'r') + fatal("the second command must be `x res'"); + int n = get_integer(); + if (n != font::res) + fatal("resolution does not match"); + n = get_integer(); + if (n != font::hor) + fatal("horizontal resolution does not match"); + n = get_integer(); + if (n != font::vert) + fatal("vertical resolution does not match"); + skip_line(); + command = get_char(); + if (command != 'x') + fatal("the third command must be `x init'"); + s = get_string(); + if (s[0] != 'i') + fatal("the third command must be `x init'"); + skip_line(); + if (pr == 0) + pr = make_printer(); + while ((command = get_char()) != EOF) { + switch (command) { + case 's': + env.size = get_integer(); + if (env.height == env.size) + env.height = 0; + break; + case 'f': + env.fontno = get_integer(); + break; + case 'C': + { + if (npages == 0) + fatal("`C' command illegal before first `p' command"); + char *s = get_string(); + pr->set_special_char(s, &env); + } + break; + case 'N': + { + if (npages == 0) + fatal("`N' command illegal before first `p' command"); + pr->set_numbered_char(get_integer(), &env); + } + break; + case 'H': + env.hpos = get_integer(); + break; + case 'h': + env.hpos += get_integer(); + break; + case 'V': + env.vpos = get_integer(); + break; + case 'v': + env.vpos += get_integer(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + int c = get_char(); + if (!isascii(c) || !isdigit(c)) + fatal("digit expected"); + env.hpos += (command - '0')*10 + (c - '0'); + } + // fall through + case 'c': + { + if (npages == 0) + fatal("`c' command illegal before first `p' command"); + int c = get_char(); + if (c == EOF) + fatal("missing argument to `c' command"); + pr->set_ascii_char(c, &env); + } + break; + case 'n': + if (npages == 0) + fatal("`n' command illegal before first `p' command"); + pr->end_of_line(); + (void)get_integer(); + (void)get_integer(); + break; + case 'w': + case ' ': + break; + case '\n': + current_lineno++; + break; + case 'p': + if (npages) + pr->end_page(env.vpos); + npages++; + pr->begin_page(get_integer()); + env.vpos = 0; + break; + case '{': + env_list = new environment_list(env, env_list); + break; + case '}': + if (!env_list) { + fatal("can't pop"); + } + else { + env = env_list->env; + environment_list *tem = env_list; + env_list = env_list->next; + delete tem; + } + break; + case 'u': + { + if (npages == 0) + fatal("`u' command illegal before first `p' command"); + int kern = get_integer(); + int c = get_char(); + while (c == ' ') + c = get_char(); + while (c != EOF) { + if (c == '\n') { + current_lineno++; + break; + } + int w; + pr->set_ascii_char(c, &env, &w); + env.hpos += w + kern; + c = get_char(); + if (c == ' ') + break; + } + } + break; + case 't': + { + if (npages == 0) + fatal("`t' command illegal before first `p' command"); + int c; + while ((c = get_char()) != EOF && c != ' ') { + if (c == '\n') { + current_lineno++; + break; + } + int w; + pr->set_ascii_char(c, &env, &w); + env.hpos += w; + } + } + break; + case '#': + skip_line(); + break; + case 'D': + { + if (npages == 0) + fatal("`D' command illegal before first `p' command"); + int c; + while ((c = get_char()) == ' ') + ; + int n; + int *p = 0; + int szp = 0; + for (int np = 0; possibly_get_integer(&n); np++) { + if (np >= szp) { + if (szp == 0) { + szp = 16; + p = new int[szp]; + } + else { + int *oldp = p; + p = new int[szp*2]; + memcpy(p, oldp, szp*sizeof(int)); + szp *= 2; + a_delete oldp; + } + } + p[np] = n; + } + pr->draw(c, p, np, &env); + if (c == 'e') { + if (np > 0) + env.hpos += p[0]; + } + else { + for (int i = 0; i < np/2; i++) { + env.hpos += p[i*2]; + env.vpos += p[i*2 + 1]; + } + // there might be an odd number of characters + if (i*2 < np) + env.hpos += p[i*2]; + } + a_delete p; + skip_line(); + } + break; + case 'x': + { + char *s = get_string(); + int suppress_skip = 0; + switch (s[0]) { + case 'i': + error("duplicate `x init' command"); + break; + case 'T': + error("duplicate `x T' command"); + break; + case 'r': + error("duplicate `x res' command"); + break; + case 'p': + break; + case 's': + break; + case 't': + break; + case 'f': + { + int n = get_integer(); + char *name = get_string(); + pr->load_font(n, name); + } + break; + case 'H': + env.height = get_integer(); + if (env.height == env.size) + env.height = 0; + break; + case 'S': + env.slant = get_integer(); + break; + case 'X': + if (npages == 0) + fatal("`x X' command illegal before first `p' command"); + pr->special(get_string(1), &env); + suppress_skip = 1; + break; + default: + error("unrecognised x command `%1'", s); + } + if (!suppress_skip) + skip_line(); + } + break; + default: + error("unrecognised command code %1", int(command)); + skip_line(); + break; + } + } + if (npages) + pr->end_page(env.vpos); +} + +int get_integer() +{ + int c = get_char(); + while (c == ' ') + c = get_char(); + int neg = 0; + if (c == '-') { + neg = 1; + c = get_char(); + } + if (!isascii(c) || !isdigit(c)) + fatal("integer expected"); + int total = 0; + do { + total = total*10; + if (neg) + total -= c - '0'; + else + total += c - '0'; + c = get_char(); + } while (isascii(c) && isdigit(c)); + if (c != EOF) + ungetc(c, current_file); + return total; +} + +int possibly_get_integer(int *res) +{ + int c = get_char(); + while (c == ' ') + c = get_char(); + int neg = 0; + if (c == '-') { + neg = 1; + c = get_char(); + } + if (!isascii(c) || !isdigit(c)) { + if (c != EOF) + ungetc(c, current_file); + return 0; + } + int total = 0; + do { + total = total*10; + if (neg) + total -= c - '0'; + else + total += c - '0'; + c = get_char(); + } while (isascii(c) && isdigit(c)); + if (c != EOF) + ungetc(c, current_file); + *res = total; + return 1; +} + + +char *get_string(int is_long) +{ + static char *buf; + static int buf_size; + int c = get_char(); + while (c == ' ') + c = get_char(); + for (int i = 0;; i++) { + if (i >= buf_size) { + if (buf_size == 0) { + buf_size = 16; + buf = new char[buf_size]; + } + else { + char *old_buf = buf; + int old_size = buf_size; + buf_size *= 2; + buf = new char[buf_size]; + memcpy(buf, old_buf, old_size); + a_delete old_buf; + } + } + if ((!is_long && (c == ' ' || c == '\n')) || c == EOF) { + buf[i] = '\0'; + break; + } + if (is_long && c == '\n') { + current_lineno++; + c = get_char(); + if (c == '+') + c = '\n'; + else { + buf[i] = '\0'; + break; + } + } + buf[i] = c; + c = get_char(); + } + if (c != EOF) + ungetc(c, current_file); + return buf; +} + +void skip_line() +{ + int c; + while ((c = get_char()) != EOF) + if (c == '\n') { + current_lineno++; + break; + } +} + diff --git a/gnu/usr.bin/groff/libdriver/printer.cc b/gnu/usr.bin/groff/libdriver/printer.cc new file mode 100644 index 0000000000..f7e0b5fc43 --- /dev/null +++ b/gnu/usr.bin/groff/libdriver/printer.cc @@ -0,0 +1,240 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "driver.h" + +printer *pr = 0; + +font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp) +: p(f), next(fp) +{ +} + +printer::printer() +: font_table(0), nfonts(0), font_list(0) +{ +} + +printer::~printer() +{ + a_delete font_table; + while (font_list) { + font_pointer_list *tem = font_list; + font_list = font_list->next; + delete tem->p; + delete tem; + } + if (ferror(stdout) || fflush(stdout) < 0) + fatal("output error"); +} + +void printer::load_font(int n, const char *nm) +{ + assert(n >= 0); + if (n >= nfonts) { + if (nfonts == 0) { + nfonts = 10; + if (nfonts <= n) + nfonts = n + 1; + font_table = new font *[nfonts]; + for (int i = 0; i < nfonts; i++) + font_table[i] = 0; + } + else { + font **old_font_table = font_table; + int old_nfonts = nfonts; + nfonts *= 2; + if (n >= nfonts) + nfonts = n + 1; + font_table = new font *[nfonts]; + for (int i = 0; i < old_nfonts; i++) + font_table[i] = old_font_table[i]; + for (i = old_nfonts; i < nfonts; i++) + font_table[i] = 0; + a_delete old_font_table; + } + } + font *f = find_font(nm); + font_table[n] = f; +} + +font *printer::find_font(const char *nm) +{ + for (font_pointer_list *p = font_list; p; p = p->next) + if (strcmp(p->p->get_name(), nm) == 0) + return p->p; + font *f = make_font(nm); + if (!f) + fatal("sorry, I can't continue"); + font_list = new font_pointer_list(f, font_list); + return f; +} + +font *printer::make_font(const char *nm) +{ + return font::load_font(nm); +} + +void printer::end_of_line() +{ +} + +void printer::special(char *, const environment *) +{ +} + +void printer::draw(int, int *, int, const environment *) +{ +} + +void printer::set_ascii_char(unsigned char c, const environment *env, + int *widthp) +{ + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + set_special_char(buf, env, widthp); +} + +void printer::set_special_char(const char *nm, const environment *env, + int *widthp) +{ + int i = font::name_to_index(nm); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("bad font position `%1'", fn); + return; + } + font *f = font_table[fn]; + if (f == 0) { + error("no font mounted at `%1'", fn); + return; + } + if (!f->contains(i)) { + if (nm[0] != '\0' && nm[1] == '\0') + error("font `%1' does not contain ascii character `%2'", + f->get_name(), + nm[0]); + else + error("font `%1' does not contain special character `%2'", + f->get_name(), + nm); + return; + } + int w = f->get_width(i, env->size); + if (widthp) + *widthp = w; + set_char(i, f, env, w); +} + +void printer::set_numbered_char(int num, const environment *env, int *widthp) +{ + int i = font::number_to_index(num); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("bad font position `%1'", fn); + return; + } + font *f = font_table[fn]; + if (f == 0) { + error("no font mounted at `%1'", fn); + return; + } + if (!f->contains(i)) { + error("font `%1' does not contain numbered character %2", + f->get_name(), + num); + return; + } + int w = f->get_width(i, env->size); + if (widthp) + *widthp = w; + set_char(i, f, env, w); +} + +// This utility function adjusts the specified center of the +// arc so that it is equidistant between the specified start +// and end points. (p[0], p[1]) is a vector from the current +// point to the center; (p[2], p[3]) is a vector from the +// center to the end point. If the center can be adjusted, +// a vector from the current point to the adjusted center is +// stored in c[0], c[1] and 1 is returned. Otherwise 0 is +// returned. + +#if 1 +int printer::adjust_arc_center(const int *p, double *c) +{ + // We move the center along a line parallel to the line between + // the specified start point and end point so that the center + // is equidistant between the start and end point. + // It can be proved (using Lagrange multipliers) that this will + // give the point nearest to the specified center that is equidistant + // between the start and end point. + + double x = p[0] + p[2]; // (x, y) is the end point + double y = p[1] + p[3]; + double n = x*x + y*y; + if (n != 0) { + c[0]= double(p[0]); + c[1] = double(p[1]); + double k = .5 - (c[0]*x + c[1]*y)/n; + c[0] += k*x; + c[1] += k*y; + return 1; + } + else + return 0; +} +#else +int printer::adjust_arc_center(const int *p, double *c) +{ + int x = p[0] + p[2]; // (x, y) is the end point + int y = p[1] + p[3]; + // Start at the current point; go in the direction of the specified + // center point until we reach a point that is equidistant between + // the specified starting point and the specified end point. Place + // the center of the arc there. + double n = p[0]*double(x) + p[1]*double(y); + if (n > 0) { + double k = (double(x)*x + double(y)*y)/(2.0*n); + // (cx, cy) is our chosen center + c[0] = k*p[0]; + c[1] = k*p[1]; + return 1; + } + else { + // We would never reach such a point. So instead start at the + // specified end point of the arc. Go towards the specified + // center point until we reach a point that is equidistant between + // the specified start point and specified end point. Place + // the center of the arc there. + n = p[2]*double(x) + p[3]*double(y); + if (n > 0) { + double k = 1 - (double(x)*x + double(y)*y)/(2.0*n); + // (c[0], c[1]) is our chosen center + c[0] = p[0] + k*p[2]; + c[1] = p[1] + k*p[3]; + return 1; + } + else + return 0; + } +} +#endif diff --git a/gnu/usr.bin/groff/libgroff/Makefile b/gnu/usr.bin/groff/libgroff/Makefile new file mode 100644 index 0000000000..6e2006ce56 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/Makefile @@ -0,0 +1,24 @@ +# Makefile for libgroff + +LIB= groff +SRCS= assert.cc change_lf.cc cmap.cc cset.cc device.cc errarg.cc\ + error.cc fatal.cc filename.cc font.cc fontfile.cc lf.cc\ + lineno.cc macropath.cc nametoindex.cc new.cc prime.cc\ + progname.cc ptable.cc searchpath.cc string.cc strsave.cc\ + tmpfile.cc illegal.cc version.cc +SRCS+= iftoa.c itoa.c matherr.c +CFLAGS+= -I$(.CURDIR)/../include + +NOMAN= noman +NOPROFILE= noprofile + +CLEANFILES+= version.cc +version.cc: $(.CURDIR)/../VERSION + @echo Making version.cc + @echo const char \*version_string = \"`cat $(.CURDIR)/../VERSION`\"\; >$@ + +install: + +.include +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/libgroff/Makefile.dep b/gnu/usr.bin/groff/libgroff/Makefile.dep new file mode 100644 index 0000000000..f135af7ddc --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/Makefile.dep @@ -0,0 +1,39 @@ +assert.o : assert.cc ../include/assert.h +change_lf.o : change_lf.cc +cmap.o : cmap.cc ../include/cmap.h +cset.o : cset.cc ../include/cset.h +device.o : device.cc ../include/device.h ../include/defs.h +errarg.o : errarg.cc ../include/assert.h ../include/errarg.h +error.o : error.cc ../include/errarg.h ../include/error.h +fatal.o : fatal.cc +filename.o : filename.cc +font.o : font.cc ../include/errarg.h ../include/error.h ../include/cset.h \ + ../include/font.h ../include/lib.h +fontfile.o : fontfile.cc ../include/font.h ../include/lib.h \ + ../include/searchpath.h ../include/device.h ../include/defs.h +lf.o : lf.cc ../include/cset.h ../include/stringclass.h +lineno.o : lineno.cc +macropath.o : macropath.cc ../include/lib.h ../include/searchpath.h \ + ../include/macropath.h ../include/defs.h +nametoindex.o : nametoindex.cc ../include/lib.h ../include/errarg.h \ + ../include/error.h ../include/font.h ../include/ptable.h +new.o : new.cc ../include/posix.h +prime.o : prime.cc +progname.o : progname.cc +ptable.o : ptable.cc ../include/ptable.h ../include/errarg.h \ + ../include/error.h +searchpath.o : searchpath.cc ../include/lib.h ../include/searchpath.h +string.o : string.cc ../include/stringclass.h ../include/lib.h +strsave.o : strsave.cc +tmpfile.o : tmpfile.cc ../include/posix.h ../include/lib.h \ + ../include/errarg.h ../include/error.h +version.o : version.cc +illegal.o : illegal.cc ../include/lib.h +fmod.o : fmod.c +getcwd.o : getcwd.c +iftoa.o : iftoa.c +itoa.o : itoa.c +matherr.o : matherr.c +strerror.o : strerror.c +strtol.o : strtol.c +putenv.o : putenv.c diff --git a/gnu/usr.bin/groff/libgroff/assert.cc b/gnu/usr.bin/groff/libgroff/assert.cc new file mode 100644 index 0000000000..1dc0745168 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/assert.cc @@ -0,0 +1,39 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { +#include +#include +} +#include "assert.h" + +extern const char *program_name; + +#ifdef __GNUG__ +volatile +#endif +void assertion_failed(int lineno, const char *filename) +{ + if (program_name != 0) + fprintf(stderr, "%s: ", program_name); + fprintf(stderr, "Failed assertion at line %d, file `%s'.\n", + lineno, filename); + fflush(stderr); + abort(); +} diff --git a/gnu/usr.bin/groff/libgroff/change_lf.cc b/gnu/usr.bin/groff/libgroff/change_lf.cc new file mode 100644 index 0000000000..34ee6a04ce --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/change_lf.cc @@ -0,0 +1,39 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { +#include +} + +extern char *strsave(const char *); + +extern const char *current_filename; +extern int current_lineno; + +void change_filename(const char *f) +{ + if (current_filename != 0 && strcmp(current_filename, f) == 0) + return; + current_filename = strsave(f); +} + +void change_lineno(int ln) +{ + current_lineno = ln; +} diff --git a/gnu/usr.bin/groff/libgroff/cmap.cc b/gnu/usr.bin/groff/libgroff/cmap.cc new file mode 100644 index 0000000000..4b1a43e22b --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/cmap.cc @@ -0,0 +1,55 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "cmap.h" + +cmap cmlower(CMAP_BUILTIN); +cmap cmupper(CMAP_BUILTIN); + +#define ISASCII(c) isascii(c) +#if 0 +#define ISASCII(c) 1 /* use this is you have an ANSI ctype.h */ +#endif + +cmap::cmap() +{ + unsigned char *p = v; + for (int i = 0; i <= UCHAR_MAX; i++) + p[i] = i; +} + +cmap::cmap(cmap_builtin) +{ + // these are initialised by cmap_init::cmap_init() +} + +int cmap_init::initialised = 0; + +cmap_init::cmap_init() +{ + if (initialised) + return; + initialised = 1; + for (int i = 0; i <= UCHAR_MAX; i++) { + cmupper.v[i] = ISASCII(i) && islower(i) ? toupper(i) : i; + cmlower.v[i] = ISASCII(i) && isupper(i) ? tolower(i) : i; + } +} diff --git a/gnu/usr.bin/groff/libgroff/cset.cc b/gnu/usr.bin/groff/libgroff/cset.cc new file mode 100644 index 0000000000..9fe44d9b7b --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/cset.cc @@ -0,0 +1,101 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "cset.h" + +cset csalpha(CSET_BUILTIN); +cset csupper(CSET_BUILTIN); +cset cslower(CSET_BUILTIN); +cset csdigit(CSET_BUILTIN); +cset csxdigit(CSET_BUILTIN); +cset csspace(CSET_BUILTIN); +cset cspunct(CSET_BUILTIN); +cset csalnum(CSET_BUILTIN); +cset csprint(CSET_BUILTIN); +cset csgraph(CSET_BUILTIN); +cset cscntrl(CSET_BUILTIN); + +#define ISASCII(c) isascii(c) +#if 0 +#define ISASCII(c) 1 /* use this is you have an ANSI ctype.h */ +#endif + +void cset::clear() +{ + char *p = v; + for (int i = 0; i <= UCHAR_MAX; i++) + p[i] = 0; +} + +cset::cset() +{ + clear(); +} + +cset::cset(const char *s) +{ + clear(); + while (*s) + v[(unsigned char)*s++] = 1; +} + +cset::cset(const unsigned char *s) +{ + clear(); + while (*s) + v[*s++] = 1; +} + +cset::cset(cset_builtin) +{ + // these are initialised by cset_init::cset_init() +} + +cset &cset::operator|=(const cset &cs) +{ + for (int i = 0; i <= UCHAR_MAX; i++) + if (cs.v[i]) + v[i] = 1; + return *this; +} + + +int cset_init::initialised = 0; + +cset_init::cset_init() +{ + if (initialised) + return; + initialised = 1; + for (int i = 0; i <= UCHAR_MAX; i++) { + csalpha.v[i] = ISASCII(i) && isalpha(i); + csupper.v[i] = ISASCII(i) && isupper(i); + cslower.v[i] = ISASCII(i) && islower(i); + csdigit.v[i] = ISASCII(i) && isdigit(i); + csxdigit.v[i] = ISASCII(i) && isxdigit(i); + csspace.v[i] = ISASCII(i) && isspace(i); + cspunct.v[i] = ISASCII(i) && ispunct(i); + csalnum.v[i] = ISASCII(i) && isalnum(i); + csprint.v[i] = ISASCII(i) && isprint(i); + csgraph.v[i] = ISASCII(i) && isgraph(i); + cscntrl.v[i] = ISASCII(i) && iscntrl(i); + } +} diff --git a/gnu/usr.bin/groff/libgroff/device.cc b/gnu/usr.bin/groff/libgroff/device.cc new file mode 100644 index 0000000000..84a26259e9 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/device.cc @@ -0,0 +1,38 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { +#include +} +#include "device.h" +#include "defs.h" + +const char *device = DEVICE; + +struct device_init { + device_init(); +} _device_init; + +device_init::device_init() +{ + char *tem = getenv("GROFF_TYPESETTER"); + if (tem) + device = tem; +} diff --git a/gnu/usr.bin/groff/libgroff/errarg.cc b/gnu/usr.bin/groff/libgroff/errarg.cc new file mode 100644 index 0000000000..7598c8d91a --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/errarg.cc @@ -0,0 +1,120 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { +#include +} +#include "assert.h" +#include "errarg.h" + +errarg::errarg(const char *p) : type(STRING) +{ + s = p ? p : "(null)"; +} + +errarg::errarg() : type(EMPTY) +{ +} + +errarg::errarg(unsigned char cc) : type(CHAR) +{ + c = cc; +} + +errarg::errarg(int nn) : type(INTEGER) +{ + n = nn; +} + +errarg::errarg(char cc) : type(CHAR) +{ + c = cc; +} + +errarg::errarg(double dd) : type(DOUBLE) +{ + d = dd; +} + +int errarg::empty() const +{ + return type == EMPTY; +} + +extern "C" { + const char *itoa(int); +} + +void errarg::print() const +{ + switch (type) { + case INTEGER: + fputs(itoa(n), stderr); + break; + case CHAR: + putc(c, stderr); + break; + case STRING: + fputs(s, stderr); + break; + case DOUBLE: + fprintf(stderr, "%g", d); + break; + case EMPTY: + break; + } +} + +errarg empty_errarg; + +void errprint(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + assert(format != 0); + char c; + while ((c = *format++) != '\0') { + if (c == '%') { + c = *format++; + switch(c) { + case '%': + fputc('%', stderr); + break; + case '1': + assert(!arg1.empty()); + arg1.print(); + break; + case '2': + assert(!arg2.empty()); + arg2.print(); + break; + case '3': + assert(!arg3.empty()); + arg3.print(); + break; + default: + assert(0); + } + } + else + putc(c, stderr); + } +} diff --git a/gnu/usr.bin/groff/libgroff/error.cc b/gnu/usr.bin/groff/libgroff/error.cc new file mode 100644 index 0000000000..adf02d4a02 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/error.cc @@ -0,0 +1,139 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { +#include +#include +#include +} +#include "errarg.h" +#include "error.h" + +extern void fatal_error_exit(); + +enum error_type { WARNING, ERROR, FATAL }; + +static void do_error_with_file_and_line(const char *filename, int lineno, + error_type type, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + int need_space = 0; + if (program_name) { + fprintf(stderr, "%s:", program_name); + need_space = 1; + } + if (lineno >= 0 && filename != 0) { + if (strcmp(filename, "-") == 0) + filename = ""; + fprintf(stderr, "%s:%d:", filename, lineno); + need_space = 1; + } + switch (type) { + case FATAL: + fputs("fatal error:", stderr); + need_space = 1; + break; + case ERROR: + break; + case WARNING: + fputs("warning:", stderr); + need_space = 1; + break; + } + if (need_space) + fputc(' ', stderr); + errprint(format, arg1, arg2, arg3); + fputc('\n', stderr); + fflush(stderr); + if (type == FATAL) + fatal_error_exit(); +} + + +static void do_error(error_type type, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(current_filename, current_lineno, + type, format, arg1, arg2, arg3); +} + + +void error(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(ERROR, format, arg1, arg2, arg3); +} + +void warning(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(WARNING, format, arg1, arg2, arg3); +} + +void fatal(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(FATAL, format, arg1, arg2, arg3); +} + +void error_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, lineno, + ERROR, format, arg1, arg2, arg3); +} + +void warning_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, lineno, + WARNING, format, arg1, arg2, arg3); +} + +void fatal_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, lineno, + FATAL, format, arg1, arg2, arg3); +} diff --git a/gnu/usr.bin/groff/libgroff/fatal.cc b/gnu/usr.bin/groff/libgroff/fatal.cc new file mode 100644 index 0000000000..7ab5b07dbd --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/fatal.cc @@ -0,0 +1,29 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { +#include +} + +#define FATAL_ERROR_EXIT_CODE 3 + +void fatal_error_exit() +{ + exit(FATAL_ERROR_EXIT_CODE); +} diff --git a/gnu/usr.bin/groff/libgroff/filename.cc b/gnu/usr.bin/groff/libgroff/filename.cc new file mode 100644 index 0000000000..1cbaa93ddd --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/filename.cc @@ -0,0 +1 @@ +const char *current_filename = 0; diff --git a/gnu/usr.bin/groff/libgroff/fmod.c b/gnu/usr.bin/groff/libgroff/fmod.c new file mode 100644 index 0000000000..74c5c36b68 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/fmod.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +double fmod(x, y) + double x, y; +{ + double quot = x/y; + return x - (quot < 0.0 ? ceil(quot) : floor(quot)) * y; +} + diff --git a/gnu/usr.bin/groff/libgroff/font.cc b/gnu/usr.bin/groff/libgroff/font.cc new file mode 100644 index 0000000000..f360d4bc6b --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/font.cc @@ -0,0 +1,907 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include "errarg.h" +#include "error.h" +#include "cset.h" +#include "font.h" +#include "lib.h" + +const char *const WS = " \t\n\r"; + +struct font_char_metric { + char type; + int code; + int width; + int height; + int depth; + int pre_math_space; + int italic_correction; + int subscript_correction; +}; + +struct font_kern_list { + int i1; + int i2; + int amount; + font_kern_list *next; + + font_kern_list(int, int, int, font_kern_list * = 0); +}; + +struct font_widths_cache { + font_widths_cache *next; + int point_size; + int *width; + + font_widths_cache(int, int, font_widths_cache *); + ~font_widths_cache(); +}; + +/* text_file */ + +struct text_file { + FILE *fp; + char *path; + int lineno; + int size; + int skip_comments; + char *buf; + text_file(FILE *fp, char *p); + ~text_file(); + int next(); + void error(const char *format, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); +}; + +text_file::text_file(FILE *p, char *s) +: lineno(0), buf(0), size(0), skip_comments(1), fp(p), path(s) +{ +} + +text_file::~text_file() +{ + a_delete buf; + a_delete path; + if (fp) + fclose(fp); +} + + +int text_file::next() +{ + if (fp == 0) + return 0; + if (buf == 0) { + buf = new char [128]; + size = 128; + } + for (;;) { + int i = 0; + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + if (illegal_input_char(c)) + error("illegal input character code `%1'", int(c)); + else { + if (i + 1 >= size) { + char *old_buf = buf; + buf = new char[size*2]; + memcpy(buf, old_buf, size); + a_delete old_buf; + size *= 2; + } + buf[i++] = c; + if (c == '\n') + break; + } + } + if (i == 0) + break; + buf[i] = '\0'; + lineno++; + char *ptr = buf; + while (csspace(*ptr)) + ptr++; + if (*ptr != 0 && (!skip_comments || *ptr != '#')) + return 1; + } + return 0; +} + +void text_file::error(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + error_with_file_and_line(path, lineno, format, arg1, arg2, arg3); +} + + +/* font functions */ + +font::font(const char *s) +: special(0), ligatures(0), kern_hash_table(0), space_width(0), + ch(0), ch_used(0), ch_size(0), ch_index(0), nindices(0), widths_cache(0) +{ + name = new char[strlen(s) + 1]; + strcpy(name, s); + internalname = 0; + slant = 0.0; + // load(); // for testing +} + +font::~font() +{ + a_delete ch; + a_delete ch_index; + if (kern_hash_table) { + for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) { + font_kern_list *kerns = kern_hash_table[i]; + while (kerns) { + font_kern_list *tem = kerns; + kerns = kerns->next; + delete tem; + } + } + a_delete kern_hash_table; + } + a_delete name; + a_delete internalname; + while (widths_cache) { + font_widths_cache *tem = widths_cache; + widths_cache = widths_cache->next; + delete tem; + } +} + +static int scale_round(int n, int x, int y) +{ + assert(x >= 0 && y > 0); + int y2 = y/2; + if (x == 0) + return 0; + if (n >= 0) { + if (n <= (INT_MAX - y2)/x) + return (n*x + y2)/y; + return int(n*double(x)/double(y) + .5); + } + else { + if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x) + return (n*x - y2)/y; + return int(n*double(x)/double(y) - .5); + } +} + +inline int font::scale(int w, int sz) +{ + return sz == unitwidth ? w : scale_round(w, sz, unitwidth); +} + +int font::get_skew(int c, int point_size, int sl) +{ + int h = get_height(c, point_size); + return int(h*tan((slant+sl)*M_PI/180.0) + .5); +} + +int font::contains(int c) +{ + return c >= 0 && c < nindices && ch_index[c] >= 0; +} + +int font::is_special() +{ + return special; +} + +font_widths_cache::font_widths_cache(int ps, int ch_size, + font_widths_cache *p = 0) +: next(p), point_size(ps) +{ + width = new int[ch_size]; + for (int i = 0; i < ch_size; i++) + width[i] = -1; +} + +font_widths_cache::~font_widths_cache() +{ + a_delete width; +} + +int font::get_width(int c, int point_size) +{ + assert(c >= 0 && c < nindices); + int i = ch_index[c]; + assert(i >= 0); + + if (point_size == unitwidth) + return ch[i].width; + + if (!widths_cache) + widths_cache = new font_widths_cache(point_size, ch_size); + else if (widths_cache->point_size != point_size) { + for (font_widths_cache **p = &widths_cache; *p; p = &(*p)->next) + if ((*p)->point_size == point_size) + break; + if (*p) { + font_widths_cache *tem = *p; + *p = (*p)->next; + tem->next = widths_cache; + widths_cache = tem; + } + else + widths_cache = new font_widths_cache(point_size, ch_size, widths_cache); + } + int &w = widths_cache->width[i]; + if (w < 0) + w = scale(ch[i].width, point_size); + return w; +} + +int font::get_height(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].height, point_size); +} + +int font::get_depth(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].depth, point_size); +} + +int font::get_italic_correction(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].italic_correction, point_size); +} + +int font::get_left_italic_correction(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].pre_math_space, point_size); +} + +int font::get_subscript_correction(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].subscript_correction, point_size); +} + +int font::get_space_width(int point_size) +{ + return scale(space_width, point_size); +} + +font_kern_list::font_kern_list(int c1, int c2, int n, font_kern_list *p) + : i1(c1), i2(c2), amount(n), next(p) +{ +} + +inline int font::hash_kern(int i1, int i2) +{ + int n = ((i1 << 10) + i2) % KERN_HASH_TABLE_SIZE; + return n < 0 ? -n : n; +} + +void font::add_kern(int i1, int i2, int amount) +{ + if (!kern_hash_table) { + kern_hash_table = new font_kern_list *[KERN_HASH_TABLE_SIZE]; + for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) + kern_hash_table[i] = 0; + } + font_kern_list **p = kern_hash_table + hash_kern(i1, i2); + *p = new font_kern_list(i1, i2, amount, *p); +} + +int font::get_kern(int i1, int i2, int point_size) +{ + if (kern_hash_table) { + for (font_kern_list *p = kern_hash_table[hash_kern(i1, i2)]; p; p = p->next) + if (i1 == p->i1 && i2 == p->i2) + return scale(p->amount, point_size); + } + return 0; +} + +int font::has_ligature(int mask) +{ + return mask & ligatures; +} + +int font::get_character_type(int c) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return ch[ch_index[c]].type; +} + +int font::get_code(int c) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return ch[ch_index[c]].code; +} + +const char *font::get_name() +{ + return name; +} + +const char *font::get_internal_name() +{ + return internalname; +} + +void font::alloc_ch_index(int index) +{ + if (nindices == 0) { + nindices = 128; + if (index >= nindices) + nindices = index + 10; + ch_index = new short[nindices]; + for (int i = 0; i < nindices; i++) + ch_index[i] = -1; + } + else { + int old_nindices = nindices; + nindices *= 2; + if (index >= nindices) + nindices = index + 10; + short *old_ch_index = ch_index; + ch_index = new short[nindices]; + memcpy(ch_index, old_ch_index, sizeof(short)*old_nindices); + for (int i = old_nindices; i < nindices; i++) + ch_index[i] = -1; + a_delete old_ch_index; + } +} + +void font::extend_ch() +{ + if (ch == 0) + ch = new font_char_metric[ch_size = 16]; + else { + int old_ch_size = ch_size; + ch_size *= 2; + font_char_metric *old_ch = ch; + ch = new font_char_metric[ch_size]; + memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric)); + a_delete old_ch; + } +} + +void font::compact() +{ + for (int i = nindices - 1; i >= 0; i--) + if (ch_index[i] >= 0) + break; + i++; + if (i < nindices) { + short *old_ch_index = ch_index; + ch_index = new short[i]; + memcpy(ch_index, old_ch_index, i*sizeof(short)); + a_delete old_ch_index; + nindices = i; + } + if (ch_used < ch_size) { + font_char_metric *old_ch = ch; + ch = new font_char_metric[ch_used]; + memcpy(ch, old_ch, ch_used*sizeof(font_char_metric)); + a_delete old_ch; + ch_size = ch_used; + } +} + +void font::add_entry(int index, const font_char_metric &metric) +{ + assert(index >= 0); + if (index >= nindices) + alloc_ch_index(index); + assert(index < nindices); + if (ch_used + 1 >= ch_size) + extend_ch(); + assert(ch_used + 1 < ch_size); + ch_index[index] = ch_used; + ch[ch_used++] = metric; +} + +void font::copy_entry(int new_index, int old_index) +{ + assert(new_index >= 0 && old_index >= 0 && old_index < nindices); + if (new_index >= nindices) + alloc_ch_index(new_index); + ch_index[new_index] = ch_index[old_index]; +} + +font *font::load_font(const char *s, int *not_found) +{ + font *f = new font(s); + if (!f->load(not_found)) { + delete f; + return 0; + } + return f; +} + +static char *trim_arg(char *p) +{ + if (!p) + return 0; + while (csspace(*p)) + p++; + char *q = strchr(p, '\0'); + while (q > p && csspace(q[-1])) + q--; + *q = '\0'; + return p; +} + +// If the font can't be found, then if not_found is NULL it will be set +// to 1 otherwise a message will be printed. + +int font::load(int *not_found) +{ + char *path; + FILE *fp; + if ((fp = open_file(name, &path)) == NULL) { + if (not_found) + *not_found = 1; + else + error("can't find font file `%1'", name); + return 0; + } + text_file t(fp, path); + t.skip_comments = 1; + char *p; + for (;;) { + if (!t.next()) { + t.error("missing charset command"); + return 0; + } + p = strtok(t.buf, WS); + if (strcmp(p, "name") == 0) { + } + else if (strcmp(p, "spacewidth") == 0) { + p = strtok(0, WS); + int n; + if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) { + t.error("bad argument for spacewidth command"); + return 0; + } + space_width = n; + } + else if (strcmp(p, "slant") == 0) { + p = strtok(0, WS); + double n; + if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) { + t.error("bad argument for slant command", p); + return 0; + } + slant = n; + } + else if (strcmp(p, "ligatures") == 0) { + for (;;) { + p = strtok(0, WS); + if (p == 0 || strcmp(p, "0") == 0) + break; + if (strcmp(p, "ff") == 0) + ligatures |= LIG_ff; + else if (strcmp(p, "fi") == 0) + ligatures |= LIG_fi; + else if (strcmp(p, "fl") == 0) + ligatures |= LIG_fl; + else if (strcmp(p, "ffi") == 0) + ligatures |= LIG_ffi; + else if (strcmp(p, "ffl") == 0) + ligatures |= LIG_ffl; + else { + t.error("unrecognised ligature `%1'", p); + return 0; + } + } + } + else if (strcmp(p, "internalname") == 0) { + p = strtok(0, WS); + if (!p) { + t.error("`internalname command requires argument"); + return 0; + } + internalname = new char[strlen(p) + 1]; + strcpy(internalname, p); + } + else if (strcmp(p, "special") == 0) { + special = 1; + } + else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) { + char *command = p; + p = strtok(0, "\n"); + handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno); + } + else + break; + } + char *command = p; + int had_charset = 0; + t.skip_comments = 0; + while (command) { + if (strcmp(command, "kernpairs") == 0) { + for (;;) { + if (!t.next()) { + command = 0; + break; + } + char *c1 = strtok(t.buf, WS); + if (c1 == 0) + continue; + char *c2 = strtok(0, WS); + if (c2 == 0) { + command = c1; + break; + } + p = strtok(0, WS); + if (p == 0) { + t.error("missing kern amount"); + return 0; + } + int n; + if (sscanf(p, "%d", &n) != 1) { + t.error("bad kern amount `%1'", p); + return 0; + } + int i1 = name_to_index(c1); + if (i1 < 0) { + t.error("illegal character `%1'", c1); + return 0; + } + int i2 = name_to_index(c2); + if (i2 < 0) { + t.error("illegal character `%1'", c2); + return 0; + } + add_kern(i1, i2, n); + } + } + else if (strcmp(command, "charset") == 0) { + had_charset = 1; + int last_index = -1; + for (;;) { + if (!t.next()) { + command = 0; + break; + } + char *nm = strtok(t.buf, WS); + if (nm == 0) + continue; // I dont think this should happen + p = strtok(0, WS); + if (p == 0) { + command = nm; + break; + } + if (p[0] == '"') { + if (last_index == -1) { + t.error("first charset entry is duplicate"); + return 0; + } + if (strcmp(nm, "---") == 0) { + t.error("unnamed character cannot be duplicate"); + return 0; + } + int index = name_to_index(nm); + if (index < 0) { + t.error("illegal character `%1'", nm); + return 0; + } + copy_entry(index, last_index); + } + else { + font_char_metric metric; + metric.height = 0; + metric.depth = 0; + metric.pre_math_space = 0; + metric.italic_correction = 0; + metric.subscript_correction = 0; + int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d", + &metric.width, &metric.height, &metric.depth, + &metric.italic_correction, + &metric.pre_math_space, + &metric.subscript_correction); + if (nparms < 1) { + t.error("bad width for `%1'", nm); + return 0; + } + p = strtok(0, WS); + if (p == 0) { + t.error("missing character type for `%1'", nm); + return 0; + } + int type; + if (sscanf(p, "%d", &type) != 1) { + t.error("bad character type for `%1'", nm); + return 0; + } + if (type < 0 || type > 255) { + t.error("character code `%1' out of range", type); + return 0; + } + metric.type = type; + p = strtok(0, WS); + if (p == 0) { + t.error("missing code for `%1'", nm); + return 0; + } + char *ptr; + metric.code = (int)strtol(p, &ptr, 0); + if (metric.code == 0 && ptr == p) { + t.error("bad code `%1' for character `%2'", p, nm); + return 0; + } + if (strcmp(nm, "---") == 0) { + last_index = number_to_index(metric.code); + add_entry(last_index, metric); + } + else { + last_index = name_to_index(nm); + if (last_index < 0) { + t.error("illegal character `%1'", nm); + return 0; + } + add_entry(last_index, metric); + copy_entry(number_to_index(metric.code), last_index); + } + } + } + if (last_index == -1) { + t.error("I didn't seem to find any characters"); + return 0; + } + } + else { + t.error("unrecognised command `%1' after `kernpairs' or `charset' command", command); + return 0; + } + } + if (!had_charset) { + t.error("missing charset command"); + return 0; + } + if (space_width == 0) + space_width = scale_round(unitwidth, res, 72*3*sizescale); + compact(); + return 1; +} + +static struct { + const char *command; + int *ptr; +} table[] = { + "res", &font::res, + "hor", &font::hor, + "vert", &font::vert, + "unitwidth", &font::unitwidth, + "paperwidth", &font::paperwidth, + "paperlength", &font::paperlength, + "spare1", &font::biggestfont, + "biggestfont", &font::biggestfont, + "spare2", &font::spare2, + "sizescale", &font::sizescale + }; + + +int font::load_desc() +{ + int nfonts = 0; + FILE *fp; + char *path; + if ((fp = open_file("DESC", &path)) == 0) { + error("can't find `DESC' file"); + return 0; + } + text_file t(fp, path); + t.skip_comments = 1; + res = 0; + while (t.next()) { + char *p = strtok(t.buf, WS); + int found = 0; + for (int i = 0; !found && i < sizeof(table)/sizeof(table[0]); i++) + if (strcmp(table[i].command, p) == 0) + found = 1; + if (found) { + char *q = strtok(0, WS); + if (!q) { + t.error("missing value for command `%1'", p); + return 0; + } + //int *ptr = &(this->*(table[i-1].ptr)); + int *ptr = table[i-1].ptr; + if (sscanf(q, "%d", ptr) != 1) { + t.error("bad number `%1'", q); + return 0; + } + } + else if (strcmp("tcommand", p) == 0) { + tcommand = 1; + } + else if (strcmp("family", p) == 0) { + p = strtok(0, WS); + if (!p) { + t.error("family command requires an argument"); + return 0; + } + char *tem = new char[strlen(p)+1]; + strcpy(tem, p); + family = tem; + } + else if (strcmp("fonts", p) == 0) { + p = strtok(0, WS); + if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) { + t.error("bad number of fonts `%1'", p); + return 0; + } + font_name_table = (const char **)new char *[nfonts+1]; + for (int i = 0; i < nfonts; i++) { + p = strtok(0, WS); + while (p == 0) { + if (!t.next()) { + t.error("end of file while reading list of fonts"); + return 0; + } + p = strtok(t.buf, WS); + } + char *temp = new char[strlen(p)+1]; + strcpy(temp, p); + font_name_table[i] = temp; + } + p = strtok(0, WS); + if (p != 0) { + t.error("font count does not match number of fonts"); + return 0; + } + font_name_table[nfonts] = 0; + } + else if (strcmp("sizes", p) == 0) { + int n = 16; + sizes = new int[n]; + int i = 0; + for (;;) { + p = strtok(0, WS); + while (p == 0) { + if (!t.next()) { + t.error("list of sizes must be terminated by `0'"); + return 0; + } + p = strtok(t.buf, WS); + } + int lower, upper; + switch (sscanf(p, "%d-%d", &lower, &upper)) { + case 1: + upper = lower; + // fall through + case 2: + if (lower <= upper && lower >= 0) + break; + // fall through + default: + t.error("bad size range `%1'", p); + return 0; + } + if (i + 2 > n) { + int *old_sizes = sizes; + sizes = new int[n*2]; + memcpy(sizes, old_sizes, n*sizeof(int)); + n *= 2; + a_delete old_sizes; + } + sizes[i++] = lower; + if (lower == 0) + break; + sizes[i++] = upper; + } + if (i == 1) { + t.error("must have some sizes"); + return 0; + } + } + else if (strcmp("styles", p) == 0) { + int style_table_size = 5; + style_table = (const char **)new char *[style_table_size]; + for (int j = 0; j < style_table_size; j++) + style_table[j] = 0; + int i = 0; + for (;;) { + p = strtok(0, WS); + if (p == 0) + break; + // leave room for terminating 0 + if (i + 1 >= style_table_size) { + const char **old_style_table = style_table; + style_table_size *= 2; + style_table = (const char **)new char*[style_table_size]; + for (j = 0; j < i; j++) + style_table[j] = old_style_table[j]; + for (; j < style_table_size; j++) + style_table[j] = 0; + a_delete old_style_table; + } + char *tem = new char[strlen(p) + 1]; + strcpy(tem, p); + style_table[i++] = tem; + } + } + else if (strcmp("charset", p) == 0) + break; + else if (unknown_desc_command_handler) { + char *command = p; + p = strtok(0, "\n"); + (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno); + } + } + if (res == 0) { + t.error("missing `res' command"); + return 0; + } + if (unitwidth == 0) { + t.error("missing `unitwidth' command"); + return 0; + } + if (font_name_table == 0) { + t.error("missing `fonts' commmand"); + return 0; + } + if (sizes == 0) { + t.error("missing `sizes' command"); + return 0; + } + if (sizescale < 1) { + t.error("bad `sizescale' value"); + return 0; + } + if (hor < 1) { + t.error("bad `hor' value"); + return 0; + } + if (vert < 1) { + t.error("bad `vert' value"); + return 0; + } + return 1; +} + +void font::handle_unknown_font_command(const char *, const char *, + const char *, int) +{ +} + +FONT_COMMAND_HANDLER +font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func) +{ + FONT_COMMAND_HANDLER prev = unknown_desc_command_handler; + unknown_desc_command_handler = func; + return prev; +} + diff --git a/gnu/usr.bin/groff/libgroff/fontfile.cc b/gnu/usr.bin/groff/libgroff/fontfile.cc new file mode 100644 index 0000000000..5353958dbe --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/fontfile.cc @@ -0,0 +1,64 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include "font.h" +#include "lib.h" +#include "searchpath.h" +#include "device.h" +#include "defs.h" + +const char *const FONT_ENV_VAR = "GROFF_FONT_PATH"; + +static search_path font_path(FONT_ENV_VAR, FONTPATH); + +int font::res = 0; +int font::hor = 1; +int font::vert = 1; +int font::unitwidth = 0; +int font::paperwidth = 0; +int font::paperlength = 0; +int font::biggestfont = 0; +int font::spare2 = 0; +int font::sizescale = 1; +int font::tcommand = 0; +const char **font::font_name_table = 0; +int *font::sizes = 0; +const char *font::family = 0; +const char **font::style_table = 0; +FONT_COMMAND_HANDLER font::unknown_desc_command_handler = 0; + +void font::command_line_font_dir(const char *dir) +{ + font_path.command_line_dir(dir); +} + +FILE *font::open_file(const char *name, char **pathp) +{ + char *filename = new char[strlen(name) + strlen(device) + 5]; + sprintf(filename, "dev%s/%s", device, name); + FILE *fp = font_path.open_file(filename, pathp); + a_delete filename; + return fp; +} diff --git a/gnu/usr.bin/groff/libgroff/getcwd.c b/gnu/usr.bin/groff/libgroff/getcwd.c new file mode 100644 index 0000000000..208e811185 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/getcwd.c @@ -0,0 +1,38 @@ +/* Partial emulation of getcwd in terms of getwd. */ + +#include +#include +#include +#ifndef errno +extern int errno; +#endif + +char *getwd(); + +char *getcwd(buf, size) + char *buf; + int size; /* POSIX says this should be size_t */ +{ + if (size <= 0) { + errno = EINVAL; + return 0; + } + else { + char mybuf[MAXPATHLEN]; + int saved_errno = errno; + + errno = 0; + if (!getwd(mybuf)) { + if (errno == 0) + ; /* what to do? */ + return 0; + } + errno = saved_errno; + if (strlen(mybuf) + 1 > size) { + errno = ERANGE; + return 0; + } + strcpy(buf, mybuf); + return buf; + } +} diff --git a/gnu/usr.bin/groff/libgroff/iftoa.c b/gnu/usr.bin/groff/libgroff/iftoa.c new file mode 100644 index 0000000000..ac37183a4d --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/iftoa.c @@ -0,0 +1,65 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define INT_DIGITS 19 /* enough for 64-bit integer */ + +char *iftoa(i, decimal_point) + int i, decimal_point; +{ + /* room for a -, INT_DIGITS digits, a decimal point, and a terminating '\0' */ + static char buf[INT_DIGITS + 3]; + char *p = buf + INT_DIGITS + 2; + int point = 0; + buf[INT_DIGITS + 2] = '\0'; + /* assert(decimal_point <= INT_DIGITS); */ + if (i >= 0) { + do { + *--p = '0' + (i % 10); + i /= 10; + if (++point == decimal_point) + *--p = '.'; + } while (i != 0 || point < decimal_point); + } + else { /* i < 0 */ + do { + *--p = '0' - (i % 10); + i /= 10; + if (++point == decimal_point) + *--p = '.'; + } while (i != 0 || point < decimal_point); + *--p = '-'; + } + if (decimal_point > 0) { + char *q; + /* there must be a dot, so this will terminate */ + for (q = buf + INT_DIGITS + 2; q[-1] == '0'; --q) + ; + if (q[-1] == '.') { + if (q - 1 == p) { + q[-1] = '0'; + q[0] = '\0'; + } + else + q[-1] = '\0'; + } + else + *q = '\0'; + } + return p; +} diff --git a/gnu/usr.bin/groff/libgroff/illegal.cc b/gnu/usr.bin/groff/libgroff/illegal.cc new file mode 100644 index 0000000000..10f4d5bd7d --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/illegal.cc @@ -0,0 +1,22 @@ +#include "lib.h" + +// Table of illegal input characters. + +char illegal_char_table[256]= { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; diff --git a/gnu/usr.bin/groff/libgroff/itoa.c b/gnu/usr.bin/groff/libgroff/itoa.c new file mode 100644 index 0000000000..e10d9dcfb8 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/itoa.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define INT_DIGITS 19 /* enough for 64 bit integer */ + +char *itoa(i) + int i; +{ + /* Room for INT_DIGITS digits, - and '\0' */ + static char buf[INT_DIGITS + 2]; + char *p = buf + INT_DIGITS + 1; /* points to terminating '\0' */ + if (i >= 0) { + do { + *--p = '0' + (i % 10); + i /= 10; + } while (i != 0); + return p; + } + else { /* i < 0 */ + do { + *--p = '0' - (i % 10); + i /= 10; + } while (i != 0); + *--p = '-'; + } + return p; +} diff --git a/gnu/usr.bin/groff/libgroff/lf.cc b/gnu/usr.bin/groff/libgroff/lf.cc new file mode 100644 index 0000000000..482b102a47 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/lf.cc @@ -0,0 +1,63 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { +#include +#include +} +#include "cset.h" +#include "stringclass.h" + +extern void change_filename(const char *); +extern void change_lineno(int); + +int interpret_lf_args(const char *p) +{ + while (*p == ' ') + p++; + if (!csdigit(*p)) + return 0; + int ln = 0; + do { + ln *= 10; + ln += *p++ - '0'; + } while (csdigit(*p)); + if (*p != ' ' && *p != '\n' && *p != '\0') + return 0; + while (*p == ' ') + p++; + if (*p == '\0' || *p == '\n') { + change_lineno(ln); + return 1; + } + for (const char *q = p; + *q != '\0' && *q != ' ' && *q != '\n' && *q != '\\'; + q++) + ; + string tem(p, q - p); + while (*q == ' ') + q++; + if (*q != '\n' && *q != '\0') + return 0; + tem += '\0'; + change_filename(tem.contents()); + change_lineno(ln); + return 1; +} diff --git a/gnu/usr.bin/groff/libgroff/lineno.cc b/gnu/usr.bin/groff/libgroff/lineno.cc new file mode 100644 index 0000000000..f7138dba02 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/lineno.cc @@ -0,0 +1 @@ +int current_lineno = 0; diff --git a/gnu/usr.bin/groff/libgroff/macropath.cc b/gnu/usr.bin/groff/libgroff/macropath.cc new file mode 100644 index 0000000000..7297977e91 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/macropath.cc @@ -0,0 +1,28 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "lib.h" +#include "searchpath.h" +#include "macropath.h" +#include "defs.h" + +#define MACROPATH_ENVVAR "GROFF_TMAC_PATH" + +extern "C" { search_path macro_path(MACROPATH_ENVVAR, MACROPATH); } diff --git a/gnu/usr.bin/groff/libgroff/matherr.c b/gnu/usr.bin/groff/libgroff/matherr.c new file mode 100644 index 0000000000..1f334f4052 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/matherr.c @@ -0,0 +1,45 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include + +#ifdef HAVE_STRUCT_EXCEPTION +#ifdef TLOSS + +int matherr(exc) +struct exception *exc; +{ + switch (exc->type) { + case SING: + case DOMAIN: + errno = EDOM; + break; + case OVERFLOW: + case UNDERFLOW: + case TLOSS: + case PLOSS: + errno = ERANGE; + break; + } + return 1; +} + +#endif /* TLOSS */ +#endif /* HAVE_STRUCT_EXCEPTION */ diff --git a/gnu/usr.bin/groff/libgroff/nametoindex.cc b/gnu/usr.bin/groff/libgroff/nametoindex.cc new file mode 100644 index 0000000000..827e15a1ee --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/nametoindex.cc @@ -0,0 +1,117 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "font.h" +#include "ptable.h" + +declare_ptable(int) +implement_ptable(int) + +class character_indexer { +public: + character_indexer(); + ~character_indexer(); + int ascii_char_index(unsigned char); + int named_char_index(const char *); + int numbered_char_index(int); +private: + enum { NSMALL = 256 }; + int next_index; + int ascii_index[256]; + int small_number_index[NSMALL]; + PTABLE(int) table; + int lookup_char(const char *, int); +}; + +character_indexer::character_indexer() +: next_index(0) +{ + for (int i = 0; i < 256; i++) + ascii_index[i] = -1; + for (i = 0; i < NSMALL; i++) + small_number_index[i] = -1; +} + +character_indexer::~character_indexer() +{ +} + +int character_indexer::ascii_char_index(unsigned char c) +{ + if (ascii_index[c] < 0) + ascii_index[c] = next_index++; + return ascii_index[c]; +} + +int character_indexer::numbered_char_index(int n) +{ + if (n >= 0 && n < NSMALL) { + if (small_number_index[n] < 0) + small_number_index[n] = next_index++; + return small_number_index[n]; + } + // Not the most efficient possible implementation. + char buf[INT_DIGITS + 3]; + buf[0] = ' '; + strcpy(buf + 1, itoa(n)); + return named_char_index(buf); +} + +int character_indexer::named_char_index(const char *s) +{ + int *np = table.lookup(s); + if (!np) { + np = new int; + *np = next_index++; + table.define(s, np); + } + return *np; +} + +static character_indexer indexer; + +int font::number_to_index(int n) +{ + return indexer.numbered_char_index(n); +} + +int font::name_to_index(const char *s) +{ + assert(s != 0 && s[0] != '\0' && s[0] != ' '); + if (s[1] == '\0') + return indexer.ascii_char_index(s[0]); + /* char128 and \200 are synonyms */ + if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') { + char *res; + long n = strtol(s + 4, &res, 10); + if (res != s + 4 && *res == '\0' && n >= 0 && n < 256) + return indexer.ascii_char_index((unsigned char)n); + } + return indexer.named_char_index(s); +} + diff --git a/gnu/usr.bin/groff/libgroff/new.cc b/gnu/usr.bin/groff/libgroff/new.cc new file mode 100644 index 0000000000..fbb038376f --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/new.cc @@ -0,0 +1,67 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { +#include +#include +#include +} + +#include "posix.h" + +extern const char *program_name; + +static void ewrite(const char *s) +{ + write(2, s, strlen(s)); +} + +void *operator new(size_t size) +{ + // Avoid relying on the behaviour of malloc(0). + if (size == 0) + size++; +#ifdef COOKIE_BUG + char *p = (char *)malloc(unsigned(size + 8)); + if (p != 0) { + ((unsigned *)p)[1] = 0; + return p + 8; + } +#else /* not COOKIE_BUG */ + char *p = (char *)malloc(unsigned(size)); + if (p != 0) + return p; +#endif /* not COOKIE_BUG */ + if (program_name) { + ewrite(program_name); + ewrite(": "); + } + ewrite("out of memory\n"); + _exit(-1); +} + +#ifdef COOKIE_BUG + +void operator delete(void *p) +{ + if (p) + free((void *)((char *)p - 8)); +} + +#endif /* COOKIE_BUG */ diff --git a/gnu/usr.bin/groff/libgroff/prime.cc b/gnu/usr.bin/groff/libgroff/prime.cc new file mode 100644 index 0000000000..531856c2a5 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/prime.cc @@ -0,0 +1,28 @@ +extern "C" { +#include +} + +int is_prime(unsigned n) +{ + if (n <= 3) + return 1; + if (!(n & 1)) + return 0; + if (n % 3 == 0) + return 0; + unsigned lim = unsigned(sqrt((double)n)); + unsigned d = 5; + for (;;) { + if (d > lim) + break; + if (n % d == 0) + return 0; + d += 2; + if (d > lim) + break; + if (n % d == 0) + return 0; + d += 4; + } + return 1; +} diff --git a/gnu/usr.bin/groff/libgroff/progname.cc b/gnu/usr.bin/groff/libgroff/progname.cc new file mode 100644 index 0000000000..a70e3419c2 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/progname.cc @@ -0,0 +1 @@ +const char *program_name = 0; diff --git a/gnu/usr.bin/groff/libgroff/ptable.cc b/gnu/usr.bin/groff/libgroff/ptable.cc new file mode 100644 index 0000000000..a6086de993 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/ptable.cc @@ -0,0 +1,51 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "ptable.h" +#include "errarg.h" +#include "error.h" + +unsigned long hash_string(const char *s) +{ + assert(s != 0); + unsigned long h = 0, g; + while (*s != 0) { + h <<= 4; + h += *s++; + if ((g = h & 0xf0000000) != 0) { + h ^= g >> 24; + h ^= g; + } + } + return h; +} + +static const unsigned table_sizes[] = { +101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, +80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009, +16000057, 32000011, 64000031, 128000003, 0 +}; + +unsigned next_ptable_size(unsigned n) +{ + for (const unsigned *p = table_sizes; *p <= n; p++) + if (*p == 0) + fatal("cannot expand table"); + return *p; +} diff --git a/gnu/usr.bin/groff/libgroff/putenv.c b/gnu/usr.bin/groff/libgroff/putenv.c new file mode 100644 index 0000000000..9e1cd322ca --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/putenv.c @@ -0,0 +1,96 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* Hacked slightly by jjc@jclark.com for groff. */ + +#include + +#ifdef __STDC__ +#include +typedef void *PTR; +typedef size_t SIZE_T; +#else /* not __STDC__ */ +typedef char *PTR; +typedef int SIZE_T; +#endif /* not __STDC__ */ + +#ifdef HAVE_STDLIB_H +#include +#else /* not HAVE_STDLIB_H */ +PTR malloc(); +#endif /* not HAVE_STDLIB_H */ + +#ifndef NULL +#define NULL 0 +#endif + +extern char **environ; + +/* Put STRING, which is of the form "NAME=VALUE", in the environment. */ + +int putenv(string) + char *string; +{ + char *name_end = strchr(string, '='); + SIZE_T size; + char **ep; + + if (name_end == NULL) + { + /* Remove the variable from the environment. */ + size = strlen(string); + for (ep = environ; *ep != NULL; ++ep) + if (!strncmp(*ep, string, size) && (*ep)[size] == '=') + { + while (ep[1] != NULL) + { + ep[0] = ep[1]; + ++ep; + } + *ep = NULL; + return 0; + } + } + + size = 0; + for (ep = environ; *ep != NULL; ++ep) + if (!strncmp(*ep, string, name_end - string) + && (*ep)[name_end - string] == '=') + break; + else + ++size; + + if (*ep == NULL) + { + static char **last_environ = NULL; + char **new_environ = (char **) malloc((size + 2) * sizeof(char *)); + if (new_environ == NULL) + return -1; + (void) memcpy((PTR) new_environ, (PTR) environ, size * sizeof(char *)); + new_environ[size] = (char *) string; + new_environ[size + 1] = NULL; + if (last_environ != NULL) + free((PTR) last_environ); + last_environ = new_environ; + environ = new_environ; + } + else + *ep = (char *) string; + + return 0; +} diff --git a/gnu/usr.bin/groff/libgroff/searchpath.cc b/gnu/usr.bin/groff/libgroff/searchpath.cc new file mode 100644 index 0000000000..eb7a6690cd --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/searchpath.cc @@ -0,0 +1,117 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include + +#include "lib.h" +#include "searchpath.h" + +search_path::search_path(const char *envvar, const char *standard) +{ + char *e = envvar ? getenv(envvar) : 0; + if (e && standard) { + dirs = new char[strlen(e) + strlen(standard) + 2]; + strcpy(dirs, e); + strcat(dirs, ":"); + strcat(dirs, standard); + } + else + dirs = strsave(e ? e : standard); + init_len = dirs ? strlen(dirs) : 0; +} + +search_path::~search_path() +{ + if (dirs) + a_delete dirs; +} + +void search_path::command_line_dir(const char *s) +{ + if (!dirs) + dirs = strsave(s); + else { + char *old = dirs; + unsigned old_len = strlen(old); + unsigned slen = strlen(s); + dirs = new char[old_len + 1 + slen + 1]; + memcpy(dirs, old, old_len - init_len); + char *p = dirs; + p += old_len - init_len; + if (init_len == 0) + *p++ = ':'; + memcpy(p, s, slen); + p += slen; + if (init_len > 0) { + *p++ = ':'; + memcpy(p, old + old_len - init_len, init_len); + p += init_len; + } + *p++ = '\0'; + a_delete old; + } +} + +FILE *search_path::open_file(const char *name, char **pathp) +{ + assert(name != 0); + if (*name == '/' || dirs == 0 || *dirs == '\0') { + FILE *fp = fopen(name, "r"); + if (fp) { + if (pathp) + *pathp = strsave(name); + return fp; + } + else + return 0; + } + unsigned namelen = strlen(name); + char *p = dirs; + for (;;) { + char *end = strchr(p, ':'); + if (!end) + end = strchr(p, '\0'); + int need_slash = end > p && end[-1] != '/'; + char *path = new char[(end - p) + need_slash + namelen + 1]; + memcpy(path, p, end - p); + if (need_slash) + path[end - p] = '/'; + strcpy(path + (end - p) + need_slash, name); +#if 0 + fprintf(stderr, "trying `%s'\n", path); +#endif + FILE *fp = fopen(path, "r"); + if (fp) { + if (pathp) + *pathp = path; + else + a_delete path; + return fp; + } + a_delete path; + if (*end == '\0') + break; + p = end + 1; + } + return 0; +} diff --git a/gnu/usr.bin/groff/libgroff/strerror.c b/gnu/usr.bin/groff/libgroff/strerror.c new file mode 100644 index 0000000000..de42b83846 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/strerror.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#define INT_DIGITS 19 /* enough for 64 bit integer */ + +extern int sys_nerr; +extern char *sys_errlist[]; + +char *strerror(n) + int n; +{ + static char buf[sizeof("Error ") + 1 + INT_DIGITS]; + if (n >= 0 && n < sys_nerr && sys_errlist[n] != 0) + return sys_errlist[n]; + else { + sprintf(buf, "Error %d", n); + return buf; + } +} diff --git a/gnu/usr.bin/groff/libgroff/string.cc b/gnu/usr.bin/groff/libgroff/string.cc new file mode 100644 index 0000000000..e20e249068 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/string.cc @@ -0,0 +1,310 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "stringclass.h" +#include "lib.h" + +static char *salloc(int len, int *sizep); +static void sfree(char *ptr, int size); +static char *sfree_alloc(char *ptr, int size, int len, int *sizep); +static char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep); + +static char *salloc(int len, int *sizep) +{ + if (len == 0) { + *sizep = 0; + return 0; + } + else + return new char[*sizep = len*2]; +} + +static void sfree(char *ptr, int) +{ + a_delete ptr; +} + +static char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep) +{ + if (oldsz >= len) { + *sizep = oldsz; + return ptr; + } + a_delete ptr; + if (len == 0) { + *sizep = 0; + return 0; + } + else + return new char[*sizep = len*2]; +} + +static char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep) +{ + if (oldsz >= newlen) { + *sizep = oldsz; + return ptr; + } + if (newlen == 0) { + a_delete ptr; + *sizep = 0; + return 0; + } + else { + char *p = new char[*sizep = newlen*2]; + if (oldlen < newlen && oldlen != 0) + memcpy(p, ptr, oldlen); + a_delete ptr; + return p; + } +} + +string::string() : len(0), ptr(0), sz(0) +{ +} + +string::string(const char *p, int n) : len(n) +{ + assert(n >= 0); + ptr = salloc(n, &sz); + if (n != 0) + memcpy(ptr, p, n); +} + +string::string(const char *p) +{ + if (p == 0) { + len = 0; + ptr = 0; + sz = 0; + } + else { + len = strlen(p); + ptr = salloc(len, &sz); + memcpy(ptr, p, len); + } +} + +string::string(char c) : len(1) +{ + ptr = salloc(1, &sz); + *ptr = c; +} + +string::string(const string &s) : len(s.len) +{ + ptr = salloc(len, &sz); + if (len != 0) + memcpy(ptr, s.ptr, len); +} + +string::~string() +{ + sfree(ptr, sz); +} + +string &string::operator=(const string &s) +{ + ptr = sfree_alloc(ptr, sz, s.len, &sz); + len = s.len; + if (len != 0) + memcpy(ptr, s.ptr, len); + return *this; +} + +string &string::operator=(const char *p) +{ + if (p == 0) { + sfree(ptr, len); + len = 0; + ptr = 0; + sz = 0; + } + else { + int slen = strlen(p); + ptr = sfree_alloc(ptr, sz, slen, &sz); + len = slen; + memcpy(ptr, p, len); + } + return *this; +} + +string &string::operator=(char c) +{ + ptr = sfree_alloc(ptr, sz, 1, &sz); + len = 1; + *ptr = c; + return *this; +} + +void string::move(string &s) +{ + sfree(ptr, sz); + ptr = s.ptr; + len = s.len; + sz = s.sz; + s.ptr = 0; + s.len = 0; + s.sz = 0; +} + +void string::grow1() +{ + ptr = srealloc(ptr, sz, len, len + 1, &sz); +} + +string &string::operator+=(const char *p) +{ + if (p != 0) { + int n = strlen(p); + int newlen = len + n; + if (newlen > sz) + ptr = srealloc(ptr, sz, len, newlen, &sz); + memcpy(ptr + len, p, n); + len = newlen; + } + return *this; +} + +string &string::operator+=(const string &s) +{ + if (s.len != 0) { + int newlen = len + s.len; + if (newlen > sz) + ptr = srealloc(ptr, sz, len, newlen, &sz); + memcpy(ptr + len, s.ptr, s.len); + len = newlen; + } + return *this; +} + +void string::append(const char *p, int n) +{ + if (n > 0) { + int newlen = len + n; + if (newlen > sz) + ptr = srealloc(ptr, sz, len, newlen, &sz); + memcpy(ptr + len, p, n); + len = newlen; + } +} + +string::string(const char *s1, int n1, const char *s2, int n2) +{ + assert(n1 >= 0 && n2 >= 0); + len = n1 + n2; + if (len == 0) { + sz = 0; + ptr = 0; + } + else { + ptr = salloc(len, &sz); + if (n1 == 0) + memcpy(ptr, s2, n2); + else { + memcpy(ptr, s1, n1); + if (n2 != 0) + memcpy(ptr + n1, s2, n2); + } + } +} + +int operator<=(const string &s1, const string &s2) +{ + return (s1.len <= s2.len + ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0 + : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0); +} + +int operator<(const string &s1, const string &s2) +{ + return (s1.len < s2.len + ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0 + : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0); +} + +int operator>=(const string &s1, const string &s2) +{ + return (s1.len >= s2.len + ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0 + : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0); +} + +int operator>(const string &s1, const string &s2) +{ + return (s1.len > s2.len + ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0 + : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0); +} + +void string::set_length(int i) +{ + assert(i >= 0); + if (i > sz) + ptr = srealloc(ptr, sz, len, i, &sz); + len = i; +} + +void string::clear() +{ + len = 0; +} + +int string::search(char c) const +{ + char *p = (char *)memchr(ptr, c, len); + return p ? p - ptr : -1; +} + +// we silently strip nuls + +char *string::extract() const +{ + char *p = ptr; + int n = len; + int nnuls = 0; + for (int i = 0; i < n; i++) + if (p[i] == '\0') + nnuls++; + char *q = new char[n + 1 - nnuls]; + char *r = q; + for (i = 0; i < n; i++) + if (p[i] != '\0') + *r++ = p[i]; + q[n] = '\0'; + return q; +} + +void put_string(const string &s, FILE *fp) +{ + int len = s.length(); + const char *ptr = s.contents(); + for (int i = 0; i < len; i++) + putc(ptr[i], fp); +} + +string as_string(int i) +{ + static char buf[INT_DIGITS + 2]; + sprintf(buf, "%d", i); + return string(buf); +} + diff --git a/gnu/usr.bin/groff/libgroff/strsave.cc b/gnu/usr.bin/groff/libgroff/strsave.cc new file mode 100644 index 0000000000..ab09644ec8 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/strsave.cc @@ -0,0 +1,33 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern "C" { +#include +} + +char *strsave(const char *s) +{ + if (s == 0) + return 0; + char *p = new char[strlen(s) + 1]; + strcpy(p, s); + return p; +} + diff --git a/gnu/usr.bin/groff/libgroff/strtol.c b/gnu/usr.bin/groff/libgroff/strtol.c new file mode 100644 index 0000000000..4a1830f685 --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/strtol.c @@ -0,0 +1,120 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#ifndef errno +extern int errno; +#endif + +#ifdef HAVE_LIMITS_H +#include +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#ifndef LONG_MIN +#define LONG_MIN (-LONG_MAX-1) +#endif + +long strtol(str, ptr, base) + char *str, **ptr; + int base; +{ + char *start = str; + int neg = 0; + long val; + char *p; + static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + + while (isascii(*str) && isspace(*str)) + str++; + + if (*str == '-') { + neg = 1; + str++; + } + if (base == 0) { + if (*str == '0') { + if (str[1] == 'x' || str[1] == 'X') { + str += 2; + base = 16; + } + else + base = 8; + } + else + base = 10; + } + if (base < 2 || base > 36) + base = 10; + else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) + str += 2; + + p = strchr(digits, isascii(*str) && isupper(*str) ? tolower(*str) : *str); + if (p == 0 || (val = (p - digits)) >= base) { + if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) { + if (ptr) + *ptr = str - 1; + } + else { + if (ptr) + *ptr = start; + errno = ERANGE; + } + return 0; + } + if (neg) + val = -val; + + while (*++str != '\0') { + int n; + + p = strchr(digits, isascii(*str) && isupper(*str) ? tolower(*str) : *str); + if (p == 0) + break; + n = p - digits; + if (n >= base) + break; + if (neg) { + if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) { + val = LONG_MIN; + errno = ERANGE; + } + else + val = val*base - n; + } + else { + if (val > (LONG_MAX - n)/base) { + val = LONG_MAX; + errno = ERANGE; + } + else + val = val*base + n; + } + } + + if (ptr) + *ptr = str; + + return val; +} diff --git a/gnu/usr.bin/groff/libgroff/tmpfile.cc b/gnu/usr.bin/groff/libgroff/tmpfile.cc new file mode 100644 index 0000000000..bd6f8ad69a --- /dev/null +++ b/gnu/usr.bin/groff/libgroff/tmpfile.cc @@ -0,0 +1,99 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include + +#include "posix.h" +#include "lib.h" +#include "errarg.h" +#include "error.h" + +extern "C" { + // Sun's stdlib.h fails to declare this. + char *mktemp(char *); + int mkstemp(char *); +} + +// If this is set, create temporary files there +#define GROFF_TMPDIR_ENVVAR "GROFF_TMPDIR" +// otherwise if this is set, create temporary files there +#define TMPDIR_ENVVAR "TMPDIR" +// otherwise create temporary files here. +#define DEFAULT_TMPDIR "/tmp" +// Use this as the prefix for temporary filenames. +#define TMPFILE_PREFIX "groff" + +// Open a temporary file with fatal error on failure. + +FILE *xtmpfile() +{ + const char *dir = getenv(GROFF_TMPDIR_ENVVAR); + if (!dir) { + dir = getenv(TMPDIR_ENVVAR); + if (!dir) + dir = DEFAULT_TMPDIR; + } + + const char *p = strrchr(dir, '/'); + int needs_slash = (!p || p[1]); + char *templ = new char[strlen(dir) + needs_slash + + sizeof(TMPFILE_PREFIX) - 1 + 6 + 1]; + strcpy(templ, dir); + if (needs_slash) + strcat(templ, "/"); + strcat(templ, TMPFILE_PREFIX); + strcat(templ, "XXXXXX"); + +#ifdef HAVE_MKSTEMP + errno = 0; + int fd = mkstemp(templ); + if (fd < 0) + fatal("cannot create temporary file: %1", strerror(errno)); + errno = 0; + FILE *fp = fdopen(fd, "w+"); + if (!fp) + fatal("fdopen: %1", strerror(errno)); +#else /* not HAVE_MKSTEMP */ + if (!mktemp(templ) || !templ[0]) + fatal("cannot create file name for temporary file"); + errno = 0; + FILE *fp = fopen(templ, "w+"); + if (!fp) + fatal("cannot open `%1': %2", templ, strerror(errno)); +#endif /* not HAVE_MKSTEMP */ + if (unlink(templ) < 0) + error("cannot unlink `%1': %2", templ, strerror(errno)); + a_delete templ; + return fp; +} + +#if 0 +// If you're not running Unix, the following will do: +FILE *xtmpfile() +{ + FILE *fp = tmpfile(); + if (!fp) + fatal("couldn't create temporary file"); + return fp; +} +#endif diff --git a/gnu/usr.bin/groff/lkbib/Makefile b/gnu/usr.bin/groff/lkbib/Makefile new file mode 100644 index 0000000000..f7c274feb4 --- /dev/null +++ b/gnu/usr.bin/groff/lkbib/Makefile @@ -0,0 +1,12 @@ +# Makefile for lkbib + +PROG= lkbib +SRCS= lkbib.cc +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBBIB) $(LIBGROFF) -lm +DPADD+= $(LIBBIB) $(LIBGROFF) $(LIBMATH) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/lkbib/Makefile.dep b/gnu/usr.bin/groff/lkbib/Makefile.dep new file mode 100644 index 0000000000..b6845ea507 --- /dev/null +++ b/gnu/usr.bin/groff/lkbib/Makefile.dep @@ -0,0 +1,2 @@ +lkbib.o : lkbib.cc ../include/lib.h ../include/errarg.h ../include/error.h \ + ../include/defs.h ../include/refid.h ../include/search.h diff --git a/gnu/usr.bin/groff/lkbib/lkbib.1 b/gnu/usr.bin/groff/lkbib/lkbib.1 new file mode 100644 index 0000000000..efbc9aaa18 --- /dev/null +++ b/gnu/usr.bin/groff/lkbib/lkbib.1 @@ -0,0 +1,90 @@ +.\" -*- nroff -*- +.ds g \" empty +.ds G \" empty +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH LKBIB 1 "6 August 1992" "Groff Version 1.08" +.SH NAME +lkbib \- search bibliographic databases +.SH SYNOPSIS +.B lkbib +[ +.B \-v +] +[ +.BI \-i fields +] +[ +.BI \-p filename +] +[ +.BI \-t n +] +.IR key \|.\|.\|. +.SH DESCRIPTION +.B lkbib +searches bibliographic databases for references that contain the keys +.IR key \|.\|.\|. +and prints any references found on the standard output. +.B lkbib +will search any databases given by +.B \-p +options, and then a default database. +The default database is taken from the +.SB REFER +environment variable if it is set, +otherwise it is +.BR /usr/share/dict/papers/Ind . +For each database +.I filename +to be searched, +if an index +.IB filename .i +created by +.BR indxbib (1) +exists, then it will be searched instead; +each index can cover multiple databases. +.SH OPTIONS +.TP +.B \-v +Print the version number. +.TP +.BI \-p filename +Search +.IR filename . +Multiple +.B \-p +options can be used. +.TP +.BI \-i string +When searching files for which no index exists, +ignore the contents of fields whose names are in +.IR string . +.TP +.BI \-t n +Only require the first +.I n +characters of keys to be given. +Initially +.I n +is 6. +.SH ENVIRONMENT +.TP \w'\fBREFER'u+2n +.SB REFER +Default database. +.SH FILES +.Tp \w'\fB/usr/share/dict/papers/Ind'u+2n +.B /usr/share/dict/papers/Ind +Default database to be used if the +.SB REFER +environment variable is not set. +.IB filename .i +Index files. +.SH "SEE ALSO" +.BR refer (1), +.BR lookbib (1), +.BR indxbib (1) diff --git a/gnu/usr.bin/groff/lkbib/lkbib.cc b/gnu/usr.bin/groff/lkbib/lkbib.cc new file mode 100644 index 0000000000..a6d3e8fee5 --- /dev/null +++ b/gnu/usr.bin/groff/lkbib/lkbib.cc @@ -0,0 +1,122 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +#include "lib.h" +#include "errarg.h" +#include "error.h" + +#include "defs.h" +#include "refid.h" +#include "search.h" + +static void usage() +{ + fprintf(stderr, "usage: %s [-nv] [-p database] [-i XYZ] [-t N] keys ...\n", + program_name); + exit(1); +} + +main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int search_default = 1; + search_list list; + int opt; + while ((opt = getopt(argc, argv, "nvVi:t:p:")) != EOF) + switch (opt) { + case 'V': + verify_flag = 1; + break; + case 'n': + search_default = 0; + break; + case 'i': + linear_ignore_fields = optarg; + break; + case 't': + { + char *ptr; + long n = strtol(optarg, &ptr, 10); + if (n == 0 && ptr == optarg) { + error("bad integer `%1' in `t' option", optarg); + break; + } + if (n < 1) + n = 1; + linear_truncate_len = int(n); + break; + } + case 'v': + { + extern const char *version_string; + fprintf(stderr, "GNU lkbib version %s\n", version_string); + fflush(stderr); + break; + } + case 'p': + list.add_file(optarg); + break; + case '?': + usage(); + default: + assert(0); + } + if (optind >= argc) + usage(); + char *filename = getenv("REFER"); + if (filename) + list.add_file(filename); + else if (search_default) + list.add_file(DEFAULT_INDEX, 1); + if (list.nfiles() == 0) + fatal("no databases"); + int total_len = 0; + for (int i = optind; i < argc; i++) + total_len += strlen(argv[i]); + total_len += argc - optind - 1 + 1; // for spaces and '\0' + char *buffer = new char[total_len]; + char *ptr = buffer; + for (i = optind; i < argc; i++) { + if (i > optind) + *ptr++ = ' '; + strcpy(ptr, argv[i]); + ptr = strchr(ptr, '\0'); + } + search_list_iterator iter(&list, buffer); + const char *start; + int len; + for (int count = 0; iter.next(&start, &len); count++) { + if (fwrite(start, 1, len, stdout) != len) + fatal("write error on stdout: %1", strerror(errno)); + // Can happen for last reference in file. + if (start[len - 1] != '\n') + putchar('\n'); + putchar('\n'); + } + exit(!count); +} diff --git a/gnu/usr.bin/groff/lookbib/Makefile b/gnu/usr.bin/groff/lookbib/Makefile new file mode 100644 index 0000000000..6997c7821f --- /dev/null +++ b/gnu/usr.bin/groff/lookbib/Makefile @@ -0,0 +1,12 @@ +# Makefile for lookbib + +PROG= lookbib +SRCS= lookbib.cc +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBBIB) $(LIBGROFF) -lm +DPADD+= $(LIBBIB) $(LIBGROFF) $(LIBMATH) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/lookbib/Makefile.dep b/gnu/usr.bin/groff/lookbib/Makefile.dep new file mode 100644 index 0000000000..e6597d4eac --- /dev/null +++ b/gnu/usr.bin/groff/lookbib/Makefile.dep @@ -0,0 +1,2 @@ +lookbib.o : lookbib.cc ../include/errarg.h ../include/error.h \ + ../include/lib.h ../include/cset.h ../include/refid.h ../include/search.h diff --git a/gnu/usr.bin/groff/lookbib/lookbib.1 b/gnu/usr.bin/groff/lookbib/lookbib.1 new file mode 100644 index 0000000000..e0708ce3f0 --- /dev/null +++ b/gnu/usr.bin/groff/lookbib/lookbib.1 @@ -0,0 +1,58 @@ +.\" -*- nroff -*- +.TH LOOKBIB 1 "6 August 1992" "Groff Version 1.08" +.SH NAME +lookbib \- search bibliographic databases +.SH SYNOPSIS +.B lookbib +[ +.B \-v +] +[ +.BI \-i string +] +[ +.BI \-t n +] +.IR filename \|.\|.\|. +.SH DESCRIPTION +lookbib prints a prompt on the standard error (unless the standard input is not a terminal), +reads from the standard input a line containing a set of keywords, +searches the bibliographic databases +.IR filename \|.\|.\|. +for references containing those keywords, +prints any references found on the standard output, +and repeats this process until the end of input. +For each database +.I filename +to be searched, +if an index +.IB filename .i +created by +.BR indxbib (1) +exists, then it will be searched instead; +each index can cover multiple databases. +.SH OPTIONS +.TP +.B \-v +Print the version number. +.TP +.BI \-i string +When searching files for which no index exists, +ignore the contents of fields whose names are in +.IR string . +.TP +.BI \-t n +Only require the first +.I n +characters of keys to be given. +Initially +.I n +is 6. +.SH FILES +.TP \w'\fIfilename\fB.i'u+2n +.IB filename .i +Index files. +.SH "SEE ALSO" +.BR refer (1), +.BR lkbib (1), +.BR indxbib (1) diff --git a/gnu/usr.bin/groff/lookbib/lookbib.cc b/gnu/usr.bin/groff/lookbib/lookbib.cc new file mode 100644 index 0000000000..fcb3277353 --- /dev/null +++ b/gnu/usr.bin/groff/lookbib/lookbib.cc @@ -0,0 +1,127 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +#include "errarg.h" +#include "error.h" +#include "lib.h" +#include "cset.h" + +#include "refid.h" +#include "search.h" + +extern "C" { + int isatty(int); +} + +static void usage() +{ + fprintf(stderr, "usage: %s [-v] [-i XYZ] [-t N] database ...\n", + program_name); + exit(1); +} + +main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int opt; + while ((opt = getopt(argc, argv, "vVi:t:")) != EOF) + switch (opt) { + case 'V': + verify_flag = 1; + break; + case 'i': + linear_ignore_fields = optarg; + break; + case 't': + { + char *ptr; + long n = strtol(optarg, &ptr, 10); + if (n == 0 && ptr == optarg) { + error("bad integer `%1' in `t' option", optarg); + break; + } + if (n < 1) + n = 1; + linear_truncate_len = int(n); + break; + } + case 'v': + { + extern const char *version_string; + fprintf(stderr, "GNU lookbib version %s\n", version_string); + fflush(stderr); + break; + } + case '?': + usage(); + default: + assert(0); + } + if (optind >= argc) + usage(); + search_list list; + for (int i = optind; i < argc; i++) + list.add_file(argv[i]); + if (list.nfiles() == 0) + fatal("no databases"); + char line[1024]; + int interactive = isatty(fileno(stdin)); + for (;;) { + if (interactive) { + fputs("> ", stderr); + fflush(stderr); + } + if (!fgets(line, sizeof(line), stdin)) + break; + char *ptr = line; + while (csspace(*ptr)) + ptr++; + if (*ptr == '\0') + continue; + search_list_iterator iter(&list, line); + const char *start; + int len; + for (int count = 0; iter.next(&start, &len); count++) { + if (fwrite(start, 1, len, stdout) != len) + fatal("write error on stdout: %1", strerror(errno)); + // Can happen for last reference in file. + if (start[len - 1] != '\n') + putchar('\n'); + putchar('\n'); + } + fflush(stdout); + if (interactive) { + fprintf(stderr, "%d found\n", count); + fflush(stderr); + } + } + if (interactive) + putc('\n', stderr); + return 0; +} + diff --git a/gnu/usr.bin/groff/man/Makefile b/gnu/usr.bin/groff/man/Makefile new file mode 100644 index 0000000000..ef61aca3da --- /dev/null +++ b/gnu/usr.bin/groff/man/Makefile @@ -0,0 +1,7 @@ +# Makefile for manpages + +MAN5= groff_font.0 groff_out.0 +MAN7= groff_char.0 + +.include +.include "../Makefile.cfg" diff --git a/gnu/usr.bin/groff/man/groff_char.7 b/gnu/usr.bin/groff/man/groff_char.7 new file mode 100644 index 0000000000..ac023e8b3b --- /dev/null +++ b/gnu/usr.bin/groff/man/groff_char.7 @@ -0,0 +1,545 @@ +.\" -*- nroff -*- +.\" For best results, print this with groff. +.TH GROFF_CHAR 7 "31 May 1993" "Groff Version 1.08" +.ds aq \(aq +.ie !\n(.g .if '\(aq'' .ds aq \' +.el \{\ +. tr \(aq\(aq +. if !c\(aq .ds aq \' +.\} +.if !\n(.g .ig +.\" .Ac accented-char accent char +.de Ac +.char \\$1 \\$3\ +\k[acc]\ +\h'(u;-\w'\\$2'-\w'\\$3'/2+\\\\n[skw]+(\w'x'*0)-\\\\n[skw])'\ +\v'(u;\w'x'*0+\\\\n[rst]+(\w'\\$3'*0)-\\\\n[rst])'\ +\\$2\ +\v'(u;\w'x'*0-\\\\n[rst]+(\w'\\$3'*0)+\\\\n[rst])'\ +\h'|\\\\n[acc]u' +.hcode \\$1\\$3 +.. +.Ac \(vc \(ah c +.Ac \(vC \(ah C +.SH NAME +groff_char \- groff character names +.SH DESCRIPTION +This manual page lists the standard +.B groff +input characters. +Only the characters that are available for the device that +is being used to print this manual page will be displayed. +The +.I "Input code" +column applies to characters which can be +input with a single character, and gives the ISO Latin-1 code +of that input character. +The +.I "PostScript name\" +column gives the usual PostScript name of the output character. +.LP +The ISO Latin-1 no-break space (code 0240 octal) is equivalent to +.BR \e (space). +All other ISO Latin-1 characters print as themselves with the following +exceptions: +.B \` +prints as `, +.B \*(aq +prints as '; +the corresponding ISO Latin-1 characters can be obtained with +.B \e` +and +.BR \e(aq . +The ISO Latin-1 `Hyphen, Minus Sign' (code 45) prints as a hyphen; +a minus sign can be obtained with +.BR \e- . +The ISO Latin-1 `Tilde' (code 126) prints as ~; +the larger glyph can be obtained with +.BR \e(ti . +The ISO Latin-1 `Circumflex Accent' (code 94) prints as ^; +a larger glyph can be obtained with +.BR \e(ha . +.sp +'nf +.nr Sp 3n +.ta \w'\fIOutput'u+\n(Spu +\w'\fIInput'u+\n(Spu +\w'\fIInput'u+\n(Spu \ ++\w'periodcentered'u+\n(Spu +.de C0 +.C \\$1 "" \\$1 \\$2 "\\$3" +.. +.de C1 +.C \e\\$1 "" \\\\\\$1 \\$2 "\\$3" +.. +.de C2 +.C \e(\\$1 "" \\(\\$1 \\$2 "\\$3" +.. +.if !\n(.g .ig +.de CD +.C \[char\\$1] \\$1 \[char\\$1] \\$2 "\\$3" +.. +.do fspecial CR R +.\" input-name decimal-code output-name ps-name description +.if !\n(.g .ig +.de C +.if c\\$3 \{\ +.ft CR +.tr `\`'\*(aq +.in 0 +.di CH +\&\\$1 +.br +.di +.in +.ft +.ds CH \\*(CH\ +.tr ``'' +\&\\$3\t\\*(CH\t\\$2\t\\$4\t\\$5 +.\} +.. +.if \n(.g .ig +.de C +.if !'\\$3'' \{\ +.ft B +.tr `\`'\*(aq +.in 0 +.di CH +\&\\$1 +.br +.di +.in +.ft +.ds CH \\*(CH\ +.tr ``'' +\&\\$3\t\\*(CH\t\\$2\t\\$4\t\\$5 +.\} +.. +.wh \n(nlu+\n(.tu-\n(.Vu Fo +.de Fo +'bp +.He +.. +.de He +.ft I +Output Input Input PostScript Notes + name code name +.ft +.LP +'nf +.. +.He +.CD 33 exclam +.CD 34 quotedbl +.CD 35 numbersign +.CD 36 dollar +.CD 37 percent +.CD 38 ampersand +.CD 39 quoteright +.CD 40 parenleft +.CD 41 parenright +.CD 42 asterisk +.CD 43 plus +.CD 44 comma +.CD 45 hyphen +.CD 46 period +.CD 47 slash +.CD 58 colon +.CD 59 semicolon +.CD 60 less +.CD 61 equal +.CD 62 greater +.CD 63 question +.CD 64 at +.CD 91 bracketleft +.CD 92 backslash +.CD 93 bracketright +.CD 94 circumflex "circumflex accent" +.CD 95 underscore +.CD 96 quoteleft +.CD 123 braceleft +.CD 124 bar +.CD 125 braceright +.CD 126 tilde "tilde accent" +.CD 161 exclamdown +.CD 162 cent +.CD 163 sterling +.CD 164 currency +.CD 165 yen +.CD 166 brokenbar +.CD 167 section +.CD 168 dieresis +.CD 169 copyright +.CD 170 ordfeminine +.CD 171 guillemotleft +.CD 172 logicalnot +.CD 173 hyphen +.CD 174 registered +.CD 175 macron +.CD 176 degree +.CD 177 plusminus +.CD 178 twosuperior +.CD 179 threesuperior +.CD 180 acute "acute accent" +.CD 181 mu +.CD 182 paragraph +.CD 183 periodcentered +.CD 184 cedilla +.CD 185 onesuperior +.CD 186 ordmasculine +.CD 187 guillemotright +.CD 188 onequarter +.CD 189 onehalf +.CD 190 threequarters +.CD 191 questiondown +.CD 192 Agrave +.CD 193 Aacute +.CD 194 Acircumflex +.CD 195 Atilde +.CD 196 Adieresis +.CD 197 Aring +.CD 198 AE +.CD 199 Ccedilla +.CD 200 Egrave +.CD 201 Eacute +.CD 202 Ecircumflex +.CD 203 Edieresis +.CD 204 Igrave +.CD 205 Iacute +.CD 206 Icircumflex +.CD 207 Idieresis +.CD 208 Eth +.CD 209 Ntilde +.CD 210 Ograve +.CD 211 Oacute +.CD 212 Ocircumflex +.CD 213 Otilde +.CD 214 Odieresis +.CD 215 multiply +.CD 216 Oslash +.CD 217 Ugrave +.CD 218 Uacute +.CD 219 Ucircumflex +.CD 220 Udieresis +.CD 221 Yacute +.CD 222 Thorn +.CD 223 germandbls +.CD 224 agrave +.CD 225 aacute +.CD 226 acircumflex +.CD 227 atilde +.CD 228 adieresis +.CD 229 aring +.CD 230 ae +.CD 231 ccedilla +.CD 232 egrave +.CD 233 eacute +.CD 234 ecircumflex +.CD 235 edieresis +.CD 236 igrave +.CD 237 iacute +.CD 238 icircumflex +.CD 239 idieresis +.CD 240 eth +.CD 241 ntilde +.CD 242 ograve +.CD 243 oacute +.CD 244 ocircumflex +.CD 245 otilde +.CD 246 odieresis +.CD 247 divide +.CD 248 oslash +.CD 249 ugrave +.CD 250 uacute +.CD 251 ucircumflex +.CD 252 udieresis +.CD 253 yacute +.CD 254 thorn +.CD 255 ydieresis +.C2 -D Eth "Icelandic uppercase eth" +.C2 Sd eth "Icelandic lowercase eth" +.C2 TP Thorn "Icelandic uppercase thorn" +.C2 Tp thorn "Icelandic lowercase thorn" +.C2 AE AE +.C2 ae ae +.C2 OE OE +.C2 oe oe +.C2 IJ IJ "Dutch IJ ligature" +.C2 ij ij "Dutch ij ligature" +.C2 ss germandbls +.C2 'A Aacute +.C2 'C Cacute +.C2 'E Eacute +.C2 'I Iacute +.C2 'O Oacute +.C2 'U Uacute +.C2 'a aacute +.C2 'c cacute +.C2 'e eacute +.C2 'i iacute +.C2 'o oacute +.C2 'u uacute +.C2 :A Adieresis +.C2 :E Edieresis +.C2 :I Idieresis +.C2 :O Odieresis +.C2 :U Udieresis +.C2 :Y Ydieresis +.C2 :a adieresis +.C2 :e edieresis +.C2 :i idieresis +.C2 :o odieresis +.C2 :u udieresis +.C2 :y ydieresis +.C2 ^A Acircumflex +.C2 ^E Ecircumflex +.C2 ^I Icircumflex +.C2 ^O Ocircumflex +.C2 ^U Ucircumflex +.C2 ^a acircumflex +.C2 ^e ecircumflex +.C2 ^i icircumflex +.C2 ^o ocircumflex +.C2 ^u ucircumflex +.C2 `A Agrave +.C2 `E Egrave +.C2 `I Igrave +.C2 `O Ograve +.C2 `U Ugrave +.C2 `a agrave +.C2 `e egrave +.C2 `i igrave +.C2 `o ograve +.C2 `u ugrave +.C2 ~A Atilde +.C2 ~N Ntilde +.C2 ~O Otilde +.C2 ~a atilde +.C2 ~n ntilde +.C2 ~o otilde +.C2 vS Scaron +.C2 vs scaron +.C2 vZ Zcaron +.C2 vz zcaron +.C2 ,C Ccedilla +.C2 ,c ccedilla +.C2 /L Lslash "Polish L with a slash" +.C2 /l lslash "Polish l with a slash" +.C2 /O Oslash +.C2 /o oslash +.C2 oA Aring +.C2 oa aring +.C2 a" hungarumlaut "Hungarian umlaut" +.C2 a- macron "macron or bar accent" +.C2 a. dotaccent "dot accent" +.C2 a^ circumflex "circumflex accent" +.C2 aa acute "acute accent" +.C2 ga grave "grave accent" +.C2 ab breve "breve accent" +.C2 ac cedilla "cedilla accent" +.C2 ad dieresis "umlaut or dieresis" +.C2 ah caron "h\('a\(vcek accent" +.C2 ao ring "ring or circle accent" +.C2 a~ tilde "tilde accent" +.C2 ho ogonek "hook or ogonek accent" +.C2 .i dotlessi "i without a dot" +.C2 .j dotlessj "j without a dot" +.C2 Cs currency "Scandinavian currency sign" +.C2 Do dollar +.C2 Po sterling +.C2 Ye yen +.C2 Fn florin +.C2 ct cent +.C2 Fo guillemotleft +.C2 Fc guillemotright +.C2 fo guilsinglleft +.C2 fc guilsinglright +.C2 r! exclamdown +.C2 r? questiondown +.C2 ff ff "ff ligature" +.C2 fi fi "fi ligature" +.C2 fl fl "fl ligature" +.C2 Fi ffi "ffi ligature" +.C2 Fl ffl "ffl ligature" +.C2 OK \& "check mark, tick" +.C2 Of ordfeminine +.C2 Om ordmasculine +.C2 S1 onesuperior +.C2 S2 twosuperior +.C2 S3 threesuperior +.C2 <- arrowleft +.C2 -> arrowright +.C2 <> arrowboth "horizontal double-headed arrow" +.C2 da arrowdown +.C2 ua arrowup +.C2 va \& "vertical double-headed arrow" +.C2 lA arrowdblleft +.C2 rA arrowdblright +.C2 hA arrowdblboth "horizontal double-headed double arrow" +.C2 dA arrowdbldown +.C2 uA arrowdblup +.C2 vA \& "vertical double-headed double arrow" +.C2 ba bar +.C2 bb brokenbar +.C2 br br "box rule with traditional troff metrics" +.C2 ru ru "baseline rule" +.C2 ul ul "underline with traditional troff metrics" +.C2 bv bv "bold vertical" +.C2 bs bell +.C2 ci circle +.C2 bu bullet +.C2 co copyright +.C2 rg registered +.C2 tm trademark +.C2 dd daggerdbl "double dagger sign" +.C2 dg dagger +.C2 ps paragraph +.C2 sc section +.C2 de degree +.C2 em emdash "em dash" +.C2 en endash "en dash" +.C2 %0 perthousand "per thousand, per mille sign" +.C2 12 onehalf +.C2 14 onequarter +.C2 34 threequarters +.C2 f/ fraction "bar for fractions" +.C2 fm minute "footmark, prime" +.C2 sd second +.C2 ha asciicircum "\s-2ASCII\s+2 circumflex, hat, caret" +.C2 ti asciitilde "\s-2ASCII\s0 tilde, large tilde" +.C2 hy hyphen +.C2 lB bracketleft +.C2 rB bracketright +.C2 lC braceleft +.C2 rC braceright +.C2 la angleleft "left angle bracket" +.C2 ra angleright "right angle bracket" +.C2 lh handleft +.C2 rh handright +.C2 Bq quotedblbase "low double comma quote" +.C2 bq quotesinglbase "low single comma quote" +.C2 lq quotedblleft +.C2 rq quotedblright +.C2 oq quoteleft "single open quote" +.C2 aq quotesingle "apostrophe quote" +.C2 or bar +.C2 at at +.C1 - minus "minus sign from current font" +.C2 sh numbersign +.C2 sl slash +.C2 rs backslash +.C2 sq square +.C2 3d therefore +.C2 tf therefore +.C2 *A Alpha +.C2 *B Beta +.C2 *C Xi +.C2 *D Delta +.C2 *E Epsilon +.C2 *F Phi +.C2 *G Gamma +.C2 *H Theta +.C2 *I Iota +.C2 *K Kappa +.C2 *L Lambda +.C2 *M Mu +.C2 *N Nu +.C2 *O Omicron +.C2 *P Pi +.C2 *Q Psi +.C2 *R Rho +.C2 *S Sigma +.C2 *T Tau +.C2 *U Upsilon +.C2 *W Omega +.C2 *X Chi +.C2 *Y Eta +.C2 *Z Zeta +.C2 *a alpha +.C2 *b beta +.C2 *c xi +.C2 *d delta +.C2 *e epsilon +.C2 *f phi +.C2 +f phi1 "variant phi" +.C2 *g gamma +.C2 *h theta +.C2 +h theta1 "variant theta" +.C2 *i iota +.C2 *k kappa +.C2 *l lambda +.C2 *m mu +.C2 *n nu +.C2 *o omicron +.C2 *p pi +.C2 +p omega1 "variant pi, looking like omega" +.C2 *q psi +.C2 *r rho +.C2 *s sigma +.C2 *t tau +.C2 *u upsilon +.C2 *w omega +.C2 *x chi +.C2 *y eta +.C2 *z zeta +.C2 ts sigma1 "terminal sigma" +.C2 ~~ approxequal +.C2 ~= approxequal +.C2 != notequal +.C2 ** asteriskmath +.C2 -+ minusplus +.C2 +- plusminus +.C2 <= lessequal +.C2 == equivalence +.C2 =~ congruent +.C2 >= greaterequal +.C2 AN logicaland +.C2 OR logicalor +.C2 no logicalnot +.C2 te existential "there exists, existential quantifier" +.C2 fa universal "for all, universal quantifier" +.C2 Ah aleph +.C2 Im Ifraktur "Fraktur I, imaginary" +.C2 Re Rfraktur "Fraktur R, real" +.C2 if infinity +.C2 md dotmath +.C2 mo element +.C2 mu multiply +.C2 nc notpropersuperset +.C2 ne notequivalence +.C2 nm notelement +.C2 pl plusmath "plus sign in special font" +.C2 eq equalmath "equals sign in special font" +.C2 pt proportional +.C2 pp perpendicular +.C2 sb propersubset +.C2 sp propersuperset +.C2 ib reflexsubset +.C2 ip reflexsuperset +.C2 ap similar +.C2 pd partialdiff "partial differentiation sign" +.C2 c* circlemultiply "multiply sign in a circle" +.C2 c+ circleplus "plus sign in a circle" +.C2 ca intersection "intersection, cap" +.C2 cu union "union, cup" +.C2 di divide "division sign" +.C2 -h hbar +.C2 gr gradient +.C2 es emptyset +.C2 CL club "club suit" +.C2 SP spade "spade suit" +.C2 HE heart "heart suit" +.C2 DI diamond "diamond suit" +.C2 CR carriagereturn "carriage return symbol" +.C2 st suchthat +.C2 /_ angle +.C2 << "" "much less" +.C2 >> "" "much greater" +.C2 wp weierstrass "Weierstrass p" +.C2 lz lozenge +.C2 an arrowhorizex "horizontal arrow extension" +.ch Fo +.SH "SEE ALSO" +.BR groff (1) +.br +.IR "An extension to the troff character set for Europe" , +E.G. Keizer, K.J. Simonsen, J. Akkerhuis, +EUUG Newsletter, Volume 9, No. 2, Summer 1989 diff --git a/gnu/usr.bin/groff/man/groff_font.5 b/gnu/usr.bin/groff/man/groff_font.5 new file mode 100644 index 0000000000..78afa2e2c7 --- /dev/null +++ b/gnu/usr.bin/groff/man/groff_font.5 @@ -0,0 +1,351 @@ +.\" -*- nroff -*- +.de TQ +.br +.ns +.TP \\$1 +.. +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH GROFF_FONT 5 "24 September 1992" "Groff Version 1.08" +.SH NAME +groff_font \- format of groff device and font description files +.SH DESCRIPTION +The groff font format is roughly a superset of the ditroff +font format. +Unlike the ditroff font format, there is no associated binary +format. +The font files for device +.I name +are stored in a directory +.BI dev name. +There are two types of file: a +device description file called +.B DESC +and for each font +.I F +a font file called +.IR F . +These are text files; +there is no associated binary format. +.SS DESC file format +The DESC file can contain the following types of line: +.TP +.BI res\ n +There are +.I n +machine units per inch. +.TP +.BI hor\ n +The horizontal resolution is +.I n +machine units. +.TP +.BI vert\ n +The vertical resolution is +.I n +machine units. +.TP +.BI sizescale\ n +The scale factor for pointsizes. +By default this has a value of 1. +One +.I +scaled point +is equal to +one +.RI point/ n . +The arguments to the +.B unitwidth +and +.B sizes +commands are given in scaled points. +.TP +.BI unitwidth\ n +Quantities in the font files are given in machine units +for fonts whose point size is +.I n +scaled points. +.TP +.B tcommand +This means that the postprocessor can handle the +.B t +and +.B u +output commands. +.TP +.BI sizes\ s1\ s2\|.\|.\|.\|sn\ 0 +This means that the device has fonts at +.IR s1 , +.IR s2 ,\|.\|.\|.\| sn +scaled points. +The list of sizes must be terminated by a +.BR 0 . +Each +.BI s i +can also be a range of sizes +.IR m \- n . +The list can extend over more than one line. +.TP +.BI styles\ S1\ S2\|.\|.\|.\|Sm +The first +.I m +font positions will be associated with styles +.IR S1\|.\|.\|.\|Sm . +.TP +.BI fonts\ n\ F1\ F2\ F3\|.\|.\|.\|Fn +Fonts +.I F1\|.\|.\|.\|Fn +will be mounted in the font positions +.IR m +1,\|.\|.\|., m + n +where +.I m +is the number of styles. +This command may extend over more than one line. +A font name of +.B 0 +will cause no font to be mounted on the corresponding font position. +.TP +.BI family\ fam +The default font family is +.IR fam . +.TP +.B charset +This line and everything following in the file are ignored. +It is allowed for the sake of backwards compatibility. +.LP +The res, unitwidth, fonts and sizes lines are compulsory. +Other commands are ignored by +.B troff +but may be used by postprocessors to store arbitrary information +about the device in the DESC file. +.SS Font file format +A font file has two sections. The first section is a sequence +of lines each containing a sequence of blank delimited +words; the first word in the line is a key, and subsequent +words give a value for that key. +.TP +.BI name\ F +The name of the font is +.IR F . +.TP +.BI spacewidth\ n +The normal width of a space is +.IR n . +.TP +.BI slant\ n +The characters of the font have a slant of +.I n +degrees. (Positive means forward.) +.TP +.BI ligatures\ lig1\ lig2\|.\|.\|.\|lign\ \fR[ 0 \fR] +Characters +.IR lig1 , +.IR lig2 ,\|.\|.\|., lign +are ligatures; possible ligatures are +.BR ff , +.BR fi , +.BR fl +and +.BR ffl . +For backwards compatibiliy, the list of ligatures may be terminated +with a +.BR 0. +The list of ligatures may not extend over more than one line. +.TP +.B special +The font is +.IR special ; +this means that when a character is requested that is not present in +the current font, it will be searched for in any special fonts that +are mounted. +.LP +Other commands are ignored by +.B troff +but may be used by postprocessors to store arbitrary information +about the font in the font file. +.LP +The first section can contain comments which start with the +.B # +character and extend to the end of a line. +.LP +The second section contains one or two subsections. +It must contain a +.I charset +subsection +and it may also contain a +.I kernpairs +subsection. +These subsections can appear in any order. +Each subsection starts with a word on a line by itself. +.LP +The word +.B charset +starts the charset subsection. +The +.B charset +line is followed by a sequence of lines. +Each line gives information for one character. +A line comprises a number of fields separated +by blanks or tabs. The format is +.IP +.I +name metrics type code comment +.LP +.I name +identifies the character: +if +.I name +is a single character +.I c +then it corresponds to the groff input character +.IR c ; +if it is of the form +.BI \e c +where c is a single character, then it +corresponds to the groff input character +.BI \e c\fR; +otherwise it corresponds to the groff input character +.BI \e[ name ] +(if it is exactly two characters +.I xx +it can be entered as +.BI \e( xx\fR.) +Groff supports eight bit characters; however some utilities +has difficulties with eight bit characters. +For this reason, there is a convention that the name +.BI char n +is equivalent to the single character whose code is +.I n . +For example, +.B char163 +would be equivalent to the character with code 163 +which is the pounds sterling sign in ISO Latin-1. +The name +.B \-\-\- +is special and indicates that the character is unnamed; +such characters can only be used by means of the +.B \eN +escape sequence in +.BR troff . +.LP +The +.I type +field gives the character type: +.TP +1 +means the character has an descender, for example, p; +.TP +2 +means the character has an ascender, for example, b; +.TP +3 +means the character has both an ascender and a descender, for example, +(. +.LP +The +.I code +field gives the code which the postprocessor uses to print the character. +The character can also be input to groff using this code by means of the +.B \eN +escape sequence. +The code can be any integer. +If it starts with a +.B 0 +it will be interpreted as octal; +if it starts with +.B 0x +or +.B 0X +it will be intepreted as hexdecimal. +.LP +Anything on the line after the code field will be ignored. +.LP +The +.I metrics +field has the form: +.IP +.IR width [\fB, height [\fB, depth [\fB, italic_correction [\fB, \ +left_italic_correction [\fB, subscript_correction ]]]]] +.LP +There must not be any spaces between these subfields. +Missing subfields are assumed to be 0. +The subfields are all decimal integers. +Since there is no associated binary format, these +values are not required to fit into a variable of type +.B char +as they are in ditroff. +The +.I width +subfields gives the width of the character. +The +.I height +subfield gives the height of the character (upwards is positive); +if a character does not extend above the baseline, it should be +given a zero height, rather than a negative height. +The +.I depth +subfield gives the depth of the character, that is, the distance +below the lowest point below the baseline to which the +character extends (downwards is positive); +if a character does not extend below above the baseline, it should be +given a zero depth, rather than a negative depth. +The +.I italic_correction +subfield gives the amount of space that should be added after the +character when it is immediately to be followed by a character +from a roman font. +The +.I left_italic_correction +subfield gives the amount of space that should be added before the +character when it is immediately to be preceded by a character +from a roman font. +The +.I subscript_correction +gives the amount of space that should be added after a character +before adding a subscript. +This should be less than the italic correction. +.LP +A line in the charset section can also have the format +.IP +.I +name \fB" +.LP +This indicates that +.I name +is just another name for the character mentioned in the +preceding line. +.LP +The word +.B kernpairs +starts the kernpairs section. +This contains a sequence of lines of the form: +.IP +.I +c1 c2 n +.LP +This means that when character +.I c1 +appears next to character +.I c2 +the space between them should be increased by +.IR n . +Most entries in kernpairs section will have a negative value for +.IR n . +.SH FILES +.Tp \w'/usr/share/groff_font/devname/DESC'u+3n +.BI /usr/share/groff_font/dev name /DESC +Device description file for device +.IR name . +.TP +.BI /usr/share/groff_font/dev name / F +Font file for font +.I F +of device +.IR name . +.SH "SEE ALSO" +.BR groff_out (5), +.BR troff (1). diff --git a/gnu/usr.bin/groff/man/groff_out.5 b/gnu/usr.bin/groff/man/groff_out.5 new file mode 100644 index 0000000000..1d9303cad0 --- /dev/null +++ b/gnu/usr.bin/groff/man/groff_out.5 @@ -0,0 +1,215 @@ +'\" e +.\" -*- nroff -*- +.\" This man page must be preprocessed with eqn. +.ie \n(.g .ds ic \/ +.el .ds ic \^ +.TH GROFF_OUT 5 "6 August 1992" "Groff Version 1.08" +.SH NAME +groff_out \- groff intermediate output format +.SH DESCRIPTION +This manual page describes the format output by GNU troff. +The output format used by GNU troff is very similar to that used +by Unix device-independent troff. Only the differences are documented +here. +.LP +The argument to the +.B s +command is in scaled points (units of +.IR points/ n , +where +.I n +is the argument to the +.B sizescale +command in the DESC file.) +The argument to the +.B x\ Height +command is also in scaled points. +.LP +The first three output commands are guaranteed to be: +.IP +.BI x\ T\ device +.br +.BI x\ res\ n\ h\ v +.br +.B x init +.LP +If the +.B tcommand +line is present in the DESC file, troff will use the following +two commands +.TP +.BI t xxx +.I xxx +is any sequence of characters terminated by a space or a newline; +the first character should be printed at the current position, +the the current horizontal position should be increased by +the width of the first character, and so on for each character. +The width of the character is that given in the font file, +appropriately scaled for the current point size, and rounded +so that it is a multiple of the horizontal resolution. +Special characters cannot be printed using this command. +.TP +.BI u n\ xxx +This is same as the +.B t +command except that after printing each character, the current horizontal +position is increased by the sum of the width of that character +and +.IR n . +.LP +Note that single characters can have the eighth bit set, as can the +names of fonts and special characters. +.LP +The names of characters and fonts an be of arbitrary length; drivers +should not assume that they will be only two characters long. +.LP +When a character is to be printed, that character will always be +in the current font. +Unlike device-independent troff, it is not necessary +for drivers to search special fonts to find a character. +.LP +The +.B D +drawing command has been extended. +These extensions will only be used by GNU pic if the +.B \-x +option is given. +.TP +\fBDf \fIn\fR\*(ic\en +Set the shade of gray to be used for filling solid objects to +.IR n ; +.I n +must be an integer between 0 and 1000, where 0 corresponds solid white +and 1000 to solid black, and values in between correspond to +intermediate shades of gray. +This applies only to solid circles, solid ellipses and solid +polygons. +By default, a level of 1000 will be used. +Whatever color a solid object has, it should completely obscure +everything beneath it. +A value greater than 1000 or less than 0 can also be used: +this means fill with the shade of gray that is currently being used +for lines and text. +Normally this will be black, but some drivers may provide +a way of changing this. +.TP +\fBDC \fId\fR\*(ic\en +Draw a solid circle with a diameter of +.I d +with the leftmost point at the current position. +.TP +\fBDE \fIdx dy\fR\*(ic\en +Draw a solid ellipse with a horizontal diameter of +.I dx +and a vertical diameter of +.I dy +with the leftmost point at the current position. +.EQ +delim $$ +.EN +.TP +\fBDp\fR $dx sub 1$ $dy sub 1$ $dx sub 2$ $dy sub 2$ $...$ $dx sub n$ $dy sub n$\en +Draw a polygon with, +for $i = 1 ,..., n+1$, the +.IR i -th +vertex at the current position +$+ sum from j=1 to i-1 ( dx sub j , dy sub j )$. +At the moment, +GNU pic only uses this command to generate triangles and rectangles. +.TP +\fBDP\fR $dx sub 1$ $dy sub 1$ $dx sub 2$ $dy sub 2$ $...$ $dx sub n$ $dy sub n$\en +Like +.B Dp +but draw a solid rather than outlined polygon. +.TP +\fBDt \fIn\fR\*(ic\en +Set the current line thickness to +.I n +machine units. +Traditionally Unix troff drivers use a line thickness proportional to the current +point size; drivers should continue to do this if no +.B Dt +command has been given, or if a +.B Dt +command has been given with a negative value of +.IR n . +A zero value of +.I n +selects the smallest available line thickness. +.LP +A difficulty arises in how the current position should be changed after +the execution of these commands. +This is not of great importance since the code generated by GNU pic +does not depend on this. +Given a drawing command of the form +.IP +\fB\eD\(fm\fIc\fR $x sub 1$ $y sub 1$ $x sub 2$ $y sub 2$ $...$ $x sub n$ $y sub n$\(fm +.LP +where +.I c +is not one of +.BR c , +.BR e , +.BR l , +.B a +or +.BR ~ , +Unix troff will treat each of the $x sub i$ as a horizontal quantity, +and each of the $y sub i$ as a vertical quantity and will assume that +the width of the drawn object is $sum from i=1 to n x sub i$, +and that the height is $sum from i=1 to n y sub i$. +(The assumption about the height can be seen by examining the +.B st +and +.B sb +registers after using such a +.B D +command in a \ew escape sequence.) +This rule also holds for all the original drawing commands +with the exception of +.BR De . +For the sake of compatibility GNU troff also follows this rule, +even though it produces an ugly result in the case of the +.BR Df , +.BR Dt , +and, to a lesser extent, +.B DE +commands. +Thus after executing a +.B D +command of the form +.IP +\fBD\fIc\fR $x sub 1$ $y sub 1$ $x sub 2$ $y sub 2$ $...$ $x sub n$ $y sub n$\en +.LP +the current position should be increased by +$( sum from i=1 to n x sub i , sum from i=1 to n y sub i )$. +.LP +There is a continuation convention which permits the argument to the +.B x\ X +command to contain newlines: +when outputting the argument to the +.B x\ X +command, GNU troff +will follow each newline in the argument with a +.B + +character +(as usual, it will terminate the entire argument with a newline); +thus if the line after the line containing the +.B x\ X +command starts with +.BR + , +then the newline ending the line containing the +.B x\ X +command should be treated as part of the argument to the +.B x\ X +command, +the +.B + +should be ignored, +and the part of the line following the +.B + +should be treated like the part of the line following the +.B x\ X +command. +.SH "SEE ALSO" +.BR groff_font (5) diff --git a/gnu/usr.bin/groff/mm/ChangeLog b/gnu/usr.bin/groff/mm/ChangeLog new file mode 100644 index 0000000000..389777fa85 --- /dev/null +++ b/gnu/usr.bin/groff/mm/ChangeLog @@ -0,0 +1,252 @@ +Mon Mar 29 10:53:13 1993 Joergen Haegg (jh at efd.lth.se) + + * version 1.16 + * MUL* now use the previus font and family. + * extra blank page at end-of-text eliminated. + +Mon Mar 8 10:27:47 1993 Joergen Haegg (jh at efd.lth.se) + + * version 1.15 + * Didn't restore pointsize to current size in .H. + * B1/B2 did not work with indent. (MULE and friends) + * fixed old problem with trailing empty pages. + +Fri Mar 5 15:20:49 1993 Joergen Haegg (jh at efd.lth.se) + + * version 1.14 + * Sigh. Amazing what a missing \} can do. If the string + HP was set, then all text disappeared... + +Fri Mar 5 14:12:43 1993 Joergen Haegg (jh at efd.lth.se) + + * version 1.13 + * Fixed bug with handling ps/vs in .H. (again, sigh... ) + +Wed Mar 3 09:21:20 1993 Joergen Haegg (jh at efd.lth.se) + + * version 1.12 + * Line-break added to PGFORM. + * added more features to VERBON + * .S is not used anymore in H, it caused confusion with + normal text, but it will still set .vs. + * SK was broken, will now produce the requested number of + empty pages. + * dotted lines added to LIST OF FIGURES adn friends. + Also better linespacing. + +Mon Feb 22 12:41:06 1993 Joergen Haegg (jh at efd.lth.se) + + * version 1.11 + * missing left-parenthesis gave ") .sp" when N=4. + * N=4 removed user-specified header also. + * MOVE made linelength pageoffset wider than wanted. + * fixed (again) parenthesis in RP. + +Thu Jan 21 12:10:39 1993 Joergen Haegg (jh at efd.lth.se) + + * version 1.10 + * changed PROG_PREFIX to g in the manual-pages. + * Better check if new page is needed in .H, when Ej>0. + * Usage of variable Lsp now more complete. + * Space added in TOC when mark is equal to size. + * Usermacro HY moved after font-calulations. + * .S used instead of .ps, which will use .vs correct. + * Now possible to set Hps1/2 inside HX. + * .FD "" 1 is now fixed. + * section-page numbering bug fixed. + * several bugs in VERBON/OFF fixed. + +Tue Dec 8 16:43:15 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.09 + * N==4 gives no default header + +Sat Nov 21 14:28:20 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.08 + * Escape-character disabled between + VERBON/VERBOFF (turned on by an argument). + Pointsize and fontchange also added as arguments. + * MULB, MULN and MULE added to get multicolumn output + with different width. + * Number register N can now use 1-5. + * Register Sectp and Sectf added. + * Register P is now updated correctly for "section-page" numbering. + +Thu Nov 19 11:19:33 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.07 + * .OP fixed to eject a blank page if not odd. + +Fri Nov 13 09:46:09 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.06 + * Macro TL rewritten. TL depends now on a following .AU. + * NOTES updated. + * .lt is now used more frequent when linelength is changed. + * macro AST added. + * removed PH/EH/OH not needed in ?.MT. + +Wed Oct 28 14:35:43 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.05 + * .VM implemented. + * Possible bug in page heading fixed. Changed .sp to 'sp in HEADER. + +Thu Aug 20 13:56:31 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.04 + * page-break in .EQ moved. + * changed unit for footer-size and header-size from units to lines. + Fixes problems with .S and page-breaks. + * \n[%] is now treated as a string, wich makes it possible + to assign new formats to it. Unfortunately, it was necessary + to change the page-number-variable in GETPN to a string. + * Makefile.sub included. (Thank you, James) + +Thu May 7 16:14:10 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.03 + * Typo and centering in DS/DE fixed. + Even and odd pageheaders were reversed. + * LI: pad and mark-indent was lost in some earlier versions. Now fixed. + * fixed bug in reference to .FG, .TB, ... + * APP did not clear headercounters. + * Pointsize in titles is now only set at the beginning and + when PH, PF, OH, OF, EH and EF are used. + +Thu May 6 16:01:35 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.02 + * OP fixed. + +Fri Mar 6 09:36:09 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.01 + * two .LI without text between should not be printed + on the same row. Now fixed. + * figure titles and friends fixed, now possible with many .FG + in a DS/DE. Didn't always position correctly in previous version, + but is now always printed as it should. + * Makefile fixed for Ultrix. + * DS/DF could not handle empty arguments correct + * Missing .br i EQ added. + +Sat Jan 25 15:47:21 1992 Joergen Haegg (jh at efd.lth.se) + + * version 1.00 + * No betaversion anymore! + * Fixed headernumbers within appendixes. + * DS did not keep the same font as before DS. + * mmse did a line break. + +Fri Jan 24 14:38:16 1992 Joergen Haegg (jh at efd.lth.se) + + * version 0.16 + * bug in TC, multiple line headers did not wrap correctly. + * added support for mm/locale and mm/language_locale. + * cov*default-firm in locale sets name of firm in the MT covers. + * cov*location-xxxx in locale sets location xxxx to the contents + of cov*location-xxxx. Used in the MT covers. + * hanging indent in lists fixed. + * use larger empty lines if .nroff is defined. + * macros, like .P, can now be used inside abstracts. + * .S do not reset indentation anymore. + * .RS aA now sets a string, not an integer. + * appendix with .APP or .APPSK added. + +Thu Nov 28 22:00:59 1991 Joergen Haegg (jh at efd.lth.se) + + * version 0.15 + * Fixed .AU in MT 0-3, added support for variable Au. + * Bug in the positioning of the foot-notes. + * lists not indented properly. + * Hps1 and Hps2 added. + * COVER had to have an argument. + * table of contents can now have multiline header. + * .HU now increments headingvariable H? + * added the inclusion of a locale file. + +Sat Nov 23 14:40:17 1991 Joergen Haegg (jh at efd.lth.se) + + * version 0.14 + * bug when using -rO fixed. + * MT 1-4 added. + * default is now MT 1 + * .EQ/.EN can be used outside of .DS/.DE without complaints. But + I don't recommend it. Neither does the DWB books. + * LI don't break lines now if arg too big. + * PGFORM did not reset indent. + * Added the numbervariable Hps. + * Rewritten and added MT 0-5 + "string". + * Added TM. + * Indent to AS added + +Wed Nov 6 15:18:40 1991 Joergen Haegg (jh at efd.lth.se) + + * version 0.13 + * ds*format nod defined if PS/PE is used without DS/DE. + * GETST added, fourth argument to EX, FG, TB and EC added. + +Mon Nov 4 13:38:01 1991 Joergen Haegg (jh at efd.lth.se) + + * version 0.12 + * Fixed C,D,P,+-size in .S + +Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se) + * Next version will have ChangeLog entries... + * Bug in INITR fixed. + * VERBON/VERBOFF added to include programlistings + * Bug in .DE fixed, addition overflow +Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se) + * spelling error in month-names. + * WC should work now (no warranty :-) + * FD almost finished, some details missing. + * incorrect calculation of foot-notes fixed. + * DS/DE did not break page when the size was smaller than the paper + * Forward/backward referencesystem added. Se .INITR in README. + * mgmsw changed name to mgmse. +Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se) + * embarrassing bug in .P fixed + * .H did always eject page, now fixed. + * lost floating displays now found. + * accents added (from mgs) + * empty line in .EQ/.EN removed + * indentation in .TC corrected. + * indentation of DS/DE in lists fixed. + * .TB and friends now work inside DS/DE and outside. + * .WC partially implemented (WF and WD). Still working on it. + * .mso used if version>=1.02 +Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se) + * register P was not working. + * support for register Fg, Tb, Ec and Ex. + * list items was left on the previous page at a page break. + * tlevel in .TC now defaults to 2. + * string DT, EM and Tm supported. + * new macro: PGNH, see comments. + * bug in MOVE fixed. + * pagenumber in .TC fixed. + * a blank page was ejected if Ej==1, now fixed + * bug in floating display fixed (did break and SP wrong) + * bug in .SP fixed, no lines is now printed at top of page + * There are still problems with footnotes and displays in two column mode. +Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se) + * register P added (same as %) + * bug in floating displays fixed + * MOVE added + * MT added, see comment below + * COVER/COVEND added + * fixed bug in figure titles + * extended S, se comment below + * MT 0 added + * ms-cover added (COVER ms) +Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se) + * bugs in RD and comb. fonts fixed +Sun Jan 1 00:00:00 1991 Joergen Haegg (jh at efd.lth.se) + * HC added + * Combined fonts (IB,BI...) + * HM added + * RD added + * OP added + * TP&PX supported + * warnings for unimplemented macros diff --git a/gnu/usr.bin/groff/mm/Makefile b/gnu/usr.bin/groff/mm/Makefile new file mode 100644 index 0000000000..09d614cf24 --- /dev/null +++ b/gnu/usr.bin/groff/mm/Makefile @@ -0,0 +1,34 @@ +TMACOWN?= bin +TMACGRP?= bin +TMACMODE?= 444 +TMACDIR?= /usr/share/tmac + +FILES= 0.MT 5.MT 4.MT ms.cov se_ms.cov +LOCALE= locale se_locale + +MAN7= groff_mm.0 groff_mmse.0 +MLINKS= groff_mm.7 mm.7 groff_mmse.7 mmse.7 + +afterinstall: + install -c -o $(TMACOWN) -g $(TMACGRP) -m $(TMACMODE) \ + $(.CURDIR)/tmac.m $(DESTDIR)$(TMACDIR)/tmac.$(tmac_m) + install -c -o $(TMACOWN) -g $(TMACGRP) -m $(TMACMODE) \ + $(.CURDIR)/tmac.m $(DESTDIR)$(TMACDIR)/tmac.$(tmac_m)se + + test -d $(DESTDIR)$(TMACDIR)/mm || mkdir $(DESTDIR)$(TMACDIR)/mm + chown $(TMACOWN).$(TMACGRP) $(DESTDIR)$(TMACDIR)/mm + chmod 755 $(DESTDIR)$(TMACDIR)/mm + + for f in $(FILES); do \ + rm -f $(TMACDIR)/mm/$$f; \ + install -c -o $(TMACOWN) -g $(TMACGRP) -m $(TMACMODE) \ + $(.CURDIR)/mm/$$f $(DESTDIR)$(TMACDIR)/mm/$$f; \ + done + for f in $(LOCALE); do \ + test -f $(DESTDIR)$(TMACDIR)/mm/$$f || touch $(DESTDIR)$(TMACDIR)/mm/$$f; \ + chown $(TMACOWN).$(TMACGRP) $(DESTDIR)$(TMACDIR)/mm/$$f; \ + chmod $(TMACMODE) $(DESTDIR)$(TMACDIR)/mm/$$f; \ + done + +.include +.include "../Makefile.cfg" diff --git a/gnu/usr.bin/groff/mm/NOTES b/gnu/usr.bin/groff/mm/NOTES new file mode 100644 index 0000000000..ee258d349e --- /dev/null +++ b/gnu/usr.bin/groff/mm/NOTES @@ -0,0 +1,101 @@ +###################################################################### + +Implementation notes. (Or how to make your own national mm) + +Different commands: + +COVER [arg] +MT [arg [addressee]] +The arg is part of a filename in mm/*.MT or mm/*.cov. +This file is read when the macro is executed. Therefore it must be +put before any text output. +In each file there are definitions of all extra macros needed for the +cover sheet. MT files is only for compatibility reasons, and has several +limits due to that it don't know when the cover starts, and cannot +change sizes. Use COVER for new coversheet macros. + +But with MT it is possible to write all of the AT&T covers. +An example can be found in mm/0.MT. + +When writing a new cover using COVER, have in mind that the cover +should print the page with the COVEND macro. This macro +should be defined by the new macrofile. + +Here is a part of ms.cov: +> .\"----------------- +> .de COVEND +> .sp |4.2c +> .cov@print-title +> .cov@print-authors +> .cov@print-firm +> .cov@print-abstract +> .cov@print-date +This is important, since COVER disables the page header. +> .pg@enable-top-trap +Should begin with page one (normally). +> .bp 1 +And enable the trap at the page footer. +> .pg@enable-trap +> .. + +######################### + +Variables for covers: +I = integer +S = string +D = diversion +M = macro + +Name Type Desc. +cov*au I The number of authors. + +cov*title M Title collected with .TL. + +cov*au!x!y S Author(s) given to .AU +cov*at!x!y S Author(s) title given to .AT + x is the author-index [1-cov*au], + y is the argument-index [1-9]. + Look at the table with indexes. + +cov*firm I Author(s) firm. + +cov*abs-arg I Argument to abstract. + +cov*abs-ind I Indent for abstract. + +cov*abs-name S The string 'ABSTRACT', changed with .AST + +cov*abstract M The abstract. + +cov*new-date S The date (todays date if ND is not used) + +cov*mt-type S MT type +cov*mt-addresse S MT addressee + + +########################## +Argument-index for cov*au: + +Index Desc. +1 name +2 initials +3 location +4 department +5 extension +6 room +7 arg 7 +8 arg 8 +9 arg 9 + +The location is set to the contents of string cov*location-xxxx +if location is equal to xxxx and cov*location-xxxx is defined +in the file locale. + + +Argument-index for cov*at: + +Index Desc. +1 title 1 +. . +. . +9 title 9 diff --git a/gnu/usr.bin/groff/mm/README b/gnu/usr.bin/groff/mm/README new file mode 100644 index 0000000000..54b32d211c --- /dev/null +++ b/gnu/usr.bin/groff/mm/README @@ -0,0 +1,26 @@ +This is mgm, a macro package for groff. + +It is supposed to be compatible with the DWB mm macros, +and has several extensions. + +Send bug reports to jh@efd.lth.se with a description of the problem +and a sample of text which reproduces the error. + +Don't forget to mention the version of mgm (look in the beginning +of tmac.m) and the version of groff. + +Any new ideas or improvements are welcome. + +Newest version is available with anonymous FTP +at ftp.efd.lth.se [130.235.48.11], as pub/groff/mm.Z + +You can install mgm as a separate package without the configure in groff +with the following command: + +make -f Makefile.sim install + +This README should be bigger :-) + +Jörgen. + +Thanks to everyone who have send me bug-reports and fixes. diff --git a/gnu/usr.bin/groff/mm/groff_mm.7 b/gnu/usr.bin/groff/mm/groff_mm.7 new file mode 100644 index 0000000000..68313b3151 --- /dev/null +++ b/gnu/usr.bin/groff/mm/groff_mm.7 @@ -0,0 +1,738 @@ +.TH GROFF_MM 7 "4 March 1993" "Groff Version 1.08" +.SH NAME +groff_mm \- groff mm macros +.SH SYNOPSIS +.B groff +.B \-mm +[ +.IR options .\|.\|. +] +[ +.IR files .\|.\|. +] +.SH DESCRIPTION +The groff mm macros are intended to be compatible with the DWB mm macros +with the following limitations: +.TP +.B \(bu +no letter macros implemented (yet). +.TP +.B \(bu +no Bell Labs localisms implemented. +.TP +.B \(bu +the macros OK and PM is not implemented. +.TP +.B \(bu +groff mm does not support cut marks +.LP +\fBmm\fP is intended to be international. Therefore it is +possible to write short national macrofiles which change all +english text to the preferred language. Use \fBmmse\fP as an example. +.LP +Groff mm has several extensions: +.TP +.B "APP name text" +Begin an appendix with name \fIname\fP. Automatic naming occurs if +\fIname\fP is "". The appendixes starts with \fBA\fP if auto is used. +An new page is ejected, and a header is also produced if the number +variable \fBAph\fP is non-zero. This is the default. +The appendix always appear in the 'List of contents' with correct +pagenumber. The name \fIAPPENDIX\fP can be changed by setting +the string \fBApp\fP to the desired text. +.TP +.B "APPSK name pages text" +Same as \fB.APP\fP, but the pagenr is incremented with \fIpages\fP. +This is used when diagrams or other non-formatted documents are +included as appendixes. +.TP +.B B1 +Begin box (as the ms macro) +Draws a box around the text. +.TP +.B B2 +End box. Finish the box. +.TP +.B BVL +Start of +broken variable-item list. +As VL but text begins always at the next line +.TP +.B "COVER [arg]" +\&\fBCOVER\fP begins a coversheet definition. It is important +that \fB.COVER\fP appears before any normal text. +\&\fB.COVER\fP uses \fIarg\fP to build the filename +/usr/share/tmac/mm/\fIarg\fP.cov. Therefore it is possible to create unlimited +types of coversheets. +\fIms.cov\fP is supposed to look like the \fBms\fP coversheet. +\&\fB.COVER\fP requires a \fB.COVEND\fP at the end of the coverdefinition. +Always use this order of the covermacros: +.nf +\&.COVER +\&.TL +\&.AF +\&.AU +\&.AT +\&.AS +\&.AE +\&.COVEND +.fi +However, only \fB.TL\fP and \fB.AU\fP are required. +.TP +.B COVEND +This finish the cover description and prints the cover-page. +It is defined in the cover file. +.TP +.B "GETHN refname [varname]" +Includes the headernumber where the corresponding \fBSETR\fP \fIrefname\fP +was placed. Will be X.X.X. in pass 1. See \fBINITR\fP. +If varname is used, \fBGETHN\fP sets the stringvariable \fIvarname\fP to the +headernumber. +.TP +.B "GETPN refname [varname]" +Includes the pagenumber where the corresponding \fBSETR\fP \fIrefname\fP +was placed. Will be 9999 in pass 1. See \fBINITR\fP. +If varname is used, \fBGETPN\fP sets the stringvariable \fIvarname\fP +to the pagenumber. +.TP +.B "GETR refname" +Combines \fBGETHN\fP and \fBGETPN\fP with the text 'chapter' and ', page'. +The string \fIQrf\fP contains the text for reference: +.ti +.5i +\&.ds Qrf See chapter \e\e*[Qrfh], page \e\e*[Qrfp]. +.br +\fIQrf\fP may be changed to support other languages. +Strings \fIQrfh\fP and \fIQrfp\fP are set by \fBGETR\fP +and contains the page and headernumber. +.TP +.B "GETST refname [varname]" +Includes the string saved with the second argument to \fB.SETR\fP. +Will be dummystring in pass 1. +If varname is used, \fBGETST\fP sets the stringvariable \fIvarname\fP to the +saved string. See \fBINITR\fP. +.TP +.B "INITR filename" +Initialize the refencemacros. References will be written to +\fIfilename.tmp\fP and \fIfilename.qrf\fP. Requires two passes with groff. +The first looks for references and the second includes them. +\fBINITR\fP can be used several times, but it is only the first +occurence of \fBINITR\fP that is active. +See also \fBSETR\fP, \fBGETPN\fP and \fBGETHN\fP. +.TP +.B "MC column-size [column-separation] " +Begin multiple columns. Return to normal with 1C. +.TP +.B "MT [arg [addressee]]" +Memorandom type. +The \fIarg\fP is part of a filename in \fI/usr/share/tmac/mm/*.MT\fP. +Memorandum type 0 thru 5 are supported, including \fI"string"\fP. +\fIAddresse\fP just sets a variable, used in the AT&T macros. +.TP +.B "MOVE y-pos [x-pos [line-length]]" +Move to a position, pageoffset set to \fIx-pos\fP. +If \fIline-length\fP is not given, the difference between +current and new pageoffset is used. +Use \fBPGFORM\fP without arguments to return to normal. +.TP +.B "MULB cw1 space1 [cw2 space2 [cw3 ...]]" +Begin a special multi-column mode. Every columns width must be specified. +Also the space between the columns must be specified. The last column +does not need any space-definition. MULB starts a diversion and MULE +ends the diversion and prints the columns. +The unit for width and space is 'n', but MULB accepts all +normal unitspecifications like 'c' and 'i'. +MULB operates in a separate environment. +.TP +.B "MULN" +Begin the next column. This is the only way to switch column. +.TP +.B "MULE" +End the multi-column mode and print the columns. +.TP +.B "PGFORM [linelength [pagelength [pageoffset]]]" +Sets linelength, pagelength and/or pageoffset. +This macro can be used for special formatting, like letterheads +and other. +\fBPGFORM\fP can be used without arguments +to reset everything after a \fBMOVE\fP. +.TP +.B PGNH +No header is printed on the next page. Used to get rid off +the header in letters or other special texts +This macro must be used before any text to inhibit the pageheader +on the first page. +.TP +.B "SETR refname [string]" +Remember the current header and page-number as refname. +Saves \fIstring\fP if \fIstring\fP is defined. \fIstring\fP is retrieved +with \fB.GETST\fP. +See \fBINITR\fP. +.TP +.B TAB +reset tabs to every 5n. Normally used to reset any previous tabpositions. +.TP +.B VERBON [flag [pointsize [font]]] +Begin verbatim output using courier font. +Usually for printing programs. +All character has equal width. +The pointsize can be changed with +the second argument. By specifying the font-argument +it is possible to use another font instead of courier. +\fIflag\fP control several special features. +It contains the sum of all wanted features. +.in +.5i +.ti -.5i +Value +.sp -1 +Description +.ti -.5i +1 +.sp -1 +Enable the escape-character (\e). This is normally turned off during +verbose output. +.ti -.5i +2 +.sp -1 +Add en empty line before the verbose text. +.ti -.5i +4 +.sp -1 +Add en empty line after the verbose text. +.ti -.5i +8 +.sp -1 +Print the verbose text with numbered lines. This adds four digitsized +spaces in the beginning of each line. Finer control is available with +the string-variable \fBVerbnm\fP. It contains all arguments to the +\fBtroff\fP-command \fB.nm\fP, normally '1'. +.ti -.5i +16 +.sp -1 +Indent the verbose text with five 'n':s. This is controlled by the +number-variable \fBVerbin\fP (in units). +.in +.TP +.B VERBOFF +End verbatim output. +.sp +.LP +.\"######################################################################## +New variables in mm: +.TP +.B App +A string containing the word "APPENDIX". +.TP +.B Aph +Print an appendix-page for every new appendix +if this numbervariable is non-zero. +No output will occur if \fBAph\fP is zero, but there will always +be an appendix-entry in the 'List of contents'. +.TP +.B Hps +Numbervariable with the heading pre-space level. If the heading-level +is less than or equal to \fBHps\fP, then two lines will precede the +section heading instead of one. Default is first level only. +The real amount of lines is controlled by the variables \fBHps1\fP and +\fBHps2\fP. +.TP +.B Hps1 +This is the number of lines preceding \fB.H\fP when the heading-level +is greater than \fBHps\fP. Value is in units, normally 0.5v. +.TP +.B Hps2 +This is the number of lines preceding \fB.H\fP when the heading-level +is less than or equal to \fBHps\fP. Value is in units, normally 1v. +.TP +.B Lifg +String containing \fIFigure\fP. +.TP +.B Litb +String containing \fITABLE\fP. +.TP +.B Liex +String containing \fIExhibit\fP. +.TP +.B Liec +String containing \fIEquation\fP. +.TP +.B Licon +String containing \fICONTENTS\fP. +.TP +.B Lsp +.TP +The size of an empty line. Normally 0.5v, but it is 1v +if \fBn\fP is set (\fB.nroff\fP). +.B "MO1 - MO12" +Strings containing \fIJanuary\fI to \fIDecember\fP. +.TP +.B Qrf +String containing "See chapter \e\e*[Qrfh], page \e\en[Qrfp].". +.TP +.B Sectf +Flag controlling "section-figures". A non-zero value enables this. +Se also register N. +.TP +.B Sectp +Flag controlling "section-page-numbers". A non-zero value enables this. +Se also register N. +.TP +.B .mgm +Always 1. +.\"######################################################################## +.LP +A file called \fBlocale\fP or \fIlang\fP\fB_locale\fP is read +after the initiation of the global variables. It is therefore +possible to localize the macros with companyname and so on. +.sp 3 +.LP +The following standard macros are implemented: +.TP +.B 1C +Begin one column processing +.TP +.B 2C +Begin two column processing +.TP +.B AE +Abstract end +.TP +.B "AF [name of firm]" +Authors firm +.TP +.B "AL [type [text-indent [1]]]]" +Start autoincrement list +.TP +.B "AS [arg [indent]]" +Abstract start. Indent is specified in 'ens', but scaling is allowed. +.TP +.B "AST [title]" +Abstract title. Default is 'ABSTRACT'. +.TP +.B "AT title1 [title2 ...]" +Authors title +.TP +.B "AU name [initials [loc [dept [ext [room [arg [arg [arg]]]]]]]]" +Author information +.TP +.B "B [bold-text [prev-font-tex [...]]]" +Begin boldface +No limit on the number of arguments. +.TP +.B BE +End bottom block +.TP +.B "BI [bold-text [italic-text [bold-text [...]]]" +Bold-italic. +No limit on the number of arguments. +.TP +.B "BL [text-indent [1]]" +Start bullet list +.TP +.B "BR [bold-text [roman-text [bold-text [...]]]" +Bold-roman. +No limit on the number of arguments. +.TP +.B BS +Bottom block start +.TP +.B DE +Display end +.TP +.B "DF [format [fill [rindent]]]" +Begin floating display (no nesting allowed) +.TP +.B "DL [text-indent [1]]" +Dash list start +.TP +.B "DS [format [fill [rindent]]]" +Static display start. +Can now have unlimited nesting. Also +right adjusted text and block may be used (R or RB as \fIformat\fP). +.TP +.B "EC [title [override [flag [refname]]]]" +Equation title. +If \fIrefname\fP is used, then the equationnumber is saved with +\&\fB.SETR\fP, and can be retrieved with \fB.GETST\fP \fIrefname\fP. +.TP +.B "EF [arg]" +Even-page footer. +.TP +.B "EH [arg]" +Even-page header. +.TP +.B EN +Equation end. +.TP +.B "EQ [label]" +Equation start. +.TP +.B "EX [title [override [flag [refname]]]]" +Exhibit title. +If \fIrefname\fP is used, then the exhibitnumber is saved with +\&\fB.SETR\fP, and can be retrieved with \fB.GETST\fP \fIrefname\fP. +.TP +.B "FD [arg [1]]" +Footnote default format. +.TP +.B FE +Footnote end. +.TP +.B "FG [title [override [flag [refname]]]]" +Figure title. +If \fIrefname\fP is used, then the figurenumber is saved with +\&\fB.SETR\fP, and can be retrieved with \fB.GETST\fP \fIrefname\fP. +.TP +.B FS +Footnote start. +Footnotes in displays is now possible. +.TP +.B "H level [heading-text [heading-suffix]]" +Numbered heading. +.TP +.B "HC [hypenation-character]" +Set hypenation character. +.TP +.B "HM [arg1 [arg2 [... [arg7]]]]" +Heading mark style. +.TP +.B "HU heading-text" +Unnumbered header. +.TP +.B "HX dlevel rlevel heading-text" +Userdefined heading exit. +Called just before printing the header. +.TP +.B "HY dlevel rlevel heading-text" +Userdefined heading exit. +Called just before printing the header. +.TP +.B "HZ dlevel rlevel heading-text" +Userdefined heading exit. +Called just after printing the header. +.TP +.B "I [italic-text [prev-font-text [italic-text [...]]]" +Italic. +.TP +.B "IB [italic-text [bold-text [italic-text [...]]]" +Italic-bold +.TP +.B "IR [italic-text [roman-text [italic-text [...]]]" +Italic-roman +.TP +.B "LB text-indent mark-indent pad type [mark [LI-space [LB-space]]]" +List begin macro. +.TP +.B "LC [list level]" +List-status clear +.TP +.B LE +List end. +.TP +.B "LI [mark [1]]" +List item +.TP +.B "ML mark [text-indent]" +Marked list start +.TP +.B "MT [arg [addressee]]" +Memorandom type. See above note about MT. +.TP +.B "ND new-date" +New date. +.TP +.B "OF [arg]" +Odd-page footer +.TP +.B "OH [arg]" +Odd-page header +.TP +.B OP +Skip to odd page. +.TP +.B "P [type]" +Begin new paragraph. +.TP +.B PE +Picture end. +.TP +.B "PF [arg]" +Page footer +.TP +.B "PH [arg]" +Page header +.TP +.B PS +Picture start (from pic) +.TP +.B PX +Page-header user-defined exit. +.TP +.B R +Roman. +.TP +.B "RB [roman-text [bold-text [roman-text [...]]]" +Roman-bold. +.TP +.B "RD [prompt [diversion [string]]]" +Read to diversion and/or string. +.TP +.B RF +Reference end +.TP +.B "RI [roman-text [italic-text [roman-text [...]]]" +Roman-italic. +.TP +.B "RL [text-indent [1]]" +Reference list start +.TP +.B "RP [arg [arg]]" +Produce reference page. +.TP +.B "RS [string-name]" +Reference start. +.TP +.B "S [size [spacing]]" +Set point size and vertical spacing. If any argument is equal 'P', then +the previous value is used. A 'C' means current value, and 'D' default value. +If '+' or '-' is used before the value, then increment or decrement of +the current value will be done. +.TP +.B "SA [arg]" +Set adjustment. +.TP +.B "SK [pages]" +Skip pages. +.TP +.B "SM string1 [string2 [string3]]" +Make a string smaller. +.TP +.B "SP [lines]" +Space vertically. \fIlines\fP can have any scalingfactor, like \fI3i\fP or +\fI8v\fP. +.TP +.B "TB [title [override [flag [refname]]]]" +Table title. +If \fIrefname\fP is used, then the tablenumber is saved with +\&\fB.SETR\fP, and can be retrieved with \fB.GETST\fP \fIrefname\fP. +.TP +.B "TC [slevel [spacing [tlevel [tab [h1 [h2 [h3 [h4 [h5]]]]]]]]]" +Table of contents. +All texts can be redefined, new stringvariables +\fILifg\fP, \fILitb\fP, \fILiex\fP, \fILiec\fP and \fILicon\fP contains +"Figure", "TABLE", "Exhibit", "Equation" and "CONTENTS". +These can be redefined to other languages. +.TP +.B TE +Table end. +.TP +.B "TH [N]" +Table header. +.TP +.B TL +Begin title of memorandom. +.TP +.B TM [num1 [num2 [...]]] +Technical memorandumnumbers used in \fB.MT\fP. Unlimited number +of arguments may be given. +.TP +.B TP +Top of page user-defined macro. +.TP +.B "TS [H]" +Table start +.TP +.B TX +Userdefined table of contents exit. +.TP +.B TY +Userdefined tbale of contents exit (no "CONTENTS"). +.TP +.B "VL [text-indent [mark-indent [1]]]" +Variable-item list start +.TP +.B "VM [top [bottom]]" +Vertical margin. +.TP +.B "WC [format]" +Footnote and display width control. +.sp 3 +.LP +Strings used in mm: +.TP +.B "EM" +Em dash string +.TP +.B HF +Fontlist for headings, normally "2 2 2 2 2 2 2". +Nonnumeric fontnames may also be used. +.TP +.B HP +Pointsize list for headings. Normally "0 0 0 0 0 0 0" which is the same as +"10 10 10 10 10 10 10". +.TP +.B Lf +Contains "LIST OF FIGURES". +.TP +.B Lt +Contains "LIST OF TABLES". +.TP +.B Lx +Contains "LIST OF EXHIBITS". +.TP +.B Le +Contains "LIST OF EQUATIONS". +.TP +.B Rp +Contains "REFERENCES". +.TP +.B Tm +Contains \e(tm, trade mark. +.\"----------------------------------- +.LP +Number variables used in mm: +.TP +.B Cl=2 +Contents level [0:7], contents saved if heading level <= Cl +.TP +.B Cp=0 +Eject page between LIST OF XXXX if Cp == 0 +.TP +.B D=0 +Debugflag, values >0 produces varying degree of debug. A value of 1 +gives information about the progress of formatting. +.TP +.B De=0 +Eject after floating display is output [0:1] +.TP +.B Df=5 +Floating keep output [0:5] +.TP +.B Ds=1 +space before and after display if == 1 [0:1] +.TP +.B Ej=0 +Eject page +.TP +.B Eq=0 +Eqation lable adjust 0=left, 1=right +.TP +.B Fs=1 +Footnote spacing +.TP +.B "H1-H7" +Heading counters +.TP +.B Hb=2 +Heading break level [0:7] +.TP +.B Hc=0 +Heading centering level, [0:7] +.TP +.B Hi=1 +Heading temporary indent [0:2] +0 -> 0 indent, left margin +.br +1 -> indent to right , like .P 1 +.br +2 -> indent to line up with text part of preceding heading +.TP +.B Hs=2 +Heading space level [0:7] +.TP +.B Ht=0 +Heading numbering type +0 -> multiple (1.1.1 ...) +.br +1 -> single +.TP +.B Hu=2 +Unnumbered heading level +.TP +.B Hy=1 +Hyphenation in body +0 -> no hyphenation +.br +1 -> hyphenation 14 on +.TP +.B "Lf=1, Lt=1, Lx=1, Le=0" +Enables (1) or disables (0) the printing of List of figures, +List of tables, List of exhibits and List of equations. +.TP +.B Li=6 +List indent, used by .AL +.TP +.B Ls=99 +List space, if current listlevel > Ls then no spacing will occur around lists. +.TP +.B N=0 +Numbering style [0:5] +0 == (default) normal header for all pages. +.br +1 == header replaces footer on first page, header is empty. +.br +2 == page header is removed on the first page. +.br +3 == "section-page" numbering enabled. +.br +4 == page header is removed on the first page. +.br +5 == "section-page" and "section-figure" numbering enabled. +Se also the number-register Sectf and Sectp. +.TP +.B Np=0 +Numbered paragraphs. +.br +0 == not numbered +.br +1 == numbered in first level headings. +.TP +.B Of=0 +Format of figure,table,exhibit,equation titles. +.br +0= ". " +.br +1= " - " +.TP +.B P +Current page-number, normally the same as % unless "section-page" numbering +is enabled. +.TP +.B Pi=5 +paragraph indent +.TP +.B Ps=1 +paragraph spacing +.TP +.B Pt=0 +Paragraph type. +.br +0 == left-justified +.br +1 == indented .P +.br +2 == indented .P except after .H, .DE or .LE. +.TP +.B Si=5 +Display indent. +.LP +.\".SH BUGS +.SH AUTHOR +Jörgen Hägg, Lund Institute of Technology, Sweden +.SH FILES +.TP +.B /usr/share/tmac/tmac.m +.TP +.B /usr/share/tmac/mm/*.cov +.TP +.B /usr/share/tmac/mm/*.MT +.TP +.B /usr/share/tmac/mm/locale +.SH "SEE ALSO" +.BR groff (1), +.BR troff (1), +.BR tbl (1), +.BR pic (1), +.BR eqn (1) +.br +.BR mm (7) +.BR mmse (7) diff --git a/gnu/usr.bin/groff/mm/groff_mmse.7 b/gnu/usr.bin/groff/mm/groff_mmse.7 new file mode 100644 index 0000000000..eabdbda914 --- /dev/null +++ b/gnu/usr.bin/groff/mm/groff_mmse.7 @@ -0,0 +1,36 @@ +.\" +.\" Skrivet av Jörgen Hägg, Lund, Sverige +.\" +.TH GROFF_MMSE 7 "21 February 1993" "Groff Version 1.08" +.SH NAMN +groff_mmse \- svenska mm makro för groff +.SH SYNTAX +.B groff +.B \-mmse +[ +.IR flaggor .\|.\|. +] +[ +.IR filer .\|.\|. +] +.SH BESKRIVNING +\fBmmse\fP är en svensk variant av \fBmm\fP. Alla texter +är översatta. En A4 sida får text som är 13 cm bred, 3.5 cm indragning +samt är 28.5 cm hög. +.LP +\fBCOVER\fP kan använda \fIse_ms\fP som argument. Detta ger ett +svenskt försättsblad. +Se \fBgroff_mm(7)\fP för övriga detaljer. +.SH "SKRIVET AV" +Jörgen Hägg, Lunds Tekniska Högskola +.SH FILER +.B /usr/share/tmac/tmac.mse +.B /usr/share/tmac/mm/se_*.cov +.SH "SE OCKSÅ" +.BR groff (1), +.BR troff (1), +.BR tbl (1), +.BR pic (1), +.BR eqn (1) +.br +.BR mm (7) diff --git a/gnu/usr.bin/groff/mm/mm/0.MT b/gnu/usr.bin/groff/mm/mm/0.MT new file mode 100644 index 0000000000..1ac4859844 --- /dev/null +++ b/gnu/usr.bin/groff/mm/mm/0.MT @@ -0,0 +1,143 @@ +.\"------------ +.\" Cover sheet. Memorandum type 0-3 and "string". +.\"------------ +.if !r Au .nr Au 1 +.nr cov*mt0-ind 1.1c +.de cov@print-title +.MOVE 4.8c 1.5c +.S 8 +subject: +.sp -1.1 +.S +.PGFORM +.B +.ll 9c +.fi +.cov*title +.R +.ll +.nf +.if d cov*title-charge-case \fBCharge Case \\*[cov*title-charge-case]\fP +.if d cov*title-file-case \fBFile Case \\*[cov*title-file-case]\fP +.fi +.. +.\"------------ +.de cov@print-authors +.MOVE 5.7c 13.3c +.nf +.S 8 +\\$1: +.br +.S +.sp -1 +.in 0.8c +.B +.nr cov*i 0 1 +.while \\n+[cov*i]<=\\n[cov*au] \{\ +. cov@print-au1 \\n[cov*i] 1 +. if \\n[Au] \{\ +. cov@print-au2 \\n[cov*i] 3 4 +. cov@print-au2 \\n[cov*i] 6 5 +. cov@print-au1 \\n[cov*i] 7 +. cov@print-au1 \\n[cov*i] 8 +. cov@print-au1 \\n[cov*i] 9 +. \} +. if \\n[cov*i]<\\n[cov*au] .SP 1 +.\} +.R +.if r cov*mt-tm-max \{\ +. SP 1 +. nr cov*i 0 1 +. B +TM +. in 1.5c +. sp -1 +. while \\n+[cov*i]<\\n[cov*mt-tm-max] \\*[cov*mt-tm!\\n[cov*i]] +. in +. R +.\} +.fi +.PGFORM +.. +.\"------------ +.\" index arg1 +.de cov@print-au1 +.if d cov*au!\\$1!\\$2 \\*[cov*au!\\$1!\\$2] +.. +.\"------------ +.de cov@print-au2 +.\" index arg1 arg2 +.if d cov*au!\\$1!\\$2 \\*[cov*au!\\$1!\\$2] \c +.if \\$3=5 .if d cov*au!\\$1!\\$3 x\c +.if d cov*au!\\$1!\\$3 \\*[cov*au!\\$1!\\$3]\c +.br +.. +.\"------------ +.de cov@print-date +.MOVE 4.8c 13.3c +.S 8 +\\$1: +.br +.S +.sp -1 +.in 0.8c +.B "\\*[cov*new-date]" +.br +.PGFORM +.. +.\"------------ +.de cov@print-firm +.if d cov*firm \{\ +. MOVE 2.8c 0 17.7c +. S 18 +. rj 1 +\fB\\*[cov*firm]\fP +. S +. PGFORM +.\} +.. +.\"------------ +.de cov@print-abstract +.SP 3 +.if d cov*abstract \{\ +. misc@ev-keep cov*ev +. if \\n[cov*abs-ind]>0 \{\ +. in +\\n[cov*abs-ind]u +. ll -\\n[cov*abs-ind]u +. \} +. ce +\fI\\$1\fP +. SP 1.5 +. fi +. cov*abstract +. br +. ev +.\} +.. +.\"----------------- +.ds cov*mt0-txt!1 MEMORANDUM FOR FILE +.ds cov*mt0-txt!2 PROGRAMMER'S NOTES +.ds cov*mt0-txt!3 ENGINEER'S NOTES +.if d cov*default-firm .if !d cov*firm .ds cov*firm \\*[cov*default-firm] +.\" +.if !d cov*mt-printed \{\ +. cov@print-firm +. cov@print-title subject +. cov@print-date date +. cov@print-authors from +. cov@print-abstract \\*[cov*abs-name] +. SP 3 +. if (\*[cov*mt-type]>=1)&(\*[cov*mt-type]<=3) \{\ +. ce +\fI\*[cov*mt0-txt!\*[cov*mt-type]]\fP +. SP 1.5 +. \} +. if \*[cov*mt-type]=6 \{\ +. ce +\fI\*[cov*mt-type-text]\fP +. SP 1.5 +. \} +. pg@enable-top-trap +. pg@enable-trap +. ds cov*mt-printed +.\} diff --git a/gnu/usr.bin/groff/mm/mm/4.MT b/gnu/usr.bin/groff/mm/mm/4.MT new file mode 100644 index 0000000000..e36113247a --- /dev/null +++ b/gnu/usr.bin/groff/mm/mm/4.MT @@ -0,0 +1,65 @@ +.\"------------ +.\" Cover sheet. Memorandum type 4 +.\"------------ +.de cov@print-title +.MOVE 2.4c +.S 12 +.ad c +.fi +.B +.cov*title +.br +.S +.R +.ad b +.PGFORM +.. +.\"------------ +.de cov@print-authors +.SP 0.5 +.I +.nr cov*i 0 1 +.while \\n+[cov*i]<=\\n[cov*au] \{\ +.ce +\\*[cov*au!\\n[cov*i]!1] +.br +.\} +.R +.PGFORM +.. +.\"------------ +.de cov@print-firm +.SP 0.5 +.ce +\\*[cov*firm] +.. +.\"------------ +.de cov@print-abstract +.SP 2 +.if d cov*abstract \{\ +. misc@ev-keep cov*ev +. if \\n[cov*abs-ind]>0 \{\ +. in +\\n[cov*abs-ind]u +. ll -\\n[cov*abs-ind]u +. \} +. ce +\fI\\*[cov*abs-name]\fP +. SP 2 +. fi +. cov*abstract +. br +. ev +.\} +.. +.\"----------------- +.if d cov*default-firm .if !d cov*firm .ds cov*firm \\*[cov*default-firm] +.if !d cov*mt-printed \{\ +. cov@print-title +. cov@print-authors +. cov@print-firm +. cov@print-abstract +. SP 3 +. ds cov*mt-printed +. pg@enable-top-trap +. pg@enable-trap +.\} diff --git a/gnu/usr.bin/groff/mm/mm/5.MT b/gnu/usr.bin/groff/mm/mm/5.MT new file mode 100644 index 0000000000..654fc95f22 --- /dev/null +++ b/gnu/usr.bin/groff/mm/mm/5.MT @@ -0,0 +1,33 @@ +.\"------------ +.\" Cover sheet. Memorandum type 5 +.\"------------ +.nr cov*mt0-ind 1.1c +.de cov@print-title +.B +.ll 9c +.fi +.cov*title +.R +.ll +.nf +.if d cov*title-charge-case \fBCharge Case \\*[cov*title-charge-case]\fP +.if d cov*title-file-case \fBFile Case \\*[cov*title-file-case]\fP +.fi +.. +.\"------------ +.de cov@print-date +.rj 1 +.B "\\*[cov*new-date]" +.br +.. +.\"------------ +.if !d cov*mt-printed \{\ +. SP 1.9c +. cov@print-title +. SP 1.2c +. cov@print-date +. SP 3 +. pg@enable-top-trap +. pg@enable-trap +. ds cov*mt-printed +.\} diff --git a/gnu/usr.bin/groff/mm/mm/ms.cov b/gnu/usr.bin/groff/mm/mm/ms.cov new file mode 100644 index 0000000000..ee75113928 --- /dev/null +++ b/gnu/usr.bin/groff/mm/mm/ms.cov @@ -0,0 +1,82 @@ +.\"------------ +.\" Cover sheet. Mostly like ms cover. +.\"------------ +.de cov@print-title +.in 0 +.misc@ev-keep cov*ev +.init@reset +.ad c +.hy 0 +.fi +.B +.cov*title +.br +.ad b +.R +.ev +.. +.\"------------ +.de cov@print-authors +.SP +.nr cov*i 0 1 +.while \\n+[cov*i]<=\\n[cov*au] \{\ +. ce +\fI\\*[cov*au!\\n[cov*i]!1]\fP +. nr cov*j 0 1 +. while \\n+[cov*j]<=9 \{\ +. if d cov*at!\\n[cov*i]!\\n[cov*j] \{\ +. if \w'\\*[cov*at!\\n[cov*i]!\\n[cov*j]]' \{\ +. ce +\s-1\\*[cov*at!\\n[cov*i]!\\n[cov*j]]\s0 +. .\} +. \} +. \} +.\} +.. +.\"------------ +.de cov@print-firm +.SP .5 +.ce +\\*[cov*firm] +.. +.\"------------ +.de cov@print-abstract +.SP 2 +.if d cov*abstract \{\ +. misc@ev-keep cov*ev +. init@reset +. if \\n[cov*abs-ind]>0 \{\ +. in +\\n[cov*abs-ind]u +. ll -\\n[cov*abs-ind]u +. \} +. ce +\fI\\$1\fP +. SP 1.5 +. fi +. cov*abstract +. br +. ev +.\} +.. +.\"------------ +.de cov@print-date +.SP 2 +\\*[cov*new-date] +.. +.\"----------------- +.de COVEND +.if d cov*default-firm .if !d cov*firm .ds cov*firm \\*[cov*default-firm] +.sp |4.2c +.cov@print-title +.cov@print-authors +.cov@print-firm +.cov@print-abstract \\*[cov*abs-name] +.cov@print-date +.pg@enable-top-trap +.bp 1 +.pg@enable-trap +.if d cov*abs-arg .if \\n[cov*abs-arg] \{\ +. cov@print-abstract ABSTRACT +. SP 2 +.\} +.. diff --git a/gnu/usr.bin/groff/mm/mm/se_ms.cov b/gnu/usr.bin/groff/mm/mm/se_ms.cov new file mode 100644 index 0000000000..e6431f25e9 --- /dev/null +++ b/gnu/usr.bin/groff/mm/mm/se_ms.cov @@ -0,0 +1,2 @@ +.mso mm/ms.cov +.nr cur*abstract-ll 11c diff --git a/gnu/usr.bin/groff/mm/tmac.m b/gnu/usr.bin/groff/mm/tmac.m new file mode 100644 index 0000000000..d37bdac0a5 --- /dev/null +++ b/gnu/usr.bin/groff/mm/tmac.m @@ -0,0 +1,2582 @@ +.\" Version: +.ds RE 1.16 +.ig + +Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +mgm is written by Jörgen Hägg (jh@efd.lth.se) + +mgm is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +mgm is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Almost complete. The letter format is not included. +Maybe as a separate package. +Should be better as time goes. + +Please send bugreports with examples to jh@efd.lth.se. + +Naming convention stolen from mgs. +Local names module*name +Extern names module@name +Env.var environ:name +Index array!index +.. +.warn +.\" ####### init ###### +.\" Contents level [0:7], contents saved if heading level <= Cl +.nr Cl 2 +.\" Eject page between LIST OF XXXX if Cp == 0 +.nr Cp 0 +.\" Debugflag +.if !r D .nr D 0 +.\" Eject after floating display is output [0:1] +.nr De 0 +.\" Floating keep output [0;5] +.nr Df 5 +.\" space before and after display if == 1 [0:1] +.nr Ds 1 +.\" Eject page +.nr Ej 0 +.\" Eqation lable adjust 0=left, 1=right +.nr Eq 0 +.\" Em dash string +.ds EM \- +.\" Footnote spacing +.nr Fs 1 +.\" H1-H7 heading counters +.nr H1 0 1 +.nr H2 0 1 +.nr H3 0 1 +.nr H4 0 1 +.nr H5 0 1 +.nr H6 0 1 +.nr H7 0 1 +.\" Heading break level [0:7] +.nr Hb 2 +.\" heading centering level, [0:7] +.nr Hc 0 +.\" header format +.ds HF 2 2 2 2 2 2 2 +.\" heading temp. indent [0:2] +.\" 0 -> 0 indent, left margin +.\" 1 -> indent to right , like .P 1 +.\" 2 -> indent to line up with text part of preceding heading +.nr Hi 1 +.\" header pointsize +.ds HP 0 0 0 0 0 0 0 +.\" heading space level [0:7] +.nr Hs 2 +.\" heading numbering type +.\" 0 -> multiple (1.1.1 ...) +.\" 1 -> single +.nr Ht 0 +.\" Unnumbered heading level +.nr Hu 2 +.\" hyphenation in body +.\" 0 -> no hyphenation +.\" 1 -> hyphenation 14 on +.nr Hy 1 +.\" text for toc, selfexplanatory. Look in the new variable section +.ds Lf LIST OF FIGURES +.nr Lf 1 +.ds Lt LIST OF TABLES +.nr Lt 1 +.ds Lx LIST OF EXHIBITS +.nr Lx 1 +.ds Le LIST OF EQUATIONS +.nr Le 0 +.\" List indent, used by .AL +.nr Li 6 +.\" List space, if listlevel > Ls then no spacing will occur around lists. +.nr Ls 99 +.\" Numbering style [0:5] +.if !r N .nr N 0 +.\" numbered paragraphs +.\" 0 == not numbered +.\" 1 == numbered in first level headings. +.nr Np 0 +.\" Format of figure,table,exhibit,equation titles. +.\" 0= ". ", 1=" - " +.nr Of 0 +.\" Page-number, normally same as %. +.nr P 0 +.\" paragraph indent +.nr Pi 5 +.\" paragraph spacing +.nr Ps 1 +.\" paragraph type +.\" 0 == left-justified +.\" 1 == indented .P +.\" 2 == indented .P except after .H, .DE or .LE. +.nr Pt 0 +.\" Reference title +.ds Rp REFERENCES +.\" Display indent +.nr Si 5 +.\" +.ds Tm \(tm +.\" +.\"--------------------------------------------- +.\" Internal global variables +.\" +.\" These two are for cover macro .MT +.\" Change @langage in the national file. +.ds @cur-lib /usr/local/lib/groff/tmac +.\" .ds @language +.\" +.\" Current pointsize and vertical space, always in points. +.nr @ps 10 +.nr @vs 12 +.\" Page length +.ie r L .nr @pl \n[L] +.el .nr @pl 11i +.\" page width +.ie r W .nr @ll \n[W] +.el .nr @ll 6i +.\" page offset +.ie r O .nr @po \n[O] +.el .nr @po 1i +.\" +.\" cheating... +.pl \n[@pl]u +.ll \n[@ll]u +.lt \n[@ll]u +.po \n[@po]u +.nr @cur-ll \n[@ll] +.\" +.\" non-zero if escape mechanism is turned off. Used by VERBON/OFF +.nr @verbose-flag 0 +.\"--------------------------------------------- +.\" New variables +.\" +.\" Appendix name +.ds App APPENDIX +.\" print appendixheader, 0 == don't +.nr Aph 1 +.\" +.\" header prespace level. If level <= Hps, then two lines will be printed +.\" before the header instead of one. +.nr Hps 1 +.\" +.\" These variables controls the number of lines preceding .H. +.\" Hps1 is the number of lines when level > Hps +.nr Hps1 0.5v +.if n .nr Hps1 1v +.\" +.\" Hps2 is the number of lines when level >= Hps +.nr Hps2 1v +.if n .nr Hps2 2v +.\" +.\" flag for mkindex +.if !r Idxf .nr Idxf 0 +.\" Change these in the national configuration file +.ds Lifg Figure +.ds Litb TABLE +.ds Liex Exhibit +.ds Liec Equation +.ds Licon CONTENTS +.\" +.\" Lsp controls the height of an empty line. Normally 0.5v +.\" Normally used for nroff compatibility. +.nr Lsp 0.5v +.if n .nr Lsp 1v +.ds MO1 January +.ds MO2 February +.ds MO3 March +.ds MO4 April +.ds MO5 May +.ds MO6 June +.ds MO7 July +.ds MO8 August +.ds MO9 September +.ds MO10 October +.ds MO11 November +.ds MO12 December +.\" for GETR +.ds Qrf See chapter \\*[Qrfh], page \\*[Qrfp]. +.\" test for mgm macro. This can be used if the text must test +.\" what macros is used. +.\" +.\" section-page if Sectp > 0 +.nr Sectp 0 +.if (\n[N]=3):(\n[N]=5) \{\ +. nr Sectp 1 +. nr Ej 1 +.\} +.\" section-figure if Sectf > 0 +.nr Sectf 0 +.if \n[N]=5 .nr Sectf 1 +.\" +.\" argument to .nm in .VERBON. +.ds Verbnm "1 +.\" indent for VERBON +.nr Verbin 5n +.\" +.nr .mgm 1 +.\" +.\"--------------------------------------------- +.\" set local variables. +.ie d @language .mso mm/\\*[@language]_locale +.el .mso mm/locale +.\"--------------------------------------------- +.if \n[D] .tm Groff mm, version \*[RE]. +.\" ####### module init ###### +.\" reset all things +.de init@reset +.ie \\n[misc@adjust] 'ad +.el 'na +.ie \\n[Hy] 'hy 14 +.el 'nh +'in 0 +'ti 0 +'ps \\n[@ps] +'vs \\n[@vs] +.. +.de @error +.tm ****************** +.tm ERROR:(\\n[.F]) input line \\n[.c]:\\$* +.if \\n[D] .backtrace +.tm ****************** +.ab +.. +.\" ####### module debug ################################# +.de debug +.tm \\$1:\\n[.F]:\\n[c.] ll=\\n[.l] vs=\\n[.v] ps=\\n[.s],\\n[.ps] \ +in=\\n[.i] fi=\\n[.u] .d=\\n[.d] nl=\\n[nl] pg=\\n[%] +.. +.de debug-all +.nr debug*n 1n +.nr debug*m 1m +.tm \\$1:\\n[.F]:\\n[c.] ll=\\n[.l] vs=\\n[.v] ps=\\n[.s] in=\\n[.i]\ + ad=\\n[.j] fi=\\n[.u] pl=\\n[.p] page=\\n[%] .o=\\n[.o] +.tm _______ .d=\\n[.d] .f=\\n[.f] .h=\\n[.h] .k=\\n[.k] .n=\\n[.n]\ + .p=\\n[.p] .t=\\n[.t] .z=\\n[.z] nl=\\n[nl] dn=\\n[dn] n=\\n[debug*n] +.. +.\" ####### module par ################################# +.nr par@ind-flag 1 \" indent on following P if Pt=2 +.nr hd*last-pos -1 +.nr hd*last-hpos -1 +.nr par*number 0 1 +.af par*number 01 +.nr par*num-count 0 1 +.af par*num-count 01 +.\" reset numbered paragraphs, arg1 = headerlevel +.de par@reset-num +.if \\$1<3 .nr par*num-count 0 +.if (\\$1=1)&(\\n[Np]=1) .nr par*number 0 +.. +.\"------------ +.\" paragraph +.de P +.\" skip P if previous heading +.ie !((\\n[nl]=\\n[hd*last-pos]):(\\n[nl]=(\\n[hd*last-pos]-.5v))) \{\ +. if \\n[D]>2 .tm Paragraph +. par@doit \\$* +.\} +.el .if !(\\n[hd*last-hpos]=\\n[.k]) \{\ +. if \\n[D]>2 .tm Paragraph +. par@doit \\$* +.\} +.nr par@ind-flag 1 +.. +.de par@doit +.SP (u;\\n[Ps]*\\n[Lsp]) +.ie \\n[.$] \{\ +. if \\$1=1 .ti +\\n[Pi]n +.\} +.el \{\ +. if \\n[Pt]=1 .ti +\\n[Pi]n +. if (\\n[Pt]=2)&\\n[par@ind-flag] .ti +\\n[Pi]n +.\} +.if \\n[Np] \{\ +\\n[H1].\\n+[par*number]\ \ \c +.\" $$$ 'br +.\} +.. +.\" ####### module line ####################################### +.de SP +.br +.if !r line*lp\\n[.z] .nr line*lp\\n[.z] 0 +.if !r line*ac\\n[.z] .nr line*ac\\n[.z] 0 +.ie \\n[.$] .nr line*temp (v;\\$1) +.el .nr line*temp 1v +.\" +.ie \\n[line*lp\\n[.z]]=\\n[.d] \{\ +. \" go here if no output since the last .SP +. nr line*output \\n[line*temp]-\\n[line*ac\\n[.z]] +. if \\n[line*output]<0 .nr line*output 0 +. nr line*ac\\n[.z] +\\n[line*output] +.\} +.el \{\ +. nr line*ac\\n[.z] \\n[line*temp] +. nr line*output \\n[line*temp] +. \" no extra space in the beginning of a page +. if (\\n[.d]<0):(\\n[pg*head-mark]=\\n[.d]) .nr line*output 0 +.\} +.if \\n[line*output] .sp \\n[line*output]u +.nr line*lp\\n[.z] \\n[.d] +.. +.\" ######## module misc ############### +.nr misc@adjust 14 +.de SA +.if \\n[.$] \{\ +. if \\$1-1 .@error "SA: bad arg: \\$1" +. nr misc@adjust 0\\$1 +.\} +.ie \\n[misc@adjust] 'ad +.el 'na +.. +.\"------------- +.\" switch environment, keep all important settings. +.de misc@ev-keep +.nr misc*ll \\n[.l] +.ev \\$1 +.ll \\n[misc*ll]u +.lt \\n[misc*ll]u +.. +.\"------------- +.\" .misc@push stackname value +.de misc@push +.ie d misc*st-\\$1 .ds misc*st-\\$1 \\$2 \\*[misc*st-\\$1] +.el .ds misc*st-\\$1 \\$2 +.. +.\"------------- +.\" .misc@pop stackname +.\" value returned in the string misc*pop +.de misc@pop +.misc@pop-set misc*st-\\$1 \\*[misc*st-\\$1] +.. +.\"------------- +.de misc@pop-set +.ds misc*st-name \\$1 +.shift +.if \\n[.$]<1 .@error "stack \\*[misc*st-name] empty" +.ds misc*pop \\$1 +.shift +.ds \\*[misc*st-name] \\$* +.. +.\"------------- +.\" .misc@pop-nr stackname varname +.de misc@pop-nr +.misc@pop \\$1 +.nr \\$2 \\*[misc*pop] +.. +.\"------------- +.\" .misc@pop-ds stackname varname +.de misc@pop-ds +.misc@pop \\$1 +.ds \\$2 \\*[misc*pop] +.. +.\"----------- +.\" reset tabs +.de TAB +.ta T 5n +.. +.\"------------- +.\" .PGFORM linelength [ pagelength [ pageoffset ] ] +.de PGFORM +.\" Break here to avoid problems with new linesetting of the previous line. +.\" Hope this doesn't break anything else :-) +.br +.if !''\\$1' .nr @ll \\$1 +.if !''\\$2' .nr @pl \\$2 +.if !''\\$3' .nr @po \\$3 +.ll \\n[@ll]u +.lt \\n[@ll]u +.po \\n[@po]u +.pl \\n[@pl]u +.nr @cur-ll \\n[@ll] +.in 0 +.pg@move-trap +.. +.\"------------- +.\" .MOVE y [[x] linelength] +.\" move to line y, indent to x +.de MOVE +.if !\\n[.$] .@error "MOVE y [x]: no arguments" +.if \\n[nl]<0 \c +.\" move to Y-pos +.sp |(v;\\$1) +.\" calc linelength +.ie \\n[.$]>2 .nr pg*i (n;\\$3) +.el \{\ +. ie \\n[.$]>1 .nr pg*i (n;\\n[@ll]u-\\$2) +. el .nr pg*i \\n[@ll]u +.\} +.\" move to X-pos, if any +.if !''\\$2' .po \\$2 +.\" set linelength +.ll \\n[pg*i]u +.. +.\"------------- +.de SM +.if !\\n[.$] .@error "SM: no arguments" +.if \\n[.$]=1 \s-1\\$1\s0 +.if \\n[.$]=2 \s-1\\$1\s0\\$2 +.if \\n[.$]=3 \\$1\s-1\\$2\s0\\$3 +.. +.\"------------- +.nr misc*S-ps \n[@ps] +.nr misc*S-vs \n[@vs] +.nr misc*S-ps1 \n[@ps] +.nr misc*S-vs1 \n[@vs] +.ds misc*a +.ds misc*b +.de S +.ie !\\n[.$] \{\ +. ds misc*a P +. ds misc*b P +.\} +.el \{\ +. ie \\n[.$]=1 .ds misc*b D +. el \{\ +. ie \w@\\$2@=0 .ds misc*b C +. el .ds misc*b \\$2 +. \} +. ie \w@\\$1@=0 .ds misc*a C +. el .ds misc*a \\$1 +.\} +.\" +.\" set point size +.if !'\\*[misc*a]'C' \{\ +. ie '\\*[misc*a]'P' .nr @ps \\n[misc*S-ps] +. el \{\ +. ie '\\*[misc*a]'D' .nr @ps 10 +. el .nr @ps \\*[misc*a] +. \} +.\} +.\" +.\" set vertical spacing +.if !'\\*[misc*b]'C' \{\ +. ie '\\*[misc*b]'P' .nr @vs \\n[misc*S-vs] +. el \{\ +. ie '\\*[misc*b]'D' .nr @vs \\n[@ps]+2 +. el .nr @vs \\*[misc*b] +. \} +.\} +'ps \\n[@ps] +'vs \\n[@vs] +.if \\n[D]>1 .tm point-size \\n[@ps] (\\n[.s]), vertical spacing \\n[@vs] (\\n[.v]) +.nr misc*S-ps \\n[misc*S-ps1] +.nr misc*S-vs \\n[misc*S-vs1] +.nr misc*S-ps1 \\n[@ps] +.nr misc*S-vs1 \\n[@vs] +.. +.\"------------ +.de HC +.ev 0 +.hc \\$1 +.ev +.ev 1 +.hc \\$1 +.ev +.ev 2 +.hc \\$1 +.ev +.. +.\"------------ +.de RD +.di misc*rd +'fl +.rd \\$1 +.br +.di +.ie !''\\$3' \{\ +. di misc*rd2 +. ds \\$3 "\\*[misc*rd] +. br +. di +.\} +.if !''\\$2' .rn misc*rd \\$2 +.rm misc*rd misc*rd2 +.. +.\"------------ +.\" VERBON [flag [pointsize [font]]] +.\" flag +.\" bit function +.\" 0 escape on +.\" 1 add an empty line before verbose text +.\" 2 add an empty line after verbose text +.\" 4 numbered lines (controlled by the string Verbnm) +.\" 8 indent text by the numbervariable Verbin. +.de VERBON +.nr misc*verb 0\\$1 +.if (0\\n[misc*verb]%4)/2 .SP \\n[Lsp]u +.br +.misc@ev-keep misc*verb-ev +.nf +.if (0\\n[misc*verb]%16)/8 .nm \\*[Verbnm] +.ie !'\\$3'' .ft \\$3 +.el .ft CR +.ss 12 +.ta T 8u*\w@n@u +.if 0\\$2 \{\ +. ps \\$2 +. vs \\$2 +.\} +.if (0\\n[misc*verb]%32)/16 .in +\\n[Verbin]u +.if !(0\\n[misc*verb]%2) \{\ +. eo +. nr @verbose-flag 1 \" tell pageheader to set ec/eo +.\} +.. +.de VERBOFF +.ec +.if (0\\n[misc*verb]%8)/4 .SP \\n[Lsp]u +.if (0\\n[misc*verb]%16)/8 .nm +.if (0\\n[misc*verb]%32)/16 .in +.ev +.nr @verbose-flag 0 +.. +.\" ######## module acc ################# +.\"----------- +.\" accents. These are copied from mgs, written by James Clark. +.de acc@over-def +.ds \\$1 \Z'\v'(u;\w'x'*0+\En[rst]-\En[.cht])'\ +\h'(u;-\En[skw]+(-\En[.w]-\w'\\$2'/2)+\En[.csk])'\\$2' +.. +.de acc@under-def +.ds \\$1 \Z'\v'\En[.cdp]u'\h'(u;-\En[.w]-\w'\\$2'/2)'\\$2' +.. +.acc@over-def ` \` +.acc@over-def ' \' +.acc@over-def ^ ^ +.acc@over-def ~ ~ +.acc@over-def : \(ad +.acc@over-def ; \(ad +.acc@under-def , \(ac +.\" ######## module uni ################# +.\" unimplemented macros +.de OK +.tm "OK: not implemented" +.. +.de PM +.tm "PM: not implemented" +.. +.\" ######## module hd ################# +.\" support for usermacro +.nr hd*h1-page 1 \" last page-number for level 1 header. +.nr hd*htype 0 +.ds hd*sect-pg +.ds hd*mark +.ds hd*suf-space +.nr hd*need 0 +.aln ;0 hd*htype +.als }0 hd*mark +.als }2 hd*suf-space +.aln ;3 hd*need +.\"------------- +.\" .hd@split varable index name val1 val2 ... +.de hd@split +.if \\$2>(\\n[.$]-3) .@error "\\$3 must have at least \\$2 values (\\*[\\$3]). +.nr hd*sp-tmp \\$2+3 +.ds \\$1 \\$[\\n[hd*sp-tmp]] +.. +.de HU +.H 0 "\\$1" +.. +.\"------------- +.de H +.if !r hd*cur-bline .nr hd*cur-bline \\n[nl] +.br +.ds@print-float 2\" $$$ could be wrong... +.\" terminate all lists +.LC 0 +.init@reset +.nr hd*level 0\\$1 +.nr hd*arg1 0\\$1 +.if !\\n[hd*level] .nr hd*level \\n[Hu] +.\" +.\" clear lower counters +.nr hd*i 1 1 +.while \\n+[hd*i]<8 .if \\n[hd*level]<\\n[hd*i] .nr H\\n[hd*i] 0 1 +.\" +.\" Check if it's time for new page. Only if text has +.\" appeared before. +.if \\n[Ej]&(\\n[Ej]>=\\n[hd*level])&(\\n[nl]>\\n[hd*cur-bline]) .pg@next-page +.\" +.\" increment current counter +.nr H\\n[hd*level] +1 +.\" +.\" if level==1 -> prepare for new section. +.if \\n[hd*level]=1 .rr hd*h1-page +.\" +.\" +.\" hd*mark is the text written to the left of the header. +.ds hd*mark \\n[H1]. +.\" +.if \\n[hd*level]>1 .as hd*mark \\n[H2] +.\" +.nr hd*i 2 1 +.while \\n+[hd*i]<8 .if \\n[hd*level]>(\\n[hd*i]-1) .as hd*mark .\\n[H\\n[hd*i]] +.if \\n[Ht] .ds hd*mark \\n[H\\n[hd*level]]. +.\" +.\" toc-mark is sent to the table of contents +.ds hd*toc-mark \\*[hd*mark] +.as hd*mark \ \ \" add spaces between mark and heading +.if !\\n[hd*arg1] \{\ +. ds hd*mark\" no mark for unnumbered +. ds hd*toc-mark +.\} +.\" +.if \\n[D]>1 .tm At header \\*[hd*toc-mark] "\\$2" +.nr hd*htype 0 \" hd*htype = check break and space +. \" 0 = run-in, 1 = break only, 2 = space +.if \\n[hd*level]<=\\n[Hb] .nr hd*htype 1 +.if \\n[hd*level]<=\\n[Hs] .nr hd*htype 2 +. \" two spaces if hd*htype == 0 +.ie (\\n[hd*htype]=0)&(\w@\\$2@) .ds hd*suf-space " \" +.el .ds hd*suf-space +.nr hd*need 2v \" hd*need = header need space +.if \\n[hd*htype]<2 .nr hd*need +\\n[Lsp]u \" add some extra space +.\"---------- user macro HX ------------ +.\" User exit macro to override numbering. +.\" May change hd*mark (}0), hd*suf-space (}2) and hd*need (;3) +.\" Can also change Hps1/2. +.if d HX .HX \\n[hd*level] \\n[hd*arg1] "\\$2\\$3" +.\"-------------------------------------- +.\" pre-space +.ie \\n[hd*level]<=\\n[Hps] .SP \\n[Hps2]u +.el .SP \\n[Hps1]u +.\" +.par@reset-num \\n[hd*level]\" reset numbered paragraph +.\" start diversion to measure size of header +.di hd*div +\\*[hd*mark]\\$2\\$3\\*[hd*suf-space] +.br +.di +.rm hd*div +.ne \\n[hd*need]u+\\n[dn]u+.5p \" this is the needed space for a header +.if \\n[hd*htype] .na \" no adjust if run-in +.\" +.\" size and font calculations +.hd@split hd*font \\n[hd*level] HF \\*[HF]\" get font for this level +.ft \\*[hd*font]\" set new font +.hd@split hd*new-ps \\n[hd*level] HP \\*[HP]\" get point size +.ie (\\*[hd*new-ps]=0):(\w@\\*[hd*new-ps]@=0) \{\ +. if \\n[hd*htype] \{\ +. if '\\*[hd*font]'3' \{\ +. ps -1 +. vs -1 +. \} +. if '\\*[hd*font]'B' \{\ +. ps -1 +. vs -1 +. \} +. \} +.\} +.el \{\ +. ps \\*[hd*new-ps] +. vs \\*[hd*new-ps]+2 +.\} +.\" +.\"---------- user macro HY ------------- +.\" user macro to reset indents +.if d HY .HY \\n[hd*level] \\n[hd*arg1] "\\$2\\$3" +.\"-------------------------------------- +.nr hd*mark-size \w@\\*[hd*mark]@ +.if (\\n[hd*level]<=\\n[Hc])&\\n[hd*htype] .ce\" center if level<=Hc +.\" +.\" finally, output the header +\\*[hd*mark]\&\c +.\" and the rest of the header +.ie \\n[hd*htype] \{\ +\\$2\\$3 +. br +.\} +.el \\$2\\$3\\*[hd*suf-space]\&\c +.ft 1 +.\" restore pointsize and vertical size. +.ps \\n[@ps] +.vs \\n[@vs] +.\" +.\" table of contents +.if (\\n[hd*level]<=\\n[Cl])&\w@\\$2@ \{\ +. ie \\n[Sectp] \{\ +. toc@save \\n[hd*level] "\\*[hd*toc-mark]" "\\$2" \\*[hd*sect-pg] +. \} +. el .toc@save \\n[hd*level] "\\*[hd*toc-mark]" "\\$2" \\n[%] +.\} +.\" set adjust to previous value +.SA +.\" do break or space +.if \\n[hd*htype] .br +.if \\n[hd*htype]>1 .SP \\n[Lsp]u +.if \\n[hd*htype] \{\ +. \" indent if Hi=1 and Pt=1 +. if (\\n[Hi]=1)&(\\n[Pt]=1) .ti +\\n[Pi]n +. \" indent size of mark if Hi=2 +. if \\n[hd*htype]&(\\n[Hi]>1) .ti +\\n[hd*mark-size]u +.\} +.nr par@ind-flag 0 \" no indent on .P if Pt=2 +.\" +.\" check if it is time to reset footnotes +.if (\\n[hd*level]=1)&\\n[ft*clear-at-header] .nr ft*nr 0 1 +.\" +.\" check if it is time to reset indexes +.if (\\n[hd*level]=1)&\\n[Sectf] \{\ +. nr lix*fg-nr 0 1 +. nr lix*tb-nr 0 1 +. nr lix*ec-nr 0 1 +. nr lix*ex-nr 0 1 +.\} +.\"---------- user macro HZ ---------- +.if d HZ .HZ \\n[hd*level] \\n[hd*arg1] "\\$2\\$3" +.nr hd*last-pos \\n[nl] +.nr hd*last-hpos \\n[.k] +.nr par@ind-flag 0 +.. +.\"-------- +.de HM +.nr hd*i 0 1 +.while \\n+[hd*i]<8 .af H\\n[hd*i] \\$[\\n[hd*i]] 1 +.. +.\"---------------------- +.\" set page-nr, called from header +.\" +.de hd@set-page +.if !r hd*h1-page .nr hd*h1-page \\n[%] +.\" +.ie \\n[Sectp] .nr P \\n[%]-\\n[hd*h1-page]+1 +.el .nr P \\n[%] +.\" +.\" Set section-page-string +.ds hd*sect-pg \\n[H1]-\\n[P] +.. +.\"########### module pg #################### +.\" set end of text trap +.wh 0 pg@header +.em pg@end-of-text +.\" +.ie \n[N]=4 .ds pg*header '''' +.el .ds pg*header ''- % -'' +.ds pg*even-footer +.ds pg*odd-footer +.ds pg*even-header +.ds pg*odd-header +.ds pg*footer +.\" +.nr pg*top-margin 0 +.nr pg*foot-margin 0 +.nr pg*block-size 0 +.nr pg*footer-size 5\" 1v+footer+even/odd footer+2v +.nr pg*header-size 7\" 3v+header+even/odd header+2v +.nr pg*extra-footer-size 0 +.nr pg*extra-header-size 0 +.nr ft*note-size 0 +.nr pg*cur-column 0 +.nr pg*cols-per-page 1 +.nr pg*cur-po \n[@po] +.nr pg*head-mark 0 +.\" +.nr pg*ps \n[@ps] +.nr pg*vs \n[@vs] +.\"------------------------- +.\" footer traps: set, enable and disable +.de pg@set-new-trap +.nr pg*foot-trap \\n[@pl]u-(\\n[pg*block-size]u+\\n[ft*note-size]u+\\n[pg*foot-margin]u+\\n[pg*footer-size]v+\\n[pg*extra-footer-size]u) +.if \\n[D]>2 .tm pg*foot-trap \\n[@pl]u-(\\n[pg*block-size]u+\\n[ft*note-size]u+\\n[pg*foot-margin]u+\\n[pg*footer-size]v) = \\n[pg*foot-trap] +.\" last-pos points to the position of the footer and bottom +.\" block below foot-notes. +.nr pg*last-pos \\n[@pl]u-(\\n[pg*block-size]u+\\n[pg*foot-margin]u+\\n[pg*footer-size]v) +.. +.de pg@enable-trap +.wh \\n[pg*foot-trap]u pg@footer +.if \\n[D]>2 .tm pg@enable-trap .t=\\n[.t] nl=\\n[nl] +.. +.de pg@disable-trap +.ch pg@footer +.. +.\" move to new trap (if changed). +.de pg@move-trap +.pg@disable-trap +.pg@set-new-trap +.pg@enable-trap +.. +.de pg@enable-top-trap +.\" set trap for pageheader. +.nr pg*top-enabled 1 +.. +.de pg@disable-top-trap +.\" remove trap for pageheader. +.nr pg*top-enabled 0 +.. +.\" no header on the next page +.de PGNH +.nr pg*top-enabled -1 +.. +.\" set first trap for pagefooter +.pg@enable-top-trap +.pg@set-new-trap +.pg@enable-trap +.\"------------------------- +.\" stop output and begin on next page. Fix footnotes and all that. +.de pg@next-page +.\".debug next-page +.ne 999i \" activate trap +.\" .pg@footer +.. +.\"------------------------- +.\" support for PX and TP +.als }t pg*header +.als }e pg*even-header +.als }o pg*odd-header +.\"------------------------------------------------------------ +.\" HEADER +.de pg@header +.if \\n[D]>1 .tm Page# \\n[%] (\\n[.F]:\\n[c.]) +.if \\n[Idxf] \{\ +.tl '''' +.\} +.\" assign current page-number to P +.hd@set-page +.\" +.\" suppress pageheader if pagenumber == 1 and N == [124] +.if \\n[pg*top-enabled] \{\ +. if \\n[pg*extra-header-size] 'sp \\n[pg*extra-header-size]u +. if \\n[pg*top-margin] 'sp \\n[pg*top-margin]u +. ev pg*tl-ev +. pg@set-env +. ie !d TP \{\ +' sp 3 +. lt \\n[@ll]u +. ie ((\\n[%]=1)&(\\n[N]=1):(\\n[N]=2)) .sp +. el .tl \\*[pg*header] +. ie o .tl \\*[pg*odd-header] +. el .tl \\*[pg*even-header] +' sp 2 +. \} +. el .TP +. ev +. \" why no-space?? +. if d PX \{\ +. ns +. PX +. rs +. \} +. \" check for pending footnotes +. ft@check-old +. \" +. \" back to normal text processing +. \" .pg@enable-trap +. \" mark for multicolumn +. nr pg*head-mark \\n[nl]u +. \" set multicolumn +. \" +. pg@set-po +. \" print floating displays +. ds@print-float 4 +. tbl@top-hook +. ns +.\} +.if \\n[pg*top-enabled]<0 .nr pg*top-enabled 1 +.nr hd*cur-bline \\n[nl] \" .H needs to know if output has occured +.. +.\"--------------------------------------------------------- +.\" FOOTER +.de pg@footer +.ec +.if \\n[D]>2 .tm Footer# \\n[%] (\\n[.F]:\\n[c.]) +.pg@disable-trap +.\".debug footer +.tbl@bottom-hook +.\" increment pageoffset for MC +.\" move to the exact start of footer. +'sp |\\n[pg*foot-trap]u+1v +.\" +.if \\n[D]>3 .tm FOOTER after .sp +.\" print footnotes +.if d ft*div .ft@print +.\" +.pg@inc-po +.if !\\n[pg*cur-column] .pg@print-footer +.\" next column +.pg@set-po +.pg@enable-trap +.if \\n[@verbose-flag] .eo \" to help VERBON/VERBOFF +.. +.\"------------------------- +.de pg@print-footer +.\" jump to the position just below the foot-notes. +'sp |\\n[pg*last-pos]u+1v +.\" check if there are any bottom block +.if d pg*block-div .pg@block +.\" +.\" print the footer and eject new page +.ev pg*tl-ev +.pg@set-env +.lt \\n[@ll]u +.ie o .tl \\*[pg*odd-footer] +.el .tl \\*[pg*even-footer] +.ie (\\n[%]=1)&(\\n[N]=1) .tl \\*[pg*header] +.el .tl \\*[pg*footer] +.ev +.ie (\\n[ds*fnr]>=\\n[ds*o-fnr]):\\n[ft*exist] \{\ +. ev ne +' bp +. ev +.\} +.el 'bp +.. +.\"------------------------- +.\" +.\" Initialize the title environment +.de pg@set-env +'na +'nh +'in 0 +'ti 0 +'ps \\n[pg*ps] +'vs \\n[pg*vs] +.. +.\"------------------------- +.de PH +.ds pg*header "\\$1 +.pg@set-new-size +.. +.de PF +.ds pg*footer "\\$1 +.pg@set-new-size +.. +.de OH +.ds pg*odd-header "\\$1 +.pg@set-new-size +.. +.de EH +.ds pg*even-header "\\$1 +.pg@set-new-size +.. +.de OF +.ds pg*odd-footer "\\$1 +.pg@set-new-size +.. +.de EF +.ds pg*even-footer "\\$1 +.pg@set-new-size +.. +.de pg@clear-hd +.ds pg*even-header +.ds pg*odd-header +.ds pg*header +.. +.de pg@clear-ft +.ds pg*even-footer +.ds pg*odd-footer +.ds pg*footer +.. +.de pg@set-new-size +.nr pg*ps \\n[@ps] +.nr pg*vs \\n[@vs] +.pg@move-trap +.. +.\"------------------------- +.\" end of page processing +.de pg@footnotes +.\".debug footnotes +.\" output footnotes. set trap for block +.\" +.. +.\"------------------------- +.\" print bottom block +.de pg@block +.ev pg*block-ev +'nf +'in 0 +.ll 100i +.pg*block-div +.br +.ev +.. +.\"------------------------- +.\" define bottom block +.de BS +.misc@ev-keep pg*block-ev +.init@reset +.br +.di pg*block-div +.. +.\"------------------------- +.de BE +.br +.di +.nr pg*block-size \\n[dn]u +.ev +.pg@move-trap +.. +.\"------------------------- +.\" print out all pending text +.de pg@end-of-text +.if \\n[D]>2 .tm ---------- End of text processing ---------------- +.ds@eot-print +.ref@eot-print +.. +.\"------------------------- +.\" set top and bottom margins +.de VM +.if \\n[.$]=0 \{\ +. nr pg*extra-footer-size 0 +. nr pg*extra-header-size 0 +.\} +.if \\n[.$]>0 .nr pg*extra-header-size (v;\\$1) +.if \\n[.$]>1 .nr pg*extra-footer-size (v;\\$2) +.if \\n[D]>2 \{\ +. tm extra top \\n[pg*extra-footer-size] +. tm extra bottom \\n[pg*extra-header-size] +.\} +.pg@move-trap +.. +.\"--------------------- +.\" multicolumn output. +.de pg@set-po +.if \\n[pg*cols-per-page]>1 \{\ +. ll \\n[pg*column-size]u +.\} +.. +.de pg@inc-po +.if \\n[pg*cols-per-page]>1 \{\ +. ie \\n+[pg*cur-column]>=\\n[pg*cols-per-page] \{\ +. nr pg*cur-column 0 1 +. nr pg*cur-po \\n[@po]u +. po \\n[@po]u +. ll \\n[@ll]u +. \} +. el \{\ +. nr pg*cur-po +(\\n[pg*column-size]u+\\n[pg*column-sep]u) +. po \\n[pg*cur-po]u +' sp |\\n[pg*head-mark]u +. tbl@top-hook +. \} +.\} +.. +.de 1C +.br +.if \\n[pg*cols-per-page]<=1 .@error "1C: multicolumn mode not active" +.nr pg*cols-per-page 1 +.nr pg*column-sep 0 +.nr pg*column-size \\n[@ll] +.nr pg*cur-column 0 1 +.nr pg*cur-po \\n[@po]u +.PGFORM +.\".pg@next-page +.SK +.. +.de 2C +.br +.nr pg*head-mark \\n[nl]u +.if \\n[pg*cols-per-page]>1 .@error "2C: multicolumn mode already active" +.nr pg*cols-per-page 2 +.nr pg*column-sep \\n[@ll]/15 +.nr pg*column-size (\\n[@ll]u*7)/15 +.nr pg*cur-column 0 1 +.nr pg*cur-po \\n[@po]u +.ll \\n[pg*column-size]u +.lt \\n[pg*column-size]u +.. +.\" MC column-size [ column-separation ] +.de MC +.br +.nr pg*head-mark \\n[nl]u +.if \\n[pg*cols-per-page]>1 .@error "MC: multicolumn mode already active" +.ie ''\\$1' .nr pg*column-size \\n[.l] +.el .nr pg*column-size (n;\\$1) +.ie ''\\$2' .nr pg*column-sep \\n[pg*column-size]/15 +.el .nr pg*column-sep (n;\\$2) +.\" +.nr pg*cols-per-page (u;\\n[.l]/(\\n[pg*column-size]+\\n[pg*column-sep]+1)) +.nr pg*cur-column 0 1 +.nr pg*cur-po \\n[@po]u +.ll \\n[pg*column-size]u +.lt \\n[pg*column-size]u +.. +.\" begin a new column +.de NCOL +.br +.pg@footer +.. +.\" skip pages +.de SK +.br +.bp +.nr pg*i 0 1 +.\" force new page by writing something invisible. +.while \\n+[pg*i]<=(0\\$1) \{\ +\& +. bp +.\} +.. +.\"------------------------------- +.\" MULB width1 space1 width2 space2 width3 space3 ... +.de MULB +.br +.nr pg*i 0 1 +.nr pg*mul-x 0 1 +.nr pg*mul-ind 0 +.nr pg*mul-last 0 +.while \\n[.$] \{\ +. nr pg*mul!\\n+[pg*i] (n;0\\$1) +. nr pg*muls!\\n[pg*i] (n;0\\$2) +. shift 2 +.\} +.nr pg*mul-max-col \\n[pg*i] +.ds pg*mul-fam \\n[.fam] +.nr pg*mul-font \\n[.f] +.ev pg*mul-ev +.fam \\*[pg*mul-fam] +.ft \\n[pg*mul-font] +.fi +.hy 14 +.di pg*mul-div +.MULN +.. +.\"----------- +.de MULN +.if \\n[pg*mul-x]>=\\n[pg*mul-max-col] .@error "MULN: Undefined columnwidth" +.br +.if \\n[.d]>\\n[pg*mul-last] .nr pg*mul-last \\n[.d] +.rt +0 +.in \\n[pg*mul-ind]u +.ll (u;\\n[.i]+\\n[pg*mul!\\n+[pg*mul-x]])u +.nr pg*mul-ind +(u;\\n[pg*mul!\\n[pg*mul-x]]+\\n[pg*muls!\\n[pg*mul-x]]) +.. +.\"----------- +.\" MULE +.de MULE +.br +.if \\n[.d]>\\n[pg*mul-last] .nr pg*mul-last \\n[.d] +.di +.ev +.ne \\n[pg*mul-last]u +.nf +.mk +.pg*mul-div +.rt +.sp \\n[pg*mul-last]u +.fi +.. +.\"----------- +.de OP +.br +.ie o .if !\\n[pg*head-mark]=\\n[nl] \{\ +. bp +1 +. bp +1 +.\} +.el .bp +.. +.\"########### module footnotes ################### +.nr ft*note-size 0 +.nr ft*busy 0 +.nr ft*nr 0 1 +.nr ft*wide 0 +.nr ft*hyphen 0\" hyphenation value +.nr ft*adjust 1\" >0 if adjust true +.nr ft*indent 1\" >0 if text indent true (not imp. $$$) +.nr ft*just 0\" 0=left justification, 1=right (not imp. $$$) +.nr ft*exist 0\" not zero if there are any footnotes to be printed +.nr ft*clear-at-header 0\" >0 if footnotes should be reset at first level head. +.\" +.ds F \v'-.4m'\s-3\\n+[ft*nr]\s0\v'.4m' +.\" +.\"----------------- +.\" init footnote environment +.de ft@init +.\" indentcontrol not implemented $$$ +.\" label justification not implemented $$$ +'in 0 +'fi +.ie \\n[ft*adjust] 'ad +.el 'na +.ie \\n[ft*hyphen] 'hy 14 +.el 'hy 0 +.ll \\n[@cur-ll]u +.lt \\n[@cur-ll]u +.ps (\\n[@ps]-2) +.vs (\\n[@vs]-1) +.. +.\"----------------- +.\" set footnote format +.\" no support for two column processing (yet). $$$ +.de FD +.if \\n[.$]=0 .@error "FD: bad arg \\$1" +.ie \\n[.$]=2 .nr ft*clear-at-header 1 +.el .nr ft*clear-at-header 0 +.\" +.if !'\\$1'' \{\ +. ie \\$1>11 .nr ft*format 0 +. el .nr ft*format \\$1 +. \" +. nr ft*hyphen (\\n[ft*format]%2)*14 +. nr ft*format \\n[ft*format]/2 +. \" +. nr ft*adjust 1-(\\n[ft*format]%2) +. nr ft*format \\n[ft*format]/2 +. \" +. nr ft*indent 1-(\\n[ft*format]%2) +. nr ft*format \\n[ft*format]/2 +. \" +. nr ft*just \\n[ft*format]%2 +.\} +.. +.\"--------------- +.\" Footnote and display width control $$$ +.de WC +.nr ft*i 0 1 +.while \\n+[ft*i]<=\\n[.$] \{\ +. ds ft*x \\$[\\n[ft*i]] +. if '\\*[ft*x]'N' \{\ +. nr ft*wide 0 +. nr ft*first-fn 0 +. nr ds*wide 0 +. nr ds*float-break 1 +. \} +. if '\\*[ft*x]'-WF' .nr ft*wide 0 +. if '\\*[ft*x]'WF' .nr ft*wide 1 +. if '\\*[ft*x]'-FF' .nr ft*first-fn 0 +. if '\\*[ft*x]'FF' .nr ft*first-fn 1 +. if '\\*[ft*x]'-WD' .nr ds*wide 0 +. if '\\*[ft*x]'WD' .nr ds*wide 1 +. if '\\*[ft*x]'-FB' .nr ds*float-break 0 +. if '\\*[ft*x]'FB' .nr ds*float-break 1 +.\} +.. +.\"----------------- +.\" begin footnote +.de FS +.if \\n[ft*busy] .@error "FS: missing FE" +.nr ft*busy 1 +.ev ft*ev +.ft@init +.if !\\n[ft*wide] .pg@set-po +.if !d ft*div .ft@init-footnote +.di ft*tmp-div +.nr ft*space (u;\\n[Fs]*\\n[Lsp]) +.sp \\n[ft*space]u +.\" print mark +.ie \\n[.$] .ds ft*mark \\$1 +.el .ds ft*mark \\n[ft*nr]. +\\*[ft*mark] +.in +.75c +.sp -1 +.nr ft*exist 1 +.. +.\"----------------- +.\" init footnote diversion +.de ft@init-footnote +.di ft*div +\l'20n' +.br +.di +.nr ft*note-size \\n[dn] +.. +.\"----------------- +.\" end footnote +.de FE +.nr ft*busy 0 +.br +.di +'in 0 +'nf +.if \\n[@pl]u<\\n[dn]u .@error "FE: too big footnote" +.ie (\\n[pg*foot-trap]u-\\n[.d]u)<\\n[dn]u \{\ +. da ft*next-div +. ft*tmp-div +. br +. di +.\} +.el \{\ +. da ft*div +. ft*tmp-div +. di +. nr ft*note-size +\\n[dn] +.\} +.rm ft*tmp-div +.ev +.pg@move-trap +.. +.\"----------------- +.\" print footnotes, see pg@footer +.de ft@print +.ev ft*print-ev +'nf +'in 0 +.ll 100i +.ft*div +.br +.ev +.rm ft*div +.nr ft*note-size 0 +.pg@move-trap +.. +.\"----------------- +.\" check if any pending footnotes, see pg@header +.de ft@check-old +.if d ft*next-div \{\ +. ev ft*ev +. ft@init +. ft@init-footnote +. nf +. in 0 +. da ft*div +. ft*next-div +. di +. nr ft*note-size +\\n[dn] +. rm ft*next-div +. ev +. nr ft*exist 0 +. pg@move-trap +.\} +.. +.\"########### module display ################### +.nr ds*wide 0\" >0 if wide displays wanted +.nr ds*fnr 0 1\" floating display counter +.nr ds*o-fnr 1\" floating display counter, already printed +.nr ds*snr 0 1\" static display counter +.nr ds*lvl 0 1\" display level +.nr ds*float-busy 0\" >0 if printing float +.nr ds*ffloat 0\" >0 if DF, 0 if DS +.\" static display start +.\" nested DS/DE is allowed. No limit on depth. +.de DS +.br +.ds@start 0 DS \\$@ +.. +.\" floating display start +.\" nested DF/DE is not allowed. +.de DF +.if \\n[ds*lvl] .@error "DF:nested floating is not allowed. Use DS." +.ds@start 1 DF \\$@ +.. +.\"--------------- +.nr ds*format 0\" dummy value for .En/.EQ +.nr ds*format! 0\" no indent +.nr ds*format!0 0\" no indent +.nr ds*format!L 0\" no indent +.nr ds*format!I 1\" indent +.nr ds*format!1 1\" indent +.nr ds*format!C 2\" center each line +.nr ds*format!2 2\" center each line +.nr ds*format!CB 3\" center as block +.nr ds*format!3 3\" center as block +.nr ds*format!R 4\" right justify each line +.nr ds*format!4 4\" right justify each line +.nr ds*format!RB 5\" right justify as block +.nr ds*format!5 5\" right justify as block +.\"--------------- +.nr ds*fill! 0\" no fill +.nr ds*fill!N 0\" no fill +.nr ds*fill!0 0\" no fill +.nr ds*fill!F 1\" fill on +.nr ds*fill!1 1\" fill on +.\"--------------- +.de ds@start +.nr ds*ffloat \\$1 +.ds ds*type \\$2 +.shift 2 +.nr ds*lvl +1 +.\" get format of the display +.ie \\n[.$] \{\ +. ie r ds*format!\\$1 .nr ds*format \\n[ds*format!\\$1] +. el .@error "\\*[ds*type]:wrong format:\\$1" +.\} +.el .nr ds*format 0 +.\" fill or not to fill, that is the... +.nr ds*fill 0 +.ie \\n[.$]>1 \{\ +. ie r ds*fill!\\$2 .nr ds*fill \\n[ds*fill!\\$2] +. el .@error "\\*[ds*type]:wrong fill:\\$2" +.\} +.nr ds*rindent 0 +.if \\n[.$]>2 .nr ds*rindent \\$3 +.\" +.\"--------------- +.nr ds*old-ll \\n[.l] +.misc@push ds-ll \\n[.l] +.misc@push ds-form \\n[ds*format] +.misc@push ds-ffloat \\n[ds*ffloat] +.nr ds*i \\n[.i] +.nr ds*ftmp \\n[.f] +.misc@ev-keep ds*ev!\\n+[ds*snr] +.ft \\n[ds*ftmp] +.\" +.init@reset +'in \\n[ds*i]u +.di ds*div!\\n[ds*snr] +.\" +.ll \\n[ds*old-ll]u +.lt \\n[ds*old-ll]u +.if \\n[ds*rindent] \{\ +. ll -\\n[ds*rindent]n +. lt -\\n[ds*rindent]n +.\} +.if \\n[ds*wide] \{\ +. ll \\n[@ll]u +. lt \\n[@ll]u +.\} +.\" +.ie \\n[ds*fill] 'fi +.el 'nf +.\" +.if \\n[ds*format]=1 \{\ +. ll -\\n[Si]n +. lt -\\n[Si]n +' in +\\n[Si]n +.\} +.if (\\n[ds*format]=3):(\\n[ds*format]=5) 'in 0 +.. +.\"--------------- +.de DE +.if \\n-[ds*lvl]<0 .@error "DE: no corresponding DS or DF" +.br +.if \\n[ds*ffloat] .SP \\n[Lsp]u +.di +.nr ds*width \\n[dl] +.nr ds*height \\n[dn] +.misc@pop-nr ds-ll ds*old-ll +.misc@pop-nr ds-form ds*format +.misc@pop-nr ds-ffloat ds*ffloat +.if (\\n[ds*format]>=2)&(\\n[ds*width]>\\n[ds*old-ll]) \{\ +. @error "DE: display too wide for current line-length" +.\} +.\" prepare copy to floating display +.if \\n[ds*ffloat] .di ds*fdiv!\\n+[ds*fnr] +.\" +'in 0 +'nf +.if \\n[ds*format]=2 'ce 9999 +.if \\n[ds*format]=3 'in (u;(\\n[ds*old-ll]-\\n[ds*width])/2) +.if \\n[ds*format]=4 'rj 9999 +.if \\n[ds*format]=5 'in (u;\\n[ds*old-ll]-\\n[ds*width]) +.\" +.ie !\\n[ds*ffloat] \{\ +. \" +. \" Print static display +. \" Eject page if display will fit one page and +. \" there are less than half of the page left. +. nr ds*i \\n[pg*foot-trap]-\\n[pg*header-size]v-\\n[pg*extra-header-size]v +. if (\\n[ds*height]>\\n[ds*i])&(\\n[.t]<(\\n[ds*i]/2)) \{\ +. ne \\n[.t]u+1v +. \} +. if (\\n[ds*height]<\\n[ds*i])&(\\n[.t]<(\\n[ds*height])) \{\ +. ne \\n[.t]u+1v +. \} +. if \\n[Ds] .SP \\n[Lsp]u +.\} +.el .SP \\n[Lsp]u +.ds*div!\\n[ds*snr] +.ie !\\n[ds*ffloat] .if \\n[Ds] .SP \\n[Lsp]u +.el \{\ +. SP \\n[Lsp]u +. di +.\} +.if \\n[ds*format]=2 'ce 0 +.if \\n[ds*format]=4 'rj 0 +.rm ds*div!\\n[ds*snr] +.nr ds*snr -1 +.nr par@ind-flag 0 +.\" move div to the floating display list +.ev +.if \\n[ds*ffloat] \{\ +. nr ds*fsize!\\n[ds*fnr] \\n[dn] +. \" print float if queue is empty and the display fits into +. \" the current page +. if (\\n[ds*fnr]>\\n[ds*o-fnr])&(\\n[ds*height]<\\n[.t]) \{\ +. ds@print-float 1 +. \} +.\} +.. +.\"------------- +.\" called by end-of-text +.de ds@eot-print +.if \\n[ds*o-fnr]<=\\n[ds*fnr] \{\ +. if \\n[D]>2 .tm Print remaining displays. +.\" still some floats left, make non-empty environment +. misc@ev-keep ne +. init@reset +\c +. ds@print-float 3 +. ev +.\} +.. +.\"--------------- +.\" print according to Df and De. +.\" .ds@print-float type +.\" type called from +.\" 1 .DE +.\" 2 end of section +.\" 3 end of document +.\" 4 beginning of new page +.\" +.de ds@print-float +.if \\n[Df]>5 .@error "Df=\\n[Df], max value is 5" +.if !\\n[ds*float-busy] \{\ +. nr ds*float-busy 1 +.\" at .DE +. if (\\$1=1)&((\\n[Df]%2)=1) \{\ +. if \\n[.t]>\\n[ds*fsize!\\n[ds*fnr]] \{\ +. \" Df = 1,3 or 5 +. ds@print-one-float +. \} +. \} +.\" print all if Df<2 and end of section +. if (\\$1=2)&(\\n[Df]<2) .ds@print-all-floats +.\" print all if end of document. Where should they go instead? +. if \\$1=3 .ds@print-all-floats +.\" new page +. if (\\$1=4)&(\\n[Df]>1) \{\ +. if \\n[Df]=2 .ds@print-one-float +. if \\n[Df]=3 .ds@print-one-float +. if \\n[Df]>3 \{\ +. ie \\n[De] .ds@print-all-floats +. el .ds@print-this-page +. \} +. \} +. nr ds*float-busy 0 +.\} +.. +.\"--------------- +.\" print a floating diversion +.de ds@output-div +.ev ds*fev +.in 0 +.nf +.ds*fdiv!\\n[ds*o-fnr] +.ev +.rm ds*fdiv!\\n[ds*o-fnr] +.rm ds*fsize!\\n[ds*o-fnr] +.rm ds*fformat!\\n[ds*o-fnr] +.nr ds*o-fnr +1 +.. +.\"--------------- +.\" print one floating display if there is one. +.de ds@print-one-float +.if \\n[ds*o-fnr]<=\\n[ds*fnr] \{\ +. if \\n[.t]<\\n[ds*fsize!\\n[ds*o-fnr]] .pg@next-page +. ds@output-div +. if \\n[De] .pg@next-page +.\} +.. +.\"--------------- +.\" print all queued floats. +.\" if De>0 do a page eject between the floats. +.de ds@print-all-floats +.while \\n[ds*o-fnr]<=\\n[ds*fnr] \{\ +. if \\n[.t]<\\n[ds*fsize!\\n[ds*o-fnr]] .pg@next-page +. ds@output-div +. if \\n[De] .pg@next-page +.\} +.. +.\"--------------- +.\" print as many floats as will fit on the current page +.de ds@print-this-page +.while \\n[ds*o-fnr]<=\\n[ds*fnr] \{\ +. if \\n[.t]<\\n[ds*fsize!\\n[ds*o-fnr]] .break +. ds@output-div +.\} +.. +.\"########### module list ################### +.\" .LI text-indent mark-indent pad type [mark [LI-space [LB-space] ] ] +.\" +.nr li*tind 0 +.nr li*mind 0 +.nr li*pad 0 +.nr li*type 0 +.ds li*mark 0 +.nr li*li-spc 0 +.nr li*lvl 0 1 +.nr li*cur-vpos 0 +.\"-------------------------- +.\" the major list-begin macro. +.\" If type == -1 a 'break' will occur. +.de LB +.if \\n[.$]<4 .@error "LB: not enough arguments, min 4" +.misc@push cind \\n[.i] +.misc@push tind \\n[li*tind] +.misc@push mind \\n[li*mind] +.misc@push pad \\n[li*pad] +.misc@push type \\n[li*type] +.misc@push li-spc \\n[li*li-spc] +.ds li*mark-list!\\n[li*lvl] \\*[li*mark] +.nr li*lvl +1 +.\" +.nr li*tind (n;0\\$1)\" text-indent +.nr li*mind (n;0\\$2)\" mark-indent +.nr li*pad (n;0\\$3)\" pad +.nr li*type 0\\$4\" type +.ds li*mark \\$5\" mark +.ie !'\\$6'' .nr li*li-spc \\$6\" LI-space +.el .nr li*li-spc 1 +.ie !'\\$7'' .nr li*lb-spc \\$6\" LB-space +.el .nr li*lb-spc 0 +.\" init listcounter +.nr li*cnt!\\n[li*lvl] 0 1 +.\" assign format +.af li*cnt!\\n[li*lvl] 1 +.if \\n[li*type] .if !'\\*[li*mark]'' .af li*cnt!\\n[li*lvl] \\*[li*mark] +.\" +.if \\n[li*lb-spc] .SP (u;\\n[li*lb-spc]*\\n[Lsp]) +.in +\\n[li*tind]u +.. +.\"--------------- +.de LI +.if \\n[li*lvl]<1 .@error "LI:no lists active" +.if \\n[li*li-spc]&(\\n[Ls]>=\\n[li*lvl]) .SP (u;\\n[li*li-spc]*\\n[Lsp]) +.ne 2v +.\" +.ds li*c-mark \\*[li*mark] +.nr li*cnt!\\n[li*lvl] +1 +.if \\n[li*type]=1 .ds li*c-mark \\n[li*cnt!\\n[li*lvl]]. +.if \\n[li*type]=2 .ds li*c-mark \\n[li*cnt!\\n[li*lvl]]) +.if \\n[li*type]=3 .ds li*c-mark (\\n[li*cnt!\\n[li*lvl]]) +.if \\n[li*type]=4 .ds li*c-mark [\\n[li*cnt!\\n[li*lvl]]] +.if \\n[li*type]=5 .ds li*c-mark <\\n[li*cnt!\\n[li*lvl]]> +.if \\n[li*type]=6 .ds li*c-mark {\\n[li*cnt!\\n[li*lvl]]} +.if \\n[.$]=1 .ds li*c-mark \\$1 +.if \\n[.$]=2 .ds li*c-mark \\$1\ \\*[li*c-mark] +.if '\\*[li*c-mark]'\ ' .ds li*c-mark +.\" +.\" determine where the text begins +.nr li*text-begin \\n[li*tind]>?\w@\\*[li*c-mark]\ @ +.\" +.\" determine where the mark begin +.ie !\\n[li*pad] .nr li*in \\n[li*mind] +.el .nr li*in \\n[li*text-begin]-\\n[li*pad]-\w@\\*[li*c-mark]@ +.if !\\n[li*in] .nr li*in 0 +.\" +.ti -\\n[li*tind]u +.\" no indentation if hanging indent +.if (\w@\\*[li*c-mark]@=0)&((\\n[.$]=0):(\w@\\$1@=0)) .nr li*text-begin 0 +\Z'\&\h'\\n[li*in]u'\\*[li*c-mark]'\h'\\n[li*text-begin]u'\&\c +.if \\n[li*type]=-1 .br +.. +.\" +.\"------------- +.de li@pop +.nr li*lvl -1 +.misc@pop-nr cind li*tmp +.in \\n[li*tmp]u +.misc@pop-nr tind li*tind +.misc@pop-nr mind li*mind +.misc@pop-nr pad li*pad +.misc@pop-nr type li*type +.misc@pop-nr li-spc li*li-spc +.ds li*mark \\*[li*mark-list!\\n[li*lvl]] +.. +.de LE +.if \\n[li*lvl]<1 .@error "LE:mismatched" +.li@pop +.if '\\$1'1' .SP \\n[Lsp]u +.. +.\"------------- +.\" list status clear. +.de LC +.if !\\n[.$]=1 .@error "LC: no argument" +.if \\$1>\\n[li*lvl] .@error "LC: incorrect argument: \\$1 (too big)" +.while \\n[li*lvl]>\\$1 .li@pop +.nr par@ind-flag 0 +.. +.\"------------- +.de AL +.if \\n[.$]>3 .@error "AL: too many arguments" +.if \\n[D]>2 .tm AL $* +.ie \\n[.$]<=1 .LB \\n[Li] 0 2 1 "\\$1" +.el \{\ +. ie \\n[.$]=2 .LB 0\\$2 0 2 1 "\\$1" +. el \{\ +. ie !'\\$2'' .LB \\$2 0 2 1 "\\$1" 0 1 +. el .LB \\n[Li] 0 2 1 "\\$1" 0 1 +. \} +.\} +.. +.de ML +.if \\n[.$]>3 .@error "ML: too many arguments" +.if \\n[D]>2 .tm ML $* +.nr li*ml-width \w@\\$1@u+1n +.if \\n[.$]<2 .LB \\n[li*ml-width]u 0 1 0 "\\$1" +.if \\n[.$]=2 .LB 0\\$2 0 1 0 "\\$1" +.if \\n[.$]=3 \{\ +. ie '\\$2'' .LB \\n[li*ml-width]u 0 1 0 "\\$1" 0 1 +. el .LB \\n[Li] 0 1 0 "\\$1" 0 1 +.\} +.. +.de VL +.if \\n[D]>2 .tm VL $* +.if \\n[.$]>3 .@error "VL: too many arguments" +.if \\n[.$]<1 .@error "VL: missing text-indent" +.ie \\n[.$]<3 .LB 0\\$1 0\\$2 0 0 +.el .LB 0\\$1 0\\$2 0 0 \& 0 1 +.. +.\" Bullet (for .BL) +.de BL +.if \\n[D]>2 .tm BL $* +.ds BU \s-2\(bu\s0 +.if \\n[.$]>2 .@error "BL: too many arguments" +.if \\n[.$]<1 .LB \\n[Pi] 0 1 0 \\*[BU] +.if \\n[.$]=1 .LB 0\\$1 0 1 0 \\*[BU] +.if \\n[.$]=2 \{\ +. ie '\\$1'' .LB \\n[Pi] 0 1 0 \\*[BU] 0 1 +. el .LB 0\\$1 0 1 0 \\*[BU] 0 1 +.\} +.. +.de DL +.if \\n[D]>2 .tm DL $* +.if \\n[.$]>2 .@error "DL: too many arguments" +.if \\n[.$]<1 .LB \\n[Pi] 0 1 0 \(em +.if \\n[.$]=1 .LB 0\\$1 0 1 0 \(em +.if \\n[.$]=2 \{\ +. ie '\\$1'' .LB \\n[Pi] 0 1 0 \(em 0 1 +. el .LB 0\\$1 0 1 0 \(em 0 1 +.\} +.. +.de RL +.if \\n[D]>2 .tm RL $* +.if \\n[.$]>2 .@error "RL: too many arguments" +.if \\n[.$]<1 .LB 6 0 2 4 +.if \\n[.$]=1 .LB 0\\$1 0 2 4 +.if \\n[.$]=2 \{\ +. ie '\\$1'' .LB 6 0 2 4 1 0 1 +. el .LB 0\\$1 0 2 4 1 0 1 +.\} +.. +.\" Broken Variable List. As .VL but text begin on the next line +.de BVL +.if \\n[D]>2 .tm BVL $* +.if \\n[.$]>3 .@error "BVL: too many arguments" +.if \\n[.$]<1 .@error "BVL: missing text-indent" +.ie \\n[.$]<3 .LB 0\\$1 0\\$2 0 -1 +.el .LB 0\\$1 0\\$2 0 -1 \& 0 1 +.. +.\" ####### module tbl ####################################### +.\" This module is copied from groff_ms and modified for mgm. +.\" Yes, it does not resemble the original anymore :-). +.\" Don't know if I missed something important. +.\" Groff_ms is written by James Clark. +.nr tbl*have-header 0 +.nr tbl*header-written 0 +.de TS +.br +.if ''\\n[.z]' .SP +.if '\\$1'H' .di tbl*header-div +.. +.de tbl@top-hook +.if \\n[tbl*have-header] \{\ +. ie \\n[.t]-\\n[tbl*header-ht]-1v .tbl@print-header +. el .sp \\n[.t]u +.\} +.. +.de tbl@bottom-hook +.if \\n[tbl*have-header] \{\ +. nr T. 1 +.\" draw bottom and side lines of boxed tables. +. T# +.\} +.nr tbl*header-written 0 +.. +.de tbl@print-header +.ev tbl*ev +'nf +.tbl*header-div +.ev +.mk #T +.nr tbl*header-written 1 +.. +.de TH +.ie '\\n[.z]'tbl*header-div' \{\ +. nr T. 0 +. T# +. br +. di +. nr tbl*header-ht \\n[dn] +. ne \\n[dn]u+1v +. nr tbl*have-header 1 +. ie '\\$1'N' .if !\\n[tbl*header-written] .tbl@print-header +. el .tbl@print-header +.\} +.el .@error ".TH without .TS H" +.. +.de TE +.ie '\\n(.z'tbl*header-div' .@error ".TS H but no .TH before .TE" +.el \{\ +. nr tbl*have-header 0 +.\} +.\" reset tabs +.TAB +.. +.de T& +.. +.\" ####### module pic ####################################### +.de PS +.nr pic*in 0 +.br +.SP .5 +.ie \\n[.$]<2 .@error "PS: bad arguments. Probably not processed with pic." +.el \{\ +. if !\\n[ds*lvl] .ne (u;\\$1)+1v +.\" should be contained between .DS/.DE +.if r ds*format \{\ +. if \\n[ds*lvl]&((\\n[ds*format]=2):(\\n[ds*format]=3)) \{\ +. nr pic*in \\n[.i] +.\" . in +(u;\\n[.l]-\\n[.i]-\\$2/2) +. \} +. \} +.\} +.. +.de PE +.init@reset +.SP .5 +.. +.\" ####### module eq ####################################### +.\" +.nr eq*number 0 1 +.de EQ +.ds eq*lable "\\$1 +.di eq*div +.misc@ev-keep eq*ev +.in 0 +.nf +.. +.de EN +.br +.di +.ta +.\" equation with lable. +.if \\n[dl] \{\ +. br +. chop eq*div +. ie (\\n[Eq]%2) \{\ +. \" lable to the left +. if \\n[ds*format]<2 \{\ +. ta (u;(\\n[.l]/7)+\\n[.i]) \\n[.l]u\" L +\\*[eq*lable]\t\\*[eq*div]\t\& +. \} +. if (\\n[ds*format]=2):(\\n[ds*format]=3) \{\ +. ta (u;(\\n[.l]-\\n[.i])/2+\\n[.i])C \\n[.l]u\" C +\\*[eq*lable]\t\\*[eq*div]\t\& +. \} +. if \\n[ds*format]>3 \{\ +. ta \\n[.l]uR\" R +\\*[eq*lable]\t\\*[eq*div] +. \} +. \} +. el \{\ +. \" lable to the right +. if \\n[ds*format]<2 \{\ +. ta \\n[.l]uR\" L +\\*[eq*div]\t\\*[eq*lable] +. \} +. if (\\n[ds*format]=2):(\\n[ds*format]=3) \{\ +. ta (u;(\\n[.l]-\\n[.i])/2+\\n[.i])C \\n[.l]uR\" C +\t\\*[eq*div]\t\\*[eq*lable] +. \} +. if \\n[ds*format]>3 \{\ +. ta (\\n[.l]u-\w@\\*[eq*lable]@u-1m)R \\n[.l]uR\" R +\t\\*[eq*div]\t\\*[eq*lable] +. \} +. \} +.\} +.TAB +.ev +.. +.\"########### module toc ################### +.\" table of contents +.nr toc*slevel 1 +.nr toc*spacing \n[Lsp]u +.nr toc*tlevel 2 +.nr toc*tab 0 +.\"----------- +.\" Table of contents with friends (module lix) +.de TC +.br +.\" print any pending displays and references +.ds@print-float 3 +.if \\n[ref*flag] .RP 0 1 +.\" +.if \w@\\$1@>0 .nr toc*slevel \\$1 +.if \w@\\$2@>0 .nr toc*spacing (u;\\$2*\\n[Lsp]) +.if \w@\\$3@>0 .nr toc*tlevel \\$3 +.if \w@\\$4@>0 .nr toc*tab \\$4 +.if \\n[pg*cols-per-page]>1 .1C +.pg@clear-hd +.pg@next-page +.pg@clear-ft +.\"------------- +.if d Ci .toc@read-Ci \\*[Ci] +.nf +.in 0 +.nr toc*pn 0 1 +.af toc*pn i +.PF "''\\\\\\\\n+[toc*pn]''" +.nr toc*i 4 1 +.while \\n+[toc*i]<10 \{\ +. if !'\\$\\n[toc*i]'' \{\ +. ce +\\$\\n[toc*i] +. br +. \} +.\} +.if \\n[.$]<=4 .if d TX .TX +.ie d TY .if \\n[.$]<=4 .TY +.el \{\ +. ce +\\*[Licon] +. br +. SP 3 +.\} +.if d toc*list .toc*list +.\" print LIST OF XXX +.if d lix*dsfg .lix@print-ds fg "\\*[Lf]" +.if d lix*dstb .lix@print-ds tb "\\*[Lt]" +.if d lix*dsec .lix@print-ds ec "\\*[Le]" +.if d lix*dsex .lix@print-ds ex "\\*[Lx]" +.. +.\"----------- +.\" .toc@read-Ci lev1 lev2 lev3 lev4 ... lev7 +.de toc@read-Ci +.nr toc*i 0 1 +.while \\n+[toc*i]<8 \{\ +. nr toc*hl!\\n[toc*i] \\$\\n[toc*i] +.\} +.. +.\"----------- +.de toc@save +.\" collect maxsize of mark if string Ci don't exist. +.if !d Ci \{\ +. if !r toc*hl!\\$1 .nr toc*hl!\\$1 0 +. if \\n[toc*hl!\\$1]<=\w@\\$2@ \{\ +. nr toc*hl!\\$1 \w@\\$2@u+1m +. \} +.\} +.am toc*list +.\" .toc@set level headernumber text pagenr +.toc@set \\$1 "\\$2" "\\$3" \\$4 +\\.. +.. +.\"----------- +.\" level mark text pagenumber +.de toc@set +.if \\$1<=\\n[toc*slevel] .SP \\n[toc*spacing]u +.ne 2v +.na +.fi +.nr toc*ind 0 +.nr toc*i 0 1 +.ie d Ci \{\ +. nr toc*ind +\\n[toc*hl!\\$1]u +.\} +.el \{\ +. while \\n+[toc*i]<\\$1 \{\ +. nr toc*ind +\\n[toc*hl!\\n[toc*i]]u +. \} +.\} +.nr toc*text \\n[toc*ind]u+\\n[toc*hl!\\$1]u +.in \\n[toc*text]u +.ti -\\n[toc*hl!\\$1]u +.\" +.\" length of headernum space +.nr toc*i \\n[toc*hl!\\$1]-\w@\\$2@ +.\" +.ll \\n[@ll]u-\w@\\$4@u-2m +.\" ragged right --------------------------------- +.ie \\$1>\\n[toc*tlevel] \{\ +\\$2 +. sp -1 +\\$3\ \ \ \\$4 +. br +.\} +.el \{\ +. \" unnumbered heading -------------------- +. ie '\\$2'' \{\ +. in \\n[toc*ind]u +\\$3\h'1m' +. \} +. \" normal heading ------------------------ +. el \{\ +\\$2 +. sp -1 +\\$3\h'1m' +. \} +. ll \\n[@ll]u +. sp -1 +. nr toc*sep (u;\\n[.l]-\\n[.n]-\\n[.i]-\w@\\$4@)-1m +\h'|\\n[.n]u'\l'\\n[toc*sep]u.'\h'1m'\\$4 +.\} +.ll \\n[@ll]u +.. +.\"########################### module lix ############################ +.\" LIST OF figures, tables, exhibits and equations +.nr lix*fg-nr 0 1 +.nr lix*tb-nr 0 1 +.nr lix*ec-nr 0 1 +.nr lix*ex-nr 0 1 +.aln Fg lix*fg-nr +.aln Tb lix*tb-nr +.aln Ec lix*ec-nr +.aln Ex lix*ex-nr +.\"------------ +.de FG +.lix@print-line fg Lf \\n+[lix*fg-nr] "\\$1" "\\$2" "\\$3" "\\$4" +.. +.de TB +.lix@print-line tb Lt \\n+[lix*tb-nr] "\\$1" "\\$2" "\\$3" "\\$4" +.. +.de EC +.lix@print-line ec Le \\n+[lix*ec-nr] "\\$1" "\\$2" "\\$3" "\\$4" +.. +.de EX +.lix@print-line ex Lx \\n+[lix*ex-nr] "\\$1" "\\$2" "\\$3" "\\$4" +.. +.\"------------ +.\" print line with 'figure' in the text +.\" type stringvar number text override flag refname +.de lix@print-line +.ds lix*text "\\$4 +.\" +.ie \\n[Sectf] .ds lix*numb \\n[H1]-\\$3 +.el .ds lix*numb \\$3 +.\" +.ie !\\n[Of] .ds lix*ds-form .\ \ \" +.el .ds lix*ds-form "\ \(em\ \" +.nr lix*in \\n[.i] +.ds lix*lable \\*[Li\\$1]\ \\*[lix*numb]\\*[lix*ds-form] +.if !'\\$5'' \{\ +. if !0\\$6 .ds lix*lable \\*[Li\\$1]\ \\$5\\*[lix*numb]\\*[lix*ds-form] +. if 0\\$6=1 .ds lix*lable \\*[Li\\$1]\ \\*[lix*numb]\\$5\\*[lix*ds-form] +. if 0\\$6=2 .ds lix*lable \\*[Li\\$1]\ \\$5\\*[lix*ds-form] +.\} +.ie \\n[Sectp] .ds lix*pgnr \\*[hd*sect-pg] +.el .ds lix*pgnr \\n[%] +.\" print line if not between DS/DE +.ie \\n[ds*lvl]<1 .lix@print-text "\\*[lix*lable]" "\\*[lix*text]" +.el .lix@embedded-text "\\*[lix*lable]" "\\*[lix*text]" +.\" +.\" save line for LIST OF XXX +.if !r lix*wth\\$1 .nr lix*wth\\$1 0 +.if \w@\\*[lix*lable]@>\\n[lix*wth\\$1] .nr lix*wth\\$1 \w@\\*[lix*lable]@ +.if \\n[\\$2] .lix@ds-save \\$1 \\*[lix*pgnr] "\\$4" "\\*[lix*lable]" +.if !'\\$7'' .SETR \\$7 \\*[lix*numb] +.. +.\"----------- +.de lix@print-text +.SP \\n[Lsp]u +.misc@ev-keep lix +.init@reset +.br +.ie (\w@\\$1\\$2@)>(\\n[.l]-\\n[.i]) \{\ +. in +\w@\\$1@u +. ti 0 +.\} +.el .ce 1 +\fB\\$1\fP\\$2 +.br +.ev +.. +.\" hide printout until diversion is evaluated +.de lix@embedded-text +\!.SP \\n[Lsp]u +\!.misc@ev-keep lix +\!.init@reset +\!.br +\!.ie (\w@\\$1\\$2@)>(\\n[.l]-\\n[.i]) \{\ +\!. in +\w@\\$1@u +\!. ti 0 +\!.\} +\!.el .ce 1 +\!\fB\\$1\fP\\$2 +\!.br +\!.ev +.. +.\"------------ +.\" print complete list of XXXX +.de lix@print-ds +.\" arg: fg,tb,ec,ex text +.if !\\n[Cp] .pg@next-page +.\" print LIST OF XXXX +.ce +\\$2 +.SP 3 +.in \\n[lix*wth\\$1]u +.fi +.lix*ds\\$1 +.. +.\"------------ +.\" save line of list in macro +.de lix@ds-save +.\" type pagenumber text +.am lix*ds\\$1 +.lix@dsln \\$1 \\$2 "\\$3" "\\$4" \\$5 +\\.. +.. +.\"------------ +.\" print appended macro +.\" lix@dsln type pagenumber text headernr +.de lix@dsln +.nr lix*i \\n[lix*wth\\$1]-\w@\\$4@ +.ne 2v +.nr lix*sep \\n[.l]-\\n[lix*i]-\w'\\$4\\$3\\$2'-1m-1n-\\n[.i] +\h'\\n[lix*i]u'\\$4\\$3\h'1n'\l'\\n[lix*sep]u.'\h'1m'\\$2 +.SP \\n[toc*spacing]u +.. +.\"########################### module fnt ############################ +.\" some font macros. +.de R +.ft R +.ul 0 +.. +.\"----------- +.de fnt@switch +.ul 0 +.ds fnt*tmp +.nr fnt*prev \\n[.f] +.nr fnt*i 2 1 +.while \\n+[fnt*i]<=\\n[.$] \{\ +. if \\n[fnt*i]>3 .as fnt*tmp \, +. ie (\\n[fnt*i]%2)=1 .as fnt*tmp \\$1\\$[\\n[fnt*i]] +. el .as fnt*tmp \\$2\\$[\\n[fnt*i]] +. if \\n[fnt*i]<\\n[.$] .as fnt*tmp \/ +.\} +\&\\*[fnt*tmp]\f[\\n[fnt*prev]] +.. +.\"----------- +.de B +.ie \\n[.$] .fnt@switch \fB \f[\\n[.f]] \\$@ +.el .ft B +.. +.de I +.ie \\n[.$] .fnt@switch \fI \f[\\n[.f]] \\$@ +.el .ft I +.. +.de IB +.if \\n[.$] .fnt@switch \fI \fB \\$@ +.. +.de BI +.if \\n[.$] .fnt@switch \fB \fI \\$@ +.. +.de IR +.if \\n[.$] .fnt@switch \fI \fR \\$@ +.. +.de RI +.if \\n[.$] .fnt@switch \fR \fI \\$@ +.. +.de RB +.if \\n[.$] .fnt@switch \fR \fB \\$@ +.. +.de BR +.if \\n[.$] .fnt@switch \fB \fR \\$@ +.. +.\"########################### module box ############################ +.\" draw a box around some text. Text will be kept on the same page. +.\" +.nr box*ll 0 +.\" .B1 and .B2 works like .DS +.de B1 +.if \\n[box*ll] .@error "B1: missing B2" +.nr box*ll \\n[.l] +.nr box*ind \\n[.i] +.nr box*hyp \\n[.hy] +.nr box*wid \\n[.l]-\\n[.i] +.\" +.\" jump to new environment. +.ev box*ev +.di box*div +.in 1n +.ll (u;\\n[box*wid]-1n) +.hy \\n[.hy] +.. +.de B2 +.if !\\n[box*ll] .@error "B2: missing B1" +.br +.di +.nr box*height \\n[dn] +.ne \\n[dn]u+1v +.ll \\n[box*ll]u +.in \\n[box*ind]u +.nr box*y-pos \\n[.d]u +.nf +.box*div +.fi +\v'-1v+.25m'\ +\D'l \\n[box*wid]u 0'\ +\D'l 0 -\\n[box*height]u'\ +\D'l -\\n[box*wid]u 0'\ +\D'l 0 \\n[box*height]u' +.br +.sp -1 +.ev +.sp .20v +.in \\n[box*ind]u +.ll \\n[box*ll]u +.rm box*div +.nr box*ll 0 +.. +.\"########################### module ref ############################ +.nr ref*nr 0 1 +.nr ref*nr-width 5n +.nr ref*flag 0 \" for end-of-text +.ds Rf \v'-.4m'\s-3[\\n+[ref*nr]]\s0\v'.4m' +.\" +.\" start reference +.de RS +.if !''\\$1' .ds \\$1 \\n[ref*nr] +.nr ref*flag 1 +.ev ref*ev +.da ref*div +.init@reset +.ll \\n[@ll]u +.in \\n[ref*nr-width]u +.ti -(\w@\\n[ref*nr].@u+1n) +\\n[ref*nr]. +.sp -1 +.. +.de RF +.br +.if \\n[Ls] .SP \\n[Lsp]u +.di +.ev +.. +.\"----------- +.de RP +.if !d ref*div .@error "RP: No references!" +.nr ref*flag 0 +.nr ref*i 0\\$2 +.if \\n[ref*i]<2 .SK +.SP 2 +.ref@print-refs +.if 0\\$1<1 .nr ref*nr 0 1 +.if ((\\n[ref*i]=0):(\\n[ref*i]=2)) .SK +.. +.\"----------- +.\" called by end-of-text! +.de ref@eot-print +.if \\n[ref*flag] \{\ +. if \\n[D]>2 .tm Print references, called by eot +. nr ref*flag 0 +. br +. misc@ev-keep ne +. init@reset +\c +' bp +. ev +. ref@print-refs +.\} +.. +.\"----------- +.\" prints the references +.de ref@print-refs +.toc@save 1 "" "\\*[Rp]" \\n[%] +.ev ref*ev +.ce +\fI\\*[Rp]\fP +.sp +.in 0 +.nf +.ref*div +.in +.rm ref*div +.ev +.. +.\"########################### module app ############################ +.\" +.nr app*nr 0 1 +.af app*nr A +.nr app*dnr 0 1 +.\"------------ +.\" .APP name text +.\" name == "" -> autonumber +.de APP +.\" .if \\n[.$]<2 .@error "APP: too few arguments" +.app@set-ind "\\$1" +.\" +.ie \\n[Aph] .app@header \\*[app*ind] "\\$2" +.el .bp +.app@index "\\*[app*ind]" "\\$2" +.. +.\"------------ +.\" .APPSK name pages text +.\" name == "" -> autonumber +.de APPSK +.if \\n[.$]<2 .@error "APPSK: too few arguments" +.app@set-ind "\\$1" +.\" +.ie \\n[Aph] .app@header \\*[app*ind] "\\$3" +.el .bp +.app@index "\\*[app*ind]" "\\$3" +.pn +\\$2 +.. +.\"------------ +.de app@set-ind +.ie \w@\\$1@ .ds app*ind \\$1 +.el \{\ +. if !\\n[app*dnr] \{\ +. nr H1 0 1 +. af H1 A +. \} +. ds app*ind \\n+[app*nr] +. nr H1 \\n+[app*dnr] +.\} +.\" clear lower counters +.nr app*i 1 1 +.while \\n+[app*i]<8 .nr H\\n[app*i] 0 1 +.. +.\"------------ +.de app@index +.toc@save 1 "" "\\*[App] \\$1: \\$2" \\n[%] +.. +.\"------------ +.\" app@heaer name text +.de app@header +.bp +.SP (u;\\n[Lsp]*4) +.ce 1 +\s+4\fB\\*[App]\ \\$1\fP\s0 +.SP (u;\\n[Lsp]*2) +.if \w@\\$2@<\\n[.l] .ce 1 +\fB\s+2\\$2\s0\fP +.SP (u;\\n[Lsp]*4) +.. +.\"########################### module cov ############################ +.\" title stored in diversion cov*title +.\" abstract stored in diversion cov*abstract +.\" arg to abstract stored in cov*abs-arg +.\" indent stored in cov*abs-ind +.\" number of authors stored in cov*au +.\" author(s) stored in cov*au!x!y +.\" author(s) title stored in cov*at!x!y +.\" x is the author-index [1-cov*au], y is the argument-index [1-9]. +.\" author(s) firm stored in cov*firm +.\" new date (if .ND exists) is stored in cov*new-date +.\" +.\" +.ds cov*abs-name ABSTRACT +.\" +.nr cov*au 0 +.de TL +.if \\n[.$]>0 .ds cov*title-charge-case \\$1 +.if \\n[.$]>1 .ds cov*title-file-case \\$2 +.pg@disable-top-trap +.eo +.de cov*title AU +.. +.\"------------------- +.de cov@title-end +.ec +.. +.\"------------------- +.\" .AU name [initials [loc [dept [ext [room [arg [arg [arg]]]]]]]] +.de AU +.cov@title-end +.pg@disable-top-trap +.if \\n[.$]<1 .@error "AU: no arguments" +.nr cov*au +1 +.nr cov*i 0 1 +.while \\n[.$]>=\\n+[cov*i] \{\ +. ds cov*au!\\n[cov*au]!\\n[cov*i] "\\$[\\n[cov*i]] +.\} +.if (\\n[.$]>=3)&(\w@\\$3@) \{\ +. if d cov*location-\\$3] \{\ +. ds cov*au!3!\\n[cov*au] \\*[cov*location-\\$3] +. \} +.\} +.. +.\"------------------- +.\" .AT title1 [title2 [... [title9] ]]]] +.\" Well, thats all that COVEND look for. +.\" Must appear directly after .AU +.de AT +.if \\n[.$]<1 .@error "AT: no arguments" +.nr cov*i 0 1 +.while \\n[.$]>=\\n+[cov*i] \{\ +. ds cov*at!\\n[cov*au]!\\n[cov*i] "\\$[\\n[cov*i]] +.\} +.. +.\"------------------- +.de AF +.cov@title-end +.if \\n[.$]<1 .@error "AF: no arguments" +.ds cov*firm \\$1 +.. +.de AST +.ds cov*abs-name \\$1 +.. +.de AS +.pg@disable-top-trap +.if d cov*abstract .@error "AS: only one abstract allowed" +.if !''\\n[.z]' .@error "AS: no diversion allowed (previous .AS?)" +.nr cov*abs-arg 0\\$1 +.nr cov*abs-ind (n;0\\$2) +.de cov*abstract AE +.. +.de AE +.. +.\" I am planning to use mgm some time :-) +.ie \\n[yr]<50 .ds cov*new-date \\*[MO\\n[mo]] \\n[dy], 20\\n[yr] +.el .ds cov*new-date \\*[MO\\n[mo]] \\n[dy], 19\\n[yr] +.als DT cov*new-date +.de ND +.\" don't remember why I did this: .pg@disable-top-trap +.ds cov*new-date \\$1 +.. +.\"------------------- +.\" save technical numbers. +.de TM +.nr cov*i 0 1 +.while \\n[.$]>=\\n+[cov*i] .ds cov*mt-tm!\\n[cov*i] \\$[\\n[cov*i]] +.nr cov*mt-tm-max \\n[.$] +.. +.\"----------------------- +.\" cover sheet +.\" the file must have the following last lines (somewhere): +.\" .pg@enable-top-trap +.\" .bp 1 +.\" .pg@enable-trap +.ds cov*mt-file!0 0.MT +.ds cov*mt-file!1 0.MT +.ds cov*mt-file!2 0.MT +.ds cov*mt-file!3 0.MT +.ds cov*mt-file!4 4.MT +.ds cov*mt-file!5 5.MT +.ds cov*mt-file!6 0.MT +.\"------------ +.de MT +.ie \\n[.$] \{\ +. ie d cov*mt-file!\\$1 .ds cov*mt-type \\$1 +. el .ds cov*mt-type 6 +.\} +.el .ds cov*mt-type 1 +.ds cov*mt-addresse "\\$2 +.ds cov*mt-type-text "\\$1 +.ie d @language .ds cov*str mm/\\*[@language]_ +.el .ds cov*str mm/ +.mso \\*[cov*str]\\*[cov*mt-file!\\*[cov*mt-type]] +.. +.de COVER +.ie !\\n[.$] .ds cov*cov-type ms +.el .ds cov*cov-type \\$1 +.pg@disable-top-trap +.ie d @language .ds cov*str mm/\\*[@language]_\\*[cov*cov-type].cov +.el .ds cov*str mm/\\*[cov*cov-type].cov +.mso \\*[cov*str] +.. +.\"########################### module qrf ############################ +.\" forward and backward reference thru special files. +.\" +.\" init reference system +.de INITR +.if \\n[.$]<1 .@error "INITR:filename missing" +.\" ignore if INITR has already been used +.if !r qrf*pass \{\ +.\" +. ds qrf*file \\$1 +. sy test -f \\*[qrf*file].tmp +. ie \\n[systat] \{\ +. \" PASS 1 +. if \\n[D]=1 .tm PASS 1 +. if \\n[D]>1 .tm INITR: file \\*[qrf*file].tmp, PASS 1 +. nr qrf*pass 1 +. open qrf*stream \\*[qrf*file].tmp +. write qrf*stream .\\\\" references for \\*[qrf*file] +. close qrf*stream +. \} +. el \{\ +. nr qrf*pass 2 +. if \\n[D]=1 .tm PASS 2 +. if \\n[D]>1 .tm INITR: file \\*[qrf*file].tmp, PASS 2 +. sy mv \\*[qrf*file].tmp \\*[qrf*file].qrf +' so \\*[qrf*file].qrf +. \} +.\} +.. +.\"--------------- +.\" set a reference. +.de SETR +.if \\n[.$]<1 .@error "SETR:reference name missing" +.ie !r qrf*pass .tm "SETR: No .INITR in this file" +.el \{\ +. ds qrf*name qrf*ref-\\$1 +.\" probably pass two if already defined +. if \\n[qrf*pass]<2 \{\ +. if \\n[D]>2 .tm SETR: ref \\*[qrf*name]=\\*[hd*toc-mark],\\n[%] +. \" heading-number +. ds \\*[qrf*name]-hn \\*[hd*toc-mark] +. \" page-number +. ds \\*[qrf*name]-pn \\n[%] +. \" +. \" append to file +. opena qrf*stream \\*[qrf*file].tmp +. write qrf*stream .ds \\*[qrf*name]-hn \\*[hd*toc-mark] +. write qrf*stream .ds \\*[qrf*name]-pn \\n[%] +. if !'\\$2'' .write qrf*stream .ds \\*[qrf*name]-xx \\$2 +. close qrf*stream +. \} +.\} +.. +.\"--------------- +.\" get misc-string, output <->42<-> in pass 1 +.\" If two arg -> set var. arg to misc-string. +.de GETST +.if \\n[.$]<1 .@error "GETST:reference name missing" +.if !r qrf*pass .tm "GETST: No .INITR in this file" +.ds qrf*name qrf*ref-\\$1 +.ie \\n[qrf*pass]=2 \{\ +. ie !d \\*[qrf*name]-xx .tm "GETHN:\\$1 not defined" +. el \{\ +. ie \\n[.$]>1 .ds \\$2 \\*[\\*[qrf*name]-xx] +. el \\*[\\*[qrf*name]-xx]\c +. \} +.\} +.\" The answer... +.el <->42<->\c +.. +.\"--------------- +.\" get header-number, output X.X.X. in pass 1 +.\" If two arg -> set var. arg to header-number. +.de GETHN +.if \\n[.$]<1 .@error "GETHN:reference name missing" +.if !r qrf*pass .tm "GETHN: No .INITR in this file" +.ds qrf*name qrf*ref-\\$1 +.ie \\n[qrf*pass]=2 \{\ +. ie !d \\*[qrf*name]-hn .tm "GETHN:\\$1 not defined" +. el \{\ +. ie \\n[.$]>1 .ds \\$2 \\*[\\*[qrf*name]-hn] +. el \\*[\\*[qrf*name]-hn]\c +. \} +.\} +.el X.X.X.\c +.. +.\"--------------- +.\" get page-number, output 9999 in pass 1 +.\" If two arg -> set var. arg to page-number. +.de GETPN +.if \\n[.$]<1 .@error "GETPN:reference name missing" +.if !r qrf*pass .tm "GETPN: No .INITR in this file" +.ds qrf*name qrf*ref-\\$1 +.ie \\n[qrf*pass]=2 \{\ +. ie !d \\*[qrf*name]-pn .tm "GETPN:\\$1 not defined" +. el \{\ +. ie \\n[.$]>1 .ds \\$2 \\*[\\*[qrf*name]-pn] +. el \\*[\\*[qrf*name]-pn]\c +. \} +.\} +.el 9999\c +.. +.\"---------- +.de GETR +.if \\n[.$]<1 .@error "GETR:reference name missing" +.ie !r qrf*pass \{\ +. tm "GETR: No .INITR in this file" +.\} +.el \{\ +. if \\n[qrf*pass]=2 \{\ +. GETHN \\$1 Qrfh +. GETPN \\$1 Qrfp +\\*[Qrf] +. \} +.\} +.. diff --git a/gnu/usr.bin/groff/mm/tmac.mse b/gnu/usr.bin/groff/mm/tmac.mse new file mode 100644 index 0000000000..315d684d2f --- /dev/null +++ b/gnu/usr.bin/groff/mm/tmac.mse @@ -0,0 +1,42 @@ +.\" swedish version of mm +.\" for mgm version 1.04 +.mso tmac.m +.ds @language se +.\" +.ds Lf Figurer +.ds Lt Tabeller +.ds Lx Uppställningar +.ds Le Ekvationer +.\" Page length +.if !r L .nr @pl 28.5c +.\" page width +.if !r W .nr @ll 13c +.\" page offset +.if !r O .nr @po 3.5c +.\" set the above parameters +.ll \n[@ll]u +.po \n[@po]u +.pl \n[@pl]u +.ds Lifg Figur +.ds Litb Tabell +.ds Liex Uppställning +.ds Liec Ekvation +.ds Licon Innehållsförteckning +.ds Qrf Se kapitel \\*[Qrfh], sidan \\*[Qrfp]. +.ds Rp Referenser +.\" +.ds MO1 januari +.ds MO2 februari +.ds MO3 mars +.ds MO4 april +.ds MO5 maj +.ds MO6 juni +.ds MO7 juli +.ds MO8 augusti +.ds MO9 september +.ds MO10 oktober +.ds MO11 november +.ds MO12 december +.ie \\n[yr]<50 .ds cov*new-date \\n[dy] \\*[MO\\n[mo]] 20\\n[yr] +.el .ds cov*new-date \\n[dy] \\*[MO\\n[mo]] 19\\n[yr] +.nr pg*footer-size 4\" 1v+footer+even/odd footer+1v diff --git a/gnu/usr.bin/groff/nroff/Makefile b/gnu/usr.bin/groff/nroff/Makefile new file mode 100644 index 0000000000..71f62f4057 --- /dev/null +++ b/gnu/usr.bin/groff/nroff/Makefile @@ -0,0 +1,11 @@ +MAN1= nroff.0 + +afterinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + $(.CURDIR)/nroff.sh $(DESTDIR)$(BINDIR)/nroff + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + $(.CURDIR)/psroff.sh $(DESTDIR)$(BINDIR)/psroff + +.include +.include <../../../usr.bin/Makefile.inc> +.include <../Makefile.cfg> diff --git a/gnu/usr.bin/groff/nroff/nroff.1 b/gnu/usr.bin/groff/nroff/nroff.1 new file mode 100644 index 0000000000..1dae057186 --- /dev/null +++ b/gnu/usr.bin/groff/nroff/nroff.1 @@ -0,0 +1,58 @@ +.TH NROFF 1 "10 August 1992" "Groff Version 1.08" +.SH NAME +nroff \- emulate nroff command with groff +.SH SYNOPSIS +.B nroff +[ +.B \-hi +] +[ +.BI \-m name +] +[ +.BI \-n num +] +[ +.BI \-o list +] +[ +.BI \-r cn +] +[ +.BI \-T name +] +[ +.I file\|.\|.\|. +] +.SH DESCRIPTION +The +.B nroff +script emulates the +.B nroff +command using groff. +The +.B \-T +option with an argument other than +.B ascii +and +.B latin1 +will be ignored. +The +.B \-h +option +is equivalent to the +.B grotty +.B \-h +option. +Other options are as described in +.BR troff (1). +In addition the +.BR \-e , +.B \-q +and +.B \-s +options are silently ignored. +.SH "SEE ALSO" +.BR groff (1), +.BR troff (1), +.BR grotty (1) diff --git a/gnu/usr.bin/groff/nroff/nroff.sh b/gnu/usr.bin/groff/nroff/nroff.sh new file mode 100644 index 0000000000..1be695995f --- /dev/null +++ b/gnu/usr.bin/groff/nroff/nroff.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# Emulate nroff with groff. + +prog="$0" +# Default device. +T=-Tascii +opts= + +for i +do + case $1 in + -h) + opts="$opts -P-h" + ;; + -[eq]|-s*) + # ignore these options + ;; + -[mrnoT]) + echo "$prog: option $1 requires an argument" >&2 + exit 1 + ;; + -i|-[mrno]*) + opts="$opts $1"; + ;; + + -Tascii|-Tlatin1) + T=$1 + ;; + -T*) + # ignore other devices + ;; + --) + shift + break + ;; + -) + break + ;; + -*) + echo "$prog: invalid option $1" >&2 + exit 1 + ;; + *) + break + ;; + esac + shift +done + +# This shell script is intended for use with man, so warnings are +# probably not wanted. Also load nroff-style character definitions. +exec groff -Wall -mtty-char $T $opts ${1+"$@"} diff --git a/gnu/usr.bin/groff/nroff/psroff.sh b/gnu/usr.bin/groff/nroff/psroff.sh new file mode 100644 index 0000000000..8a9008234b --- /dev/null +++ b/gnu/usr.bin/groff/nroff/psroff.sh @@ -0,0 +1,2 @@ +#! /bin/sh - +exec groff -Tps -l -C ${1+"$@"} diff --git a/gnu/usr.bin/groff/pfbtops/Makefile b/gnu/usr.bin/groff/pfbtops/Makefile new file mode 100644 index 0000000000..1d7ba2d755 --- /dev/null +++ b/gnu/usr.bin/groff/pfbtops/Makefile @@ -0,0 +1,11 @@ +# Makefile for pfbtops + +PROG= pfbtops +SRCS= pfbtops.c +LDADD+= $(LIBGROFF) +DPADD+= $(LIBGROFF) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/pfbtops/Makefile.dep b/gnu/usr.bin/groff/pfbtops/Makefile.dep new file mode 100644 index 0000000000..2cc41ed5a2 --- /dev/null +++ b/gnu/usr.bin/groff/pfbtops/Makefile.dep @@ -0,0 +1 @@ +pfbtops.o : pfbtops.c diff --git a/gnu/usr.bin/groff/pfbtops/pfbtops.1 b/gnu/usr.bin/groff/pfbtops/pfbtops.1 new file mode 100644 index 0000000000..46c353c393 --- /dev/null +++ b/gnu/usr.bin/groff/pfbtops/pfbtops.1 @@ -0,0 +1,27 @@ +.\" -*- nroff -*- +.TH PFBTOPS 1 "6 August 1992" "Groff Version 1.08" +.SH NAME +pfbtops \- translate a PostScript font in .pfb format to ASCII +.SH SYNOPSIS +.B pfbtops +[ +.I pfb_file +] +.SH DESCRIPTION +.B pfbtops +translates a PostScript font in +.B .pfb +format to ASCII. +If +.I pfb_file +is omitted the pfb file will be read from the standard input. +The ASCII format PostScript font will be written on the standard output. +PostScript fonts for MS-DOS are normally supplied in +.B .pfb +format. +.LP +The resulting ASCII format PostScript font can be used with groff. +It must first be listed in +.BR /usr/share/groff_font/devps/download . +.SH "SEE ALSO" +.BR grops (1) diff --git a/gnu/usr.bin/groff/pfbtops/pfbtops.c b/gnu/usr.bin/groff/pfbtops/pfbtops.c new file mode 100644 index 0000000000..bc79bce59d --- /dev/null +++ b/gnu/usr.bin/groff/pfbtops/pfbtops.c @@ -0,0 +1,112 @@ +/* This translates ps fonts in .pfb format to ASCII ps files. */ + +#include + +/* Binary bytes per output line. */ +#define BYTES_PER_LINE (79/2) +#define HEX_DIGITS "0123456789ABCDEF" + +static char *program_name; + +static void error(s) + char *s; +{ + fprintf(stderr, "%s: %s\n", program_name, s); + exit(2); +} + +static void usage() +{ + fprintf(stderr, "usage: %s [-v] [pfb_file]\n", program_name); + exit(1); +} + +int main(argc, argv) + int argc; + char **argv; +{ + int opt; + extern int optind; + + program_name = argv[0]; + + while ((opt = getopt(argc, argv, "v")) != EOF) { + switch (opt) { + case 'v': + { + extern char *version_string; + fprintf(stderr, "pfbtops groff version %s\n", version_string); + fflush(stderr); + break; + } + case '?': + usage(); + } + } + + if (argc - optind > 1) + usage(); + if (argc > optind && !freopen(argv[optind], "r", stdin)) + { + perror(argv[optind]); + exit(1); + } + for (;;) + { + int type, c, i; + long n; + + c = getchar(); + if (c != 0x80) + error("first byte of packet not 0x80"); + type = getchar(); + if (type == 3) + break; + if (type != 1 && type != 2) + error("bad packet type"); + n = 0; + for (i = 0; i < 4; i++) + { + c = getchar(); + if (c == EOF) + error("end of file in packet header"); + n |= (long)c << (i << 3); + } + if (n < 0) + error("negative packet length"); + if (type == 1) + { + while (--n >= 0) + { + c = getchar(); + if (c == EOF) + error("end of file in text packet"); + if (c == '\r') + c = '\n'; + putchar(c); + } + if (c != '\n') + putchar('\n'); + } + else + { + int count = 0; + while (--n >= 0) + { + c = getchar(); + if (c == EOF) + error("end of file in binary packet"); + if (count >= BYTES_PER_LINE) + { + putchar('\n'); + count = 0; + } + count++; + putchar(HEX_DIGITS[(c >> 4) & 0xf]); + putchar(HEX_DIGITS[c & 0xf]); + } + putchar('\n'); + } + } + exit(0); +} diff --git a/gnu/usr.bin/groff/pic/Makefile b/gnu/usr.bin/groff/pic/Makefile new file mode 100644 index 0000000000..90341133db --- /dev/null +++ b/gnu/usr.bin/groff/pic/Makefile @@ -0,0 +1,15 @@ +# Makefile for pic + +PROG= pic +SRCS= lex.cc main.cc object.cc common.cc troff.cc tex.cc +OBJS= pic.o +CFLAGS+= -I. -I$(.CURDIR)/../include +LDADD+= $(LIBGROFF) -lm +DPADD+= $(LIBGROFF) $(LIBMATH) + +CLEANFILES+= pic.cc pic.tab.h + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/pic/Makefile.dep b/gnu/usr.bin/groff/pic/Makefile.dep new file mode 100644 index 0000000000..f16199cdc8 --- /dev/null +++ b/gnu/usr.bin/groff/pic/Makefile.dep @@ -0,0 +1,22 @@ +lex.o : lex.cc pic.h ../include/assert.h ../include/cset.h ../include/lib.h \ + ../include/stringclass.h ../include/errarg.h ../include/error.h \ + position.h text.h output.h ../include/ptable.h object.h pic.cc +main.o : main.cc pic.h ../include/assert.h ../include/cset.h \ + ../include/lib.h ../include/stringclass.h ../include/errarg.h \ + ../include/error.h position.h text.h output.h +object.o : object.cc pic.h ../include/assert.h ../include/cset.h \ + ../include/lib.h ../include/stringclass.h ../include/errarg.h \ + ../include/error.h position.h text.h output.h ../include/ptable.h \ + object.h +common.o : common.cc pic.h ../include/assert.h ../include/cset.h \ + ../include/lib.h ../include/stringclass.h ../include/errarg.h \ + ../include/error.h position.h text.h output.h common.h +troff.o : troff.cc pic.h ../include/assert.h ../include/cset.h \ + ../include/lib.h ../include/stringclass.h ../include/errarg.h \ + ../include/error.h position.h text.h output.h common.h +tex.o : tex.cc pic.h ../include/assert.h ../include/cset.h ../include/lib.h \ + ../include/stringclass.h ../include/errarg.h ../include/error.h \ + position.h text.h output.h common.h +pic.o : pic.cc pic.h ../include/assert.h ../include/cset.h ../include/lib.h \ + ../include/stringclass.h ../include/errarg.h ../include/error.h \ + position.h text.h output.h ../include/ptable.h object.h diff --git a/gnu/usr.bin/groff/pic/TODO b/gnu/usr.bin/groff/pic/TODO new file mode 100644 index 0000000000..2346b575e1 --- /dev/null +++ b/gnu/usr.bin/groff/pic/TODO @@ -0,0 +1,37 @@ +Dotted and dashed ellipses. + +In troff mode, dotted and dashed splines. + +Make DELIMITED have type lstr; this would allow us to give better +error messages for problems within the body of for and if constructs. + +In troff mode without -x, fake \D't' with .ps commands. + +Perhaps an option to set command char. + +Add an output class for dumb line printers. It wouldn't be pretty but +it would be better than nothing. Integrate it with texinfo. Useful +for groff -Tascii as well. + +Option to allow better positioning of arrowheads on arcs. + +Perhaps add PostScript output mode. + +Change the interface to the output class so that output devices have +the opportunity to handle arrowheads themselves. + +Consider whether the line thickness should scale. + +Consider whether the test in a for loop should be fuzzy (as it +apparently is in grap). + +Possibly change fillval so that zero is black. + +Provide a way of getting text blocks (positioned with `.in' rather +than \h), into pic. Should be possible to use block of diverted text +in pic. Possibly something similar to T{ and T} in tbl. + +Option to provide macro backtraces. + +Have a path that is searched by `copy' statement. Set by environment +variable or command line option. diff --git a/gnu/usr.bin/groff/pic/common.cc b/gnu/usr.bin/groff/pic/common.cc new file mode 100644 index 0000000000..0f61c750eb --- /dev/null +++ b/gnu/usr.bin/groff/pic/common.cc @@ -0,0 +1,495 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "pic.h" +#include "common.h" + +// output a dashed circle as a series of arcs + +void common_output::dashed_circle(const position ¢, double rad, + const line_type <) +{ + assert(lt.type == line_type::dashed); + line_type slt = lt; + slt.type = line_type::solid; + double dash_angle = lt.dash_width/rad; + int ndashes; + double gap_angle; + if (dash_angle >= M_PI/4.0) { + if (dash_angle < M_PI/2.0) { + gap_angle = M_PI/2.0 - dash_angle; + ndashes = 4; + } + else if (dash_angle < M_PI) { + gap_angle = M_PI - dash_angle; + ndashes = 2; + } + else { + circle(cent, rad, slt, -1.0); + return; + } + } + else { + ndashes = 4*int(ceil(M_PI/(4.0*dash_angle))); + gap_angle = (M_PI*2.0)/ndashes - dash_angle; + } + for (int i = 0; i < ndashes; i++) { + double start_angle = i*(dash_angle+gap_angle) - dash_angle/2.0; + solid_arc(cent, rad, start_angle, start_angle + dash_angle, lt); + } +} + +// output a dotted circle as a series of dots + +void common_output::dotted_circle(const position ¢, double rad, + const line_type <) +{ + assert(lt.type == line_type::dotted); + double gap_angle = lt.dash_width/rad; + int ndots; + if (gap_angle >= M_PI/2.0) { + // always have at least 2 dots + gap_angle = M_PI; + ndots = 2; + } + else { + ndots = 4*int(M_PI/(2.0*gap_angle)); + gap_angle = (M_PI*2.0)/ndots; + } + double ang = 0.0; + for (int i = 0; i < ndots; i++, ang += gap_angle) + dot(cent + position(cos(ang), sin(ang))*rad, lt); +} + +// return non-zero iff we can compute a center + +int compute_arc_center(const position &start, const position ¢, + const position &end, position *result) +{ + // This finds the point along the vector from start to cent that + // is equidistant between start and end. + distance c = cent - start; + distance e = end - start; + double n = c*e; + if (n == 0.0) + return 0; + *result = start + c*((e*e)/(2.0*n)); + return 1; +} + +// output a dashed arc as a series of arcs + +void common_output::dashed_arc(const position &start, const position ¢, + const position &end, const line_type <) +{ + assert(lt.type == line_type::dashed); + position c; + if (!compute_arc_center(start, cent, end, &c)) { + line(start, &end, 1, lt); + return; + } + distance start_offset = start - c; + distance end_offset = end - c; + double start_angle = atan2(start_offset.y, start_offset.x); + double end_angle = atan2(end_offset.y, end_offset.x); + double rad = hypot(c - start); + double dash_angle = lt.dash_width/rad; + double total_angle = end_angle - start_angle; + while (total_angle < 0) + total_angle += M_PI + M_PI; + if (total_angle <= dash_angle*2.0) { + solid_arc(cent, rad, start_angle, end_angle, lt); + return; + } + int ndashes = int((total_angle - dash_angle)/(dash_angle*2.0) + .5); + double dash_and_gap_angle = (total_angle - dash_angle)/ndashes; + for (int i = 0; i <= ndashes; i++) + solid_arc(cent, rad, start_angle + i*dash_and_gap_angle, + start_angle + i*dash_and_gap_angle + dash_angle, lt); +} + +// output a dotted arc as a series of dots + +void common_output::dotted_arc(const position &start, const position ¢, + const position &end, const line_type <) +{ + assert(lt.type == line_type::dotted); + position c; + if (!compute_arc_center(start, cent, end, &c)) { + line(start, &end, 1, lt); + return; + } + distance start_offset = start - c; + distance end_offset = end - c; + double start_angle = atan2(start_offset.y, start_offset.x); + double total_angle = atan2(end_offset.y, end_offset.x) - start_angle; + while (total_angle < 0) + total_angle += M_PI + M_PI; + double rad = hypot(c - start); + int ndots = int(total_angle/(lt.dash_width/rad) + .5); + if (ndots == 0) + dot(start, lt); + else { + for (int i = 0; i <= ndots; i++) { + double a = start_angle + (total_angle*i)/ndots; + dot(cent + position(cos(a), sin(a))*rad, lt); + } + } +} + +void common_output::solid_arc(const position ¢, double rad, + double start_angle, double end_angle, + const line_type <) +{ + line_type slt = lt; + slt.type = line_type::solid; + arc(cent + position(cos(start_angle), sin(start_angle))*rad, + cent, + cent + position(cos(end_angle), sin(end_angle))*rad, + slt); +} + + +void common_output::rounded_box(const position ¢, const distance &dim, + double rad, const line_type <, double fill) +{ + if (fill >= 0.0) + filled_rounded_box(cent, dim, rad, fill); + switch (lt.type) { + case line_type::invisible: + break; + case line_type::dashed: + dashed_rounded_box(cent, dim, rad, lt); + break; + case line_type::dotted: + dotted_rounded_box(cent, dim, rad, lt); + break; + case line_type::solid: + solid_rounded_box(cent, dim, rad, lt); + break; + default: + assert(0); + } +} + + +void common_output::dashed_rounded_box(const position ¢, + const distance &dim, double rad, + const line_type <) +{ + line_type slt = lt; + slt.type = line_type::solid; + + double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad; + int n_hor_dashes = int(hor_length/(lt.dash_width*2.0) + .5); + double hor_gap_width = (n_hor_dashes != 0 + ? hor_length/n_hor_dashes - lt.dash_width + : 0.0); + + double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad; + int n_vert_dashes = int(vert_length/(lt.dash_width*2.0) + .5); + double vert_gap_width = (n_vert_dashes != 0 + ? vert_length/n_vert_dashes - lt.dash_width + : 0.0); + // Note that each corner arc has to be split into two for dashing, + // because one part is dashed using vert_gap_width, and the other + // using hor_gap_width. + double offset = lt.dash_width/2.0; + dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, + -M_PI/4.0, 0, slt, lt.dash_width, vert_gap_width, &offset); + dash_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad), + cent + position(dim.x/2.0, dim.y/2.0 - rad), + slt, lt.dash_width, vert_gap_width, &offset); + dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, + 0, M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset); + + offset = lt.dash_width/2.0; + dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, + M_PI/4.0, M_PI/2, slt, lt.dash_width, hor_gap_width, &offset); + dash_line(cent + position(dim.x/2.0 - rad, dim.y/2.0), + cent + position(-dim.x/2.0 + rad, dim.y/2.0), + slt, lt.dash_width, hor_gap_width, &offset); + dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, + M_PI/2, 3*M_PI/4.0, slt, lt.dash_width, hor_gap_width, &offset); + + offset = lt.dash_width/2.0; + dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, + 3.0*M_PI/4.0, M_PI, slt, lt.dash_width, vert_gap_width, &offset); + dash_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad), + cent + position(-dim.x/2.0, -dim.y/2.0 + rad), + slt, lt.dash_width, vert_gap_width, &offset); + dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, + M_PI, 5.0*M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset); + + offset = lt.dash_width/2.0; + dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, + 5*M_PI/4.0, 3*M_PI/2.0, slt, lt.dash_width, hor_gap_width, &offset); + dash_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0), + cent + position(dim.x/2.0 - rad, -dim.y/2.0), + slt, lt.dash_width, hor_gap_width, &offset); + dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, + 3*M_PI/2, 7*M_PI/4, slt, lt.dash_width, hor_gap_width, &offset); +} + +// Used by dashed_rounded_box. + +void common_output::dash_arc(const position ¢, double rad, + double start_angle, double end_angle, + const line_type <, + double dash_width, double gap_width, + double *offsetp) +{ + double length = (end_angle - start_angle)*rad; + double pos = 0.0; + for (;;) { + if (*offsetp >= dash_width) { + double rem = dash_width + gap_width - *offsetp; + if (pos + rem > length) { + *offsetp += length - pos; + break; + } + else { + pos += rem; + *offsetp = 0.0; + } + } + else { + double rem = dash_width - *offsetp; + if (pos + rem > length) { + solid_arc(cent, rad, start_angle + pos/rad, end_angle, lt); + *offsetp += length - pos; + break; + } + else { + solid_arc(cent, rad, start_angle + pos/rad, + start_angle + (pos + rem)/rad, lt); + pos += rem; + *offsetp = dash_width; + } + } + } +} + +// Used by dashed_rounded_box. + +void common_output::dash_line(const position &start, const position &end, + const line_type <, + double dash_width, double gap_width, + double *offsetp) +{ + distance dist = end - start; + double length = hypot(dist); + if (length == 0.0) + return; + double pos = 0.0; + for (;;) { + if (*offsetp >= dash_width) { + double rem = dash_width + gap_width - *offsetp; + if (pos + rem > length) { + *offsetp += length - pos; + break; + } + else { + pos += rem; + *offsetp = 0.0; + } + } + else { + double rem = dash_width - *offsetp; + if (pos + rem > length) { + line(start + dist*(pos/length), &end, 1, lt); + *offsetp += length - pos; + break; + } + else { + position p(start + dist*((pos + rem)/length)); + line(start + dist*(pos/length), &p, 1, lt); + pos += rem; + *offsetp = dash_width; + } + } + } +} + +void common_output::dotted_rounded_box(const position ¢, + const distance &dim, double rad, + const line_type <) +{ + line_type slt = lt; + slt.type = line_type::solid; + + double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad; + int n_hor_dots = int(hor_length/lt.dash_width + .5); + double hor_gap_width = (n_hor_dots != 0 + ? hor_length/n_hor_dots + : lt.dash_width); + + double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad; + int n_vert_dots = int(vert_length/lt.dash_width + .5); + double vert_gap_width = (n_vert_dots != 0 + ? vert_length/n_vert_dots + : lt.dash_width); + double epsilon = lt.dash_width/(rad*100.0); + + double offset = 0.0; + dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, + -M_PI/4.0, 0, slt, vert_gap_width, &offset); + dot_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad), + cent + position(dim.x/2.0, dim.y/2.0 - rad), + slt, vert_gap_width, &offset); + dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, + 0, M_PI/4.0 - epsilon, slt, vert_gap_width, &offset); + + offset = 0.0; + dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, + M_PI/4.0, M_PI/2, slt, hor_gap_width, &offset); + dot_line(cent + position(dim.x/2.0 - rad, dim.y/2.0), + cent + position(-dim.x/2.0 + rad, dim.y/2.0), + slt, hor_gap_width, &offset); + dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, + M_PI/2, 3*M_PI/4.0 - epsilon, slt, hor_gap_width, &offset); + + offset = 0.0; + dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, + 3.0*M_PI/4.0, M_PI, slt, vert_gap_width, &offset); + dot_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad), + cent + position(-dim.x/2.0, -dim.y/2.0 + rad), + slt, vert_gap_width, &offset); + dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, + M_PI, 5.0*M_PI/4.0 - epsilon, slt, vert_gap_width, &offset); + + offset = 0.0; + dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, + 5*M_PI/4.0, 3*M_PI/2.0, slt, hor_gap_width, &offset); + dot_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0), + cent + position(dim.x/2.0 - rad, -dim.y/2.0), + slt, hor_gap_width, &offset); + dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, + 3*M_PI/2, 7*M_PI/4 - epsilon, slt, hor_gap_width, &offset); +} + +// Used by dotted_rounded_box. + +void common_output::dot_arc(const position ¢, double rad, + double start_angle, double end_angle, + const line_type <, double gap_width, + double *offsetp) +{ + double length = (end_angle - start_angle)*rad; + double pos = 0.0; + for (;;) { + if (*offsetp == 0.0) { + double ang = start_angle + pos/rad; + dot(cent + position(cos(ang), sin(ang))*rad, lt); + } + double rem = gap_width - *offsetp; + if (pos + rem > length) { + *offsetp += length - pos; + break; + } + else { + pos += rem; + *offsetp = 0.0; + } + } +} + +// Used by dotted_rounded_box. + +void common_output::dot_line(const position &start, const position &end, + const line_type <, double gap_width, + double *offsetp) +{ + distance dist = end - start; + double length = hypot(dist); + double pos = 0.0; + for (;;) { + if (*offsetp == 0.0) + dot(start + dist*(pos/length), lt); + double rem = gap_width - *offsetp; + if (pos + rem > length) { + *offsetp += length - pos; + break; + } + else { + pos += rem; + *offsetp = 0.0; + } + } +} + + +void common_output::solid_rounded_box(const position ¢, + const distance &dim, double rad, + const line_type <) +{ + position tem = cent - dim/2.0; + arc(tem + position(0.0, rad), + tem + position(rad, rad), + tem + position(rad, 0.0), + lt); + tem = cent + position(-dim.x/2.0, dim.y/2.0); + arc(tem + position(rad, 0.0), + tem + position(rad, -rad), + tem + position(0.0, -rad), + lt); + tem = cent + dim/2.0; + arc(tem + position(0.0, -rad), + tem + position(-rad, -rad), + tem + position(-rad, 0.0), + lt); + tem = cent + position(dim.x/2.0, -dim.y/2.0); + arc(tem + position(-rad, 0.0), + tem + position(-rad, rad), + tem + position(0.0, rad), + lt); + position end; + end = cent + position(-dim.x/2.0, dim.y/2.0 - rad); + line(cent - dim/2.0 + position(0.0, rad), &end, 1, lt); + end = cent + position(dim.x/2.0 - rad, dim.y/2.0); + line(cent + position(-dim.x/2.0 + rad, dim.y/2.0), &end, 1, lt); + end = cent + position(dim.x/2.0, -dim.y/2.0 + rad); + line(cent + position(dim.x/2.0, dim.y/2.0 - rad), &end, 1, lt); + end = cent + position(-dim.x/2.0 + rad, -dim.y/2.0); + line(cent + position(dim.x/2.0 - rad, -dim.y/2.0), &end, 1, lt); +} + +void common_output::filled_rounded_box(const position ¢, + const distance &dim, double rad, + double fill) +{ + line_type ilt; + ilt.type = line_type::invisible; + circle(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, ilt, fill); + circle(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, ilt, fill); + circle(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, ilt, fill); + circle(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, ilt, fill); + position vec[4]; + vec[0] = cent + position(dim.x/2.0, dim.y/2.0 - rad); + vec[1] = cent + position(-dim.x/2.0, dim.y/2.0 - rad); + vec[2] = cent + position(-dim.x/2.0, -dim.y/2.0 + rad); + vec[3] = cent + position(dim.x/2.0, -dim.y/2.0 + rad); + polygon(vec, 4, ilt, fill); + vec[0] = cent + position(dim.x/2.0 - rad, dim.y/2.0); + vec[1] = cent + position(-dim.x/2.0 + rad, dim.y/2.0); + vec[2] = cent + position(-dim.x/2.0 + rad, -dim.y/2.0); + vec[3] = cent + position(dim.x/2.0 - rad, -dim.y/2.0); + polygon(vec, 4, ilt, fill); +} diff --git a/gnu/usr.bin/groff/pic/common.h b/gnu/usr.bin/groff/pic/common.h new file mode 100644 index 0000000000..47560ce1c6 --- /dev/null +++ b/gnu/usr.bin/groff/pic/common.h @@ -0,0 +1,70 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +class common_output : public output { +private: + void dash_line(const position &start, const position &end, + const line_type <, double dash_width, double gap_width, + double *offsetp); + void dash_arc(const position ¢, double rad, + double start_angle, double end_angle, const line_type <, + double dash_width, double gap_width, double *offsetp); + void dot_line(const position &start, const position &end, + const line_type <, double gap_width, double *offsetp); + void dot_arc(const position ¢, double rad, + double start_angle, double end_angle, const line_type <, + double gap_width, double *offsetp); +protected: + virtual void dot(const position &, const line_type &) = 0; + void dashed_circle(const position &, double rad, const line_type &); + void dotted_circle(const position &, double rad, const line_type &); + void dashed_arc(const position &, const position &, const position &, + const line_type &); + void dotted_arc(const position &, const position &, const position &, + const line_type &); + virtual void solid_arc(const position ¢, double rad, double start_angle, + double end_angle, const line_type <); + void dashed_rounded_box(const position &, const distance &, double, + const line_type &); + void dotted_rounded_box(const position &, const distance &, double, + const line_type &); + void solid_rounded_box(const position &, const distance &, double, + const line_type &); + void filled_rounded_box(const position &, const distance &, double, double); +public: + void start_picture(double sc, const position &ll, const position &ur) = 0; + void finish_picture() = 0; + void circle(const position &, double rad, const line_type &, double) = 0; + void text(const position &, text_piece *, int, double) = 0; + void line(const position &, const position *, int n, const line_type &) = 0; + void polygon(const position *, int n, const line_type &, double) = 0; + void spline(const position &, const position *, int n, + const line_type &) = 0; + void arc(const position &, const position &, const position &, + const line_type &) = 0; + void ellipse(const position &, const distance &, + const line_type &, double) = 0; + void rounded_box(const position &, const distance &, double, + const line_type &, double); +}; + +int compute_arc_center(const position &start, const position ¢, + const position &end, position *result); + diff --git a/gnu/usr.bin/groff/pic/depend b/gnu/usr.bin/groff/pic/depend new file mode 100644 index 0000000000..73ac3ab909 --- /dev/null +++ b/gnu/usr.bin/groff/pic/depend @@ -0,0 +1,21 @@ +pic.tab.o : pic.tab.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \ + ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \ + output.h ../lib/ptable.h object.h +lex.o : lex.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \ + ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \ + output.h ../lib/ptable.h object.h pic.tab.h +main.o : main.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \ + ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \ + output.h +object.o : object.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \ + ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \ + output.h ../lib/ptable.h object.h +common.o : common.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \ + ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \ + output.h common.h +troff.o : troff.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \ + ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \ + output.h common.h +tex.o : tex.cc pic.h ../lib/assert.h ../lib/cset.h ../lib/lib.h \ + ../lib/stringclass.h ../lib/errarg.h ../lib/error.h position.h text.h \ + output.h common.h diff --git a/gnu/usr.bin/groff/pic/lex.cc b/gnu/usr.bin/groff/pic/lex.cc new file mode 100644 index 0000000000..a066533b55 --- /dev/null +++ b/gnu/usr.bin/groff/pic/lex.cc @@ -0,0 +1,1938 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "pic.h" +#include "ptable.h" +#include "object.h" +#include "pic.tab.h" + +declare_ptable(char) +implement_ptable(char) + +PTABLE(char) macro_table; + +class macro_input : public input { + char *s; + char *p; +public: + macro_input(const char *); + ~macro_input(); + int get(); + int peek(); +}; + +class argument_macro_input : public input { + char *s; + char *p; + char *ap; + int argc; + char *argv[9]; +public: + argument_macro_input(const char *, int, char **); + ~argument_macro_input(); + int get(); + int peek(); +}; + +input::input() : next(0) +{ +} + +input::~input() +{ +} + +int input::get_location(const char **, int *) +{ + return 0; +} + +file_input::file_input(FILE *f, const char *fn) +: lineno(0), ptr(""), filename(fn) +{ + fp = f; +} + +file_input::~file_input() +{ + fclose(fp); +} + +int file_input::read_line() +{ + for (;;) { + line.clear(); + lineno++; + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + else if (illegal_input_char(c)) + lex_error("illegal input character code %1", c); + else { + line += char(c); + if (c == '\n') + break; + } + } + if (line.length() == 0) + return 0; + if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'P' + && (line[2] == 'S' || line[2] == 'E' || line[2] == 'F') + && (line.length() == 3 || line[3] == ' ' || line[3] == '\n' + || compatible_flag))) { + line += '\0'; + ptr = line.contents(); + return 1; + } + } +} + +int file_input::get() +{ + if (*ptr != '\0' || read_line()) + return (unsigned char)*ptr++; + else + return EOF; +} + +int file_input::peek() +{ + if (*ptr != '\0' || read_line()) + return (unsigned char)*ptr; + else + return EOF; +} + +int file_input::get_location(const char **fnp, int *lnp) +{ + *fnp = filename; + *lnp = lineno; + return 1; +} + +macro_input::macro_input(const char *str) +{ + p = s = strsave(str); +} + +macro_input::~macro_input() +{ + a_delete s; +} + +int macro_input::get() +{ + if (p == 0 || *p == '\0') + return EOF; + else + return (unsigned char)*p++; +} + +int macro_input::peek() +{ + if (p == 0 || *p == '\0') + return EOF; + else + return (unsigned char)*p; +} + +// Character respresenting $1. Must be illegal input character. +#define ARG1 14 + +char *process_body(const char *body) +{ + char *s = strsave(body); + int j = 0; + for (int i = 0; s[i] != '\0'; i++) + if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') { + if (s[i+1] != '0') + s[j++] = ARG1 + s[++i] - '1'; + } + else + s[j++] = s[i]; + s[j] = '\0'; + return s; +} + + +argument_macro_input::argument_macro_input(const char *body, int ac, char **av) +: argc(ac), ap(0) +{ + for (int i = 0; i < argc; i++) + argv[i] = av[i]; + p = s = process_body(body); +} + + +argument_macro_input::~argument_macro_input() +{ + for (int i = 0; i < argc; i++) + a_delete argv[i]; + a_delete s; +} + +int argument_macro_input::get() +{ + if (ap) { + if (*ap != '\0') + return (unsigned char)*ap++; + ap = 0; + } + if (p == 0) + return EOF; + while (*p >= ARG1 && *p <= ARG1 + 8) { + int i = *p++ - ARG1; + if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { + ap = argv[i]; + return (unsigned char)*ap++; + } + } + if (*p == '\0') + return EOF; + return (unsigned char)*p++; +} + +int argument_macro_input::peek() +{ + if (ap) { + if (*ap != '\0') + return (unsigned char)*ap; + ap = 0; + } + if (p == 0) + return EOF; + while (*p >= ARG1 && *p <= ARG1 + 8) { + int i = *p++ - ARG1; + if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { + ap = argv[i]; + return (unsigned char)*ap; + } + } + if (*p == '\0') + return EOF; + return (unsigned char)*p; +} + +class input_stack { + static input *current_input; + static int bol_flag; +public: + static void push(input *); + static void clear(); + static int get_char(); + static int peek_char(); + static int get_location(const char **fnp, int *lnp); + static void push_back(unsigned char c, int was_bol = 0); + static int bol(); +}; + +input *input_stack::current_input = 0; +int input_stack::bol_flag = 0; + +inline int input_stack::bol() +{ + return bol_flag; +} + +void input_stack::clear() +{ + while (current_input != 0) { + input *tem = current_input; + current_input = current_input->next; + delete tem; + } + bol_flag = 1; +} + +void input_stack::push(input *in) +{ + in->next = current_input; + current_input = in; +} + +void lex_init(input *top) +{ + input_stack::clear(); + input_stack::push(top); +} + +void lex_cleanup() +{ + while (input_stack::get_char() != EOF) + ; +} + +int input_stack::get_char() +{ + while (current_input != 0) { + int c = current_input->get(); + if (c != EOF) { + bol_flag = c == '\n'; + return c; + } + // don't pop the top-level input off the stack + if (current_input->next == 0) + return EOF; + input *tem = current_input; + current_input = current_input->next; + delete tem; + } + return EOF; +} + +int input_stack::peek_char() +{ + while (current_input != 0) { + int c = current_input->peek(); + if (c != EOF) + return c; + if (current_input->next == 0) + return EOF; + input *tem = current_input; + current_input = current_input->next; + delete tem; + } + return EOF; +} + +class char_input : public input { + int c; +public: + char_input(int); + int get(); + int peek(); +}; + +char_input::char_input(int n) : c((unsigned char)n) +{ +} + +int char_input::get() +{ + int n = c; + c = EOF; + return n; +} + +int char_input::peek() +{ + return c; +} + +void input_stack::push_back(unsigned char c, int was_bol) +{ + push(new char_input(c)); + bol_flag = was_bol; +} + +int input_stack::get_location(const char **fnp, int *lnp) +{ + for (input *p = current_input; p; p = p->next) + if (p->get_location(fnp, lnp)) + return 1; + return 0; +} + +string context_buffer; + +string token_buffer; +double token_double; +int token_int; + +void interpolate_macro_with_args(const char *body) +{ + char *argv[9]; + int argc = 0; + for (int i = 0; i < 9; i++) + argv[i] = 0; + int level = 0; + int c; + enum { NORMAL, IN_STRING, IN_STRING_QUOTED } state = NORMAL; + do { + token_buffer.clear(); + for (;;) { + c = input_stack::get_char(); + if (c == EOF) { + lex_error("end of input while scanning macro arguments"); + break; + } + if (state == NORMAL && level == 0 && (c == ',' || c == ')')) { + if (token_buffer.length() > 0) { + token_buffer += '\0'; + argv[argc] = strsave(token_buffer.contents()); + } + // for `foo()', argc = 0 + if (argc > 0 || c != ')' || i > 0) + argc++; + break; + } + token_buffer += char(c); + switch (state) { + case NORMAL: + if (c == '"') + state = IN_STRING; + else if (c == '(') + level++; + else if (c == ')') + level--; + break; + case IN_STRING: + if (c == '"') + state = NORMAL; + else if (c == '\\') + state = IN_STRING_QUOTED; + break; + case IN_STRING_QUOTED: + state = IN_STRING; + break; + } + } + } while (c != ')' && c != EOF); + input_stack::push(new argument_macro_input(body, argc, argv)); +} + +static int docmp(const char *s1, int n1, const char *s2, int n2) +{ + if (n1 < n2) { + int r = memcmp(s1, s2, n1); + return r ? r : -1; + } + else if (n1 > n2) { + int r = memcmp(s1, s2, n2); + return r ? r : 1; + } + else + return memcmp(s1, s2, n1); +} + +int lookup_keyword(const char *str, int len) +{ + static struct keyword { + const char *name; + int token; + } table[] = { + "Here", HERE, + "above", ABOVE, + "aligned", ALIGNED, + "and", AND, + "arc", ARC, + "arrow", ARROW, + "at", AT, + "atan2", ATAN2, + "below", BELOW, + "between", BETWEEN, + "bottom", BOTTOM, + "box", BOX, + "by", BY, + "ccw", CCW, + "center", CENTER, + "chop", CHOP, + "circle", CIRCLE, + "command", COMMAND, + "copy", COPY, + "cos", COS, + "cw", CW, + "dashed", DASHED, + "define", DEFINE, + "diam", DIAMETER, + "diameter", DIAMETER, + "do", DO, + "dotted", DOTTED, + "down", DOWN, + "ellipse", ELLIPSE, + "else", ELSE, + "end", END, + "exp", EXP, + "fill", FILL, + "filled", FILL, + "for", FOR, + "from", FROM, + "height", HEIGHT, + "ht", HEIGHT, + "if", IF, + "int", INT, + "invis", INVISIBLE, + "invisible", INVISIBLE, + "last", LAST, + "left", LEFT, + "line", LINE, + "ljust", LJUST, + "log", LOG, + "lower", LOWER, + "max", K_MAX, + "min", K_MIN, + "move", MOVE, + "of", OF, + "plot", PLOT, + "print", PRINT, + "rad", RADIUS, + "radius", RADIUS, + "rand", RAND, + "reset", RESET, + "right", RIGHT, + "rjust", RJUST, + "same", SAME, + "sh", SH, + "sin", SIN, + "spline", SPLINE, + "sprintf", SPRINTF, + "sqrt", SQRT, + "start", START, + "the", THE, + "then", THEN, + "thick", THICKNESS, + "thickness", THICKNESS, + "thru", THRU, + "to", TO, + "top", TOP, + "undef", UNDEF, + "until", UNTIL, + "up", UP, + "upper", UPPER, + "way", WAY, + "wid", WIDTH, + "width", WIDTH, + "with", WITH, + }; + + const keyword *start = table; + const keyword *end = table + sizeof(table)/sizeof(table[0]); + while (start < end) { + // start <= target < end + const keyword *mid = start + (end - start)/2; + + int cmp = docmp(str, len, mid->name, strlen(mid->name)); + if (cmp == 0) + return mid->token; + if (cmp < 0) + end = mid; + else + start = mid + 1; + } + return 0; +} + +int get_token_after_dot(int c) +{ + // get_token deals with the case where c is a digit + switch (c) { + case 'h': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + context_buffer = ".ht"; + return DOT_HT; + } + else if (c == 'e') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'i') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'g') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'h') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + context_buffer = ".height"; + return DOT_HT; + } + input_stack::push_back('h'); + } + input_stack::push_back('g'); + } + input_stack::push_back('i'); + } + input_stack::push_back('e'); + } + input_stack::push_back('h'); + return '.'; + case 'x': + input_stack::get_char(); + context_buffer = ".x"; + return DOT_X; + case 'y': + input_stack::get_char(); + context_buffer = ".y"; + return DOT_Y; + case 'c': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'e') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'n') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'e') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'r') { + input_stack::get_char(); + context_buffer = ".center"; + return DOT_C; + } + input_stack::push_back('e'); + } + input_stack::push_back('t'); + } + input_stack::push_back('n'); + } + input_stack::push_back('e'); + } + context_buffer = ".c"; + return DOT_C; + case 'n': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'e') { + input_stack::get_char(); + context_buffer = ".ne"; + return DOT_NE; + } + else if (c == 'w') { + input_stack::get_char(); + context_buffer = ".nw"; + return DOT_NW; + } + else { + context_buffer = ".n"; + return DOT_N; + } + break; + case 'e': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'n') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'd') { + input_stack::get_char(); + context_buffer = ".end"; + return DOT_END; + } + input_stack::push_back('n'); + context_buffer = ".e"; + return DOT_E; + } + context_buffer = ".e"; + return DOT_E; + case 'w': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'i') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'd') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'h') { + input_stack::get_char(); + context_buffer = ".width"; + return DOT_WID; + } + input_stack::push_back('t'); + } + context_buffer = ".wid"; + return DOT_WID; + } + input_stack::push_back('i'); + } + context_buffer = ".w"; + return DOT_W; + case 's': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'e') { + input_stack::get_char(); + context_buffer = ".se"; + return DOT_SE; + } + else if (c == 'w') { + input_stack::get_char(); + context_buffer = ".sw"; + return DOT_SW; + } + else { + if (c == 't') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'a') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'r') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + context_buffer = ".start"; + return DOT_START; + } + input_stack::push_back('r'); + } + input_stack::push_back('a'); + } + input_stack::push_back('t'); + } + context_buffer = ".s"; + return DOT_S; + } + break; + case 't': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'o') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'p') { + input_stack::get_char(); + context_buffer = ".top"; + return DOT_N; + } + input_stack::push_back('o'); + } + context_buffer = ".t"; + return DOT_N; + case 'l': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'e') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'f') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + context_buffer = ".left"; + return DOT_W; + } + input_stack::push_back('f'); + } + input_stack::push_back('e'); + } + context_buffer = ".l"; + return DOT_W; + case 'r': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'a') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'd') { + input_stack::get_char(); + context_buffer = ".rad"; + return DOT_RAD; + } + input_stack::push_back('a'); + } + else if (c == 'i') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'g') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'h') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + context_buffer = ".right"; + return DOT_E; + } + input_stack::push_back('h'); + } + input_stack::push_back('g'); + } + input_stack::push_back('i'); + } + context_buffer = ".r"; + return DOT_E; + case 'b': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'o') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'o') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'm') { + input_stack::get_char(); + context_buffer = ".bottom"; + return DOT_S; + } + input_stack::push_back('o'); + } + input_stack::push_back('t'); + } + context_buffer = ".bot"; + return DOT_S; + } + input_stack::push_back('o'); + } + context_buffer = ".b"; + return DOT_S; + default: + context_buffer = '.'; + return '.'; + } +} + +int get_token(int lookup_flag) +{ + context_buffer.clear(); + for (;;) { + int n = 0; + int bol = input_stack::bol(); + int c = input_stack::get_char(); + if (bol && c == command_char) { + token_buffer.clear(); + token_buffer += c; + // the newline is not part of the token + for (;;) { + c = input_stack::peek_char(); + if (c == EOF || c == '\n') + break; + input_stack::get_char(); + token_buffer += char(c); + } + context_buffer = token_buffer; + return COMMAND_LINE; + } + switch (c) { + case EOF: + return EOF; + case ' ': + case '\t': + break; + case '\\': + { + int d = input_stack::peek_char(); + if (d != '\n') { + context_buffer = '\\'; + return '\\'; + } + input_stack::get_char(); + break; + } + case '#': + do { + c = input_stack::get_char(); + } while (c != '\n' && c != EOF); + if (c == '\n') + context_buffer = '\n'; + return c; + case '"': + context_buffer = '"'; + token_buffer.clear(); + for (;;) { + c = input_stack::get_char(); + if (c == '\\') { + context_buffer += '\\'; + c = input_stack::peek_char(); + if (c == '"') { + input_stack::get_char(); + token_buffer += '"'; + context_buffer += '"'; + } + else + token_buffer += '\\'; + } + else if (c == '\n') { + error("newline in string"); + break; + } + else if (c == EOF) { + error("missing `\"'"); + break; + } + else if (c == '"') { + context_buffer += '"'; + break; + } + else { + context_buffer += char(c); + token_buffer += char(c); + } + } + return TEXT; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + int overflow = 0; + n = 0; + for (;;) { + if (n > (INT_MAX - 9)/10) { + overflow = 1; + break; + } + n *= 10; + n += c - '0'; + context_buffer += char(c); + c = input_stack::peek_char(); + if (c == EOF || !csdigit(c)) + break; + c = input_stack::get_char(); + } + token_double = n; + if (overflow) { + for (;;) { + token_double *= 10.0; + token_double += c - '0'; + context_buffer += char(c); + c = input_stack::peek_char(); + if (c == EOF || !csdigit(c)) + break; + c = input_stack::get_char(); + } + // if somebody asks for 1000000000000th, we will silently + // give them INT_MAXth + double temp = token_double; // work around gas 1.34/sparc bug + if (token_double > INT_MAX) + n = INT_MAX; + else + n = int(temp); + } + } + switch (c) { + case 'i': + case 'I': + context_buffer += char(c); + input_stack::get_char(); + return NUMBER; + case '.': + { + context_buffer += '.'; + input_stack::get_char(); + got_dot: + double factor = 1.0; + for (;;) { + c = input_stack::peek_char(); + if (!c == EOF || !csdigit(c)) + break; + input_stack::get_char(); + context_buffer += char(c); + factor /= 10.0; + if (c != '0') + token_double += factor*(c - '0'); + } + if (c != 'e' && c != 'E') { + if (c == 'i' || c == 'I') { + context_buffer += char(c); + input_stack::get_char(); + } + return NUMBER; + } + } + // fall through + case 'e': + case 'E': + { + int echar = c; + input_stack::get_char(); + c = input_stack::peek_char(); + int sign = '+'; + if (c == '+' || c == '-') { + sign = c; + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == EOF || !csdigit(c)) { + input_stack::push_back(sign); + input_stack::push_back(echar); + return NUMBER; + } + context_buffer += char(echar); + context_buffer += char(sign); + } + else { + if (c == EOF || !csdigit(c)) { + input_stack::push_back(echar); + return NUMBER; + } + context_buffer += char(echar); + } + input_stack::get_char(); + context_buffer += char(c); + n = c - '0'; + for (;;) { + c = input_stack::peek_char(); + if (c == EOF || !csdigit(c)) + break; + input_stack::get_char(); + context_buffer += char(c); + n = n*10 + (c - '0'); + } + if (sign == '-') + n = -n; + if (c == 'i' || c == 'I') { + context_buffer += char(c); + input_stack::get_char(); + } + token_double *= pow(10.0, n); + return NUMBER; + } + case 'n': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'd') { + input_stack::get_char(); + token_int = n; + context_buffer += "nd"; + return ORDINAL; + } + input_stack::push_back('n'); + return NUMBER; + case 'r': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'd') { + input_stack::get_char(); + token_int = n; + context_buffer += "rd"; + return ORDINAL; + } + input_stack::push_back('r'); + return NUMBER; + case 't': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'h') { + input_stack::get_char(); + token_int = n; + context_buffer += "th"; + return ORDINAL; + } + input_stack::push_back('t'); + return NUMBER; + case 's': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + token_int = n; + context_buffer += "st"; + return ORDINAL; + } + input_stack::push_back('s'); + return NUMBER; + default: + return NUMBER; + } + break; + case '\'': + { + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'h') { + input_stack::get_char(); + context_buffer = "'th"; + return TH; + } + else + input_stack::push_back('t'); + } + context_buffer = "'"; + return '\''; + } + case '.': + { + c = input_stack::peek_char(); + if (c != EOF && csdigit(c)) { + n = 0; + token_double = 0.0; + context_buffer = '.'; + goto got_dot; + } + return get_token_after_dot(c); + } + case '<': + c = input_stack::peek_char(); + if (c == '-') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == '>') { + input_stack::get_char(); + context_buffer = "<->"; + return DOUBLE_ARROW_HEAD; + } + context_buffer = "<-"; + return LEFT_ARROW_HEAD; + } + else if (c == '=') { + input_stack::get_char(); + context_buffer = "<="; + return LESSEQUAL; + } + context_buffer = "<"; + return '<'; + case '-': + c = input_stack::peek_char(); + if (c == '>') { + input_stack::get_char(); + context_buffer = "->"; + return RIGHT_ARROW_HEAD; + } + context_buffer = "-"; + return '-'; + case '!': + c = input_stack::peek_char(); + if (c == '=') { + input_stack::get_char(); + context_buffer = "!="; + return NOTEQUAL; + } + context_buffer = "!"; + return '!'; + case '>': + c = input_stack::peek_char(); + if (c == '=') { + input_stack::get_char(); + context_buffer = ">="; + return GREATEREQUAL; + } + context_buffer = ">"; + return '>'; + case '=': + c = input_stack::peek_char(); + if (c == '=') { + input_stack::get_char(); + context_buffer = "=="; + return EQUALEQUAL; + } + context_buffer = "="; + return '='; + case '&': + c = input_stack::peek_char(); + if (c == '&') { + input_stack::get_char(); + context_buffer = "&&"; + return ANDAND; + } + context_buffer = "&"; + return '&'; + case '|': + c = input_stack::peek_char(); + if (c == '|') { + input_stack::get_char(); + context_buffer = "||"; + return OROR; + } + context_buffer = "|"; + return '|'; + default: + if (c != EOF && csalpha(c)) { + token_buffer.clear(); + token_buffer = c; + for (;;) { + c = input_stack::peek_char(); + if (c == EOF || (!csalnum(c) && c != '_')) + break; + input_stack::get_char(); + token_buffer += char(c); + } + int tok = lookup_keyword(token_buffer.contents(), + token_buffer.length()); + if (tok != 0) { + context_buffer = token_buffer; + return tok; + } + char *def = 0; + if (lookup_flag) { + token_buffer += '\0'; + def = macro_table.lookup(token_buffer.contents()); + token_buffer.set_length(token_buffer.length() - 1); + if (def) { + if (c == '(') { + input_stack::get_char(); + interpolate_macro_with_args(def); + } + else + input_stack::push(new macro_input(def)); + } + } + if (!def) { + context_buffer = token_buffer; + if (csupper(token_buffer[0])) + return LABEL; + else + return VARIABLE; + } + } + else { + context_buffer = char(c); + return (unsigned char)c; + } + break; + } + } +} + +int get_delimited() +{ + token_buffer.clear(); + int c = input_stack::get_char(); + while (c == ' ' || c == '\t' || c == '\n') + c = input_stack::get_char(); + if (c == EOF) { + lex_error("missing delimiter"); + return 0; + } + context_buffer = char(c); + int had_newline = 0; + int start = c; + int level = 0; + enum { NORMAL, IN_STRING, IN_STRING_QUOTED, DELIM_END } state = NORMAL; + for (;;) { + c = input_stack::get_char(); + if (c == EOF) { + lex_error("missing closing delimiter"); + return 0; + } + if (c == '\n') + had_newline = 1; + else if (!had_newline) + context_buffer += char(c); + switch (state) { + case NORMAL: + if (start == '{') { + if (c == '{') { + level++; + break; + } + if (c == '}') { + if (--level < 0) + state = DELIM_END; + break; + } + } + else { + if (c == start) { + state = DELIM_END; + break; + } + } + if (c == '"') + state = IN_STRING; + break; + case IN_STRING_QUOTED: + if (c == '\n') + state = NORMAL; + else + state = IN_STRING; + break; + case IN_STRING: + if (c == '"' || c == '\n') + state = NORMAL; + else if (c == '\\') + state = IN_STRING_QUOTED; + break; + case DELIM_END: + // This case it just to shut cfront 2.0 up. + default: + assert(0); + } + if (state == DELIM_END) + break; + token_buffer += c; + } + return 1; +} + +void do_define() +{ + int t = get_token(0); // do not expand what we are defining + if (t != VARIABLE && t != LABEL) { + lex_error("can only define variable or placename"); + return; + } + token_buffer += '\0'; + string nm = token_buffer; + const char *name = nm.contents(); + if (!get_delimited()) + return; + token_buffer += '\0'; + macro_table.define(name, strsave(token_buffer.contents())); +} + +void do_undef() +{ + int t = get_token(0); // do not expand what we are undefining + if (t != VARIABLE && t != LABEL) { + lex_error("can only define variable or placename"); + return; + } + token_buffer += '\0'; + macro_table.define(token_buffer.contents(), 0); +} + + +class for_input : public input { + char *var; + char *body; + double to; + int by_is_multiplicative; + double by; + const char *p; + int done_newline; +public: + for_input(char *, double, int, double, char *); + ~for_input(); + int get(); + int peek(); +}; + +for_input::for_input(char *vr, double t, int bim, double b, char *bd) +: var(vr), to(t), by_is_multiplicative(bim), by(b), body(bd), p(body), + done_newline(0) +{ +} + +for_input::~for_input() +{ + a_delete var; + a_delete body; +} + +int for_input::get() +{ + if (p == 0) + return EOF; + for (;;) { + if (*p != '\0') + return (unsigned char)*p++; + if (!done_newline) { + done_newline = 1; + return '\n'; + } + double val; + if (!lookup_variable(var, &val)) { + lex_error("body of `for' terminated enclosing block"); + return EOF; + } + if (by_is_multiplicative) + val *= by; + else + val += by; + define_variable(var, val); + if (val > to) { + p = 0; + return EOF; + } + p = body; + done_newline = 0; + } +} + +int for_input::peek() +{ + if (p == 0) + return EOF; + if (*p != '\0') + return (unsigned char)*p; + if (!done_newline) + return '\n'; + double val; + if (!lookup_variable(var, &val)) + return EOF; + if (by_is_multiplicative) { + if (val * by > to) + return EOF; + } + else { + if (val + by > to) + return EOF; + } + if (*body == '\0') + return EOF; + return (unsigned char)*body; +} + +void do_for(char *var, double from, double to, int by_is_multiplicative, + double by, char *body) +{ + define_variable(var, from); + if (from <= to) + input_stack::push(new for_input(var, to, by_is_multiplicative, by, body)); +} + + +void do_copy(const char *filename) +{ + errno = 0; + FILE *fp = fopen(filename, "r"); + if (fp == 0) { + lex_error("can't open `%1': %2", filename, strerror(errno)); + return; + } + input_stack::push(new file_input(fp, filename)); +} + +class copy_thru_input : public input { + int done; + char *body; + char *until; + const char *p; + const char *ap; + int argv[9]; + int argc; + string line; + int get_line(); + virtual int inget() = 0; +public: + copy_thru_input(const char *b, const char *u); + ~copy_thru_input(); + int get(); + int peek(); +}; + +class copy_file_thru_input : public copy_thru_input { + input *in; +public: + copy_file_thru_input(input *, const char *b, const char *u); + ~copy_file_thru_input(); + int inget(); +}; + +copy_file_thru_input::copy_file_thru_input(input *i, const char *b, + const char *u) +: in(i), copy_thru_input(b, u) +{ +} + +copy_file_thru_input::~copy_file_thru_input() +{ + delete in; +} + +int copy_file_thru_input::inget() +{ + if (!in) + return EOF; + else + return in->get(); +} + +class copy_rest_thru_input : public copy_thru_input { +public: + copy_rest_thru_input(const char *, const char *u); + int inget(); +}; + +copy_rest_thru_input::copy_rest_thru_input(const char *b, const char *u) +: copy_thru_input(b, u) +{ +} + +int copy_rest_thru_input::inget() +{ + while (next != 0) { + int c = next->get(); + if (c != EOF) + return c; + if (next->next == 0) + return EOF; + input *tem = next; + next = next->next; + delete tem; + } + return EOF; + +} + +copy_thru_input::copy_thru_input(const char *b, const char *u) +: done(0) +{ + ap = 0; + body = process_body(b); + p = 0; + until = strsave(u); +} + + +copy_thru_input::~copy_thru_input() +{ + a_delete body; + a_delete until; +} + +int copy_thru_input::get() +{ + if (ap) { + if (*ap != '\0') + return (unsigned char)*ap++; + ap = 0; + } + for (;;) { + if (p == 0) { + if (!get_line()) + break; + p = body; + } + if (*p == '\0') { + p = 0; + return '\n'; + } + while (*p >= ARG1 && *p <= ARG1 + 8) { + int i = *p++ - ARG1; + if (i < argc && line[argv[i]] != '\0') { + ap = line.contents() + argv[i]; + return (unsigned char)*ap++; + } + } + if (*p != '\0') + return (unsigned char)*p++; + } + return EOF; +} + +int copy_thru_input::peek() +{ + if (ap) { + if (*ap != '\0') + return (unsigned char)*ap; + ap = 0; + } + for (;;) { + if (p == 0) { + if (!get_line()) + break; + p = body; + } + if (*p == '\0') + return '\n'; + while (*p >= ARG1 && *p <= ARG1 + 8) { + int i = *p++ - ARG1; + if (i < argc && line[argv[i]] != '\0') { + ap = line.contents() + argv[i]; + return (unsigned char)*ap; + } + } + if (*p != '\0') + return (unsigned char)*p; + } + return EOF; +} + +int copy_thru_input::get_line() +{ + if (done) + return 0; + line.clear(); + argc = 0; + int c = inget(); + for (;;) { + while (c == ' ') + c = inget(); + if (c == EOF || c == '\n') + break; + if (argc == 9) { + do { + c = inget(); + } while (c != '\n' && c != EOF); + break; + } + argv[argc++] = line.length(); + do { + line += char(c); + c = inget(); + } while (c != ' ' && c != '\n'); + line += '\0'; + } + if (until != 0 && argc > 0 && strcmp(&line[argv[0]], until) == 0) { + done = 1; + return 0; + } + return argc > 0 || c == '\n'; +} + +class simple_file_input : public input { + const char *filename; + int lineno; + FILE *fp; +public: + simple_file_input(FILE *, const char *); + ~simple_file_input(); + int get(); + int peek(); + int get_location(const char **, int *); +}; + +simple_file_input::simple_file_input(FILE *p, const char *s) +: filename(s), fp(p), lineno(1) +{ +} + +simple_file_input::~simple_file_input() +{ + // don't delete the filename + fclose(fp); +} + +int simple_file_input::get() +{ + int c = getc(fp); + while (illegal_input_char(c)) { + error("illegal input character code %1", c); + c = getc(fp); + } + if (c == '\n') + lineno++; + return c; +} + +int simple_file_input::peek() +{ + int c = getc(fp); + while (illegal_input_char(c)) { + error("illegal input character code %1", c); + c = getc(fp); + } + if (c != EOF) + ungetc(c, fp); + return c; +} + +int simple_file_input::get_location(const char **fnp, int *lnp) +{ + *fnp = filename; + *lnp = lineno; + return 1; +} + + +void copy_file_thru(const char *filename, const char *body, const char *until) +{ + errno = 0; + FILE *fp = fopen(filename, "r"); + if (fp == 0) { + lex_error("can't open `%1': %2", filename, strerror(errno)); + return; + } + input *in = new copy_file_thru_input(new simple_file_input(fp, filename), + body, until); + input_stack::push(in); +} + +void copy_rest_thru(const char *body, const char *until) +{ + input_stack::push(new copy_rest_thru_input(body, until)); +} + +void push_body(const char *s) +{ + input_stack::push(new char_input('\n')); + input_stack::push(new macro_input(s)); +} + +int delim_flag = 0; + +char *get_thru_arg() +{ + int c = input_stack::peek_char(); + while (c == ' ') { + input_stack::get_char(); + c = input_stack::peek_char(); + } + if (c != EOF && csalpha(c)) { + // looks like a macro + input_stack::get_char(); + token_buffer = c; + for (;;) { + c = input_stack::peek_char(); + if (c == EOF || (!csalnum(c) && c != '_')) + break; + input_stack::get_char(); + token_buffer += char(c); + } + context_buffer = token_buffer; + token_buffer += '\0'; + char *def = macro_table.lookup(token_buffer.contents()); + if (def) + return strsave(def); + // I guess it wasn't a macro after all; so push the macro name back. + // -2 because we added a '\0' + for (int i = token_buffer.length() - 2; i >= 0; i--) + input_stack::push_back(token_buffer[i]); + } + if (get_delimited()) { + token_buffer += '\0'; + return strsave(token_buffer.contents()); + } + else + return 0; +} + +int lookahead_token = -1; +string old_context_buffer; + +void do_lookahead() +{ + if (lookahead_token == -1) { + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + } +} + +int yylex() +{ + if (delim_flag) { + assert(lookahead_token == -1); + if (delim_flag == 2) { + if ((yylval.str = get_thru_arg()) != 0) + return DELIMITED; + else + return 0; + } + else { + if (get_delimited()) { + token_buffer += '\0'; + yylval.str = strsave(token_buffer.contents()); + return DELIMITED; + } + else + return 0; + } + } + for (;;) { + int t; + if (lookahead_token >= 0) { + t = lookahead_token; + lookahead_token = -1; + } + else + t = get_token(1); + switch (t) { + case '\n': + return ';'; + case EOF: + return 0; + case DEFINE: + do_define(); + break; + case UNDEF: + do_undef(); + break; + case ORDINAL: + yylval.n = token_int; + return t; + case NUMBER: + yylval.x = token_double; + return t; + case COMMAND_LINE: + case TEXT: + token_buffer += '\0'; + if (!input_stack::get_location(&yylval.lstr.filename, + &yylval.lstr.lineno)) { + yylval.lstr.filename = 0; + yylval.lstr.lineno = -1; + } + yylval.lstr.str = strsave(token_buffer.contents()); + return t; + case LABEL: + case VARIABLE: + token_buffer += '\0'; + yylval.str = strsave(token_buffer.contents()); + return t; + case LEFT: + // change LEFT to LEFT_CORNER when followed by OF + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + if (lookahead_token == OF) + return LEFT_CORNER; + else + return t; + case RIGHT: + // change RIGHT to RIGHT_CORNER when followed by OF + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + if (lookahead_token == OF) + return RIGHT_CORNER; + else + return t; + case UPPER: + // recognise UPPER only before LEFT or RIGHT + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + if (lookahead_token != LEFT && lookahead_token != RIGHT) { + yylval.str = strsave("upper"); + return VARIABLE; + } + else + return t; + case LOWER: + // recognise LOWER only before LEFT or RIGHT + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + if (lookahead_token != LEFT && lookahead_token != RIGHT) { + yylval.str = strsave("lower"); + return VARIABLE; + } + else + return t; + case TOP: + // recognise TOP only before OF + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + if (lookahead_token != OF) { + yylval.str = strsave("top"); + return VARIABLE; + } + else + return t; + case BOTTOM: + // recognise BOTTOM only before OF + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + if (lookahead_token != OF) { + yylval.str = strsave("bottom"); + return VARIABLE; + } + else + return t; + case CENTER: + // recognise CENTER only before OF + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + if (lookahead_token != OF) { + yylval.str = strsave("center"); + return VARIABLE; + } + else + return t; + case START: + // recognise START only before OF + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + if (lookahead_token != OF) { + yylval.str = strsave("start"); + return VARIABLE; + } + else + return t; + case END: + // recognise END only before OF + old_context_buffer = context_buffer; + lookahead_token = get_token(1); + if (lookahead_token != OF) { + yylval.str = strsave("end"); + return VARIABLE; + } + else + return t; + default: + return t; + } + } +} + +void lex_error(const char *message, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + const char *filename; + int lineno; + if (!input_stack::get_location(&filename, &lineno)) + error(message, arg1, arg2, arg3); + else + error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3); +} + +void lex_warning(const char *message, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + const char *filename; + int lineno; + if (!input_stack::get_location(&filename, &lineno)) + warning(message, arg1, arg2, arg3); + else + warning_with_file_and_line(filename, lineno, message, arg1, arg2, arg3); +} + +void yyerror(const char *s) +{ + const char *filename; + int lineno; + const char *context = 0; + if (lookahead_token == -1) { + if (context_buffer.length() > 0) { + context_buffer += '\0'; + context = context_buffer.contents(); + } + } + else { + if (old_context_buffer.length() > 0) { + old_context_buffer += '\0'; + context = old_context_buffer.contents(); + } + } + if (!input_stack::get_location(&filename, &lineno)) { + if (context) { + if (context[0] == '\n' && context[1] == '\0') + error("%1 before newline", s); + else + error("%1 before `%2'", s, context); + } + else + error("%1 at end of picture", s); + } + else { + if (context) { + if (context[0] == '\n' && context[1] == '\0') + error_with_file_and_line(filename, lineno, "%1 before newline", s); + else + error_with_file_and_line(filename, lineno, "%1 before `%2'", + s, context); + } + else + error_with_file_and_line(filename, lineno, "%1 at end of picture", s); + } +} + diff --git a/gnu/usr.bin/groff/pic/main.cc b/gnu/usr.bin/groff/pic/main.cc new file mode 100644 index 0000000000..fe608ebd98 --- /dev/null +++ b/gnu/usr.bin/groff/pic/main.cc @@ -0,0 +1,611 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "pic.h" + +extern int yyparse(); + +output *out; + +int flyback_flag; +int zero_length_line_flag = 0; +// Non-zero means we're using a groff driver. +int driver_extension_flag = 1; +int compatible_flag = 0; +int command_char = '.'; // the character that introduces lines + // that should be passed through tranparently +static int lf_flag = 1; // non-zero if we should attempt to understand + // lines beginning with `.lf' + +void do_file(const char *filename); + +class top_input : public input { + FILE *fp; + int bol; + int eof; + int push_back[3]; + int start_lineno; +public: + top_input(FILE *); + int get(); + int peek(); + int get_location(const char **, int *); +}; + +top_input::top_input(FILE *p) : fp(p), bol(1), eof(0) +{ + push_back[0] = push_back[1] = push_back[2] = EOF; + start_lineno = current_lineno; +} + +int top_input::get() +{ + if (eof) + return EOF; + if (push_back[2] != EOF) { + int c = push_back[2]; + push_back[2] = EOF; + return c; + } + else if (push_back[1] != EOF) { + int c = push_back[1]; + push_back[1] = EOF; + return c; + } + else if (push_back[0] != EOF) { + int c = push_back[0]; + push_back[0] = EOF; + return c; + } + int c = getc(fp); + while (illegal_input_char(c)) { + error("illegal input character code %1", int(c)); + c = getc(fp); + bol = 0; + } + if (bol && c == '.') { + c = getc(fp); + if (c == 'P') { + c = getc(fp); + if (c == 'F' || c == 'E') { + int d = getc(fp); + if (d != EOF) + ungetc(d, fp); + if (d == EOF || d == ' ' || d == '\n' || compatible_flag) { + eof = 1; + flyback_flag = c == 'F'; + return EOF; + } + push_back[0] = c; + push_back[1] = 'P'; + return '.'; + } + if (c == 'S') { + c = getc(fp); + if (c != EOF) + ungetc(c, fp); + if (c == EOF || c == ' ' || c == '\n' || compatible_flag) { + error("nested .PS"); + eof = 1; + return EOF; + } + push_back[0] = 'S'; + push_back[1] = 'P'; + return '.'; + } + if (c != EOF) + ungetc(c, fp); + push_back[0] = 'P'; + return '.'; + } + else { + if (c != EOF) + ungetc(c, fp); + return '.'; + } + } + if (c == '\n') { + bol = 1; + current_lineno++; + return '\n'; + } + bol = 0; + if (c == EOF) { + eof = 1; + error("end of file before .PE or .PF"); + error_with_file_and_line(current_filename, start_lineno - 1, + ".PS was here"); + } + return c; +} + +int top_input::peek() +{ + if (eof) + return EOF; + if (push_back[2] != EOF) + return push_back[2]; + if (push_back[1] != EOF) + return push_back[1]; + if (push_back[0] != EOF) + return push_back[0]; + int c = getc(fp); + while (illegal_input_char(c)) { + error("illegal input character code %1", int(c)); + c = getc(fp); + bol = 0; + } + if (bol && c == '.') { + c = getc(fp); + if (c == 'P') { + c = getc(fp); + if (c == 'F' || c == 'E') { + int d = getc(fp); + if (d != EOF) + ungetc(d, fp); + if (d == EOF || d == ' ' || d == '\n' || compatible_flag) { + eof = 1; + flyback_flag = c == 'F'; + return EOF; + } + push_back[0] = c; + push_back[1] = 'P'; + push_back[2] = '.'; + return '.'; + } + if (c == 'S') { + c = getc(fp); + if (c != EOF) + ungetc(c, fp); + if (c == EOF || c == ' ' || c == '\n' || compatible_flag) { + error("nested .PS"); + eof = 1; + return EOF; + } + push_back[0] = 'S'; + push_back[1] = 'P'; + push_back[2] = '.'; + return '.'; + } + if (c != EOF) + ungetc(c, fp); + push_back[0] = 'P'; + push_back[1] = '.'; + return '.'; + } + else { + if (c != EOF) + ungetc(c, fp); + push_back[0] = '.'; + return '.'; + } + } + if (c != EOF) + ungetc(c, fp); + if (c == '\n') + return '\n'; + return c; +} + +int top_input::get_location(const char **filenamep, int *linenop) +{ + *filenamep = current_filename; + *linenop = current_lineno; + return 1; +} + +void do_picture(FILE *fp) +{ + flyback_flag = 0; + int c; + while ((c = getc(fp)) == ' ') + ; + if (c == '<') { + string filename; + while ((c = getc(fp)) == ' ') + ; + while (c != EOF && c != ' ' && c != '\n') { + filename += char(c); + c = getc(fp); + } + if (c == ' ') { + do { + c = getc(fp); + } while (c != EOF && c != '\n'); + } + if (c == '\n') + current_lineno++; + if (filename.length() == 0) + error("missing filename after `<'"); + else { + filename += '\0'; + const char *old_filename = current_filename; + int old_lineno = current_lineno; + // filenames must be permanent + do_file(strsave(filename.contents())); + current_filename = old_filename; + current_lineno = old_lineno; + } + out->set_location(current_filename, current_lineno); + } + else { + out->set_location(current_filename, current_lineno); + string start_line; + while (c != EOF) { + if (c == '\n') { + current_lineno++; + break; + } + start_line += c; + c = getc(fp); + } + if (c == EOF) + return; + start_line += '\0'; + double wid, ht; + switch (sscanf(&start_line[0], "%lf %lf", &wid, &ht)) { + case 1: + ht = 0.0; + break; + case 2: + break; + default: + ht = wid = 0.0; + break; + } + out->set_desired_width_height(wid, ht); + out->set_args(start_line.contents()); + lex_init(new top_input(fp)); + if (yyparse()) + lex_error("giving up on this picture"); + parse_cleanup(); + lex_cleanup(); + + // skip the rest of the .PF/.PE line + while ((c = getc(fp)) != EOF && c != '\n') + ; + if (c == '\n') + current_lineno++; + out->set_location(current_filename, current_lineno); + } +} + +void do_file(const char *filename) +{ + FILE *fp; + if (strcmp(filename, "-") == 0) + fp = stdin; + else { + errno = 0; + fp = fopen(filename, "r"); + if (fp == 0) + fatal("can't open `%1': %2", filename, strerror(errno)); + } + out->set_location(filename, 1); + current_filename = filename; + current_lineno = 1; + enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START; + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + switch (state) { + case START: + if (c == '.') + state = HAD_DOT; + else { + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case MIDDLE: + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + break; + case HAD_DOT: + if (c == 'P') + state = HAD_P; + else if (lf_flag && c == 'l') + state = HAD_l; + else { + putchar('.'); + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case HAD_P: + if (c == 'S') + state = HAD_PS; + else { + putchar('.'); + putchar('P'); + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case HAD_PS: + if (c == ' ' || c == '\n' || compatible_flag) { + ungetc(c, fp); + do_picture(fp); + state = START; + } + else { + fputs(".PS", stdout); + putchar(c); + state = MIDDLE; + } + break; + case HAD_l: + if (c == 'f') + state = HAD_lf; + else { + putchar('.'); + putchar('l'); + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case HAD_lf: + if (c == ' ' || c == '\n' || compatible_flag) { + string line; + while (c != EOF) { + line += c; + if (c == '\n') { + current_lineno++; + break; + } + c = getc(fp); + } + line += '\0'; + interpret_lf_args(line.contents()); + printf(".lf%s", line.contents()); + state = START; + } + else { + fputs(".lf", stdout); + putchar(c); + state = MIDDLE; + } + break; + default: + assert(0); + } + } + switch (state) { + case START: + break; + case MIDDLE: + putchar('\n'); + break; + case HAD_DOT: + fputs(".\n", stdout); + break; + case HAD_P: + fputs(".P\n", stdout); + break; + case HAD_PS: + fputs(".PS\n", stdout); + break; + case HAD_l: + fputs(".l\n", stdout); + break; + case HAD_lf: + fputs(".lf\n", stdout); + break; + } + if (fp != stdin) + fclose(fp); +} + +#ifdef FIG_SUPPORT +void do_whole_file(const char *filename) +{ + // Do not set current_filename. + FILE *fp; + if (strcmp(filename, "-") == 0) + fp = stdin; + else { + errno = 0; + fp = fopen(filename, "r"); + if (fp == 0) + fatal("can't open `%1': %2", filename, strerror(errno)); + } + lex_init(new file_input(fp, filename)); + yyparse(); + parse_cleanup(); + lex_cleanup(); +} +#endif + +void usage() +{ + fprintf(stderr, "usage: %s [ -nvC ] [ filename ... ]\n", program_name); +#ifdef TEX_SUPPORT + fprintf(stderr, " %s -t [ -cvzC ] [ filename ... ]\n", program_name); +#endif +#ifdef FIG_SUPPORT + fprintf(stderr, " %s -f [ -v ] [ filename ]\n", program_name); +#endif + exit(1); +} + +#ifdef __MSDOS__ +static char *fix_program_name(char *arg, char *dflt) +{ + if (!arg) + return dflt; + char *prog = strchr(arg, '\0'); + for (;;) { + if (prog == arg) + break; + --prog; + if (strchr("\\/:", *prog)) { + prog++; + break; + } + } + char *ext = strchr(prog, '.'); + if (ext) + *ext = '\0'; + for (char *p = prog; *p; p++) + if ('A' <= *p && *p <= 'Z') + *p = 'a' + (*p - 'A'); + return prog; +} +#endif /* __MSDOS__ */ + +int main(int argc, char **argv) +{ +#ifdef __MSDOS__ + argv[0] = fix_program_name(argv[0], "pic"); +#endif /* __MSDOS__ */ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int opt; +#ifdef TEX_SUPPORT + int tex_flag = 0; + int tpic_flag = 0; +#endif +#ifdef FIG_SUPPORT + int whole_file_flag = 0; + int fig_flag = 0; +#endif + while ((opt = getopt(argc, argv, "T:CDtcvnxzpf")) != EOF) + switch (opt) { + case 'C': + compatible_flag = 1; + break; + case 'D': + case 'T': + break; + case 'f': +#ifdef FIG_SUPPORT + whole_file_flag++; + fig_flag++; +#else + fatal("fig support not included"); +#endif + break; + case 'n': + driver_extension_flag = 0; + break; + case 'p': + case 'x': + warning("-%1 option is obsolete", char(opt)); + break; + case 't': +#ifdef TEX_SUPPORT + tex_flag++; +#else + fatal("TeX support not included"); +#endif + break; + case 'c': +#ifdef TEX_SUPPORT + tpic_flag++; +#else + fatal("TeX support not included"); +#endif + break; + case 'v': + { + extern const char *version_string; + fprintf(stderr, "GNU pic version %s\n", version_string); + fflush(stderr); + break; + } + case 'z': + // zero length lines will be printed as dots + zero_length_line_flag++; + break; + case '?': + usage(); + break; + default: + assert(0); + } + parse_init(); +#ifdef TEX_SUPPORT + if (tpic_flag) { + out = make_tpic_output(); + lf_flag = 0; + } + else if (tex_flag) { + out = make_tex_output(); + command_char = '\\'; + lf_flag = 0; + } + else +#endif +#ifdef FIG_SUPPORT + if (fig_flag) + out = make_fig_output(); + else +#endif + out = make_troff_output(); +#ifdef FIG_SUPPORT + if (whole_file_flag) { + if (optind >= argc) + do_whole_file("-"); + else if (argc - optind > 1) + usage(); + else + do_whole_file(argv[optind]); + } + else { +#endif + if (optind >= argc) + do_file("-"); + else + for (int i = optind; i < argc; i++) + do_file(argv[i]); +#ifdef FIG_SUPPORT + } +#endif + delete out; + if (ferror(stdout) || fflush(stdout) < 0) + fatal("output error"); + exit(0); +} + diff --git a/gnu/usr.bin/groff/pic/object.cc b/gnu/usr.bin/groff/pic/object.cc new file mode 100644 index 0000000000..b5fbf59a8e --- /dev/null +++ b/gnu/usr.bin/groff/pic/object.cc @@ -0,0 +1,1815 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "pic.h" +#include "ptable.h" +#include "object.h" + +void print_object_list(object *); + +line_type::line_type() +: type(solid), thickness(1.0) +{ +} + +output::output() : desired_height(0.0), desired_width(0.0), args(0) +{ +} + +output::~output() +{ + a_delete args; +} + +void output::set_desired_width_height(double wid, double ht) +{ + desired_width = wid; + desired_height = ht; +} + +void output::set_args(const char *s) +{ + a_delete args; + if (s == 0 || *s == '\0') + args = 0; + else + args = strsave(s); +} + +void output::command(const char *, const char *, int) +{ +} + +void output::set_location(const char *, int) +{ +} + +int output::supports_filled_polygons() +{ + return 0; +} + +void output::begin_block(const position &, const position &) +{ +} + +void output::end_block() +{ +} + +double output::compute_scale(double sc, const position &ll, const position &ur) +{ + distance dim = ur - ll; + if (desired_width != 0.0 || desired_height != 0.0) { + sc = 0.0; + if (desired_width != 0.0) { + if (dim.x == 0.0) + error("width specified for picture with zero width"); + else + sc = dim.x/desired_width; + } + if (desired_height != 0.0) { + if (dim.y == 0.0) + error("height specified for picture with zero height"); + else { + double tem = dim.y/desired_height; + if (tem > sc) + sc = tem; + } + } + return sc == 0.0 ? 1.0 : sc; + } + else { + if (sc <= 0.0) + sc = 1.0; + distance sdim = dim/sc; + double max_width = 0.0; + lookup_variable("maxpswid", &max_width); + double max_height = 0.0; + lookup_variable("maxpsht", &max_height); + if ((max_width > 0.0 && sdim.x > max_width) + || (max_height > 0.0 && sdim.y > max_height)) { + double xscale = dim.x/max_width; + double yscale = dim.y/max_height; + return xscale > yscale ? xscale : yscale; + } + else + return sc; + } +} + +position::position(const place &pl) +{ + if (pl.obj != 0) { + // Use two statements to work around bug in SGI C++. + object *tem = pl.obj; + *this = tem->origin(); + } + else { + x = pl.x; + y = pl.y; + } +} + +position::position() : x(0.0), y(0.0) +{ +} + +position::position(double a, double b) : x(a), y(b) +{ +} + + +int operator==(const position &a, const position &b) +{ + return a.x == b.x && a.y == b.y; +} + +int operator!=(const position &a, const position &b) +{ + return a.x != b.x || a.y != b.y; +} + +position &position::operator+=(const position &a) +{ + x += a.x; + y += a.y; + return *this; +} + +position &position::operator-=(const position &a) +{ + x -= a.x; + y -= a.y; + return *this; +} + +position &position::operator*=(double a) +{ + x *= a; + y *= a; + return *this; +} + +position &position::operator/=(double a) +{ + x /= a; + y /= a; + return *this; +} + +position operator-(const position &a) +{ + return position(-a.x, -a.y); +} + +position operator+(const position &a, const position &b) +{ + return position(a.x + b.x, a.y + b.y); +} + +position operator-(const position &a, const position &b) +{ + return position(a.x - b.x, a.y - b.y); +} + +position operator/(const position &a, double n) +{ + return position(a.x/n, a.y/n); +} + +position operator*(const position &a, double n) +{ + return position(a.x*n, a.y*n); +} + +// dot product + +double operator*(const position &a, const position &b) +{ + return a.x*b.x + a.y*b.y; +} + +double hypot(const position &a) +{ + return hypot(a.x, a.y); +} + +struct arrow_head_type { + double height; + double width; + int solid; +}; + +void draw_arrow(const position &pos, const distance &dir, + const arrow_head_type &aht, const line_type <) +{ + double hyp = hypot(dir); + if (hyp == 0.0) { + error("cannot draw arrow on object with zero length"); + return; + } + position base = -dir; + base *= aht.height/hyp; + position n(dir.y, -dir.x); + n *= aht.width/(hyp*2.0); + line_type slt = lt; + slt.type = line_type::solid; + if (aht.solid && out->supports_filled_polygons()) { + position v[3]; + v[0] = pos; + v[1] = pos + base + n; + v[2] = pos + base - n; + // A value > 1 means fill with the current color. + out->polygon(v, 3, slt, 2.0); + } + else { + position v[2]; + v[0] = pos; + v[1] = pos + base + n; + out->line(pos + base - n, v, 2, slt); + } +} + +object::object() : prev(0), next(0) +{ +} + +object::~object() +{ +} + +void object::move_by(const position &) +{ +} + +void object::print() +{ +} + +void object::print_text() +{ +} + +int object::blank() +{ + return 0; +} + +struct bounding_box { + int blank; + position ll; + position ur; + + bounding_box(); + void encompass(const position &); +}; + +bounding_box::bounding_box() +: blank(1) +{ +} + +void bounding_box::encompass(const position &pos) +{ + if (blank) { + ll = pos; + ur = pos; + blank = 0; + } + else { + if (pos.x < ll.x) + ll.x = pos.x; + if (pos.y < ll.y) + ll.y = pos.y; + if (pos.x > ur.x) + ur.x = pos.x; + if (pos.y > ur.y) + ur.y = pos.y; + } +} + +void object::update_bounding_box(bounding_box *) +{ +} + +position object::origin() +{ + return position(0.0,0.0); +} + +position object::north() +{ + return origin(); +} + +position object::south() +{ + return origin(); +} + +position object::east() +{ + return origin(); +} + +position object::west() +{ + return origin(); +} + +position object::north_east() +{ + return origin(); +} + +position object::north_west() +{ + return origin(); +} + +position object::south_east() +{ + return origin(); +} + +position object::south_west() +{ + return origin(); +} + +position object::start() +{ + return origin(); +} + +position object::end() +{ + return origin(); +} + +position object::center() +{ + return origin(); +} + +double object::width() +{ + return 0.0; +} + +double object::radius() +{ + return 0.0; +} + +double object::height() +{ + return 0.0; +} + +place *object::find_label(const char *) +{ + return 0; +} + +segment::segment(const position &a, int n, segment *p) +: pos(a), is_absolute(n), next(p) +{ +} + +text_item::text_item(char *t, const char *fn, int ln) +: filename(fn), lineno(ln), text(t), next(0) +{ + adj.h = CENTER_ADJUST; + adj.v = NONE_ADJUST; +} + +text_item::~text_item() +{ + a_delete text; +} + +object_spec::object_spec(object_type t) : type(t) +{ + flags = 0; + tbl = 0; + segment_list = 0; + segment_width = segment_height = 0.0; + segment_is_absolute = 0; + text = 0; + with = 0; + dir = RIGHT_DIRECTION; +} + +object_spec::~object_spec() +{ + delete tbl; + while (segment_list != 0) { + segment *tem = segment_list; + segment_list = segment_list->next; + delete tem; + } + object *p = oblist.head; + while (p != 0) { + object *tem = p; + p = p->next; + delete tem; + } + while (text != 0) { + text_item *tem = text; + text = text->next; + delete tem; + } + delete with; +} + +class command_object : public object { + char *s; + const char *filename; + int lineno; +public: + command_object(char *, const char *, int); + ~command_object(); + object_type type() { return OTHER_OBJECT; } + void print(); +}; + +command_object::command_object(char *p, const char *fn, int ln) +: s(p), filename(fn), lineno(ln) +{ +} + +command_object::~command_object() +{ + a_delete s; +} + +void command_object::print() +{ + out->command(s, filename, lineno); +} + +object *make_command_object(char *s, const char *fn, int ln) +{ + return new command_object(s, fn, ln); +} + +class mark_object : public object { +public: + mark_object(); + object_type type(); +}; + +object *make_mark_object() +{ + return new mark_object(); +} + +mark_object::mark_object() +{ +} + +object_type mark_object::type() +{ + return MARK_OBJECT; +} + +object_list::object_list() : head(0), tail(0) +{ +} + +void object_list::append(object *obj) +{ + if (tail == 0) { + obj->next = obj->prev = 0; + head = tail = obj; + } + else { + obj->prev = tail; + obj->next = 0; + tail->next = obj; + tail = obj; + } +} + +void object_list::wrap_up_block(object_list *ol) +{ + for (object *p = tail; p && p->type() != MARK_OBJECT; p = p->prev) + ; + assert(p != 0); + ol->head = p->next; + if (ol->head) { + ol->tail = tail; + ol->head->prev = 0; + } + else + ol->tail = 0; + tail = p->prev; + if (tail) + tail->next = 0; + else + head = 0; + delete p; +} + +text_piece::text_piece() +: text(0), filename(0), lineno(-1) +{ + adj.h = CENTER_ADJUST; + adj.v = NONE_ADJUST; +} + +text_piece::~text_piece() +{ + a_delete text; +} + +class graphic_object : public object { + int ntext; + text_piece *text; + int aligned; +protected: + line_type lt; +public: + graphic_object(); + ~graphic_object(); + object_type type() = 0; + void print_text(); + void add_text(text_item *, int); + void set_dotted(double); + void set_dashed(double); + void set_thickness(double); + void set_invisible(); + virtual void set_fill(double); +}; + +graphic_object::graphic_object() : ntext(0), text(0), aligned(0) +{ +} + +void graphic_object::set_dotted(double wid) +{ + lt.type = line_type::dotted; + lt.dash_width = wid; +} + +void graphic_object::set_dashed(double wid) +{ + lt.type = line_type::dashed; + lt.dash_width = wid; +} + +void graphic_object::set_thickness(double th) +{ + lt.thickness = th; +} + +void graphic_object::set_fill(double) +{ +} + +void graphic_object::set_invisible() +{ + lt.type = line_type::invisible; +} + +void graphic_object::add_text(text_item *t, int a) +{ + aligned = a; + int len = 0; + for (text_item *p = t; p; p = p->next) + len++; + if (len == 0) + text = 0; + else { + text = new text_piece[len]; + for (p = t, len = 0; p; p = p->next, len++) { + text[len].text = p->text; + p->text = 0; + text[len].adj = p->adj; + text[len].filename = p->filename; + text[len].lineno = p->lineno; + } + } + ntext = len; +} + +void graphic_object::print_text() +{ + double angle = 0.0; + if (aligned) { + position d(end() - start()); + if (d.x != 0.0 || d.y != 0.0) + angle = atan2(d.y, d.x); + } + if (text != 0) + out->text(center(), text, ntext, angle); +} + +graphic_object::~graphic_object() +{ + if (text) + ad_delete(ntext) text; +} + +class rectangle_object : public graphic_object { +protected: + position cent; + position dim; +public: + rectangle_object(const position &); + double width() { return dim.x; } + double height() { return dim.y; } + position origin() { return cent; } + position center() { return cent; } + position north() { return position(cent.x, cent.y + dim.y/2.0); } + position south() { return position(cent.x, cent.y - dim.y/2.0); } + position east() { return position(cent.x + dim.x/2.0, cent.y); } + position west() { return position(cent.x - dim.x/2.0, cent.y); } + position north_east() { return position(cent.x + dim.x/2.0, cent.y + dim.y/2.0); } + position north_west() { return position(cent.x - dim.x/2.0, cent.y + dim.y/2.0); } + position south_east() { return position(cent.x + dim.x/2.0, cent.y - dim.y/2.0); } + position south_west() { return position(cent.x - dim.x/2.0, cent.y - dim.y/2.0); } + object_type type() = 0; + void update_bounding_box(bounding_box *); + void move_by(const position &); +}; + +rectangle_object::rectangle_object(const position &d) +: dim(d) +{ +} + +void rectangle_object::update_bounding_box(bounding_box *p) +{ + p->encompass(cent - dim/2.0); + p->encompass(cent + dim/2.0); +} + +void rectangle_object::move_by(const position &a) +{ + cent += a; +} + +class closed_object : public rectangle_object { +public: + closed_object(const position &); + object_type type() = 0; + void set_fill(double); +protected: + double fill; // < 0 if not filled +}; + +closed_object::closed_object(const position &pos) +: rectangle_object(pos), fill(-1.0) +{ +} + +void closed_object::set_fill(double f) +{ + assert(f >= 0.0); + fill = f; +} + + +class box_object : public closed_object { + double xrad; + double yrad; +public: + box_object(const position &, double); + object_type type() { return BOX_OBJECT; } + void print(); + position north_east(); + position north_west(); + position south_east(); + position south_west(); +}; + +box_object::box_object(const position &pos, double r) +: closed_object(pos), xrad(dim.x > 0 ? r : -r), yrad(dim.y > 0 ? r : -r) +{ +} + +const double CHOP_FACTOR = 1.0 - 1.0/M_SQRT2; + +position box_object::north_east() +{ + return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad, + cent.y + dim.y/2.0 - CHOP_FACTOR*yrad); +} + +position box_object::north_west() +{ + return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad, + cent.y + dim.y/2.0 - CHOP_FACTOR*yrad); +} + +position box_object::south_east() +{ + return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad, + cent.y - dim.y/2.0 + CHOP_FACTOR*yrad); +} + +position box_object::south_west() +{ + return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad, + cent.y - dim.y/2.0 + CHOP_FACTOR*yrad); +} + +void box_object::print() +{ + if (lt.type == line_type::invisible && fill < 0.0) + return; + if (xrad == 0.0) { + distance dim2 = dim/2.0; + position vec[4]; + vec[0] = cent + position(dim2.x, -dim2.y); + vec[1] = cent + position(dim2.x, dim2.y); + vec[2] = cent + position(-dim2.x, dim2.y); + vec[3] = cent + position(-dim2.x, -dim2.y); + out->polygon(vec, 4, lt, fill); + } + else { + distance abs_dim(fabs(dim.x), fabs(dim.y)); + out->rounded_box(cent, abs_dim, fabs(xrad), lt, fill); + } +} + +graphic_object *object_spec::make_box(position *curpos, direction *dirp) +{ + static double last_box_height; + static double last_box_width; + static double last_box_radius; + static int have_last_box = 0; + if (!(flags & HAS_HEIGHT)) { + if ((flags & IS_SAME) && have_last_box) + height = last_box_height; + else + lookup_variable("boxht", &height); + } + if (!(flags & HAS_WIDTH)) { + if ((flags & IS_SAME) && have_last_box) + width = last_box_width; + else + lookup_variable("boxwid", &width); + } + if (!(flags & HAS_RADIUS)) { + if ((flags & IS_SAME) && have_last_box) + radius = last_box_radius; + else + lookup_variable("boxrad", &radius); + } + last_box_width = width; + last_box_height = height; + last_box_radius = radius; + have_last_box = 1; + radius = fabs(radius); + if (radius*2.0 > fabs(width)) + radius = fabs(width/2.0); + if (radius*2.0 > fabs(height)) + radius = fabs(height/2.0); + box_object *p = new box_object(position(width, height), radius); + if (!position_rectangle(p, curpos, dirp)) { + delete p; + p = 0; + } + return p; +} + +// return non-zero for success + +int object_spec::position_rectangle(rectangle_object *p, + position *curpos, direction *dirp) +{ + position pos; + dir = *dirp; // ignore any direction in attribute list + position motion; + switch (dir) { + case UP_DIRECTION: + motion.y = p->height()/2.0; + break; + case DOWN_DIRECTION: + motion.y = -p->height()/2.0; + break; + case LEFT_DIRECTION: + motion.x = -p->width()/2.0; + break; + case RIGHT_DIRECTION: + motion.x = p->width()/2.0; + break; + default: + assert(0); + } + if (flags & HAS_AT) { + pos = at; + if (flags & HAS_WITH) { + place offset; + place here; + here.obj = p; + if (!with->follow(here, &offset)) + return 0; + pos -= offset; + } + } + else { + pos = *curpos; + pos += motion; + } + p->move_by(pos); + pos += motion; + *curpos = pos; + return 1; +} + +class block_object : public rectangle_object { + object_list oblist; + PTABLE(place) *tbl; +public: + block_object(const position &, const object_list &ol, PTABLE(place) *t); + ~block_object(); + place *find_label(const char *); + object_type type(); + void move_by(const position &); + void print(); +}; + +block_object::block_object(const position &d, const object_list &ol, + PTABLE(place) *t) +: oblist(ol), tbl(t), rectangle_object(d) +{ +} + +block_object::~block_object() +{ + delete tbl; + object *p = oblist.head; + while (p != 0) { + object *tem = p; + p = p->next; + delete tem; + } +} + +void block_object::print() +{ + out->begin_block(south_west(), north_east()); + print_object_list(oblist.head); + out->end_block(); +} + +static void adjust_objectless_places(PTABLE(place) *tbl, const position &a) +{ + // Adjust all the labels that aren't attached to objects. + PTABLE_ITERATOR(place) iter(tbl); + const char *key; + place *pl; + while (iter.next(&key, &pl)) + if (key && csupper(key[0]) && pl->obj == 0) { + pl->x += a.x; + pl->y += a.y; + } +} + +void block_object::move_by(const position &a) +{ + cent += a; + for (object *p = oblist.head; p; p = p->next) + p->move_by(a); + adjust_objectless_places(tbl, a); +} + + +place *block_object::find_label(const char *name) +{ + return tbl->lookup(name); +} + +object_type block_object::type() +{ + return BLOCK_OBJECT; +} + +graphic_object *object_spec::make_block(position *curpos, direction *dirp) +{ + bounding_box bb; + for (object *p = oblist.head; p; p = p->next) + p->update_bounding_box(&bb); + position dim; + if (!bb.blank) { + position m = -(bb.ll + bb.ur)/2.0; + for (object *p = oblist.head; p; p = p->next) + p->move_by(m); + adjust_objectless_places(tbl, m); + dim = bb.ur - bb.ll; + } + if (flags & HAS_WIDTH) + dim.x = width; + if (flags & HAS_HEIGHT) + dim.y = height; + block_object *block = new block_object(dim, oblist, tbl); + if (!position_rectangle(block, curpos, dirp)) { + delete block; + block = 0; + } + tbl = 0; + oblist.head = oblist.tail = 0; + return block; +} + +class text_object : public rectangle_object { +public: + text_object(const position &); + object_type type() { return TEXT_OBJECT; } +}; + +text_object::text_object(const position &d) +: rectangle_object(d) +{ +} + +graphic_object *object_spec::make_text(position *curpos, direction *dirp) +{ + if (!(flags & HAS_HEIGHT)) { + lookup_variable("textht", &height); + int nitems = 0; + for (text_item *t = text; t; t = t->next) + nitems++; + height *= nitems; + } + if (!(flags & HAS_WIDTH)) + lookup_variable("textwid", &width); + text_object *p = new text_object(position(width, height)); + if (!position_rectangle(p, curpos, dirp)) { + delete p; + p = 0; + } + return p; +} + + +class ellipse_object : public closed_object { +public: + ellipse_object(const position &); + position north_east() { return position(cent.x + dim.x/(M_SQRT2*2.0), + cent.y + dim.y/(M_SQRT2*2.0)); } + position north_west() { return position(cent.x - dim.x/(M_SQRT2*2.0), + cent.y + dim.y/(M_SQRT2*2.0)); } + position south_east() { return position(cent.x + dim.x/(M_SQRT2*2.0), + cent.y - dim.y/(M_SQRT2*2.0)); } + position south_west() { return position(cent.x - dim.x/(M_SQRT2*2.0), + cent.y - dim.y/(M_SQRT2*2.0)); } + double radius() { return dim.x/2.0; } + object_type type() { return ELLIPSE_OBJECT; } + void print(); +}; + +ellipse_object::ellipse_object(const position &d) +: closed_object(d) +{ +} + +void ellipse_object::print() +{ + if (lt.type == line_type::invisible && fill < 0.0) + return; + out->ellipse(cent, dim, lt, fill); +} + +graphic_object *object_spec::make_ellipse(position *curpos, direction *dirp) +{ + static double last_ellipse_height; + static double last_ellipse_width; + static int have_last_ellipse = 0; + if (!(flags & HAS_HEIGHT)) { + if ((flags & IS_SAME) && have_last_ellipse) + height = last_ellipse_height; + else + lookup_variable("ellipseht", &height); + } + if (!(flags & HAS_WIDTH)) { + if ((flags & IS_SAME) && have_last_ellipse) + width = last_ellipse_width; + else + lookup_variable("ellipsewid", &width); + } + last_ellipse_width = width; + last_ellipse_height = height; + have_last_ellipse = 1; + ellipse_object *p = new ellipse_object(position(width, height)); + if (!position_rectangle(p, curpos, dirp)) { + delete p; + return 0; + } + return p; +} + +class circle_object : public ellipse_object { +public: + circle_object(double); + object_type type() { return CIRCLE_OBJECT; } + void print(); +}; + +circle_object::circle_object(double diam) +: ellipse_object(position(diam, diam)) +{ +} + +void circle_object::print() +{ + if (lt.type == line_type::invisible && fill < 0.0) + return; + out->circle(cent, dim.x/2.0, lt, fill); +} + +graphic_object *object_spec::make_circle(position *curpos, direction *dirp) +{ + static double last_circle_radius; + static int have_last_circle = 0; + if (!(flags & HAS_RADIUS)) { + if ((flags & IS_SAME) && have_last_circle) + radius = last_circle_radius; + else + lookup_variable("circlerad", &radius); + } + last_circle_radius = radius; + have_last_circle = 1; + circle_object *p = new circle_object(radius*2.0); + if (!position_rectangle(p, curpos, dirp)) { + delete p; + return 0; + } + return p; +} + +class move_object : public graphic_object { + position strt; + position en; +public: + move_object(const position &s, const position &e); + position origin() { return en; } + object_type type() { return MOVE_OBJECT; } + void update_bounding_box(bounding_box *); + void move_by(const position &); +}; + +move_object::move_object(const position &s, const position &e) +: strt(s), en(e) +{ +} + +void move_object::update_bounding_box(bounding_box *p) +{ + p->encompass(strt); + p->encompass(en); +} + +void move_object::move_by(const position &a) +{ + strt += a; + en += a; +} + +graphic_object *object_spec::make_move(position *curpos, direction *dirp) +{ + static position last_move; + static int have_last_move = 0; + *dirp = dir; + // No need to look at at since `at' attribute sets `from' attribute. + position startpos = (flags & HAS_FROM) ? from : *curpos; + if (!(flags & HAS_SEGMENT)) { + if ((flags && IS_SAME) && have_last_move) + segment_pos = last_move; + else { + switch (dir) { + case UP_DIRECTION: + segment_pos.y = segment_height; + break; + case DOWN_DIRECTION: + segment_pos.y = -segment_height; + break; + case LEFT_DIRECTION: + segment_pos.x = -segment_width; + break; + case RIGHT_DIRECTION: + segment_pos.x = segment_width; + break; + default: + assert(0); + } + } + } + segment_list = new segment(segment_pos, segment_is_absolute, segment_list); + // Reverse the segment_list so that it's in forward order. + segment *old = segment_list; + segment_list = 0; + while (old != 0) { + segment *tem = old->next; + old->next = segment_list; + segment_list = old; + old = tem; + } + // Compute the end position. + position endpos = startpos; + for (segment *s = segment_list; s; s = s->next) + if (s->is_absolute) + endpos = s->pos; + else + endpos += s->pos; + have_last_move = 1; + last_move = endpos - startpos; + move_object *p = new move_object(startpos, endpos); + *curpos = endpos; + return p; +} + +class linear_object : public graphic_object { +protected: + char arrow_at_start; + char arrow_at_end; + arrow_head_type aht; + position strt; + position en; +public: + linear_object(const position &s, const position &e); + position start() { return strt; } + position end() { return en; } + void move_by(const position &); + void update_bounding_box(bounding_box *) = 0; + object_type type() = 0; + void add_arrows(int at_start, int at_end, const arrow_head_type &); +}; + +class line_object : public linear_object { +protected: + position *v; + int n; +public: + line_object(const position &s, const position &e, position *, int); + ~line_object(); + position origin() { return strt; } + position center() { return (strt + en)/2.0; } + position north() { return (en.y - strt.y) > 0 ? en : strt; } + position south() { return (en.y - strt.y) < 0 ? en : strt; } + position east() { return (en.x - strt.x) > 0 ? en : strt; } + position west() { return (en.x - strt.x) < 0 ? en : strt; } + object_type type() { return LINE_OBJECT; } + void update_bounding_box(bounding_box *); + void print(); + void move_by(const position &); +}; + +class arrow_object : public line_object { +public: + arrow_object(const position &, const position &, position *, int); + object_type type() { return ARROW_OBJECT; } +}; + +class spline_object : public line_object { +public: + spline_object(const position &, const position &, position *, int); + object_type type() { return SPLINE_OBJECT; } + void print(); + void update_bounding_box(bounding_box *); +}; + +linear_object::linear_object(const position &s, const position &e) +: strt(s), en(e), arrow_at_start(0), arrow_at_end(0) +{ +} + +void linear_object::move_by(const position &a) +{ + strt += a; + en += a; +} + +void linear_object::add_arrows(int at_start, int at_end, + const arrow_head_type &a) +{ + arrow_at_start = at_start; + arrow_at_end = at_end; + aht = a; +} + +line_object::line_object(const position &s, const position &e, + position *p, int i) +: v(p), n(i), linear_object(s, e) +{ +} + +void line_object::print() +{ + if (lt.type == line_type::invisible) + return; + out->line(strt, v, n, lt); + if (arrow_at_start) + draw_arrow(strt, strt-v[0], aht, lt); + if (arrow_at_end) + draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt); +} + +void line_object::update_bounding_box(bounding_box *p) +{ + p->encompass(strt); + for (int i = 0; i < n; i++) + p->encompass(v[i]); +} + +void line_object::move_by(const position &pos) +{ + linear_object::move_by(pos); + for (int i = 0; i < n; i++) + v[i] += pos; +} + +void spline_object::update_bounding_box(bounding_box *p) +{ + p->encompass(strt); + p->encompass(en); + /* + + If + + p1 = q1/2 + q2/2 + p2 = q1/6 + q2*5/6 + p3 = q2*5/6 + q3/6 + p4 = q2/2 + q3/2 + [ the points for the Bezier cubic ] + + and + + t = .5 + + then + + (1-t)^3*p1 + 3*t*(t - 1)^2*p2 + 3*t^2*(1-t)*p3 + t^3*p4 + [ the equation for the Bezier cubic ] + + = .125*q1 + .75*q2 + .125*q3 + + */ + for (int i = 1; i < n; i++) + p->encompass((i == 1 ? strt : v[i-2])*.125 + v[i-1]*.75 + v[i]*.125); +} + +arrow_object::arrow_object(const position &s, const position &e, + position *p, int i) +: line_object(s, e, p, i) +{ +} + +spline_object::spline_object(const position &s, const position &e, + position *p, int i) +: line_object(s, e, p, i) +{ +} + +void spline_object::print() +{ + if (lt.type == line_type::invisible) + return; + out->spline(strt, v, n, lt); + if (arrow_at_start) + draw_arrow(strt, strt-v[0], aht, lt); + if (arrow_at_end) + draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt); +} + +line_object::~line_object() +{ + a_delete v; +} + +linear_object *object_spec::make_line(position *curpos, direction *dirp) +{ + static position last_line; + static int have_last_line = 0; + *dirp = dir; + // No need to look at at since `at' attribute sets `from' attribute. + position startpos = (flags & HAS_FROM) ? from : *curpos; + if (!(flags & HAS_SEGMENT)) { + if ((flags & IS_SAME) && (type == LINE_OBJECT || type == ARROW_OBJECT) + && have_last_line) + segment_pos = last_line; + else + switch (dir) { + case UP_DIRECTION: + segment_pos.y = segment_height; + break; + case DOWN_DIRECTION: + segment_pos.y = -segment_height; + break; + case LEFT_DIRECTION: + segment_pos.x = -segment_width; + break; + case RIGHT_DIRECTION: + segment_pos.x = segment_width; + break; + default: + assert(0); + } + } + segment_list = new segment(segment_pos, segment_is_absolute, segment_list); + // reverse the segment_list so that it's in forward order + segment *old = segment_list; + segment_list = 0; + while (old != 0) { + segment *tem = old->next; + old->next = segment_list; + segment_list = old; + old = tem; + } + // Absolutise all movements + position endpos = startpos; + int nsegments = 0; + for (segment *s = segment_list; s; s = s->next, nsegments++) + if (s->is_absolute) + endpos = s->pos; + else { + endpos += s->pos; + s->pos = endpos; + s->is_absolute = 1; // to avoid confusion + } + // handle chop + line_object *p = 0; + position *v = new position[nsegments]; + int i = 0; + for (s = segment_list; s; s = s->next, i++) + v[i] = s->pos; + if (flags & IS_DEFAULT_CHOPPED) { + lookup_variable("circlerad", &start_chop); + end_chop = start_chop; + flags |= IS_CHOPPED; + } + if (flags & IS_CHOPPED) { + position start_chop_vec, end_chop_vec; + if (start_chop != 0.0) { + start_chop_vec = v[0] - startpos; + start_chop_vec *= start_chop / hypot(start_chop_vec); + } + if (end_chop != 0.0) { + end_chop_vec = (v[nsegments - 1] + - (nsegments > 1 ? v[nsegments - 2] : startpos)); + end_chop_vec *= end_chop / hypot(end_chop_vec); + } + startpos += start_chop_vec; + v[nsegments - 1] -= end_chop_vec; + endpos -= end_chop_vec; + } + switch (type) { + case SPLINE_OBJECT: + p = new spline_object(startpos, endpos, v, nsegments); + break; + case ARROW_OBJECT: + p = new arrow_object(startpos, endpos, v, nsegments); + break; + case LINE_OBJECT: + p = new line_object(startpos, endpos, v, nsegments); + break; + default: + assert(0); + } + have_last_line = 1; + last_line = endpos - startpos; + *curpos = endpos; + return p; +} + +class arc_object : public linear_object { + int clockwise; + position cent; + double rad; +public: + arc_object(int, const position &, const position &, const position &); + position origin() { return cent; } + position center() { return cent; } + double radius() { return rad; } + position north(); + position south(); + position east(); + position west(); + position north_east(); + position north_west(); + position south_east(); + position south_west(); + void update_bounding_box(bounding_box *); + object_type type() { return ARC_OBJECT; } + void print(); + void move_by(const position &pos); +}; + +arc_object::arc_object(int cw, const position &s, const position &e, + const position &c) +: linear_object(s, e), clockwise(cw), cent(c) +{ + rad = hypot(c - s); +} + +void arc_object::move_by(const position &pos) +{ + linear_object::move_by(pos); + cent += pos; +} + +// we get arc corners from the corresponding circle + +position arc_object::north() +{ + position result(cent); + result.y += rad; + return result; +} + +position arc_object::south() +{ + position result(cent); + result.y -= rad; + return result; +} + +position arc_object::east() +{ + position result(cent); + result.x += rad; + return result; +} + +position arc_object::west() +{ + position result(cent); + result.x -= rad; + return result; +} + +position arc_object::north_east() +{ + position result(cent); + result.x += rad/M_SQRT2; + result.y += rad/M_SQRT2; + return result; +} + +position arc_object::north_west() +{ + position result(cent); + result.x -= rad/M_SQRT2; + result.y += rad/M_SQRT2; + return result; +} + +position arc_object::south_east() +{ + position result(cent); + result.x += rad/M_SQRT2; + result.y -= rad/M_SQRT2; + return result; +} + +position arc_object::south_west() +{ + position result(cent); + result.x -= rad/M_SQRT2; + result.y -= rad/M_SQRT2; + return result; +} + + +void arc_object::print() +{ + if (lt.type == line_type::invisible) + return; + if (clockwise) + out->arc(en, cent, strt, lt); + else + out->arc(strt, cent, en, lt); + if (arrow_at_start) { + position c = cent - strt; + draw_arrow(strt, + (clockwise ? position(c.y, -c.x) : position(-c.y, c.x)), + aht, lt); + } + if (arrow_at_end) { + position e = en - cent; + draw_arrow(en, + (clockwise ? position(e.y, -e.x) : position(-e.y, e.x)), + aht, lt); + } +} + +inline double max(double a, double b) +{ + return a > b ? a : b; +} + +void arc_object::update_bounding_box(bounding_box *p) +{ + p->encompass(strt); + p->encompass(en); + position start_offset = strt - cent; + if (start_offset.x == 0.0 && start_offset.y == 0.0) + return; + position end_offset = en - cent; + if (end_offset.x == 0.0 && end_offset.y == 0.0) + return; + double start_quad = atan2(start_offset.y, start_offset.x)/(M_PI/2.0); + double end_quad = atan2(end_offset.y, end_offset.x)/(M_PI/2.0); + if (clockwise) { + double temp = start_quad; + start_quad = end_quad; + end_quad = temp; + } + if (start_quad < 0.0) + start_quad += 4.0; + while (end_quad <= start_quad) + end_quad += 4.0; + double radius = max(hypot(start_offset), hypot(end_offset)); + for (int q = int(start_quad) + 1; q < end_quad; q++) { + position offset; + switch (q % 4) { + case 0: + offset.x = radius; + break; + case 1: + offset.y = radius; + break; + case 2: + offset.x = -radius; + break; + case 3: + offset.y = -radius; + break; + } + p->encompass(cent + offset); + } +} + +// We ignore the with attribute. The at attribute always refers to the center. + +linear_object *object_spec::make_arc(position *curpos, direction *dirp) +{ + *dirp = dir; + int cw = (flags & IS_CLOCKWISE) != 0; + // compute the start + position startpos; + if (flags & HAS_FROM) + startpos = from; + else + startpos = *curpos; + if (!(flags & HAS_RADIUS)) + lookup_variable("arcrad", &radius); + // compute the end + position endpos; + if (flags & HAS_TO) + endpos = to; + else { + position m(radius, radius); + // Adjust the signs. + if (cw) { + if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION) + m.x = -m.x; + if (dir == DOWN_DIRECTION || dir == RIGHT_DIRECTION) + m.y = -m.y; + *dirp = direction((dir + 3) % 4); + } + else { + if (dir == UP_DIRECTION || dir == LEFT_DIRECTION) + m.x = -m.x; + if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION) + m.y = -m.y; + *dirp = direction((dir + 1) % 4); + } + endpos = startpos + m; + } + // compute the center + position centerpos; + if (flags & HAS_AT) + centerpos = at; + else if (startpos == endpos) + centerpos = startpos; + else { + position h = (endpos - startpos)/2.0; + double d = hypot(h); + if (radius <= 0) + radius = .25; + // make the radius big enough + while (radius < d) + radius *= 2.0; + double alpha = acos(d/radius); + double theta = atan2(h.y, h.x); + if (cw) + theta -= alpha; + else + theta += alpha; + centerpos = position(cos(theta), sin(theta))*radius + startpos; + } + arc_object *p = new arc_object(cw, startpos, endpos, centerpos); + *curpos = endpos; + return p; +} + +graphic_object *object_spec::make_linear(position *curpos, direction *dirp) +{ + linear_object *obj; + if (type == ARC_OBJECT) + obj = make_arc(curpos, dirp); + else + obj = make_line(curpos, dirp); + if (type == ARROW_OBJECT + && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD)) == 0) + flags |= HAS_RIGHT_ARROW_HEAD; + if (obj && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD))) { + arrow_head_type a; + int at_start = (flags & HAS_LEFT_ARROW_HEAD) != 0; + int at_end = (flags & HAS_RIGHT_ARROW_HEAD) != 0; + if (flags & HAS_HEIGHT) + a.height = height; + else + lookup_variable("arrowht", &a.height); + if (flags & HAS_WIDTH) + a.width = width; + else + lookup_variable("arrowwid", &a.width); + double solid; + lookup_variable("arrowhead", &solid); + a.solid = solid != 0.0; + obj->add_arrows(at_start, at_end, a); + } + return obj; +} + +object *object_spec::make_object(position *curpos, direction *dirp) +{ + graphic_object *obj = 0; + switch (type) { + case BLOCK_OBJECT: + obj = make_block(curpos, dirp); + break; + case BOX_OBJECT: + obj = make_box(curpos, dirp); + break; + case TEXT_OBJECT: + obj = make_text(curpos, dirp); + break; + case ELLIPSE_OBJECT: + obj = make_ellipse(curpos, dirp); + break; + case CIRCLE_OBJECT: + obj = make_circle(curpos, dirp); + break; + case MOVE_OBJECT: + obj = make_move(curpos, dirp); + break; + case ARC_OBJECT: + case LINE_OBJECT: + case SPLINE_OBJECT: + case ARROW_OBJECT: + obj = make_linear(curpos, dirp); + break; + case MARK_OBJECT: + case OTHER_OBJECT: + default: + assert(0); + break; + } + if (obj) { + if (flags & IS_INVISIBLE) + obj->set_invisible(); + if (text != 0) + obj->add_text(text, (flags & IS_ALIGNED) != 0); + if (flags & IS_DOTTED) + obj->set_dotted(dash_width); + else if (flags & IS_DASHED) + obj->set_dashed(dash_width); + double th; + if (flags & HAS_THICKNESS) + th = thickness; + else + lookup_variable("linethick", &th); + obj->set_thickness(th); + if (flags & (IS_DEFAULT_FILLED|IS_FILLED)) { + if (flags & IS_DEFAULT_FILLED) + lookup_variable("fillval", &fill); + if (fill < 0.0) + error("bad fill value %1", fill); + else + obj->set_fill(fill); + } + } + return obj; +} + +struct string_list { + string_list *next; + char *str; + string_list(char *); + ~string_list(); +}; + +string_list::string_list(char *s) +: next(0), str(s) +{ +} + +string_list::~string_list() +{ + a_delete str; +} + +/* A path is used to hold the argument to the with attribute. For example, +`.nw' or `.A.s' or `.A'. The major operation on a path is to take a +place and follow the path through the place to place within the place. +Note that `.A.B.C.sw' will work. */ + +path::path(corner c) +: label_list(0), crn(c) +{ +} + +path::path(char *l, corner c) +: crn(c) +{ + label_list = new string_list(l); +} + +path::~path() +{ + while (label_list) { + string_list *tem = label_list; + label_list = label_list->next; + delete tem; + } +} + +void path::append(corner c) +{ + assert(crn == 0); + crn = c; +} + +void path::append(char *s) +{ + for (string_list **p = &label_list; *p; p = &(*p)->next) + ; + *p = new string_list(s); +} + +// return non-zero for success + +int path::follow(const place &pl, place *result) const +{ + const place *p = &pl; + for (string_list *lb = label_list; lb; lb = lb->next) + if (p->obj == 0 || (p = p->obj->find_label(lb->str)) == 0) { + lex_error("object does not contain a place `%1'", lb->str); + return 0; + } + if (crn == 0 || p->obj == 0) + *result = *p; + else { + position pos = ((p->obj)->*(crn))(); + result->x = pos.x; + result->y = pos.y; + result->obj = 0; + } + return 1; +} + +void print_object_list(object *p) +{ + for (; p; p = p->next) { + p->print(); + p->print_text(); + } +} + +void print_picture(object *obj) +{ + bounding_box bb; + for (object *p = obj; p; p = p->next) + p->update_bounding_box(&bb); + double scale; + lookup_variable("scale", &scale); + out->start_picture(scale, bb.ll, bb.ur); + print_object_list(obj); + out->finish_picture(); +} + diff --git a/gnu/usr.bin/groff/pic/object.h b/gnu/usr.bin/groff/pic/object.h new file mode 100644 index 0000000000..39240b634f --- /dev/null +++ b/gnu/usr.bin/groff/pic/object.h @@ -0,0 +1,215 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct place; + +enum object_type { + OTHER_OBJECT, + BOX_OBJECT, + CIRCLE_OBJECT, + ELLIPSE_OBJECT, + ARC_OBJECT, + SPLINE_OBJECT, + LINE_OBJECT, + ARROW_OBJECT, + MOVE_OBJECT, + TEXT_OBJECT, + BLOCK_OBJECT, + MARK_OBJECT + }; + +struct bounding_box; + +struct object { + object *prev; + object *next; + object(); + virtual ~object(); + virtual position origin(); + virtual double width(); + virtual double radius(); + virtual double height(); + virtual position north(); + virtual position south(); + virtual position east(); + virtual position west(); + virtual position north_east(); + virtual position north_west(); + virtual position south_east(); + virtual position south_west(); + virtual position start(); + virtual position end(); + virtual position center(); + virtual place *find_label(const char *); + virtual void move_by(const position &); + virtual int blank(); + virtual void update_bounding_box(bounding_box *); + virtual object_type type() = 0; + virtual void print(); + virtual void print_text(); +}; + +typedef position (object::*corner)(); + +struct place { + object *obj; + double x, y; +}; + +struct string_list; + +class path { + corner crn; + string_list *label_list; +public: + path(corner = 0); + path(char *, corner = 0); + ~path(); + void append(corner); + void append(char *); + int follow(const place &, place *) const; +}; + +struct object_list { + object *head; + object *tail; + object_list(); + void append(object *); + void wrap_up_block(object_list *); +}; + +declare_ptable(place) + +// these go counterclockwise +enum direction { + RIGHT_DIRECTION, + UP_DIRECTION, + LEFT_DIRECTION, + DOWN_DIRECTION + }; + +struct graphics_state { + double x, y; + direction dir; +}; + +struct saved_state : graphics_state { + saved_state *prev; + PTABLE(place) *tbl; +}; + + +struct text_item { + text_item *next; + char *text; + adjustment adj; + const char *filename; + int lineno; + + text_item(char *, const char *, int); + ~text_item(); +}; + +const unsigned long IS_DOTTED = 01; +const unsigned long IS_DASHED = 02; +const unsigned long IS_CLOCKWISE = 04; +const unsigned long IS_INVISIBLE = 020; +const unsigned long HAS_LEFT_ARROW_HEAD = 040; +const unsigned long HAS_RIGHT_ARROW_HEAD = 0100; +const unsigned long HAS_SEGMENT = 0200; +const unsigned long IS_SAME = 0400; +const unsigned long HAS_FROM = 01000; +const unsigned long HAS_AT = 02000; +const unsigned long HAS_WITH = 04000; +const unsigned long HAS_HEIGHT = 010000; +const unsigned long HAS_WIDTH = 020000; +const unsigned long HAS_RADIUS = 040000; +const unsigned long HAS_TO = 0100000; +const unsigned long IS_CHOPPED = 0200000; +const unsigned long IS_DEFAULT_CHOPPED = 0400000; +const unsigned long HAS_THICKNESS = 01000000; +const unsigned long IS_FILLED = 02000000; +const unsigned long IS_DEFAULT_FILLED = 04000000; +const unsigned long IS_ALIGNED = 010000000; + +struct segment { + int is_absolute; + position pos; + segment *next; + segment(const position &, int, segment *); +}; + +struct rectangle_object; +struct graphic_object; +struct linear_object; + +struct object_spec { + unsigned long flags; + object_type type; + object_list oblist; + PTABLE(place) *tbl; + double dash_width; + position from; + position to; + position at; + position by; + path *with; + text_item *text; + double height; + double radius; + double width; + double segment_width; + double segment_height; + double start_chop; + double end_chop; + double thickness; + double fill; + direction dir; + segment *segment_list; + position segment_pos; + int segment_is_absolute; + + object_spec(object_type); + ~object_spec(); + object *make_object(position *, direction *); + graphic_object *make_box(position *, direction *); + graphic_object *make_block(position *, direction *); + graphic_object *make_text(position *, direction *); + graphic_object *make_ellipse(position *, direction *); + graphic_object *make_circle(position *, direction *); + linear_object *make_line(position *, direction *); + linear_object *make_arc(position *, direction *); + graphic_object *make_linear(position *, direction *); + graphic_object *make_move(position *, direction *); + int position_rectangle(rectangle_object *p, position *curpos, + direction *dirp); +}; + + +object *make_object(object_spec *, position *, direction *); + +object *make_mark_object(); +object *make_command_object(char *, const char *, int); + +int lookup_variable(const char *name, double *val); +void define_variable(const char *name, double val); + +void print_picture(object *); + diff --git a/gnu/usr.bin/groff/pic/output.h b/gnu/usr.bin/groff/pic/output.h new file mode 100644 index 0000000000..ddcc4b5bf7 --- /dev/null +++ b/gnu/usr.bin/groff/pic/output.h @@ -0,0 +1,79 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct line_type { + enum { invisible, solid, dotted, dashed } type; + double dash_width; + double thickness; // the thickness is in points + + line_type(); +}; + + +class output { +protected: + char *args; + double desired_height; // zero if no height specified + double desired_width; // zero if no depth specified + double compute_scale(double, const position &, const position &); +public: + output(); + virtual ~output(); + void set_desired_width_height(double wid, double ht); + void set_args(const char *); + virtual void start_picture(double sc, const position &ll, const position &ur) = 0; + virtual void finish_picture() = 0; + virtual void circle(const position &, double rad, + const line_type &, double) = 0; + virtual void text(const position &, text_piece *, int, double) = 0; + virtual void line(const position &, const position *, int n, + const line_type &) = 0; + virtual void polygon(const position *, int n, + const line_type &, double) = 0; + virtual void spline(const position &, const position *, int n, + const line_type &) = 0; + virtual void arc(const position &, const position &, const position &, + const line_type &) = 0; + virtual void ellipse(const position &, const distance &, + const line_type &, double) = 0; + virtual void rounded_box(const position &, const distance &, double, + const line_type &, double) = 0; + virtual void command(const char *, const char *, int); + virtual void set_location(const char *, int); + virtual int supports_filled_polygons(); + virtual void begin_block(const position &ll, const position &ur); + virtual void end_block(); +}; + +extern output *out; + +/* #define FIG_SUPPORT 1 */ +#define TEX_SUPPORT 1 + +output *make_troff_output(); + +#ifdef TEX_SUPPORT +output *make_tex_output(); +output *make_tpic_output(); +#endif /* TEX_SUPPORT */ + +#ifdef FIG_SUPPORT +output *make_fig_output(); +#endif /* FIG_SUPPORT */ diff --git a/gnu/usr.bin/groff/pic/pic.1 b/gnu/usr.bin/groff/pic/pic.1 new file mode 100644 index 0000000000..3b0345b953 --- /dev/null +++ b/gnu/usr.bin/groff/pic/pic.1 @@ -0,0 +1,730 @@ +.\" -*- nroff -*- +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X +.el .ds tx TeX +.ie \n(.g .ds ic \/ +.el .ds ic \^ +.\" The BSD man macros can't handle " in arguments to font change macros, +.\" so use \(ts instead of ". +.tr \(ts" +.TH PIC 1 "9 August 1992" "Groff Version 1.08" +.SH NAME +pic \- compile pictures for troff or TeX +.SH SYNOPSIS +.B pic +[ +.B \-nvC +] +[ +.I filename +\&.\|.\|. +] +.br +.B pic +.B \-t +[ +.B \-cvzC +] +[ +.I filename +\&.\|.\|. +] +.SH DESCRIPTION +.LP +This manual page descibes the GNU version of +.BR pic , +which is part of the groff document formatting system. +.B pic +compiles descriptions of pictures embedded within +.B troff +or \*(tx input files into commands that are understood by \*(tx or +.BR troff . +Each picture starts with a line beginning with +.B .PS +and ends with a line beginning with +.BR .PE . +Anything outside of +.B .PS +and +.B .PE +is passed through without change. +.LP +It is the user's responsibility to provide appropriate definitions of the +.B PS +and +.B PE +macros. +When the macro package being used does not supply such definitions +(for example, old versions of \-ms), +appropriate definitions can be obtained with +.BR \-mpic : +these will center each picture. +.SH OPTIONS +.LP +Options that do not take arguments may be grouped behind a single +.BR \- . +The special option +.B \-\^\- +can be used to mark the end of the options. +A filename of +.B \- +refers to the standard input. +.TP +.B \-C +Recognize +.B .PS +and +.B .PE +even when followed by a character other than space or newline. +.TP +.B \-n +Don't use the groff extensions to the troff drawing commands. +You should use this if you are using a postprocessor that doesn't support +these extensions. +The extensions are described in +.BR groff_out (5). +The +.B \-n +option also causes pic +not to use zero-length lines to draw dots in troff mode. +.TP +.B \-t +\*(tx mode. +.TP +.B \-c +Be more compatible with +.BR tpic . +Implies +.BR \-t . +Lines beginning with +.B \e +are not passed through transparently. +Lines beginning with +.B . +are passed through with the initial +.B . +changed to +.BR \e . +A line beginning with +.B .ps +is given special treatment: +it takes an optional integer argument specifying +the line thickness (pen size) in milliinches; +a missing argument restores the previous line thickness; +the default line thickness is 8 milliinches. +The line thickness thus specified takes effect only +when a non-negative line thickness has not been +specified by use of the +.B thickness +attribute or by setting the +.B linethick +variable. +.TP +.B \-v +Print the version number. +.TP +.B \-z +In \*(tx mode draw dots using zero-length lines. +.LP +The following options supported by other versions of +.B pic +are ignored: +.TP +.B \-D +Draw all lines using the \eD escape sequence. +.B pic +always does this. +.TP +.BI \-T \ dev +Generate output for the +.B troff +device +.IR dev . +This is unnecessary because the +.B troff +output generated by +.B pic +is device-independent. +.SH USAGE +This section describes only the differences between GNU pic and the original +version of pic. +Many of these differences also apply to newer versions of Unix pic. +.SS \*(tx mode +.LP +\*(tx mode is enabled by the +.B \-t +option. +In \*(tx mode, pic will define a vbox called +.B \egraph +for each picture. +You must yourself print that vbox using, for example, the command +.RS +.LP +.B +\ecenterline{\ebox\egraph} +.RE +.LP +Actually, since the vbox has a height of zero this will produce +slightly more vertical space above the picture than below it; +.RS +.LP +.B +\ecenterline{\eraise 1em\ebox\egraph} +.RE +.LP +would avoid this. +.LP +You must use a \*(tx driver that supports the +.B tpic +specials, version 2. +.LP +Lines beginning with +.B \e +are passed through transparently; a +.B % +is added to the end of the line to avoid unwanted spaces. +You can safely use this feature to change fonts or to +change the value of +.BR \ebaselineskip . +Anything else may well produce undesirable results; use at your own risk. +Lines beginning with a period are not given any special treatment. +.SS Commands +.TP +\fBfor\fR \fIvariable\fR \fB=\fR \fIexpr1\fR \fBto\fR \fIexpr2\fR \ +[\fBby\fR [\fB*\fR]\fIexpr3\fR] \fBdo\fR \fIX\fR \fIbody\fR \fIX\fR +Set +.I variable +to +.IR expr1 . +While the value of +.I variable +is less than or equal to +.IR expr2 , +do +.I body +and increment +.I variable +by +.IR expr3 ; +if +.B by +is not given, increment +.I variable +by 1. +If +.I expr3 +is prefixed by +.B * +then +.I variable +will instead be multiplied by +.IR expr3 . +.I X +can be any character not occurring in +.IR body . +.TP +\fBif\fR \fIexpr\fR \fBthen\fR \fIX\fR \fIif-true\fR \fIX\fR \ +[\fBelse\fR \fIY\fR \fIif-false\fR \fIY\fR] +Evaluate +.IR expr ; +if it is non-zero then do +.IR if-true , +otherwise do +.IR if-false . +.I X +can be any character not occurring in +.IR if-true . +.I Y +can be any character not occurring in +.IR if-false . +.TP +\fBprint\fR \fIarg\fR\|.\|.\|. +Concatenate the arguments and print as a line on stderr. +Each +.I arg +must be an expression, a position, or text. +This is useful for debugging. +.TP +\fBcommand\fR \fIarg\fR\|.\|.\|. +Concatenate the arguments +and pass them through as a line to troff or\*(tx. +Each +.I arg +must be an expression, a position, or text. +This has a similar effect to a line beginning with +.B . +or +.BR \e , +but allows the values of variables to be passed through. +.TP +\fBsh\fR \fIX\fR \fIcommand\fR \fIX\fR +Pass +.I command +to a shell. +.I X +can be any character not occurring in +.IR command . +.TP +\fBcopy\fR \fB"\fIfilename\fB"\fR +Include +.I filename +at this point in the file. +.TP +\fBcopy\fR [\fB"\fIfilename\fB"\fR] \fBthru\fR \fIX\fR \fIbody\fR \fIX\fR \ +[\fBuntil\fR \fB"\fIword\*(ic\fB"\fR] +.ns +.TP +\fBcopy\fR [\fB"\fIfilename\fB"\fR] \fBthru\fR \fImacro\fR \ +[\fBuntil\fR \fB"\fIword\*(ic\fB"\fR] +This construct does +.I body +once for each line of +.IR filename ; +the line is split into blank-delimited words, +and occurrences of +.BI $ i +in +.IR body , +for +.I i +between 1 and 9, +are replaced by the +.IR i -th +word of the line. +If +.I filename +is not given, lines are taken from the current input up to +.BR .PE . +If an +.B until +clause is specified, +lines will be read only until a line the first word of which is +.IR word ; +that line will then be discarded. +.I X +can be any character not occurring in +.IR body . +For example, +.RS +.IP +.ft B +.nf +\&.PS +copy thru % circle at ($1,$2) % until "END" +1 2 +3 4 +5 6 +END +box +\&.PE +.ft +.fi +.RE +.IP +is equivalent to +.RS +.IP +.ft B +.nf +\&.PS +circle at (1,2) +circle at (3,4) +circle at (5,6) +box +\&.PE +.ft +.fi +.RE +.IP +The commands to be performed for each line can also be taken +from a macro defined earlier by giving the name of the macro +as the argument to +.BR thru . +.LP +.B reset +.br +.ns +.TP +\fBreset\fI variable1\fB,\fI variable2 .\^.\^. +Reset pre-defined variables +.IR variable1 , +.I variable2 +\&.\^.\^. to their default values. +If no arguments are given, reset all pre-defined variables +to their default values. +Note that assigning a value to +.B scale +also causes all pre-defined variables that control dimensions +to be reset to their default values times the new value of scale. +.TP +\fBplot\fR \fIexpr\fR [\fB"\fItext\*(ic\fB"\fR] +This is a text object which is constructed by using +.I text +as a format string for sprintf +with an argument of +.IR expr . +If +.I text +is omitted a format string of +.B "\(ts%g\(ts" +is used. +Attributes can be specified in the same way as for a normal text +object. +Be very careful that you specify an appropriate format string; +pic does only very limited checking of the string. +This is deprecated in favour of +.BR sprintf . +.TP +.IB variable := expr +This is similar to +.B = +except +.I variable +must already be defined, +and the value of +.I variable +will be changed only in the innermost block in which it is defined. +(By contrast, +.B = +defines the variable in the current block if it is not already defined there, +and then changes the value in the current block.) +.LP +Arguments of the form +.IP +.IR X\ anything\ X +.LP +are also allowed to be of the form +.IP +.BI {\ anything\ } +.LP +In this case +.I anything +can contain balanced occurrences of +.B { +and +.BR } . +Strings may contain +.I X +or imbalanced occurrences of +.B { +and +.BR } . +.SS Expressions +The syntax for expressions has been significantly extended: +.LP +.IB x\ ^\ y +(exponentiation) +.br +.BI sin( x ) +.br +.BI cos( x ) +.br +.BI atan2( y , \ x ) +.br +.BI log( x ) +(base 10) +.br +.BI exp( x ) +(base 10, ie 10\v'-.4m'\fIx\*(ic\fR\v'.4m') +.br +.BI sqrt( x ) +.br +.BI int( x ) +.br +.B rand() +(return a random number between 0 and 1) +.br +.BI rand( x ) +(return a random number between 1 and +.IR x ; +deprecated) +.br +.BI max( e1 , \ e2 ) +.br +.BI min( e1 , \ e2 ) +.br +.BI ! e +.br +\fIe1\fB && \fIe2\fR +.br +\fIe1\fB || \fIe2\fR +.br +\fIe1\fB == \fIe2\fR +.br +\fIe1\fB != \fIe2\fR +.br +\fIe1\fB >= \fIe2\fR +.br +\fIe1\fB > \fIe2\fR +.br +\fIe1\fB <= \fIe2\fR +.br +\fIe1\fB < \fIe2\fR +.br +\fB"\fIstr1\*(ic\fB" == "\fIstr2\*(ic\fB"\fR +.br +\fB"\fIstr1\*(ic\fB" != "\fIstr2\*(ic\fB"\fR +.br +.LP +String comparison expressions must be parenthesised in some contexts +to avoid ambiguity. +.SS Other Changes +.LP +A bare expression, +.IR expr , +is acceptable as an attribute; +it is equivalent to +.IR dir\ expr , +where +.I dir +is the current direction. +For example +.IP +.B line 2i +.LP +means draw a line 2 inches long in the current direction. +.LP +The maximum width and height of the picture are taken from the variables +.B maxpswid +and +.BR maxpsht . +Initially these have values 8.5 and 11. +.LP +Scientific notation is allowed for numbers. +For example +.RS +.B +x = 5e\-2 +.RE +.LP +Text attributes can be compounded. +For example, +.RS +.B +"foo" above ljust +.RE +is legal. +.LP +There is no limit to the depth to which blocks can be examined. +For example, +.RS +.B +[A: [B: [C: box ]]] with .A.B.C.sw at 1,2 +.br +.B +circle at last [\^].A.B.C +.RE +is acceptable. +.LP +Arcs now have compass points +determined by the circle of which the arc is a part. +.LP +Circles and arcs can be dotted or dashed. +In \*(tx mode splines can be dotted or dashed. +.LP +Boxes can have rounded corners. +The +.B rad +attribute specifies the radius of the quarter-circles at each corner. +If no +.B rad +or +.B diam +attribute is given, a radius of +.B boxrad +is used. +Initially, +.B boxrad +has a value of 0. +A box with rounded corners can be dotted or dashed. +.LP +The +.B .PS +line can have a second argument specifying a maximum height for +the picture. +If the width of zero is specified the width will be ignored in computing +the scaling factor for the picture. +Note that GNU pic will always scale a picture by the same amount +vertically as horizontally. +This is different from the +.SM DWB +2.0 pic which may scale a picture by a +different amount vertically than horizontally if a height is +specified. +.LP +Each text object has an invisible box associated with it. +The compass points of a text object are determined by this box. +The implicit motion associated with the object is also determined +by this box. +The dimensions of this box are taken from the width and height attributes; +if the width attribute is not supplied then the width will be taken to be +.BR textwid ; +if the height attribute is not supplied then the height will be taken to be +the number of text strings associated with the object +times +.BR textht . +Initially +.B textwid +and +.B textht +have a value of 0. +.LP +In places where a quoted text string can be used, +an expression of the form +.IP +.BI sprintf(\(ts format \(ts,\ arg ,\fR.\|.\|.\fB) +.LP +can also be used; +this will produce the arguments formatted according to +.IR format , +which should be a string as described in +.BR printf (3) +appropriate for the number of arguments supplied, +using only the +.BR e , +.BR f , +.B g +or +.B % +format characters. +.LP +The thickness of the lines used to draw objects is controlled by the +.B linethick +variable. +This gives the thickness of lines in points. +A negative value means use the default thickness: +in \*(tx output mode, this means use a thickness of 8 milliinches; +in \*(tx output mode with the +.B -c +option, this means use the line thickness specified by +.B .ps +lines; +in troff output mode, this means use a thickness proportional +to the pointsize. +A zero value means draw the thinnest possible line supported by +the output device. +Initially it has a value of -1. +There is also a +.BR thick [ ness ] +attribute. +For example, +.RS +.LP +.B circle thickness 1.5 +.RE +.LP +would draw a circle using a line with a thickness of 1.5 points. +The thickness of lines is not affected by the +value of the +.B scale +variable, nor by the width or height given in the +.B .PS +line. +.LP +Boxes (including boxes with rounded corners), +circles and ellipses can be filled by giving then an attribute of +.BR fill [ ed ]. +This takes an optional argument of an expression with a value between +0 and 1; 0 will fill it with white, 1 with black, values in between +with a proportionally gray shade. +A value greater than 1 can also be used: +this means fill with the +shade of gray that is currently being used for text and lines. +Normally this will be black, but output devices may provide +a mechanism for changing this. +Without an argument, then the value of the variable +.B fillval +will be used. +Initially this has a value of 0.5. +The invisible attribute does not affect the filling of objects. +Any text associated with a filled object will be added after the +object has been filled, so that the text will not be obscured +by the filling. +.LP +Arrow heads will be drawn as solid triangles if the variable +.B arrowhead +is non-zero and either \*(tx mode is enabled or +the +.B \-x +option has been given. +Initially +.B arrowhead +has a value of 1. +.LP +The troff output of pic is device-independent. +The +.B \-T +option is therefore redundant. +All numbers are taken to be in inches; numbers are never interpreted +to be in troff machine units. +.LP +Objects can have an +.B aligned +attribute. +This will only work when the postprocessor is +.BR grops . +Any text associated with an object having the +.B aligned +attribute will be rotated about the center of the object +so that it is aligned in the direction from the start point +to the end point of the object. +Note that this attribute will have no effect for objects whose start and +end points are coincident. +.LP +In places where +.IB n th +is allowed +.BI ` expr 'th +is also allowed. +Note that +.B 'th +is a single token: no space is allowed between the +.B ' +and the +.BR th . +For example, +.IP +.B +.nf +for i = 1 to 4 do { + line from `i'th box.nw to `i+1'th box.se +} +.fi +.SH FILES +.Tp \w'\fB/usr/share/tmac/tmac.pic'u+3n +.B +/usr/share/tmac/tmac.pic +Example definitions of the +.B PS +and +.B PE +macros. +.SH "SEE ALSO" +.BR troff (1), +.BR groff_out (5), +.BR tex (1) +.br +Tpic: Pic for \*(tx +.br +AT&T Bell Laboratories, Computing Science Technical Report No.\ 116, +PIC \(em A Graphics Language for Typesetting. +(This can be obtained by sending a mail message to netlib@research.att.com +with a body of `send\ 116\ from\ research/cstr'.) +.SH BUGS +.LP +Input characters that are illegal for +.B groff +(ie those with +.SM ASCII +code 0 or between 013 and 037 octal or between 0200 and 0237 octal) +are rejected even in \*(tx mode. +.LP +The interpretation of +.B fillval +is incompatible with the pic in 10th edition Unix, +which interprets 0 as black and 1 as white. diff --git a/gnu/usr.bin/groff/pic/pic.h b/gnu/usr.bin/groff/pic/pic.h new file mode 100644 index 0000000000..30c2cd5a1e --- /dev/null +++ b/gnu/usr.bin/groff/pic/pic.h @@ -0,0 +1,101 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +extern "C" { + double hypot(double, double); +} + +#include "assert.h" +#include "cset.h" +#include "lib.h" +#include "stringclass.h" +#include "errarg.h" +#include "error.h" +#include "position.h" +#include "text.h" +#include "output.h" + +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +class input { + input *next; +public: + input(); + virtual ~input(); + virtual int get() = 0; + virtual int peek() = 0; + virtual int get_location(const char **, int *); + friend class input_stack; + friend class copy_rest_thru_input; +}; + +class file_input : public input { + FILE *fp; + const char *filename; + int lineno; + string line; + const char *ptr; + int read_line(); +public: + file_input(FILE *, const char *); + ~file_input(); + int get(); + int peek(); + int get_location(const char **, int *); +}; + +void lex_init(input *); +int get_location(char **, int *); + +void do_copy(const char *file); +void parse_init(); +void parse_cleanup(); + +void lex_error(const char *message, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +void lex_warning(const char *message, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +void lex_cleanup(); + +extern int flyback_flag; +extern int command_char; +// zero_length_line_flag is non-zero if zero-length lines are drawn +// as dots by the output device +extern int zero_length_line_flag; +extern int driver_extension_flag; +extern int compatible_flag; diff --git a/gnu/usr.bin/groff/pic/pic.y b/gnu/usr.bin/groff/pic/pic.y new file mode 100644 index 0000000000..8c0405ffe4 --- /dev/null +++ b/gnu/usr.bin/groff/pic/pic.y @@ -0,0 +1,1780 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +%{ +#include "pic.h" +#include "ptable.h" +#include "object.h" + +extern int delim_flag; +extern void do_copy(const char *); +extern void copy_rest_thru(const char *, const char *); +extern void copy_file_thru(const char *, const char *, const char *); +extern void push_body(const char *); +extern void do_for(char *var, double from, double to, + int by_is_multiplicative, double by, char *body); +extern void do_lookahead(); + +#undef fmod +#undef rand + +extern "C" { + double fmod(double, double); + int rand(); +} + +/* Maximum number of characters produced by printf("%g") */ +#define GDIGITS 14 + +int yylex(); +void yyerror(const char *); + +void reset(const char *nm); +void reset_all(); + +place *lookup_label(const char *); +void define_label(const char *label, const place *pl); + +direction current_direction; +position current_position; + +implement_ptable(place) + +PTABLE(place) top_table; + +PTABLE(place) *current_table = &top_table; +saved_state *current_saved_state = 0; + +object_list olist; + +const char *ordinal_postfix(int n); +const char *object_type_name(object_type type); +char *format_number(const char *form, double n); +char *do_sprintf(const char *form, const double *v, int nv); + +%} + + +%union { + char *str; + int n; + double x; + struct { double x, y; } pair; + struct { double x; char *body; } if_data; + struct { char *str; const char *filename; int lineno; } lstr; + struct { double *v; int nv; int maxv; } dv; + struct { double val; int is_multiplicative; } by; + place pl; + object *obj; + corner crn; + path *pth; + object_spec *spec; + saved_state *pstate; + graphics_state state; + object_type obtype; +} + +%token LABEL +%token VARIABLE +%token NUMBER +%token TEXT +%token COMMAND_LINE +%token DELIMITED +%token ORDINAL +%token TH +%token LEFT_ARROW_HEAD +%token RIGHT_ARROW_HEAD +%token DOUBLE_ARROW_HEAD +%token LAST +%token UP +%token DOWN +%token LEFT +%token RIGHT +%token BOX +%token CIRCLE +%token ELLIPSE +%token ARC +%token LINE +%token ARROW +%token MOVE +%token SPLINE +%token HEIGHT +%token RADIUS +%token WIDTH +%token DIAMETER +%token UP +%token DOWN +%token RIGHT +%token LEFT +%token FROM +%token TO +%token AT +%token WITH +%token BY +%token THEN +%token DOTTED +%token DASHED +%token CHOP +%token SAME +%token INVISIBLE +%token LJUST +%token RJUST +%token ABOVE +%token BELOW +%token OF +%token THE +%token WAY +%token BETWEEN +%token AND +%token HERE +%token DOT_N +%token DOT_E +%token DOT_W +%token DOT_S +%token DOT_NE +%token DOT_SE +%token DOT_NW +%token DOT_SW +%token DOT_C +%token DOT_START +%token DOT_END +%token DOT_X +%token DOT_Y +%token DOT_HT +%token DOT_WID +%token DOT_RAD +%token SIN +%token COS +%token ATAN2 +%token LOG +%token EXP +%token SQRT +%token K_MAX +%token K_MIN +%token INT +%token RAND +%token COPY +%token THRU +%token TOP +%token BOTTOM +%token UPPER +%token LOWER +%token SH +%token PRINT +%token CW +%token CCW +%token FOR +%token DO +%token IF +%token ELSE +%token ANDAND +%token OROR +%token NOTEQUAL +%token EQUALEQUAL +%token LESSEQUAL +%token GREATEREQUAL +%token LEFT_CORNER +%token RIGHT_CORNER +%token CENTER +%token END +%token START +%token RESET +%token UNTIL +%token PLOT +%token THICKNESS +%token FILL +%token ALIGNED +%token SPRINTF +%token COMMAND + +%token DEFINE +%token UNDEF + +/* this ensures that plot 17 "%g" parses as (plot 17 "%g") */ +%left PLOT +%left TEXT SPRINTF + +/* give text adjustments higher precedence than TEXT, so that +box "foo" above ljust == box ("foo" above ljust) +*/ + +%left LJUST RJUST ABOVE BELOW + +%left LEFT RIGHT +/* Give attributes that take an optional expression a higher +precedence than left and right, so that eg `line chop left' +parses properly. */ +%left CHOP DASHED DOTTED UP DOWN FILL +%left LABEL + +%left VARIABLE NUMBER '(' SIN COS ATAN2 LOG EXP SQRT K_MAX K_MIN INT RAND LAST +%left ORDINAL HERE '`' + +/* these need to be lower than '-' */ +%left HEIGHT RADIUS WIDTH DIAMETER FROM TO AT THICKNESS + +/* these must have higher precedence than CHOP so that `label %prec CHOP' +works */ +%left DOT_N DOT_E DOT_W DOT_S DOT_NE DOT_SE DOT_NW DOT_SW DOT_C +%left DOT_START DOT_END TOP BOTTOM LEFT_CORNER RIGHT_CORNER +%left UPPER LOWER CENTER START END + +%left ',' +%left OROR +%left ANDAND +%left EQUALEQUAL NOTEQUAL +%left '<' '>' LESSEQUAL GREATEREQUAL + +%left BETWEEN OF +%left AND + +%left '+' '-' +%left '*' '/' '%' +%right '!' +%right '^' + +%type expr any_expr text_expr +%type optional_by +%type expr_pair position_not_place +%type simple_if +%type nth_primitive +%type corner +%type path label_path relative_path +%type place label element element_list middle_element_list +%type object_spec +%type position +%type object_type +%type optional_ordinal_last ordinal +%type until +%type sprintf_args +%type text print_args print_arg + +%% + +top: + optional_separator + | element_list + { + if (olist.head) + print_picture(olist.head); + } + ; + + +element_list: + optional_separator middle_element_list optional_separator + { $$ = $2; } + ; + +middle_element_list: + element + { $$ = $1; } + | middle_element_list separator element + { $$ = $1; } + ; + +optional_separator: + /* empty */ + | separator + ; + +separator: + ';' + | separator ';' + ; + +placeless_element: + VARIABLE '=' any_expr + { + define_variable($1, $3); + a_delete $1; + } + | VARIABLE ':' '=' any_expr + { + place *p = lookup_label($1); + if (!p) { + lex_error("variable `%1' not defined", $1); + YYABORT; + } + p->obj = 0; + p->x = $4; + p->y = 0.0; + a_delete $1; + } + | UP + { current_direction = UP_DIRECTION; } + | DOWN + { current_direction = DOWN_DIRECTION; } + | LEFT + { current_direction = LEFT_DIRECTION; } + | RIGHT + { current_direction = RIGHT_DIRECTION; } + | COMMAND_LINE + { + olist.append(make_command_object($1.str, $1.filename, + $1.lineno)); + } + | COMMAND print_args + { + olist.append(make_command_object($2.str, $2.filename, + $2.lineno)); + } + | PRINT print_args + { + fprintf(stderr, "%s\n", $2.str); + a_delete $2.str; + fflush(stderr); + } + | SH + { delim_flag = 1; } + DELIMITED + { + delim_flag = 0; + system($3); + a_delete $3; + } + | COPY TEXT + { + if (yychar < 0) + do_lookahead(); + do_copy($2.str); + // do not delete the filename + } + | COPY TEXT THRU + { delim_flag = 2; } + DELIMITED + { delim_flag = 0; } + until + { + if (yychar < 0) + do_lookahead(); + copy_file_thru($2.str, $5, $7); + // do not delete the filename + a_delete $5; + a_delete $7; + } + | COPY THRU + { delim_flag = 2; } + DELIMITED + { delim_flag = 0; } + until + { + if (yychar < 0) + do_lookahead(); + copy_rest_thru($4, $6); + a_delete $4; + a_delete $6; + } + | FOR VARIABLE '=' expr TO expr optional_by DO + { delim_flag = 1; } + DELIMITED + { + delim_flag = 0; + if (yychar < 0) + do_lookahead(); + do_for($2, $4, $6, $7.is_multiplicative, $7.val, $10); + } + | simple_if + { + if (yychar < 0) + do_lookahead(); + if ($1.x != 0.0) + push_body($1.body); + a_delete $1.body; + } + | simple_if ELSE + { delim_flag = 1; } + DELIMITED + { + delim_flag = 0; + if (yychar < 0) + do_lookahead(); + if ($1.x != 0.0) + push_body($1.body); + else + push_body($4); + a_delete $1.body; + a_delete $4; + } + | reset_variables + | RESET + { define_variable("scale", 1.0); } + ; + +reset_variables: + RESET VARIABLE + { reset($2); a_delete $2; } + | reset_variables VARIABLE + { reset($2); a_delete $2; } + | reset_variables ',' VARIABLE + { reset($3); a_delete $3; } + ; + +print_args: + print_arg + { $$ = $1; } + | print_args print_arg + { + $$.str = new char[strlen($1.str) + strlen($2.str) + 1]; + strcpy($$.str, $1.str); + strcat($$.str, $2.str); + a_delete $1.str; + a_delete $2.str; + if ($1.filename) { + $$.filename = $1.filename; + $$.lineno = $1.lineno; + } + else if ($2.filename) { + $$.filename = $2.filename; + $$.lineno = $2.lineno; + } + } + ; + +print_arg: + expr %prec ',' + { + $$.str = new char[GDIGITS + 1]; + sprintf($$.str, "%g", $1); + $$.filename = 0; + $$.lineno = 0; + } + | text + { $$ = $1; } + | position %prec ',' + { + $$.str = new char[GDIGITS + 2 + GDIGITS + 1]; + sprintf($$.str, "%g, %g", $1.x, $1.y); + $$.filename = 0; + $$.lineno = 0; + } + +simple_if: + IF any_expr THEN + { delim_flag = 1; } + DELIMITED + { delim_flag = 0; $$.x = $2; $$.body = $5; } + ; + +until: + /* empty */ + { $$ = 0; } + | UNTIL TEXT + { $$ = $2.str; } + ; + +any_expr: + expr + { $$ = $1; } + | text_expr + { $$ = $1; } + ; + +text_expr: + text EQUALEQUAL text + { + $$ = strcmp($1.str, $3.str) == 0; + a_delete $1.str; + a_delete $3.str; + } + | text NOTEQUAL text + { + $$ = strcmp($1.str, $3.str) != 0; + a_delete $1.str; + a_delete $3.str; + } + | text_expr ANDAND text_expr + { $$ = ($1 != 0.0 && $3 != 0.0); } + | text_expr ANDAND expr + { $$ = ($1 != 0.0 && $3 != 0.0); } + | expr ANDAND text_expr + { $$ = ($1 != 0.0 && $3 != 0.0); } + | text_expr OROR text_expr + { $$ = ($1 != 0.0 || $3 != 0.0); } + | text_expr OROR expr + { $$ = ($1 != 0.0 || $3 != 0.0); } + | expr OROR text_expr + { $$ = ($1 != 0.0 || $3 != 0.0); } + | '!' text_expr + { $$ = ($2 == 0.0); } + ; + + +optional_by: + /* empty */ + { $$.val = 1.0; $$.is_multiplicative = 0; } + | BY expr + { $$.val = $2; $$.is_multiplicative = 0; } + | BY '*' expr + { $$.val = $3; $$.is_multiplicative = 1; } + ; + +element: + object_spec + { + $$.obj = $1->make_object(¤t_position, + ¤t_direction); + if ($$.obj == 0) + YYABORT; + delete $1; + if ($$.obj) + olist.append($$.obj); + else { + $$.x = current_position.x; + $$.y = current_position.y; + } + } + | LABEL ':' optional_separator element + { $$ = $4; define_label($1, & $$); a_delete $1; } + | LABEL ':' optional_separator position_not_place + { + $$.obj = 0; + $$.x = $4.x; + $$.y = $4.y; + define_label($1, & $$); + a_delete $1; + } + | LABEL ':' optional_separator place + { + $$ = $4; + define_label($1, & $$); + a_delete $1; + } + | '{' + { + $$.x = current_position.x; + $$.y = current_position.y; + $$.dir = current_direction; + } + element_list '}' + { + current_position.x = $2.x; + current_position.y = $2.y; + current_direction = $2.dir; + } + optional_element + { + $$ = $3; + } + | placeless_element + { + $$.obj = 0; + $$.x = current_position.x; + $$.y = current_position.y; + } + ; + +optional_element: + /* empty */ + {} + | element + {} + ; + +object_spec: + BOX + { + $$ = new object_spec(BOX_OBJECT); + } + | CIRCLE + { + $$ = new object_spec(CIRCLE_OBJECT); + } + | ELLIPSE + { + $$ = new object_spec(ELLIPSE_OBJECT); + } + | ARC + { + $$ = new object_spec(ARC_OBJECT); + $$->dir = current_direction; + } + | LINE + { + $$ = new object_spec(LINE_OBJECT); + lookup_variable("lineht", & $$->segment_height); + lookup_variable("linewid", & $$->segment_width); + $$->dir = current_direction; + } + | ARROW + { + $$ = new object_spec(ARROW_OBJECT); + lookup_variable("lineht", & $$->segment_height); + lookup_variable("linewid", & $$->segment_width); + $$->dir = current_direction; + } + | MOVE + { + $$ = new object_spec(MOVE_OBJECT); + lookup_variable("moveht", & $$->segment_height); + lookup_variable("movewid", & $$->segment_width); + $$->dir = current_direction; + } + | SPLINE + { + $$ = new object_spec(SPLINE_OBJECT); + lookup_variable("lineht", & $$->segment_height); + lookup_variable("linewid", & $$->segment_width); + $$->dir = current_direction; + } + | text %prec TEXT + { + $$ = new object_spec(TEXT_OBJECT); + $$->text = new text_item($1.str, $1.filename, $1.lineno); + } + | PLOT expr + { + $$ = new object_spec(TEXT_OBJECT); + $$->text = new text_item(format_number(0, $2), 0, -1); + } + | PLOT expr text + { + $$ = new object_spec(TEXT_OBJECT); + $$->text = new text_item(format_number($3.str, $2), + $3.filename, $3.lineno); + a_delete $3.str; + } + | '[' + { + saved_state *p = new saved_state; + $$ = p; + p->x = current_position.x; + p->y = current_position.y; + p->dir = current_direction; + p->tbl = current_table; + p->prev = current_saved_state; + current_position.x = 0.0; + current_position.y = 0.0; + current_table = new PTABLE(place); + current_saved_state = p; + olist.append(make_mark_object()); + } + element_list ']' + { + current_position.x = $2->x; + current_position.y = $2->y; + current_direction = $2->dir; + $$ = new object_spec(BLOCK_OBJECT); + olist.wrap_up_block(& $$->oblist); + $$->tbl = current_table; + current_table = $2->tbl; + current_saved_state = $2->prev; + delete $2; + } + | object_spec HEIGHT expr + { + $$ = $1; + $$->height = $3; + $$->flags |= HAS_HEIGHT; + } + | object_spec RADIUS expr + { + $$ = $1; + $$->radius = $3; + $$->flags |= HAS_RADIUS; + } + | object_spec WIDTH expr + { + $$ = $1; + $$->width = $3; + $$->flags |= HAS_WIDTH; + } + | object_spec DIAMETER expr + { + $$ = $1; + $$->radius = $3/2.0; + $$->flags |= HAS_RADIUS; + } + | object_spec expr %prec HEIGHT + { + $$ = $1; + $$->flags |= HAS_SEGMENT; + switch ($$->dir) { + case UP_DIRECTION: + $$->segment_pos.y += $2; + break; + case DOWN_DIRECTION: + $$->segment_pos.y -= $2; + break; + case RIGHT_DIRECTION: + $$->segment_pos.x += $2; + break; + case LEFT_DIRECTION: + $$->segment_pos.x -= $2; + break; + } + } + | object_spec UP + { + $$ = $1; + $$->dir = UP_DIRECTION; + $$->flags |= HAS_SEGMENT; + $$->segment_pos.y += $$->segment_height; + } + | object_spec UP expr + { + $$ = $1; + $$->dir = UP_DIRECTION; + $$->flags |= HAS_SEGMENT; + $$->segment_pos.y += $3; + } + | object_spec DOWN + { + $$ = $1; + $$->dir = DOWN_DIRECTION; + $$->flags |= HAS_SEGMENT; + $$->segment_pos.y -= $$->segment_height; + } + | object_spec DOWN expr + { + $$ = $1; + $$->dir = DOWN_DIRECTION; + $$->flags |= HAS_SEGMENT; + $$->segment_pos.y -= $3; + } + | object_spec RIGHT + { + $$ = $1; + $$->dir = RIGHT_DIRECTION; + $$->flags |= HAS_SEGMENT; + $$->segment_pos.x += $$->segment_width; + } + | object_spec RIGHT expr + { + $$ = $1; + $$->dir = RIGHT_DIRECTION; + $$->flags |= HAS_SEGMENT; + $$->segment_pos.x += $3; + } + | object_spec LEFT + { + $$ = $1; + $$->dir = LEFT_DIRECTION; + $$->flags |= HAS_SEGMENT; + $$->segment_pos.x -= $$->segment_width; + } + | object_spec LEFT expr + { + $$ = $1; + $$->dir = LEFT_DIRECTION; + $$->flags |= HAS_SEGMENT; + $$->segment_pos.x -= $3; + } + | object_spec FROM position + { + $$ = $1; + $$->flags |= HAS_FROM; + $$->from.x = $3.x; + $$->from.y = $3.y; + } + | object_spec TO position + { + $$ = $1; + if ($$->flags & HAS_SEGMENT) + $$->segment_list = new segment($$->segment_pos, + $$->segment_is_absolute, + $$->segment_list); + $$->flags |= HAS_SEGMENT; + $$->segment_pos.x = $3.x; + $$->segment_pos.y = $3.y; + $$->segment_is_absolute = 1; + $$->flags |= HAS_TO; + $$->to.x = $3.x; + $$->to.y = $3.y; + } + | object_spec AT position + { + $$ = $1; + $$->flags |= HAS_AT; + $$->at.x = $3.x; + $$->at.y = $3.y; + if ($$->type != ARC_OBJECT) { + $$->flags |= HAS_FROM; + $$->from.x = $3.x; + $$->from.y = $3.y; + } + } + | object_spec WITH path + { + $$ = $1; + $$->flags |= HAS_WITH; + $$->with = $3; + } + | object_spec BY expr_pair + { + $$ = $1; + $$->flags |= HAS_SEGMENT; + $$->segment_pos.x += $3.x; + $$->segment_pos.y += $3.y; + } + | object_spec THEN + { + $$ = $1; + if ($$->flags & HAS_SEGMENT) { + $$->segment_list = new segment($$->segment_pos, + $$->segment_is_absolute, + $$->segment_list); + $$->flags &= ~HAS_SEGMENT; + $$->segment_pos.x = $$->segment_pos.y = 0.0; + $$->segment_is_absolute = 0; + } + } + | object_spec DOTTED + { + $$ = $1; + $$->flags |= IS_DOTTED; + lookup_variable("dashwid", & $$->dash_width); + } + | object_spec DOTTED expr + { + $$ = $1; + $$->flags |= IS_DOTTED; + $$->dash_width = $3; + } + | object_spec DASHED + { + $$ = $1; + $$->flags |= IS_DASHED; + lookup_variable("dashwid", & $$->dash_width); + } + | object_spec DASHED expr + { + $$ = $1; + $$->flags |= IS_DASHED; + $$->dash_width = $3; + } + | object_spec FILL + { + $$ = $1; + $$->flags |= IS_DEFAULT_FILLED; + } + | object_spec FILL expr + { + $$ = $1; + $$->flags |= IS_FILLED; + $$->fill = $3; + } + | object_spec CHOP + { + $$ = $1; + // line chop chop means line chop 0 chop 0 + if ($$->flags & IS_DEFAULT_CHOPPED) { + $$->flags |= IS_CHOPPED; + $$->flags &= ~IS_DEFAULT_CHOPPED; + $$->start_chop = $$->end_chop = 0.0; + } + else if ($$->flags & IS_CHOPPED) { + $$->end_chop = 0.0; + } + else { + $$->flags |= IS_DEFAULT_CHOPPED; + } + } + | object_spec CHOP expr + { + $$ = $1; + if ($$->flags & IS_DEFAULT_CHOPPED) { + $$->flags |= IS_CHOPPED; + $$->flags &= ~IS_DEFAULT_CHOPPED; + $$->start_chop = 0.0; + $$->end_chop = $3; + } + else if ($$->flags & IS_CHOPPED) { + $$->end_chop = $3; + } + else { + $$->start_chop = $$->end_chop = $3; + $$->flags |= IS_CHOPPED; + } + } + | object_spec SAME + { + $$ = $1; + $$->flags |= IS_SAME; + } + | object_spec INVISIBLE + { + $$ = $1; + $$->flags |= IS_INVISIBLE; + } + | object_spec LEFT_ARROW_HEAD + { + $$ = $1; + $$->flags |= HAS_LEFT_ARROW_HEAD; + } + | object_spec RIGHT_ARROW_HEAD + { + $$ = $1; + $$->flags |= HAS_RIGHT_ARROW_HEAD; + } + | object_spec DOUBLE_ARROW_HEAD + { + $$ = $1; + $$->flags |= (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD); + } + | object_spec CW + { + $$ = $1; + $$->flags |= IS_CLOCKWISE; + } + | object_spec CCW + { + $$ = $1; + $$->flags &= ~IS_CLOCKWISE; + } + | object_spec text %prec TEXT + { + $$ = $1; + for (text_item **p = & $$->text; *p; p = &(*p)->next) + ; + *p = new text_item($2.str, $2.filename, $2.lineno); + } + | object_spec LJUST + { + $$ = $1; + if ($$->text) { + for (text_item *p = $$->text; p->next; p = p->next) + ; + p->adj.h = LEFT_ADJUST; + } + } + | object_spec RJUST + { + $$ = $1; + if ($$->text) { + for (text_item *p = $$->text; p->next; p = p->next) + ; + p->adj.h = RIGHT_ADJUST; + } + } + | object_spec ABOVE + { + $$ = $1; + if ($$->text) { + for (text_item *p = $$->text; p->next; p = p->next) + ; + p->adj.v = ABOVE_ADJUST; + } + } + | object_spec BELOW + { + $$ = $1; + if ($$->text) { + for (text_item *p = $$->text; p->next; p = p->next) + ; + p->adj.v = BELOW_ADJUST; + } + } + | object_spec THICKNESS expr + { + $$ = $1; + $$->flags |= HAS_THICKNESS; + $$->thickness = $3; + } + | object_spec ALIGNED + { + $$ = $1; + $$->flags |= IS_ALIGNED; + } + ; + +text: + TEXT + { + $$ = $1; + } + | SPRINTF '(' TEXT sprintf_args ')' + { + $$.filename = $3.filename; + $$.lineno = $3.lineno; + $$.str = do_sprintf($3.str, $4.v, $4.nv); + a_delete $4.v; + a_delete $3.str; + } + ; + +sprintf_args: + /* empty */ + { + $$.v = 0; + $$.nv = 0; + $$.maxv = 0; + } + | sprintf_args ',' expr + { + $$ = $1; + if ($$.nv >= $$.maxv) { + if ($$.nv == 0) { + $$.v = new double[4]; + $$.maxv = 4; + } + else { + double *oldv = $$.v; + $$.maxv *= 2; + $$.v = new double[$$.maxv]; + memcpy($$.v, oldv, $$.nv*sizeof(double)); + a_delete oldv; + } + } + $$.v[$$.nv] = $3; + $$.nv += 1; + } + ; + +position: + position_not_place + { $$ = $1; } + | place + { + position pos = $1; + $$.x = pos.x; + $$.y = pos.y; + } + ; + +position_not_place: + expr_pair + { $$ = $1; } + | position '+' expr_pair + { + $$.x = $1.x + $3.x; + $$.y = $1.y + $3.y; + } + | position '-' expr_pair + { + $$.x = $1.x - $3.x; + $$.y = $1.y - $3.y; + } + | '(' position ',' position ')' + { + $$.x = $2.x; + $$.y = $4.y; + } + | expr between position AND position + { + $$.x = (1.0 - $1)*$3.x + $1*$5.x; + $$.y = (1.0 - $1)*$3.y + $1*$5.y; + } + | expr '<' position ',' position '>' + { + $$.x = (1.0 - $1)*$3.x + $1*$5.x; + $$.y = (1.0 - $1)*$3.y + $1*$5.y; + } + ; + +between: + BETWEEN + | OF THE WAY BETWEEN + ; + +expr_pair: + expr ',' expr + { $$.x = $1; $$.y = $3; } + | '(' expr_pair ')' + { $$ = $2; } + ; + +place: + label %prec CHOP /* line at A left == line (at A) left */ + { $$ = $1; } + | label corner + { + path pth($2); + if (!pth.follow($1, & $$)) + YYABORT; + } + | corner label + { + path pth($1); + if (!pth.follow($2, & $$)) + YYABORT; + } + | corner OF label + { + path pth($1); + if (!pth.follow($3, & $$)) + YYABORT; + } + | HERE + { + $$.x = current_position.x; + $$.y = current_position.y; + $$.obj = 0; + } + ; + +label: + LABEL + { + place *p = lookup_label($1); + if (!p) { + lex_error("there is no place `%1'", $1); + YYABORT; + } + $$ = *p; + a_delete $1; + } + | nth_primitive + { + $$.obj = $1; + } + | label '.' LABEL + { + path pth($3); + if (!pth.follow($1, & $$)) + YYABORT; + } + ; + +ordinal: + ORDINAL + { $$ = $1; } + | '`' any_expr TH + { + // XXX Check for overflow (and non-integers?). + $$ = (int)$2; + } + ; + +optional_ordinal_last: + LAST + { $$ = 1; } + | ordinal LAST + { $$ = $1; } + ; + +nth_primitive: + ordinal object_type + { + int count = 0; + for (object *p = olist.head; p != 0; p = p->next) + if (p->type() == $2 && ++count == $1) { + $$ = p; + break; + } + if (p == 0) { + lex_error("there is no %1%2 %3", $1, ordinal_postfix($1), + object_type_name($2)); + YYABORT; + } + } + | optional_ordinal_last object_type + { + int count = 0; + for (object *p = olist.tail; p != 0; p = p->prev) + if (p->type() == $2 && ++count == $1) { + $$ = p; + break; + } + if (p == 0) { + lex_error("there is no %1%2 last %3", $1, + ordinal_postfix($1), object_type_name($2)); + YYABORT; + } + } + ; + +object_type: + BOX + { $$ = BOX_OBJECT; } + | CIRCLE + { $$ = CIRCLE_OBJECT; } + | ELLIPSE + { $$ = ELLIPSE_OBJECT; } + | ARC + { $$ = ARC_OBJECT; } + | LINE + { $$ = LINE_OBJECT; } + | ARROW + { $$ = ARROW_OBJECT; } + | SPLINE + { $$ = SPLINE_OBJECT; } + | '[' ']' + { $$ = BLOCK_OBJECT; } + | TEXT + { $$ = TEXT_OBJECT; } + ; + +label_path: + '.' LABEL + { + $$ = new path($2); + } + | label_path '.' LABEL + { + $$ = $1; + $$->append($3); + } + ; + +relative_path: + corner + { + $$ = new path($1); + } + /* give this a lower precedence than LEFT and RIGHT so that + [A: box] with .A left == [A: box] with (.A left) */ + + | label_path %prec TEXT + { + $$ = $1; + } + | label_path corner + { + $$ = $1; + $$->append($2); + } + ; + +path: + relative_path + { + $$ = $1; + } + /* The rest of these rules are a compatibility sop. */ + | ORDINAL LAST object_type relative_path + { + lex_warning("`%1%2 last %3' in `with' argument ignored", + $1, ordinal_postfix($1), object_type_name($3)); + $$ = $4; + } + | LAST object_type relative_path + { + lex_warning("`last %1' in `with' argument ignored", + object_type_name($2)); + $$ = $3; + } + | ORDINAL object_type relative_path + { + lex_warning("`%1%2 %3' in `with' argument ignored", + $1, ordinal_postfix($1), object_type_name($2)); + $$ = $3; + } + | LABEL relative_path + { + lex_warning("initial `%1' in `with' argument ignored", $1); + a_delete $1; + $$ = $2; + } + ; + +corner: + DOT_N + { $$ = &object::north; } + | DOT_E + { $$ = &object::east; } + | DOT_W + { $$ = &object::west; } + | DOT_S + { $$ = &object::south; } + | DOT_NE + { $$ = &object::north_east; } + | DOT_SE + { $$ = &object:: south_east; } + | DOT_NW + { $$ = &object::north_west; } + | DOT_SW + { $$ = &object::south_west; } + | DOT_C + { $$ = &object::center; } + | DOT_START + { $$ = &object::start; } + | DOT_END + { $$ = &object::end; } + | TOP + { $$ = &object::north; } + | BOTTOM + { $$ = &object::south; } + | LEFT + { $$ = &object::west; } + | RIGHT + { $$ = &object::east; } + | UPPER LEFT + { $$ = &object::north_west; } + | LOWER LEFT + { $$ = &object::south_west; } + | UPPER RIGHT + { $$ = &object::north_east; } + | LOWER RIGHT + { $$ = &object::south_east; } + | LEFT_CORNER + { $$ = &object::west; } + | RIGHT_CORNER + { $$ = &object::east; } + | UPPER LEFT_CORNER + { $$ = &object::north_west; } + | LOWER LEFT_CORNER + { $$ = &object::south_west; } + | UPPER RIGHT_CORNER + { $$ = &object::north_east; } + | LOWER RIGHT_CORNER + { $$ = &object::south_east; } + | CENTER + { $$ = &object::center; } + | START + { $$ = &object::start; } + | END + { $$ = &object::end; } + ; + +expr: + VARIABLE + { + if (!lookup_variable($1, & $$)) { + lex_error("there is no variable `%1'", $1); + YYABORT; + } + a_delete $1; + } + | NUMBER + { $$ = $1; } + | place DOT_X + { + if ($1.obj != 0) + $$ = $1.obj->origin().x; + else + $$ = $1.x; + } + | place DOT_Y + { + if ($1.obj != 0) + $$ = $1.obj->origin().y; + else + $$ = $1.y; + } + | place DOT_HT + { + if ($1.obj != 0) + $$ = $1.obj->height(); + else + $$ = 0.0; + } + | place DOT_WID + { + if ($1.obj != 0) + $$ = $1.obj->width(); + else + $$ = 0.0; + } + | place DOT_RAD + { + if ($1.obj != 0) + $$ = $1.obj->radius(); + else + $$ = 0.0; + } + | expr '+' expr + { $$ = $1 + $3; } + | expr '-' expr + { $$ = $1 - $3; } + | expr '*' expr + { $$ = $1 * $3; } + | expr '/' expr + { + if ($3 == 0.0) { + lex_error("division by zero"); + YYABORT; + } + $$ = $1/$3; + } + | expr '%' expr + { + if ($3 == 0.0) { + lex_error("modulus by zero"); + YYABORT; + } + $$ = fmod($1, $3); + } + | expr '^' expr + { + errno = 0; + $$ = pow($1, $3); + if (errno == EDOM) { + lex_error("arguments to `^' operator out of domain"); + YYABORT; + } + if (errno == ERANGE) { + lex_error("result of `^' operator out of range"); + YYABORT; + } + } + | '-' expr %prec '!' + { $$ = -$2; } + | '(' any_expr ')' + { $$ = $2; } + | SIN '(' any_expr ')' + { + errno = 0; + $$ = sin($3); + if (errno == ERANGE) { + lex_error("sin result out of range"); + YYABORT; + } + } + | COS '(' any_expr ')' + { + errno = 0; + $$ = cos($3); + if (errno == ERANGE) { + lex_error("cos result out of range"); + YYABORT; + } + } + | ATAN2 '(' any_expr ',' any_expr ')' + { + errno = 0; + $$ = atan2($3, $5); + if (errno == EDOM) { + lex_error("atan2 argument out of domain"); + YYABORT; + } + if (errno == ERANGE) { + lex_error("atan2 result out of range"); + YYABORT; + } + } + | LOG '(' any_expr ')' + { + errno = 0; + $$ = log10($3); + if (errno == ERANGE) { + lex_error("log result out of range"); + YYABORT; + } + } + | EXP '(' any_expr ')' + { + errno = 0; + $$ = pow(10.0, $3); + if (errno == ERANGE) { + lex_error("exp result out of range"); + YYABORT; + } + } + | SQRT '(' any_expr ')' + { + errno = 0; + $$ = sqrt($3); + if (errno == EDOM) { + lex_error("sqrt argument out of domain"); + YYABORT; + } + } + | K_MAX '(' any_expr ',' any_expr ')' + { $$ = $3 > $5 ? $3 : $5; } + | K_MIN '(' any_expr ',' any_expr ')' + { $$ = $3 < $5 ? $3 : $5; } + | INT '(' any_expr ')' + { $$ = floor($3); } + | RAND '(' any_expr ')' + { $$ = 1.0 + floor(((rand()&0x7fff)/double(0x7fff))*$3); } + | RAND '(' ')' + { + /* return a random number in the range [0,1) */ + /* portable, but not very random */ + $$ = (rand() & 0x7fff) / double(0x8000); + } + | expr '<' expr + { $$ = ($1 < $3); } + | expr LESSEQUAL expr + { $$ = ($1 <= $3); } + | expr '>' expr + { $$ = ($1 > $3); } + | expr GREATEREQUAL expr + { $$ = ($1 >= $3); } + | expr EQUALEQUAL expr + { $$ = ($1 == $3); } + | expr NOTEQUAL expr + { $$ = ($1 != $3); } + | expr ANDAND expr + { $$ = ($1 != 0.0 && $3 != 0.0); } + | expr OROR expr + { $$ = ($1 != 0.0 || $3 != 0.0); } + | '!' expr + { $$ = ($2 == 0.0); } + + ; + +%% + +/* bison defines const to be empty unless __STDC__ is defined, which it +isn't under cfront */ + +#ifdef const +#undef const +#endif + +static struct { + const char *name; + double val; + int scaled; // non-zero if val should be multiplied by scale +} defaults_table[] = { + "arcrad", .25, 1, + "arrowht", .1, 1, + "arrowwid", .05, 1, + "circlerad", .25, 1, + "boxht", .5, 1, + "boxwid", .75, 1, + "boxrad", 0.0, 1, + "dashwid", .05, 1, + "ellipseht", .5, 1, + "ellipsewid", .75, 1, + "moveht", .5, 1, + "movewid", .5, 1, + "lineht", .5, 1, + "linewid", .5, 1, + "textht", 0.0, 1, + "textwid", 0.0, 1, + "scale", 1.0, 0, + "linethick", -1.0, 0, // in points + "fillval", .5, 0, + "arrowhead", 1.0, 0, + "maxpswid", 8.5, 0, + "maxpsht", 11.0, 0, +}; + +place *lookup_label(const char *label) +{ + saved_state *state = current_saved_state; + PTABLE(place) *tbl = current_table; + for (;;) { + place *pl = tbl->lookup(label); + if (pl) + return pl; + if (!state) + return 0; + tbl = state->tbl; + state = state->prev; + } +} + +void define_label(const char *label, const place *pl) +{ + place *p = new place; + *p = *pl; + current_table->define(label, p); +} + +int lookup_variable(const char *name, double *val) +{ + place *pl = lookup_label(name); + if (pl) { + *val = pl->x; + return 1; + } + return 0; +} + +void define_variable(const char *name, double val) +{ + place *p = new place; + p->obj = 0; + p->x = val; + p->y = 0.0; + current_table->define(name, p); + if (strcmp(name, "scale") == 0) { + // When the scale changes, reset all scaled pre-defined variables to + // their default values. + for (int i = 0; i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++) + if (defaults_table[i].scaled) + define_variable(defaults_table[i].name, val*defaults_table[i].val); + } +} + +// called once only (not once per parse) + +void parse_init() +{ + current_direction = RIGHT_DIRECTION; + current_position.x = 0.0; + current_position.y = 0.0; + // This resets everything to its default value. + reset_all(); +} + +void reset(const char *nm) +{ + for (int i = 0; i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++) + if (strcmp(nm, defaults_table[i].name) == 0) { + double val = defaults_table[i].val; + if (defaults_table[i].scaled) { + double scale; + lookup_variable("scale", &scale); + val *= scale; + } + define_variable(defaults_table[i].name, val); + return; + } + lex_error("`%1' is not a predefined variable", nm); +} + +void reset_all() +{ + // We only have to explicitly reset the pre-defined variables that + // aren't scaled because `scale' is not scaled, and changing the + // value of `scale' will reset all the pre-defined variables that + // are scaled. + for (int i = 0; i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++) + if (!defaults_table[i].scaled) + define_variable(defaults_table[i].name, defaults_table[i].val); +} + +// called after each parse + +void parse_cleanup() +{ + while (current_saved_state != 0) { + delete current_table; + current_table = current_saved_state->tbl; + saved_state *tem = current_saved_state; + current_saved_state = current_saved_state->prev; + delete tem; + } + assert(current_table == &top_table); + PTABLE_ITERATOR(place) iter(current_table); + const char *key; + place *pl; + while (iter.next(&key, &pl)) + if (pl->obj != 0) { + position pos = pl->obj->origin(); + pl->obj = 0; + pl->x = pos.x; + pl->y = pos.y; + } + while (olist.head != 0) { + object *tem = olist.head; + olist.head = olist.head->next; + delete tem; + } + olist.tail = 0; + current_direction = RIGHT_DIRECTION; + current_position.x = 0.0; + current_position.y = 0.0; +} + +const char *ordinal_postfix(int n) +{ + if (n < 10 || n > 20) + switch (n % 10) { + case 1: + return "st"; + case 2: + return "nd"; + case 3: + return "rd"; + } + return "th"; +} + +const char *object_type_name(object_type type) +{ + switch (type) { + case BOX_OBJECT: + return "box"; + case CIRCLE_OBJECT: + return "circle"; + case ELLIPSE_OBJECT: + return "ellipse"; + case ARC_OBJECT: + return "arc"; + case SPLINE_OBJECT: + return "spline"; + case LINE_OBJECT: + return "line"; + case ARROW_OBJECT: + return "arrow"; + case MOVE_OBJECT: + return "move"; + case TEXT_OBJECT: + return "\"\""; + case BLOCK_OBJECT: + return "[]"; + case OTHER_OBJECT: + case MARK_OBJECT: + default: + break; + } + return "object"; +} + +static char sprintf_buf[1024]; + +char *format_number(const char *form, double n) +{ + if (form == 0) + form = "%g"; + else { + // this is a fairly feeble attempt at validation of the format + int nspecs = 0; + for (const char *p = form; *p != '\0'; p++) + if (*p == '%') { + if (p[1] == '%') + p++; + else + nspecs++; + } + if (nspecs > 1) { + lex_error("bad format `%1'", form); + return strsave(form); + } + } + sprintf(sprintf_buf, form, n); + return strsave(sprintf_buf); +} + +char *do_sprintf(const char *form, const double *v, int nv) +{ + string result; + int i = 0; + string one_format; + while (*form) { + if (*form == '%') { + one_format += *form++; + for (; *form != '\0' && strchr("#-+ 0123456789.", *form) != 0; form++) + one_format += *form; + if (*form == '\0' || strchr("eEfgG%", *form) == 0) { + lex_error("bad sprintf format"); + result += one_format; + result += form; + break; + } + if (*form == '%') { + one_format += *form++; + one_format += '\0'; + sprintf(sprintf_buf, one_format.contents()); + } + else { + if (i >= nv) { + lex_error("too few arguments to sprintf"); + result += one_format; + result += form; + break; + } + one_format += *form++; + one_format += '\0'; + sprintf(sprintf_buf, one_format.contents(), v[i++]); + } + one_format.clear(); + result += sprintf_buf; + } + else + result += *form++; + } + result += '\0'; + return strsave(result.contents()); +} diff --git a/gnu/usr.bin/groff/pic/position.h b/gnu/usr.bin/groff/pic/position.h new file mode 100644 index 0000000000..6706fb1dda --- /dev/null +++ b/gnu/usr.bin/groff/pic/position.h @@ -0,0 +1,47 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct place; +struct position { + double x; + double y; + position(double, double ); + position(); + position(const place &); + position &operator+=(const position &); + position &operator-=(const position &); + position &operator*=(double); + position &operator/=(double); +}; + +position operator-(const position &); +position operator+(const position &, const position &); +position operator-(const position &, const position &); +position operator/(const position &, double); +position operator*(const position &, double); +// dot product +double operator*(const position &, const position &); +int operator==(const position &, const position &); +int operator!=(const position &, const position &); + +double hypot(const position &a); + +typedef position distance; + diff --git a/gnu/usr.bin/groff/pic/tex.cc b/gnu/usr.bin/groff/pic/tex.cc new file mode 100644 index 0000000000..d0fd962a64 --- /dev/null +++ b/gnu/usr.bin/groff/pic/tex.cc @@ -0,0 +1,411 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "pic.h" + +#ifdef TEX_SUPPORT + +#include "common.h" + +class tex_output : public common_output { +public: + tex_output(); + ~tex_output(); + void start_picture(double, const position &ll, const position &ur); + void finish_picture(); + void text(const position &, text_piece *, int, double); + void line(const position &, const position *, int n, + const line_type &); + void polygon(const position *, int n, + const line_type &, double); + void spline(const position &, const position *, int n, + const line_type &); + void arc(const position &, const position &, const position &, + const line_type &); + void circle(const position &, double rad, const line_type &, double); + void ellipse(const position &, const distance &, const line_type &, double); + void command(const char *, const char *, int); + int supports_filled_polygons(); +private: + position upper_left; + double height; + double width; + double scale; + double pen_size; + + void point(const position &); + void dot(const position &, const line_type &); + void solid_arc(const position ¢, double rad, double start_angle, + double end_angle, const line_type <); + position transform(const position &); +protected: + virtual void set_pen_size(double ps); +}; + +// convert inches to milliinches + +inline int milliinches(double x) +{ + return int(x*1000.0 + .5); +} + +inline position tex_output::transform(const position &pos) +{ + return position((pos.x - upper_left.x)/scale, + (upper_left.y - pos.y)/scale); +} + +output *make_tex_output() +{ + return new tex_output; +} + +tex_output::tex_output() +{ +} + +tex_output::~tex_output() +{ +} + +const int DEFAULT_PEN_SIZE = 8; + +void tex_output::set_pen_size(double ps) +{ + if (ps < 0.0) + ps = -1.0; + if (ps != pen_size) { + pen_size = ps; + printf(" \\special{pn %d}%%\n", + ps < 0.0 ? DEFAULT_PEN_SIZE : int(ps*(1000.0/72.0) + .5)); + } +} + +void tex_output::start_picture(double sc, const position &ll, + const position &ur) +{ + upper_left.x = ll.x; + upper_left.y = ur.y; + scale = compute_scale(sc, ll, ur); + height = (ur.y - ll.y)/scale; + width = (ur.x - ll.x)/scale; + /* the point of \vskip 0pt is to ensure that the vtop gets + a height of 0 rather than the height of the hbox; this + might be non-zero if text from text attributes lies outside pic's + idea of the bounding box of the picture. */ + fputs("\\expandafter\\ifx\\csname graph\\endcsname\\relax \\csname newbox\\endcsname\\graph\\fi\n" + "\\expandafter\\ifx\\csname graphtemp\\endcsname\\relax \\csname newdimen\\endcsname\\graphtemp\\fi\n" + "\\setbox\\graph=\\vtop{\\vskip 0pt\\hbox{%\n", + stdout); + pen_size = -2.0; +} + +void tex_output::finish_picture() +{ + printf(" \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n" + " \\kern %.3fin\n" + " }%%\n" + "}%%\n", + height, width); +} + +void tex_output::text(const position ¢er, text_piece *v, int n, double) +{ + position c = transform(center); + for (int i = 0; i < n; i++) + if (v[i].text != 0 && *v[i].text != '\0') { + int j = 2*i - n + 1; + if (v[i].adj.v == ABOVE_ADJUST) + j--; + else if (v[i].adj.v == BELOW_ADJUST) + j++; + if (j == 0) { + printf(" \\graphtemp=.5ex\\advance\\graphtemp by %.3fin\n", c.y); + } + else { + printf(" \\graphtemp=\\baselineskip" + "\\multiply\\graphtemp by %d" + "\\divide\\graphtemp by 2\n" + " \\advance\\graphtemp by .5ex" + "\\advance\\graphtemp by %.3fin\n", + j, c.y); + } + printf(" \\rlap{\\kern %.3fin\\lower\\graphtemp", c.x); + fputs("\\hbox to 0pt{", stdout); + if (v[i].adj.h != LEFT_ADJUST) + fputs("\\hss ", stdout); + fputs(v[i].text, stdout); + if (v[i].adj.h != RIGHT_ADJUST) + fputs("\\hss", stdout); + fputs("}}%\n", stdout); + } +} + +void tex_output::point(const position &pos) +{ + position p = transform(pos); + printf(" \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y)); +} + +void tex_output::line(const position &start, const position *v, int n, + const line_type <) +{ + set_pen_size(lt.thickness); + point(start); + for (int i = 0; i < n; i++) + point(v[i]); + fputs(" \\special{", stdout); + switch(lt.type) { + case line_type::invisible: + fputs("ip", stdout); + break; + case line_type::solid: + fputs("fp", stdout); + break; + case line_type::dotted: + printf("dt %.3f", lt.dash_width/scale); + break; + case line_type::dashed: + printf("da %.3f", lt.dash_width/scale); + break; + } + fputs("}%\n", stdout); +} + +void tex_output::polygon(const position *v, int n, + const line_type <, double fill) +{ + if (fill >= 0.0) { + if (fill > 1.0) + fill = 1.0; + printf(" \\special{sh %.3f}%%\n", fill); + } + line(v[n-1], v, n, lt); +} + +void tex_output::spline(const position &start, const position *v, int n, + const line_type <) +{ + if (lt.type == line_type::invisible) + return; + set_pen_size(lt.thickness); + point(start); + for (int i = 0; i < n; i++) + point(v[i]); + fputs(" \\special{sp", stdout); + switch(lt.type) { + case line_type::solid: + break; + case line_type::dotted: + printf(" %.3f", -lt.dash_width/scale); + break; + case line_type::dashed: + printf(" %.3f", lt.dash_width/scale); + break; + case line_type::invisible: + assert(0); + } + fputs("}%\n", stdout); +} + +void tex_output::solid_arc(const position ¢, double rad, + double start_angle, double end_angle, + const line_type <) +{ + set_pen_size(lt.thickness); + position c = transform(cent); + printf(" \\special{ar %d %d %d %d %f %f}%%\n", + milliinches(c.x), + milliinches(c.y), + milliinches(rad/scale), + milliinches(rad/scale), + -end_angle, + (-end_angle > -start_angle) ? M_PI * 2 - start_angle : -start_angle); +} + +void tex_output::arc(const position &start, const position ¢, + const position &end, const line_type <) +{ + switch (lt.type) { + case line_type::invisible: + break; + case line_type::dashed: + dashed_arc(start, cent, end, lt); + break; + case line_type::dotted: + dotted_arc(start, cent, end, lt); + break; + case line_type::solid: + { + position c; + if (!compute_arc_center(start, cent, end, &c)) { + line(start, &end, 1, lt); + break; + } + solid_arc(c, + hypot(cent - start), + atan2(start.y - c.y, start.x - c.x), + atan2(end.y - c.y, end.x - c.x), + lt); + break; + } + } +} + +void tex_output::circle(const position ¢, double rad, + const line_type <, double fill) +{ + if (fill >= 0.0 && lt.type != line_type::solid) { + if (fill > 1.0) + fill = 1.0; + line_type ilt; + ilt.type = line_type::invisible; + ellipse(cent, position(rad*2.0, rad*2.0), ilt, fill); + } + switch (lt.type) { + case line_type::dashed: + dashed_circle(cent, rad, lt); + break; + case line_type::invisible: + break; + case line_type::solid: + ellipse(cent, position(rad*2.0,rad*2.0), lt, fill); + break; + case line_type::dotted: + dotted_circle(cent, rad, lt); + break; + default: + assert(0); + } +} + +void tex_output::ellipse(const position ¢, const distance &dim, + const line_type <, double fill) +{ + if (lt.type == line_type::invisible) { + if (fill < 0.0) + return; + } + else + set_pen_size(lt.thickness); + if (fill >= 0.0) { + if (fill > 1.0) + fill = 1.0; + printf(" \\special{sh %.3f}%%\n", fill); + } + position c = transform(cent); + printf(" \\special{%s %d %d %d %d 0 6.28319}%%\n", + (lt.type == line_type::invisible ? "ia" : "ar"), + milliinches(c.x), + milliinches(c.y), + milliinches(dim.x/(2.0*scale)), + milliinches(dim.y/(2.0*scale))); +} + +void tex_output::command(const char *s, const char *, int) +{ + fputs(s, stdout); + putchar('%'); // avoid unwanted spaces + putchar('\n'); +} + +int tex_output::supports_filled_polygons() +{ + return 1; +} + +void tex_output::dot(const position &pos, const line_type <) +{ + if (zero_length_line_flag) { + line_type slt = lt; + slt.type = line_type::solid; + line(pos, &pos, 1, slt); + } + else { + int dot_rad = int(lt.thickness*(1000.0/(72.0*2)) + .5); + if (dot_rad == 0) + dot_rad = 1; + position p = transform(pos); + printf(" \\special{sh 1}%%\n" + " \\special{ia %d %d %d %d 0 6.28319}%%\n", + milliinches(p.x), milliinches(p.y), dot_rad, dot_rad); + } +} + +class tpic_output : public tex_output { +public: + tpic_output(); + void command(const char *, const char *, int); +private: + void set_pen_size(double ps); + int default_pen_size; + int prev_default_pen_size; +}; + +tpic_output::tpic_output() +: default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE) +{ +} + +void tpic_output::command(const char *s, const char *filename, int lineno) +{ + assert(s[0] == '.'); + if (s[1] == 'p' && s[2] == 's' && (s[3] == '\0' || !csalpha(s[3]))) { + const char *p = s + 3; + while (csspace(*p)) + p++; + if (*p == '\0') { + int temp = default_pen_size; + default_pen_size = prev_default_pen_size; + prev_default_pen_size = temp; + } + else { + char *ptr; + int temp = (int)strtol(p, &ptr, 10); + if (temp == 0 && ptr == p) + error_with_file_and_line(filename, lineno, + "argument to `.ps' not an integer"); + else if (temp < 0) + error_with_file_and_line(filename, lineno, + "negative pen size"); + else { + prev_default_pen_size = default_pen_size; + default_pen_size = temp; + } + } + } + else + printf("\\%s%%\n", s + 1); +} + +void tpic_output::set_pen_size(double ps) +{ + if (ps < 0.0) + printf(" \\special{pn %d}%%\n", default_pen_size); + else + tex_output::set_pen_size(ps); +} + +output *make_tpic_output() +{ + return new tpic_output; +} + +#endif diff --git a/gnu/usr.bin/groff/pic/text.h b/gnu/usr.bin/groff/pic/text.h new file mode 100644 index 0000000000..f9d3487507 --- /dev/null +++ b/gnu/usr.bin/groff/pic/text.h @@ -0,0 +1,28 @@ +// -*- C++ -*- + +enum hadjustment { + CENTER_ADJUST, + LEFT_ADJUST, + RIGHT_ADJUST + }; + +enum vadjustment { + NONE_ADJUST, + ABOVE_ADJUST, + BELOW_ADJUST + }; + +struct adjustment { + hadjustment h; + vadjustment v; +}; + +struct text_piece { + char *text; + adjustment adj; + const char *filename; + int lineno; + + text_piece(); + ~text_piece(); +}; diff --git a/gnu/usr.bin/groff/pic/troff.cc b/gnu/usr.bin/groff/pic/troff.cc new file mode 100644 index 0000000000..2b6d0d7b89 --- /dev/null +++ b/gnu/usr.bin/groff/pic/troff.cc @@ -0,0 +1,499 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "pic.h" +#include "common.h" + + +const double RELATIVE_THICKNESS = -1.0; +const double BAD_THICKNESS = -2.0; + +class simple_output : public common_output { + virtual void simple_line(const position &, const position &) = 0; + virtual void simple_spline(const position &, const position *, int n) = 0; + virtual void simple_arc(const position &, const position &, + const position &) = 0; + virtual void simple_circle(int, const position &, double rad) = 0; + virtual void simple_ellipse(int, const position &, const distance &) = 0; + virtual void simple_polygon(int, const position *, int) = 0; + virtual void line_thickness(double) = 0; + virtual void set_fill(double) = 0; + void dot(const position &, const line_type &) = 0; +public: + void start_picture(double sc, const position &ll, const position &ur) = 0; + void finish_picture() = 0; + void text(const position &, text_piece *, int, double) = 0; + void line(const position &, const position *, int n, + const line_type &); + void polygon(const position *, int n, + const line_type &, double); + void spline(const position &, const position *, int n, + const line_type &); + void arc(const position &, const position &, const position &, + const line_type &); + void circle(const position &, double rad, const line_type &, double); + void ellipse(const position &, const distance &, const line_type &, double); + int supports_filled_polygons(); +}; + +int simple_output::supports_filled_polygons() +{ + return driver_extension_flag != 0; +} + +void simple_output::arc(const position &start, const position ¢, + const position &end, const line_type <) +{ + switch (lt.type) { + case line_type::solid: + line_thickness(lt.thickness); + simple_arc(start, cent, end); + break; + case line_type::invisible: + break; + case line_type::dashed: + dashed_arc(start, cent, end, lt); + break; + case line_type::dotted: + dotted_arc(start, cent, end, lt); + break; + } +} + +void simple_output::line(const position &start, const position *v, int n, + const line_type <) +{ + position pos = start; + line_thickness(lt.thickness); + for (int i = 0; i < n; i++) { + switch (lt.type) { + case line_type::solid: + simple_line(pos, v[i]); + break; + case line_type::dotted: + { + distance vec(v[i] - pos); + double dist = hypot(vec); + int ndots = int(dist/lt.dash_width + .5); + if (ndots == 0) + dot(pos, lt); + else { + vec /= double(ndots); + for (int j = 0; j <= ndots; j++) + dot(pos + vec*j, lt); + } + } + break; + case line_type::dashed: + { + distance vec(v[i] - pos); + double dist = hypot(vec); + if (dist <= lt.dash_width*2.0) + simple_line(pos, v[i]); + else { + int ndashes = int((dist - lt.dash_width)/(lt.dash_width*2.0) + .5); + distance dash_vec = vec*(lt.dash_width/dist); + double dash_gap = (dist - lt.dash_width)/ndashes; + distance dash_gap_vec = vec*(dash_gap/dist); + for (int j = 0; j <= ndashes; j++) { + position s(pos + dash_gap_vec*j); + simple_line(s, s + dash_vec); + } + } + } + break; + case line_type::invisible: + break; + default: + assert(0); + } + pos = v[i]; + } +} + +void simple_output::spline(const position &start, const position *v, int n, + const line_type <) +{ + line_thickness(lt.thickness); + simple_spline(start, v, n); +} + +void simple_output::polygon(const position *v, int n, + const line_type <, double fill) +{ + if (driver_extension_flag) { + if (fill >= 0.0) { + set_fill(fill); + simple_polygon(1, v, n); + } + } + if (lt.type == line_type::solid && driver_extension_flag) { + line_thickness(lt.thickness); + simple_polygon(0, v, n); + } + else if (lt.type != line_type::invisible) { + line_thickness(lt.thickness); + line(v[n - 1], v, n, lt); + } +} + +void simple_output::circle(const position ¢, double rad, + const line_type <, double fill) +{ + if (driver_extension_flag && fill >= 0.0) { + set_fill(fill); + simple_circle(1, cent, rad); + } + line_thickness(lt.thickness); + switch (lt.type) { + case line_type::invisible: + break; + case line_type::dashed: + dashed_circle(cent, rad, lt); + break; + case line_type::dotted: + dotted_circle(cent, rad, lt); + break; + case line_type::solid: + simple_circle(0, cent, rad); + break; + default: + assert(0); + } +} + +void simple_output::ellipse(const position ¢, const distance &dim, + const line_type <, double fill) +{ + if (driver_extension_flag && fill >= 0.0) { + set_fill(fill); + simple_ellipse(1, cent, dim); + } + if (lt.type != line_type::invisible) + line_thickness(lt.thickness); + switch (lt.type) { + case line_type::invisible: + break; + case line_type::dotted: + case line_type::dashed: + case line_type::solid: + simple_ellipse(0, cent, dim); + break; + default: + assert(0); + } +} + +#define FILL_MAX 1000 + +class troff_output : public simple_output { + const char *last_filename; + position upper_left; + double height; + double scale; + double last_line_thickness; + double last_fill; +public: + troff_output(); + ~troff_output(); + void start_picture(double, const position &ll, const position &ur); + void finish_picture(); + void text(const position &, text_piece *, int, double); + void dot(const position &, const line_type &); + void command(const char *, const char *, int); + void set_location(const char *, int); + void simple_line(const position &, const position &); + void simple_spline(const position &, const position *, int n); + void simple_arc(const position &, const position &, const position &); + void simple_circle(int, const position &, double rad); + void simple_ellipse(int, const position &, const distance &); + void simple_polygon(int, const position *, int); + void line_thickness(double p); + void set_fill(double); + position transform(const position &); +}; + +output *make_troff_output() +{ + return new troff_output; +} + +troff_output::troff_output() +: last_filename(0), last_line_thickness(BAD_THICKNESS), last_fill(-1.0) +{ +} + +troff_output::~troff_output() +{ +} + +inline position troff_output::transform(const position &pos) +{ + return position((pos.x - upper_left.x)/scale, + (upper_left.y - pos.y)/scale); +} + +#define FILL_REG "00" + +// If this register > 0, then pic will generate \X'ps: ...' commands +// if the aligned attribute is used. +#define GROPS_REG "0p" + +// If this register is defined, geqn won't produce `\x's. +#define EQN_NO_EXTRA_SPACE_REG "0x" + +void troff_output::start_picture(double sc, + const position &ll, const position &ur) +{ + upper_left.x = ll.x; + upper_left.y = ur.y; + scale = compute_scale(sc, ll, ur); + height = (ur.y - ll.y)/scale; + double width = (ur.x - ll.x)/scale; + printf(".PS %.3fi %.3fi", height, width); + if (args) + printf(" %s\n", args); + else + putchar('\n'); + printf(".\\\" %g %g %g %g\n", ll.x, ll.y, ur.x, ur.y); + printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height, width, 0.0); + printf(".nr " FILL_REG " \\n(.u\n.nf\n"); + printf(".nr " EQN_NO_EXTRA_SPACE_REG " 1\n"); + // This guarantees that if the picture is used in a diversion it will + // have the right width. + printf("\\h'%.3fi'\n.sp -1\n", width); +} + +void troff_output::finish_picture() +{ + line_thickness(BAD_THICKNESS); + last_fill = -1.0; // force it to be reset for each picture + if (!flyback_flag) + printf(".sp %.3fi+1\n", height); + printf(".if \\n(" FILL_REG " .fi\n"); + printf(".br\n"); + printf(".nr " EQN_NO_EXTRA_SPACE_REG " 0\n"); + // this is a little gross + set_location(current_filename, current_lineno); + fputs(flyback_flag ? ".PF\n" : ".PE\n", stdout); +} + +void troff_output::command(const char *s, + const char *filename, int lineno) +{ + if (filename != 0) + set_location(filename, lineno); + fputs(s, stdout); + putchar('\n'); +} + +void troff_output::simple_circle(int filled, const position ¢, double rad) +{ + position c = transform(cent); + printf("\\h'%.3fi'" + "\\v'%.3fi'" + "\\D'%c%.3fi'" + "\n.sp -1\n", + c.x - rad/scale, + c.y, + (filled ? 'C' : 'c'), + rad*2.0/scale); +} + +void troff_output::simple_ellipse(int filled, const position ¢, + const distance &dim) +{ + position c = transform(cent); + printf("\\h'%.3fi'" + "\\v'%.3fi'" + "\\D'%c%.3fi %.3fi'" + "\n.sp -1\n", + c.x - dim.x/(2.0*scale), + c.y, + (filled ? 'E' : 'e'), + dim.x/scale, dim.y/scale); +} + +void troff_output::simple_arc(const position &start, const distance ¢, + const distance &end) +{ + position s = transform(start); + position c = transform(cent); + distance cv = c - s; + distance ev = transform(end) - c; + printf("\\h'%.3fi'" + "\\v'%.3fi'" + "\\D'a%.3fi %.3fi %.3fi %.3fi'" + "\n.sp -1\n", + s.x, s.y, cv.x, cv.y, ev.x, ev.y); +} + +void troff_output::simple_line(const position &start, const position &end) +{ + position s = transform(start); + distance ev = transform(end) - s; + printf("\\h'%.3fi'" + "\\v'%.3fi'" + "\\D'l%.3fi %.3fi'" + "\n.sp -1\n", + s.x, s.y, ev.x, ev.y); +} + +void troff_output::simple_spline(const position &start, + const position *v, int n) +{ + position pos = transform(start); + printf("\\h'%.3fi'" + "\\v'%.3fi'", + pos.x, pos.y); + fputs("\\D'~", stdout); + for (int i = 0; i < n; i++) { + position temp = transform(v[i]); + distance d = temp - pos; + pos = temp; + if (i != 0) + putchar(' '); + printf("%.3fi %.3fi", d.x, d.y); + } + printf("'\n.sp -1\n"); +} + +// a solid polygon + +void troff_output::simple_polygon(int filled, const position *v, int n) +{ + position pos = transform(v[0]); + printf("\\h'%.3fi'" + "\\v'%.3fi'", + pos.x, pos.y); + printf("\\D'%c", (filled ? 'P' : 'p')); + for (int i = 1; i < n; i++) { + position temp = transform(v[i]); + distance d = temp - pos; + pos = temp; + if (i != 1) + putchar(' '); + printf("%.3fi %.3fi", d.x, d.y); + } + printf("'\n.sp -1\n"); +} + +const double TEXT_AXIS = 0.22; // in ems + +static const char *choose_delimiter(const char *text) +{ + if (strchr(text, '\'') == 0) + return "'"; + else + return "\\(ts"; +} + +void troff_output::text(const position ¢er, text_piece *v, int n, + double ang) +{ + int rotate_flag = 0; + if (driver_extension_flag && ang != 0.0) { + rotate_flag = 1; + position c = transform(center); + printf(".if \\n(" GROPS_REG " \\{\\\n" + "\\h'%.3fi'" + "\\v'%.3fi'" + "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'" + "\n.sp -1\n" + ".\\}\n", + c.x, c.y, -ang*180.0/M_PI); + } + for (int i = 0; i < n; i++) + if (v[i].text != 0 && *v[i].text != '\0') { + position c = transform(center); + if (v[i].filename != 0) + set_location(v[i].filename, v[i].lineno); + printf("\\h'%.3fi", c.x); + const char *delim = choose_delimiter(v[i].text); + if (v[i].adj.h == RIGHT_ADJUST) + printf("-\\w%s%s%su", delim, v[i].text, delim); + else if (v[i].adj.h != LEFT_ADJUST) + printf("-(\\w%s%s%su/2u)", delim, v[i].text, delim); + putchar('\''); + printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm", + c.y, + n - 1, + i, + TEXT_AXIS); + if (v[i].adj.v == ABOVE_ADJUST) + printf("-.5v"); + else if (v[i].adj.v == BELOW_ADJUST) + printf("+.5v"); + putchar('\''); + fputs(v[i].text, stdout); + fputs("\n.sp -1\n", stdout); + } + if (rotate_flag) + printf(".if '\\*(.T'ps' \\{\\\n" + "\\X'ps: exec grestore'\n.sp -1\n" + ".\\}\n"); +} + +void troff_output::line_thickness(double p) +{ + if (p < 0.0) + p = RELATIVE_THICKNESS; + if (driver_extension_flag && p != last_line_thickness) { + printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p, -p); + last_line_thickness = p; + } +} + +void troff_output::set_fill(double f) +{ + if (driver_extension_flag && f != last_fill) { + printf("\\D'f %du'\\h'%du'\n.sp -1\n", int(f*FILL_MAX), -int(f*FILL_MAX)); + last_fill = f; + } +} + +const double DOT_AXIS = .044; + +void troff_output::dot(const position ¢, const line_type <) +{ + if (driver_extension_flag) { + line_thickness(lt.thickness); + simple_line(cent, cent); + } + else { + position c = transform(cent); + printf("\\h'%.3fi-(\\w'.'u/2u)'" + "\\v'%.3fi+%.2fm'" + ".\n.sp -1\n", + c.x, + c.y, + DOT_AXIS); + } +} + +void troff_output::set_location(const char *s, int n) +{ + if (last_filename != 0 && strcmp(s, last_filename) == 0) + printf(".lf %d\n", n); + else { + printf(".lf %d %s\n", n, s); + last_filename = s; + } +} diff --git a/gnu/usr.bin/groff/psbb/Makefile b/gnu/usr.bin/groff/psbb/Makefile new file mode 100644 index 0000000000..9556fbba12 --- /dev/null +++ b/gnu/usr.bin/groff/psbb/Makefile @@ -0,0 +1,9 @@ +# Makefile for psbb + +PROG= psbb +SRCS= psbb.c + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/psbb/Makefile.dep b/gnu/usr.bin/groff/psbb/Makefile.dep new file mode 100644 index 0000000000..640782ea9a --- /dev/null +++ b/gnu/usr.bin/groff/psbb/Makefile.dep @@ -0,0 +1 @@ +psbb.o : psbb.c diff --git a/gnu/usr.bin/groff/psbb/psbb.1 b/gnu/usr.bin/groff/psbb/psbb.1 new file mode 100644 index 0000000000..f5da3eb157 --- /dev/null +++ b/gnu/usr.bin/groff/psbb/psbb.1 @@ -0,0 +1,26 @@ +.\" -*- nroff -*- +.TH PSBB 1 "6 August 1992" "Groff Version 1.08" +.SH NAME +psbb \- extract bounding box from PostScript document +.SH SYNOPSIS +.B psbb +.I file +.SH DESCRIPTION +psbb reads +.I file +which should be a PostScript document conforming to +the Document Structuring conventions +and looks for a +.B %%BoundingBox +comment. +If it finds one, +it prints a line +.IP +.I +llx lly urx ury +.LP +on the standard output and exits with zero status. +If it doesn't find such a line or if the line is invalid +it prints a message and exits with non-zero status. +.SH "SEE ALSO" +.BR grops (1) diff --git a/gnu/usr.bin/groff/psbb/psbb.c b/gnu/usr.bin/groff/psbb/psbb.c new file mode 100644 index 0000000000..4df15621fa --- /dev/null +++ b/gnu/usr.bin/groff/psbb/psbb.c @@ -0,0 +1,169 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#ifndef errno +extern int errno; +#endif + +struct bounding_box { + int llx, lly, urx, ury; +}; + +#ifdef __STDC__ +const char *do_file(FILE *, struct bounding_box *); +int parse_bounding_box(char *, struct bounding_box *); +#else +#define const /* as nothing */ +const char *do_file(); +int parse_bounding_box(); +#endif + +int main(argc, argv) +int argc; +char **argv; +{ + FILE *fp; + const char *message; + struct bounding_box bb; + if (argc != 2) { + fprintf(stderr, "usage: %s filename\n", argv[0]); + exit(3); + } + errno = 0; + fp = fopen(argv[1], "r"); + if (fp == NULL) { + fprintf(stderr, "%s: can't open `%s': ", argv[0], argv[1]); + perror((char *)NULL); + exit(2); + } + message = do_file(fp, &bb); + if (message) { + fprintf(stderr, "%s: ", argv[0]); + fprintf(stderr, message, argv[1]); + putc('\n', stderr); + exit(1); + } + printf("%d %d %d %d\n", bb.llx, bb.lly, bb.urx, bb.ury); + exit(0); +} + +/* If the bounding box was found return NULL, and store the bounding box +in bb. If the bounding box was not found return a string suitable for +giving to printf with the filename as an argument saying why not. */ + +const char *do_file(fp, bb) +FILE *fp; +struct bounding_box *bb; +{ + int bb_at_end = 0; + char buf[256]; + if (!fgets(buf, sizeof(buf), fp)) + return "%s is empty"; + if (strncmp("%!PS-Adobe-", buf, 11) != 0) + return "%s is not conforming"; + while (fgets(buf, sizeof(buf), fp) != 0) { + if (buf[0] != '%' || buf[1] != '%' + || strncmp(buf + 2, "EndComments", 11) == 0) + break; + if (strncmp(buf + 2, "BoundingBox:", 12) == 0) { + int res = parse_bounding_box(buf + 14, bb); + if (res == 1) + return NULL; + else if (res == 2) { + bb_at_end = 1; + break; + } + else + return "the arguments to the %%%%BoundingBox comment in %s are bad"; + } + } + if (bb_at_end) { + long offset; + int last_try = 0; + /* in the trailer, the last BoundingBox comment is significant */ + for (offset = 512; !last_try; offset *= 2) { + int had_trailer = 0; + int got_bb = 0; + if (offset > 32768 || fseek(fp, -offset, 2) == -1) { + last_try = 1; + if (fseek(fp, 0L, 0) == -1) + break; + } + while (fgets(buf, sizeof(buf), fp) != 0) { + if (buf[0] == '%' && buf[1] == '%') { + if (!had_trailer) { + if (strncmp(buf + 2, "Trailer", 7) == 0) + had_trailer = 1; + } + else { + if (strncmp(buf + 2, "BoundingBox:", 12) == 0) { + int res = parse_bounding_box(buf + 14, bb); + if (res == 1) + got_bb = 1; + else if (res == 2) + return "`(atend)' not allowed in trailer"; + else + return "the arguments to the %%%%BoundingBox comment in %s are bad"; + } + } + } + } + if (got_bb) + return NULL; + } + } + return "%%%%BoundingBox comment not found in %s"; +} + +/* Parse the argument to a %%BoundingBox comment. Return 1 if it +contains 4 numbers, 2 if it contains (atend), 0 otherwise. */ + +int parse_bounding_box(p, bb) +char *p; +struct bounding_box *bb; +{ + if (sscanf(p, "%d %d %d %d", + &bb->llx, &bb->lly, &bb->urx, &bb->ury) == 4) + return 1; + else { + /* The Document Structuring Conventions say that the numbers + should be integers. Unfortunately some broken applications + get this wrong. */ + double x1, x2, x3, x4; + if (sscanf(p, "%lf %lf %lf %lf", &x1, &x2, &x3, &x4) == 4) { + bb->llx = (int)x1; + bb->lly = (int)x2; + bb->urx = (int)x3; + bb->ury = (int)x4; + return 1; + } + else { + for (; *p == ' ' || *p == '\t'; p++) + ; + if (strncmp(p, "(atend)", 7) == 0) { + return 2; + } + } + } + return 0; +} + diff --git a/gnu/usr.bin/groff/refer/Makefile b/gnu/usr.bin/groff/refer/Makefile new file mode 100644 index 0000000000..a812435f41 --- /dev/null +++ b/gnu/usr.bin/groff/refer/Makefile @@ -0,0 +1,15 @@ +# Makefile for refer + +PROG= refer +SRCS= command.cc ref.cc refer.cc token.cc +OBJS= label.o +CFLAGS+= -I. -I$(.CURDIR)/../include +LDADD+= $(LIBBIB) $(LIBGROFF) -lm +DPADD+= $(LIBBIB) $(LIBGROFF) $(LIBMATH) + +CLEANFILES+= label.cc label.tab.h + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/refer/Makefile.dep b/gnu/usr.bin/groff/refer/Makefile.dep new file mode 100644 index 0000000000..6a6c987341 --- /dev/null +++ b/gnu/usr.bin/groff/refer/Makefile.dep @@ -0,0 +1,17 @@ +command.o : command.cc refer.h ../include/errarg.h ../include/error.h \ + ../include/lib.h ../include/stringclass.h ../include/cset.h \ + ../include/cmap.h ../include/defs.h ../include/refid.h \ + ../include/search.h command.h +ref.o : ref.cc refer.h ../include/errarg.h ../include/error.h \ + ../include/lib.h ../include/stringclass.h ../include/cset.h \ + ../include/cmap.h ../include/defs.h ../include/refid.h ref.h token.h +refer.o : refer.cc refer.h ../include/errarg.h ../include/error.h \ + ../include/lib.h ../include/stringclass.h ../include/cset.h \ + ../include/cmap.h ../include/defs.h ../include/refid.h ref.h token.h \ + ../include/search.h command.h +token.o : token.cc refer.h ../include/errarg.h ../include/error.h \ + ../include/lib.h ../include/stringclass.h ../include/cset.h \ + ../include/cmap.h ../include/defs.h token.h +label.o : label.cc refer.h ../include/errarg.h ../include/error.h \ + ../include/lib.h ../include/stringclass.h ../include/cset.h \ + ../include/cmap.h ../include/defs.h ../include/refid.h ref.h token.h diff --git a/gnu/usr.bin/groff/refer/command.cc b/gnu/usr.bin/groff/refer/command.cc new file mode 100644 index 0000000000..93b6cfe95e --- /dev/null +++ b/gnu/usr.bin/groff/refer/command.cc @@ -0,0 +1,807 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "refer.h" +#include "refid.h" +#include "search.h" +#include "command.h" + +cset cs_field_name = csalpha; + +class input_item { + input_item *next; + char *filename; + int first_lineno; + string buffer; + const char *ptr; + const char *end; +public: + input_item(string &, const char *, int = 1); + ~input_item(); + int get_char(); + int peek_char(); + void skip_char(); + int get_location(const char **, int *); + + friend class input_stack; +}; + +input_item::input_item(string &s, const char *fn, int ln) +: filename(strsave(fn)), first_lineno(ln) +{ + buffer.move(s); + ptr = buffer.contents(); + end = ptr + buffer.length(); +} + +input_item::~input_item() +{ + a_delete filename; +} + +inline int input_item::peek_char() +{ + if (ptr >= end) + return EOF; + else + return (unsigned char)*ptr; +} + +inline int input_item::get_char() +{ + if (ptr >= end) + return EOF; + else + return (unsigned char)*ptr++; +} + +inline void input_item::skip_char() +{ + ptr++; +} + +int input_item::get_location(const char **filenamep, int *linenop) +{ + *filenamep = filename; + if (ptr == buffer.contents()) + *linenop = first_lineno; + else { + int ln = first_lineno; + const char *e = ptr - 1; + for (const char *p = buffer.contents(); p < e; p++) + if (*p == '\n') + ln++; + *linenop = ln; + } + return 1; +} + +class input_stack { + static input_item *top; +public: + static void init(); + static int get_char(); + static int peek_char(); + static void skip_char() { top->skip_char(); } + static void push_file(const char *); + static void push_string(string &, const char *, int); + static void error(const char *format, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); +}; + +input_item *input_stack::top = 0; + +void input_stack::init() +{ + while (top) { + input_item *tem = top; + top = top->next; + delete tem; + } +} + +int input_stack::get_char() +{ + while (top) { + int c = top->get_char(); + if (c >= 0) + return c; + input_item *tem = top; + top = top->next; + delete tem; + } + return -1; +} + +int input_stack::peek_char() +{ + while (top) { + int c = top->peek_char(); + if (c >= 0) + return c; + input_item *tem = top; + top = top->next; + delete tem; + } + return -1; +} + +void input_stack::push_file(const char *fn) +{ + FILE *fp; + if (strcmp(fn, "-") == 0) { + fp = stdin; + fn = ""; + } + else { + errno = 0; + fp = fopen(fn, "r"); + if (fp == 0) { + error("can't open `%1': %2", fn, strerror(errno)); + return; + } + } + string buf; + int bol = 1; + int lineno = 1; + for (;;) { + int c = getc(fp); + if (bol && c == '.') { + // replace lines beginning with .R1 or .R2 with a blank line + c = getc(fp); + if (c == 'R') { + c = getc(fp); + if (c == '1' || c == '2') { + int cc = c; + c = getc(fp); + if (compatible_flag || c == ' ' || c == '\n' || c == EOF) { + while (c != '\n' && c != EOF) + c = getc(fp); + } + else { + buf += '.'; + buf += 'R'; + buf += cc; + } + } + else { + buf += '.'; + buf += 'R'; + } + } + else + buf += '.'; + } + if (c == EOF) + break; + if (illegal_input_char(c)) + error_with_file_and_line(fn, lineno, + "illegal input character code %1", int(c)); + else { + buf += c; + if (c == '\n') { + bol = 1; + lineno++; + } + else + bol = 0; + } + } + if (fp != stdin) + fclose(fp); + if (buf.length() > 0 && buf[buf.length() - 1] != '\n') + buf += '\n'; + input_item *it = new input_item(buf, fn); + it->next = top; + top = it; +} + +void input_stack::push_string(string &s, const char *filename, int lineno) +{ + input_item *it = new input_item(s, filename, lineno); + it->next = top; + top = it; +} + +void input_stack::error(const char *format, const errarg &arg1, + const errarg &arg2, const errarg &arg3) +{ + const char *filename; + int lineno; + for (input_item *it = top; it; it = it->next) + if (it->get_location(&filename, &lineno)) { + error_with_file_and_line(filename, lineno, format, arg1, arg2, arg3); + return; + } + ::error(format, arg1, arg2, arg3); +} + +void command_error(const char *format, const errarg &arg1, + const errarg &arg2, const errarg &arg3) +{ + input_stack::error(format, arg1, arg2, arg3); +} + +// # not recognized in "" +// \ is recognized in "" +// # does not conceal newline +// if missing closing quote, word extends to end of line +// no special treatment of \ other than before newline +// \ not recognized after # +// ; allowed as alternative to newline +// ; not recognized in "" +// don't clear word_buffer; just append on +// return -1 for EOF, 0 for newline, 1 for word + +int get_word(string &word_buffer) +{ + int c = input_stack::get_char(); + for (;;) { + if (c == '#') { + do { + c = input_stack::get_char(); + } while (c != '\n' && c != EOF); + break; + } + if (c == '\\' && input_stack::peek_char() == '\n') + input_stack::skip_char(); + else if (c != ' ' && c != '\t') + break; + c = input_stack::get_char(); + } + if (c == EOF) + return -1; + if (c == '\n' || c == ';') + return 0; + if (c == '"') { + for (;;) { + c = input_stack::peek_char(); + if (c == EOF || c == '\n') + break; + input_stack::skip_char(); + if (c == '"') { + int d = input_stack::peek_char(); + if (d == '"') + input_stack::skip_char(); + else + break; + } + else if (c == '\\') { + int d = input_stack::peek_char(); + if (d == '\n') + input_stack::skip_char(); + else + word_buffer += '\\'; + } + else + word_buffer += c; + } + return 1; + } + word_buffer += c; + for (;;) { + c = input_stack::peek_char(); + if (c == ' ' || c == '\t' || c == '\n' || c == '#' || c == ';') + break; + input_stack::skip_char(); + if (c == '\\') { + int d = input_stack::peek_char(); + if (d == '\n') + input_stack::skip_char(); + else + word_buffer += '\\'; + } + else + word_buffer += c; + } + return 1; +} + +union argument { + const char *s; + int n; +}; + +// This is for debugging. + +static void echo_command(int argc, argument *argv) +{ + for (int i = 0; i < argc; i++) + fprintf(stderr, "%s\n", argv[i].s); +} + +static void include_command(int argc, argument *argv) +{ + assert(argc == 1); + input_stack::push_file(argv[0].s); +} + +static void capitalize_command(int argc, argument *argv) +{ + if (argc > 0) + capitalize_fields = argv[0].s; + else + capitalize_fields.clear(); +} + +static void accumulate_command(int, argument *) +{ + accumulate = 1; +} + +static void no_accumulate_command(int, argument *) +{ + accumulate = 0; +} + +static void move_punctuation_command(int, argument *) +{ + move_punctuation = 1; +} + +static void no_move_punctuation_command(int, argument *) +{ + move_punctuation = 0; +} + +static void sort_command(int argc, argument *argv) +{ + if (argc == 0) + sort_fields = "AD"; + else + sort_fields = argv[0].s; + accumulate = 1; +} + +static void no_sort_command(int, argument *) +{ + sort_fields.clear(); +} + +static void articles_command(int argc, argument *argv) +{ + articles.clear(); + int i; + for (i = 0; i < argc; i++) { + articles += argv[i].s; + articles += '\0'; + } + int len = articles.length(); + for (i = 0; i < len; i++) + articles[i] = cmlower(articles[i]); +} + +static void database_command(int argc, argument *argv) +{ + for (int i = 0; i < argc; i++) + database_list.add_file(argv[i].s); +} + +static void default_database_command(int, argument *) +{ + search_default = 1; +} + +static void no_default_database_command(int, argument *) +{ + search_default = 0; +} + +static void bibliography_command(int argc, argument *argv) +{ + const char *saved_filename = current_filename; + int saved_lineno = current_lineno; + int saved_label_in_text = label_in_text; + label_in_text = 0; + if (!accumulate) + fputs(".]<\n", stdout); + for (int i = 0; i < argc; i++) + do_bib(argv[i].s); + if (accumulate) + output_references(); + else + fputs(".]>\n", stdout); + current_filename = saved_filename; + current_lineno = saved_lineno; + label_in_text = saved_label_in_text; +} + +static void annotate_command(int argc, argument *argv) +{ + if (argc > 0) + annotation_field = argv[0].s[0]; + else + annotation_field = 'X'; + if (argc == 2) + annotation_macro = argv[1].s; + else + annotation_macro = "AP"; +} + +static void no_annotate_command(int, argument *) +{ + annotation_macro.clear(); + annotation_field = -1; +} + +static void reverse_command(int, argument *argv) +{ + reverse_fields = argv[0].s; +} + +static void no_reverse_command(int, argument *) +{ + reverse_fields.clear(); +} + +static void abbreviate_command(int argc, argument *argv) +{ + abbreviate_fields = argv[0].s; + period_before_initial = argc > 1 ? argv[1].s : ". "; + period_before_last_name = argc > 2 ? argv[2].s : ". "; + period_before_other = argc > 3 ? argv[3].s : ". "; + period_before_hyphen = argc > 4 ? argv[4].s : "."; +} + +static void no_abbreviate_command(int, argument *) +{ + abbreviate_fields.clear(); +} + +string search_ignore_fields; + +static void search_ignore_command(int argc, argument *argv) +{ + if (argc > 0) + search_ignore_fields = argv[0].s; + else + search_ignore_fields = "XYZ"; + search_ignore_fields += '\0'; + linear_ignore_fields = search_ignore_fields.contents(); +} + +static void no_search_ignore_command(int, argument *) +{ + linear_ignore_fields = ""; +} + +static void search_truncate_command(int argc, argument *argv) +{ + if (argc > 0) + linear_truncate_len = argv[0].n; + else + linear_truncate_len = 6; +} + +static void no_search_truncate_command(int, argument *) +{ + linear_truncate_len = -1; +} + +static void discard_command(int argc, argument *argv) +{ + if (argc == 0) + discard_fields = "XYZ"; + else + discard_fields = argv[0].s; + accumulate = 1; +} + +static void no_discard_command(int, argument *) +{ + discard_fields.clear(); +} + +static void label_command(int, argument *argv) +{ + set_label_spec(argv[0].s); +} + +static void abbreviate_label_ranges_command(int argc, argument *argv) +{ + abbreviate_label_ranges = 1; + label_range_indicator = argc > 0 ? argv[0].s : "-"; +} + +static void no_abbreviate_label_ranges_command(int, argument *) +{ + abbreviate_label_ranges = 0; +} + +static void label_in_reference_command(int, argument *) +{ + label_in_reference = 1; +} + +static void no_label_in_reference_command(int, argument *) +{ + label_in_reference = 0; +} + +static void label_in_text_command(int, argument *) +{ + label_in_text = 1; +} + +static void no_label_in_text_command(int, argument *) +{ + label_in_text = 0; +} + +static void sort_adjacent_labels_command(int, argument *) +{ + sort_adjacent_labels = 1; +} + +static void no_sort_adjacent_labels_command(int, argument *) +{ + sort_adjacent_labels = 0; +} + +static void date_as_label_command(int argc, argument *argv) +{ + if (set_date_label_spec(argc > 0 ? argv[0].s : "D%a*")) + date_as_label = 1; +} + +static void no_date_as_label_command(int, argument *) +{ + date_as_label = 0; +} + +static void short_label_command(int, argument *argv) +{ + if (set_short_label_spec(argv[0].s)) + short_label_flag = 1; +} + +static void no_short_label_command(int, argument *) +{ + short_label_flag = 0; +} + +static void compatible_command(int, argument *) +{ + compatible_flag = 1; +} + +static void no_compatible_command(int, argument *) +{ + compatible_flag = 0; +} + +static void join_authors_command(int argc, argument *argv) +{ + join_authors_exactly_two = argv[0].s; + join_authors_default = argc > 1 ? argv[1].s : argv[0].s; + join_authors_last_two = argc == 3 ? argv[2].s : argv[0].s; +} + +static void bracket_label_command(int, argument *argv) +{ + pre_label = argv[0].s; + post_label = argv[1].s; + sep_label = argv[2].s; +} + +static void separate_label_second_parts_command(int, argument *argv) +{ + separate_label_second_parts = argv[0].s; +} + +static void et_al_command(int argc, argument *argv) +{ + et_al = argv[0].s; + et_al_min_elide = argv[1].n; + if (et_al_min_elide < 1) + et_al_min_elide = 1; + et_al_min_total = argc >= 3 ? argv[2].n : 0; +} + +static void no_et_al_command(int, argument *) +{ + et_al.clear(); + et_al_min_elide = 0; +} + +typedef void (*command_t)(int, argument *); + +/* arg_types is a string describing the numbers and types of arguments. +s means a string, i means an integer, f is a list of fields, F is +a single field, +? means that the previous argument is optional, * means that the +previous argument can occur any number of times. */ + +struct { + const char *name; + command_t func; + const char *arg_types; +} command_table[] = { + "include", include_command, "s", + "echo", echo_command, "s*", + "capitalize", capitalize_command, "f?", + "accumulate", accumulate_command, "", + "no-accumulate", no_accumulate_command, "", + "move-punctuation", move_punctuation_command, "", + "no-move-punctuation", no_move_punctuation_command, "", + "sort", sort_command, "s?", + "no-sort", no_sort_command, "", + "articles", articles_command, "s*", + "database", database_command, "ss*", + "default-database", default_database_command, "", + "no-default-database", no_default_database_command, "", + "bibliography", bibliography_command, "ss*", + "annotate", annotate_command, "F?s?", + "no-annotate", no_annotate_command, "", + "reverse", reverse_command, "s", + "no-reverse", no_reverse_command, "", + "abbreviate", abbreviate_command, "ss?s?s?s?", + "no-abbreviate", no_abbreviate_command, "", + "search-ignore", search_ignore_command, "f?", + "no-search-ignore", no_search_ignore_command, "", + "search-truncate", search_truncate_command, "i?", + "no-search-truncate", no_search_truncate_command, "", + "discard", discard_command, "f?", + "no-discard", no_discard_command, "", + "label", label_command, "s", + "abbreviate-label-ranges", abbreviate_label_ranges_command, "s?", + "no-abbreviate-label-ranges", no_abbreviate_label_ranges_command, "", + "label-in-reference", label_in_reference_command, "", + "no-label-in-reference", no_label_in_reference_command, "", + "label-in-text", label_in_text_command, "", + "no-label-in-text", no_label_in_text_command, "", + "sort-adjacent-labels", sort_adjacent_labels_command, "", + "no-sort-adjacent-labels", no_sort_adjacent_labels_command, "", + "date-as-label", date_as_label_command, "s?", + "no-date-as-label", no_date_as_label_command, "", + "short-label", short_label_command, "s", + "no-short-label", no_short_label_command, "", + "compatible", compatible_command, "", + "no-compatible", no_compatible_command, "", + "join-authors", join_authors_command, "sss?", + "bracket-label", bracket_label_command, "sss", + "separate-label-second-parts", separate_label_second_parts_command, "s", + "et-al", et_al_command, "sii?", + "no-et-al", no_et_al_command, "", +}; + +static int check_args(const char *types, const char *name, + int argc, argument *argv) +{ + int argno = 0; + while (*types) { + if (argc == 0) { + if (types[1] == '?') + break; + else if (types[1] == '*') { + assert(types[2] == '\0'); + break; + } + else { + input_stack::error("missing argument for command `%1'", name); + return 0; + } + } + switch (*types) { + case 's': + break; + case 'i': + { + char *ptr; + long n = strtol(argv->s, &ptr, 10); + if ((n == 0 && ptr == argv->s) + || *ptr != '\0') { + input_stack::error("argument %1 for command `%2' must be an integer", + argno + 1, name); + return 0; + } + argv->n = (int)n; + break; + } + case 'f': + { + for (const char *ptr = argv->s; *ptr != '\0'; ptr++) + if (!cs_field_name(*ptr)) { + input_stack::error("argument %1 for command `%2' must be a list of fields", + argno + 1, name); + return 0; + } + break; + } + case 'F': + if (argv->s[0] == '\0' || argv->s[1] != '\0' + || !cs_field_name(argv->s[0])) { + input_stack::error("argument %1 for command `%2' must be a field name", + argno + 1, name); + return 0; + } + break; + default: + assert(0); + } + if (types[1] == '?') + types += 2; + else if (types[1] != '*') + types += 1; + --argc; + ++argv; + ++argno; + } + if (argc > 0) { + input_stack::error("too many arguments for command `%1'", name); + return 0; + } + return 1; +} + +static void execute_command(const char *name, int argc, argument *argv) +{ + for (int i = 0; i < sizeof(command_table)/sizeof(command_table[0]); i++) + if (strcmp(name, command_table[i].name) == 0) { + if (check_args(command_table[i].arg_types, name, argc, argv)) + (*command_table[i].func)(argc, argv); + return; + } + input_stack::error("unknown command `%1'", name); +} + +static void command_loop() +{ + string command; + for (;;) { + command.clear(); + int res = get_word(command); + if (res != 1) { + if (res == 0) + continue; + break; + } + int argc = 0; + command += '\0'; + while ((res = get_word(command)) == 1) { + argc++; + command += '\0'; + } + argument *argv = new argument[argc]; + const char *ptr = command.contents(); + for (int i = 0; i < argc; i++) + argv[i].s = ptr = strchr(ptr, '\0') + 1; + execute_command(command.contents(), argc, argv); + a_delete argv; + if (res == -1) + break; + } +} + +void process_commands(const char *file) +{ + input_stack::init(); + input_stack::push_file(file); + command_loop(); +} + +void process_commands(string &s, const char *file, int lineno) +{ + input_stack::init(); + input_stack::push_string(s, file, lineno); + command_loop(); +} diff --git a/gnu/usr.bin/groff/refer/command.h b/gnu/usr.bin/groff/refer/command.h new file mode 100644 index 0000000000..2b977eae9a --- /dev/null +++ b/gnu/usr.bin/groff/refer/command.h @@ -0,0 +1,36 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +void process_commands(const char *file); +void process_commands(string &s, const char *file, int lineno); + +extern int accumulate; +extern int move_punctuation; +extern int search_default; +extern search_list database_list; +extern int label_in_text; +extern int label_in_reference; +extern int sort_adjacent_labels; +extern string pre_label; +extern string post_label; +extern string sep_label; + +extern void do_bib(const char *); +extern void output_references(); diff --git a/gnu/usr.bin/groff/refer/label.y b/gnu/usr.bin/groff/refer/label.y new file mode 100644 index 0000000000..d18eb89a98 --- /dev/null +++ b/gnu/usr.bin/groff/refer/label.y @@ -0,0 +1,1173 @@ +/* -*- C++ -*- + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +%{ + +#include "refer.h" +#include "refid.h" +#include "ref.h" +#include "token.h" + +int yylex(); +void yyerror(const char *); +int yyparse(); + +static const char *format_serial(char c, int n); + +struct label_info { + int start; + int length; + int count; + int total; + label_info(const string &); +}; + +label_info *lookup_label(const string &label); + +struct expression { + enum { + // Does the tentative label depend on the reference? + CONTAINS_VARIABLE = 01, + CONTAINS_STAR = 02, + CONTAINS_FORMAT = 04, + CONTAINS_AT = 010 + }; + virtual ~expression() { } + virtual void evaluate(int, const reference &, string &, + substring_position &) = 0; + virtual unsigned analyze() { return 0; } +}; + +class at_expr : public expression { +public: + at_expr() { } + void evaluate(int, const reference &, string &, substring_position &); + unsigned analyze() { return CONTAINS_VARIABLE|CONTAINS_AT; } +}; + +class format_expr : public expression { + char type; + int width; + int first_number; +public: + format_expr(char c, int w = 0, int f = 1) + : type(c), width(w), first_number(f) { } + void evaluate(int, const reference &, string &, substring_position &); + unsigned analyze() { return CONTAINS_FORMAT; } +}; + +class field_expr : public expression { + int number; + char name; +public: + field_expr(char nm, int num) : name(nm), number(num) { } + void evaluate(int, const reference &, string &, substring_position &); + unsigned analyze() { return CONTAINS_VARIABLE; } +}; + +class literal_expr : public expression { + string s; +public: + literal_expr(const char *ptr, int len) : s(ptr, len) { } + void evaluate(int, const reference &, string &, substring_position &); +}; + +class unary_expr : public expression { +protected: + expression *expr; +public: + unary_expr(expression *e) : expr(e) { } + ~unary_expr() { delete expr; } + void evaluate(int, const reference &, string &, substring_position &) = 0; + unsigned analyze() { return expr ? expr->analyze() : 0; } +}; + +// This caches the analysis of an expression. + +class analyzed_expr : public unary_expr { + unsigned flags; +public: + analyzed_expr(expression *); + void evaluate(int, const reference &, string &, substring_position &); + unsigned analyze() { return flags; } +}; + +class star_expr : public unary_expr { +public: + star_expr(expression *e) : unary_expr(e) { } + void evaluate(int, const reference &, string &, substring_position &); + unsigned analyze() { + return ((expr ? (expr->analyze() & ~CONTAINS_VARIABLE) : 0) + | CONTAINS_STAR); + } +}; + +typedef void map_t(const char *, const char *, string &); + +class map_expr : public unary_expr { + map_t *func; +public: + map_expr(expression *e, map_t *f) : unary_expr(e), func(f) { } + void evaluate(int, const reference &, string &, substring_position &); +}; + +typedef const char *extractor_t(const char *, const char *, const char **); + +class extractor_expr : public unary_expr { + int part; + extractor_t *func; +public: + enum { BEFORE = +1, MATCH = 0, AFTER = -1 }; + extractor_expr(expression *e, extractor_t *f, int pt) + : unary_expr(e), func(f), part(pt) { } + void evaluate(int, const reference &, string &, substring_position &); +}; + +class truncate_expr : public unary_expr { + int n; +public: + truncate_expr(expression *e, int i) : n(i), unary_expr(e) { } + void evaluate(int, const reference &, string &, substring_position &); +}; + +class separator_expr : public unary_expr { +public: + separator_expr(expression *e) : unary_expr(e) { } + void evaluate(int, const reference &, string &, substring_position &); +}; + +class binary_expr : public expression { +protected: + expression *expr1; + expression *expr2; +public: + binary_expr(expression *e1, expression *e2) : expr1(e1), expr2(e2) { } + ~binary_expr() { delete expr1; delete expr2; } + void evaluate(int, const reference &, string &, substring_position &) = 0; + unsigned analyze() { + return (expr1 ? expr1->analyze() : 0) | (expr2 ? expr2->analyze() : 0); + } +}; + +class alternative_expr : public binary_expr { +public: + alternative_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { } + void evaluate(int, const reference &, string &, substring_position &); +}; + +class list_expr : public binary_expr { +public: + list_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { } + void evaluate(int, const reference &, string &, substring_position &); +}; + +class substitute_expr : public binary_expr { +public: + substitute_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { } + void evaluate(int, const reference &, string &, substring_position &); +}; + +class ternary_expr : public expression { +protected: + expression *expr1; + expression *expr2; + expression *expr3; +public: + ternary_expr(expression *e1, expression *e2, expression *e3) + : expr1(e1), expr2(e2), expr3(e3) { } + ~ternary_expr() { delete expr1; delete expr2; delete expr3; } + void evaluate(int, const reference &, string &, substring_position &) = 0; + unsigned analyze() { + return ((expr1 ? expr1->analyze() : 0) + | (expr2 ? expr2->analyze() : 0) + | (expr3 ? expr3->analyze() : 0)); + } +}; + +class conditional_expr : public ternary_expr { +public: + conditional_expr(expression *e1, expression *e2, expression *e3) + : ternary_expr(e1, e2, e3) { } + void evaluate(int, const reference &, string &, substring_position &); +}; + +static expression *parsed_label = 0; +static expression *parsed_date_label = 0; +static expression *parsed_short_label = 0; + +static expression *parse_result; + +string literals; + +%} + +%union { + int num; + expression *expr; + struct { int ndigits; int val; } dig; + struct { int start; int len; } str; +} + +/* uppercase or lowercase letter */ +%token TOKEN_LETTER +/* literal characters */ +%token TOKEN_LITERAL +/* digit */ +%token TOKEN_DIGIT + +%type conditional +%type alternative +%type list +%type string +%type substitute +%type optional_conditional +%type number +%type digits +%type optional_number +%type flag + +%% + +expr: + optional_conditional + { parse_result = ($1 ? new analyzed_expr($1) : 0); } + ; + +conditional: + alternative + { $$ = $1; } + | alternative '?' optional_conditional ':' conditional + { $$ = new conditional_expr($1, $3, $5); } + ; + +optional_conditional: + /* empty */ + { $$ = 0; } + | conditional + { $$ = $1; } + ; + +alternative: + list + { $$ = $1; } + | alternative '|' list + { $$ = new alternative_expr($1, $3); } + | alternative '&' list + { $$ = new conditional_expr($1, $3, 0); } + ; + +list: + substitute + { $$ = $1; } + | list substitute + { $$ = new list_expr($1, $2); } + ; + +substitute: + string + { $$ = $1; } + | substitute '~' string + { $$ = new substitute_expr($1, $3); } + ; + +string: + '@' + { $$ = new at_expr; } + | TOKEN_LITERAL + { + $$ = new literal_expr(literals.contents() + $1.start, + $1.len); + } + | TOKEN_LETTER + { $$ = new field_expr($1, 0); } + | TOKEN_LETTER number + { $$ = new field_expr($1, $2 - 1); } + | '%' TOKEN_LETTER + { + switch ($2) { + case 'I': + case 'i': + case 'A': + case 'a': + $$ = new format_expr($2); + break; + default: + command_error("unrecognized format `%1'", char($2)); + $$ = new format_expr('a'); + break; + } + } + + | '%' digits + { + $$ = new format_expr('0', $2.ndigits, $2.val); + } + | string '.' flag TOKEN_LETTER optional_number + { + switch ($4) { + case 'l': + $$ = new map_expr($1, lowercase); + break; + case 'u': + $$ = new map_expr($1, uppercase); + break; + case 'c': + $$ = new map_expr($1, capitalize); + break; + case 'r': + $$ = new map_expr($1, reverse_name); + break; + case 'a': + $$ = new map_expr($1, abbreviate_name); + break; + case 'y': + $$ = new extractor_expr($1, find_year, $3); + break; + case 'n': + $$ = new extractor_expr($1, find_last_name, $3); + break; + default: + $$ = $1; + command_error("unknown function `%1'", char($4)); + break; + } + } + + | string '+' number + { $$ = new truncate_expr($1, $3); } + | string '-' number + { $$ = new truncate_expr($1, -$3); } + | string '*' + { $$ = new star_expr($1); } + | '(' optional_conditional ')' + { $$ = $2; } + | '<' optional_conditional '>' + { $$ = new separator_expr($2); } + ; + +optional_number: + /* empty */ + { $$ = -1; } + | number + { $$ = $1; } + ; + +number: + TOKEN_DIGIT + { $$ = $1; } + | number TOKEN_DIGIT + { $$ = $1*10 + $2; } + ; + +digits: + TOKEN_DIGIT + { $$.ndigits = 1; $$.val = $1; } + | digits TOKEN_DIGIT + { $$.ndigits = $1.ndigits + 1; $$.val = $1.val*10 + $2; } + ; + + +flag: + /* empty */ + { $$ = 0; } + | '+' + { $$ = 1; } + | '-' + { $$ = -1; } + ; + +%% + +/* bison defines const to be empty unless __STDC__ is defined, which it +isn't under cfront */ + +#ifdef const +#undef const +#endif + +const char *spec_ptr; +const char *spec_end; +const char *spec_cur; + +int yylex() +{ + while (spec_ptr < spec_end && csspace(*spec_ptr)) + spec_ptr++; + spec_cur = spec_ptr; + if (spec_ptr >= spec_end) + return 0; + unsigned char c = *spec_ptr++; + if (csalpha(c)) { + yylval.num = c; + return TOKEN_LETTER; + } + if (csdigit(c)) { + yylval.num = c - '0'; + return TOKEN_DIGIT; + } + if (c == '\'') { + yylval.str.start = literals.length(); + for (; spec_ptr < spec_end; spec_ptr++) { + if (*spec_ptr == '\'') { + if (++spec_ptr < spec_end && *spec_ptr == '\'') + literals += '\''; + else { + yylval.str.len = literals.length() - yylval.str.start; + return TOKEN_LITERAL; + } + } + else + literals += *spec_ptr; + } + yylval.str.len = literals.length() - yylval.str.start; + return TOKEN_LITERAL; + } + return c; +} + +int set_label_spec(const char *label_spec) +{ + spec_cur = spec_ptr = label_spec; + spec_end = strchr(label_spec, '\0'); + literals.clear(); + if (yyparse()) + return 0; + delete parsed_label; + parsed_label = parse_result; + return 1; +} + +int set_date_label_spec(const char *label_spec) +{ + spec_cur = spec_ptr = label_spec; + spec_end = strchr(label_spec, '\0'); + literals.clear(); + if (yyparse()) + return 0; + delete parsed_date_label; + parsed_date_label = parse_result; + return 1; +} + +int set_short_label_spec(const char *label_spec) +{ + spec_cur = spec_ptr = label_spec; + spec_end = strchr(label_spec, '\0'); + literals.clear(); + if (yyparse()) + return 0; + delete parsed_short_label; + parsed_short_label = parse_result; + return 1; +} + +void yyerror(const char *message) +{ + if (spec_cur < spec_end) + command_error("label specification %1 before `%2'", message, spec_cur); + else + command_error("label specification %1 at end of string", + message, spec_cur); +} + +void at_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &) +{ + if (tentative) + ref.canonicalize_authors(result); + else { + const char *end, *start = ref.get_authors(&end); + if (start) + result.append(start, end - start); + } +} + +void format_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &) +{ + if (tentative) + return; + const label_info *lp = ref.get_label_ptr(); + int num = lp == 0 ? ref.get_number() : lp->count; + if (type != '0') + result += format_serial(type, num + 1); + else { + const char *ptr = itoa(num + first_number); + int pad = width - strlen(ptr); + while (--pad >= 0) + result += '0'; + result += ptr; + } +} + +static const char *format_serial(char c, int n) +{ + assert(n > 0); + static char buf[128]; // more than enough. + switch (c) { + case 'i': + case 'I': + { + char *p = buf; + // troff uses z and w to represent 10000 and 5000 in Roman + // numerals; I can find no historical basis for this usage + const char *s = c == 'i' ? "zwmdclxvi" : "ZWMDCLXVI"; + if (n >= 40000) + return itoa(n); + while (n >= 10000) { + *p++ = s[0]; + n -= 10000; + } + for (int i = 1000; i > 0; i /= 10, s += 2) { + int m = n/i; + n -= m*i; + switch (m) { + case 3: + *p++ = s[2]; + /* falls through */ + case 2: + *p++ = s[2]; + /* falls through */ + case 1: + *p++ = s[2]; + break; + case 4: + *p++ = s[2]; + *p++ = s[1]; + break; + case 8: + *p++ = s[1]; + *p++ = s[2]; + *p++ = s[2]; + *p++ = s[2]; + break; + case 7: + *p++ = s[1]; + *p++ = s[2]; + *p++ = s[2]; + break; + case 6: + *p++ = s[1]; + *p++ = s[2]; + break; + case 5: + *p++ = s[1]; + break; + case 9: + *p++ = s[2]; + *p++ = s[0]; + } + } + *p = 0; + break; + } + case 'a': + case 'A': + { + char *p = buf; + // this is derived from troff/reg.c + while (n > 0) { + int d = n % 26; + if (d == 0) + d = 26; + n -= d; + n /= 26; + *p++ = c + d - 1; // ASCII dependent + } + *p-- = 0; + // Reverse it. + char *q = buf; + while (q < p) { + char temp = *q; + *q = *p; + *p = temp; + --p; + ++q; + } + break; + } + default: + assert(0); + } + return buf; +} + +void field_expr::evaluate(int, const reference &ref, + string &result, substring_position &) +{ + const char *end; + const char *start = ref.get_field(name, &end); + if (start) { + start = nth_field(number, start, &end); + if (start) + result.append(start, end - start); + } +} + +void literal_expr::evaluate(int, const reference &, + string &result, substring_position &) +{ + result += s; +} + +analyzed_expr::analyzed_expr(expression *e) +: unary_expr(e), flags(e ? e->analyze() : 0) +{ +} + +void analyzed_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &pos) +{ + if (expr) + expr->evaluate(tentative, ref, result, pos); +} + +void star_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &pos) +{ + const label_info *lp = ref.get_label_ptr(); + if (!tentative + && (lp == 0 || lp->total > 1) + && expr) + expr->evaluate(tentative, ref, result, pos); +} + +void separator_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &pos) +{ + int start_length = result.length(); + int is_first = pos.start < 0; + if (expr) + expr->evaluate(tentative, ref, result, pos); + if (is_first) { + pos.start = start_length; + pos.length = result.length() - start_length; + } +} + +void map_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &) +{ + if (expr) { + string temp; + substring_position temp_pos; + expr->evaluate(tentative, ref, temp, temp_pos); + (*func)(temp.contents(), temp.contents() + temp.length(), result); + } +} + +void extractor_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &) +{ + if (expr) { + string temp; + substring_position temp_pos; + expr->evaluate(tentative, ref, temp, temp_pos); + const char *end, *start = (*func)(temp.contents(), + temp.contents() + temp.length(), + &end); + switch (part) { + case BEFORE: + if (start) + result.append(temp.contents(), start - temp.contents()); + else + result += temp; + break; + case MATCH: + if (start) + result.append(start, end - start); + break; + case AFTER: + if (start) + result.append(end, temp.contents() + temp.length() - end); + break; + default: + assert(0); + } + } +} + +static void first_part(int len, const char *ptr, const char *end, + string &result) +{ + for (;;) { + const char *token_start = ptr; + if (!get_token(&ptr, end)) + break; + const token_info *ti = lookup_token(token_start, ptr); + int counts = ti->sortify_non_empty(token_start, ptr); + if (counts && --len < 0) + break; + if (counts || ti->is_accent()) + result.append(token_start, ptr - token_start); + } +} + +static void last_part(int len, const char *ptr, const char *end, + string &result) +{ + const char *start = ptr; + int count = 0; + for (;;) { + const char *token_start = ptr; + if (!get_token(&ptr, end)) + break; + const token_info *ti = lookup_token(token_start, ptr); + if (ti->sortify_non_empty(token_start, ptr)) + count++; + } + ptr = start; + int skip = count - len; + if (skip > 0) { + for (;;) { + const char *token_start = ptr; + if (!get_token(&ptr, end)) + assert(0); + const token_info *ti = lookup_token(token_start, ptr); + if (ti->sortify_non_empty(token_start, ptr) && --skip < 0) { + ptr = token_start; + break; + } + } + } + first_part(len, ptr, end, result); +} + +void truncate_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &) +{ + if (expr) { + string temp; + substring_position temp_pos; + expr->evaluate(tentative, ref, temp, temp_pos); + const char *start = temp.contents(); + const char *end = start + temp.length(); + if (n > 0) + first_part(n, start, end, result); + else if (n < 0) + last_part(-n, start, end, result); + } +} + +void alternative_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &pos) +{ + int start_length = result.length(); + if (expr1) + expr1->evaluate(tentative, ref, result, pos); + if (result.length() == start_length && expr2) + expr2->evaluate(tentative, ref, result, pos); +} + +void list_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &pos) +{ + if (expr1) + expr1->evaluate(tentative, ref, result, pos); + if (expr2) + expr2->evaluate(tentative, ref, result, pos); +} + +void substitute_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &pos) +{ + int start_length = result.length(); + if (expr1) + expr1->evaluate(tentative, ref, result, pos); + if (result.length() > start_length && result[result.length() - 1] == '-') { + // ought to see if pos covers the - + result.set_length(result.length() - 1); + if (expr2) + expr2->evaluate(tentative, ref, result, pos); + } +} + +void conditional_expr::evaluate(int tentative, const reference &ref, + string &result, substring_position &pos) +{ + string temp; + substring_position temp_pos; + if (expr1) + expr1->evaluate(tentative, ref, temp, temp_pos); + if (temp.length() > 0) { + if (expr2) + expr2->evaluate(tentative, ref, result, pos); + } + else { + if (expr3) + expr3->evaluate(tentative, ref, result, pos); + } +} + +void reference::pre_compute_label() +{ + if (parsed_label != 0 + && (parsed_label->analyze() & expression::CONTAINS_VARIABLE)) { + label.clear(); + substring_position temp_pos; + parsed_label->evaluate(1, *this, label, temp_pos); + label_ptr = lookup_label(label); + } +} + +void reference::compute_label() +{ + label.clear(); + if (parsed_label) + parsed_label->evaluate(0, *this, label, separator_pos); + if (short_label_flag && parsed_short_label) + parsed_short_label->evaluate(0, *this, short_label, short_separator_pos); + if (date_as_label) { + string new_date; + if (parsed_date_label) { + substring_position temp_pos; + parsed_date_label->evaluate(0, *this, new_date, temp_pos); + } + set_date(new_date); + } + if (label_ptr) + label_ptr->count += 1; +} + +void reference::immediate_compute_label() +{ + if (label_ptr) + label_ptr->total = 2; // force use of disambiguator + compute_label(); +} + +int reference::merge_labels(reference **v, int n, label_type type, + string &result) +{ + if (abbreviate_label_ranges) + return merge_labels_by_number(v, n, type, result); + else + return merge_labels_by_parts(v, n, type, result); +} + +int reference::merge_labels_by_number(reference **v, int n, label_type type, + string &result) +{ + if (n <= 1) + return 0; + int num = get_number(); + // Only merge three or more labels. + if (v[0]->get_number() != num + 1 + || v[1]->get_number() != num + 2) + return 0; + for (int i = 2; i < n; i++) + if (v[i]->get_number() != num + i + 1) + break; + result = get_label(type); + result += label_range_indicator; + result += v[i - 1]->get_label(type); + return i; +} + +const substring_position &reference::get_separator_pos(label_type type) const +{ + if (type == SHORT_LABEL && short_label_flag) + return short_separator_pos; + else + return separator_pos; +} + +const string &reference::get_label(label_type type) const +{ + if (type == SHORT_LABEL && short_label_flag) + return short_label; + else + return label; +} + +int reference::merge_labels_by_parts(reference **v, int n, label_type type, + string &result) +{ + if (n <= 0) + return 0; + const string &lb = get_label(type); + const substring_position &sp = get_separator_pos(type); + if (sp.start < 0 + || sp.start != v[0]->get_separator_pos(type).start + || memcmp(lb.contents(), v[0]->get_label(type).contents(), + sp.start) != 0) + return 0; + result = lb; + int i = 0; + do { + result += separate_label_second_parts; + const substring_position &s = v[i]->get_separator_pos(type); + int sep_end_pos = s.start + s.length; + result.append(v[i]->get_label(type).contents() + sep_end_pos, + v[i]->get_label(type).length() - sep_end_pos); + } while (++i < n + && sp.start == v[i]->get_separator_pos(type).start + && memcmp(lb.contents(), v[i]->get_label(type).contents(), + sp.start) == 0); + return i; +} + +string label_pool; + +label_info::label_info(const string &s) +: count(0), total(1), length(s.length()), start(label_pool.length()) +{ + label_pool += s; +} + +static label_info **label_table = 0; +static int label_table_size = 0; +static int label_table_used = 0; + +label_info *lookup_label(const string &label) +{ + if (label_table == 0) { + label_table = new label_info *[17]; + label_table_size = 17; + for (int i = 0; i < 17; i++) + label_table[i] = 0; + } + unsigned h = hash_string(label.contents(), label.length()) % label_table_size; + for (label_info **ptr = label_table + h; + *ptr != 0; + (ptr == label_table) + ? (ptr = label_table + label_table_size - 1) + : ptr--) + if ((*ptr)->length == label.length() + && memcmp(label_pool.contents() + (*ptr)->start, label.contents(), + label.length()) == 0) { + (*ptr)->total += 1; + return *ptr; + } + label_info *result = *ptr = new label_info(label); + if (++label_table_used * 2 > label_table_size) { + // Rehash the table. + label_info **old_table = label_table; + int old_size = label_table_size; + label_table_size = next_size(label_table_size); + label_table = new label_info *[label_table_size]; + int i; + for (i = 0; i < label_table_size; i++) + label_table[i] = 0; + for (i = 0; i < old_size; i++) + if (old_table[i]) { + unsigned h = hash_string(label_pool.contents() + old_table[i]->start, + old_table[i]->length); + for (label_info **p = label_table + (h % label_table_size); + *p != 0; + (p == label_table) + ? (p = label_table + label_table_size - 1) + : --p) + ; + *p = old_table[i]; + } + a_delete old_table; + } + return result; +} + +void clear_labels() +{ + for (int i = 0; i < label_table_size; i++) { + delete label_table[i]; + label_table[i] = 0; + } + label_table_used = 0; + label_pool.clear(); +} + +static void consider_authors(reference **start, reference **end, int i); + +void compute_labels(reference **v, int n) +{ + if (parsed_label + && (parsed_label->analyze() & expression::CONTAINS_AT) + && sort_fields.length() >= 2 + && sort_fields[0] == 'A' + && sort_fields[1] == '+') + consider_authors(v, v + n, 0); + for (int i = 0; i < n; i++) + v[i]->compute_label(); +} + + +/* A reference with a list of authors _needs_ author i +where 0 <= i <= N if there exists a reference with a list of authors + such that != and M >= i +and Aj = Bj for 0 <= j < i. In this case if we can't say ``A0, +A1,...,A(i-1) et al'' because this would match both and +. If a reference needs author i we only have to call +need_author(j) for some j >= i such that the reference also needs +author j. */ + +/* This function handles 2 tasks: +determine which authors are needed (cannot be elided with et al.); +determine which authors can have only last names in the labels. + +References >= start and < end have the same first i author names. +Also they're sorted by A+. */ + +static void consider_authors(reference **start, reference **end, int i) +{ + if (start >= end) + return; + reference **p = start; + if (i >= (*p)->get_nauthors()) { + for (++p; p < end && i >= (*p)->get_nauthors(); p++) + ; + if (p < end && i > 0) { + // If we have an author list and an author list , + // then both lists need C. + for (reference **q = start; q < end; q++) + (*q)->need_author(i - 1); + } + start = p; + } + while (p < end) { + reference **last_name_start = p; + reference **name_start = p; + for (++p; + p < end && i < (*p)->get_nauthors() + && same_author_last_name(**last_name_start, **p, i); + p++) { + if (!same_author_name(**name_start, **p, i)) { + consider_authors(name_start, p, i + 1); + name_start = p; + } + } + consider_authors(name_start, p, i + 1); + if (last_name_start == name_start) { + for (reference **q = last_name_start; q < p; q++) + (*q)->set_last_name_unambiguous(i); + } + // If we have an author list and , then the lists + // need author D and E respectively. + if (name_start > start || p < end) { + for (reference **q = last_name_start; q < p; q++) + (*q)->need_author(i); + } + } +} + +int same_author_last_name(const reference &r1, const reference &r2, int n) +{ + const char *ae1; + const char *as1 = r1.get_sort_field(0, n, 0, &ae1); + assert(as1 != 0); + const char *ae2; + const char *as2 = r2.get_sort_field(0, n, 0, &ae2); + assert(as2 != 0); + return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0; +} + +int same_author_name(const reference &r1, const reference &r2, int n) +{ + const char *ae1; + const char *as1 = r1.get_sort_field(0, n, -1, &ae1); + assert(as1 != 0); + const char *ae2; + const char *as2 = r2.get_sort_field(0, n, -1, &ae2); + assert(as2 != 0); + return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0; +} + + +void int_set::set(int i) +{ + assert(i >= 0); + int bytei = i >> 3; + if (bytei >= v.length()) { + int old_length = v.length(); + v.set_length(bytei + 1); + for (int j = old_length; j <= bytei; j++) + v[j] = 0; + } + v[bytei] |= 1 << (i & 7); +} + +int int_set::get(int i) const +{ + assert(i >= 0); + int bytei = i >> 3; + return bytei >= v.length() ? 0 : (v[bytei] & (1 << (i & 7))) != 0; +} + +void reference::set_last_name_unambiguous(int i) +{ + last_name_unambiguous.set(i); +} + +void reference::need_author(int n) +{ + if (n > last_needed_author) + last_needed_author = n; +} + +const char *reference::get_authors(const char **end) const +{ + if (!computed_authors) { + ((reference *)this)->computed_authors = 1; + string &result = ((reference *)this)->authors; + int na = get_nauthors(); + result.clear(); + for (int i = 0; i < na; i++) { + if (last_name_unambiguous.get(i)) { + const char *e, *start = get_author_last_name(i, &e); + assert(start != 0); + result.append(start, e - start); + } + else { + const char *e, *start = get_author(i, &e); + assert(start != 0); + result.append(start, e - start); + } + if (i == last_needed_author + && et_al.length() > 0 + && et_al_min_elide > 0 + && last_needed_author + et_al_min_elide < na + && na >= et_al_min_total) { + result += et_al; + break; + } + if (i < na - 1) { + if (na == 2) + result += join_authors_exactly_two; + else if (i < na - 2) + result += join_authors_default; + else + result += join_authors_last_two; + } + } + } + const char *start = authors.contents(); + *end = start + authors.length(); + return start; +} + +int reference::get_nauthors() const +{ + if (nauthors < 0) { + const char *dummy; + for (int na = 0; get_author(na, &dummy) != 0; na++) + ; + ((reference *)this)->nauthors = na; + } + return nauthors; +} diff --git a/gnu/usr.bin/groff/refer/ref.cc b/gnu/usr.bin/groff/refer/ref.cc new file mode 100644 index 0000000000..0b78813ec1 --- /dev/null +++ b/gnu/usr.bin/groff/refer/ref.cc @@ -0,0 +1,1144 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. +Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "refer.h" +#include "refid.h" +#include "ref.h" +#include "token.h" + +static const char *find_day(const char *, const char *, const char **); +static int find_month(const char *start, const char *end); +static void abbreviate_names(string &); + +#define DEFAULT_ARTICLES "the\000a\000an" + +string articles(DEFAULT_ARTICLES, sizeof(DEFAULT_ARTICLES)); + +// Multiple occurrences of fields are separated by FIELD_SEPARATOR. +const char FIELD_SEPARATOR = '\0'; + +const char MULTI_FIELD_NAMES[] = "AE"; +const char *AUTHOR_FIELDS = "AQ"; + +enum { OTHER, JOURNAL_ARTICLE, BOOK, ARTICLE_IN_BOOK, TECH_REPORT, BELL_TM }; + +const char *reference_types[] = { + "other", + "journal-article", + "book", + "article-in-book", + "tech-report", + "bell-tm", +}; + +static string temp_fields[256]; + +reference::reference(const char *start, int len, reference_id *ridp) +: no(-1), field(0), nfields(0), h(0), merged(0), label_ptr(0), + computed_authors(0), last_needed_author(-1), nauthors(-1) +{ + for (int i = 0; i < 256; i++) + field_index[i] = NULL_FIELD_INDEX; + if (ridp) + rid = *ridp; + if (start == 0) + return; + if (len <= 0) + return; + const char *end = start + len; + const char *ptr = start; + assert(*ptr == '%'); + while (ptr < end) { + if (ptr + 1 < end && ptr[1] != '\0' + && ((ptr[1] != '%' && ptr[1] == annotation_field) + || (ptr + 2 < end && ptr[1] == '%' && ptr[2] != '\0' + && discard_fields.search(ptr[2]) < 0))) { + if (ptr[1] == '%') + ptr++; + string &f = temp_fields[(unsigned char)ptr[1]]; + ptr += 2; + while (ptr < end && csspace(*ptr)) + ptr++; + for (;;) { + for (;;) { + if (ptr >= end) { + f += '\n'; + break; + } + f += *ptr; + if (*ptr++ == '\n') + break; + } + if (ptr >= end || *ptr == '%') + break; + } + } + else if (ptr + 1 < end && ptr[1] != '\0' && ptr[1] != '%' + && discard_fields.search(ptr[1]) < 0) { + string &f = temp_fields[(unsigned char)ptr[1]]; + if (f.length() > 0) { + if (strchr(MULTI_FIELD_NAMES, ptr[1]) != 0) + f += FIELD_SEPARATOR; + else + f.clear(); + } + ptr += 2; + if (ptr < end) { + if (*ptr == ' ') + ptr++; + for (;;) { + const char *p = ptr; + while (ptr < end && *ptr != '\n') + ptr++; + // strip trailing white space + const char *q = ptr; + while (q > p && q[-1] != '\n' && csspace(q[-1])) + q--; + while (p < q) + f += *p++; + if (ptr >= end) + break; + ptr++; + if (ptr >= end) + break; + if (*ptr == '%') + break; + f += ' '; + } + } + } + else { + // skip this field + for (;;) { + while (ptr < end && *ptr++ != '\n') + ; + if (ptr >= end || *ptr == '%') + break; + } + } + } + for (i = 0; i < 256; i++) + if (temp_fields[i].length() > 0) + nfields++; + field = new string[nfields]; + int j = 0; + for (i = 0; i < 256; i++) + if (temp_fields[i].length() > 0) { + field[j].move(temp_fields[i]); + if (abbreviate_fields.search(i) >= 0) + abbreviate_names(field[j]); + field_index[i] = j; + j++; + } +} + +reference::~reference() +{ + if (nfields > 0) + ad_delete(nfields) field; +} + +// ref is the inline, this is the database ref + +void reference::merge(reference &ref) +{ + int i; + for (i = 0; i < 256; i++) + if (field_index[i] != NULL_FIELD_INDEX) + temp_fields[i].move(field[field_index[i]]); + for (i = 0; i < 256; i++) + if (ref.field_index[i] != NULL_FIELD_INDEX) + temp_fields[i].move(ref.field[ref.field_index[i]]); + for (i = 0; i < 256; i++) + field_index[i] = NULL_FIELD_INDEX; + int old_nfields = nfields; + nfields = 0; + for (i = 0; i < 256; i++) + if (temp_fields[i].length() > 0) + nfields++; + if (nfields != old_nfields) { + if (old_nfields > 0) + ad_delete(old_nfields) field; + field = new string[nfields]; + } + int j = 0; + for (i = 0; i < 256; i++) + if (temp_fields[i].length() > 0) { + field[j].move(temp_fields[i]); + field_index[i] = j; + j++; + } + merged = 1; +} + +void reference::insert_field(unsigned char c, string &s) +{ + assert(s.length() > 0); + if (field_index[c] != NULL_FIELD_INDEX) { + field[field_index[c]].move(s); + return; + } + assert(field_index[c] == NULL_FIELD_INDEX); + string *old_field = field; + field = new string[nfields + 1]; + int pos = 0; + for (int i = 0; i < int(c); i++) + if (field_index[i] != NULL_FIELD_INDEX) + pos++; + for (i = 0; i < pos; i++) + field[i].move(old_field[i]); + field[pos].move(s); + for (i = pos; i < nfields; i++) + field[i + 1].move(old_field[i]); + if (nfields > 0) + ad_delete(nfields) old_field; + nfields++; + field_index[c] = pos; + for (i = c + 1; i < 256; i++) + if (field_index[i] != NULL_FIELD_INDEX) + field_index[i] += 1; +} + +void reference::delete_field(unsigned char c) +{ + if (field_index[c] == NULL_FIELD_INDEX) + return; + string *old_field = field; + field = new string[nfields - 1]; + for (int i = 0; i < int(field_index[c]); i++) + field[i].move(old_field[i]); + for (i = field_index[c]; i < nfields - 1; i++) + field[i].move(old_field[i + 1]); + if (nfields > 0) + ad_delete(nfields) old_field; + nfields--; + field_index[c] = NULL_FIELD_INDEX; + for (i = c + 1; i < 256; i++) + if (field_index[i] != NULL_FIELD_INDEX) + field_index[i] -= 1; +} + +void reference::compute_hash_code() +{ + if (!rid.is_null()) + h = rid.hash(); + else { + h = 0; + for (int i = 0; i < nfields; i++) + if (field[i].length() > 0) { + h <<= 4; + h ^= hash_string(field[i].contents(), field[i].length()); + } + } +} + +void reference::set_number(int n) +{ + no = n; +} + +const char SORT_SEP = '\001'; +const char SORT_SUB_SEP = '\002'; +const char SORT_SUB_SUB_SEP = '\003'; + +// sep specifies additional word separators + +void sortify_words(const char *s, const char *end, const char *sep, + string &result) +{ + int non_empty = 0; + int need_separator = 0; + for (;;) { + const char *token_start = s; + if (!get_token(&s, end)) + break; + if ((s - token_start == 1 + && (*token_start == ' ' + || *token_start == '\n' + || (sep && *token_start != '\0' + && strchr(sep, *token_start) != 0))) + || (s - token_start == 2 + && token_start[0] == '\\' && token_start[1] == ' ')) { + if (non_empty) + need_separator = 1; + } + else { + const token_info *ti = lookup_token(token_start, s); + if (ti->sortify_non_empty(token_start, s)) { + if (need_separator) { + result += ' '; + need_separator = 0; + } + ti->sortify(token_start, s, result); + non_empty = 1; + } + } + } +} + +void sortify_word(const char *s, const char *end, string &result) +{ + for (;;) { + const char *token_start = s; + if (!get_token(&s, end)) + break; + const token_info *ti = lookup_token(token_start, s); + ti->sortify(token_start, s, result); + } +} + +void sortify_other(const char *s, int len, string &key) +{ + sortify_words(s, s + len, 0, key); +} + +void sortify_title(const char *s, int len, string &key) +{ + const char *end = s + len; + for (; s < end && (*s == ' ' || *s == '\n'); s++) + ; + const char *ptr = s; + for (;;) { + const char *token_start = ptr; + if (!get_token(&ptr, end)) + break; + if (ptr - token_start == 1 + && (*token_start == ' ' || *token_start == '\n')) + break; + } + if (ptr < end) { + int first_word_len = ptr - s - 1; + const char *ae = articles.contents() + articles.length(); + for (const char *a = articles.contents(); + a < ae; + a = strchr(a, '\0') + 1) + if (first_word_len == strlen(a)) { + for (int j = 0; j < first_word_len; j++) + if (a[j] != cmlower(s[j])) + break; + if (j >= first_word_len) { + s = ptr; + for (; s < end && (*s == ' ' || *s == '\n'); s++) + ; + break; + } + } + } + sortify_words(s, end, 0, key); +} + +void sortify_name(const char *s, int len, string &key) +{ + const char *last_name_end; + const char *last_name = find_last_name(s, s + len, &last_name_end); + sortify_word(last_name, last_name_end, key); + key += SORT_SUB_SUB_SEP; + if (last_name > s) + sortify_words(s, last_name, ".", key); + key += SORT_SUB_SUB_SEP; + if (last_name_end < s + len) + sortify_words(last_name_end, s + len, ".,", key); +} + +void sortify_date(const char *s, int len, string &key) +{ + const char *year_end; + const char *year_start = find_year(s, s + len, &year_end); + if (!year_start) { + // Things without years are often `forthcoming', so it makes sense + // that they sort after things with explicit years. + key += 'A'; + sortify_words(s, s + len, 0, key); + return; + } + int n = year_end - year_start; + while (n < 4) { + key += '0'; + n++; + } + while (year_start < year_end) + key += *year_start++; + int m = find_month(s, s + len); + if (m < 0) + return; + key += 'A' + m; + const char *day_end; + const char *day_start = find_day(s, s + len, &day_end); + if (!day_start) + return; + if (day_end - day_start == 1) + key += '0'; + while (day_start < day_end) + key += *day_start++; +} + +// SORT_{SUB,SUB_SUB}_SEP can creep in from use of @ in label specification. + +void sortify_label(const char *s, int len, string &key) +{ + const char *end = s + len; + for (;;) { + for (const char *ptr = s; + ptr < end && *ptr != SORT_SUB_SEP && *ptr != SORT_SUB_SUB_SEP; + ptr++) + ; + if (ptr > s) + sortify_words(s, ptr, 0, key); + s = ptr; + if (s >= end) + break; + key += *s++; + } +} + +void reference::compute_sort_key() +{ + if (sort_fields.length() == 0) + return; + sort_fields += '\0'; + const char *sf = sort_fields.contents(); + while (*sf != '\0') { + if (sf > sort_fields) + sort_key += SORT_SEP; + char f = *sf++; + int n = 1; + if (*sf == '+') { + n = INT_MAX; + sf++; + } + else if (csdigit(*sf)) { + char *ptr; + long l = strtol(sf, &ptr, 10); + if (l == 0 && ptr == sf) + ; + else { + sf = ptr; + if (l < 0) { + n = 1; + } + else { + n = int(l); + } + } + } + if (f == '.') + sortify_label(label.contents(), label.length(), sort_key); + else if (f == AUTHOR_FIELDS[0]) + sortify_authors(n, sort_key); + else + sortify_field(f, n, sort_key); + } + sort_fields.set_length(sort_fields.length() - 1); +} + +void reference::sortify_authors(int n, string &result) const +{ + for (const char *p = AUTHOR_FIELDS; *p != '\0'; p++) + if (contains_field(*p)) { + sortify_field(*p, n, result); + return; + } + sortify_field(AUTHOR_FIELDS[0], n, result); +} + +void reference::canonicalize_authors(string &result) const +{ + int len = result.length(); + sortify_authors(INT_MAX, result); + if (result.length() > len) + result += SORT_SUB_SEP; +} + +void reference::sortify_field(unsigned char f, int n, string &result) const +{ + typedef void (*sortify_t)(const char *, int, string &); + sortify_t sortifier = sortify_other; + switch (f) { + case 'A': + case 'E': + sortifier = sortify_name; + break; + case 'D': + sortifier = sortify_date; + break; + case 'B': + case 'J': + case 'T': + sortifier = sortify_title; + break; + } + int fi = field_index[(unsigned char)f]; + if (fi != NULL_FIELD_INDEX) { + string &str = field[fi]; + const char *start = str.contents(); + const char *end = start + str.length(); + for (int i = 0; i < n && start < end; i++) { + const char *p = start; + while (start < end && *start != FIELD_SEPARATOR) + start++; + if (i > 0) + result += SORT_SUB_SEP; + (*sortifier)(p, start - p, result); + if (start < end) + start++; + } + } +} + +int compare_reference(const reference &r1, const reference &r2) +{ + assert(r1.no >= 0); + assert(r2.no >= 0); + const char *s1 = r1.sort_key.contents(); + int n1 = r1.sort_key.length(); + const char *s2 = r2.sort_key.contents(); + int n2 = r2.sort_key.length(); + for (; n1 > 0 && n2 > 0; --n1, --n2, ++s1, ++s2) + if (*s1 != *s2) + return (int)(unsigned char)*s1 - (int)(unsigned char)*s2; + if (n2 > 0) + return -1; + if (n1 > 0) + return 1; + return r1.no - r2.no; +} + +int same_reference(const reference &r1, const reference &r2) +{ + if (!r1.rid.is_null() && r1.rid == r2.rid) + return 1; + if (r1.h != r2.h) + return 0; + if (r1.nfields != r2.nfields) + return 0; + int i = 0; + for (i = 0; i < 256; i++) + if (r1.field_index != r2.field_index) + return 0; + for (i = 0; i < r1.nfields; i++) + if (r1.field[i] != r2.field[i]) + return 0; + return 1; +} + +const char *find_last_name(const char *start, const char *end, + const char **endp) +{ + const char *ptr = start; + const char *last_word = start; + for (;;) { + const char *token_start = ptr; + if (!get_token(&ptr, end)) + break; + if (ptr - token_start == 1) { + if (*token_start == ',') { + *endp = token_start; + return last_word; + } + else if (*token_start == ' ' || *token_start == '\n') { + if (ptr < end && *ptr != ' ' && *ptr != '\n') + last_word = ptr; + } + } + } + *endp = end; + return last_word; +} + +void abbreviate_name(const char *ptr, const char *end, string &result) +{ + const char *last_name_end; + const char *last_name_start = find_last_name(ptr, end, &last_name_end); + int need_period = 0; + for (;;) { + const char *token_start = ptr; + if (!get_token(&ptr, last_name_start)) + break; + const token_info *ti = lookup_token(token_start, ptr); + if (need_period) { + if ((ptr - token_start == 1 && *token_start == ' ') + || (ptr - token_start == 2 && token_start[0] == '\\' + && token_start[1] == ' ')) + continue; + if (ti->is_upper()) + result += period_before_initial; + else + result += period_before_other; + need_period = 0; + } + result.append(token_start, ptr - token_start); + if (ti->is_upper()) { + const char *lower_ptr = ptr; + int first_token = 1; + for (;;) { + token_start = ptr; + if (!get_token(&ptr, last_name_start)) + break; + if ((ptr - token_start == 1 && *token_start == ' ') + || (ptr - token_start == 2 && token_start[0] == '\\' + && token_start[1] == ' ')) + break; + ti = lookup_token(token_start, ptr); + if (ti->is_hyphen()) { + const char *ptr1 = ptr; + if (get_token(&ptr1, last_name_start)) { + ti = lookup_token(ptr, ptr1); + if (ti->is_upper()) { + result += period_before_hyphen; + result.append(token_start, ptr1 - token_start); + ptr = ptr1; + } + } + } + else if (ti->is_upper()) { + // MacDougal -> MacD. + result.append(lower_ptr, ptr - lower_ptr); + lower_ptr = ptr; + first_token = 1; + } + else if (first_token && ti->is_accent()) { + result.append(token_start, ptr - token_start); + lower_ptr = ptr; + } + first_token = 0; + } + need_period = 1; + } + } + if (need_period) + result += period_before_last_name; + result.append(last_name_start, end - last_name_start); +} + +static void abbreviate_names(string &result) +{ + string str; + str.move(result); + const char *ptr = str.contents(); + const char *end = ptr + str.length(); + while (ptr < end) { + const char *name_end = (char *)memchr(ptr, FIELD_SEPARATOR, end - ptr); + if (name_end == 0) + name_end = end; + abbreviate_name(ptr, name_end, result); + if (name_end >= end) + break; + ptr = name_end + 1; + result += FIELD_SEPARATOR; + } +} + +void reverse_name(const char *ptr, const char *name_end, string &result) +{ + const char *last_name_end; + const char *last_name_start = find_last_name(ptr, name_end, &last_name_end); + result.append(last_name_start, last_name_end - last_name_start); + while (last_name_start > ptr + && (last_name_start[-1] == ' ' || last_name_start[-1] == '\n')) + last_name_start--; + if (last_name_start > ptr) { + result += ", "; + result.append(ptr, last_name_start - ptr); + } + if (last_name_end < name_end) + result.append(last_name_end, name_end - last_name_end); +} + +void reverse_names(string &result, int n) +{ + if (n <= 0) + return; + string str; + str.move(result); + const char *ptr = str.contents(); + const char *end = ptr + str.length(); + while (ptr < end) { + if (--n < 0) { + result.append(ptr, end - ptr); + break; + } + const char *name_end = (char *)memchr(ptr, FIELD_SEPARATOR, end - ptr); + if (name_end == 0) + name_end = end; + reverse_name(ptr, name_end, result); + if (name_end >= end) + break; + ptr = name_end + 1; + result += FIELD_SEPARATOR; + } +} + +// Return number of field separators. + +int join_fields(string &f) +{ + const char *ptr = f.contents(); + int len = f.length(); + int nfield_seps = 0; + for (int j = 0; j < len; j++) + if (ptr[j] == FIELD_SEPARATOR) + nfield_seps++; + if (nfield_seps == 0) + return 0; + string temp; + int field_seps_left = nfield_seps; + for (j = 0; j < len; j++) { + if (ptr[j] == FIELD_SEPARATOR) { + if (nfield_seps == 1) + temp += join_authors_exactly_two; + else if (--field_seps_left == 0) + temp += join_authors_last_two; + else + temp += join_authors_default; + } + else + temp += ptr[j]; + } + f = temp; + return nfield_seps; +} + +void uppercase(const char *start, const char *end, string &result) +{ + for (;;) { + const char *token_start = start; + if (!get_token(&start, end)) + break; + const token_info *ti = lookup_token(token_start, start); + ti->upper_case(token_start, start, result); + } +} + +void lowercase(const char *start, const char *end, string &result) +{ + for (;;) { + const char *token_start = start; + if (!get_token(&start, end)) + break; + const token_info *ti = lookup_token(token_start, start); + ti->lower_case(token_start, start, result); + } +} + +void capitalize(const char *ptr, const char *end, string &result) +{ + int in_small_point_size = 0; + for (;;) { + const char *start = ptr; + if (!get_token(&ptr, end)) + break; + const token_info *ti = lookup_token(start, ptr); + const char *char_end = ptr; + int is_lower = ti->is_lower(); + if ((is_lower || ti->is_upper()) && get_token(&ptr, end)) { + const token_info *ti2 = lookup_token(char_end, ptr); + if (!ti2->is_accent()) + ptr = char_end; + } + if (is_lower) { + if (!in_small_point_size) { + result += "\\s-2"; + in_small_point_size = 1; + } + ti->upper_case(start, char_end, result); + result.append(char_end, ptr - char_end); + } + else { + if (in_small_point_size) { + result += "\\s+2"; + in_small_point_size = 0; + } + result.append(start, ptr - start); + } + } + if (in_small_point_size) + result += "\\s+2"; +} + +void capitalize_field(string &str) +{ + string temp; + capitalize(str.contents(), str.contents() + str.length(), temp); + str.move(temp); +} + +int is_terminated(const char *ptr, const char *end) +{ + const char *last_token = end; + for (;;) { + const char *p = ptr; + if (!get_token(&ptr, end)) + break; + last_token = p; + } + return end - last_token == 1 + && (*last_token == '.' || *last_token == '!' || *last_token == '?'); +} + +void reference::output(FILE *fp) +{ + fputs(".]-\n", fp); + for (int i = 0; i < 256; i++) + if (field_index[i] != NULL_FIELD_INDEX && i != annotation_field) { + string &f = field[field_index[i]]; + if (!csdigit(i)) { + int j = reverse_fields.search(i); + if (j >= 0) { + int n; + int len = reverse_fields.length(); + if (++j < len && csdigit(reverse_fields[j])) { + n = reverse_fields[j] - '0'; + for (++j; j < len && csdigit(reverse_fields[j]); j++) + // should check for overflow + n = n*10 + reverse_fields[j] - '0'; + } + else + n = INT_MAX; + reverse_names(f, n); + } + } + int is_multiple = join_fields(f) > 0; + if (capitalize_fields.search(i) >= 0) + capitalize_field(f); + if (memchr(f.contents(), '\n', f.length()) == 0) { + fprintf(fp, ".ds [%c ", i); + if (f[0] == ' ' || f[0] == '\\' || f[0] == '"') + putc('"', fp); + put_string(f, fp); + putc('\n', fp); + } + else { + fprintf(fp, ".de [%c\n", i); + put_string(f, fp); + fputs("..\n", fp); + } + if (i == 'P') { + int multiple_pages = 0; + if (f.length() > 0 && memchr(f.contents(), '-', f.length()) != 0) + multiple_pages = 1; + fprintf(fp, ".nr [P %d\n", multiple_pages); + } + else if (i == 'E') + fprintf(fp, ".nr [E %d\n", is_multiple); + } + for (const char *p = "TAO"; *p; p++) { + int fi = field_index[(unsigned char)*p]; + if (fi != NULL_FIELD_INDEX) { + string &f = field[fi]; + fprintf(fp, ".nr [%c %d\n", *p, + is_terminated(f.contents(), f.contents() + f.length())); + } + } + int t = classify(); + fprintf(fp, ".][ %d %s\n", t, reference_types[t]); + if (annotation_macro.length() > 0 && annotation_field >= 0 + && field_index[annotation_field] != NULL_FIELD_INDEX) { + putc('.', fp); + put_string(annotation_macro, fp); + putc('\n', fp); + put_string(field[field_index[annotation_field]], fp); + } +} + +void reference::print_sort_key_comment(FILE *fp) +{ + fputs(".\\\"", fp); + put_string(sort_key, fp); + putc('\n', fp); +} + +const char *find_year(const char *start, const char *end, const char **endp) +{ + for (;;) { + while (start < end && !csdigit(*start)) + start++; + const char *ptr = start; + if (start == end) + break; + while (ptr < end && csdigit(*ptr)) + ptr++; + if (ptr - start == 4 || ptr - start == 3 + || (ptr - start == 2 + && (start[0] >= '4' || (start[0] == '3' && start[1] >= '2')))) { + *endp = ptr; + return start; + } + start = ptr; + } + return 0; +} + +static const char *find_day(const char *start, const char *end, + const char **endp) +{ + for (;;) { + while (start < end && !csdigit(*start)) + start++; + const char *ptr = start; + if (start == end) + break; + while (ptr < end && csdigit(*ptr)) + ptr++; + if ((ptr - start == 1 && start[0] != '0') + || (ptr - start == 2 && + (start[0] == '1' + || start[0] == '2' + || (start[0] == '3' && start[1] <= '1') + || (start[0] == '0' && start[1] != '0')))) { + *endp = ptr; + return start; + } + start = ptr; + } + return 0; +} + +static int find_month(const char *start, const char *end) +{ + static const char *months[] = { + "january", + "february", + "march", + "april", + "may", + "june", + "july", + "august", + "september", + "october", + "november", + "december", + }; + for (;;) { + while (start < end && !csalpha(*start)) + start++; + const char *ptr = start; + if (start == end) + break; + while (ptr < end && csalpha(*ptr)) + ptr++; + if (ptr - start >= 3) { + for (int i = 0; i < sizeof(months)/sizeof(months[0]); i++) { + const char *q = months[i]; + const char *p = start; + for (; p < ptr; p++, q++) + if (cmlower(*p) != *q) + break; + if (p >= ptr) + return i; + } + } + start = ptr; + } + return -1; +} + +int reference::contains_field(char c) const +{ + return field_index[(unsigned char)c] != NULL_FIELD_INDEX; +} + +int reference::classify() +{ + if (contains_field('J')) + return JOURNAL_ARTICLE; + if (contains_field('B')) + return ARTICLE_IN_BOOK; + if (contains_field('G')) + return TECH_REPORT; + if (contains_field('R')) + return TECH_REPORT; + if (contains_field('I')) + return BOOK; + if (contains_field('M')) + return BELL_TM; + return OTHER; +} + +const char *reference::get_year(const char **endp) const +{ + if (field_index['D'] != NULL_FIELD_INDEX) { + string &date = field[field_index['D']]; + const char *start = date.contents(); + const char *end = start + date.length(); + return find_year(start, end, endp); + } + else + return 0; +} + +const char *reference::get_field(unsigned char c, const char **endp) const +{ + if (field_index[c] != NULL_FIELD_INDEX) { + string &f = field[field_index[c]]; + const char *start = f.contents(); + *endp = start + f.length(); + return start; + } + else + return 0; +} + +const char *reference::get_date(const char **endp) const +{ + return get_field('D', endp); +} + +const char *nth_field(int i, const char *start, const char **endp) +{ + while (--i >= 0) { + start = (char *)memchr(start, FIELD_SEPARATOR, *endp - start); + if (!start) + return 0; + start++; + } + const char *e = (char *)memchr(start, FIELD_SEPARATOR, *endp - start); + if (e) + *endp = e; + return start; +} + +const char *reference::get_author(int i, const char **endp) const +{ + for (const char *f = AUTHOR_FIELDS; *f != '\0'; f++) { + const char *start = get_field(*f, endp); + if (start) { + if (strchr(MULTI_FIELD_NAMES, *f) != 0) + return nth_field(i, start, endp); + else if (i == 0) + return start; + else + return 0; + } + } + return 0; +} + +const char *reference::get_author_last_name(int i, const char **endp) const +{ + for (const char *f = AUTHOR_FIELDS; *f != '\0'; f++) { + const char *start = get_field(*f, endp); + if (start) { + if (strchr(MULTI_FIELD_NAMES, *f) != 0) { + start = nth_field(i, start, endp); + if (!start) + return 0; + } + if (*f == 'A') + return find_last_name(start, *endp, endp); + else + return start; + } + } + return 0; +} + +void reference::set_date(string &d) +{ + if (d.length() == 0) + delete_field('D'); + else + insert_field('D', d); +} + +int same_year(const reference &r1, const reference &r2) +{ + const char *ye1; + const char *ys1 = r1.get_year(&ye1); + const char *ye2; + const char *ys2 = r2.get_year(&ye2); + if (ys1 == 0) { + if (ys2 == 0) + return same_date(r1, r2); + else + return 0; + } + else if (ys2 == 0) + return 0; + else if (ye1 - ys1 != ye2 - ys2) + return 0; + else + return memcmp(ys1, ys2, ye1 - ys1) == 0; +} + +int same_date(const reference &r1, const reference &r2) +{ + const char *e1; + const char *s1 = r1.get_date(&e1); + const char *e2; + const char *s2 = r2.get_date(&e2); + if (s1 == 0) + return s2 == 0; + else if (s2 == 0) + return 0; + else if (e1 - s1 != e2 - s2) + return 0; + else + return memcmp(s1, s2, e1 - s1) == 0; +} + +const char *reference::get_sort_field(int i, int si, int ssi, + const char **endp) const +{ + const char *start = sort_key.contents(); + const char *end = start + sort_key.length(); + if (i < 0) { + *endp = end; + return start; + } + while (--i >= 0) { + start = (char *)memchr(start, SORT_SEP, end - start); + if (!start) + return 0; + start++; + } + const char *e = (char *)memchr(start, SORT_SEP, end - start); + if (e) + end = e; + if (si < 0) { + *endp = end; + return start; + } + while (--si >= 0) { + start = (char *)memchr(start, SORT_SUB_SEP, end - start); + if (!start) + return 0; + start++; + } + e = (char *)memchr(start, SORT_SUB_SEP, end - start); + if (e) + end = e; + if (ssi < 0) { + *endp = end; + return start; + } + while (--ssi >= 0) { + start = (char *)memchr(start, SORT_SUB_SUB_SEP, end - start); + if (!start) + return 0; + start++; + } + e = (char *)memchr(start, SORT_SUB_SUB_SEP, end - start); + if (e) + end = e; + *endp = end; + return start; +} + diff --git a/gnu/usr.bin/groff/refer/ref.h b/gnu/usr.bin/groff/refer/ref.h new file mode 100644 index 0000000000..28e498dc5d --- /dev/null +++ b/gnu/usr.bin/groff/refer/ref.h @@ -0,0 +1,120 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct label_info; + +enum label_type { NORMAL_LABEL, SHORT_LABEL }; +const int N_LABEL_TYPES = 2; + +struct substring_position { + int start; + int length; + substring_position() : start(-1) { } +}; + +class int_set { + string v; +public: + int_set() { } + void set(int i); + int get(int i) const; +}; + +class reference { +private: + unsigned h; + reference_id rid; + int merged; + string sort_key; + int no; + string *field; + int nfields; + unsigned char field_index[256]; + enum { NULL_FIELD_INDEX = 255 }; + string label; + substring_position separator_pos; + string short_label; + substring_position short_separator_pos; + label_info *label_ptr; + string authors; + int computed_authors; + int last_needed_author; + int nauthors; + int_set last_name_unambiguous; + + int contains_field(char) const; + void insert_field(unsigned char, string &s); + void delete_field(unsigned char); + void set_date(string &); + const char *get_sort_field(int i, int si, int ssi, const char **endp) const; + int merge_labels_by_parts(reference **, int, label_type, string &); + int merge_labels_by_number(reference **, int, label_type, string &); +public: + reference(const char * = 0, int = -1, reference_id * = 0); + ~reference(); + void output(FILE *); + void print_sort_key_comment(FILE *); + void set_number(int); + int get_number() const { return no; } + unsigned hash() const { return h; } + const string &get_label(label_type type) const; + const substring_position &get_separator_pos(label_type) const; + int is_merged() const { return merged; } + void compute_sort_key(); + void compute_hash_code(); + void pre_compute_label(); + void compute_label(); + void immediate_compute_label(); + int classify(); + void merge(reference &); + int merge_labels(reference **, int, label_type, string &); + int get_nauthors() const; + void need_author(int); + void set_last_name_unambiguous(int); + void sortify_authors(int, string &) const; + void canonicalize_authors(string &) const; + void sortify_field(unsigned char, int, string &) const; + const char *get_author(int, const char **) const; + const char *get_author_last_name(int, const char **) const; + const char *get_date(const char **) const; + const char *get_year(const char **) const; + const char *get_field(unsigned char, const char **) const; + const label_info *get_label_ptr() const { return label_ptr; } + const char *get_authors(const char **) const; + // for sorting + friend int compare_reference(const reference &r1, const reference &r2); + // for merging + friend int same_reference(const reference &, const reference &); + friend int same_year(const reference &, const reference &); + friend int same_date(const reference &, const reference &); + friend int same_author_last_name(const reference &, const reference &, int); + friend int same_author_name(const reference &, const reference &, int); +}; + +const char *find_year(const char *, const char *, const char **); +const char *find_last_name(const char *, const char *, const char **); + +const char *nth_field(int i, const char *start, const char **endp); + +void capitalize(const char *ptr, const char *end, string &result); +void reverse_name(const char *ptr, const char *end, string &result); +void uppercase(const char *ptr, const char *end, string &result); +void lowercase(const char *ptr, const char *end, string &result); +void abbreviate_name(const char *ptr, const char *end, string &result); diff --git a/gnu/usr.bin/groff/refer/refer.1 b/gnu/usr.bin/groff/refer/refer.1 new file mode 100644 index 0000000000..1ab5565217 --- /dev/null +++ b/gnu/usr.bin/groff/refer/refer.1 @@ -0,0 +1,1282 @@ +.\" -*- nroff -*- +.de TQ +.br +.ns +.TP \\$1 +.. +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.\" The BSD man macros can't handle " in arguments to font change macros, +.\" so use \(ts instead of ". +.tr \(ts" +.TH REFER 1 "19 February 1993" "Groff Version 1.08" +.SH NAME +refer \- preprocess bibliographic references for groff +.SH SYNOPSIS +.nr a \n(.j +.ad l +.nr i \n(.i +.in +\w'\fBrefer 'u +.ti \niu +.B refer +.de OP +.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]" +.el .RB "[\ " "\\$1" "\ ]" +.. +.OP \-benvCPRS +.OP \-a n +.OP \-c fields +.OP \-f n +.OP \-i fields +.OP \-k field +.OP \-l m,n +.OP \-p filename +.OP \-s fields +.OP \-t n +.OP \-B field.macro +.RI [\ filename \|.\|.\|.\ ] +.br +.ad \na +.SH DESCRIPTION +This file documents the GNU version of +.BR refer , +which is part of the groff document formatting system. +.B refer +copies the contents of +.IR filename \|.\|.\|. +to the standard output, +except that lines between +.B .[ +and +.B .] +are interpreted as citations, +and lines between +.B .R1 +and +.B .R2 +are interpreted as commands about how citations are to be processed. +.LP +Each citation specifies a reference. +The citation can specify a reference that is contained in +a bibliographic database by giving a set of keywords +that only that reference contains. +Alternatively it can specify a reference by supplying a database +record in the citation. +A combination of these alternatives is also possible. +.LP +For each citation, +.B refer +can produce a mark in the text. +This mark consists of some label which can be separated from +the text and from other labels in various ways. +For each reference it also outputs +.B groff +commands that can be used by a macro package to produce a formatted +reference for each citation. +The output of +.B refer +must therefore be processed using a suitable macro package. +The +.B \-ms +and +.B \-me +macros are both suitable. +The commands to format a citation's reference can be output immediately after +the citation, +or the references may be accumulated, +and the commands output at some later point. +If the references are accumulated, then multiple citations of the same +reference will produce a single formatted reference. +.LP +The interpretation of lines between +.B .R1 +and +.B .R2 +as commands is a new feature of GNU refer. +Documents making use of this feature can still be processed by +Unix refer just by adding the lines +.RS +.LP +.nf +.ft B +\&.de R1 +\&.ig R2 +\&.. +.ft +.fi +.RE +to the beginning of the document. +This will cause +.B troff +to ignore everything between +.B .R1 +and +.BR .R2 . +The effect of some commands can also be achieved by options. +These options are supported mainly for compatibility with Unix refer. +It is usually more convenient to use commands. +.LP +.B refer +generates +.B .lf +lines so that filenames and line numbers in messages produced +by commands that read +.B refer +output will be correct; +it also interprets lines beginning with +.B .lf +so that filenames and line numbers in the messages and +.B .lf +lines that it produces will be accurate even if the input has been +preprocessed by a command such as +.BR soelim (1). +.SH OPTIONS +.LP +Most options are equivalent to commands +(for a description of these commands see the +.B Commands +subsection): +.TP +.B \-b +.B +no-label-in-text; no-label-in-reference +.TP +.B \-e +.B accumulate +.TP +.B \-n +.B no-default-database +.TP +.B \-C +.B compatible +.TP +.B \-P +.B move-puntuation +.TP +.B \-S +.B +label "(A.n|Q) ', ' (D.y|D)"; bracket-label " (" ) "; " +.TP +.BI \-a n +.B reverse +.BI A n +.TP +.BI \-c fields +.B capitalize +.I fields +.TP +.BI \-f n +.B label +.BI % n +.TP +.BI \-i fields +.B search-ignore +.I fields +.TP +.B \-k +.B label +.B L\(ti%a +.TP +.BI \-k field +.B label +.IB field \(ti%a +.TP +.B \-l +.B label +.BI A.nD.y%a +.TP +.BI \-l m +.B label +.BI A.n+ m D.y%a +.TP +.BI \-l, n +.B label +.BI A.nD.y\- n %a +.TP +.BI \-l m , n +.B label +.BI A.n+ m D.y\- n %a +.TP +.BI \-p filename +.B database +.I filename +.TP +.BI \-s spec +.B sort +.I spec +.TP +.BI \-t n +.B search-truncate +.I n +.LP +These options are equivalent to the following commands with the +addition that the filenames specified on the command line are +processed as if they were arguments to the +.B bibliography +command instead of in the normal way: +.TP +.B \-B +.B +annotate X AP; no-label-in-reference +.TP +.BI \-B field . macro +.B annotate +.I field +.IB macro ; +.B no-label-in-reference +.LP +The following options have no equivalent commands: +.TP +.B \-v +Print the version number. +.TP +.B \-R +Don't recognize lines beginning with +.BR .R1 / .R2 . +.SH USAGE +.SS Bibliographic databases +The bibliographic database is a text file consisting of records +separated by one or more blank lines. +Within each record fields start with a +.B % +at the beginning of a line. +Each field has a one character name that immediately follows the +.BR % . +It is best to use only upper and lower case letters for the names +of fields. +The name of the field should be followed by exactly one space, +and then by the contents of the field. +Empty fields are ignored. +The conventional meaning of each field is as follows: +.TP +.B A +The name of an author. +If the name contains a title such as +.B Jr. +at the end, +it should be separated from the last name by a comma. +There can be multiple occurences of the +.B A +field. +The order is siginificant. +It is a good idea always to supply an +.B A +field or a +.B Q +field. +.TP +.B B +For an article that is part of a book, the title of the book +.TP +.B C +The place (city) of publication. +.TP +.B D +The date of publication. +The year should be specified in full. +If the month is specified, the name rather than the number of the month +should be used, but only the first three letters are required. +It is a good idea always to supply a +.B D +field; +if the date is unknown, a value such as +.B in press +or +.B unknown +can be used. +.TP +.B E +For an article that is part of a book, the name of an editor of the book. +Where the work has editors and no authors, +the names of the editors should be given as +.B A +fields and +.B ,\ (ed) +or +.B ,\ (eds) +should be appended to the last author. +.TP +.B G +US Government ordering number. +.TP +.B I +The publisher (issuer). +.TP +.B J +For an article in a journal, the name of the journal. +.TP +.B K +Keywords to be used for searching. +.TP +.B L +Label. +.TP +.B N +Journal issue number. +.TP +.B O +Other information. +This is usually printed at the end of the reference. +.TP +.B P +Page number. +A range of pages can be specified as +.IB m \- n\fR. +.TP +.B Q +The name of the author, if the author is not a person. +This will only be used if there are no +.B A +fields. +There can only be one +.B Q +field. +.TP +.B R +Technical report number. +.TP +.B S +Series name. +.TP +.B T +Title. +For an article in a book or journal, +this should be the title of the article. +.TP +.B V +Volume number of the journal or book. +.TP +.B X +Annotation. +.LP +For all fields except +.B A +and +.BR E , +if there is more than one occurence of a particular field in a record, +only the last such field will be used. +.LP +If accent strings are used, they should follow the charater to be accented. +This means that the +.B AM +macro must be used with the +.B \-ms +macros. +Accent strings should not be quoted: +use one +.B \e +rather than two. +.SS Citations +The format of a citation is +.RS +.BI .[ opening-text +.br +.I +flags keywords +.br +.I fields +.br +.BI .] closing-text +.RE +.LP +The +.IR opening-text , +.IR closing-text +and +.I flags +components are optional. +Only one of the +.I keywords +and +.I fields +components need be specified. +.LP +The +.I keywords +component says to search the bibliographic databases for a reference +that contains all the words in +.IR keywords . +It is an error if more than one reference if found. +.LP +The +.I fields +components specifies additional fields to replace or supplement +those specified in the reference. +When references are being accumulated and the +.I keywords +component is non-empty, +then additional fields should be specified only on the first +occasion that a particular reference is cited, +and will apply to all citations of that reference. +.LP +The +.I opening-text +and +.I closing-text +component specifies strings to be used to bracket the label instead +of the strings specified in the +.B bracket-label +command. +If either of these components is non-empty, +the strings specified in the +.B bracket-label +command will not be used; +this behaviour can be altered using the +.B [ +and +.B ] +flags. +Note that leading and trailing spaces are significant for these components. +.LP +The +.I flags +component is a list of +non-alphanumeric characters each of which modifies the treatment +of this particular citation. +Unix refer will treat these flags as part of the keywords and +so will ignore them since they are non-alphanumeric. +The following flags are currently recognized: +.TP +.B # +This says to use the label specified by the +.B short-label +command, +instead of that specified by the +.B label +command. +If no short label has been specified, the normal label will be used. +Typically the short label is used with author-date labels +and consists of only the date and possibly a disambiguating letter; +the +.B # +is supposed to be suggestive of a numeric type of label. +.TP +.B [ +Precede +.I opening-text +with the first string specified in the +.B bracket-label +command. +.TP +.B ] +Follow +.I closing-text +with the second string specified in the +.B bracket-label +command. +.LP +One advantages of using the +.B [ +and +.B ] +flags rather than including the brackets in +.I opening-text +and +.I closing-text +is that +you can change the style of bracket used in the document just by changing the +.B bracket-label +command. +Another advantage is that sorting and merging of citations +will not necessarily be inhibited if the flags are used. +.LP +If a label is to be inserted into the text, +it will be attached to the line preceding the +.B .[ +line. +If there is no such line, then an extra line will be inserted before the +.B .[ +line and a warning will be given. +.LP +There is no special notation for making a citation to multiple references. +Just use a sequence of citations, one for each reference. +Don't put anything between the citations. +The labels for all the citations will be attached to the line preceding +the first citation. +The labels may also be sorted or merged. +See the description of the +.B <> +label expression, and of the +.B sort-adjacent-labels +and +.B abbreviate-label-ranges +command. +A label will not be merged if its citation has a non-empty +.I opening-text +or +.IR closing-text . +However, the labels for a citation using the +.B ] +flag and without any +.I closing-text +immediately followed by a citation using the +.B [ +flag and without any +.I opening-text +may be sorted and merged +even though the first citation's +.I opening-text +or the second citation's +.I closing-text +is non-empty. +(If you wish to prevent this just make the first citation's +.I closing-text +.BR \e& .) +.SS Commands +Commands are contained between lines starting with +.B .R1 +and +.BR .R2 . +Recognition of these lines can be prevented by the +.B \-R +option. +When a +.B .R1 +line is recognized any accumulated references are flushed out. +Neither +.B .R1 +nor +.B .R2 +lines, +nor anything between them +is output. +.LP +Commands are separated by newlines or +.BR ; s. +.B # +introduces a comment that extends to the end of the line +(but does not conceal the newline). +Each command is broken up into words. +Words are separated by spaces or tabs. +A word that begins with +.B \(ts +extends to the next +.B \(ts +that is not followed by another +.BR \(ts . +If there is no such +.B \(ts +the word extends to the end of the line. +Pairs of +.B \(ts +in a word beginning with +.B \(ts +collapse to a single +.BR \(ts . +Neither +.B # +nor +.B ; +are recognized inside +.BR \(ts s. +A line can be continued by ending it with +.BR \e ; +this works everywhere except after a +.BR # . +.LP +.ds n \fR* +Each command +.I name +that is marked with \*n has an associated negative command +.BI no- name +that undoes the effect of +.IR name . +For example, the +.B no-sort +command specifies that references should not be sorted. +The negative commands take no arguments. +.LP +In the following description each argument must be a single word; +.I field +is used for a single upper or lower case letter naming a field; +.I fields +is used for a sequence of such letters; +.I m +and +.I n +are used for a non-negative numbers; +.I string +is used for an arbitrary string; +.I filename +is used for the name of a file. +.Tp \w'\fBabbreviate-label-ranges'u+2n +.BI abbreviate\*n\ fields\ string1\ string2\ string3\ string4 +Abbreviate the first names of +.IR fields . +An initial letter will be separated from another initial letter by +.IR string1 , +from the last name by +.IR string2 , +and from anything else +(such as a +.B von +or +.BR de ) +by +.IR string3 . +These default to a period followed by a space. +In a hyphenated first name, +the initial of the first part of the name will be separated from the hyphen by +.IR string4 ; +this defaults to a period. +No attempt is made to handle any ambiguities that might +result from abbreviation. +Names are abbreviated before sorting and before +label construction. +.TP +.BI abbreviate-label-ranges\*n\ string +Three or more adjacent labels that refer to consecutive references +will be abbreviated to a label consisting +of the first label, followed by +.I string +followed by the last label. +This is mainly useful with numeric labels. +If +.I string +is omitted it defaults to +.BR \- . +.TP +.B accumulate\*n +Accumulate references instead of writing out each reference +as it is encountered. +Accumulated references will be written out whenever a reference +of the form +.RS +.IP +.B .[ +.br +.B $LIST$ +.br +.B .] +.LP +is encountered, +after all input files hve been processed, +and whenever +.B .R1 +line is recognized. +.RE +.TP +.BI annotate\*n\ field\ string +.I field +is an annotation; +print it at the end of the reference as a paragraph preceded by the line +.RS +.IP +.BI . string +.LP +If +.I macro +is omitted it will default to +.BR AP ; +if +.I field +is also omitted it will default to +.BR X . +Only one field can be an annotation. +.RE +.TP +.BI articles\ string \fR\|.\|.\|. +.IR string \|.\|.\|. +are definite or indefinite articles, and should be ignored at the beginning of +.B T +fields when sorting. +Initially, +.BR the , +.B a +and +.B an +are recognized as articles. +.TP +.BI bibliography\ filename \fR\|.\|.\|. +Write out all the references contained in the bibliographic databases +.IR filename \|.\|.\|. +.TP +.BI bracket-label\ string1\ string2\ string3 +In the text, bracket each label +with +.I string1 +and +.IR string2 . +An occurrence of +.I string2 +immediately followed by +.I string1 +will be turned into +.IR string3 . +The default behaviour is +.RS +.IP +.B +bracket-label \e*([. \e*(.] ", " +.RE +.TP +.BI capitalize\ fields +Convert +.I fields +to caps and small caps. +.TP +.B compatible\*n +Recognize +.B .R1 +and +.B .R2 +even when followed by a character other than space or newline. +.TP +.BI database\ filename \fR\|.\|.\|. +Search the bibligraphic databases +.IR filename \|.\|.\|. +For each +.I filename +if an index +.IB filename .i +created by +.BR indxbib (1) +exists, then it will be searched instead; +each index can cover multiple databases. +.TP +.BI date-as-label\*n\ string +.I string +is a label expression that specifies a string with which to replace the +.B D +field after constructing the label. +See the +.B "Label expressions" +subsection for a description of label expressions. +This command is useful if you do not want explicit labels in the +reference list, but instead want to handle any necessary +disambiguation by qualifying the date in some way. +The label used in the text would typically be some combination of the +author and date. +In most cases you should also use the +.B no-label-in-reference +command. +For example, +.RS +.IP +.B +date-as-label D.+yD.y%a*D.-y +.LP +would attach a disambiguating letter to the year part of the +.B D +field in the reference. +.RE +.TP +.B default-database\*n +The default database should be searched. +This is the default behaviour, so the negative version of +this command is more useful. +refer determines whether the default database should be searched +on the first occasion that it needs to do a search. +Thus a +.B no-default-database +command must be given before then, +in order to be effective. +.TP +.BI discard\*n\ fields +When the reference is read, +.I fields +should be discarded; +no string definitions for +.I fields +will be output. +Initially, +.I fields +are +.BR XYZ . +.TP +.BI et-al\*n\ string\ m\ n +Control use of +.B +et al +in the evaluation of +.B @ +expressions in label expressions. +If the number of authors needed to make the author sequence +unambiguous is +.I u +and the total number of authors is +.I t +then the last +.IR t \|\-\| u +authors will be replaced by +.I string +provided that +.IR t \|\-\| u +is not less than +.I m +and +.I t +is not less than +.IR n . +The default behaviour is +.RS +.IP +.B +et-al " et al" 2 3 +.RE +.TP +.BI include\ filename +Include +.I filename +and interpret the contents as commands. +.TP +.BI join-authors\ string1\ string2\ string3 +This says how authors should be joined together. +When there are exactly two authors, they will be joined with +.IR string1 . +When there are more than two authors, all but the last two will +be joined with +.IR string2 , +and the last two authors will be joined with +.IR string3 . +If +.I string3 +is omitted, +it will default to +.IR string1 ; +if +.I string2 +is also omitted it will also default to +.IR string1 . +For example, +.RS +.IP +.B +join-authors " and " ", " ", and " +.LP +will restore the default method for joining authors. +.RE +.TP +.B label-in-reference\*n +When outputting the reference, +define the string +.B [F +to be the reference's label. +This is the default behaviour; so the negative version +of this command is more useful. +.TP +.B label-in-text\*n +For each reference output a label in the text. +The label will be separated from the surrounding text as described in the +.B bracket-label +command. +This is the default behaviour; so the negative version +of this command is more useful. +.TP +.BI label\ string +.I string +is a label expression describing how to label each reference. +.TP +.BI separate-label-second-parts\ string +When merging two-part labels, separate the second part of the second +label from the first label with +.IR string . +See the description of the +.B <> +label expression. +.TP +.B move-punctuation\*n +In the text, move any punctuation at the end of line past the label. +It is usually a good idea to give this command unless you are using +superscripted numbers as labels. +.TP +.BI reverse\*n\ string +Reverse the fields whose names +are in +.IR string . +Each field name can be followed by a number which says +how many such fields should be reversed. +If no number is given for a field, all such fields will be reversed. +.TP +.BI search-ignore\*n\ fields +While searching for keys in databases for which no index exists, +ignore the contents of +.IR fields . +Initially, fields +.B XYZ +are ignored. +.TP +.BI search-truncate\*n\ n +Only require the first +.I n +characters of keys to be given. +In effect when searching for a given key +words in the database are truncated to the maximum of +.I n +and the length of the key. +Initially +.I n +is 6. +.TP +.BI short-label\*n\ string +.I string +is a label expression that specifies an alternative (usually shorter) +style of label. +This is used when the +.B # +flag is given in the citation. +When using author-date style labels, the identity of the author +or authors is sometimes clear from the context, and so it +may be desirable to omit the author or authors from the label. +The +.B short-label +command will typically be used to specify a label containing just +a date and possibly a disambiguating letter. +.TP +.BI sort\*n\ string +Sort references according to +.BR string . +References will automatically be accumulated. +.I string +should be a list of field names, each followed by a number, +indicating how many fields with the name should be used for sorting. +.B + +can be used to indicate that all the fields with the name should be used. +Also +.B . +can be used to indicate the references should be sorted using the +(tentative) label. +(The +.B +Label expressions +subsection describes the concept of a tentative label.) +.TP +.B sort-adjacent-labels\*n +Sort labels that are adjacent in the text according to their +position in the reference list. +This command should usually be given if the +.B abbreviate-label-ranges +command has been given, +or if the label expression contains a +.B <> +expression. +This will have no effect unless references are being accumulated. +.SS Label expressions +.LP +Label expressions can be evaluated both normally and tentatively. +The result of normal evaluation is used for output. +The result of tentative evaluation, called the +.I +tentative label, +is used to gather the information +that normal evaluation needs to disambiguate the label. +Label expressions specified by the +.B date-as-label +and +.B short-label +commands are not evaluated tentatively. +Normal and tentative evaluation are the same for all types +of expression other than +.BR @ , +.BR * , +and +.B % +expressions. +The description below applies to normal evaluation, +except where otherwise specified. +.TP +.I field +.TQ +.I field\ n +The +.IR n -th +part of +.IR field . +If +.I n +is omitted, it defaults to 1. +.TP +.BI ' string ' +The characters in +.I string +literally. +.TP +.B @ +All the authors joined as specified by the +.B join-authors +command. +The whole of each author's name will be used. +However, if the references are sorted by author +(that is the sort specification starts with +.BR A+ ), +then authors' last names will be used instead, provided that this does +not introduce ambiguity, +and also an initial subsequence of the authors may be used +instead of all the authors, again provided that this does not +introduce ambiguity. +The use of only the last name for the +.IR i -th +author of some reference +is considered to be ambiguous if +there is some other reference, +such that the first +.IR i \|-\|1 +authors of the references are the same, +the +.IR i -th +authors are not the same, +but the +.IR i -th +authors' last names are the same. +A proper initial subsequence of the sequence +of authors for some reference is considered to be ambiguous if there is +a reference with some other sequence of authors which also has +that subsequence as a proper initial subsequence. +When an initial subsequence of authors is used, the remaining +authors are replaced by the string specified by the +.B et-al +command; +this command may also specify additional requirements that must be +met before an initial subsequence can be used. +.B @ +tentatively evaluates to a canonical representation of the authors, +such that authors that compare equally for sorting purpose +will have the same representation. +.TP +.BI % n +.TQ +.B %a +.TQ +.B %A +.TQ +.B %i +.TQ +.B %I +The serial number of the reference formatted according to the character +following the +.BR % . +The serial number of a reference is 1 plus the number of earlier references +with same tentative label as this reference. +These expressions tentatively evaluate to an empty string. +.TP +.IB expr * +If there is another reference with the same tentative label as +this reference, then +.IR expr , +otherwise an empty string. +It tentatively evaluates to an empty string. +.TP +.IB expr + n +.TQ +.IB expr \- n +The first +.RB ( + ) +or last +.RB ( \- ) +.I n +upper or lower case letters or digits of +.IR expr . +Troff special characters (such as +.BR \e('a ) +count as a single letter. +Accent strings are retained but do not count towards the total. +.TP +.IB expr .l +.I expr +converted to lowercase. +.TP +.IB expr .u +.I expr +converted to uppercase. +.TP +.IB expr .c +.I expr +converted to caps and small caps. +.TP +.IB expr .r +.I expr +reversed so that the last name is first. +.TP +.IB expr .a +.I expr +with first names abbreviated. +Note that fields specified in the +.B abbreviate +command are abbreviated before any labels are evaluated. +Thus +.B .a +is useful only when you want a field to be abbreviated in a label +but not in a reference. +.TP +.IB expr .y +The year part of +.IR expr . +.TP +.IB expr .+y +The part of +.I expr +before the year, or the whole of +.I expr +if it does not contain a year. +.TP +.IB expr .\-y +The part of +.I expr +after the year, or an empty string if +.I expr +does not contain a year. +.TP +.IB expr .n +The last name part of +.IR expr . +.TP +.IB expr1 \(ti expr2 +.I expr1 +except that if the last character of +.I expr1 +is +.B \- +then it will be replaced by +.IR expr2 . +.TP +.I expr1\ expr2 +The concatenation of +.I expr1 +and +.IR expr2 . +.TP +.IB expr1 | expr2 +If +.I expr1 +is non-empty then +.I expr1 +otherwise +.IR expr2 . +.TP +.IB expr1 & expr2 +If +.I expr1 +is non-empty +then +.I expr2 +otherwise an empty string. +.TP +.IB expr1 ? expr2 : expr3 +If +.I expr1 +is non-empty +then +.I expr2 +otherwise +.IR expr3 . +.TP +.BI < expr > +The label is in two parts, which are separated by +.IR expr . +Two adjacent two-part labels which have the same first part will be +merged by appending the second part of the second label onto the first +label separated by the string specified in the +.B separate-label-second-parts +command (initially, a comma followed by a space); the resulting label +will also be a two-part label with the same first part as before +merging, and so additional labels can be merged into it. +Note that it is permissible for the first part to be empty; +this maybe desirable for expressions used in the +.B short-label +command. +.TP +.BI ( expr ) +The same as +.IR expr . +Used for grouping. +.LP +The above expressions are listed in order of precedence +(highest first); +.B & +and +.B | +have the same precedence. +.SS Macro interface +Each reference starts with a call to the macro +.BR ]- . +The string +.B [F +will be defined to be the label for this reference, +unless the +.B no-label-in-reference +command has been given. +There then follows a series of string definitions, +one for each field: +string +.BI [ X +corresponds to field +.IR X . +The number register +.B [P +is set to 1 if the +.B P +field contains a range of pages. +The +.BR [T , +.B [A +and +.B [O +number registers are set to 1 according as the +.BR T , +.B A +and +.B O +fields end with one of the characters +.BR .?! . +The +.B [E +number register will be set to 1 if the +.B [E +string contains more than one name. +The reference is followed by a call to the +.B ][ +macro. +The first argument to this macro gives a number representing +the type of the reference. +If a reference contains a +.B J +field, it will be classified as type 1, +otherwise if it contains a +.B B +field, it will type 3, +otherwise if it contains a +.B G +or +.B R +field it will be type 4, +otherwise if contains a +.B I +field it will be type 2, +otherwise it will be type 0. +The second argument is a symbolic name for the type: +.BR other , +.BR journal-article , +.BR book , +.B article-in-book +or +.BR tech-report . +Groups of references that have been accumulated +or are produced by the +.B bibliography +command are preceded by a call to the +.B ]< +macro and followed by a call to the +.B ]> +macro. +.SH FILES +.Tp \w'\fB/usr/share/dict/papers/Ind'u+2n +.B /usr/share/dict/papers/Ind +Default database. +.TP +.IB file .i +Index files. +.SH "SEE ALSO" +.BR indxbib (1), +.BR lookbib (1), +.BR lkbib (1) +.br +.SH BUGS +In label expressions, +.B <> +expressions are ignored inside +.BI . char +expressions. diff --git a/gnu/usr.bin/groff/refer/refer.cc b/gnu/usr.bin/groff/refer/refer.cc new file mode 100644 index 0000000000..cb6e218e3e --- /dev/null +++ b/gnu/usr.bin/groff/refer/refer.cc @@ -0,0 +1,1221 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "refer.h" +#include "refid.h" +#include "ref.h" +#include "token.h" +#include "search.h" +#include "command.h" + +const char PRE_LABEL_MARKER = '\013'; +const char POST_LABEL_MARKER = '\014'; +const char LABEL_MARKER = '\015'; // label_type is added on + +#define FORCE_LEFT_BRACKET 04 +#define FORCE_RIGHT_BRACKET 010 + +static FILE *outfp = stdout; + +string capitalize_fields; +string reverse_fields; +string abbreviate_fields; +string period_before_last_name = ". "; +string period_before_initial = "."; +string period_before_hyphen = ""; +string period_before_other = ". "; +string sort_fields; +int annotation_field = -1; +string annotation_macro; +string discard_fields = "XYZ"; +string pre_label = "\\*([."; +string post_label = "\\*(.]"; +string sep_label = ", "; +int accumulate = 0; +int move_punctuation = 0; +int abbreviate_label_ranges = 0; +string label_range_indicator; +int label_in_text = 1; +int label_in_reference = 1; +int date_as_label = 0; +int sort_adjacent_labels = 0; +// Join exactly two authors with this. +string join_authors_exactly_two = " and "; +// When there are more than two authors join the last two with this. +string join_authors_last_two = ", and "; +// Otherwise join authors with this. +string join_authors_default = ", "; +string separate_label_second_parts = ", "; +// Use this string to represent that there are other authors. +string et_al = " et al"; +// Use et al only if it can replace at least this many authors. +int et_al_min_elide = 2; +// Use et al only if the total number of authors is at least this. +int et_al_min_total = 3; + + +int compatible_flag = 0; + +int short_label_flag = 0; + +static int recognize_R1_R2 = 1; + +search_list database_list; +int search_default = 1; +static int default_database_loaded = 0; + +static reference **citation = 0; +static int ncitations = 0; +static int citation_max = 0; + +static reference **reference_hash_table = 0; +static int hash_table_size; +static int nreferences = 0; + +static int need_syncing = 0; +string pending_line; +string pending_lf_lines; + +static void output_pending_line(); +static unsigned immediately_handle_reference(const string &); +static void immediately_output_references(); +static unsigned store_reference(const string &); +static void divert_to_temporary_file(); +static reference *make_reference(const string &, unsigned *); +static void usage(); +static void do_file(const char *); +static void split_punct(string &line, string &punct); +static void output_citation_group(reference **v, int n, label_type, FILE *fp); +static void possibly_load_default_database(); + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + outfp = stdout; + int finished_options = 0; + int bib_flag = 0; + int done_spec = 0; + + for (--argc, ++argv; + !finished_options && argc > 0 && argv[0][0] == '-' + && argv[0][1] != '\0'; + argv++, argc--) { + const char *opt = argv[0] + 1; + while (opt != 0 && *opt != '\0') { + switch (*opt) { + case 'C': + compatible_flag = 1; + opt++; + break; + case 'B': + bib_flag = 1; + label_in_reference = 0; + label_in_text = 0; + ++opt; + if (*opt == '\0') { + annotation_field = 'X'; + annotation_macro = "AP"; + } + else if (csalnum(opt[0]) && opt[1] == '.' && opt[2] != '\0') { + annotation_field = opt[0]; + annotation_macro = opt + 2; + } + opt = 0; + break; + case 'P': + move_punctuation = 1; + opt++; + break; + case 'R': + recognize_R1_R2 = 0; + opt++; + break; + case 'S': + // Not a very useful spec. + set_label_spec("(A.n|Q)', '(D.y|D)"); + done_spec = 1; + pre_label = " ("; + post_label = ")"; + sep_label = "; "; + opt++; + break; + case 'V': + verify_flag = 1; + opt++; + break; + case 'f': + { + const char *num = 0; + if (*++opt == '\0') { + if (argc > 1) { + num = *++argv; + --argc; + } + else { + error("option `f' requires an argument"); + usage(); + } + } + else { + num = opt; + opt = 0; + } + for (const char *ptr = num; *ptr; ptr++) + if (!csdigit(*ptr)) { + error("bad character `%1' in argument to -f option", *ptr); + break; + } + if (*ptr == '\0') { + string spec; + spec = '%'; + spec += num; + spec += '\0'; + set_label_spec(spec.contents()); + done_spec = 1; + } + break; + } + case 'b': + label_in_text = 0; + label_in_reference = 0; + opt++; + break; + case 'e': + accumulate = 1; + opt++; + break; + case 'c': + capitalize_fields = ++opt; + opt = 0; + break; + case 'k': + { + char buf[5]; + if (csalpha(*++opt)) + buf[0] = *opt++; + else { + if (*opt != '\0') + error("bad field name `%1'", *opt++); + buf[0] = 'L'; + } + buf[1] = '~'; + buf[2] = '%'; + buf[3] = 'a'; + buf[4] = '\0'; + set_label_spec(buf); + done_spec = 1; + } + break; + case 'a': + { + for (const char *ptr = ++opt; *ptr; ptr++) + if (!csdigit(*ptr)) { + error("argument to `a' option not a number"); + break; + } + if (*ptr == '\0') { + reverse_fields = 'A'; + reverse_fields += opt; + } + opt = 0; + } + break; + case 'i': + linear_ignore_fields = ++opt; + opt = 0; + break; + case 'l': + { + char buf[INT_DIGITS*2 + 11]; // A.n+2D.y-3%a + strcpy(buf, "A.n"); + if (*++opt != '\0' && *opt != ',') { + char *ptr; + long n = strtol(opt, &ptr, 10); + if (n == 0 && ptr == opt) { + error("bad integer `%1' in `l' option", opt); + opt = 0; + break; + } + if (n < 0) + n = 0; + opt = ptr; + sprintf(strchr(buf, '\0'), "+%d", n); + } + strcat(buf, "D.y"); + if (*opt == ',') + opt++; + if (*opt != '\0') { + char *ptr; + long n = strtol(opt, &ptr, 10); + if (n == 0 && ptr == opt) { + error("bad integer `%1' in `l' option", opt); + opt = 0; + break; + } + if (n < 0) + n = 0; + sprintf(strchr(buf, '\0'), "-%d", n); + opt = ptr; + if (*opt != '\0') + error("argument to `l' option not of form `m,n'"); + } + strcat(buf, "%a"); + if (!set_label_spec(buf)) + assert(0); + done_spec = 1; + } + break; + case 'n': + search_default = 0; + opt++; + break; + case 'p': + { + const char *filename = 0; + if (*++opt == '\0') { + if (argc > 1) { + filename = *++argv; + argc--; + } + else { + error("option `p' requires an argument"); + usage(); + } + } + else { + filename = opt; + opt = 0; + } + database_list.add_file(filename); + } + break; + case 's': + if (*++opt == '\0') + sort_fields = "AD"; + else { + sort_fields = opt; + opt = 0; + } + accumulate = 1; + break; + case 't': + { + char *ptr; + long n = strtol(opt, &ptr, 10); + if (n == 0 && ptr == opt) { + error("bad integer `%1' in `t' option", opt); + opt = 0; + break; + } + if (n < 1) + n = 1; + linear_truncate_len = int(n); + opt = ptr; + break; + } + case 'v': + { + extern const char *version_string; + fprintf(stderr, "GNU refer version %s\n", version_string); + fflush(stderr); + opt++; + break; + } + case '-': + if (opt[1] == '\0') { + finished_options = 1; + opt++; + break; + } + // fall through + default: + error("unrecognized option `%1'", *opt); + usage(); + break; + } + } + } + if (!done_spec) + set_label_spec("%1"); + if (argc <= 0) { + if (bib_flag) + do_bib("-"); + else + do_file("-"); + } + else { + for (int i = 0; i < argc; i++) { + if (bib_flag) + do_bib(argv[i]); + else + do_file(argv[i]); + } + } + if (accumulate) + output_references(); + if (fflush(stdout) < 0) + fatal("output error"); + exit(0); +} + +static void usage() +{ + fprintf(stderr, +"usage: %s [-benvCPRS] [-aN] [-cXYZ] [-fN] [-iXYZ] [-kX] [-lM,N] [-p file]\n" +" [-sXYZ] [-tN] [-BL.M] [files ...]\n", + program_name); + exit(1); +} + +static void possibly_load_default_database() +{ + if (search_default && !default_database_loaded) { + char *filename = getenv("REFER"); + if (filename) + database_list.add_file(filename); + else + database_list.add_file(DEFAULT_INDEX, 1); + default_database_loaded = 1; + } +} + +static int is_list(const string &str) +{ + const char *start = str.contents(); + const char *end = start + str.length(); + while (end > start && csspace(end[-1])) + end--; + while (start < end && csspace(*start)) + start++; + return end - start == 6 && memcmp(start, "$LIST$", 6) == 0; +} + +static void do_file(const char *filename) +{ + FILE *fp; + if (strcmp(filename, "-") == 0) { + fp = stdin; + } + else { + errno = 0; + fp = fopen(filename, "r"); + if (fp == 0) { + error("can't open `%1': %2", filename, strerror(errno)); + return; + } + current_filename = filename; + } + fprintf(outfp, ".lf 1 %s\n", filename); + string line; + current_lineno = 0; + for (;;) { + line.clear(); + for (;;) { + int c = getc(fp); + if (c == EOF) { + if (line.length() > 0) + line += '\n'; + break; + } + if (illegal_input_char(c)) + error("illegal input character code %1", c); + else { + line += c; + if (c == '\n') + break; + } + } + int len = line.length(); + if (len == 0) + break; + current_lineno++; + if (len >= 2 && line[0] == '.' && line[1] == '[') { + int start_lineno = current_lineno; + int start_of_line = 1; + string str; + string post; + string pre(line.contents() + 2, line.length() - 3); + for (;;) { + int c = getc(fp); + if (c == EOF) { + error_with_file_and_line(current_filename, start_lineno, + "missing `.]' line"); + break; + } + if (start_of_line) + current_lineno++; + if (start_of_line && c == '.') { + int d = getc(fp); + if (d == ']') { + while ((d = getc(fp)) != '\n' && d != EOF) { + if (illegal_input_char(d)) + error("illegal input character code %1", d); + else + post += d; + } + break; + } + if (d != EOF) + ungetc(d, fp); + } + if (illegal_input_char(c)) + error("illegal input character code %1", c); + else + str += c; + start_of_line = (c == '\n'); + } + if (is_list(str)) { + output_pending_line(); + if (accumulate) + output_references(); + else + error("found `$LIST$' but not accumulating references"); + } + else { + unsigned flags = (accumulate + ? store_reference(str) + : immediately_handle_reference(str)); + if (label_in_text) { + if (accumulate && outfp == stdout) + divert_to_temporary_file(); + if (pending_line.length() == 0) { + warning("can't attach citation to previous line"); + } + else + pending_line.set_length(pending_line.length() - 1); + string punct; + if (move_punctuation) + split_punct(pending_line, punct); + int have_text = pre.length() > 0 || post.length() > 0; + label_type lt = label_type(flags & ~(FORCE_LEFT_BRACKET + |FORCE_RIGHT_BRACKET)); + if ((flags & FORCE_LEFT_BRACKET) || !have_text) + pending_line += PRE_LABEL_MARKER; + pending_line += pre; + pending_line += LABEL_MARKER + lt; + pending_line += post; + if ((flags & FORCE_RIGHT_BRACKET) || !have_text) + pending_line += POST_LABEL_MARKER; + pending_line += punct; + pending_line += '\n'; + } + } + need_syncing = 1; + } + else if (len >= 4 + && line[0] == '.' && line[1] == 'l' && line[2] == 'f' + && (compatible_flag || line[3] == '\n' || line[3] == ' ')) { + pending_lf_lines += line; + line += '\0'; + if (interpret_lf_args(line.contents() + 3)) + current_lineno--; + } + else if (recognize_R1_R2 + && len >= 4 + && line[0] == '.' && line[1] == 'R' && line[2] == '1' + && (compatible_flag || line[3] == '\n' || line[3] == ' ')) { + line.clear(); + int start_of_line = 1; + int start_lineno = current_lineno; + for (;;) { + int c = getc(fp); + if (c != EOF && start_of_line) + current_lineno++; + if (start_of_line && c == '.') { + c = getc(fp); + if (c == 'R') { + c = getc(fp); + if (c == '2') { + c = getc(fp); + if (compatible_flag || c == ' ' || c == '\n' || c == EOF) { + while (c != EOF && c != '\n') + c = getc(fp); + break; + } + else { + line += '.'; + line += 'R'; + line += '2'; + } + } + else { + line += '.'; + line += 'R'; + } + } + else + line += '.'; + } + if (c == EOF) { + error_with_file_and_line(current_filename, start_lineno, + "missing `.R2' line"); + break; + } + if (illegal_input_char(c)) + error("illegal input character code %1", int(c)); + else { + line += c; + start_of_line = c == '\n'; + } + } + output_pending_line(); + if (accumulate) + output_references(); + else + nreferences = 0; + process_commands(line, current_filename, start_lineno + 1); + need_syncing = 1; + } + else { + output_pending_line(); + pending_line = line; + } + } + need_syncing = 0; + output_pending_line(); + if (fp != stdin) + fclose(fp); +} + +class label_processing_state { + enum { + NORMAL, + PENDING_LABEL, + PENDING_LABEL_POST, + PENDING_LABEL_POST_PRE, + PENDING_POST + } state; + label_type type; // type of pending labels + int count; // number of pending labels + reference **rptr; // pointer to next reference + int rcount; // number of references left + FILE *fp; + int handle_pending(int c); +public: + label_processing_state(reference **, int, FILE *); + ~label_processing_state(); + void process(int c); +}; + +static void output_pending_line() +{ + if (label_in_text && !accumulate && ncitations > 0) { + label_processing_state state(citation, ncitations, outfp); + int len = pending_line.length(); + for (int i = 0; i < len; i++) + state.process((unsigned char)(pending_line[i])); + } + else + put_string(pending_line, outfp); + pending_line.clear(); + if (pending_lf_lines.length() > 0) { + put_string(pending_lf_lines, outfp); + pending_lf_lines.clear(); + } + if (!accumulate) + immediately_output_references(); + if (need_syncing) { + fprintf(outfp, ".lf %d %s\n", current_lineno, current_filename); + need_syncing = 0; + } +} + +static void split_punct(string &line, string &punct) +{ + const char *start = line.contents(); + const char *end = start + line.length(); + const char *ptr = start; + const char *last_token_start = 0; + for (;;) { + if (ptr >= end) + break; + last_token_start = ptr; + if (*ptr == PRE_LABEL_MARKER || *ptr == POST_LABEL_MARKER + || (*ptr >= LABEL_MARKER && *ptr < LABEL_MARKER + N_LABEL_TYPES)) + ptr++; + else if (!get_token(&ptr, end)) + break; + } + if (last_token_start) { + const token_info *ti = lookup_token(last_token_start, end); + if (ti->is_punct()) { + punct.append(last_token_start, end - last_token_start); + line.set_length(last_token_start - start); + } + } +} + +static void divert_to_temporary_file() +{ + outfp = xtmpfile(); +} + +static void store_citation(reference *ref) +{ + if (ncitations >= citation_max) { + if (citation == 0) + citation = new reference*[citation_max = 100]; + else { + reference **old_citation = citation; + citation_max *= 2; + citation = new reference *[citation_max]; + memcpy(citation, old_citation, ncitations*sizeof(reference *)); + a_delete old_citation; + } + } + citation[ncitations++] = ref; +} + +static unsigned store_reference(const string &str) +{ + if (reference_hash_table == 0) { + reference_hash_table = new reference *[17]; + hash_table_size = 17; + for (int i = 0; i < hash_table_size; i++) + reference_hash_table[i] = 0; + } + unsigned flags; + reference *ref = make_reference(str, &flags); + ref->compute_hash_code(); + unsigned h = ref->hash(); + for (reference **ptr = reference_hash_table + (h % hash_table_size); + *ptr != 0; + ((ptr == reference_hash_table) + ? (ptr = reference_hash_table + hash_table_size - 1) + : --ptr)) + if (same_reference(**ptr, *ref)) + break; + if (*ptr != 0) { + if (ref->is_merged()) + warning("fields ignored because reference already used"); + delete ref; + ref = *ptr; + } + else { + *ptr = ref; + ref->set_number(nreferences); + nreferences++; + ref->pre_compute_label(); + ref->compute_sort_key(); + if (nreferences*2 >= hash_table_size) { + // Rehash it. + reference **old_table = reference_hash_table; + int old_size = hash_table_size; + hash_table_size = next_size(hash_table_size); + reference_hash_table = new reference*[hash_table_size]; + int i; + for (i = 0; i < hash_table_size; i++) + reference_hash_table[i] = 0; + for (i = 0; i < old_size; i++) + if (old_table[i]) { + for (reference **p = (reference_hash_table + + (old_table[i]->hash() % hash_table_size)); + *p; + ((p == reference_hash_table) + ? (p = reference_hash_table + hash_table_size - 1) + : --p)) + ; + *p = old_table[i]; + } + a_delete old_table; + } + } + if (label_in_text) + store_citation(ref); + return flags; +} + +unsigned immediately_handle_reference(const string &str) +{ + unsigned flags; + reference *ref = make_reference(str, &flags); + ref->set_number(nreferences); + if (label_in_text || label_in_reference) { + ref->pre_compute_label(); + ref->immediate_compute_label(); + } + nreferences++; + store_citation(ref); + return flags; +} + +static void immediately_output_references() +{ + for (int i = 0; i < ncitations; i++) { + reference *ref = citation[i]; + if (label_in_reference) { + fputs(".ds [F ", outfp); + const string &label = ref->get_label(NORMAL_LABEL); + if (label.length() > 0 + && (label[0] == ' ' || label[0] == '\\' || label[0] == '"')) + putc('"', outfp); + put_string(label, outfp); + putc('\n', outfp); + } + ref->output(outfp); + delete ref; + } + ncitations = 0; +} + +static void output_citation_group(reference **v, int n, label_type type, + FILE *fp) +{ + if (sort_adjacent_labels) { + // Do an insertion sort. Usually n will be very small. + for (int i = 1; i < n; i++) { + int num = v[i]->get_number(); + reference *temp = v[i]; + for (int j = i - 1; j >= 0 && v[j]->get_number() > num; j--) + v[j + 1] = v[j]; + v[j + 1] = temp; + } + } + // This messes up if !accumulate. + if (accumulate && n > 1) { + // remove duplicates + int j = 1; + for (int i = 1; i < n; i++) + if (v[i]->get_label(type) != v[i - 1]->get_label(type)) + v[j++] = v[i]; + n = j; + } + string merged_label; + for (int i = 0; i < n; i++) { + int nmerged = v[i]->merge_labels(v + i + 1, n - i - 1, type, merged_label); + if (nmerged > 0) { + put_string(merged_label, fp); + i += nmerged; + } + else + put_string(v[i]->get_label(type), fp); + if (i < n - 1) + put_string(sep_label, fp); + } +} + + +label_processing_state::label_processing_state(reference **p, int n, FILE *f) +: state(NORMAL), count(0), rptr(p), rcount(n), fp(f) +{ +} + +label_processing_state::~label_processing_state() +{ + int handled = handle_pending(EOF); + assert(!handled); + assert(rcount == 0); +} + +int label_processing_state::handle_pending(int c) +{ + switch (state) { + case NORMAL: + break; + case PENDING_LABEL: + if (c == POST_LABEL_MARKER) { + state = PENDING_LABEL_POST; + return 1; + } + else { + output_citation_group(rptr, count, type, fp); + rptr += count ; + rcount -= count; + state = NORMAL; + } + break; + case PENDING_LABEL_POST: + if (c == PRE_LABEL_MARKER) { + state = PENDING_LABEL_POST_PRE; + return 1; + } + else { + output_citation_group(rptr, count, type, fp); + rptr += count; + rcount -= count; + put_string(post_label, fp); + state = NORMAL; + } + break; + case PENDING_LABEL_POST_PRE: + if (c >= LABEL_MARKER + && c < LABEL_MARKER + N_LABEL_TYPES + && c - LABEL_MARKER == type) { + count += 1; + state = PENDING_LABEL; + return 1; + } + else { + output_citation_group(rptr, count, type, fp); + rptr += count; + rcount -= count; + put_string(sep_label, fp); + state = NORMAL; + } + break; + case PENDING_POST: + if (c == PRE_LABEL_MARKER) { + put_string(sep_label, fp); + state = NORMAL; + return 1; + } + else { + put_string(post_label, fp); + state = NORMAL; + } + break; + } + return 0; +} + +void label_processing_state::process(int c) +{ + if (handle_pending(c)) + return; + assert(state == NORMAL); + switch (c) { + case PRE_LABEL_MARKER: + put_string(pre_label, fp); + state = NORMAL; + break; + case POST_LABEL_MARKER: + state = PENDING_POST; + break; + case LABEL_MARKER: + case LABEL_MARKER + 1: + count = 1; + state = PENDING_LABEL; + type = label_type(c - LABEL_MARKER); + break; + default: + state = NORMAL; + putc(c, fp); + break; + } +} + +extern "C" { + +static int rcompare(const void *p1, const void *p2) +{ + return compare_reference(**(reference **)p1, **(reference **)p2); +} + +} + +void output_references() +{ + assert(accumulate); + if (nreferences > 0) { + int j = 0; + int i; + for (i = 0; i < hash_table_size; i++) + if (reference_hash_table[i] != 0) + reference_hash_table[j++] = reference_hash_table[i]; + assert(j == nreferences); + for (; j < hash_table_size; j++) + reference_hash_table[j] = 0; + qsort(reference_hash_table, nreferences, sizeof(reference*), rcompare); + for (i = 0; i < nreferences; i++) + reference_hash_table[i]->set_number(i); + compute_labels(reference_hash_table, nreferences); + } + if (outfp != stdout) { + rewind(outfp); + { + label_processing_state state(citation, ncitations, stdout); + int c; + while ((c = getc(outfp)) != EOF) + state.process(c); + } + ncitations = 0; + fclose(outfp); + outfp = stdout; + } + if (nreferences > 0) { + fputs(".]<\n", outfp); + for (int i = 0; i < nreferences; i++) { + if (sort_fields.length() > 0) + reference_hash_table[i]->print_sort_key_comment(outfp); + if (label_in_reference) { + fputs(".ds [F ", outfp); + const string &label = reference_hash_table[i]->get_label(NORMAL_LABEL); + if (label.length() > 0 + && (label[0] == ' ' || label[0] == '\\' || label[0] == '"')) + putc('"', outfp); + put_string(label, outfp); + putc('\n', outfp); + } + reference_hash_table[i]->output(outfp); + delete reference_hash_table[i]; + reference_hash_table[i] = 0; + } + fputs(".]>\n", outfp); + nreferences = 0; + } + clear_labels(); +} + +static reference *find_reference(const char *query, int query_len) +{ + // This is so that error messages look better. + while (query_len > 0 && csspace(query[query_len - 1])) + query_len--; + string str; + for (int i = 0; i < query_len; i++) + str += query[i] == '\n' ? ' ' : query[i]; + str += '\0'; + possibly_load_default_database(); + search_list_iterator iter(&database_list, str.contents()); + reference_id rid; + const char *start; + int len; + if (!iter.next(&start, &len, &rid)) { + error("no matches for `%1'", str.contents()); + return 0; + } + const char *end = start + len; + while (start < end) { + if (*start == '%') + break; + while (start < end && *start++ != '\n') + ; + } + if (start >= end) { + error("found a reference for `%1' but it didn't contain any fields", + str.contents()); + return 0; + } + reference *result = new reference(start, end - start, &rid); + if (iter.next(&start, &len, &rid)) + warning("multiple matches for `%1'", str.contents()); + return result; +} + +static reference *make_reference(const string &str, unsigned *flagsp) +{ + const char *start = str.contents(); + const char *end = start + str.length(); + const char *ptr = start; + while (ptr < end) { + if (*ptr == '%') + break; + while (ptr < end && *ptr++ != '\n') + ; + } + *flagsp = 0; + for (; start < ptr; start++) { + if (*start == '#') + *flagsp = (SHORT_LABEL | (*flagsp & (FORCE_RIGHT_BRACKET + | FORCE_LEFT_BRACKET))); + else if (*start == '[') + *flagsp |= FORCE_LEFT_BRACKET; + else if (*start == ']') + *flagsp |= FORCE_RIGHT_BRACKET; + else if (!csspace(*start)) + break; + } + if (start >= end) { + error("empty reference"); + return new reference; + } + reference *database_ref = 0; + if (start < ptr) + database_ref = find_reference(start, ptr - start); + reference *inline_ref = 0; + if (ptr < end) + inline_ref = new reference(ptr, end - ptr); + if (inline_ref) { + if (database_ref) { + database_ref->merge(*inline_ref); + delete inline_ref; + return database_ref; + } + else + return inline_ref; + } + else if (database_ref) + return database_ref; + else + return new reference; +} + +static void do_ref(const string &str) +{ + if (accumulate) + (void)store_reference(str); + else { + (void)immediately_handle_reference(str); + immediately_output_references(); + } +} + +static void trim_blanks(string &str) +{ + const char *start = str.contents(); + const char *end = start + str.length(); + while (end > start && end[-1] != '\n' && csspace(end[-1])) + --end; + str.set_length(end - start); +} + +void do_bib(const char *filename) +{ + FILE *fp; + if (strcmp(filename, "-") == 0) + fp = stdin; + else { + errno = 0; + fp = fopen(filename, "r"); + if (fp == 0) { + error("can't open `%1': %2", filename, strerror(errno)); + return; + } + current_filename = filename; + } + enum { + START, MIDDLE, BODY, BODY_START, BODY_BLANK, BODY_DOT + } state = START; + string body; + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + if (illegal_input_char(c)) { + error("illegal input character code %1", c); + continue; + } + switch (state) { + case START: + if (c == '%') { + body = c; + state = BODY; + } + else if (c != '\n') + state = MIDDLE; + break; + case MIDDLE: + if (c == '\n') + state = START; + break; + case BODY: + body += c; + if (c == '\n') + state = BODY_START; + break; + case BODY_START: + if (c == '\n') { + do_ref(body); + state = START; + } + else if (c == '.') + state = BODY_DOT; + else if (csspace(c)) { + state = BODY_BLANK; + body += c; + } + else { + body += c; + state = BODY; + } + break; + case BODY_BLANK: + if (c == '\n') { + trim_blanks(body); + do_ref(body); + state = START; + } + else if (csspace(c)) + body += c; + else { + body += c; + state = BODY; + } + break; + case BODY_DOT: + if (c == ']') { + do_ref(body); + state = MIDDLE; + } + else { + body += '.'; + body += c; + state = c == '\n' ? BODY_START : BODY; + } + break; + default: + assert(0); + } + if (c == '\n') + current_lineno++; + } + switch (state) { + case START: + case MIDDLE: + break; + case BODY: + body += '\n'; + do_ref(body); + break; + case BODY_DOT: + case BODY_START: + do_ref(body); + break; + case BODY_BLANK: + trim_blanks(body); + do_ref(body); + break; + } + fclose(fp); +} + +// from the Dragon Book + +unsigned hash_string(const char *s, int len) +{ + const char *end = s + len; + unsigned h = 0, g; + while (s < end) { + h <<= 4; + h += *s++; + if ((g = h & 0xf0000000) != 0) { + h ^= g >> 24; + h ^= g; + } + } + return h; +} + +int next_size(int n) +{ + static const int table_sizes[] = { + 101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, + 80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009, + 16000057, 32000011, 64000031, 128000003, 0 + }; + + for (const int *p = table_sizes; *p <= n && *p != 0; p++) + ; + assert(*p != 0); + return *p; +} + diff --git a/gnu/usr.bin/groff/refer/refer.h b/gnu/usr.bin/groff/refer/refer.h new file mode 100644 index 0000000000..932b85536e --- /dev/null +++ b/gnu/usr.bin/groff/refer/refer.h @@ -0,0 +1,78 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +#include "errarg.h" +#include "error.h" +#include "lib.h" +#include "stringclass.h" +#include "cset.h" +#include "cmap.h" + +#include "defs.h" + +unsigned hash_string(const char *, int); +int next_size(int); + +extern string capitalize_fields; +extern string reverse_fields; +extern string abbreviate_fields; +extern string period_before_last_name; +extern string period_before_initial; +extern string period_before_hyphen; +extern string period_before_other; +extern string sort_fields; +extern int annotation_field; +extern string annotation_macro; +extern string discard_fields; +extern string articles; +extern int abbreviate_label_ranges; +extern string label_range_indicator; +extern int date_as_label; +extern string join_authors_exactly_two; +extern string join_authors_last_two; +extern string join_authors_default; +extern string separate_label_second_parts; +extern string et_al; +extern int et_al_min_elide; +extern int et_al_min_total; + +extern int compatible_flag; + +extern int set_label_spec(const char *); +extern int set_date_label_spec(const char *); +extern int set_short_label_spec(const char *); + +extern int short_label_flag; + +void clear_labels(); +void command_error(const char *, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +struct reference; + +void compute_labels(reference **, int); diff --git a/gnu/usr.bin/groff/refer/token.cc b/gnu/usr.bin/groff/refer/token.cc new file mode 100644 index 0000000000..8847081bd4 --- /dev/null +++ b/gnu/usr.bin/groff/refer/token.cc @@ -0,0 +1,370 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "refer.h" +#include "token.h" + +#define TOKEN_TABLE_SIZE 1009 +// I believe in Icelandic thorn sorts after z. +#define THORN_SORT_KEY "{" + +struct token_table_entry { + const char *tok; + token_info ti; + token_table_entry(); +}; + +token_table_entry token_table[TOKEN_TABLE_SIZE]; +int ntokens = 0; + +static void skip_name(const char **ptr, const char *end) +{ + if (*ptr < end) { + switch (*(*ptr)++) { + case '(': + if (*ptr < end) { + *ptr += 1; + if (*ptr < end) + *ptr += 1; + } + break; + case '[': + while (*ptr < end) + if (*(*ptr)++ == ']') + break; + break; + } + } +} + +int get_token(const char **ptr, const char *end) +{ + if (*ptr >= end) + return 0; + char c = *(*ptr)++; + if (c == '\\' && *ptr < end) { + switch (**ptr) { + default: + *ptr += 1; + break; + case '(': + case '[': + skip_name(ptr, end); + break; + case '*': + case 'f': + *ptr += 1; + skip_name(ptr, end); + break; + } + } + return 1; +} + +token_info::token_info() +: type(TOKEN_OTHER), sort_key(0), other_case(0) +{ +} + +void token_info::set(token_type t, const char *sk, const char *oc) +{ + assert(oc == 0 || t == TOKEN_UPPER || t == TOKEN_LOWER); + type = t; + sort_key = sk; + other_case = oc; +} + +void token_info::sortify(const char *start, const char *end, string &result) + const +{ + if (sort_key) + result += sort_key; + else if (type == TOKEN_UPPER || type == TOKEN_LOWER) { + for (; start < end; start++) + if (csalpha(*start)) + result += cmlower(*start); + } +} + +int token_info::sortify_non_empty(const char *start, const char *end) const +{ + if (sort_key) + return *sort_key != '\0'; + if (type != TOKEN_UPPER && type != TOKEN_LOWER) + return 0; + for (; start < end; start++) + if (csalpha(*start)) + return 1; + return 0; +} + + +void token_info::lower_case(const char *start, const char *end, + string &result) const +{ + if (type != TOKEN_UPPER) { + while (start < end) + result += *start++; + } + else if (other_case) + result += other_case; + else { + while (start < end) + result += cmlower(*start++); + } +} + +void token_info::upper_case(const char *start, const char *end, + string &result) const +{ + if (type != TOKEN_LOWER) { + while (start < end) + result += *start++; + } + else if (other_case) + result += other_case; + else { + while (start < end) + result += cmupper(*start++); + } +} + +token_table_entry::token_table_entry() +: tok(0) +{ +} + +static void store_token(const char *tok, token_type typ, + const char *sk = 0, const char *oc = 0) +{ + unsigned n = hash_string(tok, strlen(tok)) % TOKEN_TABLE_SIZE; + while (n >= 0) { + if (token_table[n].tok == 0) { + if (++ntokens == TOKEN_TABLE_SIZE) + assert(0); + token_table[n].tok = tok; + break; + } + if (strcmp(tok, token_table[n].tok) == 0) + break; + if (--n < 0) + n = TOKEN_TABLE_SIZE - 1; + } + token_table[n].ti.set(typ, sk, oc); +} + + +token_info default_token_info; + +const token_info *lookup_token(const char *start, const char *end) +{ + unsigned n = hash_string(start, end - start) % TOKEN_TABLE_SIZE; + while (n >= 0) { + if (token_table[n].tok == 0) + break; + if (strlen(token_table[n].tok) == end - start + && memcmp(token_table[n].tok, start, end - start) == 0) + return &(token_table[n].ti); + if (--n < 0) + n = TOKEN_TABLE_SIZE - 1; + } + return &default_token_info; +} + +static void init_ascii() +{ + for (const char *p = "abcdefghijklmnopqrstuvwxyz"; *p; p++) { + char buf[2]; + buf[0] = *p; + buf[1] = '\0'; + store_token(strsave(buf), TOKEN_LOWER); + buf[0] = cmupper(buf[0]); + store_token(strsave(buf), TOKEN_UPPER); + } + for (p = "0123456789"; *p; p++) { + char buf[2]; + buf[0] = *p; + buf[1] = '\0'; + const char *s = strsave(buf); + store_token(s, TOKEN_OTHER, s); + } + for (p = ".,:;?!"; *p; p++) { + char buf[2]; + buf[0] = *p; + buf[1] = '\0'; + store_token(strsave(buf), TOKEN_PUNCT); + } + store_token("-", TOKEN_HYPHEN); +} + +static void store_letter(const char *lower, const char *upper, + const char *sort_key = 0) +{ + store_token(lower, TOKEN_LOWER, sort_key, upper); + store_token(upper, TOKEN_UPPER, sort_key, lower); +} + +static void init_letter(unsigned char uc_code, unsigned char lc_code, + const char *sort_key) +{ + char lbuf[2]; + lbuf[0] = lc_code; + lbuf[1] = 0; + char ubuf[2]; + ubuf[0] = uc_code; + ubuf[1] = 0; + store_letter(strsave(lbuf), strsave(ubuf), sort_key); +} + +static void init_latin1() +{ + init_letter(0xc0, 0xe0, "a"); + init_letter(0xc1, 0xe1, "a"); + init_letter(0xc2, 0xe2, "a"); + init_letter(0xc3, 0xe3, "a"); + init_letter(0xc4, 0xe4, "a"); + init_letter(0xc5, 0xe5, "a"); + init_letter(0xc6, 0xe6, "ae"); + init_letter(0xc7, 0xe7, "c"); + init_letter(0xc8, 0xe8, "e"); + init_letter(0xc9, 0xe9, "e"); + init_letter(0xca, 0xea, "e"); + init_letter(0xcb, 0xeb, "e"); + init_letter(0xcc, 0xec, "i"); + init_letter(0xcd, 0xed, "i"); + init_letter(0xce, 0xee, "i"); + init_letter(0xcf, 0xef, "i"); + + init_letter(0xd0, 0xf0, "d"); + init_letter(0xd1, 0xf1, "n"); + init_letter(0xd2, 0xf2, "o"); + init_letter(0xd3, 0xf3, "o"); + init_letter(0xd4, 0xf4, "o"); + init_letter(0xd5, 0xf5, "o"); + init_letter(0xd6, 0xf6, "o"); + init_letter(0xd8, 0xf8, "o"); + init_letter(0xd9, 0xf9, "u"); + init_letter(0xda, 0xfa, "u"); + init_letter(0xdb, 0xfb, "u"); + init_letter(0xdc, 0xfc, "u"); + init_letter(0xdd, 0xfd, "y"); + init_letter(0xde, 0xfe, THORN_SORT_KEY); + + store_token("\337", TOKEN_LOWER, "ss", "SS"); + store_token("\377", TOKEN_LOWER, "y", "Y"); +} + +static void init_two_char_letter(char l1, char l2, char u1, char u2, + const char *sk = 0) +{ + char buf[6]; + buf[0] = '\\'; + buf[1] = '('; + buf[2] = l1; + buf[3] = l2; + buf[4] = '\0'; + const char *p = strsave(buf); + buf[2] = u1; + buf[3] = u2; + store_letter(p, strsave(buf), sk); + buf[1] = '['; + buf[4] = ']'; + buf[5] = '\0'; + p = strsave(buf); + buf[2] = l1; + buf[3] = l2; + store_letter(strsave(buf), p, sk); + +} + +static void init_special_chars() +{ + for (const char *p = "':^`~"; *p; p++) + for (const char *q = "aeiouy"; *q; q++) { + // Use a variable to work around bug in gcc 2.0 + char c = cmupper(*q); + init_two_char_letter(*p, *q, *p, c); + } + for (p = "/l/o~n,coeaeij"; *p; p += 2) { + // Use variables to work around bug in gcc 2.0 + char c0 = cmupper(p[0]); + char c1 = cmupper(p[1]); + init_two_char_letter(p[0], p[1], c0, c1); + } + init_two_char_letter('v', 's', 'v', 'S', "s"); + init_two_char_letter('v', 'z', 'v', 'Z', "z"); + init_two_char_letter('o', 'a', 'o', 'A', "a"); + init_two_char_letter('T', 'p', 'T', 'P', THORN_SORT_KEY); + init_two_char_letter('-', 'd', '-', 'D'); + + store_token("\\(ss", TOKEN_LOWER, 0, "SS"); + store_token("\\[ss]", TOKEN_LOWER, 0, "SS"); + + store_token("\\(Sd", TOKEN_LOWER, "d", "\\(-D"); + store_token("\\[Sd]", TOKEN_LOWER, "d", "\\[-D]"); + store_token("\\(hy", TOKEN_HYPHEN); + store_token("\\[hy]", TOKEN_HYPHEN); +} + +static void init_strings() +{ + char buf[6]; + buf[0] = '\\'; + buf[1] = '*'; + for (const char *p = "'`^^,:~v_o./;"; *p; p++) { + buf[2] = *p; + buf[3] = '\0'; + store_token(strsave(buf), TOKEN_ACCENT); + buf[2] = '['; + buf[3] = *p; + buf[4] = ']'; + buf[5] = '\0'; + store_token(strsave(buf), TOKEN_ACCENT); + } + + // -ms special letters + store_letter("\\*(th", "\\*(Th", THORN_SORT_KEY); + store_letter("\\*[th]", "\\*[Th]", THORN_SORT_KEY); + store_letter("\\*(d-", "\\*(D-"); + store_letter("\\*[d-]", "\\*[D-]"); + store_letter("\\*(ae", "\\*(Ae", "ae"); + store_letter("\\*[ae]", "\\*[Ae]", "ae"); + store_letter("\\*(oe", "\\*(Oe", "oe"); + store_letter("\\*[oe]", "\\*[Oe]", "oe"); + + store_token("\\*3", TOKEN_LOWER, "y", "Y"); + store_token("\\*8", TOKEN_LOWER, "ss", "SS"); + store_token("\\*q", TOKEN_LOWER, "o", "O"); +} + +struct token_initer { + token_initer(); +}; + +static token_initer the_token_initer; + +token_initer::token_initer() +{ + init_ascii(); + init_latin1(); + init_special_chars(); + init_strings(); + default_token_info.set(TOKEN_OTHER); +} diff --git a/gnu/usr.bin/groff/refer/token.h b/gnu/usr.bin/groff/refer/token.h new file mode 100644 index 0000000000..c6445d230f --- /dev/null +++ b/gnu/usr.bin/groff/refer/token.h @@ -0,0 +1,81 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +enum token_type { + TOKEN_OTHER, + TOKEN_UPPER, + TOKEN_LOWER, + TOKEN_ACCENT, + TOKEN_PUNCT, + TOKEN_HYPHEN +}; + +class token_info { +private: + token_type type; + const char *sort_key; + const char *other_case; +public: + token_info(); + void set(token_type, const char *sk = 0, const char *oc = 0); + void lower_case(const char *start, const char *end, string &result) const; + void upper_case(const char *start, const char *end, string &result) const; + void sortify(const char *start, const char *end, string &result) const; + int sortify_non_empty(const char *start, const char *end) const; + int is_upper() const; + int is_lower() const; + int is_accent() const; + int is_other() const; + int is_punct() const; + int is_hyphen() const; +}; + +inline int token_info::is_upper() const +{ + return type == TOKEN_UPPER; +} + +inline int token_info::is_lower() const +{ + return type == TOKEN_LOWER; +} + +inline int token_info::is_accent() const +{ + return type == TOKEN_ACCENT; +} + +inline int token_info::is_other() const +{ + return type == TOKEN_OTHER; +} + +inline int token_info::is_punct() const +{ + return type == TOKEN_PUNCT; +} + +inline int token_info::is_hyphen() const +{ + return type == TOKEN_HYPHEN; +} + +int get_token(const char **ptr, const char *end); +const token_info *lookup_token(const char *start, const char *end); diff --git a/gnu/usr.bin/groff/soelim/Makefile b/gnu/usr.bin/groff/soelim/Makefile new file mode 100644 index 0000000000..d9059b3eaf --- /dev/null +++ b/gnu/usr.bin/groff/soelim/Makefile @@ -0,0 +1,12 @@ +# Makefile for soelim + +PROG= soelim +SRCS= soelim.cc +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBGROFF) +DPADD+= $(LIBGROFF) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/soelim/Makefile.dep b/gnu/usr.bin/groff/soelim/Makefile.dep new file mode 100644 index 0000000000..6cfd475467 --- /dev/null +++ b/gnu/usr.bin/groff/soelim/Makefile.dep @@ -0,0 +1,2 @@ +soelim.o : soelim.cc ../include/lib.h ../include/errarg.h \ + ../include/error.h ../include/stringclass.h diff --git a/gnu/usr.bin/groff/soelim/soelim.1 b/gnu/usr.bin/groff/soelim/soelim.1 new file mode 100644 index 0000000000..93c0f5f0c3 --- /dev/null +++ b/gnu/usr.bin/groff/soelim/soelim.1 @@ -0,0 +1,42 @@ +.\" -*- nroff -*- +.TH SOELIM 1 "15 September 1992" "Groff Version 1.08" +.SH NAME +soelim \- interpret .so requests in groff input +.SH SYNOPSIS +.B soelim +[ +.B \-Cv +] +[ +.IR files \|.\|.\|.\| +] +.SH DESCRIPTION +.B soelim +reads +.I files +and replaces lines of the form +.IP +.BI .so\ file +.LP +by the contents of +.IR file . +It is useful if files included with +.B so +need to be preprocessed. +Normally, +.B soelim +should be invoked with the +.B \-s +option of +.BR groff . +.SH OPTIONS +.TP +.B \-C +Recognize +.B .so +even when followed by a character other than space or newline. +.TP +.B \-v +Print the version number. +.SH "SEE ALSO" +.BR groff (1) diff --git a/gnu/usr.bin/groff/soelim/soelim.cc b/gnu/usr.bin/groff/soelim/soelim.cc new file mode 100644 index 0000000000..f69baeee88 --- /dev/null +++ b/gnu/usr.bin/groff/soelim/soelim.cc @@ -0,0 +1,278 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "stringclass.h" + +int compatible_flag = 0; + +extern int interpret_lf_args(const char *); + +int do_file(const char *filename); + +void usage() +{ + fprintf(stderr, "usage: %s [ -vC ] [ files ]\n", program_name); + exit(1); +} + +int main(int argc, char **argv) +{ + program_name = argv[0]; + int opt; + while ((opt = getopt(argc, argv, "vC")) != EOF) + switch (opt) { + case 'v': + { + extern const char *version_string; + fprintf(stderr, "GNU soelim version %s\n", version_string); + fflush(stderr); + break; + } + case 'C': + compatible_flag = 1; + break; + case '?': + usage(); + break; + default: + assert(0); + } + int nbad = 0; + if (optind >= argc) + nbad += !do_file("-"); + else + for (int i = optind; i < argc; i++) + nbad += !do_file(argv[i]); + if (ferror(stdout) || fflush(stdout) < 0) + fatal("output error"); + exit(nbad != 0); +} + +void set_location() +{ + printf(".lf %d %s\n", current_lineno, current_filename); +} + +void do_so(const char *line) +{ + const char *p = line; + while (*p == ' ') + p++; + string filename; + int success = 1; + for (const char *q = p; + success && *q != '\0' && *q != '\n' && *q != ' '; + q++) + if (*q == '\\') { + switch (*++q) { + case 'e': + case '\\': + filename += '\\'; + break; + case ' ': + filename += ' '; + break; + default: + success = 0; + break; + } + } + else + filename += char(*q); + if (success && filename.length() > 0) { + filename += '\0'; + const char *fn = current_filename; + int ln = current_lineno; + current_lineno--; + if (do_file(filename.contents())) { + current_filename = fn; + current_lineno = ln; + set_location(); + return; + } + current_lineno++; + } + fputs(".so", stdout); + fputs(line, stdout); +} + +int do_file(const char *filename) +{ + FILE *fp; + if (strcmp(filename, "-") == 0) + fp = stdin; + else { + errno = 0; + fp = fopen(filename, "r"); + if (fp == 0) { + error("can't open `%1': %2", filename, strerror(errno)); + return 0; + } + } + current_filename = filename; + current_lineno = 1; + set_location(); + enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START; + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + switch (state) { + case START: + if (c == '.') + state = HAD_DOT; + else { + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case MIDDLE: + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + break; + case HAD_DOT: + if (c == 's') + state = HAD_s; + else if (c == 'l') + state = HAD_l; + else { + putchar('.'); + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case HAD_s: + if (c == 'o') + state = HAD_so; + else { + putchar('.'); + putchar('s'); + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case HAD_so: + if (c == ' ' || c == '\n' || compatible_flag) { + string line; + for (; c != EOF && c != '\n'; c = getc(fp)) + line += c; + current_lineno++; + line += '\n'; + line += '\0'; + do_so(line.contents()); + state = START; + } + else { + fputs(".so", stdout); + putchar(c); + state = MIDDLE; + } + break; + case HAD_l: + if (c == 'f') + state = HAD_lf; + else { + putchar('.'); + putchar('l'); + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case HAD_lf: + if (c == ' ' || c == '\n' || compatible_flag) { + string line; + for (; c != EOF && c != '\n'; c = getc(fp)) + line += c; + current_lineno++; + line += '\n'; + line += '\0'; + interpret_lf_args(line.contents()); + printf(".lf%s", line.contents()); + state = START; + } + else { + fputs(".lf", stdout); + putchar(c); + state = MIDDLE; + } + break; + default: + assert(0); + } + } + switch (state) { + case HAD_DOT: + fputs(".\n", stdout); + break; + case HAD_l: + fputs(".l\n", stdout); + break; + case HAD_s: + fputs(".s\n", stdout); + break; + case HAD_lf: + fputs(".lf\n", stdout); + break; + case HAD_so: + fputs(".so\n", stdout); + break; + case MIDDLE: + putc('\n', stdout); + break; + case START: + break; + } + if (fp != stdin) + fclose(fp); + current_filename = 0; + return 1; +} diff --git a/gnu/usr.bin/groff/tbl/Makefile b/gnu/usr.bin/groff/tbl/Makefile new file mode 100644 index 0000000000..4c9c3cbe5c --- /dev/null +++ b/gnu/usr.bin/groff/tbl/Makefile @@ -0,0 +1,12 @@ +# Makefile for tbl + +PROG= tbl +SRCS= main.cc table.cc +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBGROFF) -lm +DPADD+= $(LIBGROFF) $(LIBMATH) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/tbl/Makefile.dep b/gnu/usr.bin/groff/tbl/Makefile.dep new file mode 100644 index 0000000000..0e6938bed0 --- /dev/null +++ b/gnu/usr.bin/groff/tbl/Makefile.dep @@ -0,0 +1,6 @@ +main.o : main.cc table.h ../include/cset.h ../include/cmap.h \ + ../include/stringclass.h ../include/errarg.h ../include/error.h \ + ../include/lib.h +table.o : table.cc table.h ../include/cset.h ../include/cmap.h \ + ../include/stringclass.h ../include/errarg.h ../include/error.h \ + ../include/lib.h diff --git a/gnu/usr.bin/groff/tbl/main.cc b/gnu/usr.bin/groff/tbl/main.cc new file mode 100644 index 0000000000..c99af2b85e --- /dev/null +++ b/gnu/usr.bin/groff/tbl/main.cc @@ -0,0 +1,1497 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "table.h" + +#define MAX_POINT_SIZE 99 +#define MAX_VERTICAL_SPACING 72 + +static int compatible_flag = 0; + +class table_input { + FILE *fp; + enum { START, MIDDLE, REREAD_T, REREAD_TE, REREAD_E, END, ERROR } state; + string unget_stack; +public: + table_input(FILE *); + int get(); + int ended() { return unget_stack.empty() && state == END; } + void unget(char); +}; + +table_input::table_input(FILE *p) +: fp(p), state(START) +{ +} + +void table_input::unget(char c) +{ + assert(c != '\0'); + unget_stack += c; + if (c == '\n') + current_lineno--; +} + +int table_input::get() +{ + int len = unget_stack.length(); + if (len != 0) { + unsigned char c = unget_stack[len - 1]; + unget_stack.set_length(len - 1); + if (c == '\n') + current_lineno++; + return c; + } + int c; + for (;;) { + switch (state) { + case START: + if ((c = getc(fp)) == '.') { + if ((c = getc(fp)) == 'T') { + if ((c = getc(fp)) == 'E') { + if (compatible_flag) { + state = END; + return EOF; + } + else { + c = getc(fp); + if (c != EOF) + ungetc(c, fp); + if (c == EOF || c == ' ' || c == '\n') { + state = END; + return EOF; + } + state = REREAD_TE; + return '.'; + } + } + else { + if (c != EOF) + ungetc(c, fp); + state = REREAD_T; + return '.'; + } + } + else { + if (c != EOF) + ungetc(c, fp); + state = MIDDLE; + return '.'; + } + } + else if (c == EOF) { + state = ERROR; + return EOF; + } + else { + if (c == '\n') + current_lineno++; + else { + state = MIDDLE; + if (c == '\0') { + error("illegal input character code 0"); + break; + } + } + return c; + } + break; + case MIDDLE: + // handle line continuation + if ((c = getc(fp)) == '\\') { + c = getc(fp); + if (c == '\n') + c = getc(fp); // perhaps state ought to be START now + else { + if (c != EOF) + ungetc(c, fp); + c = '\\'; + } + } + if (c == EOF) { + state = ERROR; + return EOF; + } + else { + if (c == '\n') { + state = START; + current_lineno++; + } + else if (c == '\0') { + error("illegal input character code 0"); + break; + } + return c; + } + case REREAD_T: + state = MIDDLE; + return 'T'; + case REREAD_TE: + state = REREAD_E; + return 'T'; + case REREAD_E: + state = MIDDLE; + return 'E'; + case END: + case ERROR: + return EOF; + } + } +} + +void process_input_file(FILE *); +void process_table(table_input &in); + +void process_input_file(FILE *fp) +{ + enum { START, MIDDLE, HAD_DOT, HAD_T, HAD_TS, HAD_l, HAD_lf } state; + state = START; + int c; + while ((c = getc(fp)) != EOF) + switch (state) { + case START: + if (c == '.') + state = HAD_DOT; + else { + if (c == '\n') + current_lineno++; + else + state = MIDDLE; + putchar(c); + } + break; + case MIDDLE: + if (c == '\n') { + current_lineno++; + state = START; + } + putchar(c); + break; + case HAD_DOT: + if (c == 'T') + state = HAD_T; + else if (c == 'l') + state = HAD_l; + else { + putchar('.'); + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case HAD_T: + if (c == 'S') + state = HAD_TS; + else { + putchar('.'); + putchar('T'); + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case HAD_TS: + if (c == ' ' || c == '\n' || compatible_flag) { + putchar('.'); + putchar('T'); + putchar('S'); + while (c != '\n') { + if (c == EOF) { + error("end of file at beginning of table"); + return; + } + putchar(c); + c = getc(fp); + } + putchar('\n'); + current_lineno++; + { + table_input input(fp); + process_table(input); + set_troff_location(current_filename, current_lineno); + if (input.ended()) { + fputs(".TE", stdout); + while ((c = getc(fp)) != '\n') { + if (c == EOF) { + putchar('\n'); + return; + } + putchar(c); + } + putchar('\n'); + current_lineno++; + } + } + state = START; + } + else { + fputs(".TS", stdout); + putchar(c); + state = MIDDLE; + } + break; + case HAD_l: + if (c == 'f') + state = HAD_lf; + else { + putchar('.'); + putchar('l'); + putchar(c); + if (c == '\n') { + current_lineno++; + state = START; + } + else + state = MIDDLE; + } + break; + case HAD_lf: + if (c == ' ' || c == '\n' || compatible_flag) { + string line; + while (c != EOF) { + line += c; + if (c == '\n') { + current_lineno++; + break; + } + c = getc(fp); + } + line += '\0'; + interpret_lf_args(line.contents()); + printf(".lf%s", line.contents()); + state = START; + } + else { + fputs(".lf", stdout); + putchar(c); + state = MIDDLE; + } + break; + default: + assert(0); + } + switch(state) { + case START: + break; + case MIDDLE: + putchar('\n'); + break; + case HAD_DOT: + fputs(".\n", stdout); + break; + case HAD_l: + fputs(".l\n", stdout); + break; + case HAD_T: + fputs(".T\n", stdout); + break; + case HAD_lf: + fputs(".lf\n", stdout); + break; + case HAD_TS: + fputs(".TS\n", stdout); + break; + } + if (fp != stdin) + fclose(fp); +} + +struct options { + unsigned flags; + int linesize; + char delim[2]; + char tab_char; + char decimal_point_char; + + options(); +}; + +options::options() +: flags(0), tab_char('\t'), decimal_point_char('.'), linesize(0) +{ + delim[0] = delim[1] = '\0'; +} + +// Return non-zero if p and q are the same ignoring case. + +int strieq(const char *p, const char *q) +{ + for (; cmlower(*p) == cmlower(*q); p++, q++) + if (*p == '\0') + return 1; + return 0; +} + +// return 0 if we should give up in this table + +options *process_options(table_input &in) +{ + options *opt = new options; + string line; + int level = 0; + for (;;) { + int c = in.get(); + if (c == EOF) { + int i = line.length(); + while (--i >= 0) + in.unget(line[i]); + return opt; + } + if (c == '\n') { + in.unget(c); + int i = line.length(); + while (--i >= 0) + in.unget(line[i]); + return opt; + } + else if (c == '(') + level++; + else if (c == ')') + level--; + else if (c == ';' && level == 0) { + line += '\0'; + break; + } + line += c; + } + if (line.empty()) + return opt; + char *p = &line[0]; + for (;;) { + while (csspace(*p) || *p == ',') + p++; + if (*p == '\0') + break; + char *q = p; + while (*q != ' ' && *q != '\0' && *q != '\t' && *q != ',' && *q != '(') + q++; + char *arg = 0; + if (*q != '(' && *q != '\0') + *q++ = '\0'; + while (csspace(*q)) + q++; + if (*q == '(') { + *q++ = '\0'; + arg = q; + while (*q != ')' && *q != '\0') + q++; + if (*q == '\0') + error("missing `)'"); + else + *q++ = '\0'; + } + if (*p == '\0') { + if (arg) + error("argument without option"); + } + else if (strieq(p, "tab")) { + if (!arg) + error("`tab' option requires argument in parentheses"); + else { + if (arg[0] == '\0' || arg[1] != '\0') + error("argument to `tab' option must be a single character"); + else + opt->tab_char = arg[0]; + } + } + else if (strieq(p, "linesize")) { + if (!arg) + error("`linesize' option requires argument in parentheses"); + else { + if (sscanf(arg, "%d", &opt->linesize) != 1) + error("bad linesize `%s'", arg); + else if (opt->linesize <= 0) { + error("linesize must be positive"); + opt->linesize = 0; + } + } + } + else if (strieq(p, "delim")) { + if (!arg) + error("`delim' option requires argument in parentheses"); + else if (arg[0] == '\0' || arg[1] == '\0' || arg[2] != '\0') + error("argument to `delim' option must be two characters"); + else { + opt->delim[0] = arg[0]; + opt->delim[1] = arg[1]; + } + } + else if (strieq(p, "center") || strieq(p, "centre")) { + if (arg) + error("`center' option does not take a argument"); + opt->flags |= table::CENTER; + } + else if (strieq(p, "expand")) { + if (arg) + error("`expand' option does not take a argument"); + opt->flags |= table::EXPAND; + } + else if (strieq(p, "box") || strieq(p, "frame")) { + if (arg) + error("`box' option does not take a argument"); + opt->flags |= table::BOX; + } + else if (strieq(p, "doublebox") || strieq(p, "doubleframe")) { + if (arg) + error("`doublebox' option does not take a argument"); + opt->flags |= table::DOUBLEBOX; + } + else if (strieq(p, "allbox")) { + if (arg) + error("`allbox' option does not take a argument"); + opt->flags |= table::ALLBOX; + } + else if (strieq(p, "nokeep")) { + if (arg) + error("`nokeep' option does not take a argument"); + opt->flags |= table::NOKEEP; + } + else if (strieq(p, "decimalpoint")) { + if (!arg) + error("`decimalpoint' option requires argument in parentheses"); + else { + if (arg[0] == '\0' || arg[1] != '\0') + error("argument to `decimalpoint' option must be a single character"); + else + opt->decimal_point_char = arg[0]; + } + } + else { + error("unrecognised global option `%1'", p); + // delete opt; + // return 0; + } + p = q; + } + return opt; +} + +entry_modifier::entry_modifier() +: vertical_alignment(CENTER), zero_width(0), stagger(0) +{ + vertical_spacing.inc = vertical_spacing.val = 0; + point_size.inc = point_size.val = 0; +} + +entry_modifier::~entry_modifier() +{ +} + +entry_format::entry_format() : type(FORMAT_LEFT) +{ +} + +entry_format::entry_format(format_type t) : type(t) +{ +} + +void entry_format::debug_print() const +{ + switch (type) { + case FORMAT_LEFT: + putc('l', stderr); + break; + case FORMAT_CENTER: + putc('c', stderr); + break; + case FORMAT_RIGHT: + putc('r', stderr); + break; + case FORMAT_NUMERIC: + putc('n', stderr); + break; + case FORMAT_ALPHABETIC: + putc('a', stderr); + break; + case FORMAT_SPAN: + putc('s', stderr); + break; + case FORMAT_VSPAN: + putc('^', stderr); + break; + case FORMAT_HLINE: + putc('_', stderr); + break; + case FORMAT_DOUBLE_HLINE: + putc('=', stderr); + break; + default: + assert(0); + break; + } + if (point_size.val != 0) { + putc('p', stderr); + if (point_size.inc > 0) + putc('+', stderr); + else if (point_size.inc < 0) + putc('-', stderr); + fprintf(stderr, "%d ", point_size.val); + } + if (vertical_spacing.val != 0) { + putc('v', stderr); + if (vertical_spacing.inc > 0) + putc('+', stderr); + else if (vertical_spacing.inc < 0) + putc('-', stderr); + fprintf(stderr, "%d ", vertical_spacing.val); + } + if (!font.empty()) { + putc('f', stderr); + put_string(font, stderr); + putc(' ', stderr); + } + switch (vertical_alignment) { + case entry_modifier::CENTER: + break; + case entry_modifier::TOP: + putc('t', stderr); + break; + case entry_modifier::BOTTOM: + putc('d', stderr); + break; + } + if (zero_width) + putc('z', stderr); + if (stagger) + putc('u', stderr); +} + +struct format { + int nrows; + int ncolumns; + int *separation; + string *width; + char *equal; + entry_format **entry; + char **vline; + + format(int nr, int nc); + ~format(); + void add_rows(int n); +}; + +format::format(int nr, int nc) : nrows(nr), ncolumns(nc) +{ + int i; + separation = ncolumns > 1 ? new int[ncolumns - 1] : 0; + for (i = 0; i < ncolumns-1; i++) + separation[i] = -1; + width = new string[ncolumns]; + equal = new char[ncolumns]; + for (i = 0; i < ncolumns; i++) + equal[i] = 0; + entry = new entry_format *[nrows]; + for (i = 0; i < nrows; i++) + entry[i] = new entry_format[ncolumns]; + vline = new char*[nrows]; + for (i = 0; i < nrows; i++) { + vline[i] = new char[ncolumns+1]; + for (int j = 0; j < ncolumns+1; j++) + vline[i][j] = 0; + } +} + +void format::add_rows(int n) +{ + int i; + char **old_vline = vline; + vline = new char*[nrows + n]; + for (i = 0; i < nrows; i++) + vline[i] = old_vline[i]; + a_delete old_vline; + for (i = 0; i < n; i++) { + vline[nrows + i] = new char[ncolumns + 1]; + for (int j = 0; j < ncolumns + 1; j++) + vline[nrows + i][j] = 0; + } + entry_format **old_entry = entry; + entry = new entry_format *[nrows + n]; + for (i = 0; i < nrows; i++) + entry[i] = old_entry[i]; + a_delete old_entry; + for (i = 0; i < n; i++) + entry[nrows + i] = new entry_format[ncolumns]; + nrows += n; +} + +format::~format() +{ + a_delete separation; + ad_delete(ncolumns) width; + a_delete equal; + for (int i = 0; i < nrows; i++) { + a_delete vline[i]; + ad_delete(ncolumns) entry[i]; + } + a_delete vline; + a_delete entry; +} + +struct input_entry_format : entry_format { + input_entry_format *next; + string width; + int separation; + int vline; + int pre_vline; + int last_column; + int equal; + input_entry_format(format_type, input_entry_format * = 0); + ~input_entry_format(); + void debug_print(); +}; + +input_entry_format::input_entry_format(format_type t, input_entry_format *p) +: entry_format(t), next(p) +{ + separation = -1; + last_column = 0; + vline = 0; + pre_vline = 0; + equal = 0; +} + +input_entry_format::~input_entry_format() +{ +} + +void free_input_entry_format_list(input_entry_format *list) +{ + while (list) { + input_entry_format *tem = list; + list = list->next; + delete tem; + } +} + +void input_entry_format::debug_print() +{ + for (int i = 0; i < pre_vline; i++) + putc('|', stderr); + entry_format::debug_print(); + if (!width.empty()) { + putc('w', stderr); + putc('(', stderr); + put_string(width, stderr); + putc(')', stderr); + } + if (equal) + putc('e', stderr); + if (separation >= 0) + fprintf(stderr, "%d", separation); + for (i = 0; i < vline; i++) + putc('|', stderr); + if (last_column) + putc(',', stderr); +} + +// Return zero if we should give up on this table. +// If this is a continuation format line, current_format will be the current +// format line. + +format *process_format(table_input &in, options *opt, + format *current_format = 0) +{ + input_entry_format *list = 0; + int c = in.get(); + for (;;) { + int pre_vline = 0; + int got_format = 0; + int got_period = 0; + format_type t; + for (;;) { + if (c == EOF) { + error("end of input while processing format"); + free_input_entry_format_list(list); + return 0; + } + switch (c) { + case 'n': + case 'N': + t = FORMAT_NUMERIC; + got_format = 1; + break; + case 'a': + case 'A': + got_format = 1; + t = FORMAT_ALPHABETIC; + break; + case 'c': + case 'C': + got_format = 1; + t = FORMAT_CENTER; + break; + case 'l': + case 'L': + got_format = 1; + t = FORMAT_LEFT; + break; + case 'r': + case 'R': + got_format = 1; + t = FORMAT_RIGHT; + break; + case 's': + case 'S': + got_format = 1; + t = FORMAT_SPAN; + break; + case '^': + got_format = 1; + t = FORMAT_VSPAN; + break; + case '_': + got_format = 1; + t = FORMAT_HLINE; + break; + case '=': + got_format = 1; + t = FORMAT_DOUBLE_HLINE; + break; + case '.': + got_period = 1; + break; + case '|': + pre_vline++; + break; + case ' ': + case '\t': + case '\n': + break; + default: + if (c == opt->tab_char) + break; + error("unrecognised format `%1'", char(c)); + free_input_entry_format_list(list); + return 0; + } + if (got_period) + break; + c = in.get(); + if (got_format) + break; + } + if (got_period) + break; + list = new input_entry_format(t, list); + if (pre_vline) + list->pre_vline = pre_vline; + int success = 1; + do { + switch (c) { + case 't': + case 'T': + c = in.get(); + list->vertical_alignment = entry_modifier::TOP; + break; + case 'd': + case 'D': + c = in.get(); + list->vertical_alignment = entry_modifier::BOTTOM; + break; + case 'u': + case 'U': + c = in.get(); + list->stagger = 1; + break; + case 'z': + case 'Z': + c = in.get(); + list->zero_width = 1; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + int w = 0; + do { + w = w*10 + (c - '0'); + c = in.get(); + } while (c != EOF && csdigit(c)); + list->separation = w; + } + break; + case 'f': + case 'F': + do { + c = in.get(); + } while (c == ' ' || c == '\t'); + if (c == EOF) { + error("missing font name"); + break; + } + if (c == '(') { + for (;;) { + c = in.get(); + if (c == EOF || c == ' ' || c == '\t') { + error("missing `)'"); + break; + } + if (c == ')') { + c = in.get(); + break; + } + list->font += char(c); + } + } + else { + list->font = c; + char cc = c; + c = in.get(); + if (!csdigit(cc) + && c != EOF && c != ' ' && c != '\t' && c != '.' && c != '\n') { + list->font += char(c); + c = in.get(); + } + } + break; + case 'v': + case 'V': + c = in.get(); + list->vertical_spacing.val = 0; + list->vertical_spacing.inc = 0; + if (c == '+' || c == '-') { + list->vertical_spacing.inc = (c == '+' ? 1 : -1); + c = in.get(); + } + if (c == EOF || !csdigit(c)) { + error("`v' modifier must be followed by number"); + list->vertical_spacing.inc = 0; + } + else { + do { + list->vertical_spacing.val *= 10; + list->vertical_spacing.val += c - '0'; + c = in.get(); + } while (c != EOF && csdigit(c)); + } + if (list->vertical_spacing.val > MAX_VERTICAL_SPACING + || list->vertical_spacing.val < -MAX_VERTICAL_SPACING) { + error("unreasonable point size"); + list->vertical_spacing.val = 0; + list->vertical_spacing.inc = 0; + } + break; + case 'p': + case 'P': + c = in.get(); + list->point_size.val = 0; + list->point_size.inc = 0; + if (c == '+' || c == '-') { + list->point_size.inc = (c == '+' ? 1 : -1); + c = in.get(); + } + if (c == EOF || !csdigit(c)) { + error("`p' modifier must be followed by number"); + list->point_size.inc = 0; + } + else { + do { + list->point_size.val *= 10; + list->point_size.val += c - '0'; + c = in.get(); + } while (c != EOF && csdigit(c)); + } + if (list->point_size.val > MAX_POINT_SIZE + || list->point_size.val < -MAX_POINT_SIZE) { + error("unreasonable point size"); + list->point_size.val = 0; + list->point_size.inc = 0; + } + break; + case 'w': + case 'W': + c = in.get(); + while (c == ' ' || c == '\t') + c = in.get(); + if (c == '(') { + list->width = ""; + c = in.get(); + while (c != ')') { + if (c == EOF || c == '\n') { + error("missing `)'"); + free_input_entry_format_list(list); + return 0; + } + list->width += c; + c = in.get(); + } + c = in.get(); + } + else { + if (c == '+' || c == '-') { + list->width = char(c); + c = in.get(); + } + else + list->width = ""; + if (c == EOF || !csdigit(c)) + error("bad argument for `w' modifier"); + else { + do { + list->width += char(c); + c = in.get(); + } while (c != EOF && csdigit(c)); + } + } + break; + case 'e': + case 'E': + c = in.get(); + list->equal++; + break; + case '|': + c = in.get(); + list->vline++; + break; + case 'B': + case 'b': + c = in.get(); + list->font = "B"; + break; + case 'I': + case 'i': + c = in.get(); + list->font = "I"; + break; + case ' ': + case '\t': + c = in.get(); + break; + default: + if (c == opt->tab_char) + c = in.get(); + else + success = 0; + break; + } + } while (success); + if (list->vline > 2) { + list->vline = 2; + error("more than 2 vertical bars between key letters"); + } + if (c == '\n' || c == ',') { + c = in.get(); + list->last_column = 1; + } + } + if (c == '.') { + do { + c = in.get(); + } while (c == ' ' || c == '\t'); + if (c != '\n') { + error("`.' not last character on line"); + free_input_entry_format_list(list); + return 0; + } + } + if (!list) { + error("no format"); + free_input_entry_format_list(list); + return 0; + } + list->last_column = 1; + // now reverse the list so that the first row is at the beginning + input_entry_format *rev = 0; + while (list != 0) { + input_entry_format *tem = list->next; + list->next = rev; + rev = list; + list = tem; + } + list = rev; + input_entry_format *tem; + +#if 0 + for (tem = list; tem; tem = tem->next) + tem->debug_print(); + putc('\n', stderr); +#endif + // compute number of columns and rows + int ncolumns = 0; + int nrows = 0; + int col = 0; + for (tem = list; tem; tem = tem->next) { + if (tem->last_column) { + if (col >= ncolumns) + ncolumns = col + 1; + col = 0; + nrows++; + } + else + col++; + } + int row; + format *f; + if (current_format) { + if (ncolumns > current_format->ncolumns) { + error("cannot increase the number of columns in a continued format"); + free_input_entry_format_list(list); + return 0; + } + f = current_format; + row = f->nrows; + f->add_rows(nrows); + } + else { + f = new format(nrows, ncolumns); + row = 0; + } + col = 0; + for (tem = list; tem; tem = tem->next) { + f->entry[row][col] = *tem; + if (col < ncolumns-1) { + // use the greatest separation + if (tem->separation > f->separation[col]) { + if (current_format) + error("cannot change column separation in continued format"); + else + f->separation[col] = tem->separation; + } + } + else if (tem->separation >= 0) + error("column separation specified for last column"); + if (tem->equal && !f->equal[col]) { + if (current_format) + error("cannot change which columns are equal in continued format"); + else + f->equal[col] = 1; + } + if (!tem->width.empty()) { + // use the last width + if (!f->width[col].empty() && f->width[col] != tem->width) + error("multiple widths for column %1", col+1); + f->width[col] = tem->width; + } + if (tem->pre_vline) { + assert(col == 0); + f->vline[row][col] = tem->pre_vline; + } + f->vline[row][col+1] = tem->vline; + if (tem->last_column) { + row++; + col = 0; + } + else + col++; + } + free_input_entry_format_list(list); + for (col = 0; col < ncolumns; col++) { + entry_format *e = f->entry[f->nrows-1] + col; + if (e->type != FORMAT_HLINE + && e->type != FORMAT_DOUBLE_HLINE + && e->type != FORMAT_SPAN) + break; + } + if (col >= ncolumns) { + error("last row of format is all lines"); + delete f; + return 0; + } + return f; +} + +table *process_data(table_input &in, format *f, options *opt) +{ + char tab_char = opt->tab_char; + int ncolumns = f->ncolumns; + int current_row = 0; + int format_index = 0; + int give_up = 0; + enum { DATA_INPUT_LINE, TROFF_INPUT_LINE, SINGLE_HLINE, DOUBLE_HLINE } type; + table *tbl = new table(ncolumns, opt->flags, opt->linesize, + opt->decimal_point_char); + if (opt->delim[0] != '\0') + tbl->set_delim(opt->delim[0], opt->delim[1]); + for (;;) { + // first determine what type of line this is + int c = in.get(); + if (c == EOF) + break; + if (c == '.') { + int d = in.get(); + if (d != EOF && csdigit(d)) { + in.unget(d); + type = DATA_INPUT_LINE; + } + else { + in.unget(d); + type = TROFF_INPUT_LINE; + } + } + else if (c == '_' || c == '=') { + int d = in.get(); + if (d == '\n') { + if (c == '_') + type = SINGLE_HLINE; + else + type = DOUBLE_HLINE; + } + else { + in.unget(d); + type = DATA_INPUT_LINE; + } + } + else { + type = DATA_INPUT_LINE; + } + switch (type) { + case DATA_INPUT_LINE: + { + string input_entry; + if (format_index >= f->nrows) + format_index = f->nrows - 1; + // A format row that is all lines doesn't use up a data line. + while (format_index < f->nrows - 1) { + for (int c = 0; c < ncolumns; c++) { + entry_format *e = f->entry[format_index] + c; + if (e->type != FORMAT_HLINE + && e->type != FORMAT_DOUBLE_HLINE + // Unfortunately tbl treats a span as needing data. + // && e->type != FORMAT_SPAN + ) + break; + } + if (c < ncolumns) + break; + for (c = 0; c < ncolumns; c++) + tbl->add_entry(current_row, c, input_entry, + f->entry[format_index] + c, current_filename, + current_lineno); + tbl->add_vlines(current_row, f->vline[format_index]); + format_index++; + current_row++; + } + entry_format *line_format = f->entry[format_index]; + int col = 0; + for (;;) { + if (c == tab_char || c == '\n') { + int ln = current_lineno; + if (c == '\n') + --ln; + while (col < ncolumns + && line_format[col].type == FORMAT_SPAN) { + tbl->add_entry(current_row, col, "", &line_format[col], + current_filename, ln); + col++; + } + if (c == '\n' && input_entry.length() == 2 + && input_entry[0] == 'T' && input_entry[1] == '{') { + input_entry = ""; + ln++; + enum { + START, MIDDLE, GOT_T, GOT_RIGHT_BRACE, GOT_DOT, + GOT_l, GOT_lf, END + } state = START; + while (state != END) { + c = in.get(); + if (c == EOF) + break; + switch (state) { + case START: + if (c == 'T') + state = GOT_T; + else if (c == '.') + state = GOT_DOT; + else { + input_entry += c; + if (c != '\n') + state = MIDDLE; + } + break; + case GOT_T: + if (c == '}') + state = GOT_RIGHT_BRACE; + else { + input_entry += 'T'; + input_entry += c; + state = c == '\n' ? START : MIDDLE; + } + break; + case GOT_DOT: + if (c == 'l') + state = GOT_l; + else { + input_entry += '.'; + input_entry += c; + state = c == '\n' ? START : MIDDLE; + } + break; + case GOT_l: + if (c == 'f') + state = GOT_lf; + else { + input_entry += ".l"; + input_entry += c; + state = c == '\n' ? START : MIDDLE; + } + break; + case GOT_lf: + if (c == ' ' || c == '\n' || compatible_flag) { + string args; + input_entry += ".lf"; + while (c != EOF) { + args += c; + if (c == '\n') + break; + c = in.get(); + } + args += '\0'; + interpret_lf_args(args.contents()); + // remove the '\0' + args.set_length(args.length() - 1); + input_entry += args; + state = START; + } + else { + input_entry += ".lf"; + input_entry += c; + state = MIDDLE; + } + break; + case GOT_RIGHT_BRACE: + if (c == '\n' || c == tab_char) + state = END; + else { + input_entry += 'T'; + input_entry += '}'; + input_entry += c; + state = c == '\n' ? START : MIDDLE; + } + break; + case MIDDLE: + if (c == '\n') + state = START; + input_entry += c; + break; + case END: + default: + assert(0); + } + } + if (c == EOF) { + error("end of data in middle of text block"); + give_up = 1; + break; + } + } + if (col >= ncolumns) { + if (!input_entry.empty()) { + if (c == '\n') + in.unget(c); + input_entry += '\0'; + error("excess data entry `%1' discarded", + input_entry.contents()); + if (c == '\n') + (void)in.get(); + } + } + else + tbl->add_entry(current_row, col, input_entry, + &line_format[col], current_filename, ln); + col++; + if (c == '\n') + break; + input_entry = ""; + } + else + input_entry += c; + c = in.get(); + if (c == EOF) + break; + } + if (give_up) + break; + input_entry = ""; + for (; col < ncolumns; col++) + tbl->add_entry(current_row, col, input_entry, &line_format[col], + current_filename, current_lineno - 1); + tbl->add_vlines(current_row, f->vline[format_index]); + current_row++; + format_index++; + } + break; + case TROFF_INPUT_LINE: + { + string line; + int ln = current_lineno; + for (;;) { + line += c; + if (c == '\n') + break; + c = in.get(); + if (c == EOF) { + break; + } + } + tbl->add_text_line(current_row, line, current_filename, ln); + if (line.length() >= 4 + && line[0] == '.' && line[1] == 'T' && line[2] == '&') { + format *newf = process_format(in, opt, f); + if (newf == 0) + give_up = 1; + else + f = newf; + } + if (line.length() >= 3 + && line[0] == '.' && line[1] == 'f' && line[2] == 'f') { + line += '\0'; + interpret_lf_args(line.contents() + 3); + } + } + break; + case SINGLE_HLINE: + tbl->add_single_hline(current_row); + break; + case DOUBLE_HLINE: + tbl->add_double_hline(current_row); + break; + default: + assert(0); + } + if (give_up) + break; + } + if (!give_up && current_row == 0) { + error("no real data"); + give_up = 1; + } + if (give_up) { + delete tbl; + return 0; + } + // Do this here rather than at the beginning in case continued formats + // change it. + for (int i = 0; i < ncolumns - 1; i++) + if (f->separation[i] >= 0) + tbl->set_column_separation(i, f->separation[i]); + for (i = 0; i < ncolumns; i++) + if (!f->width[i].empty()) + tbl->set_minimum_width(i, f->width[i]); + for (i = 0; i < ncolumns; i++) + if (f->equal[i]) + tbl->set_equal_column(i); + return tbl; +} + +void process_table(table_input &in) +{ + int c; + options *opt = 0; + format *form = 0; + table *tbl = 0; + if ((opt = process_options(in)) != 0 + && (form = process_format(in, opt)) != 0 + && (tbl = process_data(in, form, opt)) != 0) { + tbl->print(); + delete tbl; + } + else { + error("giving up on this table"); + while ((c = in.get()) != EOF) + ; + } + delete opt; + delete form; + if (!in.ended()) + error("premature end of file"); +} + +static void usage() +{ + fprintf(stderr, "usage: %s [ -vC ] [ files... ]\n", program_name); + exit(1); +} + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int opt; + while ((opt = getopt(argc, argv, "vC")) != EOF) + switch (opt) { + case 'C': + compatible_flag = 1; + break; + case 'v': + { + extern const char *version_string; + fprintf(stderr, "GNU tbl version %s\n", version_string); + fflush(stderr); + break; + } + case '?': + usage(); + break; + default: + assert(0); + } + printf(".if !\\n(.g .ab GNU tbl requires GNU troff.\n" + ".if !dTS .ds TS\n" + ".if !dTE .ds TE\n"); + if (argc > optind) { + for (int i = optind; i < argc; i++) + if (argv[i][0] == '-' && argv[i][1] == '\0') { + current_filename = "-"; + current_lineno = 1; + printf(".lf 1 -\n"); + process_input_file(stdin); + } + else { + errno = 0; + FILE *fp = fopen(argv[i], "r"); + if (fp == 0) { + current_lineno = -1; + error("can't open `%1': %2", argv[i], strerror(errno)); + } + else { + current_lineno = 1; + current_filename = argv[i]; + printf(".lf 1 %s\n", current_filename); + process_input_file(fp); + } + } + } + else { + current_filename = "-"; + current_lineno = 1; + printf(".lf 1 -\n"); + process_input_file(stdin); + } + if (ferror(stdout) || fflush(stdout) < 0) + fatal("output error"); + exit(0); +} + diff --git a/gnu/usr.bin/groff/tbl/table.cc b/gnu/usr.bin/groff/tbl/table.cc new file mode 100644 index 0000000000..76c7cd74a9 --- /dev/null +++ b/gnu/usr.bin/groff/tbl/table.cc @@ -0,0 +1,2764 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "table.h" + +#define BAR_HEIGHT ".25m" +#define DOUBLE_LINE_SEP "2p" +#define HALF_DOUBLE_LINE_SEP "1p" +#define LINE_SEP "2p" +#define BODY_DEPTH ".25m" + +const int DEFAULT_COLUMN_SEPARATION = 3; + +#define DELIMITER_CHAR "\\[tbl]" +#define PREFIX "3" +#define SEPARATION_FACTOR_REG PREFIX "sep" +#define BOTTOM_REG PREFIX "bot" +#define RESET_MACRO_NAME PREFIX "init" +#define LINESIZE_REG PREFIX "lps" +#define TOP_REG PREFIX "top" +#define CURRENT_ROW_REG PREFIX "crow" +#define LAST_PASSED_ROW_REG PREFIX "passed" +#define TRANSPARENT_STRING_NAME PREFIX "trans" +#define QUOTE_STRING_NAME PREFIX "quote" +#define SECTION_DIVERSION_NAME PREFIX "section" +#define SECTION_DIVERSION_FLAG_REG PREFIX "sflag" +#define SAVED_VERTICAL_POS_REG PREFIX "vert" +#define NEED_BOTTOM_RULE_REG PREFIX "brule" +#define KEEP_MACRO_NAME PREFIX "keep" +#define RELEASE_MACRO_NAME PREFIX "release" +#define SAVED_FONT_REG PREFIX "fnt" +#define SAVED_SIZE_REG PREFIX "sz" +#define SAVED_FILL_REG PREFIX "fll" +#define SAVED_INDENT_REG PREFIX "ind" +#define SAVED_CENTER_REG PREFIX "cent" +#define TABLE_DIVERSION_NAME PREFIX "table" +#define TABLE_DIVERSION_FLAG_REG PREFIX "tflag" +#define TABLE_KEEP_MACRO_NAME PREFIX "tkeep" +#define TABLE_RELEASE_MACRO_NAME PREFIX "trelease" +#define NEEDED_REG PREFIX "needed" +#define REPEATED_MARK_MACRO PREFIX "rmk" +#define REPEATED_VPT_MACRO PREFIX "rvpt" +#define SUPPRESS_BOTTOM_REG PREFIX "supbot" +#define SAVED_DN_REG PREFIX "dn" + +// this must be one character +#define COMPATIBLE_REG PREFIX "c" + +#define BLOCK_WIDTH_PREFIX PREFIX "tbw" +#define BLOCK_DIVERSION_PREFIX PREFIX "tbd" +#define BLOCK_HEIGHT_PREFIX PREFIX "tbh" +#define SPAN_WIDTH_PREFIX PREFIX "w" +#define SPAN_LEFT_NUMERIC_WIDTH_PREFIX PREFIX "lnw" +#define SPAN_RIGHT_NUMERIC_WIDTH_PREFIX PREFIX "rnw" +#define SPAN_ALPHABETIC_WIDTH_PREFIX PREFIX "aw" +#define COLUMN_SEPARATION_PREFIX PREFIX "cs" +#define ROW_START_PREFIX PREFIX "rs" +#define COLUMN_START_PREFIX PREFIX "cl" +#define COLUMN_END_PREFIX PREFIX "ce" +#define COLUMN_DIVIDE_PREFIX PREFIX "cd" +#define ROW_TOP_PREFIX PREFIX "rt" + +string block_width_reg(int r, int c); +string block_diversion_name(int r, int c); +string block_height_reg(int r, int c); +string span_width_reg(int start_col, int end_col); +string span_left_numeric_width_reg(int start_col, int end_col); +string span_right_numeric_width_reg(int start_col, int end_col); +string span_alphabetic_width_reg(int start_col, int end_col); +string column_separation_reg(int col); +string row_start_reg(int r); +string column_start_reg(int c); +string column_end_reg(int c); +string column_divide_reg(int c); +string row_top_reg(int r); + +void set_inline_modifier(const entry_modifier *); +void restore_inline_modifier(const entry_modifier *m); +void set_modifier(const entry_modifier *); +int find_decimal_point(const char *s, char decimal_point_char, + const char *delim); + +string an_empty_string; +int location_force_filename = 0; + +void printfs(const char *, + const string &arg1 = an_empty_string, + const string &arg2 = an_empty_string, + const string &arg3 = an_empty_string, + const string &arg4 = an_empty_string, + const string &arg5 = an_empty_string); + +void prints(const string &); + +inline void prints(char c) +{ + putchar(c); +} + +inline void prints(const char *s) +{ + fputs(s, stdout); +} + +void prints(const string &s) +{ + if (!s.empty()) + fwrite(s.contents(), 1, s.length(), stdout); +} + +struct horizontal_span { + horizontal_span *next; + short start_col; + short end_col; + horizontal_span(int, int, horizontal_span *); +}; + +struct single_line_entry; +struct double_line_entry; +struct simple_entry; + +class table_entry { +friend class table; + table_entry *next; + int input_lineno; + const char *input_filename; +protected: + short start_row; + short start_col; + short end_row; + short end_col; + const entry_modifier *mod; +public: + void set_location(); + table_entry(const entry_modifier *); + virtual ~table_entry(); + virtual int divert(int ncols, const string *mw, int *sep); + virtual void do_width(); + virtual void do_depth(); + virtual void print() = 0; + virtual void position_vertically() = 0; + virtual single_line_entry *to_single_line_entry(); + virtual double_line_entry *to_double_line_entry(); + virtual simple_entry *to_simple_entry(); + virtual int line_type(); + virtual void note_double_vrule_on_right(int); + virtual void note_double_vrule_on_left(int); +}; + +class simple_entry : public table_entry { +public: + simple_entry(const entry_modifier *); + void print(); + void position_vertically(); + simple_entry *to_simple_entry(); + virtual void add_tab(); + virtual void simple_print(int); +}; + +class empty_entry : public simple_entry { +public: + empty_entry(const entry_modifier *); + int line_type(); +}; + +class text_entry : public simple_entry { +protected: + char *contents; + void print_contents(); +public: + text_entry(char *, const entry_modifier *); + ~text_entry(); +}; + +void text_entry::print_contents() +{ + set_inline_modifier(mod); + prints(contents); + restore_inline_modifier(mod); +} + +class repeated_char_entry : public text_entry { +public: + repeated_char_entry(char *s, const entry_modifier *m); + void simple_print(int); +}; + +class simple_text_entry : public text_entry { +public: + simple_text_entry(char *s, const entry_modifier *m); + void do_width(); +}; + +class left_text_entry : public simple_text_entry { +public: + left_text_entry(char *s, const entry_modifier *m); + void simple_print(int); + void add_tab(); +}; + +class right_text_entry : public simple_text_entry { +public: + right_text_entry(char *s, const entry_modifier *m); + void simple_print(int); + void add_tab(); +}; + +class center_text_entry : public simple_text_entry { +public: + center_text_entry(char *s, const entry_modifier *m); + void simple_print(int); + void add_tab(); +}; + +class numeric_text_entry : public text_entry { + int dot_pos; +public: + numeric_text_entry(char *s, const entry_modifier *m, int pos); + void do_width(); + void simple_print(int); +}; + +class alphabetic_text_entry : public text_entry { +public: + alphabetic_text_entry(char *s, const entry_modifier *m); + void do_width(); + void simple_print(int); + void add_tab(); +}; + +class line_entry : public simple_entry { +protected: + char double_vrule_on_right; + char double_vrule_on_left; +public: + line_entry(const entry_modifier *); + void note_double_vrule_on_right(int); + void note_double_vrule_on_left(int); + void simple_print(int) = 0; +}; + +class single_line_entry : public line_entry { +public: + single_line_entry(const entry_modifier *m); + void simple_print(int); + single_line_entry *to_single_line_entry(); + int line_type(); +}; + +class double_line_entry : public line_entry { +public: + double_line_entry(const entry_modifier *m); + void simple_print(int); + double_line_entry *to_double_line_entry(); + int line_type(); +}; + +class short_line_entry : public simple_entry { +public: + short_line_entry(const entry_modifier *m); + void simple_print(int); + int line_type(); +}; + +class short_double_line_entry : public simple_entry { +public: + short_double_line_entry(const entry_modifier *m); + void simple_print(int); + int line_type(); +}; + +class block_entry : public table_entry { + char *contents; +protected: + void do_divert(int alphabetic, int ncols, const string *mw, int *sep); +public: + block_entry(char *s, const entry_modifier *m); + ~block_entry(); + int divert(int ncols, const string *mw, int *sep); + void do_width(); + void do_depth(); + void position_vertically(); + void print() = 0; +}; + +class left_block_entry : public block_entry { +public: + left_block_entry(char *s, const entry_modifier *m); + void print(); +}; + +class right_block_entry : public block_entry { +public: + right_block_entry(char *s, const entry_modifier *m); + void print(); +}; + +class center_block_entry : public block_entry { +public: + center_block_entry(char *s, const entry_modifier *m); + void print(); +}; + +class alphabetic_block_entry : public block_entry { +public: + alphabetic_block_entry(char *s, const entry_modifier *m); + void print(); + int divert(int ncols, const string *mw, int *sep); +}; + +table_entry::table_entry(const entry_modifier *m) +: next(0), start_row(-1), end_row(-1), start_col(-1), end_col(-1), mod(m), + input_lineno(-1), input_filename(0) +{ +} + +table_entry::~table_entry() +{ +} + +int table_entry::divert(int, const string *, int *) +{ + return 0; +} + +void table_entry::do_width() +{ +} + +single_line_entry *table_entry::to_single_line_entry() +{ + return 0; +} + +double_line_entry *table_entry::to_double_line_entry() +{ + return 0; +} + +simple_entry *table_entry::to_simple_entry() +{ + return 0; +} + +void table_entry::do_depth() +{ +} + +void table_entry::set_location() +{ + set_troff_location(input_filename, input_lineno); +} + +int table_entry::line_type() +{ + return -1; +} + +void table_entry::note_double_vrule_on_right(int) +{ +} + +void table_entry::note_double_vrule_on_left(int) +{ +} + +simple_entry::simple_entry(const entry_modifier *m) : table_entry(m) +{ +} + +void simple_entry::add_tab() +{ + // do nothing +} + +void simple_entry::simple_print(int) +{ + // do nothing +} + +void simple_entry::position_vertically() +{ + if (start_row != end_row) + switch (mod->vertical_alignment) { + case entry_modifier::TOP: + printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); + break; + case entry_modifier::CENTER: + // Peform the motion in two stages so that the center is rounded + // vertically upwards even if net vertical motion is upwards. + printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); + printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-1v/2u\n", + row_start_reg(start_row)); + break; + case entry_modifier::BOTTOM: + printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-1v\n", + row_start_reg(start_row)); + break; + default: + assert(0); + } +} + +void simple_entry::print() +{ + prints(".ta"); + add_tab(); + prints('\n'); + set_location(); + prints("\\&"); + simple_print(0); + prints('\n'); +} + +simple_entry *simple_entry::to_simple_entry() +{ + return this; +} + +empty_entry::empty_entry(const entry_modifier *m) +: simple_entry(m) +{ +} + +int empty_entry::line_type() +{ + return 0; +} + +text_entry::text_entry(char *s, const entry_modifier *m) +: contents(s), simple_entry(m) +{ +} + +text_entry::~text_entry() +{ + a_delete contents; +} + + +repeated_char_entry::repeated_char_entry(char *s, const entry_modifier *m) +: text_entry(s, m) +{ +} + +void repeated_char_entry::simple_print(int) +{ + printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); + set_inline_modifier(mod); + printfs("\\l" DELIMITER_CHAR "\\n[%1]u\\&", + span_width_reg(start_col, end_col)); + prints(contents); + prints(DELIMITER_CHAR); + restore_inline_modifier(mod); +} + +simple_text_entry::simple_text_entry(char *s, const entry_modifier *m) +: text_entry(s, m) +{ +} + +void simple_text_entry::do_width() +{ + set_location(); + printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, + span_width_reg(start_col, end_col)); + print_contents(); + prints(DELIMITER_CHAR "\n"); +} + +left_text_entry::left_text_entry(char *s, const entry_modifier *m) +: simple_text_entry(s, m) +{ +} + +void left_text_entry::simple_print(int) +{ + printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); + print_contents(); +} + +// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr. + +void left_text_entry::add_tab() +{ + printfs(" \\n[%1]u", column_end_reg(end_col)); +} + +right_text_entry::right_text_entry(char *s, const entry_modifier *m) +: simple_text_entry(s, m) +{ +} + +void right_text_entry::simple_print(int) +{ + printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); + prints("\002\003"); + print_contents(); + prints("\002"); +} + +void right_text_entry::add_tab() +{ + printfs(" \\n[%1]u", column_end_reg(end_col)); +} + +center_text_entry::center_text_entry(char *s, const entry_modifier *m) +: simple_text_entry(s, m) +{ +} + +void center_text_entry::simple_print(int) +{ + printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); + prints("\002\003"); + print_contents(); + prints("\003\002"); +} + +void center_text_entry::add_tab() +{ + printfs(" \\n[%1]u", column_end_reg(end_col)); +} + +numeric_text_entry::numeric_text_entry(char *s, const entry_modifier *m, int pos) +: text_entry(s, m), dot_pos(pos) +{ +} + +void numeric_text_entry::do_width() +{ + if (dot_pos != 0) { + set_location(); + printfs(".nr %1 0\\w" DELIMITER_CHAR, + block_width_reg(start_row, start_col)); + set_inline_modifier(mod); + for (int i = 0; i < dot_pos; i++) + prints(contents[i]); + restore_inline_modifier(mod); + prints(DELIMITER_CHAR "\n"); + printfs(".nr %1 \\n[%1]>?\\n[%2]\n", + span_left_numeric_width_reg(start_col, end_col), + block_width_reg(start_row, start_col)); + } + else + printfs(".nr %1 0\n", block_width_reg(start_row, start_col)); + if (contents[dot_pos] != '\0') { + set_location(); + printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, + span_right_numeric_width_reg(start_col, end_col)); + set_inline_modifier(mod); + prints(contents + dot_pos); + restore_inline_modifier(mod); + prints(DELIMITER_CHAR "\n"); + } +} + +void numeric_text_entry::simple_print(int) +{ + printfs("\\h'|(\\n[%1]u-\\n[%2]u-\\n[%3]u/2u+\\n[%2]u+\\n[%4]u-\\n[%5]u)'", + span_width_reg(start_col, end_col), + span_left_numeric_width_reg(start_col, end_col), + span_right_numeric_width_reg(start_col, end_col), + column_start_reg(start_col), + block_width_reg(start_row, start_col)); + print_contents(); +} + +alphabetic_text_entry::alphabetic_text_entry(char *s, const entry_modifier *m) +: text_entry(s, m) +{ +} + +void alphabetic_text_entry::do_width() +{ + set_location(); + printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, + span_alphabetic_width_reg(start_col, end_col)); + print_contents(); + prints(DELIMITER_CHAR "\n"); +} + +void alphabetic_text_entry::simple_print(int) +{ + printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); + printfs("\\h'\\n[%1]u-\\n[%2]u/2u'", + span_width_reg(start_col, end_col), + span_alphabetic_width_reg(start_col, end_col)); + print_contents(); +} + +// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr. + +void alphabetic_text_entry::add_tab() +{ + printfs(" \\n[%1]u", column_end_reg(end_col)); +} + +block_entry::block_entry(char *s, const entry_modifier *m) +: table_entry(m), contents(s) +{ +} + +block_entry::~block_entry() +{ + a_delete contents; +} + +void block_entry::position_vertically() +{ + if (start_row != end_row) + switch(mod->vertical_alignment) { + case entry_modifier::TOP: + printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); + break; + case entry_modifier::CENTER: + // Peform the motion in two stages so that the center is rounded + // vertically upwards even if net vertical motion is upwards. + printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); + printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u/2u\n", + row_start_reg(start_row), + block_height_reg(start_row, start_col)); + break; + case entry_modifier::BOTTOM: + printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u\n", + row_start_reg(start_row), + block_height_reg(start_row, start_col)); + break; + default: + assert(0); + } + if (mod->stagger) + prints(".sp -.5v\n"); +} + +int block_entry::divert(int ncols, const string *mw, int *sep) +{ + do_divert(0, ncols, mw, sep); + return 1; +} + +void block_entry::do_divert(int alphabetic, int ncols, const string *mw, + int *sep) +{ + printfs(".di %1\n", block_diversion_name(start_row, start_col)); + prints(".if \\n[" SAVED_FILL_REG "] .fi\n" + ".in 0\n"); + prints(".ll "); + for (int i = start_col; i <= end_col; i++) + if (mw[i].empty()) + break; + if (i > end_col) { + // Every column spanned by this entry has a minimum width. + for (int i = start_col; i <= end_col; i++) { + if (i > start_col) { + if (sep) + printfs("+%1n", as_string(sep[i - 1])); + prints('+'); + } + printfs("(n;%1)", mw[i]); + } + printfs(">?\\n[%1]u", span_width_reg(start_col, end_col)); + } + else + printfs("(u;\\n[%1]>?(\\n[.l]*%2/%3))", + span_width_reg(start_col, end_col), + as_string(end_col - start_col + 1), + as_string(ncols + 1)); + if (alphabetic) + prints("-2n"); + prints("\n"); + set_modifier(mod); + prints(".cp \\n(" COMPATIBLE_REG "\n"); + set_location(); + prints(contents); + prints(".br\n.di\n.cp 0\n"); + if (!mod->zero_width) { + if (alphabetic) { + printfs(".nr %1 \\n[%1]>?(\\n[dl]+2n)\n", + span_width_reg(start_col, end_col)); + printfs(".nr %1 \\n[%1]>?\\n[dl]\n", + span_alphabetic_width_reg(start_col, end_col)); + } + else + printfs(".nr %1 \\n[%1]>?\\n[dl]\n", span_width_reg(start_col, end_col)); + } + printfs(".nr %1 \\n[dn]\n", block_height_reg(start_row, start_col)); + printfs(".nr %1 \\n[dl]\n", block_width_reg(start_row, start_col)); + prints("." RESET_MACRO_NAME "\n" + ".in \\n[" SAVED_INDENT_REG "]u\n" + ".nf\n"); + // the block might have contained .lf commands + location_force_filename = 1; +} + +void block_entry::do_width() +{ + // do nothing; the action happens in divert +} + +void block_entry::do_depth() +{ + printfs(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?(\\n[%1]+\\n[%2])\n", + row_start_reg(start_row), + block_height_reg(start_row, start_col)); +} + +left_block_entry::left_block_entry(char *s, const entry_modifier *m) +: block_entry(s, m) +{ +} + +void left_block_entry::print() +{ + printfs(".in +\\n[%1]u\n", column_start_reg(start_col)); + printfs(".%1\n", block_diversion_name(start_row, start_col)); + prints(".in\n"); +} + + + +right_block_entry::right_block_entry(char *s, const entry_modifier *m) +: block_entry(s, m) +{ +} + +void right_block_entry::print() +{ + printfs(".in +\\n[%1]u+\\n[%2]u-\\n[%3]u\n", + column_start_reg(start_col), + span_width_reg(start_col, end_col), + block_width_reg(start_row, start_col)); + printfs(".%1\n", block_diversion_name(start_row, start_col)); + prints(".in\n"); +} + +center_block_entry::center_block_entry(char *s, const entry_modifier *m) +: block_entry(s, m) +{ +} + +void center_block_entry::print() +{ + printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n", + column_start_reg(start_col), + span_width_reg(start_col, end_col), + block_width_reg(start_row, start_col)); + printfs(".%1\n", block_diversion_name(start_row, start_col)); + prints(".in\n"); +} + +alphabetic_block_entry::alphabetic_block_entry(char *s, + const entry_modifier *m) +: block_entry(s, m) +{ +} + +int alphabetic_block_entry::divert(int ncols, const string *mw, int *sep) +{ + do_divert(1, ncols, mw, sep); + return 1; +} + +void alphabetic_block_entry::print() +{ + printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n", + column_start_reg(start_col), + span_width_reg(start_col, end_col), + span_alphabetic_width_reg(start_col, end_col)); + printfs(".%1\n", block_diversion_name(start_row, start_col)); + prints(".in\n"); +} + +line_entry::line_entry(const entry_modifier *m) +: simple_entry(m), double_vrule_on_right(0), double_vrule_on_left(0) +{ +} + +void line_entry::note_double_vrule_on_right(int is_corner) +{ + double_vrule_on_right = is_corner ? 1 : 2; +} + +void line_entry::note_double_vrule_on_left(int is_corner) +{ + double_vrule_on_left = is_corner ? 1 : 2; +} + + +single_line_entry::single_line_entry(const entry_modifier *m) +: line_entry(m) +{ +} + +int single_line_entry::line_type() +{ + return 1; +} + +void single_line_entry::simple_print(int dont_move) +{ + printfs("\\h'|\\n[%1]u", + column_divide_reg(start_col)); + if (double_vrule_on_left) { + prints(double_vrule_on_left == 1 ? "-" : "+"); + prints(HALF_DOUBLE_LINE_SEP); + } + prints("'"); + if (!dont_move) + prints("\\v'-" BAR_HEIGHT "'"); + printfs("\\s[\\n[" LINESIZE_REG "]]" "\\D'l |\\n[%1]u", + column_divide_reg(end_col+1)); + if (double_vrule_on_right) { + prints(double_vrule_on_left == 1 ? "+" : "-"); + prints(HALF_DOUBLE_LINE_SEP); + } + prints("0'\\s0"); + if (!dont_move) + prints("\\v'" BAR_HEIGHT "'"); +} + +single_line_entry *single_line_entry::to_single_line_entry() +{ + return this; +} + +double_line_entry::double_line_entry(const entry_modifier *m) +: line_entry(m) +{ +} + +int double_line_entry::line_type() +{ + return 2; +} + +void double_line_entry::simple_print(int dont_move) +{ + if (!dont_move) + prints("\\v'-" BAR_HEIGHT "'"); + printfs("\\h'|\\n[%1]u", + column_divide_reg(start_col)); + if (double_vrule_on_left) { + prints(double_vrule_on_left == 1 ? "-" : "+"); + prints(HALF_DOUBLE_LINE_SEP); + } + prints("'"); + printfs("\\v'-" HALF_DOUBLE_LINE_SEP "'" + "\\s[\\n[" LINESIZE_REG "]]" + "\\D'l |\\n[%1]u", + column_divide_reg(end_col+1)); + if (double_vrule_on_right) + prints("-" HALF_DOUBLE_LINE_SEP); + prints(" 0'"); + printfs("\\v'" DOUBLE_LINE_SEP "'" + "\\D'l |\\n[%1]u", + column_divide_reg(start_col)); + if (double_vrule_on_right) { + prints(double_vrule_on_left == 1 ? "+" : "-"); + prints(HALF_DOUBLE_LINE_SEP); + } + prints(" 0'"); + prints("\\s0" + "\\v'-" HALF_DOUBLE_LINE_SEP "'"); + if (!dont_move) + prints("\\v'" BAR_HEIGHT "'"); +} + +double_line_entry *double_line_entry::to_double_line_entry() +{ + return this; +} + +short_line_entry::short_line_entry(const entry_modifier *m) +: simple_entry(m) +{ +} + +int short_line_entry::line_type() +{ + return 1; +} + +void short_line_entry::simple_print(int dont_move) +{ + if (mod->stagger) + prints("\\v'-.5v'"); + if (!dont_move) + prints("\\v'-" BAR_HEIGHT "'"); + printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); + printfs("\\s[\\n[" LINESIZE_REG "]]" + "\\D'l \\n[%1]u 0'" + "\\s0", + span_width_reg(start_col, end_col)); + if (!dont_move) + prints("\\v'" BAR_HEIGHT "'"); + if (mod->stagger) + prints("\\v'.5v'"); +} + +short_double_line_entry::short_double_line_entry(const entry_modifier *m) +: simple_entry(m) +{ +} + +int short_double_line_entry::line_type() +{ + return 2; +} + +void short_double_line_entry::simple_print(int dont_move) +{ + if (mod->stagger) + prints("\\v'-.5v'"); + if (!dont_move) + prints("\\v'-" BAR_HEIGHT "'"); + printfs("\\h'|\\n[%2]u'" + "\\v'-" HALF_DOUBLE_LINE_SEP "'" + "\\s[\\n[" LINESIZE_REG "]]" + "\\D'l \\n[%1]u 0'" + "\\v'" DOUBLE_LINE_SEP "'" + "\\D'l |\\n[%2]u 0'" + "\\s0" + "\\v'-" HALF_DOUBLE_LINE_SEP "'", + span_width_reg(start_col, end_col), + column_start_reg(start_col)); + if (!dont_move) + prints("\\v'" BAR_HEIGHT "'"); + if (mod->stagger) + prints("\\v'.5v'"); +} + +void set_modifier(const entry_modifier *m) +{ + if (!m->font.empty()) + printfs(".ft %1\n", m->font); + if (m->point_size.val != 0) { + prints(".ps "); + if (m->point_size.inc > 0) + prints('+'); + else if (m->point_size.inc < 0) + prints('-'); + printfs("%1\n", as_string(m->point_size.val)); + } + if (m->vertical_spacing.val != 0) { + prints(".vs "); + if (m->vertical_spacing.inc > 0) + prints('+'); + else if (m->vertical_spacing.inc < 0) + prints('-'); + printfs("%1\n", as_string(m->vertical_spacing.val)); + } +} + +void set_inline_modifier(const entry_modifier *m) +{ + if (!m->font.empty()) + printfs("\\f[%1]", m->font); + if (m->point_size.val != 0) { + prints("\\s["); + if (m->point_size.inc > 0) + prints('+'); + else if (m->point_size.inc < 0) + prints('-'); + printfs("%1]", as_string(m->point_size.val)); + } + if (m->stagger) + prints("\\v'-.5v'"); +} + +void restore_inline_modifier(const entry_modifier *m) +{ + if (!m->font.empty()) + prints("\\f[\\n[" SAVED_FONT_REG "]]"); + if (m->point_size.val != 0) + prints("\\s[\\n[" SAVED_SIZE_REG "]]"); + if (m->stagger) + prints("\\v'.5v'"); +} + + +struct stuff { + stuff *next; + int row; // occurs before row `row' + char printed; // has it been printed? + + stuff(int); + virtual void print(table *) = 0; + virtual ~stuff(); + virtual int is_single_line() { return 0; }; + virtual int is_double_line() { return 0; }; +}; + +stuff::stuff(int r) : row(r), next(0), printed(0) +{ +} + +stuff::~stuff() +{ +} + +struct text_stuff : stuff { + string contents; + const char *filename; + int lineno; + + text_stuff(const string &, int r, const char *fn, int ln); + ~text_stuff(); + void print(table *); +}; + + +text_stuff::text_stuff(const string &s, int r, const char *fn, int ln) +: contents(s), stuff(r), filename(fn), lineno(ln) +{ +} + +text_stuff::~text_stuff() +{ +} + +void text_stuff::print(table *) +{ + printed = 1; + prints(".cp \\n(" COMPATIBLE_REG "\n"); + set_troff_location(filename, lineno); + prints(contents); + prints(".cp 0\n"); + location_force_filename = 1; // it might have been a .lf command +} + +struct single_hline_stuff : stuff { + single_hline_stuff(int r); + void print(table *); + int is_single_line(); +}; + +single_hline_stuff::single_hline_stuff(int r) : stuff(r) +{ +} + +void single_hline_stuff::print(table *tbl) +{ + printed = 1; + tbl->print_single_hline(row); +} + +int single_hline_stuff::is_single_line() +{ + return 1; +} + +struct double_hline_stuff : stuff { + double_hline_stuff(int r); + void print(table *); + int is_double_line(); +}; + +double_hline_stuff::double_hline_stuff(int r) : stuff(r) +{ +} + +void double_hline_stuff::print(table *tbl) +{ + printed = 1; + tbl->print_double_hline(row); +} + +int double_hline_stuff::is_double_line() +{ + return 1; +} + +struct vertical_rule { + vertical_rule *next; + short start_row; + short end_row; + short col; + char is_double; + string top_adjust; + string bot_adjust; + + vertical_rule(int sr, int er, int c, int dbl, vertical_rule *); + ~vertical_rule(); + void contribute_to_bottom_macro(table *); + void print(); +}; + +vertical_rule::vertical_rule(int sr, int er, int c, int dbl, vertical_rule *p) +: start_row(sr), end_row(er), col(c), is_double(dbl), next(p) +{ +} + +vertical_rule::~vertical_rule() +{ +} + +void vertical_rule::contribute_to_bottom_macro(table *tbl) +{ + printfs(".if \\n[" CURRENT_ROW_REG "]>=%1", + as_string(start_row)); + if (end_row != tbl->get_nrows() - 1) + printfs("&(\\n[" CURRENT_ROW_REG "]<%1)", + as_string(end_row)); + prints(" \\{"); + printfs(".if %1<=\\n[" LAST_PASSED_ROW_REG "] .nr %2 \\n[#T]\n", + as_string(start_row), + row_top_reg(start_row)); + const char *offset_table[3]; + if (is_double) { + offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; + offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; + offset_table[2] = 0; + } + else { + offset_table[0] = ""; + offset_table[1] = 0; + } + for (const char **offsetp = offset_table; *offsetp; offsetp++) { + prints(".sp -1\n" + "\\v'" BODY_DEPTH); + if (!bot_adjust.empty()) + printfs("+%1", bot_adjust); + prints("'"); + printfs("\\h'\\n[%1]u%3'\\s[\\n[" LINESIZE_REG "]]\\D'l 0 |\\n[%2]u-1v", + column_divide_reg(col), + row_top_reg(start_row), + *offsetp); + if (!bot_adjust.empty()) + printfs("-(%1)", bot_adjust); + // don't perform the top adjustment if the top is actually #T + if (!top_adjust.empty()) + printfs("+((%1)*(%2>\\n[" LAST_PASSED_ROW_REG "]))", + top_adjust, + as_string(start_row)); + prints("'\\s0\n"); + } + prints(".\\}\n"); +} + +void vertical_rule::print() +{ + printfs("\\*[" TRANSPARENT_STRING_NAME "]" + ".if %1<=\\*[" QUOTE_STRING_NAME "]\\n[" LAST_PASSED_ROW_REG "] " + ".nr %2 \\*[" QUOTE_STRING_NAME "]\\n[#T]\n", + as_string(start_row), + row_top_reg(start_row)); + const char *offset_table[3]; + if (is_double) { + offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; + offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; + offset_table[2] = 0; + } + else { + offset_table[0] = ""; + offset_table[1] = 0; + } + for (const char **offsetp = offset_table; *offsetp; offsetp++) { + prints("\\*[" TRANSPARENT_STRING_NAME "].sp -1\n" + "\\*[" TRANSPARENT_STRING_NAME "]\\v'" BODY_DEPTH); + if (!bot_adjust.empty()) + printfs("+%1", bot_adjust); + prints("'"); + printfs("\\h'\\n[%1]u%3'" + "\\s[\\n[" LINESIZE_REG "]]" + "\\D'l 0 |\\*[" QUOTE_STRING_NAME "]\\n[%2]u-1v", + column_divide_reg(col), + row_top_reg(start_row), + *offsetp); + if (!bot_adjust.empty()) + printfs("-(%1)", bot_adjust); + // don't perform the top adjustment if the top is actually #T + if (!top_adjust.empty()) + printfs("+((%1)*(%2>\\*[" QUOTE_STRING_NAME "]\\n[" + LAST_PASSED_ROW_REG "]))", + top_adjust, + as_string(start_row)); + prints("'" + "\\s0\n"); + } +} + +table::table(int nc, unsigned f, int ls, char dpc) +: ncolumns(nc), flags(f), linesize(ls), decimal_point_char(dpc), + nrows(0), allocated_rows(0), entry(0), entry_list(0), + left_separation(0), right_separation(0), stuff_list(0), vline(0), + vrule_list(0), row_is_all_lines(0), span_list(0) +{ + minimum_width = new string[ncolumns]; + column_separation = ncolumns > 1 ? new int[ncolumns - 1] : 0; + equal = new char[ncolumns]; + int i; + for (i = 0; i < ncolumns; i++) + equal[i] = 0; + for (i = 0; i < ncolumns-1; i++) + column_separation[i] = DEFAULT_COLUMN_SEPARATION; + delim[0] = delim[1] = '\0'; +} + +table::~table() +{ + for (int i = 0; i < nrows; i++) { + a_delete entry[i]; + a_delete vline[i]; + } + a_delete entry; + a_delete vline; + while (entry_list) { + table_entry *tem = entry_list; + entry_list = entry_list->next; + delete tem; + } + ad_delete(ncolumns) minimum_width; + a_delete column_separation; + a_delete equal; + while (stuff_list) { + stuff *tem = stuff_list; + stuff_list = stuff_list->next; + delete tem; + } + while (vrule_list) { + vertical_rule *tem = vrule_list; + vrule_list = vrule_list->next; + delete tem; + } + a_delete row_is_all_lines; + while (span_list) { + horizontal_span *tem = span_list; + span_list = span_list->next; + delete tem; + } +} + +void table::set_delim(char c1, char c2) +{ + delim[0] = c1; + delim[1] = c2; +} + +void table::set_minimum_width(int c, const string &w) +{ + assert(c >= 0 && c < ncolumns); + minimum_width[c] = w; +} + +void table::set_column_separation(int c, int n) +{ + assert(c >= 0 && c < ncolumns - 1); + column_separation[c] = n; +} + +void table::set_equal_column(int c) +{ + assert(c >= 0 && c < ncolumns); + equal[c] = 1; +} + +void table::add_stuff(stuff *p) +{ + for (stuff **pp = &stuff_list; *pp; pp = &(*pp)->next) + ; + *pp = p; +} + +void table::add_text_line(int r, const string &s, const char *filename, int lineno) +{ + add_stuff(new text_stuff(s, r, filename, lineno)); +} + +void table::add_single_hline(int r) +{ + add_stuff(new single_hline_stuff(r)); +} + +void table::add_double_hline(int r) +{ + add_stuff(new double_hline_stuff(r)); +} + +void table::allocate(int r) +{ + if (r >= nrows) { + typedef table_entry **PPtable_entry; // work around g++ 1.36.1 bug + if (r >= allocated_rows) { + if (allocated_rows == 0) { + allocated_rows = 16; + if (allocated_rows <= r) + allocated_rows = r + 1; + entry = new PPtable_entry[allocated_rows]; + vline = new char*[allocated_rows]; + } + else { + table_entry ***old_entry = entry; + int old_allocated_rows = allocated_rows; + allocated_rows *= 2; + if (allocated_rows <= r) + allocated_rows = r + 1; + entry = new PPtable_entry[allocated_rows]; + memcpy(entry, old_entry, sizeof(table_entry**)*old_allocated_rows); + a_delete old_entry; + char **old_vline = vline; + vline = new char*[allocated_rows]; + memcpy(vline, old_vline, sizeof(char*)*old_allocated_rows); + a_delete old_vline; + } + } + assert(allocated_rows > r); + while (nrows <= r) { + entry[nrows] = new table_entry*[ncolumns]; + for (int i = 0; i < ncolumns; i++) + entry[nrows][i] = 0; + vline[nrows] = new char[ncolumns+1]; + for (i = 0; i < ncolumns+1; i++) + vline[nrows][i] = 0; + nrows++; + } + } +} + +void table::do_hspan(int r, int c) +{ + assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); + if (c == 0) { + error("first column cannot be horizontally spanned"); + return; + } + table_entry *e = entry[r][c]; + if (e) { + assert(e->start_row <= r && r <= e->end_row + && e->start_col <= c && c <= e->end_col + && e->end_row - e->start_row > 0 + && e->end_col - e->start_col > 0); + return; + } + e = entry[r][c-1]; + // e can be 0 if we had an empty entry or an error + if (e == 0) + return; + if (e->start_row != r) { + /* + l l + ^ s */ + error("impossible horizontal span at row %1, column %2", r + 1, c + 1); + } + else { + e->end_col = c; + entry[r][c] = e; + } +} + +void table::do_vspan(int r, int c) +{ + assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); + if (r == 0) { + error("first row cannot be vertically spanned"); + return; + } + table_entry *e = entry[r][c]; + if (e) { + assert(e->start_row <= r && r <= e->end_row + && e->start_col <= c && c <= e->end_col + && e->end_row - e->start_row > 0 + && e->end_col - e->start_col > 0); + return; + } + e = entry[r-1][c]; + // e can be 0 if we had an empty entry or an error + if (e == 0) + return; + if (e->start_col != c) { + /* l s + l ^ */ + error("impossible vertical span at row %1, column %2", r + 1, c + 1); + } + else { + for (int i = c; i <= e->end_col; i++) { + assert(entry[r][i] == 0); + entry[r][i] = e; + } + e->end_row = r; + } +} + +int find_decimal_point(const char *s, char decimal_point_char, + const char *delim) +{ + if (s == 0 || *s == '\0') + return -1; + const char *p; + int in_delim = 0; // is p within eqn delimiters? + // tbl recognises \& even within eqn delimiters; I don't + for (p = s; *p; p++) + if (in_delim) { + if (*p == delim[1]) + in_delim = 0; + } + else if (*p == delim[0]) + in_delim = 1; + else if (p[0] == '\\' && p[1] == '&') + return p - s; + int possible_pos = -1; + in_delim = 0; + for (p = s; *p; p++) + if (in_delim) { + if (*p == delim[1]) + in_delim = 0; + } + else if (*p == delim[0]) + in_delim = 1; + else if (p[0] == decimal_point_char && csdigit(p[1])) + possible_pos = p - s; + if (possible_pos >= 0) + return possible_pos; + in_delim = 0; + for (p = s; *p; p++) + if (in_delim) { + if (*p == delim[1]) + in_delim = 0; + } + else if (*p == delim[0]) + in_delim = 1; + else if (csdigit(*p)) + possible_pos = p + 1 - s; + return possible_pos; +} + +void table::add_entry(int r, int c, const string &str, const entry_format *f, + const char *fn, int ln) +{ + allocate(r); + table_entry *e = 0; + if (str == "\\_") { + e = new short_line_entry(f); + } + else if (str == "\\=") { + e = new short_double_line_entry(f); + } + else if (str == "_") { + single_line_entry *lefte; + if (c > 0 && entry[r][c-1] != 0 && + (lefte = entry[r][c-1]->to_single_line_entry()) != 0 + && lefte->start_row == r + && lefte->mod->stagger == f->stagger) { + lefte->end_col = c; + entry[r][c] = lefte; + } + else + e = new single_line_entry(f); + } + else if (str == "=") { + double_line_entry *lefte; + if (c > 0 && entry[r][c-1] != 0 && + (lefte = entry[r][c-1]->to_double_line_entry()) != 0 + && lefte->start_row == r + && lefte->mod->stagger == f->stagger) { + lefte->end_col = c; + entry[r][c] = lefte; + } + else + e = new double_line_entry(f); + } + else if (str == "\\^") { + do_vspan(r, c); + } + else if (str.length() > 2 && str[0] == '\\' && str[1] == 'R') { + if (str.search('\n') >= 0) + error_with_file_and_line(fn, ln, "bad repeated character"); + else { + char *s = str.substring(2, str.length() - 2).extract(); + e = new repeated_char_entry(s, f); + } + } + else { + int is_block = str.search('\n') >= 0; + char *s; + switch (f->type) { + case FORMAT_SPAN: + assert(str.empty()); + do_hspan(r, c); + break; + case FORMAT_LEFT: + if (!str.empty()) { + s = str.extract(); + if (is_block) + e = new left_block_entry(s, f); + else + e = new left_text_entry(s, f); + } + else + e = new empty_entry(f); + break; + case FORMAT_CENTER: + if (!str.empty()) { + s = str.extract(); + if (is_block) + e = new center_block_entry(s, f); + else + e = new center_text_entry(s, f); + } + else + e = new empty_entry(f); + break; + case FORMAT_RIGHT: + if (!str.empty()) { + s = str.extract(); + if (is_block) + e = new right_block_entry(s, f); + else + e = new right_text_entry(s, f); + } + else + e = new empty_entry(f); + break; + case FORMAT_NUMERIC: + if (!str.empty()) { + s = str.extract(); + if (is_block) { + error_with_file_and_line(fn, ln, "can't have numeric text block"); + e = new left_block_entry(s, f); + } + else { + int pos = find_decimal_point(s, decimal_point_char, delim); + if (pos < 0) + e = new center_text_entry(s, f); + else + e = new numeric_text_entry(s, f, pos); + } + } + else + e = new empty_entry(f); + break; + case FORMAT_ALPHABETIC: + if (!str.empty()) { + s = str.extract(); + if (is_block) + e = new alphabetic_block_entry(s, f); + else + e = new alphabetic_text_entry(s, f); + } + else + e = new empty_entry(f); + break; + case FORMAT_VSPAN: + do_vspan(r, c); + break; + case FORMAT_HLINE: + if (str.length() != 0) + error_with_file_and_line(fn, ln, + "non-empty data entry for `_' format ignored"); + e = new single_line_entry(f); + break; + case FORMAT_DOUBLE_HLINE: + if (str.length() != 0) + error_with_file_and_line(fn, ln, + "non-empty data entry for `=' format ignored"); + e = new double_line_entry(f); + break; + default: + assert(0); + } + } + if (e) { + table_entry *preve = entry[r][c]; + if (preve) { + /* c s + ^ l */ + error_with_file_and_line(fn, ln, "row %1, column %2 already spanned", + r + 1, c + 1); + delete e; + } + else { + e->input_lineno = ln; + e->input_filename = fn; + e->start_row = e->end_row = r; + e->start_col = e->end_col = c; + for (table_entry **p = &entry_list; *p; p = &(*p)->next) + ; + *p = e; + entry[r][c] = e; + } + } +} + +// add vertical lines for row r + +void table::add_vlines(int r, const char *v) +{ + allocate(r); + for (int i = 0; i < ncolumns+1; i++) + vline[r][i] = v[i]; +} + +void table::check() +{ + table_entry *p = entry_list; + int i, j; + while (p) { + for (i = p->start_row; i <= p->end_row; i++) + for (j = p->start_col; j <= p->end_col; j++) + assert(entry[i][j] == p); + p = p->next; + } +} + +void table::print() +{ + location_force_filename = 1; + check(); + init_output(); + determine_row_type(); + compute_widths(); + if (!(flags & CENTER)) + prints(".if \\n[" SAVED_CENTER_REG "] \\{"); + prints(".in +(u;\\n[.l]-\\n[.i]-\\n[TW]/2)\n" + ".nr " SAVED_INDENT_REG " \\n[.i]\n"); + if (!(flags & CENTER)) + prints(".\\}\n"); + build_vrule_list(); + define_bottom_macro(); + do_top(); + for (int i = 0; i < nrows; i++) + do_row(i); + do_bottom(); +} + +void table::determine_row_type() +{ + row_is_all_lines = new char[nrows]; + for (int i = 0; i < nrows; i++) { + int had_single = 0; + int had_double = 0; + int had_non_line = 0; + for (int c = 0; c < ncolumns; c++) { + table_entry *e = entry[i][c]; + if (e != 0) { + if (e->start_row == e->end_row) { + int t = e->line_type(); + switch (t) { + case -1: + had_non_line = 1; + break; + case 0: + // empty + break; + case 1: + had_single = 1; + break; + case 2: + had_double = 1; + break; + default: + assert(0); + } + if (had_non_line) + break; + } + c = e->end_col; + } + } + if (had_non_line) + row_is_all_lines[i] = 0; + else if (had_double) + row_is_all_lines[i] = 2; + else if (had_single) + row_is_all_lines[i] = 1; + else + row_is_all_lines[i] = 0; + } +} + + +void table::init_output() +{ + prints(".nr " COMPATIBLE_REG " \\n(.C\n" + ".cp 0\n"); + if (linesize > 0) + printfs(".nr " LINESIZE_REG " %1\n", as_string(linesize)); + else + prints(".nr " LINESIZE_REG " \\n[.s]\n"); + if (!(flags & CENTER)) + prints(".nr " SAVED_CENTER_REG " \\n[.ce]\n"); + prints(".de " RESET_MACRO_NAME "\n" + ".ft \\n[.f]\n" + ".ps \\n[.s]\n" + ".vs \\n[.v]u\n" + ".in \\n[.i]u\n" + ".ll \\n[.l]u\n" + ".ls \\n[.L]\n" + ".ad \\n[.j]\n" + ".ie \\n[.u] .fi\n" + ".el .nf\n" + ".ce \\n[.ce]\n" + "..\n" + ".nr " SAVED_INDENT_REG " \\n[.i]\n" + ".nr " SAVED_FONT_REG " \\n[.f]\n" + ".nr " SAVED_SIZE_REG " \\n[.s]\n" + ".nr " SAVED_FILL_REG " \\n[.u]\n" + ".nr T. 0\n" + ".nr " CURRENT_ROW_REG " 0-1\n" + ".nr " LAST_PASSED_ROW_REG " 0-1\n" + ".nr " SECTION_DIVERSION_FLAG_REG " 0\n" + ".ds " TRANSPARENT_STRING_NAME "\n" + ".ds " QUOTE_STRING_NAME "\n" + ".nr " NEED_BOTTOM_RULE_REG " 1\n" + ".nr " SUPPRESS_BOTTOM_REG " 0\n" + ".eo\n" + ".de " REPEATED_MARK_MACRO "\n" + ".mk \\$1\n" + ".if !'\\n(.z'' \\!." REPEATED_MARK_MACRO " \"\\$1\"\n" + "..\n" + ".de " REPEATED_VPT_MACRO "\n" + ".vpt \\$1\n" + ".if !'\\n(.z'' \\!." REPEATED_VPT_MACRO " \"\\$1\"\n" + "..\n"); + if (!(flags & NOKEEP)) + prints(".de " KEEP_MACRO_NAME "\n" + ".if '\\n[.z]'' \\{.ds " QUOTE_STRING_NAME " \\\\\n" + ".ds " TRANSPARENT_STRING_NAME " \\!\n" + ".di " SECTION_DIVERSION_NAME "\n" + ".nr " SECTION_DIVERSION_FLAG_REG " 1\n" + ".in 0\n" + ".\\}\n" + "..\n" + ".de " RELEASE_MACRO_NAME "\n" + ".if \\n[" SECTION_DIVERSION_FLAG_REG "] \\{" + ".di\n" + ".in \\n[" SAVED_INDENT_REG "]u\n" + ".nr " SAVED_DN_REG " \\n[dn]\n" + ".ds " QUOTE_STRING_NAME "\n" + ".ds " TRANSPARENT_STRING_NAME "\n" + ".nr " SECTION_DIVERSION_FLAG_REG " 0\n" + ".if \\n[.t]<=\\n[dn] \\{" + ".nr T. 1\n" + ".T#\n" + ".nr " SUPPRESS_BOTTOM_REG " 1\n" + ".sp \\n[.t]u\n" + ".nr " SUPPRESS_BOTTOM_REG " 0\n" + ".mk #T\n" + ".\\}\n" + ".if \\n[.t]<=\\n[" SAVED_DN_REG "] " + /* Since we turn off traps, it won't get into an infinite loop + when we try and print it; it will just go off the bottom of the + page. */ + ".tm warning: page \\n%: table text block will not fit on one page\n" + ".nf\n" + ".ls 1\n" + "." SECTION_DIVERSION_NAME "\n" + ".ls\n" + ".rm " SECTION_DIVERSION_NAME "\n" + ".\\}\n" + "..\n" + ".nr " TABLE_DIVERSION_FLAG_REG " 0\n" + ".de " TABLE_KEEP_MACRO_NAME "\n" + ".if '\\n[.z]'' \\{" + ".di " TABLE_DIVERSION_NAME "\n" + ".nr " TABLE_DIVERSION_FLAG_REG " 1\n" + ".\\}\n" + "..\n" + ".de " TABLE_RELEASE_MACRO_NAME "\n" + ".if \\n[" TABLE_DIVERSION_FLAG_REG "] \\{.br\n" + ".di\n" + ".nr " SAVED_DN_REG " \\n[dn]\n" + ".ne \\n[dn]u+\\n[.V]u\n" + ".ie \\n[.t]<=\\n[" SAVED_DN_REG "] " + ".tm error: page \\n%: table will not fit on one page; use .TS H/.TH with a supporting macro package\n" + ".el \\{" + ".in 0\n" + ".ls 1\n" + ".nf\n" + "." TABLE_DIVERSION_NAME "\n" + ".\\}\n" + ".rm " TABLE_DIVERSION_NAME "\n" + ".\\}\n" + "..\n"); + prints(".ec\n" + ".ce 0\n" + ".nf\n"); +} + +string block_width_reg(int r, int c) +{ + static char name[sizeof(BLOCK_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; + sprintf(name, BLOCK_WIDTH_PREFIX "%d,%d", r, c); + return string(name); +} + +string block_diversion_name(int r, int c) +{ + static char name[sizeof(BLOCK_DIVERSION_PREFIX)+INT_DIGITS+1+INT_DIGITS]; + sprintf(name, BLOCK_DIVERSION_PREFIX "%d,%d", r, c); + return string(name); +} + +string block_height_reg(int r, int c) +{ + static char name[sizeof(BLOCK_HEIGHT_PREFIX)+INT_DIGITS+1+INT_DIGITS]; + sprintf(name, BLOCK_HEIGHT_PREFIX "%d,%d", r, c); + return string(name); +} + +string span_width_reg(int start_col, int end_col) +{ + static char name[sizeof(SPAN_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; + sprintf(name, SPAN_WIDTH_PREFIX "%d", start_col); + if (end_col != start_col) + sprintf(strchr(name, '\0'), ",%d", end_col); + return string(name); +} + +string span_left_numeric_width_reg(int start_col, int end_col) +{ + static char name[sizeof(SPAN_LEFT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; + sprintf(name, SPAN_LEFT_NUMERIC_WIDTH_PREFIX "%d", start_col); + if (end_col != start_col) + sprintf(strchr(name, '\0'), ",%d", end_col); + return string(name); +} + +string span_right_numeric_width_reg(int start_col, int end_col) +{ + static char name[sizeof(SPAN_RIGHT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; + sprintf(name, SPAN_RIGHT_NUMERIC_WIDTH_PREFIX "%d", start_col); + if (end_col != start_col) + sprintf(strchr(name, '\0'), ",%d", end_col); + return string(name); +} + +string span_alphabetic_width_reg(int start_col, int end_col) +{ + static char name[sizeof(SPAN_ALPHABETIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; + sprintf(name, SPAN_ALPHABETIC_WIDTH_PREFIX "%d", start_col); + if (end_col != start_col) + sprintf(strchr(name, '\0'), ",%d", end_col); + return string(name); +} + + +string column_separation_reg(int col) +{ + static char name[sizeof(COLUMN_SEPARATION_PREFIX)+INT_DIGITS]; + sprintf(name, COLUMN_SEPARATION_PREFIX "%d", col); + return string(name); +} + +string row_start_reg(int row) +{ + static char name[sizeof(ROW_START_PREFIX)+INT_DIGITS]; + sprintf(name, ROW_START_PREFIX "%d", row); + return string(name); +} + +string column_start_reg(int col) +{ + static char name[sizeof(COLUMN_START_PREFIX)+INT_DIGITS]; + sprintf(name, COLUMN_START_PREFIX "%d", col); + return string(name); +} + +string column_end_reg(int col) +{ + static char name[sizeof(COLUMN_END_PREFIX)+INT_DIGITS]; + sprintf(name, COLUMN_END_PREFIX "%d", col); + return string(name); +} + +string column_divide_reg(int col) +{ + static char name[sizeof(COLUMN_DIVIDE_PREFIX)+INT_DIGITS]; + sprintf(name, COLUMN_DIVIDE_PREFIX "%d", col); + return string(name); +} + +string row_top_reg(int row) +{ + static char name[sizeof(ROW_TOP_PREFIX)+INT_DIGITS]; + sprintf(name, ROW_TOP_PREFIX "%d", row); + return string(name); +} + +void init_span_reg(int start_col, int end_col) +{ + printfs(".nr %1 \\n(.H\n.nr %2 0\n.nr %3 0\n.nr %4 0\n", + span_width_reg(start_col, end_col), + span_alphabetic_width_reg(start_col, end_col), + span_left_numeric_width_reg(start_col, end_col), + span_right_numeric_width_reg(start_col, end_col)); +} + +void compute_span_width(int start_col, int end_col) +{ + printfs(".nr %1 \\n[%1]>?(\\n[%2]+\\n[%3])\n" + ".if \\n[%4] .nr %1 \\n[%1]>?(\\n[%4]+2n)\n", + span_width_reg(start_col, end_col), + span_left_numeric_width_reg(start_col, end_col), + span_right_numeric_width_reg(start_col, end_col), + span_alphabetic_width_reg(start_col, end_col)); + +} + +// Increase the widths of columns so that the width of any spanning entry +// is no greater than the sum of the widths of the columns that it spans. +// Ensure that the widths of columns remain equal. + +void table::divide_span(int start_col, int end_col) +{ + assert(end_col > start_col); + printfs(".nr " NEEDED_REG " \\n[%1]-(\\n[%2]", + span_width_reg(start_col, end_col), + span_width_reg(start_col, start_col)); + for (int i = start_col + 1; i <= end_col; i++) { + // The column separation may shrink with the expand option. + if (!(flags & EXPAND)) + printfs("+%1n", as_string(column_separation[i - 1])); + printfs("+\\n[%1]", span_width_reg(i, i)); + } + prints(")\n"); + printfs(".nr " NEEDED_REG " \\n[" NEEDED_REG "]/%1\n", + as_string(end_col - start_col + 1)); + prints(".if \\n[" NEEDED_REG "] \\{"); + for (i = start_col; i <= end_col; i++) + printfs(".nr %1 +\\n[" NEEDED_REG "]\n", + span_width_reg(i, i)); + int equal_flag = 0; + for (i = start_col; i <= end_col && !equal_flag; i++) + if (equal[i]) + equal_flag = 1; + if (equal_flag) { + for (i = 0; i < ncolumns; i++) + if (i < start_col || i > end_col) + printfs(".nr %1 +\\n[" NEEDED_REG "]\n", + span_width_reg(i, i)); + } + prints(".\\}\n"); +} + + +void table::sum_columns(int start_col, int end_col) +{ + assert(end_col > start_col); + printfs(".nr %1 \\n[%2]", + span_width_reg(start_col, end_col), + span_width_reg(start_col, start_col)); + for (int i = start_col + 1; i <= end_col; i++) + printfs("+(%1*\\n[" SEPARATION_FACTOR_REG "])+\\n[%2]", + as_string(column_separation[i - 1]), + span_width_reg(i, i)); + prints('\n'); +} + +horizontal_span::horizontal_span(int sc, int ec, horizontal_span *p) +: start_col(sc), end_col(ec), next(p) +{ +} + +void table::build_span_list() +{ + span_list = 0; + table_entry *p = entry_list; + while (p) { + if (p->end_col != p->start_col) { + for (horizontal_span *q = span_list; q; q = q->next) + if (q->start_col == p->start_col + && q->end_col == p->end_col) + break; + if (!q) + span_list = new horizontal_span(p->start_col, p->end_col, span_list); + } + p = p->next; + } + // Now sort span_list primarily by order of end_row, and secondarily + // by reverse order of start_row. This ensures that if we divide + // spans using the order in span_list, we will get reasonable results. + horizontal_span *unsorted = span_list; + span_list = 0; + while (unsorted) { + for (horizontal_span **pp = &span_list; *pp; pp = &(*pp)->next) + if (unsorted->end_col < (*pp)->end_col + || (unsorted->end_col == (*pp)->end_col + && (unsorted->start_col > (*pp)->start_col))) + break; + horizontal_span *tem = unsorted->next; + unsorted->next = *pp; + *pp = unsorted; + unsorted = tem; + } +} + + +void table::compute_separation_factor() +{ + if (flags & (ALLBOX|BOX|DOUBLEBOX)) + left_separation = right_separation = 1; + else { + for (int i = 0; i < nrows; i++) { + if (vline[i][0] > 0) + left_separation = 1; + if (vline[i][ncolumns] > 0) + right_separation = 1; + } + } + if (flags & EXPAND) { + int total_sep = left_separation + right_separation; + for (int i = 0; i < ncolumns - 1; i++) + total_sep += column_separation[i]; + if (total_sep != 0) { + // Don't let the separation factor be negative. + prints(".nr " SEPARATION_FACTOR_REG " \\n[.l]-\\n[.i]"); + for (i = 0; i < ncolumns; i++) + printfs("-\\n[%1]", span_width_reg(i, i)); + printfs("/%1>?0\n", as_string(total_sep)); + } + } +} + +void table::compute_column_positions() +{ + printfs(".nr %1 0\n", column_divide_reg(0)); + printfs(".nr %1 %2*\\n[" SEPARATION_FACTOR_REG "]\n", + column_start_reg(0), + as_string(left_separation)); + for (int i = 1;; i++) { + printfs(".nr %1 \\n[%2]+\\n[%3]\n", + column_end_reg(i-1), + column_start_reg(i-1), + span_width_reg(i-1, i-1)); + if (i >= ncolumns) + break; + printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n", + column_start_reg(i), + column_end_reg(i-1), + as_string(column_separation[i-1])); + printfs(".nr %1 \\n[%2]+\\n[%3]/2\n", + column_divide_reg(i), + column_end_reg(i-1), + column_start_reg(i)); + } + printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n", + column_divide_reg(ncolumns), + column_end_reg(i-1), + as_string(right_separation)); + printfs(".nr TW \\n[%1]\n", + column_divide_reg(ncolumns)); + if (flags & DOUBLEBOX) { + printfs(".nr %1 +" DOUBLE_LINE_SEP "\n", column_divide_reg(0)); + printfs(".nr %1 -" DOUBLE_LINE_SEP "\n", column_divide_reg(ncolumns)); + } +} + +void table::make_columns_equal() +{ + int first = -1; // index of first equal column + for (int i = 0; i < ncolumns; i++) + if (equal[i]) { + if (first < 0) { + printfs(".nr %1 \\n[%1]", span_width_reg(i, i)); + first = i; + } + else + printfs(">?\\n[%1]", span_width_reg(i, i)); + } + if (first >= 0) { + prints('\n'); + for (i = first + 1; i < ncolumns; i++) + if (equal[i]) + printfs(".nr %1 \\n[%2]\n", + span_width_reg(i, i), + span_width_reg(first, first)); + } +} + +void table::compute_widths() +{ + build_span_list(); + int i; + horizontal_span *p; + prints(".nr " SEPARATION_FACTOR_REG " 1n\n"); + for (i = 0; i < ncolumns; i++) { + init_span_reg(i, i); + if (!minimum_width[i].empty()) + printfs(".nr %1 %2\n", span_width_reg(i, i), minimum_width[i]); + } + for (p = span_list; p; p = p->next) + init_span_reg(p->start_col, p->end_col); + table_entry *q; + for (q = entry_list; q; q = q->next) + if (!q->mod->zero_width) + q->do_width(); + for (i = 0; i < ncolumns; i++) + compute_span_width(i, i); + for (p = span_list; p; p = p->next) + compute_span_width(p->start_col, p->end_col); + make_columns_equal(); + // Note that divide_span keeps equal width columns equal. + for (p = span_list; p; p = p->next) + divide_span(p->start_col, p->end_col); + for (p = span_list; p; p = p->next) + sum_columns(p->start_col, p->end_col); + int had_spanning_block = 0; + int had_equal_block = 0; + for (q = entry_list; q; q = q->next) + if (q->divert(ncolumns, minimum_width, + (flags & EXPAND) ? column_separation : 0)) { + if (q->end_col > q->start_col) + had_spanning_block = 1; + for (i = q->start_col; i <= q->end_col && !had_equal_block; i++) + if (equal[i]) + had_equal_block = 1; + } + if (had_equal_block) + make_columns_equal(); + if (had_spanning_block) + for (p = span_list; p; p = p->next) + divide_span(p->start_col, p->end_col); + compute_separation_factor(); + for (p = span_list; p; p = p->next) + sum_columns(p->start_col, p->end_col); + compute_column_positions(); +} + +void table::print_single_hline(int r) +{ + prints(".vs " LINE_SEP ">?\\n[.V]u\n" + ".ls 1\n" + "\\v'" BODY_DEPTH "'" + "\\s[\\n[" LINESIZE_REG "]]"); + if (r > nrows - 1) + prints("\\D'l |\\n[TW]u 0'"); + else { + int start_col = 0; + for (;;) { + while (start_col < ncolumns + && entry[r][start_col] != 0 + && entry[r][start_col]->start_row != r) + start_col++; + for (int end_col = start_col; + end_col < ncolumns + && (entry[r][end_col] == 0 + || entry[r][end_col]->start_row == r); + end_col++) + ; + if (end_col <= start_col) + break; + printfs("\\h'|\\n[%1]u", + column_divide_reg(start_col)); + if ((r > 0 && vline[r-1][start_col] == 2) + || (r < nrows && vline[r][start_col] == 2)) + prints("-" HALF_DOUBLE_LINE_SEP); + prints("'"); + printfs("\\D'l |\\n[%1]u", + column_divide_reg(end_col)); + if ((r > 0 && vline[r-1][end_col] == 2) + || (r < nrows && vline[r][end_col] == 2)) + prints("+" HALF_DOUBLE_LINE_SEP); + prints(" 0'"); + start_col = end_col; + } + } + prints("\\s0\n"); + prints(".ls\n" + ".vs\n"); +} + +void table::print_double_hline(int r) +{ + prints(".vs " LINE_SEP "+" DOUBLE_LINE_SEP + ">?\\n[.V]u\n" + ".ls 1\n" + "\\v'" BODY_DEPTH "'" + "\\s[\\n[" LINESIZE_REG "]]"); + if (r > nrows - 1) + prints("\\v'-" DOUBLE_LINE_SEP "'" + "\\D'l |\\n[TW]u 0'" + "\\v'" DOUBLE_LINE_SEP "'" + "\\h'|0'" + "\\D'l |\\n[TW]u 0'"); + else { + int start_col = 0; + for (;;) { + while (start_col < ncolumns + && entry[r][start_col] != 0 + && entry[r][start_col]->start_row != r) + start_col++; + for (int end_col = start_col; + end_col < ncolumns + && (entry[r][end_col] == 0 + || entry[r][end_col]->start_row == r); + end_col++) + ; + if (end_col <= start_col) + break; + const char *left_adjust = 0; + if ((r > 0 && vline[r-1][start_col] == 2) + || (r < nrows && vline[r][start_col] == 2)) + left_adjust = "-" HALF_DOUBLE_LINE_SEP; + const char *right_adjust = 0; + if ((r > 0 && vline[r-1][end_col] == 2) + || (r < nrows && vline[r][end_col] == 2)) + right_adjust = "+" HALF_DOUBLE_LINE_SEP; + printfs("\\v'-" DOUBLE_LINE_SEP "'" + "\\h'|\\n[%1]u", + column_divide_reg(start_col)); + if (left_adjust) + prints(left_adjust); + prints("'"); + printfs("\\D'l |\\n[%1]u", + column_divide_reg(end_col)); + if (right_adjust) + prints(right_adjust); + prints(" 0'"); + printfs("\\v'" DOUBLE_LINE_SEP "'" + "\\h'|\\n[%1]u", + column_divide_reg(start_col)); + if (left_adjust) + prints(left_adjust); + prints("'"); + printfs("\\D'l |\\n[%1]u", + column_divide_reg(end_col)); + if (right_adjust) + prints(right_adjust); + prints(" 0'"); + start_col = end_col; + } + } + prints("\\s0\n" + ".ls\n" + ".vs\n"); +} + +void table::compute_vrule_top_adjust(int start_row, int col, string &result) +{ + if (row_is_all_lines[start_row] && start_row < nrows - 1) { + if (row_is_all_lines[start_row] == 2) + result = LINE_SEP ">?\\n[.V]u" "+" DOUBLE_LINE_SEP; + else + result = LINE_SEP ">?\\n[.V]u"; + start_row++; + } + else { + result = ""; + if (start_row == 0) + return; + for (stuff *p = stuff_list; p && p->row <= start_row; p = p->next) + if (p->row == start_row + && (p->is_single_line() || p->is_double_line())) + return; + } + int left = 0; + if (col > 0) { + table_entry *e = entry[start_row-1][col-1]; + if (e && e->start_row == e->end_row) { + if (e->to_double_line_entry() != 0) + left = 2; + else if (e->to_single_line_entry() != 0) + left = 1; + } + } + int right = 0; + if (col < ncolumns) { + table_entry *e = entry[start_row-1][col]; + if (e && e->start_row == e->end_row) { + if (e->to_double_line_entry() != 0) + right = 2; + else if (e->to_single_line_entry() != 0) + right = 1; + } + } + if (row_is_all_lines[start_row-1] == 0) { + if (left > 0 || right > 0) { + result += "-" BODY_DEPTH "-" BAR_HEIGHT; + if ((left == 2 && right != 2) || (right == 2 && left != 2)) + result += "-" HALF_DOUBLE_LINE_SEP; + else if (left == 2 && right == 2) + result += "+" HALF_DOUBLE_LINE_SEP; + } + } + else if (row_is_all_lines[start_row-1] == 2) { + if ((left == 2 && right != 2) || (right == 2 && left != 2)) + result += "-" DOUBLE_LINE_SEP; + else if (left == 1 || right == 1) + result += "-" HALF_DOUBLE_LINE_SEP; + } +} + +void table::compute_vrule_bot_adjust(int end_row, int col, string &result) +{ + if (row_is_all_lines[end_row] && end_row > 0) { + end_row--; + result = ""; + } + else { + for (stuff *p = stuff_list; p && p->row < end_row + 1; p = p->next) + ; + if (p && p->row == end_row + 1 && p->is_double_line()) { + result = "-" DOUBLE_LINE_SEP; + return; + } + if ((p != 0 && p->row == end_row + 1) + || end_row == nrows - 1) { + result = ""; + return; + } + if (row_is_all_lines[end_row+1] == 1) + result = LINE_SEP; + else if (row_is_all_lines[end_row+1] == 2) + result = LINE_SEP "+" DOUBLE_LINE_SEP; + else + result = ""; + } + int left = 0; + if (col > 0) { + table_entry *e = entry[end_row+1][col-1]; + if (e && e->start_row == e->end_row) { + if (e->to_double_line_entry() != 0) + left = 2; + else if (e->to_single_line_entry() != 0) + left = 1; + } + } + int right = 0; + if (col < ncolumns) { + table_entry *e = entry[end_row+1][col]; + if (e && e->start_row == e->end_row) { + if (e->to_double_line_entry() != 0) + right = 2; + else if (e->to_single_line_entry() != 0) + right = 1; + } + } + if (row_is_all_lines[end_row+1] == 0) { + if (left > 0 || right > 0) { + result = "1v-" BODY_DEPTH "-" BAR_HEIGHT; + if ((left == 2 && right != 2) || (right == 2 && left != 2)) + result += "+" HALF_DOUBLE_LINE_SEP; + else if (left == 2 && right == 2) + result += "-" HALF_DOUBLE_LINE_SEP; + } + } + else if (row_is_all_lines[end_row+1] == 2) { + if (left == 2 && right == 2) + result += "-" DOUBLE_LINE_SEP; + else if (left != 2 && right != 2 && (left == 1 || right == 1)) + result += "-" HALF_DOUBLE_LINE_SEP; + } +} + +void table::add_vertical_rule(int start_row, int end_row, int col, int is_double) +{ + vrule_list = new vertical_rule(start_row, end_row, col, is_double, + vrule_list); + compute_vrule_top_adjust(start_row, col, vrule_list->top_adjust); + compute_vrule_bot_adjust(end_row, col, vrule_list->bot_adjust); +} + +void table::build_vrule_list() +{ + int col; + if (flags & ALLBOX) { + for (col = 1; col < ncolumns; col++) { + int start_row = 0; + for (;;) { + while (start_row < nrows && vline_spanned(start_row, col)) + start_row++; + if (start_row >= nrows) + break; + int end_row = start_row; + while (end_row < nrows && !vline_spanned(end_row, col)) + end_row++; + end_row--; + add_vertical_rule(start_row, end_row, col, 0); + start_row = end_row + 1; + } + } + } + if (flags & (BOX|ALLBOX|DOUBLEBOX)) { + add_vertical_rule(0, nrows - 1, 0, 0); + add_vertical_rule(0, nrows - 1, ncolumns, 0); + } + for (int end_row = 0; end_row < nrows; end_row++) + for (col = 0; col < ncolumns+1; col++) + if (vline[end_row][col] > 0 + && !vline_spanned(end_row, col) + && (end_row == nrows - 1 + || vline[end_row+1][col] != vline[end_row][col] + || vline_spanned(end_row+1, col))) { + for (int start_row = end_row - 1; + start_row >= 0 + && vline[start_row][col] == vline[end_row][col] + && !vline_spanned(start_row, col); + start_row--) + ; + start_row++; + add_vertical_rule(start_row, end_row, col, vline[end_row][col] > 1); + } + for (vertical_rule *p = vrule_list; p; p = p->next) + if (p->is_double) + for (int r = p->start_row; r <= p->end_row; r++) { + if (p->col > 0 && entry[r][p->col-1] != 0 + && entry[r][p->col-1]->end_col == p->col-1) { + int is_corner = r == p->start_row || r == p->end_row; + entry[r][p->col-1]->note_double_vrule_on_right(is_corner); + } + if (p->col < ncolumns && entry[r][p->col] != 0 + && entry[r][p->col]->start_col == p->col) { + int is_corner = r == p->start_row || r == p->end_row; + entry[r][p->col]->note_double_vrule_on_left(is_corner); + } + } +} + +void table::define_bottom_macro() +{ + prints(".eo\n" + ".de T#\n" + ".if !\\n[" SUPPRESS_BOTTOM_REG "] \\{" + "." REPEATED_VPT_MACRO " 0\n" + ".mk " SAVED_VERTICAL_POS_REG "\n"); + if (flags & (BOX|ALLBOX|DOUBLEBOX)) { + prints(".if \\n[T.]&\\n[" NEED_BOTTOM_RULE_REG "] \\{"); + print_single_hline(0); + prints(".\\}\n"); + } + prints(".ls 1\n"); + for (vertical_rule *p = vrule_list; p; p = p->next) + p->contribute_to_bottom_macro(this); + if (flags & DOUBLEBOX) + prints(".if \\n[T.] \\{.vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n" + "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]" + "\\D'l \\n[TW]u 0'\\s0\n" + ".vs\n" + ".\\}\n" + ".if \\n[" LAST_PASSED_ROW_REG "]>=0 " + ".nr " TOP_REG " \\n[#T]-" DOUBLE_LINE_SEP "\n" + ".sp -1\n" + "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]" + "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n" + ".sp -1\n" + "\\v'" BODY_DEPTH "'\\h'|\\n[TW]u'\\s[\\n[" LINESIZE_REG "]]" + "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n"); + prints(".ls\n"); + prints(".nr " LAST_PASSED_ROW_REG " \\n[" CURRENT_ROW_REG "]\n" + ".sp |\\n[" SAVED_VERTICAL_POS_REG "]u\n" + "." REPEATED_VPT_MACRO " 1\n" + ".\\}\n" + "..\n" + ".ec\n"); +} + + +// is the vertical line before column c in row r horizontally spanned? + +int table::vline_spanned(int r, int c) +{ + assert(r >= 0 && r < nrows && c >= 0 && c < ncolumns + 1); + return (c != 0 && c != ncolumns && entry[r][c] != 0 + && entry[r][c]->start_col != c + // horizontally spanning lines don't count + && entry[r][c]->to_double_line_entry() == 0 + && entry[r][c]->to_single_line_entry() == 0); +} + +int table::row_begins_section(int r) +{ + assert(r >= 0 && r < nrows); + for (int i = 0; i < ncolumns; i++) + if (entry[r][i] && entry[r][i]->start_row != r) + return 0; + return 1; +} + +int table::row_ends_section(int r) +{ + assert(r >= 0 && r < nrows); + for (int i = 0; i < ncolumns; i++) + if (entry[r][i] && entry[r][i]->end_row != r) + return 0; + return 1; +} + +void table::do_row(int r) +{ + if (!(flags & NOKEEP) && row_begins_section(r)) + prints("." KEEP_MACRO_NAME "\n"); + int had_line = 0; + for (stuff *p = stuff_list; p && p->row < r; p = p->next) + ; + for (stuff *p1 = p; p1 && p1->row == r; p1 = p1->next) + if (!p1->printed && (p1->is_single_line() || p1->is_double_line())) { + had_line = 1; + break; + } + if (!had_line && !row_is_all_lines[r]) + printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); + had_line = 0; + for (; p && p->row == r; p = p->next) + if (!p->printed) { + p->print(this); + if (!had_line && (p->is_single_line() || p->is_double_line())) { + printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); + had_line = 1; + } + } + // Change the row *after* printing the stuff list (which might contain .TH). + printfs("\\*[" TRANSPARENT_STRING_NAME "].nr " CURRENT_ROW_REG " %1\n", + as_string(r)); + if (!had_line && row_is_all_lines[r]) + printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); + // we might have had a .TH, for example, since we last tried + if (!(flags & NOKEEP) && row_begins_section(r)) + prints("." KEEP_MACRO_NAME "\n"); + printfs(".mk %1\n", row_start_reg(r)); + prints(".mk " BOTTOM_REG "\n" + "." REPEATED_VPT_MACRO " 0\n"); + int c; + int row_is_blank = 1; + int first_start_row = r; + for (c = 0; c < ncolumns; c++) { + table_entry *e = entry[r][c]; + if (e) { + if (e->end_row == r) { + e->do_depth(); + if (e->start_row < first_start_row) + first_start_row = e->start_row; + row_is_blank = 0; + } + c = e->end_col; + } + } + if (row_is_blank) + prints(".nr " BOTTOM_REG " +1v\n"); + if (row_is_all_lines[r]) { + prints(".vs " LINE_SEP); + if (row_is_all_lines[r] == 2) + prints("+" DOUBLE_LINE_SEP); + prints(">?\\n[.V]u\n.ls 1\n"); + prints("\\&"); + prints("\\v'" BODY_DEPTH); + if (row_is_all_lines[r] == 2) + prints("-" HALF_DOUBLE_LINE_SEP); + prints("'"); + for (c = 0; c < ncolumns; c++) { + table_entry *e = entry[r][c]; + if (e) { + if (e->end_row == e->start_row) + e->to_simple_entry()->simple_print(1); + c = e->end_col; + } + } + prints("\n"); + prints(".ls\n" + ".vs\n"); + prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); + printfs(".sp |\\n[%1]u\n", row_start_reg(r)); + } + for (int i = row_is_all_lines[r] ? r - 1 : r; + i >= first_start_row; + i--) { + simple_entry *first = 0; + for (c = 0; c < ncolumns; c++) { + table_entry *e = entry[r][c]; + if (e) { + if (e->end_row == r && e->start_row == i) { + simple_entry *simple = e->to_simple_entry(); + if (simple) { + if (!first) { + prints(".ta"); + first = simple; + } + simple->add_tab(); + } + } + c = e->end_col; + } + } + if (first) { + prints('\n'); + first->position_vertically(); + first->set_location(); + prints("\\&"); + first->simple_print(0); + for (c = first->end_col + 1; c < ncolumns; c++) { + table_entry *e = entry[r][c]; + if (e) { + if (e->end_row == r && e->start_row == i) { + simple_entry *simple = e->to_simple_entry(); + if (simple) + simple->simple_print(0); + } + c = e->end_col; + } + } + prints('\n'); + prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); + printfs(".sp |\\n[%1]u\n", row_start_reg(r)); + } + } + for (c = 0; c < ncolumns; c++) { + table_entry *e = entry[r][c]; + if (e) { + if (e->end_row == r && e->to_simple_entry() == 0) { + e->position_vertically(); + e->print(); + prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); + printfs(".sp |\\n[%1]u\n", row_start_reg(r)); + } + c = e->end_col; + } + } + prints("." REPEATED_VPT_MACRO " 1\n" + ".sp |\\n[" BOTTOM_REG "]u\n" + "\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 1\n"); + if (r != nrows - 1 && (flags & ALLBOX)) { + print_single_hline(r + 1); + prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 0\n"); + } + if (r != nrows - 1) { + if (p && p->row == r + 1 + && (p->is_single_line() || p->is_double_line())) { + p->print(this); + prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG + " 0\n"); + } + int printed_one = 0; + for (vertical_rule *p = vrule_list; p; p = p->next) + if (p->end_row == r) { + if (!printed_one) { + prints("." REPEATED_VPT_MACRO " 0\n"); + printed_one = 1; + } + p->print(); + } + if (printed_one) + prints("." REPEATED_VPT_MACRO " 1\n"); + if (!(flags & NOKEEP) && row_ends_section(r)) + prints("." RELEASE_MACRO_NAME "\n"); + } +} + +void table::do_top() +{ + prints(".fc \002\003\n"); + if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX))) + prints("." TABLE_KEEP_MACRO_NAME "\n"); + if (flags & DOUBLEBOX) { + prints(".ls 1\n" + ".vs " LINE_SEP ">?\\n[.V]u\n" + "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]\\D'l \\n[TW]u 0'\\s0\n" + ".vs\n" + "." REPEATED_MARK_MACRO " " TOP_REG "\n" + ".vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n"); + printfs("\\v'" BODY_DEPTH "'" + "\\s[\\n[" LINESIZE_REG "]]" + "\\h'\\n[%1]u'" + "\\D'l |\\n[%2]u 0'" + "\\s0" + "\n", + column_divide_reg(0), + column_divide_reg(ncolumns)); + prints(".ls\n" + ".vs\n"); + } + else if (flags & (ALLBOX|BOX)) { + print_single_hline(0); + } + //printfs(".mk %1\n", row_top_reg(0)); +} + +void table::do_bottom() +{ + // print stuff after last row + for (stuff *p = stuff_list; p; p = p->next) + if (p->row > nrows - 1) + p->print(this); + if (!(flags & NOKEEP)) + prints("." RELEASE_MACRO_NAME "\n"); + printfs(".mk %1\n", row_top_reg(nrows)); + prints(".nr " NEED_BOTTOM_RULE_REG " 1\n" + ".nr T. 1\n" + ".T#\n"); + if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX))) + prints("." TABLE_RELEASE_MACRO_NAME "\n"); + if (flags & DOUBLEBOX) + prints(".sp " DOUBLE_LINE_SEP "\n"); + prints("." RESET_MACRO_NAME "\n" + ".fc\n" + ".cp \\n(" COMPATIBLE_REG "\n"); +} + +int table::get_nrows() +{ + return nrows; +} + +const char *last_filename = 0; + +void set_troff_location(const char *fn, int ln) +{ + if (!location_force_filename && last_filename != 0 + && strcmp(fn, last_filename) == 0) + printfs(".lf %1\n", as_string(ln)); + else { + printfs(".lf %1 %2\n", as_string(ln), fn); + last_filename = fn; + location_force_filename = 0; + } +} + +void printfs(const char *s, const string &arg1, const string &arg2, + const string &arg3, const string &arg4, const string &arg5) +{ + if (s) { + char c; + while ((c = *s++) != '\0') { + if (c == '%') { + switch (*s++) { + case '1': + prints(arg1); + break; + case '2': + prints(arg2); + break; + case '3': + prints(arg3); + break; + case '4': + prints(arg4); + break; + case '5': + prints(arg5); + break; + case '6': + case '7': + case '8': + case '9': + break; + case '%': + prints('%'); + break; + default: + assert(0); + } + } + else + prints(c); + } + } +} + diff --git a/gnu/usr.bin/groff/tbl/table.h b/gnu/usr.bin/groff/tbl/table.h new file mode 100644 index 0000000000..ae27545e2c --- /dev/null +++ b/gnu/usr.bin/groff/tbl/table.h @@ -0,0 +1,151 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +#include "cset.h" +#include "cmap.h" +#include "stringclass.h" +#include "errarg.h" +#include "error.h" +#include "lib.h" + +struct inc_number { + short inc; + short val; +}; + +struct entry_modifier { + inc_number point_size; + inc_number vertical_spacing; + string font; + enum { CENTER, TOP, BOTTOM } vertical_alignment; + char zero_width; + char stagger; + + entry_modifier(); + ~entry_modifier(); +}; + +enum format_type { + FORMAT_LEFT, + FORMAT_CENTER, + FORMAT_RIGHT, + FORMAT_NUMERIC, + FORMAT_ALPHABETIC, + FORMAT_SPAN, + FORMAT_VSPAN, + FORMAT_HLINE, + FORMAT_DOUBLE_HLINE +}; + +struct entry_format : entry_modifier { + format_type type; + + entry_format(format_type); + entry_format(); + void debug_print() const; +}; + +struct table_entry; +struct horizontal_span; +struct stuff; +struct vertical_rule; + +class table { + unsigned flags; + int nrows; + int ncolumns; + int linesize; + char delim[2]; + char decimal_point_char; + vertical_rule *vrule_list; + stuff *stuff_list; + horizontal_span *span_list; + table_entry *entry_list; + table_entry ***entry; + char **vline; + char *row_is_all_lines; + string *minimum_width; + int *column_separation; + char *equal; + int left_separation; + int right_separation; + int allocated_rows; + void build_span_list(); + void do_hspan(int r, int c); + void do_vspan(int r, int c); + void allocate(int r); + void compute_widths(); + void divide_span(int, int); + void sum_columns(int, int); + void compute_separation_factor(); + void compute_column_positions(); + void do_row(int); + void init_output(); + void add_stuff(stuff *); + void do_top(); + void do_bottom(); + void do_vertical_rules(); + void build_vrule_list(); + void add_vertical_rule(int, int, int, int); + void define_bottom_macro(); + int vline_spanned(int r, int c); + int row_begins_section(int); + int row_ends_section(int); + void make_columns_equal(); + void compute_vrule_top_adjust(int, int, string &); + void compute_vrule_bot_adjust(int, int, string &); + void determine_row_type(); +public: + /* used by flags */ + enum { + CENTER = 01, + EXPAND = 02, + BOX = 04, + ALLBOX = 010, + DOUBLEBOX = 020, + NOKEEP = 040 + }; + table(int nc, unsigned flags, int linesize, char decimal_point_char); + ~table(); + + void add_text_line(int r, const string &, const char *, int); + void add_single_hline(int r); + void add_double_hline(int r); + void add_entry(int r, int c, const string &, const entry_format *, + const char *, int lineno); + void add_vlines(int r, const char *); + void check(); + void print(); + void set_minimum_width(int c, const string &w); + void set_column_separation(int c, int n); + void set_equal_column(int c); + void set_delim(char c1, char c2); + void print_single_hline(int r); + void print_double_hline(int r); + int get_nrows(); +}; + +void set_troff_location(const char *, int); diff --git a/gnu/usr.bin/groff/tbl/tbl.1 b/gnu/usr.bin/groff/tbl/tbl.1 new file mode 100644 index 0000000000..de72a767ab --- /dev/null +++ b/gnu/usr.bin/groff/tbl/tbl.1 @@ -0,0 +1,143 @@ +.\" -*- nroff -*- +.TH TBL 1 "1 April 1993" "Groff Version 1.08" +.SH NAME +tbl \- format tables for troff +.SH SYNOPSIS +.B tbl +[ +.B \-Cv +] +[ +.IR files \|.\|.\|. +] +.SH DESCRIPTION +This manual page describes the GNU version of +.BR tbl , +which is part of the groff document formatting system. +.B tbl +compiles descriptions of tables embedded within +.B troff +input files into commands that are understood by +.BR troff . +Normally, it should be invoked using the +.B \-t +option of +.B groff. +It is highly compatible with Unix +.BR tbl . +The output generated by GNU +.B tbl +cannot be processed with Unix +.BR troff ; +it must be processed with GNU +.BR troff . +If no files are given on the command line, the standard input +will be read. +A filename of +.B \- +will cause the standard input to be read. +.SH OPTIONS +.TP +.B \-C +Recognize +.B .TS +and +.B .TE +even when followed by a character other than space or newline. +.TP +.B \-v +Print the version number. +.SH USAGE +Only the differences between GNU +.B tbl +and Unix +.B tbl +are described here. +.LP +Normally +.B tbl +attempts to prevent undesirable breaks in the table by using diversions. +This can sometimes interact badly with macro packages' own use of diversions, +when footnotes, for example, are used. +The +.B nokeep +option tells +.B tbl +not to try and prevent breaks in this way. +.LP +The +.B decimalpoint +option specifies the character to be recognized as the decimal +point character in place of the default period. +It takes an argument in parentheses, which must be a single +character, as for the +.B tab +option. +.LP +The +.B f +format modifier can be followed by an arbitrary length +font name in parentheses. +.LP +There is a +.B d +format modifier which means that a vertically spanning entry +should be aligned at the bottom of its range. +.LP +There is no limit on the number of columns in a table, nor any limit +on the number of text blocks. +All the lines of a table are considered in deciding column +widths, not just the first 200. +Table continuation +.RB ( .T& ) +lines are not restricted to the first 200 lines. +.LP +Numeric and alphabetic items may appear in the same column. +.LP +Numeric and alphabetic items may span horizontally. +.LP +.B tbl +uses register, string, macro and diversion names beginning with +.BR 3 . +When using +.B tbl +you should avoid using any names beginning with a +.BR 3 . +.SH BUGS +You should use +.BR .TS\ H / .TH +in conjunction with a supporting macro package for +.I all +multi-page boxed tables. +If there is no header that you wish to appear at the top of each page +of the table, place the +.B .TH +line immediately after the format section. +Do not enclose a multi-page table within keep/release macros, +or divert it in any other way. +.LP +A text block within a table must be able to fit on one page. +.LP +The +.B bp +request cannot be used to force a page-break in a multi-page table. +Instead, define +.B BP +as follows +.IP +.B .de BP +.br +.B .ie '\e\en(.z'' .bp \e\e$1 +.br +.B .el \e!.BP \e\e$1 +.br +.B .. +.br +.LP +and use +.B BP +instead of +.BR bp . +.SH "SEE ALSO" +.BR groff (1), +.BR troff (1) diff --git a/gnu/usr.bin/groff/tfmtodit/Makefile b/gnu/usr.bin/groff/tfmtodit/Makefile new file mode 100644 index 0000000000..4c4e8c8673 --- /dev/null +++ b/gnu/usr.bin/groff/tfmtodit/Makefile @@ -0,0 +1,12 @@ +# Makefile for tfmtodit + +PROG= tfmtodit +SRCS= tfmtodit.cc +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBGROFF) -lm +DPADD+= $(LIBGROFF) $(LIBMATH) + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/tfmtodit/Makefile.dep b/gnu/usr.bin/groff/tfmtodit/Makefile.dep new file mode 100644 index 0000000000..9e1b9f56c3 --- /dev/null +++ b/gnu/usr.bin/groff/tfmtodit/Makefile.dep @@ -0,0 +1,2 @@ +tfmtodit.o : tfmtodit.cc ../include/lib.h ../include/errarg.h \ + ../include/error.h ../include/assert.h ../include/cset.h diff --git a/gnu/usr.bin/groff/tfmtodit/tfmtodit.1 b/gnu/usr.bin/groff/tfmtodit/tfmtodit.1 new file mode 100644 index 0000000000..248f595034 --- /dev/null +++ b/gnu/usr.bin/groff/tfmtodit/tfmtodit.1 @@ -0,0 +1,150 @@ +.\" -*- nroff -*- +.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X +.el .ds tx TeX +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH TFMTODIT 1 "6 August 1992" "Groff Version 1.08" +.SH NAME +tfmtodit \- create font files for use with groff \-Tdvi +.SH SYNOPSIS +.B tfmtodit +[ +.B \-sv +] +[ +.BI \-g gf_file +] +[ +.BI \-k skewchar +] +.I tfm_file +.I map_file +.I font +.SH DESCRIPTION +.B tfmtodit +creates a font file for use with +.B +groff \-Tdvi\fR. +.I tfm_file +is the name of the \*(tx font metric file for the font. +.I map_file +is a file giving the groff names for characters in the font; +this file should consist of a sequence of lines of the form: +.IP +.I +n c1 c2 \fR.\|.\|. +.LP +where +.I n +is a decimal integer giving the position of the character in the font, +and +.IR c1 , +.IR c2 ,.\|.\|. +are the groff names of the character. +If a character has no groff names but exists in the tfm file, +then it will be put in the groff font file as an unnamed character. +.I font +is the name of the groff font file. +The groff font file is written to +.IR font . +.LP +The +.B \-s +option should be given if the font is special +(a font is +.I special +if +.B troff +should search it whenever +a character is not found in the current font.) +If the font is special, +it should be listed in the +.B fonts +command in the DESC file; +if it is not special, there is no need to list it, since +.B troff +can automatically mount it when it's first used. +.LP +To do a good job of math typesetting, groff requires +font metric information not present in the tfm file. +The reason for this is that \*(tx has separate math italic fonts +whereas groff uses normal italic fonts for math. +The additional information required by groff is given by the +two arguments to the +.B math_fit +macro in the Metafont programs for the Computer Modern fonts. +In a text font (a font for which +.B math_fitting +is false), Metafont normally ignores these two arguments. +Metafont can be made to put this information in the gf file +by loading the following definition after +.B cmbase +when creating +.BR cm.base : +.IP +.nf +.ft B +def ignore_math_fit(expr left_adjustment,right_adjustment) = + special "adjustment"; + numspecial left_adjustment*16/designsize; + numspecial right_adjustment*16/designsize; + enddef; +.fi +.ft R +.LP +The gf file created using this modified +.B cm.base +should be specified with the +.B \-g +option. +The +.B \-g +option should not be given for a font for which +.B math_fitting +is true. +.SH OPTIONS +.TP +.B \-v +Print the version number. +.TP +.B \-s +The font is special. +The effect of this option is to add the +.B special +command to the font file. +.TP +.BI \-k n +The skewchar of this font is at position +.IR n . +.I n +should be an integer; +it may be given in decimal, +or with a leading +.B 0 +in octal, +or with a leading +.B 0x +in hexadecimal. +The effect of this option is to ignore any kerns whose second component +is the specified character. +.TP +.BI \-g gf_file +.I gf_file +is a gf file produced by Metafont containing special and numspecial +commands giving additional font metric information. +.SH FILES +.Tp \w'\fB/usr/share/groff_font/devdvi/DESC'u+2n +.B /usr/share/groff_font/devdvi/DESC +Device desciption file. +.TP +.BI /usr/share/groff_font/devdvi/ F +Font description file for font +.IR F . +.SH "SEE ALSO" +.BR groff (1), +.BR grodvi (1), +.BR groff_font (5) diff --git a/gnu/usr.bin/groff/tfmtodit/tfmtodit.cc b/gnu/usr.bin/groff/tfmtodit/tfmtodit.cc new file mode 100644 index 0000000000..851735d163 --- /dev/null +++ b/gnu/usr.bin/groff/tfmtodit/tfmtodit.cc @@ -0,0 +1,850 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* I have tried to incorporate the changes needed for TeX 3.0 tfm files, +but I haven't tested them. */ + +/* Groff requires more font metric information than TeX. The reason +for this is that TeX has separate Math Italic fonts, whereas groff +uses normal italic fonts for math. The two additional pieces of +information required by groff correspond to the two arguments to the +math_fit() macro in the Metafont programs for the CM fonts. In the +case of a font for which math_fitting is false, these two arguments +are normally ignored by Metafont. We need to get hold of these two +parameters and put them in the groff font file. + +We do this by loading this definition after cmbase when creating cm.base. + +def ignore_math_fit(expr left_adjustment,right_adjustment) = + special "adjustment"; + numspecial left_adjustment*16/designsize; + numspecial right_adjustment*16/designsize; + enddef; + +This puts the two arguments to the math_fit macro into the gf file. +(They will appear in the gf file immediately before the character to +which they apply.) We then create a gf file using this cm.base. Then +we run tfmtodit and specify this gf file with the -g option. + +This need only be done for a font for which math_fitting is false; +When it's true, the left_correction and subscript_correction should +both be zero. */ + +#include +#include +#include +#include +#include +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "assert.h" +#include "cset.h" + +/* Values in the tfm file should be multiplied by this. */ + +#define MULTIPLIER 1 + +struct char_info_word { + unsigned char width_index; + char height_index; + char depth_index; + char italic_index; + char tag; + unsigned char remainder; +}; + +struct lig_kern_command { + unsigned char skip_byte; + unsigned char next_char; + unsigned char op_byte; + unsigned char remainder; +}; + +class tfm { + int bc; + int ec; + int nw; + int nh; + int nd; + int ni; + int nl; + int nk; + int np; + int cs; + int ds; + char_info_word *char_info; + int *width; + int *height; + int *depth; + int *italic; + lig_kern_command *lig_kern; + int *kern; + int *param; +public: + tfm(); + ~tfm(); + int load(const char *); + int contains(int); + int get_width(int); + int get_height(int); + int get_depth(int); + int get_italic(int); + int get_param(int, int *); + int get_checksum(); + int get_design_size(); + int get_lig(unsigned char, unsigned char, unsigned char *); + friend class kern_iterator; +}; + +class kern_iterator { + tfm *t; + int c; + int i; +public: + kern_iterator(tfm *); + int next(unsigned char *c1, unsigned char *c2, int *k); +}; + + +kern_iterator::kern_iterator(tfm *p) +: t(p), i(-1), c(t->bc) +{ +} + +int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k) +{ + for (; c <= t->ec; c++) + if (t->char_info[c - t->bc].tag == 1) { + if (i < 0) { + i = t->char_info[c - t->bc].remainder; + if (t->lig_kern[i].skip_byte > 128) + i = (256*t->lig_kern[i].op_byte + + t->lig_kern[i].remainder); + } + for (;;) { + int skip = t->lig_kern[i].skip_byte; + if (skip <= 128 && t->lig_kern[i].op_byte >= 128) { + *c1 = c; + *c2 = t->lig_kern[i].next_char; + *k = t->kern[256*(t->lig_kern[i].op_byte - 128) + + t->lig_kern[i].remainder]; + if (skip == 128) { + c++; + i = -1; + } + else + i += skip + 1; + return 1; + } + if (skip >= 128) + break; + i += skip + 1; + } + i = -1; + } + return 0; +} + +tfm::tfm() +: char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0), + kern(0), param(0) +{ +} + +int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp) +{ + if (contains(c1) && char_info[c1 - bc].tag == 1) { + int i = char_info[c1 - bc].remainder; + if (lig_kern[i].skip_byte > 128) + i = 256*lig_kern[i].op_byte + lig_kern[i].remainder; + for (;;) { + int skip = lig_kern[i].skip_byte; + if (skip > 128) + break; + // We are only interested in normal ligatures, for which + // op_byte == 0. + if (lig_kern[i].op_byte == 0 + && lig_kern[i].next_char == c2) { + *cp = lig_kern[i].remainder; + return 1; + } + if (skip == 128) + break; + i += skip + 1; + } + } + return 0; +} + +int tfm::contains(int i) +{ + return i >= bc && i <= ec && char_info[i - bc].width_index != 0; +} + +int tfm::get_width(int i) +{ + return width[char_info[i - bc].width_index]; +} + +int tfm::get_height(int i) +{ + return height[char_info[i - bc].height_index]; +} + +int tfm::get_depth(int i) +{ + return depth[char_info[i - bc].depth_index]; +} + +int tfm::get_italic(int i) +{ + return italic[char_info[i - bc].italic_index]; +} + +int tfm::get_param(int i, int *p) +{ + if (i <= 0 || i > np) + return 0; + else { + *p = param[i - 1]; + return 1; + } +} + +int tfm::get_checksum() +{ + return cs; +} + +int tfm::get_design_size() +{ + return ds; +} + +tfm::~tfm() +{ + a_delete char_info; + a_delete width; + a_delete height; + a_delete depth; + a_delete italic; + a_delete lig_kern; + a_delete kern; + a_delete param; +} + +int read2(unsigned char *&s) +{ + int n; + n = *s++ << 8; + n |= *s++; + return n; +} + +int read4(unsigned char *&s) +{ + int n; + n = *s++ << 24; + n |= *s++ << 16; + n |= *s++ << 8; + n |= *s++; + return n; +} + + +int tfm::load(const char *file) +{ + errno = 0; + FILE *fp = fopen(file, "r"); + if (!fp) { + error("can't open `%1': %2", file, strerror(errno)); + return 0; + } + int c1 = getc(fp); + int c2 = getc(fp); + if (c1 == EOF || c2 == EOF) { + fclose(fp); + error("unexpected end of file on `%1'", file); + return 0; + } + int lf = (c1 << 8) + c2; + int toread = lf*4 - 2; + unsigned char *buf = new unsigned char[toread]; + if (fread(buf, 1, toread, fp) != toread) { + if (feof(fp)) + error("unexpected end of file on `%1'", file); + else + error("error on file `%1'", file); + a_delete buf; + fclose(fp); + return 0; + } + fclose(fp); + if (lf < 6) { + error("bad tfm file `%1': impossibly short", file); + a_delete buf; + return 0; + } + unsigned char *ptr = buf; + int lh = read2(ptr); + bc = read2(ptr); + ec = read2(ptr); + nw = read2(ptr); + nh = read2(ptr); + nd = read2(ptr); + ni = read2(ptr); + nl = read2(ptr); + nk = read2(ptr); + int ne = read2(ptr); + np = read2(ptr); + if (6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np != lf) { + error("bad tfm file `%1': lengths do not sum", file); + a_delete buf; + return 0; + } + if (lh < 2) { + error("bad tfm file `%1': header too short", file); + a_delete buf; + return 0; + } + char_info = new char_info_word[ec - bc + 1]; + width = new int[nw]; + height = new int[nh]; + depth = new int[nd]; + italic = new int[ni]; + lig_kern = new lig_kern_command[nl]; + kern = new int[nk]; + param = new int[np]; + int i; + cs = read4(ptr); + ds = read4(ptr); + ptr += (lh-2)*4; + for (i = 0; i < ec - bc + 1; i++) { + char_info[i].width_index = *ptr++; + unsigned char tem = *ptr++; + char_info[i].depth_index = tem & 0xf; + char_info[i].height_index = tem >> 4; + tem = *ptr++; + char_info[i].italic_index = tem >> 2; + char_info[i].tag = tem & 3; + char_info[i].remainder = *ptr++; + } + for (i = 0; i < nw; i++) + width[i] = read4(ptr); + for (i = 0; i < nh; i++) + height[i] = read4(ptr); + for (i = 0; i < nd; i++) + depth[i] = read4(ptr); + for (i = 0; i < ni; i++) + italic[i] = read4(ptr); + for (i = 0; i < nl; i++) { + lig_kern[i].skip_byte = *ptr++; + lig_kern[i].next_char = *ptr++; + lig_kern[i].op_byte = *ptr++; + lig_kern[i].remainder = *ptr++; + } + for (i = 0; i < nk; i++) + kern[i] = read4(ptr); + ptr += ne*4; + for (i = 0; i < np; i++) + param[i] = read4(ptr); + assert(ptr == buf + lf*4 - 2); + a_delete buf; + return 1; +} + +class gf { + int left[256]; + int right[256]; + static int sread4(int *p, FILE *fp); + static int uread3(int *p, FILE *fp); + static int uread2(int *p, FILE *fp); + static int skip(int n, FILE *fp); +public: + gf(); + int load(const char *file); + int get_left_adjustment(int i) { return left[i]; } + int get_right_adjustment(int i) { return right[i]; } +}; + +gf::gf() +{ + for (int i = 0; i < 256; i++) + left[i] = right[i] = 0; +} + +int gf::load(const char *file) +{ + enum { + paint_0 = 0, + paint1 = 64, + boc = 67, + boc1 = 68, + eoc = 69, + skip0 = 70, + skip1 = 71, + new_row_0 = 74, + xxx1 = 239, + yyy = 243, + no_op = 244, + pre = 247, + post = 248 + }; + int got_an_adjustment = 0; + int pending_adjustment = 0; + int left_adj, right_adj; + const int gf_id_byte = 131; + errno = 0; + FILE *fp = fopen(file, "r"); + if (!fp) { + error("can't open `%1': %2", file, strerror(errno)); + return 0; + } + if (getc(fp) != pre || getc(fp) != gf_id_byte) { + error("bad gf file"); + return 0; + } + int n = getc(fp); + if (n == EOF) + goto eof; + if (!skip(n, fp)) + goto eof; + for (;;) { + int op = getc(fp); + if (op == EOF) + goto eof; + if (op == post) + break; + if ((op >= paint_0 && op <= paint_0 + 63) + || (op >= new_row_0 && op <= new_row_0 + 164)) + continue; + switch (op) { + case no_op: + case eoc: + case skip0: + break; + case paint1: + case skip1: + if (!skip(1, fp)) + goto eof; + break; + case paint1 + 1: + case skip1 + 1: + if (!skip(2, fp)) + goto eof; + break; + case paint1 + 2: + case skip1 + 2: + if (!skip(3, fp)) + goto eof; + break; + case boc: + { + int code; + if (!sread4(&code, fp)) + goto eof; + if (pending_adjustment) { + pending_adjustment = 0; + left[code & 0377] = left_adj; + right[code & 0377] = right_adj; + } + if (!skip(20, fp)) + goto eof; + break; + } + case boc1: + { + int code = getc(fp); + if (code == EOF) + goto eof; + if (pending_adjustment) { + pending_adjustment = 0; + left[code] = left_adj; + right[code] = right_adj; + } + if (!skip(4, fp)) + goto eof; + break; + } + case xxx1: + { + int len = getc(fp); + if (len == EOF) + goto eof; + char buf[256]; + if (fread(buf, 1, len, fp) != len) + goto eof; + if (len == 10 /* strlen("adjustment") */ + && memcmp(buf, "adjustment", len) == 0) { + int c = getc(fp); + if (c != yyy) { + if (c != EOF) + ungetc(c, fp); + break; + } + if (!sread4(&left_adj, fp)) + goto eof; + c = getc(fp); + if (c != yyy) { + if (c != EOF) + ungetc(c, fp); + break; + } + if (!sread4(&right_adj, fp)) + goto eof; + got_an_adjustment = 1; + pending_adjustment = 1; + } + break; + } + case xxx1 + 1: + if (!uread2(&n, fp) || !skip(n, fp)) + goto eof; + break; + case xxx1 + 2: + if (!uread3(&n, fp) || !skip(n, fp)) + goto eof; + break; + case xxx1 + 3: + if (!sread4(&n, fp) || !skip(n, fp)) + goto eof; + break; + case yyy: + if (!skip(4, fp)) + goto eof; + break; + default: + fatal("unrecognized opcode `%1'", op); + break; + } + } + if (!got_an_adjustment) + warning("no adjustment specials found in gf file"); + return 1; + eof: + error("unexpected end of file"); + return 0; +} + +int gf::sread4(int *p, FILE *fp) +{ + *p = getc(fp); + if (*p >= 128) + *p -= 256; + *p <<= 8; + *p |= getc(fp); + *p <<= 8; + *p |= getc(fp); + *p <<= 8; + *p |= getc(fp); + return !ferror(fp) && !feof(fp); +} + +int gf::uread3(int *p, FILE *fp) +{ + *p = getc(fp); + *p <<= 8; + *p |= getc(fp); + *p <<= 8; + *p |= getc(fp); + return !ferror(fp) && !feof(fp); +} + +int gf::uread2(int *p, FILE *fp) +{ + *p = getc(fp); + *p <<= 8; + *p |= getc(fp); + return !ferror(fp) && !feof(fp); +} + +int gf::skip(int n, FILE *fp) +{ + while (--n >= 0) + if (getc(fp) == EOF) + return 0; + return 1; +} + + +struct char_list { + char *ch; + char_list *next; + char_list(const char *, char_list * = 0); +}; + +char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p) +{ +} + + +int read_map(const char *file, char_list **table) +{ + errno = 0; + FILE *fp = fopen(file, "r"); + if (!fp) { + error("can't open `%1': %2", file, strerror(errno)); + return 0; + } + for (int i = 0; i < 256; i++) + table[i] = 0; + char buf[512]; + int lineno = 0; + while (fgets(buf, int(sizeof(buf)), fp)) { + lineno++; + char *ptr = buf; + while (csspace(*ptr)) + ptr++; + if (*ptr == '\0' || *ptr == '#') + continue; + ptr = strtok(ptr, " \n\t"); + if (!ptr) + continue; + int n; + if (sscanf(ptr, "%d", &n) != 1) { + error("%1:%2: bad map file", file, lineno); + fclose(fp); + return 0; + } + if (n < 0 || n > 255) { + error("%1:%2: code out of range", file, lineno); + fclose(fp); + return 0; + } + ptr = strtok(0, " \n\t"); + if (!ptr) { + error("%1:%2: missing names", file, lineno); + fclose(fp); + return 0; + } + for (; ptr; ptr = strtok(0, " \n\t")) + table[n] = new char_list(ptr, table[n]); + } + fclose(fp); + return 1; +} + + +/* Every character that can participate in a ligature appears in the +lig_chars table. `ch' gives the full-name of the character, `name' +gives the groff name of the character, `i' gives its index in +the encoding, which is filled in later (-1 if it does not appear). */ + +struct { + const char *ch; + int i; +} lig_chars[] = { + "f", -1, + "i", -1, + "l", -1, + "ff", -1, + "fi", -1, + "fl", -1, + "Fi", -1, + "Fl", -1, +}; + +// Indices into lig_chars[]. + +enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl }; + +// Each possible ligature appears in this table. + +struct { + unsigned char c1, c2, res; + const char *ch; +} lig_table[] = { + CH_f, CH_f, CH_ff, "ff", + CH_f, CH_i, CH_fi, "fi", + CH_f, CH_l, CH_fl, "fl", + CH_ff, CH_i, CH_ffi, "ffi", + CH_ff, CH_l, CH_ffl, "ffl", + }; + +static void usage(); + +int main(int argc, char **argv) +{ + program_name = argv[0]; + int special_flag = 0; + int skewchar = -1; + int opt; + const char *gf_file = 0; + while ((opt = getopt(argc, argv, "svg:k:")) != EOF) + switch (opt) { + case 'g': + gf_file = optarg; + break; + case 's': + special_flag = 1; + break; + case 'k': + { + char *ptr; + long n = strtol(optarg, &ptr, 0); + if ((n == 0 && ptr == optarg) + || *ptr != '\0' + || n < 0 + || n > UCHAR_MAX) + error("invalid skewchar"); + else + skewchar = (int)n; + break; + } + case 'v': + { + extern const char *version_string; + fprintf(stderr, "tfmtodit version %s\n", version_string); + fflush(stderr); + break; + } + case '?': + usage(); + break; + case EOF: + assert(0); + } + if (argc - optind != 3) + usage(); + gf g; + if (gf_file) { + if (!g.load(gf_file)) + return 1; + } + const char *tfm_file = argv[optind]; + const char *map_file = argv[optind + 1]; + const char *font_file = argv[optind + 2]; + tfm t; + if (!t.load(tfm_file)) + return 1; + char_list *table[256]; + if (!read_map(map_file, table)) + return 1; + errno = 0; + if (!freopen(font_file, "w", stdout)) { + error("can't open `%1' for writing: %2", font_file, strerror(errno)); + return 1; + } + printf("name %s\n", font_file); + if (special_flag) + fputs("special\n", stdout); + char *internal_name = strsave(argv[optind]); + int len = strlen(internal_name); + if (len > 4 && strcmp(internal_name + len - 4, ".tfm") == 0) + internal_name[len - 4] = '\0'; + char *s = strrchr(internal_name, '/'); + printf("internalname %s\n", s ? s + 1 : internal_name); + int n; + if (t.get_param(2, &n)) { + if (n > 0) + printf("spacewidth %d\n", n*MULTIPLIER); + } + if (t.get_param(1, &n) && n != 0) + printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/M_PI); + int xheight; + if (!t.get_param(5, &xheight)) + xheight = 0; + int i; + // Print the list of ligatures. + // First find the indices of each character that can participate in + // a ligature. + for (i = 0; i < 256; i++) + for (int j = 0; j < sizeof(lig_chars)/sizeof(lig_chars[0]); j++) + for (char_list *p = table[i]; p; p = p->next) + if (strcmp(lig_chars[j].ch, p->ch) == 0) + lig_chars[j].i = i; + // For each possible ligature, if its participants all exist, + // and it appears as a ligature in the tfm file, include in + // the list of ligatures. + int started = 0; + for (i = 0; i < sizeof(lig_table)/sizeof(lig_table[0]); i++) { + int i1 = lig_chars[lig_table[i].c1].i; + int i2 = lig_chars[lig_table[i].c2].i; + int r = lig_chars[lig_table[i].res].i; + if (i1 >= 0 && i2 >= 0 && r >= 0) { + unsigned char c; + if (t.get_lig(i1, i2, &c) && c == r) { + if (!started) { + started = 1; + fputs("ligatures", stdout); + } + printf(" %s", lig_table[i].ch); + } + } + } + if (started) + fputs(" 0\n", stdout); + printf("checksum %d\n", t.get_checksum()); + printf("designsize %d\n", t.get_design_size()); + // Now print out the kerning information. + int had_kern = 0; + kern_iterator iter(&t); + unsigned char c1, c2; + int k; + while (iter.next(&c1, &c2, &k)) + if (c2 != skewchar) { + k *= MULTIPLIER; + char_list *q = table[c2]; + for (char_list *p1 = table[c1]; p1; p1 = p1->next) + for (char_list *p2 = q; p2; p2 = p2->next) { + if (!had_kern) { + printf("kernpairs\n"); + had_kern = 1; + } + printf("%s %s %d\n", p1->ch, p2->ch, k); + } + } + printf("charset\n"); + char_list unnamed("---"); + for (i = 0; i < 256; i++) + if (t.contains(i)) { + char_list *p = table[i] ? table[i] : &unnamed; + int m[6]; + m[0] = t.get_width(i); + m[1] = t.get_height(i); + m[2] = t.get_depth(i); + m[3] = t.get_italic(i); + m[4] = g.get_left_adjustment(i); + m[5] = g.get_right_adjustment(i); + printf("%s\t%d", p->ch, m[0]*MULTIPLIER); + for (int j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--) + if (m[j] != 0) + break; + for (int k = 1; k <= j; k++) + printf(",%d", m[k]*MULTIPLIER); + int type = 0; + if (m[2] > 0) + type = 1; + if (m[1] > xheight) + type += 2; + printf("\t%d\t%04o\n", type, i); + for (p = p->next; p; p = p->next) + printf("%s\t\"\n", p->ch); + } + return 0; +} + +static void usage() +{ + fprintf(stderr, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n", + program_name); + exit(1); +} diff --git a/gnu/usr.bin/groff/tmac/Makefile b/gnu/usr.bin/groff/tmac/Makefile new file mode 100644 index 0000000000..eac75f94ea --- /dev/null +++ b/gnu/usr.bin/groff/tmac/Makefile @@ -0,0 +1,26 @@ +# Makefile for groff macros + +TMACOWN?= bin +TMACGRP?= bin +TMACMODE?= 444 +TMACDIR?= /usr/share/tmac + +MAN7= groff_ms.0 +MLINKS= groff_ms.7 ms.7 + +FILES= tmac.pic tmac.ps tmac.psnew tmac.psold tmac.pspic tmac.psatk\ + tmac.dvi tmac.tty tmac.tty-char tmac.X tmac.Xps tmac.latin1\ + man.local eqnrc troffrc + +afterinstall: + for f in ${FILES}; do \ + install -c -o ${TMACOWN} -g ${TMACGRP} -m ${TMACMODE} \ + ${.CURDIR}/$$f ${DESTDIR}${TMACDIR}; \ + done + install -c -o ${TMACOWN} -g ${TMACGRP} -m ${TMACMODE} \ + ${.CURDIR}/tmac.s ${DESTDIR}${TMACDIR}/tmac.${tmac_s} + install -c -o ${TMACOWN} -g ${TMACGRP} -m ${TMACMODE} \ + ${.CURDIR}/tmac.an ${DESTDIR}${TMACDIR}/tmac.an.old + +.include +.include "../Makefile.cfg" diff --git a/gnu/usr.bin/groff/tmac/TODO b/gnu/usr.bin/groff/tmac/TODO new file mode 100644 index 0000000000..5213fc274c --- /dev/null +++ b/gnu/usr.bin/groff/tmac/TODO @@ -0,0 +1,38 @@ +Support multiple line-spacing. + +Improve the device independence of the character definitions. + +If we have footnotes in the abstract in RP format, then the footnote +will appear on the cover sheet, which it should, but also on the first +page, which it should not. + +Should we allow multi-page cover-sheets? + +Warn about automatically numbered footnotes in floating keeps. + +When we bring back the footnote overflow at the top of page, it would +be more efficient to avoid diverting it again. (Need to keep track of +footnote height.) + +Possibly have a place above which the footnote trap must not be +placed. + +Improved indexing, not using tm, controlled by string variable (eg +-dIDX=file.idx). + +When changing from multi-column to narrower columns, we could avoid +doing a @super-eject. (This might not be a good idea.) + +Think about cutmarks. Possibly implement CM. + +Implement thesis Mode (TM, CT). + +Implement more V10 features. + +Should this + +.LP +.rs +.sp \n(.tu + +print two pages? diff --git a/gnu/usr.bin/groff/tmac/eqnrc b/gnu/usr.bin/groff/tmac/eqnrc new file mode 100644 index 0000000000..eab720cf34 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/eqnrc @@ -0,0 +1,60 @@ +.\" Startup file for eqn. +.EQ +sdefine << %{ < back 20 < }% +sdefine >> %{ > back 20 > }% + +sdefine dot %accent "\fR\(a.\fP"% +sdefine dotdot %accent "\fR\(ad\fP"% +sdefine vec %accent {up 52 "\s[\En[.s]/2u]\(->\s0"}% +sdefine dyad %accent {up 52 "\s[\En[.s]/2u]\(<>\s0"}% + +sdefine cdot %type "binary" \(md% + +ifdef X75 ! define X %1% ! +ifdef X100 ! define X %1% ! +ifdef X75-12 ! define X %1% ! +ifdef X100-12 ! define X %1% ! + +ifdef ps ! define ps|X %1% ! +ifdef X ! define ps|X %1% ! + +ifdef ps|X ! sdefine inf %"\s[\En[.s]*13u/10u]\v'12M'\(if\v'-12M'\s0"% ! + +ifdef dvi ! +sdefine int %{type "operator" vcenter \(is}% +sdefine sum %{type "operator" vcenter \[sum]}% +sdefine prod %{type "operator" vcenter \[product]}% +sdefine coprod %{type "operator" vcenter \[coproduct]}% +set num1 68 +set num2 39 +set denom1 69 +set denom2 34 +set sup1 41 +set sup2 36 +set sup3 29 +set sup_drop 39 +set sub_drop 5 +set axis_height 25 +set x_height 43 +set default_rule_thickness 4 +set big_op_spacing1 11 +set big_op_spacing2 16 +set big_op_spacing3 20 +set big_op_spacing4 60 +set big_op_spacing5 10 +! + +ifdef X ! set axis_height 32 ! + +ifdef ps|X ! set draw_lines 1 ! + +ifdef ascii ! define n %1% ! +ifdef latin1 ! define n %1% ! +ifdef n ! +set nroff 1 +! + +undef X +undef ps|X +undef n +.EN diff --git a/gnu/usr.bin/groff/tmac/groff_ms.7 b/gnu/usr.bin/groff/tmac/groff_ms.7 new file mode 100644 index 0000000000..a2aacb80e4 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/groff_ms.7 @@ -0,0 +1,210 @@ +.\" -*- nroff -*- +.TH GROFF_MS 7 "6 August 1992" "Groff Version 1.08" +.SH NAME +groff_ms \- groff ms macros +.SH SYNOPSIS +.B groff +.B \-ms +[ +.IR options .\|.\|. +] +[ +.IR files .\|.\|. +] +.SH DESCRIPTION +This manual page describes the GNU version of the ms macros, +which is part of the groff document formatting system. +The groff ms macros are intended to be compatible with the 4.3 +.SM BSD +Unix ms macros subject to the following limitations: +.IP \(bu +the internals of groff ms are not similar to the internals of Unix ms +and so documents that depend upon implementation details of Unix ms +may well not work with groff ms; +.IP \(bu +there is no support for typewriter-like devices; +.IP \(bu +Berkeley localisms, in particular the +.B TM +and +.B CT +macros, are not implemented; +.IP \(bu +groff ms +does not provide cut marks; +.IP \(bu +multiple line spacing is not allowed +(use a larger vertical spacing instead); +.IP \(bu +groff ms does not work in compatibility mode (eg with the +.B \-C +option); +.IP \(bu +the error-handling policy of groff ms +is to detect and report errors, +rather than silently to ignore them. +.LP +The groff ms macros make use of many features of GNU troff +and therefore cannot be used with any other troff. +.LP +Bell Labs localisms are not implemented in either the +.SM BSD +ms macros or in the groff ms macros. +.LP +Some Unix ms documentation says that the +.B CW +and +.B GW +number registers can be used to control the column width and +gutter width respectively. +This is not the case. +These number registers are not used in groff ms. +.LP +Macros that cause a reset set the indent. +Macros that change the indent do not increment or decrement +the indent, but rather set it absolutely. +This can cause problems for documents that define +additional macros of their own. +The solution is to use not the +.B in +request but instead the +.B RS +and +.B RE +macros. +.LP +The number register +.B GS +is set to 1 by the groff ms macros, +but is not used by the Unix ms macros. +It is intended that documents that need to determine whether +they are being formatted with Unix ms or groff ms make use of this +number register. +.LP +Footnotes are implemented so that they can safely be used within +keeps and displays. +Automatically numbered footnotes within floating keeps are +not recommended. +It is safe to have another +.B \e** +between a +.B \e** +and the corresponding +.BR .FS ; +it is required only that each +.B .FS +occur after the corresponding +.B \e** +and that the occurrences of +.B .FS +are in the same order as the corresponding occurrences of +.BR \e** . +.LP +The strings +.B \e*{ +and +.B \e*} +can be used to begin and end a superscript. +.LP +Some Unix V10 ms features are implemented. +The +.BR B , +.BR I +and +.B BI +macros can have an optional third argument which will be printed +in the current font before the first argument. +There is a macro +.B CW +like +.B B +that changes to a constant-width font. +.LP +The following strings can be redefined to adapt the groff ms macros +to languages other than English: +.LP +.nf +.ta \w'REFERENCES'u+2n +String Default Value +.sp .3v +REFERENCES References +ABSTRACT ABSTRACT +TOC Table of Contents +MONTH1 January +MONTH2 February +MONTH3 March +MONTH4 April +MONTH5 May +MONTH6 June +MONTH7 July +MONTH8 August +MONTH9 September +MONTH10 October +MONTH11 November +MONTH12 December +.fi +.LP +The font family is reset from the string +.BR FAM ; +at initialization if this string is undefined it is set to the current +font family. +The point size, vertical spacing, and inter-paragraph spacing for footnotes +are taken from the number registers +.BR FPS , +.BR FVS , +and +.BR FPD ; +at initialization these are set to +.BR \en(PS-2 , +.BR \en[FPS]+2 , +and +.B \en(PD/2 +respectively; however, if any of these registers has been defined +before initialization, it will not be set. +.LP +Right-aligned displays are available with +.B ".DS R" +and +.BR .RD . +.LP +The following conventions are used for names of macros, strings and +number registers. +External names available to documents that use the groff ms +macros contain only uppercase letters and digits. +Internally the macros are divided into modules. +Names used only within one module are of the form +.IB module * name\fR. +Names used outside the module in which they are defined are of the form +.IB module @ name\fR. +Names associated with a particular environment are of the form +.IB environment : name; +these are used only within the +.B par +module, +and +.I name +does not have a module prefix. +Constructed names used to implement arrays are of the form +.IB array ! index\fR. +Thus the groff ms macros reserve the following names: +.IP \(bu +names containing +.BR * ; +.IP \(bu +names containing +.BR @ ; +.IP \(bu +names containing +.BR : ; +.IP \(bu +names containing only uppercase letters and digits. +.SH FILES +.B /usr/share/tmac/tmac.s +.SH "SEE ALSO" +.BR groff (1), +.BR troff (1), +.BR tbl (1), +.BR pic (1), +.BR eqn (1) +.br +.BR ms (7) diff --git a/gnu/usr.bin/groff/tmac/man.local b/gnu/usr.bin/groff/tmac/man.local new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gnu/usr.bin/groff/tmac/tmac.X b/gnu/usr.bin/groff/tmac/tmac.X new file mode 100644 index 0000000000..044113fe92 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.X @@ -0,0 +1,45 @@ +.nr _C \n(.C +.cp 0 +.ftr CW CR +.ftr C CR +.ftr CO CI +.ftr CX CBI +.ftr H HR +.ftr HO HI +.ftr HX HBI +.ftr NX NBI +.char \(ru \D'l .5m 0' +.char \(ul \v'.25m'\D'l .5m 0'\v'-.25m' +.char \(br \v'.25m'\D'l 0 -1m'\v'.75m' +.char ~ \v'-.55m'\\s[\\n(.s/2u]\v'.2m'\(ti\v'-.2m'\s0\v'.55m' +.char ^ \v'-.55m'\\s[\\n(.s/2u]\v'.3m'\(ha\v'-.3m'\s0\v'.55m' +.if !c\(va .char \(va \o'\(ua\(da' +.if !c\(em .char \(em -- +.if !c\(en .char \(en \- +.if !c\(fi .char \(fi fi +.if !c\(fl .char \(fl fl +.if !c\(ff .char \(ff ff +.if !c\(Fi .char \(Fi ffi +.if !c\(Fl .char \(Fl ffl +.if !c\(ci .char \(ci \v'-.25m'\h'.05m'\D'c .5m'\h'.05m'\v'.25m' +.if !c\(sq .char \(sq \h'.05m'\D'l .5m 0'\D'l 0 -.5m'\D'l -.5m 0'\D'l 0 .5m'\h'.55m' +.if !c\(ga .char \(ga \Z'\v'-.7m'\D'l .22m .18m''\h'.33m' +.if !c\(dg .char \(dg \Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\ +\D'l .39m 0''\h'.5m' +.if !c\(dd .char \(dd \Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\ +\D'l .39m 0'\v'.4m'\D'l -.39m 0''\h'.5m' +.if !c\(lq .char \(lq `` +.if !c\(rq .char \(rq '' +.if !c\(Bq .char \(bq ,, +.if !c\(OE .char \(OE O\h'-.25m'E +.if !c\(oe .char \(oe o\h'-.14m'e +.if !c\(ah .char \(ah \v'-.55m'\s[\En[.s]/2u]v\s0\v'.55m' +.if !c\(ao .char \(ao \v'-.55m'\s[\En[.s]*6u/10u]\D'c .25m'\s0\v'.55m' +.if !c\(ho .char \(ho \s[\En[.s]/2u]\v'.4m'c\v'-.4m'\s0 +.if !c\(lh .tr \(lh\(lA +.if !c\(rh .tr \(rh\(rA +.if !c\(bq .tr \(bq, +.if !c\(aq .tr \(aq' +.if '\*(.T'X100' .char \(rn \h'-\w'\(sr'u'\(rn\h'\w'\(sr'u' +.if !\n(_C .mso tmac.pspic +.cp \n(_C diff --git a/gnu/usr.bin/groff/tmac/tmac.Xps b/gnu/usr.bin/groff/tmac/tmac.Xps new file mode 100644 index 0000000000..92471abbc1 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.Xps @@ -0,0 +1,44 @@ +.do mso tmac.ps +.nr _C \n(.C +.cp 0 +.de Xps-char +.char \\$1 \Z"\X'ps: invis'\\$2\X'ps: endinvis'"\\$1 +.. +.Xps-char \(bu \fS\(bu\fP +.Xps-char \(em "\v'-.25m'\h'.05m'\D'l .9m 0'\h'.05m'" +.Xps-char \(aq ' +.Xps-char \(bq , +.Xps-char \(Bq ,, +.Xps-char \(lq `` +.Xps-char \(rq '' +.Xps-char \(OE OE +.Xps-char \(oe oe +.Xps-char \(Fn \fS\(Fn\fP +.Xps-char \(vS \o'\(ahS' +.Xps-char \(vs \o'\(ahs' +.Xps-char \(vZ \o'\(ahZ' +.Xps-char \(vz \o'\(ahz' +.Xps-char \(/L \o'/L' +.Xps-char \(/l \o'/l' +.Xps-char \(:Y \o'\(adY' +.Xps-char \(a" \(sd +.Xps-char \(a. \v'-.6m'. +.Xps-char \(ga "\Z'\v'-.7m'\D'l .22m .18m''\h'.33m'" +.Xps-char \(ab \v'-.55m'\s'\\\\n(.s*6u/10u'u\s0 +.Xps-char \(ah \v'-.55m'\s[\En[.s]/2u]v\s0\v'.55m' +.Xps-char \(ao "\v'-.55m'\s[\En[.s]*6u/10u]\D'c .25m'\s0\v'.55m'" +.Xps-char \(ho \s[\En[.s]/2u]\v'.4m'c\v'-.4m'\s0 +.Xps-char \(.i i +.Xps-char \(fo < +.Xps-char \(fc > +.Xps-char \(OK \s'\\\\n(.s*6u/10u'\e\s0/ +.Xps-char \(tm \v'-.3m'\s'\\\\n(.s*6u/10u'TM\s0\v'.3m' +.Xps-char \(dd "\Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\ +\D'l .39m 0'\v'.4m'\D'l -.39m 0''\h'.5m'" +.Xps-char \(dg "\Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\ +\D'l .39m 0''\h'.5m'" +.Xps-char \(en \- +.Xps-char \(%0 %\s'\\\\n(.s*6u/10u'\fI0\fP\s0 +.Xps-char \(lh \(-> +.Xps-char \(rh \(<- +.cp \n(_C diff --git a/gnu/usr.bin/groff/tmac/tmac.an b/gnu/usr.bin/groff/tmac/tmac.an new file mode 100644 index 0000000000..017a6a8c09 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.an @@ -0,0 +1,326 @@ +.\"Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. +.\" Written by James Clark (jjc@jclark.com) +.\" +.\"This file is part of groff. +.\" +.\"groff is free software; you can redistribute it and/or modify it under +.\"the terms of the GNU General Public License as published by the Free +.\"Software Foundation; either version 2, or (at your option) any later +.\"version. +.\" +.\"groff is distributed in the hope that it will be useful, but WITHOUT ANY +.\"WARRANTY; without even the implied warranty of MERCHANTABILITY or +.\"FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +.\"for more details. +.\" +.\"You should have received a copy of the GNU General Public License along +.\"with groff; see the file COPYING. If not, write to the Free Software +.\"Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +.\" +.\" -rC1 => number pages continuously, rather than start each at 1 +.\" -rD1 => double-sided printing, ie different odd and even page footers +.\" -rPnnn => number first page nnn +.\" -rXnnn => number pages after nnn as nnna, nnnb, nnnc, ... +.\" +.\" The file man.local is loaded at the end. Put local additions there. +.\" If you need to add things to TH, use `.am TH'. +.\" +.if !\n(.g .ab These man macros work only with groff. +.nr _C \n(.C +.cp 0 +.if !rD .nr D 0 +.if !rC .nr C 0 +.if rP .pn 0\nP +.\" .TH title section extra1 extra2 extra3 +.de TH +.cp 0 +.de an-init \" We have to do it like this to get multiple man pages right. +.ds an-title "\\$1 +.ds an-section "\\$2 +.ds an-extra1 "\\$3 +.ie \\n[.$]>3 .ds an-extra2 "\\$4 +.el .ds an-extra2 \"Sun Release 4.0 +.ie \\n[.$]>4 .ds an-extra3 "\\$5 +.el .ds an-extra3 \"UNIX Programmer's Manual +.ds an-init +\\.. +.DT +.nr IN 7.2n +.nr LL 6.5i +.PD +.nr PS 10 \" normal point-size +.nr SN 3n \" the indentation of sub-sub-headings relative to sub-headings +.nr an-level 1 +.nr an-margin \\n[IN] +.nr an-prevailing-indent \\n[IN] +.nr an-tag-sep 1n +.nr an-no-space-flag 0 +.nr an-break-flag 0 +.nr an-div? 0 +.wh 0 an-header +.wh -1i an-footer +.wh -.5i an-p-footer +.if \\n[nl]>0 \{\ +. ie \\nC .bp \\n%+1 +. el .bp 1 +.\} +.. +.de DT +.ta T .5i \" This sets tabs every .5 inches +.. +.de PD +.ie \\n[.$] .nr PD (v;\\$1) +.el .nr PD .4v>?\n[.V] +.. +.de an-header +.an-init +.ev 1 +.sp .5i +.tl '\\*[an-title](\\*[an-section])'\\*[an-extra3]'\\*[an-title](\\*[an-section])' +.sp |1i +.ev +.ns +.. +.de an-footer +'bp +.. +.af an-page-letter a +.de an-p-footer +.ev 1 +.ds an-page-string \\n% +.if rX \{\ +. if \\n%>\\nX \{\ +. nr an-page-letter \\n%-\\nX +. ds an-page-string \\nX\\n[an-page-letter] +.\}\} +.ie \\nD \{\ +. if o .tl '\\*[an-extra2]'\\*[an-extra1]'\\*[an-page-string]' +. if e .tl '\\*[an-page-string]'\\*[an-extra1]'\\*[an-extra2]' +.\} +.el .tl '\\*[an-extra2]'\\*[an-extra1]'\\*[an-page-string]' +.ev +.. +.de SH +.sp \\n[PD]u +.nr an-level 1 +.nr an-margin \\n[IN] +.nr an-prevailing-indent \\n[IN] +.fi +.in \\n[IN]u +.ti 0 +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.ps \\n[PS]-1 +.ft B +.ne 2v+1u +.if \\n[.$] \&\\$* +.. +.de SS +.sp \\n[PD]u +.nr an-level 1 +.nr an-margin \\n[IN] +.nr an-prevailing-indent \\n[IN] +.fi +.in \\n[IN]u +.ti \\n[SN]u +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.ps \\n[PS] +.ft B +.ne 2v+1u +.if \\n[.$] \&\\$* +.. +.de B +.it 1 an-trap +.ft B +.if \\n[.$] \&\\$* +.. +.de I +.it 1 an-trap +.ft I +.if \\n[.$] \&\\$* +.. +.de SM +.it 1 an-trap +.ps -1 +.if \\n[.$] \&\\$* +.. +.de SB +.it 1 an-trap +.ps -1 +.ft B +.if \\n[.$] \&\\$* +.. +.de TP +.sp \\n[PD]u +.if \\n[.$] .nr an-prevailing-indent (n;\\$1) +.it 1 an-trap +.if !\\n[an-div?] .di an-div +.in 0 +.nr an-div? 1 +.. +.de an-trap +.ft R +.ps \\n[PS] +.if \\n[an-break-flag] \{\ +. br +. nr an-break-flag 0 +.\} +.if \\n[an-no-space-flag] \{\ +. ns +. nr an-no-space-flag 0 +.\} +.if \\n[an-div?] .an-do-tag +.. +.de an-do-tag +.nr an-div? 0 +.br +.di +.in \\n[an-margin]u+\\n[an-prevailing-indent]u +.ti -\\n[an-prevailing-indent]u +.ie \\n[dl]+\\n[an-tag-sep]>\\n[an-prevailing-indent] \{\ +. ne 2v+1u +. an-div +. br +.\} +.el \{\ +. chop an-div +. ne 1v+1u +\\*[an-div]\\h'|\\n[an-prevailing-indent]u'\c +.\} +.. +.de LP +.br +.sp \\n[PD]u +.ps \\n[PS] +.ft R +.in \\n[an-margin]u +.nr an-prevailing-indent \\n[IN] +.. +.als PP LP +.als P LP +.de IP +.ie !\\n[.$] \{\ +. ps \\n[PS] +. ft R +. sp \\n[PD]u +. ne 1v+1u +. in \\n[an-margin]u+\\n[an-prevailing-indent]u +.\} +.el \{\ +. ie \\n[.$]-1 .TP "\\$2" +. el .TP +\&\\$1 +.\} +.. +.de HP +.ps \\n[PS] +.ft R +.sp \\n[PD]u +.ne 1v+1u +.if \\n[.$] .nr an-prevailing-indent (n;\\$1) +.in \\n[an-margin]u+\\n[an-prevailing-indent]u +.ti \\n[an-margin]u +.. +.de RI +.if \\n[.$] \{\ +. ds an-result \&\\$1 +. shift +. while \\n[.$]>=2 \{\ +. as an-result \,\fI\\$1\fR\/\\$2 +. shift 2 +. \} +. if \\n[.$] .as an-result \,\fI\\$1\fR +\\*[an-result] +.\} +.. +.de IR +.if \\n[.$] \{\ +. ds an-result \&\fI\\$1\fR +. shift +. while \\n[.$]>=2 \{\ +. as an-result \/\\$1\fI\,\\$2\fR +. shift 2 +. \} +. if \\n[.$] .as an-result \/\\$1 +\\*[an-result] +.\} +.. +.de IB +.if \\n[.$] \{\ +. ds an-result \&\fI\\$1 +. shift +. while \\n[.$]>=2 \{\ +. as an-result \/\\fB\\$1\fI\,\\$2 +. shift 2 +. \} +. if \\n[.$] .as an-result \/\\fB\\$1 +\\*[an-result] +. ft R +.\} +.. +.de BI +.if \\n[.$] \{\ +. ds an-result \&\fB\\$1 +. shift +. while \\n[.$]>=2 \{\ +. as an-result \,\fI\\$1\fB\/\\$2 +. shift 2 +. \} +. if \\n[.$] .as an-result \,\fI\\$1 +\\*[an-result] +. ft R +.\} +.. +.de RB +.ds an-result \& +.while \\n[.$]>=2 \{\ +. as an-result \fR\\$1\fB\\$2 +. shift 2 +.\} +.if \\n[.$] .as an-result \fR\\$1 +\\*[an-result] +.ft R +.. +.de BR +.ds an-result \& +.while \\n[.$]>=2 \{\ +. as an-result \fB\\$1\fR\\$2 +. shift 2 +.\} +.if \\n[.$] .as an-result \fB\\$1 +\\*[an-result] +.ft R +.. +.de RS +.br +.nr an-saved-margin\\n[an-level] \\n[an-margin] +.nr an-saved-prevailing-indent\\n[an-level] \\n[an-prevailing-indent] +.ie \\n[.$] .nr an-margin +(n;\\$1) +.el .nr an-margin +\\n[an-prevailing-indent] +.in \\n[an-margin]u +.nr an-prevailing-indent \\n[IN] +.nr an-level +1 +.. +.de RE +.br +.ie \\n[.$] .nr an-level (;\\$1)?\\n[an-level] +.nr an-margin \\n[an-saved-margin\\n[an-level]] +.nr an-prevailing-indent \\n[an-saved-prevailing-indent\\n[an-level]] +.in \\n[an-margin]u +.. +.ds S \s[\\n[PS]] +.ie c\[rg] .ds R \[rg] +.el .ds R (Reg.) +.ie c\[tm] .ds Tm \[tm] +.el .ds Tm (TM) +.ds lq \(lq +.ds rq \(rq +.hy 14 +.\" Load local modifications. +.mso man.local +.cp \n(_C diff --git a/gnu/usr.bin/groff/tmac/tmac.dvi b/gnu/usr.bin/groff/tmac/tmac.dvi new file mode 100644 index 0000000000..c64fc73ce7 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.dvi @@ -0,0 +1,132 @@ +.nr _C \n(.C +.cp 0 +.ftr CR CW +.ftr C CW +.ftr TT CW +.ftr HR H +.\" This uses the dvi-char_1 string in font CW, dvi-char_0 otherwise. +.char _ \R'dvi-char_ \\n(.f=\f(CW\\n(.f\fP'\\*[dvi-char_\\n[dvi-char_]] +.char \[ul] \R'dvi-char_ \w'M'=\w'i''\\*[dvi-char_\\n[dvi-char_]] +.\" Normally use a rule. +.ds dvi-char_0 \v'.23m'\D'R .5m .04m'\v'-.04m'\v'-.23m' +.\" In font CW use a real _ character. +.ds dvi-char_1 _ +.if !c\[rn] .char \[rn] \D'R .5m -.04m'\v'.04m' +.if !c\[br] .char \[br] \Z'\v'.25m'\D'R .04m -1m'' +.if !c\[ru] .char \[ru] \v'-.02m'\D'R .5m .04m'\v'-.04m'\v'.02m' +.if !c\[co] .char \[co] \z\(ci\h'\w'\(ci'u-\w'c'u/2u'c\h'\w'\(ci'u-\w'c'u/2u' +.if !c\[rg] .char \[rg] \z\(ci\h'\w'\(ci'u-\w'r'u/2u'r\h'\w'\(ci'u-\w'r'u/2u' +.if !c\[fm] .char \[fm] \v'-.35m'\s[\\n(.s*7u/10u]\[prime]\s0\v'.35m' +.if !c\[de] .char \[de] \h'.05m'\v'-.54m'\D'c .3m'\v'.54m'\h'.05m' +.if !c\[ct] .char \[ct] \o'c/' +.if !c\[sq] .char \[sq] \Z'\h'.05m'\D'R .4m -.04m'\v'.04m'\h'-.04m'\ +\D'R .04m -.4m'\v'.04m'\D'R -.4m -.04m'\D'R .04m .4m''\h'.5m' +.\"char \[sq] \h'.05m'\D'l .4m 0'\D'l 0 -.4m'\D'l -.4m 0'\D'l 0 .4m'\h'.45m' +.if !c\[!=] .char \[!=] \[slashnot]\(eq +.if !c\[tm] .char \[tm] \v'-.3m'\s[\\n(.s/2u]TM\s0\v'.3m' +.if !c\[aq] .char \[aq] ' +.if !c\[bq] .char \[bq] , +.if !c\[Bq] .char \[Bq] ,\h'\w'\(rq'u-(2u*\w"'"u)', +.if !c\[ho] .char \[ho] \s[\En[.s]/2u]\v'.4m'c\v'-.4m'\s0 +.if !c\[-D] .char \[-D] \Z'\v'-.1m'\h'.05m'-'D +.if !c\[Sd] .char \[Sd] \Z'\v'-.3m'\h'.35m'-'\(pd +.if !c\[TP] .char \[TP] I\h'-.25m'\v'-.33m'\s[\En[.s]*6u/10u]\v'.33m'D\ +\v'-.33m'\s0\v'.33m' +.if !c\[Tp] .char \[Tp] \zlp +.cflags 8 \(an +.if !c\[an] .char \[an] \h'-.167m'\(mi\h'-.167m' +.\" Define some fractions. +.de dvi-frac +.if !c\[\\$1\\$2] .char \[\\$1\\$2] \ +\v'-.25m'\s[\\\\n(.s*7u/10u]\\$1\s0\v'.25m'\h'-.2m'\ +/\h'-.2m'\v'.25m'\s[\\\\n(.s*7u/10u]\\$2\s0\v'-.25m' +.. +.dvi-frac 1 2 +.dvi-frac 3 4 +.dvi-frac 1 4 +.dvi-frac 1 8 +.dvi-frac 3 8 +.dvi-frac 5 8 +.dvi-frac 7 8 +.\" support for ISO Latin-1 +.if !c\[S1] .char \[S1] \v'-.2m'\s-31\s+3\v'+.2m' +.if !c\[S2] .char \[S2] \v'-.2m'\s-32\s+3\v'+.2m' +.if !c\[S3] .char \[S3] \v'-.2m'\s-33\s+3\v'+.2m' +.if !c\[Of] .char \[Of] \v'-.2m'\s'\En(.s*6u/10u'\o'_a'\s0\v'.2m' +.if !c\[Om] .char \[Om] \v'-.2m'\s'\En(.s*6u/10u'\o'_o'\s0\v'.2m' +.if !c\[Fo] .char \[Fo] << +.if !c\[Fc] .char \[Fc] >> +.if !c\[bb] .char \[bb] | +.if !c\[Ye] .char \[Ye] \o'-Y' +.if !c\[Cs] .char \[Cs] \o'\[mu]o' +.de dvi-achar +.\" Note that character definitions are always interpreted with +.\" compatibility mode off. +.if !c\\$1 \{\ +.char \\$1 \\$3\ +\k[acc]\ +\h'(u;-\w'\\$2'-\w'\\$3'/2+\\\\n[skw]+(\w'x'*0)-\\\\n[skw])'\ +\v'(u;\w'x'*0+\\\\n[rst]+(\w'\\$3'*0)-\\\\n[rst])'\ +\\$2\ +\v'(u;\w'x'*0-\\\\n[rst]+(\w'\\$3'*0)+\\\\n[rst])'\ +\h'|\\\\n[acc]u' +.\} +.hcode \\$1\\$4 +.. +.dvi-achar \(`A \` A a +.dvi-achar \('A \' A a +.dvi-achar \(^A ^ A a +.dvi-achar \(~A ~ A a +.dvi-achar \(:A \(ad A a +.dvi-achar \(oA \(ao A a +.dvi-achar \(`E \` E e +.dvi-achar \('E \' E e +.dvi-achar \(^E ^ E e +.dvi-achar \(:E \(ad E e +.dvi-achar \(`I \` I i +.dvi-achar \('I \' I i +.dvi-achar \(^I ^ I i +.dvi-achar \(:I \(ad I i +.dvi-achar \(~N ~ N n +.dvi-achar \(`O \` O o +.dvi-achar \('O \' O o +.dvi-achar \(^O ^ O o +.dvi-achar \(~O ~ O o +.dvi-achar \(:O \(ad O o +.dvi-achar \(`U \` U u +.dvi-achar \('U \' U u +.dvi-achar \(^U ^ U u +.dvi-achar \(:U \(ad U u +.dvi-achar \('Y \' Y y +.dvi-achar \(`a \` a a +.dvi-achar \('a \' a a +.dvi-achar \(^a ^ a a +.dvi-achar \(~a ~ a a +.dvi-achar \(:a \(ad a a +.dvi-achar \(oa \(ao a a +.dvi-achar \(`e \` e e +.dvi-achar \('e \' e e +.dvi-achar \(^e ^ e e +.dvi-achar \(:e \(ad e e +.dvi-achar \(`i \` \(.i i +.dvi-achar \('i \' \(.i i +.dvi-achar \(^i ^ \(.i i +.dvi-achar \(:i \(ad \(.i i +.dvi-achar \(~n ~ n n +.dvi-achar \(`o \` o o +.dvi-achar \('o \' o o +.dvi-achar \(^o ^ o o +.dvi-achar \(~o ~ o o +.dvi-achar \(:o \(ad o o +.dvi-achar \(`u \` u u +.dvi-achar \('u \' u u +.dvi-achar \(^u ^ u u +.dvi-achar \(:u \(ad u u +.dvi-achar \('y \' y y +.dvi-achar \(:y \(ad y y +.char \(,C \o'\(acc' +.hcode \(,Cc +.char \(,c \o'\(acc' +.hcode \(,cc +.cp \n(_C +.do mso tmac.latin1 diff --git a/gnu/usr.bin/groff/tmac/tmac.latin1 b/gnu/usr.bin/groff/tmac/tmac.latin1 new file mode 100644 index 0000000000..f33ea2164d --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.latin1 @@ -0,0 +1,101 @@ +.nr _C \n(.C +.cp 0 +.de latin1-tr +.if c\\$2 .if !c\\$1 .tr \\$1\\$2 +.. +.latin1-tr \[char161] \(r! +.latin1-tr \[char162] \(ct +.latin1-tr \[char163] \(Po +.latin1-tr \[char164] \(Cs +.latin1-tr \[char165] \(Ye +.latin1-tr \[char166] \(bb +.latin1-tr \[char167] \(sc +.latin1-tr \[char168] \(ad +.latin1-tr \[char169] \(co +.latin1-tr \[char170] \(Of +.latin1-tr \[char171] \(Fo +.latin1-tr \[char172] \(no +.latin1-tr \[char173] \(hy +.latin1-tr \[char174] \(rg +.latin1-tr \[char175] \(a- +.latin1-tr \[char176] \(de +.latin1-tr \[char177] \(+- +.latin1-tr \[char178] \(S2 +.latin1-tr \[char179] \(S3 +.latin1-tr \[char180] \(aa +.latin1-tr \[char181] \(*m +.latin1-tr \[char182] \(ps +.latin1-tr \[char183] \(md +.latin1-tr \[char184] \(ac +.latin1-tr \[char185] \(S1 +.latin1-tr \[char186] \(Om +.latin1-tr \[char187] \(Fc +.latin1-tr \[char188] \(14 +.latin1-tr \[char189] \(12 +.latin1-tr \[char190] \(34 +.latin1-tr \[char191] \(r? +.latin1-tr \[char192] \(`A +.latin1-tr \[char193] \('A +.latin1-tr \[char194] \(^A +.latin1-tr \[char195] \(~A +.latin1-tr \[char196] \(:A +.latin1-tr \[char197] \(oA +.latin1-tr \[char198] \(AE +.latin1-tr \[char199] \(,C +.latin1-tr \[char200] \(`E +.latin1-tr \[char201] \('E +.latin1-tr \[char202] \(^E +.latin1-tr \[char203] \(:E +.latin1-tr \[char204] \(`I +.latin1-tr \[char205] \('I +.latin1-tr \[char206] \(^I +.latin1-tr \[char207] \(:I +.latin1-tr \[char208] \(-D +.latin1-tr \[char209] \(~N +.latin1-tr \[char210] \(`O +.latin1-tr \[char211] \('O +.latin1-tr \[char212] \(^O +.latin1-tr \[char213] \(~O +.latin1-tr \[char214] \(:O +.latin1-tr \[char215] \(mu +.latin1-tr \[char216] \(/O +.latin1-tr \[char217] \(`U +.latin1-tr \[char218] \('U +.latin1-tr \[char219] \(^U +.latin1-tr \[char220] \(:U +.latin1-tr \[char221] \('Y +.latin1-tr \[char222] \(TP +.latin1-tr \[char223] \(ss +.latin1-tr \[char224] \(`a +.latin1-tr \[char225] \('a +.latin1-tr \[char226] \(^a +.latin1-tr \[char227] \(~a +.latin1-tr \[char228] \(:a +.latin1-tr \[char229] \(oa +.latin1-tr \[char230] \(ae +.latin1-tr \[char231] \(,c +.latin1-tr \[char232] \(`e +.latin1-tr \[char233] \('e +.latin1-tr \[char234] \(^e +.latin1-tr \[char235] \(:e +.latin1-tr \[char236] \(`i +.latin1-tr \[char237] \('i +.latin1-tr \[char238] \(^i +.latin1-tr \[char239] \(:i +.latin1-tr \[char240] \(Sd +.latin1-tr \[char241] \(~n +.latin1-tr \[char242] \(`o +.latin1-tr \[char243] \('o +.latin1-tr \[char244] \(^o +.latin1-tr \[char245] \(~o +.latin1-tr \[char246] \(:o +.latin1-tr \[char247] \(di +.latin1-tr \[char248] \(/o +.latin1-tr \[char249] \(`u +.latin1-tr \[char250] \('u +.latin1-tr \[char251] \(^u +.latin1-tr \[char252] \(:u +.latin1-tr \[char253] \('y +.latin1-tr \[char254] \(Tp +.latin1-tr \[char255] \(:y +.cp \n(_C diff --git a/gnu/usr.bin/groff/tmac/tmac.pic b/gnu/usr.bin/groff/tmac/tmac.pic new file mode 100644 index 0000000000..1177fc09d1 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.pic @@ -0,0 +1,10 @@ +.de PS +.br +.sp .3v +.ne 0\\$1+1v+\n(.Vu +.in \\n(.lu-\\n(.iu-0\\$2/2u>?0 +.. +.de PE +.in +.sp .3v+.5m +.. diff --git a/gnu/usr.bin/groff/tmac/tmac.ps b/gnu/usr.bin/groff/tmac/tmac.ps new file mode 100644 index 0000000000..d7d655dbad --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.ps @@ -0,0 +1,52 @@ +.nr _C \n(.C +.cp 0 +.ftr AX ABI +.ftr KR BMR +.ftr KI BMI +.ftr KB BMB +.ftr KX BMBI +.ftr CW CR +.ftr CO CI +.ftr CX CBI +.ftr H HR +.ftr HO HI +.ftr HX HBI +.ftr Hr HNR +.ftr Hi HNI +.ftr Hb HNB +.ftr Hx HNBI +.ftr NX NBI +.ftr PA PR +.ftr PX PBI +.ftr ZI ZCMI +.ftr C CR +.cflags 8 \(an +.char \(rn \h'-\w'\(sr'u'\(rn\h'\w'\(sr'u' +.char \(mo \h'.08m'\(mo\h'-.08m' +.char \(nm \h'.08m'\(nm\h'-.08m' +.char \[parenlefttp] \[parenlefttp]\h'.016m' +.char \[parenleftbt] \[parenleftbt]\h'.016m' +.char \[parenleftex] \[parenleftex]\h'.016m' +.char \[parenrighttp] \[parenrighttp]\h'.016m' +.char \[parenrightbt] \[parenrightbt]\h'.016m' +.char \[parenrightex] \[parenrightex]\h'.016m' +.if !c\[va] .char \[va] \o'\[ua]\[da]' +.if !c\[ci] \ +.char \[ci] \v'-.25m'\h'.05m'\D'c .5m'\h'.05m'\v'.25m' +.if !c\[sq] \ +.char \[sq] \h'.05m'\D'l .5m 0'\D'l 0 -.5m'\D'l -.5m 0'\D'l 0 .5m'\h'.55m' +.if !c\[ru] .char \[ru] \D'l .5m 0' +.if !c\[ul] .char \[ul] \v'.25m'\D'l .5m 0'\v'-.25m' +.if !c\[br] .char \[br] \Z'\v'.25m'\D'l 0 -1m'' +.if !c\[or] .char \[or] \h'.1m'\Z'\D'l 0 -.675m''\h'.1m' +.if !c\[Fi] .char \[Fi] ffi +.if !c\[Fl] .char \[Fl] ffl +.if !c\[ff] .char \[ff] ff +.if !c\[ij] .char \[ij] ij +.if !c\[IJ] .char \[IJ] IJ +.if !c\[tm] .char \[tm] \s-3\v'-.3m'TM\v'+.3m'\s+3 +.\" pic tests this register to see whether it should use \X'ps:...' +.nr 0p 1 +.cp \n(_C +.if !\n(.C .mso tmac.pspic +.do mso tmac.psold diff --git a/gnu/usr.bin/groff/tmac/tmac.psatk b/gnu/usr.bin/groff/tmac/tmac.psatk new file mode 100644 index 0000000000..b59d23a24e --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.psatk @@ -0,0 +1,61 @@ +.\" Implementation of the ATK PB and PE macros for use with groff and grops. +.\" Load this after tmac.atk. +.nr zT 0 +.if '\*(.T'ps' .nr zT 1 +.nr psatk-unit 1p +.de psatk-defs +ps: mdef 5 +/PB { + /saved save def + currentpoint translate + \n[psatk-unit] u -\n[psatk-unit] u scale + userdict begin + /showpage {} def +} bind def +/PE { + end + saved restore +} bind def +/troffadjust { + pop 0 +} bind def +.. +.de PB +.ne \\$1p +.nr zT \\n(zT>0 +\\*[PB\\n(zT]\\ +.. +.de PE +\\*[PE\\n(zT]\\ +.. +.ds PB0 +.\" The last line before the "'PE" is "\}" rather than ".\}". This +.\" would cause a spurious space to be introduced before any picture +.\" that was the first thing on a line. So we have to catch that and +.\" remove it. +.de PB1 +.ev psatk +.fi +.di psatk-mac +\!ps: exec PB +.. +.de PE0 +\v'-.75m'\ +\D'l \\$1p 0'\D'l 0 \\$2p'\D'l -\\$1p 0'\D'l 0 -\\$2p'\ +\h'\\$1p'\v'.75m'\x'\\$2p-1m>?0'\c +.. +.ds psatk-init \Y[psatk-defs] +.de PE1 +\!PE +.di +.di null +.br +.di +.rm null +.ev +\v'-.75m'\ +\\*[psatk-init]\Y[psatk-mac]\ +\h'\\$1p'\v'.75m'\x'\\$2p-1m>?0'\c +.rm psatk-mac +.if \\n(.P .ds psatk-init +.. diff --git a/gnu/usr.bin/groff/tmac/tmac.psfig b/gnu/usr.bin/groff/tmac/tmac.psfig new file mode 100644 index 0000000000..5f4111ce6a --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.psfig @@ -0,0 +1,87 @@ +.\" These are macros to make psfig work with groff. +.\" They require that psfig be patched as described in ../grops/psfig.diff. +.de psfig-defs +ps: mdef 100 + +% wid ht llx lly urx ury psfigstart - + +/psfigstart { + /level1 save def + /ury exch def + /urx exch def + /lly exch def + /llx exch def + /ht exch u def + /wid exch u def + currentpoint ht add translate + wid urx llx sub div ht ury lly sub div neg scale + llx neg lly neg translate + + % set the graphics state to default values + 0 setgray + 0 setlinecap + 1 setlinewidth + 0 setlinejoin + 10 setmiterlimit + [] 0 setdash + newpath + /showpage {} def +} bind def + +% psfigclip - + +/psfigclip { + currentpoint newpath + llx lly moveto + urx lly lineto + urx ury lineto + llx ury lineto + closepath clip + newpath moveto +} bind def + +% psfigend - + +/psfigend { + level1 restore +} bind def + +% globalstart - + +/globalstart { + % save the current space code on the stack + SC + level0 restore +} bind def + +% globalend - + +/globalend { + end + BP + /SC exch def + DEFS begin +} bind def +.. +.de psfig-init +.if \\n[.P] \{\ +\Y[psfig-defs] +. br +. sp -1 +. ds psfig-init\" empty +. rm psfig-defs +.\} +.. +.de F+ +.br +.psfig-init +.nr psfig-fill \\n[.u] +.nf +.sp -.5 +.if !\\n[.$] .ce 9999 +.. +.de F- +.br +.ce 0 +.if \\n[psfig-fill] .fi +.. diff --git a/gnu/usr.bin/groff/tmac/tmac.psnew b/gnu/usr.bin/groff/tmac/tmac.psnew new file mode 100644 index 0000000000..e13bdb8869 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.psnew @@ -0,0 +1,26 @@ +.\" Undo the effect of tmac.psold. This gives access to the additional +.\" characters that are present in the text fonts of newer PostScript +.\" printers. It is a bad idea to use this if you are going to +.\" distribute the resulting PostScript output to others. +.nr _C \n(.C +.cp 0 +.rchar \('y\('Y\(12\(14\(34\(S1\(S2\(S3\(bb\(de\(Tp\(TP\(-D\(Sd +.tr \[char166]\[char166] +.tr \[char176]\[char176] +.tr \[char177]\[char177] +.tr \[char178]\[char178] +.tr \[char179]\[char179] +.tr \[char181]\[char181] +.tr \[char185]\[char185] +.tr \[char188]\[char188] +.tr \[char189]\[char189] +.tr \[char190]\[char190] +.tr \[char208]\[char208] +.tr \[char215]\[char215] +.tr \[char221]\[char221] +.tr \[char222]\[char222] +.tr \[char240]\[char240] +.tr \[char247]\[char247] +.tr \[char253]\[char253] +.tr \[char254]\[char254] +.cp \n(_C diff --git a/gnu/usr.bin/groff/tmac/tmac.psold b/gnu/usr.bin/groff/tmac/tmac.psold new file mode 100644 index 0000000000..04a5f6df49 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.psold @@ -0,0 +1,60 @@ +.\" In the newer PostScript printers, the text fonts contain all ISO Latin-1 +.\" characters. The font description files that comes with groff match +.\" these fonts. The text fonts in older PostScript printers are missing +.\" some of these characters. This file prevents those characters from +.\" being used. This will allow the PostScript output to be printed on both +.\" old and new printers. The effect of this file can be undone by +.\" tmac.psnew. +.nr _C \n(.C +.cp 0 +.\" Define an accented character. +.de ps-achar +.\" Note that character definitions are always interpreted with +.\" compatibility mode off. +.char \\$1 \\$3\ +\k[acc]\ +\h'(u;-\w'\\$2'-\w'\\$3'/2+\\\\n[skw]+(\w'x'*0)-\\\\n[skw])'\ +\v'(u;\w'x'*0+\\\\n[rst]+(\w'\\$3'*0)-\\\\n[rst])'\ +\\$2\ +\v'(u;\w'x'*0-\\\\n[rst]+(\w'\\$3'*0)+\\\\n[rst])'\ +\h'|\\\\n[acc]u' +.ie '\\$3'\(.i' .hcode \\$1i +.el .hcode \\$1\\$3 +.. +.ps-achar \['y] \(aa y +.ps-achar \['Y] \(aa Y +.char \[12] \v'-.7m\s[\\n(.s*6u/10u]+.7m'1\v'-.7m\s0+.7m'\ +\(f/\s[\\n(.s*6u/10u]2\s0 +.char \[14] \v'-.7m\s[\\n(.s*6u/10u]+.7m'1\v'-.7m\s0+.7m'\ +\(f/\s[\\n(.s*6u/10u]4\s0 +.char \[34] \v'-.7m\s[\\n(.s*6u/10u]+.7m'3\v'-.7m\s0+.7m'\ +\(f/\s[\\n(.s*6u/10u]4\s0 +.char \[S1] \v'-.2m'\s-31\s+3\v'+.2m' +.char \[S2] \v'-.2m'\s-32\s+3\v'+.2m' +.char \[S3] \v'-.2m'\s-33\s+3\v'+.2m' +.char \[bb] | +.char \[de] \fS\(de +.char \[-D] \Z'\v'-.1m'-'D +.char \[TP] \ +I\h'-.25m'\v'-.33m'\s'\En(.s*6u/10u'\v'.33m'D\v'-.33m'\s0\v'.33m' +.char \[Sd] \Z'\v'-.3m'\h'.2m'-'\(pd +.char \[Tp] \zlp +.tr \[char166]\[bb] +.tr \[char176]\[de] +.tr \[char177]\[+-] +.tr \[char178]\[S2] +.tr \[char179]\[S3] +.tr \[char181]\[*m] +.tr \[char185]\[S1] +.tr \[char188]\[14] +.tr \[char189]\[12] +.tr \[char190]\[34] +.tr \[char208]\[-D] +.tr \[char215]\[mu] +.tr \[char221]\['Y] +.tr \[char222]\[TP] +.tr \[char240]\[Sd] +.tr \[char247]\[di] +.tr \[char253]\['y] +.tr \[char254]\[Tp] +.cp \n(_C diff --git a/gnu/usr.bin/groff/tmac/tmac.pspic b/gnu/usr.bin/groff/tmac/tmac.pspic new file mode 100644 index 0000000000..9923907ff7 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.pspic @@ -0,0 +1,41 @@ +.\" Define the PSPIC macro. +.\" When used other than with -Tps, it will draw a box around where +.\" the picture would go. +.de ps-bb +.nr ps-nargs \\n[.$] +.if \\n[ps-nargs]=4 \{\ +. nr ps-llx 0\\$1 +. nr ps-lly 0\\$2 +. nr ps-urx 0\\$3 +. nr ps-ury 0\\$4 +.\} +.. +.de PSPIC +.br +.sy echo .ps-bb `psbb \\$1` >/tmp/psbb\\n[$$] +.so /tmp/psbb\\n[$$] +.if \\n[ps-nargs]=4 \{\ +. nr ps-wid (\\n[ps-urx]-\\n[ps-llx]) +. nr ps-ht (\\n[ps-ury]-\\n[ps-lly]) +. if \\n[ps-wid]<0 .nr ps-wid 0-\\n[ps-wid] +. if \\n[ps-ht]<0 .nr ps-ht 0-\\n[ps-ht] +. ie \\n[.$]>=2 .nr ps-deswid (i;\\$2) +. el .nr ps-deswid \\n[.l]-\\n[.i]=3 .nr ps-desht (i;\\$3) +. el .nr ps-desht \\n[ps-deswid]*1000+(\\n[ps-wid]/2)/\\n[ps-wid]\ +*\\n[ps-ht]+500/1000 +. ne \\n[ps-desht]u+1v +. nr ps-offset \\n[.l]-\\n[.i]-\\n[ps-deswid]/2 +. ie \\n[.$]>=3 .ds ps-desht \\n[ps-desht] +. el .ds ps-desht \" empty +\h'\\n[ps-offset]u'\ +\X'ps: invis'\ +\Z'\D'p 0 \\n[ps-desht]u \\n[ps-deswid]u 0 0 -\\n[ps-desht]u''\ +\X'ps: endinvis'\ +\v'\\n[ps-desht]u'\X'ps: import \\$1 \ +\\n[ps-llx] \\n[ps-lly] \\n[ps-urx] \\n[ps-ury] \\n[ps-deswid] \\*[ps-desht]' +. br +. sp \\n[ps-desht]u +.\} +.sy rm /tmp/psbb\\n[$$] +.. diff --git a/gnu/usr.bin/groff/tmac/tmac.s b/gnu/usr.bin/groff/tmac/tmac.s new file mode 100644 index 0000000000..9afb7e6f0b --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.s @@ -0,0 +1,1803 @@ +.ig +Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +.. +.if !\n(.g .ab These ms macros require groff. +.if \n(.C \ +. ab The groff ms macros do not work in compatibility mode. +.\" Enable warnings. You can delete this if you want. +.warn +.\" See if already loaded. +.if r GS .nx +.nr GS 1 +.de @error +.tm \\n(.F:\\n(.c: macro error: \\$* +.. +.de @warning +.tm \\n(.F:\\n(.c: macro warning: \\$* +.. +.de @fatal +.ab \\n(.F:\\n(.c: fatal macro error: \\$* +.. +.de @not-implemented +.@error sorry, \\$0 not implemented +.als \\$0 @nop +.. +.als TM @not-implemented +.als CT @not-implemented +.de @nop +.. +.de @init +.\" a non-empty environment +.ev ne +\c +.ev +.ev nf +'nf +.ev +.. +.ds REFERENCES References +.ds ABSTRACT ABSTRACT +.ds TOC Table of Contents +.ds MONTH1 January +.ds MONTH2 February +.ds MONTH3 March +.ds MONTH4 April +.ds MONTH5 May +.ds MONTH6 June +.ds MONTH7 July +.ds MONTH8 August +.ds MONTH9 September +.ds MONTH10 October +.ds MONTH11 November +.ds MONTH12 December +.ds MO \\*[MONTH\n[mo]] +.nr *year \n[yr]+1900 +.ds DY \n[dy] \*[MO] \n[*year] +.de ND +.if \\n[.$] .ds DY "\\$* +.. +.de DA +.if \\n[.$] .ds DY "\\$* +.ds CF \\*[DY] +.. +.\" indexing +.de IX +.tm \\$1\t\\$2\t\\$3\t\\$4 ... \\n[PN] +.. +.\" print an error message and then try to recover +.de @error-recover +.@error \\$@ (recovering) +.nr *pop-count 0 +.while !'\\n(.z'' \{\ +. \"@warning automatically terminating diversion \\n(.z +. ie d @div-end!\\n(.z .@div-end!\\n(.z +. el .*div-end-default +. nr *pop-count +1 +. \" ensure that we don't loop forever +. if \\n[*pop-count]>20 .@fatal recovery failed +.\} +.while !'\\n[.ev]'0' .ev +.par@reset-env +.par@reset +.. +.de *div-end-default +.ds *last-div \\n(.z +.br +.di +.ev nf +.\\*[*last-div] +.ev +.. +.\" **************************** +.\" ******** module cov ******** +.\" **************************** +.\" Cover sheet and first page. +.de cov*err-not-after-first-page +.@error \\$0 is not allowed after the first page has started +.. +.de cov*err-not-before-tl +.@error \\$0 is not allowed before TL +.. +.de cov*err-not-again +.@error \\$0 is not allowed more than once +.. +.de cov*err-not-after-ab +.@error \\$0 is not allowed after first AB, LP, PP, IP, SH or NH +.. +.als AU cov*err-not-before-tl +.als AI cov*err-not-before-tl +.als AB cov*err-not-before-tl +.de cov*first-page-init +.rm cov*first-page-init +.par@init +.als RP cov*err-not-after-first-page +.@init +.ie \\n[cov*rp-format] \{\ +. pg@cs-top +. als FS cov*FS +. als FE cov*FE +.\} +.el \{\ +. pg@top +. als FS @FS +. als FE @FE +.\} +.wh 0 pg@top +.. +.wh 0 cov*first-page-init +.\" This handles the case where FS occurs before TL or LP. +.de FS +.br +\\*[FS]\\ +.. +.nr cov*rp-format 0 +.nr cov*rp-no 0 +.\" released paper format +.de RP +.nr cov*rp-format 1 +.if \\n[.$] .if '\\$1'no' .nr cov*rp-no 1 +.pn 0 +.. +.de TL +.br +.als TL cov*err-not-again +.rn @AB AB +.rn @AU AU +.rn @AI AI +.di cov*tl-div +.par@reset +.ft B +.ps +2 +.vs +3p +.ll (u;\\n[LL]*5/6) +.nr cov*n-au 0 +.. +.de @AU +.par@reset +.if !'\\n(.z'' \{\ +. br +. di +.\} +.nr cov*n-au +1 +.di cov*au-div!\\n[cov*n-au] +.nf +.ft I +.ps \\n[PS] +.. +.de @AI +.par@reset +.if !'\\n(.z'' \{\ +. br +. di +.\} +.ie !\\n[cov*n-au] .@error AI before AU +.el \{\ +. di cov*ai-div!\\n[cov*n-au] +. nf +. ft R +. ps \\n[PS] +.\} +.. +.de LP +.if !'\\n[.z]'' \{\ +. br +. di +.\} +.br +.cov*ab-init +.cov*print +\\*[\\$0]\\ +.. +.als IP LP +.als PP LP +.als XP LP +.als NH LP +.als SH LP +.als MC LP +.als RT LP +.als XS LP +.de cov*ab-init +.als cov*ab-init @nop +.als LP @LP +.als IP @IP +.als PP @PP +.als XP @XP +.als RT @RT +.als XS @XS +.als SH @SH +.als NH @NH +.als QP @QP +.als RS @RS +.als RE @RE +.als QS @QS +.als QE @QE +.als MC @MC +.als EQ @EQ +.als EN @EN +.als AB cov*err-not-after-ab +.als AU par@AU +.als AI par@AI +.als TL par@TL +.. +.de @AB +.if !'\\n(.z'' \{\ +. br +. di +.\} +.cov*ab-init +.di cov*ab-div +.par@ab-indent +.par@reset +.if !'\\$1'no' \{\ +. ft I +. ce 1 +\\*[ABSTRACT] +. sp +. ft R +.\} +.ns +.@PP +.. +.de AE +.ie '\\n(.z'cov*ab-div' \{\ +. als AE cov*err-not-again +. br +. di +.\" nr cov*ab-height \\n[dn] +. par@reset-env +. par@reset +. cov*print +.\} +.el .@error AE without AB +.. +.de @div-end!cov*ab-div +.AE +.. +.de cov*print +.als cov*print @nop +.ie d cov*tl-div \{\ +. ie \\n[cov*rp-format] .cov*rp-print +. el .cov*draft-print +.\} +.el \{\ +. if \\n[cov*rp-format] \{\ +. @warning RP format but no TL +. bp 1 +. als FS @FS +. als FE @FE +. \} +. br +.\} +.. +.de cov*rp-print +.nr cov*page-length \\n[.p] +.pl 1000i +.cov*tl-au-print +.sp 3 +.if d cov*ab-div \{\ +. nf +. cov*ab-div +.\} +.sp 3 +.par@reset +\\*[DY] +.br +.if \\n[cov*fn-height] \{\ +. sp |(u;\\n[cov*page-length]-\\n[FM]\ +-\\n[cov*fn-height]-\\n[fn@sep-dist]>?\\n[nl]) +. fn@print-sep +. ev nf +. cov*fn-div +. ev +. ie \\n[cov*rp-no] .rm cov*fn-div +. el \{\ +. rn cov*fn-div fn@overflow-div +. nr fn@have-overflow 1 +. \} +.\} +.als FS @FS +.als FE @FE +.\" If anything was printed below where the footer line is normally printed, +.\" then that's an overflow. +.if -\\n[FM]/2+1v+\\n[cov*page-length]<\\n[nl] .@error cover sheet overflow +.pl \\n[cov*page-length]u +.bp 1 +.if !\\n[cov*rp-no] .cov*tl-au-print +.rs +.sp 1 +.. +.de cov*draft-print +.cov*tl-au-print +.if d cov*ab-div \{\ +. nf +. sp 2 +. cov*ab-div +.\} +.sp 1 +.. +.de cov*tl-au-print +.par@reset +.nf +.rs +.sp 3 +.ce 9999 +.cov*tl-div +.nr cov*i 1 +.nr cov*sp 1v +.while \\n[cov*i]<=\\n[cov*n-au] \{\ +. sp \\n[cov*sp]u +. cov*au-div!\\n[cov*i] +. ie d cov*ai-div!\\n[cov*i] \{\ +. sp .5v +. cov*ai-div!\\n[cov*i] +. nr cov*sp 1v +. \} +. el .nr cov*sp .5v +. nr cov*i +1 +.\} +.ce 0 +.. +.nr cov*fn-height 0 +.nr cov*in-fn 0 +.\" start of footnote on cover +.de cov*FS +.if \\n[cov*in-fn] \{\ +. @error nested FS +. FE +.\} +.nr cov*in-fn 1 +.ev fn +.par@reset-env +.da cov*fn-div +.if !\\n[cov*fn-height] .ns +.ie \\n[.$] .FP "\\$1" no +.el .@LP +.. +.de @div-end!cov*fn-div +.cov*FE +.. +.\" end of footnote on cover +.de cov*FE +.ie '\\n(.z'cov*fn-div' \{\ +. br +. ev +. di +. nr cov*in-fn 0 +. nr cov*fn-height +\\n[dn] +.\} +.el .@error FE without matching FS +.. +.\" *************************** +.\" ******** module pg ******** +.\" *************************** +.\" Page-level formatting. +.\" > 0 if we have a footnote on the current page +.nr pg@fn-flag 0 +.nr pg@colw 0 +.nr pg@fn-colw 0 +.nr HM 1i +.nr FM 1i +.nr PO 1i +.ds LF +.ds CF +.ds RF +.ds LH +.ds CH -\\n[PN]- +.ds RH +.ds pg*OH '\\*[LH]'\\*[CH]'\\*[RH]' +.ds pg*EH '\\*[LH]'\\*[CH]'\\*[RH]' +.ds pg*OF '\\*[LF]'\\*[CF]'\\*[RF]' +.ds pg*EF '\\*[LF]'\\*[CF]'\\*[RF]' +.de OH +.ds pg*\\$0 "\\$* +.. +.als EH OH +.als OF OH +.als EF OH +.de PT +.ie \\n%=1 .if \\n[pg*P1] .tl \\*[pg*OH] +.el \{\ +. ie o .tl \\*[pg*OH] +. el .tl \\*[pg*EH] +.\} +.. +.de BT +.ie o .tl \\*[pg*OF] +.el .tl \\*[pg*EF] +.. +.nr pg*P1 0 +.de P1 +.nr pg*P1 1 +.. +.wh -\n[FM]u pg@bottom +.wh -\n[FM]u/2u pg*footer +.nr MINGW 2n +.nr pg@ncols 1 +.de @MC +.if !'\\n(.z'' .error-recover MC while diversion open +.br +.ie \\n[pg@ncols]>1 .pg@super-eject +.el \{\ +. \" flush out any floating keeps +. while \\n[kp@tail]>\\n[kp@head] \{\ +. rs +. bp +. \} +.\} +.ie !\\n(.$ \{\ +. nr pg@colw \\n[LL]*7/15 +. nr pg*gutw \\n[LL]-(2*\\n[pg@colw]) +. nr pg@ncols 2 +.\} +.el \{\ +. nr pg@colw (n;\\$1)1 \ +. nr pg*gutw \\n[LL]-(\\n[pg@ncols]*\\n[pg@colw])/(\\n[pg@ncols]-1) +. el .nr pg*gutw 0 +.\} +.mk pg*col-top +.ns +.nr pg*col-num 0 +.nr pg@fn-colw \\n[pg@colw]*5/6 +.par@reset +.. +.de 2C +.MC +.. +.de 1C +.MC \\n[LL]u +.. +.\" top of page macro +.de pg@top +.ch pg*footer -\\n[FM]u/2u +.nr PN \\n% +.nr pg*col-num 0 +.nr pg@fn-bottom-margin 0 +.nr pg*saved-po \\n[PO] +.po \\n[PO]u +.ev h +.par@reset +.sp (u;\\n[HM]/2) +.PT +.sp |\\n[HM]u +.if d HD .HD +.mk pg@header-bottom +.ev +.mk pg*col-top +.pg*start-col +.. +.de pg*start-col +.\" Handle footnote overflow before floating keeps, because the keep +.\" might contain an embedded footnote. +.fn@top-hook +.kp@top-hook +.tbl@top-hook +.ns +.. +.de pg@cs-top +.sp \\n[HM]u +.\" move pg@bottom and pg*footer out of the way +.ch pg@bottom \\n[.p]u*2u +.ch pg*footer \\n[.p]u*2u +.ns +.. +.de pg@bottom +.tbl@bottom-hook +.if \\n[pg@fn-flag] .fn@bottom-hook +.nr pg*col-num +1 +.ie \\n[pg*col-num]<\\n[pg@ncols] .pg*end-col +.el .pg*end-page +.. +.de pg*end-col +'sp |\\n[pg*col-top]u +.po (u;\\n[pg*saved-po]+(\\n[pg@colw]+\\n[pg*gutw]*\\n[pg*col-num])) +.\"po +(u;\\n[pg@colw]+\\n[pg*gutw]) +.pg*start-col +.. +.de pg*end-page +.po \\n[pg*saved-po]u +.\" Make sure we don't exit if there are still floats or footnotes left-over. +.ie \\n[kp@head]<\\n[kp@tail]:\\n[fn@have-overflow] \{\ +. \" Switching environments ensures that we don't get an unnecessary +. \" blank line at the top of the page. +. ev ne +' bp +. ev +.\} +.el \{\ +. \" If the text has ended and there are no more footnotes or keeps, exit. +. if \\n[pg@text-ended] .ex +. if r pg*next-number \{\ +. pn \\n[pg*next-number] +. rr pg*next-number +. if d pg*next-format \{\ +. af PN \\*[pg*next-format] +. rm pg*next-format +. \} +. \} +' bp +.\} +.. +.\" pg@begin number format +.de pg@begin +.ie \\n[.$]>0 \{\ +. nr pg*next-number (;\\$1) +. ie \\n[.$]>1 .ds pg*next-format \\$2 +. el .rm pg*next-format +.\} +.el .rr pg*next-number +.pg@super-eject +.. +.\" print the footer line +.de pg*footer +.ev h +.par@reset +.BT +.ev +.. +.\" flush out any keeps or footnotes +.de pg@super-eject +.br +.if !'\\n(.z'' .@error-recover diversion open while ejecting page +.\" Make sure we stay in the end macro while there is still footnote overflow +.\" left, or floating keeps. +.while \\n[kp@tail]>\\n[kp@head]:\\n[pg@fn-flag] \{\ +. rs +. bp +.\} +.bp +.. +.nr pg@text-ended 0 +.de pg@end-text +.br +.nr pg@text-ended 1 +.pg@super-eject +.. +.em pg@end-text +.\" *************************** +.\" ******** module fn ******** +.\" *************************** +.\" Footnotes. +.nr fn@sep-dist 8p +.ev fn +.\" Round it vertically +.vs \n[fn@sep-dist]u +.nr fn@sep-dist \n[.v] +.ev +.nr fn*text-num 0 1 +.nr fn*note-num 0 1 +.ds * \\*[par@sup-start]\En+[fn*text-num]\\*[par@sup-end] +.nr fn*open 0 +.\" normal FS +.de @FS +.ie \\n[.$] .fn*do-FS "\\$1" no +.el \{\ +. ie \\n[fn*text-num]>\\n[fn*note-num] .fn*do-FS \\n+[fn*note-num] +. el .fn*do-FS +.\} +.. +.\" Second argument of `no' means don't embellish the first argument. +.de fn*do-FS +.if \\n[fn*open] .@error-recover nested FS +.nr fn*open 1 +.if \\n[.u] \{\ +. \" Ensure that the first line of the footnote is on the same page +. \" as the reference. I think this is minimal. +. ev fn +. nr fn*need 1v +. ev +. ie \\n[pg@fn-flag] .nr fn*need +\\n[fn:PD] +. el .nr fn*need +\\n[fn@sep-dist] +. ne \\n[fn*need]u+\\n[.V]u>?0 +.\} +.ev fn +.par@reset-env +.fn*start-div +.par@reset +.ie \\n[.$] .FP \\$@ +.el .@LP +.. +.de @FE +.ie !\\n[fn*open] .@error FE without FS +.el \{\ +. nr fn*open 0 +. br +. ev +. fn*end-div +.\} +.. +.nr fn@have-overflow 0 +.\" called at the top of each column +.de fn@top-hook +.nr fn*max-width 0 +.nr fn*page-bottom-pos 0-\\n[FM]-\\n[pg@fn-bottom-margin] +.ch pg@bottom \\n[fn*page-bottom-pos]u +.if \\n[fn@have-overflow] \{\ +. nr fn@have-overflow 0 +. fn*start-div +. ev nf +. fn@overflow-div +. ev +. fn*end-div +.\} +.. +.\" This is called at the bottom of the column if pg@fn-flag is set. +.de fn@bottom-hook +.nr pg@fn-flag 0 +.nr fn@have-overflow 0 +.nr fn@bottom-pos \\n[.p]-\\n[FM]-\\n[pg@fn-bottom-margin]+\\n[.v] +.ev fn +.nr fn@bottom-pos -\\n[.v] +.ev +.ie \\n[nl]+\\n[fn@sep-dist]+\n[.V]>\\n[fn@bottom-pos] \{\ +. rn fn@div fn@overflow-div +. nr fn@have-overflow 1 +.\} +.el \{\ +. if \\n[pg@ncols]>1 \ +. if \\n[fn*max-width]>\\n[pg@fn-colw] \ +. nr pg@fn-bottom-margin \\n[.p]-\\n[FM]-\\n[nl]+1v +. wh \\n[fn@bottom-pos]u fn*catch-overflow +. fn@print-sep +. ev nf +. fn@div +. rm fn@div +. ev +. if '\\n(.z'fn@overflow-div' \{\ +. di +. nr fn@have-overflow \\n[dn]>0 +. \} +. ch fn*catch-overflow +.\} +.. +.de fn*catch-overflow +.di fn@overflow-div +.. +.nr fn*embed-count 0 +.de @div-end!fn@div +.br +.if '\\n[.ev]'fn' .ev +.fn*end-div +.nr fn*open 0 +.. +.als @div-end!fn*embed-div @div-end!fn@div +.de fn*start-div +.ie '\\n(.z'' \{\ +. da fn@div +. if !\\n[pg@fn-flag] .ns +.\} +.el .di fn*embed-div +.. +.de fn*end-div +.ie '\\n(.z'fn@div' \{\ +. di +. nr fn*page-bottom-pos -\\n[dn] +. nr fn*max-width \\n[fn*max-width]>?\\n[dl] +. if !\\n[pg@fn-flag] .nr fn*page-bottom-pos -\\n[fn@sep-dist] +. nr pg@fn-flag 1 +. nr fn*page-bottom-pos \\n[nl]-\\n[.p]+\n[.V]>?\\n[fn*page-bottom-pos] +. ch pg@bottom \\n[fn*page-bottom-pos]u +.\} +.el \{\ +. ie '\\n(.z'fn*embed-div' \{\ +. di +. rn fn*embed-div fn*embed-div!\\n[fn*embed-count] +\!. fn*embed-start \\n[fn*embed-count] +. rs +' sp (u;\\n[dn]+\\n[fn@sep-dist]+\\n[.V]) +\!. fn*embed-end +. nr fn*embed-count +1 +. \} +. el \{\ +. ev fn +. @error-recover unclosed diversion within footnote +. \} +.\} +.. +.de fn*embed-start +.ie '\\n(.z'' \{\ +. fn*start-div +. ev nf +. fn*embed-div!\\$1 +. rm fn*embed-div!\\$1 +. ev +. fn*end-div +. di fn*null +.\} +.el \{\ +\!. fn*embed-start \\$1 +. rs +.\} +.. +.de fn*embed-end +.ie '\\n(.z'fn*null' \{\ +. di +. rm fn*null +.\} +.el \!.fn*embed-end +.. +.\" It's important that fn@print-sep use up exactly fn@sep-dist vertical space. +.de fn@print-sep +.ev fn +.in 0 +.vs \\n[fn@sep-dist]u +\D'l 1i 0' +.br +.ev +.. +.\" *************************** +.\" ******** module kp ******** +.\" *************************** +.\" Keeps. +.de KS +.br +.di kp*div +.. +.de KF +.if !'\\n(.z'' .@error-recover KF while open diversion +.di kp*fdiv +.ev k +.par@reset-env +.par@reset +.. +.de KE +.ie '\\n(.z'kp*div' .kp*end +.el \{\ +. ie '\\n(.z'kp*fdiv' .kp*fend +. el .@error KE without KS or KF +.\} +.. +.de @div-end!kp*div +.kp*end +.. +.de @div-end!kp*fdiv +.kp*fend +.. +.de kp*need +.ie '\\n(.z'' .ds@need \\$1 +.el \!.kp*need \\$1 +.. +.\" end non-floating keep +.de kp*end +.br +.di +.kp*need \\n[dn] +.ev nf +.kp*div +.ev +.rm kp*div +.. +.\" Floating keeps. +.nr kp@head 0 +.nr kp@tail 0 +.\" end floating keep +.de kp*fend +.br +.ev +.di +.ie \\n[.t]-(\\n[.k]>0*1v)>\\n[dn] \{\ +. br +. ev nf +. kp*fdiv +. rm kp*fdiv +. ev +.\} +.el \{\ +. rn kp*fdiv kp*div!\\n[kp@tail] +. nr kp*ht!\\n[kp@tail] 0\\n[dn] +. nr kp@tail +1 +.\} +.. +.\" top of page processing for KF +.nr kp*doing-top 0 +.de kp@top-hook +.if !\\n[kp*doing-top] \{\ +. nr kp*doing-top 1 +. kp*do-top +. nr kp*doing-top 0 +.\} +.. +.de kp*do-top +.\" If the first keep won't fit, only force it out if we haven't had a footnote +.\" and we're at the top of the page. +.nr kp*force \\n[pg@fn-flag]=0&(\\n[nl]<=\\n[pg@header-bottom]) +.nr kp*fits 1 +.while \\n[kp@tail]>\\n[kp@head]&\\n[kp*fits] \{\ +. ie \\n[.t]>\\n[kp*ht!\\n[kp@head]]:\\n[kp*force] \{\ +. nr kp*force 0 +. \" It's important to advance kp@head before bringing +. \" back the keep, so that if the last line of the +. \" last keep springs the bottom of page trap, a new +. \" page will not be started unnecessarily. +. rn kp*div!\\n[kp@head] kp*temp +. nr kp@head +1 +. ev nf +. kp*temp +. ev +. rm kp*temp +. \} +. el .nr kp*fits 0 +.\} +.. +.\" *************************** +.\" ******** module ds ******** +.\" *************************** +.\" Displays and non-floating keeps. +.de DE +.ds*end!\\n[\\n[.ev]:ds-type] +.nr \\n[.ev]:ds-type 0 +.. +.de ds@auto-end +.if \\n[\\n[.ev]:ds-type] \{\ +. @error automatically terminating display +. DE +.\} +.. +.de @div-end!ds*div +.ie \\n[\\n[.ev]:ds-type] .DE +.el .ds*end!2 +.. +.de ds*end!0 +.@error DE without DS, ID, CD, LD or BD +.. +.de LD +.br +.nr \\n[.ev]:ds-type 1 +.par@reset +.nf +.sp \\n[DD]u +.. +.de ID +.LD +.ie \\n[.$] .in +(n;\\$1) +.el .in +\\n[DI]u +.. +.de CD +.LD +.ce 9999 +.. +.de RD +.LD +.rj 9999 +.. +.de ds*common-end +.par@reset +.sp \\n[DD]u +.. +.als ds*end!1 ds*common-end +.de BD +.LD +.nr \\n[.ev]:ds-type 2 +.di ds*div +.. +.de ds*end!2 +.br +.ie '\\n(.z'ds*div' \{\ +. di +. nf +. in (u;\\n[.l]-\\n[dl]/2) +. ds*div +. rm ds*div +. ds*common-end +.\} +.el .@error-recover mismatched DE +.. +.de DS +.br +.di ds*div +.ie '\\$1'B' \{\ +. LD +. nr \\n[.ev]:ds-type 4 +.\} +.el \{\ +. ie '\\$1'L' .LD +. el \{\ +. ie '\\$1'C' .CD +. el \{\ +. ie '\\$1'R' .RD +. el \{\ +. ie '\\$1'I' .ID \\$2 +. el .ID \\$1 +. \} +. \} +. \} +. nr \\n[.ev]:ds-type 3 +.\} +.. +.de ds@need +.if '\\n(.z'' \{\ +. while \\n[.t]<=(\\$1)&(\\n[nl]>\\n[pg@header-bottom]) \{\ +. rs +' sp \\n[.t]u +. \} +.\} +.. +.de ds*end!3 +.br +.ie '\\n(.z'ds*div' \{\ +. di +. ds@need \\n[dn] +. ev nf +. ds*div +. ev +. rm ds*div +. ds*common-end +.\} +.el .@error-recover mismatched DE +.. +.de ds*end!4 +.ie '\\n(.z'ds*div' \{\ +. br +. di +. nf +. in (u;\\n[.l]-\\n[dl]/2) +. ds@need \\n[dn] +. ds*div +. rm ds*div +. ds*common-end +.\} +.el .@error-recover mismatched DE +.. +.\" **************************** +.\" ******** module par ******** +.\" **************************** +.\" Paragraph-level formatting. +.nr PS 10 +.nr LL 6i +.de par*vs +.\" If it's too big to be in points, treat it as units. +.ie (p;\\$1)>=40p .vs (u;\\$1) +.el .vs (p;\\$1) +.. +.de par@ab-indent +.nr 0:li (u;\\n[LL]/12) +.nr 0:ri \\n[0:li] +.. +.de par*env-init +.aln \\n[.ev]:PS PS +.aln \\n[.ev]:VS VS +.aln \\n[.ev]:LL LL +.aln \\n[.ev]:MCLL LL +.aln \\n[.ev]:LT LT +.aln \\n[.ev]:MCLT LT +.aln \\n[.ev]:PI PI +.aln \\n[.ev]:PD PD +.ad \\n[par*adj] +.par@reset-env +.. +.\" happens when the first page begins +.de par@init +.if !rLT .nr LT \\n[LL] +.if !rFL .nr FL \\n[LL]*5/6 +.if !rVS .nr VS \\n[PS]+2 +.ps \\n[PS] +.if !rDI .nr DI .5i +.if !rQI .nr QI 5n +.if !rPI .nr PI 5n +.par*vs \\n[VS] +.if !rPD .nr PD .3v>?\n(.V +.if !rDD .nr DD .5v>?\n(.V +.if !dFAM .ds FAM \\n[.fam] +.nr par*adj \\n[.j] +.par*env-init +.ev h +.par*env-init +.ev +.ev fn +.par*env-init +.ev +.ev k +.par*env-init +.ev +.aln 0:MCLL pg@colw +.aln 0:MCLT pg@colw +.aln k:MCLL pg@colw +.aln k:MCLT pg@colw +.if !rFPS .nr FPS \\n[PS]-2 +.if !rFVS .nr FVS \\n[FPS]+2 +.if !rFI .nr FI 2n +.if !rFPD .nr FPD \\n[PD]/2 +.aln fn:PS FPS +.aln fn:VS FVS +.aln fn:LL FL +.aln fn:LT FL +.aln fn:PI FI +.aln fn:PD FPD +.aln fn:MCLL pg@fn-colw +.aln fn:MCLT pg@fn-colw +.. +.de par@reset-env +.nr \\n[.ev]:il 0 +.nr \\n[.ev]:li 0 +.nr \\n[.ev]:ri 0 +.nr \\n[.ev]:ai \\n[\\n[.ev]:PI] +.nr \\n[.ev]:pli 0 +.nr \\n[.ev]:pri 0 +.nr \\n[.ev]:ds-type 0 +.. +.\" par@reset +.de par@reset +.br +.ce 0 +.rj 0 +.ul 0 +.fi +.ie \\n[pg@ncols]>1 \{\ +. ll (u;\\n[\\n[.ev]:MCLL]-\\n[\\n[.ev]:ri]-\\n[\\n[.ev]:pri]) +. lt \\n[\\n[.ev]:MCLT]u +.\} +.el \{\ +. ll (u;\\n[\\n[.ev]:LL]-\\n[\\n[.ev]:ri]-\\n[\\n[.ev]:pri]) +. lt \\n[\\n[.ev]:LT]u +.\} +.in (u;\\n[\\n[.ev]:li]+\\n[\\n[.ev]:pli]) +.ft 1 +.fam \\*[FAM] +.ps \\n[\\n[.ev]:PS] +.par*vs \\n[\\n[.ev]:VS] +.ls 1 +.TA +.hy 14 +.. +.als @RT par@reset +.\" This can be redefined by the user. +.de TA +.ta T 5n +.. +.de par*start +.ds@auto-end +.nr \\n[.ev]:pli \\$1 +.nr \\n[.ev]:pri \\$2 +.par@reset +.sp \\n[\\n[.ev]:PD]u +.ne 1v+\\n(.Vu +.. +.de par@finish +.nr \\n[.ev]:pli 0 +.nr \\n[.ev]:pri 0 +.par@reset +.. +.\" normal LP +.de @LP +.par*start 0 0 +.nr \\n[.ev]:ai \\n[\\n[.ev]:PI] +.. +.de @PP +.par*start 0 0 +.nr \\n[.ev]:ai \\n[\\n[.ev]:PI] +.ti +\\n[\\n[.ev]:ai]u +.. +.de @QP +.nr \\n[.ev]:ai \\n[\\n[.ev]:PI] +.par*start \\n[QI] \\n[QI] +.. +.de @XP +.par*start \\n[\\n[.ev]:PI] 0 +.ti -\\n[\\n[.ev]:PI]u +.. +.de @IP +.if \\n[.$]>1 .nr \\n[.ev]:ai (n;\\$2) +.par*start \\n[\\n[.ev]:ai] 0 +.if !'\\$1'' \{\ +. \" Divert the label so as to freeze any spaces. +. di par*label +. in 0 +. nf +\&\\$1 +. di +. in +. fi +. chop par*label +. ti -\\n[\\n[.ev]:ai]u +. ie \\n[dl]+1n<=\\n[\\n[.ev]:ai] \\*[par*label]\h'|\\n[\\n[.ev]:ai]u'\c +. el \{\ +\\*[par*label] +. br +. \} +. rm par*label +.\} +.. +.de @RS +.br +.nr \\n[.ev]:li!\\n[\\n[.ev]:il] \\n[\\n[.ev]:li] +.nr \\n[.ev]:ri!\\n[\\n[.ev]:il] \\n[\\n[.ev]:ri] +.nr \\n[.ev]:ai!\\n[\\n[.ev]:il] \\n[\\n[.ev]:ai] +.nr \\n[.ev]:pli!\\n[\\n[.ev]:il] \\n[\\n[.ev]:pli] +.nr \\n[.ev]:pri!\\n[\\n[.ev]:il] \\n[\\n[.ev]:pri] +.nr \\n[.ev]:il +1 +.nr \\n[.ev]:li +\\n[\\n[.ev]:ai] +.nr \\n[.ev]:ai \\n[\\n[.ev]:PI] +.par@reset +.. +.de @RE +.br +.ie \\n[\\n[.ev]:il] \{\ +. nr \\n[.ev]:il -1 +. nr \\n[.ev]:ai \\n[\\n[.ev]:ai!\\n[\\n[.ev]:il]] +. nr \\n[.ev]:li \\n[\\n[.ev]:li!\\n[\\n[.ev]:il]] +. nr \\n[.ev]:ri \\n[\\n[.ev]:ri!\\n[\\n[.ev]:il]] +. nr \\n[.ev]:pli \\n[\\n[.ev]:pli!\\n[\\n[.ev]:il]] +. nr \\n[.ev]:pri \\n[\\n[.ev]:pri!\\n[\\n[.ev]:il]] +.\} +.el .@error unbalanced \\$0 +.par@reset +.. +.de @QS +.br +.nr \\n[.ev]:li!\\n[\\n[.ev]:il] \\n[\\n[.ev]:li] +.nr \\n[.ev]:ri!\\n[\\n[.ev]:il] \\n[\\n[.ev]:ri] +.nr \\n[.ev]:ai!\\n[\\n[.ev]:il] \\n[\\n[.ev]:ai] +.nr \\n[.ev]:pli!\\n[\\n[.ev]:il] \\n[\\n[.ev]:pli] +.nr \\n[.ev]:pri!\\n[\\n[.ev]:il] \\n[\\n[.ev]:pri] +.nr \\n[.ev]:il +1 +.nr \\n[.ev]:li +\\n[QI] +.nr \\n[.ev]:ri +\\n[QI] +.nr \\n[.ev]:ai \\n[\\n[.ev]:PI] +.par@reset +.. +.als @QE @RE +.\" start boxed text +.de B1 +.br +.di par*box-div +.nr \\n[.ev]:li +1n +.nr \\n[.ev]:ri +1n +.par@reset +.. +.de @div-end!par*box-div +.B2 +.. +.\" end boxed text +.\" Postpone the drawing of the box until we're in the top-level diversion, +.\" in case there's a footnote inside the box. +.de B2 +.ie '\\n(.z'par*box-div' \{\ +. br +. di +. ds@need \\n[dn] +. par*box-mark-top +. ev nf +. par*box-div +. ev +. nr \\n[.ev]:ri -1n +. nr \\n[.ev]:li -1n +. par@finish +. par*box-draw \\n[.i]u \\n[.l]u +.\} +.el .@error B2 without B1 +.. +.de par*box-mark-top +.ie '\\n[.z]'' .mk par*box-top +.el \!.par*box-mark-top +.. +.de par*box-draw +.ie '\\n[.z]'' \{\ +. nr par*box-in \\n[.i] +. nr par*box-ll \\n[.l] +. nr par*box-vpt \\n[.vpt] +. vpt 0 +. in \\$1 +. ll \\$2 +\v'-1v+.25m'\ +\D'l (u;\\n[.l]-\\n[.i]) 0'\ +\D'l 0 |\\n[par*box-top]u'\ +\D'l -(u;\\n[.l]-\\n[.i]) 0'\ +\D'l 0 -|\\n[par*box-top]u' +. br +. sp -1 +. in \\n[par*box-in]u +. ll \\n[par*box-ll]u +. vpt \\n[par*box-vpt] +.\} +.el \!.par*box-draw \\$1 \\$2 +.. +.de @SH +.par@finish +.\" Keep together the heading and the first two lines of the next paragraph. +.ne 3v+\\n[\\n[.ev]:PD]u+\\n(.Vu +.sp 1 +.ft B +.. +.\" TL, AU, and AI are aliased to these in cov*ab-init. +.de par@TL +.par@finish +.sp 1 +.ft B +.ps +2 +.vs +3p +.ce 9999 +.. +.de par@AU +.par@finish +.sp 1 +.ft I +.ce 9999 +.. +.de par@AI +.par@finish +.sp .5 +.ce 9999 +.. +.\" In paragraph macros. +.de NL +.ps \\n[\\n[.ev]:PS] +.. +.de SM +.ps -2 +.. +.de LG +.ps +2 +.. +.de R +.ft R +.. +.\" par*define-font-macro macro font +.de par*define-font-macro +.de \\$1 +.ie \\\\n[.$] \{\ +. nr par*prev-font \\\\n[.f] +\&\\\\$3\f[\\$2]\\\\$1\f[\\\\n[par*prev-font]]\\\\$2 +.\} +.el .ft \\$2 +\\.. +.. +.par*define-font-macro B B +.par*define-font-macro I I +.par*define-font-macro BI BI +.par*define-font-macro CW CR +.\" underline a word +.de UL +\Z'\\$1'\v'.25m'\D'l \w'\\$1'u 0'\v'-.25m'\\$2 +.. +.\" box a word +.de BX +.nr par*bxw \w'\\$1'+.4m +\Z'\v'.25m'\D'l 0 -1m'\D'l \\n[par*bxw]u 0'\D'l 0 1m'\D'l -\\n[par*bxw]u 0''\ +\Z'\h'.2m'\\$1'\ +\h'\\n[par*bxw]u' +.. +.\" The first time UX is used, put a registered mark after it. +.ds par*ux-rg \(rg +.de UX +\s[\\n[.s]*8u/10u]UNIX\s0\\$1\\*[par*ux-rg] +.ds par*ux-rg +.. +.ds par@sup-start \v'-.9m\s'\En[.s]*7u/10u'+.7m' +.als { par@sup-start +.ds par@sup-end \v'-.7m\s0+.9m' +.als } par@sup-end +.\" footnote paragraphs +.\" FF is the footnote format +.nr FF 0 +.\" This can be redefined. It gets a second argument of `no' if the first +.\" argument was supplied by the user, rather than automatically. +.de FP +.br +.if !d par*fp!\\n[FF] \{\ +. @error unknown footnote format `\\n[FF]' +. nr FF 0 +.\} +.ie '\\$2'no' .par*fp!\\n[FF]-no "\\$1" +.el .par*fp!\\n[FF] "\\$1" +.. +.de par*fp!0 +.@PP +\&\\*[par@sup-start]\\$1\\*[par@sup-end]\ \c +.. +.de par*fp!0-no +.@PP +\&\\$1\ \c +.. +.de par*fp!1 +.@PP +\&\\$1.\ \c +.. +.de par*fp!1-no +.@PP +\&\\$1\ \c +.. +.de par*fp!2 +.@LP +\&\\$1.\ \c +.. +.de par*fp!2-no +.@LP +\&\\$1\ \c +.. +.de par*fp!3 +.@IP "\\$1." (u;\\n[\\n[.ev]:PI]*2) +.. +.de par*fp!3-no +.@IP "\\$1" (u;\\n[\\n[.ev]:PI]*2) +.. +.\" *************************** +.\" ******** module nh ******** +.\" *************************** +.\" Numbered headings. +.\" nh*hl is the level of the last heading +.nr nh*hl 0 +.\" numbered heading +.de @NH +.ie '\\$1'S' \{\ +. shift +. nr nh*hl 0 +. while \\n[.$] \{\ +. nr nh*hl +1 +. nr H\\n[nh*hl] 0\\$1 +. shift +. \} +. if !\\n[nh*hl] \{\ +. nr H1 1 +. nr nh*hl 1 +. @error missing arguments to .NH S +. \} +.\} +.el \{\ +. nr nh*ohl \\n[nh*hl] +. ie \\n[.$] \{\ +. nr nh*hl 0\\$1 +. ie \\n[nh*hl]<=0 \{\ +. nr nh*ohl 0 +. nr nh*hl 1 +. \} +. el \{\ +. if \\n[nh*hl]-\\n[nh*ohl]>1 \ +. @warning .NH \\n[nh*ohl] followed by .NH \\n[nh*hl] +. \} +. \} +. el .nr nh*hl 1 +. while \\n[nh*hl]>\\n[nh*ohl] \{\ +. nr nh*ohl +1 +. nr H\\n[nh*ohl] 0 +. \} +. nr H\\n[nh*hl] +1 +.\} +.ds SN +.nr nh*i 0 +.while \\n[nh*i]<\\n[nh*hl] \{\ +. nr nh*i +1 +. as SN \\n[H\\n[nh*i]]. +.\} +.SH +\\*[SN] +.. +.\" **************************** +.\" ******** module toc ******** +.\" **************************** +.\" Table of contents generation. +.de @XS +.da toc*div +.ev h +.ie \\n[.$] .XA "\\$1" +.el .XA +.. +.de @div-end!toc*div +.XE +.. +.de XA +.ie '\\n(.z'toc*div' \{\ +. if d toc*num .toc*end-entry +. ie \\n[.$] \{\ +. ie '\\$1'no' .ds toc*num +. el .ds toc*num "\\$1 +. \} +. el .ds toc*num \\n[PN] +. LP +. na +. ll -8n +. in (n;0\\$2) +.\} +.el .@error XA without XS +.. +.de XE +.ie '\\n(.z'toc*div' \{\ +. if d toc*num .toc*end-entry +. ev +. di +.\} +.el .@error XS without XE +.. +.de toc*end-entry +\\a\\t\\*[toc*num] +.br +.rm toc*num +.. +.de PX +.1C +.if !'\\$1'no' \{\ +. ce 1 +. ps \\n[PS]+2 +. ft B +\\*[TOC] +. ft +. ps +.\} +.nf +.char \[toc*leader-char] .\h'1m' +.lc \[toc*leader-char] +.ta (u;\\n[.l]-\\n[.i]-\w'000') (u;\\n[.l]-\\n[.i])R +.sp 2 +.toc*div +.par@reset +.. +.\" print the table of contents on page i +.de TC +.P1 +.pg@begin 1 i +.PX \\$1 +.. +.\" **************************** +.\" ******** module eqn ******** +.\" **************************** +.\" Eqn support. +.de EQ +.. +.de EN +.. +.de @EQ +.br +.ds eqn*num "\\$2 +.ie '\\$1'L' .nr eqn*type 0 +.el \{\ +. ie '\\$1'I' .nr eqn*type 1 +. el \{\ +. nr eqn*type 2 +. if !'\\$1'C' .ds eqn*num "\\$1 +. \} +.\} +.di eqn*div +.in 0 +.nf +.. +.de @div-end!eqn*div +.@EN +.. +.\" Note that geqn mark and lineup work correctly in centered equations. +.de @EN +.ie !'\\n(.z'eqn*div' .@error-recover mismatched EN +.el \{\ +. br +. di +. nr eqn*have-num 0 +. if !'\\*[eqn*num]'' .nr eqn*have-num 1 +. if \\n[dl]:\\n[eqn*have-num] \{\ +. sp \\n[DD]u +. par@reset +. ds eqn*tabs \\n[.tabs] +. nf +. ie \\n[dl] \{\ +. ds@need \\n[dn]u-1v+\n[.V]u +. chop eqn*div +. ie \\n[eqn*type]=0 \{\ +. ta (u;\\n[.l]-\\n[.i])R +\\*[eqn*div]\t\\*[eqn*num] +. \} +. el \{\ +. ie \\n[eqn*type]=1 .ta \\n[DI]u \ +(u;\\n[.l]-\\n[.i])R +. el .ta (u;\\n[.l]-\\n[.i]/2)C \ +(u;\\n[.l]-\\n[.i])R +\t\\*[eqn*div]\t\\*[eqn*num] +. \} +. \} +. el \{\ +. ta (u;\\n[.l]-\\n[.i])R +\t\\*[eqn*num] +. \} +. sp \\n[DD]u +. fi +. ta \\*[eqn*tabs] +. \} +.\} +.. +.\" **************************** +.\" ******** module tbl ******** +.\" **************************** +.\" Tbl support. +.nr tbl*have-header 0 +.de TS +.\" The break is necessary in the case where the first page has not yet begun. +.br +.sp \\n[DD]u +.if '\\$1'H' .di tbl*header-div +.. +.de tbl@top-hook +.if \\n[tbl*have-header] \{\ +. ie \\n[.t]-\\n[tbl*header-ht]-1v .tbl*print-header +. el .sp \\n[.t]u +.\} +.. +.de tbl*print-header +.ev nf +.tbl*header-div +.ev +.mk #T +.. +.de TH +.ie '\\n[.z]'tbl*header-div' \{\ +. nr T. 0 +. T# +. br +. di +. ie \\n[dn]+\\n[FM]+\\n[HM]+2v>=\\n[.p] \{\ +. @error ridiculously long table header +. ds@need \\n[dn] +. tbl*print-header +. \} +. el \{\ +. nr tbl*header-ht \\n[dn] +. ds@need \\n[dn]u+1v +. tbl*print-header +. nr tbl*have-header 1 +. \} +.\} +.el .@error-recover .TH without .TS H +.. +.de @div-end!tbl*header-div +.TH +.TE +.. +.de TE +.ie '\\n(.z'tbl*header-div' .@error-recover .TS H but no .TH before .TE +.el \{\ +. nr tbl*have-header 0 +. sp \\n[DD]u +.\} +.\" reset tabs +.TA +.. +.de tbl@bottom-hook +.if \\n[tbl*have-header] \{\ +. nr T. 1 +. T# +.\} +.. +.de T& +.. +.\" **************************** +.\" ******** module pic ******** +.\" **************************** +.\" Pic support. +.\" PS height width +.de PS +.br +.sp \\n[DD]u +.ie \\n[.$]<2 .@error bad arguments to PS (not preprocessed with pic?) +.el \{\ +. ds@need (u;\\$1)+1v +. in +(u;\\n[.l]-\\n[.i]-\\$2/2>?0) +.\} +.. +.de PE +.par@reset +.sp \\n[DD]u+.5m +.. +.\" **************************** +.\" ******** module ref ******** +.\" **************************** +.\" Refer support. +.de ]- +.rm [A [B [C [D [E [G [I [J [N [O [P [Q [R [S [T [V +.rm ref*string +.. +.\" Other +.ds ref*spec!0 Q A T1 S V N P I C D O +.\" Journal article +.ds ref*spec!1 Q A T2 J S V N P I C D O +.\" Book +.ds ref*spec!2 Q A T1 S V P I C D O +.\" Article within book +.ds ref*spec!3 Q A T2 B E S V P I C D O +.\" Tech report +.ds ref*spec!4 Q A T2 R G P I C D O +.\" ][ type +.de ][ +.if r [T \{\ +. als [T1 [T +. als [T2 [T +.\} +.ie d ref*spec!\\$1 .ref*build \\*[ref*spec!\\$1] +.el \{\ +. @error unknown reference type `\\$1' +. ref*build \\*[ref*spec!0] +.\} +.ref*print +.rm ref*string +.rm [F [T1 [T2 +.. +.\" start of reference number +.ds [. \\*[par@sup-start] +.\" end of reference number +.ds .] \\*[par@sup-end] +.\" period before reference +.ds <. . +.\" period after reference +.ds >. \" empty +.\" comma before reference +.ds <, , +.\" comma after reference +.ds >, \" empty +.\" start collected references +.de ]< +.als ref*print ref*end-print +.SH +\&\\*[REFERENCES] +.par@reset +.. +.\" end collected references +.de ]> +.par@finish +.als ref*print ref*normal-print +.. +.de ref*normal-print +.ie d [F .FS "\\*([.\\*([F\\*(.]" +.el .FS \& +\\*[ref*string] +.FE +.. +.de ref*end-print +.ie d [F .IP "\\*([F." +.el .XP +\\*[ref*string] +.. +.als ref*print ref*normal-print +.de ref*build +.rm ref*string ref*post-punct +.nr ref*suppress-period 1 +.while \\n[.$] \{\ +. if d [\\$1 \{\ +. ie d ref*add-\\$1 .ref*add-\\$1 +. el .ref*add-dflt \\$1 +. \} +. shift +.\} +.\" now add a final period +.ie d ref*string \{\ +. if !\\n[ref*suppress-period] .as ref*string . +. if d ref*post-punct \{\ +. as ref*string "\\*[ref*post-punct] +. rm ref*post-punct +. \} +.\} +.el .ds ref*string +.. +.de ref*add-T1 +.ref*field T , "\fI" "" "\fP" +.if r [T .nr ref*suppress-period \\n([T +.. +.de ref*add-T2 +.ref*field T , "\\*Q" "" "\\*U" +.if r [T .nr ref*suppress-period \\n([T +.. +.de ref*add-P +.ie \\n([P>0 .ref*field P , "pp. " +.el .ref*field P , "p. " +.. +.de ref*add-J +.ref*field J , \fI "" \fP +.. +.de ref*add-D +.ref*field D "" ( ) +.. +.de ref*add-E +.ref*field E , "ed. " +.. +.de ref*add-G +.ref*field G "" ( ) +.. +.de ref*add-B +.ref*field B "" "in \fI" "" \fP +.. +.de ref*add-O +.ref*field O . +.ie r [O .nr ref*suppress-period \\n([O +.el .nr ref*suppress-period 1 +.. +.de ref*add-A +.ref*field A , +.if r [A .nr ref*suppress-period \\n([A +.. +.de ref*add-dflt +.ref*field \\$1 , +.. +.\" First argument is the field letter. +.\" Second argument is the punctuation character to use to separate this field +.\" from the previous field. +.\" Third argument is a string with which to prefix this field. +.\" Fourth argument is a string with which to postfix this field. +.\" Fifth argument is a string to add after the punctuation character supplied +.\" by the next field. +.de ref*field +.if d ref*string \{\ +. ie d ref*post-punct \{\ +. as ref*string "\\$2\\*[ref*post-punct] \" +. rm ref*post-punct +. \} +. el .as ref*string "\\$2 \" +.\} +.as ref*string "\\$3\\*([\\$1\\$4 +.if \\n[.$]>4 .ds ref*post-punct "\\$5 +.nr ref*suppress-period 0 +.. +.\" **************************** +.\" ******** module acc ******** +.\" **************************** +.\" Accents and special characters. +.ds Q \(lq +.ds U \(rq +.ds - \(em +.\" Characters +.\" The idea of this definition is for the top of the 3 to be at the x-height. +.if !c\[yogh] .char \[yogh] \Z'\v'\w'x'*0-\En[rst]u'\s[\En[.s]*8u/10u]\ +\v'\w'3'*0+\En[rst]u'3\s0'\h'\w'\s[\En[.s]*8u/10u]3'u' +.\" Accents +.de acc*over-def +.ds \\$1 \Z'\v'(u;\w'x'*0+\En[rst]-\En[.cht])'\ +\h'(u;-\En[skw]+(-\En[.w]-\w'\\$2'/2)+\En[.csk])'\\$2' +.. +.de acc*under-def +.ds \\$1 \Z'\v'\En[.cdp]u'\h'(u;-\En[.w]-\w'\\$2'/2)'\\$2' +.. +.de acc*slash-def +.ds \\$1 \Z'\h'(u;-\En[.w]-\w'\\$2'/2)'\ +\v'(u;\En[.cdp]-\En[.cht]+\En[rst]+\En[rsb]/2)'\\$2' +.. +.de acc*prefix-def +.ds \\$1 \Z'\h'(u;\w'x'-\w'\\$2'/2)'\\$2' +.. +.acc*prefix-def ' \' +.acc*prefix-def ` \` +.acc*prefix-def ^ ^ +.acc*prefix-def , \(ac +.acc*prefix-def : \(ad +.acc*prefix-def ~ ~ +.\" improved accent marks +.de AM +.acc*over-def ' \' +.acc*over-def ` \` +.acc*over-def ^ ^ +.acc*over-def ~ ~ +.acc*over-def : \(ad +.acc*over-def v \(ah +.acc*over-def _ \(a- +.acc*over-def o \(ao +.acc*under-def , \(ac +.acc*under-def . \s[\En[.s]*8u/10u]\v'.2m'.\v'-.2m'\s0 +.acc*under-def hook \(ho +.acc*slash-def / / +.char \[hooko] o\\\\*[hook] +.ds q \[hooko] +.ds 3 \[yogh] +.ds D- \(-D\" Icelandic uppercase eth +.ds d- \(Sd\" Icelandic lowercase eth +.ds Th \(TP\" Icelandic uppercase thorn +.ds th \(Tp\" Icelandic lowercase thorn +.ds 8 \(ss\" German double s +.ds Ae \(AE\" AE ligature +.ds ae \(ae\" ae ligature +.ds Oe \(OE\" OE ligature +.ds oe \(oe\" oe ligature +.ds ? \(r?\" upside down ? +.ds ! \(r!\" upside down ! +.. +.\" Make sure that no blank lines creep in at the end of this file. diff --git a/gnu/usr.bin/groff/tmac/tmac.tty b/gnu/usr.bin/groff/tmac/tmac.tty new file mode 100644 index 0000000000..4d5193fe3a --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.tty @@ -0,0 +1,48 @@ +.nr _C \n(.C +.cp 0 +.nroff +.ftr CW B +.ftr C B +.ftr CR B +.po 0 +.if c\[char173] .shc \[char173] +.de tty-char +.if !c\\$1 .char \\$1 "\\$2 +.. +.if c\(md .tr \(bu\(md +.tty-char \(bu \z+o +.tty-char \(14 1/4 +.tty-char \(12 1/2 +.tty-char \(34 3/4 +.tty-char \(ff ff +.tty-char \(fi fi +.tty-char \(fl fl +.tty-char \(Fi ffi +.tty-char \(Fl ffl +.tty-char \(<- <- +.tty-char \(-> -> +.tty-char \(<> <-> +.tty-char \(em -- +.tty-char \(+- +- +.tty-char \(co (C) +.tty-char \(<= <= +.tty-char \(>= >= +.tty-char \(!= != +.tty-char \(== == +.tty-char \(~= ~= +.tty-char \(sq [] +.tty-char \(lh <= +.tty-char \(rh => +.tty-char \(lA <= +.tty-char \(rA => +.tty-char \(hA <=> +.tty-char \(rg (R) +.tty-char \(OE OE +.tty-char \(oe oe +.tty-char \(AE AE +.tty-char \(ae ae +.tty-char \(an - +.cp \n(_C +.\" If you want the character definitions in tmac.tty-char to be loaded +.\" automatically, remove the `\"' from the next line. +.\"do mso tmac.tty-char diff --git a/gnu/usr.bin/groff/tmac/tmac.tty-char b/gnu/usr.bin/groff/tmac/tmac.tty-char new file mode 100644 index 0000000000..9815e6c0f0 --- /dev/null +++ b/gnu/usr.bin/groff/tmac/tmac.tty-char @@ -0,0 +1,196 @@ +.\" This file defines standard troff characters and some groff characters for +.\" use with -Tascii and -Tlatin1. +.\" +.\" These definitions are chosen so that, as far as possible, they: +.\" - work with both -Tascii and -Tlatin1. +.\" - work on devices that display only the last overstruck character +.\" as well as on devices that support overstriking +.\" - represent the character's graphical shape (not its meaning) +.\" +.nr _C \n(.C +.cp 0 +.de tty-char +.if !c\\$1 .char \\$1 "\\$2 +.. +.ie c\(a- .ds tty-rn \(a- +.el .ds tty-rn \v'-1m'_\v'+1m' +.tty-char \(tm tm +.tty-char \(rn \*[tty-rn] +.tty-char \(ua \z|^ +.tty-char \(da \z|v +.tty-char \(sc S +.tty-char \(ct \z/c +.tty-char \(dg \z|- +.tty-char \(dd \z|= +.tty-char \(ib (\z=_ +.tty-char \(ip \z=_) +.tty-char \(sb (= +.tty-char \(sp =) +.tty-char \(if oo +.tty-char \(pt oc +.tty-char \(es {} +.tty-char \(ca (^) +.tty-char \(cu U +.tty-char \(de o +.tty-char \(di -:- +.tty-char \(no ~ +.tty-char \(gr \Z'\*[tty-rn]'V +.tty-char \(is \z'\z,I +.tty-char \(mo E +.tty-char \(pd a +.tty-char \(sr \e/ +.tty-char \(*C \z_H +.tty-char \(*D \z_/\z_\e +.tty-char \(*F \zIO +.tty-char \(*G |\*[tty-rn] +.tty-char \(*H \z-O +.tty-char \(*L /\e +.tty-char \(*P TT +.tty-char \(*Q \zIY +.tty-char \(*S \z_\Z'\*[tty-rn]'> +.tty-char \(*W \z_O +.if c\(ss .tty-char \(*b \(ss +.tty-char \(*b B +.tty-char \(*a a +.tty-char \(*c \z,E +.tty-char \(*d d +.tty-char \(*e e +.tty-char \(*f \z|o +.tty-char \(+f \z|o +.tty-char \(*g y +.tty-char \(*h \z-0 +.tty-char \(+h \z-0 +.tty-char \(*i i +.tty-char \(*k k +.tty-char \(*l \z>\e +.tty-char \(*m \z,u +.tty-char \(*n v +.tty-char \(*p \z-n +.tty-char \(+p \z-w +.tty-char \(*q \z|u +.tty-char \(*r p +.tty-char \(*s \z-o +.tty-char \(*t \z~t +.tty-char \(*u u +.tty-char \(*w w +.tty-char \(*x x +.tty-char \(*y n +.tty-char \(*z \z,C +.tty-char \(ts s +.\" Definition of \(ss should follow that of \(*b. +.tty-char \(ss B +.tty-char \(c* \zO\(mu +.tty-char \(c+ \zO+ +.tty-char \(AN ^ +.tty-char \(OR v +.tty-char \(uA \z=^ +.tty-char \(dA \z=v +.if c\(md .tty-char \(a. \(md +.tty-char \(Im I +.tty-char \(Re R +.tty-char \(/L \z/L +.tty-char \(/l \z/l +.tty-char \(%0 %o +.tty-char \(ao o +.tty-char \(a" """" +.tty-char \(ah v +.tty-char \(ho \(ac +.tty-char \(/_ \z_/ +.tty-char \(=~ =~ +.tty-char \(Ah N +.tty-char \(CR _| +.tty-char \(fa \z-V +.tty-char \(nm \z/E +.tty-char \(pp \z_| +.tty-char \(sd '' +.tty-char \(st -) +.tty-char \(te 3 +.if c\(md .tty-char \(tf .\(md. +.tty-char \(tf .:. +.tty-char \(wp p +.tty-char \(~~ ~~ +.tty-char \(Fn \z,f +.tty-char \(Bq ,, +.tty-char \(bq , +.tty-char \(lz <> +.\" Latin-1 characters +.tty-char \(r! \z,i +.tty-char \(Po \z-L +.tty-char \(Cs \zox +.tty-char \(Ye \z=Y +.tty-char \(bb | +.tty-char \(ad """" +.tty-char \(Of \z_a +.tty-char \(Fo << +.tty-char \(a- \*[tty-rn] +.tty-char \(S2 2 +.tty-char \(S3 3 +.tty-char \(ps 9| +.tty-char \(md . +.tty-char \(ac , +.tty-char \(S1 1 +.tty-char \(Om \z_o +.tty-char \(Fc >> +.tty-char \(r? \z'c +.tty-char \(`A \z`A +.tty-char \('A \z'A +.tty-char \(^A \z^A +.tty-char \(~A \z~A +.tty-char \(:A \z"A +.tty-char \(oA \zoA +.tty-char \(,C \z,C +.tty-char \(`E \z`E +.tty-char \('E \z'E +.tty-char \(^E \z^E +.tty-char \(:E \z"E +.tty-char \(`I \z`I +.tty-char \('I \z'I +.tty-char \(^I \z^I +.tty-char \(:I \z"I +.tty-char \(-D \z-D +.tty-char \(~N \z~N +.tty-char \(`O \z`O +.tty-char \('O \z'O +.tty-char \(^O \z^O +.tty-char \(~O \z~O +.tty-char \(:O \z"O +.tty-char \(/O \z/O +.tty-char \(`U \z`U +.tty-char \('U \z'U +.tty-char \(^U \z^U +.tty-char \(:U \z"U +.tty-char \('Y \z'Y +.tty-char \(TP \zIb +.tty-char \(`a \z`a +.tty-char \('a \z'a +.tty-char \(^a \z^a +.tty-char \(~a \z~a +.tty-char \(:a \z"a +.tty-char \(oa \zoa +.tty-char \(,c \z,c +.tty-char \(`e \z`e +.tty-char \('e \z'e +.tty-char \(^e \z^e +.tty-char \(:e \z"e +.tty-char \(`i \z`i +.tty-char \('i \z'i +.tty-char \(^i \z^i +.tty-char \(:i \z"i +.tty-char \(Sd \z`\z'o +.tty-char \(~n \z~n +.tty-char \(`o \z`o +.tty-char \('o \z'o +.tty-char \(^o \z^o +.tty-char \(~o \z~o +.tty-char \(:o \z"o +.tty-char \(/o \z/o +.tty-char \(`u \z`u +.tty-char \('u \z'u +.tty-char \(^u \z^u +.tty-char \(:u \z"u +.tty-char \('y \z'y +.tty-char \(Tp \zpb +.tty-char \(:y \z"y +.\"tty-char \(:y \ij +.cp \n(_C +.do mso tmac.latin1 diff --git a/gnu/usr.bin/groff/tmac/troffrc b/gnu/usr.bin/groff/tmac/troffrc new file mode 100644 index 0000000000..f3140d8e6a --- /dev/null +++ b/gnu/usr.bin/groff/tmac/troffrc @@ -0,0 +1,24 @@ +.\" Startup file for troff. +.\" This is tested by pic. +.nr 0p 0 +.\" Use .do here, so that it works with -C. +.\" The groff command defines the .X string if the -X option was given. +.ie r.X .do ds troffrc!ps tmac.Xps +.el .do ds troffrc!ps tmac.ps +.do ds troffrc!dvi tmac.dvi +.do ds troffrc!X75 tmac.X +.do ds troffrc!X75-12 tmac.X +.do ds troffrc!X100 tmac.X +.do ds troffrc!X100-12 tmac.X +.do ds troffrc!ascii tmac.tty +.do ds troffrc!latin1 tmac.tty +.do if d troffrc!\*[.T] \ +. do mso \*[troffrc!\*[.T]] +.do rm troffrc!ps troffrc!Xps troffrc!dvi troffrc!X75 troffrc!X75-12 \ +troffrc!X100 troffrc!X100-12 +.do tr \[char160] +.\" Set the hyphenation language to `us'. +.do hla us +.\" Load hyphenation patterns from `hyphen.us' (in the tmac directory). +.do hpf hyphen.us +.\" Don't let blank lines creep in here. diff --git a/gnu/usr.bin/groff/troff/Makefile b/gnu/usr.bin/groff/troff/Makefile new file mode 100644 index 0000000000..0da8255823 --- /dev/null +++ b/gnu/usr.bin/groff/troff/Makefile @@ -0,0 +1,37 @@ +# Makefile for troff + +PROG= troff +SRCS= env.cc node.cc input.cc div.cc symbol.cc dictionary.cc reg.cc \ + number.cc majorminor.cc +CFLAGS+= -I$(.CURDIR)/../include +LDADD+= $(LIBGROFF) -lm +DPADD+= $(LIBGROFF) $(LIBMATH) +tmacdir?= /usr/share/tmac + +CLEANFILES+= majorminor.cc +majorminor.cc: $(.CURDIR)/../VERSION + @echo Making $@ + @-rm -f $@ + @echo const char \*major_version = \ + \"`sed -e 's/^\([^.]*\)\..*$$/\1/' $(.CURDIR)/../VERSION`\"\; >$@ + @echo const char \*minor_version = \ + \"`sed -e 's/^[^.]*\.\([0-9]*\).*$$/\1/' $(.CURDIR)/../VERSION`\"\; >>$@ + +install_data: hyphen.us + -test -d $(datadir) || mkdir $(datadir) + -test -d $(datasubdir) || mkdir $(datasubdir) + -test -d $(tmacdir) || mkdir $(tmacdir) + -rm -f $(tmacdir)/hyphen.us + $(INSTALL_DATA) $(srcdir)/hyphen.us $(tmacdir)/hyphen.us + +uninstall_sub: + -rm -f $(tmacdir)/hyphen.us + +afterinstall: + install -c -o bin -g bin -m 444 $(.CURDIR)/hyphen.us \ + $(DESTDIR)$(tmacdir)/hyphen.us + +.include +.include "../../../usr.bin/Makefile.inc" +.include "../Makefile.cfg" +.include "Makefile.dep" diff --git a/gnu/usr.bin/groff/troff/Makefile.dep b/gnu/usr.bin/groff/troff/Makefile.dep new file mode 100644 index 0000000000..b1fd7791e1 --- /dev/null +++ b/gnu/usr.bin/groff/troff/Makefile.dep @@ -0,0 +1,34 @@ +env.o : env.cc troff.h ../include/lib.h ../include/assert.h \ + ../include/device.h ../include/cset.h ../include/cmap.h \ + ../include/errarg.h ../include/error.h symbol.h dictionary.h hvunits.h \ + env.h request.h node.h token.h div.h reg.h charinfo.h \ + ../include/searchpath.h ../include/macropath.h +node.o : node.cc troff.h ../include/lib.h ../include/assert.h \ + ../include/device.h ../include/cset.h ../include/cmap.h \ + ../include/errarg.h ../include/error.h symbol.h dictionary.h hvunits.h \ + env.h request.h node.h token.h charinfo.h ../include/font.h reg.h +input.o : input.cc troff.h ../include/lib.h ../include/assert.h \ + ../include/device.h ../include/cset.h ../include/cmap.h \ + ../include/errarg.h ../include/error.h symbol.h dictionary.h hvunits.h \ + env.h request.h node.h reg.h token.h div.h charinfo.h ../include/font.h \ + ../include/searchpath.h ../include/macropath.h ../include/defs.h \ + ../include/posix.h +div.o : div.cc troff.h ../include/lib.h ../include/assert.h \ + ../include/device.h ../include/cset.h ../include/cmap.h \ + ../include/errarg.h ../include/error.h symbol.h dictionary.h hvunits.h \ + env.h request.h node.h token.h div.h reg.h +symbol.o : symbol.cc troff.h ../include/lib.h ../include/assert.h \ + ../include/device.h ../include/cset.h ../include/cmap.h \ + ../include/errarg.h ../include/error.h symbol.h +dictionary.o : dictionary.cc troff.h ../include/lib.h ../include/assert.h \ + ../include/device.h ../include/cset.h ../include/cmap.h \ + ../include/errarg.h ../include/error.h symbol.h dictionary.h +reg.o : reg.cc troff.h ../include/lib.h ../include/assert.h \ + ../include/device.h ../include/cset.h ../include/cmap.h \ + ../include/errarg.h ../include/error.h symbol.h dictionary.h token.h \ + request.h reg.h +number.o : number.cc troff.h ../include/lib.h ../include/assert.h \ + ../include/device.h ../include/cset.h ../include/cmap.h \ + ../include/errarg.h ../include/error.h symbol.h hvunits.h env.h token.h \ + div.h +majorminor.o : majorminor.cc diff --git a/gnu/usr.bin/groff/troff/TODO b/gnu/usr.bin/groff/troff/TODO new file mode 100644 index 0000000000..f67707490e --- /dev/null +++ b/gnu/usr.bin/groff/troff/TODO @@ -0,0 +1,132 @@ +Give a more helpful error message when the indent is set to a value +greater than the line-length. + +Tracing. This is a pain to implement because requests are responsible +for reading their own arguments. + +Possibly implement -s option (stop every N pages). This functionality +would be more appropriate in a postprocessor. + +Line breaking should be smarter. In particular, it should be possible +to shrink spaces. Also avoid having a line that's been shrunk a lot +next to a line that's been stretched a lot. The difficulty is to +design a mechanism that allows the user complete control over the +decision of where to break the line. + +Provide a mechanism to control the shape of the rag in non-justified +text. + +Add a discretionary break escape sequence. \B'...'...'...' like TeX. + +Think about kerning between characters and spaces. (Need to implement +get_breakpoints and split methods for kern_pair_node class.) + +In troff, if .L > 1 when a diversion is reread in no-fill mode, then +extra line-spacing is added on. Groff at the moment treats line-spacing +like vertical spacing and doesn't do this. + +Suppose \(ch comes from a special font S, and that the current font is +R. Suppose that R contains a hyphen character and that S does not. +Suppose that the current font is R. Suppose that \(ch is in a word +and has a non-zero hyphen-type. Then we ought to be able to hyphenate, +but we won't be able to because we will look for the hyphen only in +font S and not in font R. + +Variant of tm which doesn't write a newline. + +Perhaps the current input level should be accessible in a number register. + +Should \w deal with a newline like \X? + +Have another look at uses of token::delimiter. Perhaps we need to +distinguish the case where we want to see if a token could start a +number, from the case where we want to see if it could occur somewhere +in a number expression. + +Provide a facility like copy thru in pic. + +Fancier implementation of font families which doesn't group fonts into +families purely on the basis of their names. + +In the DESC file make the number of fonts optional if they are all on +one line. + +Number register to give the diversion level. + +Time various alternative implementations of scale (both in font.c and +number.c). On a sparc it's faster to always do it in floating point. + +Devise a more compact representation for the hyphenation patterns trie. + +Have a per-environment parameter to increase letter-spacing. + +Number register to return character height. + +Number register to return character slant. + +Request to set character height. + +Request to set character slant. + +Provide some way to upcase or downcase strings. + +Support non-uniformly scaleable fonts. Perhaps associate a suffix with +a particular range of sizes. eg + sizesuffix .display 14-512 +Then is you ask for R at pointsize 16, groff will first look for +R.display and then R. Probably necessary to be able to specify a +separate unitwidth for each sizesuffix (eg. for X). + +Request to copy an environment into the current environment. + +Variant of `.it' for which a line interrupted with \c counts as one +input line. + +Make it possible to suppress hyphenation on a word-by-word basis. +(Perhaps store hyphenation flags in tfont.) + +Possibly allow multiple simultaneous input line traps. + +Unpaddable, breakable space escape sequence. + +Support hanging punctuation. + +In justified text, if the last line of a paragraph is only a little +bit short it might be desirable to justify the line. Allow the user +control over this. + +Have a blank line macro like the end macro. When a blank line macro +has been set, then a blank line causes the blank line macro to be +called rather than doing the equivalent of .sp. + +The pm request could print where the macro was defined. Also could +optionally print the contents of a macro. + +Provide some way to round numbers to multiples of the current +horizontal or vertical resolution. + +Better string-processing support (substring, length, search). + +Generalized ligatures. + +Provide some way for a macro to tell whether it was called with `'' or +`.'. This would be useful for implementing a tracing macro packge. + +Request to remove an environment. (Maintain a count of the references +to the environment from the environment table, environment dictionary +or environment stack.) + +Perhaps in the nr request a leading `-' should only be recognized as a +decrement when it's at the same input level as the request. + +Don't ever change a charinfo. Create new variants instead and chain +them together. + +Make it possible to tr characters onto \~. + +Unix troff appears to read the first character of a request name in +copy mode. Should we do the same? + +Number register giving name of end macro. + +More thorough range checking. diff --git a/gnu/usr.bin/groff/troff/charinfo.h b/gnu/usr.bin/groff/troff/charinfo.h new file mode 100644 index 0000000000..29a5b853d4 --- /dev/null +++ b/gnu/usr.bin/groff/troff/charinfo.h @@ -0,0 +1,165 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +class macro; + +class charinfo { + static int next_index; + charinfo *translation; + int index; + int number; + macro *mac; + unsigned char special_translation; + unsigned char hyphenation_code; + unsigned char flags; + unsigned char ascii_code; + char not_found; + char transparent_translate; // non-zero means translation applies to + // to transparent throughput +public: + enum { + ENDS_SENTENCE = 1, + BREAK_BEFORE = 2, + BREAK_AFTER = 4, + OVERLAPS_HORIZONTALLY = 8, + OVERLAPS_VERTICALLY = 16, + TRANSPARENT = 32, + NUMBERED = 64 + }; + enum { + TRANSLATE_NONE, + TRANSLATE_SPACE, + TRANSLATE_DUMMY, + TRANSLATE_STRETCHABLE_SPACE, + TRANSLATE_HYPHEN_INDICATOR + }; + symbol nm; + charinfo(symbol s); + int get_index(); + int ends_sentence(); + int overlaps_vertically(); + int overlaps_horizontally(); + int can_break_before(); + int can_break_after(); + int transparent(); + unsigned char get_hyphenation_code(); + unsigned char get_ascii_code(); + void set_hyphenation_code(unsigned char); + void set_ascii_code(unsigned char); + charinfo *get_translation(int = 0); + void set_translation(charinfo *, int); + void set_flags(unsigned char); + void set_special_translation(int, int); + int get_special_translation(int = 0); + macro *set_macro(macro *); + macro *get_macro(); + int first_time_not_found(); + void set_number(int); + int get_number(); + int numbered(); +}; + +charinfo *get_charinfo(symbol); +extern charinfo *charset_table[]; +charinfo *get_charinfo_by_number(int); + +inline int charinfo::overlaps_horizontally() +{ + return flags & OVERLAPS_HORIZONTALLY; +} + +inline int charinfo::overlaps_vertically() +{ + return flags & OVERLAPS_VERTICALLY; +} + +inline int charinfo::can_break_before() +{ + return flags & BREAK_BEFORE; +} + +inline int charinfo::can_break_after() +{ + return flags & BREAK_AFTER; +} + +inline int charinfo::ends_sentence() +{ + return flags & ENDS_SENTENCE; +} + +inline int charinfo::transparent() +{ + return flags & TRANSPARENT; +} + +inline int charinfo::numbered() +{ + return flags & NUMBERED; +} + +inline charinfo *charinfo::get_translation(int transparent_throughput) +{ + return (transparent_throughput && !transparent_translate + ? 0 + : translation); +} + +inline unsigned char charinfo::get_hyphenation_code() +{ + return hyphenation_code; +} + +inline unsigned char charinfo::get_ascii_code() +{ + return ascii_code; +} + +inline void charinfo::set_flags(unsigned char c) +{ + flags = c; +} + +inline int charinfo::get_index() +{ + return index; +} + +inline int charinfo::get_special_translation(int transparent_throughput) +{ + return (transparent_throughput && !transparent_translate + ? TRANSLATE_NONE + : special_translation); +} + +inline macro *charinfo::get_macro() +{ + return mac; +} + +inline int charinfo::first_time_not_found() +{ + if (not_found) + return 0; + else { + not_found = 1; + return 1; + } +} diff --git a/gnu/usr.bin/groff/troff/column.cc b/gnu/usr.bin/groff/troff/column.cc new file mode 100644 index 0000000000..230e544e0d --- /dev/null +++ b/gnu/usr.bin/groff/troff/column.cc @@ -0,0 +1,732 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef COLUMN + +#include "troff.h" +#include "symbol.h" +#include "dictionary.h" +#include "hvunits.h" +#include "env.h" +#include "request.h" +#include "node.h" +#include "token.h" +#include "div.h" +#include "reg.h" +#include "stringclass.h" + +void output_file::vjustify(vunits, symbol) +{ + // do nothing +} + +struct justification_spec; +struct output_line; + +class column : public output_file { +private: + output_file *out; + vunits bottom; + output_line *col; + output_line **tail; + void add_output_line(output_line *); + void begin_page(int pageno, vunits page_length); + void flush(); + void print_line(hunits, vunits, node *, vunits, vunits); + void vjustify(vunits, symbol); + void transparent_char(unsigned char c); + void copy_file(hunits, vunits, const char *); + int is_printing(); + void check_bottom(); +public: + column(); + ~column(); + void start(); + void output(); + void justify(const justification_spec &); + void trim(); + void reset(); + vunits get_bottom(); + vunits get_last_extra_space(); + int is_active() { return out != 0; } +}; + +column *the_column = 0; + +struct transparent_output_line; +struct vjustify_output_line; + +class output_line { + output_line *next; +public: + output_line(); + virtual ~output_line(); + virtual void output(output_file *, vunits); + virtual transparent_output_line *as_transparent_output_line(); + virtual vjustify_output_line *as_vjustify_output_line(); + virtual vunits distance(); + virtual vunits height(); + virtual void reset(); + virtual vunits extra_space(); // post line + friend class column; + friend class justification_spec; +}; + +class position_output_line : public output_line { + vunits dist; +public: + position_output_line(vunits); + vunits distance(); +}; + +class node_output_line : public position_output_line { + node *nd; + hunits page_offset; + vunits before; + vunits after; +public: + node_output_line(vunits, node *, hunits, vunits, vunits); + ~node_output_line(); + void output(output_file *, vunits); + vunits height(); + vunits extra_space(); +}; + +class vjustify_output_line : public position_output_line { + vunits current; + symbol typ; +public: + vjustify_output_line(vunits dist, symbol); + vunits height(); + vjustify_output_line *as_vjustify_output_line(); + void vary(vunits amount); + void reset(); + symbol type(); +}; + +inline symbol vjustify_output_line::type() +{ + return typ; +} + +class copy_file_output_line : public position_output_line { + symbol filename; + hunits hpos; +public: + copy_file_output_line(vunits, const char *, hunits); + void output(output_file *, vunits); +}; + +class transparent_output_line : public output_line { + string buf; +public: + transparent_output_line(); + void output(output_file *, vunits); + void append_char(unsigned char c); + transparent_output_line *as_transparent_output_line(); +}; + +output_line::output_line() : next(0) +{ +} + +output_line::~output_line() +{ +} + +void output_line::reset() +{ +} + +transparent_output_line *output_line::as_transparent_output_line() +{ + return 0; +} + +vjustify_output_line *output_line::as_vjustify_output_line() +{ + return 0; +} + +void output_line::output(output_file *, vunits) +{ +} + +vunits output_line::distance() +{ + return V0; +} + +vunits output_line::height() +{ + return V0; +} + +vunits output_line::extra_space() +{ + return V0; +} + +position_output_line::position_output_line(vunits d) +: dist(d) +{ +} + +vunits position_output_line::distance() +{ + return dist; +} + +node_output_line::node_output_line(vunits d, node *n, hunits po, vunits b, vunits a) +: position_output_line(d), nd(n), page_offset(po), before(b), after(a) +{ +} + +node_output_line::~node_output_line() +{ + delete_node_list(nd); +} + +void node_output_line::output(output_file *out, vunits pos) +{ + out->print_line(page_offset, pos, nd, before, after); + nd = 0; +} + +vunits node_output_line::height() +{ + return after; +} + +vunits node_output_line::extra_space() +{ + return after; +} + +vjustify_output_line::vjustify_output_line(vunits d, symbol t) +: position_output_line(d), typ(t) +{ +} + +void vjustify_output_line::reset() +{ + current = V0; +} + +vunits vjustify_output_line::height() +{ + return current; +} + +vjustify_output_line *vjustify_output_line::as_vjustify_output_line() +{ + return this; +} + +inline void vjustify_output_line::vary(vunits amount) +{ + current += amount; +} + +transparent_output_line::transparent_output_line() +{ +} + +transparent_output_line *transparent_output_line::as_transparent_output_line() +{ + return this; +} + +void transparent_output_line::append_char(unsigned char c) +{ + assert(c != 0); + buf += c; +} + +void transparent_output_line::output(output_file *out, vunits) +{ + int len = buf.length(); + for (int i = 0; i < len; i++) + out->transparent_char(buf[i]); +} + +copy_file_output_line::copy_file_output_line(vunits d, const char *f, hunits h) +: position_output_line(d), hpos(h), filename(f) +{ +} + +void copy_file_output_line::output(output_file *out, vunits pos) +{ + out->copy_file(hpos, pos, filename.contents()); +} + +column::column() +: bottom(V0), col(0), tail(&col), out(0) +{ +} + +column::~column() +{ + assert(out != 0); + error("automatically outputting column before exiting"); + output(); + delete the_output; +} + +void column::start() +{ + assert(out == 0); + if (!the_output) + init_output(); + assert(the_output != 0); + out = the_output; + the_output = this; +} + +void column::begin_page(int pageno, vunits page_length) +{ + assert(out != 0); + if (col) { + error("automatically outputting column before beginning next page"); + output(); + the_output->begin_page(pageno, page_length); + } + else + out->begin_page(pageno, page_length); + +} + +void column::flush() +{ + assert(out != 0); + out->flush(); +} + +int column::is_printing() +{ + assert(out != 0); + return out->is_printing(); +} + +vunits column::get_bottom() +{ + return bottom; +} + +void column::add_output_line(output_line *ln) +{ + *tail = ln; + bottom += ln->distance(); + bottom += ln->height(); + ln->next = 0; + tail = &(*tail)->next; +} + +void column::print_line(hunits page_offset, vunits pos, node *nd, + vunits before, vunits after) +{ + assert(out != 0); + add_output_line(new node_output_line(pos - bottom, nd, page_offset, before, after)); +} + +void column::vjustify(vunits pos, symbol typ) +{ + assert(out != 0); + add_output_line(new vjustify_output_line(pos - bottom, typ)); +} + +void column::transparent_char(unsigned char c) +{ + assert(out != 0); + transparent_output_line *tl = 0; + if (*tail) + tl = (*tail)->as_transparent_output_line(); + if (!tl) { + tl = new transparent_output_line; + add_output_line(tl); + } + tl->append_char(c); +} + +void column::copy_file(hunits page_offset, vunits pos, const char *filename) +{ + assert(out != 0); + add_output_line(new copy_file_output_line(pos - bottom, filename, page_offset)); +} + +void column::trim() +{ + output_line **spp = 0; + for (output_line **pp = &col; *pp; pp = &(*pp)->next) + if ((*pp)->as_vjustify_output_line() == 0) + spp = 0; + else if (!spp) + spp = pp; + if (spp) { + output_line *ln = *spp; + *spp = 0; + tail = spp; + while (ln) { + output_line *tem = ln->next; + bottom -= ln->distance(); + bottom -= ln->height(); + delete ln; + ln = tem; + } + } +} + +void column::reset() +{ + bottom = V0; + for (output_line *ln = col; ln; ln = ln->next) { + bottom += ln->distance(); + ln->reset(); + bottom += ln->height(); + } +} + +void column::check_bottom() +{ + vunits b; + for (output_line *ln = col; ln; ln = ln->next) { + b += ln->distance(); + b += ln->height(); + } + assert(b == bottom); +} + +void column::output() +{ + assert(out != 0); + vunits vpos(V0); + output_line *ln = col; + while (ln) { + vpos += ln->distance(); + ln->output(out, vpos); + vpos += ln->height(); + output_line *tem = ln->next; + delete ln; + ln = tem; + } + tail = &col; + bottom = V0; + col = 0; + the_output = out; + out = 0; +} + +vunits column::get_last_extra_space() +{ + if (!col) + return V0; + for (output_line *p = col; p->next; p = p->next) + ; + return p->extra_space(); +} + +class justification_spec { + vunits height; + symbol *type; + vunits *amount; + int n; + int maxn; +public: + justification_spec(vunits); + ~justification_spec(); + void append(symbol t, vunits v); + void justify(output_line *, vunits *bottomp) const; +}; + +justification_spec::justification_spec(vunits h) +: height(h), n(0), maxn(10) +{ + type = new symbol[maxn]; + amount = new vunits[maxn]; +} + +justification_spec::~justification_spec() +{ + a_delete type; + a_delete amount; +} + +void justification_spec::append(symbol t, vunits v) +{ + if (v <= V0) { + if (v < V0) + warning(WARN_RANGE, + "maximum space for vertical justification must not be negative"); + else + warning(WARN_RANGE, + "maximum space for vertical justification must not be zero"); + return; + } + if (n >= maxn) { + maxn *= 2; + symbol *old_type = type; + type = new symbol[maxn]; + int i; + for (i = 0; i < n; i++) + type[i] = old_type[i]; + a_delete old_type; + vunits *old_amount = amount; + amount = new vunits[maxn]; + for (i = 0; i < n; i++) + amount[i] = old_amount[i]; + a_delete old_amount; + } + assert(n < maxn); + type[n] = t; + amount[n] = v; + n++; +} + +void justification_spec::justify(output_line *col, vunits *bottomp) const +{ + if (*bottomp >= height) + return; + vunits total; + output_line *p; + for (p = col; p; p = p->next) { + vjustify_output_line *sp = p->as_vjustify_output_line(); + if (sp) { + symbol t = sp->type(); + for (int i = 0; i < n; i++) { + if (t == type[i]) + total += amount[i]; + } + } + } + vunits gap = height - *bottomp; + for (p = col; p; p = p->next) { + vjustify_output_line *sp = p->as_vjustify_output_line(); + if (sp) { + symbol t = sp->type(); + for (int i = 0; i < n; i++) { + if (t == type[i]) { + if (total <= gap) { + sp->vary(amount[i]); + gap -= amount[i]; + } + else { + // gap < total + vunits v = scale(amount[i], gap, total); + sp->vary(v); + gap -= v; + } + total -= amount[i]; + } + } + } + } + assert(total == V0); + *bottomp = height - gap; +} + +void column::justify(const justification_spec &js) +{ + check_bottom(); + js.justify(col, &bottom); + check_bottom(); +} + +void column_justify() +{ + vunits height; + if (!the_column->is_active()) + error("can't justify column - column not active"); + else if (get_vunits(&height, 'v')) { + justification_spec js(height); + symbol nm = get_long_name(1); + if (!nm.is_null()) { + vunits v; + if (get_vunits(&v, 'v')) { + js.append(nm, v); + int err = 0; + while (has_arg()) { + nm = get_long_name(1); + if (nm.is_null()) { + err = 1; + break; + } + if (!get_vunits(&v, 'v')) { + err = 1; + break; + } + js.append(nm, v); + } + if (!err) + the_column->justify(js); + } + } + } + skip_line(); +} + +void column_start() +{ + if (the_column->is_active()) + error("can't start column - column already active"); + else + the_column->start(); + skip_line(); +} + +void column_output() +{ + if (!the_column->is_active()) + error("can't output column - column not active"); + else + the_column->output(); + skip_line(); +} + +void column_trim() +{ + if (!the_column->is_active()) + error("can't trim column - column not active"); + else + the_column->trim(); + skip_line(); +} + +void column_reset() +{ + if (!the_column->is_active()) + error("can't reset column - column not active"); + else + the_column->reset(); + skip_line(); +} + +class column_bottom_reg : public reg { +public: + const char *get_string(); +}; + +const char *column_bottom_reg::get_string() +{ + return itoa(the_column->get_bottom().to_units()); +} + +class column_extra_space_reg : public reg { +public: + const char *get_string(); +}; + +const char *column_extra_space_reg::get_string() +{ + return itoa(the_column->get_last_extra_space().to_units()); +} + +class column_active_reg : public reg { +public: + const char *get_string(); +}; + +const char *column_active_reg::get_string() +{ + return the_column->is_active() ? "1" : "0"; +} + +static int no_vjustify_mode = 0; + +class vjustify_node : public node { + symbol typ; +public: + vjustify_node(symbol); + int reread(int *); + const char *type(); + int same(node *); + node *copy(); +}; + +vjustify_node::vjustify_node(symbol t) +: typ(t) +{ +} + +node *vjustify_node::copy() +{ + return new vjustify_node(typ); +} + +const char *vjustify_node::type() +{ + return "vjustify_node"; +} + +int vjustify_node::same(node *nd) +{ + return typ == ((vjustify_node *)nd)->typ; +} + +int vjustify_node::reread(int *bolp) +{ + curdiv->vjustify(typ); + *bolp = 1; + return 1; +} + +void macro_diversion::vjustify(symbol type) +{ + if (!no_vjustify_mode) + mac->append(new vjustify_node(type)); +} + +void top_level_diversion::vjustify(symbol type) +{ + if (no_space_mode || no_vjustify_mode) + return; + assert(first_page_begun); // I'm not sure about this. + the_output->vjustify(vertical_position, type); +} + +void no_vjustify() +{ + skip_line(); + no_vjustify_mode = 1; +} + +void restore_vjustify() +{ + skip_line(); + no_vjustify_mode = 0; +} + +void init_column_requests() +{ + the_column = new column; + init_request("cols", column_start); + init_request("colo", column_output); + init_request("colj", column_justify); + init_request("colr", column_reset); + init_request("colt", column_trim); + init_request("nvj", no_vjustify); + init_request("rvj", restore_vjustify); + number_reg_dictionary.define(".colb", new column_bottom_reg); + number_reg_dictionary.define(".colx", new column_extra_space_reg); + number_reg_dictionary.define(".cola", new column_active_reg); + number_reg_dictionary.define(".nvj", + new constant_int_reg(&no_vjustify_mode)); +} + +#endif /* COLUMN */ diff --git a/gnu/usr.bin/groff/troff/dictionary.cc b/gnu/usr.bin/groff/troff/dictionary.cc new file mode 100644 index 0000000000..5437a1a1ed --- /dev/null +++ b/gnu/usr.bin/groff/troff/dictionary.cc @@ -0,0 +1,211 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "troff.h" +#include "symbol.h" +#include "dictionary.h" + +// is `p' a good size for a hash table + +static int is_good_size(int p) +{ + const int SMALL = 10; + for (unsigned i = 2; i <= p/2; i++) + if (p % i == 0) + return 0; + for (i = 0x100; i != 0; i <<= 8) + if (i % p <= SMALL || i % p > p - SMALL) + return 0; + return 1; +} + +dictionary::dictionary(int n) : threshold(0.5), factor(1.5), used(0), size(n) +{ + table = new association[n]; + for (int i = 0; i < n; i++) + table[i].v = 0; +} + +// see Knuth, Sorting and Searching, p518, Algorithm L +// we can't use double-hashing because we want a remove function + +void *dictionary::lookup(symbol s, void *v) +{ + for (int i = int(s.hash() % size); + table[i].v != 0; + i == 0 ? i = size - 1: --i) + if (s == table[i].s) { + if (v != 0) { + void *temp = table[i].v; + table[i].v = v; + return temp; + } + else + return table[i].v; + } + if (v == 0) + return 0; + ++used; + table[i].v = v; + table[i].s = s; + if ((double)used/(double)size >= threshold || used + 1 >= size) { + int old_size = size; + size = int(size*factor); + while (!is_good_size(size)) + ++size; + association *old_table = table; + table = new association[size]; + used = 0; + for (i = 0; i < old_size; i++) + if (old_table[i].v != 0) + (void)lookup(old_table[i].s, old_table[i].v); + a_delete old_table; + } + return 0; +} + +void *dictionary::lookup(const char *p) +{ + symbol s(p, MUST_ALREADY_EXIST); + if (s.is_null()) + return 0; + else + return lookup(s); +} + +// see Knuth, Sorting and Searching, p527, Algorithm R + +void *dictionary::remove(symbol s) +{ + // this relies on the fact that we are using linear probing + for (int i = int(s.hash() % size); + table[i].v != 0 && s != table[i].s; + i == 0 ? i = size - 1: --i) + ; + void *p = table[i].v; + while (table[i].v != 0) { + table[i].v = 0; + int j = i; + int r; + do { + --i; + if (i < 0) + i = size - 1; + if (table[i].v == 0) + break; + r = int(table[i].s.hash() % size); + } while ((i <= r && r < j) || (j < i && i <= r)); + table[j] = table[i]; + } + if (p != 0) + --used; + return p; +} + +dictionary_iterator::dictionary_iterator(dictionary &d) : dict(&d), i(0) +{ +} + +int dictionary_iterator::get(symbol *sp, void **vp) +{ + for (; i < dict->size; i++) + if (dict->table[i].v) { + *sp = dict->table[i].s; + *vp = dict->table[i].v; + i++; + return 1; + } + return 0; +} + +object_dictionary_iterator::object_dictionary_iterator(object_dictionary &od) + : di(od.d) +{ +} + +object::object() : rcount(0) +{ +} + +object::~object() +{ +} + +void object::add_reference() +{ + rcount += 1; +} + +void object::remove_reference() +{ + if (--rcount == 0) + delete this; +} + +object_dictionary::object_dictionary(int n) : d(n) +{ +} + +object *object_dictionary::lookup(symbol nm) +{ + return (object *)d.lookup(nm); +} + +void object_dictionary::define(symbol nm, object *obj) +{ + obj->add_reference(); + obj = (object *)d.lookup(nm, obj); + if (obj) + obj->remove_reference(); +} + +void object_dictionary::rename(symbol oldnm, symbol newnm) +{ + object *obj = (object *)d.remove(oldnm); + if (obj) { + obj = (object *)d.lookup(newnm, obj); + if (obj) + obj->remove_reference(); + } +} + +void object_dictionary::remove(symbol nm) +{ + object *obj = (object *)d.remove(nm); + if (obj) + obj->remove_reference(); +} + +// Return non-zero if oldnm was defined. + +int object_dictionary::alias(symbol newnm, symbol oldnm) +{ + object *obj = (object *)d.lookup(oldnm); + if (obj) { + obj->add_reference(); + obj = (object *)d.lookup(newnm, obj); + if (obj) + obj->remove_reference(); + return 1; + } + return 0; +} + diff --git a/gnu/usr.bin/groff/troff/dictionary.h b/gnu/usr.bin/groff/troff/dictionary.h new file mode 100644 index 0000000000..47d6d59926 --- /dev/null +++ b/gnu/usr.bin/groff/troff/dictionary.h @@ -0,0 +1,92 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +// there is no distinction between name with no value and name with NULL value +// null names are not permitted (they will be ignored). + +struct association { + symbol s; + void *v; + association() : v(0) {} +}; + +class dictionary; + +class dictionary_iterator { + dictionary *dict; + int i; +public: + dictionary_iterator(dictionary &); + int get(symbol *, void **); +}; + +class dictionary { + int size; + int used; + double threshold; + double factor; + association *table; + void rehash(int); +public: + dictionary(int); + void *lookup(symbol s, void *v=0); // returns value associated with key + void *lookup(const char *); + // if second parameter not NULL, value will be replaced + void *remove(symbol); + friend class dictionary_iterator; +}; + +class object { + int rcount; + public: + object(); + virtual ~object(); + void add_reference(); + void remove_reference(); +}; + +class object_dictionary; + +class object_dictionary_iterator { + dictionary_iterator di; +public: + object_dictionary_iterator(object_dictionary &); + int get(symbol *, object **); +}; + +class object_dictionary { + dictionary d; +public: + object_dictionary(int); + object *lookup(symbol nm); + void define(symbol nm, object *obj); + void rename(symbol oldnm, symbol newnm); + void remove(symbol nm); + int alias(symbol newnm, symbol oldnm); + friend class object_dictionary_iterator; +}; + + +inline int object_dictionary_iterator::get(symbol *sp, object **op) +{ + return di.get(sp, (void **)op); +} diff --git a/gnu/usr.bin/groff/troff/div.cc b/gnu/usr.bin/groff/troff/div.cc new file mode 100644 index 0000000000..c30001f2ae --- /dev/null +++ b/gnu/usr.bin/groff/troff/div.cc @@ -0,0 +1,1124 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +// diversions + +#include "troff.h" +#include "symbol.h" +#include "dictionary.h" +#include "hvunits.h" +#include "env.h" +#include "request.h" +#include "node.h" +#include "token.h" +#include "div.h" +#include "reg.h" + +int exit_started = 0; // the exit process has started +int done_end_macro = 0; // the end macro (if any) has finished +int seen_last_page_ejector = 0; // seen the LAST_PAGE_EJECTOR cookie +static int began_page_in_end_macro = 0; // a new page was begun during the end macro + +static int last_post_line_extra_space = 0; // needed for \n(.a +static int nl_reg_contents = -1; +static int dl_reg_contents = 0; +static int dn_reg_contents = 0; +static int vertical_position_traps_flag = 1; +static vunits truncated_space; +static vunits needed_space; + +diversion::diversion(symbol s) +: nm(s), prev(0), vertical_position(V0), marked_place(V0), high_water_mark(V0) +{ +} + +struct vertical_size { + vunits pre_extra, post_extra, pre, post; + vertical_size(vunits vs, int ls); +}; + +vertical_size::vertical_size(vunits vs, int ls) +: pre_extra(V0), post_extra(V0), pre(vs) +{ + if (ls > 1) + post = vs*(ls - 1); + else + post = V0; +} + +void node::set_vertical_size(vertical_size *) +{ +} + +void extra_size_node::set_vertical_size(vertical_size *v) +{ + if (n < V0) { + if (-n > v->pre_extra) + v->pre_extra = -n; + } + else if (n > v->post_extra) + v->post_extra = n; +} + +void vertical_size_node::set_vertical_size(vertical_size *v) +{ + if (n < V0) + v->pre = -n; + else + v->post = n; +} + +top_level_diversion *topdiv; + +diversion *curdiv; + +void do_divert(int append) +{ + tok.skip(); + symbol nm = get_name(); + if (nm.is_null()) { + if (curdiv->prev) { + diversion *temp = curdiv; + curdiv = curdiv->prev; + delete temp; + } + else + warning(WARN_DI, "diversion stack underflow"); + } + else { + macro_diversion *md = new macro_diversion(nm, append); + md->prev = curdiv; + curdiv = md; + } + skip_line(); +} + +void divert() +{ + do_divert(0); +} + +void divert_append() +{ + do_divert(1); +} + +void diversion::need(vunits n) +{ + vunits d = distance_to_next_trap(); + if (d < n) { + space(d, 1); + truncated_space = -d; + needed_space = n; + } +} + +macro_diversion::macro_diversion(symbol s, int append) +: diversion(s), max_width(H0) +{ +#if 0 + if (append) { + /* We don't allow recursive appends eg: + + .da a + .a + .di + + This causes an infinite loop in troff anyway. + This is because the user could do + + .as a foo + + in the diversion, and this would mess things up royally, + since there would be two things appending to the same + macro_header. + To make it work, we would have to copy the _contents_ + of the macro into which we were diverting; this doesn't + strike me as worthwhile. + However, + + .di a + .a + .a + .di + + will work and will make `a' contain two copies of what it contained + before; in troff, `a' would contain nothing. */ + request_or_macro *rm + = (request_or_macro *)request_dictionary.remove(s); + if (!rm || (mac = rm->to_macro()) == 0) + mac = new macro; + } + else + mac = new macro; +#endif + // We can now catch the situation described above by comparing + // the length of the charlist in the macro_header with the length + // stored in the macro. When we detect this, we copy the contents. + mac = new macro; + if (append) { + request_or_macro *rm + = (request_or_macro *)request_dictionary.lookup(s); + if (rm) { + macro *m = rm->to_macro(); + if (m) + *mac = *m; + } + } +} + +macro_diversion::~macro_diversion() +{ + request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm); + macro *m = rm ? rm->to_macro() : 0; + if (m) { + *m = *mac; + delete mac; + } + else + request_dictionary.define(nm, mac); + mac = 0; + dl_reg_contents = max_width.to_units(); + dn_reg_contents = vertical_position.to_units(); +} + +vunits macro_diversion::distance_to_next_trap() +{ + if (!diversion_trap.is_null() && diversion_trap_pos > vertical_position) + return diversion_trap_pos - vertical_position; + else + // Substract vresolution so that vunits::vunits does not overflow. + return vunits(INT_MAX - vresolution); +} + +void macro_diversion::transparent_output(unsigned char c) +{ + mac->append(c); +} + +void macro_diversion::transparent_output(node *n) +{ + mac->append(n); +} + +void macro_diversion::output(node *nd, int retain_size, + vunits vs, int ls, hunits width) +{ + vertical_size v(vs, ls); + while (nd != 0) { + nd->set_vertical_size(&v); + node *temp = nd; + nd = nd->next; + if (temp->interpret(mac)) { + delete temp; + } + else { +#if 1 + temp->freeze_space(); +#endif + mac->append(temp); + } + } + if (!v.post_extra.is_zero()) + last_post_line_extra_space = v.post_extra.to_units(); + if (!retain_size) { + v.pre = vs; + v.post = (ls > 1) ? vs*(ls - 1) : V0; + } + if (width > max_width) + max_width = width; + vunits x = v.pre + v.pre_extra + v.post + v.post_extra; + if (vertical_position_traps_flag + && !diversion_trap.is_null() && diversion_trap_pos > vertical_position + && diversion_trap_pos <= vertical_position + x) { + vunits trunc = vertical_position + x - diversion_trap_pos; + if (trunc > v.post) + trunc = v.post; + v.post -= trunc; + x -= trunc; + truncated_space = trunc; + spring_trap(diversion_trap); + } + mac->append(new vertical_size_node(-v.pre)); + mac->append(new vertical_size_node(v.post)); + mac->append('\n'); + vertical_position += x; + if (vertical_position - v.post > high_water_mark) + high_water_mark = vertical_position - v.post; +} + +void macro_diversion::space(vunits n, int) +{ + if (vertical_position_traps_flag + && !diversion_trap.is_null() && diversion_trap_pos > vertical_position + && diversion_trap_pos <= vertical_position + n) { + truncated_space = vertical_position + n - diversion_trap_pos; + n = diversion_trap_pos - vertical_position; + spring_trap(diversion_trap); + } + else if (n + vertical_position < V0) + n = -vertical_position; + mac->append(new diverted_space_node(n)); + vertical_position += n; +} + +void macro_diversion::copy_file(const char *filename) +{ + mac->append(new diverted_copy_file_node(filename)); +} + +top_level_diversion::top_level_diversion() +: page_count(0), have_next_page_number(0), page_length(units_per_inch*11), + page_offset(units_per_inch), prev_page_offset(units_per_inch), + ejecting_page(0), page_trap_list(0), before_first_page(1), no_space_mode(0), + page_number(0), last_page_count(-1) +{ +} + +// find the next trap after pos + +trap *top_level_diversion::find_next_trap(vunits *next_trap_pos) +{ + trap *next_trap = 0; + for (trap *pt = page_trap_list; pt != 0; pt = pt->next) + if (!pt->nm.is_null()) { + if (pt->position >= V0) { + if (pt->position > vertical_position + && pt->position < page_length + && (next_trap == 0 || pt->position < *next_trap_pos)) { + next_trap = pt; + *next_trap_pos = pt->position; + } + } + else { + vunits pos = pt->position; + pos += page_length; + if (pos > 0 && pos > vertical_position && (next_trap == 0 || pos < *next_trap_pos)) { + next_trap = pt; + *next_trap_pos = pos; + } + } + } + return next_trap; +} + +vunits top_level_diversion::distance_to_next_trap() +{ + vunits d; + if (!find_next_trap(&d)) + return page_length - vertical_position; + else + return d - vertical_position; +} + +void top_level_diversion::output(node *nd, int retain_size, + vunits vs, int ls, hunits /*width*/) +{ + no_space_mode = 0; + vunits next_trap_pos; + trap *next_trap = find_next_trap(&next_trap_pos); + if (before_first_page && begin_page()) + fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); + vertical_size v(vs, ls); + for (node *tem = nd; tem != 0; tem = tem->next) + tem->set_vertical_size(&v); + if (!v.post_extra.is_zero()) + last_post_line_extra_space = v.post_extra.to_units(); + if (!retain_size) { + v.pre = vs; + v.post = (ls > 1) ? vs*(ls - 1) : V0; + } + vertical_position += v.pre; + vertical_position += v.pre_extra; + the_output->print_line(page_offset, vertical_position, nd, + v.pre + v.pre_extra, v.post_extra); + vertical_position += v.post_extra; + if (vertical_position > high_water_mark) + high_water_mark = vertical_position; + if (vertical_position_traps_flag && vertical_position >= page_length) + begin_page(); + else if (vertical_position_traps_flag + && next_trap != 0 && vertical_position >= next_trap_pos) { + nl_reg_contents = vertical_position.to_units(); + truncated_space = v.post; + spring_trap(next_trap->nm); + } + else if (v.post > V0) { + vertical_position += v.post; + if (vertical_position_traps_flag + && next_trap != 0 && vertical_position >= next_trap_pos) { + truncated_space = vertical_position - next_trap_pos; + vertical_position = next_trap_pos; + nl_reg_contents = vertical_position.to_units(); + spring_trap(next_trap->nm); + } + else if (vertical_position_traps_flag && vertical_position >= page_length) + begin_page(); + else + nl_reg_contents = vertical_position.to_units(); + } + else + nl_reg_contents = vertical_position.to_units(); +} + +void top_level_diversion::transparent_output(unsigned char c) +{ + if (before_first_page && begin_page()) + // This can only happen with the transparent() request. + fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); + const char *s = asciify(c); + while (*s) + the_output->transparent_char(*s++); +} + +void top_level_diversion::transparent_output(node * /*n*/) +{ + error("can't transparently output node at top level"); +} + +void top_level_diversion::copy_file(const char *filename) +{ + if (before_first_page && begin_page()) + fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); + the_output->copy_file(page_offset, vertical_position, filename); +} + +void top_level_diversion::space(vunits n, int forced) +{ + if (no_space_mode) { + if (!forced) + return; + else + no_space_mode = 0; + } + if (before_first_page) { + if (begin_page()) { + // This happens if there's a top of page trap, and the first-page + // transition is caused by `'sp'. + truncated_space = n > V0 ? n : V0; + return; + } + } + vunits next_trap_pos; + trap *next_trap = find_next_trap(&next_trap_pos); + vunits y = vertical_position + n; + if (vertical_position_traps_flag && next_trap != 0 && y >= next_trap_pos) { + vertical_position = next_trap_pos; + nl_reg_contents = vertical_position.to_units(); + truncated_space = y - vertical_position; + spring_trap(next_trap->nm); + } + else if (y < V0) { + vertical_position = V0; + nl_reg_contents = vertical_position.to_units(); + } + else if (vertical_position_traps_flag && y >= page_length && n >= V0) + begin_page(); + else { + vertical_position = y; + nl_reg_contents = vertical_position.to_units(); + } +} + +trap::trap(symbol s, vunits n, trap *p) + : nm(s), next(p), position(n) +{ +} + +void top_level_diversion::add_trap(symbol nm, vunits pos) +{ + trap *first_free_slot = 0; + for (trap **p = &page_trap_list; *p; p = &(*p)->next) { + if ((*p)->nm.is_null()) { + if (first_free_slot == 0) + first_free_slot = *p; + } + else if ((*p)->position == pos) { + (*p)->nm = nm; + return; + } + } + if (first_free_slot) { + first_free_slot->nm = nm; + first_free_slot->position = pos; + } + else + *p = new trap(nm, pos, 0); +} + +void top_level_diversion::remove_trap(symbol nm) +{ + for (trap *p = page_trap_list; p; p = p->next) + if (p->nm == nm) { + p->nm = NULL_SYMBOL; + return; + } +} + +void top_level_diversion::remove_trap_at(vunits pos) +{ + for (trap *p = page_trap_list; p; p = p->next) + if (p->position == pos) { + p->nm = NULL_SYMBOL; + return; + } +} + +void top_level_diversion::change_trap(symbol nm, vunits pos) +{ + for (trap *p = page_trap_list; p; p = p->next) + if (p->nm == nm) { + p->position = pos; + return; + } +} + +void top_level_diversion::print_traps() +{ + for (trap *p = page_trap_list; p; p = p->next) + if (p->nm.is_null()) + fprintf(stderr, " empty\n"); + else + fprintf(stderr, "%s\t%d\n", p->nm.contents(), p->position.to_units()); + fflush(stderr); +} + +void end_diversions() +{ + while (curdiv != topdiv) { + error("automatically ending diversion `%1' on exit", + curdiv->nm.contents()); + diversion *tem = curdiv; + curdiv = curdiv->prev; + delete tem; + } +} + +NO_RETURN void cleanup_and_exit(int exit_code) +{ + if (the_output) { + the_output->trailer(topdiv->get_page_length()); + delete the_output; + } + exit(exit_code); +} + +// returns non-zero if it sprung a top of page trap + +int top_level_diversion::begin_page() +{ + if (exit_started) { + if (page_count == last_page_count + ? curenv->is_empty() + : (done_end_macro && (seen_last_page_ejector || began_page_in_end_macro))) + cleanup_and_exit(0); + if (!done_end_macro) + began_page_in_end_macro = 1; + } + if (!the_output) + init_output(); + ++page_count; + if (have_next_page_number) { + page_number = next_page_number; + have_next_page_number = 0; + } + else if (before_first_page == 1) + page_number = 1; + else + page_number++; + // spring the top of page trap if there is one + vunits next_trap_pos; + vertical_position = -vresolution; + trap *next_trap = find_next_trap(&next_trap_pos); + vertical_position = V0; + high_water_mark = V0; + ejecting_page = 0; + // If before_first_page was 2, then the top of page transition was undone + // using eg .nr nl 0-1. See nl_reg::set_value. + if (before_first_page != 2) + the_output->begin_page(page_number, page_length); + before_first_page = 0; + nl_reg_contents = vertical_position.to_units(); + if (vertical_position_traps_flag && next_trap != 0 && next_trap_pos == V0) { + truncated_space = V0; + spring_trap(next_trap->nm); + return 1; + } + else + return 0; +} + +void continue_page_eject() +{ + if (topdiv->get_ejecting()) { + if (curdiv != topdiv) + error("can't continue page ejection because of current diversion"); + else if (!vertical_position_traps_flag) + error("can't continue page ejection because vertical position traps disabled"); + else { + push_page_ejector(); + topdiv->space(topdiv->get_page_length(), 1); + } + } +} + +void top_level_diversion::set_next_page_number(int n) +{ + next_page_number= n; + have_next_page_number = 1; +} + +int top_level_diversion::get_next_page_number() +{ + return have_next_page_number ? next_page_number : page_number + 1; +} + +void top_level_diversion::set_page_length(vunits n) +{ + page_length = n; +} + +diversion::~diversion() +{ +} + +void page_offset() +{ + hunits n; + if (!has_arg() || !get_hunits(&n, 'v', topdiv->page_offset)) + n = topdiv->prev_page_offset; + topdiv->prev_page_offset = topdiv->page_offset; + topdiv->page_offset = n; + skip_line(); +} + +void page_length() +{ + vunits n; + if (has_arg() && get_vunits(&n, 'v', topdiv->get_page_length())) + topdiv->set_page_length(n); + else + topdiv->set_page_length(11*units_per_inch); + skip_line(); +} + +void when_request() +{ + vunits n; + if (get_vunits(&n, 'v')) { + symbol s = get_name(); + if (s.is_null()) + topdiv->remove_trap_at(n); + else + topdiv->add_trap(s, n); + } + skip_line(); +} + +void begin_page() +{ + int got_arg = 0; + int n; + if (has_arg() && get_integer(&n, topdiv->get_page_number())) + got_arg = 1; + while (!tok.newline() && !tok.eof()) + tok.next(); + if (curdiv == topdiv) { + if (topdiv->before_first_page) { + if (!break_flag) { + if (got_arg) + topdiv->set_next_page_number(n); + if (got_arg || !topdiv->no_space_mode) + topdiv->begin_page(); + } + else if (topdiv->no_space_mode && !got_arg) + topdiv->begin_page(); + else { + /* Given this + + .wh 0 x + .de x + .tm \\n% + .. + .bp 3 + + troff prints + + 1 + 3 + + This code makes groff do the same. */ + + push_page_ejector(); + topdiv->begin_page(); + if (got_arg) + topdiv->set_next_page_number(n); + topdiv->set_ejecting(); + } + } + else { + push_page_ejector(); + if (break_flag) + curenv->do_break(); + if (got_arg) + topdiv->set_next_page_number(n); + if (!(topdiv->no_space_mode && !got_arg)) + topdiv->set_ejecting(); + } + } + tok.next(); +} + +void no_space() +{ + if (curdiv == topdiv) + topdiv->no_space_mode = 1; + skip_line(); +} + +void restore_spacing() +{ + if (curdiv == topdiv) + topdiv->no_space_mode = 0; + skip_line(); +} + +/* It is necessary to generate a break before before reading the argument, +because otherwise arguments using | will be wrong. But if we just +generate a break as usual, then the line forced out may spring a trap +and thus push a macro onto the input stack before we have had a chance +to read the argument to the sp request. We resolve this dilemma by +setting, before generating the break, a flag which will postpone the +actual pushing of the macro associated with the trap sprung by the +outputting of the line forced out by the break till after we have read +the argument to the request. If the break did cause a trap to be +sprung, then we don't actually do the space. */ + +void space_request() +{ + postpone_traps(); + if (break_flag) + curenv->do_break(); + vunits n; + if (!has_arg() || !get_vunits(&n, 'v')) + n = curenv->get_vertical_spacing(); + while (!tok.newline() && !tok.eof()) + tok.next(); + if (!unpostpone_traps()) + curdiv->space(n); + else + // The line might have had line spacing that was truncated. + truncated_space += n; + tok.next(); +} + +void blank_line() +{ + curenv->do_break(); + if (!trap_sprung_flag) + curdiv->space(curenv->get_vertical_spacing()); + else + truncated_space += curenv->get_vertical_spacing(); +} + +/* need_space might spring a trap and so we must be careful that the +BEGIN_TRAP token is not skipped over. */ + +void need_space() +{ + vunits n; + if (!has_arg() || !get_vunits(&n, 'v')) + n = curenv->get_vertical_spacing(); + while (!tok.newline() && !tok.eof()) + tok.next(); + curdiv->need(n); + tok.next(); +} + +void page_number() +{ + int n; + if (has_arg() && get_integer(&n, topdiv->get_page_number())) + topdiv->set_next_page_number(n); + skip_line(); +} + +vunits saved_space; + +void save_vertical_space() +{ + vunits x; + if (get_vunits(&x, 'v')) { + if (curdiv->distance_to_next_trap() > x) + curdiv->space(x, 1); + else + saved_space = x; + } + skip_line(); +} + +void output_saved_vertical_space() +{ + while (!tok.newline() && !tok.eof()) + tok.next(); + if (saved_space > V0) + curdiv->space(saved_space, 1); + saved_space = V0; + tok.next(); +} + +void flush_output() +{ + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + if (the_output) + the_output->flush(); + tok.next(); +} + +void macro_diversion::set_diversion_trap(symbol s, vunits n) +{ + diversion_trap = s; + diversion_trap_pos = n; +} + +void macro_diversion::clear_diversion_trap() +{ + diversion_trap = NULL_SYMBOL; +} + +void top_level_diversion::set_diversion_trap(symbol, vunits) +{ + error("can't set diversion trap when no current diversion"); +} + +void top_level_diversion::clear_diversion_trap() +{ + error("can't set diversion trap when no current diversion"); +} + +void diversion_trap() +{ + vunits n; + if (has_arg() && get_vunits(&n, 'v')) { + symbol s = get_name(); + if (!s.is_null()) + curdiv->set_diversion_trap(s, n); + else + curdiv->clear_diversion_trap(); + } + else + curdiv->clear_diversion_trap(); + skip_line(); +} + +void change_trap() +{ + symbol s = get_name(1); + if (!s.is_null()) { + vunits x; + if (has_arg() && get_vunits(&x, 'v')) + topdiv->change_trap(s, x); + else + topdiv->remove_trap(s); + } + skip_line(); +} + +void print_traps() +{ + topdiv->print_traps(); + skip_line(); +} + +void mark() +{ + symbol s = get_name(); + if (s.is_null()) + curdiv->marked_place = curdiv->get_vertical_position(); + else if (curdiv == topdiv) + set_number_reg(s, nl_reg_contents); + else + set_number_reg(s, curdiv->get_vertical_position().to_units()); + skip_line(); +} + +// This is truly bizarre. It is documented in the SQ manual. + +void return_request() +{ + vunits dist = curdiv->marked_place - curdiv->get_vertical_position(); + if (has_arg()) { + if (tok.ch() == '-') { + tok.next(); + vunits x; + if (get_vunits(&x, 'v')) + dist = -x; + } + else { + vunits x; + if (get_vunits(&x, 'v')) + dist = x >= V0 ? x - curdiv->get_vertical_position() : V0; + } + } + if (dist < V0) + curdiv->space(dist); + skip_line(); +} + +void vertical_position_traps() +{ + int n; + if (has_arg() && get_integer(&n)) + vertical_position_traps_flag = (n != 0); + else + vertical_position_traps_flag = 1; + skip_line(); +} + +class page_offset_reg : public reg { +public: + int get_value(units *); + const char *get_string(); +}; + +int page_offset_reg::get_value(units *res) +{ + *res = topdiv->get_page_offset().to_units(); + return 1; +} + +const char *page_offset_reg::get_string() +{ + return itoa(topdiv->get_page_offset().to_units()); +} + +class page_length_reg : public reg { +public: + int get_value(units *); + const char *get_string(); +}; + +int page_length_reg::get_value(units *res) +{ + *res = topdiv->get_page_length().to_units(); + return 1; +} + +const char *page_length_reg::get_string() +{ + return itoa(topdiv->get_page_length().to_units()); +} + +class vertical_position_reg : public reg { +public: + int get_value(units *); + const char *get_string(); +}; + +int vertical_position_reg::get_value(units *res) +{ + if (curdiv == topdiv && topdiv->before_first_page) + *res = -1; + else + *res = curdiv->get_vertical_position().to_units(); + return 1; +} + +const char *vertical_position_reg::get_string() +{ + if (curdiv == topdiv && topdiv->before_first_page) + return "-1"; + else + return itoa(curdiv->get_vertical_position().to_units()); +} + +class high_water_mark_reg : public reg { +public: + int get_value(units *); + const char *get_string(); +}; + +int high_water_mark_reg::get_value(units *res) +{ + *res = curdiv->get_high_water_mark().to_units(); + return 1; +} + +const char *high_water_mark_reg::get_string() +{ + return itoa(curdiv->get_high_water_mark().to_units()); +} + +class distance_to_next_trap_reg : public reg { +public: + int get_value(units *); + const char *get_string(); +}; + +int distance_to_next_trap_reg::get_value(units *res) +{ + *res = curdiv->distance_to_next_trap().to_units(); + return 1; +} + +const char *distance_to_next_trap_reg::get_string() +{ + return itoa(curdiv->distance_to_next_trap().to_units()); +} + +class diversion_name_reg : public reg { +public: + const char *get_string(); +}; + +const char *diversion_name_reg::get_string() +{ + return curdiv->get_diversion_name(); +} + +class page_number_reg : public general_reg { +public: + page_number_reg(); + int get_value(units *); + void set_value(units); +}; + +page_number_reg::page_number_reg() +{ +} + +void page_number_reg::set_value(units n) +{ + topdiv->set_page_number(n); +} + +int page_number_reg::get_value(units *res) +{ + *res = topdiv->get_page_number(); + return 1; +} + +class next_page_number_reg : public reg { +public: + const char *get_string(); +}; + +const char *next_page_number_reg::get_string() +{ + return itoa(topdiv->get_next_page_number()); +} + +class page_ejecting_reg : public reg { +public: + const char *get_string(); +}; + +const char *page_ejecting_reg::get_string() +{ + return itoa(topdiv->get_ejecting()); +} + +class constant_vunits_reg : public reg { + vunits *p; +public: + constant_vunits_reg(vunits *); + const char *get_string(); +}; + +constant_vunits_reg::constant_vunits_reg(vunits *q) : p(q) +{ +} + +const char *constant_vunits_reg::get_string() +{ + return itoa(p->to_units()); +} + +class nl_reg : public variable_reg { +public: + nl_reg(); + void set_value(units); +}; + +nl_reg::nl_reg() : variable_reg(&nl_reg_contents) +{ +} + +void nl_reg::set_value(units n) +{ + variable_reg::set_value(n); + // Setting nl to a negative value when the vertical position in + // the top-level diversion is 0 undoes the top of page transition, + // so that the header macro will be called as if the top of page + // transition hasn't happened. This is used by Larry Wall's + // wrapman program. Setting before_first_page to 2 rather than 1, + // tells top_level_diversion::begin_page not to call + // output_file::begin_page again. + if (n < 0 && topdiv->get_vertical_position() == V0) + topdiv->before_first_page = 2; +} + +void init_div_requests() +{ + init_request("wh", when_request); + init_request("ch", change_trap); + init_request("pl", page_length); + init_request("po", page_offset); + init_request("rs", restore_spacing); + init_request("ns", no_space); + init_request("sp", space_request); + init_request("di", divert); + init_request("da", divert_append); + init_request("bp", begin_page); + init_request("ne", need_space); + init_request("pn", page_number); + init_request("dt", diversion_trap); + init_request("rt", return_request); + init_request("mk", mark); + init_request("sv", save_vertical_space); + init_request("os", output_saved_vertical_space); + init_request("fl", flush_output); + init_request("vpt", vertical_position_traps); + init_request("ptr", print_traps); + number_reg_dictionary.define(".a", + new constant_int_reg(&last_post_line_extra_space)); + number_reg_dictionary.define(".z", new diversion_name_reg); + number_reg_dictionary.define(".o", new page_offset_reg); + number_reg_dictionary.define(".p", new page_length_reg); + number_reg_dictionary.define(".d", new vertical_position_reg); + number_reg_dictionary.define(".h", new high_water_mark_reg); + number_reg_dictionary.define(".t", new distance_to_next_trap_reg); + number_reg_dictionary.define("dl", new variable_reg(&dl_reg_contents)); + number_reg_dictionary.define("dn", new variable_reg(&dn_reg_contents)); + number_reg_dictionary.define("nl", new nl_reg); + number_reg_dictionary.define(".vpt", + new constant_int_reg(&vertical_position_traps_flag)); + number_reg_dictionary.define("%", new page_number_reg); + number_reg_dictionary.define(".pn", new next_page_number_reg); + number_reg_dictionary.define(".trunc", + new constant_vunits_reg(&truncated_space)); + number_reg_dictionary.define(".ne", + new constant_vunits_reg(&needed_space)); + number_reg_dictionary.define(".pe", new page_ejecting_reg); +} diff --git a/gnu/usr.bin/groff/troff/div.h b/gnu/usr.bin/groff/troff/div.h new file mode 100644 index 0000000000..dd27540133 --- /dev/null +++ b/gnu/usr.bin/groff/troff/div.h @@ -0,0 +1,146 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +class diversion { + friend void do_divert(int append); + friend void end_diversions(); + diversion *prev; +protected: + symbol nm; + vunits vertical_position; + vunits high_water_mark; +public: + vunits marked_place; + diversion(symbol s = NULL_SYMBOL); + virtual ~diversion(); + virtual void output(node *nd, int retain_size, vunits vs, int ls, hunits width) = 0; + virtual void transparent_output(unsigned char) = 0; + virtual void transparent_output(node *) = 0; + virtual void space(vunits distance, int forced = 0) = 0; +#ifdef COLUMN + virtual void vjustify(symbol) = 0; +#endif /* COLUMN */ + vunits get_vertical_position() { return vertical_position; } + vunits get_high_water_mark() { return high_water_mark; } + virtual vunits distance_to_next_trap() = 0; + void need(vunits); + const char *get_diversion_name() { return nm.contents(); } + virtual void set_diversion_trap(symbol, vunits) = 0; + virtual void clear_diversion_trap() = 0; + virtual void copy_file(const char *filename) = 0; +}; + +class macro; + +class macro_diversion : public diversion { + macro *mac; + hunits max_width; + symbol diversion_trap; + vunits diversion_trap_pos; +public: + macro_diversion(symbol, int); + ~macro_diversion(); + void output(node *nd, int retain_size, vunits vs, int ls, hunits width); + void transparent_output(unsigned char); + void transparent_output(node *); + void space(vunits distance, int forced = 0); +#ifdef COLUMN + void vjustify(symbol); +#endif /* COLUMN */ + vunits distance_to_next_trap(); + void set_diversion_trap(symbol, vunits); + void clear_diversion_trap(); + void copy_file(const char *filename); +}; + +struct trap { + trap *next; + vunits position; + symbol nm; + trap(symbol, vunits, trap *); +}; + +struct output_file; + +class top_level_diversion : public diversion { + int page_number; + int page_count; + int last_page_count; + vunits page_length; + hunits prev_page_offset; + hunits page_offset; + trap *page_trap_list; + trap *find_next_trap(vunits *); + int have_next_page_number; + int next_page_number; + int ejecting_page; // Is the current page being ejected? +public: + int before_first_page; + int no_space_mode; + top_level_diversion(); + void output(node *nd, int retain_size, vunits vs, int ls, hunits width); + void transparent_output(unsigned char); + void transparent_output(node *); + void space(vunits distance, int forced = 0); +#ifdef COLUMN + void vjustify(symbol); +#endif /* COLUMN */ + hunits get_page_offset() { return page_offset; } + vunits get_page_length() { return page_length; } + vunits distance_to_next_trap(); + void add_trap(symbol nm, vunits pos); + void change_trap(symbol nm, vunits pos); + void remove_trap(symbol); + void remove_trap_at(vunits pos); + void print_traps(); + int get_page_count() { return page_count; } + int get_page_number() { return page_number; } + int get_next_page_number(); + void set_page_number(int n) { page_number = n; } + int begin_page(); + void set_next_page_number(int); + void set_page_length(vunits); + void copy_file(const char *filename); + int get_ejecting() { return ejecting_page; } + void set_ejecting() { ejecting_page = 1; } + friend void page_offset(); + void set_diversion_trap(symbol, vunits); + void clear_diversion_trap(); + void set_last_page() { last_page_count = page_count; } +}; + +extern top_level_diversion *topdiv; +extern diversion *curdiv; + +extern int exit_started; +extern int done_end_macro; +extern int seen_last_page_ejector; + +void spring_trap(symbol); // implemented by input.c +extern int trap_sprung_flag; +void postpone_traps(); +int unpostpone_traps(); + +void push_page_ejector(); +void continue_page_eject(); +void handle_first_page_transition(); +void blank_line(); + +extern void cleanup_and_exit(int); diff --git a/gnu/usr.bin/groff/troff/env.cc b/gnu/usr.bin/groff/troff/env.cc new file mode 100644 index 0000000000..0d343ffc59 --- /dev/null +++ b/gnu/usr.bin/groff/troff/env.cc @@ -0,0 +1,3052 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "troff.h" +#include "symbol.h" +#include "dictionary.h" +#include "hvunits.h" +#include "env.h" +#include "request.h" +#include "node.h" +#include "token.h" +#include "div.h" +#include "reg.h" +#include "charinfo.h" +#include "searchpath.h" +#include "macropath.h" +#include + +symbol default_family("T"); + +enum { ADJUST_LEFT = 0, ADJUST_BOTH = 1, ADJUST_CENTER = 3, ADJUST_RIGHT = 5 }; + +enum { HYPHEN_LAST_LINE = 2, HYPHEN_LAST_CHARS = 4, HYPHEN_FIRST_CHARS = 8 }; + +struct env_list { + environment *env; + env_list *next; + env_list(environment *e, env_list *p) : env(e), next(p) {} +}; + +env_list *env_stack; +const int NENVIRONMENTS = 10; +environment *env_table[NENVIRONMENTS]; +dictionary env_dictionary(10); +environment *curenv; +static int next_line_number = 0; + +charinfo *field_delimiter_char; +charinfo *padding_indicator_char; + +int translate_space_to_dummy = 0; + +class pending_output_line { + node *nd; + int no_fill; + vunits vs; + int ls; + hunits width; +#ifdef WIDOW_CONTROL + int last_line; // Is it the last line of the paragraph? +#endif /* WIDOW_CONTROL */ +public: + pending_output_line *next; + + pending_output_line(node *, int, vunits, int, hunits, + pending_output_line * = 0); + ~pending_output_line(); + int output(); + +#ifdef WIDOW_CONTROL + friend void environment::mark_last_line(); + friend void environment::output(node *, int, vunits, int, hunits); +#endif /* WIDOW_CONTROL */ +}; + +pending_output_line::pending_output_line(node *n, int nf, vunits v, int l, + hunits w, pending_output_line *p) +: nd(n), no_fill(nf), vs(v), ls(l), width(w), +#ifdef WIDOW_CONTROL + last_line(0), +#endif /* WIDOW_CONTROL */ + next(p) +{ +} + +pending_output_line::~pending_output_line() +{ + delete_node_list(nd); +} + +int pending_output_line::output() +{ + if (trap_sprung_flag) + return 0; +#ifdef WIDOW_CONTROL + if (next && next->last_line && !no_fill) { + curdiv->need(vs*ls + vunits(vresolution)); + if (trap_sprung_flag) { + next->last_line = 0; // Try to avoid infinite loops. + return 0; + } + } +#endif + curdiv->output(nd, no_fill, vs, ls, width); + nd = 0; + return 1; +} + +void environment::output(node *nd, int no_fill, vunits vs, int ls, + hunits width) +{ +#ifdef WIDOW_CONTROL + while (pending_lines) { + if (widow_control && !pending_lines->no_fill && !pending_lines->next) + break; + if (!pending_lines->output()) + break; + pending_output_line *tem = pending_lines; + pending_lines = pending_lines->next; + delete tem; + } +#else /* WIDOW_CONTROL */ + output_pending_lines(); +#endif /* WIDOW_CONTROL */ + if (!trap_sprung_flag && !pending_lines +#ifdef WIDOW_CONTROL + && (!widow_control || no_fill) +#endif /* WIDOW_CONTROL */ + ) + curdiv->output(nd, no_fill, vs, ls, width); + else { + for (pending_output_line **p = &pending_lines; *p; p = &(*p)->next) + ; + *p = new pending_output_line(nd, no_fill, vs, ls, width); + } +} + +// a line from .tl goes at the head of the queue + +void environment::output_title(node *nd, int no_fill, vunits vs, int ls, + hunits width) +{ + if (!trap_sprung_flag) + curdiv->output(nd, no_fill, vs, ls, width); + else + pending_lines = new pending_output_line(nd, no_fill, vs, ls, width, + pending_lines); +} + +void environment::output_pending_lines() +{ + while (pending_lines && pending_lines->output()) { + pending_output_line *tem = pending_lines; + pending_lines = pending_lines->next; + delete tem; + } +} + +#ifdef WIDOW_CONTROL + +void environment::mark_last_line() +{ + if (!widow_control || !pending_lines) + return; + for (pending_output_line *p = pending_lines; p->next; p = p->next) + ; + if (!p->no_fill) + p->last_line = 1; +} + +void widow_control_request() +{ + int n; + if (has_arg() && get_integer(&n)) + curenv->widow_control = n != 0; + else + curenv->widow_control = 1; + skip_line(); +} + +#endif /* WIDOW_CONTROL */ + +/* font_size functions */ + +size_range *font_size::size_table = 0; +int font_size::nranges = 0; + +extern "C" { + +static int compare_ranges(const void *p1, const void *p2) +{ + return ((size_range *)p1)->min - ((size_range *)p2)->min; +} + +} + +void font_size::init_size_table(int *sizes) +{ + nranges = 0; + while (sizes[nranges*2] != 0) + nranges++; + assert(nranges > 0); + size_table = new size_range[nranges]; + for (int i = 0; i < nranges; i++) { + size_table[i].min = sizes[i*2]; + size_table[i].max = sizes[i*2 + 1]; + } + qsort(size_table, nranges, sizeof(size_range), compare_ranges); +} + +font_size::font_size(int sp) +{ + for (int i = 0; i < nranges; i++) { + if (sp < size_table[i].min) { + if (i > 0 && size_table[i].min - sp >= sp - size_table[i - 1].max) + p = size_table[i - 1].max; + else + p = size_table[i].min; + return; + } + if (sp <= size_table[i].max) { + p = sp; + return; + } + } + p = size_table[nranges - 1].max; +} + +int font_size::to_units() +{ + return scale(p, units_per_inch, sizescale*72); +} + +// we can't do this in a static constructor because various dictionaries +// have to get initialized first + +void init_environments() +{ + curenv = env_table[0] = new environment("0"); +} + +void tab_character() +{ + curenv->tab_char = get_optional_char(); + skip_line(); +} + +void leader_character() +{ + curenv->leader_char = get_optional_char(); + skip_line(); +} + +void environment::add_char(charinfo *ci) +{ + if (interrupted) + ; + // don't allow fields in dummy environments + else if (ci == field_delimiter_char && !dummy) { + if (current_field) + wrap_up_field(); + else + start_field(); + } + else if (current_field && ci == padding_indicator_char) + add_padding(); + else if (current_tab) { + if (tab_contents == 0) + tab_contents = new line_start_node; + if (ci != hyphen_indicator_char) + tab_contents = tab_contents->add_char(ci, this, &tab_width); + else + tab_contents = tab_contents->add_discretionary_hyphen(); + } + else { + if (line == 0) + start_line(); + if (ci != hyphen_indicator_char) + line = line->add_char(ci, this, &width_total); + else + line = line->add_discretionary_hyphen(); + } +} + +node *environment::make_char_node(charinfo *ci) +{ + return make_node(ci, this); +} + +void environment::add_node(node *n) +{ + assert(n != 0); + if (current_tab || current_field) + n->freeze_space(); + if (interrupted) { + delete n; + } + else if (current_tab) { + n->next = tab_contents; + tab_contents = n; + tab_width += n->width(); + } + else { + if (line == 0) { + if (discarding && n->discardable()) { + // XXX possibly: input_line_start -= n->width(); + delete n; + return; + } + start_line(); + } + width_total += n->width(); + space_total += n->nspaces(); + n->next = line; + line = n; + } +} + + +void environment::add_hyphen_indicator() +{ + if (current_tab || interrupted || current_field + || hyphen_indicator_char != 0) + return; + if (line == 0) + start_line(); + line = line->add_discretionary_hyphen(); +} + +int environment::get_hyphenation_flags() +{ + return hyphenation_flags; +} + +int environment::get_hyphen_line_max() +{ + return hyphen_line_max; +} + +int environment::get_hyphen_line_count() +{ + return hyphen_line_count; +} + +int environment::get_center_lines() +{ + return center_lines; +} + +int environment::get_right_justify_lines() +{ + return right_justify_lines; +} + +void environment::add_italic_correction() +{ + if (current_tab) { + if (tab_contents) + tab_contents = tab_contents->add_italic_correction(&tab_width); + } + else if (line) + line = line->add_italic_correction(&width_total); +} + +void environment::space_newline() +{ + assert(!current_tab && !current_field); + if (interrupted) + return; + hunits x = H0; + if (!translate_space_to_dummy) { + x = env_space_width(this); + if (node_list_ends_sentence(line) == 1) + x += env_sentence_space_width(this); + } + if (line != 0 && line->merge_space(x)) { + width_total += x; + return; + } + add_node(new word_space_node(x)); + possibly_break_line(spread_flag); + spread_flag = 0; +} + +void environment::space() +{ + if (interrupted) + return; + if (current_field && padding_indicator_char == 0) { + add_padding(); + return; + } + hunits x = translate_space_to_dummy ? H0 : env_space_width(this); + node *p = current_tab ? tab_contents : line; + hunits *tp = current_tab ? &tab_width : &width_total; + if (p && p->nspaces() == 1 && p->width() == x + && node_list_ends_sentence(p->next) == 1) { + hunits xx = translate_space_to_dummy ? H0 : env_sentence_space_width(this); + if (p->merge_space(xx)) { + *tp += xx; + return; + } + } + if (p && p->merge_space(x)) { + *tp += x; + return; + } + add_node(new word_space_node(x)); + possibly_break_line(spread_flag); + spread_flag = 0; +} + +void environment::set_font(symbol nm) +{ + if (interrupted) + return; + if (nm == symbol("P")) { + if (family->make_definite(prev_fontno) < 0) + return; + int tem = fontno; + fontno = prev_fontno; + prev_fontno = tem; + } + else { + int n = symbol_fontno(nm); + if (n < 0) { + n = next_available_font_position(); + if (!mount_font(n, nm)) + return; + } + if (family->make_definite(n) < 0) + return; + prev_fontno = fontno; + fontno = n; + } +} + +void environment::set_font(int n) +{ + if (interrupted) + return; + if (is_good_fontno(n)) { + prev_fontno = fontno; + fontno = n; + } + else + error("bad font number"); +} + +void environment::set_family(symbol fam) +{ + if (fam.is_null()) { + if (prev_family->make_definite(fontno) < 0) + return; + font_family *tem = family; + family = prev_family; + prev_family = tem; + } + else { + font_family *f = lookup_family(fam); + if (f->make_definite(fontno) < 0) + return; + prev_family = family; + family = f; + } +} + +void environment::set_size(int n) +{ + if (interrupted) + return; + if (n == 0) { + font_size temp = prev_size; + prev_size = size; + size = temp; + int temp2 = prev_requested_size; + prev_requested_size = requested_size; + requested_size = temp2; + } + else { + prev_size = size; + size = font_size(n); + prev_requested_size = requested_size; + requested_size = n; + } +} + +void environment::set_char_height(int n) +{ + if (interrupted) + return; + if (n == requested_size || n <= 0) + char_height = 0; + else + char_height = n; +} + +void environment::set_char_slant(int n) +{ + if (interrupted) + return; + char_slant = n; +} + +environment::environment(symbol nm) +: name(nm), + prev_line_length((units_per_inch*13)/2), + line_length((units_per_inch*13)/2), + prev_title_length((units_per_inch*13)/2), + title_length((units_per_inch*13)/2), + prev_size(sizescale*10), + size(sizescale*10), + requested_size(sizescale*10), + prev_requested_size(sizescale*10), + char_height(0), + char_slant(0), + space_size(12), + sentence_space_size(12), + adjust_mode(ADJUST_BOTH), + fill(1), + interrupted(0), + prev_line_interrupted(0), + center_lines(0), + right_justify_lines(0), + prev_vertical_spacing(points_to_units(12)), + vertical_spacing(points_to_units(12)), + prev_line_spacing(1), + line_spacing(1), + prev_indent(0), + indent(0), + have_temporary_indent(0), + temporary_indent(0), + underline_lines(0), + input_trap_count(0), + prev_text_length(0), + width_total(0), + space_total(0), + input_line_start(0), + control_char('.'), + no_break_control_char('\''), + hyphen_indicator_char(0), + spread_flag(0), + line(0), + pending_lines(0), + discarding(0), + tabs(units_per_inch/2, TAB_LEFT), + current_tab(TAB_NONE), + current_field(0), + margin_character_flags(0), + margin_character_node(0), + margin_character_distance(points_to_units(10)), + numbering_nodes(0), + number_text_separation(1), + line_number_multiple(1), + line_number_indent(0), + no_number_count(0), + tab_char(0), + leader_char(charset_table['.']), + hyphenation_flags(1), + dummy(0), + leader_node(0), +#ifdef WIDOW_CONTROL + widow_control(0), +#endif /* WIDOW_CONTROL */ + hyphen_line_count(0), + hyphen_line_max(-1), + hyphenation_space(H0), + hyphenation_margin(H0), + composite(0) +{ + prev_family = family = lookup_family(default_family); + prev_fontno = fontno = 1; + if (!is_good_fontno(1)) + fatal("font number 1 not a valid font"); + if (family->make_definite(1) < 0) + fatal("invalid default family `%1'", default_family.contents()); + prev_fontno = fontno; +} + +environment::environment(const environment *e) +: name(e->name), // so that eg `.if "\n[.ev]"0"' works + prev_line_length(e->prev_line_length), + line_length(e->line_length), + prev_title_length(e->prev_title_length), + title_length(e->title_length), + prev_size(e->prev_size), + size(e->size), + prev_requested_size(e->prev_requested_size), + requested_size(e->requested_size), + char_height(e->char_height), + char_slant(e->char_slant), + space_size(e->space_size), + sentence_space_size(e->sentence_space_size), + adjust_mode(e->adjust_mode), + fill(e->fill), + interrupted(0), + prev_line_interrupted(0), + center_lines(0), + right_justify_lines(0), + prev_vertical_spacing(e->prev_vertical_spacing), + vertical_spacing(e->vertical_spacing), + prev_line_spacing(e->prev_line_spacing), + line_spacing(e->line_spacing), + prev_indent(e->prev_indent), + indent(e->indent), + have_temporary_indent(0), + temporary_indent(0), + underline_lines(0), + input_trap_count(0), + prev_text_length(e->prev_text_length), + width_total(0), + space_total(0), + input_line_start(0), + control_char(e->control_char), + no_break_control_char(e->no_break_control_char), + hyphen_indicator_char(e->hyphen_indicator_char), + spread_flag(0), + line(0), + pending_lines(0), + discarding(0), + tabs(e->tabs), + current_tab(TAB_NONE), + current_field(0), + margin_character_flags(e->margin_character_flags), + margin_character_node(e->margin_character_node), + margin_character_distance(e->margin_character_distance), + numbering_nodes(0), + number_text_separation(e->number_text_separation), + line_number_multiple(e->line_number_multiple), + line_number_indent(e->line_number_indent), + no_number_count(e->no_number_count), + tab_char(e->tab_char), + leader_char(e->leader_char), + hyphenation_flags(e->hyphenation_flags), + fontno(e->fontno), + prev_fontno(e->prev_fontno), + dummy(1), + family(e->family), + prev_family(e->prev_family), + leader_node(0), +#ifdef WIDOW_CONTROL + widow_control(e->widow_control), +#endif /* WIDOW_CONTROL */ + hyphen_line_max(e->hyphen_line_max), + hyphen_line_count(0), + hyphenation_space(e->hyphenation_space), + hyphenation_margin(e->hyphenation_margin), + composite(0) +{ +} + +environment::~environment() +{ + delete leader_node; + delete_node_list(line); + delete_node_list(numbering_nodes); +} + +hunits environment::get_input_line_position() +{ + hunits n; + if (line == 0) + n = -input_line_start; + else + n = width_total - input_line_start; + if (current_tab) + n += tab_width; + return n; +} + +void environment::set_input_line_position(hunits n) +{ + input_line_start = line == 0 ? -n : width_total - n; + if (current_tab) + input_line_start += tab_width; +} + +hunits environment::get_line_length() +{ + return line_length; +} + +hunits environment::get_saved_line_length() +{ + if (line) + return target_text_length + saved_indent; + else + return line_length; +} + +vunits environment::get_vertical_spacing() +{ + return vertical_spacing; +} + +int environment::get_line_spacing() +{ + return line_spacing; +} + +int environment::get_bold() +{ + return get_bold_fontno(fontno); +} + +hunits environment::get_digit_width() +{ + return env_digit_width(this); +} + +int environment::get_adjust_mode() +{ + return adjust_mode; +} + +int environment::get_fill() +{ + return fill; +} + +hunits environment::get_indent() +{ + return indent; +} + +hunits environment::get_saved_indent() +{ + if (line) + return saved_indent; + else if (have_temporary_indent) + return temporary_indent; + else + return indent; +} + +hunits environment::get_temporary_indent() +{ + return temporary_indent; +} + +hunits environment::get_title_length() +{ + return title_length; +} + +node *environment::get_prev_char() +{ + for (node *n = current_tab ? tab_contents : line; n; n = n->next) { + node *last = n->last_char_node(); + if (last) + return last; + } + return 0; +} + +hunits environment::get_prev_char_width() +{ + node *last = get_prev_char(); + if (!last) + return H0; + return last->width(); +} + +hunits environment::get_prev_char_skew() +{ + node *last = get_prev_char(); + if (!last) + return H0; + return last->skew(); +} + +vunits environment::get_prev_char_height() +{ + node *last = get_prev_char(); + if (!last) + return V0; + vunits min, max; + last->vertical_extent(&min, &max); + return -min; +} + +vunits environment::get_prev_char_depth() +{ + node *last = get_prev_char(); + if (!last) + return V0; + vunits min, max; + last->vertical_extent(&min, &max); + return max; +} + +hunits environment::get_text_length() +{ + hunits n = line == 0 ? H0 : width_total; + if (current_tab) + n += tab_width; + return n; +} + +hunits environment::get_prev_text_length() +{ + return prev_text_length; +} + + +static int sb_reg_contents = 0; +static int st_reg_contents = 0; +static int ct_reg_contents = 0; +static int rsb_reg_contents = 0; +static int rst_reg_contents = 0; +static int skw_reg_contents = 0; +static int ssc_reg_contents = 0; + +void environment::width_registers() +{ + // this is used to implement \w; it sets the st, sb, ct registers + vunits min = 0, max = 0, cur = 0; + int character_type = 0; + ssc_reg_contents = line ? line->subscript_correction().to_units() : 0; + skw_reg_contents = line ? line->skew().to_units() : 0; + line = reverse_node_list(line); + vunits real_min = V0; + vunits real_max = V0; + vunits v1, v2; + for (node *tem = line; tem; tem = tem->next) { + tem->vertical_extent(&v1, &v2); + v1 += cur; + if (v1 < real_min) + real_min = v1; + v2 += cur; + if (v2 > real_max) + real_max = v2; + if ((cur += tem->vertical_width()) < min) + min = cur; + else if (cur > max) + max = cur; + character_type |= tem->character_type(); + } + line = reverse_node_list(line); + st_reg_contents = -min.to_units(); + sb_reg_contents = -max.to_units(); + rst_reg_contents = -real_min.to_units(); + rsb_reg_contents = -real_max.to_units(); + ct_reg_contents = character_type; +} + +node *environment::extract_output_line() +{ + if (current_tab) + wrap_up_tab(); + node *n = line; + line = 0; + return n; +} + +/* environment related requests */ + +void environment_switch() +{ + int pop = 0; // 1 means pop, 2 means pop but no error message on underflow + if (curenv->is_dummy()) + error("can't switch environments when current environment is dummy"); + else if (!has_arg()) + pop = 1; + else { + symbol nm; + if (!tok.delimiter()) { + // It looks like a number. + int n; + if (get_integer(&n)) { + if (n >= 0 && n < NENVIRONMENTS) { + env_stack = new env_list(curenv, env_stack); + if (env_table[n] == 0) + env_table[n] = new environment(itoa(n)); + curenv = env_table[n]; + } + else + nm = itoa(n); + } + else + pop = 2; + } + else { + nm = get_long_name(1); + if (nm.is_null()) + pop = 2; + } + if (!nm.is_null()) { + environment *e = (environment *)env_dictionary.lookup(nm); + if (!e) { + e = new environment(nm); + (void)env_dictionary.lookup(nm, e); + } + env_stack = new env_list(curenv, env_stack); + curenv = e; + } + } + if (pop) { + if (env_stack == 0) { + if (pop == 1) + error("environment stack underflow"); + } + else { + curenv = env_stack->env; + env_list *tem = env_stack; + env_stack = env_stack->next; + delete tem; + } + } + skip_line(); +} + + +static symbol P_symbol("P"); + +void font_change() +{ + symbol s = get_name(); + int is_number = 1; + if (s.is_null() || s == P_symbol) { + s = P_symbol; + is_number = 0; + } + else { + for (const char *p = s.contents(); p != 0 && *p != 0; p++) + if (!csdigit(*p)) { + is_number = 0; + break; + } + } + if (is_number) + curenv->set_font(atoi(s.contents())); + else + curenv->set_font(s); + skip_line(); +} + +void family_change() +{ + symbol s = get_name(1); + if (!s.is_null()) + curenv->set_family(s); + skip_line(); +} + +void point_size() +{ + int n; + if (has_arg() && get_number(&n, 'z', curenv->get_requested_point_size())) { + if (n <= 0) + n = 1; + curenv->set_size(n); + } + else + curenv->set_size(0); + skip_line(); +} + +void space_size() +{ + int n; + if (get_integer(&n)) { + curenv->space_size = n; + if (has_arg() && get_integer(&n)) + curenv->sentence_space_size = n; + else + curenv->sentence_space_size = curenv->space_size; + } + skip_line(); +} + +void fill() +{ + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + curenv->fill = 1; + tok.next(); +} + +void no_fill() +{ + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + curenv->fill = 0; + tok.next(); +} + +void center() +{ + int n; + if (!has_arg() || !get_integer(&n)) + n = 1; + else if (n < 0) + n = 0; + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + curenv->right_justify_lines = 0; + curenv->center_lines = n; + tok.next(); +} + +void right_justify() +{ + int n; + if (!has_arg() || !get_integer(&n)) + n = 1; + else if (n < 0) + n = 0; + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + curenv->center_lines = 0; + curenv->right_justify_lines = n; + tok.next(); +} + +void line_length() +{ + hunits temp; + if (has_arg() && get_hunits(&temp, 'm', curenv->line_length)) { + if (temp < H0) { + warning(WARN_RANGE, "bad line length %1u", temp.to_units()); + temp = H0; + } + } + else + temp = curenv->prev_line_length; + curenv->prev_line_length = curenv->line_length; + curenv->line_length = temp; + skip_line(); +} + +void title_length() +{ + hunits temp; + if (has_arg() && get_hunits(&temp, 'm', curenv->title_length)) { + if (temp < H0) { + warning(WARN_RANGE, "bad title length %1u", temp.to_units()); + temp = H0; + } + } + else + temp = curenv->prev_title_length; + curenv->prev_title_length = curenv->title_length; + curenv->title_length = temp; + skip_line(); +} + +void vertical_spacing() +{ + vunits temp; + if (has_arg() && get_vunits(&temp, 'p', curenv->vertical_spacing)) { + if (temp <= V0) { + warning(WARN_RANGE, "vertical spacing must be greater than 0"); + temp = vresolution; + } + } + else + temp = curenv->prev_vertical_spacing; + curenv->prev_vertical_spacing = curenv->vertical_spacing; + curenv->vertical_spacing = temp; + skip_line(); +} + +void line_spacing() +{ + int temp; + if (has_arg() && get_integer(&temp)) { + if (temp < 1) { + warning(WARN_RANGE, "value %1 out of range: interpreted as 1", temp); + temp = 1; + } + } + else + temp = curenv->prev_line_spacing; + curenv->prev_line_spacing = curenv->line_spacing; + curenv->line_spacing = temp; + skip_line(); +} + +void indent() +{ + hunits temp; + if (has_arg() && get_hunits(&temp, 'm', curenv->indent)) { + if (temp < H0) { + warning(WARN_RANGE, "indent cannot be negative"); + temp = H0; + } + } + else + temp = curenv->prev_indent; + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + curenv->have_temporary_indent = 0; + curenv->prev_indent = curenv->indent; + curenv->indent = temp; + tok.next(); +} + +void temporary_indent() +{ + int err = 0; + hunits temp; + if (!get_hunits(&temp, 'm', curenv->get_indent())) + err = 1; + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + if (temp < H0) { + warning(WARN_RANGE, "total indent cannot be negative"); + temp = H0; + } + if (!err) { + curenv->temporary_indent = temp; + curenv->have_temporary_indent = 1; + } + tok.next(); +} + +void underline() +{ + int n; + if (!has_arg() || !get_integer(&n)) + n = 1; + if (n <= 0) { + if (curenv->underline_lines > 0) { + curenv->prev_fontno = curenv->fontno; + curenv->fontno = curenv->pre_underline_fontno; + } + curenv->underline_lines = 0; + } + else { + curenv->underline_lines = n; + curenv->pre_underline_fontno = curenv->fontno; + curenv->fontno = get_underline_fontno(); + } + skip_line(); +} + +void control_char() +{ + curenv->control_char = '.'; + if (has_arg()) { + if (tok.ch() == 0) + error("bad control character"); + else + curenv->control_char = tok.ch(); + } + skip_line(); +} + +void no_break_control_char() +{ + curenv->no_break_control_char = '\''; + if (has_arg()) { + if (tok.ch() == 0) + error("bad control character"); + else + curenv->no_break_control_char = tok.ch(); + } + skip_line(); +} + +void margin_character() +{ + charinfo *ci = get_optional_char(); + if (ci) { + node *nd = curenv->make_char_node(ci); + if (nd) { + delete curenv->margin_character_node; + curenv->margin_character_node = nd; + curenv->margin_character_flags = (MARGIN_CHARACTER_ON + |MARGIN_CHARACTER_NEXT); + hunits d; + if (has_arg() && get_hunits(&d, 'm')) + curenv->margin_character_distance = d; + } + } + else { + curenv->margin_character_flags &= ~MARGIN_CHARACTER_ON; + if (curenv->margin_character_flags == 0) { + delete curenv->margin_character_node; + curenv->margin_character_node = 0; + } + } + skip_line(); +} + +void number_lines() +{ + delete_node_list(curenv->numbering_nodes); + curenv->numbering_nodes = 0; + if (has_arg()) { + node *nd = 0; + for (int i = '9'; i >= '0'; i--) { + node *tem = make_node(charset_table[i], curenv); + if (!tem) { + skip_line(); + return; + } + tem->next = nd; + nd = tem; + } + curenv->numbering_nodes = nd; + curenv->line_number_digit_width = env_digit_width(curenv); + int n; + if (!tok.delimiter()) { + if (get_integer(&n, next_line_number)) { + next_line_number = n; + if (next_line_number < 0) { + warning(WARN_RANGE, "negative line number"); + next_line_number = 0; + } + } + } + else + while (!tok.space() && !tok.newline() && !tok.eof()) + tok.next(); + if (has_arg()) { + if (!tok.delimiter()) { + if (get_integer(&n)) { + if (n <= 0) { + warning(WARN_RANGE, "negative or zero line number multiple"); + } + else + curenv->line_number_multiple = n; + } + } + else + while (!tok.space() && !tok.newline() && !tok.eof()) + tok.next(); + if (has_arg()) { + if (!tok.delimiter()) { + if (get_integer(&n)) + curenv->number_text_separation = n; + } + else + while (!tok.space() && !tok.newline() && !tok.eof()) + tok.next(); + if (has_arg() && !tok.delimiter() && get_integer(&n)) + curenv->line_number_indent = n; + } + } + } + skip_line(); +} + +void no_number() +{ + int n; + if (has_arg() && get_integer(&n)) + curenv->no_number_count = n > 0 ? n : 0; + else + curenv->no_number_count = 1; + skip_line(); +} + +void no_hyphenate() +{ + curenv->hyphenation_flags = 0; + skip_line(); +} + +void hyphenate_request() +{ + int n; + if (has_arg() && get_integer(&n)) + curenv->hyphenation_flags = n; + else + curenv->hyphenation_flags = 1; + skip_line(); +} + +void hyphen_char() +{ + curenv->hyphen_indicator_char = get_optional_char(); + skip_line(); +} + +void hyphen_line_max_request() +{ + int n; + if (has_arg() && get_integer(&n)) + curenv->hyphen_line_max = n; + else + curenv->hyphen_line_max = -1; + skip_line(); +} + +void environment::interrupt() +{ + if (!dummy) { + add_node(new transparent_dummy_node); + interrupted = 1; + } +} + +void environment::newline() +{ + if (underline_lines > 0) { + if (--underline_lines == 0) { + prev_fontno = fontno; + fontno = pre_underline_fontno; + } + } + if (current_field) + wrap_up_field(); + if (current_tab) + wrap_up_tab(); + // strip trailing spaces + while (line != 0 && line->discardable()) { + width_total -= line->width(); + space_total -= line->nspaces(); + node *tem = line; + line = line->next; + delete tem; + } + node *to_be_output = 0; + hunits to_be_output_width; + prev_line_interrupted = 0; + if (dummy) + space_newline(); + else if (interrupted) { + interrupted = 0; + // see environment::final_break + prev_line_interrupted = exit_started ? 2 : 1; + } + else if (center_lines > 0) { + --center_lines; + hunits x = target_text_length - width_total; + if (x > H0) + saved_indent += x/2; + to_be_output = line; + to_be_output_width = width_total; + line = 0; + } + else if (right_justify_lines > 0) { + --right_justify_lines; + hunits x = target_text_length - width_total; + if (x > H0) + saved_indent += x; + to_be_output = line; + to_be_output_width = width_total; + line = 0; + } + else if (fill) + space_newline(); + else { + to_be_output = line; + to_be_output_width = width_total; + line = 0; + } + input_line_start = line == 0 ? H0 : width_total; + if (to_be_output) { + output_line(to_be_output, to_be_output_width); + hyphen_line_count = 0; + } + if (input_trap_count > 0) { + if (--input_trap_count == 0) + spring_trap(input_trap); + } +} + +void environment::output_line(node *n, hunits width) +{ + prev_text_length = width; + if (margin_character_flags) { + hunits d = line_length + margin_character_distance - saved_indent - width; + if (d > 0) { + n = new hmotion_node(d, n); + width += d; + } + margin_character_flags &= ~MARGIN_CHARACTER_NEXT; + node *tem; + if (!margin_character_flags) { + tem = margin_character_node; + margin_character_node = 0; + } + else + tem = margin_character_node->copy(); + tem->next = n; + n = tem; + width += tem->width(); + } + node *nn = 0; + while (n != 0) { + node *tem = n->next; + n->next = nn; + nn = n; + n = tem; + } + if (!saved_indent.is_zero()) + nn = new hmotion_node(saved_indent, nn); + width += saved_indent; + if (no_number_count > 0) + --no_number_count; + else if (numbering_nodes) { + hunits w = (line_number_digit_width + *(3+line_number_indent+number_text_separation)); + if (next_line_number % line_number_multiple != 0) + nn = new hmotion_node(w, nn); + else { + hunits x = w; + nn = new hmotion_node(number_text_separation*line_number_digit_width, + nn); + x -= number_text_separation*line_number_digit_width; + char buf[30]; + sprintf(buf, "%3d", next_line_number); + for (char *p = strchr(buf, '\0') - 1; p >= buf && *p != ' '; --p) { + node *gn = numbering_nodes; + for (int count = *p - '0'; count > 0; count--) + gn = gn->next; + gn = gn->copy(); + x -= gn->width(); + gn->next = nn; + nn = gn; + } + nn = new hmotion_node(x, nn); + } + width += w; + ++next_line_number; + } + output(nn, !fill, vertical_spacing, line_spacing, width); +} + +void environment::start_line() +{ + assert(line == 0); + discarding = 0; + line = new line_start_node; + if (have_temporary_indent) { + saved_indent = temporary_indent; + have_temporary_indent = 0; + } + else + saved_indent = indent; + target_text_length = line_length - saved_indent; + width_total = H0; + space_total = 0; +} + +hunits environment::get_hyphenation_space() +{ + return hyphenation_space; +} + +void hyphenation_space_request() +{ + hunits n; + if (get_hunits(&n, 'm')) { + if (n < H0) { + warning(WARN_RANGE, "hyphenation space cannot be negative"); + n = H0; + } + curenv->hyphenation_space = n; + } + skip_line(); +} + +hunits environment::get_hyphenation_margin() +{ + return hyphenation_margin; +} + +void hyphenation_margin_request() +{ + hunits n; + if (get_hunits(&n, 'm')) { + if (n < H0) { + warning(WARN_RANGE, "hyphenation margin cannot be negative"); + n = H0; + } + curenv->hyphenation_margin = n; + } + skip_line(); +} + +breakpoint *environment::choose_breakpoint() +{ + hunits x = width_total; + int s = space_total; + node *n = line; + breakpoint *best_bp = 0; // the best breakpoint so far + int best_bp_fits = 0; + while (n != 0) { + x -= n->width(); + s -= n->nspaces(); + breakpoint *bp = n->get_breakpoints(x, s); + while (bp != 0) { + if (bp->width <= target_text_length) { + if (!bp->hyphenated) { + breakpoint *tem = bp->next; + bp->next = 0; + while (tem != 0) { + breakpoint *tem1 = tem; + tem = tem->next; + delete tem1; + } + if (best_bp_fits + // Decide whether to use the hyphenated breakpoint. + && (hyphen_line_max < 0 + // Only choose the hyphenated breakpoint if it would not + // exceed the maximum number of consecutive hyphenated + // lines. + || hyphen_line_count + 1 <= hyphen_line_max) + && !(adjust_mode == ADJUST_BOTH + // Don't choose the hyphenated breakpoint if the line + // can be justified by adding no more than + // hyphenation_space to any word space. + ? (bp->nspaces > 0 + && (((target_text_length - bp->width + + (bp->nspaces - 1)*hresolution)/bp->nspaces) + <= hyphenation_space)) + // Don't choose the hyphenated breakpoint if the line + // is no more than hyphenation_margin short. + : target_text_length - bp->width <= hyphenation_margin)) { + delete bp; + return best_bp; + } + if (best_bp) + delete best_bp; + return bp; + } + else { + if ((adjust_mode == ADJUST_BOTH + ? hyphenation_space == H0 + : hyphenation_margin == H0) + && (hyphen_line_max < 0 + || hyphen_line_count + 1 <= hyphen_line_max)) { + // No need to consider a non-hyphenated breakpoint. + if (best_bp) + delete best_bp; + return bp; + } + // It fits but it's hyphenated. + if (!best_bp_fits) { + if (best_bp) + delete best_bp; + best_bp = bp; + bp = bp->next; + best_bp_fits = 1; + } + else { + breakpoint *tem = bp; + bp = bp->next; + delete tem; + } + } + } + else { + if (best_bp) + delete best_bp; + best_bp = bp; + bp = bp->next; + } + } + n = n->next; + } + if (best_bp) { + if (!best_bp_fits) + warning(WARN_BREAK, "can't break line"); + return best_bp; + } + return 0; +} + +void environment::hyphenate_line() +{ + if (line == 0) + return; + hyphenation_type prev_type = line->get_hyphenation_type(); + for (node **startp = &line->next; *startp != 0; startp = &(*startp)->next) { + hyphenation_type this_type = (*startp)->get_hyphenation_type(); + if (prev_type == HYPHEN_BOUNDARY && this_type == HYPHEN_MIDDLE) + break; + prev_type = this_type; + } + if (*startp == 0) + return; + node *tem = *startp; + int i = 0; + do { + ++i; + tem = tem->next; + } while (tem != 0 && tem->get_hyphenation_type() == HYPHEN_MIDDLE); + int inhibit = (tem != 0 && tem->get_hyphenation_type() == HYPHEN_INHIBIT); + node *end = tem; + hyphen_list *sl = 0; + tem = *startp; + node *forward = 0; + while (tem != end) { + sl = tem->get_hyphen_list(sl); + node *tem1 = tem; + tem = tem->next; + tem1->next = forward; + forward = tem1; + } + if (!inhibit) { + // this is for characters like hyphen and emdash + int prev_code = 0; + for (hyphen_list *h = sl; h; h = h->next) { + h->breakable = (prev_code != 0 + && h->next != 0 + && h->next->hyphenation_code != 0); + prev_code = h->hyphenation_code; + } + } + if (hyphenation_flags != 0 + && !inhibit + // this may not be right if we have extra space on this line + && !((hyphenation_flags & HYPHEN_LAST_LINE) + && curdiv->distance_to_next_trap() <= line_spacing*vertical_spacing) + && i >= 4) + hyphenate(sl, hyphenation_flags); + while (forward != 0) { + node *tem1 = forward; + forward = forward->next; + tem1->next = 0; + tem = tem1->add_self(tem, &sl); + } + *startp = tem; +} + +static node *node_list_reverse(node *n) +{ + node *res = 0; + while (n) { + node *tem = n; + n = n->next; + tem->next = res; + res = tem; + } + return res; +} + +static void distribute_space(node *n, int nspaces, hunits desired_space, + int force_reverse = 0) +{ + static int reverse = 0; + if (force_reverse || reverse) + n = node_list_reverse(n); + for (node *tem = n; tem; tem = tem->next) + tem->spread_space(&nspaces, &desired_space); + if (force_reverse || reverse) + (void)node_list_reverse(n); + if (!force_reverse) + reverse = !reverse; + assert(desired_space.is_zero() && nspaces == 0); +} + +void environment::possibly_break_line(int forced) +{ + if (!fill || current_tab || current_field || dummy) + return; + while (line != 0 && (forced || width_total > target_text_length)) { + hyphenate_line(); + breakpoint *bp = choose_breakpoint(); + if (bp == 0) + // we'll find one eventually + return; + node *pre, *post; + node **ndp = &line; + while (*ndp != bp->nd) + ndp = &(*ndp)->next; + bp->nd->split(bp->index, &pre, &post); + *ndp = post; + hunits extra_space_width = H0; + switch(adjust_mode) { + case ADJUST_BOTH: + if (bp->nspaces != 0) + extra_space_width = target_text_length - bp->width; + break; + case ADJUST_CENTER: + saved_indent += (target_text_length - bp->width)/2; + break; + case ADJUST_RIGHT: + saved_indent += target_text_length - bp->width; + break; + } + distribute_space(pre, bp->nspaces, extra_space_width); + hunits output_width = bp->width + extra_space_width; + input_line_start -= output_width; + if (bp->hyphenated) + hyphen_line_count++; + else + hyphen_line_count = 0; + delete bp; + space_total = 0; + width_total = 0; + node *first_non_discardable = 0; + for (node *tem = line; tem != 0; tem = tem->next) + if (!tem->discardable()) + first_non_discardable = tem; + node *to_be_discarded; + if (first_non_discardable) { + to_be_discarded = first_non_discardable->next; + first_non_discardable->next = 0; + for (tem = line; tem != 0; tem = tem->next) { + width_total += tem->width(); + space_total += tem->nspaces(); + } + discarding = 0; + } + else { + discarding = 1; + to_be_discarded = line; + line = 0; + } + // Do output_line() here so that line will be 0 iff the + // the environment will be empty. + output_line(pre, output_width); + while (to_be_discarded != 0) { + tem = to_be_discarded; + to_be_discarded = to_be_discarded->next; + input_line_start -= tem->width(); + delete tem; + } + if (line != 0) { + if (have_temporary_indent) { + saved_indent = temporary_indent; + have_temporary_indent = 0; + } + else + saved_indent = indent; + target_text_length = line_length - saved_indent; + } + } +} + +/* +Do the break at the end of input after the end macro (if any). + +Unix troff behaves as follows: if the last line is + +foo bar\c + +it will output foo on the current page, and bar on the next page; +if the last line is + +foo\c + +or + +foo bar + +everything will be output on the current page. This behaviour must be +considered a bug. + +The problem is that some macro packages rely on this. For example, +the ATK macros have an end macro that emits \c if it needs to print a +table of contents but doesn't do a 'bp in the end macro; instead the +'bp is done in the bottom of page trap. This works with Unix troff, +provided that the current environment is not empty at the end of the +input file. + +The following will make macro packages that do that sort of thing work +even if the current environment is empty at the end of the input file. +If the last input line used \c and this line occurred in the end macro, +then we'll force everything out on the current page, but we'll make +sure that the environment isn't empty so that we won't exit at the +bottom of this page. +*/ + +void environment::final_break() +{ + if (prev_line_interrupted == 2) { + do_break(); + add_node(new transparent_dummy_node); + } + else + do_break(); +} + +void environment::do_break() +{ + if (curdiv == topdiv && topdiv->before_first_page) { + topdiv->begin_page(); + return; + } + if (current_tab) + wrap_up_tab(); + if (line) { + line = new space_node(H0, line); // this is so that hyphenation works + space_total++; + possibly_break_line(); + } + while (line != 0 && line->discardable()) { + width_total -= line->width(); + space_total -= line->nspaces(); + node *tem = line; + line = line->next; + delete tem; + } + discarding = 0; + input_line_start = H0; + if (line != 0) { + if (fill) { + switch (adjust_mode) { + case ADJUST_CENTER: + saved_indent += (target_text_length - width_total)/2; + break; + case ADJUST_RIGHT: + saved_indent += target_text_length - width_total; + break; + } + } + node *tem = line; + line = 0; + output_line(tem, width_total); + hyphen_line_count = 0; + } + prev_line_interrupted = 0; +#ifdef WIDOW_CONTROL + mark_last_line(); + output_pending_lines(); +#endif /* WIDOW_CONTROL */ +} + +int environment::is_empty() +{ + return !current_tab && line == 0 && pending_lines == 0; +} + +void break_request() +{ + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + tok.next(); +} + +void title() +{ + if (curdiv == topdiv && topdiv->before_first_page) { + handle_initial_title(); + return; + } + node *part[3]; + hunits part_width[3]; + part[0] = part[1] = part[2] = 0; + environment env(curenv); + environment *oldenv = curenv; + curenv = &env; + read_title_parts(part, part_width); + curenv = oldenv; + curenv->size = env.size; + curenv->prev_size = env.prev_size; + curenv->requested_size = env.requested_size; + curenv->prev_requested_size = env.prev_requested_size; + curenv->char_height = env.char_height; + curenv->char_slant = env.char_slant; + curenv->fontno = env.fontno; + curenv->prev_fontno = env.prev_fontno; + node *n = 0; + node *p = part[2]; + while (p != 0) { + node *tem = p; + p = p->next; + tem->next = n; + n = tem; + } + hunits title_length(curenv->title_length); + hunits f = title_length - part_width[1]; + hunits f2 = f/2; + n = new hmotion_node(f2 - part_width[2], n); + p = part[1]; + while (p != 0) { + node *tem = p; + p = p->next; + tem->next = n; + n = tem; + } + n = new hmotion_node(f - f2 - part_width[0], n); + p = part[0]; + while (p != 0) { + node *tem = p; + p = p->next; + tem->next = n; + n = tem; + } + curenv->output_title(n, !curenv->fill, curenv->vertical_spacing, + curenv->line_spacing, title_length); + curenv->hyphen_line_count = 0; + tok.next(); +} + +void adjust() +{ + curenv->adjust_mode |= 1; + if (has_arg()) { + switch (tok.ch()) { + case 'l': + curenv->adjust_mode = ADJUST_LEFT; + break; + case 'r': + curenv->adjust_mode = ADJUST_RIGHT; + break; + case 'c': + curenv->adjust_mode = ADJUST_CENTER; + break; + case 'b': + case 'n': + curenv->adjust_mode = ADJUST_BOTH; + break; + default: + int n; + if (get_integer(&n)) { + if (n < 0) + warning(WARN_RANGE, "negative adjustment mode"); + else if (n > 5) { + curenv->adjust_mode = 5; + warning(WARN_RANGE, "adjustment mode `%1' out of range", n); + } + else + curenv->adjust_mode = n; + } + } + } + skip_line(); +} + +void no_adjust() +{ + curenv->adjust_mode &= ~1; + skip_line(); +} + +void input_trap() +{ + curenv->input_trap_count = 0; + int n; + if (has_arg() && get_integer(&n)) { + if (n <= 0) + warning(WARN_RANGE, + "number of lines for input trap must be greater than zero"); + else { + symbol s = get_name(1); + if (!s.is_null()) { + curenv->input_trap_count = n; + curenv->input_trap = s; + } + } + } + skip_line(); +} + +/* tabs */ + +// must not be R or C or L or a legitimate part of a number expression +const char TAB_REPEAT_CHAR = 'T'; + +struct tab { + tab *next; + hunits pos; + tab_type type; + tab(hunits, tab_type); + enum { BLOCK = 1024 }; + static tab *free_list; + void *operator new(size_t); + void operator delete(void *); +}; + +tab *tab::free_list = 0; + +void *tab::operator new(size_t n) +{ + assert(n == sizeof(tab)); + if (!free_list) { + free_list = (tab *)new char[sizeof(tab)*BLOCK]; + for (int i = 0; i < BLOCK - 1; i++) + free_list[i].next = free_list + i + 1; + free_list[BLOCK-1].next = 0; + } + tab *p = free_list; + free_list = (tab *)(free_list->next); + p->next = 0; + return p; +} + +#ifdef __GNUG__ +/* cfront can't cope with this. */ +inline +#endif +void tab::operator delete(void *p) +{ + if (p) { + ((tab *)p)->next = free_list; + free_list = (tab *)p; + } +} + +tab::tab(hunits x, tab_type t) : next(0), pos(x), type(t) +{ +} + +tab_stops::tab_stops(hunits distance, tab_type type) + : initial_list(0) +{ + repeated_list = new tab(distance, type); +} + +tab_stops::~tab_stops() +{ + clear(); +} + +tab_type tab_stops::distance_to_next_tab(hunits curpos, hunits *distance) +{ + hunits lastpos = 0; + for (tab *tem = initial_list; tem && tem->pos <= curpos; tem = tem->next) + lastpos = tem->pos; + if (tem) { + *distance = tem->pos - curpos; + return tem->type; + } + if (repeated_list == 0) + return TAB_NONE; + hunits base = lastpos; + for (;;) { + for (tem = repeated_list; tem && tem->pos + base <= curpos; tem = tem->next) + lastpos = tem->pos; + if (tem) { + *distance = tem->pos + base - curpos; + return tem->type; + } + assert(lastpos > 0); + base += lastpos; + } + return TAB_NONE; +} + +const char *tab_stops::to_string() +{ + static char *buf = 0; + static int buf_size = 0; + // figure out a maximum on the amount of space we can need + int count = 0; + for (tab *p = initial_list; p; p = p->next) + ++count; + for (p = repeated_list; p; p = p->next) + ++count; + // (10 for digits + 1 for u + 1 for 'C' or 'R') + 2 for ' &' + 1 for '\0' + int need = count*12 + 3; + if (buf == 0 || need > buf_size) { + if (buf) + a_delete buf; + buf_size = need; + buf = new char[buf_size]; + } + char *ptr = buf; + for (p = initial_list; p; p = p->next) { + strcpy(ptr, itoa(p->pos.to_units())); + ptr = strchr(ptr, '\0'); + *ptr++ = 'u'; + *ptr = '\0'; + switch (p->type) { + case TAB_LEFT: + break; + case TAB_RIGHT: + *ptr++ = 'R'; + break; + case TAB_CENTER: + *ptr++ = 'C'; + break; + case TAB_NONE: + default: + assert(0); + } + } + if (repeated_list) + *ptr++ = TAB_REPEAT_CHAR; + for (p = repeated_list; p; p = p->next) { + strcpy(ptr, itoa(p->pos.to_units())); + ptr = strchr(ptr, '\0'); + *ptr++ = 'u'; + *ptr = '\0'; + switch (p->type) { + case TAB_LEFT: + break; + case TAB_RIGHT: + *ptr++ = 'R'; + break; + case TAB_CENTER: + *ptr++ = 'C'; + break; + case TAB_NONE: + default: + assert(0); + } + } + *ptr++ = '\0'; + return buf; +} + +tab_stops::tab_stops() : initial_list(0), repeated_list(0) +{ +} + +tab_stops::tab_stops(const tab_stops &ts) + : initial_list(0), repeated_list(0) +{ + tab **p = &initial_list; + tab *t = ts.initial_list; + while (t) { + *p = new tab(t->pos, t->type); + t = t->next; + p = &(*p)->next; + } + p = &repeated_list; + t = ts.repeated_list; + while (t) { + *p = new tab(t->pos, t->type); + t = t->next; + p = &(*p)->next; + } +} + +void tab_stops::clear() +{ + while (initial_list) { + tab *tem = initial_list; + initial_list = initial_list->next; + delete tem; + } + while (repeated_list) { + tab *tem = repeated_list; + repeated_list = repeated_list->next; + delete tem; + } +} + +void tab_stops::add_tab(hunits pos, tab_type type, int repeated) +{ + for (tab **p = repeated ? &repeated_list : &initial_list; *p; p = &(*p)->next) + ; + *p = new tab(pos, type); +} + + +void tab_stops::operator=(const tab_stops &ts) +{ + clear(); + tab **p = &initial_list; + tab *t = ts.initial_list; + while (t) { + *p = new tab(t->pos, t->type); + t = t->next; + p = &(*p)->next; + } + p = &repeated_list; + t = ts.repeated_list; + while (t) { + *p = new tab(t->pos, t->type); + t = t->next; + p = &(*p)->next; + } +} + +void set_tabs() +{ + hunits pos; + hunits prev_pos = 0; + int first = 1; + int repeated = 0; + tab_stops tabs; + while (has_arg()) { + if (tok.ch() == TAB_REPEAT_CHAR) { + tok.next(); + repeated = 1; + prev_pos = 0; + } + if (!get_hunits(&pos, 'm', prev_pos)) + break; + tab_type type = TAB_LEFT; + if (tok.ch() == 'C') { + tok.next(); + type = TAB_CENTER; + } + else if (tok.ch() == 'R') { + tok.next(); + type = TAB_RIGHT; + } + else if (tok.ch() == 'L') { + tok.next(); + } + if (pos <= prev_pos && !first) + warning(WARN_RANGE, + "positions of tab stops must be strictly increasing"); + else { + tabs.add_tab(pos, type, repeated); + prev_pos = pos; + first = 0; + } + } + curenv->tabs = tabs; + skip_line(); +} + +const char *environment::get_tabs() +{ + return tabs.to_string(); +} + +#if 0 +tab_stops saved_tabs; + +void tabs_save() +{ + saved_tabs = curenv->tabs; + skip_line(); +} + +void tabs_restore() +{ + curenv->tabs = saved_tabs; + skip_line(); +} +#endif + +tab_type environment::distance_to_next_tab(hunits *distance) +{ + return curenv->tabs.distance_to_next_tab(get_input_line_position(), distance); +} + +void field_characters() +{ + field_delimiter_char = get_optional_char(); + if (field_delimiter_char) + padding_indicator_char = get_optional_char(); + else + padding_indicator_char = 0; + skip_line(); +} + +void environment::wrap_up_tab() +{ + if (!current_tab) + return; + if (line == 0) + start_line(); + hunits tab_amount; + switch (current_tab) { + case TAB_RIGHT: + tab_amount = tab_distance - tab_width; + line = make_tab_node(tab_amount, line); + break; + case TAB_CENTER: + tab_amount = tab_distance - tab_width/2; + line = make_tab_node(tab_amount, line); + break; + case TAB_NONE: + case TAB_LEFT: + default: + assert(0); + } + width_total += tab_amount; + width_total += tab_width; + if (current_field) { + if (tab_precedes_field) { + pre_field_width += tab_amount; + tab_precedes_field = 0; + } + field_distance -= tab_amount; + field_spaces += tab_field_spaces; + } + if (tab_contents != 0) { + for (node *tem = tab_contents; tem->next != 0; tem = tem->next) + ; + tem->next = line; + line = tab_contents; + } + tab_field_spaces = 0; + tab_contents = 0; + tab_width = H0; + tab_distance = H0; + current_tab = TAB_NONE; +} + +node *environment::make_tab_node(hunits d, node *next) +{ + if (leader_node != 0 && d < 0) { + error("motion generated by leader cannot be negative"); + delete leader_node; + leader_node = 0; + } + if (!leader_node) + return new hmotion_node(d, next); + node *n = new hline_node(d, leader_node, next); + leader_node = 0; + return n; +} + +void environment::handle_tab(int is_leader) +{ + hunits d; + if (current_tab) + wrap_up_tab(); + charinfo *ci = is_leader ? leader_char : tab_char; + delete leader_node; + leader_node = ci ? make_char_node(ci) : 0; + tab_type t = distance_to_next_tab(&d); + switch (t) { + case TAB_NONE: + return; + case TAB_LEFT: + add_node(make_tab_node(d)); + return; + case TAB_RIGHT: + case TAB_CENTER: + tab_width = 0; + tab_distance = d; + tab_contents = 0; + current_tab = t; + tab_field_spaces = 0; + return; + default: + assert(0); + } +} + +void environment::start_field() +{ + assert(!current_field); + hunits d; + if (distance_to_next_tab(&d) != TAB_NONE) { + pre_field_width = get_text_length(); + field_distance = d; + current_field = 1; + field_spaces = 0; + tab_field_spaces = 0; + for (node *p = line; p; p = p->next) + if (p->nspaces()) { + p->freeze_space(); + space_total--; + } + tab_precedes_field = current_tab != TAB_NONE; + } + else + error("zero field width"); +} + +void environment::wrap_up_field() +{ + if (!current_tab && field_spaces == 0) + add_padding(); + hunits padding = field_distance - (get_text_length() - pre_field_width); + if (current_tab && tab_field_spaces != 0) { + hunits tab_padding = scale(padding, + tab_field_spaces, + field_spaces + tab_field_spaces); + padding -= tab_padding; + distribute_space(tab_contents, tab_field_spaces, tab_padding, 1); + tab_field_spaces = 0; + tab_width += tab_padding; + } + if (field_spaces != 0) { + distribute_space(line, field_spaces, padding, 1); + width_total += padding; + if (current_tab) { + // the start of the tab has been moved to the right by padding, so + tab_distance -= padding; + if (tab_distance <= H0) { + // use the next tab stop instead + current_tab = tabs.distance_to_next_tab(get_input_line_position() + - tab_width, + &tab_distance); + if (current_tab == TAB_NONE || current_tab == TAB_LEFT) { + width_total += tab_width; + if (current_tab == TAB_LEFT) { + line = make_tab_node(tab_distance, line); + width_total += tab_distance; + current_tab = TAB_NONE; + } + if (tab_contents != 0) { + for (node *tem = tab_contents; tem->next != 0; tem = tem->next) + ; + tem->next = line; + line = tab_contents; + tab_contents = 0; + } + tab_width = H0; + tab_distance = H0; + } + } + } + } + current_field = 0; +} + +void environment::add_padding() +{ + if (current_tab) { + tab_contents = new space_node(H0, tab_contents); + tab_field_spaces++; + } + else { + if (line == 0) + start_line(); + line = new space_node(H0, line); + field_spaces++; + } +} + +typedef int (environment::*INT_FUNCP)(); +typedef vunits (environment::*VUNITS_FUNCP)(); +typedef hunits (environment::*HUNITS_FUNCP)(); +typedef const char *(environment::*STRING_FUNCP)(); + +class int_env_reg : public reg { + INT_FUNCP func; + public: + int_env_reg(INT_FUNCP); + const char *get_string(); + int get_value(units *val); +}; + +class vunits_env_reg : public reg { + VUNITS_FUNCP func; + public: + vunits_env_reg(VUNITS_FUNCP f); + const char *get_string(); + int get_value(units *val); +}; + + +class hunits_env_reg : public reg { + HUNITS_FUNCP func; + public: + hunits_env_reg(HUNITS_FUNCP f); + const char *get_string(); + int get_value(units *val); +}; + +class string_env_reg : public reg { + STRING_FUNCP func; +public: + string_env_reg(STRING_FUNCP); + const char *get_string(); +}; + +int_env_reg::int_env_reg(INT_FUNCP f) : func(f) +{ +} + +int int_env_reg::get_value(units *val) +{ + *val = (curenv->*func)(); + return 1; +} + +const char *int_env_reg::get_string() +{ + return itoa((curenv->*func)()); +} + +vunits_env_reg::vunits_env_reg(VUNITS_FUNCP f) : func(f) +{ +} + +int vunits_env_reg::get_value(units *val) +{ + *val = (curenv->*func)().to_units(); + return 1; +} + +const char *vunits_env_reg::get_string() +{ + return itoa((curenv->*func)().to_units()); +} + +hunits_env_reg::hunits_env_reg(HUNITS_FUNCP f) : func(f) +{ +} + +int hunits_env_reg::get_value(units *val) +{ + *val = (curenv->*func)().to_units(); + return 1; +} + +const char *hunits_env_reg::get_string() +{ + return itoa((curenv->*func)().to_units()); +} + +string_env_reg::string_env_reg(STRING_FUNCP f) : func(f) +{ +} + +const char *string_env_reg::get_string() +{ + return (curenv->*func)(); +} + +class horizontal_place_reg : public general_reg { +public: + horizontal_place_reg(); + int get_value(units *); + void set_value(units); +}; + +horizontal_place_reg::horizontal_place_reg() +{ +} + +int horizontal_place_reg::get_value(units *res) +{ + *res = curenv->get_input_line_position().to_units(); + return 1; +} + +void horizontal_place_reg::set_value(units n) +{ + curenv->set_input_line_position(hunits(n)); +} + +const char *environment::get_font_family_string() +{ + return family->nm.contents(); +} + +const char *environment::get_name_string() +{ + return name.contents(); +} + +// Convert a quantity in scaled points to ascii decimal fraction. + +const char *sptoa(int sp) +{ + assert(sp > 0); + assert(sizescale > 0); + if (sizescale == 1) + return itoa(sp); + if (sp % sizescale == 0) + return itoa(sp/sizescale); + // See if 1/sizescale is exactly representable as a decimal fraction, + // ie its only prime factors are 2 and 5. + int n = sizescale; + int power2 = 0; + while ((n & 1) == 0) { + n >>= 1; + power2++; + } + int power5 = 0; + while ((n % 5) == 0) { + n /= 5; + power5++; + } + if (n == 1) { + int decimal_point = power5 > power2 ? power5 : power2; + if (decimal_point <= 10) { + int factor = 1; + int t; + for (t = decimal_point - power2; --t >= 0;) + factor *= 2; + for (t = decimal_point - power5; --t >= 0;) + factor *= 5; + if (factor == 1 || sp <= INT_MAX/factor) + return iftoa(sp*factor, decimal_point); + } + } + double s = double(sp)/double(sizescale); + double factor = 10.0; + double val = s; + int decimal_point = 0; + do { + double v = ceil(s*factor); + if (v > INT_MAX) + break; + val = v; + factor *= 10.0; + } while (++decimal_point < 10); + return iftoa(int(val), decimal_point); +} + +const char *environment::get_point_size_string() +{ + return sptoa(curenv->get_point_size()); +} + +const char *environment::get_requested_point_size_string() +{ + return sptoa(curenv->get_requested_point_size()); +} + +#define init_int_env_reg(name, func) \ + number_reg_dictionary.define(name, new int_env_reg(&environment::func)) + +#define init_vunits_env_reg(name, func) \ + number_reg_dictionary.define(name, new vunits_env_reg(&environment::func)) + +#define init_hunits_env_reg(name, func) \ + number_reg_dictionary.define(name, new hunits_env_reg(&environment::func)) + +#define init_string_env_reg(name, func) \ + number_reg_dictionary.define(name, new string_env_reg(&environment::func)) + +void init_env_requests() +{ + init_request("it", input_trap); + init_request("ad", adjust); + init_request("na", no_adjust); + init_request("ev", environment_switch); + init_request("lt", title_length); + init_request("ps", point_size); + init_request("ft", font_change); + init_request("fam", family_change); + init_request("ss", space_size); + init_request("fi", fill); + init_request("nf", no_fill); + init_request("ce", center); + init_request("rj", right_justify); + init_request("vs", vertical_spacing); + init_request("ls", line_spacing); + init_request("ll", line_length); + init_request("in", indent); + init_request("ti", temporary_indent); + init_request("ul", underline); + init_request("cu", underline); + init_request("cc", control_char); + init_request("c2", no_break_control_char); + init_request("br", break_request); + init_request("tl", title); + init_request("ta", set_tabs); + init_request("fc", field_characters); + init_request("mc", margin_character); + init_request("nn", no_number); + init_request("nm", number_lines); + init_request("tc", tab_character); + init_request("lc", leader_character); + init_request("hy", hyphenate_request); + init_request("hc", hyphen_char); + init_request("nh", no_hyphenate); + init_request("hlm", hyphen_line_max_request); +#ifdef WIDOW_CONTROL + init_request("wdc", widow_control_request); +#endif /* WIDOW_CONTROL */ +#if 0 + init_request("tas", tabs_save); + init_request("tar", tabs_restore); +#endif + init_request("hys", hyphenation_space_request); + init_request("hym", hyphenation_margin_request); + init_int_env_reg(".f", get_font); + init_int_env_reg(".b", get_bold); + init_hunits_env_reg(".i", get_indent); + init_hunits_env_reg(".in", get_saved_indent); + init_int_env_reg(".j", get_adjust_mode); + init_hunits_env_reg(".k", get_text_length); + init_hunits_env_reg(".l", get_line_length); + init_hunits_env_reg(".ll", get_saved_line_length); + init_int_env_reg(".L", get_line_spacing); + init_hunits_env_reg(".n", get_prev_text_length); + init_string_env_reg(".s", get_point_size_string); + init_string_env_reg(".sr", get_requested_point_size_string); + init_int_env_reg(".ps", get_point_size); + init_int_env_reg(".psr", get_requested_point_size); + init_int_env_reg(".u", get_fill); + init_vunits_env_reg(".v", get_vertical_spacing); + init_hunits_env_reg(".w", get_prev_char_width); + init_int_env_reg(".ss", get_space_size); + init_int_env_reg(".sss", get_sentence_space_size); + init_string_env_reg(".fam", get_font_family_string); + init_string_env_reg(".ev", get_name_string); + init_int_env_reg(".hy", get_hyphenation_flags); + init_int_env_reg(".hlm", get_hyphen_line_max); + init_int_env_reg(".hlc", get_hyphen_line_count); + init_hunits_env_reg(".lt", get_title_length); + init_string_env_reg(".tabs", get_tabs); + init_hunits_env_reg(".csk", get_prev_char_skew); + init_vunits_env_reg(".cht", get_prev_char_height); + init_vunits_env_reg(".cdp", get_prev_char_depth); + init_int_env_reg(".ce", get_center_lines); + init_int_env_reg(".rj", get_right_justify_lines); + init_hunits_env_reg(".hys", get_hyphenation_space); + init_hunits_env_reg(".hym", get_hyphenation_margin); + number_reg_dictionary.define("ln", new variable_reg(&next_line_number)); + number_reg_dictionary.define("ct", new variable_reg(&ct_reg_contents)); + number_reg_dictionary.define("sb", new variable_reg(&sb_reg_contents)); + number_reg_dictionary.define("st", new variable_reg(&st_reg_contents)); + number_reg_dictionary.define("rsb", new variable_reg(&rsb_reg_contents)); + number_reg_dictionary.define("rst", new variable_reg(&rst_reg_contents)); + number_reg_dictionary.define("ssc", new variable_reg(&ssc_reg_contents)); + number_reg_dictionary.define("skw", new variable_reg(&skw_reg_contents)); + number_reg_dictionary.define("hp", new horizontal_place_reg); +} + +// Hyphenation - TeX's hyphenation algorithm with a less fancy implementation. + +struct trie_node; + +class trie { + trie_node *tp; + virtual void do_match(int len, void *val) = 0; + virtual void do_delete(void *) = 0; + void delete_trie_node(trie_node *); +public: + trie() : tp(0) {} + virtual ~trie(); // virtual to shut up g++ + void insert(const char *, int, void *); + // find calls do_match for each match it finds + void find(const char *pat, int patlen); + void clear(); +}; + +class hyphen_trie : private trie { + int *h; + void do_match(int i, void *v); + void do_delete(void *v); + void insert_pattern(const char *pat, int patlen, int *num); +public: + hyphen_trie() {} + ~hyphen_trie() {} + void hyphenate(const char *word, int len, int *hyphens); + void read_patterns_file(const char *name); +}; + + +struct hyphenation_language { + symbol name; + dictionary exceptions; + hyphen_trie patterns; + hyphenation_language(symbol nm) : name(nm), exceptions(501) {} + ~hyphenation_language() { } +}; + +dictionary language_dictionary(5); +hyphenation_language *current_language = 0; + +static void set_hyphenation_language() +{ + symbol nm = get_name(1); + if (!nm.is_null()) { + current_language = (hyphenation_language *)language_dictionary.lookup(nm); + if (!current_language) { + current_language = new hyphenation_language(nm); + (void)language_dictionary.lookup(nm, (void *)current_language); + } + } + skip_line(); +} + +const int WORD_MAX = 1024; + +static void hyphen_word() +{ + if (!current_language) { + error("no current hyphenation language"); + skip_line(); + return; + } + char buf[WORD_MAX + 1]; + unsigned char pos[WORD_MAX + 2]; + for (;;) { + tok.skip(); + if (tok.newline() || tok.eof()) + break; + int i = 0; + int npos = 0; + while (i < WORD_MAX && !tok.space() && !tok.newline() && !tok.eof()) { + charinfo *ci = tok.get_char(1); + if (ci == 0) { + skip_line(); + return; + } + tok.next(); + if (ci->get_ascii_code() == '-') { + if (i > 0 && (npos == 0 || pos[npos - 1] != i)) + pos[npos++] = i; + } + else { + int c = ci->get_hyphenation_code(); + if (c == 0) + break; + buf[i++] = c; + } + } + if (i > 0) { + pos[npos] = 0; + buf[i] = 0; + unsigned char *tem = new unsigned char[npos + 1]; + memcpy(tem, pos, npos+1); + tem = (unsigned char *)current_language->exceptions.lookup(symbol(buf), + tem); + if (tem) + a_delete tem; + } + } + skip_line(); +} + +struct trie_node { + char c; + trie_node *down; + trie_node *right; + void *val; + trie_node(char, trie_node *); +}; + +trie_node::trie_node(char ch, trie_node *p) +: c(ch), right(p), down(0), val(0) +{ +} + +trie::~trie() +{ + clear(); +} + +void trie::clear() +{ + delete_trie_node(tp); + tp = 0; +} + + +void trie::delete_trie_node(trie_node *p) +{ + if (p) { + delete_trie_node(p->down); + delete_trie_node(p->right); + if (p->val) + do_delete(p->val); + delete p; + } +} + +void trie::insert(const char *pat, int patlen, void *val) +{ + trie_node **p = &tp; + assert(patlen > 0 && pat != 0); + for (;;) { + while (*p != 0 && (*p)->c < pat[0]) + p = &((*p)->right); + if (*p == 0 || (*p)->c != pat[0]) + *p = new trie_node(pat[0], *p); + if (--patlen == 0) { + (*p)->val = val; + break; + } + ++pat; + p = &((*p)->down); + } +} + +void trie::find(const char *pat, int patlen) +{ + trie_node *p = tp; + for (int i = 0; p != 0 && i < patlen; i++) { + while (p != 0 && p->c < pat[i]) + p = p->right; + if (p != 0 && p->c == pat[i]) { + if (p->val != 0) + do_match(i+1, p->val); + p = p->down; + } + else + break; + } +} + +struct operation { + operation *next; + short distance; + short num; + operation(int, int, operation *); +}; + +operation::operation(int i, int j, operation *op) +: num(i), distance(j), next(op) +{ +} + +void hyphen_trie::insert_pattern(const char *pat, int patlen, int *num) +{ + operation *op = 0; + for (int i = 0; i < patlen+1; i++) + if (num[i] != 0) + op = new operation(num[i], patlen - i, op); + insert(pat, patlen, op); +} + +void hyphen_trie::hyphenate(const char *word, int len, int *hyphens) +{ + for (int j = 0; j < len+1; j++) + hyphens[j] = 0; + for (j = 0; j < len - 1; j++) { + h = hyphens + j; + find(word + j, len - j); + } +} + +inline int max(int m, int n) +{ + return m > n ? m : n; +} + +void hyphen_trie::do_match(int i, void *v) +{ + operation *op = (operation *)v; + while (op != 0) { + h[i - op->distance] = max(h[i - op->distance], op->num); + op = op->next; + } +} + +void hyphen_trie::do_delete(void *v) +{ + operation *op = (operation *)v; + while (op) { + operation *tem = op; + op = tem->next; + delete tem; + } +} + +void hyphen_trie::read_patterns_file(const char *name) +{ + clear(); + char buf[WORD_MAX]; + int num[WORD_MAX+1]; + errno = 0; + char *path = 0; + FILE *fp = macro_path.open_file(name, &path); + if (fp == 0) { + error("can't find hyphenation patterns file `%1'", name); + return; + } + int c = getc(fp); + for (;;) { + for (;;) { + if (c == '%') { + do { + c = getc(fp); + } while (c != EOF && c != '\n'); + } + if (c == EOF || !csspace(c)) + break; + c = getc(fp); + } + if (c == EOF) + break; + int i = 0; + num[0] = 0; + do { + if (csdigit(c)) + num[i] = c - '0'; + else { + buf[i++] = c; + num[i] = 0; + } + c = getc(fp); + } while (i < WORD_MAX && c != EOF && !csspace(c) && c != '%'); + insert_pattern(buf, i, num); + } + fclose(fp); + a_delete path; + return; +} + +void hyphenate(hyphen_list *h, unsigned flags) +{ + if (!current_language) + return; + while (h && h->hyphenation_code == 0) + h = h->next; + int len = 0; + char hbuf[WORD_MAX+2]; + char *buf = hbuf + 1; + for (hyphen_list *tem = h; tem && len < WORD_MAX; tem = tem->next) { + if (tem->hyphenation_code != 0) + buf[len++] = tem->hyphenation_code; + else + break; + } + if (len > 2) { + buf[len] = 0; + unsigned char *pos = (unsigned char *)current_language->exceptions.lookup(buf); + if (pos != 0) { + int j = 0; + int i = 1; + for (tem = h; tem != 0; tem = tem->next, i++) + if (pos[j] == i) { + tem->hyphen = 1; + j++; + } + } + else { + hbuf[0] = hbuf[len+1] = '.'; + int num[WORD_MAX+3]; + current_language->patterns.hyphenate(hbuf, len+2, num); + int i; + num[2] = 0; + if (flags & 8) + num[3] = 0; + if (flags & 4) + --len; + for (i = 2, tem = h; i < len && tem; tem = tem->next, i++) + if (num[i] & 1) + tem->hyphen = 1; + } + } +} + +static void hyphenation_patterns_file() +{ + symbol name = get_long_name(1); + if (!name.is_null()) { + if (!current_language) + error("no current hyphenation language"); + else + current_language->patterns.read_patterns_file(name.contents()); + } + skip_line(); +} + +class hyphenation_language_reg : public reg { +public: + const char *get_string(); +}; + +const char *hyphenation_language_reg::get_string() +{ + return current_language ? current_language->name.contents() : ""; +} + +void init_hyphen_requests() +{ + init_request("hw", hyphen_word); + init_request("hla", set_hyphenation_language); + init_request("hpf", hyphenation_patterns_file); + number_reg_dictionary.define(".hla", new hyphenation_language_reg); +} diff --git a/gnu/usr.bin/groff/troff/env.h b/gnu/usr.bin/groff/troff/env.h new file mode 100644 index 0000000000..14441e1f3a --- /dev/null +++ b/gnu/usr.bin/groff/troff/env.h @@ -0,0 +1,327 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct size_range { + int min; + int max; +}; + +class font_size { + static size_range *size_table; + static int nranges; + int p; +public: + font_size(); + font_size(int points); + int to_points(); + int to_scaled_points(); + int to_units(); + int operator==(font_size); + int operator!=(font_size); + static void init_size_table(int *sizes); +}; + +inline font_size::font_size() : p(0) +{ +} + +inline int font_size::operator==(font_size fs) +{ + return p == fs.p; +} + +inline int font_size::operator!=(font_size fs) +{ + return p != fs.p; +} + +inline int font_size::to_scaled_points() +{ + return p; +} + +inline int font_size::to_points() +{ + return p/sizescale; +} + +struct environment; + +hunits env_digit_width(environment *); +hunits env_space_width(environment *); +hunits env_sentence_space_width(environment *); +hunits env_narrow_space_width(environment *); +hunits env_half_narrow_space_width(environment *); + +struct tab; + +enum tab_type { TAB_NONE, TAB_LEFT, TAB_CENTER, TAB_RIGHT }; + +class tab_stops { + tab *initial_list; + tab *repeated_list; +public: + tab_stops(); + tab_stops(hunits distance, tab_type type); + tab_stops(const tab_stops &); + ~tab_stops(); + void operator=(const tab_stops &); + tab_type distance_to_next_tab(hunits pos, hunits *distance); + void clear(); + void add_tab(hunits pos, tab_type type, int repeated); + const char *to_string(); +}; + +const unsigned MARGIN_CHARACTER_ON = 1; +const unsigned MARGIN_CHARACTER_NEXT = 2; + +struct charinfo; +struct node; +struct breakpoint; +struct font_family; +struct pending_output_line; + +class environment { + int dummy; // dummy environment used for \w + hunits prev_line_length; + hunits line_length; + hunits prev_title_length; + hunits title_length; + font_size prev_size; + font_size size; + int requested_size; + int prev_requested_size; + int char_height; + int char_slant; + int prev_fontno; + int fontno; + font_family *prev_family; + font_family *family; + int space_size; // in 36ths of an em + int sentence_space_size; // same but for spaces at the end of sentences + int adjust_mode; + int fill; + int interrupted; + int prev_line_interrupted; + int center_lines; + int right_justify_lines; + vunits prev_vertical_spacing; + vunits vertical_spacing; + int prev_line_spacing; + int line_spacing; + hunits prev_indent; + hunits indent; + hunits temporary_indent; + int have_temporary_indent; + hunits saved_indent; + hunits target_text_length; + int pre_underline_fontno; + int underline_lines; + symbol input_trap; + int input_trap_count; + node *line; // in reverse order + hunits prev_text_length; + hunits width_total; + int space_total; + hunits input_line_start; + tab_stops tabs; + node *tab_contents; + hunits tab_width; + hunits tab_distance; + tab_type current_tab; + node *leader_node; + charinfo *tab_char; + charinfo *leader_char; + int current_field; // is there a current field? + hunits field_distance; + hunits pre_field_width; + int field_spaces; + int tab_field_spaces; + int tab_precedes_field; + int discarding; + int spread_flag; // set by \p + unsigned margin_character_flags; + node *margin_character_node; + hunits margin_character_distance; + node *numbering_nodes; + hunits line_number_digit_width; + int number_text_separation; // in digit spaces + int line_number_indent; // in digit spaces + int line_number_multiple; + int no_number_count; + unsigned hyphenation_flags; + int hyphen_line_count; + int hyphen_line_max; + hunits hyphenation_space; + hunits hyphenation_margin; + int composite; // used for construction of composite char? + pending_output_line *pending_lines; +#ifdef WIDOW_CONTROL + int widow_control; +#endif /* WIDOW_CONTROL */ + + tab_type distance_to_next_tab(hunits *); + void start_line(); + void output_line(node *, hunits); + void output(node *nd, int retain_size, vunits vs, int ls, hunits width); + void output_title(node *nd, int retain_size, vunits vs, int ls, + hunits width); +#ifdef WIDOW_CONTROL + void mark_last_line(); +#endif /* WIDOW_CONTROL */ + void possibly_break_line(int forced = 0); + breakpoint *choose_breakpoint(); + void hyphenate_line(); + void start_field(); + void wrap_up_field(); + void add_padding(); + node *make_tab_node(hunits d, node *next = 0); + node *get_prev_char(); +public: + const symbol name; + unsigned char control_char; + unsigned char no_break_control_char; + charinfo *hyphen_indicator_char; + + environment(symbol); + environment(const environment *); // for temporary environment + ~environment(); + int is_dummy() { return dummy; } + int is_empty(); + int is_composite() { return composite; } + void set_composite() { composite = 1; } + vunits get_vertical_spacing(); // .v + int get_line_spacing(); // .L + int get_point_size() { return size.to_scaled_points(); } + font_size get_font_size() { return size; } + int get_size() { return size.to_units(); } + int get_requested_point_size() { return requested_size; } + int get_char_height() { return char_height; } + int get_char_slant() { return char_slant; } + hunits get_digit_width(); + int get_font() { return fontno; }; // .f + font_family *get_family() { return family; } + int get_bold(); // .b + int get_adjust_mode(); // .j + int get_fill(); // .u + hunits get_indent(); // .i + hunits get_temporary_indent(); + hunits get_line_length(); // .l + hunits get_saved_line_length(); // .ll + hunits get_saved_indent(); // .in + hunits get_title_length(); + hunits get_prev_char_width(); // .w + hunits get_prev_char_skew(); + vunits get_prev_char_height(); + vunits get_prev_char_depth(); + hunits get_text_length(); // .k + hunits get_prev_text_length(); // .n + hunits get_space_width() { return env_space_width(this); } + int get_space_size() { return space_size; } // in ems/36 + int get_sentence_space_size() { return sentence_space_size; } + hunits get_narrow_space_width() { return env_narrow_space_width(this); } + hunits get_half_narrow_space_width() + { return env_half_narrow_space_width(this); } + hunits get_input_line_position(); + const char *get_tabs(); + int get_hyphenation_flags(); + int get_hyphen_line_max(); + int get_hyphen_line_count(); + hunits get_hyphenation_space(); + hunits get_hyphenation_margin(); + int get_center_lines(); + int get_right_justify_lines(); + int get_prev_line_interrupted() { return prev_line_interrupted; } + node *make_char_node(charinfo *); + node *extract_output_line(); + void width_registers(); + void wrap_up_tab(); + void set_font(int); + void set_font(symbol); + void set_family(symbol); + void set_size(int); + void set_char_height(int); + void set_char_slant(int); + void set_input_line_position(hunits); // used by \n(hp + void interrupt(); + void spread() { spread_flag = 1; } + void do_break(); // .br + void final_break(); + void newline(); + void handle_tab(int is_leader = 0); // do a tab or leader + void add_node(node *); + void add_char(charinfo *); + void add_hyphen_indicator(); + void add_italic_correction(); + void space(); + void space_newline(); + const char *get_font_family_string(); + const char *get_name_string(); + const char *get_point_size_string(); + const char *get_requested_point_size_string(); + void output_pending_lines(); + + friend void title_length(); + friend void space_size(); + friend void fill(); + friend void no_fill(); + friend void adjust(); + friend void no_adjust(); + friend void center(); + friend void right_justify(); + friend void vertical_spacing(); + friend void line_spacing(); + friend void line_length(); + friend void indent(); + friend void temporary_indent(); + friend void underline(); + friend void input_trap(); + friend void set_tabs(); + friend void margin_character(); + friend void no_number(); + friend void number_lines(); + friend void leader_character(); + friend void tab_character(); + friend void hyphenate_request(); + friend void no_hyphenate(); + friend void hyphen_line_max_request(); + friend void hyphenation_space_request(); + friend void hyphenation_margin_request(); + friend void line_width(); +#if 0 + friend void tabs_save(); + friend void tabs_restore(); +#endif + friend void title(); +#ifdef WIDOW_CONTROL + friend void widow_control_request(); +#endif /* WIDOW_CONTROL */ +}; + +extern environment *curenv; +extern void pop_env(); +extern void push_env(int); + +void init_environments(); +void read_hyphen_file(const char *name); + +extern int break_flag; +extern symbol default_family; +extern int translate_space_to_dummy; diff --git a/gnu/usr.bin/groff/troff/hvunits.h b/gnu/usr.bin/groff/troff/hvunits.h new file mode 100644 index 0000000000..4a1c5fd6d0 --- /dev/null +++ b/gnu/usr.bin/groff/troff/hvunits.h @@ -0,0 +1,340 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +class vunits { + int n; +public: + vunits(); + vunits(units); + units to_units(); + int is_zero(); + vunits& operator+=(const vunits&); + vunits& operator-=(const vunits&); + friend inline vunits scale(vunits n, units x, units y); // scale n by x/y + friend inline vunits scale(vunits n, vunits x, vunits y); + friend inline vunits operator +(const vunits&, const vunits&); + friend inline vunits operator -(const vunits&, const vunits&); + friend inline vunits operator -(const vunits&); + friend inline int operator /(const vunits&, const vunits&); + friend inline vunits operator /(const vunits&, int); + friend inline vunits operator *(const vunits&, int); + friend inline vunits operator *(int, const vunits&); + friend inline int operator <(const vunits&, const vunits&); + friend inline int operator >(const vunits&, const vunits&); + friend inline int operator <=(const vunits&, const vunits&); + friend inline int operator >=(const vunits&, const vunits&); + friend inline int operator ==(const vunits&, const vunits&); + friend inline int operator !=(const vunits&, const vunits&); +}; + +extern vunits V0; + + +class hunits { + int n; +public: + hunits(); + hunits(units); + units to_units(); + int is_zero(); + hunits& operator+=(const hunits&); + hunits& operator-=(const hunits&); + friend inline hunits scale(hunits n, units x, units y); // scale n by x/y + friend inline hunits scale(hunits n, double x); + friend inline hunits operator +(const hunits&, const hunits&); + friend inline hunits operator -(const hunits&, const hunits&); + friend inline hunits operator -(const hunits&); + friend inline int operator /(const hunits&, const hunits&); + friend inline hunits operator /(const hunits&, int); + friend inline hunits operator *(const hunits&, int); + friend inline hunits operator *(int, const hunits&); + friend inline int operator <(const hunits&, const hunits&); + friend inline int operator >(const hunits&, const hunits&); + friend inline int operator <=(const hunits&, const hunits&); + friend inline int operator >=(const hunits&, const hunits&); + friend inline int operator ==(const hunits&, const hunits&); + friend inline int operator !=(const hunits&, const hunits&); +}; + +extern hunits H0; + +extern int get_vunits(vunits *, unsigned char si); +extern int get_hunits(hunits *, unsigned char si); +extern int get_vunits(vunits *, unsigned char si, vunits prev_value); +extern int get_hunits(hunits *, unsigned char si, hunits prev_value); + +inline vunits:: vunits() : n(0) +{ +} + +inline units vunits::to_units() +{ + return n*vresolution; +} + +inline int vunits::is_zero() +{ + return n == 0; +} + +inline vunits operator +(const vunits & x, const vunits & y) +{ + vunits r; + r = x; + r.n += y.n; + return r; +} + +inline vunits operator -(const vunits & x, const vunits & y) +{ + vunits r; + r = x; + r.n -= y.n; + return r; +} + +inline vunits operator -(const vunits & x) +{ + vunits r; + r.n = -x.n; + return r; +} + +inline int operator /(const vunits & x, const vunits & y) +{ + return x.n/y.n; +} + +inline vunits operator /(const vunits & x, int n) +{ + vunits r; + r = x; + r.n /= n; + return r; +} + +inline vunits operator *(const vunits & x, int n) +{ + vunits r; + r = x; + r.n *= n; + return r; +} + +inline vunits operator *(int n, const vunits & x) +{ + vunits r; + r = x; + r.n *= n; + return r; +} + +inline int operator <(const vunits & x, const vunits & y) +{ + return x.n < y.n; +} + +inline int operator >(const vunits & x, const vunits & y) +{ + return x.n > y.n; +} + +inline int operator <=(const vunits & x, const vunits & y) +{ + return x.n <= y.n; +} + +inline int operator >=(const vunits & x, const vunits & y) +{ + return x.n >= y.n; +} + +inline int operator ==(const vunits & x, const vunits & y) +{ + return x.n == y.n; +} + +inline int operator !=(const vunits & x, const vunits & y) +{ + return x.n != y.n; +} + + +inline vunits& vunits::operator+=(const vunits & x) +{ + n += x.n; + return *this; +} + +inline vunits& vunits::operator-=(const vunits & x) +{ + n -= x.n; + return *this; +} + +inline hunits:: hunits() : n(0) +{ +} + +inline units hunits::to_units() +{ + return n*hresolution; +} + +inline int hunits::is_zero() +{ + return n == 0; +} + +inline hunits operator +(const hunits & x, const hunits & y) +{ + hunits r; + r = x; + r.n += y.n; + return r; +} + +inline hunits operator -(const hunits & x, const hunits & y) +{ + hunits r; + r = x; + r.n -= y.n; + return r; +} + +inline hunits operator -(const hunits & x) +{ + hunits r; + r = x; + r.n = -x.n; + return r; +} + +inline int operator /(const hunits & x, const hunits & y) +{ + return x.n/y.n; +} + +inline hunits operator /(const hunits & x, int n) +{ + hunits r; + r = x; + r.n /= n; + return r; +} + +inline hunits operator *(const hunits & x, int n) +{ + hunits r; + r = x; + r.n *= n; + return r; +} + +inline hunits operator *(int n, const hunits & x) +{ + hunits r; + r = x; + r.n *= n; + return r; +} + +inline int operator <(const hunits & x, const hunits & y) +{ + return x.n < y.n; +} + +inline int operator >(const hunits & x, const hunits & y) +{ + return x.n > y.n; +} + +inline int operator <=(const hunits & x, const hunits & y) +{ + return x.n <= y.n; +} + +inline int operator >=(const hunits & x, const hunits & y) +{ + return x.n >= y.n; +} + +inline int operator ==(const hunits & x, const hunits & y) +{ + return x.n == y.n; +} + +inline int operator !=(const hunits & x, const hunits & y) +{ + return x.n != y.n; +} + + +inline hunits& hunits::operator+=(const hunits & x) +{ + n += x.n; + return *this; +} + +inline hunits& hunits::operator-=(const hunits & x) +{ + n -= x.n; + return *this; +} + +inline hunits scale(hunits n, units x, units y) +{ + hunits r; + r.n = scale(n.n, x, y); + return r; +} + +inline vunits scale(vunits n, units x, units y) +{ + vunits r; + r.n = scale(n.n, x, y); + return r; +} + +inline vunits scale(vunits n, vunits x, vunits y) +{ + vunits r; + r.n = scale(n.n, x.n, y.n); + return r; +} + +inline hunits scale(hunits n, double x) +{ + hunits r; + r.n = int(n.n*x); + return r; +} + +inline units scale(units n, double x) +{ + return int(n*x); +} + +inline units points_to_units(units n) +{ + return scale(n, units_per_inch, 72); +} + diff --git a/gnu/usr.bin/groff/troff/hyphen.us b/gnu/usr.bin/groff/troff/hyphen.us new file mode 100644 index 0000000000..d86c3d58a7 --- /dev/null +++ b/gnu/usr.bin/groff/troff/hyphen.us @@ -0,0 +1,4449 @@ +% Hyphenation patterns for US English. +% These are the standard Plain TeX hyphenation patterns (in hyphen.tex). +.ach4 +.ad4der +.af1t +.al3t +.am5at +.an5c +.ang4 +.ani5m +.ant4 +.an3te +.anti5s +.ar5s +.ar4tie +.ar4ty +.as3c +.as1p +.as1s +.aster5 +.atom5 +.au1d +.av4i +.awn4 +.ba4g +.ba5na +.bas4e +.ber4 +.be5ra +.be3sm +.be5sto +.bri2 +.but4ti +.cam4pe +.can5c +.capa5b +.car5ol +.ca4t +.ce4la +.ch4 +.chill5i +.ci2 +.cit5r +.co3e +.co4r +.cor5ner +.de4moi +.de3o +.de3ra +.de3ri +.des4c +.dictio5 +.do4t +.du4c +.dumb5 +.earth5 +.eas3i +.eb4 +.eer4 +.eg2 +.el5d +.el3em +.enam3 +.en3g +.en3s +.eq5ui5t +.er4ri +.es3 +.eu3 +.eye5 +.fes3 +.for5mer +.ga2 +.ge2 +.gen3t4 +.ge5og +.gi5a +.gi4b +.go4r +.hand5i +.han5k +.he2 +.hero5i +.hes3 +.het3 +.hi3b +.hi3er +.hon5ey +.hon3o +.hov5 +.id4l +.idol3 +.im3m +.im5pin +.in1 +.in3ci +.ine2 +.in2k +.in3s +.ir5r +.is4i +.ju3r +.la4cy +.la4m +.lat5er +.lath5 +.le2 +.leg5e +.len4 +.lep5 +.lev1 +.li4g +.lig5a +.li2n +.li3o +.li4t +.mag5a5 +.mal5o +.man5a +.mar5ti +.me2 +.mer3c +.me5ter +.mis1 +.mist5i +.mon3e +.mo3ro +.mu5ta +.muta5b +.ni4c +.od2 +.odd5 +.of5te +.or5ato +.or3c +.or1d +.or3t +.os3 +.os4tl +.oth3 +.out3 +.ped5al +.pe5te +.pe5tit +.pi4e +.pio5n +.pi2t +.pre3m +.ra4c +.ran4t +.ratio5na +.ree2 +.re5mit +.res2 +.re5stat +.ri4g +.rit5u +.ro4q +.ros5t +.row5d +.ru4d +.sci3e +.self5 +.sell5 +.se2n +.se5rie +.sh2 +.si2 +.sing4 +.st4 +.sta5bl +.sy2 +.ta4 +.te4 +.ten5an +.th2 +.ti2 +.til4 +.tim5o5 +.ting4 +.tin5k +.ton4a +.to4p +.top5i +.tou5s +.trib5ut +.un1a +.un3ce +.under5 +.un1e +.un5k +.un5o +.un3u +.up3 +.ure3 +.us5a +.ven4de +.ve5ra +.wil5i +.ye4 +4ab. +a5bal +a5ban +abe2 +ab5erd +abi5a +ab5it5ab +ab5lat +ab5o5liz +4abr +ab5rog +ab3ul +a4car +ac5ard +ac5aro +a5ceou +ac1er +a5chet +4a2ci +a3cie +ac1in +a3cio +ac5rob +act5if +ac3ul +ac4um +a2d +ad4din +ad5er. +2adi +a3dia +ad3ica +adi4er +a3dio +a3dit +a5diu +ad4le +ad3ow +ad5ran +ad4su +4adu +a3duc +ad5um +ae4r +aeri4e +a2f +aff4 +a4gab +aga4n +ag5ell +age4o +4ageu +ag1i +4ag4l +ag1n +a2go +3agog +ag3oni +a5guer +ag5ul +a4gy +a3ha +a3he +ah4l +a3ho +ai2 +a5ia +a3ic. +ai5ly +a4i4n +ain5in +ain5o +ait5en +a1j +ak1en +al5ab +al3ad +a4lar +4aldi +2ale +al3end +a4lenti +a5le5o +al1i +al4ia. +ali4e +al5lev +4allic +4alm +a5log. +a4ly. +4alys +5a5lyst +5alyt +3alyz +4ama +am5ab +am3ag +ama5ra +am5asc +a4matis +a4m5ato +am5era +am3ic +am5if +am5ily +am1in +ami4no +a2mo +a5mon +amor5i +amp5en +a2n +an3age +3analy +a3nar +an3arc +anar4i +a3nati +4and +ande4s +an3dis +an1dl +an4dow +a5nee +a3nen +an5est. +a3neu +2ang +ang5ie +an1gl +a4n1ic +a3nies +an3i3f +an4ime +a5nimi +a5nine +an3io +a3nip +an3ish +an3it +a3niu +an4kli +5anniz +ano4 +an5ot +anoth5 +an2sa +an4sco +an4sn +an2sp +ans3po +an4st +an4sur +antal4 +an4tie +4anto +an2tr +an4tw +an3ua +an3ul +a5nur +4ao +apar4 +ap5at +ap5ero +a3pher +4aphi +a4pilla +ap5illar +ap3in +ap3ita +a3pitu +a2pl +apoc5 +ap5ola +apor5i +apos3t +aps5es +a3pu +aque5 +2a2r +ar3act +a5rade +ar5adis +ar3al +a5ramete +aran4g +ara3p +ar4at +a5ratio +ar5ativ +a5rau +ar5av4 +araw4 +arbal4 +ar4chan +ar5dine +ar4dr +ar5eas +a3ree +ar3ent +a5ress +ar4fi +ar4fl +ar1i +ar5ial +ar3ian +a3riet +ar4im +ar5inat +ar3io +ar2iz +ar2mi +ar5o5d +a5roni +a3roo +ar2p +ar3q +arre4 +ar4sa +ar2sh +4as. +as4ab +as3ant +ashi4 +a5sia. +a3sib +a3sic +5a5si4t +ask3i +as4l +a4soc +as5ph +as4sh +as3ten +as1tr +asur5a +a2ta +at3abl +at5ac +at3alo +at5ap +ate5c +at5ech +at3ego +at3en. +at3era +ater5n +a5terna +at3est +at5ev +4ath +ath5em +a5then +at4ho +ath5om +4ati. +a5tia +at5i5b +at1ic +at3if +ation5ar +at3itu +a4tog +a2tom +at5omiz +a4top +a4tos +a1tr +at5rop +at4sk +at4tag +at5te +at4th +a2tu +at5ua +at5ue +at3ul +at3ura +a2ty +au4b +augh3 +au3gu +au4l2 +aun5d +au3r +au5sib +aut5en +au1th +a2va +av3ag +a5van +ave4no +av3era +av5ern +av5ery +av1i +avi4er +av3ig +av5oc +a1vor +3away +aw3i +aw4ly +aws4 +ax4ic +ax4id +ay5al +aye4 +ays4 +azi4er +azz5i +5ba. +bad5ger +ba4ge +bal1a +ban5dag +ban4e +ban3i +barbi5 +bari4a +bas4si +1bat +ba4z +2b1b +b2be +b3ber +bbi4na +4b1d +4be. +beak4 +beat3 +4be2d +be3da +be3de +be3di +be3gi +be5gu +1bel +be1li +be3lo +4be5m +be5nig +be5nu +4bes4 +be3sp +be5str +3bet +bet5iz +be5tr +be3tw +be3w +be5yo +2bf +4b3h +bi2b +bi4d +3bie +bi5en +bi4er +2b3if +1bil +bi3liz +bina5r4 +bin4d +bi5net +bi3ogr +bi5ou +bi2t +3bi3tio +bi3tr +3bit5ua +b5itz +b1j +bk4 +b2l2 +blath5 +b4le. +blen4 +5blesp +b3lis +b4lo +blun4t +4b1m +4b3n +bne5g +3bod +bod3i +bo4e +bol3ic +bom4bi +bon4a +bon5at +3boo +5bor. +4b1ora +bor5d +5bore +5bori +5bos4 +b5ota +both5 +bo4to +bound3 +4bp +4brit +broth3 +2b5s2 +bsor4 +2bt +bt4l +b4to +b3tr +buf4fer +bu4ga +bu3li +bumi4 +bu4n +bunt4i +bu3re +bus5ie +buss4e +5bust +4buta +3butio +b5uto +b1v +4b5w +5by. +bys4 +1ca +cab3in +ca1bl +cach4 +ca5den +4cag4 +2c5ah +ca3lat +cal4la +call5in +4calo +can5d +can4e +can4ic +can5is +can3iz +can4ty +cany4 +ca5per +car5om +cast5er +cas5tig +4casy +ca4th +4cativ +cav5al +c3c +ccha5 +cci4a +ccompa5 +ccon4 +ccou3t +2ce. +4ced. +4ceden +3cei +5cel. +3cell +1cen +3cenc +2cen4e +4ceni +3cent +3cep +ce5ram +4cesa +3cessi +ces5si5b +ces5t +cet4 +c5e4ta +cew4 +2ch +4ch. +4ch3ab +5chanic +ch5a5nis +che2 +cheap3 +4ched +che5lo +3chemi +ch5ene +ch3er. +ch3ers +4ch1in +5chine. +ch5iness +5chini +5chio +3chit +chi2z +3cho2 +ch4ti +1ci +3cia +ci2a5b +cia5r +ci5c +4cier +5cific. +4cii +ci4la +3cili +2cim +2cin +c4ina +3cinat +cin3em +c1ing +c5ing. +5cino +cion4 +4cipe +ci3ph +4cipic +4cista +4cisti +2c1it +cit3iz +5ciz +ck1 +ck3i +1c4l4 +4clar +c5laratio +5clare +cle4m +4clic +clim4 +cly4 +c5n +1co +co5ag +coe2 +2cog +co4gr +coi4 +co3inc +col5i +5colo +col3or +com5er +con4a +c4one +con3g +con5t +co3pa +cop3ic +co4pl +4corb +coro3n +cos4e +cov1 +cove4 +cow5a +coz5e +co5zi +c1q +cras5t +5crat. +5cratic +cre3at +5cred +4c3reta +cre4v +cri2 +cri5f +c4rin +cris4 +5criti +cro4pl +crop5o +cros4e +cru4d +4c3s2 +2c1t +cta4b +ct5ang +c5tant +c2te +c3ter +c4ticu +ctim3i +ctu4r +c4tw +cud5 +c4uf +c4ui +cu5ity +5culi +cul4tis +3cultu +cu2ma +c3ume +cu4mi +3cun +cu3pi +cu5py +cur5a4b +cu5ria +1cus +cuss4i +3c4ut +cu4tie +4c5utiv +4cutr +1cy +cze4 +1d2a +5da. +2d3a4b +dach4 +4daf +2dag +da2m2 +dan3g +dard5 +dark5 +4dary +3dat +4dativ +4dato +5dav4 +dav5e +5day +d1b +d5c +d1d4 +2de. +deaf5 +deb5it +de4bon +decan4 +de4cil +de5com +2d1ed +4dee. +de5if +deli4e +del5i5q +de5lo +d4em +5dem. +3demic +dem5ic. +de5mil +de4mons +demor5 +1den +de4nar +de3no +denti5f +de3nu +de1p +de3pa +depi4 +de2pu +d3eq +d4erh +5derm +dern5iz +der5s +des2 +d2es. +de1sc +de2s5o +des3ti +de3str +de4su +de1t +de2to +de1v +dev3il +4dey +4d1f +d4ga +d3ge4t +dg1i +d2gy +d1h2 +5di. +1d4i3a +dia5b +di4cam +d4ice +3dict +3did +5di3en +d1if +di3ge +di4lato +d1in +1dina +3dine. +5dini +di5niz +1dio +dio5g +di4pl +dir2 +di1re +dirt5i +dis1 +5disi +d4is3t +d2iti +1di1v +d1j +d5k2 +4d5la +3dle. +3dled +3dles. +4dless +2d3lo +4d5lu +2dly +d1m +4d1n4 +1do +3do. +do5de +5doe +2d5of +d4og +do4la +doli4 +do5lor +dom5iz +do3nat +doni4 +doo3d +dop4p +d4or +3dos +4d5out +do4v +3dox +d1p +1dr +drag5on +4drai +dre4 +drea5r +5dren +dri4b +dril4 +dro4p +4drow +5drupli +4dry +2d1s2 +ds4p +d4sw +d4sy +d2th +1du +d1u1a +du2c +d1uca +duc5er +4duct. +4ducts +du5el +du4g +d3ule +dum4be +du4n +4dup +du4pe +d1v +d1w +d2y +5dyn +dy4se +dys5p +e1a4b +e3act +ead1 +ead5ie +ea4ge +ea5ger +ea4l +eal5er +eal3ou +eam3er +e5and +ear3a +ear4c +ear5es +ear4ic +ear4il +ear5k +ear2t +eart3e +ea5sp +e3ass +east3 +ea2t +eat5en +eath3i +e5atif +e4a3tu +ea2v +eav3en +eav5i +eav5o +2e1b +e4bel. +e4bels +e4ben +e4bit +e3br +e4cad +ecan5c +ecca5 +e1ce +ec5essa +ec2i +e4cib +ec5ificat +ec5ifie +ec5ify +ec3im +eci4t +e5cite +e4clam +e4clus +e2col +e4comm +e4compe +e4conc +e2cor +ec3ora +eco5ro +e1cr +e4crem +ec4tan +ec4te +e1cu +e4cul +ec3ula +2e2da +4ed3d +e4d1er +ede4s +4edi +e3dia +ed3ib +ed3ica +ed3im +ed1it +edi5z +4edo +e4dol +edon2 +e4dri +e4dul +ed5ulo +ee2c +eed3i +ee2f +eel3i +ee4ly +ee2m +ee4na +ee4p1 +ee2s4 +eest4 +ee4ty +e5ex +e1f +e4f3ere +1eff +e4fic +5efici +efil4 +e3fine +ef5i5nite +3efit +efor5es +e4fuse. +4egal +eger4 +eg5ib +eg4ic +eg5ing +e5git5 +eg5n +e4go. +e4gos +eg1ul +e5gur +5egy +e1h4 +eher4 +ei2 +e5ic +ei5d +eig2 +ei5gl +e3imb +e3inf +e1ing +e5inst +eir4d +eit3e +ei3th +e5ity +e1j +e4jud +ej5udi +eki4n +ek4la +e1la +e4la. +e4lac +elan4d +el5ativ +e4law +elaxa4 +e3lea +el5ebra +5elec +e4led +el3ega +e5len +e4l1er +e1les +el2f +el2i +e3libe +e4l5ic. +el3ica +e3lier +el5igib +e5lim +e4l3ing +e3lio +e2lis +el5ish +e3liv3 +4ella +el4lab +ello4 +e5loc +el5og +el3op. +el2sh +el4ta +e5lud +el5ug +e4mac +e4mag +e5man +em5ana +em5b +e1me +e2mel +e4met +em3ica +emi4e +em5igra +em1in2 +em5ine +em3i3ni +e4mis +em5ish +e5miss +em3iz +5emniz +emo4g +emoni5o +em3pi +e4mul +em5ula +emu3n +e3my +en5amo +e4nant +ench4er +en3dic +e5nea +e5nee +en3em +en5ero +en5esi +en5est +en3etr +e3new +en5ics +e5nie +e5nil +e3nio +en3ish +en3it +e5niu +5eniz +4enn +4eno +eno4g +e4nos +en3ov +en4sw +ent5age +4enthes +en3ua +en5uf +e3ny. +4en3z +e5of +eo2g +e4oi4 +e3ol +eop3ar +e1or +eo3re +eo5rol +eos4 +e4ot +eo4to +e5out +e5ow +e2pa +e3pai +ep5anc +e5pel +e3pent +ep5etitio +ephe4 +e4pli +e1po +e4prec +ep5reca +e4pred +ep3reh +e3pro +e4prob +ep4sh +ep5ti5b +e4put +ep5uta +e1q +equi3l +e4q3ui3s +er1a +era4b +4erand +er3ar +4erati. +2erb +er4bl +er3ch +er4che +2ere. +e3real +ere5co +ere3in +er5el. +er3emo +er5ena +er5ence +4erene +er3ent +ere4q +er5ess +er3est +eret4 +er1h +er1i +e1ria4 +5erick +e3rien +eri4er +er3ine +e1rio +4erit +er4iu +eri4v +e4riva +er3m4 +er4nis +4ernit +5erniz +er3no +2ero +er5ob +e5roc +ero4r +er1ou +er1s +er3set +ert3er +4ertl +er3tw +4eru +eru4t +5erwau +e1s4a +e4sage. +e4sages +es2c +e2sca +es5can +e3scr +es5cu +e1s2e +e2sec +es5ecr +es5enc +e4sert. +e4serts +e4serva +4esh +e3sha +esh5en +e1si +e2sic +e2sid +es5iden +es5igna +e2s5im +es4i4n +esis4te +esi4u +e5skin +es4mi +e2sol +es3olu +e2son +es5ona +e1sp +es3per +es5pira +es4pre +2ess +es4si4b +estan4 +es3tig +es5tim +4es2to +e3ston +2estr +e5stro +estruc5 +e2sur +es5urr +es4w +eta4b +eten4d +e3teo +ethod3 +et1ic +e5tide +etin4 +eti4no +e5tir +e5titio +et5itiv +4etn +et5ona +e3tra +e3tre +et3ric +et5rif +et3rog +et5ros +et3ua +et5ym +et5z +4eu +e5un +e3up +eu3ro +eus4 +eute4 +euti5l +eu5tr +eva2p5 +e2vas +ev5ast +e5vea +ev3ell +evel3o +e5veng +even4i +ev1er +e5verb +e1vi +ev3id +evi4l +e4vin +evi4v +e5voc +e5vu +e1wa +e4wag +e5wee +e3wh +ewil5 +ew3ing +e3wit +1exp +5eyc +5eye. +eys4 +1fa +fa3bl +fab3r +fa4ce +4fag +fain4 +fall5e +4fa4ma +fam5is +5far +far5th +fa3ta +fa3the +4fato +fault5 +4f5b +4fd +4fe. +feas4 +feath3 +fe4b +4feca +5fect +2fed +fe3li +fe4mo +fen2d +fend5e +fer1 +5ferr +fev4 +4f1f +f4fes +f4fie +f5fin. +f2f5is +f4fly +f2fy +4fh +1fi +fi3a +2f3ic. +4f3ical +f3ican +4ficate +f3icen +fi3cer +fic4i +5ficia +5ficie +4fics +fi3cu +fi5del +fight5 +fil5i +fill5in +4fily +2fin +5fina +fin2d5 +fi2ne +f1in3g +fin4n +fis4ti +f4l2 +f5less +flin4 +flo3re +f2ly5 +4fm +4fn +1fo +5fon +fon4de +fon4t +fo2r +fo5rat +for5ay +fore5t +for4i +fort5a +fos5 +4f5p +fra4t +f5rea +fres5c +fri2 +fril4 +frol5 +2f3s +2ft +f4to +f2ty +3fu +fu5el +4fug +fu4min +fu5ne +fu3ri +fusi4 +fus4s +4futa +1fy +1ga +gaf4 +5gal. +3gali +ga3lo +2gam +ga5met +g5amo +gan5is +ga3niz +gani5za +4gano +gar5n4 +gass4 +gath3 +4gativ +4gaz +g3b +gd4 +2ge. +2ged +geez4 +gel4in +ge5lis +ge5liz +4gely +1gen +ge4nat +ge5niz +4geno +4geny +1geo +ge3om +g4ery +5gesi +geth5 +4geto +ge4ty +ge4v +4g1g2 +g2ge +g3ger +gglu5 +ggo4 +gh3in +gh5out +gh4to +5gi. +1gi4a +gia5r +g1ic +5gicia +g4ico +gien5 +5gies. +gil4 +g3imen +3g4in. +gin5ge +5g4ins +5gio +3gir +gir4l +g3isl +gi4u +5giv +3giz +gl2 +gla4 +glad5i +5glas +1gle +gli4b +g3lig +3glo +glo3r +g1m +g4my +gn4a +g4na. +gnet4t +g1ni +g2nin +g4nio +g1no +g4non +1go +3go. +gob5 +5goe +3g4o4g +go3is +gon2 +4g3o3na +gondo5 +go3ni +5goo +go5riz +gor5ou +5gos. +gov1 +g3p +1gr +4grada +g4rai +gran2 +5graph. +g5rapher +5graphic +4graphy +4gray +gre4n +4gress. +4grit +g4ro +gruf4 +gs2 +g5ste +gth3 +gu4a +3guard +2gue +5gui5t +3gun +3gus +4gu4t +g3w +1gy +2g5y3n +gy5ra +h3ab4l +hach4 +hae4m +hae4t +h5agu +ha3la +hala3m +ha4m +han4ci +han4cy +5hand. +han4g +hang5er +hang5o +h5a5niz +han4k +han4te +hap3l +hap5t +ha3ran +ha5ras +har2d +hard3e +har4le +harp5en +har5ter +has5s +haun4 +5haz +haz3a +h1b +1head +3hear +he4can +h5ecat +h4ed +he5do5 +he3l4i +hel4lis +hel4ly +h5elo +hem4p +he2n +hena4 +hen5at +heo5r +hep5 +h4era +hera3p +her4ba +here5a +h3ern +h5erou +h3ery +h1es +he2s5p +he4t +het4ed +heu4 +h1f +h1h +hi5an +hi4co +high5 +h4il2 +himer4 +h4ina +hion4e +hi4p +hir4l +hi3ro +hir4p +hir4r +his3el +his4s +hith5er +hi2v +4hk +4h1l4 +hlan4 +h2lo +hlo3ri +4h1m +hmet4 +2h1n +h5odiz +h5ods +ho4g +hoge4 +hol5ar +3hol4e +ho4ma +home3 +hon4a +ho5ny +3hood +hoon4 +hor5at +ho5ris +hort3e +ho5ru +hos4e +ho5sen +hos1p +1hous +house3 +hov5el +4h5p +4hr4 +hree5 +hro5niz +hro3po +4h1s2 +h4sh +h4tar +ht1en +ht5es +h4ty +hu4g +hu4min +hun5ke +hun4t +hus3t4 +hu4t +h1w +h4wart +hy3pe +hy3ph +hy2s +2i1a +i2al +iam4 +iam5ete +i2an +4ianc +ian3i +4ian4t +ia5pe +iass4 +i4ativ +ia4tric +i4atu +ibe4 +ib3era +ib5ert +ib5ia +ib3in +ib5it. +ib5ite +i1bl +ib3li +i5bo +i1br +i2b5ri +i5bun +4icam +5icap +4icar +i4car. +i4cara +icas5 +i4cay +iccu4 +4iceo +4ich +2ici +i5cid +ic5ina +i2cip +ic3ipa +i4cly +i2c5oc +4i1cr +5icra +i4cry +ic4te +ictu2 +ic4t3ua +ic3ula +ic4um +ic5uo +i3cur +2id +i4dai +id5anc +id5d +ide3al +ide4s +i2di +id5ian +idi4ar +i5die +id3io +idi5ou +id1it +id5iu +i3dle +i4dom +id3ow +i4dr +i2du +id5uo +2ie4 +ied4e +5ie5ga +ield3 +ien5a4 +ien4e +i5enn +i3enti +i1er. +i3esc +i1est +i3et +4if. +if5ero +iff5en +if4fr +4ific. +i3fie +i3fl +4ift +2ig +iga5b +ig3era +ight3i +4igi +i3gib +ig3il +ig3in +ig3it +i4g4l +i2go +ig3or +ig5ot +i5gre +igu5i +ig1ur +i3h +4i5i4 +i3j +4ik +i1la +il3a4b +i4lade +i2l5am +ila5ra +i3leg +il1er +ilev4 +il5f +il1i +il3ia +il2ib +il3io +il4ist +2ilit +il2iz +ill5ab +4iln +il3oq +il4ty +il5ur +il3v +i4mag +im3age +ima5ry +imenta5r +4imet +im1i +im5ida +imi5le +i5mini +4imit +im4ni +i3mon +i2mu +im3ula +2in. +i4n3au +4inav +incel4 +in3cer +4ind +in5dling +2ine +i3nee +iner4ar +i5ness +4inga +4inge +in5gen +4ingi +in5gling +4ingo +4ingu +2ini +i5ni. +i4nia +in3io +in1is +i5nite. +5initio +in3ity +4ink +4inl +2inn +2i1no +i4no4c +ino4s +i4not +2ins +in3se +insur5a +2int. +2in4th +in1u +i5nus +4iny +2io +4io. +ioge4 +io2gr +i1ol +io4m +ion3at +ion4ery +ion3i +io5ph +ior3i +i4os +io5th +i5oti +io4to +i4our +2ip +ipe4 +iphras4 +ip3i +ip4ic +ip4re4 +ip3ul +i3qua +iq5uef +iq3uid +iq3ui3t +4ir +i1ra +ira4b +i4rac +ird5e +ire4de +i4ref +i4rel4 +i4res +ir5gi +ir1i +iri5de +ir4is +iri3tu +5i5r2iz +ir4min +iro4g +5iron. +ir5ul +2is. +is5ag +is3ar +isas5 +2is1c +is3ch +4ise +is3er +3isf +is5han +is3hon +ish5op +is3ib +isi4d +i5sis +is5itiv +4is4k +islan4 +4isms +i2so +iso5mer +is1p +is2pi +is4py +4is1s +is4sal +issen4 +is4ses +is4ta. +is1te +is1ti +ist4ly +4istral +i2su +is5us +4ita. +ita4bi +i4tag +4ita5m +i3tan +i3tat +2ite +it3era +i5teri +it4es +2ith +i1ti +4itia +4i2tic +it3ica +5i5tick +it3ig +it5ill +i2tim +2itio +4itis +i4tism +i2t5o5m +4iton +i4tram +it5ry +4itt +it3uat +i5tud +it3ul +4itz. +i1u +2iv +iv3ell +iv3en. +i4v3er. +i4vers. +iv5il. +iv5io +iv1it +i5vore +iv3o3ro +i4v3ot +4i5w +ix4o +4iy +4izar +izi4 +5izont +5ja +jac4q +ja4p +1je +jer5s +4jestie +4jesty +jew3 +jo4p +5judg +3ka. +k3ab +k5ag +kais4 +kal4 +k1b +k2ed +1kee +ke4g +ke5li +k3en4d +k1er +kes4 +k3est. +ke4ty +k3f +kh4 +k1i +5ki. +5k2ic +k4ill +kilo5 +k4im +k4in. +kin4de +k5iness +kin4g +ki4p +kis4 +k5ish +kk4 +k1l +4kley +4kly +k1m +k5nes +1k2no +ko5r +kosh4 +k3ou +kro5n +4k1s2 +k4sc +ks4l +k4sy +k5t +k1w +lab3ic +l4abo +laci4 +l4ade +la3dy +lag4n +lam3o +3land +lan4dl +lan5et +lan4te +lar4g +lar3i +las4e +la5tan +4lateli +4lativ +4lav +la4v4a +2l1b +lbin4 +4l1c2 +lce4 +l3ci +2ld +l2de +ld4ere +ld4eri +ldi4 +ld5is +l3dr +l4dri +le2a +le4bi +left5 +5leg. +5legg +le4mat +lem5atic +4len. +3lenc +5lene. +1lent +le3ph +le4pr +lera5b +ler4e +3lerg +3l4eri +l4ero +les2 +le5sco +5lesq +3less +5less. +l3eva +lev4er. +lev4era +lev4ers +3ley +4leye +2lf +l5fr +4l1g4 +l5ga +lgar3 +l4ges +lgo3 +2l3h +li4ag +li2am +liar5iz +li4as +li4ato +li5bi +5licio +li4cor +4lics +4lict. +l4icu +l3icy +l3ida +lid5er +3lidi +lif3er +l4iff +li4fl +5ligate +3ligh +li4gra +3lik +4l4i4l +lim4bl +lim3i +li4mo +l4im4p +l4ina +1l4ine +lin3ea +lin3i +link5er +li5og +4l4iq +lis4p +l1it +l2it. +5litica +l5i5tics +liv3er +l1iz +4lj +lka3 +l3kal +lka4t +l1l +l4law +l2le +l5lea +l3lec +l3leg +l3lel +l3le4n +l3le4t +ll2i +l2lin4 +l5lina +ll4o +lloqui5 +ll5out +l5low +2lm +l5met +lm3ing +l4mod +lmon4 +2l1n2 +3lo. +lob5al +lo4ci +4lof +3logic +l5ogo +3logu +lom3er +5long +lon4i +l3o3niz +lood5 +5lope. +lop3i +l3opm +lora4 +lo4rato +lo5rie +lor5ou +5los. +los5et +5losophiz +5losophy +los4t +lo4ta +loun5d +2lout +4lov +2lp +lpa5b +l3pha +l5phi +lp5ing +l3pit +l4pl +l5pr +4l1r +2l1s2 +l4sc +l2se +l4sie +4lt +lt5ag +ltane5 +l1te +lten4 +ltera4 +lth3i +l5ties. +ltis4 +l1tr +ltu2 +ltur3a +lu5a +lu3br +luch4 +lu3ci +lu3en +luf4 +lu5id +lu4ma +5lumi +l5umn. +5lumnia +lu3o +luo3r +4lup +luss4 +lus3te +1lut +l5ven +l5vet4 +2l1w +1ly +4lya +4lyb +ly5me +ly3no +2lys4 +l5yse +1ma +2mab +ma2ca +ma5chine +ma4cl +mag5in +5magn +2mah +maid5 +4mald +ma3lig +ma5lin +mal4li +mal4ty +5mania +man5is +man3iz +4map +ma5rine. +ma5riz +mar4ly +mar3v +ma5sce +mas4e +mas1t +5mate +math3 +ma3tis +4matiza +4m1b +mba4t5 +m5bil +m4b3ing +mbi4v +4m5c +4me. +2med +4med. +5media +me3die +m5e5dy +me2g +mel5on +mel4t +me2m +mem1o3 +1men +men4a +men5ac +men4de +4mene +men4i +mens4 +mensu5 +3ment +men4te +me5on +m5ersa +2mes +3mesti +me4ta +met3al +me1te +me5thi +m4etr +5metric +me5trie +me3try +me4v +4m1f +2mh +5mi. +mi3a +mid4a +mid4g +mig4 +3milia +m5i5lie +m4ill +min4a +3mind +m5inee +m4ingl +min5gli +m5ingly +min4t +m4inu +miot4 +m2is +mis4er. +mis5l +mis4ti +m5istry +4mith +m2iz +4mk +4m1l +m1m +mma5ry +4m1n +mn4a +m4nin +mn4o +1mo +4mocr +5mocratiz +mo2d1 +mo4go +mois2 +moi5se +4mok +mo5lest +mo3me +mon5et +mon5ge +moni3a +mon4ism +mon4ist +mo3niz +monol4 +mo3ny. +mo2r +4mora. +mos2 +mo5sey +mo3sp +moth3 +m5ouf +3mous +mo2v +4m1p +mpara5 +mpa5rab +mpar5i +m3pet +mphas4 +m2pi +mpi4a +mp5ies +m4p1in +m5pir +mp5is +mpo3ri +mpos5ite +m4pous +mpov5 +mp4tr +m2py +4m3r +4m1s2 +m4sh +m5si +4mt +1mu +mula5r4 +5mult +multi3 +3mum +mun2 +4mup +mu4u +4mw +1na +2n1a2b +n4abu +4nac. +na4ca +n5act +nag5er. +nak4 +na4li +na5lia +4nalt +na5mit +n2an +nanci4 +nan4it +nank4 +nar3c +4nare +nar3i +nar4l +n5arm +n4as +nas4c +nas5ti +n2at +na3tal +nato5miz +n2au +nau3se +3naut +nav4e +4n1b4 +ncar5 +n4ces. +n3cha +n5cheo +n5chil +n3chis +nc1in +nc4it +ncour5a +n1cr +n1cu +n4dai +n5dan +n1de +nd5est. +ndi4b +n5d2if +n1dit +n3diz +n5duc +ndu4r +nd2we +2ne. +n3ear +ne2b +neb3u +ne2c +5neck +2ned +ne4gat +neg5ativ +5nege +ne4la +nel5iz +ne5mi +ne4mo +1nen +4nene +3neo +ne4po +ne2q +n1er +nera5b +n4erar +n2ere +n4er5i +ner4r +1nes +2nes. +4nesp +2nest +4nesw +3netic +ne4v +n5eve +ne4w +n3f +n4gab +n3gel +nge4n4e +n5gere +n3geri +ng5ha +n3gib +ng1in +n5git +n4gla +ngov4 +ng5sh +n1gu +n4gum +n2gy +4n1h4 +nha4 +nhab3 +nhe4 +3n4ia +ni3an +ni4ap +ni3ba +ni4bl +ni4d +ni5di +ni4er +ni2fi +ni5ficat +n5igr +nik4 +n1im +ni3miz +n1in +5nine. +nin4g +ni4o +5nis. +nis4ta +n2it +n4ith +3nitio +n3itor +ni3tr +n1j +4nk2 +n5kero +n3ket +nk3in +n1kl +4n1l +n5m +nme4 +nmet4 +4n1n2 +nne4 +nni3al +nni4v +nob4l +no3ble +n5ocl +4n3o2d +3noe +4nog +noge4 +nois5i +no5l4i +5nologis +3nomic +n5o5miz +no4mo +no3my +no4n +non4ag +non5i +n5oniz +4nop +5nop5o5li +nor5ab +no4rary +4nosc +nos4e +nos5t +no5ta +1nou +3noun +nov3el3 +nowl3 +n1p4 +npi4 +npre4c +n1q +n1r +nru4 +2n1s2 +ns5ab +nsati4 +ns4c +n2se +n4s3es +nsid1 +nsig4 +n2sl +ns3m +n4soc +ns4pe +n5spi +nsta5bl +n1t +nta4b +nter3s +nt2i +n5tib +nti4er +nti2f +n3tine +n4t3ing +nti4p +ntrol5li +nt4s +ntu3me +nu1a +nu4d +nu5en +nuf4fe +n3uin +3nu3it +n4um +nu1me +n5umi +3nu4n +n3uo +nu3tr +n1v2 +n1w4 +nym4 +nyp4 +4nz +n3za +4oa +oad3 +o5a5les +oard3 +oas4e +oast5e +oat5i +ob3a3b +o5bar +obe4l +o1bi +o2bin +ob5ing +o3br +ob3ul +o1ce +och4 +o3chet +ocif3 +o4cil +o4clam +o4cod +oc3rac +oc5ratiz +ocre3 +5ocrit +octor5a +oc3ula +o5cure +od5ded +od3ic +odi3o +o2do4 +odor3 +od5uct. +od5ucts +o4el +o5eng +o3er +oe4ta +o3ev +o2fi +of5ite +ofit4t +o2g5a5r +og5ativ +o4gato +o1ge +o5gene +o5geo +o4ger +o3gie +1o1gis +og3it +o4gl +o5g2ly +3ogniz +o4gro +ogu5i +1ogy +2ogyn +o1h2 +ohab5 +oi2 +oic3es +oi3der +oiff4 +oig4 +oi5let +o3ing +oint5er +o5ism +oi5son +oist5en +oi3ter +o5j +2ok +o3ken +ok5ie +o1la +o4lan +olass4 +ol2d +old1e +ol3er +o3lesc +o3let +ol4fi +ol2i +o3lia +o3lice +ol5id. +o3li4f +o5lil +ol3ing +o5lio +o5lis. +ol3ish +o5lite +o5litio +o5liv +olli4e +ol5ogiz +olo4r +ol5pl +ol2t +ol3ub +ol3ume +ol3un +o5lus +ol2v +o2ly +om5ah +oma5l +om5atiz +om2be +om4bl +o2me +om3ena +om5erse +o4met +om5etry +o3mia +om3ic. +om3ica +o5mid +om1in +o5mini +5ommend +omo4ge +o4mon +om3pi +ompro5 +o2n +on1a +on4ac +o3nan +on1c +3oncil +2ond +on5do +o3nen +on5est +on4gu +on1ic +o3nio +on1is +o5niu +on3key +on4odi +on3omy +on3s +onspi4 +onspir5a +onsu4 +onten4 +on3t4i +ontif5 +on5um +onva5 +oo2 +ood5e +ood5i +oo4k +oop3i +o3ord +oost5 +o2pa +ope5d +op1er +3opera +4operag +2oph +o5phan +o5pher +op3ing +o3pit +o5pon +o4posi +o1pr +op1u +opy5 +o1q +o1ra +o5ra. +o4r3ag +or5aliz +or5ange +ore5a +o5real +or3ei +ore5sh +or5est. +orew4 +or4gu +4o5ria +or3ica +o5ril +or1in +o1rio +or3ity +o3riu +or2mi +orn2e +o5rof +or3oug +or5pe +3orrh +or4se +ors5en +orst4 +or3thi +or3thy +or4ty +o5rum +o1ry +os3al +os2c +os4ce +o3scop +4oscopi +o5scr +os4i4e +os5itiv +os3ito +os3ity +osi4u +os4l +o2so +os4pa +os4po +os2ta +o5stati +os5til +os5tit +o4tan +otele4g +ot3er. +ot5ers +o4tes +4oth +oth5esi +oth3i4 +ot3ic. +ot5ica +o3tice +o3tif +o3tis +oto5s +ou2 +ou3bl +ouch5i +ou5et +ou4l +ounc5er +oun2d +ou5v +ov4en +over4ne +over3s +ov4ert +o3vis +oviti4 +o5v4ol +ow3der +ow3el +ow5est +ow1i +own5i +o4wo +oy1a +1pa +pa4ca +pa4ce +pac4t +p4ad +5pagan +p3agat +p4ai +pain4 +p4al +pan4a +pan3el +pan4ty +pa3ny +pa1p +pa4pu +para5bl +par5age +par5di +3pare +par5el +p4a4ri +par4is +pa2te +pa5ter +5pathic +pa5thy +pa4tric +pav4 +3pay +4p1b +pd4 +4pe. +3pe4a +pear4l +pe2c +2p2ed +3pede +3pedi +pedia4 +ped4ic +p4ee +pee4d +pek4 +pe4la +peli4e +pe4nan +p4enc +pen4th +pe5on +p4era. +pera5bl +p4erag +p4eri +peri5st +per4mal +perme5 +p4ern +per3o +per3ti +pe5ru +per1v +pe2t +pe5ten +pe5tiz +4pf +4pg +4ph. +phar5i +phe3no +ph4er +ph4es. +ph1ic +5phie +ph5ing +5phisti +3phiz +ph2l +3phob +3phone +5phoni +pho4r +4phs +ph3t +5phu +1phy +pi3a +pian4 +pi4cie +pi4cy +p4id +p5ida +pi3de +5pidi +3piec +pi3en +pi4grap +pi3lo +pi2n +p4in. +pind4 +p4ino +3pi1o +pion4 +p3ith +pi5tha +pi2tu +2p3k2 +1p2l2 +3plan +plas5t +pli3a +pli5er +4plig +pli4n +ploi4 +plu4m +plum4b +4p1m +2p3n +po4c +5pod. +po5em +po3et5 +5po4g +poin2 +5point +poly5t +po4ni +po4p +1p4or +po4ry +1pos +pos1s +p4ot +po4ta +5poun +4p1p +ppa5ra +p2pe +p4ped +p5pel +p3pen +p3per +p3pet +ppo5site +pr2 +pray4e +5preci +pre5co +pre3em +pref5ac +pre4la +pre3r +p3rese +3press +pre5ten +pre3v +5pri4e +prin4t3 +pri4s +pris3o +p3roca +prof5it +pro3l +pros3e +pro1t +2p1s2 +p2se +ps4h +p4sib +2p1t +pt5a4b +p2te +p2th +pti3m +ptu4r +p4tw +pub3 +pue4 +puf4 +pul3c +pu4m +pu2n +pur4r +5pus +pu2t +5pute +put3er +pu3tr +put4ted +put4tin +p3w +qu2 +qua5v +2que. +3quer +3quet +2rab +ra3bi +rach4e +r5acl +raf5fi +raf4t +r2ai +ra4lo +ram3et +r2ami +rane5o +ran4ge +r4ani +ra5no +rap3er +3raphy +rar5c +rare4 +rar5ef +4raril +r2as +ration4 +rau4t +ra5vai +rav3el +ra5zie +r1b +r4bab +r4bag +rbi2 +rbi4f +r2bin +r5bine +rb5ing. +rb4o +r1c +r2ce +rcen4 +r3cha +rch4er +r4ci4b +rc4it +rcum3 +r4dal +rd2i +rdi4a +rdi4er +rdin4 +rd3ing +2re. +re1al +re3an +re5arr +5reav +re4aw +r5ebrat +rec5oll +rec5ompe +re4cre +2r2ed +re1de +re3dis +red5it +re4fac +re2fe +re5fer. +re3fi +re4fy +reg3is +re5it +re1li +re5lu +r4en4ta +ren4te +re1o +re5pin +re4posi +re1pu +r1er4 +r4eri +rero4 +re5ru +r4es. +re4spi +ress5ib +res2t +re5stal +re3str +re4ter +re4ti4z +re3tri +reu2 +re5uti +rev2 +re4val +rev3el +r5ev5er. +re5vers +re5vert +re5vil +rev5olu +re4wh +r1f +rfu4 +r4fy +rg2 +rg3er +r3get +r3gic +rgi4n +rg3ing +r5gis +r5git +r1gl +rgo4n +r3gu +rh4 +4rh. +4rhal +ri3a +ria4b +ri4ag +r4ib +rib3a +ric5as +r4ice +4rici +5ricid +ri4cie +r4ico +rid5er +ri3enc +ri3ent +ri1er +ri5et +rig5an +5rigi +ril3iz +5riman +rim5i +3rimo +rim4pe +r2ina +5rina. +rin4d +rin4e +rin4g +ri1o +5riph +riph5e +ri2pl +rip5lic +r4iq +r2is +r4is. +ris4c +r3ish +ris4p +ri3ta3b +r5ited. +rit5er. +rit5ers +rit3ic +ri2tu +rit5ur +riv5el +riv3et +riv3i +r3j +r3ket +rk4le +rk4lin +r1l +rle4 +r2led +r4lig +r4lis +rl5ish +r3lo4 +r1m +rma5c +r2me +r3men +rm5ers +rm3ing +r4ming. +r4mio +r3mit +r4my +r4nar +r3nel +r4ner +r5net +r3ney +r5nic +r1nis4 +r3nit +r3niv +rno4 +r4nou +r3nu +rob3l +r2oc +ro3cr +ro4e +ro1fe +ro5fil +rok2 +ro5ker +5role. +rom5ete +rom4i +rom4p +ron4al +ron4e +ro5n4is +ron4ta +1room +5root +ro3pel +rop3ic +ror3i +ro5ro +ros5per +ros4s +ro4the +ro4ty +ro4va +rov5el +rox5 +r1p +r4pea +r5pent +rp5er. +r3pet +rp4h4 +rp3ing +r3po +r1r4 +rre4c +rre4f +r4reo +rre4st +rri4o +rri4v +rron4 +rros4 +rrys4 +4rs2 +r1sa +rsa5ti +rs4c +r2se +r3sec +rse4cr +rs5er. +rs3es +rse5v2 +r1sh +r5sha +r1si +r4si4b +rson3 +r1sp +r5sw +rtach4 +r4tag +r3teb +rten4d +rte5o +r1ti +rt5ib +rti4d +r4tier +r3tig +rtil3i +rtil4l +r4tily +r4tist +r4tiv +r3tri +rtroph4 +rt4sh +ru3a +ru3e4l +ru3en +ru4gl +ru3in +rum3pl +ru2n +runk5 +run4ty +r5usc +ruti5n +rv4e +rvel4i +r3ven +rv5er. +r5vest +r3vey +r3vic +rvi4v +r3vo +r1w +ry4c +5rynge +ry3t +sa2 +2s1ab +5sack +sac3ri +s3act +5sai +salar4 +sal4m +sa5lo +sal4t +3sanc +san4de +s1ap +sa5ta +5sa3tio +sat3u +sau4 +sa5vor +5saw +4s5b +scan4t5 +sca4p +scav5 +s4ced +4scei +s4ces +sch2 +s4cho +3s4cie +5scin4d +scle5 +s4cli +scof4 +4scopy +scour5a +s1cu +4s5d +4se. +se4a +seas4 +sea5w +se2c3o +3sect +4s4ed +se4d4e +s5edl +se2g +seg3r +5sei +se1le +5self +5selv +4seme +se4mol +sen5at +4senc +sen4d +s5ened +sen5g +s5enin +4sentd +4sentl +sep3a3 +4s1er. +s4erl +ser4o +4servo +s1e4s +se5sh +ses5t +5se5um +5sev +sev3en +sew4i +5sex +4s3f +2s3g +s2h +2sh. +sh1er +5shev +sh1in +sh3io +3ship +shiv5 +sho4 +sh5old +shon3 +shor4 +short5 +4shw +si1b +s5icc +3side. +5sides +5sidi +si5diz +4signa +sil4e +4sily +2s1in +s2ina +5sine. +s3ing +1sio +5sion +sion5a +si2r +sir5a +1sis +3sitio +5siu +1siv +5siz +sk2 +4ske +s3ket +sk5ine +sk5ing +s1l2 +s3lat +s2le +slith5 +2s1m +s3ma +small3 +sman3 +smel4 +s5men +5smith +smol5d4 +s1n4 +1so +so4ce +soft3 +so4lab +sol3d2 +so3lic +5solv +3som +3s4on. +sona4 +son4g +s4op +5sophic +s5ophiz +s5ophy +sor5c +sor5d +4sov +so5vi +2spa +5spai +spa4n +spen4d +2s5peo +2sper +s2phe +3spher +spho5 +spil4 +sp5ing +4spio +s4ply +s4pon +spor4 +4spot +squal4l +s1r +2ss +s1sa +ssas3 +s2s5c +s3sel +s5seng +s4ses. +s5set +s1si +s4sie +ssi4er +ss5ily +s4sl +ss4li +s4sn +sspend4 +ss2t +ssur5a +ss5w +2st. +s2tag +s2tal +stam4i +5stand +s4ta4p +5stat. +s4ted +stern5i +s5tero +ste2w +stew5a +s3the +st2i +s4ti. +s5tia +s1tic +5stick +s4tie +s3tif +st3ing +5stir +s1tle +5stock +stom3a +5stone +s4top +3store +st4r +s4trad +5stratu +s4tray +s4trid +4stry +4st3w +s2ty +1su +su1al +su4b3 +su2g3 +su5is +suit3 +s4ul +su2m +sum3i +su2n +su2r +4sv +sw2 +4swo +s4y +4syc +3syl +syn5o +sy5rin +1ta +3ta. +2tab +ta5bles +5taboliz +4taci +ta5do +4taf4 +tai5lo +ta2l +ta5la +tal5en +tal3i +4talk +tal4lis +ta5log +ta5mo +tan4de +tanta3 +ta5per +ta5pl +tar4a +4tarc +4tare +ta3riz +tas4e +ta5sy +4tatic +ta4tur +taun4 +tav4 +2taw +tax4is +2t1b +4tc +t4ch +tch5et +4t1d +4te. +tead4i +4teat +tece4 +5tect +2t1ed +te5di +1tee +teg4 +te5ger +te5gi +3tel. +teli4 +5tels +te2ma2 +tem3at +3tenan +3tenc +3tend +4tenes +1tent +ten4tag +1teo +te4p +te5pe +ter3c +5ter3d +1teri +ter5ies +ter3is +teri5za +5ternit +ter5v +4tes. +4tess +t3ess. +teth5e +3teu +3tex +4tey +2t1f +4t1g +2th. +than4 +th2e +4thea +th3eas +the5at +the3is +3thet +th5ic. +th5ica +4thil +5think +4thl +th5ode +5thodic +4thoo +thor5it +tho5riz +2ths +1tia +ti4ab +ti4ato +2ti2b +4tick +t4ico +t4ic1u +5tidi +3tien +tif2 +ti5fy +2tig +5tigu +till5in +1tim +4timp +tim5ul +2t1in +t2ina +3tine. +3tini +1tio +ti5oc +tion5ee +5tiq +ti3sa +3tise +tis4m +ti5so +tis4p +5tistica +ti3tl +ti4u +1tiv +tiv4a +1tiz +ti3za +ti3zen +2tl +t5la +tlan4 +3tle. +3tled +3tles. +t5let. +t5lo +4t1m +tme4 +2t1n2 +1to +to3b +to5crat +4todo +2tof +to2gr +to5ic +to2ma +tom4b +to3my +ton4ali +to3nat +4tono +4tony +to2ra +to3rie +tor5iz +tos2 +5tour +4tout +to3war +4t1p +1tra +tra3b +tra5ch +traci4 +trac4it +trac4te +tras4 +tra5ven +trav5es5 +tre5f +tre4m +trem5i +5tria +tri5ces +5tricia +4trics +2trim +tri4v +tro5mi +tron5i +4trony +tro5phe +tro3sp +tro3v +tru5i +trus4 +4t1s2 +t4sc +tsh4 +t4sw +4t3t2 +t4tes +t5to +ttu4 +1tu +tu1a +tu3ar +tu4bi +tud2 +4tue +4tuf4 +5tu3i +3tum +tu4nis +2t3up. +3ture +5turi +tur3is +tur5o +tu5ry +3tus +4tv +tw4 +4t1wa +twis4 +4two +1ty +4tya +2tyl +type3 +ty5ph +4tz +tz4e +4uab +uac4 +ua5na +uan4i +uar5ant +uar2d +uar3i +uar3t +u1at +uav4 +ub4e +u4bel +u3ber +u4bero +u1b4i +u4b5ing +u3ble. +u3ca +uci4b +uc4it +ucle3 +u3cr +u3cu +u4cy +ud5d +ud3er +ud5est +udev4 +u1dic +ud3ied +ud3ies +ud5is +u5dit +u4don +ud4si +u4du +u4ene +uens4 +uen4te +uer4il +3ufa +u3fl +ugh3en +ug5in +2ui2 +uil5iz +ui4n +u1ing +uir4m +uita4 +uiv3 +uiv4er. +u5j +4uk +u1la +ula5b +u5lati +ulch4 +5ulche +ul3der +ul4e +u1len +ul4gi +ul2i +u5lia +ul3ing +ul5ish +ul4lar +ul4li4b +ul4lis +4ul3m +u1l4o +4uls +uls5es +ul1ti +ultra3 +4ultu +u3lu +ul5ul +ul5v +um5ab +um4bi +um4bly +u1mi +u4m3ing +umor5o +um2p +unat4 +u2ne +un4er +u1ni +un4im +u2nin +un5ish +uni3v +un3s4 +un4sw +unt3ab +un4ter. +un4tes +unu4 +un5y +un5z +u4ors +u5os +u1ou +u1pe +uper5s +u5pia +up3ing +u3pl +up3p +upport5 +upt5ib +uptu4 +u1ra +4ura. +u4rag +u4ras +ur4be +urc4 +ur1d +ure5at +ur4fer +ur4fr +u3rif +uri4fic +ur1in +u3rio +u1rit +ur3iz +ur2l +url5ing. +ur4no +uros4 +ur4pe +ur4pi +urs5er +ur5tes +ur3the +urti4 +ur4tie +u3ru +2us +u5sad +u5san +us4ap +usc2 +us3ci +use5a +u5sia +u3sic +us4lin +us1p +us5sl +us5tere +us1tr +u2su +usur4 +uta4b +u3tat +4ute. +4utel +4uten +uten4i +4u1t2i +uti5liz +u3tine +ut3ing +ution5a +u4tis +5u5tiz +u4t1l +ut5of +uto5g +uto5matic +u5ton +u4tou +uts4 +u3u +uu4m +u1v2 +uxu3 +uz4e +1va +5va. +2v1a4b +vac5il +vac3u +vag4 +va4ge +va5lie +val5o +val1u +va5mo +va5niz +va5pi +var5ied +3vat +4ve. +4ved +veg3 +v3el. +vel3li +ve4lo +v4ely +ven3om +v5enue +v4erd +5vere. +v4erel +v3eren +ver5enc +v4eres +ver3ie +vermi4n +3verse +ver3th +v4e2s +4ves. +ves4te +ve4te +vet3er +ve4ty +vi5ali +5vian +5vide. +5vided +4v3iden +5vides +5vidi +v3if +vi5gn +vik4 +2vil +5vilit +v3i3liz +v1in +4vi4na +v2inc +vin5d +4ving +vio3l +v3io4r +vi1ou +vi4p +vi5ro +vis3it +vi3so +vi3su +4viti +vit3r +4vity +3viv +5vo. +voi4 +3vok +vo4la +v5ole +5volt +3volv +vom5i +vor5ab +vori4 +vo4ry +vo4ta +4votee +4vv4 +v4y +w5abl +2wac +wa5ger +wag5o +wait5 +w5al. +wam4 +war4t +was4t +wa1te +wa5ver +w1b +wea5rie +weath3 +wed4n +weet3 +wee5v +wel4l +w1er +west3 +w3ev +whi4 +wi2 +wil2 +will5in +win4de +win4g +wir4 +3wise +with3 +wiz5 +w4k +wl4es +wl3in +w4no +1wo2 +wom1 +wo5ven +w5p +wra4 +wri4 +writa4 +w3sh +ws4l +ws4pe +w5s4t +4wt +wy4 +x1a +xac5e +x4ago +xam3 +x4ap +xas5 +x3c2 +x1e +xe4cuto +x2ed +xer4i +xe5ro +x1h +xhi2 +xhil5 +xhu4 +x3i +xi5a +xi5c +xi5di +x4ime +xi5miz +x3o +x4ob +x3p +xpan4d +xpecto5 +xpe3d +x1t2 +x3ti +x1u +xu3a +xx4 +y5ac +3yar4 +y5at +y1b +y1c +y2ce +yc5er +y3ch +ych4e +ycom4 +ycot4 +y1d +y5ee +y1er +y4erf +yes4 +ye4t +y5gi +4y3h +y1i +y3la +ylla5bl +y3lo +y5lu +ymbol5 +yme4 +ympa3 +yn3chr +yn5d +yn5g +yn5ic +5ynx +y1o4 +yo5d +y4o5g +yom4 +yo5net +y4ons +y4os +y4ped +yper5 +yp3i +y3po +y4poc +yp2ta +y5pu +yra5m +yr5ia +y3ro +yr4r +ys4c +y3s2e +ys3ica +ys3io +3ysis +y4so +yss4 +ys1t +ys3ta +ysur4 +y3thin +yt3ic +y1w +za1 +z5a2b +zar2 +4zb +2ze +ze4n +ze4p +z1er +ze3ro +zet4 +2z1i +z4il +z4is +5zl +4zm +1zo +zo4m +zo5ol +zte4 +4z1z2 +z4zy diff --git a/gnu/usr.bin/groff/troff/input.cc b/gnu/usr.bin/groff/troff/input.cc new file mode 100644 index 0000000000..609ee78edf --- /dev/null +++ b/gnu/usr.bin/groff/troff/input.cc @@ -0,0 +1,5824 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "troff.h" +#include "symbol.h" +#include "dictionary.h" +#include "hvunits.h" +#include "env.h" +#include "request.h" +#include "node.h" +#include "reg.h" +#include "token.h" +#include "div.h" +#include "charinfo.h" +#include "font.h" +#include "searchpath.h" +#include "macropath.h" +#include "defs.h" + +// Needed for getpid(). +#include "posix.h" + +#define USAGE_EXIT_CODE 1 +#define MACRO_PREFIX "tmac." +#define STARTUP_FILE "troffrc" +#define DEFAULT_INPUT_STACK_LIMIT 1000 + +#ifndef DEFAULT_WARNING_MASK +// warnings that are enabled by default +#define DEFAULT_WARNING_MASK \ + (WARN_CHAR|WARN_NUMBER|WARN_BREAK|WARN_SPACE|WARN_FONT) +#endif + +// initial size of buffer for reading names; expanded as necessary +#define ABUF_SIZE 16 + +#ifdef COLUMN +void init_column_requests(); +#endif /* COLUMN */ + +static node *read_draw_node(); +void handle_first_page_transition(); +static void push_token(const token &); +void copy_file(); +#ifdef COLUMN +void vjustify(); +#endif /* COLUMN */ +void transparent(); +void transparent_file(); + +const char *program_name = 0; +token tok; +int break_flag = 0; +static int backtrace_flag = 0; +char *pipe_command = 0; +charinfo *charset_table[256]; + +static int warning_mask = DEFAULT_WARNING_MASK; +static int inhibit_errors = 0; + +static void enable_warning(const char *); +static void disable_warning(const char *); + +static int escape_char = '\\'; +static symbol end_macro_name; +static int compatible_flag = 0; +static void process_input_stack(); +int ascii_output_flag = 0; +int suppress_output_flag = 0; + +int tcommand_flag = 0; + +static int get_copy(node**, int = 0); +static symbol read_escape_name(); +static void interpolate_string(symbol); +static void interpolate_macro(symbol); +static void interpolate_number_format(symbol); +static void interpolate_environment_variable(symbol); + +static void interpolate_arg(symbol); +static request_or_macro *lookup_request(symbol); +static int get_delim_number(units *, int); +static int get_delim_number(units *, int, units); +static int get_line_arg(units *res, int si, charinfo **cp); +static int read_size(int *); +static symbol get_delim_name(); +static void init_registers(); + +struct input_iterator; +input_iterator *make_temp_iterator(const char *); +const char *input_char_description(int); + +const int ESCAPE_QUESTION = 015; +const int BEGIN_TRAP = 016; +const int END_TRAP = 017; +const int PAGE_EJECTOR = 020; +const int ESCAPE_NEWLINE = 021; +const int ESCAPE_AMPERSAND = 022; +const int ESCAPE_UNDERSCORE = 023; +const int ESCAPE_BAR = 024; +const int ESCAPE_CIRCUMFLEX = 025; +const int ESCAPE_LEFT_BRACE = 026; +const int ESCAPE_RIGHT_BRACE = 027; +const int ESCAPE_LEFT_QUOTE = 030; +const int ESCAPE_RIGHT_QUOTE = 031; +const int ESCAPE_HYPHEN = 032; +const int ESCAPE_BANG = 033; +const int ESCAPE_c = 034; +const int ESCAPE_e = 035; +const int ESCAPE_PERCENT = 036; +const int ESCAPE_SPACE = 037; + +const int TITLE_REQUEST = 0200; +const int COPY_FILE_REQUEST = 0201; +const int TRANSPARENT_FILE_REQUEST = 0202; +#ifdef COLUMN +const int VJUSTIFY_REQUEST = 0203; +#endif /* COLUMN */ +const int ESCAPE_E = 0204; +const int LAST_PAGE_EJECTOR = 0205; +const int ESCAPE_RIGHT_PARENTHESIS = 0206; + +void set_escape_char() +{ + if (has_arg()) { + if (tok.ch() == 0) { + error("bad escape character"); + escape_char = '\\'; + } + else + escape_char = tok.ch(); + } + else + escape_char = '\\'; + skip_line(); +} + +void escape_off() +{ + escape_char = 0; + skip_line(); +} + +class input_iterator { +public: + input_iterator(); + virtual ~input_iterator(); + int get(node **); + friend class input_stack; +protected: + const unsigned char *ptr; + const unsigned char *eptr; + input_iterator *next; +private: + virtual int fill(node **); + virtual int peek(); + virtual int has_args() { return 0; } + virtual int nargs() { return 0; } + virtual input_iterator *get_arg(int) { return NULL; } + virtual int get_location(int, const char **, int *) + { return 0; } + virtual void backtrace() {} + virtual int set_location(const char *, int) + { return 0; } + virtual int next_file(FILE *, const char *) { return 0; } + virtual void shift(int) {} + virtual int is_boundary(); + virtual int internal_level() { return 0; } + virtual int is_file() { return 0; } +}; + +input_iterator::input_iterator() +: ptr(0), eptr(0) +{ +} + +input_iterator::~input_iterator() +{ +} + +int input_iterator::fill(node **) +{ + return EOF; +} + +int input_iterator::peek() +{ + return EOF; +} + +int input_iterator::is_boundary() +{ + return 0; +} + +inline int input_iterator::get(node **p) +{ + return ptr < eptr ? *ptr++ : fill(p); +} + + +class input_boundary : public input_iterator { +public: + int is_boundary() { return 1; } +}; + +class file_iterator : public input_iterator { + FILE *fp; + int lineno; + const char *filename; + int newline_flag; + enum { BUF_SIZE = 512 }; + unsigned char buf[BUF_SIZE]; +public: + file_iterator(FILE *, const char *); + ~file_iterator(); + int fill(node **); + int peek(); + int get_location(int, const char **, int *); + void backtrace(); + int set_location(const char *, int); + int next_file(FILE *, const char *); + int is_file(); +}; + +file_iterator::file_iterator(FILE *f, const char *fn) +: fp(f), filename(fn), lineno(1), newline_flag(0) +{ +} + +file_iterator::~file_iterator() +{ + if (fp != stdin) + fclose(fp); + else + clearerr(stdin); +} + +int file_iterator::is_file() +{ + return 1; +} + +int file_iterator::next_file(FILE *f, const char *s) +{ + if (fp != stdin) + fclose(fp); + else + clearerr(stdin); + filename = s; + fp = f; + lineno = 1; + newline_flag = 0; + ptr = 0; + eptr = 0; + return 1; +} + +int file_iterator::fill(node **) +{ + if (newline_flag) + lineno++; + newline_flag = 0; + unsigned char *p = buf; + ptr = p; + unsigned char *e = p + BUF_SIZE; + while (p < e) { + int c = getc(fp); + if (c == EOF) + break; + if (illegal_input_char(c)) + warning(WARN_INPUT, "illegal input character code %1", int(c)); + else { + *p++ = c; + if (c == '\n') { + newline_flag = 1; + break; + } + } + } + if (p > buf) { + eptr = p; + return *ptr++; + } + else { + eptr = p; + return EOF; + } +} + +int file_iterator::peek() +{ + int c = getc(fp); + while (illegal_input_char(c)) { + warning(WARN_INPUT, "illegal input character code %1", int(c)); + c = getc(fp); + } + if (c != EOF) + ungetc(c, fp); + return c; +} + +int file_iterator::get_location(int /*allow_macro*/, + const char **filenamep, int *linenop) +{ + *linenop = lineno; + if (filename != 0 && strcmp(filename, "-") == 0) + *filenamep = ""; + else + *filenamep = filename; + return 1; +} + +void file_iterator::backtrace() +{ + errprint("%1:%2: backtrace: file `%1'\n", filename, lineno); +} + +int file_iterator::set_location(const char *f, int ln) +{ + if (f) + filename = f; + lineno = ln; + return 1; +} + +input_iterator nil_iterator; + +class input_stack { +public: + static int get(node **); + static int peek(); + static void push(input_iterator *); + static input_iterator *get_arg(int); + static int nargs(); + static int get_location(int, const char **, int *); + static int set_location(const char *, int); + static void backtrace(); + static void backtrace_all(); + static void next_file(FILE *, const char *); + static void end_file(); + static void shift(int n); + static void add_boundary(); + static void remove_boundary(); + static int get_level(); + static void clear(); + + static int limit; +private: + static input_iterator *top; + static int level; + + static int finish_get(node **); + static int finish_peek(); +}; + +input_iterator *input_stack::top = &nil_iterator; +int input_stack::level = 0; +int input_stack::limit = DEFAULT_INPUT_STACK_LIMIT; + +inline int input_stack::get_level() +{ + return level + top->internal_level(); +} + +inline int input_stack::get(node **np) +{ + return (top->ptr < top->eptr) ? *top->ptr++ : finish_get(np); +} + +int input_stack::finish_get(node **np) +{ + for (;;) { + int c = top->fill(np); + if (c != EOF || top->is_boundary()) + return c; + if (top == &nil_iterator) + break; + input_iterator *tem = top; + top = top->next; + level--; + delete tem; + if (top->ptr < top->eptr) + return *top->ptr++; + } + assert(level == 0); + return EOF; +} + +inline int input_stack::peek() +{ + return (top->ptr < top->eptr) ? *top->ptr : finish_peek(); +} + +int input_stack::finish_peek() +{ + for (;;) { + int c = top->peek(); + if (c != EOF || top->is_boundary()) + return c; + if (top == &nil_iterator) + break; + input_iterator *tem = top; + top = top->next; + level--; + delete tem; + if (top->ptr < top->eptr) + return *top->ptr; + } + assert(level == 0); + return EOF; +} + +void input_stack::add_boundary() +{ + push(new input_boundary); +} + +void input_stack::remove_boundary() +{ + assert(top->is_boundary()); + input_iterator *temp = top->next; + delete top; + top = temp; + level--; +} + +void input_stack::push(input_iterator *in) +{ + if (in == 0) + return; + if (++level > limit && limit > 0) + fatal("input stack limit exceeded (probable infinite loop)"); + in->next = top; + top = in; +} + +input_iterator *input_stack::get_arg(int i) +{ + input_iterator *p; + for (p = top; p != NULL; p = p->next) + if (p->has_args()) + return p->get_arg(i); + return 0; +} + +void input_stack::shift(int n) +{ + for (input_iterator *p = top; p; p = p->next) + if (p->has_args()) { + p->shift(n); + return; + } +} + +int input_stack::nargs() +{ + for (input_iterator *p =top; p != 0; p = p->next) + if (p->has_args()) + return p->nargs(); + return 0; +} + +int input_stack::get_location(int allow_macro, const char **filenamep, int *linenop) +{ + for (input_iterator *p = top; p; p = p->next) + if (p->get_location(allow_macro, filenamep, linenop)) + return 1; + return 0; +} + +void input_stack::backtrace() +{ + const char *f; + int n; + // only backtrace down to (not including) the topmost file + for (input_iterator *p = top; + p && !p->get_location(0, &f, &n); + p = p->next) + p->backtrace(); +} + +void input_stack::backtrace_all() +{ + for (input_iterator *p = top; p; p = p->next) + p->backtrace(); +} + +int input_stack::set_location(const char *filename, int lineno) +{ + for (input_iterator *p = top; p; p = p->next) + if (p->set_location(filename, lineno)) + return 1; + return 0; +} + +void input_stack::next_file(FILE *fp, const char *s) +{ + for (input_iterator **pp = ⊤ *pp != &nil_iterator; pp = &(*pp)->next) + if ((*pp)->next_file(fp, s)) + return; + if (++level > limit && limit > 0) + fatal("input stack limit exceeded"); + *pp = new file_iterator(fp, s); + (*pp)->next = &nil_iterator; +} + +void input_stack::end_file() +{ + for (input_iterator **pp = ⊤ *pp != &nil_iterator; pp = &(*pp)->next) + if ((*pp)->is_file()) { + input_iterator *tem = *pp; + *pp = (*pp)->next; + delete tem; + level--; + return; + } +} + +void input_stack::clear() +{ + int nboundaries = 0; + while (top != &nil_iterator) { + if (top->is_boundary()) + nboundaries++; + input_iterator *tem = top; + top = top->next; + level--; + delete tem; + } + // Keep while_request happy. + for (; nboundaries > 0; --nboundaries) + add_boundary(); +} + +void backtrace_request() +{ + input_stack::backtrace_all(); + fflush(stderr); + skip_line(); +} + +void next_file() +{ + symbol nm = get_long_name(0); + while (!tok.newline() && !tok.eof()) + tok.next(); + if (nm.is_null()) + input_stack::end_file(); + else { + errno = 0; + FILE *fp = fopen(nm.contents(), "r"); + if (!fp) + error("can't open `%1': %2", nm.contents(), strerror(errno)); + else + input_stack::next_file(fp, nm.contents()); + } + tok.next(); +} + +void shift() +{ + int n; + if (!has_arg() || !get_integer(&n)) + n = 1; + input_stack::shift(n); + skip_line(); +} + +static int get_char_for_escape_name() +{ + int c = get_copy(NULL); + switch (c) { + case EOF: + error("end of input in escape name"); + return '\0'; + default: + if (!illegal_input_char(c)) + break; + // fall through + case ' ': + case '\n': + case '\t': + case '\001': + case '\b': + error("%1 is not allowed in an escape name", input_char_description(c)); + return '\0'; + } + return c; +} + +static symbol read_two_char_escape_name() +{ + char buf[3]; + buf[0] = get_char_for_escape_name(); + if (buf[0] != '\0') { + buf[1] = get_char_for_escape_name(); + if (buf[1] == '\0') + buf[0] = 0; + else + buf[2] = 0; + } + return symbol(buf); +} + +static symbol read_long_escape_name() +{ + int start_level = input_stack::get_level(); + char abuf[ABUF_SIZE]; + char *buf = abuf; + int buf_size = ABUF_SIZE; + int i = 0; + for (;;) { + int c = get_char_for_escape_name(); + if (c == 0) { + if (buf != abuf) + a_delete buf; + return NULL_SYMBOL; + } + if (i + 2 > buf_size) { + if (buf == abuf) { + buf = new char [ABUF_SIZE*2]; + memcpy(buf, abuf, buf_size); + buf_size = ABUF_SIZE*2; + } + else { + char *old_buf = buf; + buf = new char[buf_size*2]; + memcpy(buf, old_buf, buf_size); + buf_size *= 2; + a_delete old_buf; + } + } + if (c == ']' && input_stack::get_level() == start_level) + break; + buf[i++] = c; + } + buf[i] = 0; + if (buf == abuf) { + if (i == 0) { + error("empty escape name"); + return NULL_SYMBOL; + } + return symbol(abuf); + } + else { + symbol s(buf); + a_delete buf; + return s; + } +} + +static symbol read_escape_name() +{ + int c = get_char_for_escape_name(); + if (c == 0) + return NULL_SYMBOL; + if (c == '(') + return read_two_char_escape_name(); + if (c == '[' && !compatible_flag) + return read_long_escape_name(); + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + return symbol(buf); +} + +static symbol read_increment_and_escape_name(int *incp) +{ + int c = get_char_for_escape_name(); + switch (c) { + case 0: + *incp = 0; + return NULL_SYMBOL; + case '(': + *incp = 0; + return read_two_char_escape_name(); + case '+': + *incp = 1; + return read_escape_name(); + case '-': + *incp = -1; + return read_escape_name(); + case '[': + if (!compatible_flag) { + *incp = 0; + return read_long_escape_name(); + } + break; + } + *incp = 0; + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + return symbol(buf); +} + +static int get_copy(node **nd, int defining) +{ + for (;;) { + int c = input_stack::get(nd); + if (c == ESCAPE_NEWLINE) { + if (defining) + return c; + do { + c = input_stack::get(nd); + } while (c == ESCAPE_NEWLINE); + } + if (c != escape_char || escape_char <= 0) + return c; + c = input_stack::peek(); + switch(c) { + case 0: + return escape_char; + case '"': + (void)input_stack::get(NULL); + while ((c = input_stack::get(NULL)) != '\n' && c != EOF) + ; + return c; + case '#': // Like \" but newline is ignored. + (void)input_stack::get(NULL); + while ((c = input_stack::get(NULL)) != '\n') + if (c == EOF) + return EOF; + break; + case '$': + { + (void)input_stack::get(NULL); + symbol s = read_escape_name(); + if (!s.is_null()) + interpolate_arg(s); + break; + } + case '*': + { + (void)input_stack::get(NULL); + symbol s = read_escape_name(); + if (!s.is_null()) + interpolate_string(s); + break; + } + case 'a': + (void)input_stack::get(NULL); + return '\001'; + case 'e': + (void)input_stack::get(NULL); + return ESCAPE_e; + case 'E': + (void)input_stack::get(NULL); + return ESCAPE_E; + case 'n': + { + (void)input_stack::get(NULL); + int inc; + symbol s = read_increment_and_escape_name(&inc); + if (!s.is_null()) + interpolate_number_reg(s, inc); + break; + } + case 'g': + { + (void)input_stack::get(NULL); + symbol s = read_escape_name(); + if (!s.is_null()) + interpolate_number_format(s); + break; + } + case 't': + (void)input_stack::get(NULL); + return '\t'; + case 'V': + { + (void)input_stack::get(NULL); + symbol s = read_escape_name(); + if (!s.is_null()) + interpolate_environment_variable(s); + break; + } + case '\n': + (void)input_stack::get(NULL); + if (defining) + return ESCAPE_NEWLINE; + break; + case ' ': + (void)input_stack::get(NULL); + return ESCAPE_SPACE; + case '|': + (void)input_stack::get(NULL); + return ESCAPE_BAR; + case '^': + (void)input_stack::get(NULL); + return ESCAPE_CIRCUMFLEX; + case '{': + (void)input_stack::get(NULL); + return ESCAPE_LEFT_BRACE; + case '}': + (void)input_stack::get(NULL); + return ESCAPE_RIGHT_BRACE; + case '`': + (void)input_stack::get(NULL); + return ESCAPE_LEFT_QUOTE; + case '\'': + (void)input_stack::get(NULL); + return ESCAPE_RIGHT_QUOTE; + case '-': + (void)input_stack::get(NULL); + return ESCAPE_HYPHEN; + case '_': + (void)input_stack::get(NULL); + return ESCAPE_UNDERSCORE; + case 'c': + (void)input_stack::get(NULL); + return ESCAPE_c; + case '!': + (void)input_stack::get(NULL); + return ESCAPE_BANG; + case '?': + (void)input_stack::get(NULL); + return ESCAPE_QUESTION; + case '&': + (void)input_stack::get(NULL); + return ESCAPE_AMPERSAND; + case ')': + (void)input_stack::get(NULL); + return ESCAPE_RIGHT_PARENTHESIS; + case '.': + (void)input_stack::get(NULL); + return c; + case '%': + (void)input_stack::get(NULL); + return ESCAPE_PERCENT; + default: + if (c == escape_char) { + (void)input_stack::get(NULL); + return c; + } + else + return escape_char; + } + } +} + +class non_interpreted_char_node : public node { + unsigned char c; +public: + non_interpreted_char_node(unsigned char); + node *copy(); + int interpret(macro *); + int same(node *); + const char *type(); +}; + +int non_interpreted_char_node::same(node *nd) +{ + return c == ((non_interpreted_char_node *)nd)->c; +} + +const char *non_interpreted_char_node::type() +{ + return "non_interpreted_char_node"; +} + +non_interpreted_char_node::non_interpreted_char_node(unsigned char n) : c(n) +{ + assert(n != 0); +} + +node *non_interpreted_char_node::copy() +{ + return new non_interpreted_char_node(c); +} + +int non_interpreted_char_node::interpret(macro *mac) +{ + mac->append(c); + return 1; +} + +static void do_width(); +static node *do_non_interpreted(); +static node *do_special(); +static void do_register(); + +static node *do_overstrike() +{ + token start; + overstrike_node *on = new overstrike_node; + start.next(); + tok.next(); + while (tok != start) { + if (tok.newline() || tok.eof()) { + warning(WARN_DELIM, "missing closing delimiter"); + break; + } + charinfo *ci = tok.get_char(1); + if (ci) { + node *n = curenv->make_char_node(ci); + if (n) + on->overstrike(n); + } + tok.next(); + } + return on; +} + +static node *do_bracket() +{ + token start; + bracket_node *bn = new bracket_node; + start.next(); + tok.next(); + while (tok != start) { + if (tok.eof()) { + warning(WARN_DELIM, "missing closing delimiter"); + break; + } + if (tok.newline()) { + warning(WARN_DELIM, "missing closing delimiter"); + input_stack::push(make_temp_iterator("\n")); + break; + } + charinfo *ci = tok.get_char(1); + if (ci) { + node *n = curenv->make_char_node(ci); + if (n) + bn->bracket(n); + } + tok.next(); + } + return bn; +} + +static int do_name_test() +{ + token start; + start.next(); + int start_level = input_stack::get_level(); + int bad_char = 0; + int some_char = 0; + for (;;) { + tok.next(); + if (tok.newline() || tok.eof()) { + warning(WARN_DELIM, "missing closing delimiter"); + break; + } + if (tok == start + && (compatible_flag || input_stack::get_level() == start_level)) + break; + if (!tok.ch()) + bad_char = 1; + some_char = 1; + } + return some_char && !bad_char; +} + +#if 0 +static node *do_zero_width() +{ + token start; + start.next(); + int start_level = input_stack::get_level(); + environment env(curenv); + environment *oldenv = curenv; + curenv = &env; + for (;;) { + tok.next(); + if (tok.newline() || tok.eof()) { + error("missing closing delimiter"); + break; + } + if (tok == start + && (compatible_flag || input_stack::get_level() == start_level)) + break; + tok.process(); + } + curenv = oldenv; + node *rev = env.extract_output_line(); + node *n = 0; + while (rev) { + node *tem = rev; + rev = rev->next; + tem->next = n; + n = tem; + } + return new zero_width_node(n); +} + +#else + +// It's undesirable for \Z to change environments, because then +// \n(.w won't work as expected. + +static node *do_zero_width() +{ + node *rev = new dummy_node; + token start; + start.next(); + int start_level = input_stack::get_level(); + for (;;) { + tok.next(); + if (tok.newline() || tok.eof()) { + warning(WARN_DELIM, "missing closing delimiter"); + break; + } + if (tok == start + && (compatible_flag || input_stack::get_level() == start_level)) + break; + if (!tok.add_to_node_list(&rev)) + error("illegal token in argument to \\Z"); + } + node *n = 0; + while (rev) { + node *tem = rev; + rev = rev->next; + tem->next = n; + n = tem; + } + return new zero_width_node(n); +} + +#endif + +token_node *node::get_token_node() +{ + return 0; +} + +class token_node : public node { +public: + token tk; + token_node(const token &t); + node *copy(); + token_node *get_token_node(); + int same(node *); + const char *type(); +}; + +token_node::token_node(const token &t) : tk(t) +{ +} + +node *token_node::copy() +{ + return new token_node(tk); +} + +token_node *token_node::get_token_node() +{ + return this; +} + +int token_node::same(node *nd) +{ + return tk == ((token_node *)nd)->tk; +} + +const char *token_node::type() +{ + return "token_node"; +} + +token::token() : nd(0), type(TOKEN_EMPTY) +{ +} + +token::~token() +{ + delete nd; +} + +token::token(const token &t) +: nm(t.nm), c(t.c), val(t.val), dim(t.dim), type(t.type) +{ + // Use two statements to work around bug in SGI C++. + node *tem = t.nd; + nd = tem ? tem->copy() : 0; +} + +void token::operator=(const token &t) +{ + delete nd; + nm = t.nm; + // Use two statements to work around bug in SGI C++. + node *tem = t.nd; + nd = tem ? tem->copy() : 0; + c = t.c; + val = t.val; + dim = t.dim; + type = t.type; +} + +void token::skip() +{ + while (space()) + next(); +} + +int has_arg() +{ + while (tok.space()) + tok.next(); + return !tok.newline(); +} + +void token::make_space() +{ + type = TOKEN_SPACE; +} + +void token::make_newline() +{ + type = TOKEN_NEWLINE; +} + +void token::next() +{ + if (nd) { + delete nd; + nd = 0; + } + units x; + for (;;) { + node *n; + int cc = input_stack::get(&n); + if (cc != escape_char || escape_char == 0) { + handle_normal_char: + switch(cc) { + case EOF: + type = TOKEN_EOF; + return; + case TRANSPARENT_FILE_REQUEST: + case TITLE_REQUEST: + case COPY_FILE_REQUEST: +#ifdef COLUMN + case VJUSTIFY_REQUEST: +#endif /* COLUMN */ + type = TOKEN_REQUEST; + c = cc; + return; + case BEGIN_TRAP: + type = TOKEN_BEGIN_TRAP; + return; + case END_TRAP: + type = TOKEN_END_TRAP; + return; + case LAST_PAGE_EJECTOR: + seen_last_page_ejector = 1; + // fall through + case PAGE_EJECTOR: + type = TOKEN_PAGE_EJECTOR; + return; + case ESCAPE_PERCENT: + ESCAPE_PERCENT: + type = TOKEN_HYPHEN_INDICATOR; + return; + case ESCAPE_SPACE: + ESCAPE_SPACE: + type = TOKEN_NODE; + nd = new space_char_hmotion_node(curenv->get_space_width()); + return; + case ESCAPE_e: + ESCAPE_e: + type = TOKEN_ESCAPE; + return; + case ESCAPE_E: + goto handle_escape_char; + case ESCAPE_BAR: + ESCAPE_BAR: + type = TOKEN_NODE; + nd = new hmotion_node(curenv->get_narrow_space_width()); + return; + case ESCAPE_CIRCUMFLEX: + ESCAPE_CIRCUMFLEX: + type = TOKEN_NODE; + nd = new hmotion_node(curenv->get_half_narrow_space_width()); + return; + case ESCAPE_NEWLINE: + break; + case ESCAPE_LEFT_BRACE: + ESCAPE_LEFT_BRACE: + type = TOKEN_LEFT_BRACE; + return; + case ESCAPE_RIGHT_BRACE: + ESCAPE_RIGHT_BRACE: + type = TOKEN_RIGHT_BRACE; + return; + case ESCAPE_LEFT_QUOTE: + ESCAPE_LEFT_QUOTE: + type = TOKEN_SPECIAL; + nm = symbol("ga"); + return; + case ESCAPE_RIGHT_QUOTE: + ESCAPE_RIGHT_QUOTE: + type = TOKEN_SPECIAL; + nm = symbol("aa"); + return; + case ESCAPE_HYPHEN: + ESCAPE_HYPHEN: + type = TOKEN_SPECIAL; + nm = symbol("-"); + return; + case ESCAPE_UNDERSCORE: + ESCAPE_UNDERSCORE: + type = TOKEN_SPECIAL; + nm = symbol("ul"); + return; + case ESCAPE_c: + ESCAPE_c: + type = TOKEN_INTERRUPT; + return; + case ESCAPE_BANG: + ESCAPE_BANG: + type = TOKEN_TRANSPARENT; + return; + case ESCAPE_QUESTION: + ESCAPE_QUESTION: + nd = do_non_interpreted(); + if (nd) { + type = TOKEN_NODE; + return; + } + break; + case ESCAPE_AMPERSAND: + ESCAPE_AMPERSAND: + type = TOKEN_DUMMY; + return; + case ESCAPE_RIGHT_PARENTHESIS: + ESCAPE_RIGHT_PARENTHESIS: + type = TOKEN_NODE; + nd = new transparent_dummy_node; + return; + case '\b': + type = TOKEN_BACKSPACE; + return; + case ' ': + type = TOKEN_SPACE; + return; + case '\t': + type = TOKEN_TAB; + return; + case '\n': + type = TOKEN_NEWLINE; + return; + case '\001': + type = TOKEN_LEADER; + return; + case 0: + { + assert(n != 0); + token_node *tn = n->get_token_node(); + if (tn) { + *this = tn->tk; + delete tn; + } + else { + nd = n; + type = TOKEN_NODE; + } + } + return; + default: + type = TOKEN_CHAR; + c = cc; + return; + } + } + else { + handle_escape_char: + cc = input_stack::get(NULL); + switch(cc) { + case '(': + nm = read_two_char_escape_name(); + type = TOKEN_SPECIAL; + return; + case EOF: + type = TOKEN_EOF; + error("end of input after escape character"); + return; + case '`': + goto ESCAPE_LEFT_QUOTE; + case '\'': + goto ESCAPE_RIGHT_QUOTE; + case '-': + goto ESCAPE_HYPHEN; + case '_': + goto ESCAPE_UNDERSCORE; + case '%': + goto ESCAPE_PERCENT; + case ' ': + goto ESCAPE_SPACE; + case '0': + nd = new hmotion_node(curenv->get_digit_width()); + type = TOKEN_NODE; + return; + case '|': + goto ESCAPE_BAR; + case '^': + goto ESCAPE_CIRCUMFLEX; + case '/': + type = TOKEN_ITALIC_CORRECTION; + return; + case ',': + type = TOKEN_NODE; + nd = new left_italic_corrected_node; + return; + case '&': + goto ESCAPE_AMPERSAND; + case ')': + goto ESCAPE_RIGHT_PARENTHESIS; + case '!': + goto ESCAPE_BANG; + case '?': + goto ESCAPE_QUESTION; + case '~': + nd = new unbreakable_space_node(curenv->get_space_width()); + type = TOKEN_NODE; + return; + case '"': + while ((cc = input_stack::get(NULL)) != '\n' && cc != EOF) + ; + if (cc == '\n') + type = TOKEN_NEWLINE; + else + type = TOKEN_EOF; + return; + case '#': // Like \" but newline is ignored. + while ((cc = input_stack::get(NULL)) != '\n') + if (cc == EOF) { + type = TOKEN_EOF; + return; + } + break; + case '$': + { + symbol nm = read_escape_name(); + if (!nm.is_null()) + interpolate_arg(nm); + break; + } + case '*': + { + symbol nm = read_escape_name(); + if (!nm.is_null()) + interpolate_string(nm); + break; + } + case 'a': + nd = new non_interpreted_char_node('\001'); + type = TOKEN_NODE; + return; + case 'A': + c = '0' + do_name_test(); + type = TOKEN_CHAR; + return; + case 'b': + nd = do_bracket(); + type = TOKEN_NODE; + return; + case 'c': + goto ESCAPE_c; + case 'C': + nm = get_delim_name(); + if (nm.is_null()) + break; + type = TOKEN_SPECIAL; + return; + case 'd': + type = TOKEN_NODE; + nd = new vmotion_node(curenv->get_size()/2); + return; + case 'D': + nd = read_draw_node(); + if (!nd) + break; + type = TOKEN_NODE; + return; + case 'e': + goto ESCAPE_e; + case 'E': + goto handle_escape_char; + case 'f': + { + symbol s = read_escape_name(); + if (s.is_null()) + break; + for (const char *p = s.contents(); *p != '\0'; p++) + if (!csdigit(*p)) + break; + if (*p) + curenv->set_font(s); + else + curenv->set_font(atoi(s.contents())); + break; + } + case 'g': + { + symbol s = read_escape_name(); + if (!s.is_null()) + interpolate_number_format(s); + break; + } + case 'h': + if (!get_delim_number(&x, 'm')) + break; + type = TOKEN_NODE; + nd = new hmotion_node(x); + return; + case 'H': + if (get_delim_number(&x, 'z', curenv->get_requested_point_size())) + curenv->set_char_height(x); + break; + case 'k': + nm = read_escape_name(); + if (nm.is_null()) + break; + type = TOKEN_MARK_INPUT; + return; + case 'l': + case 'L': + { + charinfo *s = 0; + if (!get_line_arg(&x, (cc == 'l' ? 'm': 'v'), &s)) + break; + if (s == 0) + s = get_charinfo(cc == 'l' ? "ru" : "br"); + type = TOKEN_NODE; + node *n = curenv->make_char_node(s); + if (cc == 'l') + nd = new hline_node(x, n); + else + nd = new vline_node(x, n); + return; + } + case 'n': + { + int inc; + symbol nm = read_increment_and_escape_name(&inc); + if (!nm.is_null()) + interpolate_number_reg(nm, inc); + break; + } + case 'N': + if (!get_delim_number(&val, 0)) + break; + type = TOKEN_NUMBERED_CHAR; + return; + case 'o': + nd = do_overstrike(); + type = TOKEN_NODE; + return; + case 'p': + type = TOKEN_SPREAD; + return; + case 'r': + type = TOKEN_NODE; + nd = new vmotion_node(-curenv->get_size()); + return; + case 'R': + do_register(); + break; + case 's': + if (read_size(&x)) + curenv->set_size(x); + break; + case 'S': + if (get_delim_number(&x, 0)) + curenv->set_char_slant(x); + break; + case 't': + type = TOKEN_NODE; + nd = new non_interpreted_char_node('\t'); + return; + case 'u': + type = TOKEN_NODE; + nd = new vmotion_node(-curenv->get_size()/2); + return; + case 'v': + if (!get_delim_number(&x, 'v')) + break; + type = TOKEN_NODE; + nd = new vmotion_node(x); + return; + case 'V': + { + symbol nm = read_escape_name(); + if (!nm.is_null()) + interpolate_environment_variable(nm); + break; + } + case 'w': + do_width(); + break; + case 'x': + if (!get_delim_number(&x, 'v')) + break; + type = TOKEN_NODE; + nd = new extra_size_node(x); + return; + case 'X': + nd = do_special(); + if (!nd) + break; + type = TOKEN_NODE; + return; + case 'Y': + { + symbol s = read_escape_name(); + if (s.is_null()) + break; + request_or_macro *p = lookup_request(s); + macro *m = p->to_macro(); + if (!m) { + error("can't transparently throughput a request"); + break; + } + nd = new special_node(*m); + type = TOKEN_NODE; + return; + } + case 'z': + { + next(); + if (type == TOKEN_NODE) + nd = new zero_width_node(nd); + else { + charinfo *ci = get_char(1); + if (ci == 0) + break; + node *gn = curenv->make_char_node(ci); + if (gn == 0) + break; + nd = new zero_width_node(gn); + type = TOKEN_NODE; + } + return; + } + case 'Z': + nd = do_zero_width(); + if (nd == 0) + break; + type = TOKEN_NODE; + return; + case '{': + goto ESCAPE_LEFT_BRACE; + case '}': + goto ESCAPE_RIGHT_BRACE; + case '\n': + break; + case '[': + if (!compatible_flag) { + nm = read_long_escape_name(); + if (nm.is_null()) + break; + type = TOKEN_SPECIAL; + return; + } + goto handle_normal_char; + default: + if (cc != escape_char && cc != '.') + warning(WARN_ESCAPE, "escape character ignored before %1", + input_char_description(cc)); + goto handle_normal_char; + } + } + } +} + +int token::operator==(const token &t) +{ + if (type != t.type) + return 0; + switch(type) { + case TOKEN_CHAR: + return c == t.c; + case TOKEN_SPECIAL: + return nm == t.nm; + case TOKEN_NUMBERED_CHAR: + return val == t.val; + default: + return 1; + } +} + +int token::operator!=(const token &t) +{ + return !(*this == t); +} + +// is token a suitable delimiter (like ')? + +int token::delimiter(int err) +{ + switch(type) { + case TOKEN_CHAR: + switch(c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case '/': + case '*': + case '%': + case '<': + case '>': + case '=': + case '&': + case ':': + case '(': + case ')': + case '.': + if (err) + error("cannot use character `%1' as a starting delimiter", char(c)); + return 0; + default: + return 1; + } + case TOKEN_NODE: + case TOKEN_SPACE: + case TOKEN_TAB: + case TOKEN_NEWLINE: + if (err) + error("cannot use %1 as a starting delimiter", description()); + return 0; + default: + return 1; + } +} + +const char *token::description() +{ + static char buf[4]; + switch (type) { + case TOKEN_BACKSPACE: + return "a backspace character"; + case TOKEN_CHAR: + buf[0] = '`'; + buf[1] = c; + buf[2] = '\''; + buf[3] = '\0'; + return buf; + case TOKEN_DUMMY: + return "`\\&'"; + case TOKEN_ESCAPE: + return "`\\e'"; + case TOKEN_HYPHEN_INDICATOR: + return "`\\%'"; + case TOKEN_INTERRUPT: + return "`\\c'"; + case TOKEN_ITALIC_CORRECTION: + return "`\\/'"; + case TOKEN_LEADER: + return "a leader character"; + case TOKEN_LEFT_BRACE: + return "`\\{'"; + case TOKEN_MARK_INPUT: + return "`\\k'"; + case TOKEN_NEWLINE: + return "newline"; + case TOKEN_NODE: + return "a node"; + case TOKEN_NUMBERED_CHAR: + return "`\\N'"; + case TOKEN_RIGHT_BRACE: + return "`\\}'"; + case TOKEN_SPACE: + return "a space"; + case TOKEN_SPECIAL: + return "a special character"; + case TOKEN_SPREAD: + return "`\\p'"; + case TOKEN_TAB: + return "a tab character"; + case TOKEN_TRANSPARENT: + return "`\\!'"; + case TOKEN_EOF: + return "end of input"; + default: + break; + } + return "a magic token"; +} + +void skip_line() +{ + while (!tok.newline()) + if (tok.eof()) + return; + else + tok.next(); + tok.next(); +} + +void compatible() +{ + int n; + if (has_arg() && get_integer(&n)) + compatible_flag = n != 0; + else + compatible_flag = 1; + skip_line(); +} + +static void empty_name_warning(int required) +{ + if (tok.newline() || tok.eof()) { + if (required) + warning(WARN_MISSING, "missing name"); + } + else if (tok.right_brace() || tok.tab()) { + const char *start = tok.description(); + do { + tok.next(); + } while (tok.space() || tok.right_brace() || tok.tab()); + if (!tok.newline() && !tok.eof()) + error("%1 is not allowed before an argument", start); + else if (required) + warning(WARN_MISSING, "missing name"); + } + else if (required) + error("name expected (got %1)", tok.description()); + else + error("name expected (got %1): treated as missing", tok.description()); +} + +static void non_empty_name_warning() +{ + if (!tok.newline() && !tok.eof() && !tok.space() && !tok.tab() + && !tok.right_brace() + // We don't want to give a warning for .el\{ + && !tok.left_brace()) + error("%1 is not allowed in a name", tok.description()); +} + +symbol get_name(int required) +{ + if (compatible_flag) { + char buf[3]; + tok.skip(); + if ((buf[0] = tok.ch()) != 0) { + tok.next(); + if ((buf[1] = tok.ch()) != 0) { + buf[2] = 0; + tok.make_space(); + } + else + non_empty_name_warning(); + return symbol(buf); + } + else { + empty_name_warning(required); + return NULL_SYMBOL; + } + } + else + return get_long_name(required); +} + +symbol get_long_name(int required) +{ + while (tok.space()) + tok.next(); + char abuf[ABUF_SIZE]; + char *buf = abuf; + int buf_size = ABUF_SIZE; + int i = 0; + for (;;) { + if (i + 1 > buf_size) { + if (buf == abuf) { + buf = new char [ABUF_SIZE*2]; + memcpy(buf, abuf, buf_size); + buf_size = ABUF_SIZE*2; + } + else { + char *old_buf = buf; + buf = new char[buf_size*2]; + memcpy(buf, old_buf, buf_size); + buf_size *= 2; + a_delete old_buf; + } + } + if ((buf[i] = tok.ch()) == 0) + break; + i++; + tok.next(); + } + if (i == 0) { + empty_name_warning(required); + return NULL_SYMBOL; + } + non_empty_name_warning(); + if (buf == abuf) + return symbol(buf); + else { + symbol s(buf); + a_delete buf; + return s; + } +} + +NO_RETURN void exit_troff() +{ + exit_started = 1; + topdiv->set_last_page(); + if (!end_macro_name.is_null()) { + spring_trap(end_macro_name); + tok.next(); + process_input_stack(); + } + curenv->final_break(); + tok.next(); + process_input_stack(); + end_diversions(); + done_end_macro = 1; + topdiv->set_ejecting(); + static unsigned char buf[2] = { LAST_PAGE_EJECTOR, '\0' }; + input_stack::push(make_temp_iterator((char *)buf)); + topdiv->space(topdiv->get_page_length(), 1); + tok.next(); + process_input_stack(); + seen_last_page_ejector = 1; // should be set already + topdiv->set_ejecting(); + push_page_ejector(); + topdiv->space(topdiv->get_page_length(), 1); + tok.next(); + process_input_stack(); + // This will only happen if a trap-invoked macro starts a diversion, + // or if vertical position traps have been disabled. + cleanup_and_exit(0); +} + +// This implements .ex. The input stack must be cleared before calling +// exit_troff(). + +void exit_request() +{ + input_stack::clear(); + if (exit_started) + tok.next(); + else + exit_troff(); +} + +void end_macro() +{ + end_macro_name = get_name(); + skip_line(); +} + +void do_request() +{ + int saved_compatible_flag = compatible_flag; + compatible_flag = 0; + symbol nm = get_name(); + if (nm.is_null()) + skip_line(); + else + interpolate_macro(nm); + compatible_flag = saved_compatible_flag; +} + +inline int possibly_handle_first_page_transition() +{ + if (topdiv->before_first_page && curdiv == topdiv && !curenv->is_dummy()) { + handle_first_page_transition(); + return 1; + } + else + return 0; +} + +static int transparent_translate(int cc) +{ + if (!illegal_input_char(cc)) { + charinfo *ci = charset_table[cc]; + switch (ci->get_special_translation(1)) { + case charinfo::TRANSLATE_SPACE: + return ' '; + case charinfo::TRANSLATE_DUMMY: + return ESCAPE_AMPERSAND; + case charinfo::TRANSLATE_HYPHEN_INDICATOR: + return ESCAPE_PERCENT; + } + // This is realy ugly. + ci = ci->get_translation(1); + if (ci) { + int c = ci->get_ascii_code(); + if (c != '\0') + return c; + error("can't translate %1 to special character `%2'" + " in transparent throughput", + input_char_description(cc), + ci->nm.contents()); + } + } + return cc; +} + +class int_stack { + struct int_stack_element { + int n; + int_stack_element *next; + } *top; +public: + int_stack(); + ~int_stack(); + void push(int); + int is_empty(); + int pop(); +}; + +int_stack::int_stack() +{ + top = 0; +} + +int_stack::~int_stack() +{ + while (top != 0) { + int_stack_element *temp = top; + top = top->next; + delete temp; + } + +} + +int int_stack::is_empty() +{ + return top == 0; +} + +void int_stack::push(int n) +{ + int_stack_element *p = new int_stack_element; + p->next = top; + p->n = n; + top = p; +} + + +int int_stack::pop() +{ + assert(top != 0); + int_stack_element *p = top; + top = top->next; + int n = p->n; + delete p; + return n; +} + +int node::reread(int *) +{ + return 0; +} + +int diverted_space_node::reread(int *bolp) +{ + if (curenv->get_fill()) + blank_line(); + else + curdiv->space(n); + *bolp = 1; + return 1; +} + +int diverted_copy_file_node::reread(int *bolp) +{ + curdiv->copy_file(filename.contents()); + *bolp = 1; + return 1; +} + +static void process_input_stack() +{ + int_stack trap_bol_stack; + int bol = 1; + for (;;) { + int suppress_next = 0; + switch (tok.type) { + case token::TOKEN_CHAR: + { + unsigned char ch = tok.c; + if (bol && + (ch == curenv->control_char + || ch == curenv->no_break_control_char)) { + break_flag = ch == curenv->control_char; + // skip tabs as well as spaces here + do { + tok.next(); + } while (tok.white_space()); + symbol nm = get_name(); + if (nm.is_null()) + skip_line(); + else + interpolate_macro(nm); + suppress_next = 1; + } + else { + if (possibly_handle_first_page_transition()) + ; + else { + for (;;) { + curenv->add_char(charset_table[ch]); + tok.next(); + if (tok.type != token::TOKEN_CHAR) + break; + ch = tok.c; + } + suppress_next = 1; + bol = 0; + } + } + break; + } + case token::TOKEN_TRANSPARENT: + { + if (bol) { + if (possibly_handle_first_page_transition()) + ; + else { + int cc; + do { + node *n; + cc = get_copy(&n); + if (cc != EOF) + if (cc != '\0') + curdiv->transparent_output(transparent_translate(cc)); + else + curdiv->transparent_output(n); + } while (cc != '\n' && cc != EOF); + if (cc == EOF) + curdiv->transparent_output('\n'); + } + } + break; + } + case token::TOKEN_NEWLINE: + { + if (bol && !curenv->get_prev_line_interrupted()) + blank_line(); + else { + curenv->newline(); + bol = 1; + } + break; + } + case token::TOKEN_REQUEST: + { + int request_code = tok.c; + tok.next(); + switch (request_code) { + case TITLE_REQUEST: + title(); + break; + case COPY_FILE_REQUEST: + copy_file(); + break; + case TRANSPARENT_FILE_REQUEST: + transparent_file(); + break; +#ifdef COLUMN + case VJUSTIFY_REQUEST: + vjustify(); + break; +#endif /* COLUMN */ + default: + assert(0); + break; + } + suppress_next = 1; + break; + } + case token::TOKEN_SPACE: + { + if (possibly_handle_first_page_transition()) + ; + else if (bol && !curenv->get_prev_line_interrupted()) { + int nspaces = 0; + do { + nspaces += tok.nspaces(); + tok.next(); + } while (tok.space()); + if (tok.newline()) + blank_line(); + else { + push_token(tok); + curenv->do_break(); + curenv->add_node(new hmotion_node(curenv->get_space_width()*nspaces)); + bol = 0; + } + } + else { + curenv->space(); + bol = 0; + } + break; + } + case token::TOKEN_EOF: + return; + case token::TOKEN_NODE: + { + if (possibly_handle_first_page_transition()) + ; + else if (tok.nd->reread(&bol)) { + delete tok.nd; + tok.nd = 0; + } + else { + curenv->add_node(tok.nd); + tok.nd = 0; + bol = 0; + } + break; + } + case token::TOKEN_PAGE_EJECTOR: + { + continue_page_eject(); + // I think we just want to preserve bol. + // bol = 1; + break; + } + case token::TOKEN_BEGIN_TRAP: + { + trap_bol_stack.push(bol); + bol = 1; + break; + } + case token::TOKEN_END_TRAP: + { + if (trap_bol_stack.is_empty()) + error("spurious end trap token detected!"); + else + bol = trap_bol_stack.pop(); + + /* I'm not totally happy about this. But I can't think of any other + way to do it. Doing an output_pending_lines() whenever a + TOKEN_END_TRAP is detected doesn't work: for example, + + .wh -1i x + .de x + 'bp + .. + .wh -.5i y + .de y + .tl ''-%-'' + .. + .br + .ll .5i + .sp |\n(.pu-1i-.5v + a\%very\%very\%long\%word + + will print all but the first lines from the word immediately + after the footer, rather than on the next page. */ + + if (trap_bol_stack.is_empty()) + curenv->output_pending_lines(); + break; + } + default: + { + bol = 0; + tok.process(); + break; + } + } + if (!suppress_next) + tok.next(); + trap_sprung_flag = 0; + } +} + +#ifdef WIDOW_CONTROL + +void flush_pending_lines() +{ + while (!tok.newline() && !tok.eof()) + tok.next(); + curenv->output_pending_lines(); + tok.next(); +} + +#endif /* WIDOW_CONTROL */ + +request_or_macro::request_or_macro() +{ +} + +macro *request_or_macro::to_macro() +{ + return 0; +} + +request::request(REQUEST_FUNCP pp) : p(pp) +{ +} + +void request::invoke(symbol) +{ + (*p)(); +} + +struct char_block { + enum { SIZE = 128 }; + unsigned char s[SIZE]; + char_block *next; + char_block(); +}; + +char_block::char_block() +: next(0) +{ +} + +class char_list { +public: + char_list(); + ~char_list(); + void append(unsigned char); + int length(); +private: + unsigned char *ptr; + int len; + char_block *head; + char_block *tail; + friend class macro_header; + friend class string_iterator; +}; + +char_list::char_list() +: head(0), tail(0), ptr(0), len(0) +{ +} + +char_list::~char_list() +{ + while (head != 0) { + char_block *tem = head; + head = head->next; + delete tem; + } +} + +int char_list::length() +{ + return len; +} + +void char_list::append(unsigned char c) +{ + if (tail == 0) { + head = tail = new char_block; + ptr = tail->s; + } + else { + if (ptr >= tail->s + char_block::SIZE) { + tail->next = new char_block; + tail = tail->next; + ptr = tail->s; + } + } + *ptr++ = c; + len++; +} + +class node_list { + node *head; + node *tail; +public: + node_list(); + ~node_list(); + void append(node *); + int length(); + node *extract(); + + friend class macro_header; + friend class string_iterator; +}; + +void node_list::append(node *n) +{ + if (head == 0) { + n->next = 0; + head = tail = n; + } + else { + n->next = 0; + tail = tail->next = n; + } +} + +int node_list::length() +{ + int total = 0; + for (node *n = head; n != 0; n = n->next) + ++total; + return total; +} + +node_list::node_list() +{ + head = tail = 0; +} + +node *node_list::extract() +{ + node *temp = head; + head = tail = 0; + return temp; +} + + +node_list::~node_list() +{ + delete_node_list(head); +} + +struct macro_header { + int count; + char_list cl; + node_list nl; + macro_header() { count = 1; } + macro_header *copy(int); +}; + + +macro::~macro() +{ + if (p != 0 && --(p->count) <= 0) + delete p; +} + +macro::macro() +{ + if (!input_stack::get_location(1, &filename, &lineno)) { + filename = 0; + lineno = 0; + } + length = 0; + p = 0; +} + +macro::macro(const macro &m) +: filename(m.filename), lineno(m.lineno), p(m.p), length(m.length) +{ + if (p != 0) + p->count++; +} + +macro ¯o::operator=(const macro &m) +{ + // don't assign object + if (m.p != 0) + m.p->count++; + if (p != 0 && --(p->count) <= 0) + delete p; + p = m.p; + filename = m.filename; + lineno = m.lineno; + length = m.length; + return *this; +} + +void macro::append(unsigned char c) +{ + assert(c != 0); + if (p == 0) + p = new macro_header; + if (p->cl.length() != length) { + macro_header *tem = p->copy(length); + if (--(p->count) <= 0) + delete p; + p = tem; + } + p->cl.append(c); + ++length; +} + +void macro::append(node *n) +{ + assert(n != 0); + if (p == 0) + p = new macro_header; + if (p->cl.length() != length) { + macro_header *tem = p->copy(length); + if (--(p->count) <= 0) + delete p; + p = tem; + } + p->cl.append(0); + p->nl.append(n); + ++length; +} + +void macro::print_size() +{ + errprint("%1", length); +} + +// make a copy of the first n bytes + +macro_header *macro_header::copy(int n) +{ + macro_header *p = new macro_header; + char_block *bp = cl.head; + unsigned char *ptr = bp->s; + node *nd = nl.head; + while (--n >= 0) { + if (ptr >= bp->s + char_block::SIZE) { + bp = bp->next; + ptr = bp->s; + } + int c = *ptr++; + p->cl.append(c); + if (c == 0) { + p->nl.append(nd->copy()); + nd = nd->next; + } + } + return p; +} + +void print_macros() +{ + object_dictionary_iterator iter(request_dictionary); + request_or_macro *rm; + symbol s; + while (iter.get(&s, (object **)&rm)) { + assert(!s.is_null()); + macro *m = rm->to_macro(); + if (m) { + errprint("%1\t", s.contents()); + m->print_size(); + errprint("\n"); + } + } + fflush(stderr); + skip_line(); +} + +class string_iterator : public input_iterator { + macro mac; + const char *how_invoked; + int newline_flag; + int lineno; + char_block *bp; + int count; // of characters remaining + node *nd; +protected: + symbol nm; + string_iterator(); +public: + string_iterator(const macro &m, const char *p = 0, symbol s = NULL_SYMBOL); + int fill(node **); + int peek(); + int get_location(int, const char **, int *); + void backtrace(); +}; + +string_iterator::string_iterator(const macro &m, const char *p, symbol s) +: lineno(1), mac(m), newline_flag(0), how_invoked(p), nm(s) +{ + count = mac.length; + if (count != 0) { + bp = mac.p->cl.head; + nd = mac.p->nl.head; + ptr = eptr = bp->s; + } + else { + bp = 0; + nd = 0; + ptr = eptr = 0; + } +} + +string_iterator::string_iterator() +{ + bp = 0; + nd = 0; + ptr = eptr = 0; + newline_flag = 0; + how_invoked = 0; + lineno = 1; + count = 0; +} + +int string_iterator::fill(node **np) +{ + if (newline_flag) + lineno++; + newline_flag = 0; + if (count <= 0) + return EOF; + const unsigned char *p = eptr; + if (p >= bp->s + char_block::SIZE) { + bp = bp->next; + p = bp->s; + } + if (*p == '\0') { + if (np) + *np = nd->copy(); + nd = nd->next; + eptr = ptr = p + 1; + count--; + return 0; + } + const unsigned char *e = bp->s + char_block::SIZE; + if (e - p > count) + e = p + count; + ptr = p; + while (p < e) { + unsigned char c = *p; + if (c == '\n' || c == ESCAPE_NEWLINE) { + newline_flag = 1; + p++; + break; + } + if (c == '\0') + break; + p++; + } + eptr = p; + count -= p - ptr; + return *ptr++; +} + +int string_iterator::peek() +{ + if (count <= 0) + return EOF; + const unsigned char *p = eptr; + if (count <= 0) + return EOF; + if (p >= bp->s + char_block::SIZE) { + p = bp->next->s; + } + return *p; +} + +int string_iterator::get_location(int allow_macro, + const char **filep, int *linep) +{ + if (!allow_macro) + return 0; + if (mac.filename == 0) + return 0; + *filep = mac.filename; + *linep = mac.lineno + lineno - 1; + return 1; +} + +void string_iterator::backtrace() +{ + if (mac.filename) { + errprint("%1:%2: backtrace", mac.filename, mac.lineno + lineno - 1); + if (how_invoked) { + if (!nm.is_null()) + errprint(": %1 `%2'\n", how_invoked, nm.contents()); + else + errprint(": %1\n", how_invoked); + } + else + errprint("\n"); + } +} + +class temp_iterator : public input_iterator { + unsigned char *base; + temp_iterator(const char *, int len); +public: + ~temp_iterator(); + friend input_iterator *make_temp_iterator(const char *); +}; + +#ifdef __GNUG__ +inline +#endif +temp_iterator::temp_iterator(const char *s, int len) +{ + base = new unsigned char[len]; + memcpy(base, s, len); + ptr = base; + eptr = base + len; +} + +temp_iterator::~temp_iterator() +{ + a_delete base; +} + +class small_temp_iterator : public input_iterator { +private: + small_temp_iterator(const char *, int); + ~small_temp_iterator(); + enum { BLOCK = 16 }; + static small_temp_iterator *free_list; + void *operator new(size_t); + void operator delete(void *); + enum { SIZE = 12 }; + unsigned char buf[SIZE]; + friend input_iterator *make_temp_iterator(const char *); +}; + +small_temp_iterator *small_temp_iterator::free_list = 0; + +void *small_temp_iterator::operator new(size_t n) +{ + assert(n == sizeof(small_temp_iterator)); + if (!free_list) { + free_list = (small_temp_iterator *)new char[sizeof(small_temp_iterator)*BLOCK]; + for (int i = 0; i < BLOCK - 1; i++) + free_list[i].next = free_list + i + 1; + free_list[BLOCK-1].next = 0; + } + small_temp_iterator *p = free_list; + free_list = (small_temp_iterator *)(free_list->next); + p->next = 0; + return p; +} + +#ifdef __GNUG__ +inline +#endif +void small_temp_iterator::operator delete(void *p) +{ + if (p) { + ((small_temp_iterator *)p)->next = free_list; + free_list = (small_temp_iterator *)p; + } +} + +small_temp_iterator::~small_temp_iterator() +{ +} + + +#ifdef __GNUG__ +inline +#endif +small_temp_iterator::small_temp_iterator(const char *s, int len) +{ + for (int i = 0; i < len; i++) + buf[i] = s[i]; + ptr = buf; + eptr = buf + len; +} + +input_iterator *make_temp_iterator(const char *s) +{ + if (s == 0) + return new small_temp_iterator(s, 0); + else { + int n = strlen(s); + if (n <= small_temp_iterator::SIZE) + return new small_temp_iterator(s, n); + else + return new temp_iterator(s, n); + } +} + +// this is used when macros are interpolated using the .macro_name notation + +struct arg_list { + macro mac; + arg_list *next; + arg_list(const macro &); + ~arg_list(); +}; + +arg_list::arg_list(const macro &m) : mac(m), next(0) +{ +} + +arg_list::~arg_list() +{ +} + +class macro_iterator : public string_iterator { + arg_list *args; + int argc; +public: + macro_iterator(symbol, macro &); + macro_iterator(); + ~macro_iterator(); + int has_args() { return 1; } + input_iterator *get_arg(int i); + int nargs() { return argc; } + void add_arg(const macro &m); + void shift(int n); +}; + +input_iterator *macro_iterator::get_arg(int i) +{ + if (i == 0) + return make_temp_iterator(nm.contents()); + if (i > 0 && i <= argc) { + arg_list *p = args; + for (int j = 1; j < i; j++) { + assert(p != 0); + p = p->next; + } + return new string_iterator(p->mac); + } + else + return 0; +} + +void macro_iterator::add_arg(const macro &m) +{ + for (arg_list **p = &args; *p; p = &((*p)->next)) + ; + *p = new arg_list(m); + ++argc; +} + +void macro_iterator::shift(int n) +{ + while (n > 0 && argc > 0) { + arg_list *tem = args; + args = args->next; + delete tem; + --argc; + --n; + } +} + +// This gets used by eg .if '\?xxx\?''. + +int operator==(const macro &m1, const macro &m2) +{ + if (m1.length != m2.length) + return 0; + string_iterator iter1(m1); + string_iterator iter2(m2); + int n = m1.length; + while (--n >= 0) { + node *nd1 = 0; + int c1 = iter1.get(&nd1); + assert(c1 != EOF); + node *nd2 = 0; + int c2 = iter2.get(&nd2); + assert(c2 != EOF); + if (c1 != c2) { + if (c1 == 0) + delete nd1; + else if (c2 == 0) + delete nd2; + return 0; + } + if (c1 == 0) { + assert(nd1 != 0); + assert(nd2 != 0); + int are_same = nd1->type() == nd2->type() && nd1->same(nd2); + delete nd1; + delete nd2; + if (!are_same) + return 0; + } + } + return 1; +} + +static void interpolate_macro(symbol nm) +{ + request_or_macro *p = (request_or_macro *)request_dictionary.lookup(nm); + if (p == 0) { + int warned = 0; + const char *s = nm.contents(); + if (strlen(s) > 2) { + request_or_macro *r; + char buf[3]; + buf[0] = s[0]; + buf[1] = s[1]; + buf[2] = '\0'; + r = (request_or_macro *)request_dictionary.lookup(symbol(buf)); + if (r) { + macro *m = r->to_macro(); + if (!m || !m->empty()) + warned = warning(WARN_SPACE, + "space required between `%1' and argument", buf); + } + } + if (!warned) { + warning(WARN_MAC, "`%1' not defined", nm.contents()); + p = new macro; + request_dictionary.define(nm, p); + } + } + if (p) + p->invoke(nm); + else { + skip_line(); + return; + } +} + +static void decode_args(macro_iterator *mi) +{ + if (!tok.newline() && !tok.eof()) { + node *n; + int c = get_copy(&n); + for (;;) { + while (c == ' ') + c = get_copy(&n); + if (c == '\n' || c == EOF) + break; + macro arg; + int quote_input_level = 0; + if (c == '\"') { + quote_input_level = input_stack::get_level(); + c = get_copy(&n); + } + while (c != EOF && c != '\n' && !(c == ' ' && quote_input_level == 0)) { + if (quote_input_level > 0 && c == '\"' + && (compatible_flag + || input_stack::get_level() == quote_input_level)) { + c = get_copy(&n); + if (c == '"') { + arg.append(c); + c = get_copy(&n); + } + else + break; + } + else { + if (c == 0) + arg.append(n); + else + arg.append(c); + c = get_copy(&n); + } + } + mi->add_arg(arg); + } + } +} + +void macro::invoke(symbol nm) +{ + macro_iterator *mi = new macro_iterator(nm, *this); + decode_args(mi); + input_stack::push(mi); + tok.next(); +} + +macro *macro::to_macro() +{ + return this; +} + +int macro::empty() +{ + return length == 0; +} + +macro_iterator::macro_iterator(symbol s, macro &m) +: string_iterator(m, "macro", s), args(0), argc(0) +{ +} + +macro_iterator::macro_iterator() : args(0), argc(0) +{ +} + +macro_iterator::~macro_iterator() +{ + while (args != 0) { + arg_list *tem = args; + args = args->next; + delete tem; + } +} + +void read_request() +{ + macro_iterator *mi = new macro_iterator; + int had_prompt = 0; + if (!tok.newline() && !tok.eof()) { + int c = get_copy(NULL); + while (c == ' ') + c = get_copy(NULL); + while (c != EOF && c != '\n' && c != ' ') { + if (!illegal_input_char(c)) { + fputc(c, stderr); + had_prompt = 1; + } + c = get_copy(NULL); + } + if (c == ' ') { + tok.make_space(); + decode_args(mi); + } + } + fputc(had_prompt ? ':' : '\007', stderr); + fflush(stderr); + input_stack::push(mi); + macro mac; + int nl = 0; + int c; + while ((c = getchar()) != EOF) { + if (illegal_input_char(c)) + warning(WARN_INPUT, "illegal input character code %1", int(c)); + else { + if (c == '\n') { + if (nl) + break; + else + nl = 1; + } + else + nl = 0; + mac.append(c); + } + } + input_stack::push(new string_iterator(mac)); + tok.next(); +} + + +void do_define_string(int append) +{ + symbol nm; + node *n; + int c; + nm = get_name(1); + if (nm.is_null()) { + skip_line(); + return; + } + if (tok.newline()) + c = '\n'; + else if (tok.tab()) + c = '\t'; + else if (!tok.space()) { + error("bad string definition"); + skip_line(); + return; + } + else + c = get_copy(&n); + while (c == ' ') + c = get_copy(&n); + if (c == '"') + c = get_copy(&n); + macro mac; + request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm); + macro *mm = rm ? rm->to_macro() : 0; + if (append && mm) + mac = *mm; + while (c != '\n' && c != EOF) { + if (c == 0) + mac.append(n); + else + mac.append((unsigned char)c); + c = get_copy(&n); + } + if (!mm) { + mm = new macro; + request_dictionary.define(nm, mm); + } + *mm = mac; + tok.next(); +} + +void define_string() +{ + do_define_string(0); +} + +void append_string() +{ + do_define_string(1); +} + +void define_character() +{ + node *n; + int c; + tok.skip(); + charinfo *ci = tok.get_char(1); + if (ci == 0) { + skip_line(); + return; + } + tok.next(); + if (tok.newline()) + c = '\n'; + else if (tok.tab()) + c = '\t'; + else if (!tok.space()) { + error("bad character definition"); + skip_line(); + return; + } + else + c = get_copy(&n); + while (c == ' ' || c == '\t') + c = get_copy(&n); + if (c == '"') + c = get_copy(&n); + macro *m = new macro; + while (c != '\n' && c != EOF) { + if (c == 0) + m->append(n); + else + m->append((unsigned char)c); + c = get_copy(&n); + } + m = ci->set_macro(m); + if (m) + delete m; + tok.next(); +} + + +static void remove_character() +{ + tok.skip(); + while (!tok.newline() && !tok.eof()) { + if (!tok.space() && !tok.tab()) { + charinfo *ci = tok.get_char(1); + if (!ci) + break; + macro *m = ci->set_macro(0); + if (m) + delete m; + } + tok.next(); + } + skip_line(); +} + +static void interpolate_string(symbol nm) +{ + request_or_macro *p = lookup_request(nm); + macro *m = p->to_macro(); + if (!m) + error("you can only invoke a string using \\*"); + else { + string_iterator *si = new string_iterator(*m, "string", nm); + input_stack::push(si); + } +} + +/* This class is used for the implementation of \$@. It is used for +each of the closing double quotes. It artificially increases the +input level by 2, so that the closing double quote will appear to have +the same input level as the opening quote. */ + +class end_quote_iterator : public input_iterator { + unsigned char buf[1]; +public: + end_quote_iterator(); + ~end_quote_iterator() { } + int internal_level() { return 2; } +}; + +end_quote_iterator::end_quote_iterator() +{ + buf[0] = '"'; + ptr = buf; + eptr = buf + 1; +} + +static void interpolate_arg(symbol nm) +{ + const char *s = nm.contents(); + if (!s || *s == '\0') + error("missing argument name"); + else if (s[1] == 0 && csdigit(s[0])) + input_stack::push(input_stack::get_arg(s[0] - '0')); + else if (s[0] == '*' && s[1] == '\0') { + for (int i = input_stack::nargs(); i > 0; i--) { + input_stack::push(input_stack::get_arg(i)); + if (i != 1) + input_stack::push(make_temp_iterator(" ")); + } + } + else if (s[0] == '@' && s[1] == '\0') { + for (int i = input_stack::nargs(); i > 0; i--) { + input_stack::push(new end_quote_iterator); + input_stack::push(input_stack::get_arg(i)); + input_stack::push(make_temp_iterator(i == 1 ? "\"" : " \"")); + } + } + else { + for (const char *p = s; *p && csdigit(*p); p++) + ; + if (*p) + error("bad argument name `%1'", s); + else + input_stack::push(input_stack::get_arg(atoi(s))); + } +} + +void handle_first_page_transition() +{ + push_token(tok); + topdiv->begin_page(); +} + +// We push back a token by wrapping it up in a token_node, and +// wrapping that up in a string_iterator. + +static void push_token(const token &t) +{ + macro m; + m.append(new token_node(t)); + input_stack::push(new string_iterator(m)); +} + +void push_page_ejector() +{ + static char buf[2] = { PAGE_EJECTOR, '\0' }; + input_stack::push(make_temp_iterator(buf)); +} + +void handle_initial_request(unsigned char code) +{ + char buf[2]; + buf[0] = code; + buf[1] = '\0'; + macro mac; + mac.append(new token_node(tok)); + input_stack::push(new string_iterator(mac)); + input_stack::push(make_temp_iterator(buf)); + topdiv->begin_page(); + tok.next(); +} + +void handle_initial_title() +{ + handle_initial_request(TITLE_REQUEST); +} + +int trap_sprung_flag = 0; +int postpone_traps_flag = 0; +symbol postponed_trap; + +void spring_trap(symbol nm) +{ + assert(!nm.is_null()); + trap_sprung_flag = 1; + if (postpone_traps_flag) { + postponed_trap = nm; + return; + } + static char buf[2] = { BEGIN_TRAP, 0 }; + static char buf2[2] = { END_TRAP, '\0' }; + input_stack::push(make_temp_iterator(buf2)); + request_or_macro *p = lookup_request(nm); + macro *m = p->to_macro(); + if (m) + input_stack::push(new string_iterator(*m, "trap-invoked macro", nm)); + else + error("you can't invoke a request with a trap"); + input_stack::push(make_temp_iterator(buf)); +} + +void postpone_traps() +{ + postpone_traps_flag = 1; +} + +int unpostpone_traps() +{ + postpone_traps_flag = 0; + if (!postponed_trap.is_null()) { + spring_trap(postponed_trap); + postponed_trap = NULL_SYMBOL; + return 1; + } + else + return 0; +} + +// this should be local to define_macro, but cfront 1.2 doesn't support that +static symbol dot_symbol("."); + +enum define_mode { DEFINE_NORMAL, DEFINE_APPEND, DEFINE_IGNORE }; + +void do_define_macro(define_mode mode) +{ + symbol nm; + if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { + nm = get_name(1); + if (nm.is_null()) { + skip_line(); + return; + } + } + symbol term = get_name(); // the request that terminates the definition + if (term.is_null()) + term = dot_symbol; + while (!tok.newline() && !tok.eof()) + tok.next(); + const char *start_filename; + int start_lineno; + int have_start_location = input_stack::get_location(0, &start_filename, + &start_lineno); + node *n; + // doing this here makes the line numbers come out right + int c = get_copy(&n, 1); + macro mac; + macro *mm = 0; + if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { + request_or_macro *rm = + (request_or_macro *)request_dictionary.lookup(nm); + if (rm) + mm = rm->to_macro(); + if (mm && mode == DEFINE_APPEND) + mac = *mm; + } + int bol = 1; + for (;;) { + while (c == ESCAPE_NEWLINE) { + if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) + mac.append(c); + c = get_copy(&n, 1); + } + if (bol && c == '.') { + const char *s = term.contents(); + int d; + // see if it matches term + for (int i = 0; s[i] != 0; i++) { + d = get_copy(&n); + if ((unsigned char)s[i] != d) + break; + } + if (s[i] == 0 + && ((i == 2 && compatible_flag) + || (d = get_copy(&n)) == ' ' + || d == '\n')) { // we found it + if (d == '\n') + tok.make_newline(); + else + tok.make_space(); + if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) { + if (!mm) { + mm = new macro; + request_dictionary.define(nm, mm); + } + *mm = mac; + } + if (term != dot_symbol) + interpolate_macro(term); + else + skip_line(); + return; + } + if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) { + mac.append(c); + for (int j = 0; j < i; j++) + mac.append(s[j]); + } + c = d; + } + if (c == EOF) { + if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { + if (have_start_location) + error_with_file_and_line(start_filename, start_lineno, + "end of file while defining macro `%1'", + nm.contents()); + else + error("end of file while defining macro `%1'", nm.contents()); + } + else { + if (have_start_location) + error_with_file_and_line(start_filename, start_lineno, + "end of file while ignoring input lines"); + else + error("end of file while ignoring input lines"); + } + tok.next(); + return; + } + if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { + if (c == 0) + mac.append(n); + else + mac.append(c); + } + bol = (c == '\n'); + c = get_copy(&n, 1); + } +} + +void define_macro() +{ + do_define_macro(DEFINE_NORMAL); +} + +void append_macro() +{ + do_define_macro(DEFINE_APPEND); +} + +void ignore() +{ + do_define_macro(DEFINE_IGNORE); +} + +void remove_macro() +{ + for (;;) { + symbol s = get_name(); + if (s.is_null()) + break; + request_dictionary.remove(s); + } + skip_line(); +} + +void rename_macro() +{ + symbol s1 = get_name(1); + if (!s1.is_null()) { + symbol s2 = get_name(1); + if (!s2.is_null()) + request_dictionary.rename(s1, s2); + } + skip_line(); +} + +void alias_macro() +{ + symbol s1 = get_name(1); + if (!s1.is_null()) { + symbol s2 = get_name(1); + if (!s2.is_null()) { + if (!request_dictionary.alias(s1, s2)) + warning(WARN_MAC, "`%1' not defined", s2.contents()); + } + } + skip_line(); +} + +void chop_macro() +{ + symbol s = get_name(1); + if (!s.is_null()) { + request_or_macro *p = lookup_request(s); + macro *m = p->to_macro(); + if (!m) + error("cannot chop request"); + else if (m->length == 0) + error("cannot chop empty macro"); + else + m->length -= 1; + } + skip_line(); +} + +void asciify_macro() +{ + symbol s = get_name(1); + if (!s.is_null()) { + request_or_macro *p = lookup_request(s); + macro *m = p->to_macro(); + if (!m) + error("cannot asciify request"); + else { + macro am; + string_iterator iter(*m); + for (;;) { + node *nd; + int c = iter.get(&nd); + if (c == EOF) + break; + if (c != 0) + am.append(c); + else + nd->asciify(&am); + } + *m = am; + } + } + skip_line(); +} + +static void interpolate_environment_variable(symbol nm) +{ + const char *s = getenv(nm.contents()); + if (s && *s) + input_stack::push(make_temp_iterator(s)); +} + +void interpolate_number_reg(symbol nm, int inc) +{ + reg *r = lookup_number_reg(nm); + if (inc < 0) + r->decrement(); + else if (inc > 0) + r->increment(); + input_stack::push(make_temp_iterator(r->get_string())); +} + +static void interpolate_number_format(symbol nm) +{ + reg *r = (reg *)number_reg_dictionary.lookup(nm); + if (r) + input_stack::push(make_temp_iterator(r->get_format())); +} + +static int get_delim_number(units *n, int si, int prev_value) +{ + token start; + start.next(); + if (start.delimiter(1)) { + tok.next(); + if (get_number(n, si, prev_value)) { + if (start != tok) + warning(WARN_DELIM, "closing delimiter does not match"); + return 1; + } + } + return 0; +} + +static int get_delim_number(units *n, int si) +{ + token start; + start.next(); + if (start.delimiter(1)) { + tok.next(); + if (get_number(n, si)) { + if (start != tok) + warning(WARN_DELIM, "closing delimiter does not match"); + return 1; + } + } + return 0; +} + +static int get_line_arg(units *n, int si, charinfo **cp) +{ + token start; + start.next(); + if (start.delimiter(1)) { + tok.next(); + if (get_number(n, si)) { + if (tok.dummy()) + tok.next(); + if (start != tok) { + *cp = tok.get_char(1); + tok.next(); + } + if (start != tok) + warning(WARN_DELIM, "closing delimiter does not match"); + return 1; + } + } + return 0; +} + +static int read_size(int *x) +{ + tok.next(); + int c = tok.ch(); + int inc = 0; + if (c == '-') { + inc = -1; + tok.next(); + c = tok.ch(); + } + else if (c == '+') { + inc = 1; + tok.next(); + c = tok.ch(); + } + int val; + int bad = 0; + if (c == '(') { + tok.next(); + c = tok.ch(); + if (!inc) { + // allow an increment either before or after the left parenthesis + if (c == '-') { + inc = -1; + tok.next(); + c = tok.ch(); + } + else if (c == '+') { + inc = 1; + tok.next(); + c = tok.ch(); + } + } + if (!csdigit(c)) + bad = 1; + else { + val = c - '0'; + tok.next(); + c = tok.ch(); + if (!csdigit(c)) + bad = 1; + else { + val = val*10 + (c - '0'); + val *= sizescale; + } + } + } + else if (csdigit(c)) { + val = c - '0'; + if (!inc && c != '0' && c < '4') { + tok.next(); + c = tok.ch(); + if (!csdigit(c)) + bad = 1; + else + val = val*10 + (c - '0'); + } + val *= sizescale; + } + else if (!tok.delimiter(1)) + return 0; + else { + token start(tok); + tok.next(); + if (!(inc + ? get_number(&val, 'z') + : get_number(&val, 'z', curenv->get_requested_point_size()))) + return 0; + if (!(start.ch() == '[' && tok.ch() == ']') && start != tok) { + if (start.ch() == '[') + error("missing `]'"); + else + error("missing closing delimiter"); + return 0; + } + } + if (!bad) { + switch (inc) { + case 0: + *x = val; + break; + case 1: + *x = curenv->get_requested_point_size() + val; + break; + case -1: + *x = curenv->get_requested_point_size() - val; + break; + default: + assert(0); + } + return 1; + } + else { + error("bad digit in point size"); + return 0; + } +} + +static symbol get_delim_name() +{ + token start; + start.next(); + if (start.eof()) { + error("end of input at start of delimited name"); + return NULL_SYMBOL; + } + if (start.newline()) { + error("can't delimit name with a newline"); + return NULL_SYMBOL; + } + int start_level = input_stack::get_level(); + char abuf[ABUF_SIZE]; + char *buf = abuf; + int buf_size = ABUF_SIZE; + int i = 0; + for (;;) { + if (i + 1 > buf_size) { + if (buf == abuf) { + buf = new char [ABUF_SIZE*2]; + memcpy(buf, abuf, buf_size); + buf_size = ABUF_SIZE*2; + } + else { + char *old_buf = buf; + buf = new char[buf_size*2]; + memcpy(buf, old_buf, buf_size); + buf_size *= 2; + a_delete old_buf; + } + } + tok.next(); + if (tok == start + && (compatible_flag || input_stack::get_level() == start_level)) + break; + if ((buf[i] = tok.ch()) == 0) { + error("missing delimiter (got %1)", tok.description()); + if (buf != abuf) + a_delete buf; + return NULL_SYMBOL; + } + i++; + } + buf[i] = '\0'; + if (buf == abuf) { + if (i == 0) { + error("empty delimited name"); + return NULL_SYMBOL; + } + else + return symbol(buf); + } + else { + symbol s(buf); + a_delete buf; + return s; + } +} + + +// Implement \R + +static void do_register() +{ + token start; + start.next(); + if (!start.delimiter(1)) + return; + tok.next(); + symbol nm = get_long_name(1); + if (nm.is_null()) + return; + while (tok.space()) + tok.next(); + reg *r = (reg *)number_reg_dictionary.lookup(nm); + int prev_value; + if (!r || !r->get_value(&prev_value)) + prev_value = 0; + int val; + if (!get_number(&val, 'u', prev_value)) + return; + if (start != tok) + warning(WARN_DELIM, "closing delimiter does not match"); + if (r) + r->set_value(val); + else + set_number_reg(nm, val); +} + +// this implements the \w escape sequence + +static void do_width() +{ + token start; + start.next(); + int start_level = input_stack::get_level(); + environment env(curenv); + environment *oldenv = curenv; + curenv = &env; + for (;;) { + tok.next(); + if (tok.eof()) { + warning(WARN_DELIM, "missing closing delimiter"); + break; + } + if (tok.newline()) { + warning(WARN_DELIM, "missing closing delimiter"); + input_stack::push(make_temp_iterator("\n")); + break; + } + if (tok == start + && (compatible_flag || input_stack::get_level() == start_level)) + break; + tok.process(); + } + env.wrap_up_tab(); + units x = env.get_input_line_position().to_units(); + input_stack::push(make_temp_iterator(itoa(x))); + env.width_registers(); + curenv = oldenv; +} + +charinfo *page_character; + +void set_page_character() +{ + page_character = get_optional_char(); + skip_line(); +} + +static const symbol percent_symbol("%"); + +void read_title_parts(node **part, hunits *part_width) +{ + tok.skip(); + if (tok.newline() || tok.eof()) + return; + token start(tok); + int start_level = input_stack::get_level(); + tok.next(); + for (int i = 0; i < 3; i++) { + while (!tok.newline() && !tok.eof()) { + if (tok == start + && (compatible_flag || input_stack::get_level() == start_level)) { + tok.next(); + break; + } + if (page_character != 0 && tok.get_char() == page_character) + interpolate_number_reg(percent_symbol, 0); + else + tok.process(); + tok.next(); + } + curenv->wrap_up_tab(); + part_width[i] = curenv->get_input_line_position(); + part[i] = curenv->extract_output_line(); + } + while (!tok.newline() && !tok.eof()) + tok.next(); +} + +class non_interpreted_node : public node { + macro mac; +public: + non_interpreted_node(const macro &); + int interpret(macro *); + node *copy(); + int same(node *); + const char *type(); +}; + +non_interpreted_node::non_interpreted_node(const macro &m) : mac(m) +{ +} + +int non_interpreted_node::same(node *nd) +{ + return mac == ((non_interpreted_node *)nd)->mac; +} + +const char *non_interpreted_node::type() +{ + return "non_interpreted_node"; +} + +node *non_interpreted_node::copy() +{ + return new non_interpreted_node(mac); +} + +int non_interpreted_node::interpret(macro *m) +{ + string_iterator si(mac); + node *n; + for (;;) { + int c = si.get(&n); + if (c == EOF) + break; + if (c == 0) + m->append(n); + else + m->append(c); + } + return 1; +} + +static node *do_non_interpreted() +{ + node *n; + int c; + macro mac; + while ((c = get_copy(&n)) != ESCAPE_QUESTION && c != EOF && c != '\n') + if (c == 0) + mac.append(n); + else + mac.append(c); + if (c == EOF || c == '\n') { + error("missing \\?"); + return 0; + } + return new non_interpreted_node(mac); +} + +node *do_special() +{ + token start; + start.next(); + int start_level = input_stack::get_level(); + macro mac; + for (tok.next(); + tok != start || input_stack::get_level() != start_level; + tok.next()) { + if (tok.eof()) { + warning(WARN_DELIM, "missing closing delimiter"); + return 0; + } + if (tok.newline()) { + input_stack::push(make_temp_iterator("\n")); + warning(WARN_DELIM, "missing closing delimiter"); + break; + } + unsigned char c; + if (tok.space()) + c = ' '; + else if (tok.tab()) + c = '\t'; + else if (tok.leader()) + c = '\001'; + else if (tok.backspace()) + c = '\b'; + else + c = tok.ch(); + if (c == '\0') + error("%1 is illegal within \\X", tok.description()); + else + mac.append(c); + } + return new special_node(mac); +} + +void special_node::tprint(troff_output_file *out) +{ + tprint_start(out); + string_iterator iter(mac); + for (;;) { + int c = iter.get(NULL); + if (c == EOF) + break; + for (const char *s = ::asciify(c); *s; s++) + tprint_char(out, *s); + } + tprint_end(out); +} + +int get_file_line(const char **filename, int *lineno) +{ + return input_stack::get_location(0, filename, lineno); +} + +void line_file() +{ + int n; + if (get_integer(&n)) { + const char *filename = 0; + if (has_arg()) { + symbol s = get_long_name(); + filename = s.contents(); + } + (void)input_stack::set_location(filename, n-1); + } + skip_line(); +} + +static int nroff_mode = 0; + +static void nroff_request() +{ + nroff_mode = 1; + skip_line(); +} + +static void troff_request() +{ + nroff_mode = 0; + skip_line(); +} + +static void skip_alternative() +{ + int level = 0; + // ensure that ``.if 0\{'' works as expected + if (tok.left_brace()) + level++; + int c; + for (;;) { + c = input_stack::get(NULL); + if (c == EOF) + break; + if (c == ESCAPE_LEFT_BRACE) + ++level; + else if (c == ESCAPE_RIGHT_BRACE) + --level; + else if (c == escape_char && escape_char > 0) + switch(input_stack::get(NULL)) { + case '{': + ++level; + break; + case '}': + --level; + break; + case '"': + while ((c = input_stack::get(NULL)) != '\n' && c != EOF) + ; + } + /* + Note that the level can properly be < 0, eg + + .if 1 \{\ + .if 0 \{\ + .\}\} + + So don't give an error message in this case. + */ + if (level <= 0 && c == '\n') + break; + } + tok.next(); +} + +static void begin_alternative() +{ + while (tok.space() || tok.left_brace()) + tok.next(); +} + + +static int_stack if_else_stack; + +int do_if_request() +{ + int invert = 0; + while (tok.space()) + tok.next(); + while (tok.ch() == '!') { + tok.next(); + invert = !invert; + } + int result; + unsigned char c = tok.ch(); + if (c == 't') { + tok.next(); + result = !nroff_mode; + } + else if (c == 'n') { + tok.next(); + result = nroff_mode; + } + else if (c == 'v') { + tok.next(); + result = 0; + } + else if (c == 'o') { + result = (topdiv->get_page_number() & 1); + tok.next(); + } + else if (c == 'e') { + result = !(topdiv->get_page_number() & 1); + tok.next(); + } + else if (c == 'd' || c == 'r') { + tok.next(); + symbol nm = get_name(1); + if (nm.is_null()) { + skip_alternative(); + return 0; + } + result = (c == 'd' + ? request_dictionary.lookup(nm) != 0 + : number_reg_dictionary.lookup(nm) != 0); + } + else if (c == 'c') { + tok.next(); + tok.skip(); + charinfo *ci = tok.get_char(1); + if (ci == 0) { + skip_alternative(); + return 0; + } + result = character_exists(ci, curenv); + tok.next(); + } + else if (tok.space()) + result = 0; + else if (tok.delimiter()) { + token delim = tok; + int delim_level = input_stack::get_level(); + environment env1(curenv); + environment env2(curenv); + environment *oldenv = curenv; + curenv = &env1; + for (int i = 0; i < 2; i++) { + for (;;) { + tok.next(); + if (tok.newline() || tok.eof()) { + warning(WARN_DELIM, "missing closing delimiter"); + tok.next(); + curenv = oldenv; + return 0; + } + if (tok == delim + && (compatible_flag || input_stack::get_level() == delim_level)) + break; + tok.process(); + } + curenv = &env2; + } + node *n1 = env1.extract_output_line(); + node *n2 = env2.extract_output_line(); + result = same_node_list(n1, n2); + delete_node_list(n1); + delete_node_list(n2); + tok.next(); + curenv = oldenv; + } + else { + units n; + if (!get_number(&n, 'u')) { + skip_alternative(); + return 0; + } + else + result = n > 0; + } + if (invert) + result = !result; + if (result) + begin_alternative(); + else + skip_alternative(); + return result; +} + +void if_else_request() +{ + if_else_stack.push(do_if_request()); +} + +void if_request() +{ + do_if_request(); +} + +void else_request() +{ + if (if_else_stack.is_empty()) { + warning(WARN_EL, "unbalanced .el request"); + skip_alternative(); + } + else { + if (if_else_stack.pop()) + skip_alternative(); + else + begin_alternative(); + } +} + +static int while_depth = 0; +static int while_break_flag = 0; + +void while_request() +{ + macro mac; + int escaped = 0; + int level = 0; + mac.append(new token_node(tok)); + for (;;) { + node *n; + int c = input_stack::get(&n); + if (c == EOF) + break; + if (c == 0) { + escaped = 0; + mac.append(n); + } + else if (escaped) { + if (c == '{') + level += 1; + else if (c == '}') + level -= 1; + escaped = 0; + mac.append(c); + } + else { + if (c == ESCAPE_LEFT_BRACE) + level += 1; + else if (c == ESCAPE_RIGHT_BRACE) + level -= 1; + else if (c == escape_char) + escaped = 1; + mac.append(c); + if (c == '\n' && level <= 0) + break; + } + } + if (level != 0) + error("unbalanced \\{ \\}"); + else { + while_depth++; + input_stack::add_boundary(); + for (;;) { + input_stack::push(new string_iterator(mac, "while loop")); + tok.next(); + if (!do_if_request()) { + while (input_stack::get(NULL) != EOF) + ; + break; + } + process_input_stack(); + if (while_break_flag) { + while_break_flag = 0; + break; + } + } + input_stack::remove_boundary(); + while_depth--; + } + tok.next(); +} + +void while_break_request() +{ + if (!while_depth) { + error("no while loop"); + skip_line(); + } + else { + while_break_flag = 1; + while (input_stack::get(NULL) != EOF) + ; + tok.next(); + } +} + +void while_continue_request() +{ + if (!while_depth) { + error("no while loop"); + skip_line(); + } + else { + while (input_stack::get(NULL) != EOF) + ; + tok.next(); + } +} + +// .so + +void source() +{ + symbol nm = get_long_name(1); + if (nm.is_null()) + skip_line(); + else { + while (!tok.newline() && !tok.eof()) + tok.next(); + errno = 0; + FILE *fp = fopen(nm.contents(), "r"); + if (fp) + input_stack::push(new file_iterator(fp, nm.contents())); + else + error("can't open `%1': %2", nm.contents(), strerror(errno)); + tok.next(); + } +} + +const char *asciify(int c) +{ + static char buf[3]; + buf[0] = escape_char == '\0' ? '\\' : escape_char; + buf[1] = buf[2] = '\0'; + switch (c) { + case ESCAPE_QUESTION: + buf[1] = '?'; + break; + case ESCAPE_AMPERSAND: + buf[1] = '&'; + break; + case ESCAPE_UNDERSCORE: + buf[1] = '_'; + break; + case ESCAPE_BAR: + buf[1] = '|'; + break; + case ESCAPE_CIRCUMFLEX: + buf[1] = '^'; + break; + case ESCAPE_LEFT_BRACE: + buf[1] = '{'; + break; + case ESCAPE_RIGHT_BRACE: + buf[1] = '}'; + break; + case ESCAPE_LEFT_QUOTE: + buf[1] = '`'; + break; + case ESCAPE_RIGHT_QUOTE: + buf[1] = '\''; + break; + case ESCAPE_HYPHEN: + buf[1] = '-'; + break; + case ESCAPE_BANG: + buf[1] = '!'; + break; + case ESCAPE_c: + buf[1] = 'c'; + break; + case ESCAPE_e: + buf[1] = 'e'; + break; + case ESCAPE_E: + buf[1] = 'E'; + break; + case ESCAPE_PERCENT: + buf[1] = '%'; + break; + case ESCAPE_SPACE: + buf[1] = ' '; + break; + default: + if (illegal_input_char(c)) + buf[0] = '\0'; + else + buf[0] = c; + break; + } + return buf; +} + + +const char *input_char_description(int c) +{ + switch (c) { + case '\n': + return "a newline character"; + case '\b': + return "a backspace character"; + case '\001': + return "a leader character"; + case '\t': + return "a tab character "; + case ' ': + return "a space character"; + case '\0': + return "a node"; + } + static char buf[sizeof("magic character code ") + 1 + INT_DIGITS]; + if (illegal_input_char(c)) { + const char *s = asciify(c); + if (*s) { + buf[0] = '`'; + strcpy(buf + 1, s); + strcat(buf, "'"); + return buf; + } + sprintf(buf, "magic character code %d", c); + return buf; + } + if (csprint(c)) { + buf[0] = '`'; + buf[1] = c; + buf[2] = '\''; + return buf; + } + sprintf(buf, "character code %d", c); + return buf; +} + +// .tm + +void terminal() +{ + if (!tok.newline() && !tok.eof()) { + int c; + while ((c = get_copy(NULL)) == ' ' || c == '\t') + ; + for (; c != '\n' && c != EOF; c = get_copy(NULL)) + fputs(asciify(c), stderr); + } + fputc('\n', stderr); + fflush(stderr); + tok.next(); +} + +dictionary stream_dictionary(20); + +void do_open(int append) +{ + symbol stream = get_name(1); + if (!stream.is_null()) { + symbol filename = get_long_name(1); + if (!filename.is_null()) { + errno = 0; + FILE *fp = fopen(filename.contents(), append ? "a" : "w"); + if (!fp) { + error("can't open `%1' for %2: %3", + filename.contents(), + append ? "appending" : "writing", + strerror(errno)); + fp = (FILE *)stream_dictionary.remove(stream); + } + else + fp = (FILE *)stream_dictionary.lookup(stream, fp); + if (fp) + fclose(fp); + } + } + skip_line(); +} + +void open_request() +{ + do_open(0); +} + +void opena_request() +{ + do_open(1); +} + +void close_request() +{ + symbol stream = get_name(1); + if (!stream.is_null()) { + FILE *fp = (FILE *)stream_dictionary.remove(stream); + if (!fp) + error("no stream named `%1'", stream.contents()); + else + fclose(fp); + } + skip_line(); +} + +void write_request() +{ + symbol stream = get_name(1); + if (stream.is_null()) { + skip_line(); + return; + } + FILE *fp = (FILE *)stream_dictionary.lookup(stream); + if (!fp) { + error("no stream named `%1'", stream.contents()); + skip_line(); + return; + } + int c; + while ((c = get_copy(NULL)) == ' ') + ; + if (c == '"') + c = get_copy(NULL); + for (; c != '\n' && c != EOF; c = get_copy(NULL)) + fputs(asciify(c), fp); + fputc('\n', fp); + fflush(fp); + tok.next(); +} + +static void init_charset_table() +{ + char buf[16]; + strcpy(buf, "char"); + for (int i = 0; i < 256; i++) { + strcpy(buf + 4, itoa(i)); + charset_table[i] = get_charinfo(symbol(buf)); + charset_table[i]->set_ascii_code(i); + if (csalpha(i)) + charset_table[i]->set_hyphenation_code(cmlower(i)); + } + charset_table['.']->set_flags(charinfo::ENDS_SENTENCE); + charset_table['?']->set_flags(charinfo::ENDS_SENTENCE); + charset_table['!']->set_flags(charinfo::ENDS_SENTENCE); + charset_table['-']->set_flags(charinfo::BREAK_AFTER); + charset_table['"']->set_flags(charinfo::TRANSPARENT); + charset_table['\'']->set_flags(charinfo::TRANSPARENT); + charset_table[')']->set_flags(charinfo::TRANSPARENT); + charset_table[']']->set_flags(charinfo::TRANSPARENT); + charset_table['*']->set_flags(charinfo::TRANSPARENT); + get_charinfo(symbol("dg"))->set_flags(charinfo::TRANSPARENT); + get_charinfo(symbol("rq"))->set_flags(charinfo::TRANSPARENT); + get_charinfo(symbol("em"))->set_flags(charinfo::BREAK_AFTER); + get_charinfo(symbol("ul"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); + get_charinfo(symbol("rn"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); + get_charinfo(symbol("ru"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); + get_charinfo(symbol("br"))->set_flags(charinfo::OVERLAPS_VERTICALLY); + page_character = charset_table['%']; +} + +static +void do_translate(int translate_transparent) +{ + tok.skip(); + while (!tok.newline() && !tok.eof()) { + if (tok.space()) { + // This is a really bizarre troff feature. + tok.next(); + translate_space_to_dummy = tok.dummy(); + if (tok.newline() || tok.eof()) + break; + tok.next(); + continue; + } + charinfo *ci1 = tok.get_char(1); + if (ci1 == 0) + break; + tok.next(); + if (tok.newline() || tok.eof()) { + ci1->set_special_translation(charinfo::TRANSLATE_SPACE, + translate_transparent); + break; + } + if (tok.space()) + ci1->set_special_translation(charinfo::TRANSLATE_SPACE, + translate_transparent); + else if (tok.dummy()) + ci1->set_special_translation(charinfo::TRANSLATE_DUMMY, + translate_transparent); + else if (tok.hyphen_indicator()) + ci1->set_special_translation(charinfo::TRANSLATE_HYPHEN_INDICATOR, + translate_transparent); + else { + charinfo *ci2 = tok.get_char(1); + if (ci2 == 0) + break; + if (ci1 == ci2) + ci1->set_translation(0, translate_transparent); + else + ci1->set_translation(ci2, translate_transparent); + } + tok.next(); + } + skip_line(); +} + +void translate() +{ + do_translate(1); +} + +void translate_no_transparent() +{ + do_translate(0); +} + +void char_flags() +{ + int flags; + if (get_integer(&flags)) + while (has_arg()) { + charinfo *ci = tok.get_char(1); + if (ci) { + charinfo *tem = ci->get_translation(); + if (tem) + ci = tem; + ci->set_flags(flags); + } + tok.next(); + } + skip_line(); +} + +void hyphenation_code() +{ + tok.skip(); + while (!tok.newline() && !tok.eof()) { + charinfo *ci = tok.get_char(1); + if (ci == 0) + break; + tok.next(); + tok.skip(); + unsigned char c = tok.ch(); + if (c == 0) { + error("hyphenation code must be ordinary character"); + break; + } + if (csdigit(c)) { + error("hyphenation code cannot be digit"); + break; + } + ci->set_hyphenation_code(c); + tok.next(); + } + skip_line(); +} + +charinfo *token::get_char(int required) +{ + if (type == TOKEN_CHAR) + return charset_table[c]; + if (type == TOKEN_SPECIAL) + return get_charinfo(nm); + if (type == TOKEN_NUMBERED_CHAR) + return get_charinfo_by_number(val); + if (type == TOKEN_ESCAPE) { + if (escape_char != 0) + return charset_table[escape_char]; + else { + error("`\\e' used while no current escape character"); + return 0; + } + } + if (required) { + if (type == TOKEN_EOF || type == TOKEN_NEWLINE) + warning(WARN_MISSING, "missing normal or special character"); + else + error("normal or special character expected (got %1)", description()); + } + return 0; +} + +charinfo *get_optional_char() +{ + while (tok.space()) + tok.next(); + charinfo *ci = tok.get_char(); + if (!ci) { + if (!tok.newline() && !tok.eof() && !tok.right_brace() && !tok.tab()) + error("normal or special character expected (got %1): " + "treated as missing", + tok.description()); + } + else + tok.next(); + return ci; +} + +int token::add_to_node_list(node **pp) +{ + hunits w; + node *n = 0; + switch (type) { + case TOKEN_CHAR: + *pp = (*pp)->add_char(charset_table[c], curenv, &w); + break; + case TOKEN_DUMMY: + n = new dummy_node; + break; + case TOKEN_ESCAPE: + if (escape_char != 0) + *pp = (*pp)->add_char(charset_table[escape_char], curenv, &w); + break; + case TOKEN_HYPHEN_INDICATOR: + *pp = (*pp)->add_discretionary_hyphen(); + break; + case TOKEN_ITALIC_CORRECTION: + *pp = (*pp)->add_italic_correction(&w); + break; + case TOKEN_LEFT_BRACE: + break; + case TOKEN_MARK_INPUT: + set_number_reg(nm, curenv->get_input_line_position().to_units()); + break; + case TOKEN_NODE: + n = nd; + nd = 0; + break; + case TOKEN_NUMBERED_CHAR: + *pp = (*pp)->add_char(get_charinfo_by_number(val), curenv, &w); + break; + case TOKEN_RIGHT_BRACE: + break; + case TOKEN_SPACE: + n = new hmotion_node(curenv->get_space_width()); + break; + case TOKEN_SPECIAL: + *pp = (*pp)->add_char(get_charinfo(nm), curenv, &w); + break; + default: + return 0; + } + if (n) { + n->next = *pp; + *pp = n; + } + return 1; +} + +void token::process() +{ + if (possibly_handle_first_page_transition()) + return; + switch (type) { + case TOKEN_BACKSPACE: + curenv->add_node(new hmotion_node(-curenv->get_space_width())); + break; + case TOKEN_CHAR: + curenv->add_char(charset_table[c]); + break; + case TOKEN_DUMMY: + curenv->add_node(new dummy_node); + break; + case TOKEN_EOF: + assert(0); + break; + case TOKEN_EMPTY: + assert(0); + break; + case TOKEN_ESCAPE: + if (escape_char != 0) + curenv->add_char(charset_table[escape_char]); + break; + case TOKEN_BEGIN_TRAP: + case TOKEN_END_TRAP: + case TOKEN_PAGE_EJECTOR: + // these are all handled in process_input_stack() + break; + case TOKEN_HYPHEN_INDICATOR: + curenv->add_hyphen_indicator(); + break; + case TOKEN_INTERRUPT: + curenv->interrupt(); + break; + case TOKEN_ITALIC_CORRECTION: + curenv->add_italic_correction(); + break; + case TOKEN_LEADER: + curenv->handle_tab(1); + break; + case TOKEN_LEFT_BRACE: + break; + case TOKEN_MARK_INPUT: + set_number_reg(nm, curenv->get_input_line_position().to_units()); + break; + case TOKEN_NEWLINE: + curenv->newline(); + break; + case TOKEN_NODE: + curenv->add_node(nd); + nd = 0; + break; + case TOKEN_NUMBERED_CHAR: + curenv->add_char(get_charinfo_by_number(val)); + break; + case TOKEN_REQUEST: + // handled in process_input_stack + break; + case TOKEN_RIGHT_BRACE: + break; + case TOKEN_SPACE: + curenv->space(); + break; + case TOKEN_SPECIAL: + curenv->add_char(get_charinfo(nm)); + break; + case TOKEN_SPREAD: + curenv->spread(); + break; + case TOKEN_TAB: + curenv->handle_tab(0); + break; + case TOKEN_TRANSPARENT: + break; + default: + assert(0); + } +} + +class nargs_reg : public reg { +public: + const char *get_string(); +}; + +const char *nargs_reg::get_string() +{ + return itoa(input_stack::nargs()); +} + +class lineno_reg : public reg { +public: + const char *get_string(); +}; + +const char *lineno_reg::get_string() +{ + int line; + const char *file; + if (!input_stack::get_location(0, &file, &line)) + line = 0; + return itoa(line); +} + + +class writable_lineno_reg : public general_reg { +public: + writable_lineno_reg(); + void set_value(units); + int get_value(units *); +}; + +writable_lineno_reg::writable_lineno_reg() +{ +} + +int writable_lineno_reg::get_value(units *res) +{ + int line; + const char *file; + if (!input_stack::get_location(0, &file, &line)) + return 0; + *res = line; + return 1; +} + +void writable_lineno_reg::set_value(units n) +{ + input_stack::set_location(0, n); +} + +class filename_reg : public reg { +public: + const char *get_string(); +}; + +const char *filename_reg::get_string() +{ + int line; + const char *file; + if (input_stack::get_location(0, &file, &line)) + return file; + else + return 0; +} + + +class constant_reg : public reg { + const char *s; +public: + constant_reg(const char *); + const char *get_string(); +}; + +constant_reg::constant_reg(const char *p) : s(p) +{ +} + +const char *constant_reg::get_string() +{ + return s; +} + +constant_int_reg::constant_int_reg(int *q) : p(q) +{ +} + +const char *constant_int_reg::get_string() +{ + return itoa(*p); +} + +void abort_request() +{ + int c; + while ((c = get_copy(0)) == ' ') + ; + if (c == EOF || c == '\n') + fputs("User Abort.", stderr); + else { + for (; c != '\n' && c != EOF; c = get_copy(NULL)) + fputs(asciify(c), stderr); + } + fputc('\n', stderr); + cleanup_and_exit(1); +} + +char *read_string() +{ + int len = 256; + char *s = new char[len]; + int c; + while ((c = get_copy(0)) == ' ') + ; + int i = 0; + while (c != '\n' && c != EOF) { + if (!illegal_input_char(c)) { + if (i + 2 > len) { + char *tem = s; + s = new char[len*2]; + memcpy(s, tem, len); + len *= 2; + a_delete tem; + } + s[i++] = c; + } + c = get_copy(0); + } + s[i] = '\0'; + tok.next(); + if (i == 0) { + a_delete s; + return 0; + } + return s; +} + +void pipe_output() +{ + if (the_output) { + error("can't pipe: output already started"); + skip_line(); + } + else { + if ((pipe_command = read_string()) == 0) + error("can't pipe to empty command"); + } +} + +static int system_status; + +void system_request() +{ + char *command = read_string(); + if (!command) + error("empty command"); + else { + system_status = system(command); + a_delete command; + } +} + +void copy_file() +{ + if (curdiv == topdiv && topdiv->before_first_page) { + handle_initial_request(COPY_FILE_REQUEST); + return; + } + symbol filename = get_long_name(1); + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + if (!filename.is_null()) + curdiv->copy_file(filename.contents()); + tok.next(); +} + +#ifdef COLUMN + +void vjustify() +{ + if (curdiv == topdiv && topdiv->before_first_page) { + handle_initial_request(VJUSTIFY_REQUEST); + return; + } + symbol type = get_long_name(1); + if (!type.is_null()) + curdiv->vjustify(type); + skip_line(); +} + +#endif /* COLUMN */ + +void transparent_file() +{ + if (curdiv == topdiv && topdiv->before_first_page) { + handle_initial_request(TRANSPARENT_FILE_REQUEST); + return; + } + symbol filename = get_long_name(1); + while (!tok.newline() && !tok.eof()) + tok.next(); + if (break_flag) + curenv->do_break(); + if (!filename.is_null()) { + errno = 0; + FILE *fp = fopen(filename.contents(), "r"); + if (!fp) + error("can't open `%1': %2", filename.contents(), strerror(errno)); + else { + int bol = 1; + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + if (illegal_input_char(c)) + warning(WARN_INPUT, "illegal input character code %1", int(c)); + else { + curdiv->transparent_output(c); + bol = c == '\n'; + } + } + if (!bol) + curdiv->transparent_output('\n'); + fclose(fp); + } + } + tok.next(); +} + +class page_range { + int first; + int last; +public: + page_range *next; + page_range(int, int, page_range *); + int contains(int n); +}; + +page_range::page_range(int i, int j, page_range *p) +: first(i), last(j), next(p) +{ +} + +int page_range::contains(int n) +{ + return n >= first && (last <= 0 || n <= last); +} + +page_range *output_page_list = 0; + +int in_output_page_list(int n) +{ + if (!output_page_list) + return 1; + for (page_range *p = output_page_list; p; p = p->next) + if (p->contains(n)) + return 1; + return 0; +} + +static void parse_output_page_list(char *p) +{ + for (;;) { + int i; + if (*p == '-') + i = 1; + else if (csdigit(*p)) { + i = 0; + do + i = i*10 + *p++ - '0'; + while (csdigit(*p)); + } + else + break; + int j; + if (*p == '-') { + p++; + j = 0; + if (csdigit(*p)) { + do + j = j*10 + *p++ - '0'; + while (csdigit(*p)); + } + } + else + j = i; + output_page_list = new page_range(i, j, output_page_list); + if (*p != ',') + break; + ++p; + } + if (*p != '\0') { + error("bad output page list"); + output_page_list = 0; + } +} + +static FILE *open_mac_file(const char *mac, char **path) +{ + char *s = new char[strlen(mac)+strlen(MACRO_PREFIX)+1]; + strcpy(s, MACRO_PREFIX); + strcat(s, mac); + FILE *fp = macro_path.open_file(s, path); + a_delete s; + return fp; +} + +static void process_macro_file(const char *mac) +{ + char *path; + FILE *fp = open_mac_file(mac, &path); + if (!fp) + fatal("can't find macro file %1", mac); + const char *s = symbol(path).contents(); + a_delete path; + input_stack::push(new file_iterator(fp, s)); + tok.next(); + process_input_stack(); +} + +static void process_startup_file() +{ + char *path; + FILE *fp = macro_path.open_file(STARTUP_FILE, &path); + if (fp) { + input_stack::push(new file_iterator(fp, symbol(path).contents())); + a_delete path; + tok.next(); + process_input_stack(); + } +} + +void macro_source() +{ + symbol nm = get_long_name(1); + if (nm.is_null()) + skip_line(); + else { + while (!tok.newline() && !tok.eof()) + tok.next(); + char *path; + FILE *fp = macro_path.open_file(nm.contents(), &path); + if (fp) { + input_stack::push(new file_iterator(fp, symbol(path).contents())); + a_delete path; + } + else + error("can't find macro file `%1'", nm.contents()); + tok.next(); + } +} + +static void process_input_file(const char *name) +{ + FILE *fp; + if (strcmp(name, "-") == 0) { + clearerr(stdin); + fp = stdin; + } + else { + errno = 0; + fp = fopen(name, "r"); + if (!fp) + fatal("can't open `%1': %2", name, strerror(errno)); + } + input_stack::push(new file_iterator(fp, name)); + tok.next(); + process_input_stack(); +} + +// make sure the_input is empty before calling this + +static int evaluate_expression(const char *expr, units *res) +{ + input_stack::push(make_temp_iterator(expr)); + tok.next(); + int success = get_number(res, 'u'); + while (input_stack::get(NULL) != EOF) + ; + return success; +} + +static void do_register_assignment(const char *s) +{ + const char *p = strchr(s, '='); + if (!p) { + char buf[2]; + buf[0] = s[0]; + buf[1] = 0; + units n; + if (evaluate_expression(s + 1, &n)) + set_number_reg(buf, n); + } + else { + char *buf = new char[p - s + 1]; + memcpy(buf, s, p - s); + buf[p - s] = 0; + units n; + if (evaluate_expression(p + 1, &n)) + set_number_reg(buf, n); + a_delete buf; + } +} + +static void set_string(const char *name, const char *value) +{ + macro *m = new macro; + for (const char *p = value; *p; p++) + if (!illegal_input_char((unsigned char)*p)) + m->append(*p); + request_dictionary.define(name, m); +} + + +static void do_string_assignment(const char *s) +{ + const char *p = strchr(s, '='); + if (!p) { + char buf[2]; + buf[0] = s[0]; + buf[1] = 0; + set_string(buf, s + 1); + } + else { + char *buf = new char[p - s + 1]; + memcpy(buf, s, p - s); + buf[p - s] = 0; + set_string(buf, p + 1); + a_delete buf; + } +} + +struct string_list { + const char *s; + string_list *next; + string_list(const char *ss) : s(ss), next(0) {} +}; + +static void add_string(const char *s, string_list **p) +{ + while (*p) + p = &((*p)->next); + *p = new string_list(s); +} + +void usage(const char *prog) +{ + errprint( +"usage: %1 -abivzCER -wname -Wname -dcstring -mname -nN -olist -rcN\n" +" -Tname -Fdir -Mdir [ files ]\n", + prog); + exit(USAGE_EXIT_CODE); +} + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int c; + string_list *macros = 0; + string_list *register_assignments = 0; + string_list *string_assignments = 0; + int iflag = 0; + int tflag = 0; + int fflag = 0; + int nflag = 0; + int no_rc = 0; // don't process troffrc + int next_page_number; + opterr = 0; + hresolution = vresolution = 1; + while ((c = getopt(argc, argv, "abivw:W:zCEf:m:n:o:r:d:F:M:T:tqs:R")) + != EOF) + switch(c) { + case 'v': + { + extern const char *version_string; + fprintf(stderr, "GNU troff version %s\n", version_string); + fflush(stderr); + break; + } + case 'T': + device = optarg; + tflag = 1; + break; + case 'C': + compatible_flag = 1; + break; + case 'M': + macro_path.command_line_dir(optarg); + break; + case 'F': + font::command_line_font_dir(optarg); + break; + case 'm': + add_string(optarg, ¯os); + break; + case 'E': + inhibit_errors = 1; + break; + case 'R': + no_rc = 1; + break; + case 'w': + enable_warning(optarg); + break; + case 'W': + disable_warning(optarg); + break; + case 'i': + iflag = 1; + break; + case 'b': + backtrace_flag = 1; + break; + case 'a': + ascii_output_flag = 1; + break; + case 'z': + suppress_output_flag = 1; + break; + case 'n': + if (sscanf(optarg, "%d", &next_page_number) == 1) + nflag++; + else + error("bad page number"); + break; + case 'o': + parse_output_page_list(optarg); + break; + case 'd': + if (*optarg == '\0') + error("`-d' requires non-empty argument"); + else + add_string(optarg, &string_assignments); + break; + case 'r': + if (*optarg == '\0') + error("`-r' requires non-empty argument"); + else + add_string(optarg, ®ister_assignments); + break; + case 'f': + default_family = symbol(optarg); + fflag = 1; + break; + case 'q': + case 's': + case 't': + // silently ignore these + break; + case '?': + usage(argv[0]); + default: + assert(0); + } + set_string(".T", device); + init_charset_table(); + if (!font::load_desc()) + fatal("sorry, I can't continue"); + units_per_inch = font::res; + hresolution = font::hor; + vresolution = font::vert; + sizescale = font::sizescale; + tcommand_flag = font::tcommand; + if (!fflag && font::family != 0 && *font::family != '\0') + default_family = symbol(font::family); + font_size::init_size_table(font::sizes); + int i; + int j = 1; + if (font::style_table) { + for (i = 0; font::style_table[i]; i++) + mount_style(j++, symbol(font::style_table[i])); + } + for (i = 0; font::font_name_table[i]; i++, j++) + // In the DESC file a font name of 0 (zero) means leave this + // position empty. + if (strcmp(font::font_name_table[i], "0") != 0) + mount_font(j, symbol(font::font_name_table[i])); + curdiv = topdiv = new top_level_diversion; + if (nflag) + topdiv->set_next_page_number(next_page_number); + init_input_requests(); + init_env_requests(); + init_div_requests(); +#ifdef COLUMN + init_column_requests(); +#endif /* COLUMN */ + init_node_requests(); + number_reg_dictionary.define(".T", new constant_reg(tflag ? "1" : "0")); + init_registers(); + init_reg_requests(); + init_hyphen_requests(); + init_environments(); + while (string_assignments) { + do_string_assignment(string_assignments->s); + string_list *tem = string_assignments; + string_assignments = string_assignments->next; + delete tem; + } + while (register_assignments) { + do_register_assignment(register_assignments->s); + string_list *tem = register_assignments; + register_assignments = register_assignments->next; + delete tem; + } + if (!no_rc) + process_startup_file(); + while (macros) { + process_macro_file(macros->s); + string_list *tem = macros; + macros = macros->next; + delete tem; + } + for (i = optind; i < argc; i++) + process_input_file(argv[i]); + if (optind >= argc || iflag) + process_input_file("-"); + exit_troff(); +} + +void warn_request() +{ + int n; + if (has_arg() && get_integer(&n)) { + if (n & ~WARN_TOTAL) { + warning(WARN_RANGE, "warning mask must be between 0 and %1", WARN_TOTAL); + n &= WARN_TOTAL; + } + warning_mask = n; + } + else + warning_mask = WARN_TOTAL; + skip_line(); +} + +static void init_registers() +{ +#ifdef LONG_FOR_TIME_T + long +#else /* not LONG_FOR_TIME_T */ + time_t +#endif /* not LONG_FOR_TIME_T */ + t = time(0); + // Use struct here to work around misfeature in old versions of g++. + struct tm *tt = localtime(&t); + set_number_reg("dw", int(tt->tm_wday + 1)); + set_number_reg("dy", int(tt->tm_mday)); + set_number_reg("mo", int(tt->tm_mon + 1)); + set_number_reg("yr", int(tt->tm_year)); + set_number_reg("$$", getpid()); + number_reg_dictionary.define(".A", + new constant_reg(ascii_output_flag + ? "1" + : "0")); +} + +void init_input_requests() +{ + init_request("ds", define_string); + init_request("as", append_string); + init_request("de", define_macro); + init_request("am", append_macro); + init_request("ig", ignore); + init_request("rm", remove_macro); + init_request("rn", rename_macro); + init_request("if", if_request); + init_request("ie", if_else_request); + init_request("el", else_request); + init_request("so", source); + init_request("nx", next_file); + init_request("pm", print_macros); + init_request("eo", escape_off); + init_request("ec", set_escape_char); + init_request("pc", set_page_character); + init_request("tm", terminal); + init_request("ex", exit_request); + init_request("em", end_macro); + init_request("tr", translate); + init_request("trnt", translate_no_transparent); + init_request("ab", abort_request); + init_request("pi", pipe_output); + init_request("cf", copy_file); + init_request("sy", system_request); + init_request("lf", line_file); + init_request("cflags", char_flags); + init_request("shift", shift); + init_request("rd", read_request); + init_request("cp", compatible); + init_request("char", define_character); + init_request("rchar", remove_character); + init_request("hcode", hyphenation_code); + init_request("while", while_request); + init_request("break", while_break_request); + init_request("continue", while_continue_request); + init_request("als", alias_macro); + init_request("backtrace", backtrace_request); + init_request("chop", chop_macro); + init_request("asciify", asciify_macro); + init_request("warn", warn_request); + init_request("open", open_request); + init_request("opena", opena_request); + init_request("close", close_request); + init_request("write", write_request); + init_request("trf", transparent_file); +#ifdef WIDOW_CONTROL + init_request("fpl", flush_pending_lines); +#endif /* WIDOW_CONTROL */ + init_request("nroff", nroff_request); + init_request("troff", troff_request); +#ifdef COLUMN + init_request("vj", vjustify); +#endif /* COLUMN */ + init_request("mso", macro_source); + init_request("do", do_request); + number_reg_dictionary.define("systat", new variable_reg(&system_status)); + number_reg_dictionary.define("slimit", + new variable_reg(&input_stack::limit)); + number_reg_dictionary.define(".$", new nargs_reg); + number_reg_dictionary.define(".c", new lineno_reg); + number_reg_dictionary.define("c.", new writable_lineno_reg); + number_reg_dictionary.define(".F", new filename_reg); + number_reg_dictionary.define(".C", new constant_int_reg(&compatible_flag)); + number_reg_dictionary.define(".H", new constant_int_reg(&hresolution)); + number_reg_dictionary.define(".V", new constant_int_reg(&vresolution)); + number_reg_dictionary.define(".R", new constant_reg("10000")); + extern const char *major_version; + number_reg_dictionary.define(".x", new constant_reg(major_version)); + extern const char *minor_version; + number_reg_dictionary.define(".y", new constant_reg(minor_version)); + number_reg_dictionary.define(".g", new constant_reg("1")); + number_reg_dictionary.define(".warn", new constant_int_reg(&warning_mask)); +} + +object_dictionary request_dictionary(501); + +void init_request(const char *s, REQUEST_FUNCP f) +{ + request_dictionary.define(s, new request(f)); +} + +static request_or_macro *lookup_request(symbol nm) +{ + assert(!nm.is_null()); + request_or_macro *p = (request_or_macro *)request_dictionary.lookup(nm); + if (p == 0) { + warning(WARN_MAC, "`%1' not defined", nm.contents()); + p = new macro; + request_dictionary.define(nm, p); + } + return p; +} + + +node *charinfo_to_node_list(charinfo *ci, const environment *envp) +{ + // Don't interpret character definitions in compatible mode. + int old_compatible_flag = compatible_flag; + compatible_flag = 0; + int old_escape_char = escape_char; + escape_char = '\\'; + macro *mac = ci->set_macro(0); + assert(mac != 0); + environment *oldenv = curenv; + environment env(envp); + curenv = &env; + curenv->set_composite(); + token old_tok = tok; + input_stack::add_boundary(); + string_iterator *si = new string_iterator(*mac, "composite character", ci->nm); + input_stack::push(si); + // we don't use process_input_stack, because we don't want to recognise + // requests + for (;;) { + tok.next(); + if (tok.eof()) + break; + if (tok.newline()) { + error("composite character mustn't contain newline"); + while (!tok.eof()) + tok.next(); + break; + } + else + tok.process(); + } + node *n = curenv->extract_output_line(); + input_stack::remove_boundary(); + ci->set_macro(mac); + tok = old_tok; + curenv = oldenv; + compatible_flag = old_compatible_flag; + escape_char = old_escape_char; + return n; +} + +static node *read_draw_node() +{ + token start; + start.next(); + if (!start.delimiter(1)){ + do { + tok.next(); + } while (tok != start && !tok.newline() && !tok.eof()); + } + else { + tok.next(); + if (tok == start) + error("missing argument"); + else { + unsigned char type = tok.ch(); + tok.next(); + int maxpoints = 10; + hvpair *point = new hvpair[maxpoints]; + int npoints = 0; + int no_last_v = 0; + int err = 0; + int i; + for (i = 0; tok != start; i++) { + if (i == maxpoints) { + hvpair *oldpoint = point; + point = new hvpair[maxpoints*2]; + for (int j = 0; j < maxpoints; j++) + point[j] = oldpoint[j]; + maxpoints *= 2; + a_delete oldpoint; + } + if (!get_hunits(&point[i].h, 'm')) { + err = 1; + break; + } + ++npoints; + tok.skip(); + point[i].v = V0; + if (tok == start) { + no_last_v = 1; + break; + } + if (!get_vunits(&point[i].v, 'v')) { + err = 1; + break; + } + tok.skip(); + } + while (tok != start && !tok.newline() && !tok.eof()) + tok.next(); + if (!err) { + switch (type) { + case 'l': + if (npoints != 1 || no_last_v) { + error("two arguments needed for line"); + npoints = 1; + } + break; + case 'c': + if (npoints != 1 || !no_last_v) { + error("one argument needed for circle"); + npoints = 1; + point[0].v = V0; + } + break; + case 'e': + if (npoints != 1 || no_last_v) { + error("two arguments needed for ellipse"); + npoints = 1; + } + break; + case 'a': + if (npoints != 2 || no_last_v) { + error("four arguments needed for arc"); + npoints = 2; + } + break; + case '~': + if (no_last_v) + error("even number of arguments needed for spline"); + break; + default: + // silently pass it through + break; + } + draw_node *dn = new draw_node(type, point, npoints, + curenv->get_font_size()); + a_delete point; + return dn; + } + else { + a_delete point; + } + } + } + return 0; +} + +static struct { + const char *name; + int mask; +} warning_table[] = { + "char", WARN_CHAR, + "range", WARN_RANGE, + "break", WARN_BREAK, + "delim", WARN_DELIM, + "el", WARN_EL, + "scale", WARN_SCALE, + "number", WARN_NUMBER, + "syntax", WARN_SYNTAX, + "tab", WARN_TAB, + "right-brace", WARN_RIGHT_BRACE, + "missing", WARN_MISSING, + "input", WARN_INPUT, + "escape", WARN_ESCAPE, + "space", WARN_SPACE, + "font", WARN_FONT, + "di", WARN_DI, + "mac", WARN_MAC, + "reg", WARN_REG, + "all", WARN_TOTAL & ~(WARN_DI | WARN_MAC | WARN_REG), + "w", WARN_TOTAL, + "default", DEFAULT_WARNING_MASK, +}; + +static int lookup_warning(const char *name) +{ + for (int i = 0; + i < sizeof(warning_table)/sizeof(warning_table[0]); + i++) + if (strcmp(name, warning_table[i].name) == 0) + return warning_table[i].mask; + return 0; +} + +static void enable_warning(const char *name) +{ + int mask = lookup_warning(name); + if (mask) + warning_mask |= mask; + else + error("unknown warning `%1'", name); +} + +static void disable_warning(const char *name) +{ + int mask = lookup_warning(name); + if (mask) + warning_mask &= ~mask; + else + error("unknown warning `%1'", name); +} + +enum error_type { WARNING, ERROR, FATAL }; + +static void do_error(error_type type, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + const char *filename; + int lineno; + if (inhibit_errors && type < FATAL) + return; + if (backtrace_flag) + input_stack::backtrace(); + if (!get_file_line(&filename, &lineno)) + filename = 0; + if (filename) + errprint("%1:%2: ", filename, lineno); + else if (program_name) + fprintf(stderr, "%s: ", program_name); + switch (type) { + case FATAL: + fputs("fatal error: ", stderr); + break; + case ERROR: + break; + case WARNING: + fputs("warning: ", stderr); + break; + } + errprint(format, arg1, arg2, arg3); + fputc('\n', stderr); + fflush(stderr); + if (type == FATAL) + cleanup_and_exit(1); +} + +int warning(warning_type t, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + if ((t & warning_mask) != 0) { + do_error(WARNING, format, arg1, arg2, arg3); + return 1; + } + else + return 0; +} + +void error(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(ERROR, format, arg1, arg2, arg3); +} + +void fatal(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(FATAL, format, arg1, arg2, arg3); +} + +void fatal_with_file_and_line(const char *filename, int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + fprintf(stderr, "%s:%d: fatal error: ", filename, lineno); + errprint(format, arg1, arg2, arg3); + fputc('\n', stderr); + fflush(stderr); + cleanup_and_exit(1); +} + +void error_with_file_and_line(const char *filename, int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + fprintf(stderr, "%s:%d: error: ", filename, lineno); + errprint(format, arg1, arg2, arg3); + fputc('\n', stderr); + fflush(stderr); +} + +dictionary charinfo_dictionary(501); + +charinfo *get_charinfo(symbol nm) +{ + void *p = charinfo_dictionary.lookup(nm); + if (p != 0) + return (charinfo *)p; + charinfo *cp = new charinfo(nm); + (void)charinfo_dictionary.lookup(nm, cp); + return cp; +} + +int charinfo::next_index = 0; + +charinfo::charinfo(symbol s) +: nm(s), hyphenation_code(0), translation(0), flags(0), ascii_code(0), + special_translation(TRANSLATE_NONE), mac(0), not_found(0), + transparent_translate(1) +{ + index = next_index++; +} + +void charinfo::set_hyphenation_code(unsigned char c) +{ + hyphenation_code = c; +} + +void charinfo::set_translation(charinfo *ci, int tt) +{ + translation = ci; + special_translation = TRANSLATE_NONE; + transparent_translate = tt; +} + +void charinfo::set_special_translation(int c, int tt) +{ + special_translation = c; + translation = 0; + transparent_translate = tt; +} + +void charinfo::set_ascii_code(unsigned char c) +{ + ascii_code = c; +} + +macro *charinfo::set_macro(macro *m) +{ + macro *tem = mac; + mac = m; + return tem; +} + +void charinfo::set_number(int n) +{ + number = n; + flags |= NUMBERED; +} + +int charinfo::get_number() +{ + assert(flags & NUMBERED); + return number; +} + +symbol UNNAMED_SYMBOL("---"); + +// For numbered characters not between 0 and 255, we make a symbol out +// of the number and store them in this dictionary. + +dictionary numbered_charinfo_dictionary(11); + +charinfo *get_charinfo_by_number(int n) +{ + static charinfo *number_table[256]; + + if (n >= 0 && n < 256) { + charinfo *ci = number_table[n]; + if (!ci) { + ci = new charinfo(UNNAMED_SYMBOL); + ci->set_number(n); + number_table[n] = ci; + } + return ci; + } + else { + symbol ns(itoa(n)); + charinfo *ci = (charinfo *)numbered_charinfo_dictionary.lookup(ns); + if (!ci) { + ci = new charinfo(UNNAMED_SYMBOL); + ci->set_number(n); + numbered_charinfo_dictionary.lookup(ns, ci); + } + return ci; + } +} + +int font::name_to_index(const char *nm) +{ + charinfo *ci; + if (nm[1] == 0) + ci = charset_table[nm[0] & 0xff]; + else if (nm[0] == '\\' && nm[2] == 0) + ci = get_charinfo(symbol(nm + 1)); + else + ci = get_charinfo(symbol(nm)); + if (ci == 0) + return -1; + else + return ci->get_index(); +} + +int font::number_to_index(int n) +{ + return get_charinfo_by_number(n)->get_index(); +} diff --git a/gnu/usr.bin/groff/troff/node.cc b/gnu/usr.bin/groff/troff/node.cc new file mode 100644 index 0000000000..6d36519d75 --- /dev/null +++ b/gnu/usr.bin/groff/troff/node.cc @@ -0,0 +1,4845 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "troff.h" +#include "symbol.h" +#include "dictionary.h" +#include "hvunits.h" +#include "env.h" +#include "request.h" +#include "node.h" +#include "token.h" +#include "charinfo.h" +#include "font.h" +#include "reg.h" + +#define STORE_WIDTH 1 + +symbol HYPHEN_SYMBOL("hy"); + +// Character used when a hyphen is inserted at a line break. +static charinfo *soft_hyphen_char; + +enum constant_space_type { + CONSTANT_SPACE_NONE, + CONSTANT_SPACE_RELATIVE, + CONSTANT_SPACE_ABSOLUTE + }; + +struct special_font_list { + int n; + special_font_list *next; +}; + +special_font_list *global_special_fonts; +static int global_ligature_mode = 1; +static int global_kern_mode = 1; + +class track_kerning_function { + int non_zero; + units min_size; + hunits min_amount; + units max_size; + hunits max_amount; +public: + track_kerning_function(); + track_kerning_function(units, hunits, units, hunits); + int operator==(const track_kerning_function &); + int operator!=(const track_kerning_function &); + hunits compute(int point_size); +}; + +// embolden fontno when this is the current font + +struct conditional_bold { + conditional_bold *next; + int fontno; + hunits offset; + conditional_bold(int, hunits, conditional_bold * = 0); +}; + +struct tfont; + +class font_info { + tfont *last_tfont; + int number; + font_size last_size; + int last_height; + int last_slant; + symbol internal_name; + symbol external_name; + font *fm; + char is_bold; + hunits bold_offset; + track_kerning_function track_kern; + constant_space_type is_constant_spaced; + units constant_space; + int last_ligature_mode; + int last_kern_mode; + conditional_bold *cond_bold_list; + void flush(); +public: + special_font_list *sf; + + font_info(symbol nm, int n, symbol enm, font *f); + int contains(charinfo *); + void set_bold(hunits); + void unbold(); + void set_conditional_bold(int, hunits); + void conditional_unbold(int); + void set_track_kern(track_kerning_function &); + void set_constant_space(constant_space_type, units = 0); + int is_named(symbol); + symbol get_name(); + tfont *get_tfont(font_size, int, int, int); + hunits get_space_width(font_size, int); + hunits get_narrow_space_width(font_size); + hunits get_half_narrow_space_width(font_size); + int get_bold(hunits *); + int is_special(); + int is_style(); +}; + +class tfont_spec { +protected: + symbol name; + int input_position; + font *fm; + font_size size; + char is_bold; + char is_constant_spaced; + int ligature_mode; + int kern_mode; + hunits bold_offset; + hunits track_kern; // add this to the width + hunits constant_space_width; + int height; + int slant; +public: + tfont_spec(symbol nm, int pos, font *, font_size, int, int); + tfont_spec plain(); + int operator==(const tfont_spec &); + friend tfont *font_info::get_tfont(font_size fs, int, int, int); +}; + +class tfont : public tfont_spec { + static tfont *tfont_list; + tfont *next; + tfont *plain_version; +public: + tfont(tfont_spec &); + int contains(charinfo *); + hunits get_width(charinfo *c); + int get_bold(hunits *); + int get_constant_space(hunits *); + hunits get_track_kern(); + tfont *get_plain(); + font_size get_size(); + symbol get_name(); + charinfo *get_lig(charinfo *c1, charinfo *c2); + int get_kern(charinfo *c1, charinfo *c2, hunits *res); + int get_input_position(); + int get_character_type(charinfo *); + int get_height(); + int get_slant(); + vunits get_char_height(charinfo *); + vunits get_char_depth(charinfo *); + hunits get_char_skew(charinfo *); + hunits get_italic_correction(charinfo *); + hunits get_left_italic_correction(charinfo *); + hunits get_subscript_correction(charinfo *); + friend tfont *make_tfont(tfont_spec &); +}; + +inline int env_definite_font(environment *env) +{ + return env->get_family()->make_definite(env->get_font()); +} + +static void invalidate_fontno(int n); + +/* font_info functions */ + +static font_info **font_table = 0; +static int font_table_size = 0; + +font_info::font_info(symbol nm, int n, symbol enm, font *f) +: internal_name(nm), external_name(enm), fm(f), number(n), + is_constant_spaced(CONSTANT_SPACE_NONE), + sf(0), is_bold(0), cond_bold_list(0), + last_ligature_mode(1), last_kern_mode(1), + last_tfont(0), last_size(0) +{ +} + +inline int font_info::contains(charinfo *ci) +{ + return fm != 0 && fm->contains(ci->get_index()); +} + +inline int font_info::is_special() +{ + return fm != 0 && fm->is_special(); +} + +inline int font_info::is_style() +{ + return fm == 0; +} + +// this is the current_font, fontno is where we found the character, +// presumably a special font + +tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno) +{ + if (last_tfont == 0 || fs != last_size + || height != last_height || slant != last_slant + || global_ligature_mode != last_ligature_mode + || global_kern_mode != last_kern_mode + || fontno != number) { + font_info *f = font_table[fontno]; + tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant); + for (conditional_bold *p = cond_bold_list; p; p = p->next) + if (p->fontno == fontno) { + spec.is_bold = 1; + spec.bold_offset = p->offset; + break; + } + if (!spec.is_bold && is_bold) { + spec.is_bold = 1; + spec.bold_offset = bold_offset; + } + spec.track_kern = track_kern.compute(fs.to_scaled_points()); + spec.ligature_mode = global_ligature_mode; + spec.kern_mode = global_kern_mode; + switch (is_constant_spaced) { + case CONSTANT_SPACE_NONE: + break; + case CONSTANT_SPACE_ABSOLUTE: + spec.is_constant_spaced = 1; + spec.constant_space_width = constant_space; + break; + case CONSTANT_SPACE_RELATIVE: + spec.is_constant_spaced = 1; + spec.constant_space_width + = scale(constant_space*fs.to_scaled_points(), + units_per_inch, + 36*72*sizescale); + break; + default: + assert(0); + } + if (fontno != number) + return make_tfont(spec); + last_tfont = make_tfont(spec); + last_size = fs; + last_height = height; + last_slant = slant; + last_ligature_mode = global_ligature_mode; + last_kern_mode = global_kern_mode; + } + return last_tfont; +} + +int font_info::get_bold(hunits *res) +{ + if (is_bold) { + *res = bold_offset; + return 1; + } + else + return 0; +} + +void font_info::unbold() +{ + if (is_bold) { + is_bold = 0; + flush(); + } +} + +void font_info::set_bold(hunits offset) +{ + if (!is_bold || offset != bold_offset) { + is_bold = 1; + bold_offset = offset; + flush(); + } +} + +void font_info::set_conditional_bold(int fontno, hunits offset) +{ + for (conditional_bold *p = cond_bold_list; p; p = p->next) + if (p->fontno == fontno) { + if (offset != p->offset) { + p->offset = offset; + flush(); + } + return; + } + cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list); +} + +conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x) + : fontno(f), offset(h), next(x) +{ +} + +void font_info::conditional_unbold(int fontno) +{ + for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next) + if ((*p)->fontno == fontno) { + conditional_bold *tem = *p; + *p = (*p)->next; + delete tem; + flush(); + return; + } +} + +void font_info::set_constant_space(constant_space_type type, units x) +{ + if (type != is_constant_spaced + || (type != CONSTANT_SPACE_NONE && x != constant_space)) { + flush(); + is_constant_spaced = type; + constant_space = x; + } +} + +void font_info::set_track_kern(track_kerning_function &tk) +{ + if (track_kern != tk) { + track_kern = tk; + flush(); + } +} + +void font_info::flush() +{ + last_tfont = 0; +} + +int font_info::is_named(symbol s) +{ + return internal_name == s; +} + +symbol font_info::get_name() +{ + return internal_name; +} + +hunits font_info::get_space_width(font_size fs, int space_size) +{ + if (is_constant_spaced == CONSTANT_SPACE_NONE) + return scale(hunits(fm->get_space_width(fs.to_scaled_points())), + space_size, 12); + else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE) + return constant_space; + else + return scale(constant_space*fs.to_scaled_points(), + units_per_inch, 36*72*sizescale); +} + +hunits font_info::get_narrow_space_width(font_size fs) +{ + charinfo *ci = get_charinfo(symbol("|")); + if (fm->contains(ci->get_index())) + return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); + else + return hunits(fs.to_units()/6); +} + +hunits font_info::get_half_narrow_space_width(font_size fs) +{ + charinfo *ci = get_charinfo(symbol("^")); + if (fm->contains(ci->get_index())) + return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); + else + return hunits(fs.to_units()/12); +} + +/* tfont */ + +tfont_spec::tfont_spec(symbol nm, int n, font *f, + font_size s, int h, int sl) + : name(nm), input_position(n), fm(f), size(s), + is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1), + height(h), slant(sl) +{ + if (height == size.to_scaled_points()) + height = 0; +} + +int tfont_spec::operator==(const tfont_spec &spec) +{ + if (fm == spec.fm + && size == spec.size + && input_position == spec.input_position + && name == spec.name + && height == spec.height + && slant == spec.slant + && (is_bold + ? (spec.is_bold && bold_offset == spec.bold_offset) + : !spec.is_bold) + && track_kern == spec.track_kern + && (is_constant_spaced + ? (spec.is_constant_spaced + && constant_space_width == spec.constant_space_width) + : !spec.is_constant_spaced) + && ligature_mode == spec.ligature_mode + && kern_mode == spec.kern_mode) + return 1; + else + return 0; +} + +tfont_spec tfont_spec::plain() +{ + return tfont_spec(name, input_position, fm, size, height, slant); +} + +hunits tfont::get_width(charinfo *c) +{ + if (is_constant_spaced) + return constant_space_width; + else if (is_bold) + return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) + + track_kern + bold_offset); + else + return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) + track_kern); +} + +vunits tfont::get_char_height(charinfo *c) +{ + vunits v = fm->get_height(c->get_index(), size.to_scaled_points()); + if (height != 0 && height != size.to_scaled_points()) + return scale(v, height, size.to_scaled_points()); + else + return v; +} + +vunits tfont::get_char_depth(charinfo *c) +{ + vunits v = fm->get_depth(c->get_index(), size.to_scaled_points()); + if (height != 0 && height != size.to_scaled_points()) + return scale(v, height, size.to_scaled_points()); + else + return v; +} + +hunits tfont::get_char_skew(charinfo *c) +{ + return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant)); +} + +hunits tfont::get_italic_correction(charinfo *c) +{ + return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points())); +} + +hunits tfont::get_left_italic_correction(charinfo *c) +{ + return hunits(fm->get_left_italic_correction(c->get_index(), + size.to_scaled_points())); +} + +hunits tfont::get_subscript_correction(charinfo *c) +{ + return hunits(fm->get_subscript_correction(c->get_index(), + size.to_scaled_points())); +} + +inline int tfont::get_input_position() +{ + return input_position; +} + +inline int tfont::contains(charinfo *ci) +{ + return fm->contains(ci->get_index()); +} + +inline int tfont::get_character_type(charinfo *ci) +{ + return fm->get_character_type(ci->get_index()); +} + +inline int tfont::get_bold(hunits *res) +{ + if (is_bold) { + *res = bold_offset; + return 1; + } + else + return 0; +} + +inline int tfont::get_constant_space(hunits *res) +{ + if (is_constant_spaced) { + *res = constant_space_width; + return 1; + } + else + return 0; +} + +inline hunits tfont::get_track_kern() +{ + return track_kern; +} + +inline tfont *tfont::get_plain() +{ + return plain_version; +} + +inline font_size tfont::get_size() +{ + return size; +} + +inline symbol tfont::get_name() +{ + return name; +} + +inline int tfont::get_height() +{ + return height; +} + +inline int tfont::get_slant() +{ + return slant; +} + +symbol SYMBOL_ff("ff"); +symbol SYMBOL_fi("fi"); +symbol SYMBOL_fl("fl"); +symbol SYMBOL_Fi("Fi"); +symbol SYMBOL_Fl("Fl"); + +charinfo *tfont::get_lig(charinfo *c1, charinfo *c2) +{ + if (ligature_mode == 0) + return 0; + charinfo *ci = 0; + if (c1->get_ascii_code() == 'f') { + switch (c2->get_ascii_code()) { + case 'f': + if (fm->has_ligature(font::LIG_ff)) + ci = get_charinfo(SYMBOL_ff); + break; + case 'i': + if (fm->has_ligature(font::LIG_fi)) + ci = get_charinfo(SYMBOL_fi); + break; + case 'l': + if (fm->has_ligature(font::LIG_fl)) + ci = get_charinfo(SYMBOL_fl); + break; + } + } + else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) { + switch (c2->get_ascii_code()) { + case 'i': + if (fm->has_ligature(font::LIG_ffi)) + ci = get_charinfo(SYMBOL_Fi); + break; + case 'l': + if (fm->has_ligature(font::LIG_ffl)) + ci = get_charinfo(SYMBOL_Fl); + break; + } + } + if (ci != 0 && fm->contains(ci->get_index())) + return ci; + return 0; +} + +inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res) +{ + if (kern_mode == 0) + return 0; + else { + int n = fm->get_kern(c1->get_index(), + c2->get_index(), + size.to_scaled_points()); + if (n) { + *res = hunits(n); + return 1; + } + else + return 0; + } +} + +tfont *make_tfont(tfont_spec &spec) +{ + for (tfont *p = tfont::tfont_list; p; p = p->next) + if (*p == spec) + return p; + return new tfont(spec); +} + +tfont *tfont::tfont_list = 0; + +tfont::tfont(tfont_spec &spec) : tfont_spec(spec) +{ + next = tfont_list; + tfont_list = this; + tfont_spec plain_spec = plain(); + for (tfont *p = tfont_list; p; p = p->next) + if (*p == plain_spec) { + plain_version = p; + break; + } + if (!p) + plain_version = new tfont(plain_spec); +} + +/* output_file */ + +class real_output_file : public output_file { + int piped; + int printing; + virtual void really_transparent_char(unsigned char) = 0; + virtual void really_print_line(hunits x, vunits y, node *n, + vunits before, vunits after) = 0; + virtual void really_begin_page(int pageno, vunits page_length) = 0; + virtual void really_copy_file(hunits x, vunits y, const char *filename); +protected: + FILE *fp; +public: + real_output_file(); + ~real_output_file(); + void flush(); + void transparent_char(unsigned char); + void print_line(hunits x, vunits y, node *n, vunits before, vunits after); + void begin_page(int pageno, vunits page_length); + int is_printing(); + void copy_file(hunits x, vunits y, const char *filename); +}; + +class suppress_output_file : public real_output_file { +public: + suppress_output_file(); + void really_transparent_char(unsigned char); + void really_print_line(hunits x, vunits y, node *n, vunits, vunits); + void really_begin_page(int pageno, vunits page_length); +}; + +class ascii_output_file : public real_output_file { +public: + ascii_output_file(); + void really_transparent_char(unsigned char); + void really_print_line(hunits x, vunits y, node *n, vunits, vunits); + void really_begin_page(int pageno, vunits page_length); + void outc(unsigned char c); + void outs(const char *s); +}; + +void ascii_output_file::outc(unsigned char c) +{ + fputc(c, fp); +} + +void ascii_output_file::outs(const char *s) +{ + fputc('<', fp); + if (s) + fputs(s, fp); + fputc('>', fp); +} + +struct hvpair; + +class troff_output_file : public real_output_file { + units hpos; + units vpos; + units output_vpos; + units output_hpos; + int force_motion; + int current_size; + int current_slant; + int current_height; + tfont *current_tfont; + int current_font_number; + symbol *font_position; + int nfont_positions; + enum { TBUF_SIZE = 256 }; + char tbuf[TBUF_SIZE]; + int tbuf_len; + int tbuf_kern; + int begun_page; + void do_motion(); + void put(char c); + void put(unsigned char c); + void put(int i); + void put(const char *s); + void set_font(tfont *tf); + void flush_tbuf(); +public: + troff_output_file(); + ~troff_output_file(); + void trailer(vunits page_length); + void put_char(charinfo *ci, tfont *tf); + void put_char_width(charinfo *ci, tfont *tf, hunits w, hunits k); + void right(hunits); + void down(vunits); + void moveto(hunits, vunits); + void start_special(); + void special_char(unsigned char c); + void end_special(); + void word_marker(); + void really_transparent_char(unsigned char c); + void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after); + void really_begin_page(int pageno, vunits page_length); + void really_copy_file(hunits x, vunits y, const char *filename); + void draw(char, hvpair *, int, font_size); + int get_hpos() { return hpos; } + int get_vpos() { return vpos; } +}; + +static void put_string(const char *s, FILE *fp) +{ + for (; *s != '\0'; ++s) + putc(*s, fp); +} + +inline void troff_output_file::put(char c) +{ + putc(c, fp); +} + +inline void troff_output_file::put(unsigned char c) +{ + putc(c, fp); +} + +inline void troff_output_file::put(const char *s) +{ + put_string(s, fp); +} + +inline void troff_output_file::put(int i) +{ + put_string(itoa(i), fp); +} + +void troff_output_file::start_special() +{ + flush_tbuf(); + do_motion(); + put("x X "); +} + +void troff_output_file::special_char(unsigned char c) +{ + put(c); + if (c == '\n') + put('+'); +} + +void troff_output_file::end_special() +{ + put('\n'); +} + +inline void troff_output_file::moveto(hunits h, vunits v) +{ + hpos = h.to_units(); + vpos = v.to_units(); +} + +void troff_output_file::really_print_line(hunits x, vunits y, node *n, + vunits before, vunits after) +{ + moveto(x, y); + while (n != 0) { + n->tprint(this); + n = n->next; + } + flush_tbuf(); + // This ensures that transparent throughput will have a more predictable + // position. + do_motion(); + force_motion = 1; + hpos = 0; + put('n'); + put(before.to_units()); + put(' '); + put(after.to_units()); + put('\n'); +} + +inline void troff_output_file::word_marker() +{ + flush_tbuf(); + put('w'); +} + +inline void troff_output_file::right(hunits n) +{ + hpos += n.to_units(); +} + +inline void troff_output_file::down(vunits n) +{ + vpos += n.to_units(); +} + +void troff_output_file::do_motion() +{ + if (force_motion) { + put('V'); + put(vpos); + put('\n'); + put('H'); + put(hpos); + put('\n'); + } + else { + if (hpos != output_hpos) { + units n = hpos - output_hpos; + if (n > 0 && n < hpos) { + put('h'); + put(n); + } + else { + put('H'); + put(hpos); + } + put('\n'); + } + if (vpos != output_vpos) { + units n = vpos - output_vpos; + if (n > 0 && n < vpos) { + put('v'); + put(n); + } + else { + put('V'); + put(vpos); + } + put('\n'); + } + } + output_vpos = vpos; + output_hpos = hpos; + force_motion = 0; +} + +void troff_output_file::flush_tbuf() +{ + if (tbuf_len == 0) + return; + if (tbuf_kern == 0) + put('t'); + else { + put('u'); + put(tbuf_kern); + put(' '); + } + for (int i = 0; i < tbuf_len; i++) + put(tbuf[i]); + put('\n'); + tbuf_len = 0; +} + +void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w, + hunits k) +{ + if (tf != current_tfont) { + flush_tbuf(); + set_font(tf); + } + char c = ci->get_ascii_code(); + int kk = k.to_units(); + if (c == '\0') { + flush_tbuf(); + do_motion(); + if (ci->numbered()) { + put('N'); + put(ci->get_number()); + } + else { + put('C'); + const char *s = ci->nm.contents(); + if (s[1] == 0) { + put('\\'); + put(s[0]); + } + else + put(s); + } + put('\n'); + hpos += w.to_units() + kk; + } + else if (tcommand_flag) { + if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos + && kk == tbuf_kern + && tbuf_len < TBUF_SIZE) { + tbuf[tbuf_len++] = c; + output_hpos += w.to_units() + kk; + hpos = output_hpos; + return; + } + flush_tbuf(); + do_motion(); + tbuf[tbuf_len++] = c; + output_hpos += w.to_units() + kk; + tbuf_kern = kk; + hpos = output_hpos; + } + else { + // flush_tbuf(); + int n = hpos - output_hpos; + if (vpos == output_vpos && n > 0 && n < 100 && !force_motion) { + put(char(n/10 + '0')); + put(char(n%10 + '0')); + put(c); + output_hpos = hpos; + } + else { + do_motion(); + put('c'); + put(c); + } + hpos += w.to_units() + kk; + } +} + +void troff_output_file::put_char(charinfo *ci, tfont *tf) +{ + flush_tbuf(); + if (tf != current_tfont) + set_font(tf); + char c = ci->get_ascii_code(); + if (c == '\0') { + do_motion(); + if (ci->numbered()) { + put('N'); + put(ci->get_number()); + } + else { + put('C'); + const char *s = ci->nm.contents(); + if (s[1] == 0) { + put('\\'); + put(s[0]); + } + else + put(s); + } + put('\n'); + } + else { + int n = hpos - output_hpos; + if (vpos == output_vpos && n > 0 && n < 100) { + put(char(n/10 + '0')); + put(char(n%10 + '0')); + put(c); + output_hpos = hpos; + } + else { + do_motion(); + put('c'); + put(c); + } + } +} + +void troff_output_file::set_font(tfont *tf) +{ + if (current_tfont == tf) + return; + int n = tf->get_input_position(); + symbol nm = tf->get_name(); + if (n >= nfont_positions || font_position[n] != nm) { + put("x font "); + put(n); + put(' '); + put(nm.contents()); + put('\n'); + if (n >= nfont_positions) { + int old_nfont_positions = nfont_positions; + symbol *old_font_position = font_position; + nfont_positions *= 3; + nfont_positions /= 2; + if (nfont_positions <= n) + nfont_positions = n + 10; + font_position = new symbol[nfont_positions]; + memcpy(font_position, old_font_position, + old_nfont_positions*sizeof(symbol)); + a_delete old_font_position; + } + font_position[n] = nm; + } + if (current_font_number != n) { + put('f'); + put(n); + put('\n'); + current_font_number = n; + } + int size = tf->get_size().to_scaled_points(); + if (current_size != size) { + put('s'); + put(size); + put('\n'); + current_size = size; + } + int slant = tf->get_slant(); + if (current_slant != slant) { + put("x Slant "); + put(slant); + put('\n'); + current_slant = slant; + } + int height = tf->get_height(); + if (current_height != height) { + put("x Height "); + put(height == 0 ? current_size : height); + put('\n'); + current_height = height; + } + current_tfont = tf; +} + +void troff_output_file::draw(char code, hvpair *point, int npoints, + font_size fsize) +{ + flush_tbuf(); + do_motion(); + int size = fsize.to_scaled_points(); + if (current_size != size) { + put('s'); + put(size); + put('\n'); + current_size = size; + current_tfont = 0; + } + put('D'); + put(code); + int i; + if (code == 'c') { + put(' '); + put(point[0].h.to_units()); + } + else + for (i = 0; i < npoints; i++) { + put(' '); + put(point[i].h.to_units()); + put(' '); + put(point[i].v.to_units()); + } + for (i = 0; i < npoints; i++) + output_hpos += point[i].h.to_units(); + hpos = output_hpos; + if (code != 'e') { + for (i = 0; i < npoints; i++) + output_vpos += point[i].v.to_units(); + vpos = output_vpos; + } + put('\n'); +} + +void troff_output_file::really_begin_page(int pageno, vunits page_length) +{ + flush_tbuf(); + if (begun_page) { + if (page_length > V0) { + put('V'); + put(page_length.to_units()); + put('\n'); + } + } + else + begun_page = 1; + current_tfont = 0; + current_font_number = -1; + current_size = 0; + // current_height = 0; + // current_slant = 0; + hpos = 0; + vpos = 0; + output_hpos = 0; + output_vpos = 0; + force_motion = 1; + for (int i = 0; i < nfont_positions; i++) + font_position[i] = NULL_SYMBOL; + put('p'); + put(pageno); + put('\n'); +} + +void troff_output_file::really_copy_file(hunits x, vunits y, const char *filename) +{ + moveto(x, y); + flush_tbuf(); + do_motion(); + errno = 0; + FILE *ifp = fopen(filename, "r"); + if (ifp == 0) + error("can't open `%1': %2", filename, strerror(errno)); + else { + int c; + while ((c = getc(ifp)) != EOF) + put(char(c)); + fclose(ifp); + } + force_motion = 1; + current_size = 0; + current_tfont = 0; + current_font_number = -1; + for (int i = 0; i < nfont_positions; i++) + font_position[i] = NULL_SYMBOL; +} + +void troff_output_file::really_transparent_char(unsigned char c) +{ + put(c); +} + +troff_output_file::~troff_output_file() +{ + a_delete font_position; +} + +void troff_output_file::trailer(vunits page_length) +{ + flush_tbuf(); + if (page_length > V0) { + put("x trailer\n"); + put('V'); + put(page_length.to_units()); + put('\n'); + } + put("x stop\n"); +} + +troff_output_file::troff_output_file() +: current_height(0), current_slant(0), tbuf_len(0), nfont_positions(10), + begun_page(0) +{ + font_position = new symbol[nfont_positions]; + put("x T "); + put(device); + put('\n'); + put("x res "); + put(units_per_inch); + put(' '); + put(hresolution); + put(' '); + put(vresolution); + put('\n'); + put("x init\n"); +} + +/* output_file */ + +output_file *the_output = 0; + +output_file::output_file() +{ +} + +output_file::~output_file() +{ +} + +void output_file::trailer(vunits) +{ +} + +real_output_file::real_output_file() +: printing(0) +{ + if (pipe_command) { + if ((fp = popen(pipe_command, "w")) != 0) { + piped = 1; + return; + } + error("pipe open failed: %1", strerror(errno)); + } + piped = 0; + fp = stdout; +} + +real_output_file::~real_output_file() +{ + if (!fp) + return; + // To avoid looping, set fp to 0 before calling fatal(). + if (ferror(fp) || fflush(fp) < 0) { + fp = 0; + fatal("error writing output file"); + } + if (piped) { + int result = pclose(fp); + fp = 0; + if (result < 0) + fatal("pclose failed"); + if ((result & 0x7f) != 0) + error("output process `%1' got fatal signal %2", + pipe_command, result & 0x7f); + else { + int exit_status = (result >> 8) & 0xff; + if (exit_status != 0) + error("output process `%1' exited with status %2", + pipe_command, exit_status); + } + } + else if (fclose(fp) < 0) { + fp = 0; + fatal("error closing output file"); + } +} + +void real_output_file::flush() +{ + if (fflush(fp) < 0) + fatal("error writing output file"); +} + +int real_output_file::is_printing() +{ + return printing; +} + +void real_output_file::begin_page(int pageno, vunits page_length) +{ + printing = in_output_page_list(pageno); + if (printing) + really_begin_page(pageno, page_length); +} + +void real_output_file::copy_file(hunits x, vunits y, const char *filename) +{ + if (printing) + really_copy_file(x, y, filename); +} + +void real_output_file::transparent_char(unsigned char c) +{ + if (printing) + really_transparent_char(c); +} + +void real_output_file::print_line(hunits x, vunits y, node *n, + vunits before, vunits after) +{ + if (printing) + really_print_line(x, y, n, before, after); + delete_node_list(n); +} + +void real_output_file::really_copy_file(hunits, vunits, const char *) +{ + // do nothing +} + + +/* ascii_output_file */ + +void ascii_output_file::really_transparent_char(unsigned char c) +{ + putc(c, fp); +} + +void ascii_output_file::really_print_line(hunits, vunits, node *n, vunits, vunits) +{ + while (n != 0) { + n->ascii_print(this); + n = n->next; + } + fputc('\n', fp); +} + +void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/) +{ + fputs("\n", fp); +} + +ascii_output_file::ascii_output_file() +{ +} + +/* suppress_output_file */ + +suppress_output_file::suppress_output_file() +{ +} + +void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits) +{ +} + +void suppress_output_file::really_begin_page(int, vunits) +{ +} + +void suppress_output_file::really_transparent_char(unsigned char) +{ +} + +/* glyphs, ligatures, kerns, discretionary breaks */ + +class glyph_node : public node { + static glyph_node *free_list; +protected: + charinfo *ci; + tfont *tf; +#ifdef STORE_WIDTH + hunits wid; + glyph_node(charinfo *, tfont *, hunits, node * = 0); +#endif +public: + void *operator new(size_t); + void operator delete(void *); + glyph_node(charinfo *, tfont *, node * = 0); + ~glyph_node() {} + node *copy(); + node *merge_glyph_node(glyph_node *); + node *merge_self(node *); + hunits width(); + node *last_char_node(); + units size(); + void vertical_extent(vunits *, vunits *); + hunits subscript_correction(); + hunits italic_correction(); + hunits left_italic_correction(); + hunits skew(); + hyphenation_type get_hyphenation_type(); + tfont *get_tfont(); + void tprint(troff_output_file *); + void zero_width_tprint(troff_output_file *); + hyphen_list *get_hyphen_list(hyphen_list *ss = 0); + node *add_self(node *, hyphen_list **); + int ends_sentence(); + int overlaps_vertically(); + int overlaps_horizontally(); + void ascii_print(ascii_output_file *); + void asciify(macro *); + int character_type(); + int same(node *); + const char *type(); +}; + +glyph_node *glyph_node::free_list = 0; + +class ligature_node : public glyph_node { + node *n1; + node *n2; +#ifdef STORE_WIDTH + ligature_node(charinfo *, tfont *, hunits, node *gn1, node *gn2, node *x = 0); +#endif +public: + void *operator new(size_t); + void operator delete(void *); + ligature_node(charinfo *, tfont *, node *gn1, node *gn2, node *x = 0); + ~ligature_node(); + node *copy(); + node *add_self(node *, hyphen_list **); + hyphen_list *get_hyphen_list(hyphen_list *ss = 0); + void ascii_print(ascii_output_file *); + void asciify(macro *); + int same(node *); + const char *type(); +}; + +class kern_pair_node : public node { + hunits amount; + node *n1; + node *n2; +public: + kern_pair_node(hunits n, node *first, node *second, node *x = 0); + ~kern_pair_node(); + node *copy(); + node *merge_glyph_node(glyph_node *); + node *add_self(node *, hyphen_list **); + hyphen_list *get_hyphen_list(hyphen_list *ss = 0); + node *add_discretionary_hyphen(); + hunits width(); + node *last_char_node(); + hunits italic_correction(); + hunits subscript_correction(); + void tprint(troff_output_file *); + hyphenation_type get_hyphenation_type(); + int ends_sentence(); + void ascii_print(ascii_output_file *); + void asciify(macro *); + int same(node *); + const char *type(); +}; + +class dbreak_node : public node { + node *none; + node *pre; + node *post; +public: + dbreak_node(node *n, node *p, node *x = 0); + ~dbreak_node(); + node *copy(); + node *merge_glyph_node(glyph_node *); + node *add_discretionary_hyphen(); + hunits width(); + node *last_char_node(); + hunits italic_correction(); + hunits subscript_correction(); + void tprint(troff_output_file *); + breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0, + int is_inner = 0); + int nbreaks(); + int ends_sentence(); + void split(int, node **, node **); + hyphenation_type get_hyphenation_type(); + void ascii_print(ascii_output_file *); + void asciify(macro *); + int same(node *); + const char *type(); +}; + +void *glyph_node::operator new(size_t n) +{ + assert(n == sizeof(glyph_node)); + if (!free_list) { + const int BLOCK = 1024; + free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK]; + for (int i = 0; i < BLOCK - 1; i++) + free_list[i].next = free_list + i + 1; + free_list[BLOCK-1].next = 0; + } + glyph_node *p = free_list; + free_list = (glyph_node *)(free_list->next); + p->next = 0; + return p; +} + +void *ligature_node::operator new(size_t n) +{ + return new char[n]; +} + +void glyph_node::operator delete(void *p) +{ + if (p) { + ((glyph_node *)p)->next = free_list; + free_list = (glyph_node *)p; + } +} + +void ligature_node::operator delete(void *p) +{ + delete p; +} + +glyph_node::glyph_node(charinfo *c, tfont *t, node *x) + : ci(c), tf(t), node(x) +{ +#ifdef STORE_WIDTH + wid = tf->get_width(ci); +#endif +} + +#ifdef STORE_WIDTH +glyph_node::glyph_node(charinfo *c, tfont *t, hunits w, node *x) + : ci(c), tf(t), wid(w), node(x) +{ +} +#endif + +node *glyph_node::copy() +{ +#ifdef STORE_WIDTH + return new glyph_node(ci, tf, wid); +#else + return new glyph_node(ci, tf); +#endif +} + +node *glyph_node::merge_self(node *nd) +{ + return nd->merge_glyph_node(this); +} + +int glyph_node::character_type() +{ + return tf->get_character_type(ci); +} + +node *glyph_node::add_self(node *n, hyphen_list **p) +{ + assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); + next = 0; + node *nn; + if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) { + next = n; + nn = this; + } + if ((*p)->hyphen) + nn = nn->add_discretionary_hyphen(); + hyphen_list *pp = *p; + *p = (*p)->next; + delete pp; + return nn; +} + +int glyph_node::overlaps_horizontally() +{ + return ci->overlaps_horizontally(); +} + +int glyph_node::overlaps_vertically() +{ + return ci->overlaps_vertically(); +} + +units glyph_node::size() +{ + return tf->get_size().to_units(); +} + +hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail) +{ + return new hyphen_list(ci->get_hyphenation_code(), tail); +} + + +tfont *node::get_tfont() +{ + return 0; +} + +tfont *glyph_node::get_tfont() +{ + return tf; +} + +node *node::merge_glyph_node(glyph_node * /*gn*/) +{ + return 0; +} + +node *glyph_node::merge_glyph_node(glyph_node *gn) +{ + if (tf == gn->tf) { + charinfo *lig; + if ((lig = tf->get_lig(ci, gn->ci)) != 0) { + node *next1 = next; + next = 0; + return new ligature_node(lig, tf, this, gn, next1); + } + hunits kern; + if (tf->get_kern(ci, gn->ci, &kern)) { + node *next1 = next; + next = 0; + return new kern_pair_node(kern, this, gn, next1); + } + } + return 0; +} + +#ifdef STORE_WIDTH +inline +#endif +hunits glyph_node::width() +{ +#ifdef STORE_WIDTH + return wid; +#else + return tf->get_width(ci); +#endif +} + +node *glyph_node::last_char_node() +{ + return this; +} + +void glyph_node::vertical_extent(vunits *min, vunits *max) +{ + *min = -tf->get_char_height(ci); + *max = tf->get_char_depth(ci); +} + +hunits glyph_node::skew() +{ + return tf->get_char_skew(ci); +} + +hunits glyph_node::subscript_correction() +{ + return tf->get_subscript_correction(ci); +} + +hunits glyph_node::italic_correction() +{ + return tf->get_italic_correction(ci); +} + +hunits glyph_node::left_italic_correction() +{ + return tf->get_left_italic_correction(ci); +} + +hyphenation_type glyph_node::get_hyphenation_type() +{ + return HYPHEN_MIDDLE; +} + +int glyph_node::ends_sentence() +{ + if (ci->ends_sentence()) + return 1; + else if (ci->transparent()) + return 2; + else + return 0; +} + +void glyph_node::ascii_print(ascii_output_file *ascii) +{ + unsigned char c = ci->get_ascii_code(); + if (c != 0) + ascii->outc(c); + else + ascii->outs(ci->nm.contents()); +} + +ligature_node::ligature_node(charinfo *c, tfont *t, + node *gn1, node *gn2, node *x) + : glyph_node(c, t, x), n1(gn1), n2(gn2) +{ +} + +#ifdef STORE_WIDTH +ligature_node::ligature_node(charinfo *c, tfont *t, hunits w, + node *gn1, node *gn2, node *x) + : glyph_node(c, t, w, x), n1(gn1), n2(gn2) +{ +} +#endif + +ligature_node::~ligature_node() +{ + delete n1; + delete n2; +} + +node *ligature_node::copy() +{ +#ifdef STORE_WIDTH + return new ligature_node(ci, tf, wid, n1->copy(), n2->copy()); +#else + return new ligature_node(ci, tf, n1->copy(), n2->copy()); +#endif +} + +void ligature_node::ascii_print(ascii_output_file *ascii) +{ + n1->ascii_print(ascii); + n2->ascii_print(ascii); +} + +hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail) +{ + return n1->get_hyphen_list(n2->get_hyphen_list(tail)); +} + +node *ligature_node::add_self(node *n, hyphen_list **p) +{ + n = n1->add_self(n, p); + n = n2->add_self(n, p); + n1 = n2 = 0; + delete this; + return n; +} + +kern_pair_node::kern_pair_node(hunits n, node *first, node *second, node *x) + : node(x), n1(first), n2(second), amount(n) +{ +} + +dbreak_node::dbreak_node(node *n, node *p, node *x) + : node(x), none(n), pre(p), post(0) +{ +} + +node *dbreak_node::merge_glyph_node(glyph_node *gn) +{ + glyph_node *gn2 = (glyph_node *)gn->copy(); + node *new_none = none ? none->merge_glyph_node(gn) : 0; + node *new_post = post ? post->merge_glyph_node(gn2) : 0; + if (new_none == 0 && new_post == 0) { + delete gn2; + return 0; + } + if (new_none != 0) + none = new_none; + else { + gn->next = none; + none = gn; + } + if (new_post != 0) + post = new_post; + else { + gn2->next = post; + post = gn2; + } + return this; +} + +node *kern_pair_node::merge_glyph_node(glyph_node *gn) +{ + node *nd = n2->merge_glyph_node(gn); + if (nd == 0) + return 0; + n2 = nd; + nd = n2->merge_self(n1); + if (nd) { + nd->next = next; + n1 = 0; + n2 = 0; + delete this; + return nd; + } + return this; +} + + +hunits kern_pair_node::italic_correction() +{ + return n2->italic_correction(); +} + +hunits kern_pair_node::subscript_correction() +{ + return n2->subscript_correction(); +} + +node *kern_pair_node::add_discretionary_hyphen() +{ + tfont *tf = n2->get_tfont(); + if (tf) { + if (tf->contains(soft_hyphen_char)) { + node *next1 = next; + next = 0; + node *n = copy(); + glyph_node *gn = new glyph_node(soft_hyphen_char, tf); + node *nn = n->merge_glyph_node(gn); + if (nn == 0) { + gn->next = n; + nn = gn; + } + return new dbreak_node(this, nn, next1); + } + } + return this; +} + + +kern_pair_node::~kern_pair_node() +{ + if (n1 != 0) + delete n1; + if (n2 != 0) + delete n2; +} + +dbreak_node::~dbreak_node() +{ + delete_node_list(pre); + delete_node_list(post); + delete_node_list(none); +} + +node *kern_pair_node::copy() +{ + return new kern_pair_node(amount, n1->copy(), n2->copy()); +} + +node *copy_node_list(node *n) +{ + node *p = 0; + while (n != 0) { + node *nn = n->copy(); + nn->next = p; + p = nn; + n = n->next; + } + while (p != 0) { + node *pp = p->next; + p->next = n; + n = p; + p = pp; + } + return n; +} + +void delete_node_list(node *n) +{ + while (n != 0) { + node *tem = n; + n = n->next; + delete tem; + } +} + +node *dbreak_node::copy() +{ + dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre)); + p->post = copy_node_list(post); + return p; +} + +hyphen_list *node::get_hyphen_list(hyphen_list *tail) +{ + return tail; +} + + +hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail) +{ + return n1->get_hyphen_list(n2->get_hyphen_list(tail)); +} + +class hyphen_inhibitor_node : public node { +public: + hyphen_inhibitor_node(node *nd = 0); + node *copy(); + int same(node *); + const char *type(); + hyphenation_type get_hyphenation_type(); +}; + +hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd) +{ +} + +node *hyphen_inhibitor_node::copy() +{ + return new hyphen_inhibitor_node; +} + +int hyphen_inhibitor_node::same(node *) +{ + return 1; +} + +const char *hyphen_inhibitor_node::type() +{ + return "hyphen_inhibitor_node"; +} + +hyphenation_type hyphen_inhibitor_node::get_hyphenation_type() +{ + return HYPHEN_INHIBIT; +} + +/* add_discretionary_hyphen methods */ + +node *dbreak_node::add_discretionary_hyphen() +{ + if (post) + post = post->add_discretionary_hyphen(); + if (none) + none = none->add_discretionary_hyphen(); + return this; +} + + +node *node::add_discretionary_hyphen() +{ + tfont *tf = get_tfont(); + if (!tf) + return new hyphen_inhibitor_node(this); + if (tf->contains(soft_hyphen_char)) { + node *next1 = next; + next = 0; + node *n = copy(); + glyph_node *gn = new glyph_node(soft_hyphen_char, tf); + node *n1 = n->merge_glyph_node(gn); + if (n1 == 0) { + gn->next = n; + n1 = gn; + } + return new dbreak_node(this, n1, next1); + } + return this; +} + + +node *node::merge_self(node *) +{ + return 0; +} + +node *node::add_self(node *n, hyphen_list ** /*p*/) +{ + next = n; + return this; +} + +node *kern_pair_node::add_self(node *n, hyphen_list **p) +{ + n = n1->add_self(n, p); + n = n2->add_self(n, p); + n1 = n2 = 0; + delete this; + return n; +} + + +hunits node::width() +{ + return H0; +} + +node *node::last_char_node() +{ + return 0; +} + +hunits hmotion_node::width() +{ + return n; +} + +units node::size() +{ + return points_to_units(10); +} + +hunits kern_pair_node::width() +{ + return n1->width() + n2->width() + amount; +} + +node *kern_pair_node::last_char_node() +{ + node *nd = n2->last_char_node(); + if (nd) + return nd; + return n1->last_char_node(); +} + +hunits dbreak_node::width() +{ + hunits x = H0; + for (node *n = none; n != 0; n = n->next) + x += n->width(); + return x; +} + +node *dbreak_node::last_char_node() +{ + for (node *n = none; n; n = n->next) { + node *last = n->last_char_node(); + if (last) + return last; + } + return 0; +} + +hunits dbreak_node::italic_correction() +{ + return none ? none->italic_correction() : H0; +} + +hunits dbreak_node::subscript_correction() +{ + return none ? none->subscript_correction() : H0; +} + +class italic_corrected_node : public node { + node *n; + hunits x; +public: + italic_corrected_node(node *, hunits, node * = 0); + ~italic_corrected_node(); + node *copy(); + void ascii_print(ascii_output_file *); + void asciify(macro *m); + hunits width(); + node *last_char_node(); + void vertical_extent(vunits *, vunits *); + int ends_sentence(); + int overlaps_horizontally(); + int overlaps_vertically(); + int same(node *); + hyphenation_type get_hyphenation_type(); + tfont *get_tfont(); + hyphen_list *get_hyphen_list(hyphen_list *ss = 0); + int character_type(); + void tprint(troff_output_file *); + hunits subscript_correction(); + hunits skew(); + node *add_self(node *, hyphen_list **); + const char *type(); +}; + +node *node::add_italic_correction(hunits *width) +{ + hunits ic = italic_correction(); + if (ic.is_zero()) + return this; + else { + node *next1 = next; + next = 0; + *width += ic; + return new italic_corrected_node(this, ic, next1); + } +} + +italic_corrected_node::italic_corrected_node(node *nn, hunits xx, node *p) +: n(nn), x(xx), node(p) +{ + assert(n != 0); +} + +italic_corrected_node::~italic_corrected_node() +{ + delete n; +} + +node *italic_corrected_node::copy() +{ + return new italic_corrected_node(n->copy(), x); +} + +hunits italic_corrected_node::width() +{ + return n->width() + x; +} + +void italic_corrected_node::vertical_extent(vunits *min, vunits *max) +{ + n->vertical_extent(min, max); +} + +void italic_corrected_node::tprint(troff_output_file *out) +{ + n->tprint(out); + out->right(x); +} + +hunits italic_corrected_node::skew() +{ + return n->skew() - x/2; +} + +hunits italic_corrected_node::subscript_correction() +{ + return n->subscript_correction() - x; +} + +void italic_corrected_node::ascii_print(ascii_output_file *out) +{ + n->ascii_print(out); +} + +int italic_corrected_node::ends_sentence() +{ + return n->ends_sentence(); +} + +int italic_corrected_node::overlaps_horizontally() +{ + return n->overlaps_horizontally(); +} + +int italic_corrected_node::overlaps_vertically() +{ + return n->overlaps_vertically(); +} + +node *italic_corrected_node::last_char_node() +{ + return n->last_char_node(); +} + +tfont *italic_corrected_node::get_tfont() +{ + return n->get_tfont(); +} + +hyphenation_type italic_corrected_node::get_hyphenation_type() +{ + return n->get_hyphenation_type(); +} + +node *italic_corrected_node::add_self(node *nd, hyphen_list **p) +{ + nd = n->add_self(nd, p); + hunits not_interested; + nd = nd->add_italic_correction(¬_interested); + n = 0; + delete this; + return nd; +} + +hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail) +{ + return n->get_hyphen_list(tail); +} + +int italic_corrected_node::character_type() +{ + return n->character_type(); +} + +class break_char_node : public node { + node *ch; + char break_code; +public: + break_char_node(node *, int, node * = 0); + ~break_char_node(); + node *copy(); + hunits width(); + vunits vertical_width(); + node *last_char_node(); + int character_type(); + int ends_sentence(); + node *add_self(node *, hyphen_list **); + hyphen_list *get_hyphen_list(hyphen_list *s = 0); + void tprint(troff_output_file *); + void zero_width_tprint(troff_output_file *); + void ascii_print(ascii_output_file *); + void asciify(macro *m); + hyphenation_type get_hyphenation_type(); + int overlaps_vertically(); + int overlaps_horizontally(); + units size(); + tfont *get_tfont(); + int same(node *); + const char *type(); +}; + +break_char_node::break_char_node(node *n, int c, node *x) +: node(x), ch(n), break_code(c) +{ +} + +break_char_node::~break_char_node() +{ + delete ch; +} + +node *break_char_node::copy() +{ + return new break_char_node(ch->copy(), break_code); +} + +hunits break_char_node::width() +{ + return ch->width(); +} + +vunits break_char_node::vertical_width() +{ + return ch->vertical_width(); +} + +node *break_char_node::last_char_node() +{ + return ch->last_char_node(); +} + +int break_char_node::character_type() +{ + return ch->character_type(); +} + +int break_char_node::ends_sentence() +{ + return ch->ends_sentence(); +} + +node *break_char_node::add_self(node *n, hyphen_list **p) +{ + assert((*p)->hyphenation_code == 0); + if ((*p)->breakable && (break_code & 1)) { + n = new space_node(H0, n); + n->freeze_space(); + } + next = n; + n = this; + if ((*p)->breakable && (break_code & 2)) { + n = new space_node(H0, n); + n->freeze_space(); + } + hyphen_list *pp = *p; + *p = (*p)->next; + delete pp; + return n; +} + +hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail) +{ + return new hyphen_list(0, tail); +} + +hyphenation_type break_char_node::get_hyphenation_type() +{ + return HYPHEN_MIDDLE; +} + +void break_char_node::ascii_print(ascii_output_file *ascii) +{ + ch->ascii_print(ascii); +} + +int break_char_node::overlaps_vertically() +{ + return ch->overlaps_vertically(); +} + +int break_char_node::overlaps_horizontally() +{ + return ch->overlaps_horizontally(); +} + +units break_char_node::size() +{ + return ch->size(); +} + +tfont *break_char_node::get_tfont() +{ + return ch->get_tfont(); +} + +node *extra_size_node::copy() +{ + return new extra_size_node(n); +} + +node *vertical_size_node::copy() +{ + return new vertical_size_node(n); +} + +node *hmotion_node::copy() +{ + return new hmotion_node(n); +} + +node *space_char_hmotion_node::copy() +{ + return new space_char_hmotion_node(n); +} + +node *vmotion_node::copy() +{ + return new vmotion_node(n); +} + +node *dummy_node::copy() +{ + return new dummy_node; +} + +node *transparent_dummy_node::copy() +{ + return new transparent_dummy_node; +} + +hline_node::~hline_node() +{ + if (n) + delete n; +} + +node *hline_node::copy() +{ + return new hline_node(x, n ? n->copy() : 0); +} + +hunits hline_node::width() +{ + return x < H0 ? H0 : x; +} + + +vline_node::~vline_node() +{ + if (n) + delete n; +} + +node *vline_node::copy() +{ + return new vline_node(x, n ? n->copy() : 0); +} + +hunits vline_node::width() +{ + return n == 0 ? H0 : n->width(); +} + + +zero_width_node::zero_width_node(node *nd) : n(nd) +{ +} + +zero_width_node::~zero_width_node() +{ + delete_node_list(n); +} + +node *zero_width_node::copy() +{ + return new zero_width_node(copy_node_list(n)); +} + +int node_list_character_type(node *p) +{ + int t = 0; + for (; p; p = p->next) + t |= p->character_type(); + return t; +} + +int zero_width_node::character_type() +{ + return node_list_character_type(n); +} + +void node_list_vertical_extent(node *p, vunits *min, vunits *max) +{ + *min = V0; + *max = V0; + vunits cur_vpos = V0; + vunits v1, v2; + for (; p; p = p->next) { + p->vertical_extent(&v1, &v2); + v1 += cur_vpos; + if (v1 < *min) + *min = v1; + v2 += cur_vpos; + if (v2 > *max) + *max = v2; + cur_vpos += p->vertical_width(); + } +} + +void zero_width_node::vertical_extent(vunits *min, vunits *max) +{ + node_list_vertical_extent(n, min, max); +} + +overstrike_node::overstrike_node() : max_width(H0), list(0) +{ +} + +overstrike_node::~overstrike_node() +{ + delete_node_list(list); +} + +node *overstrike_node::copy() +{ + overstrike_node *on = new overstrike_node; + for (node *tem = list; tem; tem = tem->next) + on->overstrike(tem->copy()); + return on; +} + +void overstrike_node::overstrike(node *n) +{ + if (n == 0) + return; + hunits w = n->width(); + if (w > max_width) + max_width = w; + for (node **p = &list; *p; p = &(*p)->next) + ; + n->next = 0; + *p = n; +} + +hunits overstrike_node::width() +{ + return max_width; +} + +bracket_node::bracket_node() : max_width(H0), list(0) +{ +} + +bracket_node::~bracket_node() +{ + delete_node_list(list); +} + +node *bracket_node::copy() +{ + bracket_node *on = new bracket_node; + for (node *tem = list; tem; tem = tem->next) + on->bracket(tem->copy()); + return on; +} + + +void bracket_node::bracket(node *n) +{ + if (n == 0) + return; + hunits w = n->width(); + if (w > max_width) + max_width = w; + n->next = list; + list = n; +} + +hunits bracket_node::width() +{ + return max_width; +} + +int node::nspaces() +{ + return 0; +} + +int node::merge_space(hunits) +{ + return 0; +} + +#if 0 +space_node *space_node::free_list = 0; + +void *space_node::operator new(size_t n) +{ + assert(n == sizeof(space_node)); + if (!free_list) { + free_list = (space_node *)new char[sizeof(space_node)*BLOCK]; + for (int i = 0; i < BLOCK - 1; i++) + free_list[i].next = free_list + i + 1; + free_list[BLOCK-1].next = 0; + } + space_node *p = free_list; + free_list = (space_node *)(free_list->next); + p->next = 0; + return p; +} + +inline void space_node::operator delete(void *p) +{ + if (p) { + ((space_node *)p)->next = free_list; + free_list = (space_node *)p; + } +} +#endif + +space_node::space_node(hunits nn, node *p) : node(p), n(nn), set(0) +{ +} + +space_node::space_node(hunits nn, int s, node *p) : node(p), n(nn), set(s) +{ +} + +#if 0 +space_node::~space_node() +{ +} +#endif + +node *space_node::copy() +{ + return new space_node(n, set); +} + +int space_node::nspaces() +{ + return set ? 0 : 1; +} + +int space_node::merge_space(hunits h) +{ + n += h; + return 1; +} + +hunits space_node::width() +{ + return n; +} + +void node::spread_space(int*, hunits*) +{ +} + +void space_node::spread_space(int *nspaces, hunits *desired_space) +{ + if (!set) { + assert(*nspaces > 0); + if (*nspaces == 1) { + n += *desired_space; + *desired_space = H0; + } + else { + hunits extra = *desired_space / *nspaces; + *desired_space -= extra; + n += extra; + } + *nspaces -= 1; + set = 1; + } +} + +void node::freeze_space() +{ +} + +void space_node::freeze_space() +{ + set = 1; +} + +diverted_space_node::diverted_space_node(vunits d, node *p) +: node(p), n(d) +{ +} + +node *diverted_space_node::copy() +{ + return new diverted_space_node(n); +} + +diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p) +: node(p), filename(s) +{ +} + +node *diverted_copy_file_node::copy() +{ + return new diverted_copy_file_node(filename); +} + +int node::ends_sentence() +{ + return 0; +} + +int kern_pair_node::ends_sentence() +{ + switch (n2->ends_sentence()) { + case 0: + return 0; + case 1: + return 1; + case 2: + break; + default: + assert(0); + } + return n1->ends_sentence(); +} + +int node_list_ends_sentence(node *n) +{ + for (; n != 0; n = n->next) + switch (n->ends_sentence()) { + case 0: + return 0; + case 1: + return 1; + case 2: + break; + default: + assert(0); + } + return 2; +} + + +int dbreak_node::ends_sentence() +{ + return node_list_ends_sentence(none); +} + + +int node::overlaps_horizontally() +{ + return 0; +} + +int node::overlaps_vertically() +{ + return 0; +} + +int node::discardable() +{ + return 0; +} + +int space_node::discardable() +{ + return set ? 0 : 1; +} + + +vunits node::vertical_width() +{ + return V0; +} + +vunits vline_node::vertical_width() +{ + return x; +} + +vunits vmotion_node::vertical_width() +{ + return n; +} + +int node::character_type() +{ + return 0; +} + +hunits node::subscript_correction() +{ + return H0; +} + +hunits node::italic_correction() +{ + return H0; +} + +hunits node::left_italic_correction() +{ + return H0; +} + +hunits node::skew() +{ + return H0; +} + + +/* vertical_extent methods */ + +void node::vertical_extent(vunits *min, vunits *max) +{ + vunits v = vertical_width(); + if (v < V0) { + *min = v; + *max = V0; + } + else { + *max = v; + *min = V0; + } +} + +void vline_node::vertical_extent(vunits *min, vunits *max) +{ + if (n == 0) + node::vertical_extent(min, max); + else { + vunits cmin, cmax; + n->vertical_extent(&cmin, &cmax); + vunits h = n->size(); + if (x < V0) { + if (-x < h) { + *min = x; + *max = V0; + } + else { + // we print the first character and then move up, so + *max = cmax; + // we print the last character and then move up h + *min = cmin + h; + if (*min > V0) + *min = V0; + *min += x; + } + } + else { + if (x < h) { + *max = x; + *min = V0; + } + else { + // we move down by h and then print the first character, so + *min = cmin + h; + if (*min > V0) + *min = V0; + *max = x + cmax; + } + } + } +} + +/* ascii_print methods */ + + +static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n) +{ + if (n == 0) + return; + ascii_print_reverse_node_list(ascii, n->next); + n->ascii_print(ascii); +} + +void dbreak_node::ascii_print(ascii_output_file *ascii) +{ + ascii_print_reverse_node_list(ascii, none); +} + +void kern_pair_node::ascii_print(ascii_output_file *ascii) +{ + n1->ascii_print(ascii); + n2->ascii_print(ascii); +} + + +void node::ascii_print(ascii_output_file *) +{ +} + +void space_node::ascii_print(ascii_output_file *ascii) +{ + if (!n.is_zero()) + ascii->outc(' '); +} + +void hmotion_node::ascii_print(ascii_output_file *ascii) +{ + // this is pretty arbitrary + if (n >= points_to_units(2)) + ascii->outc(' '); +} + +void space_char_hmotion_node::ascii_print(ascii_output_file *ascii) +{ + ascii->outc(' '); +} + +/* asciify methods */ + +void node::asciify(macro *m) +{ + m->append(this); +} + +void glyph_node::asciify(macro *m) +{ + unsigned char c = ci->get_ascii_code(); + if (c != 0) { + m->append(c); + delete this; + } + else + m->append(this); +} + +void kern_pair_node::asciify(macro *m) +{ + n1->asciify(m); + n2->asciify(m); + n1 = n2 = 0; + delete this; +} + +static void asciify_reverse_node_list(macro *m, node *n) +{ + if (n == 0) + return; + asciify_reverse_node_list(m, n->next); + n->asciify(m); +} + +void dbreak_node::asciify(macro *m) +{ + asciify_reverse_node_list(m, none); + none = 0; + delete this; +} + +void ligature_node::asciify(macro *m) +{ + n1->asciify(m); + n2->asciify(m); + n1 = n2 = 0; + delete this; +} + +void break_char_node::asciify(macro *m) +{ + ch->asciify(m); + ch = 0; + delete this; +} + +void italic_corrected_node::asciify(macro *m) +{ + n->asciify(m); + n = 0; + delete this; +} + +void left_italic_corrected_node::asciify(macro *m) +{ + if (n) { + n->asciify(m); + n = 0; + } + delete this; +} + +space_char_hmotion_node::space_char_hmotion_node(hunits i, node *next) +: hmotion_node(i, next) +{ +} + +void space_char_hmotion_node::asciify(macro *m) +{ + m->append(' '); + delete this; +} + +void line_start_node::asciify(macro *) +{ + delete this; +} + +void vertical_size_node::asciify(macro *) +{ + delete this; +} + +breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/, + breakpoint *rest, int /*is_inner*/) +{ + return rest; +} + +int node::nbreaks() +{ + return 0; +} + +breakpoint *space_node::get_breakpoints(hunits width, int ns, breakpoint *rest, + int is_inner) +{ + if (next->discardable()) + return rest; + breakpoint *bp = new breakpoint; + bp->next = rest; + bp->width = width; + bp->nspaces = ns; + bp->hyphenated = 0; + if (is_inner) { + assert(rest != 0); + bp->index = rest->index + 1; + bp->nd = rest->nd; + } + else { + bp->nd = this; + bp->index = 0; + } + return bp; +} + +int space_node::nbreaks() +{ + if (next->discardable()) + return 0; + else + return 1; +} + +static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp, + int ns, breakpoint *rest) +{ + if (p != 0) { + rest = p->get_breakpoints(*widthp, + ns, + node_list_get_breakpoints(p->next, widthp, ns, + rest), + 1); + *widthp += p->width(); + } + return rest; +} + + +breakpoint *dbreak_node::get_breakpoints(hunits width, int ns, + breakpoint *rest, int is_inner) +{ + breakpoint *bp = new breakpoint; + bp->next = rest; + bp->width = width; + for (node *tem = pre; tem != 0; tem = tem->next) + bp->width += tem->width(); + bp->nspaces = ns; + bp->hyphenated = 1; + if (is_inner) { + assert(rest != 0); + bp->index = rest->index + 1; + bp->nd = rest->nd; + } + else { + bp->nd = this; + bp->index = 0; + } + return node_list_get_breakpoints(none, &width, ns, bp); +} + +int dbreak_node::nbreaks() +{ + int i = 1; + for (node *tem = none; tem != 0; tem = tem->next) + i += tem->nbreaks(); + return i; +} + +void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/) +{ + assert(0); +} + +void space_node::split(int where, node **pre, node **post) +{ + assert(where == 0); + *pre = next; + *post = 0; + delete this; +} + +static void node_list_split(node *p, int *wherep, node **prep, node **postp) +{ + if (p == 0) + return; + int nb = p->nbreaks(); + node_list_split(p->next, wherep, prep, postp); + if (*wherep < 0) { + p->next = *postp; + *postp = p; + } + else if (*wherep < nb) { + p->next = *prep; + p->split(*wherep, prep, postp); + } + else { + p->next = *prep; + *prep = p; + } + *wherep -= nb; +} + +void dbreak_node::split(int where, node **prep, node **postp) +{ + assert(where >= 0); + if (where == 0) { + *postp = post; + post = 0; + if (pre == 0) + *prep = next; + else { + for (node *tem = pre; tem->next != 0; tem = tem->next) + ; + tem->next = next; + *prep = pre; + } + pre = 0; + delete this; + } + else { + *prep = next; + where -= 1; + node_list_split(none, &where, prep, postp); + none = 0; + delete this; + } +} + + +hyphenation_type node::get_hyphenation_type() +{ + return HYPHEN_BOUNDARY; +} + + +hyphenation_type dbreak_node::get_hyphenation_type() +{ + return HYPHEN_INHIBIT; +} + +hyphenation_type kern_pair_node::get_hyphenation_type() +{ + return HYPHEN_MIDDLE; +} + +hyphenation_type dummy_node::get_hyphenation_type() +{ + return HYPHEN_MIDDLE; +} + +hyphenation_type transparent_dummy_node::get_hyphenation_type() +{ + return HYPHEN_MIDDLE; +} + +int node::interpret(macro *) +{ + return 0; +} + +special_node::special_node(const macro &m) +: mac(m) +{ +} + +int special_node::same(node *n) +{ + return mac == ((special_node *)n)->mac; +} + +const char *special_node::type() +{ + return "special_node"; +} + +node *special_node::copy() +{ + return new special_node(mac); +} + +void special_node::tprint_start(troff_output_file *out) +{ + out->start_special(); +} + +void special_node::tprint_char(troff_output_file *out, unsigned char c) +{ + out->special_char(c); +} + +void special_node::tprint_end(troff_output_file *out) +{ + out->end_special(); +} + +/* composite_node */ + +class composite_node : public node { + charinfo *ci; + node *n; + tfont *tf; +public: + composite_node(node *, charinfo *, tfont *, node * = 0); + ~composite_node(); + node *copy(); + hunits width(); + node *last_char_node(); + units size(); + void tprint(troff_output_file *); + hyphenation_type get_hyphenation_type(); + int overlaps_horizontally(); + int overlaps_vertically(); + void ascii_print(ascii_output_file *); + void asciify(macro *); + hyphen_list *get_hyphen_list(hyphen_list *tail); + node *add_self(node *, hyphen_list **); + tfont *get_tfont(); + int same(node *); + const char *type(); + void vertical_extent(vunits *, vunits *); + vunits vertical_width(); +}; + +composite_node::composite_node(node *p, charinfo *c, tfont *t, node *x) +: node(x), n(p), ci(c), tf(t) +{ +} + +composite_node::~composite_node() +{ + delete_node_list(n); +} + +node *composite_node::copy() +{ + return new composite_node(copy_node_list(n), ci, tf); +} + +hunits composite_node::width() +{ + hunits x; + if (tf->get_constant_space(&x)) + return x; + x = H0; + for (node *tem = n; tem; tem = tem->next) + x += tem->width(); + hunits offset; + if (tf->get_bold(&offset)) + x += offset; + x += tf->get_track_kern(); + return x; +} + +node *composite_node::last_char_node() +{ + return this; +} + +vunits composite_node::vertical_width() +{ + vunits v = V0; + for (node *tem = n; tem; tem = tem->next) + v += tem->vertical_width(); + return v; +} + +units composite_node::size() +{ + return tf->get_size().to_units(); +} + +hyphenation_type composite_node::get_hyphenation_type() +{ + return HYPHEN_MIDDLE; +} + +int composite_node::overlaps_horizontally() +{ + return ci->overlaps_horizontally(); +} + +int composite_node::overlaps_vertically() +{ + return ci->overlaps_vertically(); +} + +void composite_node::asciify(macro *m) +{ + unsigned char c = ci->get_ascii_code(); + if (c != 0) { + m->append(c); + delete this; + } + else + m->append(this); +} + +void composite_node::ascii_print(ascii_output_file *ascii) +{ + unsigned char c = ci->get_ascii_code(); + if (c != 0) + ascii->outc(c); + else + ascii->outs(ci->nm.contents()); + +} + +hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail) +{ + return new hyphen_list(ci->get_hyphenation_code(), tail); + +} + +node *composite_node::add_self(node *nn, hyphen_list **p) +{ + assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); + next = nn; + nn = this; + if ((*p)->hyphen) + nn = nn->add_discretionary_hyphen(); + hyphen_list *pp = *p; + *p = (*p)->next; + delete pp; + return nn; +} + +tfont *composite_node::get_tfont() +{ + return tf; +} + +node *reverse_node_list(node *n) +{ + node *r = 0; + while (n) { + node *tem = n; + n = n->next; + tem->next = r; + r = tem; + } + return r; +} + +void composite_node::vertical_extent(vunits *min, vunits *max) +{ + n = reverse_node_list(n); + node_list_vertical_extent(n, min, max); + n = reverse_node_list(n); +} + +word_space_node::word_space_node(hunits d, node *x) : space_node(d, x) +{ +} + +word_space_node::word_space_node(hunits d, int s, node *x) +: space_node(d, s, x) +{ +} + +node *word_space_node::copy() +{ + return new word_space_node(n, set); +} + +void word_space_node::tprint(troff_output_file *out) +{ + out->word_marker(); + space_node::tprint(out); +} + +unbreakable_space_node::unbreakable_space_node(hunits d, node *x) +: word_space_node(d, x) +{ +} + +unbreakable_space_node::unbreakable_space_node(hunits d, int s, node *x) +: word_space_node(d, s, x) +{ +} + +node *unbreakable_space_node::copy() +{ + return new unbreakable_space_node(n, set); +} + +breakpoint *unbreakable_space_node::get_breakpoints(hunits, int, + breakpoint *rest, int) +{ + return rest; +} + +int unbreakable_space_node::nbreaks() +{ + return 0; +} + +void unbreakable_space_node::split(int, node **, node **) +{ + assert(0); +} + +int unbreakable_space_node::merge_space(hunits) +{ + return 0; +} + +hvpair::hvpair() +{ +} + +draw_node::draw_node(char c, hvpair *p, int np, font_size s) + : code(c), npoints(np), sz(s) +{ + point = new hvpair[npoints]; + for (int i = 0; i < npoints; i++) + point[i] = p[i]; +} + +int draw_node::same(node *n) +{ + draw_node *nd = (draw_node *)n; + if (code != nd->code || npoints != nd->npoints || sz != nd->sz) + return 0; + for (int i = 0; i < npoints; i++) + if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v) + return 0; + return 1; +} + +const char *draw_node::type() +{ + return "draw_node"; +} + +draw_node::~draw_node() +{ + if (point) + a_delete point; +} + +hunits draw_node::width() +{ + hunits x = H0; + for (int i = 0; i < npoints; i++) + x += point[i].h; + return x; +} + +vunits draw_node::vertical_width() +{ + if (code == 'e') + return V0; + vunits x = V0; + for (int i = 0; i < npoints; i++) + x += point[i].v; + return x; +} + +node *draw_node::copy() +{ + return new draw_node(code, point, npoints, sz); +} + +void draw_node::tprint(troff_output_file *out) +{ + out->draw(code, point, npoints, sz); +} + +/* tprint methods */ + +void glyph_node::tprint(troff_output_file *out) +{ + tfont *ptf = tf->get_plain(); + if (ptf == tf) + out->put_char_width(ci, ptf, width(), H0); + else { + hunits offset; + int bold = tf->get_bold(&offset); + hunits w = ptf->get_width(ci); + hunits k = H0; + hunits x; + int cs = tf->get_constant_space(&x); + if (cs) { + x -= w; + if (bold) + x -= offset; + hunits x2 = x/2; + out->right(x2); + k = x - x2; + } + else + k = tf->get_track_kern(); + if (bold) { + out->put_char(ci, ptf); + out->right(offset); + } + out->put_char_width(ci, ptf, w, k); + } +} + +void glyph_node::zero_width_tprint(troff_output_file *out) +{ + tfont *ptf = tf->get_plain(); + hunits offset; + int bold = tf->get_bold(&offset); + hunits x; + int cs = tf->get_constant_space(&x); + if (cs) { + x -= ptf->get_width(ci); + if (bold) + x -= offset; + x = x/2; + out->right(x); + } + out->put_char(ci, ptf); + if (bold) { + out->right(offset); + out->put_char(ci, ptf); + out->right(-offset); + } + if (cs) + out->right(-x); +} + +void break_char_node::tprint(troff_output_file *t) +{ + ch->tprint(t); +} + +void break_char_node::zero_width_tprint(troff_output_file *t) +{ + ch->zero_width_tprint(t); +} + +void hline_node::tprint(troff_output_file *out) +{ + if (x < H0) { + out->right(x); + x = -x; + } + if (n == 0) { + out->right(x); + return; + } + hunits w = n->width(); + if (w <= H0) { + error("horizontal line drawing character must have positive width"); + out->right(x); + return; + } + int i = int(x/w); + if (i == 0) { + hunits xx = x - w; + hunits xx2 = xx/2; + out->right(xx2); + n->tprint(out); + out->right(xx - xx2); + } + else { + hunits rem = x - w*i; + if (rem > H0) + if (n->overlaps_horizontally()) { + n->tprint(out); + out->right(rem - w); + } + else + out->right(rem); + while (--i >= 0) + n->tprint(out); + } +} + +void vline_node::tprint(troff_output_file *out) +{ + if (n == 0) { + out->down(x); + return; + } + vunits h = n->size(); + int overlaps = n->overlaps_vertically(); + vunits y = x; + if (y < V0) { + y = -y; + int i = y / h; + vunits rem = y - i*h; + if (i == 0) { + out->right(n->width()); + out->down(-rem); + } + else { + while (--i > 0) { + n->zero_width_tprint(out); + out->down(-h); + } + if (overlaps) { + n->zero_width_tprint(out); + out->down(-rem); + n->tprint(out); + out->down(-h); + } + else { + n->tprint(out); + out->down(-h - rem); + } + } + } + else { + int i = y / h; + vunits rem = y - i*h; + if (i == 0) { + out->down(rem); + out->right(n->width()); + } + else { + out->down(h); + if (overlaps) + n->zero_width_tprint(out); + out->down(rem); + while (--i > 0) { + n->zero_width_tprint(out); + out->down(h); + } + n->tprint(out); + } + } +} + +void zero_width_node::tprint(troff_output_file *out) +{ + if (!n) + return; + if (!n->next) { + n->zero_width_tprint(out); + return; + } + int hpos = out->get_hpos(); + int vpos = out->get_vpos(); + node *tem = n; + while (tem) { + tem->tprint(out); + tem = tem->next; + } + out->moveto(hpos, vpos); +} + +void overstrike_node::tprint(troff_output_file *out) +{ + hunits pos = H0; + for (node *tem = list; tem; tem = tem->next) { + hunits x = (max_width - tem->width())/2; + out->right(x - pos); + pos = x; + tem->zero_width_tprint(out); + } + out->right(max_width - pos); +} + +void bracket_node::tprint(troff_output_file *out) +{ + if (list == 0) + return; + int npieces = 0; + for (node *tem = list; tem; tem = tem->next) + ++npieces; + vunits h = list->size(); + vunits totalh = h*npieces; + vunits y = (totalh - h)/2; + out->down(y); + for (tem = list; tem; tem = tem->next) { + tem->zero_width_tprint(out); + out->down(-h); + } + out->right(max_width); + out->down(totalh - y); +} + +void node::tprint(troff_output_file *) +{ +} + +void node::zero_width_tprint(troff_output_file *out) +{ + int hpos = out->get_hpos(); + int vpos = out->get_vpos(); + tprint(out); + out->moveto(hpos, vpos); +} + +void space_node::tprint(troff_output_file *out) +{ + out->right(n); +} + +void hmotion_node::tprint(troff_output_file *out) +{ + out->right(n); +} + +void vmotion_node::tprint(troff_output_file *out) +{ + out->down(n); +} + +void kern_pair_node::tprint(troff_output_file *out) +{ + n1->tprint(out); + out->right(amount); + n2->tprint(out); +} + +static void tprint_reverse_node_list(troff_output_file *out, node *n) +{ + if (n == 0) + return; + tprint_reverse_node_list(out, n->next); + n->tprint(out); +} + +void dbreak_node::tprint(troff_output_file *out) +{ + tprint_reverse_node_list(out, none); +} + +void composite_node::tprint(troff_output_file *out) +{ + hunits bold_offset; + int is_bold = tf->get_bold(&bold_offset); + hunits track_kern = tf->get_track_kern(); + hunits constant_space; + int is_constant_spaced = tf->get_constant_space(&constant_space); + hunits x = H0; + if (is_constant_spaced) { + x = constant_space; + for (node *tem = n; tem; tem = tem->next) + x -= tem->width(); + if (is_bold) + x -= bold_offset; + hunits x2 = x/2; + out->right(x2); + x -= x2; + } + if (is_bold) { + int hpos = out->get_hpos(); + int vpos = out->get_vpos(); + tprint_reverse_node_list(out, n); + out->moveto(hpos, vpos); + out->right(bold_offset); + } + tprint_reverse_node_list(out, n); + if (is_constant_spaced) + out->right(x); + else + out->right(track_kern); +} + +node *make_composite_node(charinfo *s, environment *env) +{ + int fontno = env_definite_font(env); + if (fontno < 0) { + error("no current font"); + return 0; + } + assert(fontno < font_table_size && font_table[fontno] != 0); + node *n = charinfo_to_node_list(s, env); + font_size fs = env->get_font_size(); + int char_height = env->get_char_height(); + int char_slant = env->get_char_slant(); + tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, + fontno); + if (env->is_composite()) + tf = tf->get_plain(); + return new composite_node(n, s, tf); +} + +node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0) +{ + int fontno = env_definite_font(env); + if (fontno < 0) { + error("no current font"); + return 0; + } + assert(fontno < font_table_size && font_table[fontno] != 0); + int fn = fontno; + int found = font_table[fontno]->contains(s); + if (!found) { + if (s->numbered()) { + if (!no_error_message) + warning(WARN_CHAR, "can't find numbered character %1", + s->get_number()); + return 0; + } + special_font_list *sf = font_table[fontno]->sf; + while (sf != 0 && !found) { + fn = sf->n; + if (font_table[fn]) + found = font_table[fn]->contains(s); + sf = sf->next; + } + if (!found) { + sf = global_special_fonts; + while (sf != 0 && !found) { + fn = sf->n; + if (font_table[fn]) + found = font_table[fn]->contains(s); + sf = sf->next; + } + } + if (!found +#if 0 + && global_special_fonts == 0 && font_table[fontno]->sf == 0 +#endif + ) { + for (fn = 0; fn < font_table_size; fn++) + if (font_table[fn] + && font_table[fn]->is_special() + && font_table[fn]->contains(s)) { + found = 1; + break; + } + } + if (!found) { + if (!no_error_message && s->first_time_not_found()) { + unsigned char input_code = s->get_ascii_code(); + if (input_code != 0) { + if (csgraph(input_code)) + warning(WARN_CHAR, "can't find character `%1'", input_code); + else + warning(WARN_CHAR, "can't find character with input code %1", + int(input_code)); + } + else + warning(WARN_CHAR, "can't find special character `%1'", + s->nm.contents()); + } + return 0; + } + } + font_size fs = env->get_font_size(); + int char_height = env->get_char_height(); + int char_slant = env->get_char_slant(); + tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn); + if (env->is_composite()) + tf = tf->get_plain(); + return new glyph_node(s, tf); +} + +node *make_node(charinfo *ci, environment *env) +{ + switch (ci->get_special_translation()) { + case charinfo::TRANSLATE_SPACE: + return new space_char_hmotion_node(env->get_space_width()); + case charinfo::TRANSLATE_DUMMY: + return new dummy_node; + case charinfo::TRANSLATE_HYPHEN_INDICATOR: + error("translation to \\% ignored in this context"); + break; + } + charinfo *tem = ci->get_translation(); + if (tem) + ci = tem; + macro *mac = ci->get_macro(); + if (mac) + return make_composite_node(ci, env); + else + return make_glyph_node(ci, env); +} + +int character_exists(charinfo *ci, environment *env) +{ + if (ci->get_special_translation() != charinfo::TRANSLATE_NONE) + return 1; + charinfo *tem = ci->get_translation(); + if (tem) + ci = tem; + if (ci->get_macro()) + return 1; + node *nd = make_glyph_node(ci, env, 1); + if (nd) { + delete nd; + return 1; + } + return 0; +} + +node *node::add_char(charinfo *ci, environment *env, hunits *widthp) +{ + node *res; + switch (ci->get_special_translation()) { + case charinfo::TRANSLATE_SPACE: + res = new space_char_hmotion_node(env->get_space_width(), this); + *widthp += res->width(); + return res; + case charinfo::TRANSLATE_DUMMY: + return new dummy_node(this); + case charinfo::TRANSLATE_HYPHEN_INDICATOR: + return add_discretionary_hyphen(); + } + charinfo *tem = ci->get_translation(); + if (tem) + ci = tem; + macro *mac = ci->get_macro(); + if (mac) { + res = make_composite_node(ci, env); + if (res) { + res->next = this; + *widthp += res->width(); + } + else + return this; + } + else { + node *gn = make_glyph_node(ci, env); + if (gn == 0) + return this; + else { + hunits old_width = width(); + node *p = gn->merge_self(this); + if (p == 0) { + *widthp += gn->width(); + gn->next = this; + res = gn; + } + else { + *widthp += p->width() - old_width; + res = p; + } + } + } + int break_code = 0; + if (ci->can_break_before()) + break_code = 1; + if (ci->can_break_after()) + break_code |= 2; + if (break_code) { + node *next1 = res->next; + res->next = 0; + res = new break_char_node(res, break_code, next1); + } + return res; +} + + +#ifdef __GNUG__ +inline +#endif +int same_node(node *n1, node *n2) +{ + if (n1 != 0) { + if (n2 != 0) + return n1->type() == n2->type() && n1->same(n2); + else + return 0; + } + else + return n2 == 0; +} + +int same_node_list(node *n1, node *n2) +{ + while (n1 && n2) { + if (n1->type() != n2->type() || !n1->same(n2)) + return 0; + n1 = n1->next; + n2 = n2->next; + } + return !n1 && !n2; +} + +int extra_size_node::same(node *nd) +{ + return n == ((extra_size_node *)nd)->n; +} + +const char *extra_size_node::type() +{ + return "extra_size_node"; +} + +int vertical_size_node::same(node *nd) +{ + return n == ((vertical_size_node *)nd)->n; +} + +const char *vertical_size_node::type() +{ + return "vertical_size_node"; +} + +int hmotion_node::same(node *nd) +{ + return n == ((hmotion_node *)nd)->n; +} + +const char *hmotion_node::type() +{ + return "hmotion_node"; +} + +int space_char_hmotion_node::same(node *nd) +{ + return n == ((space_char_hmotion_node *)nd)->n; +} + +const char *space_char_hmotion_node::type() +{ + return "space_char_hmotion_node"; +} + +int vmotion_node::same(node *nd) +{ + return n == ((vmotion_node *)nd)->n; +} + +const char *vmotion_node::type() +{ + return "vmotion_node"; +} + +int hline_node::same(node *nd) +{ + return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n); +} + +const char *hline_node::type() +{ + return "hline_node"; +} + +int vline_node::same(node *nd) +{ + return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n); +} + +const char *vline_node::type() +{ + return "vline_node"; +} + +int dummy_node::same(node * /*nd*/) +{ + return 1; +} + +const char *dummy_node::type() +{ + return "dummy_node"; +} + +int transparent_dummy_node::same(node * /*nd*/) +{ + return 1; +} + +const char *transparent_dummy_node::type() +{ + return "transparent_dummy_node"; +} + +int transparent_dummy_node::ends_sentence() +{ + return 2; +} + +int zero_width_node::same(node *nd) +{ + return same_node_list(n, ((zero_width_node *)nd)->n); +} + +const char *zero_width_node::type() +{ + return "zero_width_node"; +} + +int italic_corrected_node::same(node *nd) +{ + return (x == ((italic_corrected_node *)nd)->x + && same_node(n, ((italic_corrected_node *)nd)->n)); +} + +const char *italic_corrected_node::type() +{ + return "italic_corrected_node"; +} + + +left_italic_corrected_node::left_italic_corrected_node(node *x) +: n(0), node(x) +{ +} + +left_italic_corrected_node::~left_italic_corrected_node() +{ + delete n; +} + +node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn) +{ + if (n == 0) { + hunits lic = gn->left_italic_correction(); + if (!lic.is_zero()) { + x = lic; + n = gn; + return this; + } + } + else { + node *nd = n->merge_glyph_node(gn); + if (nd) { + n = nd; + x = n->left_italic_correction(); + return this; + } + } + return 0; +} + +node *left_italic_corrected_node::copy() +{ + left_italic_corrected_node *nd = new left_italic_corrected_node; + if (n) { + nd->n = n->copy(); + nd->x = x; + } + return nd; +} + +void left_italic_corrected_node::tprint(troff_output_file *out) +{ + if (n) { + out->right(x); + n->tprint(out); + } +} + +const char *left_italic_corrected_node::type() +{ + return "left_italic_corrected_node"; +} + +int left_italic_corrected_node::same(node *nd) +{ + return (x == ((left_italic_corrected_node *)nd)->x + && same_node(n, ((left_italic_corrected_node *)nd)->n)); +} + +void left_italic_corrected_node::ascii_print(ascii_output_file *out) +{ + if (n) + n->ascii_print(out); +} + +hunits left_italic_corrected_node::width() +{ + return n ? n->width() + x : H0; +} + +void left_italic_corrected_node::vertical_extent(vunits *min, vunits *max) +{ + if (n) + n->vertical_extent(min, max); + else + node::vertical_extent(min, max); +} + +hunits left_italic_corrected_node::skew() +{ + return n ? n->skew() + x/2 : H0; +} + +hunits left_italic_corrected_node::subscript_correction() +{ + return n ? n->subscript_correction() : H0; +} + +hunits left_italic_corrected_node::italic_correction() +{ + return n ? n->italic_correction() : H0; +} + +int left_italic_corrected_node::ends_sentence() +{ + return n ? n->ends_sentence() : 0; +} + +int left_italic_corrected_node::overlaps_horizontally() +{ + return n ? n->overlaps_horizontally() : 0; +} + +int left_italic_corrected_node::overlaps_vertically() +{ + return n ? n->overlaps_vertically() : 0; +} + +node *left_italic_corrected_node::last_char_node() +{ + return n ? n->last_char_node() : 0; +} + +tfont *left_italic_corrected_node::get_tfont() +{ + return n ? n->get_tfont() : 0; +} + +hyphenation_type left_italic_corrected_node::get_hyphenation_type() +{ + if (n) + return n->get_hyphenation_type(); + else + return HYPHEN_MIDDLE; +} + +hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail) +{ + return n ? n->get_hyphen_list(tail) : tail; +} + +node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p) +{ + if (n) { + nd = new left_italic_corrected_node(nd); + nd = n->add_self(nd, p); + n = 0; + delete this; + } + return nd; +} + +int left_italic_corrected_node::character_type() +{ + return n ? n->character_type() : 0; +} + +int overstrike_node::same(node *nd) +{ + return same_node_list(list, ((overstrike_node *)nd)->list); +} + +const char *overstrike_node::type() +{ + return "overstrike_node"; +} + +int bracket_node::same(node *nd) +{ + return same_node_list(list, ((bracket_node *)nd)->list); +} + +const char *bracket_node::type() +{ + return "bracket_node"; +} + +int composite_node::same(node *nd) +{ + return ci == ((composite_node *)nd)->ci + && same_node_list(n, ((composite_node *)nd)->n); +} + +const char *composite_node::type() +{ + return "composite_node"; +} + +int glyph_node::same(node *nd) +{ + return ci == ((glyph_node *)nd)->ci && tf == ((glyph_node *)nd)->tf; +} + +const char *glyph_node::type() +{ + return "glyph_node"; +} + +int ligature_node::same(node *nd) +{ + return (same_node(n1, ((ligature_node *)nd)->n1) + && same_node(n2, ((ligature_node *)nd)->n2) + && glyph_node::same(nd)); +} + +const char *ligature_node::type() +{ + return "ligature_node"; +} + +int kern_pair_node::same(node *nd) +{ + return (amount == ((kern_pair_node *)nd)->amount + && same_node(n1, ((kern_pair_node *)nd)->n1) + && same_node(n2, ((kern_pair_node *)nd)->n2)); +} + +const char *kern_pair_node::type() +{ + return "kern_pair_node"; +} + +int dbreak_node::same(node *nd) +{ + return (same_node_list(none, ((dbreak_node *)nd)->none) + && same_node_list(pre, ((dbreak_node *)nd)->pre) + && same_node_list(post, ((dbreak_node *)nd)->post)); +} + +const char *dbreak_node::type() +{ + return "dbreak_node"; +} + +int break_char_node::same(node *nd) +{ + return (break_code == ((break_char_node *)nd)->break_code + && same_node(ch, ((break_char_node *)nd)->ch)); +} + +const char *break_char_node::type() +{ + return "break_char_node"; +} + +int line_start_node::same(node * /*nd*/) +{ + return 1; +} + +const char *line_start_node::type() +{ + return "line_start_node"; +} + +int space_node::same(node *nd) +{ + return n == ((space_node *)nd)->n && set == ((space_node *)nd)->set; +} + +const char *space_node::type() +{ + return "space_node"; +} + +int word_space_node::same(node *nd) +{ + return (n == ((word_space_node *)nd)->n + && set == ((word_space_node *)nd)->set); +} + +const char *word_space_node::type() +{ + return "word_space_node"; +} + +int unbreakable_space_node::same(node *nd) +{ + return (n == ((unbreakable_space_node *)nd)->n + && set == ((unbreakable_space_node *)nd)->set); +} + +const char *unbreakable_space_node::type() +{ + return "unbreakable_space_node"; +} + +int diverted_space_node::same(node *nd) +{ + return n == ((diverted_space_node *)nd)->n; +} + +const char *diverted_space_node::type() +{ + return "diverted_space_node"; +} + +int diverted_copy_file_node::same(node *nd) +{ + return filename == ((diverted_copy_file_node *)nd)->filename; +} + +const char *diverted_copy_file_node::type() +{ + return "diverted_copy_file_node"; +} + +// Grow the font_table so that its size is > n. + +static void grow_font_table(int n) +{ + assert(n >= font_table_size); + font_info **old_font_table = font_table; + int old_font_table_size = font_table_size; + font_table_size = font_table_size ? (font_table_size*3)/2 : 10; + if (font_table_size <= n) + font_table_size = n + 10; + font_table = new font_info *[font_table_size]; + if (old_font_table_size) + memcpy(font_table, old_font_table, + old_font_table_size*sizeof(font_info *)); + a_delete old_font_table; + for (int i = old_font_table_size; i < font_table_size; i++) + font_table[i] = 0; +} + +dictionary font_translation_dictionary(17); + +static symbol get_font_translation(symbol nm) +{ + void *p = font_translation_dictionary.lookup(nm); + return p ? symbol((char *)p) : nm; +} + +dictionary font_dictionary(50); + +static int mount_font_no_translate(int n, symbol name, symbol external_name) +{ + assert(n >= 0); + // We store the address of this char in font_dictionary to indicate + // that we've previously tried to mount the font and failed. + static char a_char; + font *fm = 0; + void *p = font_dictionary.lookup(external_name); + if (p == 0) { + int not_found; + fm = font::load_font(external_name.contents(), ¬_found); + if (!fm) { + if (not_found) + warning(WARN_FONT, "can't find font `%1'", external_name.contents()); + font_dictionary.lookup(external_name, &a_char); + return 0; + } + font_dictionary.lookup(name, fm); + } + else if (p == &a_char) { +#if 0 + error("invalid font `%1'", external_name.contents()); +#endif + return 0; + } + else + fm = (font*)p; + if (n >= font_table_size) { + if (n - font_table_size > 1000) { + error("font position too much larger than first unused position"); + return 0; + } + grow_font_table(n); + } + else if (font_table[n] != 0) + delete font_table[n]; + font_table[n] = new font_info(name, n, external_name, fm); + invalidate_fontno(n); + return 1; +} + +int mount_font(int n, symbol name, symbol external_name) +{ + assert(n >= 0); + name = get_font_translation(name); + if (external_name.is_null()) + external_name = name; + else + external_name = get_font_translation(external_name); + return mount_font_no_translate(n, name, external_name); +} + +void mount_style(int n, symbol name) +{ + assert(n >= 0); + if (n >= font_table_size) { + if (n - font_table_size > 1000) { + error("font position too much larger than first unused position"); + return; + } + grow_font_table(n); + } + else if (font_table[n] != 0) + delete font_table[n]; + font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0); + invalidate_fontno(n); +} + +/* global functions */ + +void font_translate() +{ + symbol from = get_name(1); + if (!from.is_null()) { + symbol to = get_name(); + if (to.is_null() || from == to) + font_translation_dictionary.remove(from); + else + font_translation_dictionary.lookup(from, (void *)to.contents()); + } + skip_line(); +} + +void font_position() +{ + int n; + if (get_integer(&n)) { + if (n < 0) + error("negative font position"); + else { + symbol internal_name = get_name(1); + if (!internal_name.is_null()) { + symbol external_name = get_long_name(0); + mount_font(n, internal_name, external_name); // ignore error + } + } + } + skip_line(); +} + +font_family::font_family(symbol s) +: nm(s), map_size(10) +{ + map = new int[map_size]; + for (int i = 0; i < map_size; i++) + map[i] = -1; +} + +font_family::~font_family() +{ + a_delete map; +} + +int font_family::make_definite(int i) +{ + if (i >= 0) { + if (i < map_size && map[i] >= 0) + return map[i]; + else { + if (i < font_table_size && font_table[i] != 0) { + if (i >= map_size) { + int old_map_size = map_size; + int *old_map = map; + map_size *= 3; + map_size /= 2; + if (i >= map_size) + map_size = i + 10; + map = new int[map_size]; + memcpy(map, old_map, old_map_size*sizeof(int)); + a_delete old_map; + for (int j = old_map_size; j < map_size; j++) + map[j] = -1; + } + if (font_table[i]->is_style()) { + symbol sty = font_table[i]->get_name(); + symbol f = concat(nm, sty); + int n; + // don't use symbol_fontno, because that might return a style + // and because we don't want to translate the name + for (n = 0; n < font_table_size; n++) + if (font_table[n] != 0 && font_table[n]->is_named(f) + && !font_table[n]->is_style()) + break; + if (n >= font_table_size) { + n = next_available_font_position(); + if (!mount_font_no_translate(n, f, f)) + return -1; + } + return map[i] = n; + } + else + return map[i] = i; + } + else + return -1; + } + } + else + return -1; +} + +dictionary family_dictionary(5); + +font_family *lookup_family(symbol nm) +{ + font_family *f = (font_family *)family_dictionary.lookup(nm); + if (!f) { + f = new font_family(nm); + (void)family_dictionary.lookup(nm, f); + } + return f; +} + +static void invalidate_fontno(int n) +{ + assert(n >= 0 && n < font_table_size); + dictionary_iterator iter(family_dictionary); + symbol nm; + font_family *fam; + while (iter.get(&nm, (void **)&fam)) { + int map_size = fam->map_size; + if (n < map_size) + fam->map[n] = -1; + for (int i = 0; i < map_size; i++) + if (fam->map[i] == n) + fam->map[i] = -1; + } +} + +void style() +{ + int n; + if (get_integer(&n)) { + if (n < 0) + error("negative font position"); + else { + symbol internal_name = get_name(1); + if (!internal_name.is_null()) + mount_style(n, internal_name); + } + } + skip_line(); +} + +static int get_fontno() +{ + int n; + tok.skip(); + if (tok.delimiter()) { + symbol s = get_name(1); + if (!s.is_null()) { + n = symbol_fontno(s); + if (n < 0) { + n = next_available_font_position(); + if (!mount_font(n, s)) + return -1; + } + return curenv->get_family()->make_definite(n); + } + } + else if (get_integer(&n)) { + if (n < 0 || n >= font_table_size || font_table[n] == 0) + error("bad font number"); + else + return curenv->get_family()->make_definite(n); + } + return -1; +} + +static int underline_fontno = 2; + +void underline_font() +{ + int n = get_fontno(); + if (n >= 0) + underline_fontno = n; + skip_line(); +} + +int get_underline_fontno() +{ + return underline_fontno; +} + +static void read_special_fonts(special_font_list **sp) +{ + special_font_list *s = *sp; + *sp = 0; + while (s != 0) { + special_font_list *tem = s; + s = s->next; + delete tem; + } + special_font_list **p = sp; + while (has_arg()) { + int i = get_fontno(); + if (i >= 0) { + special_font_list *tem = new special_font_list; + tem->n = i; + tem->next = 0; + *p = tem; + p = &(tem->next); + } + } +} + +void font_special_request() +{ + int n = get_fontno(); + if (n >= 0) + read_special_fonts(&font_table[n]->sf); + skip_line(); +} + + +void special_request() +{ + read_special_fonts(&global_special_fonts); + skip_line(); +} + +int next_available_font_position() +{ + for (int i = 1; i < font_table_size && font_table[i] != 0; i++) + ; + return i; +} + +int symbol_fontno(symbol s) +{ + s = get_font_translation(s); + for (int i = 0; i < font_table_size; i++) + if (font_table[i] != 0 && font_table[i]->is_named(s)) + return i; + return -1; +} + +int is_good_fontno(int n) +{ + return n >= 0 && n < font_table_size && font_table[n] != NULL; +} + +int get_bold_fontno(int n) +{ + if (n >= 0 && n < font_table_size && font_table[n] != 0) { + hunits offset; + if (font_table[n]->get_bold(&offset)) + return offset.to_units() + 1; + else + return 0; + } + else + return 0; +} + +hunits env_digit_width(environment *env) +{ + node *n = make_glyph_node(charset_table['0'], env); + if (n) { + hunits x = n->width(); + delete n; + return x; + } + else + return H0; +} + +hunits env_space_width(environment *env) +{ + int fn = env_definite_font(env); + font_size fs = env->get_font_size(); + if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) + return scale(fs.to_units()/3, env->get_space_size(), 12); + else + return font_table[fn]->get_space_width(fs, env->get_space_size()); +} + +hunits env_sentence_space_width(environment *env) +{ + int fn = env_definite_font(env); + font_size fs = env->get_font_size(); + if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) + return scale(fs.to_units()/3, env->get_sentence_space_size(), 12); + else + return font_table[fn]->get_space_width(fs, env->get_sentence_space_size()); +} + +hunits env_half_narrow_space_width(environment *env) +{ + int fn = env_definite_font(env); + font_size fs = env->get_font_size(); + if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) + return 0; + else + return font_table[fn]->get_half_narrow_space_width(fs); +} + +hunits env_narrow_space_width(environment *env) +{ + int fn = env_definite_font(env); + font_size fs = env->get_font_size(); + if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) + return 0; + else + return font_table[fn]->get_narrow_space_width(fs); +} + +void bold_font() +{ + int n = get_fontno(); + if (n >= 0) { + if (has_arg()) { + if (tok.delimiter()) { + int f = get_fontno(); + if (f >= 0) { + units offset; + if (has_arg() && get_number(&offset, 'u') && offset >= 1) + font_table[f]->set_conditional_bold(n, hunits(offset - 1)); + else + font_table[f]->conditional_unbold(n); + } + } + else { + units offset; + if (get_number(&offset, 'u') && offset >= 1) + font_table[n]->set_bold(hunits(offset - 1)); + else + font_table[n]->unbold(); + } + } + else + font_table[n]->unbold(); + } + skip_line(); +} + +track_kerning_function::track_kerning_function() : non_zero(0) +{ +} + +track_kerning_function::track_kerning_function(int min_s, hunits min_a, + int max_s, hunits max_a) + : non_zero(1), + min_size(min_s), min_amount(min_a), + max_size(max_s), max_amount(max_a) +{ +} + +int track_kerning_function::operator==(const track_kerning_function &tk) +{ + if (non_zero) + return (tk.non_zero + && min_size == tk.min_size + && min_amount == tk.min_amount + && max_size == tk.max_size + && max_amount == tk.max_amount); + else + return !tk.non_zero; +} + +int track_kerning_function::operator!=(const track_kerning_function &tk) +{ + if (non_zero) + return (!tk.non_zero + || min_size != tk.min_size + || min_amount != tk.min_amount + || max_size != tk.max_size + || max_amount != tk.max_amount); + else + return tk.non_zero; +} + +hunits track_kerning_function::compute(int size) +{ + if (non_zero) { + if (max_size <= min_size) + return min_amount; + else if (size <= min_size) + return min_amount; + else if (size >= max_size) + return max_amount; + else + return (scale(max_amount, size - min_size, max_size - min_size) + + scale(min_amount, max_size - size, max_size - min_size)); + } + else + return H0; +} + +void track_kern() +{ + int n = get_fontno(); + if (n >= 0) { + int min_s, max_s; + hunits min_a, max_a; + if (has_arg() + && get_number(&min_s, 'z') + && get_hunits(&min_a, 'p') + && get_number(&max_s, 'z') + && get_hunits(&max_a, 'p')) { + track_kerning_function tk(min_s, min_a, max_s, max_a); + font_table[n]->set_track_kern(tk); + } + else { + track_kerning_function tk; + font_table[n]->set_track_kern(tk); + } + } + skip_line(); +} + +void constant_space() +{ + int n = get_fontno(); + if (n >= 0) { + int x, y; + if (!has_arg() || !get_integer(&x)) + font_table[n]->set_constant_space(CONSTANT_SPACE_NONE); + else { + if (!has_arg() || !get_number(&y, 'z')) + font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x); + else + font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE, + scale(y*x, + units_per_inch, + 36*72*sizescale)); + } + } + skip_line(); +} + +void ligature() +{ + int lig; + if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2) + global_ligature_mode = lig; + else + global_ligature_mode = 1; + skip_line(); +} + +void kern_request() +{ + int k; + if (has_arg() && get_integer(&k)) + global_kern_mode = k != 0; + else + global_kern_mode = 1; + skip_line(); +} + +void set_soft_hyphen_char() +{ + soft_hyphen_char = get_optional_char(); + if (!soft_hyphen_char) + soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); + skip_line(); +} + +void init_output() +{ + if (suppress_output_flag) + the_output = new suppress_output_file; + else if (ascii_output_flag) + the_output = new ascii_output_file; + else + the_output = new troff_output_file; +} + +class next_available_font_position_reg : public reg { +public: + const char *get_string(); +}; + +const char *next_available_font_position_reg::get_string() +{ + return itoa(next_available_font_position()); +} + +class printing_reg : public reg { +public: + const char *get_string(); +}; + +const char *printing_reg::get_string() +{ + if (the_output) + return the_output->is_printing() ? "1" : "0"; + else + return "0"; +} + +void init_node_requests() +{ + init_request("fp", font_position); + init_request("sty", style); + init_request("cs", constant_space); + init_request("bd", bold_font); + init_request("uf", underline_font); + init_request("lg", ligature); + init_request("kern", kern_request); + init_request("tkf", track_kern); + init_request("special", special_request); + init_request("fspecial", font_special_request); + init_request("ftr", font_translate); + init_request("shc", set_soft_hyphen_char); + number_reg_dictionary.define(".fp", new next_available_font_position_reg); + number_reg_dictionary.define(".kern", + new constant_int_reg(&global_kern_mode)); + number_reg_dictionary.define(".lg", + new constant_int_reg(&global_ligature_mode)); + number_reg_dictionary.define(".P", new printing_reg); + soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); +} diff --git a/gnu/usr.bin/groff/troff/node.h b/gnu/usr.bin/groff/troff/node.h new file mode 100644 index 0000000000..02526e7c95 --- /dev/null +++ b/gnu/usr.bin/groff/troff/node.h @@ -0,0 +1,493 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +struct hyphen_list { + unsigned char hyphen; + unsigned char breakable; + unsigned char hyphenation_code; + hyphen_list *next; + hyphen_list(unsigned char code, hyphen_list *p = 0); +}; + +void hyphenate(hyphen_list *, unsigned); + +enum hyphenation_type { HYPHEN_MIDDLE, HYPHEN_BOUNDARY, HYPHEN_INHIBIT }; + +class ascii_output_file; + +struct breakpoint; +struct vertical_size; +struct charinfo; + +class macro; + +class troff_output_file; +class tfont; +class environment; + +class glyph_node; +class diverted_space_node; +class token_node; + +struct node { + node *next; + node(); + node(node *n); + node *add_char(charinfo *c, environment *, hunits *widthp); + + virtual ~node(); + virtual node *copy() = 0; + virtual hunits width(); + virtual hunits subscript_correction(); + virtual hunits italic_correction(); + virtual hunits left_italic_correction(); + virtual hunits skew(); + virtual int nspaces(); + virtual int merge_space(hunits); + virtual vunits vertical_width(); + virtual node *last_char_node(); + virtual void vertical_extent(vunits *min, vunits *max); + virtual int character_type(); + virtual void set_vertical_size(vertical_size *); + virtual int ends_sentence(); + virtual node *merge_self(node *); + virtual node *add_discretionary_hyphen(); + virtual node *add_self(node *, hyphen_list **); + virtual hyphen_list *get_hyphen_list(hyphen_list *s = 0); + virtual void ascii_print(ascii_output_file *); + virtual void asciify(macro *); + virtual int discardable(); + virtual void spread_space(int *, hunits *); + virtual void freeze_space(); + virtual breakpoint *get_breakpoints(hunits width, int nspaces, + breakpoint *rest = 0, + int is_inner = 0); + virtual int nbreaks(); + virtual void split(int, node **, node **); + virtual hyphenation_type get_hyphenation_type(); + virtual int reread(int *); + virtual token_node *get_token_node(); + virtual int overlaps_vertically(); + virtual int overlaps_horizontally(); + virtual units size(); + virtual int interpret(macro *); + + virtual node *merge_glyph_node(glyph_node *); + virtual tfont *get_tfont(); + virtual void tprint(troff_output_file *); + virtual void zero_width_tprint(troff_output_file *); + + node *add_italic_correction(hunits *); + + virtual int same(node *) = 0; + virtual const char *type() = 0; +}; + +inline node::node() : next(0) +{ +} + +inline node::node(node *n) : next(n) +{ +} + +inline node::~node() +{ +} + +// 0 means it doesn't, 1 means it does, 2 means it's transparent + +int node_list_ends_sentence(node *); + +struct breakpoint { + breakpoint *next; + hunits width; + int nspaces; + node *nd; + int index; + char hyphenated; +}; + +class line_start_node : public node { +public: + line_start_node() {} + node *copy() { return new line_start_node; } + int same(node *); + const char *type(); + void asciify(macro *); +}; + +class space_node : public node { +private: +#if 0 + enum { BLOCK = 1024 }; + static space_node *free_list; + void operator delete(void *); +#endif +protected: + hunits n; + char set; + space_node(hunits, int, node * = 0); +public: + space_node(hunits d, node *p = 0); +#if 0 + ~space_node(); + void *operator new(size_t); +#endif + node *copy(); + int nspaces(); + hunits width(); + int discardable(); + int merge_space(hunits); + void freeze_space(); + void spread_space(int*, hunits*); + void tprint(troff_output_file *); + breakpoint *get_breakpoints(hunits width, int nspaces, breakpoint *rest = 0, + int is_inner = 0); + int nbreaks(); + void split(int, node **, node **); + void ascii_print(ascii_output_file *); + int same(node *); + const char *type(); +}; + +class word_space_node : public space_node { +protected: + word_space_node(hunits, int, node * = 0); +public: + word_space_node(hunits, node * = 0); + node *copy(); + void tprint(troff_output_file *); + int same(node *); + const char *type(); +}; + +class unbreakable_space_node : public word_space_node { + unbreakable_space_node(hunits, int, node * = 0); +public: + unbreakable_space_node(hunits, node * = 0); + node *copy(); + int same(node *); + const char *type(); + breakpoint *get_breakpoints(hunits width, int nspaces, breakpoint *rest = 0, + int is_inner = 0); + int nbreaks(); + void split(int, node **, node **); + int merge_space(hunits); +}; + +class diverted_space_node : public node { +public: + vunits n; + diverted_space_node(vunits d, node *p = 0); + node *copy(); + int reread(int *); + int same(node *); + const char *type(); +}; + +class diverted_copy_file_node : public node { + symbol filename; +public: + vunits n; + diverted_copy_file_node(symbol s, node *p = 0); + node *copy(); + int reread(int *); + int same(node *); + const char *type(); +}; + +class extra_size_node : public node { + vunits n; + public: + extra_size_node(vunits i) : n(i) {} + void set_vertical_size(vertical_size *); + node *copy(); + int same(node *); + const char *type(); +}; + +class vertical_size_node : public node { + vunits n; + public: + vertical_size_node(vunits i) : n(i) {} + void set_vertical_size(vertical_size *); + void asciify(macro *); + node *copy(); + int same(node *); + const char *type(); +}; + +class hmotion_node : public node { +protected: + hunits n; +public: + hmotion_node(hunits i, node *next = 0) : node(next), n(i) {} + node *copy(); + void tprint(troff_output_file *); + hunits width(); + void ascii_print(ascii_output_file *); + int same(node *); + const char *type(); +}; + +class space_char_hmotion_node : public hmotion_node { +public: + space_char_hmotion_node(hunits i, node *next = 0); + node *copy(); + void ascii_print(ascii_output_file *); + void asciify(macro *); + int same(node *); + const char *type(); +}; + +class vmotion_node : public node { + vunits n; + public: + vmotion_node(vunits i) : n(i) {} + void tprint(troff_output_file *); + node *copy(); + vunits vertical_width(); + int same(node *); + const char *type(); +}; + + +class hline_node : public node { + hunits x; + node *n; + public: + hline_node(hunits i, node *c, node *next = 0) : node(next), x(i), n(c) {} + ~hline_node(); + node *copy(); + hunits width(); + void tprint(troff_output_file *); + int same(node *); + const char *type(); +}; + +class vline_node : public node { + vunits x; + node *n; + public: + vline_node(vunits i, node *c, node *next= 0) : node(next), x(i), n(c) {} + ~vline_node(); + node *copy(); + void tprint(troff_output_file *); + hunits width(); + vunits vertical_width(); + void vertical_extent(vunits *, vunits *); + int same(node *); + const char *type(); +}; + + +class dummy_node : public node { + public: + dummy_node(node *nd = 0) : node(nd) {} + node *copy(); + int same(node *); + const char *type(); + hyphenation_type get_hyphenation_type(); +}; + +class transparent_dummy_node : public node { +public: + transparent_dummy_node() {} + node *copy(); + int same(node *); + const char *type(); + int ends_sentence(); + hyphenation_type get_hyphenation_type(); +}; + +class zero_width_node : public node { + node *n; + public: + zero_width_node(node *gn); + ~zero_width_node(); + node *copy(); + void tprint(troff_output_file *); + int same(node *); + const char *type(); + void append(node *); + int character_type(); + void vertical_extent(vunits *min, vunits *max); +}; + +class left_italic_corrected_node : public node { + node *n; + hunits x; +public: + left_italic_corrected_node(node * = 0); + ~left_italic_corrected_node(); + void tprint(troff_output_file *); + void ascii_print(ascii_output_file *); + void asciify(macro *); + node *copy(); + int same(node *); + const char *type(); + hunits width(); + node *last_char_node(); + void vertical_extent(vunits *, vunits *); + int ends_sentence(); + int overlaps_horizontally(); + int overlaps_vertically(); + hyphenation_type get_hyphenation_type(); + tfont *get_tfont(); + int character_type(); + hunits skew(); + hunits italic_correction(); + hunits subscript_correction(); + hyphen_list *get_hyphen_list(hyphen_list *ss = 0); + node *add_self(node *, hyphen_list **); + node *merge_glyph_node(glyph_node *); +}; + +class overstrike_node : public node { + node *list; + hunits max_width; +public: + overstrike_node(); + ~overstrike_node(); + node *copy(); + void tprint(troff_output_file *); + void overstrike(node *); // add another node to be overstruck + hunits width(); + int same(node *); + const char *type(); +}; + +class bracket_node : public node { + node *list; + hunits max_width; +public: + bracket_node(); + ~bracket_node(); + node *copy(); + void tprint(troff_output_file *); + void bracket(node *); // add another node to be overstruck + hunits width(); + int same(node *); + const char *type(); +}; + +class special_node : public node { + macro mac; + void tprint_start(troff_output_file *); + void tprint_char(troff_output_file *, unsigned char); + void tprint_end(troff_output_file *); +public: + special_node(const macro &); + node *copy(); + void tprint(troff_output_file *); + int same(node *); + const char *type(); +}; + + +struct hvpair { + hunits h; + vunits v; + + hvpair(); +}; + +class draw_node : public node { + int npoints; + font_size sz; + char code; + hvpair *point; +public: + draw_node(char, hvpair *, int, font_size); + ~draw_node(); + hunits width(); + vunits vertical_width(); + node *copy(); + void tprint(troff_output_file *); + int same(node *); + const char *type(); +}; + +class charinfo; +node *make_node(charinfo *ci, environment *); +int character_exists(charinfo *, environment *); + +int same_node_list(node *n1, node *n2); +node *reverse_node_list(node *n); +void delete_node_list(node *); +node *copy_node_list(node *); + +int get_bold_fontno(int f); + +inline hyphen_list::hyphen_list(unsigned char code, hyphen_list *p) +: hyphenation_code(code), next(p), hyphen(0), breakable(0) +{ +} + +extern void read_desc(); +extern int mount_font(int n, symbol, symbol = NULL_SYMBOL); +extern void mount_style(int n, symbol); +extern int is_good_fontno(int n); +extern int symbol_fontno(symbol); +extern int next_available_font_position(); +extern void init_size_table(int *); +extern int get_underline_fontno(); + +class output_file { + char make_g_plus_plus_shut_up; +public: + output_file(); + virtual ~output_file(); + virtual void trailer(vunits page_length); + virtual void flush() = 0; + virtual void transparent_char(unsigned char) = 0; + virtual void print_line(hunits x, vunits y, node *n, + vunits before, vunits after) = 0; + virtual void begin_page(int pageno, vunits page_length) = 0; + virtual void copy_file(hunits x, vunits y, const char *filename) = 0; + virtual int is_printing() = 0; +#ifdef COLUMN + virtual void vjustify(vunits, symbol); +#endif /* COLUMN */ +}; + +extern char *pipe_command; + +extern output_file *the_output; +extern void init_output(); +int in_output_page_list(int n); + +static void invalidate_fontno(int); + +class font_family { + int *map; + int map_size; +public: + const symbol nm; + + font_family(symbol); + ~font_family(); + make_definite(int); + friend void invalidate_fontno(int); +}; + +font_family *lookup_family(symbol); diff --git a/gnu/usr.bin/groff/troff/number.cc b/gnu/usr.bin/groff/troff/number.cc new file mode 100644 index 0000000000..3e695b527a --- /dev/null +++ b/gnu/usr.bin/groff/troff/number.cc @@ -0,0 +1,669 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "troff.h" +#include "symbol.h" +#include "hvunits.h" +#include "env.h" +#include "token.h" +#include "div.h" + +vunits V0; +hunits H0; + +int hresolution = 1; +int vresolution = 1; +int units_per_inch; +int sizescale; + +static int parse_expr(units *v, int scale_indicator, int parenthesised); +static int start_number(); + +int get_vunits(vunits *res, unsigned char si) +{ + if (!start_number()) + return 0; + units x; + if (parse_expr(&x, si, 0)) { + *res = vunits(x); + return 1; + } + else + return 0; +} + +int get_hunits(hunits *res, unsigned char si) +{ + if (!start_number()) + return 0; + units x; + if (parse_expr(&x, si, 0)) { + *res = hunits(x); + return 1; + } + else + return 0; +} + +int get_number(units *res, unsigned char si) +{ + if (!start_number()) + return 0; + units x; + if (parse_expr(&x, si, 0)) { + *res = x; + return 1; + } + else + return 0; +} + +int get_integer(int *res) +{ + if (!start_number()) + return 0; + units x; + if (parse_expr(&x, 0, 0)) { + *res = x; + return 1; + } + else + return 0; +} + +enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT }; + +static incr_number_result get_incr_number(units *res, unsigned char); + +int get_vunits(vunits *res, unsigned char si, vunits prev_value) +{ + units v; + switch (get_incr_number(&v, si)) { + case BAD: + return 0; + case ABSOLUTE: + *res = v; + break; + case INCREMENT: + *res = prev_value + v; + break; + case DECREMENT: + *res = prev_value - v; + break; + default: + assert(0); + } + return 1; +} + +int get_hunits(hunits *res, unsigned char si, hunits prev_value) +{ + units v; + switch (get_incr_number(&v, si)) { + case BAD: + return 0; + case ABSOLUTE: + *res = v; + break; + case INCREMENT: + *res = prev_value + v; + break; + case DECREMENT: + *res = prev_value - v; + break; + default: + assert(0); + } + return 1; +} + +int get_number(units *res, unsigned char si, units prev_value) +{ + units v; + switch (get_incr_number(&v, si)) { + case BAD: + return 0; + case ABSOLUTE: + *res = v; + break; + case INCREMENT: + *res = prev_value + v; + break; + case DECREMENT: + *res = prev_value - v; + break; + default: + assert(0); + } + return 1; +} + +int get_integer(int *res, int prev_value) +{ + units v; + switch (get_incr_number(&v, 0)) { + case BAD: + return 0; + case ABSOLUTE: + *res = v; + break; + case INCREMENT: + *res = prev_value + int(v); + break; + case DECREMENT: + *res = prev_value - int(v); + break; + default: + assert(0); + } + return 1; +} + + +static incr_number_result get_incr_number(units *res, unsigned char si) +{ + if (!start_number()) + return BAD; + incr_number_result result = ABSOLUTE; + if (tok.ch() == '+') { + tok.next(); + result = INCREMENT; + } + else if (tok.ch() == '-') { + tok.next(); + result = DECREMENT; + } + if (parse_expr(res, si, 0)) + return result; + else + return BAD; +} + +static int start_number() +{ + while (tok.space()) + tok.next(); + if (tok.newline()) { + warning(WARN_MISSING, "missing number"); + return 0; + } + if (tok.tab()) { + warning(WARN_TAB, "tab character where number expected"); + return 0; + } + if (tok.right_brace()) { + warning(WARN_RIGHT_BRACE, "`\\}' where number expected"); + return 0; + } + return 1; +} + +enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' }; + +#define SCALE_INDICATOR_CHARS "icPmnpuvMsz" + +static int parse_term(units *v, int scale_indicator, int parenthesised); + +static int parse_expr(units *v, int scale_indicator, int parenthesised) +{ + int result = parse_term(v, scale_indicator, parenthesised); + while (result) { + if (parenthesised) + tok.skip(); + int op = tok.ch(); + switch (op) { + case '+': + case '-': + case '/': + case '*': + case '%': + case ':': + case '&': + tok.next(); + break; + case '>': + tok.next(); + if (tok.ch() == '=') { + tok.next(); + op = OP_GEQ; + } + else if (tok.ch() == '?') { + tok.next(); + op = OP_MAX; + } + break; + case '<': + tok.next(); + if (tok.ch() == '=') { + tok.next(); + op = OP_LEQ; + } + else if (tok.ch() == '?') { + tok.next(); + op = OP_MIN; + } + break; + case '=': + tok.next(); + if (tok.ch() == '=') + tok.next(); + break; + default: + return result; + } + units v2; + if (!parse_term(&v2, scale_indicator, parenthesised)) + return 0; + int overflow = 0; + switch (op) { + case '<': + *v = *v < v2; + break; + case '>': + *v = *v > v2; + break; + case OP_LEQ: + *v = *v <= v2; + break; + case OP_GEQ: + *v = *v >= v2; + break; + case OP_MIN: + if (*v > v2) + *v = v2; + break; + case OP_MAX: + if (*v < v2) + *v = v2; + break; + case '=': + *v = *v == v2; + break; + case '&': + *v = *v > 0 && v2 > 0; + break; + case ':': + *v = *v > 0 || v2 > 0; + case '+': + if (v2 < 0) { + if (*v < INT_MIN - v2) + overflow = 1; + } + else if (v2 > 0) { + if (*v > INT_MAX - v2) + overflow = 1; + } + if (overflow) { + error("addition overflow"); + return 0; + } + *v += v2; + break; + case '-': + if (v2 < 0) { + if (*v > INT_MAX + v2) + overflow = 1; + } + else if (v2 > 0) { + if (*v < INT_MIN + v2) + overflow = 1; + } + if (overflow) { + error("subtraction overflow"); + return 0; + } + *v -= v2; + break; + case '*': + if (v2 < 0) { + if (*v > 0) { + if (*v > -(unsigned)INT_MIN / -(unsigned)v2) + overflow = 1; + } + else if (-(unsigned)*v > INT_MAX / -(unsigned)v2) + overflow = 1; + } + else if (v2 > 0) { + if (*v > 0) { + if (*v > INT_MAX / v2) + overflow = 1; + } + else if (-(unsigned)*v > -(unsigned)INT_MIN / v2) + overflow = 1; + } + if (overflow) { + error("multiplication overflow"); + return 0; + } + *v *= v2; + break; + case '/': + if (v2 == 0) { + error("division by zero"); + return 0; + } + *v /= v2; + break; + case '%': + if (v2 == 0) { + error("modulus by zero"); + return 0; + } + *v %= v2; + break; + default: + assert(0); + } + } + return result; +} + +static int parse_term(units *v, int scale_indicator, int parenthesised) +{ + int negative = 0; + for (;;) + if (parenthesised && tok.space()) + tok.next(); + else if (tok.ch() == '+') + tok.next(); + else if (tok.ch() == '-') { + tok.next(); + negative = !negative; + } + else + break; + unsigned char c = tok.ch(); + switch (c) { + case '|': + // | is not restricted to the outermost level + // tbl uses this + tok.next(); + if (!parse_term(v, scale_indicator, parenthesised)) + return 0; + int tem; + tem = (scale_indicator == 'v' + ? curdiv->get_vertical_position().to_units() + : curenv->get_input_line_position().to_units()); + if (tem >= 0) { + if (*v < INT_MIN + tem) { + error("numeric overflow"); + return 0; + } + } + else { + if (*v > INT_MAX + tem) { + error("numeric overflow"); + return 0; + } + } + *v -= tem; + if (negative) { + if (*v == INT_MIN) { + error("numeric overflow"); + return 0; + } + *v = -*v; + } + return 1; + case '(': + tok.next(); + c = tok.ch(); + if (c == ')') { + warning(WARN_SYNTAX, "empty parentheses"); + tok.next(); + *v = 0; + return 1; + } + else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) { + tok.next(); + if (tok.ch() == ';') { + tok.next(); + scale_indicator = c; + } + else { + error("expected `;' after scale-indicator (got %1)", + tok.description()); + return 0; + } + } + else if (c == ';') { + scale_indicator = 0; + tok.next(); + } + if (!parse_expr(v, scale_indicator, 1)) + return 0; + tok.skip(); + if (tok.ch() != ')') { + warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description()); + } + else + tok.next(); + if (negative) { + if (*v == INT_MIN) { + error("numeric overflow"); + return 0; + } + *v = -*v; + } + return 1; + case '.': + *v = 0; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + *v = 0; + do { + if (*v > INT_MAX/10) { + error("numeric overflow"); + return 0; + } + *v *= 10; + if (*v > INT_MAX - (int(c) - '0')) { + error("numeric overflow"); + return 0; + } + *v += c - '0'; + tok.next(); + c = tok.ch(); + } while (csdigit(c)); + break; + case '/': + case '*': + case '%': + case ':': + case '&': + case '>': + case '<': + case '=': + warning(WARN_SYNTAX, "empty left operand"); + *v = 0; + return 1; + default: + warning(WARN_NUMBER, "numeric expression expected (got %1)", + tok.description()); + return 0; + } + int divisor = 1; + if (tok.ch() == '.') { + tok.next(); + for (;;) { + c = tok.ch(); + if (!csdigit(c)) + break; + // we may multiply the divisor by 254 later on + if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) { + *v *= 10; + *v += c - '0'; + divisor *= 10; + } + tok.next(); + } + } + int si = scale_indicator; + int do_next = 0; + if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) { + switch (scale_indicator) { + case 'z': + if (c != 'u' && c != 'z') { + warning(WARN_SCALE, + "only `z' and `u' scale indicators valid in this context"); + break; + } + si = c; + break; + case 0: + warning(WARN_SCALE, "scale indicator invalid in this context"); + break; + case 'u': + si = c; + break; + default: + if (c == 'z') { + warning(WARN_SCALE, "`z' scale indicator invalid in this context"); + break; + } + si = c; + break; + } + // Don't do tok.next() here because the next token might be \s, which + // would affect the interpretation of m. + do_next = 1; + } + switch (si) { + case 'i': + *v = scale(*v, units_per_inch, divisor); + break; + case 'c': + *v = scale(*v, units_per_inch*100, divisor*254); + break; + case 0: + case 'u': + if (divisor != 1) + *v /= divisor; + break; + case 'p': + *v = scale(*v, units_per_inch, divisor*72); + break; + case 'P': + *v = scale(*v, units_per_inch, divisor*6); + break; + case 'm': + { + // Convert to hunits so that with -Tascii `m' behaves as in nroff. + hunits em = curenv->get_size(); + *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor); + } + break; + case 'M': + { + hunits em = curenv->get_size(); + *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100); + } + break; + case 'n': + { + // Convert to hunits so that with -Tascii `n' behaves as in nroff. + hunits en = curenv->get_size()/2; + *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor); + } + break; + case 'v': + *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor); + break; + case 's': + while (divisor > INT_MAX/(sizescale*72)) { + divisor /= 10; + *v /= 10; + } + *v = scale(*v, units_per_inch, divisor*sizescale*72); + break; + case 'z': + *v = scale(*v, sizescale, divisor); + break; + default: + assert(0); + } + if (do_next) + tok.next(); + if (negative) { + if (*v == INT_MIN) { + error("numeric overflow"); + return 0; + } + *v = -*v; + } + return 1; +} + +units scale(units n, units x, units y) +{ + assert(x >= 0 && y > 0); + if (x == 0) + return 0; + if (n >= 0) { + if (n <= INT_MAX/x) + return (n*x)/y; + } + else { + if (-(unsigned)n <= -(unsigned)INT_MIN/x) + return (n*x)/y; + } + double res = n*double(x)/double(y); + if (res > INT_MAX) { + error("numeric overflow"); + return INT_MAX; + } + else if (res < INT_MIN) { + error("numeric overflow"); + return INT_MIN; + } + return int(res); +} + +vunits::vunits(units x) +{ + // don't depend on the rounding direction for division of negative integers + if (vresolution == 1) + n = x; + else + n = (x < 0 + ? -((-x + vresolution/2 - 1)/vresolution) + : (x + vresolution/2 - 1)/vresolution); +} + +hunits::hunits(units x) +{ + // don't depend on the rounding direction for division of negative integers + if (hresolution == 1) + n = x; + else + n = (x < 0 + ? -((-x + hresolution/2 - 1)/hresolution) + : (x + hresolution/2 - 1)/hresolution); +} diff --git a/gnu/usr.bin/groff/troff/reg.cc b/gnu/usr.bin/groff/troff/reg.cc new file mode 100644 index 0000000000..cefeb87ed5 --- /dev/null +++ b/gnu/usr.bin/groff/troff/reg.cc @@ -0,0 +1,458 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "troff.h" +#include "symbol.h" +#include "dictionary.h" +#include "token.h" +#include "request.h" +#include "reg.h" + +object_dictionary number_reg_dictionary(101); + +int reg::get_value(units * /*d*/) +{ + return 0; +} + +void reg::increment() +{ + error("can't increment read-only register"); +} + +void reg::decrement() +{ + error("can't decrement read-only register"); +} + +void reg::set_increment(units /*n*/) +{ + error("can't auto increment read-only register"); +} + +void reg::alter_format(char /*f*/, int /*w*/) +{ + error("can't alter format of read-only register"); +} + +const char *reg::get_format() +{ + return "0"; +} + +void reg::set_value(units /*n*/) +{ + error("can't write read-only register"); +} + +general_reg::general_reg() : format('1'), width(0), inc(0) +{ +} + +static const char *number_value_to_ascii(int value, char format, int width) +{ + static char buf[128]; // must be at least 21 + switch(format) { + case '1': + if (width <= 0) + return itoa(value); + else if (width > sizeof(buf) - 2) + sprintf(buf, "%.*d", sizeof(buf) - 2, int(value)); + else + sprintf(buf, "%.*d", width, int(value)); + break; + case 'i': + case 'I': + { + char *p = buf; + // troff uses z and w to represent 10000 and 5000 in Roman + // numerals; I can find no historical basis for this usage + const char *s = format == 'i' ? "zwmdclxvi" : "ZWMDCLXVI"; + int n = int(value); + if (n >= 40000 || n <= -40000) { + error("magnitude of `%1' too big for i or I format", n); + return itoa(n); + } + if (n == 0) { + *p++ = '0'; + *p = 0; + break; + } + if (n < 0) { + *p++ = '-'; + n = -n; + } + while (n >= 10000) { + *p++ = s[0]; + n -= 10000; + } + for (int i = 1000; i > 0; i /= 10, s += 2) { + int m = n/i; + n -= m*i; + switch (m) { + case 3: + *p++ = s[2]; + /* falls through */ + case 2: + *p++ = s[2]; + /* falls through */ + case 1: + *p++ = s[2]; + break; + case 4: + *p++ = s[2]; + *p++ = s[1]; + break; + case 8: + *p++ = s[1]; + *p++ = s[2]; + *p++ = s[2]; + *p++ = s[2]; + break; + case 7: + *p++ = s[1]; + *p++ = s[2]; + *p++ = s[2]; + break; + case 6: + *p++ = s[1]; + *p++ = s[2]; + break; + case 5: + *p++ = s[1]; + break; + case 9: + *p++ = s[2]; + *p++ = s[0]; + } + } + *p = 0; + break; + } + case 'a': + case 'A': + { + int n = value; + char *p = buf; + if (n == 0) { + *p++ = '0'; + *p = 0; + } + else { + if (n < 0) { + n = -n; + *p++ = '-'; + } + // this is a bit tricky + while (n > 0) { + int d = n % 26; + if (d == 0) + d = 26; + n -= d; + n /= 26; + *p++ = format + d - 1; + } + *p-- = 0; + char *q = buf[0] == '-' ? buf+1 : buf; + while (q < p) { + char temp = *q; + *q = *p; + *p = temp; + --p; + ++q; + } + } + break; + } + default: + assert(0); + break; + } + return buf; +} + +const char *general_reg::get_string() +{ + units n; + if (!get_value(&n)) + return ""; + return number_value_to_ascii(n, format, width); +} + + +void general_reg::increment() +{ + int n; + if (get_value(&n)) + set_value(n + inc); +} + +void general_reg::decrement() +{ + int n; + if (get_value(&n)) + set_value(n - inc); +} + +void general_reg::set_increment(units n) +{ + inc = n; +} + +void general_reg::alter_format(char f, int w) +{ + format = f; + width = w; +} + +static const char *number_format_to_ascii(char format, int width) +{ + static char buf[24]; + if (format == '1') { + if (width > 0) { + int n = width; + if (n > int(sizeof(buf)) - 1) + n = int(sizeof(buf)) - 1; + sprintf(buf, "%.*d", n, 0); + return buf; + } + else + return "0"; + } + else { + buf[0] = format; + buf[1] = '\0'; + return buf; + } +} + +const char *general_reg::get_format() +{ + return number_format_to_ascii(format, width); +} + +class number_reg : public general_reg { + units value; +public: + number_reg(); + int get_value(units *); + void set_value(units); +}; + +number_reg::number_reg() : value(0) +{ +} + +int number_reg::get_value(units *res) +{ + *res = value; + return 1; +} + +void number_reg::set_value(units n) +{ + value = n; +} + +variable_reg::variable_reg(units *p) : ptr(p) +{ +} + +void variable_reg::set_value(units n) +{ + *ptr = n; +} + +int variable_reg::get_value(units *res) +{ + *res = *ptr; + return 1; +} + +void define_number_reg() +{ + symbol nm = get_name(1); + if (nm.is_null()) { + skip_line(); + return; + } + reg *r = (reg *)number_reg_dictionary.lookup(nm); + units v; + units prev_value; + if (!r || !r->get_value(&prev_value)) + prev_value = 0; + if (get_number(&v, 'u', prev_value)) { + if (r == 0) { + r = new number_reg; + number_reg_dictionary.define(nm, r); + } + r->set_value(v); + if (tok.space() && has_arg() && get_number(&v, 'u')) + r->set_increment(v); + } + skip_line(); +} + +#if 0 +void inline_define_reg() +{ + token start; + start.next(); + if (!start.delimiter(1)) + return; + tok.next(); + symbol nm = get_name(1); + if (nm.is_null()) + return; + reg *r = (reg *)number_reg_dictionary.lookup(nm); + if (r == 0) { + r = new number_reg; + number_reg_dictionary.define(nm, r); + } + units v; + units prev_value; + if (!r->get_value(&prev_value)) + prev_value = 0; + if (get_number(&v, 'u', prev_value)) { + r->set_value(v); + if (start != tok) { + if (get_number(&v, 'u')) { + r->set_increment(v); + if (start != tok) + warning(WARN_DELIM, "closing delimiter does not match"); + } + } + } +} +#endif + +void set_number_reg(symbol nm, units n) +{ + reg *r = (reg *)number_reg_dictionary.lookup(nm); + if (r == 0) { + r = new number_reg; + number_reg_dictionary.define(nm, r); + } + r->set_value(n); +} + +reg *lookup_number_reg(symbol nm) +{ + reg *r = (reg *)number_reg_dictionary.lookup(nm); + if (r == 0) { + warning(WARN_REG, "number register `%1' not defined", nm.contents()); + r = new number_reg; + number_reg_dictionary.define(nm, r); + } + return r; +} + +void alter_format() +{ + symbol nm = get_name(1); + if (nm.is_null()) { + skip_line(); + return; + } + reg *r = (reg *)number_reg_dictionary.lookup(nm); + if (r == 0) { + r = new number_reg; + number_reg_dictionary.define(nm, r); + } + tok.skip(); + char c = tok.ch(); + if (csdigit(c)) { + int n = 0; + do { + ++n; + tok.next(); + } while (csdigit(tok.ch())); + r->alter_format('1', n); + } + else if (c == 'i' || c == 'I' || c == 'a' || c == 'A') + r->alter_format(c); + else if (tok.newline() || tok.eof()) + warning(WARN_MISSING, "missing number register format"); + else + error("bad number register format (got %1)", tok.description()); + skip_line(); +} + +void remove_reg() +{ + for (;;) { + symbol s = get_name(); + if (s.is_null()) + break; + number_reg_dictionary.remove(s); + } + skip_line(); +} + +void alias_reg() +{ + symbol s1 = get_name(1); + if (!s1.is_null()) { + symbol s2 = get_name(1); + if (!s2.is_null()) { + if (!number_reg_dictionary.alias(s1, s2)) + warning(WARN_REG, "number register `%1' not defined", s2.contents()); + } + } + skip_line(); +} + +void rename_reg() +{ + symbol s1 = get_name(1); + if (!s1.is_null()) { + symbol s2 = get_name(1); + if (!s2.is_null()) + number_reg_dictionary.rename(s1, s2); + } + skip_line(); +} + +void print_number_regs() +{ + object_dictionary_iterator iter(number_reg_dictionary); + reg *r; + symbol s; + while (iter.get(&s, (object **)&r)) { + assert(!s.is_null()); + errprint("%1\t", s.contents()); + const char *p = r->get_string(); + if (p) + errprint(p); + errprint("\n"); + } + fflush(stderr); + skip_line(); +} + +void init_reg_requests() +{ + init_request("rr", remove_reg); + init_request("nr", define_number_reg); + init_request("af", alter_format); + init_request("aln", alias_reg); + init_request("rnn", rename_reg); + init_request("pnr", print_number_regs); +} diff --git a/gnu/usr.bin/groff/troff/reg.h b/gnu/usr.bin/groff/troff/reg.h new file mode 100644 index 0000000000..4ecbc97960 --- /dev/null +++ b/gnu/usr.bin/groff/troff/reg.h @@ -0,0 +1,73 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +class reg : public object { +public: + virtual const char *get_string() = 0; + virtual int get_value(units *); + virtual void increment(); + virtual void decrement(); + virtual void set_increment(units); + virtual void alter_format(char f, int w = 0); + virtual const char *get_format(); + virtual void set_value(units); +}; + +class constant_int_reg : public reg { + int *p; +public: + constant_int_reg(int *); + const char *get_string(); +}; + +class general_reg : public reg { + char format; + int width; + int inc; +public: + general_reg(); + const char *get_string(); + void increment(); + void decrement(); + void alter_format(char f, int w = 0); + void set_increment(units); + const char *get_format(); + void add_value(units); + + void set_value(units) = 0; + int get_value(units *) = 0; +}; + +class variable_reg : public general_reg { + units *ptr; +public: + variable_reg(int *); + void set_value(units); + int get_value(units *); +}; + +extern object_dictionary number_reg_dictionary; +extern void set_number_reg(symbol nm, units n); + +reg *lookup_number_reg(symbol); +#if 0 +void inline_define_reg(); +#endif diff --git a/gnu/usr.bin/groff/troff/request.h b/gnu/usr.bin/groff/troff/request.h new file mode 100644 index 0000000000..2de9fb7c77 --- /dev/null +++ b/gnu/usr.bin/groff/troff/request.h @@ -0,0 +1,80 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +typedef void (*REQUEST_FUNCP)(); + +class macro; + +class request_or_macro : public object { +public: + request_or_macro(); + virtual void invoke(symbol s) = 0; + virtual macro *to_macro(); +}; + +class request : public request_or_macro { + REQUEST_FUNCP p; +public: + void invoke(symbol); + request(REQUEST_FUNCP); +}; + +void delete_request_or_macro(request_or_macro *); + +extern object_dictionary request_dictionary; + +struct macro_header; +struct node; + +class macro : public request_or_macro { + macro_header *p; + const char *filename; // where was it defined? + int lineno; + int length; +public: + macro(); + ~macro(); + macro(const macro &); + macro &operator=(const macro &); + void append(unsigned char); + void append(node *); + void invoke(symbol); + macro *to_macro(); + void print_size(); + int empty(); + friend class string_iterator; + friend void chop_macro(); + friend int operator==(const macro &, const macro &); +}; + +extern void init_input_requests(); +extern void init_div_requests(); +extern void init_node_requests(); +extern void init_reg_requests(); +extern void init_env_requests(); +extern void init_hyphen_requests(); +extern void init_request(const char *s, REQUEST_FUNCP f); + +extern int no_break_flag; // indicates whether request was invoked with . or ' + +class charinfo; +class environment; + +node *charinfo_to_node_list(charinfo *, const environment *); diff --git a/gnu/usr.bin/groff/troff/symbol.cc b/gnu/usr.bin/groff/troff/symbol.cc new file mode 100644 index 0000000000..eb816990d1 --- /dev/null +++ b/gnu/usr.bin/groff/troff/symbol.cc @@ -0,0 +1,144 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "troff.h" +#include "symbol.h" + +const char **symbol::table = 0; +int symbol::table_used = 0; +int symbol::table_size = 0; +char *symbol::block = 0; +int symbol::block_size = 0; + +const symbol NULL_SYMBOL; + +#ifdef BLOCK_SIZE +#undef BLOCK_SIZE +#endif + +const int BLOCK_SIZE = 1024; +// the table will increase in size as necessary +// the size will be chosen from the following array +// add some more if you want +// I think it unlikely that we'll need more than a million symbols +static const unsigned int table_sizes[] = { +101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021, 160001, 500009, 1000003, 0 +}; +const double FULL_MAX = 0.3; // don't let the table get more than this full + +static unsigned int hash_string(const char *p) +{ + // compute a hash code; this assumes 32-bit unsigned ints + // see p436 of Compilers by Aho, Sethi & Ullman + // give special treatment to two-character names + unsigned int hc = 0, g; + if (*p != 0) { + hc = *p++; + if (*p != 0) { + hc <<= 7; + hc += *p++; + for (; *p != 0; p++) { + hc <<= 4; + hc += *p; + if ((g = (hc & 0xf0000000)) == 0) { + hc ^= g >> 24; + hc ^= g; + } + } + } + } + return hc; +} + +symbol::symbol(const char *p, int how) +{ + if (p == 0 || *p == 0) { + s = 0; + return; + } + if (table == 0) { + table_size = table_sizes[0]; + table = (const char **)new char*[table_size]; + for (int i = 0; i < table_size; i++) + table[i] = 0; + table_used = 0; + } + unsigned int hc = hash_string(p); + for (const char **pp = table + hc % table_size; + *pp != 0; + (pp == table ? pp = table + table_size - 1 : --pp)) + if (strcmp(p, *pp) == 0) { + s = *pp; + return; + } + if (how == MUST_ALREADY_EXIST) { + s = 0; + return; + } + if (table_used >= table_size - 1 || table_used >= table_size*FULL_MAX) { + const char **old_table = table; + unsigned int old_table_size = table_size; + for (int i = 1; table_sizes[i] <= old_table_size; i++) + if (table_sizes[i] == 0) + fatal("too many symbols"); + table_size = table_sizes[i]; + table_used = 0; + table = (const char **)new char*[table_size]; + for (i = 0; i < table_size; i++) + table[i] = 0; + for (pp = old_table + old_table_size - 1; + pp >= old_table; + --pp) { + symbol temp(*pp, 1); /* insert it into the new table */ + } + a_delete old_table; + for (pp = table + hc % table_size; + *pp != 0; + (pp == table ? pp = table + table_size - 1 : --pp)) + ; + } + ++table_used; + if (how == DONT_STORE) { + s = *pp = p; + } + else { + int len = strlen(p)+1; + if (block == 0 || block_size < len) { + block_size = len > BLOCK_SIZE ? len : BLOCK_SIZE; + block = new char [block_size]; + } + (void)strcpy(block, p); + s = *pp = block; + block += len; + block_size -= len; + } +} + +symbol concat(symbol s1, symbol s2) +{ + char *buf = new char [strlen(s1.contents()) + strlen(s2.contents()) + 1]; + strcpy(buf, s1.contents()); + strcat(buf, s2.contents()); + symbol res(buf); + a_delete buf; + return res; +} + diff --git a/gnu/usr.bin/groff/troff/symbol.h b/gnu/usr.bin/groff/troff/symbol.h new file mode 100644 index 0000000000..37916742de --- /dev/null +++ b/gnu/usr.bin/groff/troff/symbol.h @@ -0,0 +1,73 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define DONT_STORE 1 +#define MUST_ALREADY_EXIST 2 + +class symbol { + static const char **table; + static int table_used; + static int table_size; + static char *block; + static int block_size; + const char *s; +public: + symbol(const char *p, int how = 0); + symbol(); + unsigned long hash() const; + operator ==(symbol) const; + operator !=(symbol) const; + const char *contents() const; + int is_null() const; +}; + + +extern const symbol NULL_SYMBOL; + +inline symbol::symbol() : s(0) +{ +} + +inline int symbol::operator==(symbol p) const +{ + return s == p.s; +} + +inline int symbol::operator!=(symbol p) const +{ + return s != p.s; +} + +inline unsigned long symbol::hash() const +{ + return (unsigned long)s; +} + +inline const char *symbol::contents() const +{ + return s; +} + +inline int symbol::is_null() const +{ + return s == 0; +} + +symbol concat(symbol, symbol); diff --git a/gnu/usr.bin/groff/troff/token.h b/gnu/usr.bin/groff/troff/token.h new file mode 100644 index 0000000000..486c6eafde --- /dev/null +++ b/gnu/usr.bin/groff/troff/token.h @@ -0,0 +1,197 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +struct charinfo; +struct node; +struct vunits; + +// See ARM p251. +static void process_input_stack(); + +class token { + symbol nm; + node *nd; + unsigned char c; + int val; + units dim; + enum token_type { + TOKEN_BACKSPACE, + TOKEN_BEGIN_TRAP, + TOKEN_CHAR, // a normal printing character + TOKEN_DUMMY, + TOKEN_EMPTY, // this is the initial value + TOKEN_END_TRAP, + TOKEN_ESCAPE, // \e + TOKEN_HYPHEN_INDICATOR, + TOKEN_INTERRUPT, // \c + TOKEN_ITALIC_CORRECTION, // \/ + TOKEN_LEADER, // ^A + TOKEN_LEFT_BRACE, + TOKEN_MARK_INPUT, // \k -- `nm' is the name of the register + TOKEN_NEWLINE, // newline + TOKEN_NODE, + TOKEN_NUMBERED_CHAR, + TOKEN_PAGE_EJECTOR, + TOKEN_REQUEST, + TOKEN_RIGHT_BRACE, + TOKEN_SPACE, // ` ' -- ordinary space + TOKEN_SPECIAL, // a special character -- \' \` \- \(xx + TOKEN_SPREAD, // \p -- break and spread output line + TOKEN_TAB, // tab + TOKEN_TRANSPARENT, // \! + TOKEN_EOF // end of file + } type; +public: + token(); + ~token(); + token(const token &); + void operator=(const token &); + void next(); + void process(); + void skip(); + int eof(); + int nspaces(); // 1 if space, 2 if double space, 0 otherwise + int space(); // is it a space or double space? + int white_space(); // is the current token space or tab? + int newline(); // is the current token a newline? + int tab(); // is the current token a tab? + int leader(); + int backspace(); + int delimiter(int warn = 0); // is it suitable for use as a delimiter? + int dummy(); + int transparent(); + int left_brace(); + int right_brace(); + int page_ejector(); + int hyphen_indicator(); + int operator==(const token &); // need this for delimiters, and for conditions + int operator!=(const token &); // ditto + unsigned char ch(); + charinfo *get_char(int required = 0); + int add_to_node_list(node **); + int title(); + void make_space(); + void make_newline(); + const char *description(); + + friend void process_input_stack(); +}; + +extern token tok; // the current token + +extern symbol get_name(int required = 0); +extern symbol get_long_name(int required = 0); +extern charinfo *get_optional_char(); +extern void skip_line(); +extern void handle_initial_title(); + +struct hunits; +extern void read_title_parts(node **part, hunits *part_width); + +extern int get_number(units *result, unsigned char si); +extern int get_integer(int *result); + +extern int get_number(units *result, unsigned char si, units prev_value); +extern int get_integer(int *result, int prev_value); + +void interpolate_number_reg(symbol, int); + +const char *asciify(int c); + +inline int token::newline() +{ + return type == TOKEN_NEWLINE; +} + +inline int token::space() +{ + return type == TOKEN_SPACE; +} + +inline int token::nspaces() +{ + if (type == TOKEN_SPACE) + return 1; + else + return 0; +} + +inline int token::white_space() +{ + return type == TOKEN_SPACE || type == TOKEN_TAB; +} + +inline int token::transparent() +{ + return type == TOKEN_TRANSPARENT; +} + +inline int token::page_ejector() +{ + return type == TOKEN_PAGE_EJECTOR; +} + +inline unsigned char token::ch() +{ + return type == TOKEN_CHAR ? c : 0; +} + +inline int token::eof() +{ + return type == TOKEN_EOF; +} + +inline int token::dummy() +{ + return type == TOKEN_DUMMY; +} + +inline int token::left_brace() +{ + return type == TOKEN_LEFT_BRACE; +} + +inline int token::right_brace() +{ + return type == TOKEN_RIGHT_BRACE; +} + +inline int token::tab() +{ + return type == TOKEN_TAB; +} + +inline int token::leader() +{ + return type == TOKEN_LEADER; +} + +inline int token::backspace() +{ + return type == TOKEN_BACKSPACE; +} + +inline int token::hyphen_indicator() +{ + return type == TOKEN_HYPHEN_INDICATOR; +} + +int has_arg(); diff --git a/gnu/usr.bin/groff/troff/troff.1 b/gnu/usr.bin/groff/troff/troff.1 new file mode 100644 index 0000000000..35184e817f --- /dev/null +++ b/gnu/usr.bin/groff/troff/troff.1 @@ -0,0 +1,2004 @@ +.\" -*- nroff -*- +.\" define a string tx for the TeX logo +.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X +.el .ds tx TeX +.de TQ +.br +.ns +.TP \\$1 +.. +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.\" The BSD man macros can't handle " in arguments to font change macros, +.\" so use \(ts instead of ". +.tr \(ts" +.TH TROFF 1 "1 April 1993" "Groff Version 1.08" +.SH NAME +troff \- format documents +.SH SYNOPSIS +.nr a \n(.j +.ad l +.nr i \n(.i +.in +\w'\fBtroff 'u +.ti \niu +.B troff +.de OP +.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]" +.el .RB "[\ " "\\$1" "\ ]" +.. +.OP \-abivzCER +.OP \-w name +.OP \-W name +.OP \-d cs +.OP \-f fam +.OP \-m name +.OP \-n num +.OP \-o list +.OP \-r cn +.OP \-T name +.OP \-F dir +.OP \-M dir +.RI "[\ " files\|.\|.\|. "\ ]" +.br +.ad \na +.SH DESCRIPTION +This manual page describes the GNU version of +.BR troff , +which is part of the groff document formatting system. +It is highly compatible with Unix troff. +Usually it should be invoked using the groff command, which will +also run preprocessors and postprocessors in the appropriate +order and with the appropriate options. +.SH OPTIONS +.TP \w'\-dname=s'u+2n +.B \-a +Generate an +.SM ASCII +approximation of the typeset output. +.TP +.B \-b +Print a backtrace with each warning or error message. This backtrace +should help track down the cause of the error. The line numbers given +in the backtrace may not always correct: troff's idea of line numbers +gets confused by +.B as +or +.B am +requests. +.TP +.B \-i +Read the standard input after all the named input files have been +processed. +.TP +.B \-v +Print the version number. +.TP +.BI \-w name +Enable warning +.IR name . +Available warnings are described in +the Warnings subsection below. +Multiple +.B \-w +options are allowed. +.TP +.BI \-W name +Inhibit warning +.IR name . +Multiple +.B \-W +options are allowed. +.TP +.B \-E +Inhibit all error messages. +.TP +.B \-z +Suppress formatted output. +.TP +.B \-C +Enable compatibility mode. +.TP +.BI \-d cs +.TQ +.BI \-d name = s +Define +.I c +or +.I name +to be a string +.IR s ; +.I c +must be a one letter name. +.TP +.BI \-f fam +Use +.I fam +as the default font family. +.TP +.BI \-m name +Read in the file +.BI tmac. name\fR. +Normally this will be searched for in /usr/share/tmac. +.TP +.B \-R +Don't load +.BR troffrc . +.TP +.BI \-n num +Number the first page +.IR num . +.TP +.BI \-o list +Output only pages in +.IR list , +which is a comma-separated list of page ranges; +.I n +means print page +.IR n , +.IB m \- n +means print every page between +.I m +and +.IR n , +.BI \- n +means print every page up to +.IR n , +.IB n \- +means print every page from +.IR n . +.TP +.BI \-r cn +.TQ +.BI \-r name = n +Set number register +.I c +or +.I name +to +.IR n ; +.I c +must be a one character name; +.I n +can be any troff numeric expression. +.TP +.BI \-T name +Prepare output for device +.IR name , +rather than the default +.BR ps . +.TP +.BI \-F dir +Search +.I dir +for subdirectories +.BI dev name +.RI ( name +is the name of the device) +for the +.B DESC +file and font files before the normal +.BR /usr/share/groff_font . +.TP +.BI \-M dir +Search directory +.I dir +for macro files before the normal +.BR /usr/share/tmac . +.SH USAGE +Only the features not in Unix troff are described here. +.SS Long names +The names of number registers, fonts, strings/macros/diversions, +special characters can be of any length. In escape sequences, where +you can use +.BI ( xx +for a two character name, you can use +.BI [ xxx ] +for a name of arbitrary length: +.TP +.BI \e[ xxx ] +Print the special character called +.IR xxx . +.TP +.BI \ef[ xxx ] +Set font +.IR xxx . +.TP +.BI \e*[ xxx ] +Interpolate string +.IR xxx . +.TP +.BI \en[ xxx ] +Interpolate number register +.IR xxx . +.SS Fractional pointsizes +A +.I +scaled point +is equal to 1/sizescale +points, where +sizescale is specified in the +.B DESC +file (1 by default.) +There is a new scale indicator +.B z +which has the effect of multiplying by sizescale. +Requests and escape sequences in troff +interpret arguments that represent a pointsize as being in units +of scaled points, but they evaluate each such argument +using a default scale indicator of +.BR z . +Arguments treated in this way are +the argument to the +.B ps +request, +the third argument to the +.B cs +request, +the second and fourth arguments to the +.B tkf +request, +the argument to the +.B \eH +escape sequence, +and those variants of the +.B \es +escape sequence that take a numeric expression as their argument. +.LP +For example, suppose sizescale is 1000; +then a scaled point will be equivalent to a millipoint; +the request +.B .ps 10.25 +is equivalent to +.B .ps 10.25z +and so sets the pointsize to 10250 scaled points, +which is equal to 10.25 points. +.LP +The number register +.B \en(.s +returns the pointsize in points as decimal fraction. +There is also a new number register +.B \en[.ps] +that returns the pointsize in scaled points. +.LP +It would make no sense to use the +.B z +scale indicator in a numeric expression +whose default scale indicator was neither +.B u +nor +.BR z , +and so +.B troff +disallows this. +Similarily it would make no sense to use a scaling indicator +other than +.B z +or +.B u +in a numeric expression whose default scale indicator was +.BR z , +and so +.B troff +disallows this as well. +.LP +There is also new scale indicator +.B s +which multiplies by the number of units in a scaled point. +So, for example, +.B \en[.ps]s +is equal to +.BR 1m . +Be sure not to confuse the +.B s +and +.B z +scale indicators. +.SS Numeric expressions +.LP +Spaces are permitted in a number expression within parentheses. +.LP +.B M +indicates a scale of 100ths of an em. +.TP +.IB e1 >? e2 +The maximum of +.I e1 +and +.IR e2 . +.TP +.IB e1 +#include +#include +#include +#include +#include +#include + +#include "lib.h" +#include "assert.h" +#include "device.h" + +#ifdef __GNUG__ +#define NO_RETURN volatile +#else +#define NO_RETURN +#endif + +NO_RETURN void cleanup_and_exit(int n); + +typedef int units; + +extern units scale(units n, units x, units y); // scale n by x/y + +extern units units_per_inch; + +extern int ascii_output_flag; +extern int suppress_output_flag; + +extern int tcommand_flag; +extern int vresolution; +extern int hresolution; +extern int sizescale; + +#include "cset.h" +#include "cmap.h" +#include "errarg.h" +#include "error.h" + +enum warning_type { + WARN_CHAR = 01, + WARN_NUMBER = 02, + WARN_BREAK = 04, + WARN_DELIM = 010, + WARN_EL = 020, + WARN_SCALE = 040, + WARN_RANGE = 0100, + WARN_SYNTAX = 0200, + WARN_DI = 0400, + WARN_MAC = 01000, + WARN_REG = 02000, + WARN_TAB = 04000, + WARN_RIGHT_BRACE = 010000, + WARN_MISSING = 020000, + WARN_INPUT = 040000, + WARN_ESCAPE = 0100000, + WARN_SPACE = 0200000, + WARN_FONT = 0400000 + // change WARN_TOTAL if you add more warning types +}; + +const int WARN_TOTAL = 0777777; + +int warning(warning_type, const char *, + const errarg & = empty_errarg, + const errarg & = empty_errarg, + const errarg & = empty_errarg); diff --git a/gnu/usr.bin/groff/xditview/ChangeLog b/gnu/usr.bin/groff/xditview/ChangeLog new file mode 100644 index 0000000000..880201cc4e --- /dev/null +++ b/gnu/usr.bin/groff/xditview/ChangeLog @@ -0,0 +1,259 @@ +Tue Mar 30 15:12:09 1993 James Clark (jjc at jclark) + + * draw.c (charExists): Check that fi->per_char is not NULL. + +Sat Dec 12 17:42:40 1992 James Clark (jjc at jclark) + + * Dvi.c (SetGeometry): Cast XtMakeGeometryRequest arguments. + + * draw.c (DrawPolygon, DrawFilledPolygon): Cast Xtfree argument. + + * font.c (DisposeFontSizes): Add declaration. + + * draw.c (FakeCharacter): Add declaration. + +Wed Oct 28 13:24:00 1992 James Clark (jjc at jclark) + + * Imakefile (install.dev): Deleted. + (fonts): New target. + +Mon Oct 12 10:50:44 1992 James Clark (jjc at jclark) + + * Imakefile (install.dev): Say when we're installing devX*-12. + + * Imakefile (install.dev): Depends on DESC and FontMap. + +Thu Oct 1 20:03:45 1992 James Clark (jjc at jclark) + + * xditview.c (Syntax): Mention -filename option. + +Sat Aug 15 12:56:39 1992 James Clark (jjc at jclark) + + * GXditview.ad: Bind space and return to NextPage. Bind backspace + and delete to previous page. + + * DviChar.c (Adobe_Symbol_map): Add `an'. + + * DviChar.c (Adobe_Symbol_map): Add arrowvertex, arrowverttp, and + arrowvertbt. + +Mon Aug 10 11:54:27 1992 James Clark (jjc at jclark) + + * FontMap: Add m/p fields to the fonts names. + +Sat Aug 8 12:00:28 1992 James Clark (jjc at jclark) + + * DESC: Leave font positions 5-9 blank. + +Tue Jul 28 11:37:05 1992 James Clark (jjc at jclark) + + * Imakefile: Don't use gendef. Pass definition of FONTPATH using + DEFINES. + (path.h): Deleted. + (device.c): Don't include path.h. Provide default definition of + FONTPATH. + +Mon Jul 6 14:06:53 1992 James Clark (jjc at jclark) + + * Imakefile: Don't install tmac.X and tmac.Xps. + * tmac.X, tmac.Xps: Moved to ../macros. + + * Imakefile: Don't install eqnchar. + * eqnchar: Deleted. + +Sun Jun 14 12:55:02 1992 James Clark (jjc@jclark) + + * tmac.Xps: Handle OE, oe, lq, rq. + * draw.c (FakeCharacter): Don't handle these. + + * draw.c (FakeCharacter): Don't handle f/. + +Mon Jun 8 11:46:37 1992 James Clark (jjc@jclark) + + * tmac.X: Translate char160 to space. + +Sun Jun 7 14:39:53 1992 James Clark (jjc@jclark) + + * tmac.X: Do `mso tmac.psic' before restoring compatibility mode. + + * tmac.X: Add \(OE, \(oe, \(ah, \(ao, \(ho. + + * tmac.Xps: Make it work in compatibility mode. + Redo existing character definitions with .Xps-char. + Add more character definitions. + (Xps-char): New macro. + +Sat Jun 6 21:46:03 1992 James Clark (jjc@jclark) + + * DviChar.c (Adobe_Symbol_map): Add +h, +f, +p, Fn, lz. + * tmac.X: Add \(bq, \(Bq, \(aq. + * tmac.Xps: Handle \(aq, \(bq, \(Bq, \(Fn. + +Wed Jun 3 11:11:15 1992 James Clark (jjc@jclark) + + * DviChar.c (Adobe_Symbol_map): Add wp. + +Tue Apr 21 09:21:59 1992 James Clark (jjc at jclark) + + * GXditview.ad: Bind n, p, q keys to NextPage, PreviousPage and + Quit actions. + + * xditview.c (RerasterizeAction): New function. + (xditview_actions): Add RerasterizeAction. + * GXditview.ad: Bind r key to Rerasterize action. + +Fri Apr 17 08:25:36 1992 James Clark (jjc at jclark) + + * xditview.c: Add -filename option. + (main): Copy any -filename argument into current_file_name. + +Mon Mar 16 10:21:58 1992 James Clark (jjc at jclark) + + * tmac.X: Load tmac.pspic. + +Sun Mar 8 11:27:19 1992 James Clark (jjc at jclark) + + * Lex.c (GetLine, GetWord, GetNumber): Rewrite. + +Sat Oct 12 22:58:52 1991 James Clark (jjc at jclark) + + * Dvi.c (SetDevice): If the size change request is refused but a + larger geometry is offered, request that. + +Wed Oct 9 12:27:48 1991 James Clark (jjc at jclark) + + * font.c (InstallFontSizes): Ignore FontNameAverageWidth component. + + * Dvi.c (default_font_map): Add `adobe' to font names to avoid + ambiguity. + + * FontMap: New file. + * FontMap.X100, FontMap.X75: Deleted. + * xtotroff.c (main, usage): Add -s and -r options. + (MapFont): Change the font pattern to have the selected resolution and + size. + * Imakefile (install.dev): Use FontMap and supply appropriate -s + and -r options. + + * xtotroff.c (MapFont): Check for ambiguity by comparing canonicalized + font names. + + * DviP.h (DviFontList): Add initialized and scalable members. + (font.c): Add support for scalable fonts based on R5 xditview. + + * DviChar.c: Use xmalloc rather than malloc. + * xditview.c (xmalloc): New function. + * xtotroff.c (xmalloc): New function. + * other files: Use XtMalloc and XtFree instead of malloc and free. + +Thu Aug 29 20:15:31 1991 James Clark (jjc at jclark) + + * draw.c (setGC): Do multiplication in floating point to avoid + overflow. + +Tue Aug 13 12:04:41 1991 James Clark (jjc at jclark) + + * draw.c (FakeCharacter): Remove casts in defintion of pack2. + +Tue Jul 30 11:42:39 1991 James Clark (jjc at jclark) + + * tmac.Xps: New file. + * Imakefile (install): Install tmac.Xps. + +Tue Jul 2 09:31:37 1991 James Clark (jjc at jclark) + + * xtotroff.c (main): Pass argv[0] to usage(). + +Sun Jun 30 12:34:06 1991 James Clark (jjc at jclark) + + * xtotroff.c (MapFont): Handle the case where XLoadQueryFont + returns NULL. + +Sat Jun 29 12:32:52 1991 James Clark (jjc at jclark) + + * Imakefile: Use ../gendef to generate path.h. + +Sun Jun 16 13:26:34 1991 James Clark (jjc at jclark) + + * Imakefile (depend.o): Change to device.o. + +Sun Jun 2 12:17:56 1991 James Clark (jjc at jclark) + + * Imakefile: Remove spaces from the beginning of variable + assignment lines. + +Sun May 26 14:14:01 1991 James Clark (jjc at jclark) + + * xditview.c (Syntax): Update. + + * Dvi.c (DviSaveToFile, SaveToFile): New functions. + (FindPage): Check that we're not readingTmp before checking for + end of file of normal input file. + (ClassPartInitialize): New function. + * Dvi.h: Add declaration of DviSaveToFile. + * DviP.h: Add save method to DviClassPart. Declare + InheritSaveToFile. + * xditview.c (DoPrint, Print, PrintAction): New functions. + * xditview.c: Add print menu entry. + * xditview.c: Provide printCommand application resource. + * lex.c: Don't output EOF to temporary file. + + * Dvi.c (QueryGeometry): Check request->request_mode. + + * Dvi.c (SetDevice): New function. + (SetDeviceResolution): Deleted. + + * Dvi.c: Add resolution resource. + * DviP.h: Add definitions of XtNResolution and XtCResolution. + * xditview.c: Add -resolution argument. + * GXditview.ad: Add default for GXditview.height. + * Dvi.c (Initialize, SetDevice): Use default_resolution. + + * Dvi.c: Make MY_HEIGHT and MY_WIDTH use the paperlength and + paperwidth commands in the DESC file. + + * Dvi.c: Add SS font to default font map. + + * draw.c: Rewritten so as not to assume device and display + resolution is the same. + * DviP.h: Include device.h. Add device_font member to DviFontList. + Add adjustable arrary to DviCharCache. Add text_x_width, + text_device_width, word_flag, device_font, device_font_number, + device, native, device_resolution, display_resolution, + paperlength, paperwidth, scale_factor, sizescale members. + * Dvi.c (Initialize): Initialize new variable used by draw.c + (Destroy): Call device_destroy. + * font.c (MaxFontPosition): New function. + (LookupFontSizeBySize): Handle sizescale. + (InstallFont): Load the device font. + (ForgetFonts): New function. + (QueryDeviceFont): New function. + * parse.c (ParseInput): Handle t and u commands. Split off + character output into draw.c. + (ParseDeviceControl): Ignore res command. Use the device argument + to the T command. + + * font.c (MapXNameToDviName): Ifdefed out. + + * path.h: New file. + * device.c, device.h: New files. + + * DviChar.c: Add entries for lB, rB, oq, lC, rC, md. + + * INSTALL: New file. + + * libxdvi: Merged into main directory. + * xtotroff.c, xditview.c: Change includes accordingly. + + * devX75, devX100: Merged into main directory. + * xditview.man: Renamed to gxditview.man. + + * Xditview.ad: Renamed to GXditview.ad. + * xditview.c (main): Use class of GXditview rather than xditview. + + * Imakefile: New file. + * Makefile: Deleted. + + * xtotroff.c (MapFont): Unlink output file before opening it. + + * Started separate ChangeLog. diff --git a/gnu/usr.bin/groff/xditview/DESC b/gnu/usr.bin/groff/xditview/DESC new file mode 100644 index 0000000000..172170c9c0 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/DESC @@ -0,0 +1,9 @@ +styles R I B BI +fonts 6 0 0 0 0 0 S +sizes 8 10 12 14 18 24 0 +res 75 +X11 +hor 1 +vert 1 +unitwidth 10 +postpro gxditview diff --git a/gnu/usr.bin/groff/xditview/Dvi.c b/gnu/usr.bin/groff/xditview/Dvi.c new file mode 100644 index 0000000000..8402119a36 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/Dvi.c @@ -0,0 +1,544 @@ +#ifndef SABER +#ifndef lint +static char Xrcsid[] = "$XConsortium: Dvi.c,v 1.9 89/12/10 16:12:25 rws Exp $"; +#endif /* lint */ +#endif /* SABER */ + +/* + * Dvi.c - Dvi display widget + * + */ + +#define XtStrlen(s) ((s) ? strlen(s) : 0) + + /* The following are defined for the reader's convenience. Any + Xt..Field macro in this code just refers to some field in + one of the substructures of the WidgetRec. */ + +#include +#include +#include +#include +#include +#include "DviP.h" + +/**************************************************************** + * + * Full class record constant + * + ****************************************************************/ + +/* Private Data */ + +static char default_font_map[] = "\ +TR -adobe-times-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\ +TI -adobe-times-medium-i-normal--*-100-*-*-*-*-iso8859-1\n\ +TB -adobe-times-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\ +TBI -adobe-times-bold-i-normal--*-100-*-*-*-*-iso8859-1\n\ +CR -adobe-courier-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\ +CI -adobe-courier-medium-o-normal--*-100-*-*-*-*-iso8859-1\n\ +CB -adobe-courier-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\ +CBI -adobe-courier-bold-o-normal--*-100-*-*-*-*-iso8859-1\n\ +HR -adobe-helvetica-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\ +HI -adobe-helvetica-medium-o-normal--*-100-*-*-*-*-iso8859-1\n\ +HB -adobe-helvetica-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\ +HBI -adobe-helvetica-bold-o-normal--*-100-*-*-*-*-iso8859-1\n\ +NR -adobe-new century schoolbook-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\ +NI -adobe-new century schoolbook-medium-i-normal--*-100-*-*-*-*-iso8859-1\n\ +NB -adobe-new century schoolbook-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\ +NBI -adobe-new century schoolbook-bold-i-normal--*-100-*-*-*-*-iso8859-1\n\ +S -adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\n\ +SS -adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\n\ +"; + +#define offset(field) XtOffset(DviWidget, field) + +#define MY_WIDTH(dw) ((int)(dw->dvi.paperwidth * dw->dvi.scale_factor + .5)) +#define MY_HEIGHT(dw) ((int)(dw->dvi.paperlength * dw->dvi.scale_factor + .5)) + +static XtResource resources[] = { + {XtNfontMap, XtCFontMap, XtRString, sizeof (char *), + offset(dvi.font_map_string), XtRString, default_font_map}, + {XtNforeground, XtCForeground, XtRPixel, sizeof (unsigned long), + offset(dvi.foreground), XtRString, "black"}, + {XtNbackground, XtCBackground, XtRPixel, sizeof (unsigned long), + offset(dvi.background), XtRString, "white"}, + {XtNpageNumber, XtCPageNumber, XtRInt, sizeof (int), + offset(dvi.requested_page), XtRString, "1"}, + {XtNlastPageNumber, XtCLastPageNumber, XtRInt, sizeof (int), + offset (dvi.last_page), XtRString, "0"}, + {XtNfile, XtCFile, XtRFile, sizeof (FILE *), + offset (dvi.file), XtRFile, (char *) 0}, + {XtNseek, XtCSeek, XtRBoolean, sizeof (Boolean), + offset(dvi.seek), XtRString, "false"}, + {XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *), + offset(dvi.default_font), XtRString, "xtdefaultfont"}, + {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int), + offset(dvi.backing_store), XtRString, "default"}, + {XtNnoPolyText, XtCNoPolyText, XtRBoolean, sizeof (Boolean), + offset(dvi.noPolyText), XtRString, "false"}, + {XtNresolution, XtCResolution, XtRInt, sizeof(int), + offset(dvi.default_resolution), XtRString, "75"}, +}; + +#undef offset + +static void ClassInitialize (); +static void ClassPartInitialize(); +static void Initialize(), Realize (), Destroy (), Redisplay (); +static Boolean SetValues (), SetValuesHook (); +static XtGeometryResult QueryGeometry (); +static void ShowDvi (); +static void CloseFile (), OpenFile (); +static void FindPage (); + +static void SaveToFile (); + +DviClassRec dviClassRec = { +{ + &widgetClassRec, /* superclass */ + "Dvi", /* class_name */ + sizeof(DviRec), /* size */ + ClassInitialize, /* class_initialize */ + ClassPartInitialize, /* class_part_initialize */ + FALSE, /* class_inited */ + Initialize, /* initialize */ + NULL, /* initialize_hook */ + Realize, /* realize */ + NULL, /* actions */ + 0, /* num_actions */ + resources, /* resources */ + XtNumber(resources), /* resource_count */ + NULLQUARK, /* xrm_class */ + FALSE, /* compress_motion */ + TRUE, /* compress_exposure */ + TRUE, /* compress_enterleave */ + FALSE, /* visible_interest */ + Destroy, /* destroy */ + NULL, /* resize */ + Redisplay, /* expose */ + SetValues, /* set_values */ + SetValuesHook, /* set_values_hook */ + NULL, /* set_values_almost */ + NULL, /* get_values_hook */ + NULL, /* accept_focus */ + XtVersion, /* version */ + NULL, /* callback_private */ + 0, /* tm_table */ + QueryGeometry, /* query_geometry */ + NULL, /* display_accelerator */ + NULL /* extension */ +},{ + SaveToFile, /* save */ +}, +}; + +WidgetClass dviWidgetClass = (WidgetClass) &dviClassRec; + +static void ClassInitialize () +{ + XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore, + NULL, 0 ); +} + +/**************************************************************** + * + * Private Procedures + * + ****************************************************************/ + +/* ARGSUSED */ +static void Initialize(request, new) + Widget request, new; +{ + DviWidget dw = (DviWidget) new; + + dw->dvi.current_page = 0; + dw->dvi.font_map = 0; + dw->dvi.cache.index = 0; + dw->dvi.text_x_width = 0; + dw->dvi.text_device_width = 0; + dw->dvi.word_flag = 0; + dw->dvi.file = 0; + dw->dvi.tmpFile = 0; + dw->dvi.state = 0; + dw->dvi.readingTmp = 0; + dw->dvi.cache.char_index = 0; + dw->dvi.cache.font_size = -1; + dw->dvi.cache.font_number = -1; + dw->dvi.cache.adjustable[0] = 0; + dw->dvi.file_map = 0; + dw->dvi.fonts = 0; + dw->dvi.seek = False; + dw->dvi.device_resolution = dw->dvi.default_resolution; + dw->dvi.display_resolution = dw->dvi.default_resolution; + dw->dvi.paperlength = dw->dvi.default_resolution*11; + dw->dvi.paperwidth = (dw->dvi.default_resolution*8 + + dw->dvi.default_resolution/2); + dw->dvi.scale_factor = 1.0; + dw->dvi.sizescale = 1; + dw->dvi.line_thickness = -1; + dw->dvi.line_width = 1; + dw->dvi.fill = DVI_FILL_MAX; + dw->dvi.device_font = 0; + dw->dvi.device_font_number = -1; + dw->dvi.device = 0; + dw->dvi.native = 0; +} + +#include + +static void +Realize (w, valueMask, attrs) + Widget w; + XtValueMask *valueMask; + XSetWindowAttributes *attrs; +{ + DviWidget dw = (DviWidget) w; + XGCValues values; + + if (dw->dvi.backing_store != Always + WhenMapped + NotUseful) { + attrs->backing_store = dw->dvi.backing_store; + *valueMask |= CWBackingStore; + } + XtCreateWindow (w, (unsigned)InputOutput, (Visual *) CopyFromParent, + *valueMask, attrs); + values.foreground = dw->dvi.foreground; + values.cap_style = CapRound; + values.join_style = JoinRound; + values.line_width = dw->dvi.line_width; + dw->dvi.normal_GC = XCreateGC (XtDisplay (w), XtWindow (w), + GCForeground|GCCapStyle|GCJoinStyle + |GCLineWidth, + &values); + dw->dvi.gray = XCreateBitmapFromData(XtDisplay (w), XtWindow (w), + gray_bits, + gray_width, gray_height); + values.background = dw->dvi.background; + values.stipple = dw->dvi.gray; + dw->dvi.fill_GC = XCreateGC (XtDisplay (w), XtWindow (w), + GCForeground|GCBackground|GCStipple, + &values); + + dw->dvi.fill_type = DVI_FILL_BLACK; + + if (dw->dvi.file) + OpenFile (dw); + ParseFontMap (dw); +} + +static void +Destroy(w) + Widget w; +{ + DviWidget dw = (DviWidget) w; + + XFreeGC (XtDisplay (w), dw->dvi.normal_GC); + XFreeGC (XtDisplay (w), dw->dvi.fill_GC); + XFreePixmap (XtDisplay (w), dw->dvi.gray); + DestroyFontMap (dw->dvi.font_map); + DestroyFileMap (dw->dvi.file_map); + device_destroy (dw->dvi.device); +} + +/* + * Repaint the widget window + */ + +/* ARGSUSED */ +static void +Redisplay(w, event, region) + Widget w; + XEvent *event; + Region region; +{ + DviWidget dw = (DviWidget) w; + XRectangle extents; + + XClipBox (region, &extents); + dw->dvi.extents.x1 = extents.x; + dw->dvi.extents.y1 = extents.y; + dw->dvi.extents.x2 = extents.x + extents.width; + dw->dvi.extents.y2 = extents.y + extents.height; + ShowDvi (dw); +} + +/* + * Set specified arguments into widget + */ +/* ARGSUSED */ +static Boolean +SetValues (current, request, new) + DviWidget current, request, new; +{ + Boolean redisplay = FALSE; + char *new_map; + int cur, req; + + if (current->dvi.font_map_string != request->dvi.font_map_string) { + new_map = XtMalloc (strlen (request->dvi.font_map_string) + 1); + if (new_map) { + redisplay = TRUE; + strcpy (new_map, request->dvi.font_map_string); + new->dvi.font_map_string = new_map; + if (current->dvi.font_map_string) + XtFree (current->dvi.font_map_string); + current->dvi.font_map_string = 0; + ParseFontMap (new); + } + } + + req = request->dvi.requested_page; + cur = current->dvi.requested_page; + if (cur != req) { + if (!request->dvi.file) + req = 0; + else { + if (req < 1) + req = 1; + if (current->dvi.last_page != 0 && + req > current->dvi.last_page) + req = current->dvi.last_page; + } + if (cur != req) + redisplay = TRUE; + new->dvi.requested_page = req; + if (current->dvi.last_page == 0 && req > cur) + FindPage (new); + } + + return redisplay; +} + +/* + * use the set_values_hook entry to check when + * the file is set + */ + +static Boolean +SetValuesHook (dw, args, num_argsp) + DviWidget dw; + ArgList args; + Cardinal *num_argsp; +{ + Cardinal i; + + for (i = 0; i < *num_argsp; i++) { + if (!strcmp (args[i].name, XtNfile)) { + CloseFile (dw); + OpenFile (dw); + return TRUE; + } + } + return FALSE; +} + +static void CloseFile (dw) + DviWidget dw; +{ + if (dw->dvi.tmpFile) + fclose (dw->dvi.tmpFile); + ForgetPagePositions (dw); +} + +static void OpenFile (dw) + DviWidget dw; +{ + char tmpName[sizeof ("/tmp/dviXXXXXX")]; + + dw->dvi.tmpFile = 0; + if (!dw->dvi.seek) { + strcpy (tmpName, "/tmp/dviXXXXXX"); + mktemp (tmpName); + dw->dvi.tmpFile = fopen (tmpName, "w+"); + unlink (tmpName); + } + dw->dvi.requested_page = 1; + dw->dvi.last_page = 0; +} + +static XtGeometryResult +QueryGeometry (w, request, geometry_return) + Widget w; + XtWidgetGeometry *request, *geometry_return; +{ + XtGeometryResult ret; + DviWidget dw = (DviWidget) w; + + ret = XtGeometryYes; + if (((request->request_mode & CWWidth) + && request->width < MY_WIDTH(dw)) + || ((request->request_mode & CWHeight) + && request->height < MY_HEIGHT(dw))) + ret = XtGeometryAlmost; + geometry_return->width = MY_WIDTH(dw); + geometry_return->height = MY_HEIGHT(dw); + geometry_return->request_mode = CWWidth|CWHeight; + return ret; +} + +SetDevice (dw, name) + DviWidget dw; + char *name; +{ + XtWidgetGeometry request, reply; + XtGeometryResult ret; + + ForgetFonts (dw); + dw->dvi.device = device_load (name); + if (!dw->dvi.device) + return; + dw->dvi.sizescale = dw->dvi.device->sizescale; + dw->dvi.device_resolution = dw->dvi.device->res; + dw->dvi.native = dw->dvi.device->X11; + dw->dvi.paperlength = dw->dvi.device->paperlength; + dw->dvi.paperwidth = dw->dvi.device->paperwidth; + if (dw->dvi.native) { + dw->dvi.display_resolution = dw->dvi.device_resolution; + dw->dvi.scale_factor = 1.0; + } + else { + dw->dvi.display_resolution = dw->dvi.default_resolution; + dw->dvi.scale_factor = ((double)dw->dvi.display_resolution + / dw->dvi.device_resolution); + } + request.request_mode = CWWidth|CWHeight; + request.width = MY_WIDTH(dw); + request.height = MY_HEIGHT(dw); + ret = XtMakeGeometryRequest ((Widget)dw, &request, &reply); + if (ret == XtGeometryAlmost + && reply.height >= request.height + && reply.width >= request.width) { + request.width = reply.width; + request.height = reply.height; + XtMakeGeometryRequest ((Widget)dw, &request, &reply); + } +} + +static void +ShowDvi (dw) + DviWidget dw; +{ + if (!dw->dvi.file) { + static char Error[] = "No file selected"; + + XSetFont (XtDisplay(dw), dw->dvi.normal_GC, + dw->dvi.default_font->fid); + XDrawString (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC, + 20, 20, Error, strlen (Error)); + return; + } + + FindPage (dw); + + dw->dvi.display_enable = 1; + ParseInput (dw); + if (dw->dvi.last_page && dw->dvi.requested_page > dw->dvi.last_page) + dw->dvi.requested_page = dw->dvi.last_page; +} + +static void +FindPage (dw) + DviWidget dw; +{ + int i; + long file_position; + + if (dw->dvi.requested_page < 1) + dw->dvi.requested_page = 1; + + if (dw->dvi.last_page != 0 && dw->dvi.requested_page > dw->dvi.last_page) + dw->dvi.requested_page = dw->dvi.last_page; + + file_position = SearchPagePosition (dw, dw->dvi.requested_page); + if (file_position != -1) { + FileSeek(dw, file_position); + dw->dvi.current_page = dw->dvi.requested_page; + } else { + for (i=dw->dvi.requested_page; i > 0; i--) { + file_position = SearchPagePosition (dw, i); + if (file_position != -1) + break; + } + if (file_position == -1) + file_position = 0; + FileSeek (dw, file_position); + + dw->dvi.current_page = i; + + dw->dvi.display_enable = 0; + while (dw->dvi.current_page != dw->dvi.requested_page) { + dw->dvi.current_page = ParseInput (dw); + /* + * at EOF, seek back to the begining of this page. + */ + if (!dw->dvi.readingTmp && feof (dw->dvi.file)) { + file_position = SearchPagePosition (dw, + dw->dvi.current_page); + if (file_position != -1) + FileSeek (dw, file_position); + dw->dvi.requested_page = dw->dvi.current_page; + break; + } + } + } +} + +void DviSaveToFile(w, fp) + Widget w; + FILE *fp; +{ + XtCheckSubclass(w, dviWidgetClass, NULL); + (*((DviWidgetClass) XtClass(w))->command_class.save)(w, fp); +} + +static +void SaveToFile(w, fp) + Widget w; + FILE *fp; +{ + DviWidget dw = (DviWidget)w; + long pos; + int c; + + if (dw->dvi.tmpFile) { + pos = ftell(dw->dvi.tmpFile); + if (dw->dvi.ungot) { + pos--; + dw->dvi.ungot = 0; + /* The ungot character is in the tmpFile, so we don't + want to read it from file. */ + (void)getc(dw->dvi.file); + } + } + else + pos = ftell(dw->dvi.file); + FileSeek(dw, 0L); + while (DviGetC(dw, &c) != EOF) + if (putc(c, fp) == EOF) { + /* XXX print error message */ + break; + } + FileSeek(dw, pos); +} + +static +void ClassPartInitialize(widget_class) + WidgetClass widget_class; +{ + DviWidgetClass wc = (DviWidgetClass)widget_class; + DviWidgetClass super = (DviWidgetClass) wc->core_class.superclass; + if (wc->command_class.save == InheritSaveToFile) + wc->command_class.save = super->command_class.save; +} + +/* +Local Variables: +c-indent-level: 8 +c-continued-statement-offset: 8 +c-brace-offset: -8 +c-argdecl-indent: 8 +c-label-offset: -8 +c-tab-always-indent: nil +End: +*/ diff --git a/gnu/usr.bin/groff/xditview/Dvi.h b/gnu/usr.bin/groff/xditview/Dvi.h new file mode 100644 index 0000000000..5aab7d8c75 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/Dvi.h @@ -0,0 +1,46 @@ +/* +* $XConsortium: Dvi.h,v 1.4 89/07/21 14:22:06 jim Exp $ +*/ + +#ifndef _XtDvi_h +#define _XtDvi_h + +/*********************************************************************** + * + * Dvi Widget + * + ***********************************************************************/ + +/* Parameters: + + Name Class RepType Default Value + ---- ----- ------- ------------- + background Background pixel White + foreground Foreground Pixel Black + fontMap FontMap char * ... + pageNumber PageNumber int 1 +*/ + +#define XtNfontMap "fontMap" +#define XtNpageNumber "pageNumber" +#define XtNlastPageNumber "lastPageNumber" +#define XtNnoPolyText "noPolyText" +#define XtNseek "seek" +#define XtNresolution "resolution" + +#define XtCFontMap "FontMap" +#define XtCPageNumber "PageNumber" +#define XtCLastPageNumber "LastPageNumber" +#define XtCNoPolyText "NoPolyText" +#define XtCSeek "Seek" +#define XtCResolution "Resolution" + +typedef struct _DviRec *DviWidget; /* completely defined in DviPrivate.h */ +typedef struct _DviClassRec *DviWidgetClass; /* completely defined in DviPrivate.h */ + +extern WidgetClass dviWidgetClass; + +extern void DviSaveToFile(); + +#endif /* _XtDvi_h */ +/* DON'T ADD STUFF AFTER THIS #endif */ diff --git a/gnu/usr.bin/groff/xditview/DviChar.c b/gnu/usr.bin/groff/xditview/DviChar.c new file mode 100644 index 0000000000..dc511bf497 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/DviChar.c @@ -0,0 +1,664 @@ +/* + * DviChar.c + * + * Map DVI (ditroff output) character names to + * font indexes and back + */ + +#include "DviChar.h" + +extern char *xmalloc(); + +#define allocHash() ((DviCharNameHash *) xmalloc (sizeof (DviCharNameHash))) + +struct map_list { + struct map_list *next; + DviCharNameMap *map; +}; + +static struct map_list *world; + +static int standard_maps_loaded = 0; +static void load_standard_maps (); +static int hash_name (); +static dispose_hash(), compute_hash(); + +DviCharNameMap * +DviFindMap (encoding) + char *encoding; +{ + struct map_list *m; + + if (!standard_maps_loaded) + load_standard_maps (); + for (m = world; m; m=m->next) + if (!strcmp (m->map->encoding, encoding)) + return m->map; + return 0; +} + +void +DviRegisterMap (map) + DviCharNameMap *map; +{ + struct map_list *m; + + if (!standard_maps_loaded) + load_standard_maps (); + for (m = world; m; m = m->next) + if (!strcmp (m->map->encoding, map->encoding)) + break; + if (!m) { + m = (struct map_list *) xmalloc (sizeof *m); + m->next = world; + world = m; + } + dispose_hash (map); + m->map = map; + compute_hash (map); +} + +static +dispose_hash (map) + DviCharNameMap *map; +{ + DviCharNameHash **buckets; + DviCharNameHash *h, *next; + int i; + + buckets = map->buckets; + for (i = 0; i < DVI_HASH_SIZE; i++) { + for (h = buckets[i]; h; h=next) { + next = h->next; + free (h); + } + } +} + +static int +hash_name (name) + char *name; +{ + int i = 0; + + while (*name) + i = (i << 1) ^ *name++; + if (i < 0) + i = -i; + return i; +} + +static +compute_hash (map) + DviCharNameMap *map; +{ + DviCharNameHash **buckets; + int c, s, i; + DviCharNameHash *h; + + buckets = map->buckets; + for (i = 0; i < DVI_HASH_SIZE; i++) + buckets[i] = 0; + for (c = 0; c < DVI_MAP_SIZE; c++) + for (s = 0; s < DVI_MAX_SYNONYMS; s++) { + if (!map->dvi_names[c][s]) + break; + i = hash_name (map->dvi_names[c][s]) % DVI_HASH_SIZE; + h = allocHash (); + h->next = buckets[i]; + buckets[i] = h; + h->name = map->dvi_names[c][s]; + h->position = c; + } + +} + +int +DviCharIndex (map, name) + DviCharNameMap *map; + char *name; +{ + int i; + DviCharNameHash *h; + + i = hash_name (name) % DVI_HASH_SIZE; + for (h = map->buckets[i]; h; h=h->next) + if (!strcmp (h->name, name)) + return h->position; + return -1; +} + +static DviCharNameMap ISO8859_1_map = { + "iso8859-1", + 0, +{ +{ 0, /* 0 */}, +{ 0, /* 1 */}, +{ 0, /* 2 */}, +{ 0, /* 3 */}, +{ 0, /* 4 */}, +{ 0, /* 5 */}, +{ 0, /* 6 */}, +{ 0, /* 7 */}, +{ 0, /* 8 */}, +{ 0, /* 9 */}, +{ 0, /* 10 */}, +{ 0, /* 11 */}, +{ 0, /* 12 */}, +{ 0, /* 13 */}, +{ 0, /* 14 */}, +{ 0, /* 15 */}, +{ 0, /* 16 */}, +{ 0, /* 17 */}, +{ 0, /* 18 */}, +{ 0, /* 19 */}, +{ 0, /* 20 */}, +{ 0, /* 21 */}, +{ 0, /* 22 */}, +{ 0, /* 23 */}, +{ 0, /* 24 */}, +{ 0, /* 25 */}, +{ 0, /* 26 */}, +{ 0, /* 27 */}, +{ 0, /* 28 */}, +{ 0, /* 29 */}, +{ 0, /* 30 */}, +{ 0, /* 31 */}, +{ 0, /* 32 */}, +{ "!", /* 33 */}, +{ "\"", /* 34 */}, +{ "#","sh", /* 35 */}, +{ "$","Do", /* 36 */}, +{ "%", /* 37 */}, +{ "&", /* 38 */}, +{ "'", /* 39 */}, +{ "(", /* 40 */}, +{ ")", /* 41 */}, +{ "*", /* 42 */}, +{ "+", /* 43 */}, +{ ",", /* 44 */}, +{ "\\-", /* 45 */}, +{ ".", /* 46 */}, +{ "/","sl", /* 47 */}, +{ "0", /* 48 */}, +{ "1", /* 49 */}, +{ "2", /* 50 */}, +{ "3", /* 51 */}, +{ "4", /* 52 */}, +{ "5", /* 53 */}, +{ "6", /* 54 */}, +{ "7", /* 55 */}, +{ "8", /* 56 */}, +{ "9", /* 57 */}, +{ ":", /* 58 */}, +{ ";", /* 59 */}, +{ "<", /* 60 */}, +{ "=","eq", /* 61 */}, +{ ">", /* 62 */}, +{ "?", /* 63 */}, +{ "@","at", /* 64 */}, +{ "A", /* 65 */}, +{ "B", /* 66 */}, +{ "C", /* 67 */}, +{ "D", /* 68 */}, +{ "E", /* 69 */}, +{ "F", /* 70 */}, +{ "G", /* 71 */}, +{ "H", /* 72 */}, +{ "I", /* 73 */}, +{ "J", /* 74 */}, +{ "K", /* 75 */}, +{ "L", /* 76 */}, +{ "M", /* 77 */}, +{ "N", /* 78 */}, +{ "O", /* 79 */}, +{ "P", /* 80 */}, +{ "Q", /* 81 */}, +{ "R", /* 82 */}, +{ "S", /* 83 */}, +{ "T", /* 84 */}, +{ "U", /* 85 */}, +{ "V", /* 86 */}, +{ "W", /* 87 */}, +{ "X", /* 88 */}, +{ "Y", /* 89 */}, +{ "Z", /* 90 */}, +{ "[","lB", /* 91 */}, +{ "\\","rs", /* 92 */}, +{ "]","rB", /* 93 */}, +{ "^","a^","ha" /* 94 */}, +{ "_", /* 95 */}, +{ "`","oq", /* 96 */}, +{ "a", /* 97 */}, +{ "b", /* 98 */}, +{ "c", /* 99 */}, +{ "d", /* 100 */}, +{ "e", /* 101 */}, +{ "f", /* 102 */}, +{ "g", /* 103 */}, +{ "h", /* 104 */}, +{ "i", /* 105 */}, +{ "j", /* 106 */}, +{ "k", /* 107 */}, +{ "l", /* 108 */}, +{ "m", /* 109 */}, +{ "n", /* 110 */}, +{ "o", /* 111 */}, +{ "p", /* 112 */}, +{ "q", /* 113 */}, +{ "r", /* 114 */}, +{ "s", /* 115 */}, +{ "t", /* 116 */}, +{ "u", /* 117 */}, +{ "v", /* 118 */}, +{ "w", /* 119 */}, +{ "x", /* 120 */}, +{ "y", /* 121 */}, +{ "z", /* 122 */}, +{ "{","lC", /* 123 */}, +{ "|","or","ba" /* 124 */}, +{ "}","rC", /* 125 */}, +{ "~","a~","ap","ti" /* 126 */}, +{ 0, /* 127 */}, +{ 0, /* 128 */}, +{ 0, /* 129 */}, +{ 0, /* 130 */}, +{ 0, /* 131 */}, +{ 0, /* 132 */}, +{ 0, /* 133 */}, +{ 0, /* 134 */}, +{ 0, /* 135 */}, +{ 0, /* 136 */}, +{ 0, /* 137 */}, +{ 0, /* 138 */}, +{ 0, /* 139 */}, +{ 0, /* 140 */}, +{ 0, /* 141 */}, +{ 0, /* 142 */}, +{ 0, /* 143 */}, +{ 0, /* 144 */}, +{ 0, /* 145 */}, +{ 0, /* 146 */}, +{ 0, /* 147 */}, +{ 0, /* 148 */}, +{ 0, /* 149 */}, +{ 0, /* 150 */}, +{ 0, /* 151 */}, +{ 0, /* 152 */}, +{ 0, /* 153 */}, +{ 0, /* 154 */}, +{ 0, /* 155 */}, +{ 0, /* 156 */}, +{ 0, /* 157 */}, +{ 0, /* 158 */}, +{ 0, /* 159 */}, +{ 0, /* 160 */}, +{ "r!", "\241", /* 161 */}, +{ "ct", "\242", /* 162 */}, +{ "Po", "\243", /* 163 */}, +{ "Cs", "\244", /* 164 */}, +{ "Ye", "\245", /* 165 */}, +{ "bb", "\246", /* 166 */}, +{ "sc", "\247", /* 167 */}, +{ "ad", "\250", /* 168 */}, +{ "co", "\251", /* 169 */}, +{ "Of", "\252", /* 170 */}, +{ "Fo", "\253", /* 171 */}, +{ "no", "\254", /* 172 */}, +{ "-", "hy", "\255" /* 173 */}, +{ "rg", "\256", /* 174 */}, +{ "a-", "\257", /* 175 */}, +{ "de", "\260", /* 176 */}, +{ "+-", "\261", /* 177 */}, +{ "S2", "\262", /* 178 */}, +{ "S3", "\263", /* 179 */}, +{ "aa", "\264", /* 180 */}, +/* Omit *m here; we want *m to match the other greek letters in the + symbol font. */ +{ "\265", /* 181 */}, +{ "ps", "\266", /* 182 */}, +{ "md", "\267", /* 183 */}, +{ "ac", "\270", /* 184 */}, +{ "S1", "\271", /* 185 */}, +{ "Om", "\272", /* 186 */}, +{ "Fc", "\273", /* 187 */}, +{ "14", "\274", /* 188 */}, +{ "12", "\275", /* 189 */}, +{ "34", "\276", /* 190 */}, +{ "r?", "\277", /* 191 */}, +{ "`A", "\300", /* 192 */}, +{ "'A", "\301", /* 193 */}, +{ "^A", "\302", /* 194 */}, +{ "~A", "\303", /* 195 */}, +{ ":A", "\304", /* 196 */}, +{ "oA", "\305", /* 197 */}, +{ "AE", "\306", /* 198 */}, +{ ",C", "\307", /* 199 */}, +{ "`E", "\310", /* 200 */}, +{ "'E", "\311", /* 201 */}, +{ "^E", "\312", /* 202 */}, +{ ":E", "\313", /* 203 */}, +{ "`I", "\314", /* 204 */}, +{ "'I", "\315", /* 205 */}, +{ "^I", "\316", /* 206 */}, +{ ":I", "\317", /* 207 */}, +{ "-D", "\320", /* 208 */}, +{ "~N", "\321", /* 209 */}, +{ "`O", "\322", /* 210 */}, +{ "'O", "\323", /* 211 */}, +{ "^O", "\324", /* 212 */}, +{ "~O", "\325", /* 213 */}, +{ ":O", "\326", /* 214 */}, +{ "mu", "\327", /* 215 */}, +{ "/O", "\330", /* 216 */}, +{ "`U", "\331", /* 217 */}, +{ "'U", "\332", /* 218 */}, +{ "^U", "\333", /* 219 */}, +{ ":U", "\334", /* 220 */}, +{ "'Y", "\335", /* 221 */}, +{ "TP", "\336", /* 222 */}, +{ "ss", "\337", /* 223 */}, +{ "`a", "\340", /* 224 */}, +{ "'a", "\341", /* 225 */}, +{ "^a", "\342", /* 226 */}, +{ "~a", "\343", /* 227 */}, +{ ":a", "\344", /* 228 */}, +{ "oa", "\345", /* 229 */}, +{ "ae", "\346", /* 230 */}, +{ ",c", "\347", /* 231 */}, +{ "`e", "\350", /* 232 */}, +{ "'e", "\351", /* 233 */}, +{ "^e", "\352", /* 234 */}, +{ ":e", "\353", /* 235 */}, +{ "`i", "\354", /* 236 */}, +{ "'i", "\355", /* 237 */}, +{ "^i", "\356", /* 238 */}, +{ ":i", "\357", /* 239 */}, +{ "Sd", "\360", /* 240 */}, +{ "~n", "\361", /* 241 */}, +{ "`o", "\362", /* 242 */}, +{ "'o", "\363", /* 243 */}, +{ "^o", "\364", /* 244 */}, +{ "~o", "\365", /* 245 */}, +{ ":o", "\366", /* 246 */}, +{ "di", "\367", /* 247 */}, +{ "/o", "\370", /* 248 */}, +{ "`u", "\371", /* 249 */}, +{ "'u", "\372", /* 250 */}, +{ "^u", "\373", /* 251 */}, +{ ":u", "\374", /* 252 */}, +{ "'y", "\375", /* 253 */}, +{ "Tp", "\376", /* 254 */}, +{ ":y", "\377", /* 255 */}, +}}; + +static DviCharNameMap Adobe_Symbol_map = { + "adobe-fontspecific", + 1, +{ +{ 0, /* 0 */}, +{ 0, /* 1 */}, +{ 0, /* 2 */}, +{ 0, /* 3 */}, +{ 0, /* 4 */}, +{ 0, /* 5 */}, +{ 0, /* 6 */}, +{ 0, /* 7 */}, +{ 0, /* 8 */}, +{ 0, /* 9 */}, +{ 0, /* 10 */}, +{ 0, /* 11 */}, +{ 0, /* 12 */}, +{ 0, /* 13 */}, +{ 0, /* 14 */}, +{ 0, /* 15 */}, +{ 0, /* 16 */}, +{ 0, /* 17 */}, +{ 0, /* 18 */}, +{ 0, /* 19 */}, +{ 0, /* 20 */}, +{ 0, /* 21 */}, +{ 0, /* 22 */}, +{ 0, /* 23 */}, +{ 0, /* 24 */}, +{ 0, /* 25 */}, +{ 0, /* 26 */}, +{ 0, /* 27 */}, +{ 0, /* 28 */}, +{ 0, /* 29 */}, +{ 0, /* 30 */}, +{ 0, /* 31 */}, +{ 0, /* 32 */}, +{ "!", /* 33 */}, +{ "fa", /* 34 */}, +{ "#", "sh", /* 35 */}, +{ "te", /* 36 */}, +{ "%", /* 37 */}, +{ "&", /* 38 */}, +{ "st", /* 39 */}, +{ "(", /* 40 */}, +{ ")", /* 41 */}, +{ "**", /* 42 */}, +{ "+", "pl", /* 43 */}, +{ ",", /* 44 */}, +{ "\\-", "mi", /* 45 */}, +{ ".", /* 46 */}, +{ "/", "sl", /* 47 */}, +{ "0", /* 48 */}, +{ "1", /* 49 */}, +{ "2", /* 50 */}, +{ "3", /* 51 */}, +{ "4", /* 52 */}, +{ "5", /* 53 */}, +{ "6", /* 54 */}, +{ "7", /* 55 */}, +{ "8", /* 56 */}, +{ "9", /* 57 */}, +{ ":", /* 58 */}, +{ ";", /* 59 */}, +{ "<", /* 60 */}, +{ "=", "eq", /* 61 */}, +{ ">", /* 62 */}, +{ "?", /* 63 */}, +{ "=~", /* 64 */}, +{ "*A", /* 65 */}, +{ "*B", /* 66 */}, +{ "*X", /* 67 */}, +{ "*D", /* 68 */}, +{ "*E", /* 69 */}, +{ "*F", /* 70 */}, +{ "*G", /* 71 */}, +{ "*Y", /* 72 */}, +{ "*I", /* 73 */}, +{ "+h", /* 74 */}, +{ "*K", /* 75 */}, +{ "*L", /* 76 */}, +{ "*M", /* 77 */}, +{ "*N", /* 78 */}, +{ "*O", /* 79 */}, +{ "*P", /* 80 */}, +{ "*H", /* 81 */}, +{ "*R", /* 82 */}, +{ "*S", /* 83 */}, +{ "*T", /* 84 */}, +{ 0, /* 85 */}, +{ "ts", /* 86 */}, +{ "*W", /* 87 */}, +{ "*C", /* 88 */}, +{ "*Q", /* 89 */}, +{ "*Z", /* 90 */}, +{ "[", "lB", /* 91 */}, +{ "tf", "3d", /* 92 */}, +{ "]", "rB", /* 93 */}, +{ "pp", /* 94 */}, +{ "_", /* 95 */}, +{ "rn", /* 96 */}, +{ "*a", /* 97 */}, +{ "*b", /* 98 */}, +{ "*x", /* 99 */}, +{ "*d", /* 100 */}, +{ "*e", /* 101 */}, +{ "*f", /* 102 */}, +{ "*g", /* 103 */}, +{ "*y", /* 104 */}, +{ "*i", /* 105 */}, +{ "+f", /* 106 */}, +{ "*k", /* 107 */}, +{ "*l", /* 108 */}, +{ "*m", "\265", /* 109 */}, +{ "*n", /* 110 */}, +{ "*o", /* 111 */}, +{ "*p", /* 112 */}, +{ "*h", /* 113 */}, +{ "*r", /* 114 */}, +{ "*s", /* 115 */}, +{ "*t", /* 116 */}, +{ "*u", /* 117 */}, +{ "+p", /* 118 */}, +{ "*w", /* 119 */}, +{ "*c", /* 120 */}, +{ "*q", /* 121 */}, +{ "*z", /* 122 */}, +{ "lC", "{", /* 123 */}, +{ "ba", "or", "|", /* 124 */}, +{ "rC", "}", /* 125 */}, +{ "ap", /* 126 */}, +{ 0, /* 127 */}, +{ 0, /* 128 */}, +{ 0, /* 129 */}, +{ 0, /* 130 */}, +{ 0, /* 131 */}, +{ 0, /* 132 */}, +{ 0, /* 133 */}, +{ 0, /* 134 */}, +{ 0, /* 135 */}, +{ 0, /* 136 */}, +{ 0, /* 137 */}, +{ 0, /* 138 */}, +{ 0, /* 139 */}, +{ 0, /* 140 */}, +{ 0, /* 141 */}, +{ 0, /* 142 */}, +{ 0, /* 143 */}, +{ 0, /* 144 */}, +{ 0, /* 145 */}, +{ 0, /* 146 */}, +{ 0, /* 147 */}, +{ 0, /* 148 */}, +{ 0, /* 149 */}, +{ 0, /* 150 */}, +{ 0, /* 151 */}, +{ 0, /* 152 */}, +{ 0, /* 153 */}, +{ 0, /* 154 */}, +{ 0, /* 155 */}, +{ 0, /* 156 */}, +{ 0, /* 157 */}, +{ 0, /* 158 */}, +{ 0, /* 159 */}, +{ 0, /* 160 */}, +{ "*U", /* 161 */}, +{ "fm", /* 162 */}, +{ "<=", /* 163 */}, +{ "f/", /* 164 */}, +{ "if", /* 165 */}, +{ "Fn", /* 166 */}, +{ "CL", /* 167 */}, +{ "DI", /* 168 */}, +{ "HE", /* 169 */}, +{ "SP", /* 170 */}, +{ "<>", /* 171 */}, +{ "<-", /* 172 */}, +{ "ua", "arrowverttp" /* 173 */}, +{ "->", /* 174 */}, +{ "da", "arrowvertbt" /* 175 */}, +{ "de", "\260", /* 176 */}, +{ "+-", "\261", /* 177 */}, +{ "sd", /* 178 */}, +{ ">=", /* 179 */}, +{ "mu", "\327", /* 180 */}, +{ "pt", /* 181 */}, +{ "pd", /* 182 */}, +{ "bu", /* 183 */}, +{ "di", "\367", /* 184 */}, +{ "!=", /* 185 */}, +{ "==", /* 186 */}, +{ "~=", "~~", /* 187 */}, +{ 0, /* 188 */}, +{ "arrowvertex", /* 189 */}, +{ "an", /* 190 */}, +{ "CR", /* 191 */}, +{ "Ah", /* 192 */}, +{ "Im", /* 193 */}, +{ "Re", /* 194 */}, +{ "wp", /* 195 */}, +{ "c*", /* 196 */}, +{ "c+", /* 197 */}, +{ "es", /* 198 */}, +{ "ca", /* 199 */}, +{ "cu", /* 200 */}, +{ "sp", /* 201 */}, +{ "ip", /* 202 */}, +{ 0, /* 203 */}, +{ "sb", /* 204 */}, +{ "ib", /* 205 */}, +{ "mo", /* 206 */}, +{ "nm", /* 207 */}, +{ "/_", /* 208 */}, +{ "gr", /* 209 */}, +{ "rg", /* 210 */}, +{ "co", /* 211 */}, +{ "tm", /* 212 */}, +{ 0, /* 213 */}, +{ "sr", /* 214 */}, +{ "md", /* 215 */}, +{ "no", "\254", /* 216 */}, +{ "AN", /* 217 */}, +{ "OR", /* 218 */}, +{ "hA", /* 219 */}, +{ "lA", /* 220 */}, +{ "uA", /* 221 */}, +{ "rA", /* 222 */}, +{ "dA", /* 223 */}, +{ "lz", /* 224 */}, +{ "la", /* 225 */}, +{ 0, /* 226 */}, +{ 0, /* 227 */}, +{ 0, /* 228 */}, +{ 0, /* 229 */}, +{ "parenlefttp", /* 230 */}, +{ "parenleftex", /* 231 */}, +{ "parenleftbt", /* 232 */}, +{ "bracketlefttp", "lc", /* 233 */}, +{ "bracketleftex", /* 234 */}, +{ "bracketleftbt", "lf", /* 235 */}, +{ "bracelefttp", "lt", /* 236 */}, +{ "braceleftmid", "lk", /* 237 */}, +{ "braceleftbt", "lb", /* 238 */}, +{ "bracerightex", "braceleftex", "bv", /* 239 */}, +{ 0, /* 240 */}, +{ "ra", /* 241 */}, +{ "is", /* 242 */}, +{ 0, /* 243 */}, +{ 0, /* 244 */}, +{ 0, /* 245 */}, +{ "parenrighttp", /* 246 */}, +{ "parenrightex", /* 247 */}, +{ "parenrightbt", /* 248 */}, +{ "bracketrighttp", "rc", /* 249 */}, +{ "bracketrightex", /* 250 */}, +{ "bracketrightbt", "rf", /* 251 */}, +{ "bracerighttp", "rt" /* 252 */}, +{ "bracerightmid", "rk" /* 253 */}, +{ "bracerightbt", "rb" /* 254 */}, +{ 0, /* 255 */}, +}}; + + +static void +load_standard_maps () +{ + standard_maps_loaded = 1; + DviRegisterMap (&ISO8859_1_map); + DviRegisterMap (&Adobe_Symbol_map); +} diff --git a/gnu/usr.bin/groff/xditview/DviChar.h b/gnu/usr.bin/groff/xditview/DviChar.h new file mode 100644 index 0000000000..4a8f6bbe6f --- /dev/null +++ b/gnu/usr.bin/groff/xditview/DviChar.h @@ -0,0 +1,37 @@ +/* + * DviChar.h + * + * descriptions for mapping dvi names to + * font indexes and back. Dvi fonts are all + * 256 elements (actually only 256-32 are usable). + * + * The encoding names are taken from X - + * case insensitive, a dash seperating the + * CharSetRegistry from the CharSetEncoding + */ + +# define DVI_MAX_SYNONYMS 10 +# define DVI_MAP_SIZE 256 +# define DVI_HASH_SIZE 256 + +typedef struct _dviCharNameHash { + struct _dviCharNameHash *next; + char *name; + int position; +} DviCharNameHash; + +typedef struct _dviCharNameMap { + char *encoding; + int special; + char *dvi_names[DVI_MAP_SIZE][DVI_MAX_SYNONYMS]; + DviCharNameHash *buckets[DVI_HASH_SIZE]; +} DviCharNameMap; + +extern DviCharNameMap *DviFindMap ( /* char *encoding */ ); +extern void DviRegisterMap ( /* DviCharNameMap *map */ ); +#ifdef NOTDEF +extern char *DviCharName ( /* DviCharNameMap *map, int index, int synonym */ ); +#else +#define DviCharName(map,index,synonym) ((map)->dvi_names[index][synonym]) +#endif +extern int DviCharIndex ( /* DviCharNameMap *map, char *name */ ); diff --git a/gnu/usr.bin/groff/xditview/DviP.h b/gnu/usr.bin/groff/xditview/DviP.h new file mode 100644 index 0000000000..c3b7d2c713 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/DviP.h @@ -0,0 +1,233 @@ +/* + * $XConsortium: DviP.h,v 1.5 89/07/22 19:44:08 keith Exp $ + */ + +/* + * DviP.h - Private definitions for Dvi widget + */ + +#ifndef _XtDviP_h +#define _XtDviP_h + +#include "Dvi.h" +#include "DviChar.h" +#include "device.h" + +/*********************************************************************** + * + * Dvi Widget Private Data + * + ***********************************************************************/ + +/************************************ + * + * Class structure + * + ***********************************/ + +/* Type for save method. */ + +typedef void (*DviSaveProc)(); + +/* + * New fields for the Dvi widget class record + */ + + +typedef struct _DviClass { + DviSaveProc save; +} DviClassPart; + +/* + * Full class record declaration + */ + +typedef struct _DviClassRec { + CoreClassPart core_class; + DviClassPart command_class; +} DviClassRec; + +extern DviClassRec dviClassRec; + +/*************************************** + * + * Instance (widget) structure + * + **************************************/ + +/* + * a list of fonts we've used for this widget + */ + +typedef struct _dviFontSizeList { + struct _dviFontSizeList *next; + int size; + char *x_name; + XFontStruct *font; + int doesnt_exist; +} DviFontSizeList; + +typedef struct _dviFontList { + struct _dviFontList *next; + char *dvi_name; + char *x_name; + int dvi_number; + Boolean initialized; + Boolean scalable; + DviFontSizeList *sizes; + DviCharNameMap *char_map; + DeviceFont *device_font; +} DviFontList; + +typedef struct _dviFontMap { + struct _dviFontMap *next; + char *dvi_name; + char *x_name; +} DviFontMap; + +#define DVI_TEXT_CACHE_SIZE 256 +#define DVI_CHAR_CACHE_SIZE 1024 + +typedef struct _dviCharCache { + XTextItem cache[DVI_TEXT_CACHE_SIZE]; + char adjustable[DVI_TEXT_CACHE_SIZE]; + char char_cache[DVI_CHAR_CACHE_SIZE]; + int index; + int max; + int char_index; + int font_size; + int font_number; + XFontStruct *font; + int start_x, start_y; + int x, y; +} DviCharCache; + +typedef struct _dviState { + struct _dviState *next; + int font_size; + int font_number; + int x; + int y; +} DviState; + +typedef struct _dviFileMap { + struct _dviFileMap *next; + long position; + int page_number; +} DviFileMap; + +/* + * New fields for the Dvi widget record + */ + +typedef struct { + /* + * resource specifiable items + */ + char *font_map_string; + unsigned long foreground; + unsigned long background; + int requested_page; + int last_page; + XFontStruct *default_font; + FILE *file; + Boolean noPolyText; + Boolean seek; /* file is "seekable" */ + int default_resolution; + /* + * private state + */ + FILE *tmpFile; /* used when reading stdin */ + char readingTmp; /* reading now from tmp */ + char ungot; /* have ungetc'd a char */ + GC normal_GC; + GC fill_GC; + DviFileMap *file_map; + DviFontList *fonts; + DviFontMap *font_map; + int current_page; + int font_size; + int font_number; + DeviceFont *device_font; + int device_font_number; + Device *device; + int native; + int device_resolution; + int display_resolution; + int paperlength; + int paperwidth; + double scale_factor; /* display res / device res */ + int sizescale; + int line_thickness; + int line_width; + +#define DVI_FILL_MAX 1000 + + int fill; +#define DVI_FILL_WHITE 0 +#define DVI_FILL_GRAY 1 +#define DVI_FILL_BLACK 2 + int fill_type; + Pixmap gray; + int backing_store; + XFontStruct *font; + int display_enable; + struct ExposedExtents { + int x1, y1, x2, y2; + } extents; + DviState *state; + DviCharCache cache; + int text_x_width; + int text_device_width; + int word_flag; +} DviPart; + +#define DviGetIn(dw,cp)\ + (dw->dvi.tmpFile ? (\ + DviGetAndPut (dw, cp) \ + ) :\ + (*cp = getc (dw->dvi.file))\ +) + +#define DviGetC(dw, cp)\ + (dw->dvi.readingTmp ? (\ + ((*cp = getc (dw->dvi.tmpFile)) == EOF) ? (\ + fseek (dw->dvi.tmpFile, 0l, 2),\ + (dw->dvi.readingTmp = 0),\ + DviGetIn (dw,cp)\ + ) : (\ + *cp\ + )\ + ) : (\ + DviGetIn(dw,cp)\ + )\ +) + +#define DviUngetC(dw, c)\ + (dw->dvi.readingTmp ? (\ + ungetc (c, dw->dvi.tmpFile)\ + ) : ( \ + (dw->dvi.ungot = 1),\ + ungetc (c, dw->dvi.file))) + +/* + * Full widget declaration + */ + +typedef struct _DviRec { + CorePart core; + DviPart dvi; +} DviRec; + +#define InheritSaveToFile ((DviSaveProc)_XtInherit) + +extern XFontStruct *QueryFont (); + +extern DviCharNameMap *QueryFontMap (); + +extern DeviceFont *QueryDeviceFont (); + +extern char *GetWord(), *GetLine(); +#endif /* _XtDviP_h */ + + diff --git a/gnu/usr.bin/groff/xditview/FontMap b/gnu/usr.bin/groff/xditview/FontMap new file mode 100644 index 0000000000..90911f048d --- /dev/null +++ b/gnu/usr.bin/groff/xditview/FontMap @@ -0,0 +1,17 @@ +TR -adobe-times-medium-r-normal--*-*-*-*-p-*-iso8859-1 +TI -adobe-times-medium-i-normal--*-*-*-*-p-*-iso8859-1 +TB -adobe-times-bold-r-normal--*-*-*-*-p-*-iso8859-1 +TBI -adobe-times-bold-i-normal--*-*-*-*-p-*-iso8859-1 +CR -adobe-courier-medium-r-normal--*-*-*-*-m-*-iso8859-1 +CI -adobe-courier-medium-o-normal--*-*-*-*-m-*-iso8859-1 +CB -adobe-courier-bold-r-normal--*-*-*-*-m-*-iso8859-1 +CBI -adobe-courier-bold-o-normal--*-*-*-*-m-*-iso8859-1 +HR -adobe-helvetica-medium-r-normal--*-*-*-*-p-*-iso8859-1 +HI -adobe-helvetica-medium-o-normal--*-*-*-*-p-*-iso8859-1 +HB -adobe-helvetica-bold-r-normal--*-*-*-*-p-*-iso8859-1 +HBI -adobe-helvetica-bold-o-normal--*-*-*-*-p-*-iso8859-1 +NR -adobe-new century schoolbook-medium-r-normal--*-*-*-*-p-*-iso8859-1 +NI -adobe-new century schoolbook-medium-i-normal--*-*-*-*-p-*-iso8859-1 +NB -adobe-new century schoolbook-bold-r-normal--*-*-*-*-p-*-iso8859-1 +NBI -adobe-new century schoolbook-bold-i-normal--*-*-*-*-p-*-iso8859-1 +S -adobe-symbol-medium-r-normal--*-*-*-*-p-*-adobe-fontspecific diff --git a/gnu/usr.bin/groff/xditview/GXditview.ad b/gnu/usr.bin/groff/xditview/GXditview.ad new file mode 100644 index 0000000000..e99ff5e16f --- /dev/null +++ b/gnu/usr.bin/groff/xditview/GXditview.ad @@ -0,0 +1,57 @@ +GXditview.height: 840 + +GXditview.paned.allowResize: true +GXditview.paned.viewport.allowVert: true +GXditview.paned.viewport.allowHoriz: true +GXditview.paned.viewport.skipAdjust: false +GXditview.paned.viewport.width: 600 +GXditview.paned.viewport.height: 800 +GXditview.paned.viewport.showGrip: false +GXditview.paned.label.skipAdjust: true + +GXditview.paned.viewport.dvi.translations: #augment \ + : XawPositionSimpleMenu(menu) MenuPopup(menu)\n\ + Next: NextPage()\n\ + n: NextPage()\n\ + space: NextPage()\n\ + Return: NextPage()\n\ + Prior: PreviousPage()\n\ + p: PreviousPage()\n\ + BackSpace: PreviousPage()\n\ + Delete: PreviousPage()\n\ + Select: SelectPage()\n\ + Find: OpenFile()\n\ + r: Rerasterize()\n\ + q: Quit() +GXditview.paned.label.translations: #augment \ + : XawPositionSimpleMenu(menu) MenuPopup(menu)\n\ + Next: NextPage()\n\ + n: NextPage()\n\ + space: NextPage()\n\ + Return: NextPage()\n\ + Prior: PreviousPage()\n\ + p: PreviousPage()\n\ + BackSpace: PreviousPage()\n\ + Delete: PreviousPage()\n\ + Select: SelectPage()\n\ + Find: OpenFile()\n\ + r: Rerasterize()\n\ + q: Quit() +GXditview.menu.nextPage.label: Next Page +GXditview.menu.previousPage.label: Previous Page +GXditview.menu.selectPage.label: Select Page +GXditview.menu.print.label: Print +GXditview.menu.openFile.label: Open +GXditview.menu.quit.label: Quit + +GXditview.promptShell.allowShellResize: true +GXditview.promptShell.promptDialog.value.translations: #override \ + Return: Accept() + +GXditview.promptShell.promptDialog.accept.label: Accept +GXditview.promptShell.promptDialog.accept.translations: #override \ + : Accept() unset() + +GXditview.promptShell.promptDialog.cancel.label: Cancel +GXditview.promptShell.promptDialog.cancel.translations: #override \ + : Cancel() unset() diff --git a/gnu/usr.bin/groff/xditview/INSTALL b/gnu/usr.bin/groff/xditview/INSTALL new file mode 100644 index 0000000000..144118fd7d --- /dev/null +++ b/gnu/usr.bin/groff/xditview/INSTALL @@ -0,0 +1,20 @@ +This version of gxditview uses imake. + +Here are the steps needed to install gxditview: + +- edit the Imakefile if necessary + +- xmkmf + +- make depend + +- make + +- make install + +- make install.man (installs the man page) + +The gxditview binary will be installed in the usual place for X +binaries (eg /usr/bin/X11). Previous versions of gxditview were +installed along with the other groff binaries (eg in /usr/local/bin); +you will need to remove these by hand. diff --git a/gnu/usr.bin/groff/xditview/Imakefile b/gnu/usr.bin/groff/xditview/Imakefile new file mode 100644 index 0000000000..62ac707f24 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/Imakefile @@ -0,0 +1,52 @@ +GROFF_LIBDIR = /usr/local/lib/groff +GROFF_FONTDIR = $(GROFF_LIBDIR)/font +GROFF_FONTPATH = .:$(GROFF_FONTDIR):/usr/local/lib/font:/usr/lib/font +DPIS = 75 100 + +PROGRAMS = gxditview xtotroff +DEPLIBS = XawClientDepLibs +LOCAL_LIBRARIES = XawClientLibs +SRCS1 = xditview.c Dvi.c draw.c font.c lex.c page.c \ + parse.c XFontName.c DviChar.c device.c +OBJS1 = xditview.o Dvi.o draw.o font.o lex.o page.o \ + parse.o XFontName.o DviChar.o device.o +SRCS2 = xtotroff.c XFontName.c DviChar.c +OBJS2 = xtotroff.o XFontName.o DviChar.o +INCLUDES = -I$(TOOLKITSRC) -I$(TOP) +MATHLIB = -lm +DEFINES = $(SIGNAL_DEFINES) -DFONTPATH=\"$(GROFF_FONTPATH)\" # -DX_NOT_STDC_ENV + +ComplexProgramTarget_1(gxditview,$(LOCAL_LIBRARIES),$(MATHLIB)) +NormalProgramTarget(xtotroff,$(OBJS2),$(DEPXLIB),$(XLIB), /**/) + +InstallAppDefaults(GXditview) + +fonts: xtotroff DESC FontMap + @dir=`pwd`; \ + fonts=`sed -e 's/[ ].*//' FontMap`; \ + for dpi in $(DPIS); do \ + echo Making devX$$dpi; \ + test -d ../devX$$dpi || mkdir ../devX$$dpi; \ + rm -f ../devX$$dpi/DESC; \ + sed -e "s/res 75/res $$dpi/" DESC >../devX$$dpi/DESC; \ + (cd ../devX$$dpi; \ + rm -f Makefile.sub; \ + echo DEV=X$$dpi >Makefile.sub; \ + echo DEVFILES=DESC $$fonts >>Makefile.sub; \ + $$dir/xtotroff -g -r $$dpi -s 10 $$dir/FontMap); \ + echo Making devX$$dpi-12; \ + test -d ../devX$$dpi-12 || mkdir ../devX$$dpi-12; \ + rm -f ../devX$$dpi-12/DESC; \ + sed -e "s/res 75/res $$dpi/" -e 's/unitwidth 10/unitwidth 12/' DESC \ + >../devX$$dpi-12/DESC; \ + (cd ../devX$$dpi-12; \ + rm -f Makefile.sub; \ + echo DEV=X$$dpi-12 >Makefile.sub; \ + echo DEVFILES=DESC $$fonts >>Makefile.sub; \ + $$dir/xtotroff -g -r $$dpi -s 12 $$dir/FontMap); \ + done + +extraclean: clean + -rm -f junk tmp grot old + +FORCE: diff --git a/gnu/usr.bin/groff/xditview/Makefile b/gnu/usr.bin/groff/xditview/Makefile new file mode 100644 index 0000000000..1e2a9a6e30 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/Makefile @@ -0,0 +1,17 @@ +.if exists(/usr/X386) + +BINDIR= /usr/X386/bin +MANDIR= /usr/X386/man/cat + +PROG= gxditview +CFLAGS+= -I/usr/X386/include -DFONTPATH=\"/usr/share/groff_font\" +SRCS+= xditview.c Dvi.c draw.c font.c lex.c page.c parse.c \ + XFontName.c DviChar.c device.c +LDADD+= -L/usr/X386/lib -lXaw -lXmu -lXt -lXext -lX11 -lm + +afterinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/GXditview.ad \ + $(DESTDIR)/usr/X386/lib/X11/app-defaults +.endif + +.include diff --git a/gnu/usr.bin/groff/xditview/Menu.h b/gnu/usr.bin/groff/xditview/Menu.h new file mode 100644 index 0000000000..c306b2740a --- /dev/null +++ b/gnu/usr.bin/groff/xditview/Menu.h @@ -0,0 +1,46 @@ +/* + * $XConsortium: Menu.h,v 1.2 89/07/21 14:22:10 jim Exp $ + */ + +#ifndef _XtMenu_h +#define _XtMenu_h + +/*********************************************************************** + * + * Menu Widget + * + ***********************************************************************/ + +/* Parameters: + + Name Class RepType Default Value + ---- ----- ------- ------------- + background Background pixel White + border BorderColor pixel Black + borderWidth BorderWidth int 1 + height Height int 120 + mappedWhenManaged MappedWhenManaged Boolean True + reverseVideo ReverseVideo Boolean False + width Width int 120 + x Position int 0 + y Position int 0 + +*/ + +#define XtNmenuEntries "menuEntries" +#define XtNhorizontalPadding "horizontalPadding" +#define XtNverticalPadding "verticalPadding" +#define XtNselection "Selection" + +#define XtCMenuEntries "MenuEntries" +#define XtCPadding "Padding" +#define XtCSelection "Selection" + +typedef struct _MenuRec *MenuWidget; /* completely defined in MenuPrivate.h */ +typedef struct _MenuClassRec *MenuWidgetClass; /* completely defined in MenuPrivate.h */ + +extern WidgetClass menuWidgetClass; + +extern Widget XawMenuCreate (); +#endif /* _XtMenu_h */ +/* DON'T ADD STUFF AFTER THIS #endif */ diff --git a/gnu/usr.bin/groff/xditview/README b/gnu/usr.bin/groff/xditview/README new file mode 100644 index 0000000000..b99a991857 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/README @@ -0,0 +1,14 @@ +This is gxditview, a X11 previewer for groff based on MIT's xditview. +This version can be used with the output of gtroff -Tps as well as +with -TX75 and -TX100. You will need X11R5 to install it (it might +work on X11R4, but I haven't tested it.) + +See the file INSTALL in this directory for installation instructions. + +xditview is copyrighted by MIT under the usual X terms (see +gxditview.man); my changes to it are in the public domain. + +Please report bugs to bug-groff@prep.ai.mit.edu. + +James Clark +jjc@jclark.com diff --git a/gnu/usr.bin/groff/xditview/TODO b/gnu/usr.bin/groff/xditview/TODO new file mode 100644 index 0000000000..88a0dae2ea --- /dev/null +++ b/gnu/usr.bin/groff/xditview/TODO @@ -0,0 +1,15 @@ +Better error handling. + +Resource and command-line option to specify font path. + +Resource to specify name of environment variable from which to get the +font path. + +Have character substitutions (currently done in draw.c:FakeCharacter) +specified in a resource (similar format to FontMap). + +The initial width of the dialog box should expand to accomodate the +default value. + +Option in Print dialog to specify that only the current page should be +printed. diff --git a/gnu/usr.bin/groff/xditview/XFontName.c b/gnu/usr.bin/groff/xditview/XFontName.c new file mode 100644 index 0000000000..5ca9bb81e9 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/XFontName.c @@ -0,0 +1,256 @@ +/* + * XFontName.c + * + * build/parse X Font name strings + */ + +#include +#include +#include "XFontName.h" +#include + +static char * +extractStringField (name, buffer, size, attrp, bit) + char *name; + char *buffer; + int size; + unsigned int *attrp; + unsigned int bit; +{ + char *buf = buffer; + + if (!*name) + return 0; + while (*name && *name != '-' && size > 0) { + *buf++ = *name++; + --size; + } + if (size <= 0) + return 0; + *buf = '\0'; + if (buffer[0] != '*' || buffer[1] != '\0') + *attrp |= bit; + if (*name == '-') + return name+1; + return name; +} + +static char * +extractUnsignedField (name, result, attrp, bit) + char *name; + unsigned int *result; + unsigned int *attrp; + unsigned int bit; +{ + char buf[256]; + char *c; + unsigned int i; + + name = extractStringField (name, buf, sizeof (buf), attrp, bit); + if (!name) + return 0; + if (!(*attrp & bit)) + return name; + i = 0; + for (c = buf; *c; c++) { + if (!isdigit (*c)) + return 0; + i = i * 10 + (*c - '0'); + } + *result = i; + return name; +} + +Bool +XParseFontName (fontNameString, fontName, fontNameAttributes) + XFontNameString fontNameString; + XFontName *fontName; + unsigned int *fontNameAttributes; +{ + char *name = fontNameString; + XFontName temp; + unsigned int attributes = 0; + +#define GetString(field,bit)\ + if (!(name = extractStringField \ + (name, temp.field, sizeof (temp.field),\ + &attributes, bit))) \ + return False; + +#define GetUnsigned(field,bit)\ + if (!(name = extractUnsignedField \ + (name, &temp.field, \ + &attributes, bit))) \ + return False; + + GetString (Registry, FontNameRegistry) + GetString (Foundry, FontNameFoundry) + GetString (FamilyName, FontNameFamilyName) + GetString (WeightName, FontNameWeightName) + GetString (Slant, FontNameSlant) + GetString (SetwidthName, FontNameSetwidthName) + GetString (AddStyleName, FontNameAddStyleName) + GetUnsigned (PixelSize, FontNamePixelSize) + GetUnsigned (PointSize, FontNamePointSize) + GetUnsigned (ResolutionX, FontNameResolutionX) + GetUnsigned (ResolutionY, FontNameResolutionY) + GetString (Spacing, FontNameSpacing) + GetUnsigned (AverageWidth, FontNameAverageWidth) + GetString (CharSetRegistry, FontNameCharSetRegistry) + if (!*name) { + temp.CharSetEncoding[0] = '\0'; + attributes |= FontNameCharSetEncoding; + } else { + GetString (CharSetEncoding, FontNameCharSetEncoding) + } + *fontName = temp; + *fontNameAttributes = attributes; + return True; +} + +static char * +utoa (u, s, size) + unsigned int u; + char *s; + int size; +{ + char *t; + + t = s + size; + *--t = '\0'; + do + *--t = (u % 10) + '0'; + while (u /= 10); + return t; +} + +Bool +XFormatFontName (fontName, fontNameAttributes, fontNameString) + XFontName *fontName; + unsigned int fontNameAttributes; + XFontNameString fontNameString; +{ + XFontNameString tmp; + char *name = tmp, *f; + int left = sizeof (tmp) - 1; + char number[32]; + +#define PutString(field, bit)\ + f = (fontNameAttributes & bit) ? \ + fontName->field \ + : "*"; \ + if ((left -= strlen (f)) < 0) \ + return False; \ + while (*f) \ + if ((*name++ = *f++) == '-') \ + return False; +#define PutHyphen()\ + if (--left < 0) \ + return False; \ + *name++ = '-'; + +#define PutUnsigned(field, bit) \ + f = (fontNameAttributes & bit) ? \ + utoa (fontName->field, number, sizeof (number)) \ + : "*"; \ + if ((left -= strlen (f)) < 0) \ + return False; \ + while (*f) \ + *name++ = *f++; + + PutString (Registry, FontNameRegistry) + PutHyphen (); + PutString (Foundry, FontNameFoundry) + PutHyphen (); + PutString (FamilyName, FontNameFamilyName) + PutHyphen (); + PutString (WeightName, FontNameWeightName) + PutHyphen (); + PutString (Slant, FontNameSlant) + PutHyphen (); + PutString (SetwidthName, FontNameSetwidthName) + PutHyphen (); + PutString (AddStyleName, FontNameAddStyleName) + PutHyphen (); + PutUnsigned (PixelSize, FontNamePixelSize) + PutHyphen (); + PutUnsigned (PointSize, FontNamePointSize) + PutHyphen (); + PutUnsigned (ResolutionX, FontNameResolutionX) + PutHyphen (); + PutUnsigned (ResolutionY, FontNameResolutionY) + PutHyphen (); + PutString (Spacing, FontNameSpacing) + PutHyphen (); + PutUnsigned (AverageWidth, FontNameAverageWidth) + PutHyphen (); + PutString (CharSetRegistry, FontNameCharSetRegistry) + PutHyphen (); + PutString (CharSetEncoding, FontNameCharSetEncoding) + *name = '\0'; + strcpy (fontNameString, tmp); + return True; +} + +Bool +XCompareFontName (name1, name2, fontNameAttributes) + XFontName *name1, *name2; + unsigned int fontNameAttributes; +{ +#define CompareString(field,bit) \ + if (fontNameAttributes & bit) \ + if (strcmp (name1->field, name2->field)) \ + return False; + +#define CompareUnsigned(field,bit) \ + if (fontNameAttributes & bit) \ + if (name1->field != name2->field) \ + return False; + + CompareString (Registry, FontNameRegistry) + CompareString (Foundry, FontNameFoundry) + CompareString (FamilyName, FontNameFamilyName) + CompareString (WeightName, FontNameWeightName) + CompareString (Slant, FontNameSlant) + CompareString (SetwidthName, FontNameSetwidthName) + CompareString (AddStyleName, FontNameAddStyleName) + CompareUnsigned (PixelSize, FontNamePixelSize) + CompareUnsigned (PointSize, FontNamePointSize) + CompareUnsigned (ResolutionX, FontNameResolutionX) + CompareUnsigned (ResolutionY, FontNameResolutionY) + CompareString (Spacing, FontNameSpacing) + CompareUnsigned (AverageWidth, FontNameAverageWidth) + CompareString (CharSetRegistry, FontNameCharSetRegistry) + CompareString (CharSetEncoding, FontNameCharSetEncoding) + return True; +} + +XCopyFontName (name1, name2, fontNameAttributes) + XFontName *name1, *name2; + unsigned int fontNameAttributes; +{ +#define CopyString(field,bit) \ + if (fontNameAttributes & bit) \ + strcpy (name2->field, name1->field); + +#define CopyUnsigned(field,bit) \ + if (fontNameAttributes & bit) \ + name2->field = name1->field; + + CopyString (Registry, FontNameRegistry) + CopyString (Foundry, FontNameFoundry) + CopyString (FamilyName, FontNameFamilyName) + CopyString (WeightName, FontNameWeightName) + CopyString (Slant, FontNameSlant) + CopyString (SetwidthName, FontNameSetwidthName) + CopyString (AddStyleName, FontNameAddStyleName) + CopyUnsigned (PixelSize, FontNamePixelSize) + CopyUnsigned (PointSize, FontNamePointSize) + CopyUnsigned (ResolutionX, FontNameResolutionX) + CopyUnsigned (ResolutionY, FontNameResolutionY) + CopyString (Spacing, FontNameSpacing) + CopyUnsigned (AverageWidth, FontNameAverageWidth) + CopyString (CharSetRegistry, FontNameCharSetRegistry) + CopyString (CharSetEncoding, FontNameCharSetEncoding) + return True; +} diff --git a/gnu/usr.bin/groff/xditview/XFontName.h b/gnu/usr.bin/groff/xditview/XFontName.h new file mode 100644 index 0000000000..efe9eb16d1 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/XFontName.h @@ -0,0 +1,45 @@ +typedef struct _xFontName { + char Registry[256]; + char Foundry[256]; + char FamilyName[256]; + char WeightName[256]; + char Slant[3]; + char SetwidthName[256]; + char AddStyleName[256]; + unsigned int PixelSize; + unsigned int PointSize; + unsigned int ResolutionX; + unsigned int ResolutionY; + char Spacing[2]; + unsigned int AverageWidth; + char CharSetRegistry[256]; + char CharSetEncoding[256]; +} XFontName; + +#define FontNameRegistry (1<<0) +#define FontNameFoundry (1<<1) +#define FontNameFamilyName (1<<2) +#define FontNameWeightName (1<<3) +#define FontNameSlant (1<<4) +#define FontNameSetwidthName (1<<5) +#define FontNameAddStyleName (1<<6) +#define FontNamePixelSize (1<<7) +#define FontNamePointSize (1<<8) +#define FontNameResolutionX (1<<9) +#define FontNameResolutionY (1<<10) +#define FontNameSpacing (1<<11) +#define FontNameAverageWidth (1<<12) +#define FontNameCharSetRegistry (1<<13) +#define FontNameCharSetEncoding (1<<14) + +#define SlantRoman "R" +#define SlantItalic "I" +#define SlantOblique "O" +#define SlantReverseItalic "RI" +#define SlantReverseOblique "RO" + +#define SpacingMonoSpaced "M" +#define SpacingProportional "P" +#define SpacingCharacterCell "C" + +typedef char XFontNameString[256]; diff --git a/gnu/usr.bin/groff/xditview/device.c b/gnu/usr.bin/groff/xditview/device.c new file mode 100644 index 0000000000..45cce4c6cf --- /dev/null +++ b/gnu/usr.bin/groff/xditview/device.c @@ -0,0 +1,581 @@ +/* device.c */ + +#include +#include + +#include +#include + +#include "device.h" + +#ifndef FONTPATH +#define FONTPATH "/usr/local/lib/groff/font:/usr/local/lib/font:/usr/lib/font" +#endif + +extern void exit(); +extern char *strtok(), *strchr(); +extern char *getenv(); + +/* Name of environment variable containing path to be used for +searching for device and font description files. */ +#define FONTPATH_ENV_VAR "GROFF_FONT_PATH" + +#define WS " \t\r\n" + +/* Minimum and maximum values a `signed int' can hold. */ +#define INT_MIN (-INT_MAX-1) +#define INT_MAX 2147483647 + +#define CHAR_TABLE_SIZE 307 + +struct _DeviceFont { + char *name; + int special; + DeviceFont *next; + Device *dev; + struct charinfo *char_table[CHAR_TABLE_SIZE]; + struct charinfo *code_table[256]; +}; + +struct charinfo { + int width; + int code; + struct charinfo *next; + struct charinfo *code_next; + char name[1]; +}; + +static char *current_filename = 0; +static int current_lineno = -1; + +static void error(); +static FILE *open_device_file(); +static DeviceFont *load_font(); +static Device *new_device(); +static DeviceFont *new_font(); +static void delete_font(); +static unsigned hash_name(); +static struct charinfo *add_char(); +static int read_charset_section(); +static char *canonicalize_name(); + +static +Device *new_device(name) + char *name; +{ + Device *dev; + + dev = XtNew(Device); + dev->sizescale = 1; + dev->res = 0; + dev->unitwidth = 0; + dev->fonts = 0; + dev->X11 = 0; + dev->paperlength = 0; + dev->paperwidth = 0; + dev->name = XtNewString(name); + return dev; +} + +void device_destroy(dev) + Device *dev; +{ + DeviceFont *f; + + if (!dev) + return; + f = dev->fonts; + while (f) { + DeviceFont *tem = f; + f = f->next; + delete_font(tem); + } + + XtFree(dev->name); + XtFree((char *)dev); +} + +Device *device_load(name) + char *name; +{ + Device *dev; + FILE *fp; + int err = 0; + char buf[256]; + + fp = open_device_file(name, "DESC", ¤t_filename); + if (!fp) + return 0; + dev = new_device(name); + current_lineno = 0; + while (fgets(buf, sizeof(buf), fp)) { + char *p; + current_lineno++; + p = strtok(buf, WS); + if (p) { + int *np = 0; + char *q; + + if (strcmp(p, "charset") == 0) + break; + if (strcmp(p, "X11") == 0) + dev->X11 = 1; + else if (strcmp(p, "sizescale") == 0) + np = &dev->sizescale; + else if (strcmp(p, "res") == 0) + np = &dev->res; + else if (strcmp(p, "unitwidth") == 0) + np = &dev->unitwidth; + else if (strcmp(p, "paperwidth") == 0) + np = &dev->paperwidth; + else if (strcmp(p, "paperlength") == 0) + np = &dev->paperlength; + + if (np) { + q = strtok((char *)0, WS); + if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) { + error("bad argument"); + err = 1; + break; + } + } + } + } + fclose(fp); + current_lineno = -1; + if (!err) { + if (dev->res == 0) { + error("missing res line"); + err = 1; + } + else if (dev->unitwidth == 0) { + error("missing unitwidth line"); + err = 1; + } + } + if (dev->paperlength == 0) + dev->paperlength = dev->res*11; + if (dev->paperwidth == 0) + dev->paperwidth = dev->res*8 + dev->res/2; + if (err) { + device_destroy(dev); + dev = 0; + } + XtFree(current_filename); + current_filename = 0; + return dev; +} + + +DeviceFont *device_find_font(dev, name) + Device *dev; + char *name; +{ + DeviceFont *f; + + if (!dev) + return 0; + for (f = dev->fonts; f; f = f->next) + if (strcmp(f->name, name) == 0) + return f; + return load_font(dev, name); +} + +static +DeviceFont *load_font(dev, name) + Device *dev; + char *name; +{ + FILE *fp; + char buf[256]; + DeviceFont *f; + int special = 0; + + fp = open_device_file(dev->name, name, ¤t_filename); + if (!fp) + return 0; + current_lineno = 0; + for (;;) { + char *p; + + if (!fgets(buf, sizeof(buf), fp)) { + error("no charset line"); + return 0; + } + current_lineno++; + p = strtok(buf, WS); + /* charset must be on a line by itself */ + if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0) + break; + if (p && strcmp(p, "special") == 0) + special = 1; + } + f = new_font(name, dev); + f->special = special; + if (!read_charset_section(f, fp)) { + delete_font(f); + f = 0; + } + else { + f->next = dev->fonts; + dev->fonts = f; + } + fclose(fp); + XtFree(current_filename); + current_filename = 0; + return f; +} + +static +DeviceFont *new_font(name, dev) + char *name; + Device *dev; +{ + int i; + DeviceFont *f; + + f = XtNew(DeviceFont); + f->name = XtNewString(name); + f->dev = dev; + f->special = 0; + f->next = 0; + for (i = 0; i < CHAR_TABLE_SIZE; i++) + f->char_table[i] = 0; + for (i = 0; i < 256; i++) + f->code_table[i] = 0; + return f; +} + +static +void delete_font(f) + DeviceFont *f; +{ + int i; + + if (!f) + return; + XtFree(f->name); + for (i = 0; i < CHAR_TABLE_SIZE; i++) { + struct charinfo *ptr = f->char_table[i]; + while (ptr) { + struct charinfo *tem = ptr; + ptr = ptr->next; + XtFree((char *)tem); + } + } + XtFree((char *)f); +} + + +static +unsigned hash_name(name) + char *name; +{ + unsigned n = 0; + /* XXX do better than this */ + while (*name) + n = (n << 1) ^ *name++; + + return n; +} + +static +int scale_round(n, x, y) + int n, x, y; +{ + int y2; + + if (x == 0) + return 0; + y2 = y/2; + if (n >= 0) { + if (n <= (INT_MAX - y2)/x) + return (n*x + y2)/y; + } + else if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x) + return (n*x - y2)/y; + return (int)(n*(double)x/(double)y + .5); +} + +static +char *canonicalize_name(s) + char *s; +{ + static char ch[2]; + if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') { + char *p; + int n; + + for (p = s + 4; *p; p++) + if (!isascii(*p) || !isdigit(*p)) + return s; + n = atoi(s + 4); + if (n >= 0 && n <= 0xff) { + ch[0] = (char)n; + return ch; + } + } + return s; +} + +/* Return 1 if the character is present in the font; widthp gets the +width if non-null. */ + +int device_char_width(f, ps, name, widthp) + DeviceFont *f; + int ps; + char *name; + int *widthp; +{ + struct charinfo *p; + + name = canonicalize_name(name); + for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) { + if (!p) + return 0; + if (strcmp(p->name, name) == 0) + break; + } + *widthp = scale_round(p->width, ps, f->dev->unitwidth); + return 1; +} + +int device_code_width(f, ps, code, widthp) + DeviceFont *f; + int ps; + int code; + int *widthp; +{ + struct charinfo *p; + + for (p = f->code_table[code & 0xff];; p = p->code_next) { + if (!p) + return 0; + if (p->code == code) + break; + } + *widthp = scale_round(p->width, ps, f->dev->unitwidth); + return 1; +} + +char *device_name_for_code(f, code) + DeviceFont *f; + int code; +{ + static struct charinfo *state = 0; + if (f) + state = f->code_table[code & 0xff]; + for (; state; state = state->code_next) + if (state->code == code && state->name[0] != '\0') { + char *name = state->name; + state = state->code_next; + return name; + } + return 0; +} + +int device_font_special(f) + DeviceFont *f; +{ + return f->special; +} + +static +struct charinfo *add_char(f, name, width, code) + DeviceFont *f; + char *name; + int width, code; +{ + struct charinfo **pp; + struct charinfo *ci; + + name = canonicalize_name(name); + if (strcmp(name, "---") == 0) + name = ""; + + ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0]) + + strlen(name) + 1); + + strcpy(ci->name, name); + ci->width = width; + ci->code = code; + + if (*name != '\0') { + pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE]; + ci->next = *pp; + *pp = ci; + } + pp = &f->code_table[code & 0xff]; + ci->code_next = *pp; + *pp = ci; + return ci; +} + +/* Return non-zero for success. */ + +static +int read_charset_section(f, fp) + DeviceFont *f; + FILE *fp; +{ + struct charinfo *last_charinfo = 0; + char buf[256]; + + while (fgets(buf, sizeof(buf), fp)) { + char *name; + int width; + int code; + char *p; + + current_lineno++; + name = strtok(buf, WS); + if (!name) + continue; /* ignore blank lines */ + p = strtok((char *)0, WS); + if (!p) /* end of charset section */ + break; + if (strcmp(p, "\"") == 0) { + if (!last_charinfo) { + error("first line of charset section cannot use `\"'"); + return 0; + } + else + (void)add_char(f, name, + last_charinfo->width, last_charinfo->code); + } + else { + char *q; + if (sscanf(p, "%d", &width) != 1) { + error("bad width field"); + return 0; + } + p = strtok((char *)0, WS); + if (!p) { + error("missing type field"); + return 0; + } + p = strtok((char *)0, WS); + if (!p) { + error("missing code field"); + return 0; + } + code = (int)strtol(p, &q, 0); + if (q == p) { + error("bad code field"); + return 0; + } + last_charinfo = add_char(f, name, width, code); + } + } + return 1; +} + +static +FILE *find_file(file, path, result) + char *file, *path, **result; +{ + char *buf = NULL; + int bufsiz = 0; + int flen; + FILE *fp; + + *result = NULL; + + if (file == NULL) + return NULL; + if (*file == '\0') + return NULL; + + if (*file == '/') { + fp = fopen(file, "r"); + if (fp) + *result = XtNewString(file); + return fp; + } + + flen = strlen(file); + + if (!path) + return NULL; + + while (*path) { + int len; + char *start, *end; + + start = path; + end = strchr(path, ':'); + if (end) + path = end + 1; + else + path = end = strchr(path, '\0'); + if (start >= end) + continue; + if (end[-1] == '/') + --end; + len = (end - start) + 1 + flen + 1; + if (len > bufsiz) { + if (buf) + buf = XtRealloc(buf, len); + else + buf = XtMalloc(len); + bufsiz = len; + } + memcpy(buf, start, end - start); + buf[end - start] = '/'; + strcpy(buf + (end - start) + 1, file); + fp = fopen(buf, "r"); + if (fp) { + *result = buf; + return fp; + } + } + XtFree(buf); + return NULL; +} + +static +FILE *open_device_file(device_name, file_name, result) + char *device_name, *file_name, **result; +{ + char *buf, *path; + FILE *fp; + + buf = XtMalloc(3 + strlen(device_name) + 1 + strlen(file_name) + 1); + sprintf(buf, "dev%s/%s", device_name, file_name); + path = getenv(FONTPATH_ENV_VAR); + if (!path) + path = FONTPATH; + fp = find_file(buf, path, result); + if (!fp) { + fprintf(stderr, "can't find device file `%s'\n", file_name); + fflush(stderr); + } + XtFree(buf); + return fp; +} + +static +void error(s) + char *s; +{ + if (current_filename) { + fprintf(stderr, "%s:", current_filename); + if (current_lineno > 0) + fprintf(stderr, "%d:", current_lineno); + putc(' ', stderr); + } + fputs(s, stderr); + putc('\n', stderr); + fflush(stderr); +} + +/* +Local Variables: +c-indent-level: 4 +c-continued-statement-offset: 4 +c-brace-offset: -4 +c-argdecl-indent: 4 +c-label-offset: -4 +c-tab-always-indent: nil +End: +*/ diff --git a/gnu/usr.bin/groff/xditview/device.h b/gnu/usr.bin/groff/xditview/device.h new file mode 100644 index 0000000000..2b9a64bac9 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/device.h @@ -0,0 +1,21 @@ + +typedef struct _DeviceFont DeviceFont; + +typedef struct _Device { + char *name; + int sizescale; + int res; + int unitwidth; + int paperlength; + int paperwidth; + int X11; + DeviceFont *fonts; +} Device; + +extern void device_destroy(); +extern Device *device_load(); +extern DeviceFont *device_find_font(); +extern int device_char_width(); +extern char *device_name_for_code(); +extern int device_code_width(); +extern int device_font_special(); diff --git a/gnu/usr.bin/groff/xditview/draw.c b/gnu/usr.bin/groff/xditview/draw.c new file mode 100644 index 0000000000..7715cde60b --- /dev/null +++ b/gnu/usr.bin/groff/xditview/draw.c @@ -0,0 +1,721 @@ +/* + * draw.c + * + * accept dvi function calls and translate to X + */ + +#include +#include +#include +#include +#include +#include + +/* math.h on a Sequent doesn't define M_PI, apparently */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include "DviP.h" + +#define DeviceToX(dw, n) ((int)((n) * (dw)->dvi.scale_factor + .5)) +#define XPos(dw) (DeviceToX((dw), (dw)->dvi.state->x - \ + (dw)->dvi.text_device_width) + (dw)->dvi.text_x_width) +#define YPos(dw) (DeviceToX((dw), (dw)->dvi.state->y)) + +static int FakeCharacter(); + +HorizontalMove(dw, delta) + DviWidget dw; + int delta; +{ + dw->dvi.state->x += delta; +} + +HorizontalGoto(dw, NewPosition) + DviWidget dw; + int NewPosition; +{ + dw->dvi.state->x = NewPosition; +} + +VerticalMove(dw, delta) + DviWidget dw; + int delta; +{ + dw->dvi.state->y += delta; +} + +VerticalGoto(dw, NewPosition) + DviWidget dw; + int NewPosition; +{ + dw->dvi.state->y = NewPosition; +} + +AdjustCacheDeltas (dw) + DviWidget dw; +{ + int extra; + int nadj; + int i; + + nadj = 0; + extra = DeviceToX(dw, dw->dvi.text_device_width) + - dw->dvi.text_x_width; + if (extra == 0) + return; + for (i = 0; i <= dw->dvi.cache.index; i++) + if (dw->dvi.cache.adjustable[i]) + ++nadj; + if (nadj == 0) + return; + dw->dvi.text_x_width += extra; + for (i = 0; i <= dw->dvi.cache.index; i++) + if (dw->dvi.cache.adjustable[i]) { + int x; + int *deltap; + + x = extra/nadj; + deltap = &dw->dvi.cache.cache[i].delta; +#define MIN_DELTA 2 + if (*deltap > 0 && x + *deltap < MIN_DELTA) { + x = MIN_DELTA - *deltap; + if (x <= 0) + *deltap = MIN_DELTA; + else + x = 0; + } + else + *deltap += x; + extra -= x; + --nadj; + dw->dvi.cache.adjustable[i] = 0; + } +} + +FlushCharCache (dw) + DviWidget dw; +{ + if (dw->dvi.cache.char_index != 0) { + AdjustCacheDeltas (dw); + XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC, + dw->dvi.cache.start_x, dw->dvi.cache.start_y, + dw->dvi.cache.cache, dw->dvi.cache.index + 1); + } + dw->dvi.cache.index = 0; + dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE; +#if 0 + if (dw->dvi.noPolyText) + dw->dvi.cache.max = 1; +#endif + dw->dvi.cache.char_index = 0; + dw->dvi.cache.cache[0].nchars = 0; + dw->dvi.cache.start_x = dw->dvi.cache.x = XPos (dw); + dw->dvi.cache.start_y = dw->dvi.cache.y = YPos (dw); +} + +Newline (dw) + DviWidget dw; +{ + FlushCharCache (dw); + dw->dvi.text_x_width = dw->dvi.text_device_width = 0; + dw->dvi.word_flag = 0; +} + +Word (dw) + DviWidget dw; +{ + dw->dvi.word_flag = 1; +} + +#define charWidth(fi,c) (\ + (fi)->per_char ?\ + (fi)->per_char[(c) - (fi)->min_char_or_byte2].width\ + :\ + (fi)->max_bounds.width\ +) + + +static +int charExists (fi, c) + XFontStruct *fi; + int c; +{ + XCharStruct *p; + + if (fi->per_char == NULL || + c < fi->min_char_or_byte2 || c > fi->max_char_or_byte2) + return 0; + p = fi->per_char + (c - fi->min_char_or_byte2); + return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0 + || p->ascent != 0 || p->descent != 0 || p->attributes != 0); +} + +static +DoCharacter (dw, c, wid) + DviWidget dw; + int c; + int wid; /* width in device units */ +{ + register XFontStruct *font; + register XTextItem *text; + int x, y; + + x = XPos(dw); + y = YPos(dw); + + /* + * quick and dirty extents calculation: + */ + if (!(y + 24 >= dw->dvi.extents.y1 + && y - 24 <= dw->dvi.extents.y2 +#if 0 + && x + 24 >= dw->dvi.extents.x1 + && x - 24 <= dw->dvi.extents.x2 +#endif + )) + return; + + if (y != dw->dvi.cache.y + || dw->dvi.cache.char_index >= DVI_CHAR_CACHE_SIZE) { + FlushCharCache (dw); + x = dw->dvi.cache.x; + } + /* + * load a new font, if the current block is not empty, + * step to the next. + */ + if (dw->dvi.cache.font_size != dw->dvi.state->font_size || + dw->dvi.cache.font_number != dw->dvi.state->font_number) + { + dw->dvi.cache.font_size = dw->dvi.state->font_size; + dw->dvi.cache.font_number = dw->dvi.state->font_number; + dw->dvi.cache.font = QueryFont (dw, + dw->dvi.cache.font_number, + dw->dvi.cache.font_size); + if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) { + ++dw->dvi.cache.index; + if (dw->dvi.cache.index >= dw->dvi.cache.max) + FlushCharCache (dw); + dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0; + dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0; + } + } + if (x != dw->dvi.cache.x || dw->dvi.word_flag) { + if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) { + ++dw->dvi.cache.index; + if (dw->dvi.cache.index >= dw->dvi.cache.max) + FlushCharCache (dw); + dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0; + } + dw->dvi.cache.adjustable[dw->dvi.cache.index] + = dw->dvi.word_flag; + dw->dvi.word_flag = 0; + } + font = dw->dvi.cache.font; + text = &dw->dvi.cache.cache[dw->dvi.cache.index]; + if (text->nchars == 0) { + text->chars = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index]; + text->delta = x - dw->dvi.cache.x; + if (font != dw->dvi.font) { + text->font = font->fid; + dw->dvi.font = font; + } else + text->font = None; + dw->dvi.cache.x += text->delta; + } + if (charExists(font, c)) { + int w; + dw->dvi.cache.char_cache[dw->dvi.cache.char_index++] = (char) c; + ++text->nchars; + w = charWidth(font, c); + dw->dvi.cache.x += w; + if (wid != 0) { + dw->dvi.text_x_width += w; + dw->dvi.text_device_width += wid; + } + } +} + +static +int FindCharWidth (dw, buf, widp) + DviWidget dw; + char *buf; + int *widp; +{ + int maxpos; + int i; + + if (dw->dvi.device_font == 0 + || dw->dvi.state->font_number != dw->dvi.device_font_number) { + dw->dvi.device_font_number = dw->dvi.state->font_number; + dw->dvi.device_font + = QueryDeviceFont (dw, dw->dvi.device_font_number); + } + if (dw->dvi.device_font + && device_char_width (dw->dvi.device_font, + dw->dvi.state->font_size, buf, widp)) + return 1; + + maxpos = MaxFontPosition (dw); + for (i = 1; i <= maxpos; i++) { + DeviceFont *f = QueryDeviceFont (dw, i); + if (f && device_font_special (f) + && device_char_width (f, dw->dvi.state->font_size, + buf, widp)) { + dw->dvi.state->font_number = i; + return 1; + } + } + return 0; +} + +/* Return the width of the character in device units. */ + +int PutCharacter (dw, buf) + DviWidget dw; + char *buf; +{ + int prevFont; + int c = -1; + int wid = 0; + DviCharNameMap *map; + + if (!dw->dvi.display_enable) + return 0; /* The width doesn't matter in this case. */ + prevFont = dw->dvi.state->font_number; + if (!FindCharWidth (dw, buf, &wid)) + return 0; + map = QueryFontMap (dw, dw->dvi.state->font_number); + if (map) + c = DviCharIndex (map, buf); + if (c >= 0) + DoCharacter (dw, c, wid); + else + (void) FakeCharacter (dw, buf, wid); + dw->dvi.state->font_number = prevFont; + return wid; +} + +/* Return 1 if we can fake it; 0 otherwise. */ + +static +int FakeCharacter (dw, buf, wid) + DviWidget dw; + char *buf; + int wid; +{ + int oldx, oldw; + char ch[2]; + char *chars = 0; + + if (buf[0] == '\0' || buf[1] == '\0' || buf[2] != '\0') + return 0; +#define pack2(c1, c2) (((c1) << 8) | (c2)) + + switch (pack2(buf[0], buf[1])) { + case pack2('f', 'i'): + chars = "fi"; + break; + case pack2('f', 'l'): + chars = "fl"; + break; + case pack2('f', 'f'): + chars = "ff"; + break; + case pack2('F', 'i'): + chars = "ffi"; + break; + case pack2('F', 'l'): + chars = "ffl"; + break; + } + if (!chars) + return 0; + oldx = dw->dvi.state->x; + oldw = dw->dvi.text_device_width; + ch[1] = '\0'; + for (; *chars; chars++) { + ch[0] = *chars; + dw->dvi.state->x += PutCharacter (dw, ch); + } + dw->dvi.state->x = oldx; + dw->dvi.text_device_width = oldw + wid; + return 1; +} + +PutNumberedCharacter (dw, c) + DviWidget dw; + int c; +{ + char *name; + int wid; + DviCharNameMap *map; + + if (!dw->dvi.display_enable) + return; + + if (dw->dvi.device_font == 0 + || dw->dvi.state->font_number != dw->dvi.device_font_number) { + dw->dvi.device_font_number = dw->dvi.state->font_number; + dw->dvi.device_font + = QueryDeviceFont (dw, dw->dvi.device_font_number); + } + + if (dw->dvi.device_font == 0 + || !device_code_width (dw->dvi.device_font, + dw->dvi.state->font_size, c, &wid)) + return; + if (dw->dvi.native) { + DoCharacter (dw, c, wid); + return; + } + map = QueryFontMap (dw, dw->dvi.state->font_number); + if (!map) + return; + for (name = device_name_for_code (dw->dvi.device_font, c); + name; + name = device_name_for_code ((DeviceFont *)0, c)) { + int code = DviCharIndex (map, name); + if (code >= 0) { + DoCharacter (dw, code, wid); + break; + } + if (FakeCharacter (dw, name, wid)) + break; + } +} + +ClearPage (dw) + DviWidget dw; +{ + XClearWindow (XtDisplay (dw), XtWindow (dw)); +} + +static +setGC (dw) + DviWidget dw; +{ + int desired_line_width; + + if (dw->dvi.line_thickness < 0) + desired_line_width = (int)(((double)dw->dvi.device_resolution + * dw->dvi.state->font_size) + / (10.0*72.0*dw->dvi.sizescale)); + else + desired_line_width = dw->dvi.line_thickness; + + if (desired_line_width != dw->dvi.line_width) { + XGCValues values; + values.line_width = DeviceToX(dw, desired_line_width); + if (values.line_width == 0) + values.line_width = 1; + XChangeGC(XtDisplay (dw), dw->dvi.normal_GC, + GCLineWidth, &values); + dw->dvi.line_width = desired_line_width; + } +} + +static +setFillGC (dw) + DviWidget dw; +{ + int fill_type; + + if (dw->dvi.fill == DVI_FILL_MAX) + fill_type = DVI_FILL_BLACK; + else if (dw->dvi.fill == 0) + fill_type = DVI_FILL_WHITE; + else + fill_type = DVI_FILL_GRAY; + if (dw->dvi.fill_type != fill_type) { + XGCValues values; + switch (fill_type) { + case DVI_FILL_WHITE: + values.foreground = dw->dvi.background; + values.fill_style = FillSolid; + break; + case DVI_FILL_BLACK: + values.foreground = dw->dvi.foreground; + values.fill_style = FillSolid; + break; + case DVI_FILL_GRAY: + values.foreground = dw->dvi.foreground; + values.fill_style = FillOpaqueStippled; + break; + } + XChangeGC(XtDisplay (dw), dw->dvi.fill_GC, + GCFillStyle|GCForeground, + &values); + dw->dvi.fill_type = fill_type; + } +} + +DrawLine (dw, x, y) + DviWidget dw; + int x, y; +{ + int xp, yp; + + AdjustCacheDeltas (dw); + setGC (dw); + xp = XPos (dw); + yp = YPos (dw); + XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC, + xp, yp, + xp + DeviceToX (dw, x), yp + DeviceToX (dw, y)); +} + +DrawCircle (dw, diam) + DviWidget dw; + int diam; +{ + int d; + + AdjustCacheDeltas (dw); + setGC (dw); + d = DeviceToX (dw, diam); + XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC, + XPos (dw), YPos (dw) - d/2, + d, d, 0, 64*360); +} + +DrawFilledCircle (dw, diam) + DviWidget dw; + int diam; +{ + int d; + + AdjustCacheDeltas (dw); + setFillGC (dw); + d = DeviceToX (dw, diam); + XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC, + XPos (dw), YPos (dw) - d/2, + d, d, 0, 64*360); +} + +DrawEllipse (dw, a, b) + DviWidget dw; + int a, b; +{ + AdjustCacheDeltas (dw); + setGC (dw); + XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC, + XPos (dw), YPos (dw) - DeviceToX (dw, b/2), + DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360); +} + +DrawFilledEllipse (dw, a, b) + DviWidget dw; + int a, b; +{ + AdjustCacheDeltas (dw); + setFillGC (dw); + XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC, + XPos (dw), YPos (dw) - DeviceToX (dw, b/2), + DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360); +} + +DrawArc (dw, x0, y0, x1, y1) + DviWidget dw; + int x0, y0, x1, y1; +{ + int angle1, angle2; + int rad = (int)((sqrt ((double)x0*x0 + (double)y0*y0) + + sqrt ((double)x1*x1 + (double)y1*y1) + 1.0)/2.0); + if ((x0 == 0 && y0 == 0) || (x1 == 0 && y1 == 0)) + return; + angle1 = (int)(atan2 ((double)y0, (double)-x0)*180.0*64.0/M_PI); + angle2 = (int)(atan2 ((double)-y1, (double)x1)*180.0*64.0/M_PI); + + angle2 -= angle1; + if (angle2 < 0) + angle2 += 64*360; + + AdjustCacheDeltas (dw); + setGC (dw); + + rad = DeviceToX (dw, rad); + XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC, + XPos (dw) + DeviceToX (dw, x0) - rad, + YPos (dw) + DeviceToX (dw, y0) - rad, + rad*2, rad*2, angle1, angle2); +} + +DrawPolygon (dw, v, n) + DviWidget dw; + int *v; + int n; +{ + XPoint *p; + int i; + int dx, dy; + + n /= 2; + + AdjustCacheDeltas (dw); + setGC (dw); + p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint)); + p[0].x = XPos (dw); + p[0].y = YPos (dw); + dx = 0; + dy = 0; + for (i = 0; i < n; i++) { + dx += v[2*i]; + p[i + 1].x = DeviceToX (dw, dx) + p[0].x; + dy += v[2*i + 1]; + p[i + 1].y = DeviceToX (dw, dy) + p[0].y; + } + p[n+1].x = p[0].x; + p[n+1].y = p[0].y; + XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC, + p, n + 2, CoordModeOrigin); + XtFree((char *)p); +} + + +DrawFilledPolygon (dw, v, n) + DviWidget dw; + int *v; + int n; +{ + XPoint *p; + int i; + int dx, dy; + + n /= 2; + if (n < 2) + return; + + AdjustCacheDeltas (dw); + setFillGC (dw); + p = (XPoint *)XtMalloc((n + 1)*sizeof(XPoint)); + p[0].x = XPos (dw); + p[0].y = YPos (dw); + dx = 0; + dy = 0; + for (i = 0; i < n; i++) { + dx += v[2*i]; + p[i + 1].x = DeviceToX (dw, dx) + p[0].x; + dy += v[2*i + 1]; + p[i + 1].y = DeviceToX (dw, dy) + p[0].y; + } + XFillPolygon (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC, + p, n + 1, Complex, CoordModeOrigin); + XtFree((char *)p); +} + +#define POINTS_MAX 10000 + +static +appendPoint(points, pointi, x, y) + XPoint *points; + int *pointi; + int x, y; +{ + if (*pointi < POINTS_MAX) { + points[*pointi].x = x; + points[*pointi].y = y; + *pointi += 1; + } +} + +#define FLATNESS 1 + +static +flattenCurve(points, pointi, x2, y2, x3, y3, x4, y4) + XPoint *points; + int *pointi; + int x2, y2, x3, y3, x4, y4; +{ + int x1, y1, dx, dy, n1, n2, n; + + x1 = points[*pointi - 1].x; + y1 = points[*pointi - 1].y; + + dx = x4 - x1; + dy = y4 - y1; + + n1 = dy*(x2 - x1) - dx*(y2 - y1); + n2 = dy*(x3 - x1) - dx*(y3 - y1); + if (n1 < 0) + n1 = -n1; + if (n2 < 0) + n2 = -n2; + n = n1 > n2 ? n1 : n2; + + if (n*n / (dy*dy + dx*dx) <= FLATNESS*FLATNESS) + appendPoint (points, pointi, x4, y4); + else { + flattenCurve (points, pointi, + (x1 + x2)/2, (y1 + y2)/2, + (x1 + x2*2 + x3)/4, (y1 + y2*2 + y3)/4, + (x1 +3*x2 + 3*x3 + x4)/8, (y1 +3*y2 + 3*y3 + y4)/8); + flattenCurve (points, pointi, + (x2 + x3*2 + x4)/4, (y2 + y3*2 + y4)/4, + (x3 + x4)/2, (y3 + y4)/2, + x4, y4); + } +} + + +DrawSpline (dw, v, n) + DviWidget dw; + int *v; + int n; +{ + int sx, sy, tx, ty; + int ox, oy, dx, dy; + int i; + int pointi; + XPoint points[POINTS_MAX]; + + if (n == 0 || (n & 1) != 0) + return; + AdjustCacheDeltas (dw); + setGC (dw); + ox = XPos (dw); + oy = YPos (dw); + dx = v[0]; + dy = v[1]; + sx = ox; + sy = oy; + tx = sx + DeviceToX (dw, dx); + ty = sy + DeviceToX (dw, dy); + + pointi = 0; + + appendPoint (points, &pointi, sx, sy); + appendPoint (points, &pointi, (sx + tx)/2, (sy + ty)/2); + + for (i = 2; i < n; i += 2) { + int ux = ox + DeviceToX (dw, dx += v[i]); + int uy = oy + DeviceToX (dw, dy += v[i+1]); + flattenCurve (points, &pointi, + (sx + tx*5)/6, (sy + ty*5)/6, + (tx*5 + ux)/6, (ty*5 + uy)/6, + (tx + ux)/2, (ty + uy)/2); + sx = tx; + sy = ty; + tx = ux; + ty = uy; + } + + appendPoint (points, &pointi, tx, ty); + + XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC, + points, pointi, CoordModeOrigin); +} + + +/* +Local Variables: +c-indent-level: 8 +c-continued-statement-offset: 8 +c-brace-offset: -8 +c-argdecl-indent: 8 +c-label-offset: -8 +c-tab-always-indent: nil +End: +*/ diff --git a/gnu/usr.bin/groff/xditview/font.c b/gnu/usr.bin/groff/xditview/font.c new file mode 100644 index 0000000000..ecfba4ee4d --- /dev/null +++ b/gnu/usr.bin/groff/xditview/font.c @@ -0,0 +1,471 @@ +/* + * font.c + * + * map dvi fonts to X fonts + */ + +#include +#include +#include +#include +#include +#include "DviP.h" +#include "XFontName.h" + +static DisposeFontSizes(); + +static char * +savestr (s) + char *s; +{ + char *n; + + if (!s) + return 0; + n = XtMalloc (strlen (s) + 1); + if (n) + strcpy (n, s); + return n; +} + +static DviFontList * +LookupFontByPosition (dw, position) + DviWidget dw; + int position; +{ + DviFontList *f; + + for (f = dw->dvi.fonts; f; f = f->next) + if (f->dvi_number == position) + break; + return f; +} + +int +MaxFontPosition (dw) + DviWidget dw; +{ + DviFontList *f; + int n = -1; + + for (f = dw->dvi.fonts; f; f = f->next) + if (f->dvi_number > n) + n = f->dvi_number; + return n; +} + +static DviFontSizeList * +LookupFontSizeBySize (dw, f, size) + DviWidget dw; + DviFontList *f; + int size; +{ + DviFontSizeList *fs, *best = 0, *smallest = 0; + int bestsize = 0; + XFontName fontName; + unsigned int fontNameAttributes; + char fontNameString[2048]; + int decipointsize; + + if (f->scalable) { + decipointsize = (10*size)/dw->dvi.sizescale; + for (best = f->sizes; best; best = best->next) + if (best->size == decipointsize) + return best; + best = (DviFontSizeList *) XtMalloc(sizeof *best); + best->next = f->sizes; + best->size = decipointsize; + f->sizes = best; + XParseFontName (f->x_name, &fontName, &fontNameAttributes); + fontNameAttributes &= ~(FontNamePixelSize|FontNameAverageWidth); + fontNameAttributes |= FontNameResolutionX; + fontNameAttributes |= FontNameResolutionY; + fontNameAttributes |= FontNamePointSize; + fontName.ResolutionX = dw->dvi.display_resolution; + fontName.ResolutionY = dw->dvi.display_resolution; + fontName.PointSize = decipointsize; + XFormatFontName (&fontName, fontNameAttributes, fontNameString); + best->x_name = savestr (fontNameString); + best->doesnt_exist = 0; + best->font = 0; + return best; + } + for (fs = f->sizes; fs; fs=fs->next) { + if (dw->dvi.sizescale*fs->size <= 10*size + && fs->size >= bestsize) { + best = fs; + bestsize = fs->size; + } + if (smallest == 0 || fs->size < smallest->size) + smallest = fs; + } + return best ? best : smallest; +} + +static char * +SkipFontNameElement (n) + char *n; +{ + while (*n != '-') + if (!*++n) + return 0; + return n+1; +} + +# define SizePosition 8 +# define EncodingPosition 13 + +static +ConvertFontNameToSize (n) + char *n; +{ + int i, size; + + for (i = 0; i < SizePosition; i++) { + n = SkipFontNameElement (n); + if (!n) + return -1; + } + size = atoi (n); + return size; +} + +static char * +ConvertFontNameToEncoding (n) + char *n; +{ + int i; + for (i = 0; i < EncodingPosition; i++) { + n = SkipFontNameElement (n); + if (!n) + return 0; + } + return n; +} + +DviFontSizeList * +InstallFontSizes (dw, x_name, scalablep) + DviWidget dw; + char *x_name; + Boolean *scalablep; +{ + char fontNameString[2048]; + char **fonts; + int i, count; + int size; + DviFontSizeList *sizes, *new; + XFontName fontName; + unsigned int fontNameAttributes; + + *scalablep = FALSE; + if (!XParseFontName (x_name, &fontName, &fontNameAttributes)) + return 0; + fontNameAttributes &= ~(FontNamePixelSize|FontNamePointSize + |FontNameAverageWidth); + fontNameAttributes |= FontNameResolutionX; + fontNameAttributes |= FontNameResolutionY; + fontName.ResolutionX = dw->dvi.display_resolution; + fontName.ResolutionY = dw->dvi.display_resolution; + XFormatFontName (&fontName, fontNameAttributes, fontNameString); + fonts = XListFonts (XtDisplay (dw), fontNameString, 10000000, &count); + sizes = 0; + for (i = 0; i < count; i++) { + size = ConvertFontNameToSize (fonts[i]); + if (size == 0) { + DisposeFontSizes (dw, sizes); + sizes = 0; + *scalablep = TRUE; + break; + } + if (size != -1) { + new = (DviFontSizeList *) XtMalloc (sizeof *new); + new->next = sizes; + new->size = size; + new->x_name = savestr (fonts[i]); + new->doesnt_exist = 0; + new->font = 0; + sizes = new; + } + } + XFreeFontNames (fonts); + return sizes; +} + +static +DisposeFontSizes (dw, fs) + DviWidget dw; + DviFontSizeList *fs; +{ + DviFontSizeList *next; + + for (; fs; fs=next) { + next = fs->next; + if (fs->x_name) + XtFree (fs->x_name); + if (fs->font) { + XUnloadFont (XtDisplay (dw), fs->font->fid); + XFree ((char *)fs->font); + } + XtFree ((char *) fs); + } +} + +static DviFontList * +InstallFont (dw, position, dvi_name, x_name) + DviWidget dw; + int position; + char *dvi_name; + char *x_name; +{ + DviFontList *f; + char *encoding; + + if ((f = LookupFontByPosition (dw, position)) != NULL) { + /* + * ignore gratuitous font loading + */ + if (!strcmp (f->dvi_name, dvi_name) && + !strcmp (f->x_name, x_name)) + return f; + + DisposeFontSizes (dw, f->sizes); + if (f->dvi_name) + XtFree (f->dvi_name); + if (f->x_name) + XtFree (f->x_name); + f->device_font = 0; + } else { + f = (DviFontList *) XtMalloc (sizeof (*f)); + f->next = dw->dvi.fonts; + dw->dvi.fonts = f; + } + f->initialized = FALSE; + f->dvi_name = savestr (dvi_name); + f->device_font = device_find_font (dw->dvi.device, dvi_name); + f->x_name = savestr (x_name); + f->dvi_number = position; + f->sizes = 0; + f->scalable = FALSE; + if (f->x_name) { + encoding = ConvertFontNameToEncoding (f->x_name); + f->char_map = DviFindMap (encoding); + } else + f->char_map = 0; + /* + * force requery of fonts + */ + dw->dvi.font = 0; + dw->dvi.font_number = -1; + dw->dvi.cache.font = 0; + dw->dvi.cache.font_number = -1; + dw->dvi.device_font = 0; + dw->dvi.device_font_number = -1; + return f; +} + +ForgetFonts (dw) + DviWidget dw; +{ + DviFontList *f = dw->dvi.fonts; + + while (f) { + DviFontList *tem = f; + + if (f->sizes) + DisposeFontSizes (dw, f->sizes); + if (f->dvi_name) + XtFree (f->dvi_name); + if (f->x_name) + XtFree (f->x_name); + f = f->next; + XtFree ((char *) tem); + } + + /* + * force requery of fonts + */ + dw->dvi.font = 0; + dw->dvi.font_number = -1; + dw->dvi.cache.font = 0; + dw->dvi.cache.font_number = -1; + dw->dvi.device_font = 0; + dw->dvi.device_font_number = -1; + dw->dvi.fonts = 0; +} + + +static char * +MapDviNameToXName (dw, dvi_name) + DviWidget dw; + char *dvi_name; +{ + DviFontMap *fm; + + for (fm = dw->dvi.font_map; fm; fm=fm->next) + if (!strcmp (fm->dvi_name, dvi_name)) + return fm->x_name; + return 0; +} + +#if 0 +static char * +MapXNameToDviName (dw, x_name) + DviWidget dw; + char *x_name; +{ + DviFontMap *fm; + + for (fm = dw->dvi.font_map; fm; fm=fm->next) + if (!strcmp (fm->x_name, x_name)) + return fm->dvi_name; + return 0; +} +#endif + +ParseFontMap (dw) + DviWidget dw; +{ + char dvi_name[1024]; + char x_name[2048]; + char *m, *s; + DviFontMap *fm, *new; + + if (dw->dvi.font_map) + DestroyFontMap (dw->dvi.font_map); + fm = 0; + m = dw->dvi.font_map_string; + while (*m) { + s = m; + while (*m && !isspace (*m)) + ++m; + strncpy (dvi_name, s, m-s); + dvi_name[m-s] = '\0'; + while (isspace (*m)) + ++m; + s = m; + while (*m && *m != '\n') + ++m; + strncpy (x_name, s, m-s); + x_name[m-s] = '\0'; + new = (DviFontMap *) XtMalloc (sizeof *new); + new->x_name = savestr (x_name); + new->dvi_name = savestr (dvi_name); + new->next = fm; + fm = new; + ++m; + } + dw->dvi.font_map = fm; +} + +DestroyFontMap (font_map) + DviFontMap *font_map; +{ + DviFontMap *next; + + for (; font_map; font_map = next) { + next = font_map->next; + if (font_map->x_name) + XtFree (font_map->x_name); + if (font_map->dvi_name) + XtFree (font_map->dvi_name); + XtFree ((char *) font_map); + } +} + +/* ARGSUSED */ + +SetFontPosition (dw, position, dvi_name, extra) + DviWidget dw; + int position; + char *dvi_name; + char *extra; /* unused */ +{ + char *x_name; + + x_name = MapDviNameToXName (dw, dvi_name); + if (x_name) + (void) InstallFont (dw, position, dvi_name, x_name); +} + +XFontStruct * +QueryFont (dw, position, size) + DviWidget dw; + int position; + int size; +{ + DviFontList *f; + DviFontSizeList *fs; + + f = LookupFontByPosition (dw, position); + if (!f) + return dw->dvi.default_font; + if (!f->initialized) { + f->sizes = InstallFontSizes (dw, f->x_name, &f->scalable); + f->initialized = TRUE; + } + fs = LookupFontSizeBySize (dw, f, size); + if (!fs) + return dw->dvi.default_font; + if (!fs->font) { + if (fs->x_name) + fs->font = XLoadQueryFont (XtDisplay (dw), fs->x_name); + if (!fs->font) + fs->font = dw->dvi.default_font; + } + return fs->font; +} + +DeviceFont * +QueryDeviceFont (dw, position) + DviWidget dw; + int position; +{ + DviFontList *f; + + f = LookupFontByPosition (dw, position); + if (!f) + return 0; + return f->device_font; +} + +DviCharNameMap * +QueryFontMap (dw, position) + DviWidget dw; + int position; +{ + DviFontList *f; + + f = LookupFontByPosition (dw, position); + if (f) + return f->char_map; + else + return 0; +} + +#if 0 +LoadFont (dw, position, size) + DviWidget dw; + int position; + int size; +{ + XFontStruct *font; + + font = QueryFont (dw, position, size); + dw->dvi.font_number = position; + dw->dvi.font_size = size; + dw->dvi.font = font; + XSetFont (XtDisplay (dw), dw->dvi.normal_GC, font->fid); + return; +} +#endif + +/* +Local Variables: +c-indent-level: 8 +c-continued-statement-offset: 8 +c-brace-offset: -8 +c-argdecl-indent: 8 +c-label-offset: -8 +c-tab-always-indent: nil +End: +*/ diff --git a/gnu/usr.bin/groff/xditview/gxditview.1 b/gnu/usr.bin/groff/xditview/gxditview.1 new file mode 100644 index 0000000000..e4718aa7a0 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/gxditview.1 @@ -0,0 +1,217 @@ +.\" -*- nroff -*- +.TH GXDITVIEW 1 "Release 5" "X Version 11" +.SH NAME +gxditview \- display gtroff output files +.SH SYNOPSIS +.B gxditview +.RI [\fB\- toolkitoption\ .\|.\|.\|] +.RI [\fB\- option\ .\|.\|.\|] +.RI [ filename ] +.SH DESCRIPTION +The +.I gxditview +program displays gtroff output on an X display. +It uses the standard X11 fonts, +so it does not require access to the server machine for font loading. +.PP +If +.I filename +is +.BR \- , +.I gxditview +will read the standard input. +.PP +The left mouse button brings up a menu with the following entries: +.TP 8 +.B "Next Page" +Display the next page. +.TP +.B "Previous Page" +Display the previous page. +.TP +.B "Select Page" +Select a particular numbered page specified by a dialog box. +.TP +.B Print +Print the gtroff output using a command specified by a dialog box. +The default command initially displayed is controlled by the +.B printCommand +application resource, and by the +.B \-printCommand +option. +.TP +.B Open +Open for display a new file specified by a dialog box. +The file should contain gtroff output. +If the filename starts with +.B | +it will be taken to be a command to read from. +.TP +.B Quit +Exit from +.IR gxditview . +.PP +The +.BR n , +Space +and Return keys are bound to the +.B Next\ Page +action. +The +.BR p , +BackSpace +and +Delete +keys are bound to the +.B Previous\ Page +action. +The +.B q +key is bound to the +.B Quit +action. +The +.B r +key is bound to the +.B Rerasterize +action which rereads the current file, and redisplays the current page; +if the current file is a command, the command will be reexecuted. +.PP +The +.B paperlength +and +.B paperwidth +commands in the DESC file specify the length and width in machine units +of the virtual page displayed by +.IR gxditview . +.SH OPTIONS +.I Gxditview +accepts all of the standard X Toolkit command line options along with the +additional options listed below: +.TP 8 +.B \-help +This option indicates that a brief summary of the allowed options should be +printed. +.TP +.B \-page +This option specifies the page number of the document to be displayed. +.TP +.BI \-backingStore\ backing-store-type +Redisplay of the gtroff output window can take upto a second or so, +this option causes the server to save the window contents so that when +it is scrolled around the viewport, the window is painted from +contents saved in backing store. +.I backing-store-type +can be one of +.BR Always , +.B WhenMapped +or +.BR NotUseful . +.TP +.BI \-printCommand\ command +The default command displayed in the dialog box for the +.B Print +menu entry will be +.IR command . +.TP +.BI \-resolution\ res +The gtroff output file will be displayed at a resolution of +.I res +dpi, +unless the DESC file contains the +.B X11 +command, in which case the device resolution will be used. +This corresponds the +.I Dvi +widget's +.B resolution +resource. +The default is 75. +.TP +.BI \-filename\ string +The default filename displayed in the dialog box for the +.B Open +menu entry will be +.IR string . +This can be either a filename, or a command starting with +.BR | . +.PP +The following standard X Toolkit command line arguments are commonly used with +.IR gxditview : +.TP 8 +.BI \-bg\ color +This option specifies the color to use for the background of the window. +The default is \fIwhite\fP. +.TP +.BI \-bd\ color +This option specifies the color to use for the border of the window. +The default is \fIblack\fP. +.TP +.BI \-bw\ number +This option specifies the width in pixels of the border surrounding the window. +.TP +.BI \-fg\ color +This option specifies the color to use for displaying text. The default is +\fIblack\fP. +.TP +.BI \-fn\ font +This option specifies the font to be used for displaying widget text. The +default is \fIfixed\fP. +.TP +.B \-rv +This option indicates that reverse video should be simulated by swapping +the foreground and background colors. +.TP +.BI \-geometry\ geometry +This option specifies the preferred size and position of the window. +.TP +.BI \-display\ host : display +This option specifies the X server to contact. +.TP +.BI \-xrm\ resourcestring +This option specifies a resource string to be used. +.SH X DEFAULTS +This program uses the +.I Dvi +widget in the X Toolkit. It understands all of the core resource names and +classes as well as: +.PP +.TP 8 +.BR width\ (class\ Width ) +Specifies the width of the window. +.TP +.BR height\ (class\ Height ) +Specifies the height of the window. +.TP +.BR foreground\ (class\ Foreground ) +Specifies the default foreground color. +.TP +.BR font\ (class\ Font ) +Specifies the font to be used for error messages. +.SH "SEE ALSO" +.IR X (1), +.IR xrdb (1), +.IR gtroff (1), +.IR groff (1) +.SH ORIGIN +This program is derived from xditview; +portions of xditview originated in xtroff which was derived +from suntroff. +.SH COPYRIGHT +Copyright 1989, Massachusetts Institute of Technology. +.br +See +.IR X (1) +for a full statement of rights and permissions. +.SH AUTHORS +Keith Packard (MIT X Consortium) +.br +Richard L. Hyde (Purdue) +.br +David Slattengren (Berkeley) +.br +Malcom Slaney (Schlumberger Palo Alto Research) +.br +Mark Moraes (University of Toronto) +.br +James Clark diff --git a/gnu/usr.bin/groff/xditview/lex.c b/gnu/usr.bin/groff/xditview/lex.c new file mode 100644 index 0000000000..32831bdacd --- /dev/null +++ b/gnu/usr.bin/groff/xditview/lex.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include "DviP.h" + +DviGetAndPut(dw, cp) + DviWidget dw; + int *cp; +{ + if (dw->dvi.ungot) { + dw->dvi.ungot = 0; + *cp = getc (dw->dvi.file); + } + else { + *cp = getc (dw->dvi.file); + if (*cp != EOF) + putc (*cp, dw->dvi.tmpFile); + } + return *cp; +} + +char * +GetLine(dw, Buffer, Length) + DviWidget dw; + char *Buffer; + int Length; +{ + int i = 0, c; + + Length--; /* Save room for final '\0' */ + + while (DviGetC (dw, &c) != EOF) { + if (Buffer && i < Length) + Buffer[i++] = c; + if (c == '\n') { + DviUngetC(dw, c); + break; + } + } + if (Buffer) + Buffer[i] = '\0'; + return Buffer; +} + +char * +GetWord(dw, Buffer, Length) + DviWidget dw; + char *Buffer; + int Length; +{ + int i = 0, c; + + Length--; /* Save room for final '\0' */ + while (DviGetC(dw, &c) == ' ' || c == '\n') + ; + while (c != EOF) { + if (Buffer && i < Length) + Buffer[i++] = c; + if (DviGetC(dw, &c) == ' ' || c == '\n') { + DviUngetC(dw, c); + break; + } + } + if (Buffer) + Buffer[i] = '\0'; + return Buffer; +} + +GetNumber(dw) + DviWidget dw; +{ + int i = 0, c; + int negative = 0; + + while (DviGetC(dw, &c) == ' ' || c == '\n') + ; + if (c == '-') { + negative = 1; + DviGetC(dw, &c); + } + + for (; c >= '0' && c <= '9'; DviGetC(dw, &c)) { + if (negative) + i = i*10 - (c - '0'); + else + i = i*10 + c - '0'; + } + if (c != EOF) + DviUngetC(dw, c); + return i; +} + +/* +Local Variables: +c-indent-level: 8 +c-continued-statement-offset: 8 +c-brace-offset: -8 +c-argdecl-indent: 8 +c-label-offset: -8 +c-tab-always-indent: nil +End: +*/ diff --git a/gnu/usr.bin/groff/xditview/page.c b/gnu/usr.bin/groff/xditview/page.c new file mode 100644 index 0000000000..9284199cde --- /dev/null +++ b/gnu/usr.bin/groff/xditview/page.c @@ -0,0 +1,88 @@ +/* + * page.c + * + * map page numbers to file position + */ + +#include +#include +#include +#include +#include +#include "DviP.h" + +#ifdef X_NOT_STDC_ENV +extern long ftell(); +#endif + +static DviFileMap * +MapPageNumberToFileMap (dw, number) + DviWidget dw; + int number; +{ + DviFileMap *m; + + for (m = dw->dvi.file_map; m; m=m->next) + if (m->page_number == number) + break; + return m; +} + +DestroyFileMap (m) + DviFileMap *m; +{ + DviFileMap *next; + + for (; m; m = next) { + next = m->next; + XtFree ((char *) m); + } +} + +ForgetPagePositions (dw) + DviWidget dw; +{ + DestroyFileMap (dw->dvi.file_map); + dw->dvi.file_map = 0; +} + +RememberPagePosition(dw, number) + DviWidget dw; + int number; +{ + DviFileMap *m; + + if (!(m = MapPageNumberToFileMap (dw, number))) { + m = (DviFileMap *) XtMalloc (sizeof *m); + m->page_number = number; + m->next = dw->dvi.file_map; + dw->dvi.file_map = m; + } + if (dw->dvi.tmpFile) + m->position = ftell (dw->dvi.tmpFile); + else + m->position = ftell (dw->dvi.file); +} + +SearchPagePosition (dw, number) + DviWidget dw; + int number; +{ + DviFileMap *m; + + if (!(m = MapPageNumberToFileMap (dw, number))) + return -1; + return m->position; +} + +FileSeek(dw, position) +DviWidget dw; +long position; +{ + if (dw->dvi.tmpFile) { + dw->dvi.readingTmp = 1; + fseek (dw->dvi.tmpFile, position, 0); + } else + fseek (dw->dvi.file, position, 0); +} + diff --git a/gnu/usr.bin/groff/xditview/parse.c b/gnu/usr.bin/groff/xditview/parse.c new file mode 100644 index 0000000000..8367c17b92 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/parse.c @@ -0,0 +1,334 @@ +/* + * parse.c + * + * parse dvi input + */ + +#include +#include +#include +#include +#include +#include "DviP.h" + +static int StopSeen = 0; +static ParseDrawFunction(), ParseDeviceControl(); +static push_env(), pop_env(); + +#define HorizontalMove(dw, delta) ((dw)->dvi.state->x += (delta)) + + +ParseInput(dw) + register DviWidget dw; +{ + int n, k; + int c; + char Buffer[BUFSIZ]; + int NextPage; + int otherc; + + StopSeen = 0; + + /* + * make sure some state exists + */ + + if (!dw->dvi.state) + push_env (dw); + for (;;) { + switch (DviGetC(dw, &c)) { + case '\n': + break; + case ' ': /* when input is text */ + case 0: /* occasional noise creeps in */ + break; + case '{': /* push down current environment */ + push_env(dw); + break; + case '}': + pop_env(dw); + break; + /* + * two motion digits plus a character + */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + HorizontalMove(dw, (c-'0')*10 + + DviGetC(dw,&otherc)-'0'); + /* fall through */ + case 'c': /* single ascii character */ + DviGetC(dw,&c); + if (c == ' ') + break; + Buffer[0] = c; + Buffer[1] = '\0'; + (void) PutCharacter (dw, Buffer); + break; + case 'C': + GetWord (dw, Buffer, BUFSIZ); + (void) PutCharacter (dw, Buffer); + break; + case 't': + Buffer[1] = '\0'; + while (DviGetC (dw, &c) != EOF + && c != ' ' && c != '\n') { + Buffer[0] = c; + HorizontalMove (dw, PutCharacter (dw, Buffer)); + } + break; + case 'u': + n = GetNumber(dw); + Buffer[1] = '\0'; + while (DviGetC (dw, &c) == ' ') + ; + while (c != EOF && c != ' ' && c != '\n') { + Buffer[0] = c; + HorizontalMove (dw, + PutCharacter (dw, Buffer) + n); + DviGetC (dw, &c); + } + break; + + case 'D': /* draw function */ + (void) GetLine(dw, Buffer, BUFSIZ); + if (dw->dvi.display_enable) + ParseDrawFunction(dw, Buffer); + break; + case 's': /* ignore fractional sizes */ + n = GetNumber(dw); + dw->dvi.state->font_size = n; + break; + case 'f': + n = GetNumber(dw); + dw->dvi.state->font_number = n; + break; + case 'H': /* absolute horizontal motion */ + k = GetNumber(dw); + HorizontalGoto(dw, k); + break; + case 'h': /* relative horizontal motion */ + k = GetNumber(dw); + HorizontalMove(dw, k); + break; + case 'w': /* word space */ + Word (dw); + break; + case 'V': + n = GetNumber(dw); + VerticalGoto(dw, n); + break; + case 'v': + n = GetNumber(dw); + VerticalMove(dw, n); + break; + case 'P': /* new spread */ + break; + case 'p': /* new page */ + (void) GetNumber(dw); + NextPage = dw->dvi.current_page + 1; + RememberPagePosition(dw, NextPage); + FlushCharCache (dw); + return(NextPage); + case 'N': + n = GetNumber(dw); + PutNumberedCharacter (dw, n); + break; + case 'n': /* end of line */ + GetNumber(dw); + GetNumber(dw); + Newline (dw); + HorizontalGoto(dw, 0); + break; + case '+': /* continuation of X device control */ + case '#': /* comment */ + GetLine(dw, NULL, 0); + break; + case 'x': /* device control */ + ParseDeviceControl(dw); + break; + case EOF: + dw->dvi.last_page = dw->dvi.current_page; + FlushCharCache (dw); + return dw->dvi.current_page; + default: + break; + } + } +} + +static +push_env(dw) + DviWidget dw; +{ + DviState *new; + + new = (DviState *) XtMalloc (sizeof (*new)); + if (dw->dvi.state) + *new = *(dw->dvi.state); + else { + new->font_size = 10; + new->font_number = 1; + new->x = 0; + new->y = 0; + } + new->next = dw->dvi.state; + dw->dvi.state = new; +} + +static +pop_env(dw) + DviWidget dw; +{ + DviState *old; + + old = dw->dvi.state; + dw->dvi.state = old->next; + XtFree ((char *) old); +} + +static +InitTypesetter (dw) + DviWidget dw; +{ + while (dw->dvi.state) + pop_env (dw); + push_env (dw); + FlushCharCache (dw); +} + +#define DRAW_ARGS_MAX 128 + +static +ParseDrawFunction(dw, buf) +DviWidget dw; +char *buf; +{ + int v[DRAW_ARGS_MAX]; + int i; + char *ptr; + + v[0] = v[1] = v[2] = v[3] = 0; + + if (buf[0] == '\0') + return; + ptr = buf+1; + + for (i = 0; i < DRAW_ARGS_MAX; i++) { + if (sscanf(ptr, "%d", v + i) != 1) + break; + while (*ptr == ' ') + ptr++; + while (*ptr != '\0' && *ptr != ' ') + ptr++; + } + + switch (buf[0]) { + case 'l': /* draw a line */ + DrawLine(dw, v[0], v[1]); + break; + case 'c': /* circle */ + DrawCircle(dw, v[0]); + break; + case 'C': + DrawFilledCircle(dw, v[0]); + break; + case 'e': /* ellipse */ + DrawEllipse(dw, v[0], v[1]); + break; + case 'E': + DrawFilledEllipse(dw, v[0], v[1]); + break; + case 'a': /* arc */ + DrawArc(dw, v[0], v[1], v[2], v[3]); + break; + case 'p': + DrawPolygon(dw, v, i); + break; + case 'P': + DrawFilledPolygon(dw, v, i); + break; + case '~': /* wiggly line */ + DrawSpline(dw, v, i); + break; + case 't': + dw->dvi.line_thickness = v[0]; + break; + case 'f': + if (i > 0 && v[0] >= 0 && v[0] <= DVI_FILL_MAX) + dw->dvi.fill = v[0]; + break; + default: +#if 0 + warning("unknown drawing function %s", buf); +#endif + break; + } + + if (buf[0] == 'e') { + if (i > 0) + dw->dvi.state->x += v[0]; + } + else { + while (--i >= 0) { + if (i & 1) + dw->dvi.state->y += v[i]; + else + dw->dvi.state->x += v[i]; + } + } +} + +static +ParseDeviceControl(dw) /* Parse the x commands */ + DviWidget dw; +{ + char str[20], str1[50]; + int c, n; + extern int LastPage, CurrentPage; + + GetWord (dw, str, 20); + switch (str[0]) { /* crude for now */ + case 'T': /* output device */ + GetWord (dw, str, 20); + SetDevice (dw, str); + break; + case 'i': /* initialize */ + InitTypesetter (dw); + break; + case 't': /* trailer */ + break; + case 'p': /* pause -- can restart */ + break; + case 's': /* stop */ + StopSeen = 1; + return; + case 'r': /* resolution when prepared */ + break; + case 'f': /* font used */ + n = GetNumber (dw); + GetWord (dw, str, 20); + GetLine (dw, str1, 50); + SetFontPosition (dw, n, str, str1); + break; + case 'H': /* char height */ + break; + case 'S': /* slant */ + break; + } + while (DviGetC (dw, &c) != '\n') /* skip rest of input line */ + if (c == EOF) + return; + return; +} + + +/* +Local Variables: +c-indent-level: 8 +c-continued-statement-offset: 8 +c-brace-offset: -8 +c-argdecl-indent: 8 +c-label-offset: -8 +c-tab-always-indent: nil +End: +*/ diff --git a/gnu/usr.bin/groff/xditview/xdit.bm b/gnu/usr.bin/groff/xditview/xdit.bm new file mode 100644 index 0000000000..67b9c8ab56 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/xdit.bm @@ -0,0 +1,14 @@ +#define xdit_width 32 +#define xdit_height 32 +static char xdit_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x03, 0x02, 0x00, 0x00, 0x02, + 0x8a, 0xa2, 0xfc, 0x03, 0x52, 0x14, 0x03, 0x04, 0x02, 0x80, 0x00, 0x08, + 0x52, 0x54, 0x00, 0x10, 0x8a, 0x22, 0x8f, 0x23, 0x02, 0x20, 0x06, 0x21, + 0x8a, 0x12, 0x8c, 0x40, 0x52, 0x14, 0x8c, 0x40, 0x02, 0x10, 0x58, 0x40, + 0x52, 0x14, 0x30, 0x40, 0x8a, 0x12, 0x30, 0x40, 0x02, 0x10, 0x70, 0x40, + 0x8a, 0x12, 0xc8, 0x40, 0x52, 0x24, 0xc4, 0xe0, 0x02, 0x20, 0x84, 0xe1, + 0x52, 0x54, 0xce, 0xf3, 0x8a, 0xa2, 0x00, 0xf8, 0x02, 0x00, 0x03, 0xfc, + 0x8a, 0x22, 0xfc, 0xf3, 0x52, 0x14, 0x00, 0xc2, 0x02, 0x00, 0x00, 0x02, + 0x52, 0x14, 0x45, 0x02, 0x8a, 0xa2, 0x28, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x02, 0x00, 0x00, 0x02, 0xfe, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/gnu/usr.bin/groff/xditview/xdit_mask.bm b/gnu/usr.bin/groff/xditview/xdit_mask.bm new file mode 100644 index 0000000000..f34a4f863f --- /dev/null +++ b/gnu/usr.bin/groff/xditview/xdit_mask.bm @@ -0,0 +1,14 @@ +#define xdit_mask_width 32 +#define xdit_mask_height 32 +static char xdit_mask_bits[] = { + 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, + 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x1f, + 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc7, + 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, + 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/gnu/usr.bin/groff/xditview/xditview.c b/gnu/usr.bin/groff/xditview/xditview.c new file mode 100644 index 0000000000..7179045baf --- /dev/null +++ b/gnu/usr.bin/groff/xditview/xditview.c @@ -0,0 +1,587 @@ +/* + * Copyright 1991 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ +/* + * xditview -- + * + * Display ditroff output in an X window + */ + +#ifndef SABER +#ifndef lint +static char rcsid[] = "$XConsortium: xditview.c,v 1.17 89/12/10 17:05:08 rws Exp $"; +#endif /* lint */ +#endif /* SABER */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Dvi.h" + +#include "xdit.bm" +#include "xdit_mask.bm" +#include "stdio.h" + +extern FILE *popen(); +extern void exit(); + +static struct app_resources { + char *print_command; + char *filename; +} app_resources; + +#define offset(field) XtOffset(struct app_resources *, field) + +/* Application resources. */ + +static XtResource resources[] = { + {"printCommand", "PrintCommand", XtRString, sizeof(char*), + offset(print_command), XtRString, NULL}, + {"filename", "Filename", XtRString, sizeof(char*), + offset(filename), XtRString, NULL}, +}; + +#undef offset + +/* Command line options table. Only resources are entered here...there is a + pass over the remaining options after XtParseCommand is let loose. */ + +static XrmOptionDescRec options[] = { +{"-page", "*dvi.pageNumber", XrmoptionSepArg, NULL}, +{"-backingStore", "*dvi.backingStore", XrmoptionSepArg, NULL}, +{"-resolution", "*dvi.resolution", XrmoptionSepArg, NULL}, +{"-printCommand", ".printCommand", XrmoptionSepArg, NULL}, +{"-filename", ".filename", XrmoptionSepArg, NULL}, +{"-noPolyText", "*dvi.noPolyText", XrmoptionNoArg, "TRUE"}, +}; + +static char current_print_command[1024]; + +static char current_file_name[1024]; +static FILE *current_file; + +/* + * Report the syntax for calling xditview. + */ + +static +Syntax(call) + char *call; +{ + (void) printf ("Usage: %s [-fg ] [-bg ]\n", call); + (void) printf (" [-bd ] [-bw ] [-help]\n"); + (void) printf (" [-display displayname] [-geometry geom]\n"); + (void) printf (" [-page ] [-backing ]\n"); + (void) printf (" [-resolution ] [-print ]\n"); + (void) printf (" [-filename ] [filename]\n\n"); + exit(1); +} + +static void NewFile (), SetPageNumber (); +static Widget toplevel, paned, viewport, dvi; +static Widget page; +static Widget simpleMenu; + +static void NextPage(), PreviousPage(), SelectPage(), OpenFile(), Quit(); +static void Print(); + +static struct menuEntry { + char *name; + void (*function)(); +} menuEntries[] = { + "nextPage", NextPage, + "previousPage", PreviousPage, + "selectPage", SelectPage, + "print", Print, + "openFile", OpenFile, + "quit", Quit, +}; + +static void NextPageAction(), PreviousPageAction(), SelectPageAction(); +static void OpenFileAction(), QuitAction(); +static void AcceptAction(), CancelAction(); +static void PrintAction(); +static void RerasterizeAction(); + +XtActionsRec xditview_actions[] = { + "NextPage", NextPageAction, + "PreviousPage", PreviousPageAction, + "SelectPage", SelectPageAction, + "Print", PrintAction, + "OpenFile", OpenFileAction, + "Rerasterize", RerasterizeAction, + "Quit", QuitAction, + "Accept", AcceptAction, + "Cancel", CancelAction, +}; + +#define MenuNextPage 0 +#define MenuPreviousPage 1 +#define MenuSelectPage 2 +#define MenuPrint 3 +#define MenuOpenFile 4 +#define MenuQuit 5 + +static char pageLabel[256] = "Page "; + +void main(argc, argv) + int argc; + char **argv; +{ + char *file_name = 0; + int i; + static Arg labelArgs[] = { + {XtNlabel, (XtArgVal) pageLabel}, + }; + Arg topLevelArgs[2]; + Widget entry; + Arg pageNumberArgs[1]; + int page_number; + + toplevel = XtInitialize("main", "GXditview", + options, XtNumber (options), + &argc, argv); + if (argc > 2) + Syntax(argv[0]); + + XtGetApplicationResources(toplevel, (XtPointer)&app_resources, + resources, XtNumber(resources), + NULL, (Cardinal) 0); + if (app_resources.print_command) + strcpy(current_print_command, app_resources.print_command); + + XtAppAddActions(XtWidgetToApplicationContext(toplevel), + xditview_actions, XtNumber (xditview_actions)); + + XtSetArg (topLevelArgs[0], XtNiconPixmap, + XCreateBitmapFromData (XtDisplay (toplevel), + XtScreen(toplevel)->root, + xdit_bits, xdit_width, xdit_height)); + + XtSetArg (topLevelArgs[1], XtNiconMask, + XCreateBitmapFromData (XtDisplay (toplevel), + XtScreen(toplevel)->root, + xdit_mask_bits, + xdit_mask_width, xdit_mask_height)); + XtSetValues (toplevel, topLevelArgs, 2); + if (argc > 1) + file_name = argv[1]; + + /* + * create the menu and insert the entries + */ + simpleMenu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, toplevel, + NULL, 0); + for (i = 0; i < XtNumber (menuEntries); i++) { + entry = XtCreateManagedWidget(menuEntries[i].name, + smeBSBObjectClass, simpleMenu, + NULL, (Cardinal) 0); + XtAddCallback(entry, XtNcallback, menuEntries[i].function, NULL); + } + + paned = XtCreateManagedWidget("paned", panedWidgetClass, toplevel, + NULL, (Cardinal) 0); + viewport = XtCreateManagedWidget("viewport", viewportWidgetClass, paned, + NULL, (Cardinal) 0); + dvi = XtCreateManagedWidget ("dvi", dviWidgetClass, viewport, NULL, 0); + page = XtCreateManagedWidget ("label", labelWidgetClass, paned, + labelArgs, XtNumber (labelArgs)); + XtSetArg (pageNumberArgs[0], XtNpageNumber, &page_number); + XtGetValues (dvi, pageNumberArgs, 1); + if (file_name) + NewFile (file_name); + /* NewFile modifies current_file_name, so do this here. */ + if (app_resources.filename) + strcpy(current_file_name, app_resources.filename); + XtRealizeWidget (toplevel); + if (file_name) + SetPageNumber (page_number); + XtMainLoop(); +} + +static void +SetPageNumber (number) +{ + Arg arg[2]; + int actual_number, last_page; + + XtSetArg (arg[0], XtNpageNumber, number); + XtSetValues (dvi, arg, 1); + XtSetArg (arg[0], XtNpageNumber, &actual_number); + XtSetArg (arg[1], XtNlastPageNumber, &last_page); + XtGetValues (dvi, arg, 2); + if (actual_number == 0) + sprintf (pageLabel, "Page "); + else if (last_page > 0) + sprintf (pageLabel, "Page %d of %d", actual_number, last_page); + else + sprintf (pageLabel, "Page %d", actual_number); + XtSetArg (arg[0], XtNlabel, pageLabel); + XtSetValues (page, arg, 1); +} + +static void +SelectPageNumber (number_string) +char *number_string; +{ + SetPageNumber (atoi(number_string)); +} + +static int hadFile = 0; + +static void +NewFile (name) +char *name; +{ + Arg arg[2]; + char *n, *rindex (); + FILE *new_file; + Boolean seek = 0; + + if (current_file) { + if (!strcmp (current_file_name, "-")) + ; + else if (current_file_name[0] == '|') + pclose (current_file); + else + fclose (current_file); + } + if (!strcmp (name, "-")) + new_file = stdin; + else if (name[0] == '|') + new_file = popen (name+1, "r"); + else { + new_file = fopen (name, "r"); + seek = 1; + } + if (!new_file) { + /* XXX display error message */ + return; + } + XtSetArg (arg[0], XtNfile, new_file); + XtSetArg (arg[1], XtNseek, seek); + XtSetValues (dvi, arg, 2); + if (hadFile || name[0] != '-' || name[1] != '\0') { + XtSetArg (arg[0], XtNtitle, name); + if (name[0] != '/' && (n = rindex (name, '/'))) + n = n + 1; + else + n = name; + XtSetArg (arg[1], XtNiconName, n); + XtSetValues (toplevel, arg, 2); + } + hadFile = 1; + SelectPageNumber ("1"); + strcpy (current_file_name, name); + current_file = new_file; +} + +static char fileBuf[1024]; + +ResetMenuEntry (entry) + Widget entry; +{ + Arg arg[1]; + + XtSetArg (arg[0], XtNpopupOnEntry, entry); + XtSetValues (XtParent(entry) , arg, (Cardinal) 1); +} + +/*ARGSUSED*/ + +static void +NextPage (entry, name, data) + Widget entry; + caddr_t name, data; +{ + NextPageAction(); + ResetMenuEntry (entry); +} + +static void +NextPageAction () +{ + Arg args[1]; + int number; + + XtSetArg (args[0], XtNpageNumber, &number); + XtGetValues (dvi, args, 1); + SetPageNumber (number+1); +} + +/*ARGSUSED*/ + +static void +PreviousPage (entry, name, data) + Widget entry; + caddr_t name, data; +{ + PreviousPageAction (); + ResetMenuEntry (entry); +} + +static void +PreviousPageAction () +{ + Arg args[1]; + int number; + + XtSetArg (args[0], XtNpageNumber, &number); + XtGetValues (dvi, args, 1); + SetPageNumber (number-1); +} + +/* ARGSUSED */ + +static void +SelectPage (entry, name, data) + Widget entry; + caddr_t name, data; +{ + SelectPageAction (); + ResetMenuEntry (entry); +} + +static void +SelectPageAction () +{ + MakePrompt (toplevel, "Page number", SelectPageNumber, ""); +} + + +static void +DoPrint (name) + char *name; +{ + FILE *print_file; +#ifdef SIGNALRETURNSINT + int (*handler)(); +#else + void (*handler)(); +#endif + /* Avoid dieing because of an invalid command. */ + handler = signal(SIGPIPE, SIG_IGN); + + print_file = popen(name, "w"); + if (!print_file) + /* XXX print error message */ + return; + DviSaveToFile(dvi, print_file); + pclose(print_file); + signal(SIGPIPE, handler); + strcpy(current_print_command, name); +} + +static void +RerasterizeAction() +{ + Arg args[1]; + int number; + + if (current_file_name[0] == 0) { + /* XXX display an error message */ + return; + } + XtSetArg (args[0], XtNpageNumber, &number); + XtGetValues (dvi, args, 1); + NewFile(current_file_name); + SetPageNumber (number); +} + +/* ARGSUSED */ + +static void +Print (entry, name, data) + Widget entry; + caddr_t name, data; +{ + PrintAction (); + ResetMenuEntry (entry); +} + +static void +PrintAction () +{ + if (current_print_command[0]) + strcpy (fileBuf, current_print_command); + else + fileBuf[0] = '\0'; + MakePrompt (toplevel, "Print command:", DoPrint, fileBuf); +} + + +/* ARGSUSED */ + +static void +OpenFile (entry, name, data) + Widget entry; + caddr_t name, data; +{ + OpenFileAction (); + ResetMenuEntry (entry); +} + +static void +OpenFileAction () +{ + if (current_file_name[0]) + strcpy (fileBuf, current_file_name); + else + fileBuf[0] = '\0'; + MakePrompt (toplevel, "File to open:", NewFile, fileBuf); +} + +/* ARGSUSED */ + +static void +Quit (entry, closure, data) + Widget entry; + caddr_t closure, data; +{ + QuitAction (); +} + +static void +QuitAction () +{ + exit (0); +} + +Widget promptShell, promptDialog; +void (*promptfunction)(); + +/* ARGSUSED */ +static +void CancelAction (widget, event, params, num_params) + Widget widget; + XEvent *event; + String *params; + Cardinal *num_params; +{ + if (promptShell) { + XtSetKeyboardFocus(toplevel, (Widget) None); + XtDestroyWidget(promptShell); + promptShell = (Widget) 0; + } +} + +static +void AcceptAction (widget, event, params, num_params) + Widget widget; + XEvent *event; + String *params; + Cardinal *num_params; +{ + (*promptfunction)(XawDialogGetValueString(promptDialog)); + CancelAction (widget, event, params, num_params); +} + +MakePrompt(centerw, prompt, func, def) +Widget centerw; +char *prompt; +void (*func)(); +char *def; +{ + static Arg dialogArgs[] = { + {XtNlabel, NULL}, + {XtNvalue, NULL}, + }; + Arg valueArgs[1]; + Arg centerArgs[2]; + Position source_x, source_y; + Position dest_x, dest_y; + Dimension center_width, center_height; + Dimension prompt_width, prompt_height; + Widget valueWidget; + + CancelAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0); + promptShell = XtCreatePopupShell ("promptShell", transientShellWidgetClass, + toplevel, NULL, (Cardinal) 0); + dialogArgs[0].value = (XtArgVal)prompt; + dialogArgs[1].value = (XtArgVal)def; + promptDialog = XtCreateManagedWidget( "promptDialog", dialogWidgetClass, + promptShell, dialogArgs, XtNumber (dialogArgs)); + XawDialogAddButton(promptDialog, "accept", NULL, (caddr_t) 0); + XawDialogAddButton(promptDialog, "cancel", NULL, (caddr_t) 0); + valueWidget = XtNameToWidget (promptDialog, "value"); + if (valueWidget) { + XtSetArg (valueArgs[0], XtNresizable, TRUE); + XtSetValues (valueWidget, valueArgs, 1); + /* + * as resizable isn't set until just above, the + * default value will be displayed incorrectly. + * rectify the situation by resetting the values + */ + XtSetValues (promptDialog, dialogArgs, XtNumber (dialogArgs)); + } + XtSetKeyboardFocus (promptDialog, valueWidget); + XtSetKeyboardFocus (toplevel, valueWidget); + XtRealizeWidget (promptShell); + /* + * place the widget in the center of the "parent" + */ + XtSetArg (centerArgs[0], XtNwidth, ¢er_width); + XtSetArg (centerArgs[1], XtNheight, ¢er_height); + XtGetValues (centerw, centerArgs, 2); + XtSetArg (centerArgs[0], XtNwidth, &prompt_width); + XtSetArg (centerArgs[1], XtNheight, &prompt_height); + XtGetValues (promptShell, centerArgs, 2); + source_x = (center_width - prompt_width) / 2; + source_y = (center_height - prompt_height) / 3; + XtTranslateCoords (centerw, source_x, source_y, &dest_x, &dest_y); + XtSetArg (centerArgs[0], XtNx, dest_x); + XtSetArg (centerArgs[1], XtNy, dest_y); + XtSetValues (promptShell, centerArgs, 2); + XtMapWidget(promptShell); + promptfunction = func; +} + +/* For DviChar.c */ + +char *xmalloc(n) + int n; +{ + return XtMalloc(n); +} + +/* +Local Variables: +c-indent-level: 4 +c-continued-statement-offset: 4 +c-brace-offset: -4 +c-argdecl-indent: 4 +c-label-offset: -4 +c-tab-always-indent: nil +End: +*/ diff --git a/gnu/usr.bin/groff/xditview/xtotroff.c b/gnu/usr.bin/groff/xditview/xtotroff.c new file mode 100644 index 0000000000..16e8c263e8 --- /dev/null +++ b/gnu/usr.bin/groff/xditview/xtotroff.c @@ -0,0 +1,303 @@ +/* + * xtotroff + * + * convert X font metrics into troff font metrics + */ + +#include +#include +#include +#include "XFontName.h" +#include "DviChar.h" + +#ifdef X_NOT_STDC_ENV +char *malloc(); +#else +#include +#endif + +#define charWidth(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].width) +#define charHeight(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].ascent) +#define charDepth(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].descent) +#define charLBearing(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].lbearing) +#define charRBearing(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].rbearing) + +Display *dpy; +int groff_flag = 0; +unsigned resolution = 75; +unsigned point_size = 10; + +int charExists (fi, c) + XFontStruct *fi; + int c; +{ + XCharStruct *p; + + if (c < fi->min_char_or_byte2 || c > fi->max_char_or_byte2) + return 0; + p = fi->per_char + (c - fi->min_char_or_byte2); + return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0 + || p->ascent != 0 || p->descent != 0 || p->attributes != 0); +} + +/* Canonicalize the font name by replacing scalable parts by *s. */ + +CanonicalizeFontName (font_name, canon_font_name) + char *font_name, *canon_font_name; +{ + unsigned int attributes; + XFontName parsed; + + if (!XParseFontName(font_name, &parsed, &attributes)) { + fprintf (stderr, "not a standard name: %s\n", font_name); + return 0; + } + + attributes &= ~(FontNamePixelSize|FontNameAverageWidth + |FontNamePointSize + |FontNameResolutionX|FontNameResolutionY); + XFormatFontName(&parsed, attributes, canon_font_name); + return 1; +} + +int FontNamesAmbiguous(font_name, names, count) +char *font_name; +char **names; +int count; +{ + char name1[2048], name2[2048]; + int i; + + if (count == 1) + return 0; + + for (i = 0; i < count; i++) { + if (!CanonicalizeFontName(names[i], i == 0 ? name1 : name2)) { + fprintf(stderr, "bad font name: %s\n", names[i]); + return 1; + } + if (i > 0 && strcmp(name1, name2) != 0) { + fprintf(stderr, "ambiguous font name: %s\n", font_name); + fprintf(stderr, " matches %s\n", names[0]); + fprintf(stderr, " and %s\n", names[i]); + return 1; + } + + } + return 0; +} + +MapFont (font_name, troff_name) + char *font_name; + char *troff_name; +{ + XFontStruct *fi; + int count; + char **names; + FILE *out; + int c; + unsigned int attributes; + XFontName parsed; + int j, k; + DviCharNameMap *char_map; + char encoding[256]; + char *s; + int wid; + char name_string[2048]; + + if (!XParseFontName(font_name, &parsed, &attributes)) { + fprintf (stderr, "not a standard name: %s\n", font_name); + return 0; + } + + attributes &= ~(FontNamePixelSize|FontNameAverageWidth); + attributes |= FontNameResolutionX; + attributes |= FontNameResolutionY; + attributes |= FontNamePointSize; + parsed.ResolutionX = resolution; + parsed.ResolutionY = resolution; + parsed.PointSize = point_size*10; + XFormatFontName(&parsed, attributes, name_string); + + names = XListFonts (dpy, name_string, 100000, &count); + if (count < 1) { + fprintf (stderr, "bad font name: %s\n", font_name); + return 0; + } + + if (FontNamesAmbiguous(font_name, names, count)) + return 0; + + XParseFontName(names[0], &parsed, &attributes); + sprintf (encoding, "%s-%s", parsed.CharSetRegistry, + parsed.CharSetEncoding); + for (s = encoding; *s; s++) + if (isupper (*s)) + *s = tolower (*s); + char_map = DviFindMap (encoding); + if (!char_map) { + fprintf (stderr, "not a standard encoding: %s\n", encoding); + return 0; + } + + fi = XLoadQueryFont (dpy, names[0]); + if (!fi) { + fprintf (stderr, "font does not exist: %s\n", names[0]); + return 0; + } + + printf ("%s -> %s\n", names[0], troff_name); + + (void) unlink (troff_name); + out = fopen (troff_name, "w"); + if (!out) { + perror (troff_name); + return 0; + } + fprintf (out, "name %s\n", troff_name); + if (!strcmp (char_map->encoding, "adobe-fontspecific")) + fprintf (out, "special\n"); + if (charExists (fi, ' ')) { + int w = charWidth (fi, ' '); + if (w > 0) + fprintf (out, "spacewidth %d\n", w); + } + fprintf (out, "charset\n"); + for (c = fi->min_char_or_byte2; c <= fi->max_char_or_byte2; c++) { + char *name = DviCharName (char_map,c,0); + if (charExists (fi, c) && (groff_flag || name)) { + + wid = charWidth (fi, c); + + fprintf (out, "%s\t%d", + name ? name : "---", + wid); + if (groff_flag) { + int param[5]; + param[0] = charHeight (fi, c); + param[1] = charDepth (fi, c); + param[2] = 0 /* charRBearing (fi, c) - wid */; + param[3] = 0 /* charLBearing (fi, c) */; + param[4] = 0; /* XXX */ + for (j = 0; j < 5; j++) + if (param[j] < 0) + param[j] = 0; + for (j = 4; j >= 0; j--) + if (param[j] != 0) + break; + for (k = 0; k <= j; k++) + fprintf (out, ",%d", param[k]); + } + fprintf (out, "\t0\t0%o\n", c); + + if (name) { + for (k = 1; DviCharName(char_map,c,k); k++) { + fprintf (out, "%s\t\"\n", + DviCharName (char_map,c,k)); + } + } + } + } + XUnloadFont (dpy, fi->fid); + fclose (out); + return 1; +} + +static usage(prog) + char *prog; +{ + fprintf (stderr, + "usage: %s [-g] [-r resolution] [-s pointsize FontMap\n", + prog); + exit (1); +} + + +/* For use by DviChar.c */ + +char *xmalloc(n) +int n; +{ + char *p = malloc(n); + if (!p) { + fprintf(stderr, "Out of memory\n"); + exit(1); + } + return p; +} + +main (argc, argv) + char **argv; +{ + char troff_name[1024]; + char font_name[1024]; + char line[1024]; + char *a, *b, c; + int position; + FILE *map; + int opt; + extern int optind; + extern char *optarg; + + while ((opt = getopt(argc, argv, "gr:s:")) != EOF) { + switch (opt) { + case 'g': + groff_flag = 1; + break; + case 'r': + sscanf(optarg, "%u", &resolution); + break; + case 's': + sscanf(optarg, "%u", &point_size); + break; + default: + usage(argv[0]); + } + } + if (argc - optind != 1) + usage(argv[0]); + + dpy = XOpenDisplay (0); + if (!dpy) { + fprintf (stderr, "Can't connect to the X server.\n"); + fprintf (stderr, "Make sure the DISPLAY environment variable is set correctly.\n"); + exit (1); + } + position = 1; + + map = fopen (argv[optind], "r"); + if (map == NULL) { + perror (argv[optind]); + exit (1); + } + + while (fgets (line, sizeof (line), map)) { + for (a=line,b=troff_name; *a; a++,b++) { + c = (*b = *a); + if (c == ' ' || c == '\t') + break; + } + *b = '\0'; + while (*a && (*a == ' ' || *a == '\t')) + ++a; + for (b=font_name; *a; a++,b++) + if ((*b = *a) == '\n') + break; + *b = '\0'; + if (!MapFont (font_name, troff_name)) + exit (1); + ++position; + } + exit (0); +} + +/* +Local Variables: +c-indent-level: 8 +c-continued-statement-offset: 8 +c-brace-offset: -8 +c-argdecl-indent: 8 +c-label-offset: -8 +c-tab-always-indent: nil +End: +*/ diff --git a/gnu/usr.bin/rcs/Makefile b/gnu/usr.bin/rcs/Makefile new file mode 100644 index 0000000000..21818151d9 --- /dev/null +++ b/gnu/usr.bin/rcs/Makefile @@ -0,0 +1,3 @@ +SUBDIR= lib ci co ident merge rcs rcsdiff rcsmerge rlog rcsfreeze + +.include diff --git a/gnu/usr.bin/rcs/Makefile.inc b/gnu/usr.bin/rcs/Makefile.inc new file mode 100644 index 0000000000..b9eca7d521 --- /dev/null +++ b/gnu/usr.bin/rcs/Makefile.inc @@ -0,0 +1,3 @@ +# @(#)Makefile.inc 5.1 (Berkeley) 5/11/90 + +BINDIR?= /usr/bin diff --git a/gnu/usr.bin/rcs/ci/Makefile b/gnu/usr.bin/rcs/ci/Makefile new file mode 100644 index 0000000000..9b64e0848a --- /dev/null +++ b/gnu/usr.bin/rcs/ci/Makefile @@ -0,0 +1,7 @@ +PROG= ci + +SRCS= ci.c +LDADD= -L${.CURDIR}/../lib/obj -lrcs +CFLAGS+= -I${.CURDIR}/../lib + +.include diff --git a/gnu/usr.bin/rcs/ci/ci.1 b/gnu/usr.bin/rcs/ci/ci.1 new file mode 100644 index 0000000000..5736dc95a0 --- /dev/null +++ b/gnu/usr.bin/rcs/ci/ci.1 @@ -0,0 +1,772 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: ci.1,v 5.9 1991/10/07 17:32:46 eggert Exp $ +.ds r \&\s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.TH CI 1 \*(Dt GNU +.SH NAME +ci \- check in RCS revisions +.SH SYNOPSIS +.B ci +.RI [ options ] " file " .\|.\|. +.SH DESCRIPTION +.B ci +stores new revisions into \*r files. +Each pathname matching an \*r suffix +is taken to be an \*r file. +All others +are assumed to be working files containing new revisions. +.B ci +deposits the contents of each working file +into the corresponding \*r file. +If only a working file is given, +.B ci +tries to find the corresponding \*r file in an \*r subdirectory +and then in the working file's directory. +For more details, see +.SM "FILE NAMING" +below. +.PP +For +.B ci +to work, the caller's login must be on the access list, +except if the access list is empty or the caller is the superuser or the +owner of the file. +To append a new revision to an existing branch, the tip revision on +that branch must be locked by the caller. Otherwise, only a +new branch can be created. This restriction is not enforced +for the owner of the file if non-strict locking is used +(see +.BR rcs (1)). +A lock held by someone else may be broken with the +.B rcs +command. +.PP +Unless the +.B \-f +option is given, +.B ci +checks whether the revision to be deposited differs from the preceding one. +If not, instead of creating a new revision +.B ci +reverts to the preceding one. +To revert, ordinary +.B ci +removes the working file and any lock; +.B "ci\ \-l" +keeps and +.B "ci\ \-u" +removes any lock, and then they both generate a new working file much as if +.B "co\ \-l" +or +.B "co\ \-u" +had been applied to the preceding revision. +When reverting, any +.B \-n +and +.B \-s +options apply to the preceding revision. +.PP +For each revision deposited, +.B ci +prompts for a log message. +The log message should summarize the change and must be terminated by +end-of-file or by a line containing +.BR \&. "\ by" +itself. +If several files are checked in +.B ci +asks whether to reuse the +previous log message. +If the standard input is not a terminal, +.B ci +suppresses the prompt +and uses the same log message for all files. +See also +.BR \-m . +.PP +If the \*r file does not exist, +.B ci +creates it and +deposits the contents of the working file as the initial revision +(default number: +.BR 1.1 ). +The access list is initialized to empty. +Instead of the log message, +.B ci +requests descriptive text (see +.B \-t +below). +.PP +The number +.I rev +of the deposited revision can be given by any of the options +.BR \-f , +.BR \-I , +.BR \-k , +.BR \-l , +.BR \-M , +.BR \-q , +.BR \-r , +or +.BR \-u . +.I rev +may be symbolic, numeric, or mixed. +If +.I rev +is +.BR $ , +.B ci +determines the revision number from keyword values in the working file. +.PP +If +.I rev +is a revision number, it must be higher than the latest +one on the branch to which +.I rev +belongs, or must start a new branch. +.PP +If +.I rev +is a branch rather than a revision number, +the new revision is appended to that branch. The level number is obtained +by incrementing the tip revision number of that branch. +If +.I rev +indicates a non-existing branch, +that branch is created with the initial revision numbered +.IB rev .1\f1.\fP +.br +.ne 8 +.PP +If +.I rev +is omitted, +.B ci +tries to derive the new revision number from +the caller's last lock. If the caller has locked the tip revision of a branch, +the new revision is appended to that branch. +The new revision number is obtained +by incrementing the tip revision number. +If the caller locked a non-tip revision, a new branch is started at +that revision by incrementing the highest branch number at that revision. +The default initial branch and level numbers are +.BR 1 . +.PP +If +.I rev +is omitted and the caller has no lock, but owns +the file and locking +is not set to +.IR strict , +then the revision is appended to the +default branch (normally the trunk; see the +.B \-b +option of +.BR rcs (1)). +.PP +Exception: On the trunk, revisions can be appended to the end, but +not inserted. +.SH OPTIONS +.TP +.BR \-r [\f2rev\fP] +checks in a revision, releases the corresponding lock, and +removes the working file. This is the default. +.RS +.PP +The +.B \-r +option has an unusual meaning in +.BR ci . +In other \*r commands, +.B \-r +merely specifies a revision number, +but in +.B ci +it also releases a lock and removes the working file. +See +.B \-u +for a tricky example. +.RE +.TP +.BR \-l [\f2rev\fP] +works like +.BR \-r , +except it performs an additional +.B "co\ \-l" +for the +deposited revision. Thus, the deposited revision is immediately +checked out again and locked. +This is useful for saving a revision although one wants to continue +editing it after the checkin. +.TP +.BR \-u [\f2rev\fP] +works like +.BR \-l , +except that the deposited revision is not locked. +This lets one read the working file +immediately after checkin. +.RS +.PP +The +.BR \-l , +.BR \-r , +and +.B \-u +options are mutually exclusive and silently override each other. +For example, +.B "ci\ \-u\ \-r" +is equivalent to +.B "ci\ \-r" +because +.B \-r +overrides +.BR \-u . +.RE +.TP +.BR \-f [\f2rev\fP] +forces a deposit; the new revision is deposited even it is not different +from the preceding one. +.TP +.BR \-k [\f2rev\fP] +searches the working file for keyword values to determine its revision number, +creation date, state, and author (see +.BR co (1)), +and assigns these +values to the deposited revision, rather than computing them locally. +It also generates a default login message noting the login of the caller +and the actual checkin date. +This option is useful for software distribution. A revision that is sent to +several sites should be checked in with the +.B \-k +option at these sites to +preserve the original number, date, author, and state. +The extracted keyword values and the default log message may be overridden +with the options +.BR \-d , +.BR \-m , +.BR \-s , +.BR \-w , +and any option that carries a revision number. +.TP +.BR \-q [\f2rev\fP] +quiet mode; diagnostic output is not printed. +A revision that is not different from the preceding one is not deposited, +unless +.B \-f +is given. +.TP +.BR \-I [\f2rev\fP] +interactive mode; +the user is prompted and questioned +even if the standard input is not a terminal. +.TP +.BR \-d "[\f2date\fP]" +uses +.I date +for the checkin date and time. +The +.I date +is specified in free format as explained in +.BR co (1). +This is useful for lying about the checkin date, and for +.B \-k +if no date is available. +If +.I date +is empty, the working file's time of last modification is used. +.TP +.BR \-M [\f2rev\fP] +Set the modification time on any new working file +to be the date of the retrieved revision. +For example, +.BI "ci\ \-d\ \-M\ \-u" "\ f" +does not alter +.IR f 's +modification time, even if +.IR f 's +contents change due to keyword substitution. +Use this option with care; it can confuse +.BR make (1). +.TP +.BI \-m "msg" +uses the string +.I msg +as the log message for all revisions checked in. +.TP +.BI \-n "name" +assigns the symbolic name +.I name +to the number of the checked-in revision. +.B ci +prints an error message if +.I name +is already assigned to another +number. +.TP +.BI \-N "name" +same as +.BR \-n , +except that it overrides a previous assignment of +.IR name . +.TP +.BI \-s "state" +sets the state of the checked-in revision to the identifier +.IR state . +The default state is +.BR Exp . +.TP +.BI \-t file +writes descriptive text from the contents of the named +.I file +into the \*r file, +deleting the existing text. +The +.I file +may not begin with +.BR \- . +.TP +.BI \-t\- string +Write descriptive text from the +.I string +into the \*r file, deleting the existing text. +.RS +.PP +The +.B \-t +option, in both its forms, has effect only during an initial checkin; +it is silently ignored otherwise. +.PP +During the initial checkin, if +.B \-t +is not given, +.B ci +obtains the text from standard input, +terminated by end-of-file or by a line containing +.BR \&. "\ by" +itself. +The user is prompted for the text if interaction is possible; see +.BR \-I . +.PP +For backward compatibility with older versions of \*r, a bare +.B \-t +option is ignored. +.RE +.TP +.BI \-w "login" +uses +.I login +for the author field of the deposited revision. +Useful for lying about the author, and for +.B \-k +if no author is available. +.TP +.BI \-V n +Emulate \*r version +.IR n . +See +.BR co (1) +for details. +.TP +.BI \-x "suffixes" +specifies the suffixes for \*r files. +A nonempty suffix matches any pathname ending in the suffix. +An empty suffix matches any pathname of the form +.BI RCS/ file +or +.IB path /RCS/ file. +The +.B \-x +option can specify a list of suffixes +separated by +.BR / . +For example, +.B \-x,v/ +specifies two suffixes: +.B ,v +and the empty suffix. +If two or more suffixes are specified, +they are tried in order when looking for an \*r file; +the first one that works is used for that file. +If no \*r file is found but an \*r file can be created, +the suffixes are tried in order +to determine the new \*r file's name. +The default for +.IR suffixes +is installation-dependent; normally it is +.B ,v/ +for hosts like Unix that permit commas in file names, +and is empty (i.e. just the empty suffix) for other hosts. +.SH "FILE NAMING" +Pairs of \*r files and working files may be specified in three ways +(see also the +example section). +.PP +1) Both the \*r file and the working file are given. The \*r pathname is of +the form +.IB path1 / workfileX +and the working pathname is of the form +.IB path2 / workfile +where +.IB path1 / +and +.IB path2 / +are (possibly different or empty) paths, +.I workfile +is a filename, and +.I X +is an \*r suffix. +If +.I X +is empty, +.IB path1 / +must be +.B RCS/ +or must end in +.BR /RCS/ . +.PP +2) Only the \*r file is given. Then the working file is created in the current +directory and its name is derived from the name of the \*r file +by removing +.IB path1 / +and the suffix +.IR X . +.PP +3) Only the working file is given. +Then +.B ci +considers each \*r suffix +.I X +in turn, looking for an \*r file of the form +.IB path2 /RCS/ workfileX +or (if the former is not found and +.I X +is nonempty) +.IB path2 / workfileX. +.PP +If the \*r file is specified without a path in 1) and 2), +.B ci +looks for the \*r file first in the directory +.B ./RCS +and then in the current +directory. +.PP +.B ci +reports an error if an attempt to open an \*r file fails for an unusual reason, +even if the \*r file's pathname is just one of several possibilities. +For example, to suppress use of \*r commands in a directory +.IR d , +create a regular file named +.IB d /RCS +so that casual attempts to use \*r commands in +.I d +fail because +.IB d /RCS +is not a directory. +.SH EXAMPLES +Suppose +.B ,v +is an \*r suffix and the current directory contains a subdirectory +.B RCS +with an \*r file +.BR io.c,v . +Then each of the following commands check in a copy of +.B io.c +into +.B RCS/io.c,v +as the latest revision, removing +.BR io.c . +.LP +.RS +.nf +.ft 3 +ci io.c; ci RCS/io.c,v; ci io.c,v; +ci io.c RCS/io.c,v; ci io.c io.c,v; +ci RCS/io.c,v io.c; ci io.c,v io.c; +.ft +.fi +.RE +.PP +Suppose instead that the empty suffix +is an \*r suffix and the current directory contains a subdirectory +.B RCS +with an \*r file +.BR io.c . +The each of the following commands checks in a new revision. +.LP +.RS +.nf +.ft 3 +ci io.c; ci RCS/io.c; +ci io.c RCS/io.c; +ci RCS/io.c io.c; +.ft +.fi +.RE +.SH "FILE MODES" +An \*r file created by +.B ci +inherits the read and execute permissions +from the working file. If the \*r file exists already, +.B ci +preserves its read and execute permissions. +.B ci +always turns off all write permissions of \*r files. +.SH FILES +Several temporary files may be created in the directory containing +the working file, and also in the temporary directory (see +.B \s-1TMPDIR\s0 +under +.BR \s-1ENVIRONMENT\s0 ). +A semaphore file or files are created in the directory containing the \*r file. +With a nonempty suffix, the semaphore names begin with +the first character of the suffix; therefore, do not specify an suffix +whose first character could be that of a working filename. +With an empty suffix, the semaphore names end with +.B _ +so working filenames should not end in +.BR _ . +.PP +.B ci +never changes an \*r or working file. +Normally, +.B ci +unlinks the file and creates a new one; +but instead of breaking a chain of one or more symbolic links to an \*r file, +it unlinks the destination file instead. +Therefore, +.B ci +breaks any hard or symbolic links to any working file it changes; +and hard links to \*r files are ineffective, +but symbolic links to \*r files are preserved. +.PP +The effective user must be able to +search and write the directory containing the \*r file. +Normally, the real user must be able to +read the \*r and working files +and to search and write the directory containing the working file; +however, some older hosts +cannot easily switch between real and effective users, +so on these hosts the effective user is used for all accesses. +The effective user is the same as the real user +unless your copies of +.B ci +and +.B co +have setuid privileges. +As described in the next section, +these privileges yield extra security if +the effective user owns all \*r files and directories, +and if only the effective user can write \*r directories. +.PP +Users can control access to \*r files by setting the permissions +of the directory containing the files; only users with write access +to the directory can use \*r commands to change its \*r files. +For example, in hosts that allow a user to belong to several groups, +one can make a group's \*r directories writable to that group only. +This approach suffices for informal projects, +but it means that any group member can arbitrarily change the group's \*r files, +and can even remove them entirely. +Hence more formal projects sometimes distinguish between an \*r administrator, +who can change the \*r files at will, and other project members, +who can check in new revisions but cannot otherwise change the \*r files. +.SH "SETUID USE" +To prevent anybody but their \*r administrator from deleting revisions, +a set of users can employ setuid privileges as follows. +.nr n \w'\(bu '+1n-1/1n +.IP \(bu \nn +Check that the host supports \*r setuid use. +Consult a trustworthy expert if there are any doubts. +It is best if the +.B seteuid() +system call works as described in Posix 1003.1a Draft 5, +because \*r can switch back and forth easily +between real and effective users, even if the real user is +.BR root . +If not, the second best is if the +.B setuid() +system call supports saved setuid +(the {\s-1_POSIX_SAVED_IDS\s0} behavior of Posix 1003.1-1990); +this fails only if the real user is +.BR root . +If \*r detects any failure in setuid, it quits immediately. +.IP \(bu \nn +Choose a user +.I A +to serve as \*r administrator for the set of users. +Only +.I A +will be able to invoke the +.B rcs +command on the users' \*r files. +.I A +should not be +.B root +or any other user with special powers. +Mutually suspicious sets of users should use different administrators. +.IP \(bu \nn +Choose a path name +.I B +that will be a directory of files to be executed by the users. +.IP \(bu \nn +Have +.I A +set up +.I B +to contain copies of +.B ci +and +.B co +that are setuid to +.I A +by copying the commands from their standard installation directory +.I D +as follows: +.LP +.RS +.nf +.ne 3 +\f3mkdir\fP \f2B\fP +\f3cp\fP \f2D\fP\^\f3/c[io]\fP \f2B\fP +\f3chmod go\-w,u+s\fP \f2B\fP\f3/c[io]\fP +.fi +.RE +.IP \(bu \nn +Have each user prepend +.I B +to their path as follows: +.LP +.RS +.nf +.ne 2 +\f3PATH=\fP\f2B\fP\f3:$PATH; export PATH\fP # ordinary shell +\f3set path=(\fP\f2B\fP \f3$path)\fP # C shell +.fi +.RE +.IP \(bu \nn +Have +.I A +create each \*r directory +.I R +with write access only to +.I A +as follows: +.LP +.RS +.nf +.ne 2 +\f3mkdir\fP \f2R\fP +\f3chmod go\-w\fP \f2R\fP +.fi +.RE +.IP \(bu \nn +If you want to let only certain users read the \*r files, +put the users into a group +.IR G , +and have +.I A +further protect the \*r directory as follows: +.LP +.RS +.nf +.ne 2 +\f3chgrp\fP \f2G R\fP +\f3chmod g\-w,o\-rwx\fP \f2R\fP +.fi +.RE +.IP \(bu \nn +Have +.I A +copy old \*r files (if any) into +.IR R , +to ensure that +.I A +owns them. +.IP \(bu \nn +An \*r file's access list limits who can check in and lock revisions. +The default access list is empty, +which grants checkin access to anyone who can read the \*r file. +If you want limit checkin access, +have +.I A +invoke +.B "rcs\ \-a" +on the file; see +.BR rcs (1). +In particular, +.BI "rcs\ \-e\ \-a" A +limits access to just +.IR A . +.IP \(bu \nn +Have +.I A +initialize any new \*r files with +.B "rcs\ \-i" +before initial checkin, adding the +.B \-a +option if you want to limit checkin access. +.IP \(bu \nn +Give setuid privileges only to +.BR ci , +.BR co , +and +.BR rcsclean ; +do not give them to +.B rcs +or to any other command. +.IP \(bu \nn +Do not use other setuid commands to invoke \*r commands; +setuid is trickier than you think! +.SH ENVIRONMENT +.TP +.B \s-1RCSINIT\s0 +options prepended to the argument list, separated by spaces. +A backslash escapes spaces within an option. +The +.B \s-1RCSINIT\s0 +options are prepended to the argument lists of most \*r commands. +Useful +.B \s-1RCSINIT\s0 +options include +.BR \-q , +.BR \-V , +and +.BR \-x . +.TP +.B \s-1TMPDIR\s0 +Name of the temporary directory. +If not set, the environment variables +.B \s-1TMP\s0 +and +.B \s-1TEMP\s0 +are inspected instead and the first value found is taken; +if none of them are set, +a host-dependent default is used, typically +.BR /tmp . +.SH DIAGNOSTICS +For each revision, +.B ci +prints the \*r file, the working file, and the number +of both the deposited and the preceding revision. +The exit status is zero if and only if all operations were successful. +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH "SEE ALSO" +co(1), ident(1), make(1), rcs(1), rcsclean(1), rcsdiff(1), +rcsintro(1), rcsmerge(1), rlog(1), rcsfile(5) +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. +.br diff --git a/gnu/usr.bin/rcs/ci/ci.c b/gnu/usr.bin/rcs/ci/ci.c new file mode 100644 index 0000000000..566747e139 --- /dev/null +++ b/gnu/usr.bin/rcs/ci/ci.c @@ -0,0 +1,1165 @@ +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + +/* + * RCS checkin operation + */ +/******************************************************************* + * check revisions into RCS files + ******************************************************************* + */ + + + +/* $Log: ci.c,v $ + * Revision 5.21 1991/11/20 17:58:07 eggert + * Don't read the delta tree from a nonexistent RCS file. + * + * Revision 5.20 1991/10/07 17:32:46 eggert + * Fix log bugs. Remove lint. + * + * Revision 5.19 1991/09/26 23:10:30 eggert + * Plug file descriptor leak. + * + * Revision 5.18 1991/09/18 07:29:10 eggert + * Work around a common ftruncate() bug. + * + * Revision 5.17 1991/09/10 22:15:46 eggert + * Fix test for redirected stdin. + * + * Revision 5.16 1991/08/19 23:17:54 eggert + * When there are no changes, revert to previous revision instead of aborting. + * Add piece tables, -M, -r$. Tune. + * + * Revision 5.15 1991/04/21 11:58:14 eggert + * Ensure that working file is newer than RCS file after ci -[lu]. + * Add -x, RCSINIT, MS-DOS support. + * + * Revision 5.14 1991/02/28 19:18:47 eggert + * Don't let a setuid ci create a new RCS file; rcs -i -a must be run first. + * Fix ci -ko -l mode bug. Open work file at most once. + * + * Revision 5.13 1991/02/25 07:12:33 eggert + * getdate -> getcurdate (SVR4 name clash) + * + * Revision 5.12 1990/12/31 01:00:12 eggert + * Don't use uninitialized storage when handling -{N,n}. + * + * Revision 5.11 1990/12/04 05:18:36 eggert + * Use -I for prompts and -q for diagnostics. + * + * Revision 5.10 1990/11/05 20:30:10 eggert + * Don't remove working file when aborting due to no changes. + * + * Revision 5.9 1990/11/01 05:03:23 eggert + * Add -I and new -t behavior. Permit arbitrary data in logs. + * + * Revision 5.8 1990/10/04 06:30:09 eggert + * Accumulate exit status across files. + * + * Revision 5.7 1990/09/25 20:11:46 hammer + * fixed another small typo + * + * Revision 5.6 1990/09/24 21:48:50 hammer + * added cleanups from Paul Eggert. + * + * Revision 5.5 1990/09/21 06:16:38 hammer + * made it handle multiple -{N,n}'s. Also, made it treat re-directed stdin + * the same as the terminal + * + * Revision 5.4 1990/09/20 02:38:51 eggert + * ci -k now checks dates more thoroughly. + * + * Revision 5.3 1990/09/11 02:41:07 eggert + * Fix revision bug with `ci -k file1 file2'. + * + * Revision 5.2 1990/09/04 08:02:10 eggert + * Permit adjacent revisions with identical time stamps (possible on fast hosts). + * Improve incomplete line handling. Standardize yes-or-no procedure. + * + * Revision 5.1 1990/08/29 07:13:44 eggert + * Expand locker value like co. Clean old log messages too. + * + * Revision 5.0 1990/08/22 08:10:00 eggert + * Don't require a final newline. + * Make lock and temp files faster and safer. + * Remove compile-time limits; use malloc instead. + * Permit dates past 1999/12/31. Switch to GMT. + * Add setuid support. Don't pass +args to diff. Check diff's output. + * Ansify and Posixate. Add -k, -V. Remove snooping. Tune. + * Check diff's output. + * + * Revision 4.9 89/05/01 15:10:54 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.8 88/11/08 13:38:23 narten + * changes from root@seismo.CSS.GOV (Super User) + * -d with no arguments uses the mod time of the file it is checking in + * + * Revision 4.7 88/08/09 19:12:07 eggert + * Make sure workfile is a regular file; use its mode if RCSfile doesn't have one. + * Use execv(), not system(); allow cc -R; remove lint. + * isatty(fileno(stdin)) -> ttystdin() + * + * Revision 4.6 87/12/18 11:34:41 narten + * lint cleanups (from Guy Harris) + * + * Revision 4.5 87/10/18 10:18:48 narten + * Updating version numbers. Changes relative to revision 1.1 are actually + * relative to 4.3 + * + * Revision 1.3 87/09/24 13:57:19 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:21:33 jenkins + * Port to suns + * + * Revision 4.3 83/12/15 12:28:54 wft + * ci -u and ci -l now set mode of working file properly. + * + * Revision 4.2 83/12/05 13:40:54 wft + * Merged with 3.9.1.1: added calls to clearerr(stdin). + * made rewriteflag external. + * + * Revision 4.1 83/05/10 17:03:06 wft + * Added option -d and -w, and updated assingment of date, etc. to new delta. + * Added handling of default branches. + * Option -k generates std. log message; fixed undef. pointer in reading of log. + * Replaced getlock() with findlock(), link--unlink with rename(), + * getpwuid() with getcaller(). + * Moved all revision number generation to new routine addelta(). + * Removed calls to stat(); now done by pairfilenames(). + * Changed most calls to catchints() with restoreints(). + * Directed all interactive messages to stderr. + * + * Revision 3.9.1.1 83/10/19 04:21:03 lepreau + * Added clearerr(stdin) to getlogmsg() for re-reading stdin. + * + * Revision 3.9 83/02/15 15:25:44 wft + * 4.2 prerelease + * + * Revision 3.9 83/02/15 15:25:44 wft + * Added call to fastcopy() to copy remainder of RCS file. + * + * Revision 3.8 83/01/14 15:34:05 wft + * Added ignoring of interrupts while new RCS file is renamed; + * Avoids deletion of RCS files by interrupts. + * + * Revision 3.7 82/12/10 16:09:20 wft + * Corrected checking of return code from diff. + * + * Revision 3.6 82/12/08 21:34:49 wft + * Using DATEFORM to prepare date of checked-in revision; + * Fixed return from addbranch(). + * + * Revision 3.5 82/12/04 18:32:42 wft + * Replaced getdelta() with gettree(), SNOOPDIR with SNOOPFILE. Updated + * field lockedby in removelock(), moved getlogmsg() before calling diff. + * + * Revision 3.4 82/12/02 13:27:13 wft + * added option -k. + * + * Revision 3.3 82/11/28 20:53:31 wft + * Added mustcheckin() to check for redundant checkins. + * Added xpandfile() to do keyword expansion for -u and -l; + * -m appends linefeed to log message if necessary. + * getlogmsg() suppresses prompt if stdin is not a terminal. + * Replaced keeplock with lockflag, fclose() with ffclose(), + * %02d with %.2d, getlogin() with getpwuid(). + * + * Revision 3.2 82/10/18 20:57:23 wft + * An RCS file inherits its mode during the first ci from the working file, + * otherwise it stays the same, except that write permission is removed. + * Fixed ci -l, added ci -u (both do an implicit co after the ci). + * Fixed call to getlogin(), added call to getfullRCSname(), added check + * for write error. + * Changed conflicting identifiers. + * + * Revision 3.1 82/10/13 16:04:59 wft + * fixed type of variables receiving from getc() (char -> int). + * added include file dbm.h for getting BYTESIZ. This is used + * to check the return code from diff portably. + */ + +#include "rcsbase.h" + +struct Symrev { + char const *ssymbol; + int override; + struct Symrev * nextsym; +}; + +static char const *getcurdate P((void)); +static int addbranch P((struct hshentry*,struct buf*)); +static int addelta P((void)); +static int addsyms P((char const*)); +static int fixwork P((mode_t,char const*)); +static int removelock P((struct hshentry*)); +static int xpandfile P((RILE*,char const*,struct hshentry const*,char const**)); +static struct cbuf getlogmsg P((void)); +static void cleanup P((void)); +static void incnum P((char const*,struct buf*)); +static void addassoclst P((int, char *)); + +static FILE *exfile; +static RILE *workptr; /* working file pointer */ +static struct buf newdelnum; /* new revision number */ +static struct cbuf msg; +static int exitstatus; +static int forceciflag; /* forces check in */ +static int keepflag, keepworkingfile, rcsinitflag; +static struct hshentries *gendeltas; /* deltas to be generated */ +static struct hshentry *targetdelta; /* old delta to be generated */ +static struct hshentry newdelta; /* new delta to be inserted */ +static struct stat workstat; +static struct Symrev *assoclst, *lastassoc; + +mainProg(ciId, "ci", "$Id: ci.c,v 5.21 1991/11/20 17:58:07 eggert Exp $") +{ + static char const cmdusage[] = + "\nci usage: ci -{fklqru}[rev] -mmsg -{nN}name -sstate -t[textfile] -Vn file ..."; + static char const default_state[] = DEFAULTSTATE; + + char altdate[datesize]; + char olddate[datesize]; + char newdatebuf[datesize], targetdatebuf[datesize]; + char *a, **newargv, *textfile; + char const *author, *krev, *rev, *state; + char const *diffilename, *expfilename; + char const *workdiffname, *newworkfilename; + char const *mtime; + int lockflag, lockthis, mtimeflag, removedlock; + int r; + int changedRCS, changework, newhead; + int usestatdate; /* Use mod time of file for -d. */ + mode_t newworkmode; /* mode for working file */ + struct hshentry *workdelta; + + setrid(); + + author = rev = state = textfile = nil; + lockflag = false; + mtimeflag = false; + altdate[0]= '\0'; /* empty alternate date for -d */ + usestatdate=false; + suffixes = X_DEFAULT; + + argc = getRCSINIT(argc, argv, &newargv); + argv = newargv; + while (a = *++argv, 0<--argc && *a++=='-') { + switch (*a++) { + + case 'r': + keepworkingfile = lockflag = false; + revno: + if (*a) { + if (rev) warn("redefinition of revision number"); + rev = a; + } + break; + + case 'l': + keepworkingfile=lockflag=true; + goto revno; + + case 'u': + keepworkingfile=true; lockflag=false; + goto revno; + + case 'I': + interactiveflag = true; + goto revno; + + case 'q': + quietflag=true; + goto revno; + + case 'f': + forceciflag=true; + goto revno; + + case 'k': + keepflag=true; + goto revno; + + case 'm': + if (msg.size) redefined('m'); + msg = cleanlogmsg(a, strlen(a)); + if (!msg.size) + warn("missing message for -m option"); + break; + + case 'n': + if (!*a) { + error("missing symbolic name after -n"); + break; + } + checksid(a); + addassoclst(false, a); + break; + + case 'N': + if (!*a) { + error("missing symbolic name after -N"); + break; + } + checksid(a); + addassoclst(true, a); + break; + + case 's': + if (*a) { + if (state) redefined('s'); + checksid(a); + state = a; + } else + warn("missing state for -s option"); + break; + + case 't': + if (*a) { + if (textfile) redefined('t'); + textfile = a; + } + break; + + case 'd': + if (altdate[0] || usestatdate) + redefined('d'); + altdate[0] = 0; + if (!(usestatdate = !*a)) + str2date(a, altdate); + break; + + case 'M': + mtimeflag = true; + goto revno; + + case 'w': + if (*a) { + if (author) redefined('w'); + checksid(a); + author = a; + } else + warn("missing author for -w option"); + break; + + case 'x': + suffixes = a; + break; + + case 'V': + setRCSversion(*argv); + break; + + + + default: + faterror("unknown option: %s%s", *argv, cmdusage); + }; + } /* end processing of options */ + + if (argc<1) faterror("no input file%s", cmdusage); + + /* now handle all filenames */ + do { + targetdelta=nil; + ffree(); + + switch (pairfilenames(argc, argv, rcswriteopen, false, false)) { + + case -1: /* New RCS file */ +# if has_setuid && has_getuid + if (euid() != ruid()) { + error("setuid initial checkin prohibited; use `rcs -i -a' first"); + continue; + } +# endif + rcsinitflag = true; + break; + + case 0: /* Error */ + continue; + + case 1: /* Normal checkin with prev . RCS file */ + rcsinitflag = !Head; + } + + /* now RCSfilename contains the name of the RCS file, and + * workfilename contains the name of the working file. + * If the RCS file exists, finptr contains the file descriptor for the + * RCS file. The admin node is initialized. + * RCSstat is set. + */ + + diagnose("%s <-- %s\n", RCSfilename,workfilename); + + if (!(workptr = Iopen(workfilename, FOPEN_R_WORK, &workstat))) { + eerror(workfilename); + continue; + } + if (finptr && !checkaccesslist()) continue; /* give up */ + + krev = rev; + if (keepflag) { + /* get keyword values from working file */ + if (!getoldkeys(workptr)) continue; + if (!rev && !*(krev = prevrev.string)) { + error("can't find a revision number in %s",workfilename); + continue; + } + if (!*prevdate.string && *altdate=='\0' && usestatdate==false) + warn("can't find a date in %s", workfilename); + if (!*prevauthor.string && !author) + warn("can't find an author in %s", workfilename); + if (!*prevstate.string && !state) + warn("can't find a state in %s", workfilename); + } /* end processing keepflag */ + + /* Read the delta tree. */ + if (finptr) + gettree(); + + /* expand symbolic revision number */ + if (!fexpandsym(krev, &newdelnum, workptr)) + continue; + + /* splice new delta into tree */ + if ((removedlock = addelta()) < 0) + continue; + + newdelta.num = newdelnum.string; + newdelta.branches=nil; + newdelta.lockedby=nil; /*might be changed by addlock() */ + newdelta.selector = true; + /* set author */ + if (author!=nil) + newdelta.author=author; /* set author given by -w */ + else if (keepflag && *prevauthor.string) + newdelta.author=prevauthor.string; /* preserve old author if possible*/ + else newdelta.author=getcaller();/* otherwise use caller's id */ + newdelta.state = default_state; + if (state!=nil) + newdelta.state=state; /* set state given by -s */ + else if (keepflag && *prevstate.string) + newdelta.state=prevstate.string; /* preserve old state if possible */ + if (usestatdate) { + time2date(workstat.st_mtime, altdate); + } + if (*altdate!='\0') + newdelta.date=altdate; /* set date given by -d */ + else if (keepflag && *prevdate.string) { + /* Preserve old date if possible. */ + str2date(prevdate.string, olddate); + newdelta.date = olddate; + } else + newdelta.date = getcurdate(); /* use current date */ + /* now check validity of date -- needed because of -d and -k */ + if (targetdelta!=nil && + cmpnum(newdelta.date,targetdelta->date) < 0) { + error("Date %s precedes %s in existing revision %s.", + date2str(newdelta.date, newdatebuf), + date2str(targetdelta->date, targetdatebuf), + targetdelta->num + ); + continue; + } + + + if (lockflag && addlock(&newdelta) < 0) continue; + if (!addsyms(newdelta.num)) + continue; + + + putadmin(frewrite); + puttree(Head,frewrite); + putdesc(false,textfile); + + changework = Expand != OLD_EXPAND; + lockthis = lockflag; + workdelta = &newdelta; + + /* build rest of file */ + if (rcsinitflag) { + diagnose("initial revision: %s\n", newdelnum.string); + /* get logmessage */ + newdelta.log=getlogmsg(); + if (!putdftext(newdelnum.string,newdelta.log,workptr,frewrite,false)) continue; + RCSstat.st_mode = workstat.st_mode; + changedRCS = true; + } else { + diffilename = maketemp(0); + workdiffname = workfilename; + if (workdiffname[0] == '+') { + /* Some diffs have options with leading '+'. */ + char *dp = ftnalloc(char, strlen(workfilename)+3); + workdiffname = dp; + *dp++ = '.'; + *dp++ = SLASH; + VOID strcpy(dp, workfilename); + } + newhead = Head == &newdelta; + if (!newhead) + foutptr = frewrite; + expfilename = buildrevision( + gendeltas, targetdelta, (FILE*)0, false + ); + if ( + !forceciflag && + (changework = rcsfcmp( + workptr, &workstat, expfilename, targetdelta + )) <= 0 + ) { + diagnose("file is unchanged; reverting to previous revision %s\n", + targetdelta->num + ); + if (removedlock < lockflag) { + diagnose("previous revision was not locked; ignoring -l option\n"); + lockthis = 0; + } + if (!(changedRCS = + lockflag < removedlock + || assoclst + || newdelta.state != default_state + && strcmp(newdelta.state, targetdelta->state) != 0 + )) + workdelta = targetdelta; + else { + /* + * We have started to build the wrong new RCS file. + * Start over from the beginning. + */ + long hwm = ftell(frewrite); + int bad_truncate; + if (fseek(frewrite, 0L, SEEK_SET) != 0) + Oerror(); +# if !has_ftruncate + bad_truncate = 1; +# else + /* + * Work around a common ftruncate() bug. + * We can't rely on has_truncate, because we might + * be using a filesystem exported to us via NFS. + */ + bad_truncate = ftruncate(fileno(frewrite),(off_t)0); + if (bad_truncate && errno != EACCES) + Oerror(); +# endif + Irewind(finptr); + Lexinit(); + getadmin(); + gettree(); + if (!(workdelta = genrevs( + targetdelta->num, (char*)0, (char*)0, (char*)0, + &gendeltas + ))) + continue; + workdelta->log = targetdelta->log; + if (newdelta.state != default_state) + workdelta->state = newdelta.state; + if (removedlock && removelock(workdelta)<0) + continue; + if (!addsyms(workdelta->num)) + continue; + if (!dorewrite(true, true)) + continue; + fastcopy(finptr, frewrite); + if (bad_truncate) + while (ftell(frewrite) < hwm) + /* White out any earlier mistake with '\n's. */ + /* This is unlikely. */ + afputc('\n', frewrite); + } + } else { + diagnose("new revision: %s; previous revision: %s\n", + newdelnum.string, targetdelta->num + ); + newdelta.log = getlogmsg(); + switch (run((char*)0, diffilename, + DIFF DIFF_FLAGS, + newhead ? workdiffname : expfilename, + newhead ? expfilename : workdiffname, + (char*)0 + )) { + case DIFF_FAILURE: case DIFF_SUCCESS: break; + default: faterror("diff failed"); + } + if (newhead) { + Irewind(workptr); + if (!putdftext(newdelnum.string,newdelta.log,workptr,frewrite,false)) continue; + if (!putdtext(targetdelta->num,targetdelta->log,diffilename,frewrite,true)) continue; + } else + if (!putdtext(newdelnum.string,newdelta.log,diffilename,frewrite,true)) continue; + changedRCS = true; + } + } + if (!donerewrite(changedRCS)) + continue; + + if (!keepworkingfile) { + Izclose(&workptr); + r = un_link(workfilename); /* Get rid of old file */ + } else { + newworkmode = WORKMODE(RCSstat.st_mode, + ! (Expand==VAL_EXPAND || lockthis < StrictLocks) + ); + mtime = mtimeflag ? workdelta->date : (char const*)0; + + /* Expand if it might change or if we can't fix mode, time. */ + if (changework || (r=fixwork(newworkmode,mtime)) != 0) { + Irewind(workptr); + /* Expand keywords in file. */ + locker_expansion = lockthis; + switch (xpandfile( + workptr, workfilename, + workdelta, &newworkfilename + )) { + default: + continue; + + case 0: + /* + * No expansion occurred; try to reuse working file + * unless we already tried and failed. + */ + if (changework) + if ((r=fixwork(newworkmode,mtime)) == 0) + break; + /* fall into */ + case 1: + if (!(r = setfiledate(newworkfilename,mtime))) { + Izclose(&workptr); + ignoreints(); + r = chnamemod(&exfile, newworkfilename, workfilename, newworkmode); + keepdirtemp(newworkfilename); + restoreints(); + } + } + } + } + if (r != 0) { + eerror(workfilename); + continue; + } + diagnose("done\n"); + + } while (cleanup(), + ++argv, --argc >=1); + + tempunlink(); + exitmain(exitstatus); +} /* end of main (ci) */ + + static void +cleanup() +{ + if (nerror) exitstatus = EXIT_FAILURE; + Izclose(&finptr); + Izclose(&workptr); + Ozclose(&exfile); + Ozclose(&fcopy); + Ozclose(&frewrite); + dirtempunlink(); +} + +#if lint +# define exiterr ciExit +#endif + exiting void +exiterr() +{ + dirtempunlink(); + tempunlink(); + _exit(EXIT_FAILURE); +} + +/*****************************************************************/ +/* the rest are auxiliary routines */ + + + static int +addelta() +/* Function: Appends a delta to the delta tree, whose number is + * given by newdelnum. Updates Head, newdelnum, newdelnumlength, + * and the links in newdelta. + * Return -1 on error, 1 if a lock is removed, 0 otherwise. + */ +{ + register char *tp; + register unsigned i; + int removedlock; + unsigned newdnumlength; /* actual length of new rev. num. */ + + newdnumlength = countnumflds(newdelnum.string); + + if (rcsinitflag) { + /* this covers non-existing RCS file and a file initialized with rcs -i */ + if ((newdnumlength==0)&&(Dbranch!=nil)) { + bufscpy(&newdelnum, Dbranch); + newdnumlength = countnumflds(Dbranch); + } + if (newdnumlength==0) bufscpy(&newdelnum, "1.1"); + else if (newdnumlength==1) bufscat(&newdelnum, ".1"); + else if (newdnumlength>2) { + error("Branch point doesn't exist for %s.",newdelnum.string); + return -1; + } /* newdnumlength == 2 is OK; */ + Head = &newdelta; + newdelta.next=nil; + return 0; + } + if (newdnumlength==0) { + /* derive new revision number from locks */ + switch (findlock(true, &targetdelta)) { + + default: + /* found two or more old locks */ + return -1; + + case 1: + /* found an old lock */ + /* check whether locked revision exists */ + if (!genrevs(targetdelta->num,(char*)0,(char*)0,(char*)0,&gendeltas)) + return -1; + if (targetdelta==Head) { + /* make new head */ + newdelta.next=Head; + Head= &newdelta; + } else if (!targetdelta->next && countnumflds(targetdelta->num)>2) { + /* new tip revision on side branch */ + targetdelta->next= &newdelta; + newdelta.next = nil; + } else { + /* middle revision; start a new branch */ + bufscpy(&newdelnum, ""); + return addbranch(targetdelta,&newdelnum); + } + incnum(targetdelta->num, &newdelnum); + return 1; /* successful use of existing lock */ + + case 0: + /* no existing lock; try Dbranch */ + /* update newdelnum */ + if (StrictLocks || !myself(RCSstat.st_uid)) { + error("no lock set by %s",getcaller()); + return -1; + } + if (Dbranch) { + bufscpy(&newdelnum, Dbranch); + } else { + incnum(Head->num, &newdelnum); + } + newdnumlength = countnumflds(newdelnum.string); + /* now fall into next statement */ + } + } + if (newdnumlength<=2) { + /* add new head per given number */ + if(newdnumlength==1) { + /* make a two-field number out of it*/ + if (cmpnumfld(newdelnum.string,Head->num,1)==0) + incnum(Head->num, &newdelnum); + else + bufscat(&newdelnum, ".1"); + } + if (cmpnum(newdelnum.string,Head->num) <= 0) { + error("deltanumber %s too low; must be higher than %s", + newdelnum.string, Head->num); + return -1; + } + targetdelta = Head; + if (0 <= (removedlock = removelock(Head))) { + if (!genrevs(Head->num,(char*)0,(char*)0,(char*)0,&gendeltas)) + return -1; + newdelta.next = Head; + Head = &newdelta; + } + return removedlock; + } else { + /* put new revision on side branch */ + /*first, get branch point */ + tp = newdelnum.string; + for (i = newdnumlength - (newdnumlength&1 ^ 1); (--i); ) + while (*tp++ != '.') + ; + *--tp = 0; /* Kill final dot to get old delta temporarily. */ + if (!(targetdelta=genrevs(newdelnum.string,(char*)nil,(char*)nil,(char*)nil,&gendeltas))) + return -1; + if (cmpnum(targetdelta->num, newdelnum.string) != 0) { + error("can't find branchpoint %s", newdelnum.string); + return -1; + } + *tp = '.'; /* Restore final dot. */ + return addbranch(targetdelta,&newdelnum); + } +} + + + + static int +addbranch(branchpoint,num) + struct hshentry *branchpoint; + struct buf *num; +/* adds a new branch and branch delta at branchpoint. + * If num is the null string, appends the new branch, incrementing + * the highest branch number (initially 1), and setting the level number to 1. + * the new delta and branchhead are in globals newdelta and newbranch, resp. + * the new number is placed into num. + * Return -1 on error, 1 if a lock is removed, 0 otherwise. + */ +{ + struct branchhead *bhead, **btrail; + struct buf branchnum; + int removedlock, result; + unsigned field, numlength; + static struct branchhead newbranch; /* new branch to be inserted */ + + numlength = countnumflds(num->string); + + if (branchpoint->branches==nil) { + /* start first branch */ + branchpoint->branches = &newbranch; + if (numlength==0) { + bufscpy(num, branchpoint->num); + bufscat(num, ".1.1"); + } else if (numlength&1) + bufscat(num, ".1"); + newbranch.nextbranch=nil; + + } else if (numlength==0) { + /* append new branch to the end */ + bhead=branchpoint->branches; + while (bhead->nextbranch) bhead=bhead->nextbranch; + bhead->nextbranch = &newbranch; + bufautobegin(&branchnum); + getbranchno(bhead->hsh->num, &branchnum); + incnum(branchnum.string, num); + bufautoend(&branchnum); + bufscat(num, ".1"); + newbranch.nextbranch=nil; + } else { + /* place the branch properly */ + field = numlength - (numlength&1 ^ 1); + /* field of branch number */ + btrail = &branchpoint->branches; + while (0 < (result=cmpnumfld(num->string,(*btrail)->hsh->num,field))) { + btrail = &(*btrail)->nextbranch; + if (!*btrail) { + result = -1; + break; + } + } + if (result < 0) { + /* insert/append new branchhead */ + newbranch.nextbranch = *btrail; + *btrail = &newbranch; + if (numlength&1) bufscat(num, ".1"); + } else { + /* branch exists; append to end */ + bufautobegin(&branchnum); + getbranchno(num->string, &branchnum); + targetdelta=genrevs(branchnum.string,(char*)nil, + (char*)nil,(char*)nil,&gendeltas); + bufautoend(&branchnum); + if (!targetdelta) + return -1; + if (cmpnum(num->string,targetdelta->num) <= 0) { + error("deltanumber %s too low; must be higher than %s", + num->string,targetdelta->num); + return -1; + } + if (0 <= (removedlock = removelock(targetdelta))) { + if (numlength&1) + incnum(targetdelta->num,num); + targetdelta->next = &newdelta; + newdelta.next = 0; + } + return removedlock; + /* Don't do anything to newbranch. */ + } + } + newbranch.hsh = &newdelta; + newdelta.next=nil; + return 0; +} + + static int +addsyms(num) + char const *num; +{ + register struct Symrev *p; + + for (p = assoclst; p; p = p->nextsym) + if (!addsymbol(num, p->ssymbol, p->override)) + return false; + return true; +} + + + static void +incnum(onum,nnum) + char const *onum; + struct buf *nnum; +/* Increment the last field of revision number onum by one and + * place the result into nnum. + */ +{ + register char *tp, *np; + register size_t l; + + l = strlen(onum); + bufalloc(nnum, l+2); + np = tp = nnum->string; + VOID strcpy(np, onum); + for (tp = np + l; np != tp; ) + if (isdigit(*--tp)) { + if (*tp != '9') { + ++*tp; + return; + } + *tp = '0'; + } else { + tp++; + break; + } + /* We changed 999 to 000; now change it to 1000. */ + *tp = '1'; + tp = np + l; + *tp++ = '0'; + *tp = 0; +} + + + + static int +removelock(delta) +struct hshentry * delta; +/* function: Finds the lock held by caller on delta, + * removes it, and returns nonzero if successful. + * Print an error message and return -1 if there is no such lock. + * An exception is if !StrictLocks, and caller is the owner of + * the RCS file. If caller does not have a lock in this case, + * return 0; return 1 if a lock is actually removed. + */ +{ + register struct lock *next, **trail; + char const *num; + + num=delta->num; + for (trail = &Locks; (next = *trail); trail = &next->nextlock) + if (next->delta == delta) + if (strcmp(getcaller(), next->login) == 0) { + /* We found a lock on delta by caller; delete it. */ + *trail = next->nextlock; + delta->lockedby = 0; + return 1; + } else { + error("revision %s locked by %s",num,next->login); + return -1; + } + if (!StrictLocks && myself(RCSstat.st_uid)) + return 0; + error("no lock set by %s for revision %s", getcaller(), num); + return -1; +} + + + + static char const * +getcurdate() +/* Return a pointer to the current date. */ +{ + static char buffer[datesize]; /* date buffer */ + time_t t; + + if (!buffer[0]) { + t = time((time_t *)0); + if (t == -1) + faterror("time not available"); + time2date(t, buffer); + } + return buffer; +} + + static int +#if has_prototypes +fixwork(mode_t newworkmode, char const *mtime) + /* The `#if has_prototypes' is needed because mode_t might promote to int. */ +#else + fixwork(newworkmode, mtime) + mode_t newworkmode; + char const *mtime; +#endif +{ + int r; + return + 1 < workstat.st_nlink + || newworkmode&S_IWUSR && !myself(workstat.st_uid) + ? -1 + : + workstat.st_mode != newworkmode + && + (r = +# if has_fchmod + fchmod(Ifileno(workptr), newworkmode) +# else + chmod(workfilename, newworkmode) +# endif + ) != 0 + ? r + : + setfiledate(workfilename, mtime); +} + + static int +xpandfile(unexfile, dir, delta, exfilename) + RILE *unexfile; + char const *dir; + struct hshentry const *delta; + char const **exfilename; +/* + * Read unexfile and copy it to a + * file in dir, performing keyword substitution with data from delta. + * Return -1 if unsuccessful, 1 if expansion occurred, 0 otherwise. + * If successful, stores the stream descriptor into *EXFILEP + * and its name into *EXFILENAME. + */ +{ + char const *targetfname; + int e, r; + + targetfname = makedirtemp(dir, 1); + if (!(exfile = fopen(targetfname, FOPEN_W_WORK))) { + eerror(targetfname); + error("can't expand working file"); + return -1; + } + r = 0; + if (Expand == OLD_EXPAND) + fastcopy(unexfile,exfile); + else { + for (;;) { + e = expandline(unexfile,exfile,delta,false,(FILE*)nil); + if (e < 0) + break; + r |= e; + if (e <= 1) + break; + } + } + *exfilename = targetfname; + aflush(exfile); + return r & 1; +} + + + + +/* --------------------- G E T L O G M S G --------------------------------*/ + + + static struct cbuf +getlogmsg() +/* Obtain and yield a log message. + * If a log message is given with -m, yield that message. + * If this is the initial revision, yield a standard log message. + * Otherwise, reads a character string from the terminal. + * Stops after reading EOF or a single '.' on a + * line. getlogmsg prompts the first time it is called for the + * log message; during all later calls it asks whether the previous + * log message can be reused. + */ +{ + static char const + emptych[] = EMPTYLOG, + initialch[] = "Initial revision"; + static struct cbuf const + emptylog = { emptych, sizeof(emptych)-sizeof(char) }, + initiallog = { initialch, sizeof(initialch)-sizeof(char) }; + static struct buf logbuf; + static struct cbuf logmsg; + + register char *tp; + register size_t i; + char const *caller; + + if (msg.size) return msg; + + if (keepflag) { + /* generate std. log message */ + caller = getcaller(); + i = sizeof(ciklog)+strlen(caller)+3; + bufalloc(&logbuf, i+datesize); + tp = logbuf.string; + VOID sprintf(tp, "%s%s at ", ciklog, caller); + VOID date2str(getcurdate(), tp+i); + logmsg.string = tp; + logmsg.size = strlen(tp); + return logmsg; + } + + if (!targetdelta && ( + cmpnum(newdelnum.string,"1.1")==0 || + cmpnum(newdelnum.string,"1.0")==0 + )) + return initiallog; + + if (logmsg.size) { + /*previous log available*/ + if (yesorno(true, "reuse log message of previous file? [yn](y): ")) + return logmsg; + } + + /* now read string from stdin */ + logmsg = getsstdin("m", "log message", "", &logbuf); + + /* now check whether the log message is not empty */ + if (logmsg.size) + return logmsg; + return emptylog; +} + +/* Make a linked list of Symbolic names */ + + static void +addassoclst(flag, sp) +int flag; +char * sp; +{ + struct Symrev *pt; + + pt = talloc(struct Symrev); + pt->ssymbol = sp; + pt->override = flag; + pt->nextsym = nil; + if (lastassoc) + lastassoc->nextsym = pt; + else + assoclst = pt; + lastassoc = pt; + return; +} diff --git a/gnu/usr.bin/rcs/co/Makefile b/gnu/usr.bin/rcs/co/Makefile new file mode 100644 index 0000000000..e9de8da3c0 --- /dev/null +++ b/gnu/usr.bin/rcs/co/Makefile @@ -0,0 +1,7 @@ +PROG= co + +SRCS= co.c +LDADD= -L${.CURDIR}/../lib/obj -lrcs +CFLAGS+= -I${.CURDIR}/../lib + +.include diff --git a/gnu/usr.bin/rcs/co/co.1 b/gnu/usr.bin/rcs/co/co.1 new file mode 100644 index 0000000000..d9ce65e3d1 --- /dev/null +++ b/gnu/usr.bin/rcs/co/co.1 @@ -0,0 +1,569 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: co.1,v 5.7 1991/08/19 03:13:55 eggert Exp $ +.ds g \&\s-1UTC\s0 +.ds r \&\s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.TH CO 1 \*(Dt GNU +.SH NAME +co \- check out RCS revisions +.SH SYNOPSIS +.B co +.RI [ options ] " file " .\|.\|. +.SH DESCRIPTION +.B co +retrieves a revision from each \*r file and stores it into +the corresponding working file. +.PP +Pathnames matching an \*r suffix denote \*r files; +all others denote working files. +Names are paired as explained in +.BR ci (1). +.PP +Revisions of an \*r file may be checked out locked or unlocked. Locking a +revision prevents overlapping updates. A revision checked out for reading or +processing (e.g., compiling) need not be locked. A revision checked out +for editing and later checkin must normally be locked. Checkout with locking +fails if the revision to be checked out is currently locked by another user. +(A lock may be broken with +.BR rcs "(1).)\ \&" +Checkout with locking also requires the caller to be on the access list of +the \*r file, unless he is the owner of the +file or the superuser, or the access list is empty. +Checkout without locking is not subject to accesslist restrictions, and is +not affected by the presence of locks. +.PP +A revision is selected by options for revision or branch number, +checkin date/time, author, or state. +When the selection options +are applied in combination, +.B co +retrieves the latest revision +that satisfies all of them. +If none of the selection options +is specified, +.B co +retrieves the latest revision +on the default branch (normally the trunk, see the +.B \-b +option of +.BR rcs (1)). +A revision or branch number may be attached +to any of the options +.BR \-f , +.BR \-I , +.BR \-l , +.BR \-M , +.BR \-p , +.BR \-q , +.BR \-r , +or +.BR \-u . +The options +.B \-d +(date), +.B \-s +(state), and +.B \-w +(author) +retrieve from a single branch, the +.I selected +branch, +which is either specified by one of +.BR \-f, +\&.\|.\|., +.BR \-u , +or the default branch. +.PP +A +.B co +command applied to an \*r +file with no revisions creates a zero-length working file. +.B co +always performs keyword substitution (see below). +.SH OPTIONS +.TP +.BR \-r [\f2rev\fP] +retrieves the latest revision whose number is less than or equal to +.I rev. +If +.I rev +indicates a branch rather than a revision, +the latest revision on that branch is retrieved. +If +.I rev +is omitted, the latest revision on the default branch +(see the +.B \-b +option of +.BR rcs (1)) +is retrieved. +If +.I rev +is +.BR $ , +.B co +determines the revision number from keyword values in the working file. +Otherwise, a revision is composed of one or more numeric or symbolic fields +separated by periods. The numeric equivalent of a symbolic field +is specified with the +.B \-n +option of the commands +.BR ci (1) +and +.BR rcs (1). +.TP +.BR \-l [\f2rev\fP] +same as +.BR \-r , +except that it also locks the retrieved revision for +the caller. +.TP +.BR \-u [\f2rev\fP] +same as +.BR \-r , +except that it unlocks the retrieved revision if it was +locked by the caller. If +.I rev +is omitted, +.B \-u +retrieves the revision locked by the caller, if there is one; otherwise, +it retrieves the latest revision on the default branch. +.TP +.BR \-f [\f2rev\fP] +forces the overwriting of the working file; +useful in connection with +.BR \-q . +See also +.SM "FILE MODES" +below. +.TP +.B \-kkv +Generate keyword strings using the default form, e.g.\& +.B "$\&Revision: \*(Rv $" +for the +.B Revision +keyword. +A locker's name is inserted in the value of the +.BR Header , +.BR Id , +and +.B Locker +keyword strings +only as a file is being locked, +i.e. by +.B "ci\ \-l" +and +.BR "co\ \-l". +This is the default. +.TP +.B \-kkvl +Like +.BR \-kkv , +except that a locker's name is always inserted +if the given revision is currently locked. +.TP +.BR \-kk +Generate only keyword names in keyword strings; omit their values. +See +.SM "KEYWORD SUBSTITUTION" +below. +For example, for the +.B Revision +keyword, generate the string +.B $\&Revision$ +instead of +.BR "$\&Revision: \*(Rv $". +This option is useful to ignore differences due to keyword substitution +when comparing different revisions of a file. +.TP +.BR \-ko +Generate the old keyword string, +present in the working file just before it was checked in. +For example, for the +.B Revision +keyword, generate the string +.B "$\&Revision: 1.1 $" +instead of +.B "$\&Revision: \*(Rv $" +if that is how the string appeared when the file was checked in. +This can be useful for binary file formats +that cannot tolerate any changes to substrings +that happen to take the form of keyword strings. +.TP +.BR \-kv +Generate only keyword values for keyword strings. +For example, for the +.B Revision +keyword, generate the string +.B \*(Rv +instead of +.BR "$\&Revision: \*(Rv $". +This can help generate files in programming languages where it is hard to +strip keyword delimiters like +.B "$\&Revision:\ $" +from a string. +However, further keyword substitution cannot be performed once the +keyword names are removed, so this option should be used with care. +Because of this danger of losing keywords, +this option cannot be combined with +.BR \-l , +and the owner write permission of the working file is turned off; +to edit the file later, check it out again without +.BR \-kv . +.TP +.BR \-p [\f2rev\fP] +prints the retrieved revision on the standard output rather than storing it +in the working file. +This option is useful when +.B co +is part of a pipe. +.TP +.BR \-q [\f2rev\fP] +quiet mode; diagnostics are not printed. +.TP +.BR \-I [\f2rev\fP] +interactive mode; +the user is prompted and questioned +even if the standard input is not a terminal. +.TP +.BI \-d date +retrieves the latest revision on the selected branch whose checkin date/time is +less than or equal to +.I date. +The date and time may be given in free format. +The time zone +.B LT +stands for local time; +other common time zone names are understood. +For example, the following +.IR date s +are equivalent +if local time is January 11, 1990, 8pm Pacific Standard Time, +eight hours west of Coordinated Universal Time (\*g): +.RS +.LP +.RS +.nf +.ta \w'\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP 'u +.ne 9 +\f38:00 pm lt\fP +\f34:00 AM, Jan. 12, 1990\fP note: default is \*g +\f31990/01/12 04:00:00\fP \*r date format +\f3Thu Jan 11 20:00:00 1990 LT\fP output of \f3ctime\fP(3) + \f3LT\fP +\f3Thu Jan 11 20:00:00 PST 1990\fP output of \f3date\fP(1) +\f3Fri Jan 12 04:00:00 GMT 1990\fP +\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP +\f3Fri-JST, 1990, 1pm Jan 12\fP +\f312-January-1990, 04:00-WET\fP +.ta 4n +4n +4n +4n +.fi +.RE +.LP +Most fields in the date and time may be defaulted. +The default time zone is \*g. +The other defaults are determined in the order year, month, day, +hour, minute, and second (most to least significant). At least one of these +fields must be provided. For omitted fields that are of higher significance +than the highest provided field, the time zone's current values are assumed. +For all other omitted fields, +the lowest possible values are assumed. +For example, the date +.B "20, 10:30" +defaults to +10:30:00 \*g of the 20th of the \*g time zone's current month and year. +The date/time must be quoted if it contains spaces. +.RE +.TP +.BR \-M [\f2rev\fP] +Set the modification time on the new working file +to be the date of the retrieved revision. +Use this option with care; it can confuse +.BR make (1). +.TP +.BI \-s state +retrieves the latest revision on the selected branch whose state is set to +.I state. +.TP +.BR \-w [\f2login\fP] +retrieves the latest revision on the selected branch which was checked in +by the user with login name +.I login. +If the argument +.I login +is +omitted, the caller's login is assumed. +.TP +.BI \-j joinlist +generates a new revision which is the join of the revisions on +.I joinlist. +This option is largely obsoleted by +.BR rcsmerge (1) +but is retained for backwards compatibility. +.RS +.PP +The +.I joinlist +is a comma-separated list of pairs of the form +.IB rev2 : rev3, +where +.I rev2 +and +.I rev3 +are (symbolic or numeric) +revision numbers. +For the initial such pair, +.I rev1 +denotes the revision selected +by the above options +.BR \-f, +\&.\|.\|., +.BR \-w . +For all other pairs, +.I rev1 +denotes the revision generated by the previous pair. +(Thus, the output +of one join becomes the input to the next.) +.PP +For each pair, +.B co +joins revisions +.I rev1 +and +.I rev3 +with respect to +.I rev2. +This means that all changes that transform +.I rev2 +into +.I rev1 +are applied to a copy of +.I rev3. +This is particularly useful if +.I rev1 +and +.I rev3 +are the ends of two branches that have +.I rev2 +as a common ancestor. If +.IR rev1 < rev2 < rev3 +on the same branch, +joining generates a new revision which is like +.I rev3, +but with all changes that lead from +.I rev1 +to +.I rev2 +undone. +If changes from +.I rev2 +to +.I rev1 +overlap with changes from +.I rev2 +to +.I rev3, +.B co +reports overlaps as described in +.BR merge (1). +.PP +For the initial pair, +.I rev2 +may be omitted. The default is the common +ancestor. +If any of the arguments indicate branches, the latest revisions +on those branches are assumed. +The options +.B \-l +and +.B \-u +lock or unlock +.I rev1. +.RE +.TP +.BI \-V n +Emulate \*r version +.I n, +where +.I n +may be +.BR 3 , +.BR 4 , +or +.BR 5 . +This may be useful when interchanging \*r files with others who are +running older versions of \*r. +To see which version of \*r your correspondents are running, have them invoke +.B rlog +on an \*r file; +if none of the first few lines of output contain the string +.B branch: +it is version 3; +if the dates' years have just two digits, it is version 4; +otherwise, it is version 5. +An \*r file generated while emulating version 3 will lose its default branch. +An \*r revision generated while emulating version 4 or earlier will have +a timestamp that is off by up to 13 hours. +A revision extracted while emulating version 4 or earlier will contain +dates of the form +.IB yy / mm / dd +instead of +.IB yyyy / mm / dd +and may also contain different white space in the substitution for +.BR $\&Log$ . +.TP +.BI \-x "suffixes" +Use +.I suffixes +to characterize \*r files. +See +.BR ci (1) +for details. +.SH "KEYWORD SUBSTITUTION" +Strings of the form +.BI $ keyword $ +and +.BI $ keyword : .\|.\|. $ +embedded in +the text are replaced +with strings of the form +.BI $ keyword : value $ +where +.I keyword +and +.I value +are pairs listed below. +Keywords may be embedded in literal strings +or comments to identify a revision. +.PP +Initially, the user enters strings of the form +.BI $ keyword $ . +On checkout, +.B co +replaces these strings with strings of the form +.BI $ keyword : value $ . +If a revision containing strings of the latter form +is checked back in, the value fields will be replaced during the next +checkout. +Thus, the keyword values are automatically updated on checkout. +This automatic substitution can be modified by the +.B \-k +options. +.PP +Keywords and their corresponding values: +.TP +.B $\&Author$ +The login name of the user who checked in the revision. +.TP +.B $\&Date$ +The date and time (\*g) the revision was checked in. +.TP +.B $\&Header$ +A standard header containing the full pathname of the \*r file, the +revision number, the date (\*g), the author, the state, +and the locker (if locked). +.TP +.B $\&Id$ +Same as +.BR $\&Header$ , +except that the \*r filename is without a path. +.TP +.B $\&Locker$ +The login name of the user who locked the revision (empty if not locked). +.TP +.B $\&Log$ +The log message supplied during checkin, preceded by a header +containing the \*r filename, the revision number, the author, and the date +(\*g). +Existing log messages are +.I not +replaced. +Instead, the new log message is inserted after +.BR $\&Log: .\|.\|. $ . +This is useful for +accumulating a complete change log in a source file. +.TP +.B $\&RCSfile$ +The name of the \*r file without a path. +.TP +.B $\&Revision$ +The revision number assigned to the revision. +.TP +.B $\&Source$ +The full pathname of the \*r file. +.TP +.B $\&State$ +The state assigned to the revision with the +.B \-s +option of +.BR rcs (1) +or +.BR ci (1). +.SH "FILE MODES" +The working file inherits the read and execute permissions from the \*r +file. In addition, the owner write permission is turned on, unless +.B \-kv +is set or the file +is checked out unlocked and locking is set to strict (see +.BR rcs (1)). +.PP +If a file with the name of the working file exists already and has write +permission, +.B co +aborts the checkout, +asking beforehand if possible. +If the existing working file is +not writable or +.B \-f +is given, the working file is deleted without asking. +.SH FILES +.B co +accesses files much as +.BR ci (1) +does, except that it does not need to read the working file. +.SH ENVIRONMENT +.TP +.B \s-1RCSINIT\s0 +options prepended to the argument list, separated by spaces. +See +.BR ci (1) +for details. +.SH DIAGNOSTICS +The \*r pathname, the working pathname, +and the revision number retrieved are +written to the diagnostic output. +The exit status is zero if and only if all operations were successful. +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH "SEE ALSO" +ci(1), ctime(3), date(1), ident(1), make(1), +rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1), +rcsfile(5) +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. +.SH LIMITS +Links to the \*r and working files are not preserved. +.PP +There is no way to selectively suppress the expansion of keywords, except +by writing them differently. In nroff and troff, this is done by embedding the +null-character +.B \e& +into the keyword. +.SH BUGS +The +.B \-d +option sometimes gets confused, and accepts no date before 1970. +.br diff --git a/gnu/usr.bin/rcs/co/co.c b/gnu/usr.bin/rcs/co/co.c new file mode 100644 index 0000000000..9435574e7d --- /dev/null +++ b/gnu/usr.bin/rcs/co/co.c @@ -0,0 +1,769 @@ +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + +/* + * RCS checkout operation + */ +/***************************************************************************** + * check out revisions from RCS files + ***************************************************************************** + */ + + +/* $Log: co.c,v $ + * Revision 5.9 1991/10/07 17:32:46 eggert + * ci -u src/RCS/co.c,v src/co.c <<\. + * -k affects just working file, not RCS file. + * + * Revision 5.8 1991/08/19 03:13:55 eggert + * Warn before removing somebody else's file. + * Add -M. Fix co -j bugs. Tune. + * + * Revision 5.7 1991/04/21 11:58:15 eggert + * Ensure that working file is newer than RCS file after co -[lu]. + * Add -x, RCSINIT, MS-DOS support. + * + * Revision 5.6 1990/12/04 05:18:38 eggert + * Don't checkaccesslist() unless necessary. + * Use -I for prompts and -q for diagnostics. + * + * Revision 5.5 1990/11/01 05:03:26 eggert + * Fix -j. Add -I. + * + * Revision 5.4 1990/10/04 06:30:11 eggert + * Accumulate exit status across files. + * + * Revision 5.3 1990/09/11 02:41:09 eggert + * co -kv yields a readonly working file. + * + * Revision 5.2 1990/09/04 08:02:13 eggert + * Standardize yes-or-no procedure. + * + * Revision 5.0 1990/08/22 08:10:02 eggert + * Permit multiple locks by same user. Add setuid support. + * Remove compile-time limits; use malloc instead. + * Permit dates past 1999/12/31. Switch to GMT. + * Make lock and temp files faster and safer. + * Ansify and Posixate. Add -k, -V. Remove snooping. Tune. + * + * Revision 4.7 89/05/01 15:11:41 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.6 88/08/09 19:12:15 eggert + * Fix "co -d" core dump; rawdate wasn't always initialized. + * Use execv(), not system(); fix putchar('\0') and diagnose() botches; remove lint + * + * Revision 4.5 87/12/18 11:35:40 narten + * lint cleanups (from Guy Harris) + * + * Revision 4.4 87/10/18 10:20:53 narten + * Updating version numbers changes relative to 1.1, are actually + * relative to 4.2 + * + * Revision 1.3 87/09/24 13:58:30 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:21:38 jenkins + * Port to suns + * + * Revision 4.2 83/12/05 13:39:48 wft + * made rewriteflag external. + * + * Revision 4.1 83/05/10 16:52:55 wft + * Added option -u and -f. + * Added handling of default branch. + * Replaced getpwuid() with getcaller(). + * Removed calls to stat(); now done by pairfilenames(). + * Changed and renamed rmoldfile() to rmworkfile(). + * Replaced catchints() calls with restoreints(), unlink()--link() with rename(); + * + * Revision 3.7 83/02/15 15:27:07 wft + * Added call to fastcopy() to copy remainder of RCS file. + * + * Revision 3.6 83/01/15 14:37:50 wft + * Added ignoring of interrupts while RCS file is renamed; this avoids + * deletion of RCS files during the unlink/link window. + * + * Revision 3.5 82/12/08 21:40:11 wft + * changed processing of -d to use DATEFORM; removed actual from + * call to preparejoin; re-fixed printing of done at the end. + * + * Revision 3.4 82/12/04 18:40:00 wft + * Replaced getdelta() with gettree(), SNOOPDIR with SNOOPFILE. + * Fixed printing of "done". + * + * Revision 3.3 82/11/28 22:23:11 wft + * Replaced getlogin() with getpwuid(), flcose() with ffclose(), + * %02d with %.2d, mode generation for working file with WORKMODE. + * Fixed nil printing. Fixed -j combined with -l and -p, and exit + * for non-existing revisions in preparejoin(). + * + * Revision 3.2 82/10/18 20:47:21 wft + * Mode of working file is now maintained even for co -l, but write permission + * is removed. + * The working file inherits its mode from the RCS file, plus write permission + * for the owner. The write permission is not given if locking is strict and + * co does not lock. + * An existing working file without write permission is deleted automatically. + * Otherwise, co asks (empty answer: abort co). + * Call to getfullRCSname() added, check for write error added, call + * for getlogin() fixed. + * + * Revision 3.1 82/10/13 16:01:30 wft + * fixed type of variables receiving from getc() (char -> int). + * removed unused variables. + */ + + + + +#include "rcsbase.h" + +static char const *getancestor P((char const*,char const*)); +static int buildjoin P((char const*)); +static int preparejoin P((void)); +static int rmlock P((struct hshentry const*)); +static int rmworkfile P((void)); +static void cleanup P((void)); + +static char const quietarg[] = "-q"; + +static char const *expandarg, *join, *suffixarg, *versionarg; +static char const *joinlist[joinlength]; /* revisions to be joined */ +static FILE *neworkptr; +static int exitstatus; +static int forceflag; +static int lastjoin; /* index of last element in joinlist */ +static int lockflag; /* -1 -> unlock, 0 -> do nothing, 1 -> lock */ +static int mtimeflag; +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 $") +{ + static char const cmdusage[] = + "\nco usage: co -{flpqru}[rev] -ddate -jjoinlist -sstate -w[login] -Vn file ..."; + + char *a, **newargv; + char const *author, *date, *rev, *state; + char const *joinfilename, *newdate, *neworkfilename; + int changelock; /* 1 if a lock has been changed, -1 if error */ + int expmode, r, tostdout, workstatstat; + struct buf numericrev; /* expanded revision number */ + char finaldate[datesize]; + + setrid(); + author = date = rev = state = nil; + bufautobegin(&numericrev); + expmode = -1; + suffixes = X_DEFAULT; + tostdout = false; + + argc = getRCSINIT(argc, argv, &newargv); + argv = newargv; + while (a = *++argv, 0<--argc && *a++=='-') { + switch (*a++) { + + case 'r': + revno: + if (*a) { + if (rev) warn("redefinition of revision number"); + rev = a; + } + break; + + case 'f': + forceflag=true; + goto revno; + + case 'l': + if (lockflag < 0) { + warn("-l overrides -u."); + } + lockflag = 1; + goto revno; + + case 'u': + if (0 < lockflag) { + warn("-l overrides -u."); + } + lockflag = -1; + goto revno; + + case 'p': + tostdout = true; + goto revno; + + case 'I': + interactiveflag = true; + goto revno; + + case 'q': + quietflag=true; + goto revno; + + case 'd': + if (date) + redefined('d'); + str2date(a, finaldate); + date=finaldate; + break; + + case 'j': + if (*a) { + if (join) redefined('j'); + join = a; + } + break; + + case 'M': + mtimeflag = true; + goto revno; + + case 's': + if (*a) { + if (state) redefined('s'); + state = a; + } + break; + + case 'w': + if (author) redefined('w'); + if (*a) + author = a; + else + author = getcaller(); + break; + + case 'x': + suffixarg = *argv; + suffixes = a; + break; + + case 'V': + versionarg = *argv; + setRCSversion(versionarg); + break; + + case 'k': /* set keyword expand mode */ + expandarg = *argv; + if (0 <= expmode) redefined('k'); + if (0 <= (expmode = str2expmode(a))) + break; + /* fall into */ + default: + faterror("unknown option: %s%s", *argv, cmdusage); + + }; + } /* end of option processing */ + + if (argc<1) faterror("no input file%s", cmdusage); + if (tostdout) +# if text_equals_binary_stdio || text_work_stdio + workstdout = stdout; +# else + if (!(workstdout = fdopen(STDOUT_FILENO, FOPEN_W_WORK))) + efaterror("stdout"); +# endif + + /* now handle all filenames */ + do { + ffree(); + + if (pairfilenames(argc, argv, lockflag?rcswriteopen:rcsreadopen, true, false) <= 0) + continue; + + /* now RCSfilename contains the name of the RCS file, and finptr + * points at it. workfilename contains the name of the working file. + * Also, RCSstat has been set. + */ + diagnose("%s --> %s\n", RCSfilename,tostdout?"stdout":workfilename); + + workstatstat = -1; + if (tostdout) { + neworkfilename = 0; + neworkptr = workstdout; + } else { + workstatstat = stat(workfilename, &workstat); + neworkfilename = makedirtemp(workfilename, 1); + if (!(neworkptr = fopen(neworkfilename, FOPEN_W_WORK))) { + if (errno == EACCES) + error("%s: parent directory isn't writable", + workfilename + ); + else + eerror(neworkfilename); + continue; + } + } + + gettree(); /* reads in the delta tree */ + + if (Head==nil) { + /* no revisions; create empty file */ + diagnose("no revisions present; generating empty revision 0.0\n"); + Ozclose(&fcopy); + if (workstatstat == 0) + if (!rmworkfile()) continue; + changelock = 0; + newdate = 0; + /* Can't reserve a delta, so don't call addlock */ + } else { + if (rev!=nil) { + /* expand symbolic revision number */ + if (!expandsym(rev, &numericrev)) + continue; + } else + switch (lockflag<0 ? findlock(false,&targetdelta) : 0) { + default: + continue; + case 0: + bufscpy(&numericrev, Dbranch?Dbranch:""); + break; + case 1: + bufscpy(&numericrev, targetdelta->num); + break; + } + /* get numbers of deltas to be generated */ + if (!(targetdelta=genrevs(numericrev.string,date,author,state,&gendeltas))) + continue; + /* check reservations */ + changelock = + lockflag < 0 ? + rmlock(targetdelta) + : lockflag == 0 ? + 0 + : + addlock(targetdelta); + + if ( + changelock < 0 || + changelock && !checkaccesslist() || + !dorewrite(lockflag, changelock) + ) + continue; + + if (0 <= expmode) + Expand = expmode; + if (0 < lockflag && Expand == VAL_EXPAND) { + error("cannot combine -kv and -l"); + continue; + } + + if (join && !preparejoin()) continue; + + diagnose("revision %s%s\n",targetdelta->num, + 0first!=targetdelta, + finptr, MADV_SEQUENTIAL + ); + + if (!donerewrite(changelock)) + continue; + + newdate = targetdelta->date; + if (join) { + newdate = 0; + if (!joinfilename) { + aflush(neworkptr); + joinfilename = neworkfilename; + } + if (!buildjoin(joinfilename)) + continue; + } + } + if (!tostdout) { + r = 0; + if (mtimeflag && newdate) { + if (!join) + aflush(neworkptr); + r = setfiledate(neworkfilename, newdate); + } + if (r == 0) { + ignoreints(); + r = chnamemod(&neworkptr, neworkfilename, workfilename, + WORKMODE(RCSstat.st_mode, + !(Expand==VAL_EXPAND || lockflag<=0&&StrictLocks) + ) + ); + keepdirtemp(neworkfilename); + restoreints(); + } + if (r != 0) { + eerror(workfilename); + error("see %s", neworkfilename); + continue; + } + diagnose("done\n"); + } + } while (cleanup(), + ++argv, --argc >=1); + + tempunlink(); + Ofclose(workstdout); + exitmain(exitstatus); + +} /* end of main (co) */ + + static void +cleanup() +{ + if (nerror) exitstatus = EXIT_FAILURE; + Izclose(&finptr); + Ozclose(&frewrite); +# if !large_memory + if (fcopy!=workstdout) Ozclose(&fcopy); +# endif + if (neworkptr!=workstdout) Ozclose(&neworkptr); + dirtempunlink(); +} + +#if lint +# define exiterr coExit +#endif + exiting void +exiterr() +{ + dirtempunlink(); + tempunlink(); + _exit(EXIT_FAILURE); +} + + +/***************************************************************** + * The following routines are auxiliary routines + *****************************************************************/ + + static int +rmworkfile() +/* Function: prepares to remove workfilename, if it exists, and if + * it is read-only. + * Otherwise (file writable): + * if !quietmode asks the user whether to really delete it (default: fail); + * otherwise failure. + * Returns true if permission is gotten. + */ +{ + if (workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH) && !forceflag) { + /* File is writable */ + if (!yesorno(false, "writable %s exists%s; remove it? [ny](n): ", + workfilename, + myself(workstat.st_uid) ? "" : ", and you do not own it" + )) { + error(!quietflag && ttystdin() + ? "checkout aborted" + : "writable %s exists; checkout aborted", workfilename); + return false; + } + } + /* Actual unlink is done later by caller. */ + return true; +} + + + static int +rmlock(delta) + struct hshentry const *delta; +/* Function: removes the lock held by caller on delta. + * Returns -1 if someone else holds the lock, + * 0 if there is no lock on delta, + * and 1 if a lock was found and removed. + */ +{ register struct lock * next, * trail; + char const *num; + struct lock dummy; + int whomatch, nummatch; + + num=delta->num; + dummy.nextlock=next=Locks; + trail = &dummy; + while (next!=nil) { + whomatch = strcmp(getcaller(), next->login); + nummatch=strcmp(num,next->delta->num); + if ((whomatch==0) && (nummatch==0)) break; + /*found a lock on delta by caller*/ + if ((whomatch!=0)&&(nummatch==0)) { + error("revision %s locked by %s; use co -r or rcs -u",num,next->login); + return -1; + } + trail=next; + next=next->nextlock; + } + if (next!=nil) { + /*found one; delete it */ + trail->nextlock=next->nextlock; + Locks=dummy.nextlock; + next->delta->lockedby=nil; /* reset locked-by */ + return 1; /*success*/ + } else return 0; /*no lock on delta*/ +} + + + + +/***************************************************************** + * The rest of the routines are for handling joins + *****************************************************************/ + + + static char const * +addjoin(joinrev) + char *joinrev; +/* Add joinrev's number to joinlist, yielding address of char past joinrev, + * or nil if no such revision exists. + */ +{ + register char *j; + register struct hshentry const *d; + char terminator; + struct buf numrev; + struct hshentries *joindeltas; + + j = joinrev; + for (;;) { + switch (*j++) { + default: + continue; + case 0: + case ' ': case '\t': case '\n': + case ':': case ',': case ';': + break; + } + break; + } + terminator = *--j; + *j = 0; + bufautobegin(&numrev); + d = 0; + if (expandsym(joinrev, &numrev)) + d = genrevs(numrev.string,(char*)nil,(char*)nil,(char*)nil,&joindeltas); + bufautoend(&numrev); + *j = terminator; + if (d) { + joinlist[++lastjoin] = d->num; + return j; + } + return nil; +} + + static int +preparejoin() +/* Function: Parses a join list pointed to by join and places pointers to the + * revision numbers into joinlist. + */ +{ + register char const *j; + + j=join; + lastjoin= -1; + for (;;) { + while ((*j==' ')||(*j=='\t')||(*j==',')) j++; + if (*j=='\0') break; + if (lastjoin>=joinlength-2) { + error("too many joins"); + return(false); + } + if (!(j = addjoin(j))) return false; + while ((*j==' ') || (*j=='\t')) j++; + if (*j == ':') { + j++; + while((*j==' ') || (*j=='\t')) j++; + if (*j!='\0') { + if (!(j = addjoin(j))) return false; + } else { + error("join pair incomplete"); + return false; + } + } else { + if (lastjoin==0) { /* first pair */ + /* common ancestor missing */ + joinlist[1]=joinlist[0]; + lastjoin=1; + /*derive common ancestor*/ + if (!(joinlist[0] = getancestor(targetdelta->num,joinlist[1]))) + return false; + } else { + error("join pair incomplete"); + return false; + } + } + } + if (lastjoin<1) { + error("empty join"); + return false; + } else return true; +} + + + + static char const * +getancestor(r1, r2) + char const *r1, *r2; +/* Yield the common ancestor of r1 and r2 if successful, nil otherwise. + * Work reliably only if r1 and r2 are not branch numbers. + */ +{ + static struct buf t1, t2; + + unsigned l1, l2, l3; + char const *r; + + l1 = countnumflds(r1); + l2 = countnumflds(r2); + if ((22 ? (unsigned)2 : l1); + VOID partialno(&t2, r2, l2>2 ? (unsigned)2 : l2); + r = cmpnum(t1.string,t2.string)<0 ? t1.string : t2.string; + if (cmpnum(r,r1)!=0 && cmpnum(r,r2)!=0) + return r; + } else if (cmpnumfld(r1, r2, l3+1)!=0) + return partialno(&t1,r1,l3); + } + error("common ancestor of %s and %s undefined", r1, r2); + return nil; +} + + + + static int +buildjoin(initialfile) + char const *initialfile; +/* Function: merge pairs of elements in joinlist into initialfile + * If workstdout is set, copy result to stdout. + * All unlinking of initialfile, rev2, and rev3 should be done by tempunlink(). + */ +{ + struct buf commarg; + struct buf subs; + char const *rev2, *rev3; + int i; + char const *cov[10], *mergev[12]; + char const **p; + + bufautobegin(&commarg); + bufautobegin(&subs); + rev2 = maketemp(0); + rev3 = maketemp(3); /* buildrevision() may use 1 and 2 */ + + cov[0] = nil; + /* cov[1] setup below */ + cov[2] = CO; + /* cov[3] setup below */ + p = &cov[4]; + if (expandarg) *p++ = expandarg; + if (suffixarg) *p++ = suffixarg; + if (versionarg) *p++ = versionarg; + *p++ = quietarg; + *p++ = RCSfilename; + *p = nil; + + mergev[0] = nil; + mergev[1] = nil; + mergev[2] = MERGE; + mergev[3] = mergev[5] = "-L"; + /* rest of mergev setup below */ + + i=0; + while (inum); + else { + bufscat(&subs, ","); + bufscat(&subs, joinlist[i-2]); + bufscat(&subs, ":"); + bufscat(&subs, joinlist[i-1]); + } + diagnose("revision %s\n",joinlist[i]); + bufscpy(&commarg, "-p"); + bufscat(&commarg, joinlist[i]); + cov[1] = rev2; + cov[3] = commarg.string; + if (runv(cov)) + goto badmerge; + diagnose("revision %s\n",joinlist[i+1]); + bufscpy(&commarg, "-p"); + bufscat(&commarg, joinlist[i+1]); + cov[1] = rev3; + cov[3] = commarg.string; + if (runv(cov)) + goto badmerge; + diagnose("merging...\n"); + mergev[4] = subs.string; + mergev[6] = joinlist[i+1]; + p = &mergev[7]; + if (quietflag) *p++ = quietarg; + if (lastjoin<=i+2 && workstdout) *p++ = "-p"; + *p++ = initialfile; + *p++ = rev2; + *p++ = rev3; + *p = nil; + switch (runv(mergev)) { + case DIFF_FAILURE: case DIFF_SUCCESS: + break; + default: + goto badmerge; + } + i=i+2; + } + bufautoend(&commarg); + bufautoend(&subs); + return true; + + badmerge: + nerror++; + bufautoend(&commarg); + bufautoend(&subs); + return false; +} diff --git a/gnu/usr.bin/rcs/doc/rcs.ms b/gnu/usr.bin/rcs/doc/rcs.ms new file mode 100644 index 0000000000..7b3f807726 --- /dev/null +++ b/gnu/usr.bin/rcs/doc/rcs.ms @@ -0,0 +1,1524 @@ +.\" Format this file with: +.\" pic file | tbl | troff -ms +.\" +.\" \*s stands for $, and avoids problems when this file is checked in. +.ds s $ +.\" PS and PE center pic diagrams. (The corresponding ms-macros may not.) +.de PS +.nr pE (\\n(.lu-\\$2u)/2u +.in +\\n(pEu +.ne \\$1u +.. +.de PE +.in -\\n(pEu +.. +.de D( +.DS +.nr VS 12p +.vs 12p +.I +.. +.de D) +.DE +.nr VS 18p +.vs 18p +.R +.. +.de Id +.ND \\$4 +.. +.Id $Id: rcs.ms,v 5.2 1991/01/03 10:57:28 eggert Exp $ +.RP +.TL +RCS\*-A System for Version Control +.sp +.AU +Walter F. Tichy +.AI +Department of Computer Sciences +Purdue University +West Lafayette, Indiana 47907 +.sp +.AB +An important problem in program development and maintenance is version control, +i.e., the task of keeping a software system consisting of many versions and +configurations well organized. +The Revision Control System (RCS) +is a software tool that assists with that task. +RCS manages revisions of text documents, in particular source programs, +documentation, and test data. +It automates the storing, retrieval, logging and identification of revisions, +and it provides selection mechanisms for composing configurations. +This paper introduces basic version control concepts and +discusses the practice of version control +using RCS. +For conserving space, RCS stores deltas, i.e., differences between +successive revisions. Several delta storage methods are discussed. +Usage statistics show that RCS's delta storage method is +space and time efficient. +The paper concludes with a detailed survey of version control tools. +.sp +\fBKeywords\fR: configuration management, history management, +version control, revisions, deltas. +.AE +.FS +An earlier version of this paper was published in +.I "Software\*-Practice & Experience" +.B 15 , +7 (July 1985), 637-654. +.FE +.nr VS 18p +.LP +.NH +Introduction +.PP +Version control is the task of keeping software +systems consisting of many versions and configurations well organized. +The Revision Control System (RCS) is a set of UNIX +commands that assist with that task. +.PP +RCS' primary function is to manage \fIrevision groups\fR. +A revision group is a set of text documents, called \fIrevisions\fR, +that evolved from each other. A new revision is +created by manually editing an existing one. +RCS organizes the revisions into an ancestral tree. The initial revision +is the root of the tree, and the tree edges indicate +from which revision a given one evolved. +Besides managing individual revision groups, RCS provides +flexible selection functions for composing configurations. +RCS may be combined with MAKE\u1\d, +resulting in a powerful package for version control. +.PP +RCS also offers facilities for +merging updates with customer modifications, +for distributed software development, and +for automatic identification. +Identification is the `stamping' +of revisions and configurations with unique markers. +These markers are akin to serial numbers, +telling software maintainers unambiguously which configuration +is before them. +.PP +RCS is designed for both production and experimental +environments. +In production environments, +access controls detect update conflicts and prevent overlapping changes. +In experimental environments, where strong controls are +counterproductive, it is possible to loosen the controls. +.PP +Although RCS was originally intended for programs, it is useful for any +text that is revised frequently and whose previous revisions must be +preserved. RCS has been applied successfully to store the source +text for drawings, VLSI layouts, documentation, specifications, +test data, form letters and articles. +.PP +This paper discusses the practice of +version control using RCS. +It also introduces basic version control concepts, +useful for clarifying current practice and designing similar systems. +Revision groups of individual components are treated in the next three sections, +and the extensions to configurations follow. +Because of its size, a survey of version control tools +appears at the end of the paper. +.NH +Getting started with RCS +.PP +Suppose a text file \fIf.c\fR is to be placed under control of RCS. +Invoking the check-in command +.D( +ci f.c +.D) +creates a new revision group with the contents of +\fIf.c\fR as the initial +revision (numbered 1.1) +and stores the group into the file \fIf.c,v\fR. +Unless told otherwise, the command deletes \fIf.c\fR. +It also asks for a description of the group. +The description should state the common purpose of all revisions in the group, +and becomes part of the group's documentation. +All later check-in commands will ask for a log entry, +which should summarize the changes made. +(The first revision is assigned a default log message, +which just records the fact that it is the initial revision.) +.PP +Files ending in \fI,v\fR +are called \fIRCS files\fR (\fIv\fR stands for \fIv\fRersions); +the others are called working files. +To get back the working file \fIf.c\fR in the previous example, +execute the check-out command: +.D( +co f.c +.D) +.R +This command extracts the latest revision from +the revision group \fIf.c,v\fR and writes +it into \fIf.c\fR. +The file \fIf.c\fR can now be edited and, when finished, +checked back in with \fIci\fR: +.D( +ci f.c +.D) +\fICi\fR assigns number 1.2 to +the new revision. +If \fIci\fR complains with the message +.D( +ci error: no lock set by +.D) +then the system administrator has decided to configure RCS for a +production environment by enabling the `strict locking feature'. +If this feature is enabled, all RCS files are initialized +such that check-in operations require a lock on the previous revision +(the one from which the current one evolved). +Locking prevents overlapping modifications if several people work on the same file. +If locking is required, the revision should +have been locked during the check-out by using +the option \fI\-l\fR: +.D( +co \-l f.c +.D) +Of course it is too late now for the check-out with locking, because +\fIf.c\fR has already been changed; checking out the file again +would overwrite the modifications. +(To prevent accidental overwrites, \fIco\fR senses the presence +of a working file and asks whether the user really intended to overwrite it. +The overwriting check-out is sometimes useful for +backing up to the previous revision.) +To be able to proceed with the check-in in the present case, first execute +.D( +rcs \-l f.c +.D) +This command retroactively locks the latest revision, unless someone +else locked it in the meantime. In this case, the two programmers +involved have to negotiate whose +modifications should take precedence. +.PP +If an RCS file is private, i.e., if only the owner of the file is expected +to deposit revisions into it, the strict locking feature is unnecessary and +may be disabled. +If strict locking is disabled, +the owner of the RCS file need not have a lock for check-in. +For safety reasons, all others +still do. Turning strict locking off and on is done with the commands: +.D( +rcs \-U f.c \fRand\fP rcs \-L f.c +.D) +These commands enable or disable the strict locking feature for each RCS file +individually. +The system administrator only decides whether strict locking is +enabled initially. +.PP +To reduce the clutter in a working directory, all RCS files can be moved +to a subdirectory with the name \fIRCS\fR. +RCS commands look first into that directory for RCS files. +All the commands presented above work +with the \fIRCS\fR subdirectory without change.\(dg +.FS \(dg +Pairs of RCS and working files can actually be specified in 3 ways: +a) both are given, b) only the working file is given, c) only the +RCS file is given. +If a pair is given, both files may have arbitrary path prefixes; +RCS commands pair them up intelligently. +.FE +.PP +It may be undesirable that \fIci\fR deletes the working file. +For instance, sometimes one would like to save the current revision, +but continue editing. +Invoking +.D( +ci \-l f.c +.D) +checks in \fIf.c\fR as usual, but performs an additional +check-out with locking afterwards. Thus, the working file does +not disappear after the check-in. +Similarly, the option +\fI\-u\fR does a check-in followed by a check-out without +locking. This option is useful if the file is needed for compilation after the check-in. +Both options update the identification markers in the working file +(see below). +.PP +Besides the operations \fIci\fR and \fIco\fR, RCS provides the following +commands: +.sp 0 +.nr VS 12p +.vs 12p +.TS +tab(%); +li l. +ident%extract identification markers +rcs%change RCS file attributes +rcsclean%remove unchanged working files (optional) +rcsdiff%compare revisions +rcsfreeze%record a configuration (optional) +rcsmerge%merge revisions +rlog%read log messages and other information in RCS files +.TE +A synopsis of these commands appears in the Appendix. +.NH 2 +Automatic Identification +.PP +RCS can stamp source and object code with special identification strings, +similar to product and serial numbers. +To obtain such identification, place the marker +.D( +\*sId\*s +.D) +into the text of a revision, for instance inside a comment. +The check-out operation will replace this marker with a string of the form +.D( +\*sId: filename revisionnumber date time author state locker \*s +.D) +This string need never be touched, because \fIco\fR keeps it +up to date automatically. +To propagate the marker into object code, simply put +it into a literal character string. In C, this is done as follows: +.D( +static char rcsid[] = \&"\*sId\*s\&"; +.D) +The command \fIident\fR extracts such markers from any file, in particular from +object code. +\fIIdent\fR helps to find out +which revisions of which modules were used in a given program. +It returns a complete and unambiguous component list, +from which a copy of the program can be reconstructed. +This facility is invaluable for program maintenance. +.PP +There are several additional identification markers, one for each component +of \*sId\*s. +The marker +.D( +\*sLog\*s +.D) +has a similar function. It accumulates +the log messages that are requested during check-in. +Thus, one can maintain the complete history of a revision directly inside it, +by enclosing it in a comment. +Figure 1 is a partial reproduction of a log contained in revision 4.1 of +the file \fIci.c\fR. The log appears at the beginning of the file, +and makes it easy to determine what the recent modifications were. +.sp +.nr VS 12p +.vs 12p +.ne 18 +.nf +.in +0.5i +/* \*sLog: ci.c,v \*s + * Revision 4.1 1983/05/10 17:03:06 wft + * Added option \-d and \-w, and updated assignment of date, etc. to new delta. + * Added handling of default branches. + * + * Revision 3.9 1983/02/15 15:25:44 wft + * Added call to fastcopy() to copy remainder of RCS file. + * + * Revision 3.8 1983/01/14 15:34:05 wft + * Added ignoring of interrupts while new RCS file is renamed; + * avoids deletion of RCS files by interrupts. + * + * Revision 3.7 1982/12/10 16:09:20 wft + * Corrected checking of return code from diff. + * An RCS file now inherits its mode during the first ci from the working file, + * except that write permission is removed. + */ +.in 0 +.ce 1 +Figure 1. Log entries produced by the marker \*sLog\*s. +.fi +.nr VS 18p +.vs 18p +.sp 0 +.LP +Since revisions are stored in the form of differences, +each log message is +physically stored once, +independent of the number of revisions present. +Thus, the \*sLog\*s marker incurs negligible space overhead. +.NH +The RCS Revision Tree +.PP +RCS arranges revisions in an ancestral tree. +The \fIci\fR command builds this tree; the auxiliary command \fIrcs\fR +prunes it. +The tree has a root revision, normally numbered 1.1, and successive revisions +are numbered 1.2, 1.3, etc. The first field of a revision number +is called the \fIrelease number\fR and the second one +the \fIlevel number\fR. Unless given explicitly, +the \fIci\fR command assigns a new revision number +by incrementing the level number of the previous revision. +The release number must be incremented explicitly, using the +\fI\-r\fR option of \fIci\fR. +Assuming there are revisions 1.1, 1.2, and 1.3 in the RCS file f.c,v, the command +.D( +ci \-r2.1 f.c \fRor\fP ci \-r2 f.c +.D) +assigns the number 2.1 to the new revision. +Later check-ins without the \fI\-r\fR option will assign the numbers 2.2, 2.3, +and so on. +The release number should be incremented only at major transition points +in the development, for instance when a new release of a software product has +been completed. +.NH 2 +When are branches needed? +.PP +A young revision tree is slender: +It consists of only one branch, called the trunk. +As the tree ages, side branches may form. +Branches are needed in the following 4 situations. +.IP "\fITemporary fixes\fR" +.sp 0 +Suppose a tree has 5 revisions grouped in 2 releases, +as illustrated in Figure 2. +Revision 1.3, the last one of release 1, is in operation at customer sites, +while release 2 is in active development. +.ne 4 +.PS 4i +.ps -2 +box "1.1" +arrow +box "1.2" +arrow +box "1.3" +arrow +box "2.1" +arrow +box "2.2" +arrow dashed +.ps +2 +.PE +.ce 1 +Figure 2. A slender revision tree. +.sp 0 +Now imagine a customer requesting a fix of +a problem in revision 1.3, although actual development has moved on +to release 2. RCS does not permit an extra +revision to be spliced in between 1.3 and 2.1, since that would not reflect +the actual development history. Instead, create a branch +at revision 1.3, and check in the fix on that branch. +The first branch starting at 1.3 has number 1.3.1, and +the revisions on that branch are numbered 1.3.1.1, 1.3.1.2, etc. +The double numbering is needed to allow for another +branch at 1.3, say 1.3.2. +Revisions on the second branch would be numbered +1.3.2.1, 1.3.2.2, and so on. +The following steps create +branch 1.3.1 and add revision 1.3.1.1: +.sp 0 +.I +.nr VS 12p +.vs 12p +.TS +tab(%); +l l l. + %co \-r1.3 f.c% \*- check out revision 1.3 + %edit f.c% \*- change it + %ci \-r1.3.1 f.c% \*- check it in on branch 1.3.1 +.TE +.nr VS 18p +.vs 18p +.R +This sequence of commands transforms the tree of Figure 2 into +the one in Figure 3. +Note that it may be necessary to incorporate the differences +between 1.3 and 1.3.1.1 +into a revision at level 2. The operation \fIrcsmerge\fR automates this +process (see the Appendix). +.ne 7 +.PS 4i +.ps -2 + box "1.1" + arrow + box "1.2" + arrow +R13: box "1.3" + arrow +R21: box "2.1" + arrow +R22: box "2.2" + arrow dashed + line invis down from R21.s +RB1: box "1.3.1.1" + arrow dashed right from RB1.e + arrow from R13.s to RB1.w +.ps +2 +.PE +.ce 1 +Figure 3. A revision tree with one side branch +.sp +.IP "\fIDistributed development and customer modifications\fR" +.sp 0 +Assume a situation as in Figure 2, where revision 1.3 is in operation +at several customer sites, +while release 2 is in development. +Customer sites should use RCS to store the distributed software. +However, customer modifications should not be placed on the same branch +as the distributed source; instead, they should be placed on a side branch. +When the next software distribution arrives, +it should be appended to the trunk of +the customer's RCS file, and the customer +can then merge the local modifications back into the new release. +In the above example, a +customer's RCS file would contain the following tree, assuming +that the customer has received revision 1.3, added his local modifications +as revision 1.3.1.1, then received revision 2.4, and merged +2.4 and 1.3.1.1, resulting in 2.4.1.1. +.ne 7 +.PS 4i +.ps -2 +R13: box "1.3" + line invis +R21: box invis + line invis +R22: box invis + line invis +R24: box "2.4" + line invis +R25: box invis + line invis + arrow from R13.e to R24.w + line invis down from R21.s +RB1: box "1.3.1.1" + arrow from R13.s to RB1.w + right + line invis down from R25.s +RB2: box "2.4.1.1" + arrow from R24.s to RB2.w +.ps +2 +.PE +.ce 1 +Figure 4. A customer's revision tree with local modifications. +.sp 1 +This approach is actually practiced in the CSNET project, +where several universities and a company cooperate +in developing a national computer network. +.IP "\fIParallel development\fR" +.sp 0 +Sometimes it is desirable to explore an alternate design or +a different implementation technique in parallel with the +main line development. Such development +should be carried out on a side branch. +The experimental changes may later be moved into the main line, or abandoned. +.IP "\fIConflicting updates\fR" +.sp 0 +A common occurrence is that one programmer +has checked out a revision, but cannot complete the assignment +for some reason. In the meantime, another person +must perform another modification +immediately. In that case, the second person should check-out the same revision, +modify it, and check it in on a side branch, for later merging. +.PP +Every node in a revision tree consists of the following attributes: +a revision number, a check-in date and time, the author's identification, +a log entry, a state and the actual text. All these attributes +are determined at the time the revision is checked in. +The state attribute indicates the status of a revision. +It is set automatically to `experimental' during check-in. +A revision can later be promoted to a higher status, for example +`stable' or `released'. The set of states is user-defined. +.NH 2 +Revisions are represented as deltas +.PP +For conserving space, RCS stores revisions in the form +of deltas, i.e., as differences between revisions. +The user interface completely hides this fact. +.PP +A delta is a sequence of edit commands that transforms one string +into another. The deltas employed by RCS are line-based, which means +that the only edit commands allowed are insertion and deletion of lines. +If a single character in a line is changed, the +edit scripts consider the entire line changed. +The program \fIdiff\fR\u2\d +produces a small, line-based delta between pairs of text files. +A character-based edit script would take much longer to compute, +and would not be significantly shorter. +.PP +Using deltas is a classical space-time tradeoff: deltas reduce the +space consumed, but increase access time. +However, a version control tool should impose as little delay +as possible on programmers. +Excessive delays discourage the use of version controls, +or induce programmers to take shortcuts that compromise system integrity. +To gain reasonably fast access time for both editing and compiling, +RCS arranges deltas in the following way. +The most recent revision on the trunk is stored intact. +All other revisions on the trunk are stored as reverse deltas. +A reverse delta describes how to go backward in the development history: +it produces the desired revision if applied to the successor of that revision. +This implementation has the advantage +that extraction of the latest revision is a simple and fast copy +operation. +Adding a new revision to the trunk is also fast: \fIci\fR simply +adds the new revision intact, replaces the previous +revision with a reverse delta, and keeps the rest of the old deltas. +Thus, \fIci\fR requires the computation +of only one new delta. +.PP +Branches need special treatment. The naive solution would be to +store complete copies for the tips of all branches. +Clearly, this approach would cost too much space. Instead, +RCS uses \fIforward\fR deltas for branches. Regenerating a revision +on a side branch proceeds as follows. First, extract the latest revision +on the trunk; secondly, apply reverse deltas until the fork revision for +the branch is obtained; thirdly, apply forward deltas until the desired +branch revision is reached. Figure 5 illustrates a tree with +one side branch. Triangles pointing to the left and right represent +reverse and forward deltas, respectively. +.ne 8 +.PS 4i +.ps -2 +define BD X [line invis $1 right .5; +line up .3 then left .5 down .3 then right .5 down .3 then up .3] X + +define FD X [line invis $1 right .5; +line left .5 down .3 then up .6 then right .5 down .3;] X + +right +D11: BD(" 1.1") + arrow right from D11.e +D12: BD(" 1.2") + arrow right from D12.e +D13: BD(" 1.3") + arrow right from D13.e +D21: BD(" 2.1") + arrow right from D21.e +D22: box "2.2" + line invis down from D21.s +F1: FD("1.3.1.1 ") + arrow from D13.se to F1.w + arrow from F1.e right + right +F2: FD("1.3.1.2 ") +.ps +2 +.PE +.ce 1 +Figure 5. A revision tree with reverse and forward deltas. +.sp 0 +.PP +Although implementing fast check-out for the latest trunk revision, +this arrangement has the disadvantage that generation of other revisions +takes time proportional to the number of deltas applied. For example, +regenerating the branch tip in Figure 5 requires application of five +deltas (including the initial one). Since usage statistics show that +the latest trunk revision is the one that is retrieved in 95 per cent +of all cases (see the section on usage statistics), biasing check-out time +in favor of that revision results in significant savings. +However, careful implementation of the delta application process is +necessary to provide low retrieval overhead for other revisions, in +particular for branch tips. +.PP +There are several techniques for delta application. +The naive one is to pass each delta to a general-purpose text editor. +A prototype of RCS invoked the UNIX editor \fIed\fR both +for applying deltas and for expanding the identification markers. +Although easy to implement, performance was poor, owing to the +high start-up costs and excess generality of \fIed\fR. An intermediate +version of RCS used a special-purpose, stream-oriented editor. +This technique reduced the cost of applying a delta to the cost of +checking out the latest trunk revision. The reason for this behavior +is that each delta application involves a complete pass over +the preceding revision. +.PP +However, there is a much better algorithm. Note that the deltas are +line oriented and that most of the work of a stream editor involves +copying unchanged lines from one revision to the next. A faster +algorithm avoids unnecessary copying of character strings by using +a \fIpiece table\fR. +A piece table is a one-dimensional array, specifying how a given +revision is `pieced together' from lines in the RCS file. +Suppose piece table \fIPT\dr\u\fR represents revision \fIr\fR. +Then \fIPT\dr\u[i]\fR contains the starting position of line \fIi\fR +of revision \fIr\fR. +Application of the next delta transforms piece table \fIPT\dr\u\fR +into \fIPT\dr+1\u\fR. For instance, a delete command removes a +series of entries from the piece table. An insertion command inserts +new entries, moving the entries following the insertion point further down the +array. The inserted entries point to the text lines in the delta. +Thus, no I/O is involved except for reading the delta itself. When all +deltas have been applied to the piece table, a sequential pass +through the table looks up each line in the RCS file and copies it to +the output file, updating identification markers at the same time. +Of course, the RCS file must permit random access, since the copied +lines are scattered throughout that file. Figure 6 illustrates an +RCS file with two revisions and the corresponding piece tables. +.ne 13 +.sp 6 +.ce 1 +\fIFigure 6 is not available.\fP +.sp 5 +.ce 1 +Figure 6. An RCS file and its piece tables +.sp 0 +.PP +The piece table approach has the property that the time for applying a single +delta is roughly determined by the size of the delta, and not by the +size of the revision. For example, if a delta is +10 per cent of the size of a revision, then applying it takes only +10 per cent of the time to generate the latest trunk revision. (The stream +editor would take 100 per cent.) +.PP +There is an important alternative for representing deltas that affects +performance. SCCS\u3\d, +a precursor of RCS, uses \fIinterleaved\fR deltas. +A file containing interleaved deltas is partitioned into blocks of lines. +Each block has a header that specifies to which revision(s) the block +belongs. The blocks are sorted out in such a way that a single +pass over the file can pick up all the lines belonging to a given +revision. Thus, the regeneration time for all revisions is the same: +all headers must be inspected, and the associated blocks either copied +or skipped. As the number of revisions increases, the cost of retrieving +any revision is much higher than the cost of checking out the +latest trunk revision with reverse deltas. A detailed comparison +of SCCS's interleaved deltas and RCS's reverse deltas can be found +in Reference 4. +This reference considers the version of RCS with the +stream editor only. The piece table method improves performance +further, so that RCS is always faster than SCCS, except if 10 +or more deltas are applied. +.PP +Additional speed-up for both delta methods can be obtained by caching +the most recently generated revision, as has been implemented in DSEE.\u5\d +With caching, access time to frequently used revisions can approach normal file +access time, at the cost of some additional space. +.NH +Locking: A Controversial Issue +.PP +The locking mechanism for RCS was difficult to design. +The problem and its solution are first presented in their `pure' form, +followed by a discussion of the complications +caused by `real-world' considerations. +.PP +RCS must prevent two or more persons from depositing competing changes of the +same revision. +Suppose two programmers check out revision 2.4 and +modify it. Programmer A checks in a revision before programmer B\&. +Unfortunately, programmer B has not seen A's +changes, so the effect is that A's changes are covered up by B's deposit. +A's changes are not lost since all revisions +are saved, but they are confined to a single revision.\(dd +.FS \(dd +Note that this problem is entirely different from the atomicity problem. +Atomicity means that +concurrent update operations on the same RCS file cannot be permitted, +because that may result in inconsistent data. +Atomic updates are essential (and implemented in RCS), +but do not solve the conflict discussed here. +.FE +.PP +This conflict is prevented in RCS by locking. +Whenever someone intends to edit a revision (as opposed +to reading or compiling it), the revision should be checked out +and locked, +using the \fI\-l\fR option on \fIco\fR. On subsequent check-in, +\fIci\fR tests the lock and then removes it. +At most one programmer at a time may +lock a particular revision, and only this programmer may check in +the succeeding revision. +Thus, while a revision is locked, it is the exclusive responsibility +of the locker. +.PP +An important maxim for software tools like RCS is that they must +not stand in the way of making progress with a project. +This consideration leads to several weakenings of the locking mechanism. +First of all, even if a revision is locked, it can +still be checked out. This is necessary if other people +wish to compile or inspect the locked revision +while the next one is in preparation. The only operations they +cannot do are to lock the revision or to check in the succeeding one. Secondly, +check-in operations on other branches in the RCS file are still possible; the +locking of one revision does not affect any other revision. +Thirdly, revisions are occasionally locked for a long period of time +because a programmer is absent or otherwise unable to complete +the assignment. If another programmer has to make a pressing change, +there are the following three alternatives for making progress: +a) find out who is holding the lock and ask that person to release it; +b) check out the locked revision, modify it, check it +in on a branch, and merge the changes later; +c) break the lock. Breaking a lock leaves a highly visible +trace, namely an electronic mail message that is sent automatically to the +holder of the lock, recording the breaker and a commentary requested from him. +Thus, breaking locks is tolerated under certain circumstances, +but will not go unnoticed. +Experience has shown that the automatic mail message attaches a high enough +stigma to lock breaking, +such that programmers break locks only in real emergencies, +or when a co-worker resigns and leaves locked revisions behind. +.PP +If an RCS file is private, i.e., when a programmer owns an RCS file +and does not expect anyone else to perform check-in operations, +locking is an unnecessary nuisance. +In this case, +the `strict locking feature' discussed earlier may be disabled, +provided that file protection +is set such that only the owner may write the RCS file. +This has the effect that only the owner can check-in revisions, +and that no lock is needed for doing so. +.PP +As added protection, +each RCS file contains an access list that specifies the users +who may execute update operations. If an access list is empty, +only normal UNIX file protection applies. Thus, the access list is +useful for restricting the set of people who would otherwise have update +permission. Just as with locking, the access list +has no effect on read-only operations such as \fIco\fR. This approach +is consistent with the UNIX philosophy of openness, which contributes +to a productive software development environment. +.NH +Configuration Management +.PP +The preceding sections described how RCS deals with revisions of individual +components; this section discusses how to handle configurations. +A configuration is a set of revisions, where each revision comes +from a different revision group, and the revisions are selected +according to a certain criterion. +For example, +in order to build a functioning compiler, the `right' +revisions from the scanner, the parser, the optimizer +and the code generator must be combined. +RCS, in conjunction with MAKE, +provides a number of facilities to effect a smooth selection. +.NH 2 +RCS Selection Functions +.PP +.IP "\fIDefault selection\fR" +.sp 0 +During development, the usual selection criterion is to choose +the latest revision of all components. The \fIco\fR command +makes this selection by default. For example, the command +.D( +co *,v +.D) +retrieves the latest revision on the default branch of each RCS file +in the current directory. +The default branch is usually the trunk, but may be +set to be a side branch. +Side branches as defaults are needed in distributed software development, +as discussed in the section on the RCS revision tree. +.sp +.IP "\fIRelease based selection\fR" +.sp 0 +Specifying a release or branch number selects the latest revision in +that release or branch. +For instance, +.D( +co \-r2 *,v +.D) +retrieves the latest revision with release number 2 from each RCS file. +This selection is convenient if a release has been completed and +development has moved on to the next release. +.sp +.IP "\fIState and author based selection\fR" +.sp 0 +If the highest level number within a given release number +is not the desired one, +the state attribute can help. For example, +.D( +co \-r2 \-sReleased *,v +.D) +retrieves the latest revision with release number 2 whose state attribute +is `Released'. +Of course, the state attribute has to be set appropriately, using the +\fIci\fR or \fIrcs\fR commands. +Another alternative is to select a revision by its author, +using the \fI\-w\fR option. +.sp +.IP "\fIDate based selection\fR" +.sp 0 +Revisions may also be selected by date. +Suppose a release of an entire system was +completed and current on March 4, at 1:00 p.m. local time. Then the command +.D( +co \-d'March 4, 1:00 pm LT' *,v +.D) +checks out all the components of that release, independent of the numbering. +The \fI\-d\fR option specifies a `cutoff date', i.e., +the revision selected has a check-in date that +is closest to, but not after the date given. +.IP "\fIName based selection\fR" +.sp 0 +The most powerful selection function is based on assigning symbolic +names to revisions and branches. +In large systems, a single release number or date is not sufficient +to collect the appropriate revisions from all groups. +For example, suppose one wishes to combine release 2 +of one subsystem and release 15 of another. +Most likely, the creation dates of those releases differ also. +Thus, a single revision number or date passed to the \fIco\fR command +will not suffice to select the right revisions. +Symbolic revision numbers solve this problem. +Each RCS file may contain a set of symbolic names that are mapped +to numeric revision numbers. For example, assume +the symbol \fIV3\fR is bound to release number 2 in file \fIs,v\fR, and to +revision number 15.9 in \fIt,v\fR. +Then the single command +.D( +co \-rV3 s,v t,v +.D) +retrieves the latest revision of release 2 from \fIs,v\fR, +and revision 15.9 from \fIt,v\fR. +In a large system with many modules, checking out all +revisions with one command greatly simplifies configuration management. +.PP +Judicious use of symbolic revision numbers helps with organizing +large configurations. +A special command, \fIrcsfreeze\fR, +assigns a symbolic revision number to a selected revision +in every RCS file. +\fIRcsfreeze\fR effectively freezes a configuration. +The assigned symbolic revision number selects all components +of the configuration. +If necessary, symbolic numbers +may even be intermixed with numeric ones. Thus, \fIV3.5\fR in the +above example +would select revision 2.5 in \fIs,v\fR and branch 15.9.5 in \fIt,v\fR. +.PP +The options \fI\-r\fR, \fI\-s\fR, \fI\-w\fR and \fI\-d\fR +may be combined. If a branch is given, the latest revision +on that branch satisfying all conditions is retrieved; +otherwise, the default branch is used. +.NH 2 +Combining MAKE and RCS +.PP +MAKE\u1\d +is a program that processes configurations. +It is driven by configuration specifications +recorded in a special file, called a `Makefile'. +MAKE avoids redundant processing steps +by comparing creation dates of source and processed objects. +For example, when instructed to compile all +modules of a given system, it only recompiles +those source modules that were changed +since they were processed last. +.PP +MAKE has been extended with an auto-checkout feature for RCS.* +.FS * +This auto-checkout extension is available only in some versions of MAKE, +e.g. GNU MAKE. +.FE +When a certain file to be processed is not present, +MAKE attempts a check-out operation. +If successful, MAKE performs the required processing, and then deletes +the checked out file to conserve space. +The selection parameters discussed above can be passed to MAKE +either as parameters, or directly embedded in the Makefile. +MAKE has also been extended to search the subdirectory named \fIRCS\fR +for needed files, rather than just the current working directory. +However, if a working file is present, MAKE totally ignores the corresponding +RCS file and uses the working file. +(In newer versions of MAKE distributed by AT&T and others, +auto-checkout can be +achieved with the rule DEFAULT, instead of a special extension of MAKE. +However, a file checked out by the rule DEFAULT +will not be deleted after processing. \fIRcsclean\fR can be +used for that purpose.) +.PP +With auto-checkout, RCS/MAKE can effect a selection rule +especially tuned for multi-person software development and maintenance. +In these situations, +programmers should obtain configurations that consist of +the revisions they have personally checked out plus the latest +checked in revision of all other revision groups. +This schema can be set up as follows. +.PP +Each programmer chooses a working directory +and places into it a symbolic link, named \fIRCS\fR, +to the directory containing the relevant RCS files. +The symbolic link makes sure that \fIco\fR and \fIci\fR +operations need only specify the working files, and that +the Makefile need not be changed. +The programmer then checks out the needed files and modifies them. +If MAKE is invoked, +it composes configurations by selecting those +revisions that are checked out, and the rest from the +subdirectory \fIRCS\fR. +The latter selection may be controlled by a symbolic +revision number or any of the other selection criteria. +If there are several programmers editing in separate working directories, +they are insulated from each other's changes until checking in their +modifications. +.PP +Similarly, a maintainer can recreate an older configuration +by starting to work in an empty working directory. +During the initial MAKE invocation, all revisions are selected from RCS files. +As the maintainer checks out files and modifies them, +a new configuration is gradually built up. +Every time MAKE is invoked, it substitutes the modified revisions +into the configuration being manipulated. +.PP +A final application of RCS is to use it for storing Makefiles. +Revision groups of Makefiles represent +multiple versions of configurations. +Whenever a configuration is baselined or distributed, +the best approach is to unambiguously fix +the configuration with a symbolic revision number by calling +\fIrcsfreeze\fR, +to embed that symbol into the Makefile, and to +check in the Makefile (using the same symbolic revision number). +With this approach, old configurations +can be regenerated easily and reliably. +.NH +Usage Statistics +.PP +The following usage statistics were collected on two DEC VAX-11/780 +computers of the Purdue Computer Science Department. Both machines +are mainly used for research purposes. Thus, the data +reflect an environment in which the majority of projects +involve prototyping and advanced software development, +but relatively little long-term maintenance. +.PP +For the first experiment, +the \fIci\fR and \fIco\fR operations were instrumented +to log the number of backward and forward deltas applied. +The data were collected during a 13 month period +from Dec. 1982 to Dec. 1983. +Table I summarizes the results. +.sp 0 +.nr VS 12p +.vs 12p +.TS +center,box,tab(#); +c|c|c|c|c s|c s +c|c|c|c|c s|c s +l|n|n|n|n n|n n. +Operation#Total#Total deltas#Mean deltas#Operations#Branch + #operations #applied#applied#with >1 delta#operations +_ +co # 7867# 9320#1.18#509#(6%)#203#(3%) +ci # 3468# 2207#0.64# 85#(2%)# 75#(2%) +ci & co#11335#11527#1.02#594#(5%)#278#(2%) +.TE +.ce 1 +Table I. Statistics for \fIco\fR and \fIci\fR operations. +.nr VS 18p +.vs 18p +.PP +The first two lines show statistics for check-out and check-in; +the third line shows the combination. +Recall that \fIci\fR performs an implicit check-out to obtain +a revision for computing the delta. +In all measures presented, the most recent revision (stored intact) +counts as one delta. The number of deltas applied represents +the number of passes necessary, where the first `pass' is a copying step. +.PP +Note that the check-out operation is executed more than +twice as frequently as the check-in operation. +The fourth column gives the mean number of deltas +applied in all three cases. +For \fIci\fR, the mean number of deltas applied is less +than one. +The reasons are that the initial check-in requires no delta at all, and that +the only time \fIci\fR requires more than one delta is for branches. +Column 5 shows the actual number of operations that applied more than one +delta. +The last column indicates that branches were not used often. +.PP +The last three columns demonstrate that the most recent trunk revision +is by far the most frequently accessed. +For RCS, check-out of +this revision is a simple copy operation, which is the absolute minimum +given the copy-semantics of \fIco\fR. +Access to older revisions and branches +is more common in non-academic environments, +yet even if access to older deltas were an order +of magnitude more frequent, +the combined average number of deltas applied would still be below 1.2. +Since RCS is faster than SCCS until up to 10 delta applications, +reverse deltas are clearly the method of choice. +.PP +The second experiment, conducted in March of 1984, +involved surveying the existing RCS files +on our two machines. The goal was to determine the mean number of +revisions per RCS file, as well as the space consumed by them. +Table II shows the results. (Tables I and II were produced at different +times and are unrelated.) +.sp 0 +.nr VS 12p +.vs 12p +.TS +center,box,tab(#); +c | c | c | c | c | c | c +c | c | c | c | c | c | c +l | n | n | n | n | n | n. + #Total RCS#Total#Mean#Mean size of#Mean size of#Overhead + #files#revisions#revisions#RCS files#revisions +_ +All files #8033#11133#1.39#6156#5585#1.10 +Files with#1477# 4578#3.10#8074#6041#1.34 +\(>= 2 deltas +.TE +.ce 1 +Table II. Statistics for RCS files. +.nr VS 18p +.vs 18p +.PP +The mean number of revisions per RCS file is 1.39. +Columns 5 and 6 show the mean sizes (in bytes) of an RCS file +and of the latest revision of each RCS file, respectively. +The `overhead' column contains the ratio of the mean sizes. +Assuming that all revisions in an RCS file are approximately the same size, +this ratio gives a measure of the space consumed by the extra revisions. +.PP +In our sample, over 80 per cent of the RCS files contained only a single revision. +The reason is that our +systems programmers routinely check in all source files +on the distribution tapes, even though they may never touch them again. +To get a better indication of how much space savings are possible +with deltas, all measures with those files +that contained 2 or more revisions were recomputed. Only for those files +is RCS necessary. +As shown in the second line, the average number of revisions for those files is +3.10, with an overhead of 1.34. This means that the extra 2.10 deltas +require 34 per cent extra space, or +16 per cent per extra revision. +Rochkind\u3\d +measured the space consumed by SCCS, and +reported an average of 5 revisions per group +and an overhead of 1.37 (or about 9 per cent per extra revision). +In a later paper, Glasser\u6\d +observed an average of 7 revisions per group in a single, large project, +but provided no overhead figure. +In his paper on DSEE\u5\d, +Leblang reported that delta storage combined with blank compression +results in an overhead of a mere 1\-2 per cent per revision. +Since leading blanks accounted for about 20 per cent of the surveyed Pascal +programs, a revision group with 5\-10 members was smaller +than a single cleartext copy. +.PP +The above observations demonstrate clearly that the space needed +for extra revisions is small. With delta storage, the luxury of +keeping multiple revisions online is certainly affordable. +In fact, introducing a system with delta storage may reduce +storage requirements, because programmers often save back-up copies +anyway. Since back-up copies are stored much more efficiently with deltas, +introducing a system such as RCS may +actually free a considerable amount of space. +.NH +Survey of Version Control Tools +.PP +The need to keep back-up copies of software arose when +programs and data were no longer stored on paper media, but were entered +from terminals and stored on disk. +Back-up copies are desirable for reliability, and many modern editors +automatically save a back-up copy for every file touched. +This strategy +is valuable for short-term back-ups, but not suitable for long-term +version control, since an existing back-up copy is overwritten whenever the +corresponding file is edited. +.PP +Tape archives are suitable for long-term, offline storage. +If all changed files are dumped on a back-up tape once per day, old revisions +remain accessible. However, tape archives are unsatisfactory +for version control in several ways. First, backing up the file +system every 24 hours does not capture intermediate revisions. +Secondly, the old revisions are not online, +and accessing them is tedious and time-consuming. +In particular, it is impractical to +compare several old revisions of a group, +because that may require mounting and searching several tapes. +Tape archives are important fail-safe tools in the +event of catastrophic disk failures or accidental deletions, +but they are ill-suited for version control. +Conversely, version control tools do not obviate the +need for tape archives. +.PP +A natural technique for keeping several old revisions online is +to never delete a file. +Editing a file +simply creates a new file with the same +name, but with a different sequence number. +This technique, available as an option in DEC's VMS operating system, +turns out to be inadequate for version control. +First, it is prohibitively expensive in terms of storage costs, +especially since no data compression techniques are employed. +Secondly, indiscriminately storing every change produces too many +revisions, and programmers have difficulties distinguishing them. +The proliferation of revisions forces programmers to spend much time on +finding and deleting useless files. +Thirdly, most of the support functions like locking, logging, +revision selection, +and identification described in this paper are not available. +.PP +An alternative approach is to separate editing from revision control. +The user may repeatedly edit a given revision, +until freezing it with an explicit command. +Once a revision is frozen, it is stored permanently and can no longer be modified. +(In RCS, freezing a revisions is done with \fIci\fR.) +Editing a frozen revision implicitly creates a new one, which +can again be changed repeatedly until it is frozen itself. +This approach saves exactly those revisions that the user +considers important, and keeps the number of revisions manageable. +IBM's CLEAR/CASTER\u7\d, +AT&T's SCCS\u3\d, +CMU's SDC\u8\d +and DEC's CMS\u9\d, +are examples of version control systems using this approach. +CLEAR/CASTER maintains a data base of programs, specifications, +documentation and messages, using deltas. +Its goal is to provide control over the development process from a +management viewpoint. +SCCS stores multiple revisions of source text in an ancestral tree, +records a log entry for each revision, +provides access control, and has facilities +for uniquely identifying each revision. +An efficient delta technique +reduces the space consumed by each revision group. +SDC is much simpler than SCCS because it stores not more than +two revisions. However, it maintains a complete log for all old +revisions, some of which may be on back-up tape. +CMS, like SCCS, manages tree-structured revision groups, +but offers no identification mechanism. +.PP +Tools for dealing with configurations are still in a state of flux. +SCCS, SDC and CMS can be combined with MAKE or MAKE-like programs. +Since flexible selection rules are missing from all these tools, +it is sometimes difficult +to specify precisely which revision of each group +should be passed to MAKE for building a desired configuration. +The Xerox Cedar system\u10\d +provides a `System Modeller' that can rebuild +a configuration from an arbitrary set of module revisions. +The revisions of a module are only distinguished by creation time, +and there is no tool for managing groups. +Since the selection rules are primitive, +the System Modeller appears to be somewhat tedious to use. +Apollo's DSEE\u5\d +is a sophisticated software engineering environment. +It manages revision groups in a way similar to SCCS and CMS. Configurations +are built using `configuration threads'. +A configuration thread states which revision of each group +named in a configuration should be chosen. +A configuration thread may contain dynamic specifiers +(e.g., `choose the revisions I am currently working on, +and the most recent revisions otherwise'), which are bound +automatically at build time. +It also provides a notification mechanism for alerting +maintainers about the need to rebuild a system after a change. +.PP +RCS is based on a general model for describing +multi-version/multi-configuration systems\u11\d. +The model describes systems using AND/OR graphs, where AND nodes represent +configurations, and OR nodes represent version groups. +The model gives rise to a suit of selection rules for +composing configurations, almost all of which are implemented in RCS. +The revisions selected by RCS are passed to MAKE for configuration building. +Revision group management is modelled after SCCS. +RCS retains SCCS's best features, +but offers a significantly simpler user interface, +flexible selection rules, adequate integration with MAKE +and improved identification. +A detailed comparison of RCS and SCCS appears in Reference 4. +.PP +An important component of all revision control systems +is a program for computing deltas. +SCCS and RCS use the program \fIdiff\fR\u2\d, +which first computes the longest common substring of two +revisions, and then produces the delta from that substring. +The delta is simply an edit script consisting of deletion and +insertion commands that generate one revision from the other. +.PP +A delta based on a longest common substring is not necessarily minimal, +because it does not take advantage of crossing block moves. +Crossing block moves arise if two or more blocks of lines +(e.g., procedures) +appear in a different order in two revisions. +An edit script derived from a longest common substring +first deletes the shorter of the two blocks, and then reinserts it. +Heckel\u12\d +proposed an algorithm for detecting block moves, but +since the algorithm is based on heuristics, +there are conditions +under which the generated delta is far from minimal. +DSEE uses this algorithm combined with blank compression, +apparently with satisfactory overall results. +A new algorithm that is guaranteed to produce a minimal delta based on +block moves appears in Reference 13. +A future release of RCS will use this algorithm. +.PP +\fIAcknowledgements\fR: +Many people have helped make RCS a success by contributed criticisms, suggestions, +corrections, and even whole new commands (including manual pages). +The list of people is too long to be +reproduced here, but my sincere thanks for their help and +goodwill goes to all of them. +.sp +.nr VS 12p +.vs 12p +.SH +Appendix: Synopsis of RCS Operations +.LP +.IP "\fIci\fP \fB\- check in revisions\fP" +.sp 0 +\fICi\fR stores the contents of a working file into the +corresponding RCS file as a new revision. +If the RCS file doesn't exist, \fIci\fR creates it. +\fICi\fR removes the working file, unless one of the options +\fI\-u\fR or \fI\-l\fR is present. +For each check-in, \fIci\fR asks for a commentary +describing the changes relative to the previous revision. +.sp 1 +\fICi\fR assigns the revision number given by the \fI\-r\fR option; +if that option is missing, it derives the number from the +lock held by the user; if there is no lock and locking is not strict, +\fIci\fR increments the number of the latest revision on the trunk. +A side branch can only be started by explicitly specifying its +number with the \fI\-r\fR option during check-in. +.sp 1 +\fICi\fR also determines +whether the revision to be checked in is different from the +previous one, and asks whether to proceed if not. +This facility simplifies check-in operations for large systems, +because one need not remember which files were changed. +.sp 1 +The option \fI\-k\fR searches the checked in file for identification +markers containing +the attributes +revision number, check-in date, author and state, and assigns these +to the new revision rather than computing them. This option is +useful for software distribution: Recipients of distributed software +using RCS should check in updates with the \fI\-k\fR option. +This convention guarantees that revision numbers, check-in dates, +etc., are the same at all sites. +.IP "\fIco\fP \fB\- check out revisions\fP" +.sp 0 +\fICo\fR retrieves revisions according to revision number, +date, author and state attributes. It either places the revision +into the working file, or prints it on the standard output. +\fICo\fR always expands the identification markers. +.IP "\fIident\fP \fB\- extract identification markers\fP" +.sp 0 +\fIIdent\fR extracts the identification markers expanded by \fIco\fR +from any file and prints them. +.IP "\fIrcs\fP \fB\- change RCS file attributes\fP" +.sp 0 +\fIRcs\fR is an administrative operation that changes access lists, +locks, unlocks, breaks locks, toggles the strict-locking feature, +sets state attributes and symbolic revision numbers, changes the +description, and deletes revisions. A revision can +only be deleted if it is not the fork of a side branch. +.IP "\fIrcsclean\fP \fB\- clean working directory\fP" +.sp 0 +.ne 10 +\fIRcsclean\fR removes working files that were checked out but never changed.* +.FS * +The \fIrcsclean\fP and \fIrcsfreeze\fP commands +are optional and are not always installed. +.FE +.IP "\fIrcsdiff\fP \fB\- compare revisions\fP" +.sp 0 +\fIRcsdiff\fR compares two revisions and prints their +difference, using the UNIX tool \fIdiff\fR. +One of the revisions compared may be checked out. +This command is useful for finding out about changes. +.IP "\fIrcsfreeze\fP \fB\- freeze a configuration\fP" +.sp 0 +\fIRcsfreeze\fR assigns the same symbolic revision number +to a given revision in all RCS files. +This command is useful for accurately recording a configuration.* +.IP "\fIrcsmerge\fP \fB\- merge revisions\fP" +.sp 0 +\fIRcsmerge\fR merges two revisions, \fIrev1\fR and \fIrev2\fR, +with respect to a common ancestor. +A 3-way file comparison determines the segments of lines that +are (a) the same in all three revisions, or (b) the same in 2 revisions, +or (c) different in all three. For all segments of type (b) where +\fIrev1\fR is the differing revision, +the segment in \fIrev1\fR replaces the corresponding segment of \fIrev2\fR. +Type (c) indicates an overlapping change, is flagged as an error, and requires user +intervention to select the correct alternative. +.IP "\fIrlog\fP \fB\- read log messages\fP" +.sp 0 +\fIRlog\fR prints the log messages and other information in an RCS file. +.bp +.LP +.nr VS 12p +.vs 12p +.]< +.ds [F 1 +.]- +.ds [K FELD02 +.ds [K MakeArticle +.ds [A Feldman, Stuart I. +.ds [D March 1979 +.ds [T Make\*-A Program for Maintaining Computer Programs +.ds [J Software\*-Practice & Experience +.ds [V 9 +.ds [N 3 +.ds [P 255-265 +.nr [P 1 +.nr [T 0 +.nr [A 1 +.nr [O 0 +.][ 1 journal-article +.ds [F 2 +.]- +.ds [K HUNT01 +.ds [T An Algorithm for Differential File Comparison +.ds [A Hunt, James W. +.as [A " and McIlroy, M. D. +.ds [I Computing Science Technical Report, Bell Laboratories +.ds [R 41 +.ds [D June 1976 +.nr [T 0 +.nr [A 1 +.nr [O 0 +.][ 4 tech-report +.ds [F 3 +.]- +.ds [K SCCS +.ds [A Rochkind, Marc J. +.ds [D Dec. 1975 +.ds [T The Source Code Control System +.ds [J IEEE Transactions on Software Engineering +.ds [V SE-1 +.ds [N 4 +.ds [P 364-370 +.nr [P 1 +.nr [T 0 +.nr [A 1 +.nr [O 0 +.][ 1 journal-article +.ds [F 4 +.]- +.ds [K TICH08 +.ds [T Design, Implementation, and Evaluation of a Revision Control System +.ds [A Tichy, Walter F. +.ds [B Proceedings of the 6th International Conference on Software Engineering +.ds [I ACM, IEEE, IPS, NBS +.ds [D September 1982 +.ds [P 58-67 +.nr [P 1 +.nr [T 0 +.nr [A 1 +.nr [O 0 +.][ 3 article-in-book +.ds [F 5 +.]- +.ds [K LEBL01 +.ds [A Leblang, David B. +.as [A " and Chase, Robert P. +.ds [T Computer-Aided Software Engineering in a Distributed Workstation Environment +.ds [O Proceedings of the ACM SIGSOFT/SIGPLAN Software Engineering Symposium +.as [O " on Practical Software Development Environments. +.ds [J SIGPLAN Notices +.ds [V 19 +.ds [N 5 +.ds [D May 1984 +.ds [P 104-112 +.nr [P 1 +.nr [T 0 +.nr [A 1 +.nr [O 0 +.][ 1 journal-article +.ds [F 1 +.ds [F 3 +.ds [F 6 +.]- +.ds [K SCCSEval +.ds [A Glasser, Alan L. +.ds [D Nov. 1978 +.ds [T The Evolution of a Source Code Control System +.ds [J Software Engineering Notes +.ds [V 3 +.ds [N 5 +.ds [P 122-125 +.nr [P 1 +.ds [O Proceedings of the Software Quality and Assurance Workshop. +.nr [T 0 +.nr [A 1 +.nr [O 1 +.][ 1 journal-article +.ds [F 5 +.ds [F 7 +.]- +.ds [K IBMClearCaster +.ds [A Brown, H.B. +.ds [D 1970 +.ds [T The Clear/Caster System +.ds [J Nato Conference on Software Engineering, Rome +.nr [T 0 +.nr [A 1 +.nr [O 0 +.][ 1 journal-article +.ds [F 3 +.ds [F 8 +.]- +.ds [K HabermannSDC +.ds [A Habermann, A. Nico +.ds [D Jan. 1979 +.ds [T A Software Development Control System +.ds [I Technical Report, Carnegie-Mellon University, Department of Computer Science +.nr [T 0 +.nr [A 0 +.nr [O 0 +.][ 2 book +.ds [F 9 +.]- +.ds [K CMS +.ds [A DEC +.ds [T Code Management System +.ds [I Digital Equipment Corporation +.ds [O Document No.\ EA-23134-82 +.ds [D 1982 +.nr [T 0 +.nr [A 0 +.nr [O 0 +.][ 2 book +.ds [F 10 +.]- +.ds [K LAMP01 +.ds [A Lampson, Butler W. +.as [A " and Schmidt, Eric E. +.ds [T Practical Use of a Polymorphic Applicative Language +.ds [B Proceedings of the 10th Symposium on Principles of Programming Languages +.ds [I ACM +.ds [P 237-255 +.nr [P 1 +.ds [D January 1983 +.nr [T 0 +.nr [A 1 +.nr [O 0 +.][ 3 article-in-book +.ds [F 5 +.ds [F 11 +.]- +.ds [K TICH07 +.ds [T A Data Model for Programming Support Environments and its Application +.ds [A Tichy, Walter F. +.ds [B Automated Tools for Information System Design and Development +.ds [E Hans-Jochen Schneider and Anthony I. Wasserman +.ds [C Amsterdam +.ds [I North-Holland Publishing Company +.ds [D 1982 +.nr [T 0 +.nr [A 1 +.nr [O 0 +.][ 3 article-in-book +.ds [F 4 +.ds [F 2 +.ds [F 12 +.]- +.ds [K HECK01 +.ds [T A Technique for Isolating Differences Between Files +.ds [A Heckel, Paul +.ds [J Communications of the ACM +.ds [D April 1978 +.ds [V 21 +.ds [N 4 +.ds [P 264-268 +.nr [P 1 +.nr [T 0 +.nr [A 0 +.nr [O 0 +.][ 1 journal-article +.ds [F 13 +.]- +.ds [K TICH11 +.ds [T The String-to-String Correction Problem with Block Moves +.ds [A Tichy, Walter F. +.ds [D Nov. 1984 +.ds [J ACM Transactions on Computer Systems +.ds [V 2 +.ds [N 4 +.ds [P 309-321 +.nr [P 1 +.nr [T 0 +.nr [A 1 +.nr [O 0 +.][ 1 journal-article +.]> diff --git a/gnu/usr.bin/rcs/doc/rcs_func.ms b/gnu/usr.bin/rcs/doc/rcs_func.ms new file mode 100644 index 0000000000..9818086c3d --- /dev/null +++ b/gnu/usr.bin/rcs/doc/rcs_func.ms @@ -0,0 +1,95 @@ +.SH +Functions of RCS (Revision Control System) +.PP +RCS manages software libraries. It greatly increases programmer productivity +by providing the following functions. +.IP 1. +RCS stores and retrieves multiple revisions of program and other text. +Thus, one can maintain one or more releases while developing the next +release, with a minimum of space overhead. Changes no longer destroy the +original -- previous revisions remain accessible. +.RS +.IP a. +Maintains each module as a tree of revisions. +.IP b. +Project libraries can +be organized centrally, decentralized, or any way you like. +.IP c. +RCS works for any type of text: programs, documentation, memos, papers, +graphics, VLSI layouts, form letters, etc. +.RE +.IP 2. +RCS maintains a complete history of changes. +Thus, one can find out what happened to a module easily +and quickly, without having to compare source listings or +having to track down colleagues. +.RS +.IP a. +RCS performs automatic record keeping. +.IP b. +RCS logs all changes automatically. +.IP c. +RCS guarantees project continuity. +.RE +.IP 3. +RCS manages multiple lines of development. +.IP 4. +RCS can merge multiple lines of development. +Thus, when several parallel lines of development must be consolidated +into one line, the merging of changes is automatic. +.IP 5. +RCS flags coding conflicts. +If two or more lines of development modify the same section of code, +RCS can alert programmers about overlapping changes. +.IP 6. +RCS resolves access conflicts. +When two or more programmers wish to modify the same revision, +RCS alerts the programmers and makes sure that one modification won't wipe +out the other one. +.IP 7. +RCS provides high-level retrieval functions. +Revisions can be retrieved according to ranges of revision numbers, +symbolic names, dates, authors, and states. +.IP 8. +RCS provides release and configuration control. +Revisions can be marked as released, stable, experimental, etc. +Configurations of modules can be described simply and directly. +.IP 9. +RCS performs automatic identification of modules with name, revision +number, creation time, author, etc. +Thus, it is always possible to determine which revisions of which +modules make up a given configuration. +.IP 10. +Provides high-level management visibility. +Thus, it is easy to track the status of a software project. +.RS +.IP a. +RCS provides a complete change history. +.IP b. +RCS records who did what when to which revision of which module. +.RE +.IP 11. +RCS is fully compatible with existing software development tools. +RCS is unobtrusive -- its interface to the file system is such that +all your existing software tools can be used as before. +.IP 12. +RCS' basic user interface is extremely simple. The novice need to learn +only two commands. Its more sophisticated features have been +tuned towards advanced software development environments and the +experienced software professional. +.IP 13. +RCS simplifies software distribution if customers +maintain sources with RCS also. This technique assures proper +identification of versions and configurations, and tracking of customer +modifications. Customer modifications can be merged into distributed +versions locally or by the development group. +.IP 14. +RCS needs little extra space for the revisions (only the differences). +If intermediate revisions are deleted, the corresponding +differences are compressed into the shortest possible form. +.IP 15. +RCS is implemented with reverse deltas. This means that +the latest revision, which is the one that is accessed most often, +is stored intact. All others are regenerated from the latest one +by applying reverse deltas (backward differences). This +results in fast access time for the revision needed most often. diff --git a/gnu/usr.bin/rcs/ident/Makefile b/gnu/usr.bin/rcs/ident/Makefile new file mode 100644 index 0000000000..1a618e529b --- /dev/null +++ b/gnu/usr.bin/rcs/ident/Makefile @@ -0,0 +1,7 @@ +PROG= ident + +SRCS= ident.c +LDADD= -L${.CURDIR}/../lib/obj -lrcs +CFLAGS+= -I${.CURDIR}/../lib + +.include diff --git a/gnu/usr.bin/rcs/ident/ident.1 b/gnu/usr.bin/rcs/ident/ident.1 new file mode 100644 index 0000000000..37c8eda202 --- /dev/null +++ b/gnu/usr.bin/rcs/ident/ident.1 @@ -0,0 +1,76 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.ds iD \\$3 \\$4 \\$5 \\$6 \\$7 +.. +.Id $Id: ident.1,v 5.0 1990/08/22 09:09:36 eggert Exp $ +.ds r \s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.TH IDENT 1 \*(Dt GNU +.SH NAME +ident \- identify files +.SH SYNOPSIS +.B ident +[ +.B \-q +] [ +.I file +\&.\|.\|. ] +.SH DESCRIPTION +.B ident +searches for all occurrences of the pattern +.BI $ keyword : .\|.\|. $ +in the named files or, if no file name appears, the standard input. +.PP +These patterns are normally inserted automatically by the \*r command +.BR co (1), +but can also be inserted manually. +The option +.B \-q +suppresses +the warning given if there are no patterns in a file. +.PP +.B ident +works on text files as well as object files and dumps. +For example, if the C program in +.B f.c +contains +.IP +\f3char rcsid[] = \&"$\&Id: f.c,v \*(iD $\&";\fP +.LP +and +.B f.c +is compiled into +.BR f.o , +then the command +.IP +.B "ident f.c f.o" +.LP +will output +.nf +.IP +.ft 3 +f.c: + $\&Id: f.c,v \*(iD $ +f.o: + $\&Id: f.c,v \*(iD $ +.ft +.fi +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990 by Paul Eggert. +.SH "SEE ALSO" +ci(1), co(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1), +rcsfile(5) +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. diff --git a/gnu/usr.bin/rcs/ident/ident.c b/gnu/usr.bin/rcs/ident/ident.c new file mode 100644 index 0000000000..a2cc018da3 --- /dev/null +++ b/gnu/usr.bin/rcs/ident/ident.c @@ -0,0 +1,214 @@ +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + +/* + * RCS identification operation + */ + +/* $Log: ident.c,v $ + * Revision 5.3 1991/09/10 22:15:46 eggert + * Open files with FOPEN_R, not FOPEN_R_WORK, + * because they might be executables, not working files. + * + * Revision 5.2 1991/08/19 03:13:55 eggert + * Report read errors immediately. + * + * Revision 5.1 1991/02/25 07:12:37 eggert + * Don't report empty keywords. Check for I/O errors. + * + * Revision 5.0 1990/08/22 08:12:37 eggert + * Don't limit output to known keywords. + * Remove arbitrary limits and lint. Ansify and Posixate. + * + * Revision 4.5 89/05/01 15:11:54 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.4 87/10/23 17:09:57 narten + * added exit(0) so exit return code would be non random + * + * Revision 4.3 87/10/18 10:23:55 narten + * Updating version numbers. Changes relative to 1.1 are actually relative + * to 4.1 + * + * Revision 1.3 87/07/09 09:20:52 trinkle + * Added check to make sure there is at least one arg before comparing argv[1] + * with "-q". This necessary on machines that don't allow dereferncing null + * pointers (i.e. Suns). + * + * Revision 1.2 87/03/27 14:21:47 jenkins + * Port to suns + * + * Revision 4.1 83/05/10 16:31:02 wft + * Added option -q and input from reading stdin. + * Marker matching is now done with trymatch() (independent of keywords). + * + * Revision 3.4 83/02/18 17:37:49 wft + * removed printing of new line after last file. + * + * Revision 3.3 82/12/04 12:48:55 wft + * Added LOCKER. + * + * Revision 3.2 82/11/28 18:24:17 wft + * removed Suffix; added ungetc to avoid skipping over trailing KDELIM. + * + * Revision 3.1 82/10/13 15:58:51 wft + * fixed type of variables receiving from getc() (char-->int). +*/ + +#include "rcsbase.h" + +static int match P((FILE*)); +static void scanfile P((FILE*,char const*,int)); + +mainProg(identId, "ident", "$Id: ident.c,v 5.3 1991/09/10 22:15:46 eggert Exp $") +/* Ident searches the named files for all occurrences + * of the pattern $keyword:...$, where the keywords are + * Author, Date, Header, Id, Log, RCSfile, Revision, Source, and State. + */ + +{ + FILE *fp; + int quiet; + int status = EXIT_SUCCESS; + + if ((quiet = argc > 1 && strcmp("-q",argv[1])==0)) { + argc--; argv++; + } + + if (argc<2) + scanfile(stdin, (char*)0, quiet); + + while ( --argc > 0 ) { + if (!(fp = fopen(*++argv, FOPEN_R))) { + VOID fprintf(stderr, "%s error: can't open %s\n", cmdid, *argv); + status = EXIT_FAILURE; + } else { + scanfile(fp, *argv, quiet); + if (argc>1) VOID putchar('\n'); + } + } + if (ferror(stdout) || fclose(stdout)!=0) { + VOID fprintf(stderr, "%s error: write error\n", cmdid); + status = EXIT_FAILURE; + } + exitmain(status); +} + +#if lint + exiting void identExit() { _exit(EXIT_FAILURE); } +#endif + + + static void +scanfile(file, name, quiet) + register FILE *file; + char const *name; + int quiet; +/* Function: scan an open file with descriptor file for keywords. + * Return false if there's a read error. + */ +{ + register int c; + + if (name) + VOID printf("%s:\n", name); + else + name = "input"; + c = 0; + for (;;) { + if (c < 0) { + if (feof(file)) + break; + if (ferror(file)) + goto read_error; + } + if (c == KDELIM) { + if ((c = match(file))) + continue; + quiet = true; + } + c = getc(file); + } + if (!quiet) + VOID fprintf(stderr, "%s warning: no id keywords in %s\n", cmdid, name); + if (fclose(file) == 0) + return; + + read_error: + VOID fprintf(stderr, "%s error: %s: read error\n", cmdid, name); + exit(EXIT_FAILURE); +} + + + + static int +match(fp) /* group substring between two KDELIM's; then do pattern match */ + register FILE *fp; +{ + char line[BUFSIZ]; + register int c; + register char * tp; + + tp = line; + while ((c = getc(fp)) != VDELIM) { + if (c < 0) + return c; + switch (ctab[c]) { + case LETTER: case Letter: + *tp++ = c; + if (tp < line+sizeof(line)-4) + break; + /* fall into */ + default: + return c ? c : '\n'/* anything but 0 or KDELIM or EOF */; + } + } + if (tp == line) + return c; + *tp++ = c; + if ((c = getc(fp)) != ' ') + return c ? c : '\n'; + *tp++ = c; + while( (c = getc(fp)) != KDELIM ) { + if (c < 0 && feof(fp) | ferror(fp)) + return c; + switch (ctab[c]) { + default: + *tp++ = c; + if (tp < line+sizeof(line)-2) + break; + /* fall into */ + case NEWLN: case UNKN: + return c ? c : '\n'; + } + } + if (tp[-1] != ' ') + return c; + *tp++ = c; /*append trailing KDELIM*/ + *tp = '\0'; + VOID fprintf(stdout, " %c%s\n", KDELIM, line); + return 0; +} diff --git a/gnu/usr.bin/rcs/lib/Makefile b/gnu/usr.bin/rcs/lib/Makefile new file mode 100644 index 0000000000..b198e9ec6f --- /dev/null +++ b/gnu/usr.bin/rcs/lib/Makefile @@ -0,0 +1,5 @@ +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 + +.include diff --git a/gnu/usr.bin/rcs/lib/conf.h b/gnu/usr.bin/rcs/lib/conf.h new file mode 100644 index 0000000000..d29e51159d --- /dev/null +++ b/gnu/usr.bin/rcs/lib/conf.h @@ -0,0 +1,495 @@ +/* RCS compile-time configuration */ + + /* $Id: conf.sh,v 5.14 1991/11/20 18:21:10 eggert Exp $ */ + +/* + * This file is generated automatically. + * If you edit it by hand your changes may be lost. + * Instead, please try to fix conf.sh, + * and send your fixes to rcs-bugs@cs.purdue.edu. + */ + +#define exitmain(n) return n /* how to exit from main() */ +/* #define _POSIX_SOURCE */ /* Define this if Posix + strict Standard C. */ + +#include +#include +#include + +/* Comment out #include lines below that do not work. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ + +/* Define the following symbols to be 1 or 0. */ +#define has_sys_dir_h 1 /* Does #include work? */ +#define has_sys_param_h 1 /* Does #include work? */ +#define has_readlink 1 /* Does readlink() work? */ + +/* #undef NAME_MAX */ /* Uncomment this if NAME_MAX is broken. */ + +#if !defined(NAME_MAX) && !defined(_POSIX_NAME_MAX) +# if has_sys_dir_h +# include +# endif +# ifndef NAME_MAX +# ifndef MAXNAMLEN +# define MAXNAMLEN 14 +# endif +# define NAME_MAX MAXNAMLEN +# endif +#endif +#if !defined(PATH_MAX) && !defined(_POSIX_PATH_MAX) +# if has_sys_param_h +# include +# define included_sys_param_h 1 +# endif +# ifndef PATH_MAX +# ifndef MAXPATHLEN +# define MAXPATHLEN 1024 +# endif +# define PATH_MAX (MAXPATHLEN-1) +# endif +#endif +#if has_readlink && !defined(MAXSYMLINKS) +# if has_sys_param_h && !included_sys_param_h +# include +# endif +# ifndef MAXSYMLINKS +# define MAXSYMLINKS 20 /* BSD; not standard yet */ +# endif +#endif + +/* Comment out the keyword definitions below if the keywords work. */ +/* #define const */ +/* #define volatile */ + +/* Comment out the typedefs below if the types are already declared. */ +/* Fix any uncommented typedefs that are wrong. */ +/* typedef int mode_t; */ +/* typedef int pid_t; */ +typedef int sig_atomic_t; +/* typedef unsigned size_t; */ +/* typedef int ssize_t; */ +/* typedef long time_t; */ +/* typedef int uid_t; */ + +/* Define the following symbols to be 1 or 0. */ +#define has_prototypes 1 /* Do function prototypes work? */ +#define has_stdarg 1 /* Does work? */ +#define has_varargs 0 /* Does work? */ +#define va_start_args 2 /* How many args does va_start() take? */ +#if has_prototypes +# define P(params) params +#else +# define P(params) () +#endif +#if has_stdarg +# include +#else +# if has_varargs +# include +# else + typedef char *va_list; +# define va_dcl int va_alist; +# define va_start(ap) ((ap) = (va_list)&va_alist) +# define va_arg(ap,t) (((t*) ((ap)+=sizeof(t))) [-1]) +# define va_end(ap) +# endif +#endif +#if va_start_args == 2 +# define vararg_start va_start +#else +# define vararg_start(ap,p) va_start(ap) +#endif + +#define text_equals_binary_stdio 1 /* Does stdio treat text like binary? */ +#define text_work_stdio 0 /* Text i/o for working file, binary for RCS file? */ +#if text_equals_binary_stdio + /* Text and binary i/o behave the same, or binary i/o does not work. */ +# define FOPEN_R "r" +# define FOPEN_W "w" +# define FOPEN_WPLUS "w+" +#else + /* Text and binary i/o behave differently. */ + /* This is incompatible with Posix and Unix. */ +# define FOPEN_R "rb" +# define FOPEN_W "wb" +# define FOPEN_WPLUS "w+b" +#endif +#if text_work_stdio +# define FOPEN_R_WORK "r" +# define FOPEN_W_WORK "w" +# define FOPEN_WPLUS_WORK "w+" +#else +# define FOPEN_R_WORK FOPEN_R +# define FOPEN_W_WORK FOPEN_W +# define FOPEN_WPLUS_WORK FOPEN_WPLUS +#endif + +/* Define or comment out the following symbols as needed. */ +#define bad_fopen_wplus 0 /* Does fopen(f,FOPEN_WPLUS) fail to truncate f? */ +#define getlogin_is_secure 0 /* Is getlogin() secure? Usually it's not. */ +#define has_dirent 1 /* Do opendir(), readdir(), closedir() work? */ +#define has_fchmod 0 /* Does fchmod() work? */ +#define has_fputs 0 /* Does fputs() work? */ +#define has_ftruncate 1 /* Does ftruncate() work? */ +#define has_getuid 1 /* Does getuid() work? */ +#define has_getpwuid 1 /* Does getpwuid() work? */ +#define has_link 1 /* Does link() work? */ +#define has_memcmp 1 /* Does memcmp() work? */ +#define has_memcpy 1 /* Does memcpy() work? */ +#define has_memmove 1 /* Does memmove() work? */ +#define has_madvise 0 /* Does madvise() work? */ +#define has_mmap 0 /* Does mmap() work on regular files? */ +#define has_rename 1 /* Does rename() work? */ +#define bad_a_rename 0 /* Does rename(A,B) fail if A is unwritable? */ +#define bad_b_rename 0 /* Does rename(A,B) fail if B is unwritable? */ +#define VOID (void) /* 'VOID e;' discards the value of an expression 'e'. */ +#define has_seteuid 0 /* Does seteuid() work? See README. */ +#define has_setuid 1 /* Does setuid() exist? */ +#define has_signal 1 /* Does signal() work? */ +#define signal_args P((int)) /* arguments of signal handlers */ +#define signal_type void /* type returned by signal handlers */ +#define sig_zaps_handler 0 /* Must a signal handler reinvoke signal()? */ +#define has_sigaction 1 /* Does struct sigaction work? */ +/* #define has_sigblock ? */ /* Does sigblock() work? */ +/* #define sigmask(s) (1 << ((s)-1)) */ /* Yield mask for signal number. */ +#define has_sys_siglist 0 /* Does sys_siglist[] work? */ +typedef ssize_t fread_type; /* type returned by fread() and fwrite() */ +typedef size_t freadarg_type; /* type of their size arguments */ +typedef void *malloc_type; /* type returned by malloc() */ +#define has_getcwd 1 /* Does getcwd() work? */ +/* #define has_getwd ? */ /* Does getwd() work? */ +#define has_mktemp 1 /* Does mktemp() work? */ +#define has_NFS 1 /* Might NFS be used? */ +/* #define strchr index */ /* Use old-fashioned name for strchr()? */ +/* #define strrchr rindex */ /* Use old-fashioned name for strrchr()? */ +#define bad_unlink 0 /* Does unlink() fail on unwritable files? */ +#define has_vfork 0 /* Does vfork() work? */ +#define has_fork 1 /* Does fork() work? */ +#define has_spawn 0 /* Does spawn*() work? */ +#define has_wait 1 /* Does wait() work? */ +#define has_waitpid 0 /* Does waitpid() work? */ +#define RCS_SHELL "/bin/sh" /* shell to run RCS subprograms */ +#define has_vfprintf 1 /* Does vfprintf() work? */ +/* #define has__doprintf ? */ /* Does _doprintf() work? */ +/* #define has__doprnt ? */ /* Does _doprnt() work? */ +/* #undef EXIT_FAILURE */ /* Uncomment this if EXIT_FAILURE is broken. */ +#define large_memory 0 /* Can main memory hold entire RCS files? */ +/* #undef ULONG_MAX */ /* Uncomment this if ULONG_MAX is broken (e.g. < 0). */ +/* struct utimbuf { time_t actime, modtime; }; */ /* Uncomment this if needed. */ +#define CO "/usr/bin/co" /* name of 'co' program */ +#define COMPAT2 0 /* Are version 2 files supported? */ +#define DATEFORM "%.2d.%.2d.%.2d.%.2d.%.2d.%.2d" /* e.g. 01.01.01.01.01.01 */ +#define DIFF "/usr/bin/diff" /* name of 'diff' program */ +#define DIFF3 "/usr/bin/diff3" /* name of 'diff3' program */ +#define DIFF3_BIN 1 /* Is diff3 user-visible (not the /usr/lib auxiliary)? */ +#define DIFF_FLAGS , "-an" /* Make diff output suitable for RCS. */ +#define DIFF_L 1 /* Does diff -L work? */ +#define DIFF_SUCCESS 0 /* DIFF status if no differences are found */ +#define DIFF_FAILURE 1 /* DIFF status if differences are found */ +#define DIFF_TROUBLE 2 /* DIFF status if trouble */ +#define ED "/bin/ed" /* name of 'ed' program (used only if !DIFF3_BIN) */ +#define MERGE "/usr/bin/merge" /* name of 'merge' program */ +#define TMPDIR "/tmp" /* default directory for temporary files */ +#define SLASH '/' /* principal pathname separator */ +#define SLASHes '/' /* `case SLASHes:' labels all pathname separators */ +#define isSLASH(c) ((c) == SLASH) /* Is arg a pathname separator? */ +#define ROOTPATH(p) isSLASH((p)[0]) /* Is p an absolute pathname? */ +#define X_DEFAULT ",v/" /* default value for -x option */ +#define DIFF_ABSOLUTE 1 /* Is ROOTPATH(DIFF) true? */ +#define ALL_ABSOLUTE 1 /* Are all subprograms absolute pathnames? */ +#define SENDMAIL "/usr/bin/mail" /* how to send mail */ +#define TZ_must_be_set 0 /* Must TZ be set for gmtime() to work? */ + + + +/* Adjust the following declarations as needed. */ + + +#if __GNUC__ && !__STRICT_ANSI__ +# define exiting volatile /* GCC extension: function cannot return */ +#else +# define exiting +#endif + +#if has_ftruncate + int ftruncate P((int,off_t)); +#endif + +/* */ +#if has_madvise + int madvise P((caddr_t,size_t,int)); +#endif +#if has_mmap + caddr_t mmap P((caddr_t,size_t,int,int,int,off_t)); + int munmap P((caddr_t,size_t)); +#endif + + +/* Posix (ISO/IEC 9945-1: 1990 / IEEE Std 1003.1-1990) */ +/* These definitions are for the benefit of non-Posix hosts, and */ +/* Posix hosts that have Standard C compilers but traditional include files. */ +/* Unfortunately, mixed-up hosts are all too common. */ + +/* */ +#ifdef F_DUPFD + int fcntl P((int,int,...)); +#else + int dup2 P((int,int)); +#endif +#ifndef O_BINARY /* some non-Posix hosts need O_BINARY */ +# define O_BINARY 0 /* no effect on Posix */ +#endif +#ifdef O_CREAT +# define open_can_creat 1 +#else +# define open_can_creat 0 +# define O_RDONLY 0 +# define O_WRONLY 1 +# define O_RDWR 2 +# define O_CREAT 01000 +# define O_TRUNC 02000 + int creat P((char const*,mode_t)); +#endif +#ifndef O_EXCL +# define O_EXCL 0 +#endif + +/* */ +#if has_getpwuid + struct passwd *getpwuid P((uid_t)); +#endif + +/* */ +#if has_sigaction + int sigaction P((int,struct sigaction const*,struct sigaction*)); + int sigaddset P((sigset_t*,int)); + int sigemptyset P((sigset_t*)); +#else +#if has_sigblock + /* BSD */ + int sigblock P((int)); + int sigmask P((int)); + int sigsetmask P((int)); +#endif +#endif + +/* */ +FILE *fdopen P((int,char const*)); +int fileno P((FILE*)); + +/* */ +int chmod P((char const*,mode_t)); +int fstat P((int,struct stat*)); +int stat P((char const*,struct stat*)); +mode_t umask P((mode_t)); +#if has_fchmod + int fchmod P((int,mode_t)); +#endif +#ifndef S_IRUSR +# ifdef S_IREAD +# define S_IRUSR S_IREAD +# else +# define S_IRUSR 0400 +# endif +# ifdef S_IWRITE +# define S_IWUSR S_IWRITE +# else +# define S_IWUSR (S_IRUSR/2) +# endif +#endif +#ifndef S_IRGRP +# if has_getuid +# define S_IRGRP (S_IRUSR / 0010) +# define S_IWGRP (S_IWUSR / 0010) +# define S_IROTH (S_IRUSR / 0100) +# define S_IWOTH (S_IWUSR / 0100) +# else + /* single user OS -- not Posix or Unix */ +# define S_IRGRP 0 +# define S_IWGRP 0 +# define S_IROTH 0 +# define S_IWOTH 0 +# endif +#endif +#ifndef S_ISREG +# define S_ISREG(n) (((n) & S_IFMT) == S_IFREG) +#endif + +/* */ +#if has_wait + pid_t wait P((int*)); +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +# undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */ +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (!((stat_val) & 255)) +#endif + +/* */ +char *getlogin P((void)); +int close P((int)); +int isatty P((int)); +int link P((char const*,char const*)); +int open P((char const*,int,...)); +int unlink P((char const*)); +int _filbuf P((FILE*)); /* keeps lint quiet in traditional C */ +int _flsbuf P((int,FILE*)); /* keeps lint quiet in traditional C */ +long pathconf P((char const*,int)); +ssize_t write P((int,void const*,size_t)); +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +# define STDOUT_FILENO 1 +# define STDERR_FILENO 2 +#endif +#if has_fork +# if !has_vfork +# undef vfork +# define vfork fork +# endif + pid_t vfork P((void)); /* vfork is nonstandard but faster */ +#endif +#if has_getcwd || !has_getwd + char *getcwd P((char*,size_t)); +#else + char *getwd P((char*)); +#endif +#if has_getuid + uid_t getuid P((void)); +#endif +#if has_readlink +/* ssize_t readlink P((char const*,char*,size_t)); *//* BSD; not standard yet */ +#endif +#if has_setuid +# if !has_seteuid +# undef seteuid +# define seteuid setuid +# endif + int seteuid P((uid_t)); + uid_t geteuid P((void)); +#endif +#if has_spawn + int spawnv P((int,char const*,char*const*)); +# if ALL_ABSOLUTE +# define spawn_RCS spawnv +# else +# define spawn_RCS spawnvp + int spawnvp P((int,char const*,char*const*)); +# endif +#else + int execv P((char const*,char*const*)); +# if ALL_ABSOLUTE +# define exec_RCS execv +# else +# define exec_RCS execvp + int execvp P((char const*,char*const*)); +# endif +#endif + +/* utime.h */ +int utime P((char const*,struct utimbuf const*)); + + +/* Standard C library */ +/* These definitions are for the benefit of hosts that have */ +/* traditional C include files, possibly with Standard C compilers. */ +/* Unfortunately, mixed-up hosts are all too common. */ + +/* */ +extern int errno; + +/* */ +#ifndef ULONG_MAX + /* This does not work in #ifs, but it's good enough for us. */ +# define ULONG_MAX ((unsigned long)-1) +#endif + +/* */ +#if has_signal + signal_type (*signal P((int,signal_type(*)signal_args)))signal_args; +#endif + +/* */ +FILE *fopen P((char const*,char const*)); +fread_type fread P((void*,freadarg_type,freadarg_type,FILE*)); +fread_type fwrite P((void const*,freadarg_type,freadarg_type,FILE*)); +int fclose P((FILE*)); +int feof P((FILE*)); +int ferror P((FILE*)); +int fflush P((FILE*)); +int fprintf P((FILE*,char const*,...)); +int fputs P((char const*,FILE*)); +int fseek P((FILE*,long,int)); +int printf P((char const*,...)); +int rename P((char const*,char const*)); +int sprintf P((char*,char const*,...)); +/* long ftell P((FILE*)); */ +void clearerr P((FILE*)); +void perror P((char const*)); +#ifndef L_tmpnam +# define L_tmpnam 32 /* power of 2 > sizeof("/usr/tmp/xxxxxxxxxxxxxxx") */ +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif +#if has_mktemp + char *mktemp P((char*)); /* traditional */ +#else + char *tmpnam P((char*)); +#endif +#if has_vfprintf + int vfprintf P((FILE*,char const*,va_list)); +#else +#if has__doprintf + void _doprintf P((FILE*,char const*,va_list)); /* Minix */ +#else + void _doprnt P((char const*,va_list,FILE*)); /* BSD */ +#endif +#endif + +/* */ +char *getenv P((char const*)); +exiting void _exit P((int)); +exiting void exit P((int)); +malloc_type malloc P((size_t)); +malloc_type realloc P((malloc_type,size_t)); +void free P((malloc_type)); +#ifndef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif +#if !has_fork && !has_spawn + int system P((char const*)); +#endif + +/* */ +char *strcpy P((char*,char const*)); +char *strchr P((char const*,int)); +char *strrchr P((char const*,int)); +int memcmp P((void const*,void const*,size_t)); +int strcmp P((char const*,char const*)); +size_t strlen P((char const*)); +void *memcpy P((void*,void const*,size_t)); +#if has_memmove + void *memmove P((void*,void const*,size_t)); +#endif + +/* */ +time_t time P((time_t*)); diff --git a/gnu/usr.bin/rcs/lib/maketime.c b/gnu/usr.bin/rcs/lib/maketime.c new file mode 100644 index 0000000000..c95c9f0b1e --- /dev/null +++ b/gnu/usr.bin/rcs/lib/maketime.c @@ -0,0 +1,344 @@ +# +/* + * MAKETIME derive 32-bit time value from TM structure. + * + * Usage: + * int zone; Minutes west of GMT, or + * 48*60 for localtime + * time_t t; + * struct tm *tp; Pointer to TM structure from + * t = maketime(tp,zone); + * + * Returns: + * -1 if failure; parameter out of range or nonsensical. + * else time-value. + * Notes: + * This code is quasi-public; it may be used freely in like software. + * It is not to be sold, nor used in licensed software without + * permission of the author. + * For everyone's benefit, please report bugs and improvements! + * Copyright 1981 by Ken Harrenstien, SRI International. + * (ARPANET: KLH @ SRI) + */ +/* $Log: maketime.c,v $ + * Revision 5.3 1991/08/19 03:13:55 eggert + * Add setfiledate, str2time, TZ_must_be_set. + * + * Revision 5.2 1990/11/01 05:03:30 eggert + * Remove lint. + * + * Revision 5.1 1990/10/04 06:30:13 eggert + * Calculate the GMT offset of 'xxx LT' as of xxx, not as of now. + * Don't assume time_t is 32 bits. Fix bugs near epoch and near end of time. + * + * Revision 5.0 1990/08/22 08:12:38 eggert + * Switch to GMT and fix the bugs exposed thereby. + * Permit dates past 1999/12/31. Ansify and Posixate. + * + * Revision 1.8 88/11/08 13:54:53 narten + * allow negative timezones (-24h <= x <= 24h) + * + * Revision 1.7 88/08/28 14:47:52 eggert + * Allow cc -R. Remove unportable "#endif XXX"s. + * + * Revision 1.6 87/12/18 17:05:58 narten + * include rcsparam.h + * + * Revision 1.5 87/12/18 11:35:51 narten + * maketime.c: fixed USG code - you have tgo call "tzset" in order to have + * "timezone" set. ("localtime" calls it, but it's probably better not to + * count on "localtime" having been called.) + * + * Revision 1.4 87/10/18 10:26:57 narten + * Updating version numbers. Changes relative to 1.0 are actually + * relative to 1.2 + * + * Revision 1.3 87/09/24 13:58:45 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:21:48 jenkins + * Port to suns + * + * Revision 1.2 83/12/05 10:12:56 wft + * added cond. compilation for USG Unix; long timezone; + * + * Revision 1.1 82/05/06 11:38:00 wft + * Initial revision + * + */ + + +#include "rcsbase.h" + +libId(maketId, "$Id: maketime.c,v 5.3 1991/08/19 03:13:55 eggert Exp $") + +static struct tm const *time2tm P((time_t)); + +#define given(v) (0 <= (v)) /* Negative values are unspecified. */ + +static int const daytb[] = { + /* # days in year thus far, indexed by month (0-12!!) */ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 +}; + + static time_t +maketime(atm,zone) + struct tm const *atm; + int zone; +{ + register struct tm const *tp; + register int i; + int year, yday, mon, day, hour, min, sec, leap, localzone; + int attempts; + time_t t, tres; + + attempts = 2; + localzone = zone==48*60; + tres = -1; + year = mon = day = 0; /* Keep lint happy. */ + + do { + + if (localzone || !given(atm->tm_year)) { + if (tres == -1) + if ((tres = time((time_t*)0)) == -1) + return -1; + tp = time2tm(tres); + /* Get breakdowns of default time, adjusting to zone. */ + year = tp->tm_year; /* Use to set up defaults */ + yday = tp->tm_yday; + mon = tp->tm_mon; + day = tp->tm_mday; + hour = tp->tm_hour; + min = tp->tm_min; + if (localzone) { + tp = localtime(&tres); + zone = + min - tp->tm_min + 60*( + hour - tp->tm_hour + 24*( + /* If years differ, it's by one day. */ + year - tp->tm_year + ? year - tp->tm_year + : yday - tp->tm_yday)); + } + /* Adjust the default day, month and year according to zone. */ + if ((min -= zone) < 0) { + if (hour-(59-min)/60 < 0 && --day <= 0) { + if (--mon < 0) { + --year; + mon = 11; + } + day = daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3)); + } + } else + if ( + 24 <= hour+min/60 && + daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3)) < ++day + ) { + if (11 < ++mon) { + ++year; + mon = 0; + } + day = 1; + } + } + if (zone < -24*60 || 24*60 < zone) + return -1; + + +#ifdef DEBUG +printf("first YMD: %d %d %d\n",year,mon,day); +#endif + tp = atm; + + /* First must find date, using specified year, month, day. + * If one of these is unspecified, it defaults either to the + * current date (if no more global spec was given) or to the + * zero-value for that spec (i.e. a more global spec was seen). + * Reject times that do not fit in time_t, + * without assuming that time_t is 32 bits or is signed. + */ + if (given(tp->tm_year)) + { + year = tp->tm_year; + mon = 0; /* Since year was given, default */ + day = 1; /* for remaining specs is zero */ + } + if (year < 69) /* 1969/12/31 OK in some timezones. */ + return -1; /* ERR: year out of range */ + leap = !(year&3) && (year%100 || !((year+300)%400)); + year -= 70; /* UNIX time starts at 1970 */ + + /* + * Find day of year. + */ + { + if (given(tp->tm_mon)) + { mon = tp->tm_mon; /* Month was specified */ + day = 1; /* so set remaining default */ + } + if (11 < (unsigned)mon) + return -1; /* ERR: bad month */ + if (given(tp->tm_mday)) day = tp->tm_mday; + if(day < 1 + || (((daytb[mon+1]-daytb[mon]) < day) + && (day!=29 || mon!=1 || !leap) )) + return -1; /* ERR: bad day */ + yday = daytb[mon] /* Add # of days in months so far */ + + ((leap /* Leap year, and past Feb? If */ + && mon>1)? 1:0) /* so, add leap day for this year */ + + day-1; /* And finally add # days this mon */ + + } + if (leap+365 <= (unsigned)yday) + return -1; /* ERR: bad YDAY */ + + if (year < 0) { + if (yday != 364) + return -1; /* ERR: too early */ + t = -1; + } else { + tres = year*365; /* Get # days of years so far */ + if (tres/365 != year) + return -1; /* ERR: overflow */ + t = tres + + ((year+1)>>2) /* plus # of leap days since 1970 */ + + yday; /* and finally add # days this year */ + if (t+4 < tres) + return -1; /* ERR: overflow */ + } + tres = t; + + if (given(i = tp->tm_wday)) /* Check WDAY if present */ + if (i != (tres+4)%7) /* 1970/01/01 was Thu = 4 */ + return -1; /* ERR: bad WDAY */ + +#ifdef DEBUG +printf("YMD: %d %d %d, T=%ld\n",year,mon,day,tres); +#endif + /* + * Now determine time. If not given, default to zeros + * (since time is always the least global spec) + */ + tres *= 86400L; /* Get # seconds (24*60*60) */ + if (tres/86400L != t) + return -1; /* ERR: overflow */ + hour = min = sec = 0; + if (given(tp->tm_hour)) hour = tp->tm_hour; + if (given(tp->tm_min )) min = tp->tm_min; + if (given(tp->tm_sec )) sec = tp->tm_sec; + if (60 <= (unsigned)min || 60 < (unsigned)sec) + return -1; /* ERR: MS out of range */ + if (24 <= (unsigned)hour) + if(hour != 24 || (min+sec) !=0) /* Allow 24:00 */ + return -1; /* ERR: H out of range */ + + t = tres; + tres += sec + 60L*(zone + min + 60*hour); + +#ifdef DEBUG +printf("HMS: %d %d %d T=%ld\n",hour,min,sec,tres); +#endif + + if (!localzone) /* check for overflow */ + return (year<0 ? (tres<0||86400L<=tres) : trestm_sec) && atm->tm_sec != tp->tm_sec) + return -1; /* If seconds don't match, we're in trouble. */ + if (!( + given(atm->tm_min) && atm->tm_min != tp->tm_min || + given(atm->tm_hour) && atm->tm_hour != tp->tm_hour || + given(atm->tm_mday) && atm->tm_mday != tp->tm_mday || + given(atm->tm_mon) && atm->tm_mon != tp->tm_mon || + given(atm->tm_year) && atm->tm_year != tp->tm_year + )) + return tres; /* Everything matches. */ + + } while (--attempts); + + return -1; +} + +/* +* Convert Unix time to struct tm format. +* Use Coordinated Universal Time (UTC) if version 5 or newer; +* use local time otherwise. +*/ + static struct tm const * +time2tm(unixtime) + time_t unixtime; +{ + struct tm const *tm; +# if TZ_must_be_set + static char const *TZ; + if (!TZ && !(TZ = getenv("TZ"))) + faterror("TZ is not set"); +# endif + if (!(tm = (RCSversiontm_year + (tm->tm_year<100 ? 0 : 1900), + tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec + ); +} + + + + static time_t +str2time(source) + char const *source; +/* Parse a free-format date in SOURCE, yielding a Unix format time. */ +{ + int zone; + time_t unixtime; + struct tm parseddate; + + if (!partime(source, &parseddate, &zone)) + faterror("can't parse date/time: %s", source); + if ((unixtime = maketime(&parseddate, zone)) == -1) + faterror("bad date/time: %s", source); + return unixtime; +} + + void +str2date(source, target) + char const *source; + char target[datesize]; +/* Parse a free-format date in SOURCE, convert it + * into RCS internal format, and store the result into TARGET. + */ +{ + time2date(str2time(source), target); +} + + int +setfiledate(file, date) + char const *file, date[datesize]; +/* Set the access and modification time of FILE to DATE. */ +{ + static struct utimbuf times; /* static so unused fields are zero */ + char datebuf[datesize]; + + if (!date) + return 0; + times.actime = times.modtime = str2time(date2str(date, datebuf)); + return utime(file, ×); +} diff --git a/gnu/usr.bin/rcs/lib/merger.c b/gnu/usr.bin/rcs/lib/merger.c new file mode 100644 index 0000000000..7162ffa58e --- /dev/null +++ b/gnu/usr.bin/rcs/lib/merger.c @@ -0,0 +1,139 @@ +/* merger - three-way file merge internals */ + +/* Copyright 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + +#include "rcsbase.h" + +libId(mergerId, "$Id: merger.c,v 1.3 1991/08/20 23:05:00 eggert Exp $") + + static char const * +normalize_arg(s, b) + char const *s; + char **b; +/* + * If S looks like an option, prepend ./ to it. Yield the result. + * Set *B to the address of any storage that was allocated.. + */ +{ + char *t; + switch (*s) { + case '-': case '+': + *b = t = testalloc(strlen(s) + 3); + VOID sprintf(t, ".%c%s", SLASH, s); + return t; + default: + *b = 0; + return s; + } +} + + int +merge(tostdout, label, argv) + int tostdout; + char const *const label[2]; + char const *const argv[3]; +/* + * Do `merge [-p] -L l0 -L l1 a0 a1 a2', + * where TOSTDOUT specifies whether -p is present, + * LABEL gives l0 and l1, and ARGV gives a0, a1, and a2. + * Yield DIFF_SUCCESS or DIFF_FAILURE. + */ +{ + register int i; + FILE *f; + RILE *rt; + char const *a[3], *t; + char *b[3]; + int s; +#if !DIFF3_BIN + char const *d[2]; +#endif + + for (i=3; 0<=--i; ) + a[i] = normalize_arg(argv[i], &b[i]); + +#if DIFF3_BIN + t = 0; + if (!tostdout) + t = maketemp(0); + s = run( + (char*)0, t, + DIFF3, "-am", "-L", label[0], "-L", label[1], + a[0], a[1], a[2], (char*)0 + ); + switch (s) { + case DIFF_SUCCESS: + break; + case DIFF_FAILURE: + if (!quietflag) + warn("overlaps during merge"); + break; + default: + exiterr(); + } + if (t) { + if (!(f = fopen(argv[0], FOPEN_W))) + efaterror(argv[0]); + if (!(rt = Iopen(t, FOPEN_R, (struct stat*)0))) + efaterror(t); + fastcopy(rt, f); + Ifclose(rt); + Ofclose(f); + } +#else + for (i=0; i<2; i++) + switch (run( + (char*)0, d[i]=maketemp(i), + DIFF, a[i], a[2], (char*)0 + )) { + case DIFF_FAILURE: case DIFF_SUCCESS: break; + default: exiterr(); + } + t = maketemp(2); + s = run( + (char*)0, t, + DIFF3, "-E", d[0], d[1], a[0], a[1], a[2], + label[0], label[1], (char*)0 + ); + if (s != DIFF_SUCCESS) { + s = DIFF_FAILURE; + if (!quietflag) + warn("overlaps or other problems during merge"); + } + if (!(f = fopen(t, "a"))) + efaterror(t); + aputs(tostdout ? "1,$p\n" : "w\n", f); + Ofclose(f); + if (run(t, (char*)0, ED, "-", a[0], (char*)0)) + exiterr(); +#endif + + tempunlink(); + for (i=3; 0<=--i; ) + if (b[i]) + tfree(b[i]); + return s; +} diff --git a/gnu/usr.bin/rcs/lib/partime.c b/gnu/usr.bin/rcs/lib/partime.c new file mode 100644 index 0000000000..4751fc56d1 --- /dev/null +++ b/gnu/usr.bin/rcs/lib/partime.c @@ -0,0 +1,639 @@ +/* + * PARTIME parse date/time string into a TM structure + * + * Returns: + * 0 if parsing failed + * else time values in specified TM structure and zone (unspecified values + * set to TMNULL) + * Notes: + * This code is quasi-public; it may be used freely in like software. + * It is not to be sold, nor used in licensed software without + * permission of the author. + * For everyone's benefit, please report bugs and improvements! + * Copyright 1980 by Ken Harrenstien, SRI International. + * (ARPANET: KLH @ SRI) + */ + +/* Hacknotes: + * If parsing changed so that no backup needed, could perhaps modify + * to use a FILE input stream. Need terminator, though. + * Perhaps should return 0 on success, else a non-zero error val? + */ + +/* $Log: partime.c,v $ + * Revision 5.6 1991/08/19 03:13:55 eggert + * Update timezones. + * + * Revision 5.5 1991/04/21 11:58:18 eggert + * Don't put , just before } in initializer. + * + * Revision 5.4 1990/10/04 06:30:15 eggert + * Remove date vs time heuristics that fail between 2000 and 2400. + * Check for overflow when lexing an integer. + * Parse 'Jan 10 LT' as 'Jan 10, LT', not 'Jan, 10 LT'. + * + * Revision 5.3 1990/09/24 18:56:31 eggert + * Update timezones. + * + * Revision 5.2 1990/09/04 08:02:16 eggert + * Don't parse two-digit years, because it won't work after 1999/12/31. + * Don't permit 'Aug Aug'. + * + * Revision 5.1 1990/08/29 07:13:49 eggert + * Be able to parse our own date format. Don't assume year<10000. + * + * Revision 5.0 1990/08/22 08:12:40 eggert + * Switch to GMT and fix the bugs exposed thereby. Update timezones. + * Ansify and Posixate. Fix peekahead and int-size bugs. + * + * Revision 1.4 89/05/01 14:48:46 narten + * fixed #ifdef DEBUG construct + * + * Revision 1.3 88/08/28 14:53:40 eggert + * Remove unportable "#endif XXX"s. + * + * Revision 1.2 87/03/27 14:21:53 jenkins + * Port to suns + * + * Revision 1.1 82/05/06 11:38:26 wft + * Initial revision + * + */ + +#include "rcsbase.h" + +libId(partId, "$Id: partime.c,v 5.6 1991/08/19 03:13:55 eggert Exp $") + +#define given(v) (0 <= (v)) +#define TMNULL (-1) /* Items not given are given this value */ +#define TZ_OFFSET (24*60) /* TMNULL < zone_offset - TZ_OFFSET */ + +struct tmwent { + char const *went; + short wval; + char wflgs; + char wtype; +}; + /* wflgs */ +#define TWTIME 02 /* Word is a time value (absence implies date) */ +#define TWDST 04 /* Word is a DST-type timezone */ + /* wtype */ +#define TM_MON 1 /* month name */ +#define TM_WDAY 2 /* weekday name */ +#define TM_ZON 3 /* time zone name */ +#define TM_LT 4 /* local time */ +#define TM_DST 5 /* daylight savings time */ +#define TM_12 6 /* AM, PM, NOON, or MIDNIGHT */ + /* wval (for wtype==TM_12) */ +#define T12_AM 1 +#define T12_PM 2 +#define T12_NOON 12 +#define T12_MIDNIGHT 0 + +static struct tmwent const tmwords [] = { + {"january", 0, 0, TM_MON}, + {"february", 1, 0, TM_MON}, + {"march", 2, 0, TM_MON}, + {"april", 3, 0, TM_MON}, + {"may", 4, 0, TM_MON}, + {"june", 5, 0, TM_MON}, + {"july", 6, 0, TM_MON}, + {"august", 7, 0, TM_MON}, + {"september", 8, 0, TM_MON}, + {"october", 9, 0, TM_MON}, + {"november", 10, 0, TM_MON}, + {"december", 11, 0, TM_MON}, + + {"sunday", 0, 0, TM_WDAY}, + {"monday", 1, 0, TM_WDAY}, + {"tuesday", 2, 0, TM_WDAY}, + {"wednesday", 3, 0, TM_WDAY}, + {"thursday", 4, 0, TM_WDAY}, + {"friday", 5, 0, TM_WDAY}, + {"saturday", 6, 0, TM_WDAY}, + + {"gmt", 0*60, TWTIME, TM_ZON}, /* Greenwich */ + {"utc", 0*60, TWTIME, TM_ZON}, + {"ut", 0*60, TWTIME, TM_ZON}, + {"cut", 0*60, TWTIME, TM_ZON}, + + {"nzst", -12*60, TWTIME, TM_ZON}, /* New Zealand */ + {"jst", -9*60, TWTIME, TM_ZON}, /* Japan */ + {"kst", -9*60, TWTIME, TM_ZON}, /* Korea */ + {"ist", -5*60-30, TWTIME, TM_ZON},/* India */ + {"eet", -2*60, TWTIME, TM_ZON}, /* Eastern Europe */ + {"cet", -1*60, TWTIME, TM_ZON}, /* Central Europe */ + {"met", -1*60, TWTIME, TM_ZON}, /* Middle Europe */ + {"wet", 0*60, TWTIME, TM_ZON}, /* Western Europe */ + {"nst", 3*60+30, TWTIME, TM_ZON},/* Newfoundland */ + {"ast", 4*60, TWTIME, TM_ZON}, /* Atlantic */ + {"est", 5*60, TWTIME, TM_ZON}, /* Eastern */ + {"cst", 6*60, TWTIME, TM_ZON}, /* Central */ + {"mst", 7*60, TWTIME, TM_ZON}, /* Mountain */ + {"pst", 8*60, TWTIME, TM_ZON}, /* Pacific */ + {"akst", 9*60, TWTIME, TM_ZON}, /* Alaska */ + {"hast", 10*60, TWTIME, TM_ZON}, /* Hawaii-Aleutian */ + {"hst", 10*60, TWTIME, TM_ZON}, /* Hawaii */ + {"sst", 11*60, TWTIME, TM_ZON}, /* Samoa */ + + {"nzdt", -12*60, TWTIME+TWDST, TM_ZON}, /* New Zealand */ + {"kdt", -9*60, TWTIME+TWDST, TM_ZON}, /* Korea */ + {"bst", 0*60, TWTIME+TWDST, TM_ZON}, /* Britain */ + {"ndt", 3*60+30, TWTIME+TWDST, TM_ZON}, /* Newfoundland */ + {"adt", 4*60, TWTIME+TWDST, TM_ZON}, /* Atlantic */ + {"edt", 5*60, TWTIME+TWDST, TM_ZON}, /* Eastern */ + {"cdt", 6*60, TWTIME+TWDST, TM_ZON}, /* Central */ + {"mdt", 7*60, TWTIME+TWDST, TM_ZON}, /* Mountain */ + {"pdt", 8*60, TWTIME+TWDST, TM_ZON}, /* Pacific */ + {"akdt", 9*60, TWTIME+TWDST, TM_ZON}, /* Alaska */ + {"hadt", 10*60, TWTIME+TWDST, TM_ZON}, /* Hawaii-Aleutian */ + +#if 0 + /* + * The following names are duplicates or are not well attested. + * A standard is needed. + */ + {"east", -10*60, TWTIME, TM_ZON}, /* Eastern Australia */ + {"cast", -9*60-30, TWTIME, TM_ZON},/* Central Australia */ + {"cst", -8*60, TWTIME, TM_ZON}, /* China */ + {"hkt", -8*60, TWTIME, TM_ZON}, /* Hong Kong */ + {"sst", -8*60, TWTIME, TM_ZON}, /* Singapore */ + {"wast", -8*60, TWTIME, TM_ZON}, /* Western Australia */ + {"?", -6*60-30, TWTIME, TM_ZON},/* Burma */ + {"?", -4*60-30, TWTIME, TM_ZON},/* Afghanistan */ + {"it", -3*60-30, TWTIME, TM_ZON},/* Iran */ + {"ist", -2*60, TWTIME, TM_ZON}, /* Israel */ + {"mez", -1*60, TWTIME, TM_ZON}, /* Mittel-Europaeische Zeit */ + {"ast", 1*60, TWTIME, TM_ZON}, /* Azores */ + {"fst", 2*60, TWTIME, TM_ZON}, /* Fernando de Noronha */ + {"bst", 3*60, TWTIME, TM_ZON}, /* Brazil */ + {"wst", 4*60, TWTIME, TM_ZON}, /* Western Brazil */ + {"ast", 5*60, TWTIME, TM_ZON}, /* Acre Brazil */ + {"?", 9*60+30, TWTIME, TM_ZON},/* Marquesas */ + {"?", 12*60, TWTIME, TM_ZON}, /* Kwajalein */ + + {"eadt", -10*60, TWTIME+TWDST, TM_ZON}, /* Eastern Australia */ + {"cadt", -9*60-30, TWTIME+TWDST, TM_ZON}, /* Central Australia */ + {"cdt", -8*60, TWTIME+TWDST, TM_ZON}, /* China */ + {"wadt", -8*60, TWTIME+TWDST, TM_ZON}, /* Western Australia */ + {"idt", -2*60, TWTIME+TWDST, TM_ZON}, /* Israel */ + {"eest", -2*60, TWTIME+TWDST, TM_ZON}, /* Eastern Europe */ + {"cest", -1*60, TWTIME+TWDST, TM_ZON}, /* Central Europe */ + {"mest", -1*60, TWTIME+TWDST, TM_ZON}, /* Middle Europe */ + {"mesz", -1*60, TWTIME+TWDST, TM_ZON}, /* Mittel-Europaeische Sommerzeit */ + {"west", 0*60, TWTIME+TWDST, TM_ZON}, /* Western Europe */ + {"adt", 1*60, TWTIME+TWDST, TM_ZON}, /* Azores */ + {"fdt", 2*60, TWTIME+TWDST, TM_ZON}, /* Fernando de Noronha */ + {"edt", 3*60, TWTIME+TWDST, TM_ZON}, /* Eastern Brazil */ + {"wdt", 4*60, TWTIME+TWDST, TM_ZON}, /* Western Brazil */ + {"adt", 5*60, TWTIME+TWDST, TM_ZON}, /* Acre Brazil */ +#endif + + {"lt", 0, TWTIME, TM_LT}, /* local time */ + {"dst", 1*60, TWTIME, TM_DST}, /* daylight savings time */ + {"ddst", 2*60, TWTIME, TM_DST}, /* double dst */ + + {"am", T12_AM, TWTIME, TM_12}, + {"pm", T12_PM, TWTIME, TM_12}, + {"noon", T12_NOON, TWTIME, TM_12}, + {"midnight", T12_MIDNIGHT, TWTIME, TM_12}, + + {0, 0, 0, 0} /* Zero entry to terminate searches */ +}; + +struct token { + char const *tcp;/* pointer to string */ + int tcnt; /* # chars */ + char tbrk; /* "break" char */ + char tbrkl; /* last break char */ + char tflg; /* 0 = alpha, 1 = numeric */ + union { /* Resulting value; */ + int tnum;/* either a #, or */ + struct tmwent const *ttmw;/* a ptr to a tmwent. */ + } tval; +}; + +static struct tmwent const*ptmatchstr P((char const*,int,struct tmwent const*)); +static int pt12hack P((struct tm *,int)); +static int ptitoken P((struct token *)); +static int ptstash P((int *,int)); +static int pttoken P((struct token *)); + + static int +goodzone(t, offset, am) + register struct token const *t; + int offset; + int *am; +{ + register int m; + if ( + t->tflg && + t->tcnt == 4+offset && + (m = t->tval.tnum) <= 2400 && + isdigit(t->tcp[offset]) && + (m%=100) < 60 + ) { + m += t->tval.tnum/100 * 60; + if (t->tcp[offset-1]=='+') + m = -m; + *am = m; + return 1; + } + return 0; +} + + int +partime(astr, atm, zone) +char const *astr; +register struct tm *atm; +int *zone; +{ + register int i; + struct token btoken, atoken; + int zone_offset; /* minutes west of GMT, plus TZ_OFFSET */ + register char const *cp; + register char ch; + int ord, midnoon; + int *atmfield, dst, m; + int got1 = 0; + + atm->tm_sec = TMNULL; + atm->tm_min = TMNULL; + atm->tm_hour = TMNULL; + atm->tm_mday = TMNULL; + atm->tm_mon = TMNULL; + atm->tm_year = TMNULL; + atm->tm_wday = TMNULL; + atm->tm_yday = TMNULL; + midnoon = TMNULL; /* and our own temp stuff */ + zone_offset = TMNULL; + dst = TMNULL; + btoken.tcnt = btoken.tbrk = 0; + btoken.tcp = astr; + + for (;; got1=1) { + if (!ptitoken(&btoken)) /* Get a token */ + { if(btoken.tval.tnum) return(0); /* Read error? */ + if (given(midnoon)) /* EOF, wrap up */ + if (!pt12hack(atm, midnoon)) + return 0; + if (!given(atm->tm_min)) + atm->tm_min = 0; + *zone = + (given(zone_offset) ? zone_offset-TZ_OFFSET : 0) + - (given(dst) ? dst : 0); + return got1; + } + if(btoken.tflg == 0) /* Alpha? */ + { i = btoken.tval.ttmw->wval; + switch (btoken.tval.ttmw->wtype) { + default: + return 0; + case TM_MON: + atmfield = &atm->tm_mon; + break; + case TM_WDAY: + atmfield = &atm->tm_wday; + break; + case TM_DST: + atmfield = &dst; + break; + case TM_LT: + if (ptstash(&dst, 0)) + return 0; + i = 48*60; /* local time magic number -- see maketime() */ + /* fall into */ + case TM_ZON: + i += TZ_OFFSET; + if (btoken.tval.ttmw->wflgs & TWDST) + if (ptstash(&dst, 60)) + return 0; + /* Peek ahead for offset immediately afterwards. */ + if ( + (btoken.tbrk=='-' || btoken.tbrk=='+') && + (atoken=btoken, ++atoken.tcnt, ptitoken(&atoken)) && + goodzone(&atoken, 0, &m) + ) { + i += m; + btoken = atoken; + } + atmfield = &zone_offset; + break; + case TM_12: + atmfield = &midnoon; + } + if (ptstash(atmfield, i)) + return(0); /* ERR: val already set */ + continue; + } + + /* Token is number. Lots of hairy heuristics. */ + if (!isdigit(*btoken.tcp)) { + if (!goodzone(&btoken, 1, &m)) + return 0; + zone_offset = TZ_OFFSET + m; + continue; + } + + i = btoken.tval.tnum; /* Value now known to be valid; get it. */ + if (btoken.tcnt == 3) /* 3 digits = HMM */ + { +hhmm4: if (ptstash(&atm->tm_min, i%100)) + return(0); /* ERR: min conflict */ + i /= 100; +hh2: if (ptstash(&atm->tm_hour, i)) + return(0); /* ERR: hour conflict */ + continue; + } + + if (4 < btoken.tcnt) + goto year4; /* far in the future */ + if(btoken.tcnt == 4) /* 4 digits = YEAR or HHMM */ + { if (given(atm->tm_year)) goto hhmm4; /* Already got yr? */ + if (given(atm->tm_hour)) goto year4; /* Already got hr? */ + if(btoken.tbrk == ':') /* HHMM:SS ? */ + if ( ptstash(&atm->tm_hour, i/100) + || ptstash(&atm->tm_min, i%100)) + return(0); /* ERR: hr/min clash */ + else goto coltm2; /* Go handle SS */ + if(btoken.tbrk != ',' && btoken.tbrk != '/' + && (atoken=btoken, ptitoken(&atoken)) /* Peek */ + && ( atoken.tflg + ? !isdigit(*atoken.tcp) + : atoken.tval.ttmw->wflgs & TWTIME)) /* HHMM-ZON */ + goto hhmm4; + goto year4; /* Give up, assume year. */ + } + + /* From this point on, assume tcnt == 1 or 2 */ + /* 2 digits = MM, DD, or HH (MM and SS caught at coltime) */ + if(btoken.tbrk == ':') /* HH:MM[:SS] */ + goto coltime; /* must be part of time. */ + if (31 < i) + return 0; + + /* Check for numerical-format date */ + for (cp = "/-."; ch = *cp++;) + { ord = (ch == '.' ? 0 : 1); /* n/m = D/M or M/D */ + if(btoken.tbrk == ch) /* "NN-" */ + { if(btoken.tbrkl != ch) + { + atoken = btoken; + atoken.tcnt++; + if (ptitoken(&atoken) + && atoken.tflg == 0 + && atoken.tval.ttmw->wtype == TM_MON) + goto dd2; + if(ord)goto mm2; else goto dd2; /* "NN-" */ + } /* "-NN-" */ + if (!given(atm->tm_mday) + && given(atm->tm_year)) /* If "YYYY-NN-" */ + goto mm2; /* then always MM */ + if(ord)goto dd2; else goto mm2; + } + if(btoken.tbrkl == ch /* "-NN" */ + && given(ord ? atm->tm_mon : atm->tm_mday)) + if (!given(ord ? atm->tm_mday : atm->tm_mon)) /* MM/DD */ + if(ord)goto dd2; else goto mm2; + } + + /* Now reduced to choice between HH and DD */ + if (given(atm->tm_hour)) goto dd2; /* Have hour? Assume day. */ + if (given(atm->tm_mday)) goto hh2; /* Have day? Assume hour. */ + if (given(atm->tm_mon)) goto dd2; /* Have month? Assume day. */ + if(i > 24) goto dd2; /* Impossible HH means DD */ + atoken = btoken; + if (!ptitoken(&atoken)) /* Read ahead! */ + if(atoken.tval.tnum) return(0); /* ERR: bad token */ + else goto dd2; /* EOF, assume day. */ + if ( atoken.tflg + ? !isdigit(*atoken.tcp) + : atoken.tval.ttmw->wflgs & TWTIME) + /* If next token is a time spec, assume hour */ + goto hh2; /* e.g. "3 PM", "11-EDT" */ + +dd2: if (ptstash(&atm->tm_mday, i)) /* Store day (1 based) */ + return(0); + continue; + +mm2: if (ptstash(&atm->tm_mon, i-1)) /* Store month (make zero based) */ + return(0); + continue; + +year4: if ((i-=1900) < 0 || ptstash(&atm->tm_year, i)) /* Store year-1900 */ + return(0); /* ERR: year conflict */ + continue; + + /* Hack HH:MM[[:]SS] */ +coltime: + if (ptstash(&atm->tm_hour, i)) return 0; + if (!ptitoken(&btoken)) + return(!btoken.tval.tnum); + if(!btoken.tflg) return(0); /* ERR: HH: */ + if(btoken.tcnt == 4) /* MMSS */ + if (ptstash(&atm->tm_min, btoken.tval.tnum/100) + || ptstash(&atm->tm_sec, btoken.tval.tnum%100)) + return(0); + else continue; + if(btoken.tcnt != 2 + || ptstash(&atm->tm_min, btoken.tval.tnum)) + return(0); /* ERR: MM bad */ + if (btoken.tbrk != ':') continue; /* Seconds follow? */ +coltm2: if (!ptitoken(&btoken)) + return(!btoken.tval.tnum); + if(!btoken.tflg || btoken.tcnt != 2 /* Verify SS */ + || ptstash(&atm->tm_sec, btoken.tval.tnum)) + return(0); /* ERR: SS bad */ + } +} + +/* Store date/time value, return 0 if successful. + * Fail if entry is already set. + */ + static int +ptstash(adr,val) +int *adr; +int val; +{ register int *a; + if (given(*(a=adr))) + return 1; + *a = val; + return(0); +} + +/* This subroutine is invoked for AM, PM, NOON and MIDNIGHT when wrapping up + * just prior to returning from partime. + */ + static int +pt12hack(tm, aval) +register struct tm *tm; +register int aval; +{ register int h = tm->tm_hour; + switch (aval) { + case T12_AM: + case T12_PM: + if (h > 12) + return 0; + if (h == 12) + tm->tm_hour = 0; + if (aval == T12_PM) + tm->tm_hour += 12; + break; + default: + if (0 < tm->tm_min || 0 < tm->tm_sec) + return 0; + if (!given(h) || h==12) + tm->tm_hour = aval; + else if (aval==T12_MIDNIGHT && (h==0 || h==24)) + return 0; + } + return 1; +} + +/* Get a token and identify it to some degree. + * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise + * hit error of some sort + */ + + static int +ptitoken(tkp) +register struct token *tkp; +{ + register char const *cp; + register int i, j, k; + + if (!pttoken(tkp)) +#ifdef DEBUG + { + VOID printf("EOF\n"); + return(0); + } +#else + return(0); +#endif + cp = tkp->tcp; + +#ifdef DEBUG + VOID printf("Token: \"%.*s\" ", tkp->tcnt, cp); +#endif + + if (tkp->tflg) { + i = tkp->tcnt; + if (*cp == '+' || *cp == '-') { + cp++; + i--; + } + while (0 <= --i) { + j = tkp->tval.tnum*10; + k = j + (*cp++ - '0'); + if (j/10 != tkp->tval.tnum || k < j) { + /* arithmetic overflow */ + tkp->tval.tnum = 1; + return 0; + } + tkp->tval.tnum = k; + } + } else if (!(tkp->tval.ttmw = ptmatchstr(cp, tkp->tcnt, tmwords))) + { +#ifdef DEBUG + VOID printf("Not found!\n"); +#endif + tkp->tval.tnum = 1; + return 0; + } + +#ifdef DEBUG + if(tkp->tflg) + VOID printf("Val: %d.\n",tkp->tval.tnum); + else VOID printf("Found: \"%s\", val: %d, type %d\n", + tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype); +#endif + + return(1); +} + +/* Read token from input string into token structure */ + static int +pttoken(tkp) +register struct token *tkp; +{ + register char const *cp; + register int c; + char const *astr; + + tkp->tcp = astr = cp = tkp->tcp + tkp->tcnt; + tkp->tbrkl = tkp->tbrk; /* Set "last break" */ + tkp->tcnt = tkp->tbrk = tkp->tflg = 0; + tkp->tval.tnum = 0; + + while(c = *cp++) + { switch(c) + { case ' ': case '\t': /* Flush all whitespace */ + case '\r': case '\n': + case '\v': case '\f': + if (!tkp->tcnt) { /* If no token yet */ + tkp->tcp = cp; /* ignore the brk */ + continue; /* and go on. */ + } + /* fall into */ + case '(': case ')': /* Perhaps any non-alphanum */ + case '-': case ',': /* shd qualify as break? */ + case '+': + case '/': case ':': case '.': /* Break chars */ + if(tkp->tcnt == 0) /* If no token yet */ + { tkp->tcp = cp; /* ignore the brk */ + tkp->tbrkl = c; + continue; /* and go on. */ + } + tkp->tbrk = c; + return(tkp->tcnt); + } + if (!tkp->tcnt++) { /* If first char of token, */ + if (isdigit(c)) { + tkp->tflg = 1; + if (astrtcp--; + tkp->tcnt++; + } + } + } else if ((isdigit(c)!=0) != tkp->tflg) { /* else check type */ + tkp->tbrk = c; + return --tkp->tcnt; /* Wrong type, back up */ + } + } + return(tkp->tcnt); /* When hit EOF */ +} + + + static struct tmwent const * +ptmatchstr(astr,cnt,astruc) + char const *astr; + int cnt; + struct tmwent const *astruc; +{ + register char const *cp, *mp; + register int c; + struct tmwent const *lastptr; + int i; + + lastptr = 0; + for(;mp = astruc->went; astruc += 1) + { cp = astr; + for(i = cnt; i > 0; i--) + { + switch (*cp++ - (c = *mp++)) + { case 0: continue; /* Exact match */ + case 'A'-'a': + if (ctab[c] == Letter) + continue; + } + break; + } + if(i==0) + if (!*mp) return astruc; /* Exact match */ + else if(lastptr) return(0); /* Ambiguous */ + else lastptr = astruc; /* 1st ambig */ + } + return lastptr; +} diff --git a/gnu/usr.bin/rcs/lib/rcsbase.h b/gnu/usr.bin/rcs/lib/rcsbase.h new file mode 100644 index 0000000000..c0904bbfb8 --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcsbase.h @@ -0,0 +1,677 @@ + +/* + * RCS common definitions and data structures + */ +#define RCSBASE "$Id: rcsbase.h,v 5.11 1991/10/07 17:32:46 eggert Exp $" + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + +/***************************************************************************** + * INSTRUCTIONS: + * ============= + * See the Makefile for how to define C preprocessor symbols. + * If you need to change the comment leaders, update the table comtable[] + * in rcsfnms.c. (This can wait until you know what a comment leader is.) + ***************************************************************************** + */ + + +/* $Log: rcsbase.h,v $ + * Revision 5.11 1991/10/07 17:32:46 eggert + * Support piece tables even if !has_mmap. + * + * Revision 5.10 1991/09/24 00:28:39 eggert + * Remove unexported functions. + * + * Revision 5.9 1991/08/19 03:13:55 eggert + * Add piece tables and other tuneups, and NFS workarounds. + * + * Revision 5.8 1991/04/21 11:58:20 eggert + * Add -x, RCSINIT, MS-DOS support. + * + * Revision 5.7 1991/02/28 19:18:50 eggert + * Try setuid() if seteuid() doesn't work. + * + * Revision 5.6 1991/02/26 17:48:37 eggert + * Support new link behavior. Move ANSI C / Posix declarations into conf.sh. + * + * Revision 5.5 1990/12/04 05:18:43 eggert + * Use -I for prompts and -q for diagnostics. + * + * Revision 5.4 1990/11/01 05:03:35 eggert + * Don't assume that builtins are functions; they may be macros. + * Permit arbitrary data in logs. + * + * Revision 5.3 1990/09/26 23:36:58 eggert + * Port wait() to non-Posix ANSI C hosts. + * + * Revision 5.2 1990/09/04 08:02:20 eggert + * Don't redefine NAME_MAX, PATH_MAX. + * Improve incomplete line handling. Standardize yes-or-no procedure. + * + * Revision 5.1 1990/08/29 07:13:53 eggert + * Add -kkvl. Fix type typos exposed by porting. Clean old log messages too. + * + * Revision 5.0 1990/08/22 08:12:44 eggert + * Adjust ANSI C / Posix support. Add -k, -V, setuid. Don't call access(). + * Remove compile-time limits; use malloc instead. + * Ansify and Posixate. Add support for ISO 8859. + * Remove snoop and v2 support. + * + * Revision 4.9 89/05/01 15:17:14 narten + * botched previous USG fix + * + * Revision 4.8 89/05/01 14:53:05 narten + * changed #include -> string.h for USG systems. + * + * Revision 4.7 88/11/08 15:58:45 narten + * removed defs for functions loaded from libraries + * + * Revision 4.6 88/08/09 19:12:36 eggert + * Shrink stdio code size; remove lint; permit -Dhshsize=nn. + * + * Revision 4.5 87/12/18 17:06:41 narten + * made removed BSD ifdef, now uses V4_2BSD + * + * Revision 4.4 87/10/18 10:29:49 narten + * Updating version numbers + * Changes relative to 1.1 are actually relative to 4.2 + * + * Revision 1.3 87/09/24 14:02:25 narten + * changes for lint + * + * Revision 1.2 87/03/27 14:22:02 jenkins + * Port to suns + * + * Revision 4.2 83/12/20 16:04:20 wft + * merged 3.6.1.1 and 4.1 (SMALLOG, logsize). + * moved setting of STRICT_LOCKING to Makefile. + * changed DOLLAR to UNKN (conflict with KDELIM). + * + * Revision 4.1 83/05/04 09:12:41 wft + * Added markers Id and RCSfile. + * Added Dbranch for default branches. + * + * Revision 3.6.1.1 83/12/02 21:56:22 wft + * Increased logsize, added macro SMALLOG. + * + * Revision 3.6 83/01/15 16:43:28 wft + * 4.2 prerelease + * + * Revision 3.6 83/01/15 16:43:28 wft + * Replaced dbm.h with BYTESIZ, fixed definition of rindex(). + * Added variants of NCPFN and NCPPN for bsd 4.2, selected by defining V4_2BSD. + * Added macro DELNUMFORM to have uniform format for printing delta text nodes. + * Added macro DELETE to mark deleted deltas. + * + * Revision 3.5 82/12/10 12:16:56 wft + * Added two forms of DATEFORM, one using %02d, the other %.2d. + * + * Revision 3.4 82/12/04 20:01:25 wft + * added LOCKER, Locker, and USG (redefinition of rindex). + * + * Revision 3.3 82/12/03 12:22:04 wft + * Added dbm.h, stdio.h, RCSBASE, RCSSEP, RCSSUF, WORKMODE, TMPFILE3, + * PRINTDATE, PRINTTIME, map, and ctab; removed Suffix. Redefined keyvallength + * using NCPPN. Changed putc() to abort on write error. + * + * Revision 3.2 82/10/18 15:03:52 wft + * added macro STRICT_LOCKING, removed RCSUMASK. + * renamed JOINFILE[1,2] to JOINFIL[1,2]. + * + * Revision 3.1 82/10/11 19:41:17 wft + * removed NBPW, NBPC, NCPW. + * added typdef int void to aid compiling + */ + + +#include "conf.h" + + +#define EXIT_TROUBLE DIFF_TROUBLE + +#ifdef PATH_MAX +# define SIZEABLE_PATH PATH_MAX /* size of a large path; not a hard limit */ +#else +# define SIZEABLE_PATH _POSIX_PATH_MAX +#endif + +/* for traditional C hosts with unusual size arguments */ +#define Fread(p,s,n,f) fread(p, (freadarg_type)(s), (freadarg_type)(n), f) +#define Fwrite(p,s,n,f) fwrite(p, (freadarg_type)(s), (freadarg_type)(n), f) + + +/* + * Parameters + */ + +/* backwards compatibility with old versions of RCS */ +#define VERSION_min 3 /* old output RCS format supported */ +#define VERSION_max 5 /* newest output RCS format supported */ +#ifndef VERSION_DEFAULT /* default RCS output format */ +# define VERSION_DEFAULT VERSION_max +#endif +#define VERSION(n) ((n) - VERSION_DEFAULT) /* internally, 0 is the default */ + +#ifndef STRICT_LOCKING +#define STRICT_LOCKING 1 +#endif + /* 0 sets the default locking to non-strict; */ + /* used in experimental environments. */ + /* 1 sets the default locking to strict; */ + /* used in production environments. */ + +#define yearlength 16 /* (good through AD 9,999,999,999,999,999) */ +#define datesize (yearlength+16) /* size of output of DATEFORM */ +#define joinlength 20 /* number of joined revisions permitted */ +#define RCSTMPPREFIX '_' /* prefix for temp files in working dir */ +#define KDELIM '$' /* delimiter for keywords */ +#define VDELIM ':' /* separates keywords from values */ +#define DEFAULTSTATE "Exp" /* default state of revisions */ + + + +#define true 1 +#define false 0 +#define nil 0 + + +/* + * RILE - readonly file + * declarecache; - declares local cache for RILE variable(s) + * setupcache - sets up the local RILE cache, but does not initialize it + * cache, uncache - caches and uncaches the local RILE; + * (uncache,cache) is needed around functions that advance the RILE pointer + * Igeteof(f,c,s) - get a char c from f, executing statement s at EOF + * cachegeteof(c,s) - Igeteof applied to the local RILE + * Iget(f,c) - like Igeteof, except EOF is an error + * cacheget(c) - Iget applied to the local RILE + * Ifileno, Irewind, Iseek, Itell - analogs to stdio routines + */ + +#if large_memory + typedef unsigned char const *Iptr_type; + typedef struct { + Iptr_type ptr, lim; + unsigned char *base; /* for lint, not Iptr_type even if has_mmap */ +# if has_mmap +# define Ifileno(f) ((f)->fd) + int fd; +# else +# define Ifileno(f) fileno((f)->stream) + FILE *stream; + unsigned char *readlim; +# endif + } RILE; +# if has_mmap +# define declarecache register Iptr_type ptr, lim +# define setupcache(f) (lim = (f)->lim) +# define Igeteof(f,c,s) if ((f)->ptr==(f)->lim) s else (c)= *(f)->ptr++ +# define cachegeteof(c,s) if (ptr==lim) s else (c)= *ptr++ +# else +# define declarecache register Iptr_type ptr; register RILE *rRILE +# define setupcache(f) (rRILE = (f)) +# define Igeteof(f,c,s) if ((f)->ptr==(f)->readlim && !Igetmore(f)) s else (c)= *(f)->ptr++ +# define cachegeteof(c,s) if (ptr==rRILE->readlim && !Igetmore(rRILE)) s else (c)= *ptr++ +# endif +# define uncache(f) ((f)->ptr = ptr) +# define cache(f) (ptr = (f)->ptr) +# define Iget(f,c) Igeteof(f,c,Ieof();) +# define cacheget(c) cachegeteof(c,Ieof();) +# define Itell(f) ((f)->ptr) +# define Iseek(f,p) ((f)->ptr = (p)) +# define Irewind(f) Iseek(f, (f)->base) +# define cachetell() ptr +#else +# define RILE FILE +# define declarecache register FILE *ptr +# define setupcache(f) (ptr = (f)) +# define uncache(f) +# define cache(f) +# define Igeteof(f,c,s) if(((c)=getc(f))<0){testIerror(f);if(feof(f))s}else +# define cachegeteof(c,s) Igeteof(ptr,c,s) +# define Iget(f,c) if (((c)=getc(f))<0) testIeof(f); else +# define cacheget(c) Iget(ptr,c) +# define Ifileno(f) fileno(f) +#endif + +/* Print a char, but abort on write error. */ +#define aputc(c,o) if (putc(c,o)<0) testOerror(o); else + +/* Get a character from an RCS file, perhaps copying to a new RCS file. */ +#define GETCeof(o,c,s) { cachegeteof(c,s); if (o) aputc(c,o); } +#define GETC(o,c) { cacheget(c); if (o) aputc(c,o); } + + +#define WORKMODE(RCSmode, writable) ((RCSmode)&~(S_IWUSR|S_IWGRP|S_IWOTH) | ((writable)?S_IWUSR:0)) +/* computes mode of working file: same as RCSmode, but write permission */ +/* determined by writable */ + + +/* character classes and token codes */ +enum tokens { +/* classes */ DELIM, DIGIT, IDCHAR, NEWLN, LETTER, Letter, + PERIOD, SBEGIN, SPACE, UNKN, +/* tokens */ COLON, ID, NUM, SEMI, STRING +}; + +#define SDELIM '@' /* the actual character is needed for string handling*/ +/* SDELIM must be consistent with ctab[], so that ctab[SDELIM]==SBEGIN. + * there should be no overlap among SDELIM, KDELIM, and VDELIM + */ + +#define isdigit(c) ((unsigned)((c)-'0') <= 9) /* faster than ctab[c]==DIGIT */ + + + + + +/*************************************** + * Data structures for the symbol table + ***************************************/ + +/* Buffer of arbitrary data */ +struct buf { + char *string; + size_t size; +}; +struct cbuf { + char const *string; + size_t size; +}; + +/* Hash table entry */ +struct hshentry { + char const * num; /* pointer to revision number (ASCIZ) */ + char const * date; /* pointer to date of checkin */ + char const * author; /* login of person checking in */ + char const * lockedby; /* who locks the revision */ + char const * state; /* state of revision (Exp by default) */ + struct cbuf log; /* log message requested at checkin */ + struct branchhead * branches; /* list of first revisions on branches*/ + struct cbuf ig; /* ignored phrases of revision */ + struct hshentry * next; /* next revision on same branch */ + struct hshentry * nexthsh; /* next revision with same hash value */ + unsigned long insertlns;/* lines inserted (computed by rlog) */ + unsigned long deletelns;/* lines deleted (computed by rlog) */ + char selector; /* true if selected, false if deleted */ +}; + +/* list of hash entries */ +struct hshentries { + struct hshentries *rest; + struct hshentry *first; +}; + +/* list element for branch lists */ +struct branchhead { + struct hshentry * hsh; + struct branchhead * nextbranch; +}; + +/* accesslist element */ +struct access { + char const * login; + struct access * nextaccess; +}; + +/* list element for locks */ +struct lock { + char const * login; + struct hshentry * delta; + struct lock * nextlock; +}; + +/* list element for symbolic names */ +struct assoc { + char const * symbol; + char const * num; + struct assoc * nextassoc; +}; + + +#define mainArgs (argc,argv) int argc; char **argv; + +#if lint +# define libId(name,rcsid) +# define mainProg(name,cmd,rcsid) int name mainArgs +#else +# define libId(name,rcsid) char const name[] = rcsid; +# define mainProg(name,cmd,rcsid) char const copyright[] = "Copyright 1982,1988,1989 by Walter F. Tichy\nPurdue CS\nCopyright 1990,1991 by Paul Eggert", rcsbaseId[] = RCSBASE, cmdid[] = cmd; libId(name,rcsid) int main mainArgs +#endif + +/* + * Markers for keyword expansion (used in co and ident) + * Every byte must have class LETTER or Letter. + */ +#define AUTHOR "Author" +#define DATE "Date" +#define HEADER "Header" +#define IDH "Id" +#define LOCKER "Locker" +#define LOG "Log" +#define RCSFILE "RCSfile" +#define REVISION "Revision" +#define SOURCE "Source" +#define STATE "State" +#define keylength 8 /* max length of any of the above keywords */ + +enum markers { Nomatch, Author, Date, Header, Id, + Locker, Log, RCSfile, Revision, Source, State }; + /* This must be in the same order as rcskeys.c's Keyword[] array. */ + +#define DELNUMFORM "\n\n%s\n%s\n" +/* used by putdtext and scanlogtext */ + +#define EMPTYLOG "*** empty log message ***" /* used by ci and rlog */ + +/* main program */ +extern char const cmdid[]; +exiting void exiterr P((void)); + +/* maketime */ +int setfiledate P((char const*,char const[datesize])); +void str2date P((char const*,char[datesize])); +void time2date P((time_t,char[datesize])); + +/* merge */ +int merge P((int,char const*const[2],char const*const[3])); + +/* partime */ +int partime P((char const*,struct tm*,int*)); + +/* rcsedit */ +#define ciklogsize 23 /* sizeof("checked in with -k by ") */ +extern FILE *fcopy; +extern char const *resultfile; +extern char const ciklog[ciklogsize]; +extern int locker_expansion; +extern struct buf dirtfname[]; +#define newRCSfilename (dirtfname[0].string) +RILE *rcswriteopen P((struct buf*,struct stat*,int)); +char const *makedirtemp P((char const*,int)); +char const *getcaller P((void)); +int addlock P((struct hshentry*)); +int addsymbol P((char const*,char const*,int)); +int checkaccesslist P((void)); +int chnamemod P((FILE**,char const*,char const*,mode_t)); +int donerewrite P((int)); +int dorewrite P((int,int)); +int expandline P((RILE*,FILE*,struct hshentry const*,int,FILE*)); +int findlock P((int,struct hshentry**)); +void aflush P((FILE*)); +void copystring P((void)); +void dirtempunlink P((void)); +void enterstring P((void)); +void finishedit P((struct hshentry const*,FILE*,int)); +void keepdirtemp P((char const*)); +void openfcopy P((FILE*)); +void snapshotedit P((FILE*)); +void xpandstring P((struct hshentry const*)); +#if has_NFS || bad_unlink + int un_link P((char const*)); +#else +# define un_link(s) unlink(s) +#endif +#if large_memory + void edit_string P((void)); +# define editstring(delta) edit_string() +#else + void editstring P((struct hshentry const*)); +#endif + +/* rcsfcmp */ +int rcsfcmp P((RILE*,struct stat const*,char const*,struct hshentry const*)); + +/* rcsfnms */ +#define bufautobegin(b) ((void) ((b)->string = 0, (b)->size = 0)) +extern FILE *workstdout; +extern char *workfilename; +extern char const *RCSfilename; +extern char const *suffixes; +extern struct stat RCSstat; +RILE *rcsreadopen P((struct buf*,struct stat*,int)); +char *bufenlarge P((struct buf*,char const**)); +char const *basename P((char const*)); +char const *getfullRCSname P((void)); +char const *maketemp P((int)); +char const *rcssuffix P((char const*)); +int pairfilenames P((int,char**,RILE*(*)P((struct buf*,struct stat*,int)),int,int)); +size_t dirlen P((char const*)); +struct cbuf bufremember P((struct buf*,size_t)); +void bufalloc P((struct buf*,size_t)); +void bufautoend P((struct buf*)); +void bufrealloc P((struct buf*,size_t)); +void bufscat P((struct buf*,char const*)); +void bufscpy P((struct buf*,char const*)); +void tempunlink P((void)); + +/* rcsgen */ +extern int interactiveflag; +extern struct buf curlogbuf; +char const *buildrevision P((struct hshentries const*,struct hshentry*,FILE*,int)); +int getcstdin P((void)); +int ttystdin P((void)); +int yesorno P((int,char const*,...)); +struct cbuf cleanlogmsg P((char*,size_t)); +struct cbuf getsstdin P((char const*,char const*,char const*,struct buf*)); +void putdesc P((int,char*)); + +/* rcskeep */ +extern int prevkeys; +extern struct buf prevauthor, prevdate, prevrev, prevstate; +int getoldkeys P((RILE*)); + +/* rcskeys */ +extern char const *const Keyword[]; +enum markers trymatch P((char const*)); + +/* rcslex */ +extern FILE *foutptr; +extern FILE *frewrite; +extern RILE *finptr; +extern char const *NextString; +extern enum tokens nexttok; +extern int hshenter; +extern int nerror; +extern int nextc; +extern int quietflag; +extern unsigned long rcsline; +char const *getid P((void)); +exiting void efaterror P((char const*)); +exiting void enfaterror P((int,char const*)); +exiting void faterror P((char const*,...)); +exiting void fatserror P((char const*,...)); +exiting void Ieof P((void)); +exiting void Ierror P((void)); +exiting void Oerror P((void)); +char *checkid P((char*,int)); +int eoflex P((void)); +int getkeyopt P((char const*)); +int getlex P((enum tokens)); +struct cbuf getphrases P((char const*)); +struct cbuf savestring P((struct buf*)); +struct hshentry *getnum P((void)); +void Ifclose P((RILE*)); +void Izclose P((RILE**)); +void Lexinit P((void)); +void Ofclose P((FILE*)); +void Ozclose P((FILE**)); +void afputc P((int,FILE*)); +void aprintf P((FILE*,char const*,...)); +void aputs P((char const*,FILE*)); +void checksid P((char*)); +void diagnose P((char const*,...)); +void eerror P((char const*)); +void eflush P((void)); +void enerror P((int,char const*)); +void error P((char const*,...)); +void fvfprintf P((FILE*,char const*,va_list)); +void getkey P((char const*)); +void getkeystring P((char const*)); +void nextlex P((void)); +void oflush P((void)); +void printstring P((void)); +void readstring P((void)); +void redefined P((int)); +void testIerror P((FILE*)); +void testOerror P((FILE*)); +void warn P((char const*,...)); +void warnignore P((void)); +#if has_madvise && has_mmap && large_memory + void advise_access P((RILE*,int)); +# define if_advise_access(p,f,advice) if (p) advise_access(f,advice) +#else +# define advise_access(f,advice) +# define if_advise_access(p,f,advice) +#endif +#if has_mmap && large_memory + RILE *I_open P((char const*,struct stat*)); +# define Iopen(f,m,s) I_open(f,s) +#else + RILE *Iopen P((char const*,char const*,struct stat*)); +#endif +#if !large_memory + void testIeof P((FILE*)); + void Irewind P((RILE*)); +#endif + +/* rcsmap */ +extern const enum tokens ctab[]; + +/* rcsrev */ +char *partialno P((struct buf*,char const*,unsigned)); +char const *tiprev P((void)); +int cmpnum P((char const*,char const*)); +int cmpnumfld P((char const*,char const*,unsigned)); +int compartial P((char const*,char const*,unsigned)); +int expandsym P((char const*,struct buf*)); +int fexpandsym P((char const*,struct buf*,RILE*)); +struct hshentry *genrevs P((char const*,char const*,char const*,char const*,struct hshentries**)); +unsigned countnumflds P((char const*)); +void getbranchno P((char const*,struct buf*)); + +/* rcssyn */ +/* These expand modes must agree with Expand_names[] in rcssyn.c. */ +#define KEYVAL_EXPAND 0 /* -kkv `$Keyword: value $' */ +#define KEYVALLOCK_EXPAND 1 /* -kkvl `$Keyword: value locker $' */ +#define KEY_EXPAND 2 /* -kk `$Keyword$' */ +#define VAL_EXPAND 3 /* -kv `value' */ +#define OLD_EXPAND 4 /* -ko use old string, omitting expansion */ +struct diffcmd { + unsigned long + line1, /* number of first line */ + nlines, /* number of lines affected */ + adprev, /* previous 'a' line1+1 or 'd' line1 */ + dafter; /* sum of previous 'd' line1 and previous 'd' nlines */ +}; +extern char const * Dbranch; +extern struct access * AccessList; +extern struct assoc * Symbols; +extern struct cbuf Comment; +extern struct lock * Locks; +extern struct hshentry * Head; +extern int Expand; +extern int StrictLocks; +extern unsigned TotalDeltas; +extern char const *const expand_names[]; +extern char const Kdesc[]; +extern char const Klog[]; +extern char const Ktext[]; +int getdiffcmd P((RILE*,int,FILE*,struct diffcmd*)); +int putdftext P((char const*,struct cbuf,RILE*,FILE*,int)); +int putdtext P((char const*,struct cbuf,char const*,FILE*,int)); +int str2expmode P((char const*)); +void getadmin P((void)); +void getdesc P((int)); +void gettree P((void)); +void ignorephrase P((void)); +void initdiffcmd P((struct diffcmd*)); +void putadmin P((FILE*)); +void putstring P((FILE*,int,struct cbuf,int)); +void puttree P((struct hshentry const*,FILE*)); + +/* rcsutil */ +extern int RCSversion; +char *cgetenv P((char const*)); +char *fstr_save P((char const*)); +char *str_save P((char const*)); +char const *date2str P((char const[datesize],char[datesize])); +char const *getusername P((int)); +int getRCSINIT P((int,char**,char***)); +int run P((char const*,char const*,...)); +int runv P((char const**)); +malloc_type fremember P((malloc_type)); +malloc_type ftestalloc P((size_t)); +malloc_type testalloc P((size_t)); +malloc_type testrealloc P((malloc_type,size_t)); +#define ftalloc(T) ftnalloc(T,1) +#define talloc(T) tnalloc(T,1) +#if lint + extern malloc_type lintalloc; +# define ftnalloc(T,n) (lintalloc = ftestalloc(sizeof(T)*(n)), (T*)0) +# define tnalloc(T,n) (lintalloc = testalloc(sizeof(T)*(n)), (T*)0) +# define trealloc(T,p,n) (lintalloc = testrealloc((malloc_type)0, sizeof(T)*(n)), p) +# define tfree(p) +#else +# define ftnalloc(T,n) ((T*) ftestalloc(sizeof(T)*(n))) +# define tnalloc(T,n) ((T*) testalloc(sizeof(T)*(n))) +# define trealloc(T,p,n) ((T*) testrealloc((malloc_type)(p), sizeof(T)*(n))) +# define tfree(p) free((malloc_type)(p)) +#endif +void awrite P((char const*,size_t,FILE*)); +void fastcopy P((RILE*,FILE*)); +void ffree P((void)); +void ffree1 P((char const*)); +void setRCSversion P((char const*)); +#if has_signal + void catchints P((void)); + void ignoreints P((void)); + void restoreints P((void)); +#else +# define catchints() +# define ignoreints() +# define restoreints() +#endif +#if has_getuid + uid_t ruid P((void)); +# define myself(u) ((u) == ruid()) +#else +# define myself(u) true +#endif +#if has_setuid + uid_t euid P((void)); + void nosetid P((void)); + void seteid P((void)); + void setrid P((void)); +#else +# define nosetid() +# define seteid() +# define setrid() +#endif diff --git a/gnu/usr.bin/rcs/lib/rcsedit.c b/gnu/usr.bin/rcs/lib/rcsedit.c new file mode 100644 index 0000000000..fab4f62214 --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcsedit.c @@ -0,0 +1,1656 @@ +/* + * RCS stream editor + */ +/********************************************************************************** + * edits the input file according to a + * script from stdin, generated by diff -n + * performs keyword expansion + ********************************************************************************** + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + +/* $Log: rcsedit.c,v $ + * Revision 5.11 1991/11/03 01:11:44 eggert + * Move the warning about link breaking to where they're actually being broken. + * + * Revision 5.10 1991/10/07 17:32:46 eggert + * Support piece tables even if !has_mmap. Fix rare NFS bugs. + * + * Revision 5.9 1991/09/17 19:07:40 eggert + * SGI readlink() yields ENXIO, not EINVAL, for nonlinks. + * + * Revision 5.8 1991/08/19 03:13:55 eggert + * Add piece tables, NFS bug workarounds. Catch odd filenames. Tune. + * + * Revision 5.7 1991/04/21 11:58:21 eggert + * Fix errno bugs. Add -x, RCSINIT, MS-DOS support. + * + * Revision 5.6 1991/02/25 07:12:40 eggert + * Fix setuid bug. Support new link behavior. Work around broken "w+" fopen. + * + * Revision 5.5 1990/12/30 05:07:35 eggert + * Fix report of busy RCS files when !defined(O_CREAT) | !defined(O_EXCL). + * + * Revision 5.4 1990/11/01 05:03:40 eggert + * Permit arbitrary data in comment leaders. + * + * Revision 5.3 1990/09/11 02:41:13 eggert + * Tune expandline(). + * + * Revision 5.2 1990/09/04 08:02:21 eggert + * Count RCS lines better. Improve incomplete line handling. + * + * Revision 5.1 1990/08/29 07:13:56 eggert + * Add -kkvl. + * Fix bug when getting revisions to files ending in incomplete lines. + * Fix bug in comment leader expansion. + * + * Revision 5.0 1990/08/22 08:12:47 eggert + * Don't require final newline. + * Don't append "checked in with -k by " to logs, + * so that checking in a program with -k doesn't change it. + * Don't generate trailing white space for empty comment leader. + * Remove compile-time limits; use malloc instead. Add -k, -V. + * Permit dates past 1999/12/31. Make lock and temp files faster and safer. + * Ansify and Posixate. Check diff's output. + * + * Revision 4.8 89/05/01 15:12:35 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.7 88/11/08 13:54:14 narten + * misplaced semicolon caused infinite loop + * + * Revision 4.6 88/08/09 19:12:45 eggert + * Shrink stdio code size; allow cc -R. + * + * Revision 4.5 87/12/18 11:38:46 narten + * Changes from the 43. version. Don't know the significance of the + * first change involving "rewind". Also, additional "lint" cleanup. + * (Guy Harris) + * + * Revision 4.4 87/10/18 10:32:21 narten + * Updating version numbers. Changes relative to version 1.1 actually + * relative to 4.1 + * + * Revision 1.4 87/09/24 13:59:29 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.3 87/09/15 16:39:39 shepler + * added an initializatin of the variables editline and linecorr + * this will be done each time a file is processed. + * (there was an obscure bug where if co was used to retrieve multiple files + * it would dump) + * fix attributed to Roy Morris @FileNet Corp ...!felix!roy + * + * Revision 1.2 87/03/27 14:22:17 jenkins + * Port to suns + * + * Revision 4.1 83/05/12 13:10:30 wft + * Added new markers Id and RCSfile; added locker to Header and Id. + * Overhauled expandline completely() (problem with $01234567890123456789@). + * Moved trymatch() and marker table to rcskeys.c. + * + * Revision 3.7 83/05/12 13:04:39 wft + * Added retry to expandline to resume after failed match which ended in $. + * Fixed truncation problem for $19chars followed by@@. + * Log no longer expands full path of RCS file. + * + * Revision 3.6 83/05/11 16:06:30 wft + * added retry to expandline to resume after failed match which ended in $. + * Fixed truncation problem for $19chars followed by@@. + * + * Revision 3.5 82/12/04 13:20:56 wft + * Added expansion of keyword Locker. + * + * Revision 3.4 82/12/03 12:26:54 wft + * Added line number correction in case editing does not start at the + * beginning of the file. + * Changed keyword expansion to always print a space before closing KDELIM; + * Expansion for Header shortened. + * + * Revision 3.3 82/11/14 14:49:30 wft + * removed Suffix from keyword expansion. Replaced fclose with ffclose. + * keyreplace() gets log message from delta, not from curlogmsg. + * fixed expression overflow in while(c=putc(GETC.... + * checked nil printing. + * + * Revision 3.2 82/10/18 21:13:39 wft + * I added checks for write errors during the co process, and renamed + * expandstring() to xpandstring(). + * + * Revision 3.1 82/10/13 15:52:55 wft + * changed type of result of getc() from char to int. + * made keyword expansion loop in expandline() portable to machines + * without sign-extension. + */ + + +#include "rcsbase.h" + +libId(editId, "$Id: rcsedit.c,v 5.11 1991/11/03 01:11:44 eggert Exp $") + +static void keyreplace P((enum markers,struct hshentry const*,FILE*)); + + +FILE *fcopy; /* result file descriptor */ +char const *resultfile; /* result file name */ +int locker_expansion; /* should the locker name be appended to Id val? */ +#if !large_memory + static RILE *fedit; /* edit file descriptor */ + static char const *editfile; /* edit pathname */ +#endif +static unsigned long editline; /* edit line counter; #lines before cursor */ +static long linecorr; /* #adds - #deletes in each edit run. */ + /*used to correct editline in case file is not rewound after */ + /* applying one delta */ + +#define DIRTEMPNAMES 2 +enum maker {notmade, real, effective}; +struct buf dirtfname[DIRTEMPNAMES]; /* unlink these when done */ +static enum maker volatile dirtfmaker[DIRTEMPNAMES]; /* if these are set */ + + +#if has_NFS || bad_unlink + int +un_link(s) + char const *s; +/* + * Remove S, even if it is unwritable. + * Ignore unlink() ENOENT failures; NFS generates bogus ones. + */ +{ +# if bad_unlink + int e; + if (unlink(s) == 0) + return 0; + e = errno; +# if has_NFS + if (e == ENOENT) + return 0; +# endif + if (chmod(s, S_IWUSR) != 0) { + errno = e; + return -1; + } +# endif +# if has_NFS + return unlink(s)==0 || errno==ENOENT ? 0 : -1; +# else + return unlink(s); +# endif +} +#endif + +#if !has_rename +# if !has_NFS +# define do_link(s,t) link(s,t) +# else + static int +do_link(s, t) + char const *s, *t; +/* Link S to T, ignoring bogus EEXIST problems due to NFS failures. */ +{ + struct stat sb, tb; + + if (link(s,t) == 0) + return 0; + if (errno != EEXIST) + return -1; + if ( + stat(s, &sb) == 0 && + stat(t, &tb) == 0 && + sb.st_ino == tb.st_ino && + sb.st_dev == tb.st_dev + ) + return 0; + errno = EEXIST; + return -1; +} +# endif +#endif + + + static exiting void +editEndsPrematurely() +{ + fatserror("edit script ends prematurely"); +} + + static exiting void +editLineNumberOverflow() +{ + fatserror("edit script refers to line past end of file"); +} + + +#if large_memory + +#if has_memmove +# define movelines(s1, s2, n) VOID memmove(s1, s2, (n)*sizeof(Iptr_type)) +#else + static void +movelines(s1, s2, n) + register Iptr_type *s1; + register Iptr_type const *s2; + register unsigned long n; +{ + if (s1 < s2) + do { + *s1++ = *s2++; + } while (--n); + else { + s1 += n; + s2 += n; + do { + *--s1 = *--s2; + } while (--n); + } +} +#endif + +/* + * `line' contains pointers to the lines in the currently `edited' file. + * It is a 0-origin array that represents linelim-gapsize lines. + * line[0..gap-1] and line[gap+gapsize..linelim-1] contain pointers to lines. + * line[gap..gap+gapsize-1] contains garbage. + * + * Any @s in lines are duplicated. + * Lines are terminated by \n, or (for a last partial line only) by single @. + */ +static Iptr_type *line; +static unsigned long gap, gapsize, linelim; + + + static void +insertline(n, l) + unsigned long n; + Iptr_type l; +/* Before line N, insert line L. N is 0-origin. */ +{ + if (linelim-gapsize < n) + editLineNumberOverflow(); + if (!gapsize) + line = + !linelim ? + tnalloc(Iptr_type, linelim = gapsize = 1024) + : ( + gap = gapsize = linelim, + trealloc(Iptr_type, line, linelim <<= 1) + ); + if (n < gap) + movelines(line+n+gapsize, line+n, gap-n); + else if (gap < n) + movelines(line+gap, line+gap+gapsize, n-gap); + + line[n] = l; + gap = n + 1; + gapsize--; +} + + static void +deletelines(n, nlines) + unsigned long n, nlines; +/* Delete lines N through N+NLINES-1. N is 0-origin. */ +{ + unsigned long l = n + nlines; + if (linelim-gapsize < l || l < n) + editLineNumberOverflow(); + if (l < gap) + movelines(line+l+gapsize, line+l, gap-l); + else if (gap < n) + movelines(line+gap, line+gap+gapsize, n-gap); + + gap = n; + gapsize += nlines; +} + + static void +snapshotline(f, l) + register FILE *f; + register Iptr_type l; +{ + register int c; + do { + if ((c = *l++) == SDELIM && *l++ != SDELIM) + return; + aputc(c, f); + } while (c != '\n'); +} + + void +snapshotedit(f) + FILE *f; +/* Copy the current state of the edits to F. */ +{ + register Iptr_type *p, *lim, *l=line; + for (p=l, lim=l+gap; pdate; + RCSv = RCSversion; + + if (Expand == KEYVAL_EXPAND || Expand == KEYVALLOCK_EXPAND) + aprintf(out, "%c%s%c%c", KDELIM, sp, VDELIM, + marker==Log && RCSvauthor, out); + break; + case Date: + aputs(date2str(date,datebuf), out); + break; + case Id: + case Header: + aprintf(out, "%s %s %s %s %s", + marker==Id || RCSvnum, + date2str(date, datebuf), + delta->author, + RCSv==VERSION(3) && delta->lockedby ? "Locked" + : delta->state + ); + if (delta->lockedby!=nil) + if (VERSION(5) <= RCSv) { + if (locker_expansion || Expand==KEYVALLOCK_EXPAND) + aprintf(out, " %s", delta->lockedby); + } else if (RCSv == VERSION(4)) + aprintf(out, " Locker: %s", delta->lockedby); + break; + case Locker: + if (delta->lockedby) + if ( + locker_expansion + || Expand == KEYVALLOCK_EXPAND + || RCSv <= VERSION(4) + ) + aputs(delta->lockedby, out); + break; + case Log: + case RCSfile: + aputs(basename(RCSfilename), out); + break; + case Revision: + aputs(delta->num, out); + break; + case Source: + aputs(getfullRCSname(), out); + break; + case State: + aputs(delta->state, out); + break; + default: + break; + } + if (Expand == KEYVAL_EXPAND || Expand == KEYVALLOCK_EXPAND) { + afputc(' ', out); + afputc(KDELIM, out); + } + if (marker == Log) { + sp = delta->log.string; + ls = delta->log.size; + if (sizeof(ciklog)-1<=ls && !memcmp(sp,ciklog,sizeof(ciklog)-1)) + return; + afputc('\n', out); + cp = Comment.string; + cw = cs = Comment.size; + awrite(cp, cs, out); + /* oddity: 2 spaces between date and time, not 1 as usual */ + sp1 = strchr(date2str(date,datebuf), ' '); + aprintf(out, "Revision %s %.*s %s %s", + delta->num, (int)(sp1-datebuf), datebuf, sp1, delta->author + ); + /* Do not include state: it may change and is not updated. */ + /* Comment is the comment leader. */ + if (VERSION(5) <= RCSv) + for (; cw && (cp[cw-1]==' ' || cp[cw-1]=='\t'); --cw) + ; + for (;;) { + afputc('\n', out); + awrite(cp, cw, out); + if (!ls) + break; + --ls; + c = *sp++; + if (c != '\n') { + awrite(cp+cw, cs-cw, out); + do { + afputc(c,out); + if (!ls) + break; + --ls; + c = *sp++; + } while (c != '\n'); + } + } + } +} + +#if has_readlink + static int +resolve_symlink(L) + struct buf *L; +/* + * If L is a symbolic link, resolve it to the name that it points to. + * If unsuccessful, set errno and yield -1. + * If it points to an existing file, yield 1. + * Otherwise, set errno=ENOENT and yield 0. + */ +{ + char *b, a[SIZEABLE_PATH]; + int e; + size_t s; + ssize_t r; + struct buf bigbuf; + unsigned linkcount = MAXSYMLINKS + 1; + + b = a; + s = sizeof(a); + bufautobegin(&bigbuf); + while ((r = readlink(L->string,b,s)) != -1) + if (r == s) { + bufalloc(&bigbuf, s<<1); + b = bigbuf.string; + s = bigbuf.size; + } else if (!--linkcount) { + errno = ELOOP; + return -1; + } else { + /* Splice symbolic link into L. */ + b[r] = '\0'; + L->string[ROOTPATH(b) ? (size_t)0 : dirlen(L->string)] = '\0'; + bufscat(L, b); + } + e = errno; + bufautoend(&bigbuf); + errno = e; + switch (e) { + case ENXIO: + case EINVAL: return 1; + case ENOENT: return 0; + default: return -1; + } +} +#endif + + RILE * +rcswriteopen(RCSbuf, status, mustread) + struct buf *RCSbuf; + struct stat *status; + int mustread; +/* + * Create the lock file corresponding to RCSNAME. + * Then try to open RCSNAME for reading and yield its FILE* descriptor. + * Put its status into *STATUS too. + * MUSTREAD is true if the file must already exist, too. + * If all goes well, discard any previously acquired locks, + * and set frewrite to the FILE* descriptor of the lock file, + * which will eventually turn into the new RCS file. + */ +{ + register char *tp; + register char const *sp, *RCSname, *x; + RILE *f; + size_t l; + int e, exists, fdesc, previouslock, r; + struct buf *dirt; + struct stat statbuf; + + previouslock = frewrite != 0; + exists = +# if has_readlink + resolve_symlink(RCSbuf); +# else + stat(RCSbuf->string, &statbuf) == 0 ? 1 + : errno==ENOENT ? 0 : -1; +# endif + if (exists < (mustread|previouslock)) + /* + * There's an unusual problem with the RCS file; + * or the RCS file doesn't exist, + * and we must read or we already have a lock elsewhere. + */ + return 0; + + RCSname = RCSbuf->string; + sp = basename(RCSname); + l = sp - RCSname; + dirt = &dirtfname[previouslock]; + bufscpy(dirt, RCSname); + tp = dirt->string + l; + x = rcssuffix(RCSname); +# if has_readlink + if (!x) { + error("symbolic link to non RCS filename `%s'", RCSname); + errno = EINVAL; + return 0; + } +# endif + if (*sp == *x) { + error("RCS filename `%s' incompatible with suffix `%s'", sp, x); + errno = EINVAL; + return 0; + } + /* Create a lock file whose name is a function of the RCS filename. */ + if (*x) { + /* + * The suffix is nonempty. + * The lock filename is the first char of of the suffix, + * followed by the RCS filename with last char removed. E.g.: + * foo,v RCS filename with suffix ,v + * ,foo, lock filename + */ + *tp++ = *x; + while (*sp) + *tp++ = *sp++; + *--tp = 0; + } else { + /* + * The suffix is empty. + * The lock filename is the RCS filename + * with last char replaced by '_'. + */ + while ((*tp++ = *sp++)) + ; + tp -= 2; + if (*tp == '_') { + error("RCS filename `%s' ends with `%c'", RCSname, *tp); + errno = EINVAL; + return 0; + } + *tp = '_'; + } + + sp = tp = dirt->string; + + f = 0; + + /* + * good news: + * open(f, O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, READONLY) is atomic + * according to Posix 1003.1-1990. + * bad news: + * NFS ignores O_EXCL and doesn't comply with Posix 1003.1-1990. + * good news: + * (O_TRUNC,READONLY) normally guarantees atomicity even with NFS. + * bad news: + * If you're root, (O_TRUNC,READONLY) doesn't guarantee atomicity. + * good news: + * Root-over-the-wire NFS access is rare for security reasons. + * This bug has never been reported in practice with RCS. + * So we don't worry about this bug. + * + * An even rarer NFS bug can occur when clients retry requests. + * Suppose client A renames the lock file ",f," to "f,v" + * at about the same time that client B creates ",f,", + * and suppose A's first rename request is delayed, so A reissues it. + * The sequence of events might be: + * A sends rename(",f,", "f,v") + * B sends create(",f,") + * A sends retry of rename(",f,", "f,v") + * server receives, does, and acknowledges A's first rename() + * A receives acknowledgment, and its RCS program exits + * server receives, does, and acknowledges B's create() + * server receives, does, and acknowledges A's retry of rename() + * This not only wrongly deletes B's lock, it removes the RCS file! + * Most NFS implementations have idempotency caches that usually prevent + * this scenario, but such caches are finite and can be overrun. + * This problem afflicts programs that use the traditional + * Unix method of using link() and unlink() to get and release locks, + * as well as RCS's method of using open() and rename(). + * There is no easy workaround for either link-unlink or open-rename. + * Any new method based on lockf() seemingly would be incompatible with + * the old methods; besides, lockf() is notoriously buggy under NFS. + * Since this problem afflicts scads of Unix programs, but is so rare + * that nobody seems to be worried about it, we won't worry either. + */ +# define READONLY (S_IRUSR|S_IRGRP|S_IROTH) +# if !open_can_creat +# define create(f) creat(f, READONLY) +# else +# define create(f) open(f, O_BINARY|O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, READONLY) +# endif + + catchints(); + ignoreints(); + + /* + * Create a lock file for an RCS file. This should be atomic, i.e. + * if two processes try it simultaneously, at most one should succeed. + */ + seteid(); + fdesc = create(sp); + e = errno; + setrid(); + + if (fdesc < 0) { + if (e == EACCES && stat(tp,&statbuf) == 0) + /* The RCS file is busy. */ + e = EEXIST; + } else { + dirtfmaker[0] = effective; + e = ENOENT; + if (exists) { + f = Iopen(RCSname, FOPEN_R, status); + e = errno; + if (f && previouslock) { + /* Discard the previous lock in favor of this one. */ + Ozclose(&frewrite); + seteid(); + if ((r = un_link(newRCSfilename)) != 0) + e = errno; + setrid(); + if (r != 0) + enfaterror(e, newRCSfilename); + bufscpy(&dirtfname[0], tp); + } + } + if (!(frewrite = fdopen(fdesc, FOPEN_W))) { + efaterror(newRCSfilename); + } + } + + restoreints(); + + errno = e; + return f; +} + + void +keepdirtemp(name) + char const *name; +/* Do not unlink name, either because it's not there any more, + * or because it has already been unlinked. + */ +{ + register int i; + for (i=DIRTEMPNAMES; 0<=--i; ) + if (dirtfname[i].string == name) { + dirtfmaker[i] = notmade; + return; + } + faterror("keepdirtemp"); +} + + char const * +makedirtemp(name, n) + register char const *name; + int n; +/* + * Have maketemp() do all the work if name is null. + * Otherwise, create a unique filename in name's dir using n and name + * and store it into the dirtfname[n]. + * Because of storage in tfnames, dirtempunlink() can unlink the file later. + * Return a pointer to the filename created. + */ +{ + register char *tp, *np; + register size_t dl; + register struct buf *bn; + + if (!name) + return maketemp(n); + dl = dirlen(name); + bn = &dirtfname[n]; + bufalloc(bn, +# if has_mktemp + dl + 9 +# else + strlen(name) + 3 +# endif + ); + bufscpy(bn, name); + np = tp = bn->string; + tp += dl; + *tp++ = '_'; + *tp++ = '0'+n; + catchints(); +# if has_mktemp + VOID strcpy(tp, "XXXXXX"); + if (!mktemp(np) || !*np) + faterror("can't make temporary file name `%.*s%c_%cXXXXXX'", + (int)dl, name, SLASH, '0'+n + ); +# else + /* + * Posix 1003.1-1990 has no reliable way + * to create a unique file in a named directory. + * We fudge here. If the working file name is abcde, + * the temp filename is _Ncde where N is a digit. + */ + name += dl; + if (*name) name++; + if (*name) name++; + VOID strcpy(tp, name); +# endif + dirtfmaker[n] = real; + return np; +} + + void +dirtempunlink() +/* Clean up makedirtemp() files. May be invoked by signal handler. */ +{ + register int i; + enum maker m; + + for (i = DIRTEMPNAMES; 0 <= --i; ) + if ((m = dirtfmaker[i]) != notmade) { + if (m == effective) + seteid(); + VOID un_link(dirtfname[i].string); + if (m == effective) + setrid(); + dirtfmaker[i] = notmade; + } +} + + + int +#if has_prototypes +chnamemod(FILE **fromp, char const *from, char const *to, mode_t mode) + /* The `#if has_prototypes' is needed because mode_t might promote to int. */ +#else + chnamemod(fromp,from,to,mode) FILE **fromp; char const *from,*to; mode_t mode; +#endif +/* + * Rename a file (with optional stream pointer *FROMP) from FROM to TO. + * FROM already exists. + * Change its mode to MODE, before renaming if possible. + * If FROMP, close and clear *FROMP before renaming it. + * Unlink TO if it already exists. + * Return -1 on error (setting errno), 0 otherwise. + */ +{ +# if bad_a_rename + /* + * This host is brain damaged. A race condition is possible + * while the lock file is temporarily writable. + * There doesn't seem to be a workaround. + */ + mode_t mode_while_renaming = mode|S_IWUSR; +# else +# define mode_while_renaming mode +# endif + if (fromp) { +# if has_fchmod + if (fchmod(fileno(*fromp), mode_while_renaming) != 0) + return -1; +# endif + Ozclose(fromp); + } +# if has_fchmod + else +# endif + if (chmod(from, mode_while_renaming) != 0) + return -1; + +# if !has_rename || bad_b_rename + VOID un_link(to); + /* + * We need not check the result; + * link() or rename() will catch it. + * No harm is done if TO does not exist. + * However, there's a short window of inconsistency + * during which TO does not exist. + */ +# endif + + return +# if !has_rename + do_link(from,to) != 0 ? -1 : un_link(from) +# else + rename(from, to) != 0 +# if has_NFS + && errno != ENOENT +# endif + ? -1 +# if bad_a_rename + : mode != mode_while_renaming ? chmod(to, mode) +# endif + : 0 +# endif + ; + +# undef mode_while_renaming +} + + + + int +findlock(delete, target) + int delete; + struct hshentry **target; +/* + * Find the first lock held by caller and return a pointer + * to the locked delta; also removes the lock if DELETE. + * If one lock, put it into *TARGET. + * Return 0 for no locks, 1 for one, 2 for two or more. + */ +{ + register struct lock *next, **trail, **found; + + found = 0; + for (trail = &Locks; (next = *trail); trail = &next->nextlock) + if (strcmp(getcaller(), next->login) == 0) { + if (found) { + error("multiple revisions locked by %s; please specify one", getcaller()); + return 2; + } + found = trail; + } + if (!found) + return 0; + next = *found; + *target = next->delta; + if (delete) { + next->delta->lockedby = nil; + *found = next->nextlock; + } + return 1; +} + + int +addlock(delta) + struct hshentry * delta; +/* + * Add a lock held by caller to DELTA and yield 1 if successful. + * Print an error message and yield -1 if no lock is added because + * DELTA is locked by somebody other than caller. + * Return 0 if the caller already holds the lock. + */ +{ + register struct lock *next; + + next=Locks; + for (next = Locks; next; next = next->nextlock) + if (cmpnum(delta->num, next->delta->num) == 0) + if (strcmp(getcaller(), next->login) == 0) + return 0; + else { + error("revision %s already locked by %s", + delta->num, next->login + ); + return -1; + } + next = ftalloc(struct lock); + delta->lockedby = next->login = getcaller(); + next->delta = delta; + next->nextlock = Locks; + Locks = next; + return 1; +} + + + int +addsymbol(num, name, rebind) + char const *num, *name; + int rebind; +/* + * Associate with revision NUM the new symbolic NAME. + * If NAME already exists and REBIND is set, associate NAME with NUM; + * otherwise, print an error message and return false; + * Return true if successful. + */ +{ + register struct assoc *next; + + for (next = Symbols; next; next = next->nextassoc) + if (strcmp(name, next->symbol) == 0) + if (rebind || strcmp(next->num,num) == 0) { + next->num = num; + return true; + } else { + error("symbolic name %s already bound to %s", + name, next->num + ); + return false; + } + next = ftalloc(struct assoc); + next->symbol = name; + next->num = num; + next->nextassoc = Symbols; + Symbols = next; + return true; +} + + + + char const * +getcaller() +/* Get the caller's login name. */ +{ +# if has_setuid + return getusername(euid()!=ruid()); +# else + return getusername(false); +# endif +} + + + int +checkaccesslist() +/* + * Return true if caller is the superuser, the owner of the + * file, the access list is empty, or caller is on the access list. + * Otherwise, print an error message and return false. + */ +{ + register struct access const *next; + + if (!AccessList || myself(RCSstat.st_uid) || strcmp(getcaller(),"root")==0) + return true; + + next = AccessList; + do { + if (strcmp(getcaller(), next->login) == 0) + return true; + } while ((next = next->nextaccess)); + + error("user %s not on the access list", getcaller()); + return false; +} + + + int +dorewrite(lockflag, changed) + int lockflag, changed; +/* + * Do nothing if LOCKFLAG is zero. + * Prepare to rewrite an RCS file if CHANGED is positive. + * Stop rewriting if CHANGED is zero, because there won't be any changes. + * Fail if CHANGED is negative. + * Return true on success. + */ +{ + int r, e; + + if (lockflag) + if (changed) { + if (changed < 0) + return false; + putadmin(frewrite); + puttree(Head, frewrite); + aprintf(frewrite, "\n\n%s%c", Kdesc, nextc); + foutptr = frewrite; + } else { + Ozclose(&frewrite); + seteid(); + ignoreints(); + r = un_link(newRCSfilename); + e = errno; + keepdirtemp(newRCSfilename); + restoreints(); + setrid(); + if (r != 0) { + enerror(e, RCSfilename); + return false; + } + } + return true; +} + + int +donerewrite(changed) + int changed; +/* + * Finish rewriting an RCS file if CHANGED is nonzero. + * Return true on success. + */ +{ + int r, e; + + if (changed && !nerror) { + if (finptr) { + fastcopy(finptr, frewrite); + Izclose(&finptr); + } + if (1 < RCSstat.st_nlink) + warn("breaking hard link to %s", RCSfilename); + seteid(); + ignoreints(); + r = chnamemod(&frewrite, newRCSfilename, RCSfilename, + RCSstat.st_mode & ~(S_IWUSR|S_IWGRP|S_IWOTH) + ); + e = errno; + keepdirtemp(newRCSfilename); + restoreints(); + setrid(); + if (r != 0) { + enerror(e, RCSfilename); + error("saved in %s", newRCSfilename); + dirtempunlink(); + return false; + } + } + return true; +} + + void +aflush(f) + FILE *f; +{ + if (fflush(f) != 0) + Oerror(); +} diff --git a/gnu/usr.bin/rcs/lib/rcsfcmp.c b/gnu/usr.bin/rcs/lib/rcsfcmp.c new file mode 100644 index 0000000000..75a6bbce14 --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcsfcmp.c @@ -0,0 +1,321 @@ +/* + * RCS file comparison + */ +/***************************************************************************** + * rcsfcmp() + * Testprogram: define FCMPTEST + ***************************************************************************** + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + + + +/* $Log: rcsfcmp.c,v $ + * Revision 5.9 1991/10/07 17:32:46 eggert + * Count log lines correctly. + * + * Revision 5.8 1991/08/19 03:13:55 eggert + * Tune. + * + * Revision 5.7 1991/04/21 11:58:22 eggert + * Fix errno bug. Add MS-DOS support. + * + * Revision 5.6 1991/02/28 19:18:47 eggert + * Open work file at most once. + * + * Revision 5.5 1990/11/27 09:26:05 eggert + * Fix comment leader bug. + * + * Revision 5.4 1990/11/01 05:03:42 eggert + * Permit arbitrary data in logs and comment leaders. + * + * Revision 5.3 1990/09/11 02:41:15 eggert + * Don't ignore differences inside keyword strings if -ko is set. + * + * Revision 5.1 1990/08/29 07:13:58 eggert + * Clean old log messages too. + * + * Revision 5.0 1990/08/22 08:12:49 eggert + * Don't append "checked in with -k by " log to logs, + * so that checking in a program with -k doesn't change it. + * Ansify and Posixate. Remove lint. + * + * Revision 4.5 89/05/01 15:12:42 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.4 88/08/09 19:12:50 eggert + * Shrink stdio code size. + * + * Revision 4.3 87/12/18 11:40:02 narten + * lint cleanups (Guy Harris) + * + * Revision 4.2 87/10/18 10:33:06 narten + * updting version number. Changes relative to 1.1 actually relative to + * 4.1 + * + * Revision 1.2 87/03/27 14:22:19 jenkins + * Port to suns + * + * Revision 4.1 83/05/10 16:24:04 wft + * Marker matching now uses trymatch(). Marker pattern is now + * checked precisely. + * + * Revision 3.1 82/12/04 13:21:40 wft + * Initial revision. + * + */ + +/* +#define FCMPTEST +*/ +/* Testprogram; prints out whether two files are identical, + * except for keywords + */ + +#include "rcsbase.h" + +libId(fcmpId, "$Id: rcsfcmp.c,v 5.9 1991/10/07 17:32:46 eggert Exp $") + + static int +discardkeyval(c, f) + register int c; + register RILE *f; +{ + for (;;) + switch (c) { + case KDELIM: + case '\n': + return c; + default: + Igeteof(f, c, return EOF;); + break; + } +} + + int +rcsfcmp(xfp, xstatp, ufname, delta) + register RILE *xfp; + struct stat const *xstatp; + char const *ufname; + struct hshentry const *delta; +/* Compare the files xfp and ufname. Return zero + * if xfp has the same contents as ufname and neither has keywords, + * otherwise -1 if they are the same ignoring keyword values, + * and 1 if they differ even ignoring + * keyword values. For the LOG-keyword, rcsfcmp skips the log message + * given by the parameter delta in xfp. Thus, rcsfcmp returns nonpositive + * if xfp contains the same as ufname, with the keywords expanded. + * Implementation: character-by-character comparison until $ is found. + * If a $ is found, read in the marker keywords; if they are real keywords + * and identical, read in keyword value. If value is terminated properly, + * disregard it and optionally skip log message; otherwise, compare value. + */ +{ + register int xc, uc; + char xkeyword[keylength+2]; + int eqkeyvals; + register RILE *ufp; + register int xeof, ueof; + register char * tp; + register char const *sp; + int result; + enum markers match1; + struct stat ustat; + + if (!(ufp = Iopen(ufname, FOPEN_R_WORK, &ustat))) { + efaterror(ufname); + } + xeof = ueof = false; + if (Expand==OLD_EXPAND) { + if (!(result = xstatp->st_size!=ustat.st_size)) { +# if has_mmap && large_memory + result = !!memcmp(xfp->base,ufp->base,(size_t)xstatp->st_size); +# else + for (;;) { + /* get the next characters */ + Igeteof(xfp, xc, xeof=true;); + Igeteof(ufp, uc, ueof=true;); + if (xeof | ueof) + goto eof; + if (xc != uc) + goto return1; + } +# endif + } + } else { + xc = 0; + uc = 0; /* Keep lint happy. */ + result = 0; + + for (;;) { + if (xc != KDELIM) { + /* get the next characters */ + Igeteof(xfp, xc, xeof=true;); + Igeteof(ufp, uc, ueof=true;); + if (xeof | ueof) + goto eof; + } else { + /* try to get both keywords */ + tp = xkeyword; + for (;;) { + Igeteof(xfp, xc, xeof=true;); + Igeteof(ufp, uc, ueof=true;); + if (xeof | ueof) + goto eof; + if (xc != uc) + break; + switch (xc) { + default: + if (xkeyword+keylength <= tp) + break; + *tp++ = xc; + continue; + case '\n': case KDELIM: case VDELIM: + break; + } + break; + } + if ( + (xc==KDELIM || xc==VDELIM) && (uc==KDELIM || uc==VDELIM) && + (*tp = xc, (match1 = trymatch(xkeyword)) != Nomatch) + ) { +#ifdef FCMPTEST + VOID printf("found common keyword %s\n",xkeyword); +#endif + result = -1; + for (;;) { + if (xc != uc) { + xc = discardkeyval(xc, xfp); + uc = discardkeyval(uc, ufp); + if ((xeof = xc==EOF) | (ueof = uc==EOF)) + goto eof; + eqkeyvals = false; + break; + } + switch (xc) { + default: + Igeteof(xfp, xc, xeof=true;); + Igeteof(ufp, uc, ueof=true;); + if (xeof | ueof) + goto eof; + continue; + + case '\n': case KDELIM: + eqkeyvals = true; + break; + } + break; + } + if (xc != uc) + goto return1; + if (xc==KDELIM) { + /* Skip closing KDELIM. */ + Igeteof(xfp, xc, xeof=true;); + Igeteof(ufp, uc, ueof=true;); + if (xeof | ueof) + goto eof; + /* if the keyword is LOG, also skip the log message in xfp*/ + if (match1==Log) { + /* first, compute the number of line feeds in log msg */ + unsigned lncnt; + size_t ls, ccnt; + sp = delta->log.string; + ls = delta->log.size; + if (lssize < size) { + if (b->size) + tfree(b->string); + else + b->size = sizeof(malloc_type); + while (b->size < size) + b->size <<= 1; + b->string = tnalloc(char, b->size); + } +} + + void +bufrealloc(b, size) + register struct buf *b; + size_t size; +/* like bufalloc, except *B's old contents, if any, are preserved */ +{ + if (b->size < size) { + if (!b->size) + bufalloc(b, size); + else { + while ((b->size <<= 1) < size) + ; + b->string = trealloc(char, b->string, b->size); + } + } +} + + void +bufautoend(b) + struct buf *b; +/* Free an auto buffer at block exit. */ +{ + if (b->size) + tfree(b->string); +} + + struct cbuf +bufremember(b, s) + struct buf *b; + size_t s; +/* + * Free the buffer B with used size S. + * Yield a cbuf with identical contents. + * The cbuf will be reclaimed when this input file is finished. + */ +{ + struct cbuf cb; + + if ((cb.size = s)) + cb.string = fremember(trealloc(char, b->string, s)); + else { + bufautoend(b); /* not really auto */ + cb.string = ""; + } + return cb; +} + + char * +bufenlarge(b, alim) + register struct buf *b; + char const **alim; +/* Make *B larger. Set *ALIM to its new limit, and yield the relocated value + * of its old limit. + */ +{ + size_t s = b->size; + bufrealloc(b, s + 1); + *alim = b->string + b->size; + return b->string + s; +} + + void +bufscat(b, s) + struct buf *b; + char const *s; +/* Concatenate S to B's end. */ +{ + size_t blen = b->string ? strlen(b->string) : 0; + bufrealloc(b, blen+strlen(s)+1); + VOID strcpy(b->string+blen, s); +} + + void +bufscpy(b, s) + struct buf *b; + char const *s; +/* Copy S into B. */ +{ + bufalloc(b, strlen(s)+1); + VOID strcpy(b->string, s); +} + + + char const * +basename(p) + char const *p; +/* Yield the address of the base filename of the pathname P. */ +{ + register char const *b = p, *q = p; + for (;;) + switch (*q++) { + case SLASHes: b = q; break; + case 0: return b; + } +} + + size_t +dirlen(p) + char const *p; +/* Yield the length of P's directory, including its trailing SLASH. */ +{ + return basename(p) - p; +} + + + static size_t +suffixlen(x) + char const *x; +/* Yield the length of X, an RCS filename suffix. */ +{ + register char const *p; + + p = x; + for (;;) + switch (*p) { + case 0: case SLASHes: + return p - x; + + default: + ++p; + continue; + } +} + + char const * +rcssuffix(name) + char const *name; +/* Yield the suffix of NAME if it is an RCS filename, 0 otherwise. */ +{ + char const *x, *p, *nz; + size_t dl, nl, xl; + + nl = strlen(name); + nz = name + nl; + x = suffixes; + do { + if ((xl = suffixlen(x))) { + if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0) + return p; + } else { + dl = dirlen(name); + if ( + rcsdirlen < dl && + !memcmp(p = name+(dl-=rcsdirlen+1), rcsdir, rcsdirlen) && + (!dl || isSLASH(*--p)) + ) + return nz; + } + x += xl; + } while (*x++); + return 0; +} + + /*ARGSUSED*/ RILE * +rcsreadopen(RCSname, status, mustread) + struct buf *RCSname; + struct stat *status; + int mustread; +/* Open RCSNAME for reading and yield its FILE* descriptor. + * If successful, set *STATUS to its status. + * Pass this routine to pairfilenames() for read-only access to the file. */ +{ + return Iopen(RCSname->string, FOPEN_R, status); +} + + static int +finopen(rcsopen, mustread) + RILE *(*rcsopen)P((struct buf*,struct stat*,int)); + int mustread; +/* + * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read. + * Set finptr to the result and yield true if successful. + * RCSb holds the file's name. + * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno. + * Yield true if successful or if an unusual failure. + */ +{ + int interesting, preferold; + + /* + * We prefer an old name to that of a nonexisting new RCS file, + * unless we tried locking the old name and failed. + */ + preferold = RCSbuf.string[0] && (mustread||frewrite); + + finptr = (*rcsopen)(&RCSb, &RCSstat, mustread); + interesting = finptr || errno!=ENOENT; + if (interesting || !preferold) { + /* Use the new name. */ + RCSerrno = errno; + bufscpy(&RCSbuf, RCSb.string); + } + return interesting; +} + + static int +fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread) + char const *d, *base, *x; + size_t dlen, baselen, xlen; + RILE *(*rcsopen)P((struct buf*,struct stat*,int)); + int mustread; +/* + * D is a directory name with length DLEN (including trailing slash). + * BASE is a filename with length BASELEN. + * X is an RCS filename suffix with length XLEN. + * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read. + * Yield true if successful. + * Try dRCS/basex first; if that fails and x is nonempty, try dbasex. + * Put these potential names in RCSb. + * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno. + * Yield true if successful or if an unusual failure. + */ +{ + register char *p; + + bufalloc(&RCSb, dlen + rcsdirlen + 1 + baselen + xlen + 1); + + /* Try dRCS/basex. */ + VOID memcpy(p = RCSb.string, d, dlen); + VOID memcpy(p += dlen, rcsdir, rcsdirlen); + p += rcsdirlen; + *p++ = SLASH; + VOID memcpy(p, base, baselen); + VOID memcpy(p += baselen, x, xlen); + p[xlen] = 0; + if (xlen) { + if (finopen(rcsopen, mustread)) + return true; + + /* Try dbasex. */ + /* Start from scratch, because finopen() may have changed RCSb. */ + VOID memcpy(p = RCSb.string, d, dlen); + VOID memcpy(p += dlen, base, baselen); + VOID memcpy(p += baselen, x, xlen); + p[xlen] = 0; + } + return finopen(rcsopen, mustread); +} + + int +pairfilenames(argc, argv, rcsopen, mustread, quiet) + int argc; + char **argv; + RILE *(*rcsopen)P((struct buf*,struct stat*,int)); + int mustread, quiet; +/* Function: Pairs the filenames pointed to by argv; argc indicates + * how many there are. + * Places a pointer to the RCS filename into RCSfilename, + * and a pointer to the name of the working file into workfilename. + * If both the workfilename and the RCS filename are given, and workstdout + * is set, a warning is printed. + * + * If the RCS file exists, places its status into RCSstat. + * + * If the RCS file exists, it is RCSOPENed for reading, the file pointer + * is placed into finptr, and the admin-node is read in; returns 1. + * If the RCS file does not exist and MUSTREAD, + * print an error unless QUIET and return 0. + * Otherwise, initialize the admin node and return -1. + * + * 0 is returned on all errors, e.g. files that are not regular files. + */ +{ + static struct buf tempbuf; + + register char *p, *arg, *RCS1; + char const *purefname, *pureRCSname, *x; + int paired; + size_t arglen, dlen, baselen, xlen; + + if (!(arg = *argv)) return 0; /* already paired filename */ + if (*arg == '-') { + error("%s option is ignored after file names", arg); + return 0; + } + + purefname = basename(arg); + + /* Allocate buffer temporary to hold the default paired file name. */ + p = arg; + for (;;) { + switch (*p++) { + /* Beware characters that cause havoc with ci -k. */ + case KDELIM: + error("RCS file name `%s' contains %c", arg, KDELIM); + return 0; + case ' ': case '\n': case '\t': + error("RCS file name `%s' contains white space", arg); + return 0; + default: + continue; + case 0: + break; + } + break; + } + + paired = false; + + /* first check suffix to see whether it is an RCS file or not */ + if ((x = rcssuffix(arg))) + { + /* RCS file name given*/ + RCS1 = arg; + pureRCSname = purefname; + baselen = x - purefname; + if ( + 1 < argc && + !rcssuffix(workfilename = p = argv[1]) && + baselen <= (arglen = strlen(p)) && + ((p+=arglen-baselen) == workfilename || isSLASH(p[-1])) && + memcmp(purefname, p, baselen) == 0 + ) { + argv[1] = 0; + paired = true; + } else { + bufscpy(&tempbuf, purefname); + workfilename = p = tempbuf.string; + p[baselen] = 0; + } + } else { + /* working file given; now try to find RCS file */ + workfilename = arg; + baselen = p - purefname - 1; + /* derive RCS file name*/ + if ( + 1 < argc && + (x = rcssuffix(RCS1 = argv[1])) && + baselen <= x - RCS1 && + ((pureRCSname=x-baselen)==RCS1 || isSLASH(pureRCSname[-1])) && + memcmp(purefname, pureRCSname, baselen) == 0 + ) { + argv[1] = 0; + paired = true; + } else + pureRCSname = RCS1 = 0; + } + /* now we have a (tentative) RCS filename in RCS1 and workfilename */ + /* Second, try to find the right RCS file */ + if (pureRCSname!=RCS1) { + /* a path for RCSfile is given; single RCS file to look for */ + bufscpy(&RCSbuf, RCS1); + finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread); + RCSerrno = errno; + } else { + bufscpy(&RCSbuf, ""); + if (RCS1) + /* RCS file name was given without path. */ + VOID fin2open(arg, (size_t)0, pureRCSname, baselen, + x, strlen(x), rcsopen, mustread + ); + else { + /* No RCS file name was given. */ + /* Try each suffix in turn. */ + dlen = purefname-arg; + x = suffixes; + while (! fin2open(arg, dlen, purefname, baselen, + x, xlen=suffixlen(x), rcsopen, mustread + )) { + x += xlen; + if (!*x++) + break; + } + } + } + RCSfilename = p = RCSbuf.string; + if (finptr) { + if (!S_ISREG(RCSstat.st_mode)) { + error("%s isn't a regular file -- ignored", p); + return 0; + } + Lexinit(); getadmin(); + } else { + if (RCSerrno!=ENOENT || mustread || !frewrite) { + if (RCSerrno == EEXIST) + error("RCS file %s is in use", p); + else if (!quiet || RCSerrno!=ENOENT) + enerror(RCSerrno, p); + return 0; + } + InitAdmin(); + }; +# if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED + if (filenametoolong(p)) { + error("RCS file name %s is too long", p); + return 0; + } +# ifndef NAME_MAX + /* + * Check workfilename too, even though it cannot be longer, + * because it may reside on a different filesystem. + */ + if (filenametoolong(workfilename)) { + error("working file name %s is too long", workfilename); + return 0; + } +# endif +# endif + + if (paired && workstdout) + warn("Option -p is set; ignoring output file %s",workfilename); + + prevkeys = false; + return finptr ? 1 : -1; +} + + + char const * +getfullRCSname() +/* Function: returns a pointer to the full path name of the RCS file. + * Gets the working directory's name at most once. + * Removes leading "../" and "./". + */ +{ + static char const *wdptr; + static struct buf rcsbuf, wdbuf; + static size_t pathlength; + + register char const *realname; + register size_t parentdirlength; + register unsigned dotdotcounter; + register char *d; + register char const *wd; + + if (ROOTPATH(RCSfilename)) { + return(RCSfilename); + } else { + if (!(wd = wdptr)) { + /* Get working directory for the first time. */ + if (!(d = cgetenv("PWD"))) { + bufalloc(&wdbuf, SIZEABLE_PATH + 1); +# if !has_getcwd && has_getwd + d = getwd(wdbuf.string); +# else + while ( + !(d = getcwd(wdbuf.string, wdbuf.size)) + && errno==ERANGE + ) + bufalloc(&wdbuf, wdbuf.size<<1); +# endif + if (!d) + efaterror("working directory"); + } + parentdirlength = strlen(d); + while (parentdirlength && isSLASH(d[parentdirlength-1])) { + d[--parentdirlength] = 0; + /* Check needed because some getwd implementations */ + /* generate "/" for the root. */ + } + wdptr = wd = d; + pathlength = parentdirlength; + } + /*the following must be redone since RCSfilename may change*/ + /* Find how many `../'s to remove from RCSfilename. */ + dotdotcounter =0; + realname = RCSfilename; + while (realname[0]=='.') { + if (isSLASH(realname[1])) { + /* drop leading ./ */ + realname += 2; + } else if (realname[1]=='.' && isSLASH(realname[2])) { + /* drop leading ../ and remember */ + dotdotcounter++; + realname += 3; + } else + break; + } + /* Now remove dotdotcounter trailing directories from wd. */ + parentdirlength = pathlength; + while (dotdotcounter && parentdirlength) { + /* move pointer backwards over trailing directory */ + if (isSLASH(wd[--parentdirlength])) { + dotdotcounter--; + } + } + /* build full path name */ + bufalloc(&rcsbuf, parentdirlength+strlen(realname)+2); + d = rcsbuf.string; + VOID memcpy(d, wd, parentdirlength); + d += parentdirlength; + *d++ = SLASH; + VOID strcpy(d, realname); + return rcsbuf.string; + } +} + +#ifndef isSLASH + int +isSLASH(c) + int c; +{ + switch (c) { + case SLASHes: + return true; + default: + return false; + } +} +#endif + + +#if !has_getcwd && !has_getwd + + char * +getcwd(path, size) + char *path; + size_t size; +{ + static char const usrbinpwd[] = "/usr/bin/pwd"; +# define binpwd (usrbinpwd+4) + + register FILE *fp; + register int c; + register char *p, *lim; + int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus; + pid_t child; +# if !has_waitpid + pid_t w; +# endif + + if (!size) { + errno = EINVAL; + return 0; + } + if (pipe(fd) != 0) + return 0; + if (!(child = vfork())) { + if ( + close(fd[0]) == 0 && + (fd[1] == STDOUT_FILENO || +# ifdef F_DUPFD + (VOID close(STDOUT_FILENO), + fcntl(fd[1], F_DUPFD, STDOUT_FILENO)) +# else + dup2(fd[1], STDOUT_FILENO) +# endif + == STDOUT_FILENO && + close(fd[1]) == 0 + ) + ) { + VOID close(STDERR_FILENO); + VOID execl(binpwd, binpwd, (char *)0); + VOID execl(usrbinpwd, usrbinpwd, (char *)0); + } + _exit(EXIT_FAILURE); + } + e = errno; + closeerror = close(fd[1]); + closeerrno = errno; + fp = 0; + readerror = toolong = wstatus = 0; + p = path; + if (0 <= child) { + fp = fdopen(fd[0], "r"); + e = errno; + if (fp) { + lim = p + size; + for (p = path; ; *p++ = c) { + if ((c=getc(fp)) < 0) { + if (feof(fp)) + break; + if (ferror(fp)) { + readerror = 1; + e = errno; + break; + } + } + if (p == lim) { + toolong = 1; + break; + } + } + } +# if has_waitpid + if (waitpid(child, &wstatus, 0) < 0) + wstatus = 1; +# else + do { + if ((w = wait(&wstatus)) < 0) { + wstatus = 1; + break; + } + } while (w != child); +# endif + } + if (!fp) { + VOID close(fd[0]); + errno = e; + return 0; + } + if (fclose(fp) != 0) + return 0; + if (readerror) { + errno = e; + return 0; + } + if (closeerror) { + errno = closeerrno; + return 0; + } + if (toolong) { + errno = ERANGE; + return 0; + } + if (wstatus || p == path || *--p != '\n') { + errno = EACCES; + return 0; + } + *p = '\0'; + return path; +} +#endif + + +#ifdef PAIRTEST +/* test program for pairfilenames() and getfullRCSname() */ + +char const cmdid[] = "pair"; + +main(argc, argv) +int argc; char *argv[]; +{ + int result; + int initflag; + quietflag = initflag = false; + + while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { + switch ((*argv)[1]) { + + case 'p': workstdout = stdout; + break; + case 'i': initflag=true; + break; + case 'q': quietflag=true; + break; + default: error("unknown option: %s", *argv); + break; + } + } + + do { + RCSfilename=workfilename=nil; + result = pairfilenames(argc,argv,rcsreadopen,!initflag,quietflag); + if (result!=0) { + diagnose("RCS file: %s; working file: %s\nFull RCS file name: %s\n", + RCSfilename,workfilename,getfullRCSname() + ); + } + switch (result) { + case 0: continue; /* already paired file */ + + case 1: if (initflag) { + error("RCS file %s exists already",RCSfilename); + } else { + diagnose("RCS file %s exists\n",RCSfilename); + } + Ifclose(finptr); + break; + + case -1:diagnose("RCS file doesn't exist\n"); + break; + } + + } while (++argv, --argc>=1); + +} + + exiting void +exiterr() +{ + dirtempunlink(); + tempunlink(); + _exit(EXIT_FAILURE); +} +#endif diff --git a/gnu/usr.bin/rcs/lib/rcsgen.c b/gnu/usr.bin/rcs/lib/rcsgen.c new file mode 100644 index 0000000000..9a6072ea1b --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcsgen.c @@ -0,0 +1,432 @@ +/* + * RCS revision generation + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + +/* $Log: rcsgen.c,v $ + * Revision 5.10 1991/10/07 17:32:46 eggert + * Fix log bugs, e.g. ci -t/dev/null when has_mmap. + * + * Revision 5.9 1991/09/10 22:15:46 eggert + * Fix test for redirected stdin. + * + * Revision 5.8 1991/08/19 03:13:55 eggert + * Add piece tables. Tune. + * + * Revision 5.7 1991/04/21 11:58:24 eggert + * Add MS-DOS support. + * + * Revision 5.6 1990/12/27 19:54:26 eggert + * Fix bug: rcs -t inserted \n, making RCS file grow. + * + * Revision 5.5 1990/12/04 05:18:45 eggert + * Use -I for prompts and -q for diagnostics. + * + * Revision 5.4 1990/11/01 05:03:47 eggert + * Add -I and new -t behavior. Permit arbitrary data in logs. + * + * Revision 5.3 1990/09/21 06:12:43 hammer + * made putdesc() treat stdin the same whether or not it was from a terminal + * by making it recognize that a single '.' was then end of the + * description always + * + * Revision 5.2 1990/09/04 08:02:25 eggert + * Fix `co -p1.1 -ko' bug. Standardize yes-or-no procedure. + * + * Revision 5.1 1990/08/29 07:14:01 eggert + * Clean old log messages too. + * + * Revision 5.0 1990/08/22 08:12:52 eggert + * Remove compile-time limits; use malloc instead. + * Ansify and Posixate. + * + * Revision 4.7 89/05/01 15:12:49 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.6 88/08/28 14:59:10 eggert + * Shrink stdio code size; allow cc -R; remove lint; isatty() -> ttystdin() + * + * Revision 4.5 87/12/18 11:43:25 narten + * additional lint cleanups, and a bug fix from the 4.3BSD version that + * keeps "ci" from sticking a '\377' into the description if you run it + * with a zero-length file as the description. (Guy Harris) + * + * Revision 4.4 87/10/18 10:35:10 narten + * Updating version numbers. Changes relative to 1.1 actually relative to + * 4.2 + * + * Revision 1.3 87/09/24 13:59:51 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:27 jenkins + * Port to suns + * + * Revision 4.2 83/12/02 23:01:39 wft + * merged 4.1 and 3.3.1.1 (clearerr(stdin)). + * + * Revision 4.1 83/05/10 16:03:33 wft + * Changed putamin() to abort if trying to reread redirected stdin. + * Fixed getdesc() to output a prompt on initial newline. + * + * Revision 3.3.1.1 83/10/19 04:21:51 lepreau + * Added clearerr(stdin) for re-reading description from stdin. + * + * Revision 3.3 82/11/28 21:36:49 wft + * 4.2 prerelease + * + * Revision 3.3 82/11/28 21:36:49 wft + * Replaced ferror() followed by fclose() with ffclose(). + * Putdesc() now suppresses the prompts if stdin + * is not a terminal. A pointer to the current log message is now + * inserted into the corresponding delta, rather than leaving it in a + * global variable. + * + * Revision 3.2 82/10/18 21:11:26 wft + * I added checks for write errors during editing, and improved + * the prompt on putdesc(). + * + * Revision 3.1 82/10/13 15:55:09 wft + * corrected type of variables assigned to by getc (char --> int) + */ + + + + +#include "rcsbase.h" + +libId(genId, "$Id: rcsgen.c,v 5.10 1991/10/07 17:32:46 eggert Exp $") + +int interactiveflag; /* Should we act as if stdin is a tty? */ +struct buf curlogbuf; /* buffer for current log message */ + +enum stringwork { enter, copy, edit, expand, edit_expand }; +static void scandeltatext P((struct hshentry*,enum stringwork,int)); + + + + + char const * +buildrevision(deltas, target, outfile, expandflag) + struct hshentries const *deltas; + struct hshentry *target; + FILE *outfile; + int expandflag; +/* Function: Generates the revision given by target + * by retrieving all deltas given by parameter deltas and combining them. + * If outfile is set, the revision is output to it, + * otherwise written into a temporary file. + * Temporary files are allocated by maketemp(). + * if expandflag is set, keyword expansion is performed. + * Return nil if outfile is set, the name of the temporary file otherwise. + * + * Algorithm: Copy initial revision unchanged. Then edit all revisions but + * the last one into it, alternating input and output files (resultfile and + * editfile). The last revision is then edited in, performing simultaneous + * keyword substitution (this saves one extra pass). + * All this simplifies if only one revision needs to be generated, + * or no keyword expansion is necessary, or if output goes to stdout. + */ +{ + if (deltas->first == target) { + /* only latest revision to generate */ + openfcopy(outfile); + scandeltatext(target, expandflag?expand:copy, true); + if (outfile) + return 0; + else { + Ozclose(&fcopy); + return(resultfile); + } + } else { + /* several revisions to generate */ + /* Get initial revision without keyword expansion. */ + scandeltatext(deltas->first, enter, false); + while ((deltas=deltas->rest)->rest) { + /* do all deltas except last one */ + scandeltatext(deltas->first, edit, false); + } + if (expandflag || outfile) { + /* first, get to beginning of file*/ + finishedit((struct hshentry *)nil, outfile, false); + } + scandeltatext(deltas->first, expandflag?edit_expand:edit, true); + finishedit( + expandflag ? deltas->first : (struct hshentry*)nil, + outfile, true + ); + if (outfile) + return 0; + Ozclose(&fcopy); + return resultfile; + } +} + + + + static void +scandeltatext(delta, func, needlog) + struct hshentry * delta; + enum stringwork func; + int needlog; +/* Function: Scans delta text nodes up to and including the one given + * by delta. For the one given by delta, the log message is saved into + * delta->log if needlog is set; func specifies how to handle the text. + * Assumes the initial lexeme must be read in first. + * Does not advance nexttok after it is finished. + */ +{ + struct hshentry const *nextdelta; + struct cbuf cb; + + for (;;) { + if (eoflex()) + fatserror("can't find delta for revision %s", delta->num); + nextlex(); + if (!(nextdelta=getnum())) { + fatserror("delta number corrupted"); + } + getkeystring(Klog); + if (needlog && delta==nextdelta) { + cb = savestring(&curlogbuf); + delta->log = cleanlogmsg(curlogbuf.string, cb.size); + } else {readstring(); + } + nextlex(); + while (nexttok==ID && strcmp(NextString,Ktext)!=0) + ignorephrase(); + getkeystring(Ktext); + + if (delta==nextdelta) + break; + readstring(); /* skip over it */ + + } + switch (func) { + case enter: enterstring(); break; + case copy: copystring(); break; + case expand: xpandstring(delta); break; + case edit: editstring((struct hshentry *)nil); break; + case edit_expand: editstring(delta); break; + } +} + + struct cbuf +cleanlogmsg(m, s) + char *m; + size_t s; +{ + register char *t = m; + register char const *f = t; + struct cbuf r; + while (s) { + --s; + if ((*t++ = *f++) == '\n') + while (m < --t) + if (t[-1]!=' ' && t[-1]!='\t') { + *t++ = '\n'; + break; + } + } + while (m < t && (t[-1]==' ' || t[-1]=='\t' || t[-1]=='\n')) + --t; + r.string = m; + r.size = t - m; + return r; +} + + +int ttystdin() +{ + static int initialized; + if (!initialized) { + if (!interactiveflag) + interactiveflag = isatty(STDIN_FILENO); + initialized = true; + } + return interactiveflag; +} + + int +getcstdin() +{ + register FILE *in; + register int c; + + in = stdin; + if (feof(in) && ttystdin()) + clearerr(in); + c = getc(in); + if (c < 0) { + testIerror(in); + if (feof(in) && ttystdin()) + afputc('\n',stderr); + } + return c; +} + +#if has_prototypes + int +yesorno(int default_answer, char const *question, ...) +#else + /*VARARGS2*/ int + yesorno(default_answer, question, va_alist) + int default_answer; char const *question; va_dcl +#endif +{ + va_list args; + register int c, r; + if (!quietflag && ttystdin()) { + oflush(); + vararg_start(args, question); + fvfprintf(stderr, question, args); + va_end(args); + eflush(); + r = c = getcstdin(); + while (c!='\n' && !feof(stdin)) + c = getcstdin(); + if (r=='y' || r=='Y') + return true; + if (r=='n' || r=='N') + return false; + } + return default_answer; +} + + + void +putdesc(textflag, textfile) + int textflag; + char *textfile; +/* Function: puts the descriptive text into file frewrite. + * if finptr && !textflag, the text is copied from the old description. + * Otherwise, if the textfile!=nil, the text is read from that + * file, or from stdin, if textfile==nil. + * A textfile with a leading '-' is treated as a string, not a file name. + * If finptr, the old descriptive text is discarded. + * Always clears foutptr. + */ +{ + static struct buf desc; + static struct cbuf desclean; + + register FILE *txt; + register int c; + register FILE * frew; + register char *p; + register size_t s; + char const *plim; + + frew = frewrite; + if (finptr && !textflag) { + /* copy old description */ + aprintf(frew, "\n\n%s%c", Kdesc, nextc); + foutptr = frewrite; + getdesc(false); + foutptr = 0; + } else { + foutptr = 0; + /* get new description */ + if (finptr) { + /*skip old description*/ + getdesc(false); + } + aprintf(frew,"\n\n%s\n%c",Kdesc,SDELIM); + if (!textfile) + desclean = getsstdin( + "t-", "description", + "NOTE: This is NOT the log message!\n", &desc + ); + else if (!desclean.string) { + if (*textfile == '-') { + p = textfile + 1; + s = strlen(p); + } else { + if (!(txt = fopen(textfile, "r"))) + efaterror(textfile); + bufalloc(&desc, 1); + p = desc.string; + plim = p + desc.size; + for (;;) { + if ((c=getc(txt)) < 0) { + testIerror(txt); + if (feof(txt)) + break; + } + if (plim <= p) + p = bufenlarge(&desc, &plim); + *p++ = c; + } + if (fclose(txt) != 0) + Ierror(); + s = p - desc.string; + p = desc.string; + } + desclean = cleanlogmsg(p, s); + } + putstring(frew, false, desclean, true); + aputc('\n', frew); + } +} + + struct cbuf +getsstdin(option, name, note, buf) + char const *option, *name, *note; + struct buf *buf; +{ + register int c; + register char *p; + register size_t i; + register int tty = ttystdin(); + + if (tty) + aprintf(stderr, + "enter %s, terminated with single '.' or end of file:\n%s>> ", + name, note + ); + else if (feof(stdin)) + faterror("can't reread redirected stdin for %s; use -%s<%s>", + name, option, name + ); + + for ( + i = 0, p = 0; + c = getcstdin(), !feof(stdin); + bufrealloc(buf, i+1), p = buf->string, p[i++] = c + ) + if (c == '\n') + if (i && p[i-1]=='.' && (i==1 || p[i-2]=='\n')) { + /* Remove trailing '.'. */ + --i; + break; + } else if (tty) + aputs(">> ", stderr); + return cleanlogmsg(p, i); +} diff --git a/gnu/usr.bin/rcs/lib/rcskeep.c b/gnu/usr.bin/rcs/lib/rcskeep.c new file mode 100644 index 0000000000..1a0c78f25c --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcskeep.c @@ -0,0 +1,422 @@ +/* + * RCS keyword extraction + */ +/***************************************************************************** + * main routine: getoldkeys() + * Testprogram: define KEEPTEST + ***************************************************************************** + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + +/* $Log: rcskeep.c,v $ + * Revision 5.4 1991/08/19 03:13:55 eggert + * Tune. + * + * Revision 5.3 1991/04/21 11:58:25 eggert + * Shorten names to keep them distinct on shortname hosts. + * + * Revision 5.2 1990/10/04 06:30:20 eggert + * Parse time zone offsets; future RCS versions may output them. + * + * Revision 5.1 1990/09/20 02:38:56 eggert + * ci -k now checks dates more thoroughly. + * + * Revision 5.0 1990/08/22 08:12:53 eggert + * Retrieve old log message if there is one. + * Don't require final newline. + * Remove compile-time limits; use malloc instead. Tune. + * Permit dates past 1999/12/31. Ansify and Posixate. + * + * Revision 4.6 89/05/01 15:12:56 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.5 88/08/09 19:13:03 eggert + * Remove lint and speed up by making FILE *fp local, not global. + * + * Revision 4.4 87/12/18 11:44:21 narten + * more lint cleanups (Guy Harris) + * + * Revision 4.3 87/10/18 10:35:50 narten + * Updating version numbers. Changes relative to 1.1 actually relative + * to 4.1 + * + * Revision 1.3 87/09/24 14:00:00 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:29 jenkins + * Port to suns + * + * Revision 4.1 83/05/10 16:26:44 wft + * Added new markers Id and RCSfile; extraction added. + * Marker matching with trymatch(). + * + * Revision 3.2 82/12/24 12:08:26 wft + * added missing #endif. + * + * Revision 3.1 82/12/04 13:22:41 wft + * Initial revision. + * + */ + +/* +#define KEEPTEST +*/ +/* Testprogram; prints out the keyword values found. */ + +#include "rcsbase.h" + +libId(keepId, "$Id: rcskeep.c,v 5.4 1991/08/19 03:13:55 eggert Exp $") + +static int checknum P((char const*,int)); +static int getval P((RILE*,struct buf*,int)); +static int get0val P((int,RILE*,struct buf*,int)); +static int keepdate P((RILE*)); +static int keepid P((int,RILE*,struct buf*)); +static int keeprev P((RILE*)); + +int prevkeys; +struct buf prevauthor, prevdate, prevrev, prevstate; + + int +getoldkeys(fp) + register RILE *fp; +/* Function: Tries to read keyword values for author, date, + * revision number, and state out of the file fp. + * If FNAME is nonnull, it is opened and closed instead of using FP. + * The results are placed into + * prevauthor, prevdate, prevrev, prevstate. + * Aborts immediately if it finds an error and returns false. + * If it returns true, it doesn't mean that any of the + * values were found; instead, check to see whether the corresponding arrays + * contain the empty string. + */ +{ + register int c; + char keyword[keylength+1]; + register char * tp; + int needs_closing; + + if (prevkeys) + return true; + + needs_closing = false; + if (!fp) { + if (!(fp = Iopen(workfilename, FOPEN_R_WORK, (struct stat*)0))) { + eerror(workfilename); + return false; + } + needs_closing = true; + } + + /* initialize to empty */ + bufscpy(&prevauthor, ""); + bufscpy(&prevdate, ""); + bufscpy(&prevrev, ""); + bufscpy(&prevstate, ""); + + c = '\0'; /* anything but KDELIM */ + for (;;) { + if ( c==KDELIM) { + do { + /* try to get keyword */ + tp = keyword; + for (;;) { + Igeteof(fp, c, goto ok;); + switch (c) { + default: + if (keyword+keylength <= tp) + break; + *tp++ = c; + continue; + + case '\n': case KDELIM: case VDELIM: + break; + } + break; + } + } while (c==KDELIM); + if (c!=VDELIM) continue; + *tp = c; + Igeteof(fp, c, break;); + switch (c) { + case ' ': case '\t': break; + default: continue; + } + + switch (trymatch(keyword)) { + case Author: + if (!keepid(0, fp, &prevauthor)) + return false; + c = 0; + break; + case Date: + if (!(c = keepdate(fp))) + return false; + break; + case Header: + case Id: + if (!( + getval(fp, (struct buf*)nil, false) && + keeprev(fp) && + (c = keepdate(fp)) && + keepid(c, fp, &prevauthor) && + keepid(0, fp, &prevstate) + )) + return false; + /* Skip either ``who'' (new form) or ``Locker: who'' (old). */ + if (getval(fp, (struct buf*)nil, true) && + getval(fp, (struct buf*)nil, true)) + c = 0; + else if (nerror) + return false; + else + c = KDELIM; + break; + case Locker: + case Log: + case RCSfile: + case Source: + if (!getval(fp, (struct buf*)nil, false)) + return false; + c = 0; + break; + case Revision: + if (!keeprev(fp)) + return false; + c = 0; + break; + case State: + if (!keepid(0, fp, &prevstate)) + return false; + c = 0; + break; + default: + continue; + } + if (!c) + Igeteof(fp, c, c=0;); + if (c != KDELIM) { + error("closing %c missing on keyword", KDELIM); + return false; + } + if (*prevauthor.string && *prevdate.string && *prevrev.string && *prevstate.string) { + break; + } + } + Igeteof(fp, c, break;); + } + + ok: + if (needs_closing) + Ifclose(fp); + else + Irewind(fp); + prevkeys = true; + return true; +} + + static int +badly_terminated() +{ + error("badly terminated keyword value"); + return false; +} + + static int +getval(fp, target, optional) + register RILE *fp; + struct buf *target; + int optional; +/* Reads a keyword value from FP into TARGET. + * Returns true if one is found, false otherwise. + * Does not modify target if it is nil. + * Do not report an error if OPTIONAL is set and KDELIM is found instead. + */ +{ + int c; + Igeteof(fp, c, return badly_terminated();); + return get0val(c, fp, target, optional); +} + + static int +get0val(c, fp, target, optional) + register int c; + register RILE *fp; + struct buf *target; + int optional; +/* Reads a keyword value from C+FP into TARGET, perhaps OPTIONALly. + * Same as getval, except C is the lookahead character. + */ +{ register char * tp; + char const *tlim; + register int got1; + + if (target) { + bufalloc(target, 1); + tp = target->string; + tlim = tp + target->size; + } else + tlim = tp = 0; + got1 = false; + for (;;) { + switch (c) { + default: + got1 = true; + if (tp) { + *tp++ = c; + if (tlim <= tp) + tp = bufenlarge(target, &tlim); + } + break; + + case ' ': + case '\t': + if (tp) { + *tp = 0; +# ifdef KEEPTEST + VOID printf("getval: %s\n", target); +# endif + } + if (!got1) + error("too much white space in keyword value"); + return got1; + + case KDELIM: + if (!got1 && optional) + return false; + /* fall into */ + case '\n': + case 0: + return badly_terminated(); + } + Igeteof(fp, c, return badly_terminated();); + } +} + + + static int +keepdate(fp) + RILE *fp; +/* Function: reads a date prevdate; checks format + * Return 0 on error, lookahead character otherwise. + */ +{ + struct buf prevday, prevtime, prevzone; + register char const *p; + register int c; + + c = 0; + bufautobegin(&prevday); + if (getval(fp,&prevday,false)) { + bufautobegin(&prevtime); + if (getval(fp,&prevtime,false)) { + bufautobegin(&prevzone); + bufscpy(&prevzone, ""); + Igeteof(fp, c, c=0;); + if (c=='-' || c=='+') + if (!get0val(c,fp,&prevzone,false)) + c = 0; + else + Igeteof(fp, c, c=0;); + if (c) { + p = prevday.string; + bufalloc(&prevdate, strlen(p) + strlen(prevtime.string) + strlen(prevzone.string) + 5); + VOID sprintf(prevdate.string, "%s%s %s %s", + /* Parse dates put out by old versions of RCS. */ + isdigit(p[0]) && isdigit(p[1]) && p[2]=='/' ? "19" : "", + p, prevtime.string, prevzone.string + ); + } + bufautoend(&prevzone); + } + bufautoend(&prevtime); + } + bufautoend(&prevday); + return c; +} + + static int +keepid(c, fp, b) + int c; + RILE *fp; + struct buf *b; +/* Get previous identifier from C+FP into B. */ +{ + if (!c) + Igeteof(fp, c, return false;); + if (!get0val(c, fp, b, false)) + return false; + checksid(b->string); + return true; +} + + static int +keeprev(fp) + RILE *fp; +/* Get previous revision from FP into prevrev. */ +{ + return getval(fp,&prevrev,false) && checknum(prevrev.string,-1); +} + + + static int +checknum(sp,fields) + register char const *sp; + int fields; +{ register int dotcount; + dotcount=0; + while(*sp) { + if (*sp=='.') dotcount++; + else if (!isdigit(*sp)) return false; + sp++; + } + return fields<0 ? dotcount&1 : dotcount==fields; +} + + + +#ifdef KEEPTEST + +char const cmdid[] ="keeptest"; + + int +main(argc, argv) +int argc; char *argv[]; +{ + while (*(++argv)) { + workfilename = *argv; + getoldkeys((RILE*)0); + VOID printf("%s: revision: %s, date: %s, author: %s, state: %s\n", + *argv, prevrev.string, prevdate.string, prevauthor.string, prevstate.string); + } + exitmain(EXIT_SUCCESS); +} +#endif diff --git a/gnu/usr.bin/rcs/lib/rcskeys.c b/gnu/usr.bin/rcs/lib/rcskeys.c new file mode 100644 index 0000000000..82850a7311 --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcskeys.c @@ -0,0 +1,102 @@ +/* + * RCS keyword table and match operation + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + +/* $Log: rcskeys.c,v $ + * 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.) + * + * Revision 5.1 1991/04/21 11:58:25 eggert + * Don't put , just before } in initializer. + * + * Revision 5.0 1990/08/22 08:12:54 eggert + * Add -k. Ansify and Posixate. + * + * Revision 4.3 89/05/01 15:13:02 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.2 87/10/18 10:36:33 narten + * Updating version numbers. Changes relative to 1.1 actuallyt + * relative to 4.1 + * + * Revision 1.2 87/09/24 14:00:10 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 4.1 83/05/04 10:06:53 wft + * Initial revision. + * + */ + + +#include "rcsbase.h" + +libId(keysId, "$Id: rcskeys.c,v 5.2 1991/08/19 03:13:55 eggert Exp $") + + +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 +}; + + + + enum markers +trymatch(string) + char const *string; +/* function: Checks whether string starts with a keyword followed + * by a KDELIM or a VDELIM. + * If successful, returns the appropriate marker, otherwise Nomatch. + */ +{ + register int j; + register char const *p, *s; + for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); ) { + /* try next keyword */ + p = Keyword[j]; + s = string; + while (*p++ == *s++) { + if (!*p) + switch (*s) { + case KDELIM: + case VDELIM: + return (enum markers)j; + default: + return Nomatch; + } + } + } + return(Nomatch); +} + diff --git a/gnu/usr.bin/rcs/lib/rcslex.c b/gnu/usr.bin/rcs/lib/rcslex.c new file mode 100644 index 0000000000..51e31f3445 --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcslex.c @@ -0,0 +1,1241 @@ +/* + * RCS file input + */ +/********************************************************************************* + * Lexical Analysis. + * hashtable, Lexinit, nextlex, getlex, getkey, + * getid, getnum, readstring, printstring, savestring, + * checkid, fatserror, error, faterror, warn, diagnose + * Testprogram: define LEXDB + ********************************************************************************* + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + +/* $Log: rcslex.c,v $ + * Revision 5.11 1991/11/03 03:30:44 eggert + * Fix porting bug to ancient hosts lacking vfprintf. + * + * Revision 5.10 1991/10/07 17:32:46 eggert + * Support piece tables even if !has_mmap. + * + * Revision 5.9 1991/09/24 00:28:42 eggert + * Don't export errsay(). + * + * Revision 5.8 1991/08/19 03:13:55 eggert + * Add eoflex(), mmap support. Tune. + * + * Revision 5.7 1991/04/21 11:58:26 eggert + * Add MS-DOS support. + * + * Revision 5.6 1991/02/25 07:12:42 eggert + * Work around fputs bug. strsave -> str_save (DG/UX name clash) + * + * Revision 5.5 1990/12/04 05:18:47 eggert + * Use -I for prompts and -q for diagnostics. + * + * Revision 5.4 1990/11/19 20:05:28 hammer + * no longer gives warning about unknown keywords if -q is specified + * + * Revision 5.3 1990/11/01 05:03:48 eggert + * When ignoring unknown phrases, copy them to the output RCS file. + * + * Revision 5.2 1990/09/04 08:02:27 eggert + * Count RCS lines better. + * + * Revision 5.1 1990/08/29 07:14:03 eggert + * Work around buggy compilers with defective argument promotion. + * + * Revision 5.0 1990/08/22 08:12:55 eggert + * Remove compile-time limits; use malloc instead. + * Report errno-related errors with perror(). + * Ansify and Posixate. Add support for ISO 8859. + * Use better hash function. + * + * Revision 4.6 89/05/01 15:13:07 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.5 88/08/28 15:01:12 eggert + * Don't loop when writing error messages to a full filesystem. + * Flush stderr/stdout when mixing output. + * Yield exit status compatible with diff(1). + * Shrink stdio code size; allow cc -R; remove lint. + * + * Revision 4.4 87/12/18 11:44:47 narten + * fixed to use "varargs" in "fprintf"; this is required if it is to + * work on a SPARC machine such as a Sun-4 + * + * Revision 4.3 87/10/18 10:37:18 narten + * Updating version numbers. Changes relative to 1.1 actually relative + * to version 4.1 + * + * Revision 1.3 87/09/24 14:00:17 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:33 jenkins + * Port to suns + * + * Revision 4.1 83/03/25 18:12:51 wft + * Only changed $Header to $Id. + * + * Revision 3.3 82/12/10 16:22:37 wft + * Improved error messages, changed exit status on error to 1. + * + * Revision 3.2 82/11/28 21:27:10 wft + * Renamed ctab to map and included EOFILE; ctab is now a macro in rcsbase.h. + * Added fflsbuf(), fputs(), and fprintf(), which abort the RCS operations + * properly in case there is an IO-error (e.g., file system full). + * + * Revision 3.1 82/10/11 19:43:56 wft + * removed unused label out:; + * made sure all calls to getc() return into an integer, not a char. + */ + + +/* +#define LEXDB +*/ +/* version LEXDB is for testing the lexical analyzer. The testprogram + * reads a stream of lexemes, enters the revision numbers into the + * hashtable, and prints the recognized tokens. Keywords are recognized + * as identifiers. + */ + + + +#include "rcsbase.h" + +libId(lexId, "$Id: rcslex.c,v 5.11 1991/11/03 03:30:44 eggert Exp $") + +static struct hshentry *nexthsh; /*pointer to next hash entry, set by lookup*/ + +enum tokens nexttok; /*next token, set by nextlex */ + +int hshenter; /*if true, next suitable lexeme will be entered */ + /*into the symbol table. Handle with care. */ +int nextc; /*next input character, initialized by Lexinit */ + +unsigned long rcsline; /*current line-number of input */ +int nerror; /*counter for errors */ +int quietflag; /*indicates quiet mode */ +RILE * finptr; /*input file descriptor */ + +FILE * frewrite; /*file descriptor for echoing input */ + +FILE * foutptr; /* copy of frewrite, but 0 to suppress echo */ + +static struct buf tokbuf; /* token buffer */ + +char const * NextString; /* next token */ + +/* + * Our hash algorithm is h[0] = 0, h[i+1] = 4*h[i] + c, + * so hshsize should be odd. + * See B J McKenzie, R Harries & T Bell, Selecting a hashing algorithm, + * Software--practice & experience 20, 2 (Feb 1990), 209-224. + */ +#ifndef hshsize +# define hshsize 511 +#endif + +static struct hshentry *hshtab[hshsize]; /*hashtable */ + +static int ignored_phrases; /* have we ignored phrases in this RCS file? */ + + void +warnignore() +{ + if (! (ignored_phrases|quietflag)) { + ignored_phrases = true; + warn("Unknown phrases like `%s ...;' are in the RCS file.", NextString); + } +} + + + + static void +lookup(str) + char const *str; +/* Function: Looks up the character string pointed to by str in the + * hashtable. If the string is not present, a new entry for it is created. + * In any case, the address of the corresponding hashtable entry is placed + * into nexthsh. + */ +{ + register unsigned ihash; /* index into hashtable */ + register char const *sp; + register struct hshentry *n, **p; + + /* calculate hash code */ + sp = str; + ihash = 0; + while (*sp) + ihash = (ihash<<2) + *sp++; + ihash %= hshsize; + + for (p = &hshtab[ihash]; ; p = &n->nexthsh) + if (!(n = *p)) { + /* empty slot found */ + *p = n = ftalloc(struct hshentry); + n->num = fstr_save(str); + n->nexthsh = nil; +# ifdef LEXDB + VOID printf("\nEntered: %s at %u ", str, ihash); +# endif + break; + } else if (strcmp(str, n->num) == 0) + /* match found */ + break; + nexthsh = n; + NextString = n->num; +} + + + + + + + void +Lexinit() +/* Function: Initialization of lexical analyzer: + * initializes the hashtable, + * initializes nextc, nexttok if finptr != 0 + */ +{ register int c; + + for (c = hshsize; 0 <= --c; ) { + hshtab[c] = nil; + } + + nerror = 0; + if (finptr) { + foutptr = 0; + hshenter = true; + ignored_phrases = false; + rcsline = 1; + bufrealloc(&tokbuf, 2); + Iget(finptr, nextc); + nextlex(); /*initial token*/ + } +} + + + + + + + + void +nextlex() + +/* Function: Reads the next token and sets nexttok to the next token code. + * Only if hshenter is set, a revision number is entered into the + * hashtable and a pointer to it is placed into nexthsh. + * This is useful for avoiding that dates are placed into the hashtable. + * For ID's and NUM's, NextString is set to the character string. + * Assumption: nextc contains the next character. + */ +{ register c; + declarecache; + register FILE *frew; + register char * sp; + char const *limit; + register enum tokens d; + register RILE *fin; + + fin=finptr; frew=foutptr; + setupcache(fin); cache(fin); + c = nextc; + + for (;;) { switch ((d = ctab[c])) { + + default: + fatserror("unknown character `%c'", c); + /*NOTREACHED*/ + + case NEWLN: + ++rcsline; +# ifdef LEXDB + afputc('\n',stdout); +# endif + /* Note: falls into next case */ + + case SPACE: + GETC(frew, c); + continue; + + case DIGIT: + sp = tokbuf.string; + limit = sp + tokbuf.size; + *sp++ = c; + for (;;) { + GETC(frew, c); + if ((d=ctab[c])!=DIGIT && d!=PERIOD) + break; + *sp++ = c; /* 1.2. and 1.2 are different */ + if (limit <= sp) + sp = bufenlarge(&tokbuf, &limit); + } + *sp = 0; + if (hshenter) + lookup(tokbuf.string); + else + NextString = fstr_save(tokbuf.string); + d = NUM; + break; + + + case LETTER: + case Letter: + sp = tokbuf.string; + limit = sp + tokbuf.size; + *sp++ = c; + for (;;) { + GETC(frew, c); + if ((d=ctab[c])!=LETTER && d!=Letter && d!=DIGIT && d!=IDCHAR) + break; + *sp++ = c; + if (limit <= sp) + sp = bufenlarge(&tokbuf, &limit); + } + *sp = 0; + NextString = fstr_save(tokbuf.string); + d = ID; /* may be ID or keyword */ + break; + + case SBEGIN: /* long string */ + d = STRING; + /* note: only the initial SBEGIN has been read*/ + /* read the string, and reset nextc afterwards*/ + break; + + case COLON: + case SEMI: + GETC(frew, c); + break; + } break; } + nextc = c; + nexttok = d; + uncache(fin); +} + + int +eoflex() +/* + * Yield true if we look ahead to the end of the input, false otherwise. + * nextc becomes undefined at end of file. + */ +{ + register int c; + declarecache; + register FILE *fout; + register RILE *fin; + + c = nextc; + fin = finptr; + fout = foutptr; + setupcache(fin); cache(fin); + + for (;;) { + switch (ctab[c]) { + default: + nextc = c; + uncache(fin); + return false; + + case NEWLN: + ++rcsline; + /* fall into */ + case SPACE: + cachegeteof(c, {uncache(fin);return true;}); + break; + } + if (fout) + aputc(c, fout); + } +} + + +int getlex(token) +enum tokens token; +/* Function: Checks if nexttok is the same as token. If so, + * advances the input by calling nextlex and returns true. + * otherwise returns false. + * Doesn't work for strings and keywords; loses the character string for ids. + */ +{ + if (nexttok==token) { + nextlex(); + return(true); + } else return(false); +} + + int +getkeyopt(key) + char const *key; +/* Function: If the current token is a keyword identical to key, + * advances the input by calling nextlex and returns true; + * otherwise returns false. + */ +{ + if (nexttok==ID && strcmp(key,NextString) == 0) { + /* match found */ + ffree1(NextString); + nextlex(); + return(true); + } + return(false); +} + + void +getkey(key) + char const *key; +/* Check that the current input token is a keyword identical to key, + * and advance the input by calling nextlex. + */ +{ + if (!getkeyopt(key)) + fatserror("missing '%s' keyword", key); +} + + void +getkeystring(key) + char const *key; +/* Check that the current input token is a keyword identical to key, + * and advance the input by calling nextlex; then look ahead for a string. + */ +{ + getkey(key); + if (nexttok != STRING) + fatserror("missing string after '%s' keyword", key); +} + + + char const * +getid() +/* Function: Checks if nexttok is an identifier. If so, + * advances the input by calling nextlex and returns a pointer + * to the identifier; otherwise returns nil. + * Treats keywords as identifiers. + */ +{ + register char const *name; + if (nexttok==ID) { + name = NextString; + nextlex(); + return name; + } else return nil; +} + + +struct hshentry * getnum() +/* Function: Checks if nexttok is a number. If so, + * advances the input by calling nextlex and returns a pointer + * to the hashtable entry. Otherwise returns nil. + * Doesn't work if hshenter is false. + */ +{ + register struct hshentry * num; + if (nexttok==NUM) { + num=nexthsh; + nextlex(); + return num; + } else return nil; +} + + struct cbuf +getphrases(key) + char const *key; +/* Get a series of phrases that do not start with KEY, yield resulting buffer. + * Stop when the next phrase starts with a token that is not an identifier, + * or is KEY. + * Assume !foutptr. + */ +{ + declarecache; + register int c; + register char *p; + char const *limit; + register char const *ki, *kn; + struct cbuf r; + struct buf b; + register RILE *fin; + + if (nexttok!=ID || strcmp(NextString,key) == 0) { + r.string = 0; + r.size = 0; + return r; + } else { + warnignore(); + fin = finptr; + setupcache(fin); cache(fin); + bufautobegin(&b); + bufscpy(&b, NextString); + ffree1(NextString); + p = b.string + strlen(b.string); + limit = b.string + b.size; + c = nextc; + for (;;) { + for (;;) { + if (limit <= p) + p = bufenlarge(&b, &limit); + *p++ = c; + switch (ctab[c]) { + default: + fatserror("unknown character `%c'", c); + /*NOTREACHED*/ + case NEWLN: + ++rcsline; + /* fall into */ + case COLON: case DIGIT: case LETTER: case Letter: + case PERIOD: case SPACE: + cacheget(c); + continue; + case SBEGIN: /* long string */ + for (;;) { + for (;;) { + if (limit <= p) + p = bufenlarge(&b, &limit); + cacheget(c); + *p++ = c; + switch (c) { + case '\n': + ++rcsline; + /* fall into */ + default: + continue; + + case SDELIM: + break; + } + break; + } + cacheget(c); + if (c != SDELIM) + break; + if (limit <= p) + p = bufenlarge(&b, &limit); + *p++ = c; + } + continue; + case SEMI: + cacheget(c); + if (ctab[c] == NEWLN) { + ++rcsline; + if (limit <= p) + p = bufenlarge(&b, &limit); + *p++ = c; + cacheget(c); + } + for (;;) { + switch (ctab[c]) { + case NEWLN: + ++rcsline; + /* fall into */ + case SPACE: + cacheget(c); + continue; + + default: break; + } + break; + } + break; + } + break; + } + switch (ctab[c]) { + case LETTER: + case Letter: + for (kn = key; c && *kn==c; kn++) + cacheget(c); + if (!*kn) + switch (ctab[c]) { + case DIGIT: case LETTER: case Letter: + break; + default: + nextc = c; + NextString = fstr_save(key); + nexttok = ID; + uncache(fin); + goto returnit; + } + for (ki=key; kistring; limit = tp + target->size; + for (;;) { + GETC(frew, c); + switch (c) { + case '\n': + ++rcsline; + break; + case SDELIM: + GETC(frew, c); + if (c != SDELIM) { + /* end of string */ + nextc=c; + r.string = target->string; + r.size = tp - r.string; + uncache(fin); + return r; + } + break; + } + if (tp == limit) + tp = bufenlarge(target, &limit); + *tp++ = c; + } +} + + + char * +checkid(id, delimiter) + register char *id; + int delimiter; +/* Function: check whether the string starting at id is an */ +/* identifier and return a pointer to the delimiter*/ +/* after the identifier. White space, delim and 0 */ +/* are legal delimiters. Aborts the program if not*/ +/* a legal identifier. Useful for checking commands*/ +/* If !delim, the only delimiter is 0. */ +{ + register enum tokens d; + register char *temp; + register char c,tc; + register char delim = delimiter; + + temp = id; + if ((d = ctab[(unsigned char)(c = *id)])==LETTER || d==Letter) { + while ((d = ctab[(unsigned char)(c = *++id)])==LETTER + || d==Letter || d==DIGIT || d==IDCHAR + ) + ; + if (c && (!delim || c!=delim && c!=' ' && c!='\t' && c!='\n')) { + /* append \0 to end of id before error message */ + tc = c; + while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ; + *id = '\0'; + faterror("invalid character %c in identifier `%s'",tc,temp); + } + } else { + /* append \0 to end of id before error message */ + while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ; + *id = '\0'; + faterror("identifier `%s' doesn't start with letter", temp); + } + return id; +} + + void +checksid(id) + char *id; +/* Check whether the string ID is an identifier. */ +{ + VOID checkid(id, 0); +} + + + static RILE * +#if has_mmap && large_memory +fd2_RILE(fd, filename, status) +#else +fd2RILE(fd, filename, mode, status) + char const *mode; +#endif + int fd; + char const *filename; + register struct stat *status; +{ + struct stat st; + + if (!status) + status = &st; + if (fstat(fd, status) != 0) + efaterror(filename); + if (!S_ISREG(status->st_mode)) { + error("`%s' is not a regular file", filename); + VOID close(fd); + errno = EINVAL; + return 0; + } else { + +# if ! (has_mmap && large_memory) + FILE *stream; + if (!(stream = fdopen(fd, mode))) + efaterror(filename); +# endif + +# if !large_memory + return stream; +# else +# define RILES 3 + { + static RILE rilebuf[RILES]; + + register RILE *f; + size_t s = status->st_size; + + if (s != status->st_size) + faterror("`%s' is enormous", filename); + for (f = rilebuf; f->base; f++) + if (f == rilebuf+RILES) + faterror("too many RILEs"); + if (!s) { + static unsigned char dummy; + f->base = &dummy; + } else { +# if has_mmap + if ( + (f->base = (unsigned char *)mmap( + (caddr_t)0, s, PROT_READ, MAP_SHARED, + fd, (off_t)0 + )) == (unsigned char *)-1 + ) + efaterror("mmap"); +# else + f->base = tnalloc(unsigned char, s); +# endif + } + f->ptr = f->base; + f->lim = f->base + s; +# if has_mmap + f->fd = fd; +# else + f->readlim = f->base; + f->stream = stream; +# endif + if_advise_access(s, f, MADV_SEQUENTIAL); + return f; + } +# endif + } +} + +#if !has_mmap && large_memory + int +Igetmore(f) + register RILE *f; +{ + register fread_type r; + register size_t s = f->lim - f->readlim; + + if (BUFSIZ < s) + s = BUFSIZ; + if (!(r = Fread(f->readlim, sizeof(*f->readlim), s, f->stream))) { + testIerror(f->stream); + f->lim = f->readlim; /* The file might have shrunk! */ + return 0; + } + f->readlim += r; + return 1; +} +#endif + +#if has_madvise && has_mmap && large_memory + void +advise_access(f, advice) + register RILE *f; + int advice; +{ + if (madvise((caddr_t)f->base, (size_t)(f->lim - f->base), advice) != 0) + efaterror("madvise"); +} +#endif + + RILE * +#if has_mmap && large_memory +I_open(filename, status) +#else +Iopen(filename, mode, status) + char const *mode; +#endif + char const *filename; + struct stat *status; +/* Open FILENAME for reading, yield its descriptor, and set *STATUS. */ +{ + int fd; + + if ((fd = open(filename,O_RDONLY|O_BINARY)) < 0) + return 0; +# if has_mmap && large_memory + return fd2_RILE(fd, filename, status); +# else + return fd2RILE(fd, filename, mode, status); +# endif +} + + +#if !large_memory +# define Iclose(f) fclose(f) +#else + static int + Iclose(f) + register RILE *f; + { +# if has_mmap + size_t s = f->lim - f->base; + if (s && munmap((caddr_t)f->base, s) != 0) + return -1; + f->base = 0; + return close(f->fd); +# else + tfree(f->base); + f->base = 0; + return fclose(f->stream); +# endif + } +#endif + + +static int Oerrloop; + + exiting void +Oerror() +{ + if (Oerrloop) + exiterr(); + Oerrloop = true; + efaterror("output error"); +} + +exiting void Ieof() { fatserror("unexpected end of file"); } +exiting void Ierror() { efaterror("input error"); } +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(); } +void Ofclose(f) FILE *f; { if (f && fclose(f)!=0) Oerror(); } +void Izclose(p) RILE **p; { Ifclose(*p); *p = 0; } +void Ozclose(p) FILE **p; { Ofclose(*p); *p = 0; } + +#if !large_memory + void +testIeof(f) + FILE *f; +{ + testIerror(f); + if (feof(f)) + Ieof(); +} +void Irewind(f) FILE *f; { if (fseek(f,0L,SEEK_SET) != 0) Ierror(); } +#endif + +void eflush() +{ + if (fflush(stderr) != 0 && !Oerrloop) + Oerror(); +} + +void oflush() +{ + if (fflush(workstdout ? workstdout : stdout) != 0 && !Oerrloop) + Oerror(); +} + + static exiting void +fatcleanup(already_newline) + int already_newline; +{ + VOID fprintf(stderr, already_newline+"\n%s aborted\n", cmdid); + exiterr(); +} + +static void errsay() { oflush(); aprintf(stderr,"%s error: ",cmdid); nerror++; } +static void fatsay() { oflush(); VOID fprintf(stderr,"%s error: ",cmdid); } + +void eerror(s) char const *s; { enerror(errno,s); } + + void +enerror(e,s) + int e; + char const *s; +{ + errsay(); + errno = e; + perror(s); + eflush(); +} + +exiting void efaterror(s) char const *s; { enfaterror(errno,s); } + + exiting void +enfaterror(e,s) + int e; + char const *s; +{ + fatsay(); + errno = e; + perror(s); + fatcleanup(true); +} + +#if has_prototypes + void +error(char const *format,...) +#else + /*VARARGS1*/ void error(format, va_alist) char const *format; va_dcl +#endif +/* non-fatal error */ +{ + va_list args; + errsay(); + vararg_start(args, format); + fvfprintf(stderr, format, args); + va_end(args); + afputc('\n',stderr); + eflush(); +} + +#if has_prototypes + exiting void +fatserror(char const *format,...) +#else + /*VARARGS1*/ exiting void + fatserror(format, va_alist) char const *format; va_dcl +#endif +/* fatal syntax error */ +{ + va_list args; + oflush(); + VOID fprintf(stderr, "%s: %s:%lu: ", cmdid, RCSfilename, rcsline); + vararg_start(args, format); + fvfprintf(stderr, format, args); + va_end(args); + fatcleanup(false); +} + +#if has_prototypes + exiting void +faterror(char const *format,...) +#else + /*VARARGS1*/ exiting void faterror(format, va_alist) + char const *format; va_dcl +#endif +/* fatal error, terminates program after cleanup */ +{ + va_list args; + fatsay(); + vararg_start(args, format); + fvfprintf(stderr, format, args); + va_end(args); + fatcleanup(false); +} + +#if has_prototypes + void +warn(char const *format,...) +#else + /*VARARGS1*/ void warn(format, va_alist) char const *format; va_dcl +#endif +/* prints a warning message */ +{ + va_list args; + oflush(); + aprintf(stderr,"%s warning: ",cmdid); + vararg_start(args, format); + fvfprintf(stderr, format, args); + va_end(args); + afputc('\n',stderr); + eflush(); +} + + void +redefined(c) + int c; +{ + warn("redefinition of -%c option", c); +} + +#if has_prototypes + void +diagnose(char const *format,...) +#else + /*VARARGS1*/ void diagnose(format, va_alist) char const *format; va_dcl +#endif +/* prints a diagnostic message */ +/* Unlike the other routines, it does not append a newline. */ +/* This lets some callers suppress the newline, and is faster */ +/* in implementations that flush stderr just at the end of each printf. */ +{ + va_list args; + if (!quietflag) { + oflush(); + vararg_start(args, format); + fvfprintf(stderr, format, args); + va_end(args); + eflush(); + } +} + + + + void +afputc(c, f) +/* Function: afputc(c,f) acts like aputc(c,f), but is smaller and slower. + */ + int c; + register FILE *f; +{ + aputc(c,f); +} + + + void +aputs(s, iop) + char const *s; + FILE *iop; +/* Function: Put string s on file iop, abort on error. + */ +{ +#if has_fputs + if (fputs(s, iop) < 0) + Oerror(); +#else + awrite(s, strlen(s), iop); +#endif +} + + + + void +#if has_prototypes +fvfprintf(FILE *stream, char const *format, va_list args) +#else + fvfprintf(stream,format,args) FILE *stream; char *format; va_list args; +#endif +/* like vfprintf, except abort program on error */ +{ +#if has_vfprintf + if (vfprintf(stream, format, args) < 0) +#else +# if has__doprintf + _doprintf(stream, format, args); +# else +# if has__doprnt + _doprnt(format, args, stream); +# else + int *a = (int *)args; + VOID fprintf(stream, format, + a[0], a[1], a[2], a[3], a[4], + a[5], a[6], a[7], a[8], a[9] + ); +# endif +# endif + if (ferror(stream)) +#endif + Oerror(); +} + +#if has_prototypes + void +aprintf(FILE *iop, char const *fmt, ...) +#else + /*VARARGS2*/ void +aprintf(iop, fmt, va_alist) +FILE *iop; +char const *fmt; +va_dcl +#endif +/* Function: formatted output. Same as fprintf in stdio, + * but aborts program on error + */ +{ + va_list ap; + vararg_start(ap, fmt); + fvfprintf(iop, fmt, ap); + va_end(ap); +} + + + +#ifdef LEXDB +/* test program reading a stream of lexemes and printing the tokens. + */ + + + + int +main(argc,argv) +int argc; char * argv[]; +{ + cmdid="lextest"; + if (argc<2) { + aputs("No input file\n",stderr); + exitmain(EXIT_FAILURE); + } + if (!(finptr=Iopen(argv[1], FOPEN_R, (struct stat*)0))) { + faterror("can't open input file %s",argv[1]); + } + Lexinit(); + while (!eoflex()) { + switch (nexttok) { + + case ID: + VOID printf("ID: %s",NextString); + break; + + case NUM: + if (hshenter) + VOID printf("NUM: %s, index: %d",nexthsh->num, nexthsh-hshtab); + else + VOID printf("NUM, unentered: %s",NextString); + hshenter = !hshenter; /*alternate between dates and numbers*/ + break; + + case COLON: + VOID printf("COLON"); break; + + case SEMI: + VOID printf("SEMI"); break; + + case STRING: + readstring(); + VOID printf("STRING"); break; + + case UNKN: + VOID printf("UNKN"); break; + + default: + VOID printf("DEFAULT"); break; + } + VOID printf(" | "); + nextlex(); + } + exitmain(EXIT_SUCCESS); +} + +exiting void exiterr() { _exit(EXIT_FAILURE); } + + +#endif diff --git a/gnu/usr.bin/rcs/lib/rcsmap.c b/gnu/usr.bin/rcs/lib/rcsmap.c new file mode 100644 index 0000000000..0e7b23c85f --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcsmap.c @@ -0,0 +1,68 @@ +/* RCS map of character types */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + +#include "rcsbase.h" + +libId(mapId, "$Id: rcsmap.c,v 5.2 1991/08/19 03:13:55 eggert Exp $") + +/* map of character types */ +/* ISO 8859/1 (Latin-1) */ +enum tokens const ctab[] = { + UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + SPACE, SPACE, NEWLN, SPACE, SPACE, SPACE, UNKN, UNKN, + UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + SPACE, IDCHAR, IDCHAR, IDCHAR, DELIM, IDCHAR, IDCHAR, IDCHAR, + IDCHAR, IDCHAR, IDCHAR, IDCHAR, DELIM, IDCHAR, PERIOD, IDCHAR, + DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, + DIGIT, DIGIT, COLON, SEMI, IDCHAR, IDCHAR, IDCHAR, IDCHAR, + SBEGIN, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, + IDCHAR, Letter, Letter, Letter, Letter, Letter, Letter, Letter, + Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, + Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, + Letter, Letter, Letter, IDCHAR, IDCHAR, IDCHAR, IDCHAR, UNKN, + UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, + IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, + IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, + IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, IDCHAR, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, Letter, + Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, + Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, + Letter, Letter, Letter, Letter, Letter, Letter, Letter, IDCHAR, + Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter +}; diff --git a/gnu/usr.bin/rcs/lib/rcsrev.c b/gnu/usr.bin/rcs/lib/rcsrev.c new file mode 100644 index 0000000000..ce11f54969 --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcsrev.c @@ -0,0 +1,790 @@ +/* + * RCS revision number handling + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + + +/* $Log: rcsrev.c,v $ + * Revision 5.3 1991/08/19 03:13:55 eggert + * Add `-r$', `-rB.'. Remove botches like `' from messages. Tune. + * + * Revision 5.2 1991/04/21 11:58:28 eggert + * Add tiprev(). + * + * Revision 5.1 1991/02/25 07:12:43 eggert + * Avoid overflow when comparing revision numbers. + * + * Revision 5.0 1990/08/22 08:13:43 eggert + * Remove compile-time limits; use malloc instead. + * Ansify and Posixate. Tune. + * Remove possibility of an internal error. Remove lint. + * + * Revision 4.5 89/05/01 15:13:22 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.4 87/12/18 11:45:22 narten + * more lint cleanups. Also, the NOTREACHED comment is no longer necessary, + * since there's now a return value there with a value. (Guy Harris) + * + * Revision 4.3 87/10/18 10:38:42 narten + * Updating version numbers. Changes relative to version 1.1 actually + * relative to 4.1 + * + * Revision 1.3 87/09/24 14:00:37 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:37 jenkins + * Port to suns + * + * Revision 4.1 83/03/25 21:10:45 wft + * Only changed $Header to $Id. + * + * Revision 3.4 82/12/04 13:24:08 wft + * Replaced getdelta() with gettree(). + * + * Revision 3.3 82/11/28 21:33:15 wft + * fixed compartial() and compnum() for nil-parameters; fixed nils + * in error messages. Testprogram output shortenend. + * + * Revision 3.2 82/10/18 21:19:47 wft + * renamed compnum->cmpnum, compnumfld->cmpnumfld, + * numericrevno->numricrevno. + * + * Revision 3.1 82/10/11 19:46:09 wft + * changed expandsym() to check for source==nil; returns zero length string + * in that case. + */ + + + +/* +#define REVTEST +*/ +/* version REVTEST is for testing the routines that generate a sequence + * of delta numbers needed to regenerate a given delta. + */ + +#include "rcsbase.h" + +libId(revId, "$Id: rcsrev.c,v 5.3 1991/08/19 03:13:55 eggert Exp $") + +static char const *branchtip P((char const*)); +static struct hshentry *genbranch P((struct hshentry const*,char const*,unsigned,char const*,char const*,char const*,struct hshentries**)); + + + + unsigned +countnumflds(s) + char const *s; +/* Given a pointer s to a dotted number (date or revision number), + * countnumflds returns the number of digitfields in s. + */ +{ + register char const *sp; + register unsigned count; + if ((sp=s)==nil) return(0); + if (*sp == '\0') return(0); + count = 1; + do { + if (*sp++ == '.') count++; + } while (*sp); + return(count); +} + + void +getbranchno(revno,branchno) + char const *revno; + struct buf *branchno; +/* Given a non-nil revision number revno, getbranchno copies the number of the branch + * on which revno is into branchno. If revno itself is a branch number, + * it is copied unchanged. + */ +{ + register unsigned numflds; + register char *tp; + + bufscpy(branchno, revno); + numflds=countnumflds(revno); + if (!(numflds & 1)) { + tp = branchno->string; + while (--numflds) + while (*tp++ != '.') + ; + *(tp-1)='\0'; + } +} + + + +int cmpnum(num1, num2) + char const *num1, *num2; +/* compares the two dotted numbers num1 and num2 lexicographically + * by field. Individual fields are compared numerically. + * returns <0, 0, >0 if num1num2, resp. + * omitted fields are assumed to be higher than the existing ones. +*/ +{ + register char const *s1, *s2; + register size_t d1, d2; + register int r; + + s1=num1==nil?"":num1; + s2=num2==nil?"":num2; + + for (;;) { + /* Give precedence to shorter one. */ + if (!*s1) + return (unsigned char)*s2; + if (!*s2) + return -1; + + /* Strip leading zeros, then find number of digits. */ + while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ; + while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ; + + /* Do not convert to integer; it might overflow! */ + if (d1 != d2) + return d1string; + while (length) { + while (*r1!='.' && *r1) + ++r1; + ++r1; + length--; + } + /* eliminate last '.'*/ + *(r1-1)='\0'; + return rev1->string; +} + + + + + static void +store1(store, next) + struct hshentries ***store; + struct hshentry *next; +/* + * Allocate a new list node that addresses NEXT. + * Append it to the list that **STORE is the end pointer of. + */ +{ + register struct hshentries *p; + + p = ftalloc(struct hshentries); + p->first = next; + **store = p; + *store = &p->rest; +} + +struct hshentry * genrevs(revno,date,author,state,store) + char const *revno, *date, *author, *state; + struct hshentries **store; +/* Function: finds the deltas needed for reconstructing the + * revision given by revno, date, author, and state, and stores pointers + * to these deltas into a list whose starting address is given by store. + * The last delta (target delta) is returned. + * If the proper delta could not be found, nil is returned. + */ +{ + unsigned length; + register struct hshentry * next; + int result; + char const *branchnum; + struct buf t; + char datebuf[datesize]; + + bufautobegin(&t); + + if (!(next = Head)) { + error("RCS file empty"); + goto norev; + } + + length = countnumflds(revno); + + if (length >= 1) { + /* at least one field; find branch exactly */ + while ((result=cmpnumfld(revno,next->num,1)) < 0) { + store1(&store, next); + next = next->next; + if (!next) { + error("branch number %s too low", partialno(&t,revno,1)); + goto norev; + } + } + + if (result>0) { + absent(revno, 1); + goto norev; + } + } + if (length<=1){ + /* pick latest one on given branch */ + branchnum = next->num; /* works even for empty revno*/ + while ((next!=nil) && + (cmpnumfld(branchnum,next->num,1)==0) && + !( + (date==nil?1:(cmpnum(date,next->date)>=0)) && + (author==nil?1:(strcmp(author,next->author)==0)) && + (state ==nil?1:(strcmp(state, next->state) ==0)) + ) + ) + { + store1(&store, next); + next=next->next; + } + if ((next==nil) || + (cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ { + cantfindbranch( + length ? revno : partialno(&t,branchnum,1), + date, author, state + ); + goto norev; + } else { + store1(&store, next); + } + *store = nil; + return next; + } + + /* length >=2 */ + /* find revision; may go low if length==2*/ + while ((result=cmpnumfld(revno,next->num,2)) < 0 && + (cmpnumfld(revno,next->num,1)==0) ) { + store1(&store, next); + next = next->next; + if (!next) + break; + } + + if ((next==nil) || (cmpnumfld(revno,next->num,1)!=0)) { + error("revision number %s too low", partialno(&t,revno,2)); + goto norev; + } + if ((length>2) && (result!=0)) { + absent(revno, 2); + goto norev; + } + + /* print last one */ + store1(&store, next); + + if (length>2) + return genbranch(next,revno,length,date,author,state,store); + else { /* length == 2*/ + if ((date!=nil) && (cmpnum(date,next->date)<0)){ + error("Revision %s has date %s.", + next->num, + date2str(next->date, datebuf) + ); + return nil; + } + if ((author!=nil)&&(strcmp(author,next->author)!=0)) { + error("Revision %s has author %s.",next->num,next->author); + return nil; + } + if ((state!=nil)&&(strcmp(state,next->state)!=0)) { + error("Revision %s has state %s.",next->num, + next->state==nil?"":next->state); + return nil; + } + *store=nil; + return next; + } + + norev: + bufautoend(&t); + return nil; +} + + + + + static struct hshentry * +genbranch(bpoint, revno, length, date, author, state, store) + struct hshentry const *bpoint; + char const *revno; + unsigned length; + char const *date, *author, *state; + struct hshentries **store; +/* Function: given a branchpoint, a revision number, date, author, and state, + * genbranch finds the deltas necessary to reconstruct the given revision + * from the branch point on. + * Pointers to the found deltas are stored in a list beginning with store. + * revno must be on a side branch. + * return nil on error + */ +{ + unsigned field; + register struct hshentry * next, * trail; + register struct branchhead const *bhead; + int result; + struct buf t; + char datebuf[datesize]; + + field = 3; + bhead = bpoint->branches; + + do { + if (!bhead) { + bufautobegin(&t); + error("no side branches present for %s", partialno(&t,revno,field-1)); + bufautoend(&t); + return nil; + } + + /*find branch head*/ + /*branches are arranged in increasing order*/ + while (0 < (result=cmpnumfld(revno,bhead->hsh->num,field))) { + bhead = bhead->nextbranch; + if (!bhead) { + bufautobegin(&t); + error("branch number %s too high",partialno(&t,revno,field)); + bufautoend(&t); + return nil; + } + } + + if (result<0) { + absent(revno, field); + return nil; + } + + next = bhead->hsh; + if (length==field) { + /* pick latest one on that branch */ + trail=nil; + do { if ((date==nil?1:(cmpnum(date,next->date)>=0)) && + (author==nil?1:(strcmp(author,next->author)==0)) && + (state ==nil?1:(strcmp(state, next->state) ==0)) + ) trail = next; + next=next->next; + } while (next!=nil); + + if (trail==nil) { + cantfindbranch(revno, date, author, state); + return nil; + } else { /* print up to last one suitable */ + next = bhead->hsh; + while (next!=trail) { + store1(&store, next); + next=next->next; + } + store1(&store, next); + } + *store = nil; + return next; + } + + /* length > field */ + /* find revision */ + /* check low */ + if (cmpnumfld(revno,next->num,field+1)<0) { + bufautobegin(&t); + error("revision number %s too low", partialno(&t,revno,field+1)); + bufautoend(&t); + return(nil); + } + do { + store1(&store, next); + trail = next; + next = next->next; + } while ((next!=nil) && + (cmpnumfld(revno,next->num,field+1) >=0)); + + if ((length>field+1) && /*need exact hit */ + (cmpnumfld(revno,trail->num,field+1) !=0)){ + absent(revno, field+1); + return(nil); + } + if (length == field+1) { + if ((date!=nil) && (cmpnum(date,trail->date)<0)){ + error("Revision %s has date %s.", + trail->num, + date2str(trail->date, datebuf) + ); + return nil; + } + if ((author!=nil)&&(strcmp(author,trail->author)!=0)) { + error("Revision %s has author %s.",trail->num,trail->author); + return nil; + } + if ((state!=nil)&&(strcmp(state,trail->state)!=0)) { + error("Revision %s has state %s.",trail->num, + trail->state==nil?"":trail->state); + return nil; + } + } + bhead = trail->branches; + + } while ((field+=2) <= length); + * store = nil; + return trail; +} + + + static char const * +lookupsym(id) + char const *id; +/* Function: looks up id in the list of symbolic names starting + * with pointer SYMBOLS, and returns a pointer to the corresponding + * revision number. Returns nil if not present. + */ +{ + register struct assoc const *next; + next = Symbols; + while (next!=nil) { + if (strcmp(id, next->symbol)==0) + return next->num; + else next=next->nextassoc; + } + return nil; +} + +int expandsym(source, target) + char const *source; + struct buf *target; +/* Function: Source points to a revision number. Expandsym copies + * the number to target, but replaces all symbolic fields in the + * source number with their numeric values. + * Expand a branch followed by `.' to the latest revision on that branch. + * Ignore `.' after a revision. Remove leading zeros. + * returns false on error; + */ +{ + return fexpandsym(source, target, (RILE*)0); +} + + int +fexpandsym(source, target, fp) + char const *source; + struct buf *target; + RILE *fp; +/* Same as expandsym, except if FP is nonzero, it is used to expand KDELIM. */ +{ + register char const *sp, *bp; + register char *tp; + char const *tlim; + register enum tokens d; + unsigned dots; + + sp = source; + bufalloc(target, 1); + tp = target->string; + if (!sp || !*sp) { /*accept nil pointer as a legal value*/ + *tp='\0'; + return true; + } + if (sp[0] == KDELIM && !sp[1]) { + if (!getoldkeys(fp)) + return false; + if (!*prevrev.string) { + error("working file lacks revision number"); + return false; + } + bufscpy(target, prevrev.string); + return true; + } + tlim = tp + target->size; + dots = 0; + + for (;;) { + switch (ctab[(unsigned char)*sp]) { + case DIGIT: + while (*sp=='0' && isdigit(sp[1])) + /* skip leading zeroes */ + sp++; + do { + if (tlim <= tp) + tp = bufenlarge(target, &tlim); + } while (isdigit(*tp++ = *sp++)); + --sp; + tp[-1] = '\0'; + break; + + case LETTER: + case Letter: + { + register char *p = tp; + register size_t s = tp - target->string; + do { + if (tlim <= p) + p = bufenlarge(target, &tlim); + *p++ = *sp++; + } while ((d=ctab[(unsigned char)*sp])==LETTER || + d==Letter || d==DIGIT || + (d==IDCHAR)); + if (tlim <= p) + p = bufenlarge(target, &tlim); + *p = 0; + tp = target->string + s; + } + bp = lookupsym(tp); + if (bp==nil) { + error("Symbolic number %s is undefined.", tp); + return false; + } + do { + if (tlim <= tp) + tp = bufenlarge(target, &tlim); + } while ((*tp++ = *bp++)); + break; + + default: + goto improper; + } + switch (*sp++) { + case '\0': return true; + case '.': break; + default: goto improper; + } + if (!*sp) { + if (dots & 1) + goto improper; + if (!(bp = branchtip(target->string))) + return false; + bufscpy(target, bp); + return true; + } + ++dots; + tp[-1] = '.'; + } + + improper: + error("improper revision number: %s", source); + return false; +} + + static char const * +branchtip(branch) + char const *branch; +{ + struct hshentry *h; + struct hshentries *hs; + + h = genrevs(branch, (char*)0, (char*)0, (char*)0, &hs); + return h ? h->num : (char const*)0; +} + + char const * +tiprev() +{ + return Dbranch ? branchtip(Dbranch) : Head ? Head->num : (char const*)0; +} + + + +#ifdef REVTEST + +char const cmdid[] = "revtest"; + + int +main(argc,argv) +int argc; char * argv[]; +{ + static struct buf numricrevno; + char symrevno[100]; /* used for input of revision numbers */ + char author[20]; + char state[20]; + char date[20]; + struct hshentries *gendeltas; + struct hshentry * target; + int i; + + if (argc<2) { + aputs("No input file\n",stderr); + exitmain(EXIT_FAILURE); + } + if (!(finptr=Iopen(argv[1], FOPEN_R, (struct stat*)0))) { + faterror("can't open input file %s", argv[1]); + } + Lexinit(); + getadmin(); + + gettree(); + + getdesc(false); + + do { + /* all output goes to stderr, to have diagnostics and */ + /* errors in sequence. */ + aputs("\nEnter revision number or or '.': ",stderr); + if (!gets(symrevno)) break; + if (*symrevno == '.') break; + aprintf(stderr,"%s;\n",symrevno); + expandsym(symrevno,&numricrevno); + aprintf(stderr,"expanded number: %s; ",numricrevno.string); + aprintf(stderr,"Date: "); + gets(date); aprintf(stderr,"%s; ",date); + aprintf(stderr,"Author: "); + gets(author); aprintf(stderr,"%s; ",author); + aprintf(stderr,"State: "); + gets(state); aprintf(stderr, "%s;\n", state); + target = genrevs(numricrevno.string, *date?date:(char *)nil, *author?author:(char *)nil, + *state?state:(char*)nil, &gendeltas); + if (target!=nil) { + while (gendeltas) { + aprintf(stderr,"%s\n",gendeltas->first->num); + gendeltas = gendeltas->next; + } + } + } while (true); + aprintf(stderr,"done\n"); + exitmain(EXIT_SUCCESS); +} + +exiting void exiterr() { _exit(EXIT_FAILURE); } + +#endif diff --git a/gnu/usr.bin/rcs/lib/rcssyn.c b/gnu/usr.bin/rcs/lib/rcssyn.c new file mode 100644 index 0000000000..31086c292f --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcssyn.c @@ -0,0 +1,857 @@ +/* + * RCS file input + */ +/********************************************************************************* + * Syntax Analysis. + * Keyword table + * Testprogram: define SYNTEST + * Compatibility with Release 2: define COMPAT2=1 + ********************************************************************************* + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + +/* $Log: rcssyn.c,v $ + * Revision 5.8 1991/08/19 03:13:55 eggert + * Tune. + * + * Revision 5.7 1991/04/21 11:58:29 eggert + * Disambiguate names on shortname hosts. + * Fix errno bug. Add MS-DOS support. + * + * Revision 5.6 1991/02/28 19:18:51 eggert + * Fix null termination bug in reporting keyword expansion. + * + * Revision 5.5 1991/02/25 07:12:44 eggert + * Check diff output more carefully; avoid overflow. + * + * Revision 5.4 1990/11/01 05:28:48 eggert + * When ignoring unknown phrases, copy them to the output RCS file. + * Permit arbitrary data in logs and comment leaders. + * Don't check for nontext on initial checkin. + * + * Revision 5.3 1990/09/20 07:58:32 eggert + * Remove the test for non-text bytes; it caused more pain than it cured. + * + * Revision 5.2 1990/09/04 08:02:30 eggert + * Parse RCS files with no revisions. + * Don't strip leading white space from diff commands. Count RCS lines better. + * + * Revision 5.1 1990/08/29 07:14:06 eggert + * Add -kkvl. Clean old log messages too. + * + * Revision 5.0 1990/08/22 08:13:44 eggert + * Try to parse future RCS formats without barfing. + * Add -k. Don't require final newline. + * Remove compile-time limits; use malloc instead. + * Don't output branch keyword if there's no default branch, + * because RCS version 3 doesn't understand it. + * Tune. Remove lint. + * Add support for ISO 8859. Ansify and Posixate. + * Check that a newly checked-in file is acceptable as input to 'diff'. + * Check diff's output. + * + * Revision 4.6 89/05/01 15:13:32 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.5 88/08/09 19:13:21 eggert + * Allow cc -R; remove lint. + * + * Revision 4.4 87/12/18 11:46:16 narten + * more lint cleanups (Guy Harris) + * + * Revision 4.3 87/10/18 10:39:36 narten + * Updating version numbers. Changes relative to 1.1 actually relative to + * 4.1 + * + * Revision 1.3 87/09/24 14:00:49 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:40 jenkins + * Port to suns + * + * Revision 4.1 83/03/28 11:38:49 wft + * Added parsing and printing of default branch. + * + * Revision 3.6 83/01/15 17:46:50 wft + * Changed readdelta() to initialize selector and log-pointer. + * Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM. + * + * Revision 3.5 82/12/08 21:58:58 wft + * renamed Commentleader to Commleader. + * + * Revision 3.4 82/12/04 13:24:40 wft + * Added routine gettree(), which updates keeplock after reading the + * delta tree. + * + * Revision 3.3 82/11/28 21:30:11 wft + * Reading and printing of Suffix removed; version COMPAT2 skips the + * Suffix for files of release 2 format. Fixed problems with printing nil. + * + * Revision 3.2 82/10/18 21:18:25 wft + * renamed putdeltatext to putdtext. + * + * Revision 3.1 82/10/11 19:45:11 wft + * made sure getc() returns into an integer. + */ + + + +/* version COMPAT2 reads files of the format of release 2 and 3, but + * generates files of release 3 format. Need not be defined if no + * old RCS files generated with release 2 exist. + */ +/* version SYNTEST inputs a RCS file and then prints out its internal + * data structures. +*/ + +#include "rcsbase.h" + +libId(synId, "$Id: rcssyn.c,v 5.8 1991/08/19 03:13:55 eggert Exp $") + +/* forward */ +static char const *getkeyval P((char const*,enum tokens,int)); +static int strn2expmode P((char const*,size_t)); + +/* keyword table */ + +char const + Kdesc[] = "desc", + Klog[] = "log", + Ktext[] = "text"; + +static char const + Kaccess[] = "access", + Kauthor[] = "author", + Kbranch[] = "branch", + K_branches[]= "branches", + Kcomment[] = "comment", + Kdate[] = "date", + Kexpand[] = "expand", + Khead[] = "head", + Klocks[] = "locks", + Knext[] = "next", + Kstate[] = "state", + Kstrict[] = "strict", +#if COMPAT2 + Ksuffix[] = "suffix", +#endif + Ksymbols[] = "symbols"; + +static struct buf Commleader; +static struct cbuf Ignored; +struct cbuf Comment; +struct access * AccessList; +struct assoc * Symbols; +struct lock * Locks; +int Expand; +int StrictLocks; +struct hshentry * Head; +char const * Dbranch; +unsigned TotalDeltas; + + + static void +getsemi(key) + char const *key; +/* Get a semicolon to finish off a phrase started by KEY. */ +{ + if (!getlex(SEMI)) + fatserror("missing ';' after '%s'", key); +} + + static struct hshentry * +getdnum() +/* Get a delta number. */ +{ + register struct hshentry *delta = getnum(); + if (delta && countnumflds(delta->num)&1) + fatserror("%s isn't a delta number", delta->num); + return delta; +} + + + void +getadmin() +/* Read an and initialize the appropriate global variables. */ +{ + register char const *id; + struct access * newaccess; + struct assoc * newassoc; + struct lock * newlock; + struct hshentry * delta; + struct access **LastAccess; + struct assoc **LastSymbol; + struct lock **LastLock; + struct buf b; + struct cbuf cb; + + TotalDeltas=0; + + getkey(Khead); + Head = getdnum(); + getsemi(Khead); + + Dbranch = nil; + if (getkeyopt(Kbranch)) { + if ((delta = getnum())) + Dbranch = delta->num; + getsemi(Kbranch); + } + + +#if COMPAT2 + /* read suffix. Only in release 2 format */ + if (getkeyopt(Ksuffix)) { + if (nexttok==STRING) { + readstring(); nextlex(); /* Throw away the suffix. */ + } else if (nexttok==ID) { + nextlex(); + } + getsemi(Ksuffix); + } +#endif + + getkey(Kaccess); + LastAccess = &AccessList; + while (id=getid()) { + newaccess = ftalloc(struct access); + newaccess->login = id; + *LastAccess = newaccess; + LastAccess = &newaccess->nextaccess; + } + *LastAccess = nil; + getsemi(Kaccess); + + getkey(Ksymbols); + LastSymbol = &Symbols; + while (id = getid()) { + if (!getlex(COLON)) + fatserror("missing ':' in symbolic name definition"); + if (!(delta=getnum())) { + fatserror("missing number in symbolic name definition"); + } else { /*add new pair to association list*/ + newassoc = ftalloc(struct assoc); + newassoc->symbol=id; + newassoc->num = delta->num; + *LastSymbol = newassoc; + LastSymbol = &newassoc->nextassoc; + } + } + *LastSymbol = nil; + getsemi(Ksymbols); + + getkey(Klocks); + LastLock = &Locks; + while (id = getid()) { + if (!getlex(COLON)) + fatserror("missing ':' in lock"); + if (!(delta=getdnum())) { + fatserror("missing number in lock"); + } else { /*add new pair to lock list*/ + newlock = ftalloc(struct lock); + newlock->login=id; + newlock->delta=delta; + *LastLock = newlock; + LastLock = &newlock->nextlock; + } + } + *LastLock = nil; + getsemi(Klocks); + + if ((StrictLocks = getkeyopt(Kstrict))) + getsemi(Kstrict); + + Comment.size = 0; + if (getkeyopt(Kcomment)) { + if (nexttok==STRING) { + Comment = savestring(&Commleader); + nextlex(); + } + getsemi(Kcomment); + } + + Expand = KEYVAL_EXPAND; + if (getkeyopt(Kexpand)) { + if (nexttok==STRING) { + bufautobegin(&b); + cb = savestring(&b); + if ((Expand = strn2expmode(cb.string,cb.size)) < 0) + fatserror("unknown expand mode %.*s", + (int)cb.size, cb.string + ); + bufautoend(&b); + nextlex(); + } + getsemi(Kexpand); + } + Ignored = getphrases(Kdesc); +} + +char const *const expand_names[] = { + /* These must agree with *_EXPAND in rcsbase.h. */ + "kv","kvl","k","v","o", + 0 +}; + + int +str2expmode(s) + char const *s; +/* Yield expand mode corresponding to S, or -1 if bad. */ +{ + return strn2expmode(s, strlen(s)); +} + + static int +strn2expmode(s, n) + char const *s; + size_t n; +{ + char const *const *p; + + for (p = expand_names; *p; ++p) + if (memcmp(*p,s,n) == 0 && !(*p)[n]) + return p - expand_names; + return -1; +} + + + void +ignorephrase() +/* Ignore a phrase introduced by a later version of RCS. */ +{ + warnignore(); + hshenter=false; + for (;;) { + switch (nexttok) { + case SEMI: hshenter=true; nextlex(); return; + case ID: + case NUM: ffree1(NextString); break; + case STRING: readstring(); break; + default: break; + } + nextlex(); + } +} + + + static int +getdelta() +/* Function: reads a delta block. + * returns false if the current block does not start with a number. + */ +{ + register struct hshentry * Delta, * num; + struct branchhead **LastBranch, *NewBranch; + + if (!(Delta = getdnum())) + return false; + + hshenter = false; /*Don't enter dates into hashtable*/ + Delta->date = getkeyval(Kdate, NUM, false); + hshenter=true; /*reset hshenter for revision numbers.*/ + + Delta->author = getkeyval(Kauthor, ID, false); + + Delta->state = getkeyval(Kstate, ID, true); + + getkey(K_branches); + LastBranch = &Delta->branches; + while ((num = getdnum())) { + NewBranch = ftalloc(struct branchhead); + NewBranch->hsh = num; + *LastBranch = NewBranch; + LastBranch = &NewBranch->nextbranch; + } + *LastBranch = nil; + getsemi(K_branches); + + getkey(Knext); + Delta->next = num = getdnum(); + getsemi(Knext); + Delta->lockedby = nil; + Delta->log.string = 0; + Delta->selector = true; + Delta->ig = getphrases(Kdesc); + TotalDeltas++; + return (true); +} + + + void +gettree() +/* Function: Reads in the delta tree with getdelta(), then + * updates the lockedby fields. + */ +{ + struct lock const *currlock; + + while (getdelta()); + currlock=Locks; + while (currlock) { + currlock->delta->lockedby = currlock->login; + currlock = currlock->nextlock; + } +} + + + void +getdesc(prdesc) +int prdesc; +/* Function: read in descriptive text + * nexttok is not advanced afterwards. + * If prdesc is set, the text is printed to stdout. + */ +{ + + getkeystring(Kdesc); + if (prdesc) + printstring(); /*echo string*/ + else readstring(); /*skip string*/ +} + + + + + + + static char const * +getkeyval(keyword, token, optional) + char const *keyword; + enum tokens token; + int optional; +/* reads a pair of the form + * ; + * where token is one of or . optional indicates whether + * is optional. A pointer to + * the actual character string of or is returned. + */ +{ + register char const *val = nil; + + getkey(keyword); + if (nexttok==token) { + val = NextString; + nextlex(); + } else { + if (!optional) + fatserror("missing %s", keyword); + } + getsemi(keyword); + return(val); +} + + + + + void +putadmin(fout) +register FILE * fout; +/* Function: Print the node read with getadmin() to file fout. + * Assumption: Variables AccessList, Symbols, Locks, StrictLocks, + * and Head have been set. + */ +{ + struct assoc const *curassoc; + struct lock const *curlock; + struct access const *curaccess; + + aprintf(fout, "%s\t%s;\n", Khead, Head?Head->num:""); + if (Dbranch && VERSION(4)<=RCSversion) + aprintf(fout, "%s\t%s;\n", Kbranch, Dbranch); + + aputs(Kaccess, fout); + curaccess = AccessList; + while (curaccess) { + aprintf(fout, "\n\t%s", curaccess->login); + curaccess = curaccess->nextaccess; + } + aprintf(fout, ";\n%s", Ksymbols); + curassoc = Symbols; + while (curassoc) { + aprintf(fout, "\n\t%s:%s", curassoc->symbol, curassoc->num); + curassoc = curassoc->nextassoc; + } + aprintf(fout, ";\n%s", Klocks); + curlock = Locks; + while (curlock) { + aprintf(fout, "\n\t%s:%s", curlock->login, curlock->delta->num); + curlock = curlock->nextlock; + } + if (StrictLocks) aprintf(fout, "; %s", Kstrict); + aprintf(fout, ";\n"); + if (Comment.size) { + aprintf(fout, "%s\t", Kcomment); + putstring(fout, true, Comment, false); + aprintf(fout, ";\n"); + } + if (Expand != KEYVAL_EXPAND) + aprintf(fout, "%s\t%c%s%c;\n", + Kexpand, SDELIM, expand_names[Expand], SDELIM + ); + awrite(Ignored.string, Ignored.size, fout); + aputc('\n', fout); +} + + + + + static void +putdelta(node,fout) +register struct hshentry const *node; +register FILE * fout; +/* Function: prints a node to fout; + */ +{ + struct branchhead const *nextbranch; + + if (node == nil) return; + + aprintf(fout, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches", + node->num, + Kdate, node->date, + Kauthor, node->author, + Kstate, node->state?node->state:"" + ); + nextbranch = node->branches; + while (nextbranch) { + aprintf(fout, "\n\t%s", nextbranch->hsh->num); + nextbranch = nextbranch->nextbranch; + } + + aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:""); + awrite(node->ig.string, node->ig.size, fout); +} + + + + + void +puttree(root,fout) +struct hshentry const *root; +register FILE * fout; +/* Function: prints the delta tree in preorder to fout, starting with root. + */ +{ + struct branchhead const *nextbranch; + + if (root==nil) return; + + if (root->selector) + putdelta(root,fout); + + puttree(root->next,fout); + + nextbranch = root->branches; + while (nextbranch) { + puttree(nextbranch->hsh,fout); + nextbranch = nextbranch->nextbranch; + } +} + + + static exiting void +unexpected_EOF() +{ + faterror("unexpected EOF in diff output"); +} + +int putdtext(num,log,srcfilename,fout,diffmt) + char const *num, *srcfilename; + struct cbuf log; + FILE *fout; + int diffmt; +/* Function: write a deltatext-node to fout. + * num points to the deltanumber, log to the logmessage, and + * sourcefile contains the text. Doubles up all SDELIMs in both the + * log and the text; Makes sure the log message ends in \n. + * returns false on error. + * If diffmt is true, also checks that text is valid diff -n output. + */ +{ + RILE *fin; + int result; + if (!(fin = Iopen(srcfilename, "r", (struct stat*)0))) { + eerror(srcfilename); + return false; + } + result = putdftext(num,log,fin,fout,diffmt); + Ifclose(fin); + return result; +} + + void +putstring(out, delim, s, log) + register FILE *out; + struct cbuf s; + int delim, log; +/* + * Output to OUT one SDELIM if DELIM, then the string S with SDELIMs doubled. + * If LOG is set then S is a log string; append a newline if S is nonempty. + */ +{ + register char const *sp; + register size_t ss; + + if (delim) + aputc(SDELIM, out); + sp = s.string; + for (ss = s.size; ss; --ss) { + if (*sp == SDELIM) + aputc(SDELIM, out); + aputc(*sp++, out); + } + if (s.size && log) + aputc('\n', out); + aputc(SDELIM, out); +} + + int +putdftext(num,log,finfile,foutfile,diffmt) + char const *num; + struct cbuf log; + RILE *finfile; + FILE *foutfile; + int diffmt; +/* like putdtext(), except the source file is already open */ +{ + declarecache; + register FILE *fout; + register int c; + register RILE *fin; + int ed; + struct diffcmd dc; + + fout = foutfile; + aprintf(fout,DELNUMFORM,num,Klog); + /* put log */ + putstring(fout, true, log, true); + /* put text */ + aprintf(fout, "\n%s\n%c", Ktext, SDELIM); + fin = finfile; + setupcache(fin); + if (!diffmt) { + /* Copy the file */ + cache(fin); + for (;;) { + cachegeteof(c, break;); + if (c==SDELIM) aputc(SDELIM,fout); /*double up SDELIM*/ + aputc(c,fout); + } + } else { + initdiffcmd(&dc); + while (0 <= (ed = getdiffcmd(fin,false,fout,&dc))) + if (ed) { + cache(fin); + while (dc.nlines--) + do { + cachegeteof(c, { if (!dc.nlines) goto OK_EOF; unexpected_EOF(); }); + if (c == SDELIM) + aputc(SDELIM,fout); + aputc(c,fout); + } while (c != '\n'); + uncache(fin); + } + } + OK_EOF: + aprintf(fout, "%c\n", SDELIM); + return true; +} + + void +initdiffcmd(dc) + register struct diffcmd *dc; +/* Initialize *dc suitably for getdiffcmd(). */ +{ + dc->adprev = 0; + dc->dafter = 0; +} + + static exiting void +badDiffOutput(buf) + char const *buf; +{ + faterror("bad diff output line: %s", buf); +} + + static exiting void +diffLineNumberTooLarge(buf) + char const *buf; +{ + faterror("diff line number too large: %s", buf); +} + + int +getdiffcmd(finfile, delimiter, foutfile, dc) + RILE *finfile; + FILE *foutfile; + int delimiter; + struct diffcmd *dc; +/* Get a editing command output by 'diff -n' from fin. + * The input is delimited by SDELIM if delimiter is set, EOF otherwise. + * Copy a clean version of the command to fout (if nonnull). + * Yield 0 for 'd', 1 for 'a', and -1 for EOF. + * Store the command's line number and length into dc->line1 and dc->nlines. + * Keep dc->adprev and dc->dafter up to date. + */ +{ + register int c; + declarecache; + register FILE *fout; + register char *p; + register RILE *fin; + unsigned long line1, nlines, t; + char buf[BUFSIZ]; + + fin = finfile; + fout = foutfile; + setupcache(fin); cache(fin); + cachegeteof(c, { if (delimiter) unexpected_EOF(); return -1; } ); + if (delimiter) { + if (c==SDELIM) { + cacheget(c); + if (c==SDELIM) { + buf[0] = c; + buf[1] = 0; + badDiffOutput(buf); + } + uncache(fin); + nextc = c; + if (fout) + aprintf(fout, "%c%c", SDELIM, c); + return -1; + } + } + p = buf; + do { + if (buf+BUFSIZ-2 <= p) { + faterror("diff output command line too long"); + } + *p++ = c; + cachegeteof(c, unexpected_EOF();) ; + } while (c != '\n'); + uncache(fin); + if (delimiter) + ++rcsline; + *p = '\0'; + for (p = buf+1; (c = *p++) == ' '; ) + ; + line1 = 0; + while (isdigit(c)) { + t = line1 * 10; + if ( + ULONG_MAX/10 < line1 || + (line1 = t + (c - '0')) < t + ) + diffLineNumberTooLarge(buf); + c = *p++; + } + while (c == ' ') + c = *p++; + nlines = 0; + while (isdigit(c)) { + t = nlines * 10; + if ( + ULONG_MAX/10 < nlines || + (nlines = t + (c - '0')) < t + ) + diffLineNumberTooLarge(buf); + c = *p++; + } + if (c || !nlines) { + badDiffOutput(buf); + } + if (line1+nlines < line1) + diffLineNumberTooLarge(buf); + switch (buf[0]) { + case 'a': + if (line1 < dc->adprev) { + faterror("backward insertion in diff output: %s", buf); + } + dc->adprev = line1 + 1; + break; + case 'd': + if (line1 < dc->adprev || line1 < dc->dafter) { + faterror("backward deletion in diff output: %s", buf); + } + dc->adprev = line1; + dc->dafter = line1 + nlines; + break; + default: + badDiffOutput(buf); + } + if (fout) { + aprintf(fout, "%s\n", buf); + } + dc->line1 = line1; + dc->nlines = nlines; + return buf[0] == 'a'; +} + + + +#ifdef SYNTEST + +char const cmdid[] = "syntest"; + + int +main(argc,argv) +int argc; char * argv[]; +{ + + if (argc<2) { + aputs("No input file\n",stderr); + exitmain(EXIT_FAILURE); + } + if (!(finptr = Iopen(argv[1], FOPEN_R, (struct stat*)0))) { + faterror("can't open input file %s", argv[1]); + } + Lexinit(); + getadmin(); + putadmin(stdout); + + gettree(); + puttree(Head,stdout); + + getdesc(true); + + nextlex(); + + if (!eoflex()) { + fatserror("expecting EOF"); + } + exitmain(EXIT_SUCCESS); +} + + +exiting void exiterr() { _exit(EXIT_FAILURE); } + + +#endif + diff --git a/gnu/usr.bin/rcs/lib/rcsutil.c b/gnu/usr.bin/rcs/lib/rcsutil.c new file mode 100644 index 0000000000..c523ccf1df --- /dev/null +++ b/gnu/usr.bin/rcs/lib/rcsutil.c @@ -0,0 +1,994 @@ +/* + * RCS utilities + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + + +/* $Log: rcsutil.c,v $ + * Revision 5.10 1991/10/07 17:32:46 eggert + * Support piece tables even if !has_mmap. + * + * Revision 5.9 1991/08/19 03:13:55 eggert + * Add spawn() support. Explicate assumptions about getting invoker's name. + * Standardize user-visible dates. Tune. + * + * Revision 5.8 1991/04/21 11:58:30 eggert + * Plug setuid security hole. + * + * Revision 5.6 1991/02/26 17:48:39 eggert + * Fix setuid bug. Use fread, fwrite more portably. + * Support waitpid. Don't assume -1 is acceptable to W* macros. + * strsave -> str_save (DG/UX name clash) + * + * Revision 5.5 1990/12/04 05:18:49 eggert + * Don't output a blank line after a signal diagnostic. + * Use -I for prompts and -q for diagnostics. + * + * Revision 5.4 1990/11/01 05:03:53 eggert + * Remove unneeded setid check. Add awrite(), fremember(). + * + * Revision 5.3 1990/10/06 00:16:45 eggert + * Don't fread F if feof(F). + * + * Revision 5.2 1990/09/04 08:02:31 eggert + * Store fread()'s result in an fread_type object. + * + * Revision 5.1 1990/08/29 07:14:07 eggert + * Declare getpwuid() more carefully. + * + * Revision 5.0 1990/08/22 08:13:46 eggert + * Add setuid support. Permit multiple locks per user. + * Remove compile-time limits; use malloc instead. + * Switch to GMT. Permit dates past 1999/12/31. + * Add -V. Remove snooping. Ansify and Posixate. + * Tune. Some USG hosts define NSIG but not sys_siglist. + * Don't run /bin/sh if it's hopeless. + * Don't leave garbage behind if the output is an empty pipe. + * Clean up after SIGXCPU or SIGXFSZ. Print name of signal that caused cleanup. + * + * Revision 4.6 89/05/01 15:13:40 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.5 88/11/08 16:01:02 narten + * corrected use of varargs routines + * + * Revision 4.4 88/08/09 19:13:24 eggert + * Check for memory exhaustion. + * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch. + * Use execv(), not system(); yield exit status like diff(1)'s. + * + * Revision 4.3 87/10/18 10:40:22 narten + * Updating version numbers. Changes relative to 1.1 actually + * relative to 4.1 + * + * Revision 1.3 87/09/24 14:01:01 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:43 jenkins + * Port to suns + * + * Revision 4.1 83/05/10 15:53:13 wft + * Added getcaller() and findlock(). + * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal + * (needed for background jobs in older shells). Added restoreints(). + * Removed printing of full RCS path from logcommand(). + * + * Revision 3.8 83/02/15 15:41:49 wft + * Added routine fastcopy() to copy remainder of a file in blocks. + * + * Revision 3.7 82/12/24 15:25:19 wft + * added catchints(), ignoreints() for catching and ingnoring interrupts; + * fixed catchsig(). + * + * Revision 3.6 82/12/08 21:52:05 wft + * Using DATEFORM to format dates. + * + * Revision 3.5 82/12/04 18:20:49 wft + * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update + * lockedby-field. + * + * Revision 3.4 82/12/03 17:17:43 wft + * Added check to addlock() ensuring only one lock per person. + * Addlock also returns a pointer to the lock created. Deleted fancydate(). + * + * Revision 3.3 82/11/27 12:24:37 wft + * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c. + * Introduced macro SNOOP so that snoop can be placed in directory other than + * TARGETDIR. Changed %02d to %.2d for compatibility reasons. + * + * Revision 3.2 82/10/18 21:15:11 wft + * added function getfullRCSname(). + * + * Revision 3.1 82/10/13 16:17:37 wft + * Cleanup message is now suppressed in quiet mode. + */ + + + + +#include "rcsbase.h" + +libId(utilId, "$Id: rcsutil.c,v 5.10 1991/10/07 17:32:46 eggert Exp $") + +#if !has_memcmp + int +memcmp(s1, s2, n) + void const *s1, *s2; + size_t n; +{ + register unsigned char const + *p1 = (unsigned char const*)s1, + *p2 = (unsigned char const*)s2; + register size_t i = n; + register int r = 0; + while (i-- && !(r = (*p1++ - *p2++))) + ; + return r; +} +#endif + +#if !has_memcpy + void * +memcpy(s1, s2, n) + void *s1; + void const *s2; + size_t n; +{ + register char *p1 = (char*)s1; + register char const *p2 = (char const*)s2; + while (n--) + *p1++ = *p2++; + return s1; +} +#endif + +#if lint + malloc_type lintalloc; +#endif + +/* + * list of blocks allocated with ftestalloc() + * These blocks can be freed by ffree when we're done with the current file. + * We could put the free block inside struct alloclist, rather than a pointer + * to the free block, but that would be less portable. + */ +struct alloclist { + malloc_type alloc; + struct alloclist *nextalloc; +}; +static struct alloclist *alloced; + + + static malloc_type +okalloc(p) + malloc_type p; +{ + if (!p) + faterror("out of memory"); + return p; +} + + malloc_type +testalloc(size) + size_t size; +/* Allocate a block, testing that the allocation succeeded. */ +{ + return okalloc(malloc(size)); +} + + malloc_type +testrealloc(ptr, size) + malloc_type ptr; + size_t size; +/* Reallocate a block, testing that the allocation succeeded. */ +{ + return okalloc(realloc(ptr, size)); +} + + malloc_type +fremember(ptr) + malloc_type ptr; +/* Remember PTR in 'alloced' so that it can be freed later. Yield PTR. */ +{ + register struct alloclist *q = talloc(struct alloclist); + q->nextalloc = alloced; + alloced = q; + return q->alloc = ptr; +} + + malloc_type +ftestalloc(size) + size_t size; +/* Allocate a block, putting it in 'alloced' so it can be freed later. */ +{ + return fremember(testalloc(size)); +} + + void +ffree() +/* Free all blocks allocated with ftestalloc(). */ +{ + register struct alloclist *p, *q; + for (p = alloced; p; p = q) { + q = p->nextalloc; + tfree(p->alloc); + tfree(p); + } + alloced = nil; +} + + void +ffree1(f) + register char const *f; +/* Free the block f, which was allocated by ftestalloc. */ +{ + register struct alloclist *p, **a = &alloced; + + while ((p = *a)->alloc != f) + a = &p->nextalloc; + *a = p->nextalloc; + tfree(p->alloc); + tfree(p); +} + + char * +str_save(s) + char const *s; +/* Save s in permanently allocated storage. */ +{ + return strcpy(tnalloc(char, strlen(s)+1), s); +} + + char * +fstr_save(s) + char const *s; +/* Save s in storage that will be deallocated when we're done with this file. */ +{ + return strcpy(ftnalloc(char, strlen(s)+1), s); +} + + char * +cgetenv(name) + char const *name; +/* Like getenv(), but yield a copy; getenv() can overwrite old results. */ +{ + register char *p; + + return (p=getenv(name)) ? str_save(p) : p; +} + + char const * +getusername(suspicious) + int suspicious; +/* Get the caller's login name. Trust only getwpuid if SUSPICIOUS. */ +{ + static char *name; + + if (!name) { + if ( + /* Prefer getenv() unless suspicious; it's much faster. */ +# if getlogin_is_secure + (suspicious + || + !(name = cgetenv("LOGNAME")) + && !(name = cgetenv("USER"))) + && !(name = getlogin()) +# else + suspicious + || + !(name = cgetenv("LOGNAME")) + && !(name = cgetenv("USER")) + && !(name = getlogin()) +# endif + ) { +#if has_getuid && has_getpwuid + struct passwd const *pw = getpwuid(ruid()); + if (!pw) + faterror("no password entry for userid %lu", + (unsigned long)ruid() + ); + name = pw->pw_name; +#else +#if has_setuid + faterror("setuid not supported"); +#else + faterror("Who are you? Please set LOGNAME."); +#endif +#endif + } + checksid(name); + } + return name; +} + + + + +#if has_signal + +/* + * Signal handling + * + * Standard C places too many restrictions on signal handlers. + * We obey as many of them as we can. + * Posix places fewer restrictions, and we are Posix-compatible here. + */ + +static sig_atomic_t volatile heldsignal, holdlevel; + + static signal_type +catchsig(s) + int s; +{ + char const *sname; + char buf[BUFSIZ]; + +#if sig_zaps_handler + /* If a signal arrives before we reset the signal handler, we lose. */ + VOID signal(s, SIG_IGN); +#endif + if (holdlevel) { + heldsignal = s; + return; + } + ignoreints(); + setrid(); + if (!quietflag) { + sname = nil; +#if has_sys_siglist && defined(NSIG) + if ((unsigned)s < NSIG) { +# ifndef sys_siglist + extern char const *sys_siglist[]; +# endif + sname = sys_siglist[s]; + } +#else + switch (s) { +#ifdef SIGHUP + case SIGHUP: sname = "Hangup"; break; +#endif +#ifdef SIGINT + case SIGINT: sname = "Interrupt"; break; +#endif +#ifdef SIGPIPE + case SIGPIPE: sname = "Broken pipe"; break; +#endif +#ifdef SIGQUIT + case SIGQUIT: sname = "Quit"; break; +#endif +#ifdef SIGTERM + case SIGTERM: sname = "Terminated"; break; +#endif +#ifdef SIGXCPU + case SIGXCPU: sname = "Cputime limit exceeded"; break; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: sname = "Filesize limit exceeded"; break; +#endif + } +#endif + if (sname) + VOID sprintf(buf, "\nRCS: %s. Cleaning up.\n", sname); + else + VOID sprintf(buf, "\nRCS: Signal %d. Cleaning up.\n", s); + VOID write(STDERR_FILENO, buf, strlen(buf)); + } + exiterr(); +} + + void +ignoreints() +{ + ++holdlevel; +} + + void +restoreints() +{ + if (!--holdlevel && heldsignal) + VOID catchsig(heldsignal); +} + + +static int const sig[] = { +#ifdef SIGHUP + SIGHUP, +#endif +#ifdef SIGINT + SIGINT, +#endif +#ifdef SIGPIPE + SIGPIPE, +#endif +#ifdef SIGQUIT + SIGQUIT, +#endif +#ifdef SIGTERM + SIGTERM, +#endif +#ifdef SIGXCPU + SIGXCPU, +#endif +#ifdef SIGXFSZ + SIGXFSZ, +#endif +}; +#define SIGS (sizeof(sig)/sizeof(*sig)) + + +#if has_sigaction + + static void + check_sig(r) + int r; + { + if (r != 0) + efaterror("signal"); + } + + static void + setup_catchsig() + { + register int i; + sigset_t blocked; + struct sigaction act; + + check_sig(sigemptyset(&blocked)); + for (i=SIGS; 0<=--i; ) + check_sig(sigaddset(&blocked, sig[i])); + for (i=SIGS; 0<=--i; ) { + check_sig(sigaction(sig[i], (struct sigaction*)nil, &act)); + if (act.sa_handler != SIG_IGN) { + act.sa_handler = catchsig; + act.sa_mask = blocked; + check_sig(sigaction(sig[i], &act, (struct sigaction*)nil)); + } + } + } + +#else +#if has_sigblock + + static void + setup_catchsig() + { + register int i; + int mask; + + mask = 0; + for (i=SIGS; 0<=--i; ) + mask |= sigmask(sig[i]); + mask = sigblock(mask); + for (i=SIGS; 0<=--i; ) + if ( + signal(sig[i], catchsig) == SIG_IGN && + signal(sig[i], SIG_IGN) != catchsig + ) + faterror("signal catcher failure"); + VOID sigsetmask(mask); + } + +#else + + static void + setup_catchsig() + { + register i; + + for (i=SIGS; 0<=--i; ) + if ( + signal(sig[i], SIG_IGN) != SIG_IGN && + signal(sig[i], catchsig) != SIG_IGN + ) + faterror("signal catcher failure"); + } + +#endif +#endif + + void +catchints() +{ + static int catching_ints; + if (!catching_ints) { + catching_ints = true; + setup_catchsig(); + } +} + +#endif /* has_signal */ + + + void +fastcopy(inf,outf) + register RILE *inf; + FILE *outf; +/* Function: copies the remainder of file inf to outf. + */ +{ +#if large_memory +# if has_mmap + awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf); + inf->ptr = inf->lim; +# else + for (;;) { + awrite((char const*)inf->ptr, (size_t)(inf->readlim - inf->ptr), outf); + inf->ptr = inf->readlim; + if (inf->ptr == inf->lim) + break; + VOID Igetmore(inf); + } +# endif +#else + char buf[BUFSIZ*8]; + register fread_type rcount; + + /*now read the rest of the file in blocks*/ + while (!feof(inf)) { + if (!(rcount = Fread(buf,sizeof(*buf),sizeof(buf),inf))) { + testIerror(inf); + return; + } + awrite(buf, (size_t)rcount, outf); + } +#endif +} + +#ifndef SSIZE_MAX + /* This does not work in #ifs, but it's good enough for us. */ + /* Underestimating SSIZE_MAX may slow us down, but it won't break us. */ +# define SSIZE_MAX ((unsigned)-1 >> 1) +#endif + + void +awrite(buf, chars, f) + char const *buf; + size_t chars; + FILE *f; +{ + /* Posix 1003.1-1990 ssize_t hack */ + while (SSIZE_MAX < chars) { + if (Fwrite(buf, sizeof(*buf), SSIZE_MAX, f) != SSIZE_MAX) + Oerror(); + buf += SSIZE_MAX; + chars -= SSIZE_MAX; + } + + if (Fwrite(buf, sizeof(*buf), chars, f) != chars) + Oerror(); +} + + + + + + static int +movefd(old, new) + int old, new; +{ + if (old < 0 || old == new) + return old; +# ifdef F_DUPFD + new = fcntl(old, F_DUPFD, new); +# else + new = dup2(old, new); +# endif + return close(old)==0 ? new : -1; +} + + static int +fdreopen(fd, file, flags) + int fd; + char const *file; + int flags; +{ + int newfd; + VOID close(fd); + newfd = +#if !open_can_creat + flags&O_CREAT ? creat(file, S_IRUSR|S_IWUSR) : +#endif + open(file, flags, S_IRUSR|S_IWUSR); + return movefd(newfd, fd); +} + +#if !has_spawn + static void +tryopen(fd,file,flags) + int fd, flags; + char const *file; +{ + if (file && fdreopen(fd,file,flags) != fd) + efaterror(file); +} +#else + static int +tryopen(fd,file,flags) + int fd, flags; + char const *file; +{ + int newfd = -1; + if (file && ((newfd=dup(fd)) < 0 || fdreopen(fd,file,flags) != fd)) + efaterror(file); + return newfd; +} + static void +redirect(old, new) + int old, new; +{ + if (0 <= old && (close(new) != 0 || movefd(old,new) < 0)) + efaterror("spawn I/O redirection"); +} +#endif + + + +#if !has_fork && !has_spawn + static void +bufargcat(b, c, s) + register struct buf *b; + int c; + register char const *s; +/* Append to B a copy of C, plus a quoted copy of S. */ +{ + register char *p; + register char const *t; + size_t bl, sl; + + for (t=s, sl=0; *t; ) + sl += 3*(*t++=='\'') + 1; + bl = strlen(b->string); + bufrealloc(b, bl + sl + 4); + p = b->string + bl; + *p++ = c; + *p++ = '\''; + while (*s) { + if (*s == '\'') { + *p++ = '\''; + *p++ = '\\'; + *p++ = '\''; + } + *p++ = *s++; + } + *p++ = '\''; + *p = 0; +} +#endif + +/* +* Run a command specified by the strings in 'inoutargs'. +* inoutargs[0], if nonnil, is the name of the input file. +* inoutargs[1], if nonnil, is the name of the output file. +* inoutargs[2..] form the command to be run. +*/ + int +runv(inoutargs) + char const **inoutargs; +{ + register char const **p; + int wstatus; + + oflush(); + eflush(); + { +#if has_spawn + int in, out; + p = inoutargs; + in = tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY); + out = tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY); + wstatus = spawn_RCS(0, *p, (char*const*)p); + if (wstatus == -1 && errno == ENOEXEC) { + *--p = RCS_SHELL; + wstatus = spawnv(0, *p, (char*const*)p); + } + redirect(in, STDIN_FILENO); + redirect(out, STDOUT_FILENO); +#else +#if has_fork + pid_t pid; +# if !has_waitpid + pid_t w; +# endif + if (!(pid = vfork())) { + p = inoutargs; + tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY); + tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY); + VOID exec_RCS(*p, (char*const*)p); + if (errno == ENOEXEC) { + *--p = RCS_SHELL; + VOID execv(*p, (char*const*)p); + } + VOID write(STDERR_FILENO, *p, strlen(*p)); + VOID write(STDERR_FILENO, ": not found\n", 12); + _exit(EXIT_TROUBLE); + } + if (pid < 0) + efaterror("fork"); +# if has_waitpid + if (waitpid(pid, &wstatus, 0) < 0) + efaterror("waitpid"); +# else + do { + if ((w = wait(&wstatus)) < 0) + efaterror("wait"); + } while (w != pid); +# endif +#else + static struct buf b; + + /* Use system(). On many hosts system() discards signals. Yuck! */ + p = inoutargs+2; + bufscpy(&b, *p); + while (*++p) + bufargcat(&b, ' ', *p); + if (inoutargs[0]) + bufargcat(&b, '<', inoutargs[0]); + if (inoutargs[1]) + bufargcat(&b, '>', inoutargs[1]); + wstatus = system(b.string); +#endif +#endif + } + if (!WIFEXITED(wstatus)) + faterror("%s failed", inoutargs[2]); + return WEXITSTATUS(wstatus); +} + +#define CARGSMAX 20 +/* +* Run a command. +* The first two arguments are the input and output files (if nonnil); +* the rest specify the command and its arguments. +*/ + int +#if has_prototypes +run(char const *infile, char const *outfile, ...) +#else + /*VARARGS2*/ +run(infile, outfile, va_alist) + char const *infile; + char const *outfile; + va_dcl +#endif +{ + va_list ap; + char const *rgargs[CARGSMAX]; + register i = 0; + rgargs[0] = infile; + rgargs[1] = outfile; + vararg_start(ap, outfile); + for (i = 2; (rgargs[i++] = va_arg(ap, char const*)); ) + if (CARGSMAX <= i) + faterror("too many command arguments"); + va_end(ap); + return runv(rgargs); +} + + + char const * +date2str(date, datebuf) + char const date[datesize]; + char datebuf[datesize]; +/* +* Format a user-readable form of the RCS format DATE into the buffer DATEBUF. +* Yield DATEBUF. +*/ +{ + register char const *p = date; + + while (*p++ != '.') + ; + VOID sprintf(datebuf, + "19%.*s/%.2s/%.2s %.2s:%.2s:%s" + + (date[2]=='.' && VERSION(5)<=RCSversion ? 0 : 2), + (int)(p-date-1), date, + p, p+3, p+6, p+9, p+12 + ); + return datebuf; +} + + +int RCSversion; + + void +setRCSversion(str) + char const *str; +{ + static int oldversion; + + register char const *s = str + 2; + int v = VERSION_DEFAULT; + + if (oldversion) + redefined('V'); + oldversion = true; + + if (*s) { + v = 0; + while (isdigit(*s)) + v = 10*v + *s++ - '0'; + if (*s) + faterror("%s isn't a number", str); + if (v < VERSION_min || VERSION_max < v) + faterror("%s out of range %d..%d", str, VERSION_min, VERSION_max); + } + + RCSversion = VERSION(v); +} + + int +getRCSINIT(argc, argv, newargv) + int argc; + char **argv, ***newargv; +{ + register char *p, *q, **pp; + unsigned n; + + if (!(q = cgetenv("RCSINIT"))) + *newargv = argv; + else { + n = argc + 2; + /* + * Count spaces in RCSINIT to allocate a new arg vector. + * This is an upper bound, but it's OK even if too large. + */ + for (p = q; ; ) { + switch (*p++) { + default: + continue; + + case ' ': + case '\b': case '\f': case '\n': + case '\r': case '\t': case '\v': + n++; + continue; + + case '\0': + break; + } + break; + } + *newargv = pp = tnalloc(char*, n); + *pp++ = *argv++; /* copy program name */ + for (p = q; ; ) { + for (;;) { + switch (*q) { + case '\0': + goto copyrest; + + case ' ': + case '\b': case '\f': case '\n': + case '\r': case '\t': case '\v': + q++; + continue; + } + break; + } + *pp++ = p; + ++argc; + for (;;) { + switch ((*p++ = *q++)) { + case '\0': + goto copyrest; + + case '\\': + if (!*q) + goto copyrest; + p[-1] = *q++; + continue; + + default: + continue; + + case ' ': + case '\b': case '\f': case '\n': + case '\r': case '\t': case '\v': + break; + } + break; + } + p[-1] = '\0'; + } + copyrest: + while ((*pp++ = *argv++)) + ; + } + return argc; +} + + +#define cacheid(E) static uid_t i; static int s; if (!s){ s=1; i=(E); } return i + +#if has_getuid + uid_t ruid() { cacheid(getuid()); } +#endif +#if has_setuid + uid_t euid() { cacheid(geteuid()); } +#endif + + +#if has_setuid + +/* + * Setuid execution really works only with Posix 1003.1a Draft 5 seteuid(), + * because it lets us switch back and forth between arbitrary users. + * If seteuid() doesn't work, we fall back on setuid(), + * which works if saved setuid is supported, + * unless the real or effective user is root. + * This area is such a mess that we always check switches at runtime. + */ + + static void +set_uid_to(u) + uid_t u; +/* Become user u. */ +{ + static int looping; + + if (euid() == ruid()) + return; +#if (has_fork||has_spawn) && DIFF_ABSOLUTE + if (seteuid(u) != 0) + efaterror("setuid"); +#endif + if (geteuid() != u) { + if (looping) + return; + looping = true; + faterror("root setuid not supported" + (u?5:0)); + } +} + +static int stick_with_euid; + + void +/* Ignore all calls to seteid() and setrid(). */ +nosetid() +{ + stick_with_euid = true; +} + + void +seteid() +/* Become effective user. */ +{ + if (!stick_with_euid) + set_uid_to(euid()); +} + + void +setrid() +/* Become real user. */ +{ + if (!stick_with_euid) + set_uid_to(ruid()); +} +#endif diff --git a/gnu/usr.bin/rcs/merge/Makefile b/gnu/usr.bin/rcs/merge/Makefile new file mode 100644 index 0000000000..d14afb2885 --- /dev/null +++ b/gnu/usr.bin/rcs/merge/Makefile @@ -0,0 +1,7 @@ +PROG= merge + +SRCS= merge.c +LDADD= -L${.CURDIR}/../lib/obj -lrcs +CFLAGS+= -I${.CURDIR}/../lib + +.include diff --git a/gnu/usr.bin/rcs/merge/merge.1 b/gnu/usr.bin/rcs/merge/merge.1 new file mode 100644 index 0000000000..8b1957fca0 --- /dev/null +++ b/gnu/usr.bin/rcs/merge/merge.1 @@ -0,0 +1,102 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: merge.1,v 5.3 1991/02/28 19:18:45 eggert Exp $ +.TH MERGE 1 \*(Dt GNU +.SH NAME +merge \- three-way file merge +.SH SYNOPSIS +.B merge +[ +.B \-L +.I label1 +[ +.B \-L +.I label3 +] ] [ +.B \-p +] [ +.B \-q +] +.I "file1 file2 file3" +.SH DESCRIPTION +.B merge +incorporates all changes that lead from +.I file2 +to +.I file3 +into +.IR file1 . +The result goes to standard output if +.B \-p +is present, into +.I file1 +otherwise. +.B merge +is useful for combining separate changes to an original. Suppose +.I file2 +is the original, and both +.I file1 +and +.I file3 +are modifications of +.IR file2 . +Then +.B merge +combines both changes. +.PP +An overlap occurs if both +.I file1 +and +.I file3 +have changes in a common segment of lines. +On a few older hosts where +.B diff3 +does not support the +.B \-E +option, +.B merge +does not detect overlaps, and merely supplies the changed lines from +.I file3. +On most hosts, if overlaps occur, +.B merge +outputs a message (unless the +.B \-q +option is given), +and includes both alternatives +in the result. The alternatives are delimited as follows: +.LP +.RS +.nf +.BI <<<<<<< " file1" +.I "lines in file1" +.B "=======" +.I "lines in file3" +.BI >>>>>>> " file3" +.RE +.fi +.LP +If there are overlaps, the user should edit the result and delete one of the +alternatives. +If the +.BI \-L "\ label1" +and +.BI \-L "\ label3" +options are given, the labels are output in place of the names +.I file1 +and +.I file3 +in overlap reports. +.SH DIAGNOSTICS +Exit status is 0 for no overlaps, 1 for some overlaps, 2 for trouble. +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH SEE ALSO +diff3(1), diff(1), rcsmerge(1), co(1). diff --git a/gnu/usr.bin/rcs/merge/merge.c b/gnu/usr.bin/rcs/merge/merge.c new file mode 100644 index 0000000000..4067c184a2 --- /dev/null +++ b/gnu/usr.bin/rcs/merge/merge.c @@ -0,0 +1,97 @@ +/* merge - three-way file merge */ + +/* Copyright 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + +#include "rcsbase.h" + + +static char const usage[] = + "\nmerge: usage: merge [-p] [-q] [-L label1 [-L label3]] file1 file2 file3\n"; + + static exiting void +badoption(a) + char const *a; +{ + faterror("unknown option: %s%s", a-2, usage); +} + + +mainProg(mergeId, "merge", "$Id: merge.c,v 1.2 1991/08/19 03:13:55 eggert Exp $") +{ + register char const *a; + char const *label[2], *arg[3]; + int labels, tostdout; + + labels = 0; + tostdout = false; + + while ((a = *++argv) && *a++ == '-') { + switch (*a++) { + case 'p': tostdout = true; break; + case 'q': quietflag = true; break; + case 'L': + if (1 diff --git a/gnu/usr.bin/rcs/rcs/rcs.1 b/gnu/usr.bin/rcs/rcs/rcs.1 new file mode 100644 index 0000000000..9866a9c005 --- /dev/null +++ b/gnu/usr.bin/rcs/rcs/rcs.1 @@ -0,0 +1,397 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: rcs.1,v 5.6 1991/09/26 23:16:17 eggert Exp $ +.ds r \&\s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.TH RCS 1 \*(Dt GNU +.SH NAME +rcs \- change RCS file attributes +.SH SYNOPSIS +.B rcs +.RI [ " options " ] " file " .\|.\|. +.SH DESCRIPTION +.B rcs +creates new \*r files or changes attributes of existing ones. +An \*r file contains multiple revisions of text, +an access list, a change log, +descriptive text, +and some control attributes. +For +.B rcs +to work, the caller's login name must be on the access list, +except if the access list is empty, the caller is the owner of the file +or the superuser, or +the +.B \-i +option is present. +.PP +Pathnames matching an \*r suffix denote \*r files; +all others denote working files. +Names are paired as explained in +.BR ci (1). +Revision numbers use the syntax described in +.BR ci (1). +.SH OPTIONS +.TP +.B \-i +Create and initialize a new \*r file, but do not deposit any revision. +If the \*r file has no path prefix, try to place it +first into the subdirectory +.BR ./RCS , +and then into the current directory. +If the \*r file +already exists, print an error message. +.TP +.BI \-a "logins" +Append the login names appearing in the comma-separated list +.I logins +to the access list of the \*r file. +.TP +.BI \-A "oldfile" +Append the access list of +.I oldfile +to the access list of the \*r file. +.TP +.BR \-e [\f2logins\fP] +Erase the login names appearing in the comma-separated list +.I logins +from the access list of the \*r file. +If +.I logins +is omitted, erase the entire access list. +.TP +.BR \-b [\f2rev\fP] +Set the default branch to +.IR rev . +If +.I rev +is omitted, the default +branch is reset to the (dynamically) highest branch on the trunk. +.TP +.BI \-c string +sets the comment leader to +.IR string . +The comment leader +is printed before every log message line generated by the keyword +.B $\&Log$ +during checkout (see +.BR co (1)). +This is useful for programming +languages without multi-line comments. +An initial +.B ci , +or an +.B "rcs\ \-i" +without +.BR \-c , +guesses the comment leader from the suffix of the working file. +.TP +.BI \-k subst +Set the default keyword substitution to +.IR subst . +The effect of keyword substitution is described in +.BR co (1). +Giving an explicit +.B \-k +option to +.BR co , +.BR rcsdiff , +and +.B rcsmerge +overrides this default. +Beware +.BR "rcs\ \-kv", +because +.B \-kv +is incompatible with +.BR "co\ \-l". +Use +.B "rcs\ \-kkv" +to restore the normal default keyword substitution. +.TP +.BR \-l [\f2rev\fP] +Lock the revision with number +.IR rev . +If a branch is given, lock the latest revision on that branch. +If +.I rev +is omitted, lock the latest revision on the default branch. +Locking prevents overlapping changes. +A lock is removed with +.B ci +or +.B "rcs\ \-u" +(see below). +.TP +.BR \-u [\f2rev\fP] +Unlock the revision with number +.IR rev . +If a branch is given, unlock the latest revision on that branch. +If +.I rev +is omitted, remove the latest lock held by the caller. +Normally, only the locker of a revision may unlock it. +Somebody else unlocking a revision breaks the lock. +This causes a mail message to be sent to the original locker. +The message contains a commentary solicited from the breaker. +The commentary is terminated by end-of-file or by a line containing +.BR \&. "\ by" +itself. +.TP +.B \-L +Set locking to +.IR strict . +Strict locking means that the owner +of an \*r file is not exempt from locking for checkin. +This option should be used for files that are shared. +.TP +.B \-U +Set locking to non-strict. Non-strict locking means that the owner of +a file need not lock a revision for checkin. +This option should +.I not +be used for files that are shared. +Whether default locking is strict is determined by your system administrator, +but it is normally strict. +.TP +\f3\-m\fP\f2rev\fP\f3:\fP\f2msg\fP +Replace revision +.IR rev 's +log message with +.IR msg . +.TP +\f3\-n\fP\f2name\fP[\f3:\fP[\f2rev\fP]] +Associate the symbolic name +.I name +with the branch or +revision +.IR rev . +Delete the symbolic name if both +.B : +and +.I rev +are omitted; otherwise, print an error message if +.I name +is already associated with +another number. +If +.I rev +is symbolic, it is expanded before association. +A +.I rev +consisting of a branch number followed by a +.B .\& +stands for the current latest revision in the branch. +A +.B : +with an empty +.I rev +stands for the current latest revision on the default branch, +normally the trunk. +For example, +.BI "rcs\ \-n" name ":\ RCS/*" +associates +.I name +with the current latest revision of all the named \*r files; +this contrasts with +.BI "rcs\ \-n" name ":$\ RCS/*" +which associates +.I name +with the revision numbers extracted from keyword strings +in the corresponding working files. +.TP +\f3\-N\fP\f2name\fP[\f3:\fP[\f2rev\fP]] +Act like +.BR \-n , +except override any previous assignment of +.IR name . +.TP +.BI \-o range +deletes (\*(lqoutdates\*(rq) the revisions given by +.IR range . +A range consisting of a single revision number means that revision. +A range consisting of a branch number means the latest revision on that +branch. +A range of the form +.IB rev1 : rev2 +means +revisions +.I rev1 +to +.I rev2 +on the same branch, +.BI : rev +means from the beginning of the branch containing +.I rev +up to and including +.IR rev , +and +.IB rev : +means +from revision +.I rev +to the end of the branch containing +.IR rev . +None of the outdated revisions may have branches or locks. +.TP +.B \-q +Run quietly; do not print diagnostics. +.TP +.B \-I +Run interactively, even if the standard input is not a terminal. +.TP +.B \-s\f2state\fP\f1[\fP:\f2rev\fP\f1]\fP +Set the state attribute of the revision +.I rev +to +.I state . +If +.I rev +is a branch number, assume the latest revision on that branch. +If +.I rev +is omitted, assume the latest revision on the default branch. +Any identifier is acceptable for +.IR state . +A useful set of states +is +.B Exp +(for experimental), +.B Stab +(for stable), and +.B Rel +(for +released). +By default, +.BR ci (1) +sets the state of a revision to +.BR Exp . +.TP +.BR \-t [\f2file\fP] +Write descriptive text from the contents of the named +.I file +into the \*r file, deleting the existing text. +The +.IR file +pathname may not begin with +.BR \- . +If +.I file +is omitted, obtain the text from standard input, +terminated by end-of-file or by a line containing +.BR \&. "\ by" +itself. +Prompt for the text if interaction is possible; see +.BR \-I . +With +.BR \-i , +descriptive text is obtained +even if +.B \-t +is not given. +.TP +.BI \-t\- string +Write descriptive text from the +.I string +into the \*r file, deleting the existing text. +.TP +.BI \-V n +Emulate \*r version +.IR n . +See +.BR co (1) +for details. +.TP +.BI \-x "suffixes" +Use +.I suffixes +to characterize \*r files. +See +.BR ci (1) +for details. +.SH COMPATIBILITY +The +.BI \-b rev +option generates an \*r file that cannot be parsed by \*r version 3 or earlier. +.PP +The +.BI \-k subst +options (except +.BR \-kkv ) +generate an \*r file that cannot be parsed by \*r version 4 or earlier. +.PP +Use +.BI "rcs \-V" n +to make an \*r file acceptable to \*r version +.I n +by discarding information that would confuse version +.IR n . +.PP +\*r version 5.5 and earlier does not support the +.B \-x +option, and requires a +.B ,v +suffix on an \*r pathname. +.SH FILES +.B rcs +accesses files much as +.BR ci (1) +does, +except that it uses the effective user for all accesses, +it does not write the working file or its directory, +and it does not even read the working file unless a revision number of +.B $ +is specified. +.SH ENVIRONMENT +.TP +.B \s-1RCSINIT\s0 +options prepended to the argument list, separated by spaces. +See +.BR ci (1) +for details. +.SH DIAGNOSTICS +The \*r pathname and the revisions outdated are written to +the diagnostic output. +The exit status is zero if and only if all operations were successful. +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH "SEE ALSO" +co(1), ci(1), ident(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1), +rcsfile(5) +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. +.SH BUGS +The separator for revision ranges in the +.B \-o +option used to be +.B \- +instead of +.BR : , +but this leads to confusion when symbolic names contain +.BR \- . +For backwards compatibility +.B "rcs \-o" +still supports the old +.B \- +separator, but it warns about this obsolete use. +.PP +Symbolic names need not refer to existing revisions or branches. +For example, the +.B \-o +option does not remove symbolic names for the outdated revisions; you must use +.B \-n +to remove the names. +.br diff --git a/gnu/usr.bin/rcs/rcs/rcs.c b/gnu/usr.bin/rcs/rcs/rcs.c new file mode 100644 index 0000000000..70e7ffc5a8 --- /dev/null +++ b/gnu/usr.bin/rcs/rcs/rcs.c @@ -0,0 +1,1554 @@ +/* + * RCS create/change operation + */ +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + + +/* $Log: rcs.c,v $ + * Revision 5.12 1991/11/20 17:58:08 eggert + * Don't read the delta tree from a nonexistent RCS file. + * + * Revision 5.11 1991/10/07 17:32:46 eggert + * Remove lint. + * + * Revision 5.10 1991/08/19 23:17:54 eggert + * Add -m, -r$, piece tables. Revision separator is `:', not `-'. Tune. + * + * Revision 5.9 1991/04/21 11:58:18 eggert + * Add -x, RCSINIT, MS-DOS support. + * + * Revision 5.8 1991/02/25 07:12:38 eggert + * strsave -> str_save (DG/UX name clash) + * 0444 -> S_IRUSR|S_IRGRP|S_IROTH for portability + * + * Revision 5.7 1990/12/18 17:19:21 eggert + * Fix bug with multiple -n and -N options. + * + * Revision 5.6 1990/12/04 05:18:40 eggert + * Use -I for prompts and -q for diagnostics. + * + * Revision 5.5 1990/11/11 00:06:35 eggert + * Fix `rcs -e' core dump. + * + * Revision 5.4 1990/11/01 05:03:33 eggert + * Add -I and new -t behavior. Permit arbitrary data in logs. + * + * Revision 5.3 1990/10/04 06:30:16 eggert + * Accumulate exit status across files. + * + * Revision 5.2 1990/09/04 08:02:17 eggert + * Standardize yes-or-no procedure. + * + * Revision 5.1 1990/08/29 07:13:51 eggert + * Remove unused setuid support. Clean old log messages too. + * + * Revision 5.0 1990/08/22 08:12:42 eggert + * Don't lose names when applying -a option to multiple files. + * Remove compile-time limits; use malloc instead. Add setuid support. + * Permit dates past 1999/12/31. Make lock and temp files faster and safer. + * Ansify and Posixate. Add -V. Fix umask bug. Make linting easier. Tune. + * Yield proper exit status. Check diff's output. + * + * Revision 4.11 89/05/01 15:12:06 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.10 88/11/08 16:01:54 narten + * didn't install previous patch correctly + * + * Revision 4.9 88/11/08 13:56:01 narten + * removed include (not needed) + * minor fix for -A option + * + * Revision 4.8 88/08/09 19:12:27 eggert + * Don't access freed storage. + * Use execv(), not system(); yield proper exit status; remove lint. + * + * Revision 4.7 87/12/18 11:37:17 narten + * lint cleanups (Guy Harris) + * + * Revision 4.6 87/10/18 10:28:48 narten + * Updating verison numbers. Changes relative to 1.1 are actually + * relative to 4.3 + * + * Revision 1.4 87/09/24 13:58:52 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.3 87/03/27 14:21:55 jenkins + * Port to suns + * + * Revision 1.2 85/12/17 13:59:09 albitz + * Changed setstate to rcs_setstate because of conflict with random.o. + * + * Revision 4.3 83/12/15 12:27:33 wft + * rcs -u now breaks most recent lock if it can't find a lock by the caller. + * + * Revision 4.2 83/12/05 10:18:20 wft + * Added conditional compilation for sending mail. + * Alternatives: V4_2BSD, V6, USG, and other. + * + * Revision 4.1 83/05/10 16:43:02 wft + * Simplified breaklock(); added calls to findlock() and getcaller(). + * Added option -b (default branch). Updated -s and -w for -b. + * Removed calls to stat(); now done by pairfilenames(). + * Replaced most catchints() calls with restoreints(). + * Removed check for exit status of delivermail(). + * Directed all interactive output to stderr. + * + * Revision 3.9.1.1 83/12/02 22:08:51 wft + * Added conditional compilation for 4.2 sendmail and 4.1 delivermail. + * + * Revision 3.9 83/02/15 15:38:39 wft + * Added call to fastcopy() to copy remainder of RCS file. + * + * Revision 3.8 83/01/18 17:37:51 wft + * Changed sendmail(): now uses delivermail, and asks whether to break the lock. + * + * Revision 3.7 83/01/15 18:04:25 wft + * Removed putree(); replaced with puttree() in rcssyn.c. + * Combined putdellog() and scanlogtext(); deleted putdellog(). + * Cleaned up diagnostics and error messages. Fixed problem with + * mutilated files in case of deletions in 2 files in a single command. + * Changed marking of selector from 'D' to DELETE. + * + * Revision 3.6 83/01/14 15:37:31 wft + * Added ignoring of interrupts while new RCS file is renamed; + * Avoids deletion of RCS files by interrupts. + * + * Revision 3.5 82/12/10 21:11:39 wft + * Removed unused variables, fixed checking of return code from diff, + * introduced variant COMPAT2 for skipping Suffix on -A files. + * + * Revision 3.4 82/12/04 13:18:20 wft + * Replaced getdelta() with gettree(), changed breaklock to update + * field lockedby, added some diagnostics. + * + * Revision 3.3 82/12/03 17:08:04 wft + * Replaced getlogin() with getpwuid(), flcose() with ffclose(), + * /usr/ucb/Mail with macro MAIL. Removed handling of Suffix (-x). + * fixed -u for missing revno. Disambiguated structure members. + * + * Revision 3.2 82/10/18 21:05:07 wft + * rcs -i now generates a file mode given by the umask minus write permission; + * otherwise, rcs keeps the mode, but removes write permission. + * I added a check for write error, fixed call to getlogin(), replaced + * curdir() with getfullRCSname(), cleaned up handling -U/L, and changed + * conflicting, long identifiers. + * + * Revision 3.1 82/10/13 16:11:07 wft + * fixed type of variables receiving from getc() (char -> int). + */ + + +#include "rcsbase.h" + +struct Lockrev { + char const *revno; + struct Lockrev * nextrev; +}; + +struct Symrev { + char const *revno; + char const *ssymbol; + int override; + struct Symrev * nextsym; +}; + +struct Message { + char const *revno; + struct cbuf message; + struct Message *nextmessage; +}; + +struct Status { + char const *revno; + char const *status; + struct Status * nextstatus; +}; + +enum changeaccess {append, erase}; +struct chaccess { + char const *login; + enum changeaccess command; + struct chaccess *nextchaccess; +}; + +struct delrevpair { + char const *strt; + char const *end; + int code; +}; + +static int buildeltatext P((struct hshentries const*)); +static int removerevs P((void)); +static int sendmail P((char const*,char const*)); +static struct Lockrev *rmnewlocklst P((struct Lockrev const*)); +static void breaklock P((struct hshentry const*)); +static void buildtree P((void)); +static void cleanup P((void)); +static void doaccess P((void)); +static void doassoc P((void)); +static void dolocks P((void)); +static void domessages P((void)); +static void getaccessor P((char*,enum changeaccess)); +static void getassoclst P((int,char*)); +static void getchaccess P((char const*,enum changeaccess)); +static void getdelrev P((char*)); +static void getmessage P((char*)); +static void getstates P((char*)); +static void rcs_setstate P((char const*,char const*)); +static void scanlogtext P((struct hshentry*,int)); +static void setlock P((char const*)); + +static struct buf numrev; +static char const *headstate; +static int chgheadstate, exitstatus, lockhead, unlockcaller; +static struct Lockrev *newlocklst, *rmvlocklst; +static struct Message *messagelst, *lastmessage; +static struct Status *statelst, *laststate; +static struct Symrev *assoclst, *lastassoc; +static struct chaccess *chaccess, **nextchaccess; +static struct delrevpair delrev; +static struct hshentry *cuthead, *cuttail, *delstrt; +static struct hshentries *gendeltas; + +mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $") +{ + static char const cmdusage[] = + "\nrcs usage: rcs -{ae}logins -Afile -{blu}[rev] -cstring -{iLU} -{nNs}name[:rev] -orange -t[file] -Vn file ..."; + + char *a, **newargv, *textfile; + char const *branchsym, *commsyml; + int branchflag, expmode, initflag; + int e, r, strictlock, strict_selected, textflag; + mode_t defaultRCSmode; /* default mode for new RCS files */ + mode_t RCSmode; + struct buf branchnum; + struct stat workstat; + struct Lockrev *curlock, * rmvlock, *lockpt; + struct Status * curstate; + + nosetid(); + + nextchaccess = &chaccess; + branchsym = commsyml = textfile = nil; + branchflag = strictlock = false; + bufautobegin(&branchnum); + curlock = rmvlock = nil; + defaultRCSmode = 0; + expmode = -1; + suffixes = X_DEFAULT; + initflag= textflag = false; + strict_selected = 0; + + /* preprocessing command options */ + argc = getRCSINIT(argc, argv, &newargv); + argv = newargv; + while (a = *++argv, 0<--argc && *a++=='-') { + switch (*a++) { + + case 'i': /* initial version */ + initflag = true; + break; + + case 'b': /* change default branch */ + if (branchflag) redefined('b'); + branchflag= true; + branchsym = a; + break; + + case 'c': /* change comment symbol */ + if (commsyml) redefined('c'); + commsyml = a; + break; + + case 'a': /* add new accessor */ + getaccessor(*argv+1, append); + break; + + case 'A': /* append access list according to accessfile */ + if (!*a) { + error("missing file name after -A"); + break; + } + *argv = a; + if (0 < pairfilenames(1,argv,rcsreadopen,true,false)) { + while (AccessList) { + getchaccess(str_save(AccessList->login),append); + AccessList = AccessList->nextaccess; + } + Izclose(&finptr); + } + break; + + case 'e': /* remove accessors */ + getaccessor(*argv+1, erase); + break; + + case 'l': /* lock a revision if it is unlocked */ + if (!*a) { + /* Lock head or default branch. */ + lockhead = true; + break; + } + lockpt = talloc(struct Lockrev); + lockpt->revno = a; + lockpt->nextrev = nil; + if ( curlock ) + curlock->nextrev = lockpt; + else + newlocklst = lockpt; + curlock = lockpt; + break; + + case 'u': /* release lock of a locked revision */ + if (!*a) { + unlockcaller=true; + break; + } + lockpt = talloc(struct Lockrev); + lockpt->revno = a; + lockpt->nextrev = nil; + if (rmvlock) + rmvlock->nextrev = lockpt; + else + rmvlocklst = lockpt; + rmvlock = lockpt; + + curlock = rmnewlocklst(lockpt); + break; + + case 'L': /* set strict locking */ + if (strict_selected++) { /* Already selected L or U? */ + if (!strictlock) /* Already selected -U? */ + warn("-L overrides -U."); + } + strictlock = true; + break; + + case 'U': /* release strict locking */ + if (strict_selected++) { /* Already selected L or U? */ + if (strictlock) /* Already selected -L? */ + warn("-L overrides -U."); + } + else + strictlock = false; + break; + + case 'n': /* add new association: error, if name exists */ + if (!*a) { + error("missing symbolic name after -n"); + break; + } + getassoclst(false, (*argv)+1); + break; + + case 'N': /* add or change association */ + if (!*a) { + error("missing symbolic name after -N"); + break; + } + getassoclst(true, (*argv)+1); + break; + + case 'm': /* change log message */ + getmessage(a); + break; + + case 'o': /* delete revisions */ + if (delrev.strt) redefined('o'); + if (!*a) { + error("missing revision range after -o"); + break; + } + getdelrev( (*argv)+1 ); + break; + + case 's': /* change state attribute of a revision */ + if (!*a) { + error("state missing after -s"); + break; + } + getstates( (*argv)+1); + break; + + case 't': /* change descriptive text */ + textflag=true; + if (*a) { + if (textfile) redefined('t'); + textfile = a; + } + break; + + case 'I': + interactiveflag = true; + break; + + case 'q': + quietflag = true; + break; + + case 'x': + suffixes = a; + break; + + case 'V': + setRCSversion(*argv); + break; + + case 'k': /* set keyword expand mode */ + if (0 <= expmode) redefined('k'); + if (0 <= (expmode = str2expmode(a))) + break; + /* fall into */ + default: + faterror("unknown option: %s%s", *argv, cmdusage); + }; + } /* end processing of options */ + + if (argc<1) faterror("no input file%s", cmdusage); + if (nerror) { + diagnose("%s aborted\n",cmdid); + exitmain(EXIT_FAILURE); + } + if (initflag) { + defaultRCSmode = umask((mode_t)0); + VOID umask(defaultRCSmode); + defaultRCSmode = (S_IRUSR|S_IRGRP|S_IROTH) & ~defaultRCSmode; + } + + /* now handle all filenames */ + do { + ffree(); + + if ( initflag ) { + switch (pairfilenames(argc, argv, rcswriteopen, false, false)) { + case -1: break; /* not exist; ok */ + case 0: continue; /* error */ + case 1: error("file %s exists already", RCSfilename); + continue; + } + } + else { + switch (pairfilenames(argc, argv, rcswriteopen, true, false)) { + case -1: continue; /* not exist */ + case 0: continue; /* errors */ + case 1: break; /* file exists; ok*/ + } + } + + + /* now RCSfilename contains the name of the RCS file, and + * workfilename contains the name of the working file. + * if !initflag, finptr contains the file descriptor for the + * RCS file. The admin node is initialized. + */ + + diagnose("RCS file: %s\n", RCSfilename); + + RCSmode = defaultRCSmode; + if (initflag) { + if (stat(workfilename, &workstat) == 0) + RCSmode = workstat.st_mode; + } else { + if (!checkaccesslist()) continue; + gettree(); /* Read the delta tree. */ + RCSmode = RCSstat.st_mode; + } + RCSmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH); + + /* update admin. node */ + if (strict_selected) StrictLocks = strictlock; + if (commsyml) { + Comment.string = commsyml; + Comment.size = strlen(commsyml); + } + if (0 <= expmode) Expand = expmode; + + /* update default branch */ + if (branchflag && expandsym(branchsym, &branchnum)) { + if (countnumflds(branchnum.string)) { + Dbranch = branchnum.string; + } else + Dbranch = nil; + } + + doaccess(); /* Update access list. */ + + doassoc(); /* Update association list. */ + + dolocks(); /* Update locks. */ + + domessages(); /* Update log messages. */ + + /* update state attribution */ + if (chgheadstate) { + /* change state of default branch or head */ + if (Dbranch==nil) { + if (Head==nil) + warn("can't change states in an empty tree"); + else Head->state = headstate; + } else { + rcs_setstate(Dbranch,headstate); /* Can't set directly */ + } + } + curstate = statelst; + while( curstate ) { + rcs_setstate(curstate->revno,curstate->status); + curstate = curstate->nextstatus; + } + + cuthead = cuttail = nil; + if (delrev.strt && removerevs()) { + /* rebuild delta tree if some deltas are deleted */ + if ( cuttail ) + VOID genrevs(cuttail->num, (char *)nil,(char *)nil, + (char *)nil, &gendeltas); + buildtree(); + } + + if (nerror) + continue; + + putadmin(frewrite); + if ( Head ) + puttree(Head, frewrite); + putdesc(textflag,textfile); + + if ( Head) { + if (!delrev.strt && !messagelst) { + /* No revision was deleted and no message was changed. */ + fastcopy(finptr, frewrite); + } else { + if (!cuttail || buildeltatext(gendeltas)) { + advise_access(finptr, MADV_SEQUENTIAL); + scanlogtext((struct hshentry *)nil, false); + /* copy rest of delta text nodes that are not deleted */ + } + } + } + Izclose(&finptr); + if ( ! nerror ) { /* move temporary file to RCS file if no error */ + /* update mode */ + ignoreints(); + r = chnamemod(&frewrite, newRCSfilename, RCSfilename, RCSmode); + e = errno; + keepdirtemp(newRCSfilename); + restoreints(); + if (r != 0) { + enerror(e, RCSfilename); + error("saved in %s", newRCSfilename); + dirtempunlink(); + break; + } + diagnose("done\n"); + } else { + diagnose("%s aborted; %s unchanged.\n",cmdid,RCSfilename); + } + } while (cleanup(), + ++argv, --argc >=1); + + tempunlink(); + exitmain(exitstatus); +} /* end of main (rcs) */ + + static void +cleanup() +{ + if (nerror) exitstatus = EXIT_FAILURE; + Izclose(&finptr); + Ozclose(&fcopy); + Ozclose(&frewrite); + dirtempunlink(); +} + + exiting void +exiterr() +{ + dirtempunlink(); + tempunlink(); + _exit(EXIT_FAILURE); +} + + + static void +getassoclst(flag, sp) +int flag; +char * sp; +/* Function: associate a symbolic name to a revision or branch, */ +/* and store in assoclst */ + +{ + struct Symrev * pt; + char const *temp; + int c; + + while( (c=(*++sp)) == ' ' || c == '\t' || c =='\n') ; + temp = sp; + sp = checkid(sp, ':'); /* check for invalid symbolic name */ + c = *sp; *sp = '\0'; + while( c == ' ' || c == '\t' || c == '\n') c = *++sp; + + if ( c != ':' && c != '\0') { + error("invalid string %s after option -n or -N",sp); + return; + } + + pt = talloc(struct Symrev); + pt->ssymbol = temp; + pt->override = flag; + if (c == '\0') /* delete symbol */ + pt->revno = nil; + else { + while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ; + pt->revno = sp; + } + pt->nextsym = nil; + if (lastassoc) + lastassoc->nextsym = pt; + else + assoclst = pt; + lastassoc = pt; + return; +} + + + static void +getchaccess(login, command) + char const *login; + enum changeaccess command; +{ + register struct chaccess *pt; + + *nextchaccess = pt = talloc(struct chaccess); + pt->login = login; + pt->command = command; + pt->nextchaccess = nil; + nextchaccess = &pt->nextchaccess; +} + + + + static void +getaccessor(opt, command) + char *opt; + enum changeaccess command; +/* Function: get the accessor list of options -e and -a, */ +/* and store in chaccess */ + + +{ + register c; + register char *sp; + + sp = opt; + while( ( c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',') ; + if ( c == '\0') { + if (command == erase && sp-opt == 1) { + getchaccess((char const*)nil, command); + return; + } + error("missing login name after option -a or -e"); + return; + } + + while( c != '\0') { + getchaccess(sp, command); + sp = checkid(sp,','); + c = *sp; *sp = '\0'; + while( c == ' ' || c == '\n' || c == '\t'|| c == ',')c =(*++sp); + } +} + + + static void +getmessage(option) + char *option; +{ + struct Message *pt; + struct cbuf cb; + char *m; + + if (!(m = strchr(option, ':'))) { + error("-m option lacks revision number"); + return; + } + *m++ = 0; + cb = cleanlogmsg(m, strlen(m)); + if (!cb.size) { + error("-m option lacks log message"); + return; + } + pt = talloc(struct Message); + pt->revno = option; + pt->message = cb; + pt->nextmessage = 0; + if (lastmessage) + lastmessage->nextmessage = pt; + else + messagelst = pt; + lastmessage = pt; +} + + + static void +getstates(sp) +char *sp; +/* Function: get one state attribute and the corresponding */ +/* revision and store in statelst */ + +{ + char const *temp; + struct Status *pt; + register c; + + while( (c=(*++sp)) ==' ' || c == '\t' || c == '\n') ; + temp = sp; + sp = checkid(sp,':'); /* check for invalid state attribute */ + c = *sp; *sp = '\0'; + while( c == ' ' || c == '\t' || c == '\n' ) c = *++sp; + + if ( c == '\0' ) { /* change state of def. branch or Head */ + chgheadstate = true; + headstate = temp; + return; + } + else if ( c != ':' ) { + error("missing ':' after state in option -s"); + return; + } + + while( (c = *++sp) == ' ' || c == '\t' || c == '\n') ; + pt = talloc(struct Status); + pt->status = temp; + pt->revno = sp; + pt->nextstatus = nil; + if (laststate) + laststate->nextstatus = pt; + else + statelst = pt; + laststate = pt; +} + + + + static void +getdelrev(sp) +char *sp; +/* Function: get revision range or branch to be deleted, */ +/* and place in delrev */ +{ + int c; + struct delrevpair *pt; + int separator; + + pt = &delrev; + while((c = (*++sp)) == ' ' || c == '\n' || c == '\t') ; + + /* Support old ambiguous '-' syntax; this will go away. */ + if (strchr(sp,':')) + separator = ':'; + else { + if (strchr(sp,'-') && VERSION(5) <= RCSversion) + warn("`-' is obsolete in `-o%s'; use `:' instead", sp); + separator = '-'; + } + + if (c == separator) { /* -o:rev */ + while( (c = (*++sp)) == ' ' || c == '\n' || c == '\t') ; + pt->strt = sp; pt->code = 1; + while( c != ' ' && c != '\n' && c != '\t' && c != '\0') c =(*++sp); + *sp = '\0'; + pt->end = nil; + return; + } + else { + pt->strt = sp; + while( c != ' ' && c != '\n' && c != '\t' && c != '\0' + && c != separator ) c = *++sp; + *sp = '\0'; + while( c == ' ' || c == '\n' || c == '\t' ) c = *++sp; + if ( c == '\0' ) { /* -o rev or branch */ + pt->end = nil; pt->code = 0; + return; + } + if (c != separator) { + faterror("invalid range %s %s after -o", pt->strt, sp); + } + while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ; + if (!c) { /* -orev: */ + pt->end = nil; pt->code = 2; + return; + } + } + /* -orev1:rev2 */ + pt->end = sp; pt->code = 3; + while( c!= ' ' && c != '\n' && c != '\t' && c != '\0') c = *++sp; + *sp = '\0'; +} + + + + + static void +scanlogtext(delta,edit) + struct hshentry *delta; + int edit; +/* Function: Scans delta text nodes up to and including the one given + * by delta, or up to last one present, if delta==nil. + * For the one given by delta (if delta!=nil), the log message is saved into + * delta->log if delta==cuttail; the text is edited if EDIT is set, else copied. + * Assumes the initial lexeme must be read in first. + * Does not advance nexttok after it is finished, except if delta==nil. + */ +{ + struct hshentry const *nextdelta; + struct cbuf cb; + + for (;;) { + foutptr = 0; + if (eoflex()) { + if(delta) + faterror("can't find delta for revision %s", delta->num); + return; /* no more delta text nodes */ + } + nextlex(); + if (!(nextdelta=getnum())) + faterror("delta number corrupted"); + if (nextdelta->selector) { + foutptr = frewrite; + aprintf(frewrite,DELNUMFORM,nextdelta->num,Klog); + } + getkeystring(Klog); + if (nextdelta == cuttail) { + cb = savestring(&curlogbuf); + if (!delta->log.string) + delta->log = cleanlogmsg(curlogbuf.string, cb.size); + } else if (nextdelta->log.string && nextdelta->selector) { + foutptr = 0; + readstring(); + foutptr = frewrite; + putstring(foutptr, false, nextdelta->log, true); + afputc(nextc, foutptr); + } else {readstring(); + } + nextlex(); + while (nexttok==ID && strcmp(NextString,Ktext)!=0) + ignorephrase(); + getkeystring(Ktext); + + if (delta==nextdelta) + break; + readstring(); /* skip over it */ + + } + /* got the one we're looking for */ + if (edit) + editstring((struct hshentry *)nil); + else + enterstring(); +} + + + + static struct Lockrev * +rmnewlocklst(which) + struct Lockrev const *which; +/* Function: remove lock to revision which->revno from newlocklst */ + +{ + struct Lockrev * pt, *pre; + + while( newlocklst && (! strcmp(newlocklst->revno, which->revno))){ + struct Lockrev *pn = newlocklst->nextrev; + tfree(newlocklst); + newlocklst = pn; + } + + pt = pre = newlocklst; + while( pt ) { + if ( ! strcmp(pt->revno, which->revno) ) { + pre->nextrev = pt->nextrev; + tfree(pt); + pt = pre->nextrev; + } + else { + pre = pt; + pt = pt->nextrev; + } + } + return pre; +} + + + + static void +doaccess() +{ + register struct chaccess *ch; + register struct access **p, *t; + + for (ch = chaccess; ch; ch = ch->nextchaccess) { + switch (ch->command) { + case erase: + if (!ch->login) + AccessList = nil; + else + for (p = &AccessList; (t = *p); ) + if (strcmp(ch->login, t->login) == 0) + *p = t->nextaccess; + else + p = &t->nextaccess; + break; + case append: + for (p = &AccessList; ; p = &t->nextaccess) + if (!(t = *p)) { + *p = t = ftalloc(struct access); + t->login = ch->login; + t->nextaccess = nil; + break; + } else if (strcmp(ch->login, t->login) == 0) + break; + break; + } + } +} + + + static int +sendmail(Delta, who) + char const *Delta, *who; +/* Function: mail to who, informing him that his lock on delta was + * broken by caller. Ask first whether to go ahead. Return false on + * error or if user decides not to break the lock. + */ +{ +#ifdef SENDMAIL + char const *messagefile; + int old1, old2, c; + FILE * mailmess; +#endif + + + aprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who); + if (!yesorno(false, "Do you want to break the lock? [ny](n): ")) + return false; + + /* go ahead with breaking */ +#ifdef SENDMAIL + messagefile = maketemp(0); + if (!(mailmess = fopen(messagefile, "w"))) { + efaterror(messagefile); + } + + aprintf(mailmess, "Subject: Broken lock on %s\n\nYour lock on revision %s of file %s\nhas been broken by %s for the following reason:\n", + basename(RCSfilename), Delta, getfullRCSname(), getcaller() + ); + aputs("State the reason for breaking the lock:\n(terminate with single '.' or end of file)\n>> ", stderr); + + old1 = '\n'; old2 = ' '; + for (; ;) { + c = getcstdin(); + if (feof(stdin)) { + aprintf(mailmess, "%c\n", old1); + break; + } + else if ( c == '\n' && old1 == '.' && old2 == '\n') + break; + else { + afputc(old1, mailmess); + old2 = old1; old1 = c; + if (c=='\n') aputs(">> ", stderr); + } + } + Ozclose(&mailmess); + + if (run(messagefile, (char*)nil, SENDMAIL, who, (char*)nil)) + warn("Mail may have failed."), +#else + warn("Mail notification of broken locks is not available."), +#endif + warn("Please tell `%s' why you broke the lock.", who); + return(true); +} + + + + static void +breaklock(delta) + struct hshentry const *delta; +/* function: Finds the lock held by caller on delta, + * and removes it. + * Sends mail if a lock different from the caller's is broken. + * Prints an error message if there is no such lock or error. + */ +{ + register struct lock * next, * trail; + char const *num; + struct lock dummy; + + num=delta->num; + dummy.nextlock=next=Locks; + trail = &dummy; + while (next!=nil) { + if (strcmp(num, next->delta->num) == 0) { + if ( + strcmp(getcaller(),next->login) != 0 + && !sendmail(num, next->login) + ) { + error("%s still locked by %s", num, next->login); + return; + } + break; /* exact match */ + } + trail=next; + next=next->nextlock; + } + if (next!=nil) { + /*found one */ + diagnose("%s unlocked\n",next->delta->num); + trail->nextlock=next->nextlock; + next->delta->lockedby=nil; + Locks=dummy.nextlock; + } else { + error("no lock set on revision %s", num); + } +} + + + + static struct hshentry * +searchcutpt(object, length, store) + char const *object; + unsigned length; + struct hshentries *store; +/* Function: Search store and return entry with number being object. */ +/* cuttail = nil, if the entry is Head; otherwise, cuttail */ +/* is the entry point to the one with number being object */ + +{ + cuthead = nil; + while (compartial(store->first->num, object, length)) { + cuthead = store->first; + store = store->rest; + } + return store->first; +} + + + + static int +branchpoint(strt, tail) +struct hshentry *strt, *tail; +/* Function: check whether the deltas between strt and tail */ +/* are locked or branch point, return 1 if any is */ +/* locked or branch point; otherwise, return 0 and */ +/* mark deleted */ + +{ + struct hshentry *pt; + struct lock const *lockpt; + int flag; + + + pt = strt; + flag = false; + while( pt != tail) { + if ( pt->branches ){ /* a branch point */ + flag = true; + error("can't remove branch point %s", pt->num); + } + lockpt = Locks; + while(lockpt && lockpt->delta != pt) + lockpt = lockpt->nextlock; + if ( lockpt ) { + flag = true; + error("can't remove locked revision %s",pt->num); + } + pt = pt->next; + } + + if ( ! flag ) { + pt = strt; + while( pt != tail ) { + pt->selector = false; + diagnose("deleting revision %s\n",pt->num); + pt = pt->next; + } + } + return flag; +} + + + + static int +removerevs() +/* Function: get the revision range to be removed, and place the */ +/* first revision removed in delstrt, the revision before */ +/* delstrt in cuthead( nil, if delstrt is head), and the */ +/* revision after the last removed revision in cuttail(nil */ +/* if the last is a leaf */ + +{ + struct hshentry *target, *target2, *temp; + unsigned length; + int flag; + + flag = false; + if (!expandsym(delrev.strt, &numrev)) return 0; + target = genrevs(numrev.string, (char*)nil, (char*)nil, (char*)nil, &gendeltas); + if ( ! target ) return 0; + if (cmpnum(target->num, numrev.string)) flag = true; + length = countnumflds(numrev.string); + + if (delrev.code == 0) { /* -o rev or -o branch */ + if (length & 1) + temp=searchcutpt(target->num,length+1,gendeltas); + else if (flag) { + error("Revision %s doesn't exist.", numrev.string); + return 0; + } + else + temp = searchcutpt(numrev.string, length, gendeltas); + cuttail = target->next; + if ( branchpoint(temp, cuttail) ) { + cuttail = nil; + return 0; + } + delstrt = temp; /* first revision to be removed */ + return 1; + } + + if (length & 1) { /* invalid branch after -o */ + error("invalid branch range %s after -o", numrev.string); + return 0; + } + + if (delrev.code == 1) { /* -o -rev */ + if ( length > 2 ) { + temp = searchcutpt( target->num, length-1, gendeltas); + cuttail = target->next; + } + else { + temp = searchcutpt(target->num, length, gendeltas); + cuttail = target; + while( cuttail && ! cmpnumfld(target->num,cuttail->num,1) ) + cuttail = cuttail->next; + } + if ( branchpoint(temp, cuttail) ){ + cuttail = nil; + return 0; + } + delstrt = temp; + return 1; + } + + if (delrev.code == 2) { /* -o rev- */ + if ( length == 2 ) { + temp = searchcutpt(target->num, 1,gendeltas); + if ( flag) + cuttail = target; + else + cuttail = target->next; + } + else { + if ( flag){ + cuthead = target; + if ( !(temp = target->next) ) return 0; + } + else + temp = searchcutpt(target->num, length, gendeltas); + getbranchno(temp->num, &numrev); /* get branch number */ + target = genrevs(numrev.string, (char*)nil, (char*)nil, (char*)nil, &gendeltas); + } + if ( branchpoint( temp, cuttail ) ) { + cuttail = nil; + return 0; + } + delstrt = temp; + return 1; + } + + /* -o rev1-rev2 */ + if (!expandsym(delrev.end, &numrev)) return 0; + if ( + length != countnumflds(numrev.string) + || length>2 && compartial(numrev.string, target->num, length-1) + ) { + error("invalid revision range %s-%s", target->num, numrev.string); + return 0; + } + + target2 = genrevs(numrev.string,(char*)nil,(char*)nil,(char*)nil,&gendeltas); + if ( ! target2 ) return 0; + + if ( length > 2) { /* delete revisions on branches */ + if ( cmpnum(target->num, target2->num) > 0) { + if (cmpnum(target2->num, numrev.string)) + flag = true; + else + flag = false; + temp = target; + target = target2; + target2 = temp; + } + if ( flag ) { + if ( ! cmpnum(target->num, target2->num) ) { + error("Revisions %s-%s don't exist.", delrev.strt,delrev.end); + return 0; + } + cuthead = target; + temp = target->next; + } + else + temp = searchcutpt(target->num, length, gendeltas); + cuttail = target2->next; + } + else { /* delete revisions on trunk */ + if ( cmpnum( target->num, target2->num) < 0 ) { + temp = target; + target = target2; + target2 = temp; + } + else + if (cmpnum(target2->num, numrev.string)) + flag = true; + else + flag = false; + if ( flag ) { + if ( ! cmpnum(target->num, target2->num) ) { + error("Revisions %s-%s don't exist.", delrev.strt, delrev.end); + return 0; + } + cuttail = target2; + } + else + cuttail = target2->next; + temp = searchcutpt(target->num, length, gendeltas); + } + if ( branchpoint(temp, cuttail) ) { + cuttail = nil; + return 0; + } + delstrt = temp; + return 1; +} + + + + static void +doassoc() +/* Function: add or delete(if revno is nil) association */ +/* which is stored in assoclst */ + +{ + char const *p; + struct Symrev const *curassoc; + struct assoc * pre, * pt; + + /* add new associations */ + curassoc = assoclst; + while( curassoc ) { + if ( curassoc->revno == nil ) { /* delete symbol */ + pre = pt = Symbols; + while( pt && strcmp(pt->symbol,curassoc->ssymbol) ) { + pre = pt; + pt = pt->nextassoc; + } + if ( pt ) + if ( pre == pt ) + Symbols = pt->nextassoc; + else + pre->nextassoc = pt->nextassoc; + else + warn("can't delete nonexisting symbol %s",curassoc->ssymbol); + } + else { + if (curassoc->revno[0]) { + p = 0; + if (expandsym(curassoc->revno, &numrev)) + p = fstr_save(numrev.string); + } else if (!(p = tiprev())) + error("no latest revision to associate with symbol %s", + curassoc->ssymbol + ); + if (p) + VOID addsymbol(p, curassoc->ssymbol, curassoc->override); + } + curassoc = curassoc->nextsym; + } + +} + + + + static void +dolocks() +/* Function: remove lock for caller or first lock if unlockcaller is set; + * remove locks which are stored in rmvlocklst, + * add new locks which are stored in newlocklst, + * add lock for Dbranch or Head if lockhead is set. + */ +{ + struct Lockrev const *lockpt; + struct hshentry *target; + + if (unlockcaller) { /* find lock for caller */ + if ( Head ) { + if (Locks) { + switch (findlock(true, &target)) { + case 0: + breaklock(Locks->delta); /* remove most recent lock */ + break; + case 1: + diagnose("%s unlocked\n",target->num); + break; + } + } else { + warn("No locks are set."); + } + } else { + warn("can't unlock an empty tree"); + } + } + + /* remove locks which are stored in rmvlocklst */ + lockpt = rmvlocklst; + while( lockpt ) { + if (expandsym(lockpt->revno, &numrev)) { + target = genrevs(numrev.string, (char *)nil, (char *)nil, (char *)nil, &gendeltas); + if ( target ) + if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string)) + error("can't unlock nonexisting revision %s",lockpt->revno); + else + breaklock(target); + /* breaklock does its own diagnose */ + } + lockpt = lockpt->nextrev; + } + + /* add new locks which stored in newlocklst */ + lockpt = newlocklst; + while( lockpt ) { + setlock(lockpt->revno); + lockpt = lockpt->nextrev; + } + + if (lockhead) { /* lock default branch or head */ + if (Dbranch) { + setlock(Dbranch); + } else if (Head) { + if (0 <= addlock(Head)) + diagnose("%s locked\n",Head->num); + } else { + warn("can't lock an empty tree"); + } + } + +} + + + + static void +setlock(rev) + char const *rev; +/* Function: Given a revision or branch number, finds the corresponding + * delta and locks it for caller. + */ +{ + struct hshentry *target; + + if (expandsym(rev, &numrev)) { + target = genrevs(numrev.string, (char*)nil, (char*)nil, + (char*)nil, &gendeltas); + if ( target ) + if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string)) + error("can't lock nonexisting revision %s", numrev.string); + else + if (0 <= addlock(target)) + diagnose("%s locked\n", target->num); + } +} + + + static void +domessages() +{ + struct hshentry *target; + struct Message *p; + + for (p = messagelst; p; p = p->nextmessage) + if ( + expandsym(p->revno, &numrev) && + (target = genrevs( + numrev.string, (char*)0, (char*)0, (char*)0, &gendeltas + )) + ) + target->log = p->message; +} + + + static void +rcs_setstate(rev,status) + char const *rev, *status; +/* Function: Given a revision or branch number, finds the corresponding delta + * and sets its state to status. + */ +{ + struct hshentry *target; + + if (expandsym(rev, &numrev)) { + target = genrevs(numrev.string, (char*)nil, (char*)nil, + (char*)nil, &gendeltas); + if ( target ) + if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string)) + error("can't set state of nonexisting revision %s to %s", + numrev.string, status); + else + target->state = status; + } +} + + + + + + static int +buildeltatext(deltas) + struct hshentries const *deltas; +/* Function: put the delta text on frewrite and make necessary */ +/* change to delta text */ +{ + register FILE *fcut; /* temporary file to rebuild delta tree */ + char const *cutfilename, *diffilename; + + cutfilename = nil; + cuttail->selector = false; + scanlogtext(deltas->first, false); + if ( cuthead ) { + cutfilename = maketemp(3); + if (!(fcut = fopen(cutfilename, FOPEN_W_WORK))) { + efaterror(cutfilename); + } + + while (deltas->first != cuthead) { + deltas = deltas->rest; + scanlogtext(deltas->first, true); + } + + snapshotedit(fcut); + Ofclose(fcut); + } + + while (deltas->first != cuttail) + scanlogtext((deltas = deltas->rest)->first, true); + finishedit((struct hshentry *)nil, (FILE*)0, true); + Ozclose(&fcopy); + + if ( cuthead ) { + diffilename = maketemp(0); + switch (run((char*)nil,diffilename, + DIFF DIFF_FLAGS, cutfilename, resultfile, (char*)nil + )) { + case DIFF_FAILURE: case DIFF_SUCCESS: break; + default: faterror ("diff failed"); + } + return putdtext(cuttail->num,cuttail->log,diffilename,frewrite,true); + } else + return putdtext(cuttail->num,cuttail->log,resultfile,frewrite,false); +} + + + + static void +buildtree() +/* Function: actually removes revisions whose selector field */ +/* is false, and rebuilds the linkage of deltas. */ +/* asks for reconfirmation if deleting last revision*/ +{ + struct hshentry * Delta; + struct branchhead *pt, *pre; + + if ( cuthead ) + if ( cuthead->next == delstrt ) + cuthead->next = cuttail; + else { + pre = pt = cuthead->branches; + while( pt && pt->hsh != delstrt ) { + pre = pt; + pt = pt->nextbranch; + } + if ( cuttail ) + pt->hsh = cuttail; + else if ( pt == pre ) + cuthead->branches = pt->nextbranch; + else + pre->nextbranch = pt->nextbranch; + } + else { + if ( cuttail == nil && !quietflag) { + if (!yesorno(false, "Do you really want to delete all revisions? [ny](n): ")) { + error("No revision deleted"); + Delta = delstrt; + while( Delta) { + Delta->selector = true; + Delta = Delta->next; + } + return; + } + } + Head = cuttail; + } + return; +} + +#if lint +/* This lets us lint everything all at once. */ + +char const cmdid[] = ""; + +#define go(p,e) {int p P((int,char**)); void e P((void)); if(*argv)return p(argc,argv);if(*argv[1])e();} + + int +main(argc, argv) + int argc; + char **argv; +{ + go(ciId, ciExit); + go(coId, coExit); + go(identId, identExit); + go(mergeId, mergeExit); + go(rcsId, exiterr); + go(rcscleanId, rcscleanExit); + go(rcsdiffId, rdiffExit); + go(rcsmergeId, rmergeExit); + go(rlogId, rlogExit); + return 0; +} +#endif diff --git a/gnu/usr.bin/rcs/rcs/rcsfile.5 b/gnu/usr.bin/rcs/rcs/rcsfile.5 new file mode 100644 index 0000000000..d0dbbb80cb --- /dev/null +++ b/gnu/usr.bin/rcs/rcs/rcsfile.5 @@ -0,0 +1,224 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: rcsfile.5,v 5.1 1991/08/19 03:13:55 eggert Exp $ +.ds r \s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.TH RCSFILE 5 \*(Dt GNU +.SH NAME +rcsfile \- format of RCS file +.SH DESCRIPTION +An \*r file's +contents are described by the grammar +below. +.PP +The text is free format: space, backspace, tab, newline, vertical +tab, form feed, and carriage return (collectively, +.IR "white space") +have no significance except in strings. +However, an \*r file must end in a newline character. +.PP +Strings are enclosed by +.BR @ . +If a string contains a +.BR @ , +it must be doubled; +otherwise, strings may contain arbitrary binary data. +.PP +The meta syntax uses the following conventions: `|' (bar) separates +alternatives; `{' and `}' enclose optional phrases; `{' and `}*' enclose +phrases that may be repeated zero or more times; +`{' and '}+' enclose phrases that must appear at least once and may be +repeated; +Terminal symbols are in +.BR boldface ; +nonterminal symbols are in +.IR italics . +.LP +.nr x \w'\f3branches\fP' +.nr y \w'{ \f3comment\fP' +.if \nx<\ny .nr x \ny +.nr y \w'\f3{ branch\fP' +.if \nx<\ny .nr x \ny +.ta \w'\f2deltatext\fP 'u +\w'::= 'u +\nxu+\w' 'u +.fc ~ +.nf +\f2rcstext\fP ::= \f2admin\fP {\f2delta\fP}* \f2desc\fP {\f2deltatext\fP}* +.LP +\f2admin\fP ::= \f3head\fP {\f2num\fP}\f3;\fP + { \f3branch\fP {\f2num\fP}\f3;\fP } + \f3access\fP {\f2id\fP}*\f3;\fP + \f3symbols\fP {\f2id\fP \f3:\fP \f2num\fP}*\f3;\fP + \f3locks\fP {\f2id\fP \f3:\fP \f2num\fP}*\f3;\fP {\f3strict ;\fP} + { \f3comment\fP {\f2string\fP}\f3;\fP } + { \f3expand\fP {\f2string\fP}\f3;\fP } + { \f2newphrase\fP }* +.LP +\f2delta\fP ::= \f2num\fP + \f3date\fP \f2num\fP\f3;\fP + \f3author\fP \f2id\fP\f3;\fP + \f3state\fP {\f2id\fP}\f3;\fP + \f3branches\fP {\f2num\fP}*\f3;\fP + \f3next\fP {\f2num\fP}\f3;\fP + { \f2newphrase\fP }* +.LP +\f2desc\fP ::= \f3desc\fP \f2string\fP +.LP +\f2deltatext\fP ::= \f2num\fP + \f3log\fP \f2string\fP + { \f2newphrase\fP }* + \f3text\fP \f2string\fP +.LP +\f2num\fP ::= {\f2digit\fP{\f3.\fP}}+ +.LP +\f2digit\fP ::= \f30\fP | \f31\fP | .\|.\|. | \f39\fP +.LP +\f2id\fP ::= \f2letter\fP{\f2idchar\fP}* +.LP +\f2letter\fP ::= any letter +.LP +\f2idchar\fP ::= any visible graphic character except \f2special\fP +.LP +\f2special\fP ::= \f3$\fP | \f3,\fP | \f3.\fP | \f3:\fP | \f3;\fP | \f3@\fP +.LP +\f2string\fP ::= \f3@\fP{any character, with \f3@\fP doubled}*\f3@\fP +.LP +\f2newphrase\fP ::= \f2id\fP \f2word\fP* \f3;\fP +.LP +\f2word\fP ::= \f2id\fP | \f2num\fP | \f2string\fP | \f3:\fP +.fi +.PP +Identifiers are case sensitive. Keywords are in lower case only. +The sets of keywords and identifiers may overlap. +In most environments RCS uses the ISO 8859/1 encoding: +letters are octal codes 101\-132, 141\-172, 300\-326, 330\-366 and 370-377, +visible graphic characters are codes 041\-176 and 240\-377, +and white space characters are codes 010\-015 and 040. +.PP +The +.I newphrase +productions in the grammar are reserved for future extensions +to the format of \*r files. +No +.I newphrase +will begin with any keyword already in use. +.PP +The +.I delta +nodes form a tree. All nodes whose numbers +consist of a single pair +(e.g., 2.3, 2.1, 1.3, etc.) +are on the trunk, and are linked through the +.B next +field in order of decreasing numbers. +The +.B head +field in the +.I admin +node points to the head of that sequence (i.e., contains +the highest pair). +The +.B branch +node in the admin node indicates the default +branch (or revision) for most \*r operations. +If empty, the default +branch is the highest branch on the trunk. +.PP +All +.I delta +nodes whose numbers consist of +.RI 2 n +fields +.RI ( n >=2) +(e.g., 3.1.1.1, 2.1.2.2, etc.) +are linked as follows. +All nodes whose first +.RI 2 n \-1 +number fields are identical are linked through the +.B next +field in order of increasing numbers. +For each such sequence, +the +.I delta +node whose number is identical to the first +.RI 2 n \-2 +number fields of the deltas on that sequence is called the branchpoint. +The +.B branches +field of a node contains a list of the +numbers of the first nodes of all sequences for which it is a branchpoint. +This list is ordered in increasing numbers. +.LP +.nf +.vs 12 +.ne 38 +Example: +.if t .in +0.5i +.cs 1 20 +.eo + + Head + | + | + v / \ + --------- / \ + / \ / \ | | / \ / \ + / \ / \ | 2.1 | / \ / \ + / \ / \ | | / \ / \ +/1.2.1.3\ /1.3.1.1\ | | /1.2.2.2\ /1.2.2.1.1.1\ +--------- --------- --------- --------- ------------- + ^ ^ | ^ ^ + | | | | | + | | v | | + / \ | --------- / \ | + / \ | \ 1.3 / / \ | + / \ ---------\ / / \----------- +/1.2.1.1\ \ / /1.2.2.1\ +--------- \ / --------- + ^ | ^ + | | | + | v | + | --------- | + | \ 1.2 / | + ----------------------\ /--------- + \ / + \ / + | + | + v + --------- + \ 1.1 / + \ / + \ / + \ / + +.ec +.if t .in +.cs 1 +.ce +Fig. 1: A revision tree +.vs +.fi +.PP +.SH IDENTIFICATION +.de VL +\\$2 +.. +Author: Walter F. Tichy, +Purdue University, West Lafayette, IN, 47907. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH SEE ALSO +ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsmerge(1), rlog(1), +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. diff --git a/gnu/usr.bin/rcs/rcs/rcsintro.1 b/gnu/usr.bin/rcs/rcs/rcsintro.1 new file mode 100644 index 0000000000..a76caa0ee2 --- /dev/null +++ b/gnu/usr.bin/rcs/rcs/rcsintro.1 @@ -0,0 +1,292 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: rcsintro.1,v 5.1 1991/04/21 12:00:46 eggert Exp $ +.ds r \&\s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.am SS +.LP +.. +.TH RCSINTRO 1 \*(Dt GNU +.SH NAME +rcsintro \- introduction to RCS commands +.SH DESCRIPTION +The Revision Control System (\*r) manages multiple revisions of files. +\*r automates the storing, retrieval, logging, identification, and merging +of revisions. \*r is useful for text that is revised frequently, for example +programs, documentation, graphics, papers, and form letters. +.PP +The basic user interface is extremely simple. The novice only needs +to learn two commands: +.BR ci (1) +and +.BR co (1). +.BR ci , +short for \*(lqcheck in\*(rq, deposits the contents of a +file into an archival file called an \*r file. An \*r file +contains all revisions of a particular file. +.BR co , +short for \*(lqcheck out\*(rq, retrieves revisions from an \*r file. +.SS "Functions of \*r" +.IP \(bu +Store and retrieve multiple revisions of text. \*r saves all old +revisions in a space efficient way. +Changes no longer destroy the original, because the +previous revisions remain accessible. Revisions can be retrieved according to +ranges of revision numbers, symbolic names, dates, authors, and +states. +.IP \(bu +Maintain a complete history of changes. +\*r logs all changes automatically. +Besides the text of each revision, \*r stores the author, the date and time of +check-in, and a log message summarizing the change. +The logging makes it easy to find out +what happened to a module, without having to compare +source listings or having to track down colleagues. +.IP \(bu +Resolve access conflicts. When two or more programmers wish to +modify the same revision, \*r alerts the programmers and prevents one +modification from corrupting the other. +.IP \(bu +Maintain a tree of revisions. \*r can maintain separate lines of development +for each module. It stores a tree structure that represents the +ancestral relationships among revisions. +.IP \(bu +Merge revisions and resolve conflicts. +Two separate lines of development of a module can be coalesced by merging. +If the revisions to be merged affect the same sections of code, \*r alerts the +user about the overlapping changes. +.IP \(bu +Control releases and configurations. +Revisions can be assigned symbolic names +and marked as released, stable, experimental, etc. +With these facilities, configurations of modules can be +described simply and directly. +.IP \(bu +Automatically identify each revision with name, revision number, +creation time, author, etc. +The identification is like a stamp that can be embedded at an appropriate place +in the text of a revision. +The identification makes it simple to determine which +revisions of which modules make up a given configuration. +.IP \(bu +Minimize secondary storage. \*r needs little extra space for +the revisions (only the differences). If intermediate revisions are +deleted, the corresponding deltas are compressed accordingly. +.SS "Getting Started with \*r" +Suppose you have a file +.B f.c +that you wish to put under control of \*r. +If you have not already done so, make an \*r directory with the command +.IP +.B "mkdir RCS" +.LP +Then invoke the check-in command +.IP +.B "ci f.c" +.LP +This command creates an \*r file in the +.B RCS +directory, +stores +.B f.c +into it as revision 1.1, and +deletes +.BR f.c . +It also asks you for a description. The description +should be a synopsis of the contents of the file. All later check-in +commands will ask you for a log entry, which should summarize the +changes that you made. +.PP +Files in the \*r directory are called \*r files; +the others are called working files. +To get back the working file +.B f.c +in the previous example, use the check-out +command +.IP +.B "co f.c" +.LP +This command extracts the latest revision from the \*r file +and writes +it into +.BR f.c . +If you want to edit +.BR f.c , +you must lock it as you check it out with the command +.IP +.B "co \-l f.c" +.LP +You can now edit +.BR f.c . +.PP +Suppose after some editing you want to know what changes that you have made. +The command +.IP +.B "rcsdiff f.c" +.LP +tells you the difference between the most recently checked-in version +and the working file. +You can check the file back in by invoking +.IP +.B "ci f.c" +.LP +This increments the revision number properly. +.PP +If +.B ci +complains with the message +.IP +.BI "ci error: no lock set by " "your name" +.LP +then you have tried to check in a file even though you did not +lock it when you checked it out. +Of course, it is too late now to do the check-out with locking, because +another check-out would +overwrite your modifications. Instead, invoke +.IP +.B "rcs \-l f.c" +.LP +This command will lock the latest revision for you, unless somebody +else got ahead of you already. In this case, you'll have to negotiate with +that person. +.PP +Locking assures that you, and only you, can check in the next update, and +avoids nasty problems if several people work on the same file. +Even if a revision is locked, it can still be checked out for +reading, compiling, etc. All that locking +prevents is a +.I "check-in" +by anybody but the locker. +.PP +If your \*r file is private, i.e., if you are the only person who is going +to deposit revisions into it, strict locking is not needed and you +can turn it off. +If strict locking is turned off, +the owner of the \*r file need not have a lock for check-in; all others +still do. Turning strict locking off and on is done with the commands +.IP +.BR "rcs \-U f.c" " and " "rcs \-L f.c" +.LP +If you don't want to clutter your working directory with \*r files, create +a subdirectory called +.B RCS +in your working directory, and move all your \*r +files there. \*r commands will look first into that directory to find +needed files. All the commands discussed above will still work, without any +modification. +(Actually, pairs of \*r and working files can be specified in three ways: +(a) both are given, (b) only the working file is given, (c) only the +\*r file is given. Both \*r and working files may have arbitrary path prefixes; +\*r commands pair them up intelligently.) +.PP +To avoid the deletion of the working file during check-in (in case you want to +continue editing or compiling), invoke +.IP +.BR "ci \-l f.c" " or " "ci \-u f.c" +.LP +These commands check in +.B f.c +as usual, but perform an implicit +check-out. The first form also locks the checked in revision, the second one +doesn't. Thus, these options save you one check-out operation. +The first form is useful if you want to continue editing, +the second one if you just want to read the file. +Both update the identification markers in your working file (see below). +.PP +You can give +.B ci +the number you want assigned to a checked in +revision. Assume all your revisions were numbered 1.1, 1.2, 1.3, etc., +and you would like to start release 2. +The command +.IP +.BR "ci \-r2 f.c" " or " "ci \-r2.1 f.c" +.LP +assigns the number 2.1 to the new revision. +From then on, +.B ci +will number the subsequent revisions +with 2.2, 2.3, etc. The corresponding +.B co +commands +.IP +.BR "co \-r2 f.c" " and " "co \-r2.1 f.c" +.PP +retrieve the latest revision numbered +.RI 2. x +and the revision 2.1, +respectively. +.B co +without a revision number selects +the latest revision on the +.IR trunk , +i.e. the highest +revision with a number consisting of two fields. Numbers with more than two +fields are needed for branches. +For example, to start a branch at revision 1.3, invoke +.IP +.B "ci \-r1.3.1 f.c" +.LP +This command starts a branch numbered 1 at revision 1.3, and assigns +the number 1.3.1.1 to the new revision. For more information about +branches, see +.BR rcsfile (5). +.SS "Automatic Identification" +\*r can put special strings for identification into your source and object +code. To obtain such identification, place the marker +.IP +.B "$\&Id$" +.LP +into your text, for instance inside a comment. +\*r will replace this marker with a string of the form +.IP +.BI $\&Id: " filename revision date time author state " $ +.LP +With such a marker on the first page of each module, you can +always see with which revision you are working. +\*r keeps the markers up to date automatically. +To propagate the markers into your object code, simply put +them into literal character strings. In C, this is done as follows: +.IP +.ft 3 +static char rcsid[] = \&"$\&Id$\&"; +.ft +.LP +The command +.B ident +extracts such markers from any file, even object code +and dumps. +Thus, +.B ident +lets you find out +which revisions of which modules were used in a given program. +.PP +You may also find it useful to put the marker +.B $\&Log$ +into your text, inside a comment. This marker accumulates +the log messages that are requested during check-in. +Thus, you can maintain the complete history of your file directly inside it. +There are several additional identification markers; see +.BR co (1) +for +details. +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH "SEE ALSO" +ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1) +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. +.br diff --git a/gnu/usr.bin/rcs/rcsclean/Makefile b/gnu/usr.bin/rcs/rcsclean/Makefile new file mode 100644 index 0000000000..fc0c626552 --- /dev/null +++ b/gnu/usr.bin/rcs/rcsclean/Makefile @@ -0,0 +1,7 @@ +PROG= rcsclean + +SRCS= rcsclean.c +LDADD= -L${.CURDIR}/../lib/obj -lrcs +CFLAGS+= -I${.CURDIR}/../lib + +.include diff --git a/gnu/usr.bin/rcs/rcsclean/rcsclean b/gnu/usr.bin/rcs/rcsclean/rcsclean new file mode 100644 index 0000000000000000000000000000000000000000..8aee2dc5136445cc902cf331c643aca1ecac853c GIT binary patch literal 101972 zcmeFadwf*YwFiEZnS@E0FaZ(>?@>WO9!Y=zNeBkw0D{4RA&IRtK5l=% zd;j=-44gUV?8n+`uf6u#Yp=cbKKZz%8$1-_xcHx&4W0^d;J8wz|wf&YI|piOEk(cbd~%k9A>cI`zyK5)q1(x#rv zA6Rb-9O}{1$HF?We3>zw-3Kdym)&+&l7jx8>yNZc$cJAkdM{d6x2e8*m8`h4b7xPR zjGx)`lk2`^le?^9jpDC&FPQ3HQC%r-O7^PtD^n-na&Qqka_DojY4v>GqbZYvu3%oXXQdPA!)vug{dGO7;Gg z{;KM=)k^icweEFQZse?Ppy#z}?JfR#NnN{o?Ya$!s-qNn?r{y{8l-xO>f@fGj%z?b zvQ%H|o>Il1i2i}jm1U(qz1X1@@6{WftR+v9LY{{W{DnMwh+{(ur|aURwP?eTXD5Df zdyv9|o@c#fhPsz6oh?b42f3dO9CjMTdjpMorL7|=TCPWWcF5iv?+7nIP#|R2$Lz2b z&6(nAnThuuHv40)18qft?n_;FrXj!>+p;oVlFDq7^qv2YuP(r~U=EFe?Z)#JG4D%b zo~!U2Xna`OoLsY->Fe=w*zRK=6i~e$#xsw*DJ*fK?Ihwvl0ymGzY`~+E>cszhp}+B_32h}%X)SH8yNgiopr_3%|AN5e zFo0#pz9UJyPhJy;G)|;x9)mROrMZ%n{Tj#hawCUg<)ip9)IIF35(3AQo&gj+ogyN| zfr7hGRY|!j(Dq%D3YLiTJ_YBr?AxSAsDAM(G$qTuM zR5Uy#KoTI#eg+=l4ALs8&OqZal(!Etku0D`HNwqMpJ3l520NVUr3Ml-XJh;GAmH-d z?Z}azL+rF=l#!$0j>;NY@*Wf-w=PCQwktd_s==Cg9UzI76@dcEBdHmpx#ee~>3_h} zJ7sEJ_I{m-<4#F&o1C#2R$br?CG` z8mtTrpn1B=*i!z`X{ZjiYA1y;^qoK>1F`la3x%IUb%J${Qg&niIH^$coCbxP=1x_I zH*JZ7(6|@L@HACTZrT!$_h!78vX3{KZKH0`i%;t%XM$dU1DtagUnus=r(JbU%M8-fO5`Y#&e5g+zM!8NH-SFYeJs?l3$( zrFwB^(B9w6Mm~+sUVJ*}9HteYLAp@FghHYdRf4g{P#exGu9hrFz(4_yR9zG|?LW*o z#X_u17e%Gm2E#A_{QA#c%ZNq!M2KuIS%j0be%7DKI$tfuZAvEw)1Xt1+i@F=G~ zB9JesAGDlR?Jb6qQX`c?NPKGmWpkQ9!AJxYq8LDta~&RP;>u89f?i}Naq4B`d5#Q# zuxGbLT=Gfk8+or{>^k zI%0?=3}syIC+a0~E8%yAEJ@3a9RBtSpo$Qc<_$_nY8jAn}~Wh)V75t8dk4sZh~0#^K3`=sTF zl6&tXv`nSOOO-e%G{I}G8LIe*CoL@@;OI2cVo9=O#2qY&% zt*w;kmW=z-Ygc&k+$-ej1~>lW&8^6O_nLL9+_nA&Qob)q2A?-n)>m_-SW>2tMl9&u z>7*{MI`tG9T(shDP@V{`%ndX;Bz3lta~$FFZ@`K2CJYbD*tbCnGj+<#h(p7)=U^~M zpcncJ-;I0ks|65D#eR&0=oB@D0$>vW8frJ|2aqH*&Z?8;(`Z?FJ0j#g^wWwT_A~(Q z?nH!^-i2Qz4Znqg0tFO?vE)^}G|io&4qQ;mh9)4{Arun+8A9d#$Y07X{V(dK)PGK> ziKQ%n)~<=;MX`4wk6WowJxlw@w#cp(_aGgyOMf5x{+%3O!7P$t(>!NLb~g_6u_AP3 zlp;7rb?2)+^@D?+9~9C-vS2`2;fL|c9mJE_VJ`tJ!^R> zd$7ka`c%-3`@iS7D|#e(HEP zB%~km5|b;MeC2`3=FW9XLXy_|>-`lgAwgGG*ZV6ecZ0IBdMy{L;~MfY*YmrljBA*K zJQC#+^D8?aMx5+2R1)1i(AXm>8HSqblYa|wBl?OB-2@FA8QCg2MNuE6;?r5~O@OIB@5BG+>8gE&-qj0-ts-nkvx z@j`UXG?s(mL@!R$v#Yf3?e^(KpcQ-WJTMEz6z#fKXm#rMeWlF!)G)Yo61tl;o>o=X z)|mrp?$;bo#c&Ee_Pu6zz%dztdK{q{r*%Mv zj-tp+fheM?&dnoS`=J;T3VQJ#6T%)gw->@53xbEwmt5H5=HEDOjN zq5Lq^r0{+C2|~S$q2{z+z@Mk)Un)&Pd>Lw8w?`{?QPdu^fP4{ZNx%x!RL6mKihFCn zz-P(Iut-ASvpi)GH?Pyg!Y1o-pV+ z<7FQ$69U)Xa>8}rp>v0*{anpIKpM0Z;20=USp=RbW$%+v=s?SpA>|D&A@)KL1U@s+ z2RR!)iV~tP59=lycmXWCE&Mnj17}zBF8*+__TLsI(dUW0`4%4e5A2+Ie}o`n*OpuH5X%#zdkgzKy027x4RlX7MJs$!bhleTz6jla5Gl_m zx?0}B1BuFIX?AJ%_fr>!@m1|-Fb#fDr zJ#wK;8bW{`xDe14#Nkek*1iZ0$AgIdQ^IW+0$}LKFMgE77Pm!_IMR_{_dIA#-7VRV z0Z_3fQL}O*1LX`||DRg?{ifgyaRn`$BiIzIt6R#sYtrZi61?k%F)v4nU_ttUWZam zeV<@KryPv}5M$&}M%IQ`^Rf0OQ7yuS6p%)T&eLETIb9#cYiTG$2u2yk_$7(NaA~m7 zZS9OCBVausK{Y648jwRB1C6N?ioqP$4IKK+i!2>FohqDP;#fbx#O-#Z#Q3X^BHZ)> zDpN0UD8()q1eyHW-<5l^BQP(G6#N_t>r0!-BUj8@WRYD%BpW>q{!Q%Wjjr2pOh=aZ%kfRNc-U9u`ww*kKqO&0(6=ZM=aOKx$fY;C!JnD*O;|5EVBPo&bI( zTH(7WT6u-uQ#zOR0e9JXkw<9bjNXSimU)a)Z5UY#$u}X z;*9*oj;+IZy$6#`i|W1oxK(W@>|Q=L(E{%Z?jnX$d)V!wkns2L9`v6y4VJt=Q%|J7 zPy+F@c(QtSZ*PYc@{bj!xbU(cK&+Z#0=0;W2?;I5Y$yVq8L$JLS!n-|hXDsePbZ+F zUcI72Pbap}VE9TWMuNFdZ#)(Bbip>4$;kqnm{xK!TpmwE=*ll)^$9EvrK8l15D>bj zYmt{-0|f&nLapTV#F$b<2L+wYj`ibB9Ae*&HP*+Lew&AzW`e8%8#_>{x_(6Fz$yV}V_QPxsGaW-c#Yk7;9mG%u zlQbIK(ze+}CApe^f++U!KS3fC@M5?DuUh$W<66uf%GmpSEVcvZex#Q7<7zp2?tFoB zps`a@mT2lxkck+?Wim*wAUH`Ja%_j^sKp`>1SbvkD6@0O#Dm;GS@A7S1c1W)6L5SP z`My|za{MB2juV_`H&8~-%RV+jKmom6%@2T;0-qJSTC%D6MRkULL3J9;eE)uRa-wMP z>U{q?UL7jGnbw;?TeRt2-4L1F_7RyRIy}N%E%#8T0MD5%c8c9Kg>t82jUsp_q-@ZC zSacZ9)00W2f%8h7T1mIwn4ykvW+He=|MuPD{9If#b`ZV~Mx7T+} z$&$=brnc=X@2UjukSv?D@?#g3cc-W|j_>dsi)qzUhI))mU2nBUK^Y5{aUw*fnFaoc zM_y21dMPUw>8j4rRMgdSEeZ4U(78z*Y#jh`>1qz6LgBlqMbD!}F{Q;c0j#&xgnZ@2 zAVYLNARr4N`9G{mrApYFLh?{4z1T@=_ZLDk{3!HN&Kos zMLLTqE(iL%2<<>yQoiTR`cb<5p_AJIsykupz(BWsvvd1#2*d61;VaPF%x6>%VIA=z zXQ7upUW7K|t3i<8PKujvNa6n=;dma?O`1^&;@Hx=If-CaiXqPN27&v9J!Xc$_1_{+ z4`2VICIfMp9cl<@Mm2RcJMm<8st?4<58$#@(C&9pQH{>QShgYN)5#k5NyEJJcWD(-|HqhD5Y@Z^nbjsFyITYz6HD zgZ>x95{~SzTn$4btc=`JIb}7uxJctFxeZ+0UJG} zknQ?n7>$qV>GyE;G4py7_k*}z#063VA*0?Ao=%xnm;+B? ztUAViltxr{c*7%z{~BNZj3*4->V%E1HHh*fiByyMsa}!a%2#3LqtI!A^L8Z>nT^I& zu?EkE2wf4YSF>+Hh2(q9n#|wR{h8yiljS zn-CdDC8%4>pr4x%PjgOoMygDhO1TBeWkM3DZS`0*a6)c@^SHABs})L+H!|9co)$^N z6Wdk+v?EDYo>Vr6m*ebZ_`r!Toso~o4`*X!)0P^qb<%h`1>-`2Q;<)@$z9%F9} z5>3Z`vBo5n!|R)P+-ppe|H~wfz-2b4a0X_SnAII`+B^-*aWIQdGm=!>Qngc*nkp(# zYN*Fq7mVZ3G$9?XzE&?exnsEDIoX66&mWLf_h4xb%y2wtAL3;lJS7IMRM&xaFMDY@ zM+q4pi_NIM9rfhaC<~rM`p2^udQDsNM%81ch3<(fJXErylbuQjy!C zj?ubaJ>?DZXfL}O8iD>0CDos#WRd)9Ri{{YpNqVaO&#_Ocot>Ci1J#*MFyd4wo52P z+9AB^aUJ$}$+wJ2JdhSId731?(twpXL)GhQ|-8YYG7%zP; z1Tw91U2R>3Qhf{7Uc@>KcYXV!^xQ1O)7?C-ay(Y?HV_rL>{=mYSD=8_@g&QFzsJYw zNnCrL&^@XBX)yr)15a$}2gB)$#I%F8l4qB*YpLEH+9#9BpVdqD1n2x=1z;HJvt=v= zF}5*yWLxpX68swP=Q=JBH+?s!85bISXNtyr$WbGIU4k_Q8>a9YeMc zUQpCDS5p7cQDjJwSvwN9+ZGfxx2b0X?VmN}-=tpZI$(oGDZk6rl@4U>Cy?s~zV=bZ)%AA6<72>~O; z)$$4;2H{)eW6y*H_qMrOS`m0~Ab!HX#!qVx6p4@o^+h^JKY_+4Bt@as+-<;)i14!| zR7k5RgfFbX?`k=B6uU-v=d@k}+{UAHBZr8{?46)KEd-)lCYs2NMKoTWB1su@EJX!m zp8O#$I303;7r2)dpwI877Uk+K&7OI(L&YfNH&_VNcy-|m74+}qthn0mufy7$;;*f< z>@eJqV$sGC`zY%(RLA_0ht#ByeH-csbM2x{f0ysQ0stof4`GtIj{li!ezg^={a7!o zty@=LQNM}vwA*BA44~sGZyHxA(vJr?@FEzIuN`B($jM$_2I2+~f$1%?p>|pbk}^1w zvsiFp656AJizJ7S?S$;rr)!@CM~*?G7wzyk?O9lOU@xPh@|(cW$L{+9E$8muO)cmq z(;+d}P=Yu=%UhF)LdxX7P+e{Sg%BLF-$xY&oABj(;S?fp+)qusWMl3@N}$j9DOv=k z;dnKH$&kOsj6ZWqU-bc5@a!UDH6lXxpCX^MWYf!*36Sax+2V0v8NEs`hpVBI1pRd} z;b?a~-R>=AZ}9;Dnj=PA(%K^EQmLhE6@n3#YFdM>Ncgvy%X_uz8l}1pvcYn5ZNRcV z*M^`1(RwT5;MePJsPk7=S8Z~yTk8jIqJG)N0q)>61MbHMKmadO{$?`1ItrqDD5Ir0 zuYAj7kn0yuiUzG&_26%?b{v;|JB!LFxMF&Z%C<(b&><7^EN!F_iDn2!4oN$9Nt*R&Sa26x>|nAUxbg%Xi;0!GM<1H z2;l%)wt%Bj6(|@Eq~q2P7Fw))7L{hd1yUFd*dZDPA41c|c;UixRzVK4u7V6VLQ9FM z@Lyp*Wb2WQJp=%x{+&=R5!uSvVvr2o%aw)b9}@Xq1$nr}gRTf3i^@-u=6^U%`GrHv zk*mzL7HfS>RjSum>tkQT*>If-Uaf+^Qti6>O(=@^9TF8&|73YdHW0ZB*qG}+RCe(P zB+&i@W)t>f3^f$|ScHPxL@@6&n9kKWSO-G%^f|CnXRfZ}!lmt(Sq4rrrKw|QA99|OTI z>R^^^2FgzpguNbg;8ZQ0KpQ#q%YHNu6I^;a(!Qu-?JBiSx|&><$U9S-U%zg(f33T& zy3Q{xQ>zteMbwu`DyjqHLEm0eU5mw3|HewcemeBebZm5mJD<7hOM4x;D_h1W6;Joa|ISn@(TMv_^7lpj-6Wivwu|US6f|<^ zi9Li#3w3v{xsjrlf(t{XNJ&fKhBxDy?S!Dki8ZWPIuY&sP5pXNF`?_U|HCf3$N3G{$R ziTjcAIt$)%^SLuEA2d3J^-!G&qMtI1QdvS|O`MPY7)#t@QigTv-&{#;Sq6=ID8QkK zL@woM@R2ibn=@77Tbd{WYPl1x&D+pS#@6-OWis7s;PiVNH$tTr&^y*ax-iw=M&fhp zwsv6IBrc$&6ga*8 zurMl{GjFM0o7o^sd0aQDA{{STg78}{ZK!}8fzDJ_0ZFkE=r7%Lme7u?+Mv{ zGYb`w>6b0!@iZ=!zX^6RrlTvJe+SL$l%GL7-ae$ac=p2sC>jod$#MtfI|y`wYELN} z4V1vrRWM5@%P&#X!-%TNZCBqt=jqvsx+p2e28VoVJX$^VehnGX987kq$ z9r5$$OjZ9GobU7o=O^Jx#AWj?Uj|q47Z!P&HpNdR+acLnrOh-U5ZeTTO;_ZS9AZ6p zfVa$%9qn1&K>q&~*6u)rn3_gCMioCv_Nn8jxvhTD=m_2ve*o$rr1nVap-OTM)~2X} zhwY&R3PK?5XH$ycirPPDf68@Wa8Q|lvD}&Z0;mJ(e zHvFAZwe0X-AcSo#f#>7lyR5xQ6inHgJjc{SRHqN=pwsZ5WMMwfl0BmTpJd8~ln|y;7nnky||TUf-bB!H{9? z@hJ6GK^C%~p|jG&s-Et-$CYKSr#rlCFPCnl;3msI$p=PD=HO=w6$Q~UB~UP#<1sdr zKo5jR6?DaZt;9aGNhR3y2y%JZQDn2UL&%j-LYA3a=&peRdY9AzYz&I$y3#Fp;A3TP z+@H{yc-#UWXX)7uo2)%OvxN(C*6hseTzA&=yzJ?DIXQhd<ttDM5S!r{0$O`14sdBC49ss|He9q21&+j9{DR*H%Myy%ngZu+f;HWmWLF8rd6QRk@lGW8oMor z^7+_w%zelqS{VgVIRG|0z~KAtU`LxSdkKmgP^`Wm#UgJ!tsM28==W|Rj$&)>0Qx#f z#|w}|hl^zA!PYKhK{t2px|NVMkbp7$I+RdHG7Nw6N5oe9$v!X$ZM&Q1yCUo*w0S6j zZxy9z)UFh6ZHKo z%@(}Qjuh+}M3SS3dOBp|xbQ4KhDDZ~}gmGi{$5a?_gLLT^+~}YZ7g{C$HbhF8B+B^ z&1ONn*Mjx|K~tj8DlBMAOt-S2r#n<=r-HrgADI8bMD)i}=rRb{O+YvYG&+5y@^GsC zh)`+)zW%t9ZEP- zC`m8lI*RKxT*q+HAN50_m%YlzTFh+#f*)tlJAPuM+JC$d2w)(XTv~?C`i~`q4mcKD z2yIPs60w;}J3fWdJl`E3NrApZ8v>7UQ=T;r5L+!*K83)lj(%dtrbn&WVb@C~)M`;xIjF7n)SlJ_F7zx3~Nw%k> z$lY5OJTjf~dqlAefYla)5eN+`0#W_t4vP90-n50-r-OhvVx>+VkQz8VRz5}v*hJ80 z!${um?*BUq%g_>ob-dqAq_T;9Pm5ifBEtz-TjU)zC*_Xpv(URH@GLMA=ciLcsVTbHxHuS% zNNc)qp6&0G&tPuGHex2_V}FAoD!Qc(x_1)n*_e3aCgo$#5r4{~7tGHQLMeDEzV45A z&W~a)W9`0A+C{Qcr#bABBCsfzqVhF(#G1iOLJ+2QvGe{?p+g#*hZ#9h!D%MlD3X>6 z`FRE2g!vN^3FFUD3^yw{NH4`)kM@MoPz`fICVz{^%;b55+$4+QaF~FR?M5CsjAw%| zOhvZ$xzsbW86b?#jno__JS(_e+{$>0qOUhIo(>d{)WSYuF0te)4*NMIL0)+^e|wz2 zVKJLaF=ZB)M)F!7_XEUXHk(6HMh;0Xn$TSW{T?eTX8v_nelE9^%W4XD(UUQwg?cY` z@sWg)>p8q4o;IV@$RWvM2itTD~*e9?hW0{xz>{==k zroKk(%u9f*vt$6@-N@MjJOL)iH*d*8Rq+cx5o}}0A3j@dIqPa}L7{;ysS!Xm--Q6OY9siS_ZNsrl#tbQ8&*n_A&3gmH$j0?qhSI& zj%WS)k&*tTken~^7cdyDZv4$uAyueeSni>{cb;n(kaDxKx~huiHL!gV9pv>3(8;dH zfOMq29>r1^m77*0$-5EdV{en*fJI3s2L5D}529lxg*B;>hKd&ClWnpjZYAM|iTa(S zdtp+=*Gyt`7^u$JV=O5%TMJQ)_7NI*lLM`qzs0dNrlFJ3%5B9~E5k!=4B$b&!2X~$ z!Y?un(~1_u)x3>>e4;mYH(gn%!V|Fj^6;V{RIm^GJFEEV)K7j=$5o^TrTB__8<{<@My&h-rpqu8b?a5mV-p;w{W(Bxht=eJ<9RoduTeX zU3nNA8;8@81Z5EYMBn00u_e#d5(H-i3~D8~06VbnG=GU>Yl=R^YNbRlFk0zFKJ-)H zPJ*wwfTA^?7JkDbQ#y8GqJakJLw0yhixx_ZIKhOc*{ zml7I>?b=&m*hpYYay7q+d-w(X#8&Pl4(Rih8%LG9RRE1vPJy%a87xgb1|aNLq&OYOc$oE^Cjfr^dOjSR+a_{jkE^R?Hfn9)xQWIyhO1=~o~hC>q0x4Q!My6+@z{|Rc;TYWX<*SK z?K~adU1ZLa$ZE6(mLfApG|vZ==M)+mv$;xm<;50Y8JIX64q)BdRnjdLm8&<FH0rzd4PH4{5WlB=D`^XRt9fchGY5zagB#B}A?EfE$ z{r^|+aMQ8BKbLBo*yGT+_~S-+hpP=HjK+(>0Dr$BU{KPLz&q8KtI%mQU@1syVvW;r6xtQ_qusS zX6g5FKdvDC2JPPi$bWK>1A;3Ok7_(J_h>KRUt_`)1NeE2Q%Qm6xYw8(ExiPZ1l*u~ zcy4=d?m9&5;MAW}p(M^(sazf@f$M$#w;c@wP1I!%5pdQdh`~4Jkz4*^N2EZcsZYrN zwzD_kYDzc&2`SaL9oicL7hcq@QVty;?m>W;|=~M_%e#aCRx78C|~vpDcxb zACDRKYihs!=F98km6PCl$`)A%d!Xvz{2ZxV&@?wo`83;z#4U6ku+K8BrJpqAXQ_!r z_(j}nk+}JY8*atreySvGXyfuMav5#YdlVWRDK3~y24~EIrx1!#;uetEaYs?)&ZxE( ztz$8K$5SH%=%_W=m3PF=quXNj@3Ezxjl?ZLsiUn@n{t8CJpA@zlx)T2e!SlF;TfF! zv6@`E%*WDz6I4thok=D)8Pd6R%q{U}VPvBhHyPC2xA?K_;CD+)*F{}>$X7#Xwh+Q_ zF2KQcz5gJEdAs5KC1?Upm~O#OXl=W86eSbcy?7f2HPMc9S%h62LQo1e4fk^7L=r@4 zFGMpOQPQD@#wNZzHt`9?MQ*@8b^~^0VRVb;I{_Q#^q7=1SQO!%!6gwCI0=Kl?#UyT@fwW9%_~pBFFOwd2RC>8 z48oF{T-Zv*dJU}F#XVwy3)a}Bs9`ekh$n^<<^PwQIDt5EG^~w+6Ng!xI8`N1#BUL) zk{UU`h(#8w&(X3QscWU|31F@#0=a>aMDmzSENq%RRsBcd67^h1p@ArqlRzsFihLMK z--fuu(L0Om@Y;-r1&>=^ET2+0{PUDeCb`Y!4&oy*&Tf#b2DwPo@))0Zu$^E~tcmw= zmZu1li79FhFK+JVk_eus6!_!q%=bVwIzpb~6cqBDq?|X>z%y2dz+S0EkE_^lO04~mTXD1;r9i*?Nw59A-q!kT$10N3u(PUk9vVlAt zO5NrxGG8bN$5x$GHYG&JB3#YjlZDHT2DE7!OSi(6G=XnnEWSUWwiX56Y!#?vA)ip- zc}?wFcf^HhIIq`>+-T_ZvIH7kaO6!TY9Ijr6;a`Z(aNS;@YL}lK13s(kJsQjw6&=14ih z|BV$!FNVfM-B)ZufyYckHB9)H;emGMlO!{by}5X= zlX04>*#~G}Nyu}|h7vGH>$i>!mK@hgjs{EITFJ{WKz_^Y9eT;p(0mfxSff3*$O|T1 z&f3wqUO8L>>gAxt^{qHkOr7w#3?MR3elJg+REp$@NRD8=A6zTJ&L4D}ExmO=Z8_&`n_FPxYY zU}qxf(2hk{!RbRdr?0m&`(KFDXL3%Dtl%Ub4eJzW#f}`ZnA}MrGdYt-AcsKi>Bf3a z?nk0&E+I=-FMlrpf6o;B{puKQ+PPHUg3UO`f{U?4jBSvqxi7i`%_JnE^u^g`V&ewz z7P=G0D$Cb(1c}L+R&gpngfB_>u)asVq}MJ)b5rh#w-Ru0)C7DhXf2SR;=2Yjy@pti52ERtt{kftG{Lx~&LVkU5l^(nqK>Qir-%hV|p-OH@T-bDFmhv|`ISlQ2hH$5Gkc6~jN5AcfI1U&o7cL-|f;X@2 zSb*)1kAkY2+65z7v2)Te?32S;mh}V8%pZ6->QIRp0D};I}1QBlSY+X#<2-`u2)3&K(1>1kHQCD&1H?oF)ICi4n!pP$k{d0t>_fUWde(D#1 zeX9CBL0#@^Y$76Cg zUxy$L8rJ<%o|0#sN5MpX_z|+Xz2OrPj%7sP;J3;lU6BG-SOIEL)P?+0^v3<@C{iR_ zV3&zRk&IGSCXkAxMhkhv9>x1Ga%G>un4D!2{z{OC>Q8h`5&NNF~c#+avK^lZg*|{MxCAyl| zAu!O`B`I)fbOM9!j8ogSuJ-#U5yAb~^X^iZ!YqsWG0(cisft z+rd&K6hs)eftWVEU+~qd3+#d!K2~mFR^)VJF3Nrb4vWBV1p*t3?~JB7=J3b;=+sKt zy+N+V1izuKqS8-`GZ!Gk=S1AEi!W7i&2}UWT&e6^qpAC)>ce4UqAkUA4rL@M`$X?) z%P5VX8FuFbcreC3*>bZaJzN22*sr+eBmV28`zkmWiznEz;Wy&lJc2 z>aQe0P4)Dkp8PP*$Yi9jb=aUNb>kpZIR({WW6;p>4vQ?|frVU$%ERhZzIiT)G2PpebQaw_f*) z8geT9Ju#%{{a`>#WWyM5`e^V(kM$-h`6QYM~)6&m670;`B3vy z3`>YXvNG3!ex`aeEJoEyY1$f}2?g~xU=Em(Xw34;PvFJK;Q$suOa~56rh2f~01RS@ zukUnN&v0$ohiBb$I_S5SHK<>cEs~5XjK(Ut>N`rZA^5i;Wl<6)|GR3zs3j>=PKFX)q;4V?U-RV&Xic#t^C@12wS-r6lY} z`$s*|L|&Trl{>SKzz(a7Xv&+axLgO~O`Bo@iXA#{KAC9WgM%+O(dE8m+J;U4nqIwR zQ-i6OO#5oRWS;QtyNcZO7QuPXUoTy~QXG{~kJ~ERl1#dJ)Q%(h)~WTCe#yr@`-p+@ z_n**Teu3-PxSqt-it8Y*c3dyvI)>{6F0(xv9S8a&S7d^o_9Q;;^vH1 z>~r$efp7(P?HD!>Cg$1g%DYR|KhP|~B6U;;TjSqoRyF#?5^==d^t|a=pZnrSiTUM^ zI=LQOB5AW5wyoZbu8yyVkSik0tq{j_GO}eeBk2vCcddY{LVy0P3UzoWf!?V7gcFf` zH%1UP7cJYz#^}gyYs$q=Nchvb4h#(1<6$k9)Q=7t$eI1xxpSBp&;jf-TCM{$+Dxeo zp=qUqbv;2Gh&i=#Nw8sZW;mIio*HCGTKaJm*z#HgXfyqX`v16~nn9 z9}3>)Rg$z2ww1lOKZmQRT3qy=RRg}nou1*C&+pbV4jPd!ML0W`ist1tH-H)j%+IFb%yKK#BQ1owg_j~6D~N#t?yiR&2RS^!5y;jE_EYkg*+<~r zN~}zWa!cWAu-%u}eK5x`X6Dh`ENcX||8Cv0Cz(wm>Mr(vVvDoIZFJNL&XrD})BiXX z;`>nHhCWnK(k&`nC8%K5chL)0eYrf`ydUi)MO3q4XL1xSTDk9nK43>)xdpm|+K`?2Z#>ajNR8U`N6Xfo=8q!8XYl_7hD>He_!z$M69p4Kn3g?#sj_DYz09f`K z0Gks9Cd#xb;?hU)??gOI7R}>)_W{=&2%bpeRFQ@T6xQ_lG(r!yfTe>TCJhRIZBZqK z4qw-fYafTpG1X=5u)hjE`JB!yvSQx@v@H`%_%N!2Bh)rMf^B@BZkVaCW5vd8W_k`W z9u_!)#b@BA#7$CX>IXrefmD^I|R@9@OB}xHBcM{ zvZRRO0|Lt~0*HK}ekFj!R0;kV3J%{cRFWgV5V%BknLwOh07Mo*kjd5ZJIr-1#O5T1 zxzCY~e;LFC{9jl{6~i8;9rSqvIzJZJxlF)wIF)VcGJ(*A@Hbx!z6tueF97{SKVGES zfProsDhE0^ZTRo-P-GKDu}`orfTKw#!F!+c zdt?Afi`Y3%KzyS^oQf+XbMyq@kH%iS&c%s59QN-8|MP=?(>PEXK5+6|Ljs2sWzUpI zvuLUCCUgLk^mInq#TcnWWd8Ti2wp}&O*A^~CK`pVW(nmA>h+QN@F{>kd62#aCUi;K zttOPH7dfbyu@ zKIiWC`1rb`sSxkaSrO2q3j}y-2zDOlDU+dVK0nbZ}yaU0W`an7vnSW0tjt+vx zsbP%SIb5?LDk1!VC;%rb@RK`TsHE~Qt(Z*l0Q!lEPRSRe^J@X*-$O^egfKACITmlB zQ>a`@RZHP&j381M3`vtb_`=W`^e`yxkt?thF~7K5r7s)67Uf{ipkHgyD(OQl=+xab zx^##4K$u#6uzD@bh&ULbcM1awKPHk`4_>QOS5@;l4feNP@a|r@&d>Lr!Xu(y5odeB za}iS@K5o;*r`WLrJ6?b9dMYluW@LxL-JPJWK0u?}yd48wPaV?jcR(^JAJfXshqQ9T zXyxYJ=GT`9rcd3<%}t*sDc3iBnyi#=KZ=|bHi*JfD9nN6_Svti?_*I1 zCYm;{{9Xgb@LAxBFHb9{C`ji*I_-t%3>|z)>wFG29n5;99dm5#u@mRbRA7B?l?u;L zzT^j9;5=MtnrRxHbUe}t)fOyogZ1>`N6dy)63f`%(U4Vok)vvy)Kyg=H7R4t50#jls8)fl=3J`k$BItjDE4HNfklzek+s0YNG?IPCGTwR_4d+5H z6Tb6qoG*cmkOJodFDBO5J-{BghxXvn8{Q@P2%%Jjf@pFZb;OVPUXI8w8qBrFZSHPnXc+wp|g-m`!lDgfDs#B-8UTOgF#+)^AgVcWN~5-n+X6P z`9yqSO#Fo2c%ln77yK3>V$)yD9xgNPsV|E2F%nSd|50C37v4<(D4W(Jh%=t#nmW0a zBry8!g=KRW-}-srCl=xZ0)o&ub?XjvI&;0Q2?H*y?Yrm>b0JA|FRQv(re!=6T;}0h z#&`8XlOvv!PvVYAK=5{L1KAqsGhVE4E9m|b&NhN`a)W4)Jhw>Cnt>$GB=1KCk-iSi zXK;%O$BW&3ku;rKcr#L&sJD?r#|biUtl75wtO7L1ZVIOr-a43n*(V(9FU$jugG$hw zXAbhcnf-*B*peq?R;z(h~~qF$tk!qeo!@^0gP*)mGV3s>_U|Vp6~}o z`9{tYpssna5K&A1*+y&>6`+QoR>2bIasc-+?m2bXjU}ty$k*G}jM1w=K@e;VN=7nT zA>$;5UpF185-oQOA_S2~Z;Fp)(E%k^i%^R%xqyOna)?bVy_-kqs{tw4vvk}V6qDib z`N?ooaM6~fowlJD#m0C&2VRBW^Y(Ir3z`v6t`5dvO=n8 zsFm{b-Eg;8q&zf8rR2T>zmq0OnVGm(N|kkWQsu^tSjR>>B&@7miK|Mg#AAcxN2pt> zqQf$rKvYu>XvHPNVT<6ZG%)N;h-U@ZjCg~OPo{!H8}Y|^_h!u0 zCG~2#a5E}&DFpIv3W4N>WnsF!kV2h(Lr2L=DD*78d&tuwAwDfjxx5J9MGw>~$5pPd z4s87D10G{jV;0JBqrQT(@a)eu10o8!o=tiNh7vlLKIYjvXCpv;Qk^`qbXXdH^XoBxMLS4tPJ!1|~ z$-4a~0FdfsZ}^}Z*fBcr-nL}Z`<6oz^3XY4(6YEU`|Nf#UVD{RB0eT%Cc1AK)xnw1 z#ZEX*kK~FMPV#_Jf8x=3_!{>q#f2&kgm-&b*pM87IX_HLPR6)BQG077vj=B`U*M%~%sA&` zi;##bz{=nEKMDw~6sfQ1vTK74rOVFJ?uEKmWM{|z+AEnj{ivR*Grz&UehMu<(#Z*I z2?z(Sia0|>cBpyqk9@V#jwBnp;iAcc&=Sbin0t6}dIALh4($5z1VT+(j&nPKPb33- zRbM@YVsj5|IK#KQvXy3LqBQbiNDE*!L4iLa`@=(G*d*G4{#YFIIAMJtwZ@pnCLyDj z6;Sr}NdM*RAPV4wAoG*ex||n9+cn^9p+bn+>yb|HZ!^!T)VgdI=25;Ci|%j-AAsZB zI=|1WjxylnP{#g@S1fAA;k?d4092+Ox8VS_%dRA)GP*VuL&s9~OXQ$(e~NL9_G_M- zOKB}yk)_~;9jS%Ty_1?g%~a25&qumw3x-KYA3witqIp;iNKZ5>acHmZh{u^K_Bokq zA{}}YvCWTsXpK|C7C=KoCd#IX4Kh3*bPl95V$$hD=~zENbJB-geuYYqah|?GJ0`#J z%m(bnhe@}*d*XQ?yBT&wKJ=)CFc zu)ZWV-DYIM5fBUYFhlnQokQWTumh8)9=LwpPMt%14X7T~qIzM#lP}xGRWh{iO=qmJ zj$}!(GyAn&52Htu3(26CBiQOA4l%YqWd6rxaw^zdevo=SOxl0iP3CEQ^_+%IN=?dD zyp{TOOfc-Q^o$f|JZc5^Bb$*!nPn=4<)XD>BukVxFgrn}lCu^^wsy8sDT9NaGf&f-;QxI#Um zsTmGR!*&y#?ZnSx;og{Z;wjF$$jW>)_NY? zpy}X-T~M~0uAHLcyrqY3$Ewo1P}<8FEI-&n(5;;ZLqnWHkdNJP4oinm2cYOSOVZDA z|FWwbY3Ta0H2-egg>aXkoSLy^ay!sxZgh<>Y5HaIJ5-%CRL67?EMwQPZ$B zsl1y$zf~;IsUUQ?L(?*r+gk(W>Pem+!ebsG&rk^nlKhf0N)jwJ_)K)BI)VF?z%jO) z{f66csk>v9)oD7(n_rWN42XJ2odF7%_Hi)Nmy7Pc7#O1$2@yg906td6Yg~lr=_EO{ zbdnI*<`CH`(`YNQ4MsN9ihoQNor|_u}A{&>Rz1!8KB69|*n55ji4iz?nUJJZ#i53NW~UqjR=>27(=)$${N zmZ#l`;)Y;l%pBI#>*P2)!Z#AW!wJj7j{TeQ5*Z-|g-g{5x(%Nc5GlH0YDWqVT{r5*OUI1UyL*p1y<0mm+< z3B_f%>FIXwAkk$r@7DWQ<@>tv1P`Jwdf_qp92;&u zTk%-;;OR)K{yG=gi&D%y7A(3$-bi4r|C1}W+}LND?fhR{v1QWp*KMQ!&2$&y^nd;S zzuERwmoJ0=zuo3k{#TVzIN`F1bTaDHhNPUS+3pGR{q?JH^unfz?ircWrf246N#O*{ zK%`&-LHjW-beZ}{;8R$!Tj{Nx>uXT&RXAoUV`$l`+=*S-I|k01eN=I}o|Y^5OWJC z2Xw}4l6D-51v%kaPA-6H+NEm@cGDp2yg1lK6DlgJ;0(qwNga;!zV?uSeHaac4R2|o z1d1RD(n{gv$X&HiHy9=4*$KJH77R6Tkw9qpN`9qn})q`H=3pJpoGpylP~)zavO z%_Z2rmopY>5XKV+8-?m4RD2c({_TXvC{mJIp+sSBVa;uEHZBJjEa`!f7@JhbBH99o z55)9vXurqk5CiQLbk9D}FsnA(Ar`kcXntnmMhC$-7|a`_VOm(-e<2)>6>m>b71O-x zMe!W(BkkUKD;7zaYC}C80h~uaQl2yw=UVzJ*VpB_r92#ouE^$Y>9wnpC7cp$ofb^A z+t!%@%3!w2zcIqToyidb;V-2L_6dp_eC%yn7L6JV{X4w@{i$q47^7g<86z!08AODh7GO+X0_;Ryhy0Av1mELyF*A zpo4Blc2Zu5dI|Kxzo|ru1Of|4`mCQ)_ULS4`-(-b1^$lNWh3EAR&$Pnf2OJA$s1=^yH{77e%}vPGH%p{0=p2CL!8xOmlFCo&7R67X z;(Pcr6>sOo+W=h)h3wUQUlM!($*8a4el8|`Y>&bRVoaReUgJnQ7KJhE?ff} zXy+kD-5If?Zg%FhnVGrSB#TV@y9<^wTF{=T{kQADFdSmz#EydbIQDxG8NjlSMC={& z;GpfokeG7B?MmT4#oql|^I0;P27^sli`_XZj0btx-ynYJ*kfkp2~(P4Err^ z%g}Dax^+Y~1(t`obU+^EjTaQ!Bnt6%>DhDgeHJMvB3V2_)HFTM57|3ItgIrf2qXQ0YJ z+OT)9626;WgdYriWT}!EFz7R7w5iZm#zr?I2poa43OA3|-UO=$K8;s0u&n`IF88Q1 zppQGoGS)$?bO@)=e1xX2(&jsH`aI3zlmX}3>8>VLZCmV=;&9#@Vh3o;M~3E)-3v(@ znm_p@zfH&(N^kCKaEn!5cpYYQ&I^`zk)W`n8fYsbpy|R;))oFeVzdU>bQrMVpNpNLFLC4-v(3qnL`$6c#hqB#TH=^k%s^fG5NRiUj%f+b zsbSRCAx|d($59Tnv>Wssv(8i#hnoaTUH}UWUeW#ZW=w9sA5dnAWeQ>Q?*OjlUHFg% z%?eUM!#?ep$F986cR`+Y|MaA@B zH~V)QPI51gL5I``;9icJPIo>1I?RjF`qHF<`2-HIA&Tk(4fnr=1_MPn4k1oi6blQZ zLrbTc@Fhcv7VSfHroT`EuO^voBzHncU zS}FqY@Qoo3+-c?O5X|2c=HK)_WgfB00yYL1L!XyJ6g8L z4!+vj`|7}Jop{w6oX}!p!F|*RoR;&C3*P_P=e@=*{|fSuABj3SJuWJV*_J+TkNFG?EO#TR7cD?D1^SnHs?%E)VwL)leT~jS$G1=UM9e zjn881>fg}wkW4Rrkgx6Ct2f?zEjoP2bHB)OKU>0c+{JU;g&ez)Lp!wX5RqCdxkvLn z+96HtK(Rr5^isA17uL3dqzmZnYEh9IpVDos(n=oIOAc!#I|Yt}amcfW*p%`a>RoI- zP&9L0$+1G}y=LAgs`5)7RwwBtd-F?ns+R%9Ox<(uMB<2N%UIVos@z?S0ae}eYm{vNX`IIu5?#6nd5(cl6cW7gHw zOT{eIoj$hKrVN3Gl_;jNy)=*9AI0ZxPR+yW9onapN}kn9nq5!dh{0+P7S4qSg89W0 zdq%#ec{7fzdXRrch&b$0G#melo|$#KUViVy^RN0J1dGw%3>qZLpg~E4lJHQ%L`^bD z2!UWQB!C(;K!yav!(>iEBoh)R5e~;u+G?e}+G@pHz4f;IS`<{ogm4L{ZKH52Dr!_( zPdc* zCN?;jzc8L4Y%s0IL>!%1?L+le?Z=2+s{Igu%eC)s0EwgQ&w$B;6c=$yX8$^iv6QAJ z4U7y8L$J08t+yDXWIwPJ*>1>b;(`ML zDcU|STD^RdQnnL^Q#dE1j&~WdVT^bG!_?1xyA9rpHew|2mb`0&_4qY%{~pkMyYd2g5gUiJrFkR>{H)v60`e@_8%( zGx%=M3FrmKM>5&1XJYF>DKxj6%8p5wTS|hLo{u=T_K!heohByGgb`~iJrXuz&uN9v%m&s1(#E>7)MmNNR< z+TTaUfr4yTLAuuxYDm|z?!f|3fKy9!=Y9C27R)XZ?nLiDb%2h>Y#nq0#3pRzv%`HIag*HeW7N)8&=E9bl)&*XLZMR!2C=-# z@rg51@ICO@5W-5en=hvsZpIjpqSFk=+DD#5BRwV!(zkKRn4I6op&A*rjE5mhNj`ll zE*YtvK*1ZYJlBUj{5Loeg7FiYK|r~7`=vxz%hwVilH|QY`_IYjRJ^460~A%RJwJ|O zTccv@8Cnj+&nh?&?<@d55LE~kW=)i{VM}YZJZpC7IjWL20g084V}!+i^A>5dDa2lI z6Mm^%4N&+NLnKfR22HRKGJ8t`SiRri_#7AQFrkaQA&2zlv?%A*|`XU<6eJtD*Io1awL{?n&xq{u>DIkX*Fe zhzcK&468;~xBa^WQ8w)#I6Xu~c|B;;=ADRo7$JTB623f1>BQi_6%!SFi48(BheCLk z-aMU%E*v8pkh`GK!#rQi8l+vz$o5C1g!e?5R2FO z2^v|v)&wCj!f{ZK3R<*OBxdIt{TLkzH0zEVLG+ zAUC8U?evOI{tZ?foxtuZKH%8xGG&^60^xQLKBe00=&es~CpmzKuY}pf3ni!1NjMQZ zlhK)RsH@Lnd)_g2SZ|L1D^ts7oEyP+EV{ebqXs?Fq^DUwrJsyLFWqz}Hd1pfzVGd& zuk2Mh*wtqaw5lu7$|YuXy``-uts3QK{Rn4imgc^UL%Uh3LbETOC16Qy&$o{~iY?(c zq%}9cqo1>}jU~KURl)^1B)i$=Nj>a1R86@DZpLfYc-GS92Y9!g&~TbfEQ1e{6mr}v z?*s4Fn`X%d7`U6_owN6^crVvlYKX>*vIxI?&;S6beK!kJ9&^Qf)n3>A?uv zI;J3!Ka^&>?|iu3^F6ylYrWq%ysy&J@_O1 z1%mfKz&=}%xE+wXz~XwCumZpHGW|-nj#>(bO~V{BZa7RiX2dbPXQ_tePhctFP2WKW!?*RIOIdOo{bO9pTH>h z_$?!GhP?UyOQ?$!psz5%m20sD{)+BBo9EH|Hli+22GNHQ5O~xu4=W$^u#l}{LXNiQ z<8h!`Ktrh$#uGM}4YrP7Avp`T6i{`4hF7Fj7g$}T7Tf(>!ofR3Pxf)5W(Cp(Jxl)nBNP9 z5vP2iZ|CN*8ZEd651TunEjS92#3?U5Q~*X|@4he1CbN8T>*>i}==xpbwYHv4^Cm!< zul-H=!-#l0rKORHjg*f(eNTfhCJqr+3Mb6 z!gBl(EWHb0V#-R)e~ItvnGxdB)#zC}~m$6x}MBquR}AV*k-LD)dW0&@sE zU@~LvgEvx>zYlU|*3^AUFC9bS3z=<_etaqf!m`(`K!Lx;F?Rt>FwL$SNzpWK<1mb2 zTR*c&2%XacZh{vU>T=D6HJz;sz_3n-3G5;8wK>Sge~;N^d*FINZ3pOM|73vJJ=Wx! zMcn>N5u&^g9FfUA)|+7gB=Zj~Brb=0yMTESElk@aY^NjNYs@N7oSx$ zoUVgi(e-sQ9GC+WKJFIsA+1!rPBI_z74SWRwG%d^K1lPuuK4y7w-PdLoXEH2|1i;F z8ma^a`THU8OJ4`4HYD`q@1Kesp@HN5BaPlt?Ma$AX>r9EfzdZ>wPy!7p|Rj~84rcK zpOSL88@((J$PF{XXD`kB}t823NvR0SNn?y&&ke`nfB9H1P z?RPYOTh9Q*O(9lEv4ot$6|HBWN>4rt=!0935pew7k4-Y4e&j5NE{yEzCEcu${-)$dtwLpo>$Ht z;5FvJofu%$<5b`7fMX`kc0&1k+I)Nd4zz6#xIw#qu$9y;Y#lFQS;vWJ$8YgVf=WI4 z=nz!bo%EA&sQ+j9VazCK7-*kKL}WTXH>tjzitkx&-c?B6D+h@cN$oPNE5NL3g7rBrbSG|A}-jiq*4;x)%MTj)pYK zB23zyl6SZ|+nR04?^I@^2&;dib((F{bwCs^fuEf~nvlF7_R>qWg_z7hGAM>%%j~8d z7$qMak~>2(#^Vh3x$}T|JiEGioN+9SkHEcobqW}AEf-sC8tU+Q3h!Y&?57yUd{tR^ zE9X0^kD;lx`;eX3AK~`+A>iG=34eOxRIz14Z;@SW&(TA*qFpxoX{CB|NUt#~DURw= zq8$M14jh6rt7*GZs{IN(TaMFJt*%*K@>s_|!~ro>l8|K~S~^-2(~Pzs>{!$~7{Q1| z!!_w`;VebUFEQ*X?1Mq>A=kqD?9K6rZEl94@b>h# z#8&Llcp?(%7lfwKJgn_Ow(17(*LJ1J3AH-4)Y7((2o`WmRU93(3se?N3X6@v2z_ zO(^jklQt~Hdaoa~vodp#n3wq@DwAIIGPyiI3e7kqlrvOQ&=q*7o0xTV7Gy|VH*QQ* zXSr^aof(HPcg2HykTzP?o!!ZZ;i@zHA`D59IcO?u+DC#X@vqR#MeA`l7WveJ0S7ou zpQCLb1<&nxv-$7A1ibv}Y{=bqdLzO%ex~&9B`);Gr_QRfLn*M}Jqy*--_1C>1PkLe zhT_44?WHCapURVvwb@^gl<)#g=@5e`7pAV1gB^$T=~wxE>H%c{H5jQJ+{?MEv*51i zjnBRGhP8H(=nd%&S8@kUz|D(t(l`|Sk2(Jf*_wD}>wnwU^$^x;s_J})vNSnh&L*yE zD{)ml1$N*d1tD1LfLF}4ZXi92H(eF7+pc!jH=v&~gVx2j(&JtQ@RZHyH=$6<6 zKRCM^U(}K$dQA%apr2l=uXuqNXzIgeB-~99-yhJ~&z~@FmS{gi*W_X7lh`((6JhUJ zVRwz)XjctCK6S#XtXt6}bVO}}q}oxn$)fm`(C32GWxf_ijil@Y^UF3EVt3)tzr4T) z!B^<^kuW|KC@hYx%BuCZhT=ZTyyfYasBiwS;eGh8rPl-TlpVMaNWuLV2Q;v-7&qY&z$79bvHJGF)1w_R!(?tY_cJ3$-a8D%>x zDd8i<3R+*GILh0HKT&+!1I14(#rz`M9?0Kbf({mXg9wkiZS4c%Qm`W?Z(Y-sqjTv5 zqw8@6)k=1w zsOG0a`CHZbkg(cndys6W@^h65xN$ZVZ^sy=vwodmY!L8Ca(kevU7WFCYzg~kK8t^& z)6fFJIVZ)Ul@iIZOIf7-79$;J4s0vh@!$A}m^f^E4N#a)Y$XrI?Ik*i`L_SZh=3`X zsIhew?*7I*fi}nz zhg-1dyW~6Wq+o9ik6cb z9TC_dF4lu@k{#yMwP>`hV>}!`eO69qd`X$(9OnjaLT&+I`J{Ro33ijH_;t)3{ZbrO zGgeZ*T>0Dt%hWf>W1un;N3n1cfWfO6l-}&%a6flU|0>-b>Y}HFoBzZ@T(x+x;e#ka z{<8|M$M;~zfo9r>O#uDyep#Z~W}<(UJ$t~&`J(iUsne#~k zt^0C!2ZdDia#f0NhhLz~&b2nyK(I7|AgdeG>!6`!)tXVfzVV-={karxu$zYqlIJl1 zN$3>4@8A+aP2X@&kJ}1-JA*fQ6!%Cb1nRabwB2w>BBlvN~AQ@xWk&tJDm0iXW)sAQtfj0*cl7X4hORR+aeIHwOQu?HfhClU*alH&lY+lTp0F-*std8dio3Jq)ZQF$lnNo9+T5nJN zqw;y?K6Ye2l7bDmg@Bp(AJKt4S5hKb9oU(xt@kn+|BUo#K^@5HWHKRt-TRepq%0kV z5~}Jdnd9R%YrRgqtgeAE!4>2{w4S_)_G34!+?@t6Kj8?^(;M>g%OBYhZk^ zPF_cj;~@dzty=BG-CixiVV-VEj0wCvc!XSD<)o4z_~5BoDZ_Y#lvB4-UQJ%_VD!lw zR+W*TraO%#|+9j zmo=d@$`o|~PEiz|1FLhSYn_dC za6|6&Hm$2-q!yWlKeLV)Mm;7t+(+OwgJH%pp#+gHks8H@hcoh2t|t1#e$C;1+IhZ@ z)FIdD$nyx29zTj|WL*X0=xTIX44IW{7%4y@vH~MU%={`Z8Dk*RD=XGEu92eNA@?|G1nnEri3+^V`v!Sf3#bb7XiNg#tO72J^mV(uys)|hv z%VdwIs!q5}igXh}RA8r9OO%XZ9r;Fti-hwU!#AgH>xMU{v%XsPvO0#xWL*`?tXhMq zaTbs!I@PbMrBNP*DG5HTAVW0Kfk;SIj2bgl4OO+Uw&TIbUcGEBGQkWk8Lm>I~Bx&YzJveRfvkgOsOF-mE)tkG^4q(dIOdW8w@40gt+Rq^e);yjx!Dt;FQE zysC<3Q21}bEHS^Jln?W2_@hQkh7;C?QLe+(N>dF6ArxSxTT0yUTU{qFXIR3s77J-W zG1S~_sIU+qv+`PoC2KDU-FanQ4F zS`6K^97#a2PG*5PZpkA@od5K1fEVjy?8#slZZ|K zWIXwJ?!dDF&kynJ#PdfyK|E*iIA4W5K|I-b7T~GEvmVbTJpYF0|G{$@&!6y|!jp(y z#soYrJoE9a#8ZOm_D{QoNQpgR2mbzqK)zQTr-yrE!%celqcP#&uZV4@12KqVzw1rL z1^6t3HxZVOZO`9AD*sln^pFQM&6SVS?uuVyvwdH&bzX|a{}pK<=cSmjt%I{Yb(n&{ z-L&t}`@msDvm%<;s2E5}T^$uP=^hys#tqq!(7+V?2fpDb)kg6Mqzr(@6D^K@ z;y;lmwgWz^HVJz*&V0ZA zhE~@Uc?Ryk0+7`%*FFUE&n}PTq$oMH^NX`&@?yr3XJ}wRkxzb)kYLj zuAMDH=?Uy)pjl{IKz)uxbw_zG5B?V~!>5;lJ3(P~?nv+%wPFup{Y0zl9y$JisnQ)B zfSgTdrADp-7VufKapr4mEUK>|cxL@3WjI%y6EtJUxus9_PsDpVT!VRTnhsr$OPd%WXFD z?|sqV`+rdk#Aq&}9-#L_oLfDphf{k-!Y8KGuc=uH3+qd-qPqA`%%gqNi&+l2I2?keuSI(RbB#KN zN>}cs($VusJT{T52K8S7+(=fH;TPILF*KD;PgeBY39vhi2%<8WY-}AFh#}G*28ioB zJE=Xu6(^MeiTGe5hsKl?qRg!{+N+0vTWAJFh%V=cC`akml5HHTGa>K4x1FJ=@+=mu zZD!?|cuBs7z2LszBwxWm7*VPirzj^!Lyzr}oR)q6YE^ z-YVKtXt3ZCQF%K~3?Dy&r6t=s_%{96v)GSgEBi@Waf||!hu)$erj#DMic^7ig>3~a zd){{1ebiu=(OgB7>(i05b9Q_Ki)G@}<`VT{g%Mv%0y0W>xi*hdM#PnA?684jVb?Ug zTG^I2(dS7R64e8y7F4?@JBh#1buHc;{B3d^-qaDShizs(tQ7$)8-Hh3iPp~0hJ2B& zJ%A5%Dw~R9mm-WgL6}@S8!Kv&9d|4DK)%-8b`LrOZgLA~CG?6;JlCugPNs#`JCfzD z&b2G7K>r2|Qxi^Z{2LsSH?3`h<3scr?o1K0XHW{ximnaW8?` zoCrt)Q?vW7DY8dMCeAP9&g9Ivj!AFFJ{)X`#6 zmg2gv1S}T2V8HB+K2TnY1I!y}UVxO>Ngeyp4(jWeNPh}ZRX*#*tISFQqlbTYFFs4& zQni(UP_2JXq(~a z%%V)_d5!1g?%76znhr>JGDvISiQMe7YugTdZ9c-|?xvYE1T!3b9F@4E$I*>Q*AvI8 zO~t_=pTerg&pa9D60tRet^kClsCGW2MD|1>$vcJAxU@z{`!X`g!!#25MRYL`N3qyF ztu(pNKV}&PbZ83ZbOO)-x`B^_IYssX9bWhk!*#|DMjRCj{EvyG*=6)uyIBeSzsnF zn4@48`(6T`I+qj zEF{>#Y%rP{Ze$;iV~$8Y=*l0Eli{~lIcSQP z2}3(7_bXH`c$;lk9ztj1%G<6OY`e_$wq5h;L8aqq@Bd_<{H(aj5wz+vte@i1&2xhX+&UT z^Y149L~4d`h{GsfDMmL7LvT;46JIGpPiqqW;2)>{{$>*v})fjMPGB=G(rN5w?jDzP|`%@PZj0>NZ!)W_DamyE_o)KtMg>OY52kxq&&s68=xPN8ECMljiS@PP#d*KPn+I!LCy^kYMUvHI+AV*mhX$m_8_Z7DBG#7cPd|9SvU#E zDQDHf+NQyNC9g((WE@KqxI6sC}gd+n1PnyUw*_SwYK!n6-*`r0*n78OF< zi+8ufPynLA03E94-3mN0o7+5}AbdcP&|a7M~0V(^CevoZkPN+XJA&dD$}B#B+b9k2i# zWkfMJ9p)oHXqn83vz3wieQL@-llxXOE(I^t4=B@r;^vgj{9xme=uUz8ML(+>>*;#U z()F61ew0hqCFbb&Tg~bcOH6=8U1E(1u&PT~T0M(f?dlRoObmy*Bq=5!NnMg06OgPf zamEBV)g>u00V(Q|NihMF)FqQ+0w$|V(qjVB)g{wo0;a1=X2t}}gazl@+p?m=ZofCn zqduBLEDZ&Flt*(3&h`(EZ#m2v0nko#^WmPZLzb>XsQw{~G91Rvqu-0nY7s~miBM$0 z&NU_g_R(2dJ&PhJxqx(0NgQesNEa25q!xj6Q31(n5l9ym;8cr1x~PB@wFsn(3Yer8 zfpk#;lhq=SE-D~hEduGH0;a1)AYD`dkq$fX=rDR!?`PzqV2{FKPCCx((Af|vD|dPm zm3OujTQ?8SEtF43j)(Xj1m`!lU(+GdQV7xzQ(*>6o&c`(26`XR@6^!_bfD6f$weI~ zEsmerVv_M@W>-ssp))tLYvWf+FXIvETnLJ|n1X}WyLugg*Bry^EK~y7_o((ojLQhI!8_C+gS&e+n#?j&~Cq>JM+=Z*W?c) zd?MK+$#@gkU=ev>JNi#xaYEM_=w-p{X@YGNaVPLfP<&jHR^vH{=OsM9!t(^4hwyB| za}OT)I<0y0CQO+DhcV~>!V2^^-CimTg!5316HCXV+#NET8Zw`NwU$5*=A2#@o|q*+-KWWalF*Fs|$;B zzznki@Vfmu`eCUyPe$x)9ey+en3qQIG+uBFjYhat z@Bu+U3}x+nC=(uELwi7T0d07+WjGI{R%o7{yhhlZ;y4}mq|TcigCF>SU;>L{M6w}H z(AGH)@Wnvj_Sr^HTlXM1bVBnt;Gg=B0#`;-EkaU(ALy)+AgLYHca>>!oW~Ehx&M^Z z1KOtRiPTyc?SGBbs0vvI^iC$48yU^-17E;s4x=tZBy7tV_Ka{vgYgvCL^VH8oi)^X z6jIQ73;8_8KwwM>c~;p1Q+ptWq%MW=B;tY~a|}g<1nj8HChuzcF^V@*AQ(blq#Ybi zTNAPKLVLT7k_-;fgobvXZJqDHF1(y=qef$oOw%RmbCOwGI;qv>6Qcotu_q}^9?ojQ zY(=5?;Cqa5@o zCflxFh{!YM!{22x9P+5^t)A3Bc$DT+bd%Be#zNY9AoYeY$YonviyQ___rr zl25|+3`WdByz{I&(?gh{b%9q#Gkav*!ZP>*2we_9VwiYm?6`_gvUDDGvDK57d{5Ae zt^fix84dE?=xj6|v1e!snBgw$)dVV)T!}Q`6AjPl7LX-1e~|4%krG3w2@>puJ$rhm z9yKe6eWh4wh(!)HB8gcc46iwn5^NpMAQRqiN3eOB_TD+l?+pi3pIy1$wrc_HlonyA zI&f&IA+pDxX_Qk~BSrSKA$Ce1*%$WH;ZaPrj>Mt<{EmWcEYWD2`Fqd3`bJA-U({@n z6QJ z*8Xcig48;ZJbsr^9&;|~`#TVm#+n6l7y6$Y{jZXynJAL80SXg!EGU-NMPH-!%yTkx zAT#}7Vk$O#qH<;%HuT3Z_}J9g@ny@!tO<%Ot{kg(R76CWPx4nmTbI+h*lOBLHHIM` zM#y4|DF+R4Q3is*gYxY)AHz84NkYRje6)$ECT{UTWO%CLnc8@cTOE|$XlgbRePCnM zDz>P1@N)}s?uLWFwBnO!HjjEU+6c3wj z-jy-LW3}bPV_o>@6izwrB90rDsarm!wq_YU%copBWyP{7)s^+tu)x3auBxVMm%~v1 zIua0s5E49@Lh6Z0pItGr{tAf5K^}6&EH39nA(Kh^s){L=ff$Uo$)GJ*F9!&CLiHs> zDuslg2VnMZumrlV+D+&b%s8W5$i&(QwK4DkgnhXyKgsqm#F-6ntwpB7v;}bCkafd|GEa|lkYY{Wd@ zY{updxDZw}$Qv-D*VAwox$9-Mna*OK1HSuEHZmZXa-~z4?_I}_*4_m1J+R75)r1NU z7%;Pv5Hw-Br18N|L9v27fD1srRVg9}BdPf!)#RnkNj{e1r&5@Fl zZfW5%ux*5mjp+`7Yp{@Fz#}slw?KE1bLp$>9`*rU8sexfYfJDt)uhrDsF~D*6BP@e zS2phR~z$A6aZ@eQImyO99*H6zbt|lsshVSMa08LotAAUtm^8 zDi*rImxm)?v#lNa2qf$PUI=1+?58<=HJARe4rNH6uGne4LKh$8?c7x1( zOV#l{u%kS@>p9jXNkz(ASGHKyaw{FE{e|CZs>xf?j+3h2MeOQ5pX1N_^rxTxuu=RD zIu3^3gZRNHW?A`}5P{@PA{^vlr_Ag^80ys=fO@t0C1eNTC%V11wf{R{6&B68^qJEA zr5iQt*osg#~}HsHzkQ-*>Nj46`Bm@Lur^zacoFgX_C0xa-hH=!2MIa1ldx@Lh{NvEY$oYIZKOMg@?nTUP{FAbk zx`uL_Ss5ozUf8@Z7F5|P+JLeGaet^MQ@2q_u!(8*#1oCZld&6CgMZq`ruZ#cFNId~JEpx;n0 zovV?_D*dR9*3&4Pnb#ujq3%E&e)KuHTbJ#!QZJDcg|H%~u}hfP)5n)k2jn&5YBkYq z)^=hcm^a>X9(9q`l;QGiD#kkAa+^TD1^xBvo#yN@TtduuB zSI(CrdV7`2manMtNR!scwY8~H;W@ePy!--bnY@xDsT({{;8^4J%yL428V@A#!~a0P zwi6`JLv@5kI5w|=LaczqmY>QYE4T6fCJ3sICCaOpvOWbyL+saIvZ1AkfoIaOP(T_S zE{}s65)9TlLeEh?%zVRd0rWqJxXN>R00Z()Y;eUHgV25L>6nQxgjN9jWx$FTH9(P- zfP}xnG5(jc@jKBwHq=4E{G)B}FeO0YSZ?3vL1`?$5*Wh%*tD|!<19NF2QXjlrS_s45b62e+N2BDD0d%=oO>-1akWPgNtpO-bTm7f$aNV!PeIqNQA?G z6Fs*@!FrhfyAt1iEWQWu`;>r}VfkD0Egn6efA)LnKP2fsJQPp=jZX7lC`*4|0P^T? z^luZ+kM;N0qhLMkLcjgUdx9vR%BJTH5vHekPn7@pSxH)q^0!Cf@S%X|%1@7f6maXy ztYK^&m1qOrO3wZ=!2STWv88_w{;F(%1Rx3VFdHdFLrQ?!xZ{v5kc!_^kI@@XVeh{L zFwZHiKN0YG8{Pla_vGp4%a{5dYMAA#vW~13A6^!C?*i{V%iJ&R^VeWXmh%?9V-?=zqOPF)$ec`=xLZ#(pw~ z#EUcc9}dHY{vN=Az+w=9&kW~MjkU>^q9OHR32`h7GF?!`~dkw8`QvV?nH3apFzyi2oW8Fh^l0o%W z^pi=1_hXasH}o9;OCj1`2TiObzBTQ=4hnfMZZeLk-hcapzMnQEh$4DAs78IKXr6HZ zLRnJ(Ur>XXtZoWtHI^qh9-H6=B=EmX9q8(oOg@{fgwrxMyUv!aoGi2)dTnZeqWQaE z!I);V9@g!^R*<7GmIGYW@<3vJq8kND`GL0EL6VXMq376q*0B&dl!Tt6VHA3f@{Pgz zF*+e;wSoz<)|V+V7JX51K8d%&tZBy?R64}y&_4h$szIkmHRvS04fG+Ji}OD=n|qXi z1$lcEOaEhEeSIkB4)JLC+=9>l!)~+do4O5n-R&UAxtP)9LEVU{d-rtMft-d0<0WVJ zbP(~@Q$w%3Kw|0>SpCot1bszmS=&g>pf=GNjQ4Z&Nqg!d>SQ<#@J>u)kvYM6D`$4u z0*`B#o;eV4(Y#;@jIVmIz0$5@WlO?LXzi|M6 zV@ohnNA+{N7}4GYL3Q5k!u5B8ARULA6Z}t6=lvj1ypzv7BAE=cxI}001U9r0S*l#g zELD!~{{Rig90~rCS`d=x5J~PUq$HTrdDq@-==x9U1Sa`|2wt}KP9$i}Ot-b~ z3a8}p4;a$>pF|kPU|7TTJX^jxgjH0Ohs{)0fd002rRx)-n8gN%H6Dt_CW1?FZgh73 zKAZY5b;~VQyPgHd)-1mjbnU#}AE13Nr@XzTxF>$v9O!El zm{D!XpFadE#^>WMn{=yhwvM%!fEjm5Ego1fpfCp0f7-tBw>-0d&a0+Ha+|<&(`j(A z(%;rqf@&xuffG>Z4t-9!Vn9{c;!{ewL^TH=BfcYhm-Cqzp72k^Qe#VNCYPVpCD4OHO%YdtsWLussg{hwi45y`t$&-;9R zFW84@3W)AQ`u1{6WP7<@&q}USS?_kSd4=Yn z>7X#pLDc6t`w?(}d7Oz?b^#xi%hYf#lf}LnIQ6q;qpNxtuOj!;7Hv4<(Iv5nBsTLn zRfudPDEq)u1DJz!u|(8R|Cf@z!SSovAKue`(>3no;78Y8dK1nG{3j;UAp!1faZXT% z3vW#=!|BIywalrM^$B}r!X;sO>3ilB44C)gvLHFn`PfVKz_1kPPuKVT9$Oc zcnvB~zqkS!B-au*ffszQ;%F$pPlcU1Ib}YWmiO`p-#-4{QLw|_`4kQB$7bXqYX~$V zCoPfElnoqFcbmu7yTIs zVU@YNfYl=wcL(7f9LefAl6~hXC7c4{7Dm3FeaYzIzAbz5k5Oj@CbqrtB?1?6-YBp+ zj=2xm`1dD=icbXBMPXlzE{fep2(CLz&n3!!Y-B(b*5L*O5oMUgI}tn*A=DZ~5`_9T zZQ#3b8_=y-OdE`jWKBKw8`|LN=r)L|_X*62yxttQF!jj*qj#L>DDp)vUtdG~&8;`3 zd;i{g)3vhU=Gh_nI5Z{}X}1#PdivXu5u>{aMhW42)Kzw(`3h=1d3qEvCjovhZee(g zC!stVQAKBQwTCGInMnP#<6`Z8F>6AH-ngtEe||n1CNeb<)*)cIDpDS2g$XTNdk3;U zU&offOvVs(FYS24!~eZ}y|ZOlEh-WQN*)i;=Myn4(SeK}s}2 z6++&WnBfr|gG2C9vF+kD%vJ`|^7{f+2V-XGlx$>)fA(xPFEjZHpPkI8RwQjHOMWlk zqR#+O49093cN}xrv0{rD`|n{OzIQZehua2!XK%^7G*z45s~CJQ?gZjtcH|RwYO4!9 zWA0f~t1Gi5>wqae^L;pT4q;zz$_OO{zjweL%9tO#a&8dn1J2gWYvd%Jpw*Qwk3igb z1mh%NZcvMnOK3YW6WxNZB>C1YW%kXZ-DLUe)X@W`Yl5Z&rZl(GkMpRO>*nkwWor_C zefS{y&=&TWH19{@^TrS7U`976TIRuqFUYR0@1+bi4v0T%aWN4jj|Zwn|3trI}we7?m%e zJwU>lBki>L{gV))a+3iaf zb^aW>uvF(?u@OxAcx!^wsJ`7B=_csh`oj0!7^PdJeI9A`x~5hP$c{zYN|p^|j^wMu zRXJZ<+B!yp2)J&7gbXfp*j-&%Itudpu)pT1S--+lU&9|?C`+xHU!zAtm|oeRf4Qe*}&VY2WVy(!bpF6 zHFS9G;{M)_n`?YHRy7zT)jxKpRtC=<9yK@K)1{dwhQJ!!K!4=Xr*fgjX@fa(y3ZCS zu@7w%d3-kh%BNEy5>MrqZh@%;lA`clgeb7rGP7HbQ+f-7 zadYI)qU4l_9gWyq*~P{)xqz38g@F~p@HTS0D_(9aCC0GfJ766#;DxaiGPCloxFcjX zP{_;)bhj}%#FuIi5no7Xj^}I`Cd6SGp}jPD1m{GV4{<^&0~(2+82r8gX=4J9 zU{YlWI!0VU%Fr%nRxRNnvTd$af|%=oQaTUP!Sn{j@}IIosPkS-^)m+CZd_Wr?LD|^ z22#N(J#lp3`s^5kL`hoVa2{WkdIx6z(Y99z&jipKM~S$moNF}%s&+=?iP=q}<*ow@ z{hbg)nuelCh0+WO6e3M(;11!jL%{@jhb1_A)xy&1dWcE*yBBK3nD8;5%y0S&iK9l{ zKSvt*O(6KvopZ6{Dz)HNo5s~W5S_Wwzi(k-(-+X-m+h;DYhDaGxL=})+-p|H1>Z!` zkO9fXgxUklF(Yxw;htPjnBHjrh##Du(@zrpAUeiwPi{I7o6djo_)j7I=#u>Wj#(QA z;xW{M31mrNm^vTma%yBxlPt3I-$iAETZ>zQzcI2>G=BM|IPX=@pfx%=o8t`b66&q6H}q+kUKE#x zj%4tTBJ->~#e+xzM0woktP1cUCT;Y`C6o%*O)NZJa2OjIcEw%7lTe*7@!%#1U40M8 zL=C~lFv${$tLs--FKmQ|o6z&$#=;dXPXZ}` z>e1fG*|b@w<0-wJvB%cc-}3FJ_ED$w&V_76#SxOUs5q)FwkQ?HAXcta^g-TDsW=X$ zNCm0}ixKC9x;Pn9%j#k$Tm`9%QJr5IXy^+y1LP8W_8KHhlmwd zv+Wh~T+C^yGA%?MPC)?#llZ7bDVjtE2cq6n^mmB2p?I=2K`HdH(B@<|tnW0RZM)OD z5;Bl&cUnT&)wLB`B;Hua3(PKc8C}32f2j4+c!(iYZ}3Vmt+k1|DdeAFd;q?6A$N&S z^q&TM+!X5`7ORqXW?f#ESzKVoXpui6Ekz`v$E>eKi_i}elO#Gnb|X}*4BlbEEBu2d zuOm24Xix;N1OTc@!Ak)Ed9Zrt%KpM{FKBER#Qz=QP~R0x8*t*Z^q)v484i*+gq08P z*tin7j3$4XWbXwE^THYeqZPI-umye>MjQSG z;wtbrGXDEZ^>A8OqrzQ!IM~zZ@GJH38)L&0_3+zc!@nSMQn}bxN99BP40j)N8$HxdN}63mG-rAq{=;A9t{^!RK!O4R??PlzfNw7GrrtSv#=|UlGi7`(O1C1y1y$k zZbOjD()qiGGSAeFWKlD|da7PHEz zaxE3v^B1D$80?s=&ryT}#!sPMwmH`j$Tdf=>AZe{n@w!9fB4UkfG=>(pt9heW(55z z2Wjuu9UP&2W?})%V$1@q2LypYJv!nT#qlzg5lje}FIM0@el8ZLli^bMy37_&@7O@$ zP;2I=@+jN$IffS*=E?UeV-@SYV#=rah~Z>~tr=KlkP{baGM4QAKTySrErBINt*%ey z1o)yXH3ZX0P}19c-=g58uUz5VBCwB<1J8RVwfNP*u|(^9|t-I69euc zrCYSum);v;w&03Dk?}=TPCERNYYd}AoPQt1gz&*W6AMA}49h%S4?%28Fq7tNi4j>y{VMXrzd&3z{zk?Fv;DWMjvM_u zZ?^|s=cSmRSP!}x@>0x!I2c3=XJF;wBj{^)|JC?{f0XBP*o|IWcj3YGBuzvNM`1fi z$?&E}`OK6028qZ+ zdCKdK3}4O*F&z=iq;*gNxR?$>%D^l(m%~DdUC5O`21UF6_dz_!;u^4hM+7ym{A_R- z6FBv#+1Qx&P-q&G(dIt0*9#3fD2*+I5H5~g$TF1$J_u2NESA!*6Hj^`*7fyQ`^@5M09*Z8YdJM{;8Jwb+6<~W8yfnk_>w_TBsL9m##BiOYH zHzxXuo-xt^KZii(HM`zV1oOKk6+46_$cn`L9C< zXDR64o4W57+per6(;WEdAC(Ta@KDPC>Fi~4{BU)Pe;&&nyphmR%QI+?QAH4w>}1y9B|tn zwE~?7ymtk->t40u7(8668|*6ha3~iR!?omolJCVok2)TT#Xv-$0?LH{& zN`Z<#rDA8GLQ^Vsc%W=&YHXk%$-9=Shz3LR?ZNNsxI)3zg?0?~DbdVy1^WfHWW`Bf zLrRc;VsFP-!TZ&U0iZ|0zh}V$AGHEni?37ga1^ZyWC!~n0EQ@MH~P(NBMubX7{rAJ+kKPRySb71 zh15{=v$kEyjW{FCKY@9m(P%h>eGmmH728>WQt`A}u|2KgY3z)k?%jwESMe;=?Ed@3 zaOYmCR_w>A3k*+PslxqIr`eQ$0)L?$jP6%z%-mN8Tz7`#9dK<6K?c z8|tZ&cO_Gc&B`$~R**jlQzQI{kX#cT!J30JnTqbh93wPch;*~fnZ5NR$`>urLMW&I zT{L%$>grf@XZ^st-H)#*jf#I+f#eLM4+mMR1TQX!)Ap@<*$dbjv2B_`ROE_Dp`3K4PCr)7apF*UP|ZpI z@hK<(6EqpB)4l|4!7ebuY)2!k7e(j@)@iAowB4DVAxxEn9>|u%)ygUZwBNC_)EuvZ z2nCStWNcZ1TEMjDJSu6cGe!62xmaYH;e4F5-kaybMggQ;DTJo3K}=nx(0tFM-4YwA ziV0chik_fL3@$#dUZQTsNf-3N2ASzLIAOzyO#ANPqdSM{hj$>Kx=v%alk%}iV-G1*( zq*n&n!EwNW%VHiMx-uUry_oF=wWCZthi$*1**XN)bWnSi!mwAt9Ru2FES6^PSiY;g z8R#;Gu74{a4|&9fnjfTiJw4dkiJ1gTZClrA&}}{j2CcjE&B0~tTibeOG1R-z?@NOA zx>{oGI*rE6+}Dz;TJQ5jnUAsFmz}w9<6nZ`^Qegw?onXd;0^yiBNI!^+}AwHqe4BA zeX+U`*Y_z6uCUH6&Kv|gt+xX+wdLnl9_7(m9=5co+;Em(za4GFNuxKHjw&wp9kHm+ zxB#k`f%gJ}R2_z0fxxbSVMoe?=WXPbFZ?TwoPku|zLCFRvO3(Dqu$8BrZ6SBp89Eez4_HF+uo-LU}J{sdzAh znA7rJoEf&5#t?JmpOmL^k*M(-mtmlzAc8&Lc2;rcUsee$uVgu=L-!Su!+Ro4wRm+%F>D503 zBLSU9_uuH|t^YA#PW(Ib5sdnTrf<>;Q7n9q>rU3kBN*N*St-if%<(!aMEM}948$2` zenjs`ptja#L-ZahII#YSIh*y;Nv_Bp`OZM9e$-wm-<*f;SP#RVX)cFS?k8adV_yLm(C*dJ-TRWbU{i{gZMiKo~?*#J?X=BrX ztz`HJUCa$&574%fzj(-i$B4(=Ry-tSV|ZiXrBhQ_N`2;Mp-^=<4iU7s0P#+%n>e@A zR5XEqo$zxYcaDYgXM%(&Q_sf{u}P~y4va2hM(4Jf+0rCr3><6^LA(_$AyCL>TIg&8 zO(qw~cmnR~7S4qZFd3u4rrML%h~?iq_iU&!ydS?_b3=qr?9<73j52*L-ePv_6A%Nl z(@BrN3v4bp2hzqy%!Obedh+ICtb?E6Hl(1S2ZN2+%7S4-ydhY2Vw(1d%2eRl*1j)l zFGME_te)IhvF|#Xb*n)PWgiPx9%6=#F_WOKI|_V9f$u2r9RJ7db!>nJ+K@if-ecyaJFY{s=QlIByV zOr5UBX{@Z_-os;r*AYV$O8Km;^46|hS+j=alo?%GY`iLX@BVt6>!xH}&nrNA)xaJ3 zdKM|Bk~&HZ?`6x^u7jaQpq&vTd2-#9sTn%na4fq*=Jh`p^GMy`447qeE``z~_`un< z@SYxBFHkWm4tzwD%*xjh3S-S>TRh}unnjC2X~qkMFL)+h_}3vBNa<6$Gm4=Y8k%)t;D!@dW+G?zlafR-aP&g?6BTuI zzgDrRz6&?NtN9R^dM>?LtVvHx5f4Lj%lHB+ZF`RF=1@wpQ<77Z?sK9u0XtUJMOHc8pHcufA!r7G=U4 zcuj5Xg|Vl+R^R1?FK-5y84~nzAvKG$DzaB@Q+$jzw#i_i!*aqebWxT9v4_usoL!`drJf3d#_*@vqf}7TvbQlU4H-G-fF4hiutK{lg7Y%)b>y25H_U zu&4*UrX>6x!|(s}pM|MCMN;klU&wQ~1Ocw7e{>c3ui&{DxZq|}qIy!BdpxzWKB}Wf zncfX~zo_(jIU^d=p3!5q-n*h^E$gH)y(>I;SXqsgwVW3^e```4Z&lsunzeidj9G7H zgjrF&AL^s^!u>EZ$6SatBHcu(4~lB^Q2F16=jPYg#Fod@RcG+;pm}mJ`xn(<-+|vz z;5!QZQwq>{94} xK7~#4mj#_!>L}Cu3?Rtt;9O^+GlxSA-8ho^F8%KZfvIMfjr# zUnbxzz;}r_M-itHFqQQ*GHVs^APf*}5%9?|a2+OK2Tmb=D&XcUN&1C=7tV);SOFio zO_E*|aP107+ArY6Rgy%?Z&X(GJ(Bd6fVXePJS5;_5ET7Hz|Mdq4G4H4U>MQmcmk$n zhVtnIoG9SwkdwYhz|B99B+_K1IQIj-TEN=@lS~zb?*Z%*@Dady0zLt_SiokO_bwA~ zGGH>ZKxtjZp1)TwR~@OHq30^S4o76Bgte7k_HuSimr zfF}c9BjCk=8wBhHyivd>0dEm-dZ#2kEZ~O#ld9Z!31b29F9dvNmn4z3Hwr%vm<&e} zymg->y&~Xe0Ur=>AK+dA@9vf)vb<06r=tUZ4A?B-&!XV3M4aB&CCLcpg5qm{M+ulZ zJUQs3@Fc)#0xkhOUBC}Pt~Xb}LxATBIJ*~pPr$dofxZ_7uN1Hs;p+r^Ki~}lp82sP zwF~%mzySeo1N@MHcLIJ?z&ri~OVa|b{Y;Xc6>vLXQlljNcL07thrh(w6YxpEuL{_5 zN|N3ba1vlLRYPf$A%p&jfOn2ENS_H<13W0;LK?gvGAj%4FaaL~e35_$0FM*!qoWPd zL;<%u4AQj%J_?1I>jk_XJZ!drw*f8@F!8vH1$-xX-8%*RG~iWw{7a!}smBMrLBIzA z-z(rgz*_`72>1sAwvRJNKN0XGz)uRe1n@5fTn+d)0&WFNT544HZGiU)_;tXq33xpw zw6_Jk6>y(`j|1)(uwy)EE8vrW2LVH5Sz3%XN&rA`FYp{8;I~2lBmtWPm@@@Tbh}Ex z$1F3GB$Wzy0OO)kz<&ZBs|8%RNs@d5 zJ^=#~TLiox^YB9gruE`c0Uty7b^$k|Kl~CfG*cupdGWjmAH*rnUIEj(_Fp1SAL9H@ zgzsE0Nk>KaafE*)!l@tj3;6a~lJs{06K#hCyc_G?Fs!3^m9}D>UL;^E@`Rc?3!i+u zBwZ!o-B@rl1l-#oNwWYG&Kk-s6yf$ptla{(f}TqRd=h0<3V0jxsS$81=3!aDk3t5! zRlxTrLQg}$i?72xDd5d$$Dix*F?N0>U<=li=k@R=jB5cWUoJ_n113CA0MDZ$oaU20 z0Y9B9N&Nz*x#cqfCxiZH1-un~CLw{-BoB2TE#RZsm>UI5b9;^f*@;q^$zp{ul5z0;c)@ z7Xt1@9d`)08D+g7V45rT3-}?dYp)A#bEfHlfcI{tM2NCS17bB=Cc z=oArVEu~y#z%W}{#=W%J4^|E6^z3`j`JQ`^J-;~Td)nKj(k?8a(Yg(&rp^T~VX{Vx zDW+>WS!@$3sadsk=^rH&Epf(zWMfdx6&K>`{dwNsdx=St^X~I~ete$K@8`Ln^F5c1 z*P$EVGFBe-DpRa@>C_s-&sng>E-|+6_B(%$JkVJFYOnEk?<9XRR{nF)Sb5iHjraW{xr*^o zZ0AeHito?W{n^)7!CLn<);;I;)5N<=#`^u9ZyPTxru2Q|+tJ}48Xx&MIWLolSBhCT z87o%4*?2W}`c`A*V;hX8--z8AAHEx10waQ?uYLc9+t=K@D$N=z7VoIrpX7yL#s^Pf zYsRNb_ygu&N}Qt)x&6S$h^NL+v-iI-KJ|HWW8)l0>6L&7Cj4_@$+tf(>`(! z;|H;wSB%f!wkrM5_|zK4;Wx#TC2aqCW5u<##+Uy*rJpxGgYIoGo_Yu0rZ&F12On;{ z9b3EKcr|+X+s5l};{L>VKl1GxE3eySyyp#kN5*&xJ9^ys5c50<)*dT({y8vPNUP!7 z7v1M7dUf3GYiK`dd_DM#v0koo!TmQP$8Xel5r67F+v)Rtw@=-H&KYkfj{F2X60g=H z)9Z|to2@mz`mZVdqVdz5Wq!q2_hIig{t|Qky75uuyVZE@&BR(`LT~zA@z<2X?!?Xd}u-Q9^-lNC*5b?=9E5F_eTewG~U9P&l$heO6f1b;_ZFYe0|>ShoJ56 zjg=3dGoFUduN%LH&i|Y75#;!v;Lt;4^gXw)hCi#&Gx6;rxz=jq!+(sv8E@m+8;#GN zg@?vEi){pJk3;tLez$LdCm%50e;m4vPy8}I-1u#eq|`Om8K(kko{D)MaeMdo$#0F< zyiA^8tUJOl7+*Zg&tMxLfu7^W)6a1hFh0fnFBtzVw7qD2$0>Z2@glj?OU8Qt)62#O zx2E(1uxML=wjcYc%&YI*0)LEkUb_XXKKtnNR=3~Ce&1z$buaPG`0_FA(fCXke{QVT zdVSQmLLX+0m+&n+jJGh)g7J3Z&ZEZD?@8$~;|K48SH^GQy#I``^7*62i|p~Faa!a> zN5)5(|3%~0G&X3g{QQdX#ZBZ+#t%Nj-))Wey?s@B{k54tA0gJ-`KN1){@-VO^j}hX2rNE73ZHv!{|m{+Sa%nDjg@16(*5_-|I=>o za%rHqBx;@mv>$f+v0sBf##8u{FB|L3^%eJjg8t{+{^&=sHRJX0?LUkc@x$LUo^pQ8N{<3;cvxX*W>`Jl1xF8<6|=e}o*?^7H! z-UlE4&iK)vLMeChuf>zugi`pmbprUoY<8^<8zJWFWVdmfD_N(XNq49zHQ~IE>?so12tN&5@|CZZt zC#E-zbtm?Fb^niZr(rz*Eq?LHSm)5kjW3hqeAf6he0awABmc!2-1sT*NwC&E#=2+R zzJ#t`FxKC0zTrM6=yS#G!+qpbb)QA_&3#VM=bE3+eA~xa@;c+`_oei+#+T1?HZe&Sj5&3N^CUL9-v&;+4X&wr3#t#Z5WqaJtrTj+Dh?Yc8uG@km^l)h+u761RN@tyd_Q^wQq@nTf$yo?iM^YRb!RnWJPi%^8?WEZ*~eJ-u8q3SCeDdq@k+0`8@XNgT?@t+*zaEB zJ;anhG#;|wPZ=*g#tVFnt9N31VD04sd--d(--r)<*6kN*f8Om2@Z>AThmplU7+;k|8?X2e~OJ8uX_OA8XrR^uNptW-v8HF_jN!1Gnvn)(E01Y+Hbta%aV+4j*!t@g4u1(ua%>lhgjD@zfGLHQtDCnK#xw?a25N`m;#GyznQH$8JZtz;7&bk&hzSHK2<85zZrv05&O45*q%)~kye>9$3q?Tb#idJpKrJ7|g0IzFR(j?Y{oN0&^i>8Y#PvV2sphB!wf zHVXKEIy`PR$DLM8P!06BtTfA@-6}*Y|CKWLt5K(vCdGELg68rynmTjC(V*EY#-Uod zVr`J>k~Fc2(zFJHF@a@W8HOS)*IR{hsGN%Kxt;;Rs4!}fa_!R~xwc6(1oxtjiRMt8 zC`N)I%d86XV)Sxl5f5D)1oCUVSyeCR7O|=citVZHC#!1ctSfkEahZ-rMgeB^hU1<@5&{BPML_pzk+eI~w4X4I<(q=E^Sfl#|dqc5Vcjlg% z?WqyWh^E<5(QnT8VMu2@H!6nnY{xS&V9;&J$3{=UU|6Nby$^?kvZJSW}k^Gv0Wf zvLO+%_1ZZmqSb@=thZRSdfGyVitk+|!4LXz_%uM~sN@%pnF;NJlEz?XyDKfM zX&>)~OAXClb_FndbfKDzm`^%^JBn?z%5hUGv^sMgIK=IM%W4$}+PWaF09!knP0IiE#>?JsMY_}=MbKhP;o zO0?O1#G-_4xJiZrm7!t7N!6;*xaD0zYjZwmM5T#Ov+NdS@9h|?rkP2~YFLbU!Vrfz zWLJ#(SxI0XIZiRD<|VH1>-AF2HpJI^&2bq9%$Lm_3S|vi8c4YtEUq5TzD2*Kosq2R zUTZ;vEp{q&tRg>R74{HnwYwY-Mv_`1JU4T8=4P`3v^CybYN5kN|-0`Ga$}!tg|914K!Wm^kR2$tuWyLj$*wHpy6+RMfLGNVW^PH|IF1 z7lxG@Tg%;~)KJT>sTXjf}eIo8OWDzr1_;Yg11|5y$QLqv`$TeCGH0q-TJ9C?c> zhs|!Z)8@nh(c*qc6~ULIT76@|P(>YNh)ld73mZn+r9olGIE`^AarH23$E3sg5#|O* zRzmcQaDHY>*j19LhTbIEwJ1;i#1sCv*HudQ%o)gBg|Q7s;JRLiE%j1kD2ZE<5% zpjmB*Zj6ha43-C&fvXA&ipY&15=+GZnw1rvTu5$7{W#a@BWG`^@v%v#ta3bxQ1~NJ zavJ?X;-;=$=eLZF?<0gd@%AzuN1-UM9x+wUeNqij9oknoUx)b_^0qL%TJ%}_h{9-f z&IsE%9od>$mDBoIH^l#e*eL&x6F_QgBPS34Q;l}_6k}pp(~YK}_RDli`NXn>g)LOo z07oY`n`w$OUr5gxyrMl54Ch8zD%&di-GY;&G6>QbStvAwJygxss8Hn8DS26Au^T04 zq1JUI$kqG`b(mihWg&|V8$oIAj>UC0&AXLD+&t*@!bNt*lOf(hzJ@Q#MYxadI?)QC z%uwa{B=5jhCF)TB8BS)ih?iW7F zip&laP#8WLA-bT8jyWY($n8{9Vth`F*kyfgfL15m<6+T+zl_rLL~x0y&#ojm*((|x zaVLBLhaD0m@@Uc{QW>6M6SZ2k@gR|%$H7NSC=#M$vQWi4rk8&V=@2D5qflh)4dIV_ z6=#t7rh&mLz5}($2YVz{41>=)7)dp_l@R5qWUKahE910cs5LgNQHu5DC>w7!rN}Re zNZxX0p&-sN2gb`F`Ragulbmy2ugiK$XtMfg+7$e888Z8jIwe&)Vvnw8J-)hXX)6Xo-e)<0Z1%ujI literal 0 HcmV?d00001 diff --git a/gnu/usr.bin/rcs/rcsclean/rcsclean.0 b/gnu/usr.bin/rcs/rcsclean/rcsclean.0 new file mode 100644 index 0000000000..d17b4cd8c5 --- /dev/null +++ b/gnu/usr.bin/rcs/rcsclean/rcsclean.0 @@ -0,0 +1,132 @@ + + + +RCSCLEAN(1) RCSCLEAN(1) + + +NNAAMMEE + rcsclean - clean up working files + +SSYYNNOOPPSSIISS + rrccsscclleeaann [_o_p_t_i_o_n_s] [ _f_i_l_e ... ] + +DDEESSCCRRIIPPTTIIOONN + rrccsscclleeaann removes working files that were checked out and + never modified. For each _f_i_l_e given, rrccsscclleeaann compares + the working file and a revision in the corresponding RCS + file. If it finds a difference, it does nothing. Other- + wise, it first unlocks the revision if the --uu option is + given, and then removes the working file unless the work- + ing file is writable and the revision is locked. It logs + its actions by outputting the corresponding rrccss --uu and rrmm + --ff commands on the standard output. + + If no _f_i_l_e is given, all working files in the current + directory are cleaned. Pathnames matching an RCS suffix + denote RCS files; all others denote working files. Names + are paired as explained in ccii(1). + + The number of the revision to which the working file is + compared may be attached to any of the options --nn, --qq, --rr, + or --uu. If no revision number is specified, then if the --uu + option is given and the caller has one revision locked, + rrccsscclleeaann uses that revision; otherwise rrccsscclleeaann uses the + latest revision on the default branch, normally the root. + + rrccsscclleeaann is useful for cclleeaann targets in Makefiles. See + also rrccssddiiffff(1), which prints out the differences, and + ccii(1), which normally asks whether to check in a file if + it was not changed. + +OOPPTTIIOONNSS + --kk_s_u_b_s_t + Use _s_u_b_s_t style keyword substitution when retriev- + ing the revision for comparison. See ccoo(1) for + details. + + --nn[_r_e_v] + Do not actually remove any files or unlock any + revisions. Using this option will tell you what + rrccsscclleeaann would do without actually doing it. + + --qq[_r_e_v] + Do not log the actions taken on standard output. + + --rr[_r_e_v] + This option has no effect other than specifying the + revision for comparison. + + --uu[_r_e_v] + Unlock the revision if it is locked and no + + + +GNU 1991/11/03 1 + + + + + +RCSCLEAN(1) RCSCLEAN(1) + + + difference is found. + + --VV_n Emulate RCS version _n. See ccoo(1) for details. + + --xx_s_u_f_f_i_x_e_s + Use _s_u_f_f_i_x_e_s to characterize RCS files. See ccii(1) + for details. + +EEXXAAMMPPLLEESS + rrccsscclleeaann **..cc **..hh + + removes all working files ending in ..cc or ..hh that were not + changed since their checkout. + + rrccsscclleeaann + + removes all working files in the current directory that + were not changed since their checkout. + +FFIILLEESS + rrccsscclleeaann accesses files much as ccii(1) does. + +EENNVVIIRROONNMMEENNTT + RRCCSSIINNIITT + options prepended to the argument list, separated + by spaces. A backslash escapes spaces within an + option. The RRCCSSIINNIITT options are prepended to the + argument lists of most RCS commands. Useful + RRCCSSIINNIITT options include --qq, --VV, and --xx. + +DDIIAAGGNNOOSSTTIICCSS + The exit status is zero if and only if all operations were + successful. Missing working files and RCS files are + silently ignored. + +IIDDEENNTTIIFFIICCAATTIIOONN + Author: Walter F. Tichy. + Revision Number: 1.8; Release Date: 1991/11/03. + Copyright (C) 1982, 1988, 1989 by Walter F. Tichy. + Copyright (C) 1990, 1991 by Paul Eggert. + +SSEEEE AALLSSOO + ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), + rcsmerge(1), rlog(1), rcsfile(5) + Walter F. Tichy, RCS--A System for Version Control, + _S_o_f_t_w_a_r_e_-_-_P_r_a_c_t_i_c_e _& _E_x_p_e_r_i_e_n_c_e 1155, 7 (July 1985), + 637-654. + +BBUUGGSS + At least one _f_i_l_e must be given in older Unix versions + that do not provide the needed directory scanning opera- + tions. + + + + + +GNU 1991/11/03 2 + + diff --git a/gnu/usr.bin/rcs/rcsclean/rcsclean.1 b/gnu/usr.bin/rcs/rcsclean/rcsclean.1 new file mode 100644 index 0000000000..07ed7228b6 --- /dev/null +++ b/gnu/usr.bin/rcs/rcsclean/rcsclean.1 @@ -0,0 +1,177 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: rcsclean.1,v 1.8 1991/11/03 01:09:19 eggert Exp $ +.ds r \&\s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.TH RCSCLEAN 1 \*(Dt GNU +.SH NAME +rcsclean \- clean up working files +.SH SYNOPSIS +.B rcsclean +.RI [ options "] [ " file " .\|.\|. ]" +.SH DESCRIPTION +.B rcsclean +removes working files that were checked out and never modified. +For each +.I file +given, +.B rcsclean +compares the working file and a revision in the corresponding +\*r file. If it finds a difference, it does nothing. +Otherwise, it first unlocks the revision if the +.B \-u +option is given, +and then removes the working file +unless the working file is writable and the revision is locked. +It logs its actions by outputting the corresponding +.B "rcs \-u" +and +.B "rm \-f" +commands on the standard output. +.PP +If no +.I file +is given, all working files in the current directory are cleaned. +Pathnames matching an \*r suffix denote \*r files; +all others denote working files. +Names are paired as explained in +.BR ci (1). +.PP +The number of the revision to which the working file is compared +may be attached to any of the options +.BR \-n , +.BR \-q , +.BR \-r , +or +.BR \-u . +If no revision number is specified, then if the +.B \-u +option is given and the caller has one revision locked, +.B rcsclean +uses that revision; otherwise +.B rcsclean +uses the latest revision on the default branch, normally the root. +.PP +.B rcsclean +is useful for +.B clean +targets in Makefiles. +See also +.BR rcsdiff (1), +which prints out the differences, +and +.BR ci (1), +which +normally asks whether to check in a file +if it was not changed. +.SH OPTIONS +.TP +.BI \-k subst +Use +.I subst +style keyword substitution when retrieving the revision for comparison. +See +.BR co (1) +for details. +.TP +.BR \-n [\f2rev\fP] +Do not actually remove any files or unlock any revisions. +Using this option will tell you what +.B rcsclean +would do without actually doing it. +.TP +.BR \-q [\f2rev\fP] +Do not log the actions taken on standard output. +.TP +.BR \-r [\f2rev\fP] +This option has no effect other than specifying the revision for comparison. +.TP +.BR \-u [\f2rev\fP] +Unlock the revision if it is locked and no difference is found. +.TP +.BI \-V n +Emulate \*r version +.IR n . +See +.BR co (1) +for details. +.TP +.BI \-x "suffixes" +Use +.I suffixes +to characterize \*r files. +See +.BR ci (1) +for details. +.SH EXAMPLES +.LP +.RS +.ft 3 +rcsclean *.c *.h +.ft +.RE +.LP +removes all working files ending in +.B .c +or +.B .h +that were not changed +since their checkout. +.LP +.RS +.ft 3 +rcsclean +.ft +.RE +.LP +removes all working files in the current directory +that were not changed since their checkout. +.SH FILES +.B rcsclean +accesses files much as +.BR ci (1) +does. +.SH ENVIRONMENT +.TP +.B \s-1RCSINIT\s0 +options prepended to the argument list, separated by spaces. +A backslash escapes spaces within an option. +The +.B \s-1RCSINIT\s0 +options are prepended to the argument lists of most \*r commands. +Useful +.B \s-1RCSINIT\s0 +options include +.BR \-q , +.BR \-V , +and +.BR \-x . +.SH DIAGNOSTICS +The exit status is zero if and only if all operations were successful. +Missing working files and \*r files are silently ignored. +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH "SEE ALSO" +ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1), +rcsfile(5) +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. +.SH BUGS +At least one +.I file +must be given in older Unix versions that +do not provide the needed directory scanning operations. +.br diff --git a/gnu/usr.bin/rcs/rcsclean/rcsclean.c b/gnu/usr.bin/rcs/rcsclean/rcsclean.c new file mode 100644 index 0000000000..ba24ab77e0 --- /dev/null +++ b/gnu/usr.bin/rcs/rcsclean/rcsclean.c @@ -0,0 +1,297 @@ +/* rcsclean - clean up working files */ + +/* Copyright 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + +#include "rcsbase.h" + +#if has_dirent + static int get_directory P((char const*,char***)); +#endif + +static int unlock P((struct hshentry *)); +static void cleanup P((void)); + +static RILE *workptr; +static int exitstatus; + +mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 eggert Exp $") +{ + static char const usage[] = + "\nrcsclean: usage: rcsclean [-ksubst] [-{nqru}[rev]] [-Vn] [-xsuffixes] [file ...]"; + + static struct buf revision; + + char *a, **newargv; + char const *rev, *p; + int changelock, expmode, perform, unlocked, unlockflag, waslocked; + struct hshentries *deltas; + struct hshentry *delta; + struct stat workstat; + + setrid(); + + expmode = -1; + rev = nil; + suffixes = X_DEFAULT; + perform = true; + unlockflag = false; + + argc = getRCSINIT(argc, argv, &newargv); + argv = newargv; + for (;;) { + if (--argc <= 0) { +# if has_dirent + argc = get_directory(".", &newargv); + argv = newargv; + break; +# else + faterror("no file names specified"); +# endif + } + a = *++argv; + if (*a++ != '-') + break; + switch (*a++) { + case 'k': + if (0 <= expmode) + redefined('k'); + if ((expmode = str2expmode(a)) < 0) + goto unknown; + break; + + case 'n': + perform = false; + goto handle_revision; + + case 'q': + quietflag = true; + /* fall into */ + case 'r': + handle_revision: + if (*a) { + if (rev) + warn("redefinition of revision number"); + rev = a; + } + break; + + case 'u': + unlockflag = true; + goto handle_revision; + + case 'V': + setRCSversion(*argv); + break; + + case 'x': + suffixes = a; + break; + + default: + unknown: + faterror("unknown option: %s%s", *argv, usage); + } + } + + do { + ffree(); + + if (!( + 0 < pairfilenames( + argc, argv, + unlockflag&perform ? rcswriteopen : rcsreadopen, + true, true + ) && + (workptr = Iopen(workfilename,FOPEN_R_WORK,&workstat)) + )) + continue; + + gettree(); + + p = 0; + if (rev) { + if (!fexpandsym(rev, &revision, workptr)) + continue; + p = revision.string; + } else if (Head) + switch (unlockflag ? findlock(false,&delta) : 0) { + default: + continue; + case 0: + p = Dbranch ? Dbranch : ""; + break; + case 1: + p = delta->num; + break; + } + delta = 0; + deltas = 0; /* Keep lint happy. */ + if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas))) + continue; + + waslocked = delta && delta->lockedby; + locker_expansion = unlock(delta); + unlocked = locker_expansion & unlockflag; + changelock = unlocked & perform; + if (unlockednum, RCSfilename); + + if_advise_access(changelock && deltas->first != delta, + finptr, MADV_SEQUENTIAL + ); + if (!donerewrite(changelock)) + continue; + + if (!quietflag) + aprintf(stdout, "rm -f %s\n", workfilename); + Izclose(&workptr); + if (perform && un_link(workfilename) != 0) + eerror(workfilename); + + } while (cleanup(), ++argv, 0 < --argc); + + tempunlink(); + if (!quietflag) + Ofclose(stdout); + exitmain(exitstatus); +} + + static void +cleanup() +{ + if (nerror) exitstatus = EXIT_FAILURE; + Izclose(&finptr); + Izclose(&workptr); + Ozclose(&fcopy); + Ozclose(&frewrite); + dirtempunlink(); +} + +#if lint +# define exiterr rcscleanExit +#endif + exiting void +exiterr() +{ + dirtempunlink(); + tempunlink(); + _exit(EXIT_FAILURE); +} + + static int +unlock(delta) + struct hshentry *delta; +{ + register struct lock **al, *l; + + if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0) + for (al = &Locks; (l = *al); al = &l->nextlock) + if (l->delta == delta) { + *al = l->nextlock; + delta->lockedby = 0; + return true; + } + return false; +} + +#if has_dirent + static int +get_directory(dirname, aargv) + char const *dirname; + char ***aargv; +/* + * Put a vector of all DIRNAME's directory entries names into *AARGV. + * Ignore names of RCS files. + * Yield the number of entries found. Terminate the vector with 0. + * Allocate the storage for the vector and entry names. + * Do not sort the names. Do not include '.' and '..'. + */ +{ + int i, entries = 0, entries_max = 64; + size_t chars = 0, chars_max = 1024; + size_t *offset = tnalloc(size_t, entries_max); + char *a = tnalloc(char, chars_max), **p; + DIR *d; + struct dirent *e; + + if (!(d = opendir(dirname))) + efaterror(dirname); + while ((errno = 0, e = readdir(d))) { + char const *en = e->d_name; + size_t s = strlen(en) + 1; + if (en[0]=='.' && (!en[1] || en[1]=='.' && !en[2])) + continue; + if (rcssuffix(en)) + continue; + while (chars_max < s + chars) + a = trealloc(char, a, chars_max<<=1); + if (entries == entries_max) + offset = trealloc(size_t, offset, entries_max<<=1); + offset[entries++] = chars; + VOID strcpy(a+chars, en); + chars += s; + } + if (errno || closedir(d) != 0) + efaterror(dirname); + if (chars) + a = trealloc(char, a, chars); + else + tfree(a); + *aargv = p = tnalloc(char*, entries+1); + for (i=0; i diff --git a/gnu/usr.bin/rcs/rcsdiff/rcsdiff.1 b/gnu/usr.bin/rcs/rcsdiff/rcsdiff.1 new file mode 100644 index 0000000000..b78bbdd17c --- /dev/null +++ b/gnu/usr.bin/rcs/rcsdiff/rcsdiff.1 @@ -0,0 +1,152 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: rcsdiff.1,v 5.3 1991/04/21 12:00:46 eggert Exp $ +.ds r \&\s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.TH RCSDIFF 1 \*(Dt GNU +.SH NAME +rcsdiff \- compare RCS revisions +.SH SYNOPSIS +.B rcsdiff +[ +.BI \-k subst +] [ +.B \-q +] [ +.BI \-r rev1 +[ +.BI \-r rev2 +] ] [ +.BI \-V n +] [ +.BI \-x suffixes +] [ +.I "diff options" +] +.I "file .\|.\|." +.SH DESCRIPTION +.B rcsdiff +runs +.BR diff (1) +to compare two revisions of each \*r file given. +.PP +Pathnames matching an \*r suffix denote \*r files; +all others denote working files. +Names are paired as explained in +.BR ci (1). +.PP +The option +.B \-q +suppresses diagnostic output. +Zero, one, or two revisions may be specified with +.BR \-r . +The option +.BI \-k subst +affects keyword substitution when extracting +revisions, as described in +.BR co (1); +for example, +.B "\-kk\ \-r1.1\ \-r1.2" +ignores differences in keyword values when comparing revisions +.B 1.1 +and +.BR 1.2 . +To avoid excess output from locker name substitution, +.B \-kkvl +is assumed if (1) at most one revision option is given, +(2) no +.B \-k +option is given, (3) +.B \-kkv +is the default keyword substitution, and +(4) the working file's mode would be produced by +.BR "co\ \-l". +See +.BR co (1) +for details +about +.B \-V +and +.BR \-x . +Otherwise, all options of +.BR diff (1) +that apply to regular files are accepted, with the same meaning as for +.BR diff . +.PP +If both +.I rev1 +and +.I rev2 +are omitted, +.B rcsdiff +compares the latest revision on the +default branch (by default the trunk) +with the contents of the corresponding working file. This is useful +for determining what you changed since the last checkin. +.PP +If +.I rev1 +is given, but +.I rev2 +is omitted, +.B rcsdiff +compares revision +.I rev1 +of the \*r file with +the contents of the corresponding working file. +.PP +If both +.I rev1 +and +.I rev2 +are given, +.B rcsdiff +compares revisions +.I rev1 +and +.I rev2 +of the \*r file. +.PP +Both +.I rev1 +and +.I rev2 +may be given numerically or symbolically. +.SH EXAMPLE +The command +.LP +.B " rcsdiff f.c" +.LP +compares the latest revision on the default branch of the \*r file +to the contents of the working file +.BR f.c . +.SH ENVIRONMENT +.TP +.B \s-1RCSINIT\s0 +options prepended to the argument list, separated by spaces. +See +.BR ci (1) +for details. +.SH DIAGNOSTICS +Exit status is 0 for no differences during any comparison, +1 for some differences, 2 for trouble. +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH "SEE ALSO" +ci(1), co(1), diff(1), ident(1), rcs(1), rcsintro(1), rcsmerge(1), rlog(1) +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. +.br diff --git a/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c b/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c new file mode 100644 index 0000000000..7155c8d89b --- /dev/null +++ b/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c @@ -0,0 +1,422 @@ +/* + * RCS rcsdiff operation + */ +/***************************************************************************** + * generate difference between RCS revisions + ***************************************************************************** + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + + +/* $Log: rcsdiff.c,v $ + * Revision 5.10 1991/10/07 17:32:46 eggert + * Remove lint. + * + * Revision 5.9 1991/08/19 03:13:55 eggert + * Add RCSINIT, -r$. Tune. + * + * Revision 5.8 1991/04/21 11:58:21 eggert + * Add -x, RCSINIT, MS-DOS support. + * + * Revision 5.7 1990/12/13 06:54:07 eggert + * GNU diff 1.15 has -u. + * + * Revision 5.6 1990/11/01 05:03:39 eggert + * Remove unneeded setid check. + * + * Revision 5.5 1990/10/04 06:30:19 eggert + * Accumulate exit status across files. + * + * Revision 5.4 1990/09/27 01:31:43 eggert + * Yield 1, not EXIT_FAILURE, when diffs are found. + * + * Revision 5.3 1990/09/11 02:41:11 eggert + * Simplify -kkvl test. + * + * Revision 5.2 1990/09/04 17:07:19 eggert + * Diff's argv was too small by 1. + * + * Revision 5.1 1990/08/29 07:13:55 eggert + * Add -kkvl. + * + * Revision 5.0 1990/08/22 08:12:46 eggert + * Add -k, -V. Don't use access(). Add setuid support. + * Remove compile-time limits; use malloc instead. + * Don't pass arguments with leading '+' to diff; GNU DIFF treats them as options. + * Add GNU diff's flags. Make lock and temp files faster and safer. + * Ansify and Posixate. + * + * Revision 4.6 89/05/01 15:12:27 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.5 88/08/09 19:12:41 eggert + * Use execv(), not system(); yield exit status like diff(1)s; allow cc -R. + * + * Revision 4.4 87/12/18 11:37:46 narten + * changes Jay Lepreau made in the 4.3 BSD version, to add support for + * "-i", "-w", and "-t" flags and to permit flags to be bundled together, + * merged in. + * + * Revision 4.3 87/10/18 10:31:42 narten + * Updating version numbers. Changes relative to 1.1 actually + * relative to 4.1 + * + * Revision 1.3 87/09/24 13:59:21 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:15 jenkins + * Port to suns + * + * Revision 4.1 83/05/03 22:13:19 wft + * Added default branch, option -q, exit status like diff. + * Added fterror() to replace faterror(). + * + * Revision 3.6 83/01/15 17:52:40 wft + * Expanded mainprogram to handle multiple RCS files. + * + * Revision 3.5 83/01/06 09:33:45 wft + * Fixed passing of -c (context) option to diff. + * + * Revision 3.4 82/12/24 15:28:38 wft + * Added call to catchsig(). + * + * Revision 3.3 82/12/10 16:08:17 wft + * Corrected checking of return code from diff; improved error msgs. + * + * Revision 3.2 82/12/04 13:20:09 wft + * replaced getdelta() with gettree(). Changed diagnostics. + * + * Revision 3.1 82/11/28 19:25:04 wft + * Initial revision. + * + */ +#include "rcsbase.h" + +#if DIFF_L +static char const *setup_label P((struct buf*,char const*,char const[datesize])); +#endif +static void cleanup P((void)); + +static int exitstatus; +static RILE *workptr; +static struct stat workstat; + +mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert Exp $") +{ + static char const cmdusage[] = + "\nrcsdiff usage: rcsdiff [-q] [-rrev1 [-rrev2]] [-Vn] [diff options] file ..."; + + int revnums; /* counter for revision numbers given */ + char const *rev1, *rev2; /* revision numbers from command line */ + char const *xrev1, *xrev2; /* expanded revision numbers */ + char const *expandarg, *lexpandarg, *versionarg; +#if DIFF_L + static struct buf labelbuf[2]; + int file_labels; + char const **diff_label1, **diff_label2; + char date2[datesize]; +#endif + char const *cov[9]; + char const **diffv, **diffp; /* argv for subsidiary diff */ + char const **pp, *p, *diffvstr; + struct buf commarg; + struct buf numericrev; /* expanded revision number */ + struct hshentries *gendeltas; /* deltas to be generated */ + struct hshentry * target; + char *a, *dcp, **newargv; + register c; + + exitstatus = DIFF_SUCCESS; + + bufautobegin(&commarg); + bufautobegin(&numericrev); + revnums = 0; + rev1 = rev2 = xrev2 = nil; +#if DIFF_L + file_labels = 0; +#endif + expandarg = versionarg = 0; + suffixes = X_DEFAULT; + + /* Room for args + 2 i/o [+ 2 labels] + 1 file + 1 trailing null. */ + diffp = diffv = tnalloc(char const*, argc + 4 + 2*DIFF_L); + *diffp++ = nil; + *diffp++ = nil; + *diffp++ = DIFF; + + argc = getRCSINIT(argc, argv, &newargv); + argv = newargv; + while (a = *++argv, 0<--argc && *a++=='-') { + dcp = a; + while (c = *a++) switch (c) { + case 'r': + switch (++revnums) { + case 1: rev1=a; break; + case 2: rev2=a; break; + default: faterror("too many revision numbers"); + } + goto option_handled; +#if DIFF_L + case 'L': + if (++file_labels == 2) + faterror("too many -L options"); + /* fall into */ +#endif + case 'C': case 'D': case 'F': case 'I': + *dcp++ = c; + if (*a) + do *dcp++ = *a++; + while (*a); + else { + if (!--argc) + faterror("-%c needs following argument%s", + c, cmdusage + ); + *diffp++ = *argv++; + } + break; + case 'B': case 'H': case 'T': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'h': case 'i': case 'n': case 'p': + case 't': case 'u': case 'w': + *dcp++ = c; + break; + case 'q': + quietflag=true; + break; + case 'x': + suffixes = *argv + 2; + goto option_handled; + case 'V': + versionarg = *argv; + setRCSversion(versionarg); + goto option_handled; + case 'k': + expandarg = *argv; + if (0 <= str2expmode(expandarg+2)) + goto option_handled; + /* fall into */ + default: + faterror("unknown option: %s%s", *argv, cmdusage); + }; + option_handled: + if (dcp != *argv+1) { + *dcp = 0; + *diffp++ = *argv; + } + } /* end of option processing */ + + if (argc<1) faterror("no input file%s", cmdusage); + + for (pp = diffv+3, c = 0; ppnum; + + if (!fexpandsym(rev1, &numericrev, workptr)) continue; + if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue; + xrev1=target->num; +#if DIFF_L + if (diff_label1) + *diff_label1 = setup_label(&labelbuf[0], target->num, target->date); +#endif + + lexpandarg = expandarg; + if (revnums==2) { + if (!fexpandsym( + *rev2 ? rev2 : Dbranch ? Dbranch : Head->num, + &numericrev, + workptr + )) + continue; + if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue; + xrev2=target->num; + } else if ( + target->lockedby + && !lexpandarg + && Expand == KEYVAL_EXPAND + && WORKMODE(RCSstat.st_mode,true) == workstat.st_mode + ) + lexpandarg = "-kkvl"; + Izclose(&workptr); +#if DIFF_L + if (diff_label2) + if (revnums == 2) + *diff_label2 = setup_label(&labelbuf[1], target->num, target->date); + else { + time2date(workstat.st_mtime, date2); + *diff_label2 = setup_label(&labelbuf[1], workfilename, date2); + } +#endif + + diagnose("retrieving revision %s\n", xrev1); + bufscpy(&commarg, "-p"); + bufscat(&commarg, xrev1); + + cov[1] = diffp[0] = maketemp(0); + pp = &cov[4]; + *pp++ = commarg.string; + if (lexpandarg) + *pp++ = lexpandarg; + if (versionarg) + *pp++ = versionarg; + *pp++ = RCSfilename; + *pp = 0; + + if (runv(cov)) { + error("co failed"); + continue; + } + if (!rev2) { + diffp[1] = workfilename; + if (workfilename[0] == '+') { + /* Some diffs have options with leading '+'. */ + char *dp = ftnalloc(char, strlen(workfilename)+3); + diffp[1] = dp; + *dp++ = '.'; + *dp++ = SLASH; + VOID strcpy(dp, workfilename); + } + } else { + diagnose("retrieving revision %s\n",xrev2); + bufscpy(&commarg, "-p"); + bufscat(&commarg, xrev2); + cov[1] = diffp[1] = maketemp(1); + cov[4] = commarg.string; + if (runv(cov)) { + error("co failed"); + continue; + } + } + if (!rev2) + diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workfilename); + else + diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2); + + switch (runv(diffv)) { + case DIFF_SUCCESS: + break; + case DIFF_FAILURE: + if (exitstatus == DIFF_SUCCESS) + exitstatus = DIFF_FAILURE; + break; + default: + error("diff failed"); + } + } while (cleanup(), + ++argv, --argc >=1); + + + tempunlink(); + exitmain(exitstatus); +} + + static void +cleanup() +{ + if (nerror) exitstatus = DIFF_TROUBLE; + Izclose(&finptr); + Izclose(&workptr); +} + +#if lint +# define exiterr rdiffExit +#endif + exiting void +exiterr() +{ + tempunlink(); + _exit(DIFF_TROUBLE); +} + +#if DIFF_L + static char const * +setup_label(b, name, date) + struct buf *b; + char const *name; + char const date[datesize]; +{ + char *p; + size_t l = strlen(name) + 3; + bufalloc(b, l+datesize); + p = b->string; + VOID sprintf(p, "-L%s\t", name); + VOID date2str(date, p+l); + return p; +} +#endif diff --git a/gnu/usr.bin/rcs/rcsfreeze/Makefile b/gnu/usr.bin/rcs/rcsfreeze/Makefile new file mode 100644 index 0000000000..825d4bffec --- /dev/null +++ b/gnu/usr.bin/rcs/rcsfreeze/Makefile @@ -0,0 +1,7 @@ +# Do nothing for the following +obj clean cleandir depend rcsfreeze all: + @echo No need to make $@ for rcsfreeze\; ignored + +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 diff --git a/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1 b/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1 new file mode 100644 index 0000000000..be669a9f2a --- /dev/null +++ b/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1 @@ -0,0 +1,68 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: rcsfreeze.1,v 4.4 1990/11/13 15:43:42 hammer Exp $ +.ds r \s-1RCS\s0 +.TH RCSFREEZE 1 \*(Dt GNU +.SH NAME +rcsfreeze \- freeze a configuration of sources checked in under RCS +.SH SYNOPSIS +.B rcsfreeze +.RI [ "name" ] +.SH DESCRIPTION +.B rcsfreeze +assigns a symbolic revision +number to a set of \*r files that form a valid configuration. +.PP +The idea is to run +.B rcsfreeze +each time a new version is checked +in. A unique symbolic name (\c +.BI C_ number, +where +.I number +is increased each time +.B rcsfreeze +is run) is then assigned to the most +recent revision of each \*r file of the main trunk. +.PP +An optional +.I name +argument to +.B rcsfreeze +gives a symbolic name to the configuration. +The unique identifier is still generated +and is listed in the log file but it will not appear as +part of the symbolic revision name in the actual \*r files. +.PP +A log message is requested from the user for future reference. +.PP +The shell script works only on all \*r files at one time. +All changed files must be checked in already. +Run +.IR rcsclean (1) +first and see whether any sources remain in the current directory. +.SH FILES +.TP +.B RCS/.rcsfreeze.ver +version number +.TP +.B RCS/.rcsfreeze.log +log messages, most recent first +.SH AUTHOR +Stephan v. Bechtolsheim +.SH "SEE ALSO" +co(1), rcs(1), rcsclean(1), rlog(1) +.SH BUGS +.B rcsfreeze +does not check whether any sources are checked out and modified. +.PP +Although both source file names and RCS file names are accepted, +they are not paired as usual with RCS commands. +.PP +Error checking is rudimentary. +.PP +.B rcsfreeze +is just an optional example shell script, and should not be taken too seriously. +See \s-1CVS\s0 for a more complete solution. diff --git a/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh b/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh new file mode 100644 index 0000000000..421997946b --- /dev/null +++ b/gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh @@ -0,0 +1,100 @@ +#! /bin/sh + +# rcsfreeze - assign a symbolic revision number to a configuration of RCS files + +# $Id: rcsfreeze.sh,v 4.4 1991/04/21 11:58:24 eggert Exp $ + +# The idea is to run rcsfreeze each time a new version is checked +# in. A unique symbolic revision number (C_[number], where number +# is increased each time rcsfreeze is run) is then assigned to the most +# recent revision of each RCS file of the main trunk. +# +# If the command is invoked with an argument, then this +# argument is used as the symbolic name to freeze a configuration. +# The unique identifier is still generated +# and is listed in the log file but it will not appear as +# part of the symbolic revision name in the actual RCS file. +# +# A log message is requested from the user which is saved for future +# references. +# +# The shell script works only on all RCS files at one time. +# It is important that all changed files are checked in (there are +# no precautions against any error in this respect). +# file names: +# {RCS/}.rcsfreeze.ver version number +# {RCS/}.rscfreeze.log log messages, most recent first + +PATH=/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin:/usr/ucb:$PATH +export PATH + +DATE=`date` || exit +# Check whether we have an RCS subdirectory, so we can have the right +# prefix for our paths. +if [ -d RCS ] +then RCSDIR=RCS/ +else RCSDIR= +fi + +# Version number stuff, log message file +VERSIONFILE=${RCSDIR}.rcsfreeze.ver +LOGFILE=${RCSDIR}.rcsfreeze.log +# Initialize, rcsfreeze never run before in the current directory +[ -r $VERSIONFILE ] || { echo 0 >$VERSIONFILE && >>$LOGFILE; } || exit + +# Get Version number, increase it, write back to file. +VERSIONNUMBER=`cat $VERSIONFILE` && +VERSIONNUMBER=`expr $VERSIONNUMBER + 1` && +echo $VERSIONNUMBER >$VERSIONFILE || exit + +# Symbolic Revision Number +SYMREV=C_$VERSIONNUMBER +# Allow the user to give a meaningful symbolic name to the revision. +SYMREVNAME=${1-$SYMREV} +echo >&2 "rcsfreeze: symbolic revision number computed: \"${SYMREV}\" +rcsfreeze: symbolic revision number used: \"${SYMREVNAME}\" +rcsfreeze: the two differ only when rcsfreeze invoked with argument +rcsfreeze: give log message, summarizing changes (end with EOF or single '.')" \ + || exit + +# Stamp the logfile. Because we order the logfile the most recent +# first we will have to save everything right now in a temporary file. +TMPLOG=/tmp/rcsfrz$$ +trap 'rm -f $TMPLOG; exit 1' 1 2 13 15 +# Now ask for a log message, continously add to the log file +( + echo "Version: $SYMREVNAME($SYMREV), Date: $DATE +-----------" || exit + while read MESS + do + case $MESS in + .) break + esac + echo " $MESS" || exit + done + echo "----------- +" && + cat $LOGFILE +) >$TMPLOG && + +# combine old and new logfiles +cp $TMPLOG $LOGFILE && +rm -f $TMPLOG || exit +trap 1 2 13 15 + +# Now the real work begins by assigning a symbolic revision number +# to each rcs file. Take the most recent version of the main trunk. + +status= + +for FILE in ${RCSDIR}* +do +# get the revision number of the most recent revision + HEAD=`rlog -h $FILE` && + REV=`echo "$HEAD" | sed -n 's/^head:[ ]*//p'` && +# assign symbolic name to it. + echo >&2 "rcsfreeze: $REV $FILE" && + rcs -q -n$SYMREVNAME:$REV $FILE || status=$? +done + +exit $status diff --git a/gnu/usr.bin/rcs/rcsmerge/Makefile b/gnu/usr.bin/rcs/rcsmerge/Makefile new file mode 100644 index 0000000000..0c1f643891 --- /dev/null +++ b/gnu/usr.bin/rcs/rcsmerge/Makefile @@ -0,0 +1,7 @@ +PROG= rcsmerge + +SRCS= rcsmerge.c +LDADD= -L${.CURDIR}/../lib/obj -lrcs +CFLAGS+= -I${.CURDIR}/../lib + +.include diff --git a/gnu/usr.bin/rcs/rcsmerge/rcsmerge.1 b/gnu/usr.bin/rcs/rcsmerge/rcsmerge.1 new file mode 100644 index 0000000000..82871b033b --- /dev/null +++ b/gnu/usr.bin/rcs/rcsmerge/rcsmerge.1 @@ -0,0 +1,140 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: rcsmerge.1,v 5.3 1991/08/19 03:13:55 eggert Exp $ +.ds r \&\s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.TH RCSMERGE 1 \*(Dt GNU +.SH NAME +rcsmerge \- merge RCS revisions +.SH SYNOPSIS +.B rcsmerge +.RI [ options ] " file" +.SH DESCRIPTION +.B rcsmerge +incorporates the changes between two revisions +of an \*r file into the corresponding working file. +.PP +Pathnames matching an \*r suffix denote \*r files; +all others denote working files. +Names are paired as explained in +.BR ci (1). +.PP +At least one revision must be specified with one of the options +described below, usually +.BR \-r . +At most two revisions may be specified. +If only one revision is specified, the latest +revision on the default branch (normally the highest branch on the trunk) +is assumed for the second revision. +Revisions may be specified numerically or symbolically. +.PP +.B rcsmerge +prints a warning if there are overlaps, and delimits +the overlapping regions as explained in +.BR merge (1). +The command is useful for incorporating changes into a checked-out revision. +.SH OPTIONS +.TP +.BI \-k subst +Use +.I subst +style keyword substitution. +See +.BR co (1) +for details. +For example, +.B "\-kk\ \-r1.1\ \-r1.2" +ignores differences in keyword values when merging the changes from +.B 1.1 +to +.BR 1.2 . +.TP +.BR \-p [\f2rev\fP] +Send the result to standard output instead of overwriting the working file. +.TP +.BR \-q [\f2rev\fP] +Run quietly; do not print diagnostics. +.TP +.BR \-r [\f2rev\fP] +Merge with respect to revision +.IR rev . +Here an empty +.I rev +stands for the latest revision on the default branch, normally the head. +.TP +.BI \-V n +Emulate \*r version +.IR n . +See +.BR co (1) +for details. +.TP +.BI \-x "suffixes" +Use +.I suffixes +to characterize \*r files. +See +.BR ci (1) +for details. +.SH EXAMPLES +Suppose you have released revision 2.8 of +.BR f.c . +Assume +furthermore that after you complete an unreleased revision 3.4, you receive +updates to release 2.8 from someone else. +To combine the updates to 2.8 and your changes between 2.8 and 3.4, +put the updates to 2.8 into file f.c and execute +.LP +.B " rcsmerge \-p \-r2.8 \-r3.4 f.c >f.merged.c" +.PP +Then examine +.BR f.merged.c . +Alternatively, if you want to save the updates to 2.8 in the \*r file, +check them in as revision 2.8.1.1 and execute +.BR "co \-j": +.LP +.B " ci \-r2.8.1.1 f.c" +.br +.B " co \-r3.4 \-j2.8:2.8.1.1 f.c" +.PP +As another example, the following command undoes the changes +between revision 2.4 and 2.8 in your currently checked out revision +in +.BR f.c . +.LP +.B " rcsmerge \-r2.8 \-r2.4 f.c" +.PP +Note the order of the arguments, and that +.B f.c +will be +overwritten. +.SH ENVIRONMENT +.TP +.B \s-1RCSINIT\s0 +options prepended to the argument list, separated by spaces. +See +.BR ci (1) +for details. +.SH DIAGNOSTICS +Exit status is 0 for no overlaps, 1 for some overlaps, 2 for trouble. +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH "SEE ALSO" +ci(1), co(1), ident(1), merge(1), rcs(1), rcsdiff(1), rcsintro(1), rlog(1), +rcsfile(5) +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. +.br diff --git a/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c b/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c new file mode 100644 index 0000000000..e5d4394527 --- /dev/null +++ b/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c @@ -0,0 +1,252 @@ +/* + * rcsmerge operation + */ +/***************************************************************************** + * join 2 revisions with respect to a third + ***************************************************************************** + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + +/* $Log: rcsmerge.c,v $ + * Revision 5.7 1991/11/20 17:58:09 eggert + * Don't Iopen(f, "r+"); it's not portable. + * + * Revision 5.6 1991/08/19 03:13:55 eggert + * Add -r$. Tune. + * + * Revision 5.5 1991/04/21 11:58:27 eggert + * Add -x, RCSINIT, MS-DOS support. + * + * Revision 5.4 1991/02/25 07:12:43 eggert + * Merging a revision to itself is no longer an error. + * + * Revision 5.3 1990/11/01 05:03:50 eggert + * Remove unneeded setid check. + * + * Revision 5.2 1990/09/04 08:02:28 eggert + * Check for I/O error when reading working file. + * + * Revision 5.1 1990/08/29 07:14:04 eggert + * Add -q. Pass -L options to merge. + * + * Revision 5.0 1990/08/22 08:13:41 eggert + * Propagate merge's exit status. + * Remove compile-time limits; use malloc instead. + * Make lock and temp files faster and safer. Ansify and Posixate. Add -V. + * Don't use access(). Tune. + * + * Revision 4.5 89/05/01 15:13:16 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.4 88/08/09 19:13:13 eggert + * Beware merging into a readonly file. + * Beware merging a revision to itself (no change). + * Use execv(), not system(); yield exit status like diff(1)'s. + * + * Revision 4.3 87/10/18 10:38:02 narten + * Updating version numbers. Changes relative to version 1.1 + * actually relative to 4.1 + * + * Revision 1.3 87/09/24 14:00:31 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:36 jenkins + * Port to suns + * + * Revision 4.1 83/03/28 11:14:57 wft + * Added handling of default branch. + * + * Revision 3.3 82/12/24 15:29:00 wft + * Added call to catchsig(). + * + * Revision 3.2 82/12/10 21:32:02 wft + * Replaced getdelta() with gettree(); improved error messages. + * + * Revision 3.1 82/11/28 19:27:44 wft + * Initial revision. + * + */ +#include "rcsbase.h" + +static char const co[] = CO; + +mainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 5.7 1991/11/20 17:58:09 eggert Exp $") +{ + static char const cmdusage[] = + "\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] [-p] [-Vn] file"; + static char const quietarg[] = "-q"; + + register int i; + char *a, **newargv; + char const *arg[3]; + char const *rev[2]; /*revision numbers*/ + char const *expandarg, *versionarg; + int tostdout; + int status; + RILE *workptr; + struct buf commarg; + struct buf numericrev; /* holds expanded revision number */ + struct hshentries *gendeltas; /* deltas to be generated */ + struct hshentry * target; + + bufautobegin(&commarg); + bufautobegin(&numericrev); + rev[0] = rev[1] = nil; + status = 0; /* Keep lint happy. */ + tostdout = false; + expandarg = versionarg = quietarg; /* i.e. a no-op */ + suffixes = X_DEFAULT; + + argc = getRCSINIT(argc, argv, &newargv); + argv = newargv; + while (a = *++argv, 0<--argc && *a++=='-') { + switch (*a++) { + case 'p': + tostdout=true; + goto revno; + + case 'q': + quietflag = true; + revno: + if (!*a) + break; + /* falls into -r */ + case 'r': + if (!rev[0]) + rev[0] = a; + else if (!rev[1]) + rev[1] = a; + else + faterror("too many revision numbers"); + break; + case 'x': + suffixes = a; + break; + case 'V': + versionarg = *argv; + setRCSversion(versionarg); + break; + + case 'k': + expandarg = *argv; + if (0 <= str2expmode(expandarg+2)) + break; + /* fall into */ + default: + faterror("unknown option: %s%s", *argv, cmdusage); + }; + } /* end of option processing */ + + if (argc<1) faterror("no input file%s", cmdusage); + if (!rev[0]) faterror("no base revision number given"); + + /* now handle all filenames */ + + if (0 < pairfilenames(argc, argv, rcsreadopen, true, false)) { + + if (argc>2 || (argc==2&&argv[1]!=nil)) + warn("too many arguments"); + diagnose("RCS file: %s\n", RCSfilename); + if (!(workptr = Iopen(workfilename, + FOPEN_R_WORK, + (struct stat*)0 + ))) + efaterror(workfilename); + + gettree(); /* reads in the delta tree */ + + if (Head==nil) faterror("no revisions present"); + + if (!*rev[0]) + rev[0] = Dbranch ? Dbranch : Head->num; + if (!fexpandsym(rev[0], &numericrev, workptr)) + goto end; + if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end; + rev[0] = target->num; + if (!rev[1] || !*rev[1]) + rev[1] = Dbranch ? Dbranch : Head->num; + if (!fexpandsym(rev[1], &numericrev, workptr)) + goto end; + if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end; + rev[1] = target->num; + + if (strcmp(rev[0],rev[1]) == 0) { + if (tostdout) { + FILE *o; +# if text_equals_binary_stdio || text_work_stdio + o = stdout; +# else + if (!(o=fdopen(STDOUT_FILENO,FOPEN_W_WORK))) + efaterror("stdout"); +# endif + fastcopy(workptr,o); + Ofclose(o); + } + goto end; + } + Izclose(&workptr); + + for (i=0; i<2; i++) { + diagnose("retrieving revision %s\n", rev[i]); + bufscpy(&commarg, "-p"); + bufscat(&commarg, rev[i]); + if (run( + (char*)0, + /* Do not collide with merger.c maketemp(). */ + arg[i+1] = maketemp(i+3), + co, quietarg, commarg.string, expandarg, + versionarg, RCSfilename, (char*)0 + )) + faterror("co failed"); + } + diagnose("Merging differences between %s and %s into %s%s\n", + rev[0], rev[1], workfilename, + tostdout?"; result to stdout":""); + + arg[0] = rev[0] = workfilename; + status = merge(tostdout, rev, arg); + } + +end: + Izclose(&workptr); + tempunlink(); + exitmain(nerror ? DIFF_TROUBLE : status); +} + +#if lint +# define exiterr rmergeExit +#endif + exiting void +exiterr() +{ + tempunlink(); + _exit(DIFF_TROUBLE); +} diff --git a/gnu/usr.bin/rcs/rcstest b/gnu/usr.bin/rcs/rcstest new file mode 100644 index 0000000000..e0b6c828f7 --- /dev/null +++ b/gnu/usr.bin/rcs/rcstest @@ -0,0 +1,397 @@ +#!/bin/sh + +# Test RCS's functions. +# The RCS commands are searched for in the PATH as usual; +# to test the working directory's commands, prepend . to your PATH. + +# Test RCS by creating files RCS/a.* and RCS/a.c. +# If all goes well, output nothing, and remove the temporary files. +# Otherwise, send a message to standard output. +# Exit status is 0 if OK, 1 if an RCS bug is found, and 2 if scaffolding fails. +# With the -v option, output more debugging info. + +# If diff outputs `No differences encountered' when comparing identical files, +# then rcstest may also output these noise lines; ignore them. + +# The current directory and ./RCS must be readable, writable, and searchable. + +# $Id: rcstest,v 5.8 1991/11/20 17:58:10 eggert Exp $ + + +# Copyright 1990, 1991 by Paul Eggert +# Distributed under license by the Free Software Foundation, Inc. +# +# This file is part of RCS. +# +# RCS is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# RCS is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RCS; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# +# Report problems and direct all questions to: +# +# rcs-bugs@cs.purdue.edu + +RCSINIT=-x +export RCSINIT + +SLASH=/ +RCSfile=RCS${SLASH}a.c +RCS_alt=RCS${SLASH}a.d +lockfile=RCS${SLASH}a._ + +case $1 in +-v) q=; set -x;; +'') q=-q;; +*) echo >&2 "$0: usage: $0 [-v]"; exit 2 +esac + +test -d RCS || { + echo >&2 "$0: RCS: not a directory; please \`mkdir RCS' first." + exit 1 +} + +rm -f a.* $RCSfile $RCS_alt $lockfile && +echo 1.1 >a.11 && +echo 1.1.1.1 >a.3x1 && +echo 1.2 >a.12 || { echo "#initialization failed"; exit 2; } + +case `diff -c a.11 a.3x1` in +*'! 1.1.1.1') + diff='diff -c';; +*) + echo "#warning: diff -c does not work, so diagnostics may be cryptic" + diff=diff +esac + +rcs -i -L -ta.11 $q a.c && +<$RCSfile || { + echo "#rcs -i -L failed; perhaps RCS is not properly installed." + exit 1 +} + +rlog a.c >/dev/null || { echo "#rlog failed on empty RCS file"; exit 1; } +rm -f $RCSfile || exit 2 + +cp a.11 a.c && +ci -ta.11 -mm $q a.c && +<$RCSfile && +rcs -L $q a.c || { echo "#ci+rcs -L failed"; exit 1; } +test ! -f a.c || { echo "#ci did not remove working file"; exit 1; } +for l in '' '-l' +do + co $l $q a.c && + test -f a.c || { echo '#co' $l did not create working file; exit 1; } + $diff a.11 a.c || { echo '#ci' followed by co $l is not a no-op; exit 1; } +done + +cp a.12 a.c && +ci -mm $q a.c && +co $q a.c && +$diff a.12 a.c || { echo "#ci+co failed"; exit 1; } + +co -r1.1 $q a.c && +$diff a.11 a.c || { echo "#can't retrieve first revision"; exit 1; } + +rm -f a.c && +cp a.3x1 a.c && +ci -r1.1.1 -mm $q a.c && +co -r1.1.1.1 $q a.c && +$diff a.3x1 a.c || { echo "#branches failed"; exit 1; } + +co -l $q a.c && +ci -f -mm $q a.c && +co -r1.3 $q a.c && +$diff a.12 a.c || { echo "#(co -l; ci -f) failed"; exit 1; } + +co -l $q a.c && +echo 1.4 >a.c && +ci -l -mm $q a.c && +echo error >a.c && +ci -mm $q a.c || { echo "#ci -l failed"; exit 1; } + +co -l $q a.c && +echo 1.5 >a.c && +ci -u -mm $q a.c && +a.c || exit 2 +ci -mm $q a.c 2>/dev/null && { echo "#ci -u didn't unlock the file"; exit 1; } + +rm -f a.c && +rcs -l $q a.c && +co -u $q a.c || { echo "#rcs -l + co -u failed"; exit 1; } +rm -f a.c && +echo error >a.c || exit 2 +ci -mm $q a.c 2>/dev/null && { echo "#co -u didn't unlock the file"; exit 1; } + +rm -f a.c && +cp a.11 a.c && +co -f $q a.c || { echo "#co -f failed"; exit 1; } +$diff a.11 a.c >/dev/null && { echo "#co -f had no effect"; exit 1; } + +co -p1.1 $q a.c >a.t && +$diff a.11 a.t || { echo "#co -p failed"; exit 1; } + +for n in n N +do + rm -f a.c && + co -l $q a.c && + echo $n >a.$n && + cp a.$n a.c && + ci -${n}n -mm $q a.c && + co -rn $q a.c && + $diff a.$n a.c || { echo "#ci -$n failed"; exit 1; } +done + +case $LOGNAME in +?*) me=$LOGNAME;; +*) + case $USER in + ?*) me=$USER;; + *) + me=`who am i` || exit 2 + me=`echo "$me" | sed -e 's/ .*//' -e 's/.*!//'` + case $me in + '') echo >&2 "$0: cannot deduce user name"; exit 2 + esac + esac +esac +date=`date -u 2>/dev/null` || +date=`TZ=GMT0 date 2>/dev/null` || +date=`TZ= date` || exit 2 +set $date +case $2 in +Jan) m=01;; Feb) m=02;; Mar) m=03;; Apr) m=04;; May) m=05;; Jun) m=06;; +Jul) m=07;; Aug) m=08;; Sep) m=09;; Oct) m=10;; Nov) m=11;; Dec) m=12;; +*) echo >&2 "$0: $2: unknown month name"; exit 2 +esac +case $3 in +?) d=0$3;; +*) d=$3 +esac +case $6 in +[0-9][0-9][0-9][0-9]*) D=$6/$m/$d;; +*) + case $5 in + [0-9][0-9][0-9][0-9]*) D=$5/$m/$d;; + *) echo >&2 "$0: bad date format: $date"; exit 2 + esac +esac +T=$4 +case $PWD in +'') PWD=`pwd` +esac && +co -l $q a.c && +sed 's/@/$/g' >a.kv <a.k && +sed -e 's/w s [$]/w s '"$me"' $/' -e 's/[$]Locker: /&'"$me/" a.kv >a.kvl && +sed -e '/^\$/!d' -e 's/\$$/: old $/' a.k >a.o && +sed -e 's/\$[^ ]*: //' -e 's/ \$//' a.kv >a.v && +cp a.o a.c && +ci -d"$date" -ss -ww -u2.1 -mm $q a.c && +$diff a.kv a.c || { echo "#keyword expansion failed"; exit 1; } +co -p -ko $q a.c >a.oo && +$diff a.o a.oo || { echo "#co -p -ko failed"; exit 1; } +cp a.kv a.o || exit 2 +rcs -o2.1 $q a.c && +rcs -l $q a.c && +ci -k -u $q a.c && +$diff a.kv a.c || { echo "#ci -k failed"; exit 1; } +sed '/^[^$]/d' a.kv >a.i && +ident a.c >a.i1 && +sed -e 1d -e 's/^[ ]*//' a.i1 >a.i2 && +$diff a.i a.i2 || { echo "#ident failed"; exit 1; } + +rcs -i $q a.c 2>/dev/null && { echo "#rcs -i permitted existing file"; exit 1; } + +co -l $q a.c && +echo 2.2 >a.c && +ci -mm $q a.c && +echo 1.1.1.2 >a.c && +rcs -l1.1.1 $q a.c && +ci -r1.1.1.2 -mm $q a.c && +rcs -b1.1.1 $q a.c && +test " `co -p $q a.c`" = ' 1.1.1.2' || { echo "#rcs -b1.1.1 failed"; exit 1; } +rcs -b $q a.c && +test " `co -p $q a.c`" = ' 2.2' || { echo "#rcs -b failed"; exit 1; } + +echo 2.3 >a.c || exit 2 +rcs -U $q a.c || { echo "#rcs -U failed"; exit 1; } +ci -mm $q a.c || { echo "#rcs -U didn't unset strict locking"; exit 1; } +rcs -L $q a.c || { echo "#rcs -L failed"; exit 1; } +echo error >a.c || exit 2 +ci -mm $q a.c 2>/dev/null && { echo "#ci retest failed"; exit 1; } + +rm -f a.c && +log0=`rlog -h a.c` && +co -l $q a.c && +ci -mm $q a.c && +log1=`rlog -h a.c` && +test " $log0" = " $log1" || { echo "#unchanged ci didn't revert"; exit 1; } + +rm -f a.c && +rcs -nN:1.1 $q a.c && +co -rN $q a.c && +$diff a.11 a.c || { echo "#rcs -n failed"; exit 1; } + +rcs -NN:2.1 $q a.c && +co -rN $q a.c && +$diff a.kv a.c || { echo "#rcs -N failed"; exit 1; } + +co -l $q a.c && +rcs -c':::' $q a.c && +echo '$''Log$' >a.c && +ci -u -mm $q a.c && +test " `sed '$!d' a.c`" = ' :::' || { echo "#rcs -c failed"; exit 1; } + +rcs -o2.2: $q a.c && +co $q a.c && +$diff a.kv a.c || { echo "#rcs -o failed"; exit 1; } + +rcsdiff -r1.1 -r2.1 $q a.c >a.0 +case $? in +1) ;; +*) echo "#rcsdiff bad status"; exit 1 +esac +diff a.11 a.kv >a.1 +$diff a.0 a.1 || { echo "#rcsdiff failed"; exit 1; } + +rcs -l2.1 $q a.c || { echo "#rcs -l2.1 failed"; exit 1; } +for i in k kv kvl o v +do + rm -f a.c && + cp a.$i a.c && + rcsdiff -k$i $q a.c || { echo "#rcsdiff -k$i failed"; exit 1; } +done +co -p1.1 -ko $q a.c >a.t && +$diff a.11 a.t || { echo "#co -p1.1 -ko failed"; exit 1; } +rcs -u2.1 $q a.c || { echo "#rcs -u2.1 failed"; exit 1; } + +rm -f a.c && +co -l $q a.c && +cat >a.c <<'EOF' +2.2 +a +b +c +d +EOF +test $? = 0 && +ci -l -mm $q a.c && +co -p2.2 $q a.c | sed -e s/2.2/2.3/ -e s/b/b1/ >a.c && +ci -l -mm $q a.c && +co -p2.2 $q a.c | sed -e s/2.2/new/ -e s/d/d1/ >a.c || exit 2 +cat >a.0 <<'EOF' +2.3 +a +b1 +c +d1 +EOF +cat >a.1 <<'EOF' +<<<<<<< a.c +new +======= +2.3 +>>>>>>> 2.3 +a +b1 +c +d1 +EOF +rcsmerge -r2.2 -r2.3 $q a.c +case $? in +0) + if $diff a.0 a.c >/dev/null + then echo "#warning: diff3 -E does not work, " \ + "so merge and rcsmerge ignore overlaps and suppress overlap lines." + else + $diff a.1 a.c || { echo "#rcsmerge failed (status 0)"; exit 1; } + echo "#warning: The diff3 lib program exit status ignores overlaps," \ + "so rcsmerge does not warn about overlap lines that it generates." + fi + ;; +1) + $diff a.1 a.c || { echo "#rcsmerge failed (status 1)"; exit 1; } + ;; +*) + echo "#rcsmerge bad status"; exit 1 +esac + +nl=' +' +{ + co -p $q a.c | tr "$nl" '\200' >a.24 && + cp a.24 a.c && + ciOut=`(ci -l -mm $q a.c 2>&1)` && + case $ciOut in + ?*) echo >&2 "$ciOut" + esac && + co -p $q a.c | tr '\200' "$nl" >a.c && + rcsdiff -r2.3 $q a.c >/dev/null && + + echo 2.5 >a.c && + ci -l -mm $q a.c && + cp a.24 a.c && + rcsdiff -r2.4 $q a.c >/dev/null +} || echo "#warning: Traditional diff is used, so RCS is limited to text files." + +rcs -u -o2.4: $q a.c || { echo "#rcs -u -o failed"; exit 1; } + +rcs -i -Aa.c -t- $q a.d || { echo "#rcs -i -A failed"; exit 1; } + +rlog -r2.1 a.c >a.t && +grep '^checked in with -k' a.t >/dev/null && +sed '/^checked in with -k/d' a.t >a.u && +$diff - a.u < diff --git a/gnu/usr.bin/rcs/rlog/rlog.1 b/gnu/usr.bin/rcs/rlog/rlog.1 new file mode 100644 index 0000000000..fa627ffdc1 --- /dev/null +++ b/gnu/usr.bin/rcs/rlog/rlog.1 @@ -0,0 +1,260 @@ +.de Id +.ds Rv \\$3 +.ds Dt \\$4 +.. +.Id $Id: rlog.1,v 5.3 1991/08/22 06:50:48 eggert Exp $ +.ds g \&\s-1UTC\s0 +.ds r \&\s-1RCS\s0 +.if n .ds - \%-- +.if t .ds - \(em +.TH RLOG 1 \*(Dt GNU +.SH NAME +rlog \- print log messages and other information about RCS files +.SH SYNOPSIS +.B rlog +.RI [ " options " ] " file " .\|.\|. +.SH DESCRIPTION +.B rlog +prints information about \*r files. +.PP +Pathnames matching an \*r suffix denote \*r files; +all others denote working files. +Names are paired as explained in +.BR ci (1). +.PP +.B rlog +prints the following information for each +\*r file: \*r pathname, working pathname, head (i.e., the number +of the latest revision on the trunk), default branch, access list, locks, +symbolic names, suffix, total number of revisions, +number of revisions selected for printing, and +descriptive text. This is followed by entries for the selected revisions in +reverse chronological order for each branch. For each revision, +.B rlog +prints revision number, author, date/time, state, number of +lines added/deleted (with respect to the previous revision), +locker of the revision (if any), and log message. +All times are displayed in Coordinated Universal Time (\*g). +Without options, +.B rlog +prints complete information. +The options below restrict this output. +.nr n \w'\f3\-V\fP\f2n\fP '+1n-1/1n +.TP \nn +.B \-L +Ignore \*r files that have no locks set. +This is convenient in combination with +.BR \-h , +.BR \-l , +and +.BR \-R . +.TP +.B \-R +Print only the name of the \*r file. +This is convenient for translating a +working pathname into an \*r pathname. +.TP +.B \-h +Print only the \*r pathname, working pathname, head, +default branch, access list, locks, +symbolic names, and suffix. +.TP +.B \-t +Print the same as +.BR \-h , +plus the descriptive text. +.TP +.B \-b +Print information about the revisions on the default branch, normally +the highest branch on the trunk. +.TP +.BI \-d "dates" +Print information about revisions with a checkin date/time in the ranges given by +the semicolon-separated list of +.IR dates . +A range of the form +.IB d1 < d2 +or +.IB d2 > d1 +selects the revisions that were deposited between +.I d1 +and +.I d2 +inclusive. +A range of the form +.BI < d +or +.IB d > +selects +all revisions dated +.I d +or earlier. +A range of the form +.IB d < +or +.BI > d +selects +all revisions dated +.I d +or later. +A range of the form +.I d +selects the single, latest revision dated +.I d +or earlier. +The date/time strings +.IR d , +.IR d1 , +and +.I d2 +are in the free format explained in +.BR co (1). +Quoting is normally necessary, especially for +.B < +and +.BR > . +Note that the separator is +a semicolon. +.TP +.BR \-l [\f2lockers\fP] +Print information about locked revisions only. +In addition, if the comma-separated list +.I lockers +of login names is given, +ignore all locks other than those held by the +.IR lockers . +For example, +.B "rlog\ \-L\ \-R\ \-lwft\ RCS/*" +prints the name of \*r files locked by the user +.BR wft . +.TP +.BR \-r [\f2revisions\fP] +prints information about revisions given in the comma-separated list +.I revisions +of revisions and ranges. +A range +.IB rev1 : rev2 +means revisions +.I rev1 +to +.I rev2 +on the same branch, +.BI : rev +means revisions from the beginning of the branch up to and including +.IR rev , +and +.IB rev : +means revisions starting with +.I rev +to the end of the branch containing +.IR rev . +An argument that is a branch means all +revisions on that branch. +A range of branches means all revisions +on the branches in that range. +A branch followed by a +.B .\& +means the latest revision in that branch. +A bare +.B \-r +with no +.I revisions +means the latest revision on the default branch, normally the trunk. +.TP +.BI \-s states +prints information about revisions whose state attributes match one of the +states given in the comma-separated list +.IR states . +.TP +.BR \-w [\f2logins\fP] +prints information about revisions checked in by users with +login names appearing in the comma-separated list +.IR logins . +If +.I logins +is omitted, the user's login is assumed. +.TP +.BI \-V n +Emulate \*r version +.I n +when generating logs. +See +.BR co (1) +for more. +.TP +.BI \-x "suffixes" +Use +.I suffixes +to characterize \*r files. +See +.BR ci (1) +for details. +.PP +.B rlog +prints the intersection of the revisions selected with +the options +.BR \-d , +.BR \-l , +.BR \-s , +and +.BR \-w , +intersected +with the union of the revisions selected by +.B \-b +and +.BR \-r . +.SH EXAMPLES +.LP +.nf +.B " rlog \-L \-R RCS/*" +.B " rlog \-L \-h RCS/*" +.B " rlog \-L \-l RCS/*" +.B " rlog RCS/*" +.fi +.LP +The first command prints the names of all \*r files in the subdirectory +.B RCS +that have locks. The second command prints the headers of those files, +and the third prints the headers plus the log messages of the locked revisions. +The last command prints complete information. +.SH ENVIRONMENT +.TP +.B \s-1RCSINIT\s0 +options prepended to the argument list, separated by spaces. +See +.BR ci (1) +for details. +.SH DIAGNOSTICS +The exit status is zero if and only if all operations were successful. +.SH IDENTIFICATION +Author: Walter F. Tichy. +.br +Revision Number: \*(Rv; Release Date: \*(Dt. +.br +Copyright \(co 1982, 1988, 1989 by Walter F. Tichy. +.br +Copyright \(co 1990, 1991 by Paul Eggert. +.SH "SEE ALSO" +ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), +rcsfile(5) +.br +Walter F. Tichy, +\*r\*-A System for Version Control, +.I "Software\*-Practice & Experience" +.BR 15 , +7 (July 1985), 637-654. +.SH BUGS +The separator for revision ranges in the +.B \-r +option used to be +.B \- +instead of +.BR : , +but this leads to confusion when symbolic names contain +.BR \- . +For backwards compatibility +.B "rlog \-r" +still supports the old +.B \- +separator, but it warns about this obsolete use. +.br diff --git a/gnu/usr.bin/rcs/rlog/rlog.c b/gnu/usr.bin/rcs/rlog/rlog.c new file mode 100644 index 0000000000..b18b0c97ce --- /dev/null +++ b/gnu/usr.bin/rcs/rlog/rlog.c @@ -0,0 +1,1204 @@ +/* + * RLOG operation + */ +/***************************************************************************** + * print contents of RCS files + ***************************************************************************** + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + + +/* $Log: rlog.c,v $ + * Revision 5.9 1991/09/17 19:07:40 eggert + * Getscript() didn't uncache partial lines. + * + * Revision 5.8 1991/08/19 03:13:55 eggert + * Revision separator is `:', not `-'. + * Check for missing and duplicate logs. Tune. + * Permit log messages that do not end in newline (including empty logs). + * + * Revision 5.7 1991/04/21 11:58:31 eggert + * Add -x, RCSINIT, MS-DOS support. + * + * Revision 5.6 1991/02/26 17:07:17 eggert + * Survive RCS files with missing logs. + * strsave -> str_save (DG/UX name clash) + * + * Revision 5.5 1990/11/01 05:03:55 eggert + * Permit arbitrary data in logs and comment leaders. + * + * Revision 5.4 1990/10/04 06:30:22 eggert + * Accumulate exit status across files. + * + * Revision 5.3 1990/09/11 02:41:16 eggert + * Plug memory leak. + * + * Revision 5.2 1990/09/04 08:02:33 eggert + * Count RCS lines better. + * + * Revision 5.0 1990/08/22 08:13:48 eggert + * Remove compile-time limits; use malloc instead. Add setuid support. + * Switch to GMT. + * Report dates in long form, to warn about dates past 1999/12/31. + * Change "added/del" message to make room for the longer dates. + * Don't generate trailing white space. Add -V. Ansify and Posixate. + * + * Revision 4.7 89/05/01 15:13:48 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.6 88/08/09 19:13:28 eggert + * Check for memory exhaustion; don't access freed storage. + * Shrink stdio code size; remove lint. + * + * Revision 4.5 87/12/18 11:46:38 narten + * more lint cleanups (Guy Harris) + * + * Revision 4.4 87/10/18 10:41:12 narten + * Updating version numbers + * Changes relative to 1.1 actually relative to 4.2 + * + * Revision 1.3 87/09/24 14:01:10 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:45 jenkins + * Port to suns + * + * Revision 4.2 83/12/05 09:18:09 wft + * changed rewriteflag to external. + * + * Revision 4.1 83/05/11 16:16:55 wft + * Added -b, updated getnumericrev() accordingly. + * Replaced getpwuid() with getcaller(). + * + * Revision 3.7 83/05/11 14:24:13 wft + * Added options -L and -R; + * Fixed selection bug with -l on multiple files. + * Fixed error on dates of the form -d'>date' (rewrote getdatepair()). + * + * Revision 3.6 82/12/24 15:57:53 wft + * shortened output format. + * + * Revision 3.5 82/12/08 21:45:26 wft + * removed call to checkaccesslist(); used DATEFORM to format all dates; + * removed unused variables. + * + * Revision 3.4 82/12/04 13:26:25 wft + * Replaced getdelta() with gettree(); removed updating of field lockedby. + * + * Revision 3.3 82/12/03 14:08:20 wft + * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE. + * Fixed printing of nil, removed printing of Suffix, + * added shortcut if no revisions are printed, disambiguated struct members. + * + * Revision 3.2 82/10/18 21:09:06 wft + * call to curdir replaced with getfullRCSname(), + * fixed call to getlogin(), cosmetic changes on output, + * changed conflicting long identifiers. + * + * Revision 3.1 82/10/13 16:07:56 wft + * fixed type of variables receiving from getc() (char -> int). + */ + + + +#include "rcsbase.h" + +struct lockers { /* lockers in locker option; stored */ + char const * login; /* lockerlist */ + struct lockers * lockerlink; + } ; + +struct stateattri { /* states in state option; stored in */ + char const * status; /* statelist */ + struct stateattri * nextstate; + } ; + +struct authors { /* login names in author option; */ + char const * login; /* stored in authorlist */ + struct authors * nextauthor; + } ; + +struct Revpairs{ /* revision or branch range in -r */ + unsigned numfld; /* option; stored in revlist */ + char const * strtrev; + char const * endrev; + struct Revpairs * rnext; + } ; + +struct Datepairs{ /* date range in -d option; stored in */ + char strtdate[datesize]; /* duelst and datelist */ + char enddate[datesize]; + struct Datepairs * dnext; + }; + +static char extractdelta P((struct hshentry const*)); +static int checkrevpair P((char const*,char const*)); +static struct hshentry const *readdeltalog P((void)); +static unsigned extdate P((struct hshentry*)); +static void cleanup P((void)); +static void exttree P((struct hshentry*)); +static void getauthor P((char*)); +static void getdatepair P((char*)); +static void getlocker P((char*)); +static void getnumericrev P((void)); +static void getrevpairs P((char*)); +static void getscript P((struct hshentry*)); +static void getstate P((char*)); +static void putabranch P((struct hshentry const*)); +static void putadelta P((struct hshentry const*,struct hshentry const*,int)); +static void putforest P((struct branchhead const*)); +static void putree P((struct hshentry const*)); +static void putrunk P((void)); +static void recentdate P((struct hshentry const*,struct Datepairs*)); +static void trunclocks P((void)); + +static char const *insDelFormat; +static int branchflag; /*set on -b */ +static int exitstatus; +static int lockflag; +static struct Datepairs *datelist, *duelst; +static struct Revpairs *revlist, *Revlst; +static struct authors *authorlist; +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 $") +{ + static char const cmdusage[] = + "\nrlog usage: rlog -{bhLRt} -ddates -l[lockers] -rrevs -sstates -w[logins] -Vn file ..."; + + register FILE *out; + char *a, **newargv; + struct Datepairs *currdate; + char const *accessListString, *accessFormat, *commentFormat; + char const *headFormat, *symbolFormat; + struct access const *curaccess; + struct assoc const *curassoc; + struct hshentry const *delta; + struct lock const *currlock; + int descflag, selectflag; + int onlylockflag; /* print only files with locks */ + int onlyRCSflag; /* print only RCS file name */ + unsigned revno; + + descflag = selectflag = true; + onlylockflag = onlyRCSflag = false; + out = stdout; + suffixes = X_DEFAULT; + + argc = getRCSINIT(argc, argv, &newargv); + argv = newargv; + while (a = *++argv, 0<--argc && *a++=='-') { + switch (*a++) { + + case 'L': + onlylockflag = true; + break; + + case 'R': + onlyRCSflag =true; + break; + + case 'l': + lockflag = true; + getlocker(a); + break; + + case 'b': + branchflag = true; + break; + + case 'r': + getrevpairs(a); + break; + + case 'd': + getdatepair(a); + break; + + case 's': + getstate(a); + break; + + case 'w': + getauthor(a); + break; + + case 'h': + descflag = false; + break; + + case 't': + selectflag = false; + break; + + case 'q': + /* This has no effect; it's here for consistency. */ + quietflag = true; + break; + + case 'x': + suffixes = a; + break; + + case 'V': + setRCSversion(*argv); + break; + + default: + faterror("unknown option: %s%s", *argv, cmdusage); + + }; + } /* end of option processing */ + + if (argc<1) faterror("no input file%s", cmdusage); + + if (! (descflag|selectflag)) { + warn("-t overrides -h."); + descflag = true; + } + + if (RCSversion < VERSION(5)) { + accessListString = "\naccess list: "; + accessFormat = " %s"; + commentFormat = "\ncomment leader: \""; + headFormat = "\nRCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: "; + insDelFormat = " lines added/del: %lu/%lu"; + symbolFormat = " %s: %s;"; + } else { + accessListString = "\naccess list:"; + accessFormat = "\n\t%s"; + commentFormat = "\ncomment leader: \""; + headFormat = "\nRCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s"; + insDelFormat = " lines: +%lu -%lu"; + symbolFormat = "\n\t%s: %s"; + } + + /* now handle all filenames */ + do { + ffree(); + + if (pairfilenames(argc, argv, rcsreadopen, true, false) <= 0) + continue; + + /* now RCSfilename contains the name of the RCS file, and finptr + * the file descriptor. Workfilename contains the name of the + * working file. + */ + + /* Keep only those locks given by -l. */ + if (lockflag) + trunclocks(); + + /* do nothing if -L is given and there are no locks*/ + if (onlylockflag && !Locks) + continue; + + if ( onlyRCSflag ) { + aprintf(out, "%s\n", RCSfilename); + continue; + } + /* print RCS filename , working filename and optional + administrative information */ + /* could use getfullRCSname() here, but that is very slow */ + aprintf(out, headFormat, RCSfilename, workfilename, + Head ? " " : "", Head ? Head->num : "", + Dbranch ? " " : "", Dbranch ? Dbranch : "", + StrictLocks ? " strict" : "" + ); + currlock = Locks; + while( currlock ) { + aprintf(out, symbolFormat, currlock->login, + currlock->delta->num); + currlock = currlock->nextlock; + } + if (StrictLocks && RCSversionlogin); + curaccess = curaccess->nextaccess; + } + + aputs("\nsymbolic names:", out); /* print symbolic names */ + for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc) + aprintf(out, symbolFormat, curassoc->symbol, curassoc->num); + aputs(commentFormat, out); + awrite(Comment.string, Comment.size, out); + aputs("\"\n", out); + if (VERSION(5)<=RCSversion || Expand != KEYVAL_EXPAND) + aprintf(out, "keyword substitution: %s\n", + expand_names[Expand] + ); + + gettree(); + + aprintf(out, "total revisions: %u", TotalDeltas); + + revno = 0; + + if (Head && selectflag & descflag) { + + getnumericrev(); /* get numeric revision or branch names */ + + exttree(Head); + + /* get most recently date of the dates pointed by duelst */ + currdate = duelst; + while( currdate) { + VOID sprintf(currdate->strtdate,DATEFORM,0,0,0,0,0,0); + recentdate(Head, currdate); + currdate = currdate->dnext; + } + + revno = extdate(Head); + + aprintf(out, ";\tselected revisions: %u", revno); + } + + afputc('\n',out); + if (descflag) { + aputs("description:\n", out); + getdesc(true); + } + if (revno) { + while (! (delta = readdeltalog())->selector || --revno) + ; + if (delta->next && countnumflds(delta->num)==2) + /* Read through delta->next to get its insertlns. */ + while (readdeltalog() != delta->next) + ; + putrunk(); + putree(Head); + } + aputs("=============================================================================\n",out); + } while (cleanup(), + ++argv, --argc >= 1); + Ofclose(out); + exitmain(exitstatus); +} + + static void +cleanup() +{ + if (nerror) exitstatus = EXIT_FAILURE; + Izclose(&finptr); +} + +#if lint +# define exiterr rlogExit +#endif + exiting void +exiterr() +{ + _exit(EXIT_FAILURE); +} + + + + static void +putrunk() +/* function: print revisions chosen, which are in trunk */ + +{ + register struct hshentry const *ptr; + + for (ptr = Head; ptr; ptr = ptr->next) + putadelta(ptr, ptr->next, true); +} + + + + static void +putree(root) + struct hshentry const *root; +/* function: print delta tree (not including trunk) in reverse + order on each branch */ + +{ + if ( root == nil ) return; + + putree(root->next); + + putforest(root->branches); +} + + + + + static void +putforest(branchroot) + struct branchhead const *branchroot; +/* function: print branches that has the same direct ancestor */ +{ + + if ( branchroot == nil ) return; + + putforest(branchroot->nextbranch); + + putabranch(branchroot->hsh); + putree(branchroot->hsh); +} + + + + + static void +putabranch(root) + struct hshentry const *root; +/* function : print one branch */ + +{ + + if ( root == nil) return; + + putabranch(root->next); + + putadelta(root, root, false); +} + + + + + + static void +putadelta(node,editscript,trunk) + register struct hshentry const *node, *editscript; + int trunk; +/* function: Print delta node if node->selector is set. */ +/* editscript indicates where the editscript is stored */ +/* trunk indicated whether this node is in trunk */ +{ + static char emptych[] = EMPTYLOG; + + register FILE *out; + char const *s; + size_t n; + struct branchhead const *newbranch; + struct buf branchnum; + char datebuf[datesize]; + + if (!node->selector) + return; + + out = stdout; + aprintf(out, + "----------------------------\nrevision %s", node->num + ); + if ( node->lockedby ) + aprintf(out, "\tlocked by: %s;", node->lockedby); + + aprintf(out, "\ndate: %s; author: %s; state: %s;", + date2str(node->date, datebuf), + node->author, node->state + ); + + if ( editscript ) + if(trunk) + aprintf(out, insDelFormat, + editscript->deletelns, editscript->insertlns); + else + aprintf(out, insDelFormat, + editscript->insertlns, editscript->deletelns); + + newbranch = node->branches; + if ( newbranch ) { + bufautobegin(&branchnum); + aputs("\nbranches:", out); + while( newbranch ) { + getbranchno(newbranch->hsh->num, &branchnum); + aprintf(out, " %s;", branchnum.string); + newbranch = newbranch->nextbranch; + } + bufautoend(&branchnum); + } + + afputc('\n', out); + s = node->log.string; + if (!(n = node->log.size)) { + s = emptych; + n = sizeof(emptych)-1; + } + awrite(s, n, out); + if (s[n-1] != '\n') + afputc('\n', out); +} + + + + + + static struct hshentry const * +readdeltalog() +/* Function : get the log message and skip the text of a deltatext node. + * Return the delta found. + * Assumes the current lexeme is not yet in nexttok; does not + * advance nexttok. + */ +{ + register struct hshentry * Delta; + struct buf logbuf; + struct cbuf cb; + + if (eoflex()) + fatserror("missing delta log"); + nextlex(); + if (!(Delta = getnum())) + fatserror("delta number corrupted"); + getkeystring(Klog); + if (Delta->log.string) + fatserror("duplicate delta log"); + bufautobegin(&logbuf); + cb = savestring(&logbuf); + Delta->log = bufremember(&logbuf, cb.size); + + nextlex(); + while (nexttok==ID && strcmp(NextString,Ktext)!=0) + ignorephrase(); + getkeystring(Ktext); + Delta->insertlns = Delta->deletelns = 0; + if ( Delta != Head) + getscript(Delta); + else + readstring(); + return Delta; +} + + + static void +getscript(Delta) +struct hshentry * Delta; +/* function: read edit script of Delta and count how many lines added */ +/* and deleted in the script */ + +{ + int ed; /* editor command */ + declarecache; + register RILE *fin; + register int c; + register unsigned long i; + struct diffcmd dc; + + fin = finptr; + setupcache(fin); + initdiffcmd(&dc); + while (0 <= (ed = getdiffcmd(fin,true,(FILE *)0,&dc))) + if (!ed) + Delta->deletelns += dc.nlines; + else { + /* skip scripted lines */ + i = dc.nlines; + Delta->insertlns += i; + cache(fin); + do { + for (;;) { + cacheget(c); + switch (c) { + default: + continue; + case SDELIM: + cacheget(c); + if (c == SDELIM) + continue; + if (--i) + fatserror("unexpected end to edit script"); + nextc = c; + uncache(fin); + return; + case '\n': + break; + } + break; + } + ++rcsline; + } while (--i); + uncache(fin); + } +} + + + + + + + + static void +exttree(root) +struct hshentry *root; +/* function: select revisions , starting with root */ + +{ + struct branchhead const *newbranch; + + if (root == nil) return; + + root->selector = extractdelta(root); + root->log.string = nil; + exttree(root->next); + + newbranch = root->branches; + while( newbranch ) { + exttree(newbranch->hsh); + newbranch = newbranch->nextbranch; + } +} + + + + + static void +getlocker(argv) +char * argv; +/* function : get the login names of lockers from command line */ +/* and store in lockerlist. */ + +{ + register char c; + struct lockers * newlocker; + argv--; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + if ( c == '\0') { + lockerlist=nil; + return; + } + + while( c != '\0' ) { + newlocker = talloc(struct lockers); + newlocker->lockerlink = lockerlist; + newlocker->login = argv; + lockerlist = newlocker; + while ( ( c = (*++argv)) != ',' && c != '\0' && c != ' ' + && c != '\t' && c != '\n' && c != ';') ; + *argv = '\0'; + if ( c == '\0' ) return; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + } +} + + + + static void +getauthor(argv) +char *argv; +/* function: get the author's name from command line */ +/* and store in authorlist */ + +{ + register c; + struct authors * newauthor; + + argv--; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + if ( c == '\0' ) { + authorlist = talloc(struct authors); + authorlist->login = getusername(false); + authorlist->nextauthor = nil; + return; + } + + while( c != '\0' ) { + newauthor = talloc(struct authors); + newauthor->nextauthor = authorlist; + newauthor->login = argv; + authorlist = newauthor; + while( ( c = *++argv) != ',' && c != '\0' && c != ' ' + && c != '\t' && c != '\n' && c != ';') ; + * argv = '\0'; + if ( c == '\0') return; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + } +} + + + + + static void +getstate(argv) +char * argv; +/* function : get the states of revisions from command line */ +/* and store in statelist */ + +{ + register char c; + struct stateattri *newstate; + + argv--; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + if ( c == '\0'){ + warn("missing state attributes after -s options"); + return; + } + + while( c != '\0' ) { + newstate = talloc(struct stateattri); + newstate->nextstate = statelist; + newstate->status = argv; + statelist = newstate; + while( (c = (*++argv)) != ',' && c != '\0' && c != ' ' + && c != '\t' && c != '\n' && c != ';') ; + *argv = '\0'; + if ( c == '\0' ) return; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + } +} + + + + static void +trunclocks() +/* Function: Truncate the list of locks to those that are held by the */ +/* id's on lockerlist. Do not truncate if lockerlist empty. */ + +{ + struct lockers const *plocker; + struct lock * plocked, * nextlocked; + + if ( (lockerlist == nil) || (Locks == nil)) return; + + /* shorten Locks to those contained in lockerlist */ + plocked = Locks; + Locks = nil; + while( plocked != nil) { + plocker = lockerlist; + while((plocker != nil) && ( strcmp(plocker->login, plocked->login)!=0)) + plocker = plocker->lockerlink; + nextlocked = plocked->nextlock; + if ( plocker != nil) { + plocked->nextlock = Locks; + Locks = plocked; + } + plocked = nextlocked; + } +} + + + + static void +recentdate(root, pd) + struct hshentry const *root; + struct Datepairs *pd; +/* function: Finds the delta that is closest to the cutoff date given by */ +/* pd among the revisions selected by exttree. */ +/* Successively narrows down the interval given by pd, */ +/* and sets the strtdate of pd to the date of the selected delta */ +{ + struct branchhead const *newbranch; + + if ( root == nil) return; + if (root->selector) { + if ( cmpnum(root->date, pd->strtdate) >= 0 && + cmpnum(root->date, pd->enddate) <= 0) + VOID strcpy(pd->strtdate, root->date); + } + + recentdate(root->next, pd); + newbranch = root->branches; + while( newbranch) { + recentdate(newbranch->hsh, pd); + newbranch = newbranch->nextbranch; + } +} + + + + + + + static unsigned +extdate(root) +struct hshentry * root; +/* function: select revisions which are in the date range specified */ +/* in duelst and datelist, start at root */ +/* Yield number of revisions selected, including those already selected. */ +{ + struct branchhead const *newbranch; + struct Datepairs const *pdate; + unsigned revno; + + if (!root) + return 0; + + if ( datelist || duelst) { + pdate = datelist; + while( pdate ) { + if ( (pdate->strtdate)[0] == '\0' || cmpnum(root->date,pdate->strtdate) >= 0){ + if ((pdate->enddate)[0] == '\0' || cmpnum(pdate->enddate,root->date) >= 0) + break; + } + pdate = pdate->dnext; + } + if ( pdate == nil) { + pdate = duelst; + for (;;) { + if (!pdate) { + root->selector = false; + break; + } + if ( cmpnum(root->date, pdate->strtdate) == 0) + break; + pdate = pdate->dnext; + } + } + } + revno = root->selector + extdate(root->next); + + newbranch = root->branches; + while( newbranch ) { + revno += extdate(newbranch->hsh); + newbranch = newbranch->nextbranch; + } + return revno; +} + + + + static char +extractdelta(pdelta) + struct hshentry const *pdelta; +/* function: compare information of pdelta to the authorlist, lockerlist,*/ +/* statelist, revlist and yield true if pdelta is selected. */ + +{ + struct lock const *plock; + struct stateattri const *pstate; + struct authors const *pauthor; + struct Revpairs const *prevision; + unsigned length; + + if ((pauthor = authorlist)) /* only certain authors wanted */ + while (strcmp(pauthor->login, pdelta->author) != 0) + if (!(pauthor = pauthor->nextauthor)) + return false; + if ((pstate = statelist)) /* only certain states wanted */ + while (strcmp(pstate->status, pdelta->state) != 0) + if (!(pstate = pstate->nextstate)) + return false; + if (lockflag) /* only locked revisions wanted */ + for (plock = Locks; ; plock = plock->nextlock) + if (!plock) + return false; + else if (plock->delta == pdelta) + break; + if ((prevision = Revlst)) /* only certain revs or branches wanted */ + for (;;) { + length = prevision->numfld; + if ( + countnumflds(pdelta->num) == length+(length&1) && + 0 <= compartial(pdelta->num, prevision->strtrev, length) && + 0 <= compartial(prevision->endrev, pdelta->num, length) + ) + break; + if (!(prevision = prevision->rnext)) + return false; + } + return true; +} + + + + static void +getdatepair(argv) + char * argv; +/* function: get time range from command line and store in datelist if */ +/* a time range specified or in duelst if a time spot specified */ + +{ + register char c; + struct Datepairs * nextdate; + char const * rawdate; + int switchflag; + + argv--; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + if ( c == '\0' ) { + warn("missing date/time after -d"); + return; + } + + while( c != '\0' ) { + switchflag = false; + nextdate = talloc(struct Datepairs); + if ( c == '<' ) { /* case: -d strtdate)[0] = '\0'; + } else if (c == '>') { /* case: -d'>date' */ + c = *++argv; + (nextdate->enddate)[0] = '\0'; + switchflag = true; + } else { + rawdate = argv; + while( c != '<' && c != '>' && c != ';' && c != '\0') + c = *++argv; + *argv = '\0'; + if ( c == '>' ) switchflag=true; + str2date(rawdate, + switchflag ? nextdate->enddate : nextdate->strtdate); + if ( c == ';' || c == '\0') { /* case: -d date */ + VOID strcpy(nextdate->enddate,nextdate->strtdate); + nextdate->dnext = duelst; + duelst = nextdate; + goto end; + } else { + /* case: -d date< or -d date>; see switchflag */ + while ( (c= *++argv) == ' ' || c=='\t' || c=='\n'); + if ( c == ';' || c == '\0') { + /* second date missing */ + if (switchflag) + *nextdate->strtdate= '\0'; + else + *nextdate->enddate= '\0'; + nextdate->dnext = datelist; + datelist = nextdate; + goto end; + } + } + } + rawdate = argv; + while( c != '>' && c != '<' && c != ';' && c != '\0') + c = *++argv; + *argv = '\0'; + str2date(rawdate, + switchflag ? nextdate->strtdate : nextdate->enddate); + nextdate->dnext = datelist; + datelist = nextdate; + end: + if ( c == '\0') return; + while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n'); + } +} + + + + static void +getnumericrev() +/* function: get the numeric name of revisions which stored in revlist */ +/* and then stored the numeric names in Revlst */ +/* if branchflag, also add default branch */ + +{ + struct Revpairs * ptr, *pt; + unsigned n; + struct buf s, e; + char const *lrev; + struct buf const *rstart, *rend; + + Revlst = nil; + ptr = revlist; + bufautobegin(&s); + bufautobegin(&e); + while( ptr ) { + n = 0; + rstart = &s; + rend = &e; + + switch (ptr->numfld) { + + case 1: /* -r rev */ + if (expandsym(ptr->strtrev, &s)) { + rend = &s; + n = countnumflds(s.string); + if (!n && (lrev = tiprev())) { + bufscpy(&s, lrev); + n = countnumflds(lrev); + } + } + break; + + case 2: /* -r rev- */ + if (expandsym(ptr->strtrev, &s)) { + bufscpy(&e, s.string); + n = countnumflds(s.string); + (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0; + } + break; + + case 3: /* -r -rev */ + if (expandsym(ptr->endrev, &e)) { + if ((n = countnumflds(e.string)) < 2) + bufscpy(&s, ".1"); + else { + bufscpy(&s, e.string); + VOID strcpy(strrchr(s.string,'.'), ".1"); + } + } + break; + + default: /* -r rev1-rev2 */ + if ( + expandsym(ptr->strtrev, &s) + && expandsym(ptr->endrev, &e) + && checkrevpair(s.string, e.string) + ) { + n = countnumflds(s.string); + /* Swap if out of order. */ + if (compartial(s.string,e.string,n) > 0) { + rstart = &e; + rend = &s; + } + } + break; + } + + if (n) { + pt = ftalloc(struct Revpairs); + pt->numfld = n; + pt->strtrev = fstr_save(rstart->string); + pt->endrev = fstr_save(rend->string); + pt->rnext = Revlst; + Revlst = pt; + } + ptr = ptr->rnext; + } + /* Now take care of branchflag */ + if (branchflag && (Dbranch||Head)) { + pt = ftalloc(struct Revpairs); + pt->strtrev = pt->endrev = + Dbranch ? Dbranch : fstr_save(partialno(&s,Head->num,1)); + pt->rnext=Revlst; Revlst=pt; + pt->numfld = countnumflds(pt->strtrev); + } + bufautoend(&s); + bufautoend(&e); +} + + + + static int +checkrevpair(num1,num2) + char const *num1, *num2; +/* function: check whether num1, num2 are legal pair,i.e. + only the last field are different and have same number of + fields( if length <= 2, may be different if first field) */ + +{ + unsigned length = countnumflds(num1); + + if ( + countnumflds(num2) != length + || 2 < length && compartial(num1, num2, length-1) != 0 + ) { + error("invalid branch or revision pair %s : %s", num1, num2); + return false; + } + + return true; +} + + + + static void +getrevpairs(argv) +register char * argv; +/* function: get revision or branch range from command line, and */ +/* store in revlist */ + +{ + register char c; + struct Revpairs * nextrevpair; + int separator; + + c = *argv; + + /* Support old ambiguous '-' syntax; this will go away. */ + if (strchr(argv,':')) + separator = ':'; + else { + if (strchr(argv,'-') && VERSION(5) <= RCSversion) + warn("`-' is obsolete in `-r%s'; use `:' instead", argv); + separator = '-'; + } + + for (;;) { + while (c==' ' || c=='\t' || c=='\n') + c = *++argv; + nextrevpair = talloc(struct Revpairs); + nextrevpair->rnext = revlist; + revlist = nextrevpair; + nextrevpair->numfld = 1; + nextrevpair->strtrev = argv; + for (;; c = *++argv) { + switch (c) { + default: + continue; + case '\0': case ' ': case '\t': case '\n': + case ',': case ';': + break; + case ':': case '-': + if (c == separator) + break; + continue; + } + break; + } + *argv = '\0'; + while (c==' ' || c=='\t' || c=='\n') + c = *++argv; + if (c == separator) { + while( (c =(*++argv)) == ' ' || c == '\t' || c =='\n') ; + nextrevpair->endrev = argv; + for (;; c = *++argv) { + switch (c) { + default: + continue; + case '\0': case ' ': case '\t': case '\n': + case ',': case ';': + break; + case ':': case '-': + if (c == separator) + continue; + break; + } + break; + } + *argv = '\0'; + while (c==' ' || c=='\t' || c =='\n') + c = *++argv; + nextrevpair->numfld = + !nextrevpair->endrev[0] ? 2 /* -rrev- */ : + !nextrevpair->strtrev[0] ? 3 /* -r-rev */ : + 4 /* -rrev1-rev2 */; + } + if (!c) + break; + if (c!=',' && c!=';') + error("missing `,' near `%c%s'", c, argv+1); + } +} diff --git a/gnu/usr.bin/tar/COPYING b/gnu/usr.bin/tar/COPYING new file mode 100644 index 0000000000..a43ea2126f --- /dev/null +++ b/gnu/usr.bin/tar/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. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the 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. + + , 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/tar/ChangeLog b/gnu/usr.bin/tar/ChangeLog new file mode 100644 index 0000000000..7934f2b1b2 --- /dev/null +++ b/gnu/usr.bin/tar/ChangeLog @@ -0,0 +1,1732 @@ +Thu Mar 25 13:32:40 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * version.c: Released version 1.11.2. + + * Makefile.in (dist): Do the link differently; some of the + files have changed filesystems which makes it more complex. + + * Makefile.in (dist, shar): Use gzip instead of compress. + + * create.c (dump_file): Test for curdev==-1, not curdev<0. + Some losing NFS systems give negative device numbers + sometimes. + +Thu Mar 25 11:55:15 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * level-0, level-1 (TAR_PART1): Use `--block-size', not just + `--block', which is now ambiguous. + +Wed Mar 24 22:12:51 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * backup-specs (TAR): New variable. + + * level-0, level-1 (TAR_PART1): Get path of GNU tar from `TAR' + variable, don't hardcode it. + +Sat Mar 20 00:20:05 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * backup-specs (SLEEP_MESSAGE): put backslashes in front of nested + double quotes. + + * level-0, level-1 (BACKUP_DIRS): Don't put in quotes. + (LOGFILE): Use sed to construct name, not awk. + + * dump-remind (recipients): Replaced inefficient pipeline with a + single, simple sed script. + (volno): Deal with the possibility that VOLNO_FILE may not be + created yet. + +Fri Mar 19 15:05:15 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * backup-specs (VOLNO_FILE): Removed abusive comment by Noah. + + * buffer.c (new_volume): Write the global volume number to the + volno file before running the info script, so that the script + can look at it. + +Thu Mar 18 20:11:54 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * Makefile.in (AUX): Include `dump-remind' in distribution. + + * backup-specs (SLEEP_MESSAGE): New variable. + level-0, level-1: Use it instead of external `dont_touch' file. + + * level-0, level-1: Put most of the script in () and pipe + everything from the subshell through tee -a $LOGFILE. Since you + really want most of the output to go to the logfile anyway, and + since all those pipelines were preventing one from getting the + exit status of most commands, this seems like the right idea. + + * level-0, level-1 (LOGFILE): Use YYYY-MM-DD (all numeric) format + for log file name, since that makes the file names sortable in a + coherent way. Suffix should always be `level-n' where n is the + dump level. level-0 script was just using `-full' instead. + + * level-0, level-1 (DUMP_LEVEL): New variable. Set to `0' or `1' + in each script as appropriate. + + * level-0, level-1 (HOST): Renamed to `localhost' for clarity. + (host): renamed to `remotehost' for clarity. + + * level-0, level-1 (startdate): New variable. Use it in Subject + line of mailed report. + + * level-0, level-1: Fixed all instances where sed is called with a + script on the command line to use `-e' option. + + * level-0, level-1: Don't try to call logfile.sed to filter + LOGFILE. It's not distributed with tar and was never really used + anyway. + + * level-0, level-1: Put quotes around most variable names (barring + those that are known to intentionally contain text that should be + expanded into multiple words, like `TAR_PART1'). + + * level-0, level-1: Got rid of annoying trailing backslashes in awk + scripts. They were gratuitous. Made them a little more readable + by adding some whitespace. + +Wed Mar 17 10:30:58 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * tar.c (describe, long_options): Changed --compress-block to + --block-compress. + (options): Fixed f_compress_block sanity check error message + to give the correct name of the option. + +Tue Mar 16 14:52:40 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * extract.c (extract_archive): case LF_DIR: Do chown when + necessary. Don't bother jumping to set_filestat for + f_modified; repeat the chmod code here. Replace `break', + deleted on 2 September 1992. + + * tar.c (describe, long_options, options): Added gzip options + and use-compress-program option. + * tar.h: Added new compression options. + * buffer.c (child_open, open_archive): Use new compression options. + + * create.c (start_header): Only mask off high bits when + creating old-style archives. + * list.c (decode_header): Mask off potentially misleading + high bits from the mode when reading headers. + +Mon Mar 15 11:34:34 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * extract.c (extract_archive): Put arguments in the right + order for error message. + + * create.c (deal_with_sparse): if the last byte was null, we + didn't write it out. + + * gnu.c, create.c, extract.c, diffarch.c, list.c throughout: + Replace malloc calls with ck_malloc and realloc with ck_realloc. + + * tar.c (describe): Improve doc for -L. + + * tar.c (name_next): Don't apply exclusion to explicitly named + files. + + * tar.c (long_options, describe): Added new-volume-script as + an alias for info-script. + + * extract.c (extract_archive): LF_DUMPDIR case; misplaced paren. + + * extract.c (extract_archive): extract_file case, first if, + include space for null in namelen computation. + + * extract.c (extract_sparse_file): Use value returned by write + to properly create error message. + + * create.c (create_archive): Don't assume we have anything to + dump. + + * buffer.c (open_archive): Set current_file_name for the + volume header so that verbose listings work properly. + + * Makefile.in (realclean): Added getdate.c. + +Thu Jan 14 23:38:44 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu) + + * tar.c: Include fnmatch.h after port.h to make sure we get our FNM_* + (e.g. on HPUX 8). + +Tue Nov 24 08:30:54 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * tar.c (addname), gnu.c (read_dir_file): Use HAVE_GETCWD, not USG. + + * port.h, rmt.h: Use HAVE_STRING_H, not USG. + + * port.h: Add dir header decls. + * create.c, gnu.c: Use SYSNDIR, SYSDIR, and NDIR + instead of BSD42 and USG. Rename DP_NAMELEN to NLENGTH. + Use `struct dirent' instead of `struct direct'. + * create.c, gnu.c, tar.c: Remove dir header decls. + +Wed Nov 18 15:31:30 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * tar.c: Change FNM_TARPATH to FNM_LEADING_DIR to match change + in fnmatch.[ch]. + +Wed Oct 21 00:52:24 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * level-0, level-1: put curly braces around variables for clarity. + + * backup-specs (DUMP_REMIND_SCRIPT): define it (but commented out + so that distributed dump scripts won't use it by default). + level-0, level-1 (TAR_PART1): use --info-script if + DUMP_REMIND_SCRIPT is defined. + dump-remind: new file (intended as an example). + +Thu Oct 15 03:33:28 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * level-0, level-1: remove $LOGFILE.tmp files before exiting. + +Fri Oct 2 00:28:01 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * tar.c (describe): Fix some tab alignments. + + * Makefile.in (SRC3): Add getdate.c, for systems without bison/yacc + (like MS-DOS). + + * diffarch.c (diff_sparse_files): Add missing arg to fprintf calls. + + * extract.c (extract_archive, restore_saved_dir_info), + buffer.c (child_open), list.c (decode_header, print_header): + Delete unused vars. + + * port.c [__MSDOS__]: Have strstr, rename, and mkdir. Don't + define ck_pipe. + + * buffer.c, tar.c (init_volume_number, closeout_volume_number), + create.c (write_long): Declare as void, not int, since they + don't return a value. + +Thu Sep 24 00:06:02 1992 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * level-0, level-1 (TAR_PART1): remove --atime-preserve + because of a total screw. + +Tue Sep 22 14:15:48 1992 Michael I Bushnell (mib@wookumz.gnu.ai.mit.edu) + + * buffer.c (close_archive): Removed leftover `break' from when + this was a switch. + +Tue Sep 22 08:33:16 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * create.c, port.h: indented #pragma directives with 1 space. + +Fri Sep 18 14:15:17 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * All source files: re indented using GNU indent. + + * rtapelib.c (__rmt_read): Only read the amount left in the + buffer; otherwise a broken rmt server (which puts too much + data out) could overwrite past our buffer. + +Thu Sep 17 14:08:58 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * create.c: Throughout, use struct utimbuf rather than array + of longs. + + * configure.in: Check for getpwuid and getgrgid. + + * Makefile.in (SRC3, AUX): Move alloca.c to SRC3. + (OBJ3): Add @ALLOCA@. + + * Makefile.in (getdate.c): Look in srcdir for getdate.y. + + * buffer.c (close_archive): We can't check WTERMSIG + meaningfully unless we already know tha WIFSIGNALED is true. + (There is no guarantee it WTERMSIG will return zero when + WIFSIGNALED is false.) + * port.c (rmdir, mkdir): Check WIFSIGNALED rather than + WTERMSIG. + + * Makefile.in (getdate.c): Use $(YACC) instead of `yacc'. + +Tue Sep 15 14:49:48 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * version.c: Released version 1.11.1. + + * Makefile (AUX): Added NEWS. + + * Makefile.in (rmt): Added $(LIBS). + * configure.in: Added tests for libraries needed on Solaris. + + * mangle.c (extract_mangle): Null terminate link name for + losing archives missing it. + + * Makefile.in: added target and rule for getdate.c: getdate.y; + some makes don't have one built in. + +Mon Sep 14 16:23:15 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * tar.c (options, main): Advise use of --help rather than + +help. + + * create.c (write_long): Using hstat here is a Bad Idea, and + totally unnecessary at that. + + * list.c (read_header): Compute both signed and normal + checksums. + + * configure.in: Define BSD in the presence of /sdmach or + /../../mach. + + * diffarch.c, buffer.c: Declare valloc as void* rather than + char*. + + * Makefile.in: Don't install info files. + + * configure.in: Check for malloc was scrambled. + + * port.h: Undefine index and rindex if necessary; some + string.h's define them for us. + + * tar.c (addname): Missing braces after if. + * gnu.c (read_dir_file): Missing braces after if. + + * names.c: Add include of , + + * create.c (start_header): Set current_file_name so that + print_header (used for verbose create) works properly. + (dump_file): Set current_link_name when setting up symlink + and hardlink records. + +Fri Sep 11 01:05:52 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * fnmatch.[ch]: New files. + * wildmat.c: File removed. + * tar.c: Include fnmatch.h and use fnmatch instead of wildmat. + * Makefile.in, makefile.pc: Replace wildmat.o(bj) with fnmatch. + +Thu Sep 10 23:19:30 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * buffer.c, tar.c: Remove redundant decls of getenv, rindex. + + * Makefile.in: Add uninstall target. + Define libdir instead of hardcoding /etc for installing rmt. + +Thu Sep 10 13:06:03 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * list.c (read_header): On second thought, that doesn't work + either, so just store the names in malloced areas. Sigh. + + * NEWS: New file. + * README: Removed things that belong in NEWS; point to it. + + * list.c (read_header): current_file_name and + current_link_name need to be set to the arrays in head rather + than header; header is the actual read buffer and will change. + + * extract.c (extract_archive): + * buffer.c (new_volume): `#' directives need to start in + column 1. + +Thu Sep 10 06:09:18 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * level-0, level-1 (TAR_PART1): put --atime-preserve inside quotes. + +Wed Sep 9 13:34:26 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * Makefile.in (AUX): Add getpagesize.h. + (AUX): Comment out manuals. + (all): Comment out dependency on tar.info. + + * version.c: Release of version 1.11. + + * level-0, level-1 (TAR_PART1): Use --atime-preserve. + + * Makefile, configure.in: Arrange to use local malloc on HP-UX. + + * port.h Use the canonical Autoconf chunk for alloca instead + of just looking for gcc. + +Wed Sep 9 03:16:58 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * port.h: If compiling with gcc, use __builtin_alloca. + +Tue Sep 8 16:13:41 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * extract.c: Removed long name support from here. + * list.c (read_header): Understand and skip longname/longlink + headers here. Names for current file are stored in new global + variables. All source files except create.c changed to refer + to current_file_name and current_link_name instead of fields + directly from the current header. + +Thu Sep 3 12:41:08 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * create.c (write_long): New function. + (dump_file): When writing link records or symlink records, use + new write_long function instead of mangling when the link + target is too long. + (start_header): Use write_long instead of mangling for long + names. + * extract.c (saverec): Recognize LF_LONGNAME and LF_LONGLINK. + (saverec): Throughout, use longname and longlink if they are set. + +Wed Sep 2 14:41:13 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * mangle.c: This is now deprecated; retain extract_mangle for + backward compatability. + + * list.c (print_header): patch from Chris Arthur to prevent + printing 0 when the gid or uid is null. + + * list.c (decode_header): patch from Chris Arthur to use the + gid field when the gid is empty, and similarly for uid. + + * extract.c: saved_dir_info, saved_dir_info_head: new type and + var. + (extract_archive): When extracting directories, now save info + in saved_dir_info_head. + (restore_saved_dir_info): New function. + * list.c (read_and): Call restore_saved_dir_info at the end of + the run. + This patch is from Chris Arthur (csa@pennies.sw.stratus.com). + +Mon Aug 31 15:39:55 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * create.c (create_archive): If there are no names specified, + write nothing on the archive instead of dumping ".". + + * buffer.c (open_archive): Useful error message. + + * tar.c, tar.h: Recognize f_atime_preserve. + * create.c (dump_file): Implement f_atime_preserve. + + * rmt.h (_remdev): Don't require /dev/ to be in remote archive + names; obey new force-local flag. + * tar.c, tar.h: Implement new force-local flag. + + * tar.c (describe): same-owner and same-order were confused. + + * create.c (dump_file): Check for toplevel had sense reversed. + + * buffer.c (new_archive): Don't free old_name...when these + come from the command line, they aren't malloced, and it isn't + important to save this trivial amount of memory. + + * tar.h: replace ar_file with ar_files, n_ar_files, + cur_ar_files. + * buffer.c (open_archive): multi-volume compressed archives + never worked; give an appropriate error. Change open of + ar_file to open of ar_files[0]. + (writeerror, readerror, flush_archive): use + ar_files[cur_ar_file] instead of ar_file. + (new_archive): Necessary changes to support ar_files. + * tar.c (options): handle multiple tape drive arguments. + +Fri Aug 28 17:42:13 1992 Michael I Bushnell (mib@wookumz.gnu.ai.mit.edu) + + * list.c (decode_header), create.c (start_header), tar.h (TMAGIC): + Undo djm's changes below; tar does not support the final + Posix.1 format; it's bad to make it look like it does. + +Sun Jul 19 02:13:46 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * port.h: Try to prevent redefining major. + * port.c: HAVE_BZERO -> minix. Fix a typo. + + * list.c (decode_header): Recognize the final POSIX.1 magic as + well as the early draft magic for ustar. + * create.c (start_header): Create a final POSIX.1 magic string + instead of an early draft string for ustar. + * tar.h (TMAGIC): Remove the trailing blanks. + + * rmt.c, rtapelib.c: Use POSIX and STDC headers if available. + * rmt.h: Declare the external functions defined in rtapelib.c. + +Tue Jul 14 00:44:37 1992 David J. MacKenzie (djm@apple-gunkies.gnu.ai.mit.edu) + + * pathmax.h: New file. + * port.h: Include it. + * create.c (create_archive): Allocate PATH_MAX instead of + NAME_MAX for temporary buffer so we don't have to figure out + what NAME_MAX is (portably). + +Fri Jul 10 08:30:42 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * gnu.c (collect_and_sort_names): write_dir_file has no argument. + + * level-0, level-1: Avoid silly Sun awk lossage. + +Mon Jul 6 20:11:32 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * port.c (rename): If unlinking the source at the end fails, + unlink the destination instead to avoid leaving a mess. + +Fri Jul 3 15:16:42 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * buffer.c, diffarch.c, update.c, rtapelib.c: Change NO_MTIO to + HAVE_SYS_MTIO_H. + + * port.c, tar.h: Change FOO_MISSING to HAVE_FOO. + +Tue Jun 23 23:39:02 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * rmt.c: Add #ifdefs to work on ISC. + +Wed May 20 00:12:27 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu) + + * port.h: Define major, minor, makedev if the system doesn't. + +Wed May 13 21:16:38 1992 Michael I Bushnell (mib@apple-gunkies.gnu.ai.mit.edu) + + * gnu.c (add_dir_name): Store legitimate value into + dir_contents when get_dir_contents returns NULL. + +Thu May 7 23:44:35 1992 Michael I Bushnell (mib@apple-gunkies.gnu.ai.mit.edu) + + * gnu.c (add_dir_name): Check for return of NULL from get_dir_contents; + see djm's change of Fri Jul 26 01:12:58 1991. + +Mon May 4 22:50:57 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu) + + * tar.h: Make comments for option names say -- instead of +. + +Thu Apr 30 03:09:16 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * level-1: Added `$' before VOLNO_FILE in definition of TAR_PART1. + Added line to remove $VOLNO_FILE from any previous dump before + starting. + + * level-0, level-1: Change long options to use `--' instead of `+' + (support for `+' will go away soon) + +Wed Apr 29 14:23:10 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * tar.c, tar.t: Added +volno-file option. + buffer.c: New functions init_volume_number, + closeout_volume_number. + tar.c (main): Call new functions in the right place. + + * buffer.c (fl_write, fl_read): Mod to allow losing tape + drives which use short counts to indicate end of tape + correctly handle the multi-tape stuff. The read half won't + co-exist with f_reblock; there's no way to fix that, of + course. + + * tar.c, tar.h: Added new option +show-omitted-dirs, from + Karl Berry. + list.c (read_and): Implemented show-omitted-dirs. + + * tar.c, tar.h: Added new option +checkpoint. + buffer.c (fl_read, fl_write): Implemented +checkpoint lazily. + + * create.c (dump_file): Added toplevel argument; some devices + can be negative, so the old method was bogus. All callers + changed. + + * tar.c, tar.h: Added new option +ignore-failed-read. + create.c (dump_file): Implemented +ignore-failed-read. + + * create.c (finish_sparse_file): Commented out debugging printf. + + * tar.c, tar.h: Added new option +remove-files to delete files + after they are added to the archive. + create.c (dump_file): Implemented +remove-files for + everything but directories. I don't think they need it. + +Tue Apr 28 13:21:42 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * create.c: (dump_file): save_name needs to be set equal to p, + not something inside the header, because the header changes at + the first buffer flush. + +Fri Apr 24 10:41:13 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * create.c: Djm incorrectly moved the include of port.h to + precede the include of sys/file.h; restored. + + * tar.c (main): Cases CMD_EXTRACT and CMD_LIST: declare error + string with const. + + * gnu.c (collect_and_sort_names): Leave if around + write_dir_file in place. + +Wed Apr 22 02:16:14 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu) + + * rtapelib.c: SIGTYPE -> RETSIGTYPE. + +Mon Mar 9 22:42:05 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * rtapelib.c: Reformat and make comments more complete. + Rename a few variables for clarity. + +Thu Mar 5 14:07:34 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * tar.c (describe): Document long options as starting with --. + +Thu Jan 23 22:54:41 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * tar.c (options): Check get_date return value for error indication. + +Tue Dec 24 00:03:03 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * tar.c, gnu.c, extract.c, create.c, port.h, rmt.h: Change + POSIX ifdefs to HAVE_UNISTD_H and _POSIX_VERSION. + +Fri Dec 20 13:50:38 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * testpad.c (main): flush stderr so perror and fprintf + cooperate right. + +Wed Dec 18 16:52:42 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * port.h: Check MAJOR_IN_MKDEV and MAJOR_IN_SYSMACROS to find + where to get major, minor and makedev. + * create.c, list.c, update.c: Don't check USG to include + sys/sysmacros.h. + +Thu Dec 12 21:57:10 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * mangle.c (extract_mangle): Correctly null terminate name of + link target. + +Thu Nov 21 07:44:18 1991 Michael I Bushnell (mib at nutrimat) + + * create.c (dump_file, at start of ISREG output loop): use + filename from header instead of real name to make sure that we + get the mangled version and not one that is too long and + overflows buffers. + +Sat Nov 16 01:37:45 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * tar.h: Use new criteria for STDC version of msg. + +Sat Nov 2 21:31:57 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * create.c, gnu.c, tar.c: Use DIRENT instead of NDIR to select + between dirent.h and ndir.h for USG. + + * port.c: Rename WANT_FOO to FOO_MISSING to make sharing code + and configure script with other utilities easier. Use + VPRINTF_MISSING and DOPRNT_MISSING instead of FOO_MSG to + select error reporting routines. + +Thu Oct 17 20:19:02 1991 Michael I Bushnell (mib at churchy.gnu.ai.mit.edu) + + * level-0: Repair damage from previous mod: stdin to rsh must + be the terminal or tar's questions lose. + +Sat Aug 31 15:05:27 1991 Noah Friedman (friedman at nutrimat.gnu.ai.mit.edu) + + * level-0: Fixed several syntax errors associated with + stdout/stderr redirection. + Made sure remote host executes commands from sh where redirection + is necessary, since root's shell might be csh in some places and + the redirect syntax differs. + +Thu Aug 29 00:54:01 1991 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * tar.c (long_options). Fixed info-script long option. + +Mon Aug 26 16:53:50 1991 David J. MacKenzie (djm at pogo.gnu.ai.mit.edu) + + * configure, Makefile.in: Only put $< in Makefiles if VPATH + is being used, because older makes don't understand it. + +Mon Aug 19 01:47:57 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * create.c: Indent '#pragma alloca' so non-ANSI compilers + don't choke on it. + +Wed Aug 14 14:10:43 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * list.c (UGSWIDTH): Increase from 11 (sort of like Unix tar) to + 18, so that with normal user and group names of <= 8 chars, + the columns never shift in a tar -t listing. + +Fri Aug 2 00:41:08 1991 David J. MacKenzie (djm at apple-gunkies) + + * Makefile.in (dist): Include texinfo.tex and tar.info*. + (install): Install tar.info*. + * configure: Set INSTALLDATA. + + * configure: Create config.status. Remove it and Makefile if + interrupted while creating them. + + * configure: Check for +srcdir etc. arg and look for + Makefile.in in that directory. Set VPATH if srcdir is not `.'. + * Makefile.in: Add `prefix'. + (tar.info): New target. + +Tue Jul 30 17:08:04 1991 David J. MacKenzie (djm at apple-gunkies) + + * configure: NEED_TZSET has become FTIME_MISSING. + +Mon Jul 29 19:23:10 1991 David J. MacKenzie (djm at wombat.gnu.ai.mit.edu) + + * port.c [F_CHSIZE]: Additional version. + +Sat Jul 27 22:27:47 1991 David J. MacKenzie (djm at wombat.gnu.ai.mit.edu) + + * rmt.h: Clean up ifdefs. + + * makefile.pc: Fix typo. + port.h: Change MSDOS to __MSDOS__. + [__MSDOS__]: Define off_t. Include io.h and not sys/param.h. + [__TURBOC__]: Use void * and don't define const. + +Fri Jul 26 01:12:58 1991 David J. MacKenzie (djm at bleen) + + * buffer.c: Rename `eof' to `hit_eof' to avoid conflict with an + MSDOS function. + * gnu.c (get_dir_contents): Return NULL, not "\0\0\0\0", on error. + * diffarch.c (diff_archive): Open files in binary mode. + Don't use or free a non-malloc'd return value from get_dir_contents. + * msd_dir.c [__TURBOC__]: Include stdlib.h. + * rmt.h: lseek returns off_t, not long. + + * tar.c (describe): -X is +exclude-from, not +exclude. + (names_notfound): Free memory only if amiga, not !unix. + + * tar.h, tar.c: Add +null option to make -T read + null-terminated filenames (such as those produced by GNU find + -print0), and disable -C option. + This guarantees that odd filenames will get archived. + * tar.c (read_name_from_file): New function. + (name_next): Call it instead of fgets. + +Wed Jul 24 11:17:48 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * create.c [_AIX]: Declare alloca. + + * buffer.c (open_archive): Check for successful open before, + not after, fstatting the fd. + +Tue Jul 23 20:51:31 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * configure: Only define BSD42 if sys/file.h exists. + If alloca is missing and /usr/ucblib exists (SVR4), use it + instead of -lPW. + + * port.h [!__STDC__]: #define const. + * gnu.c (dirent_cmp): Fix args to agree with ANSI C prototype. + * create.c: Declare ck_realloc. + * gnu.c, diffarch.c: Move check for symlinks to after port.h include. + +Sat Jul 20 00:03:54 1991 David J. MacKenzie (djm at apple-gunkies) + + * msd_dir.[ch]: Use POSIX-style `struct dirent' instead of + `struct direct'. + * create.c, gnu.c, tar.c: Adjust callers. + +Thu Jul 18 00:05:01 1991 David J. MacKenzie (djm at bleen) + + * port.c (ck_malloc, ck_realloc): Return PTR, not char *. + * gnu.c, create.c, tar.c: Fix decls. + + * port.c: Don't use the preprocessor to guess missing + functions on Unix; let configure do it. + [WANT_GETWD] (getwd): Function removed; not needed because + getcwd is used if needed. + * gnu.c, tar.c: Use getcwd if POSIX. + + * rtapelib.c: Use SIGTYPE instead of testing SIGNAL_VOID. + Default to void (more common these days) instead of int. + + * tar.c, gnu.c, mangle.c: Remove VOIDSTAR defn. Use PTR instead. + * port.h: Define PTR. + + * gnu.c, tar.c [__MSDOS__ || USG]: Remove incorrect getcwd + decl; put correct one in port.h [!POSIX]. + + * tar.c (describe): Print on stdout instead of stderr; it's + not so much a usage message (since you have to ask for it + explicitly) as on-line help, and you really need to be able to + page it because it's more than a screen long. + + * Make #ifdefs for sys/file.h or fcntl.h, directory header, + sys/mtio.h consistent between files. Use NO_MTIO instead of + tricks with USG and HAVE_MTIO and NO_RMTIOCTL. + * Move decls of ANSI C and POSIX functions to port.h and + use standard headers to declare them if available + [STDC_HEADERS or POSIX]. + * Add many missing function declarations and return types. + * Some places used __MSDOS__, some MSDOS; standardize on __MSDOS__. + * Change S_IF macros to S_IS for POSIX. + * port.h: Define appropriate S_IS macros if missing. + * port.h: Rename macros for testing exit status to conform to + POSIX; use the system's versions if available [POSIX]. + * Use POSIX PATH_MAX and NAME_MAX instead of MAXPATHLEN and MAXNAMLEN. + * port.h: Define PATH_MAX and NAME_MAX. + * create.c, gnu.c, tar.c: Use ck_malloc and free instead of + auto arrays of size PATH_MAX or NAME_MAX, since with pathconf + they might not be constants. + * Move all definitions of O_* to port.h to reduce redundancy. + * Make all source files that now need to include port.h do so. + * port.c: Remove #undefs of WANT_* so you can use -DWANT_* + when compiling, instead of having to edit port.c. + [WANT_DUMB_GET_DATE] (get_date): Function removed. + Even systems without bison can get bison output and compile it. + [WANT_STRING] (index, rindex, bcopy, bzero, bcmp): Functions + removed; the translation is now done by macros in port.h. + * wildmat.c (wildmat): Use POSIX.2 '!' instead of '^' to negate + character classes. + +Mon Jul 15 13:47:45 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * testpad.c (main): Return type void. + + * port.c [WANT_STRING]: Don't include memory.h if NO_MEMORY_H. + + * create.c (dump_file) [AIX]: Fix typo, `allocate' for `alloca'. + * gnu.c (collect_and_sort_names): Move misplaced brace out of #ifdef. + From: Minh Tran-Le . + + * configure: Also look in sys/signal.h for signal decl. + +Wed Jul 10 01:42:55 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * Rename rtape_server.c to rmt.c and rtape_lib.c to rtapelib.c. + + * configure, Makefile.in: $(INSTALLPROG) -> $(INSTALL). + +Tue Jul 9 01:38:37 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * Most files: Refer to GPL version 2. + * COPYING: Use version 2. + + * port.c [__TURBOC__] (utime): New function. + + * xmalloc: New function (just calls ck_malloc), for alloca.c + and bison.simple (in getdate.y output). + + * Makefile.in (AUX): Include alloca.c and tcexparg.c, a + command line globber for Turbo C. + +Mon Jul 8 14:30:52 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * testpad.c: Open and write to testpad.h instead of stdout, + because some MS-DOS makes (Borland's at least) can't do + redirection in commands. + * Makefile.in: Don't redirect testpad output. + +Mon Jul 8 12:56:35 1991 Michael I Bushnell (mib at churchy.gnu.ai.mit.edu) + + * buffer.c (fl_read): Missing \n in printf. + +Mon Jul 8 03:40:28 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * create.c, extract.c, gnu.c, diffarch.c, tar.c: Comment out + unused variables. + + * tar.c (options): Cast get_date arg to VOIDSTAR instead of + `struct timeb *', since on some non-BSD systems the latter is + undefined. + +Sat Jul 6 04:53:14 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * Replace Makefile with configure, Makefile.in, and makefile.pc. + Update README with current compilation instructions. + + * port.c [WANT_RENAME] (rename): New function. + +Wed Jul 3 18:10:52 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * testpad.c (main): Avoid warning from some compilers on array + address. + + * rtape_server.c (sys_errlist): Should be declared extern. + +Mon Jul 1 14:14:06 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * Release of version 1.10; appropriate changes to README. + + * create.c: Removed printf's about sparse files. + + * Fix a misplaced quote in level-0 and change some >& into + 2>&1. + +Fri Jun 21 23:04:31 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * list.c (skip_extended_headers): Userec was being called in + the wrong place. + +Thu Jun 20 19:10:35 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * tar.h: Use ANSI prototypes for msg and msg_perror if + STDC_MSG is defined, even if BSD42 is also. + + * Makefile: Replace DESTDIR with bindir. + (install): Don't install tar.texinfo. There's no standard + place for texinfo files, and /usr/local/man is inappropriate. + Add TAGS, distclean, and realclean targets and SHELL= line. + + * version.c: Move old change history to bottom of ChangeLog. + +Wed Jun 12 12:43:58 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * rtape_lib.c (__rmt_write): #ifdef should reference + SIGNAL_VOID, not USG. + +Wed Jun 5 14:57:11 1991 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * tar.c (name_match, addname): Ugly hack to handle -C without + any files specified. + tar.h (struct name): New field for ugly hack. + +Mon Jun 3 14:46:46 1991 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * testpad.c: New file to determine if we need special padding + in struct header in tar.h. + + * tar.h (struct header): include padding if necessary, include + testpad.h. + + * Makefile: rules to create testpad.h, etc. + +Wed May 22 16:02:35 1991 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * tar.c (options): -L takes an argument. + + * rtape_lib.c (__rmt_open): add /usr/bin/nsh to the list of + remote shell programs. + + * create.c: define MAXPATHLEN if we don't get it from a system + header file. + + * create.c (deal_with_sparse): return a real return value if + we can't open the file. + + * tar.c (long_options): +newer takes an argument. + (describe): fix printing in various trivial ways + +Tue May 21 17:15:19 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * tar.c (long_options): +get and +concatentate don't require arguments + +Mon May 20 15:55:30 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * create.c (write_eot): Don't try and write an EOF if we are + already at one. + + * port.c (strstr): Looking for null string should return zero. + +Sun May 19 22:30:10 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * tar.c (options): -l doesn't take an argument + + * Makefile: minor fix for SGI 4D defines from torda@scum.ethz.ch + + * rtape_server.c (main.c): Suggested mod for 386/AIX from + Minh Tran-Le. I'm suspicious about this one. + + * create.c (dump_file): Mods from Minh Tran-Le for hidden + files on AIX. + gnu.c (collect_and_sort_name, get_dir_contents): AIX hidden file mod. + + * tar.c: (name_next): Mod from David Taylor to allow -C inside + a file list given to -T. + + * Makefile: Comment describing presence of USE_REXEC. + + * extract.c (extract_archive, case LF_SPARSE): zero check for + last element on numbytes needs to look at value after + converted from octal. + + * port.c: Don't always demand strstr, check for HAVE_STRSTR + instead. + Makefile: Comment describing presence of HAVE_STRSTR option. + +Sun May 19 18:39:48 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu) + + * port.c (get_date): Renamed from getdate, to avoid SVR4 conflict. + * tar.c: Call get_date instead of getdate. + +Fri May 10 02:58:17 1991 Noah Friedman (friedman at nutrimat) + + * tar.c: added "\n\" to the end of some documentation strings + where they were left off. + +Thu May 9 17:28:54 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * Makefile: added level-0, level-1, and backup-specs to AUX. + * version.c: changed to 1.10 beta. + * README: updated for 1.10 beta release. + +Tue Apr 2 12:04:54 1991 Michael I Bushnell (mib at godwin) + + * create.c (dump_file): HPUX's st_blocks is in 1024 byte units + instead of 512 like the rest of the world, so I special cased + it. + * tar.c: Undo Noah's changes. + +Mon Apr 1 17:49:28 1991 Noah Friedman (friedman at wookumz.gnu.ai.mit.edu) + + (This ought to be temporary until things are fixed properly. ) + + * tar.c: (struct option long_options): flag for "sparse" zero if + compiling under hpux. + tar.c: (functon options): case 'S' is a no-op if compiling under + hpux. + +Sat Mar 30 12:20:41 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * tar.h: new variable tape_length. + + * tar.c (options): add new option +tape-length / -L. + + * buffer.c (fl_write): Turn #ifdef TEST code for limited tape + length on always, for tape-length option. + + * create.c (dump_file): avoid apollo lossage where S_IFIFO == S_IFSOCK. + + * buffer.c: include regex.h + * buffer.c (fl_read, open_archive): Use regex routines for + volume header match. + * xmalloc.c: removed file; wasn't necessary. + * tar.c: (main) use ck_malloc instead of xmalloc. + +Thu Mar 28 04:05:05 1991 Noah Friedman (friedman at goldman) + + * regex.c, regex.o: New links. + * tar.c: include regex.h. + * Makefile (OBJ2): Add regex.o. + (regex.o, tar.o): Depend on regex.h + (SRC2, AUX): Add the new files. + +Sat Mar 23 15:39:42 1991 Noah Friedman (friedman at wookumz.gnu.ai.mit.edu) + + * Makefile: added default flags and options for compiling under + hpux. + + * Added files alloca.c and xmalloc.c + +Sat Mar 23 14:35:31 1991 Michael I Bushnell (mib at geech.gnu.ai.mit.edu) + + * port.c: Define WANT_VALLOC in HPUX. + +Fri Mar 15 06:20:15 1991 David J. MacKenzie (djm at geech.ai.mit.edu) + + * rtape_lib.c: If USG and not HAVE_MTIO, define NO_RMTIOCTL + automatically. + (_rmt_rexec): Temporarily re-open stdin and stdout to + /dev/tty, to guarantee that rexec() can prompt and read the + login name and password from the user. + From pascal@cnam.cnam.fr (Pascal Meheut). + * Makefile: Mention -DUSE_REXEC. + +Fri Mar 8 20:15:11 1991 Michael I Bushnell (mib at wookumz.ai.mit.edu) + + * tar.h, Makefile: Makefile CPP macro HAVE_SIZE_T might be + useful for some people. + + * gnu.c: lstat->stat define where appropriate + + * buffer.c (fl_write): keep track of amount written for +totals. + * tar.c, tar.h: set flag f_totals from +totals option + * tar.h (f_totals, tot_written): new variables + * tar.c (main): print total written with CMD_CREATE + + * tar.c (main): return appropriate exit status + +Thu Jan 17 00:50:21 1991 David J. MacKenzie (djm at apple-gunkies) + + * port.c: Remove a spurious `+' between functions (a remnant + of a context diff, apparently). + +Wed Jan 9 19:43:59 1991 Michael I Bushnell (mib at pogo.ai.mit.edu) + + * create.c (where_is_data): Rewritten to be better, and then + #ifdef-ed out. + (deal_with_sparse): Severly pruned. Now we write or don't + write only complete blocks, not worrying about partial blocks. + This simplifies calculations, removes bugs, and elides the + second scan through the block. The first was zero_record, the + second was where_is_data. + +Mon Jan 7 17:13:29 1991 Michael I Bushnell (mib at wookumz.ai.mit.edu) + + * create.c (deal_with_sparse): Second computation (for short + reads) of numbytes increment had subtraction backwards. + Need to handle calling where_is_data better when we did a + short read (it might go past the end of the read), also, set + sparsearray[...].offset in this case too. + +Fri Jan 4 12:24:38 EST 1991 Jay Fenlason (hack@ai.mit.edu) + + * buffer.c Return a special error code if the archive you're + trying to read starts with a different label than the one specified + on the command line. + +Wed Jan 2 12:05:21 EST 1991 Jay Fenlason (hack@ai.mit.edu) + + * gnu.c Prepend the current directory to the gnu_dumpfile, so that + -C's won't affect where the output goes. (sigh.) + +Tue Dec 18 18:05:59 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * (gnu.c) Don't complain if the gnudumpfile we're reading info + from doesn't exist. + + * create.c Write out gnudumpfile after finishing writing the archive. + + * tar.c Add +exclude FNAME, and make +exclude-from do what +exclude + used to. + + Make +version an operation, not an option. + + add +confirmation alias for +interactive. + +Tue Dec 4 13:28:08 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * tar.c (check_exclude) Don't let MUMBLE match MUMBLE.c or fooMUMBLE + but only foo/MUMBLE + + * Add the name mangler (mangle.c, plus changes to create.c and + extract.c) + + * extract.c Three small patches from Chip Salzenberg + (tct!chip@uunet.uu.net) + + Don't complain when extracting a link, IFF it already exists. + + Don't complain when extracting a directory IFF it already + exists. + + Don't ad u+wx to directories when running as root. + + * gnu.c Some changes from Chip Salzenberg to make + +listed-incremental work. + + * port.c Add the F_FREESP emulation of the ftruncate syscall. + +Wed Nov 21 15:57:07 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + Remove excess \n from lots of msg() calls. + +Mon Nov 19 14:09:43 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * tar.c Rename +volume to +label + +Fri Nov 16 15:43:44 1990 David J. MacKenzie (djm at apple-gunkies) + + * tar.c (describe): Include the default values for -b and -f + (as set in the Makefile) in the message. + +Thu Nov 15 13:36:45 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * extract.c (extract_archive) Do the utime() call before the + chmod() call, 'cuz some versons of utime() trash the file's mode + bits. + + * list.c (read_and) Call do_something on volume headers and + multivol files even if they don't match the names we're looking for, + etc. . . + +Tue Nov 6 13:51:46 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * port.c (un-quote-string) Don't try to write a null + if there's already one there. + +Thu Nov 1 14:58:57 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * buffer.c (new_volume) fflush(msg_file) before reading for + confirmation on new volume. On EOF or error, print error msg and + abort. + +Mon Oct 29 12:06:35 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * getdate.y Use new version of getdate(). + + * tar.c (name_add) Use sizeof(char *) instead of sizeof(int) + + * README give the correct return address. + +Thu Oct 25 16:03:58 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + rtape_lib.c Change RMTIOCTL to NO_RMTIOCTL, so it is on by default. + + rmt.h Add _isrmt() #define for NO_REMOTE case. + + gnu.c Add forward reference for add_dir_name(). + +Tue Oct 16 11:04:52 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + 1.09 New -G file implementation of gnu-dump stuff. + + * tar.c (name_add) Get the calls to ck_realloc and ck_malloc right. + +Thu Oct 11 11:23:38 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * gnu.c Fix A couple of typos. + +Wed Sep 19 13:35:03 1990 David J. MacKenzie (djm at apple-gunkies) + + * getdate.y [USG] (ftime): Use `daylight' unless + DAYLIGHT_MISSING is defined. + +Mon Sep 17 18:04:21 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * gnu.c (gnu_restore) Don't use a passed char* for the + file name, use skipcrud+head->header.name, just like everything + else does. This means that gnu_restore will still work with + small buffers, etc. + +Thu Sep 13 15:01:17 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * tar.c (add_exclude) Don't bus-error if the exclude file doesn't + end with a newline. + +Sun Sep 9 22:35:27 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * Makefile (dist): Remove .fname when done. + +Thu Sep 6 12:48:58 EDT 1990 Jay Fenlason (hack@ai.mti.edu) + + * gnu.c (gnu_restore) Rember to skip_file() over the directory + contents, even if we don't have to do anything with them. + + * create.c extract.c diffarch.c Free sparsearray after we're done + with it. + +Tue Sep 4 10:18:50 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * Makefile Include gnu.c in dist + + * gnu.c move add_dir above read_dir_file so that cc doesn't complain + about add_dir returning void. + +Sun Sep 2 20:46:34 1990 David J. MacKenzie (djm at apple-gunkies) + + * getdate.y: Declare some more functions and add storage + classes where omitted to shut compiler up. + [USG] (ftime): Don't use extern var `daylight'; appears that + some systems don't have it. + +Wed Aug 29 00:05:06 1990 David J. MacKenzie (djm at apple-gunkies) + + * getdate.y (lookup): In the code that allows `Aug.' to be + recognized as `Aug', don't chop off the final `.' from words + like `a.m.', so they can be recognized. + +Thu Aug 16 11:34:07 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * buffer.c (open_archive) If -O, write verbosity to stderr + instead of stdout. + +Fri Aug 10 12:29:28 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * getdate.y Handle an explicit DST in the input string. + A dozen line patch from Per Foreby (perf@efd.lth.se). + +Mon Jul 16 13:05:11 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * tar.c rename -g -G +incremental, +listed-imcremental, etc. + +Fri Jul 13 14:10:33 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * tar.c Make +newer and +newer-mtime work according to their names. + + * gnu.c If +newer or +newer-mtime, use the time specified on the + command line. + + * buffer.c, create.c Add test to see if dimwit is trying to + archive the archive. + + * tar.c (long_options[]) re-ordered, so that groups of similar + options are next to each other. . . I think. + + (describe) Modified to more closely reflect reality. + +Fri Jul 6 13:13:59 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * tar.c add compile-time option for SYS V (?) style + tape-drive names /dev/rmt/{n}[lmh] + + * tar.c Fix getopt-style stuff so that -C always works correctly. + + * gnu.c, tar.c make filename to -G optional. + + * {all over}, replace some fprintf(stderr...) calls with calls + to msg(). + + * port.c Make -Dmumble_MSG option on command line override + internal assumptions. + + * Makefile Mention -Dmumble_MSG options + +Fri Jul 6 02:35:31 1990 David J. MacKenzie (djm at apple-gunkies) + + * tar.c (options): Don't change `c' if it is 0, as getopt now + handles that internally. + +Mon Jul 2 15:21:13 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * gnu.c (new file) Moved all the f_gnudump stuff here where we + can keep track of it easier. Also made -G take a file name where it + stores the inode information about directories so that we can + detect moved directores. + + * create.c (dump_file) Changed slightly to work with the new + f_gnudump. + + * tar.c Moved the f_gnudump stuff to gnu.c + + * tar.c, extract.c added the +do-chown option, which forces tar + to always try to chown the created files to their original owners. + + * version.c New version 1.09 + +Sun Jun 24 14:26:28 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * create.c: Change ifdefs for directory library header + selection to be like the ones in tar.c. + * Makefile [Xenix]: Link with -ldir to get the dirent.h + directory library. + +Thu Jun 7 03:31:51 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * Makefile, buffer.c, diffarch.c: Change MTIO symbol to HAVE_MTIO + because SCO Xenix defines 'MTIO' for an incompatible tape driver + system in a file included by termio.h. + * tar.h: Don't define size_t for Xenix. + +Tue Jun 5 11:38:00 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * create.c (dump_file) Only print the + "... is on a different filesystem..." if f_verbose is on. + also add a case for S_IFSOCK and treat it like a FIFO. + (Not sure if that's the right thing to do or not, but it's better + than all those Unknown File Type msgs.) + +Thu May 31 19:25:36 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * port.c Use #ifdef sparc instead of #ifdef SPARC since + the lowercase version is defined, and the uppercase one isn't. + +Tue May 22 11:49:18 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * port.c (ck_malloc) if size==0 pretend size=1 + (ck_realloc) if(!ptr) call ck_malloc instead. + +Tue May 15 12:05:45 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * diffarch.c (diff_archive) If not f_absolute_paths, and attempt to + open a file listed in the archive fails, try /filename also. This will + allow diff to open the wrong file if both /filename and filename exist, + but there's nothing we can do about that. + +Fri May 11 16:17:43 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * Makefile, Descripbe new -DMTIO option. + + * buffer.c diffarch.c Change ifdefs slightly, so that + -DMTIO will include sys/mtio.h even if USG is defined. + This is for HUPX and similar BSD/USG crossovers. + +Tue May 8 13:14:54 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * update.c (update_archive) Call reset_eof() when appropriate. + + * buffer.c (reset_eof) New function, that turns of EOF flag, and + re-sets the ar_record and ar_last pointers. This will allow + 'tar rf non-existant-file' to not core-dump. + +Fri May 4 14:05:31 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * tar.c: Recognize the +sparse option. It was documented, but + only the short form (-S) was actually recognized. + +Tue Apr 17 21:34:14 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * create.c Don't access location 0 if ->dir_contents is null. + +Wed Apr 11 17:30:03 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * buffer.c (flush_archive, close_archive, new_volume) Always check + the return value of rmtclose(), and only give a warning msg if it is + <0. Some device drivers (including Sun floppy disk, and HP + streaming tape) return -1 after an IO error (or something like that.) + +Fri Mar 23 00:06:30 1990 Jim Kingdon (kingdon at mole.ai.mit.edu) + + * tar.c (long_options): Make it so +append +extract +list +update + +catenate and +delete don't take arguments. + +Mon Mar 12 13:33:53 EST 1990 + + * buffer.c (open_archive, fl_write) Set the mtime of the volume + header to the current time. + +Wed Mar 7 14:10:10 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * buffer.c Fix +compress-block A two character patch from + Juha Sarlin (juha@tds.kth.se) + Replace #ifdef __GNU__ with #ifdef __STDC__ + (new_volume) If open of new archive fails, ask again + (Is probably user error.) + + * tar.c Replace #ifdef __GNU__ with #ifdef __STDC__ + + * port.c Clean up #ifdef and #defines a bit. + (quote_copy_string) Sometimes the malloc'd buffer + would be up to two characters too short. + + * extract.c (extract_archive) Don't declare ind static. + + * create.c (dump_file) Don't declare index_offset static. + + * diffarch.c Remove diff_name variable, and always use + head->header.name, which will always work, unlike diff_name, which + becomes trash when the next block is read in. + +Thu Mar 1 13:43:30 EST 1990 Jay Fenlason (hack@wookumz.ai.mit.edu) + + * Makefile Mention the -NO_REMOTE option. + * port.c Fix typo, and define WANT_FTRUNCATE on i386 machines. + +Mon Feb 26 17:44:53 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * getdate.y: Declare yylex and yyerror as static. + #define yyparse to getdate_yyparse. + +Sun Feb 25 20:47:23 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * tar.c: Remove +old option, since it is a valid abbreviation of + +old-archive, which does the same thing. + (describe): A few small cleanups in message. + +Mon Feb 5 14:29:21 EST 1990 Jay Fenlason (hack@wookumz) + + * port.c define LOSING_MSG on sparc, since doprnt_msg doesn't work. + Fix typo in #ifdef WANT_GETWD + +Fri Jan 26 16:11:20 EST 1990 Jay Fenlason (hack@wookumz) + + 1.08 Sparse file support added. Also various other features. + + * diffarch.c (compare_chunk) Include correct arguments in + a call to fprintf() for an error msg. + (compare_chunks, compare_dir) First argument is a long, not an int. + + * tar.c (options) Use tar variable (argv[0]) as the name to print + in an error msg, instead of a constant "tar". + (confirm) Use external variable char TTY_NAME[] for name of file + to open for confirmation input. + + * buffer.c (new_volume) Ditto. + + * port.c Add declaration for TTY_NAME[]. + + * rmt.h Add long declarations for lseek() and __rmt_lseek(); + +Tue Jan 23 14:06:21 EST 1990 Jay Fenlason (hack@wookumz) + * tar.c, create.c Create the +newer-mtime option, which is like + +newer, but only looks for files whose mtime is newer than the + given date. + + * rtape_lib.c Make *both* instances of signal-handler stuff use + void (*foo)() on USG systems. + +Thu Jan 11 14:03:45 EST 1990 Jay Fenlason (hack@wookumz) + + * getdate.y Parse European dates of the form YYMMDD. + In ftime() Init timezone by calling localtime(), and remember that + timezone is in seconds, but we want timeb->timezone to be in minutes. + This small patch from Joergen Haegg (jh@aahas.se) + + * rtape_lib.c (__rmt_open) Also look for /usr/bsd/rsh. + Declare signal handler as returning void instead of int if USG is + defined. + + * port.c Declare WANT_GETWD for SGI 4-D IRIS. + + * Makefile Include defines for SGI 4D version. There are a simple + patch from Mike Muuss (mike@brl.mil). + + * buffer.c (fl_read) Work properly on broken Ultrix systems where + read() returns -1 with errno==ENOSPC on end of tape. Correctly go + on to the next volume if f_multivol. + + * list.c (list_archive,print_header) Flush msg_file after printing + messages. + + * port.c Delete unused references to alloca(). + Don't crash if malloc() returns zero in quote_copy_string. + Flush stderr in msg() and msg_perror(). + + * tar.c Flush msg_file after printing confirmation msg. + +Wed Jan 10 01:58:46 1990 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * tar.c (main): Change -help option and references to it to +help, + and remove suggestion to run info (which is unreleased, so not + likely to be of any help). + +Tue Jan 9 16:16:00 EST 1990 Jay Fenlason (hack @wookumz) + + * create.c (dump_file) Close file descriptor if start_header() + fails. + (dump_file) Change test for ./ ness to not think that + .{any character} is a ./ These are both trivial changes from + Piercarlo "Peter" Grandi pcg%cs.aber.ac.uk@nsfnet-relay.ac.uk + + * diffarch.c (diff_init) Print correct number of bytes in error + message. + +Tue Jan 9 03:19:49 1990 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * Makefile: Add comment at top noting that two source files also + contain #defines that might need to be changed by hand. + + * create.c, diffarch.c, extract.c: Change L_SET to 0 in lseek + calls, because only BSD defines it. + * create.c (dump_file): Make sparse file checking code conditional + on BSD42 because it uses st_blocks, which the other systems lack. + +Tue Jan 2 13:35:56 EST 1990 Jay Fenlason (hack@gnu) + + * port.c (quote_copy_string) Fix so it doesn't scramble memory if + the last character is non-printable. A trivial fix from Kian-Tat Lim + (ktl@wag240.caltech.edu). + +Tue Dec 19 11:19:37 1989 Jim Kingdon (kingdon at pogo) + + * port.c [BSD42]: Define DOPRNT_MSG. + tar.h [BSD42]: Do not prototype msg{,_perror}. + +Fri Dec 8 11:02:47 EST 1989 Jay Fenlason (hack@gnu) + + * create.c (dump_file) Remove typo in msg. + +Fri Dec 1 19:26:47 1989 David J. MacKenzie (djm at trix) + + * Makefile: Remove comments referring to certain systems lacking + getopt, since it is now provided always and needed by all systems. + + * port.c: Remove copy of getopt.c, as it is now linked in + separately to always get the current version. + + * tar.c: Rename +cat-tars option to +catenate or +concatenate, + and +local-filesystem to +one-file-system (preferred by rms + and used in GNU cp for the same purpose). + (describe): Reflect changes. + +Tue Nov 28 04:28:26 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * port.c: Move declaration of alloca into #else /* sparc */ + so it will compile on sparcs. + +Mon Nov 27 15:17:08 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * tar.c (options): Remove -version option (replaced by +version). + (describe): Mention long options. + +Sat Nov 25 04:25:23 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * getoldopt.c (getoldopt): Make `opt_index' argument a pointer to + an int, not char. + + * tar.c: Modify long options per rms's suggestions: + Make preserve-permissions an alias for same-permissions. + Make preserve-order an alias for same-order. + Define preserve to mean both of those combined. + Make old an alias for old-archive. + Make portability an alias for old-archive, also. + Rename sym-links to dereference. + Rename gnudump to incremental. + Rename filename to file. + Make compare an alias for diff. Leave diff but prefer compare. + Rename blocking-factor to block-size. + Rename chdir to directory. + Make uncompress an alias for compress. + Rename confirm to interactive. + Make get an alias for extract. + Rename volume-header to volume. + + Also make +version an alias for -version. + + (options): Shorten code that interprets long options by using + the equivalent short options' code. This also makes it tons + easier to change the long options. + + (describe): Make usage message more internally consistent + stylistically. + +Mon Nov 20 14:55:39 EST 1989 hack@ai.mit.edu + + * list.c (read_and) Call check_exclude() to see if the files + should be skipped on extract or list. + +Thu Nov 9 18:59:32 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * buffer.c (fl_read): Fix typos in error message + "tar EOF not on block boundary". + +Mon Oct 23 13:09:40 EDT 1989 (hack@ai.mit.edu) + + * tar.c (long_options[]) Add an option for blocked compression. + +Thu Oct 19 13:38:16 EDT 1989 (hack@ai.mit.edu) + + * buffer.c (writeerror) Print a more useful error msg. + +Wed Sep 27 18:33:41 EDT 1989 (hack@ai.mit.edu) + + * tar.c (main) Mention "tar -help" if the luser types a non-workable + set of options. + +Mon Sep 11 15:03:29 EDT 1989 (hack@ai.mit.edu) + + * tar.c (options) Have -F correctly set info_script. + +Tue Aug 29 12:58:06 EDT 1989 (hack@ai.mit.edu) + + * Makefile Include ChangeLog in tar.tar and tar.tar.Z + +Mon Aug 28 17:42:24 EDT 1989 (hack@ai.mit.edu) + + * tar.c (options) Made -F imply -M + Also remind tar that the -f option takes an argument! + + * Modified -F option to make it do what (I think) it + should. e.g, if you say -F, tar won't send a msg to + msg_file and wait for a It'll just run the program + it was given, and when the prog returns, the new tape had + *better* be ready. . . + + * buffer.c (open_archive) Give error message and abort if + the luser didn't give an archive name. + +Fri Aug 25 20:05:27 EDT 1989 Joy Kendall (jak at hobbes) + + * Added code to make a new option to run a specified script + at the end of each tape in a multi-volume backup. Changed: + tar.c: made new switch, -F, and new long-named option, + "info-script". Code is where you would expect. + tar.h: added flag f_run_script_at_end, and an extern char * + called info_script, which optarg gets set to. + buffer.c: line 1158 in new_volume(): if f_run_script_at_end + is set, we give info_script to system(), otherwise we do + what we've always done. **FIXME** I'm not sure if that's all + that has to be done here. + +Thu Aug 24 10:09:38 EDT 1989 Joy Kendall (jak at spiff) +(These changes made over the course of 6/89 - 8/89) + + * diffarch.c: diff_archive: Added switches for LF_SPARSE in the + case statements that needed it. Also, skip any extended headers + if we need to when we skip over a file. (need to change + the bit about, if the size doesn't agree AND the file is NOT + sparse, then there's a discrepancy, because I added another + field to the header which should be able to deal with the + sizes) If the file is sparse, call the added routine + "diff_sparse_files" to compare. Also added routine + "fill_in_sparse_array". + + * extract.c: extract_archive: added the switch LF_SPARSE + to the case statement as needed, and code to treat the + sparse file. At label "again_file", modified opening the + file to see if we should have O_APPEND be one of the modes. + Added code at label "extract_file" to call the new routine + "extract_sparse_file" when we have an LF_SPARSE flag. + + Note: really should erase the commented-out code in there, + because it's confusing. + + * update.c: made sure that if a file needed to be "skipped" + over, it would check to see if the linkflag was sparse, and + if so, would then make sure to skip over any "extended + headers" that might come after the header itself. Do so by + calling "skip_extended_headers". + + * create.c: create_archive: added code to detect a sparse + file when in the long case statement. Added ways to detect + extended headers, and label "extend" (ack! should get rid of + that, is atrocious). Call the new routine "finish_sparse_file" + if the linkflag is LF_SPARSE to write the info to the tape. + Also added routines "init_sparsearray", "deal_with_sparse", + "clear_buffer", "where_is_data", "zero_record", and + "find_new_file_size". + + * tar.h: Added the #define's SPARSE_EXT_HDR and + SPARSE_IN_HDR. Added the struct sparse and the struct + sp_array. Added the linkflag LF_SPARSE. Changed the tar + header in several ways: + - added an array of struct sparse's SPARSE_IN_HDR long + - added a char flag isextended + - added a char string realsize to store the true + size of a sparse file + Added another choice to the union record called a + struct extended_header, which is an array of 21 struct + sparse's and a char isextended flag. Added flag + f_sparse_file to list of flags. + + * tar.c: added long-named options to make tar compatible with + getopt_long, changed Makefile. + +... ... .. ..:..:.. ... .... Jay Fenlason (hack@ai.mit.edu) + + 1.07 New version to go on beta tape with GCC 1.35 + Better USG support. Also support for __builtin_alloca + if we're compiling with GCC. + diffarch.c: Include the correct header files so MTIOCTOP + is defined. + tar.c: Don't print the verbose list of options unless + given -help. The list of options is *way* too long. + + 1.06 Use STDC_MSG if __STDC__ defined + ENXIO meand end-of-volume in archive (for the UNIX PC) + Added break after volume-header case (line 440) extract.c + Added patch from arnold@unix.cc.emory.edu to rtape_lib.c + Added f_absolute_paths option. + Deleted refereces to UN*X manual sections (dump(8), etc) + Fixed to not core-dump on illegal options + Modified msg_perror to call perror("") instead of perror(0) + patch so -X - works + Fixed tar.c so 'tar cf - -C dir' doesn't core-dump + tar.c (name_match): Fixed to chdir() to the appropriate + directory if the matching name's change_dir is set. This + makes tar xv -C foo {files} work. + + 1.05 A fix to make confirm() work when the archive is on stdin + include 'extern FILE *msg_file;' in pr_mkdir(), and fix + tar.h to work with __STDC__ + + Added to port.c: mkdir() ftruncate() Removed: lstat() + Fixed -G to work with -X + Another fix to tar.texinfo + Changed tar.c to say argv[0]":you must specify exactly ... + buffer.c: modified child_open() to keep tar from hanging when + it is done reading/writing a compressed archive + added fflush(msg_file) before printing error messages + create.c: fixed to make link_names non-absolute + + 1.04 Added functions msg() and msg_perror() Modified all the + files to call them. Also checked that all (I hope) + calls to msg_perror() have a valid errno value + (modified anno() to leave errno alone), etc + Re-fixed the -X option. This time for sure. . . + re-modified the msg stuff. flushed anno() completely + Modified the directory stuff so it should work on sysV boxes + added ftime() to getdate.y + Fixed un_quote_string() so it won't wedge on \" Also fixed + \ddd (like \123, etc) + More fixes to tar.texinfo + + 1.03 Fixed buffer.c so 'tar tzf NON_EXISTENT_FILE' returns an error + message instead of hanging forever + More fixes to tar.texinfo + + 1.02 Fixed tar.c so 'tar -h' and 'tar -v' don't cause core dump + Also fixed the 'usage' message to be more up-to-date. + Fixed diffarch.c so verify should compile without MTIOCTOP + defined + + 1.01 Fixed typoes in tar.texinfo + Fixed a bug in the #define for rmtcreat() + Fixed the -X option to not call realloc() of 0. + + Version 1.00: version.c added. -version option added + Installed new version of the remote-tape library + Added -help option + +Local Variables: +mode: indented-text +left-margin: 8 +version-control: never +End: diff --git a/gnu/usr.bin/tar/Makefile b/gnu/usr.bin/tar/Makefile new file mode 100644 index 0000000000..810fe3b7a7 --- /dev/null +++ b/gnu/usr.bin/tar/Makefile @@ -0,0 +1,14 @@ +PROG= tar +SRCS= buffer.c create.c diffarch.c extract.c fnmatch.c getdate.y \ + getoldopt.c getopt.c getopt1.c gnu.c list.c mangle.c names.c port.c \ + regex.c rtapelib.c tar.c update.c version.c +CFLAGS+= -DRETSIGTYPE=void -DDIRENT=1 -DHAVE_SYS_MTIO_H=1 -DHAVE_UNISTD_H=1 +CFLAGS+= -DHAVE_GETGRGID=1 -DHAVE_GETPWUID=1 -DHAVE_STRING_H=1 +CFLAGS+= -DHAVE_LIMITS_H=1 -DHAVE_STRSTR=1 -DHAVE_VALLOC=1 -DHAVE_MKDIR=1 +CFLAGS+= -DHAVE_MKNOD=1 -DHAVE_RENAME=1 -DHAVE_FTRUNCATE=1 -DHAVE_GETCWD=1 +CFLAGS+= -DHAVE_VPRINTF=1 -DNEEDPAD -I${.CURDIR} +CFLAGS+= -DDEF_AR_FILE=\"/dev/rst0\" -DDEFBLOCKING=20 +NOMAN=noman + +.include +.include "../../usr.bin/Makefile.inc" diff --git a/gnu/usr.bin/tar/Makefile.gnu b/gnu/usr.bin/tar/Makefile.gnu new file mode 100644 index 0000000000..a03617ae36 --- /dev/null +++ b/gnu/usr.bin/tar/Makefile.gnu @@ -0,0 +1,185 @@ +# Generated automatically from Makefile.in by configure. +# Un*x Makefile for GNU tar program. +# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#### Start of system configuration section. #### + +srcdir = . +VPATH = . + +# If you use gcc, you should either run the fixincludes script that +# comes with it or else use gcc with the -traditional option. Otherwise +# ioctl calls will be compiled incorrectly on some systems. +CC = gcc +YACC = bison -y +INSTALL = /usr/local/bin/install -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) -m 644 + +# Things you might add to DEFS: +# -DSTDC_HEADERS If you have ANSI C headers and libraries. +# -DHAVE_UNISTD_H If you have unistd.h. +# -DHAVE_STRING_H If you don't have ANSI C headers but have string.h. +# -DHAVE_LIMITS_H If you have limits.h. +# -DBSD42 If you have sys/dir.h (unless you use -DPOSIX), +# sys/file.h, and st_blocks in `struct stat'. +# -DDIRENT If you have dirent.h. +# -DSYSNDIR Old Xenix systems (sys/ndir.h). +# -DSYSDIR Old BSD systems (sys/dir.h). +# -DNDIR Old System V systems (ndir.h). +# -DMAJOR_IN_MKDEV If major, minor, makedev defined in sys/mkdev.h. +# -DMAJOR_IN_SYSMACROS If major, minor, makedev defined in sys/sysmacros.h. +# -DRETSIGTYPE=int If your signal handlers return int, not void. +# -DHAVE_SYS_MTIO_H If you have sys/mtio.h (magtape ioctls). +# -DHAVE_SYS_GENTAPE_H If you have sys/gentape.h (ISC magtape ioctls). +# -DHAVE_NETDB_H To use rexec for remote tape operations +# instead of forking rsh or remsh. +# -DNO_REMOTE If you have neither a remote shell nor rexec. +# -DHAVE_VPRINTF If you have vprintf function. +# -DHAVE_DOPRNT If you have _doprnt function (but lack vprintf). +# -DHAVE_FTIME If you have ftime system call. +# -DHAVE_STRSTR If you have strstr function. +# -DHAVE_VALLOC If you have valloc function. +# -DHAVE_MKDIR If you have mkdir and rmdir system calls. +# -DHAVE_MKNOD If you have mknod system call. +# -DHAVE_RENAME If you have rename system call. +# -DHAVE_GETCWD If not POSIX.1 but have getcwd function. +# -DHAVE_FTRUNCATE If you have ftruncate system call. +# -DV7 On Version 7 Unix (not tested in a long time). +# -DEMUL_OPEN3 If you lack a 3-argument version of open, and want +# to emulate it with system calls you do have. +# -DNO_OPEN3 If you lack the 3-argument open and want to +# disable the tar -k option instead of emulating open. +# -DXENIX If you have sys/inode.h and need it to be included. + +DEF_AR_FILE = /dev/rst0 +DEFBLOCKING = 20 +DEFS = -DRETSIGTYPE=void -DDIRENT=1 -DHAVE_SYS_MTIO_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETGRGID=1 -DHAVE_GETPWUID=1 -DHAVE_STRING_H=1 -DHAVE_LIMITS_H=1 -DHAVE_STRSTR=1 -DHAVE_VALLOC=1 -DHAVE_MKDIR=1 -DHAVE_MKNOD=1 -DHAVE_RENAME=1 -DHAVE_FTRUNCATE=1 -DHAVE_GETCWD=1 -DHAVE_VPRINTF=1 -DDEF_AR_FILE=\"$(DEF_AR_FILE)\" -DDEFBLOCKING=$(DEFBLOCKING) + +# Set this to rtapelib.o unless you defined NO_REMOTE, in which case +# make it empty. +RTAPELIB = rtapelib.o +LIBS = + +CFLAGS = -g +LDFLAGS = -g + +prefix = /usr/bin +exec_prefix = $(prefix) + +# Prefix for each installed program, normally empty or `g'. +binprefix = + +# The directory to install tar in. +bindir = $(exec_prefix)/bin + +# Where to put the rmt executable. +libdir = /sbin + +# The directory to install the info files in. +infodir = $(prefix)/info + +#### End of system configuration section. #### + +SHELL = /bin/sh + +SRC1 = tar.c create.c extract.c buffer.c getoldopt.c update.c gnu.c mangle.c +SRC2 = version.c list.c names.c diffarch.c port.c fnmatch.c getopt.c malloc.c +SRC3 = getopt1.c regex.c getdate.y getdate.c alloca.c +SRCS = $(SRC1) $(SRC2) $(SRC3) +OBJ1 = tar.o create.o extract.o buffer.o getoldopt.o update.o gnu.o mangle.o +OBJ2 = version.o list.o names.o diffarch.o port.o fnmatch.o getopt.o +OBJ3 = getopt1.o regex.o getdate.o $(RTAPELIB) +OBJS = $(OBJ1) $(OBJ2) $(OBJ3) +AUX = README INSTALL NEWS COPYING ChangeLog Makefile.in makefile.pc \ + configure configure.in \ + tar.h fnmatch.h pathmax.h port.h open3.h getopt.h regex.h \ + rmt.h rmt.c rtapelib.c \ + msd_dir.h msd_dir.c tcexparg.c \ + level-0 level-1 backup-specs dump-remind getpagesize.h +# tar.texinfo tar.info* texinfo.tex \ + +all: tar rmt +# tar.info + +.c.o: + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(DEFS) -I$(srcdir) -I. $< + +tar: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +rmt: rmt.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(srcdir)/rmt.c $(LIBS) + +tar.info: tar.texinfo + makeinfo $(srcdir)/tar.texinfo + +install: all + $(INSTALL_PROGRAM) tar $(bindir)/$(binprefix)tar + -test ! -f rmt || $(INSTALL_PROGRAM) rmt $(libdir)/rmt +# for file in $(srcdir)/tar.info*; \ +# do $(INSTALL_DATA) $$file $(infodir)/$$file; \ +# done + +uninstall: + rm -f $(bindir)/$(binprefix)tar $(infodir)/tar.info* + -rm -f $(libdir)/rmt + +$(OBJS): tar.h pathmax.h port.h +regex.o buffer.o tar.o: regex.h +tar.o fnmatch.o: fnmatch.h + +getdate.c: getdate.y + $(YACC) $(srcdir)/getdate.y + mv y.tab.c getdate.c +# getdate.y has 8 shift/reduce conflicts. + +TAGS: $(SRCS) + etags $(SRCS) + +clean: + rm -f *.o tar rmt core +mostlyclean: clean + +distclean: clean + rm -f Makefile config.status + +realclean: distclean + rm -f TAGS *.info* getdate.c y.tab.c + +shar: $(SRCS) $(AUX) + shar $(SRCS) $(AUX) | gzip > tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c`.shar.z + +dist: $(SRCS) $(AUX) + echo tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c` > .fname + -rm -rf `cat .fname` + mkdir `cat .fname` + for file in $(SRCS) $(AUX); do \ + ln $$file `cat .fname` || cp $$file `cat .fname`; done + tar chzf `cat .fname`.tar.z `cat .fname` + -rm -rf `cat .fname` .fname + +tar.zoo: $(SRCS) $(AUX) + -rm -rf tmp.dir + -mkdir tmp.dir + -rm tar.zoo + for X in $(SRCS) $(AUX) ; do echo $$X ; sed 's/$$/ /' $$X > tmp.dir/$$X ; done + cd tmp.dir ; zoo aM ../tar.zoo * + -rm -rf tmp.dir + +# Prevent GNU make v3 from overflowing arg limit on SysV. +.NOEXPORT: diff --git a/gnu/usr.bin/tar/README b/gnu/usr.bin/tar/README new file mode 100644 index 0000000000..4b577e78eb --- /dev/null +++ b/gnu/usr.bin/tar/README @@ -0,0 +1,40 @@ +Hey! Emacs! Yo! This is -*- Text -*- !!! + +This GNU tar 1.11.2. Please send bug reports, etc., to +bug-gnu-utils@prep.ai.mit.edu. This is a beta-test release. Please +try it out. There is no manual; the release of version 1.12 will +contain a manual. + +GNU tar is based heavily on John Gilmore's public domain tar, but with +added features. The manual is currently being written. + +This distribution also includes rmt, the remote tape server (which +normally must reside in /etc). The mt tape drive control program is +in the GNU cpio distribution. + +See the file INSTALL for compilation and installation instructions for Unix. +See the file NEWS for information on all that is new in this version +of tar. + +makefile.pc is a makefile for Turbo C 2.0 on MS-DOS. + +Various people have been having problems using floppies on a NeXT. In +order to have them work right, you need to kill the automounting +program which tries to monut floppies as soon as they are added. + +If you want to do incremental dumps, use the distributed backup +scripts. They are what we use at the FSF to do all our backups. Most +importantly, do not use --incremental (-G) or --after-date (-N) or +--newer-mtime to do incremental dumps. The only option that works +correctly for this purpose is --listed-incremental. (When extracting +incremental dumps, use --incremental (-G).) + +If your system needs to link with -lPW to get alloca, but has +rename in the C library (so HAVE_RENAME is defined), -lPW might +give you an incorrect version of rename. On HP-UX this manifests +itself as an undefined data symbol called "Error" when linking cp, ln, +and mv. If this happens, use `ar x' to extract alloca.o from libPW.a +and `ar rc' to put it in a library liballoca.a, and put that in LIBS +instead of -lPW. This problem does not occur when using gcc, which +has alloca built in. + diff --git a/gnu/usr.bin/tar/buffer.c b/gnu/usr.bin/tar/buffer.c new file mode 100644 index 0000000000..e0ffc2d286 --- /dev/null +++ b/gnu/usr.bin/tar/buffer.c @@ -0,0 +1,1584 @@ +/* Buffer management for tar. + Copyright (C) 1988, 1992, 1993 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Buffer management for tar. + * + * Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985. + */ + +#include +#include +#ifndef STDC_HEADERS +extern int errno; +#endif +#include /* For non-Berkeley systems */ +#include +#include +time_t time (); + +#ifdef HAVE_SYS_MTIO_H +#include +#include +#endif + +#ifdef BSD42 +#include +#else +#ifndef V7 +#include +#endif +#endif + +#ifdef __MSDOS__ +#include +#endif + +#ifdef XENIX +#include +#endif + +#include "tar.h" +#include "port.h" +#include "rmt.h" +#include "regex.h" + +/* Either stdout or stderr: The thing we write messages (standard msgs, not + errors) to. Stdout unless we're writing a pipe, in which case stderr */ +FILE *msg_file = stdout; + +#define STDIN 0 /* Standard input file descriptor */ +#define STDOUT 1 /* Standard output file descriptor */ + +#define PREAD 0 /* Read file descriptor from pipe() */ +#define PWRITE 1 /* Write file descriptor from pipe() */ + +#define MAGIC_STAT 105 /* Magic status returned by child, if + it can't exec. We hope compress/sh + never return this status! */ + +void *valloc (); + +void writeerror (); +void readerror (); + +void ck_pipe (); +void ck_close (); + +int backspace_output (); +extern void finish_header (); +void flush_archive (); +int isfile (); +int new_volume (); +void verify_volume (); +extern void to_oct (); + +#ifndef __MSDOS__ +/* Obnoxious test to see if dimwit is trying to dump the archive */ +dev_t ar_dev; +ino_t ar_ino; +#endif + +/* + * The record pointed to by save_rec should not be overlaid + * when reading in a new tape block. Copy it to record_save_area first, and + * change the pointer in *save_rec to point to record_save_area. + * Saved_recno records the record number at the time of the save. + * This is used by annofile() to print the record number of a file's + * header record. + */ +static union record **save_rec; +union record record_save_area; +static long saved_recno; + +/* + * PID of child program, if f_compress or remote archive access. + */ +static int childpid = 0; + +/* + * Record number of the start of this block of records + */ +long baserec; + +/* + * Error recovery stuff + */ +static int r_error_count; + +/* + * Have we hit EOF yet? + */ +static int hit_eof; + +/* Checkpointing counter */ +static int checkpoint; + +/* JF we're reading, but we just read the last record and its time to update */ +extern time_to_start_writing; +int file_to_switch_to = -1; /* If remote update, close archive, and use + this descriptor to write to */ + +static int volno = 1; /* JF which volume of a multi-volume tape + we're on */ +static int global_volno = 1; /* Volume number to print in external messages. */ + +char *save_name = 0; /* Name of the file we are currently writing */ +long save_totsize; /* total size of file we are writing. Only + valid if save_name is non_zero */ +long save_sizeleft; /* Where we are in the file we are writing. + Only valid if save_name is non-zero */ + +int write_archive_to_stdout; + +/* Used by fl_read and fl_write to store the real info about saved names */ +static char real_s_name[NAMSIZ]; +static long real_s_totsize; +static long real_s_sizeleft; + +/* Reset the EOF flag (if set), and re-set ar_record, etc */ + +void +reset_eof () +{ + if (hit_eof) + { + hit_eof = 0; + ar_record = ar_block; + ar_last = ar_block + blocking; + ar_reading = 0; + } +} + +/* + * Return the location of the next available input or output record. + * Return NULL for EOF. Once we have returned NULL, we just keep returning + * it, to avoid accidentally going on to the next file on the "tape". + */ +union record * +findrec () +{ + if (ar_record == ar_last) + { + if (hit_eof) + return (union record *) NULL; /* EOF */ + flush_archive (); + if (ar_record == ar_last) + { + hit_eof++; + return (union record *) NULL; /* EOF */ + } + } + return ar_record; +} + + +/* + * Indicate that we have used all records up thru the argument. + * (should the arg have an off-by-1? XXX FIXME) + */ +void +userec (rec) + union record *rec; +{ + while (rec >= ar_record) + ar_record++; + /* + * Do NOT flush the archive here. If we do, the same + * argument to userec() could mean the next record (if the + * input block is exactly one record long), which is not what + * is intended. + */ + if (ar_record > ar_last) + abort (); +} + + +/* + * Return a pointer to the end of the current records buffer. + * All the space between findrec() and endofrecs() is available + * for filling with data, or taking data from. + */ +union record * +endofrecs () +{ + return ar_last; +} + + +/* + * Duplicate a file descriptor into a certain slot. + * Equivalent to BSD "dup2" with error reporting. + */ +void +dupto (from, to, msg) + int from, to; + char *msg; +{ + int err; + + if (from != to) + { + err = close (to); + if (err < 0 && errno != EBADF) + { + msg_perror ("Cannot close descriptor %d", to); + exit (EX_SYSTEM); + } + err = dup (from); + if (err != to) + { + msg_perror ("cannot dup %s", msg); + exit (EX_SYSTEM); + } + ck_close (from); + } +} + +#ifdef __MSDOS__ +void +child_open () +{ + fprintf (stderr, "MS-DOS %s can't use compressed or remote archives\n", tar); + exit (EX_ARGSBAD); +} + +#else +void +child_open () +{ + int pipe[2]; + int err = 0; + + int kidpipe[2]; + int kidchildpid; + +#define READ 0 +#define WRITE 1 + + ck_pipe (pipe); + + childpid = fork (); + if (childpid < 0) + { + msg_perror ("cannot fork"); + exit (EX_SYSTEM); + } + if (childpid > 0) + { + /* We're the parent. Clean up and be happy */ + /* This, at least, is easy */ + + if (ar_reading) + { + f_reblock++; + archive = pipe[READ]; + ck_close (pipe[WRITE]); + } + else + { + archive = pipe[WRITE]; + ck_close (pipe[READ]); + } + return; + } + + /* We're the kid */ + if (ar_reading) + { + dupto (pipe[WRITE], STDOUT, "(child) pipe to stdout"); + ck_close (pipe[READ]); + } + else + { + dupto (pipe[READ], STDIN, "(child) pipe to stdin"); + ck_close (pipe[WRITE]); + } + + /* We need a child tar only if + 1: we're reading/writing stdin/out (to force reblocking) + 2: the file is to be accessed by rmt (compress doesn't know how) + 3: the file is not a plain file */ +#ifdef NO_REMOTE + if (!(ar_files[0][0] == '-' && ar_files[0][1] == '\0') && isfile (ar_files[0])) +#else + if (!(ar_files[0][0] == '-' && ar_files[0][1] == '\0') && !_remdev (ar_files[0]) && isfile (ar_files[0])) +#endif + { + /* We don't need a child tar. Open the archive */ + if (ar_reading) + { + archive = open (ar_files[0], O_RDONLY | O_BINARY, 0666); + if (archive < 0) + { + msg_perror ("can't open archive %s", ar_files[0]); + exit (EX_BADARCH); + } + dupto (archive, STDIN, "archive to stdin"); + /* close(archive); */ + } + else + { + archive = creat (ar_files[0], 0666); + if (archive < 0) + { + msg_perror ("can't open archive %s", ar_files[0]); + exit (EX_BADARCH); + } + dupto (archive, STDOUT, "archive to stdout"); + /* close(archive); */ + } + } + else + { + /* We need a child tar */ + ck_pipe (kidpipe); + + kidchildpid = fork (); + if (kidchildpid < 0) + { + msg_perror ("child can't fork"); + exit (EX_SYSTEM); + } + + if (kidchildpid > 0) + { + /* About to exec compress: set up the files */ + if (ar_reading) + { + dupto (kidpipe[READ], STDIN, "((child)) pipe to stdin"); + ck_close (kidpipe[WRITE]); + /* dup2(pipe[WRITE],STDOUT); */ + } + else + { + /* dup2(pipe[READ],STDIN); */ + dupto (kidpipe[WRITE], STDOUT, "((child)) pipe to stdout"); + ck_close (kidpipe[READ]); + } + /* ck_close(pipe[READ]); */ + /* ck_close(pipe[WRITE]); */ + /* ck_close(kidpipe[READ]); + ck_close(kidpipe[WRITE]); */ + } + else + { + /* Grandchild. Do the right thing, namely sit here and + read/write the archive, and feed stuff back to compress */ + tar = "tar (child)"; + if (ar_reading) + { + dupto (kidpipe[WRITE], STDOUT, "[child] pipe to stdout"); + ck_close (kidpipe[READ]); + } + else + { + dupto (kidpipe[READ], STDIN, "[child] pipe to stdin"); + ck_close (kidpipe[WRITE]); + } + + if (ar_files[0][0] == '-' && ar_files[0][1] == '\0') + { + if (ar_reading) + archive = STDIN; + else + archive = STDOUT; + } + else /* This can't happen if (ar_reading==2) + archive = rmtopen(ar_files[0], O_RDWR|O_CREAT|O_BINARY, 0666); + else */ if (ar_reading) + archive = rmtopen (ar_files[0], O_RDONLY | O_BINARY, 0666); + else + archive = rmtcreat (ar_files[0], 0666); + + if (archive < 0) + { + msg_perror ("can't open archive %s", ar_files[0]); + exit (EX_BADARCH); + } + + if (ar_reading) + { + for (;;) + { + char *ptr; + int max, count; + + r_error_count = 0; + error_loop: + err = rmtread (archive, ar_block->charptr, (int) (blocksize)); + if (err < 0) + { + readerror (); + goto error_loop; + } + if (err == 0) + break; + ptr = ar_block->charptr; + max = err; + while (max) + { + count = (max < RECORDSIZE) ? max : RECORDSIZE; + err = write (STDOUT, ptr, count); + if (err != count) + { + if (err < 0) + { + msg_perror ("can't write to compression program"); + exit (EX_SYSTEM); + } + else + msg ("write to compression program short %d bytes", + count - err); + count = (err < 0) ? 0 : err; + } + ptr += count; + max -= count; + } + } + } + else + { + for (;;) + { + int n; + char *ptr; + + n = blocksize; + ptr = ar_block->charptr; + while (n) + { + err = read (STDIN, ptr, (n < RECORDSIZE) ? n : RECORDSIZE); + if (err <= 0) + break; + n -= err; + ptr += err; + } + /* EOF */ + if (err == 0) + { + if (!f_compress_block) + blocksize -= n; + else + bzero (ar_block->charptr + blocksize - n, n); + err = rmtwrite (archive, ar_block->charptr, blocksize); + if (err != (blocksize)) + writeerror (err); + if (!f_compress_block) + blocksize += n; + break; + } + if (n) + { + msg_perror ("can't read from compression program"); + exit (EX_SYSTEM); + } + err = rmtwrite (archive, ar_block->charptr, (int) blocksize); + if (err != blocksize) + writeerror (err); + } + } + + /* close_archive(); */ + exit (0); + } + } + /* So we should exec compress (-d) */ + if (ar_reading) + execlp (f_compressprog, f_compressprog, "-d", (char *) 0); + else + execlp (f_compressprog, f_compressprog, (char *) 0); + msg_perror ("can't exec %s", f_compressprog); + _exit (EX_SYSTEM); +} + + +/* return non-zero if p is the name of a directory */ +int +isfile (p) + char *p; +{ + struct stat stbuf; + + if (stat (p, &stbuf) < 0) + return 1; + if (S_ISREG (stbuf.st_mode)) + return 1; + return 0; +} + +#endif + +/* + * Open an archive file. The argument specifies whether we are + * reading or writing. + */ +/* JF if the arg is 2, open for reading and writing. */ +void +open_archive (reading) + int reading; +{ + msg_file = f_exstdout ? stderr : stdout; + + if (blocksize == 0) + { + msg ("invalid value for blocksize"); + exit (EX_ARGSBAD); + } + + if (n_ar_files == 0) + { + msg ("No archive name given, what should I do?"); + exit (EX_BADARCH); + } + + /*NOSTRICT*/ + if (f_multivol) + { + ar_block = (union record *) valloc ((unsigned) (blocksize + (2 * RECORDSIZE))); + if (ar_block) + ar_block += 2; + } + else + ar_block = (union record *) valloc ((unsigned) blocksize); + if (!ar_block) + { + msg ("could not allocate memory for blocking factor %d", + blocking); + exit (EX_ARGSBAD); + } + + ar_record = ar_block; + ar_last = ar_block + blocking; + ar_reading = reading; + + if (f_multivol && f_verify) + { + msg ("cannot verify multi-volume archives"); + exit (EX_ARGSBAD); + } + + if (f_compressprog) + { + if (reading == 2 || f_verify) + { + msg ("cannot update or verify compressed archives"); + exit (EX_ARGSBAD); + } + if (f_multivol) + { + msg ("cannot use multi-volume compressed archives"); + exit (EX_ARGSBAD); + } + child_open (); + if (!reading && ar_files[0][0] == '-' && ar_files[0][1] == '\0') + msg_file = stderr; + /* child_open(rem_host, rem_file); */ + } + else if (ar_files[0][0] == '-' && ar_files[0][1] == '\0') + { + f_reblock++; /* Could be a pipe, be safe */ + if (f_verify) + { + msg ("can't verify stdin/stdout archive"); + exit (EX_ARGSBAD); + } + if (reading == 2) + { + archive = STDIN; + msg_file = stderr; + write_archive_to_stdout++; + } + else if (reading) + archive = STDIN; + else + { + archive = STDOUT; + msg_file = stderr; + } + } + else if (reading == 2 || f_verify) + { + archive = rmtopen (ar_files[0], O_RDWR | O_CREAT | O_BINARY, 0666); + } + else if (reading) + { + archive = rmtopen (ar_files[0], O_RDONLY | O_BINARY, 0666); + } + else + { + archive = rmtcreat (ar_files[0], 0666); + } + if (archive < 0) + { + msg_perror ("can't open %s", ar_files[0]); + exit (EX_BADARCH); + } +#ifndef __MSDOS__ + if (!_isrmt (archive)) + { + struct stat tmp_stat; + + fstat (archive, &tmp_stat); + if (S_ISREG (tmp_stat.st_mode)) + { + ar_dev = tmp_stat.st_dev; + ar_ino = tmp_stat.st_ino; + } + } +#endif + +#ifdef __MSDOS__ + setmode (archive, O_BINARY); +#endif + + if (reading) + { + ar_last = ar_block; /* Set up for 1st block = # 0 */ + (void) findrec (); /* Read it in, check for EOF */ + + if (f_volhdr) + { + union record *head; +#if 0 + char *ptr; + + if (f_multivol) + { + ptr = malloc (strlen (f_volhdr) + 20); + sprintf (ptr, "%s Volume %d", f_volhdr, 1); + } + else + ptr = f_volhdr; +#endif + head = findrec (); + if (!head) + { + msg ("Archive not labelled to match %s", f_volhdr); + exit (EX_BADVOL); + } + if (re_match (label_pattern, head->header.arch_name, + strlen (head->header.arch_name), 0, 0) < 0) + { + msg ("Volume mismatch! %s!=%s", f_volhdr, + head->header.arch_name); + exit (EX_BADVOL); + } +#if 0 + if (strcmp (ptr, head->header.name)) + { + msg ("Volume mismatch! %s!=%s", ptr, head->header.name); + exit (EX_BADVOL); + } + if (ptr != f_volhdr) + free (ptr); +#endif + } + } + else if (f_volhdr) + { + bzero ((void *) ar_block, RECORDSIZE); + if (f_multivol) + sprintf (ar_block->header.arch_name, "%s Volume 1", f_volhdr); + else + strcpy (ar_block->header.arch_name, f_volhdr); + current_file_name = ar_block->header.arch_name; + ar_block->header.linkflag = LF_VOLHDR; + to_oct (time (0), 1 + 12, ar_block->header.mtime); + finish_header (ar_block); + /* ar_record++; */ + } +} + + +/* + * Remember a union record * as pointing to something that we + * need to keep when reading onward in the file. Only one such + * thing can be remembered at once, and it only works when reading + * an archive. + * + * We calculate "offset" then add it because some compilers end up + * adding (baserec+ar_record), doing a 9-bit shift of baserec, then + * subtracting ar_block from that, shifting it back, losing the top 9 bits. + */ +void +saverec (pointer) + union record **pointer; +{ + long offset; + + save_rec = pointer; + offset = ar_record - ar_block; + saved_recno = baserec + offset; +} + +/* + * Perform a write to flush the buffer. + */ + +/*send_buffer_to_file(); + if(new_volume) { + deal_with_new_volume_stuff(); + send_buffer_to_file(); + } + */ + +void +fl_write () +{ + int err; + int copy_back; + static long bytes_written = 0; + + if (f_checkpoint && !(++checkpoint % 10)) + msg ("Write checkpoint %d\n", checkpoint); + if (tape_length && bytes_written >= tape_length * 1024) + { + errno = ENOSPC; + err = 0; + } + else + err = rmtwrite (archive, ar_block->charptr, (int) blocksize); + if (err != blocksize && !f_multivol) + writeerror (err); + else if (f_totals) + tot_written += blocksize; + + if (err > 0) + bytes_written += err; + if (err == blocksize) + { + if (f_multivol) + { + if (!save_name) + { + real_s_name[0] = '\0'; + real_s_totsize = 0; + real_s_sizeleft = 0; + return; + } +#ifdef __MSDOS__ + if (save_name[1] == ':') + save_name += 2; +#endif + while (*save_name == '/') + save_name++; + + strcpy (real_s_name, save_name); + real_s_totsize = save_totsize; + real_s_sizeleft = save_sizeleft; + } + return; + } + + /* We're multivol Panic if we didn't get the right kind of response */ + /* ENXIO is for the UNIX PC */ + if (err < 0 && errno != ENOSPC && errno != EIO && errno != ENXIO) + writeerror (err); + + /* If error indicates a short write, we just move to the next tape. */ + + if (new_volume (0) < 0) + return; + bytes_written = 0; + if (f_volhdr && real_s_name[0]) + { + copy_back = 2; + ar_block -= 2; + } + else if (f_volhdr || real_s_name[0]) + { + copy_back = 1; + ar_block--; + } + else + copy_back = 0; + if (f_volhdr) + { + bzero ((void *) ar_block, RECORDSIZE); + sprintf (ar_block->header.arch_name, "%s Volume %d", f_volhdr, volno); + to_oct (time (0), 1 + 12, ar_block->header.mtime); + ar_block->header.linkflag = LF_VOLHDR; + finish_header (ar_block); + } + if (real_s_name[0]) + { + int tmp; + + if (f_volhdr) + ar_block++; + bzero ((void *) ar_block, RECORDSIZE); + strcpy (ar_block->header.arch_name, real_s_name); + ar_block->header.linkflag = LF_MULTIVOL; + to_oct ((long) real_s_sizeleft, 1 + 12, + ar_block->header.size); + to_oct ((long) real_s_totsize - real_s_sizeleft, + 1 + 12, ar_block->header.offset); + tmp = f_verbose; + f_verbose = 0; + finish_header (ar_block); + f_verbose = tmp; + if (f_volhdr) + ar_block--; + } + + err = rmtwrite (archive, ar_block->charptr, (int) blocksize); + if (err != blocksize) + writeerror (err); + else if (f_totals) + tot_written += blocksize; + + + bytes_written = blocksize; + if (copy_back) + { + ar_block += copy_back; + bcopy ((void *) (ar_block + blocking - copy_back), + (void *) ar_record, + copy_back * RECORDSIZE); + ar_record += copy_back; + + if (real_s_sizeleft >= copy_back * RECORDSIZE) + real_s_sizeleft -= copy_back * RECORDSIZE; + else if ((real_s_sizeleft + RECORDSIZE - 1) / RECORDSIZE <= copy_back) + real_s_name[0] = '\0'; + else + { +#ifdef __MSDOS__ + if (save_name[1] == ':') + save_name += 2; +#endif + while (*save_name == '/') + save_name++; + + strcpy (real_s_name, save_name); + real_s_sizeleft = save_sizeleft; + real_s_totsize = save_totsize; + } + copy_back = 0; + } +} + +/* Handle write errors on the archive. Write errors are always fatal */ +/* Hitting the end of a volume does not cause a write error unless the write +* was the first block of the volume */ + +void +writeerror (err) + int err; +{ + if (err < 0) + { + msg_perror ("can't write to %s", ar_files[cur_ar_file]); + exit (EX_BADARCH); + } + else + { + msg ("only wrote %u of %u bytes to %s", err, blocksize, ar_files[cur_ar_file]); + exit (EX_BADARCH); + } +} + +/* + * Handle read errors on the archive. + * + * If the read should be retried, readerror() returns to the caller. + */ +void +readerror () +{ +# define READ_ERROR_MAX 10 + + read_error_flag++; /* Tell callers */ + + msg_perror ("read error on %s", ar_files[cur_ar_file]); + + if (baserec == 0) + { + /* First block of tape. Probably stupidity error */ + exit (EX_BADARCH); + } + + /* + * Read error in mid archive. We retry up to READ_ERROR_MAX times + * and then give up on reading the archive. We set read_error_flag + * for our callers, so they can cope if they want. + */ + if (r_error_count++ > READ_ERROR_MAX) + { + msg ("Too many errors, quitting."); + exit (EX_BADARCH); + } + return; +} + + +/* + * Perform a read to flush the buffer. + */ +void +fl_read () +{ + int err; /* Result from system call */ + int left; /* Bytes left */ + char *more; /* Pointer to next byte to read */ + + if (f_checkpoint && !(++checkpoint % 10)) + msg ("Read checkpoint %d\n", checkpoint); + + /* + * Clear the count of errors. This only applies to a single + * call to fl_read. We leave read_error_flag alone; it is + * only turned off by higher level software. + */ + r_error_count = 0; /* Clear error count */ + + /* + * If we are about to wipe out a record that + * somebody needs to keep, copy it out to a holding + * area and adjust somebody's pointer to it. + */ + if (save_rec && + *save_rec >= ar_record && + *save_rec < ar_last) + { + record_save_area = **save_rec; + *save_rec = &record_save_area; + } + if (write_archive_to_stdout && baserec != 0) + { + err = rmtwrite (1, ar_block->charptr, blocksize); + if (err != blocksize) + writeerror (err); + } + if (f_multivol) + { + if (save_name) + { + if (save_name != real_s_name) + { +#ifdef __MSDOS__ + if (save_name[1] == ':') + save_name += 2; +#endif + while (*save_name == '/') + save_name++; + + strcpy (real_s_name, save_name); + save_name = real_s_name; + } + real_s_totsize = save_totsize; + real_s_sizeleft = save_sizeleft; + + } + else + { + real_s_name[0] = '\0'; + real_s_totsize = 0; + real_s_sizeleft = 0; + } + } + +error_loop: + err = rmtread (archive, ar_block->charptr, (int) blocksize); + if (err == blocksize) + return; + + if ((err == 0 || (err < 0 && errno == ENOSPC) || (err > 0 && !f_reblock)) && f_multivol) + { + union record *head; + + try_volume: + if (new_volume ((cmd_mode == CMD_APPEND || cmd_mode == CMD_CAT || cmd_mode == CMD_UPDATE) ? 2 : 1) < 0) + return; + vol_error: + err = rmtread (archive, ar_block->charptr, (int) blocksize); + if (err < 0) + { + readerror (); + goto vol_error; + } + if (err != blocksize) + goto short_read; + + head = ar_block; + + if (head->header.linkflag == LF_VOLHDR) + { + if (f_volhdr) + { +#if 0 + char *ptr; + + ptr = (char *) malloc (strlen (f_volhdr) + 20); + sprintf (ptr, "%s Volume %d", f_volhdr, volno); +#endif + if (re_match (label_pattern, head->header.arch_name, + strlen (head->header.arch_name), + 0, 0) < 0) + { + msg ("Volume mismatch! %s!=%s", f_volhdr, + head->header.arch_name); + --volno; + --global_volno; + goto try_volume; + } + +#if 0 + if (strcmp (ptr, head->header.name)) + { + msg ("Volume mismatch! %s!=%s", ptr, head->header.name); + --volno; + --global_volno; + free (ptr); + goto try_volume; + } + free (ptr); +#endif + } + if (f_verbose) + fprintf (msg_file, "Reading %s\n", head->header.arch_name); + head++; + } + else if (f_volhdr) + { + msg ("Warning: No volume header!"); + } + + if (real_s_name[0]) + { + long from_oct (); + + if (head->header.linkflag != LF_MULTIVOL || strcmp (head->header.arch_name, real_s_name)) + { + msg ("%s is not continued on this volume!", real_s_name); + --volno; + --global_volno; + goto try_volume; + } + if (real_s_totsize != from_oct (1 + 12, head->header.size) + from_oct (1 + 12, head->header.offset)) + { + msg ("%s is the wrong size (%ld!=%ld+%ld)", + head->header.arch_name, save_totsize, + from_oct (1 + 12, head->header.size), + from_oct (1 + 12, head->header.offset)); + --volno; + --global_volno; + goto try_volume; + } + if (real_s_totsize - real_s_sizeleft != from_oct (1 + 12, head->header.offset)) + { + msg ("This volume is out of sequence"); + --volno; + --global_volno; + goto try_volume; + } + head++; + } + ar_record = head; + return; + } + else if (err < 0) + { + readerror (); + goto error_loop; /* Try again */ + } + +short_read: + more = ar_block->charptr + err; + left = blocksize - err; + +again: + if (0 == (((unsigned) left) % RECORDSIZE)) + { + /* FIXME, for size=0, multi vol support */ + /* On the first block, warn about the problem */ + if (!f_reblock && baserec == 0 && f_verbose && err > 0) + { + /* msg("Blocksize = %d record%s", + err / RECORDSIZE, (err > RECORDSIZE)? "s": "");*/ + msg ("Blocksize = %d records", err / RECORDSIZE); + } + ar_last = ar_block + ((unsigned) (blocksize - left)) / RECORDSIZE; + return; + } + if (f_reblock) + { + /* + * User warned us about this. Fix up. + */ + if (left > 0) + { + error2loop: + err = rmtread (archive, more, (int) left); + if (err < 0) + { + readerror (); + goto error2loop; /* Try again */ + } + if (err == 0) + { + msg ("archive %s EOF not on block boundary", ar_files[cur_ar_file]); + exit (EX_BADARCH); + } + left -= err; + more += err; + goto again; + } + } + else + { + msg ("only read %d bytes from archive %s", err, ar_files[cur_ar_file]); + exit (EX_BADARCH); + } +} + + +/* + * Flush the current buffer to/from the archive. + */ +void +flush_archive () +{ + int c; + + baserec += ar_last - ar_block;/* Keep track of block #s */ + ar_record = ar_block; /* Restore pointer to start */ + ar_last = ar_block + blocking;/* Restore pointer to end */ + + if (ar_reading) + { + if (time_to_start_writing) + { + time_to_start_writing = 0; + ar_reading = 0; + + if (file_to_switch_to >= 0) + { + if ((c = rmtclose (archive)) < 0) + msg_perror ("Warning: can't close %s(%d,%d)", ar_files[cur_ar_file], archive, c); + + archive = file_to_switch_to; + } + else + (void) backspace_output (); + fl_write (); + } + else + fl_read (); + } + else + { + fl_write (); + } +} + +/* Backspace the archive descriptor by one blocks worth. + If its a tape, MTIOCTOP will work. If its something else, + we try to seek on it. If we can't seek, we lose! */ +int +backspace_output () +{ + long cur; + /* int er; */ + extern char *output_start; + +#ifdef MTIOCTOP + struct mtop t; + + t.mt_op = MTBSR; + t.mt_count = 1; + if ((rmtioctl (archive, MTIOCTOP, &t)) >= 0) + return 1; + if (errno == EIO && (rmtioctl (archive, MTIOCTOP, &t)) >= 0) + return 1; +#endif + + cur = rmtlseek (archive, 0L, 1); + cur -= blocksize; + /* Seek back to the beginning of this block and + start writing there. */ + + if (rmtlseek (archive, cur, 0) != cur) + { + /* Lseek failed. Try a different method */ + msg ("Couldn't backspace archive file. It may be unreadable without -i."); + /* Replace the first part of the block with nulls */ + if (ar_block->charptr != output_start) + bzero (ar_block->charptr, output_start - ar_block->charptr); + return 2; + } + return 3; +} + + +/* + * Close the archive file. + */ +void +close_archive () +{ + int child; + int status; + int c; + + if (time_to_start_writing || !ar_reading) + flush_archive (); + if (cmd_mode == CMD_DELETE) + { + off_t pos; + + pos = rmtlseek (archive, 0L, 1); +#ifndef __MSDOS__ + (void) ftruncate (archive, pos); +#else + (void) rmtwrite (archive, "", 0); +#endif + } + if (f_verify) + verify_volume (); + + if ((c = rmtclose (archive)) < 0) + msg_perror ("Warning: can't close %s(%d,%d)", ar_files[cur_ar_file], archive, c); + +#ifndef __MSDOS__ + if (childpid) + { + /* + * Loop waiting for the right child to die, or for + * no more kids. + */ + while (((child = wait (&status)) != childpid) && child != -1) + ; + + if (child != -1) + { + if (WIFSIGNALED (status)) + { + /* SIGPIPE is OK, everything else is a problem. */ + if (WTERMSIG (status) != SIGPIPE) + msg ("child died with signal %d%s", WTERMSIG (status), + WIFCOREDUMPED (status) ? " (core dumped)" : ""); + } + else + { + /* Child voluntarily terminated -- but why? */ + if (WEXITSTATUS (status) == MAGIC_STAT) + { + exit (EX_SYSTEM); /* Child had trouble */ + } + if (WEXITSTATUS (status) == (SIGPIPE + 128)) + { + /* + * /bin/sh returns this if its child + * dies with SIGPIPE. 'Sok. + */ + /* Do nothing. */ + } + else if (WEXITSTATUS (status)) + msg ("child returned status %d", + WEXITSTATUS (status)); + } + } + } +#endif /* __MSDOS__ */ +} + + +#ifdef DONTDEF +/* + * Message management. + * + * anno writes a message prefix on stream (eg stdout, stderr). + * + * The specified prefix is normally output followed by a colon and a space. + * However, if other command line options are set, more output can come + * out, such as the record # within the archive. + * + * If the specified prefix is NULL, no output is produced unless the + * command line option(s) are set. + * + * If the third argument is 1, the "saved" record # is used; if 0, the + * "current" record # is used. + */ +void +anno (stream, prefix, savedp) + FILE *stream; + char *prefix; + int savedp; +{ +# define MAXANNO 50 + char buffer[MAXANNO]; /* Holds annorecment */ +# define ANNOWIDTH 13 + int space; + long offset; + int save_e; + + save_e = errno; + /* Make sure previous output gets out in sequence */ + if (stream == stderr) + fflush (stdout); + if (f_sayblock) + { + if (prefix) + { + fputs (prefix, stream); + putc (' ', stream); + } + offset = ar_record - ar_block; + (void) sprintf (buffer, "rec %d: ", + savedp ? saved_recno : + baserec + offset); + fputs (buffer, stream); + space = ANNOWIDTH - strlen (buffer); + if (space > 0) + { + fprintf (stream, "%*s", space, ""); + } + } + else if (prefix) + { + fputs (prefix, stream); + fputs (": ", stream); + } + errno = save_e; +} + +#endif + +/* Called to initialize the global volume number. */ +void +init_volume_number () +{ + FILE *vf; + + vf = fopen (f_volno_file, "r"); + if (!vf && errno != ENOENT) + msg_perror ("%s", f_volno_file); + + if (vf) + { + fscanf (vf, "%d", &global_volno); + fclose (vf); + } +} + +/* Called to write out the closing global volume number. */ +void +closeout_volume_number () +{ + FILE *vf; + + vf = fopen (f_volno_file, "w"); + if (!vf) + msg_perror ("%s", f_volno_file); + else + { + fprintf (vf, "%d\n", global_volno); + fclose (vf); + } +} + +/* We've hit the end of the old volume. Close it and open the next one */ +/* Values for type: 0: writing 1: reading 2: updating */ +int +new_volume (type) + int type; +{ + int c; + char inbuf[80]; + char *p; + static FILE *read_file = 0; + extern int now_verifying; + extern char TTY_NAME[]; + static int looped = 0; + + if (!read_file && !f_run_script_at_end) + read_file = (archive == 0) ? fopen (TTY_NAME, "r") : stdin; + + if (now_verifying) + return -1; + if (f_verify) + verify_volume (); + if ((c = rmtclose (archive)) < 0) + msg_perror ("Warning: can't close %s(%d,%d)", ar_files[cur_ar_file], archive, c); + + global_volno++; + volno++; + cur_ar_file++; + if (cur_ar_file == n_ar_files) + { + cur_ar_file = 0; + looped = 1; + } + +tryagain: + if (looped) + { + /* We have to prompt from now on. */ + if (f_run_script_at_end) + { + closeout_volume_number (); + system (info_script); + } + else + for (;;) + { + fprintf (msg_file, "\007Prepare volume #%d for %s and hit return: ", global_volno, ar_files[cur_ar_file]); + fflush (msg_file); + if (fgets (inbuf, sizeof (inbuf), read_file) == 0) + { + fprintf (msg_file, "EOF? What does that mean?"); + if (cmd_mode != CMD_EXTRACT && cmd_mode != CMD_LIST && cmd_mode != CMD_DIFF) + msg ("Warning: Archive is INCOMPLETE!"); + exit (EX_BADARCH); + } + if (inbuf[0] == '\n' || inbuf[0] == 'y' || inbuf[0] == 'Y') + break; + + switch (inbuf[0]) + { + case '?': + { + fprintf (msg_file, "\ + n [name] Give a new filename for the next (and subsequent) volume(s)\n\ + q Abort tar\n\ + ! Spawn a subshell\n\ + ? Print this list\n"); + } + break; + + case 'q': /* Quit */ + fprintf (msg_file, "No new volume; exiting.\n"); + if (cmd_mode != CMD_EXTRACT && cmd_mode != CMD_LIST && cmd_mode != CMD_DIFF) + msg ("Warning: Archive is INCOMPLETE!"); + exit (EX_BADARCH); + + case 'n': /* Get new file name */ + { + char *q, *r; + static char *old_name; + + for (q = &inbuf[1]; *q == ' ' || *q == '\t'; q++) + ; + for (r = q; *r; r++) + if (*r == '\n') + *r = '\0'; + old_name = p = (char *) malloc ((unsigned) (strlen (q) + 2)); + if (p == 0) + { + msg ("Can't allocate memory for name"); + exit (EX_SYSTEM); + } + (void) strcpy (p, q); + ar_files[cur_ar_file] = p; + } + break; + + case '!': +#ifdef __MSDOS__ + spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0); +#else + /* JF this needs work! */ + switch (fork ()) + { + case -1: + msg_perror ("can't fork!"); + break; + case 0: + p = getenv ("SHELL"); + if (p == 0) + p = "/bin/sh"; + execlp (p, "-sh", "-i", 0); + msg_perror ("can't exec a shell %s", p); + _exit (55); + default: + wait (0); + break; + } +#endif + break; + } + } + } + + + if (type == 2 || f_verify) + archive = rmtopen (ar_files[cur_ar_file], O_RDWR | O_CREAT, 0666); + else if (type == 1) + archive = rmtopen (ar_files[cur_ar_file], O_RDONLY, 0666); + else if (type == 0) + archive = rmtcreat (ar_files[cur_ar_file], 0666); + else + archive = -1; + + if (archive < 0) + { + msg_perror ("can't open %s", ar_files[cur_ar_file]); + goto tryagain; + } +#ifdef __MSDOS__ + setmode (archive, O_BINARY); +#endif + return 0; +} + +/* this is a useless function that takes a buffer returned by wantbytes + and does nothing with it. If the function called by wantbytes returns + an error indicator (non-zero), this function is called for the rest of + the file. + */ +int +no_op (size, data) + int size; + char *data; +{ + return 0; +} + +/* Some other routine wants SIZE bytes in the archive. For each chunk of + the archive, call FUNC with the size of the chunk, and the address of + the chunk it can work with. + */ +int +wantbytes (size, func) + long size; + int (*func) (); +{ + char *data; + long data_size; + + while (size) + { + data = findrec ()->charptr; + if (data == NULL) + { /* Check it... */ + msg ("Unexpected EOF on archive file"); + return -1; + } + data_size = endofrecs ()->charptr - data; + if (data_size > size) + data_size = size; + if ((*func) (data_size, data)) + func = no_op; + userec ((union record *) (data + data_size - 1)); + size -= data_size; + } + return 0; +} diff --git a/gnu/usr.bin/tar/create.c b/gnu/usr.bin/tar/create.c new file mode 100644 index 0000000000..62b9c51178 --- /dev/null +++ b/gnu/usr.bin/tar/create.c @@ -0,0 +1,1454 @@ +/* Create a tar archive. + Copyright (C) 1985, 1992, 1993 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Create a tar archive. + * + * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu. + */ + +#ifdef _AIX + #pragma alloca +#endif +#include +#include +#include +#ifndef STDC_HEADERS +extern int errno; +#endif + +#ifdef BSD42 +#include +#else +#ifndef V7 +#include +#endif +#endif + +#include "tar.h" +#include "port.h" + +#ifndef __MSDOS__ +#include +#include +#endif + +#if defined (_POSIX_VERSION) +#include +#else +struct utimbuf +{ + long actime; + long modtime; +}; + +#endif + +extern struct stat hstat; /* Stat struct corresponding */ + +#ifndef __MSDOS__ +extern dev_t ar_dev; +extern ino_t ar_ino; +#endif + +/* JF */ +extern struct name *gnu_list_name; + +/* + * If there are no symbolic links, there is no lstat(). Use stat(). + */ +#ifndef S_ISLNK +#define lstat stat +#endif + +extern void print_header (); + +union record *start_header (); +void blank_name_list (); +int check_exclude (); +PTR ck_malloc (); +PTR ck_realloc (); +void clear_buffer (); +void close_archive (); +void collect_and_sort_names (); +int confirm (); +int deal_with_sparse (); +void find_new_file_size (); +void finish_header (); +int finish_sparse_file (); +void finduname (); +void findgname (); +int is_dot_or_dotdot (); +void open_archive (); +char *name_next (); +void name_close (); +void to_oct (); +void dump_file (); +void write_dir_file (); +void write_eot (); +void write_long (); +int zero_record (); + +/* This code moved from tar.h since create.c is the only file that cares + about 'struct link's. This means that other files might not have to + include sys/types.h any more. */ + +struct link + { + struct link *next; + dev_t dev; + ino_t ino; + short linkcount; + char name[1]; + }; + +struct link *linklist; /* Points to first link in list */ + +static nolinks; /* Gets set if we run out of RAM */ + +/* + * "Scratch" space to store the information about a sparse file before + * writing the info into the header or extended header + */ +/* struct sp_array *sparsearray;*/ + +/* number of elts storable in the sparsearray */ +/*int sparse_array_size = 10;*/ + +void +create_archive () +{ + register char *p; + char *name_from_list (); + + open_archive (0); /* Open for writing */ + + if (f_gnudump) + { + char *buf = ck_malloc (PATH_MAX); + char *q, *bufp; + + collect_and_sort_names (); + + while (p = name_from_list ()) + dump_file (p, -1, 1); + /* if(!f_dironly) { */ + blank_name_list (); + while (p = name_from_list ()) + { + strcpy (buf, p); + if (p[strlen (p) - 1] != '/') + strcat (buf, "/"); + bufp = buf + strlen (buf); + for (q = gnu_list_name->dir_contents; q && *q; q += strlen (q) + 1) + { + if (*q == 'Y') + { + strcpy (bufp, q + 1); + dump_file (buf, -1, 1); + } + } + } + /* } */ + free (buf); + } + else + { + while (p = name_next (1)) + dump_file (p, -1, 1); + } + + write_eot (); + close_archive (); + if (f_gnudump) + write_dir_file (); + name_close (); +} + +/* + * Dump a single file. If it's a directory, recurse. + * Result is 1 for success, 0 for failure. + * Sets global "hstat" to stat() output for this file. + */ +void +dump_file (p, curdev, toplevel) + char *p; /* File name to dump */ + int curdev; /* Device our parent dir was on */ + int toplevel; /* Whether we are a toplevel call */ +{ + union record *header; + char type; + extern char *save_name; /* JF for multi-volume support */ + extern long save_totsize; + extern long save_sizeleft; + union record *exhdr; + char save_linkflag; + extern time_t new_time; + int critical_error = 0; + struct utimbuf restore_times; + /* int sparse_ind = 0;*/ + + + if (f_confirm && !confirm ("add", p)) + return; + + /* + * Use stat if following (rather than dumping) 4.2BSD's + * symbolic links. Otherwise, use lstat (which, on non-4.2 + * systems, is #define'd to stat anyway. + */ +#ifdef STX_HIDDEN /* AIX */ + if (0 != f_follow_links ? + statx (p, &hstat, STATSIZE, STX_HIDDEN) : + statx (p, &hstat, STATSIZE, STX_HIDDEN | STX_LINK)) +#else + if (0 != f_follow_links ? stat (p, &hstat) : lstat (p, &hstat)) +#endif + { + badperror: + msg_perror ("can't add file %s", p); + badfile: + if (!f_ignore_failed_read || critical_error) + errors++; + return; + } + + restore_times.actime = hstat.st_atime; + restore_times.modtime = hstat.st_mtime; + +#ifdef S_ISHIDDEN + if (S_ISHIDDEN (hstat.st_mode)) + { + char *new = (char *) alloca (strlen (p) + 2); + if (new) + { + strcpy (new, p); + strcat (new, "@"); + p = new; + } + } +#endif + + /* See if we only want new files, and check if this one is too old to + put in the archive. */ + if (f_new_files + && !f_gnudump + && new_time > hstat.st_mtime + && !S_ISDIR (hstat.st_mode) + && (f_new_files > 1 || new_time > hstat.st_ctime)) + { + if (curdev == -1) + { + msg ("%s: is unchanged; not dumped", p); + } + return; + } + +#ifndef __MSDOS__ + /* See if we are trying to dump the archive */ + if (ar_dev && hstat.st_dev == ar_dev && hstat.st_ino == ar_ino) + { + msg ("%s is the archive; not dumped", p); + return; + } +#endif + /* + * Check for multiple links. + * + * We maintain a list of all such files that we've written so + * far. Any time we see another, we check the list and + * avoid dumping the data again if we've done it once already. + */ + if (hstat.st_nlink > 1 + && (S_ISREG (hstat.st_mode) +#ifdef S_ISCTG + || S_ISCTG (hstat.st_mode) +#endif +#ifdef S_ISCHR + || S_ISCHR (hstat.st_mode) +#endif +#ifdef S_ISBLK + || S_ISBLK (hstat.st_mode) +#endif +#ifdef S_ISFIFO + || S_ISFIFO (hstat.st_mode) +#endif + )) + { + register struct link *lp; + + /* First quick and dirty. Hashing, etc later FIXME */ + for (lp = linklist; lp; lp = lp->next) + { + if (lp->ino == hstat.st_ino && + lp->dev == hstat.st_dev) + { + char *link_name = lp->name; + + /* We found a link. */ + while (!f_absolute_paths && *link_name == '/') + { + static int link_warn = 0; + + if (!link_warn) + { + msg ("Removing leading / from absolute links"); + link_warn++; + } + link_name++; + } + if (link_name - lp->name >= NAMSIZ) + write_long (link_name, LF_LONGLINK); + current_link_name = link_name; + + hstat.st_size = 0; + header = start_header (p, &hstat); + if (header == NULL) + { + critical_error = 1; + goto badfile; + } + strncpy (header->header.arch_linkname, + link_name, NAMSIZ); + + /* Force null truncated */ + header->header.arch_linkname[NAMSIZ - 1] = 0; + + header->header.linkflag = LF_LINK; + finish_header (header); + /* FIXME: Maybe remove from list after all links found? */ + if (f_remove_files) + { + if (unlink (p) == -1) + msg_perror ("cannot remove %s", p); + } + return; /* We dumped it */ + } + } + + /* Not found. Add it to the list of possible links. */ + lp = (struct link *) ck_malloc ((unsigned) (sizeof (struct link) + strlen (p))); + if (!lp) + { + if (!nolinks) + { + msg ( + "no memory for links, they will be dumped as separate files"); + nolinks++; + } + } + lp->ino = hstat.st_ino; + lp->dev = hstat.st_dev; + strcpy (lp->name, p); + lp->next = linklist; + linklist = lp; + } + + /* + * This is not a link to a previously dumped file, so dump it. + */ + if (S_ISREG (hstat.st_mode) +#ifdef S_ISCTG + || S_ISCTG (hstat.st_mode) +#endif + ) + { + int f; /* File descriptor */ + long bufsize, count; + long sizeleft; + register union record *start; + int header_moved; + char isextended = 0; + int upperbound; + /* int end_nulls = 0; */ + + header_moved = 0; + +#ifdef BSD42 + if (f_sparse_files) + { + /* + * JK - This is the test for sparseness: whether the + * "size" of the file matches the number of blocks + * allocated for it. If there is a smaller number + * of blocks that would be necessary to accommodate + * a file of this size, we have a sparse file, i.e., + * at least one of those records in the file is just + * a useless hole. + */ +#ifdef hpux /* Nice of HPUX to gratuitiously change it, huh? - mib */ + if (hstat.st_size - (hstat.st_blocks * 1024) > 1024) +#else + if (hstat.st_size - (hstat.st_blocks * RECORDSIZE) > RECORDSIZE) +#endif + { + int filesize = hstat.st_size; + register int i; + + header = start_header (p, &hstat); + if (header == NULL) + { + critical_error = 1; + goto badfile; + } + header->header.linkflag = LF_SPARSE; + header_moved++; + + /* + * Call the routine that figures out the + * layout of the sparse file in question. + * UPPERBOUND is the index of the last + * element of the "sparsearray," i.e., + * the number of elements it needed to + * describe the file. + */ + + upperbound = deal_with_sparse (p, header); + + /* + * See if we'll need an extended header + * later + */ + if (upperbound > SPARSE_IN_HDR - 1) + header->header.isextended++; + /* + * We store the "real" file size so + * we can show that in case someone wants + * to list the archive, i.e., tar tvf . + * It might be kind of disconcerting if the + * shrunken file size was the one that showed + * up. + */ + to_oct ((long) hstat.st_size, 1 + 12, + header->header.realsize); + + /* + * This will be the new "size" of the + * file, i.e., the size of the file + * minus the records of holes that we're + * skipping over. + */ + + find_new_file_size (&filesize, upperbound); + hstat.st_size = filesize; + to_oct ((long) filesize, 1 + 12, + header->header.size); + /* to_oct((long) end_nulls, 1+12, + header->header.ending_blanks);*/ + + for (i = 0; i < SPARSE_IN_HDR; i++) + { + if (!sparsearray[i].numbytes) + break; + to_oct (sparsearray[i].offset, 1 + 12, + header->header.sp[i].offset); + to_oct (sparsearray[i].numbytes, 1 + 12, + header->header.sp[i].numbytes); + } + + } + } +#else + upperbound = SPARSE_IN_HDR - 1; +#endif + + sizeleft = hstat.st_size; + /* Don't bother opening empty, world readable files. */ + if (sizeleft > 0 || 0444 != (0444 & hstat.st_mode)) + { + f = open (p, O_RDONLY | O_BINARY); + if (f < 0) + goto badperror; + } + else + { + f = -1; + } + + /* If the file is sparse, we've already taken care of this */ + if (!header_moved) + { + header = start_header (p, &hstat); + if (header == NULL) + { + if (f >= 0) + (void) close (f); + critical_error = 1; + goto badfile; + } + } +#ifdef S_ISCTG + /* Mark contiguous files, if we support them */ + if (f_standard && S_ISCTG (hstat.st_mode)) + { + header->header.linkflag = LF_CONTIG; + } +#endif + isextended = header->header.isextended; + save_linkflag = header->header.linkflag; + finish_header (header); + if (isextended) + { + /* int sum = 0;*/ + register int i; + /* register union record *exhdr;*/ + /* int arraybound = SPARSE_EXT_HDR;*/ + /* static */ int index_offset = SPARSE_IN_HDR; + + extend:exhdr = findrec (); + + if (exhdr == NULL) + { + critical_error = 1; + goto badfile; + } + bzero (exhdr->charptr, RECORDSIZE); + for (i = 0; i < SPARSE_EXT_HDR; i++) + { + if (i + index_offset > upperbound) + break; + to_oct ((long) sparsearray[i + index_offset].numbytes, + 1 + 12, + exhdr->ext_hdr.sp[i].numbytes); + to_oct ((long) sparsearray[i + index_offset].offset, + 1 + 12, + exhdr->ext_hdr.sp[i].offset); + } + userec (exhdr); + /* sum += i; + if (sum < upperbound) + goto extend;*/ + if (index_offset + i <= upperbound) + { + index_offset += i; + exhdr->ext_hdr.isextended++; + goto extend; + } + + } + if (save_linkflag == LF_SPARSE) + { + if (finish_sparse_file (f, &sizeleft, hstat.st_size, p)) + goto padit; + } + else + while (sizeleft > 0) + { + + if (f_multivol) + { + save_name = p; + save_sizeleft = sizeleft; + save_totsize = hstat.st_size; + } + start = findrec (); + + bufsize = endofrecs ()->charptr - start->charptr; + + if (sizeleft < bufsize) + { + /* Last read -- zero out area beyond */ + bufsize = (int) sizeleft; + count = bufsize % RECORDSIZE; + if (count) + bzero (start->charptr + sizeleft, + (int) (RECORDSIZE - count)); + } + count = read (f, start->charptr, bufsize); + if (count < 0) + { + msg_perror ("read error at byte %ld, reading\ + %d bytes, in file %s", hstat.st_size - sizeleft, bufsize, p); + goto padit; + } + sizeleft -= count; + + /* This is nonportable (the type of userec's arg). */ + userec (start + (count - 1) / RECORDSIZE); + + if (count == bufsize) + continue; + msg ("file %s shrunk by %d bytes, padding with zeros.", p, sizeleft); + goto padit; /* Short read */ + } + + if (f_multivol) + save_name = 0; + + if (f >= 0) + (void) close (f); + + if (f_remove_files) + { + if (unlink (p) == -1) + msg_perror ("cannot remove %s", p); + } + if (f_atime_preserve) + utime (p, &restore_times); + return; + + /* + * File shrunk or gave error, pad out tape to match + * the size we specified in the header. + */ + padit: + while (sizeleft > 0) + { + save_sizeleft = sizeleft; + start = findrec (); + bzero (start->charptr, RECORDSIZE); + userec (start); + sizeleft -= RECORDSIZE; + } + if (f_multivol) + save_name = 0; + if (f >= 0) + (void) close (f); + if (f_atime_preserve) + utime (p, &restore_times); + return; + } + +#ifdef S_ISLNK + else if (S_ISLNK (hstat.st_mode)) + { + int size; + char *buf = alloca (PATH_MAX + 1); + + size = readlink (p, buf, PATH_MAX + 1); + if (size < 0) + goto badperror; + buf[size] = '\0'; + if (size >= NAMSIZ) + write_long (buf, LF_LONGLINK); + current_link_name = buf; + + hstat.st_size = 0; /* Force 0 size on symlink */ + header = start_header (p, &hstat); + if (header == NULL) + { + critical_error = 1; + goto badfile; + } + strncpy (header->header.arch_linkname, buf, NAMSIZ); + header->header.arch_linkname[NAMSIZ - 1] = '\0'; + header->header.linkflag = LF_SYMLINK; + finish_header (header); /* Nothing more to do to it */ + if (f_remove_files) + { + if (unlink (p) == -1) + msg_perror ("cannot remove %s", p); + } + return; + } +#endif + + else if (S_ISDIR (hstat.st_mode)) + { + register DIR *dirp; + register struct dirent *d; + char *namebuf; + int buflen; + register int len; + int our_device = hstat.st_dev; + + /* Build new prototype name */ + len = strlen (p); + buflen = len + NAMSIZ; + namebuf = ck_malloc (buflen + 1); + strncpy (namebuf, p, buflen); + while (len >= 1 && '/' == namebuf[len - 1]) + len--; /* Delete trailing slashes */ + namebuf[len++] = '/'; /* Now add exactly one back */ + namebuf[len] = '\0'; /* Make sure null-terminated */ + + /* + * Output directory header record with permissions + * FIXME, do this AFTER files, to avoid R/O dir problems? + * If old archive format, don't write record at all. + */ + if (!f_oldarch) + { + hstat.st_size = 0; /* Force 0 size on dir */ + /* + * If people could really read standard archives, + * this should be: (FIXME) + header = start_header(f_standard? p: namebuf, &hstat); + * but since they'd interpret LF_DIR records as + * regular files, we'd better put the / on the name. + */ + header = start_header (namebuf, &hstat); + if (header == NULL) + { + critical_error = 1; + goto badfile; /* eg name too long */ + } + + if (f_gnudump) + header->header.linkflag = LF_DUMPDIR; + else if (f_standard) + header->header.linkflag = LF_DIR; + + /* If we're gnudumping, we aren't done yet so don't close it. */ + if (!f_gnudump) + finish_header (header); /* Done with directory header */ + } + + if (f_gnudump) + { + int sizeleft; + int totsize; + int bufsize; + union record *start; + int count; + char *buf, *p_buf; + + buf = gnu_list_name->dir_contents; /* FOO */ + totsize = 0; + for (p_buf = buf; p_buf && *p_buf;) + { + int tmp; + + tmp = strlen (p_buf) + 1; + totsize += tmp; + p_buf += tmp; + } + totsize++; + to_oct ((long) totsize, 1 + 12, header->header.size); + finish_header (header); + p_buf = buf; + sizeleft = totsize; + while (sizeleft > 0) + { + if (f_multivol) + { + save_name = p; + save_sizeleft = sizeleft; + save_totsize = totsize; + } + start = findrec (); + bufsize = endofrecs ()->charptr - start->charptr; + if (sizeleft < bufsize) + { + bufsize = sizeleft; + count = bufsize % RECORDSIZE; + if (count) + bzero (start->charptr + sizeleft, RECORDSIZE - count); + } + bcopy (p_buf, start->charptr, bufsize); + sizeleft -= bufsize; + p_buf += bufsize; + userec (start + (bufsize - 1) / RECORDSIZE); + } + if (f_multivol) + save_name = 0; + if (f_atime_preserve) + utime (p, &restore_times); + return; + } + + /* Now output all the files in the directory */ +#if 0 + if (f_dironly) + return; /* Unless the cmdline said not to */ +#endif + /* + * See if we are crossing from one file system to another, + * and avoid doing so if the user only wants to dump one file system. + */ + if (f_local_filesys && !toplevel && curdev != hstat.st_dev) + { + if (f_verbose) + msg ("%s: is on a different filesystem; not dumped", p); + return; + } + + + errno = 0; + dirp = opendir (p); + if (!dirp) + { + if (errno) + { + msg_perror ("can't open directory %s", p); + } + else + { + msg ("error opening directory %s", + p); + } + return; + } + + /* Hack to remove "./" from the front of all the file names */ + if (len == 2 && namebuf[0] == '.' && namebuf[1] == '/') + len = 0; + + /* Should speed this up by cd-ing into the dir, FIXME */ + while (NULL != (d = readdir (dirp))) + { + /* Skip . and .. */ + if (is_dot_or_dotdot (d->d_name)) + continue; + + if (NLENGTH (d) + len >= buflen) + { + buflen = len + NLENGTH (d); + namebuf = ck_realloc (namebuf, buflen + 1); + /* namebuf[len]='\0'; + msg("file name %s%s too long", + namebuf, d->d_name); + continue; */ + } + strcpy (namebuf + len, d->d_name); + if (f_exclude && check_exclude (namebuf)) + continue; + dump_file (namebuf, our_device, 0); + } + + closedir (dirp); + free (namebuf); + if (f_atime_preserve) + utime (p, &restore_times); + return; + } + +#ifdef S_ISCHR + else if (S_ISCHR (hstat.st_mode)) + { + type = LF_CHR; + } +#endif + +#ifdef S_ISBLK + else if (S_ISBLK (hstat.st_mode)) + { + type = LF_BLK; + } +#endif + + /* Avoid screwy apollo lossage where S_IFIFO == S_IFSOCK */ +#if (_ISP__M68K == 0) && (_ISP__A88K == 0) && defined(S_ISFIFO) + else if (S_ISFIFO (hstat.st_mode)) + { + type = LF_FIFO; + } +#endif + +#ifdef S_ISSOCK + else if (S_ISSOCK (hstat.st_mode)) + { + type = LF_FIFO; + } +#endif + else + goto unknown; + + if (!f_standard) + goto unknown; + + hstat.st_size = 0; /* Force 0 size */ + header = start_header (p, &hstat); + if (header == NULL) + { + critical_error = 1; + goto badfile; /* eg name too long */ + } + + header->header.linkflag = type; +#if defined(S_IFBLK) || defined(S_IFCHR) + if (type != LF_FIFO) + { + to_oct ((long) major (hstat.st_rdev), 8, + header->header.devmajor); + to_oct ((long) minor (hstat.st_rdev), 8, + header->header.devminor); + } +#endif + + finish_header (header); + if (f_remove_files) + { + if (unlink (p) == -1) + msg_perror ("cannot remove %s", p); + } + return; + +unknown: + msg ("%s: Unknown file type; file ignored.", p); +} + +int +finish_sparse_file (fd, sizeleft, fullsize, name) + int fd; + long *sizeleft, fullsize; + char *name; +{ + union record *start; + char tempbuf[RECORDSIZE]; + int bufsize, sparse_ind = 0, count; + long pos; + long nwritten = 0; + + + while (*sizeleft > 0) + { + start = findrec (); + bzero (start->charptr, RECORDSIZE); + bufsize = sparsearray[sparse_ind].numbytes; + if (!bufsize) + { /* we blew it, maybe */ + msg ("Wrote %ld of %ld bytes to file %s", + fullsize - *sizeleft, fullsize, name); + break; + } + pos = lseek (fd, sparsearray[sparse_ind++].offset, 0); + /* + * If the number of bytes to be written here exceeds + * the size of the temporary buffer, do it in steps. + */ + while (bufsize > RECORDSIZE) + { + /* if (amt_read) { + count = read(fd, start->charptr+amt_read, RECORDSIZE-amt_read); + bufsize -= RECORDSIZE - amt_read; + amt_read = 0; + userec(start); + start = findrec(); + bzero(start->charptr, RECORDSIZE); + }*/ + /* store the data */ + count = read (fd, start->charptr, RECORDSIZE); + if (count < 0) + { + msg_perror ("read error at byte %ld, reading %d bytes, in file %s", + fullsize - *sizeleft, bufsize, name); + return 1; + } + bufsize -= count; + *sizeleft -= count; + userec (start); + nwritten += RECORDSIZE; /* XXX */ + start = findrec (); + bzero (start->charptr, RECORDSIZE); + } + + + clear_buffer (tempbuf); + count = read (fd, tempbuf, bufsize); + bcopy (tempbuf, start->charptr, RECORDSIZE); + if (count < 0) + { + msg_perror ("read error at byte %ld, reading %d bytes, in file %s", + fullsize - *sizeleft, bufsize, name); + return 1; + } + /* if (amt_read >= RECORDSIZE) { + amt_read = 0; + userec(start+(count-1)/RECORDSIZE); + if (count != bufsize) { + msg("file %s shrunk by %d bytes, padding with zeros.", name, sizeleft); + return 1; + } + start = findrec(); + } else + amt_read += bufsize;*/ + nwritten += count; /* XXX */ + *sizeleft -= count; + userec (start); + + } + free (sparsearray); + /* printf ("Amount actually written is (I hope) %d.\n", nwritten); */ + /* userec(start+(count-1)/RECORDSIZE);*/ + return 0; + +} + +void +init_sparsearray () +{ + register int i; + + sp_array_size = 10; + /* + * Make room for our scratch space -- initially is 10 elts long + */ + sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array)); + for (i = 0; i < sp_array_size; i++) + { + sparsearray[i].offset = 0; + sparsearray[i].numbytes = 0; + } +} + + + +/* + * Okay, we've got a sparse file on our hands -- now, what we need to do is + * make a pass through the file and carefully note where any data is, i.e., + * we want to find how far into the file each instance of data is, and how + * many bytes are there. We store this information in the sparsearray, + * which will later be translated into header information. For now, we use + * the sparsearray as convenient storage. + * + * As a side note, this routine is a mess. If I could have found a cleaner + * way to do it, I would have. If anyone wants to find a nicer way to do + * this, feel free. + */ + +/* There is little point in trimming small amounts of null data at the */ +/* head and tail of blocks -- it's ok if we only avoid dumping blocks */ +/* of complete null data */ +int +deal_with_sparse (name, header, nulls_at_end) + char *name; + union record *header; + int nulls_at_end; +{ + long numbytes = 0; + long offset = 0; + /* long save_offset;*/ + int fd; + /* int current_size = hstat.st_size;*/ + int sparse_ind = 0, cc; + char buf[RECORDSIZE]; +#if 0 + int read_last_data = 0; /* did we just read the last record? */ +#endif + int amidst_data = 0; + + header->header.isextended = 0; + /* + * Can't open the file -- this problem will be caught later on, + * so just return. + */ + if ((fd = open (name, O_RDONLY)) < 0) + return 0; + + init_sparsearray (); + clear_buffer (buf); + + while ((cc = read (fd, buf, sizeof buf)) != 0) + { + + if (sparse_ind > sp_array_size - 1) + { + + /* + * realloc the scratch area, since we've run out of room -- + */ + sparsearray = (struct sp_array *) + ck_realloc (sparsearray, + 2 * sp_array_size * (sizeof (struct sp_array))); + sp_array_size *= 2; + } + if (cc == sizeof buf) + { + if (zero_record (buf)) + { + if (amidst_data) + { + sparsearray[sparse_ind++].numbytes + = numbytes; + amidst_data = 0; + } + } + else + { /* !zero_record(buf) */ + if (amidst_data) + numbytes += cc; + else + { + amidst_data = 1; + numbytes = cc; + sparsearray[sparse_ind].offset + = offset; + } + } + } + else if (cc < sizeof buf) + { + /* This has to be the last bit of the file, so this */ + /* is somewhat shorter than the above. */ + if (!zero_record (buf)) + { + if (!amidst_data) + { + amidst_data = 1; + numbytes = cc; + sparsearray[sparse_ind].offset + = offset; + } + else + numbytes += cc; + } + } + offset += cc; + clear_buffer (buf); + } + if (amidst_data) + sparsearray[sparse_ind++].numbytes = numbytes; + else + { + sparsearray[sparse_ind].offset = offset-1; + sparsearray[sparse_ind++].numbytes = 1; + } + close (fd); + + return sparse_ind - 1; +} + +/* + * Just zeroes out the buffer so we don't confuse ourselves with leftover + * data. + */ +void +clear_buffer (buf) + char *buf; +{ + register int i; + + for (i = 0; i < RECORDSIZE; i++) + buf[i] = '\0'; +} + +#if 0 /* I'm leaving this as a monument to Joy Kendall, who wrote it -mib */ +/* + * JK - + * This routine takes a character array, and tells where within that array + * the data can be found. It skips over any zeros, and sets the first + * non-zero point in the array to be the "start", and continues until it + * finds non-data again, which is marked as the "end." This routine is + * mainly for 1) seeing how far into a file we must lseek to data, given + * that we have a sparse file, and 2) determining the "real size" of the + * file, i.e., the number of bytes in the sparse file that are data, as + * opposed to the zeros we are trying to skip. + */ +where_is_data (from, to, buffer) + int *from, *to; + char *buffer; +{ + register int i = 0; + register int save_to = *to; + int amidst_data = 0; + + + while (!buffer[i]) + i++; + *from = i; + + if (*from < 16) /* don't bother */ + *from = 0; + /* keep going to make sure there isn't more real + data in this record */ + while (i < RECORDSIZE) + { + if (!buffer[i]) + { + if (amidst_data) + { + save_to = i; + amidst_data = 0; + } + i++; + } + else if (buffer[i]) + { + if (!amidst_data) + amidst_data = 1; + i++; + } + } + if (i == RECORDSIZE) + *to = i; + else + *to = save_to; + +} + +#endif + +/* Note that this routine is only called if zero_record returned true */ +#if 0 /* But we actually don't need it at all. */ +where_is_data (from, to, buffer) + int *from, *to; + char *buffer; +{ + char *fp, *tp; + + for (fp = buffer; !*fp; fp++) + ; + for (tp = buffer + RECORDSIZE - 1; !*tp; tp--) + ; + *from = fp - buffer; + *to = tp - buffer + 1; +} + +#endif + + + +/* + * Takes a recordful of data and basically cruises through it to see if + * it's made *entirely* of zeros, returning a 0 the instant it finds + * something that is a non-zero, i.e., useful data. + */ +int +zero_record (buffer) + char *buffer; +{ + register int i; + + for (i = 0; i < RECORDSIZE; i++) + if (buffer[i] != '\000') + return 0; + return 1; +} + +void +find_new_file_size (filesize, highest_index) + int *filesize; + int highest_index; +{ + register int i; + + *filesize = 0; + for (i = 0; sparsearray[i].numbytes && i <= highest_index; i++) + *filesize += sparsearray[i].numbytes; +} + +/* + * Make a header block for the file name whose stat info is st . + * Return header pointer for success, NULL if the name is too long. + */ +union record * +start_header (name, st) + char *name; + register struct stat *st; +{ + register union record *header; + + if (strlen (name) >= NAMSIZ) + write_long (name, LF_LONGNAME); + + header = (union record *) findrec (); + bzero (header->charptr, sizeof (*header)); /* XXX speed up */ + + /* + * Check the file name and put it in the record. + */ + if (!f_absolute_paths) + { + static int warned_once = 0; +#ifdef __MSDOS__ + if (name[1] == ':') + { + name += 2; + if (!warned_once++) + msg ("Removing drive spec from names in the archive"); + } +#endif + while ('/' == *name) + { + name++; /* Force relative path */ + if (!warned_once++) + msg ("Removing leading / from absolute path names in the archive."); + } + } + current_file_name = name; + strncpy (header->header.arch_name, name, NAMSIZ); + header->header.arch_name[NAMSIZ - 1] = '\0'; + + to_oct ((long) (f_oldarch ? (st->st_mode & 07777) : st->st_mode), + 8, header->header.mode); + to_oct ((long) st->st_uid, 8, header->header.uid); + to_oct ((long) st->st_gid, 8, header->header.gid); + to_oct ((long) st->st_size, 1 + 12, header->header.size); + to_oct ((long) st->st_mtime, 1 + 12, header->header.mtime); + /* header->header.linkflag is left as null */ + if (f_gnudump) + { + to_oct ((long) st->st_atime, 1 + 12, header->header.atime); + to_oct ((long) st->st_ctime, 1 + 12, header->header.ctime); + } + +#ifndef NONAMES + /* Fill in new Unix Standard fields if desired. */ + if (f_standard) + { + header->header.linkflag = LF_NORMAL; /* New default */ + strcpy (header->header.magic, TMAGIC); /* Mark as Unix Std */ + finduname (header->header.uname, st->st_uid); + findgname (header->header.gname, st->st_gid); + } +#endif + return header; +} + +/* + * Finish off a filled-in header block and write it out. + * We also print the file name and/or full info if verbose is on. + */ +void +finish_header (header) + register union record *header; +{ + register int i, sum; + register char *p; + + bcopy (CHKBLANKS, header->header.chksum, sizeof (header->header.chksum)); + + sum = 0; + p = header->charptr; + for (i = sizeof (*header); --i >= 0;) + { + /* + * We can't use unsigned char here because of old compilers, + * e.g. V7. + */ + sum += 0xFF & *p++; + } + + /* + * Fill in the checksum field. It's formatted differently + * from the other fields: it has [6] digits, a null, then a + * space -- rather than digits, a space, then a null. + * We use to_oct then write the null in over to_oct's space. + * The final space is already there, from checksumming, and + * to_oct doesn't modify it. + * + * This is a fast way to do: + * (void) sprintf(header->header.chksum, "%6o", sum); + */ + to_oct ((long) sum, 8, header->header.chksum); + header->header.chksum[6] = '\0'; /* Zap the space */ + + userec (header); + + if (f_verbose) + { + extern union record *head;/* Points to current tape header */ + extern int head_standard; /* Tape header is in ANSI format */ + + /* These globals are parameters to print_header, sigh */ + head = header; + /* hstat is already set up */ + head_standard = f_standard; + print_header (); + } + + return; +} + + +/* + * Quick and dirty octal conversion. + * Converts long "value" into a "digs"-digit field at "where", + * including a trailing space and room for a null. "digs"==3 means + * 1 digit, a space, and room for a null. + * + * We assume the trailing null 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 should be equivalent to: + * (void) sprintf(where, "%*lo ", digs-2, value); + * except that sprintf fills in the trailing null and we don't. + */ +void +to_oct (value, digs, where) + register long value; + register int digs; + register char *where; +{ + + --digs; /* Trailing null slot is left alone */ + where[--digs] = ' '; /* Put in the space, though */ + + /* Produce the digits -- at least one */ + do + { + where[--digs] = '0' + (char) (value & 7); /* one octal digit */ + value >>= 3; + } + while (digs > 0 && value != 0); + + /* Leading spaces, if necessary */ + while (digs > 0) + where[--digs] = ' '; + +} + + +/* + * Write the EOT record(s). + * We actually zero at least one record, through the end of the block. + * Old tar writes garbage after two zeroed records -- and PDtar used to. + */ +void +write_eot () +{ + union record *p; + int bufsize; + + p = findrec (); + if (p) + { + bufsize = endofrecs ()->charptr - p->charptr; + bzero (p->charptr, bufsize); + userec (p); + } +} + +/* Write a LF_LONGLINK or LF_LONGNAME record. */ +void +write_long (p, type) + char *p; + char type; +{ + int size = strlen (p) + 1; + int bufsize; + union record *header; + struct stat foo; + + + bzero (&foo, sizeof foo); + foo.st_size = size; + + header = start_header ("././@LongLink", &foo); + header->header.linkflag = type; + finish_header (header); + + header = findrec (); + + bufsize = endofrecs ()->charptr - header->charptr; + + while (bufsize < size) + { + bcopy (p, header->charptr, bufsize); + p += bufsize; + size -= bufsize; + userec (header + (bufsize - 1) / RECORDSIZE); + header = findrec (); + bufsize = endofrecs ()->charptr - header->charptr; + } + bcopy (p, header->charptr, size); + bzero (header->charptr + size, bufsize - size); + userec (header + (size - 1) / RECORDSIZE); +} diff --git a/gnu/usr.bin/tar/diffarch.c b/gnu/usr.bin/tar/diffarch.c new file mode 100644 index 0000000000..ce47d9d6ca --- /dev/null +++ b/gnu/usr.bin/tar/diffarch.c @@ -0,0 +1,759 @@ +/* Diff files from a tar archive. + Copyright (C) 1988, 1992, 1993 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Diff files from a tar archive. + * + * Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu. + */ + +#include +#include +#ifndef STDC_HEADERS +extern int errno; +#endif +#include + +#ifdef BSD42 +#include +#else +#ifndef V7 +#include +#endif +#endif + +#ifdef HAVE_SYS_MTIO_H +#include +#include +#endif + +#include "tar.h" +#include "port.h" +#include "rmt.h" + +#ifndef S_ISLNK +#define lstat stat +#endif + +extern void *valloc (); + +extern union record *head; /* Points to current tape header */ +extern struct stat hstat; /* Stat struct corresponding */ +extern int head_standard; /* Tape header is in ANSI format */ + +void decode_header (); +void diff_sparse_files (); +void fill_in_sparse_array (); +void fl_read (); +long from_oct (); +int do_stat (); +extern void print_header (); +int read_header (); +void saverec (); +void sigh (); +extern void skip_file (); +extern void skip_extended_headers (); +int wantbytes (); + +extern FILE *msg_file; + +int now_verifying = 0; /* Are we verifying at the moment? */ + +int diff_fd; /* Descriptor of file we're diffing */ + +char *diff_buf = 0; /* Pointer to area for reading + file contents into */ + +char *diff_dir; /* Directory contents for LF_DUMPDIR */ + +int different = 0; + +/*struct sp_array *sparsearray; +int sp_ar_size = 10;*/ +/* + * Initialize for a diff operation + */ +void +diff_init () +{ + /*NOSTRICT*/ + diff_buf = (char *) valloc ((unsigned) blocksize); + if (!diff_buf) + { + msg ("could not allocate memory for diff buffer of %d bytes", + blocksize); + exit (EX_ARGSBAD); + } +} + +/* + * Diff a file against the archive. + */ +void +diff_archive () +{ + register char *data; + int check, namelen; + int err; + long offset; + struct stat filestat; + int compare_chunk (); + int compare_dir (); + int no_op (); +#ifndef __MSDOS__ + dev_t dev; + ino_t ino; +#endif + char *get_dir_contents (); + long from_oct (); + + errno = EPIPE; /* FIXME, remove perrors */ + + saverec (&head); /* Make sure it sticks around */ + userec (head); /* And go past it in the archive */ + decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */ + + /* Print the record from 'head' and 'hstat' */ + if (f_verbose) + { + if (now_verifying) + fprintf (msg_file, "Verify "); + print_header (); + } + + switch (head->header.linkflag) + { + + default: + msg ("Unknown file type '%c' for %s, diffed as normal file", + head->header.linkflag, current_file_name); + /* FALL THRU */ + + case LF_OLDNORMAL: + case LF_NORMAL: + case LF_SPARSE: + case LF_CONTIG: + /* + * Appears to be a file. + * See if it's really a directory. + */ + namelen = strlen (current_file_name) - 1; + if (current_file_name[namelen] == '/') + goto really_dir; + + + if (do_stat (&filestat)) + { + if (head->header.isextended) + skip_extended_headers (); + skip_file ((long) hstat.st_size); + different++; + goto quit; + } + + if (!S_ISREG (filestat.st_mode)) + { + fprintf (msg_file, "%s: not a regular file\n", + current_file_name); + skip_file ((long) hstat.st_size); + different++; + goto quit; + } + + filestat.st_mode &= 07777; + if (filestat.st_mode != hstat.st_mode) + sigh ("mode"); + if (filestat.st_uid != hstat.st_uid) + sigh ("uid"); + if (filestat.st_gid != hstat.st_gid) + sigh ("gid"); + if (filestat.st_mtime != hstat.st_mtime) + sigh ("mod time"); + if (head->header.linkflag != LF_SPARSE && + filestat.st_size != hstat.st_size) + { + sigh ("size"); + skip_file ((long) hstat.st_size); + goto quit; + } + + diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY); + + if (diff_fd < 0 && !f_absolute_paths) + { + char tmpbuf[NAMSIZ + 2]; + + tmpbuf[0] = '/'; + strcpy (&tmpbuf[1], current_file_name); + diff_fd = open (tmpbuf, O_NDELAY | O_RDONLY); + } + if (diff_fd < 0) + { + msg_perror ("cannot open %s", current_file_name); + if (head->header.isextended) + skip_extended_headers (); + skip_file ((long) hstat.st_size); + different++; + goto quit; + } + /* + * Need to treat sparse files completely differently here. + */ + if (head->header.linkflag == LF_SPARSE) + diff_sparse_files (hstat.st_size); + else + wantbytes ((long) (hstat.st_size), compare_chunk); + + check = close (diff_fd); + if (check < 0) + msg_perror ("Error while closing %s", current_file_name); + + quit: + break; + +#ifndef __MSDOS__ + case LF_LINK: + if (do_stat (&filestat)) + break; + dev = filestat.st_dev; + ino = filestat.st_ino; + err = stat (current_link_name, &filestat); + if (err < 0) + { + if (errno == ENOENT) + { + fprintf (msg_file, "%s: does not exist\n", current_file_name); + } + else + { + msg_perror ("cannot stat file %s", current_file_name); + } + different++; + break; + } + if (filestat.st_dev != dev || filestat.st_ino != ino) + { + fprintf (msg_file, "%s not linked to %s\n", current_file_name, current_link_name); + break; + } + break; +#endif + +#ifdef S_ISLNK + case LF_SYMLINK: + { + char linkbuf[NAMSIZ + 3]; + check = readlink (current_file_name, linkbuf, + (sizeof linkbuf) - 1); + + if (check < 0) + { + if (errno == ENOENT) + { + fprintf (msg_file, + "%s: no such file or directory\n", + current_file_name); + } + else + { + msg_perror ("cannot read link %s", current_file_name); + } + different++; + break; + } + + linkbuf[check] = '\0'; /* Null-terminate it */ + if (strncmp (current_link_name, linkbuf, check) != 0) + { + fprintf (msg_file, "%s: symlink differs\n", + current_link_name); + different++; + } + } + break; +#endif + +#ifdef S_IFCHR + case LF_CHR: + hstat.st_mode |= S_IFCHR; + goto check_node; +#endif + +#ifdef S_IFBLK + /* If local system doesn't support block devices, use default case */ + case LF_BLK: + hstat.st_mode |= S_IFBLK; + goto check_node; +#endif + +#ifdef S_ISFIFO + /* If local system doesn't support FIFOs, use default case */ + case LF_FIFO: +#ifdef S_IFIFO + hstat.st_mode |= S_IFIFO; +#endif + hstat.st_rdev = 0; /* FIXME, do we need this? */ + goto check_node; +#endif + + check_node: + /* FIXME, deal with umask */ + if (do_stat (&filestat)) + break; + if (hstat.st_rdev != filestat.st_rdev) + { + fprintf (msg_file, "%s: device numbers changed\n", current_file_name); + different++; + break; + } +#ifdef S_IFMT + if (hstat.st_mode != filestat.st_mode) +#else /* POSIX lossage */ + if ((hstat.st_mode & 07777) != (filestat.st_mode & 07777)) +#endif + { + fprintf (msg_file, "%s: mode or device-type changed\n", current_file_name); + different++; + break; + } + break; + + case LF_DUMPDIR: + data = diff_dir = get_dir_contents (current_file_name, 0); + if (data) + { + wantbytes ((long) (hstat.st_size), compare_dir); + free (data); + } + else + wantbytes ((long) (hstat.st_size), no_op); + /* FALL THROUGH */ + + case LF_DIR: + /* Check for trailing / */ + namelen = strlen (current_file_name) - 1; + really_dir: + while (namelen && current_file_name[namelen] == '/') + current_file_name[namelen--] = '\0'; /* Zap / */ + + if (do_stat (&filestat)) + break; + if (!S_ISDIR (filestat.st_mode)) + { + fprintf (msg_file, "%s is no longer a directory\n", current_file_name); + different++; + break; + } + if ((filestat.st_mode & 07777) != (hstat.st_mode & 07777)) + sigh ("mode"); + break; + + case LF_VOLHDR: + break; + + case LF_MULTIVOL: + namelen = strlen (current_file_name) - 1; + if (current_file_name[namelen] == '/') + goto really_dir; + + if (do_stat (&filestat)) + break; + + if (!S_ISREG (filestat.st_mode)) + { + fprintf (msg_file, "%s: not a regular file\n", + current_file_name); + skip_file ((long) hstat.st_size); + different++; + break; + } + + filestat.st_mode &= 07777; + offset = from_oct (1 + 12, head->header.offset); + if (filestat.st_size != hstat.st_size + offset) + { + sigh ("size"); + skip_file ((long) hstat.st_size); + different++; + break; + } + + diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY); + + if (diff_fd < 0) + { + msg_perror ("cannot open file %s", current_file_name); + skip_file ((long) hstat.st_size); + different++; + break; + } + err = lseek (diff_fd, offset, 0); + if (err != offset) + { + msg_perror ("cannot seek to %ld in file %s", offset, current_file_name); + different++; + break; + } + + wantbytes ((long) (hstat.st_size), compare_chunk); + + check = close (diff_fd); + if (check < 0) + { + msg_perror ("Error while closing %s", current_file_name); + } + break; + + } + + /* We don't need to save it any longer. */ + saverec ((union record **) 0);/* Unsave it */ +} + +int +compare_chunk (bytes, buffer) + long bytes; + char *buffer; +{ + int err; + + err = read (diff_fd, diff_buf, bytes); + if (err != bytes) + { + if (err < 0) + { + msg_perror ("can't read %s", current_file_name); + } + else + { + fprintf (msg_file, "%s: could only read %d of %d bytes\n", current_file_name, err, bytes); + } + different++; + return -1; + } + if (bcmp (buffer, diff_buf, bytes)) + { + fprintf (msg_file, "%s: data differs\n", current_file_name); + different++; + return -1; + } + return 0; +} + +int +compare_dir (bytes, buffer) + long bytes; + char *buffer; +{ + if (bcmp (buffer, diff_dir, bytes)) + { + fprintf (msg_file, "%s: data differs\n", current_file_name); + different++; + return -1; + } + diff_dir += bytes; + return 0; +} + +/* + * Sigh about something that differs. + */ +void +sigh (what) + char *what; +{ + + fprintf (msg_file, "%s: %s differs\n", + current_file_name, what); +} + +void +verify_volume () +{ + int status; +#ifdef MTIOCTOP + struct mtop t; + int er; +#endif + + if (!diff_buf) + diff_init (); +#ifdef MTIOCTOP + t.mt_op = MTBSF; + t.mt_count = 1; + if ((er = rmtioctl (archive, MTIOCTOP, &t)) < 0) + { + if (errno != EIO || (er = rmtioctl (archive, MTIOCTOP, &t)) < 0) + { +#endif + if (rmtlseek (archive, 0L, 0) != 0) + { + /* Lseek failed. Try a different method */ + msg_perror ("Couldn't rewind archive file for verify"); + return; + } +#ifdef MTIOCTOP + } + } +#endif + ar_reading = 1; + now_verifying = 1; + fl_read (); + for (;;) + { + status = read_header (); + if (status == 0) + { + unsigned n; + + n = 0; + do + { + n++; + status = read_header (); + } + while (status == 0); + msg ("VERIFY FAILURE: %d invalid header%s detected!", n, n == 1 ? "" : "s"); + } + if (status == 2 || status == EOF) + break; + diff_archive (); + } + ar_reading = 0; + now_verifying = 0; + +} + +int +do_stat (statp) + struct stat *statp; +{ + int err; + + err = f_follow_links ? stat (current_file_name, statp) : lstat (current_file_name, statp); + if (err < 0) + { + if (errno == ENOENT) + { + fprintf (msg_file, "%s: does not exist\n", current_file_name); + } + else + msg_perror ("can't stat file %s", current_file_name); + /* skip_file((long)hstat.st_size); + different++;*/ + return 1; + } + else + return 0; +} + +/* + * JK + * Diff'ing a sparse file with its counterpart on the tar file is a + * bit of a different story than a normal file. First, we must know + * what areas of the file to skip through, i.e., we need to contruct + * a sparsearray, which will hold all the information we need. We must + * compare small amounts of data at a time as we find it. + */ + +void +diff_sparse_files (filesize) + int filesize; + +{ + int sparse_ind = 0; + char *buf; + int buf_size = RECORDSIZE; + union record *datarec; + int err; + long numbytes; + /* int amt_read = 0;*/ + int size = filesize; + + buf = (char *) ck_malloc (buf_size * sizeof (char)); + + fill_in_sparse_array (); + + + while (size > 0) + { + datarec = findrec (); + if (!sparsearray[sparse_ind].numbytes) + break; + + /* + * 'numbytes' is nicer to write than + * 'sparsearray[sparse_ind].numbytes' all the time ... + */ + numbytes = sparsearray[sparse_ind].numbytes; + + lseek (diff_fd, sparsearray[sparse_ind].offset, 0); + /* + * take care to not run out of room in our buffer + */ + while (buf_size < numbytes) + { + buf = (char *) ck_realloc (buf, buf_size * 2 * sizeof (char)); + buf_size *= 2; + } + while (numbytes > RECORDSIZE) + { + if ((err = read (diff_fd, buf, RECORDSIZE)) != RECORDSIZE) + { + if (err < 0) + msg_perror ("can't read %s", current_file_name); + else + fprintf (msg_file, "%s: could only read %d of %d bytes\n", + current_file_name, err, numbytes); + break; + } + if (bcmp (buf, datarec->charptr, RECORDSIZE)) + { + different++; + break; + } + numbytes -= err; + size -= err; + userec (datarec); + datarec = findrec (); + } + if ((err = read (diff_fd, buf, numbytes)) != numbytes) + { + if (err < 0) + msg_perror ("can't read %s", current_file_name); + else + fprintf (msg_file, "%s: could only read %d of %d bytes\n", + current_file_name, err, numbytes); + break; + } + + if (bcmp (buf, datarec->charptr, numbytes)) + { + different++; + break; + } + /* amt_read += numbytes; + if (amt_read >= RECORDSIZE) { + amt_read = 0; + userec(datarec); + datarec = findrec(); + }*/ + userec (datarec); + sparse_ind++; + size -= numbytes; + } + /* + * if the number of bytes read isn't the + * number of bytes supposedly in the file, + * they're different + */ + /* if (amt_read != filesize) + different++;*/ + userec (datarec); + free (sparsearray); + if (different) + fprintf (msg_file, "%s: data differs\n", current_file_name); + +} + +/* + * JK + * This routine should be used more often than it is ... look into + * that. Anyhow, what it does is translate the sparse information + * on the header, and in any subsequent extended headers, into an + * array of structures with true numbers, as opposed to character + * strings. It simply makes our life much easier, doing so many + * comparisong and such. + */ +void +fill_in_sparse_array () +{ + int ind; + + /* + * allocate space for our scratch space; it's initially + * 10 elements long, but can change in this routine if + * necessary + */ + sp_array_size = 10; + sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array)); + + /* + * there are at most five of these structures in the header + * itself; read these in first + */ + for (ind = 0; ind < SPARSE_IN_HDR; ind++) + { + if (!head->header.sp[ind].numbytes) + break; + sparsearray[ind].offset = + from_oct (1 + 12, head->header.sp[ind].offset); + sparsearray[ind].numbytes = + from_oct (1 + 12, head->header.sp[ind].numbytes); + } + /* + * if the header's extended, we gotta read in exhdr's till + * we're done + */ + if (head->header.isextended) + { + /* how far into the sparsearray we are 'so far' */ + static int so_far_ind = SPARSE_IN_HDR; + union record *exhdr; + + for (;;) + { + exhdr = findrec (); + for (ind = 0; ind < SPARSE_EXT_HDR; ind++) + { + if (ind + so_far_ind > sp_array_size - 1) + { + /* + * we just ran out of room in our + * scratch area - realloc it + */ + sparsearray = (struct sp_array *) + ck_realloc (sparsearray, + sp_array_size * 2 * sizeof (struct sp_array)); + sp_array_size *= 2; + } + /* + * convert the character strings into longs + */ + sparsearray[ind + so_far_ind].offset = + from_oct (1 + 12, exhdr->ext_hdr.sp[ind].offset); + sparsearray[ind + so_far_ind].numbytes = + from_oct (1 + 12, exhdr->ext_hdr.sp[ind].numbytes); + } + /* + * if this is the last extended header for this + * file, we can stop + */ + if (!exhdr->ext_hdr.isextended) + break; + else + { + so_far_ind += SPARSE_EXT_HDR; + userec (exhdr); + } + } + /* be sure to skip past the last one */ + userec (exhdr); + } +} diff --git a/gnu/usr.bin/tar/extract.c b/gnu/usr.bin/tar/extract.c new file mode 100644 index 0000000000..d162cab04e --- /dev/null +++ b/gnu/usr.bin/tar/extract.c @@ -0,0 +1,907 @@ +/* Extract files from a tar archive. + Copyright (C) 1988, 1992, 1993 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Extract files from a tar archive. + * + * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu. + */ + +#include +#include +#ifndef STDC_HEADERS +extern int errno; +#endif +#include +#include +time_t time (); + +#ifdef BSD42 +#include +#else +#ifndef V7 +#include +#endif +#endif + +#ifdef NO_OPEN3 +/* We need the #define's even though we don't use them. */ +#include "open3.h" +#endif + +#ifdef EMUL_OPEN3 +/* Simulated 3-argument open for systems that don't have it */ +#include "open3.h" +#endif + +#include "tar.h" +#include "port.h" + +#if defined(_POSIX_VERSION) +#include +#else +struct utimbuf +{ + long actime; + long modtime; +}; + +#endif + +extern FILE *msg_file; + +extern union record *head; /* Points to current tape header */ +extern struct stat hstat; /* Stat struct corresponding */ +extern int head_standard; /* Tape header is in ANSI format */ + +extern char *save_name; +extern long save_totsize; +extern long save_sizeleft; + +int confirm (); +void decode_header (); +void extract_mangle (); +void extract_sparse_file (); +long from_oct (); +void gnu_restore (); +extern void print_header (); +extern void skip_file (); +extern void skip_extended_headers (); +extern void pr_mkdir (); +void saverec (); + +int make_dirs (); /* Makes required directories */ + +static time_t now = 0; /* Current time */ +static we_are_root = 0; /* True if our effective uid == 0 */ +static int notumask = ~0; /* Masks out bits user doesn't want */ + +/* + * "Scratch" space to store the information about a sparse file before + * writing the info into the header or extended header + */ +/*struct sp_array *sparsearray;*/ + +/* number of elts storable in the sparsearray */ +/*int sp_array_size = 10;*/ + +struct saved_dir_info +{ + char *path; + int mode; + int atime; + int mtime; + struct saved_dir_info *next; +}; + +struct saved_dir_info *saved_dir_info_head; + +/* + * Set up to extract files. + */ +void +extr_init () +{ + int ourmask; + + now = time ((time_t *) 0); + if (geteuid () == 0) + we_are_root = 1; + + /* + * We need to know our umask. But if f_use_protection is set, + * leave our kernel umask at 0, and our "notumask" at ~0. + */ + ourmask = umask (0); /* Read it */ + if (!f_use_protection) + { + (void) umask (ourmask); /* Set it back how it was */ + notumask = ~ourmask; /* Make umask override permissions */ + } +} + + +/* + * Extract a file from the archive. + */ +void +extract_archive () +{ + register char *data; + int fd, check, namelen, written, openflag; + long size; + struct utimbuf acc_upd_times; + register int skipcrud; + register int i; + /* int sparse_ind = 0;*/ + union record *exhdr; + struct saved_dir_info *tmp; + /* int end_nulls; */ + + saverec (&head); /* Make sure it sticks around */ + userec (head); /* And go past it in the archive */ + decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */ + + if (f_confirm && !confirm ("extract", current_file_name)) + { + if (head->header.isextended) + skip_extended_headers (); + skip_file ((long) hstat.st_size); + saverec ((union record **) 0); + return; + } + + /* Print the record from 'head' and 'hstat' */ + if (f_verbose) + print_header (); + + /* + * Check for fully specified pathnames and other atrocities. + * + * Note, we can't just make a pointer to the new file name, + * since saverec() might move the header and adjust "head". + * We have to start from "head" every time we want to touch + * the header record. + */ + skipcrud = 0; + while (!f_absolute_paths + && '/' == current_file_name[skipcrud]) + { + static int warned_once = 0; + + skipcrud++; /* Force relative path */ + if (!warned_once++) + { + msg ("Removing leading / from absolute path names in the archive."); + } + } + + switch (head->header.linkflag) + { + + default: + msg ("Unknown file type '%c' for %s, extracted as normal file", + head->header.linkflag, skipcrud + current_file_name); + /* FALL THRU */ + + /* + * JK - What we want to do if the file is sparse is loop through + * the array of sparse structures in the header and read in + * and translate the character strings representing 1) the offset + * at which to write and 2) how many bytes to write into numbers, + * which we store into the scratch array, "sparsearray". This + * array makes our life easier the same way it did in creating + * the tar file that had to deal with a sparse file. + * + * After we read in the first five (at most) sparse structures, + * we check to see if the file has an extended header, i.e., + * if more sparse structures are needed to describe the contents + * of the new file. If so, we read in the extended headers + * and continue to store their contents into the sparsearray. + */ + case LF_SPARSE: + sp_array_size = 10; + sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array)); + for (i = 0; i < SPARSE_IN_HDR; i++) + { + sparsearray[i].offset = + from_oct (1 + 12, head->header.sp[i].offset); + sparsearray[i].numbytes = + from_oct (1 + 12, head->header.sp[i].numbytes); + if (!sparsearray[i].numbytes) + break; + } + + /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/ + + if (head->header.isextended) + { + /* read in the list of extended headers + and translate them into the sparsearray + as before */ + + /* static */ int ind = SPARSE_IN_HDR; + + for (;;) + { + + exhdr = findrec (); + for (i = 0; i < SPARSE_EXT_HDR; i++) + { + + if (i + ind > sp_array_size - 1) + { + /* + * realloc the scratch area + * since we've run out of room -- + */ + sparsearray = (struct sp_array *) + ck_realloc (sparsearray, + 2 * sp_array_size * (sizeof (struct sp_array))); + sp_array_size *= 2; + } + if (!exhdr->ext_hdr.sp[i].numbytes) + break; + sparsearray[i + ind].offset = + from_oct (1 + 12, exhdr->ext_hdr.sp[i].offset); + sparsearray[i + ind].numbytes = + from_oct (1 + 12, exhdr->ext_hdr.sp[i].numbytes); + } + if (!exhdr->ext_hdr.isextended) + break; + else + { + ind += SPARSE_EXT_HDR; + userec (exhdr); + } + } + userec (exhdr); + } + + /* FALL THRU */ + case LF_OLDNORMAL: + case LF_NORMAL: + case LF_CONTIG: + /* + * Appears to be a file. + * See if it's really a directory. + */ + namelen = strlen (skipcrud + current_file_name) - 1; + if (current_file_name[skipcrud + namelen] == '/') + goto really_dir; + + /* FIXME, deal with protection issues */ + again_file: + openflag = (f_keep ? + O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL : + O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC) + | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND); + /* + * JK - The last | is a kludge to solve the problem + * the O_APPEND flag causes with files we are + * trying to make sparse: when a file is opened + * with O_APPEND, it writes to the last place + * that something was written, thereby ignoring + * any lseeks that we have done. We add this + * extra condition to make it able to lseek when + * a file is sparse, i.e., we don't open the new + * file with this flag. (Grump -- this bug caused + * me to waste a good deal of time, I might add) + */ + + if (f_exstdout) + { + fd = 1; + goto extract_file; + } +#ifdef O_CTG + /* + * Contiguous files (on the Masscomp) have to specify + * the size in the open call that creates them. + */ + if (head->header.linkflag == LF_CONTIG) + fd = open ((longname ? longname : head->header.name) + + skipcrud, + openflag | O_CTG, + hstat.st_mode, hstat.st_size); + else +#endif + { +#ifdef NO_OPEN3 + /* + * On raw V7 we won't let them specify -k (f_keep), but + * we just bull ahead and create the files. + */ + fd = creat ((longname + ? longname + : head->header.name) + skipcrud, + hstat.st_mode); +#else + /* + * With 3-arg open(), we can do this up right. + */ + fd = open (skipcrud + current_file_name, + openflag, hstat.st_mode); +#endif + } + + if (fd < 0) + { + if (make_dirs (skipcrud + current_file_name)) + goto again_file; + msg_perror ("Could not create file %s", + skipcrud + current_file_name); + if (head->header.isextended) + skip_extended_headers (); + skip_file ((long) hstat.st_size); + goto quit; + } + + extract_file: + if (head->header.linkflag == LF_SPARSE) + { + char *name; + int namelen; + + /* + * Kludge alert. NAME is assigned to header.name + * because during the extraction, the space that + * contains the header will get scribbled on, and + * the name will get munged, so any error messages + * that happen to contain the filename will look + * REAL interesting unless we do this. + */ + namelen = strlen (skipcrud + current_file_name) + 1; + name = (char *) ck_malloc ((sizeof (char)) * namelen); + bcopy (skipcrud + current_file_name, name, namelen); + size = hstat.st_size; + extract_sparse_file (fd, &size, hstat.st_size, name); + } + else + for (size = hstat.st_size; + size > 0; + size -= written) + { + + /* long offset, + numbytes;*/ + + if (f_multivol) + { + save_name = current_file_name; + save_totsize = hstat.st_size; + save_sizeleft = size; + } + + /* + * Locate data, determine max length + * writeable, write it, record that + * we have used the data, then check + * if the write worked. + */ + data = findrec ()->charptr; + if (data == NULL) + { /* Check it... */ + msg ("Unexpected EOF on archive file"); + break; + } + /* + * JK - If the file is sparse, use the sparsearray + * that we created before to lseek into the new + * file the proper amount, and to see how many + * bytes we want to write at that position. + */ + /* if (head->header.linkflag == LF_SPARSE) { + off_t pos; + + pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0); + printf("%d at %d\n", (int) pos, sparse_ind); + written = sparsearray[sparse_ind++].numbytes; + } else*/ + written = endofrecs ()->charptr - data; + if (written > size) + written = size; + errno = 0; + check = write (fd, data, written); + /* + * The following is in violation of strict + * typing, since the arg to userec + * should be a struct rec *. FIXME. + */ + userec ((union record *) (data + written - 1)); + if (check == written) + continue; + /* + * Error in writing to file. + * Print it, skip to next file in archive. + */ + if (check < 0) + msg_perror ("couldn't write to file %s", + skipcrud + current_file_name); + else + msg ("could only write %d of %d bytes to file %s", + check, written, skipcrud + current_file_name); + skip_file ((long) (size - written)); + break; /* Still do the close, mod time, chmod, etc */ + } + + if (f_multivol) + save_name = 0; + + /* If writing to stdout, don't try to do anything + to the filename; it doesn't exist, or we don't + want to touch it anyway */ + if (f_exstdout) + break; + + /* if (head->header.isextended) { + register union record *exhdr; + register int i; + + for (i = 0; i < 21; i++) { + long offset; + + if (!exhdr->ext_hdr.sp[i].numbytes) + break; + offset = from_oct(1+12, + exhdr->ext_hdr.sp[i].offset); + written = from_oct(1+12, + exhdr->ext_hdr.sp[i].numbytes); + lseek(fd, offset, 0); + check = write(fd, data, written); + if (check == written) continue; + + } + + + }*/ + check = close (fd); + if (check < 0) + { + msg_perror ("Error while closing %s", + skipcrud + current_file_name); + } + + + set_filestat: + + /* + * If we are root, set the owner and group of the extracted + * file. This does what is wanted both on real Unix and on + * System V. If we are running as a user, we extract as that + * user; if running as root, we extract as the original owner. + */ + if (we_are_root || f_do_chown) + { + if (chown (skipcrud + current_file_name, + hstat.st_uid, hstat.st_gid) < 0) + { + msg_perror ("cannot chown file %s to uid %d gid %d", + skipcrud + current_file_name, + hstat.st_uid, hstat.st_gid); + } + } + + /* + * Set the modified time of the file. + * + * Note that we set the accessed time to "now", which + * is really "the time we started extracting files". + * unless f_gnudump is used, in which case .st_atime is used + */ + if (!f_modified) + { + /* fixme if f_gnudump should set ctime too, but how? */ + if (f_gnudump) + acc_upd_times.actime = hstat.st_atime; + else + acc_upd_times.actime = now; /* Accessed now */ + acc_upd_times.modtime = hstat.st_mtime; /* Mod'd */ + if (utime (skipcrud + current_file_name, + &acc_upd_times) < 0) + { + msg_perror ("couldn't change access and modification times of %s", skipcrud + current_file_name); + } + } + /* We do the utime before the chmod because some versions of + utime are broken and trash the modes of the file. Since + we then change the mode anyway, we don't care. . . */ + + /* + * If '-k' is not set, open() or creat() could have saved + * the permission bits from a previously created file, + * ignoring the ones we specified. + * Even if -k is set, if the file has abnormal + * mode bits, we must chmod since writing or chown() has + * probably reset them. + * + * If -k is set, we know *we* created this file, so the mode + * bits were set by our open(). If the file is "normal", we + * skip the chmod. This works because we did umask(0) if -p + * is set, so umask will have left the specified mode alone. + */ + if ((!f_keep) + || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX))) + { + if (chmod (skipcrud + current_file_name, + notumask & (int) hstat.st_mode) < 0) + { + msg_perror ("cannot change mode of file %s to %ld", + skipcrud + current_file_name, + notumask & (int) hstat.st_mode); + } + } + + quit: + break; + + case LF_LINK: + again_link: + { + struct stat st1, st2; + + check = link (current_link_name, skipcrud + current_file_name); + + if (check == 0) + break; + if (make_dirs (skipcrud + current_file_name)) + goto again_link; + if (f_gnudump && errno == EEXIST) + break; + if (stat (current_link_name, &st1) == 0 + && stat (current_file_name + skipcrud, &st2) == 0 + && st1.st_dev == st2.st_dev + && st1.st_ino == st2.st_ino) + break; + msg_perror ("Could not link %s to %s", + skipcrud + current_file_name, + current_link_name); + } + break; + +#ifdef S_ISLNK + case LF_SYMLINK: + again_symlink: + check = symlink (current_link_name, + skipcrud + current_file_name); + /* FIXME, don't worry uid, gid, etc... */ + if (check == 0) + break; + if (make_dirs (current_file_name + skipcrud)) + goto again_symlink; + msg_perror ("Could not create symlink to %s", + current_link_name); + break; +#endif + +#ifdef S_IFCHR + case LF_CHR: + hstat.st_mode |= S_IFCHR; + goto make_node; +#endif + +#ifdef S_IFBLK + case LF_BLK: + hstat.st_mode |= S_IFBLK; +#endif +#if defined(S_IFCHR) || defined(S_IFBLK) + make_node: + check = mknod (current_file_name + skipcrud, + (int) hstat.st_mode, (int) hstat.st_rdev); + if (check != 0) + { + if (make_dirs (skipcrud + current_file_name)) + goto make_node; + msg_perror ("Could not make %s", + current_file_name + skipcrud); + break; + }; + goto set_filestat; +#endif + +#ifdef S_ISFIFO + /* If local system doesn't support FIFOs, use default case */ + case LF_FIFO: + make_fifo: + check = mkfifo (current_file_name + skipcrud, + (int) hstat.st_mode); + if (check != 0) + { + if (make_dirs (current_file_name + skipcrud)) + goto make_fifo; + msg_perror ("Could not make %s", + skipcrud + current_file_name); + break; + }; + goto set_filestat; +#endif + + case LF_DIR: + case LF_DUMPDIR: + namelen = strlen (current_file_name + skipcrud) - 1; + really_dir: + /* Check for trailing /, and zap as many as we find. */ + while (namelen + && current_file_name[skipcrud + namelen] == '/') + current_file_name[skipcrud + namelen--] = '\0'; + if (f_gnudump) + { /* Read the entry and delete files + that aren't listed in the archive */ + gnu_restore (skipcrud); + + } + else if (head->header.linkflag == LF_DUMPDIR) + skip_file ((long) (hstat.st_size)); + + + again_dir: + check = mkdir (skipcrud + current_file_name, + (we_are_root ? 0 : 0300) | (int) hstat.st_mode); + if (check != 0) + { + struct stat st1; + + if (make_dirs (skipcrud + current_file_name)) + goto again_dir; + /* If we're trying to create '.', let it be. */ + if (current_file_name[skipcrud + namelen] == '.' && + (namelen == 0 || + current_file_name[skipcrud + namelen - 1] == '/')) + goto check_perms; + if (errno == EEXIST + && stat (skipcrud + current_file_name, &st1) == 0 + && (S_ISDIR (st1.st_mode))) + break; + msg_perror ("Could not create directory %s", skipcrud + current_file_name); + break; + } + + check_perms: + if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) + { + hstat.st_mode |= 0300; + msg ("Added write and execute permission to directory %s", + skipcrud + current_file_name); + } + + /* + * If we are root, set the owner and group of the extracted + * file. This does what is wanted both on real Unix and on + * System V. If we are running as a user, we extract as that + * user; if running as root, we extract as the original owner. + */ + if (we_are_root || f_do_chown) + { + if (chown (skipcrud + current_file_name, + hstat.st_uid, hstat.st_gid) < 0) + { + msg_perror ("cannot chown file %s to uid %d gid %d", + skipcrud + current_file_name, + hstat.st_uid, hstat.st_gid); + } + } + + if (!f_modified) + { + tmp = ((struct saved_dir_info *) + ck_malloc (sizeof (struct saved_dir_info))); + tmp->path = (char *) ck_malloc (strlen (skipcrud + + current_file_name) + 1); + strcpy (tmp->path, skipcrud + current_file_name); + tmp->mode = hstat.st_mode; + tmp->atime = hstat.st_atime; + tmp->mtime = hstat.st_mtime; + tmp->next = saved_dir_info_head; + saved_dir_info_head = tmp; + } + else + { + /* This functions exactly as the code for set_filestat above. */ + if ((!f_keep) + || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX))) + { + if (chmod (skipcrud + current_file_name, + notumask & (int) hstat.st_mode) < 0) + { + msg_perror ("cannot change mode of file %s to %ld", + skipcrud + current_file_name, + notumask & (int) hstat.st_mode); + } + } + } + break; + + case LF_VOLHDR: + if (f_verbose) + { + printf ("Reading %s\n", current_file_name); + } + break; + + case LF_NAMES: + extract_mangle (head); + break; + + case LF_MULTIVOL: + msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name); + skip_file ((long) hstat.st_size); + break; + + case LF_LONGNAME: + case LF_LONGLINK: + msg ("Visible long name error\n"); + skip_file ((long) hstat.st_size); + break; + } + + /* We don't need to save it any longer. */ + saverec ((union record **) 0);/* Unsave it */ +} + +/* + * After a file/link/symlink/dir creation has failed, see if + * it's because some required directory was not present, and if + * so, create all required dirs. + */ +int +make_dirs (pathname) + char *pathname; +{ + char *p; /* Points into path */ + int madeone = 0; /* Did we do anything yet? */ + int save_errno = errno; /* Remember caller's errno */ + int check; + + if (errno != ENOENT) + return 0; /* Not our problem */ + + for (p = index (pathname, '/'); p != NULL; p = index (p + 1, '/')) + { + /* Avoid mkdir of empty string, if leading or double '/' */ + if (p == pathname || p[-1] == '/') + continue; + /* Avoid mkdir where last part of path is '.' */ + if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/')) + continue; + *p = 0; /* Truncate the path there */ + check = mkdir (pathname, 0777); /* Try to create it as a dir */ + if (check == 0) + { + /* Fix ownership */ + if (we_are_root) + { + if (chown (pathname, hstat.st_uid, + hstat.st_gid) < 0) + { + msg_perror ("cannot change owner of %s to uid %d gid %d", pathname, hstat.st_uid, hstat.st_gid); + } + } + pr_mkdir (pathname, p - pathname, notumask & 0777); + madeone++; /* Remember if we made one */ + *p = '/'; + continue; + } + *p = '/'; + if (errno == EEXIST) /* Directory already exists */ + continue; + /* + * Some other error in the mkdir. We return to the caller. + */ + break; + } + + errno = save_errno; /* Restore caller's errno */ + return madeone; /* Tell them to retry if we made one */ +} + +void +extract_sparse_file (fd, sizeleft, totalsize, name) + int fd; + long *sizeleft, totalsize; + char *name; +{ + /* register char *data;*/ + union record *datarec; + int sparse_ind = 0; + int written, count; + + /* assuming sizeleft is initially totalsize */ + + + while (*sizeleft > 0) + { + datarec = findrec (); + if (datarec == NULL) + { + msg ("Unexpected EOF on archive file"); + return; + } + lseek (fd, sparsearray[sparse_ind].offset, 0); + written = sparsearray[sparse_ind++].numbytes; + while (written > RECORDSIZE) + { + count = write (fd, datarec->charptr, RECORDSIZE); + if (count < 0) + msg_perror ("couldn't write to file %s", name); + written -= count; + *sizeleft -= count; + userec (datarec); + datarec = findrec (); + } + + count = write (fd, datarec->charptr, written); + + if (count < 0) + { + msg_perror ("couldn't write to file %s", name); + } + else if (count != written) + { + msg ("could only write %d of %d bytes to file %s", count, + totalsize, name); + skip_file ((long) (*sizeleft)); + } + + written -= count; + *sizeleft -= count; + userec (datarec); + } + free (sparsearray); + /* if (end_nulls) { + register int i; + + printf("%d\n", (int) end_nulls); + for (i = 0; i < end_nulls; i++) + write(fd, "\000", 1); + }*/ + userec (datarec); +} + +/* Set back the utime and mode for all the extracted directories. */ +void +restore_saved_dir_info () +{ + struct utimbuf acc_upd_times; + + while (saved_dir_info_head != NULL) + { + /* fixme if f_gnudump should set ctime too, but how? */ + if (f_gnudump) + acc_upd_times.actime = saved_dir_info_head->atime; + else + acc_upd_times.actime = now; /* Accessed now */ + acc_upd_times.modtime = saved_dir_info_head->mtime; /* Mod'd */ + if (utime (saved_dir_info_head->path, &acc_upd_times) < 0) + { + msg_perror ("couldn't change access and modification times of %s", + saved_dir_info_head->path); + } + if ((!f_keep) || (saved_dir_info_head->mode & (S_ISUID | S_ISGID | S_ISVTX))) + { + if (chmod (saved_dir_info_head->path, + notumask & saved_dir_info_head->mode) < 0) + { + msg_perror ("cannot change mode of file %s to %ld", + saved_dir_info_head->path, + notumask & saved_dir_info_head->mode); + } + } + saved_dir_info_head = saved_dir_info_head->next; + } +} diff --git a/gnu/usr.bin/tar/fnmatch.c b/gnu/usr.bin/tar/fnmatch.c new file mode 100644 index 0000000000..ed8c9eea7e --- /dev/null +++ b/gnu/usr.bin/tar/fnmatch.c @@ -0,0 +1,173 @@ +/* Copyright (C) 1991, 1992 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. */ + +#include +#include + +#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; + + 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; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} diff --git a/gnu/usr.bin/tar/fnmatch.h b/gnu/usr.bin/tar/fnmatch.h new file mode 100644 index 0000000000..d4150a9a99 --- /dev/null +++ b/gnu/usr.bin/tar/fnmatch.h @@ -0,0 +1,62 @@ +/* Copyright (C) 1991, 1992 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) () +#undef const +#define const +#endif /* C++ or ANSI C. */ + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#ifdef FNM_PATHNAME /* Because it is already defined in */ +#undef FNM_PATHNAME +#endif +#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. */ +#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD|FNM_LEADING_DIR) + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_BSD_SOURCE) +#define FNM_LEADING_DIR (1 << 3)/* Ignore `/...' after a match. */ +#define FNM_FILE_NAME FNM_PATHNAME +#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/tar/getdate.y b/gnu/usr.bin/tar/getdate.y new file mode 100644 index 0000000000..7b0ac79924 --- /dev/null +++ b/gnu/usr.bin/tar/getdate.y @@ -0,0 +1,969 @@ +%{ +/* $Revision: 2.1 $ +** +** Originally written by Steven M. Bellovin while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** and Jim Berets 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 *//* Unusd static variable */ +/* SUPPRESS 288 on yyerrlab *//* Label unused */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#ifdef HAVE_ALLOCA_H +#include +#else +#ifdef _AIX /* for Bison */ + #pragma alloca +#else +char *alloca (); +#endif +#endif +#endif + +#include +#include + +/* The code at the top of get_date which figures out the offset of the + current time zone checks various CPP symbols to see if special + tricks are need, but defaults to using the gettimeofday system call. + Include if that will be used. */ + +#if !defined (USG) && !defined (sgi) && !defined (__386BSD__) +#include +#endif + +#if defined(vms) + +#include +#include + +#else + +#include + +#if defined(USG) || !defined(HAVE_FTIME) +/* +** If you need to do a tzset() call to set the +** timezone, and don't have ftime(). +*/ +struct timeb { + time_t time; /* Seconds since the epoch */ + unsigned short millitm; /* Field not used */ + short timezone; + short dstflag; /* Field not used */ +}; + +#else + +#include + +#endif /* defined(USG) && !defined(HAVE_FTIME) */ + +#if defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux)) +#include +#else +#if defined(_AIX) +#include +#endif +#include +#endif /* defined(BSD4_2) */ + +#endif /* defined(vms) */ + +#if defined (STDC_HEADERS) || defined (USG) +#include +#endif + +#if sgi +#undef timezone +#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[] = + "$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $"; +#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 tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT +%type tSEC_UNIT tSNUMBER tUNUMBER tZONE +%type tMERIDIAN o_merid + +%% + +spec : /* NULL */ + | spec item + ; + +item : time { + yyHaveTime++; + } + | zone { + yyHaveZone++; + } + | date { + yyHaveDate++; + } + | day { + yyHaveDay++; + } + | rel { + yyHaveRel++; + } + | number + ; + +time : tUNUMBER tMERIDIAN { + yyHour = $1; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = $2; + } + | tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = 0; + yyMeridian = $4; + } + | tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - ($4 % 100 + ($4 / 100) * 60); + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = $6; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - ($6 % 100 + ($6 / 100) * 60); + } + ; + +zone : tZONE { + yyTimezone = $1; + yyDSTmode = DSToff; + } + | tDAYZONE { + yyTimezone = $1; + yyDSTmode = DSTon; + } + | + tZONE tDST { + yyTimezone = $1; + yyDSTmode = DSTon; + } + ; + +day : tDAY { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tDAY ',' { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tUNUMBER tDAY { + yyDayOrdinal = $1; + yyDayNumber = $2; + } + ; + +date : tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + } + | tUNUMBER '/' tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + yyYear = $5; + } + | tUNUMBER tSNUMBER tSNUMBER { + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = $1; + yyMonth = -$2; + yyDay = -$3; + } + | 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 const MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "sept", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + { "sunday", tDAY, 0 }, + { "monday", tDAY, 1 }, + { "tuesday", tDAY, 2 }, + { "tues", tDAY, 2 }, + { "wednesday", tDAY, 3 }, + { "wednes", tDAY, 3 }, + { "thursday", tDAY, 4 }, + { "thur", tDAY, 4 }, + { "thurs", tDAY, 4 }, + { "friday", tDAY, 5 }, + { "saturday", tDAY, 6 }, + { NULL } +}; + +/* Time units table. */ +static TABLE const UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, + { "week", tMINUTE_UNIT, 7 * 24 * 60 }, + { "day", tMINUTE_UNIT, 1 * 24 * 60 }, + { "hour", tMINUTE_UNIT, 60 }, + { "minute", tMINUTE_UNIT, 1 }, + { "min", tMINUTE_UNIT, 1 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, + { NULL } +}; + +/* Assorted relative-time words. */ +static TABLE const OtherTable[] = { + { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, + { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, + { "today", tMINUTE_UNIT, 0 }, + { "now", tMINUTE_UNIT, 0 }, + { "last", tUNUMBER, -1 }, + { "this", tMINUTE_UNIT, 0 }, + { "next", tUNUMBER, 2 }, + { "first", tUNUMBER, 1 }, +/* { "second", tUNUMBER, 2 }, */ + { "third", tUNUMBER, 3 }, + { "fourth", tUNUMBER, 4 }, + { "fifth", tUNUMBER, 5 }, + { "sixth", tUNUMBER, 6 }, + { "seventh", tUNUMBER, 7 }, + { "eighth", tUNUMBER, 8 }, + { "ninth", tUNUMBER, 9 }, + { "tenth", tUNUMBER, 10 }, + { "eleventh", tUNUMBER, 11 }, + { "twelfth", tUNUMBER, 12 }, + { "ago", tAGO, 1 }, + { NULL } +}; + +/* The timezone table. */ +/* Some of these are commented out because a time_t can't store a float. */ +static TABLE const TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ + { "utc", tZONE, HOUR( 0) }, + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "wat", tZONE, HOUR( 1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ +#if 0 + /* For completeness. BST is also British Summer, and GST is + * also Guam Standard. */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ +#endif +#if 0 + { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ + { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ +#endif + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ + { "cat", tZONE, HOUR(10) }, /* Central Alaska */ + { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ + { "nt", tZONE, HOUR(11) }, /* Nome */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ +#if 0 + { "it", tZONE, -HOUR(3.5) },/* Iran */ +#endif + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ +#if 0 + { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ +#endif + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ +#if 0 + /* For completeness. NST is also Newfoundland Stanard, and SST is + * also Swedish Summer. */ + { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ +#endif /* 0 */ + { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ +#if 0 + { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ +#endif + { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ +#if 0 + { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ + { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ +#endif + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { NULL } +}; + +/* Military timezone table. */ +static TABLE const MilitaryTable[] = { + { "a", tZONE, HOUR( 1) }, + { "b", tZONE, HOUR( 2) }, + { "c", tZONE, HOUR( 3) }, + { "d", tZONE, HOUR( 4) }, + { "e", tZONE, HOUR( 5) }, + { "f", tZONE, HOUR( 6) }, + { "g", tZONE, HOUR( 7) }, + { "h", tZONE, HOUR( 8) }, + { "i", tZONE, HOUR( 9) }, + { "k", tZONE, HOUR( 10) }, + { "l", tZONE, HOUR( 11) }, + { "m", tZONE, HOUR( 12) }, + { "n", tZONE, HOUR(- 1) }, + { "o", tZONE, HOUR(- 2) }, + { "p", tZONE, HOUR(- 3) }, + { "q", tZONE, HOUR(- 4) }, + { "r", tZONE, HOUR(- 5) }, + { "s", tZONE, HOUR(- 6) }, + { "t", tZONE, HOUR(- 7) }, + { "u", tZONE, HOUR(- 8) }, + { "v", tZONE, HOUR(- 9) }, + { "w", tZONE, HOUR(-10) }, + { "x", tZONE, HOUR(-11) }, + { "y", tZONE, HOUR(-12) }, + { "z", tZONE, HOUR( 0) }, + { NULL } +}; + + + + +/* ARGSUSED */ +static int +yyerror(s) + char *s; +{ + return 0; +} + + +static time_t +ToSeconds(Hours, Minutes, Seconds, Meridian) + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) + return -1; + switch (Meridian) { + case MER24: + if (Hours < 0 || Hours > 23) + return -1; + return (Hours * 60L + Minutes) * 60L + Seconds; + case MERam: + if (Hours < 1 || Hours > 12) + return -1; + return (Hours * 60L + Minutes) * 60L + Seconds; + case MERpm: + if (Hours < 1 || Hours > 12) + return -1; + return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; + } + /* NOTREACHED */ +} + + +static time_t +Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode) + time_t Month; + time_t Day; + time_t Year; + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; + DSTMODE DSTmode; +{ + static int DaysInMonth[12] = { + 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + time_t tod; + time_t Julian; + int i; + + if (Year < 0) + Year = -Year; + if (Year < 100) + Year += 1900; + DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) + ? 29 : 28; + if (Year < EPOCH || Year > 1999 + || Month < 1 || Month > 12 + /* Lint fluff: "conversion from long may lose accuracy" */ + || Day < 1 || Day > DaysInMonth[(int)--Month]) + return -1; + + for (Julian = Day - 1, i = 0; i < Month; i++) + Julian += DaysInMonth[i]; + for (i = EPOCH; i < Year; i++) + Julian += 365 + (i % 4 == 0); + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) + return -1; + Julian += tod; + if (DSTmode == DSTon + || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) + Julian -= 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect(Start, Future) + time_t Start; + time_t Future; +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; +} + + +static time_t +RelativeDate(Start, DayOrdinal, DayNumber) + time_t Start; + time_t DayOrdinal; + time_t DayNumber; +{ + struct tm *tm; + time_t now; + + now = Start; + tm = localtime(&now); + now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); + now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); + return DSTcorrect(Start, now); +} + + +static time_t +RelativeMonth(Start, RelMonth) + time_t Start; + time_t RelMonth; +{ + struct tm *tm; + time_t Month; + time_t Year; + + if (RelMonth == 0) + return 0; + tm = localtime(&Start); + Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; + Year = Month / 12; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int +LookupWord(buff) + char *buff; +{ + register char *p; + register char *q; + register const TABLE *tp; + int i; + int abbrev; + + /* Make it lowercase. */ + for (p = buff; *p; p++) + if (isupper(*p)) + *p = tolower(*p); + + if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + + /* See if we have an abbreviation for a month. */ + if (strlen(buff) == 3) + abbrev = 1; + else if (strlen(buff) == 4 && buff[3] == '.') { + abbrev = 1; + buff[3] = '\0'; + } + else + abbrev = 0; + + for (tp = MonthDayTable; tp->name; tp++) { + if (abbrev) { + if (strncmp(buff, tp->name, 3) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + else if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + if (strcmp(buff, "dst") == 0) + return tDST; + + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + i = strlen(buff) - 1; + if (buff[i] == 's') { + buff[i] = '\0'; + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + buff[i] = 's'; /* Put back for "this" in OtherTable. */ + } + + for (tp = OtherTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Military timezones. */ + if (buff[1] == '\0' && isalpha(*buff)) { + for (tp = MilitaryTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Drop out any periods and try the timezone table again. */ + for (i = 0, p = q = buff; *q; q++) + if (*q != '.') + *p++ = *q; + else + i++; + *p = '\0'; + if (i) + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + return tID; +} + + +static int +yylex() +{ + register char c; + register char *p; + char buff[20]; + int Count; + int sign; + + for ( ; ; ) { + while (isspace(*yyInput)) + yyInput++; + + if (isdigit(c = *yyInput) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + if (!isdigit(*++yyInput)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + for (yylval.Number = 0; isdigit(c = *yyInput++); ) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + if (sign < 0) + yylval.Number = -yylval.Number; + return sign ? tSNUMBER : tUNUMBER; + } + if (isalpha(c)) { + for (p = buff; isalpha(c = *yyInput++) || c == '.'; ) + if (p < &buff[sizeof buff - 1]) + *p++ = c; + *p = '\0'; + yyInput--; + return LookupWord(buff); + } + if (c != '(') + return *yyInput++; + Count = 0; + do { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } while (Count > 0); + } +} + + +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(HAVE_FTIME) + (void)time(&ftz.time); + /* Set the timezone global. */ + tzset(); + { +#if sgi + ftz.timezone = (int) _timezone / 60; +#else /* not sgi */ +#ifdef __386BSD__ + ftz.timezone = 0; +#else /* neither sgi nor 386BSD */ +#if defined (USG) + extern time_t timezone; + + ftz.timezone = (int) timezone / 60; +#else /* neither sgi nor 386BSD nor USG */ + struct timeval tv; + struct timezone tz; + + gettimeofday (&tv, &tz); + ftz.timezone = (int) tz.tz_minuteswest; +#endif /* neither sgi nor 386BSD nor USG */ +#endif /* neither sgi nor 386BSD */ +#endif /* not sgi */ + } +#else /* HAVE_FTIME */ + (void)ftime(&ftz); +#endif /* HAVE_FTIME */ + } + + tm = localtime(&now->time); + yyYear = tm->tm_year; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = now->timezone; + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse() + || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + if (yyHaveDate || yyHaveTime || yyHaveDay) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } + else { + Start = now->time; + if (!yyHaveRel) + Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; + } + + Start += yyRelSeconds; + Start += RelativeMonth(Start, yyRelMonth); + + if (yyHaveDay && !yyHaveDate) { + tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); + Start += tod; + } + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} + + +#if defined(TEST) + +/* ARGSUSED */ +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/tar/getoldopt.c b/gnu/usr.bin/tar/getoldopt.c new file mode 100644 index 0000000000..27511b94b3 --- /dev/null +++ b/gnu/usr.bin/tar/getoldopt.c @@ -0,0 +1,96 @@ +/* Replacement for getopt() that can be used by tar. + Copyright (C) 1988 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Plug-compatible replacement for getopt() for parsing tar-like + * arguments. If the first argument begins with "-", it uses getopt; + * otherwise, it uses the old rules used by tar, dump, and ps. + * + * Written 25 August 1985 by John Gilmore (ihnp4!hoptoad!gnu) + */ + +#include +#include "getopt.h" +#include "tar.h" /* For msg() declaration if STDC_MSG. */ +#include +#include "port.h" + +int +getoldopt (argc, argv, optstring, long_options, opt_index) + int argc; + char **argv; + char *optstring; + struct option *long_options; + int *opt_index; +{ + extern char *optarg; /* Points to next arg */ + extern int optind; /* Global argv index */ + static char *key; /* Points to next keyletter */ + static char use_getopt; /* !=0 if argv[1][0] was '-' */ + char c; + char *place; + + optarg = NULL; + + if (key == NULL) + { /* First time */ + if (argc < 2) + return EOF; + key = argv[1]; + if ((*key == '-') || (*key == '+')) + use_getopt++; + else + optind = 2; + } + + if (use_getopt) + return getopt_long (argc, argv, optstring, + long_options, opt_index); + + c = *key++; + if (c == '\0') + { + key--; + return EOF; + } + place = index (optstring, c); + + if (place == NULL || c == ':') + { + msg ("unknown option %c", c); + return ('?'); + } + + place++; + if (*place == ':') + { + if (optind < argc) + { + optarg = argv[optind]; + optind++; + } + else + { + msg ("%c argument missing", c); + return ('?'); + } + } + + return (c); +} diff --git a/gnu/usr.bin/tar/getopt.c b/gnu/usr.bin/tar/getopt.c new file mode 100644 index 0000000000..3db9abf121 --- /dev/null +++ b/gnu/usr.bin/tar/getopt.c @@ -0,0 +1,712 @@ +/* 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 +#else +#ifndef _AIX +char *alloca (); +#endif +#endif /* alloca.h */ +#endif /* not __GNUC__ */ + +#if !__STDC__ && !defined(const) && IN_GCC +#define const +#endif + +#include + +/* 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 +#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 +#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; + int chr; +{ + while (*string) + { + if (*string == chr) + return string; + string++; + } + 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. */ + +/* 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); +} + +#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/tar/getopt.h b/gnu/usr.bin/tar/getopt.h new file mode 100644 index 0000000000..93a5cf7781 --- /dev/null +++ b/gnu/usr.bin/tar/getopt.h @@ -0,0 +1,125 @@ +/* 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, 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; + +/* 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/tar/getopt1.c b/gnu/usr.bin/tar/getopt1.c new file mode 100644 index 0000000000..c3582cfa5c --- /dev/null +++ b/gnu/usr.bin/tar/getopt1.c @@ -0,0 +1,161 @@ +/* Getopt for GNU. + Copyright (C) 1987, 88, 89, 90, 91, 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. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#if !__STDC__ && !defined(const) && IN_GCC +#define const +#endif + +#include + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#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); +} + +#ifdef TEST + +#include + +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/tar/getpagesize.h b/gnu/usr.bin/tar/getpagesize.h new file mode 100644 index 0000000000..2d43f262c7 --- /dev/null +++ b/gnu/usr.bin/tar/getpagesize.h @@ -0,0 +1,38 @@ +#ifdef BSD +#ifndef BSD4_1 +#define HAVE_GETPAGESIZE +#endif +#endif + +#ifndef HAVE_GETPAGESIZE + +#ifdef VMS +#define getpagesize() 512 +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef _SC_PAGESIZE +#define getpagesize() sysconf(_SC_PAGESIZE) +#else + +#include + +#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 /* no _SC_PAGESIZE */ + +#endif /* not HAVE_GETPAGESIZE */ + diff --git a/gnu/usr.bin/tar/gnu.c b/gnu/usr.bin/tar/gnu.c new file mode 100644 index 0000000000..ef51f2b5fe --- /dev/null +++ b/gnu/usr.bin/tar/gnu.c @@ -0,0 +1,677 @@ +/* GNU dump extensions to tar. + Copyright (C) 1988, 1992, 1993 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#ifndef STDC_HEADERS +extern int errno; +#endif +#include +time_t time (); + +#include "tar.h" +#include "port.h" + +#ifndef S_ISLNK +#define lstat stat +#endif + +extern time_t new_time; +extern FILE *msg_file; + +void addname (); +int check_exclude (); +extern PTR ck_malloc (); +extern PTR ck_realloc (); +int confirm (); +extern PTR init_buffer (); +extern char *get_buffer (); +int is_dot_or_dotdot (); +extern void add_buffer (); +extern void flush_buffer (); +void name_gather (); +int recursively_delete (); +void skip_file (); +char *un_quote_string (); + +extern char *new_name (); + +static void add_dir_name (); + +struct dirname + { + struct dirname *next; + char *name; + char *dir_text; + int dev; + int ino; + int allnew; + }; +static struct dirname *dir_list; +static time_t this_time; + +void +add_dir (name, dev, ino, text) + char *name; + char *text; + dev_t dev; + ino_t ino; +{ + struct dirname *dp; + + dp = (struct dirname *) ck_malloc (sizeof (struct dirname)); + if (!dp) + abort (); + dp->next = dir_list; + dir_list = dp; + dp->dev = dev; + dp->ino = ino; + dp->name = ck_malloc (strlen (name) + 1); + strcpy (dp->name, name); + dp->dir_text = text; + dp->allnew = 0; +} + +void +read_dir_file () +{ + int dev; + int ino; + char *strp; + FILE *fp; + char buf[512]; + static char *path = 0; + + if (path == 0) + path = ck_malloc (PATH_MAX); + time (&this_time); + if (gnu_dumpfile[0] != '/') + { +#if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION) + if (!getcwd (path, PATH_MAX)) + { + msg ("Couldn't get current directory."); + exit (EX_SYSTEM); + } +#else + char *getwd (); + + if (!getwd (path)) + { + msg ("Couldn't get current directory: %s", path); + exit (EX_SYSTEM); + } +#endif + /* If this doesn't fit, we're in serious trouble */ + strcat (path, "/"); + strcat (path, gnu_dumpfile); + gnu_dumpfile = path; + } + fp = fopen (gnu_dumpfile, "r"); + if (fp == 0 && errno != ENOENT) + { + msg_perror ("Can't open %s", gnu_dumpfile); + return; + } + if (!fp) + return; + fgets (buf, sizeof (buf), fp); + if (!f_new_files) + { + f_new_files++; + new_time = atol (buf); + } + while (fgets (buf, sizeof (buf), fp)) + { + strp = &buf[strlen (buf)]; + if (strp[-1] == '\n') + strp[-1] = '\0'; + strp = buf; + dev = atol (strp); + while (isdigit (*strp)) + strp++; + ino = atol (strp); + while (isspace (*strp)) + strp++; + while (isdigit (*strp)) + strp++; + strp++; + add_dir (un_quote_string (strp), dev, ino, (char *) 0); + } + fclose (fp); +} + +void +write_dir_file () +{ + FILE *fp; + struct dirname *dp; + char *str; + extern char *quote_copy_string (); + + fp = fopen (gnu_dumpfile, "w"); + if (fp == 0) + { + msg_perror ("Can't write to %s", gnu_dumpfile); + return; + } + fprintf (fp, "%lu\n", this_time); + for (dp = dir_list; dp; dp = dp->next) + { + if (!dp->dir_text) + continue; + str = quote_copy_string (dp->name); + if (str) + { + fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, str); + free (str); + } + else + fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, dp->name); + } + fclose (fp); +} + +struct dirname * +get_dir (name) + char *name; +{ + struct dirname *dp; + + for (dp = dir_list; dp; dp = dp->next) + { + if (!strcmp (dp->name, name)) + return dp; + } + return 0; +} + + +/* Collect all the names from argv[] (or whatever), then expand them into + a directory tree, and put all the directories at the beginning. */ +void +collect_and_sort_names () +{ + struct name *n, *n_next; + int num_names; + struct stat statbuf; + int name_cmp (); + char *merge_sort (); + + name_gather (); + + if (gnu_dumpfile) + read_dir_file (); + if (!namelist) + addname ("."); + for (n = namelist; n; n = n_next) + { + n_next = n->next; + if (n->found || n->dir_contents) + continue; + if (n->regexp) /* FIXME just skip regexps for now */ + continue; + if (n->change_dir) + if (chdir (n->change_dir) < 0) + { + msg_perror ("can't chdir to %s", n->change_dir); + continue; + } + +#ifdef AIX + if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK)) +#else + if (lstat (n->name, &statbuf) < 0) +#endif /* AIX */ + { + msg_perror ("can't stat %s", n->name); + continue; + } + if (S_ISDIR (statbuf.st_mode)) + { + n->found++; + add_dir_name (n->name, statbuf.st_dev); + } + } + + num_names = 0; + for (n = namelist; n; n = n->next) + num_names++; + namelist = (struct name *) merge_sort ((PTR) namelist, num_names, (char *) (&(namelist->next)) - (char *) namelist, name_cmp); + + for (n = namelist; n; n = n->next) + { + n->found = 0; + } + if (gnu_dumpfile) + write_dir_file (); +} + +int +name_cmp (n1, n2) + struct name *n1, *n2; +{ + if (n1->found) + { + if (n2->found) + return strcmp (n1->name, n2->name); + else + return -1; + } + else if (n2->found) + return 1; + else + return strcmp (n1->name, n2->name); +} + +int +dirent_cmp (p1, p2) + const PTR p1; + const PTR p2; +{ + char *frst, *scnd; + + frst = (*(char **) p1) + 1; + scnd = (*(char **) p2) + 1; + + return strcmp (frst, scnd); +} + +char * +get_dir_contents (p, device) + char *p; + int device; +{ + DIR *dirp; + register struct dirent *d; + char *new_buf; + char *namebuf; + int bufsiz; + int len; + PTR the_buffer; + char *buf; + size_t n_strs; + /* int n_size;*/ + char *p_buf; + char **vec, **p_vec; + + extern int errno; + + errno = 0; + dirp = opendir (p); + bufsiz = strlen (p) + NAMSIZ; + namebuf = ck_malloc (bufsiz + 2); + if (!dirp) + { + if (errno) + msg_perror ("can't open directory %s", p); + else + msg ("error opening directory %s", p); + new_buf = NULL; + } + else + { + struct dirname *dp; + int all_children; + + dp = get_dir (p); + all_children = dp ? dp->allnew : 0; + (void) strcpy (namebuf, p); + if (p[strlen (p) - 1] != '/') + (void) strcat (namebuf, "/"); + len = strlen (namebuf); + + the_buffer = init_buffer (); + while (d = readdir (dirp)) + { + struct stat hs; + + /* Skip . and .. */ + if (is_dot_or_dotdot (d->d_name)) + continue; + if (NLENGTH (d) + len >= bufsiz) + { + bufsiz += NAMSIZ; + namebuf = ck_realloc (namebuf, bufsiz + 2); + } + (void) strcpy (namebuf + len, d->d_name); +#ifdef AIX + if (0 != f_follow_links ? + statx (namebuf, &hs, STATSIZE, STX_HIDDEN) : + statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK)) +#else + if (0 != f_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs)) +#endif + { + msg_perror ("can't stat %s", namebuf); + continue; + } + if ((f_local_filesys && device != hs.st_dev) + || (f_exclude && check_exclude (namebuf))) + add_buffer (the_buffer, "N", 1); +#ifdef AIX + else if (S_ISHIDDEN (hs.st_mode)) + { + add_buffer (the_buffer, "D", 1); + strcat (d->d_name, "A"); + d->d_namlen++; + } +#endif /* AIX */ + else if (S_ISDIR (hs.st_mode)) + { + if (dp = get_dir (namebuf)) + { + if (dp->dev != hs.st_dev + || dp->ino != hs.st_ino) + { + if (f_verbose) + msg ("directory %s has been renamed.", namebuf); + dp->allnew = 1; + dp->dev = hs.st_dev; + dp->ino = hs.st_ino; + } + dp->dir_text = ""; + } + else + { + if (f_verbose) + msg ("Directory %s is new", namebuf); + add_dir (namebuf, hs.st_dev, hs.st_ino, ""); + dp = get_dir (namebuf); + dp->allnew = 1; + } + if (all_children) + dp->allnew = 1; + + add_buffer (the_buffer, "D", 1); + } + else if (!all_children + && f_new_files + && new_time > hs.st_mtime + && (f_new_files > 1 + || new_time > hs.st_ctime)) + add_buffer (the_buffer, "N", 1); + else + add_buffer (the_buffer, "Y", 1); + add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1)); + } + add_buffer (the_buffer, "\000\000", 2); + closedir (dirp); + + /* Well, we've read in the contents of the dir, now sort them */ + buf = get_buffer (the_buffer); + if (buf[0] == '\0') + { + flush_buffer (the_buffer); + new_buf = NULL; + } + else + { + n_strs = 0; + for (p_buf = buf; *p_buf;) + { + int tmp; + + tmp = strlen (p_buf) + 1; + n_strs++; + p_buf += tmp; + } + vec = (char **) ck_malloc (sizeof (char *) * (n_strs + 1)); + for (p_vec = vec, p_buf = buf; *p_buf; p_buf += strlen (p_buf) + 1) + *p_vec++ = p_buf; + *p_vec = 0; + qsort ((PTR) vec, n_strs, sizeof (char *), dirent_cmp); + new_buf = (char *) ck_malloc (p_buf - buf + 2); + for (p_vec = vec, p_buf = new_buf; *p_vec; p_vec++) + { + char *p_tmp; + + for (p_tmp = *p_vec; *p_buf++ = *p_tmp++;) + ; + } + *p_buf++ = '\0'; + free (vec); + flush_buffer (the_buffer); + } + } + free (namebuf); + return new_buf; +} + +/* p is a directory. Add all the files in P to the namelist. If any of the + files is a directory, recurse on the subdirectory. . . */ +static void +add_dir_name (p, device) + char *p; + int device; +{ + char *new_buf; + char *p_buf; + + char *namebuf; + int buflen; + register int len; + int sublen; + + /* PTR the_buffer;*/ + + /* char *buf;*/ + /* char **vec,**p_vec;*/ + /* int n_strs,n_size;*/ + + struct name *n; + + int dirent_cmp (); + + new_buf = get_dir_contents (p, device); + + for (n = namelist; n; n = n->next) + { + if (!strcmp (n->name, p)) + { + n->dir_contents = new_buf ? new_buf : "\0\0\0\0"; + break; + } + } + + if (new_buf) + { + len = strlen (p); + buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ; + namebuf = ck_malloc (buflen + 1); + + (void) strcpy (namebuf, p); + if (namebuf[len - 1] != '/') + { + namebuf[len++] = '/'; + namebuf[len] = '\0'; + } + for (p_buf = new_buf; *p_buf; p_buf += sublen + 1) + { + sublen = strlen (p_buf); + if (*p_buf == 'D') + { + if (len + sublen >= buflen) + { + buflen += NAMSIZ; + namebuf = ck_realloc (namebuf, buflen + 1); + } + (void) strcpy (namebuf + len, p_buf + 1); + addname (namebuf); + add_dir_name (namebuf, device); + } + } + free (namebuf); + } +} + +/* Returns non-zero if p is . or .. This could be a macro for speed. */ +int +is_dot_or_dotdot (p) + char *p; +{ + return (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0'))); +} + + + + + + +void +gnu_restore (skipcrud) + int skipcrud; +{ + char *current_dir; + /* int current_dir_length; */ + + char *archive_dir; + /* int archive_dir_length; */ + PTR the_buffer; + char *p; + DIR *dirp; + struct dirent *d; + char *cur, *arc; + extern struct stat hstat; /* Stat struct corresponding */ + long size, copied; + char *from, *to; + extern union record *head; + + dirp = opendir (skipcrud + current_file_name); + + if (!dirp) + { + /* The directory doesn't exist now. It'll be created. + In any case, we don't have to delete any files out + of it */ + skip_file ((long) hstat.st_size); + return; + } + + the_buffer = init_buffer (); + while (d = readdir (dirp)) + { + if (is_dot_or_dotdot (d->d_name)) + continue; + + add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1)); + } + closedir (dirp); + add_buffer (the_buffer, "", 1); + + current_dir = get_buffer (the_buffer); + archive_dir = (char *) ck_malloc (hstat.st_size); + if (archive_dir == 0) + { + msg ("Can't allocate %d bytes for restore", hstat.st_size); + skip_file ((long) hstat.st_size); + return; + } + to = archive_dir; + for (size = hstat.st_size; size > 0; size -= copied) + { + from = findrec ()->charptr; + if (!from) + { + msg ("Unexpected EOF in archive\n"); + break; + } + copied = endofrecs ()->charptr - from; + if (copied > size) + copied = size; + bcopy ((PTR) from, (PTR) to, (int) copied); + to += copied; + userec ((union record *) (from + copied - 1)); + } + + for (cur = current_dir; *cur; cur += strlen (cur) + 1) + { + for (arc = archive_dir; *arc; arc += strlen (arc) + 1) + { + arc++; + if (!strcmp (arc, cur)) + break; + } + if (*arc == '\0') + { + p = new_name (skipcrud + current_file_name, cur); + if (f_confirm && !confirm ("delete", p)) + { + free (p); + continue; + } + if (f_verbose) + fprintf (msg_file, "%s: deleting %s\n", tar, p); + if (recursively_delete (p)) + { + msg ("%s: Error while deleting %s\n", tar, p); + } + free (p); + } + + } + flush_buffer (the_buffer); + free (archive_dir); +} + +int +recursively_delete (path) + char *path; +{ + struct stat sbuf; + DIR *dirp; + struct dirent *dp; + char *path_buf; + /* int path_len; */ + + + if (lstat (path, &sbuf) < 0) + return 1; + if (S_ISDIR (sbuf.st_mode)) + { + + /* path_len=strlen(path); */ + dirp = opendir (path); + if (dirp == 0) + return 1; + while (dp = readdir (dirp)) + { + if (is_dot_or_dotdot (dp->d_name)) + continue; + path_buf = new_name (path, dp->d_name); + if (recursively_delete (path_buf)) + { + free (path_buf); + closedir (dirp); + return 1; + } + free (path_buf); + } + closedir (dirp); + + if (rmdir (path) < 0) + return 1; + return 0; + } + if (unlink (path) < 0) + return 1; + return 0; +} diff --git a/gnu/usr.bin/tar/list.c b/gnu/usr.bin/tar/list.c new file mode 100644 index 0000000000..a0c65a334b --- /dev/null +++ b/gnu/usr.bin/tar/list.c @@ -0,0 +1,881 @@ +/* List a tar archive. + Copyright (C) 1988, 1992, 1993 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * List a tar archive. + * + * Also includes support routines for reading a tar archive. + * + * this version written 26 Aug 1985 by John Gilmore (ihnp4!hoptoad!gnu). + */ + +#include +#include +#include +#include +#ifndef STDC_HEADERS +extern int errno; +#endif +#include + +#ifdef BSD42 +#include +#else +#ifndef V7 +#include +#endif +#endif + +#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) + +#include "tar.h" +#include "port.h" + +extern FILE *msg_file; + +long from_oct (); /* Decode octal number */ +void demode (); /* Print file mode */ +void restore_saved_dir_info (); +PTR ck_malloc (); + +union record *head; /* Points to current archive header */ +struct stat hstat; /* Stat struct corresponding */ +int head_standard; /* Tape header is in ANSI format */ + +int check_exclude (); +void close_archive (); +void decode_header (); +int findgid (); +int finduid (); +void name_gather (); +int name_match (); +void names_notfound (); +void open_archive (); +void print_header (); +int read_header (); +void saverec (); +void skip_file (); +void skip_extended_headers (); + +extern char *quote_copy_string (); + + +/* + * Main loop for reading an archive. + */ +void +read_and (do_something) + void (*do_something) (); +{ + int status = 3; /* Initial status at start of archive */ + int prev_status; + extern time_t new_time; + char save_linkflag; + + name_gather (); /* Gather all the names */ + open_archive (1); /* Open for reading */ + + for (;;) + { + prev_status = status; + status = read_header (); + switch (status) + { + + case 1: /* Valid header */ + /* We should decode next field (mode) first... */ + /* Ensure incoming names are null terminated. */ + + if (!name_match (current_file_name) + || (f_new_files && hstat.st_mtime < new_time) + || (f_exclude && check_exclude (current_file_name))) + { + + int isextended = 0; + + if (head->header.linkflag == LF_VOLHDR + || head->header.linkflag == LF_MULTIVOL + || head->header.linkflag == LF_NAMES) + { + (*do_something) (); + continue; + } + if (f_show_omitted_dirs + && head->header.linkflag == LF_DIR) + msg ("Omitting %s\n", current_file_name); + /* Skip past it in the archive */ + if (head->header.isextended) + isextended = 1; + save_linkflag = head->header.linkflag; + userec (head); + if (isextended) + { + /* register union record *exhdr; + + for (;;) { + exhdr = findrec(); + if (!exhdr->ext_hdr.isextended) { + userec(exhdr); + break; + } + } + userec(exhdr);*/ + skip_extended_headers (); + } + /* Skip to the next header on the archive */ + if (save_linkflag != LF_DIR) + skip_file ((long) hstat.st_size); + continue; + + } + + (*do_something) (); + continue; + + /* + * If the previous header was good, tell them + * that we are skipping bad ones. + */ + case 0: /* Invalid header */ + userec (head); + switch (prev_status) + { + case 3: /* Error on first record */ + msg ("Hmm, this doesn't look like a tar archive."); + /* FALL THRU */ + case 2: /* Error after record of zeroes */ + case 1: /* Error after header rec */ + msg ("Skipping to next file header..."); + case 0: /* Error after error */ + break; + } + continue; + + case 2: /* Record of zeroes */ + userec (head); + status = prev_status; /* If error after 0's */ + if (f_ignorez) + continue; + /* FALL THRU */ + case EOF: /* End of archive */ + break; + } + break; + }; + + restore_saved_dir_info (); + close_archive (); + names_notfound (); /* Print names not found */ +} + + +/* + * Print a header record, based on tar options. + */ +void +list_archive () +{ + extern char *save_name; + int isextended = 0; /* Flag to remember if head is extended */ + + /* Save the record */ + saverec (&head); + + /* Print the header record */ + if (f_verbose) + { + if (f_verbose > 1) + decode_header (head, &hstat, &head_standard, 0); + print_header (); + } + + if (f_gnudump && head->header.linkflag == LF_DUMPDIR) + { + size_t size, written, check; + char *data; + extern long save_totsize; + extern long save_sizeleft; + + userec (head); + if (f_multivol) + { + save_name = current_file_name; + save_totsize = hstat.st_size; + } + for (size = hstat.st_size; size > 0; size -= written) + { + if (f_multivol) + save_sizeleft = size; + data = findrec ()->charptr; + if (data == NULL) + { + msg ("EOF in archive file?"); + break; + } + written = endofrecs ()->charptr - data; + if (written > size) + written = size; + errno = 0; + check = fwrite (data, sizeof (char), written, msg_file); + userec ((union record *) (data + written - 1)); + if (check != written) + { + msg_perror ("only wrote %ld of %ld bytes to file %s", check, written, current_file_name); + skip_file ((long) (size) - written); + break; + } + } + if (f_multivol) + save_name = 0; + saverec ((union record **) 0); /* Unsave it */ + fputc ('\n', msg_file); + fflush (msg_file); + return; + + } + saverec ((union record **) 0);/* Unsave it */ + /* Check to see if we have an extended header to skip over also */ + if (head->header.isextended) + isextended = 1; + + /* Skip past the header in the archive */ + userec (head); + + /* + * If we needed to skip any extended headers, do so now, by + * reading extended headers and skipping past them in the + * archive. + */ + if (isextended) + { + /* register union record *exhdr; + + for (;;) { + exhdr = findrec(); + + if (!exhdr->ext_hdr.isextended) { + userec(exhdr); + break; + } + userec(exhdr); + }*/ + skip_extended_headers (); + } + + if (f_multivol) + save_name = current_file_name; + /* Skip to the next header on the archive */ + + skip_file ((long) hstat.st_size); + + if (f_multivol) + save_name = 0; +} + + +/* + * Read a record that's supposed to be a header record. + * Return its address in "head", and if it is good, the file's + * size in hstat.st_size. + * + * Return 1 for success, 0 if the checksum is bad, EOF on eof, + * 2 for a record full of zeros (EOF marker). + * + * You must always userec(head) to skip past the header which this + * routine reads. + */ +int +read_header () +{ + register int i; + register long sum, signed_sum, recsum; + register char *p; + register union record *header; + long from_oct (); + char **longp; + char *bp, *data; + int size, written; + static char *next_long_name, *next_long_link; + char *name; + +recurse: + + header = findrec (); + head = header; /* This is our current header */ + if (NULL == header) + return EOF; + + recsum = from_oct (8, header->header.chksum); + + sum = 0; + p = header->charptr; + for (i = sizeof (*header); --i >= 0;) + { + /* + * We can't use unsigned char here because of old compilers, + * e.g. V7. + */ + signed_sum += *p; + sum += 0xFF & *p++; + } + + /* Adjust checksum to count the "chksum" field as blanks. */ + for (i = sizeof (header->header.chksum); --i >= 0;) + { + sum -= 0xFF & header->header.chksum[i]; + signed_sum -= (char) header->header.chksum[i]; + } + sum += ' ' * sizeof header->header.chksum; + signed_sum += ' ' * sizeof header->header.chksum; + + if (sum == 8 * ' ') + { + /* + * This is a zeroed record...whole record is 0's except + * for the 8 blanks we faked for the checksum field. + */ + return 2; + } + + if (sum != recsum && signed_sum != recsum) + return 0; + + /* + * Good record. Decode file size and return. + */ + if (header->header.linkflag == LF_LINK) + hstat.st_size = 0; /* Links 0 size on tape */ + else + hstat.st_size = from_oct (1 + 12, header->header.size); + + header->header.arch_name[NAMSIZ - 1] = '\0'; + if (header->header.linkflag == LF_LONGNAME + || header->header.linkflag == LF_LONGLINK) + { + longp = ((header->header.linkflag == LF_LONGNAME) + ? &next_long_name + : &next_long_link); + + userec (header); + if (*longp) + free (*longp); + bp = *longp = (char *) ck_malloc (hstat.st_size); + + for (size = hstat.st_size; + size > 0; + size -= written) + { + data = findrec ()->charptr; + if (data == NULL) + { + msg ("Unexpected EOF on archive file"); + break; + } + written = endofrecs ()->charptr - data; + if (written > size) + written = size; + + bcopy (data, bp, written); + bp += written; + userec ((union record *) (data + written - 1)); + } + goto recurse; + } + else + { + name = (next_long_name + ? next_long_name + : head->header.arch_name); + if (current_file_name) + free (current_file_name); + current_file_name = ck_malloc (strlen (name) + 1); + strcpy (current_file_name, name); + + name = (next_long_link + ? next_long_link + : head->header.arch_linkname); + if (current_link_name) + free (current_link_name); + current_link_name = ck_malloc (strlen (name) + 1); + strcpy (current_link_name, name); + + next_long_link = next_long_name = 0; + return 1; + } +} + + +/* + * Decode things from a file header record into a "struct stat". + * Also set "*stdp" to !=0 or ==0 depending whether header record is "Unix + * Standard" tar format or regular old tar format. + * + * read_header() has already decoded the checksum and length, so we don't. + * + * If wantug != 0, we want the uid/group info decoded from Unix Standard + * tapes (for extraction). If == 0, we are just printing anyway, so save time. + * + * decode_header should NOT be called twice for the same record, since the + * two calls might use different "wantug" values and thus might end up with + * different uid/gid for the two calls. If anybody wants the uid/gid they + * should decode it first, and other callers should decode it without uid/gid + * before calling a routine, e.g. print_header, that assumes decoded data. + */ +void +decode_header (header, st, stdp, wantug) + register union record *header; + register struct stat *st; + int *stdp; + int wantug; +{ + long from_oct (); + + st->st_mode = from_oct (8, header->header.mode); + st->st_mode &= 07777; + st->st_mtime = from_oct (1 + 12, header->header.mtime); + if (f_gnudump) + { + st->st_atime = from_oct (1 + 12, header->header.atime); + st->st_ctime = from_oct (1 + 12, header->header.ctime); + } + + if (0 == strcmp (header->header.magic, TMAGIC)) + { + /* Unix Standard tar archive */ + *stdp = 1; + if (wantug) + { +#ifdef NONAMES + st->st_uid = from_oct (8, header->header.uid); + st->st_gid = from_oct (8, header->header.gid); +#else + st->st_uid = + (*header->header.uname + ? finduid (header->header.uname) + : from_oct (8, header->header.uid)); + st->st_gid = + (*header->header.gname + ? findgid (header->header.gname) + : from_oct (8, header->header.gid)); +#endif + } +#if defined(S_IFBLK) || defined(S_IFCHR) + switch (header->header.linkflag) + { + case LF_BLK: + case LF_CHR: + st->st_rdev = makedev (from_oct (8, header->header.devmajor), + from_oct (8, header->header.devminor)); + } +#endif + } + else + { + /* Old fashioned tar archive */ + *stdp = 0; + st->st_uid = from_oct (8, header->header.uid); + st->st_gid = from_oct (8, header->header.gid); + st->st_rdev = 0; + } +} + + +/* + * Quick and dirty octal conversion. + * + * Result is -1 if the field is invalid (all blank, or nonoctal). + */ +long +from_oct (digs, where) + register int digs; + register char *where; +{ + register long value; + + while (isspace (*where)) + { /* Skip spaces */ + where++; + if (--digs <= 0) + return -1; /* All blank field */ + } + value = 0; + while (digs > 0 && isodigit (*where)) + { /* Scan til nonoctal */ + value = (value << 3) | (*where++ - '0'); + --digs; + } + + if (digs > 0 && *where && !isspace (*where)) + return -1; /* Ended on non-space/nul */ + + return value; +} + + +/* + * Actually print it. + * + * Plain and fancy file header block logging. + * Non-verbose just prints the name, e.g. for "tar t" or "tar x". + * This should just contain file names, so it can be fed back into tar + * with xargs or the "-T" option. The verbose option can give a bunch + * of info, one line per file. I doubt anybody tries to parse its + * format, or if they do, they shouldn't. Unix tar is pretty random here + * anyway. + * + * Note that print_header uses the globals , , and + * , which must be set up in advance. This is not very clean + * and should be cleaned up. FIXME. + */ +#define UGSWIDTH 18 /* min width of User, group, size */ +/* UGSWIDTH of 18 means that with user and group names <= 8 chars the columns + never shift during the listing. */ +#define DATEWIDTH 19 /* Last mod date */ +static int ugswidth = UGSWIDTH; /* Max width encountered so far */ + +void +print_header () +{ + char modes[11]; + char *timestamp; + char uform[11], gform[11]; /* These hold formatted ints */ + char *user, *group; + char size[24]; /* Holds a formatted long or maj, min */ + time_t longie; /* To make ctime() call portable */ + int pad; + char *name; + extern long baserec; + + if (f_sayblock) + fprintf (msg_file, "rec %10d: ", baserec + (ar_record - ar_block)); + /* annofile(msg_file, (char *)NULL); */ + + if (f_verbose <= 1) + { + /* Just the fax, mam. */ + char *name; + + name = quote_copy_string (current_file_name); + if (name == 0) + name = current_file_name; + fprintf (msg_file, "%s\n", name); + if (name != current_file_name) + free (name); + } + else + { + /* File type and modes */ + modes[0] = '?'; + switch (head->header.linkflag) + { + case LF_VOLHDR: + modes[0] = 'V'; + break; + + case LF_MULTIVOL: + modes[0] = 'M'; + break; + + case LF_NAMES: + modes[0] = 'N'; + break; + + case LF_LONGNAME: + case LF_LONGLINK: + msg ("Visible longname error\n"); + break; + + case LF_SPARSE: + case LF_NORMAL: + case LF_OLDNORMAL: + case LF_LINK: + modes[0] = '-'; + if ('/' == current_file_name[strlen (current_file_name) - 1]) + modes[0] = 'd'; + break; + case LF_DUMPDIR: + modes[0] = 'd'; + break; + case LF_DIR: + modes[0] = 'd'; + break; + case LF_SYMLINK: + modes[0] = 'l'; + break; + case LF_BLK: + modes[0] = 'b'; + break; + case LF_CHR: + modes[0] = 'c'; + break; + case LF_FIFO: + modes[0] = 'p'; + break; + case LF_CONTIG: + modes[0] = 'C'; + break; + } + + demode ((unsigned) hstat.st_mode, modes + 1); + + /* Timestamp */ + longie = hstat.st_mtime; + timestamp = ctime (&longie); + timestamp[16] = '\0'; + timestamp[24] = '\0'; + + /* User and group names */ + if (*head->header.uname && head_standard) + { + user = head->header.uname; + } + else + { + user = uform; + (void) sprintf (uform, "%d", + from_oct (8, head->header.uid)); + } + if (*head->header.gname && head_standard) + { + group = head->header.gname; + } + else + { + group = gform; + (void) sprintf (gform, "%d", + from_oct (8, head->header.gid)); + } + + /* Format the file size or major/minor device numbers */ + switch (head->header.linkflag) + { +#if defined(S_IFBLK) || defined(S_IFCHR) + case LF_CHR: + case LF_BLK: + (void) sprintf (size, "%d,%d", + major (hstat.st_rdev), + minor (hstat.st_rdev)); + break; +#endif + case LF_SPARSE: + (void) sprintf (size, "%ld", + from_oct (1 + 12, head->header.realsize)); + break; + default: + (void) sprintf (size, "%ld", (long) hstat.st_size); + } + + /* Figure out padding and print the whole line. */ + pad = strlen (user) + strlen (group) + strlen (size) + 1; + if (pad > ugswidth) + ugswidth = pad; + + name = quote_copy_string (current_file_name); + if (!name) + name = current_file_name; + fprintf (msg_file, "%s %s/%s %*s%s %s %s %s", + modes, + user, + group, + ugswidth - pad, + "", + size, + timestamp + 4, timestamp + 20, + name); + + if (name != current_file_name) + free (name); + switch (head->header.linkflag) + { + case LF_SYMLINK: + name = quote_copy_string (current_link_name); + if (!name) + name = current_link_name; + fprintf (msg_file, " -> %s\n", name); + if (name != current_link_name) + free (name); + break; + + case LF_LINK: + name = quote_copy_string (current_link_name); + if (!name) + name = current_link_name; + fprintf (msg_file, " link to %s\n", current_link_name); + if (name != current_link_name) + free (name); + break; + + default: + fprintf (msg_file, " unknown file type '%c'\n", + head->header.linkflag); + break; + + case LF_OLDNORMAL: + case LF_NORMAL: + case LF_SPARSE: + case LF_CHR: + case LF_BLK: + case LF_DIR: + case LF_FIFO: + case LF_CONTIG: + case LF_DUMPDIR: + putc ('\n', msg_file); + break; + + case LF_VOLHDR: + fprintf (msg_file, "--Volume Header--\n"); + break; + + case LF_MULTIVOL: + fprintf (msg_file, "--Continued at byte %ld--\n", from_oct (1 + 12, head->header.offset)); + break; + + case LF_NAMES: + fprintf (msg_file, "--Mangled file names--\n"); + break; + } + } + fflush (msg_file); +} + +/* + * Print a similar line when we make a directory automatically. + */ +void +pr_mkdir (pathname, length, mode) + char *pathname; + int length; + int mode; +{ + char modes[11]; + char *name; + extern long baserec; + + if (f_verbose > 1) + { + /* File type and modes */ + modes[0] = 'd'; + demode ((unsigned) mode, modes + 1); + + if (f_sayblock) + fprintf (msg_file, "rec %10d: ", baserec + (ar_record - ar_block)); + /* annofile(msg_file, (char *)NULL); */ + name = quote_copy_string (pathname); + if (!name) + name = pathname; + fprintf (msg_file, "%s %*s %.*s\n", + modes, + ugswidth + DATEWIDTH, + "Creating directory:", + length, + pathname); + if (name != pathname) + free (name); + } +} + + +/* + * Skip over bytes of data in records in the archive. + */ +void +skip_file (size) + register long size; +{ + union record *x; + extern long save_totsize; + extern long save_sizeleft; + + if (f_multivol) + { + save_totsize = size; + save_sizeleft = size; + } + + while (size > 0) + { + x = findrec (); + if (x == NULL) + { /* Check it... */ + msg ("Unexpected EOF on archive file"); + exit (EX_BADARCH); + } + userec (x); + size -= RECORDSIZE; + if (f_multivol) + save_sizeleft -= RECORDSIZE; + } +} + +void +skip_extended_headers () +{ + register union record *exhdr; + + for (;;) + { + exhdr = findrec (); + if (!exhdr->ext_hdr.isextended) + { + userec (exhdr); + break; + } + userec (exhdr); + } +} + +/* + * Decode the mode string from a stat entry into a 9-char string and a null. + */ +void +demode (mode, string) + register unsigned mode; + register char *string; +{ + register unsigned mask; + register char *rwx = "rwxrwxrwx"; + + for (mask = 0400; mask != 0; mask >>= 1) + { + if (mode & mask) + *string++ = *rwx++; + else + { + *string++ = '-'; + rwx++; + } + } + + if (mode & S_ISUID) + if (string[-7] == 'x') + string[-7] = 's'; + else + string[-7] = 'S'; + if (mode & S_ISGID) + if (string[-4] == 'x') + string[-4] = 's'; + else + string[-4] = 'S'; + if (mode & S_ISVTX) + if (string[-1] == 'x') + string[-1] = 't'; + else + string[-1] = 'T'; + *string = '\0'; +} diff --git a/gnu/usr.bin/tar/mangle.c b/gnu/usr.bin/tar/mangle.c new file mode 100644 index 0000000000..628168473a --- /dev/null +++ b/gnu/usr.bin/tar/mangle.c @@ -0,0 +1,270 @@ +/* mangle.c -- encode long filenames + Copyright (C) 1988, 1992 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +time_t time (); + +#include "tar.h" +#include "port.h" + +void add_buffer (); +extern PTR ck_malloc (); +void finish_header (); +extern PTR init_buffer (); +extern char *quote_copy_string (); +extern char *get_buffer (); +char *un_quote_string (); + +extern union record *start_header (); + +extern struct stat hstat; /* Stat struct corresponding */ + +struct mangled + { + struct mangled *next; + int type; + char mangled[NAMSIZ]; + char *linked_to; + char normal[1]; + }; + + +/* Should use a hash table, etc. . */ +struct mangled *first_mangle; +int mangled_num = 0; + +#if 0 /* Deleted because there is now a better way to do all this */ + +char * +find_mangled (name) + char *name; +{ + struct mangled *munge; + + for (munge = first_mangle; munge; munge = munge->next) + if (!strcmp (name, munge->normal)) + return munge->mangled; + return 0; +} + + +#ifdef S_ISLNK +void +add_symlink_mangle (symlink, linkto, buffer) + char *symlink; + char *linkto; + char *buffer; +{ + struct mangled *munge, *kludge; + + munge = (struct mangled *) ck_malloc (sizeof (struct mangled) + strlen (symlink) + strlen (linkto) + 2); + if (!first_mangle) + first_mangle = munge; + else + { + for (kludge = first_mangle; kludge->next; kludge = kludge->next) + ; + kludge->next = munge; + } + munge->type = 1; + munge->next = 0; + strcpy (munge->normal, symlink); + munge->linked_to = munge->normal + strlen (symlink) + 1; + strcpy (munge->linked_to, linkto); + sprintf (munge->mangled, "@@MaNgLeD.%d", mangled_num++); + strncpy (buffer, munge->mangled, NAMSIZ); +} + +#endif + +void +add_mangle (name, buffer) + char *name; + char *buffer; +{ + struct mangled *munge, *kludge; + + munge = (struct mangled *) ck_malloc (sizeof (struct mangled) + strlen (name)); + if (!first_mangle) + first_mangle = munge; + else + { + for (kludge = first_mangle; kludge->next; kludge = kludge->next) + ; + kludge->next = munge; + } + munge->next = 0; + munge->type = 0; + strcpy (munge->normal, name); + sprintf (munge->mangled, "@@MaNgLeD.%d", mangled_num++); + strncpy (buffer, munge->mangled, NAMSIZ); +} + +void +write_mangled () +{ + struct mangled *munge; + struct stat hstat; + union record *header; + char *ptr1, *ptr2; + PTR the_buffer; + int size; + int bufsize; + + if (!first_mangle) + return; + the_buffer = init_buffer (); + for (munge = first_mangle, size = 0; munge; munge = munge->next) + { + ptr1 = quote_copy_string (munge->normal); + if (!ptr1) + ptr1 = munge->normal; + if (munge->type) + { + add_buffer (the_buffer, "Symlink ", 8); + add_buffer (the_buffer, ptr1, strlen (ptr1)); + add_buffer (the_buffer, " to ", 4); + + if (ptr2 = quote_copy_string (munge->linked_to)) + { + add_buffer (the_buffer, ptr2, strlen (ptr2)); + free (ptr2); + } + else + add_buffer (the_buffer, munge->linked_to, strlen (munge->linked_to)); + } + else + { + add_buffer (the_buffer, "Rename ", 7); + add_buffer (the_buffer, munge->mangled, strlen (munge->mangled)); + add_buffer (the_buffer, " to ", 4); + add_buffer (the_buffer, ptr1, strlen (ptr1)); + } + add_buffer (the_buffer, "\n", 1); + if (ptr1 != munge->normal) + free (ptr1); + } + + bzero (&hstat, sizeof (struct stat)); + hstat.st_atime = hstat.st_mtime = hstat.st_ctime = time (0); + ptr1 = get_buffer (the_buffer); + hstat.st_size = strlen (ptr1); + + header = start_header ("././@MaNgLeD_NaMeS", &hstat); + header->header.linkflag = LF_NAMES; + finish_header (header); + size = hstat.st_size; + header = findrec (); + bufsize = endofrecs ()->charptr - header->charptr; + + while (bufsize < size) + { + bcopy (ptr1, header->charptr, bufsize); + ptr1 += bufsize; + size -= bufsize; + userec (header + (bufsize - 1) / RECORDSIZE); + header = findrec (); + bufsize = endofrecs ()->charptr - header->charptr; + } + bcopy (ptr1, header->charptr, size); + bzero (header->charptr + size, bufsize - size); + userec (header + (size - 1) / RECORDSIZE); +} + +#endif + +void +extract_mangle (head) + union record *head; +{ + char *buf; + char *fromtape; + char *to; + char *ptr, *ptrend; + char *nam1, *nam1end; + int size; + int copied; + + size = hstat.st_size; + buf = to = ck_malloc (size + 1); + buf[size] = '\0'; + while (size > 0) + { + fromtape = findrec ()->charptr; + if (fromtape == 0) + { + msg ("Unexpected EOF in mangled names!"); + return; + } + copied = endofrecs ()->charptr - fromtape; + if (copied > size) + copied = size; + bcopy (fromtape, to, copied); + to += copied; + size -= copied; + userec ((union record *) (fromtape + copied - 1)); + } + for (ptr = buf; *ptr; ptr = ptrend) + { + ptrend = index (ptr, '\n'); + *ptrend++ = '\0'; + + if (!strncmp (ptr, "Rename ", 7)) + { + nam1 = ptr + 7; + nam1end = index (nam1, ' '); + while (strncmp (nam1end, " to ", 4)) + { + nam1end++; + nam1end = index (nam1end, ' '); + } + *nam1end = '\0'; + if (ptrend[-2] == '/') + ptrend[-2] = '\0'; + un_quote_string (nam1end + 4); + if (rename (nam1, nam1end + 4)) + msg_perror ("Can't rename %s to %s", nam1, nam1end + 4); + else if (f_verbose) + msg ("Renamed %s to %s", nam1, nam1end + 4); + } +#ifdef S_ISLNK + else if (!strncmp (ptr, "Symlink ", 8)) + { + nam1 = ptr + 8; + nam1end = index (nam1, ' '); + while (strncmp (nam1end, " to ", 4)) + { + nam1end++; + nam1end = index (nam1end, ' '); + } + *nam1end = '\0'; + un_quote_string (nam1); + un_quote_string (nam1end + 4); + if (symlink (nam1, nam1end + 4) && (unlink (nam1end + 4) || symlink (nam1, nam1end + 4))) + msg_perror ("Can't symlink %s to %s", nam1, nam1end + 4); + else if (f_verbose) + msg ("Symlinkd %s to %s", nam1, nam1end + 4); + } +#endif + else + msg ("Unknown demangling command %s", ptr); + } +} diff --git a/gnu/usr.bin/tar/msd_dir.h b/gnu/usr.bin/tar/msd_dir.h new file mode 100644 index 0000000000..06c7a644b4 --- /dev/null +++ b/gnu/usr.bin/tar/msd_dir.h @@ -0,0 +1,44 @@ +/* + * @(#)msd_dir.h 1.4 87/11/06 Public Domain. + * + * A public domain implementation of BSD directory routines for + * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield), + * August 1897 + */ + +#define rewinddir(dirp) seekdir(dirp, 0L) + +#define MAXNAMLEN 12 + +#ifdef __TURBOC__ +typedef int ino_t; +typedef int dev_t; +#endif + +struct dirent + { + ino_t d_ino; /* a bit of a farce */ + int d_reclen; /* more farce */ + int d_namlen; /* length of d_name */ + char d_name[MAXNAMLEN + 1]; /* garentee null termination */ + }; + +struct _dircontents + { + char *_d_entry; + struct _dircontents *_d_next; + }; + +typedef struct _dirdesc + { + int dd_id; /* uniquely identify each open directory */ + long dd_loc; /* where we are in directory entry is this */ + struct _dircontents *dd_contents; /* pointer to contents of dir */ + struct _dircontents *dd_cp; /* pointer to current position */ + } DIR; + +extern DIR *opendir (); +extern struct dirent *readdir (); +extern void seekdir (); +extern long telldir (); +extern void closedir (); diff --git a/gnu/usr.bin/tar/names.c b/gnu/usr.bin/tar/names.c new file mode 100644 index 0000000000..0de6a8898a --- /dev/null +++ b/gnu/usr.bin/tar/names.c @@ -0,0 +1,149 @@ +/* Look up user and/or group names. + Copyright (C) 1988, 1992 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Look up user and/or group names. + * + * This file should be modified for non-unix systems to do something + * reasonable. + */ + +#include +#include "tar.h" +#include "port.h" + +#ifndef NONAMES +/* Whole module goes away if NONAMES defined. Otherwise... */ +#include +#include +#include + +static int saveuid = -993; +static char saveuname[TUNMLEN]; +static int my_uid = -993; + +static int savegid = -993; +static char savegname[TGNMLEN]; +static int my_gid = -993; + +#define myuid ( my_uid < 0? (my_uid = getuid()): my_uid ) +#define mygid ( my_gid < 0? (my_gid = getgid()): my_gid ) + +/* + * Look up a user or group name from a uid/gid, maintaining a cache. + * FIXME, for now it's a one-entry cache. + * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup. + * + * This is ifdef'd because on Suns, it drags in about 38K of "yellow + * pages" code, roughly doubling the program size. Thanks guys. + */ +void +finduname (uname, uid) + char uname[TUNMLEN]; + int uid; +{ + struct passwd *pw; +#ifndef HAVE_GETPWUID + extern struct passwd *getpwuid (); +#endif + + if (uid != saveuid) + { + saveuid = uid; + saveuname[0] = '\0'; + pw = getpwuid (uid); + if (pw) + strncpy (saveuname, pw->pw_name, TUNMLEN); + } + strncpy (uname, saveuname, TUNMLEN); +} + +int +finduid (uname) + char uname[TUNMLEN]; +{ + struct passwd *pw; + extern struct passwd *getpwnam (); + + if (uname[0] != saveuname[0] /* Quick test w/o proc call */ + || 0 != strncmp (uname, saveuname, TUNMLEN)) + { + strncpy (saveuname, uname, TUNMLEN); + pw = getpwnam (uname); + if (pw) + { + saveuid = pw->pw_uid; + } + else + { + saveuid = myuid; + } + } + return saveuid; +} + + +void +findgname (gname, gid) + char gname[TGNMLEN]; + int gid; +{ + struct group *gr; +#ifndef HAVE_GETGRGID + extern struct group *getgrgid (); +#endif + + if (gid != savegid) + { + savegid = gid; + savegname[0] = '\0'; + (void) setgrent (); + gr = getgrgid (gid); + if (gr) + strncpy (savegname, gr->gr_name, TGNMLEN); + } + (void) strncpy (gname, savegname, TGNMLEN); +} + + +int +findgid (gname) + char gname[TUNMLEN]; +{ + struct group *gr; + extern struct group *getgrnam (); + + if (gname[0] != savegname[0] /* Quick test w/o proc call */ + || 0 != strncmp (gname, savegname, TUNMLEN)) + { + strncpy (savegname, gname, TUNMLEN); + gr = getgrnam (gname); + if (gr) + { + savegid = gr->gr_gid; + } + else + { + savegid = mygid; + } + } + return savegid; +} + +#endif diff --git a/gnu/usr.bin/tar/open3.h b/gnu/usr.bin/tar/open3.h new file mode 100644 index 0000000000..c1c0e59b67 --- /dev/null +++ b/gnu/usr.bin/tar/open3.h @@ -0,0 +1,67 @@ +/* Defines for Sys V style 3-argument open call. + Copyright (C) 1988 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * open3.h -- #defines for the various flags for the Sys V style 3-argument + * open() call. On BSD or System 5, the system already has this in an + * include file. This file is needed for V7 and MINIX systems for the + * benefit of open3() in port.c, a routine that emulates the 3-argument + * call using system calls available on V7/MINIX. + * + * This file is needed by PD tar even if we aren't using the + * emulator, since the #defines for O_WRONLY, etc. are used in + * a couple of places besides the open() calls, (e.g. in the assignment + * to openflag in extract.c). We just #include this rather than + * #ifdef them out. + * + * Written 6/10/87 by rmtodd@uokmax (Richard Todd). + * + * The names have been changed by John Gilmore, 31 July 1987, since + * Richard called it "bsdopen", and really this change was introduced in + * AT&T Unix systems before BSD picked it up. + */ + +/* Only one of the next three should be specified */ +#define O_RDONLY 0 /* only allow read */ +#define O_WRONLY 1 /* only allow write */ +#define O_RDWR 2 /* both are allowed */ + +/* The rest of these can be OR-ed in to the above. */ +/* + * O_NDELAY isn't implemented by the emulator. It's only useful (to tar) on + * systems that have named pipes anyway; it prevents tar's hanging by + * opening a named pipe. We #ifndef it because some systems already have + * it defined. + */ +#ifndef O_NDELAY +#define O_NDELAY 4 /* don't block on opening devices that would + * block on open -- ignored by emulator. */ +#endif +#define O_CREAT 8 /* create file if needed */ +#define O_EXCL 16 /* file cannot already exist */ +#define O_TRUNC 32 /* truncate file on open */ +#define O_APPEND 64 /* always write at end of file -- ignored by emul */ + +#ifdef EMUL_OPEN3 +/* + * make emulation transparent to rest of file -- redirect all open() calls + * to our routine + */ +#define open open3 +#endif diff --git a/gnu/usr.bin/tar/pathmax.h b/gnu/usr.bin/tar/pathmax.h new file mode 100644 index 0000000000..aeba9f7d21 --- /dev/null +++ b/gnu/usr.bin/tar/pathmax.h @@ -0,0 +1,53 @@ +/* Define PATH_MAX somehow. 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. */ + +#ifndef _PATHMAX_H +#define _PATHMAX_H + +#ifdef HAVE_UNISTD_H +#include +#endif + +/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define + PATH_MAX but might cause redefinition warnings when sys/param.h is + later included (as on MORE/BSD 4.3). */ +#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && defined(USG)) +#include +#endif + +#ifndef _POSIX_PATH_MAX +#define _POSIX_PATH_MAX 255 +#endif + +#if !defined(PATH_MAX) && defined(_PC_PATH_MAX) +#define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX)) +#endif + +/* Don't include sys/param.h if it already has been. */ +#if !defined(PATH_MAX) && !defined(MAXPATHLEN) && !defined(__MSDOS__) +#include +#endif + +#if !defined(PATH_MAX) && defined(MAXPATHLEN) +#define PATH_MAX MAXPATHLEN +#endif + +#ifndef PATH_MAX +#define PATH_MAX _POSIX_PATH_MAX +#endif + +#endif /* _PATHMAX_H */ diff --git a/gnu/usr.bin/tar/port.c b/gnu/usr.bin/tar/port.c new file mode 100644 index 0000000000..10ec32ed72 --- /dev/null +++ b/gnu/usr.bin/tar/port.c @@ -0,0 +1,1256 @@ +/* Supporting routines which may sometimes be missing. + Copyright (C) 1988, 1992 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#ifndef STDC_HEADERS +extern int errno; +#endif + +#ifdef BSD42 +#include +#else +#ifndef V7 +#include +#endif +#endif + +#include "tar.h" +#include "port.h" + +extern long baserec; + +/* All machine-dependent #ifdefs should appear here, instead of + being scattered through the file. For UN*X systems, it is better to + figure out what is needed in the configure script, for most of the + features. */ + +#ifdef __MSDOS__ +char TTY_NAME[] = "con"; +#define HAVE_STRSTR +#define HAVE_RENAME +#define HAVE_MKDIR +#else +char TTY_NAME[] = "/dev/tty"; +#endif + +/* End of system-dependent #ifdefs */ + + +#ifndef HAVE_VALLOC +/* + * valloc() does a malloc() on a page boundary. On some systems, + * this can make large block I/O more efficient. + */ +char * +valloc (size) + unsigned size; +{ + return (malloc (size)); +} + +#endif /* !HAVE_VALLOC */ + +#ifndef HAVE_MKDIR +/* + * Written by Robert Rother, Mariah Corporation, August 1985. + * + * If you want it, it's yours. All I ask in return is that if you + * figure out how to do this in a Bourne Shell script you send me + * a copy. + * sdcsvax!rmr or rmr@uscd + * + * 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. + */ + +/* + * Make a directory. + */ +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; + + switch (cpid = fork ()) + { + + case -1: /* Error in fork() */ + return (-1); /* Errno is set already */ + + case 0: /* Child process */ + /* + * Cheap hack to set mode of new directory. Since this + * child process is going away anyway, we zap its umask. + * FIXME, this won't suffice to set SUID, SGID, etc. on this + * directory. Does anybody care? + */ + status = umask (0); /* Get current umask */ + status = umask (status | (0777 & ~dmode)); /* Set for mkdir */ + execl ("/bin/mkdir", "mkdir", dpath, (char *) 0); + _exit (-1); /* Can't exec /bin/mkdir */ + + default: /* Parent process */ + while (cpid != wait (&status)); /* Wait for kid to finish */ + } + + if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0) + { + errno = EIO; /* We don't know why, but */ + return -1; /* /bin/mkdir failed */ + } + + return 0; +} + +int +rmdir (dpath) + char *dpath; +{ + int cpid, status; + struct stat statbuf; + + if (stat (dpath, &statbuf) != 0) + { + /* Stat just set errno. We don't have to */ + return -1; + } + + switch (cpid = fork ()) + { + + case -1: /* Error in fork() */ + return (-1); /* Errno is set already */ + + case 0: /* Child process */ + execl ("/bin/rmdir", "rmdir", dpath, (char *) 0); + _exit (-1); /* Can't exec /bin/mkdir */ + + default: /* Parent process */ + while (cpid != wait (&status)); /* Wait for kid to finish */ + } + + if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0) + { + errno = EIO; /* We don't know why, but */ + return -1; /* /bin/mkdir failed */ + } + + return 0; +} + +#endif /* !HAVE_MKDIR */ + +#ifndef HAVE_RENAME +/* 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; + + if (stat (from, &from_stats)) + return -1; + + if (unlink (to) && errno != ENOENT) + return -1; + + if (link (from, to)) + return -1; + + if (unlink (from) && errno != ENOENT) + { + unlink (to); + return -1; + } + + return 0; +} + +#endif /* !HAVE_RENAME */ + +#ifdef minix +/* Minix has bcopy but not bzero, and no memset. Thanks, Andy. */ +void +bzero (s1, n) + register char *s1; + register int n; +{ + while (n--) + *s1++ = '\0'; +} + +/* It also has no bcmp() */ +int +bcmp (s1, s2, n) + register char *s1, *s2; + register int n; +{ + for (; n--; ++s1, ++s2) + { + if (*s1 != *s2) + return *s1 - *s2; + } + return 0; +} + +/* + * Groan, Minix doesn't have execlp either! + * + * execlp(file,arg0,arg1...argn,(char *)NULL) + * exec a program, automatically searching for the program through + * all the directories on the PATH. + * + * This version is naive about variable argument lists, it assumes + * a straightforward C calling sequence. If your system has odd stacks + * *and* doesn't have execlp, YOU get to fix it. + */ +int +execlp (filename, arg0) + char *filename, *arg0; +{ + register char *p, *path; + register char *fnbuffer; + char **argstart = &arg0; + struct stat statbuf; + extern char **environ; + + if ((p = getenv ("PATH")) == NULL) + { + /* couldn't find path variable -- try to exec given filename */ + return execve (filename, argstart, environ); + } + + /* + * make a place to build the filename. We malloc larger than we + * need, but we know it will fit in this. + */ + fnbuffer = malloc (strlen (p) + 1 + strlen (filename)); + if (fnbuffer == NULL) + { + errno = ENOMEM; + return -1; + } + + /* + * try each component of the path to see if the file's there + * and executable. + */ + for (path = p; path; path = p) + { + /* construct full path name to try */ + if ((p = index (path, ':')) == NULL) + { + strcpy (fnbuffer, path); + } + else + { + strncpy (fnbuffer, path, p - path); + fnbuffer[p - path] = '\0'; + p++; /* Skip : for next time */ + } + if (strlen (fnbuffer) != 0) + strcat (fnbuffer, "/"); + strcat (fnbuffer, filename); + + /* check to see if file is there and is a normal file */ + if (stat (fnbuffer, &statbuf) < 0) + { + if (errno == ENOENT) + continue; /* file not there,keep on looking */ + else + goto fail; /* failed for some reason, return */ + } + if (!S_ISREG (statbuf.st_mode)) + continue; + + if (execve (fnbuffer, argstart, environ) < 0 + && errno != ENOENT + && errno != ENOEXEC) + { + /* failed, for some other reason besides "file + * not found" or "not a.out format" + */ + goto fail; + } + + /* + * If we got error ENOEXEC, the file is executable but is + * not an object file. Try to execute it as a shell script, + * returning error if we can't execute /bin/sh. + * + * FIXME, this code is broken in several ways. Shell + * scripts should not in general be executed by the user's + * SHELL variable program. On more mature systems, the + * script can specify with #!/bin/whatever. Also, this + * code clobbers argstart[-1] if the exec of the shell + * fails. + */ + if (errno == ENOEXEC) + { + char *shell; + + /* Try to execute command "sh arg0 arg1 ..." */ + if ((shell = getenv ("SHELL")) == NULL) + shell = "/bin/sh"; + argstart[-1] = shell; + argstart[0] = fnbuffer; + execve (shell, &argstart[-1], environ); + goto fail; /* Exec didn't work */ + } + + /* + * If we succeeded, the execve() doesn't return, so we + * can only be here is if the file hasn't been found yet. + * Try the next place on the path. + */ + } + + /* all attempts failed to locate the file. Give up. */ + errno = ENOENT; + +fail: + free (fnbuffer); + return -1; +} + +#endif /* minix */ + + +#ifdef EMUL_OPEN3 +#include "open3.h" +/* + * open3 -- routine to emulate the 3-argument open system + * call that is present in most modern Unix systems. + * This version attempts to support all the flag bits except for O_NDELAY + * and O_APPEND, which are silently ignored. The emulation is not as efficient + * as the real thing (at worst, 4 system calls instead of one), but there's + * not much I can do about that. + * + * Written 6/10/87 by rmtodd@uokmax + * + * open3(path, flag, mode) + * Attempts to open the file specified by + * the given pathname. The following flag bits (#defined in tar.h) + * specify options to the routine: + * O_RDONLY file open for read only + * O_WRONLY file open for write only + * O_RDWR file open for both read & write + * (Needless to say, you should only specify one of the above). + * O_CREAT file is created with specified mode if it needs to be. + * O_TRUNC if file exists, it is truncated to 0 bytes + * O_EXCL used with O_CREAT--routine returns error if file exists + * Function returns file descriptor if successful, -1 and errno if not. + */ + +/* + * array to give arguments to access for various modes + * FIXME, this table depends on the specific integer values of O_XXX, + * and also contains integers (args to 'access') that should be #define's. + */ +static int modes[] = +{ + 04, /* O_RDONLY */ + 02, /* O_WRONLY */ + 06, /* O_RDWR */ + 06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */ +}; + +/* Shut off the automatic emulation of open(), we'll need it. */ +#undef open + +int +open3 (path, flags, mode) + char *path; + int flags, mode; +{ + int exists = 1; + int call_creat = 0; + int fd; + /* + * We actually do the work by calling the open() or creat() system + * call, depending on the flags. Call_creat is true if we will use + * creat(), false if we will use open(). + */ + + /* + * See if the file exists and is accessible in the requested mode. + * + * Strictly speaking we shouldn't be using access, since access checks + * against real uid, and the open call should check against euid. + * Most cases real uid == euid, so it won't matter. FIXME. + * FIXME, the construction "flags & 3" and the modes table depends + * on the specific integer values of the O_XXX #define's. Foo! + */ + if (access (path, modes[flags & 3]) < 0) + { + if (errno == ENOENT) + { + /* the file does not exist */ + exists = 0; + } + else + { + /* probably permission violation */ + if (flags & O_EXCL) + { + /* Oops, the file exists, we didn't want it. */ + /* No matter what the error, claim EEXIST. */ + errno = EEXIST; + } + return -1; + } + } + + /* if we have the O_CREAT bit set, check for O_EXCL */ + if (flags & O_CREAT) + { + if ((flags & O_EXCL) && exists) + { + /* Oops, the file exists and we didn't want it to. */ + errno = EEXIST; + return -1; + } + /* + * If the file doesn't exist, be sure to call creat() so that + * it will be created with the proper mode. + */ + if (!exists) + call_creat = 1; + } + else + { + /* If O_CREAT isn't set and the file doesn't exist, error. */ + if (!exists) + { + errno = ENOENT; + return -1; + } + } + + /* + * If the O_TRUNC flag is set and the file exists, we want to call + * creat() anyway, since creat() guarantees that the file will be + * truncated and open()-for-writing doesn't. + * (If the file doesn't exist, we're calling creat() anyway and the + * file will be created with zero length.) + */ + if ((flags & O_TRUNC) && exists) + call_creat = 1; + /* actually do the call */ + if (call_creat) + { + /* + * call creat. May have to close and reopen the file if we + * want O_RDONLY or O_RDWR access -- creat() only gives + * O_WRONLY. + */ + fd = creat (path, mode); + if (fd < 0 || (flags & O_WRONLY)) + return fd; + if (close (fd) < 0) + return -1; + /* Fall out to reopen the file we've created */ + } + + /* + * calling old open, we strip most of the new flags just in case. + */ + return open (path, flags & (O_RDONLY | O_WRONLY | O_RDWR | O_BINARY)); +} + +#endif /* EMUL_OPEN3 */ + +#ifndef HAVE_MKNOD +#ifdef __MSDOS__ +typedef int dev_t; +#endif +/* Fake mknod by complaining */ +int +mknod (path, mode, dev) + char *path; + unsigned short mode; + dev_t dev; +{ + int fd; + + errno = ENXIO; /* No such device or address */ + return -1; /* Just give an error */ +} + +/* Fake links by copying */ +int +link (path1, path2) + char *path1; + char *path2; +{ + char buf[256]; + int ifd, ofd; + int nrbytes; + int nwbytes; + + fprintf (stderr, "%s: %s: cannot link to %s, copying instead\n", + tar, path1, path2); + if ((ifd = open (path1, O_RDONLY | O_BINARY)) < 0) + return -1; + if ((ofd = creat (path2, 0666)) < 0) + return -1; + setmode (ofd, O_BINARY); + while ((nrbytes = read (ifd, buf, sizeof (buf))) > 0) + { + if ((nwbytes = write (ofd, buf, nrbytes)) != nrbytes) + { + nrbytes = -1; + break; + } + } + /* Note use of "|" rather than "||" below: we want to close + * the files even if an error occurs. + */ + if ((nrbytes < 0) | (0 != close (ifd)) | (0 != close (ofd))) + { + unlink (path2); + return -1; + } + return 0; +} + +/* everyone owns everything on MS-DOS (or is it no one owns anything?) */ +int +chown (path, uid, gid) + char *path; + int uid; + int gid; +{ + return 0; +} + +int +geteuid () +{ + return 0; +} + +#endif /* !HAVE_MKNOD */ + +#ifdef __TURBOC__ +#include +#include +#include + +struct utimbuf +{ + time_t actime; /* Access time. */ + time_t modtime; /* Modification time. */ +}; + +int +utime (char *filename, struct utimbuf *utb) +{ + 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 /* __TURBOC__ */ + +/* Stash argv[0] here so panic will know what the program is called */ +char *myname = 0; + +void +panic (s) + char *s; +{ + if (myname) + fprintf (stderr, "%s:", myname); + fprintf (stderr, s); + putc ('\n', stderr); + exit (12); +} + + +PTR +ck_malloc (size) + size_t size; +{ + PTR ret; + + if (!size) + size++; + ret = malloc (size); + if (ret == 0) + panic ("Couldn't allocate memory"); + return ret; +} + +/* Used by alloca.c and bison.simple. */ +char * +xmalloc (size) + size_t size; +{ + return (char *) ck_malloc (size); +} + +PTR +ck_realloc (ptr, size) + PTR ptr; + size_t size; +{ + PTR ret; + + if (!ptr) + ret = ck_malloc (size); + else + ret = realloc (ptr, size); + if (ret == 0) + panic ("Couldn't re-allocate memory"); + return ret; +} + +/* Implement a variable sized buffer of 'stuff'. We don't know what it is, + nor do we care, as long as it doesn't mind being aligned on a char boundry. + */ + +struct buffer + { + int allocated; + int length; + char *b; + }; + +#define MIN_ALLOCATE 50 + +char * +init_buffer () +{ + struct buffer *b; + + b = (struct buffer *) ck_malloc (sizeof (struct buffer)); + b->allocated = MIN_ALLOCATE; + b->b = (char *) ck_malloc (MIN_ALLOCATE); + b->length = 0; + return (char *) b; +} + +void +flush_buffer (bb) + char *bb; +{ + struct buffer *b; + + b = (struct buffer *) bb; + free (b->b); + b->b = 0; + b->allocated = 0; + b->length = 0; + free ((void *) b); +} + +void +add_buffer (bb, p, n) + char *bb; + char *p; + int n; +{ + struct buffer *b; + + b = (struct buffer *) bb; + if (b->length + n > b->allocated) + { + b->allocated = b->length + n + MIN_ALLOCATE; + b->b = (char *) ck_realloc (b->b, b->allocated); + } + bcopy (p, b->b + b->length, n); + b->length += n; +} + +char * +get_buffer (bb) + char *bb; +{ + struct buffer *b; + + b = (struct buffer *) bb; + return b->b; +} + +char * +merge_sort (list, n, off, cmp) + char *list; + int (*cmp) (); + unsigned n; + int off; +{ + char *ret; + + char *alist, *blist; + unsigned alength, blength; + + char *tptr; + int tmp; + char **prev; +#define NEXTOF(ptr) (* ((char **)(((char *)(ptr))+off) ) ) + if (n == 1) + return list; + if (n == 2) + { + if ((*cmp) (list, NEXTOF (list)) > 0) + { + ret = NEXTOF (list); + NEXTOF (ret) = list; + NEXTOF (list) = 0; + return ret; + } + return list; + } + alist = list; + alength = (n + 1) / 2; + blength = n / 2; + for (tptr = list, tmp = (n - 1) / 2; tmp; tptr = NEXTOF (tptr), tmp--) + ; + blist = NEXTOF (tptr); + NEXTOF (tptr) = 0; + + alist = merge_sort (alist, alength, off, cmp); + blist = merge_sort (blist, blength, off, cmp); + prev = &ret; + for (; alist && blist;) + { + if ((*cmp) (alist, blist) < 0) + { + tptr = NEXTOF (alist); + *prev = alist; + prev = &(NEXTOF (alist)); + alist = tptr; + } + else + { + tptr = NEXTOF (blist); + *prev = blist; + prev = &(NEXTOF (blist)); + blist = tptr; + } + } + if (alist) + *prev = alist; + else + *prev = blist; + + return ret; +} + +void +ck_close (fd) + int fd; +{ + if (close (fd) < 0) + { + msg_perror ("can't close a file #%d", fd); + exit (EX_SYSTEM); + } +} + +#include + +/* Quote_copy_string is like quote_string, but instead of modifying the + string in place, it malloc-s a copy of the string, and returns that. + If the string does not have to be quoted, it returns the NULL string. + The allocated copy can, of course, be freed with free() after the + caller is done with it. + */ +char * +quote_copy_string (string) + char *string; +{ + char *from_here; + char *to_there = 0; + char *copy_buf = 0; + int c; + int copying = 0; + + from_here = string; + while (*from_here) + { + c = *from_here++; + if (c == '\\') + { + if (!copying) + { + int n; + + n = (from_here - string) - 1; + copying++; + copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4); + if (!copy_buf) + return 0; + bcopy (string, copy_buf, n); + to_there = copy_buf + n; + } + *to_there++ = '\\'; + *to_there++ = '\\'; + } + else if (isprint (c)) + { + if (copying) + *to_there++ = c; + } + else + { + if (!copying) + { + int n; + + n = (from_here - string) - 1; + copying++; + copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4); + if (!copy_buf) + return 0; + bcopy (string, copy_buf, n); + to_there = copy_buf + n; + } + *to_there++ = '\\'; + if (c == '\n') + *to_there++ = 'n'; + else if (c == '\t') + *to_there++ = 't'; + else if (c == '\f') + *to_there++ = 'f'; + else if (c == '\b') + *to_there++ = 'b'; + else if (c == '\r') + *to_there++ = 'r'; + else if (c == '\177') + *to_there++ = '?'; + else + { + to_there[0] = (c >> 6) + '0'; + to_there[1] = ((c >> 3) & 07) + '0'; + to_there[2] = (c & 07) + '0'; + to_there += 3; + } + } + } + if (copying) + { + *to_there = '\0'; + return copy_buf; + } + return (char *) 0; +} + + +/* Un_quote_string takes a quoted c-string (like those produced by + quote_string or quote_copy_string and turns it back into the + un-quoted original. This is done in place. + */ + +/* There is no un-quote-copy-string. Write it yourself */ + +char * +un_quote_string (string) + char *string; +{ + char *ret; + char *from_here; + char *to_there; + int tmp; + + ret = string; + to_there = string; + from_here = string; + while (*from_here) + { + if (*from_here != '\\') + { + if (from_here != to_there) + *to_there++ = *from_here++; + else + from_here++, to_there++; + continue; + } + switch (*++from_here) + { + case '\\': + *to_there++ = *from_here++; + break; + case 'n': + *to_there++ = '\n'; + from_here++; + break; + case 't': + *to_there++ = '\t'; + from_here++; + break; + case 'f': + *to_there++ = '\f'; + from_here++; + break; + case 'b': + *to_there++ = '\b'; + from_here++; + break; + case 'r': + *to_there++ = '\r'; + from_here++; + break; + case '?': + *to_there++ = 0177; + from_here++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + tmp = *from_here - '0'; + from_here++; + if (*from_here < '0' || *from_here > '7') + { + *to_there++ = tmp; + break; + } + tmp = tmp * 8 + *from_here - '0'; + from_here++; + if (*from_here < '0' || *from_here > '7') + { + *to_there++ = tmp; + break; + } + tmp = tmp * 8 + *from_here - '0'; + from_here++; + *to_there = tmp; + break; + default: + ret = 0; + *to_there++ = '\\'; + *to_there++ = *from_here++; + break; + } + } + if (*to_there) + *to_there++ = '\0'; + return ret; +} + +#ifndef __MSDOS__ +void +ck_pipe (pipes) + int *pipes; +{ + if (pipe (pipes) < 0) + { + msg_perror ("can't open a pipe"); + exit (EX_SYSTEM); + } +} +#endif /* !__MSDOS__ */ + +#ifndef HAVE_STRSTR +/* + * strstr - find first occurrence of wanted in s + */ + +char * /* found string, or NULL if none */ +strstr (s, wanted) + char *s; + char *wanted; +{ + register char *scan; + register size_t len; + register char firstc; + + if (*wanted == '\0') + return (char *) 0; + /* + * The odd placement of the two tests is so "" is findable. + * Also, we inline the first char for speed. + * The ++ on scan has been moved down for optimization. + */ + firstc = *wanted; + len = strlen (wanted); + for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;) + if (*scan++ == '\0') + return (char *) 0; + return scan; +} + +#endif /* !HAVE_STRSTR */ + +#ifndef HAVE_FTRUNCATE + +#ifdef F_CHSIZE +int +ftruncate (fd, length) + int fd; + off_t length; +{ + return fcntl (fd, F_CHSIZE, length); +} + +#else /* !F_CHSIZE */ +#ifdef F_FREESP +/* code courtesy of William Kucharski, kucharsk@Solbourne.com */ + +int +ftruncate (fd, length) + int fd; /* file descriptor */ + off_t length; /* length to set file to */ +{ + struct flock fl; + + fl.l_whence = 0; + fl.l_len = 0; + fl.l_start = length; + fl.l_type = F_WRLCK; /* write lock on file space */ + + /* + * This relies on the UNDOCUMENTED F_FREESP argument to + * fcntl(2), which truncates the file so that it ends at the + * position indicated by fl.l_start. + * + * Will minor miracles never cease? + */ + + if (fcntl (fd, F_FREESP, &fl) < 0) + return -1; + + return 0; +} + +#else /* !F_FREESP */ + +int +ftruncate (fd, length) + int fd; + off_t length; +{ + errno = EIO; + return -1; +} + +#endif /* !F_FREESP */ +#endif /* !F_CHSIZE */ +#endif /* !HAVE_FTRUNCATE */ + + +extern FILE *msg_file; + +#if defined (HAVE_VPRINTF) && __STDC__ +#include + +void +msg (char *str,...) +{ + va_list args; + + va_start (args, str); + fflush (msg_file); + fprintf (stderr, "%s: ", tar); + if (f_sayblock) + fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); + vfprintf (stderr, str, args); + va_end (args); + putc ('\n', stderr); + fflush (stderr); +} + +void +msg_perror (char *str,...) +{ + va_list args; + int save_e; + + save_e = errno; + fflush (msg_file); + fprintf (stderr, "%s: ", tar); + if (f_sayblock) + fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); + va_start (args, str); + vfprintf (stderr, str, args); + va_end (args); + errno = save_e; + perror (" "); + fflush (stderr); +} + +#endif /* HAVE_VPRINTF and __STDC__ */ + +#if defined(HAVE_VPRINTF) && !__STDC__ +#include +void +msg (str, va_alist) + char *str; + va_dcl +{ + va_list args; + + fflush (msg_file); + fprintf (stderr, "%s: ", tar); + if (f_sayblock) + fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); + va_start (args); + vfprintf (stderr, str, args); + va_end (args); + putc ('\n', stderr); + fflush (stderr); +} + +void +msg_perror (str, va_alist) + char *str; + va_dcl +{ + va_list args; + int save_e; + + save_e = errno; + fflush (msg_file); + fprintf (stderr, "%s: ", tar); + if (f_sayblock) + fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); + va_start (args); + vfprintf (stderr, str, args); + va_end (args); + errno = save_e; + perror (" "); + fflush (stderr); +} + +#endif /* HAVE_VPRINTF and not __STDC__ */ + +#if !defined(HAVE_VPRINTF) && defined(HAVE_DOPRNT) +void +msg (str, args) + char *str; + int args; +{ + fflush (msg_file); + fprintf (stderr, "%s: ", tar); + if (f_sayblock) + fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); + _doprnt (str, &args, stderr); + putc ('\n', stderr); + fflush (stderr); +} + +void +msg_perror (str, args) + char *str; + int args; +{ + int save_e; + + save_e = errno; + fflush (msg_file); + fprintf (stderr, "%s: ", tar); + if (f_sayblock) + fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); + _doprnt (str, &args, stderr); + errno = save_e; + perror (" "); + fflush (stderr); +} + +#endif /* !HAVE_VPRINTF and HAVE_DOPRNT */ + +#if !defined(HAVE_VPRINTF) && !defined(HAVE_DOPRNT) +void +msg (str, a1, a2, a3, a4, a5, a6) + char *str; +{ + fflush (msg_file); + fprintf (stderr, "%s: ", tar); + if (f_sayblock) + fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); + fprintf (stderr, str, a1, a2, a3, a4, a5, a6); + putc ('\n', stderr); + fflush (stderr); +} + +void +msg_perror (str, a1, a2, a3, a4, a5, a6) + char *str; +{ + int save_e; + + save_e = errno; + fflush (msg_file); + fprintf (stderr, "%s: ", tar); + if (f_sayblock) + fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); + fprintf (stderr, str, a1, a2, a3, a4, a5, a6); + fprintf (stderr, ": "); + errno = save_e; + perror (" "); +} + +#endif /* !HAVE_VPRINTF and !HAVE_DOPRNT */ diff --git a/gnu/usr.bin/tar/port.h b/gnu/usr.bin/tar/port.h new file mode 100644 index 0000000000..4e65a9ace8 --- /dev/null +++ b/gnu/usr.bin/tar/port.h @@ -0,0 +1,215 @@ +/* Portability declarations. Requires sys/types.h. + Copyright (C) 1988, 1992 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#if HAVE_ALLOCA_H +#include +#else /* not HAVE_ALLOCA_H */ +#ifdef _AIX + #pragma alloca +#else /* not _AIX */ +char *alloca (); +#endif /* not _AIX */ +#endif /* not HAVE_ALLOCA_H */ +#endif /* not __GNUC__ */ + +#include "pathmax.h" + +#ifdef _POSIX_VERSION +#include +#else /* !_POSIX_VERSION */ +#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 /* _POSIX_VERSION */ + +/* nonstandard */ +#ifndef WIFCOREDUMPED +#define WIFCOREDUMPED(w) (((w) & 0x80) != 0) +#endif + +#ifdef __MSDOS__ +/* missing things from sys/stat.h */ +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 + +/* device stuff */ +#define makedev(ma, mi) ((ma << 8) | mi) +#define major(dev) (dev) +#define minor(dev) (dev) +typedef long off_t; +#endif /* __MSDOS__ */ + +#if defined(__STDC__) || defined(__TURBOC__) +#define PTR void * +#else +#define PTR char * +#define const +#endif + +/* Since major is a function on SVR4, we can't just use `ifndef major'. */ +#ifdef major /* Might be defined in sys/types.h. */ +#define HAVE_MAJOR +#endif + +#if !defined(HAVE_MAJOR) && defined(MAJOR_IN_MKDEV) +#include +#define HAVE_MAJOR +#endif + +#if !defined(HAVE_MAJOR) && defined(MAJOR_IN_SYSMACROS) +#include +#define HAVE_MAJOR +#endif + +#ifndef HAVE_MAJOR +#define major(dev) (((dev) >> 8) & 0xff) +#define minor(dev) ((dev) & 0xff) +#define makedev(maj, min) (((maj) << 8) | (min)) +#endif +#undef HAVE_MAJOR + +#if defined(STDC_HEADERS) || defined(HAVE_STRING_H) +#include +#if !defined(__MSDOS__) && !defined(STDC_HEADERS) +#include +#endif +#ifdef index +#undef index +#endif +#ifdef rindex +#undef rindex +#endif +#define index strchr +#define rindex strrchr +#define bcopy(s, d, n) memcpy(d, s, n) +#define bzero(s, n) memset(s, 0, n) +#define bcmp memcmp +#else +#include +#endif + +#if defined(STDC_HEADERS) +#include +#else +char *malloc (), *realloc (); +char *getenv (); +#endif + +#ifndef _POSIX_VERSION +#ifdef __MSDOS__ +#include +#else /* !__MSDOS__ */ +off_t lseek (); +#endif /* !__MSDOS__ */ +char *getcwd (); +#endif /* !_POSIX_VERSION */ + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef O_CREAT +#define O_CREAT 0 +#endif +#ifndef O_NDELAY +#define O_NDELAY 0 +#endif +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif +#ifndef O_RDWR +#define O_RDWR 2 +#endif + +#include +#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) +#define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0)) +#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(S_ISCTG) && defined(S_IFCTG) /* contiguous file */ +#define S_ISCTG(m) (((m) & S_IFMT) == S_IFCTG) +#endif +#if !defined(S_ISVTX) +#define S_ISVTX 0001000 +#endif + +#ifdef __MSDOS__ +#include "msd_dir.h" +#define NLENGTH(direct) ((direct)->d_namlen) + +#else /* not __MSDOS__ */ + +#if defined(DIRENT) || defined(_POSIX_VERSION) +#include +#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 +#endif /* SYSNDIR */ +#ifdef SYSDIR +#include +#endif /* SYSDIR */ +#ifdef NDIR +#include +#endif /* NDIR */ +#endif /* DIRENT or _POSIX_VERSION */ + +#endif /* not __MSDOS__ */ diff --git a/gnu/usr.bin/tar/regex.c b/gnu/usr.bin/tar/regex.c new file mode 100644 index 0000000000..cb94d597c6 --- /dev/null +++ b/gnu/usr.bin/tar/regex.c @@ -0,0 +1,4932 @@ +/* Extended regular expression matching and search library, + version 0.11. + (Implements POSIX draft P10003.2/D11.2, except for + internationalization features.) + + Copyright (C) 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined (_AIX) && !defined (REGEX_MALLOC) + #pragma alloca +#endif + +#define _GNU_SOURCE + +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +#include + +#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 +#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 +#endif + +#ifdef STDC_HEADERS +#include +#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 + +#ifndef isascii +#define isascii(c) 1 +#endif + +#ifdef isblank +#define ISBLANK(c) (isascii (c) && isblank (c)) +#else +#define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +#define ISGRAPH(c) (isascii (c) && isgraph (c)) +#else +#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c)) +#endif + +#define ISPRINT(c) (isascii (c) && isprint (c)) +#define ISDIGIT(c) (isascii (c) && isdigit (c)) +#define ISALNUM(c) (isascii (c) && isalnum (c)) +#define ISALPHA(c) (isascii (c) && isalpha (c)) +#define ISCNTRL(c) (isascii (c) && iscntrl (c)) +#define ISLOWER(c) (isascii (c) && islower (c)) +#define ISPUNCT(c) (isascii (c) && ispunct (c)) +#define ISSPACE(c) (isascii (c) && isspace (c)) +#define ISUPPER(c) (isascii (c) && isupper (c)) +#define ISXDIGIT(c) (isascii (c) && isxdigit (c)) + +#ifndef NULL +#define NULL 0 +#endif + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +#undef SIGN_EXTEND_CHAR +#if __STDC__ +#define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +#endif + +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we + use `alloca' instead of `malloc'. This is because using malloc in + re_search* or re_match* could cause memory leaks when C-g is used in + Emacs; also, malloc is slower and causes storage fragmentation. On + the other hand, malloc is more portable, and easier to debug. + + Because we sometimes use alloca, some routines have to be macros, + not functions -- `alloca'-allocated space disappears at the end of the + function it is called in. */ + +#ifdef REGEX_MALLOC + +#define REGEX_ALLOCATE malloc +#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) + +#else /* not REGEX_MALLOC */ + +/* Emacs already defines alloca, sometimes. */ +#ifndef alloca + +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#if HAVE_ALLOCA_H +#include +#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 + +/* It is useful to test things that ``must'' be true when debugging. */ +#include + +static int debug = 0; + +#define DEBUG_STATEMENT(e) e +#define DEBUG_PRINT1(x) if (debug) printf (x) +#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) +#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) +#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) +#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ + if (debug) print_partial_compiled_pattern (s, e) +#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ + if (debug) print_double_string (w, s1, sz1, s2, sz2) + + +extern void printchar (); + +/* Print the fastmap in human-readable form. */ + +void +print_fastmap (fastmap) + char *fastmap; +{ + unsigned was_a_range = 0; + unsigned i = 0; + + while (i < (1 << BYTEWIDTH)) + { + if (fastmap[i++]) + { + was_a_range = 0; + printchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } + if (was_a_range) + { + printf ("-"); + printchar (i - 1); + } + } + } + putchar ('\n'); +} + + +/* Print a compiled pattern string in human-readable form, starting at + the START pointer into it and ending just before the pointer END. */ + +void +print_partial_compiled_pattern (start, end) + unsigned char *start; + unsigned char *end; +{ + int mcnt, mcnt2; + unsigned char *p = start; + unsigned char *pend = end; + + if (start == NULL) + { + printf ("(null)\n"); + return; + } + + /* Loop over pattern commands. */ + while (p < pend) + { + switch ((re_opcode_t) *p++) + { + case no_op: + printf ("/no_op"); + break; + + case exactn: + mcnt = *p++; + printf ("/exactn/%d", mcnt); + do + { + putchar ('/'); + printchar (*p++); + } + while (--mcnt); + break; + + case start_memory: + mcnt = *p++; + printf ("/start_memory/%d/%d", mcnt, *p++); + break; + + case stop_memory: + mcnt = *p++; + printf ("/stop_memory/%d/%d", mcnt, *p++); + break; + + case duplicate: + printf ("/duplicate/%d", *p++); + break; + + case anychar: + printf ("/anychar"); + break; + + case charset: + case charset_not: + { + register int c; + + printf ("/charset%s", + (re_opcode_t) *(p - 1) == charset_not ? "_not" : ""); + + assert (p + *p < pend); + + for (c = 0; c < *p; c++) + { + unsigned bit; + unsigned char map_byte = p[1 + c]; + + putchar ('/'); + + for (bit = 0; bit < BYTEWIDTH; bit++) + if (map_byte & (1 << bit)) + printchar (c * BYTEWIDTH + bit); + } + p += 1 + *p; + break; + } + + case begline: + printf ("/begline"); + break; + + case endline: + printf ("/endline"); + break; + + case on_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_jump/0/%d", mcnt); + break; + + case on_failure_keep_string_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_keep_string_jump/0/%d", mcnt); + break; + + case dummy_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/dummy_failure_jump/0/%d", mcnt); + break; + + case push_dummy_failure: + printf ("/push_dummy_failure"); + break; + + case maybe_pop_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/maybe_pop_jump/0/%d", mcnt); + break; + + case pop_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/pop_failure_jump/0/%d", mcnt); + break; + + case jump_past_alt: + extract_number_and_incr (&mcnt, &p); + printf ("/jump_past_alt/0/%d", mcnt); + break; + + case jump: + extract_number_and_incr (&mcnt, &p); + printf ("/jump/0/%d", mcnt); + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2); + break; + + case wordbound: + printf ("/wordbound"); + break; + + case notwordbound: + printf ("/notwordbound"); + break; + + case wordbeg: + printf ("/wordbeg"); + break; + + case wordend: + printf ("/wordend"); + +#ifdef emacs + case before_dot: + printf ("/before_dot"); + break; + + case at_dot: + printf ("/at_dot"); + break; + + case after_dot: + printf ("/after_dot"); + break; + + case syntaxspec: + printf ("/syntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; + + case notsyntaxspec: + printf ("/notsyntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; +#endif /* emacs */ + + case wordchar: + printf ("/wordchar"); + break; + + case notwordchar: + printf ("/notwordchar"); + break; + + case begbuf: + printf ("/begbuf"); + break; + + case endbuf: + printf ("/endbuf"); + break; + + default: + printf ("?%d", *(p-1)); + } + } + printf ("/\n"); +} + + +void +print_compiled_pattern (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *buffer = bufp->buffer; + + print_partial_compiled_pattern (buffer, buffer + bufp->used); + printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated); + + if (bufp->fastmap_accurate && bufp->fastmap) + { + printf ("fastmap: "); + print_fastmap (bufp->fastmap); + } + + printf ("re_nsub: %d\t", bufp->re_nsub); + printf ("regs_alloc: %d\t", bufp->regs_allocated); + printf ("can_be_null: %d\t", bufp->can_be_null); + printf ("newline_anchor: %d\n", bufp->newline_anchor); + printf ("no_sub: %d\t", bufp->no_sub); + printf ("not_bol: %d\t", bufp->not_bol); + printf ("not_eol: %d\t", bufp->not_eol); + printf ("syntax: %d\n", bufp->syntax); + /* Perhaps we should print the translate table? */ +} + + +void +print_double_string (where, string1, size1, string2, size2) + const char *where; + const char *string1; + const char *string2; + int size1; + int size2; +{ + unsigned this_char; + + if (where == NULL) + printf ("(null)"); + else + { + if (FIRST_STRING_P (where)) + { + for (this_char = where - string1; this_char < size1; this_char++) + printchar (string1[this_char]); + + where = string2; + } + + for (this_char = where - string2; this_char < size2; this_char++) + printchar (string2[this_char]); + } +} + +#else /* not DEBUG */ + +#undef assert +#define assert(e) + +#define DEBUG_STATEMENT(e) +#define DEBUG_PRINT1(x) +#define DEBUG_PRINT2(x1, x2) +#define DEBUG_PRINT3(x1, x2, x3) +#define DEBUG_PRINT4(x1, x2, x3, x4) +#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) +#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) + +#endif /* not DEBUG */ + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (syntax) + reg_syntax_t syntax; +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; + return ret; +} + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. */ + +static const char *re_error_msg[] = + { NULL, /* REG_NOERROR */ + "No match", /* REG_NOMATCH */ + "Invalid regular expression", /* REG_BADPAT */ + "Invalid collation character", /* REG_ECOLLATE */ + "Invalid character class name", /* REG_ECTYPE */ + "Trailing backslash", /* REG_EESCAPE */ + "Invalid back reference", /* REG_ESUBREG */ + "Unmatched [ or [^", /* REG_EBRACK */ + "Unmatched ( or \\(", /* REG_EPAREN */ + "Unmatched \\{", /* REG_EBRACE */ + "Invalid content of \\{\\}", /* REG_BADBR */ + "Invalid range end", /* REG_ERANGE */ + "Memory exhausted", /* REG_ESPACE */ + "Invalid preceding regular expression", /* REG_BADRPT */ + "Premature end of regular expression", /* REG_EEND */ + "Regular expression too big", /* REG_ESIZE */ + "Unmatched ) or \\)", /* REG_ERPAREN */ + }; + +/* Subroutine declarations and macros for regex_compile. */ + +static void store_op1 (), store_op2 (); +static void insert_op1 (), insert_op2 (); +static boolean at_begline_loc_p (), at_endline_loc_p (); +static boolean group_in_compile_stack (); +static reg_errcode_t compile_range (); + +/* Fetch the next character in the uncompiled pattern---translating it + if necessary. Also cast from a signed character in the constant + string passed to us by the user to an unsigned char that we can use + as an array index (in, e.g., `translate'). */ +#define PATFETCH(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + if (translate) c = translate[c]; \ + } while (0) + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH_RAW(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + } while (0) + +/* Go backwards one character in the pattern. */ +#define PATUNFETCH p-- + + +/* If `translate' is non-null, return translate[D], else just D. We + cast the subscript to translate because some data is declared as + `char *', to avoid warnings when a string constant is passed. But + when we use a character as a subscript we must make it unsigned. */ +#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d)) + + +/* Macros for outputting the compiled pattern into `buffer'. */ + +/* If the buffer isn't allocated when it comes in, use this. */ +#define INIT_BUF_SIZE 32 + +/* Make sure we have at least N more bytes of space in buffer. */ +#define GET_BUFFER_SPACE(n) \ + while (b - bufp->buffer + (n) > bufp->allocated) \ + EXTEND_BUFFER () + +/* Make sure we have one more byte of buffer space and then add C to it. */ +#define BUF_PUSH(c) \ + do { \ + GET_BUFFER_SPACE (1); \ + *b++ = (unsigned char) (c); \ + } while (0) + + +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ +#define BUF_PUSH_2(c1, c2) \ + do { \ + GET_BUFFER_SPACE (2); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + } while (0) + + +/* As with BUF_PUSH_2, except for three bytes. */ +#define BUF_PUSH_3(c1, c2, c3) \ + do { \ + GET_BUFFER_SPACE (3); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + *b++ = (unsigned char) (c3); \ + } while (0) + + +/* Store a jump with opcode OP at LOC to location TO. We store a + relative address offset by the three bytes the jump itself occupies. */ +#define STORE_JUMP(op, loc, to) \ + store_op1 (op, loc, (to) - (loc) - 3) + +/* Likewise, for a two-argument jump. */ +#define STORE_JUMP2(op, loc, to, arg) \ + store_op2 (op, loc, (to) - (loc) - 3, arg) + +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP(op, loc, to) \ + insert_op1 (op, loc, (to) - (loc) - 3, b) + +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP2(op, loc, to, arg) \ + insert_op2 (op, loc, (to) - (loc) - 3, arg, b) + + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^16 bytes turns out to + be too small, many things would have to change. */ +#define MAX_BUF_SIZE (1L << 16) + + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +#define EXTEND_BUFFER() \ + do { \ + unsigned char *old_buffer = bufp->buffer; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\ + if (bufp->buffer == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != bufp->buffer) \ + { \ + b = (b - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (fixup_alt_jump) \ + fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + } \ + } while (0) + + +/* Since we have one byte reserved for the register number argument to + {start,stop}_memory, the maximum number of groups we can report + things about is what fits in that byte. */ +#define MAX_REGNUM 255 + +/* But patterns can have more than `MAX_REGNUM' registers. We just + ignore the excess. */ +typedef unsigned regnum_t; + + +/* Macros for the compile stack. */ + +/* Since offsets can go either forwards or backwards, this type needs to + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ +typedef int pattern_offset_t; + +typedef struct +{ + pattern_offset_t begalt_offset; + pattern_offset_t fixup_alt_jump; + pattern_offset_t inner_group_offset; + pattern_offset_t laststart_offset; + regnum_t regnum; +} compile_stack_elt_t; + + +typedef struct +{ + compile_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} compile_stack_type; + + +#define INIT_COMPILE_STACK_SIZE 32 + +#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) +#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) + +/* The next available element. */ +#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) + + +/* Set the bit for character C in a list. */ +#define SET_LIST_BIT(c) \ + (b[((unsigned char) (c)) / BYTEWIDTH] \ + |= 1 << (((unsigned char) c) % BYTEWIDTH)) + + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + { if (p != pend) \ + { \ + PATFETCH (c); \ + while (ISDIGIT (c)) \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + } \ + } + +#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +#define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) + +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. + Returns one of error codes defined in `regex.h', or zero for success. + + Assumes the `allocated' (and perhaps `buffer') and `translate' + fields are set in BUFP on entry. + + If it succeeds, results are put in BUFP (if it returns an error, the + contents of BUFP are undefined): + `buffer' is the compiled pattern; + `syntax' is set to SYNTAX; + `used' is set to the length of the compiled pattern; + `fastmap_accurate' is zero; + `re_nsub' is the number of subexpressions in PATTERN; + `not_bol' and `not_eol' are zero; + + The `fastmap' and `newline_anchor' fields are neither + examined nor set. */ + +static reg_errcode_t +regex_compile (pattern, size, syntax, bufp) + const char *pattern; + int size; + reg_syntax_t syntax; + struct re_pattern_buffer *bufp; +{ + /* We fetch characters from PATTERN here. Even though PATTERN is + `char *' (i.e., signed), we declare these variables as unsigned, so + they can be reliably used as array indices. */ + register unsigned char c, c1; + + /* A random tempory spot in PATTERN. */ + const char *p1; + + /* Points to the end of the buffer, where we should append. */ + register unsigned char *b; + + /* Keeps track of unclosed groups. */ + compile_stack_type compile_stack; + + /* Points to the current (ending) position in the pattern. */ + const char *p = pattern; + const char *pend = pattern + size; + + /* How to translate the characters in the pattern. */ + char *translate = bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell if a new exact-match + character can be added to that command or if the character requires + a new `exactn' command. */ + unsigned char *pending_exact = 0; + + /* Address of start of the most recently finished expression. + This tells, e.g., postfix * where to find the start of its + operand. Reset at the beginning of groups and alternatives. */ + unsigned char *laststart = 0; + + /* Address of beginning of regexp, or inside of last group. */ + unsigned char *begalt; + + /* Place in the uncompiled pattern (i.e., the {) to + which to go back if the interval is invalid. */ + const char *beg_interval; + + /* Address of the place where a forward jump should go to the end of + the containing expression. Each alternative of an `or' -- except the + last -- ends with a forward jump of this sort. */ + unsigned char *fixup_alt_jump = 0; + + /* Counts open-groups as they are encountered. Remembered for the + matching close-group on the compile stack, so the same register + number is put in the stop_memory as the start_memory. */ + regnum_t regnum = 0; + +#ifdef DEBUG + DEBUG_PRINT1 ("\nCompiling pattern: "); + if (debug) + { + unsigned debug_count; + + for (debug_count = 0; debug_count < size; debug_count++) + printchar (pattern[debug_count]); + putchar ('\n'); + } +#endif /* DEBUG */ + + /* Initialize the compile stack. */ + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); + if (compile_stack.stack == NULL) + return REG_ESPACE; + + compile_stack.size = INIT_COMPILE_STACK_SIZE; + compile_stack.avail = 0; + + /* Initialize the pattern buffer. */ + bufp->syntax = syntax; + bufp->fastmap_accurate = 0; + bufp->not_bol = bufp->not_eol = 0; + + /* Set `used' to zero, so that if we return an error, the pattern + printer (for debugging) will think there's no pattern. We reset it + at the end. */ + bufp->used = 0; + + /* Always count groups, whether or not bufp->no_sub is set. */ + bufp->re_nsub = 0; + +#if !defined (emacs) && !defined (SYNTAX_TABLE) + /* Initialize the syntax table. */ + init_syntax_once (); +#endif + + if (bufp->allocated == 0) + { + if (bufp->buffer) + { /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } + else + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } + if (!bufp->buffer) return REG_ESPACE; + + bufp->allocated = INIT_BUF_SIZE; + } + + begalt = b = bufp->buffer; + + /* Loop through the uncompiled pattern until we're at the end. */ + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; + + + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; + + + case '+': + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; + + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; + + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ + + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + + if (p == pend) + break; + + PATFETCH (c); + + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; + + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) return REG_EESCAPE; + + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + + c = c1; + } + else + { + PATUNFETCH; + break; + } + + /* If we get here, we found another repeat character. */ + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). + + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); + + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (3); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - 3); + + /* We've added more stuff to the buffer. */ + b += 3; + } + + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 3); + pending_exact = 0; + b += 3; + + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); + b += 3; + } + } + break; + + + case '.': + laststart = b; + BUF_PUSH (anychar); + break; + + + case '[': + { + boolean had_char_class = false; + + if (p == pend) return REG_EBRACK; + + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ + GET_BUFFER_SPACE (34); + + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) return REG_EBRACK; + + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) return REG_EESCAPE; + + PATFETCH (c1); + SET_LIST_BIT (c1); + continue; + } + + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; + + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + return REG_ERANGE; + + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } + + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; + + /* Move past the `-'. */ + PATFETCH (c1); + + ret = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } + + /* See if we're at the beginning of a possible character + class. */ + + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) return REG_EBRACK; + + for (;;) + { + PATFETCH (c); + if (c == ':' || c == ']' || p == pend + || c1 == CHAR_CLASS_MAX_LENGTH) + break; + str[c1++] = c; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and:`]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); + + if (!IS_CHAR_CLASS (str)) return REG_ECTYPE; + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) return REG_EBRACK; + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch)) + || (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch)) + || (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + } + break; + + + case '(': + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; + + + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; + + + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; + + + case '|': + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; + + + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; + + + case '\\': + if (p == pend) return REG_EESCAPE; + + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); + + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; + + handle_open: + bufp->re_nsub++; + regnum++; + + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; + + compile_stack.size <<= 1; + } + + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = regnum; + + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } + + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; + break; + + + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + + if (COMPILE_STACK_EMPTY) + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + return REG_ERPAREN; + + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); + + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } + + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + return REG_ERPAREN; + + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; + + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + unsigned char *inner_group_loc + = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; + + + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; + + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; + + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; + + laststart = 0; + begalt = b; + break; + + + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + || (p - 2 == pattern && p == pend)) + goto normal_backslash; + + handle_interval: + { + /* If got here, then the syntax allows intervals. */ + + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; + + beg_interval = p - 1; + + if (p == pend) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_EBRACE; + } + + GET_UNSIGNED_NUMBER (lower_bound); + + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; + + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') return REG_EBRACE; + + PATFETCH (c); + } + + if (c != '}') + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } + + /* We just parsed a valid interval. */ + + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } + + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + } + + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at + set_number_at + succeed_n + + jump_n + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 10 + (upper_bound > 1) * 10; + + GET_BUFFER_SPACE (nbytes); + + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + (upper_bound > 1) * 5, + lower_bound); + b += 5; + + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; + + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. + + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + 5, + upper_bound - 1); + b += 5; + + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. + + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (p > pattern && p[-1] == '\\') + goto normal_backslash; + } + goto normal_char; + +#ifdef emacs + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; + + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; +#endif /* emacs */ + + + case 'w': + laststart = b; + BUF_PUSH (wordchar); + break; + + + case 'W': + laststart = b; + BUF_PUSH (notwordchar); + break; + + + case '<': + BUF_PUSH (wordbeg); + break; + + case '>': + BUF_PUSH (wordend); + break; + + case 'b': + BUF_PUSH (wordbound); + break; + + case 'B': + BUF_PUSH (notwordbound); + break; + + case '`': + BUF_PUSH (begbuf); + break; + + case '\'': + BUF_PUSH (endbuf); + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; + + c1 = c - '0'; + + if (c1 > regnum) + return REG_ESUBREG; + + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, c1)) + goto normal_char; + + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; + + + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; + + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; + + + default: + /* Expects the character in `c'. */ + normal_char: + /* If no exactn currently being built. */ + if (!pending_exact + + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ + || *pending_exact == (1 << BYTEWIDTH) - 1 + + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' + || ((syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((syntax & RE_INTERVALS) + && ((syntax & RE_NO_BK_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + /* Start building a new exactn. */ + + laststart = b; + + BUF_PUSH_2 (exactn, 0); + pending_exact = b - 1; + } + + BUF_PUSH (c); + (*pending_exact)++; + break; + } /* switch (c) */ + } /* while p != pend */ + + + /* Through the pattern now. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + if (!COMPILE_STACK_EMPTY) + return REG_EPAREN; + + free (compile_stack.stack); + + /* We have succeeded; set the length of the buffer. */ + bufp->used = b - bufp->buffer; + +#ifdef DEBUG + if (debug) + { + DEBUG_PRINT1 ("\nCompiled pattern: "); + print_compiled_pattern (bufp); + } +#endif /* DEBUG */ + + return REG_NOERROR; +} /* regex_compile */ + +/* Subroutines for `regex_compile'. */ + +/* Store OP at LOC followed by two-byte integer parameter ARG. */ + +static void +store_op1 (op, loc, arg) + re_opcode_t op; + unsigned char *loc; + int arg; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg); +} + + +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +store_op2 (op, loc, arg1, arg2) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg1); + STORE_NUMBER (loc + 3, arg2); +} + + +/* Copy the bytes from LOC to END to open up three bytes of space at LOC + for OP followed by two-byte integer parameter ARG. */ + +static void +insert_op1 (op, loc, arg, end) + re_opcode_t op; + unsigned char *loc; + int arg; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 3; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op1 (op, loc, arg); +} + + +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +insert_op2 (op, loc, arg1, arg2, end) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 5; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op2 (op, loc, arg1, arg2); +} + + +/* P points to just after a ^ in PATTERN. Return true if that ^ comes + after an alternative or a begin-subexpression. We assume there is at + least one character before the ^. */ + +static boolean +at_begline_loc_p (pattern, p, syntax) + const char *pattern, *p; + reg_syntax_t syntax; +{ + const char *prev = p - 2; + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; + + return + /* After a subexpression? */ + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) + /* After an alternative? */ + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); +} + + +/* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + +static boolean +at_endline_loc_p (p, pend, syntax) + const char *p, *pend; + int syntax; +{ + const char *next = p; + boolean next_backslash = *next == '\\'; + const char *next_next = p + 1 < pend ? p + 1 : NULL; + + return + /* Before a subexpression? */ + (syntax & RE_NO_BK_PARENS ? *next == ')' + : next_backslash && next_next && *next_next == ')') + /* Before an alternative? */ + || (syntax & RE_NO_BK_VBAR ? *next == '|' + : next_backslash && next_next && *next_next == '|'); +} + + +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and + false if it's not. */ + +static boolean +group_in_compile_stack (compile_stack, regnum) + compile_stack_type compile_stack; + regnum_t regnum; +{ + int this_element; + + for (this_element = compile_stack.avail - 1; + this_element >= 0; + this_element--) + if (compile_stack.stack[this_element].regnum == regnum) + return true; + + return false; +} + + +/* Read the ending character of a range (in a bracket expression) from the + uncompiled pattern *P_PTR (which ends at PEND). We assume the + starting character is in `P[-2]'. (`P[-1]' is the character `-'.) + Then we set the translation of all bits between the starting and + ending characters (inclusive) in the compiled pattern B. + + Return an error code. + + We use these short variable names so we can use the same macros as + `regex_compile' itself. */ + +static reg_errcode_t +compile_range (p_ptr, pend, translate, syntax, b) + const char **p_ptr, *pend; + char *translate; + reg_syntax_t syntax; + unsigned char *b; +{ + unsigned this_char; + + const char *p = *p_ptr; + int range_start, range_end; + + if (p == pend) + return REG_ERANGE; + + /* Even though the pattern is a signed `char *', we need to fetch + with unsigned char *'s; if the high bit of the pattern character + is set, the range endpoints will be negative if we fetch using a + signed char *. + + We also want to fetch the endpoints without translating them; the + appropriate translation is done in the bit-setting loop below. */ + range_start = ((unsigned char *) p)[-2]; + range_end = ((unsigned char *) p)[0]; + + /* Have to increment the pointer into the pattern string, so the + caller isn't still at the ending character. */ + (*p_ptr)++; + + /* If the start is after the end, the range is empty. */ + if (range_start > range_end) + return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; + + /* Here we see why `this_char' has to be larger than an `unsigned + char' -- the range is inclusive, so if `range_end' == 0xff + (assuming 8-bit characters), we would otherwise go into an infinite + loop, since all characters <= 0xff. */ + for (this_char = range_start; this_char <= range_end; this_char++) + { + SET_LIST_BIT (TRANSLATE (this_char)); + } + + return REG_NOERROR; +} + +/* Failure stack declarations and macros; both re_compile_fastmap and + re_match_2 use a failure stack. These have to be macros because of + REGEX_ALLOCATE. */ + + +/* Number of failure points for which to initially allocate space + when matching. If this number is exceeded, we allocate more + space, so it is not a hard limit. */ +#ifndef INIT_FAILURE_ALLOC +#define INIT_FAILURE_ALLOC 5 +#endif + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always used MAX_FAILURE_SPACE each time we failed. + This is a variable only so users of regex can assign to it; we never + change it ourselves. */ +int re_max_failures = 2000; + +typedef const unsigned char *fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} fail_stack_type; + +#define FAIL_STACK_EMPTY() (fail_stack.avail == 0) +#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) +#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) +#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail]) + + +/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */ + +#define INIT_FAIL_STACK() \ + do { \ + fail_stack.stack = (fail_stack_elt_t *) \ + REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ + \ + if (fail_stack.stack == NULL) \ + return -2; \ + \ + fail_stack.size = INIT_FAILURE_ALLOC; \ + fail_stack.avail = 0; \ + } while (0) + + +/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. + + Return 1 if succeeds, and 0 if either ran out of memory + allocating space for it or it was already too large. + + REGEX_REALLOCATE requires `destination' be declared. */ + +#define DOUBLE_FAIL_STACK(fail_stack) \ + ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \ + ? 0 \ + : ((fail_stack).stack = (fail_stack_elt_t *) \ + REGEX_REALLOCATE ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ + \ + (fail_stack).stack == NULL \ + ? 0 \ + : ((fail_stack).size <<= 1, \ + 1))) + + +/* Push PATTERN_OP on FAIL_STACK. + + Return 1 if was able to do so and 0 if ran out of memory allocating + space to do so. */ +#define PUSH_PATTERN_OP(pattern_op, fail_stack) \ + ((FAIL_STACK_FULL () \ + && !DOUBLE_FAIL_STACK (fail_stack)) \ + ? 0 \ + : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \ + 1)) + +/* This pushes an item onto the failure stack. Must be a four-byte + value. Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_ITEM(item) \ + fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item + +/* The complement operation. Assumes `fail_stack' is nonempty. */ +#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail] + +/* Used to omit pushing failure point id's when we're not debugging. */ +#ifdef DEBUG +#define DEBUG_PUSH PUSH_FAILURE_ITEM +#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM () +#else +#define DEBUG_PUSH(item) +#define DEBUG_POP(item_addr) +#endif + + +/* Push the information about the state we will need + if we ever fail back to it. + + Requires variables fail_stack, regstart, regend, reg_info, and + num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be + declared. + + Does `return FAILURE_CODE' if runs out of memory. */ + +#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ + do { \ + char *destination; \ + /* Must be int, so when we don't save any registers, the arithmetic \ + of 0 + -1 isn't done as unsigned. */ \ + int this_reg; \ + \ + DEBUG_STATEMENT (failure_id++); \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ + DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ + \ + DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \ + DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ + \ + /* Ensure we have enough space allocated for what we will push. */ \ + while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ + { \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ + \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + (fail_stack).size); \ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + } \ + \ + /* Push the info, starting with the registers. */ \ + DEBUG_PRINT1 ("\n"); \ + \ + for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ + this_reg++) \ + { \ + DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \ + DEBUG_STATEMENT (num_regs_pushed++); \ + \ + DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ + PUSH_FAILURE_ITEM (regstart[this_reg]); \ + \ + DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ + PUSH_FAILURE_ITEM (regend[this_reg]); \ + \ + DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT1 ("\n"); \ + PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ + } \ + \ + DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\ + PUSH_FAILURE_ITEM (lowest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\ + PUSH_FAILURE_ITEM (highest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ + PUSH_FAILURE_ITEM (pattern_place); \ + \ + DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \ + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ + size2); \ + DEBUG_PRINT1 ("'\n"); \ + PUSH_FAILURE_ITEM (string_place); \ + \ + DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ + DEBUG_PUSH (failure_id); \ + } while (0) + +/* This is the number of items that are pushed and popped on the stack + for each register. */ +#define NUM_REG_ITEMS 3 + +/* Individual items aside from the registers. */ +#ifdef DEBUG +#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ +#else +#define NUM_NONREG_ITEMS 4 +#endif + +/* We push at most this many items on the stack. */ +#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS) + +/* We actually push this many items. */ +#define NUM_FAILURE_ITEMS \ + ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \ + + NUM_NONREG_ITEMS) + +/* How many items can still be added to the stack without overflowing it. */ +#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) + + +/* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + LOW_REG, HIGH_REG -- the highest and lowest active registers. + REGSTART, REGEND -- arrays of string positions. + REG_INFO -- array of information about each subexpression. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ + +#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ +{ \ + DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \ + int this_reg; \ + const unsigned char *string_temp; \ + \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ + \ + DEBUG_POP (&failure_id); \ + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + string_temp = POP_FAILURE_ITEM (); \ + if (string_temp != NULL) \ + str = (const char *) string_temp; \ + \ + DEBUG_PRINT2 (" Popping string 0x%x: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + pat = (unsigned char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* Restore register info. */ \ + high_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \ + \ + low_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \ + \ + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ + { \ + DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \ + \ + reg_info[this_reg].word = POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \ + \ + regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ + \ + regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ + } \ + \ + DEBUG_STATEMENT (nfailure_points_popped++); \ +} /* POP_FAILURE_POINT */ + +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible + characters can start a string that matches the pattern. This fastmap + is used by re_search to skip quickly over impossible starting points. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as BUFP->fastmap. + + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in + the pattern buffer. + + Returns 0 if we succeed, -2 if an internal error. */ + +int +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + int j, k; + fail_stack_type fail_stack; +#ifndef REGEX_MALLOC + char *destination; +#endif + /* We don't push any register information onto the failure stack. */ + unsigned num_regs = 0; + + register char *fastmap = bufp->fastmap; + unsigned char *pattern = bufp->buffer; + unsigned long size = bufp->used; + const unsigned char *p = pattern; + register unsigned char *pend = pattern + size; + + /* Assume that each path through the pattern can be null until + proven otherwise. We set this false at the bottom of switch + statement, to which we get only if a particular path doesn't + match the empty string. */ + boolean path_can_be_null = true; + + /* We aren't doing a `succeed_n' to begin with. */ + boolean succeed_n_p = false; + + assert (fastmap != NULL && p != NULL); + + INIT_FAIL_STACK (); + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ + bufp->fastmap_accurate = 1; /* It will be when we're done. */ + bufp->can_be_null = 0; + + while (p != pend || !FAIL_STACK_EMPTY ()) + { + if (p == pend) + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail]; + } + + /* We should never be about to go beyond the end of the pattern. */ + assert (p < pend); + +#ifdef SWITCH_ENUM_BUG + switch ((int) ((re_opcode_t) *p++)) +#else + switch ((re_opcode_t) *p++) +#endif + { + + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ + case duplicate: + bufp->can_be_null = 1; + return 0; + + + /* Following are the cases which match a character. These end + with `break'. */ + + case exactn: + fastmap[p[1]] = 1; + break; + + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + fastmap[j] = 1; + break; + + + case charset_not: + /* Chars beyond end of map must be allowed. */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + fastmap[j] = 1; + break; + + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + + + case anychar: + /* `.' matches anything ... */ + for (j = 0; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = 0; + + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ + else if (bufp->can_be_null) + return 0; + + /* Otherwise, have to check alternative paths. */ + break; + + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + /* All cases after this match the empty string. These end with + `continue'. */ + + + case before_dot: + case at_dot: + case after_dot: + continue; +#endif /* not emacs */ + + + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + case push_dummy_failure: + continue; + + + case jump_n: + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case jump_past_alt: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump + && (re_opcode_t) *p != succeed_n) + continue; + + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () + && fail_stack.stack[fail_stack.avail - 1] == p) + fail_stack.avail--; + + continue; + + + case on_failure_jump: + case on_failure_keep_string_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + return -2; + } + else + bufp->can_be_null = 1; + + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; + } + + continue; + + + case succeed_n: + /* Get to the number of times to succeed. */ + p += 2; + + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 4; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; + + + case set_number_at: + p += 4; + continue; + + + case start_memory: + case stop_memory: + p += 2; + continue; + + + default: + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ + + /* Getting here means we have found the possible starting + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ + path_can_be_null = false; + p = pend; + } /* while p */ + + /* Set `can_be_null' for the last path (also the first path, if the + pattern is empty). */ + bufp->can_be_null |= path_can_be_null; + return 0; +} /* re_compile_fastmap */ + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (bufp, regs, num_regs, starts, ends) + struct re_pattern_buffer *bufp; + struct re_registers *regs; + unsigned num_regs; + regoff_t *starts, *ends; +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t) 0; + } +} + +/* Searching routines. */ + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (bufp, string, size, startpos, range, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + regs, size); +} + + +/* Using the compiled pattern in BUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. + + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. + + RANGE is how far to scan while trying to match. RANGE = 0 means try + only at STARTPOS; in general, the last start tried is STARTPOS + + RANGE. + + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire BUFP->buffer and its contained + subexpressions. + + Do not consider matching one past the index STOP in the virtual + concatenation of STRING1 and STRING2. + + We return either the position in the strings at which the match was + found, -1 if no match, or -2 if error (such as failure + stack overflow). */ + +int +re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int startpos; + int range; + struct re_registers *regs; + int stop; +{ + int val; + register char *fastmap = bufp->fastmap; + register char *translate = bufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + + /* Check for out-of-range STARTPOS. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up RANGE if it might eventually take us outside + the virtual concatenation of STRING1 and STRING2. */ + if (endpos < -1) + range = -1 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* If the search isn't to be a backwards one, don't waste time in a + search for a pattern that must be anchored. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + if (re_compile_fastmap (bufp) == -2) + return -2; + + /* Loop through the string, looking for a place to start matching. */ + for (;;) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ + if (fastmap && startpos < total_size && !bufp->can_be_null) + { + if (range > 0) /* Searching forwards. */ + { + register const char *d; + register int lim = 0; + int irange = range; + + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + d = (startpos >= size1 ? string2 - size1 : string1) + startpos; + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ + if (translate) + while (range > lim + && !fastmap[(unsigned char) + translate[(unsigned char) *d++]]) + range--; + else + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; + + startpos += irange - range; + } + else /* Searching backwards. */ + { + register char c = (size1 == 0 || startpos >= size1 + ? string2[startpos - size1] + : string1[startpos]); + + if (!fastmap[(unsigned char) TRANSLATE (c)]) + goto advance; + } + } + + /* If can't match the null string, and that's all we have left, fail. */ + if (range >= 0 && startpos == total_size && fastmap + && !bufp->can_be_null) + return -1; + + val = re_match_2 (bufp, string1, size1, string2, size2, + startpos, regs, stop); + if (val >= 0) + return startpos; + + if (val == -2) + return -2; + + advance: + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } + else + { + range++; + startpos--; + } + } + return -1; +} /* re_search_2 */ + +/* Declarations and macros for re_match_2. */ + +static int bcmp_translate (); +static boolean alt_match_null_string_p (), + common_op_match_null_string_p (), + group_match_null_string_p (); + +/* Structure for per-register (a.k.a. per-group) information. + This must not be longer than one word, because we push this value + onto the failure stack. Other register information, such as the + starting and ending positions (which are addresses), and the list of + inner groups (which is a bits list) are maintained in separate + variables. + + We are making a (strictly speaking) nonportable assumption here: that + the compiler will pack our bit fields into something that fits into + the type of `word', i.e., is something that fits into one item on the + failure stack. */ +typedef union +{ + fail_stack_elt_t word; + struct + { + /* This field is one if this group can match the empty string, + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ +#define MATCH_NULL_UNSET_VALUE 3 + unsigned match_null_string_p : 2; + unsigned is_active : 1; + unsigned matched_something : 1; + unsigned ever_matched_something : 1; + } bits; +} register_info_type; + +#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) +#define IS_ACTIVE(R) ((R).bits.is_active) +#define MATCHED_SOMETHING(R) ((R).bits.matched_something) +#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) + + +/* Call this when have matched a real character; it sets `matched' flags + for the subexpressions which we are currently inside. Also records + that those subexprs have matched. */ +#define SET_REGS_MATCHED() \ + do \ + { \ + unsigned r; \ + for (r = lowest_active_reg; r <= highest_active_reg; r++) \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ + } \ + while (0) + + +/* This converts PTR, a pointer into one of the search strings `string1' + and `string2' into an offset from the beginning of that string. */ +#define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1) + +/* Registers are set to a sentinel when they haven't yet matched. */ +#define REG_UNSET_VALUE ((char *) -1) +#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) + + +/* Macros for dealing with the split strings in re_match_2. */ + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ +#define PREFETCH() \ + while (d == dend) \ + { \ + /* End of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* End of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + + +/* Test if at very beginning or at very end of the virtual concatenation + of `string1' and `string2'. If only one string, it's `string2'. */ +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END(d) ((d) == end2) + + +/* Test if D points to a character which is word-constituent. We have + two special cases to check for: if past the end of string1, look at + the first character in string2; and if before the beginning of + string2, look at the last character in string1. */ +#define WORDCHAR_P(d) \ + (SYNTAX ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + == Sword) + +/* Test if the character before D and the one at D differ with respect + to being word-constituent. */ +#define AT_WORD_BOUNDARY(d) \ + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) + + +/* Free everything we malloc. */ +#ifdef REGEX_MALLOC +#define FREE_VAR(var) if (var) free (var); var = NULL +#define FREE_VARIABLES() \ + do { \ + FREE_VAR (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (old_regstart); \ + FREE_VAR (old_regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + FREE_VAR (reg_info); \ + FREE_VAR (reg_dummy); \ + FREE_VAR (reg_info_dummy); \ + } while (0) +#else /* not REGEX_MALLOC */ +/* Some MIPS systems (at least) want this to free alloca'd storage. */ +#define FREE_VARIABLES() alloca (0) +#endif /* not REGEX_MALLOC */ + + +/* These values must meet several constraints. They must not be valid + register values; since we have a limit of 255 registers (because + we use only one byte in the pattern for the register number), we can + use numbers larger than 255. They must differ by 1, because of + NUM_FAILURE_ITEMS above. And the value for the lowest register must + be larger than the value for the highest register, so we do not try + to actually save any registers when none are active. */ +#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) +#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) + +/* Matching routines. */ + +#ifndef emacs /* Emacs never uses this. */ +/* re_match is like re_match_2 except it takes only a single string. */ + +int +re_match (bufp, string, size, pos, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, pos; + struct re_registers *regs; + { + return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); +} +#endif /* not emacs */ + + +/* re_match_2 matches the compiled pattern in BUFP against the + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 + and SIZE2, respectively). We start matching at POS, and stop + matching at STOP. + + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we + store offsets for the substring each group matched in REGS. See the + documentation for exactly how many groups we fill. + + We return -1 if no match, -2 if an internal error (such as the + failure stack overflowing). Otherwise, we return the length of the + matched substring. */ + +int +re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + /* General temporaries. */ + int mcnt; + unsigned char *p1; + + /* Just past the end of the corresponding string. */ + const char *end1, *end2; + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + const char *end_match_1, *end_match_2; + + /* Where we are in the data, and the end of the current string. */ + const char *d, *dend; + + /* Where we are in the pattern, and the end of the pattern. */ + unsigned char *p = bufp->buffer; + register unsigned char *pend = p + bufp->used; + + /* We use this to map every character in the string. */ + char *translate = bufp->translate; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to + the subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where + to resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is + a ``dummy''; if a failure happens and the failure point is a dummy, + it gets discarded and the next next one is tried. */ + fail_stack_type fail_stack; +#ifdef DEBUG + static unsigned failure_id = 0; + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; +#endif + + /* We fill all the registers internally, independent of what we + return, for use in backreferences. The number here includes + an element for register zero. */ + unsigned num_regs = bufp->re_nsub + 1; + + /* The currently active registers. */ + unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG; + unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG; + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ + const char **regstart, **regend; + + /* If a group that's operated upon by a repetition operator fails to + match anything, then the register for its start will need to be + restored because it will have been set to wherever in the string we + are when we last see its open-group operator. Similarly for a + register's end. */ + const char **old_regstart, **old_regend; + + /* The is_active field of reg_info helps us keep track of which (possibly + nested) subexpressions we are currently in. The matched_something + field of reg_info[reg_num] helps us tell whether or not we have + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ + register_info_type *reg_info; + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + unsigned best_regs_set = false; + const char **best_regstart, **best_regend; + + /* Logically, this is `best_regend[0]'. But we don't want to have to + allocate space for that if we're not allocating space for anything + else (see below). Also, we never need info about register 0 for + any of the other register vectors, and it seems rather a kludge to + treat `best_regend' differently than the rest. So we keep track of + the end of the best match so far in a separate variable. We + initialize this to NULL so that when we backtrack the first time + and need to test it, it's not garbage. */ + const char *match_end = NULL; + + /* Used when we pop values we don't care about. */ + const char **reg_dummy; + register_info_type *reg_info_dummy; + +#ifdef DEBUG + /* Counts the total number of registers pushed. */ + unsigned num_regs_pushed = 0; +#endif + + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); + + INIT_FAIL_STACK (); + + /* Do not bother to initialize all the register variables if there are + no groups in the pattern, as it takes a fair amount of time. If + there are groups, we include space for register 0 (the whole + pattern), even though we never use it, since it simplifies the + array indexing. We should fix this. */ + if (bufp->re_nsub) + { + regstart = REGEX_TALLOC (num_regs, const char *); + regend = REGEX_TALLOC (num_regs, const char *); + old_regstart = REGEX_TALLOC (num_regs, const char *); + old_regend = REGEX_TALLOC (num_regs, const char *); + best_regstart = REGEX_TALLOC (num_regs, const char *); + best_regend = REGEX_TALLOC (num_regs, const char *); + reg_info = REGEX_TALLOC (num_regs, register_info_type); + reg_dummy = REGEX_TALLOC (num_regs, const char *); + reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); + + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } + } +#ifdef REGEX_MALLOC + else + { + /* We must initialize all our variables to NULL, so that + `FREE_VARIABLES' doesn't try to free them. */ + regstart = regend = old_regstart = old_regend = best_regstart + = best_regend = reg_dummy = NULL; + reg_info = reg_info_dummy = (register_info_type *) NULL; + } +#endif /* REGEX_MALLOC */ + + /* The starting position is bogus. */ + if (pos < 0 || pos > size1 + size2) + { + FREE_VARIABLES (); + return -1; + } + + /* Initialize subexpression text positions to -1 to mark ones that no + start_memory/stop_memory has been seen for. Also initialize the + register information struct. */ + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + /* We move `string1' into `string2' if the latter's empty -- but not if + `string1' is null. */ + if (size2 == 0 && string1 != NULL) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ + if (stop <= size1) + { + end_match_1 = string1 + stop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + stop - size1; + } + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. `d' + is advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal `string2'. */ + if (size1 > 0 && pos <= size1) + { + d = string1 + pos; + dend = end_match_1; + } + else + { + d = string2 + pos - size1; + dend = end_match_2; + } + + DEBUG_PRINT1 ("The compiled pattern is: "); + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); + DEBUG_PRINT1 ("The string to match is: `"); + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); + DEBUG_PRINT1 ("'\n"); + + /* This loops over pattern commands. It exits by returning from the + function if the match is complete, or it drops through if the match + fails at this starting point in the input data. */ + for (;;) + { + DEBUG_PRINT2 ("\n0x%x: ", p); + + if (p == pend) + { /* End of pattern means we might have succeeded. */ + DEBUG_PRINT1 ("end of pattern ... "); + + /* If we haven't matched the entire string, and we want the + longest match, try backtracking. */ + if (d != end_match_2) + { + DEBUG_PRINT1 ("backtracking.\n"); + + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); + + /* If exceeds best match so far, save it. */ + if (!best_regs_set + || (same_str_p && d > match_end) + || (!same_str_p && !MATCHING_IN_FIRST_STRING)) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. */ + else if (best_regs_set) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } /* d != end_match_2 */ + + DEBUG_PRINT1 ("Accepting match.\n"); + + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) + { + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + } + } + else + assert (bufp->regs_allocated == REGS_FIXED); + + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1 + : d - string2 + size1); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ + for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++) + { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { + regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]); + regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]); + } + } + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + } /* regs && !bufp->no_sub */ + + FREE_VARIABLES (); + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 + : string2 - size1); + + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + + return mcnt; + } + + /* Otherwise match next pattern command. */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((re_opcode_t) *p++)) +#else + switch ((re_opcode_t) *p++) +#endif + { + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; + + + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ + case exactn: + mcnt = *p++; + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + PREFETCH (); + if (translate[(unsigned char) *d++] != (char) *p++) + goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH (); + if (*d++ != (char) *p++) goto fail; + } + while (--mcnt); + } + SET_REGS_MATCHED (); + break; + + + /* Match any character except possibly a newline or a null. */ + case anychar: + DEBUG_PRINT1 ("EXECUTING anychar.\n"); + + PREFETCH (); + + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + goto fail; + + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d++; + break; + + + case charset: + case charset_not: + { + register unsigned char c; + boolean not = (re_opcode_t) *(p - 1) == charset_not; + + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + + PREFETCH (); + c = TRANSLATE (*d); /* The character to match. */ + + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ + if (c < (unsigned) (*p * BYTEWIDTH) + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + + SET_REGS_MATCHED (); + d++; + break; + } + + + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: + DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); + + /* Find out if this group can match the empty string. */ + p1 = p; /* To send to group_match_null_string_p. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", + POINTER_TO_OFFSET (old_regstart[*p])); + + regstart[*p] = d; + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); + + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + break; + + + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ + case stop_memory: + DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] + : regend[*p]; + DEBUG_PRINT2 (" old_regend: %d\n", + POINTER_TO_OFFSET (old_regend[*p])); + + regend[*p] = d; + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); + + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + unsigned char r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ + if (r == 0) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || (re_opcode_t) p[-3] == start_memory) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: + is_a_jump_n = true; + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (is_a_jump_n) + p1 += 2; + break; + + default: + /* do nothing */ ; + } + p1 += mcnt; + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) + { + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) + { + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Restore this and inner groups' (if any) registers. */ + for (r = *p; r < *p + *(p + 1); r++) + { + regstart[r] = old_regstart[r]; + + /* xx why this test? */ + if ((int) old_regend[r] >= (int) regstart[r]) + regend[r] = old_regend[r]; + } + } + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; + + + /* \ has been turned into a `duplicate' command which is + followed by the numeric value of as the register number. */ + case duplicate: + { + register const char *d2, *dend2; + int regno = *p++; /* Get which register to match against. */ + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); + + /* Can't back reference a group which we've never matched. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) + == FIRST_STRING_P (regend[regno])) + ? regend[regno] : end_match_1); + for (;;) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH (); + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? bcmp_translate (d, d2, mcnt, translate) + : bcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ + case begline: + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; + + + /* endline is the dual of begline. */ + case endline: + DEBUG_PRINT1 ("EXECUTING endline.\n"); + + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; + + + /* Match at the very beginning of the data. */ + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; + + + /* Match at the very end of the data. */ + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + if (AT_STRINGS_END (d)) + break; + goto fail; + + + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. + + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; + + + /* Uses of on_failure_jump: + + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ + case on_failure_jump: + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); + + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(\(a*\)b*\)\2, we need the inner group. */ + + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; + + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; + + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } + + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; + + + /* A smart repeat ends with `maybe_pop_jump'. + We change it to either `pop_failure_jump' or `jump'. */ + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { + register unsigned char *p2 = p; + + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ + + /* Skip over open/close-group commands. */ + while (p2 + 2 < pend + && ((re_opcode_t) *p2 == stop_memory + || (re_opcode_t) *p2 == start_memory)) + p2 += 3; /* Skip over args, too. */ + + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) + { + /* Consider what happens when matching ":\(.*\)" + against ":/". I don't really understand this code + yet. */ + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } + + else if ((re_opcode_t) *p2 == exactn + || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) + { + register unsigned char c + = *p2 == (unsigned char) endline ? '\n' : p2[2]; + p1 = p + mcnt; + + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + if ((re_opcode_t) p1[3] == exactn && p1[5] != c) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + + else if ((re_opcode_t) p1[3] == charset + || (re_opcode_t) p1[3] == charset_not) + { + int not = (re_opcode_t) p1[3] == charset_not; + + if (c < (unsigned char) (p1[4] * BYTEWIDTH) + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ + if (!not) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + } + p -= 2; /* Point at relative address again. */ + if ((re_opcode_t) p[-1] != pop_failure_jump) + { + p[-1] = (unsigned char) jump; + DEBUG_PRINT1 (" Match => jump.\n"); + goto unconditional_jump; + } + /* Note fall through. */ + + + /* The end of a simple repeat has a pop_failure_jump back to + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + unsigned dummy_low_reg, dummy_high_reg; + unsigned char *pdummy; + const char *sdummy; + + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ + + + /* Unconditionally jump (without popping any failure points). */ + case jump: + unconditional_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + p += mcnt; /* Do the jump. */ + DEBUG_PRINT2 ("(to 0x%x).\n", p); + break; + + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; + + + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (0, 0, -2); + goto unconditional_jump; + + + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (0, 0, -2); + break; + + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; + p += 2; + STORE_NUMBER_AND_INCR (p, mcnt); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); + } + else if (mcnt == 0) + { + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); + p[2] = (unsigned char) no_op; + p[3] = (unsigned char) no_op; + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + 2, mcnt); + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + case set_number_at: + { + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); + STORE_NUMBER (p1, mcnt); + break; + } + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; + + case notwordbound: + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + goto fail; + break; + + case wordbeg: + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) + break; + goto fail; + + case wordend: + DEBUG_PRINT1 ("EXECUTING wordend.\n"); + if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) + && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) + break; + goto fail; + +#ifdef emacs +#ifdef emacs19 + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; +#else /* not emacs19 */ + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point) + goto fail; + break; +#endif /* not emacs19 */ + + case syntaxspec: + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchsyntax; + + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + mcnt = (int) Sword; + matchsyntax: + PREFETCH (); + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + + case notsyntaxspec: + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchnotsyntax; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + mcnt = (int) Sword; + matchnotsyntax: + PREFETCH (); + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + +#else /* not emacs */ + case wordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + PREFETCH (); + if (!WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + PREFETCH (); + if (WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; +#endif /* not emacs */ + + default: + abort (); + } + continue; /* Successfully executed one pattern command; keep going. */ + + + /* We goto here if a matching operation fails. */ + fail: + if (!FAIL_STACK_EMPTY ()) + { /* A restart point is known. Restore to that state. */ + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); + + /* If this failure point is a dummy, try the next one. */ + if (!p) + goto fail; + + /* If we failed to the end of the pattern, don't examine *p. */ + assert (p <= pend); + if (p < pend) + { + boolean is_a_jump_n = false; + + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else + break; /* Matching at this starting point really fails. */ + } /* for (;;) */ + + if (best_regs_set) + goto restore_best_regs; + + FREE_VARIABLES (); + + return -1; /* Failure to match. */ +} /* re_match_2 */ + +/* Subroutine definitions for re_match_2. */ + + +/* We are passed P pointing to a register number after a start_memory. + + Return true if the pattern up to the corresponding stop_memory can + match the empty string, and false otherwise. + + If we find the matching stop_memory, sets P to point to one past its number. + Otherwise, sets P to an undefined byte less than or equal to END. + + We don't handle duplicates properly (yet). */ + +static boolean +group_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + /* Point to after the args to the start_memory. */ + unsigned char *p1 = *p + 2; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and return true or + false, as appropriate, when we get to one that can't, or to the + matching stop_memory. */ + + switch ((re_opcode_t) *p1) + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the + pattern. */ + + if (mcnt >= 0) + { + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': + + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c + + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ + + + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ + + while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ + + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return false; + + /* Move to right after this alternative, including the + jump_past_alt. */ + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; + + /* Still have to check that it's not an n-th + alternative that starts with an on_failure_jump. */ + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) + { + /* Get to the beginning of the n-th alternative. */ + p1 -= 3; + break; + } + } + + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); + + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return false; + + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; + + + case stop_memory: + assert (p1[1] == **p); + *p = p1 + 2; + return true; + + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return false; +} /* group_match_null_string_p */ + + +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: + It expects P to be the first byte of a single alternative and END one + byte past the last. The alternative can contain groups. */ + +static boolean +alt_match_null_string_p (p, end, reg_info) + unsigned char *p, *end; + register_info_type *reg_info; +{ + int mcnt; + unsigned char *p1 = p; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + + switch ((re_opcode_t) *p1) + { + /* It's a loop. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return true; +} /* alt_match_null_string_p */ + + +/* Deals with the ops common to group_match_null_string_p and + alt_match_null_string_p. + + Sets P to one after the op and its arguments, if any. */ + +static boolean +common_op_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + boolean ret; + int reg_no; + unsigned char *p1 = *p; + + switch ((re_opcode_t) *p1++) + { + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbeg: + case wordend: + case wordbound: + case notwordbound: +#ifdef emacs + case before_dot: + case at_dot: + case after_dot: +#endif + break; + + case start_memory: + reg_no = *p1; + assert (reg_no > 0 && reg_no <= MAX_REGNUM); + ret = group_match_null_string_p (&p1, end, reg_info); + + /* Have to set this here in case we're checking a group which + contains a group and a back reference to it. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + + if (!ret) + return false; + break; + + /* If this is an optimized succeed_n for zero times, make the jump. */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (mcnt >= 0) + p1 += mcnt; + else + return false; + break; + + case succeed_n: + /* Get to the number of times to succeed. */ + p1 += 2; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + if (mcnt == 0) + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } + else + return false; + break; + + case duplicate: + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) + return false; + break; + + case set_number_at: + p1 += 4; + + default: + /* All other opcodes mean we cannot match the empty string. */ + return false; + } + + *p = p1; + return true; +} /* common_op_match_null_string_p */ + + +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN + bytes; nonzero otherwise. */ + +static int +bcmp_translate (s1, s2, len, translate) + unsigned char *s1, *s2; + register int len; + char *translate; +{ + register unsigned char *p1 = s1, *p2 = s2; + while (len) + { + if (translate[*p1++] != translate[*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length SIZE) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. + + We call regex_compile to do the actual compilation. */ + +const char * +re_compile_pattern (pattern, length, bufp) + const char *pattern; + int length; + struct re_pattern_buffer *bufp; +{ + reg_errcode_t ret; + + /* GNU code is written to assume at least RE_NREGS registers will be set + (and at least one extra will be -1). */ + bufp->regs_allocated = REGS_UNALLOCATED; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub. */ + bufp->no_sub = 0; + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + + ret = regex_compile (pattern, length, re_syntax_options, bufp); + + return re_error_msg[(int) ret]; +} + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them if this is an Emacs or POSIX compilation. */ + +#if !defined (emacs) && !defined (_POSIX_SOURCE) + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + const char *s; +{ + reg_errcode_t ret; + + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + re_comp_buf.buffer = (unsigned char *) malloc (200); + if (re_comp_buf.buffer == NULL) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); + if (re_comp_buf.fastmap == NULL) + return "Memory exhausted"; + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + /* Match anchors at newlines. */ + re_comp_buf.newline_anchor = 1; + + ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + + /* Yes, we're discarding `const' here. */ + return (char *) re_error_msg[(int) ret]; +} + + +int +re_exec (s) + const char *s; +{ + const int len = strlen (s); + return + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); +} +#endif /* not emacs and not _POSIX_SOURCE */ + +/* POSIX.2 functions. Don't define these for Emacs. */ + +#ifndef emacs + +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `newline_anchor' to REG_NEWLINE being set in CFLAGS; + `fastmap' and `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (preg, pattern, cflags) + regex_t *preg; + const char *pattern; + int cflags; +{ + reg_errcode_t ret; + unsigned syntax + = (cflags & REG_EXTENDED) ? + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; + + /* regex_compile will allocate the space for the compiled pattern. */ + preg->buffer = 0; + preg->allocated = 0; + + /* Don't bother to use a fastmap when searching. This simplifies the + REG_NEWLINE case: if we used a fastmap, we'd have to put all the + characters after newlines into the fastmap. This way, we just try + every character. */ + preg->fastmap = 0; + + if (cflags & REG_ICASE) + { + unsigned i; + + preg->translate = (char *) malloc (CHAR_SET_SIZE); + if (preg->translate == NULL) + return (int) REG_ESPACE; + + /* Map uppercase characters to corresponding lowercase ones. */ + for (i = 0; i < CHAR_SET_SIZE; i++) + preg->translate[i] = ISUPPER (i) ? tolower (i) : i; + } + else + preg->translate = NULL; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } + else + preg->newline_anchor = 0; + + preg->no_sub = !!(cflags & REG_NOSUB); + + /* POSIX says a null character in the pattern terminates it, so we + can use strlen here in compiling the pattern. */ + ret = regex_compile (pattern, strlen (pattern), syntax, preg); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) ret = REG_EPAREN; + + return (int) ret; +} + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (preg, string, nmatch, pmatch, eflags) + const regex_t *preg; + const char *string; + size_t nmatch; + regmatch_t pmatch[]; + int eflags; +{ + int ret; + struct re_registers regs; + regex_t private_preg; + int len = strlen (string); + boolean want_reg_info = !preg->no_sub && nmatch > 0; + + private_preg = *preg; + + private_preg.not_bol = !!(eflags & REG_NOTBOL); + private_preg.not_eol = !!(eflags & REG_NOTEOL); + + /* The user has told us exactly how many registers to return + information about, via `nmatch'. We have to pass that on to the + matching routines. */ + private_preg.regs_allocated = REGS_FIXED; + + if (want_reg_info) + { + regs.num_regs = nmatch; + regs.start = TALLOC (nmatch, regoff_t); + regs.end = TALLOC (nmatch, regoff_t); + if (regs.start == NULL || regs.end == NULL) + return (int) REG_NOMATCH; + } + + /* Perform the searching operation. */ + ret = re_search (&private_preg, string, len, + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + + /* Copy the register information to the POSIX structure. */ + if (want_reg_info) + { + if (ret >= 0) + { + unsigned r; + + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } + + /* If we needed the temporary register info, free the space now. */ + free (regs.start); + free (regs.end); + } + + /* We want zero return to mean success, unlike `re_search'. */ + return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; +} + + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (errcode, preg, errbuf, errbuf_size) + int errcode; + const regex_t *preg; + char *errbuf; + size_t errbuf_size; +{ + const char *msg; + size_t msg_size; + + if (errcode < 0 + || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0]))) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { + strncpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; + } + else + strcpy (errbuf, msg); + } + + return msg_size; +} + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (preg) + regex_t *preg; +{ + if (preg->buffer != NULL) + free (preg->buffer); + preg->buffer = NULL; + + preg->allocated = 0; + preg->used = 0; + + if (preg->fastmap != NULL) + free (preg->fastmap); + preg->fastmap = NULL; + preg->fastmap_accurate = 0; + + if (preg->translate != NULL) + free (preg->translate); + preg->translate = NULL; +} + +#endif /* not emacs */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ diff --git a/gnu/usr.bin/tar/regex.h b/gnu/usr.bin/tar/regex.h new file mode 100644 index 0000000000..0840861da3 --- /dev/null +++ b/gnu/usr.bin/tar/regex.h @@ -0,0 +1,490 @@ +/* Definitions for data structures and routines for the regular + expression library, version 0.11. + + Copyright (C) 1985, 89, 90, 91, 92 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the 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 must be included (by the caller) before + . */ + +#ifdef VMS +/* VMS doesn't have `size_t' in , even though POSIX says it + should be there. */ +#include +#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 \ matches . + If not set, then \ 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/tar/rmt.h b/gnu/usr.bin/tar/rmt.h new file mode 100644 index 0000000000..2155223954 --- /dev/null +++ b/gnu/usr.bin/tar/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 +#endif + +#if !defined(_POSIX_VERSION) +#ifdef __MSDOS__ +#include +#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 +#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/tar/rtapelib.c b/gnu/usr.bin/tar/rtapelib.c new file mode 100644 index 0000000000..eece76ffcd --- /dev/null +++ b/gnu/usr.bin/tar/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 +#include +#include + +#ifdef HAVE_SYS_MTIO_H +#include +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#include +#include +#include + +#ifndef errno +extern int errno; +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef STDC_HEADERS +#include +#include +#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/tar/tar.c b/gnu/usr.bin/tar/tar.c new file mode 100644 index 0000000000..9382582339 --- /dev/null +++ b/gnu/usr.bin/tar/tar.c @@ -0,0 +1,1504 @@ +/* Tar -- a tape archiver. + Copyright (C) 1988, 1992, 1993 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * A tar (tape archiver) program. + * + * Written by John Gilmore, ihnp4!hoptoad!gnu, starting 25 Aug 85. + */ + +#include +#include /* Needed for typedefs in tar.h */ +#include "getopt.h" + +/* + * The following causes "tar.h" to produce definitions of all the + * global variables, rather than just "extern" declarations of them. + */ +#define TAR_EXTERN /**/ +#include "tar.h" + +#include "port.h" +#include "regex.h" +#include "fnmatch.h" + +/* + * We should use a conversion routine that does reasonable error + * checking -- atoi doesn't. For now, punt. FIXME. + */ +#define intconv atoi +PTR ck_malloc (); +PTR ck_realloc (); +extern int getoldopt (); +extern void read_and (); +extern void list_archive (); +extern void extract_archive (); +extern void diff_archive (); +extern void create_archive (); +extern void update_archive (); +extern void junk_archive (); +extern void init_volume_number (); +extern void closeout_volume_number (); + +/* JF */ +extern time_t get_date (); + +time_t new_time; + +static FILE *namef; /* File to read names from */ +static char **n_argv; /* Argv used by name routines */ +static int n_argc; /* Argc used by name routines */ +static char **n_ind; /* Store an array of names */ +static int n_indalloc; /* How big is the array? */ +static int n_indused; /* How many entries does it have? */ +static int n_indscan; /* How many of the entries have we scanned? */ + + +extern FILE *msg_file; + +int check_exclude (); +void add_exclude (); +void add_exclude_file (); +void addname (); +void describe (); +void diff_init (); +void extr_init (); +int is_regex (); +void name_add (); +void name_init (); +void options (); +char *un_quote_string (); + +#ifndef S_ISLNK +#define lstat stat +#endif + +#ifndef DEFBLOCKING +#define DEFBLOCKING 20 +#endif + +#ifndef DEF_AR_FILE +#define DEF_AR_FILE "tar.out" +#endif + +/* For long options that unconditionally set a single flag, we have getopt + do it. For the others, we share the code for the equivalent short + named option, the name of which is stored in the otherwise-unused `val' + field of the `struct option'; for long options that have no equivalent + short option, we use nongraphic characters as pseudo short option + characters, starting (for no particular reason) with character 10. */ + +struct option long_options[] = +{ + {"create", 0, 0, 'c'}, + {"append", 0, 0, 'r'}, + {"extract", 0, 0, 'x'}, + {"get", 0, 0, 'x'}, + {"list", 0, 0, 't'}, + {"update", 0, 0, 'u'}, + {"catenate", 0, 0, 'A'}, + {"concatenate", 0, 0, 'A'}, + {"compare", 0, 0, 'd'}, + {"diff", 0, 0, 'd'}, + {"delete", 0, 0, 14}, + {"help", 0, 0, 12}, + + {"null", 0, 0, 16}, + {"directory", 1, 0, 'C'}, + {"record-number", 0, &f_sayblock, 1}, + {"files-from", 1, 0, 'T'}, + {"label", 1, 0, 'V'}, + {"exclude-from", 1, 0, 'X'}, + {"exclude", 1, 0, 15}, + {"file", 1, 0, 'f'}, + {"block-size", 1, 0, 'b'}, + {"version", 0, 0, 11}, + {"verbose", 0, 0, 'v'}, + {"totals", 0, &f_totals, 1}, + + {"read-full-blocks", 0, &f_reblock, 1}, + {"starting-file", 1, 0, 'K'}, + {"to-stdout", 0, &f_exstdout, 1}, + {"ignore-zeros", 0, &f_ignorez, 1}, + {"keep-old-files", 0, 0, 'k'}, + {"same-permissions", 0, &f_use_protection, 1}, + {"preserve-permissions", 0, &f_use_protection, 1}, + {"modification-time", 0, &f_modified, 1}, + {"preserve", 0, 0, 10}, + {"same-order", 0, &f_sorted_names, 1}, + {"same-owner", 0, &f_do_chown, 1}, + {"preserve-order", 0, &f_sorted_names, 1}, + + {"newer", 1, 0, 'N'}, + {"after-date", 1, 0, 'N'}, + {"newer-mtime", 1, 0, 13}, + {"incremental", 0, 0, 'G'}, + {"listed-incremental", 1, 0, 'g'}, + {"multi-volume", 0, &f_multivol, 1}, + {"info-script", 1, 0, 'F'}, + {"new-volume-script", 1, 0, 'F'}, + {"absolute-paths", 0, &f_absolute_paths, 1}, + {"interactive", 0, &f_confirm, 1}, + {"confirmation", 0, &f_confirm, 1}, + + {"verify", 0, &f_verify, 1}, + {"dereference", 0, &f_follow_links, 1}, + {"one-file-system", 0, &f_local_filesys, 1}, + {"old-archive", 0, 0, 'o'}, + {"portability", 0, 0, 'o'}, + {"compress", 0, 0, 'Z'}, + {"uncompress", 0, 0, 'Z'}, + {"block-compress", 0, &f_compress_block, 1}, + {"gzip", 0, 0, 'z'}, + {"ungzip", 0, 0, 'z'}, + {"use-compress-program", 1, 0, 18}, + + + {"same-permissions", 0, &f_use_protection, 1}, + {"sparse", 0, &f_sparse_files, 1}, + {"tape-length", 1, 0, 'L'}, + {"remove-files", 0, &f_remove_files, 1}, + {"ignore-failed-read", 0, &f_ignore_failed_read, 1}, + {"checkpoint", 0, &f_checkpoint, 1}, + {"show-omitted-dirs", 0, &f_show_omitted_dirs, 1}, + {"volno-file", 1, 0, 17}, + {"force-local", 0, &f_force_local, 1}, + {"atime-preserve", 0, &f_atime_preserve, 1}, + + {0, 0, 0, 0} +}; + +/* + * Main routine for tar. + */ +void +main (argc, argv) + int argc; + char **argv; +{ + extern char version_string[]; + + tar = argv[0]; /* JF: was "tar" Set program name */ + filename_terminator = '\n'; + errors = 0; + + options (argc, argv); + + if (!n_argv) + name_init (argc, argv); + + if (f_volno_file) + init_volume_number (); + + switch (cmd_mode) + { + case CMD_CAT: + case CMD_UPDATE: + case CMD_APPEND: + update_archive (); + break; + case CMD_DELETE: + junk_archive (); + break; + case CMD_CREATE: + create_archive (); + if (f_totals) + fprintf (stderr, "Total bytes written: %d\n", tot_written); + break; + case CMD_EXTRACT: + if (f_volhdr) + { + const char *err; + label_pattern = (struct re_pattern_buffer *) + ck_malloc (sizeof *label_pattern); + err = re_compile_pattern (f_volhdr, strlen (f_volhdr), + label_pattern); + if (err) + { + fprintf (stderr, "Bad regular expression: %s\n", + err); + errors++; + break; + } + + } + extr_init (); + read_and (extract_archive); + break; + case CMD_LIST: + if (f_volhdr) + { + const char *err; + label_pattern = (struct re_pattern_buffer *) + ck_malloc (sizeof *label_pattern); + err = re_compile_pattern (f_volhdr, strlen (f_volhdr), + label_pattern); + if (err) + { + fprintf (stderr, "Bad regular expression: %s\n", + err); + errors++; + break; + } + } + read_and (list_archive); +#if 0 + if (!errors) + errors = different; +#endif + break; + case CMD_DIFF: + diff_init (); + read_and (diff_archive); + break; + case CMD_VERSION: + fprintf (stderr, "%s\n", version_string); + break; + case CMD_NONE: + msg ("you must specify exactly one of the r, c, t, x, or d options\n"); + fprintf (stderr, "For more information, type ``%s --help''.\n", tar); + exit (EX_ARGSBAD); + } + if (f_volno_file) + closeout_volume_number (); + exit (errors); + /* NOTREACHED */ +} + + +/* + * Parse the options for tar. + */ +void +options (argc, argv) + int argc; + char **argv; +{ + register int c; /* Option letter */ + int ind = -1; + + /* Set default option values */ + blocking = DEFBLOCKING; /* From Makefile */ + ar_files = (char **) ck_malloc (sizeof (char *) * 10); + ar_files_len = 10; + n_ar_files = 0; + cur_ar_file = 0; + + /* Parse options */ + while ((c = getoldopt (argc, argv, + "-01234567Ab:BcC:df:F:g:GhikK:lL:mMN:oOpPrRsStT:uvV:wWxX:zZ", + long_options, &ind)) != EOF) + { + switch (c) + { + case 0: /* long options that set a single flag */ + break; + case 1: + /* File name or non-parsed option */ + name_add (optarg); + break; + case 'C': + name_add ("-C"); + name_add (optarg); + break; + case 10: /* preserve */ + f_use_protection = f_sorted_names = 1; + break; + case 11: + if (cmd_mode != CMD_NONE) + goto badopt; + cmd_mode = CMD_VERSION; + break; + case 12: /* help */ + printf ("This is GNU tar, the tape archiving program.\n"); + describe (); + exit (1); + case 13: + f_new_files++; + goto get_newer; + + case 14: /* Delete in the archive */ + if (cmd_mode != CMD_NONE) + goto badopt; + cmd_mode = CMD_DELETE; + break; + + case 15: + f_exclude++; + add_exclude (optarg); + break; + + case 16: /* -T reads null terminated filenames. */ + filename_terminator = '\0'; + break; + + case 17: + f_volno_file = optarg; + break; + + case 18: + if (f_compressprog) + { + msg ("Only one compression option permitted\n"); + exit (EX_ARGSBAD); + } + f_compressprog = optarg; + break; + + case 'g': /* We are making a GNU dump; save + directories at the beginning of + the archive, and include in each + directory its contents */ + if (f_oldarch) + goto badopt; + f_gnudump++; + gnu_dumpfile = optarg; + break; + + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + /* JF this'll have to be modified for other + systems, of course! */ + int d, add; + static char buf[50]; + + d = getoldopt (argc, argv, "lmh"); +#ifdef MAYBEDEF + sprintf (buf, "/dev/rmt/%d%c", c, d); +#else +#ifndef LOW_NUM +#define LOW_NUM 0 +#define MID_NUM 8 +#define HGH_NUM 16 +#endif + if (d == 'l') + add = LOW_NUM; + else if (d == 'm') + add = MID_NUM; + else if (d == 'h') + add = HGH_NUM; + else + goto badopt; + + sprintf (buf, "/dev/rmt%d", add + c - '0'); +#endif + if (n_ar_files == ar_files_len) + ar_files + = (char **) + ck_malloc (sizeof (char *) + * (ar_files_len *= 2)); + ar_files[n_ar_files++] = buf; + } + break; + + case 'A': /* Arguments are tar files, + just cat them onto the end + of the archive. */ + if (cmd_mode != CMD_NONE) + goto badopt; + cmd_mode = CMD_CAT; + break; + + case 'b': /* Set blocking factor */ + blocking = intconv (optarg); + break; + + case 'B': /* Try to reblock input */ + f_reblock++; /* For reading 4.2BSD pipes */ + break; + + case 'c': /* Create an archive */ + if (cmd_mode != CMD_NONE) + goto badopt; + cmd_mode = CMD_CREATE; + break; + +#if 0 + case 'C': + if (chdir (optarg) < 0) + msg_perror ("Can't change directory to %d", optarg); + break; +#endif + + case 'd': /* Find difference tape/disk */ + if (cmd_mode != CMD_NONE) + goto badopt; + cmd_mode = CMD_DIFF; + break; + + case 'f': /* Use ar_file for the archive */ + if (n_ar_files == ar_files_len) + ar_files + = (char **) ck_malloc (sizeof (char *) + * (ar_files_len *= 2)); + + ar_files[n_ar_files++] = optarg; + break; + + case 'F': + /* Since -F is only useful with -M , make it implied */ + f_run_script_at_end++;/* run this script at the end */ + info_script = optarg; /* of each tape */ + f_multivol++; + break; + + case 'G': /* We are making a GNU dump; save + directories at the beginning of + the archive, and include in each + directory its contents */ + if (f_oldarch) + goto badopt; + f_gnudump++; + gnu_dumpfile = 0; + break; + + case 'h': + f_follow_links++; /* follow symbolic links */ + break; + + case 'i': + f_ignorez++; /* Ignore zero records (eofs) */ + /* + * This can't be the default, because Unix tar + * writes two records of zeros, then pads out the + * block with garbage. + */ + break; + + case 'k': /* Don't overwrite files */ +#ifdef NO_OPEN3 + msg ("can't keep old files on this system"); + exit (EX_ARGSBAD); +#else + f_keep++; +#endif + break; + + case 'K': + f_startfile++; + addname (optarg); + break; + + case 'l': /* When dumping directories, don't + dump files/subdirectories that are + on other filesystems. */ + f_local_filesys++; + break; + + case 'L': + tape_length = intconv (optarg); + f_multivol++; + break; + case 'm': + f_modified++; + break; + + case 'M': /* Make Multivolume archive: + When we can't write any more + into the archive, re-open it, + and continue writing */ + f_multivol++; + break; + + case 'N': /* Only write files newer than X */ + get_newer: + f_new_files++; + new_time = get_date (optarg, (PTR) 0); + if (new_time == (time_t) - 1) + { + msg ("invalid date format `%s'", optarg); + exit (EX_ARGSBAD); + } + break; + + case 'o': /* Generate old archive */ + if (f_gnudump /* || f_dironly */ ) + goto badopt; + f_oldarch++; + break; + + case 'O': + f_exstdout++; + break; + + case 'p': + f_use_protection++; + break; + + case 'P': + f_absolute_paths++; + break; + + case 'r': /* Append files to the archive */ + if (cmd_mode != CMD_NONE) + goto badopt; + cmd_mode = CMD_APPEND; + break; + + case 'R': + f_sayblock++; /* Print block #s for debug */ + break; /* of bad tar archives */ + + case 's': + f_sorted_names++; /* Names to extr are sorted */ + break; + + case 'S': /* deal with sparse files */ + f_sparse_files++; + break; + case 't': + if (cmd_mode != CMD_NONE) + goto badopt; + cmd_mode = CMD_LIST; + f_verbose++; /* "t" output == "cv" or "xv" */ + break; + + case 'T': + name_file = optarg; + f_namefile++; + break; + + case 'u': /* Append files to the archive that + aren't there, or are newer than the + copy in the archive */ + if (cmd_mode != CMD_NONE) + goto badopt; + cmd_mode = CMD_UPDATE; + break; + + case 'v': + f_verbose++; + break; + + case 'V': + f_volhdr = optarg; + break; + + case 'w': + f_confirm++; + break; + + case 'W': + f_verify++; + break; + + case 'x': /* Extract files from the archive */ + if (cmd_mode != CMD_NONE) + goto badopt; + cmd_mode = CMD_EXTRACT; + break; + + case 'X': + f_exclude++; + add_exclude_file (optarg); + break; + + case 'z': + if (f_compressprog) + { + msg ("Only one compression option permitted\n"); + exit (EX_ARGSBAD); + } + f_compressprog = "gzip"; + break; + + case 'Z': + if (f_compressprog) + { + msg ("Only one compression option permitted\n"); + exit (EX_ARGSBAD); + } + f_compressprog = "compress"; + break; + + case '?': + badopt: + msg ("Unknown option. Use '%s --help' for a complete list of options.", tar); + exit (EX_ARGSBAD); + + } + } + + blocksize = blocking * RECORDSIZE; + if (n_ar_files == 0) + { + n_ar_files = 1; + ar_files[0] = getenv ("TAPE"); /* From environment, or */ + if (ar_files[0] == 0) + ar_files[0] = DEF_AR_FILE; /* From Makefile */ + } + if (n_ar_files > 1 && !f_multivol) + { + msg ("Multiple archive files requires --multi-volume\n"); + exit (EX_ARGSBAD); + } + if (f_compress_block && !f_compressprog) + { + msg ("You must use a compression option (--gzip, --compress\n\ +or --use-compress-program) with --block-compress.\n"); + exit (EX_ARGSBAD); + } +} + + +/* + * Print as much help as the user's gonna get. + * + * We have to sprinkle in the KLUDGE lines because too many compilers + * cannot handle character strings longer than about 512 bytes. Yuk! + * In particular, MS-DOS and Xenix MSC and PDP-11 V7 Unix have this + * problem. + */ +void +describe () +{ + puts ("choose one of the following:"); + fputs ("\ +-A, --catenate,\n\ + --concatenate append tar files to an archive\n\ +-c, --create create a new archive\n\ +-d, --diff,\n\ + --compare find differences between archive and file system\n\ +--delete delete from the archive (not for use on mag tapes!)\n\ +-r, --append append files to the end of an archive\n\ +-t, --list list the contents of an archive\n\ +-u, --update only append files that are newer than copy in archive\n\ +-x, --extract,\n\ + --get extract files from an archive\n", stdout); + + fprintf (stdout, "\ +Other options:\n\ +--atime-preserve don't change access times on dumped files\n\ +-b, --block-size N block size of Nx512 bytes (default N=%d)\n", DEFBLOCKING); + fputs ("\ +-B, --read-full-blocks reblock as we read (for reading 4.2BSD pipes)\n\ +-C, --directory DIR change to directory DIR\n\ +--checkpoint print directory names while reading the archive\n\ +", stdout); /* KLUDGE */ + fprintf (stdout, "\ +-f, --file [HOSTNAME:]F use archive file or device F (default %s)\n", + DEF_AR_FILE); + fputs ("\ +--force-local archive file is local even if has a colon\n\ +-F, --info-script F\n\ + --new-volume-script F run script at end of each tape (implies -M)\n\ +-G, --incremental create/list/extract old GNU-format incremental backup\n\ +-g, --listed-incremental F create/list/extract new GNU-format incremental backup\n\ +-h, --dereference don't dump symlinks; dump the files they point to\n\ +-i, --ignore-zeros ignore blocks of zeros in archive (normally mean EOF)\n\ +--ignore-failed-read don't exit with non-zero status on unreadable files\n\ +-k, --keep-old-files keep existing files; don't overwrite them from archive\n\ +-K, --starting-file F begin at file F in the archive\n\ +-l, --one-file-system stay in local file system when creating an archive\n\ +-L, --tape-length N change tapes after writing N*1024 bytes\n\ +", stdout); /* KLUDGE */ + fputs ("\ +-m, --modification-time don't extract file modified time\n\ +-M, --multi-volume create/list/extract multi-volume archive\n\ +-N, --after-date DATE,\n\ + --newer DATE only store files newer than DATE\n\ +-o, --old-archive,\n\ + --portability write a V7 format archive, rather than ANSI format\n\ +-O, --to-stdout extract files to standard output\n\ +-p, --same-permissions,\n\ + --preserve-permissions extract all protection information\n\ +-P, --absolute-paths don't strip leading `/'s from file names\n\ +--preserve like -p -s\n\ +", stdout); /* KLUDGE */ + fputs ("\ +-R, --record-number show record number within archive with each message\n\ +--remove-files remove files after adding them to the archive\n\ +-s, --same-order,\n\ + --preserve-order list of names to extract is sorted to match archive\n\ +--same-owner create extracted files with the same ownership \n\ +-S, --sparse handle sparse files efficiently\n\ +-T, --files-from F get names to extract or create from file F\n\ +--null -T reads null-terminated names, disable -C\n\ +--totals print total bytes written with --create\n\ +-v, --verbose verbosely list files processed\n\ +-V, --label NAME create archive with volume name NAME\n\ +--version print tar program version number\n\ +-w, --interactive,\n\ + --confirmation ask for confirmation for every action\n\ +", stdout); /* KLUDGE */ + fputs ("\ +-W, --verify attempt to verify the archive after writing it\n\ +--exclude FILE exclude file FILE\n\ +-X, --exclude-from FILE exclude files listed in FILE\n\ +-Z, --compress,\n\ + --uncompress filter the archive through compress\n\ +-z, --gzip,\n\ + --ungzip filter the archive through gzip\n\ +--use-compress-program PROG\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\ +", stdout); +} + +void +name_add (name) + char *name; +{ + if (n_indalloc == n_indused) + { + n_indalloc += 10; + n_ind = (char **) (n_indused ? ck_realloc (n_ind, n_indalloc * sizeof (char *)): ck_malloc (n_indalloc * sizeof (char *))); + } + n_ind[n_indused++] = name; +} + +/* + * Set up to gather file names for tar. + * + * They can either come from stdin or from argv. + */ +void +name_init (argc, argv) + int argc; + char **argv; +{ + + if (f_namefile) + { + if (optind < argc) + { + msg ("too many args with -T option"); + exit (EX_ARGSBAD); + } + if (!strcmp (name_file, "-")) + { + namef = stdin; + } + else + { + namef = fopen (name_file, "r"); + if (namef == NULL) + { + msg_perror ("can't open file %s", name_file); + exit (EX_BADFILE); + } + } + } + else + { + /* Get file names from argv, after options. */ + n_argc = argc; + n_argv = argv; + } +} + +/* Read the next filename read from STREAM and null-terminate it. + Put it into BUFFER, reallocating and adjusting *PBUFFER_SIZE if necessary. + Return the new value for BUFFER, or NULL at end of file. */ + +char * +read_name_from_file (buffer, pbuffer_size, stream) + char *buffer; + size_t *pbuffer_size; + FILE *stream; +{ + register int c; + register int indx = 0; + register size_t buffer_size = *pbuffer_size; + + while ((c = getc (stream)) != EOF && c != filename_terminator) + { + if (indx == buffer_size) + { + buffer_size += NAMSIZ; + buffer = ck_realloc (buffer, buffer_size + 2); + } + buffer[indx++] = c; + } + if (indx == 0 && c == EOF) + return NULL; + if (indx == buffer_size) + { + buffer_size += NAMSIZ; + buffer = ck_realloc (buffer, buffer_size + 2); + } + buffer[indx] = '\0'; + *pbuffer_size = buffer_size; + return buffer; +} + +/* + * Get the next name from argv or the name file. + * + * Result is in static storage and can't be relied upon across two calls. + * + * If CHANGE_DIRS is non-zero, treat a filename of the form "-C" as + * meaning that the next filename is the name of a directory to change to. + * If `filename_terminator' is '\0', CHANGE_DIRS is effectively always 0. + */ + +char * +name_next (change_dirs) + int change_dirs; +{ + static char *buffer; /* Holding pattern */ + static int buffer_siz; + register char *p; + register char *q = 0; + register int next_name_is_dir = 0; + extern char *un_quote_string (); + + if (buffer_siz == 0) + { + buffer = ck_malloc (NAMSIZ + 2); + buffer_siz = NAMSIZ; + } + if (filename_terminator == '\0') + change_dirs = 0; +tryagain: + if (namef == NULL) + { + if (n_indscan < n_indused) + p = n_ind[n_indscan++]; + else if (optind < n_argc) + /* Names come from argv, after options */ + p = n_argv[optind++]; + else + { + if (q) + msg ("Missing filename after -C"); + return NULL; + } + + /* JF trivial support for -C option. I don't know if + chdir'ing at this point is dangerous or not. + It seems to work, which is all I ask. */ + if (change_dirs && !q && p[0] == '-' && p[1] == 'C' && p[2] == '\0') + { + q = p; + goto tryagain; + } + if (q) + { + if (chdir (p) < 0) + msg_perror ("Can't chdir to %s", p); + q = 0; + goto tryagain; + } + /* End of JF quick -C hack */ + +#if 0 + if (f_exclude && check_exclude (p)) + goto tryagain; +#endif + return un_quote_string (p); + } + while (p = read_name_from_file (buffer, &buffer_siz, namef)) + { + buffer = p; + if (*p == '\0') + continue; /* Ignore empty lines. */ + q = p + strlen (p) - 1; + while (q > p && *q == '/')/* Zap trailing "/"s. */ + *q-- = '\0'; + if (change_dirs && next_name_is_dir == 0 + && p[0] == '-' && p[1] == 'C' && p[2] == '\0') + { + next_name_is_dir = 1; + goto tryagain; + } + if (next_name_is_dir) + { + if (chdir (p) < 0) + msg_perror ("Can't change to directory %s", p); + next_name_is_dir = 0; + goto tryagain; + } +#if 0 + if (f_exclude && check_exclude (p)) + goto tryagain; +#endif + return un_quote_string (p); + } + return NULL; +} + + +/* + * Close the name file, if any. + */ +void +name_close () +{ + + if (namef != NULL && namef != stdin) + fclose (namef); +} + + +/* + * Gather names in a list for scanning. + * Could hash them later if we really care. + * + * If the names are already sorted to match the archive, we just + * read them one by one. name_gather reads the first one, and it + * is called by name_match as appropriate to read the next ones. + * At EOF, the last name read is just left in the buffer. + * This option lets users of small machines extract an arbitrary + * number of files by doing "tar t" and editing down the list of files. + */ +void +name_gather () +{ + register char *p; + static struct name *namebuf; /* One-name buffer */ + static namelen; + static char *chdir_name; + + if (f_sorted_names) + { + if (!namelen) + { + namelen = NAMSIZ; + namebuf = (struct name *) ck_malloc (sizeof (struct name) + NAMSIZ); + } + p = name_next (0); + if (p) + { + if (*p == '-' && p[1] == 'C' && p[2] == '\0') + { + chdir_name = name_next (0); + p = name_next (0); + if (!p) + { + msg ("Missing file name after -C"); + exit (EX_ARGSBAD); + } + namebuf->change_dir = chdir_name; + } + namebuf->length = strlen (p); + if (namebuf->length >= namelen) + { + namebuf = (struct name *) ck_realloc (namebuf, sizeof (struct name) + namebuf->length); + namelen = namebuf->length; + } + strncpy (namebuf->name, p, namebuf->length); + namebuf->name[namebuf->length] = 0; + namebuf->next = (struct name *) NULL; + namebuf->found = 0; + namelist = namebuf; + namelast = namelist; + } + return; + } + + /* Non sorted names -- read them all in */ + while (p = name_next (0)) + addname (p); +} + +/* + * Add a name to the namelist. + */ +void +addname (name) + char *name; /* pointer to name */ +{ + register int i; /* Length of string */ + register struct name *p; /* Current struct pointer */ + static char *chdir_name; + char *new_name (); + + if (name[0] == '-' && name[1] == 'C' && name[2] == '\0') + { + chdir_name = name_next (0); + name = name_next (0); + if (!chdir_name) + { + msg ("Missing file name after -C"); + exit (EX_ARGSBAD); + } + if (chdir_name[0] != '/') + { + char *path = ck_malloc (PATH_MAX); +#if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION) + if (!getcwd (path, PATH_MAX)) + { + msg ("Couldn't get current directory."); + exit (EX_SYSTEM); + } +#else + char *getwd (); + + if (!getwd (path)) + { + msg ("Couldn't get current directory: %s", path); + exit (EX_SYSTEM); + } +#endif + chdir_name = new_name (path, chdir_name); + free (path); + } + } + + if (name) + { + i = strlen (name); + /*NOSTRICT*/ + p = (struct name *) malloc ((unsigned) (sizeof (struct name) + i)); + } + else + p = (struct name *) malloc ((unsigned) (sizeof (struct name))); + if (!p) + { + if (name) + msg ("cannot allocate mem for name '%s'.", name); + else + msg ("cannot allocate mem for chdir record."); + exit (EX_SYSTEM); + } + p->next = (struct name *) NULL; + if (name) + { + p->fake = 0; + p->length = i; + strncpy (p->name, name, i); + p->name[i] = '\0'; /* Null term */ + } + else + p->fake = 1; + p->found = 0; + p->regexp = 0; /* Assume not a regular expression */ + p->firstch = 1; /* Assume first char is literal */ + p->change_dir = chdir_name; + p->dir_contents = 0; /* JF */ + if (name) + { + if (index (name, '*') || index (name, '[') || index (name, '?')) + { + p->regexp = 1; /* No, it's a regexp */ + if (name[0] == '*' || name[0] == '[' || name[0] == '?') + p->firstch = 0; /* Not even 1st char literal */ + } + } + + if (namelast) + namelast->next = p; + namelast = p; + if (!namelist) + namelist = p; +} + +/* + * Return nonzero if name P (from an archive) matches any name from + * the namelist, zero if not. + */ +int +name_match (p) + register char *p; +{ + register struct name *nlp; + register int len; + +again: + if (0 == (nlp = namelist)) /* Empty namelist is easy */ + return 1; + if (nlp->fake) + { + if (nlp->change_dir && chdir (nlp->change_dir)) + msg_perror ("Can't change to directory %d", nlp->change_dir); + namelist = 0; + return 1; + } + len = strlen (p); + for (; nlp != 0; nlp = nlp->next) + { + /* If first chars don't match, quick skip */ + if (nlp->firstch && nlp->name[0] != p[0]) + continue; + + /* Regular expressions (shell globbing, actually). */ + if (nlp->regexp) + { + if (fnmatch (nlp->name, p, FNM_LEADING_DIR) == 0) + { + nlp->found = 1; /* Remember it matched */ + if (f_startfile) + { + free ((void *) namelist); + namelist = 0; + } + if (nlp->change_dir && chdir (nlp->change_dir)) + msg_perror ("Can't change to directory %s", nlp->change_dir); + return 1; /* We got a match */ + } + continue; + } + + /* Plain Old Strings */ + if (nlp->length <= len /* Archive len >= specified */ + && (p[nlp->length] == '\0' || p[nlp->length] == '/') + /* Full match on file/dirname */ + && strncmp (p, nlp->name, nlp->length) == 0) /* Name compare */ + { + nlp->found = 1; /* Remember it matched */ + if (f_startfile) + { + free ((void *) namelist); + namelist = 0; + } + if (nlp->change_dir && chdir (nlp->change_dir)) + msg_perror ("Can't change to directory %s", nlp->change_dir); + return 1; /* We got a match */ + } + } + + /* + * Filename from archive not found in namelist. + * If we have the whole namelist here, just return 0. + * Otherwise, read the next name in and compare it. + * If this was the last name, namelist->found will remain on. + * If not, we loop to compare the newly read name. + */ + if (f_sorted_names && namelist->found) + { + name_gather (); /* Read one more */ + if (!namelist->found) + goto again; + } + return 0; +} + + +/* + * Print the names of things in the namelist that were not matched. + */ +void +names_notfound () +{ + register struct name *nlp, *next; + register char *p; + + for (nlp = namelist; nlp != 0; nlp = next) + { + next = nlp->next; + if (!nlp->found) + msg ("%s not found in archive", nlp->name); + + /* + * We could free() the list, but the process is about + * to die anyway, so save some CPU time. Amigas and + * other similarly broken software will need to waste + * the time, though. + */ +#ifdef amiga + if (!f_sorted_names) + free (nlp); +#endif + } + namelist = (struct name *) NULL; + namelast = (struct name *) NULL; + + if (f_sorted_names) + { + while (0 != (p = name_next (1))) + msg ("%s not found in archive", p); + } +} + +/* These next routines were created by JF */ + +void +name_expand () +{ + ; +} + +/* This is like name_match(), except that it returns a pointer to the name + it matched, and doesn't set ->found The caller will have to do that + if it wants to. Oh, and if the namelist is empty, it returns 0, unlike + name_match(), which returns TRUE */ + +struct name * +name_scan (p) + register char *p; +{ + register struct name *nlp; + register int len; + +again: + if (0 == (nlp = namelist)) /* Empty namelist is easy */ + return 0; + len = strlen (p); + for (; nlp != 0; nlp = nlp->next) + { + /* If first chars don't match, quick skip */ + if (nlp->firstch && nlp->name[0] != p[0]) + continue; + + /* Regular expressions */ + if (nlp->regexp) + { + if (fnmatch (nlp->name, p, FNM_LEADING_DIR) == 0) + return nlp; /* We got a match */ + continue; + } + + /* Plain Old Strings */ + if (nlp->length <= len /* Archive len >= specified */ + && (p[nlp->length] == '\0' || p[nlp->length] == '/') + /* Full match on file/dirname */ + && strncmp (p, nlp->name, nlp->length) == 0) /* Name compare */ + return nlp; /* We got a match */ + } + + /* + * Filename from archive not found in namelist. + * If we have the whole namelist here, just return 0. + * Otherwise, read the next name in and compare it. + * If this was the last name, namelist->found will remain on. + * If not, we loop to compare the newly read name. + */ + if (f_sorted_names && namelist->found) + { + name_gather (); /* Read one more */ + if (!namelist->found) + goto again; + } + return (struct name *) 0; +} + +/* This returns a name from the namelist which doesn't have ->found set. + It sets ->found before returning, so successive calls will find and return + all the non-found names in the namelist */ + +struct name *gnu_list_name; + +char * +name_from_list () +{ + if (!gnu_list_name) + gnu_list_name = namelist; + while (gnu_list_name && gnu_list_name->found) + gnu_list_name = gnu_list_name->next; + if (gnu_list_name) + { + gnu_list_name->found++; + if (gnu_list_name->change_dir) + if (chdir (gnu_list_name->change_dir) < 0) + msg_perror ("can't chdir to %s", gnu_list_name->change_dir); + return gnu_list_name->name; + } + return (char *) 0; +} + +void +blank_name_list () +{ + struct name *n; + + gnu_list_name = 0; + for (n = namelist; n; n = n->next) + n->found = 0; +} + +char * +new_name (path, name) + char *path, *name; +{ + char *path_buf; + + path_buf = (char *) malloc (strlen (path) + strlen (name) + 2); + if (path_buf == 0) + { + msg ("Can't allocate memory for name '%s/%s", path, name); + exit (EX_SYSTEM); + } + (void) sprintf (path_buf, "%s/%s", path, name); + return path_buf; +} + +/* returns non-zero if the luser typed 'y' or 'Y', zero otherwise. */ + +int +confirm (action, file) + char *action, *file; +{ + int c, nl; + static FILE *confirm_file = 0; + extern FILE *msg_file; + extern char TTY_NAME[]; + + fprintf (msg_file, "%s %s?", action, file); + fflush (msg_file); + if (!confirm_file) + { + confirm_file = (archive == 0) ? fopen (TTY_NAME, "r") : stdin; + if (!confirm_file) + { + msg ("Can't read confirmation from user"); + exit (EX_SYSTEM); + } + } + c = getc (confirm_file); + for (nl = c; nl != '\n' && nl != EOF; nl = getc (confirm_file)) + ; + return (c == 'y' || c == 'Y'); +} + +char *x_buffer = 0; +int size_x_buffer; +int free_x_buffer; + +char **exclude = 0; +int size_exclude = 0; +int free_exclude = 0; + +char **re_exclude = 0; +int size_re_exclude = 0; +int free_re_exclude = 0; + +void +add_exclude (name) + char *name; +{ + /* char *rname;*/ + /* char **tmp_ptr;*/ + int size_buf; + + un_quote_string (name); + size_buf = strlen (name); + + if (x_buffer == 0) + { + x_buffer = (char *) ck_malloc (size_buf + 1024); + free_x_buffer = 1024; + } + else if (free_x_buffer <= size_buf) + { + char *old_x_buffer; + char **tmp_ptr; + + old_x_buffer = x_buffer; + x_buffer = (char *) ck_realloc (x_buffer, size_x_buffer + 1024); + free_x_buffer = 1024; + for (tmp_ptr = exclude; tmp_ptr < exclude + size_exclude; tmp_ptr++) + *tmp_ptr = x_buffer + ((*tmp_ptr) - old_x_buffer); + for (tmp_ptr = re_exclude; tmp_ptr < re_exclude + size_re_exclude; tmp_ptr++) + *tmp_ptr = x_buffer + ((*tmp_ptr) - old_x_buffer); + } + + if (is_regex (name)) + { + if (free_re_exclude == 0) + { + re_exclude = (char **) (re_exclude ? ck_realloc (re_exclude, (size_re_exclude + 32) * sizeof (char *)): ck_malloc (sizeof (char *) * 32)); + free_re_exclude += 32; + } + re_exclude[size_re_exclude] = x_buffer + size_x_buffer; + size_re_exclude++; + free_re_exclude--; + } + else + { + if (free_exclude == 0) + { + exclude = (char **) (exclude ? ck_realloc (exclude, (size_exclude + 32) * sizeof (char *)): ck_malloc (sizeof (char *) * 32)); + free_exclude += 32; + } + exclude[size_exclude] = x_buffer + size_x_buffer; + size_exclude++; + free_exclude--; + } + strcpy (x_buffer + size_x_buffer, name); + size_x_buffer += size_buf + 1; + free_x_buffer -= size_buf + 1; +} + +void +add_exclude_file (file) + char *file; +{ + FILE *fp; + char buf[1024]; + + if (strcmp (file, "-")) + fp = fopen (file, "r"); + else + /* Let's hope the person knows what they're doing. */ + /* Using -X - -T - -f - will get you *REALLY* strange + results. . . */ + fp = stdin; + + if (!fp) + { + msg_perror ("can't open %s", file); + exit (2); + } + while (fgets (buf, 1024, fp)) + { + /* int size_buf;*/ + char *end_str; + + end_str = rindex (buf, '\n'); + if (end_str) + *end_str = '\0'; + add_exclude (buf); + + } + fclose (fp); +} + +int +is_regex (str) + char *str; +{ + return index (str, '*') || index (str, '[') || index (str, '?'); +} + +/* Returns non-zero if the file 'name' should not be added/extracted */ +int +check_exclude (name) + char *name; +{ + int n; + char *str; + extern char *strstr (); + + for (n = 0; n < size_re_exclude; n++) + { + if (fnmatch (re_exclude[n], name, FNM_LEADING_DIR) == 0) + return 1; + } + for (n = 0; n < size_exclude; n++) + { + /* Accept the output from strstr only if it is the last + part of the string. There is certainly a faster way to + do this. . . */ + if ((str = strstr (name, exclude[n])) + && (str == name || str[-1] == '/') + && str[strlen (exclude[n])] == '\0') + return 1; + } + return 0; +} diff --git a/gnu/usr.bin/tar/tar.h b/gnu/usr.bin/tar/tar.h new file mode 100644 index 0000000000..c3fec78743 --- /dev/null +++ b/gnu/usr.bin/tar/tar.h @@ -0,0 +1,291 @@ +/* Declarations for tar archives. + Copyright (C) 1988, 1992, 1993 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* major() and minor() macros (among other things) defined here for hpux */ +#ifdef hpux +#include +#endif + +/* + * Kludge for handling systems that can't cope with multiple + * external definitions of a variable. In ONE routine (tar.c), + * we #define TAR_EXTERN to null; here, we set it to "extern" if + * it is not already set. + */ +#ifndef TAR_EXTERN +#define TAR_EXTERN extern +#endif + +/* + * Header block on tape. + * + * I'm going to use traditional DP naming conventions here. + * A "block" is a big chunk of stuff that we do I/O on. + * A "record" is a piece of info that we care about. + * Typically many "record"s fit into a "block". + */ +#define RECORDSIZE 512 +#define NAMSIZ 100 +#define TUNMLEN 32 +#define TGNMLEN 32 +#define SPARSE_EXT_HDR 21 +#define SPARSE_IN_HDR 4 + +struct sparse + { + char offset[12]; + char numbytes[12]; + }; + +struct sp_array + { + int offset; + int numbytes; + }; + +union record + { + char charptr[RECORDSIZE]; + struct header + { + char arch_name[NAMSIZ]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char linkflag; + char arch_linkname[NAMSIZ]; + char magic[8]; + char uname[TUNMLEN]; + char gname[TGNMLEN]; + char devmajor[8]; + char devminor[8]; + /* these following fields were added by JF for gnu */ + /* and are NOT standard */ + char atime[12]; + char ctime[12]; + char offset[12]; + char longnames[4]; +#ifdef NEEDPAD + char pad; +#endif + struct sparse sp[SPARSE_IN_HDR]; + char isextended; + char realsize[12]; /* true size of the sparse file */ + /* char ending_blanks[12];*//* number of nulls at the + end of the file, if any */ + } + header; + struct extended_header + { + struct sparse sp[21]; + char isextended; + } + ext_hdr; + }; + +/* The checksum field is filled with this while the checksum is computed. */ +#define CHKBLANKS " " /* 8 blanks, no null */ + +/* The magic field is filled with this if uname and gname are valid. */ +#define TMAGIC "ustar " /* 7 chars and a null */ + +/* The linkflag defines the type of file */ +#define LF_OLDNORMAL '\0' /* Normal disk file, Unix compat */ +#define LF_NORMAL '0' /* Normal disk file */ +#define LF_LINK '1' /* Link to previously dumped file */ +#define LF_SYMLINK '2' /* Symbolic link */ +#define LF_CHR '3' /* Character special file */ +#define LF_BLK '4' /* Block special file */ +#define LF_DIR '5' /* Directory */ +#define LF_FIFO '6' /* FIFO special file */ +#define LF_CONTIG '7' /* Contiguous file */ +/* Further link types may be defined later. */ + +/* Note that the standards committee allows only capital A through + capital Z for user-defined expansion. This means that defining something + as, say '8' is a *bad* idea. */ +#define LF_DUMPDIR 'D' /* This is a dir entry that contains + the names of files that were in + the dir at the time the dump + was made */ +#define LF_LONGLINK 'K' /* Identifies the NEXT file on the tape + as having a long linkname */ +#define LF_LONGNAME 'L' /* Identifies the NEXT file on the tape + as having a long name. */ +#define LF_MULTIVOL 'M' /* This is the continuation + of a file that began on another + volume */ +#define LF_NAMES 'N' /* For storing filenames that didn't + fit in 100 characters */ +#define LF_SPARSE 'S' /* This is for sparse files */ +#define LF_VOLHDR 'V' /* This file is a tape/volume header */ +/* Ignore it on extraction */ + +/* + * Exit codes from the "tar" program + */ +#define EX_SUCCESS 0 /* success! */ +#define EX_ARGSBAD 1 /* invalid args */ +#define EX_BADFILE 2 /* invalid filename */ +#define EX_BADARCH 3 /* bad archive */ +#define EX_SYSTEM 4 /* system gave unexpected error */ +#define EX_BADVOL 5 /* Special error code means + Tape volume doesn't match the one + specified on the command line */ + +/* + * Global variables + */ +TAR_EXTERN union record *ar_block; /* Start of block of archive */ +TAR_EXTERN union record *ar_record; /* Current record of archive */ +TAR_EXTERN union record *ar_last; /* Last+1 record of archive block */ +TAR_EXTERN char ar_reading; /* 0 writing, !0 reading archive */ +TAR_EXTERN int blocking; /* Size of each block, in records */ +TAR_EXTERN int blocksize; /* Size of each block, in bytes */ +TAR_EXTERN char *info_script; /* Script to run at end of each tape change */ +TAR_EXTERN char *name_file; /* File containing names to work on */ +TAR_EXTERN char filename_terminator; /* \n or \0. */ +TAR_EXTERN char *tar; /* Name of this program */ +TAR_EXTERN struct sp_array *sparsearray; /* Pointer to the start of the scratch space */ +TAR_EXTERN int sp_array_size; /* Initial size of the sparsearray */ +TAR_EXTERN int tot_written; /* Total written to output */ +TAR_EXTERN struct re_pattern_buffer + *label_pattern; /* compiled regex for extract label */ +TAR_EXTERN char **ar_files; /* list of tape drive names */ +TAR_EXTERN int n_ar_files; /* number of tape drive names */ +TAR_EXTERN int cur_ar_file; /* tape drive currently being used */ +TAR_EXTERN int ar_files_len; /* malloced size of ar_files */ +TAR_EXTERN char *current_file_name, *current_link_name; + +/* + * Flags from the command line + */ +TAR_EXTERN int cmd_mode; +#define CMD_NONE 0 +#define CMD_CAT 1 /* -A */ +#define CMD_CREATE 2 /* -c */ +#define CMD_DIFF 3 /* -d */ +#define CMD_APPEND 4 /* -r */ +#define CMD_LIST 5 /* -t */ +#define CMD_UPDATE 6 /* -u */ +#define CMD_EXTRACT 7 /* -x */ +#define CMD_DELETE 8 /* -D */ +#define CMD_VERSION 9 /* --version */ + + +TAR_EXTERN int f_reblock; /* -B */ +#if 0 +TAR_EXTERN char f_dironly; /* -D */ +#endif +TAR_EXTERN int f_run_script_at_end; /* -F */ +TAR_EXTERN int f_gnudump; /* -G */ +TAR_EXTERN int f_follow_links; /* -h */ +TAR_EXTERN int f_ignorez; /* -i */ +TAR_EXTERN int f_keep; /* -k */ +TAR_EXTERN int f_startfile; /* -K */ +TAR_EXTERN int f_local_filesys; /* -l */ +TAR_EXTERN int tape_length; /* -L */ +TAR_EXTERN int f_modified; /* -m */ +TAR_EXTERN int f_multivol; /* -M */ +TAR_EXTERN int f_new_files; /* -N */ +TAR_EXTERN int f_oldarch; /* -o */ +TAR_EXTERN int f_exstdout; /* -O */ +TAR_EXTERN int f_use_protection;/* -p */ +TAR_EXTERN int f_absolute_paths;/* -P */ +TAR_EXTERN int f_sayblock; /* -R */ +TAR_EXTERN int f_sorted_names; /* -s */ +TAR_EXTERN int f_sparse_files; /* -S ... JK */ +TAR_EXTERN int f_namefile; /* -T */ +TAR_EXTERN int f_verbose; /* -v */ +TAR_EXTERN char *f_volhdr; /* -V */ +TAR_EXTERN int f_confirm; /* -w */ +TAR_EXTERN int f_verify; /* -W */ +TAR_EXTERN int f_exclude; /* -X */ +TAR_EXTERN char *f_compressprog; /* -z and -Z */ +TAR_EXTERN int f_do_chown; /* --do-chown */ +TAR_EXTERN int f_totals; /* --totals */ +TAR_EXTERN int f_remove_files; /* --remove-files */ +TAR_EXTERN int f_ignore_failed_read; /* --ignore-failed-read */ +TAR_EXTERN int f_checkpoint; /* --checkpoint */ +TAR_EXTERN int f_show_omitted_dirs; /* --show-omitted-dirs */ +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 */ + +/* + * We default to Unix Standard format rather than 4.2BSD tar format. + * The code can actually produce all three: + * f_standard ANSI standard + * f_oldarch V7 + * neither 4.2BSD + * but we don't bother, since 4.2BSD can read ANSI standard format anyway. + * The only advantage to the "neither" option is that we can cmp our + * output to the output of 4.2BSD tar, for debugging. + */ +#define f_standard (!f_oldarch) + +/* + * Structure for keeping track of filenames and lists thereof. + */ +struct name + { + struct name *next; + short length; /* cached strlen(name) */ + char found; /* A matching file has been found */ + char firstch; /* First char is literally matched */ + char regexp; /* This name is a regexp, not literal */ + char *change_dir; /* JF set with the -C option */ + char *dir_contents; /* JF for f_gnudump */ + char fake; /* dummy entry */ + char name[1]; + }; + +TAR_EXTERN struct name *namelist; /* Points to first name in list */ +TAR_EXTERN struct name *namelast; /* Points to last name in list */ + +TAR_EXTERN int archive; /* File descriptor for archive file */ +TAR_EXTERN int errors; /* # of files in error */ + +TAR_EXTERN char *gnu_dumpfile; + +/* + * Error recovery stuff + */ +TAR_EXTERN char read_error_flag; + + +/* + * Declarations of functions available to the world. + */ +union record *findrec (); +void userec (); +union record *endofrecs (); +void anno (); + +#if defined (HAVE_VPRINTF) && __STDC__ +void msg (char *,...); +void msg_perror (char *,...); +#else +void msg (); +void msg_perror (); +#endif diff --git a/gnu/usr.bin/tar/update.c b/gnu/usr.bin/tar/update.c new file mode 100644 index 0000000000..a64317c666 --- /dev/null +++ b/gnu/usr.bin/tar/update.c @@ -0,0 +1,585 @@ +/* Update a tar archive. + Copyright (C) 1988, 1992 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the 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 Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* JF implement the 'r' 'u' and 'A' options for tar. */ +/* The 'A' option is my own invention: It means that the file-names are + tar files, and they should simply be appended to the end of the archive. + No attempt is made to block the reads from the args; if they're on raw + tape or something like that, it'll probably lose. . . */ + +#include +#include +#include +#ifndef STDC_HEADERS +extern int errno; +#endif + +#ifdef HAVE_SYS_MTIO_H +#include +#include +#endif + +#ifdef BSD42 +#include +#else +#ifndef V7 +#include +#endif +#endif + +#ifndef __MSDOS__ +#include +#include +#endif + +#define STDIN 0 +#define STDOUT 1 + +#include "tar.h" +#include "port.h" +#include "rmt.h" + +int time_to_start_writing = 0; /* We've hit the end of the old stuff, + and its time to start writing new stuff + to the tape. This involves seeking + back one block and re-writing the current + block (which has been changed). */ + +char *output_start; /* Pointer to where we started to write in + the first block we write out. This is used + if we can't backspace the output and have + to null out the first part of the block */ + +extern void skip_file (); +extern void skip_extended_headers (); + +extern union record *head; +extern struct stat hstat; + +void append_file (); +void close_archive (); +int confirm (); +void decode_header (); +void fl_read (); +void fl_write (); +void flush_archive (); +int move_arch (); +struct name *name_scan (); +char *name_from_list (); +void name_expand (); +void name_gather (); +void names_notfound (); +void open_archive (); +int read_header (); +void reset_eof (); +void write_block (); +void write_eot (); + +/* Implement the 'r' (add files to end of archive), and 'u' (add files to + end of archive if they arent there, or are more up to date than the + version in the archive.) commands.*/ +void +update_archive () +{ + int found_end = 0; + int status = 3; + int prev_status; + char *p; + struct name *name; + extern void dump_file (); + + name_gather (); + if (cmd_mode == CMD_UPDATE) + name_expand (); + open_archive (2); /* Open for updating */ + + do + { + prev_status = status; + status = read_header (); + switch (status) + { + case EOF: + found_end = 1; + break; + + case 0: /* A bad record */ + userec (head); + switch (prev_status) + { + case 3: + msg ("This doesn't look like a tar archive."); + /* FALL THROUGH */ + case 2: + case 1: + msg ("Skipping to next header"); + case 0: + break; + } + break; + + /* A good record */ + case 1: + /* printf("File %s\n",head->header.name); */ + /* head->header.name[NAMSIZ-1]='\0'; */ + if (cmd_mode == CMD_UPDATE && (name = name_scan (current_file_name))) + { + + /* struct stat hstat; */ + struct stat nstat; + int head_standard; + + decode_header (head, &hstat, &head_standard, 0); + if (stat (current_file_name, &nstat) < 0) + { + msg_perror ("can't stat %s:", current_file_name); + } + else + { + if (hstat.st_mtime >= nstat.st_mtime) + name->found++; + } + } + userec (head); + if (head->header.isextended) + skip_extended_headers (); + skip_file ((long) hstat.st_size); + break; + + case 2: + ar_record = head; + found_end = 1; + break; + } + } + while (!found_end); + + reset_eof (); + time_to_start_writing = 1; + output_start = ar_record->charptr; + + while (p = name_from_list ()) + { + if (f_confirm && !confirm ("add", p)) + continue; + if (cmd_mode == CMD_CAT) + append_file (p); + else + dump_file (p, -1, 1); + } + + write_eot (); + close_archive (); + names_notfound (); +} + +/* Catenate file p to the archive without creating a header for it. It had + better be a tar file or the archive is screwed */ + +void +append_file (p) + char *p; +{ + int fd; + struct stat statbuf; + long bytes_left; + union record *start; + long bufsiz, count; + + if (0 != stat (p, &statbuf) || (fd = open (p, O_RDONLY | O_BINARY)) < 0) + { + msg_perror ("can't open file %s", p); + errors++; + return; + } + + bytes_left = statbuf.st_size; + + while (bytes_left > 0) + { + start = findrec (); + bufsiz = endofrecs ()->charptr - start->charptr; + if (bytes_left < bufsiz) + { + bufsiz = bytes_left; + count = bufsiz % RECORDSIZE; + if (count) + bzero (start->charptr + bytes_left, (int) (RECORDSIZE - count)); + } + count = read (fd, start->charptr, bufsiz); + if (count < 0) + { + msg_perror ("read error at byte %ld reading %d bytes in file %s", statbuf.st_size - bytes_left, bufsiz, p); + exit (EX_ARGSBAD); /* FOO */ + } + bytes_left -= count; + userec (start + (count - 1) / RECORDSIZE); + if (count != bufsiz) + { + msg ("%s: file shrunk by %d bytes, yark!", p, bytes_left); + abort (); + } + } + (void) close (fd); +} + +#ifdef DONTDEF +bprint (fp, buf, num) + FILE *fp; + char *buf; +{ + int c; + + if (num == 0 || num == -1) + return; + fputs (" '", fp); + while (num--) + { + c = *buf++; + if (c == '\\') + fputs ("\\\\", fp); + else if (c >= ' ' && c <= '~') + putc (c, fp); + else + switch (c) + { + case '\n': + fputs ("\\n", fp); + break; + case '\r': + fputs ("\\r", fp); + break; + case '\b': + fputs ("\\b", fp); + break; + case '\0': + /* fputs("\\-",fp); */ + break; + default: + fprintf (fp, "\\%03o", c); + break; + } + } + fputs ("'\n", fp); +} + +#endif + +int number_of_blocks_read = 0; + +int number_of_new_records = 0; +int number_of_records_needed = 0; + +union record *new_block = 0; +union record *save_block = 0; + +void +junk_archive () +{ + int found_stuff = 0; + int status = 3; + int prev_status; + struct name *name; + + /* int dummy_head; */ + int number_of_records_to_skip = 0; + int number_of_records_to_keep = 0; + int number_of_kept_records_in_block; + int sub_status; + extern int write_archive_to_stdout; + + /* fprintf(stderr,"Junk files\n"); */ + name_gather (); + open_archive (2); + + while (!found_stuff) + { + prev_status = status; + status = read_header (); + switch (status) + { + case EOF: + found_stuff = 1; + break; + + case 0: + userec (head); + switch (prev_status) + { + case 3: + msg ("This doesn't look like a tar archive."); + /* FALL THROUGH */ + case 2: + case 1: + msg ("Skipping to next header"); + /* FALL THROUGH */ + case 0: + break; + } + break; + + case 1: + /* head->header.name[NAMSIZ-1] = '\0'; */ + /* fprintf(stderr,"file %s\n",head->header.name); */ + if ((name = name_scan (current_file_name)) == (struct name *) 0) + { + userec (head); + /* fprintf(stderr,"Skip %ld\n",(long)(hstat.st_size)); */ + if (head->header.isextended) + skip_extended_headers (); + skip_file ((long) (hstat.st_size)); + break; + } + name->found = 1; + found_stuff = 2; + break; + + case 2: + found_stuff = 1; + break; + } + } + /* fprintf(stderr,"Out of first loop\n"); */ + + if (found_stuff != 2) + { + write_eot (); + close_archive (); + names_notfound (); + return; + } + + if (write_archive_to_stdout) + write_archive_to_stdout = 0; + new_block = (union record *) malloc (blocksize); + if (new_block == 0) + { + msg ("Can't allocate secondary block of %d bytes", blocksize); + exit (EX_SYSTEM); + } + + /* Save away records before this one in this block */ + number_of_new_records = ar_record - ar_block; + number_of_records_needed = blocking - number_of_new_records; + if (number_of_new_records) + bcopy ((void *) ar_block, (void *) new_block, (number_of_new_records) * RECORDSIZE); + + /* fprintf(stderr,"Saved %d recs, need %d more\n",number_of_new_records,number_of_records_needed); */ + userec (head); + if (head->header.isextended) + skip_extended_headers (); + skip_file ((long) (hstat.st_size)); + found_stuff = 0; + /* goto flush_file; */ + + for (;;) + { + /* Fill in a block */ + /* another_file: */ + if (ar_record == ar_last) + { + /* fprintf(stderr,"New block\n"); */ + flush_archive (); + number_of_blocks_read++; + } + sub_status = read_header (); + /* fprintf(stderr,"Header type %d\n",sub_status); */ + + if (sub_status == 2 && f_ignorez) + { + userec (head); + continue; + } + if (sub_status == EOF || sub_status == 2) + { + found_stuff = 1; + bzero (new_block[number_of_new_records].charptr, RECORDSIZE * number_of_records_needed); + number_of_new_records += number_of_records_needed; + number_of_records_needed = 0; + write_block (0); + break; + } + + if (sub_status == 0) + { + msg ("Deleting non-header from archive."); + userec (head); + continue; + } + + /* Found another header. Yipee! */ + /* head->header.name[NAMSIZ-1] = '\0'; */ + /* fprintf(stderr,"File %s ",head->header.name); */ + if (name = name_scan (current_file_name)) + { + name->found = 1; + /* fprintf(stderr,"Flush it\n"); */ + /* flush_file: */ + /* decode_header(head,&hstat,&dummy_head,0); */ + userec (head); + number_of_records_to_skip = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE; + /* fprintf(stderr,"Flushing %d recs from %s\n",number_of_records_to_skip,head->header.name); */ + + while (ar_last - ar_record <= number_of_records_to_skip) + { + + /* fprintf(stderr,"Block: %d <= %d ",ar_last-ar_record,number_of_records_to_skip); */ + number_of_records_to_skip -= (ar_last - ar_record); + flush_archive (); + number_of_blocks_read++; + /* fprintf(stderr,"Block %d left\n",number_of_records_to_skip); */ + } + ar_record += number_of_records_to_skip; + /* fprintf(stderr,"Final %d\n",number_of_records_to_skip); */ + number_of_records_to_skip = 0; + continue; + } + + /* copy_header: */ + new_block[number_of_new_records] = *head; + number_of_new_records++; + number_of_records_needed--; + number_of_records_to_keep = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE; + userec (head); + if (number_of_records_needed == 0) + write_block (1); + /* copy_data: */ + number_of_kept_records_in_block = ar_last - ar_record; + if (number_of_kept_records_in_block > number_of_records_to_keep) + number_of_kept_records_in_block = number_of_records_to_keep; + + /* fprintf(stderr,"Need %d kept_in %d keep %d\n",blocking,number_of_kept_records_in_block,number_of_records_to_keep); */ + + while (number_of_records_to_keep) + { + int n; + + if (ar_record == ar_last) + { + /* fprintf(stderr,"Flush. . .\n"); */ + fl_read (); + number_of_blocks_read++; + ar_record = ar_block; + number_of_kept_records_in_block = blocking; + if (number_of_kept_records_in_block > number_of_records_to_keep) + number_of_kept_records_in_block = number_of_records_to_keep; + } + n = number_of_kept_records_in_block; + if (n > number_of_records_needed) + n = number_of_records_needed; + + /* fprintf(stderr,"Copying %d\n",n); */ + bcopy ((void *) ar_record, (void *) (new_block + number_of_new_records), n * RECORDSIZE); + number_of_new_records += n; + number_of_records_needed -= n; + ar_record += n; + number_of_records_to_keep -= n; + number_of_kept_records_in_block -= n; + /* fprintf(stderr,"Now new %d need %d keep %d keep_in %d rec %d/%d\n", + number_of_new_records,number_of_records_needed,number_of_records_to_keep, + number_of_kept_records_in_block,ar_record-ar_block,ar_last-ar_block); */ + + if (number_of_records_needed == 0) + { + write_block (1); + } + } + } + + write_eot (); + close_archive (); + names_notfound (); +} + +void +write_block (f) + int f; +{ + /* fprintf(stderr,"Write block\n"); */ + /* We've filled out a block. Write it out. */ + + /* Backspace back to where we started. . . */ + if (archive != STDIN) + (void) move_arch (-(number_of_blocks_read + 1)); + + save_block = ar_block; + ar_block = new_block; + + if (archive == STDIN) + archive = STDOUT; + fl_write (); + + if (archive == STDOUT) + archive = STDIN; + ar_block = save_block; + + if (f) + { + /* Move the tape head back to where we were */ + if (archive != STDIN) + (void) move_arch (number_of_blocks_read); + number_of_blocks_read--; + } + + number_of_records_needed = blocking; + number_of_new_records = 0; +} + +/* Move archive descriptor by n blocks worth. If n is positive we move + forward, else we move negative. If its a tape, MTIOCTOP had better + work. If its something else, we try to seek on it. If we can't + seek, we lose! */ +int +move_arch (n) + int n; +{ + long cur; + +#ifdef MTIOCTOP + struct mtop t; + int er; + + if (n > 0) + { + t.mt_op = MTFSR; + t.mt_count = n; + } + else + { + t.mt_op = MTBSR; + t.mt_count = -n; + } + if ((er = rmtioctl (archive, MTIOCTOP, &t)) >= 0) + return 1; + if (errno == EIO && (er = rmtioctl (archive, MTIOCTOP, &t)) >= 0) + return 1; +#endif + + cur = rmtlseek (archive, 0L, 1); + cur += blocksize * n; + + /* fprintf(stderr,"Fore to %x\n",cur); */ + if (rmtlseek (archive, cur, 0) != cur) + { + /* Lseek failed. Try a different method */ + msg ("Couldn't re-position archive file."); + exit (EX_BADARCH); + } + return 3; +} diff --git a/gnu/usr.bin/tar/version.c b/gnu/usr.bin/tar/version.c new file mode 100644 index 0000000000..4454f62c8e --- /dev/null +++ b/gnu/usr.bin/tar/version.c @@ -0,0 +1 @@ +char version_string[] = "GNU tar version 1.11.2"; diff --git a/gnu/usr.bin/tar/y.tab.h b/gnu/usr.bin/tar/y.tab.h new file mode 100644 index 0000000000..4a541d2c97 --- /dev/null +++ b/gnu/usr.bin/tar/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; -- 2.20.1