This commit is contained in:
anon 2023-07-27 20:04:50 +02:00
commit a56c9e6818
48 changed files with 14682 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
obj/*.o
obj/*.gch
csope
**/*.out
src/lex.yy.c

38
Makefile Normal file
View File

@ -0,0 +1,38 @@
CC=gcc
CCFLAGS:=-ggdb #-D PRODUCTION
LDLIBS=-I ${CHDRD} $$(pkg-config --libs ncurses)
LEX:=flex
LEXD:=src/
LEXF:=$(shell find ${LEXD} -iname '*.l')
GENLEX:=$(subst .l,.c,${LEXF})
SRCD:=src/
OBJD:=obj/
SRC:=$(shell find ${SRCD} -iname '*.c') ${GENLEX}
OBJ:=$(subst .c,.o,$(subst ${SRCD},${OBJD},${SRC}))
HDRD:=${SRCD}
CHDRD:=${OBJD}
HDR:=$(shell find ${HDRD} -iname '*.h')
CHDR:=$(addsuffix .gch,$(subst ${HDRD},${CHDRD},${HDR}))
OUTPUT:=csope
main: ${CHDR} ${OBJ}
${LINK.c} ${LDLIBS} ${OBJ} -o ${OUTPUT}
obj/%.o: src/%.c
${COMPILE.c} $< -o $@
src/%.c: src/%.l
${LEX} -o $@ $<
obj/%.h.gch: src/%.h
${CC} $< -o $@
clean:
-rm ${CHDR}
-rm ${GENLEX}
-rm ${OBJ}
-rm ${OUTPUT}

12
README.md Normal file
View File

@ -0,0 +1,12 @@
# Csope
Fork of Cscope, with various improvements, because cscope is good and shall not be forgotten.
# Improvements/Changes
## User side
+ improved gui /*pending*/
+ GNU Readline integration (ie. VI/EMACS mode, command history) /*pending*/
## To the code
+ nuked autoconf, replaced with single Makefile
+ removed
+ encapsulated changes to the TUI into display.c
+ removed macros hell put in place to allow compiling on a dead badger

7
TODO Normal file
View File

@ -0,0 +1,7 @@
# BUGS
+ Changing text double frees:
free(): double free detected in tcache 2
Aborted
+ Normalize tabs and spaces
+ Ordering function declarations in global.h by alpha order is not smart
+ Handle unused parameters gracefully (#define UNUSED(x) (void)(x))

99
ass/emacs.e Normal file
View File

@ -0,0 +1,99 @@
/ ========================================================================= /
/ Copyright (c) 1998-2000, The Santa Cruz Operation /
/ All rights reserved./
/ /
/ Redistribution and use in source and binary forms, with or without/
/ modification, are permitted provided that the following conditions are met:/
//
/ *Redistributions of source code must retain the above copyright notice,/
/ this list of conditions and the following disclaimer./
//
/ *Redistributions in binary form must reproduce the above copyright notice,/
/ this list of conditions and the following disclaimer in the documentation/
/ and/or other materials provided with the distribution./
//
/ *Neither name of The Santa Cruz Operation nor the names of its contributors/
/ may be used to endorse or promote products derived from this software/
/ without specific prior written permission. /
//
/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS/
/ IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,/
/ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR/
/ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE/
/ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR/
/ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF/
/ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS/
/ INTERRUPTION)/
/ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT/
/ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY/
/ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH/
/ DAMAGE. /
/ ========================================================================= /
/ emacs menu for cscope /
((X) cscope (find current word [MACRO])
(extern symbol-character)
/ if this character is not part of a symbol /
(cond ((not symbol-character)
/ if the previous character is not part of a symbol, go to
the next word /
back
(cond ((not symbol-character) forward-word back-word))
))
/ get the current symbol (leave cursor at beginning of symbol) /
(while symbol-character forward) / go past last symbol character /
mark / mark this point /
back / back to last symbol character /
(while (cond (symbol-character (return back)))) / back fails at BOF /
(cond ((not symbol-character) forward)) / forward if not at BOF /
pickup-region / get the symbol /
(local-string symbol)
symbol=
/ if arg > 0 then display the menu /
(cond ((> arg 0) (display-menu
(format symbol "5 Find functions calling %l()")
(format symbol "4 Find functions called by %l()")
(format symbol "3 Find global definition of %l")
(format symbol "2 Find symbol %l")
"1 Call cscope"
5)
))
/ get the selection /
(local selection)
(selection= (read-character "Selection?"))
/ if the selection is in range /
(cond ((&& (>= selection '1') (<= selection '5'))
/ if the selection requests finding the symbol /
(local-string findsymbol)
(findsymbol= "")
(cond ((>= selection '2')
(findsymbol= (format (char-to-string (- selection 2)) symbol "-%l '%l'"))))
/ if arg > 1 or < 0 then don't update the cross-reference database /
(local-string doption)
(doption= "")
(cond ((|| (> arg 1) (< arg 0)) (doption= "-d")))
/ call cscope with usilent mode off /
(local oldmode) / save old usilent mode /
(oldmode= (set-mode "usilent" 0)) / turn off usilent mode /
(run-command (format doption findsymbol "cscope %l %l"))
(set-mode "usilent" oldmode) / restore usilent mode /
))
)
/ see if the current character is part of a symbol /
(symbol-character ()
(local c)
(c= current-character)
(return (cond ((&& (>= c 'a') (<= c 'z')))
((&& (>= c 'A') (<= c 'Z')))
((&& (>= c '0') (<= c '9')))
((== c '_'))
)
)
)

63
ass/gmacs.ml Normal file
View File

@ -0,0 +1,63 @@
; ===========================================================================
; Copyright (c) 1998-2000, The Santa Cruz Operation
; All rights reserved.
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
; *Redistributions of source code must retain the above copyright notice,
; this list of conditions and the following disclaimer.
; *Redistributions in binary form must reproduce the above copyright notice,
; this list of conditions and the following disclaimer in the documentation
; and/or other materials provided with the distribution.
; *Neither name of The Santa Cruz Operation nor the names of its contributors
; may be used to endorse or promote products derived from this software
; without specific prior written permission.
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
; IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
; INTERRUPTION)
; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
; DAMAGE.
; =========================================================================
; cscope.ml (s.cscope.ml) - 1.4 (2/21/84 14:53:58)
;
; Macro to handle invocation of gmacs by cscope from the
; experimental tools. Cscope invokes gmacs with two arguments:
;
; gmacs +line file
;
; This macro gobbles the line number, visits the specified file,
; and moves to the specified line number.
(progn
args
pluses
(setq pluses 0)
(setq args (argc))
(if (> args 1)
(progn
(if (= (string-to-char "+") (string-to-char (argv 1)))
(setq pluses 1)
)
(setq args (- args 1))
(while (> args pluses)
(visit-file (argv args))
(setq args (- args 1))
)
(if (= (> (argc) 2) (> pluses 0))
(goto-line (argv 1))
)
)
)
)

247
ass/ylwrap Executable file
View File

@ -0,0 +1,247 @@
#! /bin/sh
# ylwrap - wrapper for lex/yacc invocations.
scriptversion=2016-01-11.22; # UTC
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
get_dirname ()
{
case $1 in
*/*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';;
# Otherwise, we want the empty string (not ".").
esac
}
# guard FILE
# ----------
# The CPP macro used to guard inclusion of FILE.
guard ()
{
printf '%s\n' "$1" \
| sed \
-e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
-e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \
-e 's/__*/_/g'
}
# quote_for_sed [STRING]
# ----------------------
# Return STRING (or stdin) quoted to be used as a sed pattern.
quote_for_sed ()
{
case $# in
0) cat;;
1) printf '%s\n' "$1";;
esac \
| sed -e 's|[][\\.*]|\\&|g'
}
case "$1" in
'')
echo "$0: No files given. Try '$0 --help' for more information." 1>&2
exit 1
;;
--basedir)
basedir=$2
shift 2
;;
-h|--h*)
cat <<\EOF
Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
Wrapper for lex/yacc invocations, renaming files as desired.
INPUT is the input file
OUTPUT is one file PROG generates
DESIRED is the file we actually want instead of OUTPUT
PROGRAM is program to run
ARGS are passed to PROG
Any number of OUTPUT,DESIRED pairs may be used.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v|--v*)
echo "ylwrap $scriptversion"
exit $?
;;
esac
# The input.
input=$1
shift
# We'll later need for a correct munging of "#line" directives.
input_sub_rx=`get_dirname "$input" | quote_for_sed`
case $input in
[\\/]* | ?:[\\/]*)
# Absolute path; do nothing.
;;
*)
# Relative path. Make it absolute.
input=`pwd`/$input
;;
esac
input_rx=`get_dirname "$input" | quote_for_sed`
# Since DOS filename conventions don't allow two dots,
# the DOS version of Bison writes out y_tab.c instead of y.tab.c
# and y_tab.h instead of y.tab.h. Test to see if this is the case.
y_tab_nodot=false
if test -f y_tab.c || test -f y_tab.h; then
y_tab_nodot=true
fi
# The parser itself, the first file, is the destination of the .y.c
# rule in the Makefile.
parser=$1
# A sed program to s/FROM/TO/g for all the FROM/TO so that, for
# instance, we rename #include "y.tab.h" into #include "parse.h"
# during the conversion from y.tab.c to parse.c.
sed_fix_filenames=
# Also rename header guards, as Bison 2.7 for instance uses its header
# guard in its implementation file.
sed_fix_header_guards=
while test $# -ne 0; do
if test x"$1" = x"--"; then
shift
break
fi
from=$1
# Handle y_tab.c and y_tab.h output by DOS
if $y_tab_nodot; then
case $from in
"y.tab.c") from=y_tab.c;;
"y.tab.h") from=y_tab.h;;
esac
fi
shift
to=$1
shift
sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;"
sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;"
done
# The program to run.
prog=$1
shift
# Make any relative path in $prog absolute.
case $prog in
[\\/]* | ?:[\\/]*) ;;
*[\\/]*) prog=`pwd`/$prog ;;
esac
dirname=ylwrap$$
do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
mkdir $dirname || exit 1
cd $dirname
case $# in
0) "$prog" "$input" ;;
*) "$prog" "$@" "$input" ;;
esac
ret=$?
if test $ret -eq 0; then
for from in *
do
to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"`
if test -f "$from"; then
# If $2 is an absolute path name, then just use that,
# otherwise prepend '../'.
case $to in
[\\/]* | ?:[\\/]*) target=$to;;
*) target=../$to;;
esac
# Do not overwrite unchanged header files to avoid useless
# recompilations. Always update the parser itself: it is the
# destination of the .y.c rule in the Makefile. Divert the
# output of all other files to a temporary file so we can
# compare them to existing versions.
if test $from != $parser; then
realtarget=$target
target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'`
fi
# Munge "#line" or "#" directives. Don't let the resulting
# debug information point at an absolute srcdir. Use the real
# output file name, not yy.lex.c for instance. Adjust the
# include guards too.
sed -e "/^#/!b" \
-e "s|$input_rx|$input_sub_rx|" \
-e "$sed_fix_filenames" \
-e "$sed_fix_header_guards" \
"$from" >"$target" || ret=$?
# Check whether files must be updated.
if test "$from" != "$parser"; then
if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
echo "$to is unchanged"
rm -f "$target"
else
echo "updating $to"
mv -f "$target" "$realtarget"
fi
fi
else
# A missing file is only an error for the parser. This is a
# blatant hack to let us support using "yacc -d". If -d is not
# specified, don't fail when the header file is "missing".
if test "$from" = "$parser"; then
ret=1
fi
fi
done
fi
# Remove the directory.
cd ..
rm -rf $dirname
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

4
comp.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
make clean
make

0
obj/.placeholder Normal file
View File

46
src/basename.c Normal file
View File

@ -0,0 +1,46 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* get a file's base name from its path name */
#include "global.h"
char *
basename(char *path)
{
char *s;
if ((s = strrchr(path, '/')) != 0) {
return(s + 1);
}
return(path);
}

738
src/build.c Normal file
View File

@ -0,0 +1,738 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* main functions
*/
#include "build.h"
#include "global.h" /* FIXME: get rid of this! */
#include "library.h"
#include "scanner.h"
#include "version.h" /* for FILEVERSION */
#include "vp.h"
#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
#include <ncurses.h>
#else
#include <curses.h>
#endif
/* Exported variables: */
BOOL buildonly = NO; /* only build the database */
BOOL unconditional = NO; /* unconditionally build database */
BOOL fileschanged; /* assume some files changed */
/* variable copies of the master strings... */
char invname_buf[] = INVNAME;
char invpost_buf[] = INVPOST;
char reffile_buf[] = REFFILE;
char *invname = invname_buf; /* inverted index to the database */
char *invpost = invpost_buf; /* inverted index postings */
char *reffile = reffile_buf; /* cross-reference file path name */
char *newreffile; /* new cross-reference file name */
FILE *newrefs; /* new cross-reference */
FILE *postings; /* new inverted index postings */
int symrefs = -1; /* cross-reference file */
INVCONTROL invcontrol; /* inverted file control structure */
/* Local variables: */
static char *newinvname; /* new inverted index file name */
static char *newinvpost; /* new inverted index postings file name */
static long traileroffset; /* file trailer offset */
/* Internal prototypes: */
static void cannotindex(void);
static int compare(const void *s1, const void *s2);
static void copydata(void);
static void copyinverted(void);
static char *getoldfile(void);
static void movefile(char *new, char *old);
static void putheader(char *dir);
static void fetch_include_from_dbase(char *, size_t);
static void putlist(char **names, int count);
static BOOL samelist(FILE *oldrefs, char **names, int count);
/* Error handling routine if inverted index creation fails */
static void
cannotindex(void)
{
fprintf(stderr, "\
cscope: cannot create inverted index; ignoring -q option\n");
invertedindex = NO;
errorsfound = YES;
fprintf(stderr, "\
cscope: removed files %s and %s\n",
newinvname, newinvpost);
unlink(newinvname);
unlink(newinvpost);
}
/* see if the name list is the same in the cross-reference file */
static BOOL
samelist(FILE *oldrefs, char **names, int count)
{
char oldname[PATHLEN + 1]; /* name in old cross-reference */
int oldcount;
int i;
/* see if the number of names is the same */
if (fscanf(oldrefs, "%d", &oldcount) != 1 ||
oldcount != count) {
return(NO);
}
/* see if the name list is the same */
for (i = 0; i < count; ++i) {
if ((1 != fscanf(oldrefs," %[^\n]",oldname)) ||
strnotequal(oldname, names[i])) {
return(NO);
}
}
return(YES);
}
/* create the file name(s) used for a new cross-referene */
void setup_build_filenames(char *reffile)
{
char *path; /* file pathname */
char *s; /* pointer to basename in path */
path = malloc(strlen(reffile) + 10u);
strcpy(path, reffile);
s = basename(path);
*s = '\0';
strcat(path, "n");
++s;
strcpy(s, basename(reffile));
newreffile = strdup(path);
strcpy(s, basename(invname));
newinvname = strdup(path);
strcpy(s, basename(invpost));
newinvpost = strdup(path);
free(path);
}
/* open the database */
void
opendatabase(void)
{
if ((symrefs = vpopen(reffile, O_BINARY | O_RDONLY)) == -1) {
cannotopen(reffile);
myexit(1);
}
blocknumber = -1; /* force next seek to read the first block */
/* open any inverted index */
if (invertedindex == YES &&
invopen(&invcontrol, invname, invpost, INVAVAIL) == -1) {
askforreturn(); /* so user sees message */
invertedindex = NO;
}
}
/* rebuild the database */
void
rebuild(void)
{
close(symrefs);
if (invertedindex == YES) {
invclose(&invcontrol);
nsrcoffset = 0;
npostings = 0;
}
build();
opendatabase();
/* revert to the initial display */
if (refsfound != NULL) {
fclose(refsfound);
refsfound = NULL;
}
}
/* build the cross-reference */
void
build(void)
{
unsigned long i;
FILE *oldrefs; /* old cross-reference file */
time_t reftime; /* old crossref modification time */
char *file; /* current file */
char *oldfile; /* file in old cross-reference */
char newdir[PATHLEN + 1]; /* directory in new cross-reference */
char olddir[PATHLEN + 1]; /* directory in old cross-reference */
char oldname[PATHLEN + 1]; /* name in old cross-reference */
unsigned long oldnum; /* number in old cross-ref */
struct stat statstruct; /* file status */
unsigned long firstfile; /* first source file in pass */
unsigned long lastfile; /* last source file in pass */
int built = 0; /* built crossref for these files */
int copied = 0; /* copied crossref for these files */
unsigned long fileindex; /* source file name index */
BOOL interactive = YES; /* output progress messages */
/* normalize the current directory relative to the home directory so
the cross-reference is not rebuilt when the user's login is moved */
strcpy(newdir, currentdir);
if (strcmp(currentdir, home) == 0) {
strcpy(newdir, "$HOME");
} else if (strncmp(currentdir, home, strlen(home)) == 0) {
snprintf(newdir, sizeof(newdir), "$HOME%s", currentdir + strlen(home));
}
/* sort the source file names (needed for rebuilding) */
qsort(srcfiles, nsrcfiles, sizeof(*srcfiles), compare);
/* if there is an old cross-reference and its current directory matches */
/* or this is an unconditional build */
if ((oldrefs = vpfopen(reffile, "rb")) != NULL
&& unconditional == NO
&& fscanf(oldrefs, "cscope %d %" PATHLEN_STR "s", &fileversion, olddir) == 2
&& (strcmp(olddir, currentdir) == 0 /* remain compatible */
|| strcmp(olddir, newdir) == 0)) {
/* get the cross-reference file's modification time */
fstat(fileno(oldrefs), &statstruct);
reftime = statstruct.st_mtime;
if (fileversion >= 8) {
BOOL oldcompress = YES;
BOOL oldinvertedindex = NO;
BOOL oldtruncate = NO;
int c;
/* see if there are options in the database */
for (;;) {
while((c = getc(oldrefs)) == ' ')
; /* do nothing */
if (c != '-') {
ungetc(c, oldrefs);
break;
}
switch (getc(oldrefs)) {
case 'c': /* ASCII characters only */
oldcompress = NO;
break;
case 'q': /* quick search */
oldinvertedindex = YES;
fscanf(oldrefs, "%ld", &totalterms);
break;
case 'T': /* truncate symbols to 8 characters */
oldtruncate = YES;
break;
}
}
/* check the old and new option settings */
if (oldcompress != compress || oldtruncate != trun_syms) {
posterr("\
cscope: -c or -T option mismatch between command line and old symbol database\n");
goto force;
}
if (oldinvertedindex != invertedindex) {
posterr("\
cscope: -q option mismatch between command line and old symbol database\n");
if (invertedindex == NO) {
posterr("cscope: removed files %s and %s\n",
invname, invpost);
unlink(invname);
unlink(invpost);
}
goto outofdate;
}
/* seek to the trailer */
if (fscanf(oldrefs, "%ld", &traileroffset) != 1 ||
fseek(oldrefs, traileroffset, SEEK_SET) == -1) {
posterr("cscope: incorrect symbol database file format\n");
goto force;
}
}
/* if assuming that some files have changed */
if (fileschanged == YES) {
goto outofdate;
}
/* see if the directory lists are the same */
if (samelist(oldrefs, srcdirs, nsrcdirs) == NO
|| samelist(oldrefs, incdirs, nincdirs) == NO
/* get the old number of files */
|| fscanf(oldrefs, "%lu", &oldnum) != 1
/* skip the string space size */
|| (fileversion >= 9 && fscanf(oldrefs, "%*s") != 0)) {
goto outofdate;
}
/* see if the list of source files is the same and
none have been changed up to the included files */
for (i = 0; i < nsrcfiles; ++i) {
if ((1 != fscanf(oldrefs," %[^\n]",oldname))
|| strnotequal(oldname, srcfiles[i])
|| (lstat(srcfiles[i], &statstruct) != 0)
|| (statstruct.st_mtime > reftime)
) {
goto outofdate;
}
}
/* the old cross-reference is up-to-date */
/* so get the list of included files */
while (i++ < oldnum && fgets(oldname, sizeof(oldname), oldrefs)) {
addsrcfile(oldname);
}
fclose(oldrefs);
return;
outofdate:
/* if the database format has changed, rebuild it all */
if (fileversion != FILEVERSION) {
fprintf(stderr, "\
cscope: converting to new symbol database file format\n");
goto force;
}
/* reopen the old cross-reference file for fast scanning */
if ((symrefs = vpopen(reffile, O_BINARY | O_RDONLY)) == -1) {
postfatal("cscope: cannot open file %s\n", reffile);
/* NOTREACHED */
}
/* get the first file name in the old cross-reference */
blocknumber = -1;
read_block(); /* read the first cross-ref block */
scanpast('\t'); /* skip the header */
oldfile = getoldfile();
} else { /* force cross-referencing of all the source files */
force:
reftime = 0;
oldfile = NULL;
}
/* open the new cross-reference file */
if ((newrefs = myfopen(newreffile, "wb")) == NULL) {
postfatal("cscope: cannot open file %s\n", reffile);
/* NOTREACHED */
}
if (invertedindex == YES && (postings = myfopen(temp1, "wb")) == NULL) {
cannotwrite(temp1);
cannotindex();
}
putheader(newdir);
fileversion = FILEVERSION;
if (buildonly == YES && verbosemode != YES && !isatty(0)) {
interactive = NO;
} else {
searchcount = 0;
}
/* output the leading tab expected by crossref() */
dbputc('\t');
/* make passes through the source file list until the last level of
included files is processed */
firstfile = 0;
lastfile = nsrcfiles;
if (invertedindex == YES) {
srcoffset = malloc((nsrcfiles + 1u) * sizeof(*srcoffset));
}
for (;;) {
progress("Building symbol database", (long)built,
(long)lastfile);
if (linemode == NO)
refresh();
/* get the next source file name */
for (fileindex = firstfile; fileindex < lastfile; ++fileindex) {
/* display the progress about every three seconds */
if (interactive == YES && fileindex % 10 == 0) {
progress("Building symbol database", fileindex, lastfile);
}
/* if the old file has been deleted get the next one */
file = srcfiles[fileindex];
while (oldfile != NULL && strcmp(file, oldfile) > 0) {
oldfile = getoldfile();
}
/* if there isn't an old database or this is a new file */
if (oldfile == NULL || strcmp(file, oldfile) < 0) {
crossref(file);
++built;
} else if (lstat(file, &statstruct) == 0
&& statstruct.st_mtime > reftime) {
/* if this file was modified */
crossref(file);
++built;
/* skip its old crossref so modifying the last source
* file does not cause all included files to be built.
* Unfortunately a new file that is alphabetically
* last will cause all included files to be build, but
* this is less likely */
oldfile = getoldfile();
} else {
/* copy its cross-reference */
putfilename(file);
if (invertedindex == YES) {
copyinverted();
} else {
copydata();
}
++copied;
oldfile = getoldfile();
}
}
/* see if any included files were found */
if (lastfile == nsrcfiles) {
break;
}
firstfile = lastfile;
lastfile = nsrcfiles;
if (invertedindex == YES) {
srcoffset = realloc(srcoffset, (nsrcfiles + 1) * sizeof(*srcoffset));
}
/* sort the included file names */
qsort(srcfiles + firstfile, lastfile - firstfile, sizeof(*srcfiles), compare);
}
/* add a null file name to the trailing tab */
putfilename("");
dbputc('\n');
/* get the file trailer offset */
traileroffset = dboffset;
/* output the source and include directory and file lists */
putlist(srcdirs, nsrcdirs);
putlist(incdirs, nincdirs);
putlist(srcfiles, nsrcfiles);
if (fflush(newrefs) == EOF) {
/* rewind doesn't check for write failure */
cannotwrite(newreffile);
/* NOTREACHED */
}
/* create the inverted index if requested */
if (invertedindex == YES) {
char sortcommand[PATHLEN + 1];
if (fflush(postings) == EOF) {
cannotwrite(temp1);
/* NOTREACHED */
}
fstat(fileno(postings), &statstruct);
fclose(postings);
snprintf(sortcommand, sizeof(sortcommand), "env LC_ALL=C sort -T %s %s", tmpdir, temp1);
if ((postings = mypopen(sortcommand, "r")) == NULL) {
fprintf(stderr, "cscope: cannot open pipe to sort command\n");
cannotindex();
} else {
if ((totalterms = invmake(newinvname, newinvpost, postings)) > 0) {
movefile(newinvname, invname);
movefile(newinvpost, invpost);
} else {
cannotindex();
}
mypclose(postings);
}
unlink(temp1);
free(srcoffset);
}
/* rewrite the header with the trailer offset and final option list */
rewind(newrefs);
putheader(newdir);
fclose(newrefs);
/* close the old database file */
if (symrefs >= 0) {
close(symrefs);
}
if (oldrefs != NULL) {
fclose(oldrefs);
}
/* replace it with the new database file */
movefile(newreffile, reffile);
}
/* string comparison function for qsort */
static int
compare(const void *arg_s1, const void *arg_s2)
{
const char **s1 = (const char **) arg_s1;
const char **s2 = (const char **) arg_s2;
return(strcmp(*s1, *s2));
}
/* seek to the trailer, in a given file */
void
seek_to_trailer(FILE *f)
{
if (fscanf(f, "%ld", &traileroffset) != 1) {
postfatal("cscope: cannot read trailer offset from file %s\n", reffile);
/* NOTREACHED */
}
if (fseek(f, traileroffset, SEEK_SET) == -1) {
postfatal("cscope: cannot seek to trailer in file %s\n", reffile);
/* NOTREACHED */
}
}
/* get the next file name in the old cross-reference */
static char *
getoldfile(void)
{
static char file[PATHLEN + 1]; /* file name in old crossref */
if (blockp != NULL) {
do {
if (*blockp == NEWFILE) {
skiprefchar();
fetch_string_from_dbase(file, sizeof(file));
if (file[0] != '\0') { /* if not end-of-crossref */
return(file);
}
return(NULL);
}
} while (scanpast('\t') != NULL);
}
return(NULL);
}
/* Free all storage allocated for filenames: */
void free_newbuildfiles(void)
{
free(newinvname);
free(newinvpost);
free(newreffile);
}
/* output the cscope version, current directory, database format options, and
the database trailer offset */
static void
putheader(char *dir)
{
dboffset = fprintf(newrefs, "cscope %d %s", FILEVERSION, dir);
if (compress == NO) {
dboffset += fprintf(newrefs, " -c");
}
if (invertedindex == YES) {
dboffset += fprintf(newrefs, " -q %.10ld", totalterms);
} else {
/* leave space so if the header is overwritten without -q
* because writing the inverted index failed, the header
* is the same length */
dboffset += fprintf(newrefs, " ");
}
if (trun_syms == YES) {
dboffset += fprintf(newrefs, " -T");
}
dboffset += fprintf(newrefs, " %.10ld\n", traileroffset);
#ifdef PRINTF_RETVAL_BROKEN
dboffset = ftell(newrefs);
#endif
}
/* put the name list into the cross-reference file */
static void
putlist(char **names, int count)
{
int i, size = 0;
fprintf(newrefs, "%d\n", count);
if (names == srcfiles) {
/* calculate the string space needed */
for (i = 0; i < count; ++i) {
size += strlen(names[i]) + 1;
}
fprintf(newrefs, "%d\n", size);
}
for (i = 0; i < count; ++i) {
if (fputs(names[i], newrefs) == EOF ||
putc('\n', newrefs) == EOF) {
cannotwrite(newreffile);
/* NOTREACHED */
}
}
}
/* copy this file's symbol data */
static void
copydata(void)
{
char *cp;
setmark('\t');
cp = blockp;
for (;;) {
/* copy up to the next \t */
do { /* innermost loop optimized to only one test */
while (*cp != '\t') {
dbputc(*cp++);
}
} while (*++cp == '\0' && (cp = read_block()) != NULL);
dbputc('\t'); /* copy the tab */
/* get the next character */
/* HBB 2010-08-21: potential problem if above loop was left
* with cp==NULL */
if (cp && (*(cp + 1) == '\0')) {
cp = read_block();
}
/* exit if at the end of this file's data */
if (cp == NULL || *cp == NEWFILE) {
break;
}
/* look for an #included file */
if (*cp == INCLUDE) {
char symbol[PATLEN + 1];
blockp = cp;
fetch_include_from_dbase(symbol, sizeof(symbol));
writestring(symbol);
setmark('\t');
cp = blockp;
}
}
blockp = cp;
}
/* copy this file's symbol data and output the inverted index postings */
static void
copyinverted(void)
{
char *cp;
char c;
int type; /* reference type (mark character) */
char symbol[PATLEN + 1];
/* note: this code was expanded in-line for speed */
/* while (scanpast('\n') != NULL) { */
/* other macros were replaced by code using cp instead of blockp */
cp = blockp;
for (;;) {
setmark('\n');
do { /* innermost loop optimized to only one test */
while (*cp != '\n') {
dbputc(*cp++);
}
} while (*++cp == '\0' && (cp = read_block()) != NULL);
dbputc('\n'); /* copy the newline */
/* get the next character */
/* HBB 2010-08-21: potential problem if above loop was left
* with cp==NULL */
if (cp && (*(cp + 1) == '\0')) {
cp = read_block();
}
/* exit if at the end of this file's data */
if (cp == NULL) {
break;
}
switch (*cp) {
case '\n':
lineoffset = dboffset + 1;
continue;
case '\t':
dbputc('\t');
blockp = cp;
type = getrefchar();
switch (type) {
case NEWFILE: /* file name */
return;
case INCLUDE: /* #included file */
fetch_include_from_dbase(symbol, sizeof(symbol));
goto output;
}
dbputc(type);
skiprefchar();
fetch_string_from_dbase(symbol, sizeof(symbol));
goto output;
}
c = *cp;
if (c & 0200) { /* digraph char? */
c = dichar1[(c & 0177) / 8];
}
/* if this is a symbol */
if (isalpha((unsigned char)c) || c == '_') {
blockp = cp;
fetch_string_from_dbase(symbol, sizeof(symbol));
type = ' ';
output:
putposting(symbol, type);
writestring(symbol);
if (blockp == NULL) {
return;
}
cp = blockp;
}
}
blockp = cp;
}
/* replace the old file with the new file */
static void
movefile(char *new, char *old)
{
unlink(old);
if (rename(new, old) == -1) {
myperror("cscope");
postfatal("cscope: cannot rename file %s to file %s\n",
new, old);
/* NOTREACHED */
}
}
/* process the #included file in the old database */
static void
fetch_include_from_dbase(char *s, size_t length)
{
dbputc(INCLUDE);
skiprefchar();
fetch_string_from_dbase(s, length);
incfile(s + 1, s);
}

