c
c A package for terminal handling
c  we use sys$qiow for output and handle all line control ourselfs
c
	options /extend
	function terminal_init(ptr_terminal_info,prompt)
	implicit none
c
c Init the terminal info block
c 2. Get a channel to sys$command for in/output
c 3. Get the terminal width to correctly wrap lines
c 4. Set the prompt string and length
c 5. Get escape seqs for the various terminal formatting vir smg$get_term_data
c
c  Also check for /debug=filename/flags=all, disallow,routines,token,input
c
	include '($ssdef)'
	include '($dvidef)'
	include '($ttdef)'
	include '($smgtrmptr)'
	include 'terminal.inc'
	include '($jpidef)'
c
c
	integer*4 ptr_terminal_info
	character*(*) prompt			!:i: prompt string
	integer*4 terminal_init			!:f: funciton result
c
c
	integer*4 lib$get_vm
	logical cli$present
	integer*4 terminal__write
c
	record /terminal_info/ terminal_info	!:io: control  block
	pointer (p_terminal_info,terminal_info)
c
	character*255 line,imagname,startup_file
	integer*4 istat,nkar,devtyp,k,lun,nk_Imag,epos
	integer*4 nk_startup
	logical*4 skip
	character*64 devnam
c
	integer*4 sys$assign
	integer*4 lib$getdvi
	integer*4 smg$init_term_table
	integer*4 terminal_start
	integer*4 smg$get_term_data
c
c Get the control block
c
	istat = lib$get_vm(sizeof(terminal_info),p_terminal_info)
	ptr_terminal_info = p_terminal_info
c
c See if user wants to use the arrows 
c
	terminal_info.chan = 0
	terminal_info.use_arrows = cli$present('use_arrows')
c
	skip = cli$present('skip')
c
c handle the debug, flags dcl qualifiers
c
	call cli$get_value('debug',line,nkar)
	if(nkar .eq. 0) then
c
c No debug wanted
c
	  terminal_info.lun_debug = 0
	else
c
c Yes open the debug file (default=sys$output)
c
	  call lib$get_lun(terminal_info.lun_debug)
	  open(terminal_info.lun_debug,file=line(1:nkar),
     1         carriagecontrol='list',status='unknown',
     1         recl=max_line_length+20,err=70)
	  call terminal_debug(ptr_terminal_info,'Start of debug',0,-1)
c
c And handle the /flags qualifier
c
	  terminal_info.debug_flag = 0	!no flags
	  if(cli$present('flags.all')) terminal_info.debug_flag = -1
	  call terminal__setbit(terminal_info,'disallow',dbg_flag_dis)
	  call terminal__setbit(terminal_info,'routines',dbg_flag_rou)
	  call terminal__setbit(terminal_info,'token',   dbg_flag_tok)
	  call terminal__setbit(terminal_info,'input',   dbg_flag_inp)
	  call terminal__setbit(terminal_info,'symbols', dbg_flag_sym)
	endif
c
c  Set the prompt
c
	terminal_info.prompt = prompt
	terminal_info.nkar_prompt = len(prompt)
c
c And clear the flags
c
	terminal_info.nkar     = 0
	terminal_info.position = 0
	terminal_info.got_msg  = .false.
	terminal_info.replay_pos = 0
	terminal_info.nk_typeahd = 0
c
c Assign the channel to sys$command
c
	istat = sys$assign('SYS$COMMAND',terminal_info.chan,,,)
	if(.not. istat) then
	  call lib$signal(%val(istat))
	  goto 90
	endif
c
c Get the device info 
c
	call cli$get_value('terminal',devnam,nkar)
	if(nkar .eq. 0) then
c
c Now try to get the terminal type from the sys$command
c
	  call lib$getdvi(dvi$_devtype,terminal_info.chan,,devtyp)
          devnam = 'VT100'
          if(devtyp .eq. tt$_vt200_series) devnam = 'vt200_series'
          if(devtyp .eq. tt$_vt300_series) devnam = 'vt300_series'
          if(devtyp .eq. tt$_vt400_series) devnam = 'vt400_series'
          if(devtyp .eq. tt$_vt500_series) devnam = 'vt500_series'
          nkar = index(devnam,' ')-1
	endif
	call terminal_debug(ptr_terminal_info,'Setting terminal for '//
     1                      devnam(1:nkar),0,dbg_flag_inp)
c
c Get the terminal table 
c
        istat = smg$init_term_table(devnam(1:nkar),
     1             terminal_info.term_table_addr)
	if(.not. istat) goto 80
c
c Check if terminal is ansi terminal
c
	istat = smg$get_term_data(terminal_info.term_table_addr,
     1         smg$k_ansi_crt,sizeof(k),nkar,k,0)
	if(.not. istat) goto 81
	if(k .eq. 0) goto 80
c
c Get startline , since the processing of the keys will destroy the
c  cli context, we must get all cli values here
c
	call cli$get_value('startup',startup_file,nk_startup)
c
c Define the keys
c
	terminal_info.n_keys = 0
c
c insert the defaults for all keys
c  Repaint keys
c
	call terminal__define_key(terminal_info,'define kar_repaint ctrlw,ctrlr')
c
c Eol key
c
	call terminal__define_key(terminal_info,'define kar_eol  ctrle')
c
c Toggle insert/overstrike ^a/f14
c
	call terminal__define_key(terminal_info,'define kar_toggle  ctrla,f14')
c
c Add the debug key
c
	call terminal__define_key(terminal_info,'define kar_debug  ctrld')
c
c Add format override kar ^g/f11
c
	call terminal__define_key(terminal_info,'define kar_override  ctrlf,f11')
c
c Append left/right
c
	call terminal__define_key(terminal_info,'define kar_left  left')
	call terminal__define_key(terminal_info,'define kar_right  right')
c
c Add lf/f13
c
	call terminal__define_key(terminal_info,'define kar_del_token  ctrlj,f13')
c
c Add pf2/help
c
	call terminal__define_key(terminal_info,'define kar_help  pf2,help')
c
c Add ^L/f8, list
c
	call terminal__define_key(terminal_info,'define kar_list  ctrll,f8')
c
cAdd abort ^Z/f10
c
	call terminal__define_key(terminal_info,'define kar_abort  ctrlz,f10')
c
c Add cr/enter
c
	call terminal__define_key(terminal_info,'define kar_return  ctrlm,enter')
c
c If use_arrows specified,
c   up-arrow will act like kar_expand_prev
c   wodn_arrow will act like kar_expand                      
c
	if(terminal_info.use_arrows) then
	  call terminal__define_key(terminal_info,'define kar_expand  down')
	  call terminal__define_key(terminal_info,'define kar_expand_prev  up')
	endif
c
c Add ht 
c
	call terminal__define_key(terminal_info,'define kar_expand  ctrli')
c
c Add bs/f12
c
	call terminal__define_key(terminal_info,'define kar_expand_prev  ctrlh,f12')
c
c Add delete
c
	call terminal__define_key(terminal_info,'define kar_delete  delete')
c
c Add the toggle verbone key ^F/F9
c
	call terminal__define_key(terminal_info,'define kar_tog_verbone  ctrlf,f9')
c
c Add the toggle execute key ^V/F7
c
	call terminal__define_key(terminal_info,'define kar_tog_execute  ctrlv,f7')
c
c Now see if ini file present
c
c Get the terminal width
c
	istat = lib$getdvi(dvi$_devbufsiz,terminal_info.chan,,
     1                     terminal_info.width)
	if(.not. istat) call lib$signal(%val(istat))
c
	istat = lib$getdvi(dvi$_devdepend,terminal_info.chan,,k)
	if(.not. istat) call lib$signal(%val(istat))
