home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / sh.zoo / sh.2 < prev    next >
Encoding:
Text File  |  1990-02-21  |  78.9 KB  |  3,980 lines

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