/*===========================================================================
  Copyright (C) 1995-2010 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++++++++   MIDAS monitor routines PREPA2  +++++++++++++++++++++++++
.LANGUAGE      C
.IDENTIFICATION  Module PREPA2
.AUTHOR  K. Banse                  	ESO - Garching
.KEYWORDS  MIDAS monitor
.ENVIRONMENT  VMS and UNIX
.PURPOSE
synchronize fore- and background processes; 
get the MIDAS command string + take action accordingly
.ALGORITHM
loop on command input (from terminal or procedure file),
test for background activity and synchronize
system commands are executed directly,
all others are executed as command procedures

holds Parse3, TTSET, TTINIT, TTEDIT, TTPRO

.VERSION 

 100608		last modif
------------------------------------------------------------------------*/

#define _POSIX_SOURCE 1		/* indicate that this is a POSIX program */
 
#define OLDTOKMAX 62		/* size of OLDTOKENs is fixed to 64 */

#include <stdio.h>
#include <strings.h>
#include <fileexts.h>
#include <signal.h>

#ifndef SIGUSR1
#define SIGUSR1 30
#endif
#ifndef SIGUSR2
#define SIGUSR2 31
#endif

#include <osyparms.h>
#include <monitdef.h>
#include <midfront.h>

#if vms				/* FO's terminal stuff only used in VMS */
#define TW_import 0
#include <tw.h>
#include <osterm.h>
#endif

#include <ok.h>
#ifndef EOF
#define EOF   (-1)     /* End of File */
#endif

static char   wstr[84];
static char   blank = {' '};

#ifndef NO_READLINE
#define HAVE_STRING_H
#include <setjmp.h>
#include <readline/readline.h>		/* see changes in re_edit () */
#include <stdlib.h>
#include <string.h>
#include <osxdef.h>		/* MIDAS osx definitions */
#include <midback.h>		/* Context extructure */

typedef int Function ();
typedef char **CPPFunction ();

extern int  is_a_tty;		/* Is this a terminal, (yes=1) set in prepa.c */

void using_history();
int  read_history(), rl_add_funmap_entry();


static char contxt_name[MAX_CONTXT*8+2];	/* Activated contexts */
static char acknowledge;
static char buffer[20];				/* command for xhelp */
static char   *line_read;
static char   history_file[200];   /* FRONT.STARTUP+".history."+FRONT.DAZUNIT */
static sigjmp_buf  env;
/*

*/

/* Contains the line to push into readline. */
static char *push_to_readline = (char *)NULL;
static Function *old_rl_startup_hook = (Function *) NULL;


/* Push the contents of push_to_readline into the readline buffer. */
static void push_line ()
{
  if (push_to_readline)
    {
      rl_insert_text (push_to_readline);
      free (push_to_readline);
      push_to_readline = (char *)NULL;
      rl_startup_hook = old_rl_startup_hook;
    }
}

/* Call this to set the initial text for the next line to read from readline. */
int re_edit (line)
char *line;
{
  char  *xmalloc();

  if (push_to_readline)
    free (push_to_readline);

  push_to_readline = xmalloc (1 + strlen (line));
  (void) strcpy (push_to_readline,line);

  old_rl_startup_hook = rl_startup_hook;
  rl_startup_hook = (Function *)push_line;

  return (0);
}

struct COMMAND {
  char name[12];		/* User printable name of the function */
  struct COMMAND *prev;	
  };

struct CMD_LIST {
  struct COMMAND *curr;
  struct COMMAND *last;
  };

extern struct CMD_LIST cmds;

static int xhelp_fd = -1; 
static int xhelp_pid = 0;
static char *channame[2] = { (char *)NULL, (char *)NULL };

static int initialize_xhelp()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Initialize channname, containing socket name and
         filename crated by XHelp.exe containing its pid.
         It opens a server connection.
	 Initialize the contxt_name string to check for 
	 context changes.
