Artistic Style Developer Information

Calling Artistic Style from an Objective‑C Program

 

Artistic Style can be compiled as a shared library (DLL) or a static library and linked with an Objective‑C program. This is usually done on a Mac OS computer. However,  Objective‑C on Windows and Linux contains information on compiling and running Objective‑C programs using GNUstep. It has instructions for compiling the following example program on Windows or Linux.

Compile Options

To compile AStyle for use with an Objective‑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

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.

NSZoneMalloc is typically used to allocate variable sized memory. An error in this results in a NSMallocException. This means that exception handling must be used to catch the error. If instead, a “C” malloc function is used, the error results in a NULL return. In this case it simplifies the error handling since the NULL is simply returned to AStyle. The example program uses malloc instead of NSZoneMalloc.

A NSZoneMalloc 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

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.m

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

#include <Foundation/Foundation.h>

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

// functions to call AStyleMain
char* STDCALL AStyleGetVersion();
char* STDCALL AStyleMain(const char* pSourceIn,
                         const char* pOptions,
                         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(NSString* message) __attribute__((noreturn));
NSString* getProjectDirectory(const NSString* subPath);
NSString* getText(NSString* filePath);
void  setText(const NSString* textOut, NSString* filePath);


// Main function for this example.
int main()
{
#if __has_feature(objc_arc)    // clang directive
    @autoreleasepool
#else
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
#endif
    {   // options to pass to AStyle
        const NSArray* fileNames = [NSArray arrayWithObjects:
                                            @"AStyleDev/test-data/ASBeautifier.cpp",
                                            @"AStyleDev/test-data/ASFormatter.cpp",
                                            @"AStyleDev/test-data/astyle.h",
                                            nil];
        const NSString* options = @"-A2tOP";

        // get Artistic Style version
        const char* versionChar = AStyleGetVersion();
        NSLog(@"Example Obj-C - AStyle %s", versionChar);

        // process the input files
        for (NSString* fileName in fileNames)
        {   // get the text to format
            NSString* filePath = getProjectDirectory(fileName);
            NSString* textIn = getText(filePath);

            // call the Artistic Style formatting function
            char* textOutChar = AStyleMain([textIn UTF8String],
                                           [options UTF8String],
                                           ASErrorHandler,
                                           ASMemoryAlloc);

            // does not need to terminate on an error
            // an error message has been displayed by the error handler
            if (textOutChar == NULL)
                error([NSString stringWithFormat: @"Cannot format %@", fileName]);

            // return the formatted text
            NSString* textOut = [NSString stringWithUTF8String: textOutChar];
            NSLog(@"Formatted %@", fileName);
            setText(textOut, filePath);

            // free the buffer allocated with malloc
            // Malloc is used instead of NSZoneMalloc to simplify the error handling.
            // Malloc errors result in a NULL return instead of a NSMallocException.
            free(textOutChar);
            textOutChar = NULL;
        }
        //    system("pause");
    }
#if !__has_feature(objc_arc)    // clang directive
    [pool drain];
#endif
    return EXIT_SUCCESS;
}

// Error handler for the Artistic Style formatter.
void  STDCALL ASErrorHandler(int errorNumber, const char* errorMessage)
{   NSLog(@"astyle error %d", errorNumber);
    NSLog(@"%s", errorMessage);
}

// Allocate memory for the Artistic Style formatter.
// Malloc is used instead of NSZoneMalloc to simplify the error handling.
// Malloc errors result in a NULL return instead of a NSMallocException.
char* STDCALL ASMemoryAlloc(unsigned long memoryNeeded)
{   char* buffer = malloc(memoryNeeded);
    return buffer;
}

// Error message function for this example.
void error(NSString* message)
{   NSLog(@"%@", message);
    NSLog(@"The program has terminated!");
    exit(EXIT_FAILURE);
}

// Prepend the project directory to the subpath.
// This may need to be changed for your directory structure.
NSString* getProjectDirectory(const NSString* subPath)
{
#ifdef _WIN32
    char* homeDirectoryChar = getenv("USERPROFILE");
#else
    char* homeDirectoryChar = getenv("HOME");
#endif
    if (!homeDirectoryChar)
        error(@"Cannot find HOME directory");
    NSString* homeDirectory =
        [NSString stringWithCString: homeDirectoryChar
                           encoding: [NSString defaultCStringEncoding]];
    NSString* projectPath = [NSString stringWithFormat: @"%@/%@/%@",
                                      homeDirectory, @"Projects", subPath];
    return projectPath;
}

// Get the text to be formatted and convert to a NSString.
// Usually the text would be obtained from an edit control.
NSString* getText(NSString* filePath)
{   NSString* textIn = [NSString stringWithContentsOfFile: filePath
                                                 encoding: NSASCIIStringEncoding
                                                    error: NULL];
    if (!textIn)
        error([NSString stringWithFormat: @"Cannot open input file %@", filePath]);
    return textIn;
}

// Return the formatted text.
// Usually the text would be returned to an edit control.
void setText(const NSString* textOut, NSString* filePath)
{   // create a backup file
    NSFileManager* fm = [NSFileManager defaultManager];
    NSString* origfilePath =  [NSString stringWithFormat: @"%@%@", filePath, @".orig"];
    if ([fm fileExistsAtPath: origfilePath])
        [fm removeItemAtPath: origfilePath
                       error: NULL];
    if (![fm moveItemAtPath: filePath
                     toPath: origfilePath
                      error: NULL])
        NSLog(@"Cannot create backup for %@", filePath);
    // write the text
    [textOut writeToFile: filePath
              atomically: YES
                encoding: NSASCIIStringEncoding
                   error: NULL];
}