global string_first;

constant STRING_NEXT 0;
constant STRING_PTR 1;
constant STRING_LEN 2;
constant STRING_REF 3;
constant STRING__SIZE (4*2);

! Initialise the string store.

[ string_init;
	string_first = 0;
];

! Returns false if the string is constant (i.e., it points to a literal in
! the byte-code itself).

[ string_isvar s;
	return ((s < store_bottom) || (s > store_eop));
];

! Add an entry for a new string.

[ string_alloc str len  s;
	if (string_isvar(str))
	{
		! Need to duplicate the string.
		s = mem_alloc(len);
		memcpy(s, str, len);
		str = s;
	}
	s = mem_alloc(STRING__SIZE);
	s-->STRING_NEXT = string_first;
	s-->STRING_PTR = str;
	s-->STRING_LEN = len;
	string_first = s;
	return s;
];

! Print a string.

[ string_print s  i;
	i = s-->STRING_LEN;
	s = s-->STRING_PTR;
	while (i--)
		print (char) (s++)->0;
];

! Compare two strings.

[ string_compare s1 s2  i;
	i = s1-->STRING_LEN;
	if (i ~= s2-->STRING_LEN)
		return -1;
	s1 = s1-->STRING_PTR;
	s2 = s2-->STRING_PTR;
	while (i--)
		if ((s1++)->0 ~= (s2++)->0)
			return -1;
	return 0;
];

! Garbage collection: clean.

[ string_clean  s;
	s = string_first;
	while (s)
	{
		s-->STRING_REF = 0;
		s = s-->STRING_NEXT;
	}
];

! Garbage collection: mark.

[ string_mark  var;
	var = store_firstvar;
	while (var)
	{
		if (var-->VN_TYPE == TYPE_STRING)
			var-->VN_VALUE-->STRING_REF = 1;
		var = var-->VN_NEXT;
	}
];
			
#ifdef DEBUG;
! Garbage collection: list status.

[ string_status  s;
	s = string_first;
	while (s)
	{
		print s, " ", s-->STRING_NEXT, " ";
		string_print(s);
		print " ", s-->STRING_REF, "^";
		s = s-->STRING_NEXT;
	}
];
#endif;

! Garbage collection: sweep.

[ string_sweep  s olds news;
	olds = 0;
	s = string_first;
	while (s)
	{
		news = s-->STRING_NEXT;
		if (s-->STRING_REF == 0)
		{
			if (string_isvar(s-->STRING_PTR))
				mem_free(s-->STRING_PTR);
			if (olds)
				olds-->STRING_NEXT = news;
			else
			{
				! If olds is null, then we're on the first
				! string in the list; which means we need to
				! change string_first when we remove it.
				string_first = news;
			}
			mem_free(s);
		}
		else
			olds = s;
			
		s = news;
	}
];
	
! Garbage collector.

[ string_gc;
	! Phase one: clean.
	string_clean();
	! Phase two: mark.
	string_mark();
#ifdef DEBUG;
	!string_status();
#endif;
	! Phase three: sweep.
	string_sweep();
];

! Turn a string into an int.

[ string_toint s  len i neg;
	len = s-->STRING_LEN;
	s = s-->STRING_PTR;
	i = 0;
	neg = 1;

	while (len && (s->0 == 32 or 9))
	{
		s++;
		len--;
	}

	if (len == 0)
		return i;
	
	if (s->0 == '-')
	{
		neg = -1;
		s++;
		len--;
	}

	if (len == 0)
		return i;
	
	while (len && (s->0 >= '0') && (s->0 <= '9'))
	{
		i = i*10 + (s->0 - '0');
		s++;
		len--;
	}

	return i*neg;
];
