ftp.nice.ch/pub/next/developer/languages/lisp/AKCL.1.599.s.tar.gz#/akcl-1-599/c/num_log.c

This is num_log.c in view mode; [Download] [Up]

/*
(c) Copyright Taiichi Yuasa and Masami Hagiya, 1984.  All rights reserved.
Copying of this file is authorized to users who have executed the true and
proper "License Agreement for Kyoto Common LISP" with SIGLISP.
*/

/*
	Logical operations on number
*/
#include "include.h"
#include "num_include.h"
#include "mp.h"
/*
	x : fixnum or bignum (may be not normalized)
	y : integer
   returns
	fixnum or bignum ( not normalized )
*/

object big_log_op();

object
log_op(op)
int (*op)();
{
	object x;
	int	narg, i, j;
	

	narg = vs_top - vs_base;
	if (narg < 2) too_few_arguments();
	i = narg;
	while(--i >= 0)
		if (type_of(vs_base[i]) == t_bignum) goto BIG_OP;
	j = fix(vs_base[0]);
	i = 1;
	while (i < narg) {
		j = (*op)(j, fix(vs_base[i]));
		i++;
	}
	return(make_fixnum(j));

BIG_OP:
	x = (object)copy_to_big(vs_base[0]);
	vs_push(x);
	i = 1;
	{save_avma;
	while (i < narg) {
		x = (object)big_log_op(x, vs_base[i], op);
		i++;
	}
	 restore_avma;}
	x = normalize_big_to_object(x);
	vs_pop;
	return(x);
}
/*
	big_log_op(x, y, op) performs the logical operation op onto
	x and y, and return the result in x destructively.

	
*/

void minimize_lg(x)
GEN x;
{int j,i,lgx = lgef(x);
 GEN u = x+2;
 i = lgx;
 i -= 2;
 while (-- i >= 0)
   { if (*u++) break;
   }
 j = lgx -i -3;
 if (j)
   { GEN v = x+2;
     GEN w = v + j;
     GEN lim = x+lgx;
     while (w<lim)
       {*v++ = *w++;}
     setlgef(x,(i+3));}
 if (i==-1) setsigne(x,0);
}


/* Fix this.   Should be destructive into x0.
   It is for the benefit of log_op;
   Maybe write an mp version, and then do it.
*/   

GEN
complementi(x)
     GEN x;
{int l = lgef(x);
 GEN u = cgeti(l);
 unsigned long * v ;
 unsigned long *w ;

 MP_START_LOW(w,(unsigned long *)x,l);
 MP_START_LOW(v,(unsigned long *)u,l);
 setlgef(u,l);
 setsigne(u,1);
 l -= MP_CODE_WORDS;
 {unsigned int next=0;
  while (--l >=0)
    { unsigned int last = MP_NEXT_UP(w);
      MP_NEXT_UP(v) = next - last ;
       if (last > next)
	 { next -= 1 ;}}
  return u;}}
 
object big_log_op(x0,y0,op)
object x0,y0;
 long (*op)();     
{ int leadx,leady;
  int result_length;
  int lgx,lgy;
  GEN x,y,u,up,result;
  save_avma;
  x = MP(x0);
  y = (type_of(y0)==t_bignum ? MP(y0) : stoi(fix(y0)));
  leadx = signe(x);
  lgx=lgef(x);
  if (leadx < 0)
    x = complementi(x);
  else leadx = 0;

  lgy = lgef(y);
  leady = signe(y);
  if (leady < 0)
    y=complementi(y);
  else leady = 0;
  result_length = (lgx > lgy ? lgx : lgy);
  u = result = cgeti(result_length);
  setlgef(result,result_length);
  MP_START_LOW(u,u,result_length);
  result_length -= MP_CODE_WORDS;

  x += lgx;
  y += lgy;
  lgx -= MP_CODE_WORDS;
  lgy -= MP_CODE_WORDS;

  while (--lgx >= 0)
    { if (--lgy >= 0)
	{ MP_NEXT_UP(u) = (*op)(MP_NEXT_UP(x),MP_NEXT_UP(y));}
    else MP_NEXT_UP(u) = (*op)(MP_NEXT_UP(x),leady);
      }
  /*  lgx is now 0 */
  while (--lgy >= 0)
    {  MP_NEXT_UP(u) = (*op)(leadx,MP_NEXT_UP(y));}
  {int leadresult = (*op)(leadx,leady);
   if (leadresult < 0)
     { result = complementi(result);
       setsigne(result,-1);}
   else setsigne(result,1);}
  minimize_lg(result);
  restore_avma;
  gcopy_to_big(result,x0);
  return x0;
}
   