70
src/build.h Normal file
View File

@ -0,0 +1,70 @@
/*===========================================================================
Copyright (c) 2001, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
#ifndef CSCOPE_BUILD_H
#define CSCOPE_BUILD_H
#include "global.h" /* FIXME: temp. only */
#include "invlib.h"
/* types and macros of build.c to be used by other modules */
/* database output macros that update its offset */
#define dbputc(c) (++dboffset, (void) putc(c, newrefs))
#define dbfputs(s) (dboffset += strlen(s), fputs(s, newrefs))
/* declarations for globals defined in build.c */
extern BOOL buildonly; /* only build the database */
extern BOOL unconditional; /* unconditionally build database */
extern BOOL fileschanged; /* assume some files changed */
extern char *reffile; /* cross-reference file path name */
extern char *invname; /* inverted index to the database */
extern char *invpost; /* inverted index postings */
extern char *newreffile; /* new cross-reference file name */
extern FILE *newrefs; /* new cross-reference */
extern FILE *postings; /* new inverted index postings */
extern int symrefs; /* cross-reference file */
extern INVCONTROL invcontrol; /* inverted file control structure */
/* Prototypes of external functions defined by build.c */
void build(void);
void free_newbuildfiles(void);
void opendatabase(void);
void rebuild(void);
void setup_build_filenames(char *reffile);
void seek_to_trailer(FILE *f);
#endif /* CSCOPE_BUILD_H */

934
src/command.c Normal file
View File

@ -0,0 +1,934 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol or text cross-reference
*
* command functions
*/
#include "global.h"
#include "build.h" /* for rebuild() */
#include <stdlib.h>
#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
#include <ncurses.h>
#else
#include <curses.h>
#endif
#include <ctype.h>
int selecting; /* whether the (upper) symbol list is being browsed */
unsigned int curdispline = 0;
BOOL caseless; /* ignore letter case when searching */
BOOL *change; /* change this line */
BOOL changing; /* changing text */
char newpat[PATLEN + 1]; /* new pattern */
/* HBB 20040430: renamed to avoid lots of clashes with function arguments
* also named 'pattern' */
char Pattern[PATLEN + 1]; /* symbol or text pattern */
/* HBB FIXME 20060419: these should almost certainly be const */
static char appendprompt[] = "Append to file: ";
static char pipeprompt[] = "Pipe to shell command: ";
static char readprompt[] = "Read from file: ";
static char toprompt[] = "To: ";
/* Internal prototypes: */
static BOOL changestring(void);
static void clearprompt(void);
static void mark(unsigned int i);
static void scrollbar(MOUSE *p);
/* execute the command */
BOOL
command(int commandc)
{
char filename[PATHLEN + 1]; /* file path name */
MOUSE *p; /* mouse data */
int c, i;
FILE *file;
struct cmd *curritem, *item; /* command history */
char *s;
switch (commandc) {
case ctrl('C'): /* toggle caseless mode */
if (caseless == NO) {
caseless = YES;
postmsg2("Caseless mode is now ON");
} else {
caseless = NO;
postmsg2("Caseless mode is now OFF");
}
egrepcaseless(caseless); /* turn on/off -i flag */
return(NO);
case ctrl('R'): /* rebuild the cross reference */
if (isuptodate == YES) {
postmsg("The -d option prevents rebuilding the symbol database");
return(NO);
}
exitcurses();
freefilelist(); /* remake the source file list */
makefilelist();
rebuild();
if (errorsfound == YES) {
errorsfound = NO;
askforreturn();
}
entercurses();
clearmsg(); /* clear any previous message */
totallines = 0;
disprefs = 0;
topline = nextline = 1;
selecting = 0;
break;
#if UNIXPC
case ESC: /* possible unixpc mouse selection */
#endif
case ctrl('X'): /* mouse selection */
if ((p = getmouseaction(DUMMYCHAR)) == NULL) {
return(NO); /* unknown control sequence */
}
/* if the button number is a scrollbar tag */
if (p->button == '0') {
scrollbar(p);
break;
}
/* ignore a sweep */
if (p->x2 >= 0) {
return(NO);
}
/* if this is a line selection */
if (p->y1 < FLDLINE) {
/* find the selected line */
/* note: the selection is forced into range */
for (i = disprefs - 1; i > 0; --i) {
if (p->y1 >= displine[i]) {
break;
}
}
/* display it in the file with the editor */
editref(i);
} else { /* this is an input field selection */
field = p->y1 - FLDLINE;
/* force it into range */
if (field >= FIELDS) {
field = FIELDS - 1;
}
setfield();
resetcmd();
return(NO);
}
break;
case '\t': /* go to next input field */
if (disprefs) {
selecting = !selecting;
if (selecting) {
move(displine[curdispline], 0);
refresh();
} else {
atfield();
resetcmd();
}
}
return(NO);
#ifdef KEY_ENTER
case KEY_ENTER:
#endif
case '\r':
case '\n': /* go to reference */
if (selecting) {
editref(curdispline);
return(YES);
}
/* FALLTHROUGH */
case ctrl('N'):
#ifdef KEY_DOWN
case KEY_DOWN:
#endif
#ifdef KEY_RIGHT
case KEY_RIGHT:
#endif
if (selecting) {
if ((curdispline + 1) < disprefs) {
move(displine[++curdispline], 0);
refresh();
}
} else {
field = (field + 1) % FIELDS;
setfield();
atfield();
resetcmd();
}
return(NO);
case ctrl('P'): /* go to previous input field */
#ifdef KEY_UP
case KEY_UP:
#endif
#ifdef KEY_LEFT
case KEY_LEFT:
#endif
if (selecting) {
if (curdispline) {
move(displine[--curdispline], 0);
refresh();
}
} else {
field = (field + (FIELDS - 1)) % FIELDS;
setfield();
atfield();
resetcmd();
}
return(NO);
#ifdef KEY_HOME
case KEY_HOME: /* go to first input field */
if (selecting) {
curdispline = 0;
move(REFLINE, 0);
refresh();
} else {
field = 0;
setfield();
atfield();
resetcmd();
}
return(NO);
#endif
#ifdef KEY_LL
case KEY_LL: /* go to last input field */
if (selecting) {
move(displine[disprefs - 1], 0);
refresh();
} else {
field = FIELDS - 1;
setfield();
atfield();
resetcmd();
}
return(NO);
#endif /* def(KEY_LL) */
case ' ': /* display next page */
case '+':
case ctrl('V'):
#ifdef KEY_NPAGE
case KEY_NPAGE:
#endif
/* don't redisplay if there are no lines */
if (totallines == 0) {
return(NO);
}
/* note: seekline() is not used to move to the next
* page because display() leaves the file pointer at
* the next page to optimize paging forward
*/
curdispline = 0;
break;
case ctrl('H'):
case '-': /* display previous page */
#ifdef KEY_PPAGE
case KEY_PPAGE:
#endif
/* don't redisplay if there are no lines */
if (totallines == 0) {
return(NO);
}
curdispline = 0;
/* if there are only two pages, just go to the other one */
if (totallines <= 2 * mdisprefs) {
break;
}
/* if on first page but not at beginning, go to beginning */
nextline -= mdisprefs; /* already at next page */
if (nextline > 1 && nextline <= mdisprefs) {
nextline = 1;
} else {
nextline -= mdisprefs;
if (nextline < 1) {
nextline = totallines - mdisprefs + 1;
if (nextline < 1) {
nextline = 1;
}
}
}
seekline(nextline);
break;
case '>': /* write or append the lines to a file */
if (totallines == 0) {
postmsg("There are no lines to write to a file");
} else { /* get the file name */
move(PRLINE, 0);
addstr("Write to file: ");
s = "w";
if ((c = mygetch()) == '>') {
move(PRLINE, 0);
addstr(appendprompt);
c = '\0';
s = "a";
}
if (c != '\r' &&
mygetline("", newpat, COLS - sizeof(appendprompt), c, NO) > 0) {
shellpath(filename, sizeof(filename), newpat);
if ((file = myfopen(filename, s)) == NULL) {
cannotopen(filename);
} else {
seekline(1);
while ((c = getc(refsfound)) != EOF) {
putc(c, file);
}
seekline(topline);
fclose(file);
}
}
clearprompt();
}
return(NO); /* return to the previous field */
case '<': /* read lines from a file */
move(PRLINE, 0);
addstr(readprompt);
if (mygetline("", newpat, COLS - sizeof(readprompt), '\0', NO) > 0) {
clearprompt();
shellpath(filename, sizeof(filename), newpat);
if (readrefs(filename) == NO) {
postmsg2("Ignoring an empty file");
return(NO);
}
return(YES);
}
clearprompt();
return(NO);
case '^': /* pipe the lines through a shell command */
case '|': /* pipe the lines to a shell command */
if (totallines == 0) {
postmsg("There are no lines to pipe to a shell command");
return(NO);
}
/* get the shell command */
move(PRLINE, 0);
addstr(pipeprompt);
if (mygetline("", newpat, COLS - sizeof(pipeprompt), '\0', NO) == 0) {
clearprompt();
return(NO);
}
/* if the ^ command, redirect output to a temp file */
if (commandc == '^') {
strcat(strcat(newpat, " >"), temp2);
/* HBB 20020708: somebody might have even
* their non-interactive default shells
* complain about clobbering
* redirections... --> delete before
* overwriting */
remove(temp2);
}
exitcurses();
if ((file = mypopen(newpat, "w")) == NULL) {
fprintf(stderr, "\
cscope: cannot open pipe to shell command: %s\n", newpat);
} else {
seekline(1);
while ((c = getc(refsfound)) != EOF) {
putc(c, file);
}
seekline(topline);
mypclose(file);
}
if (commandc == '^') {
if (readrefs(temp2) == NO) {
postmsg("Ignoring empty output of ^ command");
}
}
askforreturn();
entercurses();
break;
#if defined(KEY_RESIZE) && !defined(__DJGPP__)
case KEY_RESIZE:
/* XXX: fill in*/
break;
#endif
case ctrl('L'): /* redraw screen */
#ifdef KEY_CLEAR
case KEY_CLEAR:
#endif
clearmsg2();
clearok(curscr, TRUE);
wrefresh(curscr);
drawscrollbar(topline, bottomline);
return(NO);
case '!': /* shell escape */
execute(shell, shell, NULL);
seekline(topline);
break;
case '?': /* help */
clear();
help();
clear();
seekline(topline);
break;
case ctrl('E'): /* edit all lines */
editall();
break;
case ctrl('A'): /* HBB 20050428: added alt. keymapping */
case ctrl('Y'): /* repeat last pattern */
if (*Pattern != '\0') {
addstr(Pattern);
goto repeat;
}
break;
case ctrl('B'): /* cmd history back */
case ctrl('F'): /* cmd history fwd */
if (selecting) {
selecting = 0;
}
curritem = currentcmd();
item = (commandc == ctrl('F')) ? nextcmd() : prevcmd();
clearmsg2();
if (curritem == item) { /* inform user that we're at history end */
postmsg2("End of input field and search pattern history");
}
if (item) {
field = item->field;
setfield();
atfield();
addstr(item->text);
strcpy(Pattern, item->text);
switch (c = mygetch()) {
case '\r':
case '\n':
goto repeat;
case ctrl('F'):
case ctrl('B'):
myungetch(c);
atfield();
clrtoeol(); /* clear current field */
break;
default:
myungetch(c);
if (mygetline(Pattern, newpat, COLS - fldcolumn - 1, '\0', caseless )) {
strcpy (Pattern, newpat);
resetcmd();
}
goto repeat;
break;
}
}
return(NO);
case '\\': /* next character is not a command */
addch('\\'); /* display the quote character */
/* get a character from the terminal */
if ((commandc = mygetch()) == EOF) {
return(NO); /* quit */
}
addstr("\b \b"); /* erase the quote character */
goto ispat;
case '.':
postmsg("The . command has been replaced by ^Y");
atfield(); /* move back to the input field */
/* FALLTHROUGH */
default:
if (selecting && !mouse) {
char *c;
if ((c = strchr(dispchars, commandc)))
editref(c - dispchars);
/* if this is the start of a pattern */
} else if (isprint(commandc)) {
ispat:
if (mygetline("", newpat, COLS - fldcolumn - 1,
commandc, caseless) > 0) {
strcpy(Pattern, newpat);
resetcmd(); /* reset command history */
repeat:
addcmd(field, Pattern); /* add to command history */
if (field == CHANGE) {
/* prompt for the new text */
move(PRLINE, 0);
addstr(toprompt);
mygetline("", newpat,
COLS - sizeof(toprompt),
'\0', NO);
}
/* search for the pattern */
if (search() == YES) {
curdispline = 0;
++selecting;
switch (field) {
case DEFINITION:
case FILENAME:
if (totallines > 1) {
break;
}
topline = 1;
editref(0);
break;
case CHANGE:
return(changestring());
}
} else if (field == FILENAME &&
access(newpat, READ) == 0) {
/* try to edit the file anyway */
edit(newpat, "1");
}
} else { /* no pattern--the input was erased */
return(NO);
}
} else { /* control character */
return(NO);
}
} /* switch(commandc) */
return(YES);
}
/* clear the prompt line */
static void
clearprompt(void)
{
move(PRLINE, 0);
clrtoeol();
}
/* read references from a file */
BOOL
readrefs(char *filename)
{
FILE *file;
int c;
if ((file = myfopen(filename, "rb")) == NULL) {
cannotopen(filename);
return(NO);
}
if ((c = getc(file)) == EOF) { /* if file is empty */
fclose(file);
return(NO);
}
totallines = 0;
disprefs = 0;
nextline = 1;
if (writerefsfound() == YES) {
putc(c, refsfound);
while ((c = getc(file)) != EOF) {
putc(c, refsfound);
}
fclose(file);
fclose(refsfound);
if ( (refsfound = myfopen(temp1, "rb")) == NULL) {
cannotopen(temp1);
return(NO);
}
countrefs();
} else
fclose(file);
return(YES);
}
/* change one text string to another */
static BOOL
changestring(void)
{
char newfile[PATHLEN + 1]; /* new file name */
char oldfile[PATHLEN + 1]; /* old file name */
char linenum[NUMLEN + 1]; /* file line number */
char msg[MSGLEN + 1]; /* message */
FILE *script; /* shell script file */
BOOL anymarked = NO; /* any line marked */
MOUSE *p; /* mouse data */
int c;
unsigned int i;
char *s;
/* open the temporary file */
if ((script = myfopen(temp2, "w")) == NULL) {
cannotopen(temp2);
return(NO);
}
/* create the line change indicators */
change = calloc(totallines, sizeof(*change));
changing = YES;
mousemenu();
/* until the quit command is entered */
for (;;) {
/* display the current page of lines */
display();
same:
atchange();
/* get a character from the terminal */
if ((c = mygetch()) == EOF || c == ctrl('D')) {
break; /* change lines */
}
if (c == ctrl('Z')) {
#ifdef SIGTSTP
kill(0, SIGTSTP);
goto same;
#else
break; /* change lines */
#endif
}
/* see if the input character is a command */
switch (c) {
case ' ': /* display next page */
case '+':
case ctrl('V'):
#ifdef KEY_NPAGE
case KEY_NPAGE:
#endif
case '-': /* display previous page */
#ifdef KEY_PPAGE
case KEY_PPAGE:
#endif
case '!': /* shell escape */
case '?': /* help */
command(c);
break;
case ctrl('L'): /* redraw screen */
#ifdef KEY_CLEAR
case KEY_CLEAR:
#endif
command(c);
goto same;
case ESC: /* don't change lines */
#if UNIXPC
if((p = getmouseaction(DUMMYCHAR)) == NULL) {
goto nochange; /* unknown escape sequence */
}
break;
#endif
case ctrl('G'):
goto nochange;
case '*': /* mark/unmark all displayed lines */
for (i = 0; topline + i < nextline; ++i) {
mark(i);
}
goto same;
case ctrl('A'): /* mark/unmark all lines */
for (i = 0; i < totallines; ++i) {
if (change[i] == NO) {
change[i] = YES;
} else {
change[i] = NO;
}
}
/* show that all have been marked */
seekline(totallines);
break;
case ctrl('X'): /* mouse selection */
if ((p = getmouseaction(DUMMYCHAR)) == NULL) {
goto same; /* unknown control sequence */
}
/* if the button number is a scrollbar tag */
if (p->button == '0') {
scrollbar(p);
break;
}
/* find the selected line */
/* note: the selection is forced into range */
for (i = disprefs - 1; i > 0; --i) {
if (p->y1 >= displine[i]) {
break;
}
}
mark(i);
goto same;
default:
{
/* if a line was selected */
char *cc;
if ((cc = strchr(dispchars, c)))
mark(cc - dispchars);
goto same;
} /* default case */
} /* switch(change code character) */
} /* for(ever) */
/* for each line containing the old text */
fprintf(script, "ed - <<\\!\n");
*oldfile = '\0';
seekline(1);
for (i = 0;
fscanf(refsfound, "%" PATHLEN_STR "s%*s%" NUMLEN_STR "s%*[^\n]", newfile, linenum) == 2;
++i) {
/* see if the line is to be changed */
if (change[i] == YES) {
anymarked = YES;
/* if this is a new file */
if (strcmp(newfile, oldfile) != 0) {
/* make sure it can be changed */
if (access(newfile, WRITE) != 0) {
snprintf(msg, sizeof(msg), "Cannot write to file %s", newfile);
postmsg(msg);
anymarked = NO;
break;
}
/* if there was an old file */
if (*oldfile != '\0') {
fprintf(script, "w\n"); /* save it */
}
/* edit the new file */
strcpy(oldfile, newfile);
fprintf(script, "e %s\n", oldfile);
}
/* output substitute command */
fprintf(script, "%ss/", linenum); /* change */
for (s = Pattern; *s != '\0'; ++s) {
/* old text */
if (strchr("/\\[.^*", *s) != NULL) {
putc('\\', script);
}
if (caseless == YES && isalpha((unsigned char)*s)) {
putc('[', script);
if(islower((unsigned char)*s)) {
putc(toupper((unsigned char)*s), script);
putc(*s, script);
} else {
putc(*s, script);
putc(tolower((unsigned char)*s), script);
}
putc(']', script);
} else
putc(*s, script);
}
putc('/', script); /* to */
for (s = newpat; *s != '\0'; ++s) { /* new text */
if (strchr("/\\&", *s) != NULL) {
putc('\\', script);
}
putc(*s, script);
}
fprintf(script, "/gp\n"); /* and print */
}
}
fprintf(script, "w\nq\n!\n"); /* write and quit */
fclose(script);
/* if any line was marked */
if (anymarked == YES) {
/* edit the files */
clearprompt();
refresh();
fprintf(stderr, "Changed lines:\n\r");
execute("sh", "sh", temp2, NULL);
askforreturn();
seekline(1);
} else {
nochange:
clearprompt();
}
changing = NO;
mousemenu();
fclose(script);
free(change);
return(anymarked);
}
/* mark/unmark this displayed line to be changed */
static void
mark(unsigned int i)
{
unsigned int j;
j = i + topline - 1;
if (j < totallines) {
move(displine[i], 1);
if (change[j] == NO) {
change[j] = YES;
addch('>');
} else {
change[j] = NO;
addch(' ');
}
}
}
/* scrollbar actions */
static void
scrollbar(MOUSE *p)
{
/* reposition list if it makes sense */
if (totallines == 0) {
return;
}
switch (p->percent) {
case 101: /* scroll down one page */
if (nextline + mdisprefs > totallines) {
nextline = totallines - mdisprefs + 1;
}
break;
case 102: /* scroll up one page */
nextline = topline - mdisprefs;
if (nextline < 1) {
nextline = 1;
}
break;
case 103: /* scroll down one line */
nextline = topline + 1;
break;
case 104: /* scroll up one line */
if (topline > 1) {
nextline = topline - 1;
}
break;
default:
nextline = p->percent * totallines / 100;
}
seekline(nextline);
}
/* count the references found */
void
countrefs(void)
{
char *subsystem; /* OGS subsystem name */
char *book; /* OGS book name */
char file[PATHLEN + 1]; /* file name */
char function[PATLEN + 1]; /* function name */
char linenum[NUMLEN + 1]; /* line number */
int i;
/* count the references found and find the length of the file,
function, and line number display fields */
subsystemlen = 9; /* strlen("Subsystem") */
booklen = 4; /* strlen("Book") */
filelen = 4; /* strlen("File") */
fcnlen = 8; /* strlen("Function") */
numlen = 0;
/* HBB NOTE 2012-04-07: it may look like we shouldn't assing tempstring here,
* since it's not used. But it has to be assigned just so the return value
* of fscanf will actually reach 4. */
while (EOF != (i = fscanf(refsfound,
"%" PATHLEN_STR "s%" PATLEN_STR "s%" NUMLEN_STR "s %" TEMPSTRING_LEN_STR "[^\n]",
file, function, linenum, tempstring
)
)
) {
if ( (i != 4)
|| !isgraph((unsigned char) *file)
|| !isgraph((unsigned char) *function)
|| !isdigit((unsigned char) *linenum)
) {
postmsg("File does not have expected format");
totallines = 0;
disprefs = 0;
return;
}
if ((i = strlen(pathcomponents(file, dispcomponents))) > filelen) {
filelen = i;
}
if (ogs == YES) {
ogsnames(file, &subsystem, &book);
if ((i = strlen(subsystem)) > subsystemlen) {
subsystemlen = i;
}
if ((i = strlen(book)) > booklen) {
booklen = i;
}
}
if ((i = strlen(function)) > fcnlen) {
fcnlen = i;
}
if ((i = strlen(linenum)) > numlen) {
numlen = i;
}
++totallines;
}
rewind(refsfound);
/* restrict the width of displayed columns */
/* HBB FIXME 20060419: magic number alert! */
i = (COLS - 5) / 3;
if (ogs == YES) {
i = (COLS - 7) / 5;
}
if (filelen > i && i > 4) {
filelen = i;
}
if (subsystemlen > i && i > 9) {
subsystemlen = i;
}
if (booklen > i && i > 4) {
booklen = i;
}
if (fcnlen > i && i > 8) {
fcnlen = i;
}
}

211
src/compath.c Normal file
View File

@ -0,0 +1,211 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/*
* compath(pathname)
*
* This compresses pathnames. All strings of multiple slashes are
* changed to a single slash. All occurrences of "./" are removed.
* Whenever possible, strings of "/.." are removed together with
* the directory names that they follow.
*
* WARNING: since pathname is altered by this function, it should
* be located in a temporary buffer. This avoids the problem
* of accidently changing strings obtained from makefiles
* and stored in global structures.
*/
#include "global.h"
#ifndef NULL
#define NULL 0
#endif
char *
compath(char *pathname) /*FDEF*/
{
char *nextchar;
char *lastchar;
char *sofar;
char *pnend;
int pnlen;
/*
* do not change the path if it has no "/"
*/
if (strchr(pathname, '/') == NULL)
return(pathname);
/*
* find all strings consisting of more than one '/'
*/
for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++)
if ((*lastchar == '/') && (*(lastchar - 1) == '/'))
{
/*
* find the character after the last slash
*/
nextchar = lastchar;
while (*++lastchar == '/')
{
}
/*
* eliminate the extra slashes by copying
* everything after the slashes over the slashes
*/
sofar = nextchar;
while ((*nextchar++ = *lastchar++) != '\0')
;
lastchar = sofar;
}
/*
* find all strings of "./"
*/
for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++)
if ((*lastchar == '/') && (*(lastchar - 1) == '.') &&
((lastchar - 1 == pathname) || (*(lastchar - 2) == '/')))
{
/*
* copy everything after the "./" over the "./"
*/
nextchar = lastchar - 1;
sofar = nextchar;
while ((*nextchar++ = *++lastchar) != '\0')
;
lastchar = sofar;
}
/*
* find each occurrence of "/.."
*/
for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++)
if ((lastchar != pathname) && (*lastchar == '/') &&
(*(lastchar + 1) == '.') && (*(lastchar + 2) == '.') &&
((*(lastchar + 3) == '/') || (*(lastchar + 3) == '\0')))
{
/*
* find the directory name preceding the "/.."
*/
nextchar = lastchar - 1;
while ((nextchar != pathname) &&
(*(nextchar - 1) != '/'))
--nextchar;
/*
* make sure the preceding directory's name
* is not "." or ".."
*/
if ((*nextchar == '.') &&
((*(nextchar + 1) == '/') ||
((*(nextchar + 1) == '.') && (*(nextchar + 2) == '/'))))
/* EMPTY */;
else
{
/*
* prepare to eliminate either
* "dir_name/../" or "dir_name/.."
*/
if (*(lastchar + 3) == '/')
lastchar += 4;
else
lastchar += 3;
/*
* copy everything after the "/.." to
* before the preceding directory name
*/
sofar = nextchar - 1;
while ((*nextchar++ = *lastchar++) != '\0');
lastchar = sofar;
/*
* if the character before what was taken
* out is '/', set up to check if the
* slash is part of "/.."
*/
if ((sofar + 1 != pathname) && (*sofar == '/'))
--lastchar;
}
}
/*
* if the string is more than a character long and ends
* in '/', eliminate the '/'.
*/
pnlen = strlen(pathname);
pnend = strchr(pathname, '\0') - 1;
if ((pnlen > 1) && (*pnend == '/'))
{
*pnend-- = '\0';
pnlen--;
}
/*
* if the string has more than two characters and ends in
* "/.", remove the "/.".
*/
if ((pnlen > 2) && (*(pnend - 1) == '/') && (*pnend == '.'))
*--pnend = '\0';
/*
* if all characters were deleted, return ".";
* otherwise return pathname
*/
if (*pathname == '\0')
(void) strcpy(pathname, ".");
return(pathname);
}

133
src/constants.h Normal file
View File