c
c The terminal lengtyh is in the upper nibble
c
	terminal_info.length = ishft(k,-24)
c
c Max 1/2 the screen for help messages
c
	terminal_info.max_help_size = 
     1       terminal_info.length*terminal_info.width/2
c
	terminal_info.nkar_prompt = min(terminal_info.width,
     1                                  terminal_info.nkar_prompt)
c
c Get the insert flag from the terminal as default insert mode
c
	istat = lib$getdvi(dvi$_tt_insert,terminal_info.chan,,
     1                     terminal_info.insert)
	if(.not. istat) call lib$signal(%val(istat))
c
c Get the wrap flag from the terminal
c
	istat = lib$getdvi(dvi$_tt_wrap,terminal_info.chan,,
     1                     terminal_info.wrap)
	if(.not. istat) call lib$signal(%val(istat))
c
c Check for ini file
c
	lun = 0
c
	if(nk_startup .gt. 0) then
	  call lib$get_lun(lun)
	  open(lun,name=startup_file(1:nk_startup),
     1         defaultfile='sys$login:.ini',
     1         status='old',readonly,shared,err=10)
	  goto 20
c
c Could not open the file , try the image dev/dir
c
10	  call lib$getjpi(jpi$_imagname,,,,imagname,nk_imag)
          call auto_file_parse(imagname,'D',k,epos)
	  open(lun,name=startup_file(1:nk_startup),
     1         defaultfile=imagname(1:epos)//'.ini',
     1         status='old',readonly,shared,err=30)
c
20	  read(lun,2000,end=30) nkar,line
2000	  format(q,a)
	  call terminal__process_line(terminal_info,line(1:nkar),skip)	  	  
	  goto 20
c
29	  write(*,*) 'INI file not found ',startup_file(1:nk_startup)
	  skip = .true.
30	  close(lun)
	  call lib$free_lun(lun)
	endif
c
	if(terminal_info.lun_debug .ne. 0) then
	  call terminal__print_keys(terminal_info)
	endif