int
ior_op(i, j)
int	i, j;
{
	return(i | j);
}

int
xor_op(i, j)
int	i, j;
{
	return(i ^ j);
}

int
and_op(i, j)
int	i, j;
{
	return(i & j);
}

int
eqv_op(i, j)
int	i, j;
{
	return(~(i ^ j));
}

int
nand_op(i, j)
int	i, j;
{
	return(~(i & j));
}

int
nor_op(i, j)
int	i, j;
{
	return(~(i | j));
}

int
andc1_op(i, j)
int	i, j;
{
	return((~i) & j);
}

int
andc2_op(i, j)
int	i, j;
{
	return(i & (~j));
}

int
orc1_op(i, j)
int	i, j;
{
	return((~i) | j);
}

int
orc2_op(i, j)
int	i, j;
{
	return(i | (~j));
}

b_clr_op(i, j)
int	i, j;
{
	return(0);
}

b_set_op(i, j)
int	i, j;
{
	return(-1);
}

b_1_op(i, j)
int	i, j;
{
	return(i);
}

b_2_op(i, j)
int	i, j;
{
	return(j);
}

b_c1_op(i, j)
int	i, j;
{
	return(~i);
}

b_c2_op(i, j)
int	i, j;
{
	return(~j);
}

int
big_bitp(x, p)
object	x;
int	p;
{ GEN u = MP(x);
  int ans ;
  int i = p /32;
  if (signe(u) < 0)
    {  save_avma;
       u = complementi(u);
       restore_avma;
   }
  if (i < lgef(u))
    { ans = ((MP_ITH_WORD(u,i,lgef(u))) & (1 << p%32));}
  else if (big_sign(x) < 0) ans = 1;
  else ans = 0;
  return ans;
}

int
fix_bitp(x, p)
object	x;
int	p;
{
	if (p > 30)		/* fix = sign + bit0-30 */
		if (fix(x) < 0)
			return(1);
		else
			return(0);
	return((fix(x) >> p) & 1);
}	

int
count_int_bits(x)
int	x;
{
	int	i, count;

	count = 0;
	for (i=0; i <= 31; i++) count += ((x >> i) & 1);
	return(count);
}

int
count_bits(x)
object	x;
{
	int	i, count, sign;

	if (type_of(x) == t_fixnum) {
		i = fix(x);
		if (i < 0) i = ~i;
		count = count_int_bits(i);
	} else if (type_of(x) == t_bignum)
	  { save_avma;
	    GEN u = MP(x);
	    if (signe(u) < 0)
	      { u = subsi(-1,u);}
	    count = 0;
	    {int leng = lgef(u);
	     MP_START_LOW(u,u,leng);
	     leng -= MP_CODE_WORDS;
	     while (--leng >= 0)
	       { count += count_int_bits(MP_NEXT_UP(u));}}
	    restore_avma;
	  }
	  else
		FEwrong_type_argument(Sinteger, x);
	return(count);
}

/*
	double_shift(h, l, w, hp, lp) shifts the int h & l ( 31 bits)
	w bits to left ( w > 0) or to right ( w < 0).
	result is returned in *hp and *lp.
*/

object
shift_integer(x, w)
object	x;
int	w;
{ GEN u ;
  
  if (type_of(x) == t_fixnum)
    { if (w <= 0) return make_fixnum (fix(x) >> (-w));
      MPOP(return, shifti,stoi(fix(x)),w);
    }
  else
    if (type_of(x) == t_bignum)
      MPOP(return, shifti,MP(x),w);
  else
    	FEwrong_type_argument(Sinteger, x);
    
}
  
int
int_bit_length(i)
int	i;
{
	int	count, j;

	count = 0;
	for (j = 0; j <= 31 ; j++)
		if (((i >> j) & 1) == 1) count = j + 1;
	return(count);
}