@ -0,0 +1,133 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* preprocessor macro and constant definitions
*/
#ifndef CSCOPE_CONSTANTS_H
#define CSCOPE_CONSTANTS_H
#define ctrl(x) (x & 037) /* control character macro */
/* fast string equality tests (avoids most strcmp() calls) */
#define strequal(s1, s2) (*(s1) == *(s2) && strcmp(s1, s2) == 0)
#define strnotequal(s1, s2) (*(s1) != *(s2) || strcmp(s1, s2) != 0)
/* set the mark character for searching the cross-reference file */
#define setmark(c) (blockmark = c, block[blocklen] = blockmark)
/* get the next character in the cross-reference */
/* note that blockp is assumed not to be null */
#define getrefchar() (*(++blockp + 1) != '\0' ? *blockp : \
(read_block() != NULL ? *blockp : '\0'))
/* skip the next character in the cross-reference */
/* note that blockp is assumed not to be null and that
this macro will always be in a statement by itself */
#define skiprefchar() if (*(++blockp + 1) == '\0') (void) read_block()
#define ESC '\033' /* escape character */
#define DEL '\177' /* delete character */
#define DUMMYCHAR ' ' /* use space as a dummy character */
#define MSGLEN ((PATLEN) + 80) /* displayed message length */
#define NUMLEN 10 /* line number length */
#define PATHLEN 250 /* file pathname length */
#define PATLEN 250 /* symbol pattern length */
#define TEMPSTRING_LEN 8191 /* max strlen() of the global temp string */
#define REFFILE "cscope.out" /* cross-reference output file */
#define NAMEFILE "cscope.files" /* default list-of-files file */
#define INVNAME "cscope.in.out" /* inverted index to the database */
#define INVPOST "cscope.po.out" /* inverted index postings */
#define INVNAME2 "cscope.out.in"/* follows correct naming convention */
#define INVPOST2 "cscope.out.po"/* follows correct naming convention */
#define STMTMAX 10000 /* maximum source statement length */
#define STR2(x) #x
#define STRINGIZE(x) STR2(x)
#define PATLEN_STR STRINGIZE(PATLEN)
#define PATHLEN_STR STRINGIZE(PATHLEN)
#define NUMLEN_STR STRINGIZE(NUMLEN)
#define TEMPSTRING_LEN_STR STRINGIZE(TEMPSTRING_LEN)
/* screen lines */
#define FLDLINE (LINES - FIELDS - 1 - 1) /* first input field line */
#define MSGLINE 0 /* message line */
#define PRLINE (LINES - 1) /* input prompt line */
#define REFLINE 3 /* first displayed reference line */
/* input fields (value matches field order on screen) */
#define SYMBOL 0
#define DEFINITION 1
#define CALLEDBY 2
#define CALLING 3
#define STRING 4
#define CHANGE 5
#define REGEXP 6
#define FILENAME 7
#define INCLUDES 8
#define FIELDS 10
#if (BSD || V9) && !__NetBSD__ && !__FreeBSD__ && !__APPLE__
# define TERMINFO 0 /* no terminfo curses */
#else
# define TERMINFO 1
#endif
#if !TERMINFO
# ifndef KEY_BREAK
# define KEY_BREAK 0400 /* easier to define than to add #if around the use */
# endif
# ifndef KEY_ENTER
# define KEY_ENTER 0401
# endif
# ifndef KEY_BACKSPACE
# define KEY_BACKSPACE 0402
# endif
# if !sun
# define cbreak() crmode() /* name change */
# endif
# if UNIXPC
# define erasechar() (_tty.c_cc[VERASE]) /* equivalent */
# define killchar() (_tty.c_cc[VKILL]) /* equivalent */
# else
# define erasechar() (_tty.sg_erase) /* equivalent */
# define killchar() (_tty.sg_kill) /* equivalent */
# endif /* if UNIXPC */
#endif /* if !TERMINFO */
#endif /* CSCOPE_CONSTANTS_H */

492
src/crossref.c Normal file
View File

@ -0,0 +1,492 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* build cross-reference file
*/
#include "global.h"
#include "build.h"
#include "scanner.h"
#include <stdlib.h>
#include <sys/stat.h>
/* convert long to a string in base BASE notation */
#define ltobase(value) \
do { \
n = (value); \
s = buf + (sizeof(buf) - 1); \
*s = '\0'; \
digits = 1; \
while (n >= BASE) { \
++digits; \
i = n; \
n /= BASE; \
*--s = i - n * BASE + '!'; \
} \
*--s = n + '!'; \
} while (0)
#define SYMBOLINC 20 /* symbol list size increment */
long dboffset; /* new database offset */
BOOL errorsfound; /* prompt before clearing messages */
long lineoffset; /* source line database offset */
long npostings; /* number of postings */
int nsrcoffset; /* number of file name database offsets */
long *srcoffset; /* source file name database offsets */
unsigned long symbols; /* number of symbols */
static char *filename; /* file name for warning messages */
static long fcnoffset; /* function name database offset */
static long macrooffset; /* macro name database offset */
static unsigned long msymbols = SYMBOLINC; /* maximum number of symbols */
struct symbol { /* symbol data */
int type; /* type */
unsigned int first; /* index of first character in text */
unsigned int last; /* index of last+1 character in text */
unsigned int length; /* symbol length */
unsigned int fcn_level; /* function level of the symbol */
};
static struct symbol *symbol;
static void putcrossref(void);
static void savesymbol(int token, int num);
void
crossref(char *srcfile)
{
unsigned int i;
unsigned int length; /* symbol length */
unsigned int entry_no; /* function level of the symbol */
int token; /* current token */
struct stat st;
if (! ((stat(srcfile, &st) == 0)
&& S_ISREG(st.st_mode))) {
cannotopen(srcfile);
errorsfound = YES;
return;
}
entry_no = 0;
/* open the source file */
if ((yyin = myfopen(srcfile, "r")) == NULL) {
cannotopen(srcfile);
errorsfound = YES;
return;
}
filename = srcfile; /* save the file name for warning messages */
putfilename(srcfile); /* output the file name */
dbputc('\n');
dbputc('\n');
/* read the source file */
initscanner(srcfile);
fcnoffset = macrooffset = 0;
symbols = 0;
if (symbol == NULL) {
symbol = malloc(msymbols * sizeof(*symbol));
}
for (;;) {
/* get the next token */
switch (token = yylex()) {
default:
/* if requested, truncate C symbols */
length = last - first;
if (trun_syms == YES && length > 8 &&
token != INCLUDE && token != NEWFILE) {
length = 8;
last = first + 8;
}
/* see if the token has a symbol */
if (length == 0) {
savesymbol(token, entry_no);
break;
}
/* update entry_no if see function entry */
if (token == FCNDEF) {
entry_no++;
}
/* see if the symbol is already in the list */
for (i = 0; i < symbols; ++i) {
if (length == symbol[i].length
&& strncmp(my_yytext + first,
my_yytext + symbol[i].first,
length) == 0
&& entry_no == symbol[i].fcn_level
&& token == symbol[i].type
) { /* could be a::a() */
break;
}
}
if (i == symbols) { /* if not already in list */
savesymbol(token, entry_no);
}
break;
case NEWLINE: /* end of line containing symbols */
entry_no = 0; /* reset entry_no for each line */
#ifdef USING_LEX
--yyleng; /* remove the newline */
#endif
putcrossref(); /* output the symbols and source line */
lineno = myylineno; /* save the symbol line number */
#ifndef USING_LEX
/* HBB 20010425: replaced yyleng-- by this chunk: */
if (my_yytext)
*my_yytext = '\0';
my_yyleng = 0;
#endif
break;
case LEXERR: /* Lexer error, abort further parsing of this file */
case LEXEOF: /* end of file; last line may not have \n */
/* if there were symbols, output them and the source line */
if (symbols > 0) {
putcrossref();
}
(void) fclose(yyin); /* close the source file */
/* output the leading tab expected by the next call */
dbputc('\t');
return;
}
}
}
/* save the symbol in the list */
static void
savesymbol(int token, int num)
{
/* make sure there is room for the symbol */
if (symbols == msymbols) {
msymbols += SYMBOLINC;
symbol = realloc(symbol, msymbols * sizeof(*symbol));
}
/* save the symbol */
symbol[symbols].type = token;
symbol[symbols].first = first;
symbol[symbols].last = last;
symbol[symbols].length = last - first;
symbol[symbols].fcn_level = num;
++symbols;
}
/* output the file name */
void
putfilename(char *srcfile)
{
/* check for file system out of space */
/* note: dbputc is not used to avoid lint complaint */
if (putc(NEWFILE, newrefs) == EOF) {
cannotwrite(newreffile);
/* NOTREACHED */
}
++dboffset;
if (invertedindex == YES) {
srcoffset[nsrcoffset++] = dboffset;
}
dbfputs(srcfile);
fcnoffset = macrooffset = 0;
}
/* output the symbols and source line */
static void
putcrossref(void)
{
unsigned int i, j;
unsigned char c;
BOOL blank; /* blank indicator */
unsigned int symput = 0; /* symbols output */
int type;
/* output the source line */
lineoffset = dboffset;
dboffset += fprintf(newrefs, "%d ", lineno);
#ifdef PRINTF_RETVAL_BROKEN
dboffset = ftell(newrefs); /* fprintf doesn't return chars written */
#endif
/* HBB 20010425: added this line: */
my_yytext[my_yyleng] = '\0';
blank = NO;
for (i = 0; i < my_yyleng; ++i) {
/* change a tab to a blank and compress blanks */
if ((c = my_yytext[i]) == ' ' || c == '\t') {
blank = YES;
} else if (symput < symbols && i == symbol[symput].first) {
/* look for the start of a symbol */
/* check for compressed blanks */
if (blank == YES) {
blank = NO;
dbputc(' ');
}
dbputc('\n'); /* symbols start on a new line */
/* output any symbol type */
if ((type = symbol[symput].type) != IDENT) {
dbputc('\t');
dbputc(type);
} else {
type = ' ';
}
/* output the symbol */
j = symbol[symput].last;
c = my_yytext[j];
my_yytext[j] = '\0';
if (invertedindex == YES) {
putposting(my_yytext + i, type);
}
writestring(my_yytext + i);
dbputc('\n');
my_yytext[j] = c;
i = j - 1;
++symput;
} else {
/* HBB: try to save some time by early-out handling of
* non-compressed mode */
if (compress == NO) {
if (blank == YES) {
dbputc(' ');
blank = NO;
}
j = i + strcspn(my_yytext+i, "\t ");
if (symput < symbols
&& j >= symbol[symput].first)
j = symbol[symput].first;
c = my_yytext[j];
my_yytext[j] = '\0';
writestring(my_yytext + i);
my_yytext[j] = c;
i = j - 1;
/* finished this 'i', continue with the blank */
continue;
}
/* check for compressed blanks */
if (blank == YES) {
if (dicode2[c]) {
c = DICODE_COMPRESS(' ', c);
} else {
dbputc(' ');
}
} else if (IS_A_DICODE(c, my_yytext[i + 1])
&& symput < symbols
&& i + 1 != symbol[symput].first) {
/* compress digraphs */
c = DICODE_COMPRESS(c, my_yytext[i + 1]);
++i;
}
dbputc((int) c);
blank = NO;
/* skip compressed characters */
if (c < ' ') {
++i;
/* skip blanks before a preprocesor keyword */
/* note: don't use isspace() because \f and \v
are used for keywords */
while ((j = my_yytext[i]) == ' ' || j == '\t') {
++i;
}
/* skip the rest of the keyword */
while (isalpha((unsigned char)my_yytext[i])) {
++i;
}
/* skip space after certain keywords */
if (keyword[c].delim != '\0') {
while ((j = my_yytext[i]) == ' ' || j == '\t') {
++i;
}
}
/* skip a '(' after certain keywords */
if (keyword[c].delim == '('
&& my_yytext[i] == '(') {
++i;
}
--i; /* compensate for ++i in for() */
} /* if compressed char */
} /* else: not a symbol */
} /* for(i) */
/* ignore trailing blanks */
dbputc('\n');
dbputc('\n');
/* output any #define end marker */
/* note: must not be part of #define so putsource() doesn't discard it
so findcalledbysub() can find it and return */
if (symput < symbols && symbol[symput].type == DEFINEEND) {
dbputc('\t');
dbputc(DEFINEEND);
dbputc('\n');
dbputc('\n'); /* mark beginning of next source line */
macrooffset = 0;
}
symbols = 0;
}
/* HBB 20000421: new function, for avoiding memory leaks */
/* free the cross reference symbol table */
void
freecrossref()
{
if (symbol)
free(symbol);
symbol = NULL;
symbols = 0;
}
/* output the inverted index posting */
void
putposting(char *term, int type)
{
long i, n;
char *s;
int digits; /* digits output */
long offset; /* function/macro database offset */
char buf[11]; /* number buffer */
/* get the function or macro name offset */
offset = fcnoffset;
if (macrooffset != 0) {
offset = macrooffset;
}
/* then update them to avoid negative relative name offset */
switch (type) {
case DEFINE:
macrooffset = dboffset;
break;
case DEFINEEND:
macrooffset = 0;
return; /* null term */
case FCNDEF:
fcnoffset = dboffset;
break;
case FCNEND:
fcnoffset = 0;
return; /* null term */
}
/* ignore a null term caused by a enum/struct/union without a tag */
if (*term == '\0') {
return;
}
/* skip any #include secondary type char (< or ") */
if (type == INCLUDE) {
++term;
}
/* output the posting, which should be as small as possible to reduce
the temp file size and sort time */
(void) fputs(term, postings);
(void) putc(' ', postings);
/* the line offset is padded so postings for the same term will sort
in ascending line offset order to order the references as they
appear withing a source file */
ltobase(lineoffset);
for (i = PRECISION - digits; i > 0; --i) {
(void) putc('!', postings);
}
do {
(void) putc(*s, postings);
} while (*++s != '\0');
/* postings are also sorted by type */
(void) putc(type, postings);
/* function or macro name offset */
if (offset > 0) {
(void) putc(' ', postings);
ltobase(offset);
do {
(void) putc(*s, postings);
} while (*++s != '\0');
}
if (putc('\n', postings) == EOF) {
cannotwrite(temp1);
/* NOTREACHED */
}
++npostings;
}
/* put the string into the new database */
void
writestring(char *s)
{
unsigned char c;
int i;
if (compress == NO) {
/* Save some I/O overhead by using puts() instead of putc(): */
dbfputs(s);
return;
}
/* compress digraphs */
for (i = 0; (c = s[i]) != '\0'; ++i) {
if (/* dicode1[c] && dicode2[(unsigned char) s[i + 1]] */
IS_A_DICODE(c, s[i + 1])) {
/* c = (0200 - 2) + dicode1[c] + dicode2[(unsigned char) s[i + 1]]; */
c = DICODE_COMPRESS(c, s[i + 1]);
++i;
}
dbputc(c);
}
}
/* print a warning message with the file name and line number */
void
warning(char *text)
{
(void) fprintf(stderr, "cscope: \"%s\", line %d: warning: %s\n", filename,
myylineno, text);
errorsfound = YES;
}

747
src/dir.c Normal file
View File

@ -0,0 +1,747 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* directory searching functions
*/
#include "global.h"
#include "vp.h" /* vpdirs and vpndirs */
#include <stdlib.h>
#include <sys/types.h> /* needed by stat.h and dirent.h */
#include <dirent.h>
#include <sys/stat.h> /* stat */
#include <assert.h>
#define DIRSEPS " ,:" /* directory list separators */
#define DIRINC 10 /* directory list size increment */
#define HASHMOD 2003 /* must be a prime number */
#define SRCINC HASHMOD /* source file list size increment */
/* largest known database had 22049 files */
char currentdir[PATHLEN + 1];/* current directory */
char **incdirs; /* #include directories */
char **srcdirs; /* source directories */
char **srcfiles; /* source files */
unsigned long nincdirs; /* number of #include directories */
unsigned long nsrcdirs; /* number of source directories */
unsigned long nsrcfiles; /* number of source files */
unsigned long msrcfiles = SRCINC; /* maximum number of source files */
static char **incnames; /* #include directory names without view pathing */
static unsigned long mincdirs = DIRINC; /* maximum number of #include directories */
static unsigned long msrcdirs; /* maximum number of source directories */
static unsigned long nvpsrcdirs; /* number of view path source directories */
static struct listitem { /* source file names without view pathing */
char *text;
struct listitem *next;
} *srcnames[HASHMOD];
/* Internal prototypes: */
static BOOL accessible_file(char *file);
static BOOL issrcfile(char *file);
static void addsrcdir(char *dir);
static void addincdir(char *name, char *path);
static void scan_dir(const char *dirfile, BOOL recurse);
static void makevpsrcdirs(void);
/* make the view source directory list */
static void
makevpsrcdirs(void)
{
int i;
/* return if this function has already been called */
if (nsrcdirs > 0) {
return;
}
/* get the current directory name */
if (getcwd(currentdir, PATHLEN) == NULL) {
fprintf(stderr, "cscope: warning: cannot get current directory name\n");
strcpy(currentdir, "<unknown>");
}
/* see if there is a view path and this directory is in it */
vpinit(currentdir);
if (vpndirs > 1) {
nsrcdirs = vpndirs;
} else {
nsrcdirs = 1;
}
/* create the source directory list */
msrcdirs = nsrcdirs + DIRINC;
srcdirs = malloc(msrcdirs * sizeof(*srcdirs));
*srcdirs = "."; /* first source dir is always current dir */
for (i = 1; i < vpndirs; ++i) {
srcdirs[i] = vpdirs[i];
}
/* save the number of original source directories in the view path */
nvpsrcdirs = nsrcdirs;
}
/* add a source directory to the list for each view path source directory */
void
sourcedir(char *dirlist)
{
char path[PATHLEN + 1];
char *dir;
unsigned int i;
makevpsrcdirs(); /* make the view source directory list */
dirlist = strdup(dirlist); /* don't change environment variable text */
/* parse the directory list */
dir = strtok(dirlist, DIRSEPS);
while (dir != NULL) {
int dir_len = strlen(dir);
addsrcdir(dir);
/* if it isn't a full path name and there is a
multi-directory view path */
if (*dirlist != '/' && vpndirs > 1) {
/* compute its path from higher view path source dirs */
for (i = 1; i < nvpsrcdirs; ++i) {
snprintf(path, sizeof(path), "%.*s/%s",
PATHLEN - 2 - dir_len,
srcdirs[i], dir);
addsrcdir(path);
}
}
dir = strtok(NULL, DIRSEPS);
}
free(dirlist); /* HBB 20000421: avoid memory leaks */
}
/* add a source directory to the list */
static void
addsrcdir(char *dir)
{
struct stat statstruct;
/* make sure it is a directory */
if (lstat(compath(dir), &statstruct) == 0 &&
S_ISDIR(statstruct.st_mode)) {
/* note: there already is a source directory list */
if (nsrcdirs == msrcdirs) {
msrcdirs += DIRINC;
srcdirs = realloc(srcdirs, msrcdirs * sizeof(*srcdirs));
}
srcdirs[nsrcdirs++] = strdup(dir);
}
}
/* HBB 20000421: new function, for avoiding leaks */
/* free list of src directories */
void
freesrclist()
{
if (!srcdirs)
return;
while(nsrcdirs>1)
free(srcdirs[--nsrcdirs]);
free(srcdirs);
}
/* add a #include directory to the list for each view path source directory */
void
includedir(char *dirlist)
{
char path[PATHLEN + 1];
char *dir;
unsigned int i;
makevpsrcdirs(); /* make the view source directory list */
dirlist = strdup(dirlist); /* don't change environment variable text */
/* parse the directory list */
dir = strtok(dirlist, DIRSEPS);
while (dir != NULL) {
size_t dir_len = strlen(dir);
addincdir(dir, dir);
/* if it isn't a full path name and there is a
multi-directory view path */
if (*dirlist != '/' && vpndirs > 1) {
/* compute its path from higher view path source dirs */
for (i = 1; i < nvpsrcdirs; ++i) {
snprintf(path, sizeof(path), "%.*s/%s",
(int)(PATHLEN - 2 - dir_len),
srcdirs[i], dir);
addincdir(dir, path);
}
}
dir = strtok(NULL, DIRSEPS);
}
free(dirlist); /* HBB 20000421: avoid leaks */
}
/* add a #include directory to the list */
static void
addincdir(char *name, char *path)
{
struct stat statstruct;
/* make sure it is a directory */
if (lstat(compath(path), &statstruct) == 0 &&
S_ISDIR(statstruct.st_mode)) {
if (incdirs == NULL) {
incdirs = malloc(mincdirs * sizeof(*incdirs));
incnames = malloc(mincdirs * sizeof(*incnames));
} else if (nincdirs == mincdirs) {
mincdirs += DIRINC;
incdirs = realloc(incdirs, mincdirs * sizeof(*incdirs));
incnames = realloc(incnames, mincdirs * sizeof(*incnames));
}
incdirs[nincdirs] = strdup(path);
incnames[nincdirs++] = strdup(name);
}
}
/* HBB 2000421: new function, for avoiding memory leaks */
/* free the list of include files, if wanted */
void
freeinclist()
{
if (!incdirs)
return;
while(nincdirs>0) {
free(incdirs[--nincdirs]);
free(incnames[nincdirs]);
}
free(incdirs);
free(incnames);
}
/* make the source file list */
void
makefilelist(void)
{
static BOOL firstbuild = YES; /* first time through */
FILE *names; /* name file pointer */
char dir[PATHLEN + 1];
char path[PATHLEN + 1];
char line[PATHLEN * 10];
char *file;
char *s;
unsigned int i;
makevpsrcdirs(); /* make the view source directory list */
/* if -i was NOT given and there are source file arguments */
if (namefile == NULL && fileargc > 0) {
/* put them in a list that can be expanded */
for (i = 0; i < fileargc; ++i) {
file = fileargv[i];
if (infilelist(file) == NO) {
if ((s = inviewpath(file)) != NULL) {
addsrcfile(s);
} else {
fprintf(stderr, "cscope: cannot find file %s\n",
file);
errorsfound = YES;
}
}
}
return;
}
/* see if a file name file exists */
if (namefile == NULL && vpaccess(NAMEFILE, READ) == 0) {
namefile = NAMEFILE;
}
if (namefile == NULL) {
/* No namefile --> make a list of all the source files
* in the directories */
for (i = 0; i < nsrcdirs; ++i) {
scan_dir(srcdirs[i], recurse_dir);
}
return;
}
/* Came here --> there is a file of source file names */
if (strcmp(namefile, "-") == 0)
names = stdin;
else if ((names = vpfopen(namefile, "r")) == NULL) {
cannotopen(namefile);
myexit(1);
}
/* get the names in the file */
while (fgets(line, 10*PATHLEN, names) != NULL) {
char *point_in_line = line + (strlen(line) - 1);
size_t length_of_name = 0;
int unfinished_option = 0;
BOOL done = NO;
/* Kill away \n left at end of fgets()'d string: */
if (*point_in_line == '\n')
*point_in_line = '\0';
/* Parse whitespace-terminated strings in line: */
point_in_line = line;
while (sscanf(point_in_line, "%" PATHLEN_STR "s", path) == 1) {
/* Have to store this length --- inviewpath() will
* modify path, later! */
length_of_name = strlen(path);
if (*path == '-') { /* if an option */
if (unfinished_option) {
/* Can't have another option directly after an
* -I or -p option with no name after it! */
fprintf(stderr, "\
cscope: Syntax error in namelist file %s: unfinished -I or -p option\n",
namefile);
unfinished_option = 0;
}
i = path[1];
switch (i) {
case 'c': /* ASCII characters only in crossref */
compress = NO;
break;
case 'k': /* ignore DFLT_INCDIR */
kernelmode = YES;
break;
case 'q': /* quick search */
invertedindex = YES;
break;
case 'T': /* truncate symbols to 8 characters */
trun_syms = YES;
break;
case 'I': /* #include file directory */
case 'p': /* file path components to display */
/* coverity[overwrite_var] */
s = path + 2; /* for "-Ipath" */
if (*s == '\0') { /* if "-I path" */
unfinished_option = i;
break;
}
/* this code block used several times in here
* --> make it a macro to avoid unnecessary
* duplication */
#define HANDLE_OPTION_ARGUMENT(i, s) \
switch (i) { \
case 'I': /* #include file directory */ \
if (firstbuild == YES) { \
/* expand $ and ~ */ \
shellpath(dir, sizeof(dir), (s)); \
includedir(dir); \
} \
unfinished_option = 0; \
done = YES; \
break; \
case 'p': /* file path components to display */ \
if (*(s) < '0' || *(s) > '9') { \
fprintf(stderr, \
"cscope: -p option in file %s: missing or invalid numeric value\n", \
namefile); \
} \
dispcomponents = atoi(s); \
unfinished_option = 0; \
done = YES; \
break; \
default: \
done = NO; \
} /* switch(i) */
/* ... and now call it for the first time */
HANDLE_OPTION_ARGUMENT(i, s)
break;
default:
fprintf(stderr, "cscope: only -I, -c, -k, -p, and -T options can be in file %s\n",
namefile);
} /* switch(i) */
} /* if('-') */
else if (*path == '"') {
/* handle quoted filenames... */
size_t in = 1, out = 0;
char *newpath = malloc(PATHLEN + 1);
while (in < PATHLEN && point_in_line[in] != '\0') {
if (point_in_line[in] == '"') {
newpath[out] = '\0';
/* Tell outer loop to skip over this entire
* quoted string */
length_of_name = in + 1;
break; /* found end of quoted string */
} else if (point_in_line[in] == '\\'
&& in < PATHLEN - 1
&& (point_in_line[in + 1]== '"'
|| point_in_line[in + 1] == '\\')) {
/* un-escape \" or \\ sequence */
newpath[out++] = point_in_line[in + 1];
in += 2;
} else {
newpath[out++] = point_in_line[in++];
}
} /* while(in) */
if (in >= PATHLEN) { /* safeguard against almost-overflow */
newpath[out]='\0';
}
/* If an -I or -p arguments was missing before,
* treat this name as the argument: */
HANDLE_OPTION_ARGUMENT(unfinished_option, newpath);
if (! done) {
/* coverity[overwrite_var] */
if ((s = inviewpath(newpath)) != NULL) {
addsrcfile(s);
} else {
fprintf(stderr, "cscope: cannot find file %s\n",
newpath);
errorsfound = YES;
}
}
free(newpath);
} /* if(quoted name) */
else {
/* ... so this is an ordinary file name, unquoted */
/* If an -I or -p arguments was missing before,
* treat this name as the argument: */
HANDLE_OPTION_ARGUMENT(unfinished_option, path);
if (!done) {
if ((s = inviewpath(path)) != NULL) {
addsrcfile(s);
} else {
fprintf(stderr, "cscope: cannot find file %s\n",
path);
errorsfound = YES;
}
}
} /* else(ordinary name) */
point_in_line += length_of_name;
while (isspace((unsigned char) *point_in_line))
point_in_line ++;
} /* while(sscanf(line)) */
} /* while(fgets(line)) */
if (names == stdin)
clearerr(stdin);
else
fclose(names);
firstbuild = NO;
return;
}
/* scan a directory (recursively?) for source files */
static void
scan_dir(const char *adir, BOOL recurse_dir)
{
DIR *dirfile;
int adir_len = strlen(adir);
/* FIXME: no guards against adir_len > PATHLEN, yet */
if ((dirfile = opendir(adir)) != NULL) {
struct dirent *entry;
char path[PATHLEN + 1];
while ((entry = readdir(dirfile)) != NULL) {
if ((strcmp(".",entry->d_name) != 0)
&& (strcmp("..",entry->d_name) != 0)) {
struct stat buf;
snprintf(path, sizeof(path), "%s/%.*s", adir,
PATHLEN - 2 - adir_len,
entry->d_name);
if (lstat(path,&buf) == 0) {
if (recurse_dir
&& S_ISDIR(buf.st_mode) ) {
scan_dir(path, recurse_dir);
} else if (issrcfile(path)
&& infilelist(path) == NO
&& access(path, R_OK) == 0) {
addsrcfile(path);
}
}
}
}
closedir(dirfile);
}
return;
}
/* see if this is a source file */
static BOOL
issrcfile(char *path)
{
struct stat statstruct;
char *file = basename(path);
char *s = strrchr(file, '.');
BOOL looks_like_source = NO;
/* ensure there is some file suffix */
if (s == NULL || *++s == '\0')
return NO;
/* if an SCCS or versioned file */
if (file[1] == '.' && file + 2 != s) { /* 1 character prefix */
switch (*file) {
case 's':
case 'S':
return(NO);
}
}
if (s[1] == '\0') { /* 1 character suffix */
switch (*s) {
case 'c':
case 'h':
case 'l':
case 'y':
case 'C':
case 'G':
case 'H':
case 'L':
looks_like_source = YES;
}
} else if ((s[2] == '\0') /* 2 char suffix */
&& ((s[0] == 'b' && s[1] == 'p') /* breakpoint listing */
|| (s[0] == 'q'
&& (s[1] == 'c' || s[1] == 'h')) /* Ingres */
|| (s[0] == 's' && s[1] == 'd') /* SDL */
|| (s[0] == 'c' && s[1] == 'c') /* C++ source */
|| (s[0] == 'h' && s[1] == 'h'))) { /* C++ header */
looks_like_source = YES;
} else if((s[3] == '\0') /* 3 char suffix */
/* C++ template source */
&& ((s[0] == 't' && s[1] == 'c' && s[2] == 'c' )
/* C++ source: */
|| (s[0] == 'c' && s[1] == 'p' && s[2] == 'p' )
|| (s[0] == 'c' && s[1] == 'x' && s[2] == 'x' )
|| (s[0] == 'h' && s[1] == 'p' && s[2] == 'p' )
|| (s[0] == 'h' && s[1] == 'x' && s[2] == 'x' ))
) {
looks_like_source = YES;
}
if (looks_like_source != YES)
return NO;
/* make sure it is a file */
if (lstat(path, &statstruct) == 0 &&
S_ISREG(statstruct.st_mode)) {
return(YES);
}
return NO;
}
/* add an include file to the source file list */
void
incfile(char *file, char *type)
{
char name[PATHLEN + 1];
char path[PATHLEN + 1];
char *s;
unsigned int i;
assert(file != NULL); /* should never happen, but let's make sure anyway */
/* see if the file is already in the source file list */
if (infilelist(file) == YES) {
return;
}
/* look in current directory if it was #include "file" */
if (type[0] == '"' && (s = inviewpath(file)) != NULL) {
addsrcfile(s);
} else {
size_t file_len = strlen(file);
/* search for the file in the #include directory list */
for (i = 0; i < nincdirs; ++i) {
/* don't include the file from two directories */
snprintf(name, sizeof(name), "%.*s/%s",
(int)(PATHLEN - 2 - file_len), incnames[i],
file);
if (infilelist(name) == YES) {
break;
}
/* make sure it exists and is readable */
snprintf(path, sizeof(path), "%.*s/%s",
(int)(PATHLEN - 2 - file_len), incdirs[i],
file);
if (access(compath(path), READ) == 0) {
addsrcfile(path);
break;
}
}
}
}
/* see if the file is already in the list */
BOOL
infilelist(char *path)
{
struct listitem *p;
for (p = srcnames[hash(compath(path)) % HASHMOD];
p != NULL;
p = p->next) {
if (strequal(path, p->text)) {
return(YES);
}
}
return(NO);
}
/* check if a file is readable enough to be allowed in the
* database */
static BOOL
accessible_file(char *file)
{
if (access(compath(file), READ) == 0) {
struct stat stats;
if (lstat(file, &stats) == 0
&& S_ISREG(stats.st_mode)) {
return YES;
}
}
return NO;
}
/* search for the file in the view path */
char *
inviewpath(char *file)
{
static char path[PATHLEN + 1];
unsigned int i;
/* look for the file */
if (accessible_file(file)) {
return(file);
}
/* if it isn't a full path name and there is a multi-directory
* view path */
if (*file != '/' && vpndirs > 1) {
int file_len = strlen(file);
/* compute its path from higher view path source dirs */
for (i = 1; i < nvpsrcdirs; ++i) {
snprintf(path, sizeof(path), "%.*s/%s",
PATHLEN - 2 - file_len, srcdirs[i],
file);
if (accessible_file(path)) {
return(path);
}
}
}
return(NULL);
}
/* add a source file to the list */
void
addsrcfile(char *path)
{
struct listitem *p;
int i;
/* make sure there is room for the file */
if (nsrcfiles == msrcfiles) {
msrcfiles += SRCINC;
srcfiles = realloc(srcfiles, msrcfiles * sizeof(*srcfiles));
}
/* add the file to the list */
srcfiles[nsrcfiles++] = strdup(compath(path));
p = malloc(sizeof(*p));
p->text = strdup(compath(path));
i = hash(p->text) % HASHMOD;
p->next = srcnames[i];
srcnames[i] = p;
}
/* free the memory allocated for the source file list */
void
freefilelist(void)
{
struct listitem *p, *nextp;
int i;
/* if '-d' option is used a string space block is allocated */
if (isuptodate == NO) {
while (nsrcfiles > 0) {
free (srcfiles[--nsrcfiles]);
}
} else {
/* for '-d' option free the string space block */
/* protect against empty list */
if (nsrcfiles > 0)
free (srcfiles[0]);
nsrcfiles = 0;
}
free (srcfiles); /* HBB 20000421: avoid leak */
msrcfiles = 0;
srcfiles=0;
for (i = 0; i < HASHMOD; ++i) {
for (p = srcnames[i]; p != NULL; p = nextp) {
/* HBB 20000421: avoid memory leak */
free(p->text);
nextp = p->next;
free(p);
}
srcnames[i] = NULL;
}
}

