Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / ksh93 / sh / io.c
1 /* $XConsortium: io.c /main/3 1995/11/01 16:48:07 rswiston $ */
2 /***************************************************************
3 *                                                              *
4 *                      AT&T - PROPRIETARY                      *
5 *                                                              *
6 *        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF        *
7 *                    AT&T BELL LABORATORIES                    *
8 *         AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN         *
9 *            ACCORDANCE WITH APPLICABLE AGREEMENTS             *
10 *                                                              *
11 *                Copyright (c) 1995 AT&T Corp.                 *
12 *              Unpublished & Not for Publication               *
13 *                     All Rights Reserved                      *
14 *                                                              *
15 *       The copyright notice above does not evidence any       *
16 *      actual or intended publication of such source code      *
17 *                                                              *
18 *               This software was created by the               *
19 *           Advanced Software Technology Department            *
20 *                    AT&T Bell Laboratories                    *
21 *                                                              *
22 *               For further information contact                *
23 *                    {research,attmail}!dgk                    *
24 *                                                              *
25 ***************************************************************/
26
27 /* : : generated by proto : : */
28
29 #if !defined(__PROTO__)
30 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
31 #if defined(__cplusplus)
32 #define __MANGLE__      "C"
33 #else
34 #define __MANGLE__
35 #endif
36 #define __STDARG__
37 #define __PROTO__(x)    x
38 #define __OTORP__(x)
39 #define __PARAM__(n,o)  n
40 #if !defined(__STDC__) && !defined(__cplusplus)
41 #if !defined(c_plusplus)
42 #define const
43 #endif
44 #define signed
45 #define void            int
46 #define volatile
47 #define __V_            char
48 #else
49 #define __V_            void
50 #endif
51 #else
52 #define __PROTO__(x)    ()
53 #define __OTORP__(x)    x
54 #define __PARAM__(n,o)  o
55 #define __MANGLE__
56 #define __V_            char
57 #define const
58 #define signed
59 #define void            int
60 #define volatile
61 #endif
62 #if defined(__cplusplus) || defined(c_plusplus)
63 #define __VARARG__      ...
64 #else
65 #define __VARARG__
66 #endif
67 #if defined(__STDARG__)
68 #define __VA_START__(p,a)       va_start(p,a)
69 #else
70 #define __VA_START__(p,a)       va_start(p)
71 #endif
72 #endif
73 #include        "defs.h"
74 #include        <fcin.h>
75 #include        <ls.h>
76 #if !defined(va_start)
77 #if defined(__STDARG__)
78 #include <stdarg.h>
79 #else
80 #include <varargs.h>
81 #endif
82 #endif
83
84 #include        "variables.h"
85 #include        "io.h"
86 #include        "jobs.h"
87 #include        "shnodes.h"
88 #include        "history.h"
89 #include        "edit.h"
90 #include        "timeout.h"
91 #include        "FEATURE/externs"
92 #include        "FEATURE/dynamic"
93 #include        "FEATURE/poll"
94
95 #ifdef  FNDELAY
96 #   ifdef EAGAIN
97 #       if EAGAIN!=EWOULDBLOCK
98 #           undef EAGAIN
99 #           define EAGAIN       EWOULDBLOCK
100 #       endif
101 #   else
102 #       define EAGAIN   EWOULDBLOCK
103 #   endif /* EAGAIN */
104 #   ifndef O_NONBLOCK
105 #       define O_NONBLOCK       FNDELAY
106 #   endif /* !O_NONBLOCK */
107 #endif  /* FNDELAY */
108 #define RW_ALL  (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
109
110 static __V_     *timeout;
111
112 #if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in)
113 #   include <sys/socket.h>
114 #   include <netinet/in.h>
115     static int str2inet __PROTO__((const char*, struct sockaddr_in*));
116 #   define SOCKET       1
117 #else
118 #   undef SOCKET
119 #endif
120
121 struct fdsave
122 {
123         int     orig_fd;        /* original file descriptor */
124         int     save_fd;        /* saved file descriptor */
125 };
126
127
128 static int      eval_exceptf __PROTO__((Sfio_t*, int, Sfdisc_t*));
129 static int      piperead __PROTO__((Sfio_t*, __V_*, int, Sfdisc_t*));
130 static int      slowread __PROTO__((Sfio_t*, __V_*, int, Sfdisc_t*));
131 static int      slowexcept __PROTO__((Sfio_t*, int, Sfdisc_t*));
132 static int      pipeexcept __PROTO__((Sfio_t*, int, Sfdisc_t*));
133 static int      io_prompt __PROTO__((int));
134 static int      io_heredoc __PROTO__((register struct ionod*));
135 static void     sftrack __PROTO__((Sfio_t*,int,int));
136 static int      tee_write __PROTO__((Sfio_t*,const __V_*,int,Sfdisc_t*));
137 static const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL};
138 static Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL};
139 static Sfio_t *subopen __PROTO__((Sfio_t*, off_t, long));
140 static int      subread __PROTO__((Sfio_t*, __V_*, int, Sfdisc_t*));
141 static int      subexcept __PROTO__((Sfio_t*, int, Sfdisc_t*));
142 static const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 };
143
144 struct subfile
145 {
146         Sfdisc_t        disc;
147         Sfio_t          *oldsp;
148         off_t           offset;
149         long            size;
150         long            left;
151 };
152
153 static struct fdsave    *filemap;
154 static short            filemapsize;
155
156 /* ======== input output and file copying ======== */
157
158 void sh_ioinit __PARAM__((void), ()){
159         register int n;
160         filemapsize = 8;
161         filemap = (struct fdsave*)malloc(8*sizeof(struct fdsave));
162 #ifdef SHOPT_FASTPIPE
163         n = sh.lim.open_max+2;
164 #else
165         n = sh.lim.open_max;
166 #endif /* SHOPT_FASTPIPE */
167         sh.fdstatus = (unsigned char*)malloc((unsigned)n);
168         memset((char*)sh.fdstatus,0,n);
169         sh.fdptrs = (int**)malloc(n*sizeof(int*));
170         memset((char*)sh.fdptrs,0,n*sizeof(int*));
171         sh.sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*));
172         memset((char*)sh.sftable,0,n*sizeof(Sfio_t*));
173         sh.sftable[0] = sfstdin;
174         sh.sftable[1] = sfstdout;
175         sh.sftable[2] = sfstderr;
176         sfnotify(sftrack);
177         sh_iostream(0);
178         /* all write steams are in the same pool and share outbuff */
179         sh.outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw");  /* pool identifier */
180         sh.outbuff = (char*)malloc(IOBSIZE);
181         sh.errbuff = (char*)malloc(IOBSIZE/4);
182         sfsetbuf(sfstderr,sh.errbuff,IOBSIZE/4);
183         sfsetbuf(sfstdout,sh.outbuff,IOBSIZE);
184         sfpool(sfstdout,sh.outpool,SF_WRITE);
185         sfpool(sfstderr,sh.outpool,SF_WRITE);
186         sfset(sfstdout,SF_LINE,0);
187 }
188
189 /*
190  * create or initialize a stream corresponding to descriptor <fd>
191  * a buffer with room for a sentinal is allocated for a read stream.
192  * A discipline is inserted when read stream is a tty or a pipe
193  * For output streams, the buffer is set to sh.output and put into
194  * the sh.outpool synchronization pool
195  */
196 Sfio_t *sh_iostream __PARAM__((register int fd), (fd)) __OTORP__(register int fd;){
197         register Sfio_t *iop;
198         register int status = sh_iocheckfd(fd);
199         register int flags = SF_WRITE;
200         char *bp;
201         int size;
202 #ifdef SHOPT_FASTPIPE
203         if(fd>=sh.lim.open_max)
204                 return(sh.sftable[fd]);
205 #endif /* SHOPT_FASTPIPE */
206         if(status==IOCLOSE)
207         {
208                 switch(fd)
209                 {
210                     case 0:
211                         return(sfstdin);
212                     case 1:
213                         return(sfstdout);
214                     case 2:
215                         return(sfstderr);
216                 }
217                 return(NIL(Sfio_t*));
218         }
219         if(status&IOREAD)
220         {
221                 size=roundof(IOBSIZE+1,sizeof(__V_*)) + sizeof(Sfdisc_t);
222                 if(!(bp = (char *)malloc(size)))
223                         return(NIL(Sfio_t*));
224                 flags |= SF_READ;
225                 if(!(status&IOWRITE))
226                         flags &= ~SF_WRITE;
227         }
228         else
229                 bp = sh.outbuff;
230         if(status&IODUP)
231                 flags |= SF_SHARE|SF_PUBLIC;
232         if((iop = sh.sftable[fd]) && sffileno(iop)>=0)
233                 sfsetbuf(iop, bp, IOBSIZE);
234         else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags)))
235                 return(NIL(Sfio_t*));
236         if(status&IOREAD)
237         {
238                 Sfdisc_t *dp;
239                 sfset(iop,SF_MALLOC,1);
240                 {
241                         dp = (Sfdisc_t*)(bp+roundof(IOBSIZE+1,sizeof(__V_*)));
242                         if(status&IOTTY)
243                                 dp->readf = slowread;
244                         else if(status&IONOSEEK)
245                                 dp->readf = piperead;
246                         else
247                                 dp->readf = 0;
248                         dp->seekf = 0;
249                         dp->writef = 0;
250                         dp->exceptf = slowexcept;
251                         sfdisc(iop,dp);
252                 }
253         }
254         else
255                 sfpool(iop,sh.outpool,SF_WRITE);
256         sh.sftable[fd] = iop;
257         return(iop);
258 }
259
260 /*
261  * preserve the file descriptor or stream by moving it
262  */
263 static void io_preserve __PARAM__((register Sfio_t *sp, register int f2), (sp, f2)) __OTORP__(register Sfio_t *sp; register int f2;){
264         register int fd;
265         if(sp)
266                 fd = sfsetfd(sp,10);
267         else
268                 fd = fcntl(f2,F_DUPFD,10);
269         if(f2==sh.infd)
270                 sh.infd = fd;
271         if(fd<0)
272                 error(ERROR_system(1),e_toomany);
273         if(sh.fdptrs[fd]=sh.fdptrs[f2])
274         {
275                 if(f2==job.fd)
276                         job.fd=fd;
277                 *sh.fdptrs[fd] = fd;
278                 sh.fdptrs[f2] = 0;
279         }
280         sh.sftable[fd] = sp;
281         sh.fdstatus[fd] = sh.fdstatus[f2];
282         if(fcntl(f2,F_GETFD,0)&1)
283         {
284                 fcntl(fd,F_SETFD,FD_CLOEXEC);
285                 sh.fdstatus[fd] |= IOCLEX;
286         }
287         sh.sftable[f2] = 0;
288 }
289
290 /*
291  * Given a file descriptor <f1>, move it to a file descriptor number <f2>
292  * If <f2> is needed move it, otherwise it is closed first.
293  * The original stream <f1> is closed.
294  *  The new file descriptor <f2> is returned;
295  */
296 int sh_iorenumber __PARAM__((register int f1,register int f2), (f1, f2)) __OTORP__(register int f1;register int f2;){
297         register Sfio_t *sp = sh.sftable[f2];
298         if(f1!=f2)
299         {
300                 /* see whether file descriptor is in use */
301                 if(sh_inuse(f2) || (f2>2 && sp))
302                 {
303                         io_preserve(sp,f2);
304                         sp = 0;
305                 }
306                 else if(f2==0)
307                         sh.st.ioset = 1;
308                 sh_close(f2);
309                 if(f2<=2 && sp)
310                 {
311                         register Sfio_t *spnew = sh_iostream(f1);
312                         sh.fdstatus[f2] = (sh.fdstatus[f1]&~IOCLEX);
313                         sfsetfd(spnew,f2);
314                         sfswap(spnew,sp);
315                         sfset(sp,SF_SHARE|SF_PUBLIC,1);
316                 }
317                 else 
318                 {
319                         sh.fdstatus[f2] = (sh.fdstatus[f1]&~IOCLEX);
320                         if((f2 = fcntl(f1,F_DUPFD, f2)) < 0)
321                                 error(ERROR_system(1),e_file+4);
322                         else if(f2 <= 2)
323                                 sh_iostream(f2);
324                 }
325                 if(sp)
326                         sh.sftable[f1] = 0;
327                 sh_close(f1);
328         }
329         return(f2);
330 }
331
332 /*
333  * close a file descriptor and update stream table and attributes 
334  */
335 int sh_close __PARAM__((register int fd), (fd)) __OTORP__(register int fd;){
336         register Sfio_t *sp;
337         register int r = 0;
338         if(fd<0)
339                 return(-1);
340         if(fd==sh.coutpipe)
341         {
342                 sh.cpid = 0;
343                 sh.coutpipe = -1;
344         }
345         if(!(sp=sh.sftable[fd]) || sfclose(sp) < 0)
346                 r=close(fd);
347         if(fd>2)
348                 sh.sftable[fd] = 0;
349         sh.fdstatus[fd] = IOCLOSE;
350         if(sh.fdptrs[fd])
351                 *sh.fdptrs[fd] = -1;
352         sh.fdptrs[fd] = 0;
353         return(r);
354 }
355
356 /*
357  * Open a file for reading
358  * On failure, print message.
359  */
360 int sh_open __PARAM__((register const char *path, int flags, ...), (va_alist)) __OTORP__(va_dcl)
361 { __OTORP__(register const char *path; int flags; )
362         register int            fd;
363         mode_t                  mode;
364 #ifdef SOCKET
365         struct sockaddr_in      addr;
366 #endif /* SOCKET */
367         va_list                 ap;
368         __VA_START__(ap, flags); __OTORP__(path = va_arg(ap, const char *);flags = va_arg(ap, int );)
369         mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
370         va_end(ap);
371         errno = 0;
372         if(*path==0)
373         {
374                 errno = ENOENT;
375                 return(-1);
376         }
377         if (strmatch(path,e_devfdNN))
378         {
379                 fd = atoi(path+8);
380                 if((mode=sh_iocheckfd(fd))==IOCLOSE)
381                         return(-1);
382                 flags &= (O_RDWR|O_WRONLY|O_RDONLY);
383                 if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR)))
384                         return(-1);
385                 if(!(mode&IOREAD) && ((flags==O_RDONLY) || (flags==O_RDWR)))
386                         return(-1);
387                 return(fd);
388
389         }
390 #ifdef SOCKET
391         if (strmatch(path, "/dev/@(tcp|udp)/*/*") && str2inet(path + 9, &addr))
392         {
393                 if ((fd = socket(AF_INET, path[5] == 't' ? SOCK_STREAM : SOCK_DGRAM, 0)) >= 0 && connect(fd, (struct sockaddr*)&addr, sizeof(addr)))
394                 {
395                         close(fd);
396                         fd = -1;
397                 }
398         }
399         else
400 #endif /* SOCKET */
401         if((fd = open(path, flags, mode)) < 0)
402                 return(-1);
403         if(flags&O_WRONLY)
404                 mode = IOWRITE;
405         else if(flags&O_RDWR)
406                 mode = (IOREAD|IOWRITE);
407         else
408                 mode = IOREAD;
409         sh.fdstatus[fd] = mode;
410         return(fd);
411 }
412
413 int sh_chkopen __PARAM__((register const char *name), (name)) __OTORP__(register const char *name;){
414         register int fd = sh_open(name,O_RDONLY,0);
415         if(fd < 0)
416                 error(ERROR_system(1),e_open,name);
417         return(fd);
418 }
419
420 /*
421  * move open file descriptor to a number > 2
422  */
423 int sh_iomovefd __PARAM__((register int fdold), (fdold)) __OTORP__(register int fdold;){
424         register int fdnew;
425         if(fdold<0 || fdold>2)
426                 return(fdold);
427         fdnew = sh_iomovefd(dup(fdold));
428         sh.fdstatus[fdnew] = (sh.fdstatus[fdold]&~IOCLEX);
429         close(fdold);
430         sh.fdstatus[fdold] = IOCLOSE;
431         return(fdnew);
432 }
433
434 /*
435  * create a pipe and print message on failure
436  */
437 int     sh_pipe __PARAM__((register int pv[]), (pv)) __OTORP__(register int pv[];){
438         int fd[2];
439         if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
440                 error(ERROR_system(1),e_pipe);
441         pv[0] = sh_iomovefd(pv[0]);
442         pv[1] = sh_iomovefd(pv[1]);
443         sh.fdstatus[pv[0]] = IONOSEEK|IOREAD|IODUP;
444         sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE;
445         return(0);
446 }
447
448 /*
449  * close a pipe
450  */
451 void sh_pclose __PARAM__((register int pv[]), (pv)) __OTORP__(register int pv[];){
452         if(pv[0]>=2)
453                 sh_close(pv[0]);
454         if(pv[1]>=2)
455                 sh_close(pv[1]);
456         pv[0] = pv[1] = -1;
457 }
458
459 /*
460  * I/O redirection
461  * flag = 0 if files are to be restored
462  * flag = 2 if files are to be closed on exec
463  * flag = 3 when called from $( < ...), just open file and return
464  */
465 int     sh_redirect __PARAM__((struct ionod *iop, int flag), (iop, flag)) __OTORP__(struct ionod *iop; int flag;){
466         register char *fname;
467         register int    fd, iof;
468         register Namval_t *np=0;
469         const char *message = e_open;
470         int o_mode;             /* mode flag for open */
471         static char io_op[5];   /* used for -x trace info */
472         int clexec=0, fn, traceon;
473         int indx = sh.topfd;
474         if(flag==2)
475                 clexec = 1;
476         if(iop)
477                 traceon = sh_trace(NIL(char**),0);
478         for(;iop;iop=iop->ionxt)
479         {
480                 iof=iop->iofile;
481                 fn = (iof&IOUFD);
482                 fname=iop->ioname;
483                 io_op[0] = '0'+(iof&IOUFD);
484                 if(iof&IOPUT)
485                 {
486                         io_op[1] = '>';
487                         o_mode = O_WRONLY|O_CREAT;
488                 }
489                 else
490                 {
491                         io_op[1] = '<';
492                         o_mode = O_RDONLY|O_NONBLOCK;
493                 }
494                 io_op[2] = 0;
495                 io_op[3] = 0;
496                 fname = iop->ioname;
497                 if(!(iof&IORAW))
498                         fname=sh_mactrim(fname,sh_isoption(SH_INTERACTIVE)?2:0);
499                 errno=0;
500                 if(*fname)
501                 {
502                         if(iof&IODOC)
503                         {
504                                 if(traceon)
505                                 {
506                                         io_op[2] = '<';
507                                         sfputr(sfstderr,io_op,'\n');
508                                 }
509                                 fd = io_heredoc(iop);
510                                 fname = 0;
511                         }
512                         else if(iof&IOMOV)
513                         {
514                                 int dupfd,toclose= -1;
515                                 io_op[2] = '&';
516                                 if((fd=fname[0])>='0' && fd<='9')
517                                 {
518                                         char *number = fname;
519                                         dupfd = strtol(fname,&number,10);
520                                         if(*number=='-')
521                                         {
522                                                 toclose = dupfd;
523                                                 number++;
524                                         }
525                                         if(*number || dupfd > IOUFD)
526                                         {
527                                                 message = e_file;
528                                                 goto fail;
529                                         }
530                                         if(sh.subshell && dupfd==1)
531                                         {
532                                                 sh_subtmpfile();
533                                                 dupfd = sffileno(sfstdout);
534                                         }
535                                 }
536                                 else if(fd=='-' && fname[1]==0)
537                                 {
538                                         fd= -1;
539                                         goto trace;
540                                 }
541                                 else if(fd=='p' && fname[1]==0)
542                                 {
543                                         if(iof&IOPUT)
544                                                 toclose = dupfd = sh.coutpipe;
545                                         else
546                                                 toclose = dupfd = sh.cpipe[0];
547                                 }
548                                 else
549                                 {
550                                         message = e_file;
551                                         goto fail;
552                                 }
553                                 if((fd=fcntl(dupfd,F_DUPFD,3))<0)
554                                         goto fail;
555                                 sh_iocheckfd(dupfd);
556                                 sh.fdstatus[fd] = (sh.fdstatus[dupfd]&~IOCLEX);
557                                 if(toclose<0 && sh.fdstatus[fd]&IOREAD)
558                                         sh.fdstatus[fd] |= IODUP;
559                                 else if(dupfd==sh.cpipe[0])
560                                         sh_pclose(sh.cpipe);
561                                 else if(toclose>=0)
562                                 {
563                                         if(flag==0)
564                                                 sh_iosave(toclose,indx); /* save file descriptor */
565                                         sh_close(toclose);
566                                 }
567                         }
568                         else if(iof&IORDW)
569                         {
570                                 io_op[2] = '>';
571                                 o_mode = O_RDWR|O_CREAT;
572                                 goto openit;
573                         }
574                         else if(!(iof&IOPUT))
575                                 fd=sh_chkopen(fname);
576                         else if(sh_isoption(SH_RESTRICTED))
577                                 error(ERROR_exit(1),e_restricted,fname);
578                         else
579                         {
580                                 if(iof&IOAPP)
581                                 {
582                                         io_op[2] = '>';
583                                         o_mode |= O_APPEND;
584                                 }
585                                 else
586                                 {
587                                         o_mode |= O_TRUNC;
588                                         if(iof&IOCLOB)
589                                                 io_op[2] = '|';
590                                         else if(sh_isoption(SH_NOCLOBBER))
591                                         {
592                                                 struct stat sb;
593                                                 if(stat(fname,&sb)>=0)
594                                                 {
595 #ifdef SHOPT_FS_3D
596                                                         if(S_ISREG(sb.st_mode)&&
597                                                                 (!sh.lim.fs3d || iview(&sb)==0))
598 #else
599                                                         if(S_ISREG(sb.st_mode))
600 #endif /* SHOPT_FS_3D */
601                                                         {
602                                                                 errno = EEXIST;
603                                                                 error(ERROR_system(1),e_exists,fname);
604                                                         }
605                                                 }
606                                                 else
607                                                         o_mode |= O_EXCL;
608                                         }
609                                 }
610                         openit:
611                                 if((fd=sh_open(fname,o_mode,RW_ALL)) <0)
612                                         error(ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname);
613                         }
614                 trace:
615                         if(traceon && fname)
616                                 sfprintf(sfstderr,"%s %s%c",io_op,fname,iop->ionxt?' ':'\n');
617                         if(flag==0)
618                                 sh_iosave(fn,indx); /* save file descriptor */
619                         if(fd<0)
620                         {
621                                 if(sh_inuse(fn) || fn==sh.infd)
622                                         io_preserve(sh.sftable[fn],fn);
623                                 sh_close(fn);
624                         }
625                         if(flag==3)
626                                 return(fd);
627                         if(fd>=0)
628                                 fd = sh_iorenumber(sh_iomovefd(fd),fn);
629                         if(fd >2 && clexec)
630                         {
631                                 fcntl(fd,F_SETFD,FD_CLOEXEC);
632                                 sh.fdstatus[fd] |= IOCLEX;
633                         }
634                 }
635         }
636         return(indx);
637 fail:
638         error(ERROR_system(1),message,fname);
639         /* NOTREACHED */
640 }
641 /*
642  * Create a tmp file for the here-document
643  */
644 static int io_heredoc __PARAM__((register struct ionod *iop), (iop)) __OTORP__(register struct ionod *iop;){
645         register Sfio_t *infile = 0, *outfile;
646         register char           fd;
647         /* create an unnamed temporary file */
648         if(!(outfile=sftmp(0)))
649                 error(ERROR_system(1),e_tmpcreate);
650         if(!(iop->iofile&IOSTRG))
651         {
652                 if(!sh.heredocs || iop->iosize==0)
653                         return(sh_open(e_devnull,O_RDONLY));
654                 infile = subopen(sh.heredocs,iop->iooffset,iop->iosize);
655         }
656         if(iop->iofile&IOQUOTE)
657         {
658                 /* This is a quoted here-document, not expansion */
659                 if(!infile)
660                         infile = sfopen(NIL(Sfio_t*),iop->ioname,"s");
661                 sfmove(infile,outfile,SF_UNBOUND,-1);
662                 sfclose(infile);
663         }
664         else
665         {
666                 if(sh_isoption(SH_XTRACE))
667                         sfdisc(outfile,&tee_disc);
668                 sh_machere(infile,outfile,iop->ioname);
669                 if(infile)
670                         sfclose(infile);
671         }
672         /* close stream outfile, but save file descriptor */
673         fd = sffileno(outfile);
674         sfsetfd(outfile,-1);
675         sfclose(outfile);
676         lseek(fd,(off_t)0,SEEK_SET);
677         sh.fdstatus[fd] = IOREAD;
678         return(fd);
679 }
680
681 /*
682  * This write discipline also writes the output on standard error
683  * This is used when tracing here-documents
684  */
685 static int tee_write __PARAM__((Sfio_t *iop,const __V_ *buff,int n,Sfdisc_t *unused), (iop, buff, n, unused)) __OTORP__(Sfio_t *iop;const __V_ *buff;int n;Sfdisc_t *unused;){
686         NOT_USED(unused);
687         sfwrite(sfstderr,buff,n);
688         return(write(sffileno(iop),buff,n));
689 }
690
691 /*
692  * copy file <origfd> into a save place
693  * The saved file is set close-on-exec
694  * if <origfd> < 0, then -origfd is saved, but not duped so that it
695  *   will be closed with sh_iorestore.
696  */
697 void sh_iosave __PARAM__((register int origfd, int oldtop), (origfd, oldtop)) __OTORP__(register int origfd; int oldtop;){
698 /*@
699         assume oldtop>=0 && oldtop<sh.lim.open_max;
700 @*/
701  
702         register int    savefd;
703         /* see if already saved, only save once */
704         for(savefd=sh.topfd; --savefd>=oldtop; )
705         {
706                 if(filemap[savefd].orig_fd == origfd)
707                         return;
708         }
709         /* make sure table is large enough */
710         if(sh.topfd >= filemapsize)
711         {
712                 filemapsize += 8;
713                 if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave))))
714                         error(ERROR_exit(4),e_nospace);
715                         
716         }
717 #ifdef SHOPT_DEVFD
718         if(origfd <0)
719         {
720                 savefd = origfd;
721                 origfd = -origfd;
722         }
723         else
724 #endif /* SHOPT_DEVFD */
725         {
726                 if((savefd = fcntl(origfd, F_DUPFD, 3)) < 0 && errno!=EBADF)
727                         error(ERROR_system(1),e_toomany);
728         }
729         filemap[sh.topfd].orig_fd = origfd;
730         filemap[sh.topfd++].save_fd = savefd;
731         if(savefd >=0)
732         {
733                 register Sfio_t* sp = sh.sftable[origfd];
734                 /* make saved file close-on-exec */
735                 fcntl(savefd,F_SETFD,FD_CLOEXEC);
736                 if(origfd==job.fd)
737                         job.fd = savefd;
738                 sh.fdstatus[savefd] = sh.fdstatus[origfd];
739                 sh.fdptrs[savefd] = &filemap[sh.topfd-1].save_fd;
740                 if(!(sh.sftable[savefd]=sp))
741                         return;
742                 sfsync(sp);
743                 if(origfd <=2)
744                 {
745                         /* copy standard stream to new stream */
746                         sp = sfswap(sp,NIL(Sfio_t*));
747                         sh.sftable[savefd] = sp;
748                 }
749                 else
750                         sh.sftable[origfd] = 0;
751         }
752 }
753
754 /*
755  *  close all saved file descriptors
756  */
757 void    sh_iounsave __PARAM__((void), ()){
758         register int fd, savefd, newfd;
759         for(newfd=fd=0; fd < sh.topfd; fd++)
760         {
761                 if((savefd = filemap[fd].save_fd)< 0)
762                         filemap[newfd++] = filemap[fd];
763                 else
764                 {
765                         sh.sftable[savefd] = 0;
766                         sh_close(savefd);
767                 }
768         }
769         sh.topfd = newfd;
770 }
771
772 /*
773  *  restore saved file descriptors from <last> on
774  */
775 void    sh_iorestore __PARAM__((int last), (last)) __OTORP__(int last;){
776         register int    origfd, savefd, fd;
777         for (fd = sh.topfd - 1; fd >= last; fd--)
778         {
779                 origfd = filemap[fd].orig_fd;
780                 sh_close(origfd);
781                 if ((savefd = filemap[fd].save_fd) >= 0)
782                 {
783                         fcntl(savefd, F_DUPFD, origfd);
784                         if(savefd==job.fd)
785                                 job.fd=origfd;
786                         sh.fdstatus[origfd] = sh.fdstatus[savefd];
787                         /* turn off close-on-exec if flag if necessary */
788                         if(sh.fdstatus[origfd]&IOCLEX)
789                                 fcntl(origfd,F_SETFD,FD_CLOEXEC);
790                         if(origfd<=2)
791                         {
792                                 sfswap(sh.sftable[savefd],sh.sftable[origfd]);
793                                 if(origfd==0)
794                                         sh.st.ioset = 0;
795                         }
796                         else
797                                 sh.sftable[origfd] = sh.sftable[savefd];
798                         sh.sftable[savefd] = 0;
799                         sh_close(savefd);
800                 }
801         }
802         if(last < sh.topfd)
803                 sh.topfd = last;
804 }
805
806 /*
807  * returns access information on open file <fd>
808  * returns -1 for failure, 0 for success
809  * <mode> is the same as for access()
810  */
811 sh_ioaccess __PARAM__((int fd,register int mode), (fd, mode)) __OTORP__(int fd;register int mode;){
812         register int flags;
813         if(mode==X_OK)
814                 return(-1);
815         if((flags=sh_iocheckfd(fd))!=IOCLOSE)
816         {
817                 if(mode==F_OK)
818                         return(0);
819                 if(mode==R_OK && (flags&IOREAD))
820                         return(0);
821                 if(mode==W_OK && (flags&IOWRITE))
822                         return(0);
823         }
824         return(-1);
825 }
826
827 #ifdef SOCKET
828 /*
829  * convert string to sockaddr_in
830  * 0 returned on error
831  */
832
833 static int str2inet __PARAM__((register const char *sp, struct sockaddr_in *addr), (sp, addr)) __OTORP__(register const char *sp; struct sockaddr_in *addr;){
834         register int    n=0,c,v;
835         unsigned long   a=0;
836         unsigned short  p;
837
838         for (;;)
839         {
840                 v = 0;
841                 while ((c = *sp++) >= '0' && c <= '9')
842                         v = v * 10 + c - '0';
843                 if (++n <= 4) a = (a << 8) | (v & 0xff);
844                 else
845                 {
846                         if (c) return(0);
847                         p = v;
848                         break;
849                 }
850                 if (c != '.' && c != '/') return(0);
851         }
852         memset((char*)addr, 0, sizeof(*addr));
853         addr->sin_family = AF_INET;
854         addr->sin_addr.s_addr = htonl(a);
855         addr->sin_port = htons(p);
856         return(1);
857 }
858 #endif /* SOCKET */
859
860
861 /*
862  *  Handle interrupts for slow streams
863  */
864 static int slowexcept __PARAM__((register Sfio_t *iop, int type, Sfdisc_t *handle), (iop, type, handle)) __OTORP__(register Sfio_t *iop; int type; Sfdisc_t *handle;){
865         register int    n,fno;
866         NOT_USED(handle);
867         if(type!=SF_READ)
868                 return(0);
869         if((sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) && errno!=EIO && errno!=ENXIO)
870                 errno = EINTR;
871         if((n=sfslen())<=0)
872         {
873                 fno = sffileno(iop);
874 #ifndef FNDELAY
875 #   ifdef O_NDELAY
876                 if(errno==0 && (n=fcntl(fno,F_GETFL,0))&O_NDELAY)
877                 {
878                         n &= ~O_NDELAY;
879                         fcntl(fno, F_SETFL, n);
880                         return(1);
881                 }
882 #   endif /* O_NDELAY */
883 #endif /* !FNDELAY */
884 #ifdef O_NONBLOCK
885                 if(errno==EAGAIN)
886                 {
887                         n = fcntl(fno,F_GETFL,0);
888                         n &= ~O_NONBLOCK;
889                         fcntl(fno, F_SETFL, n);
890                         return(1);
891                 }
892 #endif /* O_NONBLOCK */
893                 if(errno!=EINTR)
894                         return(0);
895                 n=1;
896         }
897         errno = 0;
898         if(sh.trapnote&SH_SIGSET)
899         {
900                 sfputc(sfstderr,'\n');
901                 sh_exit(SH_EXITSIG);
902         }
903         if(sh.trapnote&SH_SIGTRAP)
904                 sh_chktrap();
905         return(n);
906 }
907
908 /*
909  * called when slowread times out
910  */
911 static void time_grace __PARAM__((__V_ *handle), (handle)) __OTORP__(__V_ *handle;){
912         NOT_USED(handle);
913         timeout = 0;
914         if(sh_isstate(SH_GRACE))
915         {
916                 sh_offstate(SH_GRACE);
917                 if(!sh_isstate(SH_INTERACTIVE))
918                         return;
919                 ((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT;
920                 error(2,e_timeout);
921                 sh.trapnote |= SH_SIGSET;
922                 return;
923         }
924         error(0,e_timewarn);
925         sh_onstate(SH_GRACE);
926         sigrelease(SIGALRM);
927         sh.trapnote |= SH_SIGTRAP;
928 }
929
930 static int piperead __PARAM__((Sfio_t *iop,__V_ *buff,register int size,Sfdisc_t *handle), (iop, buff, size, handle)) __OTORP__(Sfio_t *iop;__V_ *buff;register int size;Sfdisc_t *handle;){
931         NOT_USED(handle);
932         size = ed_read(sffileno(iop), (char*)buff, size);
933         return(size);
934 }
935 /*
936  * This is the read discipline that is applied to slow devices
937  * This routine takes care of prompting for input
938  */
939 static int slowread __PARAM__((Sfio_t *iop,__V_ *buff,register int size,Sfdisc_t *handle), (iop, buff, size, handle)) __OTORP__(Sfio_t *iop;__V_ *buff;register int size;Sfdisc_t *handle;){
940         int     (*readf) __PROTO__((int, char*, int));
941         NOT_USED(handle);
942         if(io_prompt(sh.nextprompt)<0 && errno==EIO)
943                 return(0);
944         if(sh.timeout)
945                 timeout = (__V_*)timeradd(sh_isstate(SH_GRACE)?1000L*TGRACE:1000L*sh.timeout,0,time_grace,NIL(__V_*));
946 #   ifdef SHOPT_ESH
947         if(sh_isoption(SH_EMACS|SH_GMACS))
948                 readf = ed_emacsread;
949         else
950 #   endif       /* SHOPT_ESH */
951 #   ifdef SHOPT_VSH
952         if(sh_isoption(SH_VI))
953                 readf = ed_viread;
954         else
955 #   endif       /* SHOPT_VSH */
956                 readf = ed_read;
957         size = (*readf)(sffileno(iop), (char*)buff, size);
958         if(timeout)
959                 timerdel(timeout);
960         timeout=0;
961         return(size);
962 }
963
964 /*
965  * check and return the attributes for a file descriptor
966  */
967
968 int sh_iocheckfd __PARAM__((register int fd), (fd)) __OTORP__(register int fd;){
969         register int flags, n;
970         if((n=sh.fdstatus[fd])&IOCLOSE)
971                 return(n);
972         if(!(n&(IOREAD|IOWRITE)))
973         {
974 #ifdef F_GETFL
975                 if((flags=fcntl(fd,F_GETFL,0)) < 0)
976                         return(sh.fdstatus[fd]=IOCLOSE);
977                 if(!(flags&O_WRONLY))
978                         n |= IOREAD;
979                 if(flags&(O_WRONLY|O_RDWR))
980                         n |= IOWRITE;
981 #else
982                 struct stat statb;
983                 if((flags = fstat(fd,&statb))< 0)
984                         return(sh.fdstatus[fd]=IOCLOSE);
985                 n |= (IOREAD|IOWRITE);
986                 if(read(fd,"",0) < 0)
987                         n &= ~IOREAD;
988 #endif /* F_GETFL */
989         }
990         if(!(n&(IOSEEK|IONOSEEK)))
991         {
992                 struct stat statb;
993                 /* /dev/null check is a workaround for select bug */
994                 static ino_t null_ino;
995                 static dev_t null_dev;
996                 if(null_ino==0 && stat(e_devnull,&statb) >=0)
997                 {
998                         null_ino = statb.st_ino;
999                         null_dev = statb.st_dev;
1000                 }
1001                 if(tty_check(fd))
1002                         n |= IOTTY;
1003                 if(lseek(fd,NIL(off_t),SEEK_CUR)<0)
1004                 {
1005                         n |= IONOSEEK;
1006 #ifdef S_ISSOCK
1007                         if((fstat(fd,&statb)>=0) && S_ISSOCK(statb.st_mode))
1008                                 n |= IOREAD|IOWRITE;
1009 #endif /* S_ISSOCK */
1010                 }
1011                 else if((fstat(fd,&statb)>=0) && (
1012                         S_ISFIFO(statb.st_mode) ||
1013 #ifdef S_ISSOCK
1014                         S_ISSOCK(statb.st_mode) ||
1015 #endif /* S_ISSOCK */
1016                         /* The following is for sockets on the sgi */
1017                         (statb.st_ino==0 && (statb.st_mode & ~(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH|S_IXUSR|S_IXGRP|S_IXOTH|S_ISUID|S_ISGID))==0) ||
1018                         (S_ISCHR(statb.st_mode) && (statb.st_ino!=null_ino || statb.st_dev!=null_dev))
1019                 ))
1020                         n |= IONOSEEK;
1021                 else
1022                         n |= IOSEEK;
1023         }
1024         sh.fdstatus[fd] = n;
1025         return(n);
1026 }
1027
1028 /*
1029  * Display prompt PS<flag> on standard error
1030  */
1031
1032 static int      io_prompt __PARAM__((register int flag), (flag)) __OTORP__(register int flag;){
1033         register char *cp;
1034         char *endprompt;
1035         static short cmdno;
1036         int sfflags;
1037         if(flag<3 && !sh_isstate(SH_INTERACTIVE))
1038                 flag = 0;
1039         if(flag==0)
1040                 return(sfsync(sfstderr));
1041         sfflags = sfset(sfstderr,SF_SHARE|SF_PUBLIC|SF_READ,0);
1042         if(!(sh.prompt=(char*)sfreserve(sfstderr,0,0)))
1043                 sh.prompt = "";
1044         switch(flag)
1045         {
1046                 case 1:
1047                 {
1048                         register int c;
1049 #if defined(TIOCLBIC) && defined(LFLUSHO)
1050                         if(!sh_isoption(SH_VI|SH_EMACS|SH_GMACS))
1051                         {
1052                                 /*
1053                                  * re-enable output in case the user has
1054                                  * disabled it.  Not needed with edit mode
1055                                  */
1056                                 int mode = LFLUSHO;
1057                                 ioctl(sffileno(sfstderr),TIOCLBIC,&mode);
1058                         }
1059 #endif  /* TIOCLBIC */
1060                         cp = sh_mactry(nv_getval(nv_scoped(PS1NOD)));
1061                         for(;c= *cp;cp++)
1062                         {
1063                                 if(c==HIST_CHAR)
1064                                 {
1065                                         /* look at next character */
1066                                         c = *++cp;
1067                                         /* print out line number if not !! */
1068                                         if(c!= HIST_CHAR)
1069                                         {
1070                                                 sfprintf(sfstderr,"%d", sh.hist_ptr?(int)sh.hist_ptr->histind:++cmdno);
1071                                         }
1072                                         if(c==0)
1073                                                 goto done;
1074                                 }
1075                                 sfputc(sfstderr,c);
1076                         }
1077                         goto done;
1078                 }
1079                 case 2:
1080                         cp = nv_getval(nv_scoped(PS2NOD));
1081                         break;
1082                 case 3:
1083                         cp = nv_getval(nv_scoped(PS3NOD));
1084                         break;
1085                 default:
1086                         goto done;
1087         }
1088         if(cp)
1089                 sfputr(sfstderr,cp,-1);
1090 done:
1091         if(*sh.prompt && (endprompt=(char*)sfreserve(sfstderr,0,0)))
1092                 *endprompt = 0;
1093         sfset(sfstderr,sfflags&SF_READ|SF_SHARE|SF_PUBLIC,1);
1094         return(sfsync(sfstderr));
1095 }
1096
1097 /*
1098  * This discipline is inserted on write pipes to prevent SIGPIPE
1099  * from causing an infinite loop
1100  */
1101 static int pipeexcept __PARAM__((Sfio_t* iop, int mode, Sfdisc_t* handle), (iop, mode, handle)) __OTORP__(Sfio_t* iop; int mode; Sfdisc_t* handle;){
1102         NOT_USED(iop);
1103         if(mode==SF_WRITE && errno==EINTR && sh.lastsig==SIGPIPE)
1104                 return(-1);
1105         else if(mode==SF_DPOP || mode==SF_CLOSE)
1106                 free((__V_*)handle);
1107         return(0);
1108 }
1109
1110 /*
1111  * keep track of each stream that is opened and closed
1112  */
1113 static void     sftrack __PARAM__((Sfio_t* sp,int flag, int newfd), (sp, flag, newfd)) __OTORP__(Sfio_t* sp;int flag; int newfd;){
1114         register int fd = sffileno(sp);
1115         register struct checkpt *pp;
1116         register int mode;
1117         if(flag==SF_SETFD && newfd<0)
1118         {
1119                 flag = SF_CLOSE;
1120         }
1121 #ifdef DEBUG
1122         if(flag==SF_READ || flag==SF_WRITE)
1123         {
1124                 char *z = fmtbase((long)getpid(),0,0);
1125                 write(ERRIO,z,strlen(z));
1126                 write(ERRIO,": ",2);
1127                 write(ERRIO,"attempt to ",11);
1128                 if(flag==SF_READ)
1129                         write(ERRIO,"read from",9);
1130                 else
1131                         write(ERRIO,"write to",8);
1132                 write(ERRIO," locked stream\n",15);
1133                 return;
1134         }
1135 #endif
1136         if((unsigned)fd >= sh.lim.open_max)
1137                 return;
1138         if(sh_isstate(SH_NOTRACK))
1139                 return;
1140         mode = sfset(sp,0,0);
1141         if(flag==SF_NEW && (mode&SF_WRITE) && (sh_iocheckfd(fd)&IONOSEEK))
1142         {
1143                 Sfdisc_t *dp = newof(0,Sfdisc_t,1,0);
1144                 dp->exceptf = pipeexcept;
1145                 sfdisc(sp,dp);
1146         }
1147         if(fd < 3)
1148                 return;
1149         if(flag==SF_NEW)
1150         {
1151                 sh.sftable[fd] = sp;
1152                 if(sh.fdstatus[fd]==IOCLOSE)
1153                 {
1154                         flag = (mode&SF_WRITE)?IOWRITE:0;
1155                         if(mode&SF_READ)
1156                                 flag |= IOREAD;
1157                         sh.fdstatus[fd] = flag;
1158                         sh_iostream(fd);
1159                 }
1160                 if((pp=(struct checkpt*)sh.jmplist) && pp->mode==SH_JMPCMD)
1161                 {
1162                         struct openlist *item;
1163                         /*
1164                          * record open file descriptors so they can
1165                          * be closed in case a longjmp prevents
1166                          * built-ins from cleanup
1167                          */
1168                         item = new_of(struct openlist, 0);
1169                         item->strm = sp;
1170                         item->next = pp->olist;
1171                         pp->olist = item;
1172                 }
1173         }
1174         else if(flag==SF_CLOSE) 
1175         {
1176                 sh.sftable[fd] = 0;
1177                 sh.fdstatus[fd]=IOCLOSE;
1178                 if(pp=(struct checkpt*)sh.jmplist)
1179                 {
1180                         struct openlist *item;
1181                         for(item=pp->olist; item; item=item->next)
1182                         {
1183                                 if(item->strm == sp)
1184                                 {
1185                                         item->strm = 0;
1186                                         break;
1187                                 }
1188                         }
1189                 }
1190         }
1191 }
1192
1193 struct eval
1194 {
1195         Sfdisc_t        disc;
1196         char            **argv;
1197         short           slen;
1198         char            addspace;
1199 };
1200
1201 /*
1202  * Create a stream consisting of a space separated argv[] list 
1203  */
1204
1205 Sfio_t *sh_sfeval __PARAM__((register char *argv[]), (argv)) __OTORP__(register char *argv[];){
1206         register Sfio_t *iop;
1207         register char *cp;
1208         if(argv[1])
1209                 cp = "";
1210         else
1211                 cp = argv[0];
1212         iop = sfopen(NIL(Sfio_t*),(char*)cp,"s");
1213         if(argv[1])
1214         {
1215                 register struct eval *ep;
1216                 if(!(ep = new_of(struct eval,0)))
1217                         return(NIL(Sfio_t*));
1218                 ep->disc = eval_disc;
1219                 ep->argv = argv;
1220                 ep->slen  = -1;
1221                 ep->addspace  = 0;
1222                 sfdisc(iop,&ep->disc);
1223         }
1224         return(iop);
1225 }
1226
1227 /*
1228  * This code gets called whenever an end of string is found with eval
1229  */
1230
1231 static int eval_exceptf __PARAM__((Sfio_t *iop,int type, Sfdisc_t *handle), (iop, type, handle)) __OTORP__(Sfio_t *iop;int type; Sfdisc_t *handle;){
1232         register struct eval *ep = (struct eval*)handle;
1233         register char   *cp;
1234         register int    len;
1235
1236         /* no more to do */
1237         if(type!=SF_READ || !(cp = ep->argv[0]))
1238         {
1239                 if(type==SF_CLOSE)
1240                 {
1241                         sfdisc(iop,SF_POPDISC);
1242                         if(ep)
1243                                 free((__V_*)ep);
1244                 }
1245                 return(0);
1246         }
1247
1248         if(!ep->addspace)
1249         {
1250                 /* get the length of this string */
1251                 ep->slen = len = strlen(cp);
1252                 /* move to next string */
1253                 ep->argv++;
1254         }
1255         else /* insert space between arguments */
1256         {
1257                 len = 1;
1258                 cp = " ";
1259         }
1260         /* insert the new string */
1261         sfsetbuf(iop,cp,len);
1262         ep->addspace = !ep->addspace;
1263         return(1);
1264 }
1265
1266 /*
1267  * This routine returns a stream pointer to a segment of length <size> from
1268  * the stream <sp> starting at offset <offset>
1269  * The stream can be read with the normal stream operations
1270  */
1271
1272 static Sfio_t *subopen __PARAM__((Sfio_t* sp, off_t offset, long size), (sp, offset, size)) __OTORP__(Sfio_t* sp; off_t offset; long size;){
1273         register struct subfile *disp;
1274         register int fd = sffileno(sp);
1275         if(sfseek(sp,offset,SEEK_SET) <0)
1276                 return(NIL(Sfio_t*));
1277         if(!(disp = (struct subfile*)malloc(sizeof(struct subfile)+IOBSIZE+1)))
1278                 return(NIL(Sfio_t*));
1279         disp->disc = sub_disc;
1280         disp->oldsp = sp;
1281         disp->offset = offset;
1282         disp->size = disp->left = size;
1283         sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,sh.lim.open_max,SF_READ);
1284         sfdisc(sp,&disp->disc);
1285         return(sp);
1286 }
1287
1288 /*
1289  * read function for subfile discipline
1290  */
1291 static int subread __PARAM__((Sfio_t* sp,__V_* buff,register int size,Sfdisc_t* handle), (sp, buff, size, handle)) __OTORP__(Sfio_t* sp;__V_* buff;register int size;Sfdisc_t* handle;){
1292         register struct subfile *disp = (struct subfile*)handle;
1293         NOT_USED(sp);
1294         if(disp->left == 0)
1295                 return(0);
1296         if(size > disp->left)
1297                 size = disp->left;
1298         disp->left -= size;
1299         return(sfread(disp->oldsp,buff,size));
1300 }
1301
1302 /*
1303  * exception handler for subfile discipline
1304  */
1305 static int subexcept __PARAM__((Sfio_t* sp,register int mode, Sfdisc_t* handle), (sp, mode, handle)) __OTORP__(Sfio_t* sp;register int mode; Sfdisc_t* handle;){
1306         register struct subfile *disp = (struct subfile*)handle;
1307         if(mode==SF_CLOSE)
1308         {
1309                 sfdisc(sp,SF_POPDISC);
1310                 free((__V_*)handle);
1311         }
1312         else  if(mode==SF_READ)
1313                 return(0);
1314         return(-1);
1315 }
1316
1317 #define NROW    15      /* number of rows before going to multi-columns */
1318 #define LBLSIZ  3       /* size of label field and interfield spacing */
1319 /* 
1320  * print a list of arguments in columns
1321  */
1322 void    sh_menu __PARAM__((Sfio_t *outfile,int argn,char *argv[]), (outfile, argn, argv)) __OTORP__(Sfio_t *outfile;int argn;char *argv[];){
1323         register int i,j;
1324         register char **arg;
1325         int nrow, ncol=1, ndigits=1;
1326         int fldsize, wsize = ed_window();
1327         char *cp = nv_getval(nv_scoped(LINES));
1328         nrow = (cp?1+2*(atoi(cp)/3):NROW);
1329         for(i=argn;i >= 10;i /= 10)
1330                 ndigits++;
1331         if(argn < nrow)
1332         {
1333                 nrow = argn;
1334                 goto skip;
1335         }
1336         i = 0;
1337         for(arg=argv; *arg;arg++)
1338         {
1339                 if((j=strlen(*arg)) > i)
1340                         i = j;
1341         }
1342         i += (ndigits+LBLSIZ);
1343         if(i < wsize)
1344                 ncol = wsize/i;
1345         if(argn > nrow*ncol)
1346         {
1347                 nrow = 1 + (argn-1)/ncol;
1348         }
1349         else
1350         {
1351                 ncol = 1 + (argn-1)/nrow;
1352                 nrow = 1 + (argn-1)/ncol;
1353         }
1354 skip:
1355         fldsize = (wsize/ncol)-(ndigits+LBLSIZ);
1356         for(i=0;i<nrow;i++)
1357         {
1358                 if(sh.trapnote&SH_SIGSET)
1359                         return;
1360                 j = i;
1361                 while(1)
1362                 {
1363                         arg = argv+j;
1364                         sfprintf(outfile,"%*d) %s",ndigits,j+1,*arg);
1365                         j += nrow;
1366                         if(j >= argn)
1367                                 break;
1368                         sfnputc(outfile,' ',fldsize-strlen(*arg));
1369                 }
1370                 sfputc(outfile,'\n');
1371         }
1372 }
1373
1374 #undef read
1375 /*
1376  * shell version of read() for user added builtins
1377  */
1378 ssize_t sh_read __PARAM__((register int fd, __V_* buff, size_t n), (fd, buff, n)) __OTORP__(register int fd; __V_* buff; size_t n;){
1379         register Sfio_t *sp;
1380         if(sp=sh.sftable[fd])
1381                 return(sfread(sp,buff,n));
1382         else
1383                 return(read(fd,buff,n));
1384 }
1385
1386 #undef write
1387 /*
1388  * shell version of write() for user added builtins
1389  */
1390 ssize_t sh_write __PARAM__((register int fd, const __V_* buff, size_t n), (fd, buff, n)) __OTORP__(register int fd; const __V_* buff; size_t n;){
1391         register Sfio_t *sp;
1392         if(sp=sh.sftable[fd])
1393                 return(sfwrite(sp,buff,n));
1394         else
1395                 return(write(fd,buff,n));
1396 }
1397
1398 #undef lseek
1399 /*
1400  * shell version of lseek() for user added builtins
1401  */
1402 off_t sh_seek __PARAM__((register int fd, off_t offset, int whence), (fd, offset, whence)) __OTORP__(register int fd; off_t offset; int whence;){
1403         register Sfio_t *sp;
1404         if(sp=sh.sftable[fd])
1405                 return(sfseek(sp,offset,whence));
1406         else
1407                 return(lseek(fd,offset,whence));
1408 }
1409
1410 #undef dup
1411 int sh_dup __PARAM__((register int old), (old)) __OTORP__(register int old;){
1412         register int fd = dup(old);
1413         if(fd>=0)
1414                 sh.fdstatus[fd] = (sh.fdstatus[old]&~IOCLEX);
1415         return(fd);
1416 }