.RETURNS 0 OK, -1 otherwise.
------------------------------------------------------------*/
{
char *mid_work, *dazunit;
int n;

mid_work = getenv("MID_WORK");

channame[1] = (char *)
  malloc((size_t)(strlen(mid_work)+strlen("xhelp")+2+strlen("_pid")+1));

dazunit = getenv("DAZUNIT");

(void) strcpy(channame[1],mid_work);
(void) strcat(channame[1],"xhelp");
(void) strcat(channame[1],dazunit);
(void) strcat(channame[1],"_pid");

n = (int) strlen(channame[1]) - (int) strlen("_pid");
channame[0] = (char *) malloc((size_t)(n+1));
(void) strncpy(channame[0],channame[1],n);
channame[0][n] = '\0';

xhelp_fd = osxopen(channame,LOCAL|IPC_READ);
if (xhelp_fd < 0) 
   {
   (void) printf("\n\rCannot create server for GUI XHelp.exe.\n\r");
   (void) printf("Error message: %s\n\r",osmsg());
   free(channame[0]);
   free(channame[1]);
   xhelp_fd = -1;
   return(-1);
   }

/* Initialize the context_name and buffer strings */
memset(contxt_name,' ',MAX_CONTXT*8);	/* clear context names */
memset(buffer,'\0',20);		/* Initiate command name */
contxt_name[MAX_CONTXT*8] = '\0';	/* make sure we have an end marker */

return(0);
}

void close_xhelp()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Close socket and free allocated memory.
	 This routine is called by prepa.c after the BYE command.
.RETURNS void
------------------------------------------------------------*/
{
if (xhelp_fd != (-1))
   {
   (void) osxclose(xhelp_fd);
   (void) free(channame[0]);
   (void) free(channame[1]);
   }
}

Function *gui_xhelp()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE send messages to the GUI XHELP.
.RETURNS nothing
------------------------------------------------------------*/
{
  int len;
  char *start_buffer;
  FILE *fd;

if (xhelp_fd == (-1)) return 0;


  /* retrieve the pid number from XHELP */
  if (!xhelp_pid) {
    if ( (fd = fopen(channame[1],"r")) == (FILE *)NULL) {
      (void) printf("\n\rTry first: CREATE/GUI HELP \n\r");
      rl_refresh_line(0,0);
      return 0;
      }
    fscanf(fd,(const char *) "%d\n",&xhelp_pid);
    fclose(fd);
    if (kill(xhelp_pid,0) == -1) {
      xhelp_pid = 0;
      unlink(channame[1]);
      (void) printf("\n\rTry first: CREATE/GUI HELP \n\r");
      rl_refresh_line(0,0);
      return 0;
      }
    }

  /* Prepare the message to be sent to XHELP not bigger than 12 chars */
  /* Strip leading blanks */
  start_buffer = rl_line_buffer;
  while ( *start_buffer == ' ') start_buffer++;
   
  len = strlen(start_buffer);
  len = (len > 19)? 19 : len;


  strncpy(buffer,start_buffer,len);
  buffer[len] = '\0';
  if (buffer[len-1] == '/') buffer[len-1] = '\0';

 /* Check first if CONTEXT list has changed, if so then send USR2 */
 if (strcmp(contxt_name,CONTXT.NAME)) {
    (void) strcpy(contxt_name,CONTXT.NAME);
    /* (void) printf("sending SIGUSR2\n"); */
    if (osssend(xhelp_pid,SIGUSR2) == -1) {
      xhelp_pid = 0;
      return 0;
      }
    while (osxinfo(xhelp_fd,0,0) == NOCONN) ;
    /* (void) printf("sending context=%s\n",contxt_name); */
    if (osxwrite(xhelp_fd,contxt_name,MAX_CONTXT*8 + 2) != MAX_CONTXT*8 + 2) 
      if (osxwrite(xhelp_fd,contxt_name,MAX_CONTXT*8 + 2) != MAX_CONTXT*8 + 2) {
        xhelp_pid = 0;
        return 0;
        }
    acknowledge = 0;
    if (osxread(xhelp_fd,&acknowledge,1) != 1 && acknowledge != 1) {
      xhelp_pid = 0;
      return 0;
      }
    }

  /* 
   * Send the message to XHELP , and then interrupt it with USR1 signal.
   * If error, the connection is broken.
   */
  /* printf("sending SIGUSR1\n"); */
  if (osssend(xhelp_pid,SIGUSR1) == -1) {
    xhelp_pid = 0;
    return 0;
    }
  /* printf("osxinfo=%d\n",osxinfo(xhelp_fd,0,0)); */
  while (osxinfo(xhelp_fd,0,0) == NOCONN) ;
  /* printf("sending command=%s\n",buffer); */
  if (osxwrite(xhelp_fd,buffer,20) != 20 ) 
    if (osxwrite(xhelp_fd,buffer,20) != 20 ) {
      xhelp_pid = 0;
      return 0;
      }
  acknowledge = FALSE;
  if (osxread(xhelp_fd,&acknowledge,1) != 1 && acknowledge != 1) {
    xhelp_pid = 0;
    return 0;
    }
return 0;
}