784
src/display.c Normal file
View File

@ -0,0 +1,784 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* display functions
*/
#include "global.h"
#include "build.h"
#ifdef CCS
#include "sgs.h" /* ESG_PKG and ESG_REL */
#else
#include "version.h" /* FILEVERSION and FIXVERSION */
#endif
#include <ncurses.h>
#include <setjmp.h> /* jmp_buf */
#include <stdarg.h> /* va_list stuff */
#include <time.h>
#include <errno.h>
#include <stdarg.h>
int booklen; /* OGS book name display field length */
int *displine; /* screen line of displayed reference */
unsigned int disprefs; /* displayed references */
int field; /* input field */
int filelen; /* file name display field length */
int fcnlen; /* function name display field length */
unsigned int mdisprefs; /* maximum displayed references */
unsigned int nextline; /* next line to be shown */
FILE *nonglobalrefs; /* non-global references file */
int numlen; /* line number display field length */
unsigned int topline = 1; /* top line of page */
int bottomline; /* bottom line of page */
long searchcount; /* count of files searched */
int subsystemlen; /* OGS subsystem name display field length */
unsigned int totallines; /* total reference lines */
unsigned fldcolumn; /* input field column */
WINDOW* body;
WINDOW* input_fields;
static enum {
CH_BODY = 0x0001,
CH_INPUT_FIELDS = CH_BODY << 1,
CH_COMMAND_FIELD = CH_BODY << 2,
CH_ALL = CH_BODY | CH_INPUT_FIELDS | CH_COMMAND_FIELD
};
const char dispchars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static int fldline; /* input field line */
static sigjmp_buf env; /* setjmp/longjmp buffer */
static int lastdispline; /* last displayed reference line */
static char lastmsg[MSGLEN + 1]; /* last message displayed */
static const char helpstring[] = "Press the ? key for help";
static const char selprompt[] =
"Select lines to change (press the ? key for help): ";
typedef char * (*FP)(char *); /* pointer to function returning a character pointer */
/* HBB 2000/05/05: I removed the casts to function pointer type. It is
* fundamentally unsafe to call a function through a pointer of a
* different type ('undefined behaviour' in the words of the ANSI/ISO
* C standard). Instead, I made all the find...() functions adhere to
* the same function type, by changing argument passing a bit. */
static struct { /* text of input fields */
char *text1;
char *text2;
FP findfcn;
} fields[FIELDS + 1] = { /* samuel has a search that is not part of the cscope display */
{"Find this", "C symbol", findsymbol},
{"Find this", "global definition", finddef},
{"Find", "functions called by this function", findcalledby},
{"Find", "functions calling this function", findcalling},
{"Find this", "text string", findstring},
{"Change this", "text string", findstring},
{"Find this", "egrep pattern", findregexp},
{"Find this", "file", findfile},
{"Find", "files #including this file", findinclude},
{"Find", "assignments to this symbol", findassign},
{"Find all", "function definitions", findallfcns}, /* samuel only */
};
/* Internal prototypes: */
static void jumpback(int sig);
/* initialize display parameters */
void
dispinit(void)
{
/* initialize the curses display package */
initscr(); /* initialize the screen */
entercurses();
keypad(stdscr, TRUE); /* enable the keypad */
//fixkeypad(); /* fix for getch() intermittently returning garbage */
standend(); /* turn off reverse video */
/* calculate the maximum displayed reference lines */
lastdispline = FLDLINE - 3;
mdisprefs = lastdispline - REFLINE + 1;
if (mdisprefs <= 0) {
postfatal("%s: screen too small\n", argv0);
/* NOTREACHED */
}
if (mouse == NO && mdisprefs > strlen(dispchars))
mdisprefs = strlen(dispchars);
/* allocate the displayed line array */
displine = malloc(mdisprefs * sizeof(*displine));
/* initialize windows */
body = newwin(LINES-2-FIELDS, COLS-2, 1, 1);
input_fields = newwin(FIELDS, COLS-2, FLDLINE, 1);
refresh();
}
static inline void display_frame(){
box(stdscr, 0, 0);
/* Title*/
const int LEFT_PADDING = 5;
wmove(stdscr, 0, LEFT_PADDING);
#if CCS
if (displayversion == YES) {
wprintw(stdscr, "cscope %s", ESG_REL);
}
else {
waddstr(stdscr, "cscope");
}
#else
wprintw(stdscr, "Cscope version %d%s", FILEVERSION, FIXVERSION);
#endif
wmove(stdscr, 0, COLS - (int) sizeof(helpstring));
waddstr(stdscr, helpstring);
wmove(input_fields, 0, 0);
for(int i = 0; i < COLS-2; i++){
waddch(input_fields, ACS_HLINE);
}
}
static inline void display_input_fields(){
/* display the input fields */
wmove(input_fields, 1, 0);
for(int i = 0; i < FIELDS; ++i){
wprintw(input_fields, "%s %s:\n", fields[i].text1, fields[i].text2);
}
}
static inline void display_command_field(){
}
void
display(void)
{
char *subsystem; /* OGS subsystem name */
char *book; /* OGS book name */
char file[PATHLEN + 1]; /* file name */
char function[PATLEN + 1]; /* function name */
char linenum[NUMLEN + 1]; /* line number */
int screenline; /* screen line number */
int width; /* source line display width */
int i;
char *s;
erase();
display_frame();
if (totallines == 0) {
/* if no references were found */
/* redisplay the last message */
waddstr(body, lastmsg);
} else {
/* display the pattern */
if (changing == YES) {
wprintw(body, "Change \"%s\" to \"%s\"", Pattern, newpat);
} else {
wprintw(body, "%c%s: %s", toupper((unsigned char)fields[field].text2[0]),
fields[field].text2 + 1, Pattern);
}
/* display the column headings */
wmove(body, 2, 2);
if (ogs == YES && field != FILENAME) {
wprintw(body, "%-*s ", subsystemlen, "Subsystem");
wprintw(body, "%-*s ", booklen, "Book");
}
if (dispcomponents > 0)
wprintw(body, "%-*s ", filelen, "File");
if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
wprintw(body, "%-*s ", fcnlen, "Function");
}
if (field != FILENAME) {
waddstr(body, "Line");
}
waddch(body, '\n');
/* if at end of file go back to beginning */
if (nextline > totallines) {
seekline(1);
}
/* calculate the source text column */
width = COLS - numlen - 3;
if (ogs == YES) {
width -= subsystemlen + booklen + 2;
}
if (dispcomponents > 0) {
width -= filelen + 1;
}
if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
width -= fcnlen + 1;
}
/* until the max references have been displayed or
there is no more room */
topline = nextline;
for (disprefs = 0, screenline = REFLINE;
disprefs < mdisprefs && screenline <= lastdispline;
++disprefs, ++screenline) {
/* read the reference line */
if (fscanf(refsfound, "%" PATHLEN_STR "s%" PATHLEN_STR "s%" NUMLEN_STR "s %" TEMPSTRING_LEN_STR "[^\n]", file, function,
linenum, tempstring) < 4) {
break;
}
++nextline;
displine[disprefs] = screenline;
/* if no mouse, display the selection number */
if (mouse == YES) {
waddch(body, ' ');
} else {
wprintw(body, "%c", dispchars[disprefs]);
}
/* display any change mark */
if (changing == YES &&
change[topline + disprefs - 1] == YES) {
waddch(body, '>');
} else {
waddch(body, ' ');
}
/* display the file name */
if (field == FILENAME) {
wprintw(body, "%-*s ", filelen, file);
} else {
/* if OGS, display the subsystem and book names */
if (ogs == YES) {
ogsnames(file, &subsystem, &book);
wprintw(body, "%-*.*s ", subsystemlen, subsystemlen, subsystem);
wprintw(body, "%-*.*s ", booklen, booklen, book);
}
/* display the requested path components */
if (dispcomponents > 0) {
wprintw(body, "%-*.*s ", filelen, filelen,
pathcomponents(file, dispcomponents));
}
} /* else(field == FILENAME) */
/* display the function name */
if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
wprintw(body, "%-*.*s ", fcnlen, fcnlen, function);
}
if (field == FILENAME) {
waddch(body, '\n'); /* go to next line */
continue;
}
/* display the line number */
wprintw(body, "%*s ", numlen, linenum);
/* there may be tabs in egrep output */
while ((s = strchr(tempstring, '\t')) != NULL) {
*s = ' ';
}
/* display the source line */
s = tempstring;
for (;;) {
/* see if the source line will fit */
if ((i = strlen(s)) > width) {
/* find the nearest blank */
for (i = width; s[i] != ' ' && i > 0; --i) {
;
}
if (i == 0) {
i = width; /* no blank */
}
}
/* print up to this point */
wprintw(body, "%.*s", i, s);
s += i;
/* if line didn't wrap around */
if (i < width) {
waddch(body, '\n'); /* go to next line */
}
/* skip blanks */
while (*s == ' ') {
++s;
}
/* see if there is more text */
if (*s == '\0') {
break;
}
/* if the source line is too long */
if (++screenline > lastdispline) {
/* if this is the first displayed line,
display what will fit on the screen */
if (topline == nextline -1) {
disprefs++;
/* break out of two loops */
goto endrefs;
}
/* erase the reference */
while (--screenline >= displine[disprefs]) {
wmove(body, screenline, 0);
clrtoeol();
}
++screenline;
/* go back to the beginning of this reference */
--nextline;
seekline(nextline);
goto endrefs;
}
/* indent the continued source line */
wmove(body, screenline, COLS - width);
} /* for(ever) */
} /* for(reference output lines) */
endrefs:
/* position the cursor for the message */
i = FLDLINE - 1;
if (screenline < i) {
waddch(body, '\n');
}
else {
wmove(body, i, 0);
}
/* check for more references */
i = totallines - nextline + 1;
bottomline = nextline;
if (i > 0) {
wprintw(body, "* Lines %d-%d of %d, %d more - press the space bar to display more *", topline, bottomline, totallines, i);
}
/* if this is the last page of references */
else if (topline > 1 && nextline > totallines) {
waddstr(body, "* Press the space bar to display the first lines again *");
}
}
drawscrollbar(topline, nextline); /* display the scrollbar */
atfield();
display_input_fields();
display_prompt();
refresh();
wrefresh(body);
wrefresh(input_fields);
}
/* set the cursor position for the field */
//void
//setfield(void)
//{
// fldline = FLDLINE + field;
// fldcolumn = strlen(fields[field].text1) + strlen(fields[field].text2) + 3;
//}
/* move to the current input field */
//
//void
//atfield(void)
//{
// wmove(input_fields, fldline, fldcolumn);
//}
/* move to the changing lines prompt */
//void
//atchange(void)
//{
// wmove(body, PRLINE, (int) sizeof(selprompt) - 1);
//}
/* search for the symbol or text pattern */
/*ARGSUSED*/
static void
jumpback(int sig)
{
signal(sig, jumpback);
siglongjmp(env, 1);
}
BOOL
search(void)
{
char *findresult = NULL; /* find function output */
BOOL funcexist = YES; /* find "function" error */
FINDINIT rc = NOERROR; /* findinit return code */
sighandler_t savesig; /* old value of signal */
FP f; /* searching function */
int c;
/* open the references found file for writing */
if (writerefsfound() == NO) {
return(NO);
}
/* find the pattern - stop on an interrupt */
if (linemode == NO) {
postmsg("Searching");
}
searchcount = 0;
savesig = signal(SIGINT, jumpback);
if (sigsetjmp(env, 1) == 0) {
f = fields[field].findfcn;
if (f == findregexp || f == findstring) {
findresult = (*f)(Pattern);
} else {
if ((nonglobalrefs = myfopen(temp2, "wb")) == NULL) {
cannotopen(temp2);
return(NO);
}
if ((rc = findinit(Pattern)) == NOERROR) {
(void) dbseek(0L); /* read the first block */
findresult = (*f)(Pattern);
if (f == findcalledby)
funcexist = (*findresult == 'y');
findcleanup();
/* append the non-global references */
(void) fclose(nonglobalrefs);
if ((nonglobalrefs = myfopen(temp2, "rb"))
== NULL) {
cannotopen(temp2);
return(NO);
}
while ((c = getc(nonglobalrefs)) != EOF) {
(void) putc(c, refsfound);
}
}
(void) fclose(nonglobalrefs);
}
}
signal(SIGINT, savesig);
/* rewind the cross-reference file */
(void) lseek(symrefs, (long) 0, 0);
/* reopen the references found file for reading */
(void) fclose(refsfound);
if ((refsfound = myfopen(temp1, "rb")) == NULL) {
cannotopen(temp1);
return(NO);
}
nextline = 1;
totallines = 0;
disprefs = 0;
/* see if it is empty */
if ((c = getc(refsfound)) == EOF) {
if (findresult != NULL) {
(void) snprintf(lastmsg, sizeof(lastmsg), "Egrep %s in this pattern: %s",
findresult, Pattern);
} else if (rc == NOTSYMBOL) {
(void) snprintf(lastmsg, sizeof(lastmsg), "This is not a C symbol: %s",
Pattern);
} else if (rc == REGCMPERROR) {
(void) snprintf(lastmsg, sizeof(lastmsg), "Error in this regcomp(3) regular expression: %s",
Pattern);
} else if (funcexist == NO) {
(void) snprintf(lastmsg, sizeof(lastmsg), "Function definition does not exist: %s",
Pattern);
} else {
(void) snprintf(lastmsg, sizeof(lastmsg), "Could not find the %s: %s",
fields[field].text2, Pattern);
}
return(NO);
}
/* put back the character read */
(void) ungetc(c, refsfound);
/* HBB 20041027: this used to hold a copy of the code of
* countrefs(), but with the crucial display width adjustments
* missing. Just call the real thing instead! */
countrefs();
return(YES);
}
/* display search progress with default custom format */
void
progress(char *what, long current, long max)
{
static long start;
long now;
char msg[MSGLEN + 1];
int i;
/* save the start time */
if (searchcount == 0) {
start = time(NULL);
}
if ((now = time(NULL)) - start >= 1)
{
if (linemode == NO)
{
wmove(body, MSGLINE, 0);
clrtoeol();
waddstr(body, what);
snprintf(msg, sizeof(msg), "%ld", current);
wmove(body, MSGLINE, (COLS / 2) - (strlen(msg) / 2));
waddstr(body, msg);
snprintf(msg, sizeof(msg), "%ld", max);
wmove(body, MSGLINE, COLS - strlen(msg));
waddstr(body, msg);
refresh();
}
else if (verbosemode == YES)
{
snprintf(msg, sizeof(msg), "> %s %ld of %ld", what, current, max);
}
start = now;
if ((linemode == NO) && (incurses == YES))
{
wmove(body, MSGLINE, 0);
i = (float)COLS * (float)current / (float)max;
standout();
for (; i > 0; i--)
waddch(body, inch());
standend();
refresh();
}
else
if (linemode == NO || verbosemode == YES)
postmsg(msg);
}
++searchcount;
}
/* print error message on system call failure */
void
myperror(char *text)
{
char msg[MSGLEN + 1]; /* message */
char *s;
s = strerror(errno);
(void) snprintf(msg, sizeof(msg), "%s: %s", text, s);
postmsg(msg);
}
/* postmsg clears the message line and prints the message */
/* VARARGS */
void
postmsg(char *msg)
{
if (linemode == YES || incurses == NO) {
(void) printf("%s\n", msg);
fflush(stdout);
}
else {
clearmsg();
waddstr(body, msg);
refresh();
}
(void) strncpy(lastmsg, msg, sizeof(lastmsg) - 1);
}
/* clearmsg clears the first message line */
void
clearmsg(void)
{
if (linemode == NO) {
wmove(body, MSGLINE, 0);
clrtoeol();
}
}
/* clearmsg2 clears the second message line */
void
clearmsg2(void)
{
if (linemode == NO) {
wmove(body, MSGLINE + 1, 0);
clrtoeol();
}
}
/* postmsg2 clears the second message line and prints the message */
void
postmsg2(char *msg)
{
if (linemode == YES) {
(void) printf("%s\n", msg);
}
else {
clearmsg2();
waddstr(body, msg);
refresh();
}
}
/* display an error mesg - stdout or on second msg line */
void
posterr(char *msg, ...)
{
va_list ap;
char errbuf[MSGLEN];
va_start(ap, msg);
if (linemode == YES || incurses == NO)
{
(void) vfprintf(stderr, msg, ap);
(void) fputc('\n', stderr);
} else {
vsnprintf(errbuf, sizeof(errbuf), msg, ap);
postmsg2(errbuf);
}
va_end(ap);
}
/* display a fatal error mesg -- stderr *after* shutting down curses */
void
postfatal(const char *msg, ...)
{
va_list ap;
char errbuf[MSGLEN];
va_start(ap, msg);
vsnprintf(errbuf, sizeof(errbuf), msg, ap);
/* restore the terminal to its original mode */
if (incurses == YES) {
exitcurses();
}
/* display fatal error messages */
fprintf(stderr,"%s",errbuf);
/* shut down */
myexit(1);
}
/* position references found file at specified line */
void
seekline(unsigned int line)
{
int c;
/* verify that there is a references found file */
if (refsfound == NULL) {
return;
}
/* go to the beginning of the file */
rewind(refsfound);
/* find the requested line */
nextline = 1;
while (nextline < line && (c = getc(refsfound)) != EOF) {
if (c == '\n') {
nextline++;
}
}
}
/* get the OGS subsystem and book names */
void
ogsnames(char *file, char **subsystem, char **book)
{
static char buf[PATHLEN + 1];
char *s, *slash;
*subsystem = *book = "";
(void) strcpy(buf,file);
s = buf;
if (*s == '/') {
++s;
}
while ((slash = strchr(s, '/')) != NULL) {
*slash = '\0';
if ((int)strlen(s) >= 3 && strncmp(slash - 3, ".ss", 3) == 0) {
*subsystem = s;
s = slash + 1;
if ((slash = strchr(s, '/')) != NULL) {
*book = s;
*slash = '\0';
}
break;
}
s = slash + 1;
}
}
/* get the requested path components */
char *
pathcomponents(char *path, int components)
{
int i;
char *s;
s = path + strlen(path) - 1;
for (i = 0; i < components; ++i) {
while (s > path && *--s != '/') {
;
}
}
if (s > path && *s == '/') {
++s;
}
return(s);
}
/* open the references found file for writing */
BOOL
writerefsfound(void)
{
if (refsfound == NULL) {
if ((refsfound = myfopen(temp1, "wb")) == NULL) {
cannotopen(temp1);
return(NO);
}
} else {
(void) fclose(refsfound);
if ( (refsfound = myfopen(temp1, "wb")) == NULL) {
postmsg("Cannot reopen temporary file");
return(NO);
}
}
return(YES);
}

137
src/edit.c Normal file
View File

@ -0,0 +1,137 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* file editing functions
*/
#include "global.h"
#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
#include <ncurses.h>
#else
#include <curses.h>
#endif
/* edit this displayed reference */
void
editref(int i)
{
char file[PATHLEN + 1]; /* file name */
char linenum[NUMLEN + 1]; /* line number */
/* verify that there is a references found file */
if (refsfound == NULL) {
return;
}
/* get the selected line */
seekline(i + topline);
/* get the file name and line number */
if (fscanf(refsfound, "%" PATHLEN_STR "s%*s%" NUMLEN_STR "s", file, linenum) == 2) {
edit(file, linenum); /* edit it */
}
seekline(topline); /* restore the line pointer */
}
/* edit all references */
void
editall(void)
{
char file[PATHLEN + 1]; /* file name */
char linenum[NUMLEN + 1]; /* line number */
int c;
/* verify that there is a references found file */
if (refsfound == NULL) {
return;
}
/* get the first line */
seekline(1);
/* get each file name and line number */
while (fscanf(refsfound, "%" PATHLEN_STR "s%*s%" NUMLEN_STR "s%*[^\n]", file, linenum) == 2) {
edit(file, linenum); /* edit it */
if (editallprompt == YES) {
addstr("Type ^D to stop editing all lines, or any other character to continue: ");
if ((c = mygetch()) == EOF || c == ctrl('D') || c == ctrl('Z')) {
break;
}
}
}
seekline(topline);
}
/* call the editor */
void
edit(char *file, char *linenum)
{
char msg[MSGLEN + 1]; /* message */
char plusnum[NUMLEN + 20]; /* line number option: allow space for wordy line# flag */
char *s;
file = filepath(file);
(void) snprintf(msg, sizeof(msg), "%s +%s %s", basename(editor), linenum, file);
postmsg(msg);
(void) snprintf(plusnum, sizeof(plusnum), lineflag, linenum);
/* if this is the more or page commands */
if (strcmp(s = basename(editor), "more") == 0 || strcmp(s, "page") == 0) {
/* get it to pause after displaying a file smaller than the screen
length */
(void) execute(editor, editor, plusnum, file, "/dev/null", NULL);
}
else if (lineflagafterfile) {
(void) execute(editor, editor, file, plusnum, NULL);
}
else {
(void) execute(editor, editor, plusnum, file, NULL);
}
clear(); /* redisplay screen */
}
/* if requested, prepend a path to a relative file name */
char *
filepath(char *file)
{
static char path[PATHLEN + 1];
if (prependpath != NULL && *file != '/') {
(void) snprintf(path, sizeof(path), "%s/%s", prependpath, file);
file = path;
}
return(file);
}

2053
src/egrep.c Normal file

File diff suppressed because it is too large Load Diff

98
src/egrep.h Normal file
View File

@ -0,0 +1,98 @@
/* A Bison parser, made by GNU Bison 3.8.2. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
especially those whose name start with YY_ or yy_. They are
private implementation details that can be changed or removed. */
#ifndef YY_YY_EGREP_H_INCLUDED
# define YY_YY_EGREP_H_INCLUDED
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int yydebug;
#endif
/* Token kinds. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
enum yytokentype
{
YYEMPTY = -2,
YYEOF = 0, /* "end of file" */
YYerror = 256, /* error */
YYUNDEF = 257, /* "invalid token" */
CHAR = 258, /* CHAR */
DOT = 259, /* DOT */
CCL = 260, /* CCL */
NCCL = 261, /* NCCL */
OR = 262, /* OR */
CAT = 263, /* CAT */
STAR = 264, /* STAR */
PLUS = 265, /* PLUS */
QUEST = 266 /* QUEST */
};
typedef enum yytokentype yytoken_kind_t;
#endif
/* Token kinds. */
#define YYEMPTY -2
#define YYEOF 0
#define YYerror 256
#define YYUNDEF 257
#define CHAR 258
#define DOT 259
#define CCL 260
#define NCCL 261
#define OR 262
#define CAT 263
#define STAR 264
#define PLUS 265
#define QUEST 266
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
extern YYSTYPE yylval;
int yyparse (void);
#endif /* !YY_YY_EGREP_H_INCLUDED */

663
src/egrep.y Normal file
View File

