Skip to content

Instantly share code, notes, and snippets.

@jacobmcnamee
Created September 26, 2017 18:11
[2017-09-26] Challenge #333 [Easy] Packet Assembler
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
/* Element in linked list of packets */
typedef struct packet_s {
int id;
char *str;
struct packet_s *next;
} packet_t;
/* Element in linked list of messages */
typedef struct message_s {
int id;
int packet_count; /* Number of packets received so far */
int packet_total; /* Total number of packets in message */
packet_t *packets_list;
struct message_s *next;
} message_t;
static int packet_alloc = 0;
static int message_alloc = 0;
static packet_t *packet_new(int id, const char *str)
{
assert(str != NULL);
packet_t *p = (packet_t *)malloc(sizeof(*p));
assert(p != NULL);
char *str_copy = (char *)malloc(strlen(str) + 1);
assert(str_copy != NULL);
strcpy(str_copy, str);
*p = (packet_t) {
.id = id,
.str = str_copy,
.next = NULL
};
packet_alloc++;
return p;
}
static void packet_delete(packet_t **p)
{
assert(p != NULL);
assert(*p != NULL);
assert((*p)->str != NULL);
free((*p)->str);
free(*p);
*p = NULL;
packet_alloc--;
}
static void packets_list_delete(packet_t **root)
{
assert(root != NULL);
while (*root != NULL) {
packet_t *next = (*root)->next;
packet_delete(root);
*root = next;
}
}
static void packet_insert(packet_t **root, int id, const char *str)
{
assert(root != NULL);
packet_t **p = root;
while ((*p != NULL) && ((*p)->id < id)) {
p = &(*p)->next;
}
packet_t *next = *p;
*p = packet_new(id, str);
(*p)->next = next;
}
static void packet_print(packet_t *p)
{
assert(p != NULL);
printf("%d %s\n", p->id, p->str);
}
static void packets_list_print(packet_t *root)
{
assert(root != NULL);
packet_t *p = root;
while (p != NULL) {
packet_print(p);
p = p->next;
}
}
static message_t *message_new(int id, int packet_total)
{
message_t *m = (message_t *)malloc(sizeof(*m));
assert(m != NULL);
*m = (message_t) {
.id = id,
.packet_count = 0,
.packet_total = packet_total,
.packets_list = NULL,
.next = NULL
};
message_alloc++;
return m;
}
static void message_delete(message_t **m)
{
assert(m != NULL);
assert(*m != NULL);
packets_list_delete(&(*m)->packets_list);
free(*m);
*m = NULL;
message_alloc--;
}
/* Returns a pointer to the 'next' field pointing to the
* desired message struct */
static message_t **message_lookup(message_t **root, int id)
{
assert(root != NULL);
message_t **m = root;
while (*m != NULL) {
if ((*m)->id == id) {
return m;
}
m = &(*m)->next;
}
return NULL;
}
static void message_print(message_t *m)
{
printf("%d %d/%d\n", m->id, m->packet_count, m->packet_total);
packets_list_print(m->packets_list);
}
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
message_t *messages_list = NULL;
char line[1024];
while (fgets(line, sizeof(line), stdin) != NULL) {
int msg_id, packet_id, packet_total;
char str[1024];
int sscanf_ret = sscanf(line, "%d %d %d %1023[^\n]",
&msg_id, &packet_id, &packet_total, str);
if (sscanf_ret == 3) {
str[0] = '\0';
} else if (sscanf_ret != 4) {
printf("invalid input line: %s\n", line);
return 0;
}
message_t **m = message_lookup(&messages_list, msg_id);
if (m == NULL) {
/* Insert new message at top of list */
message_t *m_new = message_new(msg_id, packet_total);
m_new->next = messages_list;
messages_list = m_new;
m = &messages_list;
}
packet_insert(&(*m)->packets_list, packet_id, str);
if (++((*m)->packet_count) == (*m)->packet_total) {
/* Print and then delete completed message */
message_print(*m);
message_t **prev = m;
message_t *next = (*m)->next;
message_delete(m);
*prev = next;
}
}
#ifdef DEBUG
printf("message alloc: %d\n", message_alloc);
printf("packet alloc: %d\n", packet_alloc);
#endif
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment