The C++ Console Tool Set (CTS)

Version 0.86


1. Introduction.. 1

2. Command-line argument parser. 2

Argument syntax supported by CTS.. 2

Argument specification example.. 3

Argument specification guidelines. 4

Constraints among options. 4

Obtaining option values. 4

Obtaining all option values. 5

Obtain unbound argument values. 5

3. Logging service.. 5

Logging levels. 5

Logging details. 7

Enable and disable logging.. 8

Logging policy. 8

Direct and buffered logging.. 8

Nested Diagnostic Context. 8

Logging configuration file.. 9

Extensibility. 10

4. Other utility classes. 10

Execution Timer. 10

Java-like String handling.. 10

String tokenizer. 11

File information.. 11

Directory information.. 11

Configuration file.. 11

5. Test programs. 12

tnow.. 12

tlogger. 12

tmore.. 13

tlist. 13

tconfig.. 14

ttokenizer. 14

6. Using CTS.. 14

Compiling CTS and test programs. 15

7. Limitations. 16

8. License.. 16

9. Version history. 16

10. Feedback. 16

Appendix. 17


1. Introduction


The C++ Console Tool Set (CTS) is a small and light-weight open source set of utility classes mainly for console applications.


CTS consists of a command-line argument parser, a thread-safe logging service and other utility classes (string tokenizer, timer, file and directory walker, …). See more details in the following sections. You can also refer to the code documentation for programming interfaces.

Note: CTS is NOT really cross-platform. It has been tested on Windows (XP, Vista) and Linux (Debian, Ubuntu). In future we will port it to other systems (e.g. Solaris, AIX, BSD).

2. Command-line argument parser


The CTS command-line argument parser simplifies how arguments are handled by a program. Developer specifies requirements of command-line arguments (how they look like, whether they are optional/required, …) the parser will make sure that the real input arguments match that specification and provides functions to retrieve them.

The argument parser supports the POSIX and GNU program argument syntax conventions [1], in which an option either is a dash followed by a single character or starts with two dashes and followed by characters or dashes, e.g. -f or --input-file. On Windows, besides POSIX and GNU conventions, option can be introduced by a slash, e.g. /I.

Option input by user can appear multiple times and come in any order. An option can be referred to by any name in its specification. If you have both -f and --input-file for the same option, you can refer to it with either of them.

$ editor -f /home/user/readme.txt

is the same as:

$ editor –-input-file /home/user/readme.txt

CTS argument parser also supports Windows-style argument conventions, where an option starts with a slash. Note that in Windows-style options are NOT case-sensitive.

C:\> editor /f readme.txt

Depending on the code is compiled on Unix or Windows, the argument style is set accordingly. You can also set it manually in your code before handleUsage() is called, but this is not recommended.

     CtsConsole::setConsoleStyle(CTS_WIN);       // set Windows argument style

     CtsConsole::setConsoleStyle(CTS_UNIX);  // set Unix argument style

Argument syntax supported by CTS

The following describes how arguments can be provided in various ways supported by CTS command line argument parser:

+ Argument comes after option, separated by white spaces

$ editor -f /home/user/readme.txt

+ Option is followed directly by argument

$ compiler -I/usr/include

+ Option equals argument

$ compiler --include-dir=/usr/include

+ numeric option

$ editor +10 -f /home/user/readme.txt

+ Combined flags

$ decompressor -xvf /home/user/download/documents.tar

Argument specification example

There are rules for option specification but they are pretty strait-forward. Let's take an example:


#include "cts.hpp"

const char* DESCRIPTION = "My application";

const char* COPYRIGHT   = "My company";

const char* USAGE = "(-s --server <host name>)   # Server name\n"

                    "(-u --user <user ID>)       # User name to log in\n"

                    "[-p --password <password>]  # User's password\n"

                    "[-t --trace [<trace file>]] # Turn on tracing\n"

                    "[-v --verbose]              # Show more details\n"

                    "[-q --quiet]                # Silent mode\n";


using namespace cts;