@ -0,0 +1,663 @@
%{
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/*
* egrep -- fine lines containing a regular expression
*/
%}
%token CHAR DOT CCL NCCL OR CAT STAR PLUS QUEST
%left OR
%left CHAR DOT CCL NCCL '('
%left CAT
%left STAR PLUS QUEST
%{
#include "global.h"
#include <ctype.h>
#include <stdio.h>
#include <setjmp.h> /* jmp_buf */
#define nextch() (*input++)
#define MAXLIN 350
#define MAXPOS 4000
#define NCHARS 256
#define NSTATES 128
#define FINAL -1
static char gotofn[NSTATES][NCHARS];
static int state[NSTATES];
static char out[NSTATES];
static unsigned int line;
static int name[MAXLIN];
static unsigned int left[MAXLIN];
static unsigned int right[MAXLIN];
static unsigned int parent[MAXLIN];
static int foll[MAXLIN];
static int positions[MAXPOS];
static char chars[MAXLIN];
static int nxtpos;
static int nxtchar;
static int tmpstat[MAXLIN];
static int initstat[MAXLIN];
static int xstate;
static int count;
static int icount;
static char *input;
static long lnum;
static int iflag;
static jmp_buf env; /* setjmp/longjmp buffer */
static char *message; /* error message */
/* Internal prototypes: */
static void cfoll(int v);
static void cgotofn(void);
static int cstate(int v);
static int member(int symb, int set, int torf);
static int notin(int n);
static void synerror(void);
static void overflo(void);
static void add(int *array, int n);
static void follow(unsigned int v);
static int unary(int x, int d);
static int node(int x, int l, int r);
static unsigned int cclenter(int x);
static unsigned int enter(int x);
static int yylex(void);
static int yyerror(char *);
%}
%%
s: t
{ unary(FINAL, $1);
line--;
}
;
t: b r
{ $$ = node(CAT, $1, $2); }
| OR b r OR
{ $$ = node(CAT, $2, $3); }
| OR b r
{ $$ = node(CAT, $2, $3); }
| b r OR
{ $$ = node(CAT, $1, $2); }
;
b:
{ $$ = enter(DOT);
$$ = unary(STAR, $$); }
;
r: CHAR
{ $$ = enter($1); }
| DOT
{ $$ = enter(DOT); }
| CCL
{ $$ = cclenter(CCL); }
| NCCL
{ $$ = cclenter(NCCL); }
;
r: r OR r
{ $$ = node(OR, $1, $3); }
| r r %prec CAT
{ $$ = node(CAT, $1, $2); }
| r STAR
{ $$ = unary(STAR, $1); }
| r PLUS
{ $$ = unary(PLUS, $1); }
| r QUEST
{ $$ = unary(QUEST, $1); }
| '(' r ')'
{ $$ = $2; }
| error
;
%%
static int
yyerror(char *s)
{
message = s;
longjmp(env, 1);
return 1; /* silence a warning */
}
static int
yylex(void)
{
int cclcnt, x;
char c, d;
switch(c = nextch()) {
case '|':
case '\n':
return (OR);
case '*':
return (STAR);
case '+':
return (PLUS);
case '?':
return (QUEST);
case '(':
case ')':
return (c);
case '.':
return (DOT);
case '\0':
return (0);
case '[':
x = CCL;
cclcnt = 0;
count = nxtchar++;
if ((c = nextch()) == '^') {
x = NCCL;
c = nextch();
}
do {
if (c == '\0')
synerror();
if ( (c == '-')
&& (cclcnt > 0)
&& (chars[nxtchar-1] != 0)
) {
if ((d = nextch()) != 0) {
c = chars[nxtchar-1];
while ((unsigned int)c < (unsigned int)d) {
if (nxtchar >= MAXLIN)
overflo();
chars[nxtchar++] = ++c;
cclcnt++;
}
continue;
} /* if() */
} /* if() */
if (nxtchar >= MAXLIN)
overflo();
chars[nxtchar++] = c;
cclcnt++;
} while ((c = nextch()) != ']');
chars[count] = cclcnt;
return (x);
case '\\':
if ((c = nextch()) == '\0')
synerror();
yylval = c;
return (CHAR);
case '$':
case '^':
c = '\n';
yylval = c;
return (CHAR);
default:
yylval = c;
return (CHAR);
}
}
static void
synerror(void)
{
yyerror("Syntax error");
}
static unsigned int
enter(int x)
{
if(line >= MAXLIN)
overflo();
name[line] = x;
left[line] = 0;
right[line] = 0;
return(line++);
}
static unsigned int
cclenter(int x)
{
unsigned int linno;
linno = enter(x);
right[linno] = count;
return (linno);
}
static int
node(int x, int l, int r)
{
if(line >= MAXLIN)
overflo();
name[line] = x;
left[line] = l;
right[line] = r;
parent[l] = line;
parent[r] = line;
return(line++);
}
static int
unary(int x, int d)
{
if(line >= MAXLIN)
overflo();
name[line] = x;
left[line] = d;
right[line] = 0;
parent[d] = line;
return(line++);
}
static void
overflo(void)
{
yyerror("internal table overflow");
}
static void
cfoll(int v)
{
unsigned int i;
if (left[v] == 0) {
count = 0;
for (i = 1; i <= line; i++)
tmpstat[i] = 0;
follow(v);
add(foll, v);
} else if (right[v] == 0)
cfoll(left[v]);
else {
cfoll(left[v]);
cfoll(right[v]);
}
}
static void
cgotofn(void)
{
unsigned int i, n, s;
int c, k;
char symbol[NCHARS];
unsigned int j, l, pc, pos;
unsigned int nc;
int curpos;
unsigned int num, number, newpos;
count = 0;
for (n=3; n<=line; n++)
tmpstat[n] = 0;
if (cstate(line-1)==0) {
tmpstat[line] = 1;
count++;
out[0] = 1;
}
for (n=3; n<=line; n++)
initstat[n] = tmpstat[n];
count--; /*leave out position 1 */
icount = count;
tmpstat[1] = 0;
add(state, 0);
n = 0;
for (s = 0; s <= n; s++) {
if (out[s] == 1)
continue;
for (i = 0; i < NCHARS; i++)
symbol[i] = 0;
num = positions[state[s]];
count = icount;
for (i = 3; i <= line; i++)
tmpstat[i] = initstat[i];
pos = state[s] + 1;
for (i = 0; i < num; i++) {
curpos = positions[pos];
if ((c = name[curpos]) >= 0) {
if (c < NCHARS) {
symbol[c] = 1;
} else if (c == DOT) {
for (k = 0; k < NCHARS; k++)
if (k != '\n')
symbol[k] = 1;
} else if (c == CCL) {
nc = chars[right[curpos]];
pc = right[curpos] + 1;
for (j = 0; j < nc; j++)
symbol[(unsigned char)chars[pc++]] = 1;
} else if (c == NCCL) {
nc = chars[right[curpos]];
for (j = 0; j < NCHARS; j++) {
pc = right[curpos] + 1;
for (l = 0; l < nc; l++)
if (j==(unsigned char)chars[pc++])
goto cont;
if (j != '\n')
symbol[j] = 1;
cont:
;
}
}
}
pos++;
} /* for (i) */
for (c=0; c<NCHARS; c++) {
if (symbol[c] == 1) {
/* nextstate(s,c) */
count = icount;
for (i=3; i <= line; i++)
tmpstat[i] = initstat[i];
pos = state[s] + 1;
for (i=0; i<num; i++) {
curpos = positions[pos];
if ((k = name[curpos]) >= 0)
if ((k == c)
|| (k == DOT)
|| (k == CCL && member(c, right[curpos], 1))
|| (k == NCCL && member(c, right[curpos], 0))
) {
number = positions[foll[curpos]];
newpos = foll[curpos] + 1;
for (j = 0; j < number; j++) {
if (tmpstat[positions[newpos]] != 1) {
tmpstat[positions[newpos]] = 1;
count++;
}
newpos++;
}
}
pos++;
} /* end nextstate */
if (notin(n)) {
if (n >= NSTATES)
overflo();
add(state, ++n);
if (tmpstat[line] == 1)
out[n] = 1;
gotofn[s][c] = n;
} else {
gotofn[s][c] = xstate;
}
} /* if (symbol) */
} /* for(c) */
} /* for(s) */
}
static int
cstate(int v)
{
int b;
if (left[v] == 0) {
if (tmpstat[v] != 1) {
tmpstat[v] = 1;
count++;
}
return(1);
}
else if (right[v] == 0) {
if (cstate(left[v]) == 0) return (0);
else if (name[v] == PLUS) return (1);
else return (0);
}
else if (name[v] == CAT) {
if (cstate(left[v]) == 0 && cstate(right[v]) == 0) return (0);
else return (1);
}
else { /* name[v] == OR */
b = cstate(right[v]);
if (cstate(left[v]) == 0 || b == 0) return (0);
else return (1);
}
}
static int
member(int symb, int set, int torf)
{
unsigned int i, num, pos;
num = chars[set];
pos = set + 1;
for (i = 0; i < num; i++)
if (symb == (unsigned char)(chars[pos++]))
return (torf);
return (!torf);
}
static int
notin(int n)
{
int i, j, pos;
for (i=0; i<=n; i++) {
if (positions[state[i]] == count) {
pos = state[i] + 1;
for (j=0; j < count; j++)
if (tmpstat[positions[pos++]] != 1) goto nxt;
xstate = i;
return (0);
}
nxt: ;
}
return (1);
}
static void
add(int *array, int n)
{
unsigned int i;
if (nxtpos + count > MAXPOS)
overflo();
array[n] = nxtpos;
positions[nxtpos++] = count;
for (i=3; i <= line; i++) {
if (tmpstat[i] == 1) {
positions[nxtpos++] = i;
}
}
}
static void
follow(unsigned int v)
{
unsigned int p;
if (v == line)
return;
p = parent[v];
switch(name[p]) {
case STAR:
case PLUS: cstate(v);
follow(p);
return;
case OR:
case QUEST: follow(p);
return;
case CAT:
if (v == left[p]) {
if (cstate(right[p]) == 0) {
follow(p);
return;
}
} else
follow(p);
return;
case FINAL:
if (tmpstat[line] != 1) {
tmpstat[line] = 1;
count++;
}
return;
}
}
char *
egrepinit(char *egreppat)
{
/* initialize the global data */
memset(gotofn, 0, sizeof(gotofn));
memset(state, 0, sizeof(state));
memset(out, 0, sizeof(out));
line = 1;
memset(name, 0, sizeof(name));
memset(left, 0, sizeof(left));
memset(right, 0, sizeof(right));
memset(parent, 0, sizeof(parent));
memset(foll, 0, sizeof(foll));
memset(positions, 0, sizeof(positions));
memset(chars, 0, sizeof(chars));
nxtpos = 0;
nxtchar = 0;
memset(tmpstat, 0, sizeof(tmpstat));
memset(initstat, 0, sizeof(initstat));
xstate = 0;
count = 0;
icount = 0;
input = egreppat;
message = NULL;
if (setjmp(env) == 0) {
yyparse();
cfoll(line-1);
cgotofn();
}
return(message);
}
static char buf[2 * BUFSIZ];
static const char *buf_end = buf + (sizeof(buf) / sizeof(*buf));
static size_t read_next_chunk(char **p, FILE *fptr)
{
if (*p <= (buf + BUFSIZ)) {
/* bwlow the middle, so enough space left for one entire BUFSIZ */
return fread(*p, sizeof(**p), BUFSIZ, fptr);
} else if (*p == buf_end) {
/* exactly at end ... wrap around and use lower half */
*p = buf;
return fread(*p, sizeof(**p), BUFSIZ, fptr);
}
/* somewhere in second half, so do a limited read */
return fread(*p, sizeof(**p), buf_end - *p, fptr);
}
int
egrep(char *file, FILE *output, char *format)
{
char *p;
unsigned int cstat;
int ccount;
char *nlp;
unsigned int istat;
int in_line;
FILE *fptr;
if ((fptr = myfopen(file, "r")) == NULL)
return(-1);
lnum = 1;
p = buf;
nlp = p;
ccount = read_next_chunk(&p, fptr);
if (ccount <= 0) {
fclose(fptr);
return(0);
}
in_line = 1;
istat = cstat = (unsigned int) gotofn[0]['\n'];
if (out[cstat])
goto found;
for (;;) {
if (!iflag) {
/* all input chars made positive */
cstat = (unsigned int) gotofn[cstat][(unsigned char)*p];
} else {
/* for -i option*/
cstat = (unsigned int) gotofn[cstat][tolower((unsigned char)*p)];
}
if (out[cstat]) {
found:
for(;;) {
if (*p++ == '\n') {
in_line = 0;
succeed:
fprintf(output, format, file, lnum);
if (p <= nlp) {
while (nlp < buf_end)
putc(*nlp++, output);
nlp = buf;
}
while (nlp < p)
putc(*nlp++, output);
lnum++;
nlp = p;
if (out[cstat = istat] == 0)
goto brk2;
} /* if (p++ == \n) */
cfound:
if (--ccount <= 0) {
ccount = read_next_chunk(&p, fptr);
if (ccount <= 0) {
if (in_line) {
in_line = 0;
goto succeed;
}
fclose(fptr);
return(0);
}
} /* if(ccount <= 0) */
in_line = 1;
} /* for(ever) */
} /* if(out[cstat]) */
if (*p++ == '\n') {
in_line = 0;
lnum++;
nlp = p;
if (out[(cstat=istat)])
goto cfound;
}
brk2:
if (--ccount <= 0) {
ccount = read_next_chunk(&p, fptr);
if (ccount <= 0)
break;
}
in_line = 1;
}
fclose(fptr);
return(0);
}
void
egrepcaseless(int i)
{
iflag = i; /* simulate "egrep -i" */
}

188
src/exec.c Normal file
View File

@ -0,0 +1,188 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* process execution functions
*/
#include <unistd.h>
#include "global.h"
#include <stdarg.h>
#include <sys/wait.h>
#include <sys/types.h> /* pid_t */
#ifdef __DJGPP__
#include <process.h>
#endif
#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
#include <ncurses.h>
#else
#include <curses.h>
#endif
static sighandler_t oldsigquit; /* old value of quit signal */
static sighandler_t oldsighup; /* old value of hangup signal */
static sighandler_t oldsigtstp; /* old value of SIGTSTP */
#ifndef __MSDOS__ /* none of these is needed, there */
static int join(pid_t p);
static int myexecvp(char *a, char **args);
static pid_t myfork(void);
#endif
/* execute forks and executes a program or shell script, waits for it to
* finish, and returns its exit code.
*/
/*VARARGS1*/
int
execute(char *a, ...) /* note: "exec" is already defined on u370 */
{
va_list ap;
int exitcode = -1; /* initialize, to avoid warning */
char *argv[BUFSIZ];
pid_t p;
/* fork and exec the program or shell script */
endwin(); /* restore the terminal modes */
mousecleanup();
fflush(stdout);
va_start(ap, a);
for (p = 0; (argv[p] = va_arg(ap, char *)) != 0; p++)
;
#ifdef __MSDOS__
/* HBB 20010313: in MSDOG, everything is completely different.
* No fork()/exec()/wait(), but rather a single libc call: */
exitcode = spawnvp(P_WAIT, a, argv);
#else
if ((p = myfork()) == 0) {
myexecvp(a, argv); /* child */
}
else {
exitcode = join(p); /* parent */
}
#endif /* MSDOS */
/* the menu and scrollbar may be changed by the command executed */
#if UNIXPC || !TERMINFO
# ifndef __DJGPP__ /* leave CRLF handling as is */
nonl();
# endif
raw(); /* endwin() turns off cbreak mode so restore it */
noecho();
#endif
mousemenu();
drawscrollbar(topline, nextline);
va_end(ap);
return(exitcode);
}
#ifndef __MSDOS__ /* None of the following functions is used there */
/* myexecvp is an interface to the execvp system call to
* modify argv[0] to reference the last component of its path-name.
*/
static int
myexecvp(char *a, char **args)
{
char msg[MSGLEN + 1];
/* modify argv[0] to reference the last component of its path name */
args[0] = basename(args[0]);
/* execute the program or shell script */
execvp(a, args); /* returns only on failure */
snprintf(msg, sizeof(msg), "\nCannot exec %s", a);
perror(msg); /* display the reason */
askforreturn(); /* wait until the user sees the message */
myexit(1); /* exit the child */
/* NOTREACHED */
}
/* myfork acts like fork but also handles signals */
static pid_t
myfork(void)
{
pid_t p; /* process number */
p = fork();
/* the parent ignores the interrupt, quit, and hangup signals */
if (p > 0) {
oldsigquit = signal(SIGQUIT, SIG_IGN);
oldsighup = signal(SIGHUP, SIG_IGN);
#ifdef SIGTSTP
oldsigtstp = signal(SIGTSTP, SIG_DFL);
#endif
}
/* so they can be used to stop the child */
else if (p == 0) {
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGHUP, SIG_DFL);
#ifdef SIGTSTP
signal(SIGTSTP, SIG_DFL);
#endif
}
/* check for fork failure */
if (p == -1) {
myperror("Cannot fork");
}
return p;
}
/* join is the compliment of fork */
static int
join(pid_t p)
{
int status = -1;
pid_t w;
/* wait for the correct child to exit */
do {
w = wait(&status);
} while (p != -1 && w != p);
/* restore signal handling */
signal(SIGQUIT, oldsigquit);
signal(SIGHUP, oldsighup);
#ifdef SIGTSTP
signal(SIGTSTP, oldsigtstp);
#endif
/* return the child's exit code */
return(status >> 8);
}
#endif /* !MSDOS */

1301
src/find.c Normal file

File diff suppressed because it is too large Load Diff

904
src/fscanner.l Normal file
View File

