Archive

Archive for July, 2009

Display std::wstring in Xcode using a Data Formatter

July 21st, 2009 10 comments

std::wstring: unsafe, but sometimes necessary

When dealing with cross-platform code, especially Windows, it is not uncommon to encounter wchar_t and its companion string class, std::wstring.

Unfortunately, Xcode does not display these types natively. Yes, you can add this file to your .gdbinit file and then you will be able to type:

    pwstring mystring

but what you really want is for the values to show up in Xcode’s variable display, and in tooltips.

What you need is called a Custom Data Formatter.

In this post, I will adapt Apple’s sample wchar_t data formatter and modify it to display std::wstring variables. I will also explain where you should put this formatter in Xcode 3.1.

Complete source code is available on bitbucket.org, with a MIT license.

Initial Data Formatter

Xcode Data Formatters are simple bundles that are loaded by Xcode at startup. They are essentially plug-ins to extend Xcode.

Starting with Apple’s own wchar_t Data Formatter sample, we immediately notice that:

  • This sample is quite outdated, almost 4 years old (the Release build actually builds only PPC!)
  • It won’t work as-is with std::wstring since it only contains .c files.

We will update this sample to work with std::wstring and build it as a 4-way universal binary.

Modernizing the Data Formatter

Switching to C++

Since the data formatter will use std::wstring, we need to build it using C++. Just rename all the .c files to .cpp and voilà!

Modify CustomDataViews.plist

If you open CustomDataViews.plist, you will see that it has one entry per variable type that the formatter can handle. That entry contains a Data Formatter, much like the one you would type in Xcode itself (for example, to display the name of a notification—of type NSNotification—you can use {(NSString *)[$VAR name]}).
What is different here is the formatter contains a string that calls back in our custom Data Formatter: for example, wchar_t corresponds to {(char *)myWCharDataFormatter((wchar_t) $VAR, (int) $ID)}:s.
Add two entries to that plist, for types wstring and wstring*, and replace the callback strings with a new unique string, for instance myWStringDataFormatter and myWStringPointerDataFormatter. Watch for capitalization, case matters.

Add new callback functions

Now add the two callback functions you referenced in the plist in myCustomFormatter.cpp:

#include <string>

char * myWStringDataFormatter(std::wstring wstr, int identifier)
{
	size_t bufLen = wstr.size() + 1; 
	return dataformatter_char_for_wchar(wstr.data(), identifier, bufLen);
}

char * myWStringPointerDataFormatter(std::wstring *wstr, int identifier)
{
	size_t bufLen = wstr->size() + 1; 
	return dataformatter_char_for_wchar(wstr->data(), identifier, bufLen);
}

As you can see, we are re-using the preexisting wchar_t code with our std::wstring.

Build a 4-way Universal Binary

Double-click the wchardataformatter project icon to bring up the Project Inspector. Select the Release configuration, and click the “Architectures” pop-up menu. Select 32/64 bit universal, as shown below.

Universal Architecture in Xcode

Modify the Test Code

Finally, update wcharTest_main.cpp to add new std::wstring variables to display in the debugger:

#include <stdlib.h>
#include <wchar.h>
#include <string>

int main(int argc, char *argv[])
{
	wchar_t c = 'A';
	wchar_t b[255];
	wchar_t *d = &b[0];
	char *a = "a b c d e f g";
	mbstowcs(d, a , strlen(a));
	std::wstring s = L"wide string";
	std::wstring *ps = &s;
	return 0;
}

Switch the target to wCharTest in Xcode, set a breakpoint on the last line, and hit “Build and Go”. Xcode should build the test application and stop in the Debugger. Since you have not installed the formatter, you should not see anything special in the Variable Display window.

Installing the Data Formatter

Build the Data Formatter (Debug or Release). Locate the bundle by control-clicking on the “Products / wcharDataFormatter.bundle” in the Xcode project.
Drag the bundle to this folder: ~/Library/Application\ Support/Developer/Shared/Xcode/CustomDataViews, creating intermediate folders along the way if they do not exist.
You can remove the ~ to install for all users (not just you), and you can also replace “Shared” in the path with “3.0″ or “3.1″ if you only wanted to install the formatter for Xcode 3.0 or 3.1.

Testing the Formatter

Build the wcharTest target, and set a breakpoint in the main() function of wcharTest_main.cpp. You can step over each line, and you should see your data formatter being called and displaying in Xcode’s Variable Display, as well as in tooltips (Xcode 3.1 and later).

Formatter Display in Xcode

Categories: Development, MacOSX Tags: