/*       mystring.c                Copyright (C)  2002    Georg Post
 *
 *  This file is part of Numparam, see:  readme.txt  
 *  Free software under the terms of the GNU Lesser General Public License
 * $Id: mystring.c,v 1.16 2010/09/01 21:13:01 h_vogt Exp $
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <math.h>
#include <stdarg.h>

#include "config.h"
#ifdef HAS_WINDOWS
#include "wstdio.h"
#endif

#include "general.h"

#include "../error.h" /* controlled_exit() */

#define EOS  '\0'

/***** primitive input-output ***/

int
ci_prefix (register char *p, register char *s)
{
  while (*p)
    {
      if ((isupper (*p) ? tolower (*p) : *p) !=
	  (isupper (*s) ? tolower (*s) : *s))
	return (0);
      p++;
      s++;
    }
  return (1);
}

void
wc (char c)
{
  fputc (c, stdout);
}

void
wln (void)
{
  wc ('\n');
}

void
ws (char *s)
{
  int k = 0;

  while (s[k] != 0)
    {
      wc (s[k]);
      k++;
    }
}

void
wi (long i)
{
  SPICE_DSTRING s ;
  spice_dstring_init(&s) ;
  nadd (&s, i);
  ws ( spice_dstring_value(&s)) ;
  spice_dstring_free(&s) ;
}

void
rs ( SPICE_DSTRINGPTR dstr_p)
{				/* basic line input, limit= 80 chars */
  char c;


  spice_dstring_reinit(dstr_p) ;
  do
    {
      c = fgetc (stdin);
      cadd (dstr_p, c);
    }
  while (!((c == Cr) || (c == '\n')));
  /* return i */ ;
}

char
rc (void)
{
  int ls;
  char val ;
  char *s_p ;
  SPICE_DSTRING dstr ;

  spice_dstring_init(&dstr) ;
  rs (&dstr);
  ls = spice_dstring_length (&dstr);
  if (ls > 0){
    s_p = spice_dstring_value(&dstr) ;
    val = s_p[ls - 1] ;
  } else {
    val = 0 ;
  }
  spice_dstring_free(&dstr) ;
  return val ;

}

/*******  Strings ************
 *  are 0-terminated char arrays with a 2-byte trailer: max length.
 *  the string mini-library is "overflow-safe" under these conditions:
 *    use Str(n,s) macro: define and initialize a string s of maxlen n<255
 *    use sini() to initialize empty strings;  sfix() for non-empty ones.
 *    the Sini() macro does automatic sizing, for automatic char arrays
 *    to allocate a string on the heap, use newstring(n).
 *    use maxlen() and length() to retrieve string max and actual length
 *    use: cadd, cins, sadd, sins, scopy, pscopy to manipulate them
 *    never put '\x0' characters inside strings !
 *
 *    the 'killer idea' is the following:
 *    on string overflow and/or on heap allocation failure, a program
 *    MUST die.   Now we only die on a heap failure as with dynamic
 *    string we cannot have a string overflow.
 */

void
sfix ( SPICE_DSTRINGPTR dstr_p, int len)
/* suppose s is allocated and filled with non-zero stuff */
{
  /* This function will now eliminate the max field.   The length of
   * the string is going to be i-1 and a null is going to be added
   * at the ith position to be compatible with old codel.  Also no
   * null characters will be present in the string leading up to the
   * NULL so this will make it a valid string. */
  int j;
  char *s ;

  spice_dstring_setlength( dstr_p, len ) ;
  s = spice_dstring_value( dstr_p ) ;
  for (j = 0; j < len; j++)	/* eliminate null characters ! */
    if (s[j] == 0)
      s[j] = 1;

}

int
length (char *s)
{
  int lg = 0;

  while (s[lg])
    lg++;

  return lg;
}

/* -----------------------------------------------------------------
 * Function: add string t to dynamic string dstr_p.
 * ----------------------------------------------------------------- */
unsigned char
sadd ( SPICE_DSTRINGPTR dstr_p, char *t)
{
  spice_dstring_append( dstr_p, t, -1 ) ;
  return 1 ;
}

/* -----------------------------------------------------------------
 * Function: add character c to dynamic string dstr_p.
 * ----------------------------------------------------------------- */