@ -0,0 +1,904 @@
%{
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* C symbol scanner
*/
#include "global.h"
#include "scanner.h"
#include "lookup.h"
#include <assert.h>
/* the line counting has been moved from character reading for speed */
/* comments are discarded */
#ifndef FLEX_SCANNER
# error Sorry, this scanner needs flex. It is not usable with AT&T Lex.
#endif
#define IFLEVELINC 5 /* #if nesting level size increment */
#define YY_NO_TOP_STATE 1
int first; /* buffer index for first char of symbol */
int last; /* buffer index for last char of symbol */
int lineno; /* symbol line number */
int myylineno = 1;
/* HBB 20001007: new variables, emulating yytext in a way that allows
* the yymore() simulation, my_yymore(), to be used even in the presence of
* yyless(). */
size_t my_yyleng = 0;
char *my_yytext = NULL;
static BOOL arraydimension; /* inside array dimension declaration */
static BOOL bplisting; /* breakpoint listing */
static int braces; /* unmatched left brace count */
static BOOL classdef; /* c++ class definition */
static BOOL elseelif; /* #else or #elif found */
static BOOL esudef; /* enum/struct/union global definition */
static BOOL external; /* external definition */
static int externalbraces; /* external definition outer brace count */
static BOOL fcndef; /* function definition */
static BOOL global; /* file global scope (outside functions) */
static size_t iflevel; /* #if nesting level */
static BOOL initializer; /* data initializer */
static int initializerbraces; /* data initializer outer brace count */
static BOOL lex; /* lex file */
static size_t miflevel = IFLEVELINC; /* maximum #if nesting level */
static int *maxifbraces; /* maximum brace count within #if */
static int *preifbraces; /* brace count before #if */
static int parens; /* unmatched left parenthesis count */
static BOOL ppdefine; /* preprocessor define statement */
static BOOL pseudoelif; /* pseudo-#elif */
static BOOL oldtype; /* next identifier is an old type */
static BOOL rules; /* lex/yacc rules */
static BOOL sdl; /* sdl file */
static BOOL structfield; /* structure field declaration */
static int tagdef; /* class/enum/struct/union tag definition */
static BOOL template; /* function template */
static int templateparens; /* function template outer parentheses count */
static int typedefbraces = -1; /* initial typedef brace count */
static int token; /* token found */
static int ident_start; /* begin of preceding identifier */
static void my_yymore(void);
%}
identifier [a-zA-Z_$][a-zA-Z_0-9$]*
number \.?[0-9][.0-9a-fA-FlLuUxX]*
comment "/*"([^*]*("*"+[^/])?)*"*/"|"//"[^\n]*\n
ws [ \t\r\v\f]
wsnl [ \t\r\v\f\n]|{comment}
/* flex options: stack of start conditions, and don't use yywrap() */
%option stack
%option noyywrap
%start SDL
%a 4000
%o 7000
/* exclusive start conditions. not available in AT&T lex -> use flex! */
%x IN_PREPROC WAS_ENDIF WAS_IDENTIFIER WAS_ESU IN_DQUOTE IN_SQUOTE COMMENT
%%
%\{ { /* lex/yacc C declarations/definitions */
global = YES;
goto more;
/* NOTREACHED */
}
%\} {
global = NO;
goto more;
/* NOTREACHED */
}
^%% { /* lex/yacc rules delimiter */
braces = 0;
if (rules == NO) {
/* this %% starts the section containing the rules */
rules = YES;
/* Copy yytext to private buffer, to be able to add further
* content following it: */
my_yymore();
/* simulate a yylex() or yyparse() definition */
(void) strcat(my_yytext, " /* ");
first = strlen(my_yytext);
if (lex == YES) {
(void) strcat(my_yytext, "yylex");
} else {
/* yacc: yyparse implicitly calls yylex */
char *s = " yylex()";
char *cp = s + strlen(s);
while (--cp >= s) {
unput(*cp);
}
(void) strcat(my_yytext, "yyparse");
}
last = strlen(my_yytext);
(void) strcat(my_yytext, " */");
my_yyleng = strlen(my_yytext);
return(FCNDEF);
} else {
/* were in the rules section, now comes the closing one */
rules = NO;
global = YES;
last = first;
my_yymore();
return(FCNEND);
/* NOTREACHED */
}
}
<SDL>STATE[ \t]+({identifier}|\*) { /* sdl state, treat as function def */
braces = 1;
fcndef = YES;
token = FCNDEF;
goto findident;
/* NOTREACHED */
}
<SDL>ENDSTATE[ \t] { /* end of an sdl state, treat as end of a function */
goto endstate;
/* NOTREACHED */
}
\{ { /* count unmatched left braces for fcn def detection */
++braces;
/* mark an untagged enum/struct/union so its beginning
can be found */
if (tagdef) {
if (braces == 1) {
esudef = YES;
}
token = tagdef;
tagdef = '\0';
last = first;
my_yymore();
return(token);
}
goto more;
/* NOTREACHED */
}
\#{ws}* { /* start a preprocessor line */
if (rules == NO) /* don't consider CPP for lex/yacc rules */
BEGIN(IN_PREPROC);
yyleng = 1; /* get rid of the blanks, if any */
goto more;
/* NOTREACHED */
}
<IN_PREPROC>endif([^a-zA-Z0-9_$\n].*)? { /* #endif */
/* delay treatment of #endif depending on whether an
* #if comes right after it, or not */
/* HBB 20010619: new pattern allows trailing garbage
* after the #endif */
BEGIN(WAS_ENDIF);
goto more;
/* NOTREACHED */
}
<WAS_ENDIF>\n{wsnl}*#{ws}*if(ndef|def)?{ws}+ {
/* attempt to correct erroneous brace count caused by:
*
* #if ...
* ... {
* #endif
* #if ...
* ... {
* #endif
*/
/* the current #if must not have an #else or #elif */
if (elseelif == YES) {
goto endif;
/* NOTREACHED */
}
pseudoelif = YES;
BEGIN(INITIAL);
yyless(1); /* rescan all but the line ending */
yy_set_bol(1);
goto eol;
/* NOTREACHED */
}
<WAS_ENDIF>\n{wsnl}* { /* an #endif with no #if right after it */
endif:
if (iflevel > 0) {
/* get the maximum brace count for this #if */
if (braces < maxifbraces[--iflevel]) {
braces = maxifbraces[iflevel];
}
}
BEGIN(INITIAL);
yyless(1);
yy_set_bol(1);
goto eol;
/* NOTREACHED */
}
<IN_PREPROC>ifndef{ws}+ |
<IN_PREPROC>ifdef{ws}+ |
<IN_PREPROC>if{ws}+ { /* #if directive */
elseelif = NO;
if (pseudoelif == YES) {
pseudoelif = NO;
goto elif;
/* NOTREACHED */
}
/* make sure there is room for the current brace count */
if (iflevel == miflevel) {
miflevel += IFLEVELINC;
maxifbraces = realloc(maxifbraces, miflevel * sizeof(*maxifbraces));
preifbraces = realloc(preifbraces, miflevel * sizeof(*preifbraces));
}
/* push the current brace count */
preifbraces[iflevel] = braces;
maxifbraces[iflevel++] = 0;
BEGIN(INITIAL);
goto more;
/* NOTREACHED */
}
<IN_PREPROC>else({ws}.*)? { /* #else --- eat up whole line */
elseelif = YES;
if (iflevel > 0) {
/* save the maximum brace count for this #if */
if (braces > maxifbraces[iflevel - 1]) {
maxifbraces[iflevel - 1] = braces;
}
/* restore the brace count to before the #if */
braces = preifbraces[iflevel - 1];
}
BEGIN(INITIAL);
goto more;
/* NOTREACHED */
}
<IN_PREPROC>elif{ws}+ { /* #elif */
/* elseelif = YES; --- HBB I doubt this is correct */
elif:
if (iflevel > 0) {
/* save the maximum brace count for this #if */
if (braces > maxifbraces[iflevel - 1]) {
maxifbraces[iflevel - 1] = braces;
}
/* restore the brace count to before the #if */
braces = preifbraces[iflevel - 1];
}
BEGIN(INITIAL);
goto more;
/* NOTREACHED */
}
<IN_PREPROC>include{ws}*\"[^"\n]+\" |
<IN_PREPROC>include{ws}*<[^>\n]+> { /* #include file */
char *s;
char remember = yytext[yyleng-1];
my_yymore();
s = strpbrk(my_yytext, "\"<");
if (!s)
return(LEXERR);
my_yytext[my_yyleng-1] = '\0';
incfile(s + 1, s);
my_yytext[my_yyleng-1] = remember;
first = s - my_yytext;
last = my_yyleng - 1;
if (compress == YES) {
my_yytext[0] = '\2'; /* compress the keyword */
}
BEGIN(INITIAL);
return(INCLUDE);
/* NOTREACHED */
}
\} {
/* could be the last enum member initializer */
if (braces == initializerbraces) {
initializerbraces = -1;
initializer = NO;
}
if (--braces <= 0) {
endstate:
braces = 0;
classdef = NO;
}
if (braces == 0 || (braces == 1 && classdef == YES)) {
/* if the end of an enum/struct/union definition */
if (esudef == YES) {
esudef = NO;
}
/* if the end of the function */
else if (fcndef == YES) {
fcndef = NO;
last = first;
my_yymore();
return(FCNEND);
}
}
goto more;
/* NOTREACHED */
}
\( { /* count unmatched left parentheses for function templates */
++parens;
goto more;
/* NOTREACHED */
}
\) {
if (--parens <= 0) {
parens = 0;
}
/* if the end of a function template */
if (parens == templateparens) {
templateparens = -1;
template = NO;
}
goto more;
/* NOTREACHED */
}
= { /* if a global definition initializer */
if (!my_yytext)
return(LEXERR);
if (global == YES && ppdefine == NO && my_yytext[0] != '#') {
initializerbraces = braces;
initializer = YES;
}
goto more;
/* NOTREACHED */
}
: { /* a if global structure field */
if (!my_yytext)
return(LEXERR);
if (global == YES && ppdefine == NO && my_yytext[0] != '#') {
structfield = YES;
}
goto more;
/* NOTREACHED */
}
\, {
if (braces == initializerbraces) {
initializerbraces = -1;
initializer = NO;
}
structfield = NO;
goto more;
/* NOTREACHED */
}
; { /* if the enum/struct/union was not a definition */
if (braces == 0) {
esudef = NO;
}
/* if the end of a typedef */
if (braces == typedefbraces) {
typedefbraces = -1;
}
/* if the end of a external definition */
if (braces == externalbraces) {
externalbraces = -1;
external = NO;
}
structfield = NO;
initializer = NO;
goto more;
/* NOTREACHED */
}
<IN_PREPROC>define{ws}+{identifier} {
/* preprocessor macro or constant definition */
ppdefine = YES;
token = DEFINE;
if (compress == YES) {
my_yytext[0] = '\1'; /* compress the keyword */
}
findident:
/* search backwards through yytext[] to find the identifier */
/* NOTE: this had better be left to flex, by use of
* yet another starting condition */
my_yymore();
first = my_yyleng - 1;
while (my_yytext[first] != ' ' && my_yytext[first] != '\t') {
--first;
}
++first;
last = my_yyleng;
BEGIN(INITIAL);
goto definition;
/* NOTREACHED */
}
<IN_PREPROC>\n { /* unknown preprocessor line */
BEGIN(INITIAL);
++myylineno;
goto more;
/* NOTREACHED */
}
<IN_PREPROC>. |
<IN_PREPROC>{identifier} { /* unknown preprocessor line */
BEGIN(INITIAL);
goto more;
/* NOTREACHED */
}
class{wsnl}+{identifier}({wsnl}|{identifier}|[():])*\{ { /* class definition */
classdef = YES;
tagdef = 'c';
yyless(5); /* eat up 'class', and re-scan */
yy_set_bol(0);
goto more;
/* NOTREACHED */
}
("enum"|"struct"|"union") {
ident_start = first;
BEGIN(WAS_ESU);
goto more;
}
<WAS_ESU>{
({wsnl}+{identifier}){wsnl}*\{ { /* e/s/u definition */
tagdef = my_yytext[ident_start];
BEGIN(WAS_IDENTIFIER);
goto ident;
}
{wsnl}*\{ { /* e/s/u definition without a tag */
tagdef = my_yytext[ident_start];
BEGIN(INITIAL);
if (braces == 0) {
esudef = YES;
}
last = first;
yyless(0); /* re-scan all this as normal text */
tagdef = '\0';
goto more;
}
({wsnl}+{identifier})?{wsnl}* |
.|\n { /* e/s/u usage */
BEGIN(WAS_IDENTIFIER);
goto ident;
}
}
if{wsnl}*\( { /* ignore 'if' */
yyless(2);
yy_set_bol(0);
goto more;
}
{identifier} { /* identifier found: do nothing, yet. (!) */
BEGIN(WAS_IDENTIFIER);
ident_start = first;
goto more;
/* NOTREACHED */
}
<WAS_IDENTIFIER>{
{ws}*\(({wsnl}|{identifier}|{number}|[*&[\]=,.:])*\)([()]|{wsnl})*[:a-zA-Z_#{] {
/* a function definition */
/* note: "#define a (b) {" and "#if defined(a)\n#"
* are not fcn definitions! */
/* warning: "if (...)" must not overflow yytext,
* so the content of function argument definitions
* is restricted, in particular parentheses are
* not allowed */
/* FIXME HBB 20001003: the above 'not allowed' may well be the
* reason for the parsing bug concerning function pointer usage,
* I suspect. --- I think my new special-case rule for 'if'
* could be helpful in removing that limitation */
if ((braces == 0 && ppdefine == NO && my_yytext[0] != '#' && rules == NO) ||
(braces == 1 && classdef == YES)) {
fcndef = YES;
token = FCNDEF;
goto fcn;
/* NOTREACHED */
}
goto fcncal;
/* NOTREACHED */
}
{ws}*\(([*&[\]=,.]|{identifier}|{number}|{wsnl})* { /* function call */
fcncal: if (fcndef == YES || ppdefine == YES || rules == YES) {
token = FCNCALL;
goto fcn;
/* NOTREACHED */
}
if (template == NO) {
templateparens = parens;
template = YES;
}
goto ident;
/* NOTREACHED */
}
("*"|{wsnl})+{identifier} { /* typedef name or modifier use */
goto ident;
/* NOTREACHED */
}
.|\n { /* general identifer usage */
char *s;
if (global == YES && ppdefine == NO && my_yytext[0] != '#' &&
external == NO && initializer == NO &&
arraydimension == NO && structfield == NO &&
template == NO && fcndef == NO) {
if (esudef == YES) {
/* if enum/struct/union */
token = MEMBERDEF;
} else {
token = GLOBALDEF;
}
} else {
ident:
token = IDENT;
}
fcn:
if (YYSTATE == WAS_IDENTIFIER) {
/* Position back to the actual identifier: */
last = first;
first = ident_start;
yyless(0);
/* HBB 20001008: if the anti-backup-pattern above matched,
* and the matched context ended with a \n, then the scanner
* believes it's at the start of a new line. But the yyless()
* should feeds that \n back into the input, so that's
* wrong. --> force 'beginning-of-line' status off. */
yy_set_bol(0);
BEGIN(INITIAL);
} else {
my_yymore();
last = my_yyleng;
}
definition:
/* if a long line */
if (yyleng > STMTMAX) {
int c;
/* skip to the end of the line */
warning("line too long");
while ((c = input()) > LEXEOF) {
if (c == '\n') {
unput(c);
break;
}
}
}
/* truncate a long symbol */
if (yyleng > PATLEN) {
warning("symbol too long");
my_yyleng = first + PATLEN;
my_yytext[my_yyleng] = '\0';
}
/* if found word was a keyword: */
if ((s = lookup(my_yytext + first)) != NULL) {
first = my_yyleng;
/* if the start of a typedef */
if (s == typedeftext) {
typedefbraces = braces;
oldtype = YES;
}
/* if an enum/struct/union */
/* (needed for "typedef struct tag name;" so
tag isn't marked as the typedef name) */
else if (s == enumtext || s == structtext || s == uniontext) {
/* do nothing */
} else if (s == externtext) {
/* if an external definition */
externalbraces = braces;
external = YES;
} else if (templateparens == parens && template == YES) {
/* keyword doesn't start a function
* template */
templateparens = -1;
template = NO;
} else {
/* identifier after typedef was a
* keyword */
oldtype = NO;
}
} else {
/* not a keyword --> found an identifier */
/* last = yyleng; */
/* if a class/enum/struct/union tag definition */
/* FIXME HBB 20001001: why reject "class"? */
if (tagdef && strnotequal(my_yytext + first, "class")) {
token = tagdef;
tagdef = '\0';
if (braces == 0) {
esudef = YES;
}
} else if (braces == typedefbraces && oldtype == NO &&
arraydimension == NO) {
/* if a typedef name */
token = TYPEDEF;
} else {
oldtype = NO;
}
/* my_yymore(); */
return(token);
/* NOTREACHED */
}
}
}
\[ { /* array dimension (don't worry or about subscripts) */
arraydimension = YES;
goto more;
/* NOTREACHED */
}
\] {
arraydimension = NO;
goto more;
/* NOTREACHED */
}
\\\n { /* preprocessor statement is continued on next line */
/* save the '\\' to the output file, but not the '\n': */
yyleng = 1;
my_yymore();
goto eol;
/* NOTREACHED */
}
\n { /* end of the line */
if (ppdefine == YES) { /* end of a #define */
ppdefine = NO;
yyless(yyleng - 1);
last = first;
my_yymore();
return(DEFINEEND);
}
/* skip the first 8 columns of a breakpoint listing line */
/* and skip the file path in the page header */
if (bplisting == YES) {
int c, i;
/* FIXME HBB 20001007: should call input() instead */
switch (input()) { /* tab and EOF just fall through */
case ' ': /* breakpoint number line */
case '[':
for (i = 1; i < 8 && input() > LEXEOF; ++i)
;
break;
case '.': /* header line */
case '/':
/* skip to the end of the line */
while ((c = input()) > LEXEOF) {
if (c == '\n') {
unput(c);
break;
}
}
break;
case '\n': /* empty line */
unput('\n');
break;
}
}
eol:
++myylineno;
first = 0;
last = 0;
if (symbols > 0) {
/* no my_yymore(): \n doesn't need to be in my_yytext */
return(NEWLINE);
}
/* line ended --> flush my_yytext */
if (my_yytext)
*my_yytext = '\0';
my_yyleng = 0;
lineno = myylineno;
}
\' { /* character constant */
if (sdl == NO)
BEGIN(IN_SQUOTE);
goto more;
/* NOTREACHED */
}
<IN_SQUOTE>\' {
BEGIN(INITIAL);
goto more;
/* NOTREACHED */
}
\" { /* string constant */
BEGIN(IN_DQUOTE);
goto more;
/* NOTREACHED */
}
<IN_DQUOTE>\" {
BEGIN(INITIAL);
goto more;
/* NOTREACHED */
}
<IN_DQUOTE,IN_SQUOTE>{
\n { /* syntax error: unexpected EOL */
BEGIN(INITIAL);
goto eol;
/* NOTREACHED */
}
\\. |
. {
goto more;
/* NOTREACHED */
}
\\\n { /* line continuation inside a string! */
myylineno++;
goto more;
/* NOTREACHED */
}
}
^{ws}+ { /* don't save leading white space */
}
{ws}+\n { /* eat whitespace at end of line */
unput('\n');
}
[\t\r\v\f]+ { /* eat non-blank whitespace sequences, replace
* by single blank */
unput(' ');
}
{ws}{2,} { /* compress sequential whitespace here, not in putcrossref() */
unput(' ');
}
"/*" yy_push_state(COMMENT);
<COMMENT>{
[^*\n]* |
"*"+[^*/\n]* ; /* do nothing */
[^*\n]*\n |
"*"+[^*/\n]*\n {
if (ppdefine == NO) {
goto eol;
} else {
++myylineno;
}
/* NOTREACHED */
}
"*"+"/" {
/* replace the comment by a single blank */
unput(' ');
yy_pop_state();
}
}
"//".*\n? {
/* C++-style one-line comment */
goto eol;
/* NOTREACHED */
}
{number} | /* number */
<SDL>STATE[ \t]+ | /* ... and other syntax error catchers... */
. { /* punctuation and operators */
more:
my_yymore();
first = my_yyleng;
}
%%
void
initscanner(char *srcfile)
{
char *s;
if (maxifbraces == NULL) {
maxifbraces = malloc(miflevel * sizeof(*maxifbraces));
preifbraces = malloc(miflevel * sizeof(*preifbraces));
}
first = 0; /* buffer index for first char of symbol */
last = 0; /* buffer index for last char of symbol */
lineno = 1; /* symbol line number */
myylineno = 1; /* input line number */
arraydimension = NO; /* inside array dimension declaration */
bplisting = NO; /* breakpoint listing */
braces = 0; /* unmatched left brace count */
classdef = NO; /* c++ class definition */
elseelif = NO; /* #else or #elif found */
esudef = NO; /* enum/struct/union global definition */
external = NO; /* external definition */
externalbraces = -1; /* external definition outer brace count */
fcndef = NO; /* function definition */
global = YES; /* file global scope (outside functions) */
iflevel = 0; /* #if nesting level */
initializer = NO; /* data initializer */
initializerbraces = -1; /* data initializer outer brace count */
lex = NO; /* lex file */
parens = 0; /* unmatched left parenthesis count */
ppdefine = NO; /* preprocessor define statement */
pseudoelif = NO; /* pseudo-#elif */
oldtype = NO; /* next identifier is an old type */
rules = NO; /* lex/yacc rules */
sdl = NO; /* sdl file */
structfield = NO; /* structure field declaration */
tagdef = '\0'; /* class/enum/struct/union tag definition */
template = NO; /* function template */
templateparens = -1; /* function template outer parentheses count */
typedefbraces = -1; /* initial typedef braces count */
ident_start = 0; /* start of previously found identifier */
if (my_yytext)
*my_yytext = '\0';
my_yyleng = 0;
BEGIN(INITIAL);
/* if this is not a C file */
if ((s = strrchr(srcfile, '.')) != NULL) {
switch (*++s) { /* this switch saves time on C files */
case 'b':
if (strcmp(s, "bp") == 0) { /* breakpoint listing */
bplisting = YES;
}
break;
case 'l':
if (strcmp(s, "l") == 0) { /* lex */
lex = YES;
global = NO;
}
break;
case 's':
if (strcmp(s, "sd") == 0) { /* sdl */
sdl = YES;
BEGIN(SDL);
}
break;
case 'y':
if (strcmp(s, "y") == 0) { /* yacc */
global = NO;
}
break;
}
}
}
#define MY_YY_ALLOCSTEP 1000
static void
my_yymore(void)
{
static size_t yytext_size = 0;
/* my_yytext is an ever-growing buffer. It will not ever
* shrink, nor will it be freed at end of program, for now */
while (my_yyleng + yyleng + 1 >= yytext_size) {
my_yytext = realloc(my_yytext, yytext_size += MY_YY_ALLOCSTEP);
}
strncpy (my_yytext + my_yyleng, yytext, yyleng+1);
my_yyleng += yyleng;
}

321
src/global.h Normal file
View File

@ -0,0 +1,321 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* global type, data, and function definitions
*/
#ifndef CSCOPE_GLOBAL_H
#define CSCOPE_GLOBAL_H
//#include "config.h"
#include <unistd.h>
#include <sys/types.h>
#include <ctype.h> /* isalpha, isdigit, etc. */
#include <signal.h> /* SIGINT and SIGQUIT */
#include <stdio.h> /* standard I/O package */
#include <stdlib.h> /* standard library functions */
#include <string.h> /* string functions */
#include "constants.h" /* misc. constants */
#include "invlib.h" /* inverted index library */
#include "library.h" /* library function return values */
typedef void (*sighandler_t)(int);
#include <stdarg.h>
#include <fcntl.h>
typedef enum { /* boolean data type */
NO,
YES
} BOOL;
typedef enum { /* findinit return code */
NOERROR,
NOTSYMBOL,
REGCMPERROR
} FINDINIT;
typedef struct { /* mouse action */
int button;
int percent;
int x1;
int y1;
int x2;
int y2;
} MOUSE;
struct cmd { /* command history struct */
struct cmd *prev, *next; /* list ptrs */
int field; /* input field number */
char *text; /* input field text */
};
#ifndef R_OK
# define READ R_OK
#else
# define READ 4
#endif
#ifdef W_OK
# define WRITE W_OK
#else
# define WRITE 2
#endif
#define O_TEXT 0x00
#define O_BINARY 0x00
#ifndef DFLT_INCDIR
# define DFLT_INCDIR "/usr/include"
#endif
/* digraph data for text compression */
extern char dichar1[]; /* 16 most frequent first chars */
extern char dichar2[]; /* 8 most frequent second chars
using the above as first chars */
extern char dicode1[]; /* digraph first character code */
extern char dicode2[]; /* digraph second character code */
/* and some macros to help using dicodes: */
/* Check if a given pair of chars is compressable as a dicode: */
#define IS_A_DICODE(inchar1, inchar2) \
(dicode1[(unsigned char)(inchar1)] && dicode2[(unsigned char)(inchar2)])
/* Combine the pair into a dicode */
#define DICODE_COMPRESS(inchar1, inchar2) \
((0200 - 2) + dicode1[(unsigned char)(inchar1)] \
+ dicode2[(unsigned char)(inchar2)])
/* main.c global data */
extern char *editor, *home, *shell, *lineflag; /* environment variables */
extern char *home; /* Home directory */
extern BOOL lineflagafterfile;
extern char *argv0; /* command name */
extern BOOL compress; /* compress the characters in the crossref */
extern BOOL dbtruncated; /* database symbols truncated to 8 chars */
extern int dispcomponents; /* file path components to display */
#if CCS
extern BOOL displayversion; /* display the C Compilation System version */
#endif
extern BOOL editallprompt; /* prompt between editing files */
extern unsigned int fileargc; /* file argument count */
extern char **fileargv; /* file argument values */
extern int fileversion; /* cross-reference file version */
extern BOOL incurses; /* in curses */
extern BOOL invertedindex; /* the database has an inverted index */
extern BOOL isuptodate; /* consider the crossref up-to-date */
extern BOOL kernelmode; /* don't use DFLT_INCDIR - bad for kernels */
extern BOOL linemode; /* use line oriented user interface */
extern BOOL verbosemode; /* print extra information on line mode */
extern BOOL recurse_dir; /* recurse dirs when searching for src files */
extern char *namefile; /* file of file names */
extern BOOL ogs; /* display OGS book and subsystem names */
extern char *prependpath; /* prepend path to file names */
extern FILE *refsfound; /* references found file */
extern char temp1[]; /* temporary file name */
extern char temp2[]; /* temporary file name */
extern long totalterms; /* total inverted index terms */
extern BOOL trun_syms; /* truncate symbols to 8 characters */
extern char tempstring[TEMPSTRING_LEN + 1]; /* global dummy string buffer */
extern char *tmpdir; /* temporary directory */
/* command.c global data */
extern BOOL caseless; /* ignore letter case when searching */
extern BOOL *change; /* change this line */
extern BOOL changing; /* changing text */
extern int selecting;
extern unsigned int curdispline;
extern char newpat[]; /* new pattern */
extern char Pattern[]; /* symbol or text pattern */
/* crossref.c global data */
extern long dboffset; /* new database offset */
extern BOOL errorsfound; /* prompt before clearing error messages */
extern long lineoffset; /* source line database offset */
extern long npostings; /* number of postings */
extern unsigned long symbols; /* number of symbols */
/* dir.c global data */
extern char currentdir[]; /* current directory */
extern char **incdirs; /* #include directories */
extern char **srcdirs; /* source directories */
extern char **srcfiles; /* source files */
extern unsigned long nincdirs; /* number of #include directories */
extern unsigned long nsrcdirs; /* number of source directories */
extern unsigned long nsrcfiles; /* number of source files */
extern unsigned long msrcfiles; /* maximum number of source files */
/* display.c global data */
extern int booklen; /* OGS book name display field length */
extern int *displine; /* screen line of displayed reference */
extern unsigned int disprefs; /* displayed references */
extern int fcnlen; /* function name display field length */
extern int field; /* input field */
extern int filelen; /* file name display field length */
extern unsigned fldcolumn; /* input field column */
extern unsigned int mdisprefs; /* maximum displayed references */
extern unsigned int nextline; /* next line to be shown */
extern FILE *nonglobalrefs; /* non-global references file */
extern int numlen; /* line number display field length */
extern unsigned int topline; /* top line of page */
extern int bottomline; /* bottom line of page */
extern long searchcount; /* count of files searched */
extern int subsystemlen; /* OGS subsystem name display field length */
extern unsigned int totallines; /* total reference lines */
extern const char dispchars[]; /* display chars for jumping to lines */
/* find.c global data */
extern char block[]; /* cross-reference file block */
extern char blockmark; /* mark character to be searched for */
extern long blocknumber; /* block number */
extern char *blockp; /* pointer to current character in block */
extern int blocklen; /* length of disk block read */
/* lookup.c global data */
extern struct keystruct {
char *text;
char delim;
struct keystruct *next;
} keyword[];
/* mouse.c global data */
extern BOOL mouse; /* mouse interface */
#if UNIXPC
extern BOOL unixpcmouse; /* UNIX PC mouse interface */
#endif
/* cscope functions called from more than one function or between files */
char *filepath(char *file);
char *findcalledby(char *pattern);
char *findcalling(char *pattern);
char *findallfcns(char *dummy);
char *finddef(char *pattern);
char *findfile(char *dummy);
char *findinclude(char *pattern);
char *findsymbol(char *pattern);
char *findassign(char *pattern);
char *findregexp(char *egreppat);
char *findstring(char *pattern);
char *inviewpath(char *file);
char *lookup(char *ident);
char *pathcomponents(char *path, int components);
char *read_block(void);
char *scanpast(char c);
char ** parse_options(int *argc, char **argv);
void error_usage(void);
void longusage(void);
void usage(void);
extern BOOL remove_symfile_onexit;
extern BOOL onesearch; /* one search only in line mode */
extern char *reflines; /* symbol reference lines file */
void addcmd(int f, char *s);
void addsrcfile(char *path);
void askforchar(void);
void askforreturn(void);
void atchange(void);
void atfield(void);
void cannotwrite(char *file);
void cannotopen(char *file);
void clearmsg(void);
void clearmsg2(void);
void countrefs(void);
void crossref(char *srcfile);
void dispinit(void);
void display(void);
void drawscrollbar(int top, int bot);
void edit(char *file, char *linenum);
void editall(void);
void editref(int);
void entercurses(void);
void exitcurses(void);
void findcleanup(void);
void freesrclist(void);
void freeinclist(void);
void freecrossref(void);
void freefilelist(void);
void help(void);
void incfile(char *file, char *type);
void includedir(char *_dirname);
void initsymtab(void);
void makefilelist(void);
void mousecleanup(void);
void mousemenu(void);
void mouseinit(void);
void mousereinit(void);
void myexit(int sig);
void myperror(char *text);
void ogsnames(char *file, char **subsystem, char **book);
void progress(char *what, long current, long max);
void putfilename(char *srcfile);
void postmsg(char *msg);
void postmsg2(char *msg);
void posterr(char *msg,...);
void postfatal(const char *msg,...);
void putposting(char *term, int type);
void fetch_string_from_dbase(char *, size_t);
void resetcmd(void);
void seekline(unsigned int line);
void setfield(void);
void shellpath(char *out, int limit, char *in);
void sourcedir(char *dirlist);
void myungetch(int c);
void warning(char *text);
void writestring(char *s);
BOOL command(int commandc);
BOOL infilelist(char *file);
BOOL readrefs(char *filename);
BOOL search(void);
BOOL writerefsfound(void);
FINDINIT findinit(char *pattern);
MOUSE *getmouseaction(char leading_char);
struct cmd *currentcmd(void);
struct cmd *prevcmd(void);
struct cmd *nextcmd(void);
int egrep(char *file, FILE *output, char *format);
int mygetline(char p[], char s[], unsigned size, int firstchar, BOOL iscaseless);
int mygetch(void);
int hash(char *ss);
int execute(char *a, ...);
long dbseek(long offset);
#endif /* CSCOPE_GLOBAL_H */

1
src/gscope.c Normal file
View File

@ -0,0 +1 @@
/* Placeholder file --- replace by real gscope.c if you have it */

209
src/help.c Normal file
View File

@ -0,0 +1,209 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* display help
*
*/
#include "global.h"
#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
#include <ncurses.h>
#else
#include <curses.h>
#endif
/*
max num of lines of help screen -
this number needs to be increased if more than n help items are needed
*/
#define MAXHELP 50 /* maximum number of help strings */
void
help(void)
{
char **ep, *s, **tp, *text[MAXHELP];
int ln;
tp = text;
if (changing == NO) {
if (mouse) {
*tp++ = "Point with the mouse and click button 1 to move to the desired input field,\n";
*tp++ = "type the pattern to search for, and then press the RETURN key. For the first 4\n";
*tp++ = "and last 2 input fields, the pattern can be a regcomp(3) regular expression.\n";
*tp++ = "If the search is successful, you can edit the file containing a displayed line\n";
*tp++ = "by pointing with the mouse and clicking button 1.\n";
*tp++ = "\nYou can either use the button 2 menu or these single-character commands:\n\n";
} else {
*tp++ = "Press the RETURN key repeatedly to move to the desired input field, type the\n";
*tp++ = "pattern to search for, and then press the RETURN key. For the first 4 and\n";
*tp++ = "last 2 input fields, the pattern can be a regcomp(3) regular expression.\n";
*tp++ = "If the search is successful, you can use these single-character commands:\n\n";
*tp++ = "0-9a-zA-Z\tEdit the file containing the displayed line.\n";
}
*tp++ = "space bar\tDisplay next set of matching lines.\n";
*tp++ = "+\t\tDisplay next set of matching lines.\n";
*tp++ = "^V\t\tDisplay next set of matching lines.\n";
*tp++ = "-\t\tDisplay previous set of matching lines.\n";
*tp++ = "^E\t\tEdit all lines.\n";
*tp++ = ">\t\tWrite the list of lines being displayed to a file.\n";
*tp++ = ">>\t\tAppend the list of lines being displayed to a file.\n";
*tp++ = "<\t\tRead lines from a file.\n";
*tp++ = "^\t\tFilter all lines through a shell command.\n";
*tp++ = "|\t\tPipe all lines to a shell command.\n";
if (!mouse) {
*tp++ = "\nAt any time you can use these single-character commands:\n\n";
*tp++ = "TAB\t\tSwap positions between input and output areas.\n";
*tp++ = "RETURN\t\tMove to the next input field.\n";
*tp++ = "^N\t\tMove to the next input field.\n";
*tp++ = "^P\t\tMove to the previous input field.\n";
}
*tp++ = "^Y / ^A\t\tSearch with the last pattern typed.\n";
*tp++ = "^B\t\tRecall previous input field and search pattern.\n";
*tp++ = "^F\t\tRecall next input field and search pattern.\n";
if(caseless)
*tp++ = "^C\t\tToggle ignore/use letter case when searching (IGNORE).\n";
else
*tp++ = "^C\t\tToggle ignore/use letter case when searching (USE).\n";
*tp++ = "^R\t\tRebuild the cross-reference.\n";
*tp++ = "!\t\tStart an interactive shell (type ^D to return to cscope).\n";
*tp++ = "^L\t\tRedraw the screen.\n";
*tp++ = "?\t\tDisplay this list of commands.\n";
*tp++ = "^D\t\tExit cscope.\n";
*tp++ = "\nNote: If the first character of the pattern you want to search for matches\n";
*tp++ = "a command, type a \\ character first.\n";
*tp++ = "Note: Some ctrl keys may be occupied by your terminal configuration.\n";
} else {
if (mouse) {
*tp++ = "Point with the mouse and click button 1 to mark or unmark the line to be\n";
*tp++ = "changed. You can also use the button 2 menu or these single-character\n";
*tp++ = "commands:\n\n";
}
else {
*tp++ = "When changing text, you can use these single-character commands:\n\n";
*tp++ = "0-9a-zA-Z\tMark or unmark the line to be changed.\n";
}
*tp++ = "*\t\tMark or unmark all displayed lines to be changed.\n";
*tp++ = "space bar\tDisplay next set of lines.\n";
*tp++ = "+\t\tDisplay next set of lines.\n";
*tp++ = "-\t\tDisplay previous set of lines.\n";
*tp++ = "^A\t\tMark or unmark all lines to be changed.\n";
*tp++ = "^D\t\tChange the marked lines and exit.\n";
*tp++ = "ESC\t\tExit without changing the marked lines.\n";
*tp++ = "!\t\tStart an interactive shell (type ^D to return to cscope).\n";
*tp++ = "^L\t\tRedraw the screen.\n";
*tp++ = "?\t\tDisplay this list of commands.\n";
}
/* print help, a screen at a time */
ep = tp;
ln = 0;
for (tp = text; tp < ep; ) {
if (ln < LINES - 1) {
for (s = *tp; *s != '\0'; ++s) {
if (*s == '\n') {
++ln;
}
}
(void) addstr(*tp++);
}
else {
(void) addstr("\n");
askforchar();
(void) clear();
ln = 0;
}
}
if (ln) {
(void) addstr("\n");
askforchar();
}
}
/* error exit including short usage information */
void
error_usage(void)
{
usage();
fprintf(stderr, "Try the -h option for more information.\n");
myexit(1);
}
/* normal usage message */
void
usage(void)
{
fprintf(stderr, "Usage: cscope [-bcCdehklLqRTuUvV] [-f file] [-F file] [-i file] [-I dir] [-s dir]\n");
fprintf(stderr, " [-p number] [-P path] [-[0-8] pattern] [source files]\n");
}
/* long usage message */
void
longusage(void)
{
usage();
fprintf(stderr, "\
\n\
-b Build the cross-reference only.\n\
-C Ignore letter case when searching.\n\
-c Use only ASCII characters in the cross-ref file (don't compress).\n\
-d Do not update the cross-reference.\n\
-e Suppress the <Ctrl>-e command prompt between files.\n\
-F symfile Read symbol reference lines from symfile.\n\
-f reffile Use reffile as cross-ref file name instead of %s.\n",
REFFILE);
fprintf(stderr, "\
-h This help screen.\n\
-I incdir Look in incdir for any #include files.\n\
-i namefile Browse through files listed in namefile, instead of %s\n",
NAMEFILE);
fprintf(stderr, "\
-k Kernel Mode - don't use %s for #include files.\n",
DFLT_INCDIR);
fputs("\
-L Do a single search with line-oriented output.\n\
-l Line-oriented interface.\n\
-num pattern Go to input field num (counting from 0) and find pattern.\n\
-P path Prepend path to relative file names in pre-built cross-ref file.\n\
-p n Display the last n file path components.\n\
-q Build an inverted index for quick symbol searching.\n\
-R Recurse directories for files.\n\
-s dir Look in dir for additional source files.\n\
-T Use only the first eight characters to match against C symbols.\n\
-U Check file time stamps.\n\
-u Unconditionally build the cross-reference file.\n\
-v Be more verbose in line mode.\n\
-V Print the version number.\n\
\n\
Please see the manpage for more information.\n",
stderr);
}

103
src/history.c Normal file
View File

@ -0,0 +1,103 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol or text cross-reference
*
* command history
*/
#include "global.h"
static struct cmd *tail, *current;
/* add a cmd to the history list */
void
addcmd(int f, char *s) /* field number and command text */
{
struct cmd *h;
h = malloc(sizeof(struct cmd));
if( tail) {
tail->next = h;
h->next = 0;
h->prev = tail;
tail = h;
} else {
tail = h;
h->next = h->prev = 0;
}
h->field = f;
h->text = strdup( s);
current = 0;
}
/* return previous history item */
struct cmd *
prevcmd(void)
{
if( current) {
if( current->prev) /* stay on first item */
return current = current->prev;
else
return current;
} else if( tail)
return current = tail;
else
return NULL;
}
/* return next history item */
struct cmd *
nextcmd(void)
{
if( current) {
if( current->next) /* stay on first item */
return current = current->next;
else
return current;
} else
return NULL;
}
/* reset current to tail */
void
resetcmd(void)
{
current = 0;
}
struct cmd *
currentcmd(void)
{
return current;
}

333
src/input.c Normal file
View File

@ -0,0 +1,333 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* terminal input functions
*/
#include "global.h"
#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
#include <ncurses.h>
#else
#include <curses.h>
#endif
#include <setjmp.h> /* jmp_buf */
#include <stdlib.h>
#include <errno.h>
#if HAVE_SYS_TERMIOS_H
#include <sys/termios.h>
#endif
static jmp_buf env; /* setjmp/longjmp buffer */
static int prevchar; /* previous, ungotten character */
/* Internal prototypes: */
static void catchint(int sig);
/* catch the interrupt signal */
/*ARGSUSED*/
static void
catchint(int sig)
{
(void) sig; /* 'use' it, to avoid a warning */
signal(SIGINT, catchint);
longjmp(env, 1);
}
/* unget a character */
void
myungetch(int c)
{
prevchar = c;
}
/* get a character from the terminal */
int
mygetch(void)
{
sighandler_t savesig = 0; /* old value of signal */
int c;
/* change an interrupt signal to a break key character */
if (setjmp(env) == 0) {
savesig = signal(SIGINT, catchint);
refresh(); /* update the display */
mousereinit(); /* curses can change the menu number */
if(prevchar) {
c = prevchar;
prevchar = 0;
} else {
c = -1;
while (c == -1) {
/* get a character from the terminal */
c = getch();
if ((c == -1) && (errno != EINTR))
break;
}
}
} else { /* longjmp to here from signal handler */
c = KEY_BREAK;
}
signal(SIGINT, savesig);
return(c);
}
/* get a line from the terminal in non-canonical mode */
int
mygetline(char p[], char s[], unsigned size, int firstchar, BOOL iscaseless)
{
int c;
unsigned int i = 0, j;
char *sright; /* substring to the right of the cursor */
unsigned int ri = 0; /* position in right-string */
/* Inserts and deletes are always performed on the left-string,
* but we'll also have a right-string 'sright' to hold characters
* which are on the right of the cursor [insertion point].
*
* Think of 'sright' as a stack -- we push chars into it when the cursor
* moves left, and we pop chars off it when the cursor moves right again.
* At the end of the function, we'll pop off any remaining characters
* onto the end of 's'
*/
sright = calloc(size, sizeof(*sright));
strcpy ( s, p);
i += strlen(p);
/* if a character already has been typed */
if (firstchar != '\0') {
if(iscaseless == YES) {
firstchar = tolower(firstchar);
}
addch(firstchar); /* display it */
s[i++] = firstchar; /* save it */
}
/* until the end of the line is reached */
while ((c = mygetch()) != '\r' && c != '\n' && c != KEY_ENTER) {
if (c == KEY_LEFT || c == ctrl('B')) { /* left */
if (i > 0) {
addch('\b');
/* move this char into the second (rhs) string */
sright[ri++] = s[--i];
}
} else if (c == KEY_RIGHT || c == ctrl('F')) { /* right */
if (i < size && ri > 0) {
/* move this char to the left of the cursor */
s[i++] = sright[--ri];
addch(s[i-1]);
}
} else if (
#ifdef KEY_HOME
c == KEY_HOME ||
#endif
c == ctrl('A') ) {
while (i > 0) {
sright[ri++] = s[--i];
addch('\b');
addch(s[i]);
addch('\b');
}
} else if (
#ifdef KEY_END
c == KEY_END ||
#endif
c == ctrl('E') ) {
while (ri > 0) {
s[i++] = sright[--ri];
addch(s[i-1]);
}
} else if (c == erasechar() || c == KEY_BACKSPACE
|| c == DEL || c == ctrl('H') ) {
/* erase */
if (i > 0) {
if (ri == 0) {
addstr("\b \b");
} else {
addch('\b');
delch();
}
s[i] = '\0';
--i;
}
} else if (c == killchar() || c == KEY_BREAK) {
/* kill */
for (j = 0; j < i; ++j) {
addch('\b');
}
for (j = 0; j < i; ++j) {
addch(' ');
}
for (j = 0; j < i; ++j) {
addch('\b');
}
i = 0;
} else if (isprint(c) || c == '\t') {
/* printable */
if(iscaseless == YES) {
c = tolower(c);
}
/* if it will fit on the line */
if (i < size) {
s[i++] = c; /* save it */
if (ri == 0) {
addch(c); /* display it */
} else {
insch(c); /* display it */
addch(c); /* advance cursor */
}
}
#if UNIXPC
} else if (unixpcmouse == YES && c == ESC) { /* mouse */
getmouseaction(ESC); /* ignore it */
#endif
} else if (mouse == YES && c == ctrl('X')) {
getmouseaction(ctrl('X')); /* ignore it */
} else if (c == EOF) { /* end-of-file */
break;
}
/* return on an empty line to allow a command to be entered */
if (firstchar != '\0' && (i+ri) == 0) {
break;
}
}
/* move any remaining chars on the rhs of the cursor
* onto the end of our string
*/
while (ri > 0) {
s[i++] = sright[--ri];
}
free(sright);
s[i] = '\0';
return(i);
}
/* ask user to enter a character after reading the message */
void
askforchar(void)
{
addstr("Type any character to continue: ");
mygetch();
}
/* ask user to press the RETURN key after reading the message */
void
askforreturn(void)
{
fprintf(stderr, "Press the RETURN key to continue: ");
getchar();
/* HBB 20060419: message probably messed up the screen --- redraw */
if (incurses == YES) {
redrawwin(curscr);
}
}
/* expand the ~ and $ shell meta characters in a path */
void
shellpath(char *out, int limit, char *in)
{
char *lastchar;
char *s, *v;
/* skip leading white space */
while (isspace((unsigned char)*in)) {
++in;
}
lastchar = out + limit - 1;
/* a tilde (~) by itself represents $HOME; followed by a name it
represents the $LOGDIR of that login name */
if (*in == '~') {
*out++ = *in++; /* copy the ~ because it may not be expanded */
/* get the login name */
s = out;
while (s < lastchar && *in != '/' && *in != '\0' && !isspace((unsigned char)*in)) {
*s++ = *in++;
}
*s = '\0';
/* if the login name is null, then use $HOME */
if (*out == '\0') {
v = getenv("HOME");
} else { /* get the home directory of the login name */
v = logdir(out);
}
/* copy the directory name if it isn't too big */
if (v != NULL && strlen(v) < (lastchar - out)) {
strcpy(out - 1, v);
out += strlen(v) - 1;
} else {
/* login not found, so ~ must be part of the file name */
out += strlen(out);
}
}
/* get the rest of the path */
while (out < lastchar && *in != '\0' && !isspace((unsigned char)*in)) {
/* look for an environment variable */
if (*in == '$') {
*out++ = *in++; /* copy the $ because it may not be expanded */
/* get the variable name */
s = out;
while (s < lastchar && *in != '/' && *in != '\0' &&
!isspace((unsigned char)*in)) {
*s++ = *in++;
}
*s = '\0';
/* get its value, but only it isn't too big */
if ((v = getenv(out)) != NULL && strlen(v) < (lastchar - out)) {
strcpy(out - 1, v);
out += strlen(v) - 1;
} else {
/* var not found, or too big, so assume $ must be part of the
* file name */
out += strlen(out);
}
}
else { /* ordinary character */
*out++ = *in++;
}
}
*out = '\0';
}

1204
src/invlib.c Normal file

File diff suppressed because it is too large Load Diff

114
src/invlib.h Normal file
View File

@ -0,0 +1,114 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
#ifndef CSCOPE_INVLIB_H
#define CSCOPE_INVLIB_H
#include <stdio.h> /* need definition of FILE* */
#include <limits.h> /* need definition of CHAR_MAX */
/* inverted index definitions */
/* postings temporary file long number coding into characters */
#if CHAR_MAX==255
# define BASE 223 /* 255 - ' ' */
# define PRECISION 4 /* maximum digits after converting a long */
#else
# if CHAR_MAX==127 /* assume sign-extension of a char when converted to an int */
# define BASE 95 /* 127 - ' ' */
# define PRECISION 5 /* maximum digits after converting a long */
# else
#error Need a platform with 8 bits in a char value
# endif
#endif
/* inverted index access parameters */
#define INVAVAIL 0
#define INVBUSY 1
#define INVALONE 2
/* boolean set operations */
#define BOOL_OR 3
#define AND 4
#define NOT 5
#define REVERSENOT 6
/* note that the entire first block is for parameters */
typedef struct {
long version; /* inverted index format version */
long filestat; /* file status word */
long sizeblk; /* size of logical block in bytes */
long startbyte; /* first byte of superfinger */
long supsize; /* size of superfinger in bytes */
long cntlsize; /* size of max cntl space (should be a multiple of BUFSIZ) */
long share; /* flag whether to use shared memory */
} PARAM;
typedef struct {
FILE *invfile; /* the inverted file ptr */
FILE *postfile; /* posting file ptr */
PARAM param; /* control parameters for the file */
char *iindex; /* ptr to space for superindex */
union logicalblk *logblk; /* ptr to space for a logical block */
long numblk; /* number of block presently at *logblk */
long keypnt; /* number item in present block found */
} INVCONTROL;
typedef struct {
short offset; /* offset in this logical block */
unsigned char size; /* size of term */
unsigned char space; /* number of longs of growth space */
long post; /* number of postings for this entry */
} ENTRY;
typedef struct {
long lineoffset; /* source line database offset */
long fcnoffset; /* function name database offset */
long fileindex : 24; /* source file name index */
long type : 8; /* reference type (mark character) */
} POSTING;
extern long *srcoffset; /* source file name database offsets */
extern int nsrcoffset; /* number of file name database offsets */
void boolclear(void);
POSTING *boolfile(INVCONTROL *invcntl, long *num, int boolarg);
void invclose(INVCONTROL *invcntl);
void invdump(INVCONTROL *invcntl, char *term);
long invfind(INVCONTROL *invcntl, char *searchterm);
int invforward(INVCONTROL *invcntl);
int invopen(INVCONTROL *invcntl, char *invname, char *invpost, int status);
long invmake(char *invname, char *invpost, FILE *infile);
long invterm(INVCONTROL *invcntl, char *term);
#endif /* CSCOPE_INVLIB_H */

51
src/library.h Normal file
View File

@ -0,0 +1,51 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
#ifndef CSCOPE_LIBRARY_H
#define CSCOPE_LIBRARY_H
#include <stdio.h> /* need FILE* type def. */
/* private library */
char *compath(char *pathname);
char *egrepinit(char *egreppat);
char *logdir(char *name);
char *basename(char *path);
FILE *myfopen(char *path, char *mode);
char *mygetenv(char *variable, char *deflt);
int myopen(char *path, int flag, int mode);
FILE *mypopen(char *cmd, char *mode);
int mypclose(FILE *ptr);
FILE *vpfopen(char *filename, char *type);
void egrepcaseless(int i);
#endif /* CSCOPE_LIBRARY_H */

100
src/logdir.c Normal file
View File

@ -0,0 +1,100 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/*
* logdir()
*
* This routine does not use the getpwent(3) library routine
* because the latter uses the stdio package. The allocation of
* storage in this package destroys the integrity of the shell's
* storage allocation.
*/
#include <unistd.h>
#include <string.h>
#include "global.h"
#define OURBUFSIZ 160 /* renamed: avoid conflict with <stdio.h> */
static char line[OURBUFSIZ+1];
/* Internal prototypes: */
static char *nextfield(char *p);
static char *
nextfield(char *p)
{
while (*p && *p != ':')
++p;
if (*p) *p++ = 0;
return(p);
}
char *
logdir(char *name)
{
char *p;
int i, j;
int pwf;
/* attempt to open the password file */
if ((pwf = myopen("/etc/passwd", 0, 0)) == -1)
return(0);
/* find the matching password entry */
do {
/* get the next line in the password file */
i = read(pwf, line, OURBUFSIZ);
for (j = 0; j < i; j++)
if (line[j] == '\n')
break;
/* return a null pointer if the whole file has been read */
if (j >= i)
return(0);
line[++j] = 0; /* terminate the line */
(void) lseek(pwf, (long) (j - i), 1); /* point at the next line */
p = nextfield(line); /* get the logname */
} while (*name != *line || /* fast pretest */
strcmp(name, line) != 0);
(void) close(pwf);
/* skip the intervening fields */
p = nextfield(p);
p = nextfield(p);
p = nextfield(p);
p = nextfield(p);
/* return the login directory */
(void) nextfield(p);
return(p);
}

149
src/lookup.c Normal file
View File

@ -0,0 +1,149 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* keyword look-up routine for the C symbol scanner
*/
#include "global.h"
#include "lookup.h"
/* keyword text for fast testing of keywords in the scanner */
char enumtext[] = "enum";
char externtext[] = "extern";
char structtext[] = "struct";
char typedeftext[] = "typedef";
char uniontext[] = "union";
/* This keyword table is also used for keyword text compression. Keywords
* with an index less than the numeric value of a space are replaced with the
* control character corresponding to the index, so they cannot be moved
* without changing the database file version and adding compatibility code
* for old databases.
*/
struct keystruct keyword[] = {
{"", '\0', NULL}, /* dummy entry */
{"#define", ' ', NULL}, /* must be table entry 1 */
{"#include", ' ', NULL}, /* must be table entry 2 */
{"break", '\0', NULL}, /* rarely in cross-reference */
{"case", ' ', NULL},
{"char", ' ', NULL},
{"continue", '\0', NULL}, /* rarely in cross-reference */
{"default", '\0', NULL}, /* rarely in cross-reference */
{"double", ' ', NULL},
{"\t", '\0', NULL}, /* must be the table entry 9 */
{"\n", '\0', NULL}, /* must be the table entry 10 */
{"else", ' ', NULL},
{enumtext, ' ', NULL},
{externtext, ' ', NULL},
{"float", ' ', NULL},
{"for", '(', NULL},
{"goto", ' ', NULL},
{"if", '(', NULL},
{"int", ' ', NULL},
{"long", ' ', NULL},
{"register", ' ', NULL},
{"return", '\0', NULL},
{"short", ' ', NULL},
{"sizeof", '\0', NULL},
{"static", ' ', NULL},
{structtext, ' ', NULL},
{"switch", '(', NULL},
{typedeftext, ' ', NULL},
{uniontext, ' ', NULL},
{"unsigned", ' ', NULL},
{"void", ' ', NULL},
{"while", '(', NULL},
/* these keywords are not compressed */
{"do", '\0', NULL},
{"auto", ' ', NULL},
{"fortran", ' ', NULL},
{"const", ' ', NULL},
{"signed", ' ', NULL},
{"volatile", ' ', NULL},
};
#define KEYWORDS (sizeof(keyword) / sizeof(keyword[0]))
#define HASHMOD (KEYWORDS * 2 + 1)
static struct keystruct *hashtab[HASHMOD]; /* pointer table */
/* put the keywords into the symbol table */
void
initsymtab(void)
{
unsigned int i, j;
struct keystruct *p;
for (i = 1; i < KEYWORDS; ++i) {
p = keyword + i;
j = hash(p->text) % HASHMOD;
p->next = hashtab[j];
hashtab[j] = p;
}
}
/* see if this identifier is a keyword */
char *
lookup(char *ident)
{
struct keystruct *p;
int c;
/* look up the identifier in the keyword table */
for (p = hashtab[hash(ident) % HASHMOD]; p != NULL; p = p->next) {
if (strequal(ident, p->text)) {
if (compress == YES && (c = p - keyword) < ' ') {
ident[0] = c; /* compress the keyword */
}
return(p->text);
}
}
/* this is an identifier */
return(NULL);
}
/* form hash value for string */
int
hash(char *ss)
{
int i;
unsigned char *s = (unsigned char *)ss;
for (i = 0; *s != '\0'; )
i += *s++; /* += is faster than <<= for cscope */
return(i);
}

45
src/lookup.h Normal file
View File

@ -0,0 +1,45 @@
/*===========================================================================
Copyright (c) 2001, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
#ifndef CSCOPE_LOOKUP_H
#define CSCOPE_LOOKUP_H
/* declarations for objects defined in lookup.c */
/* keyword text for fast testing of keywords in the scanner */
extern char enumtext[];
extern char externtext[];
extern char structtext[];
extern char typedeftext[];
extern char uniontext[];
#endif /* CSCOPE_LOOKUP_H */

674
src/main.c Normal file
View File

@ -0,0 +1,674 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* main functions
*/
#include "global.h"
#include "build.h"
#include "vp.h"
#include "version.h" /* FILEVERSION and FIXVERSION */
#include "scanner.h"
#include <stdlib.h> /* atoi */
#include <ncurses.h>
#include <sys/types.h> /* needed by stat.h */
#include <sys/stat.h> /* stat */
#include <signal.h>
#include <getopt.h>
/* defaults for unset environment variables */
#define EDITOR "vi"
#define HOME "/" /* no $HOME --> use root directory */
#define SHELL "sh"
#define LINEFLAG "+%s" /* default: used by vi and emacs */
#define TMPDIR "/tmp"
/* note: these digraph character frequencies were calculated from possible
printable digraphs in the cross-reference for the C compiler */
char dichar1[] = " teisaprnl(of)=c"; /* 16 most frequent first chars */
char dichar2[] = " tnerpla"; /* 8 most frequent second chars
using the above as first chars */
char dicode1[256]; /* digraph first character code */
char dicode2[256]; /* digraph second character code */
char *editor, *shell, *lineflag; /* environment variables */
char *home; /* Home directory */
BOOL lineflagafterfile;
char *argv0; /* command name */
BOOL compress = YES; /* compress the characters in the crossref */
BOOL dbtruncated; /* database symbols are truncated to 8 chars */
int dispcomponents = 1; /* file path components to display */
#if CCS
BOOL displayversion; /* display the C Compilation System version */
#endif
BOOL editallprompt = YES; /* prompt between editing files */
unsigned int fileargc; /* file argument count */
char **fileargv; /* file argument values */
int fileversion; /* cross-reference file version */
BOOL incurses = NO; /* in curses */
BOOL invertedindex; /* the database has an inverted index */
BOOL isuptodate; /* consider the crossref up-to-date */
BOOL kernelmode; /* don't use DFLT_INCDIR - bad for kernels */
BOOL linemode = NO; /* use line oriented user interface */
BOOL verbosemode = NO; /* print extra information on line mode */
BOOL recurse_dir = NO; /* recurse dirs when searching for src files */
char *namefile; /* file of file names */
BOOL ogs; /* display OGS book and subsystem names */
char *prependpath; /* prepend path to file names */
FILE *refsfound; /* references found file */
char temp1[PATHLEN + 1]; /* temporary file name */
char temp2[PATHLEN + 1]; /* temporary file name */
char tempdirpv[PATHLEN + 1]; /* private temp directory */
long totalterms; /* total inverted index terms */
BOOL trun_syms; /* truncate symbols to 8 characters */
char tempstring[TEMPSTRING_LEN + 1]; /* use this as a buffer, instead of 'yytext',
* which had better be left alone */
char *tmpdir; /* temporary directory */
/* Internal prototypes: */
static void skiplist(FILE *oldrefs);
static void initcompress(void);
static inline void readenv(void);
#if defined(KEY_RESIZE) && !defined(__DJGPP__)
void
sigwinch_handler(int sig, siginfo_t *info, void *unused)
{
if(incurses == YES){
ungetch(KEY_RESIZE);
}
}
#endif
int
main(int argc, char **argv)
{
FILE *names; /* name file pointer */
int oldnum; /* number in old cross-ref */
char path[PATHLEN + 1]; /* file path */
FILE *oldrefs; /* old cross-reference file */
char *s;
int c;
unsigned int i;
pid_t pid;
struct stat stat_buf;
#if defined(KEY_RESIZE) && !defined(__DJGPP__)
struct sigaction winch_action;
#endif
mode_t orig_umask;
yyin = stdin;
yyout = stdout;
/* save the command name for messages */
argv0 = argv[0];
/* set the options */
argv = parse_options(&argc, argv);
/* read the environment */
readenv();
/* XXX remove if/when clearerr() in dir.c does the right thing. */
if (namefile && strcmp(namefile, "-") == 0 && !buildonly) {
postfatal("cscope: Must use -b if file list comes from stdin\n");
/* NOTREACHED */
}
/* make sure that tmpdir exists */
if (lstat (tmpdir, &stat_buf)) {
fprintf (stderr,
"cscope: Temporary directory %s does not exist or cannot be accessed\n",
tmpdir);
fprintf (stderr,
"cscope: Please create the directory or set the environment variable\n"
"cscope: TMPDIR to a valid directory\n");
myexit(1);
}
/* create the temporary file names */
orig_umask = umask(S_IRWXG|S_IRWXO);
pid = getpid();
snprintf(tempdirpv, sizeof(tempdirpv), "%s/cscope.%d", tmpdir, pid);
if(mkdir(tempdirpv,S_IRWXU)) {
fprintf(stderr,
"cscope: Could not create private temp dir %s\n",
tempdirpv);
myexit(1);
}
umask(orig_umask);
snprintf(temp1, sizeof(temp1), "%s/cscope.1", tempdirpv);
snprintf(temp2, sizeof(temp2), "%s/cscope.2", tempdirpv);
/* if running in the foreground */
if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
/* cleanup on the interrupt and quit signals */
signal(SIGINT, myexit);
signal(SIGQUIT, myexit);
}
/* cleanup on the hangup signal */
signal(SIGHUP, myexit);
/* ditto the TERM signal */
signal(SIGTERM, myexit);
/* ignore PIPE signal, so myexit() will have a chance to clean up in
* linemode, while in curses mode the "|" command can cause a pipe signal
* too
*/
signal(SIGPIPE, SIG_IGN);
/* if the database path is relative and it can't be created */
if (reffile[0] != '/' && access(".", WRITE) != 0) {
/* put it in the home directory if the database may not be
* up-to-date or doesn't exist in the relative directory,
* so a database in the current directory will be
* used instead of failing to open a non-existant database in
* the home directory
*/
snprintf(path, sizeof(path), "%s/%s", home, reffile);
if (isuptodate == NO || access(path, READ) == 0) {
reffile = strdup(path);
snprintf(path, sizeof(path), "%s/%s", home, invname);
invname = strdup(path);
snprintf(path, sizeof(path), "%s/%s", home, invpost);
invpost = strdup(path);
}
}
if (linemode == NO) {
signal(SIGINT, SIG_IGN); /* ignore interrupts */
#if defined(KEY_RESIZE) && !defined(__DJGPP__)
winch_action.sa_sigaction = sigwinch_handler;
sigemptyset(&winch_action.sa_mask);
winch_action.sa_flags = SA_SIGINFO;
sigaction(SIGWINCH,&winch_action,NULL);
#endif
dispinit(); /* initialize display parameters */
setfield(); /* set the initial cursor position */
clearmsg(); /* clear any build progress message */
display(); /* display the version number and input fields */
}
/* if the cross-reference is to be considered up-to-date */
if (isuptodate == YES) {
if ((oldrefs = vpfopen(reffile, "rb")) == NULL) {
postfatal("cscope: cannot open file %s\n", reffile);
/* NOTREACHED */
}
/* get the crossref file version but skip the current directory */
if (fscanf(oldrefs, "cscope %d %*s", &fileversion) != 1) {
postfatal("cscope: cannot read file version from file %s\n",
reffile);
/* NOTREACHED */
}
if (fileversion >= 8) {
/* override these command line options */
compress = YES;
invertedindex = NO;
/* see if there are options in the database */
for (;;) {
getc(oldrefs); /* skip the blank */
if ((c = getc(oldrefs)) != '-') {
ungetc(c, oldrefs);
break;
}
switch (getc(oldrefs)) {
case 'c': /* ASCII characters only */
compress = NO;
break;
case 'q': /* quick search */
invertedindex = YES;
fscanf(oldrefs, "%ld", &totalterms);
break;
case 'T': /* truncate symbols to 8 characters */
dbtruncated = YES;
trun_syms = YES;
break;
}
}
initcompress();
seek_to_trailer(oldrefs);
}
/* skip the source and include directory lists */
skiplist(oldrefs);
skiplist(oldrefs);
/* get the number of source files */
if (fscanf(oldrefs, "%lu", &nsrcfiles) != 1) {
postfatal(
"cscope: cannot read source file size from file %s\n",
reffile);
/* NOTREACHED */
}
/* get the source file list */
srcfiles = malloc(nsrcfiles * sizeof(*srcfiles));
if (fileversion >= 9) {
/* allocate the string space */
if (fscanf(oldrefs, "%d", &oldnum) != 1) {
postfatal(
"cscope: cannot read string space size from file %s\n",
reffile);
/* NOTREACHED */
}
s = malloc(oldnum);
getc(oldrefs); /* skip the newline */
/* read the strings */
if (fread(s, oldnum, 1, oldrefs) != 1) {
postfatal(
"cscope: cannot read source file names from file %s\n",
reffile);
/* NOTREACHED */
}
/* change newlines to nulls */
for (i = 0; i < nsrcfiles; ++i) {
srcfiles[i] = s;
for (++s; *s != '\n'; ++s) {
;
}
*s = '\0';
++s;
}
/* if there is a file of source file names */
if ((namefile != NULL && (names = vpfopen(namefile, "r")) != NULL)
|| (names = vpfopen(NAMEFILE, "r")) != NULL) {
/* read any -p option from it */
while (fgets(path, sizeof(path), names) != NULL && *path == '-') {
i = path[1];
s = path + 2; /* for "-Ipath" */
if (*s == '\0') { /* if "-I path" */
fgets(path, sizeof(path), names);
s = path;
}
switch (i) {
case 'p': /* file path components to display */
if (*s < '0' || *s > '9') {
posterr("cscope: -p option in file %s: missing or invalid numeric value\n", namefile);
}
dispcomponents = atoi(s);
}
}
fclose(names);
}
} else {
for (i = 0; i < nsrcfiles; ++i) {
if (!fgets(path, sizeof(path), oldrefs) ) {
postfatal(
"cscope: cannot read source file name from file %s\n",
reffile);
/* NOTREACHED */
}
srcfiles[i] = strdup(path);
}
}
fclose(oldrefs);
} else {
/* save the file arguments */
fileargc = argc;
fileargv = argv;
/* get source directories from the environment */
if ((s = getenv("SOURCEDIRS")) != NULL) {
sourcedir(s);
}
/* make the source file list */
srcfiles = malloc(msrcfiles * sizeof(*srcfiles));
makefilelist();
if (nsrcfiles == 0) {
postfatal("cscope: no source files found\n");
/* NOTREACHED */
}
/* get include directories from the environment */
if ((s = getenv("INCLUDEDIRS")) != NULL) {
includedir(s);
}
/* add /usr/include to the #include directory list,
but not in kernelmode... kernels tend not to use it. */
if (kernelmode == NO) {
if (NULL != (s = getenv("INCDIR"))) {
includedir(s);
} else {
includedir(DFLT_INCDIR);
}
}
/* initialize the C keyword table */
initsymtab();
/* Tell build.c about the filenames to create: */
setup_build_filenames(reffile);
/* build the cross-reference */
initcompress();
if (linemode == NO || verbosemode == YES) /* display if verbose as well */
postmsg("Building cross-reference...");
build();
if (linemode == NO )
clearmsg(); /* clear any build progress message */
if (buildonly == YES) {
myexit(0);
}
}
opendatabase();
/* if using the line oriented user interface so cscope can be a
subprocess to emacs or samuel */
if (linemode == YES) {
if (*Pattern != '\0') { /* do any optional search */
if (search() == YES) {
/* print the total number of lines in
* verbose mode */
if (verbosemode == YES)
printf("cscope: %d lines\n",
totallines);
while ((c = getc(refsfound)) != EOF)
putchar(c);
}
}
if (onesearch == YES)
myexit(0);
for (;;) {
char buf[PATLEN + 2];
printf(">> ");
fflush(stdout);
if (fgets(buf, sizeof(buf), stdin) == NULL) {
myexit(0);
}
/* remove any trailing newline character */
if (*(s = buf + strlen(buf) - 1) == '\n') {
*s = '\0';
}
switch (*buf) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': /* samuel only */
field = *buf - '0';
strcpy(Pattern, buf + 1);
if (search() == NO) {
printf("Unable to search database\n");
} else {
printf("cscope: %d lines\n", totallines);
while ((c = getc(refsfound)) != EOF) {
putchar(c);
}
}
break;
case 'c': /* toggle caseless mode */
case ctrl('C'):
if (caseless == NO) {
caseless = YES;
} else {
caseless = NO;
}
egrepcaseless(caseless);
break;
case 'r': /* rebuild database cscope style */
case ctrl('R'):
freefilelist();
makefilelist();
/* FALLTHROUGH */
case 'R': /* rebuild database samuel style */
rebuild();
putchar('\n');
break;
case 'C': /* clear file names */
freefilelist();
putchar('\n');
break;
case 'F': /* add a file name */
strcpy(path, buf + 1);
if (infilelist(path) == NO &&
(s = inviewpath(path)) != NULL) {
addsrcfile(s);
}
putchar('\n');
break;
case 'q': /* quit */
case ctrl('D'):
case ctrl('Z'):
myexit(0);
default:
fprintf(stderr, "cscope: unknown command '%s'\n", buf);
break;
}
}
/* NOTREACHED */
}
/* pause before clearing the screen if there have been error messages */
if (errorsfound == YES) {
errorsfound = NO;
askforreturn();
}
/* do any optional search */
if (*Pattern != '\0') {
atfield(); /* move to the input field */
command(ctrl('Y')); /* search */
} else if (reflines != NULL) {
/* read any symbol reference lines file */
readrefs(reflines);
}
display(); /* update the display */
for (;;) {
c = mygetch();
/* exit if the quit command is entered */
if (c == EOF || c == ctrl('D')) {
break;
}
if (c == ctrl('Z')) {
kill(0, SIGTSTP);
continue;
}
command(c);
display();
}
/* cleanup and exit */
myexit(0);
/* NOTREACHED */
return 0; /* avoid warning... */
}
void
cannotopen(char *file)
{
posterr("Cannot open file %s", file);
}
/* FIXME MTE - should use postfatal here */
void
cannotwrite(char *file)
{
char msg[MSGLEN + 1];
snprintf(msg, sizeof(msg), "Removed file %s because write failed", file);
myperror(msg); /* display the reason */
unlink(file);
myexit(1); /* calls exit(2), which closes files */
}
/* set up the digraph character tables for text compression */
static void
initcompress(void)
{
int i;
if (compress == YES) {
for (i = 0; i < 16; ++i) {
dicode1[(unsigned char) (dichar1[i])] = i * 8 + 1;
}
for (i = 0; i < 8; ++i) {
dicode2[(unsigned char) (dichar2[i])] = i + 1;
}
}
}
/* skip the list in the cross-reference file */
static void
skiplist(FILE *oldrefs)
{
int i;
if (fscanf(oldrefs, "%d", &i) != 1) {
postfatal("cscope: cannot read list size from file %s\n", reffile);
/* NOTREACHED */
}
while (--i >= 0) {
if (fscanf(oldrefs, "%*s") != 0) {
postfatal("cscope: cannot read list name from file %s\n", reffile);
/* NOTREACHED */
}
}
}
/* enter curses mode */
void
entercurses(void)
{
incurses = YES;
#ifndef __MSDOS__ /* HBB 20010313 */
nonl(); /* don't translate an output \n to \n\r */
#endif
raw(); /* single character input */
noecho(); /* don't echo input characters */
clear(); /* clear the screen */
mouseinit(); /* initialize any mouse interface */
drawscrollbar(topline, nextline);
}
/* exit curses mode */
void
exitcurses(void)
{
/* clear the bottom line */
move(LINES - 1, 0);
clrtoeol();
refresh();
/* exit curses and restore the terminal modes */
endwin();
incurses = NO;
/* restore the mouse */
mousecleanup();
fflush(stdout);
}
/* cleanup and exit */
void
myexit(int sig)
{
/* HBB 20010313; close file before unlinking it. Unix may not care
* about that, but DOS absolutely needs it */
if (refsfound != NULL)
fclose(refsfound);
/* remove any temporary files */
if (temp1[0] != '\0') {
unlink(temp1);
unlink(temp2);
rmdir(tempdirpv);
}
/* restore the terminal to its original mode */
if (incurses == YES) {
exitcurses();
}
/* dump core for debugging on the quit signal */
if (sig == SIGQUIT) {
abort();
}
/* HBB 20000421: be nice: free allocated data */
freefilelist();
freeinclist();
freesrclist();
freecrossref();
free_newbuildfiles();
if( remove_symfile_onexit == YES ) {
unlink( reffile );
unlink( invname );
unlink( invpost );
}
exit(sig);
}
static inline void readenv(void){
editor = mygetenv("EDITOR", EDITOR);
editor = mygetenv("VIEWER", editor); /* use viewer if set */
editor = mygetenv("CSCOPE_EDITOR", editor); /* has last word */
home = mygetenv("HOME", HOME);
shell = mygetenv("SHELL", SHELL);
lineflag = mygetenv("CSCOPE_LINEFLAG", LINEFLAG);
lineflagafterfile = getenv("CSCOPE_LINEFLAG_AFTER_FILE") ? 1 : 0;
tmpdir = mygetenv("TMPDIR", TMPDIR);
}

