The CScout Refactoring Browser

Diomidis Spinellis
Department of Management Science and Technology
Athens University of Economics and Business
Athens, Greece


CScout is a source code analyzer and refactoring browser for collections of C programs. It can process workspaces of multiple projects (we define a project as a collection of C source files that are linked together) mapping the complexity introduced by the C preprocessor back into the original C source code files. CScout takes advantage of modern hardware advances (fast processors and large memory capacities) to analyze C source code beyond the level of detail and accuracy provided by current compilers, linkers, and other source code analyzers. The analysis CScout performs takes into account the identifier scopes introduced by the C preprocessor and the C language proper scopes and namespaces.

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

Furthermore, CScout allows you to refactor the arguments of functions and macros, introducing new arguments, deleting existing ones, or changing their order.


If you are impatient, you can get an immediate feeling of CScout, by unpacking its distribution file, entering the example directory and typing You will then be able to use CScout and your browser to explore the source code of the one true awk (

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);
        valreturn 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.c
We 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
We are now ready to serve you at http://localhost:8081
The 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:

Scout Main Page

File Dependencies

Main page — Web: Home Manual

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)

struct number {
        int id;
        double val;

struct character {
        int id;
        char val;

static int val;

main(int argc, char *argv[])
        int val;

        if (argc > 2)
                goto val;
        return getval(n) + getval(c);
        val: return 0;

Main page

Clicking on the first identifier 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

  • Read-only: No
  • Tag for struct/union/enum: No
  • Member of struct/union: Yes
  • Label: No
  • Ordinary identifier: No
  • Macro: No
  • Undefined macro: No
  • Macro argument: No
  • File scope: No
  • Project scope: No
  • Typedef: No
  • Crosses file boundary: No
  • Unused: No
  • Matches 3 occurence(s)
  • Appears in project(s):
    • idtest
  • Substitute with:

Dependent Files (Writable)

Dependent Files (All)

Main page

Clicking on the marked source hyperlink, CScout will show us again the corresponding source code, but with only the identifiers 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)

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;

Main page

The marked identifiers will be all the ones and the only ones the replacement we specified will affect. Similarly we can specify the replacement of the 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.

Installation and Setup

System Requirements

To run CScout your system must satisfy the following requirements:

Installation and Configuration

From this point onward we use the term Unix to refer to Unix-like systems like GNU/Linux and FreeBSD, and Windows to refer to Microsoft Windows systems.

You install CScout in eight steps:

  1. Unpack the distribution file on your system.

  2. Copy the executable files 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.

  3. Under Windows adjust the second line of the file cswc.bat and csmake.bat to point to the directory where you installed the corresponding file.

  4. Copy the directory 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.

    Alternativelly, the contents of the directory etc will be searched in $HOME/.cscout, %APPDATA%/.cscout (under Windows; it will be something like C:\Documents and Settings\Your Name\Application Data), and the current directory's .cscout directory.

  5. Go in the CScout etc directory and copy the file pair 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.

  6. If you decided to use the .GENERIC files copy the include directory to an appropriate location (e.g. /usr/local/include/cscout under Unix).

  7. Edit the file cscout_incs.h to specify the location where your compiler's (or the generic) include files reside.

  8. If the compiler you are using does not match any of the files supplied, start with the .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 double
    Have a look in the existing cscout_defs files to see what might be required.
Note that there is nothing magical about the installation steps described above; feel free to follow them in whatever way matches your setup and environment, as long as you achieve the desired results.


The following diagram illustrates the data flow when working with CScout.
Data flow in a CScout project
The thick-lined objects depict active processes; the thin-lined objects depict data. CScout will analyze and process C source code under the directions of a processing script. After some user interactions through a web browser CScout can write out the modified source code. CScout can also convert the C source code into an SQL script that can be further analyzed and processesed through an RDBMS.

There are three ways to generate the processing script:

  1. Through a workspace definition file, processed by the workspace compiler cswc.
  2. By having the csmake command monitor the build process.
  3. By tailoring a project's build process to generate a processing script.
Each method has different advantages and disadvantages. Therefore, you should probably select the method that better suits your needs, and not bother with the others.

Workspace definition files offer by far the most readable and transparent way to setup a CScout workspace. They are declarative and express exactly the operations that CScout will perform. On the other hand, they can be difficult to specify for an existing large project and they must be kept in sync with the project's build process.

Running your make process under the csmake command is a very easy way to generate a CScout processing script. This method however only works if the essentials of your make process aren't too contrived. csmake can handle builds implemented through the Unix-related make, gcc, ld, ar, and mv commands. It has been successfuly tested on the Linux and FreeBSD kernels and the Apache web server. If csmake can deal with your project, you will be up and running in minutes; if not, you will only have lost those few minutes. Another advantage of the csmake method is that csmake will obtain from the compiler the predefined macros and the include file path. As a result you often don't have to tailor the files 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.

Defining Workspaces

A workspace definition provides CScout with instructions for parsing a set of C files; the task that is typically accomplished when compiling programs through the use of makefiles. CScout must always process all its source files in a single batch, so running it for each file from a makefile is not possible. Workspace definition files provide facilities for specifying linkage units (typically executable files - projects in the workspace definition file parlance) grouping together similar files and specifying include paths, read-only paths, and macros.

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 Definition Details

You can see the complete syntax of CScout workspaces in the following BNF grammar.
	workspace NAME { WORKSPACE_ELEMENT ... }

