From 3ba3e2cc4b63fa16707f51e735e751e62dd9526e Mon Sep 17 00:00:00 2001 From: Hidetoshi Shimokawa Date: Mon, 18 Jan 1999 06:59:18 +0000 Subject: [PATCH] Import Global v3_4_2 sources. Ok'd by: peter Discussed with: msmith --- contrib/global/COPYING | 25 +- contrib/global/FAQ | 67 ++ contrib/global/HISTORY | 224 +++++- contrib/global/INSTALL | 143 ++-- contrib/global/MANIFEST | 13 +- contrib/global/Makefile.inc | 15 +- contrib/global/README | 841 ++++++++++++-------- contrib/global/VERSION | 2 +- contrib/global/btreeop/Makefile | 3 - contrib/global/btreeop/btreeop.1 | 18 +- contrib/global/btreeop/btreeop.c | 139 ++-- contrib/global/dbpatches/README | 37 + contrib/global/dbpatches/patch.1.2 | 19 + contrib/global/dbpatches/patch.1.3 | 37 + contrib/global/dbpatches/patch.1.4 | 22 + contrib/global/gctags/C.c | 1185 +++++++++------------------- contrib/global/gctags/C.h | 92 +++ contrib/global/gctags/Makefile | 5 +- contrib/global/gctags/assembler.c | 165 ++-- contrib/global/gctags/gctags.1 | 200 ++--- contrib/global/gctags/gctags.c | 181 +++++ contrib/global/gctags/gctags.h | 91 +++ contrib/global/gctags/java.c | 240 ++++++ contrib/global/gctags/java.h | 91 +++ contrib/global/global.conf | 157 ++++ contrib/global/global/Makefile | 3 - contrib/global/global/global.1 | 68 +- contrib/global/global/global.c | 720 ++++++++++------- contrib/global/gozilla/Imakefile | 22 +- contrib/global/gozilla/gozilla.c | 68 +- contrib/global/gozilla/gozilla.man | 4 + contrib/global/gozilla/remote.c | 2 +- contrib/global/gtags.el | 58 +- contrib/global/gtags/Makefile | 3 - contrib/global/gtags/gtags.1 | 23 +- contrib/global/gtags/gtags.c | 406 +++++++--- contrib/global/htags/htags.1 | 66 +- contrib/global/htags/htags.pl | 917 ++++++++++++++------- contrib/global/lib/Makefile | 13 +- contrib/global/lib/conf.c | 308 ++++++++ contrib/global/lib/conf.h | 54 ++ contrib/global/lib/dbop.c | 332 ++++++++ contrib/global/lib/dbop.h | 88 +++ contrib/global/lib/defined.c | 66 ++ contrib/global/lib/defined.h | 48 ++ contrib/global/lib/die.h | 8 +- contrib/global/lib/find.c | 410 ++++++++-- contrib/global/lib/find.h | 2 +- contrib/global/lib/getdbpath.c | 47 +- contrib/global/lib/getdbpath.h | 2 +- contrib/global/lib/global.h | 27 +- contrib/global/lib/gparam.h | 14 +- contrib/global/lib/gtagsop.c | 644 +++++++++++++++ contrib/global/lib/gtagsop.h | 109 +++ contrib/global/lib/locatestring.c | 33 +- contrib/global/lib/locatestring.h | 11 +- contrib/global/lib/makepath.c | 33 +- contrib/global/lib/makepath.h | 4 +- contrib/global/lib/mgets.c | 55 +- contrib/global/lib/mgets.h | 5 +- contrib/global/lib/pathop.c | 155 ++++ contrib/global/lib/pathop.h | 59 ++ contrib/global/lib/strbuf.c | 137 ++++ contrib/global/lib/strbuf.h | 82 ++ contrib/global/lib/strmake.c | 59 ++ contrib/global/lib/strmake.h | 48 ++ contrib/global/lib/tab.c | 27 +- contrib/global/lib/tab.h | 5 +- contrib/global/lib/test.c | 18 +- contrib/global/lib/test.h | 4 +- contrib/global/lib/token.c | 293 +++++++ contrib/global/lib/token.h | 75 ++ contrib/global/lib/usable.c | 70 ++ contrib/global/lib/usable.h | 48 ++ contrib/global/nvi-1.66.diff | 673 ++++++++++++++++ contrib/global/nvi-1.79.diff | 84 +- contrib/global/systags/systags.sh | 200 ++++- 77 files changed, 8201 insertions(+), 2521 deletions(-) create mode 100644 contrib/global/FAQ create mode 100644 contrib/global/dbpatches/README create mode 100644 contrib/global/dbpatches/patch.1.2 create mode 100644 contrib/global/dbpatches/patch.1.3 create mode 100644 contrib/global/dbpatches/patch.1.4 create mode 100644 contrib/global/gctags/C.h create mode 100644 contrib/global/gctags/gctags.c create mode 100644 contrib/global/gctags/gctags.h create mode 100644 contrib/global/gctags/java.c create mode 100644 contrib/global/gctags/java.h create mode 100644 contrib/global/global.conf create mode 100644 contrib/global/lib/conf.c create mode 100644 contrib/global/lib/conf.h create mode 100644 contrib/global/lib/dbop.c create mode 100644 contrib/global/lib/dbop.h create mode 100644 contrib/global/lib/defined.c create mode 100644 contrib/global/lib/defined.h create mode 100644 contrib/global/lib/gtagsop.c create mode 100644 contrib/global/lib/gtagsop.h create mode 100644 contrib/global/lib/pathop.c create mode 100644 contrib/global/lib/pathop.h create mode 100644 contrib/global/lib/strbuf.c create mode 100644 contrib/global/lib/strbuf.h create mode 100644 contrib/global/lib/strmake.c create mode 100644 contrib/global/lib/strmake.h create mode 100644 contrib/global/lib/token.c create mode 100644 contrib/global/lib/token.h create mode 100644 contrib/global/lib/usable.c create mode 100644 contrib/global/lib/usable.h create mode 100644 contrib/global/nvi-1.66.diff diff --git a/contrib/global/COPYING b/contrib/global/COPYING index fb3baa4d627d..a13b649971f3 100644 --- a/contrib/global/COPYING +++ b/contrib/global/COPYING @@ -1,15 +1,17 @@ - @@@@@@@= - @= @= - @= @= - @= @= @@@@@= @@@@@@= @@= @= - @= F o r a l l h a c k e r s. @=@= @= - @= @@@@@@=@= @= @= @@@@@= @= @= @= - @= @= @= @= @= @= @= @@@@@= @= - @= @= @= @= @= @= @=@= @= @= - @@@@@@@@= @@@@= @@@@@= @@@@@@=@@@= @@@@= @@@@@@= + @@@@@@@=))) + @=))) @=))) @=))) + @=))) @=))) + @=))) @=))) @@@@@=)@@@@@@=))) @@=) @=))) + @=))F o r a l l)) h a c k e r s.))) @=@=))@=))) + @=))) @@@@@@=@=)))@=))) @=)@@@@@=)))@= @=))@=))) + @=))) @=))@=)))@=))) @=)@=)))@=)@@@@@=))@=))) + @=))) @=))@=)))@=))) @=)@=)))@=@=)))@=))@=))) + @@@@@@@@=)))@@@@=)@@@@@=)@@@@@@=@@@=)@@@@=)@@@@@@=))) -This software is covered by the following: + + +This software is covered by the followings: Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. @@ -40,7 +42,8 @@ This software is covered by the following: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Portions of gozilla(1) are covered by the following: + +Portions of gozilla(1): Copyright 1996 Netscape Communications Corporation, all rights reserved. Created: Jamie Zawinski , 24-Dec-94. diff --git a/contrib/global/FAQ b/contrib/global/FAQ new file mode 100644 index 000000000000..01697ff747bb --- /dev/null +++ b/contrib/global/FAQ @@ -0,0 +1,67 @@ + +Frequentry Asked Questions about GLOBAL. + +---------------------------------------------------------------------------- +Q1. Htags(1) aborts by short of memory. Why? Any workaround? + + % htags + Out of memory! + % _ + +A1. It seems that Perl4 leaks memory. If you use that version of perl, + then you had better to use Perl5. This works well. + +---------------------------------------------------------------------------- +Q2. Global(1) and btreeop(1) sometimes core dumps when using a large tag file. + Any workaround? + +A2. Btree(3) core dumps with a certain data set. + Please apply the patches in this package. See ./dbpatches/README. + +---------------------------------------------------------------------------- +Q3. GLOBAL skip some functions. + For example, GLOBAL skip the function 'func' in this example. + + #define M(a) static char *string = a; + + M(a) + + func() { <= GLOBAL skip func(). + ... + } + +A3. GLOBAL cannot recognize that pattern, because M(a) seems to be + a function definition. + + It should be follows. + + #define M(a) static char *string = a + + M(a); <= end with ';' + + func() { + ... + } + + Otherwise, you can tell gtags(1) that by listing the macros in + '.notfunction' file in current directory. + + [.notfunction] + +--------------- + |M + |... + +---------------------------------------------------------------------------- +Q4. I have set up 'global.conf' to use emacs's ctags command with GLOBAL + but I cannot use htags. + + % gtags + % htags + htags: GTAGS and GRTAGS not found. Please make them. + % ls G* + GPATH GTAGS + +A4. Emacs's ctags cannot locate function referencies. So, gtags cannot make + GRTAGS tag file with it. With the result that you cannot use htags and + global's -r option. +---------------------------------------------------------------------------- diff --git a/contrib/global/HISTORY b/contrib/global/HISTORY index d850075c7058..2b8072acfe2b 100644 --- a/contrib/global/HISTORY +++ b/contrib/global/HISTORY @@ -1,3 +1,4 @@ + GLOBAL history -------------- @@ -5,6 +6,8 @@ version 1.0 Initial version [21-Apr-96] global, gtags, btreeop, extended ctags. + Thanks to Sadaichi Hayashida. Generating relative path is his idea. + version 1.1 Only bugfix [2-May-96] [fixed bug] @@ -217,8 +220,8 @@ version 2.1 Symbol search, incremental update and gozilla [20-Sep-97] These options become default, so you need not to specify them. Gtags accepts these options for compatibility but no effect. - global - understand not only 'obj'(MAKEOBJDIR) directory but also - '/usr/obj'(MAKEOBJDIRPREFIX) directory of BSD build system. + global - understand 'obj'(MAKEOBJDIR) directory and '/usr/obj' + (MAKEOBJDIRPREFIX) directory of BSD build system. Thanks to Jordan K. Hubbard. This is his idea. @@ -304,12 +307,12 @@ version 2.21 Bugfix and slightly modified [11-Dec-97] - replace `lorder $(OBJS) | tsort -q` to already sorted list. for S.u.S.E Linux 5.1. - Thanks to Christoph Conrad for his information. + Thanks to Christoph Conrad for his information. gtags, lib/test.c - some change for Solaris environment. - Thanks to Yamashita TAKAO for his information. + Thanks to Yamashita TAKAO for his information. htags/Makefile, systags/Makefile - ${DESTDIR}/usr/bin -> ${DESTDIR}${BINDIR} @@ -323,14 +326,14 @@ version 2.22 GRTAGS support for assembler source [26-Dec-97] call EXT(xxx) call _xxx - Thanks to Yamashita TAKAO for his idea. + Thanks to Yamashita TAKAO for his idea. version 2.23 Bugfix and slightly modified [13-Jan-98] [fixed bug] gctags - GRTAGS support in version 2.22 doesn't work. - Thanks to Yamashita TAKAO for his bug report. + Thanks to Yamashita TAKAO for his bug report. [changed] gctags/Makefile, gctags/Makefile.generic @@ -347,11 +350,216 @@ version 2.24 Only bugfix [20-Jan-98] global - generates wrong path name when GTAGSROOT includes symbolic links. - Thanks to Wolfgang Helbig for his bug report. + Thanks to Wolfgang Helbig for his bug report. htags - cannot treat path name which includes digit as the second character like 'i386'. (In fact it was expand(1)'s bug.) - Thanks to Andrew Gallatin for his bug report. + Thanks to Andrew Gallatin for his bug report. global - doesn't search 'obj' directory correctly. + +version 3.0 configuration file and compact format. [25-Jun-98] + + [fixed bug] + gozilla - leaks memory. + gctags - -s option pick up symbols which belongs to GTAGS or GRTAGS. + global - cannot treat file which doesn't end with '\n'. + gtags - incremental update cannot detect removed files. + (GPATH file added.) + - make corrupted tag files. + (dbpatches/README added.) + + Thanks to Van Trinh for his bug report and information. + + htags - cannot be viewed by IE 5.0 because illegal tag. + + Thanks to Yoshida Masato for his bug report and fix patch. + + [changed] + gctags - -c option removed. These code was moved to gtags. + (It was needed for supporting plugged-in parser.) + global - -f option excute tag command instead of reading tag file. + (It became very faster than previous version.) + gtags.el- check whether or not user want to use tag name completion. + htags - URL of GLOBAL home page changed. + systags - gtags's option changed from -v to -cov. + gtags.c - replace "%+" of strftime with "%a %b %e %H:%M:%S %Z %Y". + for Debian GNU linux 1.3.1. + + [added] + gtags - -c option added. (compact format) + + Thanks to Takeshi Hojo. Compact format is based on his concept. + + htags - -c option added. (to make gzipped html file) + + Thanks to Oliver Paukstadt. This option is his idea. + + gtags, htags + - support configuration file. + (/etc/global.conf or $HOME/.globalrc) + gctags - -n option added. + --config option added. (It's undocumented.) + global - -t option added. + This option is to use with 'tagprg' and 'tagprgonce' command + in Elvis editor (2.1g-beta or later). + + Thanks to Steve Kirkendall for his excellent editor and + refined command set. + +version 3.01 Almost bugfix [5-Jul-98] + + [fixed bug] + global - print file names in a line. + gozilla - assume html file as a source file. + btreeop - insufficient usage check. + htags - cannot treat path including "++". + + [changed] + global - -f option became to accept multiple files. + all - fixed warning by -Wall -Wmissing-prototypes. + +version 3.1 Support of Java language [4-Aug-98] + + [fixed bug] + htags - locate main functions from the path which belongs + GTAGSLIBPATH when there is no main function in the local + source tree. + + [added] + gtags, global, htags, gozilla, gtags.el + - java supprt added. + gtags - --find option added. (internal use only - undocumented) + - --expand option added. (internal use only - undocumented) + htags - -h option (title header frame) added. + + Thanks to Shigeyuki Yamano. This is his idea. + + - line comment('//') detection added. + gctags, systags + - GTAGSSPECIAL environment variable added to treat system + macros like 'SYSINIT' in FreeBSD. + global.conf, lib/conf.c + - 'CVS/' added to 'skip' parameter. + + [deleted] + gtags.conf + - 'reserved_words' for htags(1) was deleted. + It is hard coded. + + [changed] + htags.pl- print guide links in .h file too. + +version 3.2 new patch for nvi-1.79(1.66) and multilingual nvi [31-Aug-98] + + [fixed bug] + nvi-1.79.diff + - may have buffer overflow. + + Thanks to David Brownlee for his advice. + + - suppress error message 'GTAGS not found'. + + [added] + nvi-1.79-m17n.diff + - patch for multilingual nvi which is included FreeBSD as + a ports. + nvi-1.66.diff + - patch for nvi-1.66 which is native command of NetBSD 1.3.2 + + [deleted] + nvi-1.34.diff + - it is old enough to support. + + [changed] + gozilla/Imakefile + - make possible to build gozilla alone without building + libgloutil.a. + +version 3.3 Rewriting gctags(1) and some bug fix. [13-Sep-98] + + [fixed bug] + gctags - look over inner class in a method.(Java) + - cannot treat 'OBJECT.class' pattern correctly.(Java) + + [changed] + Makefile* + - library name changed from libutil.a to libgloutil.a becase + that is already used. + - definition of MANDIR deleted. + global.conf + - comment fixed. + systags.sh + - additional support for NetBSD, OpenBSD, GNUmach and GNUhurd. + - doesn't use CGI form by default. + - use gtags -l and -h option by default. + - -g(gtags only), -f(form) and -c(compact) option added. + + [deleted] + gctags - fortran and lisp language support were deleted, because + it was not supported in GLOBAL system. + - -a, -d, -f, -t, -u, -w, -v options were deleted, + because it was not used in GLOBAL system. + - -D, -x options were deleted. These options became default. + - GTAGSSPECIAL was deleted. + + [added] + gctags - #if (#else #elif) #endif block parsing added. + - pick up #define in assembler source. + - can pick up object like 'definition\n\n() {'. + - -b, -n, -w options were added. + gtags.el- gtags-display-browser(ESC-h) command added. + INSTALL - explanation about formatting online manuals added. + + Thanks to Bert Gijsbers for his investigation. + + Extended ctags has been completely replaced with new gctags. + Thanks to Ken Arnold and the other people who developped BSD ctags(1). + Without it, GLOBAL had never been here. + +version 3.4 Unlimited nested index of htags(1). [8-Nov-98] + + [added] + global - --filter option added. (internal use only - undocumented) + htags - tabs parameter added in global.conf to change tab stop. + btreeop - '2' option added to the -L command. + + [changed] + htags - unlimited nested index of files supported. + README, htags.1, + - statements fixed. + + Thanks to Silas S. Brown for his fixing the statements. + + Makefile.generic + - make sub makefiles inherit the macros from the root Makefile. + +version 3.41 description added to README file. [10-Dec-98] + + [added] + README - usage description added. + '5. Elvis using global' + 'A.3. Incremental updating' + INSTALL - description about Elvis added. + + [change] + global - -t option is available with -P command. + global - assume "global -c ''" as "global -c". + + [deleted] + nvi-1.79-m17n.diff + - because it is difficult for me to maintain. Sorry. + +version 3.42 a couple of bugs fixed. [8-Jan-99] + + [fixed] + btreeop.c,gctags.c,global.c,gozilla.c,remote.c,gtags.c + - 'void main()' is not valid by the C spec. + + Thanks to David Brownlee for his patch. + + gtags.el- redefinition problem fixed. + (renamed match-string to util-match-string.) + + Thanks to Daisuke Kawahara for his bug report. diff --git a/contrib/global/INSTALL b/contrib/global/INSTALL index d958971fc6a2..a047c1e73d92 100644 --- a/contrib/global/INSTALL +++ b/contrib/global/INSTALL @@ -1,7 +1,7 @@ Installation of GLOBAL - 20-Jan-1998 Shigio Yamaguchi + 6-Dec-1998 Shigio Yamaguchi --------------------------------------------------------------------------- Guide line (C style) --------------------------------------------------------------------------- @@ -14,26 +14,30 @@ if (Your system == FreeBSD) { case 2.0.5R: case 2.1.0R: case 2.1.5R: - There is no problem. - break; case 2.1.6R: case 2.1.7R: - I don't know. But it seems same with 2.1.5R. - break; case 2.2.1R: - It is OK. But your native nvi is version 1.71. - Use 1.79 nvi available on the Internet. + There is no problem. break; case 2.2.2R: case 2.2.5R: - Your system inlucdes GLOBAL 1.9. You can overwrite it - with this 2.2 package. - But skip procedure "3. Extended vi (OPTIONAL)", because - your /usr/bin/nvi is already extended nvi for GLOBAL. + case 2.2.6R: + case 2.2.7R: + Your system includes GLOBAL 1.9 or 2.24. + You can overwrite it with this package. break; default: I don't know. But it seems to be little problem. } +} else if (Your system == NetBSD 1.3.2) { + You are lucky! + You need not to do procedure "1. Preparation for generic UNIX" + and you can use nvi-1.66.diff for native nvi. +} else if (Your system == Debian GNU linux 1.3.1) { + You are lucky! + + You can skip most of "1. Preparation for generic UNIX" except for + "a) Generic makefile".(It's very easy.) } else { You may some error messages to make GLOBAL. But it seems not so difficult to clear it. If you make a patch for it, @@ -43,6 +47,8 @@ if (Your system == FreeBSD) { Thank you in advance. } +Please see ./dbpatches/README. + ---------------------------------------------------------------------------- Install procedure ---------------------------------------------------------------------------- @@ -56,31 +62,47 @@ Install procedure 1. Preparation for generic UNIX - If you are a FreeBSD (all version) user, nothing to do here. - Please go to "2. GLOBAL basic". + If you are a user of FreeBSD (all version) or NetBSD 1.3.2 then + nothing to do here. Please go to "2. GLOBAL basic". - Otherwise, you must install following items before you install GLOBAL. + Otherwise, you must check following items before you install GLOBAL. - a) Generic makefile + a) Generic makefile (necessary) This package includes generic makefile. Please do the followings. % make -f Makefile.generic gen - % vi Makefile <- check install directories (BINDIR, MANDIR) + % vi Makefile <- check variables like BINDIR, MANDIR, ... - b) BSD db library version 1.85 + b) Some UNIX tools (necessary) + + Find(1), sed(1), sort(1), uniq(1) are needed. + If your environment is UNIX, you have them. You can confirm it like this. + + % which find + /usr/bin/find + % + + c) POSIX regular expression (extension) library (necessary) + + If you don't have it, you can use GNU's regex library (regex-0.12.tar.gz). + See following site. + + http://www.gnu.org/order/ftp.html + + d) BSD db library version 1.85 (necessary) If you don't have it, you can fetch it from this site. http://mongoose.bostic.com/db/packages/db.1.85.tar.gz - c) PERL version 4 or later + e) PERL version 4 or later (needed for htags) If you don't have it, you can fetch it from this site. ftp://ftp.cis.ufl.edu/pub/perl/CPAN/src/5.0/latest.tar.gz - d) Rewrite some files + f) Rewrite some files (needed for htags) If you install GLOBAL into other than /usr/bin, you need rewrite hard coded path in a program. You can find the place by this command. @@ -92,43 +114,33 @@ Install procedure % grep '/usr/bin/perl' */*.pl - e) POSIX regular expression (extension) library + g) Groff (needed for formatting online manuals) - If you don't have it, you can use GNU's regex library. + Online manuals in GLOBAL are written with 'mandoc' macro which is a part + of GNU groff package. See following site: - f) Some UNIX tools + http://www.gnu.org/order/ftp.html - Find(1), sed(1), sort(1) are needed. - If your environment is UNIX, you have them. + You can format these manuals by following command line manually. + + % groff -Wall -Tascii -mandoc global.1 + + If you replace your system's nroff(1) with GNU's one(nroff.sh) then + you can use man(1) to see GLOBAL's online manuals. 2. GLOBAL basic (NEEDED) % make # make install -3. Extended vi (OPTIONAL) +3. Extended nvi (OPTIONAL) - GLOBAL supports two version of nvi. - There is a little defference in behavior between them when a number of - functions located. (please see 'README'.) - Version 1.34 nvi is included by FreeBSD 2.0.5R, 2.1.0R and 2.1.5R. - Version 1.79 nvi is available on + If you use FreeBSD 2.2.2R or later, your nvi is already extended nvi. + Otherwise, please get nvi-1.79 at: - ftp://ftp.cs.berkeley.edu/ucb/4bsd/nvi-1.79.tar.gz. + ftp://ftp.cs.berkeley.edu/ucb/4bsd/nvi-1.79.tar.gz - If you don't have nvi-1.34, use nvi-1.79. - - If you use version 1.34 nvi which is a native command in FreeBSD 2.0.5R, - 2.1.0R or 2.1.5R then - - % cp -r /usr/src/usr.bin/vi vi <- version 1.34 of nex/nvi - % cd vi - % patch -p < ../nvi-1.34.diff - % make - # make install - - else if you use version 1.79 nvi which is the latest version then - fetch from ftp://ftp.cs.berkeley.edu/ucb/4bsd/nvi-1.79.tar.gz and + and do the followings. % tar xzvf nvi-1.79.tar.gz % cd nvi-1.79 @@ -138,10 +150,7 @@ Install procedure % make # make install - Caution: If you use FreeBSD 2.2.2R or later, your nvi is already - extended vi. Don't patch with nvi-1.79.diff. - - else we have no patch for it. + The patch for nvi-1.66 is also available for NetBSD 1.3.2 users. 4. Extended emacs (OPTIONAL) @@ -149,7 +158,7 @@ Install procedure Mule 2.3 (= Emacs 19.28). Other emacs version seems to work well, but I don't confirm it. - You can get it from + You can get it at: Emacs 19.34b: ftp://prep.ai.mit.edu/pub/gnu/emacs-19.34b.tar.gz @@ -165,7 +174,16 @@ Install procedure +----------------------------------------------- |(setq load-path (cons "~/lisp" load-path)) -5. Gozilla (OPTIONAL) +5. Elvis (OPTIONAL) + + You need Elvis 2.1. You can get it at: + + ftp://ftp.cs.pdx.edu/pub/elvis/elvis-2.1.tar.gz + + You need not any patch for it. + + +6. Gozilla (OPTIONAL) You need X(1) to install gozilla. @@ -175,4 +193,29 @@ Install procedure # make install # make install.man +7. other parser (OPTIONAL) + + If you want to use other tag command like etags (tag command for emacs) + as a parser, you need to write global.conf (or $HOME/.globalrc). + + Sample gtags.conf has etags's entry. Try this. + + + a) Install parser. + + % cd /lib-src + % make ctags + ... + # cp ctags /usr/local/bin/ctags-emacs + + b) Select ctags-emacs for GLOBAL system. + + % setenv GTAGSLABEL ctags-emacs + + or + + +------------------------------------------------ + |default:\ <== gtags use 'default' entry by default. + | :include=ctags-emacs:include=htags: + Good luck! diff --git a/contrib/global/MANIFEST b/contrib/global/MANIFEST index bf01ee814845..ca62a7baa4f3 100644 --- a/contrib/global/MANIFEST +++ b/contrib/global/MANIFEST @@ -1,21 +1,24 @@ COPYING Copyright notice. +FAQ Frequentry asked question. HISTORY Histroy of GLOBAL. INSTALL Installation method MANIFEST This file. Makefile Makefile for BSD. Makefile.inc A part of Makefile for BSD. Makefile.generic Makefile for generic UNIX(including BSD). -PROBLEMS Problem report. README Readme (introduction and usage). VERSION Version number. btreeop/ Btreeop command directory. -global/ Global command directory. -gozilla/ Gozilla command directory. +dbpatches/ Patch files for DB(3). gctags/ Extended ctags command directory. +global/ Global command directory. +global.conf Configuration file. +gozilla/ Gozilla command directory. gtags/ Gtags command directory. +gzshrc Gzsh start up file. htags/ Htags command directory. systags/ Script for kernel. -lib/ library. +lib/ Private library. gtags.el Gtags mode for Emacs. -nvi-1.34.diff Patch for nvi 1.34. +nvi-1.66.diff Patch for nvi 1.66. nvi-1.79.diff Patch for nvi 1.79. diff --git a/contrib/global/Makefile.inc b/contrib/global/Makefile.inc index befa954bf7a2..b2093986800c 100644 --- a/contrib/global/Makefile.inc +++ b/contrib/global/Makefile.inc @@ -1,7 +1,16 @@ +.if !defined(GLOBAL_MAKEFILE_INC_BEEN_HERE) + +GLOBAL_MAKEFILE_INC_BEEN_HERE=yes BINDIR?= /usr/bin -MANDIR?= /usr/share/man/man .if exists(${.OBJDIR}/../lib) -LIBUTIL=${.OBJDIR}/../lib/libutil.a +LIBDESTDIR= ${.OBJDIR}/../lib .else -LIBUTIL=${.CURDIR}/../lib/libutil.a +LIBDESTDIR= ${.CURDIR}/../lib +.endif +LDDESTDIR= -L${LIBDESTDIR} +LDADD= -lgloutil +DPADD= ${LIBDESTDIR}/libgloutil.a +CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../lib -O \ + -Wall -Wwrite-strings -Wmissing-prototypes + .endif diff --git a/contrib/global/README b/contrib/global/README index 584c818478a1..d6226732b1c7 100644 --- a/contrib/global/README +++ b/contrib/global/README @@ -1,30 +1,21 @@ - @@@@@@@= - @= @= - @= @= - @= @= @@@@@= @@@@@@= @@= @= - @= F o r a l l h a c k e r s. - @= @@@@@@=@= @= @= @@@@@= @= @= @= - @= @= @= @= @= @= @= @@@@@= @= - @= @= @= @= @= @= @=@= @= @= - @@@@@@@@= @@@@= @@@@@= @@@@@@=@@@= @@@@= @@@@@@= + @@@@@@@=))) + @=))) @=))) @=))) + @=))) @=))) + @=))) @=))) @@@@@=)@@@@@@=))) @@=) @=))) + @=))F o r a l l)) h a c k e r s.))) @=@=))@=))) + @=))) @@@@@@=@=)))@=))) @=)@@@@@=)))@= @=))@=))) + @=))) @=))@=)))@=))) @=)@=)))@=)@@@@@=))@=))) + @=))) @=))@=)))@=))) @=)@=)))@=@=)))@=))@=))) + @@@@@@@@=)))@@@@=)@@@@@=)@@@@@@=@@@=)@@@@=)@@@@@@=))) - Shigio Yamaguchi 20-Jan-98 + Shigio Yamaguchi 10-Dec-98 - Copyright 1996, 1997, 1998 - Shigio Yamaguchi All right resereved. + Copyright 1996, 1997, 1998 Shigio Yamaguchi All right resereved. - ---------------------------------------------------------- - Note: - This version of GLOBAL makes 'GSYMS' tag file for - searching symbols other than functions. - (Try global(1) with -s option.) - But the tag file is very large. If you hope not to - make the file, please use gtags with -o (old) option. - Htags(1) doesn't use 'GSYMS'. - ---------------------------------------------------------- +GLOBAL is a source code tag system that works the same way across diverse +environments. It supports C, Yacc and Java source code. -GLOBAL is a browsing system for C and Yacc source code. It brings benefits to all hackers. Enjoy! @@ -39,53 +30,66 @@ It brings benefits to all hackers. Enjoy! 1.3. Basic usage 1.4. Applied usage - 2. Extended vi using global + 2. Extended nvi using global 2.1. Features 2.2. Preparation 2.3. Basic usage 2.4. Applied usage - 3. Hypertext generator + 3. Extended emacs using global 3.1. Features 3.2. Preparation - 3.3. Usage - 3.4. To make hypertext of kernel - 3.5. Gozilla + 3.3. Basic usage + 3.4. Applied usage - 4. Extended emacs using global + 4. Hypertext generator 4.1. Features 4.2. Preparation - 4.3. Basic usage - 4.4. Applied usage + 4.3. Usage + 4.4. Making hypertext of the kernel + 4.5. Gozilla + + 5. Elvis using global + + 5.1. Features + 5.2. Preparation + 5.3. Basic usage + 5.4. Applied usage + + A. Other topics + + A.1. How to plug in a parser + A.2. How to use compact format + A.3. Incremental updating + A.4. Plans for the furture -------------------------------- 0. Introduction -GLOBAL is a browsing system for C and Yacc source files. -You can locate the specified function in C source files and move there easily. -It is useful to hack a large project containing many subdirectories, -many '#ifdef' and many main() functions like MH, X or BSD kernel. +GLOBAL is a source code tag system that works the same way across diverse +environments. Currently, it supports the following: -It supports following environments. + o Shell command line(see '1. Global') + o nvi editor(see '2. Extended nvi using global') + o emacs editor(see '3. Emacs using global') + o Web browser(see '4. Hypertext generator') + o Elvis editor(see '5. Elvis using global') - o shell command line(see '1. Global') - o vi editor(see '2. Extended vi using global') - o web browser(see '3. Hypertext generator') - o emacs editor(see '4. Emacs using global') +Supported languages are C/Yacc and Java. +You can locate a specified function in the source files and move there easily. +It is useful for hacking a large project containing many subdirectories, +many '#ifdef' and many main() functions, like MH, X or BSD kernel. -GLOBAL is consist of global(1), gtags(1), btreeop(1), gctags(1), htags(1), -extended vi(1), gtags.el and gozilla(1). +GLOBAL consists of global(1), gtags(1), btreeop(1), gctags(1), htags(1), +extended nvi(1), gtags.el and gozilla(1). * 'extended' means being entended for GLOBAL. - * Btreeop and gctags are used internally, so you need not - understand about them. - -The extended vi is completely upper compatible with original one. -All the functions for GLOBAL are enabled only in 'gtagsmode'. + * Btreeop and gctags are used internally, so you do not need to + understand them. ------------------------------------------------------------------------------ @@ -93,39 +97,46 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. 1.1. Features - o Global can find the locations of a specified function quickly. - o Global can locate not only function definitions but also function references. - o Global allows duplicate entries. - o Global can treat a source tree containing subdirectories and you can - get relative path of objects from anywhere within the tree. - o Global can understand POSIX 1003.2 regular expression (extension). - o Global can search in not only a source tree but also library paths. - o Global can treat yacc source file. + o Global can find the locations of a specified object quickly. + o Global can locate not only object definitions but also object references. + o Global allows duplicate objects. + o Global can treat a source tree containing subdirectories as a logical + scope. You can get the relative path of objects from anywhere within + that scope. + o Global allows duplicate objects. + o Global can understand POSIX 1003.2 regular expressions. + o Global can search not only in a source tree but also in library paths. + o Tag files are indepent of machine architecture. + o Global can use a plugged in parser with the global.conf + (or $HOME/.globalrc). + o Global can use a tag file in a compact format to save disk space. I think these features are useful for a large project containing many - subdirectories, many '#ifdef' and many main() functions like MH. + subdirectories, many '#ifdef' and many main() functions like MH, mozilla, + X and kernels. 1.2. Preparation First of all, you must execute gtags(1) at the root of source tree. - For example, if you want to browse vi's source code, please do like this. + For example, if you want to browse vi's source code: % cd /usr/src/usr.bin/vi % gtags Gtags traverse subdirectories and makes - two database at the root of source tree. + three databases at the root of the source tree. % ls G*TAGS - GRTAGS GTAGS + GRTAGS GTAGS GSYMS - GTAGS - database for function definition - GRTAGS - database for function reference + GTAGS - database of function definitions + GRTAGS - database of function references + GSYMS - database of other symbols 1.3. Basic usage - Please think of following source tree. + Consider the following source tree: ROOT/ <- the root of source tree (GTAGS,GRTAGS) | @@ -154,8 +165,9 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. |} | +---------------+ - You can get the relative path of your object from anywhere within - the source tree. + You can get the relative path of your object from anywhere in + the source tree. You need not specify where the tag file is. + Global will locate the tag file by itself. % cd ROOT % global func1 @@ -167,19 +179,20 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. % global func1 ../DIR1/fileB.c <- relative path from DIR2 - -r option locates function references. + The -r option locates function references. % global -r func2 ../DIR1/fileA.c <- func2() is referred from fileA.c - You can use POSIX regular expression (extension). + You can use POSIX regular expressions. % cd ROOT % global 'func[1-3]' DIR1/fileB.c <- func1, func2 and func3 are matched DIR2/fileC.c - -x option shows the detail. It's similar to ctags's -x option. + The -x option shows the details. It is similar to the -x option + in ctags(1). % global func2 DIR2/fileC.c @@ -187,17 +200,24 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. func2 2 DIR2/fileC.c func2(){ i++; } func2 4 DIR2/fileC.c func2(){ i--; } - -a option produces the absolute path name. + The -a option produces the absolute path name. % global -a func1 /home/user/ROOT/DIR1/fileB.c - -s option locates any symbols other than function. + The -s command locates any symbols other than functions. % global -xs X X 1 DIR2/fileC.c #ifdef X - You can edit files including specified function directly like this. + The -g command locates any patterns including symbols. + It is similar to grep(1). + + % global -xg '#ifdef' + #ifdef 1 DIR2/fileC.c #ifdef X + + You can edit all files that include a specified function by typing + one command, for example: % vi `global func1` <- edit fileB.c @@ -221,22 +241,22 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. |func1(){ i--; }| +---------------+ - When you are walking in version1.0 directory, global locates functions - only in version1.0. + When you are in the version1.0 directory, global will only locate functions + that are in version1.0. % cd ROOT/version1.0 % global -x func1 func1 1 file.c func1(){ i++; } - When you are walking in version2.0, global locates functions only in - version2.0. + When you are in the version2.0, global will only locate functions that + are in version2.0. % cd ROOT/version2.0 % global -x func1 func1 1 file.c func1(){ i--; } - If you are at ROOT/ or you set GTAGSROOT environment variable to ROOT, - global locates functions in both version1.0 and version2.0 directories. + If you are at ROOT/, or you set the GTAGSROOT environment variable to ROOT, + then global will locate functions in both directories. % cd ROOT % global -x func1 @@ -246,9 +266,9 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. =-=-=-= There is another usage of GTAGSROOT. - If your source files are on a read only device like CDROM, you cannot - make database on the root of source tree. - In such case, please do the following. + If your source files are on a read-only device, such as CDROM, + then you cannot make databases at the root of the source tree. + In such cases, please do the following: % mkdir /var/dbpath % cd /cdrom/src <- the root of source tree @@ -259,11 +279,12 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. =-=-=-= - If you want to treat the references to a function that is not defined - in the source tree like a library function or system call, you can specify - library directories with the GTAGSLIBPATH environment variable. + If you want all references to a function that is not defined in the source + tree to be treated as calls to library functions or system calls, then + you can specify library directories with the GTAGSLIBPATH environment + variable. You should execute gtags at each directory of the path. - If GTAGS is not found in a directory, global ignores it. + If GTAGS is not found in a directory, global ignores that directory. % pwd /develop/src/mh <- this is the source tree @@ -281,12 +302,12 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. % global access ../../../usr/src/sys/kern/vfs_syscalls.c <- access() is found in kernel - Of course, user program doesn't call kernel function directly, but - at least it is useful. + Of course, the user program does not call kernel functions directly, + but at least it is useful. =-=-=-= - If you forget function name, you can use -c (complete) option. + If you forget a function name, you can use the -c (complete) command. % global -c kmem <- maybe k..k.. kmem.. kmem_alloc @@ -300,7 +321,7 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. % global kmem_suballoc ../vm/vm_kern.c - You can use -c option with tcsh's complete command. + You can use the -c command with tcsh's complete command. % set funcs=(`global -c`) % complete global 'n/*/$funcs/' @@ -311,11 +332,11 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. % global kmem_suballoc ../vm/vm_kern.c - * means tab key or Ctrl-I. + * means the tab key or Ctrl-I. =-=-=-= - If you want to browse many files in order, do the followings. + If you want to browse many files in order, do the following: % global -xr fork | awk '{printf "view +%s %s\n",$2,$3}' | tee /tmp/list view +650 ../dev/aic7xxx/aic7xxx_asm.c @@ -327,24 +348,24 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. view +351 ../kern/init_main.c % sh !$ <- from now on, go to next tag with 'ZZ'. -2. Extended vi using global +2. Extended nvi using global 2.1. Features - o Tag function of extended vi can locate not only function definitions + o The tag function of extended vi can locate not only function definitions but also function references. - o Extended vi allows duplicate tag entries. - o Extended vi can understand POSIX regular expression (extension) - as a tag name for search. - o Extended vi is completely upper compatible with original one. - Above functions are available only in 'gtags mode'. + o Extended nvi allows duplicate tag entries. + o Extended nvi can understand POSIX regular expressions + as a tag name for the search. + o Extended nvi is completely backward-compatible with the original nvi. + The above functions are available only in 'gtags mode'. 2.2. Preparation First, do the preparation of global. (Please see "1.2. Preparation"). Second, to use global from vi, you need to get into 'gtagsmode'. - There are some ways to do it. + There are several ways to do this: (a) Start vi with -G option @@ -358,7 +379,7 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. ~ :set gtagsmode - (c) Previously write the set command to .exrc or .nexrc file and start vi + (c) Write the above set command to the .exrc or .nexrc file and start vi $HOME/.exrc +---------------------------- @@ -372,105 +393,70 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. :tag func1 - It seemes same with original vi, but extended vi use GTAGS - instead of tags. + It seemes the same as original vi, but extended vi use GTAGS instead of + tags. - o To go to referenced point of func1, add prefix 'r' + o To go to the referenced point of func1, add the prefix 'r' :rtag func1 - Extended vi use GRTAGS. + Extended nvi use GRTAGS. - o If a number of functions located, the action of extended vi differs - up to your nvi's version. - - [Extended vi based 1.34 nvi] - - Vi goes into 'GTAGS SELECT MODE' like this. - - +------------------------------------------------------------- - |main 347 i386/isa/ultra14f.c main() - |main 128 kern/init_main.c main(framep) - |main 104 netiso/clnp_debug.c main() - |main 164 netiso/xebec/main.c main(argc, argv) - |~ - |~ - |~ - |~ - |~ - |[GTAGS SELECT MODE] 4 lines - +------------------------------------------------------------- - - You can select a tag line by any vi command and press [RETURN], - and you can go to the tag's point. In ex mode, type "select" - instead of [RETURN]. When you want to go to next or previous tag, - you can return to 'GTAGS SELECT MODE' with and reselect. - - Suggested .nexrc: - set gtagsmode - set leftright - - [Extended vi based 1.79 nvi] - - Vi goes to the first tag. - Then you can go to next tag by ':tagnext' or back by ':tagprev'. + o If a number of functions are located, extended vi goes to the first tag. + You can go to next tag by typing ':tagnext' and back by typing ':tagprev'. Suggested .nexrc: set gtagsmode map ^N :tagnext^M map ^P :tagprev^M - == WHY TWO STYLE EXIST ? == - 1.34 nvi cannot treat duplicate tag entries, so I made 'GTAGS SELECT MODE' - in it. But 1.79 nvi (1.61 and later) can treat them, so I adapted GLOBAL - tags to nvi's tag structure. - o command is available. - In gtagsmode, if you are on the first column of line, it is identical to - ":rtag [RETURN]", otherwise ":tag [RETURN]". + In gtags mode, if you are in the first column of a line, + it is equivalent to ":rtag ", otherwise it is equivalent + to ":tag ". - o Other tag commands are available too. + o Other tag commands are also available: - Return to the most recent tag context. - ":tagpop" - Pop to the specified tag in the tags stack. - ":tagtop" - Pop to the top tag in the tags stack. - ":display tags" - Display tags stack. + ":tagpop" - Go to the specified tag in the tags stack. + ":tagtop" - Go to the top tag in the tags stack. + ":display tags" - Display the tags stack. - Please read online manual. + Please read the online manual. 2.4. Applied usage - o In large project which include many main() function like MH, - you can start vi like this. + o In large projects that include many main() function like MH, + you can start vi like this: % vi -G -t main You can browse all commands sequentially. - o When you want to check functions the name of which start with - "set" or "get", + o When you want to check functions the name of which start with "set" + or "get", use: % vi -G -t '^[sg]et' - Of cause, following command is available too. + Of course, the following command is also available: :tag ^[sg]et - o If your source files are on a read only device like CDROM, please do - the followings. + o If your source files are on a read only device like a CD-ROM, please do + the following: - % mkdir /var/dbpath <- directory for tag file - % cd /cdrom/src <- the root of source tree + % mkdir /var/dbpath <- directory for the tag file + % cd /cdrom/src <- the root of the source tree % gtags /var/dbpath <- make tag files in /var/dbpath % setenv GTAGSROOT `pwd` % setenv GTAGSDBPATH /var/dbpath % vi -G -t main - o If you want to treat the references to the function that is not defined - in the source tree like library functions or system calls, - do the followings. - + o If you want all references to function that are not defined in the source + tree to be treated as references to library functions or as system calls, + do the following: + % cd /usr/src/lib % gtags <- probably as a root % cd /usr/src/sys @@ -483,130 +469,27 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. % gtags % vi -G -t main - You can start from vi and trip the whole unix world as if using - hypertext. + You can start from vi and browse the whole unix world as if you were + using hypertext. - -3. Hypertext generator +3. Extended emacs using global 3.1. Features - o Htags makes hypertext from C source files. - o Once the hypertext generated, you need nothing other than WWW browser. - o You can move hypertext to anywhere. It is independent of the source code. - o You can use all of your browser's functions, for example, search, - history, bookmark, save, frame, windows and so on. + Addition to the extended vi, + + o More intelligent recognition of the current token and its type. + o Tag completion is available for input tag name. + o Symbol search and pattern search are available. + o Mouse events are supported. 3.2. Preparation - At first, you must prepare much disk space. Hypertext needs so much - disk space. For example, the source code of FreeBSD kernel needs the - following disk space. - - source code(/usr/src/sys) 14.0MB - - GTAGS 1.5MB - GRTAGS 8.0MB - GSYMS 12.0MB - HTML/ 55MB(!!!) - ------------------------------------------------- - total 77MB - - Please do the followings. - - (at your source directory) - % gtags <- make tag database(GTAGS,GRTAGS,GSYMS) - % htags <- make hypertext(HTML/) - - Then you will find 'HTML' directory in the current directory. - -3.3. Usage - - Please start a web browser like this. - - % lynx HTML/index.html - - You can use any browsers, for example, Lynx, Chimera, Mosaic, - Netscape Navigator, Internet Explorer and so on. But some browsers - cannot treat framed index. Then select '[no frame version is here]'. - - You will understand the usage for the looking. - You can move HTML directory to anywhere. It is independent of - the source code. - -3.4. To make hypertext of kernel - - If you would like to make hypertext of FreeBSD kernel source, - it is convenient to use systags script in this package. - - % cd /usr/src/sys - % systags - then - - % netscape HTML/index.html - - You can use following functions with systags. - - o input form for dynamic index. - (This reqires you to setup httpd server for CGI program.) - o one level nested index. - o browse assembler source file. - - Of course, you can use above functions without systags. - Please see gtags(1), htags(1). - -3.5. Gozilla - - If you use Netscape Navigator, you can control the browser from command - line by gozilla(1). - - % gtags - % htags - % global -x fork - fork 60 kern/kern_fork.c fork(p, uap, retval) - % gozilla +60 kern/kern_fork.c - % - - Then you can see the hypertext about fork function directly on Netscape - Navigator. If the browser has not been loaded, gozilla loads it. - - If you use another browser like lynx, try this. - - % gozilla -b lynx +60 kern/kern_fork.c - - or - - % setenv BROWSER lynx - % gozilla +60 kern/kern_fork.c - - You can send remote command to Netscape Navigator too. Try this. - - % gozilla -C pagedown - % gozilla -C pageup - - The remote commands are undocumented, but you can see the hint in the - resource file. (Netscape.ad file) - - NOTES: - Netscape Navigator is a registered trademark of Netscape Communications - Corporation in the United States and other countries. - -4. Extended emacs using global - -4.1. Features - - Addition to the extended vi, - - o More intelligent to recongnize current token and its type. - o Tag completion is available for input tag name. - o Mouse event is supported. - -4.2. Preparation - First, do the preparation of global. (Please see "1.2. Preparation"). - Second, to use global from emacs, you need to load gtags.el file and - execute gtags-mode function in it. There are some ways to do it. + Second, to use global from emacs, you need to load the gtags.el file + and execute gtags-mode function in it. There are several ways to + do this: (a) Start emacs, load gtags.el and execute gtags-mode function. @@ -627,8 +510,8 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. |M-x gtags-mode[RET] +------------------------------------------------------ - (b) Previously write autoload function to $HOME/.emacs file, - start emacs and execute gtags-mode function. + (b) Write the autoload function to the $HOME/.emacs file, start emacs + and execute the gtags-mode function. $HOME/.emacs +------------------------------------------------------ @@ -641,8 +524,9 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. |M-x gtags-mode[RET] +------------------------------------------------------ - (c) Previously write autoload function to $HOME/.emacs file and - start emacs with -f option + (c) Write the autoload function to the $HOME/.emacs file and start emacs + with the -f option. + $HOME/.emacs +------------------------------------------------------ @@ -650,19 +534,16 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. % emacs -f gtags-mode - You must start emacs under the source tree described in "1.2. Preparation". -4.3. Basic usage - - It is resemble to the extended vi based nvi-1.34. +3.3. Basic usage o To go to func1, press 'ESC-t' and you can see a prompt in mini-buffer. - Then input tag name. + Then input the tag name. :tag func1 # ':tag ' is a prompt. ~~~~~ - o To go to referenced point of func1, press 'ESC-r'. + o To go to a point that references func1, press 'ESC-r'. :rtag func1 # 'rtag ' is a prompt ~~~~~ @@ -673,8 +554,8 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. :tag func1 # 'nc1' is appended by emacs - o If a number of functions located, emacs goes into 'GTAGS SELECT MODE' - like this. + o If a number of functions are located, emacs goes into 'GTAGS SELECT MODE' + like this: +------------------------------------------------------------- |main 347 i386/isa/ultra14f.c main() @@ -690,68 +571,400 @@ All the functions for GLOBAL are enabled only in 'gtagsmode'. |[GTAGS SELECT MODE] 4 lines +------------------------------------------------------------- - You can select a tag line by any emacs command and press [RETURN], - and you can go to the tag's point. When you want to go to next or - previous tag, you can return to 'GTAGS SELECT MODE' with + You can select a tag line by using any emacs command and pressing [RETURN], + and you can go to the tag's point. When you want to go to the next or + the previous tag, you can return to 'GTAGS SELECT MODE' with and reselect. o command is available. - If current token is a definition, it is identical to - ":rtag [RETURN]", otherwise ":tag [RETURN]". + If current token is a definition, it is equivalent to + ":rtag [RETURN]", otherwise it is equivalent to + ":tag [RETURN]". (GLOBAL decides this intelligentlly, but may sometimes misunderstand.) o To go to any symbols other than function, try 'ESC-s'. Find symbol: lbolt ~~~~~ - o To go to any strings other than symbol, try 'ESC-g'. + o To go to any strings other than symbols, try 'ESC-g'. Find pattern: Copyright ~~~~~~~~~ -4.4. Applied usage +3.4. Applied usage - o You can use POSIX regular expression (extension). + o You can use POSIX regular expressions. :tag ^put_ # locate tags start with 'put_'. - o If your source files are on a read only device like CDROM, please do - the followings. + o If your source files are on a read-only device like a CDROM, please do + the following: - % mkdir /var/dbpath <- directory for tag file - % cd /cdrom/src <- the root of source tree + % mkdir /var/dbpath <- directory for the tag file + % cd /cdrom/src <- the root of the source tree % gtags /var/dbpath <- make tag files in /var/dbpath % setenv GTAGSROOT `pwd` % setenv GTAGSDBPATH /var/dbpath - % mule -f gtags-mode + % emacs -f gtags-mode - o If you want to treat the references to the function that is not defined - in the source tree like library functions or system calls, - do the followings. + o If you want all references to functions that are not defined in the + source tree to be treated as references to library functions or + as system calls, do the following: % cd /usr/src/lib % gtags <- probably as a root % cd /usr/src/sys % gtags % setenv GTAGSLIBPATH /usr/src/lib:/usr/src/sys - % mule -f gtags-mode + % emacs -f gtags-mode - o mouse command is avalable. + o Mouse command is avalable. - If you use X version emacs, try this. - (But xemacs doesn't work well. I don't know why.) + If you use X version emacs, try the following + (but it doesn't work well in xemacs; I don't know why). - Move mouse cursor to a function name and click center button. And you - will go to function's definition or references depending on the context. - In 'GTAGS SELECT MODE', move mouse cursor to a line and click center - button. + Move the mouse cursor to a function name and click the middle button. + You will then go to the function's definition, or to its references, + depending on the context. In 'GTAGS SELECT MODE', move the mouse cursor + to a line and click the center button. - To return to the previous position, click right button. + To return to the previous position, click the right button. -Thank you for your reading of my poor english. -And of course, I'm grateful to all excellent tools (vi, emacs, perl, C, db, -mozilla ...) and its authors. +4. Hypertext generator + +4.1. Features + + o Htags makes hypertext from C, Yacc and Java source files. + o Once the hypertext is generated, you need nothing other than a WWW browser. + o You can move the hypertext to anywhere. It is independent of the source code. + o You can use all of your browser's functions, such as search, + history, bookmark, save, frames, windows. + +4.2. Preparation + + At first, you must ensure that you have a lot of disk space. Hypertext + needs a great amount of disk space. For example, the source code + of FreeBSD kernel needs: + + source code(/usr/src/sys) 14.0MB + + GTAGS 1.5MB + GRTAGS 8.0MB + GSYMS 12.0MB + HTML/ 55MB(!!!) + ------------------------------------------------- + total 77MB + + Please do the following: + + (at your source directory) + % gtags <- make the tag database(GTAGS,GRTAGS,GSYMS) + % htags <- make the hypertext(HTML/) + + Then you will find an 'HTML' subdirectory in the current directory. + +4.3. Usage + + Please start a web browser like this: + + % lynx HTML/index.html + + You will understand the usage by looking at the examples. + + You can move the HTML directory to anywhere. It is independent of the + source code. + +4.4. Making hypertext of the kernel + + If you would like to make hypertext of the FreeBSD kernel source, it is + convenient to use the systags script in this package. + + % cd /usr/src/sys + % systags + then + + % netscape HTML/index.html + + You can use following functions with systags: + + o An input form for a dynamic index. + (this reqires you to set up an httpd server for the CGI program.) + o Unlimited nested index. + + Of course, you can use the above functions without systags. Please + see gtags(1) and htags(1). + +4.5. Gozilla + + If you use Netscape Navigator, you can control the browser from the command + line by using gozilla(1). + + % gtags + % htags + % global -x fork + fork 60 kern/kern_fork.c fork(p, uap, retval) + % gozilla +60 kern/kern_fork.c + % + + Then you can see the hypertext specified around the fork function directly + on Netscape Navigator. If the browser has not been loaded, gozilla loads it. + + If you use another browser like lynx, try this: + + % gozilla -b lynx +60 kern/kern_fork.c + + or + + % setenv BROWSER lynx + % gozilla +60 kern/kern_fork.c + + You can send a remote command to Netscape Navigator too. Try this: + + % gozilla -C pagedown + % gozilla -C pageup + + The remote commands are undocumented, but you can see the hint in the + resource file (Netscape.ad). + + NOTES: + Netscape Navigator is a registered trademark of Netscape Communications + Corporation in the United States and other countries. + + +5. Elvis using global + +Elvis 2.1 has new "tagprg" and "tagprgonce" variables for +running an external tag search program. You can use them with GLOBAL. + +5.1. Features + + o The tag function of elvis+GLOBAL can locate not only function definitions + but also function references. + o Elvis+GLOBAL allows duplicate tag entries. + o Elvis+GLOBAL can understand POSIX regular expressions + as a tag name for the search. + o Symbol search and pattern search are available. + o Mouse events are supported. + +5.2. Preparation + + First, do the preparation of global. (Please see "1.2. Preparation"). + + Second, start elvis and execute 'set tagprg="global -t $1"' like this. + + % elvis + ~ + ~ + ~ + ~ + ~ + ~ + :set tagprg="global -t $1" + +5.3. Basic usage + + o To go to func1, you can say + + :tag func1 + + It seemes the same as original elvis, but elvis execute 'global -t func1' + internally and read it instead of tags file. + + o To go to the referenced point of func1, add -r option. + + :tag -r func1 + + Elvis executes command like 'global -t -r func1' internally. + + o To go to any symbols other than function, try this. + + :tag -s lbolt + + o To go to any strings other than symbols, try this. + + :tag -g Copyright + + o When using -r, -s or -g, you had better to use browse command. + + :browse -r fork + + It brings a following selection list. You can select tag and go to + the point. + + Browse -r fork (2 matches) + +----------------+----------------+------------------------------- + | TAG NAME | SOURCE FILE | SOURCE LINE + +----------------+----------------|------------------------------- + |fork |ux/linux_misc.c | (line 565) + |fork |ern/init_main.c | (line 191) + +----------------+----------------+------------------------------- + + o To get list of functions in a file, use -f command. + + :browse -f main.c # locate functions in main.c. + + o Other tag commands are also available: + + - go to the definition of current token. + - return to the most recent tag context. + ":tag" - without argment, go to the next tag. + ":pop" - return to the most recent tag context. + ":stack" - display the tags stack. + ":stag" - creates a new window and moves its cursor to the + tag's definition point. + ":sbrowse" - same with 'browse' but show in a new window. + +5.4. Applied usage + + o You can use POSIX regular expressions. + + :tag ^put_ # locate functions start with 'put_'. + + :browse -g 'fseek(.*L_SET)' # locate fseek() using L_SET argment. + + o You can browse functions list of many files. + + :browse -f *.c # locate functions in *.c. + + o You can browse project files which includs specified pattern. + + :browse -P ^vm/ # under vm/ directory. + :browse -P \.h$ # all include files. + :browse -P init # files including 'init' + + o You can use mouse to select tag. + + +----------------+----------------+------------------------------- + | TAG NAME | SOURCE FILE | SOURCE LINE + +----------------+----------------|------------------------------- + |fork |ux/linux_misc.c | (line 565) + |fork |ern/init_main.c | (line 191) + +----------------+----------------+------------------------------- + + Please select tag name with mouse cursor and double click on the left + button and you go to the tag's point. + In source screen, also select function name and double click on the + left button and you can go to the point that the function is defined. + To come back, double click on the right button. + +A. Other topics + +A.1. How to plug in a parser + + You can use a plugged-in parser. Copy global.conf to /etc/global.conf + or $HOME/.globalrc. + + For example, if you would like to use ctags based on etags (included + by Emacs), + + % cd //lib-src + % make ctags + # cp ctags /usr/local/bin/ctags-emacs + % setenv GTAGSLABEL ctags-emacs <- see global.conf + % gtags + % ls G* + GPATH GTAGS + + Or if you would like to use exuberant ctags (included by Vim editor), + + % cd //src/ctags + % cp Makefile.unix Makefile + % make + # cp ctags /usr/local/bin/ctags-exuberant + % setenv GTAGSLABEL ctags-exuberant <- see global.conf + % gtags + % ls G* + GPATH GTAGS + + GRTAGS and GSYMS don't exist, simply because these parsers don't support + the -r option and -s option like gctags(1) does. + All plugged-in parsers must print tag information to standard output + in the same style as 'ctags -x', ie.: + + [1] [2] [3] [4] + ---------------------------------------------------------------- + main 20 ./main.c main(argc, argv) /* xxx */ + + [1] tag name + [2] line number the tag appeared + [3] path name. It must be equal to argment path name. + [4] line image + + Otherwise, you can make a suitable wrapper for the pug-in parser. + +A.2. Compact format. + + You can save disk space with the compact format. The compact format + needs source files. + + o To specify the use of the compact format on the command line, + add the -c option: + + % gtags -c + + o To specify the use of the compact format in the configuration file: + + +---------------------------- + |... + |default:\ + | format=compact:... + + o If you will publish hypertext generated by htags then use the -c option + of htags too: + + % htags -c + + With the -c option, htags makes gzipped hypertext. + You need to set up an HTTP server so that gzipped files can be read + (see 'HTML/.htaccess.skel'). + + + Example: + + Standard Compact Compressed rate + ------------------------------------------------------- + GTAGS 1744896 bytes 720896 bytes -59% + GRTAGS 10133504 bytes 1409024 bytes -86% + GSYMS 11911168 bytes 9306112 bytes -22% + + Standard Compact Compressed rate + ------------------------------------------------------- + HTML/ 56618 kbytes 15219 kbytes -73% + +A.3. Incremental updating + + Modifying some source files, you need not remake whole tag files. + Instead, you can use incremental updating facility (-i option). + + % gtags + % cd kern + % vi tty.c # modify tty.c. + ... + :wq + % global -vi # -v means verbose. + [Sun Dec 6 16:27:47 JST 1998] Gtags started + Tag found in '/usr/src/sys'. + Incremental update. + Updating tags of 'kern/tty.c' ...GTAGS..GRTAGS..GSYMS.. Done. + Global databases have been modified. + [Sun Dec 6 16:28:30 JST 1998] Done. + % global -vi # try again. + [Sun Dec 6 16:28:48 JST 1998] Gtags started + Tag found in '/usr/src/sys'. + Incremental update. + Global databases are up to date. # do nothing. + [Sun Dec 6 16:28:52 JST 1998] Done. + +A.4. Plans for the furture + + Please see GLOBAL home page. + + + +Thank you for your reading. +And of course, I'm also grateful to all excellent tools (vi, ctags, emacs, +perl, C, db, mozilla ...) and its authors. ---------------------------------------------------------------------------- E-Mail: WWW: diff --git a/contrib/global/VERSION b/contrib/global/VERSION index fd6915cc46b5..761e16c13179 100644 --- a/contrib/global/VERSION +++ b/contrib/global/VERSION @@ -1 +1 @@ -2.24 +3.42 diff --git a/contrib/global/btreeop/Makefile b/contrib/global/btreeop/Makefile index 13ed84a42c1f..643a28737981 100644 --- a/contrib/global/btreeop/Makefile +++ b/contrib/global/btreeop/Makefile @@ -1,6 +1,3 @@ PROG= btreeop -CFLAGS+=-I${.CURDIR}/../lib -LDADD= $(LIBUTIL) -DPADD= $(LIBUTIL) .include diff --git a/contrib/global/btreeop/btreeop.1 b/contrib/global/btreeop/btreeop.1 index 0b2111fe1ef3..45b6e9f4225f 100644 --- a/contrib/global/btreeop/btreeop.1 +++ b/contrib/global/btreeop/btreeop.1 @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd Nov 26, 1997 +.Dd Nov 3, 1998 .Dt BTREEOP 1 .Os BSD 4 .Sh NAME @@ -40,7 +40,7 @@ .Op Fl C .Op Fl D[keyno] Ar key .Op Fl K[keyno] Ar key -.Op Fl L +.Op Fl L[2] .Op Fl k Ar prefix .Op Ar dbname .Sh DESCRIPTION @@ -66,21 +66,11 @@ create database and write records to it. delete records by the key. By default, keyno is 0 (primary key). .It Fl K[keyno] Ar key search records by the key. By default, keyno is 0 (primary key). -.It Fl L -list all primary keys. -Following two command lines are identical except that the latter is much faster. - - btreeop | awk '{print $1}' | uniq - - btreeop -L +.It Fl L[2] +list all primary keys. If '2' is specified, list all the key and data pairs. .It Fl k Ar prefix scan records which have the prefix as a primary key. This option is valid only with sequential read operation (-L command or non command). -Following two command lines are identical except that the latter is much faster. - - btreeop | awk '$1 ~ /^fo/ {print }' - - btreeop -k fo .It Ar dbname database name. default is 'btree'. .Sh DATA FORMAT diff --git a/contrib/global/btreeop/btreeop.c b/contrib/global/btreeop/btreeop.c index 18160fb8c714..2b21cfcde5e7 100644 --- a/contrib/global/btreeop/btreeop.c +++ b/contrib/global/btreeop/btreeop.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved. + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,9 +28,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * btreeop.c 6-Nov-97 + * btreeop.c 12-Nov-98 * */ +#include #include #include @@ -38,21 +39,20 @@ #include #include -#include "dbio.h" #include "global.h" -char *dbdefault = "btree"; /* default database name */ -char *progname = "btreeop"; /* command name */ +const char *dbdefault = "btree"; /* default database name */ +const char *progname = "btreeop"; /* command name */ static void usage __P((void)); void signal_setup __P((void)); void onintr __P((int)); -void main __P((int, char **)); -void dbwrite __P((DBIO *)); -void dbkey __P((DBIO *, char *, int)); -void dbscan __P((DBIO *, char *, int)); -void dbdel __P((DBIO *, char *, int)); -void dbbysecondkey __P((DBIO *, int, char *, int)); +int main __P((int, char **)); +void dbwrite __P((DBOP *)); +void dbkey __P((DBOP *, char *, int)); +void dbscan __P((DBOP *, char *, int)); +void dbdel __P((DBOP *, char *, int)); +void dbbysecondkey __P((DBOP *, int, char *, int)); #define F_KEY 0 #define F_DEL 1 @@ -61,7 +61,7 @@ static void usage() { fprintf(stderr, "%s\n", - "usage: btreeop [-A][-C][-D[n] key][-K[n] key][-L][-k prefix][dbname]"); + "usage: btreeop [-A][-C][-D[n] key][-K[n] key][-L[2]][-k prefix][dbname]"); exit(1); } @@ -86,7 +86,7 @@ signal_setup() signal(SIGTERM, onintr); } -void +int main(argc, argv) int argc; char *argv[]; @@ -94,11 +94,12 @@ char *argv[]; char command = 'R'; char *key = NULL; int mode = 0; - char *dbname; - DBIO *dbio; + const char *db_name; + DBOP *dbop; int i, c; int secondkey = 0; - char *prefix = (char *)0; + int keylist = 0; + char *prefix = NULL; for (i = 1; i < argc && argv[i][0] == '-'; ++i) { switch (c = argv[i][1]) { @@ -106,22 +107,34 @@ char *argv[]; case 'K': if (argv[i][2] && isdigit(argv[i][2])) secondkey = atoi(&argv[i][2]); - key = argv[++i]; + if (++i < argc) + key = argv[i]; + else + usage(); + /* FALLTHROUGH */ case 'A': case 'C': case 'L': if (command != 'R') usage(); command = c; + if (command == 'L') { + keylist = 1; + if (argv[i][2] == '2') + keylist = 2; + } break; case 'k': - prefix = argv[++i]; + if (++i < argc) + prefix = argv[i]; + else + usage(); break; default: usage(); } } - dbname = (i < argc) ? argv[i] : dbdefault; + db_name = (i < argc) ? argv[i] : dbdefault; switch (command) { case 'A': case 'D': @@ -136,27 +149,35 @@ char *argv[]; mode = 0; break; } - dbio = db_open(dbname, mode, 0644, DBIO_DUP); - if (dbio == NULL) - die1("db_open failed (dbname = %s).", dbname); - + dbop = dbop_open(db_name, mode, 0644, DBOP_DUP); + if (dbop == NULL) { + switch (mode) { + case 0: + case 2: + die1("cannot open '%s'.", db_name); + break; + case 1: + die1("cannot create '%s'.", db_name); + break; + } + } switch (command) { case 'A': /* Append records */ case 'C': /* Create database */ - dbwrite(dbio); + dbwrite(dbop); break; case 'D': /* Delete records */ - dbdel(dbio, key, secondkey); + dbdel(dbop, key, secondkey); break; case 'K': /* Keyed (indexed) read */ - dbkey(dbio, key, secondkey); + dbkey(dbop, key, secondkey); break; case 'R': /* sequencial Read */ case 'L': /* primary key List */ - dbscan(dbio, prefix, (command == 'L') ? 1 : 0); + dbscan(dbop, prefix, keylist); break; } - db_close(dbio); + dbop_close(dbop); if (exitflag) exit(1); exit(0); @@ -164,11 +185,11 @@ char *argv[]; /* * dbwrite: write to database * - * i) dbio database + * i) dbop database */ void -dbwrite(dbio) -DBIO *dbio; +dbwrite(dbop) +DBOP *dbop; { char *p; char keybuf[MAXKEYLEN+1]; @@ -194,7 +215,7 @@ DBIO *dbio; * +------------------ * | __.VERSION 2 */ - while ((p = mgets(stdin, 0, NULL)) != NULL) { + while ((p = mgets(stdin, NULL, 0)) != NULL) { if (exitflag) break; c = p; @@ -215,89 +236,93 @@ DBIO *dbio; if (*c == 0) die("data part is null."); entab(p); - db_put(dbio, keybuf, p); + dbop_put(dbop, keybuf, p); } } /* * dbkey: Keyed search * - * i) dbio database + * i) dbop database * i) skey key for search * i) secondkey 0: primary key, >0: secondary key */ void -dbkey(dbio, skey, secondkey) -DBIO *dbio; +dbkey(dbop, skey, secondkey) +DBOP *dbop; char *skey; int secondkey; { char *p; if (!secondkey) { - for (p = db_first(dbio, skey, 0); p; p = db_next(dbio)) + for (p = dbop_first(dbop, skey, 0); p; p = dbop_next(dbop)) detab(stdout, p); return; } - dbbysecondkey(dbio, F_KEY, skey, secondkey); + dbbysecondkey(dbop, F_KEY, skey, secondkey); } /* * dbscan: Scan records * - * i) dbio database + * i) dbop database * i) prefix prefix of primary key - * i) keylist 0: key and data, 1: primary key only + * i) keylist 0: data, 1: key, 2: key and data */ void -dbscan(dbio, prefix, keylist) -DBIO *dbio; +dbscan(dbop, prefix, keylist) +DBOP *dbop; char *prefix; int keylist; { char *p; - int flags = DBIO_SKIPMETA; + int flags = 0; if (prefix) - flags |= DBIO_PREFIX; + flags |= DBOP_PREFIX; if (keylist) - flags |= DBIO_KEY; + flags |= DBOP_KEY; - for (p = db_first(dbio, prefix, flags); p; p = db_next(dbio)) - detab(stdout, p); + for (p = dbop_first(dbop, prefix, flags); p; p = dbop_next(dbop)) { + if (keylist == 2) + fprintf(stdout, "%s %s\n", p, dbop->lastdat); + else + detab(stdout, p); + } } /* * dbdel: Delete records * - * i) dbio database + * i) dbop database * i) skey key for search * i) secondkey 0: primary key, >0: secondary key */ void -dbdel(dbio, skey, secondkey) -DBIO *dbio; +dbdel(dbop, skey, secondkey) +DBOP *dbop; char *skey; int secondkey; { signal_setup(); if (!secondkey) { - db_del(dbio, skey); + dbop_del(dbop, skey); return; } - dbbysecondkey(dbio, F_DEL, skey, secondkey); + dbbysecondkey(dbop, F_DEL, skey, secondkey); } /* * dbbysecondkey: proc by second key * - * i) dbio database + * i) dbop database * i) func F_KEY, F_DEL * i) skey * i) secondkey */ void -dbbysecondkey(dbio, func, skey, secondkey) -DBIO *dbio; +dbbysecondkey(dbop, func, skey, secondkey) +DBOP *dbop; int func; char *skey; int secondkey; @@ -312,7 +337,7 @@ int secondkey; for (c = skey+strlen(skey)-1; *c && isspace(*c); c--) *c = 0; - for (p = db_first(dbio, NULL, DBIO_SKIPMETA); p; p = db_next(dbio)) { + for (p = dbop_first(dbop, NULL, 0); p; p = dbop_next(dbop)) { if (exitflag) break; c = p; @@ -334,7 +359,7 @@ int secondkey; detab(stdout, p); break; case F_DEL: - db_del(dbio, NULL); + dbop_del(dbop, NULL); break; } } diff --git a/contrib/global/dbpatches/README b/contrib/global/dbpatches/README new file mode 100644 index 000000000000..b1e9116db9a3 --- /dev/null +++ b/contrib/global/dbpatches/README @@ -0,0 +1,37 @@ +Patch for btree(3) +------------------ + +Btree(3) core dumps on certain data sets. + +if (your system == FreeBSD 2.2.6R or former) + needs this patch. +else if (your system == Debian GNU/Linux 1.3.1) + needs this patch. +else + I don't know. + +Please apply patch files in this directory. + +1. patch your btree(3) source code + + % ls + patch.1.2 patch.1.3 patch.1.4 + % set dir=`pwd` <- set current directory + % cd /usr/src/lib/libc/db <- your db source code directory + % cd btree <- btree library + % patch < $dir/patch.1.2 <- it must be in this order. + . + . + % patch < $dir/patch.1.3 + . + . + % patch < $dir/patch.1.4 + . + . + +2. remake and install your db(3) library. +3. remake GLOBAL. +4. remake tag files because tag files are already corrupted. + +I derived these patches from 'http://www.sleepycat.com/update/'. +Information is found on 'http://www.sleepycat.com/update/patch.185.html'. diff --git a/contrib/global/dbpatches/patch.1.2 b/contrib/global/dbpatches/patch.1.2 new file mode 100644 index 000000000000..a3439090f125 --- /dev/null +++ b/contrib/global/dbpatches/patch.1.2 @@ -0,0 +1,19 @@ +*** btree/bt_split.c Tue Jul 26 14:22:02 1994 +--- btree/bt_split.c Sat Jan 4 14:38:55 1997 +*************** +*** 673,679 **** + * where we decide to try and copy too much onto the left page. + * Make sure that doesn't happen. + */ +! if (skip <= off && used + nbytes >= full) { + --off; + break; + } +--- 673,679 ---- + * where we decide to try and copy too much onto the left page. + * Make sure that doesn't happen. + */ +! if (skip <= off && used + nbytes >= full || nxt == top - 1) { + --off; + break; + } diff --git a/contrib/global/dbpatches/patch.1.3 b/contrib/global/dbpatches/patch.1.3 new file mode 100644 index 000000000000..5ca03df2207b --- /dev/null +++ b/contrib/global/dbpatches/patch.1.3 @@ -0,0 +1,37 @@ +*** btree/bt_split.c.orig Sat Feb 8 10:14:10 1997 +--- btree/bt_split.c Sat Feb 8 10:14:51 1997 +*************** +*** 673,679 **** + * where we decide to try and copy too much onto the left page. + * Make sure that doesn't happen. + */ +! if (skip <= off && used + nbytes >= full || nxt == top - 1) { + --off; + break; + } +--- 673,680 ---- + * where we decide to try and copy too much onto the left page. + * Make sure that doesn't happen. + */ +! if (skip <= off && +! used + nbytes + sizeof(indx_t) >= full || nxt == top - 1) { + --off; + break; + } +*************** +*** 686,692 **** + memmove((char *)l + l->upper, src, nbytes); + } + +! used += nbytes; + if (used >= half) { + if (!isbigkey || bigkeycnt == 3) + break; +--- 687,693 ---- + memmove((char *)l + l->upper, src, nbytes); + } + +! used += nbytes + sizeof(indx_t); + if (used >= half) { + if (!isbigkey || bigkeycnt == 3) + break; diff --git a/contrib/global/dbpatches/patch.1.4 b/contrib/global/dbpatches/patch.1.4 new file mode 100644 index 000000000000..cec5fbc559bd --- /dev/null +++ b/contrib/global/dbpatches/patch.1.4 @@ -0,0 +1,22 @@ +*** btree/bt_page.c.orig Wed Jul 13 21:29:02 1994 +--- btree/bt_page.c Wed Jun 11 20:14:43 1997 +*************** +*** 65,70 **** +--- 65,71 ---- + h->prevpg = P_INVALID; + h->nextpg = t->bt_free; + t->bt_free = h->pgno; ++ F_SET(t, B_METADIRTY); + + /* Make sure the page gets written back. */ + return (mpool_put(t->bt_mp, h, MPOOL_DIRTY)); +*************** +*** 92,97 **** +--- 93,99 ---- + (h = mpool_get(t->bt_mp, t->bt_free, 0)) != NULL) { + *npg = t->bt_free; + t->bt_free = h->nextpg; ++ F_SET(t, B_METADIRTY); + return (h); + } + return (mpool_new(t->bt_mp, npg)); diff --git a/contrib/global/gctags/C.c b/contrib/global/gctags/C.c index c2d59f1f5aed..17df1accd5d7 100644 --- a/contrib/global/gctags/C.c +++ b/contrib/global/gctags/C.c @@ -1,6 +1,5 @@ /* - * Copyright (c) 1987, 1993, 1994 - * The Regents of the University of California. All rights reserved. + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,8 +11,7 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * This product includes software developed by Shigio Yamaguchi. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -29,49 +27,52 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * C.c 12-Sep-98 */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)C.c 8.4 (Berkeley) 4/2/94"; -#endif /* LIBC_SCCS and not lint */ - #include #include #include #include #include -#include "ctags.h" -#include "lookup.h" +#include "C.h" +#include "gctags.h" +#include "defined.h" +#include "die.h" +#include "locatestring.h" +#include "strbuf.h" +#include "token.h" -static int func_entry __P((void)); -static void hash_entry __P((void)); -static void skip_string __P((int)); -static int str_entry __P((int)); -#ifdef GLOBAL -static int cmp __P((const void *, const void *)); -static int isstatement __P((char *)); -static void define_line __P((void)); -#endif +static int function_definition __P((int)); +static void condition_macro __P((int)); +static int reserved __P((char *)); -#ifdef YACC -extern int yaccfile; /* true when *.y file */ -#endif /* - * c_entries -- - * read .c and .h files and call appropriate routines + * #ifdef stack. + */ +static struct { + short start; /* level when #if block started */ + short end; /* level when #if block end */ + short if0only; /* #if 0 or notdef only */ +} stack[MAXPIFSTACK], *cur; +static int piflevel; /* condition macro level */ +static int level; /* brace level */ + +/* + * C: read C (includes .h, .y) file and pickup tag entries. */ void -c_entries() +C(yacc) + int yacc; { - int c; /* current character */ - int level; /* brace level */ - int token; /* if reading a token */ - int t_def; /* if reading a typedef */ - int t_level; /* typedef's brace level */ - char *sp; /* buffer pointer */ - char tok[MAXTOKEN]; /* token buffer */ -#ifdef YACC + int c, cc; + int savelevel; + int target; + int startmacro, startsharp; + const char *interested = "{}=;"; + STRBUF *sb = stropen(); /* * yacc file format is like the following. * @@ -82,805 +83,395 @@ c_entries() * programs * */ -#define DECLARATIONS 0 -#define RULES 1 -#define PROGRAMS 2 - int yaccstatus = (yaccfile) ? DECLARATIONS : PROGRAMS; - int inyacc = (yaccfile) ? YES : NO; /* NO while C source */ -#endif + int yaccstatus = (yacc) ? DECLARATIONS : PROGRAMS; + int inC = (yacc) ? 0 : 1; /* 1 while C source */ - lineftell = ftell(inf); - sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1; - while (GETC(!=, EOF)) { - switch (c) { - /* - * Here's where it DOESN'T handle: { - * foo(a) - * { - * #ifdef notdef - * } - * #endif - * if (a) - * puts("hello, world"); - * } - */ - case '{': -#ifdef YACC - if (yaccstatus == RULES && level == 0) - inyacc = NO; -#endif - ++level; - goto endtok; - case '}': - /* - * if level goes below zero, try and fix - * it, even though we've already messed up - */ - if (--level < 0) - level = 0; -#ifdef GLOBAL - /* - * -e flag force a function to end when a '}' appear - * at column 0. If -e flag not specified, all functions - * after funcA() would be lost. - * - * funcA() { - * #ifdef A - * if (a) { - * ... - * #else - * if (nota) { - * ... - * #endif - * } - * } - */ - if (eflag && ftell(inf) == lineftell+1) { - level = 0; + level = piflevel = 0; + savelevel = -1; + target = (sflag) ? SYM : (rflag) ? REF : DEF; + startmacro = startsharp = 0; + cmode = 1; /* allow token like '#xxx' */ + crflag = 1; /* require '\n' as a token */ + if (yacc) + ymode = 1; /* allow token like '%xxx' */ + + while ((cc = nexttoken(interested, reserved)) != EOF) { + switch (cc) { + case SYMBOL: /* symbol */ + if (inC && peekc(0) == '('/* ) */) { + if (isnotfunction(token)) { + if (target == REF && defined(token)) + PUT(token, lineno, sp); + } else if (level > 0 || startmacro) { + if (target == REF && defined(token)) + PUT(token, lineno, sp); + } else if (level == 0 && !startmacro && !startsharp) { + char savetok[MAXTOKEN], *saveline; + int savelineno = lineno; + + strcpy(savetok, token); + strstart(sb); + strnputs(sb, sp, strlen(sp) + 1); + saveline = strvalue(sb); + if (function_definition(target)) + if (target == DEF) + PUT(savetok, savelineno, saveline); + } + } else { + if (target == SYM) + PUT(token, lineno, sp); } -#endif -#if YACC - if (yaccstatus == RULES && level == 0) - inyacc = YES; -#endif - goto endtok; - - case '\n': - SETLINE; - /* - * the above 3 cases are similar in that they - * are special characters that also end tokens. - */ - endtok: if (sp > tok) { - *sp = EOS; - token = YES; - sp = tok; - } - else - token = NO; - continue; - - /* - * We ignore quoted strings and character constants - * completely. - */ - case '"': - case '\'': - (void)skip_string(c); break; - - /* - * comments can be fun; note the state is unchanged after - * return, in case we found: - * "foo() XX comment XX { int bar; }" - */ - case '/': - if (GETC(==, '*')) { - skip_comment(); - continue; + case '{': /* } */ + DBG_PRINT(level, "{"); /* } */ + if (yaccstatus == RULES && level == 0) + inC = 1; + ++level; + if (bflag && atfirst) { + if (wflag && level != 1) /* { */ + fprintf(stderr, "Warning: forced level 1 block start by '{' at column 0 [+%d %s].\n", lineno, curfile); + level = 1; } - (void)ungetc(c, inf); - c = '/'; - goto storec; - - /* hash marks flag #define's. */ - case '#': - if (sp == tok) { - hash_entry(); + break; + /* { */ + case '}': + if (--level < 0) { + if (wflag) + fprintf(stderr, "Warning: missing left '{' [+%d %s].\n", lineno, curfile); /* } */ + level = 0; + } + if (eflag && atfirst) { + if (wflag && level != 0) /* { */ + fprintf(stderr, "Warning: forced level 0 block end by '}' at column 0 [+%d %s].\n", lineno, curfile); + level = 0; + } + if (yaccstatus == RULES && level == 0) + inC = 0; + /* { */ + DBG_PRINT(level, "}"); + break; + case '\n': + if (startmacro && level != savelevel) { + if (wflag) + fprintf(stderr, "Warning: different level before and after #define macro. reseted. [+%d %s].\n", lineno, curfile); + level = savelevel; + } + startmacro = startsharp = 0; + break; + case YACC_SEP: /* %% */ + if (level != 0) { + if (wflag) + fprintf(stderr, "Warning: forced level 0 block end by '%%' [+%d %s].\n", lineno, curfile); + level = 0; + } + if (yaccstatus == DECLARATIONS) { + if (target == DEF) + PUT("yyparse", lineno, sp); + yaccstatus = RULES; + } else if (yaccstatus == RULES) + yaccstatus = PROGRAMS; + inC = (yaccstatus == PROGRAMS) ? 1 : 0; + break; + case YACC_BEGIN: /* %{ */ + if (level != 0) { + if (wflag) + fprintf(stderr, "Warning: forced level 0 block end by '%%{' [+%d %s].\n", lineno, curfile); + level = 0; + } + if (inC == 1 && wflag) + fprintf(stderr, "Warning: '%%{' appeared in C mode. [+%d %s].\n", lineno, curfile); + inC = 1; + break; + case YACC_END: /* %} */ + if (level != 0) { + if (wflag) + fprintf(stderr, "Warning: forced level 0 block end by '%%}' [+%d %s].\n", lineno, curfile); + level = 0; + } + if (inC == 0 && wflag) + fprintf(stderr, "Warning: '%%}' appeared in Yacc mode. [+%d %s].\n", lineno, curfile); + inC = 0; + break; + /* + * #xxx + */ + case CP_DEFINE: + startmacro = 1; + savelevel = level; + if ((c = nexttoken(interested, reserved)) != SYMBOL) { + pushbacktoken(); break; } - goto storec; - - /* - * if we have a current token, parenthesis on - * level zero indicates a function. -#ifdef GLOBAL - * in the case of rflag == 1, if we have a current token, - * parenthesis on level > zero indicates a function reference. -#endif -#ifdef YACC - * inyacc == NO while C source. -#endif - */ - case '(': -#ifdef GLOBAL - if (sflag) + if (peekc(1) == '('/* ) */) { + if (target == DEF) + PUT(token, lineno, sp); + while ((c = nexttoken("()", reserved)) != EOF && c != '\n' && c != /* ( */ ')') + if (c == SYMBOL && target == SYM) + PUT(token, lineno, sp); + if (c == '\n') + pushbacktoken(); + } + break; + case CP_INCLUDE: + case CP_ERROR: + case CP_LINE: + case CP_PRAGMA: + while ((c = nexttoken(interested, reserved)) != EOF && c != '\n') + ; + break; + case CP_IFDEF: + case CP_IFNDEF: + case CP_IF: + case CP_ELIF: + case CP_ELSE: + case CP_ENDIF: + case CP_UNDEF: + condition_macro(cc); + while ((c = nexttoken(interested, reserved)) != EOF && c != '\n') { + if (!((cc == CP_IF || cc == CP_ELIF) && !strcmp(token, "defined"))) + continue; + if (c == SYMBOL && target == SYM) + PUT(token, lineno, sp); + } + break; + case CP_SHARP: /* ## */ + (void)nexttoken(interested, reserved); + break; + case C_STRUCT: + c = nexttoken(interested, reserved); + if (c == '{' /* } */) { + pushbacktoken(); break; -#endif -#ifdef YACC - if (inyacc == NO) -#endif -#ifdef GLOBAL - if (!rflag && !level && token) -#else - if (!level && token) -#endif - { - int curline; - - if (sp != tok) - *sp = EOS; - /* - * grab the line immediately, we may - * already be wrong, for example, - * foo\n - * (arg1, - */ - getline(); - curline = lineno; -#ifdef GLOBAL - /* to make sure. */ - if (!isstatement(tok)) -#endif - if (func_entry()) { - ++level; - pfnote(tok, curline); + } + if (c == SYMBOL) + if (target == SYM) + PUT(token, lineno, sp); + break; + case C_EXTERN: + if (startmacro) + break; + while ((c = nexttoken(interested, reserved)) != EOF && c != ';') { + switch (c) { + case CP_IFDEF: + case CP_IFNDEF: + case CP_IF: + case CP_ELIF: + case CP_ELSE: + case CP_ENDIF: + case CP_UNDEF: + condition_macro(c); + continue; } - break; + if (startmacro && c == '\n') + break; + if (c == '{') + level++; + else if (c == '}') + level--; + else if (c == SYMBOL) + if (target == SYM) + PUT(token, lineno, sp); } -#ifdef GLOBAL - else if (rflag && level && token) { - if (sp != tok) - *sp = EOS; - if (!isstatement(tok) && lookup(tok)) { - getline(); - pfnote(tok, lineno); - } - break; - } -#endif - goto storec; - - /* - * semi-colons indicate the end of a typedef; if we find a - * typedef we search for the next semi-colon of the same - * level as the typedef. Ignoring "structs", they are - * tricky, since you can find: - * - * "typedef long time_t;" - * "typedef unsigned int u_int;" - * "typedef unsigned int u_int [10];" - * - * If looking at a typedef, we save a copy of the last token - * found. Then, when we find the ';' we take the current - * token if it starts with a valid token name, else we take - * the one we saved. There's probably some reasonable - * alternative to this... - */ - case ';': - if (t_def && level == t_level) { - t_def = NO; - getline(); - if (sp != tok) - *sp = EOS; - pfnote(tok, lineno); - break; - } - goto storec; - -#if YACC - case '%': - if (yaccstatus == DECLARATIONS || yaccstatus == RULES) { - if (GETC(==, '%')) { - level = 0; - if (yaccstatus == DECLARATIONS) { - if (!rflag) { - getline(); - pfnote("yyparse", lineno); - } - yaccstatus = RULES; - } else if (yaccstatus == RULES) { - yaccstatus = PROGRAMS; - } - inyacc = (yaccstatus == PROGRAMS) ? NO : YES; - } else if (c == '{') { - level = 0; - inyacc = NO; - } else if (c == '}') { - level = 0; - inyacc = YES; - } else { - (void)ungetc(c, inf); - } - break; - } - /* else fall throuth */ -#endif - /* - * store characters until one that can't be part of a token - * comes along; check the current token against certain - * reserved words. - */ + break; + /* control statement check */ + case C_BREAK: + case C_CASE: + case C_CONTINUE: + case C_DEFAULT: + case C_DO: + case C_ELSE: + case C_FOR: + case C_GOTO: + case C_IF: + case C_RETURN: + case C_SWITCH: + case C_WHILE: + if (wflag && !startmacro && level == 0) + fprintf(stderr, "Warning: Out of function. %8s [+%d %s]\n", token, lineno, curfile); + break; default: - /* ignore whitespace */ - if (c == ' ' || c == '\t') { - int save = c; - while (GETC(!=, EOF) && (c == ' ' || c == '\t')) - ; - if (c == EOF) - return; - (void)ungetc(c, inf); - c = save; - } - storec: if (!intoken(c)) { - if (sp == tok) - break; - *sp = EOS; -#ifdef GLOBAL - /* ignore assembler in C source */ - if (!memcmp(tok, "_asm",4)) { - while (GETC(!=, EOF) && (c == ' ' || c == '\t')) - ; - if (c == EOF) - return; - if (c == '{') { - while (GETC(!=, EOF) && c != '}') { - if (c == '\n') - SETLINE; - } - } else { - while (GETC(!=, EOF) && c != '\n') - ; - if (c == '\n') - SETLINE; - } - if (c == EOF) - return; - break; - } - if (sflag) { - if (!isstatement(tok)) { - getline(); - pfnote(tok, lineno); - } - break; - } - if (!memcmp(tok, "extern",7)) { - while (GETC(!=, EOF) && c != ';') { - if (c == '\n') - SETLINE; - } - if (c == EOF) - return; - break; - } -#endif - if (tflag) { - /* no typedefs inside typedefs */ - if (!t_def && - !memcmp(tok, "typedef",8)) { - t_def = YES; - t_level = level; - break; - } - /* catch "typedef struct" */ - if ((!t_def || t_level < level) - && (!memcmp(tok, "struct", 7) - || !memcmp(tok, "union", 6) - || !memcmp(tok, "enum", 5))) { - /* - * get line immediately; - * may change before '{' - */ - getline(); - if (str_entry(c)) - ++level; - break; - /* } */ - } - } - sp = tok; - } - else if (sp != tok || begtoken(c)) { - *sp++ = c; - token = YES; - } -#ifdef GLOBAL - /* skip hex number */ - else if (sp == tok && c == '0') { - if (GETC(==, 'x') || c == 'X') { - while (GETC(!=, EOF) && isxdigit(c)) - ; - if (c == EOF) - return; - } - (void)ungetc(c, inf); - } -#endif - continue; - /* end of default */ - } /* end of switch */ - /* - * 'break' statement in switch block come here. - */ - sp = tok; - token = NO; - } /* end of while */ + } + } + strclose(sb); + if (wflag) { + if (level != 0) + fprintf(stderr, "Warning: {} block unmatched. (last at level %d.)[+%d %s]\n", level, lineno, curfile); + if (piflevel != 0) + fprintf(stderr, "Warning: #if block unmatched. (last at level %d.)[+%d %s]\n", piflevel, lineno, curfile); + } } - /* - * func_entry -- - * handle a function reference + * function_definition: return if function definition or not. + * + * r) target type */ static int -func_entry() +function_definition(target) +int target; { - int c; /* current character */ - int level = 0; /* for matching '()' */ + int c; + int brace_level, isdefine; - /* - * Find the end of the assumed function declaration. - * Note that ANSI C functions can have type definitions so keep - * track of the parentheses nesting level. - */ - while (GETC(!=, EOF)) { + brace_level = isdefine = 0; + while ((c = nexttoken("(,)", reserved)) != EOF) { switch (c) { - case '\'': - case '"': - /* skip strings and character constants */ - skip_string(c); - break; - case '/': - /* skip comments */ - if (GETC(==, '*')) - skip_comment(); - break; - case '(': - level++; - break; - case ')': - if (level == 0) - goto fnd; - level--; - break; - case '\n': - SETLINE; + case CP_IFDEF: + case CP_IFNDEF: + case CP_IF: + case CP_ELIF: + case CP_ELSE: + case CP_ENDIF: + case CP_UNDEF: + condition_macro(c); + continue; + } + if (c == '('/* ) */) + brace_level++; + else if (c == /* ( */')') { + if (--brace_level == 0) + break; + } else if (c == SYMBOL) { + if (target == SYM) + PUT(token, lineno, sp); } } - return (NO); -fnd: - /* - * we assume that the character after a function's right paren - * is a token character if it's a function and a non-token - * character if it's a declaration. Comments don't count... - */ - for (;;) { - while (GETC(!=, EOF) && iswhite(c)) - if (c == '\n') - SETLINE; - if (intoken(c) || c == '{') - break; - if (c == '/' && GETC(==, '*')) - skip_comment(); - else { /* don't ever "read" '/' */ - (void)ungetc(c, inf); - return (NO); + if (c == EOF) + return 0; + while ((c = nexttoken(",;{}=", reserved)) != EOF) { + switch (c) { + case CP_IFDEF: + case CP_IFNDEF: + case CP_IF: + case CP_ELIF: + case CP_ELSE: + case CP_ENDIF: + case CP_UNDEF: + condition_macro(c); + continue; } + if (c == SYMBOL || IS_RESERVED(c)) + isdefine = 1; + else if (c == ';' || c == ',') { + if (!isdefine) + break; + } else if (c == '{' /* } */) { + pushbacktoken(); + return 1; + } else if (c == /* { */'}') { + break; + } else if (c == '=') + break; } - if (c != '{') - (void)skip_key('{'); - return (YES); + return 0; } /* - * hash_entry -- - * handle a line starting with a '#' + * condition_macro: + * + * i) cc token */ static void -hash_entry() +condition_macro(cc) + int cc; { - int c; /* character read */ - int curline; /* line started on */ - char *sp; /* buffer pointer */ - char tok[MAXTOKEN]; /* storage buffer */ - - /* ignore leading whitespace */ - while (GETC(!=, EOF) && (c == ' ' || c == '\t')) - ; - (void)ungetc(c, inf); - curline = lineno; - for (sp = tok;;) { /* get next token */ - if (GETC(==, EOF)) - return; - if (iswhite(c)) - break; - *sp++ = c; - } - *sp = EOS; -#ifdef GLOBAL - if (sflag && memcmp(tok, "include", 7)) { - (void)ungetc(c, inf); - define_line(); - return; - } -#endif - if (memcmp(tok, "define", 6)) /* only interested in #define's */ - goto skip; - - for (;;) { /* this doesn't handle "#define \n" */ - if (GETC(==, EOF)) - return; - if (!iswhite(c)) - break; - } - for (sp = tok;;) { /* get next token */ - *sp++ = c; - if (GETC(==, EOF)) - return; - /* - * this is where it DOESN'T handle - * "#define \n" - */ - if (!intoken(c)) - break; - } - *sp = EOS; -#ifdef GLOBAL - if (rflag) { - /* - * #define XXX\n - */ - if (c == '\n') { - SETLINE; - return; + cur = &stack[piflevel]; + if (cc == CP_IFDEF || cc == CP_IFNDEF || cc == CP_IF) { + DBG_PRINT(piflevel, "#if"); + if (++piflevel >= MAXPIFSTACK) + die1("#if stack over flow. [%s]", curfile); + ++cur; + cur->start = level; + cur->end = -1; + cur->if0only = 0; + if (peekc(0) == '0') + cur->if0only = 1; + else if ((cc = nexttoken(NULL, reserved)) == SYMBOL && !strcmp(token, "notdef")) + cur->if0only = 1; + else + pushbacktoken(); + } else if (cc == CP_ELIF || cc == CP_ELSE) { + DBG_PRINT(piflevel - 1, "#else"); + if (cur->end == -1) + cur->end = level; + else if (cur->end != level && wflag) + fprintf(stderr, "Warning: uneven level. [+%d %s]\n", lineno, curfile); + level = cur->start; + cur->if0only = 0; + } else if (cc == CP_ENDIF) { + if (cur->if0only) + level = cur->start; + else if (cur->end != -1) { + if (cur->end != level && wflag) + fprintf(stderr, "Warning: uneven level. [+%d %s]\n", lineno, curfile); + level = cur->end; } - /* - * v - * #define XXX(X) XXXXXX - */ - if (c == '(') - (void)skip_key(')'); - /* - * v - * #define XXX(X) XXXXXX - */ - while (GETC(!=, EOF)) { - if (c != ' ' && c != '\t') { - (void)ungetc(c, inf); - break; - } - } - /* - * v - * #define XXX(X) XXXXXX - */ - define_line(); - return; + --piflevel; + DBG_PRINT(piflevel, "#endif"); } -#endif - if (dflag || c == '(') { /* only want macros */ - getline(); - pfnote(tok, curline); - } -skip: if (c == '\n') { /* get rid of rest of define */ - SETLINE - if (*(sp - 1) != '\\') - return; - } - (void)skip_key('\n'); } - -#ifdef GLOBAL /* sorted by alphabet */ -static struct words { - char *name; -} words[] = { - {"__P"}, - {"auto"}, - {"break"}, - {"case"}, - {"char"}, - {"continue"}, - {"default"}, - {"do"}, - {"double"}, - {"else"}, - {"extern"}, - {"float"}, - {"for"}, - {"goto"}, - {"if"}, - {"int"}, - {"long"}, - {"register"}, - {"return"}, - {"short"}, - {"sizeof"}, - {"static"}, - {"struct"}, - {"switch"}, - {"typedef"}, - {"union"}, - {"unsigned"}, - {"void"}, - {"while"}, +static struct words words[] = { + {"##", CP_SHARP}, + {"#define", CP_DEFINE}, + {"#elif", CP_ELIF}, + {"#else", CP_ELSE}, + {"#endif", CP_ENDIF}, + {"#error", CP_ERROR}, + {"#if", CP_IF}, + {"#ifdef", CP_IFDEF}, + {"#ifndef", CP_IFNDEF}, + {"#include", CP_INCLUDE}, + {"#line", CP_LINE}, + {"#pragma", CP_PRAGMA}, + {"#undef", CP_UNDEF}, + {"%%", YACC_SEP}, + {"%left", YACC_LEFT}, + {"%nonassoc", YACC_NONASSOC}, + {"%right", YACC_RIGHT}, + {"%start", YACC_START}, + {"%token", YACC_TOKEN}, + {"%type", YACC_TYPE}, + {"%{", YACC_BEGIN}, + {"%}", YACC_END}, + {"__P", C___P}, + {"auto", C_AUTO}, + {"break", C_BREAK}, + {"case", C_CASE}, + {"char", C_CHAR}, + {"continue", C_CONTINUE}, + {"default", C_DEFAULT}, + {"do", C_DO}, + {"double", C_DOUBLE}, + {"else", C_ELSE}, + {"extern", C_EXTERN}, + {"float", C_FLOAT}, + {"for", C_FOR}, + {"goto", C_GOTO}, + {"if", C_IF}, + {"int", C_INT}, + {"long", C_LONG}, + {"register", C_REGISTER}, + {"return", C_RETURN}, + {"short", C_SHORT}, + {"sizeof", C_SIZEOF}, + {"static", C_STATIC}, + {"struct", C_STRUCT}, + {"switch", C_SWITCH}, + {"typedef", C_TYPEDEF}, + {"union", C_UNION}, + {"unsigned", C_UNSIGNED}, + {"void", C_VOID}, + {"while", C_WHILE}, }; static int -cmp(s1, s2) - const void *s1, *s2; -{ - return strcmp(((struct words *)s1)->name, ((struct words *)s2)->name); -} - -static int -isstatement(token) - char *token; +reserved(word) + char *word; { struct words tmp; + struct words *result; - tmp.name = token; - if (bsearch(&tmp, words, sizeof(words)/sizeof(struct words), sizeof(struct words), cmp)) - return YES; - return NO; -} - -static void -define_line() -{ - int c; /* character read */ - int level; /* brace level */ - int token; /* if reading a token */ - char *sp; /* buffer pointer */ - char tok[MAXTOKEN]; /* storage buffer */ - - sp = tok; token = NO; level = 0; - while (GETC(!=, EOF)) { - switch (c) { - case '{': - ++level; - goto endtok; - case '}': - if (--level < 0) - level = 0; - goto endtok; - - case '\\': - if (GETC(==, '\n')) { - SETLINE; - } - continue; - - case '\n': - if (sflag && token) { - if (sp != tok) - *sp = EOS; - if (!isstatement(tok)) { - getline(); - pfnote(tok, lineno); - } - } - SETLINE; - return; - endtok: if (sp > tok) { - *sp = EOS; - token = YES; - sp = tok; - } - else - token = NO; - continue; - - case '"': - case '\'': - (void)skip_string(c); - break; - - case '/': - if (GETC(==, '*')) { - skip_comment(); - continue; - } - (void)ungetc(c, inf); - c = '/'; - goto storec; - - case '(': - if (sflag) - break; - if (token) { - if (sp != tok) - *sp = EOS; - getline(); - if (!isstatement(tok) && lookup(tok)) - pfnote(tok, lineno); - break; - } - goto storec; - - case ';': - goto storec; - - default: -storec: if (!intoken(c)) { - if (sp == tok) - break; - *sp = EOS; - sp = tok; - if (sflag) { - if (!isstatement(tok)) { - getline(); - pfnote(tok, lineno); - } - break; - } - } - else if (sp != tok || begtoken(c)) { - *sp++ = c; - token = YES; - } - continue; - } - - sp = tok; - token = NO; - } -} -#endif -/* - * str_entry -- - * handle a struct, union or enum entry - */ -static int -str_entry(c) - int c; /* current character */ -{ - int curline; /* line started on */ - char *sp; /* buffer pointer */ - char tok[LINE_MAX]; /* storage buffer */ - - curline = lineno; - while (iswhite(c)) - if (GETC(==, EOF)) - return (NO); - if (c == '{') /* it was "struct {" */ - return (YES); - for (sp = tok;;) { /* get next token */ - *sp++ = c; - if (GETC(==, EOF)) - return (NO); - if (!intoken(c)) - break; - } - switch (c) { - case '{': /* it was "struct foo{" */ - --sp; - break; - case '\n': /* it was "struct foo\n" */ - SETLINE; - /*FALLTHROUGH*/ - default: /* probably "struct foo " */ - while (GETC(!=, EOF)) - if (!iswhite(c)) - break; - if (c != '{') { - (void)ungetc(c, inf); - return (NO); - } - } - *sp = EOS; - pfnote(tok, curline); - return (YES); -} - -/* - * skip_comment -- - * skip over comment - */ -void -skip_comment() -{ - int c; /* character read */ - int star; /* '*' flag */ - - for (star = 0; GETC(!=, EOF);) - switch(c) { - /* comments don't nest, nor can they be escaped. */ - case '*': - star = YES; - break; - case '/': - if (star) - return; - break; - case '\n': - SETLINE; - /*FALLTHROUGH*/ - default: - star = NO; - break; - } -} - -/* - * skip_string -- - * skip to the end of a string or character constant. - */ -static void -skip_string(key) - int key; -{ - int c, - skip; - - for (skip = NO; GETC(!=, EOF); ) - switch (c) { - case '\\': /* a backslash escapes anything */ - skip = !skip; /* we toggle in case it's "\\" */ - break; - case '\n': - SETLINE; - /*FALLTHROUGH*/ - default: - if (c == key && !skip) - return; - skip = NO; - } -} - -/* - * skip_key -- - * skip to next char "key" - */ -int -skip_key(key) - int key; -{ - int c, - skip, - retval; - - for (skip = retval = NO; GETC(!=, EOF);) - switch(c) { - case '\\': /* a backslash escapes anything */ - skip = !skip; /* we toggle in case it's "\\" */ - break; - case ';': /* special case for yacc; if one */ - case '|': /* of these chars occurs, we may */ - retval = YES; /* have moved out of the rule */ - break; /* not used by C */ - case '\'': - case '"': - /* skip strings and character constants */ - skip_string(c); - break; - case '/': - /* skip comments */ - if (GETC(==, '*')) { - skip_comment(); - break; - } - (void)ungetc(c, inf); - c = '/'; - goto norm; - case '\n': - SETLINE; - /*FALLTHROUGH*/ - default: - norm: - if (c == key && !skip) - return (retval); - skip = NO; - } - return (retval); + tmp.name = word; + result = (struct words *)bsearch(&tmp, words, sizeof(words)/sizeof(struct words), sizeof(struct words), cmp); + return (result != NULL) ? result->val : SYMBOL; } diff --git a/contrib/global/gctags/C.h b/contrib/global/gctags/C.h new file mode 100644 index 000000000000..ae60948413e5 --- /dev/null +++ b/contrib/global/gctags/C.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Shigio Yamaguchi. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * C.h 20-Aug-98 + */ +#define DECLARATIONS 0 +#define RULES 1 +#define PROGRAMS 2 + +#define C___P 1001 +#define C_AUTO 1002 +#define C_BREAK 1003 +#define C_CASE 1004 +#define C_CHAR 1005 +#define C_CONTINUE 1006 +#define C_DEFAULT 1007 +#define C_DO 1008 +#define C_DOUBLE 1009 +#define C_ELSE 1010 +#define C_EXTERN 1011 +#define C_FLOAT 1012 +#define C_FOR 1013 +#define C_GOTO 1014 +#define C_IF 1015 +#define C_INT 1016 +#define C_LONG 1017 +#define C_REGISTER 1018 +#define C_RETURN 1019 +#define C_SHORT 1020 +#define C_SIZEOF 1021 +#define C_STATIC 1022 +#define C_STRUCT 1023 +#define C_SWITCH 1024 +#define C_TYPEDEF 1025 +#define C_UNION 1026 +#define C_UNSIGNED 1027 +#define C_VOID 1028 +#define C_WHILE 1029 +#define CP_ELIF 2001 +#define CP_ELSE 2002 +#define CP_DEFINE 2003 +#define CP_IF 2004 +#define CP_IFDEF 2005 +#define CP_IFNDEF 2006 +#define CP_INCLUDE 2007 +#define CP_PRAGMA 2008 +#define CP_SHARP 2009 +#define CP_ERROR 2010 +#define CP_UNDEF 2011 +#define CP_ENDIF 2012 +#define CP_LINE 2013 +#define YACC_SEP 3001 +#define YACC_BEGIN 3002 +#define YACC_END 3003 +#define YACC_LEFT 3004 +#define YACC_NONASSOC 3005 +#define YACC_RIGHT 3006 +#define YACC_START 3007 +#define YACC_TOKEN 3008 +#define YACC_TYPE 3009 + +#define IS_CTOKEN(c) (c > 1000 && c < 2001) +#define IS_CPTOKEN(c) (c > 2000 && c < 3001) +#define IS_YACCTOKEN(c) (c > 3000 && c < 4001) +#define MAXPIFSTACK 100 diff --git a/contrib/global/gctags/Makefile b/contrib/global/gctags/Makefile index bdecdfb7ffb6..18bc967ef894 100644 --- a/contrib/global/gctags/Makefile +++ b/contrib/global/gctags/Makefile @@ -1,7 +1,4 @@ PROG= gctags -CFLAGS+=-I${.CURDIR} -I${.CURDIR}/../lib -LDADD= $(LIBUTIL) -DPADD= $(LIBUTIL) -SRCS= C.c ctags.c fortran.c lisp.c print.c tree.c yacc.c assembler.c +SRCS= C.c assembler.c gctags.c java.c .include diff --git a/contrib/global/gctags/assembler.c b/contrib/global/gctags/assembler.c index 44d5aec69e58..7f2a532ec228 100644 --- a/contrib/global/gctags/assembler.c +++ b/contrib/global/gctags/assembler.c @@ -1,6 +1,5 @@ /* - * Copyright (c) 1987, 1993, 1994 - * The Regents of the University of California. All rights reserved. + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,8 +11,7 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * This product includes software developed by Shigio Yamaguchi. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -29,80 +27,111 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * assembler.c 20-Aug-98 */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)assembler.c 8.3 (Berkeley) 6/6/97"; -#endif /* LIBC_SCCS and not lint */ - #include #include #include -#include "ctags.h" -#include "lookup.h" +#include "gctags.h" +#include "defined.h" +#include "token.h" + +static int reserved __P((char *)); + +#define A_CALL 1001 +#define A_DEFINE 1002 +#define A_ENTRY 1003 +#define A_EXT 1004 +#define A_ALTENTRY 1005 -#ifdef GLOBAL void -asm_entries() +assembler() { - char *lbp; - char tok[MAXTOKEN]; - char *sp; + int c; + int target; + const char *interested = NULL; /* get all token */ + int startline = 1; + int level; /* not used */ - for (;;) { - lineftell = ftell(inf); - if (!fgets(lbuf, sizeof(lbuf), inf)) - return; - ++lineno; - if (rflag) { - /* extract only call EXT(xxx) or call _xxx */ - lbp = lbuf; - while (*lbp && isspace(*lbp)) - lbp++; - if (*lbp != 'c' || strncmp(lbp, "call", 4)) - continue; - lbp += 4; - while (*lbp && isspace(*lbp)) - lbp++; - sp = tok; - if (!strncmp(lbp, "EXT(" /* ) */, 4)) { - lbp += 4; - while (*lbp && intoken(*lbp)) - *sp++ = *lbp++; - if (*lbp != /* ( */ ')') - continue; - *sp = EOS; - } else if (*lbp == '_') { - lbp++; - while (*lbp && intoken(*lbp)) - *sp++ = *lbp++; - *sp = EOS; - } else - continue; - if (!lookup(tok)) - continue; - } else { - /* extract only ENTRY() and ALTENTRY(). */ - if (lbuf[0] != 'E' && lbuf[0] != 'A') - continue; - lbp = lbuf; - if (!strncmp(lbp, "ENTRY(", 6)) { - lbp += 6; - } else if (!strncmp(lbp, "ALTENTRY(", 9)) { - lbp += 9; - } else - continue; - sp = tok; - while (*lbp && intoken(*lbp)) - *sp++ = *lbp++; - if (*lbp != /* ( */ ')') - continue; - *sp = EOS; + level = 0; /* to satisfy compiler */ + /* symbol search doesn't supported. */ + if (sflag) + return; + target = (rflag) ? REF : DEF; + + cmode = 1; + crflag = 1; + + while ((c = nexttoken(interested, reserved)) != EOF) { + switch (c) { + case '\n': + startline = 1; + continue; + case A_CALL: + if (!startline || target != REF) + break; + if ((c = nexttoken(interested, reserved)) == A_EXT) { + if ((c = nexttoken(interested, reserved)) == '('/* ) */) + if ((c = nexttoken(interested, reserved)) == SYMBOL) + if (defined(token)) + PUT(token, lineno, sp); + } else if (c == SYMBOL && *token == '_') { + if (defined(&token[1])) + PUT(&token[1], lineno, sp); + } + break; + case A_ALTENTRY: + case A_ENTRY: + if (!startline || target != DEF) + break; + if ((c = nexttoken(interested, reserved)) == '('/* ) */) + if ((c = nexttoken(interested, reserved)) == SYMBOL) + if (peekc(1) == /* ( */ ')') + PUT(token, lineno, sp); + break; + case A_DEFINE: + if (!startline || target != DEF) + break; + if ((c = nexttoken(interested, reserved)) == SYMBOL) { + if (peekc(1) == '('/* ) */) { + PUT(token, lineno, sp); + while ((c = nexttoken(interested, reserved)) != EOF && c != '\n' && c != /* ( */ ')') + ; + while ((c = nexttoken(interested, reserved)) != EOF && c != '\n') + ; + } + } + default: } - getline(); - pfnote(tok, lineno); + startline = 0; } - /*NOTREACHED*/ } -#endif +static int +reserved(word) + char *word; +{ + switch (*word) { + case '#': + if (!strcmp(word, "#define")) + return A_DEFINE; + break; + case 'A': + if (!strcmp(word, "ALTENTRY")) + return A_ALTENTRY; + break; + case 'E': + if (!strcmp(word, "ENTRY")) + return A_ENTRY; + else if (!strcmp(word, "EXT")) + return A_EXT; + break; + case 'c': + if (!strcmp(word, "call")) + return A_CALL; + break; + } + return SYMBOL; +} diff --git a/contrib/global/gctags/gctags.1 b/contrib/global/gctags/gctags.1 index ed958751223a..31415c62536e 100644 --- a/contrib/global/gctags/gctags.1 +++ b/contrib/global/gctags/gctags.1 @@ -1,5 +1,5 @@ -.\" Copyright (c) 1987, 1990, 1993 -.\" The Regents of the University of California. All rights reserved. +.\" +.\" Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -11,8 +11,7 @@ .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. +.\" This product includes software developed by Shigio Yamaguchi. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -29,109 +28,67 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)gctags.1 8.1 (Berkeley) 6/6/93 .\" -.Dd April 21, 1997 +.Dd Aug 19, 1998 .Dt GCTAGS 1 .Os BSD 4 .Sh NAME .Nm gctags -.Nd create a tags file (special command for GLOBAL) +.Nd print cross reference list for gtags. .Sh SYNOPSIS .Nm gctags -.Op Fl BDFacderstuvwx -.Op Fl f Ar tagsfile -.Ar name ... +.Op Fl b +.Op Fl e +.Op Fl n +.Op Fl r +.Op Fl s +.Op Fl w +.Ar file ... .Sh DESCRIPTION .Nm Gctags -makes a tags file for -.Xr ex 1 +print cross reference list for +.Xr gtags 1 from the specified C, -Pascal, Fortran, .Tn YACC , -lex, lisp and assembler sources. -A tags file gives the locations of specified objects in a group of files. -Each line of the tags file contains the object name, the file in which it -is defined, and a search pattern for the object definition, separated by +.Tn JAVA , +and assembler source to standard output. +Each line of output contains the object name, the line number which it appears, +the file in which it is defined, and a line image separated by white-space. -Using the -.Ar tags -file, -.Xr ex 1 -can quickly locate these object definitions. +It's same with the output of +.Xr ctags 1 +with -x option. +.Pp Depending upon the options provided to .Nm gctags , -objects will consist of subroutines, typedefs, defines, structs, -enums and unions. +objects will consist of function definitions, function references and other +symbols. +This command is the default parser of GLOBAL source code tag system. .Bl -tag -width Ds -.It Fl B -use backward searching patterns -.Pq Li ?...? . -.It Fl D -allow duplicate object names. -.It Fl F -use forward searching patterns -.Pq Li /.../ -(the default). -.It Fl a -append to -.Ar tags -file. -.It Fl c -print with compact format. It is valid only with -x option. -.It Fl d -create tags for -.Li #defines -that don't take arguments; -.Li #defines -that take arguments are tagged automatically. +.It Fl b +force level 1 block to begin when reach a '{' at the first column. (C only) .It Fl e -force a function to end when reach a '}' at the first column. (C source only) -.It Fl f -place the tag descriptions in a file called -.Ar tagsfile . -The default behaviour is to place them in a file called -.Ar tags . +force level 1 block to end when reach a '}' at the first column. (C only) +.It Fl n +suppress output of tags. It is useful to use with +.Fl w +option. .It Fl r locate function references instead of function definitions. GTAGS file is -needed at the current directory. (C source only) +needed at the current directory. (C and Java source only) +By default, locate function definitions. .It Fl s -collect symbols except for functions. -.It Fl t -create tags for typedefs, structs, unions, and enums. -.It Fl u -update the specified files in the -.Ar tags -file, that is, all -references to them are deleted, and the new values are appended to the -file. (Beware: this option is implemented in a way which is rather -slow; it is usually faster to simply rebuild the -.Ar tags -file.) -.It Fl v -An index of the form expected by -.Xr vgrind 1 -is produced on the standard output. This listing -contains the object name, file name, and page number (assuming 64 -line pages). Since the output will be sorted into lexicographic order, -it may be desired to run the output through -.Xr sort 1 . -Sample use: -.Bd -literal -offset indent -gctags \-v files \&| sort \-f > index -vgrind \-x index -.Ed +collect symbols other than functions. By default, locate function definitions. .It Fl w -suppress warning diagnostics. -.It Fl x -.Nm gctags -produces a list of object -names, the line number and file name on which each is defined, as well -as the text of that line and prints this on the standard output. This -is a simple index which can be printed out as an off-line readable -function index. +print warning message. .El .Pp +The +.Fl r +and +.Fl s +options override each other; the last one specified determines the method used. +.Pp Files whose names end in .Nm \&.c or @@ -144,47 +101,19 @@ are assumed to be .Tn YACC source files. Files whose names end in -.Nm \&.l -are assumed to be lisp files if their -first non-blank character is `;', `(', or `[', -otherwise, they are -treated as lex files. +.Nm \&.java +are assumed to be Java source files. Files whose names end in .Nm \&.s or .Nm \&.S are assumed to be Assembler -source files. Other files are first examined to see if they -contain any Pascal or Fortran routine definitions, and, if not, are -searched for C style definitions. +source files. Other files are searched for C style definitions. .Pp -The tag -.Li main -is treated specially in C programs. The tag formed -is created by prepending -.Ar M -to the name of the file, with the -trailing -.Nm \&.c -and any leading pathname components removed. This -makes use of -.Nm gctags -practical in directories with more than one -program. -.Pp -Yacc and lex files each have a special tag. +Yacc files each have a special tag. .Ar Yyparse is the start -of the second section of the yacc file, and -.Ar yylex -is the start of -the second section of the lex file. -.Sh FILES -.Bl -tag -width tags -compact -.It Pa tags -default output tags file -.It Pa GTAGS -tags file for GLOBAL +of the second section of the yacc file. .El .Sh DIAGNOSTICS .Nm Gctags @@ -199,42 +128,15 @@ Duplicate objects are not considered errors. .Xr vi 1 . .Sh BUGS .Pp -Recognition of -.Nm functions , -.Nm subroutines -and -.Nm procedures -for -.Tn FORTRAN -and Pascal is done is a very simpleminded way. No attempt -is made to deal with block structure; if you have two Pascal procedures -in different blocks with the same name you lose. -.Nm Gctags -doesn't -understand about Pascal types. -.Pp -The method of deciding whether to look for C, Pascal or -.Tn FORTRAN -functions is a hack. -.Pp .Nm Gctags relies on the input being well formed, and any syntactical -errors will completely confuse it. It also finds some legal syntax -confusing; for example, since it doesn't understand -.Li #ifdef Ns 's -(incidentally, that's a feature, not a bug), any code with unbalanced -braces inside -.Li #ifdef Ns 's -will cause it to become somewhat disoriented. -In a similar fashion, multiple line changes within a definition will -cause it to enter the last line of the object, rather than the first, as -the searching pattern. The last line of multiple line -.Li typedef Ns 's -will similarly be noted. +errors will completely confuse it. .Pp -Assembler support is far from completeness. It extracts only ENTRY() +Assembler support is far from complete. It extracts only ENTRY() and ALTENTRY() from source file. Probably valid only for FreeBSD and Linux kernel source. +.Sh AUTHORS +Shigio Yamaguchi (shigio@wafu.netgate.net) .Sh HISTORY The .Nm diff --git a/contrib/global/gctags/gctags.c b/contrib/global/gctags/gctags.c new file mode 100644 index 000000000000..fad225065bad --- /dev/null +++ b/contrib/global/gctags/gctags.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1998 Shigio Yamaguchi. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Shigio Yamaguchi. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * gctags.c 13-Sep-98 + */ + +#include +#include +#include +#include +#include + +#include "global.h" +#include "gctags.h" + +int bflag; /* -b: force level 1 block start */ +int dflag; /* -d: debug */ +int eflag; /* -e: force level 1 block end */ +int nflag; /* -n: doen't print tag */ +int rflag; /* -r: function reference */ +int sflag; /* -s: collect symbols */ +int wflag; /* -w: warning message */ +int yaccfile; /* yacc file */ + +const char *progname = "gctags"; /* program name */ +char *notfunction; + +int main __P((int, char **)); +static void usage __P((void)); + +struct words *words; +static int tablesize; + +int +main(argc, argv) + int argc; + char **argv; +{ + char *p; + + while (--argc > 0 && (++argv)[0][0] == '-') { + for (p = argv[0] + 1; *p; p++) { + switch(*p) { + case 'b': + bflag++; + break; + case 'd': + dflag++; + break; + case 'e': + eflag++; + break; + case 'n': + nflag++; + break; + case 'r': + rflag++; + sflag = 0; + break; + case 's': + sflag++; + rflag = 0; + break; + case 'w': + wflag++; + break; + default: + usage(); + } + } + } + if (argc < 1) + usage(); + if (getenv("GTAGSWARNING")) + wflag++; + if (test("r", NOTFUNCTION)) { + FILE *ip; + STRBUF *sb = stropen(); + int i; + + if ((ip = fopen(NOTFUNCTION, "r")) == 0) + die1("'%s' cannot read.", NOTFUNCTION); + for (tablesize = 0; (p = mgets(ip, NULL, 0)) != NULL; tablesize++) + strnputs(sb, p, strlen(p) + 1); + fclose(ip); + if ((words = malloc(sizeof(struct words) * tablesize)) == NULL) + die("short of memory."); + p = strvalue(sb); + for (i = 0; i < tablesize; i++) { + words[i].name = p; + p += strlen(p) + 1; + } + qsort(words, tablesize, sizeof(struct words), cmp); + /* don't call strclose(sb); */ + } + for (; argc > 0; argv++, argc--) { + if (!opentoken(argv[0])) + die1("'%s' cannot open.", argv[0]); + if (locatestring(argv[0], ".y", MATCH_AT_LAST)) + C(1); + else if (locatestring(argv[0], ".s", MATCH_AT_LAST) || + locatestring(argv[0], ".S", MATCH_AT_LAST)) + assembler(); + else if (locatestring(argv[0], ".java", MATCH_AT_LAST)) + java(); + else + C(0); + closetoken(); + } + exit(0); +} + +static void +usage() +{ + (void)fprintf(stderr, "usage: gctags [-benrsw] file ...\n"); + exit(1); +} + +int +cmp(s1, s2) + const void *s1, *s2; +{ + return strcmp(((struct words *)s1)->name, ((struct words *)s2)->name); +} + +int +isnotfunction(name) + char *name; +{ + struct words tmp; + struct words *result; + + if (words == NULL) + return 0; + tmp.name = name; + result = (struct words *)bsearch(&tmp, words, tablesize, sizeof(struct words), cmp); + return (result != NULL) ? 1 : 0; +} + +#ifdef DEBUG +void +dbg_print(level, s) + int level; + const char *s; +{ + if (!dflag) + return; + fprintf(stderr, "[%04d]", lineno); + for (; level > 0; level--) + fprintf(stderr, " "); + fprintf(stderr, "%s\n", s); +} +#endif diff --git a/contrib/global/gctags/gctags.h b/contrib/global/gctags/gctags.h new file mode 100644 index 000000000000..e27e32d684fe --- /dev/null +++ b/contrib/global/gctags/gctags.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1998 Shigio Yamaguchi. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Shigio Yamaguchi. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * gctags.h 17-Oct-98 + */ +#include +#include "token.h" +/* + * target type. + */ +#define DEF 1 +#define REF 2 +#define SYM 3 + +#define NOTFUNCTION ".notfunction" + +extern int bflag; +extern int dflag; +extern int eflag; +extern int nflag; +extern int rflag; +extern int sflag; +extern int wflag; +extern int yaccfile; + +struct words { + const char *name; + int val; +}; + +#define PUT(tag, lno, line) { \ + DBG_PRINT(level, line); \ + if (!nflag) { \ + if (strlen(tag) >= 16 && lno >= 1000) \ + printf("%-16s %4d %-16s %s\n", \ + tag, lno, curfile, line); \ + else \ + printf("%-16s%4d %-16s %s\n", \ + tag, lno, curfile, line); \ + } \ +} + +#define IS_RESERVED(a) ((a) > 255) + +#ifndef __P +#ifdef __STDC__ +#define __P(protos) protos +#else +#define __P(protos) () +#endif +#endif + +#ifdef DEBUG +void dbg_print __P((int, const char *)); +#define DBG_PRINT(level, a) dbg_print(level, a) +#else +#define DBG_PRINT(level, a) +#endif + +int isnotfunction __P((char *)); +int cmp __P((const void *, const void *)); +void C __P((int)); +void assembler __P((void)); +void java __P((void)); diff --git a/contrib/global/gctags/java.c b/contrib/global/gctags/java.c new file mode 100644 index 000000000000..cb49f862d27e --- /dev/null +++ b/contrib/global/gctags/java.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 1998 Shigio Yamaguchi. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Shigio Yamaguchi. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * java.c 2-Sep-98 + */ + +#include +#include +#include +#include + +#include "gctags.h" +#include "defined.h" +#include "die.h" +#include "java.h" +#include "token.h" + +static int reserved __P((char *)); + +/* + * java: read java file and pickup tag entries. + */ +void +java() +{ + int c; + int level; /* brace level */ + int target; + int startclass, startthrows, startequal; + char classname[MAXTOKEN]; + char completename[MAXCOMPLETENAME]; + int classlevel; + struct { + char *classname; + char *terminate; + int level; + } stack[MAXCLASSSTACK]; + const char *interested = "{}=;"; + + stack[0].terminate = completename; + stack[0].level = 0; + level = classlevel = 0; + target = (sflag) ? SYM : ((rflag) ? REF : DEF); + startclass = startthrows = startequal = 0; + + while ((c = nexttoken(interested, reserved)) != EOF) { + switch (c) { + case SYMBOL: /* symbol */ + for (; c == SYMBOL && peekc(1) == '.'; c = nexttoken(interested, reserved)) { + if (target == SYM) + PUT(token, lineno, sp); + } + if (c != SYMBOL) + break; + if (startclass || startthrows) { + if (target == REF && defined(token)) + PUT(token, lineno, sp); + } else if (peekc(0) == '('/* ) */) { + if (target == DEF && level == stack[classlevel].level && !startequal) + /* ignore constructor */ + if (strcmp(stack[classlevel].classname, token)) + PUT(token, lineno, sp); + if (target == REF && (level > stack[classlevel].level || startequal) && defined(token)) + PUT(token, lineno, sp); + } else { + if (target == SYM) + PUT(token, lineno, sp); + } + break; + case '{': /* } */ + DBG_PRINT(level, "{"); /* } */ + + ++level; + if (startclass) { + char *p = stack[classlevel].terminate; + char *q = classname; + + if (++classlevel >= MAXCLASSSTACK) + die1("class stack over flow.[%s]", curfile); + if (classlevel > 1) + *p++ = '.'; + stack[classlevel].classname = p; + while (*q) + *p++ = *q++; + stack[classlevel].terminate = p; + stack[classlevel].level = level; + *p++ = 0; + } + startclass = startthrows = 0; + break; + /* { */ + case '}': + if (--level < 0) { + if (wflag) + fprintf(stderr, "Warning: missing left '{' (at %d).\n", lineno); /* } */ + level = 0; + } + if (level < stack[classlevel].level) + *(stack[--classlevel].terminate) = 0; + /* { */ + DBG_PRINT(level, "}"); + break; + case '=': + startequal = 1; + break; + case ';': + startclass = startthrows = startequal = 0; + break; + case J_CLASS: + case J_INTERFACE: + if ((c = nexttoken(interested, reserved)) == SYMBOL) { + strcpy(classname, token); + startclass = 1; + if (target == DEF) + PUT(token, lineno, sp); + } + break; + case J_NEW: + case J_INSTANCEOF: + while ((c = nexttoken(interested, reserved)) == SYMBOL && peekc(1) == '.') + if (target == SYM) + PUT(token, lineno, sp); + if (c == SYMBOL) + if (target == REF && defined(token)) + PUT(token, lineno, sp); + break; + case J_THROWS: + startthrows = 1; + break; + case J_BOOLEAN: + case J_BYTE: + case J_CHAR: + case J_DOUBLE: + case J_FLOAT: + case J_INT: + case J_LONG: + case J_SHORT: + case J_VOID: + if (peekc(1) == '.' && (c = nexttoken(interested, reserved)) != J_CLASS) + pushbacktoken(); + break; + default: + } + } +} + /* sorted by alphabet */ +static struct words words[] = { + {"abstract", J_ABSTRACT}, + {"boolean", J_BOOLEAN}, + {"break", J_BREAK}, + {"byte", J_BYTE}, + {"case", J_CASE}, + {"catch", J_CATCH}, + {"char", J_CHAR}, + {"class", J_CLASS}, + {"const", J_CONST}, + {"continue", J_CONTINUE}, + {"default", J_DEFAULT}, + {"do", J_DO}, + {"double", J_DOUBLE}, + {"else", J_ELSE}, + {"extends", J_EXTENDS}, + {"false", J_FALSE}, + {"final", J_FINAL}, + {"finally", J_FINALLY}, + {"float", J_FLOAT}, + {"for", J_FOR}, + {"goto", J_GOTO}, + {"if", J_IF}, + {"implements", J_IMPLEMENTS}, + {"import", J_IMPORT}, + {"instanceof", J_INSTANCEOF}, + {"int", J_INT}, + {"interface", J_INTERFACE}, + {"long", J_LONG}, + {"native", J_NATIVE}, + {"new", J_NEW}, + {"null", J_NULL}, + {"package", J_PACKAGE}, + {"private", J_PRIVATE}, + {"protected", J_PROTECTED}, + {"public", J_PUBLIC}, + {"return", J_RETURN}, + {"short", J_SHORT}, + {"static", J_STATIC}, + {"strictfp", J_STRICTFP}, + {"super", J_SUPER}, + {"switch", J_SWITCH}, + {"synchronized",J_SYNCHRONIZED}, + {"this", J_THIS}, + {"throw", J_THROW}, + {"throws", J_THROWS}, + {"union", J_UNION}, + {"transient", J_TRANSIENT}, + {"true", J_TRUE}, + {"try", J_TRY}, + {"void", J_VOID}, + {"volatile", J_VOLATILE}, + {"while", J_WHILE}, + {"widefp", J_WIDEFP}, +}; + +static int +reserved(word) + char *word; +{ + struct words tmp; + struct words *result; + + tmp.name = word; + result = (struct words *)bsearch(&tmp, words, sizeof(words)/sizeof(struct words), sizeof(struct words), cmp); + return (result != NULL) ? result->val : SYMBOL; +} diff --git a/contrib/global/gctags/java.h b/contrib/global/gctags/java.h new file mode 100644 index 000000000000..5c0da71812cb --- /dev/null +++ b/contrib/global/gctags/java.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1998 Shigio Yamaguchi. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Shigio Yamaguchi. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * java.h 20-Aug-98 + */ +/* + * java's reserved words. + */ +#define J_ABSTRACT 1001 +#define J_BOOLEAN 1002 +#define J_BREAK 1003 +#define J_BYTE 1004 +#define J_CASE 1005 +#define J_CATCH 1006 +#define J_CHAR 1007 +#define J_CLASS 1008 +#define J_CONST 1009 +#define J_CONTINUE 1010 +#define J_DEFAULT 1011 +#define J_DO 1012 +#define J_DOUBLE 1013 +#define J_ELSE 1014 +#define J_EXTENDS 1015 +#define J_FALSE 1016 +#define J_FINAL 1017 +#define J_FINALLY 1018 +#define J_FLOAT 1019 +#define J_FOR 1020 +#define J_GOTO 1021 +#define J_IF 1022 +#define J_IMPLEMENTS 1023 +#define J_IMPORT 1024 +#define J_INSTANCEOF 1025 +#define J_INT 1026 +#define J_INTERFACE 1027 +#define J_LONG 1028 +#define J_NATIVE 1029 +#define J_NEW 1030 +#define J_NULL 1031 +#define J_PACKAGE 1032 +#define J_PRIVATE 1033 +#define J_PROTECTED 1034 +#define J_PUBLIC 1035 +#define J_RETURN 1036 +#define J_SHORT 1037 +#define J_STATIC 1038 +#define J_SUPER 1039 +#define J_SWITCH 1040 +#define J_SYNCHRONIZED 1041 +#define J_THIS 1042 +#define J_THROW 1043 +#define J_THROWS 1044 +#define J_UNION 1045 +#define J_TRANSIENT 1046 +#define J_TRUE 1047 +#define J_TRY 1048 +#define J_VOID 1049 +#define J_VOLATILE 1050 +#define J_WHILE 1051 +#define J_STRICTFP 1052 +#define J_WIDEFP 1053 + +#define MAXCOMPLETENAME 1024 /* max size of complete name of class */ +#define MAXCLASSSTACK 10 /* max size of class stack */ diff --git a/contrib/global/global.conf b/contrib/global/global.conf new file mode 100644 index 000000000000..e00cf0eac07d --- /dev/null +++ b/contrib/global/global.conf @@ -0,0 +1,157 @@ +# +# Copyright (c) 1998 Shigio Yamaguchi. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Shigio Yamaguchi. +# 4. Neither the name of the author nor the names of any co-contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Configuration file for GLOBAL source code tag system. +# +# Copy this file as /etc/global.conf or $HOME/.globalrc and GLOBAL system +# use it. +# +# 'default' is default target. +# You can specify target with GTAGSLABEL environment variable. +# +# include: +# It's similar to 'tc=' in termcap but can be used anytime and anywhere. +# 8 level nested usage is allowed. +# +default:\ + :include=gctags:include=htags: +#--------------------------------------------------------------------- +# +# Configuration for gtags(1) +# +# format: +# Select 'standard' or 'compact'. By default, it assumes 'standard'. +# suffixes: +# Suffixes of target source file. By default, 'c,h,y,s,S,java'. +# skip: +# Skip files among the target files. If the name ends with '/', +# gtags skips all files under the directory. +# By default, 'y.tab.c,y.tab.h,SCCS/,RCS/,CVS/'. +# extractmethod: +# Please see source code of gtags(1). +# GTAGS: +# Tag command for definitions. Non of default value. +# GRTAGS: +# Tag command for references. Non of default value. +# GSYMS: +# Tag command for other symbols. Non of default value. +# +# Htags(1) needs both of GTAGS and GRTAGS. Global(1)'s -s option needs GSYMS. +# +#--------------------------------------------------------------------- +common:\ + :skip=y.tab.c,y.tab.h,SCCS/,RCS/,CVS/:\ + :format=standard: +# +# [gctags] +# +# This command is distributed as part of GLOBAL. +# +gctags|tag command for GLOBAL:\ + :include=common:\ + :suffixes=c,h,y,s,S,java:\ + :GTAGS=gctags %s:\ + :GRTAGS=gctags -r %s:\ + :GSYMS=gctags -s %s: +# +# [Emacs's ctags] +# +# This ctags is distributed as a part of Emacs editor. +# +# supported suffixes by etags. +# +# lisp: l,el,lsp,lisp,cl,clisp +# scheme: sm,scm,scheme,t,sch,ss,SM,SCM +# assembler: s,a,sa,asm,src,def,ins,inc +# C++: C,H,cpp,cxx,hxx,cc +# C*: cs,hs +# c,yacc: c,h,y +# pl,p,pas: pascal +# fortran: f,for +# +# [Installation] +# % cd /lib-src +# % make ctags +# # cp ctags /usr/local/bin/ctags-emacs +# +ctags-emacs|ctags based on etags|GNU Emacs ctags:\ + :include=common:\ + :suffixes=el,s,a,sa,asm,C,H,cpp,cxx,hxx,cc,c,h,y:\ + :skip=ispell.el,canna.el,gnusutil.el:\ + :extractmethod:\ + :GTAGS=/usr/local/bin/ctags-emacs -x -d -T -w %s: +# +# [Exuberant Ctags] +# +# This ctags is distributed as a part of Vim editor. +# +# [Installation] +# % cd /src/ctags +# % make +# # cp ctags /usr/local/bin/ctags-exuberant +# +ctags-exuberant|Exuberant Ctags|ctags by Darren Hiebert:\ + :include=common:\ + :suffixes=s,a,sa,asm,C,H,cpp,cxx,hxx,cc,c,h,y:\ + :extractmethod:\ + :GTAGS=/usr/local/bin/ctags-exuberant -x %s | perl -ne '($name, $type, $no, $path, $line) = split(/[ \t]+/, $_, 5); printf(STDOUT "%-16s %4d %-16s %s", $name, $no, $path, $line);': +#--------------------------------------------------------------------- +# +# Configuration for htags(1) +# Let's paint hypertext with your favorite colors! +# +# bgcolor,text,link,vlink,alink: +# attribute of . (default is not set) +# title_begin,title_end: +# title tag +# comment_begin,comment_end: +# comment tag. (/* ... */, // ...) +# sharp_begin,sharp_end: +# macro tag. (#include, #define, ...) +# brace_begin,brace_end: +# brace tag. ('{', '}') +# reserved_begin,reserved_end: +# reserved word tag. (while, if, char, ...) +# ncol: +# columns of line number. (default = 4) +# tabs: +# tab stop. (default = 8) +# gzipped_suffix: +# suffix of compressed html file. +# +#--------------------------------------------------------------------- +htags:\ + :bgcolor=silver:text=black:link=blue:vlink=red:alink=cyan:\ + :title_begin=:title_end=:\ + :comment_begin=:comment_end=:\ + :sharp_begin=:sharp_end=:\ + :brace_begin=:brace_end=:\ + :reserved_begin=:reserved_end=:\ + :ncol#4:tabs#8:gzipped_suffix=ghtml: diff --git a/contrib/global/global/Makefile b/contrib/global/global/Makefile index ef7a1763eb56..376b20000110 100644 --- a/contrib/global/global/Makefile +++ b/contrib/global/global/Makefile @@ -1,6 +1,3 @@ PROG= global -CFLAGS+=-I${.CURDIR}/../lib -LDADD= $(LIBUTIL) -DPADD= $(LIBUTIL) .include diff --git a/contrib/global/global/global.1 b/contrib/global/global/global.1 index 3df007ef5ed9..1ec56abf8f40 100644 --- a/contrib/global/global/global.1 +++ b/contrib/global/global/global.1 @@ -1,5 +1,5 @@ .\" -.\" Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved. +.\" Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd Nov 26, 1997 +.Dd Dec 8, 1998 .Dt GLOBAL 1 .Os BSD 4 .Sh NAME @@ -36,26 +36,29 @@ .Nd print the locations of specified object. .Sh SYNOPSIS .Nm global -.Op Fl alrvx +.Op Fl alnrtvx .Ar pattern .Nm global -c .Op Ar prefix .Nm global -.Fl f[arx] -.Ar file +.Fl f[anrtx] +.Ar files .Nm global -.Fl g[alvx] +.Fl g[alntvx] .Ar pattern .Nm global .Fl i[v] .Nm global .Fl p .Nm global -.Fl s[alvx] +.Fl P[alnt] +.Op Ar pattern +.Nm global +.Fl s[alntvx] .Ar pattern .Sh DESCRIPTION .Nm Global -find the locations of specified object in C and Yacc source files. +find the locations of specified object in C, Yacc and Java source files. .Nm Global can treat a source tree, that is, a directory that has subdirectories and source files. @@ -71,38 +74,53 @@ at the root directory of the source tree to make tag files. Then you can execute .Nm at anywhere in the source tree. -.Pp -The following options are available: +.Sh COMMANDS +The following commands are available: .Bl -tag -width Ds .It Ar pattern -object pattern. It can include POSIX 1003.2 regular expression. -.It Fl a -print absolute path name. By default, print relative path name. +print object which match to the +.Ar pattern . +It can include POSIX 1003.2 regular expression. .It Fl c Op Ar prefix print candidate function names which start with specified .Ar prefix . If .Ar prefix is not specified, print all function names. -.It Fl f Ar file +.It Fl f Ar files print all function definitions in the -.Ar file . +.Ar files . This option implies -x option. -.It Fl g -print all lines which match to the pattern. +.It Fl g Ar pattern +print all lines which match to the +.Ar pattern . +It is similar to grep(1). .It Fl i -reconstruct tags files incrementally. -.It Fl l -print objects which exist under the current directory. -.It Fl r -print the locations of function references. By default, print function -definitions. +locate tag files and reconstruct them incrementally. .It Fl p print the location of GTAGS. -.It Fl s +.It Fl P Op Ar pattern +print the path which match to the +.Ar pattern . +If no pattern specified, print all. +.It Fl s Ar pattern print the locations of specified symbol other than function names. You need GSYMS tags file. See .Xr gtags 1 . +.Sh OPTIONS +The following options are available: +.Bl -tag -width Ds +.It Fl a +print absolute path name. By default, print relative path name. +.It Fl l +print just objects which exist under the current directory. +.It Fl n +suppress sort filter and path conversion filter. +.It Fl r +print the locations of object references. By default, print object +definitions. +.It Fl t +print with standard ctags format. .It Fl x In addition to the default output, produce the line number and the line contents. @@ -114,6 +132,8 @@ tags file for function definitions. tags file for function references. .It Pa GSYMS tags file for symbols other then functions. +.It Pa GPATH +path index. This is used for incremental updating and compact format. .El .Sh ENVIRONMENT The following environment variables affect the execution of global. diff --git a/contrib/global/global/global.c b/contrib/global/global/global.c index 4a92fa4d5dfc..a8dbb172a174 100644 --- a/contrib/global/global/global.c +++ b/contrib/global/global/global.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved. + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,10 +28,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * global.c 7-Nov-97 + * global.c 8-Dec-98 * */ +#include #include #include @@ -43,64 +44,87 @@ #include "global.h" -char *progname = "global"; /* command name */ +const char *progname = "global"; /* command name */ static void usage __P((void)); -void main __P((int, char **)); -char *outfilter __P((void)); -void completelist __P((char *, char *)); -void relative_filter __P((char *, char *, char *)); +static void setcom __P((int)); +int main __P((int, char **)); +void makefilter __P((char *)); +FILE *openfilter __P((void)); +void closefilter __P((FILE *)); +void completelist __P((char *, char *, char *)); +void relative_filter __P((STRBUF *, char *, char *)); void grep __P((char *)); -int printtag __P((FILE *, char *, char *, int)); -int regexp __P((char *)); +void pathlist __P((char *, char *)); +void parsefile __P((int, char **, char *, char *, char *, int)); +void printtag __P((FILE *, char *)); +int notnamechar __P((char *)); int search __P((char *, char *, char *, char *, int)); -char *extractpath __P((char *)); int includepath __P((char *, char *)); -char sortfilter[MAXCOMLINE+1]; /* sort filter */ -char pathfilter[MAXCOMLINE+1]; /* path convert filter */ -char local[MAXPATHLEN+1]; /* local prefix */ +char sortfilter[MAXFILLEN+1]; /* sort filter */ +char pathfilter[MAXFILLEN+1]; /* path convert filter */ char *localprefix; /* local prefix */ int aflag; /* [option] */ int cflag; /* command */ int fflag; /* command */ -int lflag; /* [option] */ int gflag; /* command */ int iflag; /* command */ +int lflag; /* [option] */ +int nflag; /* [option] */ int pflag; /* command */ +int Pflag; /* command */ int rflag; /* [option] */ int sflag; /* command */ +int tflag; /* [option] */ int vflag; /* [option] */ int xflag; /* [option] */ +int pfilter; /* undocumented command */ static void usage() { - fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", - "global [-alrvx] pattern", + fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", + "global [-alnrtvx] pattern", "global -c [prefix]", - "global -f[arx] file", - "global -g[alvx] pattern", + "global -f[alnrtx] files", + "global -g[alntvx] pattern", "global -i[v]", - "global -p", - "global -s[alvx] pattern"); + "global -p[v]", + "global -P[alnt] [pattern]", + "global -s[alntvx] pattern"); exit(1); } -void +static int command; +static void +setcom(c) +int c; +{ + if (command == 0) + command = c; + else + usage(); +} +int main(argc, argv) int argc; char *argv[]; { - char *p, *av; + char *av; int count; int db; char cwd[MAXPATHLEN+1]; /* current directory */ char root[MAXPATHLEN+1]; /* root of source tree */ char dbpath[MAXPATHLEN+1]; /* dbpath directory */ - char comline[MAXCOMLINE+1]; while (--argc > 0 && (++argv)[0][0] == '-') { + char *p; + + if (!strcmp(argv[0], "--filter")) { + pfilter++; + continue; + } for (p = argv[0] + 1; *p; p++) { switch (*p) { case 'a': @@ -108,27 +132,44 @@ char *argv[]; break; case 'c': cflag++; + setcom(*p); break; case 'f': fflag++; + xflag++; + setcom(*p); break; case 'l': lflag++; break; + case 'n': + nflag++; + break; case 'g': gflag++; + setcom(*p); break; case 'i': iflag++; + setcom(*p); break; case 'p': pflag++; + setcom(*p); + break; + case 'P': + Pflag++; + setcom(*p); break; case 'r': rflag++; break; case 's': sflag++; + setcom(*p); + break; + case 't': + tflag++; break; case 'v': vflag++; @@ -141,44 +182,32 @@ char *argv[]; } } } - av = (argc > 0) ? *argv : (char *)0; + av = (argc > 0) ? *argv : NULL; /* - * usage check. + * only -c, -i, -P and -p allows no argment. */ - { - int commands, options; - - commands = cflag + fflag + gflag + iflag + pflag + sflag; - options = aflag + lflag + rflag + xflag; - /* - * only -c, -i and -p allows no argment. - */ - if (!av && !cflag && !iflag && !pflag) - usage(); - /* - * command cannot be duplicated. - */ - if (commands > 1) - usage(); - /* - * -c and -i command allows only -v option. - */ - if (cflag + iflag && options) - usage(); - /* - * -r is not valid for -g, -i and -s. - */ - if (rflag && (gflag + iflag + sflag)) + if (!av && !pfilter) { + switch (command) { + case 'c': + case 'i': + case 'p': + case 'P': + break; + default: usage(); + } } + /* + * invalid options are just ignored. + */ /* * remove leading blanks. */ if (av && !gflag) for (; *av == ' ' || *av == '\t'; av++) ; - if (cflag && av && regexp(av)) - die("regular expression not allowed with -c option."); + if (cflag && av && notnamechar(av)) + die("only name char is allowed with -c option."); /* * get path of following directories. * o current directory @@ -187,6 +216,12 @@ char *argv[]; * * if GTAGS not found, getdbpath doesn't return. */ + if (pflag && vflag) { + char *gtagsdbpath = getenv("GTAGSDBPATH"); + char *gtagsroot = getenv("GTAGSROOT"); + if (gtagsdbpath && !gtagsroot) + fprintf(stdout, "warning: GTAGSDBPATH is ignored becase GTAGSROOT is not set.\n"); + } getdbpath(cwd, root, dbpath); if (pflag) { @@ -197,11 +232,18 @@ char *argv[]; * incremental update of tag files. */ if (iflag) { + STRBUF *sb = stropen(); + if (chdir(root) < 0) die1("cannot change directory to '%s'.", root); - sprintf(comline, "gtags -i%s %s", (vflag) ? "v" : "", dbpath); - if (system(comline)) + strputs(sb, "gtags -i"); + if (vflag) + strputc(sb, 'v'); + strputc(sb, ' '); + strputs(sb, dbpath); + if (system(strvalue(sb))) exit(1); + strclose(sb); exit(0); } @@ -209,39 +251,62 @@ char *argv[]; * complete function name */ if (cflag) { - completelist(dbpath, av); + completelist(dbpath, root, av); exit(0); } /* * make sort filter. */ if (sflag && xflag) - *sortfilter = 0; + strcpy(sortfilter, ""); + else if (tflag) /* ctags format */ + strcpy(sortfilter, "sort +0 -1 +1 -2 +2n -3"); else if (fflag) - sprintf(sortfilter, "sort +1n -2"); + strcpy(sortfilter, "sort +2 -3 +1n -2"); else if (xflag) /* print details */ - sprintf(sortfilter, "sort +0 -1 +2 -3 +1n -2"); + strcpy(sortfilter, "sort +0 -1 +2 -3 +1n -2"); else /* print just file name */ - sprintf(sortfilter, "sort | uniq"); + strcpy(sortfilter, "sort | uniq"); /* * make path filter. */ if (aflag) /* absolute path name */ sprintf(pathfilter, "sed -e 's!\\.!%s!'", root); - else /* relative path name */ - relative_filter(root, cwd, pathfilter); + else { /* relative path name */ + STRBUF *sb = stropen(); + + relative_filter(sb, root, cwd); + strcpy(pathfilter, strvalue(sb)); + strclose(sb); + } /* * make local prefix. */ if (lflag) { + char *p = cwd + strlen(root); + STRBUF *sb = stropen(); /* * getdbpath() assure follows. * cwd != "/" and cwd includes root. */ - strcpy(local, cwd); - strcat(local, "/"); - localprefix = local + strlen(root) - 1; - *localprefix = '.'; + strputc(sb, '.'); + if (*p) + strputs(sb, p); + strputc(sb, '/'); + localprefix = strdup(strvalue(sb)); + if (!localprefix) + die("short of memory."); + strclose(sb); + } + /* + * print filter. + */ + if (pfilter) { + char filter[MAXFILLEN+1]; + + makefilter(filter); + fprintf(stdout, "%s\n", filter); + exit(0); } /* * grep the pattern in a source tree. @@ -254,41 +319,19 @@ char *argv[]; grep(av); exit(0); } + /* + * locate the path including the pattern in a source tree. + */ + if (Pflag) { + pathlist(dbpath, av); + exit(0); + } db = (rflag) ? GRTAGS : ((sflag) ? GSYMS : GTAGS); /* * print function definitions. */ if (fflag) { - struct stat sb; - char pathbuf[MAXPATHLEN+1], *path; - char *p; - FILE *op; - DBIO *dbio; - - /* av !~ /\.[chysS]$/) */ - p = av + strlen(av) - 1; /* last character */ - if (stat(av, &sb) || !S_ISREG(sb.st_mode)) - die1("file '%s' not found.", av); - if (*(p - 1) != '.' || !locatestring("chysS", p, 0)) - die("accept only file name end with '.c .h .y .s .S'."); - /* - * convert path into relative from root directory of source tree. - */ - path = realpath(av, pathbuf); - if (*path != '/') - die("realpath(3) is not compatible with BSD version."); - if (strncmp(path, root, strlen(root))) - die1("file '%s' is out of source tree.", path); - path += strlen(root) - 1; - *path = '.'; - if (!(op = popen(outfilter(), "w"))) - die("cannot open output pipe."); - dbio = gtagsopen(dbpath, db, 0); - for (p = db_first(dbio, NULL, DBIO_SKIPMETA); p; p = db_next(dbio)) - if (includepath(p, path)) - fprintf(op, "%s\n", p); - db_close(dbio); - pclose(op); + parsefile(argc, argv, cwd, root, dbpath, db); exit(0); } /* @@ -298,28 +341,30 @@ char *argv[]; /* * search in library path. */ - if (count == 0 && !rflag && !sflag && !regexp(av) && getenv("GTAGSLIBPATH")) { - char envbuf[MAXENVLEN+1]; + if (count == 0 && !rflag && !sflag && !notnamechar(av) && getenv("GTAGSLIBPATH")) { + char buf[MAXENVLEN+1]; char libdbpath[MAXPATHLEN+1]; char *p, *lib; - strcpy(envbuf, getenv("GTAGSLIBPATH")); - p = envbuf; + strcpy(buf, getenv("GTAGSLIBPATH")); + p = buf; while (p) { lib = p; - if ((p = locatestring(p, ":", 0)) != NULL) + if ((p = locatestring(p, ":", MATCH_FIRST)) != NULL) *p++ = 0; - if (!strncmp(lib, cwd, strlen(cwd)) || !strncmp(cwd, lib, strlen(lib))) - continue; if (!gtagsexist(lib, libdbpath)) continue; if (!strcmp(dbpath, libdbpath)) continue; if (aflag) /* absolute path name */ sprintf(pathfilter, "sed -e 's!\\.!%s!'", lib); - else - relative_filter(lib, cwd, pathfilter); - count = search(av, cwd, lib, libdbpath, GTAGS); + else { + STRBUF *sb = stropen(); + relative_filter(sb, lib, cwd); + strcpy(pathfilter, strvalue(sb)); + strclose(sb); + } + count = search(av, cwd, lib, libdbpath, db); if (count > 0) { strcpy(dbpath, libdbpath); break; @@ -340,58 +385,91 @@ char *argv[]; exit(0); } /* - * outfilter: return output filter. + * makefilter: make filter string. + * + * io) filter buffer + */ +void +makefilter(filter) +char *filter; +{ + if (nflag) + filter[0] = 0; + else if (sortfilter[0] == 0 && pathfilter[0] == 0) + filter[0] = 0; + else if (sortfilter[0] && pathfilter[0]) + sprintf(filter, "%s | %s", sortfilter, pathfilter); + else if (sortfilter[0]) + strcpy(filter, sortfilter); + else + strcpy(filter, pathfilter); +} +/* + * openfilter: open output filter. * * gi) pathfilter * gi) sortfilter * r) output filter */ -char * -outfilter(void) +FILE * +openfilter(void) { - static char filter[MAXCOMLINE+1]; + FILE *op; + char filter[MAXFILLEN+1]; - /* - * make output filter - */ - if (*sortfilter) - sprintf(filter, "%s | %s", sortfilter, pathfilter); + makefilter(filter); + if (filter[0] == 0) + op = stdout; else - strcpy(filter, pathfilter); - return filter; + op = popen(filter, "w"); + return op; +} +void +closefilter(op) +FILE *op; +{ + if (op != stdout) + pclose(op); } /* * completelist: print complete list of function * * i) dbpath dbpath directory + * i) root root directory * i) prefix prefix of primary key */ void -completelist(dbpath, prefix) +completelist(dbpath, root, prefix) char *dbpath; +char *root; char *prefix; { char *p; - DBIO *dbio; + int flags = GTOP_KEY; + GTOP *gtop; - dbio = gtagsopen(dbpath, GTAGS, 0); - for (p = db_first(dbio, prefix, DBIO_KEY|DBIO_PREFIX|DBIO_SKIPMETA); p; p = db_next(dbio)) + if (prefix && *prefix == 0) /* In the case global -c '' */ + prefix = NULL; + if (prefix) + flags |= GTOP_PREFIX; + gtop = gtagsopen(dbpath, root, GTAGS, GTAGS_READ, 0); + for (p = gtagsfirst(gtop, prefix, flags); p; p = gtagsnext(gtop)) (void)fprintf(stdout, "%s\n", p); - db_close(dbio); + gtagsclose(gtop); } /* * relative_filter: make relative path filter * + * i) sb string buffer * i) root the root directory of source tree - * i) argcwd current directory - * o) bp result - * relative path filter + * i) cwd current directory + * r) relative path filter */ void -relative_filter(root, cwd, bp) +relative_filter(sb, root, cwd) +STRBUF *sb; char *root; char *cwd; -char *bp; { char *p, *c, *branch; @@ -404,38 +482,36 @@ char *bp; branch = c; if (*p == 0 && (*c == 0 || *c == '/')) branch = c; - if (*c == 0 && *p) - die("illegal root."); /* * forward to root. */ - strcpy(bp, "sed -e 's!\\./!"); + strputs(sb, "sed -e 's!\\./!"); for (c = branch; *c; c++) if (*c == '/') - strcat(bp, "../"); + strputs(sb, "../"); p = root + (branch - cwd); /* * backward to leaf. */ if (*p) { p++; - strcat(bp, p); - strcat(bp, "/"); + strputs(sb, p); + strputc(sb, '/'); } - strcat(bp, "!'"); + strputs(sb, "!'"); /* * remove redundancy. */ if (*branch) { char unit[256]; - bp += strlen(bp); p = unit; for (c = branch + 1; ; c++) { if (*c == 0 || *c == '/') { *p = 0; - sprintf(bp, " -e 's!\\.\\./%s/!!'", unit); - bp += strlen(bp); + strputs(sb, " -e 's!\\.\\./"); + strputs(sb, unit); + strputs(sb, "/!!'"); if (*c == 0) break; p = unit; @@ -448,107 +524,66 @@ char *bp; * printtag: print a tag's line * * i) op output stream - * i) root root of source tree * i) bp tag's line - * i) compact 0: standard format, 1: compact format - * r) output line count */ -int -printtag(op, root, bp, compact) +void +printtag(op, bp) FILE *op; -char *root; char *bp; -int compact; { - int count = 0; - char *tag, *file, *lno; - int opened = 0; - char path[MAXPATHLEN+1]; - char *buffer; - int line = 0, tagline = 0; - FILE *ip; - - if (!xflag) { - fprintf(op, "%s\n", extractpath(bp)); - return 1; - } - if (compact) { /* compact format */ + if (tflag) { + char buf[MAXBUFLEN+1]; + char lno[20], *l = lno; char *p = bp; + char *q = buf; - tag = p; /* tag = $1 */ - for (; !isspace(*p) ; p++) + while (*p && !isspace(*p)) + *q++ = *p++; + *q++ = '\t'; + for (; *p && isspace(*p); p++) ; - *p++ = 0; - for (; isspace(*p) ; p++) + while (*p && isdigit(*p)) + *l++ = *p++; + *l = 0; + for (; *p && isspace(*p); p++) ; - file = p; /* file = $2 */ - for (; !isspace(*p) ; p++) - ; - *p++ = 0; - for (; isspace(*p) ; p++) - ; - lno = p; /* lno = $3 */ - sprintf(path, "%s/%s", root, file + 2); - if ((ip = fopen(path, "r")) != NULL) { - opened = 1; - buffer = mgets(ip, 0, NULL); - line = 1; - } else { - buffer = ""; - } - while (*lno) { - /* get line number */ - for (tagline = 0; *lno >= '0' && *lno <= '9'; lno++) - tagline = tagline * 10 + *lno - '0'; - if (*lno == ',') - lno++; - if (opened) { - while (line < tagline) { - if (!(buffer = mgets(ip, 0, NULL))) - die1("unexpected end of file. '%s'", path); - line++; - } - } - if (strlen(tag) >= 16 && tagline >= 1000) - fprintf(op, "%-16s %4d %-16s %s\n", - tag, tagline, file, buffer); - else - fprintf(op, "%-16s%4d %-16s %s\n", - tag, tagline, file, buffer); - count++; - } - if (opened) - fclose(ip); - } else { /* standard format */ - /* - * separater in key part must be ' ' to avoid sort(1)'s bug. - */ + while (*p && !isspace(*p)) + *q++ = *p++; + *q++ = '\t'; + l = lno; + while (*l) + *q++ = *l++; + *q = 0; + fprintf(op, "%s\n", buf); + } else if (!xflag) { + char *p = locatestring(bp, "./", MATCH_FIRST); + + if (p == NULL) + die("illegal tag format (path not found)."); + while (*p && *p != ' ' && *p != '\t') + (void)putc(*p++, op); + (void)putc('\n', op); + } else detab(op, bp); - count++; - } - return count; } /* - * regexp: test whether regular expression included. + * notnamechar: test whether or not no name char included. * * i) s string * r) 0: not included, 1: included - * - * This function cannot be used for generic purpose. - * Any character except '[a-zA-Z_0-9]' is assumed RE char.. */ int -regexp(s) +notnamechar(s) char *s; { int c; - while ((c = *s++) != NULL) + while ((c = *s++) != '\0') if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || - (c == '_') ) + (c == '-') || (c == '_')) ; else return 1; @@ -566,42 +601,46 @@ char *pattern; FILE *op, *fp; char *path; char edit[IDENTLEN+1]; - char *buffer, *p, *e; + char *buffer; int linenum, count, editlen; regex_t preg; /* * convert spaces into %FF format. */ - e = edit; - for (p = pattern; *p; p++) { - if (*p == '%' || *p == ' ' || *p == '\t') { - sprintf(e, "%%%02x", *p); - e += 3; - } else - *e++ = *p; + { + char *p, *e = edit; + for (p = pattern; *p; p++) { + if (*p == '%' || *p == ' ' || *p == '\t') { + sprintf(e, "%%%02x", *p); + e += 3; + } else + *e++ = *p; + } + *e = 0; } - *e = 0; editlen = strlen(edit); if (regcomp(&preg, pattern, REG_EXTENDED) != 0) die("illegal regular expression."); - if (!(op = popen(outfilter(), "w"))) - die("cannot open output pipe."); + if (!(op = openfilter())) + die("cannot open output filter."); count = 0; for (findopen(); (path = findread(NULL)) != NULL; ) { if (!(fp = fopen(path, "r"))) die1("cannot open file '%s'.", path); linenum = 0; - while ((buffer = mgets(fp, 0, NULL)) != NULL) { + while ((buffer = mgets(fp, NULL, 0)) != NULL) { linenum++; if (regexec(&preg, buffer, 0, 0, 0) == 0) { count++; - if (xflag == 0) { + if (tflag) + fprintf(op, "%s\t%s\t%d\n", + edit, path, linenum); + else if (!xflag) { fprintf(op, "%s\n", path); break; - } - if (editlen >= 16 && linenum >= 1000) + } else if (editlen >= 16 && linenum >= 1000) fprintf(op, "%-16s %4d %-16s %s\n", edit, linenum, path, buffer); else @@ -612,7 +651,7 @@ char *pattern; fclose(fp); } findclose(); - pclose(op); + closefilter(op); if (vflag) { if (count == 0) fprintf(stderr, "object not found.\n"); @@ -622,7 +661,132 @@ char *pattern; fprintf(stderr, "%d objects located.\n", count); } } +/* + * pathlist: print candidate path list. + * + * i) dbpath + */ +void +pathlist(dbpath, av) +char *dbpath; +char *av; +{ + FILE *op; + const char *tag = av; + char key[10], *path; + regex_t preg; + int i, lim; + if (av) { + if (regcomp(&preg, av, REG_EXTENDED) != 0) + die("illegal regular expression."); + } else + tag = "file"; + if (!(op = openfilter())) + die("cannot open output filter."); + if (pathopen(dbpath, 0) < 0) + die("GPATH not found."); + lim = nextkey(); + for (i = 0; i < lim; i++) { + sprintf(key, "%d", i); + if ((path = pathget(key)) == NULL) + continue; + if (lflag && !locatestring(path, localprefix, MATCH_AT_FIRST)) + continue; + if (av && regexec(&preg, path + 2, 0, 0, 0) != 0) + continue; + if (tflag) + fprintf(op, "%s\t%s\t1\n", tag, path); + else + fprintf(op, "%s\n", path); + } + pathclose(); + closefilter(op); +} +/* + * parsefile: parse file to pick up tags. + * + * i) db + * i) dbpath + * i) root + * i) cwd + * i) argc + * i) argv + */ +void +parsefile(argc, argv, cwd, root, dbpath, db) +int argc; +char **argv; +char *cwd; +char *root; +char *dbpath; +int db; +{ + char buf[MAXPATHLEN+1], *path; + char *p; + FILE *ip, *op; + char *parser, *av; + STRBUF *sb = stropen(); + STRBUF *com = stropen(); + + /* + * get parser. + */ + if (!getconfs(dbname(db), sb)) + die1("cannot get parser for %s.", dbname(db)); + parser = strvalue(sb); + + if (!(op = openfilter())) + die("cannot open output filter."); + if (pathopen(dbpath, 0) < 0) + die("GPATH not found."); + for (; argc > 0; argv++, argc--) { + av = argv[0]; + + if (test("d", av)) { + fprintf(stderr, "'%s' is a directory.\n", av); + continue; + } + if (!test("f", NULL)) { + fprintf(stderr, "'%s' not found.\n", av); + continue; + } + /* + * convert path into relative from root directory of source tree. + */ + path = realpath(av, buf); + if (*path != '/') + die("realpath(3) is not compatible with BSD version."); + if (strncmp(path, root, strlen(root))) { + fprintf(stderr, "'%s' is out of source tree.\n", path); + continue; + } + path += strlen(root) - 1; + *path = '.'; + if (!pathget(path)) { + fprintf(stderr, "'%s' not found in GPATH.\n", path); + continue; + } + if (chdir(root) < 0) + die1("cannot move to '%s' directory.", root); + /* + * make command line. + */ + strstart(com); + makecommand(parser, path, com); + if (!(ip = popen(strvalue(com), "r"))) + die1("cannot execute '%s'.", strvalue(com)); + while ((p = mgets(ip, NULL, 0)) != NULL) + printtag(op, p); + pclose(ip); + if (chdir(cwd) < 0) + die1("cannot move to '%s' directory.", cwd); + } + pathclose(); + closefilter(op); + strclose(com); + strclose(sb); +} /* * search: search specified function * @@ -644,86 +808,78 @@ int db; char *p; int count = 0; FILE *op; - DBIO *dbio; - int compact; + GTOP *gtop; regex_t preg; /* * open tag file. - * currently only GSYMS is compact format. */ - dbio = gtagsopen(dbpath, db, 0); - compact = (db == GSYMS) ? 1 : 0; - if (!(op = popen(outfilter(), "w"))) - die1("filter '%s' failed.", outfilter()); + gtop = gtagsopen(dbpath, root, db, GTAGS_READ, 0); + if (!(op = openfilter())) + die("cannot open output filter."); /* * regular expression. */ - if (regexp(pattern) && regcomp(&preg, pattern, REG_EXTENDED) == 0) { - char prefix_buf[IDENTLEN+1]; - char *prefix = (char *)0; + if (!strcmp(pattern, ".*")) { + for (p = gtagsfirst(gtop, NULL, 0); p; p = gtagsnext(gtop)) { + if (lflag) { + char *q; + /* locate start point of a path */ + q = locatestring(p, "./", MATCH_FIRST); + if (!locatestring(q, localprefix, MATCH_AT_FIRST)) + continue; + } + printtag(op, p); + count++; + } + } else if (notnamechar(pattern) && regcomp(&preg, pattern, REG_EXTENDED) == 0) { if (*pattern == '^' && *(p = pattern + 1) && (isalpha(*p) || *p == '_')) { - prefix = prefix_buf; + char buf[IDENTLEN+1]; + char *prefix = buf; + *prefix++ = *p++; while (*p && (isalpha(*p) || isdigit(*p) || *p == '_')) *prefix++ = *p++; *prefix = 0; - prefix = prefix_buf; - p = db_first(dbio, prefix, DBIO_SKIPMETA|DBIO_PREFIX); + prefix = buf; + p = gtagsfirst(gtop, prefix, GTOP_PREFIX); } else { - p = db_first(dbio, NULL, DBIO_SKIPMETA); + p = gtagsfirst(gtop, NULL, 0); } - for (; p; p = db_next(dbio)) { - if (*p == ' ') + for (; p; p = gtagsnext(gtop)) { + /* + * search $1 of tag line (not key) + */ + if (regexec(&preg, strmake(gtop->dbop->lastdat, " \t"), 0, 0, 0) != 0) continue; - if (regexec(&preg, dbio->lastkey, 0, 0, 0) == 0) - count += printtag(op, root, p, compact); - } - } else { - for (p = db_first(dbio, pattern, 0); p; p = db_next(dbio)) { if (lflag) { char *q; /* locate start point of a path */ - q = locatestring(p, "./", 0); - if (!locatestring(q, localprefix, 1)) + q = locatestring(p, "./", MATCH_FIRST); + if (!locatestring(q, localprefix, MATCH_AT_FIRST)) continue; } - count += printtag(op, root, p, compact); + printtag(op, p); + count++; + } + } else { + for (p = gtagsfirst(gtop, pattern, 0); p; p = gtagsnext(gtop)) { + if (lflag) { + char *q; + /* locate start point of a path */ + q = locatestring(p, "./", MATCH_FIRST); + if (!locatestring(q, localprefix, MATCH_AT_FIRST)) + continue; + } + printtag(op, p); + count++; } } - pclose(op); - db_close(dbio); + closefilter(op); + gtagsclose(gtop); return count; } -/* - * extractpath: extract path string of a tag line - * - * i) line tag line - * r) path - * - * standard format: main 12 ./xxx/xxx/xxx.c main(argc, argv) { - * compact format: main ./xxx/xxx/xxx.c 12,15,55,101 - */ -char * -extractpath(line) -char *line; -{ - static char buf[MAXPATHLEN+1]; - char *p, *b; - int c; - - if (!(p = locatestring(line, "./", 0))) - die("illegal tag format (path not found)."); - b = buf; - while ((c = *b++ = *p++) != NULL) { - if (c == ' ' || c == '\t') { - *(b - 1) = 0; - break; - } - } - return buf; -} /* * includepath: check if the path included in tag line or not. * @@ -739,7 +895,7 @@ char *path; char *p; int length; - if (!(p = locatestring(line, "./", 0))) + if (!(p = locatestring(line, "./", MATCH_FIRST))) die("illegal tag format (path not found)."); length = strlen(path); if (strncmp(p, path, length)) diff --git a/contrib/global/gozilla/Imakefile b/contrib/global/gozilla/Imakefile index 5bcbc01e03cc..035c5443cbde 100644 --- a/contrib/global/gozilla/Imakefile +++ b/contrib/global/gozilla/Imakefile @@ -2,11 +2,23 @@ XCOMM XCOMM Imakefile for gozilla XCOMM -LOCAL_LIBRARIES = XawClientLibs -L../lib -lutil - DEPLIBS = XawClientDepLibs ../lib/libutil.a - DEFINES = -DSTANDALONE -DGLOBAL -I../lib + INC = ../lib +LOCAL_LIBRARIES = XawClientLibs + DEPLIBS = XawClientDepLibs + DEFINES = -DSTANDALONE -DGLOBAL -I$(INC) - SRCS = gozilla.c remote.c - OBJS = gozilla.o remote.o + SRCS = gozilla.c remote.c test.c getdbpath.c strbuf.c conf.c \ + mgets.c locatestring.c makepath.c strmake.c + OBJS = gozilla.o remote.o test.o getdbpath.o strbuf.o conf.o \ + mgets.o locatestring.o makepath.o strmake.o + +LinkSourceFile(test.c,$(INC)) +LinkSourceFile(getdbpath.c,$(INC)) +LinkSourceFile(strbuf.c,$(INC)) +LinkSourceFile(conf.c,$(INC)) +LinkSourceFile(mgets.c,$(INC)) +LinkSourceFile(locatestring.c,$(INC)) +LinkSourceFile(makepath.c,$(INC)) +LinkSourceFile(strmake.c,$(INC)) ComplexProgramTarget(gozilla) diff --git a/contrib/global/gozilla/gozilla.c b/contrib/global/gozilla/gozilla.c index fd43bbf6150d..32d4730d21d8 100644 --- a/contrib/global/gozilla/gozilla.c +++ b/contrib/global/gozilla/gozilla.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved. + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,17 +28,20 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * gozilla.c 27-Oct-97 + * gozilla.c 17-Jul-98 * */ #include #include +#include #include "global.h" -char *progname = "gozilla"; /* command name */ +const char *progname = "gozilla"; /* command name */ static void usage __P((void)); -void main __P((int, char **)); + +int main __P((int, char **)); +int issource __P((char *)); int sendcommand __P((char *)); int bflag; @@ -54,17 +57,17 @@ usage() exit(1); } -void +int main(argc, argv) int argc; char *argv[]; { char c, *p, *q; - char *browser = (char *)0; - char *command = (char *)0; - char *arg = (char *)0; + char *browser = NULL; + char *command = NULL; + char *arg = NULL; char URL[MAXPATHLEN+1]; - char com[MAXCOMLINE+1]; + char com[MAXFILLEN+1]; int linenumber = 0; int status; @@ -101,16 +104,19 @@ char *argv[]; } if (argc == 0) usage(); - if (locatestring(argv[0], "http:", 1) || locatestring(argv[0], "file:", 1)) + if (locatestring(argv[0], "http:", MATCH_AT_FIRST) || + locatestring(argv[0], "ftp:", MATCH_AT_FIRST) || + locatestring(argv[0], "news:", MATCH_AT_FIRST) || + locatestring(argv[0], "mail:", MATCH_AT_FIRST) || + locatestring(argv[0], "file:", MATCH_AT_FIRST)) strcpy(URL, argv[0]); else { char *abspath; - char pathbuf[MAXPATHLEN+1]; - char htmlpath[MAXPATHLEN+1]; + char buf[MAXPATHLEN+1]; - if (!test("f", argv[0]) && !test("d", argv[0])) + if (!test("f", argv[0]) && !test("d", NULL)) die1("path '%s' not found.", argv[0]); - if (!(abspath = realpath(argv[0], pathbuf))) + if (!(abspath = realpath(argv[0], buf))) die1("cannot make absolute path name. realpath(%s) failed.", argv[0]); if (*abspath != '/') die("realpath(3) is not compatible with BSD version."); @@ -152,7 +158,7 @@ char *argv[]; /* * execute generic browser. */ - if (browser && !locatestring(browser, "netscape", 3)) { + if (browser && !locatestring(browser, "netscape", MATCH_AT_LAST)) { sprintf(com, "%s '%s'", browser, URL); system(com); exit (0); @@ -171,7 +177,7 @@ char *argv[]; if ((pid = fork()) < 0) { die("cannot execute netscape (fork)."); } else if (pid == 0) { - execlp("netscape", "netscape", URL, (char *)0); + execlp("netscape", "netscape", URL, NULL); die("loading mozilla failed."); } exit(0); @@ -179,6 +185,34 @@ char *argv[]; exit(status); } int +issource(path) +char *path; +{ + STRBUF *sb = stropen(); + char *p; + char suff[MAXPATHLEN+1]; + int retval = 0; + + if (!getconfs("suffixes", sb)) { + strclose(sb); + return 0; + } + suff[0] = '.'; + for (p = strvalue(sb); p; ) { + char *unit = p; + if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL) + *p++ = 0; + strcpy(&suff[1], unit); + if (locatestring(path, suff, MATCH_AT_LAST)) { + retval = 1; + break; + } + } + strclose(sb); + return retval; + +} +int sendcommand(com) char *com; { @@ -188,7 +222,7 @@ char *com; argv[0] = "netscape-remote"; argv[1] = "-remote"; argv[2] = com; - argv[3] = (char *)0; + argv[3] = NULL; return netscape_remote(argc, argv); } diff --git a/contrib/global/gozilla/gozilla.man b/contrib/global/gozilla/gozilla.man index 1065529e1f07..39e257fd2b3b 100644 --- a/contrib/global/gozilla/gozilla.man +++ b/contrib/global/gozilla/gozilla.man @@ -139,3 +139,7 @@ can treat not only source file but also normal file, directory, HTML file and even URL, because it is omnivorous. .Sh AUTHORS Shigio Yamaguchi (shigio@wafu.netgate.net) +.Sh HISTORY +The +.Nm +command appeared in FreeBSD 2.2.5. diff --git a/contrib/global/gozilla/remote.c b/contrib/global/gozilla/remote.c index d2e6a3417ce8..ebc08d7ca109 100644 --- a/contrib/global/gozilla/remote.c +++ b/contrib/global/gozilla/remote.c @@ -586,7 +586,7 @@ usage (void) int netscape_remote(int argc, char **argv) #else -void +int main (int argc, char **argv) #endif { diff --git a/contrib/global/gtags.el b/contrib/global/gtags.el index 2a8de7950e56..22dcc9356315 100644 --- a/contrib/global/gtags.el +++ b/contrib/global/gtags.el @@ -1,7 +1,7 @@ ;;; gtags.el --- gtags facility for Emacs ;; -;; Copyright (c) 1997 Shigio Yamaguchi. All rights reserved. +;; Copyright (c) 1997, 1998, 1999 Shigio Yamaguchi. All rights reserved. ;; ;; Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions @@ -30,12 +30,12 @@ ;; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ;; SUCH DAMAGE. ;; -;; gtags.el 31-Aug-97 +;; gtags.el 8-Jan-99 ;; ;; This file is part of GLOBAL. ;; Author: Shigio Yamaguchi -;; Version: 1.1 +;; Version: 1.5 ;; Keywords: tools ;;; Code @@ -59,6 +59,7 @@ (define-key gtags-mode-map "\es" 'gtags-find-symbol) (define-key gtags-mode-map "\eg" 'gtags-find-pattern) (define-key gtags-mode-map "\C-]" 'gtags-find-tag-from-here) +(define-key gtags-mode-map "\eh" 'gtags-display-browser) (define-key gtags-mode-map "\C-t" 'gtags-pop-stack) (define-key gtags-mode-map "\e." 'etags-style-find-tag) (define-key gtags-mode-map [mouse-2] 'gtags-find-tag-by-event) @@ -83,7 +84,7 @@ ;; ;; utility ;; -(defun match-string (n) +(defun util-match-string (n) (buffer-substring (match-beginning n) (match-end n))) ;; Return a default tag to search for, based on the text at point. @@ -99,7 +100,7 @@ (if (and (bolp) (looking-at definition-regexp)) (goto-char (match-end 0))) (if (looking-at symbol-regexp) - (match-string 0) nil)) + (util-match-string 0) nil)) ;; push current context to stack (defun push-context () @@ -132,18 +133,20 @@ ;; is it a definition? (defun is-definition () (save-excursion - (if (bolp) + (if (and (string-match "\.java$" buffer-file-name) (looking-at "[^(]+([^)]*)[ \t]*{")) t - (forward-word -1) - (cond - ((looking-at "define") - (forward-char -1) - (while (and (not (bolp)) (looking-at "[ \t]")) - (forward-char -1)) - (if (and (bolp) (looking-at "#")) - t nil)) - ((looking-at "ENTRY\\|ALTENTRY") - (if (bolp) t nil)))))) + (if (bolp) + t + (forward-word -1) + (cond + ((looking-at "define") + (forward-char -1) + (while (and (not (bolp)) (looking-at "[ \t]")) + (forward-char -1)) + (if (and (bolp) (looking-at "#")) + t nil)) + ((looking-at "ENTRY\\|ALTENTRY") + (if (bolp) t nil))))))) ;; ;; interactive command @@ -216,6 +219,18 @@ (push-context) (gtags-goto-tag tagname flag)))) +(defun gtags-display-browser () + "Display current screen on hypertext browser." + (interactive) + (let (lno) + (save-excursion + (end-of-line) + (if (equal (point-min) (point)) + (setq lno 1) + (setq lno (count-lines (point-min) (point))))) + (message (number-to-string lno)) + (call-process "gozilla" nil t nil (concat "+" (number-to-string lno)) buffer-file-name))) + (defun gtags-find-tag-by-event (event) "Get the expression as a tagname around here and move there." (interactive "e") @@ -307,8 +322,8 @@ ;; (if (not (looking-at "[A-Za-z_][A-Za-z_0-9]*[ \t]+\\([0-9]+\\)[ \t]\\([^ \t]+\\)[ \t]")) (if (not (looking-at "[^ \t]+[ \t]+\\([0-9]+\\)[ \t]\\([^ \t]+\\)[ \t]")) (pop-context) - (setq line (string-to-number (match-string 1))) - (setq file (match-string 2)) + (setq line (string-to-number (util-match-string 1))) + (setq file (util-match-string 2)) (if delete (kill-buffer (current-buffer))) ;; move to the context (if gtags-read-only (find-file-read-only file) (find-file file)) @@ -317,13 +332,15 @@ ;; make complete list (defun make-gtags-complete-list () +;; "Make tag name list for completion." +;; (interactive) (save-excursion (setq gtags-complete-list (make-vector 63 0)) (set-buffer (generate-new-buffer "*Completions*")) (call-process "global" nil t nil "-c") (goto-char (point-min)) (while (looking-at symbol-regexp) - (intern (match-string 0) gtags-complete-list) + (intern (util-match-string 0) gtags-complete-list) (forward-line)) (kill-buffer (current-buffer)))) @@ -331,7 +348,8 @@ (defun gtags-mode () "Minor mode for browsing C source using GLOBAL." (interactive) - (make-gtags-complete-list) + (if (y-or-n-p "Do you use function name completion?") + (make-gtags-complete-list)) (use-local-map gtags-mode-map) (run-hooks 'gtags-mode-hook)) diff --git a/contrib/global/gtags/Makefile b/contrib/global/gtags/Makefile index 9afed8066cf6..ecfb0eade37d 100644 --- a/contrib/global/gtags/Makefile +++ b/contrib/global/gtags/Makefile @@ -1,6 +1,3 @@ PROG= gtags -CFLAGS+=-I${.CURDIR}/../lib -LDADD= $(LIBUTIL) -DPADD= $(LIBUTIL) .include diff --git a/contrib/global/gtags/gtags.1 b/contrib/global/gtags/gtags.1 index ed18616528d3..e6b09e69bc6e 100644 --- a/contrib/global/gtags/gtags.1 +++ b/contrib/global/gtags/gtags.1 @@ -1,5 +1,5 @@ .\" -.\" Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved. +.\" Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -28,26 +28,28 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd Sep 12, 1997 +.Dd Oct 10, 1998 .Dt GTAGS 1 .Os BSD 4 .Sh NAME .Nm gtags -.Nd create GTAGS, GRTAGS and GSYMS file +.Nd create tag files for global. .Sh SYNOPSIS .Nm gtags +.Op Fl c .Op Fl i .Op Fl o +.Op Fl w .Op Fl v .Op Ar dbpath .Sh DESCRIPTION .Nm Gtags -makes GTAGS, GRTAGS and GSYMS file for +makes GTAGS, GRTAGS, GSYMS and GPATH file for .Xr global 1 . .Nm Gtags trace subdirectories, read source files, locate symbols and save the information into tag files. -C, yacc and assembler source files are supported. +C, yacc, java and assembler source files are supported. You should execute this command at the root of the source tree. .Pp If your source directory is on a read only device like CDROM, specify @@ -55,13 +57,16 @@ If your source directory is on a read only device like CDROM, specify of the directory on which make tag files. .Pp .Bl -tag -width Ds +.It Fl c +make tag files with compact format. .It Fl i -update tag files incrementally by files which modified after the tag files were -last updated. +update tag files incrementally. .It Fl o suppress making GSYMS file. Use this option if you don't use -s option of .Xr global 1 . +.It Fl w +print warning messages. .It Fl v verbose mode. .Sh FILES @@ -72,6 +77,8 @@ tag file for function definitions. tag file for function references. .It Pa GSYMS tag file for other symbols. +.It Pa GPATH +path index file which is used for incremental updating and compact format. .El .Sh DIAGNOSTICS .Nm Gtags @@ -85,7 +92,7 @@ exits with a non 0 value if an error occurred, 0 otherwise. GTAGS, GRTAGS and GSYMS are very large. In advance of using this command, check the space of your disk. .br -Assembler support is far from completeness. It extracts only ENTRY() +Assembler support is far from complete. It extracts only ENTRY() and ALTENTRY() from source file. Probably valid only for FreeBSD and Linux kernel source. .br diff --git a/contrib/global/gtags/gtags.c b/contrib/global/gtags/gtags.c index 288c16c1daf3..7a88747e29ac 100644 --- a/contrib/global/gtags/gtags.c +++ b/contrib/global/gtags/gtags.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved. + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,60 +28,105 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * gtags.c 12-Dec-97 + * gtags.c 8-Oct-98 * */ - +#include #include #include #include #include +#include #include #include #include "global.h" -char *progname = "gtags"; /* command name */ +const char *progname = "gtags"; /* command name */ static void usage __P((void)); -void main __P((int, char **)); -int incremental __P((char *)); -void tagadd __P((int, char *)); -void createtags __P((char *, int)); -char *current __P((void)); +int main __P((int, char **)); +int incremental __P((char *, char *)); +void updatetags __P((char *, char *, char *, int)); +void createtags __P((char *, char *, int)); +int printconf __P((char *)); +char *now __P((void)); -static int iflag; -static int oflag; -static int vflag; +int cflag; /* compact format */ +int iflag; /* incremental update */ +int oflag; /* suppress making GSYMS */ +int wflag; /* warning message */ +int vflag; /* verbose mode */ +int extractmethod = 0; static void usage() { - fprintf(stderr, "usage:\t%s [-i][-o][-v][dbpath]\n", progname); + fprintf(stderr, "usage:\t%s [-c][-i][-l][-o][-w][-v][dbpath]\n", progname); exit(1); } -void +int main(argc, argv) int argc; char *argv[]; { char dbpath[MAXPATHLEN+1]; + char cwd[MAXPATHLEN+1]; char env[MAXENVLEN+1]; - char *p; + STRBUF *sb = stropen(); int db; while (--argc > 0 && (++argv)[0][0] == '-') { + char *p; + /* + * Secret option for htags(1). + */ + if (!strcmp(argv[0], "--config")) { + if (argc == 1) + fprintf(stdout, "%s\n", configpath()); + else if (argc == 2) { + if (!printconf(argv[1])) + exit(1); + } + exit(0); + } else if (!strcmp(argv[0], "--find")) { + for (findopen(); (p = findread(NULL)) != NULL; ) + fprintf(stdout, "%s\n", p); + findclose(); + exit(0); + } else if (!strcmp(argv[0], "--expand")) { + FILE *ip; + + ++argv; --argc; + if (argc && argv[0][0] == '-') { + settabs(atoi(&argv[0][1])); + ++argv; --argc; + } + ip = (argc) ? fopen(argv[0], "r") : stdin; + if (ip == NULL) + exit(1); + while ((p = mgets(ip, NULL, 0)) != NULL) + detab(stdout, p); + exit(0); + } + for (p = argv[0] + 1; *p; p++) { switch (*p) { + case 'c': + cflag++; + break; case 'i': iflag++; break; case 'o': oflag++; break; + case 'w': + wflag++; + break; case 'v': vflag++; break; @@ -94,30 +139,48 @@ char *argv[]; } } } - if (argc > 0) { - strcpy(dbpath, *argv); - } else { - if (!getcwd(dbpath, MAXPATHLEN)) - die("cannot get current directory."); - } + if (!getcwd(cwd, MAXPATHLEN)) + die("cannot get current directory."); + if (argc > 0) + realpath(*argv,dbpath) ; + else + strcpy(dbpath, cwd); if (!strcmp(dbpath, "/")) die("It's root directory! What are you doing?"); if (!test("d", dbpath)) die1("directory '%s' not found.", dbpath); if (vflag) - fprintf(stderr, "[%s] Gtags started\n", current()); + fprintf(stderr, "[%s] Gtags started\n", now()); + /* + * load .gtagsrc or /etc/gtags.conf + */ + openconf(); + if (getconfb("extractmethod")) + extractmethod = 1; + strstart(sb); + if (getconfs("format", sb) && !strcmp(strvalue(sb), "compact")) + cflag++; /* * teach gctags(1) where is dbpath. */ sprintf(env, "GTAGSDBPATH=%s", dbpath); putenv(env); + if (wflag) { + sprintf(env, "GTAGSWARNING=1"); + putenv(env); + } /* * incremental update. */ if (iflag && test("f", makepath(dbpath, dbname(GTAGS))) && test("f", makepath(dbpath, dbname(GRTAGS)))) { - (void)incremental(dbpath); + /* open for version check */ + GTOP *gtop = gtagsopen(dbpath, cwd, GTAGS, GTAGS_MODIFY, 0); + gtagsclose(gtop); + if (!test("f", makepath(dbpath, "GPATH"))) + die("Old version tag file found. Please remake it."); + (void)incremental(dbpath, cwd); exit(0); } if (iflag && vflag) @@ -126,32 +189,43 @@ char *argv[]; * create GTAGS, GRTAGS and GSYMS */ for (db = GTAGS; db < GTAGLIM; db++) { + if (oflag && db == GSYMS) continue; + strstart(sb); + if (!getconfs(dbname(db), sb)) + continue; + if (!usable(strmake(strvalue(sb), " \t"))) + die1("Parser '%s' not found or not executable.", strmake(strvalue(sb), " \t")); if (vflag) - fprintf(stderr, "[%s] Creating '%s'.\n", current(), dbname(db)); - createtags(dbpath, db); + fprintf(stderr, "[%s] Creating '%s'.\n", now(), dbname(db)); + createtags(dbpath, cwd, db); } if (vflag) - fprintf(stderr, "[%s] Done.\n", current()); + fprintf(stderr, "[%s] Done.\n", now()); + closeconf(); exit(0); } /* * incremental: incremental update * * i) dbpath dbpath directory + * i) root root directory of source tree * r) 0: not updated, 1: updated */ int -incremental(dbpath) +incremental(dbpath, root) char *dbpath; +char *root; { - struct stat sb; + struct stat statp; time_t gtags_mtime; + STRBUF *addlist = stropen(); + STRBUF *updatelist = stropen(); + STRBUF *deletelist = stropen(); int updated = 0; char *path; - int db; if (vflag) { fprintf(stderr, " Tag found in '%s'.\n", dbpath); @@ -161,145 +235,255 @@ char *dbpath; * get modified time of GTAGS. */ path = makepath(dbpath, dbname(GTAGS)); - if (stat(path, &sb) < 0) + if (stat(path, &statp) < 0) die1("stat failed '%s'.", path); - gtags_mtime = sb.st_mtime; + gtags_mtime = statp.st_mtime; + if (pathopen(dbpath, 0) < 0) + die("GPATH not found."); + /* + * make add list and update list. + */ for (findopen(); (path = findread(NULL)) != NULL; ) { - if (stat(path, &sb) < 0) + if (stat(path, &statp) < 0) die1("stat failed '%s'.", path); - /* - * only the path modified after GTAGS was modified. - */ - if (gtags_mtime < sb.st_mtime) { - updated = 1; - if (vflag) - fprintf(stderr, " Updating tags of '%s' ...", path + 2); - for (db = GTAGS; db < GTAGLIM; db++) { - if (db == GSYMS && !test("f", makepath(dbpath, dbname(db)))) - continue; - if (vflag) - fprintf(stderr, "%s", dbname(db)); - tagopen(dbpath, db, 2); - /* - * GTAGS needed to make GRTAGS. - */ - if (db == GRTAGS) - lookupopen(dbpath); - tagdelete(path); - if (vflag) - fprintf(stderr, ".."); - tagadd(db, path); - if (db == GRTAGS) - lookupclose(); - tagclose(); - } - if (vflag) - fprintf(stderr, " Done.\n"); - } + if (!pathget(path)) + strnputs(addlist, path, strlen(path) + 1); + else if (gtags_mtime < statp.st_mtime) + strnputs(updatelist, path, strlen(path) + 1); } findclose(); + /* + * make delete list. + */ + { + int i, limit = nextkey(); + + for (i = 0; i < limit; i++) { + if ((path = pathiget(i)) == NULL) + continue; + if (!test("f", path)) + strnputs(deletelist, path, strlen(path) + 1); + } + } + pathclose(); + if (strbuflen(addlist) + strbuflen(deletelist) + strbuflen(updatelist)) + updated = 1; + /* + * execute updating. + */ + if (strbuflen(updatelist) > 0) { + char *start = strvalue(updatelist); + char *end = start + strbuflen(updatelist); + char *p; + + for (p = start; p < end; p += strlen(p) + 1) + updatetags(dbpath, root, p, 0); + updated = 1; + } + if (strbuflen(addlist) > 0) { + char *start = strvalue(addlist); + char *end = start + strbuflen(addlist); + char *p; + + for (p = start; p < end; p += strlen(p) + 1) + updatetags(dbpath, root, p, 1); + updated = 1; + } + if (strbuflen(deletelist) > 0) { + char *start = strvalue(deletelist); + char *end = start + strbuflen(deletelist); + char *p; + + for (p = start; p < end; p += strlen(p) + 1) + updatetags(dbpath, root, p, 2); + + pathopen(dbpath, 2); + for (p = start; p < end; p += strlen(p) + 1) + pathdel(p); + pathclose(); + updated = 1; + } if (vflag) { if (updated) fprintf(stderr, " Global databases have been modified.\n"); else fprintf(stderr, " Global databases are up to date.\n"); - fprintf(stderr, "[%s] Done.\n", current()); - - fprintf(stderr, " Done.\n"); + fprintf(stderr, "[%s] Done.\n", now()); } + strclose(addlist); + strclose(deletelist); + strclose(updatelist); return updated; } /* - * tagadd: add records which has specified path. + * updatetags: update tag file. * - * i) db 0: GTAGS, 1: GRTAGS, 2: GSYMS - * i) path source file + * i) dbpath directory in which tag file exist + * i) root root directory of source tree + * i) path path which should be updated + * i) type 0:update, 1:add, 2:delete */ void -tagadd(db, path) -int db; +updatetags(dbpath, root, path, type) +char *dbpath; +char *root; char *path; +int type; { - char *tagline, *p, *q; - char key[IDENTLEN+1]; - FILE *ip; + GTOP *gtop; + STRBUF *sb = stropen(); + int db; + const char *msg = NULL; - stropen(); - /* - * make command line. - */ - strputs("gctags -Dex"); - if (db == GRTAGS) - strputs("r"); - if (db == GSYMS) - strputs("sc"); - strputc(' '); - strputs(path); - p = strclose(); - if (!(ip = popen(p, "r"))) - die1("cannot execute '%s'.", p); - while ((tagline = mgets(ip, 0, NULL)) != NULL) { - p = tagline; - q = key; - while (*p && !isspace(*p)) - *q++ = *p++; - *q = 0; - tagput(key, tagline); + switch (type) { + case 0: msg = "Updating"; break; + case 1: msg = "Adding"; break; + case 2: msg = "Deleting"; break; } - pclose(ip); + if (vflag) + fprintf(stderr, " %s tags of '%s' ...", msg, path + 2); + for (db = GTAGS; db < GTAGLIM; db++) { + int flags = 0; + + if (db == GSYMS && !test("f", makepath(dbpath, dbname(db)))) + continue; + if (vflag) + fprintf(stderr, "%s", dbname(db)); + /* + * get tag command. + */ + strstart(sb); + if (!getconfs(dbname(db), sb)) + die1("cannot get tag command. (%s)", dbname(db)); + gtop = gtagsopen(dbpath, root, db, GTAGS_MODIFY, 0); + /* + * GTAGS needed to make GRTAGS. + */ + if (db == GRTAGS && !test("f", makepath(dbpath, "GTAGS"))) + die("GTAGS needed to create GRTAGS."); + if (type != 1) + gtagsdelete(gtop, path); + if (vflag) + fprintf(stderr, ".."); + if (type != 2) { + if (db == GSYMS) + flags |= GTAGS_UNIQUE; + if (extractmethod) + flags |= GTAGS_EXTRACTMETHOD; + gtagsadd(gtop, strvalue(sb), path, flags); + } + gtagsclose(gtop); + } + if (vflag) + fprintf(stderr, " Done.\n"); + strclose(sb); } /* * createtags: create tags file * * i) dbpath dbpath directory + * i) root root directory of source tree * i) db GTAGS, GRTAGS, GSYMS */ void -createtags(dbpath, db) +createtags(dbpath, root, db) char *dbpath; +char *root; int db; { char *path; + GTOP *gtop; + int flags; + char *comline; + STRBUF *sb = stropen(); + /* + * get tag command. + */ + if (!getconfs(dbname(db), sb)) + die1("cannot get tag command. (%s)", dbname(db)); + comline = strdup(strvalue(sb)); + if (!comline) + die("short of memory."); /* * GTAGS needed to make GRTAGS. */ - if (db == GRTAGS) - lookupopen(dbpath); - tagopen(dbpath, db, 1); + if (db == GRTAGS && !test("f", makepath(dbpath, "GTAGS"))) + die("GTAGS needed to create GRTAGS."); + flags = 0; + strstart(sb); + if (cflag) { + flags |= GTAGS_COMPACT; + flags |= GTAGS_PATHINDEX; + } + strstart(sb); + if (vflag > 1 && getconfs(dbname(db), sb)) + fprintf(stderr, " using tag command '%s '.\n", strvalue(sb)); + gtop = gtagsopen(dbpath, root, db, GTAGS_CREATE, flags); for (findopen(); (path = findread(NULL)) != NULL; ) { + int gflags = 0; /* * GSYMS doesn't treat asembler. */ - if (db == GSYMS) { - char *p = path + strlen(path) - 1; - if ((*p == 's' || *p == 'S') && *(p - 1) == '.') + if (db == GSYMS) + if (locatestring(path, ".s", MATCH_AT_LAST) != NULL || + locatestring(path, ".S", MATCH_AT_LAST) != NULL) continue; - } if (vflag) fprintf(stderr, " extracting tags of %s.\n", path); - tagadd(db, path); + if (db == GSYMS) + gflags |= GTAGS_UNIQUE; + if (extractmethod) + gflags |= GTAGS_EXTRACTMETHOD; + gtagsadd(gtop, comline, path, gflags); } findclose(); - tagclose(); - if (db == GRTAGS) - lookupclose(); + gtagsclose(gtop); + free(comline); + strclose(sb); } /* - * current: current date and time + * now: current date and time * * r) date and time */ -char * -current(void) +char * +now(void) { static char buf[80]; time_t tval; if (time(&tval) == -1) die("cannot get current time."); - (void)strftime(buf, sizeof(buf), "%+", localtime(&tval)); - + (void)strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval)); return buf; } +/* + * printconf: print configuration data. + * + * i) name label of config data + * r) exit code + */ +int +printconf(name) +char *name; +{ + STRBUF *sb; + int num; + int exist = 1; + + if (getconfn(name, &num)) + fprintf(stdout, "%d\n", num); + else if (getconfb(name)) + fprintf(stdout, "1\n"); + else { + sb = stropen(); + if (getconfs(name, sb)) + fprintf(stdout, "%s\n", strvalue(sb)); + else + exist = 0; + strclose(sb); + } + return exist; +} diff --git a/contrib/global/htags/htags.1 b/contrib/global/htags/htags.1 index e2f03559868c..4c22448e6f02 100644 --- a/contrib/global/htags/htags.1 +++ b/contrib/global/htags/htags.1 @@ -1,5 +1,5 @@ .\" -.\" Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved. +.\" Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -28,16 +28,18 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 28, 1997 +.Dd Oct 11, 1998 .Dt HTAGS 1 .Os BSD 4 .Sh NAME .Nm htags -.Nd generate hypertext from C and Yacc source code +.Nd generate hypertext from C, Yacc and Java source code .Sh SYNOPSIS .Nm htags .Op Fl a +.Op Fl c .Op Fl f +.Op Fl h .Op Fl l .Op Fl n .Op Fl v @@ -47,47 +49,59 @@ .Op Ar dir .Sh DESCRIPTION .Nm Htags -makes hypertext from C and Yacc source code using GLOBAL database (GTAGS, GRTAGS). +makes hypertext from C, Yacc and Java source code using GLOBAL database (GTAGS, GRTAGS). .Pp In advance of using this command, you must execute .Xr gtags 1 -at the root directory of the source tree. +from the root directory of the source tree. Then you can execute .Nm htags -at the same place. +from the same place. .Nm Htags -makes HTML directory and generate hypertext in it. +makes an HTML directory and generates hypertext in it. .Pp You can start browsing from 'HTML/index.html'. -Once hypertext generated, you can move it anywhere and browse it -by any browsers. +Once the hypertext is generated, you can move it anywhere and browse it +in any browsers. .Pp .br .Bl -tag -width Ds .It Fl a -make an alphabetical function index. It's suitable for large project. +Make an alphabetical function index, suitable for a large project. +.It Fl c +Compress html files by +.Xr gzip 1 . +You need to set up an HTTP server so that +.Xr gzip 1 +is invoked for each compressed +files. See skelton file 'HTML/.htaccess.skel' that is generated by htags. .It Fl f -support input form and dynamic index by CGI program. -You need to setup HTTP server for it. +Support an input form and a dynamic index with a CGI program. +You need to set up an HTTP server for this. +.It Fl h +Add title header frame. By default, doesn't add this. .It Fl l -make name tag() for each line so that outer hypertext -can point any line of this hypertext. -By default, make it only for lines which have referred object. +Make a name tag() for each line, so that other hypertext +can link to any line of this hypertext. +By default, htags makes it only for lines that are referred to by an object. .It Fl n -print line number. By default, doesn't print it. +Print the line numbers (they are not printed by default). .It Fl v -verbose mode. +Verbose mode. .It Fl w -print warning message. +Print a warning message. .It Fl d Ar tagdir -the directory in which GTAGS and GRTAGS exist. Default is current directory. +Specifies the directory in which GTAGS and GRTAGS exist. The default is the +current directory. .It Fl t Ar title -Tile of this hypertext. Default is the last component of current path. +The title of this hypertext. Defaults to the last component of the current +path. .It Ar dir -the directory in which hypertext generated. Default is current directory. +The directory in which hypertext is generated. The default is the current +directory. .Sh EXAMPLES % cd /usr/src/sys - # gtags -se + # gtags -o # htags -fnvat 'Welcom to FreeBSD kernel source tour!' % lynx HTML/index.html .Sh FILES @@ -95,17 +109,17 @@ the directory in which hypertext generated. Default is current directory. .It Pa HTML/index.html Index file. .It Pa GTAGS -tags file for function definitions. +Tags file for function definitions. .It Pa GRTAGS -tags file for function references. +Tags file for function references. .El .Sh ENVIRONMENT The following environment variables affect the execution of htags. .Pp .Bl -tag -width indent .It Ev TMPDIR -If this variable is set, its value is used as the directory to make temporary file. -Default is /tmp. +If this variable is set, its value is used as the directory to make temporary files. +The default is /tmp. .Sh DIAGNOSTICS .Nm Htags exits with a non 0 value if an error occurred, 0 otherwise. diff --git a/contrib/global/htags/htags.pl b/contrib/global/htags/htags.pl index e4e6de89d51f..d8488deae6c9 100644 --- a/contrib/global/htags/htags.pl +++ b/contrib/global/htags/htags.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl # -# Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved. +# Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -29,77 +29,196 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# htags.pl 20-Jan-98 +# htags.pl 10-Nov-98 # $com = $0; $com =~ s/.*\///; -$usage = "usage: $com [-a][-f][-l][-n][-v][-w][-t title][-d tagdir][dir]\n"; +$usage = "usage: $com [-a][-c][-f][-h][-l][-n][-v][-w][-t title][-d tagdir][dir]\n"; +#------------------------------------------------------------------------- +# COMMAND EXISTENCE CHECK +#------------------------------------------------------------------------- +foreach $c ('sort', 'gtags', 'global', 'btreeop') { + if (!&'usable($c)) { + &'error("'$c' command is required but not found."); + } +} #------------------------------------------------------------------------- # CONFIGURATION #------------------------------------------------------------------------- -# columns of line number -$ncol = 4; -# font -$comment_begin = ''; # /* ... */ -$comment_end = ''; -$sharp_begin = ''; # #define, #include or so on -$sharp_end = ''; -$brace_begin = ''; # { ... } -$brace_end = ''; -$reserved_begin = ''; # if, while, for or so on -$reserved_end = ''; -# reserved words -$reserved_words = "auto|break|case|char|continue|default|do|double|else|extern|float|for|goto|if|int|long|register|return|short|sizeof|static|struct|switch|typedef|union|unsigned|void|while"; # temporary directory -$tmp = '/tmp'; +$'tmp = '/tmp'; if (defined($ENV{'TMPDIR'}) && -d $ENV{'TMPDIR'}) { $tmp = $ENV{'TMPDIR'}; } +$'ncol = 4; # columns of line number +$'tabs = 8; # tab skip +$'gzipped_suffix = 'ghtml'; # suffix of gzipped html file +# +# font +# +$'title_begin = ''; +$'title_end = ''; +$'comment_begin = ''; # /* ... */ +$'comment_end = ''; +$'sharp_begin = ''; # #define, #include or so on +$'sharp_end = ''; +$'brace_begin = ''; # { ... } +$'brace_end = ''; +$'reserved_begin = ''; # if, while, for or so on +$'reserved_end = ''; +# +# color +# +$'body_bgcolor = ''; +$'body_text = ''; +$'body_link = ''; +$'body_vlink = ''; +$'body_alink = ''; +# +# Reserved words for C and Java are hard coded. +# (configuration parameter 'reserved_words' was deleted.) +# +$'c_reserved_words = "auto,break,case,char,continue,default,do,double,else," . + "extern,float,for,goto,if,int,long,register,return," . + "short,sizeof,static,struct,switch,typedef,union," . + "unsigned,void,while"; +$'java_reserved_words = "abstract,boolean,break,byte,case,catch,char,class," . + "const,continue,default,do,double,else,extends,false," . + "final,finally,float,for,goto,if,implements,import," . + "instanceof,int,interface,long,native,new,null," . + "package,private,protected,public,return,short," . + "static,super,switch,synchronized,this,throw,throws," . + "union,transient,true,try,void,volatile,while"; +$'c_reserved_words =~ s/,/|/g; +$'java_reserved_words =~ s/,/|/g; +# +# read values from global.conf +# +chop($config = `gtags --config`); +if ($config) { + if ($var1 = &'getconf('ncol')) { + if ($var1 < 1 || $var1 > 10) { + print STDERR "Warning: parameter 'ncol' ignored becase the value is too large or too small.\n"; + } else { + $ncol = $var1; + } + } + if ($var1 = &'getconf('tabs')) { + if ($var1 < 1 || $var1 > 32) { + print STDERR "Warning: parameter 'tabs' ignored becase the value is too large or too small.\n"; + } else { + $tabs = $var1; + } + } + if ($var1 = &'getconf('gzipped_suffix')) { + $gzipped_suffix = $var1; + } + if (($var1 = &'getconf('title_begin')) && ($var2 = &'getconf('title_end'))) { + $title_begin = $var1; + $title_end = $var2; + } + if (($var1 = &'getconf('comment_begin')) && ($var2 = &'getconf('comment_end'))) { + $comment_begin = $var1; + $comment_end = $var2; + } + if (($var1 = &'getconf('sharp_begin')) && ($var2 = &'getconf('sharp_end'))) { + $sharp_begin = $var1; + $sharp_end = $var2; + } + if (($var1 = &'getconf('brace_begin')) && ($var2 = &'getconf('brace_end'))) { + $brace_begin = $var1; + $brace_end = $var2; + } + if (($var1 = &'getconf('reserved_begin')) && ($var2 = &'getconf('reserved_end'))) { + $reserved_begin = $var1; + $reserved_end = $var2; + } + $body_bgcolor = $var1 if ($var1 = &'getconf('bgcolor')); + $body_text = $var1 if ($var1 = &'getconf('text')); + $body_link = $var1 if ($var1 = &'getconf('link')); + $body_vlink = $var1 if ($var1 = &'getconf('vlink')); + $body_alink = $var1 if ($var1 = &'getconf('alink')); +} +# HTML tag +$'begin_html = "\n"; +$'end_html = "\n"; +$'begin_body = '')); -# frame name -$f_mains = 'mains'; # for main view -$f_funcs = 'funcs'; # for function index -$f_files = 'files'; # for file index -$begin_script="\n"; -$defaultview= +$'langle = sprintf("unescape('%s')", &'escape('<')); +$'rangle = sprintf("unescape('%s')", &'escape('>')); +$'begin_script="\n"; +$'default_view= "// if your browser doesn't support javascript, write a BASE tag statically.\n" . "if (parent.frames.length)\n" . - " document.write($langle+'BASE TARGET=$f_mains'+$rangle)\n"; -$rewrite_href_funcs = - "if (parent.frames.length && parent.$f_funcs == self) {\n" . + " document.write($langle+'BASE TARGET=mains'+$rangle)\n"; +$'rewrite_href_funcs = + "if (parent.frames.length && parent.funcs == self) {\n" . " document.links[0].href = '../funcs.html';\n" . " document.links[document.links.length - 1].href = '../funcs.html';\n" . "}\n"; -$rewrite_href_files = - "if (parent.frames.length && parent.$f_files == self) {\n" . - " document.links[0].href = '../files.html';\n" . - " document.links[document.links.length - 1].href = '../files.html';\n" . +$'rewrite_href_files = + "if (parent.frames.length && parent.files == self) {\n" . + " document.links[0].href = '../files.html';\n" . + " document.links[document.links.length - 1].href = '../files.html';\n" . "}\n"; +sub set_header { + local($display, $title, $script) = @_; + local($head) = "$title"; + if ($script || ($'hflag && $display)) { + $head .= "\n"; + $head .= $'begin_script; + $head .= $script if ($script); + if ($'hflag && $display) { + $title = '[' . $title . ']' if ($title); + $head .= "if (parent.frames.length && parent.mains == self) {\n"; + $head .= " parent.title.document.open();\n"; + $head .= " parent.title.document.write('

$title

');\n"; + $head .= " parent.title.document.close();\n"; + $head .= "}\n"; + } + $head .= $'end_script; + } + $head .= "\n"; + $head; +} #------------------------------------------------------------------------- # UTIRITIES #------------------------------------------------------------------------- -$findcom = "find . \\( -type f -o -type l \\) -name '*.[chysS]' -print"; sub getcwd { local($dir) = `/bin/pwd`; chop($dir); $dir; } +sub realpath { + local($dir) = @_; + local($cwd) = &getcwd; + chdir($dir) || &'error("cannot change directory '$dir'."); + local($new) = &getcwd; + chdir($cwd) || &'error("cannot recover current directory '$cwd'."); + $new; +} sub date { local($date) = `date`; chop($date); @@ -119,9 +238,9 @@ sub escape { '%' . sprintf("%x", ord($c)); } sub usable { - local($com) = @_; + local($command) = @_; foreach (split(/:/, $ENV{'PATH'})) { - return 1 if (-x "$_/$com"); + return 1 if (-x "$_/$command"); } return 0; } @@ -132,25 +251,46 @@ sub copy { $ret = ($ret == 0) ? 1 : 0; $ret; } +sub getconf { + local($name) = @_; + local($val); + chop($val = `gtags --config $name`); + if ($? != 0) { $val = ''; } + $val; +} +sub path2file { + local($path) = @_; + $path =~ s/^\.\///; + $path =~ s!/!$'SEP!g; + $path . '.' . $'HTML; +} +sub path2url { + local($path) = @_; + $path =~ s/^\.\///; + $path =~ s!/!$'ESCSEP!g; + $path . '.' . $'HTML; +} #------------------------------------------------------------------------- # PROCESS START #------------------------------------------------------------------------- # # options check. # -$aflag = $fflag = $lflag = $nflag = $vflag = $wflag = ''; +$'aflag = $'cflag = $'fflag = $'hflag = $'lflag = $'nflag = $'vflag = $'wflag = ''; while ($ARGV[0] =~ /^-/) { $opt = shift; - if ($opt =~ /[^-aflnvwtd]/) { + if ($opt =~ /[^-acfhlnvwtd]/) { print STDERR $usage; exit 1; } - if ($opt =~ /a/) { $aflag = 'a'; } - if ($opt =~ /f/) { $fflag = 'f'; } - if ($opt =~ /l/) { $lflag = 'l'; } - if ($opt =~ /n/) { $nflag = 'n'; } - if ($opt =~ /v/) { $vflag = 'v'; } - if ($opt =~ /w/) { $wflag = 'w'; } + if ($opt =~ /a/) { $'aflag = 'a'; } + if ($opt =~ /c/) { $'cflag = 'c'; } + if ($opt =~ /f/) { $'fflag = 'f'; } + if ($opt =~ /h/) { $'hflag = 'h'; } + if ($opt =~ /l/) { $'lflag = 'l'; } + if ($opt =~ /n/) { $'nflag = 'n'; } + if ($opt =~ /v/) { $'vflag = 'v'; } + if ($opt =~ /w/) { $'wflag = 'w'; } if ($opt =~ /t/) { $opt = shift; last if ($opt eq ''); @@ -161,62 +301,61 @@ while ($ARGV[0] =~ /^-/) { $dbpath = $opt; } } +if ($'cflag && !&'usable('gzip')) { + print STDERR "Warning: 'gzip' command not found. -c option ignored.\n"; + $'cflag = ''; +} if (!$title) { - @cwd = split('/', &getcwd); + @cwd = split('/', &'getcwd); $title = $cwd[$#cwd]; } -$dbpath = &getcwd() if (!$dbpath); +$dbpath = '.' if (!$dbpath); unless (-r "$dbpath/GTAGS" && -r "$dbpath/GRTAGS") { - &error("GTAGS and GRTAGS not found. please type 'gtags[RET]'"); + &'error("GTAGS and GRTAGS not found. Please make them."); } +$dbpath = &'realpath($dbpath); # -# recognize format version -# if version record is not found, it's assumed version 1. +# for global(1) # - $support_version = 1; # I can understand this format version -# -open(GTAGS, "btreeop -K ' __.VERSION' $dbpath/GTAGS |") || &error("GTAGS not found."); -$rec = ; -close(GTAGS); -if ($rec =~ /^ __\.VERSION[ \t]+([0-9]+)$/) { - $format_version = $1; -} else { - $format_version = 1; -} -if ($format_version != $support_version) { - &error("GTAGS format version unmatched. Please remake it."); -} +$ENV{'GTAGSROOT'} = &'getcwd(); +$ENV{'GTAGSDBPATH'} = $dbpath; +delete $ENV{'GTAGSLIBPATH'}; # # check directories # -$html = &getcwd() . '/HTML'; +$dist = &'getcwd() . '/HTML'; if ($ARGV[0]) { - $cwd = &getcwd(); + $cwd = &'getcwd(); unless (-w $ARGV[0]) { - &error("'$ARGV[0]' is not writable directory."); + &'error("'$ARGV[0]' is not writable directory."); } - chdir($ARGV[0]) || &error("directory '$ARGV[0]' not found."); - $html = &getcwd() . '/HTML'; - chdir($cwd) || &error("cannot return to original directory."); + chdir($ARGV[0]) || &'error("directory '$ARGV[0]' not found."); + $dist = &'getcwd() . '/HTML'; + chdir($cwd) || &'error("cannot return to original directory."); } # +# find filter +# +$'findcom = "gtags --find"; +# # check if GTAGS, GRTAGS is the latest. # $gtags_ctime = (stat("$dbpath/GTAGS"))[10]; -open(FIND, "$findcom |") || &error("cannot exec find."); +open(FIND, "$'findcom |") || &'error("cannot fork."); while () { chop; - next if /(y\.tab\.c|y\.tab\.h)$/; - next if /(\/SCCS\/|\/RCS\/)/; if ($gtags_ctime < (stat($_))[10]) { - &error("GTAGS is not the latest one. Please remake it."); + &'error("GTAGS is not the latest one. Please remake it."); } } close(FIND); +if ($?) { &'error("cannot traverse directory."); } #------------------------------------------------------------------------- # MAKE FILES #------------------------------------------------------------------------- # HTML/cgi-bin/global.cgi ... CGI program (1) +# HTML/cgi-bin/ghtml.cgi ... unzip script (1) +# HTML/.htaccess.skel ... skelton of .htaccess (1) # HTML/help.html ... help file (2) # HTML/$REFS/* ... referencies (3) # HTML/$DEFS/* ... definitions (3) @@ -226,92 +365,110 @@ close(FIND); # HTML/files/* ... file index (5) # HTML/index.html ... index file (6) # HTML/mains.html ... main index (7) +# HTML/null.html ... main null html (7) # HTML/$SRCS/ ... source files (8) # HTML/$INCS/ ... include file index (9) #------------------------------------------------------------------------- -print STDERR "[", &date, "] ", "Htags started\n" if ($vflag); +$'HTML = ($'cflag) ? $gzipped_suffix : 'html'; +print STDERR "[", &'date, "] ", "Htags started\n" if ($'vflag); # # (0) make directories # -print STDERR "[", &date, "] ", "(0) making directories ...\n" if ($vflag); -mkdir($html, 0777) || &error("cannot make directory '$html'.") if (! -d $html); +print STDERR "[", &'date, "] ", "(0) making directories ...\n" if ($'vflag); +mkdir($dist, 0777) || &'error("cannot make directory '$dist'.") if (! -d $dist); foreach $d ($SRCS, $INCS, $DEFS, $REFS, files, funcs) { - mkdir("$html/$d", 0775) || &error("cannot make HTML directory") if (! -d "$html/$d"); + mkdir("$dist/$d", 0775) || &'error("cannot make HTML directory") if (! -d "$dist/$d"); } -if ($fflag) { - mkdir("$html/cgi-bin", 0775) || &error("cannot make cgi-bin directory") if (! -d "$html/cgi-bin"); +if ($'fflag || $'cflag) { + mkdir("$dist/cgi-bin", 0775) || &'error("cannot make cgi-bin directory") if (! -d "$dist/cgi-bin"); } # # (1) make CGI program # -if ($fflag) { - print STDERR "[", &date, "] ", "(1) making CGI program ...\n" if ($vflag); - &makeprogram("$html/cgi-bin/global.cgi") || &error("cannot make CGI program."); - chmod(0755, "$html/cgi-bin/global.cgi") || &error("cannot chmod CGI program."); - unlink("$html/cgi-bin/GTAGS", "$html/cgi-bin/GRTAGS"); - link("$dbpath/GTAGS", "$html/cgi-bin/GTAGS") || ©("$dbpath/GTAGS", "$html/cgi-bin/GTAGS") || &error("cannot copy GTAGS."); - link("$dbpath/GRTAGS", "$html/cgi-bin/GRTAGS") || ©("$dbpath/GRTAGS", "$html/cgi-bin/GRTAGS") || &error("cannot copy GRTAGS."); +if ($'fflag) { + print STDERR "[", &'date, "] ", "(1) making CGI program ...\n" if ($'vflag); + &makeprogram("$dist/cgi-bin/global.cgi") || &'error("cannot make CGI program."); + chmod(0755, "$dist/cgi-bin/global.cgi") || &'error("cannot chmod CGI program."); + unlink("$dist/cgi-bin/GTAGS", "$dist/cgi-bin/GRTAGS", "$dist/cgi-bin/GPATH"); + link("$dbpath/GTAGS", "$dist/cgi-bin/GTAGS") || &'copy("$dbpath/GTAGS", "$dist/cgi-bin/GTAGS") || &'error("cannot copy GTAGS."); + link("$dbpath/GRTAGS", "$dist/cgi-bin/GRTAGS") || &'copy("$dbpath/GRTAGS", "$dist/cgi-bin/GRTAGS") || &'error("cannot copy GRTAGS."); + link("$dbpath/GPATH", "$dist/cgi-bin/GPATH") || &'copy("$dbpath/GPATH", "$dist/cgi-bin/GPATH") || &'error("cannot copy GPATH."); +} +if ($'cflag) { + &makehtaccess("$dist/.htaccess.skel") || &'error("cannot make .htaccess skelton."); + &makeghtml("$dist/cgi-bin/ghtml.cgi") || &'error("cannot make unzip script."); + chmod(0755, "$dist/cgi-bin/ghtml.cgi") || &'error("cannot chmod unzip script."); } # # (2) make help file # -print STDERR "[", &date, "] ", "(2) making help.html ...\n" if ($vflag); -&makehelp("$html/help.html"); +print STDERR "[", &'date, "] ", "(2) making help.html ...\n" if ($'vflag); +&makehelp("$dist/help.html"); # # (3) make function entries ($DEFS/* and $REFS/*) # MAKING TAG CACHE # -print STDERR "[", &date, "] ", "(3) making duplicate entries ...\n" if ($vflag); -sub suddenly { &clean(); exit 1} +print STDERR "[", &'date, "] ", "(3) making duplicate entries ...\n" if ($'vflag); +sub suddenly { &'clean(); exit 1} $SIG{'INT'} = 'suddenly'; $SIG{'QUIT'} = 'suddenly'; $SIG{'TERM'} = 'suddenly'; &cache'open(100000); -$func_total = &makedupindex(); -print STDERR "Total $func_total functions.\n" if ($vflag); +$func_total = &makedupindex($dist); +print STDERR "Total $func_total functions.\n" if ($'vflag); # # (4) make function index (funcs.html and funcs/*) # PRODUCE @funcs # -print STDERR "[", &date, "] ", "(4) making function index ...\n" if ($vflag); -$func_total = &makefuncindex("$html/funcs.html", $func_total); -print STDERR "Total $func_total functions.\n" if ($vflag); +print STDERR "[", &'date, "] ", "(4) making function index ...\n" if ($'vflag); +$func_total = &makefuncindex($dist, "$dist/funcs.html", $func_total); +print STDERR "Total $func_total functions.\n" if ($'vflag); # # (5) make file index (files.html and files/*) # PRODUCE @files %includes # -print STDERR "[", &date, "] ", "(5) making file index ...\n" if ($vflag); -$file_total = &makefileindex("$html/files.html", "$html/$INCS"); -print STDERR "Total $file_total files.\n" if ($vflag); +print STDERR "[", &'date, "] ", "(5) making file index ...\n" if ($'vflag); +$file_total = &makefileindex($dist, "$dist/files.html", "$dist/$INCS"); +print STDERR "Total $file_total files.\n" if ($'vflag); # # [#] make a common part for mains.html and index.html # USING @funcs @files # -print STDERR "[", &date, "] ", "(#) making a common part ...\n" if ($vflag); +print STDERR "[", &'date, "] ", "(#) making a common part ...\n" if ($'vflag); $index = &makecommonpart($title); # # (6)make index file (index.html) # -print STDERR "[", &date, "] ", "(6) making index file ...\n" if ($vflag); -&makeindex("$html/index.html", $title, $index); +print STDERR "[", &'date, "] ", "(6) making index file ...\n" if ($'vflag); +&makeindex("$dist/index.html", $title, $index); # # (7) make main index (mains.html) # -print STDERR "[", &date, "] ", "(7) making main index ...\n" if ($vflag); -&makemainindex("$html/mains.html", $index); +print STDERR "[", &'date, "] ", "(7) making main index ...\n" if ($'vflag); +&makemainindex("$dist/mains.html", $index); +&makenullhtml("$dist/null.html") if ($'hflag); # # (#) make anchor database # -print STDERR "[", &date, "] ", "(#) making temporary database ...\n" if ($vflag); +print STDERR "[", &'date, "] ", "(#) making temporary database ...\n" if ($'vflag); &anchor'create(); # # (8) make HTML files ($SRCS/*) # USING TAG CACHE, %includes and anchor database. # -print STDERR "[", &date, "] ", "(8) making hypertext from source code ...\n" if ($vflag); -&makehtml($file_total); -&clean(); -print STDERR "[", &date, "] ", "Done.\n" if ($vflag); +print STDERR "[", &'date, "] ", "(8) making hypertext from source code ...\n" if ($'vflag); +&makehtml($dist, $file_total); +&'clean(); +print STDERR "[", &'date, "] ", "Done.\n" if ($'vflag); +if ($'cflag && $'vflag) { + print STDERR "\n"; + print STDERR "[Information]\n"; + print STDERR "\n"; + print STDERR " You need to setup http server so that '*.ghtml' are treated\n"; + print STDERR " as gzipped files. Please see 'HTML/.htaccess.skel'.\n"; + print STDERR " Good luck!\n"; + print STDERR "\n"; +} exit 0; #------------------------------------------------------------------------- # SUBROUTINES @@ -322,7 +479,7 @@ exit 0; sub makeprogram { local($file) = @_; - open(PROGRAM, ">$file") || &error("cannot make CGI program."); + open(PROGRAM, ">$file") || &'error("cannot make CGI program."); $program = <<'END_OF_SCRIPT'; #!/usr/bin/perl #------------------------------------------------------------------ @@ -332,6 +489,7 @@ sub makeprogram { # SO THAT THIS SCRIPT CAN BE EXECUTED AS A CGI COMMAND. THANK YOU. #------------------------------------------------------------------ $SRCS = 'S'; +$HTML = '@HTML@'; $SEP = ' '; # source file path must not include $SEP charactor $ESCSEP = &escape($SEP); sub escape { @@ -339,7 +497,7 @@ sub escape { '%' . sprintf("%x", ord($c)); } print "Content-type: text/html\n\n"; -print "\n"; +print "\n"; @pairs = split (/&/, $ENV{'QUERY_STRING'}); foreach $p (@pairs) { ($name, $value) = split(/=/, $p); @@ -349,7 +507,7 @@ foreach $p (@pairs) { } if ($form{'pattern'} eq '') { print "

Pattern not specified. [return]

\n"; - print "\n"; + print "\n"; exit 0; } $pattern = $form{'pattern'}; @@ -360,7 +518,7 @@ print "Following $words are matched to above pattern.
\n"; $pattern =~ s/'//g; # to shut security hole unless (open(PIPE, "/usr/bin/global -x$flag '$pattern' |")) { print "

Cannot execute global. [return]

\n"; - print "\n"; + print "\n"; exit 0; } $cnt = 0; @@ -370,14 +528,15 @@ while () { local($tag, $lno, $filename) = split; $filename =~ s/^\.\///; $filename =~ s/\//$ESCSEP/g; - s/($tag)/$1<\/A>/; + s/($tag)/$1<\/A>/; print; } +close(PIPE); print "\n"; if ($cnt == 0) { print "

Pattern not found. [return]

\n"; } -print "\n"; +print "\n"; exit 0; #------------------------------------------------------------------ # SORRY TO HAVE SURPRISED YOU! @@ -387,17 +546,62 @@ exit 0; #------------------------------------------------------------------ END_OF_SCRIPT + $program =~ s/\@HTML\@/$'HTML/g; print PROGRAM $program; close(PROGRAM); } # +# makeghtml: make unzip script +# +sub makeghtml { + local($file) = @_; + open(PROGRAM, ">$file") || &'error("cannot make unzip script."); + $program = <<'END_OF_SCRIPT'; +#!/bin/sh +echo "content-type: text/html" +echo +gzip -S @HTML@ -d -c "$PATH_TRANSLATED" +END_OF_SCRIPT + + $program =~ s/\@HTML\@/$'HTML/g; + print PROGRAM $program; + close(PROGRAM); +} +# +# makehtaccess: make .htaccess skelton file. +# +sub makehtaccess { + local($file) = @_; + open(SKELTON, ">$file") || &'error("cannot make .htaccess skelton file."); + $skelton = <<'END_OF_SCRIPT'; +# +# Skelton file for .htaccess -- This file was generated by htags(1). +# +# Htags have made gzipped hypertext because you specified -c option. +# You need to setup http server so that these hypertext can be treated +# as gzipped files. +# There are many way to do it, but one of the method is to put .htaccess +# file in 'HTML' directory. +# +# Please rewrite XXX to the true value in your web site and rename this +# file to '.htaccess' and http server read this. +# +AddHandler htags-gzipped-html ghtml +Action htags-gzipped-html /XXX/cgi-bin/ghtml.cgi +END_OF_SCRIPT + print SKELTON $skelton; + close(SKELTON); +} +# # makehelp: make help file # sub makehelp { local($file) = @_; - open(HELP, ">$file") || &error("cannot make help file."); - print HELP "\nHELP\n\n"; + open(HELP, ">$file") || &'error("cannot make help file."); + print HELP $'begin_html; + print HELP &'set_header(0, 'HELP'); + print HELP $'begin_body; print HELP "

Usage of Links

\n"; print HELP "
/* [<][>][^][v] [top][bottom][index][help] */
\n"; print HELP "
\n"; @@ -410,7 +614,8 @@ sub makehelp { print HELP "
[index]
Return to index page (mains.html).\n"; print HELP "
[help]
You are seeing now.\n"; print HELP "
\n"; - print HELP "\n\n"; + print HELP $'end_body; + print HELP $'end_html; close(HELP); } # @@ -425,28 +630,33 @@ sub makeline { $_[0] =~ s//>/g; local($tag, $lno, $filename) = split(/[ \t\n]+/, $_[0]);; - $filename =~ s/\//$ESCSEP/g; - $_[0] =~ s/^$tag/$tag<\/A>/; + $filename = &'path2url($filename); + $_[0] =~ s/^$tag/$tag<\/A>/; } sub makedupindex { + local($dist) = @_; local($count) = 0; foreach $db ('GRTAGS', 'GTAGS') { local($kind) = $db eq 'GTAGS' ? "definitions" : "references"; + local($option) = $db eq 'GTAGS' ? '' : 'r'; local($prev) = ''; local($first_line); local($writing) = 0; $count = 0; - open(LIST, "btreeop $dbpath/$db | sort +0 -1 +2 -3 +1n -2|") || &error("btreeop $dbpath/$db | sort +0 -1 +2 -3 +1n -2 failed."); + local($command) = "global -nx$option '.*' | sort +0 -1 +2 -3 +1n -2"; + open(LIST, "$command |") || &'error("cannot fork."); while () { chop; local($tag, $lno, $filename) = split; if ($prev ne $tag) { $count++; - print STDERR " [$count] adding $tag $kind.\n" if ($vflag); + print STDERR " [$count] adding $tag $kind.\n" if ($'vflag); if ($writing) { - print FILE "\n\n\n"; + print FILE "\n"; + print FILE $'end_body; + print FILE $'end_html; close(FILE); $writing = 0; } @@ -460,10 +670,16 @@ sub makedupindex { # duplicate entry if ($first_line) { &cache'put($db, $tag, ''); - local($type) = ($db eq 'GTAGS') ? $DEFS : $REFS; - open(FILE, ">$html/$type/$tag.html") || &error("cannot make file '$html/$type/$tag.html'."); + local($type) = ($db eq 'GTAGS') ? $'DEFS : $'REFS; + if ($'cflag) { + open(FILE, "| gzip -c >$dist/$type/$tag.$'HTML") || &'error("cannot make file '$dist/$type/$tag.$'HTML'."); + } else { + open(FILE, ">$dist/$type/$tag.$'HTML") || &'error("cannot make file '$dist/$type/$tag.$'HTML'."); + } $writing = 1; - print FILE "\n$tag\n\n"; + print FILE $'begin_html; + print FILE &'set_header(0, $tag); + print FILE $'begin_body; print FILE "
\n";
 					&makeline($first_line);
 					print FILE $first_line, "\n";
@@ -474,8 +690,11 @@ sub makedupindex {
 			}
 		}
 		close(LIST);
+		if ($?) { &'error("'$command' failed."); }
 		if ($writing) {
-			print FILE "
\n\n\n"; + print FILE "\n"; + print FILE $'end_body; + print FILE $'end_html; close(FILE); } if ($first_line) { @@ -487,174 +706,228 @@ sub makedupindex { # # makefuncindex: make function index (including alphabetic index) # +# i) dist distribution directory # i) file function index file # i) total functions total # gi) tag cache # go) @funcs # sub makefuncindex { - local($file, $total) = @_; + local($dist, $file, $total) = @_; local($count) = 0; + local($indexlink) = "../mains.$'HTML"; - open(FUNCTIONS, ">$file") || &error("cannot make function index '$file'."); - print FUNCTIONS "\nFUNCTION INDEX\n"; - print FUNCTIONS "$begin_script$defaultview$end_script\n\n"; + open(FUNCTIONS, ">$file") || &'error("cannot make function index '$file'."); + print FUNCTIONS $'begin_html; + print FUNCTIONS &'set_header(0, 'FUNCTION INDEX', $'default_view); + print FUNCTIONS $'begin_body; print FUNCTIONS "

FUNCTION INDEX

\n"; - print FUNCTIONS "
    \n" if (!$aflag); + print FUNCTIONS "
      \n" if (!$'aflag); local($old) = select(FUNCTIONS); - open(TAGS, "btreeop -L $dbpath/GTAGS |") || &error("btreeop -L $dbpath/GTAGS failed."); - local($alpha) = ''; + local($command) = "global -c"; + open(TAGS, "$command |") || &'error("cannot fork."); + local($alpha, $alpha_f); @funcs = (); # [A][B][C]... while () { $count++; chop; local($tag) = $_; - print STDERR " [$count/$total] adding $tag\n" if ($vflag); - if ($aflag && $alpha ne substr($tag, 0, 1)) { + print STDERR " [$count/$total] adding $tag\n" if ($'vflag); + if ($'aflag && ($alpha eq '' || $tag !~ /^$alpha/)) { if ($alpha) { print ALPHA "
    \n"; - print ALPHA "
    [index]\n"; - print ALPHA "$begin_script$rewrite_href_funcs$end_script"; - print ALPHA "\n\n"; + print ALPHA "[index]\n"; + print ALPHA "$'begin_script$'rewrite_href_funcs$'end_script"; + print ALPHA $'end_body; + print ALPHA $'end_html; close(ALPHA); } - $alpha = substr($tag, 0, 1); - push(@funcs, "[$alpha]\n"); - open(ALPHA, ">$html/funcs/$alpha.html") || &error("cannot make alphabetical function index."); - print ALPHA "\n$alpha\n"; - print ALPHA "$begin_script$defaultview$end_script"; - print ALPHA "\n\n

    [$alpha]

    \n"; - print ALPHA "[index]\n"; + # for multi-byte code + local($c0, $c1); + $c0 = substr($tag, 0, 1); + if (ord($c0) > 127) { + $c1 = substr($tag, 1, 1); + $alpha = $c0 . $c1; + $alpha_f = "" . ord($c0) . ord($c1); + } else { + $alpha = $alpha_f = $c0; + } + push(@funcs, "[$alpha]\n"); + if ($'cflag) { + open(ALPHA, "| gzip -c >$dist/funcs/$alpha_f.$'HTML") || &'error("cannot make alphabetical function index."); + } else { + open(ALPHA, ">$dist/funcs/$alpha_f.$'HTML") || &'error("cannot make alphabetical function index."); + } + print ALPHA $'begin_html; + print ALPHA &'set_header(0, $alpha, $'default_view); + print ALPHA $'begin_body; + print ALPHA "

    [$alpha]

    \n"; + print ALPHA "[index]\n"; print ALPHA "
      \n"; select(ALPHA); } local($line) = &cache'get('GTAGS', $tag); if (!$line) { - print "
    1. $tag\n"; + print "
    2. $tag\n"; } else { local($tag, $lno, $filename) = split(/[ \t]+/, $line); - $filename =~ s/^\.\///; - $filename =~ s/\//$ESCSEP/g; - print "
    3. $tag\n"; + $filename = &'path2url($filename); + print "
    4. $tag\n"; } } close(TAGS); + if ($?) { &'error("'$command' failed."); } select($old); - if ($aflag) { + if ($'aflag) { print ALPHA "
    \n"; - print ALPHA "[index]\n"; - print ALPHA "$begin_script$rewrite_href_funcs$end_script"; - print ALPHA "\n\n"; + print ALPHA "[index]\n"; + print ALPHA "$'begin_script$'rewrite_href_funcs$'end_script"; + print ALPHA $'end_body; + print ALPHA $'end_html; close(ALPHA); print FUNCTIONS @funcs; } - print FUNCTIONS "
\n" if (!$aflag); - print FUNCTIONS "\n\n"; + print FUNCTIONS "\n" if (!$'aflag); + print FUNCTIONS $'end_body; + print FUNCTIONS $'end_html; close(FUNCTIONS); $count; } # # makefileindex: make file index # -# i) file name -# i) $INC directory +# i) dist distribution directory +# i) file file name +# i) $incdir $INC directory # go) @files # go) %includes # sub makefileindex { - local($file, $incdir) = @_; + local($dist, $file, $incdir) = @_; local($count) = 0; - - open(FILES, ">$file") || &error("cannot make file '$file'."); - print FILES "\nFILES\n"; - print FILES "$begin_script$defaultview$end_script"; - print FILES "\n\n

FILE INDEX

\n"; + local($indexlink) = "../mains.$'HTML"; + local(@dirstack, @fdstack); + local($command) = "gtags --find | sort"; + open(FIND, "$command |") || &'error("cannot fork."); + open(FILES, ">$file") || &'error("cannot make file '$file'."); + print FILES $'begin_html; + print FILES &'set_header(0, 'FILE INDEX', $'default_view); + print FILES $'begin_body; + print FILES "

FILE INDEX

\n"; print FILES "
    \n"; - local($old) = select(FILES); - open(FIND, "$findcom | sort |") || &error("cannot exec find."); - local($lastdir) = ''; - @files = (); - while () { - next if /(y\.tab\.c|y\.tab\.h)$/; - next if /(\/SCCS\/|\/RCS\/)/; + local($org) = select(FILES); + local(@push, @pop, $file); + + while () { $count++; chop; s/^\.\///; - local($filename) = $_; - print STDERR " [$count] adding $filename\n" if ($vflag); - local($dir); - if (index($filename, '/') >= 0) { - @split = split('/'); - $dir = $split[0]; - } else { - $dir = ''; + print STDERR " [$count] adding $_\n" if ($'vflag); + @push = split('/'); + $file = pop(@push); + @pop = @dirstack; + while ($push[0] && $pop[0] && $push[0] eq $pop[0]) { + shift @push; + shift @pop; } - #if ($dir && $dir ne $lastdir) { - if ($dir ne $lastdir) { - if ($lastdir) { - print DIR "
\n"; - print DIR "[index]\n"; - print DIR "$begin_script$rewrite_href_files$end_script"; - print DIR "\n\n"; - close(DIR); + if (@push || @pop) { + while (@pop) { + pop(@dirstack); + local($parent) = (@dirstack) ? &path2url(join('/', @dirstack)) : $indexlink; + print "\n"; + print "[..]\n"; + print "$'begin_script$'rewrite_href_files$'end_script" if (@dirstack == 0); + print $'end_body; + print $'end_html; + $path = pop(@fdstack); + close($path); + select($fdstack[$#fdstack]) if (@fdstack); + pop(@pop); } - if ($dir) { - push(@files, "
  • $dir/\n"); - open(DIR, ">$html/files/$dir.html") || &error("cannot make directory index."); - print DIR "\n$dir/\n"; - print DIR "$begin_script$defaultview$end_script"; - print DIR "\n\n

    $dir/

    \n"; - print DIR "[index]\n"; - print DIR "
      \n"; + while (@push) { + local($parent) = (@dirstack) ? &path2url(join('/', @dirstack)) : $indexlink; + push(@dirstack, shift @push); + $path = join('/', @dirstack); + $cur = "$dist/files/" . &path2file($path); + local($li) = "
    1. $path/\n"; + if (@dirstack == 1) { + push(@files, $li); + } else { + print $li; + } + if ($'cflag) { + open($cur, "| gzip -c >'$cur'") || &'error("cannot make directory index."); + } else { + open($cur, ">$cur") || &'error("cannot make directory index."); + } + select($cur); + push(@fdstack, $cur); + print $'begin_html; + print &'set_header(0, "$path", $'default_view); + print $'begin_body; + print "

      $path/

      \n"; + print "[..]\n"; + print "
        \n"; } - $lastdir = $dir; } # collect include files. - if ($filename =~ /.*\.h$/) { - local($last) = $filename; - $last =~ s!.*/!!; - if (! defined $includes{$last}) { - $includes{$last} = $filename; + if (/.*\.h$/) { + if (! defined $includes{$file}) { + $includes{$file} = $_; } else { # duplicate entries - $includes{$last} = "$includes{$last}\n$filename"; + $includes{$file} = "$includes{$file}\n$_"; } } - local($path) = $filename; - $path =~ s/\//$ESCSEP/g; - if ($dir eq '') { - push(@files, "
      1. $filename\n"); + local($url) = &path2url($_); + local($li) = "
      2. $_\n"; + if (@dirstack == 0) { + push(@files, $li); } else { - print DIR "
      3. $filename\n"; + print $li; } } close(FIND); - select($old); - if ($lastdir) { - print DIR "
      \n"; - print DIR "[index]\n"; - print DIR "$begin_script$rewrite_href_files$end_script"; - print DIR "\n\n"; - close(DIR); + while (@dirstack) { + pop(@dirstack); + local($parent) = (@dirstack) ? &path2url(join('/', @dirstack)) : $indexlink; + print "
    \n"; + print "[..]\n"; + print "$'begin_script$'rewrite_href_files$'end_script" if (@dirstack == 0); + print $'end_body; + print $'end_html; + $path = pop(@fdstack); + close($path); + select($fdstack[$#fdstack]) if (@fdstack); } print FILES @files; print FILES "\n"; - print FILES "\n\n"; - close(FILES); + print FILES $'end_body; + print FILES $'end_html; + close(FILES); + select($org); foreach $last (keys %includes) { local(@incs) = split(/\n/, $includes{$last}); if (@incs > 1) { - open(INCLUDE, ">$incdir/$last.html") || &error("cannot open file '$incdir/$last.html'."); - print INCLUDE "\n$last\n\n
    \n";
    -			foreach $filename (@incs) {
    -				local($path) = $filename;
    -				$path =~ s/\//$ESCSEP/g;
    -				print INCLUDE "$filename\n";
    +			if ($'cflag) {
    +				open(INCLUDE, "| gzip -c >$incdir/$last.$'HTML") || &'error("cannot open file '$incdir/$last.$'HTML'.");
    +			} else {
    +				open(INCLUDE, ">$incdir/$last.$'HTML") || &'error("cannot open file '$incdir/$last.$'HTML'.");
     			}
    -			print INCLUDE "
    \n\n\n"; + print INCLUDE $'begin_html; + print INCLUDE &'set_header(0, $last); + print INCLUDE $'begin_body; + print INCLUDE "
    \n";
    +			foreach $filename (@incs) {
    +				local($path) = &'path2url($filename);
    +				print INCLUDE "$filename\n";
    +			}
    +			print INCLUDE "
    \n"; + print INCLUDE $'end_body; + print INCLUDE $'end_html; close(INCLUDE); # '' means that information already written to file. $includes{$last} = ''; @@ -672,18 +945,18 @@ sub makecommonpart { local($title) = @_; local($index) = ''; - $index .= "

    $title

    \n"; + $index .= "

    $'title_begin$'title$'title_end

    \n"; $index .= "

    "; - $index .= "Last updated " . &date . "
    \n"; - $index .= "This hypertext was generated by GLOBAL.
    \n"; - $index .= "$begin_script"; - $index .= "if (parent.frames.length && parent.$f_mains == self)\n"; - $index .= " document.write($langle+'A HREF=mains.html TARGET=_top'+$rangle+'[No frame version is here.]'+$langle+'/A'+$rangle)\n"; - $index .= "$end_script"; + $index .= "Last updated " . &'date . "
    \n"; + $index .= "This hypertext was generated by GLOBAL.
    \n"; + $index .= $'begin_script; + $index .= "if (parent.frames.length && parent.mains == self)\n"; + $index .= " document.write($'langle+'A HREF=mains.html TARGET=_top'+$'rangle+'[No frame version is here.]'+$'langle+'/A'+$'rangle)\n"; + $index .= $'end_script; $index .= "

    \n
    \n"; - if ($fflag) { + if ($'fflag) { $index .= "

    FUNCTION SEARCH

    \n"; - $index .= "Please input function name and select [Search]. Perl's regular expression is allowed.

    \n"; + $index .= "Please input function name and select [Search]. POSIX's regular expression is allowed.

    \n"; $index .= "

    \n"; $index .= "\n"; $index .= "\n"; @@ -694,18 +967,19 @@ sub makecommonpart { } $index .= "

    MAINS

    \n"; $index .= "
    \n";
    -	open(PIPE, "btreeop -K main $dbpath/GTAGS | sort +0 -1 +2 -3 +1n -2|") || &error("btreeop -K main $dbpath/GTAGS failed.");
    +	local($command) = "global -nx main | sort +0 -1 +2 -3 +1n -2";
    +	open(PIPE, "$command |") || &'error("cannot fork.");
     	while () {
     		local($nouse, $lno, $filename) = split;
     		$nouse = '';	# to make perl quiet
    -		$filename =~ s/^\.\///;
    -		$filename =~ s/\//$ESCSEP/g;
    -		s/(main)/$1<\/A>/;
    +		$filename = &'path2url($filename);
    +		s/(main)/$1<\/A>/;
     		$index .= $_;
     	}
     	close(PIPE);
    +	if ($?) { &'error("'$command' failed."); }
     	$index .= "
    \n
    \n

    FUNCTIONS

    \n"; - if ($aflag) { + if ($'aflag) { foreach $f (@funcs) { $index .= $f; } @@ -730,17 +1004,25 @@ sub makecommonpart { sub makeindex { local($file, $title, $index) = @_; - open(FRAME, ">$file") || &error("cannot open file '$file'."); - print FRAME "\n$title\n"; + open(FRAME, ">$file") || &'error("cannot open file '$file'."); + print FRAME $'begin_html; + print FRAME "$title\n"; print FRAME "\n"; - print FRAME "\n$index\n"; print FRAME "\n"; - print FRAME "\n"; - print FRAME "\n"; + print FRAME "\n"; + print FRAME "\n"; print FRAME "\n"; - print FRAME "\n"; + if ($'hflag) { + print FRAME "\n"; + print FRAME "\n"; + print FRAME "\n"; + print FRAME "\n"; + } else { + print FRAME "\n"; + } + print FRAME "\n$index\n"; print FRAME "\n"; - print FRAME "\n"; + print FRAME $'end_html; close(FRAME); } # @@ -752,34 +1034,48 @@ sub makeindex { sub makemainindex { local($file, $index) = @_; - open(INDEX, ">$file") || &error("cannot create file '$file'."); - print INDEX "\nMAINS\n"; - print INDEX "\n$index\n\n"; + open(INDEX, ">$file") || &'error("cannot create file '$file'."); + print INDEX $'begin_html; + print INDEX &'set_header(1, $title); + print INDEX $'begin_body; + print INDEX $index; + print INDEX $'end_body; + print INDEX $'end_html; close(INDEX); } # +# makenullhtml: make null html +# +# i) $file file name +# +sub makenullhtml { + local($file) = @_; + + open(NULL, ">$file") || &'error("cannot create file '$file'."); + print NULL "\n"; + close(NULL); +} +# # makehtml: make html files # # i) total number of files. # sub makehtml { - local($total) = @_; + local($dist, $total) = @_; local($count) = 0; - open(FIND, "$findcom |") || &error("cannot exec find."); + open(FIND, "$'findcom |") || &'error("cannot fork."); while () { - next if /y\.tab\.c|y\.tab\.h/; - next if /(\/SCCS\/|\/RCS\/)/; - - $count++; chop; + $count++; local($path) = $_; $path =~ s/^\.\///; - print STDERR " [$count/$total] converting $path\n" if ($vflag); - $path =~ s/\//$SEP/g; - &convert'src2html($_, "$html/$SRCS/$path.html"); + print STDERR " [$count/$total] converting $_\n" if ($'vflag); + $path = &'path2file($path); + &convert'src2html($_, "$dist/$'SRCS/$path"); } close(FIND); + if ($?) { &'error("cannot traverse directory."); } } #========================================================================= # CONVERT PACKAGE @@ -789,29 +1085,38 @@ package convert; # src2html: convert source code into HTML # # i) $file source file - Read from -# i) $html HTML file - Write to +# i) $hfile HTML file - Write to # gi) %includes # pairs of include file and the path # sub src2html { - local($file, $html) = @_; + local($file, $hfile) = @_; local($ncol) = $'ncol; - local($expand) = &'usable('expand') ? 'expand' : 'cat'; + local($tabs) = $'tabs; local(%ctab) = ('&', '&', '<', '<', '>', '>'); + local($expand) = &'usable('expand') ? 'expand' : 'gtags --expand'; + local($isjava) = ($file =~ /\.java$/) ? 1 : 0; + local($reserved_words) = ($isjava) ? $'java_reserved_words : $'c_reserved_words; - open(HTML, ">$html") || &'error("cannot create file '$html'."); + if ($'cflag) { + open(HTML, "| gzip -c >'$hfile'") || &'error("cannot create file '$hfile'."); + } else { + open(HTML, ">$hfile") || &'error("cannot create file '$hfile'."); + } local($old) = select(HTML); # # load tags belonging to this file. # &anchor'load($file); - open(C, "$expand '$file' |") || &'error("cannot open file '$file'."); + open(SRC, "$expand -$tabs '$file' |") || &'error("cannot fork."); # # print the header # $file =~ s/^\.\///; - print "\n$file\n"; - print "

    $file

    \n"; + print $'begin_html; + print &'set_header(1, $file); + print $'begin_body; + print "

    $file

    \n"; print &link_format(&anchor'getlinks(0)); print "\n
    \n"; print "

    FUNCTIONS

    \n"; @@ -829,24 +1134,23 @@ sub src2html { print "
    \n";
     	$INCOMMENT = 0;			# initial status is out of comment
     	local($LNO, $TAG, $TYPE) = &anchor'first();
    -	while () {
    +	while () {
     		local($converted);
     		s/\r$//;
     		# make link for include file
     		if (!$INCOMMENT && /^#include/) {
     			local($last, $sep) = m![])!;
    -			local($link);
     			if (defined $'includes{$last}) {
    +				local($link, $suffix);
     				if ($'includes{$last}) {
    -					$link = $'includes{$last};
    -					$link =~ s/\//$'ESCSEP/g;
    +					$link = &'path2url($'includes{$last});
     				} else {
    -					$link = "../$'INCS/$last";
    +					$link = "../$'INCS/$last.$'HTML";
     				}
     				if ($sep eq '"') {
    -					s!"(.*$last)"!"$1"!;
    +					s!"(.*$last)"!"$1"!;
     				} else {
    -					s!<(.*$last)>!<$1>!;
    +					s!<(.*$last)>!<$1>!;
     				}
     				$converted = 1;
     			}
    @@ -857,7 +1161,7 @@ sub src2html {
     		# painting source code
     		s/({|})/$'brace_begin$1$'brace_end/g;
     		local($sharp) = s/^(#\w+)// ? $1 : '';
    -		s/\b($'reserved_words)\b/$'reserved_begin$1$'reserved_end/go if ($sharp ne '#include');
    +		s/\b($reserved_words)\b/$'reserved_begin$1$'reserved_end/go if ($sharp ne '#include');
     		s/^/$'sharp_begin$sharp$'sharp_end/ if ($sharp);	# recover macro
     
     		local($define_line) = 0;
    @@ -882,19 +1186,28 @@ sub src2html {
     				if ($line) {
     					local($nouse, $lno, $filename) = split(/[ \t]+/, $line);
     					$nouse = '';	# to make perl quiet
    -					$filename =~ s/^\.\///;
    -					$filename =~ s/\//$'ESCSEP/g;
    -					$href = "$TAG";
    +					$filename = &'path2url($filename);
    +					$href = "$TAG";
     				} else {
     					local($dir) = ($TYPE eq 'D') ? $'REFS : $'DEFS;
    -					$href = "$TAG";
    +					$href = "$TAG";
     				}
     				# set tag marks and save hyperlink into @links
    -				if (s/\b$TAG\b/\005$count\005/ || s/\b_$TAG\b/_\005$count\005/) {
    -					$count++;
    -					push(@links, $href);
    +				if (ord($TAG) > 127) {	# for multi-byte code
    +					if (s/([\x00-\x7f])$TAG([ \t]*\()/$1\005$count\005$2/ || s/([\x00-\x7f])$TAG([\x00-\x7f])/$1\005$count\005$2/) {
    +						$count++;
    +						push(@links, $href);
    +					} else {
    +						print STDERR "Error: $file $LNO $TAG($TYPE) tag must exist.\n" if ($'wflag);
    +					}
     				} else {
    -					print STDERR "Error: $file $LNO $TAG($TYPE) tag must exist.\n" if ($'wflag);
    +					if (s/\b$TAG([ \t]*\()/\005$count\005$1/ || s/\b$TAG\b/\005$count\005/ || s/\b_$TAG\b/_\005$count\005/)
    +					{
    +						$count++;
    +						push(@links, $href);
    +					} else {
    +						print STDERR "Error: $file $LNO $TAG($TYPE) tag must exist.\n" if ($'wflag);
    +					}
     				}
     			} else {
     				print STDERR "Warning: $file $LNO $TAG($TYPE) found but not referred.\n" if ($'wflag);
    @@ -913,7 +1226,7 @@ sub src2html {
     		printf "%${ncol}d ", $. if ($'nflag);
     		print;
     		# print hyperlinks
    -		if ($define_line && $file !~ /\.h$/) {
    +		if ($define_line) {
     			print ' ' x ($ncol + 1) if ($'nflag);
     			print &link_format(&anchor'getlinks($define_line));
     			print "\n";
    @@ -924,8 +1237,10 @@ sub src2html {
     	print "\n";
     	print &link_format(&anchor'getlinks(-1));
     	print "\n";
    -	print "\n\n";
    -	close(C);
    +	print $'end_body;
    +	print $'end_html;
    +	close(SRC);
    +	if ($?) { &'error("cannot open file '$file'."); }
     	close(HTML);
     	select($old);
     
    @@ -939,6 +1254,7 @@ sub src2html {
     #	\002	quoted('') char
     #	\003	quoted string
     #	\004	comment
    +#	\005	line comment
     #	\032	temporary mark
     #
     sub protect_line {
    @@ -975,6 +1291,13 @@ sub protect_line {
     			last if ($INCOMMENT);
     		}
     	}
    +	$line_comment = '';
    +	if (s!(//.*)$!\005!) {
    +		$line_comment = $1;
    +		# ^     //   /*   $
    +		#       (1)  (2)	... (1) invalidate (2).
    +		$INCOMMENT = 0;
    +	}
     }
     #
     # unprotect_line: recover quoted strings
    @@ -984,8 +1307,12 @@ sub protect_line {
     sub unprotect_line {
     	local($s);
     
    +	if ($line_comment) {
    +		s/\005/$'comment_begin$line_comment$'comment_end/;
    +	}
     	while (@comments) {
     		$s = shift @comments;
    +		# nested tag can be occured but no problem.
     		s/\004/$'comment_begin$s$'comment_end/;
     	}
     	while (@quoted_strings) {
    @@ -1038,12 +1365,15 @@ sub create {
     	open(ANCH, ">$ANCH") || &'error("cannot create file '$ANCH'.");
     	close(ANCH);
     	chmod ($ANCH, 0600);
    -	open(ANCH, "| btreeop -C $ANCH") || &'error("btreeop -C $ANCH failed.");
    +	local($command) = "btreeop -C $ANCH";
    +	open(ANCH, "| $command") || &'error("cannot fork.");
     	local($fcount) = 1;
     	local($fnumber);
     	foreach $db ('GTAGS', 'GRTAGS') {
     		local($type) = ($db eq 'GTAGS') ? 'D' : 'R';
    -		open(PIPE, "btreeop $'dbpath/$db |") || &'error("btreeop $'dbpath/$db failed.");
    +		local($option) = ($db eq 'GTAGS') ? '' : 'r';
    +		local($command) = "global -nx$option '.*'";
    +		open(PIPE, "$command |") || &'error("cannot fork.");
     		while () {
     			local($tag, $lno, $filename) = split;
     			$fnumber = $PATHLIST{$filename};
    @@ -1053,8 +1383,10 @@ sub create {
     			print ANCH "$fnumber $lno $tag $type\n";
     		}
     		close(PIPE);
    +		if ($?) { &'error("'$command' failed."); }
     	}
     	close(ANCH);
    +	if ($?) { &'error("'$command' failed."); }
     }
     #
     # finish: remove anchors database
    @@ -1063,7 +1395,7 @@ sub finish {
     	unlink("$ANCH") if (defined($ANCH));
     }
     #
    -# load: load anchors in a file from database
    +# load: load anchors belonging to specified file.
     #
     #	i)	$file	source file
     #	gi)	%PATHLIST
    @@ -1081,15 +1413,15 @@ sub load {
     	if (!($fnumber = $PATHLIST{$file})) {
     		return;
     	}
    -	open(ANCH, "btreeop -K $fnumber $ANCH |") || &'error("btreeop -K $file $ANCH failed.");
    -$n = 0;
    +	local($command) = "btreeop -K $fnumber $ANCH";
    +	open(ANCH, "$command |") || &'error("cannot fork.");
     	while () {
     		local($fnumber, $lno, $tag, $type) = split;
     		local($line);
     		# don't refer to macros which is defined in other C source.
     		if ($type eq 'R' && ($line = &cache'get('GTAGS', $tag))) {
     			local($nouse1, $nouse2, $f, $def) = split(/[ \t]+/, $line);
    -			if ($f !~ /\.h$/ && $f !~ $file && $def =~ /^#/) {
    +			if ($f !~ /\.h$/ && $f ne $file && $def =~ /^#/) {
     				print STDERR "Information: $file $lno $tag($type) skipped, because this is a macro which is defined in other C source.\n" if ($'wflag);
     				next;
     			}
    @@ -1097,6 +1429,7 @@ $n = 0;
     		push(@ANCHORS, "$lno,$tag,$type");
     	}
     	close(ANCH);
    +	if ($?) {&'error("'$command' failed."); }
     	local(@keys);
     	foreach (@ANCHORS) {
     		push(@keys, (split(/,/))[0]);
    diff --git a/contrib/global/lib/Makefile b/contrib/global/lib/Makefile
    index 99d49efabddc..83d8be057d41 100644
    --- a/contrib/global/lib/Makefile
    +++ b/contrib/global/lib/Makefile
    @@ -1,8 +1,9 @@
    -LIB=		util
    -SRCS=		tag.o tab.o strop.o mgets.o lookup.o gtagsopen.o getdbpath.o \
    -		find.o dbname.o dbio.o test.o makepath.o locatestring.o
    -NOPROFILE=      yes
    -install:
    -	@echo -n
    +LIB=		gloutil
    +SRCS=		gtagsop.c tab.c strbuf.c mgets.c defined.c getdbpath.c \
    +		find.c dbop.c test.c makepath.c locatestring.c pathop.c \
    +		conf.c strmake.c usable.c token.c
    +NOPROFILE=		noprofile
    +INTERNALLIB=		true
    +INTERNALSTATICLIB=	true
     
     .include 
    diff --git a/contrib/global/lib/conf.c b/contrib/global/lib/conf.c
    new file mode 100644
    index 000000000000..887663d71e25
    --- /dev/null
    +++ b/contrib/global/lib/conf.c
    @@ -0,0 +1,308 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *      This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	conf.c					30-Jun-98
    + *
    + */
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "conf.h"
    +#include "die.h"
    +#include "gparam.h"
    +#include "locatestring.h"
    +#include "makepath.h"
    +#include "mgets.h"
    +#include "strbuf.h"
    +#include "strmake.h"
    +#include "test.h"
    +/*
    + * Access library for gtags.conf (.gtagsrc).
    + * File format is a subset of XXXcap (termcap, printcap) file.
    + */
    +#define	GTAGSCONF	"/etc/global.conf"
    +#define GTAGSRC		".globalrc"
    +#define DEFAULTLABEL	"default"
    +static FILE	*fp;
    +static char	*line;
    +static int	allowed_nest_level = 8;
    +static int	opened;
    +
    +static void	trim __P((char *));
    +static char	*readrecord __P((const char *));
    +static void	includelabel __P((STRBUF *, const char *, int));
    +
    +static void
    +trim(l)
    +char	*l;
    +{
    +	char	*f, *b;
    +	int	colon = 0;
    +
    +	for (f = b = l; *f; f++) {
    +		if (colon && isspace(*f))
    +			continue;
    +		colon = 0;
    +		if ((*b++ = *f) == ':')
    +			colon = 1;
    +	}
    +	*b = 0;
    +}
    +static char	*
    +readrecord(label)
    +const char *label;
    +{
    +	char	*p, *q;
    +
    +	rewind(fp);
    +	while ((p = mgets(fp, NULL, MGETS_CONT|MGETS_SKIPCOM)) != NULL) {
    +		trim(p);
    +		for (;;) {
    +			if ((q = strmake(p, "|:")) == NULL)
    +				die1("illegal configuration file format (%s).", p);
    +			if (!strcmp(label, q)) {
    +				if (!(p = locatestring(p, ":", MATCH_FIRST)))
    +					die("illegal configuration file format.");
    +				p = strdup(p);
    +				if (!p)
    +					die("short of memory.");
    +				return p;
    +			}
    +			p += strlen(q);
    +			if (*p == ':')
    +				break;
    +			else if (*p == '|')
    +				p++;
    +			else
    +				assert(0);
    +		}
    +	}
    +	return NULL;
    +}
    +static	void
    +includelabel(sb, label, level)
    +STRBUF	*sb;
    +const char *label;
    +int	level;
    +{
    +	char	*savep, *p, *q;
    +
    +	if (++level > allowed_nest_level)
    +		die("nested include= (or tc=) over flow.");
    +	if (!(savep = p = readrecord(label)))
    +		die1("label '%s' not found.", label);
    +	while ((q = locatestring(p, ":include=", MATCH_FIRST)) || (q = locatestring(p, ":tc=", MATCH_FIRST))) {
    +		char	inclabel[MAXPROPLEN+1], *c = inclabel;
    +
    +		strnputs(sb, p, q - p);
    +		q = locatestring(q, "=", MATCH_FIRST) + 1;
    +		while (*q && *q != ':')
    +			*c++ = *q++;
    +		*c = 0;
    +		includelabel(sb, inclabel, level);
    +		p = q;
    +	}
    +	strputs(sb, p);
    +	free(savep);
    +}
    +/*
    + * configpath: get path of configuration file.
    + */
    +char *
    +configpath() {
    +	static char config[MAXPATHLEN+1];
    +	char *p;
    +
    +	if ((p = getenv("GTAGSCONF")) != NULL) {
    +		if (!test("r", p))
    +			config[0] = 0;
    +		else
    +			strcpy(config, p);
    +	} else if ((p = getenv("HOME")) && test("r", makepath(p, GTAGSRC)))
    +		strcpy(config, makepath(p, GTAGSRC));
    +	else if (test("r", GTAGSCONF))
    +		strcpy(config, GTAGSCONF);
    +	else
    +		config[0] = 0;
    +	return config;
    +}
    +/*
    + * openconf: load configuration file.
    + *
    + *	go)	line	specified entry
    + */
    +void
    +openconf()
    +{
    +	const char *label, *config;
    +	STRBUF	*sb;
    +
    +	assert(opened == 0);
    +
    +	config = configpath();
    +	/*
    +	 * if configuration file is not found, default values are set
    +	 * for upper compatibility.
    +	 */
    +	if (*config == 0) {
    +		sb = stropen();
    +		strputs(sb, "suffixes=c,h,y,s,S,java:");
    +		strputs(sb, "skip=y.tab.c,y.tab.h,SCCS/,RCS/,CVS/:");
    +		strputs(sb, "format=standard:");
    +		strputs(sb, "extractmethod:");
    +		strputs(sb, "GTAGS=gctags %s:");
    +		strputs(sb, "GRTAGS=gctags -r %s:");
    +		strputs(sb, "GSYMS=gctags -s %s:");
    +		line = strdup(strvalue(sb));
    +		if (!line)
    +			die("short of memory.");
    +		strclose(sb);
    +		opened = 1;
    +		return;
    +	}
    +	if ((label = getenv("GTAGSLABEL")) == NULL)
    +		label = "default";
    +	if (!(fp = fopen(config, "r")))
    +		die1("cannot open '%s'.", config);
    +	sb = stropen();
    +	includelabel(sb, label, 0);
    +	line = strdup(strvalue(sb));
    +	strclose(sb);
    +	fclose(fp);
    +	opened = 1;
    +	return;
    +}
    +/*
    + * getconfn: get property number
    + *
    + *	i)	name	property name
    + *	o)	num	value (if not NULL)
    + *	r)		1: found, 0: not found
    + */
    +int
    +getconfn(name, num)
    +const char *name;
    +int	*num;
    +{
    +	char	*p;
    +	char	buf[MAXPROPLEN+1];
    +
    +	if (!opened)
    +		openconf();
    +	sprintf(buf, ":%s#", name);
    +	if ((p = locatestring(line, buf, MATCH_FIRST)) != NULL) {
    +		p += strlen(buf);
    +		if (num != NULL)
    +			*num = atoi(p);
    +		return 1;
    +	}
    +	return 0;
    +}
    +/*
    + * getconfs: get property string
    + *
    + *	i)	name	property name
    + *	o)	sb	string buffer (if not NULL)
    + *	r)		1: found, 0: not found
    + */
    +int
    +getconfs(name, sb)
    +const char *name;
    +STRBUF	*sb;
    +{
    +	char	*p;
    +	char	buf[MAXPROPLEN+1];
    +	int	all = 0;
    +	int	exist = 0;
    +
    +	if (!opened)
    +		openconf();
    +	if (!strcmp(name, "suffixes") || !strcmp(name, "skip") || !strcmp(name, "reserved_words"))
    +		all = 1;
    +	sprintf(buf, ":%s=", name);
    +	p = line;
    +	while ((p = locatestring(p, buf, MATCH_FIRST)) != NULL) {
    +		if (exist && sb)
    +			strputc(sb, ',');		
    +		exist = 1;
    +		for (p += strlen(buf); *p && *p != ':'; p++)
    +			if (sb)
    +				strputc(sb, *p);
    +		if (!all)
    +			break;
    +	}
    +	/*
    +	 * It may be that these code should be moved to applications.
    +	 * But nothing cannot start without them.
    +	 */
    +	if (!exist) {
    +		exist = 1;
    +		if (!strcmp(name, "suffixes")) {
    +			if (sb)
    +				strputs(sb, "c,h,y,s,S,java");
    +		} else if (!strcmp(name, "skip")) {
    +			if (sb)
    +				strputs(sb, "y.tab.c,y.tab.h,SCCS/,RCS/,CVS/");
    +		} else
    +			exist = 0;
    +	}
    +	return exist;
    +}
    +/*
    + * getconfb: get property bool value
    + *
    + *	i)	name	property name
    + *	r)		1: TRUE, 0: FALSE
    + */
    +int
    +getconfb(name)
    +const char *name;
    +{
    +	char	*p;
    +	char	buf[MAXPROPLEN+1];
    +
    +	if (!opened)
    +		openconf();
    +	sprintf(buf, ":%s:", name);
    +	if ((p = locatestring(line, buf, MATCH_FIRST)) != NULL)
    +		return 1;
    +	return 0;
    +}
    +void
    +closeconf()
    +{
    +	if (!opened)
    +		return;
    +	free(line);
    +	opened = 0;
    +}
    diff --git a/contrib/global/lib/conf.h b/contrib/global/lib/conf.h
    new file mode 100644
    index 000000000000..9317d9ff8726
    --- /dev/null
    +++ b/contrib/global/lib/conf.h
    @@ -0,0 +1,54 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *	This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	conf.h					16-Oct-97
    + *
    + */
    +
    +#ifndef _CONF_H_
    +#define _CONF_H_
    +
    +#include "strbuf.h"
    +#ifndef __P
    +#if defined(__STDC__)
    +#define __P(protos)     protos
    +#else
    +#define __P(protos)     ()
    +#endif
    +#endif
    +
    +char	*configpath __P((void));
    +void	openconf __P((void));
    +int	getconfn __P((const char *, int *));
    +int	getconfs __P((const char *, STRBUF *));
    +int	getconfb __P((const char *));
    +void	closeconf __P((void));
    +
    +#endif /* ! _CONF_H_ */
    diff --git a/contrib/global/lib/dbop.c b/contrib/global/lib/dbop.c
    new file mode 100644
    index 000000000000..9bd98f328624
    --- /dev/null
    +++ b/contrib/global/lib/dbop.c
    @@ -0,0 +1,332 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redilogibution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redilogibutions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redilogibutions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the dilogibution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *      This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	dbop.c					12-Nov-98
    + *
    + */
    +#include 
    +#include 
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "dbop.h"
    +#include "die.h"
    +#include "test.h"
    +
    +static DBT	key;				/* key of record	*/
    +static DBT	dat;				/* data of record	*/
    +/*
    + * dbop_open: open db database.
    + *
    + *	i)	dbname	database name
    + *	i)	mode	0: read only, 1: create, 2: modify
    + *	i)	perm	file permission
    + *	i)	flags
    + *			DBOP_DUP: allow duplicate records.
    + *			DBOP_REMOVE: remove on closed.
    + *	r)		descripter for dbop_xxx()
    + */
    +DBOP	*
    +dbop_open(dbname, mode, perm, flags)
    +const char *dbname;
    +int	mode;
    +int	perm;
    +int	flags;
    +{
    +	DB	*db;
    +	int     rw = 0;
    +	DBOP	*dbop;
    +	BTREEINFO info;
    +
    +	/*
    +	 * setup argments.
    +	 */
    +	switch (mode) {
    +	case 0:
    +		rw = O_RDONLY;
    +		break;
    +	case 1:
    +		rw = O_RDWR|O_CREAT|O_TRUNC;
    +		break;
    +	case 2:
    +		rw = O_RDWR;
    +		break;
    +	default:
    +		assert(0);
    +	}
    +	memset(&info, 0, sizeof(info));
    +	if (flags & DBOP_DUP)
    +		info.flags |= R_DUP;
    +	info.cachesize = 500000;
    +
    +	/*
    +	 * if unlink do job normally, those who already open tag file can use
    +	 * it until closing.
    +	 */
    +	if (mode == 1 && test("f", dbname))
    +		(void)unlink(dbname);
    +	db = dbopen(dbname, rw, 0600, DB_BTREE, &info);
    +	if (!db)
    +		return NULL;
    +	if (!(dbop = (DBOP *)malloc(sizeof(DBOP))))
    +		die("short of memory.");
    +	strcpy(dbop->dbname, dbname);
    +	dbop->db	= db;
    +	dbop->openflags	= flags;
    +	dbop->perm	= (mode == 1) ? perm : 0;
    +	dbop->lastkey	= NULL;
    +	dbop->lastdat	= NULL;
    +
    +	return dbop;
    +}
    +/*
    + * dbop_get: get data by a key.
    + *
    + *	i)	dbop	descripter
    + *	i)	name	name
    + *	r)		pointer to data
    + */
    +char	*
    +dbop_get(dbop, name)
    +DBOP	*dbop;
    +const char *name;
    +{
    +	DB	*db = dbop->db;
    +	int	status;
    +
    +	key.data = (char *)name;
    +	key.size = strlen(name)+1;
    +
    +	status = (*db->get)(db, &key, &dat, 0);
    +	dbop->lastkey	= (char *)key.data;
    +	dbop->lastdat	= (char *)dat.data;
    +	switch (status) {
    +	case RET_SUCCESS:
    +		break;
    +	case RET_ERROR:
    +		die("cannot read from database.");
    +	case RET_SPECIAL:
    +		return (NULL);
    +	}
    +	return((char *)dat.data);
    +}
    +/*
    + * dbop_put: put data by a key.
    + *
    + *	i)	dbop	descripter
    + *	i)	name	key
    + *	i)	data	data
    + */
    +void
    +dbop_put(dbop, name, data)
    +DBOP	*dbop;
    +const char *name;
    +const char *data;
    +{
    +	DB	*db = dbop->db;
    +	int	status;
    +
    +	if (strlen(name) > MAXKEYLEN)
    +		die("primary key too long.");
    +	key.data = (char *)name;
    +	key.size = strlen(name)+1;
    +	dat.data = (char *)data;
    +	dat.size = strlen(data)+1;
    +
    +	status = (*db->put)(db, &key, &dat, 0);
    +	switch (status) {
    +	case RET_SUCCESS:
    +		break;
    +	case RET_ERROR:
    +	case RET_SPECIAL:
    +		die("cannot write to database.");
    +	}
    +}
    +/*
    + * dbop_del: delete record by a key.
    + *
    + *	i)	dbop	descripter
    + *	i)	name	key
    + */
    +void
    +dbop_del(dbop, name)
    +DBOP	*dbop;
    +const char *name;
    +{
    +	DB	*db = dbop->db;
    +	int	status;
    +
    +	if (name) {
    +		key.data = (char *)name;
    +		key.size = strlen(name)+1;
    +		status = (*db->del)(db, &key, 0);
    +	} else
    +		status = (*db->del)(db, &key, R_CURSOR);
    +	if (status == RET_ERROR)
    +		die("cannot delete record.");
    +}
    +/*
    + * dbop_first: get first record. 
    + * 
    + *	i)	dbop	dbop descripter
    + *	i)	name	key
    + *			!=NULL: indexed read by key
    + *			==NULL: sequential read
    + *	i)	flags	following dbop_next call take over this.
    + *			DBOP_KEY	read key part
    + *			DBOP_PREFIX	prefix read
    + *					only valied when sequential read
    + *	r)		data
    + */
    +char	*
    +dbop_first(dbop, name, flags)
    +DBOP	*dbop;
    +const char *name;
    +int	flags;
    +{
    +	DB	*db = dbop->db;
    +	int	status;
    +
    +	if (flags & DBOP_PREFIX && !name)
    +		flags &= ~DBOP_PREFIX;
    +	if (name) {
    +		if (strlen(name) > MAXKEYLEN)
    +			die("primary key too long.");
    +		strcpy(dbop->key, name);
    +		key.data = (char *)name;
    +		key.size = strlen(name);
    +		/*
    +		 * includes NULL character unless prefix read.
    +		 */
    +		if (!(flags & DBOP_PREFIX))
    +			key.size++;
    +		dbop->keylen = key.size;
    +		status = (*db->seq)(db, &key, &dat, R_CURSOR);
    +	} else {
    +		dbop->keylen = dbop->key[0] = 0;
    +		/* skip META records */
    +		for (status = (*db->seq)(db, &key, &dat, R_FIRST);
    +			status == RET_SUCCESS;
    +			status = (*db->seq)(db, &key, &dat, R_NEXT)) {
    +			int c = (flags & DBOP_KEY) ? *((char *)key.data) : *((char *)dat.data);
    +			if (c != ' ')
    +				break;
    +		}
    +	}
    +	dbop->lastkey	= (char *)key.data;
    +	dbop->lastdat	= (char *)dat.data;
    +	switch (status) {
    +	case RET_SUCCESS:
    +		break;
    +	case RET_ERROR:
    +		die("dbop_first failed.");
    +	case RET_SPECIAL:
    +		return (NULL);
    +	}
    +	dbop->ioflags = flags;
    +	if (flags & DBOP_PREFIX) {
    +		if (strncmp((char *)key.data, dbop->key, dbop->keylen))
    +			return NULL;
    +	} else if (dbop->keylen) {
    +		if (strcmp((char *)key.data, dbop->key))
    +			return NULL;
    +	}
    +	if (flags & DBOP_KEY) {
    +		strcpy(dbop->prev, (char *)key.data);
    +		return (char *)key.data;
    +	}
    +	return ((char *)dat.data);
    +}
    +/*
    + * dbop_next: get next record. 
    + * 
    + *	i)	dbop	dbop descripter
    + *	r)		data
    + *
    + * Db_next always skip meta records.
    + */
    +char	*
    +dbop_next(dbop)
    +DBOP	*dbop;
    +{
    +	DB	*db = dbop->db;
    +	int	flags = dbop->ioflags;
    +	int	status;
    +
    +	while ((status = (*db->seq)(db, &key, &dat, R_NEXT)) == RET_SUCCESS) {
    +		assert(dat.data != NULL);
    +		if (flags & DBOP_KEY && *((char *)key.data) == ' ')
    +			continue;
    +		else if (*((char *)dat.data) == ' ')
    +			continue;
    +		if (flags & DBOP_KEY) {
    +			if (!strcmp(dbop->prev, (char *)key.data))
    +				continue;
    +			if (strlen((char *)key.data) > MAXKEYLEN)
    +				die("primary key too long.");
    +			strcpy(dbop->prev, (char *)key.data);
    +		}
    +		dbop->lastkey	= (char *)key.data;
    +		dbop->lastdat	= (char *)dat.data;
    +		if (flags & DBOP_PREFIX) {
    +			if (strncmp((char *)key.data, dbop->key, dbop->keylen))
    +				return NULL;
    +		} else if (dbop->keylen) {
    +			if (strcmp((char *)key.data, dbop->key))
    +				return NULL;
    +		}
    +		return (flags & DBOP_KEY) ? (char *)key.data : (char *)dat.data;
    +	}
    +	if (status == RET_ERROR)
    +		die("dbop_next failed.");
    +	return NULL;
    +}
    +/*
    + * dbop_close: close db
    + * 
    + *	i)	dbop	dbop descripter
    + */
    +void
    +dbop_close(dbop)
    +DBOP	*dbop;
    +{
    +	DB	*db = dbop->db;
    +
    +	(void)db->close(db);
    +	if (dbop->openflags & DBOP_REMOVE)
    +		(void)unlink(dbop->dbname);
    +	else if (dbop->perm && chmod(dbop->dbname, dbop->perm) < 0)
    +		die("cannot change file mode.");
    +	(void)free(dbop);
    +}
    diff --git a/contrib/global/lib/dbop.h b/contrib/global/lib/dbop.h
    new file mode 100644
    index 000000000000..38342ca52d04
    --- /dev/null
    +++ b/contrib/global/lib/dbop.h
    @@ -0,0 +1,88 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redilogibution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redilogibutions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redilogibutions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the dilogibution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *      This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	dbop.h					12-Nov-98
    + *
    + */
    +#ifndef _DBOP_H_
    +#define _DBOP_H_
    +
    +#include 
    +#include 
    +
    +#ifndef LITTLE_ENDIAN
    +#define LITTLE_ENDIAN   1234
    +#endif
    +#ifndef BIG_ENDIAN
    +#define BIG_ENDIAN      4321
    +#endif
    +
    +#define MAXKEYLEN	300
    +
    +typedef	struct {
    +	DB	*db;			/* descripter of DB */
    +	char	dbname[MAXPATHLEN+1];	/* dbname */
    +	char	key[MAXKEYLEN+1];	/* key */
    +	int	keylen;			/* key length */
    +	char	prev[MAXKEYLEN+1];	/* previous key value */
    +	char	*lastkey;		/* the key of last located record */
    +	char	*lastdat;		/* the data of last located record */
    +	int	openflags;		/* flags of dbop_open() */
    +	int	ioflags;		/* flags of dbop_first() */
    +	int	perm;			/* file permission */
    +} DBOP;
    +
    +/*
    + * openflags
    + */
    +#define	DBOP_DUP	1		/* allow duplicate records	*/
    +#define DBOP_REMOVE	2		/* remove file when closed	*/
    +/*
    + * ioflags
    + */
    +#define DBOP_KEY	1		/* read key part		*/
    +#define DBOP_PREFIX	2		/* prefixed read		*/
    +
    +#ifndef __P
    +#if defined(__STDC__)
    +#define __P(protos)     protos
    +#else
    +#define __P(protos)     ()
    +#endif
    +#endif
    +
    +DBOP	*dbop_open __P((const char *, int, int, int));
    +char	*dbop_get __P((DBOP *, const char *));
    +void	dbop_put __P((DBOP *, const char *, const char *));
    +void	dbop_del __P((DBOP *, const char *));
    +char	*dbop_first __P((DBOP *, const char *, int));
    +char	*dbop_next __P((DBOP *));
    +void	dbop_close __P((DBOP *));
    +#endif /* _DBOP_H_ */
    diff --git a/contrib/global/lib/defined.c b/contrib/global/lib/defined.c
    new file mode 100644
    index 000000000000..1e72b46c05dd
    --- /dev/null
    +++ b/contrib/global/lib/defined.c
    @@ -0,0 +1,66 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *      This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	defined.c				12-Nov-98
    + *
    + */
    +#include 
    +
    +#include "die.h"
    +#include "dbop.h"
    +#include "defined.h"
    +#include "makepath.h"
    +
    +static DBOP	*dbop = NULL;
    +
    +/*
    + * Tag command that supports referenced tag must call this function
    + * to decide whether or not the tag is defined.
    + */
    +int
    +defined(name)
    +const char *name;
    +{
    +	if (dbop == NULL) {
    +		const char *dbpath;
    +
    +		/*
    +		 * gtags(1) set GTAGSDBPATH to the path GTAGS exist.
    +		 */
    +		if (!(dbpath = getenv("GTAGSDBPATH")))
    +			dbpath = ".";
    +		dbop = dbop_open(makepath(dbpath, "GTAGS"), 0, 0, 0);
    +		if (dbop == NULL)
    +			die1("GTAGS not found. (%s)", makepath(dbpath, "GTAGS"));
    +	}
    +	if (dbop_get(dbop, name))
    +		return 1;
    +	return 0;
    +}
    diff --git a/contrib/global/lib/defined.h b/contrib/global/lib/defined.h
    new file mode 100644
    index 000000000000..6d342ac5ec06
    --- /dev/null
    +++ b/contrib/global/lib/defined.h
    @@ -0,0 +1,48 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *	This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	defined.h				2-May-98
    + *
    + */
    +
    +#ifndef _DEFINED_H_
    +#define _DEFINED_H_
    +
    +#ifndef __P
    +#if defined(__STDC__)
    +#define __P(protos)     protos
    +#else
    +#define __P(protos)     ()
    +#endif
    +#endif
    +
    +int	defined __P((const char *));
    +
    +#endif /* ! _DEFINED_H_ */
    diff --git a/contrib/global/lib/die.h b/contrib/global/lib/die.h
    index 46813d415953..fc0e9e014493 100644
    --- a/contrib/global/lib/die.h
    +++ b/contrib/global/lib/die.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -35,7 +35,7 @@
     #define _DIE_H_
     #include 
     
    -extern	char	*progname;
    +extern	const char *progname;
     
     #define	die(a)	fprintf(stderr, "%s: ", progname),\
     		fprintf(stderr, a),\
    @@ -46,4 +46,8 @@ extern	char	*progname;
     		fprintf(stderr, a, b),\
     		fputs("\n", stderr),\
     		exit(1)
    +#define	die2(a,b,c) fprintf(stderr, "%s: ", progname),\
    +		fprintf(stderr, a, b, c),\
    +		fputs("\n", stderr),\
    +		exit(1)
     #endif /* ! _DIE_H_ */
    diff --git a/contrib/global/lib/find.c b/contrib/global/lib/find.c
    index 6203e008a6f5..4682beec1d6d 100644
    --- a/contrib/global/lib/find.c
    +++ b/contrib/global/lib/find.c
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -28,114 +28,159 @@
      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      * SUCH DAMAGE.
      *
    - *	find.c					20-Oct-97
    + *	find.c					1-May-98
      *
      */
    -#include 
    -#include 
    -#include 
    +/*
    + * USEFIND	use find(1) to traverse directory tree.
    + *		Otherwise, use dirent(3) library.
    + */
    +#define USEFIND
    +
     #include 
    -#include "gparam.h"
    -#include "find.h"
    +
    +#include 
    +#include 
    +#ifndef USEFIND
    +#include 
    +#ifndef BSD4_4
    +#include 
    +#endif
    +#endif
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "conf.h"
     #include "die.h"
    +#include "find.h"
    +#include "gparam.h"
     #include "locatestring.h"
    +#include "makepath.h"
    +#include "strbuf.h"
     
     /*
      * usage of findxxx()
      *
    - *	findopen();
    + *	findopen(db);
      *	while (path = findread(&length)) {
      *		...
      *	}
      *	findclose();
      *
      */
    -static char	*skippath[] = {
    -	"y.tab.c",
    -	"y.tab.h",
    -	"SCCS/",
    -	"RCS/",
    -};
    -static char	*ext[] = {
    -	"c",
    -	"h",
    -	"y",
    -	"s",
    -	"S",
    -};
    -static char	findcom[MAXCOMLINE+1];
     static regex_t	skip_area;
    -static regex_t	*skip;
    -static FILE	*ip;
    +static regex_t	*skip = &skip_area;
     static int	opened;
     
    -int
    -issource(path)
    -char	*path;
    +static void	trim __P((char *));
    +
    +/*
    + * trim: remove blanks and '\'.
    + */
    +static void
    +trim(s)
    +char	*s;
     {
     	char	*p;
     
    -	if (!(p = locatestring(path, ".", 2)))
    -		return 0;
    -	++p;
    -	if (sizeof(ext) != 0) {
    -		int	i, lim = sizeof(ext)/sizeof(char *);
    -		for (i = 0; i < lim; i++)
    -			if (*ext[i] == *p && !strcmp(ext[i], p))
    -				return 1;
    +	for (p = s; *s; s++) {
    +		if (isspace(*s))
    +			continue;	
    +		if (*s == '\\' && *(s + 1))
    +			s++;
    +		*p++ = *s;
     	}
    -	return 0;
    +	*p = 0;
     }
    +#ifdef USEFIND
    +/*----------------------------------------------------------------------*/
    +/* find command version							*/
    +/*----------------------------------------------------------------------*/
    +static FILE	*ip;
     
     void
    -findopen(void)
    +findopen()
     {
    -	char	edit[512], *p, *q;
    -	int	i, lim;
    +	char	*findcom, *p, *q;
    +	STRBUF	*sb;
    +	char	*sufflist = NULL;
    +	char	*skiplist = NULL;
     
    -	if (opened)
    -		die("nested call to findopen.");
    +	assert(opened == 0);
     	opened = 1;
    -	p = findcom;
    -	strcpy(p, "find . \\( -type f -o -type l \\) \\(");
    -	p += strlen(p);
    -	lim = sizeof(ext)/sizeof(char *);
    -	for (i = 0; i < lim; i++) {
    -		sprintf(p, " -name '*.%s'%s", ext[i], (i + 1 < lim) ? " -o" : "");
    -		p += strlen(p);
    +
    +	sb = stropen();
    +	if (!getconfs("suffixes", sb))
    +		die("cannot get suffixes data.");
    +	sufflist = strdup(strvalue(sb));
    +	if (!sufflist)
    +		die("short of memory.");
    +	trim(sufflist);
    +	strstart(sb);
    +	if (getconfs("skip", sb)) {
    +		skiplist = strdup(strvalue(sb));
    +		if (!skiplist)
    +			die("short of memory.");
    +		trim(skiplist);
     	}
    -	sprintf(p, " \\) -print");
    -	if (sizeof(skippath) != 0) {
    -		int	i, lim = sizeof(skippath)/sizeof(char *);
    +
    +	strstart(sb);
    +	strputs(sb, "find . \\( -type f -o -type l \\) \\(");
    +	for (p = sufflist; p; ) {
    +		char	*suff = p;
    +		if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL)
    +			*p++ = 0;
    +		strputs(sb, " -name '*.");
    +		strputs(sb, suff);
    +		strputs(sb, "'");
    +		if (p)
    +			strputs(sb, " -o");
    +	}
    +	strputs(sb, " \\) -print");
    +	findcom = strvalue(sb);
    +
    +	if (skiplist) {
    +		char	*reg;
    +		STRBUF	*sbb = stropen();
     		/*
     		 * construct regular expression.
     		 */
    -		p = edit;
    -		*p++ = '(';
    -		for (i = 0; i < lim; i++) {
    -			*p++ = '/';
    -			for (q = skippath[i]; *q; q++) {
    +		strputc(sbb, '(');	/* ) */
    +		for (p = skiplist; p; ) {
    +			char    *skipf = p;
    +			if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL)
    +				*p++ = 0;
    +			strputc(sbb, '/');
    +			for (q = skipf; *q; q++) {
     				if (*q == '.')
    -					*p++ = '\\';
    -				*p++ = *q;
    +					strputc(sbb, '\\');
    +				strputc(sbb, *q);
     			}
     			if (*(q - 1) != '/')
    -				*p++ = '$';
    -			*p++ = '|';
    +				strputc(sbb, '$');
    +			if (p)
    +				strputc(sbb, '|');
     		}
    -		*(p - 1) = ')';
    -		*p = 0;
    +		strputc(sbb, ')');
    +		reg = strvalue(sbb);
     		/*
     		 * compile regular expression.
     		 */
    -		skip = &skip_area;
    -		if (regcomp(skip, edit, REG_EXTENDED|REG_NEWLINE) != 0)
    +		if (regcomp(skip, reg, REG_EXTENDED|REG_NEWLINE) != 0)
     			die("cannot compile regular expression.");
    +		strclose(sbb);
     	} else {
     		skip = (regex_t *)0;
     	}
     	if (!(ip = popen(findcom, "r")))
     		die("cannot execute find.");
    +	strclose(sb);
    +	if (sufflist)
    +		free(sufflist);
    +	if (skiplist)
    +		free(skiplist);
     }
     char	*
     findread(length)
    @@ -144,8 +189,12 @@ int	*length;
     	static char	path[MAXPATHLEN+1];
     	char	*p;
     
    +	assert(opened == 1);
     	while (fgets(path, MAXPATHLEN, ip)) {
     		if (!skip || regexec(skip, path, 0, 0, 0) != 0) {
    +			/*
    +			 * chop(path)
    +			 */
     			p = path + strlen(path) - 1;
     			if (*p != '\n')
     				die("output of find(1) is wrong (findread).");
    @@ -155,11 +204,242 @@ int	*length;
     			return path;
     		}
     	}
    -	return (char *)0;
    +	return NULL;
     }
     void
     findclose(void)
     {
    +	assert(opened == 1);
     	pclose(ip);
     	opened = 0;
     }
    +#else /* USEFIND */
    +/*----------------------------------------------------------------------*/
    +/* dirent version findxxx()						*/
    +/*----------------------------------------------------------------------*/
    +#define STACKSIZE 50
    +static  char    dir[MAXPATHLEN+1];		/* directory path */
    +static  struct {
    +	STRBUF  *sb;
    +	char    *dirp, *start, *end, *p;
    +} stack[STACKSIZE], *topp, *curp;		/* stack */
    +
    +static regex_t	suff_area;
    +static regex_t	*suff = &suff_area;
    +
    +static int
    +getdirs(dir, sb)
    +char    *dir;
    +STRBUF  *sb;
    +{
    +	DIR     *dirp;
    +	struct dirent *dp;
    +#ifndef BSD4_4
    +	struct stat st;
    +#endif
    +
    +	if ((dirp = opendir(dir)) == NULL)
    +		return -1;
    +	while ((dp = readdir(dirp)) != NULL) {
    +#ifdef BSD4_4
    +		if (dp->d_namlen == 1 && dp->d_name[0] == '.')
    +			continue;
    +		if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
    +			continue;
    +		if (dp->d_type == DT_DIR)
    +			strputc(sb, 'd');
    +		else if (dp->d_type == DT_REG)
    +			strputc(sb, 'f');
    +		else if (dp->d_type == DT_LNK)
    +			strputc(sb, 'l');
    +		else
    +			strputc(sb, ' ');
    +		strnputs(sb, dp->d_name, (int)dp->d_namlen);
    +#else
    +		if (stat(path, &st) < 0) {
    +			fprintf(stderr, "cannot stat '%s'. (Ignored)\n", path);
    +			continue;
    +		}
    +		if (S_ISDIR(st.st_mode))
    +			strputc(sb, 'd');
    +		else if (S_ISREG(st.st_mode))
    +			strputc(sb, 'f');
    +		else if (S_ISLNK(st.st_mode))
    +			strputc(sb, 'l');
    +		else
    +			strputc(sb, ' ');
    +		strputs(sb, dp->d_name);
    +#endif /* BSD4_4 */
    +		strputc(sb, '\0');
    +	}
    +	(void)closedir(dirp);
    +	return 0;
    +}
    +void
    +findopen()
    +{
    +	STRBUF	*sb = stropen();
    +	char	*sufflist = NULL;
    +	char	*skiplist = NULL;
    +
    +	assert(opened == 0);
    +	opened = 1;
    +
    +	/*
    +	 * setup stack.
    +	 */
    +	curp = &stack[0];
    +	topp = curp + STACKSIZE; 
    +	strcpy(dir, ".");
    +
    +	curp->dirp = dir + strlen(dir);
    +	curp->sb = stropen();
    +	if (getdirs(dir, curp->sb) < 0)
    +		die("cannot open '.' directory.");
    +	curp->start = curp->p = strvalue(curp->sb);
    +	curp->end   = curp->start + strbuflen(curp->sb);
    +
    +	/*
    +	 * preparing regular expression.
    +	 */
    +	strstart(sb);
    +	if (!getconfs("suffixes", sb))
    +		die("cannot get suffixes data.");
    +	sufflist = strdup(strvalue(sb));
    +	if (!sufflist)
    +		die("short of memory.");
    +	trim(sufflist);
    +	strstart(sb);
    +	if (getconfs("skip", sb)) {
    +		skiplist = strdup(strvalue(sb));
    +		if (!skiplist)
    +			die("short of memory.");
    +		trim(skiplist);
    +	}
    +	{
    +		char    *p;
    +
    +		strstart(sb);
    +		strputc(sb, '(');       /* ) */
    +		for (p = sufflist; p; ) {
    +			char    *suffp = p;
    +			if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL)
    +				*p++ = 0;
    +			strputs(sb, "\\.");
    +			strputs(sb, suffp);
    +			strputc(sb, '$');
    +			if (p)
    +				strputc(sb, '|');
    +		}
    +		strputc(sb, ')');
    +		/*
    +		 * compile regular expression.
    +		 */
    +		if (regcomp(suff, strvalue(sb), REG_EXTENDED) != 0)
    +			die("cannot compile regular expression.");
    +	}
    +	if (skiplist) {
    +		char    *p, *q;
    +		/*
    +		 * construct regular expression.
    +		 */
    +		strstart(sb);
    +		strputc(sb, '(');	/* ) */
    +		for (p = skiplist; p; ) {
    +			char    *skipf = p;
    +			if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL)
    +				*p++ = 0;
    +			strputc(sb, '/');
    +			for (q = skipf; *q; q++) {
    +				if (*q == '.')
    +					strputc(sb, '\\');
    +				strputc(sb, *q);
    +			}
    +			if (*(q - 1) != '/')
    +				strputc(sb, '$');
    +			if (p)
    +				strputc(sb, '|');
    +		}
    +		strputc(sb, ')');
    +		/*
    +		 * compile regular expression.
    +		 */
    +		if (regcomp(skip, strvalue(sb), REG_EXTENDED) != 0)
    +			die("cannot compile regular expression.");
    +	} else {
    +		skip = (regex_t *)0;
    +	}
    +	strclose(sb);
    +	if (sufflist)
    +		free(sufflist);
    +	if (skiplist)
    +		free(skiplist);
    +}
    +char    *
    +findread(length)
    +int	*length;
    +{
    +	static	char val[MAXPATHLEN+1];
    +
    +	for (;;) {
    +		while (curp->p < curp->end) {
    +			char	type = *(curp->p);
    +			char    *unit = curp->p + 1;
    +
    +			curp->p += strlen(curp->p) + 1;
    +			if (type == 'f' || type == 'l') {
    +				char	*path = makepath(dir, unit);
    +				if (regexec(suff, path, 0, 0, 0) != 0)
    +					continue;
    +				if (skip && regexec(skip, path, 0, 0, 0) == 0)
    +					continue;
    +				strcpy(val, path);
    +				return val;
    +			}
    +			if (type == 'd') {
    +				STRBUF  *sb = stropen();
    +				char    *dirp = curp->dirp;
    +
    +				strcat(dirp, "/");
    +				strcat(dirp, unit);
    +				if (getdirs(dir, sb) < 0) {
    +					fprintf(stderr, "cannot open directory '%s'. (Ignored)\n", dir);
    +					strclose(sb);
    +					*(curp->dirp) = 0;
    +					continue;
    +				}
    +				/*
    +				 * Push stack.
    +				 */
    +				if (++curp >= topp)
    +					die("directory stack over flow.");
    +				curp->dirp = dirp + strlen(dirp);
    +				curp->sb = sb;
    +				curp->start = curp->p = strvalue(sb);
    +				curp->end   = curp->start + strbuflen(sb);
    +			}
    +		}
    +		strclose(curp->sb);
    +		curp->sb = NULL;
    +		if (curp == &stack[0])
    +			break;
    +		/*
    +		 * Pop stack.
    +		 */
    +		curp--;
    +		*(curp->dirp) = 0;
    +	}
    +	return NULL;
    +}
    +void
    +findclose(void)
    +{
    +	assert(opened == 1);
    +	for (curp = &stack[0]; curp < topp; curp++)
    +		if (curp->sb != NULL)
    +			strclose(curp->sb);
    +		else
    +			break;
    +	opened = 0;
    +}
    +#endif /* !USEFIND */
    diff --git a/contrib/global/lib/find.h b/contrib/global/lib/find.h
    index bb140e05ddcb..ae16f7230872 100644
    --- a/contrib/global/lib/find.h
    +++ b/contrib/global/lib/find.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    diff --git a/contrib/global/lib/getdbpath.c b/contrib/global/lib/getdbpath.c
    index 1e4e7cfaefff..372d9ec3b2e8 100644
    --- a/contrib/global/lib/getdbpath.c
    +++ b/contrib/global/lib/getdbpath.c
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -40,12 +40,10 @@
     
     #include "die.h"
     #include "getdbpath.h"
    -#include "locatestring.h"
     #include "test.h"
     
    -static char	*makeobjdirprefix;	/* obj partition		*/
    -static char	*makeobjdir;		/* obj directory		*/
    -static int	bsd;			/* if BSD			*/
    +static const char *makeobjdirprefix;	/* obj partition		*/
    +static const char *makeobjdir;		/* obj directory		*/
     
     /*
      * gtagsexist: test whether GTAGS's existence.
    @@ -66,17 +64,15 @@ char	*dbpath;
     		strcpy(dbpath, candidate);
     		return 1;
     	}
    -	if (bsd) {
    -		sprintf(path, "%s/%s/GTAGS", candidate, makeobjdir);
    -		if (test("fr", path)) {
    -			sprintf(dbpath, "%s/%s", candidate, makeobjdir);
    -			return 1;
    -		}
    -		sprintf(path, "%s%s/GTAGS", makeobjdirprefix, candidate);
    -		if (test("fr", path)) {
    -			sprintf(dbpath, "%s%s", makeobjdirprefix, candidate);
    -			return 1;
    -		}
    +	sprintf(path, "%s/%s/GTAGS", candidate, makeobjdir);
    +	if (test("fr", path)) {
    +		sprintf(dbpath, "%s/%s", candidate, makeobjdir);
    +		return 1;
    +	}
    +	sprintf(path, "%s%s/GTAGS", makeobjdirprefix, candidate);
    +	if (test("fr", path)) {
    +		sprintf(dbpath, "%s%s", makeobjdirprefix, candidate);
    +		return 1;
     	}
     	return 0;
     }
    @@ -109,17 +105,14 @@ char	*dbpath;
     	if (!strcmp(cwd, "/"))
     		die("It's root directory! What are you doing?");
     
    -	if (getenv("OSTYPE") && locatestring(getenv("OSTYPE"), "BSD", 0)) {
    -		if ((p = getenv("MAKEOBJDIRPREFIX")) != NULL)
    -			makeobjdirprefix = p;
    -		else
    -			makeobjdirprefix = "/usr/obj";
    -		if ((p = getenv("MAKEOBJDIR")) != NULL)
    -			makeobjdir = p;
    -		else
    -			makeobjdir = "obj";
    -		bsd = 1;
    -	}
    +	if ((p = getenv("MAKEOBJDIRPREFIX")) != NULL)
    +		makeobjdirprefix = p;
    +	else
    +		makeobjdirprefix = "/usr/obj";
    +	if ((p = getenv("MAKEOBJDIR")) != NULL)
    +		makeobjdir = p;
    +	else
    +		makeobjdir = "obj";
     
     	if ((p = getenv("GTAGSROOT")) != NULL) {
     		if (*p != '/')
    diff --git a/contrib/global/lib/getdbpath.h b/contrib/global/lib/getdbpath.h
    index 193dfffc596a..063d2367055a 100644
    --- a/contrib/global/lib/getdbpath.h
    +++ b/contrib/global/lib/getdbpath.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    diff --git a/contrib/global/lib/global.h b/contrib/global/lib/global.h
    index 7fbc2b8ef230..5ab2ca563dc4 100644
    --- a/contrib/global/lib/global.h
    +++ b/contrib/global/lib/global.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -28,27 +28,30 @@
      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      * SUCH DAMAGE.
      *
    - *	global.h				16-Oct-97
    + *	global.h				2-May-98
      *
      */
     
     #ifndef _GLOBAL_H_
     #define _GLOBAL_H_
     
    -#include "gparam.h"
    -#include "dbname.h"
    -#include "makepath.h"
    -#include "dbio.h"
    -#include "locatestring.h"
    -#include "mgets.h"
    +#include "conf.h"
    +#include "dbop.h"
    +#include "defined.h"
     #include "die.h"
     #include "find.h"
     #include "getdbpath.h"
    -#include "strop.h"
    -#include "gtagsopen.h"
    -#include "lookup.h"
    +#include "gparam.h"
    +#include "gtagsop.h"
    +#include "locatestring.h"
    +#include "makepath.h"
    +#include "mgets.h"
    +#include "pathop.h"
    +#include "strbuf.h"
    +#include "strmake.h"
     #include "tab.h"
    -#include "tag.h"
     #include "test.h"
    +#include "token.h"
    +#include "usable.h"
     
     #endif /* ! _GLOBAL_H_ */
    diff --git a/contrib/global/lib/gparam.h b/contrib/global/lib/gparam.h
    index 8a506c465cae..8a13c7e64349 100644
    --- a/contrib/global/lib/gparam.h
    +++ b/contrib/global/lib/gparam.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -28,15 +28,17 @@
      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      * SUCH DAMAGE.
      *
    - *	gparam.h				16-Oct-97
    + *	gparam.h				16-Jul-98
      *
      */
     #ifndef _GPARAM_H_
     #define _GPARAM_H_
     
    -#define MAXCOMLINE	1024		/* max length of filter */
    -#define IDENTLEN	512		/* max length of ident	*/
    -#define MAXENVLEN	1024		/* max length of env	*/
    -#define MAXBUFLEN	1024		/* max length of buffer	*/
    +#define MAXFILLEN	1024		/* max length of filter		*/
    +#define IDENTLEN	512		/* max length of ident		*/
    +#define MAXENVLEN	1024		/* max length of env		*/
    +#define MAXBUFLEN	1024		/* max length of buffer		*/
    +#define MAXPROPLEN	1024		/* max length of property	*/
    +#define MAXARGLEN	512		/* max length of argment	*/
     
     #endif /* ! _GPARAM_H_ */
    diff --git a/contrib/global/lib/gtagsop.c b/contrib/global/lib/gtagsop.c
    new file mode 100644
    index 000000000000..41635695fef3
    --- /dev/null
    +++ b/contrib/global/lib/gtagsop.c
    @@ -0,0 +1,644 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *      This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	gtagsop.c				12-Nov-98
    + *
    + */
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "dbop.h"
    +#include "die.h"
    +#include "gtagsop.h"
    +#include "locatestring.h"
    +#include "makepath.h"
    +#include "mgets.h"
    +#include "pathop.h"
    +#include "strbuf.h"
    +#include "strmake.h"
    +#include "tab.h"
    +
    +static char	*genrecord __P((GTOP *));
    +static int	belongto __P((GTOP *, char *, char *));
    +
    +static int	support_version = 2;	/* acceptable format version   */
    +static const char *tagslist[] = {"GTAGS", "GRTAGS", "GSYMS"};
    +/*
    + * dbname: return db name
    + *
    + *	i)	db	0: GTAGS, 1: GRTAGS, 2: GSYMS
    + *	r)		dbname
    + */
    +const char *
    +dbname(db)
    +int	db;
    +{
    +	assert(db >= 0 && db < GTAGLIM);
    +	return tagslist[db];
    +}
    +/*
    + * makecommand: make command line to make global tag file
    + *
    + *	i)	comline	skelton command line
    + *	i)	path	path name
    + *	o)	sb	command line
    + */
    +void
    +makecommand(comline, path, sb)
    +char	*comline;
    +char	*path;
    +STRBUF	*sb;
    +{
    +	char	*p;
    +
    +	if (!(p = strmake(comline, "%")))
    +		die1("'%%s' is needed in tag command line. (%s)\n", comline);
    +	strputs(sb, p);
    +	strputs(sb, path);
    +	if (!(p = locatestring(comline, "%s", MATCH_FIRST)))
    +		die1("'%%s' is needed in tag command line. (%s)\n", comline);
    +	strputs(sb, p+2);
    +}
    +/*
    + * formatcheck: check format of tag command's output
    + *
    + *	i)	line	input
    + *	i)	flags	flag
    + *	r)	0:	normal
    + *		-1:	tag name
    + *		-2:	line number
    + *		-3:	path
    + *
    + * [example of right format]
    + *
    + * $1                $2 $3             $4
    + * ----------------------------------------------------
    + * main              83 ./ctags.c        main(argc, argv)
    + */
    +int
    +formatcheck(line, flags)
    +char	*line;
    +int	flags;
    +{
    +	char	*p, *q;
    +	/*
    +	 * $1 = tagname: allowed any char except sepalator.
    +	 */
    +	p = q = line;
    +	while (*p && !isspace(*p))
    +		p++;
    +	while (*p && isspace(*p))
    +		p++;
    +	if (p == q)
    +		return -1;
    +	/*
    +	 * $2 = line number: must be digit.
    +	 */
    +	q = p;
    +	while (*p && !isspace(*p))
    +		if (!isdigit(*p))
    +			return -2;
    +		else
    +			p++;
    +	if (p == q)
    +		return -2;
    +	while (*p && isspace(*p))
    +		p++;
    +	/*
    +	 * $3 = path:
    +	 *	standard format: must start with './'.
    +	 *	compact format: must be digit.
    +	 */
    +	if (flags & GTAGS_PATHINDEX) {
    +		while (*p && !isspace(*p))
    +			if (!isdigit(*p))
    +				return -3;
    +			else
    +				p++;
    +	} else {
    +		if (!(*p == '.' && *(p + 1) == '/' && *(p + 2)))
    +			return -3;
    +	}
    +	return 0;
    +}
    +/*
    + * gtagsopen: open global tag.
    + *
    + *	i)	dbpath	dbpath directory
    + *	i)	root	root directory (needed when compact format)
    + *	i)	db	GTAGS, GRTAGS, GSYMS
    + *	i)	mode	GTAGS_READ: read only
    + *			GTAGS_CREATE: create tag
    + *			GTAGS_MODIFY: modify tag
    + *	i)	flags	GTAGS_COMPACT
    + *			GTAGS_PATHINDEX
    + *	r)		GTOP structure
    + *
    + * when error occurred, gtagopen doesn't return.
    + * GTAGS_PATHINDEX needs GTAGS_COMPACT.
    + */
    +GTOP	*
    +gtagsopen(dbpath, root, db, mode, flags)
    +char	*dbpath;
    +char	*root;
    +int	db;
    +int	mode;
    +int	flags;
    +{
    +	GTOP	*gtop;
    +	int	dbmode = 0;
    +
    +	if ((gtop = (GTOP *)calloc(sizeof(GTOP), 1)) == NULL)
    +		die("short of memory.");
    +	gtop->db = db;
    +	gtop->mode = mode;
    +	switch (gtop->mode) {
    +	case GTAGS_READ:
    +		dbmode = 0;
    +		break;
    +	case GTAGS_CREATE:
    +		dbmode = 1;
    +		break;
    +	case GTAGS_MODIFY:
    +		dbmode = 2;
    +		break;
    +	default:
    +		assert(0);
    +	}
    +
    +	/*
    +	 * allow duplicate records.
    +	 */
    +	gtop->dbop = dbop_open(makepath(dbpath, dbname(db)), dbmode, 0644, DBOP_DUP);
    +	if (gtop->dbop == NULL) {
    +		if (dbmode == 1)
    +			die1("cannot make %s.", dbname(db));
    +		die1("%s not found.", dbname(db));
    +	}
    +	/*
    +	 * decide format version.
    +	 */
    +	gtop->format_version = 1;
    +	gtop->format = GTAGS_STANDARD;
    +	/*
    +	 * This is a special case. GSYMS had compact format even if
    +	 * format version 1.
    +	 */
    +	if (db == GSYMS)
    +		gtop->format |= GTAGS_COMPACT;
    +	if (gtop->mode == GTAGS_CREATE) {
    +		if (flags & GTAGS_COMPACT) {
    +			char	buf[80];
    +
    +			gtop->format_version = 2;
    +			sprintf(buf, "%s %d", VERSIONKEY, gtop->format_version);
    +			dbop_put(gtop->dbop, VERSIONKEY, buf);
    +			gtop->format |= GTAGS_COMPACT;
    +			dbop_put(gtop->dbop, COMPACTKEY, COMPACTKEY);
    +			if (flags & GTAGS_PATHINDEX) {
    +				gtop->format |= GTAGS_PATHINDEX;
    +				dbop_put(gtop->dbop, PATHINDEXKEY, PATHINDEXKEY);
    +			}
    +		}
    +	} else {
    +		/*
    +		 * recognize format version of GTAGS. 'format version record'
    +		 * is saved as a META record in GTAGS and GRTAGS.
    +		 * if 'format version record' is not found, it's assumed
    +		 * version 1.
    +		 */
    +		char	*p;
    +
    +		if ((p = dbop_get(gtop->dbop, VERSIONKEY)) != NULL) {
    +			for (p += strlen(VERSIONKEY); *p && isspace(*p); p++)
    +				;
    +			gtop->format_version = atoi(p);
    +		}
    +		if (gtop->format_version > support_version)
    +			die("GTAGS seems new format. Please install the latest GLOBAL.");
    +		if (gtop->format_version > 1) {
    +			if (dbop_get(gtop->dbop, COMPACTKEY) != NULL)
    +				gtop->format |= GTAGS_COMPACT;
    +			if (dbop_get(gtop->dbop, PATHINDEXKEY) != NULL)
    +				gtop->format |= GTAGS_PATHINDEX;
    +		}
    +	}
    +	if (gtop->format & GTAGS_PATHINDEX || gtop->mode != GTAGS_READ) {
    +		if (pathopen(dbpath, dbmode) < 0) {
    +			if (dbmode == 1)
    +				die("cannot create GPATH.");
    +			else
    +				die("GPATH not found.");
    +		}
    +	}
    +	/*
    +	 * Stuff for compact format.
    +	 */
    +	if (gtop->format & GTAGS_COMPACT) {
    +		assert(root != NULL);
    +		strcpy(gtop->root, root);
    +		if (gtop->mode != GTAGS_READ)
    +			gtop->sb = stropen();
    +	}
    +	return gtop;
    +}
    +/*
    + * gtagsput: put tag record with packing.
    + *
    + *	i)	gtop	descripter of GTOP
    + *	i)	tag	tag name
    + *	i)	record	ctags -x image
    + */
    +void
    +gtagsput(gtop, tag, record)
    +GTOP	*gtop;
    +char	*tag;
    +char	*record;
    +{
    +	char	*p, *q;
    +	char	lno[10];
    +	char	path[MAXPATHLEN+1];
    +
    +	if (gtop->format == GTAGS_STANDARD) {
    +		entab(record);
    +		dbop_put(gtop->dbop, tag, record);
    +		return;
    +	}
    +	/*
    +	 * gtop->format & GTAGS_COMPACT
    +	 */
    +	p = record;				/* ignore $1 */
    +	while (*p && !isspace(*p))
    +		p++;
    +	while (*p && isspace(*p))
    +		p++;
    +	q = lno;				/* lno = $2 */
    +	while (*p && !isspace(*p))
    +		*q++ = *p++;
    +	*q = 0;
    +	while (*p && isspace(*p))
    +		p++;
    +	q = path;				/* path = $3 */
    +	while (*p && !isspace(*p))
    +		*q++ = *p++;
    +	*q = 0;
    +	/*
    +	 * First time, it occurs, because 'prev_tag' and 'prev_path' are NULL.
    +	 */
    +	if (strcmp(gtop->prev_tag, tag) || strcmp(gtop->prev_path, path)) {
    +		if (gtop->prev_tag[0])
    +			dbop_put(gtop->dbop, gtop->prev_tag, strvalue(gtop->sb));
    +		strcpy(gtop->prev_tag, tag);
    +		strcpy(gtop->prev_path, path);
    +		/*
    +		 * Start creating new record.
    +		 */
    +		strstart(gtop->sb);
    +		strputs(gtop->sb, strmake(record, " \t"));
    +		strputc(gtop->sb, ' ');
    +		strputs(gtop->sb, path);
    +		strputc(gtop->sb, ' ');
    +		strputs(gtop->sb, lno);
    +	} else {
    +		strputc(gtop->sb, ',');
    +		strputs(gtop->sb, lno);
    +	}
    +}
    +/*
    + * gtagsadd: add tags belonging to the path into tag file.
    + *
    + *	i)	gtop	descripter of GTOP
    + *	i)	comline	tag command line
    + *	i)	path	source file
    + *	i)	flags	GTAGS_UNIQUE, GTAGS_EXTRACTMETHOD
    + */
    +void
    +gtagsadd(gtop, comline, path, flags)
    +GTOP	*gtop;
    +char	*comline;
    +char	*path;
    +int	flags;
    +{
    +	char	*tagline;
    +	FILE	*ip;
    +	STRBUF	*sb = stropen();
    +
    +	/*
    +	 * add path index if not yet.
    +	 */
    +	pathput(path);
    +	/*
    +	 * make command line.
    +	 */
    +	makecommand(comline, path, sb);
    +	/*
    +	 * Compact format.
    +	 */
    +	if (gtop->format & GTAGS_PATHINDEX) {
    +		char	*pno;
    +
    +		if ((pno = pathget(path)) == NULL)
    +			die1("GPATH is corrupted.('%s' not found)", path);
    +		strputs(sb, "| sed 's!");
    +		strputs(sb, path);
    +		strputs(sb, "!");
    +		strputs(sb, pno);
    +		strputs(sb, "!'");
    +	}
    +	if (gtop->format & GTAGS_COMPACT)
    +		strputs(sb, "| sort +0 -1 +1n -2");
    +	if (flags & GTAGS_UNIQUE)
    +		strputs(sb, "| uniq");
    +	if (!(ip = popen(strvalue(sb), "r")))
    +		die1("cannot execute '%s'.", strvalue(sb));
    +	while ((tagline = mgets(ip, NULL, MGETS_TAILCUT)) != NULL) {
    +		char	*tag, *p;
    +
    +		if (formatcheck(tagline, gtop->format) < 0)
    +			die1("illegal parser output.\n'%s'", tagline);
    +		tag = strmake(tagline, " \t");		 /* tag = $1 */
    +		/*
    +		 * extract method when class method definition.
    +		 *
    +		 * Ex: Class::method(...)
    +		 *
    +		 * key	= 'method'
    +		 * data = 'Class::method  103 ./class.cpp ...'
    +		 */
    +		if (flags & GTAGS_EXTRACTMETHOD) {
    +			if ((p = locatestring(tag, ".", MATCH_LAST)) != NULL)
    +				tag = p + 1;
    +			else if ((p = locatestring(tag, "::", MATCH_LAST)) != NULL)
    +				tag = p + 2;
    +		}
    +		gtagsput(gtop, tag, tagline);
    +	}
    +	pclose(ip);
    +	strclose(sb);
    +}
    +/*
    + * belongto: wheather or not record belongs to the path.
    + *
    + *	i)	gtop	GTOP structure
    + *	i)	path	path name (in standard format)
    + *			path number (in compact format)
    + *	i)	p	record
    + *	r)		1: belong, 0: not belong
    + */
    +static int
    +belongto(gtop, path, p)
    +GTOP	*gtop;
    +char	*path;
    +char	*p;
    +{
    +	char	*q;
    +	int	length = strlen(path);
    +
    +	/*
    +	 * seek to path part.
    +	 */
    +	if (gtop->format & GTAGS_PATHINDEX) {
    +		for (q = p; *q && !isspace(*q); q++)
    +			;
    +		if (*q == 0)
    +			die1("illegal tag format. '%s'", p);
    +		for (; *q && isspace(*q); q++)
    +			;
    +	} else
    +		q = locatestring(p, "./", MATCH_FIRST);
    +	if (*q == 0)
    +		die1("illegal tag format. '%s'", p);
    +	if (!strncmp(q, path, length) && isspace(*(q + length)))
    +		return 1;
    +	return 0;
    +}
    +/*
    + * gtagsdelete: delete records belong to path.
    + *
    + *	i)	gtop	GTOP structure
    + *	i)	path	path name
    + */
    +void
    +gtagsdelete(gtop, path)
    +GTOP	*gtop;
    +char	*path;
    +{
    +	char	*p, *key;
    +	int	length;
    +
    +	/*
    +	 * In compact format, a path is saved as a file number.
    +	 */
    +	key = path;
    +	if (gtop->format & GTAGS_PATHINDEX)
    +		if ((key = pathget(path)) == NULL)
    +			die1("GPATH is corrupted.('%s' not found)", path);
    +	length = strlen(key);
    +	/*
    +	 * read sequentially, because db(1) has just one index.
    +	 */
    +	for (p = dbop_first(gtop->dbop, NULL, 0); p; p = dbop_next(gtop->dbop))
    +		if (belongto(gtop, key, p))
    +			dbop_del(gtop->dbop, NULL);
    +	/*
    +	 * don't delete from path index.
    +	 */
    +}
    +/*
    + * gtagsfirst: return first record
    + *
    + *	i)	gtop	GTOP structure
    + *	i)	tag	tag name
    + *	i)	flags	GTOP_PREFIX	prefix read
    + *			GTOP_KEY	read key only
    + *	r)		record
    + */
    +char *
    +gtagsfirst(gtop, tag, flags)
    +GTOP	*gtop;
    +char	*tag;
    +int	flags;
    +{
    +	int	dbflags = 0;
    +	char	*line;
    +
    +	gtop->flags = flags;
    +	if (flags & GTOP_PREFIX && tag != NULL)
    +		dbflags |= DBOP_PREFIX;
    +	if (flags & GTOP_KEY)
    +		dbflags |= DBOP_KEY;
    +	if ((line = dbop_first(gtop->dbop, tag, dbflags)) == NULL)
    +		return NULL;
    +	if (gtop->format == GTAGS_STANDARD || gtop->flags & GTOP_KEY)
    +		return line;
    +	/*
    +	 * Compact format.
    +	 */
    +	gtop->line = line;			/* gtop->line = $0 */
    +	gtop->opened = 0;
    +	return genrecord(gtop);
    +}
    +/*
    + * gtagsnext: return followed record
    + *
    + *	i)	gtop	GTOP structure
    + *	r)		record
    + *			NULL end of tag
    + */
    +char *
    +gtagsnext(gtop)
    +GTOP	*gtop;
    +{
    +	char	*line;
    +
    +	/*
    +	 * If it is standard format or only key.
    +	 * Just return it.
    +	 */
    +	if (gtop->format == GTAGS_STANDARD || gtop->flags & GTOP_KEY)
    +		return dbop_next(gtop->dbop);
    +	/*
    +	 * gtop->format & GTAGS_COMPACT
    +	 */
    +	if ((line = genrecord(gtop)) != NULL)
    +		return line;
    +	/*
    +	 * read next record.
    +	 */
    +	if ((line = dbop_next(gtop->dbop)) == NULL)
    +		return line;
    +	gtop->line = line;			/* gtop->line = $0 */
    +	gtop->opened = 0;
    +	return genrecord(gtop);
    +}
    +/*
    + * gtagsclose: close tag file
    + *
    + *	i)	gtop	GTOP structure
    + */
    +void
    +gtagsclose(gtop)
    +GTOP	*gtop;
    +{
    +	if (gtop->format & GTAGS_PATHINDEX || gtop->mode != GTAGS_READ)
    +		pathclose();
    +	if (gtop->sb && gtop->prev_tag[0])
    +		dbop_put(gtop->dbop, gtop->prev_tag, strvalue(gtop->sb));
    +	if (gtop->sb)
    +		strclose(gtop->sb);
    +	dbop_close(gtop->dbop);
    +	free(gtop);
    +}
    +static char *
    +genrecord(gtop)
    +GTOP	*gtop;
    +{
    +	static char	output[MAXBUFLEN+1];
    +	char	path[MAXPATHLEN+1];
    +	static char	buf[1];
    +	char	*buffer = buf;
    +	char	*lnop;
    +	int	tagline;
    +
    +	if (!gtop->opened) {
    +		char	*p, *q;
    +
    +		gtop->opened = 1;
    +		p = gtop->line;
    +		q = gtop->tag;				/* gtop->tag = $1 */
    +		while (!isspace(*p))
    +			*q++ = *p++;
    +		*q = 0;
    +		for (; isspace(*p) ; p++)
    +			;
    +		if (gtop->format & GTAGS_PATHINDEX) {	/* gtop->path = $2 */
    +			char	*name;
    +
    +			q = path;
    +			while (!isspace(*p))
    +				*q++ = *p++;
    +			*q = 0;
    +			if ((name = pathget(path)) == NULL)
    +				die1("GPATH is corrupted.('%s' not found)", path);
    +			strcpy(gtop->path, name);
    +		} else {
    +			q = gtop->path;
    +			while (!isspace(*p))
    +				*q++ = *p++;
    +			*q = 0;
    +		}
    +		for (; isspace(*p) ; p++)
    +			;
    +		gtop->lnop = p;			/* gtop->lnop = $3 */
    +
    +		if (gtop->root)
    +			sprintf(path, "%s/%s", gtop->root, >op->path[2]);
    +		else
    +			sprintf(path, "%s", >op->path[2]);
    +		if ((gtop->fp = fopen(path, "r")) != NULL) {
    +			buffer = mgets(gtop->fp, NULL, MGETS_TAILCUT);
    +			gtop->lno = 1;
    +		}
    +	}
    +
    +	lnop = gtop->lnop;
    +	if (*lnop >= '0' && *lnop <= '9') {
    +		/* get line number */
    +		for (tagline = 0; *lnop >= '0' && *lnop <= '9'; lnop++)
    +			tagline = tagline * 10 + *lnop - '0';
    +		if (*lnop == ',')
    +			lnop++;
    +		gtop->lnop = lnop;
    +		if (gtop->fp) {
    +			if (gtop->lno == tagline)
    +				return output;
    +			while (gtop->lno < tagline) {
    +				if (!(buffer = mgets(gtop->fp, NULL, MGETS_TAILCUT)))
    +					die1("unexpected end of file. '%s'", path);
    +				gtop->lno++;
    +			}
    +		}
    +		if (strlen(gtop->tag) >= 16 && tagline >= 1000)
    +			sprintf(output, "%-16s %4d %-16s %s",
    +					gtop->tag, tagline, gtop->path, buffer);
    +		else
    +			sprintf(output, "%-16s%4d %-16s %s",
    +					gtop->tag, tagline, gtop->path, buffer);
    +		return output;
    +	}
    +	if (gtop->opened && gtop->fp != NULL) {
    +		gtop->opened = 0;
    +		fclose(gtop->fp);
    +	}
    +	return NULL;
    +}
    diff --git a/contrib/global/lib/gtagsop.h b/contrib/global/lib/gtagsop.h
    new file mode 100644
    index 000000000000..c6e75d72a63e
    --- /dev/null
    +++ b/contrib/global/lib/gtagsop.h
    @@ -0,0 +1,109 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *	This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	gtagsop.h				23-Dec-97
    + *
    + */
    +
    +#ifndef _GTOP_H_
    +#define _GTOP_H_
    +#include 
    +#include "dbop.h"
    +#include "gparam.h"
    +#include "strbuf.h"
    +
    +#define VERSIONKEY	" __.VERSION"
    +#define COMPACTKEY	" __.COMPACT"
    +#define PATHINDEXKEY	" __.PATHINDEX"
    +
    +#define GTAGS		0
    +#define GRTAGS		1
    +#define GSYMS		2
    +#define GTAGLIM		3
    +
    +#define	GTAGS_READ	0
    +#define GTAGS_CREATE	1
    +#define GTAGS_MODIFY	2
    +
    +/* gtagsopen() */
    +#define GTAGS_STANDARD		0	/* standard format */
    +#define GTAGS_COMPACT		1	/* compact format */
    +#define GTAGS_PATHINDEX		2	/* use path index */
    +/* gtagsadd() */
    +#define GTAGS_UNIQUE		1	/* compress duplicate lines */
    +#define GTAGS_EXTRACTMETHOD	2	/* extract method from class definition */
    +/* gtagsfirst() */
    +#define GTOP_KEY		1	/* read key part */
    +#define GTOP_PREFIX		2	/* prefixed read */
    +
    +typedef struct {
    +	DBOP	*dbop;			/* descripter of DBOP */
    +	int	format_version;		/* format version */
    +	int	format;			/* GTAGS_STANDARD, GTAGS_COMPACT */
    +	int	mode;			/* mode */
    +	int	db;			/* 0:GTAGS, 1:GRTAGS, 2:GSYMS */
    +	int	flags;			/* flags */
    +	char	root[MAXPATHLEN+1];	/* root directory of source tree */
    +	/*
    +	 * Stuff for compact format
    +	 */
    +	int	opened;			/* wether or not file opened */
    +	char	*line;			/* current record */
    +	char	tag[IDENTLEN+1];	/* current tag */
    +	char	prev_tag[IDENTLEN+1];	/* previous tag */
    +	char	path[MAXPATHLEN+1];	/* current path */
    +	char	prev_path[MAXPATHLEN+1];/* previous path */
    +	STRBUF	*sb;			/* string buffer */
    +	FILE	*fp;			/* descriptor of 'path' */
    +	char	*lnop;			/* current line number */
    +	int	lno;			/* integer value of 'lnop' */
    +} GTOP;
    +
    +#ifndef __P
    +#if defined(__STDC__)
    +#define __P(protos)     protos
    +#else
    +#define __P(protos)     ()
    +#endif
    +#endif
    +
    +const char *dbname __P((int));
    +void	makecommand __P((char *, char *, STRBUF *));
    +int	formatcheck __P((char *, int));
    +GTOP	*gtagsopen __P((char *, char *, int, int, int));
    +void	gtagsput __P((GTOP *, char *, char *));
    +char	*gtagsget __P((GTOP *, char *));
    +void    gtagsadd __P((GTOP *, char *, char *, int));
    +void	gtagsdelete __P((GTOP *, char *));
    +char	*gtagsfirst __P((GTOP *, char *, int));
    +char	*gtagsnext __P((GTOP *));
    +void	gtagsclose __P((GTOP *));
    +
    +#endif /* ! _GTOP_H_ */
    diff --git a/contrib/global/lib/locatestring.c b/contrib/global/lib/locatestring.c
    index 230ccce5149a..76285994befb 100644
    --- a/contrib/global/lib/locatestring.c
    +++ b/contrib/global/lib/locatestring.c
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -28,7 +28,7 @@
      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      * SUCH DAMAGE.
      *
    - *	locatestring.c				20-Oct-97
    + *	locatestring.c				25-Jul-98
      *
      */
     #include 
    @@ -40,35 +40,36 @@
      *
      *	i)	string	string
      *	i)	pattern	pattern
    - *	i)	flag	0: match first
    - *			1: match only at first column
    - *			2: match last
    - *			3: match only at last column
    + *	i)	flag	MATCH_FIRST:	match first
    + *			MATCH_AT_FIRST: match only at first column
    + *			MATCH_LAST:	match last
    + *			MATCH_AT_LAST:	match only at last column
      *	r)		pointer or NULL
      *
      * This function is made to avoid compatibility problems.
      */
     char	*
     locatestring(string, pattern, flag)
    -char	*string;
    -char	*pattern;
    +const char *string;
    +const char *pattern;
     int	flag;
     {
     	int	c = *pattern;
    -	char	*p = (char *)0;
    +	int	slen, plen;
    +	const char *p = NULL;
     
    -	if (flag == 3 && strlen(string) > strlen(pattern)) {
    -		string += strlen(string) - strlen(pattern);
    -	}
    +	plen = strlen(pattern);
    +	if (flag == MATCH_AT_LAST && (slen = strlen(string)) > plen)
    +		string += (slen - plen);
     	for (; *string; string++) {
     		if (*string == c)
    -			if (!strncmp(string, pattern, strlen(pattern))) {
    +			if (!strncmp(string, pattern, plen)) {
     				p = string;
    -				if (flag == 0)
    +				if (flag == MATCH_FIRST)
     					break;
     			}
    -		if (flag == 1 || flag == 3)
    +		if (flag == MATCH_AT_FIRST || flag == MATCH_AT_LAST)
     			break;
     	}
    -	return p;
    +	return (char *)p;
     }
    diff --git a/contrib/global/lib/locatestring.h b/contrib/global/lib/locatestring.h
    index cdaeedb1e5b0..2b881c6f447e 100644
    --- a/contrib/global/lib/locatestring.h
    +++ b/contrib/global/lib/locatestring.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -28,13 +28,18 @@
      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      * SUCH DAMAGE.
      *
    - *	locatestring.h				16-Oct-97
    + *	locatestring.h				25-Jul-98
      *
      */
     
     #ifndef _LOCATESTRING_H_
     #define _LOCATESTRING_H_
     
    +#define MATCH_FIRST	0
    +#define MATCH_AT_FIRST	1
    +#define MATCH_LAST	2
    +#define MATCH_AT_LAST	3
    +
     #ifndef __P
     #if defined(__STDC__)
     #define __P(protos)     protos
    @@ -43,6 +48,6 @@
     #endif
     #endif
     
    -char	*locatestring __P((char *, char *, int));
    +char	*locatestring __P((const char *, const char *, int));
     
     #endif /* ! _LOCATESTRING_H_ */
    diff --git a/contrib/global/lib/makepath.c b/contrib/global/lib/makepath.c
    index ba00ecfc6c2f..cf9858e95aab 100644
    --- a/contrib/global/lib/makepath.c
    +++ b/contrib/global/lib/makepath.c
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -28,11 +28,15 @@
      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      * SUCH DAMAGE.
      *
    - *	makepath.c				20-Oct-97
    + *	makepath.c				15-May-98
      *
      */
     #include 
    +#include "die.h"
     #include "makepath.h"
    +#include "strbuf.h"
    +
    +static STRBUF	*sb;
     /*
      * makepath: make path from directory and file.
      *
    @@ -42,16 +46,21 @@
      */
     char	*
     makepath(dir, file)
    -char	*dir;
    -char	*file;
    +const char *dir;
    +const char *file;
     {
    -	static char	path[MAXPATHLEN+1];
    -	char	*p;
    +	int	length;
     
    -	strcpy(path, dir);
    -	p = path + strlen(path);
    -	if (*(p - 1) != '/')
    -		*p++ = '/';
    -	strcpy(p, file);
    -	return path;
    +	if (sb == NULL)
    +		sb = stropen();
    +	strstart(sb);
    +	if ((length = strlen(dir)) > MAXPATHLEN)
    +		die1("path name too long. '%s'\n", dir);
    +	strputs(sb, dir);
    +	strunputc(sb, '/');
    +	strputc(sb, '/');
    +	strputs(sb, file);
    +	if ((length = strlen(strvalue(sb))) > MAXPATHLEN)
    +		die1("path name too long. '%s'\n", dir);
    +	return strvalue(sb);
     }
    diff --git a/contrib/global/lib/makepath.h b/contrib/global/lib/makepath.h
    index 47d292d482dc..74b1c16f7620 100644
    --- a/contrib/global/lib/makepath.h
    +++ b/contrib/global/lib/makepath.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -43,6 +43,6 @@
     #endif
     #endif
     
    -char	*makepath __P((char *, char *));
    +char	*makepath __P((const char *, const char *));
     
     #endif /* ! _MAKEPATH_H_ */
    diff --git a/contrib/global/lib/mgets.c b/contrib/global/lib/mgets.c
    index 2bc6099517c2..7f0cc7221c0e 100644
    --- a/contrib/global/lib/mgets.c
    +++ b/contrib/global/lib/mgets.c
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -28,16 +28,19 @@
      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      * SUCH DAMAGE.
      *
    - *	mgets.c					8-Nov-97
    + *	mgets.c					29-Aug-98
      *
      */
    +#include 
     #include 
     #include 
     
    -#include "mgets.h"
     #include "die.h"
    +#include "mgets.h"
    +
    +#define EXPANDSIZE 127
    +#define MINSIZE 16
     
    -#define EXPANDSIZE 512
     static int	mbufsize = EXPANDSIZE;
     static char	*mbuf;
     
    @@ -45,20 +48,21 @@ static char	*mbuf;
      * mgets: read whole record into allocated buffer
      *
      *	i)	ip	input stream
    + *	o)	length	record length
      *	i)	flags	flags
    - *			MGETS_CONT		\\ + \n -> \n
    + *			MGETS_CONT		\\ + \n -> ''
      *			MGETS_SKIPCOM		skip line which start with '#'.
    - *	o)	length	length of record
    + *			MGETS_TAILCUT		remove following blanks 
      *	r)		record buffer (NULL at end of file)
      *
      * Returned buffer has whole record.
      * The buffer end with '\0' and doesn't include '\r' and '\n'.
      */
     char	*
    -mgets(ip, flags, length)
    +mgets(ip, length, flags)
     FILE	*ip;
    -int	flags;
     int	*length;
    +int	flags;
     {
     	char	*p;
     
    @@ -72,27 +76,33 @@ int	*length;
     	 * read whole record.
     	 */
     	if (!fgets(mbuf, mbufsize, ip))
    -		return (char *)0;
    +		return NULL;
     	if (flags & MGETS_SKIPCOM)
     		while (*mbuf == '#')
     			if (!fgets(mbuf, mbufsize, ip))
    -				return (char *)0;
    +				return NULL;
     	p = mbuf + strlen(mbuf);
    +
     	for (;;) {
     		/*
     		 * get a line.
     		 */
     		while (*(p - 1) != '\n') {
     			/*
    -			 * expand and read additionally.
    +			 * expand buffer and read additionally.
     			 */
     			int count = p - mbuf;
    -			mbufsize += EXPANDSIZE;
    -			if (!(mbuf = (char *)realloc(mbuf, mbufsize + 1)))
    -				die("short of memory.");
    -			p = mbuf + count;
    -			if (!fgets(p, mbufsize - count, ip))
    -				die("illegal end of file.");
    +
    +			if (mbufsize - count < MINSIZE) {
    +				mbufsize += EXPANDSIZE;
    +				if (!(mbuf = (char *)realloc(mbuf, mbufsize + 1)))
    +					die("short of memory.");
    +				p = mbuf + count;
    +			}
    +			if (!fgets(p, mbufsize - count, ip)) {
    +				*p++ = '\n';
    +				break;
    +			}
     			p += strlen(p);
     		}
     		/*
    @@ -109,6 +119,17 @@ int	*length;
     		else
     			break;
     	}
    +/*
    +	if (flags & MGETS_SKIPCOM)
    +		for (p = mbuf; *p; p++)
    +			if (*p == '#') {
    +				*p = 0;
    +				break;
    +			}
    +*/
    +	if (flags & MGETS_TAILCUT)
    +		while (isspace(*(--p)))
    +			*p = 0;
     	if (length)
     		*length = p - mbuf;
     	return mbuf;
    diff --git a/contrib/global/lib/mgets.h b/contrib/global/lib/mgets.h
    index ea3aef2fa8d8..75b5e831268f 100644
    --- a/contrib/global/lib/mgets.h
    +++ b/contrib/global/lib/mgets.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redilogibution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -37,6 +37,7 @@
     #include 
     #define MGETS_CONT		1
     #define MGETS_SKIPCOM		2
    +#define MGETS_TAILCUT		4
     
     #ifndef __P
     #if defined(__STDC__)
    @@ -46,6 +47,6 @@
     #endif
     #endif
     
    -char	*mgets __P((FILE *, int, int *));
    +char	*mgets __P((FILE *, int *, int));
     
     #endif /* ! _MGETS_H_ */
    diff --git a/contrib/global/lib/pathop.c b/contrib/global/lib/pathop.c
    new file mode 100644
    index 000000000000..2eb9e6982675
    --- /dev/null
    +++ b/contrib/global/lib/pathop.c
    @@ -0,0 +1,155 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *      This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	pathop.c				12-Nov-98
    + *
    + */
    +#include 
    +#include 
    +#include 
    +
    +#include "die.h"
    +#include "dbop.h"
    +#include "makepath.h"
    +#include "pathop.h"
    +
    +static DBOP	*dbop;
    +static const char *gpath = "GPATH";
    +static int	_nextkey;
    +static int	_mode;
    +static int	opened;
    +static int	created;
    +
    +/*
    + * pathopen: open path dictionary tag.
    + *
    + *	i)	mode	0: read only
    + *			1: create
    + *			2: modify
    + *	r)		0: normal
    + *			-1: error
    + */
    +int
    +pathopen(dbpath, mode)
    +char	*dbpath;
    +int	mode;
    +{
    +	char	*p;
    +
    +	assert(opened == 0);
    +	/*
    +	 * We create GPATH just first time.
    +	 */
    +	_mode = mode;
    +	if (mode == 1 && created)
    +		mode = 0;
    +	dbop = dbop_open(makepath(dbpath, gpath), mode, 0644, 0);
    +	if (dbop == NULL)
    +		return -1;
    +	if (mode == 1)
    +		_nextkey = 0;
    +	else {
    +		if (!(p = dbop_get(dbop, NEXTKEY)))
    +			die("nextkey not found in GPATH.");
    +		_nextkey = atoi(p);
    +	}
    +	opened = 1;
    +	return 0;
    +}
    +void
    +pathput(path)
    +char	*path;
    +{
    +	char	buf[10];
    +
    +	assert(opened == 1);
    +	if (_mode == 1 && created)
    +		return;
    +	if (dbop_get(dbop, path) != NULL)
    +		return;
    +	sprintf(buf, "%d", _nextkey++);
    +	dbop_put(dbop, path, buf);
    +	dbop_put(dbop, buf, path);
    +}
    +char	*
    +pathget(key)
    +char	*key;
    +{
    +	assert(opened == 1);
    +	return dbop_get(dbop, key);
    +}
    +char	*
    +pathiget(n)
    +int	n;
    +{
    +	char	key[80];
    +	assert(opened == 1);
    +	sprintf(key, "%d", n);
    +	return dbop_get(dbop, key);
    +}
    +void
    +pathdel(key)
    +char	*key;
    +{
    +	char	*d;
    +
    +	assert(opened == 1);
    +	assert(_mode == 2);
    +	assert(key[0] == '.' && key[1] == '/');
    +	d = dbop_get(dbop, key);
    +	if (d == NULL)
    +		return;
    +	dbop_del(dbop, d);
    +	dbop_del(dbop, key);
    +}
    +int
    +nextkey(void)
    +{
    +	assert(_mode != 1);
    +	return _nextkey;
    +}
    +void
    +pathclose(void)
    +{
    +	char	buf[10];
    +
    +	assert(opened == 1);
    +	opened = 0;
    +	if (_mode == 1 && created) {
    +		dbop_close(dbop);
    +		return;
    +	}
    +	sprintf(buf, "%d", _nextkey);
    +	if (_mode == 1 || _mode == 2)
    +		dbop_put(dbop, NEXTKEY, buf);
    +	dbop_close(dbop);
    +	if (_mode == 1)
    +		created = 1;
    +}
    diff --git a/contrib/global/lib/pathop.h b/contrib/global/lib/pathop.h
    new file mode 100644
    index 000000000000..5bfef5dbaf55
    --- /dev/null
    +++ b/contrib/global/lib/pathop.h
    @@ -0,0 +1,59 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *	This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	pathop.h					14-May-98
    + *
    + */
    +
    +#ifndef _PATHOP_H_
    +#define _PATHOP_H_
    +#include 
    +#include "dbop.h"
    +#include "gparam.h"
    +
    +#define NEXTKEY		" __.NEXTKEY"
    +
    +#ifndef __P
    +#if defined(__STDC__)
    +#define __P(protos)     protos
    +#else
    +#define __P(protos)     ()
    +#endif
    +#endif
    +
    +int	pathopen __P((char *, int));
    +char	*pathget __P((char *));
    +char	*pathiget __P((int));
    +void	pathput __P((char *));
    +void	pathdel __P((char *));
    +void	pathclose __P((void));
    +int	nextkey __P((void));
    +
    +#endif /* ! _PATHOP_H_ */
    diff --git a/contrib/global/lib/strbuf.c b/contrib/global/lib/strbuf.c
    new file mode 100644
    index 000000000000..3df14c9ee370
    --- /dev/null
    +++ b/contrib/global/lib/strbuf.c
    @@ -0,0 +1,137 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *      This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	strbuf.c					5-Jul-98
    + *
    + */
    +#include 
    +#include 
    +
    +#include "die.h"
    +#include "strbuf.h"
    +
    +/*
    + * usage: string buffer
    + *
    + *	sb = stropen();
    + *	for (s = string; *s; s++)
    + *		strputc(sb, *s);
    + *	s = strvalue(sb);
    + *	strstart(sb);
    + *	strputs(sb, "hello");
    + *	s = strvalue(sb);
    + *	strclose(sb);
    + */
    +/*
    + * expandbuf: expand buffer so that afford to the length data at least.
    + *
    + *	i)	sb	STRBUF structure
    + *	i)	length	required room
    + */
    +void
    +expandbuf(sb, length)
    +STRBUF	*sb;
    +int	length;
    +{
    +	int count = sb->curp - sb->sbuf;
    +
    +	sb->sbufsize += (length > EXPANDSIZE) ? length : EXPANDSIZE;
    +	if (!(sb->sbuf = (char *)realloc(sb->sbuf, sb->sbufsize + 1)))
    +		die("short of memory.");
    +	sb->curp = sb->sbuf + count;
    +	sb->endp = sb->sbuf + sb->sbufsize;
    +}
    +/*
    + * stropen: open string buffer.
    + *
    + *	r)	sb	STRBUF structure
    + */
    +STRBUF *
    +stropen(void)
    +{
    +	STRBUF	*sb = (STRBUF *)calloc(sizeof(STRBUF), 1);
    +
    +	if (sb == NULL)
    +		die("short of memory.");
    +	sb->sbufsize = INITIALSIZE;
    +	if (!(sb->sbuf = (char *)malloc(sb->sbufsize + 1)))
    +		die("short of memory.");
    +	sb->curp = sb->sbuf;
    +	sb->endp = sb->sbuf + sb->sbufsize;
    +
    +	return sb;
    +}
    +/*
    + * strstart: reset string buffer for new string.
    + *
    + *	i)	sb	STRBUF structure
    + */
    +void
    +strstart(sb)
    +STRBUF	*sb;
    +{
    +	sb->curp = sb->sbuf;
    +}
    +/*
    + * strbuflen: return the length of string buffer.
    + *
    + *	i)	sb	STRBUF structure
    + */
    +int
    +strbuflen(sb)
    +STRBUF	*sb;
    +{
    +	return sb->curp - sb->sbuf;
    +}
    +/*
    + * strvalue: return the content of string buffer.
    + *
    + *	i)	sb	STRBUF structure
    + *	r)		string
    + */
    +char	*
    +strvalue(sb)
    +STRBUF	*sb;
    +{
    +	*sb->curp = 0;
    +	return sb->sbuf;
    +}
    +/*
    + * strclose: close string buffer.
    + *
    + *	i)	sb	STRBUF structure
    + */
    +void
    +strclose(sb)
    +STRBUF	*sb;
    +{
    +	(void)free(sb->sbuf);
    +	(void)free(sb);
    +}
    diff --git a/contrib/global/lib/strbuf.h b/contrib/global/lib/strbuf.h
    new file mode 100644
    index 000000000000..e62c7ab3e034
    --- /dev/null
    +++ b/contrib/global/lib/strbuf.h
    @@ -0,0 +1,82 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *	This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	strbuf.h					5-Jul-98
    + *
    + */
    +
    +#ifndef _STRBUF_H
    +#define _STRBUF_H
    +
    +#include 
    +#define INITIALSIZE 80
    +#define EXPANDSIZE 80
    +
    +typedef struct {
    +	char	*sbuf;
    +	char	*endp;
    +	char	*curp;
    +	int	sbufsize;
    +} STRBUF;
    +
    +#define strputc(sb,c)	do {\
    +	if (sb->curp + 1 > sb->endp)\
    +		expandbuf(sb, 0);\
    +	*sb->curp++ = c;\
    +} while (0)
    +#define strunputc(sb,c)	do {\
    +	if (sb->curp > sb->sbuf && *(sb->curp - 1) == c)\
    +		sb->curp--;\
    +} while (0)
    +#define strnputs(sb, s, len) do {\
    +	unsigned int _length = len;\
    +	if (sb->curp + _length > sb->endp)\
    +		expandbuf(sb, _length);\
    +	strncpy(sb->curp, s, _length);\
    +	sb->curp += _length;\
    +} while (0)
    +#define strputs(sb, s) strnputs(sb, s, strlen(s))
    +
    +#ifndef __P
    +#if defined(__STDC__)
    +#define __P(protos)     protos
    +#else
    +#define __P(protos)     ()
    +#endif
    +#endif
    +
    +void	expandbuf __P((STRBUF *, int));
    +STRBUF	*stropen __P((void));
    +void	strstart __P((STRBUF *));
    +int	strbuflen __P((STRBUF *));
    +char	*strvalue __P((STRBUF *));
    +void	strclose __P((STRBUF *));
    +
    +#endif /* ! _STRBUF_H */
    diff --git a/contrib/global/lib/strmake.c b/contrib/global/lib/strmake.c
    new file mode 100644
    index 000000000000..da5dea4f25be
    --- /dev/null
    +++ b/contrib/global/lib/strmake.c
    @@ -0,0 +1,59 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *      This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	strmake.c				15-May-98
    + *
    + */
    +#include 
    +
    +#include "strbuf.h"
    +#include "strmake.h"
    +
    +static STRBUF	*sb;
    +
    +char *
    +strmake(p, lim)
    +const char *p;
    +const char *lim;
    +{
    +	const char *c;
    +
    +	if (sb == NULL)
    +		sb = stropen();
    +	strstart(sb);
    +	for (; *p; p++) {
    +		for (c = lim; *c; c++)
    +			if (*p == *c)
    +				goto end;
    +		strputc(sb,*p);
    +	}
    +end:
    +	return strvalue(sb);
    +}
    diff --git a/contrib/global/lib/strmake.h b/contrib/global/lib/strmake.h
    new file mode 100644
    index 000000000000..3558c5514972
    --- /dev/null
    +++ b/contrib/global/lib/strmake.h
    @@ -0,0 +1,48 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *	This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	strmake.h				17-Apr-98
    + *
    + */
    +
    +#ifndef _STRMAKE_H_
    +#define _STRMAKE_H_
    +
    +#ifndef __P
    +#if defined(__STDC__)
    +#define __P(protos)     protos
    +#else
    +#define __P(protos)     ()
    +#endif
    +#endif
    +
    +char	*strmake __P((const char *, const char *));
    +
    +#endif /* ! _STRMAKE_H_ */
    diff --git a/contrib/global/lib/tab.c b/contrib/global/lib/tab.c
    index d309386a2d41..1a9896ff8b26 100644
    --- a/contrib/global/lib/tab.c
    +++ b/contrib/global/lib/tab.c
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -28,14 +28,29 @@
      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      * SUCH DAMAGE.
      *
    - *	tab.c					20-Oct-97
    + *	tab.c					8-Oct-98
      *
      */
     #include 
     
     #include "tab.h"
     
    -#define TABPOS(i)	((i)%8 == 0)
    +static	int	tabs = 8;
    +
    +#define TABPOS(i)	((i)%tabs == 0)
    +/*
    + * settabs: set default tab stop
    + *
    + *	i)	n	tab stop
    + */
    +void
    +settabs(n)
    +int	n;
    +{
    +	if (n < 1 || n > 32)
    +		return;
    +	tabs = n;
    +}
     /*
      * detab: convert tabs into spaces and print
      *
    @@ -84,7 +99,8 @@ char	*buf;
     				blanks++;		/* count blanks */
     				continue;
     			}
    -			buf[dst++] = '\t';
    +			/* don't convert single blank into tab */
    +			buf[dst++] = (blanks == 0) ? ' ' : '\t';
     		} else if (c == '\t') {
     			while (!TABPOS(++pos))
     				;
    @@ -97,5 +113,8 @@ char	*buf;
     		}
     		blanks = 0;
     	}
    +	if (blanks > 0)
    +		while (blanks--)
    +			buf[dst++] = ' ';
     	buf[dst] = 0;
     }
    diff --git a/contrib/global/lib/tab.h b/contrib/global/lib/tab.h
    index c2b507969506..6153ff186c31 100644
    --- a/contrib/global/lib/tab.h
    +++ b/contrib/global/lib/tab.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -28,7 +28,7 @@
      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      * SUCH DAMAGE.
      *
    - *	tab.h					16-Oct-97
    + *	tab.h					8-Oct-98
      *
      */
     
    @@ -43,6 +43,7 @@
     #endif
     #endif
     
    +void	settabs __P((int));
     void	detab __P((FILE *, char *));
     void	entab __P((char *));
     
    diff --git a/contrib/global/lib/test.c b/contrib/global/lib/test.c
    index a3b5966e26a4..d5c940ea294c 100644
    --- a/contrib/global/lib/test.c
    +++ b/contrib/global/lib/test.c
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -31,8 +31,8 @@
      *	test.c					 12-Dec-97
      *
      */
    -#include 
     #include 
    +#include 
     
     #include 
     
    @@ -50,21 +50,23 @@
      *			"x"	[ -x path ]
      *
      *	i)	path	path
    + *			if NULL then previous path.
      *	r)		0: no, 1: ok
      *
      * You can specify more than one character. It assumed 'and' test.
      */
     int
     test(flags, path)
    -char	*flags;
    -char	*path;
    +const char *flags;
    +const char *path;
     {
    -	struct stat sb;
    +	static struct stat sb;
     	int	c;
     
    -	if (stat(path, &sb) < 0)
    -		return 0;
    -	while ((c = *flags++) != NULL) {
    +	if (path != NULL)
    +		if (stat(path, &sb) < 0)
    +			return 0;
    +	while ((c = *flags++) != 0) {
     		switch (c) {
     		case 'f':
     	 		if (!S_ISREG(sb.st_mode))
    diff --git a/contrib/global/lib/test.h b/contrib/global/lib/test.h
    index edadbdaafd7a..c44ee48bb340 100644
    --- a/contrib/global/lib/test.h
    +++ b/contrib/global/lib/test.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -43,6 +43,6 @@
     #endif
     #endif
     
    -int	test __P((char *, char *));
    +int	test __P((const char *, const char *));
     
     #endif /* ! _TEST_H_ */
    diff --git a/contrib/global/lib/token.c b/contrib/global/lib/token.c
    new file mode 100644
    index 000000000000..27dbe4226eef
    --- /dev/null
    +++ b/contrib/global/lib/token.c
    @@ -0,0 +1,293 @@
    +/*
    + * Copyright (c) 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *	This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the University nor the names of its contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	token.c						14-Aug-98
    + */
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "mgets.h"
    +#include "token.h"
    +
    +/*
    + * File input method.
    + */
    +int	lineno;
    +char	*sp, *cp, *lp;
    +int	crflag;			/* 1: return '\n', 0: doesn't return */
    +int	cmode;			/* allow token which start with '#' */
    +int	ymode;			/* allow token which start with '%' */
    +char	token[MAXTOKEN];
    +char	curfile[MAXPATHLEN];
    +
    +static	char ptok[MAXTOKEN];
    +static	int lasttok;
    +static	FILE *ip;
    +
    +static	void pushbackchar __P((void));
    +
    +/*
    + * opentoken:
    + */
    +int
    +opentoken(file)
    +	char	*file;
    +{
    +	if ((ip = fopen(file, "r")) == NULL)
    +		return 0;
    +	strcpy(curfile, file);
    +	sp = cp = lp = NULL; lineno = 0;
    +	return 1;
    +}
    +/*
    + * closetoken:
    + */
    +void
    +closetoken()
    +{
    +	fclose(ip);
    +}
    +
    +/*
    + * nexttoken: get next token
    + *
    + *	i)	interested	interested special charactor
    + *				if NULL then all charactor.
    + *	i)	reserved	converter from token to token number
    + *				if this is specified, nexttoken() return
    + *				word number, else return symbol.
    + *	r)	EOF(-1)	end of file
    + *		==0	symbol ('tok' has the value.)
    + *		> 255	reserved word
    + *		<=255	interested special charactor
    + *
    + * nexttoken() doesn't return followings.
    + *
    + * o comment
    + * o space (' ', '\t', '\f')
    + * o quoted string ("...", '.')
    + */
    +
    +int
    +nexttoken(interested, reserved)
    +	const char *interested;
    +	int (*reserved)(char *);
    +{
    +	int	c;
    +	char	*p;
    +	int	sharp = 0;
    +	int	percent = 0;
    +
    +	/* check push back buffer */
    +	if (ptok[0]) {
    +		strcpy(token, ptok);
    +		ptok[0] = 0;
    +		return lasttok;
    +	}
    +
    +	for (;;) {
    +		/* skip spaces */
    +		if (!crflag)
    +			while ((c = nextchar()) != EOF && isspace(c))
    +				;
    +		else
    +			while ((c = nextchar()) != EOF && (c == ' ' || c == '\t' || c == '\f'))
    +				;
    +		if (c == EOF || c == '\n')
    +			break;
    +
    +		if (c == '"' || c == '\'') {	/* quoted string */
    +			int quote = c;
    +
    +			while ((c = nextchar()) != EOF) {
    +				if (c == quote)
    +					break;
    +				if (quote == '\'' && c == '\n')
    +					break;
    +				if (c == '\\' && (c = nextchar()) == EOF)
    +					break;
    +			}
    +		} else if (c == '/') {			/* comment */
    +			if ((c = nextchar()) == '/') {
    +				while ((c = nextchar()) != EOF)
    +					if (c == '\n')
    +						break;
    +			} else if (c == '*') {
    +				while ((c = nextchar()) != EOF) {
    +					if (c == '*') {
    +						if ((c = nextchar()) == '/')
    +							break;
    +						pushbackchar();
    +					}
    +				}
    +			} else
    +				pushbackchar();
    +		} else if (c == '\\') {
    +			(void)nextchar();
    +		} else if (isdigit(c)) {		/* digit */
    +			while ((c = nextchar()) != EOF && (c == '.' || isdigit(c) || isalpha(c)))
    +				;
    +			pushbackchar();
    +		} else if (c == '#' && cmode) {
    +			/* recognize '##' as a token if it is reserved word. */
    +			if (peekc(1) == '#') {
    +				p = token;
    +				*p++ = c;
    +				*p++ = nextchar();
    +				*p   = 0;
    +				if (reserved && (c = (*reserved)(token)) == 0)
    +					break;
    +			} else if (atfirst_exceptspace()) {
    +				sharp = 1;
    +				continue;
    +			}
    +		} else if (c == '%' && ymode) {
    +			/* recognize '%%' as a token if it is reserved word. */
    +			if (atfirst) {
    +				p = token;
    +				*p++ = c;
    +				if ((c = peekc(1)) == '%' || c == '{' || c == '}') {
    +					*p++ = nextchar();
    +					*p   = 0;
    +					if (reserved && (c = (*reserved)(token)) != 0)
    +						break;
    +				} else if (!isspace(c)) {
    +					percent = 1;
    +					continue;
    +				}
    +			}
    +		} else if (c & 0x80 || isalpha(c) || c == '_') {/* symbol */
    +			p = token;
    +			if (sharp) {
    +				sharp = 0;
    +				*p++ = '#';
    +			} else if (percent) {
    +				percent = 0;
    +				*p++ = '%';
    +			}
    +			for (*p++ = c; (c = nextchar()) != EOF && (c & 0x80 || isalnum(c) || c == '_'); *p++ = c)
    +				;
    +			*p = 0;
    +			if (c != EOF)
    +				pushbackchar();
    +			/* convert token string into token number */
    +			if (reserved)
    +				c = (*reserved)(token);
    +			break;
    +		} else {				/* special char */
    +			if (interested == NULL || strchr(interested, c))
    +				break;
    +			/* otherwise ignore it */
    +		}
    +		sharp = percent = 0;
    +	}
    +	return lasttok = c;
    +}
    +/*
    + * pushbacktoken: push back token
    + *
    + *	following nexttoken() return same token again.
    + */
    +void
    +pushbacktoken()
    +{
    +	strcpy(ptok, token);
    +}
    +/*
    + * peekc: peek next char
    + *
    + *	i)	immediate	0: ignore blank, 1: include blank
    + *
    + * Peekc() read ahead following blanks but doesn't chage line.
    + */
    +int
    +peekc(immediate)
    +	int	immediate;
    +{
    +	int	c;
    +	long	pos;
    +
    +	if (cp != NULL) {
    +		if (immediate)
    +			c = nextchar();
    +		else
    +			while ((c = nextchar()) != EOF && c != '\n' && isspace(c))
    +				;
    +		if (c != EOF)
    +			pushbackchar();
    +		if (c != '\n' || immediate)
    +			return c;
    +	}
    +	pos = ftell(ip);
    +	if (immediate)
    +		c = getc(ip);
    +	else
    +		while ((c = getc(ip)) != EOF && isspace(c))
    +			;
    +	(void)fseek(ip, pos, SEEK_SET);
    +
    +	return c;
    +}
    +/*
    + * atfirst_exceptspace: return if current position is the first column
    + *			except for space.
    + *	|      1 0
    + *      |      v v
    + *	|      # define
    + */
    +int
    +atfirst_exceptspace()
    +{
    +	char	*start = sp;
    +	char	*end = cp ? cp - 1 : lp;
    +
    +	while (start < end && *start && isspace(*start))
    +		start++;
    +	return (start == end) ? 1 : 0;
    +}
    +/*
    + * pushbackchar: push back charactor.
    + *
    + *	following nextchar() return same charactor again.
    + * 
    + */
    +static void
    +pushbackchar()
    +{
    +        if (sp == NULL)
    +                return;         /* nothing to do */
    +        if (cp == NULL)
    +                cp = lp;
    +        else
    +                --cp;
    +}
    diff --git a/contrib/global/lib/token.h b/contrib/global/lib/token.h
    new file mode 100644
    index 000000000000..571b8505c88d
    --- /dev/null
    +++ b/contrib/global/lib/token.h
    @@ -0,0 +1,75 @@
    +/*
    + * Copyright (c) 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *	This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the University nor the names of its contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	token.h						14-Aug-98
    + */
    +
    +#ifndef _TOKEN_H_
    +#define _TOKEN_H_
    +
    +#include 
    +#include "mgets.h"
    +#define MAXTOKEN	512
    +#define SYMBOL		0
    +
    +extern char     *sp, *cp, *lp;
    +extern int      lineno;
    +extern int	crflag;
    +extern int	cmode;
    +extern int	ymode;
    +extern char	token[MAXTOKEN];
    +extern char	curfile[MAXPATHLEN];
    +
    +#define nextchar() \
    +	(cp == NULL ? \
    +		((sp = cp = mgets(ip, NULL, 0)) == NULL ? \
    +			EOF : \
    +			(lineno++, *cp == 0 ? \
    +				lp = cp, cp = NULL, '\n' : \
    +				*cp++)) : \
    +		(*cp == 0 ? (lp = cp, cp = NULL, '\n') : *cp++))
    +#define atfirst (sp && sp == (cp ? cp - 1 : lp))
    +
    +#ifndef __P
    +#if defined(__STDC__)
    +#define __P(protos)     protos
    +#else
    +#define __P(protos)     ()
    +#endif
    +#endif
    +
    +int	opentoken __P((char *));
    +void	closetoken __P((void));
    +int	nexttoken __P((const char *, int (*)(char *)));
    +void	pushbacktoken __P((void));
    +int	peekc __P((int));
    +int     atfirst_exceptspace __P((void));
    +
    +#endif /* ! _TOKEN_H_ */
    diff --git a/contrib/global/lib/usable.c b/contrib/global/lib/usable.c
    new file mode 100644
    index 000000000000..af8dd0ab0fbb
    --- /dev/null
    +++ b/contrib/global/lib/usable.c
    @@ -0,0 +1,70 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *      This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	usable.c					22-Jun-98
    + *
    + */
    +#include 
    +#include 
    +#include 
    +
    +#include "locatestring.h"
    +#include "gparam.h"
    +#include "makepath.h"
    +#include "test.h"
    +#include "usable.h"
    +
    +/*
    + * usable: check executable or not about the command.
    + *
    + *	i)	command
    + *	r)		1: executable
    + *			0: non executable
    + */
    +int
    +usable(command)
    +char	*command;
    +{
    +	char	buf[MAXENVLEN+1], *p, *dir;
    +
    +	if (*command == '/' || locatestring(command, "./", MATCH_AT_FIRST) || locatestring(command, "../", MATCH_AT_FIRST))
    +		return test("fx", command);
    +
    +	strcpy(buf, getenv("PATH"));
    +	p = buf;
    +	while (p) {
    +		dir = p;
    +		if ((p = locatestring(p, ":", MATCH_FIRST)) != NULL)
    +			*p++ = 0;
    +		if (test("fx", makepath(dir, command)))
    +			return 1;
    +	}
    +	return 0;
    +}
    diff --git a/contrib/global/lib/usable.h b/contrib/global/lib/usable.h
    new file mode 100644
    index 000000000000..647769d7ac4a
    --- /dev/null
    +++ b/contrib/global/lib/usable.h
    @@ -0,0 +1,48 @@
    +/*
    + * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. All advertising materials mentioning features or use of this software
    + *    must display the following acknowledgement:
    + *	This product includes software developed by Shigio Yamaguchi.
    + * 4. Neither the name of the author nor the names of any co-contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	usable.h				22-Jul-98
    + *
    + */
    +
    +#ifndef _USABLE_H_
    +#define _USABLE_H_
    +
    +#ifndef __P
    +#if defined(__STDC__)
    +#define __P(protos)     protos
    +#else
    +#define __P(protos)     ()
    +#endif
    +#endif
    +
    +int	usable __P((char *));
    +
    +#endif /* ! _USABLE_H_ */
    diff --git a/contrib/global/nvi-1.66.diff b/contrib/global/nvi-1.66.diff
    new file mode 100644
    index 000000000000..bf1400b5679a
    --- /dev/null
    +++ b/contrib/global/nvi-1.66.diff
    @@ -0,0 +1,673 @@
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/build/Makefile ./build/Makefile
    +*** /usr/src/usr.bin/nvi-1.66.org/build/Makefile	Tue May  5 15:57:21 1998
    +--- ./build/Makefile	Sun Aug 16 03:22:53 1998
    +***************
    +*** 3,9 ****
    +  # from: @(#)Makefile.in	8.56 (Berkeley) 5/18/96
    +  
    +  WARNS=	0
    +! CPPFLAGS+=-I${.CURDIR} -I${.CURDIR}/../include
    +  
    +  LDADD+= -lcurses -ltermcap
    +  DPADD+= ${LIBCURSES} ${LIBTERMCAP}
    +--- 3,9 ----
    +  # from: @(#)Makefile.in	8.56 (Berkeley) 5/18/96
    +  
    +  WARNS=	0
    +! CPPFLAGS+=-I${.CURDIR} -I${.CURDIR}/../include -DGTAGS
    +  
    +  LDADD+= -lcurses -ltermcap
    +  DPADD+= ${LIBCURSES} ${LIBTERMCAP}
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/common/main.c ./common/main.c
    +*** /usr/src/usr.bin/nvi-1.66.org/common/main.c	Tue May  5 15:57:26 1998
    +--- ./common/main.c	Sun Aug 16 03:27:19 1998
    +***************
    +*** 63,68 ****
    +--- 63,71 ----
    +  	size_t len;
    +  	u_int flags;
    +  	int ch, fd, flagchk, lflag, startup, readonly, rval, silent;
    ++ #ifdef GTAGS
    ++ 	int gtags = 0;
    ++ #endif
    +  	char *tag_f, *wsizearg;
    +  	char path[256];
    +  
    +***************
    +*** 113,123 ****
    +--- 116,135 ----
    +  	/* Set the file snapshot flag. */
    +  	F_SET(gp, G_SNAPSHOT);
    +  
    ++ #ifdef GTAGS
    ++ #ifdef DEBUG
    ++ 	while ((ch = getopt(argc, argv, "c:D:eFGlRrsT:t:vw:")) != EOF)
    ++ #else
    ++ 	while ((ch = getopt(argc, argv, "c:eFGlRrst:vw:")) != EOF)
    ++ #endif
    ++ #else
    +  #ifdef DEBUG
    +  	while ((ch = getopt(argc, argv, "c:D:eFlRrsT:t:vw:")) != EOF)
    +  #else
    +  	while ((ch = getopt(argc, argv, "c:eFlRrst:vw:")) != EOF)
    +  #endif
    ++ #endif
    ++ 
    +  		switch (ch) {
    +  		case 'c':		/* Run the command. */
    +  			/*
    +***************
    +*** 167,172 ****
    +--- 179,189 ----
    +  		case 'F':		/* No snapshot. */
    +  			F_CLR(gp, G_SNAPSHOT);
    +  			break;
    ++ #ifdef GTAGS
    ++ 		case 'G':               /* gtags mode. */
    ++ 			gtags = 1;
    ++ 			break;
    ++ #endif
    +  		case 'l':		/* Set lisp, showmatch options. */
    +  			lflag = 1;
    +  			break;
    +***************
    +*** 258,263 ****
    +--- 275,284 ----
    +  	{ int oargs[4], *oargp = oargs;
    +  	if (readonly)			/* Command-line options. */
    +  		*oargp++ = O_READONLY;
    ++ #ifdef GTAGS
    ++ 	if (gtags)
    ++ 		*oargp++ = O_GTAGSMODE;
    ++ #endif
    +  	if (lflag) {
    +  		*oargp++ = O_LISP;
    +  		*oargp++ = O_SHOWMATCH;
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/common/options.c ./common/options.c
    +*** /usr/src/usr.bin/nvi-1.66.org/common/options.c	Tue May  5 15:57:26 1998
    +--- ./common/options.c	Sun Aug 16 03:29:51 1998
    +***************
    +*** 80,85 ****
    +--- 80,89 ----
    +  	{"filec",	NULL,		OPT_STR,	0},
    +  /* O_FLASH	    HPUX */
    +  	{"flash",	NULL,		OPT_1BOOL,	0},
    ++ #ifdef GTAGS
    ++ /* O_GTAGSMODE      FreeBSD, NetBSD */
    ++ 	{"gtagsmode",   NULL,           OPT_0BOOL,      0},
    ++ #endif
    +  /* O_HARDTABS	    4BSD */
    +  	{"hardtabs",	NULL,		OPT_NUM,	0},
    +  /* O_ICLOWER	  4.4BSD */
    +***************
    +*** 240,245 ****
    +--- 244,252 ----
    +  	{"eb",		O_ERRORBELLS},		/*     4BSD */
    +  	{"ed",		O_EDCOMPATIBLE},	/*     4BSD */
    +  	{"ex",		O_EXRC},		/* System V (undocumented) */
    ++ #ifdef GTAGS
    ++ 	{"gt",		O_GTAGSMODE},		/* FreeBSD, NetBSD */
    ++ #endif
    +  	{"ht",		O_HARDTABS},		/*     4BSD */
    +  	{"ic",		O_IGNORECASE},		/*     4BSD */
    +  	{"li",		O_LINES},		/*   4.4BSD */
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/docs/USD.doc/vi.man/vi.1 ./docs/USD.doc/vi.man/vi.1
    +*** /usr/src/usr.bin/nvi-1.66.org/docs/USD.doc/vi.man/vi.1	Tue May  5 15:57:31 1998
    +--- ./docs/USD.doc/vi.man/vi.1	Sun Aug 16 03:34:12 1998
    +***************
    +*** 40,46 ****
    +  .SH SYNOPSIS
    +  .B ex
    +  [\c
    +! .B -eFRrsv\c
    +  ] [\c
    +  .BI -c " cmd"\c
    +  ] [\c
    +--- 40,46 ----
    +  .SH SYNOPSIS
    +  .B ex
    +  [\c
    +! .B -eFGRrsv\c
    +  ] [\c
    +  .BI -c " cmd"\c
    +  ] [\c
    +***************
    +*** 51,57 ****
    +  .br
    +  .B vi
    +  [\c
    +! .B -eFlRrv\c
    +  ] [\c
    +  .BI -c " cmd"\c
    +  ] [\c
    +--- 51,57 ----
    +  .br
    +  .B vi
    +  [\c
    +! .B -eFGlRrv\c
    +  ] [\c
    +  .BI -c " cmd"\c
    +  ] [\c
    +***************
    +*** 62,68 ****
    +  .br
    +  .B view
    +  [\c
    +! .B -eFRrv\c
    +  ] [\c
    +  .BI -c " cmd"\c
    +  ] [\c
    +--- 62,68 ----
    +  .br
    +  .B view
    +  [\c
    +! .B -eFGRrv\c
    +  ] [\c
    +  .BI -c " cmd"\c
    +  ] [\c
    +***************
    +*** 135,140 ****
    +--- 135,143 ----
    +  (The default is to make a copy in case someone else modifies
    +  the file during your edit session.)
    +  .TP
    ++ .B \-G
    ++ Start editing in gtags mode, as if the gtagsmode option was set.
    ++ .TP
    +  .B \-l
    +  Start editing with the lisp and showmatch options set.
    +  .TP
    +***************
    +*** 441,446 ****
    +--- 444,451 ----
    +  .TP
    +  .B ""
    +  Push a tag reference onto the tag stack.
    ++ In gtagsmode, if at the first column of line,
    ++ locate function references otherwise function definitions.
    +  .TP
    +  .B ""
    +  Switch to the most recently edited file.
    +***************
    +*** 952,957 ****
    +--- 957,965 ----
    +  .B "rew[ind][!]"
    +  Rewind the argument list.
    +  .TP
    ++ .B "rta[g][!] tagstring"
    ++ Edit the file refering the specified tag. (Only in gtagsmode)
    ++ .TP
    +  .B "se[t] [option[=[value]] ...] [nooption ...] [option? ...] [all]"
    +  Display or set editor options.
    +  .TP
    +***************
    +*** 1121,1126 ****
    +--- 1129,1137 ----
    +  .TP
    +  .B "flash [on]"
    +  Flash the screen instead of beeping the keyboard on error.
    ++ .TP
    ++ .B "gtagsmode, gt [off]"
    ++ Use GTAGS and GRTAGS instead of tags.
    +  .TP
    +  .B "hardtabs, ht [8]"
    +  Set the spacing between hardware tab settings.
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/ex/ex.h ./ex/ex.h
    +*** /usr/src/usr.bin/nvi-1.66.org/ex/ex.h	Tue May  5 15:57:37 1998
    +--- ./ex/ex.h	Sun Aug 16 03:35:58 1998
    +***************
    +*** 162,167 ****
    +--- 162,170 ----
    +  #define	E_NEWLINE	0x00800000	/* Found ending . */
    +  #define	E_USELASTCMD	0x01000000	/* Use the last command. */
    +  #define	E_VISEARCH	0x02000000	/* It's really a vi search command. */
    ++ #ifdef GTAGS
    ++ #define	E_REFERENCE	0x04000000	/* locate function references */
    ++ #endif
    +  	u_int32_t flags;		/* Current flags. */
    +  };
    +  
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/ex/ex_cmd.c ./ex/ex_cmd.c
    +*** /usr/src/usr.bin/nvi-1.66.org/ex/ex_cmd.c	Tue May  5 15:57:37 1998
    +--- ./ex/ex_cmd.c	Sun Aug 16 03:38:03 1998
    +***************
    +*** 302,307 ****
    +--- 302,314 ----
    +  	    "!",
    +  	    "rew[ind][!]",
    +  	    "re-edit all the files in the file argument list"},
    ++ #ifdef GTAGS
    ++ /* C_RTAG */
    ++ 	{"rtag",        ex_rtag_push,   E_NEWSCREEN,
    ++ 	    "!w1o",
    ++ 	    "rta[g][!] [string]",
    ++ 	    "edit the file containing the tag"},
    ++ #endif
    +  /*
    +   * !!!
    +   * Adding new commands starting with 's' may break the substitute command code
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/ex/ex_tag.c ./ex/ex_tag.c
    +*** /usr/src/usr.bin/nvi-1.66.org/ex/ex_tag.c	Tue May  5 15:57:41 1998
    +--- ./ex/ex_tag.c	Sun Aug 16 03:46:43 1998
    +***************
    +*** 46,51 ****
    +--- 46,55 ----
    +  static int	 compare __P((char *, char *, char *));
    +  static void	 ctag_file __P((SCR *, TAGF *, char *, char **, size_t *));
    +  static int	 ctag_search __P((SCR *, char *, char *));
    ++ #ifdef GTAGS
    ++ static int     getentry __P((char *, char **, char **, char **));
    ++ static TAGQ   *gtag_slist __P((SCR *, char *, int));
    ++ #endif
    +  static int	 ctag_sfile __P((SCR *, TAGF *, TAGQ *, char *));
    +  static TAGQ	*ctag_slist __P((SCR *, char *));
    +  static char	*linear_search __P((char *, char *, char *));
    +***************
    +*** 89,94 ****
    +--- 93,117 ----
    +  	return (0);
    +  }
    +  
    ++ #ifdef GTAGS
    ++ /*
    ++  * ex_rtag_push -- ^]
    ++  *              :rtag[!] [string]
    ++  *
    ++  * Enter a new TAGQ context based on a ctag string.
    ++  *
    ++  * PUBLIC: int ex_rtag_push __P((SCR *, EXCMD *));
    ++  */
    ++ int
    ++ ex_rtag_push(sp, cmdp)
    ++ 	SCR *sp;
    ++ 	EXCMD *cmdp;
    ++ {
    ++ 	F_SET(cmdp, E_REFERENCE);
    ++ 	return ex_tag_push(sp, cmdp);
    ++ }
    ++ #endif
    ++ 
    +  /*
    +   * ex_tag_push -- ^]
    +   *		  :tag[!] [string]
    +***************
    +*** 138,143 ****
    +--- 161,172 ----
    +  	}
    +  
    +  	/* Get the tag information. */
    ++ #ifdef GTAGS
    ++ 	if (O_ISSET(sp, O_GTAGSMODE)) {
    ++ 		if ((tqp = gtag_slist(sp, exp->tag_last, F_ISSET(cmdp, E_REFERENCE))) == NULL)
    ++ 			return (1);
    ++ 	} else
    ++ #endif
    +  	if ((tqp = ctag_slist(sp, exp->tag_last)) == NULL)
    +  		return (1);
    +  
    +***************
    +*** 963,969 ****
    +--- 992,1120 ----
    +  	(void)nonblank(sp, sp->lno, &sp->cno);
    +  	return (0);
    +  }
    ++ #ifdef GTAGS
    ++ /*
    ++  * getentry --
    ++  *	get tag information from current line.
    ++  *
    ++  * gtags temporary file format.
    ++  *               
    ++  *
    ++  * sample.
    ++  * +------------------------------------------------
    ++  * |main     30      main.c         main(argc, argv)
    ++  * |func     21      subr.c         func(arg)
    ++  */
    ++ static int
    ++ getentry(buf, tag, file, line)
    ++ 	char *buf, **tag, **file, **line;
    ++ {
    ++ 	char *p = buf;
    ++ 
    ++ 	for (*tag = p; *p && !isspace(*p); p++)		/* tag name */
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
    ++ 	*p++ = 0;
    ++ 	for (; *p && isspace(*p); p++)			/* (skip blanks) */
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
    ++ 	*line = p;					/* line no */
    ++ 	for (*line = p; *p && !isspace(*p); p++)
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
    ++ 	*p++ = 0;
    ++ 	for (; *p && isspace(*p); p++)			/* (skip blanks) */
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
    ++ 	*file = p;					/* file name */
    ++ 	for (*file = p; *p && !isspace(*p); p++)
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
    ++ 	*p = 0;
    ++ 
    ++ 	/* value check */
    ++ 	if (strlen(*tag) && strlen(*line) && strlen(*file) && atoi(*line) > 0)
    ++ 		return 1;	/* OK */
    ++ err:
    ++ 	return 0;		/* ERROR */
    ++ }
    ++ 
    ++ /*
    ++  * gtag_slist --
    ++  *	Search the list of tags files for a tag, and return tag queue.
    ++  */
    ++ static TAGQ *
    ++ gtag_slist(sp, tag, ref)
    ++ 	SCR *sp;
    ++ 	char *tag;
    ++ 	int ref;
    ++ {
    ++ 	EX_PRIVATE *exp;
    ++ 	TAGF *tfp;
    ++ 	TAGQ *tqp;
    ++ 	size_t len;
    ++ 	int echk;
    ++ 	TAG *tp;
    ++ 	char *name, *file, *line;
    ++ 	char command[BUFSIZ];
    ++ 	char buf[BUFSIZ];
    ++ 	FILE *fp;
    ++ 
    ++ 	/* Allocate and initialize the tag queue structure. */
    ++ 	len = strlen(tag);
    ++ 	CALLOC_GOTO(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + len + 1);
    ++ 	CIRCLEQ_INIT(&tqp->tagq);
    ++ 	tqp->tag = tqp->buf;
    ++ 	memcpy(tqp->tag, tag, (tqp->tlen = len) + 1);
    ++ 
    ++ 	/*
    ++ 	 * Find the tag, only display missing file messages once, and
    ++ 	 * then only if we didn't find the tag.
    ++ 	 */
    ++ 	snprintf(command, sizeof(command), "global -%s '%s' 2>/dev/null", ref ? "rx" : "x", tag);
    ++ 	if (fp = popen(command, "r")) {
    ++ 		while (fgets(buf, sizeof(buf), fp)) {
    ++ 			if (buf[strlen(buf)-1] == '\n')		/* chop(buf) */
    ++ 				buf[strlen(buf)-1] = 0;
    ++ 			else
    ++ 				while (fgetc(fp) != '\n')
    ++ 					;
    ++ 			if (getentry(buf, &name, &file, &line) == 0) {
    ++ 				echk = 1;
    ++ 				F_SET(tfp, TAGF_ERR);
    ++ 				break;
    ++ 			}
    ++ 			CALLOC_GOTO(sp, tp,
    ++ 			    TAG *, 1, sizeof(TAG) + strlen(file) + 1 + strlen(line) + 1);
    ++ 			tp->fname = tp->buf;
    ++ 			strcpy(tp->fname, file);
    ++ 			tp->fnlen = strlen(file);
    ++ 			tp->search = tp->fname + tp->fnlen + 1;
    ++ 			strcpy(tp->search, line);
    ++ 			CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q);
    ++ 		}
    ++ 		pclose(fp);
    ++ 	}
    ++ 
    ++ 	/* Check to see if we found anything. */
    ++ 	if (tqp->tagq.cqh_first == (void *)&tqp->tagq) {
    ++ 		msgq_str(sp, M_ERR, tag, "162|%s: tag not found");
    ++ 		free(tqp);
    ++ 		return (NULL);
    ++ 	}
    +  
    ++ 	tqp->current = tqp->tagq.cqh_first;
    ++ 	return (tqp);
    ++ 
    ++ alloc_err:
    ++ 	return (NULL);
    ++ }
    ++ #endif
    +  /*
    +   * ctag_slist --
    +   *	Search the list of tags files for a tag, and return tag queue.
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/include/ex_def.h ./include/ex_def.h
    +*** /usr/src/usr.bin/nvi-1.66.org/include/ex_def.h	Tue May  5 15:57:42 1998
    +--- ./include/ex_def.h	Sun Aug 16 03:49:40 1998
    +***************
    +*** 47,78 ****
    +  #define C_RECOVER 46
    +  #define C_RESIZE 47
    +  #define C_REWIND 48
    +! #define C_SUBSTITUTE 49
    +! #define C_SCRIPT 50
    +! #define C_SET 51
    +! #define C_SHELL 52
    +! #define C_SOURCE 53
    +! #define C_STOP 54
    +! #define C_SUSPEND 55
    +! #define C_T 56
    +! #define C_TAG 57
    +! #define C_TAGNEXT 58
    +! #define C_TAGPOP 59
    +! #define C_TAGPREV 60
    +! #define C_TAGTOP 61
    +! #define C_TCLCMD 62
    +! #define C_UNDO 63
    +! #define C_UNABBREVIATE 64
    +! #define C_UNMAP 65
    +! #define C_V 66
    +! #define C_VERSION 67
    +! #define C_VISUAL_EX 68
    +! #define C_VISUAL_VI 69
    +! #define C_VIUSAGE 70
    +! #define C_WRITE 71
    +! #define C_WN 72
    +! #define C_WQ 73
    +! #define C_XIT 74
    +! #define C_YANK 75
    +! #define C_Z 76
    +! #define C_SUBTILDE 77
    +--- 47,79 ----
    +  #define C_RECOVER 46
    +  #define C_RESIZE 47
    +  #define C_REWIND 48
    +! #define C_RTAG 49
    +! #define C_SUBSTITUTE 50
    +! #define C_SCRIPT 51
    +! #define C_SET 52
    +! #define C_SHELL 53
    +! #define C_SOURCE 54
    +! #define C_STOP 55
    +! #define C_SUSPEND 56
    +! #define C_T 57
    +! #define C_TAG 58
    +! #define C_TAGNEXT 59
    +! #define C_TAGPOP 60
    +! #define C_TAGPREV 61
    +! #define C_TAGTOP 62
    +! #define C_TCLCMD 63
    +! #define C_UNDO 64
    +! #define C_UNABBREVIATE 65
    +! #define C_UNMAP 66
    +! #define C_V 67
    +! #define C_VERSION 68
    +! #define C_VISUAL_EX 69
    +! #define C_VISUAL_VI 70
    +! #define C_VIUSAGE 71
    +! #define C_WRITE 72
    +! #define C_WN 73
    +! #define C_WQ 74
    +! #define C_XIT 75
    +! #define C_YANK 76
    +! #define C_Z 77
    +! #define C_SUBTILDE 78
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/include/ex_extern.h ./include/ex_extern.h
    +*** /usr/src/usr.bin/nvi-1.66.org/include/ex_extern.h	Tue May  5 15:57:42 1998
    +--- ./include/ex_extern.h	Sun Aug 16 03:50:24 1998
    +***************
    +*** 92,97 ****
    +--- 92,100 ----
    +      char *, char **, size_t *, regex_t *, u_int));
    +  void re_error __P((SCR *, int, regex_t *));
    +  int ex_tag_first __P((SCR *, char *));
    ++ #ifdef GTAGS
    ++ int ex_rtag_push __P((SCR *, EXCMD *));
    ++ #endif
    +  int ex_tag_push __P((SCR *, EXCMD *));
    +  int ex_tag_next __P((SCR *, EXCMD *));
    +  int ex_tag_prev __P((SCR *, EXCMD *));
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/include/options_def.h ./include/options_def.h
    +*** /usr/src/usr.bin/nvi-1.66.org/include/options_def.h	Tue May  5 15:57:42 1998
    +--- ./include/options_def.h	Sun Aug 16 03:54:45 1998
    +***************
    +*** 16,77 ****
    +  #define O_EXTENDED 15
    +  #define O_FILEC 16
    +  #define O_FLASH 17
    +! #define O_HARDTABS 18
    +! #define O_ICLOWER 19
    +! #define O_IGNORECASE 20
    +! #define O_KEYTIME 21
    +! #define O_LEFTRIGHT 22
    +! #define O_LINES 23
    +! #define O_LISP 24
    +! #define O_LIST 25
    +! #define O_LOCKFILES 26
    +! #define O_MAGIC 27
    +! #define O_MATCHTIME 28
    +! #define O_MESG 29
    +! #define O_MODELINE 30
    +! #define O_MSGCAT 31
    +! #define O_NOPRINT 32
    +! #define O_NUMBER 33
    +! #define O_OCTAL 34
    +! #define O_OPEN 35
    +! #define O_OPTIMIZE 36
    +! #define O_PARAGRAPHS 37
    +! #define O_PRINT 38
    +! #define O_PROMPT 39
    +! #define O_READONLY 40
    +! #define O_RECDIR 41
    +! #define O_REDRAW 42
    +! #define O_REMAP 43
    +! #define O_REPORT 44
    +! #define O_RULER 45
    +! #define O_SCROLL 46
    +! #define O_SEARCHINCR 47
    +! #define O_SECTIONS 48
    +! #define O_SECURE 49
    +! #define O_SHELL 50
    +! #define O_SHELLMETA 51
    +! #define O_SHIFTWIDTH 52
    +! #define O_SHOWMATCH 53
    +! #define O_SHOWMODE 54
    +! #define O_SIDESCROLL 55
    +! #define O_SLOWOPEN 56
    +! #define O_SOURCEANY 57
    +! #define O_TABSTOP 58
    +! #define O_TAGLENGTH 59
    +! #define O_TAGS 60
    +! #define O_TERM 61
    +! #define O_TERSE 62
    +! #define O_TILDEOP 63
    +! #define O_TIMEOUT 64
    +! #define O_TTYWERASE 65
    +! #define O_VERBOSE 66
    +! #define O_W1200 67
    +! #define O_W300 68
    +! #define O_W9600 69
    +! #define O_WARN 70
    +! #define O_WINDOW 71
    +! #define O_WRAPLEN 72
    +! #define O_WRAPMARGIN 73
    +! #define O_WRAPSCAN 74
    +! #define O_WRITEANY 75
    +! #define O_OPTIONCOUNT 76
    +--- 16,78 ----
    +  #define O_EXTENDED 15
    +  #define O_FILEC 16
    +  #define O_FLASH 17
    +! #define O_GTAGSMODE 18
    +! #define O_HARDTABS 19
    +! #define O_ICLOWER 20
    +! #define O_IGNORECASE 21
    +! #define O_KEYTIME 22
    +! #define O_LEFTRIGHT 23
    +! #define O_LINES 24
    +! #define O_LISP 25
    +! #define O_LIST 26
    +! #define O_LOCKFILES 27
    +! #define O_MAGIC 28
    +! #define O_MATCHTIME 29
    +! #define O_MESG 30
    +! #define O_MODELINE 31
    +! #define O_MSGCAT 32
    +! #define O_NOPRINT 33
    +! #define O_NUMBER 34
    +! #define O_OCTAL 35
    +! #define O_OPEN 36
    +! #define O_OPTIMIZE 37
    +! #define O_PARAGRAPHS 38
    +! #define O_PRINT 39
    +! #define O_PROMPT 40
    +! #define O_READONLY 41
    +! #define O_RECDIR 42
    +! #define O_REDRAW 43
    +! #define O_REMAP 44
    +! #define O_REPORT 45
    +! #define O_RULER 46
    +! #define O_SCROLL 47
    +! #define O_SEARCHINCR 48
    +! #define O_SECTIONS 49
    +! #define O_SECURE 50
    +! #define O_SHELL 51
    +! #define O_SHELLMETA 52
    +! #define O_SHIFTWIDTH 53
    +! #define O_SHOWMATCH 54
    +! #define O_SHOWMODE 55
    +! #define O_SIDESCROLL 56
    +! #define O_SLOWOPEN 57
    +! #define O_SOURCEANY 58
    +! #define O_TABSTOP 59
    +! #define O_TAGLENGTH 60
    +! #define O_TAGS 61
    +! #define O_TERM 62
    +! #define O_TERSE 63
    +! #define O_TILDEOP 64
    +! #define O_TIMEOUT 65
    +! #define O_TTYWERASE 66
    +! #define O_VERBOSE 67
    +! #define O_W1200 68
    +! #define O_W300 69
    +! #define O_W9600 70
    +! #define O_WARN 71
    +! #define O_WINDOW 72
    +! #define O_WRAPLEN 73
    +! #define O_WRAPMARGIN 74
    +! #define O_WRAPSCAN 75
    +! #define O_WRITEANY 76
    +! #define O_OPTIONCOUNT 77
    +diff -c -r -N /usr/src/usr.bin/nvi-1.66.org/vi/v_ex.c ./vi/v_ex.c
    +*** /usr/src/usr.bin/nvi-1.66.org/vi/v_ex.c	Tue May  5 15:57:45 1998
    +--- ./vi/v_ex.c	Sun Aug 16 03:55:38 1998
    +***************
    +*** 221,226 ****
    +--- 221,231 ----
    +  	ARGS *ap[2], a;
    +  	EXCMD cmd;
    +  
    ++ #ifdef GTAGS
    ++ 	if (O_ISSET(sp, O_GTAGSMODE) && vp->m_start.cno == 0)
    ++ 		ex_cinit(&cmd, C_RTAG, 0, OOBLNO, 0, 0, ap);
    ++ 	else
    ++ #endif
    +  	ex_cinit(&cmd, C_TAG, 0, OOBLNO, 0, 0, ap);
    +  	ex_cadd(&cmd, &a, VIP(sp)->keyw, strlen(VIP(sp)->keyw));
    +  	return (v_exec_ex(sp, vp, &cmd));
    diff --git a/contrib/global/nvi-1.79.diff b/contrib/global/nvi-1.79.diff
    index a0c8d55c0772..7b601b204482 100644
    --- a/contrib/global/nvi-1.79.diff
    +++ b/contrib/global/nvi-1.79.diff
    @@ -1,6 +1,6 @@
     diff -c -r -N /usr/local/src/nvi-1.79/build/Makefile.in ./build/Makefile.in
     *** /usr/local/src/nvi-1.79/build/Makefile.in	Wed Oct 23 22:43:38 1996
    ---- ./build/Makefile.in	Wed Apr 16 21:20:09 1997
    +--- ./build/Makefile.in	Fri Aug 14 01:41:14 1998
     ***************
     *** 3,9 ****
       srcdir=	@srcdir@/..
    @@ -20,7 +20,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/build/Makefile.in ./build/Makefile.in
       PERLLIB=@vi_cv_perllib@
     diff -c -r -N /usr/local/src/nvi-1.79/common/main.c ./common/main.c
     *** /usr/local/src/nvi-1.79/common/main.c	Sat Oct 12 07:28:28 1996
    ---- ./common/main.c	Wed Apr 16 21:20:09 1997
    +--- ./common/main.c	Fri Aug 14 01:41:14 1998
     ***************
     *** 64,69 ****
     --- 64,72 ----
    @@ -84,7 +84,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/common/main.c ./common/main.c
       	*oargp = -1;			/* Options initialization. */
     diff -c -r -N /usr/local/src/nvi-1.79/common/options.c ./common/options.c
     *** /usr/local/src/nvi-1.79/common/options.c	Tue Oct 15 03:56:29 1996
    ---- ./common/options.c	Wed Apr 16 21:20:09 1997
    +--- ./common/options.c	Fri Aug 14 01:41:14 1998
     ***************
     *** 80,85 ****
     --- 80,89 ----
    @@ -112,7 +112,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/common/options.c ./common/options.c
       	{"li",		O_LINES},		/*   4.4BSD */
     diff -c -r -N /usr/local/src/nvi-1.79/docs/USD.doc/vi.man/vi.1 ./docs/USD.doc/vi.man/vi.1
     *** /usr/local/src/nvi-1.79/docs/USD.doc/vi.man/vi.1	Fri Oct 11 10:34:05 1996
    ---- ./docs/USD.doc/vi.man/vi.1	Wed Apr 16 21:20:09 1997
    +--- ./docs/USD.doc/vi.man/vi.1	Fri Aug 14 01:41:14 1998
     ***************
     *** 17,23 ****
       .SH SYNOPSIS
    @@ -213,7 +213,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/docs/USD.doc/vi.man/vi.1 ./docs/USD.doc/vi
       Set the spacing between hardware tab settings.
     diff -c -r -N /usr/local/src/nvi-1.79/ex/ex.h ./ex/ex.h
     *** /usr/local/src/nvi-1.79/ex/ex.h	Tue Aug 13 09:24:00 1996
    ---- ./ex/ex.h	Wed Apr 16 21:20:09 1997
    +--- ./ex/ex.h	Fri Aug 14 01:41:14 1998
     ***************
     *** 152,157 ****
     --- 152,160 ----
    @@ -228,7 +228,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex.h ./ex/ex.h
       
     diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_cmd.c ./ex/ex_cmd.c
     *** /usr/local/src/nvi-1.79/ex/ex_cmd.c	Wed Oct 23 22:31:01 1996
    ---- ./ex/ex_cmd.c	Wed Apr 16 21:20:09 1997
    +--- ./ex/ex_cmd.c	Fri Aug 14 01:41:14 1998
     ***************
     *** 302,307 ****
     --- 302,314 ----
    @@ -239,7 +239,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_cmd.c ./ex/ex_cmd.c
     + /* C_RTAG */
     + 	{"rtag",	ex_rtag_push,	E_NEWSCREEN,
     + 	    "!w1o",
    -+ 	    "[Rr]ta[g][!] [string]",
    ++ 	    "rta[g][!] [string]",
     + 	    "edit the file containing the tag"},
     + #endif
       /*
    @@ -247,7 +247,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_cmd.c ./ex/ex_cmd.c
        * Adding new commands starting with 's' may break the substitute command code
     diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_tag.c ./ex/ex_tag.c
     *** /usr/local/src/nvi-1.79/ex/ex_tag.c	Mon Sep 16 05:02:43 1996
    ---- ./ex/ex_tag.c	Wed Apr 16 21:20:09 1997
    +--- ./ex/ex_tag.c	Fri Aug 14 01:53:35 1998
     ***************
     *** 46,51 ****
     --- 46,55 ----
    @@ -255,7 +255,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_tag.c ./ex/ex_tag.c
       static void	 ctag_file __P((SCR *, TAGF *, char *, char **, size_t *));
       static int	 ctag_search __P((SCR *, char *, size_t, char *));
     + #ifdef GTAGS
    -+ static int	 getentry __P((char *, char *, char *, char *));
    ++ static int	 getentry __P((char *, char **, char **, char **));
     + static TAGQ	*gtag_slist __P((SCR *, char *, int));
     + #endif
       static int	 ctag_sfile __P((SCR *, TAGF *, TAGQ *, char *));
    @@ -306,7 +306,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_tag.c ./ex/ex_tag.c
       
     ***************
     *** 969,974 ****
    ---- 998,1116 ----
    +--- 998,1126 ----
       	return (0);
       }
       
    @@ -325,30 +325,40 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_tag.c ./ex/ex_tag.c
     +  */
     + static int
     + getentry(buf, tag, file, line)
    -+ 	char *buf, *tag, *file, *line;
    ++ 	char *buf, **tag, **file, **line;
     + {
    -+ 	char *p;
    ++ 	char *p = buf;
     + 
    -+ 	p = tag;
    -+ 	while (*buf && !isspace(*buf))		/* tag name */
    -+ 		*p++ = *buf++;
    -+ 	*p = 0;
    -+ 	while (*buf && isspace(*buf))		/* skip blanks */
    -+ 		buf++;
    -+ 	p = line;
    -+ 	while (*buf && !isspace(*buf))		/* line no */
    -+ 		*p++ = *buf++;
    -+ 	*p = 0;
    -+ 	while (*buf && isspace(*buf))		/* skip blanks */
    -+ 		buf++;
    -+ 	p = file;
    -+ 	while (*buf && !isspace(*buf))		/* file name */
    -+ 		*p++ = *buf++;
    ++ 	for (*tag = p; *p && !isspace(*p); p++)		/* tag name */
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
    ++ 	*p++ = 0;
    ++ 	for (; *p && isspace(*p); p++)			/* (skip blanks) */
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
    ++ 	*line = p;					/* line no */
    ++ 	for (*line = p; *p && !isspace(*p); p++)
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
    ++ 	*p++ = 0;
    ++ 	for (; *p && isspace(*p); p++)			/* (skip blanks) */
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
    ++ 	*file = p;					/* file name */
    ++ 	for (*file = p; *p && !isspace(*p); p++)
    ++ 		;
    ++ 	if (*p == 0)
    ++ 		goto err;
     + 	*p = 0;
     + 
     + 	/* value check */
    -+ 	if (strlen(tag) && strlen(line) && strlen(file) && atoi(line) > 0)
    ++ 	if (strlen(*tag) && strlen(*line) && strlen(*file) && atoi(*line) > 0)
     + 		return 1;	/* OK */
    ++ err:
     + 	return 0;		/* ERROR */
     + }
     + 
    @@ -368,9 +378,9 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_tag.c ./ex/ex_tag.c
     + 	size_t len;
     + 	int echk;
     + 	TAG *tp;
    -+ 	static char name[80], file[200], line[10];
    -+ 	char command[200];
    -+ 	char buf[BUFSIZ+1];
    ++ 	char *name, *file, *line;
    ++ 	char command[BUFSIZ];
    ++ 	char buf[BUFSIZ];
     + 	FILE *fp;
     + 
     + 	/* Allocate and initialize the tag queue structure. */
    @@ -384,7 +394,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_tag.c ./ex/ex_tag.c
     + 	 * Find the tag, only display missing file messages once, and
     + 	 * then only if we didn't find the tag.
     + 	 */
    -+ 	sprintf(command, "global -%s '%s'", ref ? "rx" : "x", tag);
    ++ 	snprintf(command, sizeof(command), "global -%s '%s' 2>/dev/null", ref ? "rx" : "x", tag);
     + 	if (fp = popen(command, "r")) {
     + 		while (fgets(buf, sizeof(buf), fp)) {
     + 			if (buf[strlen(buf)-1] == '\n')		/* chop(buf) */
    @@ -392,7 +402,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_tag.c ./ex/ex_tag.c
     + 			else
     + 				while (fgetc(fp) != '\n')
     + 					;
    -+ 			if (getentry(buf, name, file, line) == 0) {
    ++ 			if (getentry(buf, &name, &file, &line) == 0) {
     + 				echk = 1;
     + 				F_SET(tfp, TAGF_ERR);
     + 				break;
    @@ -428,7 +438,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/ex/ex_tag.c ./ex/ex_tag.c
        *	Search the list of tags files for a tag, and return tag queue.
     diff -c -r -N /usr/local/src/nvi-1.79/include/ex_def.h ./include/ex_def.h
     *** /usr/local/src/nvi-1.79/include/ex_def.h	Wed Oct 23 22:53:09 1996
    ---- ./include/ex_def.h	Wed Apr 16 21:20:09 1997
    +--- ./include/ex_def.h	Fri Aug 14 01:41:14 1998
     ***************
     *** 47,78 ****
       #define C_RECOVER 46
    @@ -499,7 +509,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/include/ex_def.h ./include/ex_def.h
     ! #define C_SUBTILDE 78
     diff -c -r -N /usr/local/src/nvi-1.79/include/ex_extern.h ./include/ex_extern.h
     *** /usr/local/src/nvi-1.79/include/ex_extern.h	Wed Oct 23 22:53:10 1996
    ---- ./include/ex_extern.h	Wed Apr 16 21:20:09 1997
    +--- ./include/ex_extern.h	Fri Aug 14 01:41:14 1998
     ***************
     *** 89,94 ****
     --- 89,95 ----
    @@ -512,7 +522,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/include/ex_extern.h ./include/ex_extern.h
       int ex_tag_prev __P((SCR *, EXCMD *));
     diff -c -r -N /usr/local/src/nvi-1.79/include/options_def.h ./include/options_def.h
     *** /usr/local/src/nvi-1.79/include/options_def.h	Wed Oct 23 22:53:10 1996
    ---- ./include/options_def.h	Wed Apr 16 21:20:09 1997
    +--- ./include/options_def.h	Fri Aug 14 01:41:14 1998
     ***************
     *** 16,79 ****
       #define O_EXTENDED 15
    @@ -647,7 +657,7 @@ diff -c -r -N /usr/local/src/nvi-1.79/include/options_def.h ./include/options_de
     ! #define O_OPTIONCOUNT 79
     diff -c -r -N /usr/local/src/nvi-1.79/vi/v_ex.c ./vi/v_ex.c
     *** /usr/local/src/nvi-1.79/vi/v_ex.c	Mon Sep 16 05:03:02 1996
    ---- ./vi/v_ex.c	Wed Apr 16 21:20:09 1997
    +--- ./vi/v_ex.c	Fri Aug 14 01:41:14 1998
     ***************
     *** 226,231 ****
     --- 226,236 ----
    diff --git a/contrib/global/systags/systags.sh b/contrib/global/systags/systags.sh
    index 09fa205a57b7..97f43e2665fb 100755
    --- a/contrib/global/systags/systags.sh
    +++ b/contrib/global/systags/systags.sh
    @@ -1,6 +1,6 @@
     #!/bin/sh
     #
    -# Copyright (c) 1997 Shigio Yamaguchi. All rights reserved.
    +# Copyright (c) 1997, 1998 Shigio Yamaguchi. All rights reserved.
     #
     # Redistribution and use in source and binary forms, with or without
     # modification, are permitted provided that the following conditions
    @@ -29,59 +29,219 @@
     # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     # SUCH DAMAGE.
     #
    -#       systags.sh               7-Jul-97
    +#       systags.sh				17-Aug-98
     #
     # script to make hypertext of kernel source.
    -# supporting FreeBSD and Linux.
    +# support OS: FreeBSD, NetBSD, OpenBSD, Linux, GNUmach, GNUhurd
     #
    -case $1 in
    --n)	nflag=1; shift;;
    -esac
    +while case $1 in
    +	-*)
    +		if grep '[^-cfgn]' </dev/null 2>&1; then
    +$1
    +!
    +			echo "usage: systags [-c][-f][-g][-n][dir]"
    +			exit 1
    +		fi
    +		case $1 in
    +		*c*)	cflag=c;;
    +		esac
    +		case $1 in
    +		*f*)	fflag=f;;
    +		esac
    +		case $1 in
    +		*g*)	gflag=g;;
    +		esac
    +		case $1 in
    +		*n*)	nflag=n;;
    +		esac
    +		;;
    +	*)	false;;
    +	esac
    +do
    +	shift
    +done
     case $1 in
     "")	dir=.;;
     *)	dir=$1;;
     esac
    +if [ ! -d $dir -o ! -w $dir ]; then
    +	echo "systags: '$dir' is not a directory or not writable."
    +	exit 1
    +fi
    +tmpdir=$dir/systags_tmpdir_$$
     #
     # get release number from source tree.
     #
     if [ -f conf/newvers.sh ]; then
    -	os=FreeBSD
    -	release=`awk -F= '/^RELEASE=/ {print $2}' < conf/newvers.sh`
    +	# (Free|Net|Open)BSD?
    +	if ! mkdir $tmpdir 2>/dev/null; then
    +		echo "systags: '$dir' is not writable."
    +		exit 1
    +	fi
    +	cwd=`pwd`
    +	(cd $tmpdir; sh $cwd/conf/newvers.sh)
    +	os=`awk -F\" '/char[ \t]+ostype\[\][ \t]*=[ \t]*\"[^"]+\"/ {print $2}' < $tmpdir/vers.c`;
    +	release=`awk -F\" '/char[ \t]+osrelease\[\][ \t]*=[ \t]*\"[^"]+\"/ {print $2}' < $tmpdir/vers.c`;
    +	rm -rf $tmpdir
     elif [ -f Makefile ] && grep '^vmlinux:' Makefile >/dev/null; then
    +	# Linux?
     	os=Linux
     	version=`awk -F= '/^VERSION *=/ {print $2}' < Makefile`
     	patchlevel=`awk -F= '/^PATCHLEVEL *=/ {print $2}' < Makefile`
     	sublevel=`awk -F= '/^SUBLEVEL *=/ {print $2}' < Makefile`
     	release=`echo "$version.$patchlevel.$sublevel" | tr -d ' '`
    +elif [ -f version.c ]; then
    +	# GNU mach?
    +	version=`awk -F\" '/char[ \t]+version\[\][ \t]*=[ \t]*\"[^"]+\"/ {print $2}' < version.c`
    +	os=`echo $version | awk '{print $1}'` 
    +	release=`echo $version | awk '{print $2}'` 
    +elif [ -f version.h ]; then
    +	# GNU hurd?
    +	release=`awk -F\" '/^#define[ \t]+HURD_VERSION[ \t]+"[^"]+\"/ {print $2}' < version.h`
    +	if [ ${release}X != X ]; then
    +		os=GNUhurd
    +	fi
     fi
     #
     # remove old files
     #
    +files=
    +for f in htags.log gtags.log GTAGS GRTAGS GSYMS GPATH HTML; do
    +	files="$files $dir/$f";
    +done
    +com="rm -rf $files"
     case $nflag in
    -1)	echo "rm -rf $dir/htags.log $dir/gtags.log $dir/GTAGS $dir/GRTAGS $dir/GSYMS $dir/HTML";;
    -*)	rm -rf $dir/htags.log $dir/gtags.log $dir/GTAGS $dir/GRTAGS $dir/GSYMS $dir/HTML;;
    +n)	echo $com;;
    +*)	eval $com;;
     esac
     #
    -# make global database(GTAGS, GRTAGS, GSYMS).
    +# FreeBSD System macros.
     #
    +#	These macros with argument are used out of function.
    +#	gctags(1) knows these are not function by '.notfunction' list.
    +#
    +# kernel.h	MAKE_SET,TEXT_SET,DATA_SET,BSS_SET,ABS_SET,
    +#		SYSINIT,SYSINIT_KT,SYSINIT_KP,PSEUDO_SET
    +# sysctl.h	SYSCTL_OID,SYSCTL_NODE,SYSCTL_STRING,SYSCTL_INT,SYSCTL_OPAQUE,
    +#		SYSCTL_STRUCT,SYSCTL_PROC
    +# domain.h	DOMAIN_SET
    +# mount.h	VFS_SET
    +# lkm.h		MOD_DECL,MOD_SYSCALL,MOD_VFS,MOD_DEV,MOD_EXEC,MOD_MISC
    +# vnode.h	VNODEOP_SET
    +# spl.h		GENSPL
    +# queue.h	SLIST_HEAD,SLIST_ENTRY,SLIST_INIT,SLIST_INSERT_AFTER,
    +#		SLIST_INSERT_HEAD,SLIST_REMOVE_HEAD,SLIST_REMOVE,STAILQ_HEAD,
    +#		STAILQ_ENTRY,STAILQ_INIT,STAILQ_INSERT_HEAD,STAILQ_INSERT_TAIL,
    +#		STAILQ_INSERT_AFTER,STAILQ_REMOVE_HEAD,STAILQ_REMOVE,
    +#		LIST_HEAD,LIST_ENTRY,LIST_INIT,LIST_INSERT_AFTER,LIST_INSERT_BEFORE,
    +#		LIST_INSERT_HEAD,LIST_REMOVE,TAILQ_HEAD,TAILQ_ENTRY,
    +#		TAILQ_EMPTY,TAILQ_FIRST,TAILQ_LAST,TAILQ_NEXT,TAILQ_PREV,
    +#		TAILQ_INIT,TAILQ_INSERT_HEAD,TAILQ_INSERT_TAIL,TAILQ_INSERT_AFTER,
    +#		TAILQ_INSERT_BEFORE,TAILQ_REMOVE,CIRCLEQ_HEAD,CIRCLEQ_ENTRY,
    +#		CIRCLEQ_INIT,CIRCLEQ_INSERT_AFTER,CIRCLEQ_INSERT_BEFORE,
    +#		CIRCLEQ_INSERT_HEAD,CIRCLEQ_INSERT_TAIL,CIRCLEQ_REMOVE
    +#
    +case $os in
    +FreeBSD)
    +	cat <<-! >.notfunction
    +	MAKE_SET
    +	TEXT_SET
    +	DATA_SET
    +	BSS_SET
    +	ABS_SET
    +	SYSINIT
    +	SYSINIT_KT
    +	SYSINIT_KP
    +	PSEUDO_SET
    +	SYSCTL_OID
    +	SYSCTL_NODE
    +	SYSCTL_STRING
    +	SYSCTL_INT
    +	SYSCTL_OPAQUE
    +	SYSCTL_STRUCT
    +	SYSCTL_PROC
    +	DOMAIN_SET
    +	VFS_SET
    +	MOD_DECL
    +	MOD_SYSCALL
    +	MOD_VFS
    +	MOD_DEV
    +	MOD_EXEC
    +	MOD_MISC
    +	VNODEOP_SET
    +	GENSPL
    +	SLIST_HEAD
    +	SLIST_ENTRY
    +	SLIST_INIT
    +	SLIST_INSERT_AFTER
    +	SLIST_INSERT_HEAD
    +	SLIST_REMOVE_HEAD
    +	SLIST_REMOVE
    +	STAILQ_HEAD
    +	STAILQ_ENTRY
    +	STAILQ_INIT
    +	STAILQ_INSERT_HEAD
    +	STAILQ_INSERT_TAIL
    +	STAILQ_INSERT_AFTER
    +	STAILQ_REMOVE_HEAD
    +	STAILQ_REMOVE
    +	LIST_HEAD
    +	LIST_ENTRY
    +	LIST_INIT
    +	LIST_INSERT_AFTER
    +	LIST_INSERT_BEFORE
    +	LIST_INSERT_HEAD
    +	LIST_REMOVE
    +	TAILQ_HEAD
    +	TAILQ_ENTRY
    +	TAILQ_EMPTY
    +	TAILQ_FIRST
    +	TAILQ_LAST
    +	TAILQ_NEXT
    +	TAILQ_PREV
    +	TAILQ_INIT
    +	TAILQ_INSERT_HEAD
    +	TAILQ_INSERT_TAIL
    +	TAILQ_INSERT_AFTER
    +	TAILQ_INSERT_BEFORE
    +	TAILQ_REMOVE
    +	CIRCLEQ_HEAD
    +	CIRCLEQ_ENTRY
    +	CIRCLEQ_INIT
    +	CIRCLEQ_INSERT_AFTER
    +	CIRCLEQ_INSERT_BEFORE
    +	CIRCLEQ_INSERT_HEAD
    +	CIRCLEQ_INSERT_TAIL
    +	CIRCLEQ_REMOVE
    +!
    +esac
    +#
    +# make global database(GTAGS, GRTAGS).
    +#
    +com="gtags -owv $dir > $dir/gtags.log 2>&1"
     case $nflag in
    -1)	echo "gtags -v $dir > $dir/gtags.log 2>&1";;
    -*)	gtags -v $dir > $dir/gtags.log 2>&1;;
    +n)	echo $com;;
    +*)	eval $com;;
     esac
     case $? in
     0)	;;
     *)	exit 1;;
     esac
    +case $gflag in
    +g)	exit 0;;
    +esac
     #
     # make hypertext.
     # (please replace this title with a suitable one.) 
     #
    -case $os$release in
    -"")	program=`/bin/pwd | sed 's/.*\///'`
    -	title="Welcome to $program source tour!";;
    -*)	title="Welcome to $os $release kernel source tour!";;
    -esac
    +if [ ${os}X != X -a ${release}X != X ]; then
    +	title="Welcome to $os $release kernel source tour!"
    +else
    +	program=`/bin/pwd | sed 's/.*\///'`
    +	title="Welcome to $program source tour!"
    +fi
    +com="htags -${cflag}${fflag}lhnvat '$title' -d $dir $dir > $dir/htags.log 2>&1"
     case $nflag in
    -1)	echo "htags -fnvat '$title' -d $dir $dir > $dir/htags.log 2>&1";;
    -*)	htags -fnvat "$title" -d $dir $dir> $dir/htags.log 2>&1;;
    +n)	echo $com;;
    +*)	eval $com;;
     esac