431
src/mouse.c Normal file
View File

@ -0,0 +1,431 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* mouse functions
*/
#include "global.h"
BOOL mouse = NO; /* mouse interface */
#ifdef UNIXPC /* build command requires #ifdef instead of #if */
#include <sys/window.h>
BOOL unixpcmouse = NO; /* running with a mouse on the Unix PC? */
static int uw_hs, uw_vs; /* character height and width */
#endif
typedef struct { /* menu */
char *text;
char *value;
} MENU;
static MENU mainmenu[] = { /* main menu */
{"Send", "##\033s##\r"},
{"Repeat", "\031"},
{"Edit All", "\05"},
{"Rebuild", "\022"},
{"Shell", "!"},
{"Redraw", "\f"},
{"Help", "?"},
{"Exit", "\04"},
{NULL, NULL}
};
static MENU changemenu[] = { /* change mode menu */
{"Mark Screen", "*"},
{"Mark All", "a"},
{"Change", "\04"},
{"No Change", "\033"},
{"Shell", "!"},
{"Redraw", "\f"},
{"Help", "?"},
{NULL, NULL}
};
static MENU *loaded; /* menu loaded */
static BOOL emacsviterm = NO; /* terminal type */
static void loadmenu(MENU *menu);
static int getcoordinate(void);
static int getpercent(void);
/* see if there is a mouse interface */
void
mouseinit(void)
{
char *term;
/* see if this is emacsterm or viterm */
term = mygetenv("TERM", "");
if (strcmp(term, "emacsterm") == 0 ||
strcmp(term, "viterm") == 0) {
emacsviterm = YES;
mouse = YES;
}
/* the MOUSE enviroment variable is for 5620 terminal programs that have
mouse support but the TERM environment variable is the same as a
terminal without a mouse, such as myx */
else if (strcmp(mygetenv("MOUSE", ""), "myx") == 0) {
mouse = YES;
}
#if UNIXPC
else if (strcmp(term,"s4") == 0 ||
strcmp(term,"s120") == 0 ||
strcmp(term,"s90") == 0) {
int retval;
struct uwdata uwd; /* Window data structure */
struct umdata umd; /* Mouse data structure */
/* Ask for character size info */
retval = ioctl(1,WIOCGETD,&uwd);
if(retval || uwd.uw_hs <= 0 || uwd.uw_vs <= 0) {
/**************************************************
* something wrong with the kernel, so fake it...
**************************************************/
if(!strcmp(term,"s4")) {
uw_hs = 9;
uw_vs = 12;
}
else {
uw_hs = 6;
uw_vs = 10;
}
}
else {
/* Kernel is working and knows about this font */
uw_hs = uwd.uw_hs;
uw_vs = uwd.uw_vs;
}
/**************************************************
* Now turn on mouse reporting so we can actually
* make use of all this stuff.
**************************************************/
if((retval = ioctl(1,WIOCGETMOUSE,&umd)) != -1) {
umd.um_flags= MSDOWN+MSUP;
ioctl(1,WIOCSETMOUSE,&umd);
}
unixpcmouse = YES;
}
#endif
if (mouse == YES) {
loadmenu(mainmenu);
}
}
/* load the correct mouse menu */
void
mousemenu(void)
{
if (mouse == YES) {
if (changing == YES) {
loadmenu(changemenu);
}
else {
loadmenu(mainmenu);
}
}
}
/* download a menu */
static void
loadmenu(MENU *menu)
{
int i;
if (emacsviterm == YES) {
mousereinit();
(void) printf("\033V1"); /* display the scrollbar */
(void) printf("\033M0@%s@%s@", menu[0].text, menu[0].value);
for (i = 1; menu[i].text != NULL; ++i) {
(void) printf("\033M@%s@%s@", menu[i].text, menu[i].value);
}
}
else { /* myx */
int len;
mousecleanup();
(void) printf("\033[6;1X\033[9;1X");
for (i = 0; menu[i].text != NULL; ++i) {
len = strlen(menu[i].text);
(void) printf("\033[%d;%dx%s%s", len,
(int) (len + strlen(menu[i].value)),
menu[i].text, menu[i].value);
}
loaded = menu;
}
(void) fflush(stdout);
}
/* reinitialize the mouse in case curses changed the attributes */
void
mousereinit(void)
{
if (emacsviterm == YES) {
/* enable the mouse click and sweep coordinate control sequence */
/* and switch to menu 2 */
(void) printf("\033{2\033#2");
(void) fflush(stdout);
}
}
/* restore the mouse attributes */
void
mousecleanup(void)
{
int i;
if (loaded != NULL) { /* only true for myx */
/* remove the mouse menu */
(void) printf("\033[6;0X\033[9;0X");
for (i = 0; loaded[i].text != NULL; ++i) {
(void) printf("\033[0;0x");
}
loaded = NULL;
}
}
/* draw the scrollbar */
void
drawscrollbar(int top, int bot)
{
int p1, p2;
if (emacsviterm == YES) {
if (bot > top) {
p1 = 16 + (top - 1) * 100 / totallines;
p2 = 16 + (bot - 1) * 100 / totallines;
if (p2 > 116) {
p2 = 116;
}
if (p1 < 16) {
p1 = 16;
}
/* don't send ^S or ^Q because it will hang a layer using cu(1) */
if (p1 == ctrl('Q') || p1 == ctrl('S')) {
++p1;
}
if (p2 == ctrl('Q') || p2 == ctrl('S')) {
++p2;
}
}
else {
p1 = p2 = 16;
}
(void) printf("\033W%c%c", p1, p2);
}
}
/* get the mouse information */
MOUSE *
getmouseaction(char leading_char)
{
static MOUSE m;
#if UNIXPC
if(unixpcmouse == YES && leading_char == ESC) {
/* Called if cscope received an ESC character. See if it is
* a mouse report and if so, decipher it. A mouse report
* looks like: "<ESC>[?xx;yy;b;rM"
*/
int x = 0, y = 0, button = 0, reason = 0;
int i;
/* Get a mouse report. The form is: XX;YY;B;RM where
* XX is 1,2, or 3 decimal digits with the X pixel position.
* Similarly for YY. B is a single decimal digit with the
* button number (4 for one, 2 for two, and 1 for three).
* R is the reason for the mouse report.
*
* In general, the input is read until the mouse report has
* been completely read in or we have discovered that this
* escape sequence is NOT a mouse report. In the latter case
* return the last character read to the input stream with
* myungetch().
*/
/* Check for "[?" being next 2 chars */
if(((i = mygetch()) != '[') || ((i = mygetch()) != '?')) {
myungetch(i);
return(NULL);
}
/* Grab the X position (in pixels) */
while(isdigit(i = mygetch())) {
x = (x*10) + (i - '0');
}
if(i != ';') {
myungetch(i);
return(NULL); /* not a mouse report after all */
}
/* Grab the Y position (in pixels) */
while(isdigit(i = mygetch())) {
y = (y*10) + (i - '0');
}
if(i != ';') {
myungetch(i);
return(NULL);
}
/* Get which button */
if((button = mygetch()) > '4') {
myungetch(button);
return(NULL);
}
if((i = mygetch()) != ';') {
myungetch(i);
return(NULL);
}
/* Get the reason for this mouse report */
if((reason = mygetch()) > '8') {
myungetch(reason);
return(NULL);
}
/* sequence should terminate with an 'M' */
if((i = mygetch()) != 'M') {
myungetch(i);
return(NULL);
}
/* OK. We get a mouse report whenever a button is depressed
* or released. Let's ignore the report whenever the button
* is depressed until when I am ready to implement sweeping.
*/
if(reason != '2') {
return(NULL); /* '2' means button is released */
}
/************************************************************
* Always indicate button 1 irregardless of which button was
* really pushed.
************************************************************/
m.button = 1;
/************************************************************
* Convert pixel coordinates to line and column coords.
* The height and width are obtained using an ioctl() call
* in mouseinit(). This assumes that variable width chars
* are not being used ('though it would probably work anyway).
************************************************************/
m.x1 = x/uw_hs; /* pixel/horizontal_spacing */
m.y1 = y/uw_vs; /* pixel/vertical_spacing */
/* "null" out the other fields */
m.percent = m.x2 = m.y2 = -1;
}
else
#endif /* not UNIXPC */
if (mouse == YES && leading_char == ctrl('X')) {
switch (mygetch()) {
case ctrl('_'): /* click */
if ((m.button = mygetch()) == '0') { /* if scrollbar */
m.percent = getpercent();
}
else {
m.x1 = getcoordinate();
m.y1 = getcoordinate();
m.x2 = m.y2 = -1;
}
break;
case ctrl(']'): /* sweep */
m.button = mygetch();
m.x1 = getcoordinate();
m.y1 = getcoordinate();
m.x2 = getcoordinate();
m.y2 = getcoordinate();
break;
default:
return(NULL);
}
}
else return(NULL);
return(&m);
}
/* get a row or column coordinate from a mouse button click or sweep */
static int
getcoordinate(void)
{
int c, next;
c = mygetch();
next = 0;
if (c == ctrl('A')) {
next = 95;
c = mygetch();
}
if (c < ' ') {
return (0);
}
return (next + c - ' ');
}
/* get a percentage */
static int
getpercent(void)
{
int c;
c = mygetch();
if (c < 16) {
return(0);
}
if (c > 120) {
return(100);
}
return(c - 16);
}

