Hello there,
Great forum, I don't know how I didn't find it before.
So my problem is, I'm trying to write a C version of perl's pack function.
It's not a homework or something, I was trying to create an ICQ client, and found myself over and over again manually creating the packets.
So I thought in creating a pack function, which would make my life easier.
Anyway, I wrote one, but I feel it can be really improved.
And here's where I need some help - improving this code.
Any advice will really help.
So I wont post all the code, because it's pretty useless to do so.
I removed similar cases and some error handling, to make the code easier to be read.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
char *pack( char *format, ... )
{
va_list parameters;
char *buffer = NULL;
char *pBuffer = buffer;
char *pFormat = format;
long lSize = 0;
char *tmp;
va_start( parameters, format );
while( *pFormat != '\0' )
{
if( *pFormat == 'C' )
{
/*
* signed char
*/
signed char c;
c = va_arg( parameters, int );
++lSize;
if( ( tmp = realloc( buffer, lSize ) ) == NULL )
{
perror( "realloc: " );
free( buffer );
return NULL;
}
else
{
buffer = tmp;
pBuffer = buffer+lSize-1;
*pBuffer = c;
}
}
else if( *pFormat == 'c' )
{
/*
* unsigned char
*/
unsigned char c;
c = va_arg( parameters, int );
++lSize;
if( ( tmp = realloc( buffer, lSize ) ) == NULL )
{
perror( "realloc: " );
free( buffer );
return NULL;
}
else
{
buffer = tmp;
pBuffer = buffer+lSize-1;
*pBuffer = c;
}
}
else if( *pFormat == 'n' )
{
/*
* unsigned short, 16bits, big endian
*/
unsigned short n = va_arg( parameters, int );
long lComplement = 2;
lSize += lComplement;
if( ( tmp = realloc( buffer, lSize ) ) == NULL )
{
perror( "realloc: " );
free( buffer );
return NULL;
}
else
{
buffer = tmp;
pBuffer = buffer+lSize-lComplement;
*pBuffer = n >> 8;
++pBuffer;
*pBuffer = n & 0x00ff;
}
}
else if( *pFormat == 'v' )
{
/*
* unsigned short, 16 bits, little endian
*/
unsigned short n = va_arg( parameters, int );
long lComplement = 2;
lSize += lComplement;
if( ( tmp = realloc( buffer, lSize ) ) == NULL )
{
perror( "realloc: " );
free( buffer );
return NULL;
}
else
{
buffer = tmp;
pBuffer = buffer+lSize-lComplement;
*pBuffer = n & 0x00ff;
++pBuffer;
*pBuffer = n >> 8;
}
}
else if( *pFormat == 'a' )
{
/*
* NUL padded string
*/
char *s = va_arg( parameters, char* );
long lComplement = strlen( s );
lSize += lComplement;
if( ( tmp = realloc( buffer, lSize ) ) == NULL )
{
perror( "realloc: " );
free( buffer );
return NULL;
}
else
{
buffer = tmp;
pBuffer = buffer+lSize-lComplement;
memcpy( pBuffer, s, lComplement );
}
}
else if( *pFormat == 'A' )
{
/*
* Space padded string
*/
char *s = va_arg( parameters, char* );
char *pString = s;
long lComplement = 0;
while( *pString != ' ' )
{
++lComplement;
++pString;
}
lSize += lComplement;
if( ( tmp = realloc( buffer, lSize ) ) == NULL )
{
perror( "realloc: " );
free( buffer );
return NULL;
}
else
{
buffer = tmp;
pBuffer = buffer+lSize-lComplement;
memcpy( pBuffer, s, lComplement );
}
}
else if( *pFormat == 'N' )
{
/*
* unsigned long, 32bits, big endian
*/
//0x12345678
unsigned long n = va_arg( parameters, unsigned long );
long lComplement = 4;
lSize += lComplement;
if( ( tmp = realloc( buffer, lSize ) ) == NULL )
{
perror( "realloc: " );
free( buffer );
return NULL;
}
else
{
buffer = tmp;
pBuffer = buffer+lSize-lComplement;
*pBuffer = n >> 24;
++pBuffer;
*pBuffer = ( ( n & 0xff0000) >> 16 );
++pBuffer;
*pBuffer = ( ( n & 0xff00 ) >> 8 );
++pBuffer;
*pBuffer = n & 0xff;
}
}
++pFormat;
}
/*
* before returning, add a NUL char at the end
*/
++lSize;
tmp = realloc( buffer, lSize );
if( tmp == NULL )
{
perror( "realloc: " );
return NULL;
}
else
{
buffer = tmp;
pBuffer = buffer+lSize-1;
*pBuffer = '\0';
}
va_end( parameters );
return buffer;
}
Any advice will be appreciated.
Thanks in advance, and have a nice day.
PS: I'm sorry the code alignment isn't that good, I'll try to do better next time.