istewart@datlog.co.uk (Ian Stewartson) (02/14/90)
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="[s[1;20H[1;33;44m[%p] %d %t[0m[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.