Logo Search packages:      
Sourcecode: laptop-net version File versions  Download package

parse-ipmap.c

/* -*-C-*-

$Id: parse-ipmap.c,v 1.2 2003/01/20 20:48:47 cph Exp $

Copyright 2002 Massachusetts Institute of Technology

This file is part of laptop-net.

Laptop-net is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.

Laptop-net is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with laptop-net; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "parse-ipmap.h"

typedef enum { PR_OK, PR_NULL, PR_ERROR } parse_result_t;

static const char * file_name;
static unsigned int line_number;

static parse_result_t parse_line (FILE *, struct ip_map *);
static parse_result_t parse_blank_line (FILE *);
static parse_result_t parse_key (FILE *, const char **);
static int is_key_char (int);
static parse_result_t parse_ip_address (FILE *, struct in_addr *);
static int is_address_char (int);
static parse_result_t skip_whitespace (FILE *);
static parse_result_t skip_comment (FILE *);
static parse_result_t parse_chars (FILE *, int (*) (int), const char **);
static void print_io_error (FILE *);
static void * xmalloc (size_t);
static void * xrealloc (void *, size_t);

int
parse_ip_map (const char * fn, struct ip_map ** map_return)
{
  FILE * s;
  unsigned int buffer_index = 0;
  unsigned int buffer_length = 4;
  struct ip_map * buffer;

  s = (fopen (fn, "r"));
  if (s == 0)
    {
      fprintf (stderr, "Unable to open map file '%s'.\n", fn);
      return (-1);
    }

  file_name = fn;
  line_number = 0;
  buffer = (xmalloc ((sizeof (struct ip_map)) * buffer_length));
  while (1)
    {
      struct ip_map entry;
      parse_result_t r;

      line_number += 1;
      {
      int c = (fgetc (s));
      if (c == EOF)
        {
          if (feof (s))
            break;
          free (buffer);
          fclose (s);
          return (-1);
        }
      ungetc (c, s);
      }
      r = (parse_line (s, (&entry)));
      if (r == PR_NULL)
      continue;
      if (r != PR_OK)
      {
        free (buffer);
        fclose (s);
        return (-1);
      }
      if (buffer_index == buffer_length)
      {
        buffer_length *= 2;
        buffer
          = (xrealloc (buffer, ((sizeof (struct ip_map)) * buffer_length)));
      }
      (buffer[buffer_index++]) = entry;
    }
  {
    if (buffer_index > 0)
      {
      buffer
        = (xrealloc (buffer,
                   ((sizeof (struct ip_map)) * buffer_index)));
      (*map_return) = buffer;
      }
    else
      free (buffer);
    fclose (s);
    return (buffer_index);
  }
}

static parse_result_t
parse_line (FILE * s, struct ip_map * entry)
{
  const char * key;
  unsigned int buffer_index;
  unsigned int buffer_length;
  struct in_addr * buffer;

  {
    parse_result_t r = (parse_key (s, (&key)));
    if (r == PR_NULL)
      return (parse_blank_line (s));
    if (r != PR_OK)
      return (r);
  }
  buffer_index = 0;
  buffer_length = 4;
  buffer = (xmalloc ((sizeof (struct in_addr)) * buffer_length));
  while (1)
    {
      struct in_addr address;
      parse_result_t r = (parse_ip_address (s, (&address)));
      if (r == PR_NULL)
      {
        if (buffer_index == 0)
          {
            free ((void *) key);
            free (buffer);
            fprintf
            (stderr, "Map entry on line %d of '%s' has no IP addresses.\n",
             line_number, file_name);
            return (PR_ERROR);
          }
        if ((parse_blank_line (s)) == PR_ERROR)
          return (PR_ERROR);
        buffer
          = (xrealloc (buffer, ((sizeof (struct in_addr)) * buffer_index)));
        (entry -> key) = key;
        (entry -> n_addresses) = buffer_index;
        (entry -> addresses) = buffer;
        return (PR_OK);
      }
      if (r != PR_OK)
      {
        free ((void *) key);
        free (buffer);
        return (r);
      }
      if (buffer_index == buffer_length)
      {
        buffer_length *= 2;
        buffer
          = (xrealloc (buffer, ((sizeof (struct in_addr)) * buffer_length)));
      }
      (buffer[buffer_index++]) = address;
    }
}

static parse_result_t
parse_blank_line (FILE * s)
{
  if ((skip_whitespace (s)) == PR_ERROR)
    return (PR_ERROR);
  {
    int c = (fgetc (s));
    if (c == EOF)
      {
      print_io_error (s);
      return (PR_ERROR);
      }
    if (c == '\n')
      return (PR_NULL);
    if (c == '#')
      return (skip_comment (s));
    fprintf (stderr, "Line %d of '%s' is malformed.\n",
           line_number, file_name);
    return (PR_ERROR);
  }
}

static parse_result_t
parse_key (FILE * s, const char ** buffer_ret)
{
  return (parse_chars (s, is_key_char, buffer_ret));
}

static int
is_key_char (int c)
{
  return
    ((isalnum (c)) || (c == '.') || (c == '-') || (c == '+') || (c == '_'));
}

static parse_result_t
parse_ip_address (FILE * s, struct in_addr * address_ret)
{
  parse_result_t r;
  const char * address;

  r = (skip_whitespace (s));
  if (r != PR_OK)
    return (r);
  r = (parse_chars (s, is_address_char, (&address)));
  if (r != PR_OK)
    return (r);
  if (inet_aton (address, address_ret))
    {
      free ((void *) address);
      return (PR_OK);
    }
  fprintf (stderr, "Malformed IP address '%s' on line %d of '%s'.\n",
         address, line_number, file_name);
  free ((void *) address);
  return (PR_ERROR);
}

static int
is_address_char (int c)
{
  return ((isdigit (c)) || (c == '.'));
}

static parse_result_t
skip_whitespace (FILE * s)
{
  unsigned int n = 0;
  while (1)
    {
      int c = (fgetc (s));
      if (c == EOF)
      {
        print_io_error (s);
        return (PR_ERROR);
      }
      if (! ((c == ' ') || (c == '\t')))
      {
        ungetc (c, s);
        return ((n > 0) ? PR_OK : PR_NULL);
      }
      n += 1;
    }
}

static parse_result_t
skip_comment (FILE * s)
{
  while (1)
    {
      int c = (fgetc (s));
      if (c == EOF)
      {
        print_io_error (s);
        return (PR_ERROR);
      }
      if (c == '\n')
      return (PR_NULL);
    }
}

#define ACCUM(c, b) do                                      \
{                                                     \
  if (b##_index == b##_length)                                    \
    {                                                 \
      b##_length *= 2;                                      \
      b = (xrealloc (b, b##_length));                             \
    }                                                 \
  (b[b##_index++]) = (c);                                   \
} while (0)

static parse_result_t
parse_chars (FILE * s, int (*predicate) (int), const char ** buffer_ret)
{
  unsigned int buffer_index = 0;
  unsigned int buffer_length = 16;
  char * buffer = (xmalloc (buffer_length));

  while (1)
    {
      int c = (fgetc (s));
      if (c == EOF)
      {
        free (buffer);
        print_io_error (s);
        return (PR_ERROR);
      }
      if ((*predicate) (c))
      ACCUM (c, buffer);
      else
      {
        ungetc (c, s);
        if (buffer_index == 0)
          {
            free (buffer);
            return (PR_NULL);
          }
        ACCUM ('\0', buffer);
        buffer = (xrealloc (buffer, buffer_index));
        (*buffer_ret) = buffer;
        return (PR_OK);
      }
    }
}

static void
print_io_error (FILE * s)
{
  if (feof (s))
    fprintf (stderr, "Premature end of file on line %d of '%s'.\n",
           line_number, file_name);
  else
    fprintf (stderr, "I/O error while reading '%s'.\n", file_name);
}

static void *
xmalloc (size_t n_bytes)
{
  void * p = (malloc (n_bytes));
  if (p == 0)
    {
      fprintf (stderr, "Unable to allocate %u bytes.\n", n_bytes);
      exit (1);
    }
  return (p);
}

static void *
xrealloc (void * p1, size_t n_bytes)
{
  void * p2 = (realloc (p1, n_bytes));
  if (p2 == 0)
    {
      fprintf (stderr, "Unable to reallocate %u bytes.\n", n_bytes);
      exit (1);
    }
  return (p2);
}

Generated by  Doxygen 1.6.0   Back to index