unsigned char
cadd ( SPICE_DSTRINGPTR dstr_p, char c)
{
  char tmp_str[2] ;
  tmp_str[0] = c ;
  tmp_str[1] = 0 ;
  spice_dstring_append( dstr_p, tmp_str, -1 ) ;
  return 1 ;
}

/* -----------------------------------------------------------------
 * Function: insert character c at front of dynamic string dstr_p
 * ----------------------------------------------------------------- */
unsigned char
cins ( SPICE_DSTRINGPTR dstr_p, char c)
{
  int i ;
  int ls ;
  char *s_p ;
  
  ls = spice_dstring_length(dstr_p) ;
  spice_dstring_setlength(dstr_p,ls+2) ; /* make sure we have space for char + EOS */
  s_p = spice_dstring_value(dstr_p) ;
  for (i = ls + 1; i >= 0; i--)
    s_p[i + 1] = s_p[i];
  s_p[0] = c;
  return 1 ;
}

/* -----------------------------------------------------------------
 * Function: insert string t at front of dynamic string dstr_p
 * ----------------------------------------------------------------- */
unsigned char
sins ( SPICE_DSTRINGPTR dstr_p, char *t)
{
  int i ;
  int ls ;
  int lt ;
  char *s_p ;
  
  ls = spice_dstring_length(dstr_p) ;
  lt = length (t) ;
  spice_dstring_setlength(dstr_p,ls+lt+1) ; /* make sure we have space for string + EOS */
  s_p = spice_dstring_value(dstr_p) ;
  for (i = ls + 1; i >= 0; i--)
    s_p[i + lt] = s_p[i];

  for (i = 0; i < lt; i++)
    s_p[i] = t[i];
  return 1 ;

}

int
cpos (char c, char *s)
/* return position of c in s, or 0 if not found.
 * BUG, Pascal inherited: first char is at 1, not 0 !
 * No longer!  Now position is C-based to make life easier.
 */
{
  int i = 0;
  while ((s[i] != c) && (s[i] != 0))
    i++;

  if (s[i] == c)
    return i ;
  else
    return -1 ;
}

char
upcase (char c)
{
  if ((c >= 'a') && (c <= 'z'))
    return c + 'A' - 'a';
  else
    return c;
}

/* -----------------------------------------------------------------
 * Create copy of the dynamic string.  Dynamic strings are always NULL
 * terminated.
 * ----------------------------------------------------------------- */
unsigned char
scopyd(SPICE_DSTRINGPTR s, SPICE_DSTRINGPTR t)	/* returns success flag */
{
  spice_dstring_reinit( s ) ;
  spice_dstring_append( s, spice_dstring_value(t), -1 ) ;
  return 1 ; /* Dstrings expand to any length */
}

/* -----------------------------------------------------------------
 * Create copy of the string in the dynamic string.  Dynamic strings 
 * are always NULLterminated.
 * ----------------------------------------------------------------- */
unsigned char
scopys(SPICE_DSTRINGPTR s, char *t)	/* returns success flag */
{
  spice_dstring_reinit( s ) ;
  spice_dstring_append( s, t, -1 ) ;
  return 1 ; /* Dstrings expand to any length */
}

/* -----------------------------------------------------------------
 * Create an upper case copy of a string and store it in a dynamic string.
 * Dynamic strings are always NULL * terminated.
 * ----------------------------------------------------------------- */
unsigned char
scopy_up (SPICE_DSTRINGPTR dstr_p, char *str)	/* returns success flag */
{
  char up[2] ;			/* short string */
  char *ptr ;			/* position in string */

  spice_dstring_reinit( dstr_p ) ;
  up[1] = 0 ;
  for( ptr = str ; ptr && *ptr ; ptr++ ){
    up[0] = upcase ( *ptr );
    spice_dstring_append( dstr_p, up, 1 ) ;
  }
  return 1 ; /* Dstrings expand to any length */
}

/* -----------------------------------------------------------------
 * Create a lower case copy of a string and store it in a dynamic string.
 * Dynamic strings are always NULL * terminated.
 * ----------------------------------------------------------------- */
unsigned char
scopy_lower (SPICE_DSTRINGPTR dstr_p, char *str)	/* returns success flag */
{
  char low[2] ;			/* short string */
  char *ptr ;			/* position in string */

  spice_dstring_reinit( dstr_p ) ;
  low[1] = 0 ;
  for( ptr = str ; ptr && *ptr ; ptr++ ){
    low[0] = lowcase ( *ptr );
    spice_dstring_append( dstr_p, low, 1 ) ;
  }
  return 1 ; /* Dstrings expand to any length */
}

