Goto sanos source index

//
// environ.c
//
// Environment variables
//
// 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.
// 

#include <os.h>
#include <string.h>
#include <inifile.h>

extern struct critsect env_lock;

//
// The environment block is a null terminated array of strings 
// of the form NAME=VALUE.
//

char ***_environ() {
  return &gettib()->proc->env;
}

static char *findenv(char **env, const char *name, int *offset) {
  int i;
  int len;

  if (!env || !name) return NULL;

  len = strlen(name);
  for (i = 0; env[i]; i++) {
    if (strncmp(env[i], name, len) == 0 && env[i][len] == '=') {
      if (offset) *offset = i;
      return env[i] + len + 1;
    }
  }

  return NULL;
}

char **copyenv(char **env) {
  int n;
  char **newenv;

  if (!env) return NULL;

  enter(&env_lock);
  for (n = 0; env[n]; n++);
  newenv = (char **) malloc((n + 1) * sizeof(char *));
  if (newenv) {
    newenv[n] = NULL;
    for (n = 0; env[n]; n++) newenv[n] = strdup(env[n]);
  }
  leave(&env_lock);

  return newenv;
}

void freeenv(char **env) {
  int n;
  
  if (!env) return;
  enter(&env_lock);
  for (n = 0; env[n]; n++) free(env[n]);
  free(env);
  leave(&env_lock);
}

char **initenv(struct section *sect) {
  int n;
  char **env;
  struct property *prop;

  if (!sect) return NULL;
  n = get_section_size(sect);
  env = (char **) malloc((n + 1) * sizeof(char *));
  if (!env) return NULL;
  env[n] = NULL;

  for (n = 0, prop = sect->properties; prop; n++, prop = prop->next) {
    int len = strlen(prop->name) + 1;
    if (prop->value) len += strlen(prop->value);
    env[n] = (char *) malloc(len + 1);
    if (env[n]) {
      strcpy(env[n], prop->name);
      strcat(env[n], "=");
      if (prop->value) strcat(env[n], prop->value);
    }
  }

  return env;
}

char *getenv(const char *name) {
  char *value;

  enter(&env_lock);
  value = findenv(environ, name, NULL);
  leave(&env_lock);

  return value;
}

int setenv(const char *name, const char *value, int overwrite) {
  char **env;
  char *p;
  char *buf;
  int offset;
  size_t len;

  if (!name || !*name) {
    errno = EINVAL;
    return 0;
  }

  for (p = (char *) name; *p && *p != '='; p++);
  if (*p == '=') {
    errno = EINVAL;
    return 0;
  }

  if (*value == '=') value++;

  enter(&env_lock);
  env = environ;

  len = strlen(value);
  if ((p = findenv(env, name, &offset))) {
    if (!overwrite) {
      leave(&env_lock);
      return 0;
    }

    if (strlen(p) >= len) {
      // Old value is larger; copy over
      while ((*p++ = *value++) != 0);
      leave(&env_lock);
      return 0;
    }
  } else {
    int n;

    for (n = 0; env && env[n]; n++);
    env = (char **) realloc(env, (n + 2) * sizeof(char *));
    if (!env) {
      leave(&env_lock);
      return -1;
    }
    env[n + 1] = NULL;
    offset = n;
    environ = env;
  }

  buf = (char *) malloc(strlen(name) + len + 2);
  if (!buf) {
    leave(&env_lock);
    return -1;
  }

  env[offset] = buf;
  p = (char *) name;
  while (*p) *buf++ = *p++;
  *buf++ = '=';
  p = (char *) value;
  while (*p) *buf++ = *p++;
  *buf = 0;

  leave(&env_lock);

  return 0;
}

int unsetenv(const char *name) {
  char **p;
  char **env;
  int offset;

  enter(&env_lock);
  env = environ;
  
  while (findenv(env, name, &offset)) {
    for (p = &(env[offset]);; p++) {
      if (!(*p = *(p + 1))) break;
    }
  }

  leave(&env_lock);
  return 0;
}

int putenv(const char *str) {
  const char *p;
  char *name;
  int namelen;
  int rc;

  if (!str || !*str) {
    errno = EINVAL;
    return -1;
  }
  
  p = str;
  while (*p && *p != '=') p++;
  if (!*p) return unsetenv(str);
  
  namelen = p - str;
  name = malloc(namelen + 1);
  if (!name) {
    errno = ENOMEM;
    return -1;
  }
  memcpy(name, str, namelen);
  name[namelen] = 0;

  rc = setenv(name, p + 1, 1);
  free(name);
  return rc;
}