/* Program Name            : INQUIRE.C                                  */
/*   Original Author       : C. K. Hung					*/
/*   Date                  : 9-26-89					*/
/*   Program Description   :                                            */
/*                         :                                            */
/* Revision History follows                                             */
/*	(9sep89)CKH	1. delete INQUIRE()
**			2. add GET_USERINPUT_AND_EXECUTE() to replace
**			    GENERAL_DIR_MANIPULATE_ROUTINE() in MAINMENU.C and
**			    GENERAL_FILER_MAINP_ROUTINE() in FILER.C.
**	(09oct89)CKH	1. add READ_STRING_AND_CLEAR_ERRMSG
**	(17nov89)CKH	1. delete CREATE_USERINPUT_DISPLAY().
**	(12Jan91)CKH	1. Add initial value to get_userinput_and_execute and
**			    multiple_get_userinput_and_exeute
*/
 
#include "global.h"
#include "direct.h"
#include "directkpd.h"
#include "dx.h"
#include "filer.h"
#include "filerapp.h"
#include "filercpy.h"
#include "filercus.h"
#include "filerdel.h"
#include "filerdec.h"
#include "filerdif.h"
#include "filerenc.h"
#include "filerexe.h"
#include "filerflt.h"
#include "filerfnd.h"
#include "filerkpd.h"
#include "filerlau.h"
#include "fileropt.h"
#include "filerpro.h"
#include "filerprt.h"
#include "filerpur.h"
#include "filerren.h"
#include "filersrt.h"
#include "inquire.h"
#include <signal.h>
#include <trmdef.h>
 
/*
**
**  MACRO DEFINITIONS
**
**/
 
#define FIELD_LENGTH	    255
#define MAX_RECALL_LINES    20
 
/*
**
**  GLOBAL DECLARATIONS
**
**/
 
static unsigned long userinput_display_id;
static char *recall_buf[MAX_RECALL_LINES] =
    {
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
    };
enum mode_tag
    {
	replace, insert
    };
 
