home *** CD-ROM | disk | FTP | other *** search
Text File | 1986-09-08 | 72.8 KB | 2,681 lines |
- 8-Sep-86 15:43:34-PDT,685;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 15:42:14 PDT
- Received: by unix.macc.wisc.edu;
- id AA04894; 4.12/5; Mon, 8 Sep 86 17:29:02 cdt
- Date: Mon, 8 Sep 86 17:29:02 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082229.AA04894@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: mv source
-
- Here comes the mv source. You should receive the following 17 files:
-
- absdr.asm
- break.c
- date.h
- dta.h
- error.c
- front.c
- fstat.c
- func32h.asm
- mv
- mv.c
- normal.c
- peek.h
- putn.asm
- readme.txt
- rm.c
- sector.c
- testmv.bat
-
- I believe you have mv.doc already. If not, let me know.
-
- peter
- 8-Sep-86 16:33:40-PDT,1479;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:33:28 PDT
- Received: by unix.macc.wisc.edu;
- id AA05000; 4.12/5; Mon, 8 Sep 86 17:32:30 cdt
- Date: Mon, 8 Sep 86 17:32:30 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082232.AA05000@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: readme.txt
-
- To make mv from source, you must have ibm C compiler version 1.0 or
- Microsoft C version 3.0 plus the macro assembler. Just type
-
- make mv
-
- and it will create mv.exe for you. If you use Microsoft C version
- 4.0, edit front.c to reverse the order of the parameters in the
- "rename" function.
-
- Files description
-
- mv makefile for mv
- absdr.asm absolute disk read/write BIOS call
- func32h.asm routine to call an undocumented DOS function
- putn.asm routine to print strings
- testmv.bat batch file I used to test mv
- break.c routines to check and set break status
- error.c routines to handle fatal errors
- front.c front end of the mv program
- fstat.c routines to find matching files and their attributes
- mv.c routines for moving sub-directories
- normal.c routines to normalize a path specification
- sector.c routines to do buffered disk read/write
- mv.exe executable version of mv
- peek.h macros for peeking and poking memory
- dta.h data structure at disk transfer address; used by fstat.c
- date.h defines the date when the last version was made
- 8-Sep-86 15:43:33-PDT,415;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 15:40:13 PDT
- Received: by unix.macc.wisc.edu;
- id AA04928; 4.12/5; Mon, 8 Sep 86 17:30:43 cdt
- Date: Mon, 8 Sep 86 17:30:43 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082230.AA04928@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: date.h
-
- #define date "8-20-1986"
- 8-Sep-86 15:59:17-PDT,818;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 15:45:12 PDT
- Received: by unix.macc.wisc.edu;
- id AA04988; 4.12/5; Mon, 8 Sep 86 17:32:13 cdt
- Date: Mon, 8 Sep 86 17:32:13 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082232.AA04988@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: peek.h
-
- /* pseudo functions to peek/poke byte or word. Written by Peter Wu. 6/5/86.
- ** Use /ze option when compiling.
- */
-
- #define acc(seg,off) ((long) (seg) << 16 | (unsigned short) (off))
- #define peekb(seg,off) (*(unsigned char far *)acc(seg,off))
- #define pokeb(seg,off,val) (*(char far *)acc(seg,off) = (val))
- #define peekw(seg,off) (*(short far *)acc(seg,off))
- #define pokew(seg,off,val) (*(short far *)acc(seg,off) = (val))
- 8-Sep-86 16:13:30-PDT,2449;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:09:00 PDT
- Received: by unix.macc.wisc.edu;
- id AA04966; 4.12/5; Mon, 8 Sep 86 17:31:32 cdt
- Date: Mon, 8 Sep 86 17:31:32 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082231.AA04966@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: func32h.asm
-
- ; Call DOS 32H from C. This is an undocumented function call documented in
- ; PC Tech. Journal May 1986. This function returns a pointer to a disk
- ; description table that contains the following:
- ;
- ; offset length what
- ; ------ ------ ----
- ; 0 byte assigned physical disk (A=0, B=1, ...)
- ; 1 byte same as above but 0 for RAM disk
- ; 2 word bytes per sector
- ; 4 byte sectors per cluster minus 1
- ; 5 byte #heads minus 1
- ; 6 word reserved sectors
- ; 8 byte #copies of FAT (normally 2 for real disks, 1 for RAM disks)
- ; 9 word max directory entries
- ; 11 word first usable sector (i.e. data area)
- ; 13 word total cluster count plus 1
- ; 15 byte #sectors occupied by each FAT
- ; 16 word first sector of the root's directory
- ; 18 dword device driver address
- ; 22 word media descriptor
- ; 24 dword chain to next disk table
- ; 28 word cluster of current working directory
- ;
- ; in C, use
- ; unsigned char drv, /* drive number: 1=A, 2=B, ...; 0=current drive */
- ; status; /* if 0xFF means invalid drive */
- ; unsigned short tabseg, /* disk description table segment */
- ; taboff; /* disk description table offset */
- ;
- ; status = func32h(drv, &tabseg, &taboff);
- ;
- ; The reason for writing this procedure in assembly is because the
- ; function returns the description table segment address in DS which
- ; cannot be accessed by using intdosx() function in C.
- ;
- ; Written by Peter Wu 6/27/86
- ;
- _text segment public byte 'code'
- assume cs:_text
-
- public _func32h
- _func32h proc near
- push bp
- mov bp,sp
- push ds ; save DS
-
- mov dl,[bp+4] ; drive number
- mov ah,32h
- int 21h
-
- mov cx,bx ; stupid move, but I need bx
- mov si,ds
- pop ds
-
- mov bx,[bp+6] ; &tabseg
- mov [bx],si ; store tabseg
- mov bx,[bp+8] ; &taboff
- mov [bx],cx ; store taboff
- mov ah,0 ; al contains ffh if error
-
- pop bp
- ret
- _func32h endp
-
- _text ends
- end
- 8-Sep-86 16:13:31-PDT,2971;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:09:21 PDT
- Received: by unix.macc.wisc.edu;
- id AA05017; 4.12/5; Mon, 8 Sep 86 17:32:54 cdt
- Date: Mon, 8 Sep 86 17:32:54 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082232.AA05017@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: sector.c
-
- /* Routines to read and write sectors
- ** Only one copy of a particular sector will be stored, to prevent
- ** inconsistency.
- ** Written by Peter Wu 7/11/86 @ Faculty Support Center @ Univ. of Wisconsin
- ** This is used by the mv (move files and directory) program.
- ** Link with absdr (source absdr.asm)
- */
- #define LINT_ARGS
-
- #define MAX_SECTOR_SIZE 4200 /* is this safe enough? */
- #define MAX_COPIES 5 /* max # of sectors buffered */
-
- #include <conio.h>
-
- /* global stuff */
-
- char secbufx[MAX_SECTOR_SIZE * MAX_COPIES], dirty[MAX_COPIES];
- int secind[MAX_COPIES], drvind[MAX_COPIES];
- int num_sec; /* number of sectors currently buffered */
-
- char *readsec(drv, sector) /* read a sector; return pointer to buffer */
- int drv, sector;
- {
- int i, status;
- char *where;
-
- #ifdef debug
- printf("reading sector# %d\n",sector);
- #endif
- /* first see if the sector requested is already in buffer */
- for (i=0; i < num_sec; i++) {
- if ((secind[i] == sector) &&
- (drvind[i] == drv) ) { /* aha - sector already read */
- return secbufx + i * MAX_SECTOR_SIZE; /* return pointer to buffer */
- }
- }
-
- /* sector is not in buffer, so read it, but first allocate a buffer */
- secind[num_sec] = sector; /* store sector number */
- drvind[num_sec] = drv;
- where = secbufx + num_sec * MAX_SECTOR_SIZE;
- status = absdr(drv, 1, sector, where);
- if (status) {
- cputs("Error in readsec calling absdr\n\015");
- return (char *) 0;
- }
- dirty[num_sec] = 0; /* not dirty */
- num_sec++;
-
- /* successfully read a sector into buffer */
- return where;
- }
-
- writesec(drv,sector)
- int drv, sector;
- {
- int i, status;
-
- #ifdef debug
- printf("writing sector# %d\n", sector);
- #endif
- for (i=0; i < num_sec; i++) {
- if ((secind[i] == sector) && (drvind[i] == drv)) {
- if (dirty[i]) { /* write the sector only if it's dirty */
- status = absdw(drvind[i], 1, secind[i], secbufx + i * MAX_SECTOR_SIZE);
- if (status) {
- cputs("Error in flushsec calling absdw\n\015");
- return -1;
- } else {
- dirty[i] = 0;
- }
- }
- return 0;
- }
- } /* for */
- cputs("writesec: sector is not in buffer\n\015");
- return -2;
- }
-
- flirt(drv,sector) /* turn on dirty flag */
- int drv,sector;
- {
- int i;
-
- #ifdef debug
- printf("flirting sector# %d; num_sec = %d\n",sector,num_sec);
- #endif
- for (i=0; i < num_sec; i++) {
- if ((secind[i] == sector) && (drvind[i] == drv)) {
- dirty[i] = 1;
- return 0;
- }
- }
- cputs("flirt: can't find sector to flirt with\n\015");
- return -1;
- }
- 8-Sep-86 16:13:34-PDT,3102;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:09:52 PDT
- Received: by unix.macc.wisc.edu;
- id AA04934; 4.12/5; Mon, 8 Sep 86 17:30:54 cdt
- Date: Mon, 8 Sep 86 17:30:54 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082230.AA04934@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: dta.h
-
- #define A_FIL 0x40 /* Peter's addition: this mask searches for file */
- #define A_ARC 0x20 /* attributes bits of attribute byte in dta */
- #define A_DIR 0x10
- #define A_SYS 0x4
- #define A_HID 0x2
- #define A_MASK (A_FIL | A_DIR | A_SYS | A_HID) /* mask to find all files */
-
- struct dtbuf3 { /* structure returned by dos function 0x4e and 0x4f */
- /* The first 21 bytes are undocumented; use them at your own risk.
- ** Their use is guessed by Peter Wu. This applies only to DOS 3.xx
- */
-
- unsigned char drv_no; /* drive number; 1=A 2=B 3=C ... */
- char template[11]; /* file template; no period */
- unsigned char match_attr; /* the search attribute */
- unsigned char slotl; /* directory slot number of the matching file */
- unsigned char sloth;
- unsigned char clusl, clush; /* cluster number of the directory being
- searched */
- unsigned char unknown[4]; /* haven't figured out what these are */
- /* end of first 21 bytes */
-
- unsigned char attr;
- unsigned short time;
- unsigned short data;
- unsigned long size; /* 4 bytes */
- char fn[13]; /* this is an asciiz */
- unsigned char e_attr; /* extended (by peter) search attribute */
- };
-
- struct dtbuf2 { /* structure returned by dos function 0x4e and 0x4f */
- /* The first 21 bytes are undocumented; use them at your own risk.
- ** Their use is guessed by Peter Wu. This applies only to DOS 2.xx
- */
-
- unsigned char match_attr; /* the search attribute */
- unsigned char drv_no; /* drive number; 1=A 2=B 3=C ... */
- char template[11]; /* file template; no period */
- unsigned char slotl; /* directory slot number of the matching file */
- unsigned char sloth;
- unsigned char unknown[4]; /* haven't figured out what these are */
- unsigned char clusl, clush; /* cluster number of the directory being
- searched */
- /* end of first 21 bytes */
-
- unsigned char attr;
- unsigned short time;
- unsigned short data;
- unsigned long size; /* 4 bytes */
- char fn[13]; /* this is an asciiz */
- unsigned char e_attr; /* extended (by peter) search attribute */
- };
-
- struct dtbufx { /* generic version (works for any DOS version */
- unsigned char unknown[21];
- unsigned char attr;
- unsigned short time;
- unsigned short data;
- unsigned long size; /* 4 bytes */
- char fn[13]; /* this is an asciiz */
- unsigned char e_attr; /* extended (by peter) search attribute */
-
- /* the following info has to be copied from dtbuf2 or dtbuf3 by
- ** the ffmf and fnmf functions
- */
- unsigned char drv_no;
- unsigned char slotl, sloth, clusl, clush;
- };
-
- union dtbuf {
- struct dtbuf3 dos3;
- struct dtbuf2 dos2;
- struct dtbufx dos;
- };
- 8-Sep-86 16:13:36-PDT,4915;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:10:13 PDT
- Received: by unix.macc.wisc.edu;
- id AA04962; 4.12/5; Mon, 8 Sep 86 17:31:25 cdt
- Date: Mon, 8 Sep 86 17:31:25 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082231.AA04962@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: fstat.c
-
- /* find first matching file and find next matching file
- ** written by Peter Wu @ Faculty Support Center @ Univ. of Wisconsin
- ** July 1986
- **
- ** These functions have an extended capability to search for
- ** directories only and ffmf does not return "." and "..", also
- ** ffmf will attempt to find root directory and return at least drive number
- */
- #define LINT_ARGS
-
- #include "dta.h"
- #include <dos.h>
- #include <stdlib.h>
-
- char lastc(char *);
-
- ffmf(fn,attr,dta) /* extended version of ffmf1; fn must be normalized */
- char *fn;
- short attr;
- union dtbuf *dta;
- {
- int status, len;
- char tmpfn[200];
- union dtbuf tmpdta;
-
- if (lastc(fn) != '\\') { /* if not looking for root directory */
-
- status = ffmf1(fn,attr,dta);
- if (status) {
- return status;
- }
-
- /* get rid of "." and ".." */
- while (dta->dos.fn[0] == '.') {
- status = fnmf1(dta);
- if (status) {
- return status;
- }
- }
-
- /* now check to see if we should return plain files or not */
- while ( ((dta->dos.e_attr & A_FIL) == 0) &&
- ((dta->dos.attr & A_DIR) == 0) ) {
- /* user didn't ask for plain files and we found one, so skip it */
- status = fnmf1(dta);
- if (status) {
- return status;
- }
- }
-
- fixdta(dta,dta);
- return 0;
- }
-
- /* fn ends with '\', i.e. looking for root directory. In DOS 3 ffmf1 won't
- ** find root directory, and in DOS 2 ffmf1 found root directory but reports
- ** it to have file status! Neither is right. So I have to fix it here.
- ** The reason for wanting to look for a root directory is to find out
- ** what drive it's on.
- */
-
- if (attr & A_DIR) {
- /* look for '\*.*' */
- strcpy(tmpfn, fn);
- strcat(tmpfn, "*.*");
- status = ffmf1(tmpfn, A_DIR | A_FIL, &tmpdta);
- if (status) { /* can't even find root this way: root must be empty */
- cputs("empty root directory; nothing to move\n\015");
- exit(1);
- }
-
- /* found root; now fill in dta */
- dta->dos.fn[0] = '\0';
- dta->dos.attr = A_DIR;
- fixdta(&tmpdta,dta);
- return 0;
- } else {
- return 1; /* can't find root because attr is not set to A_DIR */
- }
- }
-
- /* extended version of fnmf1; because of the way ffmf handle root directory,
- ** calling ffmf to find root directory and then call fnmf will cause an
- ** "allocation table bad" error
- */
- fnmf(dta)
- union dtbuf *dta;
- {
- int status;
-
- status = fnmf1(dta);
- if (status) {
- return status;
- }
-
- while (((dta->dos.e_attr & A_FIL) == 0) && ((dta->dos.attr & A_DIR) == 0)) { /* user didn't ask for plain file and we found one, so skip it */
- status = fnmf1(dta);
- if (status) {
- return status;
- }
- }
-
- fixdta(dta,dta);
- return 0; /* no error */
- }
-
- /* copy dos dependent dta fields to the dos independent dta fields */
- fixdta(from, to)
- union dtbuf *from, *to;
- {
- switch (_osmajor) {
-
- case 3: /* dos 3.xx */
- to->dos.drv_no = from->dos3.drv_no;
- to->dos.slotl = from->dos3.slotl;
- to->dos.sloth = from->dos3.sloth;
- to->dos.clusl = from->dos3.clusl;
- to->dos.clush = from->dos3.clush;
-
- to->dos3.drv_no = from->dos3.drv_no; /* for compatiblity sake */
- break;
-
- case 2: /* dos 2.xx */
- to->dos.drv_no = from->dos2.drv_no + 1;
- to->dos.slotl = from->dos2.slotl;
- to->dos.sloth = from->dos2.sloth;
- to->dos.clusl = from->dos2.clusl;
- to->dos.clush = from->dos2.clush;
-
- to->dos2.drv_no = from->dos2.drv_no; /* for compatiblity sake */
- break;
-
- default:
- cputs("unexpected DOS version\n\015");
- error("fixdta", 0);
- }
- }
-
- ffmf1(fn,attr,dta) /* don't call this, call ffmf */
- char *fn;
- short attr;
- union dtbuf *dta;
- {
- union REGS inregs,outregs;
-
- dta->dos.e_attr = attr; /* store the extended attribute */
- bdos(0x1a, (int) dta, 0); /* set dta */
-
- inregs.h.ah = 0x4e;
- inregs.x.dx = (int) fn;
- inregs.x.cx = attr & 0x3f; /* mask off the A_FIL bit */
- intdos(&inregs, &outregs); /* now find first entry */
-
- if (outregs.x.cflag) {
- return outregs.x.ax; /* return error code */
- }
- return 0; /* no error */
- }
-
- fnmf1(dta) /* find next matching file */
- union dtbuf *dta;
- {
- union REGS inregs,outregs;
-
- bdos(0x1a, (int) dta, 0); /* set dta */
-
- inregs.h.ah = 0x4f;
- intdos(&inregs, &outregs); /* now find next entry */
-
- if (outregs.x.cflag) {
- return (outregs.x.ax);
- } else {
- return (0);
- };
- }
- 8-Sep-86 16:13:37-PDT,7276;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:10:31 PDT
- Received: by unix.macc.wisc.edu;
- id AA05007; 4.12/5; Mon, 8 Sep 86 17:32:42 cdt
- Date: Mon, 8 Sep 86 17:32:42 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082232.AA05007@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: rm.c
-
- /* rm - removes everything you got
- ** Written by Peter Wu @ Faculty Support Center, MACC
- ** University of Wisconsin - Madison. August 1986.
- */
- #include "dta.h"
- #include <conio.h>
- #include <ctype.h>
- #include "date.h"
-
- char getkey();
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int brgc, optc, i, status, mask;
- char *brgv[40], opt[26], *t, path[200], c;
-
- optc = 0;
- brgc = 0; /* my argc */
-
- for (i=0; i < 26; i++) { /* clear options flags */
- opt[i] = 0;
- };
-
- for (i=1; i < argc; i++) { /* separate options and arguments */
- if ((*argv[i] == '/') || (*argv[i] == '-')) {
- t = argv[i] + 1;
- while ((c = *t++) != '\0') {
- if (isalpha(c)) {
- opt[tolower(c) - 'a'] = 1;
- };
- };
- } else {
- brgv[brgc++] = argv[i];
- };
- };
-
- if (brgc == 0) {
- putn("Usage: RM <filespec>\15\n",
- "<filespec> can have wild cards and attributes /f /d /h; E.g:\15\n",
- " *.* or *.*/f selects all visible file\15\n",
- " *.*/h or *.*/hf selects all visible and invisible files\15\n",
- " *.*/d selects all sub-directories\15\n\n",
- "For each file/sub-directory found, you will be prompted for\15\n",
- "one of the following actions:\15\n",
- " y - yes, delete this file\15\n",
- " Y - Yes, delete this sub-directory\15\n",
- " n - no, leave this file/sub-directory alone\15\n",
- " l - list all the rest of the files/sub-directories\15\n",
- " Z - delete ALL the rest of the files/sub-directories\15\n",
- " e - enter this sub-directory\15\n",
- " x - exit current sub-directory\15\n",
- " q - quit now\15\n\n",
- "Version 2.00 made ", date, ".\15\n",
- "Please report problems to Peter Wu.\15\n",
- 0);
- exit(0);
- }
-
- /* process parameters */
- for (i=0; i < brgc; i++) {
- strcpy(path, brgv[i]);
- mask = extype(path);
- mask |= normal(path);
- if ((mask & (A_FIL | A_DIR)) == 0) {
- mask |= A_FIL; /* default is remove files only */
- }
- rm(1, 1, mask, path);
- }
- }
-
- rm(confirm, echo, mask, path) /* use normalized path only */
- int confirm, mask;
- char *path;
- {
- char headp[200], fullp[200], c;
- int status;
- union dtbuf mydta;
-
- strcpy(headp,path);
- chopath(headp); /* cut off the tail (might be wild-cards) */
-
- status = ffmf(path, mask, &mydta);
- if (status) { /* not found; probably empty directory */
- return 1; /* let the caller print out the error message */
- }
-
- do { /* for all matching files */
-
- strcpy(fullp, headp);
- catpath(fullp, mydta.dos.fn); /* now fullp has the expanded name */
-
- do {
-
- if (confirm | echo) { /* echo files to be deleted */
- cputs(fullp);
- if (mydta.dos.attr & A_DIR) {
- cputs(" <DIR>");
- }
- if (mydta.dos.attr & (A_HID | A_SYS)) {
- cputs(" (hidden)");
- }
- }
-
- if (confirm) { /* ask for confirmation */
-
- status = 0;
- if (mydta.dos.attr & A_DIR) { /* sub-dir */
- cputs(" (Y/n/e/x/l/Z/q; ? for help): ");
- c = getkey("YynlxqeZ?");
- } else { /* file */
- cputs(" (y/n/x/l/Z/q; ? for help): ");
- c = getkey("YynlxqZx?");
- }
-
- switch (c) {
-
- case '?':
- putn("\15\n",
- "Y - Yes, delete this sub-directory and its content\15\n",
- "y - yes, delete this file\15\n",
- "n - no, skip this file/sub-directory\15\n",
- "e - enter this sub-directory\15\n",
- "x - exit current sub-directory\15\n",
- "l - list all the rest of the files/sub-directories\15\n",
- "Z - delete ALL the rest without further prompts\15\n",
- "q - quit to DOS now\15\n",
- 0);
- cputs("\n");
- break;
-
- case 'Z':
- putn("\15\n",
- "Really delete ALL the remaning files/sub-directories (Y/N)? ",
- 0);
- c = getkey("YNn");
- if (c == 'Y') {
- confirm = 0; /* no more confirmation request */
- status = 1; /* exit loop */
- }
- cputs("\15\n");
- break;
-
- case 'q':
- cputs("\15\nquiting to DOS\15\n");
- exit(0);
-
- case 'x':
- cputs("\15\n");
- return 2; /* exit current directory */
-
- case 'y':
- if (mydta.dos.attr & A_DIR) { /* can't delete sub-dir with 'y' */
- cputs(" use Y to delete sub-directory\15\n");
- } else { /* delete this file */
- putch(' '); /* move the cursor */
- status = 1; /* delete */
- }
- break;
-
- case 'Y':
- if (mydta.dos.attr & A_DIR) {
- putch(' '); /* move the cursor */
- status = 1; /* delete */
- } else { /* can't delete file with 'Y' */
- cputs(" use y to delete file\15\n");
- }
- break;
-
- case 'n':
- status = 2;
- break;
-
- case 'l':
- cputs("\15\n");
- ls(mydta);
- break;
-
- case 'e':
- cputs(" entering sub-directory\15\n\n");
- catpath(fullp,"*.*");
- if (rm(1,1,A_MASK,fullp) == 1) { /* empty */
- cputs("This sub-directory is empty. ");
- }
- chopath(fullp);
- cputs("Returning to previous directory.\15\n\n");
- break;
-
- default: /* what did I miss? */
- cputs("invalid key\15\n");
- }
-
- } else { /* confirm == 0 */
- status = 1;
- }
-
- } while (!status);
-
- /* status == 1 delete; status == 2 don't delete */
-
- if (status == 1) { /* delete */
- if (mydta.dos.attr & A_DIR) { /* delete sub-directory */
- /* check if fullp is parent of current path */
-
- /* call rm recursively to remove stuff */
- catpath(fullp,"*.*");
- rm(0,0,A_MASK,fullp); /* no confirmation for this */
- chopath(fullp); /* cut off the "*.*" */
- status = rmdir(fullp);
- if (echo || confirm) {
- if (status) {
- cputs(" can't delete\15\n");
- } else {
- cputs(" Deleted\15\n");
- }
- }
-
- } else { /* delete files */
-
- status = unlink(fullp);
- if (echo || confirm) {
- if (status) {
- cputs(" can't delete\15\n");
- } else {
- cputs(" deleted\15\n");
- }
- }
- }
-
- } else {
- cputs(" not deleted\15\n");
- }
-
- status = fnmf(&mydta);
- } while (status == 0);
-
- return 0;
- }
-
- ls(cdta) /* list the rest of the files */
- union dtbuf cdta;
- {
- int i, status, col, slen; /* column */
-
- col = 0;
- do { /* list the current one also */
- col++;
- slen = strlen(cdta.dos.fn);
- cputs(cdta.dos.fn);
- if (cdta.dos.attr & A_DIR) {
- putch('\\');
- slen++;
- };
-
- if (col < 5) {
- for (i=slen; i < 16; i++) {
- putch(' ');
- }
- } else {
- cputs("\15\n");
- col = 0;
- }
- status = fnmf(&cdta);
- } while (!status);
-
- if (col) { /* complete last line */
- cputs("\15\n");
- }
- }
-
- char getkey(valid) /* wait for valid key and echo it */
- char *valid;
- {
- char c;
- int i;
-
- do {
- c = getch();
- i = index(valid,c);
- if (i > -1) {
- putch(c); /* echo valid key */
- return c;
- } else { /* beep at invalid key */
- putch(7);
- }
- } while (1);
- }
- 8-Sep-86 16:13:38-PDT,8378;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:10:58 PDT
- Received: by unix.macc.wisc.edu;
- id AA05024; 4.12/5; Mon, 8 Sep 86 17:33:02 cdt
- Date: Mon, 8 Sep 86 17:33:02 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082233.AA05024@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: testmv.bat
-
- echo off
- rem *** run this batch file if you suspect mv does not work properly on
- rem *** your system
- echo This batch file is used to test MV. Run in an empty directory.
- echo Make sure path points to MV.
- echo
- if %2.==root. goto ok
- if %2.==notroot. goto ok
- goto noarg
- :ok
- echo > a
- if not exist %1:a goto userr
- pause
-
- echo The DOS is
- ver
-
- rem *** create files and directories to play with
- echo Creating files and sub-directories to test MV
- echo > b
- echo > c
- echo > e
- md f
- echo > f\x.x
- md g
- echo > g\y.y
-
- rem *** test #1 - #19 exercise the "front" module
-
- echo test#1 (file rename)
- rem *** should not cause any error
- mv e d > mv.log
- if errorlevel 1 goto err
- if exist e goto wrong
- if not exist d goto wrong
-
- echo test#2 (sub-directory rename)
- rem *** should not cause any error
- mv f e > mv.log
- if errorlevel 1 goto err
- if exist f\x.x goto wrong
- if not exist e\x.x goto wrong
-
- echo test#3 (try to rename file to another existing file)
- rem *** MV should detect error
- mv a b > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#4 (try to move multiple sources to a file name)
- rem *** MV should detect error
- mv * x. > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if exist x goto wrong
-
- echo test#5 (similar to test#4)
- rem *** MV should detect error
- mv a b c > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
- if not exist b goto wrong
-
- echo test#6 (try to move multiple source to a name)
- rem *** MV should detect error
- mv * x > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if exist x goto wrong
-
- echo test#7 (try to move file into non-existing sub-directory)
- rem *** MV should detect error
- mv a f\. > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#8 (destination path not exist)
- rem *** MV should detect error
- mv a f\a > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#9 (destination path includes a file)
- rem *** MV should detect error
- mv a b\c > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#10 (destination specified as sub-directory but exists as a file)
- rem *** MV should detect error
- mv a b\. > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#11 (destination is ambigious)
- rem *** MV should detect error
- mv a * > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#12 (similar to test#11)
- rem *** MV should detect error
- mv a *\. > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#13 (rename file to itself)
- rem *** MV should detect error
- mv a . > mv.log
- if errorlevel 1 goto err
- if not exist a goto wrong
-
- echo test#14 (source not exist)
- rem *** MV should detect error
- mv x y > mv.log
- if errorlevel 1 goto err
- if exist y goto wrong
-
- echo test#15 (move files and sub-directory into sub-directory)
- rem *** no error
- mv *. e > mv.log
- if errorlevel 1 goto err
- if not exist e\a goto wrong
- if not exist e\b goto wrong
- if not exist e\c goto wrong
- if not exist e\d goto wrong
- if not exist e\g\y.y goto wrong
- if exist a goto wrong
- if exist b goto wrong
- if exist c goto wrong
- if exist d goto wrong
- if exist g\y.y goto wrong
-
- echo test#16 (move sub-directory to current directory)
- rem *** no error
- mv e\g . > mv.log
- if errorlevel 1 goto err
- if not exist g\y.y goto wrong
- if exist e\g\y.y goto wrong
-
- echo test#17 (move one sub-directory into another)
- rem *** no error
- mv e g > mv.log
- if errorlevel 1 goto err
- if not exist g\e\a goto wrong
- if exist e\a goto wrong
-
- echo test#18 (move file to current directory)
- rem *** no error
- mv g\e\a .\a > mv.log
- if errorlevel 1 goto err
- if not exist a goto wrong
- if exist g\e\a goto wrong
-
- echo test#19 (multiple sources with one missing source)
- mv g\e\a g\e\b g\e\* . > mv.log
- if errorlevel 1 goto err
- if not exist b goto wrong
- if not exist c goto wrong
- if not exist d goto wrong
-
- rem *** the following tests exercise the "mv" module
-
- echo test#20 (try to move current directory)
- rem *** should cause error
- mv . x > mv.log
- if errorlevel 2 goto err
- rem *** if current directory is root it'll cause errorlevel 1;
- if %2==root if not errorlevel 1 goto noerr
- rem *** otherwise no errorlevel
- if %2==notroot if errorlevel 1 goto err
-
- echo test#21 (try to move parent into child)
- rem *** should cause error but no errorlevel
- mv g g\e > mv.log
- if errorlevel 1 goto err
- if not exist g\y.y goto wrong
-
- echo test#22 (similar to test#21)
- mv g g\e\egg > mv.log
- if errorlevel 1 goto err
- if not exist g\y.y goto wrong
-
- echo test#23 (similar to test#21)
- mv g g > mv.log
- if errorlevel 1 goto err
- if not exist g\y.y goto wrong
-
- echo test#24 (try to move parent of current directory)
- mv .. g > mv.log
- rem *** depending on where you are, you either get
- rem *** "sorry, but root directory has no parent" (errorlevel 1) or
- rem *** "not moved to preserve current directory" (errorlevel 0) or
- rem *** "move root directory? You're joking" (errorlevel 1)
- if not exist a goto wrong
- if %2==root if not errorlevel 1 goto noerr
- rem *** if %2==notroot if errorlevel 1 goto err
-
- rem ** the following tests exercise the "normal" module
-
- echo test#25 (path includes drive letters but no root)
- mv %1:a %1:h > mv.log
- if errorlevel 1 goto err
- if not exist h goto wrong
- if exist a goto wrong
-
- echo test#26 (path includes drive letters and root)
- mv %1:h %1:\i > mv.log
- if errorlevel 1 goto err
- if not exist \i goto wrong
- if exist h goto wrong
-
- echo test#27 (path has upper case letters)
- mv %1:\I A > mv.log
- if errorlevel 1 goto err
- if not exist a goto wrong
- if exist %1:\i goto wrong
-
- echo test#28 (missing sub-directory name before \..)
- mv a \\.. > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#29 (sub-directory name too long)
- mv a aaaaaaaaaaaaaaaaaaaaa > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#30 (referencing root's parent)
- mv a \.. > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#31 (.. not preceded by \)
- mv a .... > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist a goto wrong
-
- echo test#32 (source is "*\a\..")
- rem *** this is equal to mv g g which won't be performed
- mv *\a\.. g > mv.log
- if errorlevel 1 goto err
- if not exist a goto wrong
- if not exist g\y.y goto wrong
-
- echo test#33 (no \ before .)
- mv %1:\g:.\y.y . > mv.log
- if errorlevel 2 goto err
- if not errorlevel 1 goto noerr
- if not exist g\y.y goto wrong
- if exist y.y goto wrong
-
- echo MV passed all tests! Note the tests in here are not exhaustive.
- echo Now removing test files created awhile ago...
- del g\e\x.x > nul
- rd g\e > nul
- del g\y.y > nul
- rd g > nul
- del a > nul
- del b > nul
- del c > nul
- del d > nul
- del mv.log > nul
- goto dos
-
- rem *** error handling routines
- :err
- echo MV reported an error that shouldn't happen:
- goto abort
-
- :noerr
- echo MV failed to detect an error and did this:
- goto abort
-
- :wrong
- echo MV performed an operation incorrectly:
- goto abort
-
- :abort
- type mv.log
- echo Please report this problem to the author (type MV without parameters
- echo to get the author's email address).
- goto dos
-
- :userr
- del a
- echo You have entered the incorrect parameters to testmv.
-
- :noarg
- echo Usage: testmv [drv] [where]
- echo.
- echo [drv] is the drive letter of the drive you're running testmv on (e.g
- echo "A"). No quote, no colon.
- echo.
- echo [where] is
- echo "root" if you're running testmv in a root directory
- echo "notroot" if you're running testmv in a sub-directory
- goto dos
-
- :dos
- 8-Sep-86 16:13:40-PDT,10218;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:11:21 PDT
- Received: by unix.macc.wisc.edu;
- id AA04984; 4.12/5; Mon, 8 Sep 86 17:32:05 cdt
- Date: Mon, 8 Sep 86 17:32:05 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082232.AA04984@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: normal.c
-
- /* The normal routine "normalizes" a given path name to this form:
- ** drv:\id\id\id...\id
- ** so that two identical directory/file will yield the same normalized
- ** path regardless of how the user typed it in
- ** E.g.
- ** a:\x\y
- ** and a:\X\Y\.
- ** both yield A:\X\Y
- **
- ** In addition, the later one would also set the flag "dir" indicating
- ** that the user specified it as an directory.
- **
- ** Written by Peter Wu @ Faculty Support Center @ Univ. of Wisconsin
- ** 7/14/86
- */
- #define LINT_ARGS
-
- #define T_ID1 1 /* id without period */
- #define T_ID2 2 /* id with period */
- #define T_DOT 3 /* '.' */
- #define T_DD 4
- #define T_BS 5
- #define T_COL 6
- #define T_NUL 0
-
- #define PLEN 200
-
- #include "dta.h"
- #include <dos.h>
- #include <string.h>
- #include <conio.h>
-
- char *insert();
-
- index(str,c) /* first occurence of c in str */
- char *str, c;
- {
- char *i, d;
-
- i = str;
- d = *i;
- while (d != '\0') {
- if (d == c) {
- return i - str;
- }
- i++;
- d = *i;
- }
- return -1;
- }
-
- char lastc(str) /* return last character of the string */
- register char *str;
- {
- if (*str == '\0') {
- return '\0';
- }
-
- do {
- str++;
- } while (*str != '\0');
-
- return *(str-1);
- }
-
- normal(path) /* normalize a path */
- char *path;
- {
- char work1[PLEN], work2[PLEN], token[13], token2[13], *ptr;
- int i, drv, marker, t, ftype, t2;
-
- /* first make the path a complete path (include drive, and root) */
- i = index(path, ':'); /* search for ':' */
- if (i < 0) { /* no drive specification */
- if (*path == '\\') { /* start from root */
- work1[0] = '@' + drive(); /* default disk */
- work1[1] = ':';
- work1[2] = '\0';
- strcat(work1, path); /* now we have full path */
- } else { /* no drive and no root */
- current(0,work1); /* get current drive and path */
- strcat(work1, path); /* now we have full path */
- }
- } else { /* has drive specification */
- if (path[i+1] != '\\') { /* but no root, so insert current path */
- drv = toupper(path[i-1]) - '@'; /* get drive number */
- current(drv,work1); /* put down drive and path */
- strcat(work1, path+i+1); /* now we have full path */
- } else { /* nothing to change */
- strcpy(work1,path);
- }
- }
-
- #ifdef debug
- printf("full path is %s\n", work1);
- #endif
-
- /* now we have full path in work, but we need to normalize it to get rid
- ** of .. and .
- */
- marker = -2;
- work2[PLEN-1] = '\0'; /* this is where we accumulate result backwards */
- ptr = work2 + PLEN - 1; /* point to first char */
- ftype = -1; /* -1=init, 0=unknown, A_DIR=dir */
-
- do {
- t = scan(work1,&marker,token);
- #ifdef debug
- printf("ptr is %s so far, and t=%d\n", ptr, t);
- #endif
- switch (t) {
-
- case T_ID1:
- case T_ID2:
- ptr = insert(token, ptr);
- if (ftype == -1) {
- ftype = 0; /* this could be a file or a directory */
- }
- break;
-
- #ifdef ha
- case T_ID2:
- if (ftype == -1) {
- ptr = insert(token, ptr);
- ftype = 0; /* this could be file or a directory */
- } else {
- putn("invalid sub-directory name \"", token, "\"\n\015",0);
- exit(1);
- }
- break;
- #endif
-
- case T_DD:
- t2 = scan(work1,&marker,token); /* see what's in front of .. */
- if (t2 != T_BS) {
- cputs("incorrect use of \"..\" in path name\n\015");
- exit(1);
- }
- /* now delete \id\.. */
- t2 = scan(work1,&marker,token); /* read the id (hopefully) */
- if (t2 != T_ID1) {
- if (t2 == T_COL) { /* A:\.. is not permitted */
- cputs("sorry, but root directory has no parent\n\015");
- exit(1);
- } else { /* what could t2 be? */
- cputs("missing directory name in front of \"\\..\"\n\015");
- exit(1);
- }
- }
- t2 = scan(work1,&marker,token2); /* read the '\' */
- if (t2 != T_BS) { /* can this ever happen? */
- putn("missing \"\\\" before \"", token, "\" in path\n\015",0);
- exit(1);
- }
-
- /* a:\id\.. should yield a:\ not a:
- ** a:\id1\..\id2 should yield a:\id2
- ** this is taken care of somewhere else
- */
-
- /* ok, \id\.. deleted */
- if (ftype == -1) {
- ftype = A_DIR; /* this has to be a directory */
- }
- break;
-
- case T_DOT:
- t2 = scan(work1,&marker,token); /* read the '\' */
- if (t2 != T_BS) { /* is this error possible? */
- cputs("missing \"\\\" in front of \".\"\n\015");
- exit(1);
- }
- if (ftype == -1) {
- ftype = A_DIR; /* this has to be a directory */
- }
- /* special case is "a:\." we want this to turn into "A:\" and
- ** not "A:"
- */
- break;
-
- case T_BS:
- ptr = insert("\\", ptr);
- break;
-
- case T_COL:
- ptr = insert(":", ptr);
- break;
- }
- } while (t != T_NUL);
-
- if (lastc(ptr) == ':') { /* special case like a: */
- strcat(ptr,"\\");
- }
- strcpy(path,ptr); /* copy normalized path back */
- return ftype;
- }
-
- char *insert(str1,str2) /* insert str1 in front of str2 */
- char *str1, *str2;
- {
- int i;
-
- i = strlen(str1);
- return strncpy(str2 - i, str1, i);
- }
-
- scan(path,marker,tstr) /* return tokens backwards */
- char *path, *tstr;
- int *marker;
- {
- char c, d;
-
- if (*marker == -2) { /* signal new scan */
- *marker = strlen(path) - 1;
- }
-
- if (*marker == -1) {
- return T_NUL; /* end of string */
- }
-
- c = path[*marker];
- if ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ) {
- return collect_id(tstr, path, marker);
- }
-
- switch (c) {
- case '.':
- if (*marker == 0) {
- *marker = -1;
- return T_DOT;
- } else {
- d = path[*marker - 1];
- if (d == '.') {
- *marker -= 2;
- return T_DD;
- } else {
- if ((d == '\\') || (d == ':')) {
- (*marker)--;
- return T_DOT;
- } else { /* must be an id with trailing dot */
- return collect_id(tstr, path, marker);
- }
- }
- }
- cputs("how do I get here?\n\015");
- error("scan", 0);
-
- case '\\':
- (*marker)--;
- return T_BS;
-
- case ':':
- (*marker)--;
- return T_COL;
-
- default:
- return collect_id(tstr, path, marker); /* non-alpha ID */
- }
- }
-
- check_fn(fn) /* look for invalid characters in file name */
- char *fn;
- {
- char c, *s;
-
- s = fn;
- while((c= *s) != '\0') {
- if ((c < 32) || (index("\"[]|<>+=;,/",c) > -1)) {
- cputs("invalid character '"); putch(c);
- putn("' in file/sub-directory name \"", fn, "\"", 0);
- exit(1);
- }
- s++;
- }
- }
-
- collect_id(tstr, path, marker)
- char *tstr, *path;
- int *marker;
- {
- char c, id[13];
- int flag, i;
-
- id[13] = '\0';
- i = 12;
- flag = T_ID1; /* no period in file name */
- do {
- c = path[*marker];
-
- if (c == '.') { /* indicate there's period in the file name */
- flag = T_ID2;
- } else {
- c = toupper(c);
- if ((c == '\\') || (c == ':')) { /* end of file name */
- strncpy(tstr, id+i+1, 13);
- check_fn(tstr);
- return flag;
- }
- }
-
- id[i] = c;
- (*marker)--;
- if (*marker < 0) {
- strncpy(tstr, id+i, 13);
- check_fn(tstr);
- return flag;
- }
- i--;
- } while (i >= 0);
-
- putn("file/sub-directory name \"...", id, "\" too long\n\015", 0);
- exit(1);
- }
-
- drive() /* returns current drive number 1=A 2=B */
- {
- return (char) bdos(0x19, 0, 0) + 1;
- }
-
- current(drv,cpath) /* returns current path "drv:\id\..\id on drv */
- char *cpath;
- int drv;
- {
- union REGS inregs, outregs;
- char tmp[64];
-
- inregs.h.ah = 0x47; /* get current path */
- inregs.x.si = (int) tmp;
- inregs.h.dl = drv; /* drive number 0=default, 1=A, 2=B */
- intdos(&inregs, &outregs);
- if (drv == 0) {
- drv = drive();
- }
- if (outregs.x.cflag) {
- cputs("cannot find current path on drive "); putch('@'+drv);
- cputs(":\n\015");
- error("current", 0);
- } else {
- cpath[0] = '@' + drv;
- cpath[1] = ':';
- cpath[2] = '\\';
- cpath[3] = '\0';
- if (*tmp != '\0') { /* if not root directory, then append path */
- strcat(cpath,tmp);
- strcat(cpath,"\\");
- }
- }
- }
-
- catpath(path, name) /* concatenate name to path, adding \ when neccessary */
- char *path, *name;
- {
- if (path[strlen(path)-1] != '\\') {
- strcat(path, "\\");
- }
- strcat(path, name);
- }
-
- chopath(path) /* chop off the last portion of a path */
- char *path;
- {
- char *tmp;
-
- tmp = strrchr(path, '\\');
- if (tmp == (char *)0) {
- putn("can't find '\\' in ", path, "\n\015");
- error("chopath", 0);
- }
- if (*(tmp-1) == ':') { /* special case for root */
- *(tmp+1) = '\0';
- } else {
- *tmp = '\0';
- }
- }
-
- #define A_INT 0x80 /* interactive flag */
-
- /* extract the file-type specifier from the given path.
- ** E.g. x/f becomes x with file type,
- ** animal\dog/d becomes animal\dog with sub-directory type,
- ** *./f becomes *. with file type
- ** *.* becomes *.* with no type
- ** *./i becomes interactive (i.e. prompts for y/n for each file)
- */
- extype(path)
- char *path;
- {
- char *s;
- int type;
-
- s = strrchr(path,'/'); /* find last '/' */
- if (s == (char *) 0) { /* no type specified */
- return 0;
- }
-
- type = 0;
- *s = '\0';
- for (++s; *s != '\0'; s++) { /* start scanning after the '/' */
- switch (*s) {
- case 'f':
- case 'F':
- type |= A_FIL;
- break;
-
- case 'd':
- case 'D':
- type |= A_DIR;
- break;
-
- case 'h':
- case 'H':
- type |= A_HID; /* search for hidden files */
- break;
-
- case 'i':
- case 'I':
- type |= A_INT; /* requires user's confirmation for each file */
- break;
-
- default:
- cputs("unrecognized file attribute '"); putch(*s);
- putn("' in path \"", path, "\"\n\015",
- "valid attributes are f, d, h, i (for file, directory, hidden, interac)\n\015",
- 0);
- exit(1); /* maybe the user doesn't know what he/she's doing */
- }
- }
- return type;
- }
- 8-Sep-86 16:13:41-PDT,10586;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:11:55 PDT
- Received: by unix.macc.wisc.edu;
- id AA04974; 4.12/5; Mon, 8 Sep 86 17:31:56 cdt
- Date: Mon, 8 Sep 86 17:31:56 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082231.AA04974@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: mv.c
-
- /* move subdirectories
- ** Written by Peter Wu; July 86.
- ** compile with cc mv /ze
- */
- #define LINT_ARGS
-
- #define ALLOC 26 /* starting cluster number in directory entry */
- #define PLEN 200 /* max path len */
-
- #include <dos.h>
- #include "dta.h"
- #include "peek.h"
- #include <conio.h>
-
- unsigned char func32h();
- unsigned short findir();
- unsigned short clus2sec();
- char *readsec();
- char lastc(char *);
-
- /* external var */
- extern int
- num_sec, /* number of sectors buffered */
- brk_st; /* orginal break status */
-
- /* source & dest must be normalized
- ** mydta1 contains dta of source
- */
- mvdir(mydta1,source,dest) /* move subdirectory */
- union dtbuf mydta1;
- char *source, *dest;
- {
- unsigned short sector1, sector2, offset1, offset2, clus1, clus2,
- d1, d2, status, *p1, *p2, ds1, ds2, bps, parent, drv;
- char *secbuf1, *secbuf2, *secbuf3, cpath[PLEN];
- union dtbuf mydta2;
-
- /* make sure source is not a root directory */
- if (lastc(source) == '\\') {
- cputs("move root directory? You're joking!\n\015");
- exit(1);
- }
-
- /* make sure source is not predesessor of destination */
- if (apreb(source, dest)) {
- /* this will create a directory loop if allowed to go on or
- ** it's a redundant rename to itself (e.g. mv \ha\. \)
- */
- cputs("not moved to avoid loop or redundancy\n\015");
- return -1;
- }
-
- /* see if source is a predesessor of current directory */
- drv = toupper(source[0]) - '@';
- current(drv,cpath);
- if ( apreb(source,cpath) ) {
- cputs("not moved to preserve current directory\n\015");
- return -2;
- }
-
- /* there should be a way to test if source is a predesessor of
- ** a 'subst' drive's current directory
- */
-
- bset(0); /* do not allow user to break during this portion */
-
- status = mkdir(dest);
- if (status) {
- cputs("can't; file exists already/disk write protected\n\015");
- exit(1);
- }
-
- status = ffmf(dest, A_DIR, &mydta2);
- if (status) {
- cputs("error on ffmf after mkdir\n\015");
- error("mvdir", 0);
- }
-
- num_sec = 0; /* clear sector buffers */
-
- sector1 = findir(mydta1, &offset1, &d1, &secbuf1);
- if (sector1 < 0) {
- cputs("cannot find source directory\n\015");
- error("mvdir", 0);
- }
-
- sector2 = findir(mydta2, &offset2, &d2, &secbuf2);
- if (sector2 < 0) {
- cputs("cannot get info on destination directory\n\015");
- error("mvdir", 0);
- }
-
- if (d1 != d2) { /* this should have been detected earlier */
- cputs("source and destination has to be on the same drive\n\015");
- exit(1);
- }
-
- /* now switch the starting cluster of the two directories */
- p1 = (unsigned short *) (secbuf1 + offset1 + ALLOC);
- p2 = (unsigned short *) (secbuf2 + offset2 + ALLOC);
- clus1 = *p1;
- clus2 = *p2;
- #ifdef debug
- printf("clus1=%4x clus2=%4x\n", clus1, clus2);
- #endif
- *p1 = clus2;
- *p2 = clus1;
-
- status = flirt(d1-1, sector1); /* mark sector dirty */
- if (status) {
- cputs("error in flirt\n\015");
- error("mvdir", 0);
- }
-
- status = flirt(d1-1, sector2); /* mark sectors as dirty */
- if (status) {
- cputs("error in flirt\n\015");
- error("mvdir", 0);
- }
-
- /* now we must find the cluster# of the parent directory of the
- ** destination directory (slot number two in clus2) so we can put
- ** it in the source directory (which will become the new destination
- ** directory.
- */
- ds1 = clus2sec(d1, clus1, &bps); /* sector# of cluster 1 */
- ds2 = clus2sec(d1, clus2, &bps); /* sector# of cluster 2 */
- secbuf3 = readsec(d1-1,ds2);
- if (secbuf3 == (char *) 0) {
- cputs("error in calling readsec\n\015");
- error("mvdir", 0);
- }
-
- parent = * (unsigned short *) (secbuf3 + 32 + ALLOC);
- #ifdef debug
- printf("parent is %4x\n", parent );
- #endif
-
- /* now write this into source dir */
-
- secbuf3 = readsec(d1-1,ds1);
- if (secbuf3 == (char *) 0) {
- cputs("error in calling readsec\n\015");
- error("mvdir", 0);
- }
-
- *(unsigned short *) (secbuf3 + 32 + ALLOC) = parent;
- status = flirt(d1-1,ds1);
- if (status) {
- cputs("error in flirt\n\015");
- error("mvdir", 0);
- }
-
- /* now write back all three (or less) modified sectors */
- status = writesec(d1-1,ds1); /* the cluster containing parent pointer */
- if (status) { /* what could cause this to happen? */
- cputs("error in writing first modified sector\n\015");
- error("mvdir", 1);
- }
-
- status = writesec(d1-1,sector2);
- if (status) { /* it's impossible for this to happen */
- cputs("error in writing second modified sector\n\015");
- error("mvdir", 1);
- }
-
- status = writesec(d1-1,sector1);
- if (status) { /* this is also impossible */
- cputs("error in writing third modified sector\n\015");
- error("mvdir", 1);
- }
-
- bdos(0xd,0,0); /* reset disk - neccessary for rmdir to work since DOS'
- ** buffer now contains invalid information (it didn't
- ** know that the disk was modified).
- */
- status = rmdir(source); /* this dir should be empty now */
- if (status) {
- putn(
- "Oops!\n\015",
- "cannot remove old directory \"", source, "\"\n\015",
- "Maybe one of your `subst' disk is using this directory. If this is\n\015",
- "the case, remove the subst disk and then remove this directory.\n\015", 0);
- exit(1);
- }
-
- bset(brk_st); /* restore break status */
- return 0; /* no error */
- }
-
- unsigned short findir(mydta, offsetp, drv, secbuf)
- char **secbuf;
- unsigned short *offsetp;
- unsigned int *drv;
- union dtbuf mydta;
- {
- unsigned int status, i, j, offset, sector, cluster, tmp, bps;
- union REGS inregs, outregs;
- struct SREGS segregs;
- char c, dir[13]; /* directory entry formatted like X.Y not "X Y " */
-
- if (mydta.dos.attr != A_DIR) { /* guard against programmer's error */
- putn(mydta.dos.fn, " is not a directory\n\015",0);
- error("findir", 0);
- }
-
- /* now find the cluster where the searched directory is */
- cluster = mydta.dos.clusl + (mydta.dos.clush << 8);
-
- /* now convert the cluster number to sector number */
- sector = clus2sec(mydta.dos.drv_no, cluster, &bps);
-
- /* calculate directory entry offset in the sector */
- offset = ((mydta.dos.sloth << 8) + mydta.dos.slotl) * 32;
-
- sector += offset / bps; /* normalize sector & offset */
- offset %= bps;
-
- #ifdef debug
- printf("dir at sector %d\n", sector);
- #endif
-
- *secbuf = readsec(mydta.dos.drv_no - 1, sector);
- if (*secbuf == (char *) 0) {
- cputs("error in calling readsec\n\015");
- error("findir", 0);
- }
-
- #ifdef debug
- printf("First 11 bytes in sector: %11.11s\n", *secbuf+offset);
- printf("Fn returned by ffmf: %11.11s\n", mydta.fn);
- #endif
-
- /* redundant check to see if we have the correct directory entry */
- /* first format the directory entry name in this form "*.*" instead of
- ** "???????????"
- */
- i=0;
- c = (*secbuf)[offset];
- while ((c != ' ') && (i < 8)) { /* copy the first 8 characters */
- dir[i] = c;
- i++;
- c = (*secbuf)[offset+i];
- }
-
- j = 8;
- c = (*secbuf)[offset+j];
- if (c != ' ') { /* sub-dir name has extension */
- /* now add '.' and copy the extension */
- dir[i] = '.';
- i++;
- while ((c != ' ') && (j < 11)) {
- dir[i] = c;
- i++;
- j++;
- c = (*secbuf)[offset + j];
- }
- }
- dir[i] = '\0'; /* terminate string */
- #ifdef debug
- printf("formatted directory entry string: %s\n", dir);
- #endif
-
- if (strcmp(mydta.dos.fn, dir) == 0) {
- #ifdef debug
- printf("Directory entry found!\n");
- #endif
- } else {
- cputs("cannot find directory entry\n\015");
- error("findir", 0);
- }
-
- /* redundant check to make sure file size of directory is zero */
- if (*(unsigned long *)(*secbuf+offset+28) != 0L) {
- cputs("found directory with size > 0\n\015");
- error("findir", 0);
- }
-
- *offsetp = offset;
- *drv = mydta.dos.drv_no;
- return sector;
- }
-
- unsigned short clus2sec(drv, clus_no, pbps) /* convert cluster to sector */
- unsigned short clus_no, *pbps, drv;
- {
- unsigned char status;
- static unsigned short spc=0, ss, bps, tabseg, taboff;
- unsigned short sector;
-
- if (spc == 0) { /* first time function is called */
- status = func32h(drv, &tabseg, &taboff); /* See PC Tech Journal */
- if (status == 0xff) {
- cputs("func32h: invalid drive: "); putch(drv+'A'); cputs("\n\015");
- error("clus2sec", 0);
- }
-
- spc = peekb(tabseg,taboff+4)+1; /* sector per cluster */
- ss = peekw(tabseg,taboff+11); /* starting data sector */
- bps = peekw(tabseg,taboff+2); /* bytes per sector */
-
- #ifdef debug
- printf("drive #: %d\n", drv);
- printf("sectors per cluster: %d\n", spc);
- printf("# allocation units: %d\n", peekw(tabseg,taboff+13)-1 );
- printf("sector size: %d\n", bps);
- printf("starting sector: %d\n", ss);
- #endif
- }
- *pbps = bps; /* return this value */
-
- if (clus_no == 0) {
- #ifdef debug
- printf("parent directory is root! - special case\n");
- #endif
- sector = peekw(tabseg,taboff+16); /* first sector of root directory */
- } else {
- sector = (clus_no - 2) * spc + ss; /* see DOS Tech. Ref */
- }
-
- return sector;
- }
-
- /* apreb test to see if patha is equal to or is a predessesor of pathb
- ** This is used to test whether moving a directory would result
- ** in a directory loop condition and also whether the source
- ** directory is a predessor of the current path (can't delete
- ** source directory in this case, so don't move)
- **
- ** patha and pathb must be normalized paths
- ** E.g.
- ** apreb("A:\DEF", "A:\DEF") is true
- ** apreb("A:\DEF", "A:\DEF\GHI") is also true
- ** apreb("A:\DEF", "A:\DEFG") is false
- */
- apreb(patha, pathb)
- char *patha, *pathb;
- {
- int i, lena, lenb;
- char c;
-
- lena = strlen(patha);
- lenb = strlen(pathb);
- if (lena > lenb) { /* if patha is longer, it can't be a predessesor */
- return 0;
- }
-
- c = pathb[lena]; /* if patha is a predessesor, c should be '\\' or '\0' */
- if ((c != '\\') && (c != '\0')) {
- return 0;
- }
-
- if (strncmp(patha, pathb, lena)) { /* not equal */
- return 0;
- }
-
- return 1;
- }
- 8-Sep-86 16:13:42-PDT,14202;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:12:30 PDT
- Received: by unix.macc.wisc.edu;
- id AA04958; 4.12/5; Mon, 8 Sep 86 17:31:19 cdt
- Date: Mon, 8 Sep 86 17:31:19 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082231.AA04958@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: front.c
-
- /* Program to move files and/or subdirectories - like mv on unix
- ** Written by Peter Wu July, 86 @ Faculty Support Center @ UW-Madison
- ** Compile with IBM C version 1.00 (or Microsoft C 3.00).
- ** Link with fstat, mv, normal, sector, absdr, func32h, break, putn /stack:5000
- **
- ** This is module "front.c", the front end of mv. It looks at the sources
- ** and destination supplied by the user and determines whether to call
- ** mvdir to move/rename sub-directories or call rename to move/rename files.
- */
-
- /* programmer's notes:
- -- won't work on network disk
- --
- -- things to work on:
- --
- -- be interactive:
- -- ask if user wants to replace existing file/directory
- -- verbose mode where user must confirm each move
- -- better error handling
- -- make it work on network disks
- -- detect and report write-protected disk if possible
- -- allow /f option on destination?
- --
- -- bugs:
- +--------------------------------+
- | c: |
- | subst p: /user/peter/mv/test |
- | mv /usr/peter/mv/test . |
- +--------------------------------+
- -- The above sequence will prevent mv from removing the source directory after
- -- the content is moved to the destination directory. I don't know any way to
- -- detect this BEFORE moving the content. So my solution is to print a message
- -- telling the user to remove the source directory (now empty) by hand after
- -- he got rid of the 'subst drive'.
- */
- #define LINT_ARGS
-
- #define UNK_TYP 0
-
- #define A_INT 0x80 /* interactive file attribute */
-
- #define LASTDRV 26 /* drive# larger than this is network share disk */
- #define NULL (char *) 0
- #define PLEN 200 /* max. path length; hope it's long enough */
-
- #include "dta.h"
- #include "date.h"
- #include <conio.h>
- #include <string.h>
- #include <stdlib.h>
-
- char lastc(char *);
- char getkey(char *);
-
- int brk_st; /* original break status: 0=break off, 1=break on */
-
- /* When break is on, user can break the program when any DOS function is
- ** called. When break is off, user can only break the program when a DOS
- ** I/O function is called (if the user presses break before an I/O function,
- ** DOS will remember the break but let the program keep running until the
- ** program calls an IO function). It is undesirable to have break on
- ** all the time since for instance if the user breaks the program after I
- ** wrote one sector to disk (I need to write three sectors per sub-directory
- ** moved), he'll end up with an inconsistent directory. The solution is to
- ** make sure break is off when I'm doing disk writes, and restore it
- ** to its orginal status when I'm done writing the disk.
- ** If the user really wants to mess up his disk, he can still do it with
- ** ctrl-alt-del or switching the power off in the middle of running mv.
- */
-
- main(argc,argv)
- int argc;
- char *argv[];
- {
- unsigned int status, dtype, stype, status2, smask, dmask, i, drv, plimit,
- doit;
- union dtbuf mydta1, mydta2, tmpdta;
- char fsource[PLEN], fdest[PLEN], *source, *dest, *tmp, fdest2[PLEN];
-
- if (argc < 3) { /* print help */
- putn(
-
- "Usage: MV <source1> <source2> .. <sourceN> <dest>\n\15",
- " MV renames/moves the source files/directories to the destination.\n\15",
- " Wildcards ok. Specify source type with /d, /f, /h, and /i.\n\15",
- " /d=sub-directories, /f=files, /h=search hidden, /i=interactive.\n\15",
- " \"*.*\\.\" or \"*.*/d\" specifies all sub-directories only\n\15",
- " \"*.*/f\" specifies all visible files only\n\15",
- " \"*.*/hf\" specifies all visible and hidden files\n\15",
- " \"*.*/fi\" will prompt you (move or not) for every file found\n\15",
- " Version 1.20 made ", date, ". For DOS 2.xx and 3.xx.\n\n\15",
- "Please send comments/bug reports to one of the following addresses:\n\15",
- " Arpanet: pwu@unix.macc.wisc.edu\n\15",
- " Bitnet: WU at WISVMACC\n\15",
- " CompuServe: 76377,1332\n\15",
- " UUCP: {akgua|ihnp4|seismo|harvard|allegra|ucbvax}!uwvax!uwmacc!pwu\n\15",
- NULL);
-
- exit(0);
- }
-
- /* test DOS version */
- switch (_osmajor) {
- case 2: /* dos 2.xx */
- break;
- case 3: /* dos 3.xx */
- if (_osminor <= 20) { /* make sure it's no later than version 3.20 */
- break;
- }
- default:
- cputs("need DOS between version 2.00 and 3.20\n\15");
- exit(1);
- }
-
- plimit = PLEN - 80; /* limit on user supplied path name */
-
- /* process destination first */
- dest = argv[argc-1];
- if (strlen(dest) > plimit) {
- cputs("destination path too long\n\15");
- exit(1);
- }
-
- strcpy(fdest,dest);
- dtype = normal(fdest); /* normalize destination path */
-
- if (dtype == 0) { /* no specified type for destination */
- dmask = A_FIL | A_DIR;
- } else {
- dmask = dtype;
- }
-
- status2 = ffmf(fdest, A_MASK, &mydta2); /* find info on dest */
- #ifdef debug
- printf("fdest is %s, dmask=%d, status2 = %d\n", fdest, dmask, status2);
- #endif
-
- if (!status2) { /* if destination exists */
- #ifdef debug
- printf("destination exists and has attr: %x\n", mydta2.dos.attr);
- #endif
- /* check if destination is ambigious here */
- if (lastc(fdest) != '\\') { /* root would cause error, so don't check it */
- tmpdta = mydta2; /* don't disturb mydta2, we need it later */
- status = fnmf(&tmpdta);
- if (!status) { /* ha, there's more than one destination! */
- cputs("destination is ambigious\n\15");
- exit(1);
- }
- }
-
- /* if destination is an existing file, report error */
- if ((mydta2.dos.attr & A_DIR) == 0) {
- cputs("destination is an existing file!\n\15");
- exit(1);
- }
-
- /* fix fdest so that a destination of "*\." will have the expanded name
- ** by removing the * and appending the directory name found by ffmf.
- ** This will cause an error if fdest is the root of a 'subst' disk,
- ** so we must make sure fdest is not a root.
- */
- if (lastc(fdest) != '\\') { /* if not root then */
- tmp = strrchr(fdest,'\\'); /* find last '\' */
- if (tmp == NULL) { /* no '\' ????!!!! */
- cputs("error after strrchr: cannot find \\\n\15");
- error("front",0);
- }
- strcpy(tmp+1, mydta2.dos.fn); /* dest with wild cards expanded */
- }
-
- } else { /* destination not found */
-
- #ifdef debug
- printf("destination not exists\n");
- #endif
-
- if (dtype == A_DIR) { /* specified directory not exist */
- cputs("can't find destination directory\n\15");
- exit(1);
- } else { /* destination type not specified or of file type */
- /* check: source better be unambigious */
- if (argc > 3) {
- cputs("can't rename more than one source\n\15");
- exit(1);
- }
- /* destination is not found, let's lookup destination's parent.
- ** This has to exist (e.g. if C:\X\Y is destination and doesn't
- ** exist, C:\X should still exists). This lookup also allows us
- ** to compare the drive number between the destination and the
- ** source to detect cross device move.
- */
- strcpy(fdest2, fdest);
- chopath(fdest2); /* remove last portion of path */
- status = ffmf(fdest2, A_MASK, &mydta2);
- if (status) { /* if destination's parent doesn't exist */
- putn("path \"", fdest2, "\" not exist!\n\15", 0);
- exit(1);
- } else if ((mydta2.dos.attr & A_DIR) == 0) { /* not a directory */
- putn("\"", fdest2, "\" is not a directory!\n\15", 0);
- exit(1);
- }
- }
- }
-
- brk_st = bstat(); /* get current break status (on or off) */
-
- /***********************************************************/
- /* now process SOURCE **************************************/
- /***********************************************************/
- for (i=1; i < argc - 1; i++) { /* for all source specification */
- source = argv[i];
- if (strlen(source) > plimit) { /* rare user error but just in case */
- cputs("source path too long! skipped\n\15");
- continue; /* next argument */
- }
-
- strcpy(fsource,source);
- stype = extype(fsource); /* extract type */
- stype |= normal(fsource); /* normalize source path */
-
- #ifdef debug
- printf("normalized source path: %s\n", fsource);
- #endif
-
- if ((stype & (A_DIR | A_FIL)) == 0) { /* no specified type, use default */
- smask = stype | A_FIL | A_DIR; /* look for file or directory */
- } else {
- smask = stype;
- }
-
- status = ffmf(fsource, smask, &mydta1); /* find info on source */
- if (status) {
- putn(source, " not found\n\15", 0);
- continue;
- }
-
- /* see if source is on a network disk */
- if ((mydta1.dos.drv_no < 0) || (mydta1.dos.drv_no >= LASTDRV)) {
- cputs("sorry, mv doesn't work on network disks\n\15");
- exit(1);
- }
-
- /* is source and destination on same drive? */
- if (mydta1.dos.drv_no != mydta2.dos.drv_no) {
- cputs("source and destination must be on same physical drive\n\15");
- exit(1);
- }
-
- /* check: if destination does not exist, source better be unique */
- if (status2) { /* destination does not exist */
- if (lastc(fsource) != '\\') { /* don't call fnmf on root */
- tmpdta = mydta1; /* do not change mydta1, mess with a copy */
- status = fnmf(&tmpdta); /* see if there's more than one source */
- if (!status) { /* source is ambigious */
- cputs("can't rename more than one source\n\15");
- exit(1);
- }
- }
- }
-
- do { /* repeat for all source wildcard */
-
- #ifdef debug
- printf("source found, fn: %s\n", mydta1.dos.fn);
- printf("found attribute is %2xh\n", mydta1.dos.attr);
- #endif
-
- /* form source name with wild cards expanded */
- chopath(fsource); /* chop off wild cards */
- catpath(fsource, mydta1.dos.fn); /* append expanded name */
-
- if (status2) { /* destination not exist */
-
- if (stype & A_INT) { /* interactive mode */
- doit = prompt(fsource,fdest);
- } else { /* in batch mode, always do it */
- putn(fsource, " DD ", fdest, " ", 0);
- doit = 1; /* do it! */
- }
-
- if (doit) {
-
- if (mydta1.dos.attr & A_DIR) { /* rename or move directory */
-
- status = mvdir(mydta1, fsource, fdest);
- if (!status) {
- cputs("OK.\n\15");
- }
-
- } else { /* rename or move file */
-
- /* don't know what rename does when user presses break key,
- ** so set break off to be safe
- */
- bset(0); /* turn break off (disable break key) */
- status = rename(fdest,fsource); /* use fdest or dest? */
- bset(brk_st); /* restore break status to orginal value */
-
- if (status) {
- putn("can't\n\15",
- "invalid file name/disk write protected\n\15", 0);
- } else {
- cputs("ok\n\15");
- }
- /* fall thru to fnmf */
- }
-
- } else { /* doit = 0, because the user press 'n' */
-
- cputs("not moved\15\n");
-
- }
-
- } else { /* now handle the case when destination do exists */
-
- #ifdef debug
- printf("dest exists, let's see...\n");
- #endif
-
- if (mydta2.dos.attr & A_DIR) { /* destination is a directory */
- #ifdef debug
- printf("before strcat fdest is %s\n", fdest);
- printf("now cat with %13.13s\n", mydta1.dos.fn);
- #endif
-
- /* create destination + tail of source in fdest2
- ** e.g. source = \user\peter\cat
- ** destination = \junk\haha
- ** fdest2 = \junk\haha\cat
- */
- strcpy(fdest2, fdest); /* make a work copy */
- catpath(fdest2, mydta1.dos.fn);
-
- if (stype & A_INT) { /* interactive mode */
- doit = prompt(fsource,fdest2);
- } else { /* in batch mode, always do it */
- putn(fsource, " DD ", fdest2, " ", 0);
- doit = 1; /* do it! */
- }
-
- if (doit) {
-
- #ifdef debug
- printf("dest+tail of source: %s\n", fdest2);
- #endif
-
- if (mydta1.dos.attr & A_DIR) { /* source is also a directory */
-
- status = mvdir(mydta1, fsource, fdest2);
- if (!status) {
- cputs("OK.\n\15");
- }
- /* fall down to fnmf */
-
- } else { /* move a file into a directory */
-
- bset(0); /* turn break off (disable break key) */
- status = rename(fdest2, fsource);
- bset(brk_st); /* set break status to orginal value */
-
- if (status) {
- cputs("can't; file exists already/disk write-protected\n\15");
- } else {
- cputs("ok.\n\15");
- }
- }
- } else { /* doit = 0 */
- cputs("not moved\15\n");
- }
-
- } else { /* dest is an existing file! */
-
- putn(fsource, " DD ", fdest,
- " can't rename: file exists already\n\15", 0);
-
- }
-
- } /* if dest exist or not */
-
- status = fnmf(&mydta1); /* find info on next matching source */
-
- } while (status == 0); /* while there are matching files */
- } /* for different sources */
-
- exit(0); /* no error */
- }
-
- prompt(s,d) /* return 1 for 'y'; 0 for 'n' */
- char *s, *d; /* part of the prompt */
- {
- char c;
-
- do {
- putn(s, " DD ", d, " (y/n/q; ?=help): ", 0);
- c = getkey("yYnNqQ?");
- putch(' ');
- switch (c) {
-
- case '?':
- putn("\15\n",
- "y - yes, move it\15\n",
- "n - no, skip it\15\n",
- "q - quit to DOS\15\n",
- "? - this help message\15\n\n",
- 0);
- break;
-
- case 'y':
- case 'Y':
- return 1;
-
- case 'n':
- case 'N':
- return 0;
-
- case 'q':
- case 'Q':
- cputs("Quit.\15\n");
- exit(0);
-
- default:
- cputs("\15\nHow do I get here?\15\n");
- error("prompt",0);
-
- } /* end switch */
- } while (1);
- }
-
- char getkey(valid) /* wait for valid key and echo it */
- char *valid;
- {
- char c;
- int i;
-
- do {
- c = getch();
- i = index(valid,c);
- if (i > -1) {
- putch(c); /* echo valid key */
- return c;
- } else { /* beep at invalid key */
- putch(7);
- }
- } while (1);
- }
- 8-Sep-86 16:23:29-PDT,962;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:18:48 PDT
- Received: by unix.macc.wisc.edu;
- id AA04970; 4.12/5; Mon, 8 Sep 86 17:31:37 cdt
- Date: Mon, 8 Sep 86 17:31:37 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082231.AA04970@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: mv
-
- front.obj: front.c date.h dta.h
- cc front /OT;
-
- mv.obj: mv.c dta.h peek.h
- cc mv /ze /OT;
-
- fstat.obj: fstat.c dta.h
- cc fstat /OT;
-
- normal.obj: normal.c dta.h
- cc normal /OT;
-
- sector.obj: sector.c
- cc sector /OT;
-
- break.obj: break.c
- cc break /OT;
-
- error.obj: error.c
- cc error;
-
- func32h.obj: func32h.asm
- masm func32h;
-
- absdr.obj: absdr.asm
- masm absdr;
-
- putn.obj: putn.asm
- masm putn;
-
- mv.exe: mv.obj fstat.obj normal.obj front.c sector.obj func32h.obj absdr.obj
- clink mv fstat normal front sector break func32h absdr putn error /stack:5000;
- 8-Sep-86 16:23:33-PDT,1009;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:19:01 PDT
- Received: by unix.macc.wisc.edu;
- id AA04924; 4.12/5; Mon, 8 Sep 86 17:30:36 cdt
- Date: Mon, 8 Sep 86 17:30:36 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082230.AA04924@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: break.c
-
- /* routines to read break status and set break status (to on or off) */
-
- #include <dos.h>
-
- bstat() /* get break status 0=off, 1=on */
- {
- union REGS inregs, outregs;
-
- inregs.h.al = 0; /* request break status */
- inregs.h.ah = 0x33; /* DOS function for ctrl-break check */
- intdos(&inregs, &outregs);
- return outregs.h.dl;
- }
-
- bset(onoff) /* set break status 0=off 1=on */
- {
- union REGS inregs, outregs;
-
- inregs.h.al = 1; /* set break status */
- inregs.h.ah = 0x33; /* DOS function for ctrl-break check */
- inregs.h.dl = onoff; /* set to on or off */
- intdos(&inregs, &outregs);
- }
- 8-Sep-86 16:23:36-PDT,1153;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:19:27 PDT
- Received: by unix.macc.wisc.edu;
- id AA04992; 4.12/5; Mon, 8 Sep 86 17:32:20 cdt
- Date: Mon, 8 Sep 86 17:32:20 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082232.AA04992@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: putn.asm
-
- ; allows C program to call cputs with multiple arguments.
- ; E.g. putn("How ", "are ", "you?", 0);
- ; the last argument must be either 0 or ""
-
- _text segment public byte 'code'
- assume cs:_text
-
- extrn _cputs:near
-
- public _putn
- _putn proc near
- push si
- push di
- push bp
- mov bp,sp
-
- mov si,8
- loop:
- mov di,[bp+si] ; get next string
- or di,di ; is it NULL
- je done ; if so, nothing more to print
- or byte ptr [di],0 ; it is "" (null string)
- je done ; if so, nothing more to print
-
- ; now call cputs to print the string
- push di ; push parameter on stack
- call _cputs
- pop di ; get rid of parameter on stack
-
- add si,2 ; point to next parameter
- jmp loop
-
- done:
- pop bp
- pop di
- pop si
- ret
- _putn endp
- _text ends
- end
- 8-Sep-86 16:23:47-PDT,1765;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:19:46 PDT
- Received: by unix.macc.wisc.edu;
- id AA04919; 4.12/5; Mon, 8 Sep 86 17:30:29 cdt
- Date: Mon, 8 Sep 86 17:30:29 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082230.AA04919@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: absdr.asm
-
- ; bios call to do absolute disk read/write
- ; using int86 from C to call int 25h and 26h will freeze the computer
- ; (because si and di were modified?), so I had to write this in assembly.
-
- _text segment public byte 'code'
- assume cs:_text
-
- public _absdr ; absolute disk read
- _absdr proc near
- push si
- push di
- push bp
- mov bp,sp
-
- mov al,[bp+8] ; drive number
- mov cx,[bp+10] ; number of sectors to read
- mov dx,[bp+12] ; beginning sector number
- mov bx,[bp+14] ; buffer address
- int 25h ; absolute disk read
- ; int 25h supposed to destroy all registers except segment registers
- jc error ; if error, leave error no in AX
- mov ax,0 ; clear error number if no error
- error:
- inc sp ; pop the flags
- inc sp ; pop the flags
- pop bp
- pop di
- pop si
- ret
- _absdr endp
-
- public _absdw ; absolute disk write
- _absdw proc near
- push si
- push di
- push bp
- mov bp,sp
-
- mov al,[bp+8] ; drive number
- mov cx,[bp+10] ; number of sectors to read
- mov dx,[bp+12] ; beginning sector number
- mov bx,[bp+14] ; buffer address
- int 26h ; absolute disk read
- ; int 26h supposed to destroy all registers except segment registers
- jc error1 ; if error, leave error no in AX
- mov ax,0 ; clear error number if no error
- error1:
- inc sp ; pop the flags
- inc sp ; pop the flags
- pop bp
- pop di
- pop si
- ret
- _absdw endp
-
- _text ends
- end
- 8-Sep-86 16:33:37-PDT,1389;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:33:05 PDT
- Received: by unix.macc.wisc.edu;
- id AA04941; 4.12/5; Mon, 8 Sep 86 17:31:04 cdt
- Date: Mon, 8 Sep 86 17:31:04 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082231.AA04941@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: error.c
-
- /* handle internal errors */
-
-
- /* global variable */
- int brk_st; /* orginal break status */
-
- error(where,panic)
- char *where; /* call from what procedure */
- int panic; /* should I tell the user to panic? 0=no 1=yes */
- {
- putn("MV stopped due to internal error in '", where, "'\n\015", 0);
- if (panic) { /* this should never happen */
- putn("Because of this error, your disk directory might be in an\n\015",
- "inconsistent state. Please run chkdsk on your disk to see\n\015",
- "if this is so. Sorry.\n\015", 0);
- } else { /* not to panic */
- putn("Do not worry, your disk is not screwed up, only that the\n\015",
- "operation you requested was not completed.\n\015", 0);
- }
- putn("Please report this error to the author of this program. You can\n\015",
- "obtain his email address by typing 'mv' with no parameters.\n\015", 0);
-
- /* now restore break status to whatever the user set it to */
- bset(brk_st);
- exit(2); /* indicate internal error */
- }
-