unsigned char
ccopy ( SPICE_DSTRINGPTR dstr_p, char c)	/* returns success flag */
{
  char *s_p ;			/* current string */

  sfix ( dstr_p, 1);
  s_p = spice_dstring_value(dstr_p) ;
  s_p[0] = c ;
  return 1 ;
}

char *
pscopy (SPICE_DSTRINGPTR dstr_p, char *t, int start, int leng)
/* partial string copy, with C-based start - Because we now have a 0 based
 * start and string may copy outselves, we may need to restore the first
 * character of the original dstring because resetting string will wipe
 * out first character. */
{
  int i;					/* counter */
  int stop ;					/* stop value */
  char *s_p ;					/* value of dynamic string */

  stop = length(t) ;

  if (start < stop) {				/* nothing! */
    if ((start + leng - 1) > stop) {
//      leng = stop - start + 1;
      leng = stop - start ;
    }
    _spice_dstring_setlength(dstr_p,leng) ;
    s_p = spice_dstring_value(dstr_p) ;
    for (i = 0; i < leng; i++)
      s_p[i] = t[start + i];
    s_p[leng] = EOS ;
  } else {
    s_p = spice_dstring_reinit(dstr_p) ;
  }
  return s_p ;
}

char *
pscopy_up (SPICE_DSTRINGPTR dstr_p, char *t, int start, int leng)
/* partial string copy to upper case, with C convention for start. */
{
  int i;					/* counter */
  int stop ;					/* stop value */
  char *s_p ;					/* value of dynamic string */

  stop = length(t) ;

  if (start < stop) {				/* nothing! */
    if ((start + leng - 1) > stop) {
//      leng = stop - start + 1;
      leng = stop - start ;
    }
    _spice_dstring_setlength(dstr_p,leng) ;
    s_p = spice_dstring_value(dstr_p) ;
    for (i = 0; i < leng; i++)
      s_p[i] = upcase ( t[start + i] ) ;
    s_p[leng] = EOS ;
  } else {
    s_p = spice_dstring_reinit(dstr_p) ;
  }
  return s_p ;
}

int
ord (char c)
{
  return (c & 0xff);
}				/* strip high byte */

int
pred (int i)
{
  return (--i);
}

int
succ (int i)
{
  return (++i);
}

unsigned char
nadd ( SPICE_DSTRINGPTR dstr_p, long n)
/* append a decimal integer to a string */
{
  int d[25];
  int j, k ;
  char sg;			/* the sign */
  char load_str[2] ;		/* used to load dstring */
  k = 0;

  if (n < 0)
    {
      n = -n;
      sg = '-';
    }
  else
    sg = '+';

  while (n > 0)
    {
      d[k] = n % 10;
      k++;
      n = n / 10;
    }

  if (k == 0)
    cadd (dstr_p, '0');
  else {
      load_str[1] = 0 ;
      if (sg == '-')
	{
	  load_str[0] = sg ;
	  spice_dstring_append( dstr_p, load_str, 1 ) ;
	}
      for (j = k - 1; j >= 0; j--) {
	  load_str[0] = d[j] + '0';
	  spice_dstring_append( dstr_p, load_str, 1 ) ;
      }
    }

  return 1 ;
}

unsigned char
naddll (SPICE_DSTRINGPTR dstr_p, long long n)
/* append a decimal integer (but a long long) to a string */
{
  int d[25];
  int j, k ;
  char sg;			/* the sign */
  char load_str[2] ;		/* used to load dstring */
  k = 0;

  if (n < 0)
    {
      n = -n;
      sg = '-';
    }
  else
    sg = '+';

  while (n > 0)
    {
      d[k] = n % 10;
      k++;
      n = n / 10;
    }

  if (k == 0)
    cadd (dstr_p, '0');
  else {
      load_str[1] = 0 ;
      if (sg == '-')
	{
	  load_str[0] = sg ;
	  spice_dstring_append( dstr_p, load_str, 1 ) ;
	}
      for (j = k - 1; j >= 0; j--) {
	  load_str[0] = d[j] + '0';
	  spice_dstring_append( dstr_p, load_str, 1 ) ;
      }
    }

  return 1 ;
}

