Single Linked List
2002-02-28 02:57:39
Category: c:structures
Description: Reads in the data from /etc/services, loads it into a linked list and then prints it on the screen.
Author: detour
Viewed: 28134
Rating: (130 votes)


/* linklst.c written by detour@metalshell.com 
 * 
 * This is an example of a basic linked list.  The
 * data is read from /etc/services and pushed onto
 * the stack started at ll_serv.  This will not work
 * if you can't read /etc/services or it is a
 * different format then the one I used to test on.
 *
 * http://www.metalshell.com/
 *
 */
 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
 
struct services {
  int port;
  char *name;
  char *proto;
  struct services *next;
} *ll_serv;
 
void r_services(char *);
void Push_New_Entry(char *, char *, int);
void Print_All();
 
int main() {
  FILE *inFile;
  char line[100];
 
  /* Get each line from the /etc/services file and pass it
     too r_services to get split apart and pushed onto
     our linked list. */
  inFile = fopen("/etc/services", "r");
  while( fgets(line, sizeof(line), inFile) != NULL ) {
    if(line[0] != '#' && line[0] != '\n' && line[0] != ' ') {
      r_services(line);
    }
  }
  fclose(inFile);
 
  /* Cycle through and print the data */
  Print_All();
 
  return 0;
}
 
void Push_New_Entry(char *e_name, char *e_proto, int p) {
  struct services *current, *new;
 
  /* Allocate memory for the new structure that ll_serv->next will
     point too. Then make sure to clear it with memset, otherwise you
     could be creating a structure with new->next already pointing to some
     address that you didn't create. */
  new = (struct services *)malloc(sizeof(struct services));
  memset(new, 0, sizeof(struct services));
 
  /* If this is the first entry allocate memory for it as well. */
  if(ll_serv == NULL) {
    ll_serv = (struct services *)malloc(sizeof(struct services));
    memset(ll_serv, 0, sizeof(struct services));
    current = ll_serv;
  } else {
    current = ll_serv;
    /* Follow the links through the list until we hit the end */
    while(current->next != NULL)
      current = current->next;
  }
 
  current->next = new;
  current->name = (char *)malloc(strlen(e_name) + 1);
  strcpy(current->name, e_name);
  current->proto = (char *)malloc(strlen(e_proto) + 1);
  strcpy(current->proto, e_proto);
  current->port = p;
}
 
void Print_All() {
  struct services *current;
 
  /* ll_serv will always be the beginning of the list */
  current = ll_serv;
 
  /* Go through each member of the list and print it out */
  while(current->next != NULL) {
    printf("Name: %10.10s\tPort: %5d\tProto: %s\n", 
            current->name, current->port, current->proto);
    current = current->next;
  }
}
 
void r_services(char *line) {
  char *ptr;
  char *name, *proto;
  int port;
 
  name = proto = NULL;
  port = -1;
 
  ptr = line;
 
  /* This is kinda sloppy but it should work, maybe. */
  for(;*line;line++)
    if((*line == ' ' || *line == '\t') && name == NULL) {
      *line = '\0';
      name = (char *)malloc(strlen(ptr) +1);
      name = ptr;
    } else if(*line > 47 && *line < 58 && port == -1 && name != NULL) {
      ptr = (char *)malloc(strlen(line) + 1);
      strcpy(ptr, line);
      /* Just a note that strtok sucks and shouldn't be used, it will
         alter the string you send it */
      port = atoi(strtok(ptr, "/"));
      for(;*line;line++)
        if(*line == ' ' || *line == '\t' || *line == '\n') {
          *line = '\0';
          proto = line - 3;
          break;
        }
      break;
    }
 
  /* Parsed out all the data, now push it onto the list */
  Push_New_Entry(name, proto, port);
}