home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume35 / zsh / part14 < prev    next >
Text File  |  1993-02-20  |  56KB  |  2,786 lines

  1. Newsgroups: comp.sources.misc
  2. From: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
  3. Subject: v35i064:  zsh - The Z Shell, version 2.3.1, Part14/22
  4. Message-ID: <1993Feb20.212601.29047@sparky.imd.sterling.com>
  5. X-Md4-Signature: 0a1bd731879202307d405b2ee7e5eabb
  6. Date: Sat, 20 Feb 1993 21:26:01 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 64
  11. Archive-name: zsh/part14
  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/case src/glob.c src/hist.c
  22. # Wrapped by mattson@odin on Sat Feb  6 14:41:54 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 14 (of 22)."'
  26. if test -f 'help/case' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'help/case'\"
  28. else
  29.   echo shar: Extracting \"'help/case'\" \(398 characters\)
  30.   sed "s/^X//" >'help/case' <<'END_OF_FILE'
  31. X          case word in [ pattern ) list ;; ] ...  esac
  32. X               Execute the list associated with the first pattern
  33. X               that  matches  word, if any.  The form of the pat-
  34. X               terns is the same as that used for  filename  gen-
  35. X               eration.  See Filename Generation below.
  36. X
  37. X          case word { [ pattern ) list ;; ] ...  }
  38. X               Another form of case.
  39. END_OF_FILE
  40.   if test 398 -ne `wc -c <'help/case'`; then
  41.     echo shar: \"'help/case'\" unpacked with wrong size!
  42.   fi
  43.   # end of 'help/case'
  44. fi
  45. if test -f 'src/glob.c' -a "${1}" != "-c" ; then 
  46.   echo shar: Will not clobber existing file \"'src/glob.c'\"
  47. else
  48.   echo shar: Extracting \"'src/glob.c'\" \(26147 characters\)
  49.   sed "s/^X//" >'src/glob.c' <<'END_OF_FILE'
  50. X/*
  51. X *
  52. X * glob.c - filename generation
  53. X *
  54. X * This file is part of zsh, the Z shell.
  55. X *
  56. X * This software is Copyright 1992 by Paul Falstad
  57. X *
  58. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  59. X * use this software as long as: there is no monetary profit gained
  60. X * specifically from the use or reproduction of this software, it is not
  61. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  62. X * included prominently in any copy made. 
  63. X *
  64. X * The author make no claims as to the fitness or correctness of this software
  65. X * for any use whatsoever, and it is provided as is. Any use of this software
  66. X * is at the user's own risk. 
  67. X *
  68. X */
  69. X
  70. X#include "zsh.h"
  71. X
  72. X#include <sys/errno.h>
  73. X
  74. X#define exists(X) (access(X,0) == 0 || readlink(X,NULL,0) == 0)
  75. X
  76. Xstatic int mode;                /* != 0 if we are parsing glob patterns */
  77. Xstatic int pathpos;            /* position in pathbuf */
  78. Xstatic int matchsz;            /* size of matchbuf */
  79. Xstatic int matchct;            /* number of matches found */
  80. Xstatic char pathbuf[MAXPATHLEN];    /* pathname buffer */
  81. Xstatic char **matchbuf;        /* array of matches */
  82. Xstatic char **matchptr;        /* &matchbuf[matchct] */
  83. Xstatic Comp exclude;            /* pattern to exclude */
  84. X#ifdef ULTRIX
  85. Xtypedef struct stat *Statptr;   /* This makes the Ultrix compiler happy.  Go figure. */
  86. X#endif
  87. X
  88. X/* max # of qualifiers */
  89. X
  90. X#define QUALCT 16
  91. X
  92. Xstatic int (*qualfuncs[QUALCT])DCLPROTO((struct stat *,long));
  93. Xstatic long qualdata[QUALCT];
  94. Xstatic int qualsense[QUALCT];
  95. Xstatic int qualamc[QUALCT];
  96. Xstatic int qualrange[QUALCT];
  97. Xstatic int qualct;
  98. Xstatic int range, amc;
  99. Xstatic int gf_nullglob,gf_markdirs,gf_noglobdots;
  100. X
  101. X/* pathname component in filename patterns */
  102. X
  103. Xstruct complist {
  104. X    Complist next;
  105. X    Comp comp;
  106. X    int closure;    /* 1 if this is a (foo/)# */
  107. X    };
  108. Xstruct comp {
  109. X    Comp left,right,next;
  110. X    char *str;
  111. X    int closure,last;
  112. X    };
  113. X
  114. Xvoid glob(list,np) /**/
  115. XLklist list;Lknode *np;
  116. X{
  117. XLknode node = prevnode(*np);
  118. XLknode next = nextnode(*np);
  119. Xchar *str;        /* the pattern */
  120. Xint sl;            /* length of the pattern */
  121. XComplist q;        /* pattern after parsing */
  122. Xchar *ostr = getdata(*np);        /* the pattern before the parser chops it up */
  123. X
  124. X    heapalloc();
  125. X    str = strdup(ostr);
  126. X    lastalloc();
  127. X    sl = strlen(str);
  128. X    uremnode(list,*np);
  129. X    qualct = 0;
  130. X    gf_nullglob = isset(NULLGLOB);
  131. X    gf_markdirs = isset(MARKDIRS);
  132. X    gf_noglobdots = unset(GLOBDOTS);
  133. X    if (str[sl-1] == Outpar)    /* check for qualifiers */
  134. X        {
  135. X        char *s;
  136. X        int sense = 0;
  137. X        long data = 0;
  138. X#ifdef ULTRIX
  139. X        int (*func) DCLPROTO((Statptr,long));
  140. X#else
  141. X        int (*func) DCLPROTO((struct stat *,long));
  142. X#endif
  143. X
  144. X        for (s = str+sl-2; s != str; s--)
  145. X            if (*s == Bar || *s == Outpar || *s == Inpar)
  146. X                break;
  147. X        if (*s == Inpar)
  148. X            {
  149. X            *s++ = '\0';
  150. X            while (*s != Outpar)
  151. X                {
  152. X#ifdef ULTRIX
  153. X                func = (int (*) DCLPROTO((Statptr,long))) 0;
  154. X#else
  155. X                func = (int (*) DCLPROTO((struct stat *,long))) 0;
  156. X#endif
  157. X                if (idigit(*s))
  158. X                    {
  159. X                    func = qualflags;
  160. X                    data = 0;
  161. X                    while (idigit(*s))
  162. X                        data = data*010+(*s++-'0');
  163. X                    }
  164. X                else switch ((int)(unsigned char)(*s++))
  165. X                    {
  166. X                    case (int)STOUC(Hat): case '^': sense = 1-sense; break;
  167. X#ifdef S_IFLNK
  168. X                    case '@': func = qualmode; data = S_IFLNK; break;
  169. X#endif
  170. X#ifdef S_IFSOCK
  171. X                    case '=': func = qualmode; data = S_IFSOCK; break;
  172. X#endif
  173. X#ifdef S_IFIFO
  174. X                    case 'p': func = qualmode; data = S_IFIFO; break;
  175. X#endif
  176. X                    case '/': func = qualmode; data = S_IFDIR; break;
  177. X                    case '.': func = qualmode; data = S_IFREG; break;
  178. X                    case '%': func = qualisdev; break;
  179. X                    case (int)STOUC(Star):  func = qualiscom; break;
  180. X                    case 'R': func = qualflags; data = 0004; break;
  181. X                    case 'W': func = qualflags; data = 0002; break;
  182. X                    case 'X': func = qualflags; data = 0001; break;
  183. X                    case 'r': func = qualflags; data = 0400; break;
  184. X                    case 'w': func = qualflags; data = 0200; break;
  185. X                    case 'x': func = qualflags; data = 0100; break;
  186. X                    case 's': func = qualflags; data = 04000; break;
  187. X                    case 'S': func = qualflags; data = 02000; break;
  188. X                    case 'd': func = qualdev; data = qgetnum(&s); break;
  189. X                    case 'l': func = qualnlink; data = qgetnum(&s); break;
  190. X                    case 'U': func = qualuid; data = geteuid(); break;
  191. X                    case 'G': func = qualgid; data = getegid(); break;
  192. X                    case 'u': func = qualuid; data = qgetnum(&s); break;
  193. X                    case 'g': func = qualgid; data = qgetnum(&s); break;
  194. X                    case 'M': gf_markdirs = !sense; break;
  195. X                    case 'N': gf_nullglob = !sense; break;
  196. X                    case 'D': gf_noglobdots = sense; break;
  197. X                    case 'a': amc = 0; func = qualtime; goto getrange;
  198. X                    case 'm': amc = 1; func = qualtime; goto getrange;
  199. X                    case 'c': amc = 2; func = qualtime; goto getrange;
  200. X                    case 'L': func = qualsize; 
  201. Xgetrange:
  202. X                            if (range = *s == '+' ? 1 : *s == '-' ? -1 : 0) ++s;
  203. X                            data = qgetnum(&s);
  204. X                            break;
  205. X                    default: zerr("unknown file attribute",NULL,0); return;
  206. X                    }
  207. X                if (func)
  208. X                    {
  209. X                    if (qualct == QUALCT-1)
  210. X                        {
  211. X                        zerr("too many qualifiers",NULL,0);
  212. X                        return;
  213. X                        }
  214. X                    qualfuncs[qualct] = func;
  215. X                    qualsense[qualct] = sense;
  216. X                    qualdata[qualct] = data;
  217. X                    qualrange[qualct] = range;
  218. X                    qualamc[qualct] = amc;
  219. X                    qualct++;
  220. X                    }
  221. X                if (errflag)
  222. X                    return;
  223. X                }
  224. X            }
  225. X        }
  226. X    else if ((str[sl-1] == '/') && !((str[sl-2] == Star)&&
  227. X                (str[sl-3] == Star)&&(str[sl-4] == Star)&&
  228. X                (str[sl-5]==Star)))        /* foo/ == foo(/) */
  229. X        {
  230. X        str[sl-1] = '\0';
  231. X        qualfuncs[0] = qualmode;
  232. X        qualdata[0] = S_IFDIR;
  233. X        qualsense[0] = 0;
  234. X        qualct = 1;
  235. X        }
  236. X#ifdef ULTRIX
  237. X    qualfuncs[qualct] = (int (*) DCLPROTO((Statptr,long))) 0;
  238. X#else
  239. X    qualfuncs[qualct] = (int (*) DCLPROTO((struct stat *,long))) 0;
  240. X#endif
  241. X    if (*str == '/')    /* pattern has absolute path */
  242. X        {
  243. X        str++;
  244. X        pathbuf[0] = '/';
  245. X        pathbuf[pathpos = 1] = '\0';
  246. X        }
  247. X    else        /* pattern is relative to pwd */
  248. X        pathbuf[pathpos = 0] = '\0';
  249. X    q = parsepat(str);
  250. X    if (!q || errflag)    /* if parsing failed */
  251. X        {
  252. X        if (isset(NOBADPATTERN))
  253. X            {
  254. X            insnode(list,node,ostr);
  255. X            return;
  256. X            }
  257. X        errflag = 0;
  258. X        zerr("bad pattern: %s",ostr,0);
  259. X        return;
  260. X        }
  261. X    matchptr = matchbuf = (char **) zalloc((matchsz = 16)*sizeof(char *));
  262. X    matchct = 0;
  263. X    scanner(q);        /* do the globbing */
  264. X    if (matchct)
  265. X        badcshglob |= 2;
  266. X    else if (!gf_nullglob)
  267. X        if (isset(CSHNULLGLOB)) {
  268. X            badcshglob |= 1;
  269. X        } else if (unset(NONOMATCH)) {
  270. X            zerr("no matches found: %s",ostr,0);
  271. X            free(matchbuf);
  272. X            return;
  273. X        } else {
  274. X            *matchptr++ = strdup(ostr);
  275. X            matchct = 1;
  276. X        }
  277. X    qsort((vptr)&matchbuf[0],matchct,sizeof(char *),
  278. X            (int (*) DCLPROTO((const void *, const void *)))notstrcmp);
  279. X    matchptr = matchbuf;
  280. X    while (matchct--)            /* insert matches in the arg list */
  281. X        insnode(list,node,*matchptr++);
  282. X    free(matchbuf);
  283. X    *np = (next) ? prevnode(next) : lastnode(list);
  284. X}
  285. X
  286. X/* get number after qualifier */
  287. X
  288. Xlong qgetnum(s) /**/
  289. Xchar **s;
  290. X{
  291. Xlong v = 0;
  292. X
  293. X    if (!idigit(**s))
  294. X        {
  295. X        zerr("number expected",NULL,0);
  296. X        return 0;
  297. X        }
  298. X    while (idigit(**s))
  299. X        v = v*10+*(*s)++-'0';
  300. X    return v;
  301. X}
  302. X
  303. Xint notstrcmp(a,b) /**/
  304. Xchar **a;char **b;
  305. X{
  306. Xchar *c = *b,*d = *a;
  307. Xint x1,x2,cmp;
  308. X
  309. X    for (; *c == *d && *c; c++,d++);
  310. X    cmp = (int) (unsigned char) *c-(int) (unsigned char) *d;
  311. X    if (isset(NUMERICGLOBSORT)) {
  312. X        for (; c > *b && idigit(c[-1]); c--,d--);
  313. X        if(idigit(*c) && idigit(*d)) {
  314. X            x1 = atoi(c); x2 = atoi(d);
  315. X            if(x1 != x2) return x1-x2;
  316. X        }
  317. X    }
  318. X    return cmp;
  319. X}
  320. X
  321. Xint forstrcmp(a,b) /**/
  322. Xchar **a;char **b;
  323. X{
  324. Xchar *c = *b,*d = *a;
  325. X
  326. X    for (; *c == *d && *c; c++,d++);
  327. X    return ((int) (unsigned char) *d-(int) (unsigned char) *c);
  328. X}
  329. X
  330. X/* add a match to the list */
  331. X
  332. Xvoid insert(s) /**/
  333. Xchar *s;
  334. X{
  335. Xstruct stat buf;
  336. Xint statted = 0;
  337. X
  338. X    if (exclude && domatch(s,exclude,gf_noglobdots)) return;
  339. X    if (gf_markdirs && !lstat(s,&buf) && S_ISDIR(buf.st_mode)) {
  340. X        char *t;
  341. X        int ll = strlen(s);
  342. X
  343. X        t = ncalloc(ll+2);
  344. X        strcpy(t,s);
  345. X        t[ll] = '/';
  346. X        t[ll+1] = '\0';
  347. X        s = t;
  348. X        statted = 1;
  349. X    }
  350. X    if (qualct)    { /* do the (X) (^X) stuff */
  351. X#ifdef ULTRIX
  352. X        int (**fptr)DCLPROTO((Statptr,long)) = qualfuncs;
  353. X#else
  354. X        int (**fptr)DCLPROTO((struct stat *,long)) = qualfuncs;
  355. X#endif
  356. X        int *sptr = qualsense;
  357. X        int *rptr = qualrange;
  358. X        int *aptr = qualamc;
  359. X        long *lptr = qualdata;
  360. X
  361. X        if (statted || lstat(s,&buf) >= 0)
  362. X            while (*fptr) {
  363. X                range = *rptr++;
  364. X                amc = *aptr++;
  365. X                if (!(!!((*fptr++)(&buf,*lptr++)) ^ *sptr++))
  366. X                    return;
  367. X            }
  368. X    }
  369. X    *matchptr++ = s;
  370. X    if (++matchct == matchsz) {
  371. X        matchbuf = (char **) realloc((char *) matchbuf,
  372. X            sizeof(char **)*(matchsz *= 2));
  373. X        matchptr = matchbuf+matchct;
  374. X    }
  375. X}
  376. X
  377. X/* check to see if str is eligible for filename generation */
  378. X
  379. Xint haswilds(str) /**/
  380. Xchar *str;
  381. X{
  382. X    if ((*str == Inbrack || *str == Outbrack) && !str[1]) return 0;
  383. X    if (str[0] == '%') return 0;
  384. X    for (; *str; str++)
  385. X        if (*str == Pound || *str == Hat || *str == Star ||
  386. X                *str == Bar || *str == Inbrack || *str == Inang ||
  387. X                *str == Quest) return 1;
  388. X    return 0;
  389. X}
  390. X
  391. X/* check to see if str is eligible for brace expansion */
  392. X
  393. Xint hasbraces(str) /**/
  394. Xchar *str;
  395. X{
  396. Xint mb,bc,cmct1,cmct2;
  397. Xchar *lbr = NULL;
  398. X
  399. X    if (str[0] == Inbrace && str[1] == Outbrace)
  400. X        return 0;
  401. X    if (isset(BRACECCL)) {
  402. X        for (mb = bc = 0; *str; ++str)
  403. X            if (*str == Inbrace) {
  404. X                if (++bc > mb)
  405. X                    mb = bc;
  406. X            }
  407. X            else if (*str == Outbrace)
  408. X                if (--bc < 0)
  409. X                    return(0);
  410. X        return(mb && bc == 0);
  411. X    }
  412. X    for (mb = bc = cmct1 = cmct2 = 0; *str; str++)
  413. X        {
  414. X        if (*str == Inbrace)
  415. X            {
  416. X            if (!bc)
  417. X                lbr = str;
  418. X            bc++;
  419. X            if (str[4] == Outbrace && str[2] == '-') /* {a-z} */
  420. X                {
  421. X                cmct1++;
  422. X                if (bc == 1)
  423. X                    cmct2++;
  424. X                }
  425. X            }
  426. X        else if (*str == Outbrace)
  427. X            {
  428. X            bc--;
  429. X            if (!bc)
  430. X                {
  431. X                if (!cmct2)
  432. X                    {
  433. X                    *lbr = '{';
  434. X                    *str = '}';
  435. X                    }
  436. X                cmct2 = 0;
  437. X                }
  438. X            }
  439. X        else if (*str == Comma && bc)
  440. X            {
  441. X            cmct1++;
  442. X            if (bc == 1)
  443. X                cmct2++;
  444. X            }
  445. X        if (bc > mb)
  446. X            mb = bc;
  447. X        if (bc < 0)
  448. X            return 0;
  449. X        }
  450. X    return (mb && bc == 0 && cmct1);
  451. X}
  452. X
  453. X/* expand stuff like >>*.c */
  454. X
  455. Xint xpandredir(fn,tab) /**/
  456. Xstruct redir *fn;Lklist tab;
  457. X{
  458. XLklist fake;
  459. Xchar *nam;
  460. Xstruct redir *ff;
  461. Xint ret = 0;
  462. X
  463. X    fake = newlist();
  464. X    addnode(fake,fn->name);
  465. X    prefork(fake);
  466. X    if (!errflag)
  467. X        postfork(fake,1);
  468. X    if (errflag) return 0;
  469. X    if (full(fake) && !nextnode(firstnode(fake))) {
  470. X        fn->name = peekfirst(fake);
  471. X        untokenize(fn->name);
  472. X    } else
  473. X        while (nam = ugetnode(fake)) {
  474. X            ff = alloc(sizeof *ff);
  475. X            *ff = *fn;
  476. X            ff->name = nam;
  477. X            addnode(tab,ff);
  478. X            ret = 1;
  479. X        }
  480. X    return ret;
  481. X}
  482. X
  483. X/* concatenate s1 and s2 in dynamically allocated buffer */
  484. X
  485. Xchar *dyncat(s1,s2) /**/
  486. Xchar *s1;char *s2;
  487. X{
  488. Xchar *ptr;
  489. X    ptr = ncalloc(strlen(s1)+strlen(s2)+1);
  490. X    strcpy(ptr,s1);
  491. X    strcat(ptr,s2);
  492. X    return ptr;
  493. X}
  494. X
  495. X/* concatenate s1, s2, and s3 in dynamically allocated buffer */
  496. X
  497. Xchar *tricat(s1,s2,s3) /**/
  498. Xchar *s1;char *s2;char *s3;
  499. X{
  500. Xchar *ptr;
  501. X
  502. X    ptr = zalloc(strlen(s1)+strlen(s2)+strlen(s3)+1);
  503. X    strcpy(ptr,s1);
  504. X    strcat(ptr,s2);
  505. X    strcat(ptr,s3);
  506. X    return ptr;
  507. X}
  508. X
  509. X/* brace expansion */
  510. X
  511. Xvoid xpandbraces(list,np) /**/
  512. XLklist list;Lknode *np;
  513. X{
  514. XLknode node = (*np),last = prevnode(node);
  515. Xchar *str = getdata(node),*str3 = str,*str2;
  516. Xint prev, bc, comma;
  517. X
  518. X    for (; *str != Inbrace; str++);
  519. X    for (str2 = str, bc = comma = 0; *str2; ++str2)
  520. X        if (*str2 == Inbrace)
  521. X            ++bc;
  522. X        else if (*str2 == Outbrace) {
  523. X            if (--bc == 0)
  524. X                break;
  525. X        }
  526. X        else if (bc == 1 && *str2 == Comma)
  527. X            ++comma;
  528. X    if (!comma && !bc && isset(BRACECCL)) {            /* {a-mnop} */
  529. X        char    ccl[256], *p;
  530. X        unsigned char c1,c2,lastch;
  531. X
  532. X        uremnode(list,node);
  533. X        memset(ccl, 0, sizeof(ccl) / sizeof(ccl[0]));
  534. X        for (p = str + 1, lastch = 0; p < str2; ) {
  535. X            if (itok(c1 = *p++))
  536. X                c1 = ztokens[c1 - STOUC(Pound)];
  537. X            if (itok(c2 = *p))
  538. X                c2 = ztokens[c2 - STOUC(Pound)];
  539. X            if (c1 == '-' && lastch && p < str2 && lastch <= c2) {
  540. X                while (lastch < c2)
  541. X                    ccl[lastch++] = 1;
  542. X                lastch = 0;
  543. X            }
  544. X            else
  545. X                ccl[lastch = c1] = 1;
  546. X        }
  547. X        strcpy(str + 1, str2 + 1);
  548. X        for (p = ccl+255; p-- > ccl; )
  549. X            if (*p) {
  550. X                *str = p - ccl;
  551. X                insnode(list, last, strdup(str3));
  552. X            }
  553. X        *np = nextnode(last);
  554. X        return;
  555. X    }
  556. X     if (str[2] == '-' && str[4] == Outbrace)     /* {a-z} */
  557. X        {
  558. X        char c1,c2;
  559. X
  560. X        uremnode(list,node);
  561. X        chuck(str);
  562. X        c1 = *str;
  563. X        chuck(str);
  564. X        chuck(str);
  565. X        c2 = *str;
  566. X        chuck(str);
  567. X        if (itok(c1))
  568. X            c1 = ztokens[c1-Pound];
  569. X        if (itok(c2))
  570. X            c2 = ztokens[c2-Pound];
  571. X        if (c1 < c2)
  572. X            for (; c2 >= c1; c2--)    /* {a-z} */
  573. X                {
  574. X                *str = c2;
  575. X                insnode(list,last,strdup(str3));
  576. X                }
  577. X        else
  578. X            for (; c2 <= c1; c2++)    /* {z-a} */
  579. X                {
  580. X                *str = c2;
  581. X                insnode(list,last,strdup(str3));
  582. X                }
  583. X        *np = nextnode(last);
  584. X        return;
  585. X        }
  586. X    prev = str-str3;
  587. X    str2 = getparen(str++);
  588. X    if (!str2)
  589. X        {
  590. X        zerr("how did you get this error?",NULL,0);
  591. X        return;
  592. X        }
  593. X    uremnode(list,node);
  594. X    node = last;
  595. X    for(;;)
  596. X        {
  597. X        char *zz,*str4;
  598. X        int cnt;
  599. X        
  600. X        for (str4 = str, cnt = 0; cnt || (*str != Comma && *str !=
  601. X                Outbrace); str++)
  602. X            if (*str == Inbrace)
  603. X                cnt++;
  604. X            else if (*str == Outbrace)
  605. X                cnt--;
  606. X            else if (!*str)
  607. X                exit(10);
  608. X        zz = zalloc(prev+(str-str4)+strlen(str2)+1);
  609. X        ztrncpy(zz,str3,prev);
  610. X        strncat(zz,str4,str-str4);
  611. X        strcat(zz,str2);
  612. X        insnode(list,node,zz);
  613. X        incnode(node);
  614. X        if (*str != Outbrace)
  615. X            str++;
  616. X        else
  617. X            break;
  618. X        }
  619. X    *np = nextnode(last);
  620. X}
  621. X
  622. X/* get closing paren, given pointer to opening paren */
  623. X
  624. Xchar *getparen(str) /**/
  625. Xchar *str;
  626. X{
  627. Xint cnt = 1;
  628. Xchar typein = *str++,typeout = typein+1;
  629. X
  630. X    for (; *str && cnt; str++)
  631. X        if (*str == typein)
  632. X            cnt++;
  633. X        else if (*str == typeout)
  634. X            cnt--;
  635. X    if (!str && cnt)
  636. X        return NULL;
  637. X    return str;
  638. X}
  639. X
  640. X/* check to see if a matches b (b is not a filename pattern) */
  641. X
  642. Xint matchpat(a,b) /**/
  643. Xchar *a;char *b;
  644. X{
  645. XComp c;
  646. Xint val,len;
  647. Xchar *b2;
  648. X
  649. X    remnulargs(b);
  650. X    len = strlen(b);
  651. X    b2 = alloc(len+3);
  652. X    strcpy(b2+1,b);
  653. X    b2[0] = Inpar;
  654. X    b2[len+1] = Outpar;
  655. X    b2[len+2] = '\0';
  656. X    c = parsereg(b2);
  657. X    if (!c)
  658. X        {
  659. X        zerr("bad pattern: %s",b,0);
  660. X        return 0;
  661. X        }
  662. X    val = domatch(a,c,0);
  663. X    return val;
  664. X}
  665. X
  666. X/* do the ${foo%%bar}, ${foo#bar} stuff */
  667. X/* please do not laugh at this code. */
  668. X
  669. Xvoid getmatch(sp,pat,dd) /**/
  670. Xchar **sp;char *pat;int dd;
  671. X{
  672. XComp c;
  673. Xchar *t,*lng = NULL,cc,*s = *sp;
  674. X
  675. X    remnulargs(pat);
  676. X    c = parsereg(pat);
  677. X    if (!c)
  678. X        {
  679. X        zerr("bad pattern: %s",pat,0);
  680. X        return;
  681. X        }
  682. X    if (!(dd & 2))
  683. X        {
  684. X        for (t = s; t==s || t[-1]; t++)
  685. X            {
  686. X            cc = *t;
  687. X            *t = '\0';
  688. X            if (domatch(s,c,0))
  689. X                {
  690. X                if (!(dd & 1))
  691. X                    {
  692. X                    *t = cc;
  693. X                    t = strdup(t);
  694. X                    *sp = t;
  695. X                    return;
  696. X                    }
  697. X                lng = t;
  698. X                }
  699. X            *t = cc;
  700. X            }
  701. X        if (lng)
  702. X            {
  703. X            t = strdup(lng);
  704. X            *sp = t;
  705. X            return;
  706. X            }
  707. X        }
  708. X    else
  709. X        {
  710. X        for (t = s+strlen(s); t >= s; t--)
  711. X            {
  712. X            if (domatch(t,c,0))
  713. X                {
  714. X                if (!(dd & 1))
  715. X                    {
  716. X                    cc = *t;
  717. X                    *t = '\0';
  718. X                    *sp = strdup(*sp);
  719. X                    *t = cc;
  720. X                    return;
  721. X                    }
  722. X                lng = t;
  723. X                }
  724. X            }
  725. X        if (lng)
  726. X            {
  727. X            cc = *lng;
  728. X            *lng = '\0';
  729. X            *sp = strdup(*sp);
  730. X            *lng = cc;
  731. X            return;
  732. X            }
  733. X        }
  734. X}
  735. X
  736. X/* add a component to pathbuf */
  737. X
  738. Xstatic int addpath(s)
  739. Xchar *s;
  740. X{
  741. X    if (strlen(s)+pathpos >= MAXPATHLEN) return 0;
  742. X    while (pathbuf[pathpos++] = *s++);
  743. X    pathbuf[pathpos-1] = '/';
  744. X    pathbuf[pathpos] = '\0';
  745. X    return 1;
  746. X}
  747. X
  748. Xchar *getfullpath(s) /**/
  749. Xchar *s;
  750. X{
  751. Xstatic char buf[MAXPATHLEN];
  752. X
  753. X    strcpy(buf,pathbuf);
  754. X    strcat(buf,s);
  755. X    return buf;
  756. X}
  757. X
  758. X/* do the globbing */
  759. X
  760. Xvoid scanner(q) /**/
  761. XComplist q;
  762. X{
  763. XComp c;
  764. Xint closure;
  765. X
  766. X    if (closure = q->closure)    /* (foo/)# */
  767. X        if (q->closure == 2)        /* (foo/)## */
  768. X            q->closure = 1;
  769. X        else
  770. X            scanner(q->next);
  771. X    if (c = q->comp)
  772. X        {
  773. X        if (!(c->next || c->left) && !haswilds(c->str))
  774. X            if (q->next)
  775. X                {
  776. X                int oppos = pathpos;
  777. X
  778. X                if (errflag)
  779. X                    return;
  780. X                if (q->closure && !strcmp(c->str,".")) return;
  781. X                if (!addpath(c->str)) return;
  782. X                if (!closure || exists(pathbuf))
  783. X                    scanner((q->closure) ? q : q->next);
  784. X                pathbuf[pathpos = oppos] = '\0';
  785. X                }
  786. X            else
  787. X                {
  788. X                char *s;
  789. X
  790. X                if (exists(s = getfullpath(c->str)))
  791. X                    insert(strdup(s));
  792. X                }
  793. X        else
  794. X            {
  795. X            char *fn;
  796. X            int dirs = !!q->next;
  797. X            struct direct *de;
  798. X            DIR *lock = opendir((*pathbuf) ? pathbuf : ".");
  799. X             
  800. X            if (lock == NULL)
  801. X                return;
  802. X            readdir(lock); readdir(lock);     /* skip . and .. */
  803. X            while (de = readdir(lock))
  804. X                {
  805. X                if (errflag)
  806. X                    break;
  807. X                fn = &de->d_name[0];
  808. X                if (domatch(fn,c,gf_noglobdots))
  809. X                    {
  810. X                    int oppos = pathpos;
  811. X
  812. X                    if (dirs)
  813. X                        {
  814. X                        if (closure)
  815. X                            {
  816. X                            int type3;
  817. X                            struct stat buf;
  818. X
  819. X                             if (lstat(getfullpath(fn),&buf) == -1)
  820. X                                {
  821. X                                if (errno != ENOENT && errno != EINTR &&
  822. X                                        errno != ENOTDIR)
  823. X                                    {
  824. X                                    zerr("%e: %s",fn,errno);
  825. X                                    errflag = 0;
  826. X                                    }
  827. X                                continue;
  828. X                                }
  829. X                            type3 = buf.st_mode & S_IFMT;
  830. X                            if (type3 != S_IFDIR)
  831. X                                continue;
  832. X                            }
  833. X                        if (addpath(fn))
  834. X                            scanner((q->closure) ? q : q->next); /* scan next level */
  835. X                        pathbuf[pathpos = oppos] = '\0';
  836. X                        }
  837. X                    else insert(dyncat(pathbuf,fn));
  838. X                    }
  839. X                }
  840. X            closedir(lock);
  841. X            }
  842. X        }
  843. X    else
  844. X        zerr("no idea how you got this error message.",NULL,0);
  845. X}
  846. X
  847. X/* do the [..(foo)..] business */
  848. X
  849. Xint minimatch(pat,str) /**/
  850. Xchar **pat;char **str;
  851. X{
  852. Xchar *pt = *pat+1,*s = *str;
  853. X    
  854. X    for (; *pt != Outpar; s++,pt++)
  855. X        if ((*pt != Quest || !*s) && *pt != *s)
  856. X            {
  857. X            *pat = getparen(*pat)-1;
  858. X            return 0;
  859. X            }
  860. X    *str = s-1;
  861. X    return 1;
  862. X}
  863. X
  864. Xstatic char *pptr;
  865. Xstatic Comp tail = 0;
  866. Xstatic int first;
  867. X
  868. Xint domatch(str,c,fist) /**/
  869. Xchar *str;Comp c;int fist;
  870. X{
  871. X    pptr = str;
  872. X    first = fist;
  873. X    return doesmatch(c);
  874. X}
  875. X
  876. X/* see if current pattern matches c */
  877. X
  878. Xint doesmatch(c) /**/
  879. XComp c;
  880. X{
  881. Xchar *pat = c->str;
  882. X
  883. X    if (c->closure == 1) {
  884. X        char *saves = pptr;
  885. X
  886. X        if (first && *pptr == '.') return 0;
  887. X        if (doesmatch(c->next)) return 1;
  888. X        pptr = saves;
  889. X        first = 0;
  890. X    }
  891. X    for(;;)
  892. X        {
  893. X        if (!pat || !*pat)
  894. X            {
  895. X            char *saves;
  896. X            int savei;
  897. X
  898. X            if (errflag)
  899. X                return 0;
  900. X            saves = pptr;
  901. X            savei = first;
  902. X            if (c->left || c->right)
  903. X                if (!doesmatch(c->left))
  904. X                    if (c->right)
  905. X                        {
  906. X                        pptr = saves;
  907. X                        first = savei;
  908. X                        if (!doesmatch(c->right))
  909. X                            return 0;
  910. X                        }
  911. X                    else
  912. X                        return 0;
  913. X            if (c->closure)
  914. X                return doesmatch(c);
  915. X            if (!c->next)
  916. X                return (!c->last || !*pptr);
  917. X            return doesmatch(c->next);
  918. X            }
  919. X        if (first && *pptr == '.' && *pat != '.')
  920. X            return 0;
  921. X        if (*pat == Star)    /* final * is not expanded to ?#; returns success */
  922. X            {
  923. X            while (*pptr) pptr++;
  924. X            return 1;
  925. X            }
  926. X        first = 0;
  927. X        if (*pat == Quest && *pptr)
  928. X            {
  929. X            pptr++;
  930. X            pat++;
  931. X            continue;
  932. X            }
  933. X        if (*pat == Hat)
  934. X            return 1-doesmatch(c->next);
  935. X        if (*pat == Inbrack) {
  936. X            if (!*pptr) break;
  937. X            if (pat[1] == Hat || pat[1] == '^') {
  938. X                pat[1] = Hat;
  939. X                for (pat += 2; *pat != Outbrack && *pat; pat++)
  940. X                    if (*pat == '-' && pat[-1] != Hat && pat[1] != Outbrack) {
  941. X                        if (pat[-1] <= *pptr && pat[1] >= *pptr)
  942. X                            break;
  943. X                    } else if (*pptr == *pat) break;
  944. X                if (!*pat) {
  945. X                    zerr("something is very wrong.",NULL,0);
  946. X                    return 0;
  947. X                }
  948. X                if (*pat != Outbrack)
  949. X                    break;
  950. X                pat++;
  951. X                pptr++;
  952. X                continue;
  953. X            } else {
  954. X                for (pat++; *pat != Outbrack && *pat; pat++)
  955. X                    if (*pat == Inpar) {
  956. X                        if (minimatch(&pat,&pptr))
  957. X                            break;
  958. X                    } else if (*pat == '-' && pat[-1] != Inbrack &&
  959. X                            pat[1] != Outbrack) {
  960. X                        if (pat[-1] <= *pptr && pat[1] >= *pptr)
  961. X                            break;
  962. X                    } else if (*pptr == *pat) break;
  963. X                if (!pat || !*pat) {
  964. X                    zerr("oh dear.  that CAN'T be right.",NULL,0);
  965. X                    return 0;
  966. X                }
  967. X                if (*pat == Outbrack)
  968. X                    break;
  969. X                for (pptr++; *pat != Outbrack; pat++);
  970. X                pat++;
  971. X                continue;
  972. X            }
  973. X        }
  974. X        if (*pat == Inang)
  975. X            {
  976. X            int t1,t2,t3;
  977. X            char *ptr;
  978. X
  979. X            if (*++pat == Outang)    /* handle <> case */
  980. X                {
  981. X                ( void ) zstrtol(pptr,&ptr,10);
  982. X                if (ptr == pptr)
  983. X                    break;
  984. X                pptr = ptr;
  985. X                pat++;
  986. X                }
  987. X            else
  988. X                {
  989. X                t1 = zstrtol(pptr,&ptr,10);
  990. X                if (ptr == pptr)
  991. X                    break;
  992. X                pptr = ptr;
  993. X                t2 = zstrtol(pat,&ptr,10);
  994. X                if (*ptr != '-')
  995. X                    exit(31);
  996. X                t3 = zstrtol(ptr+1,&pat,10);
  997. X                if (!t3)
  998. X                    t3 = -1;
  999. X                if (*pat++ != Outang)
  1000. X                    exit(21);
  1001. X                if (t1 < t2 || (t3 != -1 && t1 > t3))
  1002. X                    break;
  1003. X                }
  1004. X            continue;
  1005. X            }
  1006. X        if (*pptr == *pat)
  1007. X            {
  1008. X            pptr++;
  1009. X            pat++;
  1010. X            continue;
  1011. X            }
  1012. X        break;
  1013. X        }
  1014. X    return 0;
  1015. X}
  1016. X
  1017. XComplist parsepat(str) /**/
  1018. Xchar *str;
  1019. X{
  1020. Xchar *s;
  1021. X
  1022. X    exclude = NULL;
  1023. X    if (isset(EXTENDEDGLOB)) {
  1024. X        s = str+strlen(str);
  1025. X        while (s-- > str) {
  1026. X            if (*s == Tilde && s[1]) {
  1027. X                *s++ = '\0';
  1028. X                exclude = parsereg(s);
  1029. X                if (!exclude) return NULL;
  1030. X                break;
  1031. X            }
  1032. X        }
  1033. X    }
  1034. X    mode = 0;
  1035. X    pptr = str;
  1036. X    return parsecomplist();
  1037. X}
  1038. X
  1039. XComp parsereg(str) /**/
  1040. Xchar *str;
  1041. X{
  1042. X    mode = 1;
  1043. X    pptr = str;
  1044. X    return parsecompsw();
  1045. X}
  1046. X
  1047. XComplist parsecomplist() /**/
  1048. X{
  1049. XComp c1;
  1050. XComplist p1;
  1051. X
  1052. X    if (pptr[0] == Star && pptr[1] == Star &&
  1053. X            (pptr[2] == '/' ||
  1054. X            (pptr[2] == Star && pptr[3] == Star && pptr[4] == '/'))) {
  1055. X        pptr += 3;
  1056. X        if (pptr[-1] == Star) pptr += 2;
  1057. X        p1 = (Complist) alloc(sizeof *p1);
  1058. X        p1->next = parsecomplist();
  1059. X        p1->comp = (Comp) alloc(sizeof *p1->comp);
  1060. X        p1->comp->last = 1;
  1061. X        p1->comp->str = strdup("*");
  1062. X        *p1->comp->str = Star;
  1063. X        p1->closure = 1;
  1064. X        return p1;
  1065. X    }
  1066. X    if (*pptr == Inpar)
  1067. X        {
  1068. X        char *str;
  1069. X        int pars = 1;
  1070. X
  1071. X        for (str = pptr+1; *str && pars; str++)
  1072. X            if (*str == Inpar)
  1073. X                pars++;
  1074. X            else if (*str == Outpar)
  1075. X                pars--;
  1076. X        if (str[0] != Pound || str[-1] != Outpar || str[-2] != '/')
  1077. X            goto kludge;
  1078. X        pptr++;
  1079. X        if (!(c1 = parsecompsw()))
  1080. X            return NULL;
  1081. X        if (pptr[0] == '/' && pptr[1] == Outpar && pptr[2] == Pound)
  1082. X            {
  1083. X            int pdflag = 0;
  1084. X
  1085. X            pptr += 3;
  1086. X            if (*pptr == Pound)
  1087. X                {
  1088. X                pdflag = 1;
  1089. X                pptr++;
  1090. X                }
  1091. X            p1 = (Complist) alloc(sizeof *p1);
  1092. X            p1->comp = c1;
  1093. X            p1->closure = 1+pdflag;
  1094. X            p1->next = parsecomplist();
  1095. X            return (p1->comp) ? p1 : NULL;
  1096. X            }
  1097. X        }
  1098. X    else
  1099. X        {
  1100. Xkludge:
  1101. X        if (!(c1 = parsecompsw()))
  1102. X            return NULL;
  1103. X        if (*pptr == '/' || !*pptr)
  1104. X            {
  1105. X            int ef = *pptr == '/';
  1106. X
  1107. X            p1 = (Complist) alloc(sizeof *p1);
  1108. X            p1->comp = c1;
  1109. X            p1->closure = 0;
  1110. X            p1->next = (*pptr == '/') ? (pptr++,parsecomplist()) : NULL;
  1111. X            return (ef && !p1->next) ? NULL : p1;
  1112. X            }
  1113. X        }
  1114. X    errflag = 1;
  1115. X    return NULL;
  1116. X}
  1117. X
  1118. XComp parsecomp() /**/
  1119. X{
  1120. XComp c = (Comp) alloc(sizeof *c),c1,c2;
  1121. Xchar *s = c->str = alloc(MAXPATHLEN*2),*ls = NULL;
  1122. X
  1123. X    c->next = tail;
  1124. X
  1125. X    while (*pptr && (mode || *pptr != '/') && *pptr != Bar &&
  1126. X            *pptr != Outpar)
  1127. X        {
  1128. X        if (*pptr == Hat)
  1129. X            {
  1130. X            *s++ = Hat;
  1131. X            *s++ = '\0';
  1132. X            pptr++;
  1133. X            if (!(c->next = parsecomp()))
  1134. X                return NULL;
  1135. X            return c;
  1136. X            }
  1137. X        if (*pptr == Star && pptr[1] && (mode || pptr[1] != '/'))
  1138. X            {
  1139. X            *s++ = '\0';
  1140. X            pptr++;
  1141. X            c1 = (Comp) alloc(sizeof *c1);
  1142. X            *(c1->str = strdup("?")) = Quest;
  1143. X            c1->closure = 1;
  1144. X            if (!(c2 = parsecomp())) return NULL;
  1145. X            c1->next = c2;
  1146. X            c->next = c1;
  1147. X            return c;
  1148. X            }
  1149. X        if (*pptr == Inpar)
  1150. X            {
  1151. X            int pars = 1;
  1152. X            char *startp = pptr, *endp;
  1153. X            Comp stail = tail;
  1154. X            int dpnd = 0;
  1155. X
  1156. X            for (pptr = pptr+1; *pptr && pars; pptr++)
  1157. X                if (*pptr == Inpar)
  1158. X                    pars++;
  1159. X                else if (*pptr == Outpar)
  1160. X                    pars--;
  1161. X            if (pptr[-1] != Outpar)
  1162. X                {
  1163. X                errflag = 1;
  1164. X                return NULL;
  1165. X                }
  1166. X            if (*pptr == Pound)
  1167. X                {
  1168. X                dpnd = 1;
  1169. X                pptr++;
  1170. X                if (*pptr == Pound)
  1171. X                    {
  1172. X                    pptr++;
  1173. X                    dpnd = 2;
  1174. X                    }
  1175. X                }
  1176. X            if (!(c1 = parsecomp())) return NULL;
  1177. X            tail = c1;
  1178. X            endp = pptr;
  1179. X            pptr = startp;
  1180. X            pptr++;
  1181. X            *s++ = '\0';
  1182. X            c->next = (Comp) alloc(sizeof *c);
  1183. X            c->next->left = parsecompsw();
  1184. X            c->next->closure = dpnd;
  1185. X            c->next->next = (Comp) alloc(sizeof *c);
  1186. X            pptr = endp;
  1187. X            tail = stail;
  1188. X            return c;
  1189. X            }
  1190. X        if (*pptr == Pound)
  1191. X            {
  1192. X            *s = '\0';
  1193. X            pptr++;
  1194. X            if (!ls)
  1195. X                return NULL;
  1196. X            if (*pptr == Pound) 
  1197. X                {
  1198. X                pptr++;
  1199. X                c->next = c1 = (Comp) alloc(sizeof *c);
  1200. X                c1->str = strdup(ls);
  1201. X                }
  1202. X            else
  1203. X                c1 = c;
  1204. X            c1->next = c2 = (Comp) alloc(sizeof *c);
  1205. X            c2->str = strdup(ls);
  1206. X            c2->closure = 1;
  1207. X            c2->next = parsecomp();
  1208. X            if (!c2->next)
  1209. X                return NULL;
  1210. X            *ls++ = '\0';
  1211. X            return c;
  1212. X            }
  1213. X        ls = s;
  1214. X        if (*pptr == Inang)
  1215. X            {
  1216. X            int dshct;
  1217. X
  1218. X            dshct = (pptr[1] == Outang);
  1219. X            *s++ = *pptr++;
  1220. X            while (*pptr && (*s++ = *pptr++) != Outang)
  1221. X                if (s[-1] == '-')
  1222. X                    dshct++;
  1223. X                else if (!idigit(s[-1]))
  1224. X                    break;
  1225. X            if (s[-1] != Outang || dshct != 1)
  1226. X                return NULL;
  1227. X            }
  1228. X        else if (*pptr == Inbrack)
  1229. X            {
  1230. X            while (*pptr && (*s++ = *pptr++) != Outbrack);
  1231. X            if (s[-1] != Outbrack)
  1232. X                return NULL;
  1233. X            }
  1234. X        else if (itok(*pptr) && *pptr != Star && *pptr != Quest)
  1235. X            *s++ = ztokens[*pptr++-Pound];
  1236. X        else
  1237. X            *s++ = *pptr++;
  1238. X        }
  1239. X    if (*pptr == '/' || !*pptr)
  1240. X        c->last = 1;
  1241. X    *s++ = '\0';
  1242. X    return c;
  1243. X}
  1244. X
  1245. XComp parsecompsw() /**/
  1246. X{
  1247. XComp c1,c2,c3;
  1248. X
  1249. X    c1 = parsecomp();
  1250. X    if (!c1)
  1251. X        return NULL;
  1252. X    if (*pptr == Bar)
  1253. X        {
  1254. X        c2 = (Comp) alloc(sizeof *c2);
  1255. X        pptr++;
  1256. X        c3 = parsecompsw();
  1257. X        if (!c3)
  1258. X            return NULL;
  1259. X        c2->str = strdup("");
  1260. X        c2->left = c1;
  1261. X        c2->right = c3;
  1262. X        return c2;
  1263. X        }
  1264. X    return c1;
  1265. X}
  1266. X
  1267. X/* tokenize and see if ss matches tt */
  1268. X
  1269. Xint patmatch(ss,tt) /**/
  1270. Xchar *ss;char *tt;
  1271. X{
  1272. Xchar *s = ss,*t;
  1273. X
  1274. X    for (; *s; s++)
  1275. X        if (*s == '\\')
  1276. X            chuck(s);
  1277. X        else
  1278. X            for (t = ztokens; *t; t++)
  1279. X                if (*t == *s)
  1280. X                    {
  1281. X                    *s = (t-ztokens)+Pound;
  1282. X                    break;
  1283. X                    }
  1284. X    return matchpat(ss,tt);
  1285. X}
  1286. X
  1287. X/* remove unnecessary Nulargs */
  1288. X
  1289. Xvoid remnulargs(s) /**/
  1290. Xchar *s;
  1291. X{
  1292. Xint nl = *s;
  1293. Xchar *t = s;
  1294. X
  1295. X    while (*s)
  1296. X        if (INULL(*s))
  1297. X            chuck(s);
  1298. X        else
  1299. X            s++;
  1300. X    if (!*t && nl)
  1301. X        {
  1302. X        t[0] = Nularg;
  1303. X        t[1] = '\0';
  1304. X        }
  1305. X}
  1306. X
  1307. X/* qualifier functions */
  1308. X
  1309. Xint qualdev(buf,dv) /**/
  1310. Xstruct stat *buf;long dv;
  1311. X{
  1312. X    return buf->st_dev == dv;
  1313. X}
  1314. X
  1315. Xint qualnlink(buf,ct) /**/
  1316. Xstruct stat *buf;long ct;
  1317. X{
  1318. X    return buf->st_nlink == ct;
  1319. X}
  1320. X
  1321. Xint qualuid(buf,uid) /**/
  1322. Xstruct stat *buf;long uid;
  1323. X{
  1324. X    return buf->st_uid == uid;
  1325. X}
  1326. X
  1327. Xint qualgid(buf,gid) /**/
  1328. Xstruct stat *buf;long gid;
  1329. X{
  1330. X    return buf->st_gid == gid;
  1331. X}
  1332. X
  1333. Xint qualisdev(buf,junk) /**/
  1334. Xstruct stat *buf;long junk;
  1335. X{
  1336. X    junk = buf->st_mode & S_IFMT;
  1337. X    return junk == S_IFBLK || junk == S_IFCHR;
  1338. X}
  1339. X
  1340. Xint qualmode(buf,mod) /**/
  1341. Xstruct stat *buf;long mod;
  1342. X{
  1343. X    return (buf->st_mode & S_IFMT) == mod;
  1344. X}
  1345. X
  1346. Xint qualflags(buf,mod) /**/
  1347. Xstruct stat *buf;long mod;
  1348. X{
  1349. X    return buf->st_mode & mod;
  1350. X}
  1351. X
  1352. Xint qualiscom(buf,mod) /**/
  1353. Xstruct stat *buf;long mod;
  1354. X{
  1355. X    return (buf->st_mode & (S_IFMT|S_IEXEC)) == (S_IFREG|S_IEXEC);
  1356. X}
  1357. X
  1358. Xint qualsize(buf,size) /**/
  1359. Xstruct stat *buf;long size;
  1360. X{
  1361. X    return(range < 0 ? buf->st_size < size :
  1362. X           range > 0 ? buf->st_size > size :
  1363. X                       buf->st_size == size);
  1364. X}
  1365. X
  1366. Xint qualtime(buf,days) /**/
  1367. Xstruct stat *buf;long days;
  1368. X{
  1369. X    time_t    now, diff;
  1370. X
  1371. X    time(&now);
  1372. X    diff = now - (amc == 0 ? buf->st_atime : amc == 1 ? buf->st_mtime :
  1373. X                                buf->st_ctime);
  1374. X    diff /= 86400l;
  1375. X    return(range < 0 ? diff < days :
  1376. X           range > 0 ? diff > days :
  1377. X                       diff == days);
  1378. X}
  1379. END_OF_FILE
  1380.   if test 26147 -ne `wc -c <'src/glob.c'`; then
  1381.     echo shar: \"'src/glob.c'\" unpacked with wrong size!
  1382.   fi
  1383.   # end of 'src/glob.c'
  1384. fi
  1385. if test -f 'src/hist.c' -a "${1}" != "-c" ; then 
  1386.   echo shar: Will not clobber existing file \"'src/hist.c'\"
  1387. else
  1388.   echo shar: Extracting \"'src/hist.c'\" \(24223 characters\)
  1389.   sed "s/^X//" >'src/hist.c' <<'END_OF_FILE'
  1390. X/*
  1391. X *
  1392. X * hist.c - history expansion
  1393. X *
  1394. X * This file is part of zsh, the Z shell.
  1395. X *
  1396. X * This software is Copyright 1992 by Paul Falstad
  1397. X *
  1398. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  1399. X * use this software as long as: there is no monetary profit gained
  1400. X * specifically from the use or reproduction of this software, it is not
  1401. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  1402. X * included prominently in any copy made. 
  1403. X *
  1404. X * The author make no claims as to the fitness or correctness of this software
  1405. X * for any use whatsoever, and it is provided as is. Any use of this software
  1406. X * is at the user's own risk. 
  1407. X *
  1408. X */
  1409. X
  1410. X#include "zsh.h"
  1411. X
  1412. X#define HEAPSIZE 4096
  1413. X
  1414. Xstruct hp {
  1415. X    Hp next;
  1416. X    char *pool,*ptr;
  1417. X    int free,histno;
  1418. X};
  1419. X
  1420. Xstatic Hp hp_lit, hp_lex;
  1421. Xstatic Histent curhistent;
  1422. X
  1423. Xstatic int lastc;
  1424. X
  1425. X/* add a character to the current history word */
  1426. X
  1427. Xvoid hwaddc(c) /**/
  1428. Xint c;
  1429. X{
  1430. X    if (hlastw && chline && (!(errflag || lexstop) || c == HISTSPACE)) {
  1431. X        if (c == '!' && unset(NOBANGHIST)) hwaddc('\\');
  1432. X        *hptr++ = c;
  1433. X        if (hptr-chline >= hlinesz) {
  1434. X            int ll,flag = 0,oldsiz = hlinesz;
  1435. X
  1436. X            ll = hptr-hlastw;
  1437. X            if (curhistent->lex == chline) flag = 1;
  1438. X            chline = hp_realloc(&hp_lex,chline,oldsiz,hlinesz = oldsiz+16);
  1439. X            if (flag) curhistent->lex = chline;
  1440. X            hptr = chline+oldsiz;
  1441. X            hlastw = hptr-ll;
  1442. X        }
  1443. X    }
  1444. X}
  1445. X
  1446. X#define habort() { errflag = lexstop = 1; return ' '; }
  1447. X
  1448. X/* get a character after performing history substitution */
  1449. X
  1450. Xint hgetc() /**/
  1451. X{
  1452. Xint c,ev,farg,larg,argc,marg = -1,cflag = 0,bflag = 0;
  1453. Xchar buf[256],*ptr;
  1454. Xchar *sline,*eline;
  1455. X
  1456. Xtailrec:
  1457. X    c = hgetch();
  1458. X    if (stophist || alstackind)
  1459. X        {
  1460. X        hwaddc(c);
  1461. X        return c;
  1462. X        }
  1463. X    if (isfirstch && c == hatchar)
  1464. X        {
  1465. X        isfirstch = 0;
  1466. X        hungetch(hatchar);
  1467. X        hungets(":s");
  1468. X        goto hatskip;
  1469. X        }
  1470. X    if (c != ' ')
  1471. X        isfirstch = 0;
  1472. X    if (c == '\\') {
  1473. X        int g = hgetch();
  1474. X        
  1475. X        if (g != bangchar)
  1476. X            hungetch(g);
  1477. X        else {
  1478. X            hwaddc(bangchar);
  1479. X            return bangchar;
  1480. X        }
  1481. X    }
  1482. X    if (c != bangchar)
  1483. X        {
  1484. X        hwaddc(c);
  1485. X        return c;
  1486. X        }
  1487. Xhatskip:
  1488. X    *hptr = '\0';
  1489. X    if ((c = hgetch()) == '{')
  1490. X        {
  1491. X        bflag = cflag = 1;
  1492. X        c = hgetch();
  1493. X        }
  1494. X    if (c == '\"')
  1495. X        {
  1496. X        stophist = 1;
  1497. X        goto tailrec;
  1498. X        }
  1499. X    if ((!cflag && inblank(c)) || c == '=' || c == '(' || lexstop)
  1500. X        {
  1501. X        if (lexstop)
  1502. X            lexstop = 0;
  1503. X        else
  1504. X            hungetch(c);
  1505. X        hwaddc(bangchar);
  1506. X        return bangchar;
  1507. X        }
  1508. X    cflag = 0;
  1509. X    ptr = buf;
  1510. X
  1511. X    /* get event number */
  1512. X
  1513. X    if (c == '?')
  1514. X        {
  1515. X        for(;;)
  1516. X            {
  1517. X            c = hgetch();
  1518. X            if (c == '?' || c == '\n' || lexstop)
  1519. X                break;
  1520. X            else
  1521. X                *ptr++ = c;
  1522. X            }
  1523. X        if (c != '\n' && !lexstop)
  1524. X            c = hgetch();
  1525. X        *ptr = '\0';
  1526. X        ev = hconsearch(hsubl = ztrdup(buf),&marg);
  1527. X        if (ev == -1)
  1528. X            {
  1529. X            herrflush();
  1530. X            zerr("no such event: %s",buf,0);
  1531. X            habort();
  1532. X            }
  1533. X        }
  1534. X    else
  1535. X        {
  1536. X        int t0;
  1537. X        for (;;)
  1538. X            {
  1539. X            if (inblank(c) || c == ';' || c == ':' || c == '^' || c == '$' ||
  1540. X                    c == '*' || c == '%' || c == '}' || lexstop)
  1541. X                break;
  1542. X            if (ptr != buf) {
  1543. X                if (c == '-') break;
  1544. X                if ((idigit(buf[0]) || buf[0] == '-') && !idigit(c)) break;
  1545. X            }
  1546. X            *ptr++ = c;
  1547. X            if (c == '#' || c == bangchar)
  1548. X                {
  1549. X                c = hgetch();
  1550. X                break;
  1551. X                }
  1552. X            c = hgetch();
  1553. X            }
  1554. X        *ptr = 0;
  1555. X        if (!*buf)
  1556. X            ev = defev;
  1557. X        else if (t0 = atoi(buf))
  1558. X            ev = (t0 < 0) ? curhist+t0 : t0;
  1559. X        else if ((unsigned) *buf == bangchar)
  1560. X            ev = curhist-1;
  1561. X        else if (*buf == '#')
  1562. X            ev = curhist;
  1563. X        else if ((ev = hcomsearch(buf)) == -1)
  1564. X            {
  1565. X            zerr("event not found: %s",buf,0);
  1566. X            while (c != '\n' && !lexstop)
  1567. X                c = hgetch();
  1568. X            habort();
  1569. X            }
  1570. X        }
  1571. X
  1572. X    /* get the event */
  1573. X
  1574. X    if (!(eline = getevent(defev = ev)))
  1575. X        habort();
  1576. X
  1577. X    /* extract the relevant arguments */
  1578. X
  1579. X    argc = getargc(eline);
  1580. X    if (c == ':')
  1581. X        {
  1582. X        cflag = 1;
  1583. X        c = hgetch();
  1584. X        }
  1585. X    if (c == '*')
  1586. X        {
  1587. X        farg = 1;
  1588. X        larg = argc;
  1589. X        cflag = 0;
  1590. X        }
  1591. X    else
  1592. X        {
  1593. X        hungetch(c);
  1594. X        larg = farg = getargspec(argc,marg);
  1595. X        if (larg == -2)
  1596. X            habort();
  1597. X        if (farg != -1)
  1598. X            cflag = 0;
  1599. X        c = hgetch();
  1600. X        if (c == '*')
  1601. X            {
  1602. X            cflag = 0;
  1603. X            larg = argc;
  1604. X            }
  1605. X        else if (c == '-')
  1606. X            {
  1607. X            cflag = 0;
  1608. X            larg = getargspec(argc,marg);
  1609. X            if (larg == -2)
  1610. X                habort();
  1611. X            if (larg == -1)
  1612. X                larg = argc-1;
  1613. X            }
  1614. X        else
  1615. X            hungetch(c);
  1616. X        }
  1617. X    if (farg == -1)
  1618. X        farg = 0;
  1619. X    if (larg == -1)
  1620. X        larg = argc;
  1621. X    if (!(sline = getargs(eline,farg,larg)))
  1622. X        habort();
  1623. X
  1624. X    /* do the modifiers */
  1625. X
  1626. X    for(;;)
  1627. X        {
  1628. X        c = (cflag) ? ':' : hgetch();
  1629. X        cflag = 0;
  1630. X        if (c == ':')
  1631. X            {
  1632. X            int gbal = 0;
  1633. X        
  1634. X            if ((c = hgetch()) == 'g')
  1635. X                {
  1636. X                gbal = 1;
  1637. X                c = hgetch();
  1638. X                }
  1639. X            switch(c)
  1640. X                {
  1641. X                case 'p':
  1642. X                    histdone = HISTFLAG_DONE|HISTFLAG_NOEXEC;
  1643. X                    break;
  1644. X                case 'h':
  1645. X                    if (!remtpath(&sline))
  1646. X                        {
  1647. X                        herrflush();
  1648. X                        zerr("modifier failed: h",NULL,0);
  1649. X                        habort();
  1650. X                        }
  1651. X                    break;
  1652. X                case 'e':
  1653. X                    if (!rembutext(&sline))
  1654. X                        {
  1655. X                        herrflush();
  1656. X                        zerr("modifier failed: e",NULL,0);
  1657. X                        habort();
  1658. X                        }
  1659. X                    break;
  1660. X                case 'r':
  1661. X                    if (!remtext(&sline))
  1662. X                        {
  1663. X                        herrflush();
  1664. X                        zerr("modifier failed: r",NULL,0);
  1665. X                        habort();
  1666. X                        }
  1667. X                    break;
  1668. X                case 't':
  1669. X                    if (!remlpaths(&sline))
  1670. X                        {
  1671. X                        herrflush();
  1672. X                        zerr("modifier failed: t",NULL,0);
  1673. X                        habort();
  1674. X                        }
  1675. X                    break;
  1676. X                case 's':
  1677. X                    {
  1678. X                    int del;
  1679. X                    char *ptr1,*ptr2;
  1680. X                
  1681. X                    del = hgetch();
  1682. X                    ptr1 = hdynread2(del);
  1683. X                    if (!ptr1)
  1684. X                        habort();
  1685. X                    ptr2 = hdynread2(del);
  1686. X                    if (strlen(ptr1))
  1687. X                        {
  1688. X                        if (hsubl)
  1689. X                            free(hsubl);
  1690. X                        hsubl = ptr1;
  1691. X                        }
  1692. X                    if (hsubr)
  1693. X                        free(hsubr);
  1694. X                    hsubr = ptr2;
  1695. X                    }
  1696. X                case '&':
  1697. X                    if (hsubl && hsubr)
  1698. X                        subst(&sline,hsubl,hsubr,gbal);
  1699. X                    else
  1700. X                        {
  1701. X                        herrflush();
  1702. X                        zerr("no previous substitution with &",NULL,0);
  1703. X                        habort();
  1704. X                        }
  1705. X                    break;
  1706. X                case 'q':
  1707. X                    quote(&sline);
  1708. X                    break;
  1709. X                case 'x':
  1710. X                    quotebreak(&sline);
  1711. X                    break;
  1712. X                case 'l':
  1713. X                    downcase(&sline);
  1714. X                    break;
  1715. X                case 'u':
  1716. X                    upcase(&sline);
  1717. X                    break;
  1718. X                default:
  1719. X                    herrflush();
  1720. X                    zerr("illegal modifier: %c",NULL,c);
  1721. X                    habort();
  1722. X            }
  1723. X        }
  1724. X    else
  1725. X        {
  1726. X        if (c != '}' || !bflag)
  1727. X            hungetch(c);
  1728. X        if (c != '}' && bflag)
  1729. X            {
  1730. X            zerr("'}' expected",NULL,0);
  1731. X            habort();
  1732. X            }
  1733. X        break;
  1734. X        }
  1735. X    }
  1736. X
  1737. X    /* stuff the resulting string in the input queue and start over */
  1738. X
  1739. X    lexstop = 0;
  1740. X    if (alstackind != MAXAL)
  1741. X        {
  1742. X        hungets(HISTMARK);
  1743. X        alstack[alstackind++] = NULL;
  1744. X        }
  1745. X    for (ptr = sline; *ptr; ptr++) {
  1746. X        if (ptr[0] == '\\' && ptr[1] == '!') chuck(ptr);
  1747. X    }
  1748. X    hungets(sline);
  1749. X    histdone |= HISTFLAG_DONE;
  1750. X    if (isset(HISTVERIFY)) histdone |= HISTFLAG_NOEXEC|HISTFLAG_RECALL;
  1751. X    goto tailrec;
  1752. X}
  1753. X
  1754. X/* reset the alias stack for lexrestore () */
  1755. X
  1756. Xvoid clearalstack() /**/
  1757. X{
  1758. XAlias ix;
  1759. X
  1760. X    while (alstackind)
  1761. X        {
  1762. X        ix = alstack[--alstackind];
  1763. X        ix->inuse = 0;
  1764. X        }
  1765. X}
  1766. X
  1767. X/* get a character without history expansion */
  1768. X
  1769. Xint hgetch() /**/
  1770. X{
  1771. Xunsigned char *line,*pmpt = NULL,*pmpt2 = NULL;
  1772. Xint plen;
  1773. X
  1774. Xstart:
  1775. X    if (inbufct)
  1776. X        {
  1777. X        inbufct--;
  1778. X        if ((lastc = *inbufptr++) == ALPOP)
  1779. X            {
  1780. X            Alias ix;
  1781. X            char *t;
  1782. X
  1783. X            if (!alstackind)
  1784. X                {
  1785. X                zerr("alias stack underflow",NULL,0);
  1786. X                errflag = lexstop = 1;
  1787. X                return lastc = ' ';
  1788. X                }
  1789. X            ix = alstack[--alstackind];
  1790. X            if (ix)
  1791. X                {
  1792. X                ix->inuse = 0;
  1793. X                t = ix->text;
  1794. X                if (*t && t[strlen(t)-1] == ' ')
  1795. X                    alstat = ALSTAT_MORE;
  1796. X                else
  1797. X                    alstat = ALSTAT_JUNK;
  1798. X                }
  1799. X            goto start;
  1800. X            }
  1801. X        if (itok(lastc))
  1802. X            goto start;
  1803. X        return lastc;
  1804. X        }
  1805. X    if (strin || errflag)
  1806. X        {
  1807. X        lexstop = 1;
  1808. X        return lastc = ' ';
  1809. X        }
  1810. X    if (interact && isset(SHINSTDIN))
  1811. X        if (!isfirstln)
  1812. X            pmpt = (unsigned char *)putprompt(prompt2,&plen,0);
  1813. X        else
  1814. X            {
  1815. X            int foo;
  1816. X
  1817. X            pmpt = (unsigned char *)putprompt(prompt,&plen,0);
  1818. X            pmpt2 = (unsigned char *)((rprompt) ? putprompt(rprompt,&foo,0) : NULL);
  1819. X            }
  1820. X    if (!(interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))) {
  1821. X        char *lbuf;
  1822. X        if (interact && isset(SHINSTDIN))
  1823. X            write(2,pmpt,strlen((char *) pmpt));
  1824. X        line = (unsigned char *)fgets(lbuf = zalloc(256),256,bshin);
  1825. X        if (!line) free(lbuf);
  1826. X    } else
  1827. X        line = zleread(pmpt,pmpt2,plen);
  1828. X    if (!line) {
  1829. X        lexstop = 1;
  1830. X        return lastc = ' ';
  1831. X    }
  1832. X    if (errflag) {
  1833. X        free(line);
  1834. X        lexstop = errflag = 1;
  1835. X        return lastc = ' ';
  1836. X    }
  1837. X    if (interact && isset(SHINSTDIN)) {
  1838. X        char *s = curhistent->lit;
  1839. X        curhistent->lit = hp_concat(s,(char*)line);
  1840. X    }
  1841. X    if (isfirstln) spaceflag = *line == ' ';
  1842. X    if (isset(VERBOSE)) {
  1843. X        fputs((char *) line,stderr);
  1844. X        fflush(stderr);
  1845. X    }
  1846. X    if (*line && line[strlen((char *) line)-1] == '\n')
  1847. X        {
  1848. X        lineno++;
  1849. X        if (interact && isset(SUNKEYBOARDHACK) && isset(SHINSTDIN) && 
  1850. X                SHTTY != -1 && *line && line[1] &&
  1851. X                line[strlen((char *) line)-2] == '`')
  1852. X            {
  1853. X            int ct;
  1854. X            unsigned char *ptr;
  1855. X
  1856. X            for (ct = 0, ptr = line; *ptr; ptr++)
  1857. X                if (*ptr == '`')
  1858. X                    ct++;
  1859. X            if (ct & 1)
  1860. X                {
  1861. X                ptr[-2] = '\n';
  1862. X                ptr[-1] = '\0';
  1863. X                }
  1864. X            }
  1865. X        }
  1866. X    isfirstch = 1;
  1867. X    hungets((char*)line);
  1868. X    free(line);
  1869. X    goto start;
  1870. X}
  1871. X
  1872. X/* Read one line of at most n-1 chars from the input queue */
  1873. X
  1874. Xchar *hgets(buf, n) /**/
  1875. Xchar *buf;int n;
  1876. X{
  1877. Xint l;
  1878. X
  1879. X    for (l = 0; l < n-1; l++)
  1880. X        if ((buf[l] = hgetch()) == '\n' || lexstop)
  1881. X            break;
  1882. X    buf[l+(lexstop?0:1)] = 0;
  1883. X
  1884. X    return (!lexstop || l) ? buf : NULL;
  1885. X}
  1886. X
  1887. X/* put a string in the input queue */
  1888. X
  1889. Xvoid hungets(str) /**/
  1890. Xchar *str;
  1891. X{
  1892. Xint slen = strlen(str);
  1893. X
  1894. X/* shrink inbuf if it gets too big */
  1895. X
  1896. X    if (!inbufct && inbufsz > 65536)
  1897. X        {
  1898. X        free(inbuf);
  1899. X        inbuf = zalloc(inbufsz = 256);
  1900. X        inbufptr = inbuf+inbufsz;
  1901. X        inbufct = 0;
  1902. X        }
  1903. X    if (slen+inbufct > inbufsz)
  1904. X        {
  1905. X        char *x;
  1906. X
  1907. X        while (slen+inbufct > inbufsz)
  1908. X            inbufsz *= 4;
  1909. X        x = zalloc(inbufsz);
  1910. X        memcpy(x+inbufsz-inbufct,inbufptr,inbufct);
  1911. X        inbufptr = x+inbufsz-inbufct;
  1912. X        free(inbuf);
  1913. X        inbuf = x;
  1914. X        }
  1915. X    memcpy(inbufptr -= slen,str,slen);
  1916. X    inbufct += slen;
  1917. X}
  1918. X
  1919. X/* unget a char and remove it from chline */
  1920. X
  1921. Xvoid hungetc(c) /**/
  1922. Xint c;
  1923. X{
  1924. X    if (lexstop)
  1925. X        return;
  1926. X    if (hlastw) {
  1927. X        if (hlastw == hptr)
  1928. X            zerr("hungetc attempted at buffer start",NULL,0);
  1929. X        else {
  1930. X            hptr--;
  1931. X            if (*hptr == '!' && unset(NOBANGHIST)) hptr--;
  1932. X        }
  1933. X    }
  1934. X    hungetch(c);
  1935. X}
  1936. X
  1937. Xvoid hungetch(c) /**/
  1938. Xint c;
  1939. X{
  1940. X    if (lexstop)
  1941. X        return;
  1942. X    if (inbufct == inbufsz)
  1943. X        {
  1944. X        hungets(" ");
  1945. X        *inbufptr = c;
  1946. X        }
  1947. X    else
  1948. X        {
  1949. X        *--inbufptr = c;
  1950. X        inbufct++;
  1951. X        }
  1952. X}
  1953. X
  1954. X/* begin reading a string */
  1955. X
  1956. Xvoid strinbeg() /**/
  1957. X{
  1958. X    strin = 1;
  1959. X    hbegin();
  1960. X    lexinit();
  1961. X}
  1962. X
  1963. X/* done reading a string */
  1964. X
  1965. Xvoid strinend() /**/
  1966. X{
  1967. X    strin = 0;
  1968. X    isfirstch = 1;
  1969. X    histdone = 0;
  1970. X    hend();
  1971. X}
  1972. X
  1973. X/* stuff a whole file into the input queue and print it */
  1974. X
  1975. Xint stuff(fn) /**/
  1976. Xchar *fn;
  1977. X{
  1978. XFILE *in;
  1979. Xchar *buf;
  1980. Xint len;
  1981. X
  1982. X    if (!(in = fopen(fn,"r")))
  1983. X        {
  1984. X        zerr("can't open %s",fn,0);
  1985. X        return 1;
  1986. X        }
  1987. X    fseek(in,0,2);
  1988. X    len = ftell(in);
  1989. X    fseek(in,0,0);
  1990. X    buf = alloc(len+1);
  1991. X    if (!(fread(buf,len,1,in)))
  1992. X        {
  1993. X        zerr("read error on %s",fn,0);
  1994. X        fclose(in);
  1995. X        free(buf);
  1996. X        return 1;
  1997. X        }
  1998. X    fclose(in);
  1999. X    buf[len] = '\0';
  2000. X    fwrite(buf,len,1,stdout);
  2001. X    hungets(buf);
  2002. X    return 0;
  2003. X}
  2004. X
  2005. X/* flush input queue */
  2006. X
  2007. Xvoid hflush() /**/
  2008. X{
  2009. X    inbufptr += inbufct;
  2010. X    inbufct = 0;
  2011. X}
  2012. X
  2013. X/* initialize the history mechanism */
  2014. X
  2015. Xvoid hbegin() /**/
  2016. X{
  2017. X    isfirstln = isfirstch = 1;
  2018. X    histremmed = errflag = histdone = spaceflag = 0;
  2019. X    stophist = !interact || isset(NOBANGHIST) || unset(SHINSTDIN);
  2020. X    lithist = isset(HISTLIT);
  2021. X    chline = hptr = hp_alloc(&hp_lex,hlinesz = 16);
  2022. X    curhistent = gethistent(curhist);
  2023. X    if (!curhistent->ftim) curhistent->ftim = time(NULL);
  2024. X    if (interact && isset(SHINSTDIN) && !strin) {
  2025. X        inittty();
  2026. X        defev = curhist++;
  2027. X        if (curhist-histsiz >= 0) gethistent(curhist-histsiz)->lex = NULL;
  2028. X        if (curhist-lithistsiz >= 0) gethistent(curhist-lithistsiz)->lit = NULL;
  2029. X        curhistent = gethistent(curhist);
  2030. X        hp_purge(hp_lex,curhist-histsiz);
  2031. X        hp_purge(hp_lit,curhist-lithistsiz);
  2032. X        curhistent->lex = chline;
  2033. X        *(curhistent->lit = hp_alloc(&hp_lit,1)) = '\0';
  2034. X    } else
  2035. X        histremmed = 1;
  2036. X}
  2037. X
  2038. Xvoid inittty() /**/
  2039. X{
  2040. X    attachtty(mypgrp);
  2041. X}
  2042. X
  2043. X/* say we're done using the history mechanism */
  2044. X
  2045. Xint hend() /**/
  2046. X{
  2047. Xint flag,save = 1;
  2048. XHistent he;
  2049. X
  2050. X    if (!chline)
  2051. X        return 1;
  2052. X    if (!interact || strin || unset(SHINSTDIN)) {
  2053. X        hp_free(hp_lex,chline,hlinesz);
  2054. X        return 1;
  2055. X    }
  2056. X    flag = histdone;
  2057. X    histdone = 0;
  2058. X    if (hptr < chline+2)
  2059. X        save = 0;
  2060. X    else {
  2061. X        char *s,*t;
  2062. X
  2063. X        s = curhistent->lit;
  2064. X        if (*s && *(t = s+strlen(s)-1) == HISTSPACE) *t = '\0';
  2065. X        hptr[-1] = '\0';
  2066. X        if (hptr[-2] == '\n')
  2067. X            if (chline[1]) {
  2068. X                if (hptr[-3] == HISTSPACE) hptr[-3] = '\0';
  2069. X            } else save = 0;
  2070. X        he = gethistent(curhist-1);
  2071. X        if (!strcmp(chline,"\n") ||
  2072. X                (isset(HISTIGNOREDUPS) && he->lex && !strcmp(he->lex,chline)) ||
  2073. X                (isset(HISTIGNORESPACE) && spaceflag))
  2074. X            save = 0;
  2075. X    }
  2076. X    if (flag & (HISTFLAG_DONE|HISTFLAG_RECALL)) {
  2077. X        char *ptr,*p;
  2078. X        p = ptr = ztrdup(chline);
  2079. X        for (;*p;p++) if (*p == HISTSPACE) *p = ' ';
  2080. X        if ((flag & (HISTFLAG_DONE|HISTFLAG_RECALL)) == HISTFLAG_DONE) {
  2081. X            fprintf(stderr,"%s\n",ptr);
  2082. X            fflush(stderr);
  2083. X        }
  2084. X        if (flag & HISTFLAG_RECALL) {
  2085. X            permalloc();
  2086. X            pushnode(bufstack,ptr);
  2087. X            lastalloc();
  2088. X            save = 0;
  2089. X        } else free(ptr);
  2090. X    }
  2091. X    curhistent->stim = time(NULL);
  2092. X    curhistent->ftim = 0L;
  2093. X    curhistent->flags = 0;
  2094. X    if (!save) remhist();
  2095. X    if (chline && !curhistent->lex) hp_free(hp_lex,chline,hlinesz);
  2096. X    chline = NULL;
  2097. X    return !(flag & HISTFLAG_NOEXEC || errflag);
  2098. X}
  2099. X
  2100. X/* remove the current line from the history List */
  2101. X
  2102. Xvoid remhist() /**/
  2103. X{
  2104. X    if (!histremmed) { histremmed = 1; curhist--; }
  2105. X}
  2106. X
  2107. X/* begin a word */
  2108. X
  2109. Xvoid hwbegin() /**/
  2110. X{
  2111. X    hlastw = hptr;
  2112. X}
  2113. X
  2114. X/* add a word to the history List */
  2115. X
  2116. Xchar *hwadd() /**/
  2117. X{
  2118. Xchar *ret = hlastw;
  2119. X
  2120. X    if (hlastw && chline)
  2121. X        {
  2122. X        hwaddc(HISTSPACE);
  2123. X        if (alstackind || strin)
  2124. X            if (!(alstackind == 1 && !alstack[0]))
  2125. X                hptr = hlastw;
  2126. X        }
  2127. X    if (alstat == ALSTAT_JUNK)
  2128. X        alstat = 0;
  2129. X    return ret;
  2130. X}
  2131. X
  2132. X/* get an argument specification */
  2133. X
  2134. Xint getargspec(argc,marg) /**/
  2135. Xint argc;int marg;
  2136. X{
  2137. Xint c,ret = -1;
  2138. X    if ((c = hgetch()) == '0')
  2139. X        return 0;
  2140. X    if (idigit(c))
  2141. X        {
  2142. X        ret = 0;
  2143. X        while (idigit(c))
  2144. X            {
  2145. X            ret = ret*10+c-'0';
  2146. X            c = hgetch();
  2147. X            }
  2148. X        hungetch(c);
  2149. X        }
  2150. X    else if (c == '^')
  2151. X        ret = 1;
  2152. X    else if (c == '$')
  2153. X        ret = argc;
  2154. X    else if (c == '%')
  2155. X        {
  2156. X        if (marg == -1)
  2157. X            {
  2158. X            herrflush();
  2159. X            zerr("%% with no previous word matched",NULL,0);
  2160. X            return -2;
  2161. X            }
  2162. X        ret = marg;
  2163. X        }
  2164. X    else
  2165. X        hungetch(c);
  2166. X    return ret;
  2167. X}
  2168. X
  2169. X/* do ?foo? search */
  2170. X
  2171. Xint hconsearch(str,marg) /**/
  2172. Xchar *str;int *marg;
  2173. X{
  2174. Xint t0,t1 = 0;
  2175. Xchar *s,*hs;
  2176. X
  2177. X    for (t0 = curhist-1; hs = quietgetevent(t0); t0--)
  2178. X        if (s = ztrstr(hs,str)) {
  2179. X            while (s != hs) if (*s-- == HISTSPACE) t1++;
  2180. X            *marg = t1;
  2181. X            return t0;
  2182. X        }
  2183. X    return -1;
  2184. X}
  2185. X
  2186. X/* do !foo search */
  2187. X
  2188. Xint hcomsearch(str) /**/
  2189. Xchar *str;
  2190. X{
  2191. Xint t0;
  2192. Xchar *hs;
  2193. X
  2194. X    for (t0 = curhist-1; hs = quietgetevent(t0); t0--)
  2195. X        if (!strncmp(hs,str,strlen(str))) return t0;
  2196. X    return -1;
  2197. X}
  2198. X
  2199. X/* various utilities for : modifiers */
  2200. X
  2201. Xint remtpath(junkptr) /**/
  2202. Xchar **junkptr;
  2203. X{
  2204. Xchar *str = *junkptr,*cut;
  2205. X    if (cut = strrchr(str,'/')) {
  2206. X        if (str != cut) *cut = '\0';
  2207. X        else str[1] = '\0';
  2208. X        return 1;
  2209. X    }
  2210. X    return 0;
  2211. X}
  2212. Xint remtext(junkptr) /**/
  2213. Xchar **junkptr;
  2214. X{
  2215. Xchar *str = *junkptr,*cut;
  2216. X    if ((cut = strrchr(str,'.')) && cut != str)
  2217. X        {
  2218. X        *cut = '\0';
  2219. X        return 1;
  2220. X        }
  2221. X    return 0;
  2222. X}
  2223. Xint rembutext(junkptr) /**/
  2224. Xchar **junkptr;
  2225. X{
  2226. Xchar *str = *junkptr,*cut;
  2227. X    if ((cut = strrchr(str,'.')) && cut != str)
  2228. X        {
  2229. X        *junkptr = strdup(cut+1);  /* .xx or xx? */
  2230. X        return 1;
  2231. X        }
  2232. X    return 0;
  2233. X}
  2234. Xint remlpaths(junkptr) /**/
  2235. Xchar **junkptr;
  2236. X{
  2237. Xchar *str = *junkptr,*cut;
  2238. X    if (cut = strrchr(str,'/'))
  2239. X        {
  2240. X        *cut = '\0';
  2241. X        *junkptr = strdup(cut+1);
  2242. X        return 1;
  2243. X        }
  2244. X    return 0;
  2245. X}
  2246. X
  2247. Xint makeuppercase(junkptr) /**/
  2248. Xchar **junkptr;
  2249. X{
  2250. Xchar *str = *junkptr;
  2251. X
  2252. X    for (; *str; str++)
  2253. X        *str = tuupper(*str);
  2254. X    return 1;
  2255. X}
  2256. X
  2257. Xint makelowercase(junkptr) /**/
  2258. Xchar **junkptr;
  2259. X{
  2260. Xchar *str = *junkptr;
  2261. X
  2262. X    for (; *str; str++)
  2263. X        *str = tulower(*str);
  2264. X    return 1;
  2265. X}
  2266. X
  2267. Xvoid subst(strptr,in,out,gbal) /**/
  2268. Xchar **strptr;char *in;char *out;int gbal;
  2269. X{
  2270. Xchar *str = *strptr,*cut,*sptr;
  2271. Xint off;
  2272. X
  2273. X    while (cut = (char *) ztrstr(str,in)) {
  2274. X        *cut = '\0';
  2275. X        sptr = convamps(out,in);
  2276. X        off = cut-*strptr+strlen(sptr);
  2277. X        cut += strlen(in);
  2278. X        *strptr = tricat(*strptr,sptr,cut);
  2279. X        if (gbal) {
  2280. X            str = (char *) *strptr+off;
  2281. X            continue;
  2282. X        }
  2283. X        break;
  2284. X    }
  2285. X}
  2286. Xchar *convamps(out,in) /**/
  2287. Xchar *out;char *in;
  2288. X{
  2289. Xchar *ptr,*ret,*pp;
  2290. Xint slen,inlen = strlen(in);
  2291. X    for (ptr = out, slen = 0; *ptr; ptr++,slen++)
  2292. X        if (*ptr == '\\')
  2293. X            ptr++;
  2294. X        else if (*ptr == '&')
  2295. X            slen += inlen-1;
  2296. X    ret = pp = alloc(slen+1);
  2297. X    for (ptr = out; *ptr; ptr++)
  2298. X        if (*ptr == '\\')
  2299. X            *pp++ = *++ptr;
  2300. X        else if (*ptr == '&')
  2301. X            {
  2302. X            strcpy(pp,in);
  2303. X            pp += inlen;
  2304. X            }
  2305. X        else
  2306. X            *pp++ = *ptr;
  2307. X    *pp = '\0';
  2308. X    return ret;
  2309. X}
  2310. X
  2311. Xchar *makehstr(s) /**/
  2312. Xchar *s;
  2313. X{
  2314. Xchar *t;
  2315. X
  2316. X    t = s = strdup(s);
  2317. X    for (; *t; t++)
  2318. X        if (*t == HISTSPACE)
  2319. X            *t = ' ';
  2320. X    return s;
  2321. X}
  2322. X
  2323. Xchar *quietgetevent(ev) /**/
  2324. Xint ev;
  2325. X{
  2326. XHistent ent;
  2327. X
  2328. X    if (ev < firsthist()) return NULL;
  2329. X    ent = gethistent(ev);
  2330. X    return (lithist) ? ent->lit : ent->lex;
  2331. X}
  2332. X
  2333. Xchar *getevent(ev) /**/
  2334. Xint ev;
  2335. X{
  2336. Xchar *ret;
  2337. X
  2338. X    ret = quietgetevent(ev);
  2339. X    if (!ret) {
  2340. X        herrflush();
  2341. X        zerr("no such event: %d",NULL,ev);
  2342. X    }
  2343. X    return ret;
  2344. X}
  2345. Xint getargc(list) /**/
  2346. Xchar *list;
  2347. X{
  2348. Xint argc = 0;
  2349. X
  2350. X    for (; *list; list++) if (*list == HISTSPACE) argc++;
  2351. X    return argc;
  2352. X}
  2353. Xchar *getargs(elist,arg1,arg2) /**/
  2354. Xchar *elist;int arg1;int arg2;
  2355. X{
  2356. Xchar *ret = elist,*retn;
  2357. Xint acnt = arg2-arg1+1;
  2358. X
  2359. X    while (arg1--)
  2360. X        while (*ret && *ret++ != HISTSPACE);
  2361. X    if (!*ret)
  2362. X        {
  2363. X        herrflush();
  2364. X        zerr("no such word in event",NULL,0);
  2365. X        return NULL;
  2366. X        }
  2367. X    retn = ret = strdup(ret);
  2368. X    while (acnt > 0)
  2369. X        {
  2370. X        while (*ret && *ret != HISTSPACE)
  2371. X            ret++;
  2372. X        if (*ret == HISTSPACE)
  2373. X            *ret = ' ';
  2374. X        else
  2375. X            break;
  2376. X        acnt--;
  2377. X        }
  2378. X    if (acnt > 1 && !*ret)
  2379. X        {
  2380. X        herrflush();
  2381. X        zerr("no such word in event",NULL,0);
  2382. X        return NULL;
  2383. X        }
  2384. X    *ret = '\0';
  2385. X    return retn;
  2386. X}
  2387. X
  2388. Xvoid upcase(x) /**/
  2389. Xchar **x;
  2390. X{
  2391. Xchar *pp = *(char **) x;
  2392. X
  2393. X    for (; *pp; pp++)
  2394. X        *pp = tuupper(*pp);
  2395. X}
  2396. X
  2397. Xvoid downcase(x) /**/
  2398. Xchar **x;
  2399. X{
  2400. Xchar *pp = *(char **) x;
  2401. X
  2402. X    for (; *pp; pp++)
  2403. X        *pp = tulower(*pp);
  2404. X}
  2405. X
  2406. Xint quote(tr) /**/
  2407. Xchar **tr;
  2408. X{
  2409. Xchar *ptr,*rptr,**str = (char **) tr;
  2410. Xint len = 3;
  2411. X    for (ptr = *str; *ptr; ptr++,len++)
  2412. X        if (*ptr == '\'') len += 3;
  2413. X    ptr = *str;
  2414. X    *str = rptr = alloc(len);
  2415. X    *rptr++ = '\'';
  2416. X    for (; *ptr; ptr++)
  2417. X        if (*ptr == '\'') {
  2418. X            *rptr++ = '\''; *rptr++ = '\\'; *rptr++ = '\''; *rptr++ = '\'';
  2419. X        } else
  2420. X            *rptr++ = *ptr;
  2421. X    *rptr++ = '\'';
  2422. X    *rptr++ = 0;
  2423. X    str[1] = NULL;
  2424. X    return 0;
  2425. X}
  2426. Xint quotebreak(tr) /**/
  2427. Xchar **tr;
  2428. X{
  2429. Xchar *ptr,*rptr,**str = (char **) tr;
  2430. Xint len = 3;
  2431. X    for (ptr = *str; *ptr; ptr++,len++)
  2432. X        if (*ptr == '\'')
  2433. X            len += 3;
  2434. X        else if (inblank(*ptr))
  2435. X            len += 2;
  2436. X    ptr = *str;
  2437. X    *str = rptr = alloc(len);
  2438. X    *rptr++ = '\'';
  2439. X    for (; *ptr; )
  2440. X        if (*ptr == '\'') {
  2441. X            *rptr++ = '\''; *rptr++ = '\\'; *rptr++ = '\''; *rptr++ = '\'';
  2442. X            ptr++;
  2443. X        } else if (inblank(*ptr)) {
  2444. X            *rptr++ = '\''; *rptr++ = *ptr++; *rptr++ = '\'';
  2445. X        } else
  2446. X            *rptr++ = *ptr++;
  2447. X    *rptr++ = '\'';
  2448. X    *rptr++ = '\0';
  2449. X    return 0;
  2450. X}
  2451. X
  2452. Xvoid herrflush() /**/
  2453. X{
  2454. X    if (strin)
  2455. X        hflush();
  2456. X    else while (lastc != '\n' && !lexstop)
  2457. X        hgetch();
  2458. X}
  2459. X
  2460. X/* read an arbitrary amount of data into a buffer until stop is found */
  2461. X
  2462. Xchar *hdynread(stop) /**/
  2463. Xint stop;
  2464. X{
  2465. Xint bsiz = 256,ct = 0,c;
  2466. Xchar *buf = zalloc(bsiz),*ptr;
  2467. X    ptr = buf;
  2468. X    while ((c = hgetch()) != stop && c != '\n' && !lexstop)
  2469. X        {
  2470. X        if (c == '\\')
  2471. X            c = hgetch();
  2472. X        *ptr++ = c;
  2473. X        if (++ct == bsiz)
  2474. X            {
  2475. X            buf = realloc(buf,bsiz *= 2);
  2476. X            ptr = buf+ct;
  2477. X            }
  2478. X        }
  2479. X    *ptr = 0;
  2480. X    if (c == '\n')
  2481. X        {
  2482. X        hungetch('\n');
  2483. X        zerr("delimiter expected",NULL,0);
  2484. X        free(buf);
  2485. X        return NULL;
  2486. X        }
  2487. X    return buf;
  2488. X}
  2489. Xchar *hdynread2(stop) /**/
  2490. Xint stop;
  2491. X{
  2492. Xint bsiz = 256,ct = 0,c;
  2493. Xchar *buf = zalloc(bsiz),*ptr;
  2494. X    ptr = buf;
  2495. X    while ((c = hgetch()) != stop && c != '\n' && !lexstop)
  2496. X        {
  2497. X        if (c == '\n')
  2498. X            {
  2499. X            hungetch(c);
  2500. X            break;
  2501. X            }
  2502. X        if (c == '\\')
  2503. X            c = hgetch();
  2504. X        *ptr++ = c;
  2505. X        if (++ct == bsiz)
  2506. X            {
  2507. X            buf = realloc(buf,bsiz *= 2);
  2508. X            ptr = buf+ct;
  2509. X            }
  2510. X        }
  2511. X    *ptr = 0;
  2512. X    if (c == '\n')
  2513. X        hungetch('\n');
  2514. X    return buf;
  2515. X}
  2516. X
  2517. Xvoid inithist() /**/
  2518. X{
  2519. X    hp_lit = zcalloc(sizeof *hp_lit);
  2520. X    hp_lit->next = NULL;
  2521. X    hp_lit->ptr = hp_lit->pool = zcalloc(HEAPSIZE);
  2522. X    hp_lit->free = HEAPSIZE;
  2523. X    hp_lex = zcalloc(sizeof *hp_lex);
  2524. X    hp_lex->next = NULL;
  2525. X    hp_lex->ptr = hp_lex->pool = zcalloc(HEAPSIZE);
  2526. X    hp_lex->free = HEAPSIZE;
  2527. X    histentct = (lithistsiz > histsiz) ? lithistsiz : histsiz;
  2528. X    histentarr = zcalloc(histentct*sizeof *histentarr);
  2529. X}
  2530. X
  2531. Xvoid resizehistents() /**/
  2532. X{
  2533. Xint newentct,t0,t1,firstlit,firstlex;
  2534. XHistent newarr;
  2535. X
  2536. X    newentct = (lithistsiz > histsiz) ? lithistsiz : histsiz;
  2537. X    newarr = zcalloc(newentct*sizeof *newarr);
  2538. X    firstlex = curhist-histsiz+1;
  2539. X    firstlit = curhist-lithistsiz+1;
  2540. X    t0 = firsthist();
  2541. X    if (t0 < curhist-newentct) t0 = curhist-newentct;
  2542. X    t1 = t0 % newentct;
  2543. X    for (; t0 <= curhist; t0++) {
  2544. X        newarr[t1] = *gethistent(t0);
  2545. X        if (t0 < firstlex) newarr[t1].lex = NULL;
  2546. X        if (t0 < firstlit) newarr[t1].lit = NULL;
  2547. X        t1++; if (t1 == newentct) t1 = 0;
  2548. X    }
  2549. X    free(histentarr);
  2550. X    histentarr = newarr;
  2551. X    histentct = newentct;
  2552. X}
  2553. X
  2554. Xchar *hp_alloc(hp,siz) /**/
  2555. XHp *hp; int siz;
  2556. X{
  2557. Xchar *ret;
  2558. XHp h = *hp;
  2559. X
  2560. X    if (h->free >= siz) {
  2561. X        ret = h->ptr;
  2562. X        h->ptr += siz;
  2563. X        h->free -= siz;
  2564. X        return ret;
  2565. X    }
  2566. X#ifdef MEMDEBUG
  2567. X    fprintf(stderr,"new heap (siz = %d, curhist = %d)\n",siz,curhist);
  2568. X#endif
  2569. X    permalloc();
  2570. X    h = zalloc(sizeof *h);
  2571. X    h->next = *hp;
  2572. X    h->free = (siz > HEAPSIZE) ? siz : HEAPSIZE;
  2573. X    h->ptr = h->pool = zalloc(h->free);
  2574. X    h->histno = curhist;
  2575. X    *hp = h;
  2576. X    heapalloc();
  2577. X    return hp_alloc(hp,siz);
  2578. X}
  2579. X
  2580. Xchar *hp_realloc(hp,ptr,oldsiz,newsiz) /**/
  2581. XHp *hp; char *ptr; int oldsiz; int newsiz;
  2582. X{
  2583. XHp h = *hp;
  2584. Xint delta = newsiz-oldsiz;
  2585. Xchar *ret;
  2586. X
  2587. X    if (h->ptr-oldsiz == ptr && h->free >= delta) {
  2588. X        h->free -= delta;
  2589. X        h->ptr += delta;
  2590. X        return ptr;
  2591. X    }
  2592. X#ifdef MEMDEBUG
  2593. X    fprintf(stderr,"realloc copy\n");
  2594. X#endif
  2595. X    memcpy(ret = hp_alloc(hp,newsiz),ptr,oldsiz);
  2596. X    return ret;
  2597. X}
  2598. X
  2599. Xvoid hp_free(h,ptr,siz) /**/
  2600. XHp h; char *ptr; int siz;
  2601. X{
  2602. X    if (h->ptr-siz == ptr) {
  2603. X        h->free += siz;
  2604. X        h->ptr -= siz;
  2605. X    }
  2606. X}
  2607. X
  2608. Xchar *hp_concat(old,new) /**/
  2609. Xchar *old; char *new;
  2610. X{
  2611. Xint oldlen,newlen;
  2612. X
  2613. X    oldlen = strlen(old); newlen = strlen(new);
  2614. X    old = hp_realloc(&hp_lit,old,oldlen+1,oldlen+newlen+1);
  2615. X    strcpy(old+oldlen,new);
  2616. X    return old;
  2617. X}
  2618. X
  2619. Xvoid hp_purge(h,lim) /**/
  2620. XHp h; int lim;
  2621. X{
  2622. XHp hlast;
  2623. X
  2624. X    if (!h->next) return;
  2625. X    while (h->next) { hlast = h; h = h->next; }
  2626. X    if (hlast->histno <= lim) {
  2627. X#ifdef MEMDEBUG
  2628. X        fprintf(stderr,"purging %d\n",lim);
  2629. X#endif
  2630. X        free(h->pool);
  2631. X        free(h);
  2632. X        hlast->next = NULL;
  2633. X    }
  2634. X}
  2635. X
  2636. Xvoid readhistfile(s,err) /**/
  2637. Xchar *s;int err;
  2638. X{
  2639. Xchar buf[1024];
  2640. XFILE *in;
  2641. XHistent ent;
  2642. Xtime_t tim = time(NULL);
  2643. X
  2644. X    if (!s) return;
  2645. X    if (in = fopen(s,"r")) {
  2646. X        while (fgets(buf,sizeof(buf),in)) {
  2647. X            int l = strlen(buf);
  2648. X            char *pt = buf;
  2649. X
  2650. X            while (l && buf[l-1] == '\n') {
  2651. X                buf[l-1] = '\0';
  2652. X                if (l > 1 && buf[l-2] == '\\') {
  2653. X                    buf[l-2] = '\n';
  2654. X                    fgets(buf+l-1,sizeof(buf)-(l-1),in);
  2655. X                    l = strlen(buf);
  2656. X                } else break;
  2657. X            }
  2658. X            for (;*pt;pt++) if (*pt == ' ') *pt = HISTSPACE;
  2659. X
  2660. X            ent = gethistent(++curhist);
  2661. X            pt = buf;
  2662. X            if (*pt == ':') {
  2663. X                pt++;
  2664. X                ent->stim = atol(pt);
  2665. X                for(;*pt != ':' && *pt; pt++)
  2666. X                    ;
  2667. X                if (*pt) {
  2668. X                    pt++;
  2669. X                    ent->ftim = atol(pt);
  2670. X                    for(;*pt != ':' && *pt; pt++)
  2671. X                        ;
  2672. X                    if (*pt) pt++;
  2673. X                } else {
  2674. X                    ent->ftim = tim;
  2675. X                }
  2676. X                if (ent->stim == 0) ent->stim = tim;
  2677. X                if (ent->ftim == 0) ent->ftim = tim;
  2678. X            } else {
  2679. X            ent->ftim = ent->stim = tim;
  2680. X        }
  2681. X            ent->lex = hp_alloc(&hp_lex,strlen(pt)+1);
  2682. X            strcpy(ent->lex,pt);
  2683. X            ent->lit = hp_alloc(&hp_lit,strlen(pt)+1);
  2684. X            strcpy(ent->lit,pt);
  2685. X            ent->flags = HIST_OLD;
  2686. X        }
  2687. X        fclose(in);
  2688. X    } else if (err)
  2689. X        zerr("can't read history file",s,0);
  2690. X}
  2691. X
  2692. Xvoid savehistfile(s,err,app) /**/
  2693. Xchar *s;int err;int app;
  2694. X{
  2695. Xchar *t;
  2696. XFILE *out;
  2697. Xint ev,flag;
  2698. XHistent ent;
  2699. X
  2700. X    if (!s || !interact || savehist == 0) return;
  2701. X    ev = curhist-savehist+1;
  2702. X    flag = (app & 1) ? O_APPEND : O_TRUNC;
  2703. X    if (ev < firsthist()) ev = firsthist();
  2704. X    if (out = fdopen(open(s,O_CREAT|O_WRONLY|flag,0600),"w")) {
  2705. X        for (; ev <= curhist; ev++) {
  2706. X            ent = gethistent(ev);
  2707. X            if (app & 2) {
  2708. X                if (ent->flags & HIST_OLD) continue;
  2709. X                ent->flags |= HIST_OLD;
  2710. X            }
  2711. X            t = ((lithist) ? ent->lit : ent->lex);
  2712. X            if (isset(EXTENDEDHISTORY)) {
  2713. X              fprintf(out, ":%d:%d:", ent->stim,
  2714. X                  ent->ftim);
  2715. X            }
  2716. X            for (; *t; t++)
  2717. X                if (*t == HISTSPACE) fputc(' ',out);
  2718. X                else {
  2719. X                    if (*t == '\n') fputc('\\',out);
  2720. X                    fputc(*t,out);
  2721. X                }
  2722. X            fputc('\n',out);
  2723. X        }
  2724. X        fclose(out);
  2725. X    } else if (err) zerr("can't write history file: %s",s,0);
  2726. X}
  2727. X
  2728. Xint firsthist() /**/
  2729. X{
  2730. Xint ev;
  2731. XHistent ent;
  2732. X
  2733. X    ev = curhist-histentct+1;
  2734. X    if (ev < 1) ev = 1;
  2735. X    do {
  2736. X        ent = gethistent(ev);
  2737. X        if ((lithist) ? ent->lit : ent->lex) break;
  2738. X        ev++;
  2739. X    } while (ev < curhist);
  2740. X    return ev;
  2741. X}
  2742. END_OF_FILE
  2743.   if test 24223 -ne `wc -c <'src/hist.c'`; then
  2744.     echo shar: \"'src/hist.c'\" unpacked with wrong size!
  2745.   fi
  2746.   # end of 'src/hist.c'
  2747. fi
  2748. echo shar: End of archive 14 \(of 22\).
  2749. cp /dev/null ark14isdone
  2750. MISSING=""
  2751. 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
  2752.     if test ! -f ark${I}isdone ; then
  2753.     MISSING="${MISSING} ${I}"
  2754.     fi
  2755. done
  2756. if test "${MISSING}" = "" ; then
  2757.     echo You have unpacked all 22 archives.
  2758.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2759. else
  2760.     echo You still must unpack the following archives:
  2761.     echo "        " ${MISSING}
  2762. fi
  2763. exit 0
  2764.  
  2765. exit 0 # Just in case...
  2766.