/* Tell the GNU Readline library how to complete. We want to try to complete
 * on command names if this is the first word in the line, or on filenames
 * if not.
 */
static void initialize_readline()
{
  char **fileman_completion();
  extern Keymap _rl_keymap;

if (KIWORDS[OFF_MODE+2] == 0)
   {   
   if (!initialize_xhelp()) {
      rl_add_funmap_entry("gui-xhelp",gui_xhelp);
      rl_bind_key('\030',gui_xhelp); 		   /* Bind CTR-X */
      rl_set_key ("\\e[11~",gui_xhelp,_rl_keymap); /* F1 on Xtectronix and PC */
      rl_set_key ("\\ep\r",gui_xhelp,_rl_keymap);   /* F1 on HPs */
      rl_set_key ("\\e[[A",gui_xhelp,_rl_keymap);   /* F1 on Digital PC */
      }
   }

  /* Allow conditional parsing of the ~/.inputrc file */
  rl_readline_name = "MIDAS";

  /* Tell the completer that we want a crack first */
  rl_attempted_completion_function = (CPPFunction *)fileman_completion;
 
  if (!is_a_tty) rl_outstream = fopen("/dev/null","w");

}
/*

*/

void fileman_ignore(matches)
char **matches;
{
  int i;
  char *ptr;
  if (!matches) return;
  for ( i = 0; matches[i]; i++) 
     if ( (ptr = strchr(matches[i], '.')) != (char *)NULL) *ptr = '\0';
}




/* Attempt to complete on the contents of TEXT. START and END show the
 * region of TEXT that contains the word to complete. We can use the entire
 * line in case we want to do some simple parsing. Return the array of matches,
 * or NULL if there aren't any. 
 */
char **fileman_completion(text, start, end)
char *text;
int start, end;
{
  extern char **completion_matches ();
  char **matches;
  char *command_generator();
  char *filename_completion_function();
  char *curr_dir, *match_dir, *dest_dir;
  char *start_buffer;

  matches = (char **)NULL;
  match_dir = (char *)NULL;

  /* If this word is at the start of the line, then it is a command to complete
   * Otherwise it is the name of a file in the current directory.
   */
  start_buffer = rl_line_buffer;
  while ( *start_buffer == ' ') { start_buffer++; start--; }

  if (start == 0)
    matches = completion_matches(text,command_generator);
  else if (!strncasecmp(start_buffer,"SHOW/COMM",9) ||
           !strncasecmp(start_buffer,"HELP ",5) || 
           !strncasecmp(start_buffer,"DELETE/COMM",11) ||
           !strncasecmp(start_buffer,"CREATE/COMM",11))
    matches = completion_matches(text,command_generator);
  else if (!strncasecmp(start_buffer,"@ " ,2)) match_dir = getenv("MID_PROC");
  else if (!strncasecmp(start_buffer,"@a ",3)) match_dir = getenv("APP_PROC");
  else if (!strncasecmp(start_buffer,"@s ",3)) match_dir = getenv("STD_PROC");
  else if (!strncasecmp(start_buffer,"@c ",3)) match_dir = getenv("CON_PROC");
  else if (!strncasecmp(start_buffer,"LOAD/LUT ",9) ||
           !strncasecmp(start_buffer,"LOAD/ITT ",9)) 
		match_dir = getenv("MID_SYSTAB");
  else if (!strncasecmp(start_buffer,"SET/CONT",8) ||
           !strncasecmp(start_buffer,"CLEAR/CONT",10)  ||
           !strncasecmp(start_buffer,"SHOW/CONT",10)) 
		match_dir = getenv("MID_CONTEXT");
  else if (!strncasecmp(start_buffer,"CREATE/GUI ",11))
		match_dir = getenv("GUI_EXE");

  if (match_dir != (char *)NULL) {
    dest_dir = malloc((size_t)(strlen(match_dir)+1));
    (void) strcpy(dest_dir,match_dir);
    oshgetcwd(&curr_dir);
    oshchdir(dest_dir);
    matches = completion_matches(text,filename_completion_function);
    oshchdir(curr_dir);
    free(dest_dir);
    }
  if (!strncasecmp(start_buffer,"SET/CONT",8) ||
      !strncasecmp(start_buffer,"CLEAR/CONT",10) ||
      !strncasecmp(start_buffer,"CREATE/GUI ",11)) fileman_ignore(matches);

  return(matches);
}
/*

*/

