From b37e0da0b7dc72ddfa513e319ca71b5f5b8aeb7d Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 13 Nov 2006 22:13:33 +0100 Subject: Initial import --- contrib/Makefile.am | 6 + contrib/Makefile.in | 328 ++++ contrib/README | 11 + contrib/ocs | 308 ++++ contrib/webcscope/CVS/Entries | 7 + contrib/webcscope/CVS/Repository | 1 + contrib/webcscope/CVS/Root | 1 + contrib/webcscope/INSTALL | 31 + contrib/webcscope/LICENSE | 340 +++++ contrib/webcscope/TODO | 5 + contrib/webcscope/cgi-lib.pl | 471 ++++++ contrib/webcscope/cscope | 446 ++++++ contrib/webcscope/hilite.c | 360 +++++ contrib/webcscope/icons/CVS/Entries | 10 + contrib/webcscope/icons/CVS/Repository | 1 + contrib/webcscope/icons/CVS/Root | 1 + contrib/webcscope/icons/back.gif | Bin 0 -> 216 bytes contrib/webcscope/icons/bomb.gif | Bin 0 -> 308 bytes contrib/webcscope/icons/c.gif | Bin 0 -> 242 bytes contrib/webcscope/icons/down.gif | Bin 0 -> 163 bytes contrib/webcscope/icons/folder.gif | Bin 0 -> 225 bytes contrib/webcscope/icons/folder.open.gif | Bin 0 -> 242 bytes contrib/webcscope/icons/left.gif | Bin 0 -> 172 bytes contrib/webcscope/icons/up.gif | Bin 0 -> 164 bytes contrib/webcscope/icons/world2.gif | Bin 0 -> 261 bytes contrib/xcscope/CVS/Entries | 3 + contrib/xcscope/CVS/Repository | 1 + contrib/xcscope/CVS/Root | 1 + contrib/xcscope/cscope-indexer | 166 +++ contrib/xcscope/xcscope.el | 2463 +++++++++++++++++++++++++++++++ 30 files changed, 4961 insertions(+) create mode 100644 contrib/Makefile.am create mode 100644 contrib/Makefile.in create mode 100644 contrib/README create mode 100755 contrib/ocs create mode 100644 contrib/webcscope/CVS/Entries create mode 100644 contrib/webcscope/CVS/Repository create mode 100644 contrib/webcscope/CVS/Root create mode 100644 contrib/webcscope/INSTALL create mode 100644 contrib/webcscope/LICENSE create mode 100644 contrib/webcscope/TODO create mode 100644 contrib/webcscope/cgi-lib.pl create mode 100755 contrib/webcscope/cscope create mode 100644 contrib/webcscope/hilite.c create mode 100644 contrib/webcscope/icons/CVS/Entries create mode 100644 contrib/webcscope/icons/CVS/Repository create mode 100644 contrib/webcscope/icons/CVS/Root create mode 100644 contrib/webcscope/icons/back.gif create mode 100644 contrib/webcscope/icons/bomb.gif create mode 100644 contrib/webcscope/icons/c.gif create mode 100644 contrib/webcscope/icons/down.gif create mode 100644 contrib/webcscope/icons/folder.gif create mode 100644 contrib/webcscope/icons/folder.open.gif create mode 100644 contrib/webcscope/icons/left.gif create mode 100644 contrib/webcscope/icons/up.gif create mode 100644 contrib/webcscope/icons/world2.gif create mode 100644 contrib/xcscope/CVS/Entries create mode 100644 contrib/xcscope/CVS/Repository create mode 100644 contrib/xcscope/CVS/Root create mode 100755 contrib/xcscope/cscope-indexer create mode 100644 contrib/xcscope/xcscope.el (limited to 'contrib') diff --git a/contrib/Makefile.am b/contrib/Makefile.am new file mode 100644 index 0000000..5e9b75f --- /dev/null +++ b/contrib/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in + +bin_SCRIPTS = ocs + +EXTRA_DIST = ocs README xcscope webcscope + diff --git a/contrib/Makefile.in b/contrib/Makefile.in new file mode 100644 index 0000000..0951263 --- /dev/null +++ b/contrib/Makefile.in @@ -0,0 +1,328 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = contrib +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +binSCRIPT_INSTALL = $(INSTALL_SCRIPT) +SCRIPTS = $(bin_SCRIPTS) +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSES_INCLUDEDIR = @CURSES_INCLUDEDIR@ +CURSES_LIBS = @CURSES_LIBS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GNOME_LINUX_FALSE = @GNOME_LINUX_FALSE@ +GNOME_LINUX_TRUE = @GNOME_LINUX_TRUE@ +HAS_CURSES_FALSE = @HAS_CURSES_FALSE@ +HAS_CURSES_TRUE = @HAS_CURSES_TRUE@ +HAS_GNOME_FALSE = @HAS_GNOME_FALSE@ +HAS_GNOME_TRUE = @HAS_GNOME_TRUE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USING_GNOME2_FALSE = @USING_GNOME2_FALSE@ +USING_GNOME2_TRUE = @USING_GNOME2_TRUE@ +USING_LEX_FALSE = @USING_LEX_FALSE@ +USING_LEX_TRUE = @USING_LEX_TRUE@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +gnome1 = @gnome1@ +gnome2 = @gnome2@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +bin_SCRIPTS = ocs +EXTRA_DIST = ocs README xcscope webcscope +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu contrib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f $$d$$p; then \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \ + else :; fi; \ + done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done +uninstall-info-am: +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(SCRIPTS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binSCRIPTS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binSCRIPTS uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-binSCRIPTS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am uninstall uninstall-am uninstall-binSCRIPTS \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/README b/contrib/README new file mode 100644 index 0000000..9bd66c6 --- /dev/null +++ b/contrib/README @@ -0,0 +1,11 @@ +Contributed addons and wrappers for cscope +$Id: README,v 1.3 2001/07/02 20:57:45 petr Exp $ + +ocs - wrapper for cscope providing database generation through recursive + directory set (among other things) - docced in script itself. + contributed from SCO osr5. + +webcscope - a web cgi interface to cscope. Contributed by Ragho Mahalingam, + using code from Dmitry Obukhovi and Steven E. Brenner. + +xcscope - An (X)Emacs interface to cscope. diff --git a/contrib/ocs b/contrib/ocs new file mode 100755 index 0000000..736de94 --- /dev/null +++ b/contrib/ocs @@ -0,0 +1,308 @@ +#!/bin/sh +# $Id: ocs,v 1.4 2004/06/21 18:13:21 broeker Exp $ +# This utility maintains the database for cscope on a recursive dir set +# Author: donwo Tue Jun 25 15:36:39 PDT 1996 +# Modified: hops Jan 2000 chg defaults to not update if files exist and force +# +# These comments ARE the manual. What more do you really need? +# if using unadorned cscope with this use cscope -d so not trash db +# cscope -L -0 - to display ptn matches on stdout +# +# The lists of files are kept in two forms: +# TMP cscope.tmplst +# The list generated by this program +# This list will be updated each time this program +# is executed. +# +# LST cscope.lst +# The fixed list generated by some other process +# This list will be used, if found, rather than +# the TMP form generated here. +# +# CSD cscope.csd +# The fixed list generated by some other process +# This list will be used, if found, rather than +# the LST or TMP forms. CSD differs from LST in +# that the CSD list is used where the source files +# change only seldom. Cscope is requested not to +# check for changed files. This can be +# significantly faster on large source trees. +# +# INC cscope.inc +# This is a list of additional directories +# in which to search for include files. +# +# Three hierarchies of libraries are supported: +# Local In the current directory ./ +# This is most useful for transient projects or +# where the information is of no use to others on +# the system. This type is NOT usable on source +# directories that are read-only. +# Home In users home directory $HOME/lib/cs/`pwd` +# This is good for items that seldom change but are +# of use only the the current user. This type is +# usable on source directories that are read-only. +# System In a global system directory $SYSDIR/`pwd` +# This is for items that are of interest to all accounts. +# This option is not available unless the system directory +# is writable by the current user. This type is usable +# on source directories that are read-only. +# +# If a shell script named ./cscope.rc is found and is +# executable, the execution of it will be included within this +# script after defaults_set/cmdline_parse and locating the +# database. +# +# Command line options: +# -x set shell debugging +# -f force +# o Do not ask about regenerating TMP. Just do it. +# o Allow cscope to regenerate libraries for CSD lists. +# -q Tell cscope to build an inverted index for quick +# symbol searching. There is a SIGNIFICANT +# increase in speed with this option however the +# disk space used is doubled. Once the quick +# database is generated, cs will detect the files +# and continue to use them. +# -d Do not regenerate. Intended for cscope sub-tasks. +# -u Update/regenerate. + +# +# Here is where we put things + +CSCOPE=cscope +HOMEDIR=${HOME}/lib/cs + +#set the default value for SYSDIR +if [ -z "${SYSDIR}" ]; then + SYSDIR=/usr/local/lib/cs + echo setting default sysdir +fi + +#check that SYSDIR exists +if [ ! -d ${SYSDIR} ]; then + echo -n $SYSDIR does not exist. + echo Please create the directory and set SYSDIR appropriately + exit +fi + +# Check that cscope is in PATH +type cscope 1>/dev/null 2>&1 + +if [ $? -ne 0 ] +then + echo "ERROR: cscope is not in \$PATH" >&2 + echo " Please set \$PATH correctly or make sure cscope is installed" >&2 + exit 1 +fi + +# popup editor +#XCS_EDITOR=${HOME}/bin/x_cscope_editor +XCS_EDITOR=${HOME}/bin/xme +if [ -n "$DISPLAY" -a -x ${XCS_EDITOR} ] +then + EDITOR=${XCS_EDITOR} + export EDITOR +fi +unset XCS_EDITOR + +# +# Misc defaults + +#FORCE=N +#NOUPDATE= +FORCE=Y # hops - default to force rather than query +NOUPDATE=-d # hops - default to no update if files already exist +QUICK= +SPECDEST= # hops - query for files + +# +# Parse the command line + +set -- `getopt xfqdu $*` + +if [ $? -ne 0 ] +then + echo "Use: cs [-x] [-f] [-q] [-u]" >&2 + echo " -x debug on " >&2 + echo " -q quick Index - faster search but larger index" >&2 + echo " -f ask about about regeneration" >&2 + echo " -d don't update database (default)" >&2 + echo " -u update database" >&2 + echo " -s specify where files go" >&2 + exit 1 +fi + +for arg +do + case $arg in + -x ) set -x; shift ;; + -f ) FORCE=N; NOUPDATE=; shift;; + -q ) QUICK=-q; shift ;; + -d ) NOUPDATE=-d; shift ;; + -u ) NOUPDATE=; shift ;; + -s ) SPECDEST=Y; shift ;; + esac +done + +# +# Here is the security hole. Execute whatever is needed for +# this project. A per-project setup script may be available. + +[ -x ./cscope.rc ] && { + . ./cscope.rc +} + +# +# We look hard for appropriate files to scope. We ignore items +# containing "SCCS" assuming that these are directories of +# source code control data. + +create_list() +{ + LIST=$1 + + if [ -f ${LIST} ] + then + [ -n "${NOUPDATE}" ] && return + + if [ "${FORCE}" != "Y" ] + then + echo "\n${LIST}" + echo "Update the library? <(Y)es, (N)o, (Q)uit> [n] \c" + read x y + case $x in + [Yy]* ) ;; + [Qq]* ) exit 1 ;; + *) return ;; + esac + fi + echo "Updating library:\n ${LIST} \c" + else + echo "Creating library:\n ${LIST} \c" + fi + + ( + find . -follow -type f \( -name \*.[sScChHlyG] -o \ + -name \*.asm -o \ + -name \*.cc -o \ + -name \*.cxx -o \ + -name \*.ccP -o \ + -name \*.hP -o \ + -name \*.inc -o \ + -name \*.ed -o \ + -name vuifile -o \ + -name Gensymvals -o \ + -name \[mM\]ake\* \) \ + -print + ) | grep -v SCCS | sort -u > ${LIST} + + echo "\n`cat ${LIST} | wc -l` files listed" +} + +# +# Expand the include file list into command line arguments + +exp_inc() +{ + theInc=$1 + + if [ -s "${theInc}" ] + then + for i in `cat ${theInc}` + do + echo "-I $i \c" + done + fi +} + +# +# This routine does not return to the caller + +do_cscope() +{ + LIST=$1 + CSLIB=$2 + INC=$3 + shift;shift;shift + ARGS="$*" + + INCARGS=`exp_inc ${INC}` + + echo "exec cscope" + exec $CSCOPE ${ARGS} -p 2 ${INCARGS} -i ${LIST} -f ${CSLIB} + echo "exec of $CSCOPE failed" >&2 + exit 1 +} + +# +# If we have existing libraries, we should use them. +std_libs() +{ + DIR=$1 + OUT=${DIR}/cscope.out + LST=${DIR}/cscope.lst + CSD=${DIR}/cscope.csd + TMP=${DIR}/cscope.tmplst + INC=${DIR}/cscope.inc + QCK=${DIR}/cscope.out.po + + [ -s ${QCK} ] && QUICK=-q + + [ -f ${CSD} ] && { + if [ "${FORCE}" = "Y" ] + then + do_cscope ${CSD} ${OUT} ${INC} ${QUICK} + else + do_cscope ${CSD} ${OUT} ${INC} ${QUICK} -d + fi + } + + [ -f ${LST} ] && do_cscope ${LST} ${OUT} ${INC} ${QUICK} ${NOUPDATE} + + [ -f ${TMP} ] && { + create_list ${TMP} + do_cscope ${TMP} ${OUT} ${INC} ${QUICK} ${NOUPDATE} + } +} + +# +# ######## main() ####### + +umask 0 +PWD=`pwd` + +umask 02 + +# +# Check for existing libraries + +std_libs $PWD +std_libs ${HOMEDIR}$PWD +std_libs ${SYSDIR}$PWD + +# +# We may need to create one for this area + +DIR=$PWD +if [ ! -n "${NOUPDATE}" -o -n "${SPECDEST}" ] ; then +echo "Create new library? <(L)ocal, (H)ome, (S)ystem, (Q)uit> [q] \c" +read x y +case $x in + [Ll]* ) DIR=$PWD ;; + [Hh]* ) DIR=${HOMEDIR}$PWD ;; + [Ss]* ) DIR=${SYSDIR}$PWD ;; + *) exit 1 ;; +esac +fi +[ -d $DIR ] || { + mkdir -p $DIR || exit $? +} + +OUT=${DIR}/cscope.out +TMP=${DIR}/cscope.tmplst +INC=${DIR}/cscope.inc + +create_list ${TMP} +do_cscope ${TMP} ${OUT} ${INC} ${QUICK} + diff --git a/contrib/webcscope/CVS/Entries b/contrib/webcscope/CVS/Entries new file mode 100644 index 0000000..998a8cd --- /dev/null +++ b/contrib/webcscope/CVS/Entries @@ -0,0 +1,7 @@ +D/icons//// +/INSTALL/1.1/Fri Jun 29 14:20:16 2001// +/LICENSE/1.1/Fri Jun 29 14:20:16 2001// +/TODO/1.1/Fri Jun 29 14:20:16 2001// +/cgi-lib.pl/1.1/Fri Jun 29 14:20:16 2001// +/cscope/1.1/Fri Jun 29 14:20:16 2001// +/hilite.c/1.1/Fri Jun 29 14:20:16 2001// diff --git a/contrib/webcscope/CVS/Repository b/contrib/webcscope/CVS/Repository new file mode 100644 index 0000000..1868bd7 --- /dev/null +++ b/contrib/webcscope/CVS/Repository @@ -0,0 +1 @@ +cscope/contrib/webcscope diff --git a/contrib/webcscope/CVS/Root b/contrib/webcscope/CVS/Root new file mode 100644 index 0000000..e0eb551 --- /dev/null +++ b/contrib/webcscope/CVS/Root @@ -0,0 +1 @@ +broeker@cscope.cvs.sourceforge.net:/cvsroot/cscope diff --git a/contrib/webcscope/INSTALL b/contrib/webcscope/INSTALL new file mode 100644 index 0000000..0ea0d9c --- /dev/null +++ b/contrib/webcscope/INSTALL @@ -0,0 +1,31 @@ +WebCScope Installation + +Quick Install + +0. Create a directory called cscope under your /cgi-bin (virtual) directory. + Copy all the files in the distribution to this directory. + +1. Edit the 'cscope' file and change the following items: + - Location to the perl interpreter + - Location of the cscope database and other modifiable parameters + - Feedback name and email + - Location of the syntax highlighter, if you wish to use it + +2. Syntax highlighter + - The syntax highlighter must be built if you decide to use it. If you + do not want syntax highlighting, you can ignore this step and set the + highlighter to /bin/cat. + - Compile 'hilite.c' using 'gcc -o hilite hilite.c' + +3. Icons + - Copy the images from the icons directory into the /icons (virtual) + directory on the web server. You can also replace these images with + whatever you choose. + +4. Organizing your CScope databases + - WebCScope supports multiple databases in $cscopedir + - Create a directory for each project or sub-source in $cscopedir and, + generate your cscope database using the following commands. + - find /some/source/dir -name '*.[chyls]' -print > cscope.files + - cscope -b -q + - Repeat the above step for each database you wish to create diff --git a/contrib/webcscope/LICENSE b/contrib/webcscope/LICENSE new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/contrib/webcscope/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/webcscope/TODO b/contrib/webcscope/TODO new file mode 100644 index 0000000..4e61555 --- /dev/null +++ b/contrib/webcscope/TODO @@ -0,0 +1,5 @@ + +- Better error checking and the like +- Add a more robust cookie mechanism +- More efficient way of searching 'all' databases +- Fix bugs diff --git a/contrib/webcscope/cgi-lib.pl b/contrib/webcscope/cgi-lib.pl new file mode 100644 index 0000000..97d0caa --- /dev/null +++ b/contrib/webcscope/cgi-lib.pl @@ -0,0 +1,471 @@ +# Perl Routines to Manipulate CGI input +# cgi-lib@pobox.com +# $Id: cgi-lib.pl,v 1.1 2001/06/29 14:20:16 petr Exp $ +# +# Copyright (c) 1993-1999 Steven E. Brenner +# Unpublished work. +# Permission granted to use and modify this library so long as the +# copyright above is maintained, modifications are documented, and +# credit is given for any use of the library. +# +# Thanks are due to many people for reporting bugs and suggestions + +# For more information, see: +# http://cgi-lib.stanford.edu/cgi-lib/ + +$cgi_lib'version = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/); + + +# Parameters affecting cgi-lib behavior +# User-configurable parameters affecting file upload. +$cgi_lib'maxdata = 131072; # maximum bytes to accept via POST - 2^17 +$cgi_lib'writefiles = 0; # directory to which to write files, or + # 0 if files should not be written +$cgi_lib'filepre = "cgi-lib"; # Prefix of file names, in directory above + +# Do not change the following parameters unless you have special reasons +$cgi_lib'bufsize = 8192; # default buffer size when reading multipart +$cgi_lib'maxbound = 100; # maximum boundary length to be encounterd +$cgi_lib'headerout = 0; # indicates whether the header has been printed + + +# ReadParse +# Reads in GET or POST data, converts it to unescaped text, and puts +# key/value pairs in %in, using "\0" to separate multiple selections + +# Returns >0 if there was input, 0 if there was no input +# undef indicates some failure. + +# Now that cgi scripts can be put in the normal file space, it is useful +# to combine both the form and the script in one place. If no parameters +# are given (i.e., ReadParse returns FALSE), then a form could be output. + +# If a reference to a hash is given, then the data will be stored in that +# hash, but the data from $in and @in will become inaccessable. +# If a variable-glob (e.g., *cgi_input) is the first parameter to ReadParse, +# information is stored there, rather than in $in, @in, and %in. +# Second, third, and fourth parameters fill associative arrays analagous to +# %in with data relevant to file uploads. + +# If no method is given, the script will process both command-line arguments +# of the form: name=value and any text that is in $ENV{'QUERY_STRING'} +# This is intended to aid debugging and may be changed in future releases + +sub ReadParse { + # Disable warnings as this code deliberately uses local and environment + # variables which are preset to undef (i.e., not explicitly initialized) + local ($perlwarn); + $perlwarn = $^W; + $^W = 0; + + local (*in) = shift if @_; # CGI input + local (*incfn, # Client's filename (may not be provided) + *inct, # Client's content-type (may not be provided) + *insfn) = @_; # Server's filename (for spooled files) + local ($len, $type, $meth, $errflag, $cmdflag, $got, $name); + + binmode(STDIN); # we need these for DOS-based systems + binmode(STDOUT); # and they shouldn't hurt anything else + binmode(STDERR); + + # Get several useful env variables + $type = $ENV{'CONTENT_TYPE'}; + $len = $ENV{'CONTENT_LENGTH'}; + $meth = $ENV{'REQUEST_METHOD'}; + + if ($len > $cgi_lib'maxdata) { #' + &CgiDie("cgi-lib.pl: Request to receive too much data: $len bytes\n"); + } + + if (!defined $meth || $meth eq '' || $meth eq 'GET' || + $meth eq 'HEAD' || + $type eq 'application/x-www-form-urlencoded') { + local ($key, $val, $i); + + # Read in text + if (!defined $meth || $meth eq '') { + $in = $ENV{'QUERY_STRING'}; + $cmdflag = 1; # also use command-line options + } elsif($meth eq 'GET' || $meth eq 'HEAD') { + $in = $ENV{'QUERY_STRING'}; + } elsif ($meth eq 'POST') { + if (($got = read(STDIN, $in, $len) != $len)) + {$errflag="Short Read: wanted $len, got $got\n";}; + } else { + &CgiDie("cgi-lib.pl: Unknown request method: $meth\n"); + } + + @in = split(/[&;]/,$in); + push(@in, @ARGV) if $cmdflag; # add command-line parameters + + foreach $i (0 .. $#in) { + # Convert plus to space + $in[$i] =~ s/\+/ /g; + + # Split into key and value. + ($key, $val) = split(/=/,$in[$i],2); # splits on the first =. + + # Convert %XX from hex numbers to alphanumeric + $key =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; + $val =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; + + # Associate key and value + $in{$key} .= "\0" if (defined($in{$key})); # \0 is the multiple separator + $in{$key} .= $val; + } + + } elsif ($ENV{'CONTENT_TYPE'} =~ m#^multipart/form-data#) { + # for efficiency, compile multipart code only if needed +$errflag = !(eval <<'END_MULTIPART'); + + local ($buf, $boundary, $head, @heads, $cd, $ct, $fname, $ctype, $blen); + local ($bpos, $lpos, $left, $amt, $fn, $ser); + local ($bufsize, $maxbound, $writefiles) = + ($cgi_lib'bufsize, $cgi_lib'maxbound, $cgi_lib'writefiles); + + + # The following lines exist solely to eliminate spurious warning messages + $buf = ''; + + ($boundary) = $type =~ /boundary="([^"]+)"/; #"; # find boundary + ($boundary) = $type =~ /boundary=(\S+)/ unless $boundary; + &CgiDie ("Boundary not provided: probably a bug in your server") + unless $boundary; + $boundary = "--" . $boundary; + $blen = length ($boundary); + + if ($ENV{'REQUEST_METHOD'} ne 'POST') { + &CgiDie("Invalid request method for multipart/form-data: $meth\n"); + } + + if ($writefiles) { + local($me); + stat ($writefiles); + $writefiles = "/tmp" unless -d _ && -w _; + # ($me) = $0 =~ m#([^/]*)$#; + $writefiles .= "/$cgi_lib'filepre"; + } + + # read in the data and split into parts: + # put headers in @in and data in %in + # General algorithm: + # There are two dividers: the border and the '\r\n\r\n' between + # header and body. Iterate between searching for these + # Retain a buffer of size(bufsize+maxbound); the latter part is + # to ensure that dividers don't get lost by wrapping between two bufs + # Look for a divider in the current batch. If not found, then + # save all of bufsize, move the maxbound extra buffer to the front of + # the buffer, and read in a new bufsize bytes. If a divider is found, + # save everything up to the divider. Then empty the buffer of everything + # up to the end of the divider. Refill buffer to bufsize+maxbound + # Note slightly odd organization. Code before BODY: really goes with + # code following HEAD:, but is put first to 'pre-fill' buffers. BODY: + # is placed before HEAD: because we first need to discard any 'preface,' + # which would be analagous to a body without a preceeding head. + + $left = $len; + PART: # find each part of the multi-part while reading data + while (1) { + die $@ if $errflag; + + $amt = ($left > $bufsize+$maxbound-length($buf) + ? $bufsize+$maxbound-length($buf): $left); + $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); + die "Short Read: wanted $amt, got $got\n" if $errflag; + $left -= $amt; + + $in{$name} .= "\0" if defined $in{$name}; + $in{$name} .= $fn if $fn; + + $name=~/([-\w]+)/; # This allows $insfn{$name} to be untainted + if (defined $1) { + $insfn{$1} .= "\0" if defined $insfn{$1}; + $insfn{$1} .= $fn if $fn; + } + + BODY: + while (($bpos = index($buf, $boundary)) == -1) { + if ($left == 0 && $buf eq '') { + foreach $value (values %insfn) { + unlink(split("\0",$value)); + } + &CgiDie("cgi-lib.pl: reached end of input while seeking boundary " . + "of multipart. Format of CGI input is wrong.\n"); + } + die $@ if $errflag; + if ($name) { # if no $name, then it's the prologue -- discard + if ($fn) { print FILE substr($buf, 0, $bufsize); } + else { $in{$name} .= substr($buf, 0, $bufsize); } + } + $buf = substr($buf, $bufsize); + $amt = ($left > $bufsize ? $bufsize : $left); #$maxbound==length($buf); + $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); + die "Short Read: wanted $amt, got $got\n" if $errflag; + $left -= $amt; + } + if (defined $name) { # if no $name, then it's the prologue -- discard + if ($fn) { print FILE substr($buf, 0, $bpos-2); } + else { $in {$name} .= substr($buf, 0, $bpos-2); } # kill last \r\n + } + close (FILE); + last PART if substr($buf, $bpos + $blen, 2) eq "--"; + substr($buf, 0, $bpos+$blen+2) = ''; + $amt = ($left > $bufsize+$maxbound-length($buf) + ? $bufsize+$maxbound-length($buf) : $left); + $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); + die "Short Read: wanted $amt, got $got\n" if $errflag; + $left -= $amt; + + + undef $head; undef $fn; + HEAD: + while (($lpos = index($buf, "\r\n\r\n")) == -1) { + if ($left == 0 && $buf eq '') { + foreach $value (values %insfn) { + unlink(split("\0",$value)); + } + &CgiDie("cgi-lib: reached end of input while seeking end of " . + "headers. Format of CGI input is wrong.\n$buf"); + } + die $@ if $errflag; + $head .= substr($buf, 0, $bufsize); + $buf = substr($buf, $bufsize); + $amt = ($left > $bufsize ? $bufsize : $left); #$maxbound==length($buf); + $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); + die "Short Read: wanted $amt, got $got\n" if $errflag; + $left -= $amt; + } + $head .= substr($buf, 0, $lpos+2); + push (@in, $head); + @heads = split("\r\n", $head); + ($cd) = grep (/^\s*Content-Disposition:/i, @heads); + ($ct) = grep (/^\s*Content-Type:/i, @heads); + + ($name) = $cd =~ /\bname="([^"]+)"/i; #"; + ($name) = $cd =~ /\bname=([^\s:;]+)/i unless defined $name; + + ($fname) = $cd =~ /\bfilename="([^"]*)"/i; #"; # filename can be null-str + ($fname) = $cd =~ /\bfilename=([^\s:;]+)/i unless defined $fname; + $incfn{$name} .= (defined $in{$name} ? "\0" : "") . + (defined $fname ? $fname : ""); + + ($ctype) = $ct =~ /^\s*Content-type:\s*"([^"]+)"/i; #"; + ($ctype) = $ct =~ /^\s*Content-Type:\s*([^\s:;]+)/i unless defined $ctype; + $inct{$name} .= (defined $in{$name} ? "\0" : "") . $ctype; + + if ($writefiles && defined $fname) { + $ser++; + $fn = $writefiles . ".$$.$ser"; + open (FILE, ">$fn") || &CgiDie("Couldn't open $fn\n"); + binmode (FILE); # write files accurately + } + substr($buf, 0, $lpos+4) = ''; + undef $fname; + undef $ctype; + } + +1; +END_MULTIPART + if ($errflag) { + local ($errmsg, $value); + $errmsg = $@ || $errflag; + foreach $value (values %insfn) { + unlink(split("\0",$value)); + } + &CgiDie($errmsg); + } else { + # everything's ok. + } + } else { + &CgiDie("cgi-lib.pl: Unknown Content-type: $ENV{'CONTENT_TYPE'}\n"); + } + + # no-ops to avoid warnings + $insfn = $insfn; + $incfn = $incfn; + $inct = $inct; + + $^W = $perlwarn; + + return ($errflag ? undef : scalar(@in)); +} + + +# PrintHeader +# Returns the magic line which tells WWW that we're an HTML document + +sub PrintHeader { + return "Content-type: text/html\n\n"; +} + + +# HtmlTop +# Returns the of a document and the beginning of the body +# with the title and a body

header as specified by the parameter + +sub HtmlTop +{ + local ($title) = @_; + + return < + +$title + + +

$title

+END_OF_TEXT +} + + +# HtmlBot +# Returns the , codes for the bottom of every HTML page + +sub HtmlBot +{ + return "\n\n"; +} + + +# SplitParam +# Splits a multi-valued parameter into a list of the constituent parameters + +sub SplitParam +{ + local ($param) = @_; + local (@params) = split ("\0", $param); + return (wantarray ? @params : $params[0]); +} + + +# MethGet +# Return true if this cgi call was using the GET request, false otherwise + +sub MethGet { + return (defined $ENV{'REQUEST_METHOD'} && $ENV{'REQUEST_METHOD'} eq "GET"); +} + + +# MethPost +# Return true if this cgi call was using the POST request, false otherwise + +sub MethPost { + return (defined $ENV{'REQUEST_METHOD'} && $ENV{'REQUEST_METHOD'} eq "POST"); +} + + +# MyBaseUrl +# Returns the base URL to the script (i.e., no extra path or query string) +sub MyBaseUrl { + local ($ret, $perlwarn); + $perlwarn = $^W; $^W = 0; + $ret = 'http://' . $ENV{'SERVER_NAME'} . + ($ENV{'SERVER_PORT'} != 80 ? ":$ENV{'SERVER_PORT'}" : '') . + $ENV{'SCRIPT_NAME'}; + $^W = $perlwarn; + return $ret; +} + + +# MyFullUrl +# Returns the full URL to the script (i.e., with extra path or query string) +sub MyFullUrl { + local ($ret, $perlwarn); + $perlwarn = $^W; $^W = 0; + $ret = 'http://' . $ENV{'SERVER_NAME'} . + ($ENV{'SERVER_PORT'} != 80 ? ":$ENV{'SERVER_PORT'}" : '') . + $ENV{'SCRIPT_NAME'} . $ENV{'PATH_INFO'} . + (length ($ENV{'QUERY_STRING'}) ? "?$ENV{'QUERY_STRING'}" : ''); + $^W = $perlwarn; + return $ret; +} + + +# MyURL +# Returns the base URL to the script (i.e., no extra path or query string) +# This is obsolete and will be removed in later versions +sub MyURL { + return &MyBaseUrl; +} + + +# CgiError +# Prints out an error message which which containes appropriate headers, +# markup, etcetera. +# Parameters: +# If no parameters, gives a generic error message +# Otherwise, the first parameter will be the title and the rest will +# be given as different paragraphs of the body + +sub CgiError { + local (@msg) = @_; + local ($i,$name); + + if (!@msg) { + $name = &MyFullUrl; + @msg = ("Error: script $name encountered fatal error\n"); + }; + + if (!$cgi_lib'headerout) { #') + print &PrintHeader; + print "\n\n$msg[0]\n\n\n"; + } + print "

$msg[0]

\n"; + foreach $i (1 .. $#msg) { + print "

$msg[$i]

\n"; + } + + $cgi_lib'headerout++; +} + + +# CgiDie +# Identical to CgiError, but also quits with the passed error message. + +sub CgiDie { + local (@msg) = @_; + &CgiError (@msg); + die @msg; +} + + +# PrintVariables +# Nicely formats variables. Three calling options: +# A non-null associative array - prints the items in that array +# A type-glob - prints the items in the associated assoc array +# nothing - defaults to use %in +# Typical use: &PrintVariables() + +sub PrintVariables { + local (*in) = @_ if @_ == 1; + local (%in) = @_ if @_ > 1; + local ($out, $key, $output); + + $output = "\n
\n"; + foreach $key (sort keys(%in)) { + foreach (split("\0", $in{$key})) { + ($out = $_) =~ s/\n/
\n/g; + $output .= "
$key\n
:$out:
\n"; + } + } + $output .= "
\n"; + + return $output; +} + +# PrintEnv +# Nicely formats all environment variables and returns HTML string +sub PrintEnv { + &PrintVariables(*ENV); +} + + +# The following lines exist only to avoid warning messages +$cgi_lib'writefiles = $cgi_lib'writefiles; +$cgi_lib'bufsize = $cgi_lib'bufsize ; +$cgi_lib'maxbound = $cgi_lib'maxbound; +$cgi_lib'version = $cgi_lib'version; +$cgi_lib'filepre = $cgi_lib'filepre; + +1; #return true + diff --git a/contrib/webcscope/cscope b/contrib/webcscope/cscope new file mode 100755 index 0000000..7d98fce --- /dev/null +++ b/contrib/webcscope/cscope @@ -0,0 +1,446 @@ +#!/bin/perl + +# $Id: cscope,v 1.1 2001/06/29 14:20:16 petr Exp $ +# +# WebCscope: A web interface to the cscope application +# Copyright (C) 2001, Ragho Mahalingam +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Change History: +# +# $Log: cscope,v $ +# Revision 1.1 2001/06/29 14:20:16 petr +# Added webcscope to contribs. +# +# Revision 1.3.4.1 2001/02/05 15:14:34 rmahalin +# initial release with some bug fixes +# +# Revision 1.3.3.1 2001/01/22 22:21:23 rmahalin +# added multi-database support +# fixed cookie support for trivial functions; removed global trivials +# added syntax highlighting for files displayed on browser +# +# Revision 1.3.1.1 2001/01/11 22:17:30 rmahalin +# added direct download with mime-type 'text/c-source' and made cosmetic changes +# +# Revision 1.3 2001/01/11 21:36:39 rmahalin +# *** empty log message *** +# +# Revision 1.2 2001/01/11 21:34:13 rmahalin +# incorporated draft feedback changes +# +# Revision 1.1 2001/01/11 21:19:32 rmahalin +# Initial revision +# + +require "cgi-lib.pl"; + +# current code version being used +$version = "iSOS 2.5/int16"; +# full path to the cscope binary +$cscopecmd = "/usr/global/bin/cscope"; +# cscope working directory, where all the in/out and db files are stored +$cscopedir = "/usr/local/cscope"; +# trivial functions not to display, one per line in the trivs file +$trivs = "/usr/local/htdocs/cscope/trivials"; +# temporary storage directory +$tmpdir = "/tmp"; +$tmpinfile = $tmpdir . "/cscopein.$$"; +$tmpoutfile = $tmpdir . "/cscopeout.$$"; +$showfile = $tmpdir . "/showfile.$$"; +# C syntax highlighting application or uncomment the line beneath to just cat +#$hiliter = "/bin/cat"; +$hiliter = "/usr/local/cgi-bin/cscope/hilite"; +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(time+1000000); +$cookie_exp = sprintf("%s %02d-%s-%s %02d:%02d:%02d GMT", $wday, $mday, $mon, $year, $hour, $min, $sec); + +# standard images, from the apache distribution +$img{openfile} = "/icons/folder.gif"; +$img{downloadfile} = "/icons/folder.open.gif"; +$img{csymbol} = "/icons/c.gif"; +$img{upfunc} = "/icons/up.gif"; +$img{downfunc} = "/icons/down.gif"; +$img{globalfunc} = "/icons/world2.gif"; +$img{trashfunc} = "/icons/bomb.gif"; +$img{untrashfunc} = "/icons/back.gif"; +$img{back} = "/icons/left.gif"; + +# feedback details +$comment{name} = "Ragho Mahalingam"; +$comment{email} = "ragho\@mahalingam.com"; + +# operations allowed +@oper = ( "Find this C symbol", +"Find this global symbol", +"Find functions called by", +"Find functions calling", +"Find this text string", +"---------------------", +"Find this egrep pattern", +"Find this file", +"Find files #including this file" ); + +# -- removed global trivial function list in favor of customized trivials +#open(TRIVIAL_FUNC, $trivs); +#@trivial = ; +#close(TRIVIAL_FUNC); +@trivial = (); + +MAIN: + +{ + $starttime = time; + + if (&ReadParse(*input)) { + &ProcessCookie; + &ProcessForm; + } else { + &PrintForm; + } +} + +sub ProcessCookie { + + if ( defined $ENV{HTTP_COOKIE} ) { + ($var, $val) = split('=',$ENV{HTTP_COOKIE}); + $Cookie{$var} = $val; + if ( defined $Cookie{'cs-trivf'} ) { + # do nothing, else initialize it to null + } else { + $Cookie{'cs-trivf'} = "defined"; + } + @loc_trivial = split(',', $Cookie{'cs-trivf'}); + @trivial = ( @loc_trivial ); + + } +} + +sub ProcessTrashForm { + + if ( defined $input{'trash'} ) { + @trivial = (@trivial, $input{'func'}); + } else { + @tmptriv = (); + for ($i=0; $i <= $#trivial; $i++) { + $fhash = unpack('H*', $input{'func'}); + $thash = unpack('H*', $trivial[$i]); + if ( $fhash != $thash ) { + @tmptriv = ( @tmptriv, $trivial[$i] ); + } + } + @trivial = @tmptriv; + } + + $Cookie{'cs-trivf'} = join(',',@trivial); + + print "Content-type: text/html\n"; + print "Set-Cookie: cs-trivf=$Cookie{'cs-trivf'}; path=$ENV{SCRIPT_NAME}; expires $cookie_exp\n\n"; + print &HtmlTop("Your WebCScope Trivial Functions"); + print "
    "; + for ($i=0; $i <= $#trivial; $i++) { + print "
  •   $trivial[$i]"; + } + print "

\n"; + print "Click to go back.\n"; + print &HtmlBot; + +} + +sub ProcessForm { + + chdir $cscopedir; + opendir(DIRLIST,$cscopedir); + @dirlist = readdir(DIRLIST); + closedir(DIRLIST); + + if ( $input{'db'} eq "all" ) { + @csdirs = (); + for ($i=0; $i <= $#dirlist; $i++ ) { + if ( ($dirlist[$i] ne ".") && ($dirlist[$i] ne "..") && ( -d $dirlist[$i] ) ) { + @csdirs = ( @csdirs, $dirlist[$i] ); + } + } + } else { + @csdirs = ( $input{'db'} ); + } + + $op = $input{'op'}; + $arg = $input{'arg'}; + $shtriv = $input{'triv'}; + $db = $input{'db'}; + + if ( defined $input{'fshow'} ) { &ShowFileForm; exit; } + if ( defined $input{'load'} ) { &DownloadFileForm; exit; } + if ( (defined $input{'trash'}) || (defined $input{'untrash'}) ) { + &ProcessTrashForm; exit; } + + print &PrintHeader; + print &HtmlTop ("WebCscope"); + print <Instructions

+

    +
  • will find a symbol with this name
    +
  • will find functions calling this function
    +
  • will find functions called by this +function
    +
  • will locate a global definition of this name
    +
  • will display this file and highlight +the fragment line
    +
  • will download this file with mimetype "text/c-source"
    +
  • will add this symbol/function to your trivial list
    +
+


+ENDOFHDR + + foreach $index ( 0 .. $#csdirs ) { + + unlink $tmpinfile, $tmpoutfile; + open(CSCOPEIN, ">$tmpinfile"); + print CSCOPEIN "$op$arg\n"; + print CSCOPEIN "exit\n"; + close(CSCOPEIN); + + $dbdir = $cscopedir . "/" . $csdirs[$index]; + chdir($dbdir); + + $syscmd = "cd $dbdir; $cscopecmd -d -l < $tmpinfile > $tmpoutfile;"; + system($syscmd); + + $count = 1; + open(CSCOPEIN, "$tmpoutfile"); + + $line = ; + @temp = split(' ',$line); + $numresult = $temp[2]; + + print <Search Results from $csdirs[$index] +$oper[$op]: $arg
+Matches: $numresult

+ + + +ENDOFHDRs + + $trivs_rm = 0; + + for ($i=0; $i < $numresult; $i++ ) { + $line = ; + @fields = split(' ',$line); + $file = shift @fields; + $fshowfile = $file; + $func = shift @fields; + $lnum = shift @fields; + @filef = split('/',$file); + $file = $filef[$#filef]; + $frag = join(' ',@fields); + + if ( ! $shtriv ) { + for ( $j=0; $j <= $#trivial; $j++ ) + { + $fhash = unpack('H*', $func); + $thash = unpack('H*', $trivial[$j]); + if ( $fhash == $thash ) { $trivs_rm++; goto done; } + } + } + + if ( $func ne "" && $func ne "" ) { + print < + + + + +ENDOFBODY1 + +} else { + $func =~ tr/<>/[]/; + print < + + + + +ENDOFBODY2 + +} + + $count++; +done: + + } + + close(CSCOPEIN); + print "
NumFileFunctionLineFragment
$count + $file + + + + + + +$func + + + + + + +$lnum$frag
$count + $file + + +$func$lnum<$frag
\n"; + print "
Eliminated $trivs_rm line item(s) as trivial functions


\n"; + unlink $tmpinfile, $tmpoutfile; + +} + + print &OperationTime; + print &Feedback; + print &HtmlBot; + +} + +sub DownloadFileForm { + $file = $input{'file'}; + print "Content-type: text/c-source\n\n"; + open(SHOWFILE, $file); + while () { print; } + close(SHOWFILE); +} + +sub ShowFileForm { + + $file = $input{'fshowfile'}; + $lnum = $input{'line'}; + + print &PrintHeader; + print &HtmlTop ("WebCscope"); + print "Note: Click to go to the reference line


\n"; + print "
"; + + unlink $showfile; + system("$hiliter $file > $showfile"); + open(SHOWFILE, $showfile); + + $curline = 1; + while ( ) { + $line = $_; + if ( $curline == $lnum ) { + print "$line"; + } else { + print $line; + } + $curline++; + } + + close (SHOWFILE); + + + + print &OperationTime; + print &Feedback; + print &HtmlBot; +} + +sub PrintForm { + + chdir $cscopedir; + opendir(DIRLIST,$cscopedir); + @dirlist = readdir(DIRLIST); + closedir(DIRLIST); + + @csdirs = (); + for ($i=0; $i <= $#dirlist; $i++ ) { + if ( ($dirlist[$i] ne ".") && ($dirlist[$i] ne "..") && ( -d $dirlist[$i] ) ) { + @csdirs = ( @csdirs, $dirlist[$i] ); + } + } + + print &PrintHeader; + print &HtmlTop ("Web-CScope"); + + print < +
+ + + + + + + + + + + + + + + +
Operation: +
CScope Database: +
Symbol, function or text:
Show trivial functions: +Yes +No +

+
+
+
+ENDOFTEXT2 + + print &Feedback; + print &HtmlBot; +} + +sub Feedback { + + $feedback = ""; + $feedback .= '$Id: cscope,v 1.1 2001/06/29 14:20:16 petr Exp $
'; + $feedback .= "$comment{name}<"; + $feedback .= "
"; + $feedback .= "$comment{email}>"; + return $feedback; +} + +sub OperationTime { + + $deltime = time - $starttime; + return "Operation took $deltime second(s)
"; + +} diff --git a/contrib/webcscope/hilite.c b/contrib/webcscope/hilite.c new file mode 100644 index 0000000..4f5af07 --- /dev/null +++ b/contrib/webcscope/hilite.c @@ -0,0 +1,360 @@ +/* + CopyRight (C) 1999, Dmitry Obukhov, dso@usa.net + mailto: dso@usa.net + http://www.EmbeddedStuff.com + + ---------------------------------------------- + Last modified 6 Apr 97 + ---------------------------------------------- + Converts C (C++) source to HTML code fragment + with syntax highlighting. + Since program written for personal purpose + the tags generated. This is optional + page format specific thing. + + Usage: CTHM . All output is done + to STDOUTPUT, error messages to STDERR. + For HTML fragment generation: + CHTM file.c > file.htm + + - Some input convertion required to use this + code as CGI module. Will be done soon. + - Optimization required for blocks of EOL + comments +*/ + +#include + +// ------------------- Decoding status values + +#define START 0 +#define INLINE 1 +#define DEFINE 2 +// ------------------- Decoding Remark +#define REM1 20 +#define REM2 21 +#define REM_END 22 +#define REM_STAR 23 +#define REM_STAR_1 24 +#define STRING 25 // String is "like" remark + + +// ------------------- HTML TAG Generation +#define ON 1 +#define OFF 0 + +// ------------------- HTML TAG type +#define MODE_KEYWORD 0 +#define MODE_REMARK 2 +#define MODE_REMARK_EOL 4 +#define MODE_DEFINE 6 +#define MODE_STRING 8 + + +int is_delimeter(char c) +{ + int ii=0; + char dlms[] = + "\t\r\n (){}[]+-*/%\"'&|^~:;<>.,"; + //-------------------------------- + while (dlms[ii]) + { + if (c==dlms[ii++]) return 1; + } + return 0; +} + +int is_keyword(char * str) +{ + char * kwords[] = + { + "asm", "auto", + "break", "case", + "cdecl", "char", + "class", "const", + "continue", "default", + "delete", "do", + "double", "else", + "enum", "extern", + "far", "float", + "for", "friend", + "goto", "huge", + "if", "inline", + "int", "interrupt", + "long", "near", + "new", "operator", + "pascal", "private", + "protected", "public", + "register", "return", + "short", "signed", + "sizeof", "static", + "struct", "switch", + "template", "this", + "typedef", "union", + "unsigned", "virtual", + "void", "volatile", + "while", NULL + }; + int ii=0; + int jj; + int check; + + while (kwords[ii]) + { + jj = 0; + check = 1; + while (kwords[ii][jj] && check) + { + if (str[jj] != kwords[ii][jj]) + { + check = 0; + } + jj++; + } + if (check) return 1; + ii++; + } + return 0; +} + + +void set_mode(int on_off, int mode) +{ + char * tags[] = + { + //-------------------- KEYWORD + "", + "", + //-------------------- Classic remarks + "", + "", + //-------------------- EOL Remarks + "", + "", + //-------------------- #DEFINE + "", + "", + //-------------------- "string" + "", + "", + NULL, NULL + }; + fprintf(stdout,tags[mode + 1 - on_off]); +} + +void print_char_html(char c) +{ + switch (c) + { + case '<': + fprintf(stdout,"<"); + break; + case '>': + fprintf(stdout,">"); + break; + case '"': + fprintf(stdout,"""); + break; + case '&': + fprintf(stdout,"&"); + break; + case '|': + fprintf(stdout,"¦"); + break; + default: + fprintf(stdout,"%c",c); + } +} + + + +int main(int _argc, char** _argv) +{ + FILE *in, *out; + char c; + int mode; + char buf[80]; + int bufidx = 0; + int progress = 1; + int echo; + int saved_mode; + int kw; + char tmpc; + char prevc; + + if (_argc < 2) + { + fprintf(stderr, + "USAGE: c2html \n"); + return 1; + } + + + if ((in = fopen(_argv[1], "rt")) == NULL) + { + fprintf(stderr, + "Cannot open input file.\n"); + return 1; + } + + fprintf(stdout, "
");
+   mode = START;
+
+   while (!feof(in) && progress)
+   {
+        echo = 1;
+        prevc = c;
+        c = fgetc(in);
+
+        if (c=='/' && (mode < REM1))
+        {
+            saved_mode = mode;
+            mode = REM1;
+        }
+
+        switch (mode)
+        {
+            case REM1:
+                 echo = 0;
+                 mode = REM2;
+                 break;
+
+            case REM2:
+                 if (c=='/')
+                 {
+                    if (saved_mode == DEFINE)
+                    {
+                      set_mode(OFF, MODE_DEFINE);
+                    }
+                    mode = REM_END;
+                    set_mode(ON, MODE_REMARK_EOL);
+                 }
+                 else if (c=='*')
+                 {
+                    if (saved_mode == DEFINE)
+                    {
+                      set_mode(OFF, MODE_DEFINE);
+                    }
+                    mode = REM_STAR;
+                    set_mode(ON, MODE_REMARK);
+                 }
+                 else
+                 {
+                    mode = saved_mode;
+                 }
+                 printf("/");
+                 break;
+
+            case REM_END:
+                 if (c=='\n')
+                 {
+                   set_mode(OFF, MODE_REMARK_EOL);
+                 }
+                 break;
+
+            case REM_STAR:
+                 if (c=='*')
+                 {
+                    mode = REM_STAR_1;
+                 }
+                 break;
+
+            case REM_STAR_1:
+                 if (c=='/')
+                 {
+                    mode = INLINE;
+                    fprintf(stdout,"/");
+                    echo = 0;
+                    set_mode(OFF, MODE_REMARK);
+                 }
+                 else mode = REM_STAR;
+                 break;
+
+            case START:
+                 if (c=='#')
+                 {
+                    mode = DEFINE;
+                    set_mode(ON, MODE_DEFINE);
+                    break;
+                 }
+                 else if (c==' ') break;
+
+                 mode = INLINE;
+                 // and continue in next case
+
+            case INLINE:
+                 if (c=='"' &&        //
+                     prevc != 0x27 && //
+                     prevc != '\\')   //
+                 {
+                    set_mode(ON, MODE_STRING);
+                    mode = STRING;
+                 }
+                 break;
+
+            case STRING:
+                 if (c=='"' && prevc != '\\')
+                 {
+                    print_char_html('"');
+                    set_mode(OFF, MODE_STRING);
+                    echo = 0;
+                    mode = INLINE;
+                 }
+                 break;
+
+            case DEFINE:
+                 if (c=='\n')
+                 {
+                    set_mode(OFF, MODE_DEFINE);
+                 }
+                 break;
+
+        }
+
+        if (echo && //
+            (mode == INLINE || //
+             (mode!=INLINE &&  //
+              bufidx)))        //
+        {
+            buf[bufidx++] = c;
+            buf[bufidx]   = 0;
+            if (is_delimeter(c))
+            {
+                kw = 0;
+                if (bufidx>2)
+                {
+                  kw = is_keyword(buf);
+                }
+                if (kw)
+                {
+                  set_mode(ON, MODE_KEYWORD);
+                }
+                tmpc = buf[bufidx-1];
+                buf[bufidx-1] = 0;
+                fprintf(stdout,"%s",buf);
+                if (kw)
+                {
+                  set_mode(OFF, MODE_KEYWORD);
+                }
+                print_char_html(tmpc);
+                bufidx = 0;
+                buf[0] = 0;
+            }
+        }
+        else if (echo) print_char_html(c);
+
+        if (c=='\n' && mode != REM_STAR)
+        {
+            mode = START;
+        }
+   }
+
+   fclose(in);
+   fprintf(stdout,"
\n"); + fprintf(stdout, + "\n"); + fprintf(stdout, + "\n"); + + return 0; +} diff --git a/contrib/webcscope/icons/CVS/Entries b/contrib/webcscope/icons/CVS/Entries new file mode 100644 index 0000000..22f20b0 --- /dev/null +++ b/contrib/webcscope/icons/CVS/Entries @@ -0,0 +1,10 @@ +/back.gif/1.3/Fri Jun 29 15:58:07 2001/-kb/ +/bomb.gif/1.3/Fri Jun 29 15:58:07 2001/-kb/ +/c.gif/1.3/Fri Jun 29 15:58:07 2001/-kb/ +/down.gif/1.3/Fri Jun 29 15:58:07 2001/-kb/ +/folder.gif/1.3/Fri Jun 29 15:58:07 2001/-kb/ +/folder.open.gif/1.3/Fri Jun 29 15:58:07 2001/-kb/ +/left.gif/1.3/Fri Jun 29 15:58:07 2001/-kb/ +/up.gif/1.3/Fri Jun 29 15:58:07 2001/-kb/ +/world2.gif/1.3/Fri Jun 29 15:58:07 2001/-kb/ +D diff --git a/contrib/webcscope/icons/CVS/Repository b/contrib/webcscope/icons/CVS/Repository new file mode 100644 index 0000000..cf072b6 --- /dev/null +++ b/contrib/webcscope/icons/CVS/Repository @@ -0,0 +1 @@ +cscope/contrib/webcscope/icons diff --git a/contrib/webcscope/icons/CVS/Root b/contrib/webcscope/icons/CVS/Root new file mode 100644 index 0000000..e0eb551 --- /dev/null +++ b/contrib/webcscope/icons/CVS/Root @@ -0,0 +1 @@ +broeker@cscope.cvs.sourceforge.net:/cvsroot/cscope diff --git a/contrib/webcscope/icons/back.gif b/contrib/webcscope/icons/back.gif new file mode 100644 index 0000000..a694ae1 Binary files /dev/null and b/contrib/webcscope/icons/back.gif differ diff --git a/contrib/webcscope/icons/bomb.gif b/contrib/webcscope/icons/bomb.gif new file mode 100644 index 0000000..270fdb1 Binary files /dev/null and b/contrib/webcscope/icons/bomb.gif differ diff --git a/contrib/webcscope/icons/c.gif b/contrib/webcscope/icons/c.gif new file mode 100644 index 0000000..7555b6c Binary files /dev/null and b/contrib/webcscope/icons/c.gif differ diff --git a/contrib/webcscope/icons/down.gif b/contrib/webcscope/icons/down.gif new file mode 100644 index 0000000..a354c87 Binary files /dev/null and b/contrib/webcscope/icons/down.gif differ diff --git a/contrib/webcscope/icons/folder.gif b/contrib/webcscope/icons/folder.gif new file mode 100644 index 0000000..4826460 Binary files /dev/null and b/contrib/webcscope/icons/folder.gif differ diff --git a/contrib/webcscope/icons/folder.open.gif b/contrib/webcscope/icons/folder.open.gif new file mode 100644 index 0000000..30979cb Binary files /dev/null and b/contrib/webcscope/icons/folder.open.gif differ diff --git a/contrib/webcscope/icons/left.gif b/contrib/webcscope/icons/left.gif new file mode 100644 index 0000000..279e671 Binary files /dev/null and b/contrib/webcscope/icons/left.gif differ diff --git a/contrib/webcscope/icons/up.gif b/contrib/webcscope/icons/up.gif new file mode 100644 index 0000000..6d6d6d1 Binary files /dev/null and b/contrib/webcscope/icons/up.gif differ diff --git a/contrib/webcscope/icons/world2.gif b/contrib/webcscope/icons/world2.gif new file mode 100644 index 0000000..e3203f7 Binary files /dev/null and b/contrib/webcscope/icons/world2.gif differ diff --git a/contrib/xcscope/CVS/Entries b/contrib/xcscope/CVS/Entries new file mode 100644 index 0000000..f7439f6 --- /dev/null +++ b/contrib/xcscope/CVS/Entries @@ -0,0 +1,3 @@ +/cscope-indexer/1.2/Thu Jun 28 04:39:47 2001// +/xcscope.el/1.14/Wed Apr 10 16:59:00 2002// +D diff --git a/contrib/xcscope/CVS/Repository b/contrib/xcscope/CVS/Repository new file mode 100644 index 0000000..f1ac4c6 --- /dev/null +++ b/contrib/xcscope/CVS/Repository @@ -0,0 +1 @@ +cscope/contrib/xcscope diff --git a/contrib/xcscope/CVS/Root b/contrib/xcscope/CVS/Root new file mode 100644 index 0000000..e0eb551 --- /dev/null +++ b/contrib/xcscope/CVS/Root @@ -0,0 +1 @@ +broeker@cscope.cvs.sourceforge.net:/cvsroot/cscope diff --git a/contrib/xcscope/cscope-indexer b/contrib/xcscope/cscope-indexer new file mode 100755 index 0000000..13c0ae2 --- /dev/null +++ b/contrib/xcscope/cscope-indexer @@ -0,0 +1,166 @@ +#! /bin/sh +############################################################################### +# +# File: cscope-indexer +# RCS: $Header: /cvsroot/cscope/cscope/contrib/xcscope/cscope-indexer,v 1.2 2001/06/28 04:39:47 darrylo Exp $ +# Description: Script to index files for cscope +# +# This script generates a list of files to index +# (cscope.out), which is then (optionally) used to +# generate a cscope database. You can use this script +# to just build a list of files, or it can be used to +# build a list and database. This script is not used to +# just build a database (skipping the list of files +# step), as this can be simply done by just calling +# "cscope -b". +# +# Normally, cscope will do its own indexing, but this +# script can be used to force indexing. This is useful +# if you need to recurse into subdirectories, or have +# many files to index (you can run this script from a +# cron job, during the night). It is especially useful +# for large projects, which can contstantly have source +# files added and deleted; by using this script, the +# changing sources files are automatically handled. +# +# Currently, any paths containing "/CVS/" or "/RCS/" are +# stripped out (ignored). +# +# This script is written to use only basic shell features, as +# not all shells have advanced features. +# +# Author: Darryl Okahata +# Created: Thu Apr 27 17:12:14 2000 +# Modified: Tue Jun 19 09:47:45 2001 (Darryl Okahata) darrylo@soco.agilent.com +# Language: Shell-script +# Package: N/A +# Status: Experimental +# +# (C) Copyright 2000, Darryl Okahata, all rights reserved. +# +############################################################################### +# +# Usage: +# +# cscope-indexer [ -v ] [-f database_file ] [-i list_file ] [ -l ] [ -r ] +# +# where: +# +# -f database_file +# Specifies the cscope database file (default: cscope.out). +# +# -i list_file +# Specifies the name of the file into which the list of files +# to index is placed (default: cscope.files). +# +# -l +# Suppress the generation/updating of the cscope database +# file. Only a list of files is generated. +# +# -r +# Recurse into subdirectories to locate files to index. +# Without this option, only the current directory is +# searched. +# +# -v +# Be verbose. Output simple progress messages. +# +# +############################################################################### +set -e + +# May have to edit this: +PATH="/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin:$PATH" +export PATH + +LIST_ONLY= +DIR='.' +LIST_FILE='cscope.files' +DATABASE_FILE='cscope.out' +RECURSE= +VERBOSE= +export DIR RECURSE # Need to pass these to subprocesses + +while [ -n "$1" ] +do + case "$1" in + -f) + if [ "X$2" = "X" ] + then + echo "$0: No database file specified" >&2 + exit 1 + fi + DATABASE_FILE="$2" + shift + ;; + -i) + if [ "X$2" = "X" ] + then + echo "$0: No list file specified" >&2 + exit 1 + fi + LIST_FILE="$2" + shift + ;; + -l) + LIST_ONLY=1 + ;; + -r) + RECURSE=1 + ;; + -v) + VERBOSE=1 + ;; + *) + DIR="$1" + ;; + esac + shift +done + +cd $DIR + +if [ "X$VERBOSE" != "X" ] +then + echo "Creating list of files to index ..." +fi + +( + if [ "X$RECURSE" = "X" ] + then + # Ugly, inefficient, but it works. + for f in * + do + echo "$DIR/$f" + done + else + find $DIR \( -type f -o -type l \) + fi +) | \ + egrep -i '\.([chly](xx|pp)*|cc|hh)$' | \ + sed -e '/\/CVS\//d' -e '/\/RCS\//d' -e 's/^\.\///' | \ + sort > $LIST_FILE + +if [ "X$VERBOSE" != "X" ] +then + echo "Creating list of files to index ... done" +fi + +if [ "X$LIST_ONLY" != "X" ] +then + exit 0 +fi + +if [ "X$VERBOSE" != "X" ] +then + echo "Indexing files ..." +fi + +cscope -b -i $LIST_FILE -f $DATABASE_FILE + +if [ "X$VERBOSE" != "X" ] +then + echo "Indexing files ... done" +fi + +exit 0 diff --git a/contrib/xcscope/xcscope.el b/contrib/xcscope/xcscope.el new file mode 100644 index 0000000..ce382a4 --- /dev/null +++ b/contrib/xcscope/xcscope.el @@ -0,0 +1,2463 @@ +; -*-Emacs-Lisp-*- +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; File: xcscope.el +; RCS: $RCSfile: xcscope.el,v $ $Revision: 1.14 $ $Date: 2002/04/10 16:59:00 $ $Author: darrylo $ +; Description: cscope interface for (X)Emacs +; Author: Darryl Okahata +; Created: Wed Apr 19 17:03:38 2000 +; Modified: Thu Apr 4 17:22:22 2002 (Darryl Okahata) darrylo@soco.agilent.com +; Language: Emacs-Lisp +; Package: N/A +; Status: Experimental +; +; (C) Copyright 2000, 2001, 2002, Darryl Okahata , +; all rights reserved. +; GNU Emacs enhancements (C) Copyright 2001, +; Triet H. Lai +; Fuzzy matching and navigation code (C) Copyright 2001, +; Steven Elliott +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ALPHA VERSION 0.96 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This is a cscope interface for (X)Emacs. +;; It currently runs under Unix only. +;; +;; Using cscope, you can easily search for where symbols are used and defined. +;; Cscope is designed to answer questions like: +;; +;; Where is this variable used? +;; What is the value of this preprocessor symbol? +;; Where is this function in the source files? +;; What functions call this function? +;; What functions are called by this function? +;; Where does the message "out of space" come from? +;; Where is this source file in the directory structure? +;; What files include this header file? +;; +;; Send comments to one of: darrylo@soco.agilent.com +;; darryl_okahata@agilent.com +;; darrylo@sonic.net +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ***** INSTALLATION ***** +;; +;; * NOTE: this interface currently runs under Unix only. +;; +;; This module needs a shell script called "cscope-indexer", which +;; should have been supplied along with this emacs-lisp file. The +;; purpose of "cscope-indexer" is to create and optionally maintain +;; the cscope databases. If all of your source files are in one +;; directory, you don't need this script; it's very nice to have, +;; though, as it handles recursive subdirectory indexing, and can be +;; used in a nightly or weekly cron job to index very large source +;; repositories. See the beginning of the file, "cscope-indexer", for +;; usage information. +;; +;; Installation steps: +;; +;; 0. (It is, of course, assumed that cscope is already properly +;; installed on the current system.) +;; +;; 1. Install the "cscope-indexer" script into some convenient +;; directory in $PATH. The only real constraint is that (X)Emacs +;; must be able to find and execute it. You may also have to edit +;; the value of PATH in the script, although this is unlikely; the +;; majority of people should be able to use the script, "as-is". +;; +;; 2. Make sure that the "cscope-indexer" script is executable. In +;; particular, if you had to ftp this file, it is probably no +;; longer executable. +;; +;; 3. Put this emacs-lisp file somewhere where (X)Emacs can find it. It +;; basically has to be in some directory listed in "load-path". +;; +;; 4. Edit your ~/.emacs file to add the line: +;; +;; (require 'xcscope) +;; +;; 5. If you intend to use xcscope.el often you can optionally edit your +;; ~/.emacs file to add keybindings that reduce the number of keystrokes +;; required. For example, the following will add "C-f#" keybindings, which +;; are easier to type than the usual "C-c s" prefixed keybindings. Note +;; that specifying "global-map" instead of "cscope:map" makes the +;; keybindings available in all buffers: +;; +;; (define-key global-map [(control f3)] 'cscope-set-initial-directory) +;; (define-key global-map [(control f4)] 'cscope-unset-initial-directory) +;; (define-key global-map [(control f5)] 'cscope-find-this-symbol) +;; (define-key global-map [(control f6)] 'cscope-find-global-definition) +;; (define-key global-map [(control f7)] +;; 'cscope-find-global-definition-no-prompting) +;; (define-key global-map [(control f8)] 'cscope-pop-mark) +;; (define-key global-map [(control f9)] 'cscope-next-symbol) +;; (define-key global-map [(control f10)] 'cscope-next-file) +;; (define-key global-map [(control f11)] 'cscope-prev-symbol) +;; (define-key global-map [(control f12)] 'cscope-prev-file) +;; (define-key global-map [(meta f9)] 'cscope-display-buffer) +;; (defin-ekey global-map [(meta f10)] 'cscope-display-buffer-toggle) +;; +;; 6. Restart (X)Emacs. That's it. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ***** USING THIS MODULE ***** +;; +;; * Basic usage: +;; +;; If all of your C/C++/lex/yacc source files are in the same +;; directory, you can just start using this module. If your files are +;; spread out over multiple directories, see "Advanced usage", below. +;; +;; Just edit a source file, and use the pull-down or pop-up (button 3) +;; menus to select one of: +;; +;; Find symbol +;; Find global definition +;; Find called functions +;; Find functions calling a function +;; Find text string +;; Find egrep pattern +;; Find a file +;; Find files #including a file +;; +;; The cscope database will be automatically created in the same +;; directory as the source files (assuming that you've never used +;; cscope before), and a buffer will pop-up displaying the results. +;; You can then use button 2 (the middle button) on the mouse to edit +;; the selected file, or you can move the text cursor over a selection +;; and press [Enter]. +;; +;; Hopefully, the interface should be fairly intuitive. +;; +;; +;; * Locating the cscope databases: +;; +;; This module will first use the variable, `cscope-database-regexps', +;; to search for a suitable database directory. If a database location +;; cannot be found using this variable then a search is begun at the +;; variable, `cscope-initial-directory', if set, or the current +;; directory otherwise. If the directory is not a cscope database +;; directory then the directory's parent, parent's parent, etc. is +;; searched until a cscope database directory is found, or the root +;; directory is reached. If the root directory is reached, the current +;; directory will be used. +;; +;; A cscope database directory is one in which EITHER a cscope database +;; file (e.g., "cscope.out") OR a cscope file list (e.g., +;; "cscope.files") exists. If only "cscope.files" exists, the +;; corresponding "cscope.out" will be automatically created by cscope +;; when a search is done. By default, the cscope database file is called +;; "cscope.out", but this can be changed (on a global basis) via the +;; variable, `cscope-database-file'. There is limited support for cscope +;; databases that are named differently than that given by +;; `cscope-database-file', using the variable, `cscope-database-regexps'. +;; +;; Note that the variable, `cscope-database-regexps', is generally not +;; needed, as the normal hierarchical database search is sufficient +;; for placing and/or locating the cscope databases. However, there +;; may be cases where it makes sense to place the cscope databases +;; away from where the source files are kept; in this case, this +;; variable is used to determine the mapping. One use for this +;; variable is when you want to share the database file with other +;; users; in this case, the database may be located in a directory +;; separate from the source files. +;; +;; Setting the variable, `cscope-initial-directory', is useful when a +;; search is to be expanded by specifying a cscope database directory +;; that is a parent of the directory that this module would otherwise +;; use. For example, consider a project that contains the following +;; cscope database directories: +;; +;; /users/jdoe/sources +;; /users/jdoe/sources/proj1 +;; /users/jdoe/sources/proj2 +;; +;; If a search is initiated from a .c file in /users/jdoe/sources/proj1 +;; then (assuming the variable, `cscope-database-regexps', is not set) +;; /users/jdoe/sources/proj1 will be used as the cscope data base directory. +;; Only matches in files in /users/jdoe/sources/proj1 will be found. This +;; can be remedied by typing "C-c s a" and then "M-del" to remove single +;; path element in order to use a cscope database directory of +;; /users/jdoe/sources. Normal searching can be restored by typing "C-c s A". +;; +;; +;; * Keybindings: +;; +;; All keybindings use the "C-c s" prefix, but are usable only while +;; editing a source file, or in the cscope results buffer: +;; +;; C-c s s Find symbol. +;; C-c s d Find global definition. +;; C-c s g Find global definition (alternate binding). +;; C-c s G Find global definition without prompting. +;; C-c s c Find functions calling a function. +;; C-c s C Find called functions (list functions called +;; from a function). +;; C-c s t Find text string. +;; C-c s e Find egrep pattern. +;; C-c s f Find a file. +;; C-c s i Find files #including a file. +;; +;; These pertain to navigation through the search results: +;; +;; C-c s b Display *cscope* buffer. +;; C-c s B Auto display *cscope* buffer toggle. +;; C-c s n Next symbol. +;; C-c s N Next file. +;; C-c s p Previous symbol. +;; C-c s P Previous file. +;; C-c s u Pop mark. +;; +;; These pertain to setting and unsetting the variable, +;; `cscope-initial-directory', (location searched for the cscope database +;; directory): +;; +;; C-c s a Set initial directory. +;; C-c s A Unset initial directory. +;; +;; These pertain to cscope database maintenance: +;; +;; C-c s L Create list of files to index. +;; C-c s I Create list and index. +;; C-c s E Edit list of files to index. +;; C-c s W Locate this buffer's cscope directory +;; ("W" --> "where"). +;; C-c s S Locate this buffer's cscope directory. +;; (alternate binding: "S" --> "show"). +;; C-c s T Locate this buffer's cscope directory. +;; (alternate binding: "T" --> "tell"). +;; C-c s D Dired this buffer's directory. +;; +;; +;; * Advanced usage: +;; +;; If the source files are spread out over multiple directories, +;; you've got a few choices: +;; +;; [ NOTE: you will need to have the script, "cscope-indexer", +;; properly installed in order for the following to work. ] +;; +;; 1. If all of the directories exist below a common directory +;; (without any extraneous, unrelated subdirectories), you can tell +;; this module to place the cscope database into the top-level, +;; common directory. This assumes that you do not have any cscope +;; databases in any of the subdirectories. If you do, you should +;; delete them; otherwise, they will take precedence over the +;; top-level database. +;; +;; If you do have cscope databases in any subdirectory, the +;; following instructions may not work right. +;; +;; It's pretty easy to tell this module to use a top-level, common +;; directory: +;; +;; a. Make sure that the menu pick, "Cscope/Index recursively", is +;; checked (the default value). +;; +;; b. Select the menu pick, "Cscope/Create list and index", and +;; specify the top-level directory. This will run the script, +;; "cscope-indexer", in the background, so you can do other +;; things if indexing takes a long time. A list of files to +;; index will be created in "cscope.files", and the cscope +;; database will be created in "cscope.out". +;; +;; Once this has been done, you can then use the menu picks +;; (described in "Basic usage", above) to search for symbols. +;; +;; Note, however, that, if you add or delete source files, you'll +;; have to either rebuild the database using the above procedure, +;; or edit the file, "cscope.files" to add/delete the names of the +;; source files. To edit this file, you can use the menu pick, +;; "Cscope/Edit list of files to index". +;; +;; +;; 2. If most of the files exist below a common directory, but a few +;; are outside, you can use the menu pick, "Cscope/Create list of +;; files to index", and specify the top-level directory. Make sure +;; that "Cscope/Index recursively", is checked before you do so, +;; though. You can then edit the list of files to index using the +;; menu pick, "Cscope/Edit list of files to index". Just edit the +;; list to include any additional source files not already listed. +;; +;; Once you've created, edited, and saved the list, you can then +;; use the menu picks described under "Basic usage", above, to +;; search for symbols. The first time you search, you will have to +;; wait a while for cscope to fully index the source files, though. +;; If you have a lot of source files, you may want to manually run +;; cscope to build the database: +;; +;; cd top-level-directory # or wherever +;; rm -f cscope.out # not always necessary +;; cscope -b +;; +;; +;; 3. If the source files are scattered in many different, unrelated +;; places, you'll have to manually create cscope.files and put a +;; list of all pathnames into it. Then build the database using: +;; +;; cd some-directory # wherever cscope.files exists +;; rm -f cscope.out # not always necessary +;; cscope -b +;; +;; Next, read the documentation for the variable, +;; "cscope-database-regexps", and set it appropriately, such that +;; the above-created cscope database will be referenced when you +;; edit a related source file. +;; +;; Once this has been done, you can then use the menu picks +;; described under "Basic usage", above, to search for symbols. +;; +;; +;; * Interesting configuration variables: +;; +;; "cscope-truncate-lines" +;; This is the value of `truncate-lines' to use in cscope +;; buffers; the default is the current setting of +;; `truncate-lines'. This variable exists because it can be +;; easier to read cscope buffers with truncated lines, while +;; other buffers do not have truncated lines. +;; +;; "cscope-use-relative-paths" +;; If non-nil, use relative paths when creating the list of files +;; to index. The path is relative to the directory in which the +;; cscope database will be created. If nil, absolute paths will +;; be used. Absolute paths are good if you plan on moving the +;; database to some other directory (if you do so, you'll +;; probably also have to modify `cscope-database-regexps'). +;; Absolute paths may also be good if you share the database file +;; with other users (you'll probably want to specify some +;; automounted network path for this). +;; +;; "cscope-index-recursively" +;; If non-nil, index files in the current directory and all +;; subdirectories. If nil, only files in the current directory +;; are indexed. This variable is only used when creating the +;; list of files to index, or when creating the list of files and +;; the corresponding cscope database. +;; +;; "cscope-name-line-width" +;; The width of the combined "function name:line number" field in +;; the cscope results buffer. If negative, the field is +;; left-justified. +;; +;; "cscope-do-not-update-database" +;; If non-nil, never check and/or update the cscope database when +;; searching. Beware of setting this to non-nil, as this will +;; disable automatic database creation, updating, and +;; maintenance. +;; +;; "cscope-display-cscope-buffer" +;; If non-nil, display the *cscope* buffer after each search +;; (default). This variable can be set in order to reduce the +;; number of keystrokes required to navigate through the matches. +;; +;; "cscope-database-regexps" +;; List to force directory-to-cscope-database mappings. +;; This is a list of `(REGEXP DBLIST [ DBLIST ... ])', where: +;; +;; REGEXP is a regular expression matched against the current buffer's +;; current directory. The current buffer is typically some source file, +;; and you're probably searching for some symbol in or related to this +;; file. Basically, this regexp is used to relate the current directory +;; to a cscope database. You need to start REGEXP with "^" if you want +;; to match from the beginning of the current directory. +;; +;; DBLIST is a list that contains one or more of: +;; +;; ( DBDIR ) +;; ( DBDIR ( OPTIONS ) ) +;; ( t ) +;; t +;; +;; Here, DBDIR is a directory (or a file) that contains a cscope +;; database. If DBDIR is a directory, then it is expected that the +;; cscope database, if present, has the filename given by the variable, +;; `cscope-database-file'; if DBDIR is a file, then DBDIR is the path +;; name to a cscope database file (which does not have to be the same as +;; that given by `cscope-database-file'). If only DBDIR is specified, +;; then that cscope database will be searched without any additional +;; cscope command-line options. If OPTIONS is given, then OPTIONS is a +;; list of strings, where each string is a separate cscope command-line +;; option. +;; +;; In the case of "( t )", this specifies that the search is to use the +;; normal hierarchical database search. This option is used to +;; explicitly search using the hierarchical database search either before +;; or after other cscope database directories. +;; +;; If "t" is specified (not inside a list), this tells the searching +;; mechanism to stop searching if a match has been found (at the point +;; where "t" is encountered). This is useful for those projects that +;; consist of many subprojects. You can specify the most-used +;; subprojects first, followed by a "t", and then followed by a master +;; cscope database directory that covers all subprojects. This will +;; cause the most-used subprojects to be searched first (hopefully +;; quickly), and the search will then stop if a match was found. If not, +;; the search will continue using the master cscope database directory. +;; +;; Here, `cscope-database-regexps' is generally not used, as the normal +;; hierarchical database search is sufficient for placing and/or locating +;; the cscope databases. However, there may be cases where it makes +;; sense to place the cscope databases away from where the source files +;; are kept; in this case, this variable is used to determine the +;; mapping. +;; +;; This module searches for the cscope databases by first using this +;; variable; if a database location cannot be found using this variable, +;; then the current directory is searched, then the parent, then the +;; parent's parent, until a cscope database directory is found, or the +;; root directory is reached. If the root directory is reached, the +;; current directory will be used. +;; +;; A cscope database directory is one in which EITHER a cscope database +;; file (e.g., "cscope.out") OR a cscope file list (e.g., +;; "cscope.files") exists. If only "cscope.files" exists, the +;; corresponding "cscope.out" will be automatically created by cscope +;; when a search is done. By default, the cscope database file is called +;; "cscope.out", but this can be changed (on a global basis) via the +;; variable, `cscope-database-file'. There is limited support for cscope +;; databases that are named differently than that given by +;; `cscope-database-file', using the variable, `cscope-database-regexps'. +;; +;; Here is an example of `cscope-database-regexps': +;; +;; (setq cscope-database-regexps +;; '( +;; ( "^/users/jdoe/sources/proj1" +;; ( t ) +;; ( "/users/jdoe/sources/proj2") +;; ( "/users/jdoe/sources/proj3/mycscope.out") +;; ( "/users/jdoe/sources/proj4") +;; t +;; ( "/some/master/directory" ("-d" "-I/usr/local/include") ) +;; ) +;; ( "^/users/jdoe/sources/gnome/" +;; ( "/master/gnome/database" ("-d") ) +;; ) +;; )) +;; +;; If the current buffer's directory matches the regexp, +;; "^/users/jdoe/sources/proj1", then the following search will be +;; done: +;; +;; 1. First, the normal hierarchical database search will be used to +;; locate a cscope database. +;; +;; 2. Next, searches will be done using the cscope database +;; directories, "/users/jdoe/sources/proj2", +;; "/users/jdoe/sources/proj3/mycscope.out", and +;; "/users/jdoe/sources/proj4". Note that, instead of the file, +;; "cscope.out", the file, "mycscope.out", will be used in the +;; directory "/users/jdoe/sources/proj3". +;; +;; 3. If a match was found, searching will stop. +;; +;; 4. If a match was not found, searching will be done using +;; "/some/master/directory", and the command-line options "-d" +;; and "-I/usr/local/include" will be passed to cscope. +;; +;; If the current buffer's directory matches the regexp, +;; "^/users/jdoe/sources/gnome", then the following search will be +;; done: +;; +;; The search will be done only using the directory, +;; "/master/gnome/database". The "-d" option will be passed to +;; cscope. +;; +;; If the current buffer's directory does not match any of the above +;; regexps, then only the normal hierarchical database search will be +;; done. +;; +;; +;; * Other notes: +;; +;; 1. The script, "cscope-indexer", uses a sed command to determine +;; what is and is not a C/C++/lex/yacc source file. It's idea of a +;; source file may not correspond to yours. +;; +;; 2. This module is called, "xcscope", because someone else has +;; already written a "cscope.el" (although it's quite old). +;; +;; +;; * KNOWN BUGS: +;; +;; 1. Cannot handle whitespace in directory or file names. +;; +;; 2. By default, colored faces are used to display results. If you happen +;; to use a black background, part of the results may be invisible +;; (because the foreground color may be black, too). There are at least +;; two solutions for this: +;; +;; 2a. Turn off colored faces, by setting `cscope-use-face' to `nil', +;; e.g.: +;; +;; (setq cscope-use-face nil) +;; +;; 2b. Explicitly set colors for the faces used by cscope. The faces +;; are: +;; +;; cscope-file-face +;; cscope-function-face +;; cscope-line-number-face +;; cscope-line-face +;; cscope-mouse-face +;; +;; The face most likely to cause problems (e.g., black-on-black +;; color) is `cscope-line-face'. +;; +;; 3. The support for cscope databases different from that specified by +;; `cscope-database-file' is quirky. If the file does not exist, it +;; will not be auto-created (unlike files names by +;; `cscope-database-file'). You can manually force the file to be +;; created by using touch(1) to create a zero-length file; the +;; database will be created the next time a search is done. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'easymenu) + + +(defgroup cscope nil + "Cscope interface for (X)Emacs. +Using cscope, you can easily search for where symbols are used and defined. +It is designed to answer questions like: + + Where is this variable used? + What is the value of this preprocessor symbol? + Where is this function in the source files? + What functions call this function? + What functions are called by this function? + Where does the message \"out of space\" come from? + Where is this source file in the directory structure? + What files include this header file? +" + :prefix "cscope-" + :group 'tools) + + +(defcustom cscope-do-not-update-database nil + "*If non-nil, never check and/or update the cscope database when searching. +Beware of setting this to non-nil, as this will disable automatic database +creation, updating, and maintenance." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-database-regexps nil + "*List to force directory-to-cscope-database mappings. +This is a list of `(REGEXP DBLIST [ DBLIST ... ])', where: + +REGEXP is a regular expression matched against the current buffer's +current directory. The current buffer is typically some source file, +and you're probably searching for some symbol in or related to this +file. Basically, this regexp is used to relate the current directory +to a cscope database. You need to start REGEXP with \"^\" if you want +to match from the beginning of the current directory. + +DBLIST is a list that contains one or more of: + + ( DBDIR ) + ( DBDIR ( OPTIONS ) ) + ( t ) + t + +Here, DBDIR is a directory (or a file) that contains a cscope database. +If DBDIR is a directory, then it is expected that the cscope database, +if present, has the filename given by the variable, +`cscope-database-file'; if DBDIR is a file, then DBDIR is the path name +to a cscope database file (which does not have to be the same as that +given by `cscope-database-file'). If only DBDIR is specified, then that +cscope database will be searched without any additional cscope +command-line options. If OPTIONS is given, then OPTIONS is a list of +strings, where each string is a separate cscope command-line option. + +In the case of \"( t )\", this specifies that the search is to use the +normal hierarchical database search. This option is used to +explicitly search using the hierarchical database search either before +or after other cscope database directories. + +If \"t\" is specified (not inside a list), this tells the searching +mechanism to stop searching if a match has been found (at the point +where \"t\" is encountered). This is useful for those projects that +consist of many subprojects. You can specify the most-used +subprojects first, followed by a \"t\", and then followed by a master +cscope database directory that covers all subprojects. This will +cause the most-used subprojects to be searched first (hopefully +quickly), and the search will then stop if a match was found. If not, +the search will continue using the master cscope database directory. + +Here, `cscope-database-regexps' is generally not used, as the normal +hierarchical database search is sufficient for placing and/or locating +the cscope databases. However, there may be cases where it makes +sense to place the cscope databases away from where the source files +are kept; in this case, this variable is used to determine the +mapping. + +This module searches for the cscope databases by first using this +variable; if a database location cannot be found using this variable, +then the current directory is searched, then the parent, then the +parent's parent, until a cscope database directory is found, or the +root directory is reached. If the root directory is reached, the +current directory will be used. + +A cscope database directory is one in which EITHER a cscope database +file (e.g., \"cscope.out\") OR a cscope file list (e.g., +\"cscope.files\") exists. If only \"cscope.files\" exists, the +corresponding \"cscope.out\" will be automatically created by cscope +when a search is done. By default, the cscope database file is called +\"cscope.out\", but this can be changed (on a global basis) via the +variable, `cscope-database-file'. There is limited support for cscope +databases that are named differently than that given by +`cscope-database-file', using the variable, `cscope-database-regexps'. + +Here is an example of `cscope-database-regexps': + + (setq cscope-database-regexps + '( + ( \"^/users/jdoe/sources/proj1\" + ( t ) + ( \"/users/jdoe/sources/proj2\") + ( \"/users/jdoe/sources/proj3/mycscope.out\") + ( \"/users/jdoe/sources/proj4\") + t + ( \"/some/master/directory\" (\"-d\" \"-I/usr/local/include\") ) + ) + ( \"^/users/jdoe/sources/gnome/\" + ( \"/master/gnome/database\" (\"-d\") ) + ) + )) + +If the current buffer's directory matches the regexp, +\"^/users/jdoe/sources/proj1\", then the following search will be +done: + + 1. First, the normal hierarchical database search will be used to + locate a cscope database. + + 2. Next, searches will be done using the cscope database + directories, \"/users/jdoe/sources/proj2\", + \"/users/jdoe/sources/proj3/mycscope.out\", and + \"/users/jdoe/sources/proj4\". Note that, instead of the file, + \"cscope.out\", the file, \"mycscope.out\", will be used in the + directory \"/users/jdoe/sources/proj3\". + + 3. If a match was found, searching will stop. + + 4. If a match was not found, searching will be done using + \"/some/master/directory\", and the command-line options \"-d\" + and \"-I/usr/local/include\" will be passed to cscope. + +If the current buffer's directory matches the regexp, +\"^/users/jdoe/sources/gnome\", then the following search will be +done: + + The search will be done only using the directory, + \"/master/gnome/database\". The \"-d\" option will be passed to + cscope. + +If the current buffer's directory does not match any of the above +regexps, then only the normal hierarchical database search will be +done. + +" + :type '(repeat (list :format "%v" + (choice :value "" + (regexp :tag "Buffer regexp") + string) + (choice :value "" + (directory :tag "Cscope database directory") + string) + (string :value "" + :tag "Optional cscope command-line arguments") + )) + :group 'cscope) +(defcustom cscope-name-line-width -30 + "*The width of the combined \"function name:line number\" field in the +cscope results buffer. If negative, the field is left-justified." + :type 'integer + :group 'cscope) + + +(defcustom cscope-truncate-lines truncate-lines + "*The value of `truncate-lines' to use in cscope buffers. +This variable exists because it can be easier to read cscope buffers +with truncated lines, while other buffers do not have truncated lines." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-display-times t + "*If non-nil, display how long each search took. +The elasped times are in seconds. Floating-point support is required +for this to work." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-program "cscope" + "*The pathname of the cscope executable to use." + :type 'string + :group 'cscope) + + +(defcustom cscope-index-file "cscope.files" + "*The name of the cscope file list file." + :type 'string + :group 'cscope) + + +(defcustom cscope-database-file "cscope.out" + "*The name of the cscope database file." + :type 'string + :group 'cscope) + + +(defcustom cscope-edit-single-match t + "*If non-nil and only one match is output, edit the matched location." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-display-cscope-buffer t + "*If non-nil automatically display the *cscope* buffer after each search." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-stop-at-first-match-dir nil + "*If non-nil, stop searching through multiple databases if a match is found. +This option is useful only if multiple cscope database directories are being +used. When multiple databases are searched, setting this variable to non-nil +will cause searches to stop when a search outputs anything; no databases after +this one will be searched." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-use-relative-paths t + "*If non-nil, use relative paths when creating the list of files to index. +The path is relative to the directory in which the cscope database +will be created. If nil, absolute paths will be used. Absolute paths +are good if you plan on moving the database to some other directory +(if you do so, you'll probably also have to modify +\`cscope-database-regexps\'). Absolute paths may also be good if you +share the database file with other users (you\'ll probably want to +specify some automounted network path for this)." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-index-recursively t + "*If non-nil, index files in the current directory and all subdirectories. +If nil, only files in the current directory are indexed. This +variable is only used when creating the list of files to index, or +when creating the list of files and the corresponding cscope database." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-no-mouse-prompts nil + "*If non-nil, use the symbol under the cursor instead of prompting. +Do not prompt for a value, except for when seaching for a egrep pattern +or a file." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-suppress-empty-matches t + "*If non-nil, delete empty matches.") + + +(defcustom cscope-indexing-script "cscope-indexer" + "*The shell script used to create cscope indices." + :type 'string + :group 'cscope) + + +(defcustom cscope-symbol-chars "A-Za-z0-9_" + "*A string containing legal characters in a symbol. +The current syntax table should really be used for this." + :type 'string + :group 'cscope) + + +(defcustom cscope-filename-chars "-.,/A-Za-z0-9_~!@#$%&+=\\\\" + "*A string containing legal characters in a symbol. +The current syntax table should really be used for this." + :type 'string + :group 'cscope) + + +(defcustom cscope-allow-arrow-overlays t + "*If non-nil, use an arrow overlay to show target lines. +Arrow overlays are only used when the following functions are used: + + cscope-show-entry-other-window + cscope-show-next-entry-other-window + cscope-show-prev-entry-other-window + +The arrow overlay is removed when other cscope functions are used. +Note that the arrow overlay is not an actual part of the text, and can +be removed by quitting the cscope buffer." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-overlay-arrow-string "=>" + "*The overlay string to use when displaying arrow overlays." + :type 'string + :group 'cscope) + + +(defvar cscope-minor-mode-hooks nil + "List of hooks to call when entering cscope-minor-mode.") + + +(defconst cscope-separator-line + "-------------------------------------------------------------------------------\n" + "Line of text to use as a visual separator. +Must end with a newline.") + + +;;;; +;;;; Faces for fontification +;;;; + +(defcustom cscope-use-face t + "*Whether to use text highlighting (à la font-lock) or not." + :group 'cscope + :type '(boolean)) + + +(defface cscope-file-face + '((((class color) (background dark)) + (:foreground "yellow")) + (((class color) (background light)) + (:foreground "blue")) + (t (:bold t))) + "Face used to highlight file name in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-function-face + '((((class color) (background dark)) + (:foreground "cyan")) + (((class color) (background light)) + (:foreground "magenta")) + (t (:bold t))) + "Face used to highlight function name in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-line-number-face + '((((class color) (background dark)) + (:foreground "red")) + (((class color) (background light)) + (:foreground "red")) + (t (:bold t))) + "Face used to highlight line number in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-line-face + '((((class color) (background dark)) + (:foreground "green")) + (((class color) (background light)) + (:foreground "black")) + (t (:bold nil))) + "Face used to highlight the rest of line in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-mouse-face + '((((class color) (background dark)) + (:foreground "white" :background "blue")) + (((class color) (background light)) + (:foreground "white" :background "blue")) + (t (:bold nil))) + "Face used when mouse pointer is within the region of an entry." + :group 'cscope) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Probably, nothing user-customizable past this point. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defconst cscope-running-in-xemacs (string-match "XEmacs\\|Lucid" emacs-version)) + +(defvar cscope-list-entry-keymap nil + "The keymap used in the *cscope* buffer which lists search results.") +(if cscope-list-entry-keymap + nil + (setq cscope-list-entry-keymap (make-keymap)) + (suppress-keymap cscope-list-entry-keymap) + ;; The following section does not appear in the "Cscope" menu. + (if cscope-running-in-xemacs + (define-key cscope-list-entry-keymap [button2] 'cscope-mouse-select-entry-other-window) + (define-key cscope-list-entry-keymap [mouse-2] 'cscope-mouse-select-entry-other-window)) + (define-key cscope-list-entry-keymap [return] 'cscope-select-entry-other-window) + (define-key cscope-list-entry-keymap " " 'cscope-show-entry-other-window) + (define-key cscope-list-entry-keymap "o" 'cscope-select-entry-one-window) + (define-key cscope-list-entry-keymap "q" 'cscope-bury-buffer) + (define-key cscope-list-entry-keymap "Q" 'cscope-quit) + (define-key cscope-list-entry-keymap "h" 'cscope-help) + (define-key cscope-list-entry-keymap "?" 'cscope-help) + ;; The following line corresponds to be beginning of the "Cscope" menu. + (define-key cscope-list-entry-keymap "s" 'cscope-find-this-symbol) + (define-key cscope-list-entry-keymap "d" 'cscope-find-this-symbol) + (define-key cscope-list-entry-keymap "g" 'cscope-find-global-definition) + (define-key cscope-list-entry-keymap "G" + 'cscope-find-global-definition-no-prompting) + (define-key cscope-list-entry-keymap "c" 'cscope-find-functions-calling-this-function) + (define-key cscope-list-entry-keymap "C" 'cscope-find-called-functions) + (define-key cscope-list-entry-keymap "t" 'cscope-find-this-text-string) + (define-key cscope-list-entry-keymap "e" 'cscope-find-egrep-pattern) + (define-key cscope-list-entry-keymap "f" 'cscope-find-this-file) + (define-key cscope-list-entry-keymap "i" 'cscope-find-files-including-file) + ;; --- (The '---' indicates that this line corresponds to a menu separator.) + (define-key cscope-list-entry-keymap "n" 'cscope-next-symbol) + (define-key cscope-list-entry-keymap "N" 'cscope-next-file) + (define-key cscope-list-entry-keymap "p" 'cscope-prev-symbol) + (define-key cscope-list-entry-keymap "P" 'cscope-prev-file) + (define-key cscope-list-entry-keymap "u" 'cscope-pop-mark) + ;; --- + (define-key cscope-list-entry-keymap "a" 'cscope-set-initial-directory) + (define-key cscope-list-entry-keymap "A" 'cscope-unset-initial-directory) + ;; --- + (define-key cscope-list-entry-keymap "L" 'cscope-create-list-of-files-to-index) + (define-key cscope-list-entry-keymap "I" 'cscope-index-files) + (define-key cscope-list-entry-keymap "E" 'cscope-edit-list-of-files-to-index) + (define-key cscope-list-entry-keymap "W" 'cscope-tell-user-about-directory) + (define-key cscope-list-entry-keymap "S" 'cscope-tell-user-about-directory) + (define-key cscope-list-entry-keymap "T" 'cscope-tell-user-about-directory) + (define-key cscope-list-entry-keymap "D" 'cscope-dired-directory) + ;; The previous line corresponds to be end of the "Cscope" menu. + ) + + +(defvar cscope-list-entry-hook nil + "*Hook run after cscope-list-entry-mode entered.") + + +(defun cscope-list-entry-mode () + "Major mode for jumping/showing entry from the list in the *cscope* buffer. + +\\{cscope-list-entry-keymap}" + (use-local-map cscope-list-entry-keymap) + (setq buffer-read-only t + mode-name "cscope" + major-mode 'cscope-list-entry-mode + overlay-arrow-string cscope-overlay-arrow-string) + (or overlay-arrow-position + (setq overlay-arrow-position (make-marker))) + (run-hooks 'cscope-list-entry-hook)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-output-buffer-name "*cscope*" + "The name of the cscope output buffer.") + + +(defvar cscope-info-buffer-name "*cscope-info*" + "The name of the cscope information buffer.") + + +(defvar cscope-process nil + "The current cscope process.") +(make-variable-buffer-local 'cscope-process) + + +(defvar cscope-process-output nil + "A buffer for holding partial cscope process output.") +(make-variable-buffer-local 'cscope-process-output) + + +(defvar cscope-command-args nil + "Internal variable for holding major command args to pass to cscope.") +(make-variable-buffer-local 'cscope-command-args) + + +(defvar cscope-start-directory nil + "Internal variable used to save the initial start directory. +The results buffer gets reset to this directory when a search has +completely finished.") +(make-variable-buffer-local 'cscope-start-directory) + + +(defvar cscope-search-list nil + "A list of (DIR . FLAGS) entries. +This is a list of database directories to search. Each entry in the list +is a (DIR . FLAGS) cell. DIR is the directory to search, and FLAGS are the +flags to pass to cscope when using this database directory. FLAGS can be +nil (meaning, \"no flags\").") +(make-variable-buffer-local 'cscope-search-list) + + +(defvar cscope-searched-dirs nil + "The list of database directories already searched.") +(make-variable-buffer-local 'cscope-searched-dirs) + + +(defvar cscope-filter-func nil + "Internal variable for holding the filter function to use (if any) when +searching.") +(make-variable-buffer-local 'cscope-filter-func) + + +(defvar cscope-sentinel-func nil + "Internal variable for holding the sentinel function to use (if any) when +searching.") +(make-variable-buffer-local 'cscope-filter-func) + + +(defvar cscope-last-file nil + "The file referenced by the last line of cscope process output.") +(make-variable-buffer-local 'cscope-last-file) + + +(defvar cscope-start-time nil + "The search start time, in seconds.") +(make-variable-buffer-local 'cscope-start-time) + + +(defvar cscope-first-match nil + "The first match result output by cscope.") +(make-variable-buffer-local 'cscope-first-match) + + +(defvar cscope-first-match-point nil + "Buffer location of the first match.") +(make-variable-buffer-local 'cscope-first-match-point) + + +(defvar cscope-item-start nil + "The point location of the start of a search's output, before header info.") +(make-variable-buffer-local 'cscope-output-start) + + +(defvar cscope-output-start nil + "The point location of the start of a search's output.") +(make-variable-buffer-local 'cscope-output-start) + + +(defvar cscope-matched-multiple nil + "Non-nil if cscope output multiple matches.") +(make-variable-buffer-local 'cscope-matched-multiple) + + +(defvar cscope-stop-at-first-match-dir-meta nil + "") +(make-variable-buffer-local 'cscope-stop-at-first-match-dir-meta) + + +(defvar cscope-symbol nil + "The last symbol searched for.") + + +(defvar cscope-adjust t + "True if the symbol searched for (cscope-symbol) should be on +the line specified by the cscope database. In such cases the point will be +adjusted if need be (fuzzy matching).") + + +(defvar cscope-adjust-range 1000 + "How far the point should be adjusted if the symbol is not on the line +specified by the cscope database.") + + +(defvar cscope-marker nil + "The location from which cscope was invoked.") + + +(defvar cscope-marker-window nil + "The window which should contain cscope-marker. This is the window from +which cscope-marker is set when searches are launched from the *cscope* +buffer.") + + +(defvar cscope-marker-ring-length 16 + "Length of the cscope marker ring.") + + +(defvar cscope-marker-ring (make-ring cscope-marker-ring-length) + "Ring of markers which are locations from which cscope was invoked.") + + +(defvar cscope-initial-directory nil + "When set the directory in which searches for the cscope database +directory should begin.") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope:map nil + "The cscope keymap.") +(if cscope:map + nil + (setq cscope:map (make-sparse-keymap)) + ;; The following line corresponds to be beginning of the "Cscope" menu. + (define-key cscope:map "\C-css" 'cscope-find-this-symbol) + (define-key cscope:map "\C-csd" 'cscope-find-global-definition) + (define-key cscope:map "\C-csg" 'cscope-find-global-definition) + (define-key cscope:map "\C-csG" 'cscope-find-global-definition-no-prompting) + (define-key cscope:map "\C-csc" 'cscope-find-functions-calling-this-function) + (define-key cscope:map "\C-csC" 'cscope-find-called-functions) + (define-key cscope:map "\C-cst" 'cscope-find-this-text-string) + (define-key cscope:map "\C-cse" 'cscope-find-egrep-pattern) + (define-key cscope:map "\C-csf" 'cscope-find-this-file) + (define-key cscope:map "\C-csi" 'cscope-find-files-including-file) + ;; --- (The '---' indicates that this line corresponds to a menu separator.) + (define-key cscope:map "\C-csb" 'cscope-display-buffer) + (define-key cscope:map "\C-csB" 'cscope-display-buffer-toggle) + (define-key cscope:map "\C-csn" 'cscope-next-symbol) + (define-key cscope:map "\C-csN" 'cscope-next-file) + (define-key cscope:map "\C-csp" 'cscope-prev-symbol) + (define-key cscope:map "\C-csP" 'cscope-prev-file) + (define-key cscope:map "\C-csu" 'cscope-pop-mark) + ;; --- + (define-key cscope:map "\C-csa" 'cscope-set-initial-directory) + (define-key cscope:map "\C-csA" 'cscope-unset-initial-directory) + ;; --- + (define-key cscope:map "\C-csL" 'cscope-create-list-of-files-to-index) + (define-key cscope:map "\C-csI" 'cscope-index-files) + (define-key cscope:map "\C-csE" 'cscope-edit-list-of-files-to-index) + (define-key cscope:map "\C-csW" 'cscope-tell-user-about-directory) + (define-key cscope:map "\C-csS" 'cscope-tell-user-about-directory) + (define-key cscope:map "\C-csT" 'cscope-tell-user-about-directory) + (define-key cscope:map "\C-csD" 'cscope-dired-directory)) + ;; The previous line corresponds to be end of the "Cscope" menu. + +(easy-menu-define cscope:menu + (list cscope:map cscope-list-entry-keymap) + "cscope menu" + '("Cscope" + [ "Find symbol" cscope-find-this-symbol t ] + [ "Find global definition" cscope-find-global-definition t ] + [ "Find global definition no prompting" + cscope-find-global-definition-no-prompting t ] + [ "Find functions calling a function" + cscope-find-functions-calling-this-function t ] + [ "Find called functions" cscope-find-called-functions t ] + [ "Find text string" cscope-find-this-text-string t ] + [ "Find egrep pattern" cscope-find-egrep-pattern t ] + [ "Find a file" cscope-find-this-file t ] + [ "Find files #including a file" + cscope-find-files-including-file t ] + "-----------" + [ "Display *cscope* buffer" cscope-display-buffer t ] + [ "Auto display *cscope* buffer toggle" + cscope-display-buffer-toggle t ] + [ "Next symbol" cscope-next-symbol t ] + [ "Next file" cscope-next-file t ] + [ "Previous symbol" cscope-prev-symbol t ] + [ "Previous file" cscope-prev-file t ] + [ "Pop mark" cscope-pop-mark t ] + "-----------" + ( "Cscope Database" + [ "Set initial directory" + cscope-set-initial-directory t ] + [ "Unset initial directory" + cscope-unset-initial-directory t ] + "-----------" + [ "Create list of files to index" + cscope-create-list-of-files-to-index t ] + [ "Create list and index" + cscope-index-files t ] + [ "Edit list of files to index" + cscope-edit-list-of-files-to-index t ] + [ "Locate this buffer's cscope directory" + cscope-tell-user-about-directory t ] + [ "Dired this buffer's cscope directory" + cscope-dired-directory t ] + ) + "-----------" + ( "Options" + [ "Auto edit single match" + (setq cscope-edit-single-match + (not cscope-edit-single-match)) + :style toggle :selected cscope-edit-single-match ] + [ "Auto display *cscope* buffer" + (setq cscope-display-cscope-buffer + (not cscope-display-cscope-buffer)) + :style toggle :selected cscope-display-cscope-buffer ] + [ "Stop at first matching database" + (setq cscope-stop-at-first-match-dir + (not cscope-stop-at-first-match-dir)) + :style toggle + :selected cscope-stop-at-first-match-dir ] + [ "Never update cscope database" + (setq cscope-do-not-update-database + (not cscope-do-not-update-database)) + :style toggle :selected cscope-do-not-update-database ] + [ "Index recursively" + (setq cscope-index-recursively + (not cscope-index-recursively)) + :style toggle :selected cscope-index-recursively ] + [ "Suppress empty matches" + (setq cscope-suppress-empty-matches + (not cscope-suppress-empty-matches)) + :style toggle :selected cscope-suppress-empty-matches ] + [ "Use relative paths" + (setq cscope-use-relative-paths + (not cscope-use-relative-paths)) + :style toggle :selected cscope-use-relative-paths ] + [ "No mouse prompts" (setq cscope-no-mouse-prompts + (not cscope-no-mouse-prompts)) + :style toggle :selected cscope-no-mouse-prompts ] + ) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Internal functions and variables +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-common-text-plist + (let (plist) + (setq plist (plist-put plist 'mouse-face 'cscope-mouse-face)) + plist) + "List of common text properties to be added to the entry line.") + + +(defun cscope-insert-with-text-properties (text filename &optional line-number) + "Insert an entry with given TEXT, add entry attributes as text properties. +The text properties to be added: +- common property: mouse-face, +- properties are used to open target file and its location: cscope-file, + cscope-line-number" + (let ((plist cscope-common-text-plist) + beg end) + (setq beg (point)) + (insert text) + (setq end (point) + plist (plist-put plist 'cscope-file filename)) + (if line-number + (progn + (if (stringp line-number) + (setq line-number (string-to-number line-number))) + (setq plist (plist-put plist 'cscope-line-number line-number)) + )) + (add-text-properties beg end plist) + )) + + +(if cscope-running-in-xemacs + (progn + (defalias 'cscope-event-window 'event-window) + (defalias 'cscope-event-point 'event-point) + (defalias 'cscope-recenter 'recenter) + ) + (defun cscope-event-window (event) + "Return the window at which the mouse EVENT occurred." + (posn-window (event-start event))) + (defun cscope-event-point (event) + "Return the point at which the mouse EVENT occurred." + (posn-point (event-start event))) + (defun cscope-recenter (&optional n window) + "Center point in WINDOW and redisplay frame. With N, put point on line N." + (save-selected-window + (if (windowp window) + (select-window window)) + (recenter n))) + ) + + +(defun cscope-show-entry-internal (file line-number + &optional save-mark-p window arrow-p) + "Display the buffer corresponding to FILE and LINE-NUMBER +in some window. If optional argument WINDOW is given, +display the buffer in that WINDOW instead. The window is +not selected. Save point on mark ring before goto +LINE-NUMBER if optional argument SAVE-MARK-P is non-nil. +Put `overlay-arrow-string' if arrow-p is non-nil. +Returns the window displaying BUFFER." + (let (buffer old-pos old-point new-point forward-point backward-point + line-end line-length) + (if (and (stringp file) + (integerp line-number)) + (progn + (unless (file-readable-p file) + (error "%s is not readable or exists" file)) + (setq buffer (find-file-noselect file)) + (if (windowp window) + (set-window-buffer window buffer) + (setq window (display-buffer buffer))) + (set-buffer buffer) + (if (> line-number 0) + (progn + (setq old-pos (point)) + (goto-line line-number) + (setq old-point (point)) + (if (and cscope-adjust cscope-adjust-range) + (progn + ;; Calculate the length of the line specified by cscope. + (end-of-line) + (setq line-end (point)) + (goto-char old-point) + (setq line-length (- line-end old-point)) + + ;; Search forward and backward for the pattern. + (setq forward-point (search-forward + cscope-symbol + (+ old-point + cscope-adjust-range) t)) + (goto-char old-point) + (setq backward-point (search-backward + cscope-symbol + (- old-point + cscope-adjust-range) t)) + (if forward-point + (progn + (if backward-point + (setq new-point + ;; Use whichever of forward-point or + ;; backward-point is closest to old-point. + ;; Give forward-point a line-length advantage + ;; so that if the symbol is on the current + ;; line the current line is chosen. + (if (<= (- (- forward-point line-length) + old-point) + (- old-point backward-point)) + forward-point + backward-point)) + (setq new-point forward-point))) + (if backward-point + (setq new-point backward-point) + (setq new-point old-point))) + (goto-char new-point) + (beginning-of-line) + (setq new-point (point))) + (setq new-point old-point)) + (set-window-point window new-point) + (if (and cscope-allow-arrow-overlays arrow-p) + (set-marker overlay-arrow-position (point)) + (set-marker overlay-arrow-position nil)) + (or (not save-mark-p) + (= old-pos (point)) + (push-mark old-pos)) + )) + + (if cscope-marker + (progn ;; The search was successful. Save the marker so it + ;; can be returned to by cscope-pop-mark. + (ring-insert cscope-marker-ring cscope-marker) + ;; Unset cscope-marker so that moving between matches + ;; (cscope-next-symbol, etc.) does not fill + ;; cscope-marker-ring. + (setq cscope-marker nil))) + (setq cscope-marker-window window) + ) + (message "No entry found at point.")) + ) + window) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; functions in *cscope* buffer which lists the search results +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-select-entry-other-window () + "Display the entry at point in other window, select the window. +Push current point on mark ring and select the entry window." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number)) + window) + (setq window (cscope-show-entry-internal file line-number t)) + (if (windowp window) + (select-window window)) + )) + + +(defun cscope-select-entry-one-window () + "Display the entry at point in one window, select the window." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number)) + window) + (setq window (cscope-show-entry-internal file line-number t)) + (if (windowp window) + (progn + (select-window window) + (sit-for 0) ;; Redisplay hack to allow delete-other-windows + ;; to continue displaying the correct location. + (delete-other-windows window) + )) + )) + + +(defun cscope-select-entry-specified-window (window) + "Display the entry at point in a specified window, select the window." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number))) + (setq window (cscope-show-entry-internal file line-number t window)) + (if (windowp window) + (select-window window)) + )) + + +(defun cscope-mouse-select-entry-other-window (event) + "Display the entry over which the mouse event occurred, select the window." + (interactive "e") + (let ((ep (cscope-event-point event)) + (win (cscope-event-window event)) + buffer file line-number window) + (if ep + (progn + (setq buffer (window-buffer win) + file (get-text-property ep 'cscope-file buffer) + line-number (get-text-property ep 'cscope-line-number buffer)) + (select-window win) + (setq window (cscope-show-entry-internal file line-number t)) + (if (windowp window) + (select-window window)) + ) + (message "No entry found at point.") + ) + )) + + +(defun cscope-show-entry-other-window () + "Display the entry at point in other window. +Point is not saved on mark ring." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number))) + (cscope-show-entry-internal file line-number nil nil t) + )) + + +(defun cscope-buffer-search (do-symbol do-next) + "The body of the following four functions." + (let* (line-number old-point point + (search-file (not do-symbol)) + (search-prev (not do-next)) + (direction (if do-next 1 -1)) + (old-buffer (current-buffer)) + (old-buffer-window (get-buffer-window old-buffer)) + (buffer (get-buffer cscope-output-buffer-name)) + (buffer-window (get-buffer-window (or buffer (error "The *cscope* buffer does not exist yet")))) + ) + (set-buffer buffer) + (setq old-point (point)) + (forward-line direction) + (setq point (point)) + (setq line-number (get-text-property point 'cscope-line-number)) + (while (or (not line-number) + (or (and do-symbol (= line-number -1)) + (and search-file (/= line-number -1)))) + (forward-line direction) + (setq point (point)) + (if (or (and do-next (>= point (point-max))) + (and search-prev (<= point (point-min)))) + (progn + (goto-char old-point) + (error "The %s of the *cscope* buffer has been reached" + (if do-next "end" "beginning")))) + (setq line-number (get-text-property point 'cscope-line-number))) + (if (eq old-buffer buffer) ;; In the *cscope* buffer. + (cscope-show-entry-other-window) + (cscope-select-entry-specified-window old-buffer-window) ;; else + (if (windowp buffer-window) + (set-window-point buffer-window point))) + (set-buffer old-buffer) + )) + + +(defun cscope-display-buffer () + "Display the *cscope* buffer." + (interactive) + (let ((buffer (get-buffer cscope-output-buffer-name))) + (if buffer + (pop-to-buffer buffer) + (error "The *cscope* buffer does not exist yet")))) + + +(defun cscope-display-buffer-toggle () + "Toggle cscope-display-cscope-buffer, which corresponds to +\"Auto display *cscope* buffer\"." + (interactive) + (setq cscope-display-cscope-buffer (not cscope-display-cscope-buffer)) + (message "The cscope-display-cscope-buffer variable is now %s." + (if cscope-display-cscope-buffer "set" "unset"))) + + +(defun cscope-next-symbol () + "Move to the next symbol in the *cscope* buffer." + (interactive) + (cscope-buffer-search t t)) + + +(defun cscope-next-file () + "Move to the next file in the *cscope* buffer." + (interactive) + (cscope-buffer-search nil t)) + + +(defun cscope-prev-symbol () + "Move to the previous symbol in the *cscope* buffer." + (interactive) + (cscope-buffer-search t nil)) + + +(defun cscope-prev-file () + "Move to the previous file in the *cscope* buffer." + (interactive) + (cscope-buffer-search nil nil)) + + +(defun cscope-pop-mark () + "Pop back to where cscope was last invoked." + (interactive) + + ;; This function is based on pop-tag-mark, which can be found in + ;; lisp/progmodes/etags.el. + + (if (ring-empty-p cscope-marker-ring) + (error "There are no marked buffers in the cscope-marker-ring yet")) + (let* ( (marker (ring-remove cscope-marker-ring 0)) + (old-buffer (current-buffer)) + (marker-buffer (marker-buffer marker)) + marker-window + (marker-point (marker-position marker)) + (cscope-buffer (get-buffer cscope-output-buffer-name)) ) + + ;; After the following both cscope-marker-ring and cscope-marker will be + ;; in the state they were immediately after the last search. This way if + ;; the user now makes a selection in the previously generated *cscope* + ;; buffer things will behave the same way as if that selection had been + ;; made immediately after the last search. + (setq cscope-marker marker) + + (if marker-buffer + (if (eq old-buffer cscope-buffer) + (progn ;; In the *cscope* buffer. + (set-buffer marker-buffer) + (setq marker-window (display-buffer marker-buffer)) + (set-window-point marker-window marker-point) + (select-window marker-window)) + (switch-to-buffer marker-buffer)) + (error "The marked buffer has been deleted")) + (goto-char marker-point) + (set-buffer old-buffer))) + + +(defun cscope-set-initial-directory (cs-id) + "Set the cscope-initial-directory variable. The +cscope-initial-directory variable, when set, specifies the directory +where searches for the cscope database directory should begin. This +overrides the current directory, which would otherwise be used." + (interactive "DCscope Initial Directory: ") + (setq cscope-initial-directory cs-id)) + + +(defun cscope-unset-initial-directory () + "Unset the cscope-initial-directory variable." + (interactive) + (setq cscope-initial-directory nil) + (message "The cscope-initial-directory variable is now unset.")) + + +(defun cscope-help () + (interactive) + (message + (format "RET=%s, SPC=%s, o=%s, n=%s, p=%s, q=%s, h=%s" + "Select" + "Show" + "SelectOneWin" + "ShowNext" + "ShowPrev" + "Quit" + "Help"))) + + +(defun cscope-bury-buffer () + "Clean up cscope, if necessary, and bury the buffer." + (interactive) + (let () + (if overlay-arrow-position + (set-marker overlay-arrow-position nil)) + (setq overlay-arrow-position nil + overlay-arrow-string nil) + (bury-buffer (get-buffer cscope-output-buffer-name)) + )) + + +(defun cscope-quit () + (interactive) + (cscope-bury-buffer) + (kill-buffer cscope-output-buffer-name) + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-canonicalize-directory (dir) + (or dir + (setq dir default-directory)) + (setq dir (file-name-as-directory + (expand-file-name (substitute-in-file-name dir)))) + dir + ) + + +(defun cscope-search-directory-hierarchy (directory) + "Look for a cscope database in the directory hierarchy. +Starting from DIRECTORY, look upwards for a cscope database." + (let (this-directory database-dir) + (catch 'done + (if (file-regular-p directory) + (throw 'done directory)) + (setq directory (cscope-canonicalize-directory directory) + this-directory directory) + (while this-directory + (if (or (file-exists-p (concat this-directory cscope-database-file)) + (file-exists-p (concat this-directory cscope-index-file))) + (progn + (setq database-dir this-directory) + (throw 'done database-dir) + )) + (if (string-match "^\\(/\\|[A-Za-z]:[\\/]\\)$" this-directory) + (throw 'done directory)) + (setq this-directory (file-name-as-directory + (file-name-directory + (directory-file-name this-directory)))) + )) + )) + + +(defun cscope-find-info (top-directory) + "Locate a suitable cscope database directory. +First, `cscope-database-regexps' is used to search for a suitable +database directory. If a database location cannot be found using this +variable, then the current directory is searched, then the parent, +then the parent's parent, until a cscope database directory is found, +or the root directory is reached. If the root directory is reached, +the current directory will be used." + (let (info regexps dir-regexp this-directory) + (setq top-directory (cscope-canonicalize-directory + (or top-directory cscope-initial-directory))) + (catch 'done + ;; Try searching using `cscope-database-regexps' ... + (setq regexps cscope-database-regexps) + (while regexps + (setq dir-regexp (car (car regexps))) + (cond + ( (stringp dir-regexp) + (if (string-match dir-regexp top-directory) + (progn + (setq info (cdr (car regexps))) + (throw 'done t) + )) ) + ( (and (symbolp dir-regexp) dir-regexp) + (progn + (setq info (cdr (car regexps))) + (throw 'done t) + ) )) + (setq regexps (cdr regexps)) + ) + + ;; Try looking in the directory hierarchy ... + (if (setq this-directory + (cscope-search-directory-hierarchy top-directory)) + (progn + (setq info (list (list this-directory))) + (throw 'done t) + )) + + ;; Should we add any more places to look? + + ) ;; end catch + (if (not info) + (setq info (list (list top-directory)))) + info + )) + + +(defun cscope-make-entry-line (func-name line-number line) + ;; The format of entry line: + ;; func-name[line-number]______line + ;; <- cscope-name-line-width -> + ;; `format' of Emacs doesn't have "*s" spec. + (let* ((fmt (format "%%%ds %%s" cscope-name-line-width)) + (str (format fmt (format "%s[%s]" func-name line-number) line)) + beg end) + (if cscope-use-face + (progn + (setq end (length func-name)) + (put-text-property 0 end 'face 'cscope-function-face str) + (setq beg (1+ end) + end (+ beg (length line-number))) + (put-text-property beg end 'face 'cscope-line-number-face str) + (setq end (length str) + beg (- end (length line))) + (put-text-property beg end 'face 'cscope-line-face str) + )) + str)) + + +(defun cscope-process-filter (process output) + "Accept cscope process output and reformat it for human readability. +Magic text properties are added to allow the user to select lines +using the mouse." + (let ( (old-buffer (current-buffer)) ) + (unwind-protect + (progn + (set-buffer (process-buffer process)) + ;; Make buffer-read-only nil + (let (buffer-read-only line file function-name line-number moving) + (setq moving (= (point) (process-mark process))) + (save-excursion + (goto-char (process-mark process)) + ;; Get the output thus far ... + (if cscope-process-output + (setq cscope-process-output (concat cscope-process-output + output)) + (setq cscope-process-output output)) + ;; Slice and dice it into lines. + ;; While there are whole lines left ... + (while (and cscope-process-output + (string-match "\\([^\n]+\n\\)\\(\\(.\\|\n\\)*\\)" + cscope-process-output)) + (setq file nil + glimpse-stripped-directory nil + ) + ;; Get a line + (setq line (substring cscope-process-output + (match-beginning 1) (match-end 1))) + (setq cscope-process-output (substring cscope-process-output + (match-beginning 2) + (match-end 2))) + (if (= (length cscope-process-output) 0) + (setq cscope-process-output nil)) + + ;; This should always match. + (if (string-match + "^\\([^ \t]+\\)[ \t]+\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\(.*\\)\n" + line) + (progn + (let (str) + (setq file (substring line (match-beginning 1) + (match-end 1)) + function-name (substring line (match-beginning 2) + (match-end 2)) + line-number (substring line (match-beginning 3) + (match-end 3)) + line (substring line (match-beginning 4) + (match-end 4)) + ) + ;; If the current file is not the same as the previous + ;; one ... + (if (not (and cscope-last-file + (string= file cscope-last-file))) + (progn + ;; The current file is different. + + ;; Insert a separating blank line if + ;; necessary. + (if cscope-last-file (insert "\n")) + ;; Insert the file name + (setq str (concat "*** " file ":")) + (if cscope-use-face + (put-text-property 0 (length str) + 'face 'cscope-file-face + str)) + (cscope-insert-with-text-properties + str + (expand-file-name file) + ;; Yes, -1 is intentional + -1) + (insert "\n") + )) + (if (not cscope-first-match) + (setq cscope-first-match-point (point))) + ;; ... and insert the line, with the + ;; appropriate indentation. + (cscope-insert-with-text-properties + (cscope-make-entry-line function-name + line-number + line) + (expand-file-name file) + line-number) + (insert "\n") + (setq cscope-last-file file) + (if cscope-first-match + (setq cscope-matched-multiple t) + (setq cscope-first-match + (cons (expand-file-name file) + (string-to-number line-number)))) + )) + (insert line "\n") + )) + (set-marker (process-mark process) (point)) + ) + (if moving + (goto-char (process-mark process))) + (set-buffer-modified-p nil) + )) + (set-buffer old-buffer)) + )) + + +(defun cscope-process-sentinel (process event) + "Sentinel for when the cscope process dies." + (let* ( (buffer (process-buffer process)) window update-window + (done t) (old-buffer (current-buffer)) + (old-buffer-window (get-buffer-window old-buffer)) ) + (set-buffer buffer) + (save-window-excursion + (save-excursion + (if (or (and (setq window (get-buffer-window buffer)) + (= (window-point window) (point-max))) + (= (point) (point-max))) + (progn + (setq update-window t) + )) + (delete-process process) + (let (buffer-read-only continue) + (goto-char (point-max)) + (if (and cscope-suppress-empty-matches + (= cscope-output-start (point))) + (delete-region cscope-item-start (point-max)) + (progn + (if (not cscope-start-directory) + (setq cscope-start-directory default-directory)) + (insert cscope-separator-line) + )) + (setq continue + (and cscope-search-list + (not (and cscope-first-match + cscope-stop-at-first-match-dir + (not cscope-stop-at-first-match-dir-meta))))) + (if continue + (setq continue (cscope-search-one-database))) + (if continue + (progn + (setq done nil) + ) + (progn + (insert "\nSearch complete.") + (if cscope-display-times + (let ( (times (current-time)) cscope-stop elapsed-time ) + (setq cscope-stop (+ (* (car times) 65536.0) + (car (cdr times)) + (* (car (cdr (cdr times))) 1.0E-6))) + (setq elapsed-time (- cscope-stop cscope-start-time)) + (insert (format " Search time = %.2f seconds." + elapsed-time)) + )) + (setq cscope-process nil) + (if cscope-running-in-xemacs + (setq modeline-process ": Search complete")) + (if cscope-start-directory + (setq default-directory cscope-start-directory)) + (if (not cscope-first-match) + (message "No matches were found.")) + ) + )) + (set-buffer-modified-p nil) + )) + (if (and done cscope-first-match-point update-window) + (if window + (set-window-point window cscope-first-match-point) + (goto-char cscope-first-match-point)) + ) + (cond + ( (not done) ;; we're not done -- do nothing for now + (if update-window + (if window + (set-window-point window (point-max)) + (goto-char (point-max)))) + ) + ( cscope-first-match + (if cscope-display-cscope-buffer + (if (and cscope-edit-single-match (not cscope-matched-multiple)) + (cscope-show-entry-internal(car cscope-first-match) + (cdr cscope-first-match) t)) + (cscope-select-entry-specified-window old-buffer-window)) + ) + ) + (if (and done (eq old-buffer buffer) cscope-first-match) + (cscope-help)) + (set-buffer old-buffer) + )) + + +(defun cscope-search-one-database () + "Pop a database entry from cscope-search-list and do a search there." + (let ( next-item options cscope-directory database-file outbuf done + base-database-file-name) + (setq outbuf (get-buffer-create cscope-output-buffer-name)) + (save-excursion + (catch 'finished + (set-buffer outbuf) + (setq options '("-L")) + (while (and (not done) cscope-search-list) + (setq next-item (car cscope-search-list) + cscope-search-list (cdr cscope-search-list) + base-database-file-name cscope-database-file + ) + (if (listp next-item) + (progn + (setq cscope-directory (car next-item)) + (if (not (stringp cscope-directory)) + (setq cscope-directory + (cscope-search-directory-hierarchy + default-directory))) + (if (file-regular-p cscope-directory) + (progn + ;; Handle the case where `cscope-directory' is really + ;; a full path name to a cscope database. + (setq base-database-file-name + (file-name-nondirectory cscope-directory) + cscope-directory + (file-name-directory cscope-directory)) + )) + (setq cscope-directory + (file-name-as-directory cscope-directory)) + (if (not (member cscope-directory cscope-searched-dirs)) + (progn + (setq cscope-searched-dirs (cons cscope-directory + cscope-searched-dirs) + done t) + )) + ) + (progn + (if (and cscope-first-match + cscope-stop-at-first-match-dir + cscope-stop-at-first-match-dir-meta) + (throw 'finished nil)) + )) + ) + (if (not done) + (throw 'finished nil)) + (if (car (cdr next-item)) + (let (newopts) + (setq newopts (car (cdr next-item))) + (if (not (listp newopts)) + (error (format "Cscope options must be a list: %s" newopts))) + (setq options (append options newopts)) + )) + (if cscope-command-args + (setq options (append options cscope-command-args))) + (setq database-file (concat cscope-directory base-database-file-name) + cscope-searched-dirs (cons cscope-directory + cscope-searched-dirs) + ) + + ;; The database file and the directory containing the database file + ;; must both be writable. + (if (or (not (file-writable-p database-file)) + (not (file-writable-p (file-name-directory database-file))) + cscope-do-not-update-database) + (setq options (cons "-d" options))) + + (goto-char (point-max)) + (setq cscope-item-start (point)) + (if (string= base-database-file-name cscope-database-file) + (insert "\nDatabase directory: " cscope-directory "\n" + cscope-separator-line) + (insert "\nDatabase directory/file: " + cscope-directory base-database-file-name "\n" + cscope-separator-line)) + ;; Add the correct database file to search + (setq options (cons base-database-file-name options)) + (setq options (cons "-f" options)) + (setq cscope-output-start (point)) + (setq default-directory cscope-directory) + (if cscope-filter-func + (progn + (setq cscope-process-output nil + cscope-last-file nil + ) + (setq cscope-process + (apply 'start-process "cscope" outbuf + cscope-program options)) + (set-process-filter cscope-process cscope-filter-func) + (set-process-sentinel cscope-process cscope-sentinel-func) + (set-marker (process-mark cscope-process) (point)) + (process-kill-without-query cscope-process) + (if cscope-running-in-xemacs + (setq modeline-process ": Searching ...")) + (setq buffer-read-only t) + ) + (apply 'call-process cscope-program nil outbuf t options) + ) + t + )) + )) + + +(defun cscope-call (msg args &optional directory filter-func sentinel-func) + "Generic function to call to process cscope requests. +ARGS is a list of command-line arguments to pass to the cscope +process. DIRECTORY is the current working directory to use (generally, +the directory in which the cscope database is located, but not +necessarily), if different that the current one. FILTER-FUNC and +SENTINEL-FUNC are optional process filter and sentinel, respectively." + (let ( (outbuf (get-buffer-create cscope-output-buffer-name)) + (old-buffer (current-buffer)) ) + (if cscope-process + (error "A cscope search is still in progress -- only one at a time is allowed")) + (setq directory (cscope-canonicalize-directory + (or cscope-initial-directory directory))) + (if (eq outbuf old-buffer) ;; In the *cscope* buffer. + (if cscope-marker-window + (progn + ;; Assume that cscope-marker-window is the window, from the + ;; users perspective, from which the search was launched and the + ;; window that should be returned to upon cscope-pop-mark. + (set-buffer (window-buffer cscope-marker-window)) + (setq cscope-marker (point-marker)) + (set-buffer old-buffer))) + (progn ;; Not in the *cscope buffer. + ;; Set the cscope-marker-window to whichever window this search + ;; was launched from. + (setq cscope-marker-window (get-buffer-window old-buffer)) + (setq cscope-marker (point-marker)))) + (save-excursion + (set-buffer outbuf) + (if cscope-display-times + (let ( (times (current-time)) ) + (setq cscope-start-time (+ (* (car times) 65536.0) (car (cdr times)) + (* (car (cdr (cdr times))) 1.0E-6))))) + (setq default-directory directory + cscope-start-directory nil + cscope-search-list (cscope-find-info directory) + cscope-searched-dirs nil + cscope-command-args args + cscope-filter-func filter-func + cscope-sentinel-func sentinel-func + cscope-first-match nil + cscope-first-match-point nil + cscope-stop-at-first-match-dir-meta (memq t cscope-search-list) + cscope-matched-multiple nil + buffer-read-only nil) + (buffer-disable-undo) + (erase-buffer) + (setq truncate-lines cscope-truncate-lines) + (if msg + (insert msg "\n")) + (cscope-search-one-database) + ) + (if cscope-display-cscope-buffer + (progn + (pop-to-buffer outbuf) + (cscope-help)) + (set-buffer outbuf)) + (goto-char (point-max)) + (cscope-list-entry-mode) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-unix-index-process-buffer-name "*cscope-indexing-buffer*" + "The name of the buffer to use for displaying indexing status/progress.") + + +(defvar cscope-unix-index-process-buffer nil + "The buffer to use for displaying indexing status/progress.") + + +(defvar cscope-unix-index-process nil + "The current indexing process.") + + +(defun cscope-unix-index-files-sentinel (process event) + "Simple sentinel to print a message saying that indexing is finished." + (let (buffer) + (save-window-excursion + (save-excursion + (setq buffer (process-buffer process)) + (set-buffer buffer) + (goto-char (point-max)) + (insert cscope-separator-line "\nIndexing finished\n") + (delete-process process) + (setq cscope-unix-index-process nil) + (set-buffer-modified-p nil) + )) + )) + + +(defun cscope-unix-index-files-internal (top-directory header-text args) + "Core function to call the indexing script." + (let () + (save-excursion + (setq top-directory (cscope-canonicalize-directory top-directory)) + (setq cscope-unix-index-process-buffer + (get-buffer-create cscope-unix-index-process-buffer-name)) + (display-buffer cscope-unix-index-process-buffer) + (set-buffer cscope-unix-index-process-buffer) + (setq buffer-read-only nil) + (setq default-directory top-directory) + (buffer-disable-undo) + (erase-buffer) + (if header-text + (insert header-text)) + (setq args (append args + (list "-v" + "-i" cscope-index-file + "-f" cscope-database-file + (if cscope-use-relative-paths + "." top-directory)))) + (if cscope-index-recursively + (setq args (cons "-r" args))) + (setq cscope-unix-index-process + (apply 'start-process "cscope-indexer" + cscope-unix-index-process-buffer + cscope-indexing-script args)) + (set-process-sentinel cscope-unix-index-process + 'cscope-unix-index-files-sentinel) + (process-kill-without-query cscope-unix-index-process) + ) + )) + + +(defun cscope-index-files (top-directory) + "Index files in a directory. +This function creates a list of files to index, and then indexes +the listed files. +The variable, \"cscope-index-recursively\", controls whether or not +subdirectories are indexed." + (interactive "DIndex files in directory: ") + (let () + (cscope-unix-index-files-internal + top-directory + (format "Creating cscope index `%s' in:\n\t%s\n\n%s" + cscope-database-file top-directory cscope-separator-line) + nil) + )) + + +(defun cscope-create-list-of-files-to-index (top-directory) + "Create a list of files to index. +The variable, \"cscope-index-recursively\", controls whether or not +subdirectories are indexed." + (interactive "DCreate file list in directory: ") + (let () + (cscope-unix-index-files-internal + top-directory + (format "Creating cscope file list `%s' in:\n\t%s\n\n" + cscope-index-file top-directory) + '("-l")) + )) + + +(defun cscope-edit-list-of-files-to-index () + "Search for and edit the list of files to index. +If this functions causes a new file to be edited, that means that a +cscope.out file was found without a corresponding cscope.files file." + (interactive) + (let (info directory file) + (setq info (cscope-find-info nil)) + (if (/= (length info) 1) + (error "There is no unique cscope database directory!")) + (setq directory (car (car info))) + (if (not (stringp directory)) + (setq directory + (cscope-search-directory-hierarchy default-directory))) + (setq file (concat (file-name-as-directory directory) cscope-index-file)) + (find-file file) + (message (concat "File: " file)) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-tell-user-about-directory () + "Display the name of the directory containing the cscope database." + (interactive) + (let (info directory) + (setq info (cscope-find-info nil)) + (if (= (length info) 1) + (progn + (setq directory (car (car info))) + (message (concat "Cscope directory: " directory)) + ) + (let ( (outbuf (get-buffer-create cscope-info-buffer-name)) ) + (display-buffer outbuf) + (save-excursion + (set-buffer outbuf) + (buffer-disable-undo) + (erase-buffer) + (insert "Cscope search directories:\n") + (while info + (if (listp (car info)) + (progn + (setq directory (car (car info))) + (if (not (stringp directory)) + (setq directory + (cscope-search-directory-hierarchy + default-directory))) + (insert "\t" directory "\n") + )) + (setq info (cdr info)) + ) + ) + )) + )) + + +(defun cscope-dired-directory () + "Run dired upon the cscope database directory. +If possible, the cursor is moved to the name of the cscope database +file." + (interactive) + (let (info directory buffer p1 p2 pos) + (setq info (cscope-find-info nil)) + (if (/= (length info) 1) + (error "There is no unique cscope database directory!")) + (setq directory (car (car info))) + (if (not (stringp directory)) + (setq directory + (cscope-search-directory-hierarchy default-directory))) + (setq buffer (dired-noselect directory nil)) + (switch-to-buffer buffer) + (set-buffer buffer) + (save-excursion + (goto-char (point-min)) + (setq p1 (search-forward cscope-index-file nil t)) + (if p1 + (setq p1 (- p1 (length cscope-index-file)))) + ) + (save-excursion + (goto-char (point-min)) + (setq p2 (search-forward cscope-database-file nil t)) + (if p2 + (setq p2 (- p2 (length cscope-database-file)))) + ) + (cond + ( (and p1 p2) + (if (< p1 p2) + (setq pos p1) + (setq pos p2)) + ) + ( p1 + (setq pos p1) + ) + ( p2 + (setq pos p2) + ) + ) + (if pos + (set-window-point (get-buffer-window buffer) pos)) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-extract-symbol-at-cursor (extract-filename) + (let* ( (symbol-chars (if extract-filename + cscope-filename-chars + cscope-symbol-chars)) + (symbol-char-regexp (concat "[" symbol-chars "]")) + ) + (save-excursion + (buffer-substring-no-properties + (progn + (if (not (looking-at symbol-char-regexp)) + (re-search-backward "\\w" nil t)) + (skip-chars-backward symbol-chars) + (point)) + (progn + (skip-chars-forward symbol-chars) + (point) + ))) + )) + + +(defun cscope-prompt-for-symbol (prompt extract-filename) + "Prompt the user for a cscope symbol." + (let (sym) + (setq sym (cscope-extract-symbol-at-cursor extract-filename)) + (if (or (not sym) + (string= sym "") + (not (and cscope-running-in-xemacs + cscope-no-mouse-prompts current-mouse-event + (or (mouse-event-p current-mouse-event) + (misc-user-event-p current-mouse-event)))) + ;; Always prompt for symbol in dired mode. + (eq major-mode 'dired-mode) + ) + (setq sym (read-from-minibuffer prompt sym)) + sym) + )) + + +(defun cscope-find-this-symbol (symbol) + "Locate a symbol in source code." + (interactive (list + (cscope-prompt-for-symbol "Find this symbol: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding symbol: %s" symbol) + (list "-0" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-global-definition (symbol) + "Find a symbol's global definition." + (interactive (list + (cscope-prompt-for-symbol "Find this global definition: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding global definition: %s" symbol) + (list "-1" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-global-definition-no-prompting () + "Find a symbol's global definition without prompting." + (interactive) + (let ( (symbol (cscope-extract-symbol-at-cursor nil)) + (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding global definition: %s" symbol) + (list "-1" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-called-functions (symbol) + "Display functions called by a function." + (interactive (list + (cscope-prompt-for-symbol + "Find functions called by this function: " nil) + )) + (let ( (cscope-adjust nil) ) ;; Disable fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding functions called by: %s" symbol) + (list "-2" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-functions-calling-this-function (symbol) + "Display functions calling a function." + (interactive (list + (cscope-prompt-for-symbol + "Find functions calling this function: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding functions calling: %s" symbol) + (list "-3" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-this-text-string (symbol) + "Locate where a text string occurs." + (interactive (list + (cscope-prompt-for-symbol "Find this text string: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding text string: %s" symbol) + (list "-4" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-egrep-pattern (symbol) + "Run egrep over the cscope database." + (interactive (list + (let (cscope-no-mouse-prompts) + (cscope-prompt-for-symbol "Find this egrep pattern: " nil)) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding egrep pattern: %s" symbol) + (list "-6" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-this-file (symbol) + "Locate a file." + (interactive (list + (let (cscope-no-mouse-prompts) + (cscope-prompt-for-symbol "Find this file: " t)) + )) + (let ( (cscope-adjust nil) ) ;; Disable fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding file: %s" symbol) + (list "-7" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-files-including-file (symbol) + "Locate all files #including a file." + (interactive (list + (let (cscope-no-mouse-prompts) + (cscope-prompt-for-symbol + "Find files #including this file: " t)) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding files #including file: %s" symbol) + (list "-8" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-minor-mode nil + "") +(make-variable-buffer-local 'cscope-minor-mode) +(put 'cscope-minor-mode 'permanent-local t) + + +(defun cscope-minor-mode (&optional arg) + "" + (progn + (setq cscope-minor-mode (if (null arg) t (car arg))) + (if cscope-minor-mode + (progn + (easy-menu-add cscope:menu cscope:map) + (run-hooks 'cscope-minor-mode-hooks) + )) + cscope-minor-mode + )) + + +(defun cscope:hook () + "" + (progn + (cscope-minor-mode) + )) + + +(or (assq 'cscope-minor-mode minor-mode-map-alist) + (setq minor-mode-map-alist (cons (cons 'cscope-minor-mode cscope:map) + minor-mode-map-alist))) + +(add-hook 'c-mode-hook (function cscope:hook)) +(add-hook 'c++-mode-hook (function cscope:hook)) +(add-hook 'dired-mode-hook (function cscope:hook)) + +(provide 'xcscope) -- cgit v1.2.3-54-g00ecf