Code:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
struct pktnode
{
int pkt_id;
char *message;
struct pktnode *next;
};
struct messagenode
{
int msg_id;
int prefix_len;
char id_prefix[3];
struct pktnode *pkthead;
struct messagenode *next;
};
FILE *fp;
char *packet;
struct messagenode *head_msg, *save_msg, *current_msg;
struct pktnode *head_pkt, *save_pkt, *current_pkt;
#define DELIM ":"
void initiate(char *filename);
void populateInList(char *packet);
struct messagenode *getMsgNode();
struct pktnode *getPktNode();
struct messagenode *search_msg(int msg_id);
struct pktnode *search_pkt(int pkt_id);
void getPacketInfo(char *packet, int *msg_id, int *pkt_id, char *message, int *prefix_len_msg);
void display();
void cleanUpAll();
void sortMsg();
int getlen(char *arg);
int main(int argc, char **argv)
{
/* Argument checking section */
if(argc != 2)
{
printf("Please provide one message data file\n");
return -1;
}
/* Perform necessary program initiation steps */
initiate(argv[1]);
/* Main Loop */
while(1)
{
/* Grab packet from file */
fgets(packet, 2001, fp);
/* If no packet remaining or END packet received then stop processing */
if(packet == NULL || !strcmp(packet, "END\n")|| !strcmp(packet, "END"))
break;
/* function to process and populate packet in linked list*/
populateInList(packet);
}
/* Sort the message linked list, i.e. the outer one */
sortMsg();
/* Display the list data structure */
display();
/* Post process routines. file close + freeing allocated memories */
cleanUpAll();
return 0;
}
void initiate(char *filename)
{
head_msg = NULL;
head_pkt = NULL;
/* Opening packet data file */
fp = fopen(filename, "r");
if(fp == NULL)
{
printf("Unable to open %s\n", filename);
exit(0);
}
packet = (char *)malloc(2000 * sizeof(char));
}
void populateInList(char *packet)
{
int msg_id, pkt_id, prefix_len_msg;
char *message;
struct messagenode *tmp_message, *loc;
struct pktnode *tmp_packet, *loc_pkt;;
message = (char *)malloc(1500*sizeof(char));
/* Get message id, packet id and packet message from each packet string -
* passed to function as argument.
*/
getPacketInfo(packet, &msg_id, &pkt_id, message, &prefix_len_msg);
/* If packet belongs to an existing message, find the message's location in message list.
* If message not found the NULL will be returned, otherwise location of message node
* will be returned.
*
* First condition: loc != NULL i.e. message entry found in list.
*/
if((loc = search_msg(msg_id)) != NULL)
{
/* Get a new packet node and populate it pkt_id and packet message.*/
tmp_packet = getPktNode();
tmp_packet->pkt_id = pkt_id;
tmp_packet->message = message;
/* Current packet head is the packet head of the current message.*/
head_pkt = loc->pkthead;
/* If current packet head is NULL then New packet will be the head packet.*/
if(head_pkt == NULL)
head_pkt = tmp_packet;
else
{
/* Otherwise, find the location where the New packet will be inserted.
* If location is the head packet and New packet id is less than the packet
* id of located node then insert the New packet before located node.
* Otherwise, insert the New packet node after the located packet node.
*/
loc_pkt = search_pkt(pkt_id);
if(loc_pkt == head_pkt && pkt_id < loc_pkt->pkt_id)
{
tmp_packet->next = head_pkt;
head_pkt = tmp_packet;
loc->pkthead = head_pkt;
}
else
{
tmp_packet->next = loc_pkt->next;
loc_pkt->next = tmp_packet;
}
}
}
else
{
/* Second condition: loc==NULL i.e. Message entry not found.
* So, (1)Create a new message node. (2)Create a new packet node corresponding
* to the new message node. (3) Populate them accordingly. (4) Add the new message
* node into the message linked list, i.e. the outer one.
*/
tmp_message = getMsgNode();
tmp_message->msg_id = msg_id;
tmp_message->prefix_len = prefix_len_msg;
tmp_message->next = NULL;
tmp_message->pkthead = getPktNode();
tmp_message->pkthead->pkt_id = pkt_id;
tmp_message->pkthead->message = message;
if(head_msg == NULL)
head_msg = tmp_message;
else
{
current_msg = head_msg;
while(current_msg != NULL)
{
save_msg = current_msg;
current_msg = current_msg->next;
}
save_msg->next = tmp_message;
}
}
}
struct messagenode * getMsgNode()
{
struct messagenode *tmp;
tmp = (struct messagenode *)malloc(sizeof(struct messagenode));
tmp->pkthead = NULL;
return tmp;
}
struct pktnode * getPktNode()
{
struct pktnode *tmp;
tmp = (struct pktnode *)malloc(sizeof(struct pktnode));
tmp->next = NULL;
return tmp;
}
/* Function to search a message node in message linked list.
* If messahe head is NULL return NULL i.e. message not found
* Else move through list searching for the node.
* .. If whole list is traversed in vain then return NULL i.e. message not found.
* .. Else return the location of the found message node.*/
struct messagenode *search_msg(int msg_id)
{
current_msg = head_msg;
if(head_msg == NULL)
return NULL;
else
{
while((current_msg != NULL) && (current_msg->msg_id != msg_id))
current_msg = current_msg->next;
if(current_msg == NULL)
return NULL;
if(current_msg->msg_id == msg_id)
return current_msg;
else
return NULL;
}
}
/* Function to search a packet node in packet linked list.(Inner one)
* Save location of current packet in each iteration of while() loop.
* If full packet list is traversed in vain or packet node is found
* with given packet node, saved location of packet is returned.*/
struct pktnode *search_pkt(int pkt_id)
{
current_pkt = head_pkt;
save_pkt = current_pkt;
while((current_pkt != NULL) && (pkt_id > current_pkt->pkt_id))
{
save_pkt = current_pkt;
current_pkt = current_pkt->next;
}
return save_pkt;
}
/* Function to get packet info from packet string.
* Tokenize the string by strtok() with delemeter ':'.
*/
void getPacketInfo(char *packet, int *msg_id, int *pkt_id, char *message, int *prefix_len_msg)
{
char *tokenPtr = NULL;
char array[10][1500];
char bkp_packet[2000];
int counter = 0, i=0;
/* Take a backup of the packet string as strtok() modifies the original string.*/
strcpy(bkp_packet, packet);
/* Extract first token. i.e. message id and save in temporary array.*/
tokenPtr = (char *)strtok(packet, DELIM);
if(tokenPtr == NULL)
{
printf("Fatal Error1 !! Invalid Message Format\n");
cleanUpAll();
exit(0);
}
strcpy(array[0], tokenPtr);
counter++;
/* Subsequent extraction of tokens and saving them.*/
while(1)
{
tokenPtr = (char *)strtok(NULL, DELIM);
if(tokenPtr == NULL)
break;
strcpy(array[counter], tokenPtr);
/* Special measure to keep the delemeter when it is a part of packet message.
* Concatinating : character to the previous token if current token counter
* is > 2. */
if(counter>2)
strcat(array[counter-1], ":");
counter++;
}
if(counter < 3)
{
printf("Fatal Error3 !! Invalid Message Format\n");
cleanUpAll();
exit(0);
}
*prefix_len_msg = getlen(array[0]);
*msg_id = atoi(array[0]);
*pkt_id = atoi(array[1]);
for(i=2; i<counter; i++)
{
strcat(message, array[i]);
}
}
int getlen(char *arg)
{
int n=0;
char ch;
while(1)
{
ch = arg[n];
if(ch != '0')
break;
n++;
}
return n;
}
/* Move through formulated linked list and display the content.*/
void display()
{
char display_string[2000];
char prefix[3];
int i;
current_msg = head_msg;
while(current_msg != NULL)
{
for(i=0; i<current_msg->prefix_len; i++)
prefix[i]= '0';
prefix[i]='\0';
sprintf(display_string, "Message %s%d\n", prefix, current_msg->msg_id);
current_pkt = current_msg->pkthead;
while(current_pkt != NULL)
{
strcat(display_string, current_pkt->message);
current_pkt = current_pkt->next;
}
current_msg = current_msg->next;
printf("%s\n", display_string);
}
}
/* Move through linked list and deallocate it. Close file pointer also */
void cleanUpAll()
{
fclose(fp);
free(packet);
while(head_msg != NULL)
{
head_pkt = head_msg->pkthead;
while(head_pkt != NULL){
free(head_pkt->message);
current_pkt = head_pkt->next;
free(head_pkt);
head_pkt = current_pkt;
}
current_msg = head_msg->next;
free(head_msg);
head_msg = current_msg;
}
}
/* Sort the message linked list, i.e. the outer one.*/
void sortMsg()
{
int tmp_id, tmp_len;
struct pktnode *tmp_head;
if(head_msg == NULL)
return;
else
{
for(current_msg = head_msg;(current_msg != NULL);current_msg = current_msg->next)
{
for(save_msg = current_msg->next;(save_msg != NULL);save_msg = save_msg->next)
{
if(current_msg->msg_id > save_msg->msg_id)
{
tmp_id = save_msg->msg_id;
tmp_head = save_msg->pkthead;
tmp_len = save_msg->prefix_len;
save_msg->msg_id = current_msg->msg_id;
save_msg->pkthead = current_msg->pkthead;
save_msg->prefix_len = current_msg->prefix_len;
current_msg->msg_id = tmp_id;
current_msg->pkthead = tmp_head;
current_msg->prefix_len = tmp_len;
}
}
}
}
}