c
c Now print the prompt to the terminal
c
	if(skip) then
	  istat = terminal__write(terminal_info,key_return//key_linefeed)
	  if(.not. istat) goto 90
	endif
c
	istat = terminal_start(ptr_terminal_info)
	goto 90
c
c Error opening debug file
c
70	call errsns(,istat)
	write(*,*) 'Could not open debug file '//line(1:nkar)
	goto 85
c
c Invalid terminal
c
80	istat = ss$_ivdevnam
81	write(*,*) 'THis type of terminal '//devnam(1:nkar)//
     1             ' cannot be used'
c
85	call terminal_exit(ptr_terminal_info)
c
c And return the status
c
90	terminal_init = istat
	return
	end
	subroutine terminal__process_line(terminal_info,line,skip)
	implicit none
c
	include 'terminal.inc'	
	record /terminal_info/ terminal_info
	character*(*) line
	logical*4 skip
c
	character*4 verb
c
c
	call auto_parse(line)
	call cli$get_value('$verb',verb)
	if(verb .eq. 'DEFI') then
	  call terminal__insert_kars(terminal_info,skip)
	else
	  write(*,*) 'Unrecognized verb '//verb
	endif
	return
	end
	options /extend
	subroutine terminal__define_key(terminal_info,line)	  	  
	implicit none
c
c Pre-defined keys
c
	include 'terminal.inc'	
	record /terminal_info/ terminal_info
	character*(*) line
c
	logical*4 skip
c
	call auto_parse(line)
	call terminal__insert_kars(terminal_info,skip)
	return
	end
	function terminal__insert_kars(terminal_info,skip)
	implicit none
c
c Insert keystrokes and responses
c
	include 'terminal.inc'
	record /terminal_info/ terminal_info	!:io: control block
	logical*4 skip				!:io: set to true if some write
	integer*4 terminal__insert_kars          !:f: function result
c
	integer*4 idx,istat,k,smg_keycode,empty
	character*20 data
	integer*4 n_data
	integer*4 smg_ptr_key
c
	include '($smgtrmptr)'
	include '($smgdef)'
c
	character*20 auto_key,smg_key
	character keyid
c
	integer*4 smg$get_term_data	
	integer*4 smg$name_to_keycode
	integer*4 cli$get_value
c
	if(terminal_info.n_keys .eq. max_keys) then
	  write(*,*) 'Too many keys, increase max_keys'
	  skip = .true.
	  istat = 0
	  goto 90
	endif
c
	call cli$get_value('p1',auto_key)
	keyid = ' '
	if(auto_key .eq. 'KAR_DEBUG')       keyid = kar_debug
	if(auto_key .eq. 'KAR_OVERRIDE')    keyid = kar_override
	if(auto_key .eq. 'KAR_EXPAND')      keyid = kar_expand
	if(auto_key .eq. 'KAR_EXPAND_PREV') keyid = kar_expand_prev
	if(auto_key .eq. 'KAR_HELP')        keyid = kar_help
	if(auto_key .eq. 'KAR_LIST')        keyid = kar_list
	if(auto_key .eq. 'KAR_ABORT')       keyid = kar_abort
	if(auto_key .eq. 'KAR_TOGGLE')      keyid = kar_toggle
	if(auto_key .eq. 'KAR_EOL')         keyid = kar_eol
	if(auto_key .eq. 'KAR_REPAINT')     keyid = kar_repaint
	if(auto_key .eq. 'KAR_TOG_VERBONE') keyid = kar_tog_verbone
	if(auto_key .eq. 'KAR_TOG_EXECUTE') keyid = kar_tog_execute
c
c HArd coded
c
	if(auto_key .eq. 'KAR_LEFT')        keyid = kar_left
	if(auto_key .eq. 'KAR_RIGHT')       keyid = kar_right
	if(auto_key .eq. 'KAR_DEL_TOKEN')   keyid = kar_del_token
	if(auto_key .eq. 'KAR_RETURN')      keyid = kar_return
c
	if(auto_key .eq. 'KAR_DELETE')      keyid = kar_delete
c
	if(keyid .eq. ' ') then
	  write(*,*) 'Invalid keyname '//auto_key//' (ignored)'
	  skip = .true.
	else
c
c First clear all entries with this value, and remember the index
c
	  empty = 0
	  do k=1,terminal_info.n_keys
	    if(terminal_Info.keys(k).result .eq. ichar(keyid)) then
	      terminal_info.keys(k).n_data = 0
	    end if
c
c If slot empty, remember this one
c
	    if(terminal_info.keys(k).n_data .eq. 0) empty = k !remember this empty slot
	  end do
c
	  do while(cli$get_value('p2',smg_key))
c	
	    if(smg_key .eq. 'DELETE') then
	      smg_keycode = 127
	    else
	      if(.not. smg$name_to_keycode(smg_key,smg_keycode)) goto 40
	    endif
	    if(smg_keycode .le. 26 .or. smg_keycode .eq. 127) then
c
c Normal CTRL keys, just add code
c
	      if(smg_keycode .eq.  3 .or.      !^C
     1           smg_keycode .eq. 17 .or.      !^Q
     1           smg_keycode .eq. 19 .or.      !^S
     1           smg_keycode .eq. 25) goto 40  !^Y
c
	      n_data = 1
	      data(1:1) = char(smg_keycode)
	    elseif(smg_keycode .le. 255) then
c
c Other characters (non escape keys) (illegal)
c
	      goto 40
	    else
c
c Function key, lookup in term_data
c  some (not so wise) person made the keymapping in
c   smgtrmptr <> keymapping in smgdef
c
c  so we need tables here.
c   We assume  pf1..pf4 are contiguous
c               f1..f20 are contiguous
c              kp0..kp9 are contiguous
c               e1..e6  Are contiguous
c
	      if(    smg_keycode .ge. smg$k_trm_pf1 .and. 
     1               smg_keycode .le. smg$k_trm_pf4) then
	        smg_ptr_key = smg_keycode - smg$k_trm_pf1 + smg$k_key_pf1
	      elseif(smg_keycode .ge. smg$k_trm_f7  .and. 
     1          smg_keycode .le. smg$k_trm_f20) then
c
c f1..f6 are illegal
c
	        smg_ptr_key = smg_keycode - smg$k_trm_f1  + smg$k_key_f1
	      elseif(smg_keycode .ge. smg$k_trm_e1 .and. 
     1               smg_keycode  .le. smg$k_trm_e6) then
	        smg_ptr_key = smg_keycode - smg$k_trm_e1  + smg$k_key_e1
	      elseif(smg_keycode .ge. smg$k_trm_kp0 .and. 
     1               smg_keycode .le. smg$k_trm_kp9) then
	        smg_ptr_key = smg_keycode - smg$k_trm_kp0 + smg$k_key_0
	      elseif(smg_keycode .eq. smg$k_trm_enter) then
	        smg_ptr_key = smg$k_key_enter
	      elseif(smg_keycode .eq. smg$k_trm_comma) then
	        smg_ptr_key = smg$k_key_comma
	      elseif(smg_keycode .eq. smg$k_trm_minus) then
	        smg_ptr_key = smg$k_key_minus
	      elseif(smg_keycode .eq. smg$k_trm_period) then
	        smg_ptr_key = smg$k_key_period
	      elseif(smg_keycode .eq. smg$k_trm_up) then
	        smg_ptr_key = smg$k_key_up_arrow
	      elseif(smg_keycode .eq. smg$k_trm_down) then
	        smg_ptr_key = smg$k_key_down_arrow
	      elseif(smg_keycode .eq. smg$k_trm_left) then
	        smg_ptr_key = smg$k_key_left_arrow
	      elseif(smg_keycode .eq. smg$k_trm_right) then
	        smg_ptr_key = smg$k_key_right_arrow
	      else
c
c Invalid key
c
	        goto 40
	      endif
c
	      istat = smg$get_term_data(
     1                   terminal_info.term_table_addr,
     1                   smg_ptr_key,
     1                   len(data),n_data,%ref(data),0)
c
c See if start is a CSI code, replace by a esc[
c  this makes comparing easier
c
	      if(.not. istat) goto 40
	      if(data(1:1) .eq. key_csi) then
	        data = key_escape//'['//data(2:)
	        n_data = n_data + 1
	      endif
	    endif
c
c And now add
c
	    if(empty .eq. 0) then
	      terminal_info.n_keys = terminal_info.n_keys + 1
	      idx = terminal_info.n_keys
	    else
	      idx = empty
	    endif
c
	    terminal_info.keys(idx).n_data   = n_data
	    terminal_info.keys(idx).data     = data(1:n_data)
	    terminal_info.keys(idx).result   = ichar(keyid)
	    terminal_info.keys(idx).smg_name = smg_key
	    terminal_info.keys(idx).auto_name= auto_key
	    goto 50
c
c Invalid SMG key
c
40	    write(*,*) 'Key invalid for mapping '//smg_key//' (ignored)'
	    skip = .true.
50	  enddo         !loop over p2
	end if		!valid auto key
90	terminal__insert_kars = 1
	return
	end
	subroutine terminal__print_keys(terminal_info)
	implicit none
c
c Print all key defs
c
	include 'terminal.inc'
	record /terminal_info/ terminal_info
c
	character*255 line
	integer*4 idx,k,nk,nk1,ptr_terminal_info
c
c And now debug info (if wanted)
c
	ptr_terminal_info = %loc(terminal_info)
	do idx=1,terminal_info.n_keys
c
	  call sys$fao('Result !AS, key !AS Keysequence',nk,line,
     1             terminal_info.keys(idx).auto_name,
     1             terminal_info.keys(idx).smg_name)
	  do k=1,terminal_info.keys(idx).n_data
	    call sys$fao(' !2XL',nk1,line(nk+1:),
     1                 %val(ichar(terminal_info.keys(idx).data(k:k))))
	    nk = nk + nk1
	  end do
	  call terminal_debug(ptr_terminal_info,line(1:nk),0,dbg_flag_inp)
	end do
	return
	end
	subroutine terminal__setbit(terminal_info,verb,flag)
	implicit none
c 
c Set a bit in the debug flag for a /flags=field foken
c
	include 'terminal.inc'
	record /terminal_info/ terminal_info
	character*(*) verb		!:i: the name of the value
	integer*4 flag			!:i: the bit to be updated
c
	integer*4 istat
	integer*4 cli$present
	external cli$_present
	external cli$_negated
c
c Get the presence of the flag
c
	istat = cli$present('flags.'//verb)
	if(istat .eq. %loc(cli$_present)) then
c
c Present, so set the flag
c
	  terminal_info.debug_flag = 
     1    terminal_info.debug_flag .or. flag
	elseif(istat .eq. %loc(cli$_negated)) then
c
c Negated so clear the flag
c  this allows for /flags=all,noterminal
c   the "all" sets all bits to one, and the noterminal clear the  terminal bit
c
	  terminal_info.debug_flag = 
     1    terminal_info.debug_flag .and. .not. flag
	endif
	return
	end
	function terminal_start(ptr_terminal_info)
	implicit none
c
c Init the line and print out the prompt
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info
	integer*4 terminal_start
c
	integer*4 istat
	integer*4 terminal__write
	integer*4 terminal__clreol
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c Position = 0, nkar=0,
c
	p_terminal_info = ptr_terminal_info
	terminal_info.position = 0
	terminal_info.nkar = 0
c
c Print out the prompt
c
	istat = terminal__write(terminal_info,key_return//
     1      terminal_info.prompt(1:terminal_info.nkar_prompt))
c
c Erate the text
c
	if(istat) istat = terminal__clreol(terminal_info)
c
	terminal_start = istat
	return
	end
	function terminal_exit(ptr_terminal_info)
	implicit none
c
c CLean up, 
c  deassign the channel to sys$command
c  close the debug file (if opened)
c
	include 'terminal.inc'
c
	integer*4 ptr_terminal_info
c
	integer*4 terminal_exit
c
	integer*4 istat
	integer*4 sys$dassgn
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c Close the output channel
c
	p_terminal_info = ptr_terminal_info
	istat = 1
c
	if(terminal_info.chan .ne.0) then
	  istat = sys$dassgn(%val(terminal_info.chan))
          if(.not. istat) call lib$signal(%val(istat))
	endif
c
c If debug was opened, close it now
c
	if(terminal_info.lun_debug .ne. 0) then
	  close(terminal_info.lun_debug)
	  call lib$free_lun(terminal_info.lun_debug)
	endif
c
c Thats all
c
	terminal_exit = istat
	return
	end
	function terminal_replace(ptr_terminal_info,line,keep_pos)
	implicit none
c
c replace the current line by line
c terminal.position is used to determine the cursor position
c
c terminal.position will be at the end of the line
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info 	!:io: the current terminal state
	character*(*) line		!:i: the net line
	logical*4 keep_pos		!:i: keep current position??
	integer*4 terminal_replace
c
	integer*4 k,nk,x,y,istat,old_pos
	logical old_insert
	integer*4 terminal__setpos
	integer*4 terminal_delete
	integer*4 terminal_insert
c
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c Find out the last pos that is equal
c
	p_terminal_info = ptr_terminal_info
	old_pos = terminal_info.position
c
	nk = min(terminal_info.nkar,len(line))
	do k=1,nk
	  if(terminal_info.line(k:k) .ne. line(k:k)) goto 10
	end do
	k = nk + 1
10	nk = k - 1
c
c Nk is the #chars that are the same
c Set the cursor to the end of the string
c  Now execute a delete until the length is nk
c
c Get the current pos
c
	call terminal__getpos(terminal_info,x,y)
c
c Set the position to the end
c
	terminal_info.position = terminal_info.nkar
c
c And set the cursor again (now to the end)
c
	istat = terminal__setpos(terminal_info,x,y)
	if(.not. istat) goto 90
c
c Now execute * times a delete
c
	do k=terminal_info.nkar,nk+1,-1
	  istat = terminal_delete(ptr_terminal_info)
	  if(.not. istat) goto 90
	end do
c
c Now insert the rest, fake the insert state to true
c  
	old_insert = terminal_info.insert	!remember the old insert state
	terminal_info.insert = .true.
c
c Print the rest of the line
c
	do k=nk+1,len(line)
	  istat = terminal_insert(ptr_terminal_info,line(k:k))
	  if(.not. istat) goto 90
	end do
c
c Return insert state to the old value
c
	terminal_info.insert = old_insert
c
c If keep_pos, we need to postition to the old_pos
c
	if(keep_pos) then
	  call terminal__getpos(terminal_info,x,y)
	  terminal_info.position = min(terminal_info.nkar,old_pos)
	  istat = terminal__setpos(terminal_info,x,y)
	endif
c	
c That's it
c
90	terminal_replace = istat
	return
	end
	function terminal_get(ptr_terminal_info,line,nk)
	implicit none
c
c Return the contents of line to caller
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info    !:i: terminal block
	character*(*) line			!:o: the line
	integer*4 nk				!:o: length of line
	logical terminal_get			!:f: return status
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c return the length
c
	p_terminal_info = ptr_terminal_info
	nk = terminal_info.nkar
c
c Return the contents
c
	line = terminal_info.line(1:nk)
c
c And status (always success)
c
	terminal_get = 1
	return
	end
	function terminal_get_nkar(ptr_terminal_info,nk)
	implicit none
c
c Return length of the  line to called
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info	!:i: terminal block
	integer*4 nk				!:o: length of line
	logical terminal_get_nkar		!:f: functin result
c
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c return the length
c
	p_terminal_info = ptr_terminal_info
	nk = terminal_info.nkar
c
c And return status, always success
c
	terminal_get_nkar = 1
	return
	end
	function terminal_read(ptr_terminal_info,kar,bpos,
     1                         ptr_table_info,execute)
	implicit none
c
c Get a char from terminal
c  use the smg$read_keytroke
c  Handle position keys (left and right arrow), but do not go before
c     position bpos (we had a syntax changed there)
c  handle ^W, ^R for replay after disturbance (a reply message f.e.)
c  handle ^A (toggle insert mode)
c  Handle DELETE, up to bpos
c  Handle LF , delete current token (upto bpos)
c
c If we are in replay mode, get a char from the replay buffer
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info	!:i: chan for sys$command
	character*(1) kar			!:o: the data
	integer*4 bpos				!:i: the limit for movement
	integer*4 ptr_table_info		!:i: table pointer
	logical*4 execute			!:io: the execute flag
	integer*4 terminal_read			!:f: function result
c#
	include '($smgdef)'
	include '($smgmsg)'
	integer*4 terminal__setpos
	integer*4 terminal_redraw
	integer*4 terminal_delete
	integer*4 terminal_message
	logical terminal_replay
	logical auto_check_printable
	logical terminal__read
	integer*4 table_toggle_verbone
	integer*4 auto_msg
c
	external auto_msg_verbone
	external auto_msg_execute
c
	character*80 line,dbgline
	integer*4 istat,nk,x,y,k,nk1,nk2
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c Check to see if we are in typehad mode
c
	p_terminal_info = ptr_terminal_info
	istat =1
c
	if(terminal_info.nk_typeahd .ne. 0) then
	  kar = terminal_info.typeahd(1:1)
	  terminal_info.typeahd = 
     1     terminal_info.typeahd(2:terminal_info.nk_typeahd)
	  terminal_info.nk_typeahd = terminal_info.nk_typeahd - 1
	  goto 99
	endif
c
c If we are in replay mode, get a char from the replay buffer
c
	if(terminal_replay(ptr_terminal_info)) then
	  x = terminal_info.replay_pos
	  kar = terminal_info.replay(x:x)
	  call terminal_kdebug(ptr_terminal_info,'Key replay ',kar,
     1                       4,dbg_flag_inp)
	  goto 99
	endif
c
c Get a char from the keyboard
c
10	istat = terminal__read(terminal_info,line,nk)
	if(.not. istat) goto 90
c
c Clear message (if there)
c
	if(.not. terminal_replay(ptr_terminal_info)) then
c
c CLear a help message
c

	  istat = terminal_message(ptr_terminal_info,' ')
	  if(.not. istat) goto 90
	endif
c
c Process the character read
c
        call terminal__getpos(terminal_info,x,y)
	if(terminal_info.lun_debug .ne. 0) then
	  call sys$fao('Read keys :',nk1,dbgline)
	  do k=1,nk
	    call terminal_kar_conv(line(k:k),nk2,dbgline(nk1+1:))
	    nk1 = nk1 + nk2
	  end do
	  call terminal_debug(ptr_terminal_info,dbgline(1:nk1),2,dbg_flag_inp)
	endif
c
c See if the string is recognized
c
	do k=1,terminal_info.n_keys
c
c See if is one of the escape strings
c
	  if(nk .eq. terminal_info.keys(k).n_data) then
	    if(line(1:nk) .eq. terminal_info.keys(k).data(1:nk)) then
c
c  Yes, gotit
c
	      if(terminal_info.lun_debug .ne. 0) then
	        call terminal_debug(ptr_terminal_info,'Mapped as '//
     1            terminal_info.keys(k).smg_name,2,dbg_flag_inp)
	      endif
	      goto 12
	    endif
	  end if
	end do
c
c Now It must be printable
c
	if(.not. auto_check_printable(line(1:1),.true.)) goto 10
c
c Valid normal char
c
	kar = line(1:1)
	if(terminal_info.lun_debug .ne. 0) then
	  call terminal_debug(ptr_terminal_info,dbgline(1:nk1)//kar,
     1            2,dbg_flag_inp)
	endif
	goto 90
c
12	kar = char(terminal_info.keys(k).result)
c
c Now handle some special chars
c
	if(kar .eq. kar_repaint) then
c
c ^R or ^w, redraw the display
c
	  istat = terminal_redraw(ptr_terminal_info)
	  if(istat) goto 10
c
	elseif(kar .eq. kar_debug) then
c
c Handle ^D (in debug mode only)
c
	  call sys$fao('DBG: nkar = !UL, Pos = !UL, bpos =!UL',
     1             nk,line,
     1             %val(terminal_info.nkar),
     1             %val(terminal_info.position),
     1             %val(bpos))
	  call terminal_debug(ptr_terminal_info,line(1:nk),0,-1)
	elseif(kar .eq. kar_tog_verbone) then
	  if(table_toggle_verbone(ptr_table_info)) then
            istat = auto_msg(ptr_terminal_info,auto_msg_verbone,
     1                       %descr('TRUE'))
          else
            istat = auto_msg(ptr_terminal_info,auto_msg_verbone,
     1                       %descr('FALSE'))
          endif
	  if(.not. istat) goto 90
	  goto 10
	elseif(kar .eq. kar_tog_execute) then
	  execute = .not. execute
	  if(execute) then
            istat = auto_msg(ptr_terminal_info,auto_msg_execute,
     1                       %descr('TRUE'))
          else
            istat = auto_msg(ptr_terminal_info,auto_msg_execute,
     1                       %descr('FALSE'))
          endif
	  if(.not. istat) goto 90
	  goto 10
	elseif(kar .eq. kar_eol) then
c
c EOL command, goto the end of the line
c
	  terminal_info.position = terminal_info.nkar
          istat = terminal__setpos(terminal_info,x,y)
	  if(.not. istat) goto 90
	  goto 10
	elseif(kar .eq. kar_toggle) then
c
c Toggle insert mode
c
	  terminal_info.insert = .not. terminal_info.insert
	  goto 10
	elseif(kar .eq. kar_delete) then
c
c Delete char, return a delete, except when 
c the we reached bpos, in that case return a kar_back
c
	  if(terminal_info.nkar .eq. bpos) then
c
c Whole substring empty, return kar_back
c
	    kar = kar_back
	  else
	    if(terminal_info.position .eq. bpos) then
c
c Try to delete beyond the mark, not allowed
c
	      goto 10
	    endif
	  endif
c
c Check for positioning (left /rigth arrow key)
c
        elseif(kar .eq. kar_left) then
c
c Position one back, (upto bpos)
c
          if(terminal_info.position .gt. bpos) then
	    terminal_info.position = terminal_info.position - 1
            istat = terminal__setpos(terminal_info,x,y)
          endif
	  if(istat) goto 10
        elseif(kar .eq. kar_right) then
c
c Position one to the rigth (upto nkar)
c
          if(terminal_info.position .lt. terminal_info.nkar) then
	    terminal_info.position = terminal_info.position + 1
            istat = terminal__setpos(terminal_info,x,y)
          endif
	  if(istat) goto 10
	elseif(kar .eq. kar_del_token) then
c
c first position cursor at the end of the string
c
	  if(terminal_info.nkar .eq. bpos) then
c
c We are at the start of a token, return kar_delete
c
	    kar = kar_delete
	  else	    
c
c In the middle of a token, delete it
c set cursor at the end of the line
c
	    call terminal__getpos(terminal_info,x,y)
	    terminal_info.position = terminal_info.nkar
	    istat = terminal__setpos(terminal_info,x,y)
	    if(.not. istat) goto 90
c
c Now delete the whole token
c
	    do while (terminal_info.nkar .gt. bpos)
	      istat = terminal_delete(ptr_terminal_info)
	      if(.not. istat) goto 90
	    enddo
	    goto 10
	  endif
	endif
c
c If debug wanted, print it 
c
90	call sys$fao(
     1         'Key input Nkar=!UL, pos=!UL, Bpos=!UL ',
     1         nk,line,
     1         %val(terminal_info.nkar),
     1         %val(terminal_info.nkar),
     1         %val(terminal_info.nkar))
	call terminal_kdebug(ptr_terminal_info,line(1:nk),kar,
     1                       4,dbg_flag_inp)
99	terminal_read = istat
	return
	end
	function terminal__write(terminal_info,kars)
	implicit none
c
c Write a string to from terminal
c
	include 'terminal.inc'
	record /terminal_info/ terminal_info
	character*(*) kars      !:i: the data
	integer*4 terminal__write
c#
	include '($iodef)'
	include '($efndef)'
c
	integer*4 istat,opcode
	integer*4 sys$qiow
c
	record /iosb/ iosb
c
	opcode = io$_writevblk .or. io$m_noformat 
c
c All chars to the terminal
c
	istat = sys$qiow(%val(efn$c_enf),
     1                   %val(terminal_info.chan),
     1                   %val(opcode),iosb,,,
     1                   %ref(kars),%val(len(kars)),,,,)
	
	if(istat) istat = iosb.status
	terminal__write = istat
	return
	end
	function terminal__clreos(terminal_info)
	implicit none
c
c CLear the terminal from the current pos upto the end of the screen
c  we use the escape[J sequence
c
	include 'terminal.inc'
        include '($smgtrmptr)'
	record /terminal_info/ terminal_info
	integer*4 terminal__clreos
c
	integer*4 istat
	integer*4 terminal__write
	integer*4 smg$get_term_data
c
	character*40 data
	integer*4 n_data
c
        istat = smg$get_term_data(terminal_info.term_table_addr,
     1         smg$k_erase_to_end_display,
     1         len(data),n_data,%ref(data),0)
c
	if(istat) istat = terminal__write(terminal_info,data(1:n_data))
	terminal__clreos = istat
	return
	end
	function terminal__clreol(terminal_info)
	implicit none
c
c CLear the terminal from the current pos upto the end of the line
c
	include 'terminal.inc'
        include '($smgtrmptr)'
	record /terminal_info/ terminal_info
	integer*4 terminal__clreol
c
	integer*4 istat
	integer*4 terminal__write
	integer*4 smg$get_term_data
c
	character*40 data
	integer*4 n_data
c
        istat = smg$get_term_data(terminal_info.term_table_addr,
     1         smg$k_erase_to_end_line,
     1         len(data),n_data,%ref(data),0)
c
	if(istat) istat = terminal__write(terminal_info,data(1:n_data))
	terminal__clreol = istat
	return
	end
	function terminal_delete(ptr_terminal_info)
	implicit none
c
c Delete the char at position .position
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info
	integer*4 terminal_delete
c
	integer*4 istat,x,y,ipos,nk,nk_l
	character*50 line
c
	integer*4 terminal__write_line
	integer*4 terminal__setpos
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c
	p_terminal_info = ptr_terminal_info
c
	if(terminal_info.position .gt. 0) then
c
c We are not on the first char
c
	  nk   = terminal_info.nkar
	  ipos = terminal_info.position
c
c Print debug output
c
	  if(terminal_info.lun_debug .ne. 0) then
	    call sys$fao('at pos !UL from !UL:',nk_l,line,%val(ipos),%val(nk))
	    call terminal_kdebug(ptr_terminal_info,'Key delete '//line(1:nk_l),
     1                 terminal_info.line(ipos:ipos),4,dbg_flag_inp)
	  endif
c
c Make the line oke
c
	  terminal_info.line(ipos:) = terminal_info.line(ipos+1:nk)
	  terminal_info.nkar = terminal_info.nkar - 1
	  nk = nk - 1
c
c Now update the screen
c Skip one back
c
	  call terminal__getpos(terminal_info,x,y)
	  terminal_info.position = terminal_info.position - 1
	  istat = terminal__setpos(terminal_info,x,y)
	  if(.not. istat) goto 90
c
c Save the curent pos
c
	  ipos = terminal_info.position
c
c And write the new_contents + one space
c
	  istat = terminal__write_line(terminal_info,
     1             terminal_info.line(ipos+1:nk)//' ')
	  if(.not. istat) goto 90
c
c Now reposition, first get the current pos
c
	  call terminal__getpos(terminal_info,x,y)
c
	  terminal_info.position = ipos
	  istat = terminal__setpos(terminal_info,x,y)
	  if(.not. istat) goto 90
	else
	  istat = 1
	endif
90	terminal_delete = istat
	return
	end
c
	function terminal_insert(ptr_terminal_info,kar)
	implicit none
c
c Insert a character at pos .position
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info
	character*1 kar			!:i: the kar to insert
	integer*4 terminal_insert	!:f: the function result
	character*50 line
c
	integer*4 ipos,x,y,nk,istat,nk_l
	logical do_wr
c
	integer*4 terminal__write_line
	integer*4 terminal__setpos
	logical terminal_replay
	integer*4 terminal_delete
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c Print debug info
c
	p_terminal_info = ptr_terminal_info
	if(terminal_info.lun_debug .ne. 0) then
	  ipos = terminal_info.position
	  nk = terminal_info.nkar
	  call sys$fao('at pos !UL from !UL:',nk_l,line,%val(ipos),%val(nk))
	  call terminal_kdebug(ptr_terminal_info,'Key insert '//line(1:nk_l),
     1                 kar,4,dbg_flag_inp)
	endif
c
	if(kar .eq. kar_delete) then
c
c If the user wanted to insert a DELETE, execute the delete
c
	  istat = terminal_delete(ptr_terminal_info)
	  goto 90
	endif
c
	if(terminal_replay(ptr_terminal_info)) then
c
c Replay mode, 
c
	  x = terminal_info.replay_pos
c
c Now the letter to insert should be the same as the one extracted
c	  
	  if(terminal_info.replay(x:x) .ne. kar) then
c
c Unexpected
c
	    call terminal_message(ptr_terminal_info,
     1         '-E-Replay expected kar '//
     1          terminal_info.replay(x:x)//' got '//kar)
	    istat = 0	
	    goto 90
	  endif
c
c Normal , increment the pointer, and do only a position, no write
c
	  terminal_info.replay_pos = x+1
	  do_wr = .false.
	  istat = 1
	else
c
c Normal, 
c
	  do_wr = .true.
	endif
c
c Get the current screen pos
c
	call terminal__getpos(terminal_info,x,y)
c
c Get the new pos
c
	ipos = terminal_info.position +1
c
	if(terminal_info.insert) then
c
c Insert mode, shift the rest of the line
c
	  nk   = terminal_info.nkar
	  terminal_info.line(ipos:) = kar//terminal_info.line(ipos:nk)
	  terminal_info.nkar = terminal_info.nkar + 1
c
c If actual write, do it
c
	  if(do_wr) then
	    istat = terminal__write_line(terminal_info,
     1                         terminal_info.line(ipos:nk+1))
	    if(.not. istat) goto 90
	  endif
c
	else
c
c Overstrike , insert and write the char
c
	  terminal_info.line(ipos:ipos) = kar
c
c If at the end of the line, update the length
c
	  if(ipos .gt. terminal_info.nkar) terminal_info.nkar = ipos
c
c If write wanted : do it
c
	  if(do_wr) then
	    istat = terminal__write_line(terminal_info,kar)
	    if(.not. istat) goto 90
	  endif
c
	endif
c
c We did some screen IO, so we might need to reposition
c
	call terminal__getpos(terminal_info,x,y)
c
	terminal_info.position = ipos
c
	if(do_wr) then
c
c And set the cursor
c
	  istat = terminal__setpos(terminal_info,x,y)
	  if(.not. istat) goto 90
	endif
c
90	terminal_insert = istat
	return
	end
	function terminal_try(ptr_terminal_info,kar,line,nkar)
	implicit none
c
c Return line with inserted/deleted char
c  do not change the terminal buffer and or the screen
c this gives the called the option to check if
c  this new character will be an allowed string
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info	!:i: terminal info
	character*1 kar				!:i: the char to insert (or kar_delete)
	character*(*) line			!:o: the resulting line
	integer*4 nkar				!:o: the resulting nkar
	integer*4 terminal_try
c
	integer*4 ipos,istat
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
	p_terminal_info = ptr_terminal_info
	ipos = terminal_info.position + 1
	nkar   = terminal_info.nkar
c
	if(kar .eq. kar_delete) then
c
c Delete char
c
	  line = terminal_info.line(1:ipos-2)//
     1           terminal_info.line(ipos:nkar)
	  nkar = nkar - 1
	else
c
c Insert the char
c
	  if(terminal_info.insert) then
	    line = terminal_info.line(1:ipos-1)//kar//
     1             terminal_info.line(ipos:nkar)
	    nkar = nkar + 1
	  else
c
c Just overwrite the char
c                     
	    line = terminal_info.line(1:nkar)
	    line(ipos:ipos) = kar
	    if(ipos .gt. nkar) nkar = ipos
	  endif
	endif
	istat = 1
	terminal_try = istat
	return
	end

	subroutine terminal__getpos(terminal_info,x,y)
	implicit none
c
c Return the X,y pos for the .position field
c
	include 'terminal.inc'
	record /terminal_info/ terminal_info
	integer*4 x		!:o: x
	integer*4 y             !:o: y
c
	x = terminal_info.position+terminal_info.nkar_prompt
	y = x/terminal_info.width
	x = mod(x,terminal_info.width)
	return
	end
c
	function terminal__setpos(terminal_info,x,y)
	implicit none
c
c Set the terminal to the x,y belonging to .position
c At this moment we are at pos x,y
c
	include 'terminal.inc'
	record /terminal_info/ terminal_info
	integer*4 x,y
	integer*4 terminal__setpos
c
	integer*4 xw,yw,istat
	integer*4 terminal__position_hor
	integer*4 terminal__position_ver
c
c We want to go to .position, so compute its xw and yw
c
	call terminal__getpos(terminal_info,xw,yw)
c
c We are at y end we want to go to yw, do some vertical movement
c
	istat = terminal__position_ver(terminal_info,yw-y)
	if(.not. istat) goto 90
c
c We are at x and we want to go to xw, so some horizontal movement
c
	istat = terminal__position_hor(terminal_info,xw-x)
90	terminal__setpos = istat
	return
	end
	function terminal__position_hor(terminal_info,n)
	implicit none
c
c Position the cursor 
c  n<0 : -n pos to the left
c  n>0 :  n pos to the right
c
	include 'terminal.inc'
	include '($smgtrmptr)'
	record /terminal_info/ terminal_info
	integer*4 n
	integer*4 terminal__position_hor
c#
	character*20 line
	integer*4 nk,option
	integer*4 args(2)
c
	integer*4 istat
	integer*4 terminal__write
	integer*4 smg$get_term_data
c
	args(1) = 0
	if(n .lt. 0) then
c
c Skip -n to the left
c We use the escape[nnnD command
c
	  args(2) = - n
	  option = smg$k_cursor_left
	else
c
c Skip n to the right
c
	  args(2) = n
	  option = smg$k_cursor_right
	endif
c	
	if(args(2) .ne. 0) then
	  args(1) = 1
          istat = smg$get_term_data(terminal_info.term_table_addr,
     1         option,
     1         len(line),nk,%ref(line),args)
	  if(istat) istat = terminal__write(terminal_info,line(1:nk))
	else
	  istat = 1
	end if
	terminal__position_hor = istat
	return
	end
	function terminal__position_ver(terminal_info,n)
	implicit none
c
c Position the cursor 
c  n<0 : -n lines up
c  n>0 :  n lines down
c
	include 'terminal.inc'
	include '($smgtrmptr)'
	record /terminal_info/ terminal_info
	integer*4 n
	integer*4 terminal__position_ver
c#
	character*10 line
	integer*4 nk
c
	integer*4 k,istat,args(2)
	integer*4 terminal__write
	integer*4 smg$get_term_data
c
	if(n .lt. 0) then
c
c -n lines up
c We use the escape[nnnA command
c
	  args(1) = 1
	  args(2) = -n
          istat = smg$get_term_data(terminal_info.term_table_addr,
     1         smg$k_cursor_up,
     1         len(line),nk,%ref(line),args)
	  if(istat) istat = terminal__write(terminal_info,line(1:nk))
	elseif(n .gt. 0) then
c
c n lines down
c We cannot use the escape[nnB command, since that will not scroll
c the terminal, if we hit the last line,  so we use the LF command
c
	  k = n
	  do k=1,k
	    istat = terminal__write(terminal_info,key_linefeed)
	  end do
	else
	  istat = 1
	end if
	terminal__position_ver = istat
	return
	end
	function terminal_message(ptr_terminal_info,message)
	implicit none
c
c Print out a message below the current input line
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info    !:i: terminal state
	character*(*) message			!:i: the message
	integer*4 terminal_message
c
	integer*4 istat,xc,yc,xl,yl,ny,k,bpos,epos
c
	integer*4 terminal__position_ver
	integer*4 terminal__position_hor
	integer*4 terminal__write
	integer*4 terminal__clreol
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c
	p_terminal_info = ptr_terminal_info
	istat = 1
c
	if(message .eq. ' ') then
c
c We want to clear the current message (if it is there)
c
	  if(.not. terminal_info.got_msg) goto 90
c
c Yes it was there, now clear it
c
	  terminal_info.got_msg = .false.
	else
c
c We need to print a message
c
	  terminal_info.got_msg = .true.
	  call terminal_debug(ptr_terminal_info,message,0,-1)
	endif
c
c Get the  x,y of the curr pos
c
	call terminal__getpos(terminal_info,xc,yc)
c
c get the x,y for the last char
c
	k = terminal_info.position
	terminal_info.position = terminal_info.nkar
	call terminal__getpos(terminal_info,xl,yl)
	terminal_info.position = k
c
c Now skip to the last line
c
	ny = yl-yc
	istat = terminal__position_ver(terminal_info,ny)
	if(.not. istat) goto 90
c
c We are the last used line, set col to 1
c 
	istat = terminal__write(terminal_info,key_return)
	if(.not. istat) goto 90
c
	if(message .eq. ' ') then
c
c Clear the message area, we are at col 1 of the first message line
c
	  do k=1,terminal_info.nl_mess
	    ny = ny + 1
	    istat = terminal__write(terminal_info,key_linefeed)
	    if(.not. istat) goto 90
	    istat = terminal__clreol(terminal_info)
	    if(.not. istat) goto 90
	  end do
	  terminal_info.nl_mess = 0
c
	else
c
c Real message, we can add messages
c Now skip past the previous message (if there is one)
c
	  bpos = 1
	  k = terminal_info.nl_mess
	  istat = terminal__position_ver(terminal_info,k)
	  ny = ny + k
c
c Now we are on the last of the message (on col 1)
c
	  do while(bpos .le. len(message))
c
c Now print the message(bpos:end)
c Now compute the end, no more then screen width
c
	    epos = bpos + terminal_info.width - 1
	    if(epos .gt. len(message)) epos = len(message)	
c
c Write out the linefeed + line + clreol + return + linefeed
c 
	    istat = terminal__write(terminal_info,key_linefeed)
	    if(.not. istat) goto 90
	    istat = terminal__clreol(terminal_info)
	    if(.not. istat) goto 90
	    istat = terminal__write(terminal_info,message(bpos:epos))
	    if(.not. istat) goto 90
	    istat = terminal__write(terminal_info,key_return)
	    if(.not. istat) goto 90
	    ny = ny + 1
	    terminal_info.nl_mess = terminal_info.nl_mess + 1
c
c Update the starting pos, and see if we need more
c
	    bpos = epos + 1
	  end do
	end if
c
c In ny we have the number of lines skipped down, reposition
c
	istat = terminal__position_ver(terminal_info,-ny)
	if(.not. istat) goto 90
c
c And reposition to the old xpos
c at this moment we are at the beginning of the line
c
	istat = terminal__position_hor(terminal_info,xc)
	if(.not. istat) goto 90
90	terminal_message = istat
	return
	end
	subroutine terminal_debug(ptr_terminal_info,line,indent,flag)
	implicit none
c
c Print out a debug message with indent, but only if the debugging
c for this type is set
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info
	character*(*) line
	integer*4 indent
	integer*4 flag
c
	character*40 spaces
	integer*4 ind
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c Set indent level
c
	p_terminal_info = ptr_terminal_info
	ind = min(len(spaces),max(0,indent))
c
	if(terminal_info.lun_debug .ne. 0) then
c
c If flag<0 , (print always)
c  or if specific bit is set, print the message indented
c
	  if(flag .lt. 0 .or.
     1       ((terminal_info.debug_flag .and. flag) .ne. 0)) then
	    spaces = ' '
	    write(terminal_info.lun_debug,'(a)') spaces(1:ind)//line
	  endif
	end if
	return
	end
	subroutine terminal_kdebug(ptr_terminal_info,line,kar,indent,flag)
	implicit none
c
c Print out a chatacter, if the char is unprintable, convert it to
c   something readable
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info
	character*(*) line		!:i: intro string
	character*1 kar			!:i: the char to be printed
	integer*4 indent		!:i: indent level
	integer*4 flag			!:i: debug flag
c
	integer*4 nk1
	character*20 wkar
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c Check to see if we are in typehad mode
c
	p_terminal_info = ptr_terminal_info
c
	if(terminal_info.lun_debug .ne. 0) then
c
c Conver char to something printable
c
	  call terminal_kar_conv(kar,nk1,wkar)
c
c and do a normal debug print
c
	  call terminal_debug(ptr_terminal_info,line//
     1         'Kar "'//wkar(1:nk1)//'"',indent,flag)
	endif
	return
	end
	subroutine terminal_kar_conv(kar,nk1,wkar)
	implicit none
c
c Convert a character to a printable one
c
	include 'terminal.inc'
c
	character kar		!:i: the character to convert
	integer*4 nk1		!:o: length of string
	character*(*) wkar	!:o: name for the char
c#
	wkar = ' '
c
	if(    kar .eq. kar_return) then
	  call sys$fao('KAR_RETURN',nk1,wkar)
	elseif(kar .eq. kar_replay) then
	  call sys$fao('KAR_REPLAY',nk1,wkar)
	elseif(kar .eq. kar_expand) then
	  call sys$fao('KAR_EXPAND',nk1,wkar)
	elseif(kar .eq. kar_expand_prev) then
	  call sys$fao('KAR_EXPAND_PREV',nk1,wkar)
	elseif(kar .eq. kar_back) then
	  call sys$fao('KAR_BACK'  ,nk1,wkar)
	elseif(kar .eq. kar_help) then
	  call sys$fao('KAR_HELP'  ,nk1,wkar)
	elseif(kar .eq. kar_list) then
	  call sys$fao('KAR_LIST'  ,nk1,wkar)
	elseif(kar .eq. kar_abort) then
	  call sys$fao('KAR_ABORT' ,nk1,wkar)
	elseif(kar .eq. kar_delete) then
	  call sys$fao('KAR_DELETE',nk1,wkar)
	elseif(kar .eq. kar_override) then
	  call sys$fao('OVERRIDE',nk1,wkar)
	elseif(kar .eq. kar_del_token) then
	  call sys$fao('CLEARTOKEN',nk1,wkar)
	elseif(kar .eq. kar_left) then
	  call sys$fao('LEFT_ARR',nk1,wkar)
	elseif(kar .eq. kar_right) then
	  call sys$fao('RIGHT_ARR',nk1,wkar)
	elseif(kar .eq. kar_toggle) then
	  call sys$fao('TOGGLE',nk1,wkar)
	elseif(kar .eq. kar_repaint) then
	  call sys$fao('REPAINT',nk1,wkar)
	else
	  if((ichar(kar).ge.32     .and. ichar(kar).le.126    ) .or.
     1       (ichar(kar).ge.32+128 .and. ichar(kar).le.126+128)) then
c
c Printable char
c
	    call sys$fao('!AS',nk1,wkar,kar)
	  else
c
c Unprintable, conver to hex string
c
	    call sys$fao('%X!2XL',nk1,wkar,%val(ichar(kar)))
	  endif
	endif	  
	return
	end
	function terminal_redraw(ptr_terminal_info)
	implicit none
c
c Redraw the line after a ^W or ^R key
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info
c
	record /terminal_info/ terminal_info	!:i: terminal block
	pointer (p_terminal_info,terminal_info)
c
	integer*4 terminal_redraw
c
	integer*4 istat,isave,x,y
c
	integer*4 terminal__write
	integer*4 terminal__write_line
	integer*4 terminal__clreos
	integer*4 terminal__setpos
c
c Position to begining of line
c
	p_terminal_info = ptr_terminal_info
c
	istat = terminal__write(terminal_info,key_return)
	if(.not. istat) goto 90
c
c clear to EOS
c
	istat = terminal__clreos(terminal_info)
	if(.not. istat) goto 90
c
c Write out the prompt and the text
c
	istat = terminal__write(terminal_info,
     1      terminal_info.prompt(1:terminal_info.nkar_prompt))
	isave = terminal_info.position
	terminal_info.position = 0
c
	istat = terminal__write_line(terminal_info,
     1      terminal_info.line(1:terminal_info.nkar))
	if(.not. istat) goto 90
c
c Now reset the cursor
c
	call terminal__getpos(terminal_info,x,y)
c
	terminal_info.position = isave
	istat = terminal__setpos(terminal_info,x,y)
	
90	terminal_redraw = istat
	return
	end
c
	function terminal__write_line(terminal_info,line)
	implicit none
c
	include 'terminal.inc'
	record /terminal_info/terminal_info
	character*(*) line	
	integer*4 terminal__write_line
c
	integer*4 bpos,epos,istat,avail,x,y
	integer*4 terminal__write
c
c Get the current position, to compute the #hars
c  that still fit on this line
c	
	call terminal__getpos(terminal_info,x,y)
c
c Getpos gives an x form 0..width-1
c
	avail = terminal_info.width - x
c
	istat = 1
	bpos  = 1
c
	do while(bpos .le. len(line))
	  epos = min(bpos+avail-1,len(line))
	  istat = terminal__write(terminal_info,
     1               line(bpos:epos))
	  if(.not. istat) goto 90
	  terminal_info.position = terminal_info.position + epos-bpos+1
	  if(epos .eq. bpos+avail-1)  then
c
c  We have a full line, go to the next line
c
	    istat = terminal__write(terminal_info,
     1                key_return//key_linefeed)
	    if(.not. istat) goto 90
	  endif
c
c For the following lines, the avail room is the terminal width
c
	  avail = terminal_info.width
	  bpos = epos + 1
	end do
c
c Update the position
c
90	terminal__write_line = istat
	return
	end
	function terminal_start_replay(ptr_terminal_info,pos)
	implicit none
c
c Initialise replay mode at pos position
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info
	integer*4 pos
	integer*4 terminal_start_replay
c
	character*50 line
	integer*4 nk_l
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
	p_terminal_info = ptr_terminal_info
c
	terminal_info.replay_pos = pos
c
	if(terminal_info.lun_debug .ne. 0) then
	  call sys$fao('!UL',nk_l,line,%val(pos))
	  call terminal_debug(ptr_terminal_info,
     1            'Start of replay at pos '//
     1             line(1:nk_l),0,dbg_flag_inp)
	endif
c
c Save chars in replay buffer
c
	terminal_info.replay     = terminal_info.line
	terminal_info.nk_replay  = terminal_info.nkar
c
c And remove chars from the actual buffer
c
	terminal_info.nkar       = pos-1
	terminal_info.position   = pos-1
	terminal_start_replay = 1
	return
	end
	function terminal_replay(ptr_terminal_info)
	implicit none
c
c Return true if in replay_mode
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info
	logical terminal_replay			!:f: true or false
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
c
	p_terminal_info = ptr_terminal_info
c
	terminal_replay = 
     1       terminal_info.replay_pos .gt. 0 .and.
     1       terminal_info.replay_pos .le. terminal_info.nk_replay
	return
	end
	function terminal__read(terminal_info,kars,nb)
	implicit none
c
c Read a char/escape sequence string from from terminal
c
	include 'terminal.inc'
	record /terminal_info/ terminal_info
	character*(*) kars      !:i: the data
	integer*4 nb
	integer*4 terminal__read
c#
	include '($iodef)'
	include '($efndef)'
c
	structure /item/
	  integer*2 buflen,opcode
	  integer*4 bufadr,retadr
	end structure
c
	integer*4 istat,opcode
	integer*4 sys$qiow
c
	record /iosb/ iosb
	record /item/ items(10)
c
	include '($trmdef)'
c
	integer*4 nit,nb1,k
c
	integer*4 terms(8)	!all chars are terrminator
c
c
	opcode = io$_readvblk .or. io$m_extend
c
c Set all chars to be a terminator (this needs 256 bits = 8 lognwords)
c
	do k=1,8
	  terms(k) = -1
	end do
c
c Init items for item_read
c
	nit = 0
c
c Set the modes
c
	nit = nit +1
	items(nit).opcode = trm$_modifiers
	items(nit).buflen = 0
	items(nit).bufadr = trm$m_tm_nofiltr .or.
     1                      trm$m_tm_noecho .or.
     1                      trm$m_tm_trmnoecho .or.
     1                      trm$m_tm_norecall .or.
     1                      trm$m_tm_escape .or.
     1                      trm$m_tm_noedit
	items(nit).retadr = 0
c
c Set the terminator
c
	nit = nit +1
	items(nit).opcode = trm$_term
	items(nit).buflen = sizeof(terms)
	items(nit).bufadr = %loc(terms)
	items(nit).retadr = 0
c	
	nb1 = nit * sizeof(items(1))
c
c And do the io
c
	istat = sys$qiow(%val(efn$c_enf),
     1                   %val(terminal_info.chan),
     1                   %val(opcode),iosb,,,
     1                   %ref(kars),%val(len(kars)),
     1                   ,,items,%val(nb1))
c	

	if(istat) istat = iosb.status
	nb = iosb.nbyte + iosb.nbterm
c
c Since we do not know if the terminal will send 8 bits
c  (we could find out, but the next is easier)
c if data(1:1) = csi , replace by escape//'[ 
c  The terminal_insert_kars uses the same algorithm
c
	if(nb .ge. 1) then
	  if(kars(1:1) .eq. key_csi) then
	    kars = key_escape//'['//kars(2:)
	    nb = nb + 1
	  end if	 
	endif
90	terminal__read = istat
	return
	end
	subroutine terminal_set_typeahd(ptr_terminal_info,line)
	implicit none
c
c Insert the line into the typeahead buffer
c the next read will return the next byte from
c the typeahead buffer, until this buffer is empty
c If there is still something in the buffer is will be afer the
c new line
c
	include 'terminal.inc'
	integer*4 ptr_terminal_info	!:io: terminal block
	character*(*) line			!:i: chars to insert
c
	integer*4 nk
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
	p_terminal_info = ptr_terminal_info
c
	nk = terminal_info.nk_typeahd
c
	terminal_info.typeahd = line//terminal_info.typeahd(1:nk)
	terminal_info.nk_typeahd = nk+len(line)
	return
	end
	subroutine terminal_get_pos(ptr_terminal_info,nk_beg,pos)
	implicit none
	include 'terminal.inc'
c
c Return the relatvie cursor position in the current field
c
	integer*4 ptr_terminal_info
	integer*4 nk_beg		!:i: start of field
	integer*4 pos			!:o: position 1..n
c
	record /terminal_info/ terminal_info
	pointer (p_terminal_info,terminal_info)
c
	p_terminal_info = ptr_terminal_info
c
	pos = terminal_info.position - nk_beg + 1
	return
	end

