;/*
; *                      Microsoft Confidential
; *                      Copyright (C) Microsoft Corporation 1991
; *                      All Rights Reserved.
; */

/******************************************************************************
*
*  Change Log:
*
*    Date    Who   #                      Description
*  --------  ---  ---  ------------------------------------------------------
*  06/29/90  EGH  C01  Added support for doing a directory of backed up
*                      diskettes via the /D option.
*
******************************************************************************/

/*-------------------------------
/* SOURCE FILE NAME: restpars.c
/*-------------------------------
/*  0 */
#include "rt.h"
#include "rt1.h"
#include "rt2.h"
#include "restpars.h"                                                 /*;AN000;4*/
#include "direct.h"
#include "string.h"
#include "ctype.h"
#include "dos.h"                                                      /*;AN000;2*/
#include "comsub.h"             /* common subroutine def'n */
#include "doscalls.h"
#include "error.h"

/*=============================*/
extern	BYTE	srcd;						      /*;AN000;4*/
extern	BYTE	destd;						      /*;AN000;4*/
extern	BYTE	inpath	[MAXPATH];				      /*;AN000;*/
extern	BYTE	infname [MAXFNAME];				      /*;AN000;*/
extern	BYTE	infext	[MAXFEXT];				      /*;AN000;*/
extern	BYTE	infspec [MAXFSPEC];				      /*;AN000;*/
/*=============================*/

extern	BYTE destddir[MAXPATH+3];
extern	BYTE srcddir[MAXPATH+3];
extern	BYTE rtswitch;
extern	BYTE rtswitch7; 		   /*;MR001+ additional switch byte   */
extern  BYTE rtswitch2;                                                 /*C01*/
extern	BYTE control_flag;
extern	BYTE control_flag2;
extern	BYTE filename[12];
extern	unsigned control_file_handle;				      /* !wrw */
extern	struct	subst_list sublist;	   /*;AN000;6Message substitution list */

struct	p_parms 	parms;		   /*;AN000;4 Parser data structure */
struct	p_parmsx	parmsx; 	   /*;AN000;4 Parser data structure */
struct	p_pos_blk	pos1;		   /*;AN000;4 Parser data structure */
struct	p_pos_blk	pos2;		   /*;AN000;4 Parser data structure */
struct	p_sw_blk	sw1;		   /*;AN000;4 /S /P /M /N  data structure */
struct	p_sw_blk	sw2;		   /*;AN000;4 /E: /L:  parser data structure */
struct	p_sw_blk	sw3;		   /*;AN000;4 /B: /A:  parser data structure */
struct	p_sw_blk	sw90;		   /*:MR001+  /Z: /Y:  parser data structure */
struct	p_sw4_blk	sw4;		/* /? parser data structure */
struct	p_result_blk	pos_buff;	   /*;AN000;4 Parser data structure */
struct	switchbuff	sw_buff;	   /*;AN000;4 Parser data structure */
struct	timebuff	time_buff;	   /*;AN000;4 Parser data structure */
struct	datebuff	date_buff;	   /*;AN000;4 Parser data structure */
DWORD	noval;				   /*;AN000;4 Value list for PARSER */
int	parse_count = 1;		   /*;AN000;4*//*;AC002;*/
char	curr_parm[128]; 		   /*;AN004; Current parameter being parsed*/
extern	struct timedate td;

