Created
September 26, 2017 18:11
[2017-09-26] Challenge #333 [Easy] Packet Assembler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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