Llogior()
{
	object  x;
	int	narg, i;
	int	ior_op();

	narg = vs_top - vs_base;
	for (i = 0; i < narg; i++)
		check_type_integer(&vs_base[i]);
	if (narg == 0) {
		vs_top = vs_base;
		vs_push(small_fixnum(0));
		return;
	}
	if (narg == 1)
		return;
	x = log_op(ior_op);
	vs_top = vs_base;
	vs_push(x);
}

Llogxor()
{
	object  x;
	int	narg, i;
	int	xor_op();

	narg = vs_top - vs_base;
	for (i = 0; i < narg; i++)
		check_type_integer(&vs_base[i]);
	if (narg == 0) {
		vs_top = vs_base;
		vs_push(small_fixnum(0));
		return;
	}
	if (narg == 1) return;
	x = log_op(xor_op);
	vs_top = vs_base;
	vs_push(x);
}

Llogand()
{
	object  x;
	int	narg, i;
	int	and_op();

	narg = vs_top - vs_base;
	for (i = 0; i < narg; i++)
		check_type_integer(&vs_base[i]);
	if (narg == 0) {
		vs_top = vs_base;
		vs_push(small_fixnum(-1));
		return;
	}
	if (narg == 1) return;
	x = log_op(and_op);
	vs_top = vs_base;
	vs_push(x);
}

Llogeqv()
{
	object  x;
	int	narg, i;
	int	eqv_op();

	narg = vs_top - vs_base;
	for (i = 0; i < narg; i++)
		check_type_integer(&vs_base[i]);
	if (narg == 0) {
		vs_top = vs_base;
		vs_push(small_fixnum(-1));
		return;
	}
	if (narg == 1) return;
	x = log_op(eqv_op);
	vs_top = vs_base;
	vs_push(x);
}

Lboole()
{
	object  x;
	object	o, r;
	int	(*op)();

	check_arg(3);
	check_type_integer(&vs_base[0]);
	check_type_integer(&vs_base[1]);
	check_type_integer(&vs_base[2]);
	o = vs_base[0];
	switch(fixint(o)) {
		case BOOLCLR:	op = b_clr_op;	break;
		case BOOLSET:	op = b_set_op;	break;
		case BOOL1:	op = b_1_op;	break;
		case BOOL2:	op = b_2_op;	break;
		case BOOLC1:	op = b_c1_op;	break;
		case BOOLC2:	op = b_c2_op;	break;
		case BOOLAND:	op = and_op;	break;
		case BOOLIOR:	op = ior_op;	break;
		case BOOLXOR:	op = xor_op;	break;
		case BOOLEQV:	op = eqv_op;	break;
		case BOOLNAND:	op = nand_op;	break;
		case BOOLNOR:	op = nor_op;	break;
		case BOOLANDC1:	op = andc1_op;	break;
		case BOOLANDC2:	op = andc2_op;	break;
		case BOOLORC1:	op = orc1_op;	break;
		case BOOLORC2:	op = orc2_op;	break;
		default:
			FEerror("~S is an invalid logical operator.",
				1, o);
	}
	vs_base++;
	x = log_op(op);
	vs_base--;
	vs_top = vs_base;
	vs_push(x);
}

Llogbitp()
{
	object	x, p;
	int	i;

	check_arg(2);
	check_type_integer(&vs_base[0]);
	check_type_integer(&vs_base[1]);
	p = vs_base[0];
	x = vs_base[1];
	if (type_of(p) == t_fixnum)
		if (type_of(x) == t_fixnum)
			i = fix_bitp(x, fix(p));
		else
			i = big_bitp(x, fix(p));
	else if (big_sign(p) < 0)
			i = 0;
		/*
		   bit position represented by bignum is out of
		   our address space. So, result is returned
		   according to sign of integer.
		*/

	else if (type_of(x) == t_fixnum)
		if (fix(x) < 0)
			i = 1;
		else
			i = 0;
	else if (big_sign(x) < 0)
			i = 1;
		else
			i = 0;

	vs_top = vs_base;
	if (i)
		vs_push(Ct);
	else
		vs_push(Cnil);
}

