/* Program Name            : FILERKPD.C                                 */
/*   Original Author       : C. K. Hung					*/
/*   Date                  : 7-12-89					*/
/*   Program Description   :                                            */
/*                         :                                            */
/* Revision History follows                                             */
 
#include "global.h"
#include "filer.h"
#include "filerapp.h"
#include "filercpy.h"
#include "filercus.h"
#include "filerdel.h"
#include "filerdec.h"
#include "filerdif.h"
#include "fileredt.h"
#include "filerenc.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 "filersta.h"
#include "filersrt.h"
#include "filertyp.h"
#include "inquire.h"
#include <strdef.h>
 
/*
**
**  MACRO DEFINITIONS
**
**/
 
/**  FILER INACTIVE SCROLL REGION		**/
#define FILER_INACTIVE_ROWS			\
    (cntrl_info_block.dir_dx[cntrl_info_block.cur_win].filer_display.view_rows/4)
#define FILER_INACTIVE_FRONT_ROW		(1+FILER_INACTIVE_ROWS)
 
 
/*
**	GLOBAL DECLARATIONS
**/
 
/*
**
**	INTERNAL FUNCTION PROTOTYPING
**
**/
    static int		    filer_find_first$2(struct fil_dx_tag *, struct fil_dx_tag **);
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_find_first()
{
    char errmsg[80];
 
    int filer_find_first$1(char *, char *, char *);
 
    strcpy(errmsg, "File not found");
    get_userinput_and_execute(
	filer_find_first$1,
	DX_CURRENT_DIRECTORY.direction == advance? "Forward Search" : "Reverse Search",
	"Find What? ",
	"",
	errmsg,
	"");
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_find_first$1(pattern, dummy, errmsg)
char *pattern;
char *dummy;
char *errmsg;
{
    struct fil_dx_tag *new_ptr;
 
    /**  Preserve search string so that it can be used by FIND_NEXT.  **/
    strcpy(DX_CURRENT_DIRECTORY.search_pattern, pattern);
 
    if (!filer_find_first$2(DX_CURRENT_FILE, &new_ptr))
    {
	return DX__ERROR;
    }
 
    unhighlight_filer_current_file();
    DX_CURRENT_FILE = new_ptr;
 
    change_filer_viewport(cntrl_info_block.cur_win);
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
static int filer_find_first$2(start_ptr, hit_ptr)
struct fil_dx_tag *start_ptr;
struct fil_dx_tag **hit_ptr;
{
    unsigned long context;
    char pattern[MAXFILESPEC+1];
    $DESCRIPTOR(pattern_descrip, DX_CURRENT_DIRECTORY.search_pattern);
    char default_filespec[MAXFILESPEC+1];
    $DESCRIPTOR(default_filespec_descrip, default_filespec);
    unsigned long condcode;
    char *indx;
    char resultant_filespec[MAXFILESPEC+1];
    $DESCRIPTOR (resultant_filespec_descrip, resultant_filespec);
    struct fil_dx_tag e;
    struct filespec_list_tag *p;
    struct w_dids_tag *q;
    char errmsg[255];
    struct list_tag
	{
	    char fn[MAXFILESPEC+1];
	    struct list_tag *next;
	} *head = NULL, *r, *new_entry;
    struct list_tag *s, *t;
    int allocate_size;
    char fn[MAXFILESPEC+1];
 
    strcpy(pattern, DX_CURRENT_DIRECTORY.search_pattern);
    LENGTH(pattern_descrip) = strlen(pattern);
 
    allocate_size = sizeof (struct list_tag);
    for (p = DX_CURRENT_DIRECTORY.cur_filter.name_filespec_list;  p;  p = p->next)
    {
    	for (q = p->w_dids;  q;  q = q->next)
	{
	    strcpy (default_filespec, q->equivalent_name);
	    strcat (default_filespec, "*.*;*");
	    LENGTH (default_filespec_descrip) = strlen (default_filespec);
	    context = 0;
	    while ((condcode = lib$find_file (
				   &pattern_descrip,
				   &resultant_filespec_descrip,
				   &context,
				   &default_filespec_descrip,
				   0,
				   0,
				   0)) != RMS$_NMF)
	    {
		if (condcode == RMS$_NORMAL &&
		    !strchr(resultant_filespec, '*'))
		{
		    if ((indx = strchr(resultant_filespec, ' ')))
		    {
			*indx = EOS;
			check_OK(lib$get_vm (
				 	 &allocate_size,
				 	 &new_entry,
				 	 0))
			strcpy(new_entry->fn, resultant_filespec);
			new_entry->next = NULL;
			if (head == NULL)
			{
			    head = new_entry;
			}
			else
			{
			    for (r = head;  r->next != NULL;  r = r->next)
			    {
			    	   ;
			    }
			    r->next = new_entry;
			}
		    }
		}
	    }
	    lib$find_file_end(&context);
	}
    }
 
    if (DX_CURRENT_DIRECTORY.direction == advance)
    {
	*hit_ptr = start_ptr->forward;
    }
    else
    {
	*hit_ptr = start_ptr->backward;
    }
 
    while (*hit_ptr != DX_CURRENT_DIRECTORY.non_dir_filelist)
    {
	 if (*hit_ptr == DX_CURRENT_DIRECTORY.dir_filelist)
	 {
	    *hit_ptr = DX_CURRENT_DIRECTORY.non_dir_filelist->forward;
	    if (*hit_ptr == DX_CURRENT_DIRECTORY.non_dir_filelist)
	    {
	    	 break;
	    }
	 }
	 find_full_path_name ((*hit_ptr)->fn, fn, cntrl_info_block.cur_win);
	 for (r = head;  r != NULL;  r = r->next)
	 {
	     if (!strcmp (fn, r->fn))
	     {
		s = head;
		while (s != NULL)
		{
		    t = s->next;
		    check_OK(lib$free_vm (
				     &allocate_size,
				     &s,
				     0))
		    s = t;
		}
		return 1;
	     }
	 }
	 if (DX_CURRENT_DIRECTORY.direction == advance)
	 {
	     *hit_ptr = (*hit_ptr)->forward;
	 }
	 else
	 {
	     *hit_ptr = (*hit_ptr)->backward;
	 }
    }
 
    s = head;
    while (s != NULL)
    {
	t = s->next;
	check_OK(lib$free_vm (
			 &allocate_size,
			 &s,
			 0))
	s = t;
    }
    return 0;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
 
int	change_filer_viewport(unsigned short int win)
{
    int new_viewport_row, new_viewport_row1;
    int number_of_scroll;
    int i;
    int lastentry_viewport_row;
    int filer_inactive_rows =
	(cntrl_info_block.dir_dx[win].filer_display.view_rows/4);
    int filer_inactive_front_row = 1+filer_inactive_rows;
    int filer_inactive_rear_row =
	cntrl_info_block.dir_dx[win].filer_display.view_rows-filer_inactive_rows;
 
    /**  Viewport for the last screen  **/
    lastentry_viewport_row =
	max(1,
	    cntrl_info_block.dir_dx[win].non_dir_filelist->backward->beg_y -
		cntrl_info_block.dir_dx[win].filer_display.view_rows + 1);
 
    if (cntrl_info_block.dir_dx[win].cur_file->beg_y < cntrl_info_block.dir_dx[win].filer_display.view_beg_y +
	filer_inactive_front_row - 1)
    {	    /**  Target row before inactive front row  **/
	new_viewport_row1 =
	    max(1, cntrl_info_block.dir_dx[win].cur_file->beg_y-(filer_inactive_front_row-1));
	new_viewport_row =
	    min(new_viewport_row1, lastentry_viewport_row);
 
	number_of_scroll =
	    cntrl_info_block.dir_dx[win].filer_display.view_beg_y-new_viewport_row;
	if (number_of_scroll <= cntrl_info_block.dir_dx[win].filer_display.view_rows/2)
	{
	    /*
	    **	The displacement between target row and current row
	    **	is leq half of the screen, use scroll by line.
	    **/
 
	    for (i = 1; i <= number_of_scroll; i++)
		check_OK(smg$scroll_viewport (
			  &cntrl_info_block.dir_dx[win].filer_display.id,
			  &SMG$M_DOWN,
			  &1))
	}
	else
	{	
	    /*	
	    **	The displacement is larger than half the screen,
	    **	use jump scroll instead.
	    **/
 
	    new_viewport_row1 =
		max(1, cntrl_info_block.dir_dx[win].cur_file->beg_y-(filer_inactive_rear_row-1));
	    new_viewport_row =
		min(new_viewport_row1, lastentry_viewport_row);
 
	    number_of_scroll =
		cntrl_info_block.dir_dx[win].filer_display.view_beg_y-new_viewport_row;
	    check_OK(smg$scroll_viewport (
		      &cntrl_info_block.dir_dx[win].filer_display.id,
		      &SMG$M_DOWN,
		      &number_of_scroll))
	}
 
	cntrl_info_block.dir_dx[win].filer_display.view_beg_y = new_viewport_row;
 
    } else if (cntrl_info_block.dir_dx[win].cur_file->beg_y > cntrl_info_block.dir_dx[win].filer_display.view_beg_y +
	filer_inactive_rear_row - 1)
    {
	/**  Target row beyond inactive rear row  **/
	new_viewport_row1 =
	    max(1, cntrl_info_block.dir_dx[win].cur_file->beg_y-(filer_inactive_rear_row-1));
	new_viewport_row =
	    min(new_viewport_row1, lastentry_viewport_row);
 
	number_of_scroll =
	    new_viewport_row-cntrl_info_block.dir_dx[win].filer_display.view_beg_y;
	if (number_of_scroll <= cntrl_info_block.dir_dx[win].filer_display.view_rows/2)
	{
	    /*
	    **	The displacement between target row and current row
	    **	is leq half of the screen, use scroll by line.
	    **/
 
	    for (i = 1; i <= abs(number_of_scroll); i++)
		if (number_of_scroll > 0)
		    check_OK(smg$scroll_viewport (
			      &cntrl_info_block.dir_dx[win].filer_display.id,
			      &SMG$M_UP,
			      &1))
		else
		    check_OK(smg$scroll_viewport (
			      &cntrl_info_block.dir_dx[win].filer_display.id,
			      &SMG$M_DOWN,
			      &1))
	}
	else
	{	
	    /*	
	    **	The displacement is larger than half the screen,
	    **	use jump scroll instead.
	    **/
 
	    new_viewport_row1 =
		max(1, cntrl_info_block.dir_dx[win].cur_file->beg_y-(filer_inactive_front_row-1));
	    new_viewport_row =
		min(new_viewport_row1, lastentry_viewport_row);
 
	    number_of_scroll =
		new_viewport_row-cntrl_info_block.dir_dx[win].filer_display.view_beg_y;
	    if (number_of_scroll > 0)
		check_OK(smg$scroll_viewport (
			  &cntrl_info_block.dir_dx[win].filer_display.id,
			  &SMG$M_UP,
			  &number_of_scroll))
	    else
		check_OK(smg$scroll_viewport (
			  &cntrl_info_block.dir_dx[win].filer_display.id,
			  &SMG$M_DOWN,
			  &number_of_scroll))
	}
 
	cntrl_info_block.dir_dx[win].filer_display.view_beg_y = new_viewport_row;
 
    }
    else if (cntrl_info_block.dir_dx[win].non_dir_filelist->forward->beg_y <=
		cntrl_info_block.dir_dx[win].filer_display.view_beg_y +
		    cntrl_info_block.dir_dx[win].filer_display.view_rows - 1)
    {
	/*
	**  Target file is in active area, and
	**  last file in this directory is also in current screen.
	**/
 
	new_viewport_row = lastentry_viewport_row;
	number_of_scroll =
	    cntrl_info_block.dir_dx[win].filer_display.view_beg_y-new_viewport_row;
	for (i = 1;
	     i <= number_of_scroll &&
		cntrl_info_block.dir_dx[win].filer_display.view_beg_y > 1;
	     i++, cntrl_info_block.dir_dx[win].filer_display.view_beg_y--)
            check_OK(smg$scroll_viewport (
                      &cntrl_info_block.dir_dx[win].filer_display.id,
                      &SMG$M_DOWN,
                      &1))
    }
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_find_next()
{
    char dummy1[80], dummy2[80];
    char errmsg[81];
 
    if (filer_find_first$1(
	    DX_CURRENT_DIRECTORY.search_pattern,
	    dummy1,
	    dummy2) == -1)
    {
	sprintf(errmsg, "%s search: file not found",
	     DX_CURRENT_DIRECTORY.direction == advance?
		"Forward" : "Reverse");
	signal_err(errmsg, bell);
    }
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**  FILER_TOP() moves the cursor to point to the first record.
**
**--
**/
int	filer_top()
{
    int i;
 
    if (DX_CURRENT_FILE->beg_y == 1 && DX_CURRENT_FILE->beg_x == 1)
    {
	signal_err("Already at top of records", bell);
    }
    else
    {
	DX_CURRENT_FILE = DX_CURRENT_DIRECTORY.dir_filelist->forward;
	if (DX_CURRENT_FILE == DX_CURRENT_DIRECTORY.dir_filelist)
	{
	    DX_CURRENT_FILE = DX_CURRENT_DIRECTORY.non_dir_filelist->forward;
	}
	change_filer_viewport(cntrl_info_block.cur_win);
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**  FILER_BOTTOM() moves the cursor to point to the last record.
**
**--
**/
int	filer_bottom()
{
    if (DX_CURRENT_FILE->beg_y ==
	    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_y &&
	DX_CURRENT_FILE->beg_x ==
	    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_x)
    {
        signal_err("Already at bottom of records", bell);
    }
    else
    {
	DX_CURRENT_FILE = DX_CURRENT_DIRECTORY.non_dir_filelist->backward;
        if (DX_CURRENT_FILE == DX_CURRENT_DIRECTORY.non_dir_filelist &&
	    DX_CURRENT_DIRECTORY.dir_filelist->backward !=
		DX_CURRENT_DIRECTORY.dir_filelist)
        {
            DX_CURRENT_FILE = DX_CURRENT_DIRECTORY.dir_filelist->backward;
        }
	change_filer_viewport(cntrl_info_block.cur_win);
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**  FILER_PAGE_DOWN() scrolls down one screenful of records.
**
**--
**/
int	filer_page_down()
{
    int i, number_of_scroll;
    int rows_in_page;
    struct fil_dx_tag *p, *q;
 
    if (DX_CURRENT_FILE->beg_y ==
	    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_y &&
	DX_CURRENT_FILE->beg_x ==
	    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_x)
    {
        signal_err("Already at bottom of records", bell);
    }
    else
    {
	rows_in_page = DX_CURRENT_DIRECTORY.filer_display.view_rows-1;
	p = DX_CURRENT_FILE;
	while (!(p->beg_y ==
		    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_y &&
		 p->beg_x ==
		    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_x))
        {
	    p = p->forward;
            if (p == DX_CURRENT_DIRECTORY.dir_filelist)
            {
                p = DX_CURRENT_DIRECTORY.non_dir_filelist;
            }
            else
            {
		q = (p->forward == DX_CURRENT_DIRECTORY.dir_filelist?
		    DX_CURRENT_DIRECTORY.non_dir_filelist->forward : p->forward);
                if ((p->beg_y == DX_CURRENT_FILE->beg_y + rows_in_page &&
			q->beg_x > DX_CURRENT_FILE->beg_x)	||
		    (q->beg_y == DX_CURRENT_FILE->beg_y + rows_in_page + 1 &&
			q->beg_x == 1))
                {
                    break;
                }
            }
        }
	DX_CURRENT_FILE = p;
 
	/*
	**  Scroll one full screen only if the current file
	**  is within inavtive area
	**/
 
	if (DX_CURRENT_FILE->beg_y <
		DX_CURRENT_DIRECTORY.filer_display.view_beg_y +
		DX_CURRENT_DIRECTORY.filer_display.view_rows +
		FILER_INACTIVE_FRONT_ROW - 2)
	{
	    number_of_scroll =
		DX_CURRENT_DIRECTORY.filer_display.view_rows - 1 -
		    (FILER_INACTIVE_FRONT_ROW-1);
	}
        else
        {
            number_of_scroll =
		DX_CURRENT_DIRECTORY.filer_display.view_rows - 1;
        }
	
	/*
	**  Scroll filer display.  stop as soon as bottom of record
	**  is reached.
	**/
 
        for (i = 1;
		i <= number_of_scroll &&
		    DX_CURRENT_DIRECTORY.filer_display.view_beg_y +
			DX_CURRENT_DIRECTORY.filer_display.view_rows - 1 <
		    DX_CURRENT_DIRECTORY.filer_display.rows;
		i++, DX_CURRENT_DIRECTORY.filer_display.view_beg_y++)
        {
            check_OK(smg$scroll_viewport (
                         &DX_CURRENT_DIRECTORY.filer_display.id,
                         &SMG$M_UP,
                         &1))
        }
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**  FILER_PAGE_UP() scrolls up one screenful of records.
**
**--
**/
int	filer_page_up()
{
    int i;
    int number_of_scroll;
    int rows_in_page;
    struct fil_dx_tag *p;
    int filer1_inactive_rear_row =
	DX_CURRENT_DIRECTORY.filer_display.view_rows-FILER_INACTIVE_ROWS;
 
    if (DX_CURRENT_FILE->beg_y == 1 && DX_CURRENT_FILE->beg_x == 1)
    {
	signal_err("Already at top of records", bell);
    }
    else
    {
	rows_in_page = DX_CURRENT_DIRECTORY.filer_display.view_rows-1;
	p = DX_CURRENT_FILE;
        while (!(p->beg_y == 1 && p->beg_x == 1))
        {
	    p = p->backward;
	    if (p == DX_CURRENT_DIRECTORY.non_dir_filelist)
	    {
		p = DX_CURRENT_DIRECTORY.dir_filelist->backward;
	    }
            else
            {
                if (p->beg_y == DX_CURRENT_FILE->beg_y-rows_in_page &&
		    p->beg_x <= DX_CURRENT_FILE->beg_x)
                {
                    break;
                }
            }
        }
	DX_CURRENT_FILE = p;
 
	if (DX_CURRENT_FILE->beg_y >
		DX_CURRENT_DIRECTORY.filer_display.view_beg_y -
                (DX_CURRENT_DIRECTORY.filer_display.view_rows-1) +
		filer1_inactive_rear_row - 1)
	{
	    number_of_scroll =
		DX_CURRENT_DIRECTORY.filer_display.view_rows - 1 -
		    (FILER_INACTIVE_FRONT_ROW-1);
	}
        else
        {
            number_of_scroll =
		DX_CURRENT_DIRECTORY.filer_display.view_rows - 1;
        }
	
	/*
	**  Scroll filer display.  stop as soon as top of record
	**  is reached.
	**/
 
        for (i = 1;
		i <= number_of_scroll &&
		    DX_CURRENT_DIRECTORY.filer_display.view_beg_y > 1;
		i++, DX_CURRENT_DIRECTORY.filer_display.view_beg_y--)
        {
            check_OK(smg$scroll_viewport (
                         &DX_CURRENT_DIRECTORY.filer_display.id,
                         &SMG$M_DOWN,
                         &1))
        }
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**  tbs
**
**--
**/
int	filer_right()
{
    if (DX_CURRENT_FILE->beg_y ==
	    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_y &&
	DX_CURRENT_FILE->beg_x ==
	    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_x)
    {
        signal_err("Already at bottom of records", bell);
    }
    else
    {
        DX_CURRENT_FILE = DX_CURRENT_FILE->forward;
        if (DX_CURRENT_FILE == DX_CURRENT_DIRECTORY.dir_filelist)
        {
            DX_CURRENT_FILE = DX_CURRENT_DIRECTORY.non_dir_filelist->forward;
        }
	change_filer_viewport(cntrl_info_block.cur_win);
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**  tbs
**
**--
**/
int	filer_left()
{
    if (DX_CURRENT_FILE->beg_y == 1 && DX_CURRENT_FILE->beg_x == 1)
    {
        signal_err("Already at top of records", bell);
    }
    else
    {
        DX_CURRENT_FILE = DX_CURRENT_FILE->backward;
        if (DX_CURRENT_FILE == DX_CURRENT_DIRECTORY.non_dir_filelist)
        {
            DX_CURRENT_FILE = DX_CURRENT_DIRECTORY.dir_filelist->backward;
        }
	change_filer_viewport(cntrl_info_block.cur_win);
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**  FILER_DOWN() moves the cursor down one record.
**
**--
**/
int	filer_down()
{
    struct fil_dx_tag *p, *q;
 
    if (DX_CURRENT_FILE->beg_y ==
	    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_y &&
	DX_CURRENT_FILE->beg_x ==
	    DX_CURRENT_DIRECTORY.non_dir_filelist->backward->beg_x)
    {
        signal_err("Already at bottom of records", bell);
    }
    else
    {
        for (p = q = DX_CURRENT_FILE;  p != DX_CURRENT_DIRECTORY.non_dir_filelist;  p = p->forward)
        {
            if (p == DX_CURRENT_DIRECTORY.dir_filelist)
            {
                p = DX_CURRENT_DIRECTORY.non_dir_filelist;
            }
            else
            {
		q = p;
		if (p->beg_x == DX_CURRENT_FILE->beg_x &&
		    p->beg_y >  DX_CURRENT_FILE->beg_y)
		{
		    break;
		}
	    }
        }
	DX_CURRENT_FILE = q;
	change_filer_viewport(cntrl_info_block.cur_win);
    }
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**  FILER_UP() moves the cursor up one line.
**
**--
**/
int	filer_up()
{
    struct fil_dx_tag *p, *q;
 
    if (DX_CURRENT_FILE->beg_y == 1 && DX_CURRENT_FILE->beg_x == 1)
    {
	signal_err("Already at top of records", bell);
    }
    else
    {
        for (p = q = DX_CURRENT_FILE;  p != DX_CURRENT_DIRECTORY.dir_filelist;  p = p->backward)
        {
            if (p == DX_CURRENT_DIRECTORY.non_dir_filelist)
            {
                p = DX_CURRENT_DIRECTORY.dir_filelist;
            }
            else
            {
		q = p;
		if (p->beg_x == DX_CURRENT_FILE->beg_x &&
		    p->beg_y <  DX_CURRENT_FILE->beg_y)
		{
		    break;
		}
	    }
        }
	DX_CURRENT_FILE = q;
	change_filer_viewport(cntrl_info_block.cur_win);
    }
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_mark(p, update)
struct fil_dx_tag *p;
int update;
{
    char str[MAXFILESPEC+1];
    $DESCRIPTOR(str_descrip, str);
 
    if (strcmp(p->fn, "[-]"))
    {
	if (p != DX_CURRENT_DIRECTORY.non_dir_filelist && p->state != ready)
	{
	    p->state = ready;
 
	    DX_CURRENT_DIRECTORY.sel_files++;
	    DX_CURRENT_DIRECTORY.sel_blocks += p->filesize;
 
	    put_filer_stat(cntrl_info_block.cur_win);
            if (update)
            {
		check_OK(smg$put_chars (
			    &DX_CURRENT_DIRECTORY.filer_display.id,
			    $DESCR ("*"),
			    &p->beg_y,
			    &p->beg_x,
			    0,
			    0,
			    0,
			    0))
            }
	}
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_unmark(p, update)
struct fil_dx_tag *p;
int update;
{
    char str[MAXFILESPEC+1];
    $DESCRIPTOR(str_descrip, str);
 
    if (p != DX_CURRENT_DIRECTORY.non_dir_filelist && p->state != waiting)
    {
	if (p->state == ready)
	{
	    DX_CURRENT_DIRECTORY.sel_files--;
	    DX_CURRENT_DIRECTORY.sel_blocks -= p->filesize;
	}
 
	p->state = waiting;
 
	put_filer_stat(cntrl_info_block.cur_win);
        if (update)
        {
	    check_OK(smg$put_chars (
			&DX_CURRENT_DIRECTORY.filer_display.id,
			$DESCR (" "),
			&p->beg_y,
			&p->beg_x,
			0,
			0,
			0,
			0))
        }
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_execute(p)
struct fil_dx_tag *p;
{
    char str[MAXFILESPEC+1];
    $DESCRIPTOR(str_descrip, str);
 
    format_filer_entry(p, str, cntrl_info_block.cur_win);
    if (p->fn[ strlen(p->fn)-1 ] != ']')
    {	/**  Current file is not a directory file  **/
	LENGTH(str_descrip) = strlen(str);
	check_OK(smg$put_chars (
		    &DX_CURRENT_DIRECTORY.filer_display.id,
		    &str_descrip,
		    &p->beg_y,
		    &p->beg_x,
		    0,
		    0,
		    &SMG$M_REVERSE,
		    0))
    }
    else if (DX_CURRENT_DIRECTORY.form == short_form)
    {	/**  Directory file with short form  **/
	LENGTH(str_descrip) = strlen(str);
	check_OK(smg$put_chars (
		    &DX_CURRENT_DIRECTORY.filer_display.id,
		    &str_descrip,
		    &p->beg_y,
		    &p->beg_x,
		    0,
		    &SMG$M_BOLD,
		    &SMG$M_REVERSE,
		    0))
    }
    else
    {	/**  Directory file with long form  **/
	LENGTH(str_descrip) = 1;
	check_OK(smg$put_chars (
		    &DX_CURRENT_DIRECTORY.filer_display.id,
		    &str_descrip,
		    &p->beg_y,
		    &1,
		    0,
		    0,
		    &SMG$M_REVERSE,
		    0))
	memcpy (str, str+1, strlen(str));
	if (!strcmp(str, "[-]"))
	{
	    check_OK(smg$put_chars (
			&DX_CURRENT_DIRECTORY.filer_display.id,
			$DESCR ("[-]"),
			&p->beg_y,
			&2,
			0,
			&SMG$M_BOLD,
			&SMG$M_REVERSE,
			0))
	}
	else
	{
	    LENGTH(str_descrip) = 30;
	    check_OK(smg$put_chars (
			&DX_CURRENT_DIRECTORY.filer_display.id,
			&str_descrip,
			&p->beg_y,
			&2,
			0,
			&SMG$M_BOLD,
			&SMG$M_REVERSE,
			0))
	    memcpy (str, str+30, strlen(str)-30+1);
	    LENGTH(str_descrip) = strlen(str);
	    check_OK(smg$put_chars (
			&DX_CURRENT_DIRECTORY.filer_display.id,
			&str_descrip,
			&p->beg_y,
			&32,
			0,
			0,
			&SMG$M_REVERSE,
			0))
	}
    }
 
    p->state = executed;
 
    DX_CURRENT_DIRECTORY.sel_files--;
    DX_CURRENT_DIRECTORY.sel_blocks -= p->filesize;
 
    put_filer_stat(cntrl_info_block.cur_win);
 
    check_OK(smg$set_cursor_abs (
	      &DX_CURRENT_DIRECTORY.filer_display.id,
	      &p->beg_y,
	      &p->beg_x))
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_multiple(func, to, errmsg)
int (*func)();
char *to;
char *errmsg;
{
    struct fil_dx_tag *MARKER, *p;
    int status = DX__NORMAL;
    int count;
    long int row;
    char fn[MAXVMSFULLNAME];
    char msg[81];
    char dirbuf[MAXFILESPEC+1];
 
    p = DX_CURRENT_DIRECTORY.dir_filelist->forward;
    count = 0;
 
    while (p != DX_CURRENT_DIRECTORY.non_dir_filelist)
    {	
        if (p == DX_CURRENT_DIRECTORY.dir_filelist)
        {
            p = DX_CURRENT_DIRECTORY.non_dir_filelist->forward;
        }
	else
	{
	    if (p->state != ready)
	    {
		p = p->forward;
	    }
	    else
	    {    /**  Found a target file  **/
		unhighlight_filer_current_file();
		DX_CURRENT_FILE = p;
		change_filer_viewport(cntrl_info_block.cur_win);
		filer_execute(p);
 
		find_full_path_name(DX_CURRENT_FILE->fn, fn, cntrl_info_block.cur_win);
		if ((status = (*func)(to, fn, errmsg)) != DX__NORMAL)
		{	/**  Opeartion failed or canceled by the user  **/
		    signal_err(errmsg, status == -1? bell : silence);
		    break;
		}
 
		p = DX_CURRENT_FILE;
		count++;	    /**  One more file processed  **/
	    }
	}
    }
 
    if (status == DX__NORMAL)
    {
	sprintf(msg, "%d %s ", count, (count > 1? "files" : "file"));
 
	if (func == filer_status$1)
	    strcat(msg, "analyzed");
	else if (func == filer_type$1)
	    strcat(msg, "typed");
	else if (func == filer_print$1)
	    strcat(msg, "printed ");
	else if (func == filer_edt$1)
	    strcat(msg, "edited");
	else if (func == filer_copy$1)
	    strcat(msg, "copied");
	else if (func == filer_rename$1)
	    strcat(msg, "renamed");
	else if (func == filer_protection$1)
	    strcat(msg, "protection set");
	else if (func == filer_find$1)
	    strcat(msg, "searched");
	else if (func == filer_delete$1)
	    strcat(msg, "deleted");
	else if (func == filer_purge$1)
	    strcat(msg, "purged");
	else if (func == filer_launch$1)
	    strcat(msg, "launched");
	else if (func == filer_diff$1)
	    strcat(msg, "compared");
	else if (func == filer_encode$1)
	    strcat(msg, "encoded");
	else if (func == filer_decode$1)
	    strcat(msg, "decoded");
	else if (func == filer_append$1)
	    strcat(msg, "decoded");
	else
	    strcpy(msg, "Internal error");    /**  Internal error  **/
 
	signal_err(msg, silence);
    }
 
    check_OK(smg$set_cursor_abs (
	      &DX_CURRENT_DIRECTORY.filer_display.id,
	      &DX_CURRENT_FILE->beg_y,
	      &DX_CURRENT_FILE->beg_x))
 
    return status;
}