/*
 * Generator fucntion for command completion. STATE lets us know weather
 * to start from scratch; without any state (i.e. STATE =0), then we start
 * at the top of the list
 */
char *command_generator(text, state)
char *text;
int state;
{
static int len;
static char mytext[12]; 
static char *ptr_text;
register struct COMMAND *mycmd;
register char *slash_ptr;
register int len_cmd, max_len_cmd, len_qua;

/* 
* If this is a new word to complete, initialize now. This includes
* saving the length of TEXT for efficiency, an initializing the index
* variable to 0
*/

if (MONIT.CMD_LIST_UPDA == 1) 		/* commands have been modified... */
   update_cmd_list();


if (!state) {
   len = strlen(text);
   if ((slash_ptr = (char *)strchr(text,'/')) != (char *)NULL) {
      len_cmd = (long)slash_ptr - (long)text;
      max_len_cmd = (len_cmd > 6)? 6 : len_cmd;
      (void) strncpy(mytext,text,max_len_cmd);
      mytext[max_len_cmd] = '/';
      mytext[max_len_cmd+1] = '\0';
      len_qua = strlen(&text[len_cmd+1]);
      (void) strncat(mytext,&text[len_cmd+1],(len_qua > 4)? 4 : len_qua);
      len = strlen(mytext);
      ptr_text= mytext;
      }
   else {
      len = (len > 6)? 6 : len;
      (void) strncpy(mytext,text,len);
      mytext[len] = '\0';
      ptr_text = text;
      }
   cmds.curr = cmds.last;
   }

/* Return the next name which partially matches from the command list. */
while ((mycmd = cmds.curr) != (struct COMMAND *)NULL) {
   cmds.curr = mycmd->prev;
   if (strncasecmp(mycmd->name,ptr_text,len) == 0) 
      return
      ((char *)strcpy((malloc((size_t)(strlen(mycmd->name)+1))),mycmd->name));
   }

/* If no names matched, then return NULL */
return((char *)NULL);
}
  


#ifdef __STDC__
static void TTPRO_alarm(int sig)
#else
static void TTPRO_alarm(sig)
/*++++++++++++++++
.PURPOSE Function called at end of time-out
.RETURNS Within ostread function. Internal use only.
---------*/
int sig;
#endif
{
  siglongjmp(env,1);    /* return with the saved signal mask from sigsetjmp */
}
#endif /* NO_READLINE */
/*

*/
 
int Parse3(start)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  clean input line
.ALGORITHM
.RETURNS
  return no. of tokens on line
---------------------------------------------------------------------*/

int  start;

