home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume10
/
sh_dos
/
part03
< prev
next >
Wrap
Text File
|
1990-02-13
|
81KB
|
3,988 lines
Newsgroups: comp.sources.misc
organization: ITM Sector, Data Logic Ltd. (A Raytheon Company)
From: istewart@datlog.co.uk (Ian Stewartson)
subject: v10i055: MSDOS Shell (sh) Implementation - Part 02 of 05
Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Posting-number: Volume 10, Issue 55
Submitted-by: istewart@datlog.co.uk (Ian Stewartson)
Archive-name: sh_dos/part03
#!/bin/sh
# this is part 2 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file lib/ms_dio.c continued
#
CurArch=2
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file lib/ms_dio.c"
sed 's/^X//' << 'SHAR_EOF' >> lib/ms_dio.c
X
X if (FP->drive & HD_FLAG)
X {
X struct partition *pp, tp;
X
X/* System call failed - no device */
X
X if ((iregs.x.cflag) || (ndrive >= iregs.h.dl))
X {
X free (FP);
X errno = ENOENT;
X return -1;
X }
X
X/* OK - save the parameters */
X
X FP->m_cyl = (iregs.h.ch | ((iregs.h.cl & 0x0c0) << 2)) + 2;
X FP->m_head = iregs.h.dh + 1;
X FP->m_sector = iregs.h.cl & 0x03f;
X FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
X
X/* If this is not partition 0 - read the partition table */
X
X if (FP->partition)
X {
X if (dio_do (BIOS_READ, FP, buf, 0L, 1) == -1)
X {
X free (FP);
X return -1;
X }
X
X if (*(int *)&buf[510] != 0xaa55)
X {
X errno = ENOENT;
X return -1;
X }
X
X/* Sort the partition table */
X
X pp = (struct partition *)&buf[0x1be];
X
X for (i = 0; i < 4; i++)
X {
X for (j = 0; j < 3; j++)
X {
X if (((!pp[j].offset) && pp[j + 1].offset) ||
X ((pp[j].offset > pp[j + 1].offset) &&
X pp[j + 1].offset))
X {
X tp = pp[j];
X pp[j] = pp[j + 1];
X pp[j + 1] = tp;
X }
X }
X }
X
X if (pp[FP->partition - 1].offset == 0L)
X {
X errno = ENOENT;
X return -1;
X }
X
X FP->m_start = pp[FP->partition - 1].offset;
X FP->m_scount = pp[FP->partition - 1].size;
X }
X }
X
X/* Floppy disk - get parameters. We try our best here, but DOS 3.3 allows
X * you to format any number of sectors per track and tracks per disk
X */
X
X else
X {
X
X/* System call failed - think this means we're on an XT. So set up the
X * XT parameters
X */
X
X if ((iregs.x.cflag) && (ndrive < 2))
X {
X iregs.h.bl = 0x01;
X FP->m_cyl = 40;
X FP->m_head = 2;
X FP->m_sector = 9;
X }
X
X/* No Drive */
X
X else if ((iregs.x.cflag) || (ndrive >= iregs.h.dl))
X {
X free (FP);
X errno = ENOENT;
X return -1;
X }
X
X/* OK - save the parameters */
X
X else
X {
X FP->m_cyl = iregs.h.ch;
X FP->m_head = iregs.h.dh + 1;
X FP->m_sector = iregs.h.cl;
X }
X
X FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
X
X/* High capacity drive ? */
X
X if ((iregs.h.bl == 0x02) || (iregs.h.bl == 0x03))
X {
X
X/* Try reading sector 0 */
X
X FP->m_sector = (iregs.h.bl == 0x02) ? 9 : 15;
X
X/* If it failed - switch to the other type */
X
X if (dio_do (BIOS_READ, FP, buf, 0L, 1) == -1)
X {
X FP->m_sector = (iregs.h.bl == 0x02) ? 15 : 9;
X
X iregs.h.ah = 0x17;
X iregs.h.dl = (unsigned char)FP->drive;
X iregs.h.al = (unsigned char)(5 - iregs.h.bl);
X int86 (0x13, &iregs, &iregs);
X }
X }
X
X/* 8 or 9 Sectors, 1 or 2 heads */
X
X if (((iregs.h.bl > 0x00) || (iregs.h.bl < 0x04)) &&
X (FP->m_sector == 9))
X {
X FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
X
X/* Check to see if sector 8 exists */
X
X if (dio_do (BIOS_READ, FP, buf, 8L, 1) == -1)
X FP->m_sector = 8;
X
X/* Check to see if sector 380 exists */
X
X if (dio_do (BIOS_READ, FP, buf, 380L, 1) == -1)
X FP->m_head = 1;
X }
X
X/* 720K drive - read sector 15 to see if 1.4M */
X
X else if (iregs.h.bl == 0x04)
X {
X FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
X
X if (dio_do (BIOS_READ, FP, buf, 17L, 1) == -1)
X FP->m_sector = 9;
X }
X
X FP->m_scount = FP->m_cyl * FP->m_head * FP->m_sector;
X }
X
X/* Set up the file descriptor entry and return the number */
X
X MS_io_fs[fp] = FP;
X return fp + MS_MODIFIER;
X }
X
X else
X return open (name, mode, permissions);
X}
X
X/* fstat function */
X
Xint dio_fstat (fp, St)
Xint fp;
Xstruct stat *St;
X{
X struct fs *FP;
X
X if (fp < MS_MODIFIER)
X return fstat (fp, St);
X
X if ((FP = dio_fpcheck (fp)) == (struct fs *)NULL)
X return -1;
X
X/* Dummy values */
X
X memset (St, 0, sizeof (struct stat));
X St->st_mode = 0x61b6;
X St->st_nlink = 1;
X
X if (FP->drive == DRIVE_RAM)
X {
X St->st_size = MEGABYTE;
X St->st_rdev = 0x0300;
X }
X
X else
X {
X St->st_rdev = ((FP->drive & (~HD_FLAG)) * 10 + FP->partition) |
X ((FP->drive & HD_FLAG) ? 0x0200 : 0x0100);
X St->st_dev = FP->drive;
X }
X
X St->st_atime = time ((time_t *)NULL);
X St->st_ctime = St->st_ctime;
X St->st_mtime = St->st_atime;
X return 0;
X}
X
X/*
X * Close function
X */
X
Xint dio_close (fp)
Xint fp;
X{
X struct fs *FP;
X
X if (fp < MS_MODIFIER)
X return close (fp);
X
X if ((FP = dio_fpcheck (fp)) == (struct fs *)NULL)
X return -1;
X
X free (FP);
X MS_io_fs[fp - MS_MODIFIER] = (struct fs *)NULL;
X return 0;
X}
X
X/*
X * Seek function
X */
X
Xlong dio_lseek (fp, off, type)
Xint fp;
Xoff_t off;
Xint type;
X{
X off_t check;
X struct fs *FP;
X
X if (fp < MS_MODIFIER)
X return lseek (fp, off, type);
X
X if ((FP = dio_fpcheck (fp)) == (struct fs *)NULL)
X return -1L;
X
X switch (type)
X {
X case SEEK_SET:
X check = off;
X break;
X
X case SEEK_CUR:
X check = off + FP->location;
X break;
X
X case SEEK_END:
X default:
X errno = EINVAL;
X return -1L;
X }
X
X if (check < 0L)
X {
X errno = EINVAL;
X return -1L;
X }
X
X return (FP->location = check);
X}
X
X/* Check for a valid file pointer */
X
Xstatic struct fs *dio_fpcheck (fp)
Xint fp;
X{
X struct fs *FP;
X
X if (((FP = MS_io_fs[fp - MS_MODIFIER]) == (struct fs *)NULL) ||
X (fp - MS_MODIFIER >= _NFILE) || (fp - MS_MODIFIER < 0))
X {
X errno = EBADF;
X return (struct fs *)NULL;
X }
X
X return FP;
X}
X
X/* Check for a valid file name */
X
Xstatic int dio_fncheck (name)
Xchar *name;
X{
X
X/* Check for hard disk */
X
X if (isdigit(name[7]) && isdigit(name[8]) && (strlen (name) == 9) &&
X (!strnicmp (name, "/dev/hd", 6)))
X {
X int i = atoi (&name[7]);
X
X return ((i % 10) > 4) ? -1 : i | HD_FLAG;
X }
X
X/* Check for floppy disk */
X
X else if (isdigit(name[7]) && (strlen (name) == 8) &&
X (!strnicmp (name, "/dev/fd", 6)))
X return name[7] - '0';
X
X else if (!stricmp (name, "/dev/kmem"))
X return DRIVE_RAM;
X
X return -1;
X}
X
X/* Get file status */
X
Xint dio_stat (name, St)
Xchar *name;
Xstruct stat *St;
X{
X int drive;
X
X if ((drive = dio_fncheck (name)) == -1)
X return stat (name, St);
X
X memset (St, 0, sizeof (struct stat));
X St->st_mode = 0x61b6;
X St->st_nlink = 1;
X St->st_atime = time ((time_t *)NULL);
X St->st_ctime = St->st_ctime;
X St->st_mtime = St->st_atime;
X
X if (drive == DRIVE_RAM)
X {
X St->st_size = MEGABYTE;
X St->st_rdev = 0x0300;
X }
X
X else
X {
X St->st_rdev = (drive & (~HD_FLAG)) | ((drive & HD_FLAG) ? 0x0200
X : 0x0100);
X St->st_dev = drive;
X }
X
X return 0;
X}
X
X/* Check file access */
X
Xint dio_access (name, mode)
Xchar *name;
Xint mode;
X{
X if (dio_fncheck (name) == -1)
X return access (name, mode);
X
X else if (mode & 1)
X {
X errno = EACCES;
X return -1;
X }
X
X return 0;
X}
X
X/* Change file permissions */
X
Xint dio_chmod (name, mode)
Xchar *name;
Xint mode;
X{
X return (dio_fncheck (name) == -1) ? chmod (name, mode) : 0;
X}
X
X/* Create file */
X
Xint dio_creat (name, mode)
Xchar *name;
Xint mode;
X{
X return (dio_fncheck (name) == -1) ? creat (name, mode)
X : dio_open (name, O_WRONLY, mode);
X}
X
X/* Duplicate handler */
X
Xint dio_dup (fp)
Xint fp;
X{
X struct fs *FP; /* New pointer */
X struct fs *FP1; /* Old pointer */
X
X if (fp < MS_MODIFIER)
X return dup (fp);
X
X if ((FP1 = dio_fpcheck (fp)) == (struct fs *)NULL)
X return -1;
X
X for (fp = 0; (fp < _NFILE) && (MS_io_fs[fp] != (struct fs *)NULL); fp++)
X ;
X
X if ((fp == _NFILE) ||
X ((FP = (struct fs *)malloc (sizeof (struct fs))) == (struct fs *)NULL))
X {
X errno = EMFILE;
X return -1;
X }
X
X MS_io_fs[fp] = FP;
X *FP = *FP1;
X return fp;
X}
X
X/* Check if tty */
X
Xint dio_isatty (fp)
Xint fp;
X{
X if (fp < MS_MODIFIER)
X return isatty (fp);
X
X return 0;
X}
X
X/* Tell location */
X
Xlong dio_tell (fp)
Xint fp;
X{
X struct fs *FP;
X
X if (fp < MS_MODIFIER)
X return tell (fp);
X
X return ((FP = dio_fpcheck (fp)) == (struct fs *)NULL) ? -1L : FP->location;
X}
SHAR_EOF
echo "File lib/ms_dio.c is complete"
chmod 0644 lib/ms_dio.c || echo "restore of lib/ms_dio.c fails"
set `wc -c lib/ms_dio.c`;Sum=$1
if test "$Sum" != "17329"
then echo original size 17329, current size $Sum;fi
echo "x - extracting lib/director.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > lib/director.c &&
X/*
X * @(#)msd_dir.c 1.4 87/11/06 Public Domain.
X *
X * A public domain implementation of BSD directory routines for
X * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
X * August 1897
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <malloc.h>
X#include <string.h>
X#include <limits.h>
X#include <errno.h>
X#include <dirent.h>
X#include <dos.h>
X
X#define ATTRIBUTES (_A_SUBDIR | _A_HIDDEN | _A_SYSTEM | \
X _A_NORMAL | _A_RDONLY | _A_ARCH | _A_VOLID)
X
Xstatic void free_dircontents (struct _dircontents *);
X
XDIR *opendir(name)
Xchar *name;
X{
X struct stat statb;
X DIR *dirp;
X char c;
X struct _dircontents *dp;
X char nbuf[PATH_MAX + NAME_MAX + 2];
X struct find_t dtabuf;
X
X if (stat (name, &statb) < 0)
X return (DIR *) NULL;
X
X if (!S_ISDIR(statb.st_mode))
X {
X errno = ENOTDIR;
X return (DIR *)NULL;
X }
X
X if ((dirp = (DIR *) malloc (sizeof (DIR))) == (DIR *) NULL)
X return (DIR *) NULL;
X
X if (*name && (c = name[strlen (name) - 1]) != '\\' && c != '/')
X (void) strcat (strcpy (nbuf, name), "\\*.*");
X
X else
X (void) strcat (strcpy (nbuf, name), "*.*");
X
X dirp->dd_loc = 0;
X dirp->dd_cp = (struct _dircontents *) NULL;
X dirp->dd_contents = (struct _dircontents *) NULL;
X
X if (_dos_findfirst (nbuf, ATTRIBUTES, &dtabuf) != 0)
X return dirp;
X
X do
X {
X if (((dp = (struct _dircontents *) malloc(sizeof(struct _dircontents))) == (struct _dircontents *) NULL) ||
X ((dp->_d_entry = strdup (dtabuf.name)) == (char *) NULL))
X {
X if (dp != (char *)NULL)
X free ((char *) dp);
X
X free_dircontents (dirp->dd_contents);
X return (DIR *) NULL;
X }
X
X if (dirp->dd_contents)
X dirp->dd_cp = dirp->dd_cp->_d_next = dp;
X
X else
X dirp->dd_contents = dirp->dd_cp = dp;
X
X dp->_d_next = (struct _dircontents *) NULL;
X
X } while (_dos_findnext (&dtabuf) == 0);
X
X dirp->dd_cp = dirp->dd_contents;
X
X return dirp;
X}
X
Xint closedir(dirp)
XDIR *dirp;
X{
X free_dircontents (dirp->dd_contents);
X free ((char *) dirp);
X return 0;
X}
X
Xstruct dirent *readdir(dirp)
XDIR *dirp;
X{
X static struct dirent dp;
X
X if (dirp->dd_cp == (struct _dircontents *) NULL)
X return (struct dirent *) NULL;
X
X dp.d_reclen = strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
X dp.d_off = dirp->dd_loc * 32;
X dp.d_ino = (ino_t)++dirp->dd_loc;
X dirp->dd_cp = dirp->dd_cp->_d_next;
X strlwr (dp.d_name);
X
X return &dp;
X}
X
Xvoid rewinddir (dirp)
XDIR *dirp;
X{
X seekdir (dirp, (off_t)0);
X}
X
Xvoid seekdir (dirp, off)
XDIR *dirp;
Xoff_t off;
X{
X long i = off;
X struct _dircontents *dp;
X
X if (off < 0L)
X return;
X
X for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next)
X ;
X
X dirp->dd_loc = off - (i + 1);
X dirp->dd_cp = dp;
X}
X
Xoff_t telldir(dirp)
XDIR *dirp;
X{
X return dirp->dd_loc;
X}
X
Xstatic void free_dircontents(dp)
Xstruct _dircontents *dp;
X{
X struct _dircontents *odp;
X
X while (dp)
X {
X if (dp->_d_entry)
X free(dp->_d_entry);
X
X dp = (odp = dp)->_d_next;
X free((char *) odp);
X }
X}
SHAR_EOF
chmod 0644 lib/director.c || echo "restore of lib/director.c fails"
set `wc -c lib/director.c`;Sum=$1
if test "$Sum" != "3067"
then echo original size 3067, current size $Sum;fi
echo "x - extracting lib/popen.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > lib/popen.c &&
X/*
X * popen/pclose: simple MS-DOS piping scheme to imitate UNIX pipes
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <string.h>
X#include <errno.h>
X#include <process.h>
X#include <limits.h>
X#include <stdlib.h>
X#include <unistd.h>
X
Xtypedef struct pipes {
X FILE *p_fp; /* File id */
X char *p_process; /* Program name */
X char *p_file; /* Pipe file name */
X int p_status; /* Status for close to return */
X /* Read pipes only */
X bool p_write; /* Read or write */
X} PIPE;
X
Xstatic PIPE P_list[_NFILE]; /* The pipe structures */
Xstatic int Pipes_Inited = 0; /* Initialised ? */
Xstatic int Unique_Pipe = 0;
X
Xstatic PIPE *_p_save_entry (char *, bool);
Xstatic int _p_run (char *);
Xstatic int _p_reset_entry (PIPE *, int);
Xstatic PIPE *_p_get_entry (FILE *);
X
X/* Set up a pipe structure */
X
Xstatic PIPE *_p_save_entry (prog, mode)
Xchar *prog;
Xbool mode;
X{
X FILE *fp; /* File handler */
X PIPE *pp; /* Pipe handler structure */
X char tmpfile[NAME_MAX + PATH_MAX + 2];
X char *tmpdir; /* Points to directory prefix of pipe */
X
X/* Find out where we should put temporary files */
X
X if ((tmpdir = getenv ("TMPDIR")) == (char *) NULL)
X tmpdir = getenv ("TMP");
X
X/* Use temporary directory if available */
X
X if (tmpdir == (char *)NULL)
X tmpdir = ".";
X
X/* Get a unique pipe file name */
X
X sprintf (tmpfile, "%s/pipe%05d.tmp", tmpdir, Unique_Pipe++);
X unlink (tmpfile);
X
X/* Create the pipe */
X
X if ((fp = fopen (tmpfile, "w")) == (FILE *) NULL)
X return (PIPE *)NULL;
X
X/* Create the PIPE entry */
X
X if ((pp = _p_get_entry ((FILE *)NULL)) == (PIPE *)NULL)
X {
X fclose (fp);
X unlink (tmpfile);
X errno = EMFILE;
X return (PIPE *)NULL;
X }
X
X/* Set up the entry */
X
X pp->p_fp = fp;
X pp->p_write = mode;
X pp->p_process = strdup (prog);
X pp->p_file = strdup (tmpfile);
X
X/* Check for errors */
X
X if ((pp->p_process == (char *)NULL) || (pp->p_file == (char *)NULL))
X {
X _p_reset_entry (pp, 1);
X errno = ENOMEM;
X return (FILE *)NULL;
X }
X
X return pp;
X}
X
X/* Execute command via SHELL or COMSPEC */
X
Xstatic int _p_run (command)
Xchar *command;
X{
X char *shell; /* Command processor */
X char *shellpath; /* Full command processor path */
X char *bp; /* Generic string pointer */
X char *dash = "/c";
X
X/* Determine the command processor */
X
X if (((shell = getenv ("SHELL")) == (char *) NULL) &&
X ((shell = getenv ("COMSPEC")) == (char *) NULL))
X shell = "command.com";
X
X shellpath = strlwr (shell);
X
X/* Strip off any leading backslash directories */
X
X if ((shell = strrchr (shellpath, '\\')) != (char *)NULL)
X ++shell;
X
X else
X shell = shellpath;
X
X/* Strip off any leading slash directories */
X
X if ((bp = strrchr (shell, '/')) != (char *)NULL)
X shell = ++bp;
X
X if (strcmp (shell, "command.com"))
X *dash = '-';
X
X/* Run the program */
X
X return spawnl (P_WAIT, shellpath, shell, dash, command, (char *) NULL);
X}
X
X/* resetpipe: Private routine to cancel a pipe */
X
Xstatic int _p_reset_entry (pp, mode)
XPIPE *pp;
Xint mode;
X{
X int result = (!mode) ? 0 : -1;
X int serrno = errno;
X
X/* Close the pipe */
X
X fclose (pp->p_fp);
X
X/* Free up memory */
X
X if (pp->p_file != (char *)NULL)
X {
X result = unlink (pp->p_file);
X
X if (!mode)
X serrno = errno;
X
X else
X result = -1;
X
X free (pp->p_file);
X }
X
X if (pp->p_process != (char *)NULL)
X free (pp->p_process);
X
X memset (pp, 0, sizeof (PIPE));
X
X/* Return error code */
X
X errno = serrno;
X return result;
X}
X
X/* Find a free entry */
X
Xstatic PIPE *_p_get_entry (fp)
XFILE *fp;
X{
X int i;
X
X for (i = 0; i < _NFILE; i++)
X {
X if (P_list[i].p_fp == fp)
X return &P_list[i];
X }
X
X return (PIPE *)NULL;
X}
X
X
X/* popen: open a pipe */
X
XFILE *popen (command, type)
Xchar *command; /* The command to be run */
Xchar *type; /* "w" or "r" */
X{
X int old_stdout;
X PIPE *pp;
X
X/* Initialise the pipe structure */
X
X if (!Pipes_Inited)
X {
X memset (&P_list[0], 0, sizeof (P_list));
X Pipes_Inited = 1;
X }
X
X/* For write style pipe, pclose handles program execution */
X
X if (strcmp (type, "w") == 0)
X return ((pp = _p_save_entry (command, TRUE)) == (PIPE *)NULL)
X ? (FILE *)NULL : pp->p_fp;
X
X/* read pipe must create tmp file, set up stdout to point to the temp
X * file, and run the program. note that if the pipe file cannot be
X * opened, it'll return a condition indicating pipe failure, which is
X * fine.
X */
X
X else if (strcmp (type, "r") == 0)
X {
X if ((pp = _p_save_entry (command, FALSE)) == (PIPE *)NULL)
X return (FILE *)NULL;
X
X/* Save the stdout file descriptor, dup the pipe onto standard out,
X * execute the command, close the pipe and re-open it
X */
X
X if ((old_stdout = dup (fileno(stdout)) < 0) ||
X (dup2 (fileno (pp->p_fp), fileno(stdout)) < 0) ||
X ((pp->p_status = _p_run (command)) < 0) ||
X (fclose (pp->p_fp) < 0) ||
X (dup2 (old_stdout, fileno (stdout)) < 0) ||
X ((pp->p_fp = fopen (pp->p_file, "r")) == (FILE *)NULL))
X {
X _p_reset_entry (pp, 1);
X return (FILE *)NULL;
X }
X
X else
X return pp->p_fp;
X }
X
X/* screwy call or unsupported type */
X
X errno = EINVAL;
X return (FILE *)NULL;
X}
X
X/* close a pipe */
X
Xint pclose (fp)
XFILE *fp;
X{
X PIPE *pp; /* Current pipe structure */
X int old_stdin; /* Where our stdin points now */
X
X if ((pp = _p_get_entry (fp)) == (PIPE *)NULL)
X {
X errno = EBADF;
X return -1;
X }
X
X if (fclose (pp->p_fp) < 0)
X return _p_reset_entry (pp, 1);
X
X/* Open the pipe in read mode, Save stdin file descriptor, copy pipe file
X * descriptor to stdin, execute the command, and then restore stdin
X */
X
X if (pp->p_write &&
X ( ((pp->p_fp = fopen (pp->p_file, "r")) == (FILE *)NULL) ||
X ((old_stdin = dup (fileno (stdin))) < 0) ||
X (dup2 (fileno (pp->p_fp), fileno (stdin)) < 0) ||
X ((pp->p_status = _p_run (pp->p_process)) < 0) ||
X (fclose (pp->p_fp) < 0) ||
X (dup2 (old_stdin, fileno (stdin)) < 0)
X ))
X return _p_reset_entry (pp, 1);
X
X/* Close the temp file and remove it */
X
X return _p_reset_entry (pp, 0);
X}
SHAR_EOF
chmod 0644 lib/popen.c || echo "restore of lib/popen.c fails"
set `wc -c lib/popen.c`;Sum=$1
if test "$Sum" != "6060"
then echo original size 6060, current size $Sum;fi
echo "x - extracting lib/syserr.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > lib/syserr.c &&
X/* perror(s) print the current error message. */
X
Xchar *sys_errlist[] = {
X "Error 0 ",
X "Operation not permitted",
X "No such file or directory",
X "No such process",
X "Interrupted system call",
X "I/O error",
X "No such device or address",
X "Arg list too long",
X "Exec format error",
X "Bad file number",
X "No children",
X "No more processes",
X "Not enough core",
X "Permission denied",
X "Bad address",
X "Block device required",
X "Mount device busy",
X "File exists",
X "Cross-device link",
X "No such device",
X "Not a directory",
X "Is a directory",
X "Invalid argument",
X "File table overflow",
X "Too many open files",
X "Not a typewriter",
X "Text file busy",
X "File too large",
X "No space left on device",
X#define ESPIPE 29
X "Illegal seek",
X "Read-only file system",
X "Too many links",
X
X "Broken pipe",
X "Math argument",
X "Result too large",
X "EUCLEAN",
X "No message of desired type",
X "Resource deadlock would occur"
X "Unknown error"
X};
X
Xint sys_nerr = sizeof(sys_errlist)/sizeof(char *) - 1;
SHAR_EOF
chmod 0644 lib/syserr.c || echo "restore of lib/syserr.c fails"
set `wc -c lib/syserr.c`;Sum=$1
if test "$Sum" != "1106"
then echo original size 1106, current size $Sum;fi
echo "x - extracting lib/stdargv.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > lib/stdargv.c &&
X/*
X * MODULE NAME: expand.c Revision: 1.0
X *
X * AUTHOR: Ian Stewartson
X *
X * LOCATION: Data Logic,
X * Greenford,
X * Middlesex,
X * England.
X *
X#include <logo.h>
X * MODULE DEFINITION: This function expandes the command line parameters
X * in a UNIX like manner. Wild character *?[] are
X * allowed in file names. @filename causes command lines
X * to be read from filename. Strings between " or ' are
X * not expanded. All entries in the array are malloced.
X *
X * This function replaces the standard MS-DOS command
X * line processing function (_setargv in stdargv.obj).
X *
X * CALLING SEQUENCE: The following calling sequences are used:
X *
X * void _setargv ();
X *
X * ERROR MESSAGES: Out of memory
X *
X * INCLUDE FILES:
X */
X
X#include <sys/types.h> /* MS-DOS type definitions */
X#include <sys/stat.h> /* File status definitions */
X#include <stdio.h> /* Standard I/O delarations */
X#include <stdlib.h> /* Standard library functions */
X#include <errno.h> /* Error number declarations */
X#include <dos.h> /* DOS functions declarations */
X#include <bios.h> /* BIOS functions declarations */
X#include <ctype.h> /* Character type declarations */
X#include <string.h> /* String library functions */
X#include <limits.h> /* String library functions */
X#include <fcntl.h> /* File Control Declarations */
X#include <io.h> /* Input/Output Declarations */
X#include <dirent.h> /* Direction I/O functions */
X
X/*
X * DATA DEFINITIONS:
X */
X
X#define MAX_LINE 160 /* Max line length */
X#define S_ENTRY sizeof (char *)
X
X/*
X * DATA DECLARATIONS:
X */
X#ifdef MSDOS
X
Xextern void _setargv (void);
Xstatic void exp_line (char *); /* Expand file */
Xstatic int ex_pfield (char *, char *); /* Expand field */
Xstatic void ex_pfile (char *);
Xstatic char *ex_gspace (int, char *); /* Get space */
Xstatic void ex_add_arg (char *); /* Add argument */
Xstatic char *ex_skip_sp (char *); /* Skip spaces */
Xstatic char *ex_tounix (char *); /* Convert name to Unix format */
Xstatic int ex_find (char*, int); /* Split file name */
Xstatic void ex_fatal (int, char *, char *); /* Fatal error processing*/
Xstatic char *ex_environment (char *); /* Process environment */
Xstatic char *_ex_multi_drive (char *); /* Check for multidrive */
Xstatic char *ex_nomem = "%s: %s\n";
X
Xextern char far *_pgmptr; /* Program name */
Xextern char **__argv; /* Current argument address */
Xextern int __argc; /* Current argument count */
X
X/*
X * MODULE ABSTRACT: _setargv
X *
X * UNIX like command line expansion
X */
X
Xvoid _setargv ()
X{
X /* Set up pointer to command line */
X char far *argvp = (char far *)((((long)_psp) << 16) + 0x081L);
X unsigned int envs = *(int far *)((((long)_psp) << 16) + 0x02cL);
X char far *s; /* Temporary string pointer */
X#ifndef M_I86LM
X char buf[MAX_LINE]; /* Temporary space */
X char *cp;
X#endif
X
X/* Command line can be null or 0x0d terminated - convert to null */
X
X s = argvp;
X
X while (*s && (*s != 0x0d))
X ++s;
X
X if (*s == 0x0d)
X *s = 0;
X
X/* Set up global parameters and expand */
X
X __argc = 0;
X
X/* Get the program name */
X
X if (_osmajor <= 2)
X s = "unknown";
X
X/* In the case of DOS 3+, we look in the environment space */
X
X else
X {
X s = (char far *)(((long)envs) << 16);
X
X while (*s)
X {
X while (*(s++) != 0);
X }
X
X s += 3;
X }
X
X _pgmptr = s;
X
X#ifndef M_I86LM
X cp = buf;
X while (*(cp++) = *(s++));
X
X ex_add_arg (ex_tounix (buf)); /* Add the program name */
X
X s = argvp;
X cp = buf;
X while (*(cp++) = *(s++));
X
X exp_line (buf);
X#else
X ex_add_arg (ex_tounix (s)); /* Add the program name */
X exp_line (argvp);
X#endif
X
X ex_add_arg ((char *)NULL);
X --__argc;
X}
X
X/*
X * Expand a line
X */
X
Xstatic void exp_line (argvp)
Xchar *argvp; /* Line to expand */
X{
X char *spos; /* End of string pointer */
X char *cpos; /* Start of string pointer */
X char *fn; /* Extracted file name string */
X
X/* Search for next separator */
X
X spos = argvp;
X
X while (*(cpos = ex_skip_sp (spos)))
X {
X
X/* Extract string argument */
X
X if ((*cpos == '"') || (*cpos == '\''))
X {
X spos = cpos + 1;
X
X do
X {
X if ((spos = strchr (spos, *cpos)) != NULL)
X {
X spos++;
X if (spos[-2] != '\\')
X break;
X }
X
X else
X spos = &spos[strlen (cpos)];
X
X }
X while (*spos);
X
X fn = ex_gspace (spos - cpos - 2, cpos + 1);
X }
X
X/* Extract normal argument */
X
X else
X {
X spos = cpos;
X while (!isspace(*spos) && *spos)
X spos++;
X
X fn = ex_gspace (spos - cpos, cpos);
X }
X
X/* Process argument */
X
X if (*cpos != '"')
X fn = ex_environment (fn);
X
X switch (*cpos)
X {
X case '@': /* Expand file */
X ex_pfile (fn);
X break;
X
X case '"': /* Expand string */
X case '\'':
X ex_add_arg (fn);
X break;
X
X default: /* Expand field */
X if (!ex_find (fn, 0))
X ex_add_arg (fn);
X }
X
X free (fn);
X }
X}
X
X/* Expand a field if it has metacharacters in it */
X
Xstatic int ex_pfield (prefix, postfix)
Xchar *prefix; /* Prefix field */
Xchar *postfix; /* Postfix field */
X{
X int count; /* File path length */
X int f_count = 0; /* Number of files generated */
X int slash_flag = 0; /* slash required */
X char fn[PATH_MAX + NAME_MAX + 2];/* Search file name */
X char *name; /* Match string */
X char *p, *p1;
X DIR *dp;
X struct dirent *c_de;
X unsigned int c_drive; /* Current drive */
X unsigned int m_drive; /* Max drive */
X unsigned int s_drive; /* Selected drive */
X unsigned int x_drive, y_drive; /* Dummies */
X char *multi; /* Multi-drive flag */
X char t_drive[2];
X
X/* Convert file name to lower case */
X
X strlwr (prefix);
X
X/* Search all drives ? */
X
X if ((multi = _ex_multi_drive (prefix)) != (char *)NULL)
X {
X _dos_getdrive (&c_drive); /* Get number of drives */
X _dos_setdrive (c_drive, &m_drive);
X t_drive[1] = 0;
X
X for (s_drive = 1; s_drive <= m_drive; ++s_drive)
X {
X _dos_setdrive (s_drive, &x_drive);
X _dos_getdrive (&y_drive);
X _dos_setdrive (c_drive, &x_drive);
X
X/* Check to see if the second diskette drive is really there */
X
X if (((_bios_equiplist () & 0x00c0) == 0x0000) && (s_drive == 2))
X continue;
X
X/* If the drive exists and is in our list - process it */
X
X *multi = 0;
X *t_drive = (char)(s_drive + 'a' - 1);
X
X if ((y_drive == s_drive) && pnmatch (t_drive, prefix, 0))
X {
X *multi = ':';
X *fn = *t_drive;
X strcpy (fn + 1, multi);
X f_count += ex_pfield (fn, postfix);
X }
X
X *multi = ':';
X }
X
X return f_count;
X }
X
X/* Get the path length */
X
X p = strrchr (prefix, '/');
X p1 = strchr (prefix, ':');
X
X if ((p1 == (char *)NULL) || (p1 < p))
X {
X if (p == (char *)NULL)
X {
X count = 0;
X name = prefix;
X }
X
X else
X {
X count = p - prefix;
X name = p + 1;
X }
X }
X
X else if ((p == (char *)NULL) || (p < p1))
X {
X count = p1 - prefix;
X name = p1 + 1;
X }
X
X/* Set up file name for search */
X
X if (((count == 2) && (strncmp (prefix + 1, ":/", 2) == 0)) ||
X ((count == 0) && (*prefix == '/')))
X {
X strncpy (fn, prefix, ++count);
X fn[count] = 0;
X strcat (fn, ".");
X }
X
X else
X {
X if ((count == 1) && (*(prefix + 1) == ':'))
X count++;
X
X strncpy (fn, prefix, count);
X fn[count] = 0;
X
X if (((count == 2) && (*(prefix + 1) == ':')) || (count == 0))
X strcat (fn, ".");
X
X else
X slash_flag = 1;
X }
X
X/* Search for file names */
X
X if ((dp = opendir (fn)) == (DIR *)NULL)
X return 0;
X
X/* Are there any matches */
X
X while ((c_de = readdir (dp)) != (struct dirent *)NULL)
X {
X if ((*c_de->d_name == '.') && (*name != '.'))
X continue;
X
X/* Check for match */
X
X if (pnmatch (c_de->d_name, name, 0))
X {
X fn[count] = 0;
X
X if (slash_flag)
X strcat (fn, "/");
X
X strcat (fn, c_de->d_name);
X
X/* If the postfix is not null, this must be a directory */
X
X if (postfix != (char *)NULL)
X {
X struct stat statb;
X
X if (stat (fn, &statb) < 0 ||
X (statb.st_mode & S_IFMT) != S_IFDIR)
X continue;
X
X strcat (fn, "/");
X strcat (fn, postfix);
X }
X
X f_count += ex_find (fn, 1);
X }
X }
X
X closedir (dp);
X return f_count;
X}
X
X/* Expand file name */
X
Xstatic void ex_pfile (file)
Xchar *file; /* Expand file name */
X{
X FILE *fp; /* File descriptor */
X char *p; /* Pointer */
X int c_maxlen = MAX_LINE;
X char *line; /* Line buffer */
X
X/* Grab some memory for the line */
X
X if ((line = malloc (c_maxlen)) == (char *)NULL)
X ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
X
X/* If file open fails, expand as a field */
X
X if ((fp = fopen (file + 1, "rt")) == NULL)
X {
X if (!ex_find (file, 0))
X ex_add_arg (file);
X
X return;
X }
X
X/* For each line in the file, remove EOF characters and add argument */
X
X while (fgets (line, c_maxlen, fp) != (char *)NULL)
X {
X while ((p = strchr (line, '\n')) == (char *)NULL)
X {
X if ((p = strchr (line, 0x1a)) != (char *)NULL)
X break;
X
X if ((line = realloc (line, c_maxlen + MAX_LINE)) == (char *)NULL)
X ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
X
X if (fgets (&line[c_maxlen - 1], MAX_LINE, fp) == (char *)NULL)
X break;
X
X c_maxlen += MAX_LINE - 1;
X }
X
X if (p != (char *)NULL)
X *p = 0;
X
X ex_add_arg (line);
X }
X
X if (ferror(fp))
X ex_fatal (errno, "%s: %s (%s)\n", file + 1);
X
X free (line);
X fclose (fp);
X}
X
X/* Get space for name */
X
Xstatic char *ex_gspace (l, in_s)
Xint l; /* String length */
Xchar *in_s; /* String address */
X{
X char *out_s; /* Malloced space address */
X
X if ((out_s = malloc (l + 1)) == (char *)NULL)
X ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
X
X/* Copy string for specified length */
X
X strncpy (out_s, in_s, l);
X out_s[l] = 0;
X
X return (out_s);
X}
X
X/* Append an argument to the string */
X
Xstatic void ex_add_arg (fn)
Xchar *fn; /* Argument to add */
X{
X if (__argc == 0)
X __argv = (char **)malloc (50 * S_ENTRY);
X
X else if ((__argc % 50) == 0)
X __argv = (char **)realloc (__argv, (__argc + 50) * S_ENTRY);
X
X if (__argv == (char **)NULL)
X ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
X
X __argv[__argc++] = (fn == (char *)NULL) ? fn : ex_gspace (strlen (fn), fn);
X}
X
X/* Skip over spaces */
X
Xstatic char *ex_skip_sp (a)
Xchar *a; /* String start address */
X{
X while (isspace(*a))
X a++;
X
X return (a);
X}
X
X/* Convert name to Unix format */
X
Xstatic char *ex_tounix (a)
Xchar *a;
X{
X char *sp = a;
X
X while ((a = strchr (a, '\\')) != (char *)NULL)
X *(a++) = '/';
X
X return strlwr (sp);
X}
X
X/* Find the location of meta-characters. If no meta, add the argument and
X * return NULL. If meta characters, return position of end of directory
X * name. If not multiple directories, return -1
X */
X
Xstatic int ex_find (file, must_exist)
Xchar *file;
Xint must_exist; /* FIle must exist flag */
X{
X char *p;
X int i;
X static char ex_meta[] = "?*[]\\"; /* Metacharacters */
X
X if ((p = strpbrk (file, ex_meta)) == (char *)NULL)
X {
X if (must_exist && (access (file, 0) < 0))
X return 0;
X
X ex_add_arg (file);
X return 1;
X }
X
X else if ((p = strchr (p, '/')) != (char *)NULL)
X *(p++) = 0;
X
X i = ex_pfield (file, p);
X
X if (p != (char *)NULL)
X *(--p) = '/';
X
X return i;
X}
X
X/* Fatal errors */
X
Xstatic void ex_fatal (ecode, format, para)
Xint ecode;
Xchar *format;
Xchar *para;
X{
X fprintf (stderr, format, "stdargv", strerror (ecode), para);
X exit (1);
X}
X
X/* Process Environment - note that field is a malloc'ed field */
X
Xstatic char *ex_environment (field)
Xchar *field;
X{
X char *sp, *cp, *np, *ep;
X char save;
X int b_flag;
X
X sp = field;
X
X/* Replace any $ strings */
X
X while ((sp = strchr (sp, '$')) != (char *)NULL)
X {
X if (*(cp = ++sp) == '{')
X {
X b_flag = 1;
X ++cp;
X
X while (*cp && (*cp != '}'))
X cp++;
X }
X
X else
X {
X b_flag;
X
X while (isalnum(*cp))
X cp++;
X }
X
X/* Grab the environment variable */
X
X if (cp == sp)
X continue;
X
X save = *cp;
X *cp = 0;
X ep = getenv (sp + b_flag);
X *cp = save;
X
X if (ep != (char *)NULL)
X {
X np = ex_gspace (strlen(field) - (cp - sp) + strlen (ep) - 1, field);
X strcpy (&np[sp - field - 1], ep);
X ex_tounix (&np[sp - field - 1]);
X free (field);
X strcpy ((sp = &np[strlen(np)]), cp + b_flag);
X field = np;
X }
X }
X
X return field;
X}
X
X/* Check for multi_drive prefix */
X
Xstatic char *_ex_multi_drive (prefix)
Xchar *prefix;
X{
X if (strlen (prefix) < 2)
X return (char *)NULL;
X
X if (((*prefix == '*') || (*prefix == '?')) && (prefix[1] == ':'))
X return prefix + 1;
X
X if (*prefix != '[')
X return (char *)NULL;
X
X while (*prefix && (*prefix != ']'))
X {
X if ((*prefix == '\\') && (*(prefix + 1)))
X ++prefix;
X
X ++prefix;
X }
X
X return (*prefix && (*(prefix + 1) == ':')) ? prefix + 1 : (char *)NULL;
X}
X#endif
SHAR_EOF
chmod 0644 lib/stdargv.c || echo "restore of lib/stdargv.c fails"
set `wc -c lib/stdargv.c`;Sum=$1
if test "$Sum" != "12922"
then echo original size 12922, current size $Sum;fi
echo "x - extracting lib/pnmatch.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > lib/pnmatch.c &&
X#include <stdlib.h>
X
X/* File name pattern matching function */
X
Xint pnmatch (string, pattern, flag)
Xchar *string; /* String to match */
Xchar *pattern; /* Pattern to match against */
Xint flag; /* Match using '$' & '^' */
X{
X register int cur_s; /* Current string character */
X register int cur_p; /* Current pattern character */
X
X/* Match $ and ^ ? */
X
X if (flag == 1)
X {
X while (*string)
X {
X if (pnmatch (string++, pattern, ++flag))
X return 1;
X }
X
X return 0;
X }
X
X/* Match string */
X
X while (cur_p = *(pattern++))
X {
X cur_s = *(string++); /* Load current string character */
X
X switch (cur_p) /* Switch on pattern character */
X {
X case '^': /* Match start of string */
X {
X if (flag == 2)
X string--;
X
X else if ((flag) || (cur_p != cur_s))
X return 0;
X
X break;
X }
X
X case '$': /* Match end of string */
X {
X if (!flag)
X {
X if (cur_p != cur_s)
X return 0;
X
X break;
X }
X
X else
X return ((cur_s) ? 0 : 1);
X }
X
X case '[': /* Match class of characters */
X {
X while(1)
X {
X if (!(cur_p = *(pattern++)))
X return 0;
X
X if (cur_p == ']')
X return 0;
X
X if (cur_s != cur_p)
X {
X if (*pattern == '-')
X {
X if(cur_p > cur_s)
X continue;
X
X if (cur_s > *(++pattern))
X continue;
X }
X else
X continue;
X }
X
X break;
X }
X
X while (*pattern)
X {
X if (*(pattern++) == ']')
X break;
X }
X }
X
X case '?': /* Match any character */
X {
X if (!cur_s)
X return 0;
X
X break;
X }
X
X case '*': /* Match any number of any character*/
X {
X string--;
X
X do
X {
X if (pnmatch (string, pattern, 0))
X return 1;
X }
X while (*(string++));
X
X return 0;
X }
X
X case '\\': /* Next character is non-meta */
X {
X if (!(cur_p = *(pattern++)))
X return 0;
X }
X
X default: /* Match against current pattern */
X {
X if (cur_p != cur_s)
X return 0;
X
X break;
X }
X }
X }
X
X return ((flag || (!(*string))) ? 1 : 0);
X}
SHAR_EOF
chmod 0644 lib/pnmatch.c || echo "restore of lib/pnmatch.c fails"
set `wc -c lib/pnmatch.c`;Sum=$1
if test "$Sum" != "2985"
then echo original size 2985, current size $Sum;fi
echo "x - extracting lib/getopt.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > lib/getopt.c &&
X/*
X * MODULE NAME: getopt.c Revision 1.0
X *
X * AUTHOR: I. Stewartson
X * Data Logic Ltd.,
X * Queens House,
X * Greenhill Way,
X * Harrow,
X * Middlesex HA1 1YR.
X * Telephone: London (01) 863 0383
X *
X#include <logo.h>
X * MODULE DESCRIPTION: This function is based on the UNIX library function.
X * getopt return the next option letter in argv that
X * matches a letter in opstring. optstring is a string
X * of recognised option letters; if a letter is followed
X * by a colon, the option is expected to have an argument
X * that may or may not be separated from it by white
X * space. optarg is set to point to the start of the
X * option argument on return from getopt.
X *
X * getopt places in optind the argv index of the next
X * argument to be processed. Because optind is external,
X * it is normally initialised to zero automatically before
X * the first call to getopt.
X *
X * When all options have been processed (i.e. up to the
X * first non-option argument), getopt returns EOF. The
X * special option -- may be used to delimit the end of
X * the options; EOF will be returned, and -- will be
X * skipped.
X *
X * getopt prints an error message on stderr and returns a
X * question mark (?) when it encounters an option letter
X * not included in optstring. This error message may be
X * disabled by setting opterr to a non-zero value.
X *
X * CALLING SEQUENCE: The following calling sequences are used:
X *
X * int getopt(argc, argv, optstring)
X * int argc;
X * char **argv;
X * char *optstring;
X *
X * ERROR MESSAGES:
X * %s: illegal option -- %c
X * %s: option requires an argument -- %c
X *
X * INCLUDE FILES:
X */
X
X#include <stdio.h> /* Standard Input/Output */
X#include <string.h> /* String function declarations */
X#include <stdlib.h> /* Standard library declarations*/
X
X/*
X * DATA DECLARATIONS:
X */
X
Xint opterr = 0;
Xint optind = 1;
Xint optopt;
Xint optvar = 0;
Xchar *optarg;
X
Xstatic char *errmes1 = "%s: illegal option -- %c\n";
Xstatic char *errmes2 = "%s: option requires an argument -- %c\n";
X
X/*
X * MODULE ABSTRACT:
X *
X * EXECUTABLE CODE:
X */
X
Xint getopt(argc, argv, optstring)
Xint argc; /* Argument count */
Xchar **argv; /* Argument string vector */
Xchar *optstring; /* Valid options */
X{
X static int string_off = 1; /* Current position */
X int cur_option; /* Current option */
X char *cp; /* Character pointer */
X
X if (string_off == 1)
X {
X if ((optind >= argc) || (argv[optind][0] != '-') || (!argv[optind][1]))
X return (EOF);
X
X else if (!strcmp(argv[optind], "--"))
X {
X optind++;
X return (EOF);
X }
X }
X
X/* Get the current character from the current argument vector */
X
X optopt = cur_option = argv[optind][string_off];
X
X/* Validate it */
X
X if ((cur_option == ':') || ((cur_option == '*') && optvar) ||
X ((cp = strchr(optstring, cur_option)) == (char *)NULL))
X {
X if (opterr)
X fprintf(stderr, errmes1, cur_option, argv[0]);
X
X if (!argv[optind][++string_off])
X {
X optind++;
X string_off = 1;
X }
X
X return ('?');
X }
X
X/* Parameters following ? */
X
X if (*(++cp) == ':')
X {
X if (argv[optind][string_off + 1])
X optarg = &argv[optind++][string_off + 1];
X
X else if (++optind >= argc)
X {
X if (opterr)
X fprintf(stderr, errmes2, cur_option, argv[0]);
X
X string_off = 1;
X return ('?');
X }
X
X else
X optarg = argv[optind++];
X
X string_off = 1;
X }
X
X else if ((*cp == '*') && optvar)
X {
X if (argv[optind][string_off + 1] != 0)
X optarg = &argv[optind++][string_off + 1];
X else
X {
X optarg = "";
X optind++;
X string_off = 1;
X }
X }
X
X else
X {
X if (!argv[optind][++string_off])
X {
X string_off = 1;
X optind++;
X }
X
X optarg = (char *)NULL;
X }
X
X return (cur_option);
X}
SHAR_EOF
chmod 0644 lib/getopt.c || echo "restore of lib/getopt.c fails"
set `wc -c lib/getopt.c`;Sum=$1
if test "$Sum" != "3853"
then echo original size 3853, current size $Sum;fi
echo "x - extracting scripts/l (Text)"
sed 's/^X//' << 'SHAR_EOF' > scripts/l &&
X#!sh
Xls -C $*
SHAR_EOF
chmod 0644 scripts/l || echo "restore of scripts/l fails"
set `wc -c scripts/l`;Sum=$1
if test "$Sum" != "14"
then echo original size 14, current size $Sum;fi
echo "x - extracting scripts/extend.lst (Text)"
sed 's/^X//' << 'SHAR_EOF' > scripts/extend.lst &&
XLIB.EXE
XLINK.EXE
Xsh.exe
SHAR_EOF
chmod 0644 scripts/extend.lst || echo "restore of scripts/extend.lst fails"
set `wc -c scripts/extend.lst`;Sum=$1
if test "$Sum" != "24"
then echo original size 24, current size $Sum;fi
echo "x - extracting scripts/profile.sh (Text)"
sed 's/^X//' << 'SHAR_EOF' > scripts/profile.sh &&
X#!sh
XPATH=".;..;c:/oracle5/bin;c:/bin;c:/dos;c:/scm;c:/windows"
XCDPATH=".;..;/;c:/;c:/windows;c:/scm;c:/ian"
XINCLUDE=c:/include
XLIB=c:/lib
XTMP=c:/tmp
XTZ=GMT0BST
XEDITOR=vi
XPS1="s0H
[%p] %d %t
u%n %e> "
XHOME=c:/
XTERM=ibmpc-mono
XCL="-AL -Zid -W3"
XINIT=c:/bin/me_ini
XEXTENDED_LINE=c:/bin/extend.lst
XEXINIT="set aw ai sm dm sw=4 wm=5"
X
Xmsdos LIB TMP
SHAR_EOF
chmod 0644 scripts/profile.sh || echo "restore of scripts/profile.sh fails"
set `wc -c scripts/profile.sh`;Sum=$1
if test "$Sum" != "366"
then echo original size 366, current size $Sum;fi
echo "x - extracting shell/Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > shell/Makefile &&
X#
X# MS-DOS SHELL - Makefile
X#
X# MS-DOS SHELL - Copyright (c) 1989 Data Logic Limited.
X#
X# Redistribution and use in source and binary forms are permitted
X# provided that the above copyright notice is duplicated in the
X# source form.
X#
X#
X# $Header$
X#
X# $Log$
X#
X
XOBJS=sh0.obj sh1.obj sh2.obj sh3.obj sh4.obj sh5.obj sh6.obj \
X sh7.obj sh8.obj sh9.obj sh10.obj
XASFLAGS= /Ml /Zi /Zd
X
Xsh.exe: $(OBJS)
X link sh0+sh1+sh2+sh3+sh4+sh5+sh6+sh7+sh8+sh9+sh10/noi, sh.exe;
SHAR_EOF
chmod 0644 shell/Makefile || echo "restore of shell/Makefile fails"
set `wc -c shell/Makefile`;Sum=$1
if test "$Sum" != "470"
then echo original size 470, current size $Sum;fi
echo "x - extracting shell/sh1.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > shell/sh1.c &&
X/* MS-DOS SHELL - Main program, memory and variable management
X *
X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
X *
X * This code is based on (in part) the shell program written by Charles
X * Forsyth and is subject to the following copyright restrictions:
X *
X * 1. Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in the
X * source form and the copyright notice in file sh6.c is displayed
X * on entry to the program.
X *
X * 2. The sources (or parts thereof) or objects generated from the sources
X * (or parts of sources) cannot be sold under any circumstances.
X *
X * $Header: sh1.c 1.1 90/01/25 13:40:39 MS_user Exp $
X *
X * $Log: sh1.c $
X * Revision 1.1 90/01/25 13:40:39 MS_user
X * Initial revision
X *
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <stdarg.h>
X#include <string.h>
X#include <unistd.h>
X#include <ctype.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <dos.h>
X#include <time.h>
X#include "sh.h"
X
X/*
X * Structure of Malloced space to allow release of space nolonger required
X * without having to know about it.
X */
X
Xtypedef struct region {
X struct region *next;
X int area;
X} s_region;
X
Xstatic struct region *areastart = (s_region *)NULL;
X
X/*
X * default shell, search rules
X */
X
Xstatic char *shellname = "c:/bin/sh";
Xstatic char *search = ";c:/bin;c:/usr/bin";
Xstatic char *ymail = "You have mail\n";
Xstatic char *Path = "PATH";
X#ifdef SIGQUIT
Xstatic void (*qflag)() = SIG_IGN;
X#endif
X
X/* Functions */
X
Xstatic char *cclass (char *, int, bool);
Xstatic char *copy_to_equals (char *, char *);
Xstatic void nameval (Var_List *, char *, char *, bool);
Xstatic void patch_up (void);
Xstatic void onecommand (void);
Xstatic void Check_Mail (void);
Xstatic void Pre_Process_Argv (char **);
Xstatic void Load_G_VL (void);
X
X/*
X * The main program starts here
X */
X
Xvoid main (argc, argv)
Xint argc;
Xregister char **argv;
X{
X register int f;
X register char *s, *s1;
X int cflag = 0;
X int sc;
X char *name, **ap;
X int (*iof)(IO_State *) = filechar;
X Var_List *lset;
X bool l_rflag = FALSE;
X
X/* Patch up various parts of the system */
X
X patch_up ();
X
X/* Load the environment into our structures */
X
X if ((ap = environ) != (char **)NULL)
X {
X while (*ap)
X assign (*ap++, !COPYV);
X
X for (ap = environ; *ap;)
X s_vstatus (lookup (*ap++, TRUE), EXPORT);
X }
X
X/* Zap all files */
X
X closeall ();
X areanum = 1;
X
X/* Get the current directory */
X
X Getcwd ();
X
X/* Set up some stardard variables if their not set */
X
X if ((lset = lookup (shell, TRUE))->value == null)
X setval (lset, shellname);
X
X s_vstatus (lset, EXPORT);
X
X/* Check for restricted shell */
X
X if ((s = strrchr (lset->value, '/')) == (char *)NULL)
X s = lset->value;
X
X else
X s++;
X
X if (*s == 'r')
X l_rflag = TRUE;
X
X/* Set up home directory */
X
X if ((lset = lookup (home, TRUE))->value == null)
X setval (lset, "c:/");
X
X s_vstatus (lset, EXPORT);
X
X/* Set up history file location */
X
X setval (lookup ("$", TRUE), putn (getpid ()));
X
X Load_G_VL ();
X path->status |= (EXPORT | PONLY);
X ifs->status |= (EXPORT | PONLY);
X ps1->status |= (EXPORT | PONLY);
X ps2->status |= (EXPORT | PONLY);
X
X if (path->value == null)
X setval (path, search);
X
X if (ifs->value == null)
X setval (ifs, " \t\n");
X
X if (ps1->value == null)
X setval (ps1, "$ ");
X
X if (ps2->value == null)
X setval (ps2, "> ");
X
X/* Check the restricted shell */
X
X if ((s = strrchr ((name = *argv), '/')) == (char *)NULL)
X s = name;
X
X if ((s1 = strchr (s, '.')) != (char *)NULL)
X *s1 = 0;
X
X if (strcmp (s, "rsh") == 0)
X l_rflag = TRUE;
X
X if (s1 != (char *)NULL)
X *s1 = '.';
X
X/* Preprocess options to convert two character options of the form /x to
X * -x. Some programs!!
X */
X
X Pre_Process_Argv (argv);
X
X/* Process the options */
X
X while ((sc = getopt (argc, argv, "abc:defghijklmnopqrtsuvwxyz0")) != EOF)
X {
X switch (sc)
X {
X case '0': /* Level 0 flag for DOS */
X level0 = TRUE;
X break;
X
X case 'r': /* Restricted */
X l_rflag = TRUE;
X break;
X
X case 'c': /* Command on line */
X ps1->status &= ~EXPORT;
X ps2->status &= ~EXPORT;
X setval (ps1, null);
X setval (ps2, null);
X cflag = 1;
X
X PUSHIO (aword, optarg, iof = nlchar);
X break;
X
X case 'q': /* No quit ints */
X#ifdef SIGQUIT
X qflag = SIG_DFL;
X#endif
X break;
X
X case 's': /* standard input */
X break;
X
X case 't': /* One command */
X ps1->status &= ~EXPORT;
X setval (ps1, null);
X iof = linechar;
X break;
X
X case 'i': /* Set interactive */
X talking++;
X
X default:
X if (islower (sc))
X FL_SET (sc);
X }
X }
X
X argv += optind;
X argc -= optind;
X
X/* Execute one off command - disable prompts */
X
X if ((iof == filechar) && (argc > 0))
X {
X setval (ps1, null);
X setval (ps2, null);
X ps1->status &= ~EXPORT;
X ps2->status &= ~EXPORT;
X
X f = 0;
X
X/* Open the file if necessary */
X
X if (strcmp ((name = *argv), "-") != 0)
X {
X if ((f = O_for_execute (name)) < 0)
X {
X print_error ("%s: cannot open\n", name);
X exit (1);
X }
X }
X
X next (remap (f)); /* Load into I/O stack */
X }
X
X/* Set up the $- variable */
X
X setdash ();
X
X/* Load terminal I/O structure if necessary and load the history file */
X
X if (e.iop < iostack)
X {
X PUSHIO (afile, 0, iof);
X
X if (isatty (0) && isatty (1) && !cflag)
X {
X fprintf (stderr, Copy_Right1, _osmajor, _osminor);
X fputs (Copy_Right2, stderr);
X
X talking++;
X History_Enabled = TRUE;
X Load_History ();
X }
X }
X
X#ifdef SIGQUIT
X signal (SIGQUIT, qflag);
X#endif
X
X/* Read profile ? */
X
X if (((name != (char *)NULL) && (*name == '-')) || level0)
X {
X talking++;
X
X if ((f = O_for_execute ("/etc/profile")) >= 0)
X next (remap(f));
X
X if ((f = O_for_execute ("profile")) >= 0)
X next (remap(f));
X }
X
X/* Set up signals */
X
X if (talking)
X signal (SIGTERM, sig);
X
X if (signal (SIGINT, SIG_IGN) != SIG_IGN)
X signal (SIGINT, onintr);
X
X/* Load any parameters */
X
X dolv = argv;
X dolc = argc;
X dolv[0] = name;
X
X if (dolc > 1)
X {
X for (ap = ++argv; --argc > 0;)
X {
X if (assign (*ap = *argv++, !COPYV))
X dolc--; /* keyword */
X
X else
X ap++;
X }
X }
X
X setval (lookup ("#", TRUE), putn ((--dolc < 0) ? (dolc = 0) : dolc));
X
X/* Execute the command loop */
X
X while (1)
X {
X if (talking && e.iop <= iostack)
X {
X Check_Mail ();
X put_prompt (ps1->value);
X r_flag = l_rflag;
X }
X
X onecommand ();
X }
X}
X
X/*
X * Set up the value of $-
X */
X
Xvoid setdash ()
X{
X register char *cp, c;
X char m['z' - 'a' + 1];
X
X for (cp = m, c = 'a'; c <= 'z'; ++c)
X {
X if (FL_TEST (c))
X *(cp++) = c;
X }
X
X *cp = 0;
X setval (lookup ("-", TRUE), m);
X}
X
X/* Execute a command */
X
Xstatic void onecommand ()
X{
X register int i;
X jmp_buf m1;
X C_Op *outtree;
X
X
X/* Exit any previous environments */
X
X while (e.oenv)
X quitenv ();
X
X/* initialise space */
X
X areanum = 1;
X freehere (areanum);
X freearea (areanum);
X wdlist = (Word_B *)NULL;
X iolist = (Word_B *)NULL;
X e.errpt = (int *)NULL;
X e.cline = space (LINE_MAX);
X e.eline = e.cline + LINE_MAX - 5;
X e.linep = e.cline;
X yynerrs = 0;
X multiline = 0;
X inparse = 1;
X SW_intr = 0;
X execflg = 0;
X
X/* Get the line and process it */
X
X if (setjmp (failpt = m1) || ((outtree = yyparse ()) == (C_Op *)NULL) ||
X SW_intr)
X {
X
X/* Failed - clean up */
X
X while (e.oenv)
X quitenv ();
X
X scraphere ();
X
X if (!talking && SW_intr)
X leave ();
X
X/* Exit */
X
X inparse = 0;
X SW_intr = 0;
X return;
X }
X
X/* Ok - reset some variables and then execute the command tree */
X
X inparse = 0;
X Break_List = (Break_C *)NULL;
X Return_List = (Break_C *)NULL;
X SShell_List = (Break_C *)NULL;
X SW_intr = 0;
X execflg = 0;
X
X/* Set execute function recursive level and the SubShell count to zero */
X
X Execute_stack_depth = 0;
X
X/* Set up Redirection IO (Saved) array and SubShell Environment information */
X
X NSave_IO_E = 0; /* Number of entries */
X MSave_IO_E = 0; /* Max Number of entries */
X NSubShells = 0; /* Number of entries */
X MSubShells = 0; /* Max Number of entries */
X
X/* Save the environment information */
X
X if (talking && e.iop <= iostack)
X Add_History (FALSE);
X
X if (!FL_TEST ('n'))
X execute (outtree, NOPIPE, NOPIPE, 0);
X
X/* Make sure the I/O and environment are back at level 0 and then clear them */
X
X Execute_stack_depth = 0;
X
X if (NSubShells != 0)
X Delete_G_VL ();
X
X if (NSave_IO_E)
X restore_std (0);
X
X if (MSubShells)
X DELETE (SubShells);
X
X if (MSave_IO_E)
X DELETE (SSave_IO);
X
X/* Check for interrupts */
X
X if (!talking && SW_intr)
X {
X execflg = 0;
X leave ();
X }
X
X/* Run any traps that are required */
X
X if ((i = trapset) != 0)
X {
X trapset = 0;
X runtrap (i);
X }
X}
X
X/*
X * Terminate current environment with an error
X */
X
Xvoid fail ()
X{
X longjmp (failpt, 1);
X
X /* NOTREACHED */
X}
X
X/*
X * Exit the shell
X */
X
Xvoid leave ()
X{
X if (execflg)
X fail ();
X
X/* Clean up */
X
X scraphere ();
X freehere (1);
X
X/* Trap zero on exit */
X
X runtrap (0);
X
X/* Dump history on exit */
X
X if (talking && isatty(0))
X Dump_History ();
X
X closeall ();
X exit (exstat);
X
X/* NOTREACHED */
X}
X
X/*
X * Output warning message
X */
X
Xvoid print_warn (fmt)
Xchar *fmt;
X{
X va_list ap;
X char x[100];
X
X va_start (ap, fmt);
X vsprintf (x, fmt, ap);
X S_puts (x);
X exstat = -1;
X
X/* If leave on error - exit */
X
X if (FL_TEST ('e'))
X leave ();
X
X va_end (ap);
X}
X
X/*
X * Output error message
X */
X
Xvoid print_error (fmt)
Xchar *fmt;
X{
X va_list ap;
X char x[100];
X
X/* Error message processing */
X
X va_start (ap, fmt);
X vsprintf (x, fmt, ap);
X S_puts (x);
X exstat = -1;
X
X if (FL_TEST ('e'))
X leave ();
X
X va_end (ap);
X
X/* Error processing */
X
X if (FL_TEST ('n'))
X return;
X
X/* If not interactive - exit */
X
X if (!talking)
X leave ();
X
X if (e.errpt)
X longjmp (e.errpt, 1);
X
X/* closeall (); Removed - caused problems. There may be problems
X * remaining with files left open?
X */
X
X e.iop = e.iobase = iostack;
X}
X
X/*
X * Create or delete a new environment. If f is set, delete the environment
X */
X
Xbool newenv (f)
Xint f;
X{
X register Environ *ep;
X
X/* Delete environment? */
X
X if (f)
X {
X quitenv ();
X return TRUE;
X }
X
X/* Create a new environment */
X
X if ((ep = (Environ *) space (sizeof (Environ))) == (Environ *)NULL)
X {
X while (e.oenv)
X quitenv ();
X
X fail ();
X }
X
X *ep = e;
X e.oenv = ep;
X e.errpt = errpt;
X return FALSE;
X}
X
X/*
X * Exit the current environment successfully
X */
X
Xvoid quitenv ()
X{
X register Environ *ep;
X register int fd;
X
X/* Restore old environment, delete the space and close any files opened in
X * this environment
X */
X
X if ((ep = e.oenv) != (Environ *)NULL)
X {
X fd = e.iofd;
X e = *ep;
X
X DELETE (ep);
X
X while (--fd >= e.iofd)
X S_close (fd, TRUE);
X }
X}
X
X/*
X * Is character c in s?
X */
X
Xbool any (c, s)
Xregister char c;
Xregister char *s;
X{
X while (*s)
X {
X if (*(s++) == c)
X return TRUE;
X }
X
X return FALSE;
X}
X
X/*
X * Convert binary to ascii
X */
X
Xchar *putn (n)
Xregister int n;
X{
X static char nt[10];
X
X sprintf (nt, "%u", n);
X return nt;
X}
X
X/*
X * Add a file to the input stack
X */
X
Xvoid next (f)
Xint f;
X{
X PUSHIO (afile, f, filechar);
X}
X
X/*
X * SIGINT interrupt processing
X */
X
Xvoid onintr (signo)
Xint signo;
X{
X
X/* Restore signal processing and set SIGINT detected flag */
X
X signal (SIGINT, onintr);
X SW_intr = 1;
X
X/* Are we talking to the user? Yes - check in parser */
X
X if (talking)
X {
X if (inparse)
X {
X S_putc (NL);
X fail ();
X }
X }
X
X/* No - exit */
X
X else
X {
X execflg = 0;
X leave ();
X }
X}
X
X/*
X * Grap some space and check for an error
X */
X
Xchar *space (n)
Xint n;
X{
X register char *cp;
X
X if ((cp = getcell (n)) == (char *)NULL)
X print_error ("sh: out of string space\n");
X
X return cp;
X}
X
X/*
X * Save a string in a given area
X */
X
Xchar *strsave (s, a)
Xregister char *s;
X{
X register char *cp;
X
X if ((cp = space (strlen (s) + 1)) != (char *)NULL)
X {
X setarea ((char *)cp, a);
X return strcpy (cp, s);
X }
X
X return null;
X}
X
X/*
X * trap handling - Save signal number and restore signal processing
X */
X
Xvoid sig (i)
Xregister int i;
X{
X trapset = i;
X signal (i, sig);
X}
X
X/*
X * Execute a trap command
X */
X
Xvoid runtrap (i)
Xint i;
X{
X char *trapstr;
X char tval[10];
X
X sprintf (tval, "~%d", i);
X
X if (((trapstr = lookup (tval, FALSE)->value)) == null)
X return;
X
X/* If signal zero, save a copy of the trap value and then delete the trap */
X
X if (i == 0)
X {
X trapstr = strsave (trapstr, areanum);
X unset (tval, TRUE);
X }
X
X RUN (aword, trapstr, nlchar);
X}
X
X/*
X * Find the given name in the dictionary and return its value. If the name was
X * not previously there, enter it now and return a null value.
X */
X
XVar_List *lookup (n, cflag)
Xregister char *n;
Xbool cflag;
X{
X register Var_List *vp;
X register char *cp;
X register int c;
X static Var_List dummy;
X
X/* Set up the dummy variable */
X
X dummy.name = n;
X dummy.status = RONLY;
X dummy.value = null;
X
X/* If digit string - use the dummy to return the value */
X
X if (isdigit (*n))
X {
X for (c = 0; isdigit (*n) && (c < 1000); n++)
X c = c * 10 + *n - '0';
X
X dummy.value = (c <= dolc) ? dolv[c] : null;
X return &dummy;
X }
X
X/* Look up in list */
X
X for (vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
X {
X if (eqname (vp->name, n))
X return vp;
X }
X
X/* If we don't want to create it, return a dummy */
X
X if (!cflag)
X return &dummy;
X
X/* Create a new variable */
X
X cp = findeq (n);
X
X if (((vp = (Var_List *)space (sizeof (Var_List))) == (Var_List *)NULL)
X || (vp->name = space ((int)(cp - n) + 2)) == (char *)NULL)
X {
X dummy.name = null;
X return &dummy;
X }
X
X/* Set area for space to zero - no auto-delete */
X
X setarea ((char *)vp, 0);
X setarea ((char *)vp->name, 0);
X
X/* Just the name upto the equals sign, no more */
X
X copy_to_equals (vp->name, n);
X
X/* Link into list */
X
X vp->value = null;
X vp->next = vlist;
X vp->status = GETCELL;
X vlist = vp;
X return vp;
X}
X
X/*
X * give variable at `vp' the value `val'.
X */
X
Xvoid setval(vp, val)
XVar_List *vp;
Xchar *val;
X{
X nameval (vp, val, (char *)NULL, FALSE);
X}
X
X/*
X * Copy and check that it terminates in an equals sign
X */
X
Xstatic char *copy_to_equals (d, s)
Xchar *d, *s;
X{
X int n = (int) (findeq (s) - s);
X
X strncpy (d, s, n);
X *(d += n) = '=';
X *(++d) = 0;
X return d;
X}
X
X/*
X * Set up new value for name
X *
X * If name is not NULL, it must be a prefix of the space `val', and end with
X * `='. This is all so that exporting values is reasonably painless.
X */
X
Xstatic void nameval (vp, val, name, disable)
Xregister Var_List *vp;
Xchar *val;
Xchar *name;
Xbool disable;
X{
X register char *xp;
X int fl = 0;
X
X/* Check if variable is read only */
X
X if (vp->status & RONLY)
X {
X char c = *(xp = findeq (vp->name));
X
X *xp = 0;
X S_puts (xp);
X *xp = c;
X print_error (" is read-only\n");
X return;
X }
X
X/* Check for $PATH reset in restricted shell */
X
X if (!disable && (strcmp (vp->name, Path) == 0) && check_rsh (Path))
X return;
X
X/* Get space for string ? */
X
X if (name == (char *)NULL)
X {
X if ((xp = space (strlen (vp->name) + strlen (val) + 2)) == (char *)NULL)
X return;
X
X/* make string: name=value */
X
X setarea ((char *)xp, 0);
X name = xp;
X
X xp = copy_to_equals (xp, vp->name);
X strcpy (xp, val);
X val = xp;
X fl = GETCELL;
X }
X
X if (vp->status & GETCELL)
X DELETE (vp->name); /* form new string `name=value' */
X
X vp->name = name;
X vp->value = val;
X vp->status |= fl;
X
X if (FL_TEST ('a'))
X s_vstatus (vp, EXPORT);
X}
X
X/*
X * Set the status of an environment variable
X */
X
Xvoid s_vstatus (vp, flag)
XVar_List *vp;
Xint flag; /* Addition status flags */
X{
X if (isalpha (*vp->name)) /* not an internal symbol ($# etc) */
X vp->status |= flag;
X}
X
X/*
X * Check for assignment X=Y
X */
X
Xbool isassign (s)
Xregister char *s;
X{
X if (!isalpha (*s))
X return FALSE;
X
X for (; *s != '='; s++)
X {
X if (!*s || !isalnum (*s))
X return FALSE;
X }
X
X return TRUE;
X}
X
X/*
X * Execute an assignment. If a valid assignment, load it into the variable
X * list.
X */
X
Xbool assign (s, cf)
Xregister char *s;
Xint cf;
X{
X register char *cp;
X Var_List *vp;
X
X if (!isalpha (*s))
X return FALSE;
X
X for (cp = s; *cp != '='; cp++)
X {
X if (!*cp || !isalnum (*cp))
X return FALSE;
X }
X
X nameval ((vp = lookup (s, TRUE)), ++cp, (cf == COPYV ? (char *)NULL : s),
X FALSE);
X
X if (cf != COPYV)
X vp->status &= ~GETCELL;
X
X return TRUE;
X}
X
X/*
X * Compare two environment strings
X */
X
Xbool eqname(n1, n2)
Xregister char *n1, *n2;
X{
X for (; *n1 != '=' && *n1 != 0; n1++)
X {
X if (*n2++ != *n1)
X return FALSE;
X }
X
X return (!*n2 || (*n2 == '=')) ? TRUE : FALSE;
X}
X
X/*
X * Find the equals sign in a string
X */
X
Xchar *findeq (cp)
Xregister char *cp;
X{
X while (*cp && (*cp != '='))
X cp++;
X
X return cp;
X}
X
X/*
X * Duplicate the Variable List for a Subshell
X *
X * Create a new Var_list environment for a Sub Shell
X */
X
Xint Create_NG_VL ()
X{
X int i;
X S_SubShell *sp;
X Var_List *vp, *vp1;
X
X for (sp = SubShells, i = 0; (i < NSubShells) &&
X (SubShells[i].depth < Execute_stack_depth);
X i++);
X
X/* If depth is greater or equal to the Execute_stack_depth - we should panic
X * as this should not happen. However, for the moment, I'll ignore it
X */
X
X if (NSubShells == MSubShells)
X {
X sp = (S_SubShell *)space ((MSubShells + SSAVE_IO_SIZE) * sizeof (S_SubShell));
X
X/* Check for error */
X
X if (sp == (S_SubShell *)NULL)
X {
X errno = ENOMEM;
X return -1;
X }
X
X/* Save original data */
X
X if (MSubShells != 0)
X {
X memcpy (sp, SubShells, sizeof (S_SubShell) * MSubShells);
X DELETE (SubShells);
X }
X
X setarea ((char *)sp, 0);
X SubShells = sp;
X MSubShells += SSAVE_IO_SIZE;
X }
X
X/* Save the depth and the old vlist value */
X
X sp = &SubShells[NSubShells++];
X sp->depth = Execute_stack_depth;
X sp->header = vlist;
X vlist = (Var_List *)NULL;
X
X/* Duplicate the old Variable list */
X
X for (vp = sp->header; vp != (Var_List *)NULL; vp = vp->next)
X {
X nameval ((vp1 = lookup (vp->name, TRUE)), findeq (vp->name) + 1,
X (char *)NULL, TRUE);
X
X vp1->status |= (vp->status & (C_MSDOS | PONLY | EXPORT | RONLY));
X }
X
X/* Reset global values */
X
X Load_G_VL ();
X return 0;
X}
X
X/*
X * Delete a SubShell environment and restore the original
X */
X
Xvoid Delete_G_VL ()
X{
X int j;
X S_SubShell *sp;
X Var_List *vp;
X
X for (j = NSubShells; j > 0; j--)
X {
X sp = &SubShells[j - 1];
X
X if (sp->depth < Execute_stack_depth)
X break;
X
X/* Reduce number of entries */
X
X --NSubShells;
X
X/* Release the space */
X
X for (vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
X {
X if (vp->status & GETCELL)
X DELETE (vp->name);
X
X DELETE (vp);
X }
X
X/* Restore vlist information */
X
X vlist = sp->header;
X Load_G_VL ();
X }
X}
X
X/*
X * Load GLobal Var List values
X */
X
Xstatic void Load_G_VL ()
X{
X path = lookup (Path, TRUE);
X ifs = lookup ("IFS", TRUE);
X ps1 = lookup ("PS1", TRUE);
X ps2 = lookup ("PS2", TRUE);
X C_dir = lookup ("~", TRUE);
X Restore_Dir ();
X}
X
X/*
X * Match a pattern as in sh(1).
X */
X
Xbool gmatch (s, p, IgnoreCase)
Xregister char *s, *p;
Xbool IgnoreCase;
X{
X register int sc, pc;
X
X if ((s == (char *)NULL) || (p == (char *)NULL))
X return FALSE;
X
X while ((pc = *(p++) & CMASK) != '\0')
X {
X sc = *(s++) & QMASK;
X
X switch (pc)
X {
X case '[': /* Class expression */
X if ((p = cclass (p, sc, IgnoreCase)) == (char *)NULL)
X return FALSE;
X
X break;
X
X case '?': /* Match any character */
X if (sc == 0)
X return FALSE;
X
X break;
X
X case '*': /* Match as many as possible */
X s--;
X do
X {
X if (!*p || gmatch (s, p, IgnoreCase))
X return TRUE;
X
X } while (*(s++));
X
X return FALSE;
X
X default:
X if (IgnoreCase)
X {
X sc = tolower (sc);
X pc = tolower ((pc & ~QUOTE));
X }
X
X if (sc != (pc & ~QUOTE))
X return FALSE;
X }
X }
X
X return (*s == 0) ? TRUE : FALSE;
X}
X
X/*
X * Process a class expression - []
X */
X
Xstatic char *cclass (p, sub, IgnoreCase)
Xregister char *p;
Xregister int sub;
Xbool IgnoreCase;
X{
X register int c, d, not, found;
X
X/* Exclusive or inclusive class */
X
X if ((not = *p == NOT) != 0)
X p++;
X
X found = not;
X
X do
X {
X if (!*p)
X return (char *)NULL;
X
X/* Get the next character in class, converting to lower case if necessary */
X
X c = IgnoreCase ? tolower ((*p & CMASK)) : (*p & CMASK);
X
X/* If this is a range, get the end of range character */
X
X if ((*(p + 1) == '-') && (*(p + 2) != ']'))
X {
X d = IgnoreCase ? tolower ((*(p + 2) & CMASK)) : (*(p + 2) & CMASK);
X p++;
X }
X
X else
X d = c;
X
X/* Is the current character in the class? */
X
X if ((c <= sub) && (sub <= d))
X found = !not;
X
X } while (*(++p) != ']');
X
X return found ? p + 1 : (char *)NULL;
X}
X
X/*
X * Get a string in a malloced area
X */
X
Xchar *getcell(nbytes)
Xunsigned int nbytes;
X{
X s_region *np;
X
X if (nbytes == 0)
X abort (); /* silly and defeats the algorithm */
X
X/* Grab some space */
X
X if ((np = (s_region *)calloc (nbytes + sizeof (s_region), 1)) == (s_region *)NULL)
X return (char *)NULL;
X
X/* Link into chain */
X
X np->next = areastart;
X np->area = areanum;
X areastart = np;
X
X return ((char *)np) + sizeof (s_region);
X}
X
X/*
X * Free a string in a malloced area
X */
X
Xvoid freecell (s)
Xchar *s;
X{
X register s_region *cp = areastart;
X s_region *lp = (s_region *)NULL;
X s_region *sp = (s_region *)(s - sizeof (s_region));
X
X/* Find the string in the chain */
X
X if (s != (char *)NULL)
X {
X while (cp != (s_region *)NULL)
X {
X if (cp != sp)
X {
X lp = cp;
X cp = cp->next;
X continue;
X }
X
X/* First in chain ? */
X
X else if (lp == (s_region *)NULL)
X areastart = cp->next;
X
X/* Delete the current entry and relink */
X
X else
X lp->next = cp->next;
X
X free (cp);
X break;
X }
X }
X}
X
X/*
X * Autodelete space nolonger required. Ie. Free all the strings in a malloced
X * area
X */
X
Xvoid freearea (a)
Xregister int a;
X{
X register s_region *cp = areastart;
X s_region *lp = (s_region *)NULL;
X
X while (cp != (s_region *)NULL)
X {
X
X/* Is the area number less than that specified - yes, continue */
X if (cp->area < a)
X {
X lp = cp;
X cp = cp->next;
X }
X
X/* OK - delete the area. Is it the first in chain ? Yes, delete, relink
X * and update start location
X */
X
X else if (lp == (s_region *)NULL)
X {
X lp = cp;
X cp = cp->next;
X areastart = cp;
X
X free (lp);
X lp = (char *)NULL;
X }
X
X/* Not first, delete the current entry and relink */
X
X else
X {
X lp->next = cp->next;
X free (cp);
X cp = lp->next;
X }
X }
X}
X
X/*
X * Set the area number for a malloced string. This allows autodeletion of
X * space that is nolonger required.
X */
X
Xvoid setarea (cp,a)
Xchar *cp;
Xint a;
X{
X s_region *sp = (s_region *)(cp - sizeof (s_region));
X
X if (cp != (char *)NULL)
X sp->area = a;
X}
X
X/*
X * Get the area number for a malloced string
X */
X
Xint getarea (cp)
Xchar *cp;
X{
X s_region *sp = (s_region *)(cp - sizeof (s_region));
X
X return sp->area;
X}
X
X/* Output one of the Prompt. We save the prompt for the history part of
X * the program
X */
X
Xvoid put_prompt (s)
Xchar *s;
X{
X struct dosdate_t d_date;
X struct dostime_t d_time;
X int i;
X char buf[PATH_MAX + 4];
X
X last_prompt = s; /* Save the Last prompt output */
X
X _dos_gettime (&d_time); /* Get the date and time in case */
X _dos_getdate (&d_date);
X
X while (*s)
X {
X
X/* If a format character, process it */
X
X if (*s == '%')
X {
X s++;
X *s = tolower(*s);
X
X if (*s == '%')
X S_putc ('%');
X
X else
X {
X *buf = 0;
X
X switch (*s)
X {
X case 'e': /* Current event number */
X if (History_Enabled)
X sprintf (buf, "%d", Current_Event + 1);
X
X break;
X
X case 't': /* time */
X sprintf (buf,"%.2d:%.2d", d_time.hour, d_time.minute);
X break;
X
X case 'd': /* date */
X sprintf (buf, "%.3s %.2d-%.2d-%.2d",
X &"SunMonTueWedThuFriSat"[d_date.dayofweek * 3],
X d_date.day, d_date.month, d_date.year % 100);
X break;
X
X case 'p': /* directory */
X case 'n': /* default drive */
X strcpy (buf, C_dir->value);
X
X if (*s == 'n')
X buf[1] = 0;
X
X break;
X
X case 'v': /* version */
X sprintf (buf, "MS-DOS %.2d:%.2d", _osmajor, _osminor);
X break;
X }
X
X/* Output the string */
X
X S_puts (buf);
X }
X }
X
X/* Escaped character ? */
X
X else if (*s == '\\')
X {
X if ((i = Process_Escape (&s)) == -1)
X i = 0;
X
X S_putc (i);
X }
X
X else
X S_putc (*s);
X
X/* Go to the next character */
X
X s++;
X }
X}
X
X/*
X * Get the current path in UNIX format and save it in the environment
X * variable $~
X */
X
Xvoid Getcwd ()
X{
X char ldir[PATH_MAX + 6];
X char *cp = getcwd (ldir, PATH_MAX + 4);
X
X strlwr (cp);
X
X/* Convert to Unix format */
X
X while (*cp)
X {
X if (*cp == '\\')
X *cp = '/';
X
X ++cp;
X }
X
X/* Save in environment */
X
X setval ((C_dir = lookup ("~", TRUE)), ldir);
X}
X
X/*
X * Patch up various parts of the system for the shell. At the moment, we
X * modify the ctype table so that _ is an upper case character.
X */
X
Xstatic void patch_up ()
X{
X/* Patch the ctype table as a cheat */
X
X (_ctype+1)['_'] |= _UPPER;
X}
X
X/*
X * Mail Check processing. Every $MAILCHECK seconds, we check either $MAIL
X * or $MAILPATH to see if any file has changed its modification time since
X * we last looked. In $MAILCHECK, the files are separated by colons (:).
X * If the filename contains a %, the string following the % is the message
X * to display if the file has changed.
X */
X
Xstatic void Check_Mail ()
X{
X int delay = atoi (lookup ("MAILCHECK", FALSE)->value);
X Var_List *mail = lookup ("MAIL", FALSE);
X Var_List *mailp = lookup ("MAILPATH", FALSE);
X static time_t last = 0L;
X time_t current = time ((time_t *)NULL);
X struct stat st;
X char *cp, *sp, *ap;
X
X/* Have we waited long enough */
X
X if ((current - last) < delay)
X return;
X
X/* Yes - Check $MAILPATH. If it is defined, process it. Otherwise, use
X * $MAIL
X */
X
X if (mailp->value != null)
X {
X
X/* Check MAILPATH */
X
X sp = mailp->value;
X
X/* Look for the next separator */
X
X while ((cp = strchr (sp, ':')) != (char *)NULL)
X {
X *cp = 0;
X
X/* % in string ? */
X
X if ((ap = strchr (ap, '%')) != (char *)NULL)
X *ap = 0;
X
X/* Check the file name */
X
X if ((stat (sp, &st) != -1) && (st.st_mtime > last))
X {
X if (ap != (char *)NULL)
X {
X S_puts (ap + 1);
X S_putc (NL);
X }
X
X else
X S_puts (ymail);
X }
X
X/* Restore the % */
X
X if (ap != (char *)NULL)
X *ap = '%';
X
X/* Restore the colon and find the next one */
X
X *cp = ':';
X sp = cp + 1;
X }
X }
X
X/* Just check MAIL */
X
X else if ((mail->value != null) && (stat (mail->value, &st) != -1) &&
X (st.st_mtime > last))
X S_puts (ymail);
X
X/* Save the last check time */
X
X last = current;
X}
X
X/*
X * Preprocess Argv to get handle of options in the format /x
X *
X * Some programs invoke the shell using / instead of - to mark the options.
X * We need to convert to -. Also /c is a special case. The rest of the
X * command line is the command to execute. So, we get the command line
X * from the original buffer instead of argv array.
X */
X
Xstatic void Pre_Process_Argv (argv)
Xchar **argv;
X{
X char *ocl = (char far *)((((long)_psp) << 16) + 0x081L);
X
X
X/* Check for these options */
X
X while ((*++argv != (char *)NULL) && (strlen (*argv) == 2) &&
X (**argv == '/'))
X {
X *strlwr (*argv) = '-';
X
X/* Get the original information from the command line */
X
X if ((*argv)[1] == 'c')
X {
X while ((*ocl != '/') && (*(ocl + 1) != 'c') && (*ocl) &&
X (*ocl != '\r'))
X ++ocl;
X
X if (*ocl != '/')
X continue;
X
X/* Find the start of the string */
X
X ocl += 2;
X
X while (isspace (*ocl) && (*ocl != '\r'))
X ++ocl;
X
X if (*ocl == '\r')
X continue;
X
X/* Found the start. Set up next parameter and ignore the rest */
X
X if (*(argv + 1) == (char *)NULL)
X continue;
X
X *(argv + 1) = ocl;
X *(argv + 2) = (char *)NULL;
X
X if ((ocl = strchr (ocl, '\r')) != (char *)NULL)
X *ocl = 0;
X
X return;
X }
X }
X}
SHAR_EOF
chmod 0644 shell/sh1.c || echo "restore of shell/sh1.c fails"
set `wc -c shell/sh1.c`;Sum=$1
if test "$Sum" != "28366"
then echo original size 28366, current size $Sum;fi
echo "x - extracting shell/sh2.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > shell/sh2.c &&
X/* MS-DOS SHELL - Parser
X *
X * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
X *
X * This code is based on (in part) the shell program written by Charles
X * Forsyth and is subject to the following copyright restrictions:
X *
X * 1. Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice is duplicated in the
X * source form and the copyright notice in file sh6.c is displayed
X * on entry to the program.
X *
X * 2. The sources (or parts thereof) or objects generated from the sources
X * (or parts of sources) cannot be sold under any circumstances.
X *
X * $Header: sh2.c 1.1 90/01/25 13:41:12 MS_user Exp $
X *
X * $Log: sh2.c $
X * Revision 1.1 90/01/25 13:41:12 MS_user
X * Initial revision
X *
X */
X
X#include <sys/types.h>
X#include <stddef.h>
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <string.h>
X#include <ctype.h>
X#include <unistd.h>
X#include "sh.h"
X
X/*
X * shell: syntax (C version)
X */
X
Xtypedef union {
X char *cp;
X char **wp;
X int i;
X C_Op *o;
X} YYSTYPE;
X
X#define WORD 256
X#define LOGAND 257
X#define LOGOR 258
X#define BREAK 259
X#define IF 260
X#define THEN 261
X#define ELSE 262
X#define ELIF 263
X#define FI 264
X#define CASE 265
X#define ESAC 266
X#define FOR 267
X#define WHILE 268
X#define UNTIL 269
X#define DO 270
X#define DONE 271
X#define IN 272
X#define YYERRCODE 300
X
X/* flags to yylex */
X
X#define CONTIN 01 /* skip new lines to complete command */
X
Xstatic bool startl;
Xstatic int peeksym;
Xstatic bool Allow_funcs;
Xstatic int iounit = IODEFAULT;
Xstatic C_Op *tp;
Xstatic YYSTYPE yylval;
Xstatic char *syntax_err = "sh: syntax error\n";
X
Xstatic C_Op *pipeline (int);
Xstatic C_Op *andor (void);
Xstatic C_Op *c_list (bool);
Xstatic bool synio (int);
Xstatic void musthave (int, int);
Xstatic C_Op *simple (void);
Xstatic C_Op *nested (int, int);
Xstatic C_Op *command (int);
Xstatic C_Op *dogroup (int);
Xstatic C_Op *thenpart (void);
Xstatic C_Op *elsepart (void);
Xstatic C_Op *caselist (void);
Xstatic C_Op *casepart (void);
Xstatic char **pattern (void);
Xstatic char **wordlist (void);
Xstatic C_Op *list (C_Op *, C_Op *);
Xstatic C_Op *block (int, C_Op *, C_Op *, char **);
Xstatic int rlookup (char *);
Xstatic C_Op *namelist (C_Op *);
Xstatic char **copyw (void);
Xstatic void word (char *);
Xstatic IO_Actions **copyio (void);
Xstatic IO_Actions *io (int, int, char *);
Xstatic void yyerror (char *);
Xstatic int yylex (int);
Xstatic int collect (int, int);
Xstatic int dual (int);
Xstatic void diag (int);
Xstatic char *tree (unsigned int);
X
XC_Op *yyparse ()
X{
X C_Op *outtree;
X
X startl = TRUE;
X peeksym = 0;
X yynerrs = 0;
X outtree = c_list (TRUE);
X musthave (NL, 0);
X
X return (yynerrs != 0) ? (C_Op *)NULL : outtree;
X}
X
Xstatic C_Op *pipeline (cf)
Xint cf;
X{
X register C_Op *t, *p;
X register int c;
X
X if ((t = command (cf)) != (C_Op *)NULL)
X {
X Allow_funcs = FALSE;
X while ((c = yylex (0)) == '|')
X {
X if ((p = command (CONTIN)) == (C_Op *)NULL)
X yyerror (syntax_err);
X
X/* shell statement */
X
X if ((t->type != TPAREN) && (t->type != TCOM))
X t = block (TPAREN, t, NOBLOCK, NOWORDS);
X
X t = block (TPIPE, t, p, NOWORDS);
X }
X
X peeksym = c;
X }
X
X return t;
X}
X
Xstatic C_Op *andor ()
X{
X register C_Op *t, *p;
X register int c;
X
X if ((t = pipeline (0)) != (C_Op *)NULL)
X {
X Allow_funcs = FALSE;
X while (((c = yylex (0)) == LOGAND) || (c == LOGOR))
X {
X if ((p = pipeline (CONTIN)) == (C_Op *)NULL)
X yyerror (syntax_err);
X
X t = block ((c == LOGAND) ? TAND : TOR, t, p, NOWORDS);
X }
X
X peeksym = c;
X }
X
X return t;
X}
X
Xstatic C_Op *c_list (allow)
Xbool allow;
X{
X register C_Op *t, *p;
X register int c;
X
X/* Functions are only allowed at the start of a line */
X
X Allow_funcs = allow;
X
X if ((t = andor ()) != (C_Op *)NULL)
X {
X Allow_funcs = FALSE;
X
X if ((peeksym = yylex (0)) == '&')
X t = block (TASYNC, t, NOBLOCK, NOWORDS);
X
X while ((c = yylex(0)) == ';' || c == '&' || multiline && c == NL)
X {
X if ((p = andor ()) == (C_Op *)NULL)
X return t;
X
X if ((peeksym = yylex (0)) == '&')
X p = block (TASYNC, p, NOBLOCK, NOWORDS);
X
X t = list (t, p);
X }
X peeksym = c;
X }
X
X return t;
X}
X
X
Xstatic bool synio (cf)
Xint cf;
X{
X register IO_Actions *iop;
X register int i;
X register int c;
X
X if (((c = yylex (cf)) != '<') && (c != '>'))
X {
X peeksym = c;
X return FALSE;
X }
X
X i = yylval.i;
X musthave (WORD, 0);
X iop = io (iounit, i, yylval.cp);
X iounit = IODEFAULT;
X
X if (i & IOHERE)
X markhere (yylval.cp, iop);
X
X return TRUE;
X}
X
Xstatic void musthave (c, cf)
Xint c, cf;
X{
X if ((peeksym = yylex (cf)) != c)
X yyerror (syntax_err);
X
X peeksym = 0;
X}
X
Xstatic C_Op *simple ()
X{
X register C_Op *t = (C_Op *)NULL;
X
X while (1)
X {
X switch (peeksym = yylex (0))
X {
X case '<':
X case '>':
X synio (0);
X break;
X
X case WORD:
X if (t == (C_Op *)NULL)
X (t = (C_Op *)tree (sizeof (C_Op)))->type = TCOM;
X
X peeksym = 0;
X word (yylval.cp);
X break;
X
X/* Check for function - name () { word; } */
X
X case '(':
X if ((t != (C_Op *)NULL) && (Allow_funcs == TRUE) &&
X (wdlist != (Word_B *)NULL) && (wdlist->w_nword == 1))
X {
X Word_B *save;
X
X peeksym = 0;
X musthave (')', 0);
X musthave ('{', 0);
X save = wdlist;
X wdlist = (Word_B *)NULL;
X t->type = TFUNC;
X t->left = nested (TBRACE, '}');
X wdlist = save;
X Allow_funcs = FALSE;
X musthave (NL, 0);
X peeksym = NL;
X }
X
X default:
X return t;
X }
X }
X}
X
Xstatic C_Op *nested (type, mark)
Xint type, mark;
X{
X register C_Op *t;
X
X multiline++;
X t = c_list (FALSE);
X musthave (mark, 0);
X multiline--;
X return block (type, t, NOBLOCK, NOWORDS);
X}
X
Xstatic C_Op *command (cf)
Xint cf;
X{
X register C_Op *t;
X Word_B *iosave = iolist;
X register int c;
X
X iolist = (Word_B *)NULL;
X
X if (multiline)
X cf |= CONTIN;
X
X while (synio (cf))
X cf = 0;
X
X switch (c = yylex (cf))
X {
X default:
X peeksym = c;
X
X if ((t = simple ()) == (C_Op *)NULL)
SHAR_EOF
echo "End of part 2"
echo "File shell/sh2.c is continued in part 3"
echo "3" > s2_seq_.tmp
exit 0
--
Regards,
Ian Stewartson
Data Logic Ltd.