int main(int argc, const char* argv[]) {

   CtsConsole console(argc, argv, DESCRIPTION, COPYRIGHT);

   if (!console.handleUsage(USAGE))

      return -1;

   CtsConsole::format("Server", console.getOptionValue("server"));

   CtsConsole::format("User ID", console.getOptionValue("user"));



The variable USAGE specifies 5 options, in which the first 2 options are required, the rest is optional.


Option "(-s --server <host name>) # Server name\n" is required, it can be refered to either by -s or --server, and has a required argument  <host name>.


Option "(-u --user <user ID>) # User name to log in\n" is required, it can be refered to either by -u or --user, and has a required argument  <user ID>.


Option "[-p --password <password>] # User's password\n" is optional, it can be refered to either by -p or --password, and has a required argument  <password>.


Option "[-t --trace [<trace file>]] # Turn on tracing\n" is optional, it can be refered to either by -t or --trace, and has an optional argument  <trace file>.


Option "[-v --verbose] # Show more details\n" is optional, it can be refered to either by -v or --verbose, and has no argument (also called a flag).  


Option "[-q --quiet] # Silent mode\n" is optional, it can be refered to either by -q or --quiet, and has no argument (also called a flag).


The code in main() instantiates a CtsConsole variable and calls its function handleUsage(). This function analyses the option specification and checks that user's input matches this specification. In case there is some mismatch it prints the error messages to standard output and returns false. Otherwise the program proceeds showing real arguments server and user ID as you see below:


TESTPROGRAM /server /user linhmt


 My company

 TESTPROGRAM – My application


   User ID.................................: linhmt


Argument specification guidelines

The example above should give you some ideas about how argument specification should look like. Specification of an option usually consists of option names, arguments and an optional description. In the example above, -s and –-server are option names, <host name> is an argument, and "Server name to connect to" is the option description. Following is some guidelines:

- An option can have multiple distinct names starting with one or two dashes (Unix) or a slash (Windows). Option names are interchangable.

- A non-option token is considered a formal argument. Arguments with multiple words must be surrounded by angle brackets, e.g. <this is an argument>.

- An option or argument is optional if it is surrounded by square brackets, e.g. [<trace file>].
- Option description is separated with the previous part of option specification by a
# character.

- Options MUST be separated by a new line character.

- Option names must be unique.

- Option name followed directly by an argument name in angle brackets indicates that the argument can follow the option name directly in the command-line input. e.g.

[-I<include dir> --include-dir=<include dir>] # add directory to search path

- An option may not have description, argument or even option name. If an option has argument but no option name, the argument is called an unbound argument (not bound to nay option), e.g. <src. file> <desc. file>

Constraints among options

CTS argument parser does not handle contraints among options. For instance, if you have two options –verbose and –quiet that cannot show up together, it is developer’s responsibility to check and handle that. The following pseudo code describes this situation.


     if (console.hasOption(“verbose”) && console.hasOption(“quiet”)) {

        console.error(“Program can only run either in verbose or quiet mode”);

        return RC_ERROR;



Obtaining option values

The CtsConsole class provides the following functions to retrieve the number and values of the option's arguments:

         const int getNumberOfOptionValues(const char* cpszOptionName);

Funtion getNumberOfOptionValues() returns the number of argument values of the option. It returns zero if the option name is not found, or no argument values are provided by use (e.g. optional argument).


         const int getNumberOfUnboundOptionValues();

Function getNumberOfUnboundOptionValues() returns the number of unbound argument values. It returns zero if the no argument values were provided by user.


         const char* getOptionValue(const char* cpszOptionName, const int idx = 0);

Function getOptionValue() returns a pointer to the argument value provided by user. It returns NULL if the option name is not found or the argument index is not in the range [0..number of arguments – 1].


         const char* getUnboundOptionValue(const int idx = 0);

Function getUnboundOptionValue() returns a pointer to the unbound argument value provided by user. It returns NULL if no unbound argument values are provided by user.


Obtaining all option values

The following shows how you can loop over all argument values of the option server using a for loop, and refer to particular argument value by its index.


         for (int i = 0; i < console.getNumberOfOptionValues("server"); i++) {

         CtsConsole::format("Server", console.getOptionValue("server", i));



Obtain unbound argument values

The following shows how you can loop over all unbound argument values using a for loop and refer to particular argument value by its index.


         for (int i = 0; i < console.getNumberOfUnboundOptionValues(); i++) {

         CtsConsole::format("Argument", console.getUnboundOptionValue(i));



For more on how to use this class, please look into the test programs provided together with CTS code.


3. Logging service

CTS provides you with a light-weight, easy and thread-safe logging capability, with which you can keep track the contexts of application runs. You can write log data to console, to files, or both. This is achieved by retrieving a logger and attaching log handlers to your logger intance. When you log data via a logger, the data is forwarded to all handlers attached to it, which write to log output destinations. Loggers are referenced by name so a logger can be refered to from anywhere via its name.

Logging levels

Each logging command and each logger has a level of logging. There are 6 levels: SEVERE, ERROR, WARNING, INFO, FINE and FINEST. SEVERE is the lowest and FINEST is the highest level.


The level of a logging command indicates the severity of the log message. The level of a logger indicates the highest level of logging commands it will process. For instance, when a logger is set to level INFO, all logging commands at level FINE or FINEST are not processed. The level of a logger can be set by dynamically in code or configured in logging configuration file at run-time.


CtsLogger::setLogLevel(CtsLogLevel level);

where can take values CtsSevere, CtsError, CtsWarning, CtsInfo, CtsFine, CtsFinest. To log a message with specific logging level, you call the following functions:

CtsLogger::severe(const char* format, ...);
CtsLogger::error(const char* format, ...);
CtsLogger::warning(const char* format, ...);
CtsLogger::info(const char* format, ...);
CtsLogger::fine(const char* format, ...);
CtsLogger::finest(const char* format, ...);


The following is an example of using CTS logging in a function:



 * Compress file


RC_CODE compress(CtsConsole & console,

      const char * & filename,

      const OutputFormat & format,

      void * buffer,

      int & size)


   CtsLoggerRef logger = CtsLogManager::getCtsLogger(“dblogger”);

   // logging with finest when trace is turned on

   if (console.hasOption(“trace”) {




   try {

      logger.finest(“Compressing file %s”, filename);

      float ratio = 1;

      switch (format) {

      case FORMAT_ZIP: {
“Output format ZIP”);

         ratio= compress_zip(format, buffer, size);



      case FORMAT_RAR: {
“Output format RAR”);

         ratio= compress_RAR(format, buffer, size);



      case FORMAT_LZ: {
“Output format LZ”);

         ratio= compress_LZ(format, buffer, size);



      case FORMAT_TAR: {
“Output format TAR”);

         ratio= compress_TAR(format, buffer, size);



      default: {

         logger.error(“Unsupported compression format”);




      logger.finest(“Compression ratio: %f”, ratio);


   catch (Exception & e) {

      logger.severe(“Compressing file failed: %s”, e.what());

      return RC_ERROR;


   return RC_SUCCESS;



Logging details

A log message written by handlers may contain timestamp when it is executed, the level of the message, ID of the thread that executed the log command, the message itself, the source code origin (including source file name, line number and function name) and Nested Diagnostic Context information (that tells you what thread this message is from). Sometimes it is unnecessary to have the source origin logged, or when timestamp is not needed, you can in some extent set what of the above information should be ignored by setting/configuring the logger's level of details. There are 3 levels: LOW, MEDIUM, HIGH, with which more details are written to output respectively. Note that when you call the logging functions mentioned above, no source origin is passed to log handlers, therefore source origin is not written to log entries even when you set logging detail to HIGH.

In order to make source origin available in log entries, you must instead call the following version of the functions, where the first parameter CTS_ORIGIN, a macro defined by CTS, is required:

CtsLogger::severe(CTS_ORIGIN, const char* format, ...);

CtsLogger::error(CTS_ORIGIN, const char* format, ...);

CtsLogger::warning(CTS_ORIGIN, const char* format, ...);

CtsLogger::info(CTS_ORIGIN, const char* format, ...);

CtsLogger::fine(CTS_ORIGIN, const char* format, ...);

CtsLogger::finest(CTS_ORIGIN, const char* format, ...);

The following is part of a log file generated by a CTS logging test program:


10-05-2010 15:49:55.500 INFO    6628  Info 1 [test/testlogger.cpp:70 doLogging] Thread_6

10-05-2010 15:49:55.500 ERROR   6132  Error 2 [test/testlogger.cpp:68 doLogging] Thread_5

10-05-2010 15:49:55.500 ERROR   7944  Error 1 [test/testlogger.cpp:68 doLogging] Thread_8

10-05-2010 15:49:55.500 ERROR   3936  Error 2 [test/testlogger.cpp:68 doLogging] Thread_1

10-05-2010 15:49:55.500 ERROR   3164  Error 0 [test/testlogger.cpp:68 doLogging] Thread_16

10-05-2010 15:49:55.500 ERROR   5496  Error 0 [test/testlogger.cpp:68 doLogging] Thread_15

10-05-2010 15:49:55.500 WARNING 4084  Warning 1 [test/testlogger.cpp:69 doLogging] Thread_9


The log file was generated with detail level HIGH. The first column contains the timestamps when the log entries were written, the second column shows the logging level of each entry, the third one shows ID of the calling thread, the rest contains the log messages, which is for demonstration purpose very simple, the source origin and function name surrounded by square brackets, and finally the Nested Diagnostic Context - the unique string that identifies a thread. In this case NDC is made of with Thread_ followed by the order of the thread in which it was created.

Enable and disable logging

Logging is expensive with respect to performance. At run-time you may set the logger's levels and details in the CTS logging configuration file to control what to be logged. However you could also completely disable logging by turning off option CtsEnableLogging, note that even though, log files are still created by log handlers and filled with some logging configuration. Alternatively you can also dynamically pause and resume logging using functions CtsLogger::pause() and CtsLogger::resume() in your code.

Logging policy

CTS logging implements a file rolling policy to control the log file size and number of files. The policy allows you to specify a maximal file size and number of log files to be created. Log files are numbered from 1 to N (number of log files). Initially, a log file with index 1 is created and written to. When the log file reaches the maximal file size, the next log file with index 2 is created, and so on. When the Nth log file reaches the maximal file size, the 1th log file is used as the next one. 


Direct and buffered logging

When logging to files, the log entries can be written directly to a file, but they can be written to memory buffer first and flushed to file when the buffer is full. You can control this behavior at run-time, define an environment variable CTS_DIRECT_LOGGING to enable direct logging and undefine it to enable buffered logging. This must be done before your application is started. 


Nested Diagnostic Context

CTS logging provides a minimal support for Nested Diagnostic Context (NDC), which is mainly used in multithreaded applications, where a per thread context is helpful to identify log records from specific thread. You would calls setNDC() function to set a context for the current thread, this function will not affect other threads. When no longer needed, you can call removeNDC() to get rid of NDC information for the current thread. 

Supposed you have a buffer for generating a string that uniquely identifies the current thread. You can call CtsLogger::setNDC(const char*) for each thread that you create:


sprintf(buffer, "Thread_%d", ndcIndex++);



Logging configuration file

Several aspects of logging can be adjusted via a configuration file named ctslogging.ini in the currnet directory where you start your application. The following is an example of the logging configuration file coming with CTS:



# CTS loggging configuration file


CtsEnableLogging  = 1   

CtsMaxFileSize    = 10   # maximal log file size in MB

CtsNumFiles       = 10   # number of log files

CtsLogDetail      = HIGH

CtsLogLevel       = SEVERE

CtsLogDirectory   = C:\\temp\\log


# Logging details (logger names are case sensitive)

# Values include LOW, MEDIUM, HIGH 


logger1           = HIGH

logger2           = HIGH


# Logging levels (logger names are case sensitive)



logger1           = FINEST 

logger2           = FINEST 




The following describes the global options in the logging configuration file:



         Type:          boolean

         Value:         True, False, 1, 0, On, Off (case insensitive)

         Default:       True



         Type:          integer

         Value:         positive integer

         Default:       2 (MB)



         Type:          integer

         Value:         positive integer

         Default:       5 (files)



         Type:          character string

         Value:         HIGH, MEDIUM, LOW (case insensitive)

         Default:       MEDIUM



         Type:          character string

         Value:         SEVERE, ERROR, WARNING, INFO, FINE, FINEST (case insensitive)

         Default:       INFO



         Type:          character string

         Value:         path to directory containing log files

         Default:       current directory



CTS logging is amed at essential functionalities, simplicity and especiallly performance (logging can greatly impact your application’s performance). Therefore you have few possibilities to customize logging, but you can subclass CtsLogHandler and overwrite flush() and log() functions (like CtsLogConsoleHandler and CtsLogFileHandler) to handle writing to log destinations yourself e.g. to socket servers, Windows event loggers or Unix syslog daemons.


4. Other utility classes


This section describes briefly other utility classes. For more details please refer to the API documentation and test programs.

Execution Timer

The class CtsTimer is for calculating the time elapsed between a timer start and timer stop, it is exact to milliseconds, so it can be used to time how long an activity takes. The time difference is described by a structure called CtsTimeDiff, which has two fields for seconds and milliseconds.


Using CtsTimer is very simple, here is an example:


   CtsTimer timer;


   compress(buffer, size);


   CtsTimeDiff td = timer.getTimeDiff();

   console.println("compress completed after %d.%03d seconds",




Java-like String handling

CtsString is a subclass of std::string. This class is used internally by CTS to manipulate character strings. It provides following Java String-like functions:


bool             startsWith(const string& str) const;

bool             endsWith(const string& str) const;

bool             isEmpty() const;

bool             isWhiteSpace() const;

bool             equalsIgnoreCase(const string& str) const;

bool             equalsIgnoreCase(const char* cpszString) const;

long             hashCode() const;

const char*     getCString() const;

void             toUpper();

void             toLower();

const CtsString&     trim();

const char&      charAt( size_type loc ) const;

CtsString       substring( size_type index, size_type length = npos ) const;

void             replaceAll(const string& s1, const string& s2);


String tokenizer


Class CtsTokenizer is also another Java-like tokenizer for C++, not only provides it the possibility to tokenize a string by delimiters, but also allows tokenizing delimiters of different types, i.e. consecutive different delimiters can be tokenized as separate tokens. The following shows an example of CtsTokenizer in use.


   CtsTokenizer tokenizer(input, delims, true, true);

   while (tokenizer.hasMoreTokens()) {

      CtsString token = tokenizer.nextToken();




File information

The class CtsFileInfo provides some information about a file specified by a file path. It checks whether the path specifies a directory or a file, whether it exists on file systems, gets the file size, file name, extension and determines the absolute path to that file. On Unix-like platforms it also checks whether the file is readable, writable or executable by the program.

Directory information

The class CtsDirInfo is similar to CtsFileInfo in that, it gives information about a particular directory, whether the directory exists, calculate directory size, get parent name, get absolute path and also provides functions to navigate to children.


Configuration file

The class CtsConfigFile is for handling configuration files which satisfy following restrictions


- Section name is surrounded by square brackets and is in a separate line.

- Option is of the form option = value.

- Option name may contain spaces.

- A backslash \ indicates that the next line of also path of the current option.

- The hash sign # indicates begin of a comment.

- Special characters must be escaped (e.g. \\, \#, \=).


With this class you can walk through the sections and access their options by name. The test program tconfig will show you how it works.


5. Test programs


The test programs coming with CTS illustrate how you can parse program arguments using CtsConsole and also the use of other classes in logging, getting file, directory information, ...

tnow is a very simple test program, that shows current timestamp. You may try:

C:\> tnow
C:\> tnow -d
C:\> tnow –t


tconsole simulates the command-line interface of a compiler, which expects at least path to one source file. It then displays the option values and if the source file exists it does a hex dump of the content. For illustration purposes, no contraints among options are checked. You may try:


C:\> tconsole –c –o prog.exe –IC:\dev\cpp\include sourcefile.cpp

C:\> tconsole –-compile-only –o prog.exe sourcefile.cpp

C:\> tconsole –-compile-only –-output-file=prog.exe sourcefile.cpp


tlogger tests the logging functionality in single and multiple thread mode. It takes no parameter and will generate log files by default in directory log (specified in logging configuration file ctslogging.ini).

C:\ tlogger
CTS version 0.8x built at Oct 13 2010 23:06:34
TLOGGER - CTS test program

     Testing CTS logging with single thread
Test completed after 0.325 seconds

     Testing CTS logging with multiple threads
     Number of threads.......................: 10

Test completed after 3.221 seconds

The following log files will be generated:

13.10.2010  23:06         3.145.782 multithread.#1.log
13.10.2010  23:06         3.145.775 multithread.#2.log
13.10.2010  23:06         3.145.759 multithread.#3.log
13.10.2010  23:06         3.145.798 multithread.#4.log
13.10.2010  23:06         3.145.797 multithread.#5.log
13.10.2010  23:06         3.145.770 multithread.#6.log
13.10.2010  23:06         3.145.817 multithread.#7.log
13.10.2010  23:06         3.145.749 multithread.#8.log
13.10.2010  23:06         2.897.383 multithread.#9.log
13.10.2010  23:06         2.563.570 singlethread.#1.log


tmore simulates the more command but it does not show the file content, but only some information about the input file or directory (whether it exists, absolute path, file name, file type and size). You may try tmore as follows:


C:\>tmore ctsconsole.cpp
CTS version 0.86 built at Oct 13 2010 23:06:37
TMORE - CTS test program

     Enable extended feature.................: No
     Clear screen before displaying page.....: No
     Expand FormFeed characters..............: No
     Squeeze multiple blank lines............: No
     Expand tab size to......................: 8 (default)
     Start displaying the first file at line.: 1 (default)
     Input file..............................: ctsconsole.cpp
     Input exists............................: Yes
     Absolute path...........................: C:\code\cts\ctsconsole.cpp
     File name...............................: ctsconsole.cpp
     File type...............................: cpp
     File size in bytes......................: 13093


tlist simulates the dir command on Windows, it lists all files and directories in input path. Running tlist without parameters will list the content of current directory. By default it shows the modifiy timestamps of files and directories. You may run tlist as follows to show last change, last modify and last access timestamps respectively:


tlist –c

tlist –m

tlist –a



Sample output:

C:\code\cts>tlist ctslogger.cpp log
CTS version 0.86 built at Oct 13 2010 23:06:41
TLIST - List directory content

10/09/2010 00:08:55            11330 ctslogger.cpp

 Listing C:\Users\Linh Mai Tuan\code\cts\current\log

10/13/2010 22:35:55            <DIR> .
10/13/2010 22:35:55            <DIR> ..
10/13/2010 23:06:52       3145782 multithread.#1.log
10/13/2010 23:06:53       3145775 multithread.#2.log
10/13/2010 23:06:53       3145759 multithread.#3.log
10/13/2010 23:06:53       3145798 multithread.#4.log
10/13/2010 23:06:54       3145797 multithread.#5.log
10/13/2010 23:06:54       3145770 multithread.#6.log
10/13/2010 23:06:54       3145817 multithread.#7.log
10/13/2010 23:06:55       3145749 multithread.#8.log
10/13/2010 23:06:55       2897383 multithread.#9.log
10/13/2010 23:06:52       2563570 singlethread.#1.log



tconfig reads a configuration file as input and shows all configuration values. There is a sample configuration file testconfig.ini in CTS directory with which you will get following output:


C:\Users\Linh Mai Tuan\code\cts\current>tconfig -f testconfig.ini

     GlobalOption1...........................: ON
     GlobalOption2...........................: ON
     GlobalOption3...........................: ON

     Extension...............................: Vista
     Extension...............................: XP
     Extension...............................: MacOS
     Extension...............................: KDE
     Extension...............................: Gnome

     MIMEtypes...............................: MP3 WMA WAV FLV MP4 AVI
     Quality.................................: High
     Users...................................: user1 user2 user3
     Maximal screen size.....................: 1400 x 900




The test program testtokenizer demonstrates how strings can be tokenized by CtsTokenizer. It takes 2 parameters: the string to be tokenized and an optional string containing delimiters. You may try it as follows:


Note: the option value for delimiters in this case may start with either a minus or a plus sign which may be considered as command-line option. In POSIX, two consecutive dash –– should indicates that everything comes after it is option values. CtsConsole supports this.


C:\> ttokenizer -i "1+(2+3)*(4+5)+(6-7)" -d -- "-+*()"

C:\> ttokenizer -i "123ab456cd789" -d "abcd"



6. Using CTS


Using CTS in your code is simple, you only need to include the header file cts.hpp and if needed specify that the namespace cts is being used. You need to either put CTS include directory in your environment variable INCLUDE or specify it as compiler argument to compile your code. On Windows, CTS is compiled as a dynamic-link library, the cts.dll and cts.lib files will be created in directory lib.  The cts.lib must be provided at link time and cts.dll must be found at run time. You need to add this directory to your PATH environment variable so that the system can find it. Test program executables are found in directory bin.

On Windows, you can regenerate documentation from code with Doxygen. The file doxyfile in CTS directory is the configuration file for this purpose. Documentation in HTML format will be generated in directory doc. 


Compiling CTS and test programs

Currently, CTS supports only Visual C++ compiler and NMAKE on Windows, GNU g++ compiler and MAKE on Unix.


On Windows

1.     Extract CTS to a directory (e.g. cts)

cd cts

2.     Set the path and environment variables for command-line builds by running vcvars32.bat (usually found at %VCINSTALLDIR%\bin\vcvars32.bat)


3.     Rename makefile_Win32 to makefile

ren makefile_Win32 makefile

4.     Run NMAKE to build CTS and test programs, executables are generated in bin, DLL is generated in lib.


5.     If you have doxygen installed, run nmake gendoc to generate API Documentation.

nmake gendoc

6.     Run setCtsPath.cmd to set add CTS to library path


7.     Now you can run test programs: tlogger, tconsole, tmore, tconfig, tlist, tnow

tconsole -?


On Unix/Linux

1.     Extract CTS to a directory (e.g. cts)

$ mkdir cts

$ cd cts

$ unzip –d .

2.     Rename makefile_Unix to makefile

$ mv makefile_Unix makefile

3.     Run MAKE to build CTS and test programs, executables are generated in bin, DLL is generated in lib.

$ make

4.     Run . (note the dot) to add CTS to library path.

$ .

5.     Now you can run test programs: tlogger, tconsole, tmore, tconfig, tlist, tnow

$ tconsole -?


If you have problems compiling CTS and test programs, you may contact us at project hompage (, we will try to help you as soon as we can.

7. Limitations

- CTS is compiled as DLL on Windows. If you use CTS in your code, you MAY have to compile it with the same compiler version as you compiled CTS library file to avoid the name mangling problem.


8. License

CTS is open source and freely available under Eclipse Public License 1.0.


9. Version history

Version 0.86 (Oct 17th 2010)

- New logging interface

- Support direct logging and buffered logging

- Bug fixes in CtsConfigFile, CtsTimer

- Update CtsUtils


Version 0.85 (May 9th 2010)

- New classes CtsDirInfo, CtsConfigFile

- New logging features: logging configuration, Nested Diagnostic Context (NDC)

- CtsUtils::calculateDirectorySizeNonRecursive

- Bug fixes in CtsConsole, CtsString

- Bug fix in makefile for Windows that prevents user code from linking with C++ runtime library

- Makefile for Linux, compiled as shared library

- Makfile dependencies using g++ -MM on Debian

- Debug with debenv Windows 

- Unix makefile debug and ship flags


Version 0.84 (March 6th 2010)

- Introduce new classes CtsLogger, CtsFileInfo, CtsTimer

- Bug fixes in CtsConsole, CtsString

- Some interface change in CtsConsole

- Code documentation


10. Feedback

We appreciate your feedbacks, bug reports, feature requests, recommendations and critiques. Please contact us at Sourceforge or write to linhmt[at]gmail[dot]com.



[1] The POSIX and GNU argument syntax convention