Lash()
{
	object	r, x, y;
	int	w, sign_x;

	check_arg(2);
        check_type_integer(&vs_base[0]);
	check_type_integer(&vs_base[1]);
	x = vs_base[0];
	y = vs_base[1];
	if (type_of(y) == t_fixnum) {
		w = fix(y);
		r = shift_integer(x, w);
	} else if (type_of(y) == t_bignum)
		goto LARGE_SHIFT;
	else
		;
	goto BYE;

	/*
	bit position represented by bignum is probably
	out of our address space. So, result is returned
	according to sign of integer.
	*/
LARGE_SHIFT:
	if (type_of(x) == t_fixnum)
		if (fix(x) > 0)
			sign_x = 1;
		else if (fix(x) == 0)
			sign_x = 0;
		else
			sign_x = -1;
	else
		sign_x = big_sign(x);
	if (big_sign(y) < 0)
		if (sign_x < 0)
			r = small_fixnum(-1);
		else
			r = small_fixnum(0);
	else if (sign_x == 0)
		r = small_fixnum(0);
	else
		FEerror("Insufficient memory.", 0);

BYE:
	vs_top = vs_base;
	vs_push(r);
}

Llogcount()
{
	object	x;
	int	i;

	check_arg(1);
	check_type_integer(&vs_base[0]);
	x = vs_base[0];
	i = count_bits(x);
	vs_top = vs_base;
	vs_push(make_fixnum(i));
}

Linteger_length()
{
	object	x;
	int	count, cell, i;

	check_arg(1);
	x = vs_base[0];
	if (type_of(x) == t_fixnum) {
		i = fix(x);
		if (i < 0) i = ~i;
		count = int_bit_length(i);
	} else if (type_of(x) == t_bignum) 
	  { GEN w,u = MP(x);
	    int l = lg(u);
	    ulong high;
	    w = u;
	    MP_START_HIGH(u,u,l);
	    high = MP_NEXT_DOWN(u);
	    count = int_bit_length(high) ;
	    
	    l -= MP_CODE_WORDS;
	    
	    if (signe(w) < 0 &&
		high == (1 << (count -1)))
	      /* in the case of -(1<< n)
		 it is one less */
	      { int ll = l;
		int nzero = 0;
		while (--ll > 0)
		  { if (MP_NEXT_DOWN(u))
		      {nzero= 1; break;}}
		if (nzero == 0) --count ;}
		
	    count +=               32* (l - 1);
	  }
	else
	      	FEwrong_type_argument(Sinteger, x);
	vs_top = vs_base;
	vs_push(make_fixnum(count));
}

#define W_SIZE (8*sizeof(int))
object
bitand(a,b,c)
     object a,b,c;
{ int d= a->bv.bv_fillp;
  int *ap,*bp,*cp;
  d=(d+W_SIZE-1)/W_SIZE;
  ap= (int *)(a->bv.bv_self);
  bp= (int *)(b->bv.bv_self);
  cp= (int *)(c->bv.bv_self);
  while (--d >= 0)
    { *cp++ = *bp++ & *ap++;
    }
  return c;
}

object
bitior(a,b,c)
     object a,b,c;
{ int *ap,*cp,*bp, d= a->bv.bv_fillp;
  d=(d+W_SIZE-1)/W_SIZE;
   ap= (int *)((a->bv.bv_self));
   bp= (int *)(b->bv.bv_self);
   cp= (int *)(c->bv.bv_self);
  while (--d >= 0)
    { *cp++ = *bp++ | *ap++;
    }
  return c;
}

/* Note in order to be equal we assume that the part above the
   fill pointer is 0 up to the next word */

bvequal(a,b)
     object a,b;
{ int *ap,*bp, d= a->bv.bv_fillp;
  d=(d+W_SIZE-1)/W_SIZE;
 ap= (int *)(a->bv.bv_self);
 bp= (int *)(b->bv.bv_self);
  while (--d >= 0)
    { if (*ap++ != *bp++) return 1;
    }
  return 0;
}

  


