I had a good weekend this weekend. The most obvious thing about this weekend was that I designed a logging mechanism for my broker component. The whole idea is to log at different levels and allow the configuration to specify which levels you’d like to show. So If you want high-level logs you’d say so and the other detailed logs will not be shown. So you add different logging calls such as log0(),log1(), or whatever and you can turn those logging instructions off depending on what you tell the program to log.

Anyway, I spend the whole day doing it and then while standing in the shower afterwards, realised that I’d over engineered it and replaced it with a simple solution in 5 minutes! I was thinking, “Surely there has to be an easier way than this way I’m doing?”. I wonder if I’d not over engineered it, would I have come up with a similar solution or could I have just started there(perhaps I should have started there?). On the plus side was I implemented a function that uses va_list as a argument which allows me to pass in variable parameters to other functions, which in itself was a carry over from my complex design which as it happens was necessary to implement the simpler design – so not all lost!

This is a print statement very much like vsprintf which allows you to pass in a va_list, and it will print out all the characters and replace those that need replacing with the variable parameters indicated by the va_list parameter :

void VPRINT(char*msg, va_list argp)	
{	
	for(char *p=msg;*p;p++) {	
		if(*p != '%') { putchar(*p); continue; }	
		switch(*++p) {	
			case 'd':	
				printf("%d", va_arg(argp,int));	
				break;	
			case 's':	
				printf("%s", va_arg(argp,char*));	
		}
	
	}
	
}

This can only interpret %s and %d for strings and integer parameters passed as the additional args to the VPRINT() function.

Which now can be called like this from as variadic function, and use the extra parameters itself to do whatever it want to do with them:

void log0(int loglevel, char* message, ...)
{
	if(loglevel > 0)
	    return;
	char *buffer;
	asprintf(&buffer, "log0: %s\t%s", TIM_GetDateTimeStr(),message);
	va_list argp;
	va_start(argp, buffer);
		VPRINT(buffer, argp);
	va_end(argp);
	free(buffer);
	buffer = 0;	
}

So that was my Saturday wiped out. Its not usual that I do that, but I was feeling inspired to work on my broker because I found new inspiration when looking at the proxy-generation routine which I wrote in perl(I look at it now and go huh? what?), and I was like – hmm that's actually a pretty cool thing I created. What it is, is you can generate a bunch on c-functions from a defined list of function declarations so you can arrange to call one of the generated functions dynamically when the protocol message states that you should do, and you usher with the provided parameters into the call – so you need the call to exist, so i generate it automatically each time I add a new function to the interface. Here is a typical protocol message that can be sent to the server, to which the server needs to call the function with the params in the message:

{ "request-type" : SERVICE_REQUEST }
{ "message-id": 3456789 }	
{ "sender-address" : "127.0.0.1" }
{ "reply-port": 8090 }
{ "op"=>"getServerDate" }
{ "params" => [ buffer, length, ... ] }

This allows me to add functions to the interface and then have the proxy-generation script read those and generate the function bodies and then arrange for the parameters passed over the wire to be loaded into those function call invocations. This kind of stuff you just take for granted with C# and WSDL.

So when I get told that I need to run the getServerDate() function with the parameters, I can call that function dynamically – this isn’t as easy in C as in a higher language that does OOP and reflection easily.

I also decided to go to the gym on Sunday, Not bad eh.