$DEBUG OFF$
$ucsd on$
module windowlib;
export
  const
    screen_y_max = 23;
    screen_x_max = 79;
  
  type
    window_type = record
                    xmin_abs, xmax_abs : integer;
                    ymin_abs, ymax_abs : integer;
                    xsize, ysize : integer;
                    current_x : integer;
                    current_y : integer;
                  end;  { record }
                    
    window_ptr = ^window_type;
  
  function init_window ( xmin, xmax : integer;
                         ymin, ymax : integer ) : window_ptr;
  procedure gotoxy_window ( w : window_ptr;  x, y : integer );
  procedure window_newline ( w : window_ptr );
  procedure write_window_char ( w : window_ptr; c : char );
  procedure write_window_string ( w : window_ptr; var s : string );
  procedure writeln_window_string ( w : window_ptr; var s : string );
  procedure clear_eol_window( w : window_ptr );
  procedure clear_end_window( w : window_ptr );
  procedure clear_window ( w : window_ptr );

implement

  var
    cursor_x, cursor_y : integer;       { screen cursor coordinates }
    
  function init_window ( xmin, xmax : integer;
                         ymin, ymax : integer ) : window_ptr;
    var pw : window_ptr;
    begin
    new(pw);
    with pw^ do begin
      xmin_abs := xmin;
      xmax_abs := xmax;
      ymin_abs := ymin;
      ymax_abs := ymax;
      xsize := xmax - xmin;
      ysize := ymax - ymin;
      current_x := 0;
      current_y := 0;
    end;  { with }
    init_window := pw;
    end;  { function init_window }
    
  procedure pos_cursor( w : window_ptr );
    begin
    with w^ do begin
      cursor_x := current_x + xmin_abs;
      cursor_y := current_y + ymin_abs;
{ special case : keep the cursor off the last position to keep the screen
  from scrolling }
      if (cursor_y = screen_y_max) and (cursor_x = screen_x_max)
         then cursor_x := screen_x_max - 1;  
      gotoxy( cursor_x, cursor_y );
    end;  { with }
    end; { procedure pos_cursor }
    
{ put_screen    puts the given character on the screen at the position
  specified by the current cursor coordinates cursor_x and cursor_y
}
  procedure put_screen( c : char );
    begin
    write(c);
    end;  { procedure put_screen }
    
  procedure gotoxy_window ( w : window_ptr;  x, y : integer );
    begin
    with w^ do begin
      current_x := x;
      current_y := y;
      if (x < 0) then current_x := 0;
      if (x > xsize) then current_x := xsize;
      if (y < 0) then current_y := 0;
      if (y > ysize) then current_y := ysize;
     end;  { with }
    end;  { procedure gotoxy_window }


procedure step_cursor ( w : window_ptr );
  begin
  with w^ do begin
      current_x := current_x + 1;
      if current_x > xsize
         then begin     { cursor went past x boundary }
           current_x := 0;
           current_y := current_y + 1;
           if current_y > ysize then current_y := 0;
           end;  { cursor went past x boundary }
    end;  { with }
  end;  { procedure step_cursor }
    
procedure back_cursor ( w : window_ptr );
  begin
  with w^ do begin
    current_x := current_x -1;
    if current_x < 0
       then begin       { x went back past start of line }
            current_x := xsize;
            current_y := current_y - 1;
            if current_y < 0 then current_y := ysize;
            end;  { x went back past start of line }
    end;  { with }
  end;  { procedure back_cursor }
    
  procedure window_newline ( w : window_ptr );
    begin
    with w^ do begin
      current_x := xsize;
      step_cursor( w );
      pos_cursor( w );
      clear_eol_window( w );
    end;  { with }
    end;  { procedure window_newline }
  
  procedure write_window_char ( w : window_ptr; c : char );
    begin
    if c = #127
       then begin  { rubout }
         back_cursor( w );
         pos_cursor( w );
         put_screen(' ');
         pos_cursor( w );
         end  { rubout } 
       else begin   { printing character }
         pos_cursor( w );
         put_screen(c);
         step_cursor ( w );
         end;  { printing character }
    end;  { procedure write_window_char }
    
  procedure write_window_string ( w : window_ptr; var s : string );
    var i : integer;
    begin
    for i := 1 to length(s) do
      write_window_char( w, s[i] );
    end;  { procedure write_window_string }
    
  procedure writeln_window_string ( w : window_ptr; var s : string );
    begin
    write_window_string (w, s);
    window_newline( w );
    end;  { procedure writeln_window_string }
  
  procedure clear_eol_window( w : window_ptr );
    var x, y : integer;
    begin
    with w^ do begin 
      x := current_x;
      y := current_y;
      pos_cursor ( w );
      if xmax_abs = screen_x_max
        then write(#9)
        else while current_x <= xsize do begin
               write(' ');
               current_x := current_x + 1;
               end;  { while }
      end;  { with }
    gotoxy_window( w, x, y );            { restore initial position }
    pos_cursor( w );
    end;  { procedure clear_eol_window }
  
  procedure clear_end_window( w : window_ptr );
    var  x, y : integer;
    begin
    with w^ do begin
      x := current_x;
      y := current_y;
      while current_y <= ysize do begin
        clear_eol_window( w );
        current_x := 0;
        current_y := current_y + 1;
        end;  { while }
      end;  { with }
    gotoxy_window( w, x, y );            { restore initial position }
    end;  { procedure clear_end_window }
    
  procedure clear_window ( w : window_ptr );
    begin
    gotoxy_window(w, 0,0);         { go to upper left hand corner }
    clear_end_window( w );      { clear to the end of the window }
    end;  { procedure clear_window }
  
  end. { module windowlib }