init_num_log()
{
	int siLbit_array_op();

	make_constant("BOOLE-CLR", make_fixnum(BOOLCLR));
	make_constant("BOOLE-SET", make_fixnum(BOOLSET));
	make_constant("BOOLE-1", make_fixnum(BOOL1));
	make_constant("BOOLE-2", make_fixnum(BOOL2));
	make_constant("BOOLE-C1", make_fixnum(BOOLC1));
	make_constant("BOOLE-C2", make_fixnum(BOOLC2));
	make_constant("BOOLE-AND", make_fixnum(BOOLAND));
	make_constant("BOOLE-IOR", make_fixnum(BOOLIOR));
	make_constant("BOOLE-XOR", make_fixnum(BOOLXOR));
	make_constant("BOOLE-EQV", make_fixnum(BOOLEQV));
	make_constant("BOOLE-NAND", make_fixnum(BOOLNAND));
	make_constant("BOOLE-NOR", make_fixnum(BOOLNOR));
	make_constant("BOOLE-ANDC1", make_fixnum(BOOLANDC1));
	make_constant("BOOLE-ANDC2", make_fixnum(BOOLANDC2));
	make_constant("BOOLE-ORC1", make_fixnum(BOOLORC1));
	make_constant("BOOLE-ORC2", make_fixnum(BOOLORC2));

	make_function("LOGIOR", Llogior);
	make_function("LOGXOR", Llogxor);
	make_function("LOGAND", Llogand);
	make_function("LOGEQV", Llogeqv);
	make_function("BOOLE", Lboole);
	make_function("LOGBITP", Llogbitp);
	make_function("ASH", Lash);
	make_function("LOGCOUNT", Llogcount);
	make_function("INTEGER-LENGTH", Linteger_length);

	Sbit = make_ordinary("BIT");
	make_si_function("BIT-ARRAY-OP", siLbit_array_op);
}


