C-KERMIT (Part 9 of 10)

gregg at okstate.UUCP gregg at okstate.UUCP
Fri Mar 8 17:51:00 AEST 1985



echo x - ckxunx.c
sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckxunx.c
Xchar *ckxv = "Unix tty I/O, 4.2(016), 5 Mar 85";
X
X/* C-Kermit interrupt, terminal control & i/o functions for Unix systems */
X
X/* F. da Cruz, Columbia University Center for Computing Activities */
X
X#ifdef BSD4
Xchar *ckxsys = " 4.2 BSD";
X#endif
X
X#ifdef PROVX1
Xchar *ckxsys = " Pro-3xx Venix 1.0";
X#endif
X
X/* Tower support contributed by John Bray, Auburn University */
X#ifdef TOWER1
Xchar *ckxsys = " NCR Tower 1632, OS 1.02";
X#endif
X
X/* Sys III/V, Xenix, PC/IX support by Herm Fischer, Litton Data Systems */
X#ifdef UXIII
X#ifdef XENIX
Xchar *ckxsys = " Xenix/286";
X#else
X#ifdef PCIX
Xchar *ckxsys = " PC/IX";
X#else
X#ifdef ISIII
Xchar *ckxsys = " Interactive Systems Corp System III";
X#else
Xchar *ckxsys = " AT&T System III/System V";
X#endif
X#endif
X#endif
X#endif
X
X/*
X Note - KERLD is the Berkeley Unix Berknet line driver, modified to pass
X through all 8  bits, and to allow an arbitrary break character to be set.
X Don't define this symbol unless you have made this modification to your
X 4.2BSD kernel!
X*/
X#ifdef BSD4
X/* #define KERLD */  /* <-- note, commented out */
X#endif
X
X/*
X Variables available to outside world:
X
X   dftty  -- Pointer to default tty name string, like "/dev/tty".
X   dfloc  -- 0 if dftty is console, 1 if external line.
X   dfprty -- Default parity
X   dfflow -- Default flow control
X   ckxech -- Flag for who echoes console typein:
X     1 - The program (system echo is turned off)
X     0 - The system (or front end, or terminal).
X   functions that want to do their own echoing should check this flag
X   before doing so.
X
X   flfnam -- Name of lock file, including its path, e.g.,
X		"/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
X   hasLock -- Flag set if this kermit established a uucp lock.
X   inbufc -- number of tty line rawmode unread characters 
X		(system III/V unixes)
X   backgrd -- Flag indicating program executing in background ( & on 
X		end of shell command). Used to ignore INT and QUIT signals.
X
X Functions for assigned communication line (either external or console tty):
X
X   ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
X   ttclos()                -- Close & reset the tty, releasing any access lock.
X   ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
X   ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
X				or in DIALING or CONNECTED modem control state.
X   ttinl(dest,max,timo)    -- Timed read line from the tty.
X   ttinc(timo)             -- Timed read character from tty.
X   myread()		   -- System 3 raw mode bulk buffer read, gives
X			   --   subsequent chars one at a time and simulates
X			   --   FIONREAD!
X   myunrd(c)		   -- Places c back in buffer to be read (one only)
X   ttchk()                 -- See how many characters in tty input buffer.
X   ttxin(n,buf)            -- Read n characters from tty (untimed).
X   ttol(string,length)     -- Write a string to the tty.
X   ttoc(c)                 -- Write a character to the tty.
X   ttflui()                -- Flush tty input buffer.
X
X   ttlock(ttname)	   -- Lock against uucp collisions (Sys III)
X   ttunlck()		   -- Unlock "       "     "
X   look4lk(ttname)	   -- Check if a lock file exists
X*/
X
X/*
XFunctions for console terminal:
X
X   congm()   -- Get console terminal modes.
X   concb(esc) -- Put the console in single-character wakeup mode with no echo.
X   conbin(esc) -- Put the console in binary (raw) mode.
X   conres()  -- Restore the console to mode obtained by congm().
X   conoc(c)  -- Unbuffered output, one character to console.
X   conol(s)  -- Unbuffered output, null-terminated string to the console.
X   conola(s) -- Unbuffered output, array of strings to the console.
X   conxo(n,s) -- Unbuffered output, n characters to the console.
X   conchk()  -- Check if characters available at console (bsd 4.2).
X		Check if escape char (^\) typed at console (System III/V).
X   coninc(timo)  -- Timed get a character from the console.
X   conint()  -- Enable terminal interrupts on the console if not background.
X   connoi()  -- Disable terminal interrupts on the console if not background.
X
XTime functions
X
X   msleep(m) -- Millisecond sleep
X   ztime(&s) -- Return pointer to date/time string
X*/
X
X/* Includes */
X
X#include <stdio.h>			/* Unix Standard i/o */
X#include <signal.h>			/* Interrupts */
X#include <setjmp.h>			/* Longjumps */
X
X#ifdef UXIII
X#include <sys/types.h>
X#endif
X
X#ifndef PROVX1
X#include <sys/file.h>			/* File information */
X#endif
X
X#ifndef DIRSIZ
X#ifdef MAXNAMLEN
X#define DIRSIZ MAXNAMLEN
X#else
X#define DIRSIZ 14
X#endif
X#endif
X
X#ifdef UXIII
X#include <termio.h>
X#include <sys/ioctl.h>
X#include <fcntl.h>			/* directory reading for locking */
X#include <sys/dir.h>
X#include <errno.h>			/* error numbers for system returns */
Xextern int errno;			/* system call error return */
X#endif
X
X#ifndef UXIII
X#include <sgtty.h>			/* Set/Get tty modes */
X#ifndef PROVX1
X#include <sys/time.h>			/* Clock info (for break generation) */
X#endif
X#endif
X
X#ifdef TOWER1
X#include <sys/timeb.h>			/* Clock info for NCR Tower */
X#endif
X
X#include "ckdebu.h"			/* Formats for debug() */
X
X/* Declarations */
X
X/* dftty is the device name of the default device for file transfer */
X/* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
X
X#ifdef PROVX1
X    char *dftty = "/dev/com1";
X    int dfloc = 1;
X#else
X    char *dftty = "/dev/tty";
X    int dfloc = 0;
X#endif
X
X    int dfprty = 0;			/* Parity (0 = none) */
X    int dfflow = 1;			/* Xon/Xoff flow control */
X    int backgrd = 0;			/* Assume in foreground (no '&' ) */
X
Xint ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
X
X/* Declarations of variables global within this module */
X
Xstatic jmp_buf sjbuf;			/* Longjump buffer */
Xstatic int lkf = 0,			/* Line lock flag */
X    conif = 0,				/* Console interrupts on/off flag */
X    cgmf = 0,				/* Flag that console modes saved */
X    xlocal = 0,				/* Flag for tty local or remote */
X    ttyfd = -1;				/* TTY file descriptor */
Xstatic char escchr;			/* Escape or attn character */
X
X#ifdef KERLD
X    static int kerld = 1;		/* Special Kermit line discipline... */
X    struct tchars oldc, newc;		/* Special characters */
X    int ld = NETLDISC;			/* Special Kermit line discipline */
X    int oldld;				/* Old discipline */
X#else
X    static int kerld = 0;		/* for 4.2BSD only, */
X#endif
X
X#ifdef BSD4
X    static struct timeval tv;		/* For getting time, from sys/time.h */
X    static struct timezone tz;
X#endif
X
X#ifdef TOWER1
Xstatic long clock;			/* For getting time from sys/time.h */
Xstatic struct timeb ftp;		/* And from sys/timeb.h */
X#endif
X
X#ifdef UXIII
X  static struct termio 			/* sgtty info... */
X    ttold, ttraw, tttvt,		/* for communication line */
X    ccold, ccraw, cccbrk;		/* and for console */
X#else
X  static struct sgttyb 			/* sgtty info... */
X    ttold, ttraw, tttvt,		/* for communication line */
X    ccold, ccraw, cccbrk;		/* and for console */
X#endif
X
Xstatic char flfnam[80];			/* uucp lock file path name */
Xstatic int hasLock = 0;			/* =1 if this kermit locked uucp */
Xstatic int inbufc = 0;			/* stuff for efficient SIII raw line */
Xstatic int ungotn = -1;			/* pushback to unread character */
Xstatic int conesc = 0;			/* set to 1 if esc char (^\) typed */
X
Xstatic int ttlock();			/* definition of ttlock subprocedure */
Xstatic int ttunlck();			/*   unlock subprocedure */
X
X/*  T T O P E N  --  Open a tty for exclusive access.  */
X
X/*  Returns 0 on success, -1 on failure.  */
X
Xttopen(ttname,lcl,modem) char *ttname; int lcl, modem; {
X
X    if (ttyfd > -1) return(0);		/* If already open, ignore this call */
X    xlocal = lcl;			/* Make available to other functions */
X#ifndef UXIII
X    ttyfd = open(ttname,2);		/* Open a tty for read/write */
X#else
X    /* if modem connection, don't wait for carrier */
X    ttyfd = open(ttname,O_RDWR | (modem ? O_NDELAY : 0) );
X#endif
X    if (ttyfd < 0) return(-1);
X    lkf = 0;
X
X#ifndef PROVX1
X    if (xlocal) {
X#ifdef BSD4
X    	if ((flock(ttyfd,(LOCK_EX|LOCK_NB)) < 0) || (ttlock(ttname) < 0 )) {
X#else
X#ifdef TOWER1
X    	if (ioctl(ttyfd,TIOCEXCL, NULL) < 0) {
X#else
X    	if (ttlock(ttname) < 0) {
X#endif
X#endif
X    	fprintf(stderr,"Sorry - Exclusive access to %s was denied\n",ttname);
X	return(-1);			/* Can't open if already locked */
X    	} else lkf = 1;
X    }
X#endif
X
X#ifndef UXIII
X    gtty(ttyfd,&ttold);			/* Get sgtty info */
X    gtty(ttyfd,&ttraw);			/* And a copy of it for packets*/
X    gtty(ttyfd,&tttvt);			/* And one for virtual tty service */
X#else
X    ioctl(ttyfd,TCGETA,&ttold);		/* Same deal for Sys III, Sys V */
X    ioctl(ttyfd,TCGETA,&ttraw);
X    ioctl(ttyfd,TCGETA,&tttvt);
X#endif
X    debug(F101,"ttopen, ttyfd","",ttyfd);
X    debug(F111," lock file",flfnam,lkf);
X    return(0);
X}
X
X/*  T T C L O S  --  Close the TTY, releasing any lock.  */
X
Xttclos() {
X    if (ttyfd < 0) return(0);		/* Wasn't open. */
X#ifndef PROVX1
X#ifdef BSD4
X    if (lkf) flock(ttyfd,LOCK_UN);	/* Unlock it first. */
X#endif
X    if (xlocal) ttunlck();
X#endif
X    ttres();				/* Reset modes. */
X    close(ttyfd);			/* Close it. */
X    ttyfd = -1;				/* Mark it as closed. */
X    return(0);
X}
X
X
X/*  T T R E S  --  Restore terminal to "normal" mode.  */
X
Xttres() {				/* Restore the tty to normal. */
X    if (ttyfd < 0) return(-1);		/* Not open. */
X    sleep(1);				/* Wait for pending i/o to finish. */
X#ifdef KERLD
X    if (kerld) ioctl(ttyfd,TIOCSETD,&oldld); /* Restore old line discipline. */
X#endif
X#ifdef UXIII
X    if (ioctl(ttyfd,TCSETA,&ttold) < 0) return(-1); /* restore termio stuff */
X#else
X    debug(F101,"ttres, ttyfd","",ttyfd);
X    if (stty(ttyfd,&ttold) < 0) return(-1); /* Restore sgtty stuff */
X#endif
X#ifdef KERLD
X    if (kerld) ioctl(ttyfd,TIOCSETC,&oldc); /* Restore old special chars. */
X#endif
X
X    return(0);
X}
X
X#ifndef PROVX1
X
X/* Exclusive uucp file locking control */
X/*
X by H. Fischer, creative non-Bell coding !
X*/
Xstatic char *
Xxxlast(s,c) char *s; char c; {		/* Equivalent to strrchr() */
X    int i;
X    for (i = strlen(s); i > 0; i--)
X    	if ( s[i-1] == c ) return( s + (i - 1) );
X    return(NULL);	    
X}
Xstatic
Xlook4lk(ttname) char *ttname; {
X    extern char *strcat(), *strcpy();
X    char *device, *devname;
X    char lockfil[DIRSIZ+1];
X
X#ifdef ISIII
X    char *lockdir = "/etc/locks";
X#else
X    char *lockdir = "/usr/spool/uucp";
X#endif
X
X    device = ( (devname=xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
X
X#ifdef ISIII
X    (void) strcpy( lockfil, device );
X#else
X    (void) strcat( strcpy( lockfil, "LCK.." ), device );
X#endif
X
X    if (access( lockdir, 04 ) < 0) {	/* read access denied on lock dir */
X	fprintf(stderr,"Warning, read access to lock directory denied\n");
X	return( 1 );			/* cannot check or set lock file */
X	}
X	
X    (void) strcat(strcat(strcpy(flfnam,lockdir),"/"), lockfil);
X    debug(F110,"look4lk",flfnam,0);
X
X    if ( ! access( flfnam, 00 ) ) {	/* print out lock file entry */
X	char lckcmd[40] ;
X	(void) strcat( strcpy(lckcmd, "ls -l ") , flfnam);
X	system(lckcmd);
X	return( -1 );
X	}
X    if ( access( lockdir, 02 ) < 0 ) {	/* lock file cannot be written */
X	fprintf(stderr,"Warning, write access to lock directory denied\n");
X	return( 1 );
X	}
X    return( 0 );			/* okay to go ahead and lock */
X}
X
X/*  T T L O C K  */
X
Xstatic
Xttlock(ttyfd) char *ttyfd; {		/* lock uucp if possible */
X    int lck_fil, l4l;
X	
X    hasLock = 0;			/* not locked yet */
X    if ((l4l=look4lk(ttyfd)) < 0) return(-1); /* already locked */
X    if (l4l == 1) return (0);		/* can't read/write lock directory */
X    if ((lck_fil=open (flfnam, O_CREAT | O_EXCL)) < 1 ) 
X    	return(-1);			/* failed to create */
X    close (lck_fil);
X    hasLock = 1;			/* now is locked */
X    return(0);
X}
X
X/*  T T U N L O C K  */
X
Xstatic
Xttunlck() {				/* kill uucp lock if possible */
X    if (hasLock) unlink( flfnam );
X}
X#endif
X
X
X
X/*  T T P K T  --  Condition the communication line for packets. */
X/*		or for modem dialing */
X
X#define DIALING	4		/* flags (via flow) for modem handling */
X#define CONNECT 5
X
X/*  If called with speed > -1, also set the speed.  */
X
X/*  Returns 0 on success, -1 on failure.  */
X
Xttpkt(speed,flow) int speed, flow; {
X    extern char ttname[];
X    int s;
X    if (ttyfd < 0) return(-1);		/* Not open. */
X
X#ifdef KERLD
X    if (kerld) {
X	ioctl(ttyfd,TIOCGETD,&oldld);	/* Get line discipline */
X	ioctl(ttyfd,TIOCGETC,&oldc);	/* Get special chars */
X	newc = oldc;			/* Copy special chars */
X	newc.t_brkc = '\r';		/* Set CR to be break character */
X	if(ioctl(ttyfd,TIOCSETC,&newc) < 0) return(-1);
X    }
X#endif
X
X/* cont'd... */
X
X/* ...ttpkt(), cont'd */
X
X
X/* Note, KERLD ignores the TANDEM, ECHO, and CRMOD bits */
X
X    s = ttsspd(speed);			/* Check the speed */
X
X#ifndef UXIII
X    if (flow == 1) ttraw.sg_flags |= TANDEM; /* Use XON/XOFF if selected */
X    if (flow == 0) ttraw.sg_flags &= ~TANDEM;
X    ttraw.sg_flags |= RAW;		/* Go into raw mode */
X    ttraw.sg_flags &= ~(ECHO|CRMOD);	/* Use CR for break character */
X#ifdef TOWER1
X    ttraw.sg_flags &= ~ANYP; 		/* Must tell Tower no parityr */
X#endif
X    if (s > -1) ttraw.sg_ispeed = ttraw.sg_ospeed = s; /* Do the speed */
X    if (stty(ttyfd,&ttraw) < 0) return(-1);	/* Set the new modes. */
X#endif
X
X#ifdef UXIII
X    if (flow == 1) ttraw.c_iflag |= (IXON|IXOFF);
X    if (flow == 0) ttraw.c_iflag &= ~(IXON|IXOFF);
X
X    if (flow == DIALING)  ttraw.c_cflag |= CLOCAL|HUPCL;
X    if (flow == CONNECT)  ttraw.c_cflag &= ~CLOCAL;
X
X    ttraw.c_lflag &= ~(ICANON|ECHO);
X    ttraw.c_lflag |= ISIG;		/* do check for interrupt */
X    ttraw.c_iflag |= (BRKINT|IGNPAR);
X    ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC);
X    ttraw.c_oflag &= ~(ONLCR|OCRNL|ONLRET);
X    ttraw.c_cc[4] = 1;
X    ttraw.c_cc[5] = 0;
X
X    if (s > -1) ttraw.c_cflag &= ~CBAUD, ttraw.c_cflag |= s; /* set speed */
X
X    if (ioctl(ttyfd,TCSETA,&ttraw) < 0) return(-1);  /* set new modes . */
X    if (flow == DIALING) {
X	if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
X		return(-1);
X	close( open(ttname,2) );	/* magic to force file open!!! */
X	}
X#endif
X
X#ifdef KERLD
X    if (kerld) {
X	if (ioctl(ttyfd,TIOCSETD,&ld) < 0)
X	    return(-1); /* Set line discpline. */
X    }
X#endif
X
X    ttflui();				/* Flush any pending input */
X    return(0);
X}
X
X/*  T T V T -- Condition communication line for use as virtual terminal  */
X
Xttvt(speed,flow) int speed, flow; {
X    extern char ttname[];
X    int s;
X    if (ttyfd < 0) return(-1);		/* Not open. */
X
X    s = ttsspd(speed);			/* Check the speed */
X
X#ifndef UXIII
X    if (flow == 1) tttvt.sg_flags |= TANDEM; /* XON/XOFF if selected */
X    if (flow == 0) tttvt.sg_flags &= ~TANDEM;
X    tttvt.sg_flags |= RAW;		/* Raw mode */
X#ifdef TOWER1
X    tttvt.sg_flags &= ~(ECHO|ANYP);	/* No echo or system III ??? parity */
X#else
X    tttvt.sg_flags &= ~ECHO;		/* No echo */
X#endif    
X    if (s > -1) tttvt.sg_ispeed = tttvt.sg_ospeed = s; /* Do the speed */
X
X/* NOTE-- bsd code needs clocal and o_Ndelay stuff here */
X    return(stty(ttyfd,&tttvt));
X#else
X    if (flow == 1) tttvt.c_iflag |= (IXON|IXOFF);
X    if (flow == 0) tttvt.c_iflag &= ~(IXON|IXOFF);
X
X    if (flow == DIALING)  tttvt.c_cflag |= CLOCAL|HUPCL;
X    if (flow == CONNECT)  tttvt.c_cflag &= ~CLOCAL;
X
X    tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
X    tttvt.c_iflag |= (IGNBRK|BRKINT|IGNPAR);
X    tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC);
X    tttvt.c_oflag &= ~(ONLCR|OCRNL|ONLRET);
X    tttvt.c_cc[4] = 1;
X    tttvt.c_cc[5] = 0;
X
X    if (s > -1) tttvt.c_cflag &= ~CBAUD, tttvt.c_cflag |= s; /* set speed */
X
X    if (ioctl(ttyfd,TCSETA,&tttvt) < 0) return(-1);  /* set new modes . */
X    if (flow == DIALING) {
X	if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
X		return(-1);
X	close( open(ttname,2) );	/* magic to force file open!!! */
X	}
X    return(0);
X#endif
X}
X
X/*  T T S S P D  --  Return the internal baud rate code for 'speed'.  */
X
Xttsspd(speed) {
X    int s, spdok;
X
X    if (speed < 0) return(-1);
X	spdok = 1;			/* Assume arg ok */
X	switch (speed) {
X	    case 0:    s = B0;    break;	/* Just the common ones. */
X	    case 110:  s = B110;  break;	/* The others from ttydev.h */
X	    case 150:  s = B150;  break;	/* could also be included if */
X	    case 300:  s = B300;  break;	/* necessary... */
X	    case 600:  s = B600;  break;
X	    case 1200: s = B1200; break;
X	    case 1800: s = B1800; break;
X	    case 2400: s = B2400; break;
X	    case 4800: s = B4800; break;
X	    case 9600: s = B9600; break;
X	    default:
X	    	spdok = 0;
X		fprintf(stderr,"Unsupported line speed - %d\n",speed);
X		fprintf(stderr,"Current speed not changed\n");
X		break;
X	}	    
X	if (spdok) return(s); else return(-1);
X }
X
X
X
X/*  T T F L U I  --  Flush tty input buffer */
X
Xttflui() {
X
X#ifndef PROVX1
X    long n;
X#endif
X    if (ttyfd < 0) return(-1);		/* Not open. */
X
X#ifdef BSD4
X#ifdef TOWER1
X    n = FREAD;				/* Specify read queue */
X    if (ioctl(ttyfd,TIOCFLUSH,&n) < 0) perror("flush failed");
X#endif
X#endif
X
X#ifdef UXIII
X    inbufc = 0;
X    ungotn = -1;
X    if (ioctl(ttyfd,TCFLSH,0) < 0) perror("flush failed");
X#endif
X
X    return(0);
X}
X
X/* Interrupt Functions */
X
X
X/* Timeout handler for communication line input functions */
X
Xtimerh() {
X    longjmp(sjbuf,1);
X}
X
X 
X/* Set up terminal interrupts on console terminal */
X
X#ifdef UXIII
Xesctrp() {				/* trap console escapes (^\) */
X    conesc = 1;
X    signal(SIGQUIT,SIG_IGN);		/* ignore until trapped */
X}
X#endif
X
X
X/*  C O N I N T  --  Console Interrupt setter  */
X
Xconint(f) int (*f)(); {			/* Set an interrupt trap. */
X
X    if (backgrd) return;		/* must ignore signals in bkgrd */
X
X#ifdef UXIII
X    signal(SIGQUIT,esctrp);	/* console escape in pkt modes */
X    if (conesc) {			/* clear out pending escapes */
X	conesc = 0;
X    }
X#endif
X
X    if (conif) return;			/* Nothing to do if already on. */
X
X/* check if invoked in background -- if so signals set to be ignored */
X
X    if (signal(SIGINT,SIG_IGN) == SIG_IGN) {
X	backgrd = 1;			/*   means running in background */
X#ifdef UXIII
X	signal(SIGQUIT,SIG_IGN);	/*   must leave signals ignored */
X#endif
X	return;
X    }
X    signal(SIGINT,f);			/* Function to trap to. */
X    conif = 1;				/* Flag console interrupts on. */
X}
X
X
X/*  C O N N O I  --  Reset console terminal interrupts */
X
Xconnoi() {				/* Console-no-interrupts */
X
X    if (backgrd) return;		/* must ignore signals in bkgrd */
X
X    signal(SIGINT,SIG_DFL);
X    conif = 0;
X}
X
X/*  myread() -- System III raw read buffer to block input up */
X
Xmyread() {			/* return character or -1 if disconnected */
X
X    static int inbuf_item;
X    static CHAR inbuf[257];
X    CHAR readit;
X    
X    if (ungotn >= 0) readit = ungotn;
X    else {
X        if (inbufc > 0)
X	    readit = inbuf[++inbuf_item];
X    	        else {
X	    if ((inbufc=read(ttyfd,inbuf,256)) == 0 ) return(-1);
X	    readit = inbuf[inbuf_item=0];
X	    }
X        inbufc--;	
X        }
X    ungotn = -1;
X    return(readit );
X    }
X
Xmyunrd(ch) CHAR ch; {			/* push back up to one character */
X    ungotn = ch;
X}
X
X
X/*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
X
Xttchk() {
X#ifndef PROVX1
X    int n, x;
X#ifdef BSD4
X    x = ioctl(ttyfd, FIONREAD, &n);
X    return((x < 0) ? 0 : n);
X#else
X    return(inbufc + (ungotn >= 0) );	
X#endif
X#else
X    return(0);
X#endif
X}
X
X
X/*  T T X I N  --  Get n characters from tty input buffer  */
X
Xttxin(n,buf) int n; char *buf; {
X    int x;
X#ifndef UXIII
X    x = read(ttyfd,buf,n);
X#else
X    for( x=0; x<n; buf[x++]=myread() );
X#endif
X    if (x > 0) buf[x] = '\0';
X    return(x);
X}
X
X/*  T T O L  --  Similar to "ttinl", but for writing.  */
X
Xttol(s,n) int n; char *s; {
X    int x;
X    if (ttyfd < 0) return(-1);		/* Not open. */
X    x = write(ttyfd,s,n);
X    debug(F111,"ttol",s,n);
X    if (x < 0) debug(F101,"ttol failed","",x);
X    return(x);
X}
X
X
X/*  T T O C  --  Output a character to the communication line  */
X
Xttoc(c) char c; {
X    if (ttyfd < 0) return(-1);		/* Not open. */
X    return(write(ttyfd,&c,1));
X}
X
X/*  T T I N L  --  Read a record (up to break character) from comm line.  */
X/*
X  If no break character encountered within "max", return "max" characters,
X  with disposition of any remaining characters undefined.  Otherwise, return
X  the characters that were read, including the break character, in "dest" and
X  the number of characters read as the value of function, or 0 upon end of
X  file, or -1 if an error occurred.  Times out & returns error if not completed
X  within "timo" seconds.
X*/
X
Xttinl(dest,max,timo,eol) int max,timo; char *dest; {
X    int x, y, c;
X    if (ttyfd < 0) return(-1);		/* Not open. */
X    if (timo <= 0) {			/* Untimed. */
X#ifndef UXIII
X	x = read(ttyfd,dest,max);	/* Try to read. */
X#else
X	for (x = c = 0; (x < max) && (c != eol); x++) {
X	     c = myread(); 
X	     dest[x] = c;
X	}
X#endif
X	return(x);			/* Return the count. */
X    }
X    signal(SIGALRM,timerh);		/* Timed, set up timeout action. */
X    alarm(timo);			/* Set the timer. */
X    if (setjmp(sjbuf)) x = -1;		/* Do this if timer went off. */
X    else if (kerld) {
X	x = read(ttyfd,dest,max);	/* Try to read. */
X    } else {
X	for (x = c = y = 0; (x < max) && (c != eol); x++) {
X#ifndef UXIII
X	     while ( !(y = read(ttyfd,&c,1))) ; /* skip null reads */
X	     if (y < 0) return(y);
X#else
X	     c = myread(); 
X#endif
X	     dest[x] = c;
X	}
X	x++;
X    }
X    alarm(0);				/* Success, turn off timer, */
X    signal(SIGALRM,SIG_DFL);		/* and associated interrupt. */
X    return(x);				/* Return the count. */
X}
X
X/*  T T I N C --  Read a character from the communication line  */
X
Xttinc(timo) int timo; {
X    int n;
X    CHAR ch;
X
X    if (ttyfd < 0) return(-1);		/* Not open. */
X    if (timo <= 0) {			/* Untimed. */
X#ifndef UXIII
X	while ( !(n = read(ttyfd,&ch,1)) ) ; /* Wait for a character. */
X	return( (n > 0) ? (ch & 0377) : n );
X#else
X	/* comm line failure returns -1 thru myread, so don't &= 0377 */
X	return( myread() );
X#endif
X    }
X
X    signal(SIGALRM,timerh);		/* Timed, set up timer. */
X    alarm(timo);
X    if (setjmp(sjbuf)) n = -1;
X    else {
X#ifndef UXIII
X    n = read(ttyfd,&ch,1);		/* Read a character. */
X#else
X    ch = myread();
X    n = 1;
X#endif
X    }
X    alarm(0);				/* Turn off timer, */
X    signal(SIGALRM,SIG_DFL);		/* and interrupt. */
X    if (n > 0) return(ch & 0377); else return(n);  /* Return char or -1. */
X}
X
X/*  T T S N D B  --  Send a BREAK signal  */
X
Xttsndb() {
X    int x;
X
X    if (ttyfd < 0) return(-1);		/* Not open. */
X
X#ifdef PROVX1
X/*** insert code to set speed to 50 baud and send 2-3 nulls ***/
X    return(0);
X#else
X#ifdef UXIII
X    if (ioctl(ttyfd,TCSBRK,(char *)0) < 0) {	/* Turn on BREAK */
X    	conol("Can't send BREAK");
X	return(-1);
X    }
X    return(0);
X#else
X#ifdef BSD4
X    if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {	/* Turn on BREAK */
X    	conol("Can't send BREAK");
X	return(-1);
X    }
X    x = msleep(275);			/* Sleep for so many milliseconds */
X    if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {	/* Turn off BREAK */
X	conol("BREAK stuck!!!");
X	doexit(1);			/* Get out, closing the line. */
X					/*   with exit status = 1 */
X    }
X    return(x);
X#endif
X#endif
X#endif
X}
X
X/*  M S L E E P  --  Millisecond version of sleep().  */
X
X/*
X Intended only for small intervals.  For big ones, just use sleep().
X*/
X
Xmsleep(m) int m; {
X
X#ifdef PROVX1
X    sleep(1+m/1000.0);
X    return(0);
X#endif
X
X#ifdef BSD4
X    int t1, t3, t4;
X    if (gettimeofday(&tv, &tz) < 0) return(-1); /* Get current time. */
X    t1 = tv.tv_sec;			/* Seconds */
X
Xif (0) {				/* Old way (works) */
X    while (1) {
X	gettimeofday(&tv, &tz);
X	t3 = tv.tv_sec - t1;
X	t4 = (tv.tv_usec + 1000000 * t3) / 1000;
X	if (t4 > m) return(t4);
X    }
X} else {				/* New way (also works) */
X    tv.tv_sec = 0;
X    tv.tv_usec = m * 1000;
X    return(select( 0, (int *)0, (int *)0, (int *)0, &tv) );
X}
X#endif
X
X#ifdef TOWER1
X    if (ftime(&ftp) < 0) return(-1);		/* Get current time. */
X    t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
X    while (1) {
X	ftime(&ftp);				/* new time */
X	t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
X	if (t3 > m) return (t3);
X    }
X#endif
X}
X
X/*  Z T I M E  --  Return date/time string  */
X
Xztime(s) char **s; {
X
X#ifdef UXIII
X    extern long time();			/* Sys III/V way to do it */
X    char *ctime();
X    long clock_storage;
X
X    clock_storage = time( (long *) 0 );
X    *s = ctime( &clock_storage );
X#endif
X
X#ifdef PROVX1
X    int utime[2];			/* Venix way */
X    time(utime);
X    *s = ctime(utime);
X#endif
X
X#ifdef BSD4
X    char *asctime();			/* Berkeley way */
X    struct tm *localtime();
X    struct tm *tp;
X
X    gettimeofday(&tv, &tz);
X    time(&tv.tv_sec);
X    tp = localtime(&tv.tv_sec);
X    *s = asctime(tp);
X#endif
X
X#ifdef TOWER1
X    char *asctime();			/* Tower way */
X    struct tm *localtime();
X    struct tm *tp;
X
X    time(&clock);
X    tp = localtime(&clock);
X    *s = asctime(tp);
X#endif
X}
X
X/*  C O N G M  --  Get console terminal modes.  */
X
X/*
X Saves current console mode, and establishes variables for switching between 
X current (presumably normal) mode and other modes.
X*/
X
Xcongm() {
X#ifndef UXIII
X     gtty(0,&ccold);			/* Structure for restoring */
X     gtty(0,&cccbrk);			/* For setting CBREAK mode */
X     gtty(0,&ccraw);			/* For setting RAW mode */
X#else
X     ioctl(0,TCGETA,&ccold);
X     ioctl(0,TCGETA,&cccbrk);
X     ioctl(0,TCGETA,&ccraw);
X#endif
X     cgmf = 1;				/* Flag that we got them. */
X}
X
X
X/*  C O N C B --  Put console in cbreak mode.  */
X
X/*  Returns 0 if ok, -1 if not  */
X
Xconcb(esc) char esc; {
X    int x;
X    if (cgmf == 0) congm();		/* Get modes if necessary. */
X    escchr = esc;			/* Make this available to other fns */
X    ckxech = 1;				/* Program can echo characters */
X#ifndef UXIII
X    cccbrk.sg_flags |= CBREAK;		/* Set to character wakeup, */
X    cccbrk.sg_flags &= ~ECHO;		/* no echo. */
X    x = stty(0,&cccbrk);
X#else
X    cccbrk.c_lflag &= ~(ICANON|ECHO);
X    cccbrk.c_cc[0] = 003;		/* interrupt char is control-c */
X    cccbrk.c_cc[1] = escchr;		/* escape during packet modes */
X    cccbrk.c_cc[4] = 1;
X    cccbrk.c_cc[5] = 1;
X    x = ioctl(0,TCSETA,&cccbrk);  	/* set new modes . */
X#endif
X    if (x > -1) setbuf(stdout,NULL);	/* Make console unbuffered. */
X    return(x);
X}
X
X/*  C O N B I N  --  Put console in binary mode  */
X
X
X/*  Returns 0 if ok, -1 if not  */
X
Xconbin(esc) char esc; {
X    if (cgmf == 0) congm();		/* Get modes if necessary. */
X    escchr = esc;			/* Make this available to other fns */
X    ckxech = 1;				/* Program can echo characters */
X#ifndef UXIII
X    ccraw.sg_flags |= (RAW|TANDEM);   	/* Set rawmode, XON/XOFF */
X    ccraw.sg_flags &= ~(ECHO|CRMOD);  	/* Set char wakeup, no echo */
X    return(stty(0,&ccraw));
X#else
X    ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
X    ccraw.c_iflag |= (BRKINT|IGNPAR);
X    ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF);
X    ccraw.c_oflag &= ~(ONLCR|OCRNL|ONLRET);
X    ccraw.c_cc[4] = 1;
X    ccraw.c_cc[5] = 1;
X    return(ioctl(0,TCSETA,&ccraw) );  	/* set new modes . */
X#endif
X}
X
X
X/*  C O N R E S  --  Restore the console terminal  */
X
Xconres() {
X    if (cgmf == 0) return(0);		/* Don't do anything if modes */
X    sleep(1);				/*  not known! */
X    ckxech = 0;				/* System should echo chars */
X#ifndef UXIII
X    return(stty(0,&ccold));		/* Restore controlling tty */
X#else
X    return(ioctl(0,TCSETA,&ccold));
X#endif
X}
X
X/*  C O N O C  --  Output a character to the console terminal  */
X
Xconoc(c) char c; {
X    write(1,&c,1);
X}
X
X/*  C O N X O  --  Write x characters to the console terminal  */
X
Xconxo(x,s) char *s; int x; {
X    write(1,s,x);
X}
X
X/*  C O N O L  --  Write a line to the console terminal  */
X
Xconol(s) char *s; {
X    int len;
X    len = strlen(s);
X    write(1,s,len);
X}
X
X/*  C O N O L A  --  Write an array of lines to the console terminal */
X
Xconola(s) char *s[]; {
X    int i;
X    for (i=0 ; *s[i] ; i++) conol(s[i]);
X}
X
X/*  C O N O L L  --  Output a string followed by CRLF  */
X
Xconoll(s) char *s; {
X    conol(s);
X    write(1,"\r\n",2);
X}
X
X
X/*  C O N C H K  --  Check if characters available at console  */
X
Xconchk() {
X#ifdef PROVX1
X    return(0);
X#else
X    int n, x;
X#ifndef UXIII
X    x = ioctl(0, FIONREAD, &n);
X    return((x < 0) ? 0 : n);
X#else
X    if (conesc) {			/* Escape typed */
X	conesc = 0;
X	signal(SIGQUIT,esctrp);		/* restore escape */
X	return(1);
X    }
X    return(0);
X#endif
X#endif
X}
X
X/*  C O N I N C  --  Get a character from the console  */
X
Xconinc(timo) int timo; {
X    int n = 0; char ch;
X    if (timo <= 0 ) {			/* untimed */
X	n = read(0, &ch, 1);		/* Read a character. */
X	ch &= 0377;
X	if (n > 0) return(ch); 		/* Return the char if read */
X	else 
X#ifdef UXIII
X	    if (n < 0 && errno == EINTR) /* if read was interrupted by QUIT */
X		return(escchr);		 /* user entered escape character */
X	    else		    /* couldnt be ^c, sigint never returns */
X#endif
X		return(-1);  		/* Return the char, or -1. */
X	}
X    signal(SIGALRM,timerh);		/* timed, set up timer */
X    alarm(timo);
X    if (setjmp(sjbuf)) n = -2;
X    else {
X	n = read(0, &ch, 1);
X	alarm(0);
X	signal(SIGALRM,SIG_DFL);	/* stop timing, we got our character */
X	ch &= 0377;
X    }
X    if (n > 0) return(ch);  
X    else
X#ifdef UXIII
X        if (n == -1 && errno == EINTR)  /* If read interrupted by QUIT, */
X	    return(escchr);		/* user entered escape character, */
X        else		    		/* can't be ^c, sigint never returns */
X#endif
X	return(-1);
X}
!FUNKY!STUFF!
echo x - ckzunx.c
sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckzunx.c
Xchar *ckzv = "Unix file support, 4.1(015) 28 Feb 85";
X
X/* C K Z B S D  --  Kermit file system support for Unix systems */
X
X/* F. da Cruz, Columbia University Center for Computing Activities */
X
X/* Berkeley Unix Version 4.x */
X#ifdef BSD4
Xchar *ckzsys = " 4.x BSD";
X#endif
X
X/* DEC Professional-300 series with Venturcom Venix 1.0 */
X#ifdef PROVX1
Xchar *ckzsys = " DEC Pro-3xx/Venix 1.0";
X#endif
X
X/* NCR Tower support contributed by Kevin O'Kane, U. of Tennessee */
X/* Tower OS is like Sys III but with BSD features -- mostly follows BSD */
X#ifdef TOWER1
Xchar *ckxsys = " NCR Tower 1632, OS 1.02";
X#endif
X
X/* Sys III/V, Xenix, PC/IX,... support by Herm Fischer, Litton Data Systems */
X#ifdef UXIII
X#ifdef XENIX
Xchar *ckzsys = " Xenix/286";
X#else
X#ifdef PCIX
Xchar *ckzsys = " PC/IX";
X#else
X#ifdef ISIII
Xchar *ckzsys = " Interactive Systems Corp, System III";
X#else
Xchar *ckzsys = " AT&T System III/System V";
X#endif
X#endif
X#endif
X#endif
X
X/* Definitions of some Unix system commands */
X
Xchar *DIRCMD = "ls -l ";		/* For directory listing */
Xchar *DELCMD = "rm -f ";		/* For file deletion */
Xchar *TYPCMD = "cat ";			/* For typing a file */
X
X#ifdef BSD4
Xchar *SPACMD = "pwd ; quota ; df .";	/* Space/quota of current directory */
X#else
Xchar *SPACMD = "df ";
X#endif
X
Xchar *SPACM2 = "df ";			/* For space in specified directory */
X
X#ifdef BSD4
Xchar *WHOCMD = "finger ";		/* For seeing who's logged in */
X#else
Xchar *WHOCMD = "who ";			/* For seeing who's logged in */
X#endif
X
X/*
X  Functions (n is one of the predefined file numbers from ckermi.h):
X
X   zopeni(n,name)   -- Opens an existing file for input.
X   zopeno(n,name)   -- Opens a new file for output.
X   zclose(n)        -- Closes a file.
X   zchin(n)         -- Gets the next character from an input file.
X   zsout(n,s)       -- Write a null-terminated string to output file, buffered.
X   zsoutl(n,s)      -- Like zsout, but appends a line terminator.
X   zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
X   zchout(n,c)      -- Add a character to an output file, unbuffered.
X   zchki(name)      -- Check if named file exists and is readable, return size.
X   zchko(name)      -- Check if named file can be created.
X   znewn(name,s)    -- Make a new unique file name based on the given name.
X   zdelet(name)     -- Delete the named file.
X   zxpand(string)   -- Expands the given wildcard string into a list of files.
X   znext(string)    -- Returns the next file from the list in "string".
X   zxcmd(cmd)       -- Execute the command in a lower fork.
X   zclosf()         -- Close input file associated with zxcmd()'s lower fork.
X   zrtol(n1,n2)     -- Convert remote filename into local form.
X   zltor(n1,n2)     -- Convert local filename into remote form.
X   zchdir(dirnam)   -- Change working directory.
X   zhome()          -- Return pointer to home directory name string.
X */
X
X/* Includes */
X
X#include "ckermi.h"			/* Kermit definitions, ctype, stdio */
X#include <sys/types.h>			/* Data types */
X#include <sys/dir.h>			/* Directory structure */
X#include <sys/stat.h>			/* File status */
X#include <pwd.h>			/* Password file for shell name */
X
X#ifndef PROVX1
X#include <sys/file.h>			/* File access */
X#endif
X
X/* Some systems define these in include files, others don't... */
X
X#ifndef R_OK
X#define R_OK 4				/* For access */
X#endif
X
X#ifndef W_OK
X#define W_OK 2
X#endif
X
X#ifdef PROVX1
X#define MAXNAMLEN DIRSIZ		/* Max file name length */
X#endif
X
X#ifdef UXIII
X#include <fcntl.h>
X#define MAXNAMLEN DIRSIZ
X#endif
X
X#ifndef O_RDONLY
X#define O_RDONLY 000
X#endif
X
X#ifndef MAXNAMLEN
X#define MAXNAMLEN 14			/* If still not defined... */
X#endif
X
X#define MAXWLD 500			/* Maximum wildcard filenames */
X
X
X/* Declarations */
X
XFILE *fp[ZNFILS] = { 			/* File pointers */
X    NULL, NULL, NULL, NULL, NULL, NULL, NULL };
X
Xstatic int pid;	    			/* pid of child fork */
Xstatic int fcount;			/* Number of files in wild group */
Xchar *getenv(), *strcpy();		/* For finding home directory */
Xextern errno;				/* System error code */
X
Xstatic char *mtchs[MAXWLD],		/* Matches found for filename */
X     **mtchptr;				/* Pointer to current match */
X
X/*  Z O P E N I  --  Open an existing file for input. */
X
Xzopeni(n,name) int n; char *name; {
X    debug(F111," zopeni",name,n);
X    debug(F101,"  fp","",(int) fp[n]);
X    if (chkfn(n) != 0) return(0);
X    if (n == ZSTDIO) {			/* Standard input? */
X	if (isatty(0)) {
X	    fprintf(stderr,"?Terminal input not allowed\n");
X	    debug(F110,"zopeni: attempts input from unredirected stdin","",0);
X	    return(0);
X	}
X	fp[ZIFILE] = stdin;
X	return(1);
X    }
X    fp[n] = fopen(name,"r");		/* Real file. */
X    debug(F111," zopeni", name, (int) fp[n]);
X    if (fp[n] == NULL) perror("zopeni");
X    return((fp[n] != NULL) ? 1 : 0);
X}
X
X/*  Z O P E N O  --  Open a new file for output.  */
X
Xzopeno(n,name) int n; char *name; {
X    debug(F111," zopeno",name,n);
X    if (chkfn(n) != 0) return(0);
X    if ((n == ZCTERM) || (n == ZSTDIO)) {   /* Terminal or standard output */
X	fp[ZOFILE] = stdout;
X	debug(F101," fp[]=stdout", "", (int) fp[n]);
X	return(1);
X    }
X    fp[n] = fopen(name,"w");		/* A real file */
X    if (fp[n] == NULL) perror("zopeno");
X    if (n == ZDFILE) setbuf(fp[n],NULL); /* Make debugging file unbuffered */
X    debug(F101, " fp[n]", "", (int) fp[n]);
X    return((fp[n] != NULL) ? 1 : 0);
X}
X
X/*  Z C L O S E  --  Close the given file.  */
X
Xzclose(n) int n; {
X    if (chkfn(n) < 1) return(0);
X    if ((fp[n] != stdout) && (fp[n] != stdin)) fclose(fp[n]);
X    fp[n] = NULL;
X    return(1);
X}
X
X/*  Z C H I N  --  Get a character from the input file.  */
X
Xzchin(n) int n; {
X    int a;
X    if (chkfn(n) < 1) return(-1);
X    a = getc(fp[n]);
X    return((a == EOF) ? -1 : a & 0377);
X}
X
X/*  Z S O U T  --  Write a string to the given file, buffered.  */
X
Xzsout(n,s) int n; char *s; {
X    if (chkfn(n) < 1) return(-1);
X    fprintf(fp[n],s);
X    return(0);
X}
X
X/*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
X
Xzsoutl(n,s) int n; char *s; {
X    if (chkfn(n) < 1) return(-1);
X    fprintf(fp[n],"%s\n",s);
X    return(0);
X}
X
X/*  Z S O U T X  --  Write x characters to file, unbuffered.  */
X
Xzsoutx(n,s,x) int n, x; char *s; {
X    if (chkfn(n) < 1) return(-1);
X    return(write(fp[n]->_file,s,x));
X}
X
X
X/*  Z C H O U T  --  Add a character to the given file.  */
X
Xzchout(n,c) int n; char c; {
X    if (chkfn(n) < 1) return(-1);
X    if (n == ZSFILE)
X    	return(write(fp[n]->_file,&c,1)); /* Use unbuffered for session log */
X    else {
X    	putc(c,fp[n]);			/* Buffered for everything else */
X	return(0);
X    }
X}
X
X/*  C H K F N  --  Internal function to verify file number is ok  */
X
X/*
X Returns:
X  -1: File number n is out of range
X   0: n is in range, but file is not open
X   1: n in range and file is open
X*/
Xchkfn(n) int n; {
X    switch (n) {
X	case ZCTERM:
X	case ZSTDIO:
X	case ZIFILE:
X	case ZOFILE:
X	case ZDFILE:
X	case ZTFILE:
X	case ZPFILE:
X	case ZSFILE: break;
X	default:
X	    debug(F101,"chkfn: file number out of range","",n);
X	    fprintf(stderr,"?File number out of range - %d\n",n);
X	    return(-1);
X    }
X    return( (fp[n] == NULL) ? 0 : 1 );
X}
X
X/*  Z C H K I  --  Check if input file exists and is readable  */
X
X/*
X  Returns:
X   >= 0 if the file can be read (returns the size).
X     -1 if file doesn't exist or can't be accessed,
X     -2 if file exists but is not readable (e.g. a directory file).
X     -3 if file exists but protected against read access.
X*/
X/*
X For Berkeley Unix, a file must be of type "regular" to be readable.
X Directory files, special files, and symbolic links are not readable.
X*/
Xzchki(name) char *name; {
X    struct stat buf;
X    int x;
X
X    x = stat(name,&buf);
X    if (x < 0) {
X	debug(F111,"zchki stat fails",name,errno);
X	return(-1);
X    }
X    x = buf.st_mode & S_IFMT;		/* Isolate file format field */
X    if (x != S_IFREG) {
X	debug(F111,"zchki skipping:",name,x);
X	return(-2);
X    }
X    debug(F111,"zchki stat ok:",name,x);
X
X    if ((x = access(name,R_OK)) < 0) { 	/* Is the file accessible? */
X	debug(F111," access failed:",name,x); /* No */
X    	return(-3);			
X    } else {
X	x = buf.st_size;
X	debug(F111," access ok:",name,x); /* Yes */
X	return( (x > -1) ? x : 0 );
X    }
X}
X
X/*  Z C H K O  --  Check if output file can be created  */
X
X/*
X Returns -1 if write permission for the file would be denied, 0 otherwise.
X*/
Xzchko(name) char *name; {
X    int i, x;
X    char s[50], *sp;	
X
X    sp = s;				/* Make a copy, get length */
X    x = 0;
X    while ((*sp++ = *name++) != '\0')
X    	x++;
X    if (x == 0) return(-1);		/* If no filename, fail. */
X
X    debug(F101," length","",x);
X    for (i = x; i > 0; i--)		/* Strip filename. */
X	if (s[i-1] == '/') break;
X    
X    debug(F101," i","",i);
X    if (i == 0)				/* If no path, use current directory */
X    	strcpy(s,"./");			
X    else				/* Otherwise, use given one. */
X        s[i] = '\0';
X
X    x = access(s,W_OK);			/* Check access of path. */
X    if (x < 0) {
X	debug(F111,"zchko access failed:",s,errno);
X	return(-1);
X    } else {
X	debug(F111,"zchko access ok:",s,x);
X	return(0);
X    }
X}
X
X/*  Z D E L E T  --  Delete the named file.  */
X
Xzdelet(name) char *name; {
X    unlink(name);
X}
X
X
X/*  Z R T O L  --  Convert remote filename into local form  */
X
X/*  For UNIX, this means changing uppercase letters to lowercase.  */
X
Xzrtol(name,name2) char *name, *name2; {
X    for ( ; *name != '\0'; name++) {
X    	*name2++ = isupper(*name) ? tolower(*name) : *name;
X    }
X    *name2 = '\0';
X}
X
X
X/*  Z L T O R  --  Convert filename from local format to common form.   */
X
Xzltor(name,name2) char *name, *name2; {
X    char work[100], *cp, *pp;
X    int dc = 0;
X
X    strcpy(work,name);
X    for (cp = pp = work; *cp != '\0'; cp++) {	/* strip path name */
X    	if (*cp == '/') {
X	    pp = cp;
X	    pp++;
X	}
X	else if (islower(*cp)) *cp = toupper(*cp); /* Uppercase letters */
X	else if (*cp == '~') *cp = 'X';	/* Change tilde to 'X' */
X	else if ((*cp == '.') && (++dc > 1)) *cp = 'X'; /* & extra dots */
X    }
X    cp = name2;				/* If nothing before dot, */
X    if (*pp == '.') *cp++ = 'X';	/* insert 'X' */
X    strcpy(cp,pp);
X}    
X
X
X/*  Z C H D I R  --  Change directory  */
X
Xzchdir(dirnam) char *dirnam; {
X    char *hd;
X    if (*dirnam == '\0') hd = getenv("HOME");
X    else hd = dirnam;
X    return((chdir(hd) == 0) ? 1 : 0);
X}
X
X
X/*  Z H O M E  --  Return pointer to user's home directory  */
X
Xchar *
Xzhome() {
X    return(getenv("HOME"));
X}
X
X/*  Z X C M D -- Run a system command so its output can be read like a file */
X
Xzxcmd(comand) char *comand; {
X    int pipes[2];
X    if (pipe(pipes) != 0) return(0);	/* can't make pipe, fail */
X    if ((pid = fork()) == 0) {		/* child */
X
X/*#if BSD4*/			/* Code from Dave Tweten at AMES-NASA */
X			/* readapted to use getpwuid to find login shell */
X			/*   -- H. Fischer */
X	char *shpath, *shname, *shptr;	/* to find desired shell */
X	struct passwd *p;
X	extern struct passwd * getpwuid();
X	extern int getuid();
X	char *defShel = "/bin/sh";	/* default shell */
X/*#endif*/
X
X	close(pipes[0]);		/* close input side of pipe */
X	close(0);			/* close stdin */
X	if (open("/dev/null",0) < 0) return(0);	/* replace input by null */
X
X#ifndef UXIII
X	dup2(pipes[1],1);		/* replace stdout & stderr */
X	dup2(pipes[1],2);		/* by the pipe */
X#else
X	close(1);			/* simulate dup2 */
X	if (dup(pipes[1]) != 1 )
X	    conol("trouble duping stdout in routine zxcmd\n");
X	close(2);			/* simulate dup2 */
X	if (dup(pipes[1]) != 2 )
X	    conol("trouble duping stderr in routine zxcmd\n");
X#endif
X
X	close(pipes[1]);		/* get rid of this copy of the pipe */
X
X/**** 	shptr = shname = shpath = getenv("SHELL");  /* What shell? */
X	p = getpwuid( getuid() );	/* get login data */
X	if ( p == (struct passwd *) NULL || !*(p->pw_shell) ) shpath = defShel;
X	  else shpath = p->pw_shell;
X	shptr = shname = shpath;
X	while (*shptr != '\0') if (*shptr++ == '/') shname = shptr;
X	execl(shpath,shname,"-c",comand,0); /* Execute the command */
X
X/****	execl("/bin/sh","sh","-c",comand,0); /* Execute the command */
X
X	exit(0); }			/* just punt if it didn't work */
X
X    close(pipes[1]);			/* don't need the output side */
X    fp[ZIFILE] = fdopen(pipes[0],"r");	/* open a stream for it */
X    return(1);
X}
X
X/*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
X
Xzclosf() {
X    int wstat;
X    fclose(fp[ZIFILE]);
X    fp[ZIFILE] = NULL;
X    while ((wstat = wait(0)) != pid && wstat != -1) ;
X}
X
X/*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
X/*
X  Returns the number of files that match fn1, with data structures set up
X  so that first file (if any) will be returned by the next znext() call.
X*/
Xzxpand(fn) char *fn; {
X    fcount = fgen(fn,mtchs,MAXWLD);	/* Look up the file. */
X    if (fcount > 0) {
X	mtchptr = mtchs;		/* Save pointer for next. */
X    }
X    debug(F111,"zxpand",mtchs[0],fcount);
X    return(fcount);
X}
X
X
X/*  Z N E X T  --  Get name of next file from list created by zxpand(). */
X/*
X Returns >0 if there's another file, with its name copied into the arg string,
X or 0 if no more files in list.
X*/
Xznext(fn) char *fn; {
X    if (fcount-- > 0) strcpy(fn,*mtchptr++);
X    else *fn = '\0';
X    debug(F111,"znext",fn,fcount+1);
X    return(fcount+1);
X}
X
X
X/*  Z N E W N  --  Make a new name for the given file  */
X
Xznewn(fn,s) char *fn, **s; {
X    static char buf[100];
X    char *bp, *xp;
X    int len = 0, n = 0, d = 0, t;
X
X    bp = buf;
X    while (*fn) {
X	*bp++ = *fn++;
X	len++;
X    }
X    *bp++ = '*';			/* Put a star on the end */
X    *bp-- = '\0';
X
X    n = zxpand(buf);			/* Expand the resulting wild name */
X    
X    while (n-- > 0) {			/* Find any existing name~d files */
X	xp = *mtchptr++;
X	xp += len;
X	if (*xp == '~') {
X	    t = atoi(xp+1);
X	    if (t > d) d = t;		/* Get maximum d */
X	}
X    }
X    sprintf(bp,"~%d",d+1);		/* Make and return name~(d+1) */
X    *s = buf;
X}
X
X/* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
X
X/*
X * The path structure is used to represent the name to match.
X * Each slash-separated segment of the name is kept in one
X * such structure, and they are linked together, to make
X * traversing the name easier.
X */
X
Xstruct path {
X              char npart[MAXNAMLEN];	/* name part of path segment */
X              struct path *fwd;		/* forward ptr */
X            };
X
X#define SSPACE 2000			/* size of string-generating buffer */
Xstatic char sspace[SSPACE];             /* buffer to generate names in */
Xstatic char *freeptr,**resptr;         	/* copies of caller's arguments */
Xstatic int remlen;                      /* remaining length in caller's array*/
Xstatic int numfnd;                      /* number of matches found */
X
X/*
X * splitpath:
X *  takes a string and splits the slash-separated portions into
X *  a list of path structures.  Returns the head of the list.  The
X *  structures are allocated by malloc, so they must be freed.
X *  Splitpath is used internally by the filename generator.
X *
X * Input: A string.
X * Returns: A linked list of the slash-separated segments of the input.
X */
X
Xstruct path *
Xsplitpath(p)
Xchar *p;
X{
X struct path *head,*cur,*prv;
X int i;
X head = prv = NULL;
X if (*p == '/') p++;            /* skip leading slash */
X while (*p != '\0')
X {
X   cur = (struct path *) malloc(sizeof (struct path));
X   cur -> fwd = NULL;
X   if (head == NULL) head = cur;
X   else prv -> fwd = cur;       /* link into chain */
X   prv = cur;
X   for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++)
X     cur -> npart[i] = *p++;
X   cur -> npart[i] = '\0';      /* end this segment */
X   if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++;
X   if (*p == '/') p++;
X }
X return(head);
X}
X
X/*
X * fgen:
X *  This is the actual name generator.  It is passed a string,
X *  possibly containing wildcards, and an array of character pointers.
X *  It finds all the matching filenames and stores them into the array.
X *  The returned strings are allocated from a static buffer local to
X *  this module (so the caller doesn't have to worry about deallocating
X *  them); this means that successive calls to fgen will wipe out
X *  the results of previous calls.  This isn't a problem here
X *  because we process one wildcard string at a time.
X *
X * Input: a wildcard string, an array to write names to, the
X *        length of the array.
X * Returns: the number of matches.  The array is filled with filenames
X *          that matched the pattern.  If there wasn't enough room in the
X *	    array, -1 is returned.
X * By: Jeff Damens, CUCCA, 1984.
X */
X
Xfgen(pat,resarry,len)
Xchar *pat,*resarry[];
Xint len;
X{
X struct path *head;
X char scratch[100],*sptr;
X head = splitpath(pat);
X if (*pat == '/')
X {
X  scratch[0] = '/';
X  sptr = scratch+1;
X }
X else
X {
X  strcpy(scratch,"./");
X  sptr = scratch+2;
X }					/* init buffer correctly */
X numfnd = 0;                            /* none found yet */
X freeptr = sspace;			/* this is where matches are copied */
X resptr = resarry;			/* static copies of these so*/
X remlen = len;				/* recursive calls can alter them */
X traverse(head,scratch,sptr);		/* go walk the directory tree */
X for (; head != NULL; head = head -> fwd)
X   free(head);				/* return the path segments */
X return(numfnd);			/* and return the number of matches */
X}
X
X/* traverse:
X *  Walks the directory tree looking for matches to its arguments.
X *  The algorithm is, briefly:
X *   If the current pattern segment contains no wildcards, that
X *   segment is added to what we already have.  If the name so far
X *   exists, we call ourselves recursively with the next segment
X *   in the pattern string; otherwise, we just return.
X *
X *   If the current pattern segment contains wildcards, we open the name
X *   we've accumulated so far (assuming it is really a directory), then read 
X *   each filename in it, and, if it matches the wildcard pattern segment, add
X *   that filename to what we have so far and call ourselves recursively on the
X *   next segment.
X *
X *   Finally, when no more pattern segments remain, we add what's accumulated
X *   so far to the result array and increment the number of matches.
X *
X * Input: a pattern path list (as generated by splitpath), a string
X *	  pointer that points to what we've traversed so far (this
X *	  can be initialized to "/" to start the search at the root
X *	  directory, or to "./" to start the search at the current
X *	  directory), and a string pointer to the end of the string
X *	  in the previous argument.
X * Returns: nothing.
X */
Xtraverse(pl,sofar,endcur)
Xstruct path *pl;
Xchar *sofar,*endcur;
X{
X#ifdef BSD4
X DIR *fd;
X struct direct *dirbuf;
X#else
X int fd;
X struct direct dir_entry;
X struct direct *dirbuf = &dir_entry;
X#endif
X struct stat statbuf;
X if (pl == NULL)
X {
X  *--endcur = '\0';                    /* end string, overwrite trailing / */
X  addresult(sofar);
X  return;
X }
X if (!iswild(pl -> npart))
X {
X  strcpy(endcur,pl -> npart);
X  endcur += strlen(pl -> npart);
X  *endcur = '\0';                     	/* end current string */
X  if (stat(sofar,&statbuf) == 0)	/* if current piece exists */
X  {
X      *endcur++ = '/';                  /* add slash to end */
X      *endcur = '\0';			/* and end the string */
X      traverse(pl -> fwd,sofar,endcur);
X  }
X  return;
X }
X/* cont'd... */
X
X/*...traverse, cont'd */
X
X/* segment contains wildcards, have to search directory */
X *endcur = '\0';                        	/* end current string */
X if (stat(sofar,&statbuf) == -1) return;   	/* doesn't exist, forget it */
X if ((statbuf.st_mode & S_IFDIR) == 0) return;  /* not a directory, skip */
X#ifdef BSD4
X if ((fd = opendir(sofar)) == NULL) return;  	/* can't open, forget it */
X while (dirbuf = readdir(fd))
X#else
X if ((fd = open(sofar,O_RDONLY)) < 0) return;  	/* can't open, forget it */
X while ( read(fd,dirbuf,sizeof dir_entry) )
X#endif
X  if (dirbuf->d_ino != 0 && match(pl -> npart,dirbuf->d_name)) {
X    char *eos;
X    strcpy(endcur,dirbuf->d_name);
X    eos = endcur + strlen(dirbuf->d_name);
X    *eos = '/';                    /* end this segment */
X    traverse(pl -> fwd,sofar,eos+1);
X  }
X#ifdef BSD4
X closedir(fd);
X#else
X close(fd);
X#endif
X}
X
X/*
X * addresult:
X *  Adds a result string to the result array.  Increments the number
X *  of matches found, copies the found string into our string
X *  buffer, and puts a pointer to the buffer into the caller's result
X *  array.  Our free buffer pointer is updated.  If there is no
X *  more room in the caller's array, the number of matches is set to -1.
X * Input: a result string.
X * Returns: nothing.
X */
X
Xaddresult(str)
Xchar *str;
X{
X int l;
X if (strncmp(str,"./",2) == 0) str += 2;
X if (--remlen < 0) {
X  numfnd = -1;
X  return;
X }
X l = strlen(str) + 1;			/* size this will take up */
X if ((freeptr + l) > &sspace[SSPACE]) {
X    numfnd = -1;			/* do not record if not enough space */
X    return;
X  }
X strcpy(freeptr,str);
X *resptr++ = freeptr;
X freeptr += l;
X numfnd++;
X}
X
Xiswild(str)
Xchar *str;
X{
X char c;
X while ((c = *str++) != '\0')
X   if (c == '*' || c == '?') return(1);
X return(0);
X}
X
X/*
X * match:
X *  pattern matcher.  Takes a string and a pattern possibly containing
X *  the wildcard characters '*' and '?'.  Returns true if the pattern
X *  matches the string, false otherwise.
X * by: Jeff Damens, CUCCA
X *
X * Input: a string and a wildcard pattern.
X * Returns: 1 if match, 0 if no match.
X */
X
Xmatch(pattern,string) char *pattern,*string; {
X    char *psave,*ssave;			/* back up pointers for failure */
X    psave = ssave = NULL;
X    while (1) {
X	for (; *pattern == *string; pattern++,string++)  /* skip first */
X	    if (*string == '\0') return(1);	/* end of strings, succeed */
X	if (*string != '\0' && *pattern == '?') {
X	    pattern++;			/* '?', let it match */
X	    string++;
X	} else if (*pattern == '*') {	/* '*' ... */
X	    psave = ++pattern;		/* remember where we saw it */
X	    ssave = string;		/* let it match 0 chars */
X	} else if (ssave != NULL && *ssave != '\0') {	/* if not at end  */
X  					/* ...have seen a star */
X	    string = ++ssave;		/* skip 1 char from string */
X	    pattern = psave;		/* and back up pattern */
X	} else return(0);		/* otherwise just fail */
X    }
X}
!FUNKY!STUFF!



More information about the Comp.sources.unix mailing list