{
int   lstart, lsave;
int   n, count, substi, kk, nn, mm;
register int  nr;

char  wbuf[MAX_TOKEN]; 
register char   sngc;



/*  extract all tokens + get their length, also use OLD_TOKEN   */

lstart = start;
substi = 0;

for (n=0; n<10; n++)
   {
   TOKEN[n].LEN = 
        CGN_EXTRSS(LINE.STR,LINE.LEN,blank,&lstart,TOKEN[n].STR,MAX_TOKEN);
   if (TOKEN[n].LEN <= 0)                       /* end of parsing reached... */
      {
      if (TOKEN[n].LEN == -2)                   /* overflow of single token */
         {
         ERRORS.SYS = 7;
         PREPERR("MIDAS",LINE.STR,TOKEN[n].STR);
         return (-1);
         }

      count = n ;
      for (nr=count; nr<10; nr++)
         {
         TOKEN[nr].STR[0] = '?';             /* init empty TOKEN + LTOKEN  */
         TOKEN[nr].STR[1] = '\0' ;
         TOKEN[nr].LEN = 1 ;
         }
      goto end_of_it;
      }


   /* test for interactive input with "."  */
 
   if ( (TOKEN[n].STR[0] == '.') && (TOKEN[n].LEN == 1) )
      {
      TOKEN[n].LEN = CGN_COPY(TOKEN[n].STR,OLDTOKEN[n].STR);
      substi = 1 ;                           /* it's like a substitution */
      }
   else
      {
      sngc = TOKEN[n].STR[OLDTOKMAX];			/* save char. */
      TOKEN[n].STR[OLDTOKMAX] = '\0';			/* so, no overrun... */
      OLDTOKEN[n].LEN = CGN_COPY(OLDTOKEN[n].STR,TOKEN[n].STR); 
      TOKEN[n].STR[OLDTOKMAX] = sngc;
      }
   }

count = 10 ;


/*  test, if more than 10 tokens on line  */

if (LINE.LEN >= lstart)
   {
   for (nr=lstart; nr<LINE.LEN; nr++)
      {
      if (LINE.STR[nr] != ' ') goto collect_rest;
      }
   goto end_of_it;                              /* only trailing blanks */


collect_rest:
   nn = TOKEN[9].LEN;
   kk = 0;
   for (nr=0; nr< 39; nr++)       /* garbage collection of 40 more tokens...  */
      {
      lsave = CGN_EXTRSS(LINE.STR,LINE.LEN,blank,&lstart,wbuf,MAX_TOKEN);
      if (lsave > 0)
         {
         if ((lsave+nn+1) > MAX_TOKEN)
            {
            kk = 1;
            mm = MAX_TOKEN - nn;
            }
         else
            {
            TOKEN[9].STR[nn++] = ' ';
            mm = lsave;
            }
         (void) strncpy(&TOKEN[9].STR[nn],wbuf,mm);
         nn += mm;
         if (kk == 1) break;
         }
      }

   TOKEN[9].STR[nn] = '\0' ;
   TOKEN[9].LEN = nn;
   }

end_of_it:
if (substi > 0)			/* rebuild input line */
   {
   int  indx;

   indx = 0;
   for (nr=0; nr<count; nr++)
      {
      (void) strncpy(&LINE.STR[indx],TOKEN[nr].STR,TOKEN[nr].LEN);
      indx += TOKEN[nr].LEN;
      LINE.STR[indx++] = ' ';
      if (indx >= MAX_LINE)
         {
         ERRORS.SYS = 7;
         PREPERR("MIDAS",LINE.STR," ");
         return (-1);
         }
      }
   LINE.STR[--indx] = '\0';		/* last blank -> \0    */
   LINE.LEN = indx;
   }

return (count);
}
/*

*/

#if vms

void TTSET(flg)			/* only used in VMS */

int  flg;	/* IN: 0 = clear, 1 = set terminal, 2 = byebye */

{

if (TERM.FLAG == 1)
   {
   if (flg < 2)
      ostraw(flg);		/* clear/set terminal settings */

   else
      {
      CloseTerm();		/* reset terminal completely */
      ospwait(1);
      }
   }

}

#endif
/*

*/

void TTINIT(hdr)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
  terminal, window
.PURPOSE
  manage the windows
.ALGORITHM
  open foreground window only
.RETURNS
  nnothing
--------------------------------------------------*/

int  hdr;	/* IN: header flag = 0 (no) or = 1 (yes)  */

{

#if vms			/* --- here for VMS --- */

int  n;

/* TERM.FLAG = 0/1 for TermWindow use (only for VMS!) */

if (TERM.FLAG == 1)
   {				/* (device,termcapfile,control_chars  */
   n = OpenTerm((char *) 0,(char *) 0,TW_cc_VMS);
   if (n != OK)
      TERM.FLAG = 0;
   else
      {
      TERM.FLAG = 1;
      if (hdr == 0)
         {
         ClearScreen(); 
         CursorTo(5,0);
         }
      }
   }

#ifndef NO_READLINE

else 
   {
   (void) strncpy(history_file,FRONT.STARTUP,80);
   (void) strcat(history_file,"midtemp");
   (void) strncat(history_file,FRONT.DAZUNIT,2);
   (void) strcat(history_file,".prg");
   using_history();
   read_history(history_file);
   initialize_readline ();		/* Bind our completer */
   }

#endif		/* endif NO_READLINE */


#else			/* --- here for Unix/Linux --- */

#ifndef NO_READLINE
(void) strncpy(history_file,FRONT.STARTUP,80);
(void) strcat(history_file,"midtemp");
(void) strncat(history_file,FRONT.DAZUNIT,2);
(void) strcat(history_file,".prg");
using_history();
read_history(history_file);
initialize_readline ();              /* Bind our completer */

#endif		/* endif NO_READLINE */


#endif			/* endif vms */



if (hdr == 0)
   {
   if (FRONT.TITLE[0] == 'F')
      {
      (void) strcpy(wstr,"                   FrontEnd to MIDAS ");
      }
   else
      {
      (void) strcpy(wstr,"              ESO-MIDAS version ");
      (void) strcat(wstr,&FRONT.TITLE[1]);
      (void) strcat(wstr," on ");
      FRONT.SYSTEM[19] = '\0';
      (void) strcat(wstr,FRONT.SYSTEM);
      FRONT.SYSTEM[19] = ' ';
      }
   (void) printf("\n\n\r%s\n\r",wstr);
   }


/* get new size of terminal window */

MID_TTINFO(&TERM.COLS,&TERM.LINES);


#if vms
if (TERM.FLAG == 1)
   {
   n = TERM.LINES - 1;
   CursorTo(n,0);			/* move cursor to lower left corner */
   }
#endif

}
/*

*/

