char *ckzv = "GEM file support, 5A(059) 16 Jul 92"; /* C K S F I O -- Kermit file system support for Atari ST systems */ /* Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET), Columbia University Center for Computing Activities. Many other contributors. First released January 1985. Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use this software as long as it is not sold for profit. This copyright notice must be retained. This software may not be included in commercial products without written permission of Columbia University. Extensively modified by: Bruce Moore (mooreb@iccgcc.decnet.ab.com). */ /* Include Files */ #include "ckcdeb.h" /* Directory structure header file */ #ifdef SDIRENT #define DIRENT #endif #ifdef GEMDOS #define TIMESTAMP /* Can do file dates */ #include /* System time stuff */ extern long timezone; extern int dstadjust; #endif /* Is `y' a leap year? */ #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) /* Number of leap years from 1970 to `y' (not including `y' itself). */ #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400) #include /* File status */ /* Functions (n is one of the predefined file numbers from ckcker.h): zopeni(n,name) -- Opens an existing file for input. zopeno(n,name,attr,fcb) -- Opens a new file for output. zclose(n) -- Closes a file. zchin(n,&c) -- Gets the next character from an input file. zsinl(n,&s,x) -- Read a line from file n, max len x, into address s. zsout(n,s) -- Write a null-terminated string to output file, buffered. zsoutl(n,s) -- Like zsout, but appends a line terminator. zsoutx(n,s,x) -- Write x characters to output file, unbuffered. zchout(n,c) -- Add a character to an output file, unbuffered. zchki(name) -- Check if named file exists and is readable, return size. zchko(name) -- Check if named file can be created. zchkspa(name,n) -- Check if n bytes available to create new file, name. znewn(name,s) -- Make a new unique file name based on the given name. zdelet(name) -- Delete the named file. zxpand(string) -- Expands the given wildcard string into a list of files. znext(string) -- Returns the next file from the list in "string". zxcmd(n,cmd) -- Execute the command in a lower fork on file number n. zclosf() -- Close input file associated with zxcmd()'s lower fork. zrtol(n1,n2) -- Convert remote filename into local form. zltor(n1,n2) -- Convert local filename into remote form. zchdir(dirnam) -- Change working directory. zhome() -- Return pointer to home directory name string. zkself() -- Kill self, log out own job. zsattr(struct zattr *) -- Return attributes for file which is being sent. zstime(f, struct zattr *, x) - Set file creation date from attribute packet. zrename(old, new) -- Rename a file. */ /* Kermit-specific includes */ /* Definitions here supersede those from system include files. ckcdeb.h is included above. */ #include "ckcker.h" /* Kermit definitions */ #include "ckucmd.h" /* For sys-dependent keyword tables */ #include "ckuver.h" char *ckzsys = HERALD; /* Definitions of some Unix system commands */ char *DELCMD = "rm "; /* For file deletion */ char *PWDCMD = "pwd "; /* For saying where I am */ char *DIRCMD = "ls -l "; /* For directory listing */ char *DIRCM2 = "ls -l "; /* For directory listing, no args */ char *TYPCMD = "cat "; /* For typing a file */ char *SPACMD = "df $cwd"; char *SPACM2 = "df "; /* For space in specified directory */ char *WHOCMD = "echo just we frogs "; /* For seeing who's logged in */ #ifdef DTILDE /* For tilde expansion */ _PROTOTYP( char * tilde_expand, (char *) ); #endif /* DTILDE */ /* More system-dependent includes, which depend on symbols defined */ /* in the Kermit-specific includes. Oh what a tangled web we weave... */ #include /* File access */ #include /* GEM o.s. bindings */ #ifndef S_ISREG #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif /* S_ISREG */ #ifndef S_ISDIR #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* S_ISDIR */ /* Define maximum length for a file name if not already defined */ #ifndef MAXNAMLEN #define MAXNAMLEN 12 #endif /* MAXNAMLEN */ /* Longest pathname */ #ifndef MAXPATH #define MAXPATH 255 #endif /* MAXPATH */ /* Maximum number of filenames for wildcard expansion */ #define MAXWLD 50 /* More internal function prototypes */ /* * The path structure is used to represent the name to match. * Each slash-separated segment of the name is kept in one * such structure, and they are linked together, to make * traversing the name easier. */ struct path { char npart[MAXNAMLEN+4]; /* name part of path segment */ struct path *fwd; /* forward ptr */ }; _PROTOTYP( int shxpand, (char *, char **, int ) ); _PROTOTYP( static int fgen, (char *, char **, int ) ); _PROTOTYP( static VOID traverse, (struct path *, char *, char *) ); _PROTOTYP( static VOID addresult, (char *) ); _PROTOTYP( static int match, (char *, char *) ); _PROTOTYP( char * xindex, (char *, char) ); _PROTOTYP( UID_T real_uid, (void) ); _PROTOTYP( struct path *splitpath, (char *p) ); /* Some systems define these symbols in include files, others don't... */ #ifndef R_OK #define R_OK AREAD /* For access */ #endif #ifndef W_OK #define W_OK AWRITE #endif #ifndef O_RDONLY #define O_RDONLY 000 #endif /* Declarations */ int maxnam = MAXNAMLEN; /* Available to the outside */ int maxpath = MAXPATH; FILE *fp[ZNFILS] = { /* File pointers */ NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /* (PWP) external def. of things used in buffered file input and output */ #ifdef DYNAMIC extern CHAR *zinbuffer, *zoutbuffer; #else extern CHAR zinbuffer[], zoutbuffer[]; #endif /* DYNAMIC */ extern CHAR *zinptr, *zoutptr; extern int zincnt, zoutcnt; extern int wildxpand; static long iflen = -1L; /* Input file length */ static int pid = 0; /* pid of child fork */ static int fcount; /* Number of files in wild group */ static char nambuf[MAXNAMLEN+4]; /* Buffer for a filename */ static char pipename[8*MAXNAMLEN]; /* Pipe name */ static char zmbuf[200]; /* For mail, remote print strings */ char *malloc(), *getenv(), *strcpy(); /* System functions */ extern char *strrchr(), *strcat(); /* and a couple more */ extern char *strchr(), *strncpy(); /* and yet more */ extern errno; /* System error code */ /* static */ /* Not static, must be global now. */ char *mtchs[MAXWLD], /* Matches found for filename */ **mtchptr; /* Pointer to current match */ /* Z K S E L F -- Kill Self: log out own job, if possible. */ /* Note, should get current pid, but if your system doesn't have */ /* getppid(), then just kill(0,9)... */ zkself() { /* For "bye", but no guarantee! */ exit(GOOD_EXIT); } /* Z O P E N I -- Open an existing file for input. */ int zopeni(n,name) int n; char *name; { debug(F111," zopeni",name,n); debug(F101," fp","", fp[n]); if (chkfn(n) != 0) return(0); zincnt = 0; /* Reset input buffer */ if (n == ZSYSFN) { /* Input from a system function? */ /*** Note, this function should not be called with ZSYSFN ***/ /*** Always call zxcmd() directly, and give it the real file number ***/ /*** you want to use. ***/ debug(F110,"zopeni called with ZSYSFN, failing!",name,0); *nambuf = '\0'; /* No filename. */ return(0); /* fail. */ #ifdef COMMENT return(zxcmd(n,name)); /* Try to fork the command */ #endif } if (n == ZSTDIO) { /* Standard input? */ if (isatty(0)) { fprintf(stderr,"Terminal input not allowed"); debug(F110,"zopeni: attempts input from unredirected stdin","",0); return(0); } fp[ZIFILE] = stdin; return(1); } fp[n] = fopen(name,"rb"); /* Real file, open it. */ debug(F111," zopeni", name, fp[n]); if (fp[n] == NULL) perror("zopeni"); return((fp[n] != NULL) ? 1 : 0); } /* Z O P E N O -- Open a new file for output. */ int zopeno(n,name,zz,fcb) /* zopeno */ int n; char *name; struct zattr *zz; struct filinfo *fcb; { char p[8]; /* (===OS2 change===) */ /* char *p; */ /* Local-use pointer */ /* As of Version 5A, the attribute structure and the file information */ /* structure are included in the arglist. */ debug(F111,"zopeno",name,n); if (fcb) { debug(F101,"zopeno fcb disp","",fcb->dsp); debug(F101,"zopeno fcb type","",fcb->typ); debug(F101,"zopeno fcb char","",fcb->cs); } else { debug(F100,"zopeno fcb is NULL","",0); } if (n != ZDFILE) debug(F101," fp[]=stdout", "", fp[n]); if (chkfn(n) != 0) return(0); if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */ fp[ZOFILE] = stdout; if (n != ZDFILE) debug(F101," fp[]=stdout", "", (int) fp[n]); zoutcnt = 0; zoutptr = zoutbuffer; return(1); } /* A real file. Open it in desired mode (create or append). */ strcpy(p,"w"); /* Assume write/create mode */ if (fcb) { /* If called with an FCB... */ if (fcb->dsp == XYFZ_A) /* Does it say Append? */ strcpy(p,"a"); /* Yes. */ } if (n == ZOFILE) strcat(p,"b"); /* Binary mode */ fp[n] = fopen(name,p); /* Open the file */ if (fp[n] == NULL) { perror("zopeno can't open"); } else { if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */ } zoutcnt = 0; /* (PWP) reset output buffer */ zoutptr = zoutbuffer; if (n != ZDFILE) debug(F101, " fp[n]", "", fp[n]); return((fp[n] != NULL) ? 1 : 0); } /* Z C L O S E -- Close the given file. */ /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */ int zclose(n) int n; { int x, x2; if (chkfn(n) < 1) return(0); /* Check range of n */ if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */ x2 = zoutdump(); else x2 = 0; x = 0; /* Initialize return code */ if (fp[ZSYSFN]) { /* If file is really pipe */ x = zclosf(n); /* do it specially */ } else { if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]); fp[n] = NULL; } iflen = -1L; /* Invalidate file length */ if (x == EOF) /* if we got a close error */ return (-1); else if (x2 < 0) /* or an error flushing the last buffer */ return (-1); /* then return an error */ else return (1); } /* Z C H I N -- Get a character from the input file. */ /* Returns -1 if EOF, 0 otherwise with character returned in argument */ int zchin(n,c) int n; int *c; { int a, x; /* (PWP) Just in case this gets called when it shouldn't. */ if (n == ZIFILE) { x = zminchar(); *c = x; return(x); } /* if (chkfn(n) < 1) return(-1); */ a = getc(fp[n]); if (a == EOF) return(-1); *c = (CHAR) a & 0377; return(0); } /* Z S I N L -- Read a line from a file */ /* Writes the line into the address provided by the caller. n is the Kermit "channel number". Writing terminates when newline is encountered, newline is not copied. Writing also terminates upon EOF or if length x is exhausted. Returns 0 on success, -1 on EOF or error. */ int zsinl(n,s,x) int n, x; char *s; { int a, z = 0; if (chkfn(n) < 1) { /* Make sure file is open */ return(-1); } a = -1; while (x--) { #ifndef NLCHAR int old; old = a; /* Previous character */ #endif if (zchin(n,&a) < 0) { /* Read a character from the file */ z = -1; break; } #ifdef NLCHAR if (a == (char) NLCHAR) break; /* Single-character line terminator */ #else if (a == '\r') continue; /* CRLF line terminator */ if (old == '\r') { if (a == '\n') break; else *s++ = '\r'; } #endif /* NLCHAR */ *s = a; s++; } *s = '\0'; return(z); } /* * (PWP) (re)fill the buffered input buffer with data. All file input * should go through this routine, usually by calling the zminchar() * macro (in ckcker.h). */ /* * Suggestion: if fread() returns 0, call ferror to find out what the * problem was. If it was not EOF, then return -2 instead of -1. * Upper layers (getpkt function in ckcfns.c) should set cxseen flag * if it gets -2 return from zminchar macro. */ int zinfill() { int x; errno = 0; zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]); #ifdef COMMENT debug(F101,"zinfill fp","",fp[ZIFILE]); debug(F101,"zinfill zincnt","",zincnt); #endif if (zincnt == 0) { #ifndef UTEK #ifdef ferror x = ferror(fp[ZIFILE]); debug(F101,"zinfill errno","",errno); debug(F101,"zinfill ferror","",x); if (x) return(-2); #endif /* ferror */ #else x = feof(fp[ZIFILE]); debug(F101,"zinfill errno","",errno); debug(F101,"zinfill feof","",x); if (!x && ferror(fp[ZIFILE])) return(-2); #endif /* UTEK */ return(-1); } zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */ zincnt--; /* one less char in buffer */ return((int)(*zinptr++) & 0377); /* because we return the first */ } /* Z S O U T -- Write a string out to the given file, buffered. */ int zsout(n,s) int n; char *s; { if (chkfn(n) < 1) return(-1); /* Keep this here, prevents memory faults */ #ifdef COMMENT while (*s) { /* (unbuffered for debugging) */ write(fileno(fp[n]),s,1); ++s; } #endif #ifdef COMMENT return(fputs(s,fp[n]) == EOF ? -1 : 0); #else #ifdef COMMENT if (n == ZSFILE) return(write(fileno(fp[n]),s,strlen(s))); else #endif return(fputs(s,fp[n]) == EOF ? -1 : 0); #endif } /* Z S O U T L -- Write string to file, with line terminator, buffered */ int zsoutl(n,s) int n; char *s; { /* if (chkfn(n) < 1) return(-1); */ if (fputs(s,fp[n]) == EOF) return(-1); if (fputs("\n",fp[n]) == EOF) return(-1); return(0); } /* Z S O U T X -- Write x characters to file, unbuffered. */ int zsoutx(n,s,x) int n, x; char *s; { #ifdef COMMENT if (chkfn(n) < 1) return(-1); return(write(fp[n]->_file,s,x)); #endif return(write(fileno(fp[n]),s,x) == x ? x : -1); } /* Z C H O U T -- Add a character to the given file. */ /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */ int #ifdef CK_ANSIC zchout(register int n, char c) #else zchout(n,c) register int n; char c; #endif /* CK_ANSIC */ /* zchout() */ { /* if (chkfn(n) < 1) return(-1); */ if (n == ZSFILE) { /* Use unbuffered for session log */ #ifdef COMMENT return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1); #else if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */ return(ferror(fp[n])?-1:0); /* Check to make sure */ else /* Otherwise... */ return(0); /* There was no error. */ #endif } else { /* Buffered for everything else */ if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */ return(ferror(fp[n])?-1:0); /* Check to make sure */ else /* Otherwise... */ return(0); /* There was no error. */ } } /* (PWP) buffered character output routine to speed up file IO */ int zoutdump() { int x; zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */ debug(F101,"zoutdump chars","",zoutcnt); if (zoutcnt == 0) { /* Nothing to output */ return(0); } else if (zoutcnt < 0) { /* Unexpected negative argument */ zoutcnt = 0; /* Reset output buffer count */ return(-1); /* and fail. */ } /* Frank Prindle suggested that replacing this fwrite() by an fflush() */ /* followed by a write() would improve the efficiency, especially when */ /* writing to stdout. Subsequent tests showed a 5-fold improvement! */ /* if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) { */ fflush(fp[ZOFILE]); if ((x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) == zoutcnt) { debug(F101,"zoutdump write ok","",zoutcnt); zoutcnt = 0; /* Reset output buffer count */ return(0); /* write() worked OK */ } else { debug(F101,"zoutdump write error","",errno); debug(F101,"zoutdump write returns","",x); zoutcnt = 0; /* Reset output buffer count */ return(-1); /* write() failed */ } } /* C H K F N -- Internal function to verify file number is ok */ /* Returns: -1: File number n is out of range 0: n is in range, but file is not open 1: n in range and file is open */ int chkfn(n) int n; { switch (n) { case ZCTERM: case ZSTDIO: case ZIFILE: case ZOFILE: case ZDFILE: case ZTFILE: case ZPFILE: case ZSFILE: case ZSYSFN: case ZRFILE: case ZWFILE: break; default: debug(F101,"chkfn: file number out of range","",n); fprintf(stderr,"?File number out of range - %d\n",n); return(-1); } return( (fp[n] == NULL) ? 0 : 1 ); } /* Z C H K I -- Check if input file exists and is readable */ /* Returns: >= 0 if the file can be read (returns the size). -1 if file doesn't exist or can't be accessed, -2 if file exists but is not readable (e.g. a directory file). -3 if file exists but protected against read access. */ /* For Berkeley Unix, a file must be of type "regular" to be readable. Directory files, special files, and symbolic links are not readable. */ long zchki(name) char *name; { struct stat buf; int x; x = stat(name,&buf); if (x < 0) { debug(F111,"zchki stat fails",name,errno); return(-1); } if (!S_ISREG (buf.st_mode)) { /* Must be regular file */ debug(F111,"zchki skipping:",name,x); return(-2); } debug(F111,"zchki stat ok:",name,x); if ((x = access(name,R_OK)) < 0) { /* Is the file accessible? */ debug(F111," access failed:",name,x); /* No */ return(-3); } else { iflen = buf.st_size; /* Yes, remember size */ strncpy(nambuf,name,MAXNAMLEN); /* and name globally. */ debug(F111," access ok:",name,(int) iflen); return( (iflen > -1L) ? iflen : 0L ); } } /* Z C H K O -- Check if output file can be created */ /* Returns -1 if write permission for the file would be denied, 0 otherwise. */ int zchko(name) char *name; { int i, x; char *s; if (!name) return(-1); /* Watch out for null pointer. */ x = strlen(name); /* Get length of filename */ debug(F101," length","",x); s = malloc(x+3); /* Must copy because we can't */ if (!s) { /* write into our argument. */ fprintf(stderr,"Malloc error 46\n"); return(-1); } strcpy(s,name); for (i = x; i > 0; i--) /* Strip filename from right. */ if (s[i-1] == '\\') break; debug(F101," i","",i); #ifdef COMMENT /* X/OPEN XPG3-compliant systems fail if argument ends with "/"... */ if (i == 0) /* If no path, use current directory */ strcpy(s,".\\"); else /* Otherwise, use given one. */ s[i] = '\0'; #else /* So now we use "path/." if path given, or "." if no path given. */ s[i++] = '.'; /* Append "." to path. */ s[i] = '\0'; #endif /* COMMENT */ x = access(s,W_OK); /* Check access of path. */ if (x < 0) debug(F111,"zchko access failed:",s,errno); else debug(F111,"zchko access ok:",s,x); free(s); /* Free temporary storage */ return((x < 0) ? -1 : 0); /* and return. */ } /* Z D E L E T -- Delete the named file. */ int zdelet(name) char *name; { return(unlink(name)); } /* Z R T O L -- Convert remote filename into local form */ /* For UNIX, this means changing uppercase letters to lowercase. */ /* For GEM, this means 8.3 filenames and other DOS baggage too */ VOID zrtol(name,name2) char *name, *name2; { zltor(name, name2); for ( ; *name != '\0'; name++) { *name2++ = isupper(*name) ? tolower(*name) : *name; } *name2 = '\0'; debug(F110,"zrtol:",name2,0); } /* Z S T R I P -- Strip device & directory name from file specification */ /* Strip pathname from filename "name", return pointer to result in name2 */ static char work[257]; /* buffer for use by zstrip and zltor */ VOID zstrip(name,name2) char *name, **name2; { char *cp, *pp; debug(F110,"zstrip before",name,0); pp = work; #ifdef DTILDE if (*name == '~') name++; #endif for (cp = name; *cp != '\0'; cp++) { if (*cp == '\\') pp = work; else *pp++ = *cp; } *pp = '\0'; /* Terminate the string */ *name2 = work; debug(F110,"zstrip after",*name2,0); } /* Z L T O R -- Local TO Remote */ zltor(name,name2) char *name, *name2; { char *cp, *pp; int dc = 0; debug(F110,"zltor",name,0); pp = work; for (cp = name; *cp != '\0'; cp++) { /* strip path name */ if (*cp == '\\') { dc = 0; pp = work; } else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */ else if (*cp == '~') *pp++ = 'X'; /* Change tilde to 'X' */ else if (*cp == '#') *pp++ = 'X'; /* Change number sign to 'X' */ else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */ else if (dc == 0 && (cp - name) >= 8) *pp++ = '.'; /* base too long */ else *pp++ = *cp; } *pp = '\0'; /* Tie it off. */ cp = name2; /* If nothing before dot, */ if (*work == '.') *cp++ = 'X'; /* insert 'X' */ strcpy(cp,work); debug(F110," name2",name2,0); } /* Z C H D I R -- Change directory */ /* Call with: dirnam = pointer to name of directory to change to, which may be "" or NULL to indicate user's home directory. Returns: 0 on failure 1 on success */ int zchdir(dirnam) char *dirnam; { char *hd, *sp, *p; debug(F110,"zchdir",dirnam,0); if (dirnam == NULL || dirnam == "" || *dirnam == '\0') /* If arg is null */ dirnam = getenv("HOME"); /* use user's home directory. */ if (dirnam == NULL) return(0); sp = dirnam; debug(F110,"zchdir 2",dirnam,0); #ifdef DTILDE hd = tilde_expand(dirnam); /* Attempt to expand tilde */ if (*hd == '\0') hd = dirnam; /* in directory name. */ #else hd = dirnam; #endif /* DTILDE */ debug(F110,"zchdir 3",hd,0); if (toschdir(hd) == 0) return(1); /* Try to cd */ /* (===OS2===) */ p = sp; /* Failed, lowercase it. */ while (*p) { if (isupper(*p)) *p = tolower(*p); p++; } debug(F110,"zchdir 4",hd,0); #ifdef DTILDE hd = tilde_expand(sp); /* Try again to expand tilde */ if (*hd == '\0') hd = sp; #else hd = sp; /* Point to result */ #endif debug(F110,"zchdir 5",hd,0); return((toschdir(hd) == 0) ? 1 : 0); } /* T O S C H D I R -- Change directory under TOS */ /* * Return 0 if it worked, 1 otherwise */ int toschdir(dirnam) char *dirnam; { char *path; int drive; if (path = strchr(dirnam, ':')) { drive = toupper(*--path) - 'A'; if (drive < 0 || drive > 25) return(1); Dsetdrv(drive); path += 2; } else path = dirnam; return((int) Dsetpath(path)); } /* Z H O M E -- Return pointer to user's home directory */ char * zhome() { char *home = NULL; home = getenv("HOME"); return(home ? home : "."); /* (===OS2===) */ } /* Z G T D I R -- Return pointer to user's current directory */ #ifdef MAXPATHLEN #define CWDBL MAXPATHLEN #else #define CWDBL 100 #endif static char cwdbuf[CWDBL+1]; char * zgtdir() { int drive; char *p; int c; p = cwdbuf; drive = Dgetdrv(); *p++ = (drive + 'a'); /* Drive letter */ *p++ = ':'; Dgetpath(p, 0); /* Rest of path */ for (p = cwdbuf; c = *p; p++) { if (isupper(c)) *p = _tolower(c); } if (strlen(cwdbuf) == 2) strcat(cwdbuf, "\\"); return(cwdbuf); } /* Z X C M D -- Run a system command so its output can be read like a file */ int zxcmd(filnum,comand) int filnum; char *comand; { char *name; char *cmdbuf; extern char *tempnam(); if (! pipename[0]) /* If no pipe has been used yet */ strcpy(pipename, tempnam(NULL, "ck")); /* Get a name for the pipe */ cmdbuf = malloc(strlen(comand) + 2 + strlen(pipename) + 1); strcpy(cmdbuf, comand); strcat(cmdbuf, " >"); strcat(cmdbuf, pipename); tossystem(cmdbuf); free(cmdbuf); fp[ZIFILE] = fopen(pipename,"r"); /* open a stream for it */ fp[ZSYSFN] = fp[ZIFILE]; /* Remember. */ debug(F101,"zxcmd fp","", fp[ZSYSFN]); return(1); } /* Z C L O S F - wait for the child fork to terminate and close the pipe. */ int zclosf(filnum) int filnum; { debug(F101,"zclosf filnum","",filnum); debug(F101,"zclosf fp[filnum]","",(int) fp[filnum]); debug(F101,"zclosf fp[ZSYSFN]","",(int) fp[ZSYSFN]); fclose(fp[filnum]); zdelet(pipename); fp[filnum] = fp[ZSYSFN] = NULL; return(1); } /* Z X P A N D -- Expand a wildcard string into an array of strings */ /* Returns the number of files that match fn1, with data structures set up so that first file (if any) will be returned by the next znext() call. Depends on external variable wildxpand: 0 means we expand wildcards internally, nonzero means we call the shell to do it. */ int zxpand(fn) char *fn; { char *p; #ifdef DTILDE /* Built with tilde-expansion? */ char *tnam; #endif /* DTILDE */ debug(F111,"zxpand entry",fn,wildxpand); #ifdef DTILDE /* Built with tilde-expansion? */ if (*fn == '~') { /* Starts with tilde? */ tnam = tilde_expand(fn); /* Try to expand it. */ if (tnam) fn = tnam; } debug(F110,"zxpand after tilde_x",fn,0); #endif /* DTILDE */ if (wildxpand) /* Who is expanding wildcards? */ fcount = shxpand(fn,mtchs,MAXWLD); /* Shell */ else fcount = fgen(fn,mtchs,MAXWLD); /* Kermit */ if (fcount > 0) { mtchptr = mtchs; /* Save pointer for next. */ } if (fcount > 0) { debug(F111,"zxpand ok",mtchs[0],fcount); return(fcount); } debug(F111,"zxpand fgen1",fn,fcount); /* Didn't get one, or got too many */ p = malloc(strlen(fn) + 10); /* Make space */ if (!p) return(0); zrtol(fn,p); /* Try again, maybe lowercase */ if (wildxpand) fcount = shxpand(p,mtchs,MAXWLD); /* Shell */ else fcount = fgen(p,mtchs,MAXWLD); /* Kermit */ if (fcount > 0) { /* Got one? */ mtchptr = mtchs; /* Save pointer for next. */ debug(F111,"zxpand fgen2 ok",mtchs[0],fcount); } else debug(F111,"zxpand 2 not ok",p,fcount); free(p); return(fcount); } /* Z N E X T -- Get name of next file from list created by zxpand(). */ /* Returns >0 if there's another file, with its name copied into the arg string, or 0 if no more files in list. */ int znext(fn) char *fn; { if (fcount-- > 0) { strcpy(fn,*mtchptr); free(*mtchptr++); } else *fn = '\0'; debug(F111,"znext",fn,fcount+1); return(fcount+1); } /* Z C H K S P A -- Check if there is enough space to store the file */ /* Call with file specification f, size n in bytes. Returns -1 on error, 0 if not enough space, 1 if enough space. */ struct disk_info { unsigned long di_free; /* Free allocation units */ unsigned long di_many; /* Allocation units per disk */ unsigned long di_ssize; /* Sector size (in bytes) */ unsigned long di_spau; /* Sectors per allocation unit */ }; int zchkspa(f,n) char *f; long n; { int drive; struct disk_info disk; long bytesleft; drive = Dgetdrv(); Dfree(&disk, 0); /* Check current drive */ bytesleft = disk.di_free * disk.di_spau * disk.di_ssize; if (n > bytesleft) return(0); return(1); /* Always say OK. */ } /* Z N E W N -- Make a new name for the given file */ /* Given the name, fn, of a file that already exists, this function builds a new name of the form "" where is the (possibly truncated) argument name (fn) and is a version number, one higher than any existing version number for that file, up to 99. If the constructed name is too long for the system's maximum, enough characters are truncated from the end of to allow the version number to fit. If no free version numbers exist between 0 and 99, a version number of "xx" is used. Returns a pointer to the new name in argument s. */ VOID znewn(fn,s) char *fn, **s; { #define ZNEWNBL 13 /* Name buffer length */ #define ZNEWNMD 2 /* Max digits for version number */ #define ZNEWEXT 3 /* Max chars in extension */ #define ZNEWPRE 8 /* Max chars in prefix */ #define ZNEWTRC (ZNEWPRE-ZNEWNMD) /* Max chars in truncated prefix */ static char buf[ZNEWNBL+1]; char prefix[ZNEWPRE+1]; char extension[ZNEWEXT+1]; char *bp, *xp; int len, n, t, d; bp = strchr(fn, '.'); /* First save the extension */ if (bp) { strncpy(extension, bp+1, ZNEWEXT); extension[ZNEWEXT] = '\0'; } else extension[0] = '\0'; strncpy(prefix, fn, ZNEWPRE); /* Now save the prefix */ prefix[ZNEWPRE] = '\0'; bp = strchr(prefix, '.'); /* Seems wasteful to do this again */ if (bp) *bp = '\0'; /* Get rid of period and extension */ len = strlen(prefix); /* Pad to six bytes with zeroes */ for (; len < ZNEWTRC; len++) prefix[len] = '0'; prefix[ZNEWTRC] = '\0'; strcpy(buf, prefix); /* Create wildcard string */ strcat(buf, "*."); strcat(buf, extension); n = zxpand(buf); /* Expand the resulting wild name */ d = -1; /* Initialize lowest unused */ while (n-- > 0) { /* Find any existing name files */ xp = *mtchptr++; /* Point at matching name */ if ( (strchr(xp, '.') - xp) > ZNEWTRC && isdigit(xp[ZNEWTRC]) ) { /* Look for prefix end */ t = atoi(&xp[ZNEWTRC]); /* Get it */ if (t > d) d = t; /* Save d = highest version number */ } } d++; /* Lowest unused version number */ strcpy(buf, prefix); /* First copy truncated prefix */ for (len = ZNEWPRE-1; len >= ZNEWTRC; len--) { buf[len] = '0' + d % 10; d /= 10; } if (d) { /* If it didn't fit use 'X' */ for (len = ZNEWPRE-1; len >= ZNEWTRC; len--) buf[len] = 'X'; } buf[ZNEWPRE] = '.'; /* Don't forget the period */ buf[ZNEWPRE+1] = '\0'; strcat(buf, extension); /* Tack on extension */ *s = buf; /* Tell caller buffer location */ return; } /* Z R E N A M E -- Rename a file */ /* Note, link() and unlink() are used because rename() is not available */ /* in some versions of UNIX. */ /* Call with old and new names */ /* Returns 0 on success, -1 on failure. */ int zrename(old,new) char *old, *new; { return(Frename(0, old, new) != 0 ? -1 : 0); } /* Z S A T T R */ /* Fills in a Kermit file attribute structure for the file which is to be sent. Returns 0 on success with the structure filled in, or -1 on failure. If any string member is null, then it should be ignored. If any numeric member is -1, then it should be ignored. */ int zsattr(xx) struct zattr *xx; { long k; char *zfcdat(); k = iflen % 1024L; /* File length in K */ if (k != 0L) k = 1L; xx->lengthk = (iflen / 1024L) + k; xx->type.len = 0; /* File type can't be filled in here */ xx->type.val = ""; if (*nambuf) { xx->date.val = zfcdat(nambuf); /* File creation date */ xx->date.len = strlen(xx->date.val); } else { xx->date.len = 0; xx->date.val = ""; } xx->creator.len = 0; /* File creator */ xx->creator.val = ""; xx->account.len = 0; /* File account */ xx->account.val = ""; xx->area.len = 0; /* File area */ xx->area.val = ""; xx->passwd.len = 0; /* Area password */ xx->passwd.val = ""; xx->blksize = -1L; /* File blocksize */ xx->access.len = 0; /* File access */ xx->access.val = ""; xx->encoding.len = 0; /* Transfer syntax */ xx->encoding.val = 0; xx->disp.len = 0; /* Disposition upon arrival */ xx->disp.val = ""; xx->lprotect.len = 0; /* Local protection */ xx->lprotect.val = ""; xx->gprotect.len = 0; /* Generic protection */ xx->gprotect.val = ""; xx->systemid.len = 2; /* System ID */ xx->systemid.val = "U1"; xx->recfm.len = 0; /* Record format */ xx->recfm.val = ""; xx->sysparam.len = 0; /* System-dependent parameters */ xx->sysparam.val = ""; xx->length = iflen; /* Length */ return(0); } /* Z F C D A T -- Get file creation date */ /* Call with pointer to filename. On success, returns pointer to creation date in yyyymmdd hh:mm:ss format. On failure, returns pointer to null string. */ static char datbuf[40]; char * zfcdat(name) char *name; { #ifdef TIMESTAMP struct stat buffer; struct tm *time_stamp, *localtime(); int yy, ss; datbuf[0] = '\0'; if(stat(name,&buffer) != 0) { debug(F110,"zfcdat stat failed",name,0); return(""); } time_stamp = localtime(&(buffer.st_mtime)); yy = time_stamp->tm_year; if (yy < 100) /* In case it returns 2-digit year? */ yy += 1900; if (yy < 0 || yy > 9999) { /* Make sure year is ok */ debug(F110,"zfcdat date failed",name,0); return(""); } if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11) return(""); if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31) return(""); if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23) return(""); if (time_stamp->tm_min < 0 || time_stamp->tm_min > 59) return(""); ss = time_stamp->tm_sec; /* Seconds */ if (ss < 0 || ss > 59) /* Some systems give a BIG number */ ss = 0; sprintf(datbuf, "%04d%02d%02d %02d:%02d:%02d", yy, time_stamp->tm_mon + 1, time_stamp->tm_mday, time_stamp->tm_hour, time_stamp->tm_min , ss ); yy = strlen(datbuf); debug(F111,"zfcdat",datbuf,yy); if (yy > 17) datbuf[17] = '\0'; return(datbuf); #else return(""); #endif /* TIMESTAMP */ } /* Z S T I M E -- Set creation date for incoming file */ /* Call with: f = pointer to name of existing file. yy = pointer to a Kermit file attribute structure in which yy->date.val is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00. x = is a function code: 0 means to set the file's creation date as given. 1 means compare the given date with the file creation date. Returns: -1 on any kind of error. 0 if x is 0 and the file date was set successfully. 0 if x is 1 and date from attribute structure <= file creation date. 1 if x is 1 and date from attribute structure > file creation date. */ int zstime(f,yy,x) char *f; struct zattr *yy; int x; { int r = -1; /* return code */ /* It is ifdef'd TIMESTAMP because it may not work on V7. bk@kullmar.se. */ #ifdef TIMESTAMP /* To do: adapt code from OS-9 Kermit's ck9fio.c zstime function, which is more flexible, allowing [yy]yymmdd[ hh:mm[:ss]]. */ extern int ftime(); long tm, days; int i, n, isleapyear, stat(), utime(); /* J F M A M J J A S O N D */ /* 31 28 31 30 31 30 31 31 30 31 30 31 */ static int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 }; char s[5], *getenv(); extern struct tm *localtime(); struct stat sb; struct utimbuf { time_t atime; /* New access time */ time_t mtime; /* New modification time */ } tp; debug(F110,"zstime",f,0); if ((yy->date.len == 0) || (yy->date.len != 17) || (yy->date.val[8] != ' ') || (yy->date.val[11] != ':') || (yy->date.val[14] != ':') ) { debug(F111,"Bad creation date ",yy->date.val,yy->date.len); return(-1); } debug(F111,"zstime date check 1",yy->date.val,yy->date.len); for(i = 0; i < 8; i++) { if (!isdigit(yy->date.val[i])) { debug(F111,"Bad creation date ",yy->date.val,yy->date.len); return(-1); } } debug(F111,"zstime date check 2",yy->date.val,yy->date.len); i++; for (; i < 16; i += 3) { if ((!isdigit(yy->date.val[i])) || (!isdigit(yy->date.val[i + 1]))) { debug(F111,"Bad creation date ",yy->date.val,yy->date.len); return(-1); } } debug(F111,"zstime date check 3",yy->date.val,yy->date.len); s[4] = '\0'; for (i = 0; i < 4; i++) /* Fix the year */ s[i] = yy->date.val[i]; debug(F110,"zstime year",s,0); n = atoi(s); debug(F111,"zstime year",s,n); /* Previous year's leap days. This won't work after year 2100, */ /* I don't care about that! */ isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0); days = (long) (n - 1970) * 365; days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400; s[2] = '\0'; for (i = 4 ; i < 16; i += 2) { s[0] = yy->date.val[i]; s[1] = yy->date.val[i + 1]; n = atoi(s); debug(F110,"zstime entering switch",s,0); switch (i) { case 4: /* MM: month */ if ((n < 1 ) || ( n > 12)) { debug(F111,"Bad creation date ",yy->date.val,yy->date.len); return(-1); } days += monthdays [n]; if (isleapyear && n > 2) ++days; continue; case 6: /* DD: day */ if ((n < 1 ) || ( n > 31)) { debug(F111,"Bad creation date ",yy->date.val,yy->date.len); return(-1); } tm = (days + n - 1) * 24L * 60L * 60L; i++; /* Skip the space */ continue; case 9: /* hh: hour */ if ((n < 0 ) || ( n > 23)) { debug(F111,"Bad creation date ",yy->date.val,yy->date.len); return(-1); } tm += n * 60L * 60L; i++; /* Skip the colon */ continue; case 12: /* mm: minute */ if ((n < 0 ) || ( n > 59)) { debug(F111,"Bad creation date ",yy->date.val,yy->date.len); return(-1); } tm += timezone - dstadjust; /* Correct for time zone */ tm += n * 60L; i++; /* Skip the colon */ continue; case 15: /* ss: second */ if ((n < 0 ) || ( n > 59)) { debug(F111,"Bad creation date ",yy->date.val,yy->date.len); return(-1); } tm += n; } } debug(F111,"Attribute creation date ok ",yy->date.val,yy->date.len); if (stat(f,&sb)) { /* Get the time for the file */ debug(F110,"Can't stat file:",f,0); return(-1); } tp.mtime = tm; /* Set modif. time to creation date */ tp.atime = sb.st_atime; /* Don't change the access time */ switch (x) { /* Execute desired function */ case 0: /* Set the creation date of the file */ if (utime(f,&tp)) { /* Fix modification time */ debug(F110,"Can't set modification time for file: ",f,0); r = -1; } else { debug(F110,"Modification time is set for file: ",f,0); r = 0; } break; case 1: /* Compare the dates */ debug(F111,"zstime compare",f,sb.st_atime); debug(F111,"zstime compare","packet",tm); if (sb.st_atime < tm) r = 0; else r = 1; break; default: /* Error */ r = -1; } #endif /* TIMESTAMP */ return(r); } /* Find initialization file. */ int zkermini(line, flag, def) char *line; int flag; char *def; { #ifdef NOICP return(0); #else extern char *homdir, *lp; homdir = zhome(); lp = line; strcpy(lp, def); if (flag) /* If init file name from cmd line */ ; /* use it */ else if (zchki(lp) >= 0) /* Then try current directory */ ; /* If it exists, use it */ else if (homdir) { /* Then try home directory (if any) */ strcpy(lp, homdir); strcat(lp, "\\"); strcat(lp, def); if (zchki(lp) >= 0) /* If it exists, use it */ return(0); } else { /* Then try root directory */ strcpy(lp, "\\"); strcat(lp, def); } return(0); #endif /* NOICP */ } #ifndef NOFRILLS int zmail(p,f) char *p; char *f; { /* Send file f as mail to address p */ return(0); } #endif /* NOFRILLS */ #ifndef NOFRILLS int zprint(p,f) char *p; char *f; { /* Print file f with options p */ sprintf(zmbuf,"pr %s >prn:", f); /* Construct print command */ zsyscmd(zmbuf); return(0); } #endif /* NOFRILLS */ /* Wildcard expansion functions. C-Kermit used to do this itself (see #else part...). New code (version 5A, 1990-91) just asks UNIX to do it. This lets users use the wildcard expansion features of their favorite shell. Operation is slower because of the forking & piping, but flexibility is greater and program is smaller. */ static char scratch[MAXPATH+4]; /* Used by both methods */ static int oldmtchs = 0; /* Let shell (ls) expand them. */ #ifdef COMMENT static char *lscmd = "/bin/ls -d"; /* Command to use. */ #else static char *lscmd = "echo"; /* Command to use. */ #endif /* COMMENT */ int shxpand(pat,namlst,len) char *pat, *namlst[]; int len; { char *fgbuf = NULL; /* Buffer for forming ls command */ char *p, *q; /* Workers */ int i, x, retcode; char c; /* ... */ x = strlen(pat) + strlen(lscmd) + 3; /* Length of ls command */ for (i = 0; i < oldmtchs; i++) /* Free previous file list */ free(namlst[i]); fgbuf = malloc(x); /* Get buffer for command */ if (!fgbuf) return(-1); /* Fail if cannot */ sprintf(fgbuf,"%s %s",lscmd,pat); /* Form the command */ zxcmd(ZIFILE,fgbuf); /* Start the command */ i = 0; /* File counter */ p = scratch; /* Point to scratch area */ retcode = -1; /* Assume failure */ while ((c = zminchar()) != -1) { /* Read characters from command */ if (c == ' ' || c == '\n') { /* Got newline or space? */ *p = '\0'; /* Yes, terminate string */ p = scratch; /* Point back to beginning */ if (zchki(p) == -1) /* Does file exist? */ continue; /* No, continue */ x = strlen(p); /* Yes, get length of name */ q = malloc(x+1); /* Allocate space for it */ if (!q) goto shxfin; /* Fail if space can't be obtained */ strcpy(q,scratch); /* Copy name to space */ namlst[i++] = q; /* Copy pointer to name into array */ if (i > len) goto shxfin; /* Fail if too many */ } else { /* Regular character */ *p++ = c; /* Copy it into scratch area */ } } retcode = i; /* Return number of matching files */ shxfin: /* Common exit point */ free(fgbuf); /* Free command buffer */ zclosf(ZIFILE); /* Delete the command fork. */ oldmtchs = i; /* Remember how many files */ return(retcode); } /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */ /* Define the size of the string space for filename expansion. */ #ifndef DYNAMIC #ifdef PROVX1 #define SSPACE 500 #else #ifdef BSD29 #define SSPACE 500 #else #ifdef pdp11 #define SSPACE 500 #else #ifdef aegis #define SSPACE 10000 /* size of string-generating buffer */ static char bslash; /* backslash character if active */ #else /* Default static buffer size */ #define SSPACE 2000 /* size of string-generating buffer */ #endif /* aegis */ #endif /* pdp11 */ #endif /* BSD29 */ #endif /* PROVX1 */ static char sspace[SSPACE]; /* buffer for generating filenames */ #else /* DYNAMIC */ #define SSPACE 10000 static char *sspace = (char *)0; #endif /* DYNAMIC */ static int ssplen = SSPACE; /* length of string space buffer */ static char *freeptr,**resptr; /* copies of caller's arguments */ static int remlen; /* remaining length in caller's array*/ static int numfnd; /* number of matches found */ /* * splitpath: * takes a string and splits the slash-separated portions into * a list of path structures. Returns the head of the list. The * structures are allocated by malloc, so they must be freed. * Splitpath is used internally by the filename generator. * * Input: A string. * Returns: A linked list of the slash-separated segments of the input. */ struct path * splitpath(p) char *p; { struct path *head,*cur,*prv; int i; debug(F110,"splitpath",p,0); head = prv = NULL; if (*p == '\\') p++; /* skip leading slash */ while (*p != '\0') { cur = (struct path *) malloc(sizeof (struct path)); debug(F101,"splitpath malloc","",cur); if (cur == NULL) fatal("malloc fails in splitpath()"); cur -> fwd = NULL; if (head == NULL) head = cur; else prv -> fwd = cur; /* link into chain */ prv = cur; for (i=0; i < MAXNAMLEN && *p != '\\' && *p != ':' && *p != '\0'; i++) cur -> npart[i] = *p++; if ( *p == ':' ) { cur -> npart[i++] = *p++; if ( *p != '\\' ) cur -> npart[i++] = '.'; } cur -> npart[i] = '\0'; /* end this segment */ if (i >= MAXNAMLEN) while (*p != '\\' && *p != '\0') p++; if (*p == '\\') p++; } return(head); } /* Directory Functions for GEMDOS, hacked up by Bruce Moore, 1991 */ /* * fgen: * This is the actual name generator. It is passed a string, * possibly containing wildcards, and an array of character pointers. * It finds all the matching filenames and stores them into the array. * The returned strings are allocated from a static buffer local to * this module (so the caller doesn't have to worry about deallocating * them); this means that successive calls to fgen will wipe out * the results of previous calls. This isn't a problem here * because we process one wildcard string at a time. * * Input: a wildcard string, an array to write names to, the * length of the array. * Returns: the number of matches. The array is filled with filenames * that matched the pattern. If there wasn't enough room in the * array, -1 is returned. * By: Jeff Damens, CUCCA, 1984. */ static int fgen(pat,resarry,len) char *pat,*resarry[]; int len; { int numfnd; numfnd = traverse(pat,resarry,len); /* go walk the directory tree */ if (numfnd >= len) return(-1); return(numfnd); /* and return the number of matches */ } /* traverse: * Walks the directory tree looking for matches to its arguments. * The algorithm is, briefly: * If the current pattern segment contains no wildcards, that * segment is added to what we already have. If the name so far * exists, we call ourselves recursively with the next segment * in the pattern string; otherwise, we just return. * * If the current pattern segment contains wildcards, we open the name * we've accumulated so far (assuming it is really a directory), then read * each filename in it, and, if it matches the wildcard pattern segment, add * that filename to what we have so far and call ourselves recursively on the * next segment. * * Finally, when no more pattern segments remain, we add what's accumulated * so far to the result array and increment the number of matches. * * Input: a pattern path list (as generated by splitpath), a string * pointer that points to what we've traversed so far (this * can be initialized to "/" to start the search at the root * directory, or to "./" to start the search at the current * directory), and a string pointer to the end of the string * in the previous argument. * Returns: nothing. */ static VOID traverse(name, wildnames, maxwild) char *name; char *wildnames[]; int maxwild; { DMABUFFER dma; DMABUFFER *saved; char *p; int found; found = 0; saved = (DMABUFFER *) Fgetdta(); Fsetdta(&dma); if (Fsfirst(name, S_IJRON) == 0) { /* Found one */ do { strcpy(scratch, name); if (p = strrchr(scratch, '\\')) p++; else p = scratch; *p = '\0'; strcat(scratch, dma.d_fname); wildnames[found] = malloc(strlen(scratch) + 1); strcpy(wildnames[found++], scratch); if (found >= maxwild) break; } while (Fsnext() == 0); } Fsetdta(saved); return(found); } /* The following function is for expanding tilde in filenames * Contributed by Howie Kaye, CUCCA, developed for CCMD package. */ /* T I L D E _ E X P A N D -- expand ~user to the user's home directory. */ #define DIRSEP '\\' char * tilde_expand(dirname) char *dirname; { #define BUFLEN 256 #ifdef DTILDE static char olddir[BUFLEN]; static char oldrealdir[BUFLEN]; static char temp[BUFLEN]; int i, j; char *user; debug(F111,"tilde_expand",dirname,dirname[0]); if (dirname[0] != '~') /* Not a tilde...return param */ return(dirname); if (!strcmp(olddir,dirname)) { /* Same as last time */ return(oldrealdir); /* so return old answer. */ } else { j = strlen(dirname); for (i = 0; i < j; i++) /* find username part of string */ if (dirname[i] != DIRSEP) temp[i] = dirname[i]; else break; temp[i] = '\0'; /* tie off with a NULL */ if (i == 1) { /* if just a "~" */ user = "?"; /* No info, we're single user */ } else { user = NULL; /* otherwise on the specified user */ } } if (user != NULL) { /* valid user? */ strcpy(olddir, dirname); /* remember the directory */ strcpy(oldrealdir, zhome()); /* and their home directory */ strcat(oldrealdir,&dirname[i]); return(oldrealdir); } else { /* invalid? */ strcpy(olddir, dirname); /* remember for next time */ strcpy(oldrealdir, dirname); return(oldrealdir); } #else return(NULL); #endif /* dtilde */ } /* Functions for executing system commands. zsyscmd() executes the system command in the normal, default way for the system. In UNIX, it does what system() does. Thus, its results are always predictable. zshcmd() executes the command using the user's preferred shell. */ int zsyscmd(s) char *s; { return(tossystem(s)); } /* UNIX code by H. Fischer; copyright rights assigned to Columbia Univ. Adapted to use getpwuid to find login shell because many systems do not have SHELL in environment, and to use direct calling of shell rather than intermediate system() call. -- H. Fischer Call with s pointing to command to execute. */ int zshcmd(s) char *s; { tossystem(s); return(1); } /* I S W I L D -- Check if filespec is "wild" */ /* Returns 0 if it is a single file, 1 if it contains wildcard characters. Note: must match the algorithm used by match(), hence no [a-z], etc. */ int iswild(filespec) char *filespec; { char c; int x; char *p; if (wildxpand) { if ((x = zxpand(filespec)) > 1) return(1); p = malloc(MAXNAMLEN + 20); znext(p); x = (strcmp(filespec,p) != 0); free(p); return(x); } else { while ((c = *filespec++) != '\0') if (c == '*' || c == '?') return(1); return(0); } } /* T O S S Y S T E M -- Execute a system command */ /* Use gulam if present, otherwise hope for MSH, the shell supplied with the Mark Williams C package. */ #define SHELLP ((char **) 0x04f6L) #define G_MAGIC 0x0135 tossystem(cmd) char *cmd; { long save_ssp; short sh_magic; char *tgptr; /* storage for togu_ */ int (* cgp)(); /* pointer to callgulam() */ save_ssp = Super(0L); /* Get gulam stuff in Supervisor mode */ if ((tgptr = *SHELLP)) { /* NULL need not apply */ sh_magic = *((short *)(tgptr - 8)); cgp = *((int (*)()) tgptr); } else sh_magic = 0; Super(save_ssp); if (sh_magic == G_MAGIC) /* Gulam??? */ (* cgp) (cmd); else /* No, hope for MSH */ system(cmd); }