49
src/mygetenv.c Normal file
View File

@ -0,0 +1,49 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
#include "library.h"
#include <stdlib.h>
/* return the non-null environment value or the default argument */
char *
mygetenv(char *variable, char *deflt)
{
char *value;
value = getenv(variable);
if (value == NULL || *value == '\0') {
return(deflt);
}
return(value);
}

208
src/mypopen.c Normal file
View File

@ -0,0 +1,208 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "global.h" /* pid_t, shell, and basename() */
#define tst(a,b) (*mode == 'r'? (b) : (a))
#define RDR 0
#define WTR 1
/* HBB 20010312: make this a bit safer --- don't blindly assume it's 1 */
#ifdef FD_CLOEXEC
# define CLOSE_ON_EXEC FD_CLOEXEC
#else
# define CLOSE_ON_EXEC 1
#endif
#ifdef HAVE_IO_H
# include <io.h> /* for setmode() */
#endif
static pid_t popen_pid[20];
static void (*tstat)(int);
int
myopen(char *path, int flag, int mode)
{
/* opens a file descriptor and then sets close-on-exec for the file */
int fd;
/* 20020103: if file is not explicitly in Binary mode, make
* sure we override silly Cygwin behaviour of automatic binary
* mode for files in "binary mounted" paths */
#if O_BINARY != O_TEXT
if (! (flag | O_BINARY))
flag |= O_TEXT;
#endif
if(mode)
fd = open(path, flag, mode);
else
fd = open(path, flag);
#ifdef __DJGPP__ /* FIXME: test feature, not platform */
/* HBB 20010312: DOS GCC doesn't have FD_CLOEXEC (yet), so it
* always fails this call. Have to skip that step */
if(fd != -1)
return(fd);
#endif
if(fd != -1 && (fcntl(fd, F_SETFD, CLOSE_ON_EXEC) != -1))
return(fd);
else
{
/* Ensure that if the fcntl fails and fd is valid, then
the file is closed properly. In general this should
not happen. */
if (fd != -1)
{
close (fd);
}
return(-1);
}
}
FILE *
myfopen(char *path, char *mode)
{
/* opens a file pointer and then sets close-on-exec for the file */
FILE *fp;
fp = fopen(path, mode);
#ifdef SETMODE
if (fp && ! strchr(mode, 'b')) {
SETMODE(fileno(fp), O_TEXT);
}
#endif /* SETMODE */
#ifdef __DJGPP__ /* FIXME: test feature, not platform */
/* HBB 20010312: DOS GCC doesn't have FD_CLOEXEC (yet), so it
* always fails this call. Have to skip that step */
if(fp)
#else
if(fp && (fcntl(fileno(fp), F_SETFD, CLOSE_ON_EXEC) != -1))
#endif
return(fp);
else {
if (fp)
fclose(fp);
return(NULL);
}
}
FILE *
mypopen(char *cmd, char *mode)
{
#ifdef __DJGPP__
/* HBB 20010312: Has its own implementation of popen(), which
* is better suited to the platform than cscope's */
return (popen)(cmd, mode);
#else
int p[2];
pid_t *poptr;
int myside, yourside;
pid_t pid;
if(pipe(p) < 0)
return(NULL);
myside = tst(p[WTR], p[RDR]);
yourside = tst(p[RDR], p[WTR]);
if((pid = fork()) == 0) {
/* myside and yourside reverse roles in child */
int stdio;
/* close all pipes from other popen's */
for (poptr = popen_pid; poptr < popen_pid+20; poptr++) {
if(*poptr)
(void) close(poptr - popen_pid);
}
stdio = tst(0, 1);
close(myside);
close(stdio);
#if V9
dup2(yourside, stdio);
#else
fcntl(yourside, F_DUPFD, stdio);
#endif
close(yourside);
execlp(shell, basename(shell), "-c", cmd, (void *)0);
_exit(1);
} else if (pid > 0)
tstat = signal(SIGTSTP, SIG_DFL);
if(pid == -1)
return(NULL);
popen_pid[myside] = pid;
(void) close(yourside);
return(fdopen(myside, mode));
#endif /* DJGPP */
}
/* HBB 20010705: renamed from 'pclose', which would collide with
* system-supplied function of same name */
int
mypclose(FILE *ptr)
{
#ifdef __DJGPP__
/* HBB 20010705: This system has its own pclose(), which we
* don't want to replace */
return (pclose)(ptr);
#else
int f;
pid_t r;
int status = -1;
sighandler_t hstat, istat, qstat;
f = fileno(ptr);
(void) fclose(ptr);
istat = signal(SIGINT, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
hstat = signal(SIGHUP, SIG_IGN);
while((r = wait(&status)) != popen_pid[f] && r != -1)
; /* nothing */
if(r == -1)
status = -1;
(void) signal(SIGINT, istat);
(void) signal(SIGQUIT, qstat);
(void) signal(SIGHUP, hstat);
(void) signal(SIGTSTP, tstat);
/* mark this pipe closed */
popen_pid[f] = 0;
return(status);
#endif /* DJGPP */
}

159
src/opt.c Normal file
View File

@ -0,0 +1,159 @@
#include "global.h"
#include "build.h"
#include "vp.h"
#include "version.h" /* FILEVERSION and FIXVERSION */
#include "scanner.h"
#include <stdlib.h> /* atoi */
#include <getopt.h>
BOOL remove_symfile_onexit = NO;
BOOL onesearch; /* one search only in line mode */
char *reflines; /* symbol reference lines file */
char ** parse_options(int *argc, char **argv)
{
int opt;
int longind;
char path[PATHLEN + 1]; /* file path */
char *s;
int argcc = *argc;
struct option lopts[] = {
{"help", 0, NULL, 'h'},
{"version", 0, NULL, 'V'},
{0, 0, 0, 0}
};
while ((opt = getopt_long(argcc, argv,
"hVbcCdeF:f:I:i:kLl0:1:2:3:4:5:6:7:8:9:P:p:qRs:TUuvX",
lopts, &longind)) != -1) {
switch(opt) {
case '?':
usage();
myexit(1);
break;
case 'X':
remove_symfile_onexit = YES;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* The input fields numbers for line mode operation */
field = opt - '0';
if (strlen(optarg) > PATHLEN) {
postfatal("\
cscope: pattern too long, cannot be > \
%d characters\n", PATLEN);
}
strcpy(Pattern, optarg);
break;
case 'b': /* only build the cross-reference */
buildonly = YES;
linemode = YES;
break;
case 'c': /* ASCII characters only in crossref */
compress = NO;
break;
case 'C': /* turn on caseless mode for symbol searches */
caseless = YES;
egrepcaseless(caseless); /* simulate egrep -i flag */
break;
case 'd': /* consider crossref up-to-date */
isuptodate = YES;
break;
case 'e': /* suppress ^E prompt between files */
editallprompt = NO;
break;
case 'h':
longusage();
myexit(1);
break;
case 'k': /* ignore DFLT_INCDIR */
kernelmode = YES;
break;
case 'L':
onesearch = YES;
/* FALLTHROUGH */
case 'l':
linemode = YES;
break;
case 'v':
verbosemode = YES;
break;
case 'V':
fprintf(stderr, "%s: version %d%s\n", argv0,
FILEVERSION, FIXVERSION);
myexit(0);
break;
case 'q': /* quick search */
invertedindex = YES;
break;
case 'T': /* truncate symbols to 8 characters */
trun_syms = YES;
break;
case 'u': /* unconditionally build the cross-reference */
unconditional = YES;
break;
case 'U': /* assume some files have changed */
fileschanged = YES;
break;
case 'R':
recurse_dir = YES;
break;
case 'f': /* alternate cross-reference file */
reffile = optarg;
if (strlen(reffile) > sizeof(path) - 3) {
postfatal("\
cscope: reffile too long, cannot \
be > %d characters\n", sizeof(path) - 3);
/* NOTREACHED */
}
strcpy(path, reffile);
s = path + strlen(path);
strcpy(s, ".in");
/*coverity[overwrite_var]*/
invname = strdup(path);
strcpy(s, ".po");
/*coverity[overwrite_var]*/
invpost = strdup(path);
break;
case 'F': /* symbol reference lines file */
reflines = optarg;
break;
case 'i': /* file containing file names */
namefile = optarg;
break;
case 'I': /* #include file directory */
includedir(optarg);
break;
case 'p': /* file path components to display */
dispcomponents = atoi(optarg);
break;
case 'P': /* prepend path to file names */
prependpath = optarg;
break;
case 's': /* additional source file directory */
sourcedir(optarg);
break;
}
}
/*
* This adjusts argv so that we only see the remaining
* args. Its ugly, but we need to do it so that the rest
* of the main routine doesn't get all confused
*/
*argc = *argc - optind;
return argv + optind;
}

94
src/scanner.h Normal file
View File

@ -0,0 +1,94 @@
/*===========================================================================
Copyright (c) 2001, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
#ifndef CSCOPE_SCANNER_H
#define CSCOPE_SCANNER_H
#include <stdio.h>
#undef YYLMAX
#define YYLMAX STMTMAX + PATLEN + 1 /* scanner line buffer size */
/* cross-reference database mark characters (when new ones are added,
* update the cscope.out format description in cscope.1)
*/
#define CLASSDEF 'c'
#define DEFINE '#'
#define DEFINEEND ')'
#define ENUMDEF 'e'
#define FCNCALL '`'
#define FCNDEF '$'
#define FCNEND '}'
#define GLOBALDEF 'g'
#define INCLUDE '~'
#define MEMBERDEF 'm'
#define NEWFILE '@'
#define STRUCTDEF 's'
#define TYPEDEF 't'
#define UNIONDEF 'u'
/* other scanner token types */
#define LEXEOF 0
#define LEXERR 1
#define IDENT 2
#define NEWLINE 3
/* scanner.l global data */
extern int first; /* buffer index for first char of symbol */
extern int last; /* buffer index for last char of symbol */
extern int lineno; /* symbol line number */
extern FILE *yyin; /* input file descriptor */
extern FILE *yyout; /* output file */
extern int myylineno; /* input line number */
#ifdef USING_LEX
/* HBB 20010430: if lex is used instead of flex, have to simulate the
* private copies of yytext and yytext for the world outside scanner.l: */
/* FIXME: there should be a feature test for this! */
#if defined(__OSF1__) || defined(__sun) || defined(_AIX)
extern char yytext[];
#else
extern unsigned char yytext[];
#endif
extern int yyleng;
# define my_yytext yytext
# define my_yyleng yyleng
#else
extern char *my_yytext; /* private copy of input line */
extern size_t my_yyleng; /* ... and current length of it */
#endif
/* The master function exported by scanner.l */
int yylex(void);
void initscanner(char *srcfile);
#endif /* CSCOPE_SCANNER_H ends */

45
src/version.h Normal file
View File

@ -0,0 +1,45 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* Changing the cross-reference file part of the program version
* forces rebuilding of the cross-reference.
*/
#ifndef CSCOPE_VERSION_H
#define CSCOPE_VERSION_H
#define FILEVERSION 15 /* Initial Open Source and Linux Port */
#define FIXVERSION ".9" /* feature and bug fix version */
#endif /* CSCOPE_VERSION_H */

70
src/vp.h Normal file
View File

@ -0,0 +1,70 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/*
* VPATH assumptions:
* VPATH is the environment variable containing the view path
* where each path name is followed by ':', '\n', or '\0'.
* Embedded blanks are considered part of the path.
*/
#ifndef CSCOPE_VP_H
#define CSCOPE_VP_H
#define MAXPATH 200 /* max length for entire name */
#ifdef HAVE_CONFIG_H
# include "config.h"
#else
# define HAVE_FCNTL_H 1 /* in case of doubt, assume it's there */
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h> /* needed for O_... open flags */
#endif
#include <sys/types.h>
#include <sys/stat.h>
#if !NOMALLOC
extern char **vpdirs; /* directories (including current) in view path */
#else
#define MAXDIR 25 /* same as libVP */
#define DIRLEN 80 /* same as libVP */
extern char vpdirs[MAXDIR][DIRLEN + 1];
#endif
extern int vpndirs; /* number of directories in view path */
void vpinit(char *current_dir);
int vpopen(char *path, int oflag);
int vpaccess(char *path, mode_t amode);
#endif /* CSCOPE_VP_H */

57
src/vpaccess.c Normal file
View File

@ -0,0 +1,57 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* vpaccess - view path version of the access system call */
#include <stdio.h>
#include <unistd.h>
#include "vp.h"
#include <sys/types.h>
int
vpaccess(char *path, mode_t amode)
{
char buf[MAXPATH + 1];
int returncode;
int i;
if ((returncode = access(path, amode)) == -1 && path[0] != '/') {
vpinit(NULL);
for (i = 1; i < vpndirs; i++) {
(void) snprintf(buf, sizeof(buf), "%s/%s", vpdirs[i], path);
if ((returncode = access(buf, amode)) != -1) {
break;
}
}
}
return(returncode);
}

62
src/vpfopen.c Normal file
View File

@ -0,0 +1,62 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* vpfopen - view path version of the fopen library function */
#include <stdio.h>
#include <string.h>
#include "vp.h"
#include "global.h"
FILE *
vpfopen(char *filename, char *type)
{
char buf[MAXPATH + 1];
FILE *returncode;
int i;
if ((returncode = myfopen(filename, type)) == NULL
&& filename[0] != '/'
/* && strcmp(type, "r") == 0 */ /* HBB: this breaks if type=="rb" */
&& type[0] == 'r'
) {
vpinit(NULL);
for (i = 1; i < vpndirs; i++) {
(void) snprintf(buf, sizeof(buf), "%s/%s", vpdirs[i], filename);
if ((returncode = myfopen(buf, type)) != NULL) {
break;
}
}
}
return(returncode);
}

169
src/vpinit.c Normal file
View File

@ -0,0 +1,169 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* vpinit - initialize vpdirs or update vpdirs based on currentdir */
#include <stdio.h> /* stderr */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "vp.h"
#include "library.h"
#include "global.h"
#include "constants.h"
#if !NOMALLOC
char **vpdirs; /* directories (including current) in view path */
#else
char vpdirs[MAXDIR][DIRLEN + 1];
#define MAXVPATH (MAXDIR * (DIRLEN + 1))
#endif
int vpndirs; /* number of directories in view path */
void
vpinit(char *current_dir)
{
char *suffix; /* path from view path node */
char *vpath; /* VPATH environment variable value */
char buf[MAXPATH + 1];
int i;
char *s;
#if NOMALLOC
char *node; /* view path node */
char vpathbuf[MAXVPATH + 1];
#endif
/* if an existing directory list is to be updated, free it */
if (current_dir != NULL && vpndirs > 0) {
#if !NOMALLOC
for (i = 0; i < vpndirs; ++i) {
free(vpdirs[i]);
}
free(vpdirs);
#endif
vpndirs = 0;
}
/* return if the directory list has been computed */
/* or there isn't a view path environment variable */
if (vpndirs > 0 || (vpath = getenv("VPATH")) == NULL ||
*vpath == '\0') {
return;
}
/* if not given, get the current directory name */
if (current_dir == NULL && (current_dir = getcwd(buf, MAXPATH)) == NULL) {
(void) fprintf(stderr, "%s: cannot get current directory name\n", argv0);
return;
}
/* see if this directory is in the first view path node */
for (i = 0; vpath[i] == current_dir[i] && vpath[i] != '\0'; ++i) {
;
}
if ((vpath[i] != ':' && vpath[i] != '\0') ||
(current_dir[i] != '/' && current_dir[i] != '\0')) {
return;
}
suffix = &current_dir[i];
#if !NOMALLOC
/* count the nodes in the view path */
vpndirs = 1;
for (i = 0; vpath[i] != '\0'; ++i) {
if (vpath[i] == ':' && vpath[i + 1]) {
++vpndirs;
}
}
/* create the source directory list */
vpdirs = malloc(vpndirs * sizeof(*vpdirs));
/* don't change VPATH in the environment */
vpath = strdup(vpath);
/* split the view path into nodes */
for (i = 0, s = vpath; *s != '\0'; ++i) {
vpdirs[i] = s;
while (*s != '\0' && *++s != ':') {
if (*s == '\n') {
*s = '\0';
}
}
if (*s != '\0') {
*s++ = '\0';
}
}
/* convert the view path nodes to directories */
for (i = 0; i < vpndirs; ++i) {
s = malloc(strlen(vpdirs[i]) + strlen(suffix) + 1);
(void) strcpy(s, vpdirs[i]);
(void) strcat(s, suffix);
vpdirs[i] = s;
}
free(vpath);
#else
/* don't change VPATH in the environment */
if (strlen(vpath) > MAXVPATH) {
(void) fprintf(stderr, "%s: VPATH is longer than %d characters: %s\n", argv0, MAXVPATH, vpath);
return;
}
(void) strcpy(vpathbuf, vpath);
s = vpathbuf;
/* convert the view path nodes to directories */
while (*s != '\0') {
/* get the next node */
node = s;
while (*s != '\0' && *++s != ':') {
if (*s == '\n') {
*s = '\0';
}
}
if (*s != '\0') {
*s++ = '\0';
}
/* ignore a directory that is too long */
if (strlen(node) + strlen(suffix) > DIRLEN) {
(void) fprintf(stderr, "%s: VPATH directory is longer than %d characters: %s%s\n", argv0, DIRLEN, node, suffix);
}
else if (vpndirs >= MAXDIR) {
(void) fprintf(stderr, "%s: VPATH has more than %d nodes\n", argv0, vpndirs);
return;
}
else {
/* create the view path directory */
(void) strcpy(vpdirs[vpndirs], node);
(void) strcat(vpdirs[vpndirs], suffix);
++vpndirs;
}
}
#endif
}

60
src/vpopen.c Normal file
View File

@ -0,0 +1,60 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* vpopen - view path version of the open system call */
#include <stdio.h>
#include "global.h"
#include "vp.h"
#define OPENFLAG_READ 0
int
vpopen(char *path, int oflag)
{
char buf[MAXPATH + 1];
int returncode;
int i;
if ((returncode = myopen(path, oflag, 0666)) == -1 && path[0] != '/' &&
oflag == OPENFLAG_READ) {
vpinit(NULL);
for (i = 1; i < vpndirs; i++) {
(void) snprintf(buf, sizeof(buf), "%s/%s", vpdirs[i], path);
if ((returncode = myopen(buf, oflag, 0666)) != -1) {
break;
}
}
}
return(returncode);
}