siLbit_array_op()
{
	int i, j, n, d;
	object  o, x, y, r, r0;
	int (*op)();
	bool replace = FALSE;
	int xi, yi, ri;
	char *xp, *yp, *rp;
	int xo, yo, ro;
	object *base = vs_base;

	check_arg(4);
	o = vs_base[0];
	x = vs_base[1];
	y = vs_base[2];
	r = vs_base[3];
	if (type_of(x) == t_bitvector) {
		d = x->bv.bv_dim;
		xp = x->bv.bv_self;
		xo = x->bv.bv_offset;
		if (type_of(y) != t_bitvector)
			goto ERROR;
		if (d != y->bv.bv_dim)
			goto ERROR;
		yp = y->bv.bv_self;
		yo = y->bv.bv_offset;
		if (r == Ct)
			r = x;
		if (r != Cnil) {
			if (type_of(r) != t_bitvector)
				goto ERROR;
			if (r->bv.bv_dim != d)
				goto ERROR;
			i = (r->bv.bv_self - xp)*8 + (r->bv.bv_offset - xo);
			if (i > 0 && i < d || i < 0 && -i < d) {
				r0 = r;
				r = Cnil;
				replace = TRUE;
				goto L1;
			}
			i = (r->bv.bv_self - yp)*8 + (r->bv.bv_offset - yo);
			if (i > 0 && i < d || i < 0 && -i < d) {
				r0 = r;
				r = Cnil;
				replace = TRUE;
			}
		}
	L1:
		if (r == Cnil) {
			vs_base = vs_top;
			vs_push(Sbit);
			vs_push(make_fixnum(d));
			vs_push(Cnil);
			vs_push(Cnil);
			vs_push(Cnil);
			vs_push(Cnil);
			vs_push(Cnil);
			siLmake_vector();
			r = vs_base[0];
		}
	} else {
		if (type_of(x) != t_array)
			goto ERROR;
		if ((enum aelttype)x->a.a_elttype != aet_bit)
			goto ERROR;
		d = x->a.a_dim;
		xp = x->bv.bv_self;
		xo = x->bv.bv_offset;
		if (type_of(y) != t_array)
			goto ERROR;
		if ((enum aelttype)y->a.a_elttype != aet_bit)
			goto ERROR;
		if (x->a.a_rank != y->a.a_rank)
			goto ERROR;
		yp = y->bv.bv_self;
		yo = y->bv.bv_offset;
		for (i = 0;  i < x->a.a_rank;  i++)
			if (x->a.a_dims[i] != y->a.a_dims[i])
				goto ERROR;
		if (r == Ct)
			r = x;
		if (r != Cnil) {
			if (type_of(r) != t_array)
				goto ERROR;
			if ((enum aelttype)r->a.a_elttype != aet_bit)
				goto ERROR;
			if (r->a.a_rank != x->a.a_rank)
				goto ERROR;
			for (i = 0;  i < x->a.a_rank;  i++)
				if (r->a.a_dims[i] != x->a.a_dims[i])
					goto ERROR;
			i = (r->bv.bv_self - xp)*8 + (r->bv.bv_offset - xo);
			if (i > 0 && i < d || i < 0 && -i < d) {
				r0 = r;
				r = Cnil;
				replace = TRUE;
				goto L2;
			} 
			i = (r->bv.bv_self - yp)*8 + (r->bv.bv_offset - yo);
			if (i > 0 && i < d || i < 0 && -i < d) {
				r0 = r;
				r = Cnil;
				replace = TRUE;
			}
		}
	L2:
		if (r == Cnil) {
			vs_base = vs_top;
			vs_push(Sbit);
			vs_push(Cnil);
			vs_push(Cnil);
			vs_push(Cnil);
			vs_push(Cnil);
			for (i = 0;  i < x->a.a_rank;  i++)
				vs_push(make_fixnum(x->a.a_dims[i]));
			siLmake_pure_array();
			r = vs_base[0];
		}
	}
	rp = r->bv.bv_self;
	ro = r->bv.bv_offset;
	switch(fixint(o)) {
		case BOOLCLR:	op = b_clr_op;	break;
		case BOOLSET:	op = b_set_op;	break;
		case BOOL1:	op = b_1_op;	break;
		case BOOL2:	op = b_2_op;	break;
		case BOOLC1:	op = b_c1_op;	break;
		case BOOLC2:	op = b_c2_op;	break;
		case BOOLAND:	op = and_op;	break;
		case BOOLIOR:	op = ior_op;	break;
		case BOOLXOR:	op = xor_op;	break;
		case BOOLEQV:	op = eqv_op;	break;
		case BOOLNAND:	op = nand_op;	break;
		case BOOLNOR:	op = nor_op;	break;
		case BOOLANDC1:	op = andc1_op;	break;
		case BOOLANDC2:	op = andc2_op;	break;
		case BOOLORC1:	op = orc1_op;	break;
		case BOOLORC2:	op = orc2_op;	break;
		default:
			FEerror("~S is an invalid logical operator.", 1, o);
	}

#define	set_high(place, nbits, value) \
	((place)=((place)&~(-0400>>(nbits))|(value)&(-0400>>(nbits))))

#define	set_low(place, nbits, value) \
	((place)=((place)&(-0400>>(8-(nbits)))|(value)&~(-0400>>(8-(nbits)))))

#define	extract_byte(integer, pointer, index, offset) \
	(integer) = (pointer)[(index)+1] & 0377; \
	(integer) = ((pointer)[index]<<(offset))|((integer)>>(8-(offset)))

#define	store_byte(pointer, index, offset, value) \
	set_low((pointer)[index], 8-(offset), (value)>>(offset)); \
	set_high((pointer)[(index)+1], offset, (value)<<(8-(offset)))

	if (xo == 0 && yo == 0 && ro == 0) {
		for (n = d/8, i = 0;  i < n;  i++)
			rp[i] = (*op)(xp[i], yp[i]);
		if ((j = d%8) > 0)
			set_high(rp[n], j, (*op)(xp[n], yp[n]));
		if (!replace) {
			vs_top = vs_base = base;
			vs_push(r);
			return;
		}
	} else {
		for (n = d/8, i = 0;  i <= n;  i++) {
			extract_byte(xi, xp, i, xo);
			extract_byte(yi, yp, i, yo);
			if (i == n) {
				if ((j = d%8) == 0)
					break;
				extract_byte(ri, rp, n, ro);
				set_high(ri, j, (*op)(xi, yi));
			} else
				ri = (*op)(xi, yi);
			store_byte(rp, i, ro, ri);
		}
		if (!replace) {
			vs_top = vs_base = base;
			vs_push(r);
			return;
		}
	}
	rp = r0->bv.bv_self;
	ro = r0->bv.bv_offset;
	for (n = d/8, i = 0;  i <= n;  i++) {
		if (i == n) {
			if ((j = d%8) == 0)
				break;
			extract_byte(ri, rp, n, ro);
			set_high(ri, j, r->bv.bv_self[n]);
		} else
			ri = r->bv.bv_self[i];
		store_byte(rp, i, ro, ri);
	}
	vs_top = vs_base = base;
	vs_push(r0);
	return;

ERROR:
	FEerror("Illegal arguments for bit-array operation.", 0);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.