/* Program Name            : FILEROPT.C                                 */
/*   Original Author       : C. K. Hung					*/
/*   Date                  : 3-AUG-1990					*/
/*   Program Description   :                                            */
/*                         :                                            */
/* Revision History follows                                             */
 
 
#include "global.h"
#include "dx.h"
#include "filer.h"
#include "filerkpd.h"
#include "fileropt.h"
#include "filerque.h"
#include "findfile.h"
#include "inquire.h"
#include <fibdef.h>
#include <iodef.h>
#include <signal.h>
#include <stat.h>
 
/*
**  INTERNAL FUNCTION PROTOTYPE
**/
 
static int	filer_toggle_form(void);
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_update()
{
    char errmsg[MAXFILESPEC+1];
 
    /*
    **	Output 'working...' message if total processing time
    **	is longer than 3 seconds.  Needs to disable broadcast message
    **	first because of interference.
    **/
 
    check_OK(smg$disable_broadcast_trapping (
                 &cntrl_info_block.pasteboard_id))
 
    signal(SIGALRM, filter_alarm_working);
    alarm(1);
 
    /*
    **	Re-read this directory
    **/
 
    filer_filter$1("", "Update", errmsg);
 
    /*
    **	Set the signal back to system default
    **/
 
    alarm(0);
    signal(SIGALRM, SIG_DFL);
    check_OK(smg$erase_chars (
    		 &cntrl_info_block.commands_display.id,
    		 &10,
    		 &2,
    		 &1))
 
    check_OK(smg$set_broadcast_trapping (
                 &cntrl_info_block.pasteboard_id,
                 broadcast_routine,
                 0))
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      FILER_HELP() outputs the help messages for FILER
**
**--
**/
int	filer_help(topic)
char *topic;
{
    unsigned int internal_display_id;
    $DESCRIPTOR(key, topic);
    char libnam[80];
    $DESCRIPTOR(lib, libnam);
    FILE *fp;
 
    /* Check if logical name "DX$HELPLIB" point to a .HLB file	*/
    sprintf (libnam, "%s",DX$HELPLIB);
    if ((fp = fopen (libnam, "r")) != NULL){
	fclose(fp);
    } else {
	/* Check if in DXHELP.HLB is in HELPLIB (DX$HOME)	*/
	sprintf (libnam, "%s%s", HELPLIB, "DXHELP.HLB");
	if ((fp = fopen (libnam, "r")) != NULL){
		fclose (fp);
 
	/* Check if in SYS$HELP					*/
	} else if ((fp = fopen ("SYS$HELP:DXHELP.HLB", "r")) != NULL) {
		fclose (fp);
		strcpy (libnam, "SYS$HELP:DXHELP.HLB");
 
	/* Damned you ! You did not install the help file	*/
	} else {
		signal_err ("Help library not found", bell);
		return DX__ERROR;
	}
    }
 
    /**  .HLB exist.  Output the help messages  **/
    check_OK(smg$save_physical_screen (
	    &cntrl_info_block.pasteboard_id,
	    &internal_display_id,
	    0,
	    0))
 
    check_OK(smg$set_physical_cursor (
	      &cntrl_info_block.pasteboard_id,
	      &1,
	      &1))
 
    LENGTH(key) = strlen(topic);
    LENGTH(lib) = strlen(libnam);
    lbr$output_help(
	&lib$put_output,
	0,
	&key,
	&lib,
	0,
	&lib$get_input);
 
    check_OK(smg$restore_physical_screen (
	    &cntrl_info_block.pasteboard_id,
	    &internal_display_id))
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      FILER_WRITE() calls PRINT_FILER_DISPLAY() to save
**	all the file characteristics in the current directory to a file
**
**--
**/
int	filer_write()
{
    char errmsg[MAXFILESPEC+1];
 
    strcpy(errmsg, "Error writing to file");
    get_userinput_and_execute(
	print_filer_display,
	"Write File Characteristics",
	"File Name: ",
	"",
	errmsg,
	"dummy");
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      PRINT_FILER_DISPLAY() outputs the contents of FILER
**	virtual display to a hardcopy.
**
**--
**/
int	print_filer_display(filespec, dummy, errmsg)
char *filespec;
char *dummy;
char *errmsg;
{
    register k;
    int i;
    FILE *dxf;
    char cwd_line[MAXFILESPEC+1];
    char display_line[MAXFILESPEC+1];
    $DESCRIPTOR(display_line_descriptor, display_line);
    char total_str[MAXFILESPEC+1], select_str[MAXFILESPEC+1];
    int spaces;
    char filler[MAXFILESPEC+1];
    char msg[MAXFILESPEC+1];
    struct fil_dx_tag temp_entry;
 
    if ((dxf = fopen(filespec, "w")) == (FILE *)NULL) {
	sprintf(errmsg, "Error opening %s as output", filespec);
	return DX__ERROR;
    }
 
    /**  Write directory name  **/
    fprintf(dxf, "Directory: %s\n\n", DX_CURRENT_DIRECTORY.cur_dir);
 
    for (i = 1; i <= DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_y; i++) {
	    check_OK(smg$read_from_display (
		    &DX_CURRENT_DIRECTORY.filer_display.id,
		    &display_line_descriptor,
		    0,
		    &i))
	    for (k = cntrl_info_block.pasteboard_width; k >= 0; k--)
		    if (isprint(display_line[k]) && !isspace(display_line[k])) {
			display_line[k+1] = '\n';
			break;
		    } else
			display_line[k] = EOS;
	    fprintf(dxf, "%s", display_line);
    }
 
    /**  Write directory statistics  **/
    sprintf(total_str, " (Total: %ldf/%ldb)",
	DX_CURRENT_DIRECTORY.tot_files, DX_CURRENT_DIRECTORY.tot_blocks);
    sprintf(select_str, "(Selections: %ldf/%ldb) ",
	DX_CURRENT_DIRECTORY.sel_files, DX_CURRENT_DIRECTORY.sel_blocks);
    spaces = cntrl_info_block.pasteboard_width - (strlen(total_str)+strlen(select_str));
 
    if (spaces <= 0)
 
	fprintf(dxf, "\n\n%s%s", total_str, select_str);
 
    else {
 
	    memset(filler, ' ', spaces);
	    filler[spaces] = EOS;
 
	    fprintf(dxf, "\n\n%s%s%s", total_str, filler, select_str);
 
    }
 
    if (fclose(dxf) == EOF) {
	sprintf(errmsg, "Error closing %s", filespec);
	return DX__ERROR;
    }
 
    /*****  Add this file to this display  *****/
 
    sprintf(msg, "%d lines written to file %s",
	DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_y+4, filespec);
    signal_err(msg, silence);
 
    /*
    **	Update the filer list and display
    **/
 
    strcpy(errmsg, "Screen not updated");
    if (filestat(filespec, &temp_entry, errmsg) == DX__ERROR)
    {
        return DX__ERROR;
    }
 
    temp_entry.state = waiting;
    temp_entry.beg_y = temp_entry.beg_x = 0;
    temp_entry.forward = temp_entry.backward = NULL;
 
    /*
    **  Update cache queue.
    **	In case of running out of memory, output error message
    **	but update current display(s) anyway.
    **/
 
    if (update_filer_cache(temp_entry, add_to_filer_cache, errmsg) == DX__ERROR)
    {
        signal_err(errmsg, bell);
    }
 
    /**  Add it to the FILER  **/
    if (add_to_filer(temp_entry, errmsg, cntrl_info_block.cur_win) == DX__ERROR)
    {
        return DX__ERROR;
    }
 
    /**  Update other windows  **/
    for (i = 0;  i < cntrl_info_block.windows;  i++)
    {
        if (i != cntrl_info_block.cur_win)
        {
            if (add_to_filer(temp_entry, errmsg, i) == DX__ERROR)
            {
                 return DX__ERROR;
            }
        }
    }
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_goto()
{
    char errmsg[MAXFILESPEC+1];
 
    strcpy(errmsg, "Error setting cursor to new position");
    get_userinput_and_execute(
	filer_goto$1,
	"Goto Page",
	"Page Number: ",
	"",
	errmsg,
	"dummy");
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_goto$1(page_str, dummy, errmsg)
char *page_str;
char *dummy;
char *errmsg;
{
    register int i;
    struct fil_dx_tag *p;
    int disp;
    int page_no;
    int new_viewport_row;
    int number_of_scroll;
 
    page_no = atoi(page_str);
    disp = 1 + abs(DX_CURRENT_DIRECTORY.filer_display.view_rows*(page_no-1));
 
    unhighlight_filer_current_file();
 
    for (p = DX_CURRENT_DIRECTORY.dir_filelist->forward;
	p != DX_CURRENT_DIRECTORY.non_dir_filelist;  p = p->forward)
    {
        if (disp <= p->beg_y)
        {
            break;
        }
	else if (p->forward == DX_CURRENT_DIRECTORY.dir_filelist)
	{
	    if (DX_CURRENT_DIRECTORY.non_dir_filelist ==
		    DX_CURRENT_DIRECTORY.non_dir_filelist->forward &&
		p != DX_CURRENT_DIRECTORY.dir_filelist)
	    {
		break;
	    }
	    else
	    {
		p = DX_CURRENT_DIRECTORY.non_dir_filelist->forward;
	    }
	}
    }
 
    DX_CURRENT_FILE = (p == DX_CURRENT_DIRECTORY.non_dir_filelist?
	DX_CURRENT_DIRECTORY.non_dir_filelist->backward : p);
 
    change_filer_viewport(cntrl_info_block.cur_win);
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_mark_all()
{
    struct fil_dx_tag *p;
    struct fil_dx_tag *MARKER;
 
    check_OK(smg$begin_pasteboard_update (
	      &cntrl_info_block.pasteboard_id))
 
    MARKER = DX_CURRENT_DIRECTORY.dir_filelist;
    for (p = MARKER->forward; p != MARKER; p = p->forward)
    {
	filer_mark(p, 1);
    }
 
    MARKER = DX_CURRENT_DIRECTORY.non_dir_filelist;
    for (p = MARKER->forward; p != MARKER; p = p->forward)
    {
	filer_mark(p, 1);
    }
 
    check_OK(smg$set_cursor_abs (
	      &DX_CURRENT_DIRECTORY.filer_display.id,
	      &DX_CURRENT_FILE->beg_y,
	      &DX_CURRENT_FILE->beg_x))
 
    check_OK(smg$end_pasteboard_update (
	      &cntrl_info_block.pasteboard_id))
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_unmark_all()
{
    struct fil_dx_tag *p;
    struct fil_dx_tag *MARKER;
 
    check_OK(smg$begin_pasteboard_update (
	      &cntrl_info_block.pasteboard_id))
 
    MARKER = DX_CURRENT_DIRECTORY.dir_filelist;
    for (p = MARKER->forward; p != MARKER; p = p->forward)
    {
	filer_unmark(p, 1);
    }
 
    MARKER = DX_CURRENT_DIRECTORY.non_dir_filelist;
    for (p = MARKER->forward; p != MARKER; p = p->forward)
    {
	filer_unmark(p, 1);
    }
 
    check_OK(smg$set_cursor_abs (
	      &DX_CURRENT_DIRECTORY.filer_display.id,
	      &DX_CURRENT_FILE->beg_y,
	      &DX_CURRENT_FILE->beg_x))
 
    check_OK(smg$end_pasteboard_update (
	      &cntrl_info_block.pasteboard_id))
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_remark_all()
{
    struct fil_dx_tag *p;
    struct fil_dx_tag *MARKER;
 
    check_OK(smg$begin_pasteboard_update (
	      &cntrl_info_block.pasteboard_id))
 
    MARKER = DX_CURRENT_DIRECTORY.dir_filelist;
    for (p = MARKER->forward; p != MARKER; p = p->forward)
	if (p->state == executed)
	{
	    filer_mark(p, 1);
	}
 
    MARKER = DX_CURRENT_DIRECTORY.non_dir_filelist;
    for (p = MARKER->forward; p != MARKER; p = p->forward)
	if (p->state == executed)
	{
	    filer_mark(p, 1);
	}
 
    check_OK(smg$set_cursor_abs (
	      &DX_CURRENT_DIRECTORY.filer_display.id,
	      &DX_CURRENT_FILE->beg_y,
	      &DX_CURRENT_FILE->beg_x))
 
    check_OK(smg$end_pasteboard_update (
	      &cntrl_info_block.pasteboard_id))
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**	tbs
**
**--
**/
int	filer_short_form()
{
    DX_CURRENT_DIRECTORY.form = short_form;
    filer_toggle_form();
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**	tbs
**
**--
**/
int	filer_long_form()
{
    DX_CURRENT_DIRECTORY.form = long_form;
    filer_toggle_form();
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**	tbs
**
**--
**/
static int	filer_toggle_form()
{
    int row, col;
    int sav_row;
    int prev_disp_rows;
 
    sav_row = DX_CURRENT_FILE->beg_y -
	DX_CURRENT_DIRECTORY.filer_display.view_beg_y;
    prev_disp_rows = DX_CURRENT_DIRECTORY.filer_display.rows;
 
    check_OK(smg$unpaste_virtual_display (
	     	  &DX_CURRENT_DIRECTORY.filer_display.id,
	     	  &cntrl_info_block.pasteboard_id))
    check_OK(smg$erase_display (
	     	  &DX_CURRENT_DIRECTORY.filer_display.id,
	     	  0,
	     	  0,
	     	  0,
	     	  0))
 
    /*
    **	Compute the position of each file
    **/
 
    DX_CURRENT_DIRECTORY.dir_filelist->beg_y =
	DX_CURRENT_DIRECTORY.dir_filelist->beg_x = 1;
    row = col = 1;
    compute_filer_begin_xy (
	DX_CURRENT_DIRECTORY.dir_filelist, &row, &col, cntrl_info_block.cur_win);
    DX_CURRENT_DIRECTORY.non_dir_filelist->beg_y =
	DX_CURRENT_DIRECTORY.dir_filelist->backward->beg_y;
    DX_CURRENT_DIRECTORY.non_dir_filelist->beg_x =
	DX_CURRENT_DIRECTORY.dir_filelist->backward->beg_x;
    compute_filer_begin_xy (
	DX_CURRENT_DIRECTORY.non_dir_filelist, &row, &col, cntrl_info_block.cur_win);
 
    DX_CURRENT_DIRECTORY.filer_display.rows =
	max (DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_y,
	     DX_CURRENT_DIRECTORY.filer_display.view_rows);
    DX_CURRENT_DIRECTORY.filer_display.width =
	cntrl_info_block.pasteboard_width;
    if (prev_disp_rows < DX_CURRENT_DIRECTORY.filer_display.rows)
    {
	check_OK(smg$change_virtual_display (
		     &DX_CURRENT_DIRECTORY.filer_display.id,
		     &DX_CURRENT_DIRECTORY.filer_display.rows,
		     0,
		     0,
		     0,
		     0))
    }
 
    /*
    **  Write all the files to screen
    **/
 
    write_to_filer(
	cntrl_info_block.dir_dx[cntrl_info_block.cur_win].dir_filelist);
    write_to_filer(
	cntrl_info_block.dir_dx[cntrl_info_block.cur_win].non_dir_filelist);
 
    if (prev_disp_rows > DX_CURRENT_DIRECTORY.filer_display.rows)
    {
	check_OK(smg$change_virtual_display (
		     &DX_CURRENT_DIRECTORY.filer_display.id,
		     &DX_CURRENT_DIRECTORY.filer_display.rows,
		     0,
		     0,
		     0,
		     0))
    }
 
    change_filer_viewport(cntrl_info_block.cur_win);
 
    highlight_filer_current_file();
 
    check_OK(smg$paste_virtual_display (
	     	  &DX_CURRENT_DIRECTORY.filer_display.id,
	     	  &cntrl_info_block.pasteboard_id,
	     	  &DX_CURRENT_DIRECTORY.filer_display.beg_y,
	     	  &DX_CURRENT_DIRECTORY.filer_display.beg_x,
	     	  0))
    return DX__NORMAL;
}
 
 

/*
**++
**
**  GET_QUOTA uses ACP services to examine a user's permanent
**  disk quota.  Read access to [0,0]QUOTA.SYS;1 is required
**  to examine all non-user entries.  Current version of DX
**  does not call this function, it is put here for possible
**  future use.
**
**--
**/
long	    get_quota(uic)
unsigned long uic;
{
    int iosb[2];
 
    static struct fibdef1 fib;
    $DESCRIPTOR (fib_descriptor, (char *)& fib);
 
    struct dqfs
	{
	    long int dqf$l_flags;
	    long int dqf$w_uic;
	    long int dqf$l_usage;
	    long int dqf$l_permquota;
	    long int dqf$l_overdraft;
	    long filler[3];
	} from_dqf, to_dqf;
 
    $DESCRIPTOR (from_dqf_descriptor, (char *)&from_dqf);
    $DESCRIPTOR (to_dqf_descriptor, (char *)&to_dqf);
 
    int len;
 
    from_dqf.dqf$w_uic = uic;
 
    LENGTH(from_dqf_descriptor) = sizeof (struct dqfs);
    LENGTH(to_dqf_descriptor) = sizeof (struct dqfs);
 
    LENGTH(fib_descriptor) = sizeof (struct fibdef1);
    fib.fib$w_cntrlfunc = FIB$C_EXA_QUOTA;
 
    check_OK(sys$qiow (
		0,
		DX_CURRENT_DIRECTORY.cur_filter.name_filespec_list->w_dids->chan,
		IO$_ACPCONTROL,
		iosb,
		0,
		0,
		&fib_descriptor,
		&from_dqf_descriptor,
		&len,
		&to_dqf_descriptor,
		0,
		0))
 
    return to_dqf.dqf$l_permquota;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	    filer_about()
{
    signal_err(DXVERSION, silence);
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	    filer_mkdir()
{
    char errmsg[MAXFILESPEC+1];
 
    strcpy(errmsg, "Error creating a directory");
    get_userinput_and_execute(
	filer_mkdir$1,
	"Create Directory",
	"Directory Name: ",
	"",
	errmsg,
	"dummy");
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	    filer_mkdir$1(newdir, dummy, errmsg)
char *newdir,
     *dummy,
     *errmsg;
{
    $DESCRIPTOR (newdir_descrip, newdir);
    unsigned short int len;
    char filespec[MAXFILESPEC+1];
    char *indx;
    char name[MAXFILESPEC+1];
    struct fil_dx_tag temp_entry;
    struct NAM nam;
    struct FAB fab;
    struct XABPRO xabpro;
    struct XABDAT xabdat;
    int i;
    char resultant_name[NAM$C_MAXRSS];
    unsigned long int status;
 
    LENGTH(newdir_descrip) = strlen(newdir);
 
    if (!(status = (lib$create_dir (
			&newdir_descrip,
			0,
			0,
			0,
			0,
			0)) & 1))
    {
	return DX__ERROR;
    }
 
    /*
    **	Convert directory spec to file spec
    **/
 
    strcpy(filespec, newdir);
    if ((indx = strrchr(filespec, '.')) == NULL)
	if ((indx = strchr(filespec, '[')) == NULL)
	    return -1;
 
    /*
    **	Get parent directory name
    **/
    indx++;
    strcpy(name, indx);
    if ((indx = strchr(name, ']')) == NULL)
	return -1;
    *indx = EOS;
 
    if (strcmp(name, "000000")) {
 
	/*
	**  Not a system master directory
	**/
	indx = strchr(filespec, ']');
	*indx++ = '.';
	*indx++ = '-';
	*indx++ = ']';
	*indx = EOS;
    }
 
    strcat(filespec, name);
    strcat(filespec, ".DIR;1");
 
    /*
    **	Get directory file attributes
    **/
 
    if (filestat(filespec, &temp_entry, errmsg) == DX__ERROR)
    {
	strcpy(errmsg, "Error getting directory attributes");
        return DX__ERROR;
    }
 
    temp_entry.state = waiting;
    temp_entry.beg_y = temp_entry.beg_x = 0;
    temp_entry.forward = temp_entry.backward = NULL;
 
    /*
    **  Update cache queue.
    **	In case of running out of memory, output error message
    **	but update current display(s) anyway.
    **/
 
    if (update_filer_cache(temp_entry, add_to_filer_cache, errmsg) == DX__ERROR)
    {
        signal_err(errmsg, bell);
    }
 
    /*
    **	Update direct queue
    **/
 
    /**  Init RMS$ data structures  **/
 
    fab = cc$rms_fab;
    nam = cc$rms_nam;
    xabpro = cc$rms_xabpro;
    xabdat = cc$rms_xabdat;
 
    /*
    **	use RMS service to get the full file spec and
    **	characteristics.  Default directory is cwd.
    **
    **/
 
    fab.fab$l_fna = filespec;
    fab.fab$b_fns = strlen(fab.fab$l_fna);
    fab.fab$l_nam = &nam;
    fab.fab$l_xab = &xabpro;
    xabpro.xab$l_nxt = &xabdat;
 
    nam.nam$l_rsa = &resultant_name;
    nam.nam$b_rss = sizeof resultant_name;
 
    if ((status = sys$open (
			&fab,
			0,
			0)) == RMS$_NORMAL)
    {
	resultant_name[nam.nam$b_rsl] = EOS;
	indx = strchr(resultant_name, ']');
	*indx = '.';
	indx = strrchr(resultant_name, '.');
	*indx = ']';
	*++indx = EOS;	    /**  Convert filespec to dirspec  **/
 
	status = sys$close(
		    &fab,
		    0,
		    0);
 
	if (add_to_direct_cache(resultant_name, errmsg) == DX__ERROR)
	{
	    signal_err(errmsg, bell);
	}
    }
 
    /**  Add it to the FILER  **/
    if (add_to_filer(temp_entry, errmsg, cntrl_info_block.cur_win) == DX__ERROR)
    {
        return DX__ERROR;
    }
 
    /**  Update other windows  **/
    for (i = 0;  i < cntrl_info_block.windows;  i++)
    {
        if (i != cntrl_info_block.cur_win)
        {
            if (add_to_filer(temp_entry, errmsg, i) == DX__ERROR)
            {
                 return DX__ERROR;
            }
        }
    }
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	    filer_show_buffer()
{
    char errmsg[256];
    char numstr[80];
    int n;
 
    if ((n = select_from_filer_cache()) != -1)
    {
    	strcpy(errmsg, "Error restoring from filer buffer");
	sprintf(numstr, "%-d", n);
        check_OK(smg$set_cursor_abs (
                     &cntrl_info_block.commands_display.id,
                     &cntrl_info_block.commands_display.rows,
                     &cntrl_info_block.commands_display.width))
	if (filer_filter$1(numstr, "Restore", errmsg) == DX__ERROR)
	{
	    signal_err(errmsg, bell);
	}
    }
 
    return DX__NORMAL;
}