int TTEDIT(line,len)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
  terminal, window
.PURPOSE
  edit a command line
.ALGORITHM
  use FO's window interfaces
.RETURNS
status
--------------------------------------------------*/

char	*line; 		/* IN/OUT: line to be edited (terminated by \0)  */
int   len;		/* IN: max. length of 'line'  */

{
#ifndef NO_READLINE
struct sigaction act, oact;
#endif


#if vms

if (TERM.FLAG != 0)			/* we use FO's termwin stuff */
   {
   int   status, n;

   MID_TTINFO(&TERM.COLS,&TERM.LINES);	/* get new size of terminal window */
   n = TERM.LINES - 1;
   CursorTo(n,0);		/* move cursor to lower left corner */

   status = tv_kmods(TERM.EDITMODE,line,len,strlen(line));
   if (status != OK) return (-1);

   NewLine();
   return 0;
   }
#endif		/* endif vms */


/* for TERM.FLAG = 0 (as in Unix) check, if we use readline library */

#ifndef NO_READLINE

line_read = (char *)NULL;
act.sa_handler = TTPRO_alarm;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
(void) sigaction(SIGALRM,&act,&oact);

if ( sigsetjmp(env,1) == 0 ) 
   {
   re_edit(line);
   line_read = readline("");
   if (line_read && *line_read) 
      {
      (void) strcpy(line,line_read); /* before: add_history(line_read); */
      free(line_read);		/* before:                         */ 
      }
   else 
      line[0] = '\0';
   }

(void) sigaction(SIGALRM,&oact,&act);

#else

(void) printf("%s\n\r",line);

#endif


return (0);
}
/*

*/

void TTPRO(prompt,line,len)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
  terminal, window
.PURPOSE
  prompt for + get an input line from windows
.ALGORITHM
  use FO's window interfaces
.RETURNS
  Nothing
--------------------------------------------------*/

char	*prompt;	/* IN: prompt string (terminated by \0)  */
char	*line;		/* OUT: input line (terminated by \0)    */
int	len;		/* IN: length of buffer 'line'  */

{
#ifndef NO_READLINE
struct sigaction act, oact;
#endif



TERM.TIMEOUT = 0;


#if vms

if (TERM.FLAG != 0)			/* we use FO's termwin stuff */
   {
   int   n;

   NewLine();

   Put(prompt);
   n = tv_kmods(TERM.EDITMODE,line,len,0);


   /*  interrupt routine `intermail' sets TERM.TIMEOUT to 2 */

   if (TERM.TIMEOUT == 0)
      {
      if (n == EOF) (void) strcpy(line,"BYE");
      NewLine();
      }
   return;
   }

#endif          /* endif vms */


/* for TERM.FLAG = 0 (as in Unix) check, if we use readline library */

#ifndef NO_READLINE

line_read = (char *)NULL;
act.sa_handler = TTPRO_alarm;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
(void) sigaction(SIGALRM,&act,&oact);

if ( sigsetjmp(env,1) == 0 ) 
   {
   if (is_a_tty) 
      line_read = readline(prompt);
   else          
      line_read = readline("");

   if (line_read) 
      {
      if (*line_read) 
         { 
         (void) strcpy(line,line_read); /* before: add_history(line_read); */
         free(line_read);		/* before:                         */
         }
      else line[0] = '\0';
      }
   else 
      (void) strcpy(line,"bye");
   }
(void) sigaction(SIGALRM,&oact,&act);

#else

(void) printf("%s ",prompt);
(void) CGN_GETLINE(line,len);

#endif

}
