Artistic Style Developer Information

Calling Artistic Style from a C++ Program

 

Artistic Style can be compiled as a shared library (DLL) or a static library and linked with a C or C++ program.

Compile Options

To compile AStyle for use with a C or C++ program the compile option ASTYLE_LIB must be defined. Then AStyle will accept the files and options as parameters from a function call. It is the responsibility of the calling program to read the source files and accept the options from the user via a graphical interface or other method. These are then passed via the function call. After the source files are formatted they will be returned to the calling program, which must then save the source file and take other appropriate action.

Visual Studio users can also use the option ASTYLE_NO_VCX (no Visual C exports) to remove the __declspec(dllexport) definition from Visual C. Use this only for static libraries or when the AStyle source is included in the compile. Do NOT use this when compiled as a shared (dynamic) library. It is effective only for Visual Studio 2012 and higher. It will NOT work with previous versions. It has no effect with other compilers since they require a separate option to create the import library and export files.

The source can also be included in a program or another shared library (DLL) instead of being compiled by itself. It should be compiled with the options ASTYLE_LIB (and ASTYLE_NO_VCX for Visual C) to get the function call instead of the console build. Then include it with the other source modules and call it using the AStyleMain function.

AStyleMain Function

This function is called to format the source code.

Syntax

extern "C"
char* STDCALL AStyleMain(const char* pSourceIn,
                         const char* pOptions,
                         void (STDCALL* fpError)(int, char*),
                         char* (STDCALL* fpAlloc)(unsigned long));

Parameters

pSourceIn
A pointer to the source file to be formatted.

pOptions
A pointer to the formatting options. They should be in the same format as in the default options file. The options may be set apart by new-lines, commas, tabs or spaces. The long options do not need the "--" prefix. Comments may be used but they must be terminated by a new-line "\n" character.

If the file is not a C/C++ file, the file mode option "mode=java" or "mode=cs" must be included. Otherwise the default mode of C/C++ is used.

fpError
A pointer to the error handling function. If there are errors in the parameters pSourceIn or pOptions, this function is called. It should display an error message and then either abort or continue the program depending on the error. The first parameter is a number identifying the error. The second parameter is a pointer to a standard error message.

Error messages numbered 100-199 are errors that prevent the file from being formatted. A NULL pointer is returned to the calling program. Error messages numbered 200-299 are errors that do NOT prevent the file from being formatted. A valid pointer and a formatted file are returned. This will occur if an invalid option is sent to AStyleMain. The calling program has the option of accepting or rejecting the formatted file.

fpAlloc
A pointer to the memory allocation function. The calling program must allocate memory for the output source file. This function will be called when the memory is needed. The parameter is the amount of memory that should be allocated.

Memory should be allocated using the operator "new (nothrow)". With this method, if there is an allocation exception, Artistic Style will generate an error message and return a NULL pointer from the AStyleMain function. The calling program can handle the exception at this point rather than in the memory allocation function. See the following example program for the procedure.

A "new" without "(nothrow)" can be used if you want, but do not abort the program in the memory allocation function. An error message may be printed but return a NULL pointer to AStyle and handle the error when AStyle returns from formatting the text.

The calling program is responsible for freeing the allocated memory when it is no longer needed.

Return Value

If the function succeeds, the return value is a pointer to the formatted source code.

If the function fails, the return value is NULL. Before the NULL is returned, an error message will be sent to the error handling function.

This function typically fails for one of the following reasons:

The function will NOT fail for an invalid option in the formatting options. In this case an error message is sent to the error handling function and the formatted source code is returned without using the invalid option.

Remarks

The STDCALL macro is defined for Windows as __stdcall. It is needed if AStyle is compiled as a Windows shared library (DLL). For Linux it is defined but does not have a value.

The calling program is responsible for freeing the memory allocated by fpAlloc when it is no longer needed.

AStyleGetVersion Function

This function is called to get the Artistic Style version number.

Syntax

extern "C"
char* STDCALL AStyleGetVersion();

Return Value

A pointer to the Artistic Style version number.

Remarks

The STDCALL macro is defined for Windows as __stdcall. It is needed if AStyle is compiled as a Windows shared library (DLL). For Linux it is defined but does not have a value.

Example

The following example formats source files by calling the Artistic Style formatter. It is a console application, but the procedure for a GUI is the same. The example can be copied and pasted into a source file. Or it can be downloaded with test data from the "Developer Information" page. The source code for Artistic Style must be added as a shared library (DLL), a static library, or included with the example source.

 

        
// Example.cpp

/* This program calls the Artistic Style formatter (AStyleMain)
 * to format the astyle source files in a test-data directory.
 */

#include <stdlib.h>
#include <string>
#include <fstream>
#include <iostream>
#if defined(__GNUC__)
    #include <string.h>     // need both string and string.h for GCC
#endif

using namespace std;

