/* BACKUP is by Steve de Plater 66 Priam St. Chester Hill, NSW, 2162, Australia Phone: (02) 644 4009 VERSION LIST - Most recent version first. 04/Jul/82 Added "usage" display when a "?" is entered on command line or in response to drive prompt. Bill Bolton, Software Tools You may make as many copies of this programme in either source or .COM forms as you like for your own use, or for your friends, relatives, dogs, cats, mothers-in-law etc. HOWEVER if I ever hear of anyone commercially marketing this I'll come and find them and insert their heads into an S-100 slot!!! All I ask is that because I did the original work that you leave my name where it is in the programme. After all, nobody else should get the blame for my shoddy programming! The function of BACKUP is to copy files from one disk to another much as PIP does. The difference is that BACKUP normally will not make a copy when a filename is found on the destination disk. Therefore, if this programme is used then you can be sure that NO files will accidently be clobbered! BACKUP also allows the following features: (i) many filename masks may be included together. They must be separated only by commas, NO SPACES! e.g. "*.com,backup.c" (ii) The NOT wildcard is supported when used as the first character of a filename mask. e.g. "!*.com" would match ALL the non .COM files. (iii) both source and destination disks may be changed many times during a run, as prompted by BACKUP. (iv) If required, existing files may be renamed as .BAK and then the copy will proceed. (v) If required, then ONLY existing files will be copied e.g. for installing an updated copy of a compiler etc. (vi) If required, the copy will be stopped at the first ^Z detected. (vii) If required, the VERIFY programme will be called automatically, and the BACKUP parameters will be passed to it. CALLING PROCEDURE: BACKUP may be called simply by typing BACKUP; however, the following parameters may be included on the CP/M command line: (i) mask(s) This must be the first parameter and will control which files are copied. ALL THE PARAMETERS WHICH FOLLOW MAY OCCUR IN ANY ORDER AT ALL WITH OR WITHOUT SPACES BETWEEN THEM. (ii) d copy TO drive 'd' (iv) n Don't prompt for disk changes (v) b If file exists rename to .BAK and then copy (vi) v Run VERIFY after BACKUP is finished (vii) z Copy only to the first CP/M EOF (^Z). (viii) i Inverse mode. Copy ONLY files which exist on both source and destination disks. (ix) d Debug mode. Show where everything is in RAM BACKUP configures itself to make the most of your system. (x) r Remember which files have been backed up so that subsequent runs will not repeat. (Implies also the Check mode below.) (xi) c Check (only) for previous backups (xii) p Print out parameter settings \*******************************************************/ #include bdscio.h #define VERSION "1.3" #define STACKSPACE 0x1000 #define DATE "July 5th, 1982" #define TIME "14:00" #define V_DEFAULT FALSE /* these default values */ #define Z_DEFAULT FALSE /* should be changed to */ #define N_DEFAULT FALSE /* configure any special*/ #define B_DEFAULT FALSE /* BACKUP for any */ #define M_DEFAULT FALSE /* particular application*/ #define D_DEFAULT FALSE #define R_DEFAULT FALSE #define C_DEFAULT FALSE #define P_DEFAULT TRUE char mask [50]; /* Buffer for filename masks */ char pass_mask [50]; /* The masks passed to VERIFY*/ char work_mask [16]; char fcb1 [36]; char fn [14]; int code; int files; int copies; char *dir; /* Where to find DIR */ char *databuf; /* Where to buffer stuff */ unsigned stackspace; int sectors; /* sectors to buffer */ char id; char od; char ld; char fn1 [16]; char fn2 [16]; char fn3 [16]; char fn4 [16]; char temp [20]; char verify; char ctr_z; int found_eof; int no_wait; int debug; int bak; int mode; int remember; int check; int parm; int no_bak; int read_only; int system; int bak_flag; int not_mask; char mask2 [36]; int masks; int matched; int total_matched; int total_copied; int no_questions; main (argc,argv) char **argv; { int x; int p,z; char *y; y = 0x501; *y = 0x20; /* modifies fn 'legfc' in RTP */ stackspace = STACKSPACE; /* configure */ dir = endext (); /* the RAM */ printf ("\nBACKUP, Ver %s, ",VERSION); printf ("%s, by Steve de Plater\n\n",DATE); verify = V_DEFAULT; ctr_z = Z_DEFAULT; no_wait = N_DEFAULT; bak = B_DEFAULT; mode = M_DEFAULT; debug = D_DEFAULT; remember = R_DEFAULT; check = C_DEFAULT; parm = P_DEFAULT; getclp (argc,argv,&id,&od, &verify,&ctr_z,&no_wait,&bak,&mode,&debug, &remember,&check,&parm); if (remember) check = TRUE; if (parm){ printf ("Parameter flag settings for this run are:\n"); printflg ("(i) Run Verify :",verify); printflg ("(ii) Stop on ^Z :",ctr_z); printflg ("(iii) No-Waiting :",no_wait); printflg ("(iv) Backup file :",bak); printflg ("(v) Inverse mode :",mode); printflg ("(vi) Debug mode :",debug); printflg ("(vii) Remember :",remember); printflg ("(viii) Check prev. :",check); putch ('\n'); } if (argc < 2) getmask (); else strcpy (mask,argv[1]); strcpy (pass_mask,mask); ld=bdos(25) + 'A'; matched = copies = total_matched = total_copied = 0; no_questions = TRUE; do_it (); } getmask () { int x; printf ("Which files? "); gets (mask); for (x=0; *(mask+x); x++) *(mask+x) = toupper (*(mask+x)); no_questions = FALSE; } getdir (fcb) char *fcb; { int x,y,z; char *s; y=files<<4; s=0x80+(code<<5); if (*(s+12)) return; files++; for (x=0; x<16; x++){ dir[y]=*(s+x); y++; } } match_mask (s) char *s; { int x,y; y=TRUE; for (x=1; x<12; x++){ if (((*(s+x)&0x7f) != mask2[x]) && (mask2[x] != '?' )){ y=FALSE; } } if (not_mask) return !y; else return y; } does_exist (s) char *s; { char fcb [36]; setfcb (fcb,s); if (bdos (17,fcb) > 3) return FALSE; else return TRUE; } copy (s1,s2) char *s1,*s2; { int fd1,fd2; int x,y,z; int records; records=0; if ((fd1=open (s1,0)) == ERROR){ printf (" OPEN ERROR: Can't open '%s\n",s1); quit (1); } if ((fd2=creat (s2)) == ERROR){ change_disks (s2,fd1,fd2); return; } found_eof = FALSE; while (TRUE){ x = read (fd1,databuf,sectors); if (!x) break; if (ctr_z) z = check_eof (databuf,x); /* returns sector */ else /* which contains */ z = x; /* ^Z */ y = write (fd2,databuf,z); if (y != z){ change_disks (s2,fd1,fd2); return; } records+=z; if (z < sectors) break; if (found_eof) break; } close (fd2); fabort (fd1); fabort (fd2); printf ("%4d records ",records); if (read_only) printf ("R/O "); else printf (" "); if (system) printf ("SYS "); else printf (" "); if (bak_flag) printf ("BAK"); putch ('\n'); copies++; } quit (a) int a; { char t1[5],t2[5]; if (!a){ printf ("%d file",matched); if (matched != 1) putch ('s'); printf (" matched, %d copied\n",copies); } total_matched += matched; matched = 0; total_copied += copies; copies = 0; if (!no_wait){ printf ("\nMore ? "); if (toupper (getchar ()) == 'Y'){ printf ("\n\n"); getmask (); id = od = FALSE; do_it (); } printf ("\nTotal Matched %d, Total Copied %d", total_matched,total_copied); printf ("\nMount system disk on drive '%c'\n",ld); printf (" press to continue: "); bios (3); putch ('\n'); } temp[0]=ld; temp[1]=':'; temp[2]=0; strcat (temp,"verify.com"); if (verify) if (does_exist (temp)){ t1[0]=id; t2[0]=od; t1[1]=0; t2[1]=0; strcpy (temp,"<"); strcat (temp,t1); strcat (temp,">"); strcat (temp,t2); if (ctr_z) strcat (temp,"Z"); if (no_wait) strcat (temp,"N"); if (debug) strcat (temp,"D"); execl ("verify",pass_mask,temp,0); } else printf ("\nVERIFY.COM not on logged disk\n"); exit (0); } trim_mask (s) char *s; { char *x; char t[16]; x=s; if (*(x+1) == ':') x+=2; strcpy (t,x); strcpy (s,t); } check_eof (s,a) int a; char *s; { int x,y; y=a<<7; for (x=0; x>7)+1); found_eof = TRUE; } return a; } getclp (argc,argv,i,o,v,z,n,b,m,d,r,c,p) int argc; char **argv; char *i; /* source disk */ char *o; /* destination disk */ int *v; /* verify flag */ int *z; /* CP/M EOF (^Z) flag */ int *n; /* no stop for disk change flag */ int *b; /* >> to 'file'.BAK */ int *m; /* mode flag, 'i' for inverse */ int *d; /* debug mode flag */ int *r; /* Remember (f4) flag */ int *c; /* Check the (f4) flag */ int *p; /* Print out Parameter settings */ { char line [100]; int x; *i=*o=FALSE; if (argc<3){ if (*argv[1] == '?'){ usage(); exit(0); } return; } strcpy (line,argv[2]); for (x=3; x': { *o=line[x+1]; x++; break; } case '(': { *i=line[x+1]; x++; break; } case ')': { *o=line[x+1]; x++; break; } case 'V': { *v=!(*v); break; } case 'Z': { *z=!(*z); break; } case 'N': { *n=!(*n); break; } case 'B': { *b=!(*b); break; } case 'I': { *m=!(*m); break; } case 'D': { *d=!(*d); break; } case 'R': { *r=!(*r); break; } case 'C': { *c=!(*c); break; } case 'P': { *p=!(*p); break; } case '?': { usage(); exit(0); } } } bak_file () { int z; if (check) if (marked (fn1)){ printf ("Not copying: %-14.14s - previously backed up\n",fn1); return; } printf ("Copying : %-14.14s - ",fn1); copy (fn1,fn2); if (read_only || system){ strcpy (fn1,fn2); for (z=0; z<14; z++){ if (fn2[z] != '.') continue; z++; if (read_only) fn2[z]=fn2[z]|0x80; z++; if (system) fn2[z]=fn2[z]|0x80; } rename (fn1,fn2); } if (remember) mark (fn1); } cant_kill (fn) char *fn; { int x,y,z; char myfcb [36]; char *dma; setfcb (myfcb,fn); x = bdos (17,myfcb); if (x>3) return FALSE; x=x<<5; dma=0x80; return *(dma+x+9)&0x80; } bak_nor () { if (does_exist (fn2)){ if ((bak) && (!no_bak)){ unlink (fn3); rename (fn2,fn3); bak_flag=TRUE; bak_file (); } else{ printf ("File exists: %-14.14s",fn2); if ((bak) && (no_bak)) printf (" - Read Only!"); putch ('\n'); } } else bak_file (); } bak_inv () { if (!does_exist (fn2)) return; if (bak && !no_bak){ unlink (fn3); rename (fn2,fn3); bak_flag=TRUE; } else{ if (cant_kill (fn2)){ printf ("FILE EXISTS: %-14.14s",fn2); printf (" - Read Only!\n"); return; } unlink (fn2); } bak_file (); } block_copy (s) char *s; { int x,z,p; char *y; int block_size; printf ("Matching mask '%s'\n\n",s); block_size=0; for (x=0; x= strlen(mask)) return; if (x) x++; for (y=x; y 'P') || (od < 'A') || (od > 'P')){ printf ("\nINVALID DRIVE NAME!\n"); exit (1); } if (!no_questions) printf ("\n"); if (!no_wait){ printf ("Mount disks, to continue: "); bios (3); printf ("\n\n"); bdos (13); } files = 0; temp[0]=id; temp[1]=':'; temp[2]=0; strcat (temp,"*.*"); setfcb (fcb1,temp); code = bdos (17,fcb1); /* search for first */ if (code > 3){ printf ("NO FILE\n"); quit (1); } getdir (fcb1); while (TRUE){ code = bdos (18); if (code > 3) break; getdir (fcb1); } config2(); masks=0; mask_num (0); while (strlen(work_mask)){ block_copy (work_mask); masks++; mask_num (masks); } quit (0); } config2() { unsigned x,p,z; char *y,*top; top = (topofmem() - stackspace) & 0xff00; x = 16*files; p = (dir + x + 0x101); databuf = p & 0xff00; sectors = (top - databuf) >> 7; if (sectors < 8){ printf ("NOT ENOUGH RAM TO RUN THIS PROGRAMME\n"); quit (1); } if (debug){ printf ("Compiled on %s, at %s\n\n",DATE,TIME); printf ("Directory assigned at: %04x\n",dir); printf ("Entries found: %4d\n", files); printf ("Buffer assigned at: %04x\n",databuf); printf ("Max. Records buffered: %4d\n", sectors); printf ("Stackspace Reserved: %04x\n",stackspace); printf ("Top of Buffer at: %04x\n\n",top); } } marked (s) char *s; { char fcb [36]; int c; char *p; setfcb (fcb,s); c = bdos (17,fcb); p = 0x80 + 32*c + 4; if ((*p) & 0x80) return TRUE; else return FALSE; } mark (s) char *s; { char fcb [36]; setfcb (fcb,s); fcb[4] = fcb[4] | 0x80; bdos (30,fcb); } change_disks (s2,fd1,fd2) char *s2; int fd1; int fd2; { char fcb [36]; int x; setfcb (fcb,s2); for (x=1; x<13; x++) fcb[x]=fcb[x]&0x7f; bdos (30,fcb); /* reset flags (R/O etc), and */ bdos (19,fcb); /* delete incomplete copy */ fabort (fd1); /* and free up the fds in */ fabort (fd2); /* the rtp */ printf ("DESTINATION DISK IS FULL,\n\n"); printf (" Change disk on drive '%c',\n",od); printf (" press to continue: "); bios (3); printf ("\n\n"); bdos (13); if (!mode) /* check inverse mode */ bak_nor (); /* and try again */ else bak_inv (); } printflg (s,a) char *s; int a; { printf (" %s ",s); if (a) printf ("ON\n"); else printf ("OFF\n"); } usage() { printf("Usage : \t BACKUP parameters\n\n"); printf("Where valid parameters are:\n\n"); printf("(i)\tmask(s)\tThis must be the first parameter and will\n"); printf("\t\tcontrol which files are copied.\n\n"); printf("ALL THE PARAMETERS WHICH FOLLOW MAY OCCUR IN ANY ORDER\n\n"); printf("(ii)\td\tcopy TO drive 'd'\n"); printf("(iv)\tn\tDon't prompt for disk changes\n"); printf("(v)\tb\tIf file exists rename to .BAK and then copy\n"); printf("(vi)\tv\tRun VERIFY after BACKUP is finished\n"); printf("(vii)\tz\tCopy only to the first CP/M EOF (^Z).\n"); printf("(viii)\ti\tCopy ONLY files which exist on source and dest\n"); printf("(ix)\td\tDebug mode. Show where everything is in RAM\n"); printf("(x)\tr\tTag files as they are backed up\n"); printf("(xi)\tc\tCheck (only) for previous backups\n"); printf("(xii)\tp\tPrint out parameter settings\n"); } .