2 /*---------------------------------
3 /* SOURCE FILE NAME: RTT3.C
4 /*---------------------------------
12 #include "dos.h" /*;AN000;2*/
13 #include "comsub.h" /* common subroutine def'n */
16 #include "process.h" /*;AN000;p972*/
18 extern BYTE filename[12];
19 extern BYTE destddir[MAXPATH+3];
20 extern BYTE srcddir[MAXPATH+3];
22 extern BYTE control_flag;
23 extern BYTE control_flag2;
24 char far *buf_pointer;
25 char far *control_buf_pointer;
26 unsigned control_selector;
27 extern BYTE dest_file_spec[MAXFSPEC];
28 extern unsigned dest_file_handle;
29 extern BYTE append_indicator; /*;AN000;2*/
30 extern WORD original_append_func; /*;AN000;2*/
31 extern struct subst_list sublist; /*;AN000;6 Message substitution list */
32 extern char response_buff[5]; /*;AN000;6*/
33 BYTE far *DBCS_ptr; /*;AN005;*/
34 char got_dbcs_vector = FFALSE; /*;AN005;*/
36 /***************** START OF SPECIFICATION ********************************
38 /* SUBROUTINE NAME : set_reset_test_flag
40 /* DESCRIPTIVE NAME : to set a flag, reset a flag, or test a flag.
42 /* FUNCTION: This subroutine is called when there is a need to set
43 /* a flag, reset a flag, or test a flag.
46 /* INPUT: (PARAMETERS)
47 /* flag - the flag to be set, reset, or tested.
48 /* targetbt - the target bit to be set, reset, or tested.
49 /* choice - = 1 if want to set
50 /* = 2 if want to reset
51 /* = 3 if want to test
53 /********************* END OF SPECIFICATIONS ********************************/
54 int set_reset_test_flag(flag,targetbt,choice)
56 BYTE *flag; /*the flag to be tested against*/
57 BYTE targetbt; /*the byte to be tested */
65 *flag = *flag | targetbt;
69 *flag = *flag & ~targetbt;
73 temp = *flag & targetbt;
75 return(FALSE); /*the tested bit is off*/
78 return(TRUE); /*the tested bit is on */
83 unexperror(UNEXPECTED);
87 return(FALSE); /* wrw! */
90 /***************** START OF SPECIFICATION ********************************
92 /* SUBROUTINE NAME : separate
94 /* DESCRIPTIVE NAME : Separate the given input string into 3 parts;
95 /* which is the path, filename, file extension, and
96 /* file specification.
98 /* FUNCTION: The subroutine searches the input string for the last '\',
99 /* which separates the path and file specification, and then
100 /* searches the file specification for '.', which separates
101 /* the filename and file extension. Also take care the
102 /* situation of the user enter '.' for file specification.
103 /* This subroutine also validate the file specification
104 /* and each path entered by the user by calling common
105 /* subroutine Comverflnm.
107 /* NOTE: The input string must start with '\'
108 /* All the output string are terminated by 00h
110 /* INPUT: (PARAMETERS)
111 /* instring - input string to be separated into path, filename,
112 /* and file extension.
115 /* path - output path name, always starts with '\' and not end
117 /* filename - output file name
118 /* fileext - output file extension
119 /* filespec - output file name and file extension
121 /********************** END OF SPECIFICATIONS *******************************/
122 void separate(instring,path,filename,fileext,filespec)
123 BYTE *instring; /* point to beginning of input string */
124 BYTE *path; /* point to beginning of path string */
125 BYTE *filename; /* point to beginning of file name */
126 BYTE *fileext; /* point to beginning of file ext. */
127 BYTE *filespec; /* point to beginning of file spec */
129 BYTE *iptr; /* working pointer */
130 BYTE *fptr; /* working pointer */
133 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
134 /* Find last non-DBCS backslash character */
135 /* fptr = com_strrchr(instring,'\\'); /*;AN000;p2532*/
138 i=strlen(instring); /*;AN005;*/
139 (i>=0) && (!chek_DBCS(instring,i,'\\')); /*;AN005;*/
144 fptr = instring + i; /*;AN005;*/
145 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
147 if (fptr!=instring || instring[0] == '\\')
149 *fptr = NULLC; /*;AC000;*/
150 strcpy(path, instring);
151 if (path[0] == NULLC)
155 strcpy(filespec, fptr);
157 if (filespec[0] == '.' && filespec[1] == NULLC)
159 strcpy(filename, "*");
160 strcpy(fileext, "*");
161 strcpy(filespec, "*.*");
164 { /*else if filespec is not '.'*/
165 for (iptr = fptr; *iptr!='.' && *iptr != NULLC; ++iptr);
170 strcpy(filename, fptr);
174 strcpy(fileext, iptr);
178 strcpy(filename, filespec);
195 /***************** START OF SPECIFICATION ********************************
197 /* SUBROUTINE NAME : initbuf
199 /* DESCRIPTIVE NAME : Initialize buffer for reading and writting.
201 /* FUNCTION: Allocate up to 64 K bytes buffer for reading and writing
202 /* data, and make sure its size is divisible by the sector
203 /* size of the restore drive.
207 /********************** END OF SPECIFICATIONS *******************************/
209 void initbuf(bufsize_long)
216 bufsize = MAXBUF; /*64K-1 */
217 /*do while allocate bufsize fail, bufsize = bufsize - DOWNSIZE*/
219 retcode = DOSALLOCSEG( (unsigned ) bufsize, /*buf length */
220 ( unsigned far * ) &selector, /* buf pointer*/
221 ( unsigned) 0 ); /* no sharing */
224 if (bufsize > DOWNSIZE)
225 bufsize = bufsize - DOWNSIZE;
232 if (bufsize != 0 && bufsize <= DOWNSIZE ) {
233 display_it(INSUFFICIENT_MEMORY,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG);/*;AN000;6*/
237 FP_SEG( buf_pointer ) = selector;
238 FP_OFF( buf_pointer ) = 0 ;
241 *bufsize_long = (DWORD)MAXBUF;
243 *bufsize_long = (DWORD)bufsize;
244 } /*end of subroutine*/
246 /***************** START OF SPECIFICATION ********************************
248 /* SUBROUTINE NAME : init_control_buf
250 /* DESCRIPTIVE NAME : Initialize buffer for control.XXX.
252 /* FUNCTION: Allocate buffer for reading in control.xxx
255 /* control_bufsize - the size of buffer
258 /********************** END OF SPECIFICATIONS *******************************/
259 void init_control_buf(control_file_len,control_bufsize) /* !wrw */
260 DWORD control_file_len; /* !wrw */
261 unsigned int *control_bufsize; /* !wrw */
263 unsigned bufsize; /* !wrw */
264 WORD retcode; /* !wrw */
266 bufsize = 3072; /* !wrw */
269 retcode = DOSALLOCSEG( (unsigned ) bufsize, /* !wrw */
270 ( unsigned far * ) &control_selector, /* !wrw */
271 ( unsigned) 0 ); /* !wrw */
274 if ( retcode != 0) /* If there is insufficient memory /* !wrw */
276 display_it(INSUFFICIENT_MEMORY,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG); /*;AN000;6*/
280 FP_SEG( control_buf_pointer ) = control_selector; /* !wrw */
281 FP_OFF( control_buf_pointer ) = 0 ; /* !wrw */
283 *control_bufsize = bufsize; /* !wrw */
285 } /*end of subroutine*/ /* !wrw */
287 /***************** START OF SPECIFICATION ********************************
289 /* SUBROUTINE NAME : unexperror
291 /* DESCRIPTIVE NAME : exit the program because of something really bad
294 /* FUNCTION: Exit the program because of unexpected error
297 /********************** END OF SPECIFICATIONS *******************************/
298 void unexperror(retcode)
301 exit_routine(retcode);
305 /***************** START OF SPECIFICATION ********************************
307 /* SUBROUTINE NAME : usererror
309 /* DESCRIPTIVE NAME : exit the program because of a user error
311 /********************** END OF SPECIFICATIONS *******************************/
312 void usererror(retcode)
319 /***************** START OF SPECIFICATION ********************************
321 /* SUBROUTINE NAME : exit_routine
323 /* DESCRIPTIVE NAME : exit the program
325 /* FUNCTION: 1. output msg if there is a sharing error.
326 /* 2. if PCDOS, convert return codes to error levels
327 /* 3. exit the program
331 /* INPUT: (PARAMETERS)
332 /* retcode - the reason of error
335 /********************** END OF SPECIFICATIONS *******************************/
336 void exit_routine(retcode)
339 union REGS regs; /*;AN000;2*/
345 /* if flag indicates there is a SHAREERROR */
346 if (retcode == NORMAL &&
347 set_reset_test_flag(&control_flag,SHARERROR,TEST)==TRUE)
352 case NORMAL: retcode = PC_NORMAL;
354 case NOFILES: retcode = PC_NOFILES;
356 case SHARERR: retcode = PC_SHARERR;
358 case TUSER: retcode = PC_TUSER;
360 default: retcode = PC_OTHER;
365 if (append_indicator == DOS_APPEND) /*;AN000;2 If append /x was reset*/
367 regs.x.ax = SET_STATE; /*;AN000;2*/
368 regs.x.bx = original_append_func; /*;AN000;2*/
369 int86(0x2f,®s,®s); /*;AN000;2*/
372 exit(retcode); /*;AN000;p972*/
375 /***************** START OF SPECIFICATION ********************************
377 /* SUBROUTINE NAME : signal_handler_routine
379 /* DESCRIPTIVE NAME : handle the situation that the user terminate
380 /* the program by Control-break.
382 /* FUNCTION: This subroutine change the directory of the
383 /* destination disk back to the original directory.
384 /* If there is a file in the middle of restoring, close
385 /* the file, deleted the partially restored file, and
387 /* Then exit with error level TUSER.
390 /********************** END OF SPECIFICATIONS *******************************/
391 void pascal far signal_handler_routine()
395 DWORD dw = 0L; /* reserved double word*/
397 /*change dir to the original directory of the destination disk*/
399 /**************************************************************/
400 /*if PARTIAL flag is on, close and delete the destination file*/
401 /**************************************************************/
402 if (set_reset_test_flag(&control_flag,PARTIAL,TEST) == TRUE) {
403 /* close the partially completed destination file*/
404 DOSCLOSE(dest_file_handle);
405 /* delete the partially completed destination file*/
406 if ((retcode = DOSDELETE((char far *) dest_file_spec, dw)) != 0) {
407 /*set file mode to 0*/
408 if ((retcode = DOSSETFILEMODE((char far *)dest_file_spec,
409 (unsigned) 0x00, dw)) != 0)
414 /* delete the partially completed destination file*/
415 if ((retcode = DOSDELETE((char far *) dest_file_spec, dw)) != 0) {
420 display_it(LAST_FILE_NOT_RESTORED,STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG); /*;AN000;6*/
424 } /* end of signal_handler*/
426 /************************************************************/
428 /* SUBROUTINE NAME: display_it (added for DOS 4.00)
430 /* SUBROUTINE FUNCTION:
431 /* Display the requested message to the standard output device.
434 /* 1) (WORD) Number of the message to be displayed.
435 /* 2) (WORD) Handle to be written to.
436 /* 3) (WORD) Substitution Count
437 /* 4) (WORD) Flag indicating user should "Strike any key..."
440 /* The message corresponding to the requested msg number will
441 /* be written to the requested handle. If requested, substitution
442 /* text will be inserted as required. The Substitution List
443 /* is global and, if used, will be initialized by DISPLAY_MSG
444 /* before calling this routine.
447 /* Message will be successfully written to requested handle.
450 /* None. Note that theoretically an error can be returned from
451 /* SYSDISPMSG, but there is nothing that the application can do.
454 /************************************************************/
455 #define CLASS -1 /* Goes in DH register */ /*;AN000;6*/
456 #define NUL_POINTER 0 /* Pointer to nothing */ /*;AN000;6*/
458 void display_it(msg_number,handle,subst_count,waitflag,class) /*;AN000;6*/
460 WORD msg_number; /*;AN000;6*/
461 WORD handle; /*;AN000;6*/
462 WORD subst_count; /*;AN000;6*/
463 WORD waitflag; /*;AN000;6*/
464 BYTE class; /*;AN000;6*/
466 union REGS reg; /*;AN000;6*/
468 reg.x.ax = msg_number; /*;AN000;6*/
469 reg.x.bx = handle; /*;AN000;6*/
470 reg.x.cx = subst_count; /*;AN000;6*/
471 reg.h.dh = class; /*;AN000;6*/
472 reg.h.dl = (BYTE)waitflag; /*;AN000;6*/
473 reg.x.di = (BYTE)&response_buff[0]; /*;AN000;6*/
474 reg.x.si = (WORD)(char far *)&sublist; /*;AN000;6*/
476 sysdispmsg(®,®); /*;AN000;6*/
477 response_buff[0] = reg.h.al; /* User input */ /*;AN000;6*/
479 return; /*;AN000;6 */
481 /***************** START OF SPECIFICATION ********************************
483 /* SUBROUTINE NAME : com_msg
485 /* DESCRIPTIVE NAME : the routine to output a message according to
486 /* the return codes returned from API calls.
488 /* FUNCTION: 1. if CP/DOS, then call rctomid
492 /* INPUT: (PARAMETERS)
493 /* retcode - return code used to call rctomid
496 /********************** END OF SPECIFICATIONS *******************************/
497 void com_msg(retcode)
501 display_it(rctomid(retcode),STND_ERR_DEV,0,NO_RESPTYPE,(BYTE)UTIL_MSG); /*;AN000;6*/
506 /*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
508 /* Subroutine Name: chek_DBCS() */
510 /* (Ripped off and Revised from ATTRIB.C) */
512 /* Subroutine Function: */
513 /* Given an array and a position in the array, check if the character */
514 /* is a non-DBCS character. */
516 /* Input: array, character position, character */
518 /* Output: TRUE - if array[position-1] != DBCS character AND */
519 /* array[position] == character. */
520 /* FALSE - otherwise */
522 /*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
523 WORD chek_DBCS(array,position,character) /*;AN005;*/
524 char *array; /*;AN005;*/
525 WORD position; /*;AN005;*/
526 char character; /*;AN005;*/
528 BYTE far *ptr; /*;AN005;*/
531 char darray[128]; /* DBCS array, put "D" in every position*/ /*;AN005;*/
532 /* that corresponds to the first byte */
533 /* of a DBCS character. */
534 if (!got_dbcs_vector) /*;AN005;*/
535 Get_DBCS_vector(); /*;AN005;*/
537 for (i=0;i<128;i++) /*;AN005;*/
538 darray[i] = ' '; /*;AN005;*/
540 /* Check each character, starting with the first in string, for DBCS */
541 /* characters and mark each with a "D" in the corresponding darray. */
542 for (i=0;i<position;i++) /*;AN005;*/
544 c = array[i]; /*;AN005;*/
546 /* look thru DBCS table to determine if character is first byte */
547 /* of a double byte character */
548 for (ptr=DBCS_ptr; (WORD)*(WORD far *)ptr != 0; ptr += 2) /*;AN005;*/
551 /* check if byte is within range values of DOS DBCS table */
552 if (c >= *ptr && c <= *(ptr+1)) /*;AN005;*/
554 darray[i] = 'D'; /*;AN005;*/
555 i++; /* skip over second byte of DBCS */ /*;AN005;*/
561 /* if character is not DBCS then check to see if it is == to character */
562 if (darray[position-1] != 'D' && character == array[position]) /*;AN005;*/
563 return (TTRUE); /*;AN005;*/
565 return (FFALSE); /*;AN005;*/
568 /*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
570 /* Subroutine Name: Get_DBCS_vector() */
572 /* Subroutine Function: */
573 /* Gets the double-byte table vector. */
574 /* Puts it in global variable DBCS_ptr */
575 /*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
576 void Get_DBCS_vector() /*;AN005;*/
578 union REGS inregs,outregs; /*;AN005;*/
579 struct SREGS segregs; /*;AN005;*/
580 char fix_es_reg[2]; /*;AN005;*/
581 WORD *ptr; /*;AN005;*/
582 DWORD far *addr_ptr; /*;AN005;*/
583 WORD *buffer; /*;AN005;*/
585 /***********************************/
586 /* Allocate a buffer */
587 /***********************************/
588 inregs.x.ax = 0x4800; /* Allocate */ /*;AN005;*/
589 inregs.x.bx = 1; /* Num paragraphs */ /*;AN005;*/
590 intdos(&inregs,&outregs); /* Int 21h */ /*;AN005;*/
591 buffer = (WORD *)outregs.x.ax; /* Segment of buffer */ /*;AN005;*/
593 inregs.x.ax = 0x6507; /* get extended country info */ /*;AN005;*/
594 inregs.x.bx = 0xffff; /* use active code page */ /*;AN005;*/
595 inregs.x.cx = 5; /* 5 bytes of return data */ /*;AN005;*/
596 inregs.x.dx = 0xffff; /* use default country */ /*;AN005;*/
597 inregs.x.di = 0; /* buffer offset */ /*;AN005;*/
598 segregs.es = (WORD)buffer; /* buffer segment */ /*;AN005;*/
599 segregs.ds = (WORD)buffer; /* buffer segment */ /*;AN005;*/
600 intdosx(&inregs,&outregs,&segregs); /*;AN005;*/
601 strcpy(fix_es_reg,NUL); /*;AN005;*/
603 outregs.x.di++; /* skip over id byte */ /*;AN005;*/
605 /* make a far ptr from ES:[DI] */
606 addr_ptr = 0; /*;AN005;*/
607 ptr = (WORD *)&addr_ptr; /*;AN005;*/
608 *ptr = (WORD)outregs.x.di; /* get offset */ /*;AN005;*/
610 *ptr = (WORD)segregs.es; /* get segment */ /*;AN005;*/
611 DBCS_ptr = (BYTE far *)*addr_ptr; /*;AN005;*/
612 DBCS_ptr += 2; /* skip over table length */ /*;AN005;*/
614 /* DBCS_ptr points to DBCS table */
615 strcpy(fix_es_reg,NUL); /*;AN005;*/
616 got_dbcs_vector = TTRUE; /*;AN005;*/