Goto sanos source index

//
// inifile.c
//
// Property files
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

#ifdef KERNEL
#include <os/krnl.h>
#include <stdlib.h>
#else
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inifile.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#endif

static char *trimstr(char *s, char *end) {
  char *str;
  char *t;
  int ch;
  int i;
  
  while (end > s) {
    if (*(end - 1) == ' ' || *(end - 1) == '\t') {
      end--;
    } else {
      break;
    }
  }
  if (end == s) return NULL;

  t = str = (char *) malloc(end - s + 1);
  while (s < end) {
    if (*s == '^') {
      s++;
      ch = 0;
      for (i = 0; i < 2; i++) {
        if (s == end) break;

        if (*s >= '0' && *s <= '9') {
          ch = (ch << 4) + *s - '0';
        } else if (*s >= 'A' && *s <= 'F') {
          ch = (ch << 4) + *s + 10 - 'A';
        } else if (*s >= 'a' && *s <= 'f') {
          ch = (ch << 4) + *s + 10 - 'a';
        } else {
          break;
        }

        s++;
      }
      *t++ = ch;
    } else {
      *t++ = *s++;
    }
  }

  *t = 0;
  return str;
}

struct section *find_section(struct section *sect, char *name) {
  while (sect) {
    if (strcmp(sect->name, name) == 0) return sect;
    sect = sect->next;
  }

  return NULL;
}

int get_section_size(struct section *sect) {
  struct property *prop;
  int n;
  
  if (!sect) return 0;
  prop = sect->properties;

  n = 0;
  while (prop) {
    n++;
    prop = prop->next;
  }

  return n;
}

char *find_property(struct section *sect, char *name) {
  struct property *prop;
  
  if (!sect) return NULL;
  prop = sect->properties;

  while (prop) {
    if (strcmp(prop->name, name) == 0) return prop->value ? prop->value : "";
    prop = prop->next;
  }

  return NULL;
}

char *get_property(struct section *sections, char *sectname, char *propname, char *defval) {
  struct section *sect;
  char *val;

  sect = find_section(sections, sectname);
  if (!sect) return defval;

  val = find_property(sect, propname);
  return val ? val : defval;
}

int get_numeric_property(struct section *sections, char *sectname, char *propname, int defval) {
  char *val;

  val = get_property(sections, sectname, propname, NULL);
  return val ? atoi(val) : defval;
}

void free_properties(struct section *sect) {
  struct section *nextsect;
  struct property *prop;
  struct property *nextprop;

  while (sect) {
    if (sect->name) free(sect->name);
    
    prop = sect->properties;
    while (prop) {
      if (prop->name) free(prop->name);
      if (prop->value) free(prop->value);
      
      nextprop = prop->next;
      free(prop);
      prop = nextprop;
    }

    nextsect = sect->next;
    free(sect);
    sect = nextsect;
  }
}

struct section *parse_properties(char *props) {
  struct section *secthead = NULL;
  struct section *sect = NULL;
  struct property *prop = NULL;
  char *p;
  char *end;
  char *split;

  p = props;
  while (*p) {
    // Skip white at start of line
    while (*p == ' ' || *p == '\t') p++;
    
    // Skip comments
    if (*p == '#' || *p == ';') {
      while (*p && *p != '\r' && *p != '\n') p++;
      if (*p == '\r') p++;
      if (*p == '\n') p++;
      continue;
    }

    // Skip blank lines
    if (*p == 0 || *p == '\r' || *p == '\n') {
      if (*p == '\r') p++;
      if (*p == '\n') p++;
      continue;
    }

    // Check for section or property
    if (*p == '[') {
      struct section *newsect;

      p++;
      end = p;
      while (*end && *end != ']') end++;

      newsect = (struct section *) malloc(sizeof(struct section));
      if (!newsect) return NULL;

      newsect->name = trimstr(p, end);
      newsect->next = NULL;
      newsect->properties = NULL;
      if (!secthead) secthead = newsect;
      if (sect) sect->next = newsect;
      sect = newsect;
      prop = NULL;

      p = end;
      if (*p == ']') p++;
    } else {
      struct property *newprop;

      end = p;
      split = NULL;
      while (*end && *end != '\r' && *end != '\n') {
        if (!split && (*end == '=' || *end == ':')) split = end;
        end++;
      }

      if (sect) {
        newprop = (struct property *) malloc(sizeof(struct property));
        if (!newprop) return NULL;

        if (split) {
          newprop->name = trimstr(p, split);
          split++;
          while (*split == ' ' || *split == '\t') split++;
          newprop->value = trimstr(split, end);
        } else {
          newprop->name = trimstr(p, end);
          newprop->value = NULL;
        }

        newprop->next = NULL;
        if (prop) {
          prop->next = newprop;
        } else {
          sect->properties = newprop;
        }

        prop = newprop;
      }

      p = end;
      if (*p == '\r') p++;
      if (*p == '\n') p++;
    }
  }

  return secthead;
}

#ifndef KERNEL

void list_properties(int f, struct section *sect) {
  struct property *prop;

  while (sect) {
    write(f, "[", 1);
    write(f, sect->name, strlen(sect->name));
    write(f, "]\r\n", 3);

    prop = sect->properties;
    while (prop) {
      write(f, prop->name, strlen(prop->name));
      if (prop->value) {
        write(f, "=", 1);
        write(f, prop->value, strlen(prop->value));
      }
      write(f, "\r\n", 2);
      prop = prop->next;
    }
    
    if (sect->next) write(f, "\r\n", 2);
    sect = sect->next;
  }
}

struct section *read_properties(char *filename) {
  int f;
  int size;
  struct stat buffer;
  char *props;
  struct section *sect;

  f = open(filename, O_BINARY);
  if (f < 0) return NULL;

  if (fstat(f, &buffer) < 0) {
    close(f);
    return NULL;
  }
  size = (int) buffer.st_size;

  props = (char *) malloc(size + 1);
  if (!props) {
    close(f);
    return NULL;
  }

  if (read(f, props, size) != size) {
    free(props);
    close(f);
    return NULL;
  }

  close(f);

  props[size] = 0;

  sect = parse_properties(props);
  free(props);

  return sect;
}

#endif