// portable acid for all architectures

defn pfl(addr)
{
	print(pcfile(addr), ":", pcline(addr), "\n");
}

defn labstk(l)				// trace from a label
{
	_stk(*l, *(l+4), l);
}

defn params(param)
{
	while param do {
		sym = head param;
		print(sym[0], "=", sym[1]);
		param = tail param;
		if param then
			print (",");
	}	
}

defn locals(l)
{
	local sym;

	while l do {
		sym = head l;
		print("\t", sym[0], "=", sym[1], "\n");
		l = tail l;
	}	
}

defn _stk(pc, sp, dolocals)
{
	local stk;

	stk = strace(pc, sp);

	while stk do {
		frame = head stk;
		print(fmt(frame[0], 'a'), "(");
		params(frame[2]);
		print(") ", pcfile(frame[0]), ":", pcline(frame[0]));
		print("called from ", fmt(frame[1], 'a'), " ");
		pfl(frame[1]);
		stk = tail stk;
		if dolocals then
			locals(frame[3]);
	}
}

defn findsrc(file)
{
	local lst;
	local src;

	lst = srcpath;
	while head lst do {
		src = file(head lst+file);
		if src != {} then {
			srcfiles = append srcfiles, file;
			srctext = append srctext, src;
			return src;
		}
		lst = tail lst;
	}
}

defn line(addr)
{
	local src;
	local file;

	file = pcfile(addr);
	src = match(file, srcfiles);

	if src >= 0 then
		src = srctext[src];
	else
		src = findsrc(file);

	if src == {} then {
		print("no source for ", file, "\n");
		return {};
	}
	line = pcline(addr)-1;
	print(file, ":", src[line], "\n");
}

defn addsrcdir(dir)
{
	dir = dir+"/";

	if match(dir, srcpath) >= 0 then {
		print("already in srcpath\n");
		return {};
	}

	srcpath = {dir}+srcpath;
}

defn source()
{
	local l;

	l = srcpath;
	while l do {
		print(head l, "\n");
		l = tail l;
	}
	l = srcfiles;

	while l do {
		print("\t", head l, "\n");
		l = tail l;
	}
}

defn Bsrc(addr)
{
	local lst;

	lst = srcpath;
	file = pcfile(addr);
	while head lst do {
		name = head lst+file;
		if access(name) then {
			rc("B "+itoa(-pcline(addr))+" "+name);
			return {};
		}
		lst = tail lst;
	}
	print("no source for ", file, "\n");
}

defn src(addr)
{
	local src;
	local file;
	local line;
	local cline;
	local text;

	file = pcfile(addr);
	src = match(file, srcfiles);

	if src >= 0 then
		src = srctext[src];
	else
		src = findsrc(file);

	if src == {} then {
		print("no source for ", file, "\n");
		return {};
	}

	cline = pcline(addr)-1;
	line = cline-5;
	loop 0,10 do {
		if line >= 0 then {
			if line == cline then
				print(">");
			else
				print(" ");
			text = src[line];
			if text == {} then
				return {};
			print(file, ":", line, "\t", text, "\n");
		}
		line = line+1;
	}	
}

defn step()					// single step the process
{
	local lst;
	local lpl;
	local addr;
	local bput;

	lst = follow(*PC);

	lpl = lst;
	while lpl do {				// place break points
		*(head lpl) = bpinst;
		lpl = tail lpl;
	}

	bput = 0;
	if match(*PC, bplist) >= 0 then {	// Sitting on a breakpoint
		bput = fmt(*PC, bpfmt);
		*bput = @bput;
	}

	startstop(pid);				// do the step

	while lst do {				// remove the breakpoints
		addr = fmt(head lst, bpfmt);
		*addr = @addr;
		lst = tail lst;
	}
	if bput != 0 then
		*bput = bpinst;
}

defn bpset(addr)				// set a breakpoint
{
	if match(addr, bplist) >= 0 then
		print("breakpoint already set at ", fmt(addr, 'a'), "\n");
	else {
		*fmt(addr, bpfmt) = bpinst;
		bplist = append bplist, addr;
	}
}

defn bptab()					// print a table of breakpoints
{
	local lst;
	local addr;

	lst = bplist;
	while lst do {
		addr = head lst;
		print("\t", fmt(addr, 'X'), fmt(addr, 'a'), "  ", fmt(addr, 'i'), "\n");
		lst = tail lst;
	}
}

defn bpdel(addr)				// delete a breakpoint
{
	local n;
	local pc;
	local nbplist;

	n = match(addr, bplist);
	if n < 0  then {
		print("no breakpoint at ", fmt(addr, 'a'), "\n");
		return {};
	}

	addr = fmt(addr, bpfmt);
	*addr = @addr;

	nbplist = {};				// delete from list
	while bplist do {
		pc = head bplist;
		if pc != addr then
			nbplist = append nbplist, pc;
		bplist = tail bplist;
	}
	bplist = nbplist;			// delete from memory
}

defn cont()					// continue execution
{
	local addr;

	addr = fmt(*PC, bpfmt);
	if match(addr, bplist) >= 0 then {	// Sitting on a breakpoint
		*addr = @addr;
		step();				// Step over
		*addr = bpinst;
	}
	startstop(pid);				// Run
}

defn stopped(pid)		// called from acid when a process changes state
{
	pstop(pid);		// stub so this is easy to replace
}

defn procs()			// print status of processes
{
	local c;
	local lst;
	local cpid;

	cpid = pid;
	lst = proclist;
	while lst do {
		np = head lst;
		setproc(np);
		if np == cpid then
			c = '>';
		else
			c = ' ';
		print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), "\n");
		lst = tail lst;
	}
	pid = cpid;
	if pid != 0 then
		setproc(pid);
}

defn asm(addr)
{
	addr = fmt(addr, 'i');
	loop 1,30 do
		print(fmt(addr, 'a'), "\t", @addr++, "\n");
}

defn new()
{
	bplist = {};
	newproc(progargs);
}

defn stmnt()			// step one statement
{
	local line;

	line = pcline(*PC);
	while 1 do {
		step();
		if line != pcline(*PC) then {
			src(*PC);
			return {};
		}
	}
}

defn func()			// step until we leave the current function
{
	local pc;
	local lst;
	local end;
	local start;

	lst = symbols;
	pc = *PC;
	while lst do {
		start = (head lst)[2];
		end = etext;
		if tail lst then
			end = (head (tail lst))[2];

		if pc >= start && pc < end then {
			while pc >= start && pc < end do {
				step();
				pc = *PC;
			}
			return {};
		}
		lst = tail lst;
	}
	print("cannot locate text symbol\n");
}

defn dump(addr, n, fmt)
{
	loop 0, n do {
		print(fmt(addr, 'a'), " ");
		addr = mem(addr, fmt);
	}
}

defn mem(addr, fmt)
{
	local i;

	i = 0;
	while fmt[i] != 0 do {
		addr = fmt(addr, fmt[i]);
		print(*addr++);
		i = i+1;
	}
	print("\n");
	return addr;
}

progargs="";
print("/lib/acid/port");
