home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / sh_dos / part03 < prev    next >
Text File  |  1990-02-13  |  81KB  |  3,988 lines

  1. Newsgroups: comp.sources.misc
  2. organization: ITM Sector, Data Logic Ltd. (A Raytheon Company)
  3. From: istewart@datlog.co.uk (Ian Stewartson)
  4. subject: v10i055: MSDOS Shell (sh) Implementation - Part 02 of 05
  5. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  6.  
  7. Posting-number: Volume 10, Issue 55
  8. Submitted-by: istewart@datlog.co.uk (Ian Stewartson)
  9. Archive-name: sh_dos/part03
  10.  
  11. #!/bin/sh
  12. # this is part 2 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file lib/ms_dio.c continued
  15. #
  16. CurArch=2
  17. if test ! -r s2_seq_.tmp
  18. then echo "Please unpack part 1 first!"
  19.      exit 1; fi
  20. ( read Scheck
  21.   if test "$Scheck" != $CurArch
  22.   then echo "Please unpack part $Scheck next!"
  23.        exit 1;
  24.   else exit 0; fi
  25. ) < s2_seq_.tmp || exit 1
  26. echo "x - Continuing file lib/ms_dio.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> lib/ms_dio.c
  28. X
  29. X    if (FP->drive & HD_FLAG)
  30. X    {
  31. X        struct partition    *pp, tp;
  32. X
  33. X/* System call failed - no device */
  34. X
  35. X        if ((iregs.x.cflag) || (ndrive >= iregs.h.dl))
  36. X        {
  37. X        free (FP);
  38. X        errno = ENOENT;
  39. X        return -1;
  40. X        }
  41. X
  42. X/* OK - save the parameters */
  43. X
  44. X        FP->m_cyl    = (iregs.h.ch | ((iregs.h.cl & 0x0c0) << 2)) + 2;
  45. X        FP->m_head   = iregs.h.dh + 1;
  46. X        FP->m_sector = iregs.h.cl & 0x03f;
  47. X        FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
  48. X
  49. X/* If this is not partition 0 - read the partition table */
  50. X
  51. X        if (FP->partition)
  52. X        {
  53. X        if (dio_do (BIOS_READ, FP, buf, 0L, 1) == -1)
  54. X        {
  55. X            free (FP);
  56. X            return -1;
  57. X        }
  58. X
  59. X        if (*(int *)&buf[510] != 0xaa55)
  60. X        {
  61. X            errno = ENOENT;
  62. X            return -1;
  63. X        }
  64. X
  65. X/* Sort the partition table */
  66. X
  67. X        pp = (struct partition *)&buf[0x1be];
  68. X
  69. X        for (i = 0; i < 4; i++)
  70. X        {
  71. X            for (j = 0; j < 3; j++)
  72. X            {
  73. X            if (((!pp[j].offset) && pp[j + 1].offset) ||
  74. X                ((pp[j].offset > pp[j + 1].offset) &&
  75. X                  pp[j + 1].offset))
  76. X            {
  77. X                tp        = pp[j];
  78. X                pp[j]     = pp[j + 1];
  79. X                pp[j + 1] = tp;
  80. X            }
  81. X            }
  82. X        }
  83. X
  84. X        if (pp[FP->partition - 1].offset == 0L)
  85. X        {
  86. X            errno = ENOENT;
  87. X            return -1;
  88. X        }
  89. X
  90. X        FP->m_start = pp[FP->partition - 1].offset;
  91. X        FP->m_scount = pp[FP->partition - 1].size;
  92. X        }
  93. X    }
  94. X
  95. X/* Floppy disk - get parameters.  We try our best here, but DOS 3.3 allows
  96. X * you to format any number of sectors per track and tracks per disk
  97. X */
  98. X
  99. X    else
  100. X    {
  101. X
  102. X/* System call failed - think this means we're on an XT.  So set up the
  103. X * XT parameters
  104. X */
  105. X
  106. X        if ((iregs.x.cflag) && (ndrive < 2))
  107. X        {
  108. X        iregs.h.bl   = 0x01;
  109. X        FP->m_cyl    = 40;
  110. X        FP->m_head   = 2;
  111. X        FP->m_sector = 9;
  112. X        }
  113. X
  114. X/* No Drive */
  115. X
  116. X        else if ((iregs.x.cflag) || (ndrive >= iregs.h.dl))
  117. X        {
  118. X        free (FP);
  119. X        errno = ENOENT;
  120. X        return -1;
  121. X        }
  122. X
  123. X/* OK - save the parameters */
  124. X
  125. X        else
  126. X        {
  127. X        FP->m_cyl    = iregs.h.ch;
  128. X        FP->m_head   = iregs.h.dh + 1;
  129. X        FP->m_sector = iregs.h.cl;
  130. X        }
  131. X
  132. X        FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
  133. X
  134. X/* High capacity drive ? */
  135. X
  136. X        if ((iregs.h.bl == 0x02) || (iregs.h.bl == 0x03))
  137. X        {
  138. X
  139. X/* Try reading sector 0 */
  140. X
  141. X        FP->m_sector = (iregs.h.bl == 0x02) ? 9 : 15;
  142. X
  143. X/* If it failed - switch to the other type */
  144. X
  145. X        if (dio_do (BIOS_READ, FP, buf, 0L, 1) == -1)
  146. X        {
  147. X            FP->m_sector = (iregs.h.bl == 0x02) ? 15 : 9;
  148. X
  149. X            iregs.h.ah   = 0x17;
  150. X            iregs.h.dl   = (unsigned char)FP->drive;
  151. X            iregs.h.al   = (unsigned char)(5 - iregs.h.bl);
  152. X            int86 (0x13, &iregs, &iregs);
  153. X        }
  154. X        }
  155. X
  156. X/* 8 or 9 Sectors, 1 or 2 heads */
  157. X
  158. X        if (((iregs.h.bl > 0x00) || (iregs.h.bl < 0x04)) &&
  159. X        (FP->m_sector == 9))
  160. X        {
  161. X        FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
  162. X
  163. X/* Check to see if sector 8 exists */
  164. X
  165. X        if (dio_do (BIOS_READ, FP, buf, 8L, 1) == -1)
  166. X            FP->m_sector = 8;
  167. X
  168. X/* Check to see if sector 380 exists */
  169. X
  170. X        if (dio_do (BIOS_READ, FP, buf, 380L, 1) == -1)
  171. X            FP->m_head = 1;
  172. X        }
  173. X
  174. X/* 720K drive - read sector 15 to see if 1.4M */
  175. X
  176. X        else if (iregs.h.bl == 0x04)
  177. X        {
  178. X        FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
  179. X
  180. X        if (dio_do (BIOS_READ, FP, buf, 17L, 1) == -1)
  181. X            FP->m_sector = 9;
  182. X        }
  183. X
  184. X        FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
  185. X    }
  186. X
  187. X/* Set up the file descriptor entry and return the number */
  188. X
  189. X    MS_io_fs[fp] = FP;
  190. X    return fp + MS_MODIFIER;
  191. X    }
  192. X
  193. X    else
  194. X    return open (name, mode, permissions);
  195. X}
  196. X
  197. X/* fstat function */
  198. X
  199. Xint        dio_fstat (fp, St)
  200. Xint        fp;
  201. Xstruct stat    *St;
  202. X{
  203. X    struct fs        *FP;
  204. X
  205. X    if (fp < MS_MODIFIER)
  206. X    return fstat (fp, St);
  207. X
  208. X    if ((FP = dio_fpcheck (fp)) == (struct fs *)NULL)
  209. X    return -1;
  210. X
  211. X/* Dummy values */
  212. X
  213. X    memset (St, 0, sizeof (struct stat));
  214. X    St->st_mode = 0x61b6;
  215. X    St->st_nlink = 1;
  216. X
  217. X    if (FP->drive == DRIVE_RAM)
  218. X    {
  219. X    St->st_size = MEGABYTE;
  220. X    St->st_rdev = 0x0300;
  221. X    }
  222. X
  223. X    else
  224. X    {
  225. X    St->st_rdev = ((FP->drive & (~HD_FLAG)) * 10 + FP->partition) |
  226. X              ((FP->drive & HD_FLAG) ? 0x0200 : 0x0100);
  227. X    St->st_dev = FP->drive;
  228. X    }
  229. X
  230. X    St->st_atime = time ((time_t *)NULL);
  231. X    St->st_ctime = St->st_ctime;
  232. X    St->st_mtime = St->st_atime;
  233. X    return 0;
  234. X}
  235. X
  236. X/*
  237. X * Close function
  238. X */
  239. X
  240. Xint    dio_close (fp)
  241. Xint    fp;
  242. X{
  243. X    struct fs        *FP;
  244. X
  245. X    if (fp < MS_MODIFIER)
  246. X    return close (fp);
  247. X
  248. X    if ((FP = dio_fpcheck (fp)) == (struct fs *)NULL)
  249. X    return -1;
  250. X
  251. X    free (FP);
  252. X    MS_io_fs[fp - MS_MODIFIER] = (struct fs *)NULL;
  253. X    return 0;
  254. X}
  255. X
  256. X/*
  257. X * Seek function
  258. X */
  259. X
  260. Xlong    dio_lseek (fp, off, type)
  261. Xint    fp;
  262. Xoff_t    off;
  263. Xint    type;
  264. X{
  265. X    off_t        check;
  266. X    struct fs        *FP;
  267. X
  268. X    if (fp < MS_MODIFIER)
  269. X    return lseek (fp, off, type);
  270. X
  271. X    if ((FP = dio_fpcheck (fp)) == (struct fs *)NULL)
  272. X    return -1L;
  273. X
  274. X    switch (type)
  275. X    {
  276. X    case SEEK_SET:
  277. X        check = off;
  278. X        break;
  279. X
  280. X    case SEEK_CUR:
  281. X        check = off + FP->location;
  282. X        break;
  283. X
  284. X    case SEEK_END:
  285. X    default:
  286. X        errno = EINVAL;
  287. X        return -1L;
  288. X    }
  289. X
  290. X    if (check < 0L)
  291. X    {
  292. X    errno = EINVAL;
  293. X    return -1L;
  294. X    }
  295. X
  296. X    return (FP->location = check);
  297. X}
  298. X
  299. X/* Check for a valid file pointer */
  300. X
  301. Xstatic struct fs    *dio_fpcheck (fp)
  302. Xint            fp;
  303. X{
  304. X    struct fs    *FP;
  305. X
  306. X    if (((FP = MS_io_fs[fp - MS_MODIFIER]) == (struct fs *)NULL) ||
  307. X    (fp - MS_MODIFIER >= _NFILE) || (fp - MS_MODIFIER < 0))
  308. X    {
  309. X    errno = EBADF;
  310. X    return (struct fs *)NULL;
  311. X    }
  312. X
  313. X    return FP;
  314. X}
  315. X
  316. X/* Check for a valid file name */
  317. X
  318. Xstatic int    dio_fncheck (name)
  319. Xchar        *name;
  320. X{
  321. X
  322. X/* Check for hard disk */
  323. X
  324. X    if (isdigit(name[7]) && isdigit(name[8]) && (strlen (name) == 9) &&
  325. X    (!strnicmp (name, "/dev/hd", 6)))
  326. X    {
  327. X    int    i = atoi (&name[7]);
  328. X
  329. X    return ((i % 10) > 4) ? -1 : i | HD_FLAG;
  330. X    }
  331. X
  332. X/* Check for floppy disk */
  333. X
  334. X    else if (isdigit(name[7]) && (strlen (name) == 8) &&
  335. X    (!strnicmp (name, "/dev/fd", 6)))
  336. X    return name[7] - '0';
  337. X
  338. X    else if (!stricmp (name, "/dev/kmem"))
  339. X    return DRIVE_RAM;
  340. X
  341. X    return -1;
  342. X}
  343. X
  344. X/* Get file status */
  345. X
  346. Xint        dio_stat (name, St)
  347. Xchar        *name;
  348. Xstruct stat    *St;
  349. X{
  350. X    int        drive;
  351. X
  352. X    if ((drive = dio_fncheck (name)) == -1)
  353. X    return stat (name, St);
  354. X
  355. X    memset (St, 0, sizeof (struct stat));
  356. X    St->st_mode = 0x61b6;
  357. X    St->st_nlink = 1;
  358. X    St->st_atime = time ((time_t *)NULL);
  359. X    St->st_ctime = St->st_ctime;
  360. X    St->st_mtime = St->st_atime;
  361. X
  362. X    if (drive == DRIVE_RAM)
  363. X    {
  364. X    St->st_size = MEGABYTE;
  365. X    St->st_rdev = 0x0300;
  366. X    }
  367. X
  368. X    else
  369. X    {
  370. X    St->st_rdev = (drive & (~HD_FLAG)) | ((drive & HD_FLAG) ? 0x0200
  371. X                                : 0x0100);
  372. X    St->st_dev = drive;
  373. X    }
  374. X
  375. X    return 0;
  376. X}
  377. X
  378. X/* Check file access */
  379. X
  380. Xint    dio_access (name, mode)
  381. Xchar    *name;
  382. Xint    mode;
  383. X{
  384. X    if (dio_fncheck (name) == -1)
  385. X    return access (name, mode);
  386. X
  387. X    else if (mode & 1)
  388. X    {
  389. X    errno = EACCES;
  390. X    return -1;
  391. X    }
  392. X
  393. X    return 0;
  394. X}
  395. X
  396. X/* Change file permissions */
  397. X
  398. Xint    dio_chmod (name, mode)
  399. Xchar    *name;
  400. Xint    mode;
  401. X{
  402. X    return (dio_fncheck (name) == -1) ? chmod (name, mode) : 0;
  403. X}
  404. X
  405. X/* Create file */
  406. X
  407. Xint    dio_creat (name, mode)
  408. Xchar    *name;
  409. Xint    mode;
  410. X{
  411. X    return (dio_fncheck (name) == -1) ? creat (name, mode)
  412. X                      : dio_open (name, O_WRONLY, mode);
  413. X}
  414. X
  415. X/* Duplicate handler */
  416. X
  417. Xint    dio_dup (fp)
  418. Xint    fp;
  419. X{
  420. X    struct fs    *FP;        /* New pointer            */
  421. X    struct fs    *FP1;        /* Old pointer            */
  422. X
  423. X    if (fp < MS_MODIFIER)
  424. X    return dup (fp);
  425. X
  426. X    if ((FP1 = dio_fpcheck (fp)) == (struct fs *)NULL)
  427. X    return -1;
  428. X
  429. X    for (fp = 0; (fp < _NFILE) && (MS_io_fs[fp] != (struct fs *)NULL); fp++)
  430. X    ;
  431. X
  432. X    if ((fp == _NFILE) ||
  433. X    ((FP = (struct fs *)malloc (sizeof (struct fs))) == (struct fs *)NULL))
  434. X    {
  435. X    errno = EMFILE;
  436. X    return -1;
  437. X    }
  438. X
  439. X    MS_io_fs[fp] = FP;
  440. X    *FP = *FP1;
  441. X    return fp;
  442. X}
  443. X
  444. X/* Check if tty */
  445. X
  446. Xint    dio_isatty (fp)
  447. Xint    fp;
  448. X{
  449. X    if (fp < MS_MODIFIER)
  450. X    return isatty (fp);
  451. X
  452. X    return 0;
  453. X}
  454. X
  455. X/* Tell location */
  456. X
  457. Xlong    dio_tell (fp)
  458. Xint    fp;
  459. X{
  460. X    struct fs    *FP;
  461. X
  462. X    if (fp < MS_MODIFIER)
  463. X    return tell (fp);
  464. X
  465. X    return ((FP = dio_fpcheck (fp)) == (struct fs *)NULL) ? -1L : FP->location;
  466. X}
  467. SHAR_EOF
  468. echo "File lib/ms_dio.c is complete"
  469. chmod 0644 lib/ms_dio.c || echo "restore of lib/ms_dio.c fails"
  470. set `wc -c lib/ms_dio.c`;Sum=$1
  471. if test "$Sum" != "17329"
  472. then echo original size 17329, current size $Sum;fi
  473. echo "x - extracting lib/director.c (Text)"
  474. sed 's/^X//' << 'SHAR_EOF' > lib/director.c &&
  475. X/*
  476. X * @(#)msd_dir.c 1.4 87/11/06    Public Domain.
  477. X *
  478. X *  A public domain implementation of BSD directory routines for
  479. X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
  480. X *  August 1897
  481. X */
  482. X
  483. X#include <sys/types.h>
  484. X#include <sys/stat.h>
  485. X#include <stdio.h>
  486. X#include <stdlib.h>
  487. X#include <malloc.h>
  488. X#include <string.h>
  489. X#include <limits.h>
  490. X#include <errno.h>
  491. X#include <dirent.h>
  492. X#include <dos.h>
  493. X
  494. X#define    ATTRIBUTES        (_A_SUBDIR | _A_HIDDEN | _A_SYSTEM | \
  495. X                 _A_NORMAL | _A_RDONLY | _A_ARCH | _A_VOLID)
  496. X
  497. Xstatic void    free_dircontents (struct _dircontents *);
  498. X
  499. XDIR    *opendir(name)
  500. Xchar    *name;
  501. X{
  502. X    struct stat        statb;
  503. X    DIR            *dirp;
  504. X    char        c;
  505. X    struct _dircontents    *dp;
  506. X    char        nbuf[PATH_MAX + NAME_MAX + 2];
  507. X    struct find_t    dtabuf;
  508. X    
  509. X    if (stat (name, &statb) < 0)
  510. X    return (DIR *) NULL;
  511. X
  512. X    if (!S_ISDIR(statb.st_mode))
  513. X    {
  514. X    errno = ENOTDIR;
  515. X    return (DIR *)NULL;
  516. X    }
  517. X
  518. X    if ((dirp = (DIR *) malloc (sizeof (DIR))) == (DIR *) NULL)
  519. X    return (DIR *) NULL;
  520. X
  521. X    if (*name && (c = name[strlen (name) - 1]) != '\\' && c != '/')
  522. X    (void) strcat (strcpy (nbuf, name), "\\*.*");
  523. X
  524. X    else
  525. X    (void) strcat (strcpy (nbuf, name), "*.*");
  526. X
  527. X    dirp->dd_loc      = 0;
  528. X    dirp->dd_cp       = (struct _dircontents *) NULL;
  529. X    dirp->dd_contents = (struct _dircontents *) NULL;
  530. X
  531. X    if (_dos_findfirst (nbuf, ATTRIBUTES, &dtabuf) != 0)
  532. X    return dirp;
  533. X
  534. X    do 
  535. X    {
  536. X    if (((dp = (struct _dircontents *) malloc(sizeof(struct _dircontents))) == (struct _dircontents *) NULL) ||
  537. X        ((dp->_d_entry = strdup (dtabuf.name)) == (char *) NULL))
  538. X    {
  539. X        if (dp != (char *)NULL)
  540. X        free ((char *) dp);
  541. X
  542. X        free_dircontents (dirp->dd_contents);
  543. X        return (DIR *) NULL;
  544. X    }
  545. X
  546. X    if (dirp->dd_contents)
  547. X        dirp->dd_cp = dirp->dd_cp->_d_next = dp;
  548. X
  549. X    else
  550. X        dirp->dd_contents = dirp->dd_cp = dp;
  551. X
  552. X    dp->_d_next = (struct _dircontents *) NULL;
  553. X
  554. X    } while (_dos_findnext (&dtabuf) == 0);
  555. X
  556. X    dirp->dd_cp = dirp->dd_contents;
  557. X
  558. X    return dirp;
  559. X}
  560. X
  561. Xint    closedir(dirp)
  562. XDIR    *dirp;
  563. X{
  564. X    free_dircontents (dirp->dd_contents);
  565. X    free ((char *) dirp);
  566. X    return 0;
  567. X}
  568. X
  569. Xstruct dirent    *readdir(dirp)
  570. XDIR        *dirp;
  571. X{
  572. X    static struct dirent    dp;
  573. X    
  574. X    if (dirp->dd_cp == (struct _dircontents *) NULL)
  575. X    return (struct dirent *) NULL;
  576. X
  577. X    dp.d_reclen = strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
  578. X    dp.d_off    = dirp->dd_loc * 32;
  579. X    dp.d_ino    = (ino_t)++dirp->dd_loc;
  580. X    dirp->dd_cp = dirp->dd_cp->_d_next;
  581. X    strlwr (dp.d_name);
  582. X
  583. X    return &dp;
  584. X}
  585. X
  586. Xvoid    rewinddir (dirp)
  587. XDIR    *dirp;
  588. X{
  589. X    seekdir (dirp, (off_t)0);
  590. X}
  591. X
  592. Xvoid    seekdir (dirp, off)
  593. XDIR    *dirp;
  594. Xoff_t    off;
  595. X{
  596. X    long        i = off;
  597. X    struct _dircontents    *dp;
  598. X
  599. X    if (off < 0L)
  600. X    return;
  601. X
  602. X    for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next)
  603. X    ;
  604. X
  605. X    dirp->dd_loc = off - (i + 1);
  606. X    dirp->dd_cp = dp;
  607. X}
  608. X
  609. Xoff_t    telldir(dirp)
  610. XDIR    *dirp;
  611. X{
  612. X    return dirp->dd_loc;
  613. X}
  614. X
  615. Xstatic void        free_dircontents(dp)
  616. Xstruct _dircontents    *dp;
  617. X{
  618. X    struct _dircontents    *odp;
  619. X
  620. X    while (dp) 
  621. X    {
  622. X    if (dp->_d_entry)
  623. X        free(dp->_d_entry);
  624. X
  625. X    dp = (odp = dp)->_d_next;
  626. X    free((char *) odp);
  627. X    }
  628. X}
  629. SHAR_EOF
  630. chmod 0644 lib/director.c || echo "restore of lib/director.c fails"
  631. set `wc -c lib/director.c`;Sum=$1
  632. if test "$Sum" != "3067"
  633. then echo original size 3067, current size $Sum;fi
  634. echo "x - extracting lib/popen.c (Text)"
  635. sed 's/^X//' << 'SHAR_EOF' > lib/popen.c &&
  636. X/*
  637. X * popen/pclose: simple MS-DOS piping scheme to imitate UNIX pipes
  638. X */
  639. X
  640. X#include <sys/types.h>
  641. X#include <stdio.h>
  642. X#include <string.h>
  643. X#include <errno.h>
  644. X#include <process.h>
  645. X#include <limits.h>
  646. X#include <stdlib.h>
  647. X#include <unistd.h>
  648. X
  649. Xtypedef struct    pipes {
  650. X    FILE    *p_fp;            /* File id            */
  651. X    char    *p_process;        /* Program name            */
  652. X    char    *p_file;        /* Pipe file name        */
  653. X    int        p_status;        /* Status for close to return    */
  654. X                    /* Read pipes only        */
  655. X    bool    p_write;        /* Read or write        */
  656. X} PIPE;
  657. X
  658. Xstatic PIPE    P_list[_NFILE];        /* The pipe structures        */
  659. Xstatic int    Pipes_Inited = 0;    /* Initialised ?        */
  660. Xstatic int    Unique_Pipe  = 0;
  661. X
  662. Xstatic PIPE    *_p_save_entry (char *, bool);
  663. Xstatic int    _p_run (char *);
  664. Xstatic int    _p_reset_entry (PIPE *, int);
  665. Xstatic PIPE    *_p_get_entry (FILE *);
  666. X
  667. X/* Set up a pipe structure */
  668. X
  669. Xstatic PIPE    *_p_save_entry (prog, mode)
  670. Xchar        *prog;
  671. Xbool        mode;
  672. X{
  673. X    FILE    *fp;        /* File handler                */
  674. X    PIPE    *pp;        /* Pipe handler structure        */
  675. X    char    tmpfile[NAME_MAX + PATH_MAX + 2];
  676. X    char    *tmpdir;    /* Points to directory prefix of pipe    */
  677. X
  678. X/* Find out where we should put temporary files */
  679. X
  680. X    if ((tmpdir = getenv ("TMPDIR")) == (char *) NULL) 
  681. X    tmpdir = getenv ("TMP");
  682. X
  683. X/* Use temporary directory if available */
  684. X
  685. X    if (tmpdir == (char *)NULL) 
  686. X    tmpdir = ".";
  687. X
  688. X/* Get a unique pipe file name */
  689. X
  690. X    sprintf (tmpfile, "%s/pipe%05d.tmp", tmpdir, Unique_Pipe++);
  691. X    unlink (tmpfile);
  692. X
  693. X/* Create the pipe */
  694. X
  695. X    if ((fp = fopen (tmpfile, "w")) == (FILE *) NULL)
  696. X    return (PIPE *)NULL;
  697. X
  698. X/* Create the PIPE entry */
  699. X
  700. X    if ((pp = _p_get_entry ((FILE *)NULL)) == (PIPE *)NULL)
  701. X    {
  702. X    fclose (fp);
  703. X    unlink (tmpfile);
  704. X    errno = EMFILE;
  705. X    return (PIPE *)NULL;
  706. X    }
  707. X
  708. X/* Set up the entry */
  709. X
  710. X    pp->p_fp      = fp;
  711. X    pp->p_write   = mode;
  712. X    pp->p_process = strdup (prog);
  713. X    pp->p_file    = strdup (tmpfile);
  714. X
  715. X/* Check for errors */
  716. X
  717. X    if ((pp->p_process == (char *)NULL) || (pp->p_file == (char *)NULL))
  718. X    {
  719. X    _p_reset_entry (pp, 1);
  720. X    errno = ENOMEM;
  721. X    return (FILE *)NULL;
  722. X    }
  723. X
  724. X    return pp;
  725. X}
  726. X
  727. X/* Execute command via SHELL or COMSPEC */
  728. X
  729. Xstatic int    _p_run (command)
  730. Xchar        *command;
  731. X{
  732. X    char    *shell;            /* Command processor        */
  733. X    char    *shellpath;        /* Full command processor path    */
  734. X    char    *bp;            /* Generic string pointer    */
  735. X    char    *dash = "/c";
  736. X
  737. X/* Determine the command processor */
  738. X
  739. X    if (((shell = getenv ("SHELL")) == (char *) NULL) &&
  740. X    ((shell = getenv ("COMSPEC")) == (char *) NULL))
  741. X    shell = "command.com";
  742. X
  743. X    shellpath = strlwr (shell);
  744. X
  745. X/* Strip off any leading backslash directories */
  746. X
  747. X    if ((shell = strrchr (shellpath, '\\')) != (char *)NULL)
  748. X    ++shell;
  749. X
  750. X    else
  751. X    shell = shellpath;
  752. X
  753. X/* Strip off any leading slash directories */
  754. X
  755. X    if ((bp = strrchr (shell, '/')) != (char *)NULL)
  756. X    shell = ++bp;
  757. X
  758. X    if (strcmp (shell, "command.com"))
  759. X    *dash = '-';
  760. X
  761. X/* Run the program */
  762. X
  763. X    return spawnl (P_WAIT, shellpath, shell, dash, command, (char *) NULL);
  764. X}
  765. X
  766. X/* resetpipe: Private routine to cancel a pipe */
  767. X
  768. Xstatic int    _p_reset_entry (pp, mode)
  769. XPIPE        *pp;
  770. Xint        mode;
  771. X{
  772. X    int        result = (!mode) ? 0 : -1;
  773. X    int        serrno = errno;
  774. X
  775. X/* Close the pipe */
  776. X    
  777. X    fclose (pp->p_fp);
  778. X
  779. X/* Free up memory */
  780. X
  781. X    if (pp->p_file != (char *)NULL)
  782. X    {
  783. X    result = unlink (pp->p_file);
  784. X
  785. X    if (!mode)
  786. X        serrno = errno;
  787. X
  788. X    else
  789. X        result = -1;
  790. X
  791. X    free (pp->p_file);
  792. X    }
  793. X
  794. X    if (pp->p_process != (char *)NULL)
  795. X    free (pp->p_process);
  796. X
  797. X    memset (pp, 0, sizeof (PIPE));
  798. X
  799. X/* Return error code */
  800. X
  801. X    errno = serrno;
  802. X    return result;
  803. X}
  804. X
  805. X/* Find a free entry */
  806. X
  807. Xstatic PIPE    *_p_get_entry (fp)
  808. XFILE        *fp;
  809. X{
  810. X    int        i;
  811. X
  812. X    for (i = 0; i < _NFILE; i++)
  813. X    {
  814. X    if (P_list[i].p_fp == fp)
  815. X        return &P_list[i];
  816. X    }
  817. X    
  818. X    return (PIPE *)NULL;
  819. X}
  820. X
  821. X
  822. X/* popen: open a pipe */
  823. X
  824. XFILE    *popen (command, type)
  825. Xchar    *command;        /* The command to be run        */
  826. Xchar    *type;            /* "w" or "r"                */
  827. X{ 
  828. X    int        old_stdout;
  829. X    PIPE    *pp;
  830. X
  831. X/* Initialise the pipe structure */
  832. X
  833. X    if (!Pipes_Inited)
  834. X    {
  835. X    memset (&P_list[0], 0, sizeof (P_list));
  836. X    Pipes_Inited = 1;
  837. X    }
  838. X
  839. X/* For write style pipe, pclose handles program execution */
  840. X
  841. X    if (strcmp (type, "w") == 0)
  842. X    return ((pp = _p_save_entry (command, TRUE)) == (PIPE *)NULL)
  843. X           ? (FILE *)NULL : pp->p_fp;
  844. X    
  845. X/* read pipe must create tmp file, set up stdout to point to the temp
  846. X * file, and run the program.  note that if the pipe file cannot be
  847. X * opened, it'll return a condition indicating pipe failure, which is
  848. X * fine.
  849. X */
  850. X
  851. X    else if (strcmp (type, "r") == 0)
  852. X    {
  853. X    if ((pp = _p_save_entry (command, FALSE)) == (PIPE *)NULL)
  854. X       return (FILE *)NULL;
  855. X
  856. X/* Save the stdout file descriptor, dup the pipe onto standard out,
  857. X * execute the command, close the pipe and re-open it 
  858. X */
  859. X
  860. X    if ((old_stdout = dup (fileno(stdout)) < 0)        ||
  861. X        (dup2 (fileno (pp->p_fp), fileno(stdout)) < 0)    ||
  862. X        ((pp->p_status = _p_run (command)) < 0)        ||
  863. X        (fclose (pp->p_fp) < 0)                ||
  864. X        (dup2 (old_stdout, fileno (stdout)) < 0)        ||
  865. X        ((pp->p_fp = fopen (pp->p_file, "r")) == (FILE *)NULL))
  866. X    {
  867. X        _p_reset_entry (pp, 1);
  868. X        return (FILE *)NULL;
  869. X    }
  870. X
  871. X    else
  872. X        return pp->p_fp;
  873. X    }
  874. X    
  875. X/* screwy call or unsupported type */
  876. X
  877. X    errno = EINVAL;
  878. X    return (FILE *)NULL;
  879. X}
  880. X
  881. X/* close a pipe */
  882. X
  883. Xint    pclose (fp)
  884. XFILE    *fp;
  885. X{
  886. X    PIPE    *pp;            /* Current pipe structure    */
  887. X    int        old_stdin;        /* Where our stdin points now    */
  888. X
  889. X    if ((pp = _p_get_entry (fp)) == (PIPE *)NULL)
  890. X    {
  891. X    errno = EBADF;
  892. X    return -1;
  893. X    }
  894. X
  895. X    if (fclose (pp->p_fp) < 0)
  896. X    return _p_reset_entry (pp, 1);
  897. X
  898. X/* Open the pipe in read mode, Save stdin file descriptor, copy pipe file
  899. X * descriptor to stdin, execute the command, and then restore stdin
  900. X */
  901. X
  902. X    if (pp->p_write &&
  903. X    (    ((pp->p_fp = fopen (pp->p_file, "r")) == (FILE *)NULL)    ||
  904. X        ((old_stdin = dup (fileno (stdin))) < 0)        ||
  905. X        (dup2 (fileno (pp->p_fp), fileno (stdin)) < 0)        ||
  906. X        ((pp->p_status = _p_run (pp->p_process)) < 0)        ||
  907. X        (fclose (pp->p_fp) < 0)                    ||
  908. X        (dup2 (old_stdin, fileno (stdin)) < 0)
  909. X    ))
  910. X    return _p_reset_entry (pp, 1);
  911. X
  912. X/* Close the temp file and remove it */
  913. X
  914. X    return _p_reset_entry (pp, 0);
  915. X}
  916. SHAR_EOF
  917. chmod 0644 lib/popen.c || echo "restore of lib/popen.c fails"
  918. set `wc -c lib/popen.c`;Sum=$1
  919. if test "$Sum" != "6060"
  920. then echo original size 6060, current size $Sum;fi
  921. echo "x - extracting lib/syserr.c (Text)"
  922. sed 's/^X//' << 'SHAR_EOF' > lib/syserr.c &&
  923. X/* perror(s) print the current error message. */
  924. X
  925. Xchar    *sys_errlist[] = {
  926. X    "Error 0 ",
  927. X    "Operation not permitted",
  928. X    "No such file or directory",
  929. X    "No such process",
  930. X    "Interrupted system call",
  931. X    "I/O error",
  932. X    "No such device or address",
  933. X    "Arg list too long",
  934. X    "Exec format error",
  935. X    "Bad file number",
  936. X    "No children",
  937. X    "No more processes",
  938. X    "Not enough core",
  939. X    "Permission denied",
  940. X    "Bad address",
  941. X    "Block device required",
  942. X    "Mount device busy",
  943. X    "File exists",
  944. X    "Cross-device link",
  945. X    "No such device",
  946. X    "Not a directory",
  947. X    "Is a directory",
  948. X    "Invalid argument",
  949. X    "File table overflow",
  950. X    "Too many open files",
  951. X    "Not a typewriter",
  952. X    "Text file busy",
  953. X    "File too large",
  954. X    "No space left on device",
  955. X#define  ESPIPE    29
  956. X    "Illegal seek",
  957. X    "Read-only file system",
  958. X    "Too many links",
  959. X
  960. X    "Broken pipe",
  961. X    "Math argument",
  962. X    "Result too large",
  963. X    "EUCLEAN",
  964. X    "No message of desired type",
  965. X    "Resource deadlock would occur"
  966. X    "Unknown error"
  967. X};
  968. X
  969. Xint    sys_nerr = sizeof(sys_errlist)/sizeof(char *) - 1;
  970. SHAR_EOF
  971. chmod 0644 lib/syserr.c || echo "restore of lib/syserr.c fails"
  972. set `wc -c lib/syserr.c`;Sum=$1
  973. if test "$Sum" != "1106"
  974. then echo original size 1106, current size $Sum;fi
  975. echo "x - extracting lib/stdargv.c (Text)"
  976. sed 's/^X//' << 'SHAR_EOF' > lib/stdargv.c &&
  977. X/*
  978. X *  MODULE NAME:     expand.c                        Revision: 1.0
  979. X *
  980. X *  AUTHOR:         Ian Stewartson
  981. X *
  982. X *  LOCATION:         Data Logic,
  983. X *             Greenford,
  984. X *             Middlesex,
  985. X *             England.
  986. X *
  987. X#include <logo.h>
  988. X *  MODULE DEFINITION:    This function expandes the command line parameters
  989. X *            in a UNIX like manner.    Wild character *?[] are
  990. X *            allowed in file names. @filename causes command lines
  991. X *            to be read from filename.  Strings between " or ' are
  992. X *            not expanded.  All entries in the array are malloced.
  993. X *
  994. X *            This function replaces the standard MS-DOS command
  995. X *            line processing function (_setargv in stdargv.obj).
  996. X *
  997. X *  CALLING SEQUENCE:    The following calling sequences are used:
  998. X *
  999. X *            void    _setargv ();
  1000. X *
  1001. X *  ERROR MESSAGES:    Out of memory
  1002. X *
  1003. X *  INCLUDE FILES:
  1004. X */
  1005. X
  1006. X#include <sys/types.h>            /* MS-DOS type definitions          */
  1007. X#include <sys/stat.h>            /* File status definitions        */
  1008. X#include <stdio.h>            /* Standard I/O delarations         */
  1009. X#include <stdlib.h>            /* Standard library functions       */
  1010. X#include <errno.h>            /* Error number declarations        */
  1011. X#include <dos.h>            /* DOS functions declarations       */
  1012. X#include <bios.h>            /* BIOS functions declarations      */
  1013. X#include <ctype.h>            /* Character type declarations      */
  1014. X#include <string.h>            /* String library functions         */
  1015. X#include <limits.h>            /* String library functions         */
  1016. X#include <fcntl.h>            /* File Control Declarations        */
  1017. X#include <io.h>                /* Input/Output Declarations        */
  1018. X#include <dirent.h>            /* Direction I/O functions        */
  1019. X
  1020. X/*
  1021. X *  DATA DEFINITIONS:
  1022. X */
  1023. X
  1024. X#define MAX_LINE    160        /* Max line length        */
  1025. X#define S_ENTRY        sizeof (char *)
  1026. X
  1027. X/*
  1028. X *  DATA DECLARATIONS:
  1029. X */
  1030. X#ifdef MSDOS
  1031. X
  1032. Xextern void    _setargv (void);
  1033. Xstatic void    exp_line (char *);        /* Expand file        */
  1034. Xstatic int    ex_pfield (char    *, char *);    /* Expand field        */
  1035. Xstatic void    ex_pfile (char *);
  1036. Xstatic char    *ex_gspace (int, char *);    /* Get space        */
  1037. Xstatic void    ex_add_arg (char *);    /* Add argument            */
  1038. Xstatic char    *ex_skip_sp (char *);    /* Skip spaces            */
  1039. Xstatic char    *ex_tounix (char *);    /* Convert name to Unix format    */
  1040. Xstatic int    ex_find (char*, int);    /* Split file name        */
  1041. Xstatic void    ex_fatal (int, char *, char *);    /* Fatal error processing*/
  1042. Xstatic char    *ex_environment (char *);    /* Process environment    */
  1043. Xstatic char    *_ex_multi_drive (char *);    /* Check for multidrive    */
  1044. Xstatic char    *ex_nomem = "%s: %s\n";
  1045. X
  1046. Xextern char far    *_pgmptr;         /* Program name            */
  1047. Xextern char    **__argv;         /* Current argument address    */
  1048. Xextern int    __argc;         /* Current argument count    */
  1049. X
  1050. X/*
  1051. X *  MODULE ABSTRACT: _setargv
  1052. X *
  1053. X *  UNIX like command line expansion
  1054. X */
  1055. X
  1056. Xvoid    _setargv ()
  1057. X{
  1058. X                    /* Set up pointer to command line */
  1059. X    char far        *argvp = (char far *)((((long)_psp) << 16) + 0x081L);
  1060. X    unsigned int    envs = *(int far *)((((long)_psp) << 16) + 0x02cL);
  1061. X    char far        *s;         /* Temporary string pointer        */
  1062. X#ifndef M_I86LM
  1063. X    char        buf[MAX_LINE];    /* Temporary space        */
  1064. X    char        *cp;
  1065. X#endif
  1066. X
  1067. X/* Command line can be null or 0x0d terminated - convert to null */
  1068. X
  1069. X    s = argvp;
  1070. X
  1071. X    while (*s && (*s != 0x0d))
  1072. X    ++s;
  1073. X    
  1074. X    if (*s == 0x0d)
  1075. X    *s = 0;
  1076. X
  1077. X/* Set up global parameters and expand */
  1078. X
  1079. X    __argc = 0;
  1080. X
  1081. X/* Get the program name */
  1082. X
  1083. X    if (_osmajor <= 2)
  1084. X    s = "unknown";
  1085. X
  1086. X/* In the case of DOS 3+, we look in the environment space */
  1087. X
  1088. X    else
  1089. X    {
  1090. X    s = (char far *)(((long)envs) << 16);
  1091. X
  1092. X    while (*s)
  1093. X    {
  1094. X        while (*(s++) != 0);
  1095. X    }
  1096. X
  1097. X    s += 3;
  1098. X    }
  1099. X
  1100. X    _pgmptr = s;
  1101. X
  1102. X#ifndef M_I86LM
  1103. X    cp = buf;
  1104. X    while (*(cp++) = *(s++));
  1105. X
  1106. X    ex_add_arg (ex_tounix (buf));    /* Add the program name        */
  1107. X
  1108. X    s  = argvp;
  1109. X    cp = buf;
  1110. X    while (*(cp++) = *(s++));
  1111. X
  1112. X    exp_line (buf);
  1113. X#else
  1114. X    ex_add_arg (ex_tounix (s));        /* Add the program name        */
  1115. X    exp_line (argvp);
  1116. X#endif
  1117. X
  1118. X    ex_add_arg ((char *)NULL);
  1119. X    --__argc;
  1120. X}
  1121. X
  1122. X/*
  1123. X * Expand a line
  1124. X */
  1125. X
  1126. Xstatic void    exp_line (argvp)
  1127. Xchar        *argvp;            /* Line to expand            */
  1128. X{
  1129. X    char    *spos;            /* End of string pointer    */
  1130. X    char    *cpos;            /* Start of string pointer    */
  1131. X    char    *fn;            /* Extracted file name string    */
  1132. X
  1133. X/* Search for next separator */
  1134. X
  1135. X    spos = argvp;
  1136. X
  1137. X    while (*(cpos = ex_skip_sp (spos)))
  1138. X    {
  1139. X
  1140. X/* Extract string argument */
  1141. X
  1142. X    if ((*cpos == '"') || (*cpos == '\''))
  1143. X    {
  1144. X        spos = cpos + 1;
  1145. X
  1146. X        do
  1147. X        {
  1148. X        if ((spos = strchr (spos, *cpos)) != NULL)
  1149. X        {
  1150. X            spos++;
  1151. X            if (spos[-2] != '\\')
  1152. X            break;
  1153. X        }
  1154. X
  1155. X        else
  1156. X            spos = &spos[strlen (cpos)];
  1157. X
  1158. X        }
  1159. X        while (*spos);
  1160. X
  1161. X        fn    = ex_gspace (spos - cpos - 2, cpos + 1);
  1162. X    }
  1163. X
  1164. X/* Extract normal argument */
  1165. X
  1166. X    else
  1167. X    {
  1168. X        spos = cpos;
  1169. X        while (!isspace(*spos) && *spos)
  1170. X        spos++;
  1171. X        
  1172. X        fn = ex_gspace (spos - cpos, cpos);
  1173. X    }
  1174. X
  1175. X/* Process argument */
  1176. X
  1177. X    if (*cpos != '"')
  1178. X        fn = ex_environment (fn);
  1179. X
  1180. X    switch (*cpos)
  1181. X    {
  1182. X        case '@':        /* Expand file                    */
  1183. X        ex_pfile (fn);
  1184. X        break;
  1185. X
  1186. X        case '"':        /* Expand string                */
  1187. X        case '\'':
  1188. X        ex_add_arg (fn);
  1189. X        break;
  1190. X
  1191. X        default:        /* Expand field                    */
  1192. X        if (!ex_find (fn, 0))
  1193. X            ex_add_arg (fn);
  1194. X    }
  1195. X
  1196. X    free (fn);
  1197. X    }
  1198. X}
  1199. X
  1200. X/* Expand a field if it has metacharacters in it */
  1201. X
  1202. Xstatic int    ex_pfield (prefix, postfix)
  1203. Xchar        *prefix;        /* Prefix field                */
  1204. Xchar        *postfix;        /* Postfix field            */
  1205. X{
  1206. X    int          count;        /* File path length        */
  1207. X    int         f_count = 0;    /* Number of files generated    */
  1208. X    int            slash_flag = 0;    /* slash required        */
  1209. X    char        fn[PATH_MAX + NAME_MAX + 2];/* Search file name */
  1210. X    char        *name;        /* Match string            */
  1211. X    char        *p, *p1;
  1212. X    DIR            *dp;
  1213. X    struct dirent    *c_de;
  1214. X    unsigned int    c_drive;    /* Current drive        */
  1215. X    unsigned int    m_drive;    /* Max drive            */
  1216. X    unsigned int    s_drive;    /* Selected drive        */
  1217. X    unsigned int    x_drive, y_drive;    /* Dummies        */
  1218. X    char        *multi;        /* Multi-drive flag        */
  1219. X    char        t_drive[2];
  1220. X
  1221. X/* Convert file name to lower case */
  1222. X
  1223. X    strlwr (prefix);
  1224. X
  1225. X/* Search all drives ? */
  1226. X
  1227. X    if ((multi = _ex_multi_drive (prefix)) != (char *)NULL)
  1228. X    {
  1229. X    _dos_getdrive (&c_drive);    /* Get number of drives        */
  1230. X    _dos_setdrive (c_drive, &m_drive);
  1231. X    t_drive[1] = 0;
  1232. X
  1233. X    for (s_drive = 1; s_drive <= m_drive; ++s_drive)
  1234. X    {
  1235. X        _dos_setdrive (s_drive, &x_drive);
  1236. X        _dos_getdrive (&y_drive);
  1237. X        _dos_setdrive (c_drive, &x_drive);
  1238. X
  1239. X/* Check to see if the second diskette drive is really there */
  1240. X
  1241. X        if (((_bios_equiplist () & 0x00c0) == 0x0000) && (s_drive == 2))
  1242. X        continue;
  1243. X
  1244. X/* If the drive exists and is in our list - process it */
  1245. X
  1246. X        *multi = 0;
  1247. X        *t_drive = (char)(s_drive + 'a' - 1);
  1248. X
  1249. X        if ((y_drive == s_drive) && pnmatch (t_drive, prefix, 0))
  1250. X        {
  1251. X        *multi = ':';
  1252. X        *fn = *t_drive;
  1253. X        strcpy (fn + 1, multi);
  1254. X        f_count += ex_pfield (fn, postfix);
  1255. X        }
  1256. X
  1257. X        *multi = ':';
  1258. X    }
  1259. X
  1260. X    return f_count;
  1261. X    }
  1262. X
  1263. X/* Get the path length */
  1264. X
  1265. X    p = strrchr (prefix, '/');
  1266. X    p1 = strchr (prefix, ':');
  1267. X
  1268. X    if ((p1 == (char *)NULL) || (p1 < p))
  1269. X    {
  1270. X    if (p == (char *)NULL)
  1271. X    {
  1272. X        count = 0;
  1273. X        name = prefix;
  1274. X    }
  1275. X
  1276. X    else
  1277. X    {
  1278. X        count = p - prefix;
  1279. X        name = p + 1;
  1280. X    }
  1281. X    }
  1282. X    
  1283. X    else if ((p == (char *)NULL) || (p < p1))
  1284. X    {
  1285. X    count = p1 - prefix;
  1286. X    name = p1 + 1;
  1287. X    }
  1288. X    
  1289. X/* Set up file name for search */
  1290. X    
  1291. X    if (((count == 2) && (strncmp (prefix + 1, ":/", 2) == 0)) ||
  1292. X    ((count == 0) && (*prefix == '/')))
  1293. X    {
  1294. X    strncpy (fn, prefix, ++count);
  1295. X    fn[count] = 0;
  1296. X    strcat (fn, ".");
  1297. X    }
  1298. X
  1299. X    else
  1300. X    {
  1301. X    if ((count == 1) && (*(prefix + 1) == ':'))
  1302. X        count++;
  1303. X
  1304. X    strncpy (fn, prefix, count);
  1305. X    fn[count] = 0;
  1306. X
  1307. X    if (((count == 2) && (*(prefix + 1) == ':')) || (count == 0))
  1308. X        strcat (fn, ".");
  1309. X    
  1310. X    else
  1311. X        slash_flag = 1;
  1312. X    }
  1313. X    
  1314. X/* Search for file names */
  1315. X
  1316. X    if ((dp = opendir (fn)) == (DIR *)NULL)
  1317. X    return 0;
  1318. X
  1319. X/* Are there any matches */
  1320. X
  1321. X    while ((c_de = readdir (dp)) != (struct dirent *)NULL)
  1322. X    {
  1323. X    if ((*c_de->d_name == '.') && (*name != '.'))
  1324. X        continue;
  1325. X
  1326. X/* Check for match */
  1327. X
  1328. X    if (pnmatch (c_de->d_name, name, 0))
  1329. X    {
  1330. X        fn[count] = 0;
  1331. X
  1332. X        if (slash_flag)
  1333. X        strcat (fn, "/");
  1334. X
  1335. X        strcat (fn, c_de->d_name);
  1336. X
  1337. X/* If the postfix is not null, this must be a directory */
  1338. X
  1339. X        if (postfix != (char *)NULL)
  1340. X        {
  1341. X        struct stat        statb;
  1342. X
  1343. X        if (stat (fn, &statb) < 0 ||
  1344. X            (statb.st_mode & S_IFMT) != S_IFDIR)
  1345. X            continue;
  1346. X
  1347. X        strcat (fn, "/");
  1348. X        strcat (fn, postfix);
  1349. X        }
  1350. X
  1351. X        f_count += ex_find (fn, 1);
  1352. X    }
  1353. X    }
  1354. X
  1355. X    closedir (dp);
  1356. X    return f_count;
  1357. X}
  1358. X
  1359. X/* Expand file name */
  1360. X
  1361. Xstatic void    ex_pfile (file)
  1362. Xchar        *file;        /* Expand file name                */
  1363. X{
  1364. X    FILE        *fp;        /* File descriptor                */
  1365. X    char    *p;        /* Pointer                */
  1366. X    int        c_maxlen = MAX_LINE;
  1367. X    char    *line;        /* Line buffer                    */
  1368. X
  1369. X/* Grab some memory for the line */
  1370. X
  1371. X    if ((line = malloc (c_maxlen)) == (char *)NULL)
  1372. X    ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
  1373. X
  1374. X/* If file open fails, expand as a field */
  1375. X
  1376. X    if ((fp = fopen (file + 1, "rt")) == NULL)
  1377. X    {
  1378. X    if (!ex_find (file, 0))
  1379. X        ex_add_arg (file);
  1380. X
  1381. X    return;
  1382. X    }
  1383. X
  1384. X/* For each line in the file, remove EOF characters and add argument */
  1385. X
  1386. X    while (fgets (line, c_maxlen, fp) != (char *)NULL)
  1387. X    {
  1388. X    while ((p = strchr (line, '\n')) == (char *)NULL)
  1389. X    {
  1390. X        if ((p = strchr (line, 0x1a)) != (char *)NULL)
  1391. X        break;
  1392. X
  1393. X        if ((line = realloc (line, c_maxlen + MAX_LINE)) == (char *)NULL)
  1394. X        ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
  1395. X
  1396. X        if (fgets (&line[c_maxlen - 1], MAX_LINE, fp) == (char *)NULL)
  1397. X        break;
  1398. X
  1399. X        c_maxlen += MAX_LINE - 1;
  1400. X    }
  1401. X
  1402. X    if (p != (char *)NULL)
  1403. X        *p = 0;
  1404. X
  1405. X    ex_add_arg (line);
  1406. X    }
  1407. X
  1408. X    if (ferror(fp))
  1409. X    ex_fatal (errno, "%s: %s (%s)\n", file + 1);
  1410. X
  1411. X    free (line);
  1412. X    fclose (fp);
  1413. X}
  1414. X
  1415. X/* Get space for name */
  1416. X
  1417. Xstatic char    *ex_gspace (l, in_s)
  1418. Xint        l;            /* String length                */
  1419. Xchar        *in_s;                  /* String address        */
  1420. X{
  1421. X    char    *out_s;            /* Malloced space address       */
  1422. X
  1423. X    if ((out_s = malloc (l + 1)) == (char *)NULL)
  1424. X    ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
  1425. X
  1426. X/* Copy string for specified length */
  1427. X
  1428. X    strncpy (out_s, in_s, l);
  1429. X    out_s[l] = 0;
  1430. X
  1431. X    return (out_s);
  1432. X}
  1433. X
  1434. X/* Append an argument to the string */
  1435. X
  1436. Xstatic void    ex_add_arg (fn)
  1437. Xchar        *fn;            /* Argument to add        */
  1438. X{
  1439. X    if (__argc == 0)
  1440. X    __argv = (char **)malloc (50 * S_ENTRY);
  1441. X    
  1442. X    else if ((__argc % 50) == 0)
  1443. X    __argv = (char **)realloc (__argv, (__argc + 50) * S_ENTRY);
  1444. X    
  1445. X    if (__argv == (char **)NULL)
  1446. X    ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
  1447. X
  1448. X    __argv[__argc++] = (fn == (char *)NULL) ? fn : ex_gspace (strlen (fn), fn);
  1449. X}
  1450. X
  1451. X/*  Skip over spaces */
  1452. X
  1453. Xstatic char    *ex_skip_sp (a)
  1454. Xchar        *a;            /* String start address        */
  1455. X{
  1456. X    while (isspace(*a))
  1457. X        a++;
  1458. X
  1459. X    return (a);
  1460. X}
  1461. X
  1462. X/* Convert name to Unix format */
  1463. X
  1464. Xstatic char    *ex_tounix (a)
  1465. Xchar        *a;
  1466. X{
  1467. X    char    *sp = a;
  1468. X
  1469. X    while ((a = strchr (a, '\\')) != (char *)NULL)
  1470. X    *(a++) = '/';
  1471. X
  1472. X    return strlwr (sp);
  1473. X}
  1474. X
  1475. X/* Find the location of meta-characters.  If no meta, add the argument and
  1476. X * return NULL.  If meta characters, return position of end of directory
  1477. X * name.  If not multiple directories, return -1
  1478. X */
  1479. X
  1480. Xstatic int    ex_find (file, must_exist)
  1481. Xchar        *file;
  1482. Xint        must_exist;        /* FIle must exist flag        */
  1483. X{
  1484. X    char    *p;
  1485. X    int        i;
  1486. X    static char    ex_meta[] = "?*[]\\";    /* Metacharacters        */
  1487. X
  1488. X    if ((p = strpbrk (file, ex_meta)) == (char *)NULL)
  1489. X    {
  1490. X    if (must_exist && (access (file, 0) < 0))
  1491. X        return 0;
  1492. X
  1493. X    ex_add_arg (file);
  1494. X    return 1;
  1495. X    }
  1496. X    
  1497. X    else if ((p = strchr (p, '/')) != (char *)NULL)
  1498. X    *(p++) = 0;
  1499. X    
  1500. X    i = ex_pfield (file, p);
  1501. X
  1502. X    if (p != (char *)NULL)
  1503. X       *(--p) = '/';
  1504. X
  1505. X    return i;
  1506. X}
  1507. X
  1508. X/* Fatal errors */
  1509. X
  1510. Xstatic void    ex_fatal (ecode, format, para)
  1511. Xint        ecode;
  1512. Xchar        *format;
  1513. Xchar        *para;
  1514. X{
  1515. X    fprintf (stderr, format, "stdargv", strerror (ecode), para);
  1516. X    exit (1);
  1517. X}
  1518. X
  1519. X/* Process Environment - note that field is a malloc'ed field */
  1520. X
  1521. Xstatic char    *ex_environment (field)
  1522. Xchar        *field;
  1523. X{
  1524. X    char    *sp, *cp, *np, *ep;
  1525. X    char    save;
  1526. X    int        b_flag;
  1527. X
  1528. X    sp = field;
  1529. X
  1530. X/* Replace any $ strings */
  1531. X
  1532. X    while ((sp = strchr (sp, '$')) != (char *)NULL)
  1533. X    {
  1534. X    if (*(cp = ++sp) == '{')
  1535. X    {
  1536. X        b_flag = 1;
  1537. X        ++cp;
  1538. X
  1539. X        while (*cp && (*cp != '}'))
  1540. X        cp++;
  1541. X    }
  1542. X
  1543. X    else
  1544. X    {
  1545. X        b_flag;
  1546. X
  1547. X        while (isalnum(*cp))
  1548. X        cp++;
  1549. X    }
  1550. X
  1551. X/* Grab the environment variable */
  1552. X
  1553. X    if (cp == sp)
  1554. X        continue;
  1555. X
  1556. X    save = *cp;
  1557. X    *cp = 0;
  1558. X    ep = getenv (sp + b_flag);
  1559. X    *cp = save;
  1560. X
  1561. X    if (ep != (char *)NULL)
  1562. X    {
  1563. X        np = ex_gspace (strlen(field) - (cp - sp) + strlen (ep) - 1, field);
  1564. X        strcpy (&np[sp - field - 1], ep);
  1565. X        ex_tounix (&np[sp - field - 1]);
  1566. X        free (field);
  1567. X        strcpy ((sp = &np[strlen(np)]), cp + b_flag);
  1568. X        field = np;
  1569. X    }
  1570. X    }
  1571. X
  1572. X    return field;
  1573. X}
  1574. X
  1575. X/* Check for multi_drive prefix */
  1576. X
  1577. Xstatic char    *_ex_multi_drive (prefix)
  1578. Xchar        *prefix;
  1579. X{
  1580. X    if (strlen (prefix) < 2)
  1581. X    return (char *)NULL;
  1582. X    
  1583. X    if (((*prefix == '*') || (*prefix == '?')) && (prefix[1] == ':'))
  1584. X    return prefix + 1;
  1585. X    
  1586. X    if (*prefix != '[')
  1587. X    return (char *)NULL;
  1588. X
  1589. X    while (*prefix && (*prefix != ']'))
  1590. X    {
  1591. X    if ((*prefix == '\\') && (*(prefix + 1)))
  1592. X        ++prefix;
  1593. X    
  1594. X    ++prefix;
  1595. X    }
  1596. X
  1597. X    return (*prefix && (*(prefix + 1) == ':')) ? prefix + 1 : (char *)NULL;
  1598. X}
  1599. X#endif
  1600. SHAR_EOF
  1601. chmod 0644 lib/stdargv.c || echo "restore of lib/stdargv.c fails"
  1602. set `wc -c lib/stdargv.c`;Sum=$1
  1603. if test "$Sum" != "12922"
  1604. then echo original size 12922, current size $Sum;fi
  1605. echo "x - extracting lib/pnmatch.c (Text)"
  1606. sed 's/^X//' << 'SHAR_EOF' > lib/pnmatch.c &&
  1607. X#include <stdlib.h>
  1608. X
  1609. X/* File name pattern matching function */
  1610. X
  1611. Xint    pnmatch (string, pattern, flag)
  1612. Xchar    *string;            /* String to match                  */
  1613. Xchar    *pattern;            /* Pattern to match against         */
  1614. Xint    flag;                /* Match using '$' & '^'            */
  1615. X{
  1616. X    register int    cur_s;        /* Current string character         */
  1617. X    register int    cur_p;        /* Current pattern character        */
  1618. X
  1619. X/* Match $ and ^ ? */
  1620. X
  1621. X    if (flag == 1)
  1622. X    {
  1623. X    while (*string)
  1624. X    {
  1625. X        if (pnmatch (string++, pattern, ++flag))
  1626. X        return 1;
  1627. X    }
  1628. X
  1629. X    return 0;
  1630. X    }
  1631. X
  1632. X/* Match string */
  1633. X
  1634. X    while (cur_p = *(pattern++))
  1635. X    {
  1636. X    cur_s = *(string++);        /* Load current string character    */
  1637. X
  1638. X        switch (cur_p)            /* Switch on pattern character      */
  1639. X        {
  1640. X            case '^':            /* Match start of string            */
  1641. X            {
  1642. X                if (flag == 2)
  1643. X                    string--;
  1644. X
  1645. X                else if ((flag) || (cur_p != cur_s))
  1646. X            return 0;
  1647. X
  1648. X                break;
  1649. X            }
  1650. X
  1651. X            case '$':            /* Match end of string              */
  1652. X            {
  1653. X                if (!flag)
  1654. X                {
  1655. X                    if (cur_p != cur_s)
  1656. X            return 0;
  1657. X
  1658. X                    break;
  1659. X                }
  1660. X
  1661. X                else
  1662. X            return ((cur_s) ? 0 : 1);
  1663. X            }
  1664. X
  1665. X            case '[':            /* Match class of characters        */
  1666. X            {
  1667. X                while(1)
  1668. X                {
  1669. X                    if (!(cur_p = *(pattern++)))
  1670. X            return 0;
  1671. X
  1672. X                    if (cur_p == ']')
  1673. X            return 0;
  1674. X
  1675. X                    if (cur_s != cur_p)
  1676. X                    {
  1677. X                        if (*pattern == '-')
  1678. X                        {
  1679. X                            if(cur_p > cur_s)
  1680. X                                continue;
  1681. X
  1682. X                            if (cur_s > *(++pattern))
  1683. X                                continue;
  1684. X                        }
  1685. X                        else
  1686. X                            continue;
  1687. X                    }
  1688. X
  1689. X                    break;
  1690. X                }
  1691. X
  1692. X                while (*pattern)
  1693. X                {
  1694. X                    if (*(pattern++) == ']')
  1695. X                        break;
  1696. X                }
  1697. X            }
  1698. X
  1699. X            case '?':            /* Match any character              */
  1700. X            {
  1701. X                if (!cur_s)
  1702. X            return 0;
  1703. X
  1704. X                break;
  1705. X            }
  1706. X
  1707. X            case '*':            /* Match any number of any character*/
  1708. X            {
  1709. X                string--;
  1710. X
  1711. X                do
  1712. X                {
  1713. X                    if (pnmatch (string, pattern, 0))
  1714. X            return 1;
  1715. X                }
  1716. X                while (*(string++));
  1717. X
  1718. X        return 0;
  1719. X            }
  1720. X
  1721. X            case '\\':            /* Next character is non-meta       */
  1722. X            {
  1723. X                if (!(cur_p = *(pattern++)))
  1724. X            return 0;
  1725. X            }
  1726. X
  1727. X            default:            /* Match against current pattern    */
  1728. X            {
  1729. X                if (cur_p != cur_s)
  1730. X            return 0;
  1731. X
  1732. X                break;
  1733. X            }
  1734. X        }
  1735. X    }
  1736. X
  1737. X    return ((flag || (!(*string))) ? 1 : 0);
  1738. X}
  1739. SHAR_EOF
  1740. chmod 0644 lib/pnmatch.c || echo "restore of lib/pnmatch.c fails"
  1741. set `wc -c lib/pnmatch.c`;Sum=$1
  1742. if test "$Sum" != "2985"
  1743. then echo original size 2985, current size $Sum;fi
  1744. echo "x - extracting lib/getopt.c (Text)"
  1745. sed 's/^X//' << 'SHAR_EOF' > lib/getopt.c &&
  1746. X/*
  1747. X *  MODULE NAME:   getopt.c                Revision 1.0
  1748. X *
  1749. X *  AUTHOR:        I. Stewartson
  1750. X *                 Data Logic Ltd.,
  1751. X *                 Queens House,
  1752. X *                 Greenhill Way,
  1753. X *                 Harrow,
  1754. X *                 Middlesex HA1 1YR.
  1755. X *                 Telephone: London (01) 863 0383
  1756. X *
  1757. X#include <logo.h>
  1758. X *  MODULE DESCRIPTION: This function is based on the UNIX library function.
  1759. X *            getopt return the next option letter in argv that
  1760. X *            matches a letter in opstring.  optstring is a string
  1761. X *            of recognised option letters; if a letter is followed
  1762. X *            by a colon, the option is expected to have an argument
  1763. X *            that may or may not be separated from it by white
  1764. X *            space.  optarg is set to point to the start of the
  1765. X *            option argument on return from getopt.
  1766. X *
  1767. X *            getopt places in optind the argv index of the next
  1768. X *            argument to be processed.  Because optind is external,
  1769. X *            it is normally initialised to zero automatically before
  1770. X *            the first call to getopt.
  1771. X *
  1772. X *            When all options have been processed (i.e. up to the
  1773. X *            first non-option argument), getopt returns EOF.  The
  1774. X *            special option -- may be used to delimit the end of
  1775. X *            the options; EOF will be returned, and -- will be
  1776. X *            skipped.
  1777. X *
  1778. X *            getopt prints an error message on stderr and returns a
  1779. X *            question mark (?) when it encounters an option letter
  1780. X *            not included in optstring.  This error message may be
  1781. X *            disabled by setting opterr to a non-zero value.
  1782. X *
  1783. X *  CALLING SEQUENCE:    The following calling sequences are used:
  1784. X *
  1785. X *            int    getopt(argc, argv, optstring)
  1786. X *            int    argc;
  1787. X *            char    **argv;
  1788. X *            char    *optstring;
  1789. X *
  1790. X *  ERROR MESSAGES:
  1791. X *            %s: illegal option -- %c
  1792. X *            %s: option requires an argument -- %c
  1793. X *
  1794. X *  INCLUDE FILES:
  1795. X */
  1796. X
  1797. X#include <stdio.h>            /* Standard Input/Output    */
  1798. X#include <string.h>            /* String function declarations    */
  1799. X#include <stdlib.h>            /* Standard library declarations*/
  1800. X
  1801. X/*
  1802. X *  DATA DECLARATIONS:
  1803. X */
  1804. X
  1805. Xint        opterr = 0;
  1806. Xint        optind = 1;
  1807. Xint        optopt;
  1808. Xint        optvar = 0;
  1809. Xchar        *optarg;
  1810. X
  1811. Xstatic char    *errmes1 = "%s: illegal option -- %c\n";
  1812. Xstatic char    *errmes2 = "%s: option requires an argument -- %c\n";
  1813. X
  1814. X/*
  1815. X *  MODULE ABSTRACT:
  1816. X *
  1817. X *  EXECUTABLE CODE:
  1818. X */
  1819. X
  1820. Xint    getopt(argc, argv, optstring)
  1821. Xint    argc;                /* Argument count        */
  1822. Xchar    **argv;                /* Argument string vector    */
  1823. Xchar    *optstring;            /* Valid options        */
  1824. X{
  1825. X    static int    string_off = 1;        /* Current position        */
  1826. X    int        cur_option;        /* Current option        */
  1827. X    char    *cp;            /* Character pointer        */
  1828. X
  1829. X    if (string_off == 1)
  1830. X    {
  1831. X    if ((optind >= argc) || (argv[optind][0] != '-') || (!argv[optind][1]))
  1832. X        return (EOF);
  1833. X    
  1834. X    else if (!strcmp(argv[optind], "--"))
  1835. X    {
  1836. X        optind++;
  1837. X        return (EOF);
  1838. X    }
  1839. X    }
  1840. X
  1841. X/* Get the current character from the current argument vector */
  1842. X
  1843. X    optopt = cur_option = argv[optind][string_off];
  1844. X
  1845. X/* Validate it */
  1846. X
  1847. X    if ((cur_option == ':') || ((cur_option == '*') && optvar) ||
  1848. X    ((cp = strchr(optstring, cur_option)) == (char *)NULL))
  1849. X    {
  1850. X    if (opterr)
  1851. X        fprintf(stderr, errmes1, cur_option, argv[0]);
  1852. X
  1853. X    if (!argv[optind][++string_off])
  1854. X    {
  1855. X        optind++;
  1856. X        string_off = 1;
  1857. X    }
  1858. X
  1859. X    return ('?');
  1860. X    }
  1861. X
  1862. X/* Parameters following ? */
  1863. X
  1864. X    if (*(++cp) == ':')
  1865. X    {
  1866. X    if (argv[optind][string_off + 1])
  1867. X        optarg = &argv[optind++][string_off + 1];
  1868. X
  1869. X    else if (++optind >= argc)
  1870. X    {
  1871. X        if (opterr)
  1872. X        fprintf(stderr, errmes2, cur_option, argv[0]);
  1873. X
  1874. X        string_off = 1;
  1875. X        return ('?');
  1876. X    }
  1877. X
  1878. X    else
  1879. X        optarg = argv[optind++];
  1880. X    
  1881. X    string_off = 1;
  1882. X    }
  1883. X
  1884. X    else if ((*cp == '*') && optvar)
  1885. X    {
  1886. X    if (argv[optind][string_off + 1] != 0)
  1887. X        optarg = &argv[optind++][string_off + 1];
  1888. X    else
  1889. X    {
  1890. X        optarg = "";
  1891. X        optind++;
  1892. X        string_off = 1;
  1893. X    }
  1894. X    }
  1895. X
  1896. X    else
  1897. X    {
  1898. X    if (!argv[optind][++string_off])
  1899. X    {
  1900. X        string_off = 1;
  1901. X        optind++;
  1902. X    }
  1903. X
  1904. X    optarg = (char *)NULL;
  1905. X    }
  1906. X
  1907. X    return (cur_option);
  1908. X}
  1909. SHAR_EOF
  1910. chmod 0644 lib/getopt.c || echo "restore of lib/getopt.c fails"
  1911. set `wc -c lib/getopt.c`;Sum=$1
  1912. if test "$Sum" != "3853"
  1913. then echo original size 3853, current size $Sum;fi
  1914. echo "x - extracting scripts/l (Text)"
  1915. sed 's/^X//' << 'SHAR_EOF' > scripts/l &&
  1916. X#!sh
  1917. Xls -C $*
  1918. SHAR_EOF
  1919. chmod 0644 scripts/l || echo "restore of scripts/l fails"
  1920. set `wc -c scripts/l`;Sum=$1
  1921. if test "$Sum" != "14"
  1922. then echo original size 14, current size $Sum;fi
  1923. echo "x - extracting scripts/extend.lst (Text)"
  1924. sed 's/^X//' << 'SHAR_EOF' > scripts/extend.lst &&
  1925. XLIB.EXE
  1926. XLINK.EXE
  1927. Xsh.exe
  1928. SHAR_EOF
  1929. chmod 0644 scripts/extend.lst || echo "restore of scripts/extend.lst fails"
  1930. set `wc -c scripts/extend.lst`;Sum=$1
  1931. if test "$Sum" != "24"
  1932. then echo original size 24, current size $Sum;fi
  1933. echo "x - extracting scripts/profile.sh (Text)"
  1934. sed 's/^X//' << 'SHAR_EOF' > scripts/profile.sh &&
  1935. X#!sh
  1936. XPATH=".;..;c:/oracle5/bin;c:/bin;c:/dos;c:/scm;c:/windows"
  1937. XCDPATH=".;..;/;c:/;c:/windows;c:/scm;c:/ian"
  1938. XINCLUDE=c:/include
  1939. XLIB=c:/lib
  1940. XTMP=c:/tmp
  1941. XTZ=GMT0BST
  1942. XEDITOR=vi
  1943. XPS1="s0H[%p] %d %tu%n %e> "
  1944. XHOME=c:/
  1945. XTERM=ibmpc-mono
  1946. XCL="-AL -Zid -W3"
  1947. XINIT=c:/bin/me_ini
  1948. XEXTENDED_LINE=c:/bin/extend.lst
  1949. XEXINIT="set aw ai sm dm sw=4 wm=5"
  1950. X
  1951. Xmsdos LIB TMP
  1952. SHAR_EOF
  1953. chmod 0644 scripts/profile.sh || echo "restore of scripts/profile.sh fails"
  1954. set `wc -c scripts/profile.sh`;Sum=$1
  1955. if test "$Sum" != "366"
  1956. then echo original size 366, current size $Sum;fi
  1957. echo "x - extracting shell/Makefile (Text)"
  1958. sed 's/^X//' << 'SHAR_EOF' > shell/Makefile &&
  1959. X#
  1960. X# MS-DOS SHELL - Makefile
  1961. X#
  1962. X# MS-DOS SHELL - Copyright (c) 1989 Data Logic Limited.
  1963. X#
  1964. X# Redistribution and use in source and binary forms are permitted
  1965. X# provided that the above copyright notice is duplicated in the
  1966. X# source form.
  1967. X#
  1968. X#
  1969. X#    $Header$
  1970. X#
  1971. X#    $Log$
  1972. X#
  1973. X
  1974. XOBJS=sh0.obj sh1.obj sh2.obj sh3.obj sh4.obj sh5.obj sh6.obj    \
  1975. X     sh7.obj sh8.obj sh9.obj sh10.obj
  1976. XASFLAGS= /Ml /Zi /Zd
  1977. X
  1978. Xsh.exe:    $(OBJS)
  1979. X    link sh0+sh1+sh2+sh3+sh4+sh5+sh6+sh7+sh8+sh9+sh10/noi, sh.exe;
  1980. SHAR_EOF
  1981. chmod 0644 shell/Makefile || echo "restore of shell/Makefile fails"
  1982. set `wc -c shell/Makefile`;Sum=$1
  1983. if test "$Sum" != "470"
  1984. then echo original size 470, current size $Sum;fi
  1985. echo "x - extracting shell/sh1.c (Text)"
  1986. sed 's/^X//' << 'SHAR_EOF' > shell/sh1.c &&
  1987. X/* MS-DOS SHELL - Main program, memory and variable management
  1988. X *
  1989. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
  1990. X *
  1991. X * This code is based on (in part) the shell program written by Charles
  1992. X * Forsyth and is subject to the following copyright restrictions:
  1993. X *
  1994. X * 1.  Redistribution and use in source and binary forms are permitted
  1995. X *     provided that the above copyright notice is duplicated in the
  1996. X *     source form and the copyright notice in file sh6.c is displayed
  1997. X *     on entry to the program.
  1998. X *
  1999. X * 2.  The sources (or parts thereof) or objects generated from the sources
  2000. X *     (or parts of sources) cannot be sold under any circumstances.
  2001. X *
  2002. X *    $Header: sh1.c 1.1 90/01/25 13:40:39 MS_user Exp $
  2003. X *
  2004. X *    $Log:    sh1.c $
  2005. X * Revision 1.1  90/01/25  13:40:39  MS_user
  2006. X * Initial revision
  2007. X * 
  2008. X */
  2009. X
  2010. X#include <sys/types.h>
  2011. X#include <sys/stat.h>
  2012. X#include <stdio.h>
  2013. X#include <stdlib.h>
  2014. X#include <signal.h>
  2015. X#include <errno.h>
  2016. X#include <setjmp.h>
  2017. X#include <stdarg.h>
  2018. X#include <string.h>
  2019. X#include <unistd.h>
  2020. X#include <ctype.h>
  2021. X#include <fcntl.h>
  2022. X#include <limits.h>
  2023. X#include <dos.h>
  2024. X#include <time.h>
  2025. X#include "sh.h"
  2026. X
  2027. X/*
  2028. X * Structure of Malloced space to allow release of space nolonger required
  2029. X * without having to know about it.
  2030. X */
  2031. X
  2032. Xtypedef struct region {
  2033. X    struct region    *next;
  2034. X    int            area;
  2035. X} s_region;
  2036. X
  2037. Xstatic struct region    *areastart = (s_region *)NULL;
  2038. X
  2039. X/*
  2040. X * default shell, search rules
  2041. X */
  2042. X
  2043. Xstatic char    *shellname = "c:/bin/sh";
  2044. Xstatic char    *search    = ";c:/bin;c:/usr/bin";
  2045. Xstatic char    *ymail     = "You have mail\n";
  2046. Xstatic char    *Path       = "PATH";
  2047. X#ifdef SIGQUIT
  2048. Xstatic void    (*qflag)() = SIG_IGN;
  2049. X#endif
  2050. X
  2051. X/* Functions */
  2052. X
  2053. Xstatic char    *cclass (char *, int, bool);
  2054. Xstatic char    *copy_to_equals (char *, char *);
  2055. Xstatic void    nameval (Var_List *, char *, char *, bool);
  2056. Xstatic void    patch_up (void);
  2057. Xstatic void    onecommand (void);
  2058. Xstatic void    Check_Mail (void);
  2059. Xstatic void    Pre_Process_Argv (char **);
  2060. Xstatic void    Load_G_VL (void);
  2061. X
  2062. X/*
  2063. X * The main program starts here
  2064. X */
  2065. X
  2066. Xvoid        main (argc, argv)
  2067. Xint        argc;
  2068. Xregister char    **argv;
  2069. X{
  2070. X    register int    f;
  2071. X    register char    *s, *s1;
  2072. X    int            cflag = 0;
  2073. X    int            sc;
  2074. X    char        *name, **ap;
  2075. X    int            (*iof)(IO_State *) = filechar;
  2076. X    Var_List        *lset;
  2077. X    bool        l_rflag = FALSE;
  2078. X
  2079. X/* Patch up various parts of the system */
  2080. X
  2081. X    patch_up ();
  2082. X
  2083. X/* Load the environment into our structures */
  2084. X
  2085. X    if ((ap = environ) != (char **)NULL)
  2086. X    {
  2087. X    while (*ap)
  2088. X        assign (*ap++, !COPYV);
  2089. X
  2090. X    for (ap = environ; *ap;)
  2091. X        s_vstatus (lookup (*ap++, TRUE), EXPORT);
  2092. X    }
  2093. X
  2094. X/* Zap all files */
  2095. X
  2096. X    closeall ();
  2097. X    areanum = 1;
  2098. X
  2099. X/* Get the current directory */
  2100. X
  2101. X    Getcwd ();
  2102. X
  2103. X/* Set up some stardard variables if their not set */
  2104. X
  2105. X    if ((lset = lookup (shell, TRUE))->value == null)
  2106. X    setval (lset, shellname);
  2107. X
  2108. X    s_vstatus (lset, EXPORT);
  2109. X
  2110. X/* Check for restricted shell */
  2111. X
  2112. X    if ((s = strrchr (lset->value, '/')) == (char *)NULL)
  2113. X    s = lset->value;
  2114. X
  2115. X    else
  2116. X    s++;
  2117. X
  2118. X    if (*s == 'r')
  2119. X    l_rflag = TRUE;
  2120. X
  2121. X/* Set up home directory */
  2122. X
  2123. X    if ((lset = lookup (home, TRUE))->value == null)
  2124. X    setval (lset, "c:/");
  2125. X
  2126. X    s_vstatus (lset, EXPORT);
  2127. X
  2128. X/* Set up history file location */
  2129. X
  2130. X    setval (lookup ("$", TRUE), putn (getpid ()));
  2131. X
  2132. X    Load_G_VL ();
  2133. X    path->status |= (EXPORT | PONLY);
  2134. X    ifs->status  |= (EXPORT | PONLY);
  2135. X    ps1->status  |= (EXPORT | PONLY);
  2136. X    ps2->status  |= (EXPORT | PONLY);
  2137. X
  2138. X    if (path->value == null)
  2139. X    setval (path, search);
  2140. X
  2141. X    if (ifs->value == null)
  2142. X    setval (ifs, " \t\n");
  2143. X
  2144. X    if (ps1->value == null)
  2145. X    setval (ps1, "$ ");
  2146. X
  2147. X    if (ps2->value == null)
  2148. X    setval (ps2, "> ");
  2149. X
  2150. X/* Check the restricted shell */
  2151. X
  2152. X    if ((s = strrchr ((name = *argv), '/')) == (char *)NULL)
  2153. X    s = name;
  2154. X
  2155. X    if ((s1 = strchr (s, '.')) != (char *)NULL)
  2156. X    *s1 = 0;
  2157. X
  2158. X    if (strcmp (s, "rsh") == 0)
  2159. X    l_rflag = TRUE;
  2160. X
  2161. X    if (s1 != (char *)NULL)
  2162. X    *s1 = '.';
  2163. X
  2164. X/* Preprocess options to convert two character options of the form /x to
  2165. X * -x.  Some programs!!
  2166. X */
  2167. X
  2168. X     Pre_Process_Argv (argv);
  2169. X
  2170. X/* Process the options */
  2171. X
  2172. X    while ((sc = getopt (argc, argv, "abc:defghijklmnopqrtsuvwxyz0")) != EOF)
  2173. X    {
  2174. X    switch (sc)
  2175. X    {
  2176. X        case '0':                /* Level 0 flag for DOS    */
  2177. X        level0 = TRUE;
  2178. X        break;
  2179. X
  2180. X        case 'r':                /* Restricted        */
  2181. X        l_rflag = TRUE;
  2182. X        break;
  2183. X
  2184. X        case 'c':                /* Command on line    */
  2185. X        ps1->status &= ~EXPORT;
  2186. X        ps2->status &= ~EXPORT;
  2187. X        setval (ps1, null);
  2188. X        setval (ps2, null);
  2189. X        cflag = 1;
  2190. X
  2191. X        PUSHIO (aword, optarg, iof = nlchar);
  2192. X        break;
  2193. X
  2194. X        case 'q':                /* No quit ints        */
  2195. X#ifdef SIGQUIT
  2196. X        qflag = SIG_DFL;
  2197. X#endif
  2198. X        break;
  2199. X
  2200. X        case 's':                /* standard input    */
  2201. X        break;
  2202. X
  2203. X        case 't':                /* One command        */
  2204. X        ps1->status &= ~EXPORT;
  2205. X        setval (ps1, null);
  2206. X        iof = linechar;
  2207. X        break;
  2208. X
  2209. X        case 'i':                /* Set interactive    */
  2210. X        talking++;
  2211. X
  2212. X        default:
  2213. X        if (islower (sc))
  2214. X            FL_SET (sc);
  2215. X    }
  2216. X    }
  2217. X
  2218. X    argv += optind;
  2219. X    argc -= optind;
  2220. X
  2221. X/* Execute one off command - disable prompts */
  2222. X
  2223. X    if ((iof == filechar) && (argc > 0))
  2224. X    {
  2225. X    setval (ps1, null);
  2226. X    setval (ps2, null);
  2227. X    ps1->status &= ~EXPORT;
  2228. X    ps2->status &= ~EXPORT;
  2229. X
  2230. X    f = 0;
  2231. X
  2232. X/* Open the file if necessary */
  2233. X
  2234. X    if (strcmp ((name = *argv), "-") != 0)
  2235. X    {
  2236. X        if ((f = O_for_execute (name)) < 0)
  2237. X        {
  2238. X        print_error ("%s: cannot open\n", name);
  2239. X        exit (1);
  2240. X        }
  2241. X    }
  2242. X
  2243. X    next (remap (f));        /* Load into I/O stack    */
  2244. X    }
  2245. X
  2246. X/* Set up the $- variable */
  2247. X
  2248. X    setdash ();
  2249. X
  2250. X/* Load terminal I/O structure if necessary and load the history file */
  2251. X
  2252. X    if (e.iop < iostack)
  2253. X    {
  2254. X    PUSHIO (afile, 0, iof);
  2255. X
  2256. X    if (isatty (0) && isatty (1) && !cflag)
  2257. X    {
  2258. X        fprintf (stderr, Copy_Right1, _osmajor, _osminor);
  2259. X        fputs (Copy_Right2, stderr);
  2260. X
  2261. X        talking++;
  2262. X        History_Enabled = TRUE;
  2263. X        Load_History ();
  2264. X    }
  2265. X    }
  2266. X
  2267. X#ifdef SIGQUIT
  2268. X    signal (SIGQUIT, qflag);
  2269. X#endif
  2270. X
  2271. X/* Read profile ? */
  2272. X
  2273. X    if (((name != (char *)NULL) && (*name == '-')) || level0)
  2274. X    {
  2275. X    talking++;
  2276. X
  2277. X    if ((f = O_for_execute ("/etc/profile")) >= 0)
  2278. X        next (remap(f));
  2279. X
  2280. X    if ((f = O_for_execute ("profile")) >= 0)
  2281. X        next (remap(f));
  2282. X    }
  2283. X
  2284. X/* Set up signals */
  2285. X
  2286. X    if (talking)
  2287. X    signal (SIGTERM, sig);
  2288. X
  2289. X    if (signal (SIGINT, SIG_IGN) != SIG_IGN)
  2290. X    signal (SIGINT, onintr);
  2291. X
  2292. X/* Load any parameters */
  2293. X
  2294. X    dolv = argv;
  2295. X    dolc = argc;
  2296. X    dolv[0] = name;
  2297. X
  2298. X    if (dolc > 1)
  2299. X    {
  2300. X    for (ap = ++argv; --argc > 0;)
  2301. X    {
  2302. X        if (assign (*ap = *argv++, !COPYV))
  2303. X        dolc--;                    /* keyword */
  2304. X
  2305. X        else
  2306. X        ap++;
  2307. X    }
  2308. X    }
  2309. X
  2310. X    setval (lookup ("#", TRUE), putn ((--dolc < 0) ? (dolc = 0) : dolc));
  2311. X
  2312. X/* Execute the command loop */
  2313. X
  2314. X    while (1)
  2315. X    {
  2316. X    if (talking && e.iop <= iostack)
  2317. X    {
  2318. X        Check_Mail ();
  2319. X        put_prompt (ps1->value);
  2320. X        r_flag = l_rflag;
  2321. X    }
  2322. X
  2323. X    onecommand ();
  2324. X    }
  2325. X}
  2326. X
  2327. X/*
  2328. X * Set up the value of $-
  2329. X */
  2330. X
  2331. Xvoid    setdash ()
  2332. X{
  2333. X    register char    *cp, c;
  2334. X    char        m['z' - 'a' + 1];
  2335. X
  2336. X    for (cp = m, c = 'a'; c <= 'z'; ++c)
  2337. X    {
  2338. X    if (FL_TEST (c))
  2339. X        *(cp++) = c;
  2340. X    }
  2341. X
  2342. X    *cp = 0;
  2343. X    setval (lookup ("-", TRUE), m);
  2344. X}
  2345. X
  2346. X/* Execute a command */
  2347. X
  2348. Xstatic void    onecommand ()
  2349. X{
  2350. X    register int    i;
  2351. X    jmp_buf        m1;
  2352. X    C_Op        *outtree;
  2353. X
  2354. X
  2355. X/* Exit any previous environments */
  2356. X
  2357. X    while (e.oenv)
  2358. X    quitenv ();
  2359. X
  2360. X/* initialise space */
  2361. X
  2362. X    areanum = 1;
  2363. X    freehere (areanum);
  2364. X    freearea (areanum);
  2365. X    wdlist = (Word_B *)NULL;
  2366. X    iolist = (Word_B *)NULL;
  2367. X    e.errpt = (int *)NULL;
  2368. X    e.cline = space (LINE_MAX);
  2369. X    e.eline = e.cline + LINE_MAX - 5;
  2370. X    e.linep = e.cline;
  2371. X    yynerrs = 0;
  2372. X    multiline = 0;
  2373. X    inparse = 1;
  2374. X    SW_intr = 0;
  2375. X    execflg = 0;
  2376. X
  2377. X/* Get the line and process it */
  2378. X
  2379. X    if (setjmp (failpt = m1) || ((outtree = yyparse ()) == (C_Op *)NULL) ||
  2380. X    SW_intr)
  2381. X    {
  2382. X
  2383. X/* Failed - clean up */
  2384. X
  2385. X    while (e.oenv)
  2386. X        quitenv ();
  2387. X
  2388. X    scraphere ();
  2389. X
  2390. X    if (!talking && SW_intr)
  2391. X        leave ();
  2392. X
  2393. X/* Exit */
  2394. X
  2395. X    inparse = 0;
  2396. X    SW_intr = 0;
  2397. X    return;
  2398. X    }
  2399. X
  2400. X/* Ok - reset some variables and then execute the command tree */
  2401. X
  2402. X    inparse = 0;
  2403. X    Break_List = (Break_C *)NULL;
  2404. X    Return_List = (Break_C *)NULL;
  2405. X    SShell_List = (Break_C *)NULL;
  2406. X    SW_intr = 0;
  2407. X    execflg = 0;
  2408. X
  2409. X/* Set execute function recursive level and the SubShell count to zero */
  2410. X
  2411. X    Execute_stack_depth = 0;
  2412. X
  2413. X/* Set up Redirection IO (Saved) array and SubShell Environment information */
  2414. X
  2415. X    NSave_IO_E = 0;        /* Number of entries        */
  2416. X    MSave_IO_E = 0;        /* Max Number of entries    */
  2417. X    NSubShells = 0;        /* Number of entries        */
  2418. X    MSubShells = 0;        /* Max Number of entries    */
  2419. X
  2420. X/* Save the environment information */
  2421. X
  2422. X    if (talking && e.iop <= iostack)
  2423. X    Add_History (FALSE);
  2424. X
  2425. X    if (!FL_TEST ('n'))
  2426. X    execute (outtree, NOPIPE, NOPIPE, 0);
  2427. X
  2428. X/* Make sure the I/O and environment are back at level 0 and then clear them */
  2429. X
  2430. X    Execute_stack_depth = 0;
  2431. X
  2432. X    if (NSubShells != 0)
  2433. X    Delete_G_VL ();
  2434. X
  2435. X    if (NSave_IO_E)
  2436. X    restore_std (0);
  2437. X
  2438. X    if (MSubShells)
  2439. X    DELETE (SubShells);
  2440. X
  2441. X    if (MSave_IO_E)
  2442. X    DELETE (SSave_IO);
  2443. X
  2444. X/* Check for interrupts */
  2445. X
  2446. X    if (!talking && SW_intr)
  2447. X    {
  2448. X    execflg = 0;
  2449. X    leave ();
  2450. X    }
  2451. X
  2452. X/* Run any traps that are required */
  2453. X
  2454. X    if ((i = trapset) != 0)
  2455. X    {
  2456. X    trapset = 0;
  2457. X    runtrap (i);
  2458. X    }
  2459. X}
  2460. X
  2461. X/*
  2462. X * Terminate current environment with an error
  2463. X */
  2464. X
  2465. Xvoid    fail ()
  2466. X{
  2467. X    longjmp (failpt, 1);
  2468. X
  2469. X    /* NOTREACHED */
  2470. X}
  2471. X
  2472. X/*
  2473. X * Exit the shell
  2474. X */
  2475. X
  2476. Xvoid    leave ()
  2477. X{
  2478. X    if (execflg)
  2479. X    fail ();
  2480. X
  2481. X/* Clean up */
  2482. X
  2483. X    scraphere ();
  2484. X    freehere (1);
  2485. X
  2486. X/* Trap zero on exit */
  2487. X
  2488. X    runtrap (0);
  2489. X
  2490. X/* Dump history on exit */
  2491. X
  2492. X    if (talking && isatty(0))
  2493. X    Dump_History ();
  2494. X
  2495. X    closeall ();
  2496. X    exit (exstat);
  2497. X
  2498. X/* NOTREACHED */
  2499. X}
  2500. X
  2501. X/*
  2502. X * Output warning message
  2503. X */
  2504. X
  2505. Xvoid    print_warn (fmt)
  2506. Xchar    *fmt;
  2507. X{
  2508. X    va_list    ap;
  2509. X    char    x[100];
  2510. X
  2511. X    va_start (ap, fmt);
  2512. X    vsprintf (x, fmt, ap);
  2513. X    S_puts (x);
  2514. X    exstat = -1;
  2515. X
  2516. X/* If leave on error - exit */
  2517. X
  2518. X    if (FL_TEST ('e'))
  2519. X    leave ();
  2520. X
  2521. X    va_end (ap);
  2522. X}
  2523. X
  2524. X/*
  2525. X * Output error message
  2526. X */
  2527. X
  2528. Xvoid    print_error (fmt)
  2529. Xchar    *fmt;
  2530. X{
  2531. X    va_list    ap;
  2532. X    char    x[100];
  2533. X
  2534. X/* Error message processing */
  2535. X
  2536. X    va_start (ap, fmt);
  2537. X    vsprintf (x, fmt, ap);
  2538. X    S_puts (x);
  2539. X    exstat = -1;
  2540. X
  2541. X    if (FL_TEST ('e'))
  2542. X    leave ();
  2543. X
  2544. X    va_end (ap);
  2545. X
  2546. X/* Error processing */
  2547. X
  2548. X    if (FL_TEST ('n'))
  2549. X    return;
  2550. X
  2551. X/* If not interactive - exit */
  2552. X
  2553. X    if (!talking)
  2554. X    leave ();
  2555. X
  2556. X    if (e.errpt)
  2557. X    longjmp (e.errpt, 1);
  2558. X
  2559. X/* closeall (); Removed - caused problems.  There may be problems
  2560. X * remaining with files left open?
  2561. X */
  2562. X
  2563. X    e.iop = e.iobase = iostack;
  2564. X}
  2565. X
  2566. X/*
  2567. X * Create or delete a new environment.  If f is set, delete the environment
  2568. X */
  2569. X
  2570. Xbool    newenv (f)
  2571. Xint    f;
  2572. X{
  2573. X    register Environ    *ep;
  2574. X
  2575. X/* Delete environment? */
  2576. X
  2577. X    if (f)
  2578. X    {
  2579. X    quitenv ();
  2580. X    return TRUE;
  2581. X    }
  2582. X
  2583. X/* Create a new environment */
  2584. X
  2585. X    if ((ep = (Environ *) space (sizeof (Environ))) == (Environ *)NULL)
  2586. X    {
  2587. X    while (e.oenv)
  2588. X        quitenv ();
  2589. X
  2590. X    fail ();
  2591. X    }
  2592. X
  2593. X    *ep = e;
  2594. X    e.oenv = ep;
  2595. X    e.errpt = errpt;
  2596. X    return FALSE;
  2597. X}
  2598. X
  2599. X/*
  2600. X * Exit the current environment successfully
  2601. X */
  2602. X
  2603. Xvoid    quitenv ()
  2604. X{
  2605. X    register Environ    *ep;
  2606. X    register int    fd;
  2607. X
  2608. X/* Restore old environment, delete the space and close any files opened in
  2609. X * this environment
  2610. X */
  2611. X
  2612. X    if ((ep = e.oenv) != (Environ *)NULL)
  2613. X    {
  2614. X    fd = e.iofd;
  2615. X    e = *ep;
  2616. X
  2617. X    DELETE (ep);
  2618. X
  2619. X    while (--fd >= e.iofd)
  2620. X        S_close (fd, TRUE);
  2621. X    }
  2622. X}
  2623. X
  2624. X/*
  2625. X * Is character c in s?
  2626. X */
  2627. X
  2628. Xbool        any (c, s)
  2629. Xregister char    c;
  2630. Xregister char    *s;
  2631. X{
  2632. X    while (*s)
  2633. X    {
  2634. X    if (*(s++) == c)
  2635. X        return TRUE;
  2636. X    }
  2637. X
  2638. X    return FALSE;
  2639. X}
  2640. X
  2641. X/*
  2642. X * Convert binary to ascii
  2643. X */
  2644. X
  2645. Xchar        *putn (n)
  2646. Xregister int    n;
  2647. X{
  2648. X    static char        nt[10];
  2649. X
  2650. X    sprintf (nt, "%u", n);
  2651. X    return nt;
  2652. X}
  2653. X
  2654. X/*
  2655. X * Add a file to the input stack
  2656. X */
  2657. X
  2658. Xvoid    next (f)
  2659. Xint    f;
  2660. X{
  2661. X    PUSHIO (afile, f, filechar);
  2662. X}
  2663. X
  2664. X/*
  2665. X * SIGINT interrupt processing
  2666. X */
  2667. X
  2668. Xvoid    onintr (signo)
  2669. Xint    signo;
  2670. X{
  2671. X
  2672. X/* Restore signal processing and set SIGINT detected flag */
  2673. X
  2674. X    signal (SIGINT, onintr);
  2675. X    SW_intr = 1;
  2676. X
  2677. X/* Are we talking to the user?  Yes - check in parser */
  2678. X
  2679. X    if (talking)
  2680. X    {
  2681. X    if (inparse)
  2682. X    {
  2683. X        S_putc (NL);
  2684. X        fail ();
  2685. X    }
  2686. X    }
  2687. X
  2688. X/* No - exit */
  2689. X
  2690. X    else
  2691. X    {
  2692. X    execflg = 0;
  2693. X    leave ();
  2694. X    }
  2695. X}
  2696. X
  2697. X/*
  2698. X * Grap some space and check for an error
  2699. X */
  2700. X
  2701. Xchar    *space (n)
  2702. Xint    n;
  2703. X{
  2704. X    register char *cp;
  2705. X
  2706. X    if ((cp = getcell (n)) == (char *)NULL)
  2707. X    print_error ("sh: out of string space\n");
  2708. X
  2709. X    return cp;
  2710. X}
  2711. X
  2712. X/*
  2713. X * Save a string in a given area
  2714. X */
  2715. X
  2716. Xchar        *strsave (s, a)
  2717. Xregister char    *s;
  2718. X{
  2719. X    register char    *cp;
  2720. X
  2721. X    if ((cp = space (strlen (s) + 1)) != (char *)NULL)
  2722. X    {
  2723. X    setarea ((char *)cp, a);
  2724. X    return strcpy (cp, s);
  2725. X    }
  2726. X
  2727. X    return null;
  2728. X}
  2729. X
  2730. X/*
  2731. X * trap handling - Save signal number and restore signal processing
  2732. X */
  2733. X
  2734. Xvoid        sig (i)
  2735. Xregister int    i;
  2736. X{
  2737. X    trapset = i;
  2738. X    signal (i, sig);
  2739. X}
  2740. X
  2741. X/*
  2742. X * Execute a trap command
  2743. X */
  2744. X
  2745. Xvoid    runtrap (i)
  2746. Xint    i;
  2747. X{
  2748. X    char    *trapstr;
  2749. X    char    tval[10];
  2750. X
  2751. X    sprintf (tval, "~%d", i);
  2752. X
  2753. X    if (((trapstr = lookup (tval, FALSE)->value)) == null)
  2754. X    return;
  2755. X
  2756. X/* If signal zero, save a copy of the trap value and then delete the trap */
  2757. X
  2758. X    if (i == 0)
  2759. X    {
  2760. X    trapstr = strsave (trapstr, areanum);
  2761. X    unset (tval, TRUE);
  2762. X    }
  2763. X
  2764. X    RUN (aword, trapstr, nlchar);
  2765. X}
  2766. X
  2767. X/*
  2768. X * Find the given name in the dictionary and return its value.  If the name was
  2769. X * not previously there, enter it now and return a null value.
  2770. X */
  2771. X
  2772. XVar_List    *lookup (n, cflag)
  2773. Xregister char    *n;
  2774. Xbool        cflag;
  2775. X{
  2776. X    register Var_List    *vp;
  2777. X    register char    *cp;
  2778. X    register int    c;
  2779. X    static Var_List    dummy;
  2780. X
  2781. X/* Set up the dummy variable */
  2782. X
  2783. X    dummy.name = n;
  2784. X    dummy.status = RONLY;
  2785. X    dummy.value = null;
  2786. X
  2787. X/* If digit string - use the dummy to return the value */
  2788. X
  2789. X    if (isdigit (*n))
  2790. X    {
  2791. X    for (c = 0; isdigit (*n) && (c < 1000); n++)
  2792. X        c = c * 10 + *n - '0';
  2793. X
  2794. X    dummy.value = (c <= dolc) ? dolv[c] : null;
  2795. X    return &dummy;
  2796. X    }
  2797. X
  2798. X/* Look up in list */
  2799. X
  2800. X    for (vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
  2801. X    {
  2802. X    if (eqname (vp->name, n))
  2803. X        return vp;
  2804. X    }
  2805. X
  2806. X/* If we don't want to create it, return a dummy */
  2807. X
  2808. X    if (!cflag)
  2809. X    return &dummy;
  2810. X
  2811. X/* Create a new variable */
  2812. X
  2813. X    cp = findeq (n);
  2814. X
  2815. X    if (((vp = (Var_List *)space (sizeof (Var_List))) == (Var_List *)NULL)
  2816. X    || (vp->name = space ((int)(cp - n) + 2)) == (char *)NULL)
  2817. X    {
  2818. X    dummy.name = null;
  2819. X    return &dummy;
  2820. X    }
  2821. X
  2822. X/* Set area for space to zero - no auto-delete */
  2823. X
  2824. X    setarea ((char *)vp, 0);
  2825. X    setarea ((char *)vp->name, 0);
  2826. X
  2827. X/* Just the name upto the equals sign, no more */
  2828. X
  2829. X    copy_to_equals (vp->name, n);
  2830. X
  2831. X/* Link into list */
  2832. X
  2833. X    vp->value = null;
  2834. X    vp->next = vlist;
  2835. X    vp->status = GETCELL;
  2836. X    vlist = vp;
  2837. X    return vp;
  2838. X}
  2839. X
  2840. X/*
  2841. X * give variable at `vp' the value `val'.
  2842. X */
  2843. X
  2844. Xvoid        setval(vp, val)
  2845. XVar_List    *vp;
  2846. Xchar        *val;
  2847. X{
  2848. X    nameval (vp, val, (char *)NULL, FALSE);
  2849. X}
  2850. X
  2851. X/*
  2852. X * Copy and check that it terminates in an equals sign
  2853. X */
  2854. X
  2855. Xstatic char    *copy_to_equals (d, s)
  2856. Xchar        *d, *s;
  2857. X{
  2858. X    int        n = (int) (findeq (s) - s);
  2859. X
  2860. X    strncpy (d, s, n);
  2861. X    *(d += n) = '=';
  2862. X    *(++d) = 0;
  2863. X    return d;
  2864. X}
  2865. X
  2866. X/*
  2867. X * Set up new value for name
  2868. X *
  2869. X * If name is not NULL, it must be a prefix of the space `val', and end with
  2870. X * `='.  This is all so that exporting values is reasonably painless.
  2871. X */
  2872. X
  2873. Xstatic void        nameval (vp, val, name, disable)
  2874. Xregister Var_List    *vp;
  2875. Xchar            *val;
  2876. Xchar            *name;
  2877. Xbool            disable;
  2878. X{
  2879. X    register char    *xp;
  2880. X    int            fl = 0;
  2881. X
  2882. X/* Check if variable is read only */
  2883. X
  2884. X    if (vp->status & RONLY)
  2885. X    {
  2886. X    char    c = *(xp = findeq (vp->name));
  2887. X
  2888. X    *xp = 0;
  2889. X    S_puts (xp);
  2890. X    *xp = c;
  2891. X    print_error (" is read-only\n");
  2892. X    return;
  2893. X    }
  2894. X
  2895. X/* Check for $PATH reset in restricted shell */
  2896. X
  2897. X    if (!disable && (strcmp (vp->name, Path) == 0) && check_rsh (Path))
  2898. X    return;
  2899. X
  2900. X/* Get space for string ? */
  2901. X
  2902. X    if (name == (char *)NULL)
  2903. X    {
  2904. X    if ((xp = space (strlen (vp->name) + strlen (val) + 2)) == (char *)NULL)
  2905. X        return;
  2906. X
  2907. X/* make string:  name=value */
  2908. X
  2909. X    setarea ((char *)xp, 0);
  2910. X    name = xp;
  2911. X
  2912. X    xp = copy_to_equals (xp, vp->name);
  2913. X    strcpy (xp, val);
  2914. X    val = xp;
  2915. X    fl = GETCELL;
  2916. X    }
  2917. X
  2918. X    if (vp->status & GETCELL)
  2919. X    DELETE (vp->name);    /* form new string `name=value' */
  2920. X
  2921. X    vp->name = name;
  2922. X    vp->value = val;
  2923. X    vp->status |= fl;
  2924. X
  2925. X    if (FL_TEST ('a'))
  2926. X    s_vstatus (vp, EXPORT);
  2927. X}
  2928. X
  2929. X/*
  2930. X * Set the status of an environment variable
  2931. X */
  2932. X
  2933. Xvoid        s_vstatus (vp, flag)
  2934. XVar_List    *vp;
  2935. Xint        flag;            /* Addition status flags    */
  2936. X{
  2937. X    if (isalpha (*vp->name))        /* not an internal symbol ($# etc) */
  2938. X    vp->status |= flag;
  2939. X}
  2940. X
  2941. X/*
  2942. X * Check for assignment X=Y
  2943. X */
  2944. X
  2945. Xbool        isassign (s)
  2946. Xregister char    *s;
  2947. X{
  2948. X    if (!isalpha (*s))
  2949. X    return FALSE;
  2950. X
  2951. X    for (; *s != '='; s++)
  2952. X    {
  2953. X    if (!*s || !isalnum (*s))
  2954. X        return FALSE;
  2955. X    }
  2956. X
  2957. X    return TRUE;
  2958. X}
  2959. X
  2960. X/*
  2961. X * Execute an assignment.  If a valid assignment, load it into the variable
  2962. X * list.
  2963. X */
  2964. X
  2965. Xbool        assign (s, cf)
  2966. Xregister char    *s;
  2967. Xint        cf;
  2968. X{
  2969. X    register char    *cp;
  2970. X    Var_List        *vp;
  2971. X
  2972. X    if (!isalpha (*s))
  2973. X    return FALSE;
  2974. X
  2975. X    for (cp = s; *cp != '='; cp++)
  2976. X    {
  2977. X    if (!*cp || !isalnum (*cp))
  2978. X        return FALSE;
  2979. X    }
  2980. X
  2981. X    nameval ((vp = lookup (s, TRUE)), ++cp, (cf == COPYV ? (char *)NULL : s),
  2982. X         FALSE);
  2983. X
  2984. X    if (cf != COPYV)
  2985. X    vp->status &= ~GETCELL;
  2986. X
  2987. X    return TRUE;
  2988. X}
  2989. X
  2990. X/*
  2991. X * Compare two environment strings
  2992. X */
  2993. X
  2994. Xbool            eqname(n1, n2)
  2995. Xregister char        *n1, *n2;
  2996. X{
  2997. X    for (; *n1 != '=' && *n1 != 0; n1++)
  2998. X    {
  2999. X    if (*n2++ != *n1)
  3000. X        return FALSE;
  3001. X    }
  3002. X
  3003. X    return (!*n2 || (*n2 == '=')) ? TRUE : FALSE;
  3004. X}
  3005. X
  3006. X/*
  3007. X * Find the equals sign in a string
  3008. X */
  3009. X
  3010. Xchar        *findeq (cp)
  3011. Xregister char    *cp;
  3012. X{
  3013. X    while (*cp && (*cp != '='))
  3014. X    cp++;
  3015. X
  3016. X    return cp;
  3017. X}
  3018. X
  3019. X/*
  3020. X * Duplicate the Variable List for a Subshell
  3021. X *
  3022. X * Create a new Var_list environment for a Sub Shell
  3023. X */
  3024. X
  3025. Xint    Create_NG_VL ()
  3026. X{
  3027. X    int            i;
  3028. X    S_SubShell        *sp;
  3029. X    Var_List        *vp, *vp1;
  3030. X
  3031. X    for (sp = SubShells, i = 0; (i < NSubShells) &&
  3032. X                   (SubShells[i].depth < Execute_stack_depth);
  3033. X     i++);
  3034. X
  3035. X/* If depth is greater or equal to the Execute_stack_depth - we should panic
  3036. X * as this should not happen.  However, for the moment, I'll ignore it
  3037. X */
  3038. X
  3039. X    if (NSubShells == MSubShells)
  3040. X    {
  3041. X    sp = (S_SubShell *)space ((MSubShells + SSAVE_IO_SIZE) * sizeof (S_SubShell));
  3042. X
  3043. X/* Check for error */
  3044. X
  3045. X    if (sp == (S_SubShell *)NULL)
  3046. X    {
  3047. X        errno = ENOMEM;
  3048. X        return -1;
  3049. X    }
  3050. X
  3051. X/* Save original data */
  3052. X
  3053. X    if (MSubShells != 0)
  3054. X    {
  3055. X        memcpy (sp, SubShells, sizeof (S_SubShell) * MSubShells);
  3056. X        DELETE (SubShells);
  3057. X    }
  3058. X
  3059. X    setarea ((char *)sp, 0);
  3060. X    SubShells = sp;
  3061. X    MSubShells += SSAVE_IO_SIZE;
  3062. X    }
  3063. X
  3064. X/* Save the depth and the old vlist value */
  3065. X
  3066. X    sp = &SubShells[NSubShells++];
  3067. X    sp->depth  = Execute_stack_depth;
  3068. X    sp->header = vlist;
  3069. X    vlist = (Var_List *)NULL;
  3070. X
  3071. X/* Duplicate the old Variable list */
  3072. X
  3073. X    for (vp = sp->header; vp != (Var_List *)NULL; vp = vp->next)
  3074. X    {
  3075. X    nameval ((vp1 = lookup (vp->name, TRUE)), findeq (vp->name) + 1,
  3076. X         (char *)NULL, TRUE);
  3077. X
  3078. X    vp1->status |= (vp->status & (C_MSDOS | PONLY | EXPORT | RONLY));
  3079. X    }
  3080. X
  3081. X/* Reset global values */
  3082. X
  3083. X    Load_G_VL ();
  3084. X    return 0;
  3085. X}
  3086. X
  3087. X/*
  3088. X * Delete a SubShell environment and restore the original
  3089. X */
  3090. X
  3091. Xvoid    Delete_G_VL ()
  3092. X{
  3093. X    int        j;
  3094. X    S_SubShell    *sp;
  3095. X    Var_List    *vp;
  3096. X
  3097. X    for (j = NSubShells; j > 0; j--)
  3098. X    {
  3099. X       sp = &SubShells[j - 1];
  3100. X
  3101. X       if (sp->depth < Execute_stack_depth)
  3102. X       break;
  3103. X
  3104. X/* Reduce number of entries */
  3105. X
  3106. X    --NSubShells;
  3107. X
  3108. X/* Release the space */
  3109. X
  3110. X    for (vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
  3111. X    {
  3112. X        if (vp->status & GETCELL)
  3113. X        DELETE (vp->name);
  3114. X
  3115. X        DELETE (vp);
  3116. X    }
  3117. X
  3118. X/* Restore vlist information */
  3119. X
  3120. X    vlist = sp->header;
  3121. X    Load_G_VL ();
  3122. X    }
  3123. X}
  3124. X
  3125. X/*
  3126. X * Load GLobal Var List values
  3127. X */
  3128. X
  3129. Xstatic void    Load_G_VL ()
  3130. X{
  3131. X    path  = lookup (Path, TRUE);
  3132. X    ifs   = lookup ("IFS", TRUE);
  3133. X    ps1   = lookup ("PS1", TRUE);
  3134. X    ps2   = lookup ("PS2", TRUE);
  3135. X    C_dir = lookup ("~", TRUE);
  3136. X    Restore_Dir ();
  3137. X}
  3138. X
  3139. X/*
  3140. X * Match a pattern as in sh(1).
  3141. X */
  3142. X
  3143. Xbool        gmatch (s, p, IgnoreCase)
  3144. Xregister char    *s, *p;
  3145. Xbool        IgnoreCase;
  3146. X{
  3147. X    register int    sc, pc;
  3148. X
  3149. X    if ((s == (char *)NULL) || (p == (char *)NULL))
  3150. X    return FALSE;
  3151. X
  3152. X    while ((pc = *(p++) & CMASK) != '\0')
  3153. X    {
  3154. X    sc = *(s++) & QMASK;
  3155. X
  3156. X    switch (pc)
  3157. X    {
  3158. X        case '[':            /* Class expression        */
  3159. X        if ((p = cclass (p, sc, IgnoreCase)) == (char *)NULL)
  3160. X            return FALSE;
  3161. X
  3162. X        break;
  3163. X
  3164. X        case '?':            /* Match any character        */
  3165. X        if (sc == 0)
  3166. X            return FALSE;
  3167. X
  3168. X        break;
  3169. X
  3170. X        case '*':            /* Match as many as possible    */
  3171. X        s--;
  3172. X        do
  3173. X        {
  3174. X            if (!*p || gmatch (s, p, IgnoreCase))
  3175. X            return TRUE;
  3176. X
  3177. X        } while (*(s++));
  3178. X
  3179. X        return FALSE;
  3180. X
  3181. X        default:
  3182. X        if (IgnoreCase)
  3183. X        {
  3184. X            sc = tolower (sc);
  3185. X            pc = tolower ((pc & ~QUOTE));
  3186. X        }
  3187. X
  3188. X        if (sc != (pc & ~QUOTE))
  3189. X            return FALSE;
  3190. X    }
  3191. X    }
  3192. X
  3193. X    return (*s == 0) ? TRUE : FALSE;
  3194. X}
  3195. X
  3196. X/*
  3197. X * Process a class expression - []
  3198. X */
  3199. X
  3200. Xstatic char    *cclass (p, sub, IgnoreCase)
  3201. Xregister char    *p;
  3202. Xregister int    sub;
  3203. Xbool        IgnoreCase;
  3204. X{
  3205. X    register int    c, d, not, found;
  3206. X
  3207. X/* Exclusive or inclusive class */
  3208. X
  3209. X    if ((not = *p == NOT) != 0)
  3210. X    p++;
  3211. X
  3212. X    found = not;
  3213. X
  3214. X    do
  3215. X    {
  3216. X    if (!*p)
  3217. X        return (char *)NULL;
  3218. X
  3219. X/* Get the next character in class, converting to lower case if necessary */
  3220. X
  3221. X    c = IgnoreCase ? tolower ((*p & CMASK)) : (*p & CMASK);
  3222. X
  3223. X/* If this is a range, get the end of range character */
  3224. X
  3225. X    if ((*(p + 1) == '-') && (*(p + 2) != ']'))
  3226. X    {
  3227. X        d = IgnoreCase ? tolower ((*(p + 2) & CMASK)) : (*(p + 2) & CMASK);
  3228. X        p++;
  3229. X    }
  3230. X
  3231. X    else
  3232. X        d = c;
  3233. X
  3234. X/* Is the current character in the class? */
  3235. X
  3236. X    if ((c <= sub) && (sub <= d))
  3237. X        found = !not;
  3238. X
  3239. X    } while (*(++p) != ']');
  3240. X
  3241. X    return found ? p + 1 : (char *)NULL;
  3242. X}
  3243. X
  3244. X/*
  3245. X * Get a string in a malloced area
  3246. X */
  3247. X
  3248. Xchar        *getcell(nbytes)
  3249. Xunsigned int    nbytes;
  3250. X{
  3251. X    s_region        *np;
  3252. X
  3253. X    if (nbytes == 0)
  3254. X    abort ();    /* silly and defeats the algorithm */
  3255. X
  3256. X/* Grab some space */
  3257. X
  3258. X    if ((np = (s_region *)calloc (nbytes + sizeof (s_region), 1)) == (s_region *)NULL)
  3259. X        return (char *)NULL;
  3260. X
  3261. X/* Link into chain */
  3262. X
  3263. X    np->next = areastart;
  3264. X    np->area = areanum;
  3265. X    areastart = np;
  3266. X
  3267. X    return ((char *)np) + sizeof (s_region);
  3268. X}
  3269. X
  3270. X/*
  3271. X * Free a string in a malloced area
  3272. X */
  3273. X
  3274. Xvoid    freecell (s)
  3275. Xchar    *s;
  3276. X{
  3277. X    register s_region    *cp = areastart;
  3278. X    s_region        *lp = (s_region *)NULL;
  3279. X    s_region        *sp = (s_region *)(s - sizeof (s_region));
  3280. X
  3281. X/* Find the string in the chain */
  3282. X
  3283. X    if (s != (char *)NULL)
  3284. X    {
  3285. X    while (cp != (s_region *)NULL)
  3286. X    {
  3287. X        if (cp != sp)
  3288. X        {
  3289. X        lp = cp;
  3290. X        cp = cp->next;
  3291. X        continue;
  3292. X        }
  3293. X
  3294. X/* First in chain ? */
  3295. X
  3296. X        else if (lp == (s_region *)NULL)
  3297. X        areastart = cp->next;
  3298. X
  3299. X/* Delete the current entry and relink */
  3300. X
  3301. X        else
  3302. X        lp->next = cp->next;
  3303. X
  3304. X        free (cp);
  3305. X        break;
  3306. X    }
  3307. X    }
  3308. X}
  3309. X
  3310. X/*
  3311. X * Autodelete space nolonger required.  Ie. Free all the strings in a malloced
  3312. X * area
  3313. X */
  3314. X
  3315. Xvoid        freearea (a)
  3316. Xregister int    a;
  3317. X{
  3318. X    register s_region    *cp = areastart;
  3319. X    s_region        *lp = (s_region *)NULL;
  3320. X
  3321. X    while (cp != (s_region *)NULL)
  3322. X    {
  3323. X
  3324. X/* Is the area number less than that specified - yes, continue */
  3325. X    if (cp->area < a)
  3326. X    {
  3327. X        lp = cp;
  3328. X        cp = cp->next;
  3329. X    }
  3330. X
  3331. X/* OK - delete the area.  Is it the first in chain ?  Yes, delete, relink
  3332. X * and update start location
  3333. X */
  3334. X
  3335. X    else if (lp == (s_region *)NULL)
  3336. X    {
  3337. X        lp = cp;
  3338. X        cp = cp->next;
  3339. X        areastart = cp;
  3340. X
  3341. X        free (lp);
  3342. X        lp = (char *)NULL;
  3343. X    }
  3344. X
  3345. X/* Not first, delete the current entry and relink */
  3346. X
  3347. X    else
  3348. X    {
  3349. X        lp->next = cp->next;
  3350. X        free (cp);
  3351. X        cp = lp->next;
  3352. X    }
  3353. X    }
  3354. X}
  3355. X
  3356. X/*
  3357. X * Set the area number for a malloced string.  This allows autodeletion of
  3358. X * space that is nolonger required.
  3359. X */
  3360. X
  3361. Xvoid    setarea (cp,a)
  3362. Xchar    *cp;
  3363. Xint    a;
  3364. X{
  3365. X    s_region    *sp = (s_region *)(cp - sizeof (s_region));
  3366. X
  3367. X    if (cp != (char *)NULL)
  3368. X    sp->area = a;
  3369. X}
  3370. X
  3371. X/*
  3372. X * Get the area number for a malloced string
  3373. X */
  3374. X
  3375. Xint    getarea (cp)
  3376. Xchar    *cp;
  3377. X{
  3378. X    s_region    *sp = (s_region *)(cp - sizeof (s_region));
  3379. X
  3380. X    return sp->area;
  3381. X}
  3382. X
  3383. X/* Output one of the Prompt.  We save the prompt for the history part of
  3384. X * the program
  3385. X */
  3386. X
  3387. Xvoid    put_prompt (s)
  3388. Xchar    *s;
  3389. X{
  3390. X    struct dosdate_t     d_date;
  3391. X    struct dostime_t    d_time;
  3392. X    int            i;
  3393. X    char        buf[PATH_MAX + 4];
  3394. X
  3395. X    last_prompt = s;        /* Save the Last prompt output        */
  3396. X
  3397. X    _dos_gettime (&d_time);    /* Get the date and time in case    */
  3398. X    _dos_getdate (&d_date);
  3399. X
  3400. X    while (*s)
  3401. X    {
  3402. X
  3403. X/* If a format character, process it */
  3404. X
  3405. X    if (*s == '%')
  3406. X    {
  3407. X        s++;
  3408. X        *s = tolower(*s);
  3409. X
  3410. X        if (*s == '%')
  3411. X        S_putc ('%');
  3412. X
  3413. X        else
  3414. X        {
  3415. X        *buf = 0;
  3416. X
  3417. X        switch (*s)
  3418. X        {
  3419. X            case 'e':            /* Current event number */
  3420. X            if (History_Enabled)
  3421. X                sprintf (buf, "%d", Current_Event + 1);
  3422. X
  3423. X            break;
  3424. X
  3425. X            case 't':            /* time        */
  3426. X            sprintf (buf,"%.2d:%.2d", d_time.hour, d_time.minute);
  3427. X            break;
  3428. X
  3429. X            case 'd':            /* date        */
  3430. X            sprintf (buf, "%.3s %.2d-%.2d-%.2d",
  3431. X                 &"SunMonTueWedThuFriSat"[d_date.dayofweek * 3],
  3432. X                 d_date.day, d_date.month, d_date.year % 100);
  3433. X            break;
  3434. X
  3435. X            case 'p':            /* directory    */
  3436. X            case 'n':            /* default drive */
  3437. X            strcpy (buf, C_dir->value);
  3438. X
  3439. X            if (*s == 'n')
  3440. X                buf[1] = 0;
  3441. X
  3442. X            break;
  3443. X
  3444. X            case 'v':            /* version        */
  3445. X            sprintf (buf, "MS-DOS %.2d:%.2d", _osmajor, _osminor);
  3446. X            break;
  3447. X        }
  3448. X
  3449. X/* Output the string */
  3450. X
  3451. X        S_puts (buf);
  3452. X        }
  3453. X    }
  3454. X
  3455. X/* Escaped character ? */
  3456. X
  3457. X    else if (*s == '\\')
  3458. X    {
  3459. X        if ((i = Process_Escape (&s)) == -1)
  3460. X        i = 0;
  3461. X
  3462. X        S_putc (i);
  3463. X    }
  3464. X
  3465. X    else
  3466. X        S_putc (*s);
  3467. X
  3468. X/* Go to the next character */
  3469. X
  3470. X    s++;
  3471. X    }
  3472. X}
  3473. X
  3474. X/*
  3475. X * Get the current path in UNIX format and save it in the environment
  3476. X * variable $~
  3477. X */
  3478. X
  3479. Xvoid    Getcwd ()
  3480. X{
  3481. X    char    ldir[PATH_MAX + 6];
  3482. X    char    *cp = getcwd (ldir, PATH_MAX + 4);
  3483. X
  3484. X    strlwr (cp);
  3485. X
  3486. X/* Convert to Unix format */
  3487. X
  3488. X    while (*cp)
  3489. X    {
  3490. X    if (*cp == '\\')
  3491. X        *cp = '/';
  3492. X
  3493. X    ++cp;
  3494. X    }
  3495. X
  3496. X/* Save in environment */
  3497. X
  3498. X    setval ((C_dir = lookup ("~", TRUE)), ldir);
  3499. X}
  3500. X
  3501. X/*
  3502. X * Patch up various parts of the system for the shell.  At the moment, we
  3503. X * modify the ctype table so that _ is an upper case character.
  3504. X */
  3505. X
  3506. Xstatic void    patch_up ()
  3507. X{
  3508. X/* Patch the ctype table as a cheat */
  3509. X
  3510. X    (_ctype+1)['_'] |= _UPPER;
  3511. X}
  3512. X
  3513. X/*
  3514. X * Mail Check processing.  Every $MAILCHECK seconds, we check either $MAIL
  3515. X * or $MAILPATH to see if any file has changed its modification time since
  3516. X * we last looked.  In $MAILCHECK, the files are separated by colons (:).
  3517. X * If the filename contains a %, the string following the % is the message
  3518. X * to display if the file has changed.
  3519. X */
  3520. X
  3521. Xstatic void    Check_Mail ()
  3522. X{
  3523. X    int            delay = atoi (lookup ("MAILCHECK", FALSE)->value);
  3524. X    Var_List        *mail = lookup ("MAIL", FALSE);
  3525. X    Var_List        *mailp = lookup ("MAILPATH", FALSE);
  3526. X    static time_t    last = 0L;
  3527. X    time_t        current = time ((time_t *)NULL);
  3528. X    struct stat        st;
  3529. X    char        *cp, *sp, *ap;
  3530. X
  3531. X/* Have we waited long enough */
  3532. X
  3533. X    if ((current - last) < delay)
  3534. X    return;
  3535. X
  3536. X/* Yes - Check $MAILPATH.  If it is defined, process it.  Otherwise, use
  3537. X * $MAIL
  3538. X */
  3539. X
  3540. X    if (mailp->value != null)
  3541. X    {
  3542. X
  3543. X/* Check MAILPATH */
  3544. X
  3545. X    sp = mailp->value;
  3546. X
  3547. X/* Look for the next separator */
  3548. X
  3549. X    while ((cp = strchr (sp, ':')) != (char *)NULL)
  3550. X    {
  3551. X        *cp = 0;
  3552. X
  3553. X/* % in string ? */
  3554. X
  3555. X        if ((ap = strchr (ap, '%')) != (char *)NULL)
  3556. X        *ap = 0;
  3557. X
  3558. X/* Check the file name */
  3559. X
  3560. X        if ((stat (sp, &st) != -1) && (st.st_mtime > last))
  3561. X        {
  3562. X        if (ap != (char *)NULL)
  3563. X        {
  3564. X            S_puts (ap + 1);
  3565. X            S_putc (NL);
  3566. X        }
  3567. X
  3568. X        else
  3569. X            S_puts (ymail);
  3570. X        }
  3571. X
  3572. X/* Restore the % */
  3573. X
  3574. X        if (ap != (char *)NULL)
  3575. X        *ap = '%';
  3576. X
  3577. X/* Restore the colon and find the next one */
  3578. X
  3579. X        *cp = ':';
  3580. X        sp = cp + 1;
  3581. X    }
  3582. X    }
  3583. X
  3584. X/* Just check MAIL */
  3585. X
  3586. X    else if ((mail->value != null) && (stat (mail->value, &st) != -1) &&
  3587. X         (st.st_mtime > last))
  3588. X    S_puts (ymail);
  3589. X
  3590. X/* Save the last check time */
  3591. X
  3592. X    last = current;
  3593. X}
  3594. X
  3595. X/*
  3596. X * Preprocess Argv to get handle of options in the format /x
  3597. X *
  3598. X * Some programs invoke the shell using / instead of - to mark the options.
  3599. X * We need to convert to -.  Also /c is a special case.  The rest of the
  3600. X * command line is the command to execute.  So, we get the command line
  3601. X * from the original buffer instead of argv array.
  3602. X */
  3603. X
  3604. Xstatic void    Pre_Process_Argv (argv)
  3605. Xchar        **argv;
  3606. X{
  3607. X    char    *ocl = (char far *)((((long)_psp) << 16) + 0x081L);
  3608. X
  3609. X
  3610. X/* Check for these options */
  3611. X
  3612. X    while ((*++argv != (char *)NULL) && (strlen (*argv) == 2) &&
  3613. X       (**argv == '/'))
  3614. X    {
  3615. X       *strlwr (*argv) = '-';
  3616. X
  3617. X/* Get the original information from the command line */
  3618. X
  3619. X       if ((*argv)[1] == 'c')
  3620. X       {
  3621. X        while ((*ocl != '/') && (*(ocl + 1) != 'c') && (*ocl) &&
  3622. X           (*ocl != '\r'))
  3623. X        ++ocl;
  3624. X
  3625. X        if (*ocl != '/')
  3626. X        continue;
  3627. X
  3628. X/* Find the start of the string */
  3629. X
  3630. X        ocl += 2;
  3631. X
  3632. X        while (isspace (*ocl) && (*ocl != '\r'))
  3633. X        ++ocl;
  3634. X
  3635. X        if (*ocl == '\r')
  3636. X        continue;
  3637. X
  3638. X/* Found the start.  Set up next parameter and ignore the rest */
  3639. X
  3640. X        if (*(argv + 1) == (char *)NULL)
  3641. X        continue;
  3642. X
  3643. X        *(argv + 1) = ocl;
  3644. X        *(argv + 2) = (char *)NULL;
  3645. X
  3646. X        if ((ocl = strchr (ocl, '\r')) != (char *)NULL)
  3647. X        *ocl = 0;
  3648. X
  3649. X        return;
  3650. X       }
  3651. X    }
  3652. X}
  3653. SHAR_EOF
  3654. chmod 0644 shell/sh1.c || echo "restore of shell/sh1.c fails"
  3655. set `wc -c shell/sh1.c`;Sum=$1
  3656. if test "$Sum" != "28366"
  3657. then echo original size 28366, current size $Sum;fi
  3658. echo "x - extracting shell/sh2.c (Text)"
  3659. sed 's/^X//' << 'SHAR_EOF' > shell/sh2.c &&
  3660. X/* MS-DOS SHELL - Parser
  3661. X *
  3662. X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
  3663. X *
  3664. X * This code is based on (in part) the shell program written by Charles
  3665. X * Forsyth and is subject to the following copyright restrictions:
  3666. X *
  3667. X * 1.  Redistribution and use in source and binary forms are permitted
  3668. X *     provided that the above copyright notice is duplicated in the
  3669. X *     source form and the copyright notice in file sh6.c is displayed
  3670. X *     on entry to the program.
  3671. X *
  3672. X * 2.  The sources (or parts thereof) or objects generated from the sources
  3673. X *     (or parts of sources) cannot be sold under any circumstances.
  3674. X *
  3675. X *    $Header: sh2.c 1.1 90/01/25 13:41:12 MS_user Exp $
  3676. X *
  3677. X *    $Log:    sh2.c $
  3678. X * Revision 1.1  90/01/25  13:41:12  MS_user
  3679. X * Initial revision
  3680. X * 
  3681. X */
  3682. X
  3683. X#include <sys/types.h>
  3684. X#include <stddef.h>
  3685. X#include <signal.h>
  3686. X#include <errno.h>
  3687. X#include <setjmp.h>
  3688. X#include <string.h>
  3689. X#include <ctype.h>
  3690. X#include <unistd.h>
  3691. X#include "sh.h"
  3692. X
  3693. X/*
  3694. X * shell: syntax (C version)
  3695. X */
  3696. X
  3697. Xtypedef union {
  3698. X    char    *cp;
  3699. X    char    **wp;
  3700. X    int        i;
  3701. X    C_Op    *o;
  3702. X} YYSTYPE;
  3703. X
  3704. X#define    WORD    256
  3705. X#define    LOGAND    257
  3706. X#define    LOGOR    258
  3707. X#define    BREAK    259
  3708. X#define    IF    260
  3709. X#define    THEN    261
  3710. X#define    ELSE    262
  3711. X#define    ELIF    263
  3712. X#define    FI    264
  3713. X#define    CASE    265
  3714. X#define    ESAC    266
  3715. X#define    FOR    267
  3716. X#define    WHILE    268
  3717. X#define    UNTIL    269
  3718. X#define    DO    270
  3719. X#define    DONE    271
  3720. X#define    IN    272
  3721. X#define    YYERRCODE 300
  3722. X
  3723. X/* flags to yylex */
  3724. X
  3725. X#define    CONTIN    01    /* skip new lines to complete command */
  3726. X
  3727. Xstatic bool        startl;
  3728. Xstatic int        peeksym;
  3729. Xstatic bool        Allow_funcs;
  3730. Xstatic int        iounit = IODEFAULT;
  3731. Xstatic C_Op        *tp;
  3732. Xstatic YYSTYPE        yylval;
  3733. Xstatic char        *syntax_err = "sh: syntax error\n";
  3734. X
  3735. Xstatic C_Op        *pipeline (int);
  3736. Xstatic C_Op        *andor (void);
  3737. Xstatic C_Op        *c_list (bool);
  3738. Xstatic bool        synio (int);
  3739. Xstatic void        musthave (int, int);
  3740. Xstatic C_Op        *simple (void);
  3741. Xstatic C_Op        *nested (int, int);
  3742. Xstatic C_Op        *command (int);
  3743. Xstatic C_Op        *dogroup (int);
  3744. Xstatic C_Op        *thenpart (void);
  3745. Xstatic C_Op        *elsepart (void);
  3746. Xstatic C_Op        *caselist (void);
  3747. Xstatic C_Op        *casepart (void);
  3748. Xstatic char        **pattern (void);
  3749. Xstatic char        **wordlist (void);
  3750. Xstatic C_Op        *list (C_Op *, C_Op *);
  3751. Xstatic C_Op        *block (int, C_Op *, C_Op *, char **);
  3752. Xstatic int        rlookup (char *);
  3753. Xstatic C_Op        *namelist (C_Op *);
  3754. Xstatic char        **copyw (void);
  3755. Xstatic void        word (char *);
  3756. Xstatic IO_Actions    **copyio (void);
  3757. Xstatic IO_Actions    *io (int, int, char *);
  3758. Xstatic void        yyerror (char *);
  3759. Xstatic int        yylex (int);
  3760. Xstatic int        collect (int, int);
  3761. Xstatic int        dual (int);
  3762. Xstatic void        diag (int);
  3763. Xstatic char        *tree (unsigned int);
  3764. X
  3765. XC_Op    *yyparse ()
  3766. X{
  3767. X    C_Op    *outtree;
  3768. X
  3769. X    startl  = TRUE;
  3770. X    peeksym = 0;
  3771. X    yynerrs = 0;
  3772. X    outtree = c_list (TRUE);
  3773. X    musthave (NL, 0);
  3774. X
  3775. X    return (yynerrs != 0) ? (C_Op *)NULL : outtree;
  3776. X}
  3777. X
  3778. Xstatic C_Op    *pipeline (cf)
  3779. Xint        cf;
  3780. X{
  3781. X    register C_Op    *t, *p;
  3782. X    register int    c;
  3783. X
  3784. X    if ((t = command (cf)) != (C_Op *)NULL)
  3785. X    {
  3786. X    Allow_funcs = FALSE;
  3787. X    while ((c = yylex (0)) == '|') 
  3788. X    {
  3789. X        if ((p = command (CONTIN)) == (C_Op *)NULL)
  3790. X        yyerror (syntax_err);
  3791. X
  3792. X/* shell statement */
  3793. X
  3794. X        if ((t->type != TPAREN) && (t->type != TCOM))
  3795. X        t = block (TPAREN, t, NOBLOCK, NOWORDS);
  3796. X
  3797. X        t = block (TPIPE, t, p, NOWORDS);
  3798. X    }
  3799. X
  3800. X    peeksym = c;
  3801. X    }
  3802. X
  3803. X    return t;
  3804. X}
  3805. X
  3806. Xstatic C_Op    *andor ()
  3807. X{
  3808. X    register C_Op    *t, *p;
  3809. X    register int    c;
  3810. X
  3811. X    if ((t = pipeline (0)) != (C_Op *)NULL)
  3812. X    {
  3813. X    Allow_funcs = FALSE;
  3814. X    while (((c = yylex (0)) == LOGAND) || (c == LOGOR))
  3815. X    {
  3816. X        if ((p = pipeline (CONTIN)) == (C_Op *)NULL)
  3817. X        yyerror (syntax_err);
  3818. X
  3819. X        t = block ((c == LOGAND) ? TAND : TOR, t, p, NOWORDS);
  3820. X    }
  3821. X
  3822. X    peeksym = c;
  3823. X    }
  3824. X
  3825. X    return t;
  3826. X}
  3827. X
  3828. Xstatic C_Op    *c_list (allow)
  3829. Xbool        allow;
  3830. X{
  3831. X    register C_Op    *t, *p;
  3832. X    register int    c;
  3833. X
  3834. X/* Functions are only allowed at the start of a line */
  3835. X
  3836. X    Allow_funcs = allow;
  3837. X
  3838. X    if ((t = andor ()) != (C_Op *)NULL)
  3839. X    {
  3840. X    Allow_funcs = FALSE;
  3841. X
  3842. X    if ((peeksym = yylex (0)) == '&')
  3843. X        t = block (TASYNC, t, NOBLOCK, NOWORDS);
  3844. X
  3845. X    while ((c = yylex(0)) == ';' || c == '&' || multiline && c == NL)
  3846. X    {
  3847. X        if ((p = andor ()) == (C_Op *)NULL)
  3848. X        return t;
  3849. X
  3850. X        if ((peeksym = yylex (0)) == '&')
  3851. X        p = block (TASYNC, p, NOBLOCK, NOWORDS);
  3852. X
  3853. X        t = list (t, p);
  3854. X    }
  3855. X    peeksym = c;
  3856. X    }
  3857. X
  3858. X    return t;
  3859. X}
  3860. X
  3861. X
  3862. Xstatic bool    synio (cf)
  3863. Xint        cf;
  3864. X{
  3865. X    register IO_Actions    *iop;
  3866. X    register int    i;
  3867. X    register int    c;
  3868. X
  3869. X    if (((c = yylex (cf)) != '<') && (c != '>'))
  3870. X    {
  3871. X    peeksym = c;
  3872. X    return FALSE;
  3873. X    }
  3874. X
  3875. X    i = yylval.i;
  3876. X    musthave (WORD, 0);
  3877. X    iop = io (iounit, i, yylval.cp);
  3878. X    iounit = IODEFAULT;
  3879. X
  3880. X    if (i & IOHERE)
  3881. X    markhere (yylval.cp, iop);
  3882. X    
  3883. X    return TRUE;
  3884. X}
  3885. X
  3886. Xstatic void    musthave (c, cf)
  3887. Xint        c, cf;
  3888. X{
  3889. X    if ((peeksym = yylex (cf)) != c)
  3890. X    yyerror (syntax_err);
  3891. X
  3892. X    peeksym = 0;
  3893. X}
  3894. X
  3895. Xstatic C_Op    *simple ()
  3896. X{
  3897. X    register C_Op    *t = (C_Op *)NULL;
  3898. X
  3899. X    while (1)
  3900. X    {
  3901. X    switch (peeksym = yylex (0)) 
  3902. X    {
  3903. X        case '<':
  3904. X        case '>':
  3905. X        synio (0);
  3906. X        break;
  3907. X
  3908. X        case WORD:
  3909. X        if (t == (C_Op *)NULL) 
  3910. X            (t = (C_Op *)tree (sizeof (C_Op)))->type = TCOM;
  3911. X
  3912. X        peeksym = 0;
  3913. X        word (yylval.cp);
  3914. X        break;
  3915. X
  3916. X/* Check for function - name () { word; } */
  3917. X
  3918. X        case '(':
  3919. X        if ((t != (C_Op *)NULL) && (Allow_funcs == TRUE) &&
  3920. X            (wdlist != (Word_B *)NULL) && (wdlist->w_nword == 1))
  3921. X        {
  3922. X            Word_B    *save;
  3923. X
  3924. X            peeksym = 0;
  3925. X            musthave (')', 0);
  3926. X            musthave ('{', 0);
  3927. X            save = wdlist;
  3928. X            wdlist = (Word_B *)NULL;
  3929. X            t->type = TFUNC;
  3930. X            t->left = nested (TBRACE, '}');
  3931. X            wdlist = save;
  3932. X            Allow_funcs = FALSE;
  3933. X            musthave (NL, 0);
  3934. X            peeksym = NL;
  3935. X        }
  3936. X
  3937. X        default:
  3938. X        return t;
  3939. X    }
  3940. X    }
  3941. X}
  3942. X
  3943. Xstatic C_Op    *nested (type, mark)
  3944. Xint        type, mark;
  3945. X{
  3946. X    register C_Op    *t;
  3947. X
  3948. X    multiline++;
  3949. X    t = c_list (FALSE);
  3950. X    musthave (mark, 0);
  3951. X    multiline--;
  3952. X    return block (type, t, NOBLOCK, NOWORDS);
  3953. X}
  3954. X
  3955. Xstatic C_Op    *command (cf)
  3956. Xint        cf;
  3957. X{
  3958. X    register C_Op    *t;
  3959. X    Word_B        *iosave = iolist;
  3960. X    register int    c;
  3961. X
  3962. X    iolist = (Word_B *)NULL;
  3963. X
  3964. X    if (multiline)
  3965. X    cf |= CONTIN;
  3966. X
  3967. X    while (synio (cf))
  3968. X    cf = 0;
  3969. X
  3970. X    switch (c = yylex (cf)) 
  3971. X    {
  3972. X    default:
  3973. X        peeksym = c;
  3974. X
  3975. X        if ((t = simple ()) == (C_Op *)NULL)
  3976. SHAR_EOF
  3977. echo "End of part 2"
  3978. echo "File shell/sh2.c is continued in part 3"
  3979. echo "3" > s2_seq_.tmp
  3980. exit 0
  3981.  
  3982. -- 
  3983. Regards,
  3984.  
  3985. Ian Stewartson
  3986. Data Logic Ltd.
  3987.  
  3988.