	cd "PATH"

	ipath "PATH"
	define MACRO

	ro_prefix "PATH"
	readonly "FILENAME"

	project NAME { PROJECT_ELEMENT ... }

	cd "PATH"

	directory PATH  { DIRECTORY_ELEMENT ... }


	file FILENAME ...
	file "FILENAME" { FILESPEC ... }

	cd "PATH"
The 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/"
	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"
			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

Automated Generation of the Processing Script

In CScout from version 2.2 and onward you can you can also use the supplied tool csmake to directly generate CScout processing scripts by monitoring a project's make-based build process. For this to work your project's build must (probably) be based on a Unix or Unix-like system, and use make and gcc. The make process can also invoke ld, ar, and mv. Recursive make invocations among different directories are also supported.

The way to use csmake is fairly simple. You first arrange for performing a full build, for example by running

make clean
Then, 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 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
                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
cat make.*.cs >all.cs
sed -n 's/#pragma process "\(.*hack.c\)"/\1/p' all.cs | xargs touch
cscout all.cs

Tailoring the Build Process to Generate the Processing Script

It is relatively easy to integrate CScout into an existing IDE (such as Eclipse) or to provide an alternative method for specifying workspaces by directly creating a processing script from existing Makefiles. A processing script (what results from compiling a workspace file) is a C file containing a number of #pragma preprocessor directives. CScout uses the following pragmas:
#pragma echo "STRING"
Will display the STRING on CScout's standard output when that part of the file is reached.


#pragma echo "Processing workspace date\n"
#pragma ro_prefix "STRING"
Will add STRING to the list of filename prefixes that mark read-only files. This is a global setting.


#pragma ro_prefix "C:\gcc"
#pragma project "STRING"
Will set the current project to STRING. All identifiers and files processed from then on will belong to the given project.


#pragma project "date"
#pragma block_enter
Will enter a nested scope block. Two blocks are supported, the first 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
Will exit a nested scope block. The number of 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"
Will analyze (CScout's equivalent to compiling) the C source file named STRING.


#pragma process "date.d"
#pragma pushd "STRING"
Will set the current directory to STRING, saving the previous current directory in a stack. From that point onward, all relative file accesses will start from the given directory.


#pragma pushd "cp"
#pragma popd
Will restore the current directory to the one in effect before a previously pushed directory. The number of pushd pragmas should match the number of popd pragmas.

#pragma includepath "STRING"
Will add STRING to the list of directories used for searching included files (the include path).


#pragma includepath "/usr/lib/gcc-lib/i386-redhat-linux/2.96/include"
#pragma clear_include
Will clear the include path, allowing the specification of a new one.

#pragma clear_defines
Will clear all defined macros allowing the specification of new ones. Should normally be executed before processing a new file. Note that macros can be defined using the normal #define C preprocessor directive.
The following is a complete example of a CScout processing script.
// 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"

Case Study: Processing the FreeBSD Kernel (the Hard Way)

As a further example consider the steps for applying CScout on the FreeBSD kernel, before the existence of the csmake command.
  1. Configure a LINT or GENERIC version of each architecture's kernel.
    Example: config LINT
  2. Go to the compilation directory, update the dependencies (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.
  3. Remove the generated object files to force a make operation to rebuild them (rm *.o).
  4. Replace the C compiler invocation command in the Makefile with an appropriate series of shell commands.
    .include "$S/conf/"
    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
  5. Create a cscout_incs.h file for each different architecture.
  6. Remove kernel.cs The existing file documents the way to do it.
  7. Run make on the custom Makefile
  8. Repeat for each different architecture
  9. Create a top-level CScout file to process all architectures:
    #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_exit
    Note that the block_enter and block_exit pragmas are furnished by this top-level file.
The run of the above specification (2 million unique lines) took 330 CPU minutes on a Rioworks HDAMA (AMD64) machine (2x1.8GHz Opteron 244 (in UP mode) - AMD 8111/8131 chipset, 8192MB mem) and required 1474MB of RAM. These are the complete metrics:

CScout Home

File Metrics

Writable Files
Number of files: 4310

File metricTotalMinMaxAvg
Number of characters625057700100834514502
Comment characters159217520850593694
Space characters79364010739681841
Number of line comments19040
Number of block comments1762530433740
Number of lines2063096027336478
Length of longest line3370490186778
Number of C strings13251901929630
Number of defined functions2958403336
Number of preprocessor directives26754202733662
Number of directly included files35408016088
Number of C statements67982504465157

CScout Execution

The CScout engine (cscout) requires as an argument a processing script, for example a cswc-compiled workspace definition file or the 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
We are now ready to serve you at http://localhost:8081
After 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 access control list specified, 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.

Preprocessor invocation

As an aid for configuring CScout for a different compiler you can run CScout and the workspace compiler with the optional -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.

Checking invocation

There are cases where you may only want to run CScout to see its error diagnostic messages. As an example, you may be running CScout as part of your daily build cycle to verify that the source code can always be parsed by CScout. The -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
/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.h
Notice that there are two types of unused include files:
  1. Directly included files
  2. Included files that are only indirectly included
You will typically remove the #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):