/*
 * getenv() for BCC
 * Copyright (c) 2017 Andreas K. Foerster <info@akfoerster.de>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <string.h>
#include <bios.h>

#define BUFSIZE 128
/*
If the name is too long, it is not found.
If the content is too long, it is truncated.
*/

static unsigned int get_env_segment ();
static char *next_variable ();

static char buf[BUFSIZE];

/*
Returns static buffer, which is changed with next call.
That is actually allowed by the standard.
*/
char *
getenv (name)
     char *name;
{
  unsigned int offset = 0;
  char *variable;

  do
    {
      variable = next_variable ('=', &offset);

      if (!strcmp (name, variable))
	return next_variable (0, &offset);	/* content */

      /* skip content */
      (void) next_variable (0, &offset);
    }
  while (*variable);

  return NULL;
}


/* gets next variable up to stopchar */
static char *
next_variable (stopchar, offset)
     int stopchar;
     unsigned int *offset;
{
  unsigned int es, length;
  int c;

  es = __get_es ();
  get_env_segment ();

  length = 0;
  do
    {
      c = __peek_es (*offset);
      ++*offset;

      if (length < (sizeof (buf) - 1))
	buf[length++] = c;
    }
  while (c != stopchar);

  buf[length - 1] = '\0';

  __set_es (es);

  return buf;
}


/* *INDENT-OFF* */

/* sets ES to segment with environment, returns ES */
static unsigned int
get_env_segment ()
{
#asm
  mov ah, #$62 ; get PSP
  int $21
  mov es, bx

  mov bx, #$002C ; offset with segment info
  seg es
  mov ax, [bx]
  mov es, ax
#endasm
}
