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.
Any advice will be appreciated.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; }
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.



LinkBack URL
About LinkBacks



