I have a library that uses wstring extensively. I need to output changes and external data using NSLog. There is a simple way (not too expensive) for wstring output using an intermediate function. Converting each wstring to an NSString using va_list is the only way I can think of right now.
Edit : Additional fixes. I have a multi-platform library. I added the MYLog registration macro.
Edit I need to call MYLog from C ++, and I do not have access to Objective-C at this point. So the problem is that I cannot convert std :: wstring before calling MYLog.
Through MYLog, I would like to be able to use NSLog or intermediate, for example:
MYLog("Received %ls(%d) from user %ls %ls cp: %ls /nRAW:/t%ls", &d.name, d.id, &d.user.firstName, &d.user.lastName, &d.caption, &d.rawText);
Here (originally from here ) I found this nice addition to NSString
@interface NSString (cppstring_additions) +(NSString*) stringWithwstring:(const std::wstring&)string; +(NSString*) stringWithstring:(const std::string&)string; -(std::wstring) getwstring; -(std::string) getstring; @end @implementation NSString (cppstring_additions) #if TARGET_RT_BIG_ENDIAN const NSStringEncoding kEncoding_wchar_t = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32BE); #else const NSStringEncoding kEncoding_wchar_t = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32LE); #endif +(NSString*) stringWithwstring:(const std::wstring&)ws { char* data = (char*)ws.data(); unsigned size = ws.size() * sizeof(wchar_t); NSString* result = [[NSString alloc] initWithBytes:data length:size encoding:kEncoding_wchar_t]; return result; } +(NSString*) stringWithstring:(const std::string&)s { NSString* result = [[NSString alloc] initWithUTF8String:s.c_str()]; return result; } -(std::wstring) getwstring { NSData* asData = [self dataUsingEncoding:kEncoding_wchar_t]; return std::wstring((wchar_t*)[asData bytes], [asData length] / sizeof(wchar_t)); } -(std::string) getstring { return [self UTF8String]; } @end
All I could think about without spending too much time (mine) was to create an intermediate function called my MYLog:
#define LAD(data) [logString appendFormat:[NSString stringWithFormat:@"%%%@", c], data] #define LAP(type) LAD(va_arg(listPointer, type)) void MyLogImplementation(NSString* message, ...) { NSMutableString* logString = [[NSMutableString alloc] init]; va_list listPointer; va_start(listPointer, message); NSArray* lmc = [message componentsSeparatedByString:@"%"]; int counter = 0; //NSLog(@"there are %d components in %@.", [lmc count], message); BOOL ignoreNext = NO; for (NSString* c in lmc) { //NSLog(@"Testing %@", c); if (ignoreNext) { [logString appendFormat:@"%%%@", c]; ignoreNext = NO; } if (0 == [c length]) { ignoreNext = !ignoreNext; } else if (0 == counter && '%' != [message characterAtIndex:0] ) { [logString appendFormat:@"%@", c]; } else { switch ([c characterAtIndex:0]) { case 'd': case 'i': LAP(int); break; case 'X': case 'x': LAP(int); break; case '@': LAP(NSObject*); break; case 'f': LAP(double); break; case 'c': LAP(char); break; case 'l': switch ([c characterAtIndex:1]) { case 's': { std::wstring* str = va_arg(listPointer, std::wstring*); NSString* nstr = [NSString stringWithwstring:str]; [logString appendFormat:@"%@", nstr]; [nstr release]; if (2 < [c length]) { [logString appendString:[c substringFromIndex:2]]; } } break; } break; default: [logString appendFormat:[NSString stringWithFormat:@"%%%@", c]]; } } ++counter; } NSLog(@"%@", logString); [logString release]; va_end(listPointer); }
But this, it seems to me, is very inefficient. Is there a better way to achieve what I am doing? I know that I can just convert this to:
NSLog(@"Received %@(%d) from user %@ %@ cp: %@ /nRAW:/t%@", [NSString stringWithwstring:d.name], d.id, [NSString stringWithwstring:d.user.firstName], [NSString stringWithwstring:d.user.lastName], [NSString stringWithwstring:d.caption], [NSString stringWithwstring:d.rawText]);
And the problem will be solved. But I would lose the advantage in the movie ... I think.