I found it necessary to write a logging method in “C” that printed not only a variable argument list but also the formatting text that the list of arguments applies to. A search of the web yielded lots of samples but they all printed just the arguments and not the formatting text (minus the % escapes).

So after a small bit of research into va_start, va_end, va_list and va_arg I came up with the following bit of logging code:

First the support code:

void LogDate(FILE *fd)
{
char buffer[256];

time_t now = time(NULL);
struct tm *ftm=localtime(&now);
sprintf(buffer,"%d-%02d-%02d|",ftm->tm_year+1900,ftm->tm_mon+1,ftm->tm_mday);
fprintf(fd,buffer);
sprintf(buffer,"%02d:%02d:%02d|",ftm->tm_hour,ftm->tm_min,ftm->tm_sec);
fprintf(fd,buffer);
}

Now the Logging code, the code executes in a loop processing the passed in string looking for formatting code, then using a switch statement and simple “if” statements, generates the appropriate output for the given datatype formatting.

void LogInfo(char *fmt, ...)
{
FILE *fd;
va_list ap;
int d;
char c, *s;
int i,len;

if((fd=fopen(LOGFILE, "a+"))!=NULL)
{
len = strlen(fmt);
LogDate(fd);
va_start(ap, fmt);
for(i=0;i
{
switch(fmt[i])
{
case '%':
i++;
if(fmt[i]=='s')
{
s = va_arg(ap, char *);
fprintf(fd,"%s", s);
}
if((fmt[i]=='d')||(fmt[i]=='i'))
{
d = va_arg(ap, int);
fprintf(fd,"%d", d);
}
if(fmt[i]=='c')
{
c = (char) va_arg(ap, int);
fprintf(fd,"%c", c);
}
break;
default:
fprintf(fd,"%c", fmt[i]);
break;
}
}
fprintf(fd,"\n");
fclose(fd);
va_end(ap);
}
}

How to use it

The example calls the logging function and passes a string with the formatting embedded in it, the output routine will search the string and identify the correct format handling code and generate the correct output.

void myFunction()
{
......
LogInfo("OPEN [%s]", pDirPtr->d_name);
......
}

Enjoy!

Advertisements