void
stri (long n, SPICE_DSTRINGPTR dstr_p)
/* convert integer to string */
{
  spice_dstring_reinit( dstr_p ) ;
  nadd (dstr_p, n) ;
}

void
rawcopy (void *a, void *b, int la, int lb)
/* dirty binary copy */
{
  int j, n;
  if (lb < la)
    n = lb;
  else
    n = la;

  for (j = 0; j < n; j++)
    ((char *) a)[j] = ((char *) b)[j];
}

int
scompare (char *a, char *b)
{
  unsigned short j = 0;
  int k = 0;
  while ((a[j] == b[j]) && (a[j] != 0) && (b[j] != 0))
    j++;

  if (a[j] < b[j])
    k = -1;
  else if (a[j] > b[j])
    k = 1;

  return k;
}

unsigned char
steq (char *a, char *b)		/* string a==b test */
{
  unsigned short j = 0;
  while ((a[j] == b[j]) && (a[j] != 0) && (b[j] != 0))
    j++;

  return ((a[j] == 0) && (b[j] == 0)) /* string equality test */ ;
}

unsigned char
stne (char *s, char *t)
{
  return scompare (s, t) != 0;
}

int
hi (long w)
{
  return (w & 0xff00) >> 8;
}

int
lo (long w)
{
  return (w & 0xff);
}

char
lowcase (char c)
{
  if ((c >= 'A') && (c <= 'Z'))
    return (char) (c - 'A' + 'a');
  else
    return c;
}

unsigned char
alfa (char c)
{
  return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || c == '_'
    || c == '[' || c == ']';
}

unsigned char
num (char c)
{
  return (c >= '0') && (c <= '9');
}

unsigned char
alfanum (char c)
{
  return alfa (c) || ((c >= '0') && (c <= '9'));
}

int
freadstr (FILE * f, SPICE_DSTRINGPTR dstr_p)
/* read a line from a file. 
   was BUG: long lines truncated without warning, ctrl chars are dumped.
   Bug no more as we can only run out of memory.  Removed max argument.
*/
{
  char c;
  char str_load[2] ;
  int len = 0 ;

  str_load[0] = 0 ;
  str_load[1] = 0 ;
  spice_dstring_reinit(dstr_p) ;
  do
    {
      c = fgetc (f);		/*  tab is the only control char accepted */
      if (((c >= ' ') || (c < 0) || (c == Tab)))
	{
	  str_load[0] = c;
	  spice_dstring_append( dstr_p, str_load, 1 ) ;
	}
    }
  while (!(feof (f) || (c == '\n')));


  return len ;
}

char
freadc (FILE * f)
{
  return fgetc (f);
}

long
freadi (FILE * f)
/* reads next integer, but returns 0 if none found. */
{
  long z = 0;
  unsigned char minus = 0;
  char c;

  do
    {
      c = fgetc (f);
    }
  while (!(feof (f) || !((c > 0) && (c <= ' '))));	/* skip space */

  if (c == '-')
    {
      minus = 1;
      c = fgetc (f);
    }

  while (num (c))
    {
      z = 10 * z + c - '0';
      c = fgetc (f);
    }

  ungetc (c, f);		/* re-push character lookahead */

  if (minus)
    z = -z;

  return z;
}

char *
stupcase (char *s)
{
  int i = 0;

  while (s[i] != 0)
    {
      s[i] = upcase (s[i]);
      i++;
    }

  return s;
}

/*****  pointer tricks: app won't use naked malloc(), free() ****/

void
dispose (void *p)
{
  if (p != NULL)
    free (p);
}

void *
new (long sz)
{
  void *p;
  if (sz <= 0)
    return NULL;
  else
    {
      p = tmalloc (sz);
      if (p == NULL)
	{			/* fatal error */
	  ws (" new() failure. Program halted.\n");
          controlled_exit(EXIT_FAILURE);
	}
      return p;
    }
}

/***** elementary math *******/

double
sqr (double x)
{
  return x * x;
}

double
absf (double x)
{
  if (x < 0.0)
    return -x;
  else
    return x;
}

long
absi (long i)
{
  if (i >= 0)
    return (i);
  else
    return (-i);
}

