Currently I am building two apps for my project one in release & another in debug (the only thing that changes are provisioning profiles used to sign and the endpoints) . Because of some policies, I shouldn't be creating ipa files locally. So I use maven to build these two versions (release & debug), based on a script. Because of the same policies, output should be complete removed from the application (NSLog, printf...). I am aware of the preprocessor macros, but I don't want to rely on them, since someone (without knowing) might change them and jeopardise what I want to achieve. So what I want is:
Be able to logout anything I want when I am using my simulator or when I run directly on a real device
When I use maven to build my applications, it will make sure the NSLogs are stripped or disabled.
Maven relies on what's in a remote repository to actually make the build, so if there is a way of disabling this logs during the remote repo commit, it's a solution as well..
Use this macro it will automatically off log on release mode.
Just replace all NSLog with DLog and in future use DLog for logging.
Example : DLog(#"Text : %#",sometext);
#ifdef DEBUG
# define DLog(fmt, ...) NSLog((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
# define DLog(...)
#endif
It's an interesting request, but feasible if you're willing to accept a bit of function-call overhead for each log that gets skipped. There is a nice feature inside of the EtPanKit framework that checks if the files that are trying to call the log function match an array of pre-defined classes in your Info.plist file. In addition to being a great debug filter, all you'd have to do at Release time is remove all the keys from the plist or specify a different one in your Release build with no values associated with the LEPLogEnabledFilenames key.
In the interest of preventing link-rot, here's the function itself and the associated macros that make it a bit prettier to call:
#define LEPLogStack(...) LEPLogInternal(__FILE__, __LINE__, 1, __VA_ARGS__)
#define LEPLog(...) LEPLogInternal(__FILE__, __LINE__, 0, __VA_ARGS__)
#import <Foundation/Foundation.h>
#import <libgen.h>
#import <time.h>
#import <sys/time.h>
#include <execinfo.h>
#include <pthread.h>
static NSSet * enabledFilesSet = nil;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void LEPLogInternal(const char * filename, unsigned int line, int dumpStack, NSString * format, ...)
{
va_list argp;
NSString * str;
NSAutoreleasePool * pool;
char * filenameCopy;
char * lastPathComponent;
struct timeval tv;
struct tm tm_value;
//NSDictionary * enabledFilenames;
pool = [[NSAutoreleasePool alloc] init];
pthread_mutex_lock(&lock);
if (enabledFilesSet == nil) {
enabledFilesSet = [[NSSet alloc] initWithArray:[[NSUserDefaults standardUserDefaults] arrayForKey:LEPLogEnabledFilenames]];
}
pthread_mutex_unlock(&lock);
NSString * fn;
fn = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:filename length:strlen(filename)];
fn = [fn lastPathComponent];
if (![enabledFilesSet containsObject:fn]) {
[pool release];
return;
}
va_start(argp, format);
str = [[NSString alloc] initWithFormat:format arguments:argp];
va_end(argp);
NSString * outputFileName = [[NSUserDefaults standardUserDefaults] stringForKey:LEPLogOutputFilename];
static FILE * outputfileStream = NULL;
if ( ( NULL == outputfileStream ) && outputFileName )
{
outputfileStream = fopen( [outputFileName UTF8String], "w+" );
}
if ( NULL == outputfileStream )
outputfileStream = stderr;
gettimeofday(&tv, NULL);
localtime_r(&tv.tv_sec, &tm_value);
fprintf(outputfileStream, "%04u-%02u-%02u %02u:%02u:%02u.%03u ", tm_value.tm_year + 1900, tm_value.tm_mon + 1, tm_value.tm_mday, tm_value.tm_hour, tm_value.tm_min, tm_value.tm_sec, tv.tv_usec / 1000);
//fprintf(stderr, "%10s ", [[[NSDate date] description] UTF8String]);
fprintf(outputfileStream, "[%s:%u] ", [[[NSProcessInfo processInfo] processName] UTF8String], [[NSProcessInfo processInfo] processIdentifier]);
filenameCopy = strdup(filename);
lastPathComponent = basename(filenameCopy);
fprintf(outputfileStream, "(%s:%u) ", lastPathComponent, line);
free(filenameCopy);
fprintf(outputfileStream, "%s\n", [str UTF8String]);
[str release];
if (dumpStack) {
void * frame[128];
int frameCount;
int i;
frameCount = backtrace(frame, 128);
for(i = 0 ; i < frameCount ; i ++) {
fprintf(outputfileStream, " %p\n", frame[i]);
}
}
if ( outputFileName )
{
fflush(outputfileStream);
}
[pool release];
}
I understand you don't want to rely pre-processor macros, but there is a simple way to remove any NSLog statements using the pre-processor:
Add to your prefix header the following:
#ifndef DEBUG
#define NSLog(...)
#endif
If DEBUG is not defined, then all NSLog statements will removed by the pre-processor throughout the app code.
If DEBUG is not added automatically in your build settings, you can simply add a #define DEBUG statement and comment it out when your build for release.
The same can be done for printf() statements.
I've used this successfully in an app I've released for getting rid of NSLog for release.
You can add a complete log system like this:
#ifndef Logs_h
#define Logs_h
/* Log levels */
#define LOG_LEVEL_NO_LOG 0
#define LOG_LEVEL_ONLY_ERRORS 1
#define LOG_LEVEL_ERROS_AND_WARNINGS 2
#define LOG_LEVEL_LOG_ALL 3
/* Log levels */
#ifdef DEBUG
#define LOG_LEVEL LOG_LEVEL_LOG_ALL /* <-- Change The Log Level here */
#else
#define LOG_LEVEL LOG_LEVEL_NO_LOG /* No logs on release now */
#endif
/* Logs Macros */
#if LOG_LEVEL >= LOG_LEVEL_LOG_ALL
#define DebugLog(fmt, ...) NSLog(#"[Debug] %s [Line %d]: " fmt, __PRETTY_FUNCTION__, __LINE__, ## __VA_ARGS__)
#else
#define DebugLog(...) /* */
#endif
#if LOG_LEVEL >= LOG_LEVEL_ERROS_AND_WARNINGS
#define WarnLog(fmt, ...) NSLog(#"[Warning] %s [Line %d]: " fmt, __PRETTY_FUNCTION__, __LINE__, ## __VA_ARGS__)
#else
#define WarnLog(...) /* */
#endif
#if LOG_LEVEL >= LOG_LEVEL_ONLY_ERRORS
#define ErrorLog(fmt, ...) NSLog(#"[Error] %s [Line %d]: " fmt, __PRETTY_FUNCTION__, __LINE__, ## __VA_ARGS__)
#else
#define ErrorLog(...) /* */
#endif
#endif
Related
When I have the following C source code, which is running on an IBM i Midrange, then I get a non-zero result from pthread_create, specifically 3025, which is ENOENT (No such path or directory), which doesn't make any sense to me. Anyone have any thoughts on what the error actually means in this context.
#define _MULTI_THREADED
#define _XOPEN_SOURCE 520
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
void* workerThread(void* parm) {
// Do some work here
pthread_exit(NULL);
}
int main(int argc, char* argv[]) {
pthread_t t;
int rc;
rc = pthread_create(&t, NULL, workerThread, NULL);
if (rc != 0) {
char *msg = strerror(errno);
perror("pthread_create failed");
}
// Other code here
return 0;
}
pthread_create doesn't set errno. You should be checking strerror of rc.
http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_create.html
char *msg = strerror(rc);
I am trying to build a network scanner.
I know the procedure so I want to ping all available hosts in the network and then get the ARP table so I can map the MAC address for each IP.
I Googled for ARP table but I didn't find any guide how to implement this feature.
I also found these similar questions on Stack overflow:
Link1
Link2
The answer are unclear on how to implement the ARP feature.
Is there any official guide for this one? Is Apple approving the ARP table feature?
UPDATE AFTER 10.2
Check the library here
I finally got it working so I will post the procedure in detail to save some time for other guys:
Go to Applications and right click on Xcode -> Show package contents and browse to: Developer ▸ Platforms ▸ MacOSX.platform ▸ Developer ▸ SDKs ▸ MacOSX10.10.sdk ▸ usr ▸ include. From "net" folder copy the route.h and if_types.h and from the "netinet" folder copy the if_ether.h into your Xcode project.
Then import the following .m and .h files:
MacFinder.h
#import <Foundation/Foundation.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include "if_types.h"
#if TARGET_IPHONE_SIMULATOR
#include <net/route.h>
#else
#include "route.h"
#endif
#include "if_ether.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#interface MacFinder : NSObject{
int nflag;
}
-(NSString*) ip2mac: (char*)ip;
#end
MacFinder.m
#import "MacFinder.h"
#implementation MacFinder
-(NSString*) ip2mac: (char*)ip
{
int found_entry = 0;
NSString *mAddr = nil;
u_long addr = inet_addr(ip);
int mib[6];
size_t needed;
char *host, *lim, *buf, *next;
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin;
struct sockaddr_dl *sdl;
extern int h_errno;
struct hostent *hp;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS;
mib[5] = RTF_LLINFO;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
err(1, "route-sysctl-estimate");
if ((buf = malloc(needed)) == NULL)
err(1, "malloc");
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
err(1, "actual retrieval of routing table");
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
sin = (struct sockaddr_inarp *)(rtm + 1);
sdl = (struct sockaddr_dl *)(sin + 1);
if (addr) {
if (addr != sin->sin_addr.s_addr)
continue;
found_entry = 1;
}
if (nflag == 0)
hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
sizeof sin->sin_addr, AF_INET);
else
hp = 0;
if (hp)
host = hp->h_name;
else {
host = "?";
if (h_errno == TRY_AGAIN)
nflag = 1;
}
if (sdl->sdl_alen) {
u_char *cp = LLADDR(sdl);
mAddr = [NSString stringWithFormat:#"%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]];
// ether_print((u_char *)LLADDR(sdl));
}
else
mAddr = nil;
}
if (found_entry == 0) {
return nil;
} else {
return mAddr;
}
}
#end
Then import the MacFinder.h file in your ViewController
Example how to use it for each host you want to find the MAC Address:
MacFinder *mc = [[MacFinder alloc]init];
NSString *mac = [mc ip2mac:"192.168.10.24"];
NSLog(#"Mac:%#",mac);
If you still having trouble here is tutorial and here the full working project (Including the necessary files)
I followed the tutorial for compiling SQLCipher on iOS devices using a binary located here: http://sqlcipher.net/sqlcipher-binaries-ios-and-osx/
I've made several changes to build settings, adding header search path and C flags. Then after testing a compile of the sqlcipher, i didn't get any errors with the binary, but errors that did not exist before with FMDB started showing up like this:
FMDatabaseAdditions.m:137:19: Implicit declaration of function 'NSFileTypeForHFSTypeCode' is invalid in C99`
FMDatabaseAdditions.m:137:19: Implicit conversion of 'int' to 'NSString *' is disallowed with ARC`
FMDatabaseAdditions.m:137:15: Incompatible integer to pointer conversion initializing 'NSString *__strong' with an expression of type 'int'`
FMDatabaseAdditions.m:158:96: Values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead`
FMDatabaseAdditions.m:161:28: Implicit declaration of function 'NSHFSTypeCodeFromFileType' is invalid in C99`
This error occurs when you play with targets in your project. The NSFileTypeForHFSTypeCode is only needed when you compile project against Mac OS target and should not be used if target is iPhone. Actually, on the new versions of XCode it seems the error occurs even if your project is targeted as iPhone .
Old answer:
So we must rewrite applicationIDString implementation and put conditional flags:
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
- (NSString*)applicationIDString {
NSString *s = NSFileTypeForHFSTypeCode([self applicationID]);
assert([s length] == 6);
s = [s substringWithRange:NSMakeRange(1, 4)];
return s;
}
#endif
The condition if TARGET_OS_MAC will not replace the need of !TARGET_OS_IPHONE because TARGET_OS_IPHONE is actually a variant of TARGET_OS_MAC. So to avoid compile errors, add #if TARGET_OS_MAC && !TARGET_OS_IPHONE
Also below that part of code:
- (void)setApplicationIDString:(NSString*)s {
if ([s length] != 4) {
NSLog(#"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]);
}
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
[self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:#"'%#'", s])];
#endif
}
New answer:
I updated the code and rearranged methods to be more grouped on scope (conditions) in FMDatabaseAdditions.m :
#if SQLITE_VERSION_NUMBER >= 3007017
- (uint32_t)applicationID {
uint32_t r = 0;
FMResultSet *rs = [self executeQuery:#"pragma application_id"];
if ([rs next]) {
r = (uint32_t)[rs longLongIntForColumnIndex:0];
}
[rs close];
return r;
}
- (void)setApplicationID:(uint32_t)appID {
NSString *query = [NSString stringWithFormat:#"pragma application_id=%d", appID];
FMResultSet *rs = [self executeQuery:query];
[rs next];
[rs close];
}
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
- (NSString*)applicationIDString {
NSString *s = NSFileTypeForHFSTypeCode([self applicationID]);
assert([s length] == 6);
s = [s substringWithRange:NSMakeRange(1, 4)];
return s;
}
- (void)setApplicationIDString:(NSString*)s {
if ([s length] != 4) {
NSLog(#"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]);
}
[self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:#"'%#'", s])];
}
#endif
#endif
Also to avoid other warnings I modified FMDatabaseAdditions.h
#if SQLITE_VERSION_NUMBER >= 3007017
///-----------------------------------
/// #name Application identifier tasks
///-----------------------------------
/** Retrieve application ID
#return The `uint32_t` numeric value of the application ID.
#see setApplicationID:
*/
- (uint32_t)applicationID;
/** Set the application ID
#param appID The `uint32_t` numeric value of the application ID.
#see applicationID
*/
- (void)setApplicationID:(uint32_t)appID;
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
/** Retrieve application ID string
#return The `NSString` value of the application ID.
#see setApplicationIDString:
*/
- (NSString*)applicationIDString;
/** Set the application ID string
#param string The `NSString` value of the application ID.
#see applicationIDString
*/
- (void)setApplicationIDString:(NSString*)string;
#endif
#endif
It looks to be a bug in FMDB (https://github.com/ccgus/fmdb/issues/163) - the code in question is only meant to compile in OSX.
I am trying to compile glib in ios, i have got an error in gio/tests/appinfo-test.h
#include <stdlib.h>
#include <gio/gio.h>
int
main (int argc, char *argv[])
{
const gchar *envvar;
gint pid_from_env;
envvar = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE_PID");
g_assert (envvar != NULL);
pid_from_env = atoi (envvar);
g_assert_cmpint (pid_from_env, ==, getpid ());
envvar = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE");
g_assert_cmpstr (envvar, ==, SRCDIR "/appinfo-test.desktop"); //got the error here that "Use of undefined identifier 'SRCDIR' "
return 0;
}
please help me out...Thank you
I can not figure out with given information how you tried to compile the sample code in your ios, but you can add
#define SRCDIR
before main().
The sample code seems to be glib/gio/tests/appinfo-test.c in the source repository. SRCDIR is defined as -DSRCDIR=\""$(srcdir)"\" in the Makefile.am.
I am using Borland C++ Builder 6, on an XP PC. When I compiled a software unit that made reference to crtdbg file, I received the following error messages:
/* Borland version of Microsoft CRTDBG.H header file
This is used by MFC and ATL.
*/
/*
* C/C++ Run Time Library - Version 11.0
*
* Copyright (c) 1999, 2002 by Borland Software Corporation
* All Rights Reserved.
*
*/
/* $Revision: 9.4.2.1 $ */
#ifndef _INC_CRTDBG
#define _INC_CRTDBG
#ifndef __UTILCLS_H
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Prototypes for internal RTL helper functions: */
void _ErrorMessage(const char *__message);
void _ErrorExit (const char *__message);
#ifdef __cplusplus
}
#endif
/* Asserts */
#if !defined(_DEBUG)
#define _ASSERT(expr) ((void)0)
#define _ASSERTE(expr) ((void)0)
#else /* !defined(_DEBUG) */
#define _ASSERT(a) _ASSERTE(a)
#define _ASSERTE(expr) do { \
if (!(expr) && __ASSERTE_Helper (#expr, __FILE__, __LINE__) == IDCANCEL) \
::DebugBreak(); \
} while (0)
/* _ASSERTE helper routine returns: MB_YES, MB_NO or MB_CANCEL
*/
__inline int __ASSERTE_Helper(bool expr, char *file, int line)
{
TCHAR msg[256*2];
::wsprintf(msg, _T("%s failed - %s/%d"), expr, file, line);
/* throw (msg); */
_ErrorExit(msg);
return 0; /* Never really gets here */
}
#endif /* !defined(_DEBUG) */
#endif /* __UTILCLS_H */
#endif /* _INC_CRTDBG */
[C++ Error] crtdbg.h(52): E2268 Call to undefined function '_T'
[C++ Error] crtdbg.h(52): E2034 Cannot convert 'int' to 'const char *'
[C++ Error] crtdbg.h(52): E2340 Type mismatch in parameter 2 (wanted 'const char *', got 'int')
What's wrong with it?
You should add the TCHAR.H include (or a Borland equivalent).
_T() is a macro that converts 8-bit strings into wide character format.