/*
**
**  INTERNAL FUNCTION PROTOTYPING
**
**/
    static int		    read_string_and_clear_errmsg(
				struct display_tag *,
				char *,
				char *,
				unsigned short *,
				unsigned short);
 
 
    static int		    put_chars_in_userinput(
				int *,
				int *,
				char *,
				char *,
				struct display_tag *,
				int,
				enum mode_tag,
				int *);
    static int		    inquire_alarm_working$1();
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      GET_USERINPUT_AND_EXECUTE() prompts the user for information
**	needed and call the actual function to perform desired operation.
**
**  MODIFICATION HISTORY:
**	(10oct89)CKH	1. Check field full
**
**--
**/
int	get_userinput_and_execute(
		int (*func)(),
		char *title_str,
		char *prompt_str,
		char *start_str,
		char *err_str,
		char *from)
{
    struct display_tag read_area_display;
    register int i;
    unsigned long maxlen;
    unsigned long flags;
    unsigned long status;
    long int title_start_row = 2;
    long int title_start_column;
    long int prompt_start_row = 5;
    long int prompt_start_column = 10;
    long int input_start_column;
    long int full_start_column;
    unsigned short terminator;
    long occlusion_state;
    char initial_str[MAXFILESPEC+1];
    char resultant_str[MAXFILESPEC+1];
    int resultant_length;
    char upper_str[FIELD_LENGTH+1];
    char filler[FIELD_LENGTH+1];
    $DESCRIPTOR (filler_descrip, filler);
    $DESCRIPTOR (title_descrip, title_str);
    $DESCRIPTOR (prompt_str_descrip, prompt_str);
    $DESCRIPTOR (err_str_descrip, err_str);
    static char str[128];
    $DESCRIPTOR (str_descrip, str);
    int userinput_pasteboard_row;
    int (*cstat)();
 
    check_OK(smg$create_virtual_display (
	    &USERINPUT_BOTTOM,
	    &USERINPUT_RIGHTMOST,
	    &userinput_display_id,
	    0,
	    0,
	    0))
    userinput_pasteboard_row =
	cntrl_info_block.pasteboard_rows-USERINPUT_BOTTOM+1;
    check_OK(smg$paste_virtual_display (
	    &userinput_display_id,
	    &cntrl_info_block.pasteboard_id,
	    &userinput_pasteboard_row,
	    &USERINPUT_PASTEBOARD_COLUMN,
	    0))
 
    /*
    **	    WRITE FORM TITLE
    **/
 
    LENGTH(title_descrip) = strlen(title_str);
    title_start_column = max ( 1,
			 (USERINPUT_RIGHTMOST-strlen(title_str))/2);
 
    check_OK(smg$put_chars (
	      &userinput_display_id,
	      &title_descrip,
	      &title_start_row,
	      &title_start_column,
	      0,
	      &SMG$M_BOLD,
	      0,
	      0))
 
    /*
    **	    WRITE PROMPT STRING
    **/
 
    LENGTH(prompt_str_descrip) = strlen(prompt_str);
    check_OK(smg$put_chars (
	      &userinput_display_id,
	      &prompt_str_descrip,
	      &prompt_start_row,
	      &prompt_start_column,
	      0,
	      0,
	      0,
	      0))
 
    /*
    **	CREATE USER READ AREA
    **/
 
    read_area_display.rows = 1;
    read_area_display.width = FIELD_LENGTH+1;
    read_area_display.beg_x = strlen(prompt_str)+prompt_start_column;
    read_area_display.beg_y = userinput_pasteboard_row+prompt_start_row-1;
 
    read_area_display.view_rows = 1;
    input_start_column = strlen(prompt_str)+prompt_start_column;
    read_area_display.view_width =
	USERINPUT_RIGHTMOST-input_start_column-prompt_start_column;
    read_area_display.view_beg_x = 1;
    read_area_display.view_beg_y = 1;
 
    check_OK(smg$create_virtual_display (
                 &read_area_display.rows,
                 &read_area_display.width,
                 &read_area_display.id,
                 0,
                 &SMG$M_UNDERLINE,
                 0))
    check_OK(smg$create_viewport (
                 &read_area_display.id,
                 &read_area_display.view_beg_y,
                 &read_area_display.view_beg_x,
                 &read_area_display.view_rows,
                 &read_area_display.view_width))
 
    check_OK(smg$paste_virtual_display (
                 &read_area_display.id,
                 &cntrl_info_block.pasteboard_id,
                 &read_area_display.beg_y,
                 &read_area_display.beg_x,
                 0))
 
    memset(filler, ' ', FIELD_LENGTH);
 
    LENGTH(filler_descrip) = FIELD_LENGTH;
    check_OK(smg$put_chars (
		&read_area_display.id,
		&filler_descrip,
		&1,
		&1,
		0,
		0,
		0,
		0))
 
    strcpy(str, "Enter information and press RETURN,");
    LENGTH(str_descrip) = strlen(str);
    check_OK(smg$put_chars (
	      &userinput_display_id,
	      &str_descrip,
	      &7,
	      &20,
	      0,
	      0,
	      0,
	      0))
 
    strcpy(str, "or press keypad 0 to exit");
    LENGTH(str_descrip) = strlen(str);
    check_OK(smg$put_chars (
	      &userinput_display_id,
	      &str_descrip,
	      &8,
	      &20,
	      0,
	      0,
	      0,
	      0))
 
    initial_str[0] = EOS;
    strcpy(initial_str, start_str);
    strcpy(resultant_str, "");
 
    read_string_and_clear_errmsg(
		&read_area_display,
		initial_str,
		resultant_str,
		&terminator,
		(func != filer_launch$1));
 
    strcpy(initial_str, resultant_str);
 
    while (terminator != SMG$K_TRM_KP0)
    {
        for (i = 0;  i < strlen(resultant_str);  i++)
        {
            upper_str[i] = toupper (resultant_str[i]);
        }
	upper_str[i] = EOS;
 
	/*
	**	Output 'working...' message if total processing time
	**	is longer than 3 seconds.  Needs to disable broadcast message
	**	first because of interference.
	**/
 
#ifndef DEBUG
	check_OK(smg$disable_broadcast_trapping (
		     &cntrl_info_block.pasteboard_id))
 
	cstat = signal(SIGALRM, inquire_alarm_working);
	alarm(1);
#endif
 
	status = (*func)(upper_str, from, err_str);
 
	/*
	**	Set the signal back to system default
	**/
 
#ifndef DEBUG
	alarm(0);
	signal(SIGALRM, cstat);
#endif
	check_OK(smg$erase_chars (
		     &userinput_display_id,
		     &10,
		     &USERINPUT_BOTTOM,
		     &1))
	check_OK(smg$set_broadcast_trapping (
		     &cntrl_info_block.pasteboard_id,
		     broadcast_routine,
		     0))
 
	if (status != DX__ERROR)
	{	    /**  Success.  Exit loop  **/
	    break;
	}
	else
	{
	    LENGTH(err_str_descrip) = strlen(err_str);
	    check_OK(smg$put_chars (
		      &userinput_display_id,
		      &err_str_descrip,
		      &USERINPUT_BOTTOM,
		      &1,
		      &SMG$M_ERASE_TO_EOL,
		      &SMG$M_BOLD,
		      0,
		      0))
	}
 
	check_OK(smg$check_for_occlusion (
		  &userinput_display_id,
		  &cntrl_info_block.pasteboard_id,
		  &occlusion_state))
 
	if (occlusion_state)
	{
            check_OK(smg$begin_pasteboard_update (
                         &cntrl_info_block.pasteboard_id))
	    check_OK(smg$repaste_virtual_display (
			&userinput_display_id,
			&cntrl_info_block.pasteboard_id,
			&userinput_pasteboard_row,
			&USERINPUT_PASTEBOARD_COLUMN,
			0))
            check_OK(smg$repaste_virtual_display (
                         &read_area_display.id,
			 &cntrl_info_block.pasteboard_id,
                         &read_area_display.beg_y,
                         &read_area_display.beg_x,
                         0))
            check_OK(smg$end_pasteboard_update (
                         &cntrl_info_block.pasteboard_id))
	}
 
	check_OK(smg$ring_bell (
		  &userinput_display_id,
		  &1))
 
	read_string_and_clear_errmsg(
	    &read_area_display,
	    initial_str,
	    resultant_str,
	    &terminator,
	    (func != filer_launch$1));
	strcpy(initial_str, resultant_str);
    }
 
    if (terminator == SMG$K_TRM_KP0)
    {
	if (func == dirtree_find_first$1)
	    strcpy(err_str, "FIND FIRST");
	else if (func == filer_append$1)
	    strcpy(err_str, "APPEND");
	else if (func == filer_copy$1)
	    strcpy(err_str, "COPY");
	else if (func == select_a_editor)
	    strcpy(err_str, "EDITOR SELECTION");
	else if (func == select_a_display_date)
	    strcpy(err_str, "SELECT DATE TYPE");
	else if (func == confirm_delete)
	    strcpy(err_str, "SET DELETE CONFIRMATION");
	else if (func == confirm_purge)
	    strcpy(err_str, "SET PURGE CONFIRMATION");
	else if (func == select_type_method)
	    strcpy(err_str, "SET TYPE BY PAGE");
	else if (func == auto_update)
	    strcpy(err_str, "AUTO UPDATE");
	else if (func == display_clock)
	    strcpy(err_str, "SET CLOCK");
	else if (func == update_in_second)
	    strcpy(err_str, "UPDATE CLOCK");
	else if (func == save_setting)
	    strcpy(err_str, "SAVE SETTINGS");
	else if (func == restore_setting)
	    strcpy(err_str, "RESTORE SETTINGS");
	else if (func == filer_decode$1)
	    strcpy(err_str, "UNPACK");
	else if (func == filer_delete$1)
	    strcpy(err_str, "DELETE");
	else if (func == filer_diff$1)
	    strcpy(err_str, "COMPARE");
	else if (func == filer_encode$1)
	    strcpy(err_str, "PACK");
	else if (func == vms_command)
	    strcpy(err_str, "EXECUTE VMS COMMAND");
	else if (func == filer_filter$1)
	    strcpy(err_str, "FILTER");
	else if (func == filer_find$1)
	    strcpy(err_str, "FIND");
	else if (func == filer_find_first$1)
	    strcpy(err_str, "FIND FIRST");
	else if (func == filer_launch$1)
	    strcpy(err_str, "LAUNCH");
	else if (func == print_filer_display)
	    strcpy(err_str, "PRINT DISPLAY");
	else if (func == filer_goto$1)
	    strcpy(err_str, "GOTO");
	else if (func == filer_mkdir$1)
	    strcpy(err_str, "CREATE DIRECTORY");
	else if (func == filer_protection$1)
	    strcpy(err_str, "SET PROTECTION");
	else if (func == filer_purge$1)
	    strcpy(err_str, "PURGE");
	else if (func == filer_rename$1)
	    strcpy(err_str, "RENAME");
	else if (func == filer_sort$1)
	    strcpy(err_str, "SORT");
	else
	    strcpy(err_str, "");
 
	strcat(err_str, " canceled by request");
	signal_err(err_str, silence);
    }
 
    check_OK(smg$begin_pasteboard_update (
                 &cntrl_info_block.pasteboard_id))
    check_OK(smg$delete_virtual_display (
		&userinput_display_id))
    check_OK(smg$delete_virtual_display (
                 &read_area_display.id))
    check_OK(smg$end_pasteboard_update (
                 &cntrl_info_block.pasteboard_id))
 
    return DX__DONTCARE;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      TBS
**
**--
**/
static int	read_string_and_clear_errmsg(
			struct display_tag *display,
			char *initial_str,
			char *resultant_str,
			unsigned short *terminatorp,
			unsigned short input_required)
{
    extern struct display_tag dirtree_cmds_display;
 
    int cursor_pos = 1;
    int len = 0;
    int p;
    int scroll_num;
    char char_str[2];
    enum mode_tag mode = replace;
    int err = 0;
    short int recall_line;
    int allocate_size;
    int i;
    int sav_cursor, del_chars;
    int timeout;
    unsigned long status;
    unsigned long clock_display_id;
 
    recall_line = (!strcmp(resultant_str, "")? -1 : 0);
    check_OK(smg$erase_display (
                 &display->id,
                 0,
                 0,
                 0,
                 0))
    display->view_beg_x = 1;
    check_OK(smg$change_viewport (
                 &display->id,
                 0,
                 &display->view_beg_x,
                 0,
                 0))
    check_OK(smg$begin_display_update (
                 &display->id))
    put_chars_in_userinput (&cursor_pos, &len, initial_str,
	resultant_str, display, userinput_display_id, mode, &err);
    check_OK(smg$end_display_update (
                 &display->id))
 
    check_OK(smg$set_cursor_abs (
                 &display->id,
                 0,
                 &cursor_pos))
 
    clock_display_id = dirtree_cmds_display.id != 0?
	dirtree_cmds_display.id : cntrl_info_block.commands_display.id;
 
    /*
    **	Read user input until user type RETURN to commit or
    **	keypad 0 to cancel
    **/
 
    timeout = cntrl_info_block.user_pref.update_in_second? 1 : 60;
    do {
	status = smg$read_keystroke (
			     &cntrl_info_block.keyboard_id,
			     terminatorp,
			     0,
			     &timeout,
			     &display->id,
			     0,
			     0);
	if (cntrl_info_block.user_pref.display_clock)
	    write_time(clock_display_id);
    } while (status == SS$_TIMEOUT || *terminatorp == SMG$K_TRM_CANCELLED);
 
    /**  Clear error message if any  **/
    check_OK(smg$begin_pasteboard_update (
                 &cntrl_info_block.pasteboard_id))
    check_OK(smg$erase_line (
		 &userinput_display_id,
		 &USERINPUT_BOTTOM,
		 &1))
    check_OK(smg$set_cursor_abs (
                 &display->id,
                 &1,
                 &cursor_pos))
    check_OK(smg$end_pasteboard_update (
                 &cntrl_info_block.pasteboard_id))
 
    while (*terminatorp != SMG$K_TRM_KP0)
    {
        switch (*terminatorp)
        {
            case SMG$K_TRM_LEFT:
                if (cursor_pos == 1)
                {
                    check_OK(smg$ring_bell (
                                 &display->id,
                                 0))
                    check_OK(smg$put_chars (
                                 &userinput_display_id,
                                 $DESCR ("Already at the leftmost column"),
                                 &USERINPUT_BOTTOM,
                                 &1,
				 &SMG$M_ERASE_TO_EOL,
                                 &SMG$M_BOLD,
                                 0,
                                 0))
                    check_OK(smg$set_cursor_abs (
                                 &display->id,
                                 &1,
                                 &1))
		    err++;
                }
		else
		{
		    cursor_pos--;
 
		    /*
		    **	Scroll display right if cursor falls off left margin
		    **/
 
                    if (cursor_pos < display->view_beg_x)
                    {
                        scroll_num = display->view_width/2;
			display->view_beg_x = max (
			    1, display->view_beg_x-scroll_num);
                        check_OK(smg$change_viewport (
                                     &display->id,
                                     0,
                                     &display->view_beg_x,
                                     0,
                                     0))
                    }
		    check_OK(smg$set_cursor_abs (
				 &display->id,
				 0,
				 &cursor_pos))
		}
		break;
            case SMG$K_TRM_CTRLU:
		cursor_pos--;
                check_OK(smg$delete_chars (
                             &display->id,
                             &cursor_pos,
                             &1,
                             &1))
		len -= cursor_pos;
		strncpy(resultant_str, resultant_str+cursor_pos, len);
		cursor_pos = 1;
		display->view_beg_x = 1;
		check_OK(smg$change_viewport (
			     &display->id,
			     0,
			     &display->view_beg_x,
			     0,
			     0))
		check_OK(smg$set_cursor_abs (
			     &display->id,
			     0,
			     &cursor_pos))
		break;
            case SMG$K_TRM_CTRLJ:	/**  Delete a word from left  **/
		sav_cursor = cursor_pos;
                while (cursor_pos > 1 && resultant_str[cursor_pos-2] == ' ')
                {
		    cursor_pos--;
		    len--;
                }
                while (cursor_pos > 1 && resultant_str[cursor_pos-2] != ' ')
                {
		    cursor_pos--;
		    len--;
                }
		scroll_num = display->view_width/2;
                while (cursor_pos <= display->view_beg_x &&
		    display->view_beg_x > 1)
                {
		    display->view_beg_x = max (
			1, display->view_beg_x-scroll_num);
                }
		del_chars = sav_cursor-cursor_pos;
                check_OK(smg$change_viewport (
                             &display->id,
                             0,
                             &display->view_beg_x,
                             0,
                             0))
                if (del_chars > 0)
                {
		    check_OK(smg$delete_chars (
				 &display->id,
				 &del_chars,
				 &1,
				 &cursor_pos))
		    for (p = cursor_pos-1;  p < len;  p++)
		    {
			resultant_str[p] = resultant_str[p+del_chars];
		    }
		    resultant_str[p] = EOS;
                }
                check_OK(smg$set_cursor_abs (
                             &display->id,
                             0,
                             &cursor_pos))
		break;
            case SMG$K_TRM_DELETE:
                if (cursor_pos == 1)
                {
                    check_OK(smg$ring_bell (
                                 &display->id,
                                 0))
                    check_OK(smg$put_chars (
                                 &userinput_display_id,
                                 $DESCR ("Already at the leftmost column"),
                                 &USERINPUT_BOTTOM,
                                 &1,
				 &SMG$M_ERASE_TO_EOL,
                                 &SMG$M_BOLD,
                                 0,
                                 0))
                    check_OK(smg$set_cursor_abs (
                                 &display->id,
                                 &1,
                                 &1))
		    err++;
                }
		else
		{
		    cursor_pos--;
 
		    /*
		    **	Scroll display right if cursor falls off left margin
		    **/
 
                    if (cursor_pos <= display->view_beg_x)
                    {
                        scroll_num = display->view_width/2;
			display->view_beg_x = max (
			    1, display->view_beg_x-scroll_num);
                        check_OK(smg$change_viewport (
                                     &display->id,
                                     0,
                                     &display->view_beg_x,
                                     0,
                                     0))
                    }
 
		    /*
		    **	Shift down 1 character
		    **/
 
                    check_OK(smg$begin_display_update (
                                 &display->id))
		    check_OK(smg$set_cursor_abs (
				 &display->id,
				 0,
				 &cursor_pos))
		    check_OK(smg$delete_chars (
				 &display->id,
				 &1,
				 &1,
				 &cursor_pos))
                    check_OK(smg$end_display_update (
                                 &display->id))
		    len--;
		    for (p = cursor_pos;  p <= len;  p++)
		    {
			resultant_str[p-1] = resultant_str[p];
		    }
		    resultant_str[p] = EOS;
		}
		break;
            case SMG$K_TRM_RIGHT:
                if (cursor_pos < len+1)
                {
                    cursor_pos++;
		    if (cursor_pos >= display->view_beg_x+display->view_width)
		    {
			scroll_num = min(
			    display->view_width/2,
			    FIELD_LENGTH-(display->view_beg_x+display->view_width-1));
			display->view_beg_x += scroll_num;
			check_OK(smg$change_viewport (
				     &display->id,
				     0,
				     &display->view_beg_x,
				     0,
				     0))
		    }
		    check_OK(smg$set_cursor_abs (
				 &display->id,
				 &1,
				 &cursor_pos))
                }
		break;
            case SMG$K_TRM_UP:
		check_OK(smg$erase_display (
			     &display->id,
			     0,
			     0,
			     0,
			     0))
		if (recall_buf[recall_line] != NULL)
		{
		    ++recall_line;
		    recall_line %= MAX_RECALL_LINES;
		}
 
		if (recall_buf[recall_line] == NULL)
		{
		    strcpy(resultant_str, "");
		    len = strlen(resultant_str);
		    cursor_pos = 1;
		    display->view_beg_x = 1;
		    check_OK(smg$change_viewport (
				 &display->id,
				 0,
				 &display->view_beg_x,
				 0,
				 0))
		    check_OK(smg$set_cursor_abs (
				 &display->id,
				 &1,
				 &cursor_pos))
		}
		else
		{
		    strcpy(initial_str, recall_buf[recall_line]);
		    len = 0;
		    cursor_pos = 1;
		    display->view_beg_x = 1;
		    check_OK(smg$change_viewport (
				 &display->id,
				 0,
				 &display->view_beg_x,
				 0,
				 0))
		    check_OK(smg$begin_display_update (
				 &display->id))
		    put_chars_in_userinput (&cursor_pos, &len, initial_str,
			resultant_str, display, userinput_display_id, mode, &err);
		    check_OK(smg$end_display_update (
				 &display->id))
		    check_OK(smg$set_cursor_abs (
				 &display->id,
				 &1,
				 &cursor_pos))
		}
		break;
            case SMG$K_TRM_DOWN:
		check_OK(smg$erase_display (
			     &display->id,
			     0,
			     0,
			     0,
			     0))
                if (recall_line <= 0)
                {
		    strcpy(resultant_str, "");
		    len = 0;
		    cursor_pos = 1;
		    display->view_beg_x = 1;
		    check_OK(smg$change_viewport (
				 &display->id,
				 0,
				 &display->view_beg_x,
				 0,
				 0))
		    check_OK(smg$set_cursor_abs (
				 &display->id,
				 &1,
				 &cursor_pos))
                    if (recall_line == 0)
                    {
                        recall_line--;
                    }
                }
		else
                {
		    recall_line--;
		    strcpy(initial_str, recall_buf[recall_line]);
		    len = 0;
		    cursor_pos = 1;
		    display->view_beg_x = 1;
		    check_OK(smg$change_viewport (
				 &display->id,
				 0,
				 &display->view_beg_x,
				 0,
				 0))
		    check_OK(smg$begin_display_update (
				 &display->id))
		    put_chars_in_userinput (&cursor_pos, &len, initial_str,
			resultant_str, display, userinput_display_id, mode, &err);
		    check_OK(smg$end_display_update (
				 &display->id))
		    check_OK(smg$set_cursor_abs (
				 &display->id,
				 0,
				 &cursor_pos))
		}
                break;
            case SMG$K_TRM_CTRLH:
                display->view_beg_x = 1;
                check_OK(smg$change_viewport (
                             &display->id,
                             &1,
                             &1,
                             0,
                             0))
		cursor_pos = 1;
                check_OK(smg$set_cursor_abs (
                             &display->id,
                             &1,
                             &1))
		break;
            case SMG$K_TRM_CTRLE:
                while (len+1 > display->view_beg_x+display->view_width-1)
                {
		    scroll_num = min(
			display->view_width/2,
			FIELD_LENGTH-(display->view_beg_x+display->view_width-1));
                    if (scroll_num <= 0)
                    {
                        break;
                    }
                    else
                    {
			display->view_beg_x += scroll_num;
                    }
                }
                check_OK(smg$change_viewport (
                             &display->id,
                             0,
                             &display->view_beg_x,
                             0,
                             0))
		cursor_pos = len+1;
                check_OK(smg$set_cursor_abs (
                             &display->id,
                             0,
                             &cursor_pos))
		break;
            case SMG$K_TRM_HT:
		/**  insert five spaces  **/
		put_chars_in_userinput (
		    &cursor_pos, &len, "     ", resultant_str,
		    display, userinput_display_id, insert, &err);
		break;
            case SMG$K_TRM_CTRLA:
                mode = (mode == replace)? insert : replace;
		break;
            case SMG$K_TRM_CR:
            case SMG$K_TRM_ENTER:
                if (len > 0 || !input_required)
		{
		    resultant_str[len] = EOS;
                    check_OK(smg$set_cursor_abs (
                                 &userinput_display_id,
                                 &USERINPUT_BOTTOM,
                                 &1))
                    if (recall_buf[MAX_RECALL_LINES-1] != NULL)
                    {
			allocate_size = strlen(recall_buf[MAX_RECALL_LINES-1]);
			allocate_size++;
                        check_OK(lib$free_vm (
                                     &allocate_size,
                                     &recall_buf[MAX_RECALL_LINES-1],
                                     0))
                    }
                    for (i = MAX_RECALL_LINES-1;  i > 0;  i--)
                    {
                        recall_buf[i] = recall_buf[i-1];
                    }
		    allocate_size = len+1;
                    check_OK(lib$get_vm (
                                 &allocate_size,
                                 &recall_buf[0],
                                 0))
		    memcpy(recall_buf[0], resultant_str, len+1);
		    return DX__NORMAL;
		}
		else
                {
                    check_OK(smg$ring_bell (
                                 &display->id,
                                 0))
                    check_OK(smg$put_chars (
                                 &userinput_display_id,
                                 $DESCR ("Input required"),
                                 &USERINPUT_BOTTOM,
                                 &1,
				 &SMG$M_ERASE_TO_EOL,
                                 &SMG$M_BOLD,
                                 0,
                                 0))
                    check_OK(smg$set_cursor_abs (
                                 &display->id,
                                 &1,
                                 &1))
		    err++;
                }
		break;
            default:
		char_str[0] = (char) *terminatorp;
		char_str[1] = EOS;
		put_chars_in_userinput (
		    &cursor_pos, &len, char_str, resultant_str,
		    display, userinput_display_id, mode, &err);
        }
 
	do {
	    status = smg$read_keystroke (
				 &cntrl_info_block.keyboard_id,
				 terminatorp,
				 0,
				 &timeout,
				 &display->id,
				 0,
				 0);
	    if (cntrl_info_block.user_pref.display_clock)
		write_time(clock_display_id);
	} while (status == SS$_TIMEOUT || *terminatorp == SMG$K_TRM_CANCELLED);
 
        if (err)
        {
	    err = 0;
	    check_OK(smg$begin_pasteboard_update (
			 &cntrl_info_block.pasteboard_id))
	    check_OK(smg$erase_line (
			 &userinput_display_id,
			 &USERINPUT_BOTTOM,
			 &1))
	    check_OK(smg$set_cursor_abs (
			 &display->id,
			 &1,
			 &cursor_pos))
	    check_OK(smg$end_pasteboard_update (
			 &cntrl_info_block.pasteboard_id))
        }
    }
    return DX__DONTCARE;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      TBS
**
**--
**/
static int	put_chars_in_userinput (cursor_pos, len, input_str,
			resultant_str, display, userinput_display_id, mode, err)
int *cursor_pos,
    *len;
char *input_str;
char *resultant_str;
struct display_tag *display;
int userinput_display_id;
enum mode_tag mode;
int *err;
{
    int scroll_num;
    char char_str[1];
    $DESCRIPTOR (char_str_descrip, char_str);
    int i, j;
 
    /*
    **	Echo the user input on to the screen.
    **	Stop when the field is full.
    **/
 
    LENGTH(char_str_descrip) = 1;
    for (i = 0;  i < strlen(input_str);  i++)
    {
	if (isprint (input_str[i]))
	{
	    char_str[0] =  input_str[i];
	    if (mode == replace && *cursor_pos <= *len)
	    {
		check_OK(smg$put_chars (
			     &display->id,
			     &char_str_descrip,
			     0,
			     0,
			     0,
			     0,
			     0,
			     0))
		 resultant_str[*cursor_pos-1] = input_str[i];
		(*cursor_pos)++;
	    }
	    else if (*len >= FIELD_LENGTH)
	    {
		check_OK(smg$ring_bell (
			     &display->id,
			     0))
		check_OK(smg$put_chars (
			     &userinput_display_id,
			     $DESCR ("Field full"),
			     &USERINPUT_BOTTOM,
			     &1,
			     &SMG$M_ERASE_TO_EOL,
			     &SMG$M_BOLD,
			     0,
			     0))
		check_OK(smg$set_cursor_abs (
			     &display->id,
			     &1,
			     cursor_pos))
 
		(*err)++;
		return DX__DONTCARE;
	    }
	    else
	    {
		check_OK(smg$insert_chars (
			     &display->id,
			     &char_str_descrip,
			     &1,
			     cursor_pos,
			     0,
			     0,
			     0))
		 /**  Shift right 1 character  **/
		 for (j = *len;  j >= *cursor_pos;  j--)
		 {
		     resultant_str[j] = resultant_str[j-1];
		 }
		 resultant_str[*cursor_pos-1] = input_str[i];
		 (*cursor_pos)++;
		 (*len)++;
	    }
	    if (*cursor_pos >= display->view_beg_x+display->view_width)
	    {
		scroll_num = min(
		    display->view_width/2,
		    FIELD_LENGTH-(display->view_beg_x+display->view_width-1));
		display->view_beg_x += scroll_num;
		check_OK(smg$change_viewport (
			     &display->id,
			     0,
			     &display->view_beg_x,
			     0,
			     0))
                check_OK(smg$set_cursor_abs (
                             &display->id,
                             &1,
                             cursor_pos))
	    }
	}
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      TBS
**
**--
**/
int	signal_err(err_str, ring)
char *err_str;
enum rings ring;
{
    unsigned long status_flags;
    char msg[256];
    $DESCRIPTOR (msg_descrip, msg);
 
    check_OK(smg$erase_display (
	      &cntrl_info_block.status_display.id,
	      0,
	      0,
	      0,
	      0))
 
    /*
    **  Repaste the display if it has not been pasted already (not
    **	a normal case.)  Otherwise, just paste the display.
    **/
 
    check_OK(smg$get_pasting_info (
	      &cntrl_info_block.status_display.id,
	      &cntrl_info_block.pasteboard_id,
	      &status_flags,
	      0,
	      0))
 
    if (status_flags == SMG$M_DISPLAY_PASTED)
 
	check_OK(smg$repaste_virtual_display (
		  &cntrl_info_block.status_display.id,
		  &cntrl_info_block.pasteboard_id,
		  &STATUS_PBD_ROW,
		  &STATUS_PBD_COLUMN,
		  0))
 
    else
 
	check_OK(smg$paste_virtual_display (
		&cntrl_info_block.status_display.id,
		&cntrl_info_block.pasteboard_id,
		&STATUS_PBD_ROW,
		&STATUS_PBD_COLUMN,
		0))
 
    if (ring == bell)	    /**  Ring a bell if error occurred  **/
 
	check_OK(smg$ring_bell (
		  &cntrl_info_block.status_display.id,
		  &1))
 
    /*
    **  Write a error message at the specific location
    **/
 
    strcpy(msg, err_str);
    LENGTH(msg_descrip) = strlen(msg);
    check_OK(smg$put_chars (
	     &cntrl_info_block.status_display.id,
	     &msg_descrip,
	     &1,
	     &1,
	     &SMG$M_ERASE_TO_EOL,
	     &SMG$M_BOLD,
	     0,
	     0))
	return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      MULTI_GET_USERINPUT_AND_EXEC() prompts the user for information
**	needed and call the actual function to perform desired operation.
**
**  MODIFICATION HISTORY:
**
**--
**/
int	multi_get_userinput_and_exec(
	    func,
	    title_str,
	    prompt_str,
	    start_str,
	    err_str)
int (*func)();
char *title_str;
char *prompt_str;
char *start_str;
char *err_str;
{
    struct display_tag read_area_display;
    register int i;
    unsigned long maxlen;
    unsigned long flags;
    long int title_start_row = 2;
    long int title_start_column;
    long int prompt_start_row = 5;
    long int prompt_start_column = 10;
    long int input_start_column;
    long int lastrow;
    unsigned short terminator;
    char initial_str[FIELD_LENGTH+1];
    char resultant_str[FIELD_LENGTH+1];
    char upper_str[FIELD_LENGTH+1];
    char filler[FIELD_LENGTH+1];
    $DESCRIPTOR (filler_descrip, filler);
    $DESCRIPTOR (title_descrip, title_str);
    $DESCRIPTOR (prompt_str_descrip, prompt_str);
    $DESCRIPTOR (err_str_descrip, err_str);
    static char str[128];
    $DESCRIPTOR (str_descrip, str);
    int userinput_pasteboard_row =
	cntrl_info_block.pasteboard_rows-USERINPUT_BOTTOM+1;
 
    check_OK(smg$create_virtual_display (
	    &USERINPUT_BOTTOM,
	    &USERINPUT_RIGHTMOST,
	    &userinput_display_id,
	    0,
	    0,
	    0))
 
    check_OK(smg$paste_virtual_display (
	    &userinput_display_id,
	    &cntrl_info_block.pasteboard_id,
	    &userinput_pasteboard_row,
	    &USERINPUT_PASTEBOARD_COLUMN,
	    0))
 
    LENGTH(title_descrip) = strlen(title_str);
    title_start_column = max ( 1,
			 (USERINPUT_RIGHTMOST-strlen(title_str))/2);
 
    check_OK(smg$put_chars (
	      &userinput_display_id,
	      &title_descrip,
	      &title_start_row,
	      &title_start_column,
	      0,
	      &SMG$M_BOLD,
	      0,
	      0))
 
    LENGTH(prompt_str_descrip) = strlen(prompt_str);
    check_OK(smg$put_chars (
	      &userinput_display_id,
	      &prompt_str_descrip,
	      &prompt_start_row,
	      &prompt_start_column,
	      0,
	      0,
	      0,
	      0))
 
    /*
    **	CREATE USER READ AREA
    **/
 
    read_area_display.rows = 1;
    read_area_display.width = FIELD_LENGTH+1;
    read_area_display.beg_x = strlen(prompt_str)+prompt_start_column;
    read_area_display.beg_y = userinput_pasteboard_row+prompt_start_row-1;
 
    read_area_display.view_rows = 1;
    input_start_column = strlen(prompt_str)+prompt_start_column;
    read_area_display.view_width =
	USERINPUT_RIGHTMOST-input_start_column-prompt_start_column;
    read_area_display.view_beg_x = 1;
    read_area_display.view_beg_y = 1;
 
    check_OK(smg$create_virtual_display (
                 &read_area_display.rows,
                 &read_area_display.width,
                 &read_area_display.id,
                 0,
                 &SMG$M_UNDERLINE,
                 0))
    check_OK(smg$create_viewport (
                 &read_area_display.id,
                 &read_area_display.view_beg_y,
                 &read_area_display.view_beg_x,
                 &read_area_display.view_rows,
                 &read_area_display.view_width))
 
    check_OK(smg$paste_virtual_display (
                 &read_area_display.id,
                 &cntrl_info_block.pasteboard_id,
                 &read_area_display.beg_y,
                 &read_area_display.beg_x,
                 0))
 
    memset(filler, ' ', FIELD_LENGTH);
 
    LENGTH(filler_descrip) = FIELD_LENGTH;
    check_OK(smg$put_chars (
		&read_area_display.id,
		&filler_descrip,
		&1,
		&1,
		0,
		0,
		0,
		0))
    check_OK(smg$erase_display (
                 &read_area_display.id,
                 0,
                 0,
                 0,
                 0))
 
    strcpy(str, "Enter information and press RETURN, ");
    LENGTH(str_descrip) = strlen(str);
    check_OK(smg$put_chars (
	      &userinput_display_id,
	      &str_descrip,
	      &7,
	      &20,
	      0,
	      0,
	      0,
	      0))
 
 
    strcpy(str, "or press keypad 0 to exit");
    LENGTH(str_descrip) = strlen(str);
    check_OK(smg$put_chars (
	      &userinput_display_id,
	      &str_descrip,
	      &8,
	      &20,
	      0,
	      0,
	      0,
	      0))
 
    strcpy(initial_str, start_str);
 
    read_string_and_clear_errmsg(
		&read_area_display,
		initial_str,
		resultant_str,
		&terminator,
		(func != filer_launch$1));
 
    check_OK(smg$begin_pasteboard_update (
                 &cntrl_info_block.pasteboard_id))
    check_OK(smg$delete_virtual_display (
		&userinput_display_id))
    check_OK(smg$delete_virtual_display (
                 &read_area_display.id))
    check_OK(smg$end_pasteboard_update (
                 &cntrl_info_block.pasteboard_id))
 
    if (terminator != SMG$K_TRM_KP0)
    {
	lastrow = userinput_pasteboard_row+USERINPUT_BOTTOM-1;
 
	check_OK(smg$set_physical_cursor (
		  &cntrl_info_block.pasteboard_id,
		  &lastrow,
		  &USERINPUT_PASTEBOARD_COLUMN))
 
        for (i = 0;  i < strlen(resultant_str);  i++)
        {
            upper_str[i] = toupper (resultant_str[i]);
        }
	upper_str[i] = EOS;
 
	return filer_multiple(func, upper_str, err_str);
    }
 
    if (func == filer_copy$1)
	strcpy(err_str, "MULTIPLE COPY");
    else if (func == filer_find$1)
	strcpy(err_str, "MULTIPLE FIND");
    else if (func == filer_rename$1)
	strcpy(err_str, "MULTIPLE RENAME");
    else if (func == filer_protection$1)
	strcpy(err_str, "MULTIPLE SET PROTECTION");
    else if (func == filer_delete$1)
	strcpy(err_str, "MULTIPLE DELETE");
    else if (func == filer_purge$1)
	strcpy(err_str, "MULTIPLE PURGE");
    else if (func == filer_launch$1)
	strcpy(err_str, "MULTIPLE LAUNCH");
    else if (func == filer_diff$1)
	strcpy(err_str, "MULTIPLE COMPARE");
    else if (func == filer_encode$1)
	strcpy(err_str, "MULTIPLE PACK");
    else if (func == filer_decode$1)
	strcpy(err_str, "MULTIPLE UNPACK");
    else
	strcpy(err_str, "");
 
    strcat(err_str, " canceled by request");
    signal_err(err_str, silence);
 
    return 0;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	    inquire_alarm_working()
{
    extern struct display_tag dirtree_cmds_display;
    static int remain_alarm = 2;
 
    unsigned long clock_display_id;
 
    clock_display_id = dirtree_cmds_display.id != 0?
	dirtree_cmds_display.id : cntrl_info_block.commands_display.id;
 
    if (cntrl_info_block.user_pref.display_clock &&
	cntrl_info_block.user_pref.update_in_second)
    {
	write_time(clock_display_id);
    }
 
    remain_alarm--;
    if (remain_alarm > 0)
    {
	signal(SIGALRM, inquire_alarm_working);
    }
    else
    {
	remain_alarm = 2;
	signal(SIGALRM, inquire_alarm_working$1);
    }
 
    alarm(1);
    return DX__NORMAL;
}
 
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
static int	    inquire_alarm_working$1()
{
    extern struct display_tag dirtree_cmds_display;
 
    static int switch_on = 0;
    static int remain_timeout = 60;
 
    unsigned long clock_display_id;
 
    if (!switch_on)
    {
        switch_on++;
	smg$put_chars (
	     &userinput_display_id,
	     $DESCR ("Working..."),
	     &USERINPUT_BOTTOM,
	     &1,
	     &SMG$M_ERASE_TO_EOL,
	     0,
	     0,
	     0);
    }
    else
    {
        switch_on = 0;
	smg$erase_line (
	     &userinput_display_id,
	     &USERINPUT_BOTTOM,
	     &1);
    }
 
    if (cntrl_info_block.user_pref.display_clock)
    {
	clock_display_id = dirtree_cmds_display.id != 0?
	    dirtree_cmds_display.id : cntrl_info_block.commands_display.id;
 
	if (cntrl_info_block.user_pref.update_in_second)
	{
	    write_time(clock_display_id);
	}
	else
	{
	    remain_timeout--;
	    if (remain_timeout == 0)
	    {
	    	 write_time(clock_display_id);
		 remain_timeout = 60;
	    }
	}
    }
 
    signal(SIGALRM, inquire_alarm_working$1);
    alarm(1);
    return DX__NORMAL;
}
