I gave up with creating a packet function which takes a va_list of arguments to create a packet with specific byte sizes. The main reason for this is that va_list automatically converts everything to type int so that defeats the entire purpose.
In my last attempt I attempted to:
1) calculate the memory space needed for the specific packet based from the format string
2) calloc the memory required in bytes
3) start the va_list and loop inserting them into the memory
This is where it falls apart. va_arg converts everything to int even if you tell it otherwise. I tried to bypass this by using memcpy to place the variable inside the buffer, but this was a failed since va_arg converted all our data into one size, int. Here is the fail code for that lol
Code
char *createPacket(const char* formats, ...) {
va_list argument_list;
int formatsLength = sizeof(formats);
int bufferLength = 0;
int i = 0;
int holder = 0;
char *buffer = NULL;
for(i = 0; i < formatsLength; i++) {
if(formats[i] == 'B')
bufferLength += 1;
else if (formats[i] == 'H')
bufferLength += 2;
else if (formats[i] == 'L')
bufferLength += 4;
else if (formats[i] == 'Q')
bufferLength += 8;
}
buffer = malloc(bufferLength);
bufferLength = 0;
va_start(argument_list, formats);
for(i = 0; i < formatsLength; i++) {
holder = va_arg(argument_list, int);
if(formats[i] == 'B') {
memcpy(buffer+bufferLength, &holder, sizeof(uint8_t));
bufferLength += 1;
} else if (formats[i] == 'H') {
memcpy(buffer+bufferLength, &holder, sizeof(uint16_t));
bufferLength += 2;
} else if (formats[i] == 'L') {
memcpy(buffer+bufferLength, &holder, sizeof(uint32_t));
bufferLength += 4;
} else if (formats[i] == 'Q') {
memcpy(buffer+bufferLength, &holder, sizeof(uint64_t));
bufferLength += 8;
}
}
va_end(argument_list);
return buffer;
}
I also tried using sprintf() but it pads the data with nullbytes, although easy to remove, it also made it a pain to use. Not to mention that it doesn't quite generate the same data has a struct memory blob would. Also it's a pain to have to prefix everything thing with their type size: u, hu, lu, llu.
The method I think will be easiest and actually work now is to just define a structure per packet inside its decoding or encoding function. This way I know it's going to work because I use this method all the time for other data projects, and I have easy to set/get access to all variables in the packet by way of overlaying received data over the packet structure:
Code
int main() {
struct packet {
uint16_t hmm;
uint16_t hmm2;
uint8_t hmm3;
uint64_t hmm4;
};
char *data = malloc(sizeof(struct packet));
struct packet *pSend = malloc(sizeof(struct packet));
pSend->hmm = 1;
pSend->hmm2 = 2;
pSend->hmm3 = 3;
pSend->hmm4 = 4;
memcpy(data, pSend, sizeof(struct packet));
struct packet *pGet = (struct packet*)data;
free(pSend);
free(pGet);
free(data);
return 1;
}

Using this method may make the code longer since I have to define every packet structure for each packet type, but it maintains the ease of use quality which is nice. The only thing better would be if I could create the original packet creator function so that it actually accepts multi arguments and doesn't jew over their types.