xref: /original-bsd/local/toolchest/ksh/sh/io.c (revision b0e4450e)
1 /* @(#)io.c	1.1 */
2 /*
3  * UNIX shell
4  *
5  * S. R. Bourne
6  * Rewritten by David Korn
7  * AT&T Bell Laboratories
8  *
9  */
10 
11 #include	<errno.h>
12 #if BSD
13 #include	<sys/types.h>
14 #include	<sys/stat.h>
15 #include	<sys/ioctl.h>
16 # ifdef BSD_4_2
17 # include	<fcntl.h>
18 # endif	/* BSD_4_2 */
19 # define CAST	(char*)
20 #else
21 # ifdef VENIX
22 # include	<sys/types.h>
23 # include	<sys/stat.h>
24 # define CAST	(char*)
25 # else
26 # include	<fcntl.h>
27 # define CAST	(unsigned char*)
28 # endif	/* VENIX */
29 #endif	/* BSD */
30 #include	"defs.h"
31 #include	"flags.h"
32 #include	"sym.h"
33 #include	"io.h"
34 #include	"shtype.h"
35 #ifndef F_DUPFD
36 #define	F_DUPFD	0
37 #define NO_FCNTL 1
38 #endif	/* F_DUPFD */
39 
40 /* This module defines the following routines */
41 FILE *fdopen();
42 FILE *create();
43 FILE *chkrdwr();
44 int	ispipe();
45 void	sync_io();
46 void	settemp();
47 void	swap_iodoc_nm();
48 void	initf();
49 void	restore();
50 int	estabf();
51 void	chkpipe();
52 
53 /* This module references the following externals */
54 extern STKPTR locstak(),cpystak();
55 extern void chkpr();
56 extern void failed();
57 extern void free();
58 extern char *heap();
59 extern char *itos();
60 extern long lseek();
61 extern char *movstr();
62 extern void p_flush();
63 extern char *strrchr();
64 
65 
66 static int qtrim();
67 static int serial;
68 static char *temp_suffix;
69 static struct filesave fdmap[MAXFILES];
70 
71 
72 /* ======== input output and file copying ======== */
73 
74 /*
75  * initialize temp file names
76  */
settemp(pid)77 void settemp(pid)
78 char *pid;
79 {
80 	register char *sp = movstr(pid,tmpout+7);
81 	*sp++ = '.';
82 	temp_suffix = sp;
83 	serial = 0;
84 	states &= ~NO_TMP;
85 }
86 
87 /*
88  * set up a fileblk associated with the stream fd
89  */
90 
initf(fd)91 void	initf(fd)
92 FILE	*fd;
93 {
94 	register SHFILE f=standin;
95 	f->fdes=fd;
96 	f->feval=0;
97 	f->flin=1;
98 }
99 
100 /*
101  * set up an I/O stream that will cause reading from a string
102  */
103 
estabf(s,fd)104 int	estabf(s,fd)
105 register FILE *fd;
106 register char *s;
107 {
108 	register SHFILE f;
109 	(f=standin)->fdes = fd;
110 	fd->_flag = _IOREAD;
111 	fd->_base = fd->_ptr = CAST s;
112 	fd->_file = F_STRING;
113 	fd->_cnt = F_INFINITE;
114 	f->flin = 1;
115 	fd->_flag|=(s==0?_IOEOF:0);
116 	return(feof(fd));
117 }
118 
push(af)119 push(af)
120 SHFILE af;
121 {
122 	register SHFILE f;
123 	(f=af)->fstak=standin;
124 	f->feval=0;
125 	standin=f;
126 }
127 
pop(flag)128 pop(flag)
129 register int flag;
130 {
131 	register SHFILE f;
132 	register FILE *fd;
133 	register int fno;
134 	if((f=standin)->fstak)
135 	{
136 		fd = f->fdes;
137 		fno = fileno(fd);
138 		if(flag==0 && fno>0 && fno!=F_STRING && fno!=INIO && fd!=cpipe[INPIPE])
139 			closefd(fd);
140 		standin=f->fstak;
141 		return(1);
142 	}
143 	return(0);
144 }
145 
146 /*
147  * sync_io - flushes output buffer and positions stdin if necessary
148  */
149 
sync_io()150 void sync_io()
151 {
152 	register FILE *fp = stdin;
153 	p_flush();
154 	/* position back the read-ahead characters */
155 	if(fp->_cnt)
156 	{
157 		lseek(fileno(fp),-((long)(fp->_cnt)),1);
158 		setbuf(fp,(char*)fp->_base);
159 	}
160 }
161 
162 
163 /*
164  * This non-standard version of fdopen makes stream numbers
165  * correspond to file unit numbers
166  */
167 
fdopen(fd,mode)168 FILE *fdopen(fd, mode)
169 register int	fd;
170 register char *mode;
171 {
172 	register FILE *iop;
173 	if(fd < 0)
174 		return(NULL);
175 	iop = file_fd(fd);
176 	iop->_cnt = 0;
177 	iop->_file = fd;
178 	iop->_base = NULL;
179 	switch(*mode)
180 	{
181 
182 		 case 'r':
183 			iop->_flag |= _IOREAD;
184 			break;
185 		 case 'a':
186 			lseek(fd, 0L, 2);
187 			/* No break */
188 		 case 'w':
189 			iop->_flag |= _IOWRT;
190 			break;
191 		 default:
192 			return(NULL);
193 		}
194 
195 	if(mode[1] == '+')
196 	{
197 		 iop->_flag &= ~(_IOREAD | _IOWRT);
198 		 iop->_flag |= _IORW;
199 		}
200 	return(iop);
201 }
202 
chkpipe(pv)203 void	chkpipe(pv)
204 FILE	*pv[];
205 {
206 	int ipv[2];
207 	if(pipe(ipv)<0 || ipv[INPIPE]<0 || ipv[OTPIPE]<0)
208 		error(piperr);
209 	pv[INPIPE] = fdopen(ipv[INPIPE],"r");
210 	pv[OTPIPE] = fdopen(ipv[OTPIPE],"w");
211 }
212 
213 /*
214  * close a pipe
215  */
216 
pipe_close(pv)217 void pipe_close(pv)
218 register FILE *pv[];
219 {
220 	if(pv[INPIPE])
221 		fclose(pv[INPIPE]);
222 	if(pv[OTPIPE])
223 		fclose(pv[OTPIPE]);
224 }
225 
226 /*
227  * Open a stream for reading
228  * On failure, print message.
229  */
230 
chkopen(name)231 FILE *chkopen(name)
232 register char *name;
233 {
234 	register FILE	*fd;
235 	if((fd=fdopen(open(name,0),"r"))==NULL)
236 		failed(name,badopen);
237 	return(fd);
238 }
239 
240 
241 /*
242  * given a file stream f1, move it to a new file stream with file number
243  * f2.  If f2 is open then it is closed first.
244  * If the MARK bit not set on f2, then close on exec will be set for f2>2
245  * The original stream is closed.
246  * File numbers greater than 2 are marked close on exec if frenumber is
247  *  invoked by a parent shell.
248  *  The new file descriptor is returned;
249  */
250 
frenumber(f1,f2)251 FILE *frenumber(f1,f2)
252 FILE *f1;
253 register int f2;
254 {
255 	register FILE *fd;
256 	register int flag = (f2&MARK);
257 	register int fs=0;
258 	register char *type;
259 	f2 &= ~MARK;
260 	if(f2>2 && flag==0)
261 		fs = 1;
262 	fd = file_fd(f2);
263 	if(fileno(f1)!=f2)
264 	{
265 		int fno;
266 		if(fs==0)
267 			fs = fcntl(f2,1,0);
268 		if(fisopen(fd))
269 		{
270 			closefd(fd);
271 		}
272 		else
273 			close(f2);
274 		fno = fcntl(fileno(f1),0,f2);
275 		if(fno < 0)
276 			error(badfile);
277 		flag = f1->_flag;
278 		if(flag&_IORW)
279 			type="w+";
280 		else
281 			type = (f1->_flag&_IOREAD?"r":"w");
282 		fclose(f1);
283 		fd = fdopen(f2,type);
284 #ifdef apollo
285 		fd->_file = fno;
286 #endif	/* apollo */
287 		fd->_flag = flag;
288 		if(fd==output)
289 			setbuf(fd,(char*)_sobuf);
290 		else if(fd==input && (fd->_flag&_IONBF)==0)
291 			setbuf(fd,(char*)_sibuf);
292 		else
293 		{
294 			fd->_cnt = f1->_cnt;
295 			fd->_ptr = f1->_ptr;
296 			fd->_base = f1->_base;
297 		}
298 		setbuf(f1,NIL);
299 		if(f2==0)
300 			ioset |= 1;
301 	}
302 	if(fs==1)
303 #ifdef BSD
304 		ioctl(f2, FIOCLEX, NULL);
305 #else
306 		fcntl(f2,2,1);
307 #endif	/* BSD */
308 	return(fd);
309 }
310 
tmp_open(fname)311 FILE *tmp_open(fname)
312 register char *fname;
313 {
314 	register int maxtry = 10;
315 	register char *tmp_name = tmpout;
316 	register FILE *fd;
317 	if(states&NO_TMP)
318 		settemp(itos(getpid()));
319 	do
320 	{
321 		movstr(itos(++serial),temp_suffix);
322 	}
323 	while((fd=create(tmp_name))== NULL && maxtry--);
324 	if(fname)
325 	{
326 		movstr(tmp_name,fname);
327 		if((fd = chkrdwr(tmp_name,fd))==NULL)
328 			failed(tmp_name,badcreate);
329 	}
330 	return(fd);
331 }
332 
333 /*
334  * create the file named s and return an open stream to it
335  */
336 
create(s)337 FILE *create(s)
338 char *s;
339 {
340 	register FILE *fd;
341 	fd = fdopen(creat(s,0666),"w+");
342 	return(fd);
343 }
344 
345 /*
346  * close file stream and reopen for reading and writing
347  */
348 
chkrdwr(name,fd)349 FILE *chkrdwr(name,fd)
350 register char *name;
351 register FILE *fd;
352 {
353 	if(fd!=NULL)
354 	{
355 		fclose(fd);
356 		fd = fdopen(open(name,2),"w+");
357 	}
358 	return(fd);
359 }
360 
closefd(fd)361 closefd(fd)
362 register FILE *fd;
363 {
364 
365 	/* reposition seek pointer if necessary */
366 	if((fd->_flag&_IOREAD) && fd->_cnt)
367 		lseek(fileno(fd),-((long)(fd->_cnt)),1);
368 	free(fd->_base);
369 	fclose(fd);
370 	setbuf(fd,NIL);
371 }
372 
copy(ioparg)373 copy(ioparg)
374 IOPTR	ioparg;
375 {
376 	register char c = '\n';
377 	register char *clinep;
378 	register IOPTR iop;
379 	register FILE	*fd;
380 	BOOL 	nosubst;
381 	char *ends,*cline,obuff[BUFSIZ];
382 	if(iop=ioparg)
383 	{
384 		int stripflg = iop->iofile&IOSTRIP;
385 		register nlflg = stripflg;
386 		copy(iop->iolst);
387 		ends=iop->ioname;
388 		/* check for and strip quoted characters in ends */
389 		nosubst = qtrim(ends);
390 		if(nosubst)
391 			iop->iofile &= ~IODOC;
392 		fd = tmp_open(NIL);
393 		iop->ioname = (char*)cpystak(tmpout);
394 		setbuf(fd,obuff);
395 		iop->iolst=iotemp; iotemp=iop;
396 		cline=(char*)locstak();
397 		if(stripflg)
398 			while(*ends=='\t')
399 				ends++;
400 		clinep = cline++;
401 		*cline = 0;
402 		do
403 		{
404 			if(c=='\n')
405 			{
406 				*clinep = 0;
407 				if(eq(ends,cline))
408 					break;
409 				chkpr(0);
410 				*clinep++ = '\n';
411 				*clinep = 0;
412 				fputs(cline,fd);
413 				clinep = cline;
414 				nlflg = stripflg;
415 			}
416 			else if(c=='\t' && nlflg)
417 				;
418 			else
419 			{
420 				*clinep++ = c;
421 				nlflg = 0;
422 			}
423 		}
424 		while(c=(nosubst?readc():nextc()));
425 		closefd(fd);
426 	}
427 }
428 
429 /*
430  * trim quotes and the escapes
431  * returns non-zero if string is quoted 0 otherwise
432  */
433 
qtrim(string)434 static int qtrim(string)
435 char *string;
436 {
437 	register char *sp = string;
438 	register char *dp = sp;
439 	register int c;
440 	register int quote = 0;
441 	while(c= *sp++)
442 	{
443 		if(c == ESCAPE)
444 		{
445 			quote = 1;
446 			c = *sp++;
447 		}
448 		else if(c == '"')
449 		{
450 			quote = 1;
451 			continue;
452 		}
453 		*dp++ = c;
454 	}
455 	*dp = 0;
456 	return(quote);
457 }
458 
459 /*
460  * short version of fputs
461  */
462 
fputs(s,fd)463 int fputs(s,fd)
464 register char *s;
465 register FILE *fd;
466 {
467 	register char c;
468 	if(s==NULL || fd==NULL)
469 		return(EOF);
470 	while(c = *s++)
471 		putc(c,fd);
472 	return(0);
473 }
474 
475 
476 /*
477  * create a link to iodoc for child process to use
478  */
479 
link_iodocs(i)480 link_iodocs(i)
481 register struct ionod	*i;
482 {
483 	while(i)
484 	{
485 		/* generate a tempory file name */
486 		fclose(tmp_open(NIL));
487 		unlink(tmpout);
488 		free(i->iolink);
489 		i->iolink = heap(tmpout);
490 		link(i->ioname, i->iolink);
491 		i = i->iolst;
492 	}
493 }
494 
495 
496 /*
497  * rename the file with the link name of the parent
498  */
499 
swap_iodoc_nm(i)500 void	swap_iodoc_nm(i)
501 register struct ionod	*i;
502 {
503 	while(i)
504 	{
505 		free(i->ioname);
506 		i->ioname = i->iolink;
507 		i->iolink = 0;
508 		i = i->iolst;
509 	}
510 }
511 
512 
513 /*
514  * copy file fd into a save place
515  */
516 
savefd(fd,oldtop)517 savefd(fd,oldtop)
518 register int fd;
519 {
520 	register int	f = topfd;
521 	register FILE *f1 = file_fd(fd);
522 	/* see if already saved, only save once */
523 	while(f > oldtop)
524 	{
525 		if(fdmap[--f].org_fd == fd)
526 			return;
527 	}
528 	if(fiswrite(f1))
529 		fflush(f1);
530 	else if(f1==stdin)
531 		sync_io();
532 	f = fcntl(fd, F_DUPFD, USERIO);
533 	if(topfd >= MAXFILES)
534 		error(nomorefiles);
535 	if(f >= 0)
536 	{
537 		*(file_fd(f)) = *f1;
538 		setbuf(f1,NIL);
539 	}
540 	fdmap[topfd].org_fd = fd;
541 	fdmap[topfd++].dup_fd = f;
542 	return;
543 }
544 
545 
546 /*
547  *  restore saved file descriptors from <last> on
548  */
549 
restore(last)550 void	restore(last)
551 register int	last;
552 {
553 	register int 	i;
554 	register int	dupfd;
555 
556 	for (i = topfd - 1; i >= last; i--)
557 	{
558 		if ((dupfd = fdmap[i].dup_fd) > 0)
559 		{
560 			(file_fd(dupfd))->_file = dupfd;
561 			frenumber(file_fd(dupfd), fdmap[i].org_fd);
562 		}
563 		else
564 			fclose(file_fd(fdmap[i].org_fd));
565 	}
566 	topfd = last;
567 }
568 
569 
570 /*
571  * This routine returns 1 if fd corresponds to a pipe, 0 otherwise.
572  */
573 
ispipe(fd)574 int ispipe(fd)
575 FILE *fd;
576 {
577 	register int fno = fileno(fd);
578 	if(lseek(fno,0L,1)>=0)
579 		return(0);
580 	if(errno==ESPIPE)
581 		return(!isatty(fno));
582 #ifdef BSD
583 	/* This may be a bug in lseek */
584 	else if(errno==EINVAL)
585 		return(1);
586 #endif /* BSD */
587 	else
588 		return(0);
589 }
590 
591 
592 #if ESH || VSH
593 /*
594  * Stripped down version of _filbuf from standard I/O library
595  */
596 
_filbuf(iop)597 _filbuf(iop)
598 register FILE *iop;
599 {
600 	register unsigned state = states;
601 	unsigned char cc;
602 	register int syncread;
603 
604 	if (iop->_flag & _IORW)
605 		iop->_flag |= _IOREAD;
606 
607 	if ((iop->_flag&_IOREAD) == 0)
608 		return(EOF);
609 	if(fnobuff(iop))
610 	{
611 		/* unbuffered reads needed for pipes */
612 		p_flush();
613 		iop->_cnt = read(fileno(iop),(char*)(&cc),1);
614 		if(iop->_cnt>0)
615 			{
616 				iop->_cnt--;
617 				return(cc);
618 			}
619 		goto skip;
620 	}
621 	syncread = ((state&PROMPT) && iop==input && (standin->fstak==0||(state&RWAIT)));
622 #ifdef ESH
623 	if(is_option(EMACS|GMACS) && syncread)
624 		iop->_cnt = hread(fileno(iop), (char*)iop->_base, BUFSIZ);
625 	else
626 #endif	/* ESH */
627 #ifdef VSH
628 	if(is_option(EDITVI) && syncread)
629 		iop->_cnt = vread(fileno(iop), (unsigned char*)iop->_base, BUFSIZ);
630 	else
631 #endif	/* VSH */
632 		{
633 			/* flush before a read */
634 			if(syncread)
635 				p_flush();
636 			iop->_cnt = read(fileno(iop), (char*)iop->_base, BUFSIZ);
637 		}
638 	iop->_ptr = iop->_base;
639 	skip:
640 	if (--iop->_cnt < 0)
641 	{
642 		if (iop->_cnt == -1)
643 		{
644 			iop->_flag |= _IOEOF;
645 			if (iop->_flag & _IORW)
646 				iop->_flag &= ~_IOREAD;
647 		}
648 		else
649 			iop->_flag |= _IOERR;
650 		iop->_cnt = 0;
651 		return(-1);
652 	}
653 	return(*iop->_ptr++&STRIP);
654 }
655 #endif
656 
657 
658 #ifdef NO_FCNTL
fcntl(f1,type,arg)659 static int fcntl(f1,type,arg)
660 register int arg;
661 {
662 	struct stat statbuf;
663 	if(type==F_DUPFD)
664 	{
665 		register int fd;
666 		/* find first non-open file */
667 		while(arg < _NFILE &&  (fstat(arg,&statbuf)>=0))
668 			arg++;
669 		if(arg >= _NFILE)
670 			return(-1);
671 		fd = dup(f1|DUPFLG,arg);
672 		return(fd);
673 	   }
674 	else
675 		return(0);
676 }
677 #endif	/* NO_FCNTL */
678 
679 #if u370 || uts
680 
681 extern int isatty();
682 extern unsigned char _smbuf[][_SBFSIZ];
683 
setbuf(iop,buf)684 void setbuf(iop, buf)
685 register FILE *iop;
686 char	*buf;
687 {
688 	register int fno = fileno(iop);  /* file number */
689 
690 	if(iop->_base != NULL && iop->_flag & _IOMYBUF)
691 		free((char*)iop->_base);
692 	iop->_flag &= ~(_IOMYBUF | _IONBF | _IOLBF);
693 	if((iop->_base = (unsigned char*)buf) == NULL)
694 	{
695 		iop->_flag |= _IONBF; /* file unbuffered except in fastio */
696 
697 			_bufend(iop) = (iop->_base = _smbuf[fno]) + _SBFSIZ;
698 	}
699 	else
700 	{  /* regular buffered I/O, standard buffer size */
701 		_bufend(iop) = iop->_base + BUFSIZ;
702 		if (isatty(fno))
703 			iop->_flag |= _IOLBF;
704 	}
705 	iop->_ptr = iop->_base;
706 	iop->_cnt = 0;
707 }
708 #endif	/* u370 */
709 
710 #ifdef INT16
711 /*
712  * special version of fread for to save space
713  * only works if count is 1
714  */
715 
fread(ptr,size,count,iop)716 fread(ptr,size,count,iop)
717 register char *ptr;
718 unsigned size,count;
719 register FILE *iop;
720 {
721 	register int c;
722 	do
723 	{
724 		if((c=getc(iop))>=0)
725 			*ptr++ = c;
726 		else
727 			return(0);
728 	}
729 	while(--size);
730 	return(1);
731 }
732 #endif	/* INT16 */
733 
734 #ifdef VENIX
getppid()735 int getppid()
736 {
737 	return(1);
738 }
739 #endif	/* VENIX */
740 
741 #ifdef _N_STATIC_IOBS
742 /*  ULTRIX doesn't have complete _iob */
743 FILE	_myiob[FCIO+1- _N_STATIC_IOBS];
744 
file_fd(n)745 FILE	*file_fd(n)
746 {
747 	if(n < _N_STATIC_IOBS)
748 		return(&_iob[n]);
749 	else
750 		return(&_myiob[n- _N_STATIC_IOBS]);
751 }
752 #endif /* _N_STATIC_IOBS */
753