

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

                      Copyright (c) 1984 by Nick de Smith

        This software is supplied for interest and non-profit making
        purposes  only.   Under  no  circumstance  shall it be lent,
        copied or otherwise used for profit.  All  rights  regarding
        the  use  and  ownership of this software shall at all times
        remain with the author, who does not guarantee the  accuracy
        or  reliabilty  of this software and who will not accept any
        liability for its use.

        This software may not be copied or distributed  without  the
        inclusion of the above copyright notice.

        January 31st 1984

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

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


	Program :	CAM

	Module	:	SYMB.C

	Author	:	Nick de Smith		November/December 1982

	Description :

			Symbol table management for CAM

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

#define	MODULE

#include	<stdio.h>

#include	"cam.h"


/*************************************************************************
*
*
*				i n s e r t
*				-----------
*
*	Insert a symbol into the relevent part of the symbol table. This
*	is a really horrid piece of code; maybe I'll pretty it up sometime.
*
*************************************************************************/
global
insert(seg, offset, name, flags)
int	seg, name[], flags;
unsigned int offset;
{
	register SYMBOL_PTR	s_ptr;
	register SYMBOL_PTR	ptr;
	register PSECT_PTR	p_ptr;
		 SYMBOL_PTR	add_symb();
		 char		*radnam();

	dbg("Adding symbol \"%s\", seg: %03o, off: %o, flags: %o\n",
			radnam(name), seg, offset, flags);

	if (flags & S_GREF) {
		if (ref_st)
			ref_end = add_symb(&(ref_end->s_next), offset, name, flags, NULL);
		else
			ref_end = add_symb(&ref_st, offset, name, flags, NULL);
		return;
	}

	if (flags & S_GABS) {
		if (abs_st)
			abs_end = add_symb(&(abs_end->s_next), offset, name, flags, NULL);
		else
			abs_end = add_symb(&abs_st, offset, name, flags, NULL);
		return;
	}

	p_ptr = &segtbl[seg];
	if (!(ptr = p_ptr->p_symb)) {
		add_symb(&(p_ptr->p_symb), offset, name, flags, NULL);
		return;
	}

	if (ptr->s_offset > offset) {
		add_symb(&(p_ptr->p_symb), offset, name, flags, ptr);
		return;
	}

	if (ptr->s_offset == offset) {
		if (flags & S_WEAK) {
			ptr->s_flags |= flags & ~S_WEAK;
			return;
		}
		add_symb(&(p_ptr->p_symb), offset, name, flags, ptr);
		return;
	}

	s_ptr = ptr->s_next;

	while (s_ptr) {
		if (offset <= s_ptr->s_offset && flags & S_STRONG)
			break;
		if (offset < s_ptr->s_offset)
			break;
		if (offset == s_ptr->s_offset)
			if (flags & S_WEAK) {
				s_ptr->s_flags |= flags & ~S_WEAK;
				return;
			}
			else
				break;
		ptr = s_ptr;
		s_ptr = s_ptr->s_next;
	}
	add_symb(&(ptr->s_next), offset, name, flags, s_ptr);
}


/*************************************************************************
*
*
*			a d d _ s y m b
*			---------------
*
*	Add a new symbol into the right tree
*
*************************************************************************/
local SYMBOL_PTR
add_symb(from, offset, name, flags, next)
SYMBOL_PTR	*from;
unsigned int	offset;
int	name[],	flags;
SYMBOL_PTR	next;
{
	register SYMBOL_PTR	s_ptr;
		 SYMBOL_PTR	new_symb();

	s_ptr = *from = new_symb();
	s_ptr->s_flags = flags | S_VALID;
	s_ptr->s_name[0] = name[0];
	s_ptr->s_name[1] = name[1];
	s_ptr->s_offset  = offset;
	s_ptr->s_next = next;
	return (s_ptr);
}


/*************************************************************************
*
*
*				f i n d
*				-------
*
*	Find the segment number for the named psect.
*
*************************************************************************/
global
find(name)
int	name[];
{
	register int i;
	char	*radnam();

	for (i = 0; i <= seg_max; i++)
		if (segtbl[i].p_name[0] == name[0] &&
		    segtbl[i].p_name[1] == name[1] )
			return(i);

	bug("Failed to find psect \"%s\"", radnam(name));
}


/*************************************************************************
*
*
*				l o o k u p
*				-----------
*
*	Lookup a symbol by segment and offset in the symbol table.
*
*************************************************************************/
global SYMBOL_PTR
lookup(seg, offset)
int	seg;
register unsigned int offset;
{
	register SYMBOL_PTR	s_ptr;

	s_ptr = segtbl[seg].p_symb;

	while (s_ptr) {
		if (s_ptr->s_offset == offset)
			return(s_ptr);
		s_ptr = s_ptr->s_next;
	}
	return (NULL);
}


/*************************************************************************
*
*
*				s _ i n d e x
*				-------------
*
*	Find the 'n'th occurrence of the relevant symbol. Note that the
*	first occurence of a symbol is the passed pointer.
*
*************************************************************************/
global SYMBOL_PTR
s_index(s_ptr, index)
register SYMBOL_PTR	s_ptr;
int	index;
{
	register int offset, temp;

	offset = s_ptr->s_offset;

	for (temp = 1; temp < index; temp++)
		if (!(s_ptr = s_ptr->s_next) || s_ptr->s_offset != offset)
			return(NULL);
	return(s_ptr);
}


/*************************************************************************
*
*
*				l _ n a m e
*				-----------
*
*	Rename all weak symbols with decent, mnemonic labels.
*
*************************************************************************/
global
l_name()
{
	int seg;
	char t_buff[6];
	char l_lab1, l_lab2, l_lab3;
	register SYMBOL_PTR	s_ptr;

	l_lab1 = l_lab2 = l_lab3 = '0';

	for (seg = 0; seg <= seg_max; seg++) {

		s_ptr = segtbl[seg].p_symb;

		while (s_ptr) {

			if (s_ptr->s_flags & S_WEAK) {

				t_buff[0] = 'L';
				t_buff[1] = '0';
				t_buff[2] = '$';
				t_buff[3] = l_lab3;
				t_buff[4] = l_lab2;
				t_buff[5] = l_lab1;

				if ((s_ptr->s_flags & (S_CREF | S_DREF))
					== (S_CREF | S_DREF))
					t_buff[0] = 'B';
				else
				if (s_ptr->s_flags & S_DREF)
					t_buff[0] = 'D';
				else
				if (s_ptr->s_flags & S_CREF)
					t_buff[0] = 'C';

				if (s_ptr->s_flags & S_LOCAL)
					t_buff[1] |= 1;
				if (s_ptr->s_flags & S_EXT)
					t_buff[1] |= 2;

				ascr50(6, t_buff, s_ptr->s_name);

				if (++l_lab1 > '9') {
					l_lab1 = '0';
					l_lab2++;
				}
				if (l_lab2 > '9') {
					l_lab2 = '0';
					l_lab3++;
				}
				if (l_lab3 == ('9' + 1))
					l_lab3 = 'A';
			}
			s_ptr = s_ptr->s_next;
		}
	}
}


/*************************************************************************
*
*
*				n e w _ s y m b
*				---------------
*
*	Allocate space for a new symbol. Fatal error if no space
*	is left.
*
*************************************************************************/
local SYMBOL_PTR
new_symb()
{
	register char	*temp;
	char	*malloc();

	if (!(temp = malloc(sizeof (SYMBOL))))
		bug("Symbol space exhausted");
	return((SYMBOL_PTR) temp);
}
