CScout has already been applied on
CScout as a source code analyzer can:
More importantly, CScout helps you in refactoring code by identifying dead objects to remove, and automatically performing accurate global rename identifier refactorings, and various function argument refactorings. CScout will automatically rename identifiers
example
directory and typing
../bin/cscout awk.cs
(under Unix), or
..\bin\cscout awk.cs
(under Windows).
For a more structured walkthrough, read on.
Consider the following C file, idtest.c
#define getval(x) ((x).val) struct number { int id; double val; } n; struct character { int id; char val; } c; static int val; main(int argc, char *argv[]) { int val; if (argc > 2) goto val; return getval(n) + getval(c); val: return 0; }Even though the file forms a contrived example, it will serve us to illustrate the basic concepts behind CScout's operation. Consider what would the correct renaming of one of the identifiers named
val
entail.
CScout will help us to automate this process.
Although, we are dealing with a single file we need to specify its processing
within the context of a workspace.
In a realistic concept a workspace will specify how numerous projects
consisting of multiple files will be processed; think of a workspace
as a collection of Makefiles.
CScout will operate across the many source files and related
executables in the same way as it operates on our example
file idtest.c
.
A workspace specifies the set of files on which CScout will operate. Each workspace consists of a number of projects; a project is a set rules for linking together C files to form an executable. The workspace definition file is in our case very simple:
workspace example { project idtest { file idtest.c } }Our workspace, named
example
, consists of a single
project, named idtest
, that consists of a single
C source file, idtest.c
.
Our first step will be to transform the declarative workspace definition file into a processing script: a file with imperative processing directives that CScout will handle.
prompt> cswc example.csw >example.cWe then invoke CScout on the processing script (the compiled workspace definition file)
example.c
.
prompt> cscout example.c Processing workspace example Processing project idtest Processing file idtest.c Done processing file idtest.c Done processing project idtest Done processing workspace example Post-processing our_path/example.c Post-processing our_path/idtest.c Processing identifiers 100% We are now ready to serve you at http://localhost:8081The output of CScout is quite verbose; when processing a large source code collection, the messages will serve to assure us that progress is being made.
The primary interface of CScout is Web-based, so once our files have been processed, we fire-up our Web browser and navigate to the CScout's URL. We leave the CScout process running; its job from now on will be to service the pages we request and perform the operations we specify.
Our browser will show us a page like the following:
In our first example we will only rename an identifier, but as is evident from the page's links CScout provides us with many powerfull tools.
By navigating through the links All files, idtest.c, and Source code with identifier hyperlinks we can see the source code with each recognised identifier marked as a hyperlink:
Source Code With Identifier Hyperlinks: your_path/idtest.c(Use the tab key to move to each marked element.) #define getval(x) ((x).val)
|
val
(in the macro definition)
we are taken to a page specifying the identifier's details.
There we can specify the identifier's new name, e.g. value
.
Identifier: val |
val
matches marked as
hyperlinks:
Identifier val: C:\dds\src\Research\cscout\refactor\idtest.c(Use the tab key to move to each marked element.) #define getval(x) ((x).val)
|
val
label, the static variable, or the local variable;
each one will only affect the relevant identifiers.
Selecting the hyperlink
Exit - saving changes from the
CScout's main page will commit our changes,
modifying the file idtest.c
.
You install CScout in eight steps:
cscout
, cswc
and csmake
(under Unix) or
cscout.exe
, cswc.bat
and csmake.bat
(under Windows)
from the bin
directory
into a directory that is part of your path.
Under Unix /usr/local/bin
is a common suitable choice.
Under Windows C:\WINNT\system32
is a location
you could use, if your system is not better organized.
cswc.bat
and csmake.bat
to point to the directory where you installed the corresponding file.
etc
to the
final installation place you prefer (renaming it, if you wish),
and arrange for the environment variable CSCOUT_HOME
to point to it.
As an example, under Unix you would probably have the directory
installed as /usr/local/etc/cscout
.
Under Unix, you can permanently set the CSCOUT_HOME
environment variable by editing a file named
.profile
(sh and derivative shells)
or
.login
(csh and derivative shells)
in your home directory.
Under Windows (NT, 2000, XP, and later editions),
you can set environment variables through an option in:
Control Panel - System - Advanced - Environment Variables,
on Windows-95/98/Me you will need to edit the file c:\autoexec.bat
.
Alternativelly, the contents of the directory etc
will be searched in $HOME/.cscout
and
the current directory's .cscout
directory.
cscout_incs.PLATFORM
and
cscout_defs.PLATFORM
(where PLATFORM is the operating system and the compiler
that most closely resemble your setup)
as cscout_incs.h
and cscout_defs.h
.
In most cases you want CScout to process your code using the include files of the compiler you are normally using. This will allow CScout to handle programs using the libraries and facilities available in your environment (e.g. Unix system calls or the Windows API). If your programs are written in ANSI C and do not use any additional include files, you can use the .GENERIC files and rely on the include files supplied with the CScout distribution.
.GENERIC
files
copy the include
directory to an appropriate location
(e.g. /usr/local/include/cscout
under Unix).
cscout_incs.h
to specify the location
where your compiler's (or the generic) include files reside.
.GENERIC
file set and
add suitable definitions to sidestep the problems caused by the
extensions your compiler supports.
As an example,
if your compiler supports a quad_double
type and associated
keyword with semantics roughly equivalent to double
you would add a line in cscout_incs
:
#define quad_double doubleHave a look in the existing
cscout_defs
files to see
what might be required.
cscout_incs.h
and cscout_defs.h
to match you environment;
you can directly use the supplied file cscout_defs.GENERIC_GCC
.
Tailoring your project's build process to generate a CScout processing script is a final possibility. Here you gain maximum flexibility and integration with the project build system at the expense of having to modify the project's build procedure. If the project is relatively large and the build procedure is under your control, this may be an option worth investigating.
Workspace definition files are line-oriented and organized around C-like blocks. Comments are introduced using the # character. Consider the following simple example:
workspace echo { project echo { cd "/usr/src/bin/echo" file echo.c } }The above workspace definition consists of a single program (echo), which in turn consists of a single source file (echo.c).
See how we could expand this for two more programs, all residing in
our system's /usr/src/bin
directory:
workspace bin { cd "/usr/src/bin" ro_prefix "/usr/include" project cp { cd "cp" file cp.c utils.c } project echo { cd "echo" file echo.c } project date { cd "date" file date.c } }In the new
bin
workspace we have factored out the common
source directory at the workspace level
(cd "/usr/src/bin"
), so that each project only
specifies its directory relatively to the workspace directory
(e.g. cd "date"
).
In addition, we have specified that files residing in the
directory /usr/include
are to be considered read-only
(ro_prefix "/usr/include"
).
This is typically needed when the user running CScout
has permission to modify the system's include files.
Specifying one or more read-only prefixes allows CScout to
distinguish between application identifiers and files, which you can
modify, and system identifiers and files, which should not be changed.
The CScout workspace compiler cswc will read from its standard input, or from the file(s) specified on its command line, a workspace definition and produce on its standard output a processing script: a C-like file that CScout can process. You will have to redirect the cswc output to a file that will then get passed as an argument to CScout.
WORKSPACE: workspace NAME { WORKSPACE_ELEMENT ... } WORKSPACE_ELEMENT: SCOPED_COMMAND GLOBAL_COMMAND cd "PATH" PROJECT SCOPED_COMMAND: ipath "PATH" define MACRO define MACRO VALUE GLOBAL_COMMAND: ro_prefix "PATH" readonly "FILENAME" PROJECT: project NAME { PROJECT_ELEMENT ... } PROJECT_ELEMENT: SCOPED_COMMAND cd "PATH" DIRECTORY FILE DIRECTORY: directory PATH { DIRECTORY_ELEMENT ... } DIRECTORY_ELEMENT: SCOPED_COMMAND FILE FILE: file FILENAME ... file "FILENAME" { FILESPEC ... } FILESPEC: SCOPED_COMMAND cd "PATH" readonlyThe above grammar essentially specifies that a workspace consists of projects, which consist of files or files in a directory. At the workspace level you can specify files and directories that are to be considered read-only using the
readonly
and
ro_prefix
commands.
Both commands affect the complete workspace.
The scoped commands (define
and ipath
)
are used to specify macro definitions and the include path.
Their scope is the block they appear in; when you exit the block
(project, directory, or file) their definition is lost.
You can therefore define a macro or an include path for the complete workspace,
a specific project, files within a directory, or a single file.
The syntax of the define
command is the same as the one
used in C programs.
The cd
command is also scoped; once you exit the block
you return to the directory that was in effect in the outside block.
Within a project you can either specify individual files using
the file
command, or express a grouping of files in
a directory using the directory
command.
The directory
command's name is the directory where a
group of files resides and serves as an implicit cd
command for the files it contains.
Finally, files can be either specified directly as arguments to the
file
command, or file
can be used to start
a separate block.
In the latter case the argument of file
is the file name
to process; the block can contain additional specifications
(scoped commands or the readonly
command without an
argument) for processing that file.
The following workspace definition was used for processing the apache web server and includes most of the features and formulations we discussed.
workspace apache { cd "/usr/local/src/apache/src" ro_prefix "/usr/local/src/apache/src/include/ap_config" # Global project definitions define HTTPD_ROOT "/usr/local/apache" define SUEXEC_BIN "/usr/local/apache/bin/suexec" define SHARED_CORE_DIR "/usr/local/apache/libexec" define DEFAULT_PIDLOG "logs/httpd.pid" define DEFAULT_SCOREBOARD "logs/httpd.scoreboard" define DEFAULT_LOCKFILE "logs/httpd.lock" define DEFAULT_XFERLOG "logs/access_log" define DEFAULT_ERRORLOG "logs/error_log" define TYPES_CONFIG_FILE "conf/mime.types" define SERVER_CONFIG_FILE "conf/httpd.conf" define ACCESS_CONFIG_FILE "conf/access.conf" define RESOURCE_CONFIG_FILE "conf/srm.conf" define AUX_CFLAGS define LINUX 22 define USE_HSREGEX define NO_DL_NEEDED # Give project-specific directory and include path properties project gen_uri_delims { cd "main" ipath "../os/unix" ipath "../include" file gen_uri_delims.c } # Alternative formulation; specify per-file properties project gen_test_char { file gen_test_char.c { cd "main" ipath "../os/unix" ipath "../include" } } # httpd executable; specify directory-based properties project httpd { directory main { ipath "../os/unix" ipath "../include" file alloc.c buff.c http_config.c http_core.c file http_log.c http_main.c http_protocol.c file http_request.c http_vhost.c util.c util_date.c file util_script.c util_uri.c util_md5.c rfc1413.c } directory regex { ipath "." ipath "../os/unix" ipath "../include" define POSIX_MISTAKE file regcomp.c regexec.c regerror.c regfree.c } directory os/unix { ipath "../../os/unix" ipath "../../include" file os.c os-inline.c } directory ap { ipath "../os/unix" ipath "../include" file ap_cpystrn.c ap_execve.c ap_fnmatch.c ap_getpass.c file ap_md5c.c ap_signal.c ap_slack.c ap_snprintf.c file ap_sha1.c ap_checkpass.c ap_base64.c ap_ebcdic.c } directory modules/standard { ipath "../../os/unix" ipath "../../include" file mod_env.c mod_log_config.c mod_mime.c file mod_negotiation.c mod_status.c mod_include.c file mod_autoindex.c mod_dir.c mod_cgi.c mod_asis.c file mod_imap.c mod_actions.c mod_userdir.c file mod_alias.c mod_access.c mod_auth.c mod_setenvif.c } directory . { ipath "./os/unix" ipath "./include" file modules.c buildmark.c } } }
make cleanThen, instead of running
make
on the project's top-level
directory you run csmake
.
When the build process has finished, csmake will leave in
the directory where you started it a CScout processing script
named make.cs
.
csmake has been used out-of-the-box to run CScout on
the Linux kernel version 2.6.11.4 and the Apache httpd version 2.2.3.
It has also been used to process the FreeBSD 7-CURRENT kernel under
its three Tier-1 architecture configurations by cross-compiling each
configuration separately and merging the resulting CScout
processing scripts.
This is the shell script that did the job.
for a in amd64 i386 sparc64 do ( cd sys/$a/conf/ make LINT config LINT ) export MAKEOBJDIRPREFIX=/home/dds/src/fbsd-head/obj/$a csmake buildkernel TARGET_ARCH=$a KERNCONF=LINT mv make.cs make.$a.cs done cat make.*.cs >all.cs sed -n 's/#pragma process "\(.*hack.c\)"/\1/p' all.cs | xargs touch cscout all.cs
#pragma
preprocessor directives.
CScout uses the following pragmas:
#pragma echo "STRING"
Example:
#pragma echo "Processing workspace date\n"
#pragma ro_prefix "STRING"
Example:
#pragma ro_prefix "C:\gcc"
#pragma project "STRING"
Example:
#pragma project "date"
#pragma block_enter
block_enter
will enter the project scope
(linkage unit); the second encountered nested
block_enter
will enter the file scope
(compilation unit).
#pragma block_exit
block_enter
pragmas should match the number of
block_exit
pragmas and there should never be more
than two block_enter
pragmas in effect.
#pragma process "STRING"
Example:
#pragma process "date.d"
#pragma pushd "STRING"
Example:
#pragma pushd "cp"
#pragma popd
pushd
pragmas should match the number of
popd
pragmas.
#pragma includepath "STRING"
Example:
#pragma includepath "/usr/lib/gcc-lib/i386-redhat-linux/2.96/include"
#pragma clear_include
#pragma clear_defines
#define
C preprocessor directive.
// workspace bin #pragma echo "Processing workspace bin\n" #pragma ro_prefix "/usr/include" #pragma echo "Entering directory /usr/src/bin" #pragma pushd "/usr/src/bin" // project date #pragma echo "Processing project date\n" #pragma project "date" #pragma block_enter #pragma echo "Entering directory date" #pragma pushd "date" // file date.c #pragma echo "Processing file date.c\n" #pragma block_enter #pragma clear_defines #pragma clear_include #include "/home/dds/src/cscout/cscout_defs.h" #include "/home/dds/src/cscout/cscout_incs.h" #pragma process "date.c" #pragma block_exit #pragma echo "Done processing file date.c\n" #pragma echo "Exiting directory date\n" #pragma popd #pragma block_exit #pragma echo "Done processing project date\n" #pragma echo "Exiting directory /usr/src/bin\n" #pragma popd #pragma echo "Done processing workspace bin\n"
config LINT
make depend
)
and compile
(make
).
This step is used to create all automatically generated C and header files.
Also during this step note the include path used, in order to provide
CScout with the same specification.
rm *.o
).
.include "$S/conf/kern.pre.mk" The code below was added after the line above NORMAL_C= echo '\#pragma echo "Processing file ${.IMPSRC}\n"' >>kernel.cs ;\ echo '\#pragma block_enter' >>kernel.cs ;\ echo '\#pragma clear_defines' >>kernel.cs ;\ echo '\#pragma clear_include' >>kernel.cs ;\ echo '\#include "cscout_defs.h"' >>kernel.cs ;\ for i in $(INCLUDES) ; \ do \ case $$i in \ -nostdinc) continue ;; \ -I-) continue ;; \ esac ; \ i=`echo $$i | sed 's/-I//'` ; \ echo '\#pragma includepath "'$$i'"' >>kernel.cs ; \ done ; \ echo '\#define _KERNEL 1' >>kernel.cs ;\ echo '\#pragma process "opt_global.h"' >>kernel.cs ;\ echo '\#pragma process "${.IMPSRC}"' >>kernel.cs ;\ echo '\#pragma block_exit' >>kernel.cs ;\ echo '\#pragma echo "Done processing file ${.IMPSRC}\n"' >>kernel.cs
cscout_incs.h
file for each different architecture.
#pragma echo "Processing workspace FreeBSD kernel\n" #pragma echo "Entering directory sys/i386/compile/LINT\n" #pragma pushd "sys/i386/compile/LINT" #pragma echo "Processing project i386\n" #pragma project "i386" #pragma block_enter #include "kernel.cs" #pragma echo "Exiting directory sys/i386/compile/LINT\n" #pragma popd #pragma echo "Done processing project i386\n" #pragma block_exit #pragma echo "Entering directory sys/amd64/compile/GENERIC\n" // [...] // and so on for all architectures // [...] #pragma echo "Exiting directory sys/sparc64/compile/LINT\n" #pragma popd #pragma echo "Done processing project sparc64\n" #pragma block_exitNote that the
block_enter
and
block_exit
pragmas
are furnished by this top-level file.
CScout HomeFile MetricsWritable FilesNumber of files: 4310
|
make.cs
script generated by csmake.
It will serially process each project and directory parsing the
corresponding files specified in the workspace definition file,
and then process once more each one of the files examined to establish
the location of the identifiers.
Note that the bulk of the work is performed in the first pass.
During the first pass CScout may report warnings, errors,
and fatal errors.
Fatal errors will terminate processing, all other errors may result in an
incorrect analysis of the particular code fragment.
CScout only checks the code to the extend needed to perform its
analysis; CScout will hapily process many illegal constructs.
The following lines illustrate the output of CScout
when run on the bin
workspace.
Entering directory /usr/src/bin Processing project cp Entering directory cp Processing file cp.c Done processing file cp.c Processing file utils.c Done processing file utils.c Exiting directory cp Done processing project cp Processing project echo Entering directory echo Processing file echo.c Done processing file echo.c Exiting directory echo Done processing project echo Processing project date Entering directory date Processing file date.c Done processing file date.c Exiting directory date Done processing project date Exiting directory /usr/src/bin Done processing workspace bin Post-processing /home/dds/src/cscout/cscout_defs.h Post-processing /home/dds/src/cscout/cscout_incs.h Post-processing /usr/home/dds/src/cscout/bin.c Post-processing /usr/include/ctype.h Post-processing /usr/include/err.h Post-processing /usr/include/errno.h Post-processing /usr/include/fcntl.h Post-processing /usr/include/fts.h Post-processing /usr/include/limits.h Post-processing /usr/include/locale.h Post-processing /usr/include/machine/ansi.h Post-processing /usr/include/machine/endian.h Post-processing /usr/include/machine/limits.h Post-processing /usr/include/machine/param.h Post-processing /usr/include/machine/signal.h Post-processing /usr/include/machine/trap.h Post-processing /usr/include/machine/types.h Post-processing /usr/include/machine/ucontext.h Post-processing /usr/include/runetype.h Post-processing /usr/include/stdio.h Post-processing /usr/include/stdlib.h Post-processing /usr/include/string.h Post-processing /usr/include/sys/_posix.h Post-processing /usr/include/sys/cdefs.h Post-processing /usr/include/sys/inttypes.h Post-processing /usr/include/sys/param.h Post-processing /usr/include/sys/signal.h Post-processing /usr/include/sys/stat.h Post-processing /usr/include/sys/syslimits.h Post-processing /usr/include/sys/time.h Post-processing /usr/include/sys/types.h Post-processing /usr/include/sys/ucontext.h Post-processing /usr/include/sys/unistd.h Post-processing /usr/include/sysexits.h Post-processing /usr/include/syslog.h Post-processing /usr/include/time.h Post-processing /usr/include/unistd.h Post-processing /vol/src/bin/cp/cp.c Post-processing /vol/src/bin/cp/extern.h Post-processing /vol/src/bin/cp/utils.c Post-processing /vol/src/bin/date/date.c Post-processing /vol/src/bin/date/extern.h Post-processing /vol/src/bin/date/vary.h Post-processing /vol/src/bin/echo/echo.c Processing identifiers 100% We are now ready to serve you at http://localhost:8081After processing your files CScout will start operating as a Web server. At that point you must open a Web browser and connect to the location printed on its output. From that point onward your CScout contact is the Web browser interface; only fatal errors and progress indicators will appear on CScout's standard output. Depending on the version of CScout you have, you may also be able to perform some operations over the network. However, since CScout operates as a single-threaded process, you may experience delays when another user sends a complex query.
When CScout processes a large project it will contact our server over the Web to say hello. The unsupported version will also send us the identifier and file metrics of the project it has processed and register your CScout project for public browsing over the Web (the unsupported version is licensed only for use on free open-source software).
-E
command-line argument.
The -E
option will orchestrate both programs to act as
a simple C preprocessor.
The workspace definition file you should use in such a case should only
specify a single file.
The corresponding output of CScout will be the file with all
preprocessor commands evaluated.
If CScout reports an error in a place where a macro is invoked,
you can examine the preprocessed output to see the result of the macro
execution.
During the CScout trials, this feature often located the use
of nonstandard compiler extensions, that were hidden inside header files.
To search for the corresponding error location in the postprocessed file use the
name of a nearby identifier as a bookmark, since the line numbers will not
match and CScout will not generate #line
directives.
Alternatively, you can rerun CScout on the preprocessed file.
-c
command-line option will cause CScout to
immediately exit after processing the specified file.
The -c
option is often used in conjunction with the
-r
option.
The -r
command-line option instructs CScout to
report all superfluously included header files and identifiers that are
either unused or wrongly scoped.
Although it is easy to recognise when a header file must be included
(if you do not follow the specification of the respective API,
a compiler's error message will act as a reminder)
detecting when an included header is no longer needed is a lot more difficult.
Thus, as code changes, entire files are duplicated as source code templates,
and functions are moved to different files, header files that were once
needed may no longer be required.
Their existence can confuse the programmers reading the code
(why is this header file included?) and unnecessarily burden the compilation
process.
CScout can detect such files by keeping track of dependencies across
files, and report included files that are not required.
The following is an example of CScout's output:
$ cscout -rc awk.cs Processing workspace awk Processing project awk Entering directory awk Processing file awkgram.y Done processing file awkgram.y [...] Processing file tran.c Done processing file tran.c Exiting directory awk Done processing project awk Done processing workspace awk Post-processing /home/dds/src/cscout/example/.cscout/cscout_defs.h [...] Post-processing /home/dds/src/cscout/include/time.h Processing identifiers 100% /home/dds/src/cscout/example/awk/run.c:84: jexit: unused project scoped writable identifier [...] /home/dds/src/cscout/example/awk/awkgram.y:93: LASTTOKEN: unused file scoped writable identifier /home/dds/src/cscout/example/awk/awk.h:152: CFREE: unused writable macro [...] /home/dds/src/cscout/example/awk/tran.c:44: CONVFMT: writable identifier should be made static /home/dds/src/cscout/example/awk/lib.c:36: file: writable identifier should be made static [...] /home/dds/src/cscout/example/awk/lib.c:33: unused included file /home/dds/src/cscout/example/awk/ytab.h /home/dds/src/cscout/example/awk/main.c:29: unused included file /home/dds/src/cscout/include/ctype.h /home/dds/src/cscout/example/awk/main.c:35: unused included file /home/dds/src/cscout/example/awk/ytab.h /home/dds/src/cscout/example/awk/tran.c:32: unused included file /home/dds/src/cscout/example/awk/ytab.hNotice that there are two types of unused include files:
#include
directives for the
directly included files.
The files that are indirectly included and unused are a lot more tricky.
They are brought into your file's compilation by the inclusion of another
file.
Even if you have control over the header file that included them
and even if your file has no use for their contents, another file
may require them, so in most cases it is best not to mess with those
files.
Finally note that it is possible to construct pathological examples of
include files that CScout will not detect as being required.
These will contain just parts of a statement or declaration that can not
be related to the file including them (e.g. a single operator, or a comma):
/* Main file main.c */ main(int argc #include "comma.h" char *argv[]) { } /* File comma.h */ ,Although such a construct is legal C it is not used in practice.
Recently CScout processed a 190KLOC project that is under active development since 1989. The project consists of 231 files, containing 5249 include directives. Following CScout's analysis 765 include directives from 178 files were removed, without a single problem.
First of all, the preprocessor token concatenation feature can result in C identifiers that are composed of multiple CScout identifiers. Consider the following example, which uses a macro to define a number of different functions. (Yes, I am familiar with the C++ templates, this is just an example.)
#define typefun(name, type, op) \ type type ## _ ## name(type a, type b) { return a op b; } typefun(add, int, +) typefun(sub, int, -) typefun(mul, int, *) typefun(div, int, /) typefun(add, double, +) typefun(sub, double, -) typefun(mul, double, *) typefun(div, double, /) main() { printf("%d\n", int_add(5, 4)); printf("%g\n", double_mul(3.14, 2.0)); }In the CScout environment the
int_add
C identifier is
actually composed of three separate parts:
int
_
add
int
identifier into integer
would change it in five different places: the argument to the four
typefun
macro invocations, and the part of int_add
.
In addition, preprocessor macro definitions can confuse the notion of the C scope, bringing together scopes that would be considered separate in the context of the C language-proper. Consider the following (slightly contrived) example:
struct foo { int foo; }; struct bar { int foo; }; #define getpart(tag, name) (((struct tag *)p)->name) #define getfoo(var) (var.foo) #define get(name) (name(0) + ((struct name *)p)->name) #define conditional(x) do {if (!x(0)) goto x; return x(0);} while(0) int foo(void *p) { struct foo f; struct bar b; foo: if (p && getpart(foo, foo)) return getpart(bar, foo); else if (getfoo(f)) return get(foo); else if (getfoo(b)) conditional(foo); else return 0; }The identifier
foo
is occuring in a number of different
scopes:
foo
identifier,
CScout will change all the instances marked below,
in order to obtain a program that has the same meaning as the original
one.
Identifier foo: test.c(Use the tab key to move to each marked element.) struct foo {
|
#define macro() middlemacro() #define middlemacro() innemacro() #define innemacro() function1() function1() {} function2() {} main() { macro(); function2(); function3(); printf("Hello"); }The corresponding call graph is as follows:
Note that in CScout functions are separate entities from identifiers. The name of a function can consist of multiple identifiers; an identifier can exist in more than one function names.
For instance,
the page for the _
(underscore) identifier in the
typefun
macro example we saw earlier
will appear as follows.
Identifier: _CScout 2.0 - 2004/07/31 12:37:12 |
Note how each function name is composed of three separate parts,
and that this instance of the _
identifier occurs in
8 different function names.
One important feature of CScout concerning files has to do with the handling of files that are exact copies of each other. These may occur in the building of a large system for the sake of convenience; for example, one header file may be copied to various parts of the source code tree. CScout will locate identical files and group them together when reporting a file's details. Identifiers occuring in the same position of two identical files are considered equivalent; if you change the name of one of them the name of the other will also change. Moreover, when CScout reports unused identifiers it takes into account uses of an identifier from all instances of the identical files, not just one of them.
File-spanning Writable IdentifiersMatching IdentifiersElements 1 to 20 of 416. |
Also note that often a query's results are split into pages. The program's options allow you to specify how many elements you want to see on each page. Keep in mind that some browsers may choke on huge pages, so keep this number down to a reasonable number (say below 1000). You can navigate between result pages using the links at the bottom of each result page page. The link titled all will present all the query's results. It is most useful as a way to save all the query's results into a file, using a browser command like Save Link Target As ...
We will examine CScout's functionality using as an
example the bin
workspace we presented in the previous section.
File: /home/user/src/cscout/example/awk/main.cDetails
Listings
Include Files
Metrics
CScout |
You can view a file's source code in five different forms:
360 #if defined(__GNUC__) && defined(__STDC__) 361 static __inline int __sputc(int _c, FILE *_p) { 362 if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n')) 363 return (*_p->_p++ = _c); 364 else 365 return (__swbuf(_c, _p)); 366 } 367 #else 368 /* 369 * This has been tuned to generate reasonable code on the vax using pcc. 370 */ 371 #define __sputc(c, p) \ 372 (--(p)->_w < 0 ? \ 373 (p)->_w >= (p)->_lbfsize ? \ 374 (*(p)->_p = (c)), *(p)->_p != '\n' ? \ 375 (int)*(p)->_p++ : \ 376 __swbuf('\n', p) : \ 377 __swbuf((int)(c), p) : \ 378 (*(p)->_p = (c), (int)*(p)->_p++)) 379 #endif 380 |
int copy_fifo(from_stat, exists) struct stat *from_stat; int exists; { if (exists && unlink(to.p_path)) { warn("unlink: %s", to.p_path); return (1); } if (mkfifo(to.p_path, from_stat->st_mode)) { warn("mkfifo: %s", to.p_path); return (1); } return (pflag ? setfile(from_stat, 0) : 0); } |
int copy_fifo(from_stat, exists) struct stat *from_stat; int exists; { if (exists && unlink(to.p_path)) { warn("unlink: %s", to.p_path); return (1); } if (mkfifo(to.p_path, from_stat->st_mode)) { warn("mkfifo: %s", to.p_path); return (1); } return (pflag ? setfile(from_stat, 0) : 0); } |
#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) int digittoint __P((int)); int isascii __P((int)); int isblank __P((int)); int ishexnumber __P((int)); int isideogram __P((int)); int isnumber __P((int)); int isphonogram __P((int)); int isrune __P((int)); int isspecial __P((int)); int toascii __P((int)); #endif __END_DECLS #define __istype(c,f) (!!__maskrune((c),(f))) #define isalnum(c) __istype((c), _CTYPE_A|_CTYPE_D) #define isalpha(c) __istype((c), _CTYPE_A) #define iscntrl(c) __istype((c), _CTYPE_C) #define isdigit(c) __isctype((c), _CTYPE_D) /* ANSI -- locale independent */ #define isgraph(c) __istype((c), _CTYPE_G) #define islower(c) __istype((c), _CTYPE_L) #define isprint(c) __istype((c), _CTYPE_R) #define ispunct(c) __istype((c), _CTYPE_P) #define isspace(c) __istype((c), _CTYPE_S) #define isupper(c) __istype((c), _CTYPE_U) #define isxdigit(c) __isctype((c), _CTYPE_X) /* ANSI -- locale independent */ #define tolower(c) __tolower(c) #define toupper(c) __toupper(c) |
File MetricsWritable FilesNumber of elements: 14
Read-only FilesNumber of elements: 14
CScout |
All Files
You can bookmark this page to save the respective query CScout 1.6 - 2003/06/04 15:14:51 |
Read-only Files
You can bookmark this page to save the respective query CScout 2.0 - 2004/07/31 12:37:12 |
Writable Files
You can bookmark this page to save the respective query CScout 1.6 - 2003/06/04 15:14:51 |
static
) identifiers, but
detecting global identifiers is more tricky, since it requires
processing of all files that will be linked together.
The restriction to writable identifiers will filter-out noise
generated through the use of the system's library functions.
In our example, the following list is generated:
Files Containing Unused Project-scoped Writable IdentifiersMatching Files
You can bookmark this page to save the respective query CScout 2.0 - 2004/07/31 12:37:12 |
tab
to go to each hyperlink.
In our example the identifier will appear as follows:
void setthetime(fmt, p, jflag, nflag) const char *fmt; register const char *p; int jflag, nflag; { register struct tm *lt; struct timeval tv; const char *dot, *t; int century; |
setthetime
is declared as
static
, but not defined as such.)
static
) unused writable identifiers.
Although some modern compilers can detect file-local
identifiers, they fail to detect macros and some types of
variable declarations.
The CScout query is more general and can be more reliable.
The restriction to writable identifiers will filter-out noise
generated through the use of the system's library functions.
In our example, the following list is generated:
Files Containing Unused File-scoped Writable IdentifiersMatching Files
You can bookmark this page to save the respective query CScout 2.0 - 2004/07/31 12:37:12 |
copyright
and the rcsid
identifiers.
#ifndef lint static char const copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)echo.c 8.1 (Berkeley) 5/31/93"; #endif static const char rcsid[] = "$FreeBSD: src/bin/echo/echo.c,v 1.8.2.1 2001/08/01 02:33:32 obrien Exp $"; #endif /* not lint */ |
#ifdef
'd out.
In our example, the result set only contains the processing script (the compiled workspace definition file).
Writable .c Files Without Any StatmentsYou can bookmark this page to save the respective query CScout 1.6 - 2003/06/04 15:14:51 |
#pragma
commands)
to drive the CScout's source code analysis.
In our case the results are:
Writable Files Containing Unprocessed Lines
You can bookmark this page to save the respective query CScout 2.0 - 2004/07/31 12:37:12 |
In our case the results are:
Writable Files Containing Strings
You can bookmark this page to save the respective query CScout 1.6 - 2003/06/04 15:14:51 |
#include
invocations.
This query can be used to find files that break such a guideline.
As usual, read-only system files are excluded; these typically
use recursive #include
invocations as a matter of course.
In our example, the result is:
Writable .h Files With #include directivesYou can bookmark this page to save the respective query CScout 1.6 - 2003/06/04 15:14:51 |
You specify the query through the following form:
File QueryCScout |
You start by specifying whether the file should be
writable (i.e. typically part of your application)
and/or
readable (i.e. typically part of the compiler or system).
Next come a series of metrics CScout collects for each
file.
For each metric (e.g. the number of comments) you can specify
an operator ==, !=, <
or >
and a number
to match that metric against.
Thus to locate files without any comments you would specify
Number of block comments ==
0.
On the left of each metric you can specify whether that metric will be used to sort the resulting file list. In that case, the corresponding number will appear together with each file listed. A separate option allows you to specify that files should be sorted in the reverse order.
You can request to see files matching any of your specifications (Match any of the above) or to see files matching all your specifications (Match all of the above).
Sometimes you may only want to search in a subset of files; you can then specify a regular expression that filenames should match against (File names should match RE).
Finally, you can also specify a title for your query. The title will then appear on the result document annotating the results, and will also provide you with a sensible name when creating a bookmark to it.
static
within a file
will not interfere with identifiers outside that scope.
Thus, the following example will print 3 and not 7.
int i = 3; foo() { int i = 7; } main() { foo(); printf("%d\n", i); }CScout analyzes and stores each identifier's scope performing substitutions accordingly.
In addition, C also partitions a program's identifiers into four namespaces. Identifiers in one namespace, are also considered different from identifiers in another. The four namespaces are:
struct/union/enum
struct/union
(actually a separate namespace is assigned
to each struct/union
)
id
identifier instances are
different:
/* structure tag */ struct id { int id; /* structure member */ }; /* Different structure */ struct id2 { char id; /* structure member */ }; /* ordinary identifier */ id() { id: /* label */ }Furthermore, macro names and the names of macro formal arguments also live in separate namespaces within the preprocessor.
Normally when you want to locate or change an identifier name, you only consider identifiers in the same scope and namespace. Sometimes however, a C preprocessor macro can semantically unite identifiers living in different namespaces, so that changes in one of them should be propagated to the others. The most common case involves macros that access structure members.
struct s1 { int id; } a; struct s2 { char id; } b; #define getid(x) ((x)->id) main() { printf("%d %c", getid(a), getid(b)); }In the above example, a name change in any of the
id
instances should be propagated to all others for the program to
retain its original meaning.
CScout understands such changes and will propagate any changes
you specify accordingly.
Finally, the C preprocessor's token concatenation feature can result in identifiers that should be treated for substitution purposes in separate parts. Consider the following example:
int xleft, xright; int ytop, ybottom; #define coord(a, b) (a ## b) main() { printf("%d %d %d %d\n", coord(x, left), coord(x, right), coord(y, top), coord(y, bottom)); }In the above example, replacing
x
in one of the coord
macro invocations should replace the x
part in the
xleft
and xright
variables.
Again CScout will recognize and correctly handle this code.
Identifier: copy_fileCScout 2.0 - 2004/07/31 12:37:12 |
typedef
(typedef
's belong to the ``ordinary identifier'' namespace,
but are obviously important, so CScout will tag them as such).
Finally, the identifier's page will list the writable and all files
the specific identifier appears in.
Clicking on the ``marked source'' hyperlink will display the respective
file's source code with only the given identifier marked as a hyperlink.
By pressing your browser's cp.c
source code
with the copy_file
identifier marked
would appear as follows:
case S_IFBLK: case S_IFCHR: if (Rflag) { if (copy_special(curr->fts_statp, !dne)) badcp = rval = 1; } else { if (copy_file(curr, dne)) badcp = rval = 1; } break; case S_IFIFO: if (Rflag) { if (copy_fifo(curr->fts_statp, !dne)) badcp = rval = 1; } else { if (copy_file(curr, dne)) badcp = rval = 1; } break; default: if (copy_file(curr, dne)) badcp = rval = 1; break; } |
Identifier MetricsWritable Identifiers
Read-only Identifiers
CScout |
You can use these metrics to compare characteristics of different projects, adherance to coding standards, or to identify identifier classes with abnormally short or long names. The ratio between the distinct number of identifiers and the total number of identifiers is the number of times each identifier is used. Notice the difference in our case between the read-only identifiers (which are mostly declarations) and the writable identifiers (which are actually used).
File-spanning Writable IdentifiersMatching Identifiers
PATH_T You can bookmark this page to save the respective query CScout 1.6 - 2003/06/04 15:14:51 |
Unused File-scoped Writable IdentifiersMatching Identifiers
copyright You can bookmark this page to save the respective query CScout 1.6 - 2003/06/04 15:14:51 |
Unused Writable MacrosMatching IdentifiersYou can bookmark this page to save the respective query CScout 1.6 - 2003/06/04 15:14:51 |
Identifier QueryCScout 1.16 - 2003/08/17 12:13:01 |
As an example, the following query could be used to identify
unused file-scoped writable identifiers, but excluding
the copyright
and rcsid
identifiers:
Identifier QueryCScout 1.16 - 2003/08/17 12:13:01 |
Function: format (C function)CScout |
From this page you can refactor the function's arguments (more on this in the next section) and obtain the following data.
static
, and function-like
macros.
@N
@2, @1
" will
swap their order, while specifying "@1, sizeof(@1), stdin
" as
the arguments for gets will refactor them in a form suitable for
calling fgets (if the original argument refers to a fixed-size character array).@.N
stdout, @1, @.2
" will introduce an extra first parameter, named stdout.
(Presumably the function will also be renamed to fprintf.)@+N{...}
@-N{...}
@1, @2, @+3{@3}@-3{NULL}
" will add to any
call to the function missing a third argument, a third argument with a
value of NULL.
Note that the refactorings will take place on all instances where the
identifier is found to match the function or macro.
This includes declarations and definitions
(which might require some hand-editing if arguments are introduced),
and the appearance of the name in the replacement
text of a macro, when that macro is used in a way that makes the function
match the one being refactored.
The replacements will not be performed to function calls that are executed
through a function pointer.
Two global options specify the format of the call graph and the content on each graph's node. Through these options you can obtain graphs in
calling function -> called function
Two links on the main page
(function and macro call graph, and non-static function call graph)
can give you the call graphs of the complete program.
For any program larger than a few thousand lines,
these graphs are only useful in their textual form.
In their graphical form, even with node information disabled,
they can only serve to give you a rough idea of how the program is
structured.
The following image depicts how the three different programs we
analyzed in the bin example relate to each other.
More useful are the call graphs that can be generated for individual functions. These can allow you to see what paths can possibly lead to a given function (call graph of all callers) and which functions can be reached starting from a given function.
As an example, the following diagram depicts all paths leading to the
setfile
function.
Correspondingly, the functions that can be reached starting from the
copy_file
function appears in the following diagram.
Function QueryCScout |
On the top you can specify whether each function you want listed:
As is the case in file queries,
next comes a series of metrics CScout collects for each
defined function.
For each metric (e.g. the number of comments) you can specify
an operator ==, !=, <
or >
and a number
to match that metric against.
Thus to locate functions containing goto
statement
you would specify
Number of goto statements !=
0.
On the left of each metric you can specify whether that metric will be used to sort the resulting file list. In that case, the corresponding number will appear together with each file listed. A separate option allows you to specify that files should be sorted in the reverse order.
Similarly to the identifier query, you can also specify whether the specified properties should be treated
In addition you can specify:
Global OptionsCScout |
Identifier: argcCScout 2.0 - 2004/07/31 12:37:12 |
78 fa *makedfa(const char *s, int anchor) /* returns dfa for reg expr s */
|
Windows.h
, WINDOWS.h
, and
windows.h
).
The use of the
``case-insensitive file name regular expression match''
option makes filename regular expression matches
ignore letter case thereby matching the operating system's semantics.
Read-only Files
You can bookmark this page to save the respective query |
_t
.
The following list contains our example's typedefs ordered by the last
character, making it easy to distinguish typedefs not ending
in _t
|
/home/jack/src/foo/filename.c
, you could
specify that /foo/
should be changed
into /../foo.new/
.
Note than when this option is specified the existing and new locations of the file must reside on the same drive and partition (under Windows) or file system (under Unix).
%s
placeholders.
The first is substituted by a regular expression that is associated
with the identifier for which the file is edited,
while the second is substituted with the corresponding file name.
The default string under Unix is
and under Windows
Under Windows a more sensible default could be something like
which fires off the VIM editor in a new window.
.cscout
will be created in the
current directory (if it does not already exist),
and a file named options will be written in it,
listing the options you specified.
When CScout starts-up it will attempt to load the options
file by searching in
$CSCOUT_HOME
,
$HOME/.cscout
, or
.cscout
in the current directory.
The options
file is text based and contains key-value pairs.
The order of the entries is not significant.
This is an example of an options
file.
fname_in_context: 1 sort_rev: 0 show_true: 1 show_line_number: 0 file_icase: 0 cgraph_type: s cgraph_show: n tab_width: 8
The following is an example of the identifier replacements page. You see all identifiers for which replacements have been specified. All specified replacements are originally active. If a particular replacement appears to be causing problems you can deactivate it from this page. In addition, you can change the replaced name of any of the replaced identifiers. Finally, clicking on an identifier name will lead you to the corresponding identifier page.
Identifier Replacements |
Select Active ProjectProject cp is currently selected CScout 1.6 - 2003/06/04 15:14:51 |
cscout_checkout
;
after the file is modified CScout will try to execute the
command cscout_checkin
.
Both commands will receive as their argument the full path name of the
respective file.
If commands with such names are in your path, they will be executed
performing whatever action you require.
As an example, for a file under RCS control the following commands could be used:
#!/bin/sh co -l $1
#!/bin/sh co -m 'CScout identifier name refactoring' -u $1
alignof
operator can be used on types (gcc) for
statement (C99)
restrict
qualifier and the inline
specifier (C99)
__atribute__(__unused__)
for determining which
identifiers should not be reported as unused (gcc).
//
line comments (common extension)
__asm__
blocks (gcc)
enum
lists ending with a comma (common extension)
struct/union
members (gcc, Microsoft C)
case
expression ranges (gcc).
goto
targets and the label address-of operator (gcc).
__typeof
keyword (gcc)
/##/
into
//
are then treated as a line comment (Microsoft C)
__try __except __finally __leave
keywords (Microsoft C) #include_next
preprocessor directive (gcc)
#warning
preprocessor directive (gcc)
long long
type (common extension)
__label__
) (gcc).
y
' are considered
to contain yacc source and processed accordingly.
CScout processes yacc files as follows:
y.tab.h
macro definitions.
%union
construct are defined as
members of the YYSTYPE
union
typedef
.
These are then considered to be accessed in all
%type
and the precedence specification constructs,
as well as the
explicit type specification through the $<tag>#
construct.
yyerrok
,
YYABORT
,
YYACCEPT
, etc)
are defined.
Feel free to define anything required to silence CScout
as a macro in the workspace definition file.
#define
d in the resulting C file)
and the corresponding macro definitions in the y.tab.h
file.
These are two separate macro definitions that happen to be the same.
CScout can not possibly recognise those, so if you change the
name of a terminal token in the yacc file you should also
change it in a C file where you refer to it.
CScout is designed to process well-formed modern-style yacc files. All rules must be terminated with a semicolon (apparently this is optional in the original yacc version). The accepted grammar appears below.
body: defs '%%' rules tail ; tail: /* Empty */ | '%%' c_code ; defs: /* Empty */ | defs def ; def: '%start' IDENTIFIER | '%union' '{' member_declaration_list '}' | '%{' c_code '%}' | rword name_list_declaration ; rword: '%token' | '%left' | '%right' | '%nonassoc' | '%type' ; tag: /* Empty: union tag is optional */ | '<' IDENTIFIER '>' ; name_list_declaration: tag name_number | name_list_declaration opt_comma name_number ; opt_comma: /* Empty */ | ',' ; name_number: name | name INT_CONST ; name: IDENTIFIER | CHAR_LITERAL ; /* rules section */ rules: rule | rules rule ; rule: IDENTIFIER ':' rule_body_list ';' ; rule_body_list: rule_body | rule_body_list '|' rule_body ; rule_body: id_action_list prec ; id_action_list: /* Empty */ | id_action_list name | id_action_list '{' c_code '}' ; prec: /* Empty */ | '%prec' name | '%prec' name '{' c_code '}' ; variable: '$$' | '$' INT_CONST | '$-' INT_CONST { $$ = basic(b_int); } | '$<' IDENTIFIER '>' variable_suffix { $$ = $3; } ; variable_suffix: '$' | INT_CONST | '-' INT_CONST ;
Regular expressions (``REs''), as defined in IEEE Std 1003.2 (``POSIX.2''), come in two forms: modern REs (roughly those of egrep(1); 1003.2 calls these ``extended'' REs) and obsolete REs (roughly those of ed(1); 1003.2 ``basic'' REs). CScout has adopted the use of modern (extended) REs.
A (modern) RE is one= or more non-empty= branches, separated by `|'. It matches anything that matches one of the branches.
A branch is one= or more pieces, concatenated. It matches a match for the first, followed by a match for the second, etc.
A piece is an atom possibly followed by a single= `*', `+', `?', or bound. An atom followed by `*' matches a sequence of 0 or more matches of the atom. An atom followed by `+' matches a sequence of 1 or more matches of the atom. An atom followed by `?' matches a sequence of 0 or 1 matches of the atom.
A bound is `{' followed by an unsigned decimal integer, possibly followed by `,' possibly followed by another unsigned decimal integer, always fol- lowed by `}'. The integers must lie between 0 and RE_DUP_MAX (255=) inclusive, and if there are two of them, the first may not exceed the second. An atom followed by a bound containing one integer i and no comma matches a sequence of exactly i matches of the atom. An atom fol- lowed by a bound containing one integer i and a comma matches a sequence of i or more matches of the atom. An atom followed by a bound containing two integers i and j matches a sequence of i through j (inclusive) matches of the atom.
An atom is a regular expression enclosed in `()' (matching a match for the regular expression), an empty set of `()' (matching the null string)=, a bracket expression (see below), `.' (matching any single character), `^' (matching the null string at the beginning of a line), `$' (matching the null string at the end of a line), a `\' followed by one of the characters `^.[$()|*+?{\' (matching that character taken as an ordinary character), a `\' followed by any other character= (matching that character taken as an ordinary character, as if the `\' had not been present=), or a single character with no other significance (matching that character). A `{' followed by a character other than a digit is an ordinary character, not the beginning of a bound=. It is illegal to end an RE with `\'.
A bracket expression is a list of characters enclosed in `[]'. It nor- mally matches any single character from the list (but see below). If the list begins with `^', it matches any single character (but see below) not from the rest of the list. If two characters in the list are separated by `-', this is shorthand for the full range of characters between those two (inclusive) in the collating sequence, e.g. `[0-9]' in ASCII matches any decimal digit. It is illegal= for two ranges to share an endpoint, e.g. `a-c-e'. Ranges are very collating-sequence-dependent, and portable programs should avoid relying on them.
To include a literal `]' in the list, make it the first character (fol- lowing a possible `^'). To include a literal `-', make it the first or last character, or the second endpoint of a range. To use a literal `-' as the first endpoint of a range, enclose it in `[.' and `.]' to make it a collating element (see below). With the exception of these and some combinations using `[' (see next paragraphs), all other special charac- ters, including `\', lose their special significance within a bracket expression.
Within a bracket expression, a collating element (a character, a multi- character sequence that collates as if it were a single character, or a collating-sequence name for either) enclosed in `[.' and `.]' stands for the sequence of characters of that collating element. The sequence is a single element of the bracket expression's list. A bracket expression containing a multi-character collating element can thus match more than one character, e.g. if the collating sequence includes a `ch' collating element, then the RE `[[.ch.]]*c' matches the first five characters of `chchcc'.
Within a bracket expression, a collating element enclosed in `[=' and `=]' is an equivalence class, standing for the sequences of characters of all collating elements equivalent to that one, including itself. (If there are no other equivalent collating elements, the treatment is as if the enclosing delimiters were `[.' and `.]'.) For example, if `x' and `y' are the members of an equivalence class, then `[[=x=]]', `[[=y=]]', and `[xy]' are all synonymous. An equivalence class may not= be an end- point of a range.
Within a bracket expression, the name of a character class enclosed in `[:' and `:]' stands for the list of all characters belonging to that class. Standard character class names are:
alnum digit punct alpha graph space blank lower upper cntrl print xdigitThese stand for the character classes defined in ctype(3). A locale may provide others. A character class may not be used as an endpoint of a range.
There are two special cases= of bracket expressions: the bracket expres- sions `[[:<:]]' and `[[:>:]]' match the null string at the beginning and end of a word respectively. A word is defined as a sequence of word characters which is neither preceded nor followed by word characters. A word character is an alnum character (as defined by ctype(3)) or an underscore. This is an extension, compatible with but not specified by IEEE Std 1003.2 (``POSIX.2''), and should be used with caution in soft- ware intended to be portable to other systems.
In the event that an RE could match more than one substring of a given string, the RE matches the one starting earliest in the string. If the RE could match more than one substring starting at that point, it matches the longest. Subexpressions also match the longest possible substrings, subject to the constraint that the whole match be as long as possible, with subexpressions starting earlier in the RE taking priority over ones starting later. Note that higher-level subexpressions thus take priority over their lower-level component subexpressions.
Match lengths are measured in characters, not collating elements. A null string is considered longer than no match at all. For example, `bb*' matches the three middle characters of `abbbc', `(wee|week)(knights|nights)' matches all ten characters of `weeknights', when `(.*).*' is matched against `abc' the parenthesized subexpression matches all three characters, and when `(a*)*' is matched against `bc' both the whole RE and the parenthesized subexpression match the null string.
If case-independent matching is specified, the effect is much as if all case distinctions had vanished from the alphabet. When an alphabetic that exists in multiple cases appears as an ordinary character outside a bracket expression, it is effectively transformed into a bracket expres- sion containing both cases, e.g. `x' becomes `[xX]'. When it appears inside a bracket expression, all case counterparts of it are added to the bracket expression, so that (e.g.) `[x]' becomes `[xX]' and `[^x]' becomes `[^xX]'.
The supported version of CScout features an access control list.
The list is specified in a file called acl
which
should be located in
$CSCOUT_HOME
,
$HOME/.cscout
, or
.cscout
in the current directory.
The list contains lines with IP numeric addresses prefixed by an
A
(allow)
or
D
(deny)
prefix and a space.
Matching is performed by comparing a substring of a machine's IP address
against the specified access rule.
Thus an entry such as
A 128.135.11.can be used to allow access from a whole subnet. Unfortunatelly allowing access from the IP address
192.168.1.1
will
also allow access
192.168.1.10
, 192.168.1.100
, and so on.
Allow and deny entries cannot be combined in a useful manner
since the rules followed are:
printf
)
unchanged.
Finally, run CScout with the switch -o
.
For each writable workspace file CScout will create a file ending
in .obf
that will contain the obfuscated version of its
contents.
The files are not overwritten, providing you with another countermeasure
against accidentally destroying them.
To overwrite the original source with the obfuscated one,
use the following Unix command:
find . -name '*.obf' | sed 's/\\/\//g;s/\(.*\)\.obf$/mv "\1.obf" "\1"/' | shYou can then compile the obfuscated version of your project, to verify the obfuscation's results.
-s
dialect,
where the argument specifies the SQL dialect (for example,
mysql, or postgresql).
The SQL script will appear in CScout's standard output,
allowing you to directly pipe the results into the database's
client.
For example, say the database you would want to create for your project
was called myproj
.( echo "create database myproj; use myproj ;" cscout -s mysql myproj.cs ) | mysqlFor PostgreSQL you would write:
createdb -U username myproj cscout -s postgres myproj.cs | psql -U username myprojFor HSQLDB you would write:
cscout -s hsqldb myproj.cs | java -classpath $HSQLDBHOME/lib/hsqldb/hsqldb.jar org.hsqldb.util.SqlTool --rcfile $HSQLDBHOME/lib/hsqldb/sqltool.rc mem -The direct piping allows you to avoid the overhead of creating an intermediate file, which can be very large.
Details of interdependant identifiers appearing in the workspace.
Field name | Field type | Value description |
---|---|---|
EID | INTEGER or BIGINT1 | Unique identifier key |
NAME | CHARACTER VARYING | Identifier name |
READONLY | BOOLEAN | True if it appears in at least one read-only file |
UNDEFMACRO | BOOLEAN | True if it is apparantly an undefined macro |
MACRO | BOOLEAN | True if it a preprocessor macro |
MACROARG | BOOLEAN | True if it a preprocessor macro argument |
ORDINARY | BOOLEAN | True if it is an ordinary identifier (variable or function) |
SUETAG | BOOLEAN | True if it is a structure, union, or enumeration tag |
SUMEMBER | BOOLEAN | True if it is a structure or union member |
LABEL | BOOLEAN | True if it is a label |
TYPEDEF | BOOLEAN | True if it is a typedef |
ENUM | BOOLEAN | True if it is an enumeration member |
FUN | BOOLEAN | True if it is a function name |
CSCOPE | BOOLEAN | True if its scope is a compilation unit |
LSCOPE | BOOLEAN | True if it has linkage scope |
UNUSED | BOOLEAN | True if it is not used |
File details.
Field name | Field type | Value description |
---|---|---|
FID | INTEGER | Unique file key |
NAME | CHARACTER VARYING | File name |
RO | BOOLEAN | True if the file is read-only |
NCHAR | INTEGER | Number of characters |
NCCOMMENT | INTEGER | Number of comment characters |
NSPACE | INTEGER | Number of space characters |
NLCOMMENT | INTEGER | Number of line comments |
NBCOMMENT | INTEGER | Number of block comments |
NLINE | INTEGER | Number of lines |
MAXLINELEN | INTEGER | Maximum number of characters in a line |
NSTRING | INTEGER | Number of character strings |
NULINE | INTEGER | Number of unprocessed lines |
NPPTOKEN | INTEGER | Number of preprocessed tokens |
NCTOKEN | INTEGER | Number of compiled tokens |
NPPDIRECTIVE | INTEGER | Number of C preprocessor directives |
NPPCOND | INTEGER | Number of processed C preprocessor conditionals (ifdef, if, elif) |
NPPFMACRO | INTEGER | Number of defined C preprocessor function-like macros |
NPPOMACRO | INTEGER | Number of defined C preprocessor object-like macros |
NSTATEMENT | INTEGER | Number of statements |
NCOPIES | INTEGER | Number of copies of the file |
NPFUNCTION | INTEGER | Number of defined project-scope functions |
NFFUNCTION | INTEGER | Number of defined file-scope (static) functions |
NPVAR | INTEGER | Number of defined project-scope variables |
NFVAR | INTEGER | Number of defined file-scope (static) variables |
NAGGREGATE | INTEGER | Number of complete aggregate (struct/union) declarations |
NAMEMBER | INTEGER | Number of declared aggregate (struct/union) members |
NENUM | INTEGER | Number of complete enumeration declarations |
NEMEMBER | INTEGER | Number of declared enumeration elements |
NINCFILE | INTEGER | Number of directly included files |
Instances of identifier tokens within the source code.
Field name | Field type | Value description |
---|---|---|
FID | INTEGER | File key (references FILES) |
FOFFSET | INTEGER | Offset within the file |
EID | INTEGER or BIGINT1 | Identifier key (references IDS) |
Comments in the code.
Field name | Field type | Value description |
---|---|---|
FID | INTEGER | File key (references FILES) |
FOFFSET | INTEGER | Offset within the file |
COMMENT | CHARACTER VARYING | The comment, including its delimiters |
Strings in the code.
Field name | Field type | Value description |
---|---|---|
FID | INTEGER | File key (references FILES) |
FOFFSET | INTEGER | Offset within the file |
STRING | CHARACTER VARYING | The string, including its delimiters |
Remaining, non-identifier source code.
Field name | Field type | Value description |
---|---|---|
FID | INTEGER | File key (references FILES) |
FOFFSET | INTEGER | Offset within the file |
CODE | CHARACTER VARYING | The actual code |
Line number offsets within each file.
Field name | Field type | Value description |
---|---|---|
FID | INTEGER | File key (references FILES) |
FOFFSET | INTEGER | Offset within the file |
LNUM | INTEGER | Line number (starts at 1) |
Project details.
Field name | Field type | Value description |
---|---|---|
PID | INTEGER | Unique project key |
NAME | CHARACTER VARYING | Project name |
Identifiers appearing in projects.
Field name | Field type | Value description |
---|---|---|
EID | INTEGER or BIGINT1 | Identifier key (references IDS) |
PID | INTEGER | Project key (references PROJECTS) |
Files used in projects.
Field name | Field type | Value description |
---|---|---|
FID | INTEGER | File key (references FILES) |
PID | INTEGER | Project key (references PROJECTS) |
Included files defining required elements for a given compilation unit and project.
Field name | Field type | Value description |
---|---|---|
PID | INTEGER | Project key (references PROJECTS) |
CUID | INTEGER | Compilation unit key (references FILES) |
BASEFILEID | INTEGER | File (often .c) requiring (using) a definition (references FILES) |
DEFINERID | INTEGER | File (often .h) providing a definition (references FILES) |
Included files including files for a given compilation unit and project.
Field name | Field type | Value description |
---|---|---|
PID | INTEGER | Project key (references PROJECTS) |
CUID | INTEGER | Compilation unit key (references FILES) |
BASEFILEID | INTEGER | File included in the compilation (references FILES) |
INCLUDERID | INTEGER | Files that include it (references FILES) |
Included files providing code or data for a given compilation unit and project.
Field name | Field type | Value description |
---|---|---|
PID | INTEGER | Project key (references PROJECTS) |
CUID | INTEGER | Compilation unit key (references FILES) |
PROVIDERID | INTEGER | Included file (references FILES) |
Tokens requiring file inclusion for a given compilation unit and project.
Field name | Field type | Value description |
---|---|---|
PID | INTEGER | Project key (references PROJECTS) |
CUID | INTEGER | Compilation unit key (references FILES) |
BASEFILEID | INTEGER | File requiring a definition (references FILES) |
DEFINERID | INTEGER | File providing a definition (references FILES) |
FOFFSET | INTEGER | Definition's offset within the providing file |
LEN | INTEGER | Token's length |
C functions and function-like macros.
Field name | Field type | Value description |
---|---|---|
ID | INTEGER or BIGINT1 | Unique function identifier |
NAME | CHARACTER VARYING | Function name (redundant; see FUNCTIONID) |
ISMACRO | BOOLEAN | True if a function-like macro (otherwise a C function) |
DEFINED | BOOLEAN | True if the function is defined within the workspace |
DECLARED | BOOLEAN | True if the function is declared within the workspace |
FILESCOPED | BOOLEAN | True if the function's scope is a single compilation unit (static or macro) |
FID | INTEGER | File key of the function's definition, declaration, or use (references FILES) |
FOFFSET | INTEGER | Offset of definition, declaration, or use within the file |
FANIN | INTEGER | Fan-in (number of callers) |
Metrics of defined functions and macros.
Field name | Field type | Value description |
---|---|---|
FUNCTIONID | INTEGER or BIGINT1 | Function identifier key (references FUNCTIONS) |
NCHAR | INTEGER | Number of characters |
NCCOMMENT | INTEGER | Number of comment characters |
NSPACE | INTEGER | Number of space characters |
NLCOMMENT | INTEGER | Number of line comments |
NBCOMMENT | INTEGER | Number of block comments |
NLINE | INTEGER | Number of lines |
MAXLINELEN | INTEGER | Maximum number of characters in a line |
NSTRING | INTEGER | Number of character strings |
NULINE | INTEGER | Number of unprocessed lines |
NPPTOKEN | INTEGER | Number of preprocessed tokens |
NCTOKEN | INTEGER | Number of compiled tokens |
NPPDIRECTIVE | INTEGER | Number of C preprocessor directives |
NPPCOND | INTEGER | Number of processed C preprocessor conditionals (ifdef, if, elif) |
NPPFMACRO | INTEGER | Number of defined C preprocessor function-like macros |
NPPOMACRO | INTEGER | Number of defined C preprocessor object-like macros |
NSTMT | INTEGER | Number of statements or declarations |
NOP | INTEGER | Number of operators |
NUOP | INTEGER | Number of unique operators |
NNCONST | INTEGER | Number of numeric constants |
NCLIT | INTEGER | Number of character literals |
NIF | INTEGER | Number of if statements |
NELSE | INTEGER | Number of else clauses |
NSWITCH | INTEGER | Number of switch statements |
NCASE | INTEGER | Number of case labels |
NDEFAULT | INTEGER | Number of default labels |
NBREAK | INTEGER | Number of break statements |
NFOR | INTEGER | Number of for statements |
NWHILE | INTEGER | Number of while statements |
NDO | INTEGER | Number of do statements |
NCONTINUE | INTEGER | Number of continue statements |
NGOTO | INTEGER | Number of goto statements |
NRETURN | INTEGER | Number of return statements |
NPID | INTEGER | Number of project-scope identifiers |
NFID | INTEGER | Number of file-scope (static) identifiers |
NMID | INTEGER | Number of macro identifiers |
NID | INTEGER | Total number of object and object-like identifiers |
NUPID | INTEGER | Number of unique project-scope identifiers |
NUFID | INTEGER | Number of unique file-scope (static) identifiers |
NUMID | INTEGER | Number of unique macro identifiers |
NUID | INTEGER | Number of unique object and object-like identifiers |
NGNSOC | INTEGER | Number of global namespace occupants at function's top |
NPARAM | INTEGER | Number of parameters |
MAXNEST | INTEGER | Maximum level of statement nesting |
NLABEL | INTEGER | Number of goto labels |
FANIN | INTEGER | Fan-in (number of calling functions) |
FANOUT | INTEGER | Fan-out (number of called functions) |
CCYCL1 | INTEGER | Cyclomatic complexity (control statements) |
CCYCL2 | INTEGER | Extended cyclomatic complexity (includes branching operators) |
CCYCL3 | INTEGER | Maximum cyclomatic complexity (includes branching operators and all switch branches) |
CSTRUC | REAL | Structure complexity (Henry and Kafura) |
CHAL | REAL | Halstead complexity |
IFLOW | REAL | Information flow metric (Henry and Selig) |
FIDBEGIN | INTEGER | File key of the function's definition begin (references FILES) |
FOFFSETBEGIN | INTEGER | Offset of definition begin within the file |
FIDEND | INTEGER | File key of the function's definition end (references FILES) |
FOFFSETEND | INTEGER | Offset of definition end within the file |
Identifiers comprising a function's name.
Field name | Field type | Value description |
---|---|---|
FUNCTIONID | INTEGER or BIGINT1 | Function identifier key (references FUNCTIONS) |
ORDINAL | INTEGER | Position of the identifier within the function name (0-based) |
EID | INTEGER or BIGINT1 | Identifier key (references IDS) |
Function calls.
Field name | Field type | Value description |
---|---|---|
SOURCEID | INTEGER or BIGINT1 | Calling function identifier key (references FUNCTIONS) |
DESTID | INTEGER or BIGINT1 | Called function identifier key (references FUNCTIONS) |
Files occuring in more than one copy.
Field name | Field type | Value description |
---|---|---|
GROUPID | INTEGER | File group identifier |
FID | INTEGER | Key of file belonging to a group of identical files (references FILES) |
Note 1: INTEGER on 32-bit architectures, BIGINT on 64-bit archiectures.
select name from ids left join tokens on ids.eid = tokens.eid where ids.typedef = trueNumber of different files that use a given identifier:
select name, count(*) as cf from ( select fid, tokens.eid, count(*) as c from tokens group by eid, fid) as cl inner join ids on cl.eid = ids.eid group by ids.eid, ids.name order by cf desc;Number of times an identifier occurs in a single file:
SELECT IDS.NAME AS INAME, FILES.NAME AS FNAME, COUNT(*) AS C FROM TOKENS INNER JOIN IDS ON IDS.EID = TOKENS.EID INNER JOIN FILES ON TOKENS.FID = FILES.FID GROUP BY IDS.EID, TOKENS.FID ORDER BY C DESC;Number of times an identifier occurs in the workspace:
select name, count(*) as c from tokens inner join ids on ids.eid = tokens.eid group by eid order by c descReconstitute the file with fid = 4:
select s from (select name as s, foffset from ids inner join tokens on ids.eid = tokens.eid where fid = 4 union select code as s, foffset from rest where fid = 4 union select comment as s, foffset from comments where fid = 4 union select string as s, foffset from strings where fid = 4 ) order by foffsetThe result will have newlines in the wrong places. Piping the output through a shell script like the following can fix this problem.
sed -e '/^[0-9][0-9]* rows/d' | tr -d '\n' | sed 's/\\u0000d/\ /g'The above script will massage the HSQLDB output removing the trailing
N rows
line and all existing newlines,
and changing the embedded \u0000d
sequences into newlines.
For the Windows line-end conventions the same script would be:
sed -e '/^[0-9][0-9]* rows/d' | tr -d '\n\r' | sed 's/\\u0000d\\u0000a/\ /g'Show the projects each identifier belongs to:
select IDS.NAME, PROJECTS.NAME from IDS INNER JOIN IDPROJ ON IDS.EID = IDPROJ.EID INNER JOIN PROJECTS ON IDPROJ.PID = PROJECTS.PID ORDER BY IDS.NAME;Show the included files required by other files for each compilation unit and project.
select projects.name as projname, cufiles.name as cuname, basefiles.name as basename, definefiles.name as defname from definers inner join projects on definers.pid = projects.pid inner join files as cufiles on definers.cuid=cufiles.fid inner join files as basefiles on definers.basefileid=basefiles.fid inner join files as definefiles on definers.definerid = definefiles.fid;Speed-up processing:
create index teid on tokens(eid) create index tfid on tokens(fid)Obtain identifiers common between files participating in a define/use relationship:
SELECT tokensa.eid, min(ids.name) as identifier, min(filesb.name) as defined, min(filesa.name) as used FROM definers INNER JOIN tokens AS tokensa ON definers.basefileid = tokensa.fid INNER JOIN tokens AS tokensb ON definers.definerid = tokensb.fid INNER JOIN ids ON ids.eid = tokensa.eid INNER JOIN files as filesa ON tokensa.fid = filesa.fid INNER JOIN files as filesb ON tokensb.fid = filesb.fid WHERE tokensa.eid = tokensb.eid GROUP BY tokensa.eid, definerid, basefileid ORDER BY defined, identifierCreate a function and macro call graph:
SELECT source.name AS CallingFunction, dest.name AS CalledFunction FROM fcalls INNER JOIN functions AS source ON fcalls.sourceid = source.id INNER JOIN functions AS dest ON fcalls.destid = dest.id
while (a) if (b) c();counts as three statements.
do .. while
form.
See note 3.if (a) { ... } else if (b) { ... } else if (c) { ... } else ... }this metric does not take into account the nesting of
else
clauses.
Thus the above code will be given a nesting level of 1,
rather than 3, which is implied by the following
(actual) reading of the code.
if (a) { ... } else if (b) { ... } else if (c) { ... } else ... }See note 1. See note 4.
switch
statements, this metric
measures the complexity of a switch
statement as 1.
case
label as a separate node.
#define x(if, while, else) (if + while + else)will be miscounted as keywords occuring in the corresponding macro. Furthermore keywords generated during preprocessing, as in
#define WHILE(x) while(x) { #define WEND } WHILE (x) foo(); WENDwill not be counted as occuring in the corresponding C function.
Some programs have parts of them compiled under conditional preprocessor directives. Consider the following example:
#ifdef unix #include <unistd.h> #define erase_file(x) unlink(x) #endif #ifdef WIN32 #include <windows.h> #define erase_file(x) DeleteFile(x) #endif main(int argc, char *argv[]) { erase_file(argv[1]); }As humans we can understand that
erase_file
occurs three times
within the file.
However, because CScout preprocesses the file following the
C preprocessor semantics, it will typically match only two instances.
In some cases you can get around this problem by defining macros that will
ensure that all code inside conditional directives gets processed.
In other cases this will result in errors (e.g. a duplicate macro definition
in the above example).
In such cases you can include in your workspace the same project multiple
times, each time with a different set of defined macros.
workspace example { project idtest { define DEBUG 1 define TEST 1 file idtest.c util.c } project idtest2 { define NDEBUG 1 define PRODUCTION file idtest.c util.c }
Consider the following example:
struct s1 { int id; } a; struct s2 { char id; } b; struct s3 { double id; } c; #define getid(x) ((x)->id) main() { printf("%d %c", getid(a), getid(b)); }In the above example, changing an
id
instance should
also change the other three instances.
However, CScout will not associate the member of
s3
with the identifier appearing in the getid
macro or the
s1
or s2
structures,
because there is no getid
macro invocation to link them together.
If e.g. id
is replaced with val
the program will compile and function correctly,
but when one tries to access the c
struture's member
in the future using getid
an error will result.
struct s1 { int val; } a; struct s2 { char val; } b; struct s3 { double id; } c; #define getid(x) ((x)->val) main() { printf("%d %c", getid(a), getid(b)); /* OK */ printf(" %g", getid(c)); /* New statement: error */ }To avoid this (rare) problem you can introduce dummy macro invocations of the form:
#ifdef CSCOUT (void)getid(d) #endif
We employ a heuristic classifying all instances of an undefined macro
as being the same identifier.
Thus in the following sequence foo
will match all
three macro instances:
#undef foo #ifdef foo #endif #ifdef foo #endif #define foo 1In most cases this is what you want, but there may be cases where the macro appears in different files and with a different meaning. In such cases the undefined instances of the macro will erroneously match the defined instance.
In addition, the analysis of functions can be confused by the following situations.
#ifdef argument is not an identifier
#ifdef
directive is not a legal identifier.Application of macro " ... ": operator # only valid before macro parameters
#
was not followed
by a macro parameter.Assuming declaration int ... (...)
Duplicate (different) macro definition of macro ...
Empty character literal
Illegal combination of sign specifiers
unsigned signed
).Processing automatically generated file; #line directive ignored.
#line
directive was found.
This signifies that the source file is automatically
generated and refactoring changes on that file may
be lost in the future.
References to the original source file are ignored.Sign specification on non-integral type - ignored
Undeclared identifier in typeof expression: ...
typeof
has not been declared.Undeclared identifier: ...
#pragma pushd: unable to get current directory: ...
getcwd
failed while
processing the
#pragma pushd
CScout-specific directive.EOF in comment
Error count exceeds 100; exiting ...
Invalid C token: '$'
Unable to get path of file ...
Unable to stat file ...
#pragma echo: string expected
#pragma echo
CScout-specific directive was not followed by a
string.#pragma includepath: string expected
#pragma includepath
CScout-specific directive was not followed by a
string.#pragma process: string expected
#pragma process
CScout-specific directive was not followed by a
string.#pragma project: string expected
#pragma project
CScout-specific directive was not followed by a
string.#pragma pushd: string expected
#pragma pushd
CScout-specific directive was not followed by a
string.#pragma readonly: string expected
#pragma readonly
CScout-specific directive was not followed by a
string.#pragma ro_prefix: string expected
#pragma ro_prefix
CScout-specific directive was not followed by a
string.% not followed by yacc keyword
%union does not have a member ...
Application of macro " ... ": operator # at end of macro pattern
#
.Array not an abstract type
At most one storage class can be specified
Conflicting declarations for identifier ...
Declared parameter does not appear in old-style function parameter list: ...
Division by zero in #if expression
#if
expression
divided by zero.Duplicate definition of identifier ...
Duplicate definition of tag ...
EOF while processing #if directive
#if
block reached the end of file, without a
corresponding
#endif
/
#else
/
#elif
directive.Empty #include directive
#include
directive was not followed by a filename specification.End of file in character literal
End of file in string literal
Explicit element tag without no %union in effect
Illegal characters in hex escape sequence
\x
continued with a non-hexadecimal
character.Illegal combination of type specifiers
double char
).Illegal pointer dereference
Invalid #include syntax
#include
directive was not followed by a legal filename specification.Invalid application of basic type, storage class, or type specifier
Invalid character escape sequence
\c
can not be
recognised.Invalid macro name
#define
or
#undef
directive is not a valid identifier.Invalid macro parameter name
#define
directive is not a valid identifier.Invalid macro parameter punctuation
#define
macro
definition are not separated
by commas.Invalid preprocessor directive
Invalid type specification
Label ... already defined
goto
label is defined more
than once in a given function.Macro [ ... ]: EOF while reading function macro arguments
Macro [ ... ]: close bracket expected for function-like macro
Member access in incomplete struct/union: ...
Missing close bracket in defined operator
defined
operator was not
followed by a closing bracket.Modulo division by zero in #if expression
#if
expression
divided by zero in a modulo
expression.Multiple storage classes in type declaration
No identifier following defined operator
defined
operator was not followed
by an identifier.Object is not a function
Only struct/union anonymous elements allowed
struct {int x, y;}
)
can only be structures or unions.
(GCC/Microsoft C extension).Pointer not an abstract type
Popd: directory stack empty
#pragma popd
CScout-specific directive was performed on an
empty directory stack.Structure or union does not have a member ...
.
or
->
operator
does not have as a member the
identifier appearing on the
operator's right.Subscript not on array or pointer
[]
operator is not an array or a pointer.Syntax error in preprocessor expression
#if
or
#elif
expression was syntactically
incorrect.Unable to open include file ...
Unbalanced #elif
#elif
directive was found without a corresponding
#if
.Unbalanced #else
#else
directive was found without a corresponding
#if
.Unbalanced #endif
#endif
directive was found without a corresponding
#if
.Undefined label ...
goto
label used within a function was never defined.Unexpected end in character escape sequence
\c
) was not
completed; no character follows the backslash.Unknown preprocessor directive: ...
Unkown %union element tag ...
Yacc $value out of range
The free unsupported CScout version is distributed under the CScout Public License. It allows free use of CScout for analyzing and modifying free/Open Source software.
For using CScout on non-free/proprietary software, the CScout supported version and associated license are available. The supported version comes with a normal commercial software license, with none of the special restrictions of this license.
The intent of this license is to establish freedom to use, share, and change the software regulated by this license under the open source model.
This license applies to any software containing a notice placed by the copyright holder saying that it is covered by the terms of the CSCOUT Public License version 1.0. Such software is herein referred to as the Software. This license covers modification and distribution of the Software and the use of the Software for the development and maintenance of free software.
1. You are granted the non-exclusive rights set forth in this license provided you agree to and comply with any and all conditions in this license. Whole or partial distribution or use of the Software in any form or way signifies acceptance of this license.
2. You may copy and distribute the Software in unmodified form provided that the entire package, including - but not restricted to - copyright, trademark notices and disclaimers, as released by the initial developer of the Software, is distributed under this license.
3. You may make modifications to the Software's source code and distribute your modifications, in a form that is separate from the Software, such as patches. The following restrictions apply to modifications:
a. Modifications must not alter or remove any copyright notices in the Software.b. When modifications to the Software are released under this license, a non-exclusive royalty-free right is granted to the initial developer of the Software to distribute your modification in future versions of the Software provided such versions remain available under these terms in addition to any other license(s) of the initial developer.
c. The machine-executable (compiled) parts of the Software shall not be modified.
4. You may use the original or modified versions of the Software to analyze and modify application programs, libraries, or other software legally developed by you or by others provided that when these items are distributed in any form you satisfy following requirements:
a. You must ensure that all recipients of machine-executable forms of these items are also able to receive and use the complete machine-readable source code to the items without any charge beyond the costs of data transfer.b. You must explicitly license all recipients of your items to use and re-distribute original and modified versions of the items in both machine-executable and source code forms. The recipients must be able to do so without any charges whatsoever, and they must be able to re-distribute to anyone they choose.
c. If the items are not available to the general public, and the initial developer of the Software requests a copy of the items, then you must supply one.
5. You acknowledge and accept the fact that the Software may contain technical measures to enforce parts of this license (such as providing the public with a browsable version of the code you are analyzing, and the transmission of workspace-related data) and agree not to interfere with these measures.
In no event shall the initial developers or copyright holders be liable for any damages whatsoever, including - but not restricted to - lost revenue or profits or other direct, indirect, special, incidental or consequential damages, even if they have been advised of the possibility of such damages, except to the extent invariable law, if any, provides otherwise.
THE SOFTWARE AND ITS DOCUMENTATION ARE PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF DESIGN, MERCHANTIBILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
This license is governed by the Laws of Greece. Disputes shall be settled by the Courts of Athens.
Free / Unsupported Version | Supported Version |
---|---|
Distributed under the CScout public license. | Distributed under a commercial software license and a support contract. |
Shall only be used on open source software. | Can be used on proprietary software. |
Unsupported. | Includes 8 hours of email-based installation and configuration support and two years of free software updates. |
After a large workspace is processed, the workspace is registered for public browsing at CScout's Web site. Project metrics are sent to the Web site and recorded for statistical processing. | Web communication is only performed for validating the software's license. No details other than the host's name and IP address are communicated. |
Can only be run on machines with a direct connection to the Internet. | A proxy host and port can be specified for connecting to the CScout registration and licensing server. |
The entire Internet is allowed read-only access to the CScout server. | Access is regulated by a fully configurable access control list, defaulting to localhost-only access. |
Only users on the local host are allowed read-write access to the server. | Read-write access through specified remote hosts is possible. |
Includes SQL back-end. | |
Includes C source obfuscation back-end. | |
Includes support for browse-only multiuser operation and an access log. |