/**
 * Miscellaneous code
 * (C) Nettle developers 2000-2001
 *
 * $Id: misc,v 1.29 2003/10/16 19:30:06 archifishal Exp $
 */

#include "generic.h"
#include "globals.h"

#include "misc.h"
#include "wimputil.h"

static FILE *log_file = NULL;
static int log_file_time=0;


/* Gets a system variable's contents */

char *get_system_variable(char *variable, const char *variable_name,
                          int variable_size)
{
  char *string;

  assert(variable != NULL);
  assert(variable_name != NULL);
  assert(variable_size > 0);

  string = getenv(variable_name);

  /* if it exists, copy it into variable */
  variable[0] = '\0';
  if (string != NULL)
    strncat(variable, string, variable_size - 1);

  return variable;
}



/* Converts a string into a binary integer */

int binary(const char *string)
{
  int          value = 0;
  const char  *s;

  assert(string != NULL);

  for (s = string; *s != 0; s++)
  {
    value *= 2;
    if (*s == '1')
      value++;
  }

  return value;
}



/* Implementation of BASIC's INSTR command */
int instr(const char *string, const char *test)
{
  assert(string != NULL);
  assert(test   != NULL);

  return esc_instr(string,test,strlen(string));
}



/* Implementation of BASIC's INSTR command with the length of the string too */
int esc_instr(const char *string, const char *test, int length)
{
  int loop;

  assert(string != NULL);
  assert(test   != NULL);
  assert(length >= 0);

  for (loop=0; loop<length; loop++)
  {
    int loop2=0;
    while (string[loop+loop2]==test[loop2] && loop2<strlen(test))
    {
      loop2++;
    }
    if (loop2==strlen(test))
    {
      return loop;
    }
  }

  return -1;
}

/*
 * Ensure a 'string' is zero-terminated.  Typically to work around bugs in
 * other apps which don't obey the DataLoad protocol on PRM P3-253 which
 * clearly states that the filename must be ZERO-terminated
 */
void misc_zero_terminate_ctrl_string(char *string)
{
  for(;*string>31;string++);

  *string=0;
}


/* read a 'string' */
char *read_mem(char *dest, const char *source, int max_length)
{
  int loop = 0;

  assert(dest       != NULL);
  assert(source     != NULL);
  assert(max_length > 0);

  while (loop < max_length - 1 && source[loop] != '\0' &&
        source[loop] != '\x0A' && source[loop] != '\x0D')
  {
    dest[loop] = source[loop];
    loop++;
  }

  dest[loop] = '\0';

  return dest;
}



/**
 * Make sure the log file is open for append, creating it if necessary
 *
 * @return true if the logfile should be written to, false if logging is
 *         disabled or the file open failed.
 */
static bool log_checkopen(void)
{
  if (!logging)
    return false;

  if (log_file == NULL)
    log_file=fopen("<Nettle$Dir>.Log", "a");

  if (log_file == NULL)
    log_file=fopen("<Nettle$Dir>.Log", "w");

  if (log_file == NULL)
    return false;

  return true;
}



/* log a string to the log file */
void log_string(const char *string)
{
  assert(string != NULL);

  if (log_checkopen())
  {
    fputs(string, log_file);
    log_file_time = _swi(OS_ReadMonotonicTime, _RETURN(0));
  }
}



void misc_logf(const char *format, ...)
{
  assert(format != NULL);

  if (log_checkopen())
  {
    va_list ap;

    va_start(ap, format);
    vfprintf(log_file, format, ap);
    va_end(ap);

    log_file_time = _swi(OS_ReadMonotonicTime, _RETURN(0));
  }
}



/* log a byte to the log file */
void log_byte(char character)
{
  if (log_checkopen())
  {
    fputc(character,log_file);

    log_file_time = _swi(OS_ReadMonotonicTime, _RETURN(0));
  }
}



/* close the log file if we haven't used it for 5 seconds */
void close_log(bool force)
{
  int current_time;

  if (!logging)
    return;

  if (log_file == NULL)
    return;

  current_time = _swi(OS_ReadMonotonicTime, _RETURN(0));

  if ((force) || (current_time > log_file_time+500))
  {
    fclose(log_file);
    log_file = NULL;
  }
}


/* Create a log file */
void create_log(void)
{
  log_file_time = _swi(OS_ReadMonotonicTime, _RETURN(0));

  if (logging)
  {
    /* create log file for use later */
    log_file=fopen("<Nettle$Dir>.Log","w");
    if (log_file)
    {
      close_log(true);
    }
  }
}


/* Get what country we're in */
char *get_country(char *string, int size)
{
  int country_number;

  assert(string != NULL);
  assert(size   > 0);

  string[0] = '\0';

  if (_swix(OS_Byte,_INR(0,1)|_OUT(1), 0x46, 127, &country_number)==0)
  {
    _swi(OS_ServiceCall, _INR(1,5), 0x43, 2, country_number, string, size);
  }

  return string;
}

/* Find out if dynamic areas are available or not */
bool dynamic_areas_available(void)
{
  if (_swix(OS_DynamicArea, _INR(0,1), 3, -1))
    return false;

  return true;
}



void misc_setfiletype(const char *filename, int type)
{
  _kernel_oserror *err = _swix(OS_File, _INR(0,2), 18, filename, type);
  if (err)
    generror (err->errmess, false);
}


#ifndef __UNIXLIB_TYPES_H

char *strdup(const char *s)
{
  size_t len;
  char *t;

  if (!s)
    return NULL;

  len = strlen(s) + 1;

  t = malloc(len);
  if (!t)
    return NULL;

  memcpy(t, s, len);

  return t;
}

#endif


char *misc_string_lower(char *string)
{
  int loop;
  int len=strlen(string);

  for (loop=0; loop<len; loop++)
  {
    string[loop]=tolower(string[loop]);
  }

  return string;
}

char *misc_string_upper(char *string)
{
  int loop;
  int len=strlen(string);

  for (loop=0; loop<len; loop++)
  {
    string[loop]=toupper(string[loop]);
  }

  return string;
}

