/* tsxutl.c */ /* * TSX+ Utilities */ #include #include #include "tsxutl.h" #include "rtfile.h" #include "logdsk.h" #include "detach.h" #include "prgreq.h" #include "suspnd.h" int execmd = EXECMDFIL; /* execute command file */ int delcmd = DELCMDFIL; /* delete command file */ char errstr[80]; /* all encompassing error report string */ int subdnest = SUBDNEST; /* maximum nesting of subdirectories */ int subdbase = SUBDBASE; /* first 'ld' unit */ int subdlevl = 0; /* subdirectory level */ static char defdev[6] = { 'd', 'k', ':', 0, 0, 0 }; static char lclname[16]; static char rmtname[16]; static char filename[16]; static FILE *iop = NULL; static char device[6] = { 'd', 'k', ':', 0, 0, 0 }; static char subnam[8][8]; static char subext[8][4]; static char subfil[16]; static char slash = '\\'; static char savpath[94]; char *filtxt[] = { "TSX-Plus filespec = {dev:}{name}{.ext}{[xx]}", " where {dev:} = 1 to 3 characters (1st alpha)", " {name} = 1 to 6 characters (*=all,?=wild,%=wild)", " {.ext} = 1 to 3 characters (*=all,?=wild,%=wild)", " {[xx]} = file size allocation, -1 = all available", " note: dev: => dev:*.* / * => *.*", " subdirectories => dev:/sub1/sub2/.../{name}{.ext}{[xx]} (or \\)", "", 0 }; /* * rtusage * * printout the filespec data */ VOID rtusage() { char **dp; for (dp = filtxt; *dp; dp++) { RTPRINT("%s\r\n", *dp); } } /* * Local filespec */ char *lclfile(s) char *s; { strcpy(lclname,rtfile(s,defdev)); return(lclname); } /* * Remote filespec */ char *rmtfile(s) char *s; { char *t,*u; /* * discard device spec and any subdirectories */ t = s; while( (u = strrchr(t,':')) != NULL || (u = strrchr(t,'/')) != NULL || (u = strrchr(t,'\\')) != NULL ) { t = ++u; } rtparse(t); sprintf(rmtname,"%s.%s", rtname(),rtext()); return(rmtname); } /* * Open a local file * * For reads, open file and return file handle * * For writes, process according to mode and return file handle * * If mode == 0 then just open a new file, * overwriting any existing file of the same name. * * If mode != 0 * then if fromtty and prompting * check for file existence, * if exists, ask for a new file name * response: * CR: overwrite the existing file. * filename: loop to check for file existence. * * else: * check for file existence, * if exists, create a sequential new file name * loop to check for file existence. * */ FILE *rtopen(fname,iotype,mode,ask) char *fname; char *iotype; int mode,ask; { char iname[50],lname[50],temp[50]; char *p; int i,j,digit; FILE *fp; if((p=setpath(fname)) == NULL) { ERRPRINT(); respath(); return(NULL); } strcpy(iname,(char *) lclfile(p)); if(strchr(iotype,'r') != NULL) { fp = fopen(iname,iotype); if(fp == NULL) respath(); return(fp); } digit = 0; strcpy(lname,iname); lcloop: if(mode) { fp = fopen(lname,"rn"); if(fp == NULL) { if(strcmp(iname,lname)) { RTPRINT("File name changed to %s\r\n", rmtfile(lname)); } fp = fopen(lname,iotype); if(fp == NULL) respath(); return(fp); } fclose(fp); if(ask) { RTPRINT("File %s exists\r\n", rmtfile(lname)); RTPRINT("Enter a new filename (CR to overwrite) -> "); if(RTRESPONSE(temp,49)) { respath(); return(-1); } if(*temp) { strcpy(lname,(char *) lclfile(temp)); goto lcloop; } fp = fopen(lname,iotype); if(fp == NULL) respath(); return(fp); } else { sprintf(temp,"%d",digit++); i = strlen(temp); rtparse(iname); p = rtname(); while((i+(j = strlen(p)))>6) { *(p+j-1) = '\0'; } strcat(p,temp); strcpy(lname,rtstring()); goto lcloop; } } fp = fopen(lname,iotype); if(fp == NULL) respath(); return(fp); } /* * rtclose * * close the open file, delete file if of zero length. */ VOID rtclose(fp) FILE *fp; { char fname[24]; int size; if(fp == NULL) return; if(fp->_flag & _IOWRT) { /* * File open for writing */ strcpy(fname,fp->io_name); fclose(fp); fp = fopen(fname,"rn"); if(fp != NULL) { size = fp->io_size; fclose(fp); if(size == 0) delete(fname); } } else { /* * File open for reading */ fclose(fp); } respath(); } /* * Check for wild card matches */ char *firstname(st) char *st; { if((iop = fwild(rtwfile(st,defdev), "r"))==NULL) return(NULL); return(nextname()); } /* * Get next matching file name */ char *nextname() { register char *p,*q; if(fnext(iop)!=NULL) { q = filename; p = iop->io_name; do { *q++ = tolower(*p); } while(*p++); return(filename); } else { iop = NULL; return(NULL); } } /* * Close open name file on aborts */ char *lastname() { if(iop!=NULL) { fclose(iop); iop = NULL; } return(NULL); } /* * File Scanner * * If not a wild card process, verifies existance of file * If a wild card process, returns first matching file * If file does not exist or no files match, returns NULL */ char *filnam(st,p,w) char *st; char *p; int w; { char xp[106]; if(w) { if(p == NULL) { /* * get first name, */ if((p = firstname(st)) == NULL) { /* * if no expansions */ sprintf(errstr,"No file(s) match %s", expand(xp,rtwfile(st,defdev))); } } else { /* * get next name */ p = nextname(); } } else { /* * no expansion */ p = rtfile(st,defdev); if((iop = fopen(p,"r")) == NULL) { sprintf(errstr,"No File %s", expand(xp,p)); p = NULL; } else { fclose(iop); } } return(p); } /* * Return file size */ int filsiz() { if(iop != NULL) { return(iop->io_size); } else { return(0); } } /* * Change local directory */ VOID cd(str) char *str; { lgcdsk(str,1); } /* * Logical Disk Directory */ int lgcdsk(str,flag) register char *str; int flag; { register char *s,*t; char sl[2]; char st[106]; char tm1[20]; char tm2[20]; int i; errstr[0] = '\0'; subfil[0] = '\0'; *st = '\0'; strcpy(sl,(strchr(str,'\\') != NULL) ? "\\" : "/"); /* * Check for device specification */ if((t = strchr(str,':')) == NULL) { t = str; } else { strncat(st,str,++t - str); } /* * Delimit any file specification */ if(*t && *t != '\\' && *t != '/' && *t != '.') strcat(st,sl); /* * Copy remainder of string */ strncat(st,t,sizeof(st)-2 - (t - str)); st[sizeof(st)-2] = '\0'; /* * Encapsulate with delimeter if this a directory spec * and there are subdirectorys */ if(flag && (strchr(st,'\\') != NULL || strchr(st,'/') != NULL)) { strcat(st,sl); } /* * Replace '/' with '\\' * Convert to lower case */ for(t=st; *t!='\0'; t++) { if(*t == '/' || *t == '\\') { slash = *t; *t = '\\'; } else { *t = tolower(*t); } } /* * cd . */ if(!strcmp(st,".")) { *st = '\0'; } /* * cd .. */ if(!strcmp(st,"..")) { if(subdlevl) { if(dismnt(--subdlevl)) return(1); if(subdlevl) { sprintf(defdev,"ld%1d:", subdlevl-1+subdbase); } else { strcpy(defdev,device); } return(0); } else { sprintf(errstr, /* */ ".. ignored, not in a subdirectory"); /* */ return(1); } } /* * Scan for Physical Device delimeter */ if((t = strchr(st,':')) != NULL) { /* * Test for a valid device */ switch(tstdev(st)) { case 1: sprintf(errstr, /* */ "Invalid device specification"); /* */ return(1); case 2: sprintf(errstr, /* */ "Non existant device"); /* */ return(1); default: break; } /* * Dismount all previously mounted logical units */ for(i=subdlevl; i>0; ) { if(dismnt(--i)) return(1); } subdlevl = 0; t++; } else { t = st; } /* * Extract each subdirectory */ while((t = strchr(s=t,'\\')) != NULL && strchr(s=++t,'\\') != NULL) { /* * Extract subdirectory */ for(s=tm1,i=0; *t!='\0' && *t!='\\' && i<19; i++) { *s++ = *t++; } *s = '\0'; /* * A null entry terminates scan */ if(tm1[0] == '\0') { return(0); } /* * An embedded device is not allowed */ if(strchr(tm1,':') != NULL) { sprintf(errstr, /* */ "'dev:' not allowed in subdirectory"); /* */ return(1); } if(subdlevl >= subdnest) { sprintf(errstr, /* */ "Subdirectory nesting may not exceed %d", subdnest); /* */ return(1); } /* * Try do dismount the current logical device (if any) */ if(dismnt(subdlevl)) return(1); /* * Try to mount the file as a subdirectory * of the current directory. The default file * type is "dsk". The complete file-spec * must be converted to rad50 for mlogcl. */ sprintf(tm2,"%s.dsk", defdev); r50blk(tm2,tm1,tm2); if(mlogcl(subdlevl+subdbase,tm2,0) != 0) { sprintf(errstr, /* */ "Subdirectory '%c%s' not found", slash,tm1); /* */ return(1); } /* * Verify this is a directory */ if(vlogcl(subdlevl+subdbase) != 0) { sprintf(errstr, /* */ "%c%s is not a directory", slash,tm1); /* */ return(1); } /* * Update directory tree */ sprintf(defdev,"ld%1d:", subdlevl+subdbase); strcpy(subnam[subdlevl],rtname()); strcpy(subext[subdlevl],rtext()); /* * Update subdirectory level */ subdlevl += 1; } /* * Assume the trailing non bracketed * string is a file name */ strncpy(subfil,s,16); subfil[15] = '\0'; return(0); } /* * Build the rad50 file block */ VOID r50blk(outstr,str1,str2) char *outstr,*str1,*str2; { char str[14]; /* * Note: This routine modifies the data in * rtstring[], the result of many RTFILE * operations. Save the string if required. */ /* * Generate a complete file spec * from the two filespec strings. */ rtparse(rtfile(str1,str2)); /* * Convert to rad50 */ sprintf(str,"%-3.3s%-6.6s%-3.3s", rtdev(),rtname(),rtext()); ascr50(12,str,outstr); } /* * Dismount logical device associated with subdlevl */ dismnt(i) int i; { if(dlogcl(i+subdbase) == 4) { sprintf(errstr, /* */ "File open on subdirectory %s.%s / [ld%1d:]", subnam[i], subext[i], i+subdbase); /* */ return(1); } return(0); } /* * Test the Device or File and Set the Default Directory */ int tstdev(st) register char *st; { char t[6]; register char *q; register int i; FILE *fp; for(i=0,q=t; *st && i<4; i++,q++,st++) *q = tolower(*st); *q = '\0'; q = strchr(t,':'); if(q==NULL || q==t || (q-t)>3) { return(1); } q = rtwfile(t,defdev); if((fp = fwild(q, "r"))==NULL) { return(2); } fclose(fp); sprintf(defdev,"%s:",rtdev()); sprintf(device,"%s:",rtdev()); return(0); } /* * Get default directory */ char *getdef() { return(defdev); } /* * Expand default path */ char *getpath(st) char *st; { char s[12]; int i; sprintf(st,"%s", device); for(i=0; i= subdnest) { sprintf(errstr, /* */ "Subdirectory nesting may not exceed %d", subdnest); /* */ aflag++; continue; } r50blk(dblk,fillst[delcnt],defdev); ldunit = subdlevl + subdbase; dlogcl(ldunit); if(!(i = mlogcl(ldunit,dblk,0))) { if((i = vlogcl(ldunit)) && !wspec) { sprintf(errstr, /* */ "%s is not a directory", xp); /* */ } dlogcl(ldunit); } if(i) continue; } /* * process file */ if(pflag) { /* * check */ RTPRINT("Delete %s %s ? ", (dflag ? "directory" : "file"),xp); if(RTRESPONSE(answer,19)) { /* * no more processing */ lastname(); p = NULL; aflag++; continue; } if( strchr(answer,'y') == NULL && strchr(answer,'Y') == NULL) { skpcnt++; continue; } } delcnt++; ttlcnt++; } while(p != NULL && delcnt<8 && wflag && !aflag); if(p != NULL) lastname(); for(i=0; iio_name; *q; q++) *q = tolower(*q); rtparse(fp->io_name); blks += fp->io_size; RTPRINT(" %-6.6s.%-3.3s %6.6u ", rtname(), rtext(), fp->io_size); if(cnt%3 == 2) RTPRINT("\r\n"); } if(cnt%3 != 0) RTPRINT("\r\n"); if(fp!=NULL) fclose(fp); if(fndbrk) { RTPRINT("---listing aborted---\r\n\r\n"); } else { q = rtwfile(st,defdev); RTPRINT( "\r\nDirectory [%s] / %d Files / %u Blocks\r\n\r\n", expand(xp,q),cnt,blks); } } /* * Make the directory by executing a * command file in a detached job */ int mkdir(st) char *st; { char *r,s[24],t[24]; char u[40]; int a,i; /* * Fill in defaults, strip allocation */ strcpy(s,rtfile(st,".dsk")); strcpy(t,rtfile(s,defdev)); if (a = rtalloc()) { r = strchr(s,'['); *r = '\0'; r = strchr(t,'['); *r = '\0'; } /* * Check for a file name */ if(*st == '\0') { sprintf(errstr, /* */ "Subdirectory name required"); /* */ } else /* * Check for a wildcard filespec */ if(chkwild(t,1)) { sprintf(errstr, /* */ "Wildcards not allowed"); /* */ } else /* * Require a minimum allocation */ if(a < 20) { sprintf(errstr, /* */ "Directory creation requires allocation --> name[n] (n >= 20)"); /* */ } else /* * Check that file does not exist */ if((iop = fopen(t,"r")) != NULL) { fclose(iop); sprintf(errstr, /* */ "Subdirectory file exists"); /* */ } else /* * Check nesting of subdirectories */ if(subdlevl >= subdnest) { sprintf(errstr, /* */ "Subdirectory nesting may not exceed %d", subdnest); /* */ } else { sprintf(u,"create %s/allocate:%d\r\n", s,a); i = bldcmd(u,0); sprintf(u,"mount ld%1d: %s\r\n", subdlevl+subdbase,s); i = bldcmd(u,i); sprintf(u,"r dup ld%1d:/z/y\r\n", subdlevl+subdbase); wrtcmd(bldcmd(u,i)); /* * Check that directory file does exist */ if((iop = fopen(t,"r")) != NULL) { fclose(iop); return(0); } sprintf(errstr, /* */ "Failed to Create Subdirectory %s", st); /* */ } return(1); } /* * Rename a file */ int rename(str1,str2,pflag,wflag) char *str1,*str2; int pflag,wflag; { char *p; char dblk[16]; char oldnam[8],oldext[4]; char newnam[8],newext[4]; char template[16]; char pstr[16]; char xp1[106],xp2[106]; char answer[20]; int wnam,wext; /* * Wildcards not allowed unless enabled */ if((chkwild(str1,wflag) < 0) || (chkwild(str2,wflag) < 0)) return(1); /* * Parse old name to check for wild cards */ rtparse(rtwfile(str1,defdev)); strcpy(oldnam,rtname()); strcpy(oldext,rtext()); /* * Parse new name to check for wild cards */ rtparse(rtwfile(rmtfile(str2),defdev)); strcpy(newnam,rtname()); strcpy(newext,rtext()); wnam = streq(newnam,"*"); wext = streq(newext,"*"); /* * Check wild card usage */ if( (iswild(oldnam) && !wnam) || (iswild(oldext) && !wext) || (iswild(newnam) && !wnam) || (iswild(newext) && !wext)) { sprintf(errstr,"Invalid use of wildcards"); return(1); } /* * Build a filespec template */ sprintf(template,"%s.%s", (wnam ? "" : newnam),(wext ? "" : newext)); /* * no names expanded yet */ p = NULL; do { /* * verify file exists / get matching file */ if((p = filnam(str1,p,wflag)) == NULL) continue; strcpy(pstr,p); expand(xp1,pstr); expand(xp2,rtfile(template,pstr)); /* * process file */ if(pflag) { /* * check */ RTPRINT("Rename %s\r\n", xp1); RTPRINT("To %s ? ", xp2); if(RTRESPONSE(answer,19)) { /* * no more processing */ lastname(); p = NULL; continue; } if( strchr(answer,'y') == NULL && strchr(answer,'Y') == NULL) { continue; } } /* * The initial and final file-specs must be * converted to rad50 for frename(). */ r50blk(&dblk[0],pstr,defdev); r50blk(&dblk[8],template,pstr); if(frename(dblk)) { if(wflag) { RTPRINT( "Protected File %s Exists\r\n", xp2); } else { sprintf(errstr, "Protected File %s Exists\r\n", xp2); return(1); } } else if(!pflag) { RTPRINT("File %s\r\n", xp1); RTPRINT("Renamed to %s\r\n", xp2); } } while(wflag && p != NULL); return(0); } /* * Set or Clear the protection flag on a file */ VOID setclrp(st,pflag,wflag) char *st; int pflag,wflag; { char *p,dblk[8]; /* * Wildcards not allowed unless enabled */ if(chkwild(st,wflag) < 0) return; /* * no names expanded yet */ p = NULL; do { /* * verify file exists / get matching file */ if((p = filnam(st,p,wflag)) == NULL) continue; /* * The complete file-spec must be * converted to rad50 for fprot(). */ r50blk(dblk,p,defdev); fprot(dblk,pflag); } while(wflag && p != NULL); } /* * Build the command buffer */ int bldcmd(st,i) char *st; int i; { char s[40]; int j; if(i+strlen(st) >= RTBUFSZ) { wrtcmd(i); i = 0; } /* * Create directory link section */ if(!i) { sprintf(s,"! TSXUTL Command File\r\n"); i = addcmd(s,i); sprintf(s,"set error error\r\n"); i = addcmd(s,i); sprintf(s,"assign %s dk:\r\n", device); i = addcmd(s,i); for(j=0; j