From a56c9e681886408305863ace84e8a13929ca1456 Mon Sep 17 00:00:00 2001
From: anon <anon@anon.anon>
Date: Thu, 27 Jul 2023 20:04:50 +0200
Subject: [PATCH] bk

---
 .gitignore       |    5 +
 Makefile         |   38 +
 README.md        |   12 +
 TODO             |    7 +
 ass/emacs.e      |   99 +++
 ass/gmacs.ml     |   63 ++
 ass/ylwrap       |  247 ++++++
 comp.sh          |    4 +
 obj/.placeholder |    0
 src/basename.c   |   46 ++
 src/build.c      |  738 +++++++++++++++++
 src/build.h      |   70 ++
 src/command.c    |  934 +++++++++++++++++++++
 src/compath.c    |  211 +++++
 src/constants.h  |  133 +++
 src/crossref.c   |  492 +++++++++++
 src/dir.c        |  747 +++++++++++++++++
 src/display.c    |  784 ++++++++++++++++++
 src/edit.c       |  137 ++++
 src/egrep.c      | 2053 ++++++++++++++++++++++++++++++++++++++++++++++
 src/egrep.h      |   98 +++
 src/egrep.y      |  663 +++++++++++++++
 src/exec.c       |  188 +++++
 src/find.c       | 1301 +++++++++++++++++++++++++++++
 src/fscanner.l   |  904 ++++++++++++++++++++
 src/global.h     |  321 ++++++++
 src/gscope.c     |    1 +
 src/help.c       |  209 +++++
 src/history.c    |  103 +++
 src/input.c      |  333 ++++++++
 src/invlib.c     | 1204 +++++++++++++++++++++++++++
 src/invlib.h     |  114 +++
 src/library.h    |   51 ++
 src/logdir.c     |  100 +++
 src/lookup.c     |  149 ++++
 src/lookup.h     |   45 +
 src/main.c       |  674 +++++++++++++++
 src/mouse.c      |  431 ++++++++++
 src/mygetenv.c   |   49 ++
 src/mypopen.c    |  208 +++++
 src/opt.c        |  159 ++++
 src/scanner.h    |   94 +++
 src/version.h    |   45 +
 src/vp.h         |   70 ++
 src/vpaccess.c   |   57 ++
 src/vpfopen.c    |   62 ++
 src/vpinit.c     |  169 ++++
 src/vpopen.c     |   60 ++
 48 files changed, 14682 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Makefile
 create mode 100644 README.md
 create mode 100644 TODO
 create mode 100644 ass/emacs.e
 create mode 100644 ass/gmacs.ml
 create mode 100755 ass/ylwrap
 create mode 100755 comp.sh
 create mode 100644 obj/.placeholder
 create mode 100644 src/basename.c
 create mode 100644 src/build.c
 create mode 100644 src/build.h
 create mode 100644 src/command.c
 create mode 100644 src/compath.c
 create mode 100644 src/constants.h
 create mode 100644 src/crossref.c
 create mode 100644 src/dir.c
 create mode 100644 src/display.c
 create mode 100644 src/edit.c
 create mode 100644 src/egrep.c
 create mode 100644 src/egrep.h
 create mode 100644 src/egrep.y
 create mode 100644 src/exec.c
 create mode 100644 src/find.c
 create mode 100644 src/fscanner.l
 create mode 100644 src/global.h
 create mode 100644 src/gscope.c
 create mode 100644 src/help.c
 create mode 100644 src/history.c
 create mode 100644 src/input.c
 create mode 100644 src/invlib.c
 create mode 100644 src/invlib.h
 create mode 100644 src/library.h
 create mode 100644 src/logdir.c
 create mode 100644 src/lookup.c
 create mode 100644 src/lookup.h
 create mode 100644 src/main.c
 create mode 100644 src/mouse.c
 create mode 100644 src/mygetenv.c
 create mode 100644 src/mypopen.c
 create mode 100644 src/opt.c
 create mode 100644 src/scanner.h
 create mode 100644 src/version.h
 create mode 100644 src/vp.h
 create mode 100644 src/vpaccess.c
 create mode 100644 src/vpfopen.c
 create mode 100644 src/vpinit.c
 create mode 100644 src/vpopen.c

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b650193
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+obj/*.o
+obj/*.gch
+csope
+**/*.out
+src/lex.yy.c
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b08b553
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
+CC=gcc
+CCFLAGS:=-ggdb #-D PRODUCTION
+LDLIBS=-I ${CHDRD} $$(pkg-config --libs ncurses)
+LEX:=flex
+
+LEXD:=src/
+LEXF:=$(shell find ${LEXD} -iname '*.l')
+GENLEX:=$(subst .l,.c,${LEXF}) 
+
+SRCD:=src/
+OBJD:=obj/
+SRC:=$(shell find ${SRCD} -iname '*.c') ${GENLEX}
+OBJ:=$(subst .c,.o,$(subst ${SRCD},${OBJD},${SRC}))
+
+HDRD:=${SRCD}
+CHDRD:=${OBJD}
+HDR:=$(shell find ${HDRD} -iname '*.h')
+CHDR:=$(addsuffix .gch,$(subst ${HDRD},${CHDRD},${HDR}))
+
+OUTPUT:=csope
+
+main: ${CHDR} ${OBJ}
+	${LINK.c} ${LDLIBS} ${OBJ} -o ${OUTPUT} 
+
+obj/%.o: src/%.c
+	${COMPILE.c} $< -o $@
+
+src/%.c: src/%.l
+	${LEX} -o $@ $<
+
+obj/%.h.gch: src/%.h
+	${CC} $< -o $@
+
+clean:
+	-rm ${CHDR}
+	-rm ${GENLEX}
+	-rm ${OBJ}
+	-rm ${OUTPUT}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0542b3b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,12 @@
+# Csope
+Fork of Cscope, with various improvements, because cscope is good and shall not be forgotten.
+
+# Improvements/Changes
+## User side
++ improved gui	/*pending*/
++ GNU Readline integration (ie. VI/EMACS mode, command history) /*pending*/
+## To the code
++ nuked autoconf, replaced with single Makefile
++ removed 
++ encapsulated changes to the TUI into display.c
++ removed macros hell put in place to allow compiling on a dead badger
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..ae2614f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,7 @@
+# BUGS
++ Changing text double frees:
+	free(): double free detected in tcache 2
+	Aborted
++ Normalize tabs and spaces
++ Ordering function declarations in global.h by alpha order is not smart
++ Handle unused parameters gracefully (#define UNUSED(x) (void)(x))
diff --git a/ass/emacs.e b/ass/emacs.e
new file mode 100644
index 0000000..ded6fbe
--- /dev/null
+++ b/ass/emacs.e
@@ -0,0 +1,99 @@
+/ ========================================================================= /
+/ Copyright (c) 1998-2000, The Santa Cruz Operation /
+/ All rights reserved./
+/ /
+/ Redistribution and use in source and binary forms, with or without/
+/ modification, are permitted provided that the following conditions are met:/
+//
+/ *Redistributions of source code must retain the above copyright notice,/
+/ this list of conditions and the following disclaimer./
+//
+/ *Redistributions in binary form must reproduce the above copyright notice,/
+/ this list of conditions and the following disclaimer in the documentation/
+/ and/or other materials provided with the distribution./
+//
+/ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. /
+/ ========================================================================= /
+
+/ emacs menu for cscope /
+((X) cscope (find current word [MACRO])
+	(extern symbol-character)
+
+	/ if this character is not part of a symbol /
+	(cond ((not symbol-character)
+		
+		/ if the previous character is not part of a symbol, go to
+		  the next word /
+		back
+		(cond ((not symbol-character) forward-word back-word))
+	))
+	/ get the current symbol (leave cursor at beginning of symbol) /
+	(while symbol-character forward)	/ go past last symbol character /
+	mark					/ mark this point /
+	back					/ back to last symbol character /
+	(while (cond (symbol-character (return back))))	/ back fails at BOF /
+	(cond ((not symbol-character) forward))		/ forward if not at BOF /
+	pickup-region				/ get the symbol /
+	(local-string symbol)
+	symbol=
+
+	/ if arg > 0 then display the menu /
+	(cond ((> arg 0) (display-menu
+		(format symbol "5  Find functions calling %l()")
+		(format symbol "4  Find functions called by %l()")
+		(format symbol "3  Find global definition of %l")
+		(format symbol "2  Find symbol %l")
+		"1  Call cscope"
+		5)
+	))
+	/ get the selection /
+	(local selection)
+	(selection= (read-character "Selection?"))
+
+	/ if the selection is in range /
+	(cond ((&& (>= selection '1') (<= selection '5'))
+	
+		/ if the selection requests finding the symbol /
+		(local-string findsymbol)
+		(findsymbol= "")
+		(cond ((>= selection '2')
+			(findsymbol= (format (char-to-string (- selection 2)) symbol "-%l '%l'"))))
+		
+		/ if arg > 1 or < 0 then don't update the cross-reference database /
+		(local-string doption)
+		(doption= "")
+		(cond ((|| (> arg 1) (< arg 0)) (doption= "-d")))
+		
+		/ call cscope with usilent mode off /
+		(local oldmode)				/ save old usilent mode /
+		(oldmode= (set-mode "usilent" 0))	/ turn off usilent mode /
+		(run-command (format doption findsymbol "cscope %l %l"))
+		(set-mode "usilent" oldmode)		/ restore usilent mode /
+	))
+)
+/ see if the current character is part of a symbol /
+(symbol-character ()
+	(local c)
+	(c= current-character)
+	(return (cond	((&& (>= c 'a') (<= c 'z')))
+			((&& (>= c 'A') (<= c 'Z')))
+			((&& (>= c '0') (<= c '9')))
+			((== c '_'))
+		)
+	)
+)
diff --git a/ass/gmacs.ml b/ass/gmacs.ml
new file mode 100644
index 0000000..ca4505a
--- /dev/null
+++ b/ass/gmacs.ml
@@ -0,0 +1,63 @@
+	; ===========================================================================
+	; Copyright (c) 1998-2000, The Santa Cruz Operation 
+	; All rights reserved.
+ 
+	; Redistribution and use in source and binary forms, with or without
+	; modification, are permitted provided that the following conditions are met:
+
+	; *Redistributions of source code must retain the above copyright notice,
+	; this list of conditions and the following disclaimer.
+
+	; *Redistributions in binary form must reproduce the above copyright notice,
+	; this list of conditions and the following disclaimer in the documentation
+	; and/or other materials provided with the distribution.
+
+	; *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+	; =========================================================================
+
+	; cscope.ml (s.cscope.ml) - 1.4 (2/21/84 14:53:58)
+	;
+	; Macro to handle invocation of gmacs by cscope from the
+	; experimental tools.  Cscope invokes gmacs with two arguments:
+	;
+	;	gmacs +line file
+	;
+	; This macro gobbles the line number, visits the specified file,
+	; and moves to the specified line number.
+
+(progn
+	args
+	pluses
+	(setq pluses 0)
+	(setq args (argc))
+	(if (> args 1)
+		(progn
+			(if (= (string-to-char "+") (string-to-char (argv 1)))
+				(setq pluses 1)
+			)
+			(setq args (- args 1))
+			(while (> args pluses)
+				(visit-file (argv args))
+				(setq args (- args 1))
+			)
+			(if (= (> (argc) 2) (> pluses 0))
+				(goto-line (argv 1))
+			)
+		)
+	)
+)
diff --git a/ass/ylwrap b/ass/ylwrap
new file mode 100755
index 0000000..d788f2d
--- /dev/null
+++ b/ass/ylwrap
@@ -0,0 +1,247 @@
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2016-01-11.22; # UTC
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+get_dirname ()
+{
+  case $1 in
+    */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';;
+    # Otherwise,  we want the empty string (not ".").
+  esac
+}
+
+# guard FILE
+# ----------
+# The CPP macro used to guard inclusion of FILE.
+guard ()
+{
+  printf '%s\n' "$1"                                                    \
+    | sed                                                               \
+        -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'   \
+        -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'                        \
+        -e 's/__*/_/g'
+}
+
+# quote_for_sed [STRING]
+# ----------------------
+# Return STRING (or stdin) quoted to be used as a sed pattern.
+quote_for_sed ()
+{
+  case $# in
+    0) cat;;
+    1) printf '%s\n' "$1";;
+  esac \
+    | sed -e 's|[][\\.*]|\\&|g'
+}
+
+case "$1" in
+  '')
+    echo "$0: No files given.  Try '$0 --help' for more information." 1>&2
+    exit 1
+    ;;
+  --basedir)
+    basedir=$2
+    shift 2
+    ;;
+  -h|--h*)
+    cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+  INPUT is the input file
+  OUTPUT is one file PROG generates
+  DESIRED is the file we actually want instead of OUTPUT
+  PROGRAM is program to run
+  ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v|--v*)
+    echo "ylwrap $scriptversion"
+    exit $?
+    ;;
+esac
+
+
+# The input.
+input=$1
+shift
+# We'll later need for a correct munging of "#line" directives.
+input_sub_rx=`get_dirname "$input" | quote_for_sed`
+case $input in
+  [\\/]* | ?:[\\/]*)
+    # Absolute path; do nothing.
+    ;;
+  *)
+    # Relative path.  Make it absolute.
+    input=`pwd`/$input
+    ;;
+esac
+input_rx=`get_dirname "$input" | quote_for_sed`
+
+# Since DOS filename conventions don't allow two dots,
+# the DOS version of Bison writes out y_tab.c instead of y.tab.c
+# and y_tab.h instead of y.tab.h. Test to see if this is the case.
+y_tab_nodot=false
+if test -f y_tab.c || test -f y_tab.h; then
+  y_tab_nodot=true
+fi
+
+# The parser itself, the first file, is the destination of the .y.c
+# rule in the Makefile.
+parser=$1
+
+# A sed program to s/FROM/TO/g for all the FROM/TO so that, for
+# instance, we rename #include "y.tab.h" into #include "parse.h"
+# during the conversion from y.tab.c to parse.c.
+sed_fix_filenames=
+
+# Also rename header guards, as Bison 2.7 for instance uses its header
+# guard in its implementation file.
+sed_fix_header_guards=
+
+while test $# -ne 0; do
+  if test x"$1" = x"--"; then
+    shift
+    break
+  fi
+  from=$1
+  # Handle y_tab.c and y_tab.h output by DOS
+  if $y_tab_nodot; then
+    case $from in
+      "y.tab.c") from=y_tab.c;;
+      "y.tab.h") from=y_tab.h;;
+    esac
+  fi
+  shift
+  to=$1
+  shift
+  sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;"
+  sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;"
+done
+
+# The program to run.
+prog=$1
+shift
+# Make any relative path in $prog absolute.
+case $prog in
+  [\\/]* | ?:[\\/]*) ;;
+  *[\\/]*) prog=`pwd`/$prog ;;
+esac
+
+dirname=ylwrap$$
+do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
+trap "ret=129; $do_exit" 1
+trap "ret=130; $do_exit" 2
+trap "ret=141; $do_exit" 13
+trap "ret=143; $do_exit" 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+  0) "$prog" "$input" ;;
+  *) "$prog" "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+  for from in *
+  do
+    to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"`
+    if test -f "$from"; then
+      # If $2 is an absolute path name, then just use that,
+      # otherwise prepend '../'.
+      case $to in
+        [\\/]* | ?:[\\/]*) target=$to;;
+        *) target=../$to;;
+      esac
+
+      # Do not overwrite unchanged header files to avoid useless
+      # recompilations.  Always update the parser itself: it is the
+      # destination of the .y.c rule in the Makefile.  Divert the
+      # output of all other files to a temporary file so we can
+      # compare them to existing versions.
+      if test $from != $parser; then
+        realtarget=$target
+        target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'`
+      fi
+
+      # Munge "#line" or "#" directives.  Don't let the resulting
+      # debug information point at an absolute srcdir.  Use the real
+      # output file name, not yy.lex.c for instance.  Adjust the
+      # include guards too.
+      sed -e "/^#/!b"                           \
+          -e "s|$input_rx|$input_sub_rx|"       \
+          -e "$sed_fix_filenames"               \
+          -e "$sed_fix_header_guards"           \
+        "$from" >"$target" || ret=$?
+
+      # Check whether files must be updated.
+      if test "$from" != "$parser"; then
+        if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+          echo "$to is unchanged"
+          rm -f "$target"
+        else
+          echo "updating $to"
+          mv -f "$target" "$realtarget"
+        fi
+      fi
+    else
+      # A missing file is only an error for the parser.  This is a
+      # blatant hack to let us support using "yacc -d".  If -d is not
+      # specified, don't fail when the header file is "missing".
+      if test "$from" = "$parser"; then
+        ret=1
+      fi
+    fi
+  done
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/comp.sh b/comp.sh
new file mode 100755
index 0000000..869038d
--- /dev/null
+++ b/comp.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+make clean
+make
diff --git a/obj/.placeholder b/obj/.placeholder
new file mode 100644
index 0000000..e69de29
diff --git a/src/basename.c b/src/basename.c
new file mode 100644
index 0000000..94d8ffd
--- /dev/null
+++ b/src/basename.c
@@ -0,0 +1,46 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/* get a file's base name from its path name */
+
+#include "global.h"
+
+char *
+basename(char *path)
+{
+	char	*s;
+	
+	if ((s = strrchr(path, '/')) != 0) {
+		return(s + 1);
+	}
+	return(path);
+}
diff --git a/src/build.c b/src/build.c
new file mode 100644
index 0000000..0ff5049
--- /dev/null
+++ b/src/build.c
@@ -0,0 +1,738 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	main functions
+ */
+
+#include "build.h"
+
+#include "global.h"		/* FIXME: get rid of this! */
+
+#include "library.h"
+
+#include "scanner.h"
+#include "version.h"		/* for FILEVERSION */
+#include "vp.h"
+
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+/* Exported variables: */
+
+BOOL	buildonly = NO;		/* only build the database */
+BOOL	unconditional = NO;	/* unconditionally build database */
+BOOL	fileschanged;		/* assume some files changed */
+
+/* variable copies of the master strings... */
+char	invname_buf[] = INVNAME;
+char	invpost_buf[] = INVPOST;
+char	reffile_buf[] = REFFILE;
+char	*invname = invname_buf;	/* inverted index to the database */
+char	*invpost = invpost_buf;	/* inverted index postings */
+char	*reffile = reffile_buf;	/* cross-reference file path name */
+
+char	*newreffile;		/* new cross-reference file name */
+FILE	*newrefs;		/* new cross-reference */
+FILE	*postings;		/* new inverted index postings */
+int	symrefs = -1;		/* cross-reference file */
+
+INVCONTROL invcontrol;		/* inverted file control structure */
+
+
+/* Local variables: */
+static char *newinvname;	/* new inverted index file name */
+static char *newinvpost;	/* new inverted index postings file name */
+static long traileroffset;	/* file trailer offset */
+
+
+/* Internal prototypes: */
+static	void	cannotindex(void);
+static	int	compare(const void *s1, const void *s2);
+static	void	copydata(void);
+static	void	copyinverted(void);
+static	char	*getoldfile(void);
+static	void	movefile(char *new, char *old);
+static	void	putheader(char *dir);
+static	void	fetch_include_from_dbase(char *, size_t);
+static	void	putlist(char **names, int count);
+static	BOOL	samelist(FILE *oldrefs, char **names, int count);
+
+
+/* Error handling routine if inverted index creation fails */
+static void
+cannotindex(void)
+{
+    fprintf(stderr, "\
+cscope: cannot create inverted index; ignoring -q option\n");
+    invertedindex = NO;
+    errorsfound = YES;
+    fprintf(stderr, "\
+cscope: removed files %s and %s\n", 
+	    newinvname, newinvpost);
+    unlink(newinvname);
+    unlink(newinvpost);
+}
+
+
+/* see if the name list is the same in the cross-reference file */
+static BOOL
+samelist(FILE *oldrefs, char **names, int count)
+{
+    char    oldname[PATHLEN + 1];   /* name in old cross-reference */
+    int     oldcount;
+    int     i;
+
+    /* see if the number of names is the same */
+    if (fscanf(oldrefs, "%d", &oldcount) != 1 ||
+	oldcount != count) {
+	return(NO);
+    }
+    /* see if the name list is the same */
+    for (i = 0; i < count; ++i) {
+	if ((1 != fscanf(oldrefs," %[^\n]",oldname)) ||
+	    strnotequal(oldname, names[i])) {
+	    return(NO);
+	}
+    }
+    return(YES);
+}
+
+
+/* create the file name(s) used for a new cross-referene */
+
+void setup_build_filenames(char *reffile)
+{
+    char *path;			/* file pathname */
+    char *s;			/* pointer to basename in path */
+
+    path = malloc(strlen(reffile) + 10u);
+    strcpy(path, reffile);
+    s = basename(path);
+    *s = '\0';
+    strcat(path, "n");
+    ++s;
+    strcpy(s, basename(reffile));
+    newreffile = strdup(path);
+    strcpy(s, basename(invname));
+    newinvname = strdup(path);
+    strcpy(s, basename(invpost));
+    newinvpost = strdup(path);
+    free(path);
+}
+
+/* open the database */
+
+void
+opendatabase(void)
+{
+    if ((symrefs = vpopen(reffile, O_BINARY | O_RDONLY)) == -1) {
+	cannotopen(reffile);
+	myexit(1);
+    }
+    blocknumber = -1;	/* force next seek to read the first block */
+	
+    /* open any inverted index */
+    if (invertedindex == YES &&
+	invopen(&invcontrol, invname, invpost, INVAVAIL) == -1) {
+	askforreturn();		/* so user sees message */
+	invertedindex = NO;
+    }
+}
+
+
+/* rebuild the database */
+void
+rebuild(void)
+{
+    close(symrefs);
+    if (invertedindex == YES) {
+	invclose(&invcontrol);
+	nsrcoffset = 0;
+	npostings = 0;
+    }
+    build();
+    opendatabase();
+
+    /* revert to the initial display */
+    if (refsfound != NULL) {
+	fclose(refsfound);
+	refsfound = NULL;
+    }
+}
+
+
+/* build the cross-reference */
+void
+build(void)
+{
+    unsigned long i;
+    FILE    *oldrefs;		/* old cross-reference file */
+    time_t  reftime;		/* old crossref modification time */
+    char    *file;		/* current file */
+    char    *oldfile;		/* file in old cross-reference */
+    char    newdir[PATHLEN + 1]; /* directory in new cross-reference */
+    char    olddir[PATHLEN + 1]; /* directory in old cross-reference */
+    char    oldname[PATHLEN + 1]; /* name in old cross-reference */
+    unsigned long oldnum;	/* number in old cross-ref */
+    struct  stat statstruct;	/* file status */
+    unsigned long firstfile;	/* first source file in pass */
+    unsigned long lastfile;	/* last source file in pass */
+    int     built = 0;		/* built crossref for these files */
+    int     copied = 0;		/* copied crossref for these files */
+    unsigned long fileindex;		/* source file name index */
+    BOOL    interactive = YES;	/* output progress messages */
+
+    /* normalize the current directory relative to the home directory so
+       the cross-reference is not rebuilt when the user's login is moved */
+    strcpy(newdir, currentdir);
+    if (strcmp(currentdir, home) == 0) {
+	strcpy(newdir, "$HOME");
+    } else if (strncmp(currentdir, home, strlen(home)) == 0) {
+	snprintf(newdir, sizeof(newdir), "$HOME%s", currentdir + strlen(home));
+    }
+    /* sort the source file names (needed for rebuilding) */
+    qsort(srcfiles, nsrcfiles, sizeof(*srcfiles), compare);
+
+    /* if there is an old cross-reference and its current directory matches */
+    /* or this is an unconditional build */
+    if ((oldrefs = vpfopen(reffile, "rb")) != NULL
+	&& unconditional == NO
+	&& fscanf(oldrefs, "cscope %d %" PATHLEN_STR "s", &fileversion, olddir) == 2 
+	&& (strcmp(olddir, currentdir) == 0 /* remain compatible */
+	    || strcmp(olddir, newdir) == 0)) {
+	/* get the cross-reference file's modification time */
+	fstat(fileno(oldrefs), &statstruct);
+	reftime = statstruct.st_mtime;
+	if (fileversion >= 8) {
+	    BOOL	oldcompress = YES;
+	    BOOL	oldinvertedindex = NO;
+	    BOOL	oldtruncate = NO;
+	    int	c;
+
+	    /* see if there are options in the database */
+	    for (;;) {
+		while((c = getc(oldrefs)) == ' ')
+		    ; 		/* do nothing */
+		if (c != '-') {
+		    ungetc(c, oldrefs);
+		    break;
+		}
+		switch (getc(oldrefs)) {
+		case 'c':	/* ASCII characters only */
+		    oldcompress = NO;
+		    break;
+		case 'q':	/* quick search */
+		    oldinvertedindex = YES;
+		    fscanf(oldrefs, "%ld", &totalterms);
+		    break;
+		case 'T':	/* truncate symbols to 8 characters */
+		    oldtruncate = YES;
+		    break;
+		}
+	    }
+	    /* check the old and new option settings */
+	    if (oldcompress != compress || oldtruncate != trun_syms) {
+		posterr("\
+cscope: -c or -T option mismatch between command line and old symbol database\n");
+		goto force;
+	    }
+	    if (oldinvertedindex != invertedindex) {
+		posterr("\
+cscope: -q option mismatch between command line and old symbol database\n");
+		if (invertedindex == NO) {
+		    posterr("cscope: removed files %s and %s\n",
+			    invname, invpost);
+		    unlink(invname);
+		    unlink(invpost);
+		}
+		goto outofdate;
+	    }
+	    /* seek to the trailer */
+	    if (fscanf(oldrefs, "%ld", &traileroffset) != 1 ||
+		fseek(oldrefs, traileroffset, SEEK_SET) == -1) {
+		posterr("cscope: incorrect symbol database file format\n");
+		goto force;
+	    }
+	}
+	/* if assuming that some files have changed */
+	if (fileschanged == YES) {
+	    goto outofdate;
+	}
+	/* see if the directory lists are the same */
+	if (samelist(oldrefs, srcdirs, nsrcdirs) == NO 
+	    || samelist(oldrefs, incdirs, nincdirs) == NO 
+	    /* get the old number of files */
+	    || fscanf(oldrefs, "%lu", &oldnum) != 1 
+	    /* skip the string space size */
+	    || (fileversion >= 9 && fscanf(oldrefs, "%*s") != 0)) {
+	    goto outofdate;
+	}
+	/* see if the list of source files is the same and
+	   none have been changed up to the included files */
+	for (i = 0; i < nsrcfiles; ++i) {
+	    if ((1 != fscanf(oldrefs," %[^\n]",oldname))
+		|| strnotequal(oldname, srcfiles[i])
+		|| (lstat(srcfiles[i], &statstruct) != 0)
+		|| (statstruct.st_mtime > reftime)
+		) {
+		goto outofdate;
+	    }
+	}
+	/* the old cross-reference is up-to-date */
+	/* so get the list of included files */
+	while (i++ < oldnum && fgets(oldname, sizeof(oldname), oldrefs)) {
+	    addsrcfile(oldname);
+	}
+	fclose(oldrefs);
+	return;
+		
+    outofdate:
+	/* if the database format has changed, rebuild it all */
+	if (fileversion != FILEVERSION) {
+	    fprintf(stderr, "\
+cscope: converting to new symbol database file format\n");
+	    goto force;
+	}
+	/* reopen the old cross-reference file for fast scanning */
+	if ((symrefs = vpopen(reffile, O_BINARY | O_RDONLY)) == -1) {
+	    postfatal("cscope: cannot open file %s\n", reffile);
+	    /* NOTREACHED */
+	}
+	/* get the first file name in the old cross-reference */
+	blocknumber = -1;
+	read_block();	/* read the first cross-ref block */
+	scanpast('\t');	/* skip the header */
+	oldfile = getoldfile();
+    } else {	/* force cross-referencing of all the source files */
+    force:	
+	reftime = 0;
+	oldfile = NULL;
+    }
+    /* open the new cross-reference file */
+    if ((newrefs = myfopen(newreffile, "wb")) == NULL) {
+	postfatal("cscope: cannot open file %s\n", reffile);
+	/* NOTREACHED */
+    }
+    if (invertedindex == YES && (postings = myfopen(temp1, "wb")) == NULL) {
+	cannotwrite(temp1);
+	cannotindex();
+    }
+    putheader(newdir);
+    fileversion = FILEVERSION;
+    if (buildonly == YES && verbosemode != YES && !isatty(0)) {
+	interactive = NO;
+    } else {
+	searchcount = 0;
+    }
+    /* output the leading tab expected by crossref() */
+    dbputc('\t');
+
+    /* make passes through the source file list until the last level of
+       included files is processed */
+    firstfile = 0;
+    lastfile = nsrcfiles;
+    if (invertedindex == YES) {
+	srcoffset = malloc((nsrcfiles + 1u) * sizeof(*srcoffset));
+    }
+    for (;;) {
+	progress("Building symbol database", (long)built,
+		 (long)lastfile);
+	if (linemode == NO)
+	    refresh();
+
+	/* get the next source file name */
+	for (fileindex = firstfile; fileindex < lastfile; ++fileindex) {
+			
+	    /* display the progress about every three seconds */
+	    if (interactive == YES && fileindex % 10 == 0) {
+		progress("Building symbol database", fileindex, lastfile);
+	    }
+	    /* if the old file has been deleted get the next one */
+	    file = srcfiles[fileindex];
+	    while (oldfile != NULL && strcmp(file, oldfile) > 0) {
+		oldfile = getoldfile();
+	    }
+	    /* if there isn't an old database or this is a new file */
+	    if (oldfile == NULL || strcmp(file, oldfile) < 0) {
+		crossref(file);
+		++built;
+	    } else if (lstat(file, &statstruct) == 0
+		       && statstruct.st_mtime > reftime) {
+		/* if this file was modified */
+		crossref(file);
+		++built;
+				
+		/* skip its old crossref so modifying the last source
+		 * file does not cause all included files to be built.
+		 * Unfortunately a new file that is alphabetically
+		 * last will cause all included files to be build, but
+		 * this is less likely */
+		oldfile = getoldfile();
+	    } else {	
+		/* copy its cross-reference */
+		putfilename(file);
+		if (invertedindex == YES) {
+		    copyinverted();
+		} else {
+		    copydata();
+		}
+		++copied;
+		oldfile = getoldfile();
+	    }
+	}
+	/* see if any included files were found */
+	if (lastfile == nsrcfiles) {
+	    break;
+	}
+	firstfile = lastfile;
+	lastfile = nsrcfiles;
+	if (invertedindex == YES) {
+	    srcoffset = realloc(srcoffset, (nsrcfiles + 1) * sizeof(*srcoffset));
+	}
+	/* sort the included file names */
+	qsort(srcfiles + firstfile, lastfile - firstfile, sizeof(*srcfiles), compare);
+    }
+    /* add a null file name to the trailing tab */
+    putfilename("");
+    dbputc('\n');
+	
+    /* get the file trailer offset */
+    traileroffset = dboffset;
+	
+    /* output the source and include directory and file lists */
+    putlist(srcdirs, nsrcdirs);
+    putlist(incdirs, nincdirs);
+    putlist(srcfiles, nsrcfiles);
+    if (fflush(newrefs) == EOF) {
+	/* rewind doesn't check for write failure */
+	cannotwrite(newreffile);
+	/* NOTREACHED */
+    }
+
+    /* create the inverted index if requested */
+    if (invertedindex == YES) {
+	char	sortcommand[PATHLEN + 1];
+
+	if (fflush(postings) == EOF) {
+	    cannotwrite(temp1);
+	    /* NOTREACHED */
+	}
+	fstat(fileno(postings), &statstruct);
+	fclose(postings);
+	snprintf(sortcommand, sizeof(sortcommand), "env LC_ALL=C sort -T %s %s", tmpdir, temp1);
+	if ((postings = mypopen(sortcommand, "r")) == NULL) {
+	    fprintf(stderr, "cscope: cannot open pipe to sort command\n");
+	    cannotindex();
+	} else {
+	    if ((totalterms = invmake(newinvname, newinvpost, postings)) > 0) {
+		movefile(newinvname, invname);
+		movefile(newinvpost, invpost);
+	    } else {
+		cannotindex();
+	    }
+	    mypclose(postings);
+	}
+	unlink(temp1);
+	free(srcoffset);
+    }
+    /* rewrite the header with the trailer offset and final option list */
+    rewind(newrefs);
+    putheader(newdir);
+    fclose(newrefs);
+	
+    /* close the old database file */
+    if (symrefs >= 0) {
+	close(symrefs);
+    }
+    if (oldrefs != NULL) {
+	fclose(oldrefs);
+    }
+    /* replace it with the new database file */
+    movefile(newreffile, reffile);
+}
+	
+
+/* string comparison function for qsort */
+static int
+compare(const void *arg_s1, const void *arg_s2)
+{
+    const char **s1 = (const char **) arg_s1;
+    const char **s2 = (const char **) arg_s2;
+			
+    return(strcmp(*s1, *s2));
+}
+
+
+/* seek to the trailer, in a given file */
+void 
+seek_to_trailer(FILE *f) 
+{
+    if (fscanf(f, "%ld", &traileroffset) != 1) {
+	postfatal("cscope: cannot read trailer offset from file %s\n", reffile);
+	/* NOTREACHED */
+    }
+    if (fseek(f, traileroffset, SEEK_SET) == -1) {
+	postfatal("cscope: cannot seek to trailer in file %s\n", reffile);
+	/* NOTREACHED */
+    }
+}
+
+
+/* get the next file name in the old cross-reference */
+static char *
+getoldfile(void)
+{
+    static char	file[PATHLEN + 1];	/* file name in old crossref */
+
+    if (blockp != NULL) {
+	do {
+	    if (*blockp == NEWFILE) {
+		skiprefchar();
+		fetch_string_from_dbase(file, sizeof(file));
+		if (file[0] != '\0') {	/* if not end-of-crossref */
+		    return(file);
+		}
+		return(NULL);
+	    }
+	} while (scanpast('\t') != NULL);
+    }
+    return(NULL);
+}
+
+
+/* Free all storage allocated for filenames: */
+void free_newbuildfiles(void)
+{
+    free(newinvname);
+    free(newinvpost);
+    free(newreffile);
+}	
+
+
+/* output the cscope version, current directory, database format options, and
+   the database trailer offset */
+static void
+putheader(char *dir)
+{
+    dboffset = fprintf(newrefs, "cscope %d %s", FILEVERSION, dir);
+    if (compress == NO) {
+	dboffset += fprintf(newrefs, " -c");
+    }
+    if (invertedindex == YES) {
+	dboffset += fprintf(newrefs, " -q %.10ld", totalterms);
+    } else {	
+	/* leave space so if the header is overwritten without -q
+	 * because writing the inverted index failed, the header
+	 * is the same length */
+	dboffset += fprintf(newrefs, "              ");
+    }
+    if (trun_syms == YES) {
+	dboffset += fprintf(newrefs, " -T");
+    }
+
+    dboffset += fprintf(newrefs, " %.10ld\n", traileroffset);
+#ifdef PRINTF_RETVAL_BROKEN
+    dboffset = ftell(newrefs); 
+#endif
+}
+
+
+/* put the name list into the cross-reference file */
+static void
+putlist(char **names, int count)
+{
+    int	i, size = 0;
+	
+    fprintf(newrefs, "%d\n", count);
+    if (names == srcfiles) {
+
+	/* calculate the string space needed */
+	for (i = 0; i < count; ++i) {
+	    size += strlen(names[i]) + 1;
+	}
+	fprintf(newrefs, "%d\n", size);
+    }
+    for (i = 0; i < count; ++i) {
+	if (fputs(names[i], newrefs) == EOF ||
+	    putc('\n', newrefs) == EOF) {
+	    cannotwrite(newreffile);
+	    /* NOTREACHED */
+	}
+    }
+}
+
+
+/* copy this file's symbol data */
+static void
+copydata(void)
+{
+    char *cp;
+
+    setmark('\t');
+    cp = blockp;
+    for (;;) {
+	/* copy up to the next \t */
+	do {	/* innermost loop optimized to only one test */
+	    while (*cp != '\t') {
+		dbputc(*cp++);
+	    }
+	} while (*++cp == '\0' && (cp = read_block()) != NULL);
+	dbputc('\t');	/* copy the tab */
+		
+	/* get the next character */
+	/* HBB 2010-08-21: potential problem if above loop was left
+	 * with cp==NULL */
+	if (cp && (*(cp + 1) == '\0')) {
+	    cp = read_block();
+	}
+	/* exit if at the end of this file's data */
+	if (cp == NULL || *cp == NEWFILE) {
+	    break;
+	}
+	/* look for an #included file */
+	if (*cp == INCLUDE) {
+            char symbol[PATLEN + 1];
+	    blockp = cp;
+	    fetch_include_from_dbase(symbol, sizeof(symbol));
+	    writestring(symbol);
+	    setmark('\t');
+	    cp = blockp;
+	}
+    }
+    blockp = cp;
+}
+
+/* copy this file's symbol data and output the inverted index postings */
+
+static void
+copyinverted(void)
+{
+    char    *cp;
+    char    c;
+    int     type;   /* reference type (mark character) */
+    char    symbol[PATLEN + 1];
+
+    /* note: this code was expanded in-line for speed */
+    /* while (scanpast('\n') != NULL) { */
+    /* other macros were replaced by code using cp instead of blockp */
+    cp = blockp;
+    for (;;) {
+	setmark('\n');
+	do {	/* innermost loop optimized to only one test */
+	    while (*cp != '\n') {
+		dbputc(*cp++);
+	    }
+	} while (*++cp == '\0' && (cp = read_block()) != NULL);
+	dbputc('\n');	/* copy the newline */
+		
+	/* get the next character */
+	/* HBB 2010-08-21: potential problem if above loop was left
+	 * with cp==NULL */
+	if (cp && (*(cp + 1) == '\0')) {
+	    cp = read_block();
+	}
+	/* exit if at the end of this file's data */
+	if (cp == NULL) {
+	    break;
+	}
+	switch (*cp) {
+	case '\n':
+	    lineoffset = dboffset + 1;
+	    continue;
+	case '\t':
+	    dbputc('\t');
+	    blockp = cp;
+	    type = getrefchar();
+	    switch (type) {
+	    case NEWFILE:		/* file name */
+		return;
+	    case INCLUDE:		/* #included file */
+		fetch_include_from_dbase(symbol, sizeof(symbol));
+		goto output;
+	    }
+	    dbputc(type);
+	    skiprefchar();
+	    fetch_string_from_dbase(symbol, sizeof(symbol));
+	    goto output;
+	}
+	c = *cp;
+	if (c & 0200) {	/* digraph char? */
+	    c = dichar1[(c & 0177) / 8];
+	}
+	/* if this is a symbol */
+	if (isalpha((unsigned char)c) || c == '_') {
+	    blockp = cp;
+	    fetch_string_from_dbase(symbol, sizeof(symbol));
+	    type = ' ';
+	output:
+	    putposting(symbol, type);
+	    writestring(symbol);
+	    if (blockp == NULL) {
+		return;
+	    }
+	    cp = blockp;
+	}
+    }
+    blockp = cp;
+}
+
+
+/* replace the old file with the new file */
+static void
+movefile(char *new, char *old)
+{
+    unlink(old);
+    if (rename(new, old) == -1) {
+	myperror("cscope");
+	postfatal("cscope: cannot rename file %s to file %s\n",
+		  new, old);
+	/* NOTREACHED */
+    }
+}
+
+
+/* process the #included file in the old database */
+static void
+fetch_include_from_dbase(char *s, size_t length)
+{
+    dbputc(INCLUDE);
+    skiprefchar();
+    fetch_string_from_dbase(s, length);
+    incfile(s + 1, s);
+}
+
diff --git a/src/build.h b/src/build.h
new file mode 100644
index 0000000..83c9c7b
--- /dev/null
+++ b/src/build.h
@@ -0,0 +1,70 @@
+/*===========================================================================
+ Copyright (c) 2001, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE. 
+ =========================================================================*/
+
+#ifndef CSCOPE_BUILD_H
+#define CSCOPE_BUILD_H
+
+#include "global.h"		/* FIXME: temp. only */
+#include "invlib.h"
+
+/* types and macros of build.c to be used by other modules */
+
+/* database output macros that update its offset */
+#define	dbputc(c)	(++dboffset, (void) putc(c, newrefs))
+#define	dbfputs(s)	(dboffset += strlen(s), fputs(s, newrefs))
+
+/* declarations for globals defined in build.c */
+
+extern	BOOL	buildonly;	/* only build the database */
+extern	BOOL	unconditional;	/* unconditionally build database */
+extern	BOOL	fileschanged;	/* assume some files changed */
+
+extern	char	*reffile;	/* cross-reference file path name */
+extern	char	*invname; 	/* inverted index to the database */
+extern	char	*invpost;	/* inverted index postings */
+extern	char	*newreffile;	/* new cross-reference file name */
+extern	FILE	*newrefs;	/* new cross-reference */
+extern	FILE	*postings;	/* new inverted index postings */
+extern	int	symrefs;	/* cross-reference file */
+
+extern	INVCONTROL invcontrol;	/* inverted file control structure */
+
+/* Prototypes of external functions defined by build.c */
+
+void	build(void);
+void	free_newbuildfiles(void);
+void	opendatabase(void);
+void	rebuild(void);
+void	setup_build_filenames(char *reffile);
+void 	seek_to_trailer(FILE *f);
+
+#endif /* CSCOPE_BUILD_H */
diff --git a/src/command.c b/src/command.c
new file mode 100644
index 0000000..920c36e
--- /dev/null
+++ b/src/command.c
@@ -0,0 +1,934 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol or text cross-reference
+ *
+ *	command functions
+ */
+
+#include "global.h"
+#include "build.h"		/* for rebuild() */
+
+
+#include <stdlib.h>
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+#include <ctype.h>
+
+int	selecting;			/* whether the (upper) symbol list is being browsed */
+unsigned int   curdispline = 0;
+
+BOOL	caseless;		/* ignore letter case when searching */
+BOOL	*change;		/* change this line */
+BOOL	changing;		/* changing text */
+char	newpat[PATLEN + 1];	/* new pattern */
+/* HBB 20040430: renamed to avoid lots of clashes with function arguments
+ * also named 'pattern' */
+char	Pattern[PATLEN + 1];	/* symbol or text pattern */
+
+/* HBB FIXME 20060419: these should almost certainly be const */
+static	char	appendprompt[] = "Append to file: ";
+static	char	pipeprompt[] = "Pipe to shell command: ";
+static	char	readprompt[] = "Read from file: ";
+static	char	toprompt[] = "To: ";
+
+
+/* Internal prototypes: */
+static	BOOL	changestring(void);
+static	void	clearprompt(void);
+static	void	mark(unsigned int i);
+static	void	scrollbar(MOUSE *p);
+
+
+/* execute the command */
+BOOL
+command(int commandc)
+{
+    char filename[PATHLEN + 1];	/* file path name */
+    MOUSE *p;			/* mouse data */
+    int	c, i;
+    FILE *file;
+    struct cmd *curritem, *item;	/* command history */
+    char *s;
+
+    switch (commandc) {
+    case ctrl('C'):	/* toggle caseless mode */
+	if (caseless == NO) {
+	    caseless = YES;
+	    postmsg2("Caseless mode is now ON");
+	} else {
+	    caseless = NO;
+	    postmsg2("Caseless mode is now OFF");
+	}
+	egrepcaseless(caseless);	/* turn on/off -i flag */
+	return(NO);
+
+    case ctrl('R'):	/* rebuild the cross reference */
+	if (isuptodate == YES) {
+	    postmsg("The -d option prevents rebuilding the symbol database");
+	    return(NO);
+	}
+	exitcurses();
+	freefilelist();		/* remake the source file list */
+	makefilelist();
+	rebuild();
+	if (errorsfound == YES) {
+	    errorsfound = NO;
+	    askforreturn();
+	}		
+	entercurses();
+	clearmsg();		/* clear any previous message */
+	totallines = 0;
+	disprefs = 0;	
+	topline = nextline = 1;
+	selecting = 0;
+	break;
+
+#if UNIXPC
+    case ESC:	/* possible unixpc mouse selection */
+#endif
+    case ctrl('X'):	/* mouse selection */
+	if ((p = getmouseaction(DUMMYCHAR)) == NULL) {
+	    return(NO);	/* unknown control sequence */
+	}
+	/* if the button number is a scrollbar tag */
+	if (p->button == '0') {
+	    scrollbar(p);
+	    break;
+	} 
+	/* ignore a sweep */
+	if (p->x2 >= 0) {
+	    return(NO);
+	}
+	/* if this is a line selection */
+	if (p->y1 < FLDLINE) {
+
+	    /* find the selected line */
+	    /* note: the selection is forced into range */
+	    for (i = disprefs - 1; i > 0; --i) {
+		if (p->y1 >= displine[i]) {
+		    break;
+		}
+	    }
+	    /* display it in the file with the editor */
+	    editref(i);
+	} else {	/* this is an input field selection */
+	    field = p->y1 - FLDLINE;
+	    /* force it into range */
+	    if (field >= FIELDS) {
+		field = FIELDS - 1;
+	    }
+	    setfield();
+	    resetcmd();
+	    return(NO);
+	}
+	break;
+
+    case '\t':	/* go to next input field */
+	if (disprefs) {
+	    selecting = !selecting;
+	    if (selecting) {
+		move(displine[curdispline], 0);
+		refresh();
+	    } else {
+		atfield();
+		resetcmd();
+	    }
+	}
+	return(NO);
+
+#ifdef KEY_ENTER
+    case KEY_ENTER:
+#endif
+    case '\r':
+    case '\n':	/* go to reference */
+	if (selecting) {
+	    editref(curdispline);
+	    return(YES);
+	}
+	/* FALLTHROUGH */
+
+    case ctrl('N'):
+#ifdef KEY_DOWN
+    case KEY_DOWN:
+#endif		
+#ifdef KEY_RIGHT
+    case KEY_RIGHT:
+#endif
+	if (selecting) {
+	    if ((curdispline + 1) < disprefs) {
+		move(displine[++curdispline], 0);
+		refresh();
+	    }
+	} else {
+	    field = (field + 1) % FIELDS;
+	    setfield();
+	    atfield();
+	    resetcmd();
+	}
+	return(NO);
+
+    case ctrl('P'):	/* go to previous input field */
+#ifdef KEY_UP
+    case KEY_UP:
+#endif
+#ifdef KEY_LEFT		
+    case KEY_LEFT:
+#endif
+	if (selecting) {
+	    if (curdispline) {
+		move(displine[--curdispline], 0);
+		refresh();
+	    }
+	} else {
+	    field = (field + (FIELDS - 1)) % FIELDS;
+	    setfield();
+	    atfield();
+	    resetcmd();
+	}
+	return(NO);
+#ifdef KEY_HOME
+    case KEY_HOME:	/* go to first input field */
+	if (selecting) {
+	    curdispline = 0;
+	    move(REFLINE, 0);
+	    refresh();
+	} else {
+	    field = 0;
+	    setfield();
+	    atfield();
+	    resetcmd();
+	}
+	return(NO);
+#endif
+
+#ifdef KEY_LL
+    case KEY_LL:	/* go to last input field */
+	if (selecting) {
+	    move(displine[disprefs - 1], 0);
+	    refresh();
+	} else {
+	    field = FIELDS - 1;
+	    setfield();
+	    atfield();
+	    resetcmd();
+	}
+	return(NO);
+#endif /* def(KEY_LL) */
+
+    case ' ':	/* display next page */
+    case '+':
+    case ctrl('V'):
+#ifdef KEY_NPAGE
+    case KEY_NPAGE:
+#endif
+	/* don't redisplay if there are no lines */
+	if (totallines == 0) {
+	    return(NO);
+	}
+	/* note: seekline() is not used to move to the next 
+	 * page because display() leaves the file pointer at
+	 * the next page to optimize paging forward
+	 */
+	curdispline = 0;
+	break;
+
+    case ctrl('H'):
+    case '-':	/* display previous page */
+#ifdef KEY_PPAGE
+    case KEY_PPAGE:
+#endif
+	/* don't redisplay if there are no lines */
+	if (totallines == 0) {
+	    return(NO);
+	}
+
+	curdispline = 0;
+
+	/* if there are only two pages, just go to the other one */
+	if (totallines <= 2 * mdisprefs) {
+	    break;
+	}
+	/* if on first page but not at beginning, go to beginning */
+	nextline -= mdisprefs;	/* already at next page */
+	if (nextline > 1 && nextline <= mdisprefs) {
+	    nextline = 1;
+	} else {
+	    nextline -= mdisprefs;
+	    if (nextline < 1) {
+		nextline = totallines - mdisprefs + 1;
+		if (nextline < 1) {
+		    nextline = 1;
+		}
+	    }
+	}
+	seekline(nextline);
+	break;
+
+    case '>':	/* write or append the lines to a file */
+	if (totallines == 0) {
+	    postmsg("There are no lines to write to a file");
+	} else {	/* get the file name */
+	    move(PRLINE, 0);
+	    addstr("Write to file: ");
+	    s = "w";
+	    if ((c = mygetch()) == '>') {
+		move(PRLINE, 0);
+		addstr(appendprompt);
+		c = '\0';
+		s = "a";
+	    }
+	    if (c != '\r' && 
+		mygetline("", newpat, COLS - sizeof(appendprompt), c, NO) > 0) {
+		shellpath(filename, sizeof(filename), newpat);
+		if ((file = myfopen(filename, s)) == NULL) {
+		    cannotopen(filename);
+		} else {
+		    seekline(1);
+		    while ((c = getc(refsfound)) != EOF) {
+			putc(c, file);
+		    }
+		    seekline(topline);
+		    fclose(file);
+		}
+	    }
+	    clearprompt();
+	}
+	return(NO);	/* return to the previous field */
+
+    case '<':	/* read lines from a file */
+	move(PRLINE, 0);
+	addstr(readprompt);
+	if (mygetline("", newpat, COLS - sizeof(readprompt), '\0', NO) > 0) {
+	    clearprompt();
+	    shellpath(filename, sizeof(filename), newpat);
+	    if (readrefs(filename) == NO) {
+		postmsg2("Ignoring an empty file");
+		return(NO);
+	    }
+	    return(YES);
+	}
+	clearprompt();
+	return(NO);
+
+    case '^':	/* pipe the lines through a shell command */
+    case '|':	/* pipe the lines to a shell command */
+	if (totallines == 0) {
+	    postmsg("There are no lines to pipe to a shell command");
+	    return(NO);
+	}
+	/* get the shell command */
+	move(PRLINE, 0);
+	addstr(pipeprompt);
+	if (mygetline("", newpat, COLS - sizeof(pipeprompt), '\0', NO) == 0) {
+	    clearprompt();
+	    return(NO);
+	}
+	/* if the ^ command, redirect output to a temp file */
+	if (commandc == '^') {
+	    strcat(strcat(newpat, " >"), temp2);
+	    /* HBB 20020708: somebody might have even
+	     * their non-interactive default shells
+	     * complain about clobbering
+	     * redirections... --> delete before
+	     * overwriting */
+	    remove(temp2);
+	}
+	exitcurses();
+	if ((file = mypopen(newpat, "w")) == NULL) {
+	    fprintf(stderr, "\
+cscope: cannot open pipe to shell command: %s\n", newpat);
+	} else {
+	    seekline(1);
+	    while ((c = getc(refsfound)) != EOF) {
+		putc(c, file);
+	    }
+	    seekline(topline);
+	    mypclose(file);
+	}
+	if (commandc == '^') {
+	    if (readrefs(temp2) == NO) {
+		postmsg("Ignoring empty output of ^ command");
+	    }
+	}
+	askforreturn();
+	entercurses();
+	break;
+#if defined(KEY_RESIZE) && !defined(__DJGPP__)
+    case KEY_RESIZE:
+		/* XXX: fill in*/
+	break;
+#endif
+    case ctrl('L'):	/* redraw screen */
+#ifdef KEY_CLEAR
+    case KEY_CLEAR:
+#endif
+	clearmsg2();
+	clearok(curscr, TRUE);
+	wrefresh(curscr);
+	drawscrollbar(topline, bottomline);
+	return(NO);
+
+    case '!':	/* shell escape */
+	execute(shell, shell, NULL);
+	seekline(topline);
+	break;
+
+    case '?':	/* help */
+	clear();
+	help();
+	clear();
+	seekline(topline);
+	break;
+
+    case ctrl('E'):	/* edit all lines */
+	editall();
+	break;
+
+    case ctrl('A'):		/* HBB 20050428: added alt. keymapping */
+    case ctrl('Y'):	/* repeat last pattern */
+	if (*Pattern != '\0') {
+	    addstr(Pattern);
+	    goto repeat;
+	}
+	break;
+
+    case ctrl('B'):		/* cmd history back */
+    case ctrl('F'):		/* cmd history fwd */
+	if (selecting) {
+	    selecting = 0;
+	}
+
+	curritem = currentcmd();
+	item = (commandc == ctrl('F')) ? nextcmd() : prevcmd();
+	clearmsg2();
+	if (curritem == item) {	/* inform user that we're at history end */
+	    postmsg2("End of input field and search pattern history");
+	}
+	if (item) {
+	    field = item->field;
+	    setfield();
+	    atfield();
+	    addstr(item->text);
+	    strcpy(Pattern, item->text);
+	    switch (c = mygetch()) {
+	    case '\r':
+	    case '\n':
+		goto repeat;
+	    case ctrl('F'):
+	    case ctrl('B'):
+		myungetch(c);
+		atfield();
+		clrtoeol();	/* clear current field */
+		break;
+	    default:
+		myungetch(c);
+		if (mygetline(Pattern, newpat, COLS - fldcolumn - 1, '\0', caseless )) {
+		    strcpy (Pattern, newpat);
+		    resetcmd();
+		}
+		goto repeat;
+		break;
+	    }
+	}
+	return(NO);
+
+    case '\\':	/* next character is not a command */
+	addch('\\');	/* display the quote character */
+
+	/* get a character from the terminal */
+	if ((commandc = mygetch()) == EOF) {
+	    return(NO);	/* quit */
+	}
+	addstr("\b \b");	/* erase the quote character */
+	goto ispat;
+
+    case '.':
+	postmsg("The . command has been replaced by ^Y");
+	atfield();	/* move back to the input field */
+	/* FALLTHROUGH */
+    default:
+	if (selecting && !mouse) {
+	    char *c;
+
+	    if ((c = strchr(dispchars, commandc)))
+		editref(c - dispchars);
+
+	    /* if this is the start of a pattern */
+	} else if (isprint(commandc)) {
+	ispat:
+	    if (mygetline("", newpat, COLS - fldcolumn - 1,
+			  commandc, caseless) > 0) {
+		strcpy(Pattern, newpat);
+		resetcmd();	/* reset command history */
+	    repeat:
+		addcmd(field, Pattern);	/* add to command history */
+		if (field == CHANGE) {
+		    /* prompt for the new text */
+		    move(PRLINE, 0);
+		    addstr(toprompt);
+		    mygetline("", newpat,
+			      COLS - sizeof(toprompt),
+			      '\0', NO);
+		}
+		/* search for the pattern */
+		if (search() == YES) {
+		    curdispline = 0;
+		    ++selecting;
+
+		    switch (field) {
+		    case DEFINITION:
+		    case FILENAME:
+			if (totallines > 1) {
+			    break;
+			}
+			topline = 1;
+			editref(0);
+			break;
+		    case CHANGE:
+			return(changestring());
+		    }
+
+		} else if (field == FILENAME && 
+			   access(newpat, READ) == 0) {
+		    /* try to edit the file anyway */
+		    edit(newpat, "1");
+		}
+	    } else {	/* no pattern--the input was erased */
+		return(NO);
+	    }
+	} else {	/* control character */
+	    return(NO);
+	}
+    } /* switch(commandc) */
+    return(YES);
+}
+
+/* clear the prompt line */
+
+static void
+clearprompt(void)
+{
+	move(PRLINE, 0);
+	clrtoeol();
+}
+
+/* read references from a file */
+
+BOOL
+readrefs(char *filename)
+{
+	FILE	*file;
+	int	c;
+
+	if ((file = myfopen(filename, "rb")) == NULL) {
+		cannotopen(filename);
+		return(NO);
+	}
+	if ((c = getc(file)) == EOF) {	/* if file is empty */
+		fclose(file);
+		return(NO);
+	}
+	totallines = 0;
+	disprefs = 0;
+	nextline = 1;
+	if (writerefsfound() == YES) {
+		putc(c, refsfound);
+		while ((c = getc(file)) != EOF) {
+			putc(c, refsfound);
+		}
+		fclose(file);
+		fclose(refsfound);
+		if ( (refsfound = myfopen(temp1, "rb")) == NULL) {
+			cannotopen(temp1);
+			return(NO);
+		}
+		countrefs();
+	} else
+		fclose(file);
+	return(YES);
+}
+
+/* change one text string to another */
+
+static BOOL
+changestring(void)
+{
+    char    newfile[PATHLEN + 1];   /* new file name */
+    char    oldfile[PATHLEN + 1];   /* old file name */
+    char    linenum[NUMLEN + 1];    /* file line number */
+    char    msg[MSGLEN + 1];        /* message */
+    FILE    *script;                /* shell script file */
+    BOOL    anymarked = NO;         /* any line marked */
+    MOUSE *p;                       /* mouse data */
+    int     c;
+    unsigned int i;
+    char    *s;
+
+    /* open the temporary file */
+    if ((script = myfopen(temp2, "w")) == NULL) {
+	cannotopen(temp2);
+	return(NO);
+    }
+    /* create the line change indicators */
+    change = calloc(totallines, sizeof(*change));
+    changing = YES;
+    mousemenu();
+
+    /* until the quit command is entered */
+    for (;;) {
+	/* display the current page of lines */
+	display();
+    same:
+	atchange();
+		
+	/* get a character from the terminal */
+	if ((c = mygetch()) == EOF || c == ctrl('D')) {
+	    break;	/* change lines */
+	}
+	if (c == ctrl('Z')) {
+#ifdef SIGTSTP
+	    kill(0, SIGTSTP);
+	    goto same;
+#else
+	    break;	/* change lines */
+#endif
+	}
+	/* see if the input character is a command */
+	switch (c) {
+	case ' ':	/* display next page */
+	case '+':
+	case ctrl('V'):
+#ifdef KEY_NPAGE
+	case KEY_NPAGE:
+#endif
+	case '-':	/* display previous page */
+#ifdef KEY_PPAGE
+	case KEY_PPAGE:
+#endif
+	case '!':	/* shell escape */
+	case '?':	/* help */
+	    command(c);
+	    break;
+
+	case ctrl('L'):	/* redraw screen */
+#ifdef KEY_CLEAR
+	case KEY_CLEAR:
+#endif
+	    command(c);
+	    goto same;
+
+	case ESC:	/* don't change lines */
+#if UNIXPC
+	    if((p = getmouseaction(DUMMYCHAR)) == NULL) {
+		goto nochange;	/* unknown escape sequence */
+	    }
+	    break;
+#endif
+	case ctrl('G'):
+	    goto nochange;
+
+	case '*':	/* mark/unmark all displayed lines */
+	    for (i = 0; topline + i < nextline; ++i) {
+		mark(i);
+	    }
+	    goto same;
+
+	case ctrl('A'):	/* mark/unmark all lines */
+	    for (i = 0; i < totallines; ++i) {
+		if (change[i] == NO) {
+		    change[i] = YES;
+		} else {
+		    change[i] = NO;
+		}
+	    }
+	    /* show that all have been marked */
+	    seekline(totallines);
+	    break;
+
+	case ctrl('X'):	/* mouse selection */
+	    if ((p = getmouseaction(DUMMYCHAR)) == NULL) {
+		goto same;	/* unknown control sequence */
+	    }
+	    /* if the button number is a scrollbar tag */
+	    if (p->button == '0') {
+		scrollbar(p);
+		break;
+	    }
+	    /* find the selected line */
+	    /* note: the selection is forced into range */
+	    for (i = disprefs - 1; i > 0; --i) {
+		if (p->y1 >= displine[i]) {
+		    break;
+		}
+	    }
+	    mark(i);
+	    goto same;
+
+	default:
+	    {
+		/* if a line was selected */
+		char		*cc;
+
+		if ((cc = strchr(dispchars, c)))
+		    mark(cc - dispchars);
+
+		goto same;
+	    } /* default case */
+	} /* switch(change code character) */
+    } /* for(ever) */
+
+    /* for each line containing the old text */
+    fprintf(script, "ed - <<\\!\n");
+    *oldfile = '\0';
+    seekline(1);
+    for (i = 0; 
+	 fscanf(refsfound, "%" PATHLEN_STR "s%*s%" NUMLEN_STR "s%*[^\n]", newfile, linenum) == 2;
+	 ++i) {
+	/* see if the line is to be changed */
+	if (change[i] == YES) {
+	    anymarked = YES;
+		
+	    /* if this is a new file */
+	    if (strcmp(newfile, oldfile) != 0) {
+				
+		/* make sure it can be changed */
+		if (access(newfile, WRITE) != 0) {
+		    snprintf(msg, sizeof(msg), "Cannot write to file %s", newfile);
+		    postmsg(msg);
+		    anymarked = NO;
+		    break;
+		}
+		/* if there was an old file */
+		if (*oldfile != '\0') {
+		    fprintf(script, "w\n");	/* save it */
+		}
+		/* edit the new file */
+		strcpy(oldfile, newfile);
+		fprintf(script, "e %s\n", oldfile);
+	    }
+	    /* output substitute command */
+	    fprintf(script, "%ss/", linenum);	/* change */
+	    for (s = Pattern; *s != '\0'; ++s) {
+		/* old text */
+		if (strchr("/\\[.^*", *s) != NULL) {
+		    putc('\\', script);
+		}
+		if (caseless == YES && isalpha((unsigned char)*s)) {
+		    putc('[', script);
+		    if(islower((unsigned char)*s)) {
+			putc(toupper((unsigned char)*s), script);
+			putc(*s, script);
+		    } else {
+			putc(*s, script);
+			putc(tolower((unsigned char)*s), script);
+		    }
+		    putc(']', script);
+		} else	
+		    putc(*s, script);
+	    }
+	    putc('/', script);			/* to */
+	    for (s = newpat; *s != '\0'; ++s) {	/* new text */
+		if (strchr("/\\&", *s) != NULL) {
+		    putc('\\', script);
+		}
+		putc(*s, script);
+	    }
+	    fprintf(script, "/gp\n");	/* and print */
+	}
+    }
+    fprintf(script, "w\nq\n!\n");	/* write and quit */
+    fclose(script);
+
+    /* if any line was marked */
+    if (anymarked == YES) {
+		
+	/* edit the files */
+	clearprompt();
+	refresh();
+	fprintf(stderr, "Changed lines:\n\r");
+	execute("sh", "sh", temp2, NULL);
+	askforreturn();
+	seekline(1);
+    } else {
+    nochange:
+	clearprompt();
+    }
+    changing = NO;
+    mousemenu();
+    fclose(script);
+    free(change);
+    return(anymarked);
+}
+
+
+/* mark/unmark this displayed line to be changed */
+static void
+mark(unsigned int i)
+{
+    unsigned int j;
+	
+    j = i + topline - 1;
+    if (j < totallines) {
+	move(displine[i], 1);
+
+	if (change[j] == NO) {
+	    change[j] = YES;
+	    addch('>');
+	} else {
+	    change[j] = NO;
+	    addch(' ');
+	}
+    }
+}
+
+
+/* scrollbar actions */
+static void
+scrollbar(MOUSE *p)
+{
+    /* reposition list if it makes sense */
+    if (totallines == 0) {
+	return;
+    }
+    switch (p->percent) {
+		
+    case 101: /* scroll down one page */
+	if (nextline + mdisprefs > totallines) {
+	    nextline = totallines - mdisprefs + 1;
+	}
+	break;
+		
+    case 102: /* scroll up one page */
+	nextline = topline - mdisprefs;
+	if (nextline < 1) {
+	    nextline = 1;
+	}
+	break;
+
+    case 103: /* scroll down one line */
+	nextline = topline + 1;
+	break;
+		
+    case 104: /* scroll up one line */
+	if (topline > 1) {
+	    nextline = topline - 1;
+	}
+	break;
+    default:
+	nextline = p->percent * totallines / 100;
+    }
+    seekline(nextline);
+}
+
+
+/* count the references found */
+void
+countrefs(void)
+{
+    char    *subsystem;             /* OGS subsystem name */
+    char    *book;                  /* OGS book name */
+    char    file[PATHLEN + 1];      /* file name */
+    char    function[PATLEN + 1];   /* function name */
+    char    linenum[NUMLEN + 1];    /* line number */
+    int     i;
+
+    /* count the references found and find the length of the file,
+       function, and line number display fields */
+    subsystemlen = 9;	/* strlen("Subsystem") */
+    booklen = 4;		/* strlen("Book") */
+    filelen = 4;		/* strlen("File") */
+    fcnlen = 8;		/* strlen("Function") */
+    numlen = 0;
+    /* HBB NOTE 2012-04-07: it may look like we shouldn't assing tempstring here,
+     * since it's not used.  But it has to be assigned just so the return value
+     * of fscanf will actually reach 4. */
+    while (EOF != (i = fscanf(refsfound, 
+			      "%" PATHLEN_STR "s%" PATLEN_STR "s%" NUMLEN_STR "s %" TEMPSTRING_LEN_STR "[^\n]",
+			      file, function, linenum, tempstring
+			     )
+	          )
+	  ) {
+	if (   (i != 4)
+	    || !isgraph((unsigned char) *file)
+	    || !isgraph((unsigned char) *function)
+	    || !isdigit((unsigned char) *linenum)
+	   ) {
+	    postmsg("File does not have expected format");
+	    totallines = 0;
+	    disprefs = 0;
+	    return;
+	}
+	if ((i = strlen(pathcomponents(file, dispcomponents))) > filelen) {
+	    filelen = i;
+	}
+	if (ogs == YES) {
+	    ogsnames(file, &subsystem, &book);
+	    if ((i = strlen(subsystem)) > subsystemlen) {
+		subsystemlen = i;
+	    }
+	    if ((i = strlen(book)) > booklen) {
+		booklen = i;
+	    }
+	}
+	if ((i = strlen(function)) > fcnlen) {
+	    fcnlen = i;
+	}
+	if ((i = strlen(linenum)) > numlen) {
+	    numlen = i;
+	}
+	++totallines;
+    }
+    rewind(refsfound);
+
+    /* restrict the width of displayed columns */
+    /* HBB FIXME 20060419: magic number alert! */ 
+    i = (COLS - 5) / 3;
+    if (ogs == YES) {
+	i = (COLS - 7) / 5;
+    }
+    if (filelen > i && i > 4) {
+	filelen = i;
+    }
+    if (subsystemlen > i && i > 9) {
+	subsystemlen = i;
+    }
+    if (booklen > i && i > 4) {
+	booklen = i;
+    }
+    if (fcnlen > i && i > 8) {
+	fcnlen = i;
+    }
+}
diff --git a/src/compath.c b/src/compath.c
new file mode 100644
index 0000000..037d341
--- /dev/null
+++ b/src/compath.c
@@ -0,0 +1,211 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*
+ *	compath(pathname)
+ *
+ *	This compresses pathnames.  All strings of multiple slashes are
+ *	changed to a single slash.  All occurrences of "./" are removed.
+ *	Whenever possible, strings of "/.." are removed together with
+ *	the directory names that they follow.
+ *
+ *	WARNING: since pathname is altered by this function, it should
+ *		 be located in a temporary buffer. This avoids the problem
+ *		 of accidently changing strings obtained from makefiles
+ *		 and stored in global structures.
+ */
+
+#include "global.h"
+
+#ifndef NULL
+#define	NULL	0
+#endif
+
+char *
+compath(char *pathname)			/*FDEF*/
+{
+	char	*nextchar;
+	char	*lastchar;
+	char	*sofar;
+	char	*pnend;
+
+	int	pnlen;
+
+		/*
+		 *	do not change the path if it has no "/"
+		 */
+
+	if (strchr(pathname, '/') == NULL)
+		return(pathname);
+
+		/*
+		 *	find all strings consisting of more than one '/'
+		 */
+
+	for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++)
+		if ((*lastchar == '/') && (*(lastchar - 1) == '/'))
+		{
+
+			/*
+			 *	find the character after the last slash
+			 */
+
+			nextchar = lastchar;
+			while (*++lastchar == '/')
+			{
+			}
+
+			/*
+			 *	eliminate the extra slashes by copying
+			 *	everything after the slashes over the slashes
+			 */
+
+			sofar = nextchar;
+			while ((*nextchar++ = *lastchar++) != '\0')
+				;
+			lastchar = sofar;
+		}
+
+		/*
+		 *	find all strings of "./"
+		 */
+
+	for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++)
+		if ((*lastchar == '/') && (*(lastchar - 1) == '.') &&
+		    ((lastchar - 1 == pathname) || (*(lastchar - 2) == '/')))
+		{
+
+			/*
+			 *	copy everything after the "./" over the "./"
+			 */
+
+			nextchar = lastchar - 1;
+			sofar = nextchar;
+			while ((*nextchar++ = *++lastchar) != '\0')
+				;
+			lastchar = sofar;
+		}
+
+		/*
+		 *	find each occurrence of "/.."
+		 */
+
+	for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++)
+		if ((lastchar != pathname) && (*lastchar == '/') &&
+		    (*(lastchar + 1) == '.') && (*(lastchar + 2) == '.') &&
+		    ((*(lastchar + 3) == '/') || (*(lastchar + 3) == '\0')))
+		{
+
+			/*
+			 *	find the directory name preceding the "/.."
+			 */
+
+			nextchar = lastchar - 1;
+			while ((nextchar != pathname) &&
+			    (*(nextchar - 1) != '/'))
+				--nextchar;
+
+			/*
+			 *	make sure the preceding directory's name
+			 *	is not "." or ".."
+			 */
+
+			if ((*nextchar == '.') &&
+			    ((*(nextchar + 1) == '/') ||
+			     ((*(nextchar + 1) == '.') && (*(nextchar + 2) == '/'))))
+				/* EMPTY */;
+			else
+			{
+
+				/*
+				 * 	prepare to eliminate either
+				 *	"dir_name/../" or "dir_name/.."
+				 */
+
+				if (*(lastchar + 3) == '/')
+					lastchar += 4;
+				else
+					lastchar += 3;
+
+				/*
+				 *	copy everything after the "/.." to
+				 *	before the preceding directory name
+				 */
+
+				sofar = nextchar - 1;
+				while ((*nextchar++ = *lastchar++) != '\0');
+					
+				lastchar = sofar;
+
+				/*
+				 *	if the character before what was taken
+				 *	out is '/', set up to check if the
+				 *	slash is part of "/.."
+				 */
+
+				if ((sofar + 1 != pathname) && (*sofar == '/'))
+					--lastchar;
+			}
+		}
+
+	/*
+ 	 *	if the string is more than a character long and ends
+	 *	in '/', eliminate the '/'.
+	 */
+
+	pnlen = strlen(pathname);
+	pnend = strchr(pathname, '\0') - 1;
+
+	if ((pnlen > 1) && (*pnend == '/'))
+	{
+		*pnend-- = '\0';
+		pnlen--;
+	}
+
+	/*
+	 *	if the string has more than two characters and ends in
+	 *	"/.", remove the "/.".
+	 */
+
+	if ((pnlen > 2) && (*(pnend - 1) == '/') && (*pnend == '.'))
+		*--pnend = '\0';
+
+	/*
+	 *	if all characters were deleted, return ".";
+	 *	otherwise return pathname
+	 */
+
+	if (*pathname == '\0')
+		(void) strcpy(pathname, ".");
+
+	return(pathname);
+}
diff --git a/src/constants.h b/src/constants.h
new file mode 100644
index 0000000..873a720
--- /dev/null
+++ b/src/constants.h
@@ -0,0 +1,133 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	preprocessor macro and constant definitions
+ */
+
+#ifndef CSCOPE_CONSTANTS_H
+#define CSCOPE_CONSTANTS_H
+
+#define ctrl(x)	(x & 037)	/* control character macro */
+
+/* fast string equality tests (avoids most strcmp() calls) */
+#define	strequal(s1, s2)	(*(s1) == *(s2) && strcmp(s1, s2) == 0)
+#define	strnotequal(s1, s2)	(*(s1) != *(s2) || strcmp(s1, s2) != 0)
+
+/* set the mark character for searching the cross-reference file */
+#define	setmark(c)	(blockmark = c, block[blocklen] = blockmark)
+
+/* get the next character in the cross-reference */
+/* note that blockp is assumed not to be null */
+#define	getrefchar()	(*(++blockp + 1) != '\0' ? *blockp : \
+			(read_block() != NULL ? *blockp : '\0'))
+
+/* skip the next character in the cross-reference */
+/* note that blockp is assumed not to be null and that
+   this macro will always be in a statement by itself */
+#define	skiprefchar()	if (*(++blockp + 1) == '\0') (void) read_block()
+
+#define	ESC	'\033'		/* escape character */
+#define	DEL	'\177'		/* delete character */
+#define	DUMMYCHAR	' '	/* use space as a dummy character */
+#define	MSGLEN	((PATLEN) + 80)	/* displayed message length */
+#define	NUMLEN	10		/* line number length */
+#define	PATHLEN	250		/* file pathname length */
+#define	PATLEN	250		/* symbol pattern length */
+#define TEMPSTRING_LEN 8191     /* max strlen() of the global temp string */
+#define	REFFILE	"cscope.out"	/* cross-reference output file */
+#define	NAMEFILE "cscope.files"	/* default list-of-files file */
+#define	INVNAME	"cscope.in.out"	/* inverted index to the database */
+#define	INVPOST	"cscope.po.out"	/* inverted index postings */
+#define	INVNAME2 "cscope.out.in"/* follows correct naming convention */
+#define	INVPOST2 "cscope.out.po"/* follows correct naming convention */
+
+#define	STMTMAX	10000		/* maximum source statement length */
+
+#define STR2(x) #x
+#define STRINGIZE(x) STR2(x)
+#define PATLEN_STR STRINGIZE(PATLEN)
+#define PATHLEN_STR STRINGIZE(PATHLEN)
+#define NUMLEN_STR STRINGIZE(NUMLEN)
+#define TEMPSTRING_LEN_STR STRINGIZE(TEMPSTRING_LEN)
+
+/* screen lines */
+#define	FLDLINE	(LINES - FIELDS - 1 - 1)	/* first input field line */
+#define	MSGLINE	0			/* message line */
+#define	PRLINE	(LINES - 1)		/* input prompt line */
+#define REFLINE	3			/* first displayed reference line */
+
+/* input fields (value matches field order on screen) */
+#define	SYMBOL		0
+#define DEFINITION	1
+#define	CALLEDBY	2
+#define	CALLING		3
+#define	STRING		4
+#define	CHANGE		5
+#define	REGEXP		6
+#define FILENAME	7
+#define INCLUDES	8
+#define	FIELDS		10
+
+#if (BSD || V9) && !__NetBSD__ && !__FreeBSD__ && !__APPLE__
+# define TERMINFO	0	/* no terminfo curses */
+#else
+# define TERMINFO	1
+#endif
+
+
+#if !TERMINFO
+# ifndef KEY_BREAK
+#  define	KEY_BREAK	0400	/* easier to define than to add #if around the use */
+# endif
+# ifndef KEY_ENTER
+#  define	KEY_ENTER	0401
+# endif
+# ifndef KEY_BACKSPACE
+#  define	KEY_BACKSPACE	0402
+# endif
+
+# if !sun
+#  define cbreak()	crmode()			/* name change */
+# endif
+
+# if UNIXPC
+#  define erasechar() (_tty.c_cc[VERASE])		/* equivalent */
+#  define killchar()  (_tty.c_cc[VKILL])		/* equivalent */
+# else
+#  define erasechar() (_tty.sg_erase)			/* equivalent */
+#  define killchar()  (_tty.sg_kill)			/* equivalent */
+# endif /* if UNIXPC */
+#endif	/* if !TERMINFO */
+
+#endif /* CSCOPE_CONSTANTS_H */
diff --git a/src/crossref.c b/src/crossref.c
new file mode 100644
index 0000000..b10ed75
--- /dev/null
+++ b/src/crossref.c
@@ -0,0 +1,492 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	build cross-reference file
+ */
+
+#include "global.h"
+
+#include "build.h"
+#include "scanner.h"
+
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+/* convert long to a string in base BASE notation */
+#define	ltobase(value)                     \
+do {                                       \
+	n = (value);                       \
+	s = buf + (sizeof(buf) - 1);       \
+	*s = '\0';                         \
+	digits = 1;                        \
+	while (n >= BASE) {                \
+		++digits;                  \
+		i = n;                     \
+		n /= BASE;                 \
+		*--s = i - n * BASE + '!'; \
+	}                                  \
+	*--s = n + '!';                    \
+} while (0)
+
+#define	SYMBOLINC	20	/* symbol list size increment */
+
+long	dboffset;		/* new database offset */
+BOOL	errorsfound;		/* prompt before clearing messages */
+long	lineoffset;		/* source line database offset */
+long	npostings;		/* number of postings */
+int	nsrcoffset;             /* number of file name database offsets */
+long	*srcoffset;             /* source file name database offsets */
+unsigned long symbols;		/* number of symbols */
+
+static	char	*filename;	/* file name for warning messages */
+static	long	fcnoffset;	/* function name database offset */
+static	long	macrooffset;	/* macro name database offset */
+static	unsigned long msymbols = SYMBOLINC; /* maximum number of symbols */
+
+struct	symbol {	/* symbol data */
+    int	type;		/* type */
+    unsigned int first;		/* index of first character in text */
+    unsigned int last;		/* index of last+1 character in text */
+    unsigned int length;	/* symbol length */
+    unsigned int fcn_level;	/* function level of the symbol */
+};
+static struct symbol *symbol;
+
+static	void	putcrossref(void);
+static	void	savesymbol(int token, int num);
+
+void
+crossref(char *srcfile)
+{
+    unsigned int i;
+    unsigned int length;	/* symbol length */
+    unsigned int entry_no;	/* function level of the symbol */
+    int token;                  /* current token */
+    struct stat st;
+
+    if (! ((stat(srcfile, &st) == 0)
+	   && S_ISREG(st.st_mode))) {
+	cannotopen(srcfile);
+	errorsfound = YES;
+	return;
+    }
+	
+    entry_no = 0;
+    /* open the source file */
+    if ((yyin = myfopen(srcfile, "r")) == NULL) {
+	cannotopen(srcfile);
+	errorsfound = YES;
+	return;
+    }
+    filename = srcfile;	/* save the file name for warning messages */
+    putfilename(srcfile);	/* output the file name */
+    dbputc('\n');
+    dbputc('\n');
+
+    /* read the source file */
+    initscanner(srcfile);
+    fcnoffset = macrooffset = 0;
+    symbols = 0;
+    if (symbol == NULL) {
+	symbol = malloc(msymbols * sizeof(*symbol));
+    }
+    for (;;) {
+		
+	/* get the next token */
+	switch (token = yylex()) {
+	default:
+	    /* if requested, truncate C symbols */
+	    length = last - first;
+	    if (trun_syms == YES && length > 8 &&
+		token != INCLUDE && token != NEWFILE) {
+		length = 8;
+		last = first + 8;
+	    }
+	    /* see if the token has a symbol */
+	    if (length == 0) {
+		savesymbol(token, entry_no);
+		break;
+	    }
+	    /* update entry_no if see function entry */
+	    if (token == FCNDEF) {
+		entry_no++;
+	    }
+	    /* see if the symbol is already in the list */
+	    for (i = 0; i < symbols; ++i) {
+		if (length == symbol[i].length
+		    && strncmp(my_yytext + first,
+			       my_yytext + symbol[i].first,
+			       length) == 0 
+		    && entry_no == symbol[i].fcn_level
+		    && token == symbol[i].type
+		    ) {	/* could be a::a() */
+		    break;
+		}
+	    }
+	    if (i == symbols) {	/* if not already in list */
+		savesymbol(token, entry_no);
+	    }
+	    break;
+
+	case NEWLINE:	/* end of line containing symbols */
+	    entry_no = 0;	/* reset entry_no for each line */
+#ifdef USING_LEX
+	    --yyleng; 	/* remove the newline */
+#endif
+	    putcrossref();	/* output the symbols and source line */
+	    lineno = myylineno;	/* save the symbol line number */
+#ifndef USING_LEX
+	    /* HBB 20010425: replaced yyleng-- by this chunk: */
+	    if (my_yytext)
+		*my_yytext = '\0';
+	    my_yyleng = 0;
+#endif
+	    break;
+			
+	case LEXERR:	/* Lexer error, abort further parsing of this file */
+	case LEXEOF:	/* end of file; last line may not have \n */
+			
+			/* if there were symbols, output them and the source line */
+	    if (symbols > 0) {
+		putcrossref();
+	    }
+	    (void) fclose(yyin);	/* close the source file */
+
+	    /* output the leading tab expected by the next call */
+	    dbputc('\t');
+	    return;
+	}
+    }
+}
+
+/* save the symbol in the list */
+
+static void
+savesymbol(int token, int num)
+{
+    /* make sure there is room for the symbol */
+    if (symbols == msymbols) {
+	msymbols += SYMBOLINC;
+	symbol = realloc(symbol, msymbols * sizeof(*symbol));
+    }
+    /* save the symbol */
+    symbol[symbols].type = token;
+    symbol[symbols].first = first;
+    symbol[symbols].last = last;
+    symbol[symbols].length = last - first;
+    symbol[symbols].fcn_level = num;
+    ++symbols;
+}
+
+/* output the file name */
+
+void
+putfilename(char *srcfile)
+{
+	/* check for file system out of space */
+	/* note: dbputc is not used to avoid lint complaint */
+	if (putc(NEWFILE, newrefs) == EOF) {
+		cannotwrite(newreffile);
+		/* NOTREACHED */
+	}
+	++dboffset;
+	if (invertedindex == YES) {
+		srcoffset[nsrcoffset++] = dboffset;
+	}
+	dbfputs(srcfile);
+	fcnoffset = macrooffset = 0;
+}
+
+/* output the symbols and source line */
+
+static void
+putcrossref(void)
+{
+    unsigned int i, j;
+    unsigned char c;
+    BOOL    blank;          /* blank indicator */
+    unsigned int symput = 0;     /* symbols output */
+    int     type;
+
+    /* output the source line */
+    lineoffset = dboffset;
+    dboffset += fprintf(newrefs, "%d ", lineno);
+#ifdef PRINTF_RETVAL_BROKEN
+    dboffset = ftell(newrefs); /* fprintf doesn't return chars written */
+#endif
+
+    /* HBB 20010425: added this line: */
+    my_yytext[my_yyleng] = '\0';
+
+    blank = NO;
+    for (i = 0; i < my_yyleng; ++i) {
+		
+	/* change a tab to a blank and compress blanks */
+	if ((c = my_yytext[i]) == ' ' || c == '\t') {
+	    blank = YES;
+	} else if (symput < symbols && i == symbol[symput].first) {
+	    /* look for the start of a symbol */
+
+	    /* check for compressed blanks */
+	    if (blank == YES) {
+		blank = NO;
+		dbputc(' ');
+	    }
+	    dbputc('\n');	/* symbols start on a new line */
+			
+	    /* output any symbol type */
+	    if ((type = symbol[symput].type) != IDENT) {
+		dbputc('\t');
+		dbputc(type);
+	    } else {
+		type = ' ';
+	    }
+	    /* output the symbol */
+	    j = symbol[symput].last;
+	    c = my_yytext[j];
+	    my_yytext[j] = '\0';
+	    if (invertedindex == YES) {
+		putposting(my_yytext + i, type);
+	    }
+	    writestring(my_yytext + i);
+	    dbputc('\n');
+	    my_yytext[j] = c;
+	    i = j - 1;
+	    ++symput;
+	} else {
+	    /* HBB: try to save some time by early-out handling of 
+	     * non-compressed mode */
+	    if (compress == NO) {
+		if (blank == YES) {
+		    dbputc(' ');
+		    blank = NO;
+		}
+		j = i + strcspn(my_yytext+i, "\t ");
+		if (symput < symbols
+		    && j >= symbol[symput].first)
+		    j = symbol[symput].first;
+		c = my_yytext[j];
+		my_yytext[j] = '\0';
+		writestring(my_yytext + i);
+		my_yytext[j] = c;
+		i = j - 1;
+		/* finished this 'i', continue with the blank */
+		continue;
+	    }
+
+	    /* check for compressed blanks */
+	    if (blank == YES) {
+		if (dicode2[c]) {
+		    c = DICODE_COMPRESS(' ', c);
+		} else {
+		    dbputc(' ');
+		}
+	    } else if (IS_A_DICODE(c, my_yytext[i + 1])
+		       && symput < symbols
+		       && i + 1 != symbol[symput].first) {
+		/* compress digraphs */
+		c = DICODE_COMPRESS(c, my_yytext[i + 1]);
+		++i;
+	    }
+	    dbputc((int) c);
+	    blank = NO;
+			
+	    /* skip compressed characters */
+	    if (c < ' ') {
+		++i;
+				
+		/* skip blanks before a preprocesor keyword */
+		/* note: don't use isspace() because \f and \v
+		   are used for keywords */
+		while ((j = my_yytext[i]) == ' ' || j == '\t') {
+		    ++i;
+		}
+		/* skip the rest of the keyword */
+		while (isalpha((unsigned char)my_yytext[i])) {
+		    ++i;
+		}
+		/* skip space after certain keywords */
+		if (keyword[c].delim != '\0') {
+		    while ((j = my_yytext[i]) == ' ' || j == '\t') {
+			++i;
+		    }
+		}
+		/* skip a '(' after certain keywords */
+		if (keyword[c].delim == '('
+		    && my_yytext[i] == '(') {
+		    ++i;
+		}
+		--i;	/* compensate for ++i in for() */
+	    } /* if compressed char */
+	} /* else: not a symbol */
+    } /* for(i) */
+
+    /* ignore trailing blanks */
+    dbputc('\n');
+    dbputc('\n');
+
+    /* output any #define end marker */
+    /* note: must not be part of #define so putsource() doesn't discard it
+       so findcalledbysub() can find it and return */
+    if (symput < symbols && symbol[symput].type == DEFINEEND) {
+	dbputc('\t');
+	dbputc(DEFINEEND);
+	dbputc('\n');
+	dbputc('\n');	/* mark beginning of next source line */
+	macrooffset = 0;
+    }
+    symbols = 0;
+}
+
+/* HBB 20000421: new function, for avoiding memory leaks */
+/* free the cross reference symbol table */
+void
+freecrossref()
+{
+	if (symbol)
+		free(symbol);
+	symbol = NULL;
+	symbols = 0;
+}
+
+/* output the inverted index posting */
+
+void
+putposting(char *term, int type)
+{
+	long	i, n;
+	char	*s;
+	int	digits;		/* digits output */
+	long	offset;		/* function/macro database offset */
+	char	buf[11];		/* number buffer */
+
+	/* get the function or macro name offset */
+	offset = fcnoffset;
+	if (macrooffset != 0) {
+		offset = macrooffset;
+	}
+	/* then update them to avoid negative relative name offset */
+	switch (type) {
+	case DEFINE:
+		macrooffset = dboffset;
+		break;
+	case DEFINEEND:
+		macrooffset = 0;
+		return;		/* null term */
+	case FCNDEF:
+		fcnoffset = dboffset;
+		break;
+	case FCNEND:
+		fcnoffset = 0;
+		return;		/* null term */
+	}
+	/* ignore a null term caused by a enum/struct/union without a tag */
+	if (*term == '\0') {
+		return;
+	}
+	/* skip any #include secondary type char (< or ") */
+	if (type == INCLUDE) {
+		++term;
+	}
+	/* output the posting, which should be as small as possible to reduce
+	   the temp file size and sort time */
+	(void) fputs(term, postings);
+	(void) putc(' ', postings);
+
+	/* the line offset is padded so postings for the same term will sort
+	   in ascending line offset order to order the references as they
+	   appear withing a source file */
+	ltobase(lineoffset);
+	for (i = PRECISION - digits; i > 0; --i) {
+		(void) putc('!', postings);
+	}
+	do {
+		(void) putc(*s, postings);
+	} while (*++s != '\0');
+	
+	/* postings are also sorted by type */
+	(void) putc(type, postings);
+	
+	/* function or macro name offset */
+	if (offset > 0) {
+		(void) putc(' ', postings);
+		ltobase(offset);
+		do {
+			(void) putc(*s, postings);
+		} while (*++s != '\0');
+	}
+	if (putc('\n', postings) == EOF) {
+		cannotwrite(temp1);
+		/* NOTREACHED */
+	}
+	++npostings;
+}
+
+/* put the string into the new database */
+
+void
+writestring(char *s)
+{
+	unsigned char c;
+	int	i;
+	
+	if (compress == NO) {
+		/* Save some I/O overhead by using puts() instead of putc(): */
+		dbfputs(s);
+		return;
+	} 
+	/* compress digraphs */
+	for (i = 0; (c = s[i]) != '\0'; ++i) {
+		if (/* dicode1[c] && dicode2[(unsigned char) s[i + 1]] */
+		    IS_A_DICODE(c, s[i + 1])) {
+			/* c = (0200 - 2) + dicode1[c] + dicode2[(unsigned char) s[i + 1]]; */
+			c = DICODE_COMPRESS(c, s[i + 1]);
+			++i;
+		}
+		dbputc(c);	
+	}
+}
+
+/* print a warning message with the file name and line number */
+
+void
+warning(char *text)
+{
+	
+	(void) fprintf(stderr, "cscope: \"%s\", line %d: warning: %s\n", filename, 
+		myylineno, text);
+	errorsfound = YES;
+}
diff --git a/src/dir.c b/src/dir.c
new file mode 100644
index 0000000..7688dea
--- /dev/null
+++ b/src/dir.c
@@ -0,0 +1,747 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	directory searching functions
+ */
+
+#include "global.h"
+
+#include "vp.h"		/* vpdirs and vpndirs */
+
+#include <stdlib.h>
+#include <sys/types.h>	/* needed by stat.h and dirent.h */
+#include <dirent.h>
+#include <sys/stat.h>	/* stat */
+#include <assert.h>
+
+#define	DIRSEPS	" ,:"	/* directory list separators */
+#define	DIRINC	10	/* directory list size increment */
+#define HASHMOD	2003	/* must be a prime number */
+#define	SRCINC	HASHMOD	/* source file list size increment */
+			/* largest known database had 22049 files */
+
+char	currentdir[PATHLEN + 1];/* current directory */
+char	**incdirs;		/* #include directories */
+char	**srcdirs;		/* source directories */
+char	**srcfiles;		/* source files */
+unsigned long nincdirs;		/* number of #include directories */
+unsigned long nsrcdirs;		/* number of source directories */
+unsigned long nsrcfiles;	/* number of source files */
+unsigned long msrcfiles = SRCINC;	/* maximum number of source files */
+
+static	char	**incnames;	/* #include directory names without view pathing */
+static	unsigned long mincdirs = DIRINC; /* maximum number of #include directories */
+static	unsigned long msrcdirs; /* maximum number of source directories */
+static	unsigned long nvpsrcdirs; /* number of view path source directories */
+
+static	struct	listitem {	/* source file names without view pathing */
+	char	*text;
+	struct	listitem *next;
+} *srcnames[HASHMOD];
+
+/* Internal prototypes: */
+static	BOOL	accessible_file(char *file);
+static	BOOL	issrcfile(char *file);
+static	void	addsrcdir(char *dir);
+static	void	addincdir(char *name, char *path);
+static	void	scan_dir(const char *dirfile, BOOL recurse);
+static	void	makevpsrcdirs(void);
+
+
+/* make the view source directory list */
+
+static void
+makevpsrcdirs(void)
+{
+	int	i;
+
+	/* return if this function has already been called */
+	if (nsrcdirs > 0) {
+		return;
+	}
+	/* get the current directory name */
+	if (getcwd(currentdir, PATHLEN) == NULL) {
+		fprintf(stderr, "cscope: warning: cannot get current directory name\n");
+		strcpy(currentdir, "<unknown>");
+	}
+	/* see if there is a view path and this directory is in it */
+	vpinit(currentdir);
+	if (vpndirs > 1) {
+		nsrcdirs = vpndirs;
+	} else {
+		nsrcdirs = 1;
+	}
+	/* create the source directory list */
+	msrcdirs = nsrcdirs + DIRINC;
+	srcdirs = malloc(msrcdirs * sizeof(*srcdirs));
+	*srcdirs = ".";	/* first source dir is always current dir */
+	for (i = 1; i < vpndirs; ++i) {
+		srcdirs[i] = vpdirs[i];
+	}
+	/* save the number of original source directories in the view path */
+	nvpsrcdirs = nsrcdirs;
+}
+
+/* add a source directory to the list for each view path source directory */
+
+void
+sourcedir(char *dirlist)
+{
+    char    path[PATHLEN + 1];
+    char    *dir;
+    unsigned int i;
+
+    makevpsrcdirs();		/* make the view source directory list */
+    dirlist = strdup(dirlist); /* don't change environment variable text */
+	
+    /* parse the directory list */
+    dir = strtok(dirlist, DIRSEPS);
+    while (dir != NULL) {
+	int dir_len = strlen(dir);
+
+	addsrcdir(dir);
+
+	/* if it isn't a full path name and there is a 
+	   multi-directory view path */
+	if (*dirlist != '/' && vpndirs > 1) {
+			
+	    /* compute its path from higher view path source dirs */
+	    for (i = 1; i < nvpsrcdirs; ++i) {
+		snprintf(path, sizeof(path), "%.*s/%s",
+			PATHLEN - 2 - dir_len,
+			srcdirs[i], dir);
+		addsrcdir(path);
+	    }
+	}
+	dir = strtok(NULL, DIRSEPS);
+    }
+    free(dirlist);		/* HBB 20000421: avoid memory leaks */
+}
+
+/* add a source directory to the list */
+
+static void
+addsrcdir(char *dir)
+{
+	struct	stat	statstruct;
+
+	/* make sure it is a directory */
+	if (lstat(compath(dir), &statstruct) == 0 && 
+	    S_ISDIR(statstruct.st_mode)) {
+
+		/* note: there already is a source directory list */
+		if (nsrcdirs == msrcdirs) {
+			msrcdirs += DIRINC;
+			srcdirs = realloc(srcdirs, msrcdirs * sizeof(*srcdirs));
+		}
+		srcdirs[nsrcdirs++] = strdup(dir);
+	}
+}
+
+/* HBB 20000421: new function, for avoiding leaks */
+/* free list of src directories */
+void
+freesrclist()
+{
+	if (!srcdirs)
+		return;
+	while(nsrcdirs>1)
+		free(srcdirs[--nsrcdirs]);
+	free(srcdirs);
+}
+
+/* add a #include directory to the list for each view path source directory */
+
+void
+includedir(char *dirlist)
+{
+    char    path[PATHLEN + 1];
+    char    *dir;
+    unsigned int i;
+
+    makevpsrcdirs();		/* make the view source directory list */
+    dirlist = strdup(dirlist); /* don't change environment variable text */
+	
+    /* parse the directory list */
+    dir = strtok(dirlist, DIRSEPS);
+    while (dir != NULL) {
+	size_t dir_len = strlen(dir);
+
+	addincdir(dir, dir);
+
+	/* if it isn't a full path name and there is a 
+	   multi-directory view path */
+	if (*dirlist != '/' && vpndirs > 1) {
+			
+	    /* compute its path from higher view path source dirs */
+	    for (i = 1; i < nvpsrcdirs; ++i) {
+		snprintf(path, sizeof(path), "%.*s/%s", 
+			(int)(PATHLEN - 2 - dir_len),
+			srcdirs[i], dir);
+		addincdir(dir, path);
+	    }
+	}
+	dir = strtok(NULL, DIRSEPS);
+    }
+    free(dirlist);			/* HBB 20000421: avoid leaks */
+}
+
+/* add a #include directory to the list */
+
+static void
+addincdir(char *name, char *path)
+{
+	struct	stat	statstruct;
+
+	/* make sure it is a directory */
+	if (lstat(compath(path), &statstruct) == 0 && 
+	    S_ISDIR(statstruct.st_mode)) {
+		if (incdirs == NULL) {
+			incdirs = malloc(mincdirs * sizeof(*incdirs));
+			incnames = malloc(mincdirs * sizeof(*incnames));
+		} else if (nincdirs == mincdirs) {
+			mincdirs += DIRINC;
+			incdirs = realloc(incdirs, mincdirs * sizeof(*incdirs));
+			incnames = realloc(incnames, mincdirs * sizeof(*incnames));
+		}
+		incdirs[nincdirs] = strdup(path);
+		incnames[nincdirs++] = strdup(name);
+	}
+}
+
+/* HBB 2000421: new function, for avoiding memory leaks */
+/* free the list of include files, if wanted */
+
+void
+freeinclist()
+{
+	if (!incdirs)	
+		return;
+	while(nincdirs>0) {
+		free(incdirs[--nincdirs]);
+		free(incnames[nincdirs]);
+	}
+	free(incdirs);
+	free(incnames);
+}
+
+/* make the source file list */
+
+void
+makefilelist(void)
+{
+    static  BOOL    firstbuild = YES;       /* first time through */
+    FILE    *names;                 /* name file pointer */
+    char    dir[PATHLEN + 1];
+    char    path[PATHLEN + 1];
+    char    line[PATHLEN * 10];
+    char    *file;
+    char    *s;
+    unsigned int i;
+
+    makevpsrcdirs();	/* make the view source directory list */
+
+    /* if -i was NOT given and there are source file arguments */
+    if (namefile == NULL && fileargc > 0) {
+		
+	/* put them in a list that can be expanded */
+	for (i = 0; i < fileargc; ++i) {
+	    file = fileargv[i];
+	    if (infilelist(file) == NO) {
+		if ((s = inviewpath(file)) != NULL) {
+		    addsrcfile(s);
+		} else {
+		    fprintf(stderr, "cscope: cannot find file %s\n",
+			    file);
+		    errorsfound = YES;
+		}
+	    }
+	}
+	return;
+    }
+
+    /* see if a file name file exists */
+    if (namefile == NULL && vpaccess(NAMEFILE, READ) == 0) {
+	namefile = NAMEFILE;
+    }
+
+    if (namefile == NULL) {
+	/* No namefile --> make a list of all the source files
+	 * in the directories */
+	for (i = 0; i < nsrcdirs; ++i) {
+	    scan_dir(srcdirs[i], recurse_dir);
+	}
+	return;
+    }
+
+    /* Came here --> there is a file of source file names */
+
+    if (strcmp(namefile, "-") == 0)
+	names = stdin;
+    else if ((names = vpfopen(namefile, "r")) == NULL) {
+	cannotopen(namefile);
+	myexit(1);
+    }
+
+    /* get the names in the file */
+    while (fgets(line, 10*PATHLEN, names) != NULL) {
+	char *point_in_line = line + (strlen(line) - 1);
+	size_t length_of_name = 0;
+	int unfinished_option = 0;
+	BOOL done = NO;
+
+	/* Kill away \n left at end of fgets()'d string: */
+	if (*point_in_line == '\n')
+	    *point_in_line = '\0';
+			
+	/* Parse whitespace-terminated strings in line: */
+	point_in_line = line;
+	while (sscanf(point_in_line, "%" PATHLEN_STR "s", path) == 1) {
+	    /* Have to store this length --- inviewpath() will
+	     * modify path, later! */
+	    length_of_name = strlen(path);
+			  
+	    if (*path == '-') {	/* if an option */
+		if (unfinished_option) {
+		    /* Can't have another option directly after an
+		     * -I or -p option with no name after it! */
+		    fprintf(stderr, "\
+cscope: Syntax error in namelist file %s: unfinished -I or -p option\n", 
+			    namefile);
+		    unfinished_option = 0;
+		}
+						
+		i = path[1];
+		switch (i) {
+		case 'c':	/* ASCII characters only in crossref */
+		    compress = NO;
+		    break;
+		case 'k':	/* ignore DFLT_INCDIR */
+		    kernelmode = YES;
+		    break;
+		case 'q':	/* quick search */
+		    invertedindex = YES;
+		    break;
+		case 'T':	/* truncate symbols to 8 characters */
+		    trun_syms = YES;
+		    break;
+		case 'I':	/* #include file directory */
+		case 'p':	/* file path components to display */
+		    /* coverity[overwrite_var] */
+		    s = path + 2;		/* for "-Ipath" */
+		    if (*s == '\0') {	/* if "-I path" */
+			unfinished_option = i;
+			break; 
+		    } 
+
+		    /* this code block used several times in here
+		     * --> make it a macro to avoid unnecessary
+		     * duplication */
+#define HANDLE_OPTION_ARGUMENT(i, s)					\
+		    switch (i) {					\
+		    case 'I':	/* #include file directory */		\
+			if (firstbuild == YES) {			\
+			    /* expand $ and ~ */			\
+			    shellpath(dir, sizeof(dir), (s));		\
+			    includedir(dir);				\
+			}						\
+			unfinished_option = 0;				\
+			done = YES;					\
+			break;						\
+		    case 'p':	/* file path components to display */	\
+			if (*(s) < '0' || *(s) > '9') {			\
+			    fprintf(stderr,				\
+"cscope: -p option in file %s: missing or invalid numeric value\n",	\
+				    namefile);				\
+			}						\
+			dispcomponents = atoi(s);			\
+			unfinished_option = 0;				\
+			done = YES;					\
+			break;						\
+		    default:						\
+			done = NO;					\
+		    } /* switch(i) */
+
+		    /* ... and now call it for the first time */
+		    HANDLE_OPTION_ARGUMENT(i, s)
+			break;
+		default:
+		    fprintf(stderr, "cscope: only -I, -c, -k, -p, and -T options can be in file %s\n", 
+			    namefile);
+		} /* switch(i) */
+	    } /* if('-') */
+	    else if (*path == '"') {
+		/* handle quoted filenames... */
+		size_t in = 1, out = 0;
+		char *newpath = malloc(PATHLEN + 1);
+
+		while (in < PATHLEN && point_in_line[in] != '\0') {
+		    if (point_in_line[in] == '"') {
+			newpath[out] = '\0';
+			/* Tell outer loop to skip over this entire
+			 * quoted string */
+			length_of_name = in + 1;
+			break;	/* found end of quoted string */
+		    } else if (point_in_line[in] == '\\'
+			       && in < PATHLEN - 1
+			       && (point_in_line[in + 1]== '"'
+				   || point_in_line[in + 1] == '\\')) {
+			/* un-escape \" or \\ sequence */
+			newpath[out++] = point_in_line[in + 1];
+			in += 2;
+		    } else {
+			newpath[out++] = point_in_line[in++];
+		    }
+		} /* while(in) */ 
+		if (in >= PATHLEN) { /* safeguard against almost-overflow */
+		    newpath[out]='\0';
+		}
+
+		/* If an -I or -p arguments was missing before,
+		 * treat this name as the argument: */
+		HANDLE_OPTION_ARGUMENT(unfinished_option, newpath);
+		if (! done) {
+		    /* coverity[overwrite_var] */
+		    if ((s = inviewpath(newpath)) != NULL) {
+			addsrcfile(s);
+		    } else {
+			fprintf(stderr, "cscope: cannot find file %s\n",
+				newpath);
+			errorsfound = YES;
+		    }
+		}
+		free(newpath);
+	    } /* if(quoted name) */
+	    else {
+		/* ... so this is an ordinary file name, unquoted */
+
+		/* If an -I or -p arguments was missing before,
+		 * treat this name as the argument: */
+		HANDLE_OPTION_ARGUMENT(unfinished_option, path);
+		if (!done) {
+		    if ((s = inviewpath(path)) != NULL) {
+			addsrcfile(s);
+		    } else {
+			fprintf(stderr, "cscope: cannot find file %s\n",
+				path);
+			errorsfound = YES;
+		    }
+		}
+	    } /* else(ordinary name) */
+
+	    point_in_line += length_of_name;
+	    while (isspace((unsigned char) *point_in_line))
+		point_in_line ++;
+	} /* while(sscanf(line)) */
+    } /* while(fgets(line)) */
+
+    if (names == stdin)
+	clearerr(stdin);
+    else
+	fclose(names);
+    firstbuild = NO;
+    return;
+
+}
+
+/* scan a directory (recursively?) for source files */
+static void
+scan_dir(const char *adir, BOOL recurse_dir)
+{
+	DIR	*dirfile;
+	int adir_len = strlen(adir);
+
+	/* FIXME: no guards against adir_len > PATHLEN, yet */
+
+	if ((dirfile = opendir(adir)) != NULL) {
+		struct dirent *entry;
+		char	path[PATHLEN + 1];
+
+		while ((entry = readdir(dirfile)) != NULL) { 
+			if ((strcmp(".",entry->d_name) != 0)
+			    && (strcmp("..",entry->d_name) != 0)) {
+				struct stat buf;
+
+				snprintf(path, sizeof(path), "%s/%.*s", adir,
+					PATHLEN - 2 - adir_len,
+					entry->d_name);
+
+				if (lstat(path,&buf) == 0) {
+					if (recurse_dir 
+                                            && S_ISDIR(buf.st_mode) ) {
+						scan_dir(path, recurse_dir);
+					} else if (issrcfile(path)
+						   && infilelist(path) == NO
+						   && access(path, R_OK) == 0) {
+						addsrcfile(path);
+					}
+				}
+			}
+		}
+		closedir(dirfile);
+	}
+        return;
+}
+
+
+/* see if this is a source file */
+static BOOL
+issrcfile(char *path)
+{
+	struct	stat	statstruct;
+	char	*file = basename(path);
+	char	*s = strrchr(file, '.');
+	BOOL looks_like_source = NO;
+
+	/* ensure there is some file suffix */
+	if (s == NULL || *++s == '\0')
+		return NO;
+
+	/* if an SCCS or versioned file */
+	if (file[1] == '.' && file + 2 != s) { /* 1 character prefix */
+		switch (*file) {
+		case 's':
+		case 'S':
+			return(NO);
+		}
+	}
+
+	if (s[1] == '\0') {	/* 1 character suffix */
+		switch (*s) {
+		case 'c':
+		case 'h':
+		case 'l':
+		case 'y':
+		case 'C':
+		case 'G':
+		case 'H':
+		case 'L':
+			looks_like_source = YES;
+		}
+	} else if ((s[2] == '\0') /* 2 char suffix */
+		   && ((s[0] == 'b' && s[1] == 'p') /* breakpoint listing */
+		       || (s[0] == 'q' 
+			   && (s[1] == 'c' || s[1] == 'h')) /* Ingres */
+		       || (s[0] == 's' && s[1] == 'd') /* SDL */
+		       || (s[0] == 'c' && s[1] == 'c') /* C++ source */
+		       || (s[0] == 'h' && s[1] == 'h'))) { /* C++ header */
+		looks_like_source = YES;
+			
+	} else if((s[3] == '\0') /* 3 char suffix */
+		  /* C++ template source */
+		  && ((s[0] == 't' && s[1] == 'c' && s[2] == 'c' )
+		      /* C++ source: */
+		      || (s[0] == 'c' && s[1] == 'p' && s[2] == 'p' )
+		      || (s[0] == 'c' && s[1] == 'x' && s[2] == 'x' )
+		      || (s[0] == 'h' && s[1] == 'p' && s[2] == 'p' )
+		      || (s[0] == 'h' && s[1] == 'x' && s[2] == 'x' ))
+		  ) {
+		looks_like_source = YES;
+	}
+
+	if (looks_like_source != YES)
+		return NO;
+	
+	/* make sure it is a file */
+	if (lstat(path, &statstruct) == 0 && 
+	    S_ISREG(statstruct.st_mode)) {
+		return(YES);
+	}
+	return NO;
+}
+
+
+/* add an include file to the source file list */
+void
+incfile(char *file, char *type)
+{
+    char    name[PATHLEN + 1];
+    char    path[PATHLEN + 1];
+    char    *s;
+    unsigned int i;
+
+    assert(file != NULL); /* should never happen, but let's make sure anyway */
+    /* see if the file is already in the source file list */
+    if (infilelist(file) == YES) {
+	return;
+    }
+    /* look in current directory if it was #include "file" */
+    if (type[0] == '"' && (s = inviewpath(file)) != NULL) {
+	addsrcfile(s);
+    } else {
+	size_t file_len = strlen(file);
+
+	/* search for the file in the #include directory list */
+	for (i = 0; i < nincdirs; ++i) {
+	    /* don't include the file from two directories */
+	    snprintf(name, sizeof(name), "%.*s/%s",
+		    (int)(PATHLEN - 2 - file_len), incnames[i],
+		    file);
+	    if (infilelist(name) == YES) {
+		break;
+	    }
+	    /* make sure it exists and is readable */
+	    snprintf(path, sizeof(path), "%.*s/%s",
+		    (int)(PATHLEN - 2 - file_len), incdirs[i],
+		    file);
+	    if (access(compath(path), READ) == 0) {
+		addsrcfile(path);
+		break;
+	    }
+	}
+    }
+}
+
+
+/* see if the file is already in the list */
+BOOL
+infilelist(char *path)
+{
+    struct listitem *p;
+
+    for (p = srcnames[hash(compath(path)) % HASHMOD];
+	 p != NULL;
+	 p = p->next) {
+	if (strequal(path, p->text)) {
+	    return(YES);
+	}
+    }
+    return(NO);
+}
+
+
+/* check if a file is readable enough to be allowed in the
+ * database */
+static BOOL
+accessible_file(char *file)
+{
+    if (access(compath(file), READ) == 0) {
+	struct stat stats;
+
+	if (lstat(file, &stats) == 0
+	    && S_ISREG(stats.st_mode)) {
+	    return YES;
+	}
+    }
+    return NO;
+}
+
+/* search for the file in the view path */
+char *
+inviewpath(char *file)
+{
+    static char	path[PATHLEN + 1];
+    unsigned int i;
+
+    /* look for the file */
+    if (accessible_file(file)) {
+	return(file);
+    }
+
+    /* if it isn't a full path name and there is a multi-directory
+     * view path */
+    if (*file != '/' && vpndirs > 1) {
+	int file_len = strlen(file);
+
+	/* compute its path from higher view path source dirs */
+	for (i = 1; i < nvpsrcdirs; ++i) {
+	    snprintf(path, sizeof(path), "%.*s/%s",
+		    PATHLEN - 2 - file_len, srcdirs[i],
+		    file);
+	    if (accessible_file(path)) {
+		return(path);
+	    }
+	}
+    }
+    return(NULL);
+}
+
+/* add a source file to the list */
+
+void
+addsrcfile(char *path)
+{
+	struct	listitem *p;
+	int	i;
+	
+	/* make sure there is room for the file */
+	if (nsrcfiles == msrcfiles) {
+		msrcfiles += SRCINC;
+		srcfiles = realloc(srcfiles, msrcfiles * sizeof(*srcfiles));
+	}
+	/* add the file to the list */
+	srcfiles[nsrcfiles++] = strdup(compath(path));
+	p = malloc(sizeof(*p));
+	p->text = strdup(compath(path));
+	i = hash(p->text) % HASHMOD;
+	p->next = srcnames[i];
+	srcnames[i] = p;
+}
+
+/* free the memory allocated for the source file list */
+
+void
+freefilelist(void)
+{
+	struct	listitem *p, *nextp;
+	int	i;
+
+	/* if '-d' option is used a string space block is allocated */	
+	if (isuptodate == NO) {
+		while (nsrcfiles > 0) {
+			free (srcfiles[--nsrcfiles]);
+		}
+	} else {
+		/* for '-d' option free the string space block */
+		/* protect against empty list */
+		if (nsrcfiles > 0)
+			free (srcfiles[0]);
+		nsrcfiles = 0;
+	}
+
+	free (srcfiles);     /* HBB 20000421: avoid leak */
+	msrcfiles = 0;
+	srcfiles=0;
+	
+	for (i = 0; i < HASHMOD; ++i) {
+		for (p = srcnames[i]; p != NULL; p = nextp) {
+			/* HBB 20000421: avoid memory leak */
+			free(p->text);
+			nextp = p->next;
+			free(p);
+		}
+		srcnames[i] = NULL;
+	}
+}
diff --git a/src/display.c b/src/display.c
new file mode 100644
index 0000000..b28fdef
--- /dev/null
+++ b/src/display.c
@@ -0,0 +1,784 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	display functions
+ */
+
+#include "global.h"
+#include "build.h"
+
+#ifdef CCS
+#include "sgs.h"	/* ESG_PKG and ESG_REL */
+#else
+#include "version.h"	/* FILEVERSION and FIXVERSION */
+#endif
+
+#include <ncurses.h>
+#include <setjmp.h>	/* jmp_buf */
+#include <stdarg.h>	/* va_list stuff */
+#include <time.h>
+#include <errno.h>
+#include <stdarg.h>
+
+int	booklen;		/* OGS book name display field length */
+int	*displine;		/* screen line of displayed reference */
+unsigned int disprefs;		/* displayed references */
+int	field;			/* input field */
+int	filelen;		/* file name display field length */
+int	fcnlen;			/* function name display field length */
+unsigned int mdisprefs;		/* maximum displayed references */
+unsigned int nextline;		/* next line to be shown */
+FILE	*nonglobalrefs;		/* non-global references file */
+int	numlen;			/* line number display field length */
+unsigned int topline = 1;		/* top line of page */
+int	bottomline;		/* bottom line of page */
+long	searchcount;		/* count of files searched */
+int	subsystemlen;		/* OGS subsystem name display field length */
+unsigned int totallines;	/* total reference lines */
+unsigned fldcolumn;		/* input field column */
+WINDOW* body;
+WINDOW* input_fields;
+
+static enum {
+	CH_BODY = 0x0001,
+	CH_INPUT_FIELDS = CH_BODY << 1,
+	CH_COMMAND_FIELD = CH_BODY << 2,
+	CH_ALL = CH_BODY | CH_INPUT_FIELDS | CH_COMMAND_FIELD
+};
+
+const char	dispchars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+static	int	fldline;		/* input field line */
+static	sigjmp_buf	env;		/* setjmp/longjmp buffer */
+static	int	lastdispline;		/* last displayed reference line */
+static	char	lastmsg[MSGLEN + 1];	/* last message displayed */
+static	const char	helpstring[] = "Press the ? key for help";
+static	const char	selprompt[] = 
+	"Select lines to change (press the ? key for help): ";
+
+typedef char * (*FP)(char *);	/* pointer to function returning a character pointer */
+
+/* HBB 2000/05/05: I removed the casts to function pointer type. It is
+ * fundamentally unsafe to call a function through a pointer of a
+ * different type ('undefined behaviour' in the words of the ANSI/ISO
+ * C standard).  Instead, I made all the find...() functions adhere to
+ * the same function type, by changing argument passing a bit. */
+static	struct	{		/* text of input fields */
+	char	*text1;
+	char	*text2;
+	FP	findfcn;
+} fields[FIELDS + 1] = {	/* samuel has a search that is not part of the cscope display */
+	{"Find this", "C symbol",			findsymbol},
+	{"Find this", "global definition",		finddef},
+	{"Find", "functions called by this function",	findcalledby},
+	{"Find", "functions calling this function",	findcalling},
+	{"Find this", "text string",			findstring},
+	{"Change this", "text string",			findstring},
+	{"Find this", "egrep pattern",			findregexp},
+	{"Find this", "file",				findfile},
+	{"Find", "files #including this file",		findinclude},
+	{"Find", "assignments to this symbol", 		findassign},
+	{"Find all", "function definitions",		findallfcns},	/* samuel only */
+};
+
+/* Internal prototypes: */
+static	void	jumpback(int sig);
+
+/* initialize display parameters */
+
+void
+dispinit(void)
+{
+	/* initialize the curses display package */
+	initscr();	/* initialize the screen */
+	entercurses();
+	keypad(stdscr, TRUE);	/* enable the keypad */
+	//fixkeypad();	/* fix for getch() intermittently returning garbage */
+	standend();	/* turn off reverse video */
+
+	/* calculate the maximum displayed reference lines */
+	lastdispline = FLDLINE - 3;
+	mdisprefs = lastdispline - REFLINE + 1;
+
+
+	if (mdisprefs <= 0) {
+		postfatal("%s: screen too small\n", argv0);
+		/* NOTREACHED */
+	}
+
+	if (mouse == NO && mdisprefs > strlen(dispchars))
+		mdisprefs = strlen(dispchars);
+
+	/* allocate the displayed line array */
+	displine = malloc(mdisprefs * sizeof(*displine));
+
+	/* initialize windows */
+	body = newwin(LINES-2-FIELDS, COLS-2, 1, 1);
+	input_fields = newwin(FIELDS, COLS-2, FLDLINE, 1);
+    refresh();
+}
+
+static inline void display_frame(){
+
+	box(stdscr, 0, 0);
+	/* Title*/
+	const int LEFT_PADDING = 5;
+	wmove(stdscr, 0, LEFT_PADDING);
+#if CCS
+	if (displayversion == YES) {
+	    wprintw(stdscr, "cscope %s", ESG_REL);
+	}
+	else {
+	    waddstr(stdscr, "cscope");
+	}
+#else
+	wprintw(stdscr, "Cscope version %d%s", FILEVERSION, FIXVERSION);
+#endif
+	wmove(stdscr, 0, COLS - (int) sizeof(helpstring));
+	waddstr(stdscr, helpstring);
+	wmove(input_fields, 0, 0);
+	for(int i = 0; i < COLS-2; i++){
+		waddch(input_fields, ACS_HLINE);
+	}
+}
+
+static inline void display_input_fields(){
+    /* display the input fields */
+    wmove(input_fields, 1, 0);
+    for(int i = 0; i < FIELDS; ++i){
+		wprintw(input_fields, "%s %s:\n", fields[i].text1, fields[i].text2);
+    }
+}
+
+static inline void display_command_field(){
+
+}
+
+void
+display(void)
+{
+    char    *subsystem;             /* OGS subsystem name */
+    char    *book;                  /* OGS book name */
+    char    file[PATHLEN + 1];      /* file name */
+    char    function[PATLEN + 1];   /* function name */
+    char    linenum[NUMLEN + 1];    /* line number */
+    int     screenline;             /* screen line number */
+    int     width;                  /* source line display width */
+    int     i;
+    char    *s;
+
+    erase();
+	display_frame();
+
+    if (totallines == 0) {
+	/* if no references were found */
+	/* redisplay the last message */
+	waddstr(body, lastmsg);
+    } else {
+	/* display the pattern */
+	if (changing == YES) {
+	    wprintw(body, "Change \"%s\" to \"%s\"", Pattern, newpat);
+	} else {
+	    wprintw(body, "%c%s: %s", toupper((unsigned char)fields[field].text2[0]),
+		   fields[field].text2 + 1, Pattern);
+	}
+	/* display the column headings */
+	wmove(body, 2, 2);
+	if (ogs == YES && field != FILENAME) {
+	    wprintw(body, "%-*s ", subsystemlen, "Subsystem");
+	    wprintw(body, "%-*s ", booklen, "Book");
+	}
+	if (dispcomponents > 0)
+	    wprintw(body, "%-*s ", filelen, "File");
+
+	if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
+	    wprintw(body, "%-*s ", fcnlen, "Function");
+	}
+	if (field != FILENAME) {
+	    waddstr(body, "Line");
+	}
+	waddch(body, '\n');
+
+	/* if at end of file go back to beginning */
+	if (nextline > totallines) {
+	    seekline(1);
+	}
+	/* calculate the source text column */
+
+	width = COLS - numlen - 3;
+
+	if (ogs == YES) {
+	    width -= subsystemlen + booklen + 2;
+	}
+	if (dispcomponents > 0) {
+	    width -= filelen + 1;
+	}
+	if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
+	    width -= fcnlen + 1;
+	}
+
+	/* until the max references have been displayed or 
+	   there is no more room */
+	topline = nextline;
+	for (disprefs = 0, screenline = REFLINE;
+	     disprefs < mdisprefs && screenline <= lastdispline;
+	     ++disprefs, ++screenline) {
+	    /* read the reference line */
+	    if (fscanf(refsfound, "%" PATHLEN_STR "s%" PATHLEN_STR "s%" NUMLEN_STR "s %" TEMPSTRING_LEN_STR "[^\n]", file, function, 
+		       linenum, tempstring) < 4) {
+		break;
+	    }
+	    ++nextline;
+	    displine[disprefs] = screenline;
+			
+	    /* if no mouse, display the selection number */
+	    if (mouse == YES) {
+		waddch(body, ' ');
+	    } else {
+		wprintw(body, "%c", dispchars[disprefs]);
+	    }
+
+	    /* display any change mark */
+	    if (changing == YES && 
+		change[topline + disprefs - 1] == YES) {
+		waddch(body, '>');
+	    } else {
+		waddch(body, ' ');
+	    }
+
+	    /* display the file name */
+	    if (field == FILENAME) {
+		wprintw(body, "%-*s ", filelen, file);
+	    } else {
+		/* if OGS, display the subsystem and book names */
+		if (ogs == YES) {
+		    ogsnames(file, &subsystem, &book);
+		    wprintw(body, "%-*.*s ", subsystemlen, subsystemlen, subsystem);
+		    wprintw(body, "%-*.*s ", booklen, booklen, book);
+		}
+		/* display the requested path components */
+		if (dispcomponents > 0) {
+		    wprintw(body, "%-*.*s ", filelen, filelen,
+			   pathcomponents(file, dispcomponents));
+		}
+	    } /* else(field == FILENAME) */
+
+	    /* display the function name */
+	    if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
+		wprintw(body, "%-*.*s ", fcnlen, fcnlen, function);
+	    }
+	    if (field == FILENAME) {
+		waddch(body, '\n');	/* go to next line */
+		continue;
+	    }
+
+	    /* display the line number */
+	    wprintw(body, "%*s ", numlen, linenum);
+	    /* there may be tabs in egrep output */
+	    while ((s = strchr(tempstring, '\t')) != NULL) {
+		*s = ' ';
+	    }
+
+	    /* display the source line */
+	    s = tempstring;
+	    for (;;) {
+		/* see if the source line will fit */
+		if ((i = strlen(s)) > width) {
+					
+		    /* find the nearest blank */
+		    for (i = width; s[i] != ' ' && i > 0; --i) {
+			;
+		    }
+		    if (i == 0) {
+			i = width;	/* no blank */
+		    }
+		}
+		/* print up to this point */
+		wprintw(body, "%.*s", i, s);
+		s += i;
+				
+		/* if line didn't wrap around */
+		if (i < width) {
+		    waddch(body, '\n');	/* go to next line */
+		}
+		/* skip blanks */
+		while (*s == ' ') {
+		    ++s;
+		}
+		/* see if there is more text */
+		if (*s == '\0') {
+		    break;
+		}
+		/* if the source line is too long */
+		if (++screenline > lastdispline) {
+
+		    /* if this is the first displayed line,
+		       display what will fit on the screen */
+		    if (topline == nextline -1) {
+			disprefs++;
+			/* break out of two loops */
+			goto endrefs;
+		    }
+					
+		    /* erase the reference */
+		    while (--screenline >= displine[disprefs]) {
+			wmove(body, screenline, 0);
+			clrtoeol();
+		    }
+		    ++screenline;
+					 
+		    /* go back to the beginning of this reference */
+		    --nextline;
+		    seekline(nextline);
+		    goto endrefs;
+		}
+		/* indent the continued source line */
+		wmove(body, screenline, COLS - width);
+	    } /* for(ever) */
+	} /* for(reference output lines) */
+    endrefs:
+	/* position the cursor for the message */
+	i = FLDLINE - 1;
+	if (screenline < i) {
+	    waddch(body, '\n');
+	}
+	else {
+	    wmove(body, i, 0);
+	}
+	/* check for more references */
+	i = totallines - nextline + 1;
+	bottomline = nextline;
+	if (i > 0) {
+	    wprintw(body, "* Lines %d-%d of %d, %d more - press the space bar to display more *", topline, bottomline, totallines, i);
+	}
+	/* if this is the last page of references */
+	else if (topline > 1 && nextline > totallines) {
+	    waddstr(body, "* Press the space bar to display the first lines again *");
+	}
+    }
+    drawscrollbar(topline, nextline);	/* display the scrollbar */
+
+	atfield();
+
+	display_input_fields();
+	display_prompt();
+
+    refresh();
+    wrefresh(body);
+    wrefresh(input_fields);
+}
+
+/* set the cursor position for the field */
+//void
+//setfield(void)
+//{
+//	fldline = FLDLINE + field;
+//	fldcolumn = strlen(fields[field].text1) + strlen(fields[field].text2) + 3;
+//}
+
+/* move to the current input field */
+//
+//void
+//atfield(void)
+//{
+//	wmove(input_fields, fldline, fldcolumn);
+//}
+
+/* move to the changing lines prompt */
+
+//void
+//atchange(void)
+//{
+//	wmove(body, PRLINE, (int) sizeof(selprompt) - 1);
+//}
+
+/* search for the symbol or text pattern */
+
+/*ARGSUSED*/
+static void
+jumpback(int sig)
+{
+	signal(sig, jumpback);
+	siglongjmp(env, 1);
+}
+
+BOOL
+search(void)
+{
+	char	*findresult = NULL;	/* find function output */
+	BOOL	funcexist = YES;		/* find "function" error */
+	FINDINIT rc = NOERROR;		/* findinit return code */
+	sighandler_t savesig;		/* old value of signal */
+	FP	f;			/* searching function */
+	int	c;
+	
+	/* open the references found file for writing */
+	if (writerefsfound() == NO) {
+		return(NO);
+	}
+	/* find the pattern - stop on an interrupt */
+	if (linemode == NO) {
+		postmsg("Searching");
+	}
+	searchcount = 0;
+	savesig = signal(SIGINT, jumpback);
+	if (sigsetjmp(env, 1) == 0) {
+		f = fields[field].findfcn;
+		if (f == findregexp || f == findstring) {
+			findresult = (*f)(Pattern);
+		} else {
+			if ((nonglobalrefs = myfopen(temp2, "wb")) == NULL) {
+				cannotopen(temp2);
+				return(NO);
+			}
+			if ((rc = findinit(Pattern)) == NOERROR) {
+				(void) dbseek(0L); /* read the first block */
+				findresult = (*f)(Pattern);
+				if (f == findcalledby) 
+					funcexist = (*findresult == 'y');
+				findcleanup();
+
+				/* append the non-global references */
+				(void) fclose(nonglobalrefs);
+				if ((nonglobalrefs = myfopen(temp2, "rb"))
+				     == NULL) {
+					cannotopen(temp2);
+					return(NO);
+				}
+				while ((c = getc(nonglobalrefs)) != EOF) {
+					(void) putc(c, refsfound);
+				}
+			}
+			(void) fclose(nonglobalrefs);
+		}
+	}
+	signal(SIGINT, savesig);
+
+	/* rewind the cross-reference file */
+	(void) lseek(symrefs, (long) 0, 0);
+	
+	/* reopen the references found file for reading */
+	(void) fclose(refsfound);
+	if ((refsfound = myfopen(temp1, "rb")) == NULL) {
+		cannotopen(temp1);
+		return(NO);
+	}
+	nextline = 1;
+	totallines = 0;
+	disprefs = 0;
+	
+	/* see if it is empty */
+	if ((c = getc(refsfound)) == EOF) {
+		if (findresult != NULL) {
+			(void) snprintf(lastmsg, sizeof(lastmsg), "Egrep %s in this pattern: %s", 
+				       findresult, Pattern);
+		} else if (rc == NOTSYMBOL) {
+			(void) snprintf(lastmsg, sizeof(lastmsg), "This is not a C symbol: %s", 
+				       Pattern);
+		} else if (rc == REGCMPERROR) {
+			(void) snprintf(lastmsg, sizeof(lastmsg), "Error in this regcomp(3) regular expression: %s", 
+				       Pattern);
+			
+		} else if (funcexist == NO) {
+			(void) snprintf(lastmsg, sizeof(lastmsg), "Function definition does not exist: %s", 
+				       Pattern);
+		} else {
+			(void) snprintf(lastmsg, sizeof(lastmsg), "Could not find the %s: %s", 
+				       fields[field].text2, Pattern);
+		}
+		return(NO);
+	}
+	/* put back the character read */
+	(void) ungetc(c, refsfound);
+
+	/* HBB 20041027: this used to hold a copy of the code of 
+	 * countrefs(), but with the crucial display width adjustments
+	 * missing.  Just call the real thing instead! */
+	countrefs();
+	return(YES);
+}
+
+/* display search progress with default custom format */
+
+void
+progress(char *what, long current, long max)
+{
+	static	long	start;
+	long	now;
+	char	msg[MSGLEN + 1];
+	int	i;
+
+	/* save the start time */
+	if (searchcount == 0) {
+		start = time(NULL);
+	}
+	if ((now = time(NULL)) - start >= 1)
+	{
+		if (linemode == NO)
+		{
+			wmove(body, MSGLINE, 0);
+			clrtoeol();
+			waddstr(body, what);
+			snprintf(msg, sizeof(msg), "%ld", current);
+			wmove(body, MSGLINE, (COLS / 2) - (strlen(msg) / 2));
+			waddstr(body, msg);
+			snprintf(msg, sizeof(msg), "%ld", max);
+			wmove(body, MSGLINE, COLS - strlen(msg));
+			waddstr(body, msg);
+			refresh();
+		}
+		else if (verbosemode == YES)
+		{
+			snprintf(msg, sizeof(msg), "> %s %ld of %ld", what, current, max);
+		}
+
+		start = now;
+		if ((linemode == NO) && (incurses == YES))
+		{
+			wmove(body, MSGLINE, 0);
+			i = (float)COLS * (float)current / (float)max;
+
+			standout();
+			for (; i > 0; i--)
+				waddch(body, inch());
+			standend();
+			refresh();
+		}
+		else
+			if (linemode == NO || verbosemode == YES)
+				postmsg(msg);
+	}
+	++searchcount;
+}
+
+/* print error message on system call failure */
+
+void
+myperror(char *text) 
+{
+	char	msg[MSGLEN + 1];	/* message */
+	char	*s;
+
+    s = strerror(errno);
+
+	(void) snprintf(msg, sizeof(msg), "%s: %s", text, s);
+	postmsg(msg);
+}
+
+/* postmsg clears the message line and prints the message */
+
+/* VARARGS */
+void
+postmsg(char *msg) 
+{
+	if (linemode == YES || incurses == NO) {
+		(void) printf("%s\n", msg);
+		fflush(stdout);
+	}
+	else {
+		clearmsg();
+		waddstr(body, msg);
+		refresh();
+	}
+	(void) strncpy(lastmsg, msg, sizeof(lastmsg) - 1);
+}
+
+/* clearmsg clears the first message line */
+
+void
+clearmsg(void)
+{
+	if (linemode == NO) {
+		wmove(body, MSGLINE, 0);
+		clrtoeol();
+	}
+}
+
+/* clearmsg2 clears the second message line */
+
+void
+clearmsg2(void)
+{
+	if (linemode == NO) {
+		wmove(body, MSGLINE + 1, 0);
+		clrtoeol();
+	}
+}
+
+/* postmsg2 clears the second message line and prints the message */
+
+void
+postmsg2(char *msg) 
+{
+	if (linemode == YES) {
+		(void) printf("%s\n", msg);
+	}
+	else {
+		clearmsg2();
+		waddstr(body, msg);
+		refresh();
+	}
+}
+
+/* display an error mesg - stdout or on second msg line */
+void
+posterr(char *msg, ...) 
+{
+    va_list ap;
+    char errbuf[MSGLEN];
+    
+    va_start(ap, msg);
+    if (linemode == YES || incurses == NO)
+    {
+        (void) vfprintf(stderr, msg, ap); 
+	(void) fputc('\n', stderr);
+    } else {
+        vsnprintf(errbuf, sizeof(errbuf), msg, ap);
+        postmsg2(errbuf); 
+    }
+    va_end(ap);
+}
+
+/* display a fatal error mesg -- stderr *after* shutting down curses */
+void
+postfatal(const char *msg, ...)
+{
+	va_list ap;
+	char errbuf[MSGLEN];
+
+	va_start(ap, msg);
+	vsnprintf(errbuf, sizeof(errbuf), msg, ap);
+	/* restore the terminal to its original mode */
+	if (incurses == YES) {
+		exitcurses();
+	}
+
+	/* display fatal error messages */
+	fprintf(stderr,"%s",errbuf);
+
+	/* shut down */
+	myexit(1);
+}
+
+/* position references found file at specified line */
+
+void
+seekline(unsigned int line) 
+{
+	int	c;
+
+	/* verify that there is a references found file */
+	if (refsfound == NULL) {
+		return;
+	}
+	/* go to the beginning of the file */
+	rewind(refsfound);
+	
+	/* find the requested line */
+	nextline = 1;
+	while (nextline < line && (c = getc(refsfound)) != EOF) {
+		if (c == '\n') {
+			nextline++;
+		}
+	}
+}
+
+/* get the OGS subsystem and book names */
+
+void
+ogsnames(char *file, char **subsystem, char **book)
+{
+	static	char	buf[PATHLEN + 1];
+	char	*s, *slash;
+
+	*subsystem = *book = "";
+	(void) strcpy(buf,file);
+	s = buf;
+	if (*s == '/') {
+		++s;
+	}
+	while ((slash = strchr(s, '/')) != NULL) {
+		*slash = '\0';
+		if ((int)strlen(s) >= 3 && strncmp(slash - 3, ".ss", 3) == 0) {
+			*subsystem = s;
+			s = slash + 1;
+			if ((slash = strchr(s, '/')) != NULL) {
+				*book = s;
+				*slash = '\0';
+			}
+			break;
+		}
+		s = slash + 1;
+	}
+}
+
+/* get the requested path components */
+
+char *
+pathcomponents(char *path, int components)
+{
+	int	i;
+	char	*s;
+	
+	s = path + strlen(path) - 1;
+	for (i = 0; i < components; ++i) {
+		while (s > path && *--s != '/') {
+			;
+		}
+	}
+	if (s > path && *s == '/') {
+		++s;
+	}
+	return(s);
+}
+
+/* open the references found file for writing */
+
+BOOL
+writerefsfound(void)
+{
+	if (refsfound == NULL) {
+		if ((refsfound = myfopen(temp1, "wb")) == NULL) {
+			cannotopen(temp1);
+			return(NO);
+		}
+	} else {
+		(void) fclose(refsfound);
+		if ( (refsfound = myfopen(temp1, "wb")) == NULL) {
+			postmsg("Cannot reopen temporary file");
+			return(NO);
+		}
+	}
+	return(YES);
+}
diff --git a/src/edit.c b/src/edit.c
new file mode 100644
index 0000000..f2935c1
--- /dev/null
+++ b/src/edit.c
@@ -0,0 +1,137 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	file editing functions
+ */
+
+#include "global.h"
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+/* edit this displayed reference */
+
+void
+editref(int i)
+{
+	char	file[PATHLEN + 1];	/* file name */
+	char	linenum[NUMLEN + 1];	/* line number */
+
+	/* verify that there is a references found file */
+	if (refsfound == NULL) {
+		return;
+	}
+	/* get the selected line */
+	seekline(i + topline);
+	
+	/* get the file name and line number */
+	if (fscanf(refsfound, "%" PATHLEN_STR "s%*s%" NUMLEN_STR "s", file, linenum) == 2) {
+		edit(file, linenum);	/* edit it */
+	}
+	seekline(topline);	/* restore the line pointer */
+}
+
+/* edit all references */
+
+void
+editall(void)
+{
+	char	file[PATHLEN + 1];	/* file name */
+	char	linenum[NUMLEN + 1];	/* line number */
+	int	c;
+
+	/* verify that there is a references found file */
+	if (refsfound == NULL) {
+		return;
+	}
+	/* get the first line */
+	seekline(1);
+	
+	/* get each file name and line number */
+	while (fscanf(refsfound, "%" PATHLEN_STR "s%*s%" NUMLEN_STR "s%*[^\n]", file, linenum) == 2) {
+		edit(file, linenum);	/* edit it */
+		if (editallprompt == YES) {
+			addstr("Type ^D to stop editing all lines, or any other character to continue: ");
+			if ((c = mygetch()) == EOF || c == ctrl('D') || c == ctrl('Z')) {
+				break;
+			}
+		}
+	}
+	seekline(topline);
+}
+	
+/* call the editor */
+
+void
+edit(char *file, char *linenum)
+{
+	char	msg[MSGLEN + 1];	/* message */
+	char	plusnum[NUMLEN + 20];	/* line number option: allow space for wordy line# flag */
+	char	*s;
+
+	file = filepath(file);
+	(void) snprintf(msg, sizeof(msg), "%s +%s %s", basename(editor), linenum, file);
+	postmsg(msg);
+	(void) snprintf(plusnum, sizeof(plusnum), lineflag, linenum);
+	/* if this is the more or page commands */
+	if (strcmp(s = basename(editor), "more") == 0 || strcmp(s, "page") == 0) {
+		
+		/* get it to pause after displaying a file smaller than the screen
+		   length */
+		(void) execute(editor, editor, plusnum, file, "/dev/null", NULL);
+	}
+	else if (lineflagafterfile) {
+		(void) execute(editor, editor, file, plusnum, NULL);
+	}
+	else {
+		(void) execute(editor, editor, plusnum, file, NULL);
+	}
+	clear();	/* redisplay screen */
+}
+
+/* if requested, prepend a path to a relative file name */
+
+char *
+filepath(char *file)
+{
+	static	char	path[PATHLEN + 1];
+	
+	if (prependpath != NULL && *file != '/') {
+		(void) snprintf(path, sizeof(path), "%s/%s", prependpath, file);
+		file = path;
+	}
+	return(file);
+}
diff --git a/src/egrep.c b/src/egrep.c
new file mode 100644
index 0000000..b00b40a
--- /dev/null
+++ b/src/egrep.c
@@ -0,0 +1,2053 @@
+/* A Bison parser, made by GNU Bison 3.8.2.  */
+
+/* Bison implementation for Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
+   Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output, and Bison version.  */
+#define YYBISON 30802
+
+/* Bison version string.  */
+#define YYBISON_VERSION "3.8.2"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+
+
+
+/* First part of user prologue.  */
+#line 1 "src/egrep.y"
+
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*
+ * egrep -- fine lines containing a regular expression
+ */
+#line 45 "src/egrep.y"
+
+#include "global.h"
+#include <ctype.h>
+#include <stdio.h>
+
+#include <setjmp.h>	/* jmp_buf */
+
+#define nextch()	(*input++)
+
+#define MAXLIN 350
+#define MAXPOS 4000
+#define NCHARS 256
+#define NSTATES 128
+#define FINAL -1
+static	char gotofn[NSTATES][NCHARS];
+static	int state[NSTATES];
+static	char out[NSTATES];
+static	unsigned int line;
+static	int name[MAXLIN];
+static	unsigned int left[MAXLIN];
+static	unsigned int right[MAXLIN];
+static	unsigned int parent[MAXLIN];
+static	int foll[MAXLIN];
+static	int positions[MAXPOS];
+static	char chars[MAXLIN];
+static	int nxtpos;
+static	int nxtchar;
+static	int tmpstat[MAXLIN];
+static	int initstat[MAXLIN];
+static	int xstate;
+static	int count;
+static	int icount;
+static	char *input;
+static	long lnum;
+static	int iflag;
+static	jmp_buf	env;	/* setjmp/longjmp buffer */
+static	char *message;	/* error message */
+
+/* Internal prototypes: */
+static	void cfoll(int v);
+static	void cgotofn(void);
+static	int cstate(int v);
+static	int member(int symb, int set, int torf);
+static	int notin(int n);
+static	void synerror(void);
+static	void overflo(void);
+static	void add(int *array, int n);
+static	void follow(unsigned int v);
+static	int unary(int x, int d);
+static	int node(int x, int l, int r);
+static	unsigned int cclenter(int x);
+static	unsigned int enter(int x);
+
+static int yylex(void);
+static int yyerror(char *);
+
+#line 165 "y.tab.c"
+
+# ifndef YY_CAST
+#  ifdef __cplusplus
+#   define YY_CAST(Type, Val) static_cast<Type> (Val)
+#   define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+#  else
+#   define YY_CAST(Type, Val) ((Type) (Val))
+#   define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+#  endif
+# endif
+# ifndef YY_NULLPTR
+#  if defined __cplusplus
+#   if 201103L <= __cplusplus
+#    define YY_NULLPTR nullptr
+#   else
+#    define YY_NULLPTR 0
+#   endif
+#  else
+#   define YY_NULLPTR ((void*)0)
+#  endif
+# endif
+
+
+/* Debug traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token kinds.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+  enum yytokentype
+  {
+    YYEMPTY = -2,
+    YYEOF = 0,                     /* "end of file"  */
+    YYerror = 256,                 /* error  */
+    YYUNDEF = 257,                 /* "invalid token"  */
+    CHAR = 258,                    /* CHAR  */
+    DOT = 259,                     /* DOT  */
+    CCL = 260,                     /* CCL  */
+    NCCL = 261,                    /* NCCL  */
+    OR = 262,                      /* OR  */
+    CAT = 263,                     /* CAT  */
+    STAR = 264,                    /* STAR  */
+    PLUS = 265,                    /* PLUS  */
+    QUEST = 266                    /* QUEST  */
+  };
+  typedef enum yytokentype yytoken_kind_t;
+#endif
+/* Token kinds.  */
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYerror 256
+#define YYUNDEF 257
+#define CHAR 258
+#define DOT 259
+#define CCL 260
+#define NCCL 261
+#define OR 262
+#define CAT 263
+#define STAR 264
+#define PLUS 265
+#define QUEST 266
+
+/* Value type.  */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+
+int yyparse (void);
+
+
+
+/* Symbol kind.  */
+enum yysymbol_kind_t
+{
+  YYSYMBOL_YYEMPTY = -2,
+  YYSYMBOL_YYEOF = 0,                      /* "end of file"  */
+  YYSYMBOL_YYerror = 1,                    /* error  */
+  YYSYMBOL_YYUNDEF = 2,                    /* "invalid token"  */
+  YYSYMBOL_CHAR = 3,                       /* CHAR  */
+  YYSYMBOL_DOT = 4,                        /* DOT  */
+  YYSYMBOL_CCL = 5,                        /* CCL  */
+  YYSYMBOL_NCCL = 6,                       /* NCCL  */
+  YYSYMBOL_OR = 7,                         /* OR  */
+  YYSYMBOL_CAT = 8,                        /* CAT  */
+  YYSYMBOL_STAR = 9,                       /* STAR  */
+  YYSYMBOL_PLUS = 10,                      /* PLUS  */
+  YYSYMBOL_QUEST = 11,                     /* QUEST  */
+  YYSYMBOL_12_ = 12,                       /* '('  */
+  YYSYMBOL_13_ = 13,                       /* ')'  */
+  YYSYMBOL_YYACCEPT = 14,                  /* $accept  */
+  YYSYMBOL_s = 15,                         /* s  */
+  YYSYMBOL_t = 16,                         /* t  */
+  YYSYMBOL_b = 17,                         /* b  */
+  YYSYMBOL_r = 18                          /* r  */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
+
+
+
+
+#ifdef short
+# undef short
+#endif
+
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+   <limits.h> and (if available) <stdint.h> are included
+   so that the code can choose integer types of a good width.  */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+#  include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+#  define YY_STDINT_H
+# endif
+#endif
+
+/* Narrow types that promote to a signed type and that can represent a
+   signed or unsigned integer of at least N bits.  In tables they can
+   save space and decrease cache pressure.  Promoting to a signed type
+   helps avoid bugs in integer arithmetic.  */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
+#else
+typedef short yytype_int16;
+#endif
+
+/* Work around bug in HP-UX 11.23, which defines these macros
+   incorrectly for preprocessor constants.  This workaround can likely
+   be removed in 2023, as HPE has promised support for HP-UX 11.23
+   (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of
+   <https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA4-7673ENW.pdf>.  */
+#ifdef __hpux
+# undef UINT_LEAST8_MAX
+# undef UINT_LEAST16_MAX
+# define UINT_LEAST8_MAX 255
+# define UINT_LEAST16_MAX 65535
+#endif
+
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
+#else
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+#  define YYPTRDIFF_T __PTRDIFF_TYPE__
+#  define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+#  ifndef ptrdiff_t
+#   include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  endif
+#  define YYPTRDIFF_T ptrdiff_t
+#  define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+#  define YYPTRDIFF_T long
+#  define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM                                  \
+  YY_CAST (YYPTRDIFF_T,                                 \
+           (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1)  \
+            ? YYPTRDIFF_MAXIMUM                         \
+            : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int8 yy_state_t;
+
+/* State numbers in computations.  */
+typedef int yy_state_fast_t;
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(Msgid) Msgid
+# endif
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+#  define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YY_USE(E) ((void) (E))
+#else
+# define YY_USE(E) /* empty */
+#endif
+
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
+# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
+#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
+# else
+#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# endif
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
+    _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN                          \
+    _Pragma ("GCC diagnostic push")                            \
+    _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END            \
+    _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
+#if !defined yyoverflow
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's 'empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
+       && ! ((defined YYMALLOC || defined malloc) \
+             && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* !defined yyoverflow */
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+         || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yy_state_t yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
+    do                                                                  \
+      {                                                                 \
+        YYPTRDIFF_T yynewbytes;                                         \
+        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+        Stack = &yyptr->Stack_alloc;                                    \
+        yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / YYSIZEOF (*yyptr);                        \
+      }                                                                 \
+    while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(Dst, Src, Count) \
+      __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
+#  else
+#   define YYCOPY(Dst, Src, Count)              \
+      do                                        \
+        {                                       \
+          YYPTRDIFF_T yyi;                      \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (Dst)[yyi] = (Src)[yyi];            \
+        }                                       \
+      while (0)
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  6
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   108
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  14
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  5
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  18
+/* YYNSTATES -- Number of states.  */
+#define YYNSTATES  25
+
+/* YYMAXUTOK -- Last valid token kind.  */
+#define YYMAXUTOK   266
+
+
+/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex, with out-of-bounds checking.  */
+#define YYTRANSLATE(YYX)                                \
+  (0 <= (YYX) && (YYX) <= YYMAXUTOK                     \
+   ? YY_CAST (yysymbol_kind_t, yytranslate[YYX])        \
+   : YYSYMBOL_YYUNDEF)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex.  */
+static const yytype_int8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+      12,    13,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11
+};
+
+#if YYDEBUG
+/* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
+static const yytype_uint8 yyrline[] =
+{
+       0,   103,   103,   108,   110,   112,   114,   118,   121,   123,
+     125,   127,   131,   133,   135,   137,   139,   141,   143
+};
+#endif
+
+/** Accessing symbol of state STATE.  */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if YYDEBUG || 0
+/* The user-facing name of the symbol whose (internal) number is
+   YYSYMBOL.  No bounds checking.  */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "\"end of file\"", "error", "\"invalid token\"", "CHAR", "DOT", "CCL",
+  "NCCL", "OR", "CAT", "STAR", "PLUS", "QUEST", "'('", "')'", "$accept",
+  "s", "t", "b", "r", YY_NULLPTR
+};
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+  return yytname[yysymbol];
+}
+#endif
+
+#define YYPACT_NINF (-5)
+
+#define yypact_value_is_default(Yyn) \
+  ((Yyn) == YYPACT_NINF)
+
+#define YYTABLE_NINF (-14)
+
+#define yytable_value_is_error(Yyn) \
+  0
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+static const yytype_int8 yypact[] =
+{
+       2,    -5,     3,    -5,     1,     1,    -5,    -5,    -5,    -5,
+      -5,    -5,     1,    47,    60,    72,    86,    -5,    -5,    -5,
+      19,    96,     1,    -5,    33
+};
+
+/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE does not specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_int8 yydefact[] =
+{
+       7,     7,     0,     2,     0,     0,     1,    18,     8,     9,
+      10,    11,     0,     0,     0,     0,     0,    14,    15,    16,
+       0,     0,     0,    17,     0
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+      -5,    -5,    -5,     9,    -4
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+       0,     2,     3,     4,    20
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule whose
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
+static const yytype_int8 yytable[] =
+{
+      13,    14,     7,     6,     8,     9,    10,    11,    15,     1,
+       5,     0,    24,    12,     0,     0,     0,    24,    24,   -13,
+       7,     0,   -13,   -13,   -13,   -13,   -13,     0,    17,    18,
+      19,   -13,   -13,   -12,     7,     0,     8,     9,    10,    11,
+     -12,     0,    17,    18,    19,    12,   -12,    -3,     7,     0,
+       8,     9,    10,    11,    16,     0,    17,    18,    19,    12,
+      -5,     7,     0,     8,     9,    10,    11,    21,     0,    17,
+      18,    19,    12,     7,     0,     8,     9,    10,    11,    22,
+       0,    17,    18,    19,    12,    23,    -6,     7,     0,     8,
+       9,    10,    11,     0,     0,     0,    -4,     7,    12,     8,
+       9,    10,    11,     0,     0,     0,     0,     0,    12
+};
+
+static const yytype_int8 yycheck[] =
+{
+       4,     5,     1,     0,     3,     4,     5,     6,    12,     7,
+       1,    -1,    16,    12,    -1,    -1,    -1,    21,    22,     0,
+       1,    -1,     3,     4,     5,     6,     7,    -1,     9,    10,
+      11,    12,    13,     0,     1,    -1,     3,     4,     5,     6,
+       7,    -1,     9,    10,    11,    12,    13,     0,     1,    -1,
+       3,     4,     5,     6,     7,    -1,     9,    10,    11,    12,
+       0,     1,    -1,     3,     4,     5,     6,     7,    -1,     9,
+      10,    11,    12,     1,    -1,     3,     4,     5,     6,     7,
+      -1,     9,    10,    11,    12,    13,     0,     1,    -1,     3,
+       4,     5,     6,    -1,    -1,    -1,     0,     1,    12,     3,
+       4,     5,     6,    -1,    -1,    -1,    -1,    -1,    12
+};
+
+/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
+   state STATE-NUM.  */
+static const yytype_int8 yystos[] =
+{
+       0,     7,    15,    16,    17,    17,     0,     1,     3,     4,
+       5,     6,    12,    18,    18,    18,     7,     9,    10,    11,
+      18,     7,     7,    13,    18
+};
+
+/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM.  */
+static const yytype_int8 yyr1[] =
+{
+       0,    14,    15,    16,    16,    16,    16,    17,    18,    18,
+      18,    18,    18,    18,    18,    18,    18,    18,    18
+};
+
+/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM.  */
+static const yytype_int8 yyr2[] =
+{
+       0,     2,     1,     2,     4,     3,     3,     0,     1,     1,
+       1,     1,     3,     2,     2,     2,     2,     3,     1
+};
+
+
+enum { YYENOMEM = -2 };
+
+#define yyerrok         (yyerrstatus = 0)
+#define yyclearin       (yychar = YYEMPTY)
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrorlab
+#define YYNOMEM         goto yyexhaustedlab
+
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                    \
+  do                                                              \
+    if (yychar == YYEMPTY)                                        \
+      {                                                           \
+        yychar = (Token);                                         \
+        yylval = (Value);                                         \
+        YYPOPSTACK (yylen);                                       \
+        yystate = *yyssp;                                         \
+        goto yybackup;                                            \
+      }                                                           \
+    else                                                          \
+      {                                                           \
+        yyerror (YY_("syntax error: cannot back up")); \
+        YYERROR;                                                  \
+      }                                                           \
+  while (0)
+
+/* Backward compatibility with an undocumented macro.
+   Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
+
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                        \
+do {                                            \
+  if (yydebug)                                  \
+    YYFPRINTF Args;                             \
+} while (0)
+
+
+
+
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
+do {                                                                      \
+  if (yydebug)                                                            \
+    {                                                                     \
+      YYFPRINTF (stderr, "%s ", Title);                                   \
+      yy_symbol_print (stderr,                                            \
+                  Kind, Value); \
+      YYFPRINTF (stderr, "\n");                                           \
+    }                                                                     \
+} while (0)
+
+
+/*-----------------------------------.
+| Print this symbol's value on YYO.  |
+`-----------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyo,
+                       yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep)
+{
+  FILE *yyoutput = yyo;
+  YY_USE (yyoutput);
+  if (!yyvaluep)
+    return;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  YY_USE (yykind);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/*---------------------------.
+| Print this symbol on YYO.  |
+`---------------------------*/
+
+static void
+yy_symbol_print (FILE *yyo,
+                 yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep)
+{
+  YYFPRINTF (yyo, "%s %s (",
+             yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
+
+  yy_symbol_value_print (yyo, yykind, yyvaluep);
+  YYFPRINTF (yyo, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                            \
+do {                                                            \
+  if (yydebug)                                                  \
+    yy_stack_print ((Bottom), (Top));                           \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+                 int yyrule)
+{
+  int yylno = yyrline[yyrule];
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
+             yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr,
+                       YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+                       &yyvsp[(yyi + 1) - (yynrhs)]);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (yyssp, yyvsp, Rule); \
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg,
+            yysymbol_kind_t yykind, YYSTYPE *yyvaluep)
+{
+  YY_USE (yyvaluep);
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  YY_USE (yykind);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/* Lookahead token kind.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+int
+yyparse (void)
+{
+    yy_state_fast_t yystate = 0;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus = 0;
+
+    /* Refer to the stacks through separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* Their size.  */
+    YYPTRDIFF_T yystacksize = YYINITDEPTH;
+
+    /* The state stack: array, bottom, top.  */
+    yy_state_t yyssa[YYINITDEPTH];
+    yy_state_t *yyss = yyssa;
+    yy_state_t *yyssp = yyss;
+
+    /* The semantic value stack: array, bottom, top.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs = yyvsa;
+    YYSTYPE *yyvsp = yyvs;
+
+  int yyn;
+  /* The return value of yyparse.  */
+  int yyresult;
+  /* Lookahead symbol kind.  */
+  yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  goto yysetstate;
+
+
+/*------------------------------------------------------------.
+| yynewstate -- push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+
+/*--------------------------------------------------------------------.
+| yysetstate -- set current state (the top of the stack) to yystate.  |
+`--------------------------------------------------------------------*/
+yysetstate:
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+  YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
+  YY_IGNORE_USELESS_CAST_BEGIN
+  *yyssp = YY_CAST (yy_state_t, yystate);
+  YY_IGNORE_USELESS_CAST_END
+  YY_STACK_PRINT (yyss, yyssp);
+
+  if (yyss + yystacksize - 1 <= yyssp)
+#if !defined yyoverflow && !defined YYSTACK_RELOCATE
+    YYNOMEM;
+#else
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYPTRDIFF_T yysize = yyssp - yyss + 1;
+
+# if defined yyoverflow
+      {
+        /* Give user a chance to reallocate the stack.  Use copies of
+           these so that the &'s don't force the real ones into
+           memory.  */
+        yy_state_t *yyss1 = yyss;
+        YYSTYPE *yyvs1 = yyvs;
+
+        /* Each stack pointer address is followed by the size of the
+           data in use in that stack, in bytes.  This used to be a
+           conditional around just the two extra args, but that might
+           be undefined if yyoverflow is a macro.  */
+        yyoverflow (YY_("memory exhausted"),
+                    &yyss1, yysize * YYSIZEOF (*yyssp),
+                    &yyvs1, yysize * YYSIZEOF (*yyvsp),
+                    &yystacksize);
+        yyss = yyss1;
+        yyvs = yyvs1;
+      }
+# else /* defined YYSTACK_RELOCATE */
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+        YYNOMEM;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+        yystacksize = YYMAXDEPTH;
+
+      {
+        yy_state_t *yyss1 = yyss;
+        union yyalloc *yyptr =
+          YY_CAST (union yyalloc *,
+                   YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
+        if (! yyptr)
+          YYNOMEM;
+        YYSTACK_RELOCATE (yyss_alloc, yyss);
+        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
+      }
+# endif
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YY_IGNORE_USELESS_CAST_BEGIN
+      YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+                  YY_CAST (long, yystacksize)));
+      YY_IGNORE_USELESS_CAST_END
+
+      if (yyss + yystacksize - 1 <= yyssp)
+        YYABORT;
+    }
+#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
+
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yypact_value_is_default (yyn))
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either empty, or end-of-input, or a valid lookahead.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token\n"));
+      yychar = yylex ();
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = YYEOF;
+      yytoken = YYSYMBOL_YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else if (yychar == YYerror)
+    {
+      /* The scanner already issued an error message, process directly
+         to error recovery.  But do not keep the error token as
+         lookahead, it is too special and may lead us to an endless
+         loop in error recovery. */
+      yychar = YYUNDEF;
+      yytoken = YYSYMBOL_YYerror;
+      goto yyerrlab1;
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+  yystate = yyn;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     '$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+  case 2: /* s: t  */
+#line 104 "src/egrep.y"
+                { unary(FINAL, yyvsp[0]);
+		  line--;
+		}
+#line 1248 "y.tab.c"
+    break;
+
+  case 3: /* t: b r  */
+#line 109 "src/egrep.y"
+                { yyval = node(CAT, yyvsp[-1], yyvsp[0]); }
+#line 1254 "y.tab.c"
+    break;
+
+  case 4: /* t: OR b r OR  */
+#line 111 "src/egrep.y"
+                { yyval = node(CAT, yyvsp[-2], yyvsp[-1]); }
+#line 1260 "y.tab.c"
+    break;
+
+  case 5: /* t: OR b r  */
+#line 113 "src/egrep.y"
+                { yyval = node(CAT, yyvsp[-1], yyvsp[0]); }
+#line 1266 "y.tab.c"
+    break;
+
+  case 6: /* t: b r OR  */
+#line 115 "src/egrep.y"
+                { yyval = node(CAT, yyvsp[-2], yyvsp[-1]); }
+#line 1272 "y.tab.c"
+    break;
+
+  case 7: /* b: %empty  */
+#line 118 "src/egrep.y"
+                { yyval = enter(DOT);
+		   yyval = unary(STAR, yyval); }
+#line 1279 "y.tab.c"
+    break;
+
+  case 8: /* r: CHAR  */
+#line 122 "src/egrep.y"
+                { yyval = enter(yyvsp[0]); }
+#line 1285 "y.tab.c"
+    break;
+
+  case 9: /* r: DOT  */
+#line 124 "src/egrep.y"
+                { yyval = enter(DOT); }
+#line 1291 "y.tab.c"
+    break;
+
+  case 10: /* r: CCL  */
+#line 126 "src/egrep.y"
+                { yyval = cclenter(CCL); }
+#line 1297 "y.tab.c"
+    break;
+
+  case 11: /* r: NCCL  */
+#line 128 "src/egrep.y"
+                { yyval = cclenter(NCCL); }
+#line 1303 "y.tab.c"
+    break;
+
+  case 12: /* r: r OR r  */
+#line 132 "src/egrep.y"
+                { yyval = node(OR, yyvsp[-2], yyvsp[0]); }
+#line 1309 "y.tab.c"
+    break;
+
+  case 13: /* r: r r  */
+#line 134 "src/egrep.y"
+                { yyval = node(CAT, yyvsp[-1], yyvsp[0]); }
+#line 1315 "y.tab.c"
+    break;
+
+  case 14: /* r: r STAR  */
+#line 136 "src/egrep.y"
+                { yyval = unary(STAR, yyvsp[-1]); }
+#line 1321 "y.tab.c"
+    break;
+
+  case 15: /* r: r PLUS  */
+#line 138 "src/egrep.y"
+                { yyval = unary(PLUS, yyvsp[-1]); }
+#line 1327 "y.tab.c"
+    break;
+
+  case 16: /* r: r QUEST  */
+#line 140 "src/egrep.y"
+                { yyval = unary(QUEST, yyvsp[-1]); }
+#line 1333 "y.tab.c"
+    break;
+
+  case 17: /* r: '(' r ')'  */
+#line 142 "src/egrep.y"
+                { yyval = yyvsp[-1]; }
+#line 1339 "y.tab.c"
+    break;
+
+
+#line 1343 "y.tab.c"
+
+      default: break;
+    }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
+  YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+
+  *++yyvsp = yyval;
+
+  /* Now 'shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+  {
+    const int yylhs = yyr1[yyn] - YYNTOKENS;
+    const int yyi = yypgoto[yylhs] + *yyssp;
+    yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
+               ? yytable[yyi]
+               : yydefgoto[yylhs]);
+  }
+
+  goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error.  |
+`--------------------------------------*/
+yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+      yyerror (YY_("syntax error"));
+    }
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+         error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+          /* Return failure if at end of input.  */
+          if (yychar == YYEOF)
+            YYABORT;
+        }
+      else
+        {
+          yydestruct ("Error: discarding",
+                      yytoken, &yylval);
+          yychar = YYEMPTY;
+        }
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+  /* Pacify compilers when the user code never invokes YYERROR and the
+     label yyerrorlab therefore never appears in user code.  */
+  if (0)
+    YYERROR;
+  ++yynerrs;
+
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
+
+  /* Pop stack until we find a state that shifts the error token.  */
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (!yypact_value_is_default (yyn))
+        {
+          yyn += YYSYMBOL_YYerror;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
+            {
+              yyn = yytable[yyn];
+              if (0 < yyn)
+                break;
+            }
+        }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+        YYABORT;
+
+
+      yydestruct ("Error: popping",
+                  YY_ACCESSING_SYMBOL (yystate), yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturnlab;
+
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturnlab;
+
+
+/*-----------------------------------------------------------.
+| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here.  |
+`-----------------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  goto yyreturnlab;
+
+
+/*----------------------------------------------------------.
+| yyreturnlab -- parsing is finished, clean up and return.  |
+`----------------------------------------------------------*/
+yyreturnlab:
+  if (yychar != YYEMPTY)
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval);
+    }
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+                  YY_ACCESSING_SYMBOL (+*yyssp), yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+
+  return yyresult;
+}
+
+#line 146 "src/egrep.y"
+
+static int
+yyerror(char *s)
+{
+	message = s;
+	longjmp(env, 1);
+	return 1;		/* silence a warning */
+}
+
+static int
+yylex(void)
+{
+    int cclcnt, x;
+    char c, d;
+
+    switch(c = nextch()) {
+    case '|':
+    case '\n':
+	return (OR);
+    case '*':
+	return (STAR);
+    case '+':
+	return (PLUS);
+    case '?':
+	return (QUEST);
+    case '(':
+    case ')':
+	return (c);
+    case '.':
+	return (DOT);
+    case '\0':
+	return (0);
+    case '[': 
+	x = CCL;
+	cclcnt = 0;
+	count = nxtchar++;
+	if ((c = nextch()) == '^') {
+	    x = NCCL;
+	    c = nextch();
+	}
+	do {
+	    if (c == '\0')
+		synerror();
+	    if (   (c == '-')
+		&& (cclcnt > 0)
+		&& (chars[nxtchar-1] != 0)
+	       ) {
+		if ((d = nextch()) != 0) {
+		    c = chars[nxtchar-1];
+		    while ((unsigned int)c < (unsigned int)d) {
+			if (nxtchar >= MAXLIN)
+			    overflo();
+			chars[nxtchar++] = ++c;
+			cclcnt++;
+		    }
+		    continue;
+		} /* if() */
+	    } /* if() */
+	    if (nxtchar >= MAXLIN)
+		overflo();
+	    chars[nxtchar++] = c;
+	    cclcnt++;
+	} while ((c = nextch()) != ']');
+	chars[count] = cclcnt;
+	return (x);
+    case '\\':
+	if ((c = nextch()) == '\0')
+	    synerror();
+	yylval = c;
+	return (CHAR);
+    case '$':
+    case '^':
+	c = '\n';
+	yylval = c;
+	return (CHAR);
+    default:
+	yylval = c;
+	return (CHAR);
+    }
+}
+
+static void
+synerror(void)
+{
+    yyerror("Syntax error");
+}
+
+static unsigned int
+enter(int x)
+{
+    if(line >= MAXLIN)
+	overflo();
+    name[line] = x;
+    left[line] = 0;
+    right[line] = 0;
+    return(line++);
+}
+
+static unsigned int
+cclenter(int x)
+{
+    unsigned int linno;
+
+    linno = enter(x);
+    right[linno] = count;
+    return (linno);
+}
+
+static int
+node(int x, int l, int r)
+{
+    if(line >= MAXLIN)
+	overflo();
+    name[line] = x;
+    left[line] = l;
+    right[line] = r;
+    parent[l] = line;
+    parent[r] = line;
+    return(line++);
+}
+
+static int
+unary(int x, int d)
+{
+    if(line >= MAXLIN)
+	overflo();
+    name[line] = x;
+    left[line] = d;
+    right[line] = 0;
+    parent[d] = line;
+    return(line++);
+}
+
+static void
+overflo(void)
+{
+    yyerror("internal table overflow");
+}
+
+static void
+cfoll(int v)
+{
+    unsigned int i;
+
+    if (left[v] == 0) {
+	count = 0;
+	for (i = 1; i <= line; i++) 
+	    tmpstat[i] = 0;
+	follow(v);
+	add(foll, v);
+    } else if (right[v] == 0)
+	cfoll(left[v]); 
+    else {
+	cfoll(left[v]);
+	cfoll(right[v]);
+    }
+}
+
+static void
+cgotofn(void)
+{
+    unsigned int i, n, s;
+    int c, k;
+    char symbol[NCHARS];
+    unsigned int j, l, pc, pos;
+    unsigned int nc;
+    int curpos;
+    unsigned int num, number, newpos;
+
+    count = 0;
+    for (n=3; n<=line; n++)
+	tmpstat[n] = 0;
+    if (cstate(line-1)==0) {
+	tmpstat[line] = 1;
+	count++;
+	out[0] = 1;
+    }
+    for (n=3; n<=line; n++)
+	initstat[n] = tmpstat[n];
+    count--;		/*leave out position 1 */
+    icount = count;
+    tmpstat[1] = 0;
+    add(state, 0);
+    n = 0;
+    for (s = 0; s <= n; s++)  {
+	if (out[s] == 1)
+	    continue;
+	for (i = 0; i < NCHARS; i++)
+	    symbol[i] = 0;
+	num = positions[state[s]];
+	count = icount;
+	for (i = 3; i <= line; i++)
+	    tmpstat[i] = initstat[i];
+	pos = state[s] + 1;
+	for (i = 0; i < num; i++) {
+	    curpos = positions[pos];
+	    if ((c = name[curpos]) >= 0) {
+		if (c < NCHARS) {
+		    symbol[c] = 1;
+		} else if (c == DOT) {
+		    for (k = 0; k < NCHARS; k++)
+			if (k != '\n')
+			    symbol[k] = 1;
+		} else if (c == CCL) {
+		    nc = chars[right[curpos]];
+		    pc = right[curpos] + 1;
+		    for (j = 0; j < nc; j++)
+			symbol[(unsigned char)chars[pc++]] = 1;
+		} else if (c == NCCL) {
+		    nc = chars[right[curpos]];
+		    for (j = 0; j < NCHARS; j++) {
+			pc = right[curpos] + 1;
+			for (l = 0; l < nc; l++)
+			    if (j==(unsigned char)chars[pc++])
+				goto cont;
+			if (j != '\n')
+			    symbol[j] = 1;
+		    cont:
+			;
+		    }
+		}
+	    }
+	    pos++;
+	} /* for (i) */
+	for (c=0; c<NCHARS; c++) {
+	    if (symbol[c] == 1) {
+		/* nextstate(s,c) */
+		count = icount;
+		for (i=3; i <= line; i++)
+		    tmpstat[i] = initstat[i];
+		pos = state[s] + 1;
+		for (i=0; i<num; i++) {
+		    curpos = positions[pos];
+		    if ((k = name[curpos]) >= 0)
+			if ((k == c)
+			    || (k == DOT)
+			    || (k == CCL && member(c, right[curpos], 1))
+			    || (k == NCCL && member(c, right[curpos], 0))
+			    ) {
+			    number = positions[foll[curpos]];
+			    newpos = foll[curpos] + 1;
+			    for (j = 0; j < number; j++) {
+				if (tmpstat[positions[newpos]] != 1) {
+				    tmpstat[positions[newpos]] = 1;
+				    count++;
+				}
+				newpos++;
+			    }
+			}
+		    pos++;
+		} /* end nextstate */
+		if (notin(n)) {
+		    if (n >= NSTATES)
+			overflo();
+		    add(state, ++n);
+		    if (tmpstat[line] == 1)
+			out[n] = 1;
+		    gotofn[s][c] = n;
+		} else {
+		    gotofn[s][c] = xstate;
+		}
+	    } /* if (symbol) */
+	} /* for(c) */
+    } /* for(s) */
+}
+
+static int
+cstate(int v)
+{
+	int b;
+	if (left[v] == 0) {
+		if (tmpstat[v] != 1) {
+			tmpstat[v] = 1;
+			count++;
+		}
+		return(1);
+	}
+	else if (right[v] == 0) {
+		if (cstate(left[v]) == 0) return (0);
+		else if (name[v] == PLUS) return (1);
+		else return (0);
+	}
+	else if (name[v] == CAT) {
+		if (cstate(left[v]) == 0 && cstate(right[v]) == 0) return (0);
+		else return (1);
+	}
+	else { /* name[v] == OR */
+		b = cstate(right[v]);
+		if (cstate(left[v]) == 0 || b == 0) return (0);
+		else return (1);
+	}
+}
+
+static int
+member(int symb, int set, int torf)
+{
+    unsigned int i, num, pos;
+
+    num = chars[set];
+    pos = set + 1;
+    for (i = 0; i < num; i++)
+	if (symb == (unsigned char)(chars[pos++]))
+	    return (torf);
+    return (!torf);
+}
+
+static int
+notin(int n)
+{
+	int i, j, pos;
+	for (i=0; i<=n; i++) {
+		if (positions[state[i]] == count) {
+			pos = state[i] + 1;
+			for (j=0; j < count; j++)
+				if (tmpstat[positions[pos++]] != 1) goto nxt;
+			xstate = i;
+			return (0);
+		}
+		nxt: ;
+	}
+	return (1);
+}
+
+static void
+add(int *array, int n)
+{
+    unsigned int i;
+
+    if (nxtpos + count > MAXPOS)
+	overflo();
+    array[n] = nxtpos;
+    positions[nxtpos++] = count;
+    for (i=3; i <= line; i++) {
+	if (tmpstat[i] == 1) {
+	    positions[nxtpos++] = i;
+	}
+    }
+}
+
+static void
+follow(unsigned int v)
+{
+    unsigned int p;
+
+    if (v == line) 
+	return;
+    p = parent[v];
+    switch(name[p]) {
+    case STAR:
+    case PLUS:	cstate(v);
+	follow(p);
+	return;
+
+    case OR:
+    case QUEST:	follow(p);
+	return;
+
+    case CAT:
+	if (v == left[p]) {
+	    if (cstate(right[p]) == 0) {
+		follow(p);
+		return;
+	    }
+	} else 
+	    follow(p);
+	return;
+    case FINAL:
+	if (tmpstat[line] != 1) {
+	    tmpstat[line] = 1;
+	    count++;
+	}
+	return;
+    }
+}
+
+char *
+egrepinit(char *egreppat)
+{
+    /* initialize the global data */
+    memset(gotofn, 0, sizeof(gotofn));
+    memset(state, 0, sizeof(state));
+    memset(out, 0, sizeof(out));
+    line = 1;
+    memset(name, 0, sizeof(name));
+    memset(left, 0, sizeof(left));
+    memset(right, 0, sizeof(right));
+    memset(parent, 0, sizeof(parent));
+    memset(foll, 0, sizeof(foll));
+    memset(positions, 0, sizeof(positions));
+    memset(chars, 0, sizeof(chars));
+    nxtpos = 0;
+    nxtchar = 0;
+    memset(tmpstat, 0, sizeof(tmpstat));
+    memset(initstat, 0, sizeof(initstat));
+    xstate = 0;
+    count = 0;
+    icount = 0;
+    input = egreppat;
+    message = NULL;
+    if (setjmp(env) == 0) {
+	yyparse();
+	cfoll(line-1);
+	cgotofn();
+    }
+    return(message);
+}
+
+static char buf[2 * BUFSIZ];
+static const char *buf_end = buf + (sizeof(buf) / sizeof(*buf));
+
+static size_t read_next_chunk(char **p, FILE *fptr)
+{
+    if (*p <= (buf + BUFSIZ)) {
+        /* bwlow the middle, so enough space left for one entire BUFSIZ */
+	return fread(*p, sizeof(**p), BUFSIZ, fptr);
+    } else if (*p == buf_end) {
+        /* exactly at end ... wrap around and use lower half */
+	*p = buf;
+	return fread(*p, sizeof(**p), BUFSIZ, fptr);
+    }
+    /* somewhere in second half, so do a limited read */
+    return fread(*p, sizeof(**p), buf_end - *p, fptr);
+}
+
+int
+egrep(char *file, FILE *output, char *format)
+{
+    char *p;
+    unsigned int cstat;
+    int ccount;
+    char *nlp;
+    unsigned int istat;
+    int in_line;
+    FILE *fptr;
+
+    if ((fptr = myfopen(file, "r")) == NULL) 
+	return(-1);
+
+    lnum = 1;
+    p = buf;
+    nlp = p;
+    ccount = read_next_chunk(&p, fptr);
+
+    if (ccount <= 0) {
+	fclose(fptr);
+	return(0);
+    }
+    in_line = 1;
+    istat = cstat = (unsigned int) gotofn[0]['\n'];
+    if (out[cstat])
+	goto found;
+    for (;;) {
+	if (!iflag) {
+	    /* all input chars made positive */
+	    cstat = (unsigned int) gotofn[cstat][(unsigned char)*p];
+	} else {
+	    /* for -i option*/
+	    cstat = (unsigned int) gotofn[cstat][tolower((unsigned char)*p)];
+        }
+	if (out[cstat]) {
+	found:
+	    for(;;) {
+		if (*p++ == '\n') {
+		    in_line = 0;
+		succeed:
+		    fprintf(output, format, file, lnum);
+		    if (p <= nlp) {
+			while (nlp < buf_end)
+			    putc(*nlp++, output);
+			nlp = buf;
+		    }
+		    while (nlp < p)
+			putc(*nlp++, output);
+		    lnum++;
+		    nlp = p;
+		    if (out[cstat = istat] == 0)
+			goto brk2;
+		} /* if (p++ == \n) */
+	    cfound:
+		if (--ccount <= 0) {
+		    ccount = read_next_chunk(&p, fptr);
+		    if (ccount <= 0) {
+			if (in_line) {
+			    in_line = 0;
+			    goto succeed;
+			}
+                        fclose(fptr);
+                        return(0);
+		    }
+		} /* if(ccount <= 0) */
+		in_line = 1;
+	    } /* for(ever) */
+	} /* if(out[cstat]) */
+
+	if (*p++ == '\n') {
+	    in_line = 0;
+	    lnum++;
+	    nlp = p;
+	    if (out[(cstat=istat)])
+		goto cfound;
+	}
+    brk2:
+	if (--ccount <= 0) {
+	    ccount = read_next_chunk(&p, fptr);
+	    if (ccount <= 0) 
+		break;
+	}
+	in_line = 1;
+    }
+    fclose(fptr);
+    return(0);
+}
+
+void
+egrepcaseless(int i)
+{
+	iflag = i;	/* simulate "egrep -i" */
+}
diff --git a/src/egrep.h b/src/egrep.h
new file mode 100644
index 0000000..2671791
--- /dev/null
+++ b/src/egrep.h
@@ -0,0 +1,98 @@
+/* A Bison parser, made by GNU Bison 3.8.2.  */
+
+/* Bison interface for Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
+   Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
+
+#ifndef YY_YY_EGREP_H_INCLUDED
+# define YY_YY_EGREP_H_INCLUDED
+/* Debug traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token kinds.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+  enum yytokentype
+  {
+    YYEMPTY = -2,
+    YYEOF = 0,                     /* "end of file"  */
+    YYerror = 256,                 /* error  */
+    YYUNDEF = 257,                 /* "invalid token"  */
+    CHAR = 258,                    /* CHAR  */
+    DOT = 259,                     /* DOT  */
+    CCL = 260,                     /* CCL  */
+    NCCL = 261,                    /* NCCL  */
+    OR = 262,                      /* OR  */
+    CAT = 263,                     /* CAT  */
+    STAR = 264,                    /* STAR  */
+    PLUS = 265,                    /* PLUS  */
+    QUEST = 266                    /* QUEST  */
+  };
+  typedef enum yytokentype yytoken_kind_t;
+#endif
+/* Token kinds.  */
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYerror 256
+#define YYUNDEF 257
+#define CHAR 258
+#define DOT 259
+#define CCL 260
+#define NCCL 261
+#define OR 262
+#define CAT 263
+#define STAR 264
+#define PLUS 265
+#define QUEST 266
+
+/* Value type.  */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+
+int yyparse (void);
+
+
+#endif /* !YY_YY_EGREP_H_INCLUDED  */
diff --git a/src/egrep.y b/src/egrep.y
new file mode 100644
index 0000000..cb7c0c4
--- /dev/null
+++ b/src/egrep.y
@@ -0,0 +1,663 @@
+%{
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*
+ * egrep -- fine lines containing a regular expression
+ */
+%}
+
+%token CHAR DOT CCL NCCL OR CAT STAR PLUS QUEST
+%left OR
+%left CHAR DOT CCL NCCL '('
+%left CAT
+%left STAR PLUS QUEST
+
+%{
+#include "global.h"
+#include <ctype.h>
+#include <stdio.h>
+
+#include <setjmp.h>	/* jmp_buf */
+
+#define nextch()	(*input++)
+
+#define MAXLIN 350
+#define MAXPOS 4000
+#define NCHARS 256
+#define NSTATES 128
+#define FINAL -1
+static	char gotofn[NSTATES][NCHARS];
+static	int state[NSTATES];
+static	char out[NSTATES];
+static	unsigned int line;
+static	int name[MAXLIN];
+static	unsigned int left[MAXLIN];
+static	unsigned int right[MAXLIN];
+static	unsigned int parent[MAXLIN];
+static	int foll[MAXLIN];
+static	int positions[MAXPOS];
+static	char chars[MAXLIN];
+static	int nxtpos;
+static	int nxtchar;
+static	int tmpstat[MAXLIN];
+static	int initstat[MAXLIN];
+static	int xstate;
+static	int count;
+static	int icount;
+static	char *input;
+static	long lnum;
+static	int iflag;
+static	jmp_buf	env;	/* setjmp/longjmp buffer */
+static	char *message;	/* error message */
+
+/* Internal prototypes: */
+static	void cfoll(int v);
+static	void cgotofn(void);
+static	int cstate(int v);
+static	int member(int symb, int set, int torf);
+static	int notin(int n);
+static	void synerror(void);
+static	void overflo(void);
+static	void add(int *array, int n);
+static	void follow(unsigned int v);
+static	int unary(int x, int d);
+static	int node(int x, int l, int r);
+static	unsigned int cclenter(int x);
+static	unsigned int enter(int x);
+
+static int yylex(void);
+static int yyerror(char *);
+%}
+
+%%
+s:	t
+		{ unary(FINAL, $1);
+		  line--;
+		}
+	;
+t:	b r
+		{ $$ = node(CAT, $1, $2); }
+	| OR b r OR
+		{ $$ = node(CAT, $2, $3); }
+	| OR b r
+		{ $$ = node(CAT, $2, $3); }
+	| b r OR
+		{ $$ = node(CAT, $1, $2); }
+	;
+b:
+		{ $$ = enter(DOT);
+		   $$ = unary(STAR, $$); }
+	;
+r:	CHAR
+		{ $$ = enter($1); }
+	| DOT
+		{ $$ = enter(DOT); }
+	| CCL
+		{ $$ = cclenter(CCL); }
+	| NCCL
+		{ $$ = cclenter(NCCL); }
+	;
+
+r:	r OR r
+		{ $$ = node(OR, $1, $3); }
+	| r r %prec CAT
+		{ $$ = node(CAT, $1, $2); }
+	| r STAR
+		{ $$ = unary(STAR, $1); }
+	| r PLUS
+		{ $$ = unary(PLUS, $1); }
+	| r QUEST
+		{ $$ = unary(QUEST, $1); }
+	| '(' r ')'
+		{ $$ = $2; }
+	| error 
+	;
+
+%%
+static int
+yyerror(char *s)
+{
+	message = s;
+	longjmp(env, 1);
+	return 1;		/* silence a warning */
+}
+
+static int
+yylex(void)
+{
+    int cclcnt, x;
+    char c, d;
+
+    switch(c = nextch()) {
+    case '|':
+    case '\n':
+	return (OR);
+    case '*':
+	return (STAR);
+    case '+':
+	return (PLUS);
+    case '?':
+	return (QUEST);
+    case '(':
+    case ')':
+	return (c);
+    case '.':
+	return (DOT);
+    case '\0':
+	return (0);
+    case '[': 
+	x = CCL;
+	cclcnt = 0;
+	count = nxtchar++;
+	if ((c = nextch()) == '^') {
+	    x = NCCL;
+	    c = nextch();
+	}
+	do {
+	    if (c == '\0')
+		synerror();
+	    if (   (c == '-')
+		&& (cclcnt > 0)
+		&& (chars[nxtchar-1] != 0)
+	       ) {
+		if ((d = nextch()) != 0) {
+		    c = chars[nxtchar-1];
+		    while ((unsigned int)c < (unsigned int)d) {
+			if (nxtchar >= MAXLIN)
+			    overflo();
+			chars[nxtchar++] = ++c;
+			cclcnt++;
+		    }
+		    continue;
+		} /* if() */
+	    } /* if() */
+	    if (nxtchar >= MAXLIN)
+		overflo();
+	    chars[nxtchar++] = c;
+	    cclcnt++;
+	} while ((c = nextch()) != ']');
+	chars[count] = cclcnt;
+	return (x);
+    case '\\':
+	if ((c = nextch()) == '\0')
+	    synerror();
+	yylval = c;
+	return (CHAR);
+    case '$':
+    case '^':
+	c = '\n';
+	yylval = c;
+	return (CHAR);
+    default:
+	yylval = c;
+	return (CHAR);
+    }
+}
+
+static void
+synerror(void)
+{
+    yyerror("Syntax error");
+}
+
+static unsigned int
+enter(int x)
+{
+    if(line >= MAXLIN)
+	overflo();
+    name[line] = x;
+    left[line] = 0;
+    right[line] = 0;
+    return(line++);
+}
+
+static unsigned int
+cclenter(int x)
+{
+    unsigned int linno;
+
+    linno = enter(x);
+    right[linno] = count;
+    return (linno);
+}
+
+static int
+node(int x, int l, int r)
+{
+    if(line >= MAXLIN)
+	overflo();
+    name[line] = x;
+    left[line] = l;
+    right[line] = r;
+    parent[l] = line;
+    parent[r] = line;
+    return(line++);
+}
+
+static int
+unary(int x, int d)
+{
+    if(line >= MAXLIN)
+	overflo();
+    name[line] = x;
+    left[line] = d;
+    right[line] = 0;
+    parent[d] = line;
+    return(line++);
+}
+
+static void
+overflo(void)
+{
+    yyerror("internal table overflow");
+}
+
+static void
+cfoll(int v)
+{
+    unsigned int i;
+
+    if (left[v] == 0) {
+	count = 0;
+	for (i = 1; i <= line; i++) 
+	    tmpstat[i] = 0;
+	follow(v);
+	add(foll, v);
+    } else if (right[v] == 0)
+	cfoll(left[v]); 
+    else {
+	cfoll(left[v]);
+	cfoll(right[v]);
+    }
+}
+
+static void
+cgotofn(void)
+{
+    unsigned int i, n, s;
+    int c, k;
+    char symbol[NCHARS];
+    unsigned int j, l, pc, pos;
+    unsigned int nc;
+    int curpos;
+    unsigned int num, number, newpos;
+
+    count = 0;
+    for (n=3; n<=line; n++)
+	tmpstat[n] = 0;
+    if (cstate(line-1)==0) {
+	tmpstat[line] = 1;
+	count++;
+	out[0] = 1;
+    }
+    for (n=3; n<=line; n++)
+	initstat[n] = tmpstat[n];
+    count--;		/*leave out position 1 */
+    icount = count;
+    tmpstat[1] = 0;
+    add(state, 0);
+    n = 0;
+    for (s = 0; s <= n; s++)  {
+	if (out[s] == 1)
+	    continue;
+	for (i = 0; i < NCHARS; i++)
+	    symbol[i] = 0;
+	num = positions[state[s]];
+	count = icount;
+	for (i = 3; i <= line; i++)
+	    tmpstat[i] = initstat[i];
+	pos = state[s] + 1;
+	for (i = 0; i < num; i++) {
+	    curpos = positions[pos];
+	    if ((c = name[curpos]) >= 0) {
+		if (c < NCHARS) {
+		    symbol[c] = 1;
+		} else if (c == DOT) {
+		    for (k = 0; k < NCHARS; k++)
+			if (k != '\n')
+			    symbol[k] = 1;
+		} else if (c == CCL) {
+		    nc = chars[right[curpos]];
+		    pc = right[curpos] + 1;
+		    for (j = 0; j < nc; j++)
+			symbol[(unsigned char)chars[pc++]] = 1;
+		} else if (c == NCCL) {
+		    nc = chars[right[curpos]];
+		    for (j = 0; j < NCHARS; j++) {
+			pc = right[curpos] + 1;
+			for (l = 0; l < nc; l++)
+			    if (j==(unsigned char)chars[pc++])
+				goto cont;
+			if (j != '\n')
+			    symbol[j] = 1;
+		    cont:
+			;
+		    }
+		}
+	    }
+	    pos++;
+	} /* for (i) */
+	for (c=0; c<NCHARS; c++) {
+	    if (symbol[c] == 1) {
+		/* nextstate(s,c) */
+		count = icount;
+		for (i=3; i <= line; i++)
+		    tmpstat[i] = initstat[i];
+		pos = state[s] + 1;
+		for (i=0; i<num; i++) {
+		    curpos = positions[pos];
+		    if ((k = name[curpos]) >= 0)
+			if ((k == c)
+			    || (k == DOT)
+			    || (k == CCL && member(c, right[curpos], 1))
+			    || (k == NCCL && member(c, right[curpos], 0))
+			    ) {
+			    number = positions[foll[curpos]];
+			    newpos = foll[curpos] + 1;
+			    for (j = 0; j < number; j++) {
+				if (tmpstat[positions[newpos]] != 1) {
+				    tmpstat[positions[newpos]] = 1;
+				    count++;
+				}
+				newpos++;
+			    }
+			}
+		    pos++;
+		} /* end nextstate */
+		if (notin(n)) {
+		    if (n >= NSTATES)
+			overflo();
+		    add(state, ++n);
+		    if (tmpstat[line] == 1)
+			out[n] = 1;
+		    gotofn[s][c] = n;
+		} else {
+		    gotofn[s][c] = xstate;
+		}
+	    } /* if (symbol) */
+	} /* for(c) */
+    } /* for(s) */
+}
+
+static int
+cstate(int v)
+{
+	int b;
+	if (left[v] == 0) {
+		if (tmpstat[v] != 1) {
+			tmpstat[v] = 1;
+			count++;
+		}
+		return(1);
+	}
+	else if (right[v] == 0) {
+		if (cstate(left[v]) == 0) return (0);
+		else if (name[v] == PLUS) return (1);
+		else return (0);
+	}
+	else if (name[v] == CAT) {
+		if (cstate(left[v]) == 0 && cstate(right[v]) == 0) return (0);
+		else return (1);
+	}
+	else { /* name[v] == OR */
+		b = cstate(right[v]);
+		if (cstate(left[v]) == 0 || b == 0) return (0);
+		else return (1);
+	}
+}
+
+static int
+member(int symb, int set, int torf)
+{
+    unsigned int i, num, pos;
+
+    num = chars[set];
+    pos = set + 1;
+    for (i = 0; i < num; i++)
+	if (symb == (unsigned char)(chars[pos++]))
+	    return (torf);
+    return (!torf);
+}
+
+static int
+notin(int n)
+{
+	int i, j, pos;
+	for (i=0; i<=n; i++) {
+		if (positions[state[i]] == count) {
+			pos = state[i] + 1;
+			for (j=0; j < count; j++)
+				if (tmpstat[positions[pos++]] != 1) goto nxt;
+			xstate = i;
+			return (0);
+		}
+		nxt: ;
+	}
+	return (1);
+}
+
+static void
+add(int *array, int n)
+{
+    unsigned int i;
+
+    if (nxtpos + count > MAXPOS)
+	overflo();
+    array[n] = nxtpos;
+    positions[nxtpos++] = count;
+    for (i=3; i <= line; i++) {
+	if (tmpstat[i] == 1) {
+	    positions[nxtpos++] = i;
+	}
+    }
+}
+
+static void
+follow(unsigned int v)
+{
+    unsigned int p;
+
+    if (v == line) 
+	return;
+    p = parent[v];
+    switch(name[p]) {
+    case STAR:
+    case PLUS:	cstate(v);
+	follow(p);
+	return;
+
+    case OR:
+    case QUEST:	follow(p);
+	return;
+
+    case CAT:
+	if (v == left[p]) {
+	    if (cstate(right[p]) == 0) {
+		follow(p);
+		return;
+	    }
+	} else 
+	    follow(p);
+	return;
+    case FINAL:
+	if (tmpstat[line] != 1) {
+	    tmpstat[line] = 1;
+	    count++;
+	}
+	return;
+    }
+}
+
+char *
+egrepinit(char *egreppat)
+{
+    /* initialize the global data */
+    memset(gotofn, 0, sizeof(gotofn));
+    memset(state, 0, sizeof(state));
+    memset(out, 0, sizeof(out));
+    line = 1;
+    memset(name, 0, sizeof(name));
+    memset(left, 0, sizeof(left));
+    memset(right, 0, sizeof(right));
+    memset(parent, 0, sizeof(parent));
+    memset(foll, 0, sizeof(foll));
+    memset(positions, 0, sizeof(positions));
+    memset(chars, 0, sizeof(chars));
+    nxtpos = 0;
+    nxtchar = 0;
+    memset(tmpstat, 0, sizeof(tmpstat));
+    memset(initstat, 0, sizeof(initstat));
+    xstate = 0;
+    count = 0;
+    icount = 0;
+    input = egreppat;
+    message = NULL;
+    if (setjmp(env) == 0) {
+	yyparse();
+	cfoll(line-1);
+	cgotofn();
+    }
+    return(message);
+}
+
+static char buf[2 * BUFSIZ];
+static const char *buf_end = buf + (sizeof(buf) / sizeof(*buf));
+
+static size_t read_next_chunk(char **p, FILE *fptr)
+{
+    if (*p <= (buf + BUFSIZ)) {
+        /* bwlow the middle, so enough space left for one entire BUFSIZ */
+	return fread(*p, sizeof(**p), BUFSIZ, fptr);
+    } else if (*p == buf_end) {
+        /* exactly at end ... wrap around and use lower half */
+	*p = buf;
+	return fread(*p, sizeof(**p), BUFSIZ, fptr);
+    }
+    /* somewhere in second half, so do a limited read */
+    return fread(*p, sizeof(**p), buf_end - *p, fptr);
+}
+
+int
+egrep(char *file, FILE *output, char *format)
+{
+    char *p;
+    unsigned int cstat;
+    int ccount;
+    char *nlp;
+    unsigned int istat;
+    int in_line;
+    FILE *fptr;
+
+    if ((fptr = myfopen(file, "r")) == NULL) 
+	return(-1);
+
+    lnum = 1;
+    p = buf;
+    nlp = p;
+    ccount = read_next_chunk(&p, fptr);
+
+    if (ccount <= 0) {
+	fclose(fptr);
+	return(0);
+    }
+    in_line = 1;
+    istat = cstat = (unsigned int) gotofn[0]['\n'];
+    if (out[cstat])
+	goto found;
+    for (;;) {
+	if (!iflag) {
+	    /* all input chars made positive */
+	    cstat = (unsigned int) gotofn[cstat][(unsigned char)*p];
+	} else {
+	    /* for -i option*/
+	    cstat = (unsigned int) gotofn[cstat][tolower((unsigned char)*p)];
+        }
+	if (out[cstat]) {
+	found:
+	    for(;;) {
+		if (*p++ == '\n') {
+		    in_line = 0;
+		succeed:
+		    fprintf(output, format, file, lnum);
+		    if (p <= nlp) {
+			while (nlp < buf_end)
+			    putc(*nlp++, output);
+			nlp = buf;
+		    }
+		    while (nlp < p)
+			putc(*nlp++, output);
+		    lnum++;
+		    nlp = p;
+		    if (out[cstat = istat] == 0)
+			goto brk2;
+		} /* if (p++ == \n) */
+	    cfound:
+		if (--ccount <= 0) {
+		    ccount = read_next_chunk(&p, fptr);
+		    if (ccount <= 0) {
+			if (in_line) {
+			    in_line = 0;
+			    goto succeed;
+			}
+                        fclose(fptr);
+                        return(0);
+		    }
+		} /* if(ccount <= 0) */
+		in_line = 1;
+	    } /* for(ever) */
+	} /* if(out[cstat]) */
+
+	if (*p++ == '\n') {
+	    in_line = 0;
+	    lnum++;
+	    nlp = p;
+	    if (out[(cstat=istat)])
+		goto cfound;
+	}
+    brk2:
+	if (--ccount <= 0) {
+	    ccount = read_next_chunk(&p, fptr);
+	    if (ccount <= 0) 
+		break;
+	}
+	in_line = 1;
+    }
+    fclose(fptr);
+    return(0);
+}
+
+void
+egrepcaseless(int i)
+{
+	iflag = i;	/* simulate "egrep -i" */
+}
diff --git a/src/exec.c b/src/exec.c
new file mode 100644
index 0000000..2ab611c
--- /dev/null
+++ b/src/exec.c
@@ -0,0 +1,188 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	process execution functions
+ */
+
+#include <unistd.h>
+#include "global.h"
+#include <stdarg.h>
+#include <sys/wait.h>
+#include <sys/types.h>      /* pid_t */
+#ifdef __DJGPP__
+#include <process.h>
+#endif
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+static	sighandler_t oldsigquit; /* old value of quit signal */
+static	sighandler_t oldsighup; /* old value of hangup signal */
+static	sighandler_t oldsigtstp; /* old value of SIGTSTP */
+
+#ifndef __MSDOS__ /* none of these is needed, there */
+static	int	join(pid_t p);
+static	int	myexecvp(char *a, char **args);
+static	pid_t	myfork(void);
+#endif
+
+/* execute forks and executes a program or shell script, waits for it to
+ * finish, and returns its exit code.
+ */
+
+/*VARARGS1*/
+int
+execute(char *a, ...)	/* note: "exec" is already defined on u370 */
+{
+	va_list	ap;
+	int	exitcode = -1;	/* initialize, to avoid warning */
+	char	*argv[BUFSIZ];
+	pid_t	p;
+
+	/* fork and exec the program or shell script */
+	endwin();	/* restore the terminal modes */
+	mousecleanup();
+	fflush(stdout);
+	va_start(ap, a);
+	for (p = 0; (argv[p] = va_arg(ap, char *)) != 0; p++)
+		;
+#ifdef __MSDOS__
+	/* HBB 20010313: in MSDOG, everything is completely different.
+	 * No fork()/exec()/wait(), but rather a single libc call: */
+        exitcode = spawnvp(P_WAIT, a, argv);
+#else
+	if ((p = myfork()) == 0) {
+		myexecvp(a, argv);	/* child */
+	}
+	else {
+		exitcode = join(p);	/* parent */
+	}
+#endif /* MSDOS */
+	
+	/* the menu and scrollbar may be changed by the command executed */
+#if UNIXPC || !TERMINFO
+# ifndef __DJGPP__ /* leave CRLF handling as is */      
+	nonl();
+# endif
+	raw();	/* endwin() turns off cbreak mode so restore it */
+	noecho();
+#endif
+	mousemenu();
+	drawscrollbar(topline, nextline);
+	va_end(ap);
+	return(exitcode);
+}
+
+#ifndef __MSDOS__ /* None of the following functions is used there */
+
+/* myexecvp is an interface to the execvp system call to
+ * modify argv[0] to reference the last component of its path-name.
+ */
+static int
+myexecvp(char *a, char **args)
+{
+    char    msg[MSGLEN + 1];
+	
+    /* modify argv[0] to reference the last component of its path name */
+    args[0] = basename(args[0]);
+
+    /* execute the program or shell script */
+    execvp(a, args);	/* returns only on failure */
+    snprintf(msg, sizeof(msg), "\nCannot exec %s", a);
+    perror(msg);		/* display the reason */
+    askforreturn();		/* wait until the user sees the message */
+    myexit(1);		/* exit the child */
+    /* NOTREACHED */
+}
+
+/* myfork acts like fork but also handles signals */
+
+static pid_t
+myfork(void)
+{
+	pid_t	p;		/* process number */
+
+	p = fork();
+	
+	/* the parent ignores the interrupt, quit, and hangup signals */
+	if (p > 0) {
+		oldsigquit = signal(SIGQUIT, SIG_IGN);
+		oldsighup = signal(SIGHUP, SIG_IGN);
+#ifdef SIGTSTP		
+		oldsigtstp = signal(SIGTSTP, SIG_DFL);
+#endif		
+	}
+	/* so they can be used to stop the child */
+	else if (p == 0) {
+		signal(SIGINT, SIG_DFL);
+		signal(SIGQUIT, SIG_DFL);
+		signal(SIGHUP, SIG_DFL);
+#ifdef SIGTSTP
+		signal(SIGTSTP, SIG_DFL);
+#endif			
+	}
+	/* check for fork failure */
+	if (p == -1) {
+		myperror("Cannot fork");
+	}
+	return p;
+}
+
+/* join is the compliment of fork */
+
+static int
+join(pid_t p) 
+{
+	int	status = -1;  
+	pid_t	w;
+
+	/* wait for the correct child to exit */
+	do {
+		w = wait(&status);
+	} while (p != -1 && w != p);
+
+	/* restore signal handling */
+	signal(SIGQUIT, oldsigquit);
+	signal(SIGHUP, oldsighup);
+#ifdef SIGTSTP
+	signal(SIGTSTP, oldsigtstp);
+#endif	
+
+	/* return the child's exit code */
+	return(status >> 8);
+}
+
+#endif /* !MSDOS */
diff --git a/src/find.c b/src/find.c
new file mode 100644
index 0000000..d7a66f0
--- /dev/null
+++ b/src/find.c
@@ -0,0 +1,1301 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol or text cross-reference
+ *
+ *	searching functions
+ */
+
+#include "global.h"
+
+#include "build.h"
+#include "scanner.h"		/* for token definitions */
+
+#include <assert.h>
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+#include <regex.h>
+
+/* most of these functions have been optimized so their innermost loops have
+ * only one test for the desired character by putting the char and 
+ * an end-of-block marker (\0) at the end of the disk block buffer.
+ * When the inner loop exits on the char, an outer loop will see if
+ * the char is followed by a \0.  If so, it will read the next block
+ * and restart the inner loop.
+ */
+
+char	*blockp;			/* pointer to current char in block */
+char	block[BUFSIZ + 2];		/* leave room for end-of-block mark */
+int	blocklen;			/* length of disk block read */
+char	blockmark;			/* mark character to be searched for */
+long	blocknumber;			/* block number */
+
+static	char	global[] = "<global>";	/* dummy global function name */
+static	char	cpattern[PATLEN + 1];	/* compressed pattern */
+static	long	lastfcnoffset;		/* last function name offset */
+static	POSTING	*postingp;		/* retrieved posting set pointer */
+static	long	postingsfound;		/* retrieved number of postings */
+static	regex_t regexp;			/* regular expression */
+static	BOOL	isregexp_valid = NO;	/* regular expression status */
+
+static	BOOL	match(void);
+static	BOOL	matchrest(void);
+static	POSTING	*getposting(void);
+static	char	*lcasify(char *s);
+static	void	findcalledbysub(char *file, BOOL macro);
+static	void	findterm(char *pattern);
+static	void	putline(FILE *output);
+static  char    *find_symbol_or_assignment(char *pattern, BOOL assign_flag);
+static  BOOL    check_for_assignment(void);
+static	void	putpostingref(POSTING *p, char *pat);
+static	void	putref(int seemore, char *file, char *func);
+static	void	putsource(int seemore, FILE *output);
+
+/* find the symbol in the cross-reference */
+
+char *
+findsymbol(char *pattern)
+{
+    return find_symbol_or_assignment(pattern, NO);
+}
+
+/* find the symbol in the cross-reference, and look for assignments */
+char *
+findassign(char *pattern)
+{
+    return find_symbol_or_assignment(pattern, YES);
+}
+
+/* Test reference whether it's an assignment to the symbol found at
+ * (global variable) 'blockp' */
+static BOOL
+check_for_assignment(void) 
+{
+    /* Do the extra work here to determine if this is an
+     * assignment or not.  Do this by examining the next character
+     * or two in blockp */
+    char *asgn_char = blockp;
+
+    while (isspace((unsigned char) asgn_char[0])) {
+	/* skip any whitespace or \n */
+	asgn_char++;
+	if (asgn_char[0] == '\0') {
+	    /* get the next block when we reach the end of
+	     * the current block */
+	    if (NULL == (asgn_char = read_block()))
+		return NO;
+	}
+    }
+    /* check for digraph starting with = */
+    if ((asgn_char[0] & 0x80) && (dichar1[(asgn_char[0] & 0177)/8] == '=')) {
+	return YES;
+    }
+    /* check for plain '=', not '==' */
+    if ((asgn_char[0] == '=') && 
+	(((asgn_char[1] != '=') && !(asgn_char[1] & 0x80)) || 
+	 ((asgn_char[1] & 0x80) && (dichar1[(asgn_char[1]& 0177)/8] != '=')))) {
+	return YES;
+    }
+
+    /* check for operator assignments: +=, ... ^= ? */
+    if (   (   (asgn_char[0] == '+') 
+	    || (asgn_char[0] == '-')
+	    || (asgn_char[0] == '*') 
+	    || (asgn_char[0] == '/') 
+	    || (asgn_char[0] == '%') 
+	    || (asgn_char[0] == '&') 
+	    || (asgn_char[0] == '|') 
+	    || (asgn_char[0] == '^') 
+	   )
+	&& ((asgn_char[1] == '=') || ((asgn_char[1] & 0x80) && (dichar1[(asgn_char[1] &0177)/8] == '=')))
+
+       ) {
+	return YES;
+    }
+
+    /* check for two-letter operator assignments: <<= or >>= ? */
+    if (   (   (asgn_char[0] == '<') 
+            || (asgn_char[0] == '>')
+           )
+	&& (asgn_char[1] == asgn_char[0])
+	&& ((asgn_char[2] == '=') || ((asgn_char[2] & 0x80) && (dichar1[(asgn_char[2] & 0177)/8] == '=')))
+       )
+	return YES;
+    return NO;
+}
+
+/* The actual routine that does the work for findsymbol() and
+* findassign() */
+static char *
+find_symbol_or_assignment(char *pattern, BOOL assign_flag)
+{
+	char	file[PATHLEN + 1];	/* source file name */
+	char	function[PATLEN + 1];	/* function name */
+	char	macro[PATLEN + 1];	/* macro name */
+	char	symbol[PATLEN + 1];	/* symbol name */
+	char	*cp;
+	char	*s;
+	size_t	s_len = 0;
+	char firstchar;		/* first character of a potential symbol */
+	BOOL fcndef = NO;
+
+	if ((invertedindex == YES) && (assign_flag == NO)) {
+		long	lastline = 0;
+		POSTING *p;
+
+		findterm(pattern);
+		while ((p = getposting()) != NULL) {
+			if (p->type != INCLUDE && p->lineoffset != lastline) {
+				putpostingref(p, 0);
+				lastline = p->lineoffset;
+			}
+		}
+		return NULL;
+	}
+
+	(void) scanpast('\t');	/* find the end of the header */
+	skiprefchar();		/* skip the file marker */
+	fetch_string_from_dbase(file, sizeof(file));
+	strcpy(function, global); /* set the dummy global function name */
+	strcpy(macro, global);	/* set the dummy global macro name */
+	
+	/* find the next symbol */
+	/* note: this code was expanded in-line for speed */
+	/* other macros were replaced by code using cp instead of blockp */
+	cp = blockp;
+	for (;;) {
+		setmark('\n');
+		do {	/* innermost loop optimized to only one test */
+			while (*cp != '\n') {
+				++cp;
+			}
+		} while (*(cp + 1) == '\0' && (cp = read_block()) != NULL);
+
+		/* skip the found character */
+		if (cp != NULL && *(++cp + 1) == '\0') {
+			cp = read_block();
+		}
+		if (cp == NULL) {
+			break;
+		}
+		/* look for a source file, function, or macro name */
+		if (*cp == '\t') {
+			blockp = cp;
+			switch (getrefchar()) {
+
+			case NEWFILE:		/* file name */
+
+				/* save the name */
+				skiprefchar();
+				fetch_string_from_dbase(file, sizeof(file));
+			
+				/* check for the end of the symbols */
+				if (*file == '\0') {
+					return NULL;
+				}
+				progress("Search", searchcount, nsrcfiles);
+				/* FALLTHROUGH */
+				
+			case FCNEND:		/* function end */
+				(void) strcpy(function, global);
+				goto notmatched;	/* don't match name */
+				
+			case FCNDEF:		/* function name */
+				fcndef = YES;
+				s = function; 
+				s_len = sizeof(function);
+				break;
+
+			case DEFINE:		/* macro name */
+				if (fileversion >= 10) {
+					s = macro;
+					s_len = sizeof(macro);
+				} else {	
+					s = symbol;
+					s_len = sizeof(symbol);
+				}
+				break;
+
+			case DEFINEEND:		/* macro end */
+				(void) strcpy(macro, global);
+				goto notmatched;
+
+			case INCLUDE:			/* #include file */
+				goto notmatched;	/* don't match name */
+			
+			default:		/* other symbol */
+				s = symbol;
+				s_len = sizeof(symbol);
+			}
+			/* save the name */
+			skiprefchar();
+			fetch_string_from_dbase(s, s_len);
+
+			/* see if this is a regular expression pattern */
+			if (isregexp_valid == YES) { 
+				if (caseless == YES) {
+					s = lcasify(s);
+				}
+				if (*s != '\0' && regexec (&regexp, s, (size_t)0, NULL, 0) == 0) { 
+					goto matched;
+				}
+			}
+			/* match the symbol to the text pattern */
+			else if (strequal(pattern, s)) {
+				goto matched;
+			}
+			goto notmatched;
+		}
+		/* if this is a regular expression pattern */
+		if (isregexp_valid == YES) {
+			
+			/* if this is a symbol */
+			
+			/**************************************************
+			 * The first character may be a digraph'ed char, so
+			 * unpack it into firstchar, and then test that.
+			 *
+			 * Assume that all digraphed chars have the 8th bit
+			 * set (0200).
+			 **************************************************/
+			if (*cp & 0200) {	/* digraph char? */
+				firstchar = dichar1[(*cp & 0177) / 8];
+			}
+			else {
+				firstchar = *cp;
+			}
+			
+			if (isalpha((unsigned char)firstchar) || firstchar == '_') {
+				blockp = cp;
+				fetch_string_from_dbase(symbol, sizeof(symbol));
+				if (caseless == YES) {
+					s = lcasify(symbol);	/* point to lower case version */
+				}
+				else {
+					s = symbol;
+				}
+				
+				/* match the symbol to the regular expression */
+				if (*s != '\0' && regexec (&regexp, s, (size_t)0, NULL, 0) == 0) {
+					goto matched;
+				}
+				goto notmatched;
+			}
+		}
+		/* match the character to the text pattern */
+		else if (*cp == cpattern[0]) {
+			blockp = cp;
+
+			/* match the rest of the symbol to the text pattern */
+			if (matchrest()) {
+				s = NULL;
+		matched:
+				/* if the assignment flag is set then
+				 * we are looking for assignments and
+				 * some extra filtering is needed */
+				if(assign_flag == YES
+				  && ! check_for_assignment())
+				       goto notmatched;
+
+
+				/* output the file, function or macro, and source line */
+				if (strcmp(macro, global) && s != macro) {
+					putref(0, file, macro);
+				}
+				else if (fcndef == YES || s != function) {
+					fcndef = NO;
+					putref(0, file, function);
+				}
+				else {
+					putref(0, file, global);
+				}
+			}
+		notmatched:
+			if (blockp == NULL) {
+				return NULL;
+			}
+			fcndef = NO;
+			cp = blockp;
+		}
+	}
+	blockp = cp;
+
+	return NULL;
+}
+/* find the function definition or #define */
+
+char *
+finddef(char *pattern)
+{
+	char	file[PATHLEN + 1];	/* source file name */
+
+	if (invertedindex == YES) {
+		POSTING *p;
+
+		findterm(pattern);
+		while ((p = getposting()) != NULL) {
+			switch (p->type) {
+			case DEFINE:/* could be a macro */
+			case FCNDEF:
+			case CLASSDEF:
+			case ENUMDEF:
+			case MEMBERDEF:
+			case STRUCTDEF:
+			case TYPEDEF:
+			case UNIONDEF:
+			case GLOBALDEF:/* other global definition */
+				putpostingref(p, pattern);
+			}
+		}
+		return NULL;
+	}
+
+
+	/* find the next file name or definition */
+	while (scanpast('\t') != NULL) {
+		switch (*blockp) {
+			
+		case NEWFILE:
+			skiprefchar();	/* save file name */
+			fetch_string_from_dbase(file, sizeof(file));
+			if (*file == '\0') {	/* if end of symbols */
+				return NULL;
+			}
+			progress("Search", searchcount, nsrcfiles);
+			break;
+
+		case DEFINE:		/* could be a macro */
+		case FCNDEF:
+		case CLASSDEF:
+		case ENUMDEF:
+		case MEMBERDEF:
+		case STRUCTDEF:
+		case TYPEDEF:
+		case UNIONDEF:
+		case GLOBALDEF:		/* other global definition */
+			skiprefchar();	/* match name to pattern */
+			if (match()) {
+		
+				/* output the file, function and source line */
+				putref(0, file, pattern);
+			}
+			break;
+		}
+	}
+	
+	return NULL;
+}
+/* find all function definitions (used by samuel only) */
+
+char *
+findallfcns(char *dummy)
+{
+	char	file[PATHLEN + 1];	/* source file name */
+	char	function[PATLEN + 1];	/* function name */
+
+	(void) dummy;		/* unused argument */
+
+	/* find the next file name or definition */
+	while (scanpast('\t') != NULL) {
+		switch (*blockp) {
+			
+		case NEWFILE:
+			skiprefchar();	/* save file name */
+			fetch_string_from_dbase(file, sizeof(file));
+			if (*file == '\0') {	/* if end of symbols */
+				return NULL;
+			}
+			progress("Search", searchcount, nsrcfiles);
+			/* FALLTHROUGH */
+			
+		case FCNEND:		/* function end */
+			(void) strcpy(function, global);
+			break;
+
+		case FCNDEF:
+		case CLASSDEF:
+			skiprefchar();	/* save function name */
+			fetch_string_from_dbase(function, sizeof(function));
+
+			/* output the file, function and source line */
+			putref(0, file, function);
+			break;
+		}
+	}
+	return NULL;
+}
+
+/* find the functions calling this function */
+
+char *
+findcalling(char *pattern)
+{
+	char	file[PATHLEN + 1];	/* source file name */
+	char	function[PATLEN + 1];	/* function name */
+	char	tmpfunc[10][PATLEN + 1];/* 10 temporary function names */
+	char	macro[PATLEN + 1];	/* macro name */
+	char	*tmpblockp;
+	int	morefuns, i;
+
+	if (invertedindex == YES) {
+		POSTING	*p;
+		
+		findterm(pattern);
+		while ((p = getposting()) != NULL) {
+			if (p->type == FCNCALL) {
+				putpostingref(p, 0);
+			}
+		}
+		return NULL;
+	}
+	/* find the next file name or function definition */
+	*macro = '\0';	/* a macro can be inside a function, but not vice versa */
+	tmpblockp = 0;
+	morefuns = 0;	/* one function definition is normal case */
+	for (i = 0; i < 10; i++) *(tmpfunc[i]) = '\0';
+	while (scanpast('\t') != NULL) {
+		switch (*blockp) {
+			
+		case NEWFILE:		/* save file name */
+			skiprefchar();
+			fetch_string_from_dbase(file, sizeof(file));
+			if (*file == '\0') {	/* if end of symbols */
+				return NULL;
+			}
+			progress("Search", searchcount, nsrcfiles);
+			(void) strcpy(function, global);
+			break;
+			
+		case DEFINE:		/* could be a macro */
+			if (fileversion >= 10) {
+				skiprefchar();
+				fetch_string_from_dbase(macro, sizeof(macro));
+			}
+			break;
+
+		case DEFINEEND:
+			*macro = '\0';
+			break;
+
+		case FCNDEF:		/* save calling function name */
+			skiprefchar();
+			fetch_string_from_dbase(function, sizeof(function));
+			for (i = 0; i < morefuns; i++)
+				if ( !strcmp(tmpfunc[i], function) )
+					break;
+			if (i == morefuns) {
+				(void) strcpy(tmpfunc[morefuns], function);
+				if (++morefuns >= 10) morefuns = 9;
+			}
+			break;
+			
+		case FCNEND:
+			for (i = 0; i < morefuns; i++)
+				*(tmpfunc[i]) = '\0';
+			morefuns = 0;
+			break;
+
+		case FCNCALL:		/* match function called to pattern */
+			skiprefchar();
+			if (match()) {
+				
+				/* output the file, calling function or macro, and source */
+				if (*macro != '\0') {
+					putref(1, file, macro);
+				}
+				else {
+					tmpblockp = blockp;
+					for (i = 0; i < morefuns; i++) {
+						blockp = tmpblockp;
+						putref(1, file, tmpfunc[i]);
+					}
+				}
+			}
+		}
+	}
+	
+	return NULL;
+}
+
+/* find the text in the source files */
+
+char *
+findstring(char *pattern)
+{
+	char	egreppat[2 * PATLEN];
+	char	*cp, *pp;
+
+	/* translate special characters in the regular expression */
+	cp = egreppat;
+	for (pp = pattern; *pp != '\0'; ++pp) {
+		if (strchr(".*[\\^$+?|()", *pp) != NULL) {
+			*cp++ = '\\';
+		}
+		*cp++ = *pp;
+	}
+	*cp = '\0';
+	
+	/* search the source files */
+	return(findregexp(egreppat));
+}
+
+/* find this regular expression in the source files */
+
+char *
+findregexp(char *egreppat)
+{
+    unsigned int i;
+    char *egreperror;
+
+    /* compile the pattern */
+    if ((egreperror = egrepinit(egreppat)) == NULL) {
+
+	/* search the files */
+	for (i = 0; i < nsrcfiles; ++i) {
+	    char *file = filepath(srcfiles[i]);
+
+	    progress("Search", searchcount, nsrcfiles);
+	    if (egrep(file, refsfound, "%s <unknown> %ld ") < 0) {
+		posterr ("Cannot open file %s", file);
+	    }
+	}
+    }
+    return(egreperror);
+}
+
+/* find matching file names */
+
+char *
+findfile(char *dummy)
+{
+    unsigned int i;
+	
+    (void) dummy;		/* unused argument */
+
+    for (i = 0; i < nsrcfiles; ++i) {
+	char *s;
+
+	if (caseless == YES) {
+	    s = lcasify(srcfiles[i]);
+	} else {
+	    s = srcfiles[i];
+	}
+	if (regexec (&regexp, s, (size_t)0, NULL, 0) == 0) {
+	    (void) fprintf(refsfound, "%s <unknown> 1 <unknown>\n", 
+			   srcfiles[i]);
+	}
+    }
+
+    return NULL;
+}
+
+/* find files #including this file */
+
+char *
+findinclude(char *pattern)
+{
+	char	file[PATHLEN + 1];	/* source file name */
+
+	if (invertedindex == YES) {
+		POSTING *p;
+
+		findterm(pattern);
+		while ((p = getposting()) != NULL) {
+			if (p->type == INCLUDE) {
+				putpostingref(p, 0);
+                        }
+                }
+                return NULL;
+        }
+
+	/* find the next file name or function definition */
+	while (scanpast('\t') != NULL) {
+		switch (*blockp) {
+			
+		case NEWFILE:		/* save file name */
+			skiprefchar();
+			fetch_string_from_dbase(file, sizeof(file));
+			if (*file == '\0') {	/* if end of symbols */
+				return NULL;
+			}
+			progress("Search", searchcount, nsrcfiles);
+			break;
+			
+		case INCLUDE:		/* match function called to pattern */
+			skiprefchar();
+			skiprefchar();	/* skip global or local #include marker */
+			if (match()) {
+				
+				/* output the file and source line */
+				putref(0, file, global);
+			}
+		}
+	}
+	
+	return NULL;
+}
+
+/* initialize */
+
+FINDINIT
+findinit(char *pattern)
+{
+	char	buf[PATLEN + 3];
+	BOOL	isregexp = NO;
+	int	i;
+	char	*s;
+	unsigned char c;	/* HBB 20010427: changed uint to uchar */
+
+	/* HBB: be nice: free regexp before allocating a new one */
+	if(isregexp_valid == YES)
+		regfree(&regexp);
+
+	isregexp_valid = NO;
+
+	/* remove trailing white space */
+	for (s = pattern + strlen(pattern) - 1; 
+	     isspace((unsigned char)*s);
+	     --s) {
+		*s = '\0';
+	}
+
+	/* HBB 20020620: new: make sure pattern is lowercased. Curses
+	 * mode gets this right all on its own, but at least -L mode
+	 * doesn't */
+	if (caseless == YES) {
+		pattern = lcasify(pattern);
+	}
+
+	/* allow a partial match for a file name */
+	if (field == FILENAME || field == INCLUDES) {
+		if (regcomp (&regexp, pattern, REG_EXTENDED | REG_NOSUB) != 0) { 
+			return(REGCMPERROR);
+		} else {
+			isregexp_valid = YES;
+		}
+		return(NOERROR);
+	}
+	/* see if the pattern is a regular expression */
+	if (strpbrk(pattern, "^.[{*+$|(") != NULL) {
+		isregexp = YES;
+	} else {
+		/* check for a valid C symbol */
+		s = pattern;
+		if (!isalpha((unsigned char)*s) && *s != '_') {
+			return(NOTSYMBOL);
+		}
+		while (*++s != '\0') {
+			if (!isalnum((unsigned char)*s) && *s != '_') {
+				return(NOTSYMBOL);
+			}
+		}
+		/* look for use of the -T option (truncate symbol to 8
+		   characters) on a database not built with -T */
+		if (trun_syms == YES && isuptodate == YES &&
+		    dbtruncated == NO && s - pattern >= 8) {
+			(void) strcpy(pattern + 8, ".*");
+			isregexp = YES;
+		}
+	}
+	/* if this is a regular expression or letter case is to be ignored */
+	/* or there is an inverted index */
+	if (isregexp == YES || caseless == YES || invertedindex == YES) {
+
+		/* remove a leading ^ */
+		s = pattern;
+		if (*s == '^') {
+			(void) strcpy(newpat, s + 1);
+			(void) strcpy(s, newpat);
+		}
+		/* remove a trailing $ */
+		i = strlen(s) - 1;
+		if (s[i] == '$') {
+			if (i > 0  && s[i-1] == '\\' ) {
+				s[i-1] = '$';
+			}
+			s[i] = '\0';
+		}
+		/* if requested, try to truncate a C symbol pattern */
+		if (trun_syms == YES && strpbrk(s, "[{*+") == NULL) {
+			s[8] = '\0';
+		}
+		/* must be an exact match */
+		/* note: regcomp doesn't recognize ^*keypad$ as a syntax error
+		         unless it is given as a single arg */
+		(void) snprintf(buf, sizeof(buf), "^%s$", s);
+		if (regcomp (&regexp, buf, REG_EXTENDED | REG_NOSUB) != 0) {
+			return(REGCMPERROR);
+		}
+		else
+		{
+			isregexp_valid = YES;
+		}
+	}
+	else {
+		/* if requested, truncate a C symbol pattern */
+		if (trun_syms == YES && field <= CALLING) {
+			pattern[8] = '\0';
+		}
+		/* compress the string pattern for matching */
+		s = cpattern;
+		for (i = 0; (c = pattern[i]) != '\0'; ++i) {
+			if (IS_A_DICODE(c, pattern[i + 1])) {
+				c = DICODE_COMPRESS(c, pattern[i + 1]);
+				++i;
+			}
+			*s++ = c;
+		}
+		*s = '\0';
+	}
+	return(NOERROR);
+}
+
+void
+findcleanup(void)
+{
+	/* discard any regular expression */
+}
+
+/* match the pattern to the string */
+
+static BOOL
+match(void)
+{
+	char	string[PATLEN + 1];
+
+	/* see if this is a regular expression pattern */
+	if (isregexp_valid == YES) {
+		fetch_string_from_dbase(string, sizeof(string));
+		if (*string == '\0') {
+			return(NO);
+		}
+		if (caseless == YES) {
+			return (regexec (&regexp, lcasify(string), (size_t)0, NULL, 0) ? NO : YES);
+		}
+		else {
+			return (regexec (&regexp, string, (size_t)0, NULL, 0) ? NO : YES);
+		}
+	}
+	/* it is a string pattern */
+	return((BOOL) (*blockp == cpattern[0] && matchrest()));
+}
+
+/* match the rest of the pattern to the name */
+
+static BOOL
+matchrest(void)
+{
+	int	i = 1;
+	
+	skiprefchar();
+	do {
+		while (*blockp == cpattern[i]) {
+			++blockp;
+			++i;
+		}
+	} while (*(blockp + 1) == '\0' && read_block() != NULL);
+	
+	if (*blockp == '\n' && cpattern[i] == '\0') {
+		return(YES);
+	}
+	return(NO);
+}
+
+/* put the reference into the file */
+
+static void
+putref(int seemore, char *file, char *func)
+{
+	FILE	*output;
+
+	if (strcmp(func, global) == 0) {
+		output = refsfound;
+	}
+	else {
+		output = nonglobalrefs;
+	}
+	(void) fprintf(output, "%s %s ", file, func);
+	putsource(seemore, output);
+}
+
+/* put the source line into the file */
+
+static void
+putsource(int seemore, FILE *output)
+{
+	char *tmpblockp;
+	char	*cp, nextc = '\0';
+	BOOL Change = NO, retreat = NO;
+	
+	if (fileversion <= 5) {
+		(void) scanpast(' ');
+		putline(output);
+		(void) putc('\n', output);
+		return;
+	}
+	/* scan back to the beginning of the source line */
+	cp = tmpblockp = blockp;
+	while (*cp != '\n' || nextc != '\n') {
+		nextc = *cp;
+		if (--cp < block) {
+			retreat = YES;
+			/* read the previous block */
+			(void) dbseek((blocknumber - 1) * BUFSIZ);
+			cp = block + (BUFSIZ - 1);
+		}
+	}
+	blockp = cp;
+	if (*blockp != '\n' || getrefchar() != '\n' || 
+	    (!isdigit(getrefchar()) && fileversion >= 12)) {
+		postfatal("Internal error: cannot get source line from database");
+		/* NOTREACHED */
+	}
+	/* until a double newline is found */
+	do {
+		/* skip a symbol type */
+		if (*blockp == '\t') {
+			/* if retreat == YES, that means tmpblockp and blockp
+			 * point to different blocks.  Offset comparison should
+			 * NOT be performed until they point to the same block.
+			 */
+ 			if (seemore && Change == NO && retreat == NO &&
+				blockp > tmpblockp) {
+					Change = YES;
+					cp = blockp;
+			}
+			skiprefchar();
+			skiprefchar();
+		}
+		/* output a piece of the source line */
+		putline(output);
+		if (retreat == YES) retreat = NO;
+	} while (blockp != NULL && getrefchar() != '\n');
+	(void) putc('\n', output);
+	if (Change == YES) blockp = cp;
+}
+
+/* put the rest of the cross-reference line into the file */
+
+static void
+putline(FILE *output)
+{
+	char	*cp;
+	unsigned c;
+	
+	setmark('\n');
+	cp = blockp;
+	do {
+		while ((c = (unsigned)(*cp)) != '\n') {
+			
+			/* check for a compressed digraph */
+			if (c > '\177') {
+				c &= 0177;
+				(void) putc(dichar1[c / 8], output);
+				(void) putc(dichar2[c & 7], output);
+			}
+			/* check for a compressed keyword */
+			else if (c < ' ') {
+				(void) fputs(keyword[c].text, output);
+				if (keyword[c].delim != '\0') {
+					(void) putc(' ', output);
+				}
+				if (keyword[c].delim == '(') {
+					(void) putc('(', output);
+				}
+			}
+			else {
+				(void) putc((int) c, output);
+			}
+			++cp;
+		}
+	} while (*(cp + 1) == '\0' && (cp = read_block()) != NULL);
+	blockp = cp;
+}
+
+
+/* put the rest of the cross-reference line into the string */
+void
+fetch_string_from_dbase(char *s, size_t length)
+{
+	char	*cp;
+	unsigned int c;
+
+	assert(length > sizeof (char *));
+
+	setmark('\n');
+	cp = blockp;
+	do {
+		while (length > 1 && (c = (unsigned int)(*cp)) != '\n') {
+			if (c >= 0x80 && length > 2) {
+				c &= 0x7f;
+				*s++ = dichar1[c / 8];
+				*s++ = dichar2[c & 7];
+				length -= 2;
+			} else {
+				*s++ = c;
+				length--;
+			}
+			++cp;
+		}
+	} while (length > 0 && cp[1] == '\0' && (cp = read_block()) != NULL);
+	blockp = cp;
+	*s = '\0';
+}
+
+
+/* scan past the next occurence of this character in the cross-reference */
+char *
+scanpast(char c)
+{
+	char *cp;
+	
+	setmark(c);
+	cp = blockp;
+	do {	/* innermost loop optimized to only one test */
+		while (*cp != c) {
+			++cp;
+		}
+	} while (*(cp + 1) == '\0' && (cp = read_block()) != NULL);
+	blockp = cp;
+	if (cp != NULL) {
+		skiprefchar();	/* skip the found character */
+	}
+	return(blockp);
+}
+
+/* read a block of the cross-reference */
+/* HBB 20040430: renamed from readblock(), to avoid name clash on QNX */
+char *
+read_block(void)
+{
+	/* read the next block */
+	blocklen = read(symrefs, block, BUFSIZ);
+	blockp = block;
+	
+	/* add the search character and end-of-block mark */
+	block[blocklen] = blockmark;
+	block[blocklen + 1] = '\0';
+	
+	/* return NULL on end-of-file */
+	if (blocklen == 0) {
+		blockp = NULL;
+	}
+	else {
+		++blocknumber;
+	}
+	return(blockp);
+}
+
+static char	*
+lcasify(char *s)
+{
+	static char ls[PATLEN+1];	/* largest possible match string */
+	char *lptr = ls;
+	
+	while(*s) {
+		*lptr = tolower((unsigned char)*s);
+		lptr++;
+		s++;
+	}
+	*lptr = '\0';
+	return(ls);
+}
+
+/* find the functions called by this function */
+
+/* HBB 2000/05/05: for consitency of calling interface between the
+ * different 'find...()' functions, this now returns a char pointer,
+ * too. Implemented as a pointer to static storage containing 'y' or
+ * 'n', for the boolean result values YES and NO */
+
+char *
+findcalledby(char *pattern)
+{
+	char	file[PATHLEN + 1];	/* source file name */
+	static char found_caller = 'n'; /* seen calling function? */
+	BOOL	macro = NO;
+
+	if (invertedindex == YES) {
+		POSTING	*p;
+		
+		findterm(pattern);
+		while ((p = getposting()) != NULL) {
+			switch (p->type) {
+			case DEFINE:		/* could be a macro */
+			case FCNDEF:
+				if (dbseek(p->lineoffset) != -1 &&
+				    scanpast('\t') != NULL) {	/* skip def */
+					found_caller = 'y';
+					findcalledbysub(srcfiles[p->fileindex], macro);
+				}
+			}
+		}
+		return(&found_caller);
+	}
+	/* find the function definition(s) */
+	while (scanpast('\t') != NULL) {
+		switch (*blockp) {
+			
+		case NEWFILE:
+			skiprefchar();	/* save file name */
+			fetch_string_from_dbase(file, sizeof(file));
+			if (*file == '\0') {	/* if end of symbols */
+				return(&found_caller);
+			}
+			progress("Search", searchcount, nsrcfiles);
+			break;
+
+		case DEFINE:		/* could be a macro */
+			if (fileversion < 10) {
+				break;
+			}
+			macro = YES;
+			/* FALLTHROUGH */
+
+		case FCNDEF:
+			skiprefchar();	/* match name to pattern */
+			if (match()) {
+				found_caller = 'y';
+				findcalledbysub(file, macro);
+			}
+			break;
+		}
+	}
+
+	return (&found_caller);
+}
+
+/* find this term, which can be a regular expression */
+
+static void
+findterm(char *pattern)
+{
+	char	*s;
+	int	len;
+	char	prefix[PATLEN + 1];
+	char	term[PATLEN + 1];
+
+	npostings = 0;		/* will be non-zero after database built */
+	lastfcnoffset = 0;	/* clear the last function name found */
+	boolclear();		/* clear the posting set */
+
+	/* get the string prefix (if any) of the regular expression */
+	(void) strcpy(prefix, pattern);
+	if ((s = strpbrk(prefix, ".[{*+")) != NULL) {
+		*s = '\0';
+	}
+	/* if letter case is to be ignored */
+	if (caseless == YES) {
+		
+		/* convert the prefix to upper case because it is lexically
+		   less than lower case */
+		s = prefix;
+		while (*s != '\0') {
+ 			*s = toupper((unsigned char)*s);
+			++s;
+		}
+	}
+	/* find the term lexically >= the prefix */
+	(void) invfind(&invcontrol, prefix);
+	if (caseless == YES) {	/* restore lower case */
+		(void) strcpy(prefix, lcasify(prefix));
+	}
+	/* a null prefix matches the null term in the inverted index,
+	   so move to the first real term */
+	if (*prefix == '\0') {
+		(void) invforward(&invcontrol);
+	}
+	len = strlen(prefix);
+	do {
+		(void) invterm(&invcontrol, term);	/* get the term */
+		s = term;
+		if (caseless == YES) {
+			s = lcasify(s);	/* make it lower case */
+		}
+		/* if it matches */
+		if (regexec (&regexp, s, (size_t)0, NULL, 0) == 0) {
+	
+			/* add its postings to the set */
+			if ((postingp = boolfile(&invcontrol, &npostings, BOOL_OR)) == NULL) {
+				break;
+			}
+		}
+		/* if there is a prefix */
+		else if (len > 0) {
+			
+			/* if ignoring letter case and the term is out of the
+			   range of possible matches */
+			if (caseless == YES) {
+				if (strncmp(term, prefix, len) > 0) {
+					break;	/* stop searching */
+				}
+			}
+			/* if using letter case and the prefix doesn't match */
+			else if (strncmp(term, prefix, len) != 0) {
+				break;	/* stop searching */
+			}
+		}
+		/* display progress about every three seconds */
+		if (++searchcount % 50 == 0) {
+			progress("Symbols matched", searchcount, totalterms);
+		}
+	} while (invforward(&invcontrol));	/* while didn't wrap around */
+	
+	/* initialize the progress message for retrieving the references */
+	searchcount = 0;
+	postingsfound = npostings;
+}
+
+/* get the next posting for this term */
+
+static POSTING *
+getposting(void)
+{
+	if (npostings-- <= 0) {
+		return(NULL);
+	}
+	/* display progress about every three seconds */
+	if (++searchcount % 100 == 0) {
+		progress("Possible references retrieved", searchcount,
+		    postingsfound);
+	}
+	return(postingp++);
+}
+
+/* put the posting reference into the file */
+
+static void
+putpostingref(POSTING *p, char *pat)
+{
+	// initialize function to "unknown" so that the first line of temp1
+	// is properly formed if symbol matches a header file entry first time
+	static char function[PATLEN + 1] = "unknown";/* function name */
+
+	if (p->fcnoffset == 0) {
+		if (p->type == FCNDEF) { /* need to find the function name */
+			if (dbseek(p->lineoffset) != -1) {
+				scanpast(FCNDEF);
+				fetch_string_from_dbase(function, sizeof(function));
+			}
+		}
+		else if (p->type != FCNCALL) {
+			strcpy(function, global);
+		}
+	}
+	else if (p->fcnoffset != lastfcnoffset) {
+		if (dbseek(p->fcnoffset) != -1) {
+			fetch_string_from_dbase(function, sizeof(function));
+			lastfcnoffset = p->fcnoffset;
+		}
+	}
+	if (dbseek(p->lineoffset) != -1) {
+		if (pat)
+			putref(0, srcfiles[p->fileindex], pat);
+		else
+			putref(0, srcfiles[p->fileindex], function);
+	}
+}
+
+/* seek to the database offset */
+
+long
+dbseek(long offset)
+{
+	long	n;
+	int	rc = 0;
+	
+	if ((n = offset / BUFSIZ) != blocknumber) {
+		if ((rc = lseek(symrefs, n * BUFSIZ, 0)) == -1) {
+			myperror("Lseek failed");
+			(void) sleep(3);
+			return(rc);
+		}
+		(void) read_block();
+		blocknumber = n;
+	}
+	blockp = block + offset % BUFSIZ;
+	return(rc);
+}
+
+static void
+findcalledbysub(char *file, BOOL macro)
+{
+	/* find the next function call or the end of this function */
+	while (scanpast('\t') != NULL) {
+		switch (*blockp) {
+		
+		case DEFINE:		/* #define inside a function */
+			if (fileversion >= 10) {	/* skip it */
+				while (scanpast('\t') != NULL &&
+				    *blockp != DEFINEEND) 
+					;
+			}
+			break;
+		
+		case FCNCALL:		/* function call */
+
+			/* output the file name */
+			(void) fprintf(refsfound, "%s ", file);
+
+			/* output the function name */
+			skiprefchar();
+			putline(refsfound);
+			(void) putc(' ', refsfound);
+
+			/* output the source line */
+			putsource(1, refsfound);
+			break;
+
+		case DEFINEEND:		/* #define end */
+			
+			if (invertedindex == NO) {
+				if (macro == YES) {
+					return;
+				}
+				break;	/* inside a function */
+			}
+			/* FALLTHROUGH */
+
+		case FCNDEF:		/* function end (pre 9.5) */
+
+			if (invertedindex == NO) break;
+			/* FALLTHROUGH */
+
+		case FCNEND:		/* function end */
+		case NEWFILE:		/* file end */
+			return;
+		}
+	}
+}
diff --git a/src/fscanner.l b/src/fscanner.l
new file mode 100644
index 0000000..5d6e8d1
--- /dev/null
+++ b/src/fscanner.l
@@ -0,0 +1,904 @@
+%{
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	C symbol scanner
+ */
+#include "global.h"
+
+#include "scanner.h"
+#include "lookup.h"
+
+#include <assert.h>
+
+/* the line counting has been moved from character reading for speed */
+/* comments are discarded */
+
+#ifndef FLEX_SCANNER
+# error Sorry, this scanner needs flex. It is not usable with AT&T Lex.
+#endif
+
+#define	IFLEVELINC	5	/* #if nesting level size increment */
+#define YY_NO_TOP_STATE 1
+
+int	first;	/* buffer index for first char of symbol */
+int	last;	/* buffer index for last char of symbol */
+int	lineno;	/* symbol line number */
+int	myylineno = 1;
+
+/* HBB 20001007: new variables, emulating yytext in a way that allows 
+ * the yymore() simulation, my_yymore(), to be used even in the presence of 
+ * yyless(). */
+size_t my_yyleng = 0;
+char *my_yytext = NULL;
+
+static	BOOL	arraydimension;		/* inside array dimension declaration */
+static	BOOL	bplisting;		/* breakpoint listing */
+static	int	braces;			/* unmatched left brace count */
+static	BOOL	classdef;		/* c++ class definition */
+static	BOOL	elseelif;		/* #else or #elif found */
+static	BOOL	esudef;			/* enum/struct/union global definition */
+static	BOOL	external;		/* external definition */
+static	int	externalbraces;		/* external definition outer brace count */
+static	BOOL	fcndef;			/* function definition */
+static	BOOL	global;			/* file global scope (outside functions) */
+static	size_t	iflevel;		/* #if nesting level */
+static	BOOL	initializer;		/* data initializer */
+static	int	initializerbraces;	/* data initializer outer brace count */
+static	BOOL	lex;			/* lex file */
+static	size_t	miflevel = IFLEVELINC;	/* maximum #if nesting level */
+static	int	*maxifbraces;		/* maximum brace count within #if */
+static	int	*preifbraces;		/* brace count before #if */
+static	int	parens;			/* unmatched left parenthesis count */
+static	BOOL	ppdefine;		/* preprocessor define statement */
+static	BOOL	pseudoelif;		/* pseudo-#elif */
+static	BOOL	oldtype;		/* next identifier is an old type */
+static	BOOL	rules;			/* lex/yacc rules */
+static	BOOL	sdl;			/* sdl file */
+static	BOOL	structfield;		/* structure field declaration */
+static	int	tagdef;			/* class/enum/struct/union tag definition */
+static	BOOL	template;		/* function template */
+static	int	templateparens;		/* function template outer parentheses count */
+static	int	typedefbraces = -1;	/* initial typedef brace count */
+static	int	token;			/* token found */
+static	int 	ident_start;		/* begin of preceding identifier */
+
+static	void	my_yymore(void);
+
+%}
+identifier	[a-zA-Z_$][a-zA-Z_0-9$]*
+number		\.?[0-9][.0-9a-fA-FlLuUxX]*
+comment		"/*"([^*]*("*"+[^/])?)*"*/"|"//"[^\n]*\n
+ws		[ \t\r\v\f]
+wsnl		[ \t\r\v\f\n]|{comment}
+
+/* flex options: stack of start conditions, and don't use yywrap() */
+%option stack
+%option noyywrap
+
+%start SDL
+%a 4000
+%o 7000
+
+/* exclusive start conditions. not available in AT&T lex -> use flex! */
+%x IN_PREPROC WAS_ENDIF WAS_IDENTIFIER WAS_ESU IN_DQUOTE IN_SQUOTE COMMENT
+
+%%
+
+%\{		{	/* lex/yacc C declarations/definitions */
+			global = YES;
+			goto more;
+			/* NOTREACHED */
+		}
+%\}		{
+			global = NO;
+			goto more;
+			/* NOTREACHED */
+		}
+^%%		{	/* lex/yacc rules delimiter */
+			braces = 0;
+			if (rules == NO) {
+				/* this %% starts the section containing the rules */
+				rules = YES;
+
+				/* Copy yytext to private buffer, to be able to add further
+				 * content following it: */
+				my_yymore();
+
+				/* simulate a yylex() or yyparse() definition */
+				(void) strcat(my_yytext, " /* ");
+				first = strlen(my_yytext);
+				if (lex == YES) {
+					(void) strcat(my_yytext, "yylex");
+				} else {	
+					/* yacc: yyparse implicitly calls yylex */
+					char *s = " yylex()";
+					char *cp = s + strlen(s);
+					while (--cp >= s) {
+						unput(*cp);
+					}
+					(void) strcat(my_yytext, "yyparse");
+				}
+				last = strlen(my_yytext);
+				(void) strcat(my_yytext, " */");
+				my_yyleng = strlen(my_yytext);
+				return(FCNDEF);
+			} else {
+				/* were in the rules section, now comes the closing one */
+				rules = NO;
+				global = YES;
+				last = first;
+				my_yymore();
+				return(FCNEND);
+				/* NOTREACHED */
+			}
+		}
+
+<SDL>STATE[ \t]+({identifier}|\*)	{ /* sdl state, treat as function def */
+			braces = 1;
+			fcndef = YES;
+			token = FCNDEF;
+			goto findident;
+			/* NOTREACHED */
+		}
+<SDL>ENDSTATE[ \t]	{ /* end of an sdl state, treat as end of a function */
+			goto endstate;
+			/* NOTREACHED */
+		}
+
+\{		{	/* count unmatched left braces for fcn def detection */
+			++braces;
+			
+			/* mark an untagged enum/struct/union so its beginning
+			   can be found */
+			if (tagdef) {
+				if (braces == 1) {
+					esudef = YES;
+				}
+				token = tagdef;
+				tagdef = '\0';
+				last = first;
+				my_yymore();
+				return(token);
+			}
+			goto more;
+			/* NOTREACHED */
+		}
+
+\#{ws}*	{ /* start a preprocessor line */
+			if (rules == NO)		/* don't consider CPP for lex/yacc rules */
+				BEGIN(IN_PREPROC);
+			yyleng = 1;	/* get rid of the blanks, if any */
+			goto more;
+			/* NOTREACHED */
+		}
+<IN_PREPROC>endif([^a-zA-Z0-9_$\n].*)?	{	/* #endif */
+			/* delay treatment of #endif depending on whether an
+			 * #if comes right after it, or not */
+			/* HBB 20010619: new pattern allows trailing garbage
+			 * after the #endif */
+			BEGIN(WAS_ENDIF);
+			goto more;
+			/* NOTREACHED */
+		}
+<WAS_ENDIF>\n{wsnl}*#{ws}*if(ndef|def)?{ws}+		{
+			/* attempt to correct erroneous brace count caused by:
+			 * 
+			 * #if ...
+			 * 	... {
+			 * #endif
+			 * #if ...
+			 * 	... {
+			 * #endif
+			 */
+			/* the current #if must not have an #else or #elif */
+			if (elseelif == YES) {
+				goto endif;
+				/* NOTREACHED */
+			}
+			pseudoelif = YES;
+			BEGIN(INITIAL);
+			yyless(1);	/* rescan all but the line ending */
+			yy_set_bol(1);
+			goto eol;
+			/* NOTREACHED */
+		}
+<WAS_ENDIF>\n{wsnl}*		 { 	/* an #endif with no #if right after it */
+		endif:
+			if (iflevel > 0) {
+				/* get the maximum brace count for this #if */
+				if (braces < maxifbraces[--iflevel]) {
+					braces = maxifbraces[iflevel];
+				}
+			}
+			BEGIN(INITIAL);
+			yyless(1);
+			yy_set_bol(1);
+			goto eol;
+			/* NOTREACHED */
+		}
+
+<IN_PREPROC>ifndef{ws}+	|
+<IN_PREPROC>ifdef{ws}+		|
+<IN_PREPROC>if{ws}+		{ /* #if directive */
+			elseelif = NO;
+			if (pseudoelif == YES) {
+				pseudoelif = NO;
+				goto elif;
+				/* NOTREACHED */
+			}
+			/* make sure there is room for the current brace count */
+			if (iflevel == miflevel) {
+				miflevel += IFLEVELINC;
+				maxifbraces = realloc(maxifbraces, miflevel * sizeof(*maxifbraces));
+				preifbraces = realloc(preifbraces, miflevel * sizeof(*preifbraces));
+			}
+			/* push the current brace count */
+			preifbraces[iflevel] = braces;
+			maxifbraces[iflevel++] = 0;
+			BEGIN(INITIAL);
+			goto more;
+			/* NOTREACHED */
+		}
+<IN_PREPROC>else({ws}.*)?	{ /* #else --- eat up whole line */
+			elseelif = YES;
+			if (iflevel > 0) {
+				
+				/* save the maximum brace count for this #if */
+				if (braces > maxifbraces[iflevel - 1]) {
+					maxifbraces[iflevel - 1] = braces;
+				}
+				/* restore the brace count to before the #if */
+				braces = preifbraces[iflevel - 1];
+			}
+			BEGIN(INITIAL);
+			goto more;
+			/* NOTREACHED */
+		}
+<IN_PREPROC>elif{ws}+	{ /* #elif */
+			/* elseelif = YES; --- HBB I doubt this is correct */
+		elif:
+			if (iflevel > 0) {
+				
+				/* save the maximum brace count for this #if */
+				if (braces > maxifbraces[iflevel - 1]) {
+					maxifbraces[iflevel - 1] = braces;
+				}
+				/* restore the brace count to before the #if */
+				braces = preifbraces[iflevel - 1];
+			}
+			BEGIN(INITIAL);
+			goto more;
+			/* NOTREACHED */
+		}
+
+<IN_PREPROC>include{ws}*\"[^"\n]+\" |
+<IN_PREPROC>include{ws}*<[^>\n]+> 	{ /* #include file */
+			char	*s;
+			char remember = yytext[yyleng-1];
+			
+			my_yymore();
+			s = strpbrk(my_yytext, "\"<");
+			if (!s)
+				return(LEXERR);
+			my_yytext[my_yyleng-1] = '\0';
+			incfile(s + 1, s);
+			my_yytext[my_yyleng-1] = remember;
+			first = s - my_yytext;
+			last = my_yyleng - 1;
+			if (compress == YES) {
+				my_yytext[0] = '\2';	/* compress the keyword */
+			}
+			BEGIN(INITIAL);
+			return(INCLUDE);
+			/* NOTREACHED */
+		}
+
+\}		{
+			/* could be the last enum member initializer */
+			if (braces == initializerbraces) {
+				initializerbraces = -1;
+				initializer = NO;
+			}
+			if (--braces <= 0) {
+		endstate:
+				braces = 0;
+				classdef = NO;
+			}
+			if (braces == 0 || (braces == 1 && classdef == YES)) {
+
+				/* if the end of an enum/struct/union definition */
+				if (esudef == YES) {
+					esudef = NO;
+				}
+				/* if the end of the function */
+				else if (fcndef == YES) {
+					fcndef = NO;
+					last = first;
+					my_yymore();
+					return(FCNEND);
+				}
+			}
+			goto more;
+			/* NOTREACHED */
+		}
+
+\(		{	/* count unmatched left parentheses for function templates */
+			++parens;
+			goto more;
+			/* NOTREACHED */
+		}
+\)		{
+			if (--parens <= 0) {
+				parens = 0;
+			}
+			/* if the end of a function template */
+			if (parens == templateparens) {
+				templateparens = -1;
+				template = NO;
+			}
+			goto more;
+			/* NOTREACHED */
+		}
+=		{	/* if a global definition initializer */
+			if (!my_yytext)
+				return(LEXERR);
+			if (global == YES && ppdefine == NO && my_yytext[0] != '#') {
+				initializerbraces = braces;
+				initializer = YES;
+			}
+			goto more;
+			/* NOTREACHED */
+		}
+:		{	/* a if global structure field */
+			if (!my_yytext)
+				return(LEXERR);
+			if (global == YES && ppdefine == NO && my_yytext[0] != '#') {
+				structfield = YES;
+			}
+			goto more;
+			/* NOTREACHED */
+		}
+\,		{
+			if (braces == initializerbraces) {
+				initializerbraces = -1;
+				initializer = NO;
+			}
+			structfield = NO;
+			goto more;
+			/* NOTREACHED */
+		}
+;		{	/* if the enum/struct/union was not a definition */
+			if (braces == 0) {
+				esudef = NO;
+			}
+			/* if the end of a typedef */
+			if (braces == typedefbraces) {
+				typedefbraces = -1;
+			}
+			/* if the end of a external definition */
+			if (braces == externalbraces) {
+				externalbraces = -1;
+				external = NO;
+			}
+			structfield = NO;
+			initializer = NO;
+			goto more;
+			/* NOTREACHED */
+		}
+<IN_PREPROC>define{ws}+{identifier}	{
+				
+			/* preprocessor macro or constant definition */
+			ppdefine = YES;
+			token = DEFINE;
+			if (compress == YES) {
+				my_yytext[0] = '\1';	/* compress the keyword */
+			}
+		findident:
+			/* search backwards through yytext[] to find the identifier */
+			/* NOTE: this had better be left to flex, by use of
+			 * yet another starting condition */
+			my_yymore();
+			first = my_yyleng - 1;
+			while (my_yytext[first] != ' ' && my_yytext[first] != '\t') {
+				--first;
+			}
+			++first;
+			last = my_yyleng;
+			BEGIN(INITIAL);
+			goto definition;
+			/* NOTREACHED */
+		}
+<IN_PREPROC>\n	{   /* unknown preprocessor line */
+			BEGIN(INITIAL);
+                        ++myylineno;
+			goto more;
+			/* NOTREACHED */
+		}
+<IN_PREPROC>.		 |
+<IN_PREPROC>{identifier}	{   /* unknown preprocessor line */
+			BEGIN(INITIAL);
+			goto more;
+			/* NOTREACHED */
+		}
+
+class{wsnl}+{identifier}({wsnl}|{identifier}|[():])*\{	{	/* class definition */
+			classdef = YES;
+			tagdef =  'c';
+			yyless(5);		/* eat up 'class', and re-scan */
+			yy_set_bol(0);
+			goto more;
+			/* NOTREACHED */
+		}
+
+("enum"|"struct"|"union")	{
+			ident_start = first;
+			BEGIN(WAS_ESU);
+			goto more;
+		}
+<WAS_ESU>{
+({wsnl}+{identifier}){wsnl}*\{		{ /* e/s/u definition */
+			tagdef = my_yytext[ident_start];
+			BEGIN(WAS_IDENTIFIER);
+			goto ident;
+		}
+{wsnl}*\{		{ /* e/s/u definition without a tag */
+			tagdef = my_yytext[ident_start];
+			BEGIN(INITIAL);
+			if (braces == 0) {
+				esudef = YES;
+			}
+			last = first;
+			yyless(0);  /* re-scan all this as normal text */
+			tagdef = '\0';
+			goto more;
+		}
+({wsnl}+{identifier})?{wsnl}* 	|   
+.|\n										{   /* e/s/u usage */
+			BEGIN(WAS_IDENTIFIER);
+			goto ident;
+		}
+}
+
+if{wsnl}*\(	{ 	/* ignore 'if' */
+			yyless(2);
+			yy_set_bol(0);
+			goto more;
+}	
+
+{identifier}	{	/* identifier found: do nothing, yet. (!) */
+			BEGIN(WAS_IDENTIFIER);
+			ident_start = first;
+			goto more;
+			/* NOTREACHED */
+		}
+
+<WAS_IDENTIFIER>{       
+{ws}*\(({wsnl}|{identifier}|{number}|[*&[\]=,.:])*\)([()]|{wsnl})*[:a-zA-Z_#{]	{
+			/* a function definition */
+			/* note: "#define a (b) {" and "#if defined(a)\n#" 
+			 * are not fcn definitions! */
+			/* warning: "if (...)" must not overflow yytext, 
+			 * so the content of function argument definitions 
+			 * is restricted, in particular parentheses are 
+			 * not allowed */
+			/* FIXME HBB 20001003: the above 'not allowed' may well be the
+			 * reason for the parsing bug concerning function pointer usage,
+			 * I suspect. --- I think my new special-case rule for 'if'
+			 * could be helpful in removing that limitation */
+			if ((braces == 0 && ppdefine == NO && my_yytext[0] != '#' && rules == NO) ||
+			    (braces == 1 && classdef == YES)) {
+				fcndef = YES;
+				token = FCNDEF;
+				goto fcn;
+				/* NOTREACHED */
+			}
+			goto fcncal;
+			/* NOTREACHED */
+		}
+{ws}*\(([*&[\]=,.]|{identifier}|{number}|{wsnl})*		{ 	/* function call */
+		fcncal:	if (fcndef == YES || ppdefine == YES || rules == YES) {
+				token = FCNCALL;
+				goto fcn;
+				/* NOTREACHED */
+			}
+			if (template == NO) {
+				templateparens = parens;
+				template = YES;
+			}
+			goto ident;
+			/* NOTREACHED */
+		}
+("*"|{wsnl})+{identifier}		{	/* typedef name or modifier use */
+			goto ident;
+			/* NOTREACHED */
+		}
+.|\n	{		/* general identifer usage */
+			char	*s;
+
+			if (global == YES && ppdefine == NO && my_yytext[0] != '#' &&
+			    external == NO && initializer == NO && 
+			    arraydimension == NO && structfield == NO &&
+			    template == NO && fcndef == NO) {
+				if (esudef == YES) {	
+					/* if enum/struct/union */
+					token = MEMBERDEF;
+				} else {
+					token = GLOBALDEF;
+				}
+			} else {
+		ident:
+				token = IDENT;
+			}
+		fcn:
+			if (YYSTATE == WAS_IDENTIFIER) {
+				/* Position back to the actual identifier: */
+				last = first; 
+				first = ident_start;
+				yyless(0);
+				/* HBB 20001008: if the anti-backup-pattern above matched,
+				 * and the matched context ended with a \n, then the scanner
+				 * believes it's at the start of a new line. But the yyless()
+				 * should feeds that \n back into the input, so that's
+				 * wrong. --> force 'beginning-of-line' status off. */
+				yy_set_bol(0);
+				BEGIN(INITIAL);
+			} else {
+				my_yymore();
+				last = my_yyleng;
+			}
+		definition:
+
+			/* if a long line */
+			if (yyleng > STMTMAX) {
+				int	c;
+				
+				/* skip to the end of the line */
+				warning("line too long");
+				while ((c = input()) > LEXEOF) { 
+					if (c == '\n') {
+						unput(c);
+						break;
+					}
+				}
+			}
+			/* truncate a long symbol */
+			if (yyleng > PATLEN) {
+				warning("symbol too long");
+				my_yyleng = first + PATLEN;
+				my_yytext[my_yyleng] = '\0';
+			}
+
+			/* if found word was a keyword: */
+			if ((s = lookup(my_yytext + first)) != NULL) {
+				first = my_yyleng;
+				
+				/* if the start of a typedef */
+				if (s == typedeftext) {
+					typedefbraces = braces;
+					oldtype = YES;
+				}
+				/* if an enum/struct/union */
+				/* (needed for "typedef struct tag name;" so
+				   tag isn't marked as the typedef name) */
+				else if (s == enumtext || s == structtext || s == uniontext) {
+					/* do nothing */
+				} else if (s == externtext) {
+					/* if an external definition */
+					externalbraces = braces;
+					external = YES;
+				} else if (templateparens == parens && template == YES) {
+					/* keyword doesn't start a function 
+					 * template */
+					templateparens = -1;
+					template = NO;
+				} else {	
+					/* identifier after typedef was a 
+					 * keyword */
+					oldtype = NO;
+				}
+			} else {	
+				/* not a keyword --> found an identifier */
+				/* last = yyleng; */
+				
+				/* if a class/enum/struct/union tag definition */
+				/* FIXME HBB 20001001: why reject "class"? */
+				if (tagdef && strnotequal(my_yytext + first, "class")) {
+					token = tagdef;
+					tagdef = '\0';
+					if (braces == 0) {
+						esudef = YES;
+					}
+				} else if (braces == typedefbraces && oldtype == NO &&
+				           arraydimension == NO) {
+					/* if a typedef name */
+					token = TYPEDEF;
+				} else {
+					oldtype = NO;
+				}
+				/* my_yymore(); */
+				return(token);
+				/* NOTREACHED */
+			}
+		}
+}
+
+\[		{	/* array dimension (don't worry or about subscripts) */
+			arraydimension = YES;
+			goto more;
+			/* NOTREACHED */
+		}
+\]		{
+			arraydimension = NO;
+			goto more;
+			/* NOTREACHED */
+		}
+\\\n		{	/* preprocessor statement is continued on next line */
+			/* save the '\\' to the output file, but not the '\n': */
+			yyleng = 1;
+			my_yymore();
+			goto eol;
+			/* NOTREACHED */
+		}
+\n		{	/* end of the line */
+			if (ppdefine == YES) {	/* end of a #define */
+				ppdefine = NO;
+				yyless(yyleng - 1);
+				last = first;
+				my_yymore();
+				return(DEFINEEND);
+			}
+			/* skip the first 8 columns of a breakpoint listing line */
+			/* and skip the file path in the page header */
+			if (bplisting == YES) {
+				int	c, i;
+
+				/* FIXME HBB 20001007: should call input() instead */
+				switch (input()) {	/* tab and EOF just fall through */
+				case ' ':	/* breakpoint number line */
+				case '[':
+					for (i = 1; i < 8 && input() > LEXEOF; ++i)
+						;
+					break;
+				case '.':	/* header line */
+				case '/':
+					/* skip to the end of the line */
+					while ((c = input()) > LEXEOF) {
+						if (c == '\n') {
+							unput(c);
+							break;
+						}
+					}
+					break;
+				case '\n':	/* empty line */
+					unput('\n');
+					break;
+				}
+			}
+		eol:
+			++myylineno;
+			first = 0;
+			last = 0;
+			if (symbols > 0) {
+				/* no my_yymore(): \n doesn't need to be in my_yytext */
+				return(NEWLINE);
+			}
+			/* line ended --> flush my_yytext */
+			if (my_yytext)
+				*my_yytext = '\0';
+			my_yyleng = 0;
+			lineno = myylineno;
+		}
+
+\'		{	/* character constant */
+			if (sdl == NO) 
+				BEGIN(IN_SQUOTE);
+			goto more;
+			/* NOTREACHED */
+		}
+<IN_SQUOTE>\'	{	
+			BEGIN(INITIAL);
+			goto more;
+			/* NOTREACHED */
+		}
+\"		{	/* string constant */
+			BEGIN(IN_DQUOTE);
+			goto more;
+			/* NOTREACHED */
+		}
+<IN_DQUOTE>\"	{	
+			BEGIN(INITIAL);
+			goto more;
+			/* NOTREACHED */
+		}
+<IN_DQUOTE,IN_SQUOTE>{
+\n	  	{	/* syntax error: unexpected EOL */
+			BEGIN(INITIAL);
+			goto eol;
+			/* NOTREACHED */
+		}
+\\.	|
+.		{
+			goto more;
+			/* NOTREACHED */
+		}
+\\\n 	{		/* line continuation inside a string! */
+			myylineno++;
+			goto more;
+			/* NOTREACHED */
+		}
+}
+	
+^{ws}+		{		/* don't save leading white space */
+		}
+		
+{ws}+\n 	{		/* eat whitespace at end of line */
+			unput('\n');
+		}
+
+[\t\r\v\f]+	{	/* eat non-blank whitespace sequences, replace
+			 * by single blank */
+			unput(' ');
+		}
+
+{ws}{2,}	{   /* compress sequential whitespace here, not in putcrossref() */
+			unput(' ');
+ 		}
+
+"/*"					yy_push_state(COMMENT);
+<COMMENT>{
+[^*\n]*			|
+"*"+[^*/\n]*	; /* do nothing */
+[^*\n]*\n		|
+"*"+[^*/\n]*\n	{
+			if (ppdefine == NO) {
+				goto eol;
+			} else {
+				++myylineno;
+			}
+			/* NOTREACHED */
+		}
+"*"+"/"		{
+			/* replace the comment by a single blank */
+			unput(' ');
+			yy_pop_state();
+		}
+}		
+
+"//".*\n?		{
+			/* C++-style one-line comment */
+			goto eol;
+			/* NOTREACHED */
+		}
+
+{number}				|	/* number */
+<SDL>STATE[ \t]+		|   /* ... and other syntax error catchers... */
+.						{	/* punctuation and operators */
+						more:	
+							my_yymore();
+							first = my_yyleng;
+						}
+
+%%
+
+void
+initscanner(char *srcfile)
+{
+	char	*s;
+	
+	if (maxifbraces == NULL) {
+		maxifbraces = malloc(miflevel * sizeof(*maxifbraces));
+		preifbraces = malloc(miflevel * sizeof(*preifbraces));
+	}
+	first = 0;		/* buffer index for first char of symbol */
+	last = 0;		/* buffer index for last char of symbol */
+	lineno = 1;		/* symbol line number */
+	myylineno = 1;		/* input line number */
+	arraydimension = NO;	/* inside array dimension declaration */
+	bplisting = NO;		/* breakpoint listing */
+	braces = 0;		/* unmatched left brace count */
+	classdef = NO;		/* c++ class definition */
+	elseelif = NO;		/* #else or #elif found */
+	esudef = NO;		/* enum/struct/union global definition */
+	external = NO;		/* external definition */
+	externalbraces = -1;	/* external definition outer brace count */
+	fcndef = NO;		/* function definition */
+	global = YES;		/* file global scope (outside functions) */
+	iflevel = 0;		/* #if nesting level */
+	initializer = NO;	/* data initializer */
+	initializerbraces = -1;	/* data initializer outer brace count */
+	lex = NO;		/* lex file */
+	parens = 0;		/* unmatched left parenthesis count */
+	ppdefine = NO;		/* preprocessor define statement */
+	pseudoelif = NO;	/* pseudo-#elif */
+	oldtype = NO;		/* next identifier is an old type */
+	rules = NO;		/* lex/yacc rules */
+	sdl = NO;		/* sdl file */
+	structfield = NO;	/* structure field declaration */
+	tagdef = '\0';		/* class/enum/struct/union tag definition */
+	template = NO;		/* function template */
+	templateparens = -1;	/* function template outer parentheses count */
+	typedefbraces = -1;	/* initial typedef braces count */
+	ident_start = 0;	/* start of previously found identifier */
+
+	if (my_yytext)
+		*my_yytext = '\0';
+	my_yyleng = 0;
+	
+	BEGIN(INITIAL);
+
+	/* if this is not a C file */
+	if ((s = strrchr(srcfile, '.')) != NULL) {
+		switch (*++s) {	/* this switch saves time on C files */
+		case 'b':
+			if (strcmp(s, "bp") == 0) {	/* breakpoint listing */
+				bplisting = YES;
+			}
+			break;
+		case 'l':
+			if (strcmp(s, "l") == 0) {	/* lex */
+				lex = YES;
+				global = NO;
+			}
+			break;
+		case 's':
+			if (strcmp(s, "sd") == 0) {	/* sdl */
+				sdl = YES;
+				BEGIN(SDL);
+			}
+			break;
+		case 'y':
+			if (strcmp(s, "y") == 0) {	/* yacc */
+				global = NO;
+			}
+			break;
+		}
+	}
+}
+
+#define MY_YY_ALLOCSTEP 1000
+static void
+my_yymore(void)
+{
+	static size_t yytext_size = 0;
+	
+	/* my_yytext is an ever-growing buffer. It will not ever
+	 * shrink, nor will it be freed at end of program, for now */
+	while (my_yyleng + yyleng + 1 >= yytext_size) {
+		my_yytext = realloc(my_yytext, yytext_size += MY_YY_ALLOCSTEP);
+	}
+	
+	strncpy (my_yytext + my_yyleng, yytext, yyleng+1);
+	my_yyleng += yyleng;
+}
diff --git a/src/global.h b/src/global.h
new file mode 100644
index 0000000..d1ec944
--- /dev/null
+++ b/src/global.h
@@ -0,0 +1,321 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	global type, data, and function definitions
+ */
+
+#ifndef CSCOPE_GLOBAL_H
+#define CSCOPE_GLOBAL_H
+
+//#include "config.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <ctype.h>	/* isalpha, isdigit, etc. */
+#include <signal.h>	/* SIGINT and SIGQUIT */
+#include <stdio.h>	/* standard I/O package */
+#include <stdlib.h>     /* standard library functions */
+
+#include <string.h>	/* string functions */
+
+#include "constants.h"	/* misc. constants */
+#include "invlib.h"	/* inverted index library */
+#include "library.h"	/* library function return values */
+
+typedef void (*sighandler_t)(int);
+
+#include <stdarg.h>
+
+#include <fcntl.h>
+
+typedef	enum	{		/* boolean data type */
+	NO,
+	YES
+} BOOL;
+
+typedef	enum	{		/* findinit return code */
+	NOERROR,
+	NOTSYMBOL,
+	REGCMPERROR
+} FINDINIT;
+
+typedef	struct {		/* mouse action */
+	int	button;
+	int	percent;
+	int	x1;
+	int	y1;
+	int	x2;
+	int	y2;
+} MOUSE;
+
+struct cmd {			/* command history struct */
+	struct	cmd *prev, *next;	/* list ptrs */
+	int	field;			/* input field number */
+	char	*text;			/* input field text */
+};
+
+#ifndef R_OK
+# define	READ	R_OK
+#else
+# define	READ	4	
+#endif
+#ifdef W_OK
+# define	WRITE	W_OK
+#else
+# define	WRITE	2
+#endif
+
+#define O_TEXT 0x00
+#define O_BINARY 0x00
+
+#ifndef DFLT_INCDIR
+# define DFLT_INCDIR "/usr/include"
+#endif
+
+/* digraph data for text compression */
+extern	char	dichar1[];	/* 16 most frequent first chars */
+extern	char	dichar2[];	/* 8 most frequent second chars 
+				   using the above as first chars */
+extern	char	dicode1[];	/* digraph first character code */
+extern	char	dicode2[];	/* digraph second character code */
+
+/* and some macros to help using dicodes: */
+/* Check if a given pair of chars is compressable as a dicode: */
+#define IS_A_DICODE(inchar1, inchar2)					   \
+  (dicode1[(unsigned char)(inchar1)] && dicode2[(unsigned char)(inchar2)])
+/* Combine the pair into a dicode */
+#define DICODE_COMPRESS(inchar1, inchar2)		\
+  ((0200 - 2) + dicode1[(unsigned char)(inchar1)]	\
+   + dicode2[(unsigned char)(inchar2)])
+
+/* main.c global data */
+extern	char	*editor, *home, *shell, *lineflag;	/* environment variables */
+extern	char	*home;		/* Home directory */
+extern 	BOOL	lineflagafterfile;
+extern	char	*argv0;		/* command name */
+extern	BOOL	compress;	/* compress the characters in the crossref */
+extern	BOOL	dbtruncated;	/* database symbols truncated to 8 chars */
+extern	int	dispcomponents;	/* file path components to display */
+#if CCS
+extern	BOOL	displayversion;	/* display the C Compilation System version */
+#endif
+extern	BOOL	editallprompt;	/* prompt between editing files */
+extern	unsigned int fileargc;	/* file argument count */
+extern	char	**fileargv;	/* file argument values */
+extern	int	fileversion;	/* cross-reference file version */
+extern	BOOL	incurses;	/* in curses */
+extern	BOOL	invertedindex;	/* the database has an inverted index */
+extern	BOOL	isuptodate;	/* consider the crossref up-to-date */
+extern	BOOL	kernelmode;	/* don't use DFLT_INCDIR - bad for kernels */
+extern	BOOL	linemode;	/* use line oriented user interface */
+extern	BOOL	verbosemode;	/* print extra information on line mode */
+extern	BOOL	recurse_dir;	/* recurse dirs when searching for src files */
+extern	char	*namefile;	/* file of file names */
+extern	BOOL	ogs;		/* display OGS book and subsystem names */
+extern	char	*prependpath;	/* prepend path to file names */
+extern	FILE	*refsfound;	/* references found file */
+extern	char	temp1[];	/* temporary file name */
+extern	char	temp2[];	/* temporary file name */
+extern	long	totalterms;	/* total inverted index terms */
+extern	BOOL	trun_syms;	/* truncate symbols to 8 characters */
+extern	char	tempstring[TEMPSTRING_LEN + 1]; /* global dummy string buffer */
+extern	char	*tmpdir;	/* temporary directory */
+
+/* command.c global data */
+extern	BOOL	caseless;	/* ignore letter case when searching */
+extern	BOOL	*change;	/* change this line */
+extern	BOOL	changing;	/* changing text */
+extern	int	selecting;
+extern	unsigned int curdispline;
+extern	char	newpat[];	/* new pattern */
+extern	char	Pattern[];	/* symbol or text pattern */
+
+/* crossref.c global data */
+extern	long	dboffset;	/* new database offset */
+extern	BOOL	errorsfound;	/* prompt before clearing error messages */
+extern	long	lineoffset;	/* source line database offset */
+extern	long	npostings;	/* number of postings */
+extern	unsigned long symbols;	/* number of symbols */
+
+/* dir.c global data */
+extern	char	currentdir[];	/* current directory */
+extern	char	**incdirs;	/* #include directories */
+extern	char	**srcdirs;	/* source directories */
+extern	char	**srcfiles;	/* source files */
+extern	unsigned long nincdirs;	/* number of #include directories */
+extern	unsigned long nsrcdirs;	/* number of source directories */
+extern	unsigned long nsrcfiles; /* number of source files */
+extern	unsigned long msrcfiles; /* maximum number of source files */
+
+/* display.c global data */
+extern 	int	booklen;	/* OGS book name display field length */
+extern	int	*displine;	/* screen line of displayed reference */
+extern	unsigned int disprefs;	/* displayed references */
+extern	int	fcnlen;		/* function name display field length */
+extern	int	field;		/* input field */
+extern	int	filelen;	/* file name display field length */
+extern	unsigned fldcolumn;	/* input field column */
+extern	unsigned int mdisprefs;	/* maximum displayed references */
+extern	unsigned int nextline;	/* next line to be shown */
+extern	FILE	*nonglobalrefs;	/* non-global references file */
+extern	int	numlen;		/* line number display field length */
+extern	unsigned int topline;	/* top line of page */
+extern	int	bottomline;	/* bottom line of page */
+extern	long	searchcount;	/* count of files searched */
+extern	int	subsystemlen;	/* OGS subsystem name display field length */
+extern	unsigned int totallines; /* total reference lines */
+extern	const char dispchars[];	/* display chars for jumping to lines */
+
+/* find.c global data */
+extern	char	block[];	/* cross-reference file block */
+extern	char	blockmark;	/* mark character to be searched for */
+extern	long	blocknumber;	/* block number */
+extern	char	*blockp;	/* pointer to current character in block */
+extern	int	blocklen;	/* length of disk block read */
+
+/* lookup.c global data */
+extern	struct	keystruct {
+	char	*text;
+	char	delim;
+	struct	keystruct *next;
+} keyword[];
+
+/* mouse.c global data */
+extern	BOOL	mouse;		/* mouse interface */
+
+#if UNIXPC
+extern	BOOL	unixpcmouse;		/* UNIX PC mouse interface */
+#endif
+
+/* cscope functions called from more than one function or between files */ 
+
+char	*filepath(char *file);
+char	*findcalledby(char *pattern);
+char	*findcalling(char *pattern);
+char	*findallfcns(char *dummy);
+char	*finddef(char *pattern);
+char	*findfile(char *dummy);
+char	*findinclude(char *pattern);
+char	*findsymbol(char *pattern);
+char	*findassign(char *pattern);
+char	*findregexp(char *egreppat);
+char	*findstring(char *pattern);
+char	*inviewpath(char *file);
+char	*lookup(char *ident);
+char	*pathcomponents(char *path, int components);
+char	*read_block(void);
+char	*scanpast(char c);
+
+char ** parse_options(int *argc, char **argv);
+void    error_usage(void);
+void	longusage(void);
+void	usage(void);
+extern BOOL	remove_symfile_onexit;
+extern BOOL	onesearch;		/* one search only in line mode */
+extern char	*reflines;		/* symbol reference lines file */
+
+void	addcmd(int f, char *s);
+void	addsrcfile(char *path);
+void	askforchar(void);
+void	askforreturn(void);
+void	atchange(void);
+void	atfield(void);
+void	cannotwrite(char *file);
+void	cannotopen(char *file);
+void	clearmsg(void);
+void	clearmsg2(void);
+void	countrefs(void);
+void	crossref(char *srcfile);
+void    dispinit(void);
+void	display(void);
+void	drawscrollbar(int top, int bot);
+void	edit(char *file, char *linenum);
+void	editall(void);
+void	editref(int);
+void	entercurses(void);
+void	exitcurses(void);
+void	findcleanup(void);
+void    freesrclist(void);
+void    freeinclist(void);
+void    freecrossref(void);
+void	freefilelist(void);
+void	help(void);
+void	incfile(char *file, char *type);
+void    includedir(char *_dirname);
+void    initsymtab(void);
+void	makefilelist(void);
+void	mousecleanup(void);
+void	mousemenu(void);
+void	mouseinit(void);
+void	mousereinit(void);
+void	myexit(int sig);
+void	myperror(char *text);
+void	ogsnames(char *file, char **subsystem, char **book);
+void	progress(char *what, long current, long max);
+void	putfilename(char *srcfile);
+void	postmsg(char *msg);
+void	postmsg2(char *msg);
+void	posterr(char *msg,...);
+void	postfatal(const char *msg,...);
+void	putposting(char *term, int type);
+void	fetch_string_from_dbase(char *, size_t);
+void	resetcmd(void);
+void	seekline(unsigned int line);
+void	setfield(void);
+void	shellpath(char *out, int limit, char *in);
+void    sourcedir(char *dirlist);
+void	myungetch(int c);
+void	warning(char *text);
+void	writestring(char *s);
+
+BOOL	command(int commandc);
+BOOL	infilelist(char *file);
+BOOL	readrefs(char *filename);
+BOOL	search(void);
+BOOL	writerefsfound(void);
+
+FINDINIT findinit(char *pattern);
+MOUSE	*getmouseaction(char leading_char);
+struct	cmd *currentcmd(void);
+struct	cmd *prevcmd(void);
+struct	cmd *nextcmd(void);
+
+int	egrep(char *file, FILE *output, char *format);
+int	mygetline(char p[], char s[], unsigned size, int firstchar, BOOL iscaseless);
+int	mygetch(void);
+int	hash(char *ss);
+int	execute(char *a, ...);
+long	dbseek(long offset);
+
+
+#endif /* CSCOPE_GLOBAL_H */
diff --git a/src/gscope.c b/src/gscope.c
new file mode 100644
index 0000000..f26f1b1
--- /dev/null
+++ b/src/gscope.c
@@ -0,0 +1 @@
+/* Placeholder file --- replace by real gscope.c if you have it */
\ No newline at end of file
diff --git a/src/help.c b/src/help.c
new file mode 100644
index 0000000..3c61942
--- /dev/null
+++ b/src/help.c
@@ -0,0 +1,209 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	display help
+ *
+ */
+
+#include "global.h"
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+/*
+	max num of lines of help screen -
+	this number needs to be increased if more than n help items are needed
+*/
+#define MAXHELP	50	/* maximum number of help strings */
+
+void
+help(void)
+{
+	char	**ep, *s, **tp, *text[MAXHELP];	
+	int	ln;
+
+	tp = text;
+	if (changing == NO) {
+		if (mouse) {
+			*tp++ = "Point with the mouse and click button 1 to move to the desired input field,\n";
+			*tp++ = "type the pattern to search for, and then press the RETURN key.  For the first 4\n";
+			*tp++ = "and last 2 input fields, the pattern can be a regcomp(3) regular expression.\n";
+			*tp++ = "If the search is successful, you can edit the file containing a displayed line\n";
+			*tp++ = "by pointing with the mouse and clicking button 1.\n";
+			*tp++ = "\nYou can either use the button 2 menu or these single-character commands:\n\n";
+		} else {
+			*tp++ = "Press the RETURN key repeatedly to move to the desired input field, type the\n";
+			*tp++ = "pattern to search for, and then press the RETURN key.  For the first 4 and\n";
+			*tp++ = "last 2 input fields, the pattern can be a regcomp(3) regular expression.\n";
+			*tp++ = "If the search is successful, you can use these single-character commands:\n\n";
+			*tp++ = "0-9a-zA-Z\tEdit the file containing the displayed line.\n";
+		}
+		*tp++ = "space bar\tDisplay next set of matching lines.\n";
+		*tp++ = "+\t\tDisplay next set of matching lines.\n";
+		*tp++ = "^V\t\tDisplay next set of matching lines.\n";
+		*tp++ = "-\t\tDisplay previous set of matching lines.\n";
+		*tp++ = "^E\t\tEdit all lines.\n";
+		*tp++ = ">\t\tWrite the list of lines being displayed to a file.\n";
+		*tp++ = ">>\t\tAppend the list of lines being displayed to a file.\n";
+		*tp++ = "<\t\tRead lines from a file.\n";
+		*tp++ = "^\t\tFilter all lines through a shell command.\n";
+		*tp++ = "|\t\tPipe all lines to a shell command.\n";
+		if (!mouse) {
+			*tp++ = "\nAt any time you can use these single-character commands:\n\n";
+			*tp++ = "TAB\t\tSwap positions between input and output areas.\n";
+			*tp++ = "RETURN\t\tMove to the next input field.\n";
+			*tp++ = "^N\t\tMove to the next input field.\n";
+			*tp++ = "^P\t\tMove to the previous input field.\n";
+		}
+		*tp++ = "^Y / ^A\t\tSearch with the last pattern typed.\n";
+		*tp++ = "^B\t\tRecall previous input field and search pattern.\n";
+		*tp++ = "^F\t\tRecall next input field and search pattern.\n";
+		if(caseless)
+			*tp++ = "^C\t\tToggle ignore/use letter case when searching (IGNORE).\n";
+		else
+			*tp++ = "^C\t\tToggle ignore/use letter case when searching (USE).\n";
+		*tp++ = "^R\t\tRebuild the cross-reference.\n";
+		*tp++ = "!\t\tStart an interactive shell (type ^D to return to cscope).\n";
+		*tp++ = "^L\t\tRedraw the screen.\n";
+		*tp++ = "?\t\tDisplay this list of commands.\n";
+		*tp++ = "^D\t\tExit cscope.\n";
+		*tp++ = "\nNote: If the first character of the pattern you want to search for matches\n";
+		*tp++ = "a command, type a \\ character first.\n";
+		*tp++ = "Note: Some ctrl keys may be occupied by your terminal configuration.\n";
+	} else {
+		if (mouse) {
+			*tp++ = "Point with the mouse and click button 1 to mark or unmark the line to be\n";
+			*tp++ = "changed.  You can also use the button 2 menu or these single-character\n";
+			*tp++ = "commands:\n\n";
+		}
+		else {
+			*tp++ = "When changing text, you can use these single-character commands:\n\n";
+			*tp++ = "0-9a-zA-Z\tMark or unmark the line to be changed.\n";
+		}
+		*tp++ = "*\t\tMark or unmark all displayed lines to be changed.\n";
+		*tp++ = "space bar\tDisplay next set of lines.\n";
+		*tp++ = "+\t\tDisplay next set of lines.\n";
+		*tp++ = "-\t\tDisplay previous set of lines.\n";
+		*tp++ = "^A\t\tMark or unmark all lines to be changed.\n";
+		*tp++ = "^D\t\tChange the marked lines and exit.\n";
+		*tp++ = "ESC\t\tExit without changing the marked lines.\n";
+		*tp++ = "!\t\tStart an interactive shell (type ^D to return to cscope).\n";
+		*tp++ = "^L\t\tRedraw the screen.\n";
+		*tp++ = "?\t\tDisplay this list of commands.\n";
+	}
+	/* print help, a screen at a time */
+	ep = tp;
+	ln = 0;
+	for (tp = text; tp < ep; ) {
+		if (ln < LINES - 1) {
+			for (s = *tp; *s != '\0'; ++s) {
+				if (*s == '\n') {
+					++ln;
+				}
+			}
+			(void) addstr(*tp++);
+		}
+		else {
+			(void) addstr("\n");
+			askforchar();
+			(void) clear();
+			ln = 0;
+		}
+	}
+	if (ln) {
+		(void) addstr("\n");
+		askforchar();
+	}
+}
+
+/* error exit including short usage information */
+void
+error_usage(void)
+{
+	usage();
+	fprintf(stderr, "Try the -h option for more information.\n");
+	myexit(1);
+}
+
+/* normal usage message */
+void
+usage(void)
+{
+	fprintf(stderr, "Usage: cscope [-bcCdehklLqRTuUvV] [-f file] [-F file] [-i file] [-I dir] [-s dir]\n");
+	fprintf(stderr, "              [-p number] [-P path] [-[0-8] pattern] [source files]\n");
+}
+
+
+/* long usage message */
+void
+longusage(void)
+{
+	usage();
+	fprintf(stderr, "\
+\n\
+-b            Build the cross-reference only.\n\
+-C            Ignore letter case when searching.\n\
+-c            Use only ASCII characters in the cross-ref file (don't compress).\n\
+-d            Do not update the cross-reference.\n\
+-e            Suppress the <Ctrl>-e command prompt between files.\n\
+-F symfile    Read symbol reference lines from symfile.\n\
+-f reffile    Use reffile as cross-ref file name instead of %s.\n",
+		REFFILE);
+	fprintf(stderr, "\
+-h            This help screen.\n\
+-I incdir     Look in incdir for any #include files.\n\
+-i namefile   Browse through files listed in namefile, instead of %s\n",
+		NAMEFILE);
+	fprintf(stderr, "\
+-k            Kernel Mode - don't use %s for #include files.\n",
+		DFLT_INCDIR);
+	fputs("\
+-L            Do a single search with line-oriented output.\n\
+-l            Line-oriented interface.\n\
+-num pattern  Go to input field num (counting from 0) and find pattern.\n\
+-P path       Prepend path to relative file names in pre-built cross-ref file.\n\
+-p n          Display the last n file path components.\n\
+-q            Build an inverted index for quick symbol searching.\n\
+-R            Recurse directories for files.\n\
+-s dir        Look in dir for additional source  files.\n\
+-T            Use only the first eight characters to match against C symbols.\n\
+-U            Check file time stamps.\n\
+-u            Unconditionally build the cross-reference file.\n\
+-v            Be more verbose in line mode.\n\
+-V            Print the version number.\n\
+\n\
+Please see the manpage for more information.\n",
+	      stderr);
+}
diff --git a/src/history.c b/src/history.c
new file mode 100644
index 0000000..6efca0e
--- /dev/null
+++ b/src/history.c
@@ -0,0 +1,103 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol or text cross-reference
+ *
+ *	command history
+ */
+
+#include "global.h"
+
+
+
+static	struct cmd *tail, *current;
+
+/* add a cmd to the history list */
+void
+addcmd(int f, char *s)		/* field number and command text */
+{
+	struct cmd *h;
+
+	h = malloc(sizeof(struct cmd));
+	if( tail) {
+		tail->next = h;
+		h->next = 0;
+		h->prev = tail;
+		tail = h;
+	} else {
+		tail = h;
+		h->next = h->prev = 0;
+	}
+	h->field = f;
+	h->text = strdup( s);
+	current = 0;
+}
+
+/* return previous history item */
+struct cmd *
+prevcmd(void)
+{
+	if( current) {
+		if( current->prev)	/* stay on first item */
+			return current = current->prev;
+		else
+			return current;
+	} else if( tail)
+		return current = tail;
+	else 
+		return NULL;
+}
+
+/* return next history item */
+struct cmd *
+nextcmd(void)
+{
+	if( current) {
+		if( current->next)	/* stay on first item */
+			return current = current->next;
+		else
+			return current;
+	} else 
+		return NULL;
+}
+/* reset current to tail */
+void
+resetcmd(void)
+{
+	current = 0;
+}
+
+struct cmd *
+currentcmd(void)
+{
+	return current;
+}
diff --git a/src/input.c b/src/input.c
new file mode 100644
index 0000000..a8d6dea
--- /dev/null
+++ b/src/input.c
@@ -0,0 +1,333 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	terminal input functions
+ */
+
+#include "global.h"
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+#include <setjmp.h>	/* jmp_buf */
+#include <stdlib.h>
+#include <errno.h>
+#if HAVE_SYS_TERMIOS_H
+#include <sys/termios.h>
+#endif
+
+static	jmp_buf	env;		/* setjmp/longjmp buffer */
+static	int	prevchar;	/* previous, ungotten character */
+
+/* Internal prototypes: */
+static void catchint(int sig);
+
+/* catch the interrupt signal */
+
+/*ARGSUSED*/
+static void
+catchint(int sig)
+{
+ 	(void) sig;		/* 'use' it, to avoid a warning */
+
+	signal(SIGINT, catchint);
+	longjmp(env, 1);
+}
+
+/* unget a character */
+void
+myungetch(int c)
+{
+	prevchar = c;
+}
+
+/* get a character from the terminal */
+int
+mygetch(void)
+{
+    sighandler_t savesig = 0; /* old value of signal */
+    int c;
+
+    /* change an interrupt signal to a break key character */
+    if (setjmp(env) == 0) {
+	savesig = signal(SIGINT, catchint);
+	refresh();	/* update the display */
+	mousereinit();	/* curses can change the menu number */
+	if(prevchar) {
+	    c = prevchar;
+	    prevchar = 0;
+	} else {
+	    c = -1;
+	    while (c == -1) {
+		/* get a character from the terminal */
+		c = getch();
+		if ((c == -1) && (errno != EINTR))
+		    break;
+	    }
+	}
+    } else {	/* longjmp to here from signal handler */
+	c = KEY_BREAK;
+    }
+    signal(SIGINT, savesig);
+    return(c);
+}
+
+
+/* get a line from the terminal in non-canonical mode */
+int
+mygetline(char p[], char s[], unsigned size, int firstchar, BOOL iscaseless)
+{
+    int	c;
+    unsigned int i = 0, j;
+    char *sright;	/* substring to the right of the cursor */
+    unsigned int ri = 0;		/* position in right-string */
+
+    /* Inserts and deletes are always performed on the left-string,
+     * but we'll also have a right-string 'sright' to hold characters
+     * which are on the right of the cursor [insertion point].
+     *
+     * Think of 'sright' as a stack -- we push chars into it when the cursor
+     * moves left, and we pop chars off it when the cursor moves right again.
+     * At the end of the function, we'll pop off any remaining characters
+     * onto the end of 's'
+     */
+    sright = calloc(size, sizeof(*sright));
+
+    strcpy ( s, p);
+    i += strlen(p);
+    /* if a character already has been typed */
+    if (firstchar != '\0') {
+	if(iscaseless == YES) {
+	    firstchar = tolower(firstchar);
+	}
+	addch(firstchar);	/* display it */
+	s[i++] = firstchar;	/* save it */
+    }
+    /* until the end of the line is reached */
+    while ((c = mygetch()) != '\r' && c != '\n' && c != KEY_ENTER) {
+	if (c == KEY_LEFT || c == ctrl('B')) {	/* left */
+	    if (i > 0) {
+		addch('\b');
+		/* move this char into the second (rhs) string */
+		sright[ri++] = s[--i];
+	    }
+	} else if (c == KEY_RIGHT || c == ctrl('F')) {	/* right */
+	    if (i < size && ri > 0) {
+		/* move this char to the left of the cursor */
+		s[i++] = sright[--ri];
+		addch(s[i-1]);
+	    }
+	} else if (
+#ifdef KEY_HOME
+		   c == KEY_HOME ||
+#endif
+		   c == ctrl('A') ) {
+	    while (i > 0) {
+		sright[ri++] = s[--i];
+		addch('\b');
+		addch(s[i]);
+		addch('\b');
+	    }
+	} else if (
+#ifdef KEY_END
+		   c == KEY_END ||
+#endif
+		   c == ctrl('E') ) {
+	    while (ri > 0) {
+		s[i++] = sright[--ri];
+		addch(s[i-1]);
+	    }
+	} else if (c == erasechar() || c == KEY_BACKSPACE
+		   || c == DEL || c == ctrl('H') ) {
+	    /* erase */
+	    if (i > 0) {
+		if (ri == 0)  {
+		    addstr("\b \b");
+		} else {
+		    addch('\b');
+		    delch();
+		}
+		s[i] = '\0';
+		--i;
+	    }
+	} else if (c == killchar() || c == KEY_BREAK) {
+	    /* kill */
+	    for (j = 0; j < i; ++j) {
+		addch('\b');
+	    }
+	    for (j = 0; j < i; ++j) {
+		addch(' ');
+	    }
+	    for (j = 0; j < i; ++j) {
+		addch('\b');
+	    }
+	    i = 0;
+	} else if (isprint(c) || c == '\t') {
+	    /* printable */
+	    if(iscaseless == YES) {
+		c = tolower(c);
+	    }
+	    /* if it will fit on the line */
+	    if (i < size) {
+		s[i++] = c;	/* save it */
+		if (ri == 0) {
+		    addch(c);	/* display it */
+		} else {
+		    insch(c);	/* display it */
+		    addch(c);	/* advance cursor */
+		}
+	    }
+#if UNIXPC
+	} else if (unixpcmouse == YES && c == ESC) {	/* mouse */
+	    getmouseaction(ESC);	/* ignore it */
+#endif
+	} else if (mouse == YES && c == ctrl('X')) {
+	    getmouseaction(ctrl('X'));	/* ignore it */
+	} else if (c == EOF) {				/* end-of-file */
+	    break;
+	}
+
+	/* return on an empty line to allow a command to be entered */
+	if (firstchar != '\0' && (i+ri) == 0) {
+	    break;
+	}
+    }
+
+    /* move any remaining chars on the rhs of the cursor
+     * onto the end of our string
+     */
+    while (ri > 0) {
+	s[i++] = sright[--ri];
+    }
+    free(sright);
+
+    s[i] = '\0';
+    return(i);
+}
+
+/* ask user to enter a character after reading the message */
+
+void
+askforchar(void)
+{
+    addstr("Type any character to continue: ");
+    mygetch();
+}
+
+/* ask user to press the RETURN key after reading the message */
+
+void
+askforreturn(void)
+{
+    fprintf(stderr, "Press the RETURN key to continue: ");
+    getchar();
+    /* HBB 20060419: message probably messed up the screen --- redraw */
+    if (incurses == YES) {
+	redrawwin(curscr);
+    }
+}
+
+/* expand the ~ and $ shell meta characters in a path */
+
+void
+shellpath(char *out, int limit, char *in) 
+{
+    char	*lastchar;
+    char	*s, *v;
+
+    /* skip leading white space */
+    while (isspace((unsigned char)*in)) {
+	++in;
+    }
+    lastchar = out + limit - 1;
+
+    /* a tilde (~) by itself represents $HOME; followed by a name it
+       represents the $LOGDIR of that login name */
+    if (*in == '~') {
+	*out++ = *in++;	/* copy the ~ because it may not be expanded */
+
+	/* get the login name */
+	s = out;
+	while (s < lastchar && *in != '/' && *in != '\0' && !isspace((unsigned char)*in)) {
+	    *s++ = *in++;
+	}
+	*s = '\0';
+
+	/* if the login name is null, then use $HOME */
+	if (*out == '\0') {
+	    v = getenv("HOME");
+	} else {	/* get the home directory of the login name */
+	    v = logdir(out);
+	}
+	/* copy the directory name if it isn't too big */
+	if (v != NULL && strlen(v) < (lastchar - out)) {
+	    strcpy(out - 1, v);
+	    out += strlen(v) - 1;
+	} else {
+	    /* login not found, so ~ must be part of the file name */
+	    out += strlen(out);
+	}
+    }
+    /* get the rest of the path */
+    while (out < lastchar && *in != '\0' && !isspace((unsigned char)*in)) {
+
+	/* look for an environment variable */
+	if (*in == '$') {
+	    *out++ = *in++;	/* copy the $ because it may not be expanded */
+
+	    /* get the variable name */
+	    s = out;
+	    while (s < lastchar && *in != '/' && *in != '\0' &&
+		   !isspace((unsigned char)*in)) {
+		*s++ = *in++;
+	    }
+	    *s = '\0';
+	
+	    /* get its value, but only it isn't too big */
+	    if ((v = getenv(out)) != NULL && strlen(v) < (lastchar - out)) {
+		strcpy(out - 1, v);
+		out += strlen(v) - 1;
+	    } else {
+		/* var not found, or too big, so assume $ must be part of the
+		 * file name */
+		out += strlen(out);
+	    }
+	}
+	else {	/* ordinary character */
+	    *out++ = *in++;
+	}
+    }
+    *out = '\0';
+}
diff --git a/src/invlib.c b/src/invlib.c
new file mode 100644
index 0000000..cd15c35
--- /dev/null
+++ b/src/invlib.c
@@ -0,0 +1,1204 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if SHARE
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#define ERR  -1
+#endif
+#include "invlib.h"
+#include "global.h"
+
+#include <assert.h>
+
+#define	DEBUG		0	/* debugging code and realloc messages */
+#define BLOCKSIZE	2 * BUFSIZ	/* logical block size */
+#define	POSTINC		10000	/* posting buffer size increment */
+#define SEP		' '	/* sorted posting field separator */
+#define	SETINC		100	/* posting set size increment */
+#define	STATS		0	/* print statistics */
+#define	SUPERINC	10000	/* super index size increment */
+#define	TERMMAX		512	/* term max size */
+#define	FMTVERSION	1	/* inverted index format version */
+#define	ZIPFSIZE	200	/* zipf curve size */
+
+#if DEBUG
+/* FIXME HBB 20010705: nowhere in the source is `invbreak' ever set to
+ * a value other than the (silent) initialization to zero. Pretty
+ * useless, that looks */
+int	invbreak;
+#endif
+
+static	int	boolready(void);
+static	int	invnewterm(void);
+static	void	invstep(INVCONTROL *invcntl);
+static	void	invcannotalloc(unsigned n);
+static	void	invcannotopen(char *file);
+static	void	invcannotwrite(char *file);
+
+#if STATS
+int	showzipf;	/* show postings per term distribution */
+#endif
+
+static	POSTING	*item, *enditem, *item1 = NULL, *item2 = NULL;
+static	unsigned int setsize1, setsize2;
+static	long	numitems, totterm, zerolong;
+static	char	*indexfile, *postingfile;
+static	FILE	*outfile, *fpost;
+static	size_t supersize = SUPERINC, supintsize;
+static  unsigned int numpost, numlogblk, amtused, nextpost;
+static  unsigned int lastinblk, numinvitems;
+static	POSTING	*POST, *postptr;
+static	unsigned long	*SUPINT, *supint, nextsupfing;
+static	char	*SUPFING, *supfing;
+static	char	thisterm[TERMMAX];
+typedef union logicalblk {
+	long	invblk[BLOCKSIZE / sizeof(long)];
+	char	chrblk[BLOCKSIZE];
+} t_logicalblk;
+static t_logicalblk logicalblk;
+
+#if DEBUG || STATS
+static	long	totpost;
+#endif
+
+#if STATS
+static	int	zipf[ZIPFSIZE + 1];
+#endif
+
+long
+invmake(char *invname, char *invpost, FILE *infile)
+{
+	unsigned char	*s;
+	long	num;
+	int	i;
+	long	fileindex = 0;	/* initialze, to avoid warning */
+	unsigned postsize = POSTINC * sizeof(*POST);
+	unsigned long	*intptr;
+	char	line[TERMMAX];
+	long	tlong;
+	PARAM	param;
+	POSTING	posting;
+	char 	temp[BLOCKSIZE];
+#if STATS
+	int	j;
+	unsigned maxtermlen = 0;
+#endif
+	/* output file */
+	if ((outfile = vpfopen(invname, "w+b")) == NULL) {
+		invcannotopen(invname);
+		return(0);
+	}
+	indexfile = invname;
+	fseek(outfile, BUFSIZ, SEEK_SET);
+
+	/* posting file  */
+	if ((fpost = vpfopen(invpost, "wb")) == NULL) {
+		invcannotopen(invpost);
+		return(0);
+	}
+	postingfile = invpost;
+	nextpost = 0;
+	/* get space for the postings list */
+	if ((POST = malloc(postsize)) == NULL) {
+		invcannotalloc(postsize);
+		return(0);
+	}
+	postptr = POST;
+	/* get space for the superfinger (superindex) */
+	if ((SUPFING = malloc(supersize)) == NULL) {
+		invcannotalloc(supersize);
+		return(0);
+	}
+	supfing = SUPFING;
+	/* FIXME HBB: magic number alert (40) */
+	supintsize = supersize / 40u;
+	/* also for the superfinger index */
+	if ((SUPINT = malloc(supintsize * sizeof(*SUPINT))) == NULL) {
+		invcannotalloc(supintsize * sizeof(*SUPINT));
+		return(0);
+	}
+	supint = SUPINT;
+	supint++; /* leave first term open for a count */
+	/* initialize using an empty term */
+	strcpy(thisterm, "");
+	*supint++ = 0;
+	*supfing++ = ' ';
+	*supfing++ = '\0';
+	nextsupfing = 2;
+#if DEBUG || STATS
+	totpost = 0L;
+#endif
+	totterm = 0L;
+	numpost = 1;
+
+	/* set up as though a block had come and gone, i.e., set up for new block  */
+	/* 3 longs needed for: numinvitems, next block, and previous block */
+	amtused = 3 * sizeof(long);
+	numinvitems = 0;
+	numlogblk = 0;
+	lastinblk = sizeof(t_logicalblk);
+
+	/* now loop as long as more to read (till eof)  */
+	while (fgets(line, TERMMAX, infile) != NULL) {
+#if DEBUG || STATS
+		++totpost;
+#endif
+		s = strchr(line, SEP);
+		if (s != NULL) {
+			*s = '\0';
+		}
+		else {
+			continue;
+		}
+#if STATS
+		if ((i = strlen(line)) > maxtermlen) {
+			maxtermlen = i;
+		}
+#endif
+#if DEBUG
+		printf("%ld: %s ", totpost, line);
+		fflush(stdout);
+#endif
+		if (strcmp(thisterm, line) == 0) {
+			if ((postptr + 10) > (POST + (postsize / sizeof(*POST)))) {
+				i = postptr - POST;
+				postsize += POSTINC * sizeof(*POST);
+				if ((POST = realloc(POST, postsize)) == NULL) {
+					invcannotalloc(postsize);
+					return(0);
+				}
+				postptr = i + POST;
+#if DEBUG
+				printf("reallocated post space to %u, totpost=%ld\n",
+				       postsize, totpost);
+#endif
+			}
+			numpost++;
+		} else {
+			/* have a new term */
+			if (!invnewterm()) {
+				return(0);
+			}
+			strcpy(thisterm, line);
+			numpost = 1;
+			postptr = POST;
+			fileindex = 0;
+		}
+		/* get the new posting */
+		num = *++s - '!';
+		i = 1;
+		do {
+			num = BASE * num + *++s - '!';
+		} while (++i < PRECISION);
+		posting.lineoffset = num;
+		while (++fileindex < nsrcfiles && num > srcoffset[fileindex]) {
+			;
+		}
+		posting.fileindex = --fileindex;
+		posting.type = *++s;
+		++s;
+		if (*s != '\n') {
+			num = *++s - '!';
+			while (*++s != '\n') {
+				num = BASE * num + *s - '!';
+			}
+			posting.fcnoffset = num;
+		}
+		else {
+			posting.fcnoffset = 0;
+		}
+		*postptr++ = posting;
+#if DEBUG
+		printf("%ld %ld %ld %ld\n", posting.fileindex,
+		       posting.fcnoffset, posting.lineoffset, posting.type);
+		fflush(stdout);
+#endif
+	}
+	if (!invnewterm()) {
+		return(0);
+	}
+	/* now clean up final block  */
+	logicalblk.invblk[0] = numinvitems;
+	/* loops pointer around to start */
+	logicalblk.invblk[1] = 0;
+	logicalblk.invblk[2] = numlogblk - 1;
+	if (fwrite(&logicalblk, sizeof(t_logicalblk), 1, outfile) == 0) {
+		goto cannotwrite;
+	}
+	numlogblk++;
+	/* write out block to save space. what in it doesn't matter */
+	if (fwrite(&logicalblk, sizeof(t_logicalblk), 1, outfile) == 0) {
+		goto cannotwrite;
+	}
+	/* finish up the super finger */
+	*SUPINT = numlogblk;
+	/* add to the offsets the size of the offset pointers */
+	intptr = (SUPINT + 1);
+	i = (char *)supint - (char *)SUPINT;
+	while (intptr < supint)
+		*intptr++ += i;
+	/* write out the offsets (1 for the N at start) and the super finger */
+	if (fwrite(SUPINT, sizeof(*SUPINT), numlogblk + 1, outfile) == 0 ||
+	    fwrite(SUPFING, 1, supfing - SUPFING, outfile) == 0) {
+		goto cannotwrite;
+	}
+	/* save the size for reference later */
+	nextsupfing = sizeof(long) + sizeof(long) * numlogblk + (supfing - SUPFING);
+	/* make sure the file ends at a logical block boundary.  This is 
+	necessary for invinsert to correctly create extended blocks 
+	 */
+	i = nextsupfing % sizeof(t_logicalblk);
+	/* write out junk to fill log blk */
+	if (fwrite(temp, sizeof(t_logicalblk) - i, 1, outfile) == 0 ||
+	    fflush(outfile) == EOF) {	/* rewind doesn't check for write failure */
+		goto cannotwrite;
+	}
+	/* write the control area */
+	rewind(outfile);
+	param.version = FMTVERSION;
+	param.filestat = 0;
+	param.sizeblk = sizeof(t_logicalblk);
+	param.startbyte = (numlogblk + 1) * sizeof(t_logicalblk) + BUFSIZ;;
+	param.supsize = nextsupfing;
+	param.cntlsize = BUFSIZ;
+	param.share = 0;
+	if (fwrite(&param, sizeof(param), 1, outfile) == 0) {
+		goto cannotwrite;
+	}
+	for (i = 0; i < 10; i++)	/* for future use */
+		if (fwrite(&zerolong, sizeof(zerolong), 1, outfile) == 0) {
+			goto cannotwrite;
+		}
+
+	/* make first block loop backwards to last block */
+	if (fflush(outfile) == EOF) {	/* fseek doesn't check for write failure */
+		goto cannotwrite;
+	}
+	/* get to second word first block */
+	fseek(outfile, BUFSIZ + 2 * sizeof(long), SEEK_SET);
+	tlong = numlogblk - 1;
+	if (fwrite(&tlong, sizeof(tlong), 1, outfile) == 0 ||
+	    fclose(outfile) == EOF) {
+	cannotwrite:
+		invcannotwrite(invname);
+		return(0);
+	}
+	if (fclose(fpost) == EOF) {
+		invcannotwrite(postingfile);
+		return(0);
+	}
+	--totterm;	/* don't count null term */
+#if STATS
+	printf("logical blocks = %d, postings = %ld, terms = %ld, max term length = %d\n",
+	    numlogblk, totpost, totterm, maxtermlen);
+	if (showzipf) {
+		printf("\n*************   ZIPF curve  ****************\n");
+		for (j = ZIPFSIZE; j > 1; j--)
+			if (zipf[j]) 
+				break;
+		for (i = 1; i < j; ++i) {
+			printf("%3d -%6d ", i, zipf[i]);
+			if (i % 6 == 0) putchar('\n');
+		}
+		printf(">%d-%6d\n", ZIPFSIZE, zipf[0]);
+	}
+#endif
+	/* free all malloc'd memory */
+	free(POST);
+	free(SUPFING);
+	free(SUPINT);
+	return(totterm);
+}
+
+/* add a term to the data base */
+
+static int
+invnewterm(void)
+{
+    int	backupflag, i, j, holditems, gooditems, howfar;
+    unsigned int maxback, len, numwilluse, wdlen;
+    char	*tptr, *tptr3;
+
+    union {
+	unsigned long	packword[2];
+	ENTRY		e;
+    } iteminfo;
+
+    gooditems = 0;		/* initialize, to avoid warning */
+    totterm++;
+#if STATS
+    /* keep zipfian info on the distribution */
+    if (numpost <= ZIPFSIZE)
+	zipf[numpost]++;
+    else
+	zipf[0]++;
+#endif
+    len = strlen(thisterm);
+    /* length of term rounded up to long boundary */
+    wdlen = (len + (sizeof(long) - 1)) / sizeof(long);
+    /* each term needs 2 longs for its iteminfo and
+     * 1 long for its offset */
+    numwilluse = (wdlen + 3) * sizeof(long);
+    /* new block if at least 1 item in block */
+    if (numinvitems && numwilluse + amtused > sizeof(t_logicalblk)) {
+	/* set up new block */
+	if (supfing + 500u > SUPFING + supersize) {
+	    i = supfing - SUPFING;
+	    supersize += 20000u;
+	    if ((SUPFING = realloc(SUPFING, supersize)) == NULL) {
+		invcannotalloc(supersize);
+		return(0);
+	    }
+	    supfing = i + SUPFING;
+#if DEBUG
+	    printf("reallocated superfinger space to %d, totpost=%ld\n", 
+		   supersize, totpost);
+#endif
+	}
+	/* check that room for the offset as well */
+	/* FIXME HBB: magic number alert (10) */
+	if ((numlogblk + 10) > supintsize) {
+	    i = supint - SUPINT;
+	    supintsize += SUPERINC;
+	    if ((SUPINT = realloc(SUPINT, supintsize * sizeof(*SUPINT))) == NULL) {
+		invcannotalloc(supintsize * sizeof(*SUPINT));
+		return(0);
+	    }
+	    supint = i + SUPINT;
+#if DEBUG
+	    printf("reallocated superfinger offset to %d, totpost = %ld\n", supintsize * sizeof(*SUPINT), totpost);
+#endif
+	}
+	/* See if backup is efficatious  */
+	backupflag = 0;
+	maxback = (int) strlen(thisterm) / 10;
+	holditems = numinvitems;
+	if (maxback > numinvitems)
+	    maxback = numinvitems - 2;
+	howfar = 0;
+	while (maxback-- > 1) {
+	    howfar++;
+	    iteminfo.packword[0] =
+		logicalblk.invblk[--holditems * 2 + (sizeof(long) - 1)];
+	    if ((i = iteminfo.e.size / 10) < maxback) {
+		maxback = i;
+		backupflag = howfar;
+		gooditems = holditems;
+	    }
+	}
+	/* see if backup will occur  */
+	if (backupflag) {
+	    numinvitems = gooditems;
+	}
+	logicalblk.invblk[0] = numinvitems;
+	/* set forward pointer pointing to next */
+	logicalblk.invblk[1] = numlogblk + 1; 
+	/* set back pointer to last block */
+	logicalblk.invblk[2] = numlogblk - 1;
+	if (fwrite(logicalblk.chrblk, 1, sizeof(t_logicalblk), outfile) == 0) {
+	    invcannotwrite(indexfile);
+	    return(0);
+	}
+	/* 3 longs needed for: numinvitems, next block, and previous block */
+	amtused = 3 * sizeof(long);
+	numlogblk++;
+	/* check if had to back up, if so do it */
+	if (backupflag) {
+	    char *tptr2;
+	    
+	    /* find out where the end of the new block is */
+	    iteminfo.packword[0] = logicalblk.invblk[numinvitems*2+1];
+	    tptr3 = logicalblk.chrblk + iteminfo.e.offset;
+	    /* move the index for this block */
+	    for (i = 3; i <= (backupflag * 2 + 2); i++)
+		logicalblk.invblk[i] = logicalblk.invblk[numinvitems*2+i];
+	    /* move the word into the super index */
+	    iteminfo.packword[0] = logicalblk.invblk[3];
+	    iteminfo.packword[1] = logicalblk.invblk[4];
+	    tptr2 = logicalblk.chrblk + iteminfo.e.offset;
+	    strncpy(supfing, tptr2, (int) iteminfo.e.size);
+	    *(supfing + iteminfo.e.size) = '\0';
+#if DEBUG
+	    printf("backup %d at term=%s to term=%s\n",
+		   backupflag, thisterm, supfing);
+#endif
+	    *supint++ = nextsupfing;
+	    nextsupfing += strlen(supfing) + 1;
+	    supfing += strlen(supfing) + 1;
+	    /* now fix up the logical block */
+	    tptr = logicalblk.chrblk + lastinblk;
+	    lastinblk = sizeof(t_logicalblk);
+	    tptr2 = logicalblk.chrblk + lastinblk;
+	    j = tptr3 - tptr;
+	    while (tptr3 > tptr)
+		*--tptr2 = *--tptr3;
+	    lastinblk -= j;
+	    amtused += ((2 * sizeof(long)) * backupflag + j);
+	    for (i = 3; i < (backupflag * 2 + 2); i += 2) {
+		iteminfo.packword[0] = logicalblk.invblk[i];
+		iteminfo.e.offset += (tptr2 - tptr3);
+		logicalblk.invblk[i] = iteminfo.packword[0];
+	    }
+	    numinvitems = backupflag;
+	} else { /* no backup needed */
+	    numinvitems = 0;
+	    lastinblk = sizeof(t_logicalblk);
+	    /* add new term to superindex */
+	    strcpy(supfing, thisterm);
+	    supfing += strlen(thisterm) + 1;
+	    *supint++ = nextsupfing;
+	    nextsupfing += strlen(thisterm) + 1;
+	}
+    }
+    /* HBB 20010501: Fixed bug by replacing magic number '8' by
+     * what it actually represents. */
+    lastinblk -= (numwilluse - 2 * sizeof(long));
+    iteminfo.e.offset = lastinblk;
+    iteminfo.e.size = len;
+    iteminfo.e.space = 0;
+    iteminfo.e.post = numpost;
+    strncpy(logicalblk.chrblk + lastinblk, thisterm, len);
+    amtused += numwilluse;
+    logicalblk.invblk[(lastinblk/sizeof(long))+wdlen] = nextpost;
+    if ((i = postptr - POST) > 0) {
+	if (fwrite(POST, sizeof(*POST), i, fpost) == 0) {
+	    invcannotwrite(postingfile);
+	    return(0);
+	}
+	nextpost += i * sizeof(*POST);
+    }
+    logicalblk.invblk[3+2*numinvitems++] = iteminfo.packword[0];
+    logicalblk.invblk[2+2*numinvitems] = iteminfo.packword[1];
+    return(1);
+}
+
+/* 
+ * If 'invname' ends with the 'from' substring, it is replaced inline with the
+ * 'to' substring (which must be of the exact same length), and the function
+ * returns 0. Otherwise, returns -1.  
+ */
+
+static int 
+invflipname(char * invname, const char *from, const char *to)
+{
+	char *temp, *i = NULL;
+
+	assert(strlen(from) == strlen(to));
+
+	temp = invname - 1;
+	while( (temp = strstr(temp + 1, from)))
+		i = temp;
+	if (!i || i[strlen(from)] != '\0')
+		return -1;
+	while(*to)
+		*i++ = *to++;
+	return 0;
+}
+
+/* small helper function to centralize handling of binary opening
+ * for reading, and use of the 'stat" flag */
+static FILE *
+open_for_reading(char *name, int stat)
+{
+	return vpfopen(name, ((stat == 0) ? "rb" : "r+b"));
+}
+
+/* handle opening of a file under a possibly "flipped" name */
+/* If db created without '-f', but now invoked with '-f cscope.out',
+ * we need to check for 'cscope.in.out', rather than 'cscope.out.in': 
+ * I.e, hack around our own violation of the inverse db naming convention */
+/* more silliness: if you create the db with '-f cscope', then try to open 
+ * it without '-f cscope', you'll fail unless we check for 'cscope.out.in'
+ * here. */
+static FILE *
+open_file_with_flipped_name(char *name, const char *flip_in, const char *flip_out, int stat)
+{
+	if (! invflipname(name, flip_in, flip_out)) {
+		FILE *fptr = open_for_reading(name, stat);
+		if (! fptr)
+			/* flip back for error message */
+			invflipname(name, flip_out, flip_in);
+		return fptr;
+	};
+	return 0;
+}
+
+static FILE *
+open_file_with_possibly_flipped_name(char *name, const char *flip1, const char *flip2, int stat)
+{
+	FILE *fptr = open_for_reading(name, stat);
+
+	if (! fptr)
+		fptr = open_file_with_flipped_name(name, flip2, flip1, stat);
+	if (! fptr)
+		fptr = open_file_with_flipped_name(name, flip1, flip2, stat);
+	return fptr;
+}
+
+int
+invopen(INVCONTROL *invcntl, char *invname, char *invpost, int stat)
+{
+	int	read_index;
+
+	invcntl->invfile = open_file_with_possibly_flipped_name(invname, INVNAME, INVNAME2, stat);
+	if (! invcntl->invfile) {
+		invcannotopen(invname);
+		return(-1);
+	}
+	if (fread(&invcntl->param, sizeof(invcntl->param), 1, invcntl->invfile) == 0) {
+		fprintf(stderr, "%s: empty inverted file\n", argv0);
+		fclose(invcntl->invfile);
+		return(-1);
+	}
+	if (invcntl->param.version != FMTVERSION) {
+		fprintf(stderr, "%s: cannot read old index format; use -U option to force database to rebuild\n", argv0);
+		fclose(invcntl->invfile);
+		return(-1);
+	}
+	assert(invcntl->param.sizeblk == sizeof(t_logicalblk));
+
+	if (stat == 0 && invcntl->param.filestat == INVALONE) {
+		fprintf(stderr, "%s: inverted file is locked\n", argv0);
+		fclose(invcntl->invfile);
+		return(-1);
+	}
+
+	invcntl->postfile = open_file_with_possibly_flipped_name(invpost, INVPOST, INVPOST2, stat);
+	if (! invcntl->postfile) {
+		invcannotopen(invpost);
+		fclose(invcntl->invfile);
+		return(-1);
+	}
+
+	/* allocate core for a logical block  */
+	if ((invcntl->logblk = malloc((size_t) invcntl->param.sizeblk)) == NULL) {
+		invcannotalloc((size_t) invcntl->param.sizeblk);
+		fclose(invcntl->postfile);
+		fclose(invcntl->invfile);
+		return(-1);
+	}
+	/* allocate for and read in superfinger  */
+	read_index = 1;
+	invcntl->iindex = NULL;
+#if SHARE
+	if (invcntl->param.share == 1) {
+		key_t shm_key;
+		struct shmid_ds shm_buf;
+		int	shm_id;
+
+		/* see if the shared segment exists */
+		shm_key = ftok(invname, 2);
+		shm_id = shmget(shm_key, 0, 0);
+		/* Failure simply means (hopefully) that segment doesn't exists */
+		if (shm_id == -1) {
+			/* Have to give general write permission due to AMdahl not having protected segments */
+			shm_id = shmget(shm_key, invcntl->param.supsize + sizeof(long), IPC_CREAT | 0666);
+			if (shm_id == -1)
+				perror("Could not create shared memory segment");
+		} else
+			read_index = 0;
+
+		if (shm_id != -1) {
+			invcntl->iindex = shmat(shm_id, 0, ((read_index) ? 0 : SHM_RDONLY));
+			if (invcntl->iindex == (char *)ERR) {
+				fprintf(stderr, "%s: shared memory link failed\n", argv0);
+				invcntl->iindex = NULL;
+				read_index = 1;
+			}
+		}
+	}
+#endif
+	if (invcntl->iindex == NULL)
+	        /* FIXME HBB: magic number alert (4, sizeof(long)) */
+		invcntl->iindex = malloc((size_t) invcntl->param.supsize + 4 *sizeof(long));
+	if (invcntl->iindex == NULL) {
+		invcannotalloc((size_t) invcntl->param.supsize);
+		free(invcntl->logblk);
+		fclose(invcntl->postfile);
+		fclose(invcntl->invfile);
+		return(-1);
+	}
+	if (read_index) {
+		fseek(invcntl->invfile, invcntl->param.startbyte, SEEK_SET);
+		fread(invcntl->iindex, (int) invcntl->param.supsize, 1,
+		      invcntl->invfile);
+	}
+	invcntl->numblk = -1;
+	if (boolready() == -1) {
+		fclose(invcntl->postfile);
+		fclose(invcntl->invfile);
+		return(-1);
+	}
+	/* write back out the control block if anything changed */
+	invcntl->param.filestat = stat;
+	if (stat > invcntl->param.filestat ) {
+		rewind(invcntl->invfile);
+		fwrite(&invcntl->param, sizeof(invcntl->param), 1, invcntl->invfile);
+	}
+	return(1);
+}
+
+/** invclose must be called to wrap things up and deallocate core  **/
+void
+invclose(INVCONTROL *invcntl)
+{
+	/* write out the control block in case anything changed */
+	if (invcntl->param.filestat > 0) {
+		invcntl->param.filestat = 0;
+		rewind(invcntl->invfile);
+		fwrite(&invcntl->param, 1,
+		    sizeof(invcntl->param), invcntl->invfile);
+	}
+	if (invcntl->param.filestat == INVALONE) {
+		/* write out the super finger */
+		fseek(invcntl->invfile, invcntl->param.startbyte, SEEK_SET);
+		fwrite(invcntl->iindex, 1,
+		       (int) invcntl->param.supsize, invcntl->invfile);
+	}
+	fclose(invcntl->invfile);
+	fclose(invcntl->postfile);
+#if SHARE
+	if (invcntl->param.share > 0) {
+		shmdt(invcntl->iindex);
+		invcntl->iindex = NULL;
+	}
+#endif
+	if (invcntl->iindex != NULL)
+		free(invcntl->iindex);
+	free(invcntl->logblk);
+}
+
+/** invstep steps the inverted file forward one item **/
+static void
+invstep(INVCONTROL *invcntl)
+{
+	if (invcntl->keypnt < (invcntl->logblk->invblk[0] - 1)) {
+		invcntl->keypnt++; 
+		return;
+	}
+
+	/* move forward a block else wrap */
+	invcntl->numblk = invcntl->logblk->invblk[1]; /* was: *(int *)(invcntl->logblk + sizeof(long))*/                           
+
+	/* now read in the block  */
+	fseek(invcntl->invfile,
+	      invcntl->numblk*invcntl->param.sizeblk + invcntl->param.cntlsize,
+	      SEEK_SET);
+	fread(invcntl->logblk, (int) invcntl->param.sizeblk, 1,
+	      invcntl->invfile); 
+	invcntl->keypnt = 0; 
+}
+
+/** invforward moves forward one term in the inverted file  **/
+int
+invforward(INVCONTROL *invcntl)
+{
+	invstep(invcntl); 
+	/* skip things with 0 postings */
+	/* FIXME HBB: magic number alert! (3) */
+	while (((ENTRY * )(invcntl->logblk->invblk + 3) + invcntl->keypnt)->post == 0) {
+		invstep(invcntl); 
+	}
+	/* Check for having wrapped - reached start of inverted file! */
+	if ((invcntl->numblk == 0) && (invcntl->keypnt == 0))
+		return(0);
+	return(1);
+}
+
+/**  invterm gets the present term from the present logical block  **/
+long
+invterm(INVCONTROL *invcntl, char *term)
+{
+	ENTRY * entryptr;
+
+	/* FIXME HBB: magic number alert! (3) */
+	entryptr = (ENTRY *)(invcntl->logblk->invblk + 3) + invcntl->keypnt;
+	strncpy(term, invcntl->logblk->chrblk + entryptr->offset,
+		       (int) entryptr->size);
+	*(term + entryptr->size) = '\0';
+	return(entryptr->post);
+}
+
+/** invfind searches for an individual item in the inverted file  **/
+long
+invfind(INVCONTROL *invcntl, char *searchterm) /* term being searched for  */
+{
+	int	imid, ilow, ihigh;
+	long	num;
+	int	i;
+	unsigned long	*intptr, *intptr2;
+	ENTRY *entryptr;
+
+	/* make sure it is initialized via invready  */
+	if (invcntl->invfile == 0)
+		return(-1L);
+
+	/* now search for the appropriate finger block */
+	intptr = (unsigned long *)invcntl->iindex;
+
+	ilow = 0;
+	ihigh = *intptr++ - 1;
+	while (ilow <= ihigh) {
+		imid = (ilow + ihigh) / 2;
+		intptr2 = intptr + imid;
+		i = strcmp(searchterm, (invcntl->iindex + *intptr2));
+		if (i < 0)
+			ihigh = imid - 1;
+		else if (i > 0)
+			ilow = ++imid;
+		else {
+			ilow = imid + 1;
+			break;
+		}
+	}
+	/* be careful about case where searchterm is after last in this block  */
+	imid = (ilow) ? ilow - 1 : 0;
+
+	/* fetch the appropriate logical block if not in core  */
+	/* note always fetch it if the file is busy */
+	if ((imid != invcntl->numblk) || (invcntl->param.filestat >= INVBUSY)) {
+		fseek(invcntl->invfile,
+		      (imid*invcntl->param.sizeblk) + invcntl->param.cntlsize,
+		      SEEK_SET);
+		invcntl->numblk = imid;
+		fread(invcntl->logblk, (int)invcntl->param.sizeblk, 1,
+		      invcntl->invfile);
+	}
+
+srch_ext:
+	/* now find the term in this block. tricky this  */
+	intptr = (unsigned long *) invcntl->logblk->invblk;
+
+	ilow = 0;
+	ihigh = *intptr - 1;
+	intptr += 3;
+	num = 0;
+	while (ilow <= ihigh) {
+		imid = (ilow + ihigh) / 2;
+		entryptr = (ENTRY *)intptr + imid;
+		i = strncmp(searchterm, invcntl->logblk->chrblk + entryptr->offset,
+		    (int) entryptr->size );
+		if (i == 0)
+			i = strlen(searchterm) - entryptr->size;
+		if (i < 0)
+			ihigh = imid - 1;
+		else if (i > 0)
+			ilow = ++imid;
+		else {
+			num = entryptr->post;
+			break;
+		}
+	}
+	/* be careful about case where searchterm is after last in this block  */
+	if (imid >= invcntl->logblk->invblk[0]) {
+		invcntl->keypnt = invcntl->logblk->invblk[0];
+		invstep(invcntl);
+		/* note if this happens the term could be in extended block */
+		if (invcntl->param.startbyte < invcntl->numblk * invcntl->param.sizeblk)
+			goto srch_ext;
+	} else
+		invcntl->keypnt = imid;
+	return(num);
+}
+
+#if DEBUG
+
+/** invdump dumps the block the term parameter is in **/
+void
+invdump(INVCONTROL *invcntl, char *term)
+{
+	long	i, j, n, *longptr;
+	ENTRY * entryptr;
+	char	temp[512], *ptr;
+
+	/* dump superindex if term is "-"  */
+	if (*term == '-') {
+		j = atoi(term + 1);
+		longptr = (long *)invcntl->iindex;
+		n = *longptr++;
+		printf("Superindex dump, num blocks=%ld\n", n);
+		longptr += j;
+		while ((longptr <= ((long *)invcntl->iindex) + n) && invbreak == 0) {
+			printf("%2ld  %6ld %s\n", j++, *longptr, invcntl->iindex + *longptr);
+			longptr++;
+		}
+		return;
+	} else if (*term == '#') {
+		j = atoi(term + 1);
+		/* fetch the appropriate logical block */
+		invcntl->numblk = j;
+		fseek(invcntl->invfile,
+		      (j * invcntl->param.sizeblk) + invcntl->param.cntlsize,
+		      SEEK_SET);
+		fread(invcntl->logblk, (int) invcntl->param.sizeblk, 1,
+		      invcntl->invfile);
+	} else
+		i = abs((int) invfind(invcntl, term));
+	longptr = invcntl->logblk->invblk;
+	n = *longptr++;
+	printf("Entry term to invdump=%s, postings=%ld, forwrd ptr=%ld, back ptr=%ld\n"
+	    , term, i, *(longptr), *(longptr + 1));
+	/* FIXME HBB: magic number alert! (3) */
+	entryptr = (ENTRY *) (invcntl->logblk->invblk + 3);
+	printf("%ld terms in this block, block=%ld\n", n, invcntl->numblk);
+	printf("\tterm\t\t\tposts\tsize\toffset\tspace\t1st word\n");
+	for (j = 0; j < n && invbreak == 0; j++) {
+		ptr = invcntl->logblk->chrblk + entryptr->offset;
+		strncpy(temp, ptr, (int) entryptr->size);
+		temp[entryptr->size] = '\0';
+		ptr += (sizeof(long) * (long)((entryptr->size + (sizeof(long) - 1)) / sizeof(long)));
+		printf("%2ld  %-24s\t%5ld\t%3d\t%d\t%d\t%ld\n", j, temp, entryptr->post,
+		    entryptr->size, entryptr->offset, entryptr->space,
+		    *(long *)ptr);
+		entryptr++;
+	}
+}
+#endif
+
+static int
+boolready(void)
+{
+	numitems = 0;
+	if (item1 != NULL) 
+		free(item1);
+	setsize1 = SETINC;
+	if ((item1 = malloc(SETINC * sizeof(*item1))) == NULL) {
+		invcannotalloc(SETINC);
+		return(-1);
+	}
+	if (item2 != NULL) 
+		free(item2);
+	setsize2 = SETINC;
+	if ((item2 = malloc(SETINC * sizeof(*item2))) == NULL) {
+		invcannotalloc(SETINC);
+		return(-1);
+	}
+	item = item1;
+	enditem = item;
+	return(0);
+}
+
+void
+boolclear(void)
+{
+	numitems = 0;
+	item = item1;
+	enditem = item;
+}
+
+POSTING *
+boolfile(INVCONTROL *invcntl, long *num, int boolarg)
+{
+	ENTRY	*entryptr;
+	FILE	*file;
+	void	*ptr;
+	unsigned long	*ptr2;
+	POSTING	*newitem = NULL; /* initialize, to avoid warning */
+	POSTING	posting;
+	unsigned u;
+	POSTING *newsetp = NULL, *set1p;
+	long	newsetc, set1c, set2c;
+
+	/* FIXME HBB: magic number alert! (3) */
+	entryptr = (ENTRY *) (invcntl->logblk->invblk + 3) + invcntl->keypnt;
+	ptr = invcntl->logblk->chrblk + entryptr->offset;
+	ptr2 = ((unsigned long *) ptr) + (entryptr->size + (sizeof(long) - 1)) / sizeof(long);
+	*num = entryptr->post;
+	switch (boolarg) {
+	case BOOL_OR:
+	case NOT:
+		if (*num == 0) {
+			*num = numitems;
+			return(item);
+		}
+	}
+	/* make room for the new set */
+	u = 0;
+	switch (boolarg) {
+	case AND:
+	case NOT:
+		newsetp = item;
+		break;
+
+	case BOOL_OR:
+		u = enditem - item;
+		/* FALLTHROUGH */
+	case REVERSENOT:
+		u += *num;
+		if (item == item2) {
+			if (u > setsize1) {
+				u += SETINC;
+				if ((item1 = realloc(item1, u * sizeof(*item1))) == NULL) {
+					invcannotalloc(u * sizeof(*item1));
+					boolready();
+					*num = -1;
+					return(NULL);
+				}
+				setsize1 = u;
+			}
+			newitem = item1;
+		}
+		else {
+			if (u > setsize2) {
+				u += SETINC;
+				if ((item2 = realloc(item2, u * sizeof(*item2))) == NULL) {
+					invcannotalloc(u * sizeof(*item2));
+					boolready();
+					*num = -1;
+					return(NULL);
+				}
+				setsize2 = u;
+			}
+			newitem = item2;
+		}
+#if 0 /* this write is only need by commented-out code later */
+		set1p = item;
+#endif
+		newsetp = newitem;
+	}
+	file = invcntl->postfile;
+	fseek(file, *ptr2, SEEK_SET);
+	fread(&posting, sizeof(posting), 1, file);
+	newsetc = 0;
+	switch (boolarg) {
+	case BOOL_OR:
+		/* while something in both sets */
+		set1p = item;
+		newsetp = newitem;
+		for (set1c = 0, set2c = 0;
+		    set1c < numitems && set2c < *num; newsetc++) {
+			if (set1p->lineoffset < posting.lineoffset) {
+				*newsetp++ = *set1p++;
+				set1c++;
+			}
+			else if (set1p->lineoffset > posting.lineoffset) {
+				*newsetp++ = posting;
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+			else if (set1p->type < posting.type) {
+				*newsetp++ = *set1p++;
+				set1c++;
+			}
+			else if (set1p->type > posting.type) {
+				*newsetp++ = posting;
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+			else {	/* identical postings */
+				*newsetp++ = *set1p++;
+				set1c++;
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+		}
+		/* find out what ran out and move the rest in */
+		if (set1c < numitems) {
+			newsetc += numitems - set1c;
+			while (set1c++ < numitems) {
+				*newsetp++ = *set1p++;
+			}
+		} else {
+			while (set2c++ < *num) {
+				*newsetp++ = posting;
+				newsetc++;
+				fread(&posting, (int) sizeof(posting), 1, file);
+			}
+		}
+		item = newitem;
+		break; /* end of BOOL_OR */
+#if 0
+	case AND:
+		for (set1c = 0, set2c = 0; set1c < numitems && set2c < *num; ) {
+			if (set1p->lineoffset < posting.lineoffset) {
+				set1p++;
+				set1c++;
+			}
+			else if (set1p->lineoffset > posting.lineoffset) {
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+			else if (set1p->type < posting.type)  {
+				*set1p++;
+				set1c++;
+			}
+			else if (set1p->type > posting.type) {
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+			else {	/* identical postings */
+				*newsetp++ = *set1p++;
+				newsetc++;
+				set1c++;
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+		}
+		break; /* end of AND */
+
+	case NOT:
+		for (set1c = 0, set2c = 0; set1c < numitems && set2c < *num; ) {
+			if (set1p->lineoffset < posting.lineoffset) {
+				*newsetp++ = *set1p++;
+				newsetc++;
+				set1c++;
+			}
+			else if (set1p->lineoffset > posting.lineoffset) {
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+			else if (set1p->type < posting.type) {
+				*newsetp++ = *set1p++;
+				newsetc++;
+				set1c++;
+			}
+			else if (set1p->type > posting.type) {
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+			else {	/* identical postings */
+				set1c++;
+				set1p++;
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+		}
+		newsetc += numitems - set1c;
+		while (set1c++ < numitems) {
+			*newsetp++ = *set1p++;
+		}
+		break; /* end of NOT */
+
+	case REVERSENOT:  /* core NOT incoming set */
+		for (set1c = 0, set2c = 0; set1c < numitems && set2c < *num; ) {
+			if (set1p->lineoffset < posting.lineoffset) {
+				set1p++;
+				set1c++;
+			}
+			else if (set1p->lineoffset > posting.lineoffset) {
+				*newsetp++ = posting;
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+			else if (set1p->type < posting.type) {
+				set1p++;
+				set1c++;
+			}
+			else if (set1p->type > posting.type) {
+				*newsetp++ = posting;
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+			else {	/* identical postings */
+				set1c++;
+				set1p++;
+				fread(&posting, (int) sizeof(posting), 1, file);
+				set2c++;
+			}
+		}
+		while (set2c++ < *num) {
+			*newsetp++ = posting;
+			newsetc++;
+			fread(&posting, (int) sizeof(posting), 1, file);
+		}
+		item = newitem;
+		break; /* end of REVERSENOT  */
+#endif
+	}
+	numitems = newsetc;
+	*num = newsetc;
+	enditem = (POSTING *) newsetp;
+	return((POSTING *) item);
+}
+
+#if 0
+POSTING *
+boolsave(int clear)		/* flag about whether to clear core  */
+{
+	int	i;
+	POSTING	*ptr;
+	POSTING	*oldstuff, *newstuff;
+
+	if (numitems == 0) {
+		if (clear) 
+			boolclear();
+		return(NULL);
+	}
+	/* if clear then give them what we have and use boolready to realloc  */
+	if (clear) {
+		ptr = item;
+		/* free up the space we didn't give them */
+		if (item == item1)
+			item1 = NULL;
+		else
+			item2 = NULL;
+		boolready();
+		return(ptr);
+	}
+	i = (enditem - item) * sizeof(*ptr) + 100;
+	if ((ptr = malloc(i)) == NULL) {
+		invcannotalloc(i);
+		return(ptr);
+	}
+	/* move present set into place  */
+	oldstuff = item;
+	newstuff = ptr;
+	while (oldstuff < enditem)
+		*newstuff++ = *oldstuff++;
+	return(ptr);
+}
+#endif
+
+static void
+invcannotalloc(unsigned n)
+{
+	fprintf(stderr, "%s: cannot allocate %u bytes\n", argv0, n);
+}
+
+static void
+invcannotopen(char *file)
+{
+	fprintf(stderr, "%s: cannot open file %s\n", argv0, file);
+}
+
+static void
+invcannotwrite(char *file)
+{
+	perror(argv0);	/* must be first to preserve errno */
+	fprintf(stderr, "%s: write to file %s failed\n", argv0, file);
+}
diff --git a/src/invlib.h b/src/invlib.h
new file mode 100644
index 0000000..c47b874
--- /dev/null
+++ b/src/invlib.h
@@ -0,0 +1,114 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE. 
+ =========================================================================*/
+
+#ifndef CSCOPE_INVLIB_H
+#define CSCOPE_INVLIB_H
+
+#include <stdio.h>		/* need definition of FILE* */
+#include <limits.h>             /* need definition of CHAR_MAX */
+
+/* inverted index definitions */
+
+/* postings temporary file long number coding into characters */
+#if CHAR_MAX==255
+# define	BASE		223	/* 255 - ' ' */
+# define	PRECISION	4	/* maximum digits after converting a long */
+#else
+# if CHAR_MAX==127	/* assume sign-extension of a char when converted to an int */
+#  define	BASE		95	/* 127 - ' ' */
+#  define	PRECISION	5	/* maximum digits after converting a long */
+# else
+  #error Need a platform with 8 bits in a char value
+# endif
+#endif
+
+/* inverted index access parameters */
+#define INVAVAIL	0
+#define INVBUSY		1
+#define INVALONE	2
+
+/* boolean set operations */
+#define	BOOL_OR		3
+#define	AND		4
+#define	NOT		5
+#define	REVERSENOT	6
+
+/* note that the entire first block is for parameters */
+typedef	struct	{
+	long	version;	/* inverted index format version */
+	long	filestat;	/* file status word  */
+	long	sizeblk;	/* size of logical block in bytes */
+	long	startbyte;	/* first byte of superfinger */
+	long	supsize;	/* size of superfinger in bytes */
+	long	cntlsize;	/* size of max cntl space (should be a multiple of BUFSIZ) */
+	long	share;		/* flag whether to use shared memory */
+} PARAM;
+
+typedef	struct {
+	FILE	*invfile;	/* the inverted file ptr */
+	FILE	*postfile;	/* posting file ptr */
+	PARAM	param;		/* control parameters for the file */
+	char	*iindex;	/* ptr to space for superindex */
+	union logicalblk *logblk;	/* ptr to space for a logical block */
+	long	numblk;		/* number of block presently at *logblk */
+	long	keypnt;		/* number item in present block found */
+} INVCONTROL;
+
+typedef        struct  {
+       short   offset;         /* offset in this logical block */
+       unsigned char size;     /* size of term */
+       unsigned char space;    /* number of longs of growth space */
+       long    post;           /* number of postings for this entry */
+} ENTRY;
+
+typedef	struct {
+	long	lineoffset;	/* source line database offset */
+	long	fcnoffset;	/* function name database offset */
+	long	fileindex : 24;	/* source file name index */
+	long	type : 8;	/* reference type (mark character) */
+} POSTING;
+
+extern	long	*srcoffset;	/* source file name database offsets */
+extern	int	nsrcoffset;	/* number of file name database offsets */
+
+
+void	boolclear(void);
+POSTING	*boolfile(INVCONTROL *invcntl, long *num, int boolarg);
+void	invclose(INVCONTROL *invcntl);
+void	invdump(INVCONTROL *invcntl, char *term);
+long	invfind(INVCONTROL *invcntl, char *searchterm);
+int	invforward(INVCONTROL *invcntl);
+int	invopen(INVCONTROL *invcntl, char *invname, char *invpost, int status);
+long	invmake(char *invname, char *invpost, FILE *infile);
+long	invterm(INVCONTROL *invcntl, char *term);
+
+#endif /* CSCOPE_INVLIB_H */
diff --git a/src/library.h b/src/library.h
new file mode 100644
index 0000000..4786730
--- /dev/null
+++ b/src/library.h
@@ -0,0 +1,51 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE. 
+ =========================================================================*/
+
+#ifndef CSCOPE_LIBRARY_H
+#define CSCOPE_LIBRARY_H
+
+#include <stdio.h>		/* need FILE* type def. */
+
+/* private library */
+char	*compath(char *pathname);
+char	*egrepinit(char *egreppat);
+char	*logdir(char *name);
+char	*basename(char *path);
+FILE	*myfopen(char *path, char *mode);
+char	*mygetenv(char *variable, char *deflt);
+int	myopen(char *path, int flag, int mode);
+FILE	*mypopen(char *cmd, char *mode);
+int	mypclose(FILE *ptr);
+FILE	*vpfopen(char *filename, char *type);
+void	egrepcaseless(int i);
+
+#endif /* CSCOPE_LIBRARY_H */
diff --git a/src/logdir.c b/src/logdir.c
new file mode 100644
index 0000000..63903f8
--- /dev/null
+++ b/src/logdir.c
@@ -0,0 +1,100 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*
+ *	logdir()
+ *
+ *	This routine does not use the getpwent(3) library routine
+ *	because the latter uses the stdio package.  The allocation of
+ *	storage in this package destroys the integrity of the shell's
+ *	storage allocation.
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include "global.h"
+
+#define	OURBUFSIZ	160	/* renamed: avoid conflict with <stdio.h> */
+
+static char line[OURBUFSIZ+1];
+
+/* Internal prototypes: */
+static	char	*nextfield(char *p);
+
+
+static char *
+nextfield(char *p)
+{
+	while (*p && *p != ':')
+		++p;
+	if (*p) *p++ = 0;
+	return(p);
+}
+
+char *
+logdir(char *name)
+{
+	char	*p;
+	int	i, j;
+	int	pwf;
+	
+	/* attempt to open the password file */
+	if ((pwf = myopen("/etc/passwd", 0, 0)) == -1)
+		return(0);
+		
+	/* find the matching password entry */
+	do {
+		/* get the next line in the password file */
+		i = read(pwf, line, OURBUFSIZ);
+		for (j = 0; j < i; j++)
+			if (line[j] == '\n')
+				break;
+		/* return a null pointer if the whole file has been read */
+		if (j >= i)
+			return(0);
+		line[++j] = 0;			/* terminate the line */
+		(void) lseek(pwf, (long) (j - i), 1);	/* point at the next line */
+		p = nextfield(line);		/* get the logname */
+	} while (*name != *line ||	/* fast pretest */
+	    strcmp(name, line) != 0);
+	(void) close(pwf);
+	
+	/* skip the intervening fields */
+	p = nextfield(p);
+	p = nextfield(p);
+	p = nextfield(p);
+	p = nextfield(p);
+	
+	/* return the login directory */
+	(void) nextfield(p);
+	return(p);
+}
diff --git a/src/lookup.c b/src/lookup.c
new file mode 100644
index 0000000..d8595db
--- /dev/null
+++ b/src/lookup.c
@@ -0,0 +1,149 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	keyword look-up routine for the C symbol scanner
+ */
+
+#include "global.h"
+#include "lookup.h"
+
+/* keyword text for fast testing of keywords in the scanner */
+char	enumtext[] = "enum";
+char	externtext[] = "extern";
+char	structtext[] = "struct";
+char	typedeftext[] = "typedef";
+char	uniontext[] = "union";
+
+/* This keyword table is also used for keyword text compression.  Keywords
+ * with an index less than the numeric value of a space are replaced with the
+ * control character corresponding to the index, so they cannot be moved
+ * without changing the database file version and adding compatibility code
+ * for old databases.
+ */
+struct	keystruct keyword[] = {
+	{"",		'\0',	NULL},	/* dummy entry */
+	{"#define",	' ',	NULL},	/* must be table entry 1 */
+	{"#include",	' ',	NULL},	/* must be table entry 2 */
+	{"break",	'\0',	NULL},	/* rarely in cross-reference */
+	{"case",	' ',	NULL},
+	{"char",	' ',	NULL},
+	{"continue",	'\0',	NULL},	/* rarely in cross-reference */
+	{"default",	'\0',	NULL},	/* rarely in cross-reference */
+	{"double",	' ',	NULL},
+	{"\t",		'\0',	NULL},	/* must be the table entry 9 */
+	{"\n",		'\0',	NULL},	/* must be the table entry 10 */
+	{"else",	' ',	NULL},
+	{enumtext,	' ',	NULL},
+	{externtext,	' ',	NULL},
+	{"float",	' ',	NULL},
+	{"for",		'(',	NULL},
+	{"goto",	' ',	NULL},
+	{"if",		'(',	NULL},
+	{"int",		' ',	NULL},
+	{"long",	' ',	NULL},
+	{"register",	' ',	NULL},
+	{"return",	'\0',	NULL},
+	{"short",	' ',	NULL},
+	{"sizeof",	'\0',	NULL},
+	{"static",	' ',	NULL},
+	{structtext,	' ',	NULL},
+	{"switch",	'(',	NULL},
+	{typedeftext,	' ',	NULL},
+	{uniontext,	' ',	NULL},
+	{"unsigned",	' ',	NULL},
+	{"void",	' ',	NULL},
+	{"while",	'(',	NULL},
+	
+	/* these keywords are not compressed */
+	{"do",		'\0',	NULL},
+	{"auto",	' ',	NULL},
+	{"fortran",	' ',	NULL},
+	{"const",	' ',	NULL},
+	{"signed",	' ',	NULL},
+	{"volatile",	' ',	NULL},
+};
+#define KEYWORDS	(sizeof(keyword) / sizeof(keyword[0]))
+
+#define HASHMOD	(KEYWORDS * 2 + 1)
+
+static	struct	keystruct *hashtab[HASHMOD]; /* pointer table */
+
+/* put the keywords into the symbol table */
+
+void
+initsymtab(void)
+{
+    unsigned int i, j;
+    struct keystruct *p;
+	
+    for (i = 1; i < KEYWORDS; ++i) {
+	p = keyword + i;
+	j = hash(p->text) % HASHMOD;
+	p->next = hashtab[j];
+	hashtab[j] = p;
+    }
+}
+
+/* see if this identifier is a keyword */
+
+char *
+lookup(char *ident)
+{
+	struct	keystruct *p;
+	int	c;
+	
+	/* look up the identifier in the keyword table */
+	for (p = hashtab[hash(ident) % HASHMOD]; p != NULL; p = p->next) {
+		if (strequal(ident, p->text)) {
+			if (compress == YES && (c = p - keyword) < ' ') {
+				ident[0] = c;	/* compress the keyword */
+			}
+			return(p->text);
+		}
+	}
+	/* this is an identifier */
+	return(NULL);
+}
+
+/* form hash value for string */
+int
+hash(char *ss)
+{
+	int	i;
+	unsigned char 	*s = (unsigned char *)ss;
+	
+	for (i = 0; *s != '\0'; )
+		i += *s++;	/* += is faster than <<= for cscope */
+	return(i);
+}
diff --git a/src/lookup.h b/src/lookup.h
new file mode 100644
index 0000000..47c37bb
--- /dev/null
+++ b/src/lookup.h
@@ -0,0 +1,45 @@
+/*===========================================================================
+ Copyright (c) 2001, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE. 
+ =========================================================================*/
+
+#ifndef CSCOPE_LOOKUP_H
+#define CSCOPE_LOOKUP_H
+
+/* declarations for objects defined in lookup.c */
+
+/* keyword text for fast testing of keywords in the scanner */
+extern	char	enumtext[];
+extern	char	externtext[];
+extern	char	structtext[];
+extern	char	typedeftext[];
+extern	char	uniontext[];
+
+#endif /* CSCOPE_LOOKUP_H */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..843d787
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,674 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	main functions
+ */
+
+#include "global.h"
+
+#include "build.h"
+#include "vp.h"
+#include "version.h"	/* FILEVERSION and FIXVERSION */
+#include "scanner.h" 
+
+#include <stdlib.h>	/* atoi */
+#include <ncurses.h>
+#include <sys/types.h>	/* needed by stat.h */
+#include <sys/stat.h>	/* stat */
+#include <signal.h>
+#include <getopt.h>
+
+/* defaults for unset environment variables */
+#define	EDITOR	"vi"
+#define HOME	"/"		/* no $HOME --> use root directory */
+#define	SHELL	"sh"
+#define LINEFLAG "+%s"	/* default: used by vi and emacs */
+#define TMPDIR	"/tmp"
+
+/* note: these digraph character frequencies were calculated from possible 
+   printable digraphs in the cross-reference for the C compiler */
+char	dichar1[] = " teisaprnl(of)=c";	/* 16 most frequent first chars */
+char	dichar2[] = " tnerpla";		/* 8 most frequent second chars 
+					   using the above as first chars */
+char	dicode1[256];		/* digraph first character code */
+char	dicode2[256];		/* digraph second character code */
+
+char	*editor, *shell, *lineflag;	/* environment variables */
+char	*home;			/* Home directory */
+BOOL	lineflagafterfile;
+char	*argv0;			/* command name */
+BOOL	compress = YES;		/* compress the characters in the crossref */
+BOOL	dbtruncated;		/* database symbols are truncated to 8 chars */
+int	dispcomponents = 1;	/* file path components to display */
+#if CCS
+BOOL	displayversion;		/* display the C Compilation System version */
+#endif
+BOOL	editallprompt = YES;	/* prompt between editing files */
+unsigned int fileargc;		/* file argument count */
+char	**fileargv;		/* file argument values */
+int	fileversion;		/* cross-reference file version */
+BOOL	incurses = NO;		/* in curses */
+BOOL	invertedindex;		/* the database has an inverted index */
+BOOL	isuptodate;		/* consider the crossref up-to-date */
+BOOL	kernelmode;		/* don't use DFLT_INCDIR - bad for kernels */
+BOOL	linemode = NO;		/* use line oriented user interface */
+BOOL	verbosemode = NO;	/* print extra information on line mode */
+BOOL	recurse_dir = NO;	/* recurse dirs when searching for src files */
+char	*namefile;		/* file of file names */
+BOOL	ogs;			/* display OGS book and subsystem names */
+char	*prependpath;		/* prepend path to file names */
+FILE	*refsfound;		/* references found file */
+char	temp1[PATHLEN + 1];	/* temporary file name */
+char	temp2[PATHLEN + 1];	/* temporary file name */
+char	tempdirpv[PATHLEN + 1];	/* private temp directory */
+long	totalterms;		/* total inverted index terms */
+BOOL	trun_syms;		/* truncate symbols to 8 characters */
+char	tempstring[TEMPSTRING_LEN + 1]; /* use this as a buffer, instead of 'yytext', 
+				 * which had better be left alone */
+char	*tmpdir;		/* temporary directory */
+
+
+/* Internal prototypes: */
+static	void	skiplist(FILE *oldrefs);
+static	void	initcompress(void);
+static inline	void	readenv(void);
+
+#if defined(KEY_RESIZE) && !defined(__DJGPP__)
+void 
+sigwinch_handler(int sig, siginfo_t *info, void *unused)
+{
+    if(incurses == YES){
+        ungetch(KEY_RESIZE);
+	}
+}
+#endif
+
+int
+main(int argc, char **argv)
+{
+    FILE *names;			/* name file pointer */
+    int	oldnum;			/* number in old cross-ref */
+    char path[PATHLEN + 1];	/* file path */
+    FILE *oldrefs;	/* old cross-reference file */
+    char *s;
+    int c;
+    unsigned int i;
+    pid_t pid;
+    struct stat	stat_buf;
+#if defined(KEY_RESIZE) && !defined(__DJGPP__)
+    struct sigaction winch_action;
+#endif
+    mode_t orig_umask;
+	
+    yyin = stdin;
+    yyout = stdout;
+    /* save the command name for messages */
+    argv0 = argv[0];
+
+    /* set the options */
+	argv = parse_options(&argc, argv);
+
+    /* read the environment */
+	readenv();
+
+    /* XXX remove if/when clearerr() in dir.c does the right thing. */
+    if (namefile && strcmp(namefile, "-") == 0 && !buildonly) {
+	postfatal("cscope: Must use -b if file list comes from stdin\n");
+	/* NOTREACHED */
+    }
+
+    /* make sure that tmpdir exists */
+    if (lstat (tmpdir, &stat_buf)) {
+	fprintf (stderr, 
+		"cscope: Temporary directory %s does not exist or cannot be accessed\n", 
+		 tmpdir);
+	fprintf (stderr,
+		"cscope: Please create the directory or set the environment variable\n"
+		"cscope: TMPDIR to a valid directory\n");
+	myexit(1);
+    }
+
+    /* create the temporary file names */
+    orig_umask = umask(S_IRWXG|S_IRWXO);
+    pid = getpid();
+    snprintf(tempdirpv, sizeof(tempdirpv), "%s/cscope.%d", tmpdir, pid);
+    if(mkdir(tempdirpv,S_IRWXU)) {
+	fprintf(stderr, 
+		"cscope: Could not create private temp dir %s\n",
+		tempdirpv);
+	myexit(1);
+    }
+    umask(orig_umask);
+
+    snprintf(temp1, sizeof(temp1), "%s/cscope.1", tempdirpv);
+    snprintf(temp2, sizeof(temp2), "%s/cscope.2", tempdirpv);
+
+    /* if running in the foreground */
+    if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
+	/* cleanup on the interrupt and quit signals */
+	signal(SIGINT, myexit);
+	signal(SIGQUIT, myexit);
+    }
+    /* cleanup on the hangup signal */
+    signal(SIGHUP, myexit);
+
+    /* ditto the TERM signal */
+    signal(SIGTERM, myexit);
+
+    /* ignore PIPE signal, so myexit() will have a chance to clean up in
+     * linemode, while in curses mode the "|" command can cause a pipe signal
+     * too
+     */
+    signal(SIGPIPE, SIG_IGN);
+
+    /* if the database path is relative and it can't be created */
+    if (reffile[0] != '/' && access(".", WRITE) != 0) {
+
+	/* put it in the home directory if the database may not be
+	 * up-to-date or doesn't exist in the relative directory,
+	 * so a database in the current directory will be
+	 * used instead of failing to open a non-existant database in
+	 * the home directory
+	 */
+	snprintf(path, sizeof(path), "%s/%s", home, reffile);
+	if (isuptodate == NO || access(path, READ) == 0) {
+	    reffile = strdup(path);
+	    snprintf(path, sizeof(path), "%s/%s", home, invname);
+	    invname = strdup(path);
+	    snprintf(path, sizeof(path), "%s/%s", home, invpost);
+	    invpost = strdup(path);
+	}
+    }
+
+    if (linemode == NO) {
+	signal(SIGINT, SIG_IGN);	/* ignore interrupts */
+
+#if defined(KEY_RESIZE) && !defined(__DJGPP__)
+	winch_action.sa_sigaction = sigwinch_handler;
+	sigemptyset(&winch_action.sa_mask);
+	winch_action.sa_flags = SA_SIGINFO;
+	sigaction(SIGWINCH,&winch_action,NULL);
+#endif
+
+	dispinit();	/* initialize display parameters */
+	setfield();	/* set the initial cursor position */
+	clearmsg();	/* clear any build progress message */
+	display();	/* display the version number and input fields */
+    }
+
+
+    /* if the cross-reference is to be considered up-to-date */
+    if (isuptodate == YES) {
+	if ((oldrefs = vpfopen(reffile, "rb")) == NULL) {
+	    postfatal("cscope: cannot open file %s\n", reffile);
+	    /* NOTREACHED */
+	}
+	/* get the crossref file version but skip the current directory */
+	if (fscanf(oldrefs, "cscope %d %*s", &fileversion) != 1) {
+	    postfatal("cscope: cannot read file version from file %s\n", 
+		      reffile);
+	    /* NOTREACHED */
+	}
+	if (fileversion >= 8) {
+
+	    /* override these command line options */
+	    compress = YES;
+	    invertedindex = NO;
+
+	    /* see if there are options in the database */
+	    for (;;) {
+		getc(oldrefs);	/* skip the blank */
+		if ((c = getc(oldrefs)) != '-') {
+		    ungetc(c, oldrefs);
+		    break;
+		}
+		switch (getc(oldrefs)) {
+		case 'c':	/* ASCII characters only */
+		    compress = NO;
+		    break;
+		case 'q':	/* quick search */
+		    invertedindex = YES;
+		    fscanf(oldrefs, "%ld", &totalterms);
+		    break;
+		case 'T':	/* truncate symbols to 8 characters */
+		    dbtruncated = YES;
+		    trun_syms = YES;
+		    break;
+		}
+	    }
+	    initcompress();
+	    seek_to_trailer(oldrefs);
+	}
+	/* skip the source and include directory lists */
+	skiplist(oldrefs);
+	skiplist(oldrefs);
+
+	/* get the number of source files */
+	if (fscanf(oldrefs, "%lu", &nsrcfiles) != 1) {
+	    postfatal(
+			"cscope: cannot read source file size from file %s\n",
+			reffile);
+	    /* NOTREACHED */
+	}
+	/* get the source file list */
+	srcfiles = malloc(nsrcfiles * sizeof(*srcfiles));
+	if (fileversion >= 9) {
+
+	    /* allocate the string space */
+	    if (fscanf(oldrefs, "%d", &oldnum) != 1) {
+		postfatal(
+			"cscope: cannot read string space size from file %s\n",
+			reffile);
+		/* NOTREACHED */
+	    }
+	    s = malloc(oldnum);
+	    getc(oldrefs);	/* skip the newline */
+			
+	    /* read the strings */
+	    if (fread(s, oldnum, 1, oldrefs) != 1) {
+		postfatal(
+			"cscope: cannot read source file names from file %s\n",
+			reffile);
+		/* NOTREACHED */
+	    }
+	    /* change newlines to nulls */
+	    for (i = 0; i < nsrcfiles; ++i) {
+		srcfiles[i] = s;
+		for (++s; *s != '\n'; ++s) {
+		    ;
+		}
+		*s = '\0';
+		++s;
+	    }
+	    /* if there is a file of source file names */
+	    if ((namefile != NULL && (names = vpfopen(namefile, "r")) != NULL)
+		|| (names = vpfopen(NAMEFILE, "r")) != NULL) {
+	
+		/* read any -p option from it */
+		while (fgets(path, sizeof(path), names) != NULL && *path == '-') {
+		    i = path[1];
+		    s = path + 2;		/* for "-Ipath" */
+		    if (*s == '\0') {	/* if "-I path" */
+			fgets(path, sizeof(path), names);
+			s = path;
+		    }
+		    switch (i) {
+		    case 'p':	/* file path components to display */
+			if (*s < '0' || *s > '9') {
+			    posterr("cscope: -p option in file %s: missing or invalid numeric value\n", 								namefile);
+
+			}
+			dispcomponents = atoi(s);
+		    }
+		}
+		fclose(names);
+	    }
+	} else {
+	    for (i = 0; i < nsrcfiles; ++i) {
+		if (!fgets(path, sizeof(path), oldrefs) ) {
+		    postfatal(
+				"cscope: cannot read source file name from file %s\n", 
+			      reffile);
+		    /* NOTREACHED */
+		}
+		srcfiles[i] = strdup(path);
+	    }
+	}
+	fclose(oldrefs);
+    } else {
+	/* save the file arguments */
+	fileargc = argc;
+	fileargv = argv;
+	
+	/* get source directories from the environment */
+	if ((s = getenv("SOURCEDIRS")) != NULL) {
+	    sourcedir(s);
+	}
+	/* make the source file list */
+	srcfiles = malloc(msrcfiles * sizeof(*srcfiles));
+	makefilelist();
+	if (nsrcfiles == 0) {
+	    postfatal("cscope: no source files found\n");
+	    /* NOTREACHED */
+	}
+	/* get include directories from the environment */
+	if ((s = getenv("INCLUDEDIRS")) != NULL) {
+	    includedir(s);
+	}
+	/* add /usr/include to the #include directory list,
+	   but not in kernelmode... kernels tend not to use it. */
+	if (kernelmode == NO) {
+	    if (NULL != (s = getenv("INCDIR"))) {
+		includedir(s);
+	    } else {
+		includedir(DFLT_INCDIR);
+	    }
+	}
+
+	/* initialize the C keyword table */
+	initsymtab();
+
+	/* Tell build.c about the filenames to create: */
+	setup_build_filenames(reffile);
+
+	/* build the cross-reference */
+	initcompress();
+	if (linemode == NO || verbosemode == YES)    /* display if verbose as well */
+	    postmsg("Building cross-reference...");    		    
+	build();
+	if (linemode == NO )
+	    clearmsg();	/* clear any build progress message */
+	if (buildonly == YES) {
+	    myexit(0);
+	}
+    }
+    opendatabase();
+
+    /* if using the line oriented user interface so cscope can be a 
+       subprocess to emacs or samuel */
+    if (linemode == YES) {
+	if (*Pattern != '\0') {		/* do any optional search */
+	    if (search() == YES) {
+		/* print the total number of lines in
+		 * verbose mode */
+		if (verbosemode == YES)
+		    printf("cscope: %d lines\n",
+			   totallines);
+
+		while ((c = getc(refsfound)) != EOF)
+		    putchar(c);
+	    }
+	}
+	if (onesearch == YES)
+	    myexit(0);
+		
+	for (;;) {
+	    char buf[PATLEN + 2];
+			
+	    printf(">> ");
+	    fflush(stdout);
+	    if (fgets(buf, sizeof(buf), stdin) == NULL) {
+		myexit(0);
+	    }
+	    /* remove any trailing newline character */
+	    if (*(s = buf + strlen(buf) - 1) == '\n') {
+		*s = '\0';
+	    }
+	    switch (*buf) {
+	    case '0':
+	    case '1':
+	    case '2':
+	    case '3':
+	    case '4':
+	    case '5':
+	    case '6':
+	    case '7':
+	    case '8':
+	    case '9':	/* samuel only */
+		field = *buf - '0';
+		strcpy(Pattern, buf + 1);
+		if (search() == NO) {
+			printf("Unable to search database\n");
+		} else {
+			printf("cscope: %d lines\n", totallines);
+			while ((c = getc(refsfound)) != EOF) {
+			    putchar(c);
+			}
+		}
+		break;
+
+	    case 'c':	/* toggle caseless mode */
+	    case ctrl('C'):
+		if (caseless == NO) {
+		    caseless = YES;
+		} else {
+		    caseless = NO;
+		}
+		egrepcaseless(caseless);
+		break;
+
+	    case 'r':	/* rebuild database cscope style */
+	    case ctrl('R'):
+		freefilelist();
+		makefilelist();
+		/* FALLTHROUGH */
+
+	    case 'R':	/* rebuild database samuel style */
+		rebuild();
+		putchar('\n');
+		break;
+
+	    case 'C':	/* clear file names */
+		freefilelist();
+		putchar('\n');
+		break;
+
+	    case 'F':	/* add a file name */
+		strcpy(path, buf + 1);
+		if (infilelist(path) == NO &&
+		    (s = inviewpath(path)) != NULL) {
+		    addsrcfile(s);
+		}
+		putchar('\n');
+		break;
+
+	    case 'q':	/* quit */
+	    case ctrl('D'):
+	    case ctrl('Z'):
+		myexit(0);
+
+	    default:
+		fprintf(stderr, "cscope: unknown command '%s'\n", buf);
+		break;
+	    }
+	}
+	/* NOTREACHED */
+    }
+    /* pause before clearing the screen if there have been error messages */
+    if (errorsfound == YES) {
+	errorsfound = NO;
+	askforreturn();
+    }
+    /* do any optional search */
+    if (*Pattern != '\0') {
+	atfield();		/* move to the input field */
+	command(ctrl('Y'));	/* search */
+    } else if (reflines != NULL) {
+	/* read any symbol reference lines file */
+	readrefs(reflines);
+    }
+    display();		/* update the display */
+
+    for (;;) {
+		c = mygetch();
+
+		/* exit if the quit command is entered */
+		if (c == EOF || c == ctrl('D')) {
+			break;
+		}
+		if (c == ctrl('Z')) {
+			kill(0, SIGTSTP);
+			continue;
+		}
+
+		command(c);
+		display();
+    }
+    /* cleanup and exit */
+    myexit(0);
+    /* NOTREACHED */
+    return 0;		/* avoid warning... */
+}
+
+void
+cannotopen(char *file)
+{
+    posterr("Cannot open file %s", file);
+}
+
+/* FIXME MTE - should use postfatal here */
+void
+cannotwrite(char *file)
+{
+    char	msg[MSGLEN + 1];
+
+    snprintf(msg, sizeof(msg), "Removed file %s because write failed", file);
+
+    myperror(msg);	/* display the reason */
+
+    unlink(file);
+    myexit(1);	/* calls exit(2), which closes files */
+}
+
+
+/* set up the digraph character tables for text compression */
+static void
+initcompress(void)
+{
+    int	i;
+	
+    if (compress == YES) {
+	for (i = 0; i < 16; ++i) {
+	    dicode1[(unsigned char) (dichar1[i])] = i * 8 + 1;
+	}
+	for (i = 0; i < 8; ++i) {
+	    dicode2[(unsigned char) (dichar2[i])] = i + 1;
+	}
+    }
+}
+
+/* skip the list in the cross-reference file */
+
+static void
+skiplist(FILE *oldrefs)
+{
+    int	i;
+	
+    if (fscanf(oldrefs, "%d", &i) != 1) {
+	postfatal("cscope: cannot read list size from file %s\n", reffile);
+	/* NOTREACHED */
+    }
+    while (--i >= 0) {
+	if (fscanf(oldrefs, "%*s") != 0) {
+	    postfatal("cscope: cannot read list name from file %s\n", reffile);
+	    /* NOTREACHED */
+	}
+    }
+}
+
+
+/* enter curses mode */
+void
+entercurses(void)
+{
+    incurses = YES;
+#ifndef __MSDOS__ /* HBB 20010313 */
+    nonl();		    /* don't translate an output \n to \n\r */
+#endif
+    raw();			/* single character input */
+    noecho();			/* don't echo input characters */
+    clear();			/* clear the screen */
+    mouseinit();		/* initialize any mouse interface */
+    drawscrollbar(topline, nextline);
+}
+
+
+/* exit curses mode */
+void
+exitcurses(void)
+{
+	/* clear the bottom line */
+	move(LINES - 1, 0);
+	clrtoeol();
+	refresh();
+
+	/* exit curses and restore the terminal modes */
+	endwin();
+	incurses = NO;
+
+	/* restore the mouse */
+	mousecleanup();
+	fflush(stdout);
+}
+
+/* cleanup and exit */
+void
+myexit(int sig)
+{
+	/* HBB 20010313; close file before unlinking it. Unix may not care
+	 * about that, but DOS absolutely needs it */
+	if (refsfound != NULL)
+		fclose(refsfound);
+	
+	/* remove any temporary files */
+	if (temp1[0] != '\0') {
+		unlink(temp1);
+		unlink(temp2);
+		rmdir(tempdirpv);		
+	}
+	/* restore the terminal to its original mode */
+	if (incurses == YES) {
+		exitcurses();
+	}
+	/* dump core for debugging on the quit signal */
+	if (sig == SIGQUIT) {
+		abort();
+	}
+	/* HBB 20000421: be nice: free allocated data */
+	freefilelist();
+	freeinclist();
+	freesrclist();
+	freecrossref();
+	free_newbuildfiles();
+
+	if( remove_symfile_onexit == YES ) {
+		unlink( reffile );
+		unlink( invname );
+		unlink( invpost );
+	}
+
+	exit(sig);
+}
+
+static inline void readenv(void){
+    editor = mygetenv("EDITOR", EDITOR);
+    editor = mygetenv("VIEWER", editor); /* use viewer if set */
+    editor = mygetenv("CSCOPE_EDITOR", editor);	/* has last word */
+    home = mygetenv("HOME", HOME);
+    shell = mygetenv("SHELL", SHELL);
+    lineflag = mygetenv("CSCOPE_LINEFLAG", LINEFLAG);
+    lineflagafterfile = getenv("CSCOPE_LINEFLAG_AFTER_FILE") ? 1 : 0;
+    tmpdir = mygetenv("TMPDIR", TMPDIR);
+}
diff --git a/src/mouse.c b/src/mouse.c
new file mode 100644
index 0000000..ea75b37
--- /dev/null
+++ b/src/mouse.c
@@ -0,0 +1,431 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	mouse functions
+ */
+
+#include "global.h"
+
+BOOL	mouse = NO;			/* mouse interface */
+
+#ifdef UNIXPC	/* build command requires #ifdef instead of #if */
+#include <sys/window.h>
+BOOL	unixpcmouse = NO;	/* running with a mouse on the Unix PC? */
+static int uw_hs, uw_vs;	/* character height and width */
+#endif
+
+typedef	struct {			/* menu */
+	char	*text;
+	char	*value;
+} MENU;
+
+static	MENU	mainmenu[] = {		/* main menu */
+	{"Send",	"##\033s##\r"},
+	{"Repeat",	"\031"},
+	{"Edit All",	"\05"},
+	{"Rebuild",	"\022"},
+	{"Shell",	"!"},
+	{"Redraw",	"\f"},
+	{"Help",	"?"},
+	{"Exit",	"\04"},
+	{NULL,		NULL}
+};
+
+static	MENU	changemenu[] = {	/* change mode menu */
+	{"Mark Screen",	"*"},
+	{"Mark All",	"a"},
+	{"Change",	"\04"},
+	{"No Change",	"\033"},
+	{"Shell",	"!"},
+	{"Redraw",	"\f"},
+	{"Help",	"?"},
+	{NULL,		NULL}
+};
+
+static	MENU	*loaded;		/* menu loaded */
+static	BOOL	emacsviterm = NO;	/* terminal type */
+
+static	void	loadmenu(MENU *menu);
+static	int	getcoordinate(void);
+static	int	getpercent(void);
+
+/* see if there is a mouse interface */
+
+void
+mouseinit(void)
+{
+	char	*term;
+
+	/* see if this is emacsterm or viterm */
+	term = mygetenv("TERM", "");
+	if (strcmp(term, "emacsterm") == 0 || 
+	    strcmp(term, "viterm") == 0) {
+		emacsviterm = YES;
+		mouse = YES;
+	}
+	/* the MOUSE enviroment variable is for 5620 terminal programs that have
+	   mouse support but the TERM environment variable is the same as a
+	   terminal without a mouse, such as myx */
+	else if (strcmp(mygetenv("MOUSE", ""), "myx") == 0) {
+		mouse = YES;
+	}
+#if UNIXPC
+	else if (strcmp(term,"s4") == 0 || 
+	         strcmp(term,"s120") == 0 ||
+	         strcmp(term,"s90") == 0) {
+		int retval;
+		struct uwdata uwd;	/* Window data structure */
+		struct umdata umd;	/* Mouse data structure */
+
+		/* Ask for character size info */
+			
+		retval = ioctl(1,WIOCGETD,&uwd);
+		if(retval || uwd.uw_hs <= 0 || uwd.uw_vs <= 0) {
+			/**************************************************
+			 * something wrong with the kernel, so fake it... 
+			 **************************************************/
+			if(!strcmp(term,"s4")) {
+				uw_hs = 9;
+				uw_vs = 12;
+			}
+			else {
+				uw_hs = 6;
+				uw_vs = 10;
+			}
+		}
+		else {
+			/* Kernel is working and knows about this font */
+			uw_hs = uwd.uw_hs;
+			uw_vs = uwd.uw_vs;
+		}
+		
+		/**************************************************
+		 * Now turn on mouse reporting so we can actually
+		 * make use of all this stuff.
+		 **************************************************/
+		if((retval = ioctl(1,WIOCGETMOUSE,&umd)) != -1) {
+			umd.um_flags= MSDOWN+MSUP;
+			ioctl(1,WIOCSETMOUSE,&umd);
+		}
+		unixpcmouse = YES;
+	}
+#endif
+	if (mouse == YES) {
+		loadmenu(mainmenu);
+	}
+}
+
+/* load the correct mouse menu */
+
+void
+mousemenu(void)
+{
+	if (mouse == YES) {
+		if (changing == YES) {
+			loadmenu(changemenu);
+		}
+		else {
+			loadmenu(mainmenu);
+		}
+	}
+}
+
+/* download a menu */
+
+static void
+loadmenu(MENU *menu)
+{
+	int	i;
+
+	if (emacsviterm == YES) {
+		mousereinit();
+		(void) printf("\033V1");	/* display the scrollbar */
+		(void) printf("\033M0@%s@%s@", menu[0].text, menu[0].value);
+		for (i = 1; menu[i].text != NULL; ++i) {
+			(void) printf("\033M@%s@%s@", menu[i].text, menu[i].value);
+		}
+	}
+	else {	/* myx */
+		int	len;
+		
+		mousecleanup();
+		(void) printf("\033[6;1X\033[9;1X");
+		for (i = 0; menu[i].text != NULL; ++i) {
+			len = strlen(menu[i].text);
+			(void) printf("\033[%d;%dx%s%s", len,
+				      (int) (len + strlen(menu[i].value)), 
+				      menu[i].text, menu[i].value);
+		}
+		loaded = menu;
+	}
+	(void) fflush(stdout);
+}
+
+/* reinitialize the mouse in case curses changed the attributes */
+
+void
+mousereinit(void)
+{
+	if (emacsviterm == YES) {
+
+		/* enable the mouse click and sweep coordinate control sequence */
+		/* and switch to menu 2 */
+		(void) printf("\033{2\033#2");
+		(void) fflush(stdout);
+	}
+}
+
+/* restore the mouse attributes */
+
+void
+mousecleanup(void)
+{
+	int	i;
+
+	if (loaded != NULL) {	/* only true for myx */
+		
+		/* remove the mouse menu */
+		(void) printf("\033[6;0X\033[9;0X");
+		for (i = 0; loaded[i].text != NULL; ++i) {
+			(void) printf("\033[0;0x");
+		}
+		loaded = NULL;
+	}
+}
+
+/* draw the scrollbar */
+
+void
+drawscrollbar(int top, int bot)
+{
+	int p1, p2;
+
+	if (emacsviterm == YES) {
+		if (bot > top) {
+			p1 = 16 + (top - 1) * 100 / totallines;
+			p2 = 16 + (bot - 1) * 100 / totallines;
+			if (p2 > 116) {
+				p2 = 116;
+			}
+			if (p1 < 16) {
+				p1 = 16;
+			}
+			/* don't send ^S or ^Q because it will hang a layer using cu(1) */
+			if (p1 == ctrl('Q') || p1 == ctrl('S')) {
+				++p1;
+			}
+			if (p2 == ctrl('Q') || p2 == ctrl('S')) {
+				++p2;
+			}
+		}
+		else {
+			p1 = p2 = 16;
+		}
+		(void) printf("\033W%c%c", p1, p2);
+	}
+}
+
+/* get the mouse information */
+
+MOUSE *
+getmouseaction(char leading_char)
+{
+	static	MOUSE	m;
+
+#if UNIXPC
+
+	if(unixpcmouse == YES && leading_char == ESC) {
+
+		/* Called if cscope received an ESC character.  See if it is
+		 * a mouse report and if so, decipher it.  A mouse report
+		 * looks like: "<ESC>[?xx;yy;b;rM"
+		 */
+		int x = 0, y = 0, button = 0, reason = 0;
+		int i;
+	
+		/* Get a mouse report.  The form is: XX;YY;B;RM where
+		 * XX is 1,2, or 3 decimal digits with the X pixel position.
+		 * Similarly for YY.  B is a single decimal digit with the
+		 * button number (4 for one, 2 for two, and 1 for three).
+		 * R is the reason for the mouse report.
+		 *
+		 * In general, the input is read until the mouse report has
+		 * been completely read in or we have discovered that this
+		 * escape sequence is NOT a mouse report.  In the latter case
+		 * return the last character read to the input stream with
+		 * myungetch().
+		 */
+		
+		/* Check for "[?" being next 2 chars */
+		if(((i = mygetch()) != '[') || ((i = mygetch()) != '?')) {
+			myungetch(i);
+			return(NULL);
+		}
+	
+		/* Grab the X position (in pixels) */
+		while(isdigit(i = mygetch())) {
+			x = (x*10) + (i - '0');
+		}
+		if(i != ';') {
+			myungetch(i);
+			return(NULL);	/* not a mouse report after all */
+		}
+	
+		/* Grab the Y position (in pixels) */
+		while(isdigit(i = mygetch())) {
+			y = (y*10) + (i - '0');
+		}
+		if(i != ';') {
+			myungetch(i);
+			return(NULL);
+		}
+	
+		/* Get which button */
+		if((button = mygetch()) > '4') {
+			myungetch(button);
+			return(NULL);
+		}
+		if((i = mygetch()) != ';') {
+			myungetch(i);
+			return(NULL);
+		}
+		
+		/* Get the reason for this mouse report */
+		if((reason = mygetch()) > '8') {
+			myungetch(reason);
+			return(NULL);
+		}
+		
+		/* sequence should terminate with an 'M' */
+		if((i = mygetch()) != 'M') {
+			myungetch(i);
+			return(NULL);
+		}
+	
+	
+		/* OK.  We get a mouse report whenever a button is depressed
+		 * or released.  Let's ignore the report whenever the button
+		 * is depressed until when I am ready to implement sweeping.
+		 */
+		if(reason != '2') {
+			return(NULL);	/* '2' means button is released */
+		}
+	
+		/************************************************************
+		 * Always indicate button 1 irregardless of which button was
+		 * really pushed.
+		 ************************************************************/
+		m.button = 1;
+	
+		/************************************************************
+		 * Convert pixel coordinates to line and column coords.
+		 * The height and width are obtained using an ioctl() call
+		 * in mouseinit().  This assumes that variable width chars
+		 * are not being used ('though it would probably work anyway).
+		 ************************************************************/
+		
+		m.x1 = x/uw_hs;	/* pixel/horizontal_spacing */
+		m.y1 = y/uw_vs;	/* pixel/vertical_spacing   */
+	
+		/* "null" out the other fields */
+		m.percent = m.x2 = m.y2 = -1;
+	}
+	else
+#endif	/* not UNIXPC */
+
+	if (mouse == YES && leading_char == ctrl('X')) {
+	
+		switch (mygetch()) {
+		case ctrl('_'):		/* click */
+			if ((m.button = mygetch()) == '0') {	/* if scrollbar */
+				m.percent = getpercent();
+			}
+			else {
+				m.x1 = getcoordinate();
+				m.y1 = getcoordinate();
+				m.x2 = m.y2 = -1;
+			}
+			break;
+	
+		case ctrl(']'):		/* sweep */
+			m.button = mygetch();
+			m.x1 = getcoordinate();
+			m.y1 = getcoordinate();
+			m.x2 = getcoordinate();
+			m.y2 = getcoordinate();
+			break;
+		default:
+			return(NULL);
+		}
+	}
+	else return(NULL);
+
+	return(&m);
+}
+
+/* get a row or column coordinate from a mouse button click or sweep */
+
+static int
+getcoordinate(void)
+{
+	int  c, next;
+
+	c = mygetch();
+	next = 0;
+	if (c == ctrl('A')) {
+		next = 95;
+		c = mygetch();
+	}
+	if (c < ' ') {
+		return (0);
+	}
+	return (next + c - ' ');
+}
+
+/* get a percentage */
+
+static int
+getpercent(void)
+{
+	int c;
+
+	c = mygetch();
+	if (c < 16) {
+		return(0);
+	}
+	if (c > 120) {
+		return(100);
+	}
+	return(c - 16);
+}
diff --git a/src/mygetenv.c b/src/mygetenv.c
new file mode 100644
index 0000000..0a6f53b
--- /dev/null
+++ b/src/mygetenv.c
@@ -0,0 +1,49 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+#include "library.h"
+
+#include <stdlib.h>
+
+/* return the non-null environment value or the default argument */
+
+char	*
+mygetenv(char *variable, char *deflt)
+{
+	char	*value;
+
+	value = getenv(variable);
+	if (value == NULL || *value == '\0') {
+		return(deflt);
+	}
+	return(value);
+}
diff --git a/src/mypopen.c b/src/mypopen.c
new file mode 100644
index 0000000..24e55d5
--- /dev/null
+++ b/src/mypopen.c
@@ -0,0 +1,208 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "global.h"	/* pid_t, shell, and basename() */
+
+#define	tst(a,b) (*mode == 'r'? (b) : (a))
+#define	RDR	0
+#define	WTR	1
+
+/* HBB 20010312: make this a bit safer --- don't blindly assume it's 1 */
+#ifdef FD_CLOEXEC
+# define CLOSE_ON_EXEC FD_CLOEXEC
+#else
+# define CLOSE_ON_EXEC 1
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>		/* for setmode() */
+#endif
+
+static pid_t popen_pid[20];
+static void (*tstat)(int);
+
+int
+myopen(char *path, int flag, int mode)
+{
+    /* opens a file descriptor and then sets close-on-exec for the file */
+    int fd;
+
+    /* 20020103: if file is not explicitly in Binary mode, make
+     * sure we override silly Cygwin behaviour of automatic binary
+     * mode for files in "binary mounted" paths */
+#if O_BINARY != O_TEXT
+    if (! (flag | O_BINARY))
+	flag |= O_TEXT;
+#endif
+    if(mode)
+	fd = open(path, flag, mode);
+    else
+	fd = open(path, flag);
+
+#ifdef __DJGPP__		/* FIXME: test feature, not platform */
+    /* HBB 20010312: DOS GCC doesn't have FD_CLOEXEC (yet), so it 
+     * always fails this call. Have to skip that step */
+    if(fd != -1)
+	return(fd);
+#endif
+    if(fd != -1 && (fcntl(fd, F_SETFD, CLOSE_ON_EXEC) != -1))
+	return(fd);
+
+    else
+	{
+	    /* Ensure that if the fcntl fails and fd is valid, then
+	       the file is closed properly. In general this should
+	       not happen. */
+	    if (fd != -1)
+		{
+		    close (fd);
+		}
+
+	    return(-1);
+	}
+}
+
+FILE *
+myfopen(char *path, char *mode)
+{
+    /* opens a file pointer and then sets close-on-exec for the file */
+    FILE *fp;
+
+    fp = fopen(path, mode);
+
+#ifdef SETMODE
+    if (fp && ! strchr(mode, 'b')) {
+	SETMODE(fileno(fp), O_TEXT);
+    }
+#endif /* SETMODE */
+	
+#ifdef __DJGPP__ /* FIXME: test feature, not platform */
+    /* HBB 20010312: DOS GCC doesn't have FD_CLOEXEC (yet), so it 
+     * always fails this call. Have to skip that step */
+    if(fp)
+#else
+	if(fp && (fcntl(fileno(fp), F_SETFD, CLOSE_ON_EXEC) != -1))
+#endif
+	    return(fp);
+
+	else {
+	    if (fp)
+		fclose(fp);
+	    return(NULL);
+	}
+}
+
+FILE *
+mypopen(char *cmd, char *mode)
+{
+#ifdef __DJGPP__
+	/* HBB 20010312: Has its own implementation of popen(), which
+	 * is better suited to the platform than cscope's */
+	return (popen)(cmd, mode);
+#else
+	int	p[2];
+	pid_t *poptr;
+	int myside, yourside;
+	pid_t pid;
+
+	if(pipe(p) < 0)
+		return(NULL);
+	myside = tst(p[WTR], p[RDR]);
+	yourside = tst(p[RDR], p[WTR]);
+	if((pid = fork()) == 0) {
+		/* myside and yourside reverse roles in child */
+		int	stdio;
+
+		/* close all pipes from other popen's */
+		for (poptr = popen_pid; poptr < popen_pid+20; poptr++) {
+			if(*poptr)
+				(void) close(poptr - popen_pid);
+		}
+		stdio = tst(0, 1);
+		close(myside);
+		close(stdio);
+#if V9
+		dup2(yourside, stdio);
+#else
+		fcntl(yourside, F_DUPFD, stdio);
+#endif
+		close(yourside);
+		execlp(shell, basename(shell), "-c", cmd, (void *)0);
+		_exit(1);
+	} else if (pid > 0)
+		tstat = signal(SIGTSTP, SIG_DFL);
+	if(pid == -1)
+		return(NULL);
+	popen_pid[myside] = pid;
+	(void) close(yourside);
+	return(fdopen(myside, mode));
+#endif /* DJGPP */
+}
+
+/* HBB 20010705: renamed from 'pclose', which would collide with
+ * system-supplied function of same name */
+int
+mypclose(FILE *ptr)
+{
+#ifdef __DJGPP__ 
+	/* HBB 20010705: This system has its own pclose(), which we
+	 * don't want to replace */
+	return (pclose)(ptr);
+#else
+	int f;
+	pid_t r;
+	int status = -1;
+	sighandler_t hstat, istat, qstat;
+
+	f = fileno(ptr);
+	(void) fclose(ptr);
+	istat = signal(SIGINT, SIG_IGN);
+	qstat = signal(SIGQUIT, SIG_IGN);
+	hstat = signal(SIGHUP, SIG_IGN);
+	while((r = wait(&status)) != popen_pid[f] && r != -1)
+		; /* nothing */
+	if(r == -1)
+		status = -1;
+	(void) signal(SIGINT, istat);
+	(void) signal(SIGQUIT, qstat);
+	(void) signal(SIGHUP, hstat);
+	(void) signal(SIGTSTP, tstat);
+	/* mark this pipe closed */
+	popen_pid[f] = 0;
+	return(status);
+#endif /* DJGPP */
+}
diff --git a/src/opt.c b/src/opt.c
new file mode 100644
index 0000000..58bee40
--- /dev/null
+++ b/src/opt.c
@@ -0,0 +1,159 @@
+#include "global.h"
+
+#include "build.h" 
+#include "vp.h"
+#include "version.h"	/* FILEVERSION and FIXVERSION */
+#include "scanner.h" 
+
+#include <stdlib.h>	/* atoi */
+#include <getopt.h>
+
+BOOL remove_symfile_onexit = NO;
+BOOL onesearch;		/* one search only in line mode */
+char *reflines;		/* symbol reference lines file */
+
+char ** parse_options(int *argc, char **argv)
+{
+	int opt;
+	int longind;
+	char path[PATHLEN + 1];     /* file path */
+	char *s;
+	int argcc = *argc;
+
+	struct option lopts[] = {
+		{"help", 0, NULL, 'h'},
+		{"version", 0, NULL, 'V'},
+		{0, 0, 0, 0}
+	};
+
+	while ((opt = getopt_long(argcc, argv,
+	       "hVbcCdeF:f:I:i:kLl0:1:2:3:4:5:6:7:8:9:P:p:qRs:TUuvX",
+	       lopts, &longind)) != -1) {
+		switch(opt) {
+
+		case '?':
+			usage();
+			myexit(1);
+			break;
+		case 'X':
+			remove_symfile_onexit = YES;
+			break;
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+			/* The input fields numbers for line mode operation */
+			field = opt - '0';
+			if (strlen(optarg) > PATHLEN) {
+				    postfatal("\
+					cscope: pattern too long, cannot be > \
+					%d characters\n", PATLEN);
+			}
+			strcpy(Pattern, optarg);	
+			break;
+		case 'b':	/* only build the cross-reference */
+			buildonly = YES;
+			linemode  = YES;
+			break;
+		case 'c':	/* ASCII characters only in crossref */
+			compress = NO;
+			break;
+		case 'C':	/* turn on caseless mode for symbol searches */
+			caseless = YES;
+			egrepcaseless(caseless); /* simulate egrep -i flag */
+			break;
+		case 'd':	/* consider crossref up-to-date */
+			isuptodate = YES;
+			break;
+		case 'e':	/* suppress ^E prompt between files */
+			editallprompt = NO;
+			break;
+		case 'h':
+			longusage();
+			myexit(1);
+			break;
+		case 'k':	/* ignore DFLT_INCDIR */
+			kernelmode = YES;
+			break;
+		case 'L':
+			onesearch = YES;
+			/* FALLTHROUGH */
+		case 'l':
+			linemode = YES;
+			break;
+		case 'v':
+			verbosemode = YES;
+			break;
+		case 'V':
+			fprintf(stderr, "%s: version %d%s\n", argv0,
+				FILEVERSION, FIXVERSION);
+			myexit(0);
+			break;
+		case 'q':	/* quick search */
+			invertedindex = YES;
+			break;
+		case 'T':	/* truncate symbols to 8 characters */
+			trun_syms = YES;
+			break;
+		case 'u':	/* unconditionally build the cross-reference */
+			unconditional = YES;
+			break;
+		case 'U':	/* assume some files have changed */
+			fileschanged = YES;
+			break;
+		case 'R':
+			recurse_dir = YES;
+			break;
+		case 'f':	/* alternate cross-reference file */
+			reffile = optarg;
+			if (strlen(reffile) > sizeof(path) - 3) {
+				postfatal("\
+					cscope: reffile too long, cannot \
+					be > %d characters\n", sizeof(path) - 3);
+				/* NOTREACHED */
+			}
+			strcpy(path, reffile);
+
+			s = path + strlen(path);
+			strcpy(s, ".in");
+			/*coverity[overwrite_var]*/
+			invname = strdup(path);
+			strcpy(s, ".po");
+			/*coverity[overwrite_var]*/
+			invpost = strdup(path);
+			break;
+
+		case 'F':	/* symbol reference lines file */
+			reflines = optarg;
+			break;
+		case 'i':	/* file containing file names */
+			namefile = optarg;
+			break;
+		case 'I':	/* #include file directory */
+			includedir(optarg);
+			break;
+		case 'p':	/* file path components to display */
+			dispcomponents = atoi(optarg);
+			break;
+		case 'P':	/* prepend path to file names */
+			prependpath = optarg;
+			break;
+		case 's':	/* additional source file directory */
+			sourcedir(optarg);
+			break;
+		}
+	}
+	/*
+ 	 * This adjusts argv so that we only see the remaining 
+ 	 * args.  Its ugly, but we need to do it so that the rest
+ 	 * of the main routine doesn't get all confused
+ 	 */
+	*argc = *argc - optind;
+	return argv + optind;
+}
diff --git a/src/scanner.h b/src/scanner.h
new file mode 100644
index 0000000..f387600
--- /dev/null
+++ b/src/scanner.h
@@ -0,0 +1,94 @@
+/*===========================================================================
+ Copyright (c) 2001, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE. 
+ =========================================================================*/
+
+#ifndef CSCOPE_SCANNER_H
+#define CSCOPE_SCANNER_H
+
+#include <stdio.h>
+
+#undef	YYLMAX		
+#define YYLMAX	STMTMAX + PATLEN + 1	/* scanner line buffer size */
+
+/* cross-reference database mark characters (when new ones are added, 
+ * update the cscope.out format description in cscope.1)
+ */
+#define CLASSDEF	'c'
+#define	DEFINE		'#'
+#define	DEFINEEND	')'
+#define ENUMDEF		'e'
+#define FCNCALL		'`'
+#define FCNDEF		'$'
+#define FCNEND		'}'
+#define GLOBALDEF	'g'
+#define	INCLUDE		'~'
+#define MEMBERDEF	'm'
+#define NEWFILE		'@'
+#define STRUCTDEF	's'
+#define TYPEDEF		't'
+#define UNIONDEF	'u'
+
+/* other scanner token types */
+#define	LEXEOF	0
+#define	LEXERR	1
+#define	IDENT	2	
+#define	NEWLINE	3	
+
+/* scanner.l global data */
+extern	int	first;		/* buffer index for first char of symbol */
+extern	int	last;		/* buffer index for last char of symbol */
+extern	int	lineno;		/* symbol line number */
+extern	FILE	*yyin;		/* input file descriptor */
+extern	FILE	*yyout;		/* output file */
+extern	int	myylineno;	/* input line number */
+
+#ifdef USING_LEX
+/* HBB 20010430: if lex is used instead of flex, have to simulate the
+ * private copies of yytext and yytext for the world outside scanner.l: */
+/* FIXME: there should be a feature test for this! */
+#if defined(__OSF1__) || defined(__sun) || defined(_AIX)
+extern	char	yytext[];
+#else
+extern	unsigned char	yytext[];
+#endif
+extern	int	yyleng;
+# define my_yytext yytext
+# define my_yyleng yyleng
+#else
+extern	char	*my_yytext;	/* private copy of input line */
+extern	size_t	my_yyleng;	/* ... and current length of it */
+#endif
+
+/* The master function exported by scanner.l */
+int 	yylex(void);
+void	initscanner(char *srcfile);
+
+#endif /* CSCOPE_SCANNER_H ends */
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000..6f8b33e
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,45 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*	cscope - interactive C symbol cross-reference
+ *
+ *	Changing the cross-reference file part of the program version
+ *	forces rebuilding of the cross-reference.
+ */
+
+#ifndef CSCOPE_VERSION_H
+#define CSCOPE_VERSION_H
+
+#define	FILEVERSION	15	/* Initial Open Source and Linux Port */
+#define	FIXVERSION	".9"	/* feature and bug fix version */
+
+#endif /* CSCOPE_VERSION_H */
diff --git a/src/vp.h b/src/vp.h
new file mode 100644
index 0000000..e5aa4ef
--- /dev/null
+++ b/src/vp.h
@@ -0,0 +1,70 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/*
+ *	VPATH assumptions:
+ *		VPATH is the environment variable containing the view path 
+ *		where each path name is followed by ':', '\n', or '\0'.
+ *		Embedded blanks are considered part of the path.
+ */
+
+#ifndef CSCOPE_VP_H
+#define CSCOPE_VP_H
+
+#define MAXPATH	200		/* max length for entire name */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+# define HAVE_FCNTL_H 1		/* in case of doubt, assume it's there */
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>		/* needed for O_... open flags */
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if !NOMALLOC
+extern	char	**vpdirs;	/* directories (including current) in view path */
+#else
+#define	MAXDIR	25		/* same as libVP */
+#define	DIRLEN	80		/* same as libVP */
+extern	char	vpdirs[MAXDIR][DIRLEN + 1];
+#endif
+extern	int	vpndirs;	/* number of directories in view path */
+
+void	vpinit(char *current_dir);
+int	vpopen(char *path, int oflag);
+int	vpaccess(char *path, mode_t amode);
+
+#endif /* CSCOPE_VP_H */
diff --git a/src/vpaccess.c b/src/vpaccess.c
new file mode 100644
index 0000000..d8c8be7
--- /dev/null
+++ b/src/vpaccess.c
@@ -0,0 +1,57 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/* vpaccess - view path version of the access system call */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "vp.h"
+#include <sys/types.h>
+ 
+int
+vpaccess(char *path, mode_t amode)
+{
+	char	buf[MAXPATH + 1];
+	int	returncode;
+	int	i;
+
+	if ((returncode = access(path, amode)) == -1 && path[0] != '/') {
+		vpinit(NULL);
+		for (i = 1; i < vpndirs; i++) {
+			(void) snprintf(buf, sizeof(buf), "%s/%s", vpdirs[i], path);
+			if ((returncode = access(buf, amode)) != -1) {
+				break;
+			}
+		}
+	}
+	return(returncode);
+}
diff --git a/src/vpfopen.c b/src/vpfopen.c
new file mode 100644
index 0000000..b236864
--- /dev/null
+++ b/src/vpfopen.c
@@ -0,0 +1,62 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/* vpfopen - view path version of the fopen library function */
+
+#include <stdio.h>
+#include <string.h>
+#include "vp.h"
+#include "global.h"
+
+FILE *
+vpfopen(char *filename, char *type)
+{
+	char	buf[MAXPATH + 1];
+	FILE	*returncode;
+	int	i;
+
+	if ((returncode = myfopen(filename, type)) == NULL 
+		&& filename[0] != '/' 
+		/* && strcmp(type, "r") == 0 */ /* HBB: this breaks if type=="rb" */
+		&& type[0] == 'r'
+		) {
+		vpinit(NULL);
+		for (i = 1; i < vpndirs; i++) {
+			(void) snprintf(buf, sizeof(buf), "%s/%s", vpdirs[i], filename);
+			if ((returncode = myfopen(buf, type)) != NULL) {
+				break;
+			}
+
+		}
+	}
+	return(returncode);
+}
diff --git a/src/vpinit.c b/src/vpinit.c
new file mode 100644
index 0000000..9535f8a
--- /dev/null
+++ b/src/vpinit.c
@@ -0,0 +1,169 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+/* vpinit - initialize vpdirs or update vpdirs based on currentdir */
+
+#include <stdio.h>	/* stderr */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "vp.h"
+
+#include "library.h"
+#include "global.h"
+#include "constants.h"
+
+#if !NOMALLOC
+char	**vpdirs;	/* directories (including current) in view path */
+#else
+char	vpdirs[MAXDIR][DIRLEN + 1];
+#define	MAXVPATH (MAXDIR * (DIRLEN + 1))
+#endif
+int	vpndirs;	/* number of directories in view path */
+
+void
+vpinit(char *current_dir)
+{
+	char	*suffix;	/* path from view path node */
+	char	*vpath;		/* VPATH environment variable value */
+	char	buf[MAXPATH + 1];
+	int	i;
+	char	*s;
+#if NOMALLOC
+	char	*node;		/* view path node */
+	char	vpathbuf[MAXVPATH + 1];
+#endif
+	
+	/* if an existing directory list is to be updated, free it */
+	if (current_dir != NULL && vpndirs > 0) {
+#if !NOMALLOC
+		for (i = 0; i < vpndirs; ++i) {
+			free(vpdirs[i]);
+		}
+		free(vpdirs);
+#endif
+		vpndirs = 0;
+	}
+	/* return if the directory list has been computed */
+	/* or there isn't a view path environment variable */
+	if (vpndirs > 0 || (vpath = getenv("VPATH")) == NULL ||
+	    *vpath == '\0') {
+		return;
+	}
+	/* if not given, get the current directory name */
+	if (current_dir == NULL && (current_dir = getcwd(buf, MAXPATH)) == NULL) {
+		(void) fprintf(stderr, "%s: cannot get current directory name\n", argv0);
+		return;
+	}
+	/* see if this directory is in the first view path node */
+	for (i = 0; vpath[i] == current_dir[i] && vpath[i] != '\0'; ++i) {
+		;
+	}
+	if ((vpath[i] != ':' && vpath[i] != '\0') ||
+	    (current_dir[i] != '/' && current_dir[i] != '\0')) {
+		return;
+	}
+	suffix = &current_dir[i];
+#if !NOMALLOC
+
+	/* count the nodes in the view path */
+	vpndirs = 1;
+	for (i = 0; vpath[i] != '\0'; ++i) {
+		if (vpath[i] == ':' && vpath[i + 1]) {
+			++vpndirs;
+		}
+	}
+	/* create the source directory list */
+	vpdirs = malloc(vpndirs * sizeof(*vpdirs));
+
+	/* don't change VPATH in the environment */
+	vpath = strdup(vpath);
+	
+	/* split the view path into nodes */
+	for (i = 0, s = vpath; *s != '\0'; ++i) {
+		vpdirs[i] = s;
+		while (*s != '\0' && *++s != ':') {
+			if (*s == '\n') {
+				*s = '\0';
+			}
+		}
+		if (*s != '\0') {
+			*s++ = '\0';
+		}
+	}
+	/* convert the view path nodes to directories */
+	for (i = 0; i < vpndirs; ++i) {
+		s = malloc(strlen(vpdirs[i]) + strlen(suffix) + 1);
+		(void) strcpy(s, vpdirs[i]);
+		(void) strcat(s, suffix);
+		vpdirs[i] = s;
+	}
+	free(vpath);
+#else
+	/* don't change VPATH in the environment */
+	if (strlen(vpath) > MAXVPATH) {
+		(void) fprintf(stderr, "%s: VPATH is longer than %d characters: %s\n", argv0, MAXVPATH, vpath);
+		return;
+	}
+	(void) strcpy(vpathbuf, vpath);
+	s = vpathbuf;
+	
+	/* convert the view path nodes to directories */
+	while (*s != '\0') {
+		
+		/* get the next node */
+		node = s;
+		while (*s != '\0' && *++s != ':') {
+			if (*s == '\n') {
+				*s = '\0';
+			}
+		}
+		if (*s != '\0') {
+			*s++ = '\0';
+		}
+		/* ignore a directory that is too long */
+		if (strlen(node) + strlen(suffix) > DIRLEN) {
+			(void) fprintf(stderr, "%s: VPATH directory is longer than %d characters: %s%s\n", argv0, DIRLEN, node, suffix);
+		}
+		else if (vpndirs >= MAXDIR) {
+			(void) fprintf(stderr, "%s: VPATH has more than %d nodes\n", argv0, vpndirs);
+			return;
+		}
+		else {
+			/* create the view path directory */
+			(void) strcpy(vpdirs[vpndirs], node);
+			(void) strcat(vpdirs[vpndirs], suffix);
+			++vpndirs;
+		}
+	}
+#endif
+}
diff --git a/src/vpopen.c b/src/vpopen.c
new file mode 100644
index 0000000..8eac788
--- /dev/null
+++ b/src/vpopen.c
@@ -0,0 +1,60 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation 
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation 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 COPYRIGHT HOLDERS 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. 
+ =========================================================================*/
+
+
+/* vpopen - view path version of the open system call */
+
+#include <stdio.h>
+#include "global.h"
+#include "vp.h"
+
+#define OPENFLAG_READ	0
+
+int
+vpopen(char *path, int oflag)
+{
+	char	buf[MAXPATH + 1];
+	int	returncode;
+	int	i;
+
+	if ((returncode = myopen(path, oflag, 0666)) == -1 && path[0] != '/' &&
+	    oflag == OPENFLAG_READ) {
+		vpinit(NULL);
+		for (i = 1; i < vpndirs; i++) {
+			(void) snprintf(buf, sizeof(buf), "%s/%s", vpdirs[i], path);
+			if ((returncode = myopen(buf, oflag, 0666)) != -1) {
+				break;
+			}
+		}
+	}
+	return(returncode);
+}