home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume35 / zsh / part10 < prev    next >
Encoding:
Text File  |  1993-02-19  |  54.7 KB  |  2,670 lines

  1. Newsgroups: comp.sources.misc
  2. From: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
  3. Subject: v35i060:  zsh - The Z Shell, version 2.3.1, Part10/22
  4. Message-ID: <1993Feb20.212357.28735@sparky.imd.sterling.com>
  5. X-Md4-Signature: 81263925250f72b5c2abf4de36ca7e92
  6. Date: Sat, 20 Feb 1993 21:23:57 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
  10. Posting-number: Volume 35, Issue 60
  11. Archive-name: zsh/part10
  12. Environment: UNIX
  13. Supersedes: zsh2.2: Volume 29, Issue 97-113
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  20. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  21. # Contents:  help/chdir src/exec.c src/zle_refresh.c
  22. # Wrapped by mattson@odin on Sat Feb  6 14:41:53 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 10 (of 22)."'
  26. if test -f 'help/chdir' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'help/chdir'\"
  28. else
  29.   echo shar: Extracting \"'help/chdir'\" \(934 characters\)
  30.   sed "s/^X//" >'help/chdir' <<'END_OF_FILE'
  31. X     cd [ arg ]
  32. X     cd old new
  33. X     cd +-n
  34. X          Change the  current  directory.   In  the  first  form,
  35. X          change the current directory to arg, or to the value of
  36. X          HOME if arg is not specified.  If arg is -,  change  to
  37. X          the  value  of  OLDPWD,  the  previous directory.  If a
  38. X          directory named arg is not found in the current  direc-
  39. X          tory  and  arg does not begin with a slash, search each
  40. X          component of the shell parameter cdpath.  If the option
  41. X          CDABLEVARS  is  set,  and  a parameter named arg exists
  42. X          whose value begins with a slash, treat its value as the
  43. X          directory.
  44. X
  45. X          The second form of cd substitutes the  string  new  for
  46. X          the  string  old  in the name of the current directory,
  47. X          and tries to change to this new directory.
  48. X
  49. X          The third form of cd is equivalent to popd.
  50. X
  51. X     chdir
  52. X          Same as cd.
  53. END_OF_FILE
  54.   if test 934 -ne `wc -c <'help/chdir'`; then
  55.     echo shar: \"'help/chdir'\" unpacked with wrong size!
  56.   fi
  57.   # end of 'help/chdir'
  58. fi
  59. if test -f 'src/exec.c' -a "${1}" != "-c" ; then 
  60.   echo shar: Will not clobber existing file \"'src/exec.c'\"
  61. else
  62.   echo shar: Extracting \"'src/exec.c'\" \(37664 characters\)
  63.   sed "s/^X//" >'src/exec.c' <<'END_OF_FILE'
  64. X/*
  65. X *
  66. X * exec.c - command execution
  67. X *
  68. X * This file is part of zsh, the Z shell.
  69. X *
  70. X * This software is Copyright 1992 by Paul Falstad
  71. X *
  72. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  73. X * use this software as long as: there is no monetary profit gained
  74. X * specifically from the use or reproduction of this software, it is not
  75. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  76. X * included prominently in any copy made. 
  77. X *
  78. X * The author make no claims as to the fitness or correctness of this software
  79. X * for any use whatsoever, and it is provided as is. Any use of this software
  80. X * is at the user's own risk. 
  81. X *
  82. X */
  83. X
  84. X#include "zsh.h"
  85. X#include <sys/errno.h>
  86. X
  87. X#define execerr() { if (forked) _exit(1); \
  88. X    closemnodes(mfds); lastval = 1; return; }
  89. X
  90. Xstatic Lklist args;
  91. Xstatic Cmdnam cn;
  92. X
  93. X/* parse list in a string */
  94. X
  95. XList parselstring(s) /**/
  96. Xchar *s;
  97. X{
  98. XList l;
  99. X
  100. X    hungets(s);
  101. X    strinbeg();
  102. X    pushheap();
  103. X    if (!(l = parse_list())) {
  104. X        strinend();
  105. X        hflush();
  106. X        popheap();
  107. X        return NULL;
  108. X    }
  109. X    strinend();
  110. X    return l;
  111. X}
  112. X
  113. X/* execute a string */
  114. X
  115. Xvoid execstring(s) /**/
  116. Xchar *s;
  117. X{
  118. XList l;
  119. X
  120. X    if (l = parselstring(s)) {
  121. X        execlist(l);
  122. X        popheap();
  123. X    }
  124. X}
  125. X
  126. X/* fork and set limits */
  127. X
  128. Xint phork() /**/
  129. X{
  130. Xint pid,t0;
  131. X
  132. X    if (thisjob >= MAXJOB-1) {
  133. X        zerr("job table full",NULL,0);
  134. X        return -1;
  135. X    }
  136. X    pid = fork();
  137. X    if (pid == -1) {
  138. X        zerr("fork failed: %e",NULL,errno);
  139. X        return -1;
  140. X    }
  141. X#ifdef RLIM_INFINITY
  142. X    if (!pid)
  143. X        for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  144. X            setrlimit(t0,limits+t0);
  145. X#endif
  146. X    return pid;
  147. X}
  148. X
  149. X/* execute a current shell command */
  150. X
  151. Xint execcursh(cmd) /**/
  152. XCmd cmd;
  153. X{
  154. X    runlist(cmd->u.list);
  155. X    cmd->u.list = NULL;
  156. X    return lastval;
  157. X}
  158. X
  159. X/* execve after handling $_ and #! */
  160. X
  161. X#define POUNDBANGLIMIT 64
  162. X
  163. Xint zexecve(pth,argv) /**/
  164. Xchar *pth;char **argv;
  165. X{
  166. Xint eno;
  167. Xstatic char buf[MAXPATHLEN*2];
  168. Xchar **eep;
  169. X
  170. X    for (eep = environ; *eep; eep++)
  171. X        if (**eep == '_' && (*eep)[1] == '=') break;
  172. X    buf[0] = '_';
  173. X    buf[1] = '=';
  174. X    if (*pth == '/') strcpy(buf+2,pth);
  175. X    else sprintf(buf+2,"%s/%s",pwd,pth);
  176. X    if (!*eep) eep[1] = NULL;
  177. X    *eep = buf;
  178. X    execve(pth,argv,environ);
  179. X    if ((eno = errno) == ENOEXEC) {
  180. X        char buf[POUNDBANGLIMIT+1],*ptr,*ptr2,*argv0;
  181. X        int fd,ct,t0;
  182. X
  183. X        if ((fd = open(pth,O_RDONLY)) >= 0) {
  184. X            argv0 = *argv;
  185. X            *argv = pth;
  186. X            ct = read(fd,buf,POUNDBANGLIMIT);
  187. X            close(fd);
  188. X            if (ct > 0) {
  189. X                if (buf[0] == '#')
  190. X                    if (buf[1] == '!') {
  191. X                        for (t0 = 0; t0 != ct; t0++)
  192. X                            if (buf[t0] == '\n')
  193. X                                buf[t0] = '\0';
  194. X                        buf[POUNDBANGLIMIT] = '\0';
  195. X                        for (ptr = buf+2; *ptr && *ptr == ' '; ptr++);
  196. X                        for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++);
  197. X                        if (*ptr) {
  198. X                            *ptr = '\0';
  199. X                            argv[-2] = ptr2;
  200. X                            argv[-1] = ptr+1;
  201. X                            execve(ptr2,argv-2,environ);
  202. X                        } else {
  203. X                            argv[-1] = ptr2;
  204. X                            execve(ptr2,argv-1,environ);
  205. X                        }
  206. X                    } else {
  207. X                        argv[-1] = "sh";
  208. X                        execve("/bin/sh",argv-1,environ);
  209. X                    }
  210. X                else {
  211. X                    for (t0 = 0; t0 != ct; t0++)
  212. X                        if (!buf[t0]) break;
  213. X                    if (t0 == ct) {
  214. X                        argv[-1] = "sh";
  215. X                        execve("/bin/sh",argv-1,environ);
  216. X                    }
  217. X                }
  218. X            } else eno = errno;
  219. X            *argv = argv0;
  220. X        } else eno = errno;
  221. X    }
  222. X    return eno;
  223. X}
  224. X
  225. X#define MAXCMDLEN (MAXPATHLEN*4)
  226. X
  227. X/* execute an external command */
  228. X
  229. Xvoid execute(dash) /**/
  230. Xint dash;
  231. X{
  232. Xstatic Lklist exargs;
  233. Xchar **argv,*arg0,**pp;
  234. Xchar *z,*s,buf[MAXCMDLEN],buf2[MAXCMDLEN];
  235. Xint ee,eno = 0;
  236. X
  237. X    if (empty(args)) {
  238. X        zerr("no command",NULL,0);
  239. X        _exit(1);
  240. X    }
  241. X    if (!exargs && (s = zgetenv("STTY"))) {
  242. X        exargs = args;
  243. X        args = (Lklist) 0;
  244. X        zyztem("stty",s);
  245. X        args = exargs;
  246. X        exargs = (Lklist) 0;
  247. X    }
  248. X    arg0 = peekfirst(args);
  249. X    cn = (Cmdnam) gethnode(arg0,cmdnamtab);
  250. X    if (cn && cn->type == DISABLED)
  251. X        cn = NULL;
  252. X    if (z = zgetenv("ARGV0")) {
  253. X        setdata(firstnode(args),ztrdup(z));
  254. X        delenv(z-6);
  255. X    } else if (dash) {
  256. X        sprintf(buf2,"-%s",arg0);
  257. X        setdata(firstnode(args),ztrdup(buf2));
  258. X    }
  259. X    argv = makecline(args);
  260. X    fixsigs();
  261. X    if (strlen(arg0) > MAXPATHLEN) {
  262. X        zerr("command too long: %s",arg0,0);
  263. X        _exit(1);
  264. X    }
  265. X    for (s = arg0; *s; s++)
  266. X        if (*s == '/') {
  267. X            errno = zexecve(arg0,argv);
  268. X            if (arg0 == s || unset(PATHDIRS)) {
  269. X                zerr("%e: %s",arg0,errno);
  270. X                _exit(1);
  271. X            }
  272. X            break;
  273. X        }
  274. X    if (cn && ISEXCMD(cn->type)) {
  275. X        for (pp = path; pp < cn->pcomp; pp++)
  276. X            if (**pp == '.' && (*pp)[1] == '\0') {
  277. X                ee = zexecve(arg0,argv);
  278. X                if (ee != ENOENT) eno = ee;
  279. X            } else if (**pp != '/') {
  280. X                z = buf;
  281. X                strucpy(&z,*pp);
  282. X                *z++ = '/';
  283. X                strcpy(z,arg0);
  284. X                ee = zexecve(buf,argv);
  285. X                if (ee != ENOENT) eno = ee;
  286. X            }
  287. X        ee = zexecve(cn->u.nam,argv);
  288. X        if (ee != ENOENT) eno = ee;
  289. X    }
  290. X    for (pp = path; *pp; pp++)
  291. X        if ((*pp)[0] == '.' && !(*pp)[1]) {
  292. X            ee = zexecve(arg0,argv);
  293. X            if (ee != ENOENT) eno = ee;
  294. X        } else {
  295. X            z = buf;
  296. X            strucpy(&z,*pp);
  297. X            *z++ = '/';
  298. X            strcpy(z,arg0);
  299. X            ee = zexecve(buf,argv);
  300. X            if (ee != ENOENT) eno = ee;
  301. X        }
  302. X    if (eno) zerr("%e: %s",arg0,eno);
  303. X    else zerr("command not found: %s",arg0,0);
  304. X    _exit(1);
  305. X}
  306. X
  307. X#define try(X) { if (iscom(X)) return ztrdup(X); }
  308. X
  309. X/* get the full pathname of an external command */
  310. X
  311. Xchar *findcmd(arg0) /**/
  312. Xchar *arg0;
  313. X{
  314. Xchar **pp;
  315. Xchar *z,*s,buf[MAXCMDLEN];
  316. X
  317. X    cn = (Cmdnam) gethnode(arg0,cmdnamtab);
  318. X    if (!cn && isset(HASHCMDS)) hashcmd(arg0,path);
  319. X    if (cn && cn->type == DISABLED) cn = NULL;
  320. X    if (strlen(arg0) > MAXPATHLEN) return NULL;
  321. X    for (s = arg0; *s; s++)
  322. X        if (*s == '/') {
  323. X            try(arg0);
  324. X            if (arg0 == s || unset(PATHDIRS)) {
  325. X                return NULL;
  326. X            }
  327. X            break;
  328. X        }
  329. X    if (cn && ISEXCMD(cn->type)) {
  330. X        for (pp = path; pp < cn->pcomp; pp++)
  331. X            if (**pp != '/') {
  332. X                z = buf;
  333. X                strucpy(&z,*pp);
  334. X                *z++ = '/';
  335. X                strcpy(z,arg0);
  336. X                try(buf);
  337. X            }
  338. X        try(cn->u.nam);
  339. X    }
  340. X    for (pp = path; *pp; pp++) {
  341. X        z = buf;
  342. X        strucpy(&z,*pp);
  343. X        *z++ = '/';
  344. X        strcpy(z,arg0);
  345. X        try(buf);
  346. X    }
  347. X    return NULL;
  348. X}
  349. X
  350. Xint iscom(s) /**/
  351. Xchar *s;
  352. X{
  353. Xstruct stat statbuf;
  354. X
  355. X    return (access(s,X_OK) == 0 && stat(s,&statbuf) >= 0 &&
  356. X            S_ISREG(statbuf.st_mode));
  357. X}
  358. X
  359. Xint isrelative(s) /**/
  360. Xchar *s;
  361. X{
  362. X    if (*s != '/') return 1;
  363. X    for (; *s; s++)
  364. X        if (*s == '.' && s[-1] == '/' &&
  365. X            (s[1] == '/' || s[1] == '\0' ||
  366. X                (s[1] == '.' && (s[2] == '/' || s[2] == '\0')))) return 1;
  367. X    return 0;
  368. X}
  369. X
  370. Xint hashcmd(arg0,pp) /**/
  371. Xchar *arg0;char **pp;
  372. X{
  373. Xchar *s,buf[MAXPATHLEN];
  374. Xchar **pq;
  375. XDIR *dir;
  376. Xstruct direct *de;
  377. X
  378. X    for (; *pp; pp++)
  379. X        if (**pp == '/') {
  380. X            s = buf;
  381. X            strucpy(&s,*pp);
  382. X            *s++ = '/';
  383. X            strcpy(s,arg0);
  384. X            if (iscom(buf)) break;
  385. X        }
  386. X    if (!*pp || isrelative(*pp)) return 0;
  387. X    cn = (Cmdnam) zcalloc(sizeof *cn);
  388. X    cn->type = EXCMD;
  389. X    cn->pcomp = pp;
  390. X    cn->u.nam = ztrdup(buf);
  391. X    addhnode(ztrdup(arg0),cn,cmdnamtab,freecmdnam);
  392. X    if (unset(HASHDIRS)) return 1;
  393. X    for (pq = pathchecked; pq <= pp; pq++) {
  394. X        if (isrelative(*pq) || !(dir = opendir(*pq))) continue;
  395. X        readdir(dir); readdir(dir);
  396. X        while (de = readdir(dir)) addhcmdnode(de->d_name,pq);
  397. X        closedir(dir);
  398. X    }
  399. X    pathchecked = pp+1;
  400. X    return 1;
  401. X}
  402. X
  403. Xvoid fullhash() /**/
  404. X{
  405. Xchar **pq;
  406. XDIR *dir;
  407. Xstruct direct *de;
  408. X
  409. X    for (pq = pathchecked; *pq; pq++) {
  410. X        if (isrelative(*pq) || !(dir = opendir(*pq))) continue;
  411. X        readdir(dir); readdir(dir);
  412. X        while (de = readdir(dir)) addhcmdnode(de->d_name,pq);
  413. X        closedir(dir);
  414. X    }
  415. X    pathchecked = pq;
  416. X}
  417. X
  418. Xvoid execlist(list) /**/
  419. XList list;
  420. X{
  421. X    if (breaks) return;
  422. X    if (!list) return;
  423. X    simplifyright(list);
  424. X    switch(list->type) {
  425. X        case SYNC:
  426. X        case ASYNC:
  427. X            execlist2(list->left,list->type,!list->right);
  428. X            if (sigtrapped[SIGDEBUG])
  429. X                dotrap(SIGDEBUG);
  430. X            if (sigtrapped[SIGERR] && lastval)
  431. X                dotrap(SIGERR);
  432. X            if (list->right && !retflag) {
  433. X                /* errflag = 0; */
  434. X                execlist(list->right);
  435. X            }
  436. X            break;
  437. X    }
  438. X}
  439. X
  440. Xvoid execlist2(list,type,last1) /**/
  441. XSublist list;int type;int last1;
  442. X{
  443. X    if (!list) return;
  444. X    switch(list->type) {
  445. X        case END:
  446. X            execpline(list,type,last1);
  447. X            break;
  448. X        case ORNEXT:
  449. X            if (!execpline(list,SYNC,0)) execlist2(list->right,type,last1);
  450. X            else while (list = list->right)
  451. X                if (list->type == ANDNEXT) {
  452. X                    execlist2(list->right,type,last1);
  453. X                    return;
  454. X                }
  455. X            break;
  456. X        case ANDNEXT:
  457. X            if (execpline(list,SYNC,0)) execlist2(list->right,type,last1);
  458. X            else while (list = list->right)
  459. X                if (list->type == ORNEXT) {
  460. X                    execlist2(list->right,type,last1);
  461. X                    return;
  462. X                }
  463. X            break;
  464. X    }
  465. X}
  466. X
  467. Xint execpline(l,how,last1) /**/
  468. XSublist l;int how;int last1;
  469. X{
  470. Xint ipipe[2],opipe[2];
  471. X
  472. X    if (!l) return 0;
  473. X    ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0;
  474. X    blockchld();
  475. X    if ((thisjob = getfreejob()) == -1)
  476. X        return 1;
  477. X    initjob();
  478. X    if (how == TIMED) {
  479. X        jobtab[thisjob].stat |= STAT_TIMED;
  480. X        how = SYNC;
  481. X    }
  482. X    if (l->flags & PFLAG_COPROC) {
  483. X        how = ASYNC;
  484. X        if (coprocin >= 0) {
  485. X            close(coprocin);
  486. X            close(coprocout);
  487. X        }
  488. X        mpipe(ipipe);
  489. X        mpipe(opipe);
  490. X        coprocin = ipipe[0];
  491. X        coprocout = opipe[1];
  492. X    }
  493. X    execpline2(l->left,how,opipe[0],ipipe[1],last1);
  494. X    if (how == ASYNC) {
  495. X        if (l->flags & PFLAG_COPROC) close(ipipe[1]);
  496. X        spawnjob();
  497. X        unblockchld();
  498. X        return 1;
  499. X    } else {
  500. X        waitjobs();
  501. X        unblockchld();
  502. X        if (l->flags & PFLAG_NOT) lastval = !lastval;
  503. X        return !lastval;
  504. X    }
  505. X}
  506. X
  507. Xvoid execpline2(pline,how,input,output,last1) /**/
  508. XPline pline;int how;int input;int output;int last1;
  509. X{
  510. Xint pid;
  511. Xint pipes[2];
  512. X
  513. X    if (breaks)
  514. X        return;
  515. X    if (!pline)
  516. X        return;
  517. X    if (pline->type == END) {
  518. X        execcmd(pline->left,input,output,how==ASYNC,last1);
  519. X        pline->left = NULL;
  520. X    } else {
  521. X        mpipe(pipes);
  522. X        if (pline->left->type >= CURSH && how == SYNC) {
  523. X
  524. X            /* if we are doing "foo | bar" where foo is a current
  525. X                shell command, do foo in a subshell and do
  526. X                the rest of the pipeline in the current shell. */
  527. X
  528. X            if (!(pid = fork())) {
  529. X                close(pipes[0]);
  530. X                entersubsh(how==ASYNC);
  531. X                exiting = 1;
  532. X                execcmd(pline->left,input,pipes[1],how==ASYNC,0);
  533. X                _exit(lastval);
  534. X            } else if (pid == -1)
  535. X                zerr("fork failed: %e",NULL,errno);
  536. X            else {
  537. X                char *text = getjobtext((vptr) pline->left);
  538. X                addproc(pid,text);
  539. X            }
  540. X        } else {
  541. X            /* otherwise just do the pipeline normally. */
  542. X            execcmd(pline->left,input,pipes[1],how==ASYNC,0);
  543. X        }
  544. X        pline->left = NULL;
  545. X        close(pipes[1]);
  546. X        if (pline->right) {
  547. X            execpline2(pline->right,how,pipes[0],output,last1);
  548. X            close(pipes[0]);
  549. X        }
  550. X    }
  551. X}
  552. X
  553. X/* make the argv array */
  554. X
  555. Xchar **makecline(list) /**/
  556. Xstruct lklist *list;
  557. X{
  558. Xint ct = 0;
  559. XLknode node;
  560. Xchar **argv,**ptr;
  561. X
  562. X    if (isset(XTRACE)) {
  563. X        fprintf(stderr,"%s",(prompt4) ? prompt4 : "");
  564. X        for (node = firstnode(list); node; incnode(node),ct++);
  565. X        ptr = argv = 2+(char **) ncalloc((ct+4)*sizeof(char *));
  566. X        for (node = firstnode(list); node; incnode(node))
  567. X            if (*(char *) getdata(node)) {
  568. X                *ptr++ = getdata(node);
  569. X                untokenize(getdata(node));
  570. X                fputs(getdata(node),stderr);
  571. X                if (nextnode(node))
  572. X                    fputc(' ',stderr);
  573. X            }
  574. X        *ptr = NULL;
  575. X        fputc('\n',stderr);
  576. X        fflush(stderr);
  577. X        return(argv);
  578. X    } else {
  579. X        for (node = firstnode(list); node; incnode(node),ct++);
  580. X        ptr = argv = 2+(char **) ncalloc((ct+4)*sizeof(char *));
  581. X        for (node = firstnode(list); node; incnode(node))
  582. X            if (*(char *) getdata(node)) {
  583. X                *ptr++ = getdata(node);
  584. X                untokenize(getdata(node));
  585. X            }
  586. X        *ptr = NULL;
  587. X        return(argv);
  588. X    }
  589. X}
  590. X
  591. X/* untokenize the command line and remove null arguments */
  592. X
  593. Xvoid fixcline(l) /**/
  594. XLklist l;
  595. X{
  596. XLknode node,next;
  597. X
  598. X    for (node = firstnode(l); node; node = next) {
  599. X        next = nextnode(node);
  600. X        if (!*(char *) getdata(node)) uremnode(l,node);
  601. X        else untokenize(getdata(node));
  602. X    }
  603. X}
  604. X
  605. Xvoid untokenize(s) /**/
  606. Xchar *s;
  607. X{
  608. X    for (; *s; s++)
  609. X        if (itok(*s))
  610. X            if (*s == Nularg) chuck(s--);
  611. X            else *s = ztokens[*s-Pound];
  612. X}
  613. X
  614. X/* nonzero if we shouldn't clobber a file */
  615. X
  616. Xint dontclob(f) /**/
  617. Xstruct redir *f;
  618. X{
  619. Xstruct stat buf;
  620. X
  621. X    if (unset(NOCLOBBER) || f->type & 1) return 0;
  622. X    if (stat(f->name,&buf) == -1) return 1;
  623. X    return S_ISREG(buf.st_mode);
  624. X}
  625. X
  626. X/* close an multio (success) */
  627. X
  628. Xvoid closemn(mfds,fd) /**/
  629. Xstruct multio **mfds;int fd;
  630. X{
  631. X    if (mfds[fd]) {
  632. X        if (mfds[fd]->ct > 1)
  633. X            if (mfds[fd]->rflag == 0)
  634. X                catproc(mfds[fd]);
  635. X            else
  636. X                teeproc(mfds[fd]);
  637. X        mfds[fd] = NULL;
  638. X    }
  639. X}
  640. X
  641. X/* close all the mnodes (failure) */
  642. X
  643. Xvoid closemnodes(mfds) /**/
  644. Xstruct multio **mfds;
  645. X{
  646. Xint t0,t1;
  647. X
  648. X    for (t0 = 0; t0 != 10; t0++)
  649. X        if (mfds[t0]) {
  650. X            for (t1 = 0; t1 != mfds[t0]->ct; t1++)
  651. X                close(mfds[t0]->fds[t1]);
  652. X            mfds[t0] = NULL;
  653. X        }
  654. X}
  655. X
  656. X/* add a fd to an multio */
  657. X/* an multio is a list of fds associated with a certain fd.
  658. X    thus if you do "foo >bar >ble", the multio for fd 1 will have
  659. X    two fds, the result of open("bar",...), and the result of
  660. X    open("ble",....). */
  661. X
  662. Xvoid addfd(forked,save,mfds,fd1,fd2,rflag) /**/
  663. Xint forked;int *save;struct multio **mfds;int fd1;int fd2;int rflag;
  664. X{
  665. Xint pipes[2];
  666. X
  667. X    if (!mfds[fd1]) {    /* starting a new multio */
  668. X        mfds[fd1] = (struct multio *) alloc(sizeof(struct multio));
  669. X        if (!forked && fd1 != fd2 && fd1 < 10)
  670. X            save[fd1] = movefd(fd1);
  671. X        redup(fd2,fd1);
  672. X        mfds[fd1]->ct = 1;
  673. X        mfds[fd1]->fds[0] = fd1;
  674. X        mfds[fd1]->rflag = rflag;
  675. X    } else {
  676. X        if (mfds[fd1]->rflag != rflag) {
  677. X            zerr("file mode mismatch on fd %d",NULL,fd1);
  678. X            return;
  679. X        }
  680. X        if (mfds[fd1]->ct == 1) {        /* split the stream */
  681. X            mfds[fd1]->fds[0] = movefd(fd1);
  682. X            mfds[fd1]->fds[1] = movefd(fd2);
  683. X            mpipe(pipes);
  684. X            mfds[fd1]->pipe = pipes[1-rflag];
  685. X            redup(pipes[rflag],fd1);
  686. X            mfds[fd1]->ct = 2;
  687. X        } else        /* add another fd to an already split stream */
  688. X            mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2);
  689. X    }
  690. X}
  691. X
  692. Xvoid addvars(l,export) /**/
  693. XLklist l;int export;
  694. X{
  695. Xstruct varasg *v;
  696. XLklist vl;
  697. X
  698. X    while (full(l)) {
  699. X        char **arr,**ptr;
  700. X
  701. X        v = (struct varasg *) ugetnode(l);
  702. X        singsub(&v->name);
  703. X        if (errflag)
  704. X            return;
  705. X        untokenize(v->name);
  706. X        if (v->type == PMFLAG_s) {
  707. X            vl = newlist();
  708. X            addnode(vl,v->str);
  709. X        } else
  710. X            vl = v->arr;
  711. X        prefork(vl);
  712. X        if (errflag)
  713. X            return;
  714. X        postfork(vl,1);
  715. X        if (errflag)
  716. X            return;
  717. X        if (v->type == PMFLAG_s && (empty(vl) || !nextnode(firstnode(vl)))) {
  718. X            Param pm;
  719. X            char *val;
  720. X
  721. X            if (empty(vl))
  722. X                val = ztrdup("");
  723. X            else {
  724. X                untokenize(peekfirst(vl));
  725. X                val = ztrdup(ugetnode(vl));
  726. X            }
  727. X            pm = setsparam(v->name,ztrdup(val));
  728. X            if (export && !(pm->flags & PMFLAG_x))
  729. X                addenv(v->name,val);
  730. X            free(val);
  731. X            continue;
  732. X        }
  733. X        ptr = arr = (char **) zalloc(sizeof(char **)*(countnodes(vl)+1));
  734. X        while (full(vl)) {
  735. X            char *pp;
  736. X            pp = ugetnode(vl);
  737. X            if (*pp) {
  738. X                *ptr = ztrdup(pp);
  739. X                untokenize(*ptr++);
  740. X            }
  741. X        }
  742. X        *ptr = NULL;
  743. X        setaparam(v->name,arr);
  744. X    }
  745. X}
  746. X
  747. Xvoid execcmd(cmd,input,output,bkg,last1) /**/
  748. XCmd cmd;int input;int output;int bkg;int last1;
  749. X{
  750. Xint type;
  751. Xlong pid;
  752. Xint save[10],t0;
  753. Xstruct redir *fn;
  754. Xstruct multio *mfds[10];
  755. Xint fil,forked = 0,iscursh,nullexec = 0;
  756. Xchar *text;
  757. X
  758. X    args = cmd->args;
  759. X    cn = NULL;
  760. X    for (t0 = 0; t0 != 10; t0++) {
  761. X        save[t0] = -1;
  762. X        mfds[t0] = NULL;
  763. X    }
  764. X    if ((type = cmd->type) == SIMPLE && empty(args))
  765. X        if (full(cmd->redir))
  766. X            if (cmd->flags & CFLAG_EXEC) {
  767. X                nullexec = 1;
  768. X            } else if (!*nullcmd) {
  769. X                zerr("redirection with no command",NULL,0);
  770. X                errflag = lastval = 1;
  771. X                return;
  772. X            } else if (*readnullcmd &&
  773. X                    ((Redir)peekfirst(cmd->redir))->type == READ &&
  774. X                    !nextnode(firstnode(cmd->redir))) {
  775. X                addnode(args,strdup(readnullcmd));
  776. X            } else
  777. X                addnode(args,strdup(nullcmd));
  778. X        else {
  779. X            addvars(cmd->vars,0);
  780. X            if (errflag)
  781. X                lastval = 1;
  782. X            return;
  783. X        }
  784. X    if (full(args) && *(char *) peekfirst(args) == '%') {
  785. X        insnode(args,(Lknode) args,strdup((bkg) ? "bg" : "fg"));
  786. X        bkg = 0;
  787. X    }
  788. X    if (isset(AUTORESUME) && !bkg && empty(cmd->redir) && full(args) &&
  789. X            !input && type == SIMPLE && !nextnode(firstnode(args))) {
  790. X        if (unset(NOTIFY)) scanjobs();
  791. X        if (findjobnam(peekfirst(args)) != -1)
  792. X            pushnode(args,strdup("fg"));
  793. X    }
  794. X    if (unset(RMSTARSILENT) && interact && isset(SHINSTDIN) &&
  795. X            type == SIMPLE && full(args) && nextnode(firstnode(args)) &&
  796. X            !strcmp(peekfirst(args),"rm") &&
  797. X            !(cmd->flags & CFLAG_NOGLOB)) {
  798. X        Lknode node, next;
  799. X
  800. X        for (node = nextnode(firstnode(args)); node && !errflag; node = next) {
  801. X            char *s = getdata(node);
  802. X            int l = strlen(s);
  803. X
  804. X            next = nextnode(node);
  805. X            if (s[0] == Star && !s[1]) {
  806. X                if (!checkrmall(pwd)) uremnode(args,node);
  807. X            } else if (l > 2 && s[l-2] == '/' && s[l-1] == Star) {
  808. X                char t = s[l-2];
  809. X                s[l-2] = 0;
  810. X                if (!checkrmall(s)) uremnode(args,node);
  811. X                s[l-2] = t;
  812. X            }
  813. X        }
  814. X        if (!nextnode(firstnode(args))) errflag = 1;
  815. X    }
  816. X    if (jobbing) {    /* get the text associated with this command */
  817. X        text = getjobtext((vptr) cmd);
  818. X    } else text = NULL;
  819. X    prefork(args);    /* do prefork substitutions */
  820. X    if (errflag) {
  821. X        lastval = 1;
  822. X        return;
  823. X    }
  824. X    if (full(args) && ((char*)peekfirst(args))[0] == Inbrack &&
  825. X            ((char*)peekfirst(args))[1] == '\0')
  826. X        ((char*)peekfirst(args))[0] = '[';
  827. X    if (type == SIMPLE && full(args) && !(cmd->flags & CFLAG_COMMAND)) {
  828. X        char *s,*t;
  829. X        cn = (Cmdnam) gethnode(t = s = peekfirst(args),cmdnamtab);
  830. X        if (!cn && isset(HASHCMDS) && strcmp(t,"..")) {
  831. X            while (*t && *t != '/') t++;
  832. X            if (!*t) hashcmd(s,pathchecked);
  833. X        }
  834. X    }
  835. X    if (type == SIMPLE && !cn && isset(AUTOCD) && isset(SHINSTDIN) &&
  836. X            full(args) && empty(cmd->redir) &&
  837. X            !nextnode(firstnode(args)) && cancd(peekfirst(args))) {
  838. X        pushnode(args,strdup("cd"));
  839. X        cn = (Cmdnam) gethnode("cd",cmdnamtab);
  840. X    }
  841. X
  842. X    /* this is nonzero if cmd is a current shell procedure */
  843. X
  844. X    iscursh = (type >= CURSH) || (type == SIMPLE && cn &&
  845. X        (cn->type == BUILTIN || cn->type == SHFUNC));
  846. X
  847. X    /* if this command is backgrounded or (this is an external
  848. X        command and we are not exec'ing it) or this is a builtin
  849. X        with output piped somewhere, then fork.  If this is the
  850. X        last stage in a subshell pipeline, don't fork, but make
  851. X        the rest of the function think we forked. */
  852. X
  853. X    if (bkg || !(iscursh || (cmd->flags & CFLAG_EXEC)) ||
  854. X            (cn && (cn->type == BUILTIN || cn->type == SHFUNC) && output)) {
  855. X        int synch[2];
  856. X
  857. X        pipe(synch);
  858. X        pid = (last1 && execok()) ? 0 : phork();
  859. X        if (pid == -1) {
  860. X            close(synch[0]);
  861. X            close(synch[1]);
  862. X            return;
  863. X        }
  864. X        if (pid) {
  865. X            close(synch[1]);
  866. X            read(synch[0],"foo",1);
  867. X            close(synch[0]);
  868. X            if (pid == -1)
  869. X                zerr("%e",NULL,errno);
  870. X            else {
  871. X                if (bkg) lastpid = pid;
  872. X                ( void ) addproc(pid,text);
  873. X            }
  874. X            return;
  875. X        }
  876. X        close(synch[0]);
  877. X        entersubsh(bkg);
  878. X        close(synch[1]);
  879. X        forked = 1;
  880. X    }
  881. X    if (bkg && isset(BGNICE))
  882. X        nice(5);
  883. X
  884. X    /* perform postfork substitutions */
  885. X    postfork(args,!(cmd->flags & CFLAG_NOGLOB));
  886. X    if (errflag) {
  887. X        lastval = 1;
  888. X        goto err;
  889. X    } else {
  890. X        char *s;
  891. X        while (full(args) && (s = peekfirst(args)) && !*s) ugetnode(args);
  892. X    }
  893. X
  894. X    if (input)        /* add pipeline input/output to mnodes */
  895. X        addfd(forked,save,mfds,0,input,0);
  896. X    if (output)
  897. X        addfd(forked,save,mfds,1,output,1);
  898. X    spawnpipes(cmd->redir);        /* do process substitutions */
  899. X    while (full(cmd->redir))
  900. X        if ((fn = (struct redir*) ugetnode(cmd->redir))->type == INPIPE) {
  901. X            if (fn->fd2 == -1) {
  902. X                fixfds(save);
  903. X                execerr();
  904. X            }
  905. X            addfd(forked,save,mfds,fn->fd1,fn->fd2,0);
  906. X        } else if (fn->type == OUTPIPE) {
  907. X            if (fn->fd2 == -1) {
  908. X                fixfds(save);
  909. X                execerr();
  910. X            }
  911. X            addfd(forked,save,mfds,fn->fd1,fn->fd2,1);
  912. X        } else {
  913. X            if (!(fn->type == HERESTR || fn->type == CLOSE || fn->type ==
  914. X                    MERGE || fn->type == MERGEOUT))
  915. X                if (xpandredir(fn,cmd->redir))
  916. X                    continue;
  917. X            if (errflag) {
  918. X                fixfds(save);
  919. X                execerr();
  920. X            }
  921. X            if (fn->type == HERESTR) {
  922. X                fil = getherestr(fn);
  923. X                if (fil == -1) {
  924. X                    fixfds(save);
  925. X                    if (errno != EINTR)
  926. X                        zerr("%e",NULL,errno);
  927. X                    execerr();
  928. X                }
  929. X                addfd(forked,save,mfds,fn->fd1,fil,0);
  930. X            } else if (fn->type == READ) {
  931. X                fil = open(fn->name,O_RDONLY);
  932. X                if (fil == -1) {
  933. X                    fixfds(save);
  934. X                    if (errno != EINTR)
  935. X                        zerr("%e: %s",fn->name,errno);
  936. X                    execerr();
  937. X                }
  938. X                addfd(forked,save,mfds,fn->fd1,fil,0);
  939. X            } else if (fn->type == CLOSE) {
  940. X                if (!forked && fn->fd1 < 10)
  941. X                    save[fn->fd1] = movefd(fn->fd1);
  942. X                closemn(mfds,fn->fd1);
  943. X                close(fn->fd1);
  944. X            } else if (fn->type == MERGE || fn->type == MERGEOUT) {
  945. X                if (fn->fd2 == FD_COPROC)
  946. X                    fn->fd2 = (fn->type == MERGEOUT) ? coprocout : coprocin;
  947. X                closemn(mfds,fn->fd1);
  948. X                fil = dup(fn->fd2);
  949. X                if (fil == -1) {
  950. X                    char fdstr[4];
  951. X                    fixfds(save);
  952. X                    sprintf(fdstr,"%d",fn->fd2);
  953. X                    zerr("%s: %e",fdstr,errno);
  954. X                    execerr();
  955. X                }
  956. X                addfd(forked,save,mfds,fn->fd1,fil,fn->type == MERGEOUT);
  957. X            } else {
  958. X                if (fn->type >= APP)
  959. X                    fil = open(fn->name,
  960. X                        (isset(NOCLOBBER) && !(fn->type & 1)) ?
  961. X                        O_WRONLY|O_APPEND : O_WRONLY|O_APPEND|O_CREAT,0666);
  962. X                else
  963. X                    fil = open(fn->name,dontclob(fn) ? 
  964. X                        O_WRONLY|O_CREAT|O_EXCL : O_WRONLY|O_CREAT|O_TRUNC,0666);
  965. X                if (fil == -1) {
  966. X                    fixfds(save);
  967. X                    if (errno != EINTR)
  968. X                        zerr("%e: %s",fn->name,errno);
  969. X                    execerr();
  970. X                }
  971. X                addfd(forked,save,mfds,fn->fd1,fil,1);
  972. X            }
  973. X        }
  974. X    
  975. X    /* we are done with redirection.  close the mnodes, spawning
  976. X        tee/cat processes as necessary. */
  977. X    for (t0 = 0; t0 != 10; t0++)
  978. X        closemn(mfds,t0);
  979. X
  980. X    if (nullexec) {
  981. X        for (t0 = 0; t0 != 10; t0++)
  982. X            if (save[t0] != -1)
  983. X                close(save[t0]);
  984. X        return;
  985. X    }
  986. X    if (unset(NOEXEC))
  987. X        if (type >= CURSH)
  988. X            {
  989. X            static int (*func[]) DCLPROTO((Cmd)) = {
  990. X                execcursh,exectime,execfuncdef,execfor,execwhile,
  991. X                execrepeat,execif,execcase,execselect,execcond };
  992. X    
  993. X            fixcline(args);
  994. X            lastval = (func[type-CURSH])(cmd);
  995. X            }
  996. X        else if (iscursh)        /* builtin or shell function */
  997. X            {
  998. X            if (!cn) {
  999. X                lastval = 1;
  1000. X                return;
  1001. X            }
  1002. X            if (cmd->vars) {
  1003. X                addvars(cmd->vars,0);
  1004. X                if (errflag) {
  1005. X                    lastval = 1;
  1006. X                    return;
  1007. X                }
  1008. X            }
  1009. X            fixcline(args);
  1010. X            if (cn->type == SHFUNC)
  1011. X                execshfunc(cmd,cn);
  1012. X            else
  1013. X                {
  1014. X                if (forked) closem();
  1015. X                lastval = execbin(args,cn);
  1016. X                if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
  1017. X                        lastval && !subsh) {
  1018. X                    fprintf(stderr,"zsh: exit %d\n",lastval);
  1019. X                }
  1020. X                fflush(stdout);
  1021. X                if (ferror(stdout))
  1022. X                    {
  1023. X                    zerr("write error: %e",NULL,errno);
  1024. X                    clearerr(stdout);
  1025. X                    }
  1026. X                }
  1027. X            }
  1028. X        else
  1029. X            {
  1030. X            if (cmd->vars) {
  1031. X                addvars(cmd->vars,1);
  1032. X                if (errflag) {
  1033. X                    lastval = 1;
  1034. X                    return;
  1035. X                }
  1036. X            }
  1037. X            if (type == SIMPLE)
  1038. X                {
  1039. X                closem();
  1040. X                execute(cmd->flags & CFLAG_DASH);
  1041. X                }
  1042. X            else    /* ( ... ) */
  1043. X                execlist(cmd->u.list);
  1044. X            }
  1045. Xerr:
  1046. X    if (forked)
  1047. X        _exit(lastval);
  1048. X    fixfds(save);
  1049. X}
  1050. X
  1051. X/* restore fds after redirecting a builtin */
  1052. X
  1053. Xvoid fixfds(save) /**/
  1054. Xint *save;
  1055. X{
  1056. Xint old_errno = errno;
  1057. Xint t0;
  1058. X
  1059. X    for (t0 = 0; t0 != 10; t0++)
  1060. X        if (save[t0] != -1)
  1061. X            redup(save[t0],t0);
  1062. X    errno = old_errno;
  1063. X}
  1064. X
  1065. Xvoid entersubsh(bkg) /**/
  1066. Xint bkg;
  1067. X{
  1068. X    if (!jobbing)
  1069. X        {
  1070. X        if (bkg && isatty(0))
  1071. X            {
  1072. X            close(0);
  1073. X            if (open("/dev/null",O_RDWR))
  1074. X                {
  1075. X                zerr("can't open /dev/null: %e",NULL,errno);
  1076. X                _exit(1);
  1077. X                }
  1078. X            }
  1079. X        }
  1080. X    else if (!jobtab[thisjob].gleader)
  1081. X        {
  1082. X        jobtab[thisjob].gleader = getpid();
  1083. X        setpgrp(0L,jobtab[thisjob].gleader);
  1084. X        if (!bkg)
  1085. X            attachtty(jobtab[thisjob].gleader);
  1086. X        }
  1087. X    else
  1088. X        setpgrp(0L,jobtab[thisjob].gleader);
  1089. X    subsh = 1;
  1090. X    if (SHTTY != -1)
  1091. X        {
  1092. X        close(SHTTY);
  1093. X        SHTTY = -1;
  1094. X        }
  1095. X    if (jobbing)
  1096. X        {
  1097. X        signal(SIGTTOU,SIG_DFL);
  1098. X        signal(SIGTTIN,SIG_DFL);
  1099. X        signal(SIGTSTP,SIG_DFL);
  1100. X        signal(SIGPIPE,SIG_DFL);
  1101. X        }
  1102. X    if (interact)
  1103. X        {
  1104. X        signal(SIGTERM,SIG_DFL);
  1105. X        if (sigtrapped[SIGINT] != 2)
  1106. X            signal(SIGINT, SIG_DFL);
  1107. X        }
  1108. X    if (sigtrapped[SIGQUIT] != 2)
  1109. X        signal(SIGQUIT,SIG_DFL);
  1110. X    opts[MONITOR] = OPT_UNSET;
  1111. X    clearjobtab();
  1112. X}
  1113. X
  1114. X/* close all internal shell fds */
  1115. X
  1116. Xvoid closem() /**/
  1117. X{
  1118. Xint t0;
  1119. X
  1120. X    for (t0 = 10; t0 != NOFILE; t0++)
  1121. X        close(t0);
  1122. X}
  1123. X
  1124. X/* convert here document into a here string */
  1125. X
  1126. Xchar *gethere(str,typ) /**/
  1127. Xchar *str;int typ;
  1128. X{
  1129. Xchar pbuf[256];
  1130. Xint qt = 0,siz = 0,l,strip = 0;
  1131. Xchar *s,*t,*bptr;
  1132. X
  1133. X    for (s = str; *s; s++)
  1134. X        if (INULL(*s))
  1135. X            {
  1136. X            *s = Nularg;
  1137. X            qt = 1;
  1138. X            }
  1139. X    untokenize(str);
  1140. X    if (typ == HEREDOCDASH)
  1141. X        {
  1142. X        strip = 1;
  1143. X        while (*str == '\t')
  1144. X            str++;
  1145. X        }
  1146. X    t = ztrdup("");
  1147. X    for(;;)
  1148. X        {
  1149. X        char *u,*v;
  1150. X
  1151. X        if (!hgets(pbuf,sizeof(pbuf)))
  1152. X            break;
  1153. X        bptr = pbuf;
  1154. X        if (strip)
  1155. X            while (*bptr == '\t')
  1156. X                bptr++;
  1157. X        for (u = bptr, v = str; *u != '\n' && *v; u++,v++)
  1158. X            if (*u != *v)
  1159. X                break;
  1160. X        if (!(*u == '\n' && !*v))
  1161. X            {
  1162. X            l = strlen(bptr);
  1163. X            if (!qt && l > 1 && bptr[l-1] == '\n' && bptr[l-2] == '\\')
  1164. X                bptr[l -= 2] = '\0';
  1165. X            t = realloc(t,siz+l+1);
  1166. X            strncpy(t+siz,bptr,l);
  1167. X            siz += l;
  1168. X            }
  1169. X        else
  1170. X            break;
  1171. X        }
  1172. X    t[siz] = '\0';
  1173. X    if (siz && t[siz-1] == '\n')
  1174. X        t[siz-1] = '\0';
  1175. X    if (!qt)
  1176. X        for (s = t; *s; s++)
  1177. X            if (*s == '$') {
  1178. X                *s = Qstring;
  1179. X            } else if (*s == '`') {
  1180. X                *s = Qtick;
  1181. X            } else if (*s == '(') {
  1182. X                *s = Inpar;
  1183. X            } else if (*s == ')') {
  1184. X                *s = Outpar;
  1185. X            } else if (*s == '\\' &&
  1186. X                (s[1] == '$' || s[1] == '`')) chuck(s);
  1187. X    s = strdup(t);
  1188. X    free(t);
  1189. X    return s;
  1190. X}
  1191. X
  1192. X/* open here string fd */
  1193. X
  1194. Xint getherestr(fn) /**/
  1195. Xstruct redir *fn;
  1196. X{
  1197. XLklist fake;
  1198. Xchar *s = gettemp(),*t;
  1199. Xint fd;
  1200. X
  1201. X    fake = newlist();
  1202. X    addnode(fake,fn->name);
  1203. X    prefork(fake);
  1204. X    if (!errflag)
  1205. X        postfork(fake,1);
  1206. X    if (errflag)
  1207. X        return -1;
  1208. X    if ((fd = open(s,O_CREAT|O_WRONLY,0600)) == -1)
  1209. X        return -1;
  1210. X    while (t = ugetnode(fake))
  1211. X        {
  1212. X        untokenize(t);
  1213. X        write(fd,t,strlen(t));
  1214. X        if (full(fake))
  1215. X            write(fd," ",1);
  1216. X        }
  1217. X    write(fd,"\n",1);
  1218. X    close(fd);
  1219. X    fd = open(s,O_RDONLY);
  1220. X    unlink(s);
  1221. X    return fd;
  1222. X}
  1223. X
  1224. Xvoid catproc(mn) /**/
  1225. Xstruct multio *mn;
  1226. X{
  1227. Xint len,t0;
  1228. Xchar *buf;
  1229. X
  1230. X    if (phork())
  1231. X        {
  1232. X        for (t0 = 0; t0 != mn->ct; t0++)
  1233. X            close(mn->fds[t0]);
  1234. X        close(mn->pipe);
  1235. X        return;
  1236. X        }
  1237. X    closeallelse(mn);
  1238. X    buf = zalloc(4096);
  1239. X    for (t0 = 0; t0 != mn->ct; t0++)
  1240. X        while (len = read(mn->fds[t0],buf,4096))
  1241. X            write(mn->pipe,buf,len);
  1242. X    _exit(0);
  1243. X}
  1244. Xvoid teeproc(mn) /**/
  1245. Xstruct multio *mn;
  1246. X{
  1247. Xint len,t0;
  1248. Xchar *buf;
  1249. X
  1250. X    if (phork())
  1251. X        {
  1252. X        for (t0 = 0; t0 != mn->ct; t0++)
  1253. X            close(mn->fds[t0]);
  1254. X        close(mn->pipe);
  1255. X        return;
  1256. X        }
  1257. X    buf = zalloc(4096);
  1258. X    closeallelse(mn);
  1259. X    while ((len = read(mn->pipe,buf,4096)) > 0)
  1260. X        for (t0 = 0; t0 != mn->ct; t0++)
  1261. X            write(mn->fds[t0],buf,len);
  1262. X    _exit(0);
  1263. X}
  1264. X
  1265. Xvoid closeallelse(mn) /**/
  1266. Xstruct multio *mn;
  1267. X{
  1268. Xint t0,t1;
  1269. X
  1270. X    for (t0 = 0; t0 != NOFILE; t0++)
  1271. X        if (mn->pipe != t0)
  1272. X            {
  1273. X            for (t1 = 0; t1 != mn->ct; t1++)
  1274. X                if (mn->fds[t1] == t0)
  1275. X                    break;
  1276. X            if (t1 == mn->ct)
  1277. X                close(t0);
  1278. X            }
  1279. X}
  1280. X
  1281. Xlong int zstrtol(s,t,base) /**/
  1282. Xchar *s;char **t;int base;
  1283. X{
  1284. Xint ret = 0;
  1285. X
  1286. X    if (base <= 10)
  1287. X        for (; *s >= '0' && *s < ('0'+base); s++)
  1288. X            ret = ret*base+*s-'0';
  1289. X    else
  1290. X        for (; idigit(*s) || (*s >= 'a' && *s < ('a'+base-10))
  1291. X                                || (*s >= 'A' && *s < ('A'+base-10)); s++)
  1292. X            ret = ret*base+(idigit(*s) ? (*s-'0') : (*s & 0x1f)+9);
  1293. X    if (t)
  1294. X        *t = (char *) s;
  1295. X    return ret;
  1296. X}
  1297. X
  1298. X/* $(...) */
  1299. X
  1300. XLklist getoutput(cmd,qt) /**/
  1301. Xchar *cmd;int qt;
  1302. X{
  1303. XList list;
  1304. Xint pipes[2];
  1305. Xint pid;
  1306. Xint status;
  1307. X
  1308. X    if (*cmd == '<') {
  1309. X        int stream;
  1310. X        char *fi,*s,x;
  1311. X
  1312. X        for (cmd++; *cmd == ' '; cmd++);
  1313. X        for (s = cmd; *s && *s != ' '; s++)
  1314. X            if (*s == '\\') s++;
  1315. X            else if (*s == '$') *s = String;
  1316. X        x = *s;
  1317. X        *s = '\0';
  1318. X        fi = strdup(cmd);
  1319. X        *s = x;
  1320. X        if (*fi == '~')
  1321. X            *fi = Tilde;
  1322. X        else if (*fi == '=')
  1323. X            *fi = Equals;
  1324. X        singsub(&fi);
  1325. X        if (errflag)
  1326. X            return NULL;
  1327. X        stream = open(fi,O_RDONLY);
  1328. X        if (stream == -1) {
  1329. X            zerr("%e: %s",fi,errno);
  1330. X            return NULL;
  1331. X        }
  1332. X        return readoutput(stream,qt);
  1333. X    }
  1334. X    if (!(list = parselstring(cmd)))
  1335. X        return NULL;
  1336. X    mpipe(pipes);
  1337. X    if ((cmdoutpid = pid = phork()) > 0)
  1338. X        {
  1339. X        Lklist retval;
  1340. X
  1341. X        popheap();
  1342. X        close(pipes[1]);
  1343. X#ifdef WAITPID
  1344. X        retval =  readoutput(pipes[0],qt);
  1345. X        waitpid(pid,&status,0);
  1346. X#else
  1347. X        blockchld();
  1348. X        retval =  readoutput(pipes[0],qt);
  1349. X        if (kill(pid, 0) >= 0)
  1350. X            {
  1351. X            unblockchld();
  1352. X            chldsuspend();
  1353. X            }
  1354. X        else
  1355. X            unblockchld();
  1356. X#endif
  1357. X        lastval = cmdoutval;
  1358. X        cmdoutval = 0;
  1359. X        return retval;
  1360. X        }
  1361. X     else if (pid == -1)
  1362. X        {
  1363. X        popheap();
  1364. X        close(pipes[0]);
  1365. X        close(pipes[1]);
  1366. X        errflag = 1;
  1367. X        cmdoutpid = 0;
  1368. X        return NULL;
  1369. X        }
  1370. X    subsh = 1;
  1371. X    close(pipes[0]);
  1372. X    redup(pipes[1],1);
  1373. X    entersubsh(0);
  1374. X    signal(SIGTSTP,SIG_IGN);
  1375. X    exiting = 1;
  1376. X    execlist(list);
  1377. X    close(1);
  1378. X    _exit(lastval);
  1379. X    zerr("exit returned in child!!",NULL,0);
  1380. X    kill(getpid(),SIGKILL);
  1381. X}
  1382. X
  1383. X/* read output of command substitution */
  1384. X
  1385. XLklist readoutput(in,qt) /**/
  1386. Xint in;int qt;
  1387. X{
  1388. XLklist ret;
  1389. Xchar *buf,*ptr;
  1390. Xint bsiz,c,cnt = 0;
  1391. XFILE *fin;
  1392. X
  1393. X    fin = fdopen(in,"r");
  1394. X    ret = newlist();
  1395. X    ptr = buf = ncalloc(bsiz = 64);
  1396. X    if (qt) {
  1397. X        *ptr++ = Nularg;
  1398. X        cnt++;
  1399. X    }
  1400. X    while ((c = fgetc(fin)) != EOF)
  1401. X        if (!qt && isep(c)) {
  1402. X            if (cnt) {
  1403. X                *ptr = '\0';
  1404. X                addnode(ret,buf);
  1405. X                ptr = buf = ncalloc(bsiz = 64);
  1406. X                cnt = 0;
  1407. X            }
  1408. X        } else {
  1409. X            *ptr++ = c;
  1410. X            if (++cnt == bsiz) {
  1411. X                char *pp = ncalloc(bsiz *= 2);
  1412. X                
  1413. X                memcpy(pp,buf,cnt);
  1414. X                ptr = (buf = pp)+cnt;
  1415. X            }
  1416. X        }
  1417. X    if (ptr != buf && ptr[-1] == '\n')
  1418. X        ptr[-1] = '\0';
  1419. X    else
  1420. X        *ptr = '\0';
  1421. X    if (cnt) addnode(ret,buf);
  1422. X    fclose(fin);
  1423. X    return ret;
  1424. X}
  1425. X
  1426. X/* =(...) */
  1427. X
  1428. Xchar *getoutputfile(cmd) /**/
  1429. Xchar *cmd;
  1430. X{
  1431. X#ifdef WAITPID
  1432. Xint pid;
  1433. X#endif
  1434. Xchar *nam = gettemp(),*str;
  1435. XList list;
  1436. X
  1437. X    if (thisjob == -1)
  1438. X        return NULL;
  1439. X    for (str = cmd; *str && *str != Outpar; str++);
  1440. X    if (!*str)
  1441. X        zerr("oops.",NULL,0);
  1442. X    *str = '\0';
  1443. X    if (!(list = parselstring(cmd)))
  1444. X        return NULL;
  1445. X    permalloc();
  1446. X    if (!jobtab[thisjob].filelist)
  1447. X        jobtab[thisjob].filelist = newlist();
  1448. X    addnode(jobtab[thisjob].filelist,ztrdup(nam));
  1449. X    heapalloc();
  1450. X#ifdef WAITPID
  1451. X    if (pid = phork())
  1452. X        {
  1453. X        popheap();
  1454. X        waitpid(pid,NULL,WUNTRACED);
  1455. X        return nam;
  1456. X        }
  1457. X#else
  1458. X    if (waitfork()) {
  1459. X        popheap();
  1460. X        return nam;
  1461. X    }
  1462. X#endif
  1463. X    subsh = 1;
  1464. X    close(1);
  1465. X    entersubsh(0);
  1466. X    (void) creat(nam,0666);
  1467. X    exiting = 1;
  1468. X    execlist(list);
  1469. X    close(1);
  1470. X    _exit(lastval);
  1471. X    zerr("exit returned in child!!",NULL,0);
  1472. X    kill(getpid(),SIGKILL);
  1473. X}
  1474. X
  1475. X/* get a temporary named pipe */
  1476. X
  1477. Xchar *namedpipe() /**/
  1478. X{
  1479. X#ifndef NO_FIFOS
  1480. Xchar *tnam = gettemp();
  1481. X
  1482. X    if (mknod(tnam,0010666,0) < 0) return NULL;
  1483. X    return tnam;
  1484. X#else
  1485. X    return NULL;
  1486. X#endif
  1487. X}
  1488. X
  1489. X/* <(...) */
  1490. X
  1491. Xchar *getoutproc(cmd) /**/
  1492. Xchar *cmd;
  1493. X{
  1494. X#ifdef NO_FIFOS
  1495. X    zerr("doesn't look like your system supports FIFOs.",NULL,0);
  1496. X    return NULL;
  1497. X#else
  1498. XList list;
  1499. Xint fd;
  1500. Xchar *pnam,*str;
  1501. X
  1502. X    if (thisjob == -1)
  1503. X        return NULL;
  1504. X    for (str = cmd; *str && *str != Outpar; str++);
  1505. X    if (!*str)
  1506. X        zerr("oops.",NULL,0);
  1507. X    *str = '\0';
  1508. X    pnam = namedpipe();
  1509. X    if (!pnam) return NULL;
  1510. X    permalloc();
  1511. X    if (!jobtab[thisjob].filelist)
  1512. X        jobtab[thisjob].filelist = newlist();
  1513. X    addnode(jobtab[thisjob].filelist,ztrdup(pnam));
  1514. X    heapalloc();
  1515. X    if (!(list = parselstring(cmd)))
  1516. X        return NULL;
  1517. X    if (phork())
  1518. X        {
  1519. X        popheap();
  1520. X        return pnam;
  1521. X        }
  1522. X    entersubsh(1);
  1523. X    closem();
  1524. X    fd = open(pnam,O_WRONLY);
  1525. X    if (fd == -1)
  1526. X        {
  1527. X        zerr("can't open %s: %e",pnam,errno);
  1528. X        _exit(1);
  1529. X        }
  1530. X    redup(fd,1);
  1531. X    fd = open("/dev/null",O_RDONLY);
  1532. X    redup(fd,0);
  1533. X    exiting = 1;
  1534. X    execlist(list);
  1535. X    close(1);
  1536. X    _exit(lastval);  return NULL;
  1537. X#endif
  1538. X}
  1539. X
  1540. X/* >(...) */
  1541. X
  1542. Xchar *getinproc(cmd) /**/
  1543. Xchar *cmd;
  1544. X{
  1545. X#ifdef NO_FIFOS
  1546. X    zerr("doesn't look like your system supports FIFOs.",NULL,0);
  1547. X    return NULL;
  1548. X#else
  1549. XList list;
  1550. Xint pid,fd;
  1551. Xchar *pnam,*str;
  1552. X
  1553. X    if (thisjob == -1)
  1554. X        return NULL;
  1555. X    for (str = cmd; *str && *str != Outpar; str++);
  1556. X    if (!*str)
  1557. X        zerr("oops.",NULL,0);
  1558. X    *str = '\0';
  1559. X    pnam = namedpipe();
  1560. X    if (!pnam) return NULL;
  1561. X    permalloc();
  1562. X    if (!jobtab[thisjob].filelist)
  1563. X        jobtab[thisjob].filelist = newlist();
  1564. X    addnode(jobtab[thisjob].filelist,ztrdup(pnam));
  1565. X    heapalloc();
  1566. X    if (!(list = parselstring(cmd)))
  1567. X        return NULL;
  1568. X    if (pid = phork())
  1569. X        {
  1570. X        popheap();
  1571. X        return pnam;
  1572. X        }
  1573. X    entersubsh(1);
  1574. X    closem();
  1575. X    fd = open(pnam,O_RDONLY);
  1576. X    redup(fd,0);
  1577. X    exiting = 1;
  1578. X    execlist(list);
  1579. X    _exit(lastval);  return NULL;
  1580. X#endif
  1581. X}
  1582. X
  1583. X/* > >(...) (does not use named pipes) */
  1584. X
  1585. Xint getinpipe(cmd) /**/
  1586. Xchar *cmd;
  1587. X{
  1588. XList list;
  1589. Xint pipes[2];
  1590. Xchar *str;
  1591. X
  1592. X    for (str = cmd; *str && *str != Outpar; str++);
  1593. X    if (!*str)
  1594. X        zerr("oops.",NULL,0);
  1595. X    *str = '\0';
  1596. X    if (!(list = parselstring(cmd+2)))
  1597. X        return -1;
  1598. X    mpipe(pipes);
  1599. X    if (phork())
  1600. X        {
  1601. X        popheap();
  1602. X        close(pipes[1]);
  1603. X        return pipes[0];
  1604. X        }
  1605. X    close(pipes[0]);
  1606. X    closem();
  1607. X    entersubsh(1);
  1608. X    redup(pipes[1],1);
  1609. X    exiting = 1;
  1610. X    execlist(list);
  1611. X    _exit(lastval);  return 0;
  1612. X}
  1613. X
  1614. X/* < <(...) */
  1615. X
  1616. Xint getoutpipe(cmd) /**/
  1617. Xchar *cmd;
  1618. X{
  1619. XList list;
  1620. Xint pipes[2];
  1621. Xchar *str;
  1622. X
  1623. X    for (str = cmd; *str && *str != Outpar; str++);
  1624. X    if (!*str)
  1625. X        zerr("oops.",NULL,0);
  1626. X    *str = '\0';
  1627. X    if (!(list = parselstring(cmd+2)))
  1628. X        return -1;
  1629. X    strinend();
  1630. X    mpipe(pipes);
  1631. X    if (phork())
  1632. X        {
  1633. X        popheap();
  1634. X        close(pipes[0]);
  1635. X        return pipes[1];
  1636. X        }
  1637. X    close(pipes[1]);
  1638. X    entersubsh(1);
  1639. X    redup(pipes[0],0);
  1640. X    closem();
  1641. X    exiting = 1;
  1642. X    execlist(list);
  1643. X    _exit(lastval);  return 0;
  1644. X}
  1645. X
  1646. X/* run a list, saving the current job num */
  1647. X
  1648. Xvoid runlist(l) /**/
  1649. XList l;
  1650. X{
  1651. Xint cj = thisjob;
  1652. X
  1653. X    execlist(l);
  1654. X    thisjob = cj;
  1655. X}
  1656. X
  1657. Xchar *gettemp() /**/
  1658. X{
  1659. X    return mktemp(dyncat(tmpprefix,"XXXXXX"));
  1660. X}
  1661. X
  1662. X/* my getwd; all the other ones I tried confused the SIGCHLD handler */
  1663. X
  1664. Xchar *zgetwd() /**/
  1665. X{
  1666. Xstatic char buf0[MAXPATHLEN];
  1667. Xchar buf3[MAXPATHLEN];
  1668. X#ifdef apollo
  1669. Xchar *buf2 = buf0+2; /* changed +1 to +2  RBC 17.11.91 */
  1670. X#else
  1671. Xchar *buf2 = buf0+1;
  1672. X#endif
  1673. Xstruct stat sbuf;
  1674. Xstruct direct *de;
  1675. XDIR *dir;
  1676. Xino_t ino, rootino = ~0;
  1677. Xdev_t dev, rootdev = ~0;
  1678. X
  1679. X    holdintr();
  1680. X    buf2[0] = '\0';
  1681. X    buf0[0] = '/';
  1682. X#ifdef apollo    
  1683. X    buf0[1] = '/'; /* added RBC 17.11.91 */
  1684. X#endif    
  1685. X    if (stat(buf0,&sbuf) >= 0)
  1686. X        {
  1687. X        rootino = sbuf.st_ino;
  1688. X        rootdev = sbuf.st_dev;
  1689. X        }
  1690. X    for(;;)
  1691. X        {
  1692. X        if (stat(".",&sbuf) < 0)
  1693. X            {
  1694. X            chdir(buf0);
  1695. X            noholdintr();
  1696. X            return ztrdup(".");
  1697. X            }
  1698. X        ino = sbuf.st_ino;
  1699. X        dev = sbuf.st_dev;
  1700. X        if (stat("..",&sbuf) < 0)
  1701. X            {
  1702. X            chdir(buf0);
  1703. X            noholdintr();
  1704. X            return ztrdup(".");
  1705. X            }
  1706. X        if ((sbuf.st_ino == ino && sbuf.st_dev == dev) ||
  1707. X            (ino == rootino && dev == rootdev))
  1708. X            {
  1709. X            chdir(buf0);
  1710. X            noholdintr();
  1711. X            return ztrdup(buf0);
  1712. X            }
  1713. X        dir = opendir("..");
  1714. X        if (!dir)
  1715. X            {
  1716. X            chdir(buf0);
  1717. X            noholdintr();
  1718. X            return ztrdup(".");
  1719. X            }
  1720. X        chdir("..");
  1721. X        readdir(dir); readdir(dir);
  1722. X        while (de = readdir(dir))
  1723. X            if (de->d_ino == ino)
  1724. X                {
  1725. X                lstat(de->d_name,&sbuf);
  1726. X                if (sbuf.st_dev == dev)
  1727. X                    goto match;
  1728. X                }
  1729. X        rewinddir(dir);
  1730. X        readdir(dir); readdir(dir);
  1731. X        while (de = readdir(dir))
  1732. X            {
  1733. X            lstat(de->d_name,&sbuf);
  1734. X            if (sbuf.st_dev == dev)
  1735. X                goto match;
  1736. X            }
  1737. X        noholdintr();
  1738. X        closedir(dir);
  1739. X        return ztrdup(".");
  1740. Xmatch:
  1741. X        strcpy(buf3,de->d_name);
  1742. X        if (*buf2)
  1743. X            strcat(buf3,"/");
  1744. X        strcat(buf3,buf2);
  1745. X        strcpy(buf2,buf3);
  1746. X        closedir(dir);
  1747. X        }
  1748. X}
  1749. X
  1750. X/* open pipes with fds >= 10 */
  1751. X
  1752. Xvoid mpipe(pp) /**/
  1753. Xint *pp;
  1754. X{
  1755. X    pipe(pp);
  1756. X    pp[0] = movefd(pp[0]);
  1757. X    pp[1] = movefd(pp[1]);
  1758. X}
  1759. X
  1760. X/* do process substitution with redirection */
  1761. X
  1762. Xvoid spawnpipes(l) /**/
  1763. XLklist l;
  1764. X{
  1765. XLknode n = firstnode(l);
  1766. XRedir f;
  1767. X
  1768. X    for (; n; incnode(n))
  1769. X        {
  1770. X        f = (Redir) getdata(n);
  1771. X        if (f->type == OUTPIPE)
  1772. X            {
  1773. X            char *str = f->name;
  1774. X            f->fd2 = getoutpipe(str);
  1775. X            }
  1776. X        if (f->type == INPIPE)
  1777. X            {
  1778. X            char *str = f->name;
  1779. X            f->fd2 = getinpipe(str);
  1780. X            }
  1781. X        }
  1782. X}
  1783. X
  1784. X/* perform time ... command */
  1785. X
  1786. Xint exectime(cmd) /**/
  1787. XCmd cmd;
  1788. X{
  1789. Xint jb = thisjob;
  1790. X
  1791. X    if (!cmd->u.pline) { shelltime(); return 0; }
  1792. X    execpline(cmd->u.pline,TIMED,0);
  1793. X    thisjob = jb;
  1794. X    return lastval;
  1795. X}
  1796. X
  1797. X/* define a function */
  1798. X
  1799. Xint execfuncdef(cmd) /**/
  1800. XCmd cmd;
  1801. X{
  1802. XCmdnam cc;
  1803. Xchar *s;
  1804. X
  1805. X    permalloc();
  1806. X    while (s = ugetnode(cmd->args))
  1807. X        {
  1808. X        cc = (Cmdnam) zalloc(sizeof *cc);
  1809. X        cc->type = SHFUNC;
  1810. X        cc->flags = 0;
  1811. X        if (!cmd->u.list)
  1812. X            cc->u.list = NULL;
  1813. X        else
  1814. X            cc->u.list = (List) dupstruct(cmd->u.list);
  1815. X        addhnode(ztrdup(s),cc,cmdnamtab,freecmdnam);
  1816. X        if (!strncmp(s,"TRAP",4))
  1817. X            {
  1818. X            int t0 = getsignum(s+4);
  1819. X
  1820. X            if (t0 != -1)
  1821. X                {
  1822. X                settrap(t0,cmd->u.list);
  1823. X                permalloc();
  1824. X                }
  1825. X            }
  1826. X        }
  1827. X    heapalloc();
  1828. X    return 0;
  1829. X}
  1830. X
  1831. X/* evaluate a [[ ... ]] */
  1832. X
  1833. Xint execcond(cmd) /**/
  1834. XCmd cmd;
  1835. X{
  1836. X    return !evalcond(cmd->u.cond);
  1837. X}
  1838. X
  1839. Xvoid execshfunc(cmd,cn) /**/
  1840. XCmd cmd;Cmdnam cn;
  1841. X{
  1842. XList l;
  1843. X
  1844. X    if (errflag) return;
  1845. X    l = cn->u.list;
  1846. X    if (!l) {
  1847. X        char *nam;
  1848. X
  1849. X        if (!(cn->flags & PMFLAG_u)) return;
  1850. X        if (!(l = getfpfunc(nam = peekfirst(cmd->args)))) {
  1851. X            zerr("function not found: %s",nam,0);
  1852. X            lastval = 1;
  1853. X            return;
  1854. X        }
  1855. X        cn->flags &= ~PMFLAG_u;
  1856. X        permalloc();
  1857. X        cn->u.list = (List) dupstruct(l);
  1858. X        heapalloc();
  1859. X    }
  1860. X    doshfunc(l,cmd->args,cn->flags);
  1861. X}
  1862. X
  1863. Xvoid doshfuncnoval(list,args,flags) /**/
  1864. XList list; Lklist args; int flags;
  1865. X{
  1866. Xint val = lastval;
  1867. X
  1868. X    doshfunc(list,args,flags);
  1869. X    lastval = val;
  1870. X}
  1871. X
  1872. Xvoid doshfunc(list,args,flags) /**/
  1873. XList list; Lklist args; int flags;
  1874. X{
  1875. Xchar **tab,**x,*oargv0;
  1876. Xint oxtr = opts[XTRACE],opev = opts[PRINTEXITVALUE],xexittr;
  1877. XLklist olist;
  1878. Xchar *s;
  1879. XList xexitfn;
  1880. X
  1881. X    xexittr = sigtrapped[SIGEXIT];
  1882. X    xexitfn = sigfuncs[SIGEXIT];
  1883. X    tab = pparams;
  1884. X    oargv0 = argzero;
  1885. X    zoptind = 1;
  1886. X    if (flags & PMFLAG_t) opts[XTRACE] = OPT_SET;
  1887. X    opts[PRINTEXITVALUE] = OPT_UNSET;
  1888. X    if (args) {
  1889. X        pparams = x = (char **) zcalloc(((sizeof *x)*(1+countnodes(args))));
  1890. X        argzero = ztrdup(ugetnode(args));
  1891. X        while (*x = ugetnode(args))
  1892. X            *x = ztrdup(*x), x++;
  1893. X    } else {
  1894. X        pparams = zcalloc(sizeof *pparams);
  1895. X        argzero = ztrdup(argzero);
  1896. X    }
  1897. X    permalloc();
  1898. X    olist = locallist;
  1899. X    locallist = newlist();
  1900. X    heapalloc();
  1901. X    runlist(dupstruct(list));
  1902. X    while (s = getnode(locallist)) unsetparam(s);
  1903. X    free(locallist);
  1904. X    locallist = olist;
  1905. X    breaks = retflag = 0;
  1906. X    freearray(pparams);
  1907. X    free(argzero);
  1908. X    argzero = oargv0;
  1909. X    pparams = tab;
  1910. X    if (sigfuncs[SIGEXIT] && sigfuncs[SIGEXIT] != xexitfn) {
  1911. X        dotrap(SIGEXIT);
  1912. X        freestruct(sigfuncs[SIGEXIT]);
  1913. X    }
  1914. X    sigtrapped[SIGEXIT] = xexittr;
  1915. X    sigfuncs[SIGEXIT] = xexitfn;
  1916. X    opts[XTRACE] = oxtr;
  1917. X    opts[PRINTEXITVALUE] = opev;
  1918. X}
  1919. X
  1920. X/* search fpath for an undefined function */
  1921. X
  1922. XList getfpfunc(s) /**/
  1923. Xchar *s;
  1924. X{
  1925. Xchar **pp = fpath,buf[MAXPATHLEN];
  1926. Xint fd;
  1927. X
  1928. X    for (; *pp; pp++)
  1929. X        {
  1930. X        sprintf(buf,"%s/%s",*pp,s);
  1931. X        if (!access(buf,R_OK) && (fd = open(buf,O_RDONLY)) != -1)
  1932. X            {
  1933. X            int len = lseek(fd,0,2);
  1934. X
  1935. X            if (len == -1)
  1936. X                close(fd);
  1937. X            else
  1938. X                {
  1939. X                char *d;
  1940. X
  1941. X                lseek(fd,0,0);
  1942. X                d = zcalloc(len+1);
  1943. X                if (read(fd,d,len) != len)
  1944. X                    {
  1945. X                    free(d);
  1946. X                    close(fd);
  1947. X                    }
  1948. X                else
  1949. X                    {
  1950. X                    close(fd);
  1951. X                    return parselstring(d);
  1952. X                    }
  1953. X                }
  1954. X            }
  1955. X        }
  1956. X    return NULL;
  1957. X}
  1958. X
  1959. X/* check to see if AUTOCD applies here */
  1960. X
  1961. Xint cancd(s) /**/
  1962. Xchar *s;
  1963. X{
  1964. Xchar *t;
  1965. X
  1966. X    if (isset(CDABLEVARS) && (t = getsparam(s)) && *t == '/') return cancd2(t);
  1967. X    if (*s != '/')
  1968. X        {
  1969. X        char sbuf[MAXPATHLEN],**cp;
  1970. X
  1971. X        if (cancd2(s))
  1972. X            return 1;
  1973. X        if (access(s,X_OK) == 0)
  1974. X            return 0;
  1975. X        for (cp = cdpath; *cp; cp++)
  1976. X            {
  1977. X            sprintf(sbuf,"%s/%s",*cp,s);
  1978. X            if (cancd2(sbuf))
  1979. X                return 1;
  1980. X            }
  1981. X        return 0;
  1982. X        }
  1983. X    return cancd2(s);
  1984. X}
  1985. X
  1986. Xint cancd2(s) /**/
  1987. Xchar *s;
  1988. X{
  1989. Xstruct stat buf;
  1990. X
  1991. X    return !(access(s,X_OK) || stat(s,&buf) || !S_ISDIR(buf.st_mode));
  1992. X}
  1993. END_OF_FILE
  1994.   if test 37664 -ne `wc -c <'src/exec.c'`; then
  1995.     echo shar: \"'src/exec.c'\" unpacked with wrong size!
  1996.   fi
  1997.   # end of 'src/exec.c'
  1998. fi
  1999. if test -f 'src/zle_refresh.c' -a "${1}" != "-c" ; then 
  2000.   echo shar: Will not clobber existing file \"'src/zle_refresh.c'\"
  2001. else
  2002.   echo shar: Extracting \"'src/zle_refresh.c'\" \(12060 characters\)
  2003.   sed "s/^X//" >'src/zle_refresh.c' <<'END_OF_FILE'
  2004. X/*
  2005. X *
  2006. X * zle_refresh.c - screen update
  2007. X *
  2008. X * This file is part of zsh, the Z shell.
  2009. X *
  2010. X * This software is Copyright 1992 by Paul Falstad
  2011. X *
  2012. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  2013. X * use this software as long as: there is no monetary profit gained
  2014. X * specifically from the use or reproduction of this software, it is not
  2015. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  2016. X * included prominently in any copy made. 
  2017. X *
  2018. X * The author make no claims as to the fitness or correctness of this software
  2019. X * for any use whatsoever, and it is provided as is. Any use of this software
  2020. X * is at the user's own risk. 
  2021. X *
  2022. X */
  2023. X
  2024. X#define ZLE
  2025. X#include "zsh.h"
  2026. X
  2027. Xchar **obuf = NULL,**nbuf = NULL;
  2028. Xint olnct,nlnct;
  2029. Xint winw,winh,winpos;
  2030. X
  2031. Xint vcs,vln,vmaxln;
  2032. X
  2033. Xvoid resetvideo() /**/
  2034. X{
  2035. Xint ln;
  2036. Xstatic int lwinw = -1,lwinh = -1;
  2037. X
  2038. X    setterm();
  2039. X    winw = columns-1;
  2040. X    if (isset(SINGLELINEZLE) || !termok)
  2041. X        winh = 1;
  2042. X    else
  2043. X        winh = (lines < 2) ? 24 : lines;
  2044. X    winpos = vln = vmaxln = 0;
  2045. X    if (lwinw != winw || lwinh != winh)
  2046. X        {
  2047. X        if (nbuf)
  2048. X            {
  2049. X            for (ln = 0; ln != lwinh; ln++)
  2050. X                {
  2051. X                free(nbuf[ln]);
  2052. X                free(obuf[ln]);
  2053. X                }
  2054. X            free(nbuf);
  2055. X            free(obuf);
  2056. X            }
  2057. X        nbuf = (char **) zalloc((winh+1)*sizeof(char *));
  2058. X        obuf = (char **) zalloc((winh+1)*sizeof(char *));
  2059. X        for (ln = 0; ln != winh+1; ln++)
  2060. X            {
  2061. X            nbuf[ln] = zalloc(winw+1);
  2062. X            obuf[ln] = zalloc(winw+1);
  2063. X            }
  2064. X        lwinw = winw;
  2065. X        lwinh = winh;
  2066. X        }
  2067. X    for (ln = 0; ln != winh+1; ln++)
  2068. X        {
  2069. X        *nbuf[ln] = '\0';
  2070. X        *obuf[ln] = '\0';
  2071. X        }
  2072. X    if (!pptlen)
  2073. X        nbuf[0][0] = obuf[0][0] = '\0';
  2074. X    else
  2075. X        {
  2076. X        for (ln = 0; ln != pptlen-1; ln++)
  2077. X            nbuf[0][ln] = obuf[0][ln] = ' ';
  2078. X        nbuf[0][ln] = obuf[0][ln] = '>';
  2079. X        nbuf[0][pptlen] = obuf[0][pptlen] = '\0';
  2080. X        }
  2081. X    vcs = pptlen;
  2082. X    olnct = nlnct = 1;
  2083. X}
  2084. X
  2085. Xint scrollwindow() /**/
  2086. X{
  2087. Xint t0,hwinh = winh/2;
  2088. X
  2089. X    for (t0 = 0; t0 != winh-hwinh; t0++)
  2090. X        {
  2091. X        char *s;
  2092. X
  2093. X        s = nbuf[t0];
  2094. X        nbuf[t0] = nbuf[t0+hwinh];
  2095. X        nbuf[t0+hwinh] = s;
  2096. X        }
  2097. X    for (t0 = 0; t0 != pptlen-1; t0++)
  2098. X        nbuf[0][t0] = ' ';
  2099. X    strcpy(nbuf[0]+t0,"> ...");
  2100. X    return winh-hwinh;
  2101. X}
  2102. X
  2103. X/* this is the messy part. */
  2104. X/* this define belongs where it's used!!! */
  2105. X
  2106. X#define nextline { *s = (unsigned char)'\0'; \
  2107. X    if (winh == ln+1) if (nvln != -1) break; else ln = scrollwindow()-1; \
  2108. X    s = (unsigned char *)nbuf[++ln]; sen = s+winw; \
  2109. X    }
  2110. X
  2111. Xvoid refresh() /**/
  2112. X{
  2113. Xunsigned char *s,*t,*sen,*scs = line+cs; char **qbuf;
  2114. Xint ln = 0,nvcs = 0,nvln = -1,t0;
  2115. X
  2116. X    cost = 0;
  2117. X    if (resetneeded)
  2118. X        {
  2119. X        resetvideo();
  2120. X        resetneeded = 0;
  2121. X        if (isset(SINGLELINEZLE) || !termok)
  2122. X            vcs = 0;
  2123. X        else
  2124. X            printf("%s",pmpt);
  2125. X        }
  2126. X    zleactive = 1;
  2127. X    if (isset(SINGLELINEZLE) || !termok)
  2128. X        {
  2129. X        singlerefresh();
  2130. X        return;
  2131. X        }
  2132. X
  2133. X/* first, we generate the video line buffers so we know what to
  2134. X    put on the screen. 
  2135. X
  2136. X    s = ptr into the video buffer.
  2137. X    t = ptr into the real buffer.
  2138. X    sen = end of the video buffer (eol)
  2139. X*/
  2140. X
  2141. X    s = (unsigned char *)(nbuf[ln = 0]+pptlen);
  2142. X    t = line;
  2143. X    sen = (unsigned char *)(*nbuf+winw);
  2144. X    for (; *t; t++)
  2145. X        {
  2146. X        if (icntrl((char)*t))
  2147. X            if (*t == '\n')
  2148. X                {
  2149. X                if (t == scs)
  2150. X                    {
  2151. X                    nvcs = (char *)s-nbuf[nvln = ln];
  2152. X                    scs = (unsigned char *)NULL;
  2153. X                    }
  2154. X                nextline
  2155. X                }
  2156. X            else if ((char)*t == '\t')
  2157. X                {
  2158. X                int t1 = (char *)s-nbuf[ln];
  2159. X
  2160. X                if ((t1|7)+1 >= winw) nextline
  2161. X                else
  2162. X                    do
  2163. X                        *s++ = ' ';
  2164. X                    while ((++t1) & 7);
  2165. X                }
  2166. X            else
  2167. X                {
  2168. X                if (s == sen) nextline
  2169. X                *s++ = '^';
  2170. X                if (s == sen) nextline
  2171. X                *s++ = (*t == 127) ? '?' : (*t | '@');
  2172. X                }
  2173. X        else
  2174. X            {
  2175. X            if (s == sen) nextline
  2176. X            *s++ = *t;
  2177. X            }
  2178. X/* if the cursor is here, remember it */
  2179. X
  2180. X        if (t == scs)
  2181. X            nvcs = s-(unsigned char *)nbuf[nvln = ln]-1;
  2182. X        }
  2183. X    if (scs == t)
  2184. X        nvcs = s-(unsigned char *)nbuf[nvln = ln];
  2185. X    *s = '\0';
  2186. X    nlnct = ln+1;
  2187. X    if (statusline)
  2188. X        strcpy(nbuf[(nlnct == winh) ? winh-1 : nlnct++],statusline);
  2189. X
  2190. X/* do RPROMPT */
  2191. X
  2192. X    if (pmpt2 && ln == 0 && strlen(nbuf[0])+strlen(pmpt2) < winw)
  2193. X        {
  2194. X        for (t0 = strlen(nbuf[0]); t0 != winw; t0++)
  2195. X            nbuf[0][t0] = ' ';
  2196. X        strcpy(nbuf[0]+winw-strlen(pmpt2),pmpt2);
  2197. X        }
  2198. X    for (ln = 0; ln < nlnct; ln++)
  2199. X        {
  2200. X
  2201. X/* if old line and new line are different,
  2202. X    see if we can insert/delete a line */
  2203. X
  2204. X        if (ln < olnct && strncmp(nbuf[ln],obuf[ln],16))
  2205. X            {
  2206. X            if (tccan(TCDELLINE) && !strncmp(nbuf[ln],obuf[ln+1],16)
  2207. X                    && obuf[ln+1][0] && ln != olnct)
  2208. X                {
  2209. X                int t0;
  2210. X
  2211. X                moveto(ln,0);
  2212. X                tcout(TCDELLINE);
  2213. X                for (t0 = ln; t0 != olnct; t0++)
  2214. X                    strcpy(obuf[t0],obuf[t0+1]);
  2215. X                olnct--;
  2216. X                }
  2217. X
  2218. X/* don't try to insert a line if olnct < vmaxln (vmaxln is the number
  2219. X    of lines that have been displayed by this routine) so that we don't
  2220. X    go off the end of the screen. */
  2221. X
  2222. X            else if (tccan(TCINSLINE) && !strncmp(nbuf[ln+1],obuf[ln],16) &&
  2223. X                    olnct < vmaxln && nbuf[ln+1][0] && ln != olnct)
  2224. X                {
  2225. X                int t0;
  2226. X
  2227. X                moveto(ln,0);
  2228. X                tcout(TCINSLINE);
  2229. X                for (t0 = olnct; t0 != ln; t0--)
  2230. X                    strcpy(obuf[t0],obuf[t0-1]);
  2231. X                *obuf[ln] = '\0';
  2232. X                olnct++;
  2233. X                }
  2234. X            }
  2235. X        refreshline(ln);
  2236. X        }
  2237. X
  2238. X/* if old buffer had extra lines, do a clear-end-of-display if we can,
  2239. X    otherwise, just fill new buffer with blank lines and refresh them */
  2240. X
  2241. X    if (olnct > nlnct)
  2242. X        {
  2243. X        for (ln = nlnct; ln < olnct; ln++)
  2244. X            nbuf[ln][0] = '\0';
  2245. X        if (tccan(TCCLEAREOD))
  2246. X            {
  2247. X            moveto(nlnct,0);
  2248. X            tcout(TCCLEAREOD);
  2249. X            }
  2250. X        else
  2251. X            for (ln = nlnct; ln < olnct; ln++)
  2252. X                refreshline(ln);
  2253. X        }
  2254. X
  2255. X/* move to the new cursor position */
  2256. X
  2257. X    moveto(nvln,nvcs);
  2258. X    qbuf = nbuf;
  2259. X    nbuf = obuf;
  2260. X    obuf = qbuf;
  2261. X    olnct = nlnct;
  2262. X    if (nlnct > vmaxln)
  2263. X        vmaxln = nlnct;
  2264. X    fflush(stdout);
  2265. X}
  2266. X
  2267. X#define tcinscost(X) (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS])
  2268. X#define tcdelcost(X) (tccan(TCMULTDEL) ? tclen[TCMULTDEL] : (X)*tclen[TCDEL])
  2269. X#define tc_delchars(X) tcmultout(TCDEL,TCMULTDEL,(X))
  2270. X#define tc_inschars(X) tcmultout(TCINS,TCMULTINS,(X))
  2271. X#define tc_upcurs(X) tcmultout(TCUP,TCMULTUP,(X))
  2272. X#define tc_leftcurs(X) tcmultout(TCLEFT,TCMULTLEFT,(X))
  2273. X
  2274. Xvoid refreshline(ln) /**/
  2275. Xint ln;
  2276. X{
  2277. Xchar *nl = nbuf[ln],*ol = obuf[ln];
  2278. Xchar *p1;
  2279. Xchar junk,*truncptr = &junk;
  2280. Xint ccs = 0;
  2281. X
  2282. X    if (ln >= olnct)
  2283. X        *ol = '\0';
  2284. X    for (;;)
  2285. X        {
  2286. X        while (*nl && *nl == *ol)
  2287. X            {
  2288. X            nl++,ol++,ccs++;
  2289. X            }
  2290. X        if (!*nl && !*ol)
  2291. X            { *truncptr = '\0'; return; }
  2292. X
  2293. X/* if this is the end of the new buffer but the old buffer has stuff
  2294. X    here, clear to end of line if we can, otherwise fill the new buffer
  2295. X    with blanks and continue. */
  2296. X
  2297. X        if (!*nl)
  2298. X            {
  2299. X            if (tccan(TCCLEAREOL) && strlen(ol) > tclen[TCCLEAREOL])
  2300. X                {
  2301. X                moveto(ln,ccs);
  2302. X                tcout(TCCLEAREOL);
  2303. X                *ol = '\0';
  2304. X                *truncptr = '\0';
  2305. X                return;
  2306. X                }
  2307. X            else
  2308. X                {
  2309. X                int x = strlen(ol);
  2310. X                char *p = nl;
  2311. X
  2312. X                truncptr = p;
  2313. X                while (x--)
  2314. X                    *p++ = ' ';
  2315. X                *p = '\0';
  2316. X                continue;
  2317. X                }
  2318. X            }
  2319. X
  2320. X/* if this is the end of the old buffer, just dump the rest of the
  2321. X    new buffer. */
  2322. X
  2323. X        if (!*ol)
  2324. X            {
  2325. X            while (*nl == ' ')
  2326. X                nl++,ccs++;
  2327. X            if (*nl)
  2328. X                {
  2329. X                moveto(ln,ccs);
  2330. X                fwrite(nl,strlen(nl),1,stdout);
  2331. X                cost += strlen(nl);
  2332. X                vcs += strlen(nl);
  2333. X                }
  2334. X            *truncptr = 0;
  2335. X            return;
  2336. X            }
  2337. X        moveto(ln,ccs);
  2338. X
  2339. X/* try to insert/delete characters */
  2340. X
  2341. X        if (ol[1] != nl[1] && tccan(TCDEL))
  2342. X            {
  2343. X            int ct = 0;
  2344. X
  2345. X            for (p1 = ol; *p1; p1++,ct++)
  2346. X                if (tcdelcost(ct) < streqct(p1,nl))
  2347. X                    {
  2348. X                    tc_delchars(ct);
  2349. X                    ol = p1;
  2350. X                    break;
  2351. X                    }
  2352. X            if (*p1)
  2353. X                continue;
  2354. X            }
  2355. X
  2356. X        if (ol[1] != nl[1] && tccan(TCINS))
  2357. X            {
  2358. X            int ct = 0;
  2359. X
  2360. X            for (p1 = nl; *p1; p1++,ct++)
  2361. X                if (tcinscost(ct) < streqct(p1,ol)+ct)
  2362. X                    {
  2363. X#if 0
  2364. X/* make sure we aren't inserting characters off the end of the screen;
  2365. X    if we are, jump to the end and truncate the line, if we can do
  2366. X    it quickly (gee, clever idea, Paul!) */
  2367. X                    if (ct+ccs+strlen(ol) >= winw-1)
  2368. X                        {
  2369. X                        if (!tccan(TCMULTRIGHT) || ccs > winw-tclen[TCMULTRIGHT])
  2370. X                            continue;
  2371. X                        moveto(ln,winw-1-ct);
  2372. X                        if (!tccan(TCCLEAREOL) || ct < tclen[TCCLEAREOL])
  2373. X                            {
  2374. X                            int x = ct;
  2375. X
  2376. X                            while (vcs++,x--)
  2377. X                                putchar(' ');
  2378. X                            }
  2379. X                        else
  2380. X                            tcout(TCCLEAREOL);
  2381. X                        moveto(ln,ccs);
  2382. X                        }
  2383. X#endif
  2384. X                    if (ct+ccs+strlen(ol) < winw-1)
  2385. X                        {
  2386. X                        tc_inschars(ct = p1-nl);
  2387. X                        ccs = (vcs += p1-nl);
  2388. X                        cost += ct;
  2389. X                        fwrite(nl,ct,1,stdout);
  2390. X                        nl += ct;
  2391. X                        break;
  2392. X                        }
  2393. X                    }
  2394. X            if (*p1)
  2395. X                continue;
  2396. X            }
  2397. X
  2398. X/* if we can't do anything fancy, just write the new character and
  2399. X    keep going. */
  2400. X
  2401. X        putchar(*nl);
  2402. X        cost++;
  2403. X        nl++,ol++,ccs = ++vcs;
  2404. X        }
  2405. X}
  2406. X
  2407. Xvoid moveto(ln,cl) /**/
  2408. Xint ln;int cl;
  2409. X{
  2410. X
  2411. X/* move up */
  2412. X
  2413. X    if (ln < vln)
  2414. X        {
  2415. X        tc_upcurs(vln-ln);
  2416. X        vln = ln;
  2417. X        }
  2418. X
  2419. X/* move down; if we might go off the end of the screen, use newlines
  2420. X    instead of TCDOWN */
  2421. X
  2422. X    while (ln > vln)
  2423. X        if (cl < (vcs/2) || ln >= vmaxln || !tccan(TCLEFT))
  2424. X            {
  2425. X            putchar('\r');
  2426. X            putchar('\n');
  2427. X            cost+=2;
  2428. X            vln++;
  2429. X            vcs = 0;
  2430. X            }
  2431. X        else
  2432. X            {
  2433. X            tc_downcurs(ln-vln);
  2434. X            vln = ln;
  2435. X            }
  2436. X    if (cl < (vcs/2) || !tccan(TCLEFT))
  2437. X        {
  2438. X        putchar('\r');
  2439. X        cost++;
  2440. X        vcs = 0;
  2441. X        }
  2442. X    if (vcs < cl)
  2443. X        tc_rightcurs(cl-vcs);
  2444. X    else if (vcs > cl)
  2445. X        tc_leftcurs(vcs-cl);
  2446. X    vcs = cl;
  2447. X}
  2448. X
  2449. Xvoid tcmultout(cap,multcap,ct) /**/
  2450. Xint cap;int multcap;int ct;
  2451. X{
  2452. X    if (tccan(multcap) && (!tccan(cap) || tclen[multcap] < tclen[cap]*ct))
  2453. X        tcoutarg(multcap,ct);
  2454. X    else while (ct--)
  2455. X        tcout(cap);
  2456. X}
  2457. X
  2458. Xvoid tc_rightcurs(ct) /**/
  2459. Xint ct;
  2460. X{
  2461. X
  2462. X/* do a multright if it's cheaper or if we're walking over the prompt.  */
  2463. X
  2464. X    if (tccan(TCMULTRIGHT) &&
  2465. X            (ct > tclen[TCMULTRIGHT] || (vln == 0 && vcs < pptlen)))
  2466. X        tcoutarg(TCMULTRIGHT,ct);
  2467. X
  2468. X/* if we're walking over the prompt and we can do a bunch of cursor rights,
  2469. X    do them, even though they're more expensive.  (We can't redraw the
  2470. X    prompt very easily in general.)  */
  2471. X
  2472. X    else if (vln == 0 && vcs < pptlen && tccan(TCRIGHT))
  2473. X        while (ct--)
  2474. X            tcout(TCRIGHT);
  2475. X
  2476. X/* otherwise write the contents of the video buffer. */
  2477. X
  2478. X    else
  2479. X        fwrite(nbuf[vln]+vcs,ct,1,stdout);
  2480. X}
  2481. X
  2482. Xvoid tc_downcurs(ct) /**/
  2483. Xint ct;
  2484. X{
  2485. X    if (tccan(TCMULTDOWN) &&
  2486. X            (!tccan(TCDOWN) || tclen[TCMULTDOWN] < tclen[TCDOWN]*ct))
  2487. X        tcoutarg(TCMULTDOWN,ct);
  2488. X    else if (tccan(TCDOWN))
  2489. X        while (ct--)
  2490. X            tcout(TCDOWN);
  2491. X    else
  2492. X        {
  2493. X        while (ct--)
  2494. X            putchar('\n');
  2495. X        vcs = 0;
  2496. X        }
  2497. X}
  2498. X
  2499. X/* I'm NOT going to worry about padding unless anyone complains. */
  2500. X
  2501. Xvoid tcout(cap) /**/
  2502. Xint cap;
  2503. X{
  2504. X    tputs(tcstr[cap],1,putraw);
  2505. X}
  2506. X
  2507. Xvoid tcoutarg(cap,arg) /**/
  2508. Xint cap;int arg;
  2509. X{
  2510. X    tputs(tgoto(tcstr[cap],arg,arg),1,putraw);
  2511. X}
  2512. X
  2513. Xvoid clearscreen() /**/
  2514. X{
  2515. X    tcout(TCCLEARSCREEN);
  2516. X    resetneeded = 1;
  2517. X}
  2518. X
  2519. Xvoid redisplay() /**/
  2520. X{
  2521. X    trashzle();
  2522. X}
  2523. X
  2524. Xvoid trashzle() /**/
  2525. X{
  2526. X    if (zleactive)
  2527. X        {
  2528. X        refresh();
  2529. X        moveto(nlnct,0);
  2530. X        printf("%s",postedit);
  2531. X        fflush(stdout);
  2532. X        unsetterm();
  2533. X        resetneeded = 1;
  2534. X        }
  2535. X}
  2536. X
  2537. Xvoid singlerefresh() /**/
  2538. X{
  2539. Xchar *vbuf,*vp,**qbuf,*op;
  2540. Xint t0,vsiz,nvcs = 0;
  2541. X
  2542. X    for (vsiz = 1+pptlen, t0 = 0; t0 != ll; t0++,vsiz++)
  2543. X        if (line[t0] == '\t')
  2544. X            vsiz += 7;
  2545. X        else if (icntrl(line[t0]))
  2546. X            vsiz++;
  2547. X    vbuf = zalloc(vsiz);
  2548. X    strcpy(vbuf,pmpt);
  2549. X    vp = vbuf+pptlen;
  2550. X    for (t0 = 0; t0 != ll; t0++)
  2551. X        {
  2552. X        if (line[t0] == '\t')
  2553. X            do
  2554. X                *vp++ = ' ';
  2555. X            while ((vp-vbuf) & 7);
  2556. X        else if (line[t0] == '\n')
  2557. X            {
  2558. X            *vp++ = '\\';
  2559. X            *vp++ = 'n';
  2560. X            }
  2561. X        else if (line[t0] == 0x7f)
  2562. X            {
  2563. X            *vp++ = '^';
  2564. X            *vp++ = '?';
  2565. X            }
  2566. X        else if (icntrl(line[t0]))
  2567. X            {
  2568. X            *vp++ = '^';
  2569. X            *vp++ = line[t0] | '@';
  2570. X            }
  2571. X        else
  2572. X            *vp++ = line[t0];
  2573. X        if (t0 == cs)
  2574. X            nvcs = vp-vbuf-1;
  2575. X        }
  2576. X    if (t0 == cs)
  2577. X        nvcs = vp-vbuf;
  2578. X    *vp = '\0';
  2579. X    if ((winpos && nvcs < winpos+1) || (nvcs > winpos+winw-1))
  2580. X        {
  2581. X        if ((winpos = nvcs-(winw/2)) < 0)
  2582. X            winpos = 0;
  2583. X        }
  2584. X    if (winpos)
  2585. X        vbuf[winpos] = '<';
  2586. X    if (strlen(vbuf+winpos) > winw)
  2587. X        {
  2588. X        vbuf[winpos+winw-1] = '>';
  2589. X        vbuf[winpos+winw] = '\0';
  2590. X        }
  2591. X    strcpy(nbuf[0],vbuf+winpos);
  2592. X    free(vbuf);
  2593. X    nvcs -= winpos;
  2594. X    for (t0 = 0,vp = *nbuf,op = *obuf; *vp; t0++,vp++)
  2595. X        {
  2596. X        if (*vp != *op && !(*vp == ' ' && !*op))
  2597. X            {
  2598. X            singmoveto(t0);
  2599. X            putchar(*vp);
  2600. X            vcs++;
  2601. X            }
  2602. X        if (*op)
  2603. X            op++;
  2604. X        }
  2605. X    if (*op)
  2606. X        {
  2607. X        singmoveto(t0);
  2608. X        for (; *op; op++)
  2609. X            {
  2610. X            putchar(' ');
  2611. X            vcs++;
  2612. X            }
  2613. X        }
  2614. X    singmoveto(nvcs);
  2615. X    qbuf = nbuf;
  2616. X    nbuf = obuf;
  2617. X    obuf = qbuf;
  2618. X    fflush(stdout);
  2619. X}
  2620. X
  2621. Xvoid singmoveto(pos) /**/
  2622. Xint pos;
  2623. X{
  2624. X    while (pos < vcs)
  2625. X        {
  2626. X        vcs--;
  2627. X        putchar('\b');
  2628. X        }
  2629. X    while (pos > vcs)
  2630. X        {
  2631. X        putchar(nbuf[0][vcs]);
  2632. X        vcs++;
  2633. X        }
  2634. X}
  2635. X
  2636. Xint streqct(s,t) /**/
  2637. Xchar *s;char *t;
  2638. X{
  2639. Xint ct = 0;
  2640. X
  2641. X    while (*s && *s == *t) s++,t++,ct++;
  2642. X    return ct;
  2643. X}
  2644. X
  2645. END_OF_FILE
  2646.   if test 12060 -ne `wc -c <'src/zle_refresh.c'`; then
  2647.     echo shar: \"'src/zle_refresh.c'\" unpacked with wrong size!
  2648.   fi
  2649.   # end of 'src/zle_refresh.c'
  2650. fi
  2651. echo shar: End of archive 10 \(of 22\).
  2652. cp /dev/null ark10isdone
  2653. MISSING=""
  2654. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
  2655.     if test ! -f ark${I}isdone ; then
  2656.     MISSING="${MISSING} ${I}"
  2657.     fi
  2658. done
  2659. if test "${MISSING}" = "" ; then
  2660.     echo You have unpacked all 22 archives.
  2661.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2662. else
  2663.     echo You still must unpack the following archives:
  2664.     echo "        " ${MISSING}
  2665. fi
  2666. exit 0
  2667.  
  2668. exit 0 # Just in case...
  2669.