void
strif (long i, int f, SPICE_DSTRINGPTR dstr_p)
/* formatting like str(i:f,s) in Turbo Pascal */
{
  int j, k ;
  char cs;
  char t[32];
  char load_str[2] ;			/* load dstring */
  k = 0;

  if (i < 0)
    {
      i = -i;
      cs = '-';
    }
  else
    {
      cs = ' ';
    }

  while (i > 0)
    {
      j = (int) (i % 10);
      i = (long) (i / 10);
      t[k] = (char)('0' + j);
      k++;
    }

  if (k == 0)
    {
      t[k] = '0';
      k++;
    }

  if (cs == '-')
    t[k] = cs;
  else
    k--;

  /* now the string  is in 0...k in reverse order */
  for (j = 1; j <= k; j++)
    t[k + j] = t[k - j];	/* mirror image */

  t[2 * k + 1] = 0;		/* null termination */
  load_str[1] = 0 ;		/* not really needed */
  spice_dstring_reinit(dstr_p) ;

  if ((f > k) && (f < 40))
    {				/* reasonable format */
      for (j = k + 2; j <= f; j++)
	{
	  load_str[0] = ' ';
	  spice_dstring_append( dstr_p, load_str, 1 ) ;
	}
    }

  for (j = 0; j <= k + 1; j++){
    load_str[0] = t[k + j];	/* shift t down */
    spice_dstring_append( dstr_p, load_str, 1 ) ;
  }
}

unsigned char
odd (long x)
{
  return (x & 1);
}

int
vali (char *s, long *i)
/* convert s to integer i. returns error code 0 if Ok */
/* BUG: almost identical to ival() with arg/return value swapped ... */
{
  int k = 0, digit = 0, ls;
  long z = 0;
  unsigned char minus = 0, ok = 1;
  char c;
  ls = length (s);

  do
    {
      c = s[k];
      k++;
    }
  while (!((k >= ls) || !((c > 0) && (c <= ' '))));	/* skip space */

  if (c == '-')
    {
      minus = 1;
      c = s[k];
      k++;
    }

  while (num (c))
    {
      z = 10 * z + c - '0';
      c = s[k];
      k++;
      digit++;
    }

  if (minus)
    z = -z;

  *i = z;
  ok = (digit > 0) && (c == 0);	/* successful end of string */

  if (ok)
    return 0;
  else
    return k;			/* one beyond error position */
}

static unsigned char
match (char *s, char *t, int n, int tstart, unsigned char testcase)
{
/* returns 0 if ( tstart is out of range. But n may be 0 ? */
/* 1 if s matches t[tstart...tstart+n]  */
  int i, j, lt;
  unsigned char ok;
  char a, b;
  i = 0;
  j = tstart;
  lt = length (t);
  ok = (tstart < lt);

  while (ok && (i < n))
    {
      a = s[i];
      b = t[j];
      if (!testcase)
	{
	  a = upcase (a);
	  b = upcase (b);
	}
      ok = (j < lt) && (a == b);
      i++;
      j++;
    }
  return ok;
}

int
posi (char *sub, char *s, int opt)
/* find position of substring in s */
{
  /* opt=0: like Turbo Pascal */
  /* opt=1: like Turbo Pascal Pos, but case insensitive */
  /* opt=2: position in space separated wordlist for scanners */
  int a, b, k, j;
  unsigned char ok, tstcase;
  SPICE_DSTRING tstr ;

  ok = 0;
  spice_dstring_init(&tstr) ;
  tstcase = (opt == 0);

  if (opt <= 1)
    scopys (&tstr, sub);
  else
    {
      cadd (&tstr, ' ');
      sadd (&tstr, sub);
      cadd (&tstr, ' ');
    }

  a = spice_dstring_length(&tstr) ;
  b = (int) (length (s) - a);
  k = 0;
  j = 1;

  if (a > 0)			/* ;} else { return 0 */
    while ((k <= b) && (!ok))
      {
	ok = match ( spice_dstring_value(&tstr), s, a, k, tstcase);	/* we must start at k=0 ! */
	k++;
	if (s[k] == ' ')
	  j++; /* word counter */ ;
      }

  if (opt == 2)
    k = j;

  if (ok)
    return k;
  else
    return 0;

}

int
spos_(char *sub, char *s)
/* equivalent to Turbo Pascal pos().
   BUG: counts 1 ... length(s), not from 0 like C  
*/
{
  char *ptr;

  if ((ptr = strstr (s, sub)))
    return strlen (s) - strlen (ptr) ;
  else
    return -1 ;

}

