I have some C code in a static library that I'm compiling into an iPhone app. I'd like to print some debug messages to the console; is there something like NSLog I should use? I'm guessing NSLog only works for the Objective-C parts of the program.
EDIT: fprintf(stdout, fmt...) and fprintf(stderr, fmt...) don't work either.. any idea why they don't? Should they work?
you can always do the classic:
fprintf(stderr, "hi, this is a log line: %s", aStringVariable);
You can make a wrapper for NSLog if you mix Objective-C code like this:
log.h
void debug(const char *message, ...) __attribute__((format(printf, 1, 2)));
log.m
#import <Foundation/Foundation.h>
#import "log.h"
void debug(const char *message,...)
{
va_list args;
va_start(args, message);
NSLog(#"%#",[[NSString alloc] initWithFormat:[NSString stringWithUTF8String:message] arguments:args]);
va_end(args);
}
and then, in your C file:
#include "log.h"
...
debug("hello world! variable: %d", num);
Other solution:
#include <CoreFoundation/CoreFoundation.h>
extern "C" void NSLog(CFStringRef format, ...);
#define MyLog(fmt, ...) \
{ \
NSLog(CFSTR(fmt), ##__VA_ARGS__); \
}
MyLog("val = %d, str = %s", 123, "abc");
While printf will show up if you're debugging from XCode, it won't show up in the Organizer Console. You can use what NSLog uses: CFLog or syslog.
#include <asl.h>
...
asl_log(NULL, NULL, ASL_LEVEL_ERR, "Hi There!");
Note that lower priority levels such as ASL_LEVEL_INFO may not show up in console.
You should be able to see printf or fprintf statements. Try running some of the code in the library but from the terminal, something should appear if not. A much more complicated (and even silly/stupid/wrong) method that I will guarantee you that will work would be:
sprintf(message,"This is a log line %s",someString);
system("echo %s",message);
If that doesn't work then you probably have something weird in your code.
Note: This will probably only work in the simulator.
You probably need to use the Apple System Log facility to get the output into the device console.
Check the functions in usr/asl.h.
asl_open
asl_new
asl_set
asl_log
asl_free
While printf will show up if you're debugging from XCode, it won't show up in the Organizer Console. You can run the following command to print only to device's console:
syslog(LOG_WARNING, "log string");
You will also need to #include <sys/syslog.h> for syslog and LOG_WARNING to be explicitly declared
Related
I am quite new to using pcap lib, so please bear with me.
I am trying to use pcap_getnonblock function, the documentation says the following:
pcap_getnonblock() returns the current 'non-blocking' state of
the capture descriptor; it always returns 0 on 'savefiles' . If
there is an error, PCAP_ERROR is returned and errbuf is filled in
with an appropriate error message.
errbuf is assumed to be able to hold at least PCAP_ERRBUF_SIZE
chars.
I got -3 returned and the errbuf is an empty string, I couldn't understand the meaning of such result.
I believe this caused a socket error: 10065.
This problem happened only once and I could not reproduce it, but still it would be great to find its causing to prevent it in future executions.
Thanks in advance.
pcap_getnonblock() can return -3 - that's PCAP_ERROR_NOT_ACTIVATED. Unfortunately, that's not documented; I'll fix that.
Here's a minimal reproducible example that demonstrates this:
#include <pcap/pcap.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
pcap_t *pcap;
char errbuf[PCAP_ERRBUF_SIZE];
if (argc != 2) {
fprintf(stderr, "Usage: this_program <interface_name>\n");
return 1;
}
pcap = pcap_create(argv[1], errbuf);
if (pcap == NULL) {
fprintf(stderr, "this_program: pcap_create(%s) failed: %s\n",
argv[1], errbuf);
return 2;
}
printf("pcap_getnonblock() returns %d on non-activated pcap_t\n",
pcap_getnonblock(pcap, errbuf));
return 0;
}
(yes, that's minimal, as 1) names of interfaces are OS-dependent, so it has to be a command-line argument and 2) if you don't run the program correctly, it should let you know what's happening, so you know what you have to do in order to reproduce the problem).
Perhaps pcap_getnonblock() and pcap_setnonblock() should be changed so that you can set non-blocking mode before activating the pcap_t, so that, when activated, it will be in non-blocking mode. It doesn't work that way currently, however.
I.e., you're allocating a pcap_t with pcap_create(), but you're not activating it with pcap_activate(). You need to do both in order to have a pcap_t on which you can capture.
I will try to use gnu-gettext for localization of a semi-big software project, so now I'm trying to learn the basics. Problem is that I got stuck on a pretty fundamental function. When I try to extract the strings from the sourcecode using xgettext I get nothing. When dll's were missing it complained, and when a parameter is wrong it complains, but now it just silently returns without producing any pot-file or anything else.
So, my question is:
Is there anybody out there recognizing this problem?
Is there any way to make xgettext more verbose about what it is doing?
I have tried putting xgettext among the source-files and putting the sourcefiles in the gettext\bin directory, but to no avail.
I should mention that I am working on a Win7-machine and I use gettext-tools-dev_0.18.1.1-2_win32. I have installed MinGW.
My testcode locks like this:
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include "libintl.h"
#include "locale.h"
#include "helper.h"
#define _(String) gettext(String)
#define N_(String) String
//#define textdomain(Domain)
//#define bindtextdomain(Package, Directory)
int main(void)
{
printf( "setlocale returns %s\n", setlocale( LC_ALL, "" ) );
bindtextdomain( "hello", "locale" );
textdomain( "hello" );
int a = 1;
int b = 2;
/// First string
printf( _( "Hello, world!\n" ) );
std::string multiline =
/* Another string */
_( "This is a " \
"multi line string." );
// A string that contains another
printf( _( "A string: %s\n" ), multiline.c_str() );
printf( N_( "An untranslatable string!\n" ));
int foo = 42;
/// Playing with positions; int before string in original...
printf( _( "int: %1$d, string: %2$s\n" ), foo, _( "Fubar" ));
printf( _( "%1$s %2$s\n" ), Helper::String1().c_str(), Helper::String2().c_str() );
exit(0);
}
If somebody could help me out on this, I would be thankful.
/Robert
Ok, I solved it. I somehow thought that xgettext would understand the redefinition:
#define _(String) gettext(String)
Well, obviously it didn't and when I read the manual carefully it kind of said that as well.
So when I added -k_ to the xgettext options it all worked.
/Robert
I got a bunch of NSLog statements in my code. Is there anyway I can suppress them from executing in production, but execute when I'm developing? I want to not comment them out, and them put them back in when developing, as it's a hassle.
DEBUG is a macro that is only defined (xcode default) when you are doing a debug/development build of your project. This will cause any code between the #ifdef DEBUG and #endif lines to not be included when doing a release build but they will be compiled and included with a debug/dev/test build.
Example:
#ifdef DEBUG
NSLog(#"Hello World!");
#endif
This is what I use in my Project-Prefix.pch file (called with DEBUGLOG(#"abc %#", someStr);):
#ifdef DEBUG
extern void DBGQuietLog(NSString *format, ...);
#define DEBUGLOG(fmt, ...) DBGQuietLog((#"[Line: %d] %s: " fmt), __LINE__, __FUNCTION__, ##__VA_ARGS__);
#else
#define DEBUGLOG(fmt, ...)
#endif
#ifdef DEBUG
void DBGQuietLog(NSString *format, ...) {
if (format == nil) {
printf("nil\n");
return;
}
va_list argList;
va_start(argList, format);
NSString *s = [[NSString alloc] initWithFormat:format arguments:argList];
printf("%s\n", [[s stringByReplacingOccurrencesOfString:#"%%" withString:#"%%%%"] UTF8String]);
[s release];
va_end(argList);
}
#endif
This prints console lines (only when debugging) with line number, class name, and method name like so:
[Line: 36] -[iPhoneAppDelegate application:didFinishLaunchingWithOptions:]: Hello World!
You could make a proxy and define it as a preprocessor macro:
#ifdef DEBUG
#define MyLog(str, ...) NSLog(str, ##__VA_ARGS__)
#else
#define MyLog(str, ...)
#endif
Then you'd use MyLog() instead of NSLog() in your code and when not compiling in debug mode the NSLog would be replaced with a no-op.
As an extension to CajunLuke's answer, I can only advise you to use this: http://kdl.nobugware.com/post/2009/03/11/better-nslog/
Wrap them with a macro. It's unfortunate that Apple doesn't do this already, with a "canned" solution, but many folks do it, and there are a number of examples on the web.
Something like:
#ifdef DEBUG_MODE
#define DebugLog( s, ... ) NSLog(#"<%#:(%d)> %#", [NSString stringWithUTF8String __PRETTY_FUNCTION__], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DebugLog( s, ... )
#endif
(Hopefully got that right -- copied by hand from another screen)
I'm following the suggestion in the answer here for redirecting NSLog output on an iOS device to a file, which works great. The problem is that it no longer shows up in the console on the device. What I'd really like is a way to tee the stderr stream to both the console and the file. Does anyone have an idea how to do that?
I found an acceptable answer on another thread (NSLog() to both console and file).
The solution provided there is to only redirect to a file if a debugger is not detected, like this:
if (!isatty(STDERR_FILENO))
{
// Redirection code
}
Thanks to Sailesh for that answer.
Once you freopen() the file descriptor, you can read from it and do as you please with the data. Some ideas from this will be useful to you.
You could either write it back out to stdout, or try to write directly to /dev/console. I've never tried to open /dev/console on an iPhone, but I'm guessing it's possible despite being outside of the sandbox. I'm not sure how the app review process will treat it.
Or you can redirect to a TCP socket and view on a remote telnet client. No need for XCode this way!
Basically:
Create a standard C function which calls an Obj-C static method:
void tcpLogg_log(NSString* fmt, ...)
{
va_list args;
va_start(args, fmt);
[TCPLogger tcpLog:fmt :args];
va_end(args);
}
The static Obj-C method:
(void)tcpLog:(NSString*)fmt :(va_list)args
{
NSLogv(fmt, args);
if(sharedSingleton != nil && sharedSingleton.socket != nil)
{
NSString *time = [sharedSingleton.dateFormat stringFromDate:[NSDate date]];
NSString *msg = [[NSString alloc] initWithFormat:fmt arguments:args];
mach_port_t tid = pthread_mach_thread_np(pthread_self());
NSString *str = [NSString stringWithFormat:#"%#[%X]: %#\r\n", time, tid, msg];
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
[sharedSingleton.socket writeData:data
withTimeout:NETWORK_CLIENT_TIMEOUT_PERIOD
tag:0];
}
}
Then in your .pch file, add the following lines to override NSLog()
define NSLog(...) tcpLogg_log(__VA_ARGS__);
void tcpLogg_log(NSString* fmt, ...);
Of course more details are required to handle the TCP Socket. Working source code is available here:
https://github.com/driedler/iOS-TCP-Logger/wiki/About
I have stdin in a select() set and I want to take a string from stdin whenever the user types it and hits Enter.
But select is triggering stdin as ready to read before Enter is hit, and, in rare cases, before anything is typed at all. This hangs my program on getstr() until I hit Enter.
I tried setting nocbreak() and it's perfect really except that nothing gets echoed to the screen so I can't see what I'm typing. And setting echo() doesn't change that.
I also tried using timeout(0), but the results of that was even crazier and didn't work.
What you need to do is tho check if a character is available with the getch() function. If you use it in no-delay mode the method will not block. Then you need to eat up the characters until you encounter a '\n', appending each char to the resulting string as you go.
Alternatively - and the method I use - is to use the GNU readline library. It has support for non-blocking behavior, but documentation about that section is not so excellent.
Included here is a small example that you can use. It has a select loop, and uses the GNU readline library:
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <stdbool.h>
int quit = false;
void rl_cb(char* line)
{
if (NULL==line) {
quit = true;
return;
}
if(strlen(line) > 0) add_history(line);
printf("You typed:\n%s\n", line);
free(line);
}
int main()
{
struct timeval to;
const char *prompt = "# ";
rl_callback_handler_install(prompt, (rl_vcpfunc_t*) &rl_cb);
to.tv_sec = 0;
to.tv_usec = 10000;
while(1){
if (quit) break;
select(1, NULL, NULL, NULL, &to);
rl_callback_read_char();
};
rl_callback_handler_remove();
return 0;
}
Compile with:
gcc -Wall rl.c -lreadline