/*************************************************/
/*
/* SUBROUTINE NAME:	parse_command_line
/*
/* FUNCTION:
/*
/*	Parse the RESTORE command line
/*
/**************************************************/
void	parse_command_line(argc,argv)				      /*;AN000;4 */
int	argc;							      /*;AN000;4 */
char	*argv[];						      /*;AN000;4 */
{								      /*;AN000;4 */
#define EOL  -1 						      /*;AN000;4 */
	union REGS inregs, outregs;				      /*;AN000;4 */
	char	cmd_line[128];					      /*;AN000;4 */
	char	not_finished = TTRUE;				      /*;AN000;4 */
	int	x;						      /*;AN000;4 */

	/*
	 * See if the user entered /? on the command line.
	 * If so, display the options help message, and then
	 * exit so they can try again.
	 */

	check_options_help(argc, argv);

		/* Copy command line parameters to local area */
	cmd_line[0] = NUL;					      /*;AN000;4*/
	for (x=1; x<=argc; x++) 				      /*;AN000;4*/
	 {							      /*;AN000;4*/
	  strcat(cmd_line,argv[x]);				      /*;AN000;4*/
	  if (x!=argc) strcat(cmd_line," ");                          /*;AN000;4*/
	 }							      /*;AN000;4*/

	strcat(cmd_line,"\r");             /* Add CR, LF */           /*;AN004;*/

	if (argc-1 < 1) 					      /*;AN000;4*/
	 {							      /*;AC000;4*/
	  display_it(NO_SOURCE,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
	  usererror(INVALIDPARM);				      /*;AC000;4*/
	 }							      /*;AC000;4*/

	if (argc-1 < 2) 					      /*;AN000;4*/
	 {							      /*;AC000;4*/
	  display_it(NO_TARGET,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
	  usererror(INVALIDPARM);				      /*;AC000;4*/
	 }							      /*;AC000;4*/

		/* Check for same source and target drive */
	if (com_toupper(*argv[1]) == com_toupper(*argv[2])	      /*;AN000;4*/
	    && (BYTE)*(argv[1]+1) == ':'                              /*;AN000;4*/
	    && (BYTE)*(argv[1]+2) == NUL			      /*;AN000;4*/
	    && (BYTE)*(argv[2]+1) == ':'                              /*;AN000;4*/
	   )							      /*;AN000;4*/
	 {							      /*;AC000;4*/
	  display_it(SOURCE_TARGET_SAME,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
	  usererror(INVALIDPARM);				      /*;AC000;4*/
	 }							      /*;AC000;4*/

		/* Initialize parser data structures */
	parse_init();						      /*;AN000;4*/

	inregs.x.si = (WORD)&cmd_line[0];  /*DS:SI*/		      /*;AN000;4 make DS:SI point to source */
	inregs.x.cx = 0;					      /*;AN000;4*/

		/*********************/
		/* PARSE LOOP !!!!!! */
		/*********************/
	while (not_finished)					      /*;AN000;4 For all strings in command line */
	 {							      /*;AN000;4 */
	  inregs.x.dx = 0;					      /*;AN000;4 RESERVED */
	  inregs.x.di = (WORD)&parms;	/*ES:DI*/		      /*;AN000;4 address of parm list */
	  parse(&inregs,&outregs);				      /*;AN000;4 Call DOS PARSE service routines*/

	  x=0;			/* Save the parsed parameter */       /*;AN004;*/
	  for (inregs.x.si; inregs.x.si<outregs.x.si; inregs.x.si++)  /*;AN004;*/
	   {							      /*;AN004;*/
	     curr_parm[x] = *(char *)inregs.x.si;		      /*;AN004;*/
	     x++;						      /*;AN004;*/
	   }							      /*;AN004;*/

	  curr_parm[x] = NUL;					      /*;AN004;*/

	  inregs = outregs;		/* Reset registers */	      /*;AN000;4 Reset registers*/

					/* Check for PARSE ERROR*/
	  if (outregs.x.ax != (WORD)NOERROR)			      /*;AN000;4*/
	   {							      /*;AN000;4*/
	     if (outregs.x.ax==(WORD)EOL)   /* Was it End of line? */ /*;AN000;4*/
	       not_finished = FFALSE;				      /*;AN000;4*/
	      else
	       {			     /* It was an error */    /*;AN000;4*/
		 not_finished = FFALSE; 			      /*;AN000;4*/
		 parse_error(outregs.x.ax,(BYTE)PARSEERR);	      /*;AN000;4*//*;AC002;*/
	      } 						      /*;AN000;4*/
	   }							      /*;AN000;4*/

	  if (not_finished)	/* Parse was successful !*/	      /*;AN000;4*/
	   {							      /*;AN000;4*/
	     if ( outregs.x.dx == (WORD)&time_buff ||		      /*;AN000;4*/
		  outregs.x.dx == (WORD)&date_buff ||		      /*;AN000;4*/
		  outregs.x.dx == (WORD)&sw_buff		      /*;AN000;4*/
		)						      /*;AN000;4*/
	       process_switch(outregs.x.dx);	      /*;AN000;4*//*;AC002;*/
	   }							      /*;AN000;4*/

	  parse_count++;					      /*;AN000;4*//*;AC002;*/
	 }  /* End WHILE Parse loop */				      /*;AN000;4*/

		/*  Check source and target filespec */
	if (strlen(argv[2]) >= 5)				      /*;AN000;p2591*/
	 check_for_device_names(argv);				      /*;AN000;p2591*/

	check_source_drive(argv);				      /*;AN000;4*/
	check_target_filespec(argc,argv);			      /*;AN000;4*/

	return; 						      /*;AN000;4*/
}	/* end parser */					      /*;AN000;4*/

/*************************************************/
/*
/* SUBROUTINE NAME:	check_options_help
/*
/* FUNCTION:
/*
/*	Check the command line for /?.  The parser cannot
/* be relied on for this, because main() first calls
/* check_drive_validity, which will error out if two
/* valid drive letters are not found in argv[].
/*
/* If /? is found, call display_options_exit(), which
/* will display the options help message, and then
/* terminate the program.
/*
/**************************************************/
void
check_options_help(argc,argv)
int	argc;
char	*argv[];
{
	/*
	 * Check every argument (except the first, which
	 * is "backup", looking for "/?".  If found,
	 * call off to display_options_exit().
	 */

	for (argc--, argv++; argc; argc--, argv++)
		if (argv[0][0] == '/' && argv[0][1] == '?' && argv[0][2] == '\0')
			display_options_exit();
}

/*************************************************/
/*
/* SUBROUTINE NAME:	parse_error
/*
/* FUNCTION:
/*
/*	There was a parse error. Display message and die
/*
/**************************************************/
void	parse_error(msg_num,class)				      /*;AN000;4*//*;AC002;*/
WORD	msg_num;						      /*;AN000;4*/
BYTE	class;							      /*;AN000;4*/
{								      /*;AN000;4*/
      sublist.value1 = &curr_parm[0];				      /*;AN002;*/
      sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ;		      /*;AN002;*/
      sublist.one = 0;						      /*;AN002;*/
      sublist.max_width1 = (BYTE)strlen(curr_parm);		      /*;AN002;*/
      sublist.min_width1 = sublist.max_width1;			      /*;AN002;*/


      if (msg_num == NO_SOURCE	||  msg_num == NO_TARGET)	      /*;AN000;6*/
       display_it(msg_num,STND_ERR_DEV,0,NO_RESPTYPE,class);	      /*;AN000;6*/
      else							      /*;AN000;6*/
       display_it(msg_num,STND_ERR_DEV,1,NO_RESPTYPE,class);	      /*;AN000;6*/


      usererror(INVALIDPARM);					      /*;AN000;4*//*;AC002;*/
      return;							      /*;AN000;4*/
}								      /*;AN000;4*/

/*************************************************/
/*
/* SUBROUTINE NAME:	display_options_exit
/*
/* FUNCTION:
/*
/*	Display the options help message, and
/*	then exit so the user can retry the command.
/*
/***************************************************/

void
display_options_exit()
{
	int	MsgNbr;

	/*
	 * Display all the message lines in the
	 * options help message.
	 */

	for (MsgNbr = MSG_OPTIONS_FIRST;
		MsgNbr <= MSG_OPTIONS_LAST;
		MsgNbr++)
	{
		display_it(MsgNbr, STND_OUT_DEV, 0, NO_RESPTYPE, (BYTE)UTIL_MSG);
	}

	/*
	 * Set the return code to show no error,
	 * and exit so the user can retry the command.
	 */

	usererror(0);		/* does not return */
}

/*************************************************/
/*
/* SUBROUTINE NAME:	check_date
/*
/* FUNCTION:
/*
/*	A date parameter was entered. Validate it
/*
/**************************************************/
void	check_date(year,month,day)				      /*;AN000;4*//*;AC002;*/
WORD	year;							      /*;AN000;4*/
BYTE	month;							      /*;AN000;4*/
BYTE	day;							      /*;AN000;4*/
{								      /*;AN000;4*/
	if (year > 2099 || year < 1980) 			      /*;AC000;4*/
	  parse_error(INV_DATE,(BYTE)UTILMSG);			      /*;AC000;4*//*;AC002;*/

	if (month > 12 || month < 1)				      /*;AC000;4*/
	  parse_error(INV_DATE,(BYTE)UTILMSG);			      /*;AC000;4*//*;AC002;*/

	if (day > 31 || month < 1)				      /*;AC000;4*/
	  parse_error(INV_DATE,(BYTE)UTILMSG);			      /*;AC000;4*//*;AC002;*/

		/* Verify day not greater then 30 if Apr,Jun,Sep,Nov */
	if ((day>30) && (month==4 || month==6 || month==9 || month==11)) /*;AC000;4*/
	  parse_error(INV_DATE,(BYTE)UTILMSG);			      /*;AC000;4*//*;AC002;*/

	if (month == 2) 		/* Deal with February */      /*;AC000;4*/
	 {							      /*;AC000;4*/
	   if (day >  29)		/*  if Feb 30 or above */     /*;AC000;4*/
	    parse_error(INV_DATE,(BYTE)UTILMSG);		      /*;AC000;4*//*;AC002;*/

	   if ((year % 4) != 0) 	/* If not a leap year */      /*;AC000;4*/
	     if (day >	28)		/*  if Feb 29 or above */     /*;AC000;4*/
	      parse_error(INV_DATE,(BYTE)UTILMSG);		      /*;AC000;4*//*;AC002;*/
	 }							      /*;AC000;4*/

	return; 						      /*;AN000;4*/
}								      /*;AN000;4*/
/*************************************************/
/*
/* SUBROUTINE NAME:	check_time
/*
/* FUNCTION:
/*
/*	A time parameter was entered. Validate it
/*
/**************************************************/
void	check_time(hours,minutes,seconds)		      /*;AN000;4*//*;AC002;*/
BYTE	hours;							      /*;AN000;4*/
BYTE	minutes;						      /*;AN000;4*/
BYTE	seconds;						      /*;AN000;4*/
{								      /*;AN000;4*/

	if (hours > 23 || hours < 0)				      /*;AC000;4*/
	 parse_error(INV_TIME,(BYTE)UTILMSG);			      /*;AC000;4*//*;AC002;*/

	if (minutes >= 60 || minutes < 0)			      /*;AC000;4*/
	  parse_error(INV_TIME,(BYTE)UTILMSG);			      /*;AC000;4*//*;AC002;*/

	if (seconds >= 60 || seconds < 0)			      /*;AC000;4*/
	   parse_error(INV_TIME,(BYTE)UTILMSG); 		      /*;AC000;4*//*;AC002;*/

	return; 						      /*;AN000;4*/
}								      /*;AN000;4*/

/*************************************************/
/*
/* SUBROUTINE NAME:	parse_init
/*
/* FUNCTION:
/*
/*	Initialize the parser data structures
/*
/**************************************************/
#define SSTRING 0x2000			/*;AN000;4*/
#define FILESPEC 0x0200 		/*;AN000;4 */
#define CAP_FILETABLE 0x0001		/*;AN000;4 */
#define DRIVELETTER 0x100;		/*;AN000;4 */
#define DATESTRING 0x1000		/*;AN000;4 */
#define TIMESTRING 0x0800		/*;AN000;4 */

void	parse_init()					/*;AN000;4 */

{		/* Initialize PARMS data structure */	/*;AN000;4 */
	parms.parmsx_ptr = (WORD)&parmsx;		/*;AN000;4 */
	parms.p_num_extra = 1;				/*;AN000;4 */
	parms.p_len_extra_delim = 1;			/*;AN000;4 */
	parms.p_extra_delim[0] = ';';                   /*;AN000;4 */
	parms.p_extra_delim[1] = NUL;			/*;AN000;4 */

		/* Initialize PARMSX data structure */
	parmsx.p_minpos= 2;				/*;AN000;4 */
	parmsx.p_maxpos= 2;				/*;AN000;4 */
	parmsx.pos1_ptr= (WORD)&pos1;			/*;AN000;4 */
	parmsx.pos2_ptr= (WORD)&pos2;			/*;AN000;4 */
	parmsx.num_sw  = 4;				/*;AN000;4 */
	parmsx.sw1_ptr = (WORD)&sw1;			/*;AN000;4 */
	parmsx.sw2_ptr = (WORD)&sw2;			/*;AN000;4 */
	parmsx.sw3_ptr = (WORD)&sw3;			/*;AN000;4 */
	parmsx.sw4_ptr = (WORD)&sw4;
	parmsx.num_keywords = 0;			/*;AN000;4 */

		/* Initialize POS1 (Source Drive) data structure */
	pos1.match_flag = FILESPEC;			/*;AN000;4 */
	pos1.function_flag = 0; 			/*;AN000;4 */
	pos1.result_buf = (WORD)&pos_buff;		/*;AN000;4 */
	pos1.value_list = (WORD)&noval; 		/*;AN000;4 */
	pos1.nid = 0;					/*;AN000;4 */

		/* Initialize POS2 (Target FILESPEC) data structure */
	pos2.match_flag = SSTRING;			/*;AN000;4 */
	pos2.function_flag = 0; 			/*;AN000;4 */
	pos2.result_buf = (WORD)&pos_buff;		/*;AN000;4 */
	pos2.value_list = (WORD)&noval; 		/*;AN000;4 */
	pos2.nid = 0;					/*;AN000;4 */

		/* Initialize SW1 data structure */
	sw1.p_match_flag = DATESTRING;			/*;AN000;4 */
	sw1.p_function_flag = 0;			/*;AN000;4 */
	sw1.p_result_buf = (WORD)&date_buff;		/*;AN000;4 */
	sw1.p_value_list = (WORD)&noval;		/*;AN000;4 */
/*	sw1.p_nid = 2;					|* MR001-  *|	 */
	sw1.p_nid = 3;					/* MR001+  */
	strcpy(sw1.switch1,"/B");                       /*;AN000;4 */
	strcpy(sw1.switch2,"/A");                       /*;AN000;4 */
	strcpy(sw1.switch3,"/Z");                       /* MR001+  */

		/* Initialize SW2 data structure */
	sw2.p_match_flag = TIMESTRING;			/*;AN000;4 */
	sw2.p_function_flag = 0;			/*;AN000;4 */
	sw2.p_result_buf = (WORD)&time_buff;		/*;AN000;4 */
	sw2.p_value_list = (WORD)&noval;		/*;AN000;4 */
/*	sw2.p_nid = 2;					|* MR001-  *|	 */
	sw2.p_nid = 3;					/* MR001+  */
	strcpy(sw2.switch1,"/E");                       /*;AN000;4 */
	strcpy(sw2.switch2,"/L");                       /*;AN000;4 */
	strcpy(sw2.switch3,"/Y");                       /* MR001+  */


		/* Initialize SW3 data structure */
	sw3.p_match_flag = 0;				/*;AN000;4 */
	sw3.p_function_flag = 0;			/*;AN000;4 */
	sw3.p_result_buf = (WORD)&sw_buff;		/*;AN000;4 */
	sw3.p_value_list = (WORD)&noval;		/*;AN000;4 */
/*C01        sw3.p_nid = 4; */                               /*;AN000;4 */
        sw3.p_nid = 5;                                                  /*C01*/
	strcpy(sw3.switch1,"/S");                       /*;AN000;4 */
	strcpy(sw3.switch2,"/P");                       /*;AN000;4 */
	strcpy(sw3.switch3,"/M");                       /*;AN000;4 */
	strcpy(sw3.switch4,"/N");                       /*;AN000;4 */
        strcpy(sw3.switch5,"/D");                                       /*C01*/

		/* Initialize SW4 data structure */
	sw4.p_match_flag = 0;
	sw4.p_function_flag = 0;
	sw4.p_result_buf = (WORD)&sw_buff;
	sw4.p_value_list = (WORD)&noval;
	sw4.p_nid = 1;
	strcpy(sw4.switch4,"/?");

   /*********************************************/
   /* Also initialize all time and date values	*/
   /*********************************************/
	td.earlier_hour = 0;
	td.earlier_minute = 0;
	td.earlier_second = 0;
	td.later_hour = 0;
	td.later_minute = 0;
	td.later_second = 0;
	td.exact_hour = 0;				/* MR001+ */
	td.exact_minute = 0;				/* MR001+ */
	td.exact_second = 0;				/* MR001+ */
	td.before_year = 0;
	td.before_month = 0;
	td.before_day = 0;
	td.after_year = 0;
	td.after_month = 0;
	td.after_day = 0;
	td.exact_year = 0;				/* MR001+ */
	td.exact_month = 0;				/* MR001+ */
	td.exact_day = 0;				/* MR001+ */


   /**************************************************/
   /* Also initialize the message substitution list  */
   /**************************************************/
	sublist.sl_size1= SUBLIST_SIZE; 	/*;AN000;6*/
	sublist.sl_size2= SUBLIST_SIZE; 	/*;AN000;6*/
	sublist.one = 1;			/*;AN000;6*/
	sublist.two = 2;			/*;AN000;6*/
	sublist.zero1 = 0;			/*;AN000;6*/
	sublist.zero2 = 0;			/*;AN000;6*/
	sublist.pad_char1 = ' ';                /*;AN000;6*/
	sublist.pad_char2 = ' ';                /*;AN000;6*/

	return; 				/*;AN000;4 */
}						/*;AN000;4 */


/*************************************************/
/*
/* SUBROUTINE NAME:	check_for_device_names
/*
/* FUNCTION:
/*
/*	Make sure user not trying to restore a reserved device name
/*
/**************************************************/
void check_for_device_names(argv)				      /*;AN000;p2591*/
char	*argv[];						      /*;AN000;p2591*/
{								      /*;AN000;p2591*/
	union REGS qregs;					      /*;AN000;p2591*/
	char target[128];					      /*;AN000;p2591*/
	char *t;						      /*;AN000;p2591*/

#define CAPITALIZE_STRING 0x6521				      /*;AN000;p2591*/

	qregs.x.ax = CAPITALIZE_STRING; 			      /*;AN000;p2591*/
	qregs.x.dx = (WORD)argv[2];				      /*;AN000;p2591*/
	strcpy(target,argv[2]); 				      /*;AN000;p2591*/
	qregs.x.cx = strlen(target);				      /*;AN000;p2591*/
	intdos(&qregs,&qregs);					      /*;AN000;p2591*/
	strcpy(target,argv[2]); 				      /*;AN000;p2591*/

	for (t=&target[0]; *t!=NUL; t++)
	 if							      /*;AN000;p2591*/
	  ( strcmp(t,"LPT1")==0   ||                                  /*;AN000;p2591*/
	    strcmp(t,"LPT2")==0   ||                                  /*;AN000;p2591*/
	    strcmp(t,"PRN")==0    ||                                  /*;AN000;p2591*/
	    strcmp(t,"CON")==0    ||                                  /*;AN000;p2591*/
	    strcmp(t,"NUL")==0    ||                                  /*;AN000;p2591*/
	    strcmp(t,"AUX")==0    ||                                  /*;AN000;p2591*/
	    strcmp(t,"LPT1:")==0  ||                                  /*;AN000;p2591*/
	    strcmp(t,"LPT2:")==0  ||                                  /*;AN000;p2591*/
	    strcmp(t,"PRN:")==0   ||                                  /*;AN000;p2591*/
	    strcmp(t,"CON:")==0   ||                                  /*;AN000;p2591*/
	    strcmp(t,"NUL:")==0   ||                                  /*;AN000;p2591*/
	    strcmp(t,"AUX:")==0                                       /*;AN000;p2591*/
	  )							      /*;AN000;p2591*/
	 {							      /*;AN000;p2591*/
	   sublist.value1 = (char far *)t;			      /*;AN000;p2591*/
	   sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ;	      /*;AN000;p2591*/
	   sublist.one = 0;					      /*;AN000;p2591*/
	   sublist.max_width1 = (BYTE)strlen(t);		      /*;AN000;p2591*/
	   sublist.min_width1 = sublist.max_width1;		      /*;AN000;p2591*/

	   display_it(INVPARM,STND_ERR_DEV,1,NO_RESPTYPE,(BYTE)PARSEERROR);/*;AN000;p2591*/
	   usererror(INVALIDPARM);				      /*;AN000;p2591*/
	 }							      /*;AN000;p2591*/


	return; 						      /*;AN000;p2591*/
}								      /*;AN000;p2591*/

/*************************************************/
/*
/* SUBROUTINE NAME:	check_source_drive
/*
/* FUNCTION:
/*
/*	Verify drive letter and start building srcddir
/*
/**************************************************/
void check_source_drive(argv)		/*;AN000;4*/
char	*argv[];				/*;AN000;4*/
{						/*;AN000;4*/
	WORD  retcode;				/*;AC000;*/
	WORD  device_handle;
	WORD  action;
	BYTE  media_type;
	WORD  dnumwant = 1;
	BYTE  temp_array1[4];
	BYTE  temp_array2[4];
	union REGS qregs;					      /*;AN000;8*/
	union REGS reg;

	*argv[1]=(BYTE)com_toupper(*argv[1]);			      /*;AN000;4*/

	if (							      /*;AN000;4*/
	     *argv[1] < 'A'    ||                                     /*;AN000;4*/
	     *argv[1] > 'Z'    ||                                     /*;AN000;4*/
	     *(argv[1]+1)!=':' ||                                     /*;AN000;4*/
	     *(argv[1]+2)!=NUL					      /*;AN000;4*/
	   )							      /*;AN000;4*/
	  {							      /*;AN000;4*/
	   display_it(INVALID_DRIVE,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
	   usererror(INVALIDDRIVE);				      /*;AN000;4*/
	  }							      /*;AN000;4*/

	srcd = (BYTE)*argv[1];					      /*;AN000;4*/
	srcddir[0] = srcd;					      /*;AN000;4*/
	srcddir[1] = ':';                                             /*;AN000;4*/
	srcddir[2] = NUL;					      /*;AN000;4*/

   /***********************************************************************/
   /* dosopen to find out whether the src drive exist			  */
   /* and dosdevioctl to find out whether it is a removable drive	  */
   /***********************************************************************/
       retcode =						      /*;AC000;4*/
	 DOSOPEN						      /*;AC000;4*/
	  ( (char far *)&srcddir[0],				      /*;AC000;4*/
	    (unsigned far *)&device_handle,			      /*;AC000;4*/
	    (unsigned far *)&action,				      /*;AC000;4*/
	    (DWORD)0,			/*file size*/		      /*;AC000;4*/
	    0,				/*file attribute*/	      /*;AC000;4*/
	    0x01,			/*if file exist, open it*/    /*;AC000;4*/
					/*if file not exist, fail it*//*;AC000;4*/
	    0x80c2,			/*deny write, read only*/     /*;AC000;4*/
	    (DWORD)0			/*reserved*/		      /*;AC000;4*/
	  );							      /*;AC000;4*/

       if (retcode != NOERROR)					      /*;AC000;4*/
	{							      /*;AC000;4*/
	  display_it(INVALID_DRIVE,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
	  usererror(INVALIDDRIVE);				      /*;AC000;4*/
	}							      /*;AC000;4*/

     /************************************/			      /*;AC000;4*/
     /* See if source drive is removable */			      /*;AC000;4*/
     /************************************/			      /*;AC000;4*/

	if(device_handle > 0xffe4)  {
	    device_handle = -(int)device_handle;
	    device_handle--;
	  }
	reg.h.ah = 0x44;
	reg.h.al = 0x8;
	reg.x.bx = device_handle;
	intdos(&reg, &reg);
	if(reg.x.cflag)  {	/* possible only for network drives */
/* M001 Start - NSM - changes to detect net work drives */
	    reg.h.ah = 0x44;
	    reg.h.al = 0x9;
	    reg.x.bx = device_handle;
	    intdos(&reg,&reg);		/* get device drive attributes */
	    if (reg.x.cflag) {		/* impossible, since we must have */
		retcode = reg.x.ax;	/* checked the drive before this */
	    }
	    else {
		retcode = NOERROR;
		media_type = (reg.x.dx & 0x1000)?1:0;
	    }
 	  }
	else {
		media_type = reg.h.al;
		retcode = NOERROR;
	}
/* M001 End */

      if (retcode != NOERROR)					      /*;AC000;4*/
       { display_it(INVALID_DRIVE,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
	 usererror(INVALIDDRIVE);				      /*;AC000;4*/
       }							      /*;AC000;4*/

#define REMOVABLE 0						      /*;AC000;4*/
   if (media_type != REMOVABLE) 				      /*;AC000;4*/
      set_reset_test_flag(&control_flag2,SRC_HDISK,SET);	      /*;AC000;4*/

    else	/* Source disk is removable */			      /*;AC000;4*/
     {								      /*;AC000;4*/
	temp_array1[0] = (BYTE)((dnumwant / 10) + '0');               /*;AC000;4*/
	temp_array1[1] = (BYTE)((dnumwant % 10) + '0');               /*;AC000;4*/
	temp_array1[2] = NUL;					      /*;AC000;4*/
	temp_array2[0] = srcd;					      /*;AC000;4*/
	temp_array2[1] = NUL;					      /*;AC000;4*/

	sublist.value1 = (char far *)temp_array1;		      /*;AN000;6*/
	sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ;	      /*;AN000;6*/
	sublist.max_width1 = (BYTE)strlen(temp_array1); 	      /*;AN000;6*/
	sublist.min_width1 = sublist.max_width1;		      /*;AN000;6*/

	sublist.value2 = (char far *)temp_array2;		      /*;AN000;6*/
	sublist.flags2 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ;	      /*;AN000;6*/
	sublist.max_width2 = (BYTE)strlen(temp_array2); 	      /*;AN000;6*/
	sublist.min_width2 = sublist.max_width2;		      /*;AN000;6*/

	display_it(INSERT_SOURCE_DISK,STND_ERR_DEV,2,NO_RESPTYPE,(BYTE)UTIL_MSG); /*;AN000;6*/
	display_it(PRESS_ANY_KEY,STND_ERR_DEV,0,ANY_KEY_RESPTYPE,(BYTE)UTIL_MSG); /*;AN000;6*/

				/* If single drive system, eliminates double prompting */
				/* for user to "Insert diskette for drive %1" */
	qregs.x.ax = SETLOGICALDRIVE;				      /*;AN000;8*/
	qregs.h.bl = srcddir[0] - 'A' + 1;                            /*;AN000;8*/
	intdos(&qregs,&qregs);					      /*;AN000;8*/

     }								      /*;AC000;4*/
	return; 						      /*;AN000;4*/
}								      /*;AN000;4*/

/*************************************************/
/*
/* SUBROUTINE NAME:	check_target_filespec
/*
/* FUNCTION:
/*
/*	Verify the target filespec.
/*	 1. Validate destination drive, or use default if none specified
/*	 2. Validate path, or use current dir if not specified
/*	 3. Validate the file name
/*
/**************************************************/
void check_target_filespec(argc,argv)				      /*;AN000;4*/
int	argc;							      /*;AN000;4*/
char	*argv[];						      /*;AN000;4*/
{								      /*;AN000;4*/
	WORD  retcode;						      /*;AC000;*/
	WORD  device_handle;
	WORD  action;
	BYTE  media_type;
	DWORD drive_map;
	BYTE  temp_destddir[MAXPATH+2];
	BYTE  temp_array1[4];
	WORD  default_drive_num;
	WORD  destd_num;
	WORD  dirlen = MAXPATH;
	BYTE  tdestddir[MAXPATH+3];
	BYTE  ttdestddir[MAXPATH+3];
	BYTE  srcf[MAXPATHF];
	BYTE  argv2_has_switch;
	BYTE  search_string[MAXPATHF+2];
	BYTE  tempp[MAXPATH];
	WORD  j,k,z;
	BYTE *c;
	BYTE  backdir;
	WORD  dnumwant = 1;
	union REGS qregs;					      /*;AN000;8*/
	union REGS reg;


	/**************************/
	/*  Uppercase the string  */
	/**************************/
#define CAPITALIZE_STRING 0x6521				      /*;AN000;p????*/

	qregs.x.ax = CAPITALIZE_STRING; 			      /*;AN000;p????*/
	qregs.x.dx = (WORD)argv[2];				      /*;AN000;p????*/
	strcpy(tempp,argv[2]);					      /*;AN000;p????*/
	qregs.x.cx = strlen(tempp);				      /*;AN000;p????*/
	intdos(&qregs,&qregs);					      /*;AN000;p????*/


	/***************************************************/
	/* If no drive letter specified, use current drive */
	/***************************************************/
	if (							      /*;AC000;4*/
	     *(argv[2]+1)!=':' ||                                     /*;AC000;4*/
	     *argv[2] < 'A'    ||                                     /*;AC000;4*/
	     *argv[2] > 'Z'                                           /*;AC000;4*/
	   )							      /*;AC000;4*/
	  {							      /*;AC000;4*/
	   DOSQCURDISK						      /*;AC000;4*/
	    ( (unsigned far *)&default_drive_num,		      /*;AC000;4*/
	      (DWORD far *) &drive_map				      /*;AC000;4*/
	    );							      /*;AC000;4*/
	   destd = (BYTE)(default_drive_num + 'A' - 1);               /*;AC000;4*/
	  }							      /*;AC000;4*/
	 else							      /*;AC000;4*/
	  {	       /* User specified the destination drive*/      /*;AC000;4*/
	    destd = (BYTE)*argv[2];				      /*;AC000;4*/
	    argv[2] = argv[2] + 2;				      /*;AC000;4*/
	  }							      /*;AC000;4*/

	destddir[0] = destd;					      /*;AC000;4*/
	destddir[1] = ':';                                            /*;AC000;4*/
	destddir[2] = NUL;					      /*;AC000;4*/

   /***********************************************************************/
   /* if source drive and destination drive are the same, output error msg*/
   /***********************************************************************/
   if (srcd == destd)						      /*;AC000;4*/
    {								      /*;AC000;4*/
     display_it(SOURCE_TARGET_SAME,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
     usererror(INVALIDPARM);					      /*;AC000;4*/
    }								      /*;AC000;4*/

   /***********************************************************************/
   /* dosopen to find out whether the destination drive is exist	  */
   /* and dosdevioctl to find out whether it is a removable drive	  */
   /***********************************************************************/

       retcode =						      /*;AC000;4*/
	DOSOPEN 						      /*;AC000;4*/
	 ( (char far *)&destddir[0],				      /*;AC000;4*/
	   (unsigned far *)&device_handle,			      /*;AC000;4*/
	   (unsigned far *)&action,				      /*;AC000;4*/
	   (DWORD)0,		/*file size*/			      /*;AC000;4*/
	   0,			/*file attribute*/		      /*;AC000;4*/
	   0x01,		/*if file exist, open it*/	      /*;AC000;4*/
				/*if file not exist, fail it*/	      /*;AC000;4*/
	   0x80c2,		/*deny write, read only*/	      /*;AC000;4*/
	   (DWORD)0		/*reserved*/			      /*;AC000;4*/
	 );							      /*;AC000;4*/

	  if (retcode != NOERROR)/*if open fail*/		      /*;AC000;4*/
	   {							      /*;AC000;4*/
	     display_it(INVALID_DRIVE,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
	     usererror(INVALIDDRIVE);				      /*;AC000;4*/
	   }							      /*;AC000;4*/

     /************************************/			      /*;AC000;4*/
     /* See if target drive is removable */			      /*;AC000;4*/
     /************************************/			      /*;AC000;4*/

	if(device_handle > 0xffe4)  {
	    device_handle = -(int)device_handle;
	    device_handle--;
	  }
	reg.h.ah = 0x44;
	reg.h.al = 0x8;
	reg.x.bx = device_handle;
	intdos(&reg, &reg);
	if(reg.x.cflag)  {
/* M001 Start - NSM changes to detect network drives */
	    reg.h.ah = 0x44;
	    reg.h.al = 0x9;
	    reg.x.bx = device_handle;
	    intdos(&reg,&reg);		/* get device drive attributes */
	    if (reg.x.cflag) {		/* impossible, since we must have */
		retcode = reg.x.ax;	/* checked the drive before this */
	    }
	    else {
		retcode = NOERROR;
		media_type = (reg.x.dx & 0x1000)?1:0;
	    }
 	  }
	else {
		media_type = reg.h.al;
		retcode = NOERROR;
	}
/* M001 End */

      if (retcode != NOERROR)					      /*;AC000;4*/
       { display_it(INVALID_DRIVE,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
	 usererror(INVALIDDRIVE);				      /*;AC000;4*/
       }							      /*;AC000;4*/

   if (media_type == REMOVABLE) 				      /*;AC000;4*/
    { temp_array1[0] = destd;					      /*;AC000;4*/
      temp_array1[1] = NUL;					      /*;AC000;4*/
      sublist.value1 = (char far *)temp_array1; 		      /*;AN000;6*/
      sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ;		      /*;AN000;6*/
      sublist.max_width1 = (BYTE)strlen(temp_array1);		      /*;AN000;6*/
      sublist.min_width1 = sublist.max_width1;			      /*;AN000;6*/

     display_it(INSERT_TARGET_DISK,STND_ERR_DEV,1,NO_RESPTYPE,(BYTE)UTIL_MSG); /*;AN000;6*/
     display_it(PRESS_ANY_KEY,STND_ERR_DEV,0,ANY_KEY_RESPTYPE,(BYTE)UTIL_MSG); /*;AN000;6*/
    }								      /*;AC000;4*/

				/* If single drive system, eliminates double prompting */
				/* for user to "Insert diskette for drive %1" */
   qregs.x.ax = SETLOGICALDRIVE;				      /*;AN000;8*/
   qregs.h.bl = destddir[0] - 'A' + 1;                                /*;AN000;8*/
   intdos(&qregs,&qregs);					      /*;AN000;8*/

   /**********************************************************************/
   /*  save current directory of destination disk to be reset back later */
   /**********************************************************************/

   destd_num = (WORD) (destd - 'A' +1);                               /*;AC000;4*/

   /*  get current directory of destd_num (DosQCurDir) */
   if ((retcode =						      /*;AC000;4*/
	DOSQCURDIR						      /*;AC000;4*/
	 ( destd_num,						      /*;AC000;4*/
	   (char far *) tdestddir,				      /*;AC000;4*/
	   (unsigned far *) &dirlen)				      /*;AC000;4*/
	 ) != 0)						      /*;AC000;4*/
    {								      /*;AC000;4*/
	display_it(INVALID_DRIVE,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
	usererror(INVALIDDRIVE);				      /*;AC000;4*/
    }								      /*;AC000;4*/

#define BACKSLASH 0x5c

   if (strlen(tdestddir) != 1)					      /*;AC000;4*/
    { strcpy(temp_destddir,"\\");                                     /*;AC000;4*/
      strcat(temp_destddir,tdestddir);				      /*;AC000;4*/
      strcpy(tdestddir,temp_destddir);				      /*;AC000;4*/
    }								      /*;AC000;4*/


   /**********************************************************************/
   /* The next parameter has to be a file name with or without path,	 */
   /* or a switch.  In the case of there is no path, the current path	 */
   /* is used.	In the case of there is no file name, the global file	 */
   /* name *.* is used							 */
   /**********************************************************************/
   /*	argv[2] is a drive spec*/				      /*;AC000;4*/
   if (*(argv[2]+1)==':' && *argv[2] >= 'A' && *argv[2] <= 'Z' && argc!=2)      /*;AC000;4*/
    {								      /*;AN000;6*/
      display_it(INVPARM,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)PARSEERROR);/*;AN000;6*/
      usererror(INVALIDPARM);					      /*;AC000;4*/
    }								      /*;AC000;4*/
   else 							      /*;AC000;4*/
    {  /*if argv[2] is not a drive spec */			      /*;AC000;4*/
       /*if argv[2] started with '/' (is a switch) or there is no argv[i]*/     /*;AC000;4*/
       if (*argv[2] == '/' ||  *argv[2] == NUL || argc ==2)           /*;AC000;4*/
	{  strcpy(srcf,tdestddir);				      /*;AC000;4*/
	   strcat(srcf,"\\*.*");                                      /*;AC000;4*/
	}							      /*;AC000;4*/
       else							      /*;AC000;4*/
	{ /*argv[2] does not started with / */			      /*;AC000;4*/
	   /* find out whether part of argv[2] is switch specification */	/*;AC000;4*/
	   for (k = 0; argv[2][k] != '/' && argv[2][k] != NUL;   ++k);/*;AC000;4*/
	   if (argv[2][k] == '/')                                     /*;AC000;4*/
	    {							      /*;AC000;4*/
	      argv[2][k] = NUL; 				      /*;AC000;4*/
	      argv2_has_switch = TRUE;				      /*;AC000;4*/
	    }							      /*;AC000;4*/

	   /*if argv[2] is \\, invalid parm */			      /*;AC000;4*/
	   if (argv[2][0] == '\\' && argv[2][1] == '\\' || argv[2][0] == ':')   /*;AC000;;4*/
	    {							      /*;AN000;6*/
	      display_it(INVPARM,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)PARSEERROR);/*;AN000;6*/
	      usererror(INVALIDPARM);				      /*;AC000;4*/
	    }							      /*;AC000;4*/

	   /*if argv[2] starts with '\' (it is a complete path)*/     /*;AC000;4*/
	   if (*argv[2] == '\\')                                      /*;AC000;4*/
	     strcpy(srcf,argv[2]);				      /*;AC000;4*/
	   else 						      /*;AC000;4*/
	      /* it is not a complete path, have to put current path in  */	/*;AC000;;4*/
	      /* front of the string to build a complete path */      /*;AC000;4*/
	    {  strcpy(srcf,tdestddir);				      /*;AC000;4*/
	       if (strlen(tdestddir) != 1)			      /*;AC000;4*/
		    strcat(srcf,"\\");                                /*;AC000;4*/
	       strcat(srcf,argv[2]);				      /*;AC000;4*/
	    } /*endif*/ 					      /*;AC000;4*/
	} /*end of argv[2] does not start with '/' */                 /*;AC000;4*/

       j = strlen(srcf);					      /*;AC000;4*/
       z = 0;							      /*;AC000;4*/
       do							      /*;AC000;4*/
	{  for (;srcf[z] != '.' && srcf[z] != NUL;   ++z);            /*;AC000;4*/
	   if (srcf[z] == '.' && srcf[z+1] == '.' &&                  /*;AC000;4*/
	       (srcf[z+2] == '\\' || srcf[z+2] == NUL))               /*;AC000;4*/
	    { backdir = TRUE;					      /*;AC000;4*/
	      break;						      /*;AC000;4*/
	    }							      /*;AC000;4*/
	   z = z+1;						      /*;AC000;4*/
	}							      /*;AC000;4*/
	while (z < j);						      /*;AC000;4*/

       /*validate the path*/					      /*;AC000;4*/
       for (z = j; srcf[z] != '\\'; --z);                             /*;AC000;4*/
       strcpy(tempp,srcf);					      /*;AC000;4*/
       tempp[z] = NUL;						      /*;AC000;4*/

       for (z = 0; tempp[z] != '*' && tempp[z] != NUL;   ++z);        /*;AC000;4*/
       if (tempp[z] == '*' )                                          /*;AC000;4*/
	{  display_it(PATH_NOT_FOUND,STND_ERR_DEV,1,NO_RESPTYPE,(BYTE)UTIL_MSG);     /*;AN000;6*/
	   usererror(INVALIDPARM);				      /*;AC000;4*/
	}							      /*;AC000;4*/

       if (backdir == TRUE)					      /*;AC000;4*/
	{  search_string[0] = destd;				      /*;AC000;4*/
	   search_string[1] = ':';                                    /*;AC000;4*/
	   search_string[2] = NUL;				      /*;AC000;4*/
	   if (srcf[0]	== NUL) 				      /*;AC000;4*/
	      strcat(search_string,"\\");                             /*;AC000;4*/
	   else 						      /*;AC000;4*/
	      strcat(search_string, tempp);			      /*;AC000;4*/

	   if(chdir(search_string)!=0)				      /*;AC000;4*/
	    { sublist.value1 = (char far *)argv[2];		      /*;AN000;6*/
	      sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ;	      /*;AN000;6*/
	      sublist.max_width1 = (BYTE)strlen(argv[2]);	      /*;AN000;6*/
	      sublist.min_width1 = sublist.max_width1;		      /*;AN000;6*/
	      display_it(PATH_NOT_FOUND,STND_ERR_DEV,1,NO_RESPTYPE,(BYTE)UTIL_MSG);  /*;AN000;6*/
	      usererror(INVALIDPARM);				      /*;AC000;4*/
	    }							      /*;AC000;4*/

	   dirlen = MAXPATH;					      /*;AC000;4*/
	   if ((retcode = DOSQCURDIR(destd_num, 		      /*;AC000;4*/
	       (char far *) ttdestddir, 			      /*;AC000;4*/
	       (unsigned far *) &dirlen)) != NOERROR)		      /*;AC000;4*/
	    {							      /*;AC000;4*/
	     com_msg(retcode);					      /*;AC000;4*/
	     usererror(retcode);				      /*;AC000;4*/
	    }							      /*;AC000;4*/
	   /* endif */						      /*;AC000;4*/

	   temp_destddir[0] = destd;				      /*;AC000;4*/
	   temp_destddir[1] = ':';                                    /*;AC000;4*/
	   temp_destddir[2] = NUL;				      /*;AC000;4*/
	   strcat(temp_destddir,tdestddir);			      /*;AC000;4*/
	   chdir(temp_destddir);				      /*;AC000;4*/

	   if (strlen(ttdestddir) != 1) 			      /*;AC000;4*/
	    { strcpy(temp_destddir,"\\");                             /*;AC000;4*/
	      strcat(temp_destddir,ttdestddir); 		      /*;AC000;4*/
	      strcpy(ttdestddir,temp_destddir); 		      /*;AC000;4*/
	    }							      /*;AC000;4*/

	   strcat(ttdestddir,"\\");                                   /*;AC000;4*/
	   strcat(ttdestddir,srcf+z+1); 			      /*;AC000;4*/
	   strcpy(srcf,ttdestddir);				      /*;AC000;4*/
	} /*end of if backdir is true */			      /*;AC000;4*/

       /* The documentation says if path is specified, file name has to */
       /* be specified also.  This logic actually allows user to specify*/
       /* path without specify filename, as long as the path end with	*/
       /* '\'.*/
       /*If *srcf ends with '\', add "*.*" to the end*/               /*;AC000;4*/
       j = strlen(srcf);					      /*;AC000;4*/
       if (srcf[j-1] == '\\')                                         /*;AC000;4*/
	   strcat(srcf,"*.*");                                        /*;AC000;4*/
       if (argv2_has_switch == TRUE)				      /*;AC000;4*/
	{  *(argv[2]+k) = '/';                                        /*;AC000;4*/
	   argv[2] = argv[2] + k;				      /*;AC000;4*/
	}   /* end of if argv[2] started with '/' */                  /*;AC000;4*/
   }  /* end of checking for argv[2] */ 			      /*;AC000;4*/

  /**********************************************************************/
  /* add '\' at the beginning of the current destination directory      */
  /**********************************************************************/
   temp_destddir[0] = destd;					      /*;AC000;4*/
   temp_destddir[1] = ':';                                            /*;AC000;4*/
   temp_destddir[2] = NUL;					      /*;AC000;4*/
   strcat(temp_destddir,tdestddir);				      /*;AC000;4*/
   strcpy(destddir,temp_destddir);				      /*;AC000;4*/

   /************************************************************************/
   /* separate the filename for search into prefix(inpath),		   */
   /* filename(infname), and file extension (infext)			   */
   /* Also take care of the situation that user enter '.' only             */
   /* for file spec.							   */
   /************************************************************************/
   separate(srcf,inpath,infname,infext,infspec);		      /*;AC000;4*/
   if (strlen(infname) > MAXFNAME-1 ||				      /*;AC000;4*/
       strlen(infext) > MAXFEXT-1   ||				      /*;AC000;4*/
       strlen(inpath) > MAXPATH-1  ||				      /*;AC000;4*/
       strcmp(infspec,"LPT1")==0   ||                                 /*;AC000;4*/
       strcmp(infspec,"LPT2")==0   ||                                 /*;AC000;4*/
       strcmp(infspec,"PRN")==0    ||                                 /*;AC000;4*/
       strcmp(infspec,"CON")==0    ||                                 /*;AC000;4*/
       strcmp(infspec,"NUL")==0    ||                                 /*;AC000;4*/
       strcmp(infspec,"AUX")==0    ||                                 /*;AC000;4*/
       strcmp(infspec,"LPT1:")==0  ||                                 /*;AC000;4*/
       strcmp(infspec,"LPT2:")==0  ||                                 /*;AC000;4*/
       strcmp(infspec,"PRN:")==0   ||                                 /*;AC000;4*/
       strcmp(infspec,"CON:")==0   ||                                 /*;AC000;4*/
       strcmp(infspec,"NUL:")==0   ||                                 /*;AC000;4*/
       strcmp(infspec,"AUX:")==0 )                                    /*;AC000;4*/
   {								      /*;AC000;4*/
       sublist.value1 = (char far *)&infspec[0];		      /*;AN000;6*/
       sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; 	      /*;AN000;6*/
       sublist.one = 0; 	/* Yes, this is right */	      /*;AN000;6*/
       sublist.max_width1 = (BYTE)strlen(infspec);		      /*;AN000;6*/
       sublist.min_width1 = sublist.max_width1; 		      /*;AN000;6*/

       display_it(INVPARM,STND_ERR_DEV,1,NO_RESPTYPE,(BYTE)PARSEERROR);/*;AN000;6*/
       usererror(INVALIDPARM);	     /* invalid parm */ 	      /*;AC000;4*/
   }								      /*;AC000;4*/

   /************************************************************************/
   /* set wildcard flag according to whether there is '*' or/and  '?' in   */
   /* file specification						   */
   /************************************************************************/
   c = infspec; 						      /*;AC000;4*/
   while (*c)							      /*;AC000;4*/
    {								      /*;AC000;4*/
      if (*c == '*' || *c == '?')                                     /*;AC000;4*/
       { set_reset_test_flag(&control_flag,WILDCARD,SET);	      /*;AC000;4*/
	 break; 						      /*;AC000;4*/
       }							      /*;AC000;4*/
      else							      /*;AC000;4*/
	c = c+1;						      /*;AC000;4*/
    }								      /*;AC000;4*/


	return; 				/*;AN000;4*/
}						/*;AN000;4*/

/*************************************************/
/*
/* SUBROUTINE NAME:	process_switch
/*
/* FUNCTION:
/*
/*	Identify the switch (/S,/P,/M,/N,/B:,/A:,/E:,/L:)
/*	 entered and handle it
/*
/**************************************************/
void process_switch(buff_addr)				      /*;AN000;4*//*;AC002;*/
unsigned buff_addr;						      /*;AN000;4*/
{								      /*;AN000;4*/

	if (buff_addr == (unsigned)&sw_buff)			      /*;AN000;4*/
	 {							      /*;AN000;4*/

	 	/* /? - options help check */

	 	if (sw_buff.sw_synonym_ptr == (WORD)&sw4.switch4[0])
			display_options_exit();

	   if (sw_buff.sw_synonym_ptr == (WORD)&sw3.switch1[0])       /*;AN000;4   /S */
	   {
			set_reset_test_flag(&rtswitch, SUB, SET);		      /*;AN000;4*/
	   }

	   if (sw_buff.sw_synonym_ptr == (WORD)&sw3.switch2[0])       /*;AN000;4   /P */
	     {							      /*;AN000;4*/
	      set_reset_test_flag(&rtswitch, PROMPT, SET);	      /*;AN000;4*/
	      set_reset_test_flag(&control_flag, SWITCHES, SET);      /*;AN000;4*/
	     }							      /*;AN000;4*/

	   if (sw_buff.sw_synonym_ptr == (WORD)&sw3.switch3[0])       /*;AN000;4   /M */
	     {							      /*;AN000;4*/
	      set_reset_test_flag(&rtswitch, Revised, SET);	      /*;AN000;4*/
	      set_reset_test_flag(&control_flag, SWITCHES, SET);      /*;AN000;4*/
	     }							      /*;AN000;4*/

	   if (sw_buff.sw_synonym_ptr == (WORD)&sw3.switch4[0])       /*;AN000;4   /N */
	     {							      /*;AN000;4*/
	      set_reset_test_flag(&rtswitch, NOTEXIST, SET);	      /*;AN000;4*/
	      set_reset_test_flag(&control_flag, SWITCHES, SET);      /*;AN000;4*/
	     }							      /*;AN000;4*/
           if (sw_buff.sw_synonym_ptr == (WORD)&sw3.switch5[0])         /*C01*/
             {                                                          /*C01*/
              set_reset_test_flag(&rtswitch2, DIR, SET);                /*C01*/
             }                                                          /*C01*/
	 }							      /*;AN000;4*/


	if (buff_addr == (unsigned)&time_buff)			      /*;AN000;4*/
	 {							      /*;AN000;4*/
	   check_time(time_buff.hours,time_buff.minutes,time_buff.seconds);	  /*;AN000;4*//*;AC002;*/

	   if (time_buff.tb_synonym_ptr == (WORD)&sw2.switch1[0])     /*;AN000;4   /E */
	     {							      /*;AN000;4*/
	       td.earlier_hour =   time_buff.hours;		      /*;AN000;4*/
	       td.earlier_minute = time_buff.minutes;		      /*;AN000;4*/
	       td.earlier_second = time_buff.seconds;		      /*;AN000;4*/
	       set_reset_test_flag(&rtswitch, EARLIER, SET);	      /*;AN000;4*/
	       set_reset_test_flag(&control_flag, SWITCHES, SET);     /*;AN000;4*/
	     }							      /*;AN000;4*/

	   if (time_buff.tb_synonym_ptr == (WORD)&sw2.switch2[0])     /*;AN000;4   /L */
	     {							      /*;AN000;4*/
	       td.later_hour =	 time_buff.hours;		      /*;AN000;4*/
	       td.later_minute = time_buff.minutes;		      /*;AN000;4*/
	       td.later_second = time_buff.seconds;		      /*;AN000;4*/
	       set_reset_test_flag(&rtswitch, LATER, SET);	      /*;AN000;4*/
	       set_reset_test_flag(&control_flag, SWITCHES, SET);     /*;AN000;4*/
	     }							      /*;AN000;4*/

	   if (time_buff.tb_synonym_ptr == (WORD)&sw2.switch3[0])     /* MR001+    /Y */
	     {							      /* MR001+ */
	       td.exact_hour =	 time_buff.hours;		      /* MR001+ */
	       td.exact_minute = time_buff.minutes;		      /* MR001+ */
	       td.exact_second = time_buff.seconds;		      /* MR001+ */
	       set_reset_test_flag(&rtswitch7, EXACT_TIME, SET);      /* MR001+ */
	       set_reset_test_flag(&control_flag, SWITCHES, SET);     /* MR001+ */
	     }							      /* MR001+ */


	 }							      /*;AN000;4*/


	if (buff_addr == (unsigned)&date_buff)			      /*;AN000;4*/
	 {							      /*;AN000;4*/
	   check_date(date_buff.year,date_buff.month,date_buff.day);	  /*;AN000;4*//*;AC002;*/

	   if (date_buff.db_synonym_ptr == (WORD)&sw1.switch1[0])     /*;AN000;4  /B */
	     {							      /*;AN000;4*/
	       td.before_year =  date_buff.year;		      /*;AN000;4*/
	       td.before_month = date_buff.month;		      /*;AN000;4*/
	       td.before_day =	 date_buff.day; 		      /*;AN000;4*/
	       set_reset_test_flag(&rtswitch, BEFORE, SET);	      /*;AN000;4*/
	       set_reset_test_flag(&control_flag, SWITCHES, SET);     /*;AN000;4*/
	     }							      /*;AN000;4*/

	   if (date_buff.db_synonym_ptr == (WORD)&sw1.switch2[0])     /*;AN000;4  /A */
	     {							      /*;AN000;4*/
	       td.after_year =	date_buff.year; 		      /*;AN000;4*/
	       td.after_month = date_buff.month;		      /*;AN000;4*/
	       td.after_day =	date_buff.day;			      /*;AN000;4*/
	       set_reset_test_flag(&rtswitch, AFTER, SET);	      /*;AN000;4*/
	       set_reset_test_flag(&control_flag, SWITCHES, SET);     /*;AN000;4*/
	     }							      /*;AN000;4*/

	   if (date_buff.db_synonym_ptr == (WORD)&sw1.switch3[0])     /* MR001+   /Z */
	     {							      /* MR001+ */
	       td.exact_year =	date_buff.year; 		      /* MR001+ */
	       td.exact_month = date_buff.month;		      /* MR001+ */
	       td.exact_day =	date_buff.day;			      /* MR001+ */
	       set_reset_test_flag(&rtswitch7, EXACT_DATE, SET);      /* MR001+ */
	       set_reset_test_flag(&control_flag, SWITCHES, SET);     /* MR001+ */
	     }							      /* MR001+ */


	 }							      /*;AN000;4*/

	return; 						      /*;AN000;4*/
}								      /*;AN000;4*/