// allow for different calling conventions in Linux and Windows
#ifdef _WIN32
    #define STDCALL __stdcall
#else
    #define STDCALL
#endif

// functions to call AStyleMain
extern "C" const char* STDCALL AStyleGetVersion(void);
extern "C" char* STDCALL AStyleMain(const char* sourceIn,
                                    const char* optionsIn,
                                    void (STDCALL* fpError)(int, const char*),
                                    char* (STDCALL* fpAlloc)(unsigned long));
void  STDCALL ASErrorHandler(int errorNumber, const char* errorMessage);
char* STDCALL ASMemoryAlloc(unsigned long memoryNeeded);

// other functions
void error(const string message);
string getProjectDirectory(const string& subPath);
char* getText(const string& filePath);
void  setText(const char* textOut, const string& filePathStr);


// Main function for this example.
int main(int, char**)
{   // options to pass to AStyle
    const string fileName[] = { "AStyleDev/test-data/ASBeautifier.cpp",
                                "AStyleDev/test-data/ASFormatter.cpp",
                                "AStyleDev/test-data/astyle.h"
                              };
    const char* options = "-A2tOP";
    size_t arraySize = sizeof(fileName) / sizeof(fileName[0]);

    // get Artistic Style version
    const char* version = AStyleGetVersion();
    cout << "Example C++ - AStyle " << version << endl;

    // process the input files
    for (size_t i = 0; i < arraySize; i++)
    {   // get the text to format
        string filePath = getProjectDirectory(fileName[i]);
        char* textIn = getText(filePath);

        // call the Artistic Style formatting function
        char* textOut = AStyleMain(textIn,
                                   options,
                                   ASErrorHandler,
                                   ASMemoryAlloc);

        // does not need to terminate on an error
        // an error message has been displayed by the error handler
        if (textOut == NULL)
            error(string("Cannot format " + filePath));

        // return the formatted text
        cout << "Formatted " << fileName[i] << endl;
        setText(textOut, filePath);

        // must delete the temporary buffers
        delete [] textIn;
        delete [] textOut;
    }

//    system("pause");
    return EXIT_SUCCESS;
}

// Error handler for the Artistic Style formatter.
void  STDCALL ASErrorHandler(int errorNumber, const char* errorMessage)
{   cout << "astyle error " << errorNumber << "\n"
         << errorMessage << endl;
}

// Allocate memory for the Artistic Style formatter.
char* STDCALL ASMemoryAlloc(unsigned long memoryNeeded)
{   // error condition is checked after return from AStyleMain
    char* buffer = new(nothrow) char [memoryNeeded];
    return buffer;
}

// Error message function for this example.
void error(string message)
{   cout << message << endl;
    cout << "The program has terminated!" << endl;
    exit(EXIT_FAILURE);
}

// Prepend the project directory to the subpath.
// This may need to be changed for your directory structure.
string getProjectDirectory(const string& subPath)
{
#ifdef _WIN32
    char* homeDirectory = getenv("USERPROFILE");
#else
    char* homeDirectory = getenv("HOME");
#endif
    if (!homeDirectory)
        error("Cannot find HOME directory");
    string projectPath = string(homeDirectory) + "/Projects/" + subPath;
    return projectPath;
}

// Get the text to be formatted.
// Usually the text would be obtained from an edit control.
char* getText(const string& filePath)
{   // open input file
    ifstream in(filePath.c_str());
    if (!in)
        error("Cannot open input file " + filePath);

    // get length of buffer
    const int bufferSizeIn = 131072;     // 128 KB

    // allocate memory
    char* bufferIn = new(nothrow) char [bufferSizeIn];
    if (bufferIn == NULL)
    {   in.close();
        error("Memory allocation failure on input");
    }

    // read data as a block
    in.read(bufferIn, bufferSizeIn);
    // get actual size - must be smaller than buffer size
    int textSizeIn = static_cast<int>(in.gcount());
    if (textSizeIn > bufferSizeIn)
    {   in.close();
        error("Read buffer is too small");
    }
    bufferIn[textSizeIn] = '\0';
    in.close();

    return bufferIn;
}

// Return the formatted text.
// Usually the text would be returned to an edit control.
void setText(const char* textOut, const string& filePathStr)
{   // create a backup file
    const char* filePath = filePathStr.c_str();
    string origfilePathStr = filePathStr + ".orig";
    const char* origfilePath = origfilePathStr.c_str();
    remove(origfilePath);              // remove a pre-existing file

    if (rename(filePath, origfilePath) < 0)
        error("Cannot open input file " + filePathStr);

    // open the output file
    ofstream out(filePath);
    if (!out)
        error("Cannot open output file " + filePathStr);

    // write the text
    size_t textSizeOut = strlen(textOut);
    out.write(textOut, static_cast<streamsize>(textSizeOut));
    out.close();
}