/**** float formatting with printf/scanf ******/

int
valr (char *s, double *r)
/* returns 0 if ok, else length of partial string ? */
{
  int n = sscanf (s, "%lG", r);
  if (n == 1)
    return (0);
  else
    return (1);
}

void
strf (double x, int f1, int f2, SPICE_DSTRINGPTR dstr_p)
/* e-format if f2<0, else f2 digits after the point, total width=f1 */
/* if f1=0, also e-format with f2 digits */
{				/* default f1=17, f2=-1 */
  int dlen ;			/* length of digits */
  char *dbuf_p ;		/* beginning of sprintf buffer */
  SPICE_DSTRING fmt ;		/* format string */
  SPICE_DSTRING dformat ;	/* format float */

  spice_dstring_init(&fmt) ;
  spice_dstring_init(&dformat) ;
  cadd (&fmt, '%');
  if (f1 > 0)
    {
      nadd (&fmt, f1);		/* f1 is the total width */
      if (f2 < 0)
	sadd (&fmt, "lE");	/* exponent format */
      else
	{
	  cadd (&fmt, '.');
	  nadd (&fmt, f2);
	  sadd (&fmt, "lg");
	}
    }
  else
    {
      cadd (&fmt, '.');
      nadd (&fmt, absi (f2 - 6));	/* note the 6 surplus positions */
      cadd (&fmt, 'e');
    }

  dlen = 2 * (f1 + f2) + 1 ;   /* be conservative */
  dbuf_p = spice_dstring_setlength(&dformat, dlen)  ;
  sprintf (dbuf_p, spice_dstring_value(&fmt), x);
  scopys( dstr_p, dbuf_p ) ;

  spice_dstring_free(&fmt) ;
  spice_dstring_free(&dformat) ;
}

double
rval (char *s, int *err)
/* returns err=0 if ok, else length of partial string ? */
{
  double r = 0.0;
  int n = sscanf (s, "%lG", &r);

  if (n == 1)
    (*err) = 0;
  else
    (*err) = 1;

  return r;
}

long
ival (char *s, int *err)
/* value of s as integer string.  error code err= 0 if Ok */
{
  int k = 0, digit = 0, ls;
  long z = 0;
  unsigned char minus = 0, ok = 1;
  char c;
  ls = length (s);

  do
    {
      c = s[k];
      k++;
    }
  while (!((k >= ls) || !((c > 0) && (c <= ' '))));	/* skip space */

  if (c == '-')
    {
      minus = 1;
      c = s[k];
      k++;
    }

  while (num (c))
    {
      z = 10 * z + c - '0';
      c = s[k];
      k++;
      digit++;
    }

  if (minus)
    z = -z;

  ok = (digit > 0) && (c == 0);	/* successful end of string */

  if (ok)
    (*err) = 0;
  else
    (*err) = k;			/* one beyond error position */

  return z;
}

#ifndef HAVE_LIBM

long
np_round (double x)
/* using <math.h>, it would be simpler: floor(x+0.5), see below */
{
  double u;
  long z;
  int n;
//  Str (40, s);
  SPICE_DSTRING s ;
  spice_dstring_init(&s) ;
  u = 2e9;
  if (x > u)
    x = u;
  else if (x < -u)
    x = -u;

  n = sprintf (s, "%-12.0f", x);
  s[n] = 0;
  sscanf (s, "%ld", &z);
  return z;
}

long
np_trunc (double x)
{
  long n = np_round (x);
  if ((n > x) && (x >= 0.0))
    n--;
  else if ((n < x) && (x < 0.0))
    n++;

  return n;
}

double
frac (double x)
{
  return x - np_trunc (x);
}

double
intp (double x)
{
  double u = 2e9;
  if ((x > u) || (x < -u))
    return x;
  else
    return np_trunc (x);
}

#else /* use floor() and ceil() */

long
np_round (double r)
{
  return (long) floor (r + 0.5);
}

long
np_trunc (double r)
{
  if (r >= 0.0)
    return (long) floor (r);
  else
    return (long) ceil (r);
}

double
frac (double x)
{
  if (x >= 0.0)
    return (x - floor (x));
  else
    return (x - ceil (x));
}

double
intp (double x)			/* integral part */
{
  if (x >= 0.0)
    return floor (x);
  else
    return ceil (x);
}

#endif
