{ --- General purpose functions --- }

const XCURSOR=$FA44;                   { address of current cursor pos }
      YCURSOR=$FA45;

function get_x_cursor: integer;
begin
get_x_cursor:=Mem[XCURSOR];
end;

function get_y_cursor: integer;
begin
get_y_cursor:=Mem[YCURSOR];
end;

function min(i,j:integer): integer;
begin
if i<j then min:=i else min:=j;
end;

function max(i,j:integer): integer;
begin
if i>j then max:=i else max:=j;
end;

function hexbyte(b:byte):char;
begin
inline ($CD/$492);
hexbyte:=Chr(0);
end; { function hexbyte }

function hexint(i:integer):char;
begin
inline ($CD/$48D);
hexint:=Chr(0);
end; { function hexint }

            { --- Cursor position functions --- }

function eol(i:integer): boolean;        { End of line reached ? }
begin
eol:= text[i]=CR;
end; { eol }

function ch_to_bol(i:integer): integer;     { text distance to begin of line }
var j: integer;
begin
j:=i-1;
while (j>=TEXTSTART) and (not eol(j)) do j:=j-1;
ch_to_bol:=i-j-1;
end; { ch_to_bol }

function ch_to_eol(i:integer): integer;     { text distance to end of line }
var j: integer;
begin
j:=i;
while not eol(j) do j:=j+1;
ch_to_eol:=j-i;
end; { ch_to_eol }

function x_to_bol(i:integer): integer;     { cursor distance to begin of line }
label break;
var j,k,x,d:integer;
begin
j:=i;
while (j>TEXTSTART) and not eol(j-1) do j:=j-1;
k:=0; x:=1;
while j<i do
    begin
    if text[j]=TAB then
        repeat k:=k+1; x:=x+1 until x mod TABPOS = 0
    else
        begin d:=exp_length[ord(text[j])]; k:=k+d; x:=x+d; end;
    j:=j+1;
    end;
x_to_bol:=k;
end; { x_to_bol }

function dx(i:integer): integer;   { cursor x-increment for char at index i }
var d,x:integer;
begin
if text[i]=TAB then
    begin
    d:=0; x:=x_to_bol(i)+1;
    repeat
        d:=d+1; x:=x+1;
    until x mod TABPOS = 0;
    dx:=d;
    end
else dx:=exp_length[ord(text[i])];
end; { dx }

function line(index:integer):integer;
var i,l:integer;
begin
i:=TEXTSTART; l:=1;
while i<index do
    begin
    if eol(i) then l:=l+1;
    i:=i+1;
    end;
line:=l;
end; { line }

function empty_string(var str:line_string):boolean;
begin
empty_string := (length(str)=0);
end; { empty_string }

                   { --- Move text --- }

function move_up(l:integer):boolean;
var i:integer;
begin
if text_end+l<=TEXTLIMIT then
    begin
    for i:=text_end downto index do text[i+l]:=text[i];
    text_end:=text_end+l;
    move_up:=true;
    end
else move_up:=false;
end; { move_up }

function move_down(l:integer):boolean;
var i:integer;
begin
for i:=index to text_end do text[i]:=text[i+l];
text_end:=text_end-l;
move_down:=true;
end; { move_down }

