/***************************************************************************
*	NAME:  IWUTILS.C $Revision: 1.11 $
**	COPYRIGHT:
**	"Copyright (c) 1994,1995 by e-Tek Labs"
**
**       "This software is furnished under a license and may be used,
**       copied, or disclosed only in accordance with the terms of such
**       license and with the inclusion of the above copyright notice.
**       This software or any other copies thereof may not be provided or
**       otherwise made available to any other person. No title to and
**       ownership of the software is hereby transfered."
****************************************************************************
* $Log: iwutils.c $
* Revision 1.11  1995/10/26 14:59:33  mleibow
* Added mutes for software mixer controls.
* Revision 1.10  1995/10/15 18:44:14  sdsmith
* Changed default revision to 4
* Revision 1.9  1995/06/23 11:15:38  sdsmith
* Moved local stack to data segment
* Revision 1.8  1995/05/25 15:13:49  mleibow
* Added multiple language support.
* Revision 1.7  1995/05/03 08:53:24  mleibow
* Simplified kernel_cfg structure and added multiple card
* support
* Revision 1.6  1995/04/26 16:22:56  sdsmith
* Added support for GP Pin usage
* Revision 1.5  1995/04/19 17:40:14  sdsmith
* Added default init string support
* Revision 1.4  1995/04/14 09:19:52  sdsmith
* Added support for B0 silicon
* Revision 1.3  1995/03/24 09:44:16  mleibow
* Added initialization for MPU401 and other emulations
* Revision 1.2  1995/03/08 15:28:11  mleibow
* add chip revision check for pre-release checks
* Revision 1.1  1995/02/23 11:07:40  unknown
* Initial revision
****************************************************************************/
/***************************************************************************
OVERVIEW:
iwu.c - InterWave Utilities

This file contains utility routines for use by wrappers or applications.
The utilities are mainly to replace the C runtime library functions.
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>
#include "iw.h"
#include "iwl.h"
#include "globals.h"

static char *iw="INTERWAVE";
static char RFAR *ustr;
static int lstack[32];

#if NEARDATA == 1
#define ENV_STR_SIZE 132
static char env_str[ENV_STR_SIZE];
#endif


#ifdef __BORLANDC__
#pragma warn -pia
#endif

/* ctype.h */
/***************************************************************************

FUNCTION DEFINITION:
iwu_isalnum - tests if c is an alphanumeric character

RETURNS: nonzero if a is an alphnumeric character

*/
int iwu_isalnum(int c)
{
  if (c >= 'A' && c <= 'Z')
    return 1;
  if (c >= 'a' && c <= 'z')
    return 1;
  if (c >= '0' && c <= '9')
    return 1;
  return 0;
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_isalpha - tests if character c is a letter between a-z or A-Z

RETURNS: nonzero if a is an alphabetic character

*/
int iwu_isalpha(int c)
{
  if (c >= 'A' && c <= 'Z')
    return 1;
  if (c >= 'a' && c <= 'z')
    return 1;
  return 0;
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_isspace - tests whether the character c is a whitespace character

RETURNS: 1 if c is whitespace 0 if not

*/
int iwu_isspace(int c)
{
  if (c >= 0x09 && c <= 0x0D)
    return 1;
  return (c == ' ');
}

/* stdlib.h */
/***************************************************************************

FUNCTION DEFINITION:
iwu_itoa - converts an integer to a string

DESCRIPTION:
iwu_itoa converts the integer integ to a null-terminated string and stores 
the result in buffer.  

radix is used tin converting value and must be between 2 and 36.  If the
radix is 10 and integ is negative, the first charater of buffer will be a
minus sign.

The space allocated for buffer must be large enough to hold the returned 
string.

RETURNS: char RFAR * - pointer to buffer

*/
char RFAR *iwu_itoa(int integ, char RFAR *buffer, int radix)
{
  unsigned int integer;
  int i, order = 0, rem;
  char RFAR *tmp;
  int lsp = 0;
  static char table[] = "0123456789abcdefghijklmnopqrstuvwxyz";

  if (radix < 2 || radix >= sizeof(table))
    return 0;

  tmp = buffer;
  if (integ < 0 && radix == 10) {
    buffer[0] = '-';
    buffer = &(tmp[1]);
    integ = -integ;
  }
  integer = (unsigned int)integ;
  do {
    rem = integer % radix;
    lstack[lsp++] = rem;
    order++;
    integer /= radix;
  } while (integer > 0);
  for (i=0; i<order; i++) {
    rem = lstack[--lsp];
    buffer[i] = table[rem];
  }
  buffer[order] = '\0';
  buffer = tmp;
  return(buffer);
}

/* string.h */
/***************************************************************************

FUNCTION DEFINITION:
iwu_memcpy - copies the first n bytes of array src to array dest

RETURNS: void

*/
void RFAR *iwu_memcpy(void RFAR *dest, const void RFAR *src, unsigned int n)
{
  unsigned char RFAR *d = dest;
  const unsigned char RFAR *s = src;
  while (n--)
    *d++ = *s++;
  return dest;
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_memset - sets the first n bytes of array dest to the character c

RETURNS: void

*/
void RFAR *iwu_memset(void RFAR *dest, int c, unsigned int n)
{
  unsigned char RFAR *d = dest;
  while (n--)
    *d++ = (unsigned char)c;
  return dest;
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_strlen - calculates the length of string s1

RETURNS: int - number of characters in s1 not including the null
	       terminating character.

*/
int iwu_strlen(const char RFAR *s1)
{
  int i = 0;
  while (*s1++) i++;
  return i;
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_strcat - appends string src to string dest

RETURNS: char RFAR * - pointer to the concatinated strings

*/
char RFAR *iwu_strcat(char RFAR *dest, const char RFAR *src)
{
  char RFAR *d = dest;
  while (*d)
    d++;
  while (*d++ = *src++)
    ;
  return dest;
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_strcmp - compares the contents of strings s1 and s2

RETURNS: int - < 0 if s1 < s2
	       = 0 if s1 = s2
	       > 0 if s1 > s2

*/
int iwu_strcmp(const char RFAR *s1, const char RFAR *s2)
{
  while (*s1 && *s1 == *s2) {
    s1++;
    s2++;
  }
  return *s1 - *s2;
}

#define UPPER(a) (((a)>='a' && (a)<='z')?((a)-'a'+'A'):(a))

/***************************************************************************

FUNCTION DEFINITION:
iwu_stricmp - compares the contents of strings s1 and s2 (case insensitive)

RETURNS: int - < 0 if s1 < s2
	       = 0 if s1 = s2
	       > 0 if s1 > s2

*/
int iwu_stricmp(const char RFAR *s1, const char RFAR *s2)
{
  while (*s1 && UPPER(*s1) == UPPER(*s2)) {
    s1++;
    s2++;
  }
  return *s1 - *s2;
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_strcpy - copies the characters from src to dest

RETURNS: char RFAR * - dest

*/
char RFAR *iwu_strcpy(char RFAR *dest, const char RFAR *src)
{
  char RFAR *d = dest;
  while (*d++ = *src++)
    ;
  return dest;
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_strncmp - compares a portion of one string to another

DESCRIPTION:
iwu_strncmp comapares at most maxlen characters between s1 and s2.

RETURNS: int - < 0 if s1 < s2
	       = 0 if s1 = s2
	       > 0 if s1 > s2

*/
int iwu_strncmp(const char RFAR *s1, const char RFAR *s2, unsigned int maxlen)
{
  int i = 0;
  while (i < (int)maxlen && *s1 && *s1 == *s2) {
    i++;
    s1++;
    s2++;
  }
  return (i == (int)maxlen) ? 0 : (*s1 - *s2);
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_strnicmp - compares a portion of one string to another (case insensitive)

DESCRIPTION:
iwu_strncmp comapares at most maxlen characters between s1 and s2.

RETURNS: int - < 0 if s1 < s2
	       = 0 if s1 = s2
	       > 0 if s1 > s2

*/
int iwu_strnicmp(const char RFAR *s1, const char RFAR *s2, unsigned int maxlen)
{
  int i = 0;
  while (i < (int)maxlen && *s1 && UPPER(*s1) == UPPER(*s2)) {
    i++;
    s1++;
    s2++;
  }
  return (i == (int)maxlen) ? 0 : (*s1 - *s2);
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_strncpy - copies a portion of one string to another

DESCRIPTION:
iwu_strncpy copies at most maxlen characters from the string src to the string
dest.  dest is null-padded or truncated if the length of src is less than
maxlen.  dest may not be null-terminated if the length of src is maxlen or
more.

RETURNS: char RFAR * - dest

*/
char RFAR *iwu_strncpy(char RFAR *dest, const char RFAR *src, unsigned int maxlen)
{
  int i = 0;
  char RFAR *d = dest;
  while (i < (int)maxlen && (*d++ = *src++))
    i++;
  return dest;
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_strtok - search a string for tokens

DESCRIPTION:
iwu_strtok searches a string, str, for tokens separated by the characters in
the delimiter string.  iwu_strtok considers str to consist of a sequence of 
zero or more text tokens separated by spans of one or more characters from
delimiter.

The first call to iwu_strtok returns a pointer to the first character of 
the first token of str and writes a null character into str immediately
followint the returned token.  Subsequent calls with NULL for the first
argument will work through the string str in this fassion until no tokens
remain.

The delimiter string can be different from call to call.

RETURNS: char RFAR * - a pointer to the first token in str.
	 NULL when there are no more tokens

*/
char RFAR *iwu_strtok(char RFAR *str, const char RFAR *delimiter)
{
  static char RFAR *parse_str=0;
  char RFAR *tmp;
  char RFAR *start;

  if (str == 0) {
    if (parse_str == 0)
      return(0);
    else
      tmp = parse_str;
  }
  else {
    tmp = str;
  }
  start = tmp;
  if (*tmp) {
    while (*tmp && iwu_strncmp(tmp, delimiter, iwu_strlen(delimiter)))
      tmp++;
    if (*tmp != '\0')
      *tmp++ = '\0';
    parse_str = tmp;
  }
  else start = 0;
  return(start);
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_strtol - convert a string to a long integer

DESCRIPTION:
iwu_strtol converts a character string, str, to a long integer value.  This
function replaces the standard C runtime strtol function.

RETURNS: long - value of converted string or 0 on error

SEE ALSO: 
Borland Run-Time Library or Microsoft Run-Time library reference for a 
description of strtol.

*/
long iwu_strtol(const char RFAR *str, char RFAR * RFAR *endptr, int rad)
{
  int radix;
  long rval = 0;
  int neg = 0;

  if (rad >= 2 && rad <= 36) {
    radix = rad;
    if (radix == 10 && str[0] == '-') {
      neg = 1;
      str++;
    }
  }
  else if (rad == 0) {
    if (str[0] == '0') {
      if (str[1] == 'x') {
	radix = 16;
	str = &str[2];
      }
      else {
	radix = 8;
	str = &str[1];
      }
    }
    else {
      radix = 10;
      if (str[0] == '-') {
	neg = 1;
	str++;
      }
    }
  }
  else {
    if (endptr) *endptr = (char RFAR *)str;
    return(0L);
  }

  while (1) {
    if (*str >= 0x30 && *str <= 0x39 && *str < (0x30 + radix)) {
      rval = rval * radix + (*str - 0x30);
    }
    else if (*str >= 0x41 && *str < (0x37 + radix)) {
      rval = rval * radix + (*str - 0x37);
    }
    else if (*str >= 0x61 && *str < (0x57 + radix)) {
      rval = rval * radix + (*str - 0x57);
    }
    else {
      break;
    }
    str++;
  }
  if (endptr) *endptr = (char RFAR *)str;
  if (neg) rval = -rval;
  return(rval);
}

/***************************************************************************

FUNCTION DEFINITION:
iwu_get_kernel_cfg - get kernel configuration info

DESCRIPTION:
iwu_get_kernel_cfg - fills the load_kernel_cfg structure pointed to by
the cfg parameter with the information stored in the iw.ini configuration
file.

RETURNS: 1 if successfull 0 if an error occurs

*/
int iwu_get_kernel_cfg(struct load_kernel_cfg RFAR *cfg, int card_num)
{
    static char buf[128];
    char *cp;
    char setup[16];
    
    if ((ustr=os_getenv(iw)) == 0L) return(0);
    
    iwu_get_profile_string("languages","default","error",buf,128,ustr);
    if (iwu_strcmp((char RFAR *)buf, (char RFAR *)"error") == 0) return(0);
    iwu_get_profile_string("languages",buf,"error",buf,128,ustr);
    if (iwu_strcmp((char RFAR *)buf, (char RFAR *)"error") == 0) return(0);
    for (cp=buf; *cp && *cp != ','; cp++) ;
    if (*cp == ',') {
	cp++;
    } else {
        return(0);
    }
    while (iwu_isspace(*cp)) cp++;
    iwu_strcpy(cfg->mls_path, cp);
    
    iwu_strcpy(setup, "setup 0");
    setup[6] += (char)card_num;
    cfg->emulation = 0; /* initialize to no emulations */
    iwu_get_profile_string(setup,"UseDma","error",buf,16,ustr);
    if (iwu_strcmp((char RFAR *)buf, (char RFAR *)"error") == 0) return(0);
    if (iwu_strcmp((char RFAR *)buf, (char RFAR *)"true") == 0) {
	cfg->UseDma = 1;
    } else {
	cfg->UseDma = 0;
    }
    iwu_get_profile_string(setup,"csn","error",buf,16,ustr);
    if (iwu_strcmp((char RFAR *)buf, (char RFAR *)"error") == 0) return(0);
    cfg->pnp_csn = (unsigned char)iwu_strtol(buf, 0, 16);
    iwu_get_profile_string(setup,"pnprdp","error",buf,16,ustr);
    if (iwu_strcmp((char RFAR *)buf, (char RFAR *)"error") == 0) return(0);
    cfg->pnp_read_port = (unsigned short)iwu_strtol(buf, 0, 16);
    iwu_get_profile_string(setup,"effects","error",buf,16,ustr);
    if (iwu_strcmp((char RFAR *)buf, (char RFAR *)"error") == 0) {
	cfg->effects = 1;
    } else if (iwu_stricmp((char RFAR *)buf, (char RFAR *)"on") == 0) {
	cfg->effects = 1;
    } else {
	cfg->effects = 0;
    }
    /* the following code is for pre-release chips only */
    iwu_get_profile_string(setup,"revision","NULL",buf,16,ustr);
    if (iwu_stricmp(buf, "A0") == 0) {
      cfg->revision = 0;
    } else if (iwu_stricmp(buf, "A1") == 0) {
      cfg->revision = 1;
    } else if (iwu_stricmp(buf, "A2") == 0) {
      cfg->revision = 2;
    } else if (iwu_stricmp(buf, "A3") == 0) {
      cfg->revision = 3;
    } else if (iwu_stricmp(buf, "B0") >= 0) {
      cfg->revision = 4;
    } else {
      cfg->revision = 4;
    }
    if (cfg->revision < 4) {
	iwu_get_profile_string(setup,"MpuBase","error",buf,16,ustr);
	if (iwu_strcmp((char RFAR *)buf, (char RFAR *)"error") == 0) return(0);
	cfg->mpubase = (unsigned short)iwu_strtol(buf, 0, 16);
    }
    iwu_get_profile_string(setup,"GPusage","none",buf,16,ustr);
    if (iwu_stricmp(buf,"NONE") == 0) {
	cfg->gpusage = none;
    } else if (iwu_stricmp(buf,"PM") == 0) {
	cfg->gpusage = pm;
    } else if (iwu_stricmp(buf,"IRQ") == 0) {
	cfg->gpusage = irq;
    }
    /* the previous code is for pre-release chips only */
    return(1);
}
