home *** CD-ROM | disk | FTP | other *** search
- /* MS-DOS System Function with Swaping - system (3C)
- *
- * MS-DOS System - Copyright (c) 1990,1,2 Data Logic Limited.
- *
- * This code is subject to the following copyright restrictions:
- *
- * 1. Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice is duplicated in the
- * source form.
- *
- * Author:
- * Ian Stewartson
- * Data Logic, Queens House, Greenhill Way
- * Harrow, Middlesex HA1 1YR, UK.
- * istewart@datlog.co.uk or ukc!datlog!istewart
- *
- * $Header: c:/usr/src/shell/RCS/system.c 2.0 1992/05/21 16:49:54 Ian_Stewartson Exp $
- *
- * $Log: system.c $
- * Revision 2.0 1992/05/21 16:49:54 Ian_Stewartson
- * MS-Shell 2.0 Baseline release
- *
- *
- * MODULE DEFINITION:
- *
- * This is a version of the standard system(3c) library function. The only
- * difference is that it supports swapping and MS-SHELL EXTENDED_LINE
- * processing.
- *
- * To get the OS2 version, compile with -DOS2
- *
- * There are four macros which can be changed:
- *
- * GET_ENVIRON To get a variable value from the environment
- * FAIL_ENVIRON The result on failure
- * FATAL_ERROR Handle a fatal error message
- * SHELL_SWITCH The command switch to the SHELL.
- *
- * This module replaces the standard Microsoft SYSTEM (3C) call. It should
- * work with most models. It has been tested in Large and Small model.
- * When you link a program using the swapper, the swapper front end
- * (swap.obj) must be the first object model on the linker command line so
- * that it is located immediately after the PSP. For example:
- *
- * link swap+x1+x2+x3+system,x1;
- * or
- * cl -o z1 swap.obj x1.obj x2.obj x3.obj system
- *
- * The location of the system object is not relevent.
- */
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <limits.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- #include <signal.h>
- #include <dirent.h>
- #ifdef DL_MAKE
- #include "make.h"
- #endif
- #ifdef OS2
- #define INCL_DOSSESMGR
- #define INCL_DOSMEMMGR
- #define INCL_DOSPROCESS
- #define INCL_WINSWITCHLIST
- #include <os2.h>
- #else
- #include <dos.h>
- #endif
-
- /*
- * Externals declared by the swapper
- */
-
- #ifndef OS2
- extern char far cmd_line[]; /* Command line */
- extern char far path_line[]; /* Process path */
- extern unsigned int far SW_intr; /* interrupt pending */
- extern unsigned int far SW_Blocks; /* Number of blocks to read */
- extern int far SW_fp; /* File or EMS Handler */
- extern unsigned int far SW_EMsize; /* Number of extend memory blks */
- extern unsigned long far SW_EMstart; /* Start addr of extend mem */
-
- #define SWAP_TO_DISK 1 /* Swap to disk */
- #define SWAP_TO_Ext 2 /* Swap to extended memory */
- /* Not recommended - no mgt */
- #define SWAP_TO_EMS 3 /* Swap to EMS */
- #define SWAP_TO_XMS 4 /* Swap to XMS */
-
- extern unsigned int far SW_Mode; /* Type of swapping to do */
- extern unsigned int far SW_EMSFrame; /* EMS Frame segment */
- extern bool far SW_I23_InShell; /* In the shell */
-
- /* Functions */
-
- extern int far SA_spawn (char **);
- extern void (interrupt far *SW_I23_V) (void); /* Int 23 address */
- extern void (far *SW_XMS_Driver) (void); /* XMS Driver Interface */
- extern int far SW_XMS_Gversion (void);
- extern int far SW_XMS_Allocate (unsigned int);
- extern int far SW_XMS_Free (int);
- extern unsigned int far SW_XMS_Available (void);
- extern void interrupt far SW_Int23 (void); /* Int 23 New address */
- extern void interrupt far SW_Int00 (void); /* Int 00 New address */
- #endif
-
- #define FFNAME_MAX (PATH_MAX + NAME_MAX + 3)
-
- /* Set these to the appropriate values to get environment variables. For
- * make the following values work. Normally, getenv and (char *)NULL should
- * be used.
- */
-
- #ifdef DL_MAKE
- #define GET_ENVIRON(p) GetMacroValue (p)
- #define FAIL_ENVIRON Nullstr
- #define FATAL_ERROR(a) PrintFatalError (a)
- #define SHELL_SWITCH "-ec"
- #else
- #define FATAL_ERROR(a) { fputs (a, stderr); fputc ('\n', stderr); exit (1); }
- #define GET_ENVIRON(p) getenv (p)
- #define FAIL_ENVIRON (char *)NULL
- #define SHELL_SWITCH "-c"
- #endif
-
- /* Declarations */
-
- /* Open in create mode */
- #define O_CMASK (O_WRONLY | O_CREAT | O_TRUNC | O_TEXT)
- /* Open in create mode for swap file */
- #define O_SMASK (O_RDWR | O_CREAT | O_TRUNC | O_BINARY)
-
- #ifndef OS2
- #define CMD_LINE_MAX 127 /* Max command line length */
-
- /* MSDOS Memory Control Block chain structure */
-
- #pragma pack (1)
- struct MCB_list {
- char MCB_type; /* M or Z */
- unsigned int MCB_pid; /* Process ID */
- unsigned int MCB_len; /* MCB length */
- };
- #pragma pack ()
-
- #define MCB_CON 'M' /* More MCB's */
- #define MCB_END 'Z' /* Last MCB's */
-
- /* Swap Mode */
-
- #define SWAP_OFF 0x0000 /* No swapping */
- #define SWAP_DISK 0x0001 /* Disk only */
- #define SWAP_EXTEND 0x0002 /* Extended memory */
- #define SWAP_EXPAND 0x0004 /* Expanded memory */
-
- static int Swap_Mode = (SWAP_DISK | SWAP_EXPAND | SWAP_EXTEND);
- static char *Swap_File = (char *)NULL;
- static char *NoSwapFiles = "No Swap files\n";
- static char *MS_emsg = "Warning: %s Error (%x)\n";
- static char *XMS_Space = "Warning: %s out of space\n";
- static char *SwapFailed = "%s swap failed (%x)\n";
-
- #else
- #define CMD_LINE_MAX 255 /* Max command line length */
- #endif
-
- char DOS_CommandPath[PATH_MAX + NAME_MAX + 3];
- char DOS_CommandLine[CMD_LINE_MAX]; /* Command line */
-
- static char *Extend_file = (char *)NULL;
- static char *Extensions [] = { "", ".exe", ".com"};
-
- /*
- * Extract field from a line
- */
-
- #define MAX_LINEFIELDS 6 /* Max number of line fields */
-
- typedef struct Fields {
- FILE *FP; /* File handler */
- char *Line; /* Line buffer */
- int LineLength; /* Line Length */
- char *Field[MAX_LINEFIELDS]; /* ptr to the start of fields */
- } LineFields;
-
- /*
- * Program type
- */
-
- static struct ExecutableProcessing {
- unsigned char Flags;
- unsigned char FieldSep;
- char *Name;
- } ExecProcessingMode;
-
- /* Flags set a bit to indicate program mode */
-
- #define EP_NONE 0x00 /* Use PSP command line */
- #define EP_DOSMODE 0x01 /* Use DOS mode extended line */
- #define EP_UNIXMODE 0x02 /* Use UNIX mode extended line */
- #define EP_NOEXPAND 0x04 /* Use -f for this command */
- #define EP_ENVIRON 0x08 /* Use environ for variable */
- #define EP_NOSWAP 0x10 /* Do not swap for this command */
- #define EP_COMSPEC 0x20 /* Special for .bat files */
- #define EP_EXPORT 0x40 /* Use -m for this command */
- #define EP_CONVERT 0x80 /* Use conversion */
-
- /*
- * Common fields in EXTENDED_LINE file
- */
-
- #define COMMON_FIELD_COUNT 4
-
- static struct CommonFields {
- char *Name;
- unsigned char Flag;
- } CommonFields [] = {
- { "switch", EP_CONVERT },
- { "export", EP_EXPORT },
- { "noswap", EP_NOSWAP },
- { "noexpand", EP_NOEXPAND }
- };
-
- /*
- * Functions
- */
-
- #ifndef OS2
- static bool near Get_XMS_Driver (void);
- static bool near Get_EMS_Driver (void);
- static bool near EMS_error (char *, int);
- static bool near XMS_error (char *, int);
- static int near XMS_Close (void);
- static int near EMS_Close (void);
- static int near SwapToDiskError (int, char *);
- static int near SwapToMemory (int);
- static void near SetUpSwapper (void);
- #endif
-
- static void near ClearExtendedLineFile (void);
- static int near ExecuteProgram (char *, char **);
- static bool near FindLocationOfExecutable (char *, char *);
- static char * near GenerateTemporaryFileName (void);
- static char * near BuildNextFullPathName (char *, char *, char *);
- static void near CheckProgramMode (char *);
- static unsigned char near CheckForCommonOptions (LineFields *, int, int);
- static void near SetCurrentDrive (unsigned int);
- static int near SpawnProcess (void);
- static int near BuildCommandLine (char *, char **);
- static char * near GenerateFullExecutablePath (char *);
- static bool near WriteToExtendedFile (int, char *);
- static size_t near WhiteSpaceLength (char *, bool *);
- static int near StartTheProcess (char *, char **);
- static char * near ConvertPathToFormat (char *);
- static char * near BuildOS2String (char **, char);
- static int ExtractFieldsFromLine (LineFields *);
-
- /*
- * System function with swapping
- */
-
- int system (char const *arg2)
- {
- char *argv[4];
- char *ep;
- int res, serrno, len;
- char p_name[PATH_MAX + NAME_MAX + 3];
- char cdirectory[PATH_MAX + 4]; /* Current directory */
- char *SaveEV = (char *)NULL;
-
- /* Set up argument array */
-
- argv[1] = SHELL_SWITCH;
-
- if ((argv[0] = GET_ENVIRON ("SHELL")) == FAIL_ENVIRON)
- {
- argv[0] = GET_ENVIRON ("COMSPEC");
- argv[1] = "/c";
- }
-
- if (argv[0] == FAIL_ENVIRON)
- FATAL_ERROR ("No Shell available");
-
- argv[2] = (char *)arg2;
- argv[3] = (char *)NULL;
-
- /* Check to see if the file exists. First check for command.com to use /
- * instead of -
- */
-
- if ((ep = strrchr (argv[0], '/')) == (char *)NULL)
- ep = argv[0];
-
- else
- ++ep;
-
- /* Check the program mode */
-
- CheckProgramMode (*argv);
-
- /* Check for command.com */
-
- #ifndef OS2
- if (!stricmp (ep, "command.com") || !stricmp (ep, "command"))
- {
- union REGS r;
-
- r.x.ax = 0x3700;
- intdos (&r, &r);
-
- if ((r.h.al == 0) && (_osmajor < 4))
- *argv[1] = (char)(r.h.dl);
-
- if (ExecProcessingMode.Flags & EP_CONVERT)
- ExecProcessingMode.Flags |= EP_COMSPEC;
- }
- #endif
-
- /* Convert arguments. If this is COMSPEC for a batch file command, skip over
- * the first switch
- */
-
- if (ExecProcessingMode.Flags & EP_COMSPEC)
- len = 2;
-
- /*
- * Convert from UNIX to DOS format: Slashes to Backslashes in paths and
- * dash to slash for switches
- */
-
- if (ExecProcessingMode.Flags & EP_CONVERT)
- {
- while ((ep = argv[len++]) != (char *)NULL)
- {
- if (*ep == '-')
- *ep = '/';
-
- else
- ConvertPathToFormat (ep);
- }
- }
-
- /* Save the current directory */
-
- getcwd (cdirectory, PATH_MAX + 3);
-
- /* If pass in environment, set up environment variable */
-
- if (ExecProcessingMode.Flags & EP_ENVIRON)
- {
- if ((SaveEV = GET_ENVIRON (ExecProcessingMode.Name)) != FAIL_ENVIRON)
- SaveEV = strdup (ExecProcessingMode.Name);
-
- /* Get some space for the environment variable */
-
- if ((ep = malloc (strlen (ExecProcessingMode.Name) + strlen (argv[1]) +
- strlen (argv[2]) + 3)) == (char *)NULL)
- {
- if (SaveEV != (char *)NULL)
- free (SaveEV);
-
- free (ExecProcessingMode.Name);
- return -1;
- }
-
- sprintf (ep, "%s=%s%c%s", ExecProcessingMode.Name, argv[1],
- ExecProcessingMode.FieldSep, argv[2]);
-
- /* Stick it in the environment */
-
- if (putenv (ep))
- {
- free (ExecProcessingMode.Name);
- return -1;
- }
-
- argv[1] = ExecProcessingMode.Name;
- argv[2] = (char *)NULL;
- }
-
- /* Start off on the search path for the executable file */
-
- res = (FindLocationOfExecutable (p_name, argv[0]))
- ? ExecuteProgram (p_name, argv) : -1;
-
- serrno = errno;
-
- /* Restore the current directory */
-
- SetCurrentDrive (tolower(*cdirectory) - 'a' + 1);
-
- if (chdir (&cdirectory[2]) != 0)
- {
- fputs ("Warning: current directory reset to /\n", stderr);
- chdir ("/");
- }
-
- /* Clean up environment. Restore original value */
-
- if (ExecProcessingMode.Flags & EP_ENVIRON)
- {
- len = strlen (ExecProcessingMode.Name) + 2;
-
- if (SaveEV != (char *)NULL)
- len += strlen (SaveEV);
-
- if ((ep = malloc (len)) != (char *)NULL)
- {
- sprintf (ep, "%s=", ExecProcessingMode.Name,
- (SaveEV == (char *)NULL) ? "" : SaveEV);
-
- putenv (ep);
- }
-
- /* Release memory */
-
- if (SaveEV != (char *)NULL)
- free (SaveEV);
-
- free (ExecProcessingMode.Name);
- }
-
- errno = serrno;
- return res;
- }
-
- /* Exec or spawn the program ? */
-
- static int near ExecuteProgram (char *path, char **parms)
- {
- int res;
- #ifndef OS2
- unsigned int size = 0;
- int serrno;
- unsigned int c_cur = (unsigned int)(_psp - 1);
- struct MCB_list far *mp = (struct MCB_list far *)((unsigned long)c_cur << 16L);
- #endif
-
- /* Check to see if the file exists */
-
- strcpy (DOS_CommandPath, path);
-
- /* Check we have access to the file */
-
- if (access (DOS_CommandPath, F_OK) != 0)
- return -1;
-
- /* Process the command line. If no swapping, we have executed the program */
-
- res = BuildCommandLine (DOS_CommandPath, parms);
-
- #ifdef OS2
- SetWindowName ();
- ClearExtendedLineFile ();
- return res;
- #else
- if ((ExecProcessingMode.Flags & EP_NOSWAP) ||
- (Swap_Mode == SWAP_OFF) || res)
- {
- ClearExtendedLineFile ();
- return res;
- }
-
- /* Find the length of the swap area */
-
- while ((mp = (struct MCB_list far *)((unsigned long)c_cur << 16L))->MCB_type
- == MCB_CON)
- {
- if ((mp->MCB_pid != _psp) && (mp->MCB_pid != 0) &&
- (mp->MCB_type != MCB_END))
- {
- ClearExtendedLineFile ();
- FATAL_ERROR ("Fatal: Memory chain corrupt");
- return -1;
- }
-
- c_cur += (mp->MCB_len + 1);
- size += mp->MCB_len + 1;
- }
-
- /*
- * Convert swap size from paragraphs to 16K blocks.
- */
-
- if (size == 0)
- size = mp->MCB_len + 1;
-
- SW_Blocks = (size / 0x0400) + 1;
-
- /* OK Now we've set up the FCB's, command line and opened the swap file.
- * Get some sys info for the swapper and execute my little assembler
- * function to swap us out
- */
-
- /* Ok - 3 methods of swapping. First tranfer to command line to the
- * swapper.
- */
-
- SetUpSwapper ();
-
- /* If expanded memory - try that */
-
- if ((Swap_Mode & SWAP_EXPAND) && Get_EMS_Driver ())
- {
- SW_Mode = 3; /* Set Expanded memory swap */
-
- if ((res = SwapToMemory (SWAP_EXPAND)) != -2)
- return res;
- }
-
- if ((Swap_Mode & SWAP_EXTEND) && Get_XMS_Driver ())
- {
- SW_Mode = (SW_fp == -1) ? 2 : 4;/* Set Extended memory or XMS driver */
-
- if ((res = SwapToMemory (SWAP_EXTEND)) != -2)
- return res;
- }
-
- /* Try the disk if available */
-
- if (Swap_Mode & SWAP_DISK)
- {
- if ((SW_fp = open ((Swap_File = GenerateTemporaryFileName ()),
- O_SMASK, 0600)) < 0)
- return SwapToDiskError (ENOSPC, NoSwapFiles);
-
- SW_Mode = 1; /* Set Disk file swap */
-
- /* Execute the program */
-
- res = SpawnProcess ();
-
- /* Close the extended command line file */
-
- ClearExtendedLineFile ();
-
- /* Close the swap file */
-
- serrno = errno;
- close (SW_fp);
- unlink (Swap_File);
- errno = serrno;
-
- /* Check for out of swap space */
-
- if (res == -2)
- return SwapToDiskError (errno, "Swap file write failed\n");
-
- /* Return the result */
-
- return res;
- }
-
- /* No swapping available - give up */
-
- ClearExtendedLineFile ();
- fputs ("swap: All Swapping methods failed\n", stderr);
- errno = ENOSPC;
- return -1;
- #endif
- }
-
- #ifndef OS2
- /*
- * OS2 does not require swapping
- *
- * Get the XMS Driver information
- */
-
- static bool near Get_XMS_Driver (void)
- {
- union REGS or;
- struct SREGS sr;
- unsigned int SW_EMsize; /* Number of extend memory blks */
-
- /* Get max Extended memory pages, and convert to 16K blocks. If Extended
- * memory swapping disabled, set to zero
- */
-
- SW_fp = -1; /* Set EMS/XMS handler not */
- /* defined */
-
- /* Is a XMS memory driver installed */
-
- or.x.ax = 0x4300;
- int86 (0x2f, &or, &or);
-
- if (or.h.al != 0x80)
- {
- or.x.ax = 0x8800;
- int86 (0x15, &or, &or);
- SW_EMsize = or.x.ax / 16;
-
- if ((SW_EMsize <= SW_Blocks) ||
- (((long)(SW_EMstart - 0x100000L) +
- ((long)(SW_Blocks - SW_EMsize) * 16L * 1024L)) < 0L))
- return XMS_error (XMS_Space, 0);
-
- else
- return TRUE;
- }
-
- /* Get the driver interface */
-
- or.x.ax = 0x4310;
- int86x (0x2f, &or, &or, &sr);
- SW_XMS_Driver = (void (far *)())((unsigned long)(sr.es) << 16L | or.x.bx);
-
- /* Support for version 3 of XMS driver */
-
- if ((SW_XMS_Gversion () & 0xff00) < 0x0200)
- return XMS_error ("Warning: %s Version < 2\n", 0);
-
- else if (SW_XMS_Available () < (SW_Blocks * 16))
- return XMS_error (XMS_Space, 0);
-
- else if ((SW_fp = SW_XMS_Allocate (SW_Blocks * 16)) == -1)
- return XMS_error (MS_emsg, errno);
-
- return TRUE;
- }
-
- /* Get the EMS Driver information */
-
- static bool near Get_EMS_Driver (void)
- {
- union REGS or;
- struct SREGS sr;
- char far *sp;
-
- /* Set EMS/XMS handler not defined */
-
- SW_fp = -1;
-
- or.x.ax = 0x3567;
- intdosx (&or, &or, &sr);
-
- sp = (char far *)((unsigned long)(sr.es) << 16L | 10L);
-
- /* If not there - disable */
-
- if (_fmemcmp ("EMMXXXX0", sp, 8) != 0)
- return EMS_error ("Warning: %s not available\n", 0);
-
- or.h.ah = 0x40; /* Check status */
- int86 (0x67, &or, &or);
-
- if (or.h.ah != 0)
- return EMS_error (MS_emsg, or.h.ah);
-
- /* Check version greater than 3.2 */
-
- or.h.ah = 0x46;
- int86 (0x67, &or, &or);
-
- if ((or.h.ah != 0) || (or.h.al < 0x32))
- return EMS_error ("Warning: %s Version < 3.2\n", 0);
-
- /* get page frame address */
-
- or.h.ah = 0x41;
- int86 (0x67, &or, &or);
-
- if (or.h.ah != 0)
- return EMS_error (MS_emsg, or.h.ah);
-
- SW_EMSFrame = or.x.bx; /* Save the page frame */
-
- /* Get the number of pages required */
-
- or.h.ah = 0x43;
- or.x.bx = SW_Blocks;
- int86 (0x67, &or, &or);
-
- if (or.h.ah != 0)
- return EMS_error (MS_emsg, or.h.ah);
-
- /* Save the EMS Handler */
-
- SW_fp = or.x.dx;
-
- /* save EMS page map */
-
- or.h.ah = 0x47;
- or.x.dx = SW_fp;
- int86 (0x67, &or, &or);
-
- return (or.h.ah != 0) ? EMS_error (MS_emsg, or.h.ah) : TRUE;
- }
-
- /* Print EMS error message */
-
- static bool near EMS_error (char *s, int v)
- {
- fprintf (stderr, s, "EMS", v);
- Swap_Mode &= ~(SWAP_EXPAND);
- EMS_Close ();
- return FALSE;
- }
-
- /* Print XMS error message */
-
- static bool near XMS_error (char *s, int v)
- {
- fprintf (stderr, s, "XMS", v);
- Swap_Mode &= ~(SWAP_EXTEND);
- XMS_Close ();
- return FALSE;
- }
-
- /* If the XMS handler is defined - close it */
-
- static int near XMS_Close (void)
- {
- int res = 0;
-
- /* Release XMS page */
-
- if (SW_fp != -1)
- res = SW_XMS_Free (SW_fp);
-
- SW_fp = -1;
- return res;
- }
-
- /* If the EMS handler is defined - close it */
-
- static int near EMS_Close (void)
- {
- union REGS or;
- int res = 0;
-
- if (SW_fp == -1)
- return 0;
-
- /* Restore EMS page */
-
- or.h.ah = 0x48;
- or.x.dx = SW_fp;
- int86 (0x67, &or, &or);
-
- if (or.h.ah != 0)
- res = or.h.al;
-
- or.h.ah = 0x45;
- or.x.dx = SW_fp;
- int86 (0x67, &or, &or);
-
- SW_fp = -1;
- return (res) ? res : or.h.ah;
- }
- #endif
-
- /*
- * Find the location of an executable and return it's full path
- * name
- */
-
- static bool near FindLocationOfExecutable (char *FullPath, char *name)
- {
- register char *sp; /* Path pointers */
- char *ep;
- char *xp1;
- int i;
-
- /* Scan the path for an executable */
-
- sp = ((strchr (name, '/') != (char *)NULL) || (*(name + 1) == ':'))
- ? "" : GET_ENVIRON ("PATH");
-
- do
- {
- sp = BuildNextFullPathName (sp, name, FullPath);
- ep = &FullPath[strlen (FullPath)];
-
- /* Get start of file name */
-
- if ((xp1 = strrchr (FullPath, '/')) == (char *)NULL)
- xp1 = FullPath;
-
- else
- ++xp1;
-
- /* Look up all 3 types */
-
- for (i = 0; i < 3; i++)
- {
- strcpy (ep, Extensions[i]);
-
- if (access (FullPath, X_OK) == 0)
- return TRUE;
- }
- } while (sp != (char *)NULL);
-
- /* Not found */
-
- errno = ENOENT;
- return FALSE;
- }
-
- /*
- * Generate a temporary filename
- */
-
- static char * near GenerateTemporaryFileName (void)
- {
- static char tmpfile[FFNAME_MAX];
- char *tmpdir; /* Points to directory prefix of pipe */
- static int temp_count = 0;
- char *sep = "/";
-
- /* Find out where we should put temporary files */
-
- if (((tmpdir = GET_ENVIRON ("TMP")) == FAIL_ENVIRON) &&
- ((tmpdir = GET_ENVIRON ("HOME")) == FAIL_ENVIRON) &&
- ((tmpdir = GET_ENVIRON ("TMPDIR")) == FAIL_ENVIRON))
- tmpdir = ".";
-
- if (strchr ("/\\", tmpdir[strlen (tmpdir) - 1]) != (char *)NULL)
- sep = "";
-
- /* Get a unique temporary file name */
-
- for (;;)
- {
- sprintf (tmpfile, "%s%ssap%.5u.tmp", tmpdir, sep, temp_count++);
-
- if (access (tmpfile, F_OK) != 0)
- break;
- }
-
- return tmpfile;
- }
-
- /*
- * Extract the next path from a string and build a new path from the
- * extracted path and a file name
- *
- * path_s - Path string
- * file_s - File name string
- * output_s - Output path
- */
-
- static char * near BuildNextFullPathName (register char *path_s,
- register char *file_s, char *output_s)
- {
- register char *s = output_s;
- int fsize = 0;
-
- while (*path_s && (*path_s != ';') && (fsize++ < FFNAME_MAX))
- *s++ = *path_s++;
-
- if ((output_s != s) && (*(s - 1) != '/') && (fsize++ < FFNAME_MAX))
- *s++ = '/';
-
- *s = '\0';
-
- if (file_s != (char *)NULL)
- strncpy (s, file_s, FFNAME_MAX - fsize);
-
- output_s[FFNAME_MAX - 1] = 0;
-
- return (*path_s ? ++path_s : (char *)NULL);
- }
-
- #ifndef OS2
- /*
- * Swap to Memory
- */
-
- static int near SwapToMemory (int mode)
- {
- int res;
- int cr;
-
- /* Swap and close memory handler */
-
- res = SpawnProcess ();
-
- cr = (SW_Mode != 3) ? XMS_Close () : EMS_Close ();
-
- if ((res != -2) && cr) /* Report Close error ? */
- {
- res = -2;
- errno = cr;
- }
-
- if (res == -2)
- (SW_Mode != 3) ? XMS_error (SwapFailed, errno)
- : EMS_error (SwapFailed, errno);
-
- else
- {
- ClearExtendedLineFile ();
- return res;
- }
-
- /* Failed - disabled */
-
- Swap_Mode &= (~mode);
- return res;
- }
-
- /*
- * Swap to disk error
- */
-
- static int near SwapToDiskError (int error, char *ErrorMessage)
- {
-
- /* Close the swap file, if open */
-
- if (SW_fp >= 0)
- close (SW_fp);
-
- /* Clean up */
-
- unlink (Swap_File);
- Swap_File = (char *)NULL;
- Swap_Mode &= (~SWAP_DISK);
- fprintf (stderr, ErrorMessage);
- errno = error;
- return -1;
- }
- #endif
-
- /* Clear Extended command line file */
-
- static void near ClearExtendedLineFile (void)
- {
- if (Extend_file != (char *)NULL)
- {
- unlink (Extend_file);
- free ((char *)Extend_file);
- }
-
- Extend_file = (char *)NULL;
- }
-
- /*
- * Check the program type
- */
-
- static void near CheckProgramMode (char *Pname)
- {
- char *sp, *sp1; /* Line pointers */
- int nFields;
- char *SPname;
- LineFields LF;
- struct ExecutableProcessing *PMode = &ExecProcessingMode;
-
- /* Set not found */
-
- PMode->Flags = EP_NONE;
- PMode->Name = (char *)NULL;
-
- /* Check not a function */
-
- if ((Pname == (char *)NULL) ||
- ((sp = GET_ENVIRON ("EXTENDED_LINE")) == FAIL_ENVIRON))
- return;
-
- /* Get some memory for the input line and the file name */
-
- sp1 = ((sp1 = strrchr (Pname, '/')) == (char *)NULL)
- ? Pname : sp1 + 1;
-
- if ((SPname = strdup (sp1)) == (char *)NULL)
- return;
-
- if ((LF.Line = malloc (LF.LineLength = 200)) == (char *)NULL)
- {
- free (SPname);
- return;
- }
-
- /* Remove terminating .exe etc */
-
- if ((sp1 = strrchr (SPname, '.')) != (char *)NULL)
- *sp1 = 0;
-
- /* Open the file */
-
- if ((LF.FP = fopen (sp, "rt")) == (FILE *)NULL)
- {
- free ((char *)LF.Line);
- free (SPname);
- return;
- }
-
- /* Scan for the file name */
-
- while ((nFields = ExtractFieldsFromLine (&LF)) != -1)
- {
- if (nFields < 2)
- continue;
-
- /* Remove terminating .exe etc */
-
- if ((sp = strrchr (LF.Field[0], '.')) != (char *)NULL)
- *sp = 0;
-
- if (stricmp (LF.Field[0], SPname))
- continue;
-
- /* What type? */
-
- if (stricmp (LF.Field[1], "unix") == 0)
- PMode->Flags = (unsigned char)(EP_UNIXMODE |
- CheckForCommonOptions (&LF, nFields, 2));
-
- else if (stricmp (LF.Field[1], "dos") == 0)
- PMode->Flags = (unsigned char)(EP_DOSMODE |
- CheckForCommonOptions (&LF, nFields, 2));
-
- /* Must have a valid name and we can get memory for it */
-
- else if ((stricmp (LF.Field[1], "environ") == 0) &&
- (nFields >= 3) &&
- ((PMode->Name = strdup (LF.Field[2])) != (char *)NULL))
- {
- PMode->Flags = EP_ENVIRON;
- PMode->FieldSep = 0;
-
- if (nFields >= 4)
- PMode->FieldSep = (unsigned char)strtol (LF.Field[3],
- (char **)NULL, 0);
-
- if (!PMode->FieldSep)
- PMode->FieldSep = ' ';
- }
-
- else
- PMode->Flags = CheckForCommonOptions (&LF, nFields, 1);
-
- break;
- }
-
- fclose (LF.FP);
- free ((char *)LF.Line);
- free (SPname);
- }
-
- /*
- * Check for common fields
- */
-
- static unsigned char near CheckForCommonOptions (LineFields *LF, int nFields,
- int Start)
- {
- unsigned char Flags = 0;
- int i, j;
-
- for (i = Start; i < nFields; i++)
- {
- for (j = 0; j < COMMON_FIELD_COUNT; ++j)
- {
- if (!stricmp (LF->Field[i], CommonFields[j].Name))
- {
- Flags |= CommonFields[j].Flag;
- break;
- }
- }
- }
-
- return Flags;
- }
-
- /*
- * Set the current drive number and return the number of drives.
- */
-
- static void near SetCurrentDrive (unsigned int drive)
- {
- #ifdef OS2
- DosSelectDisk ((USHORT)drive);
- #else
- unsigned int ndrives;
-
- _dos_setdrive (drive, &ndrives);
- #endif
- }
-
- /*
- * Convert UNIX format lines to DOS format if appropriate.
- * Build Environment variable for some programs.
- */
- #ifndef OS2
- static int near SpawnProcess (void)
- {
- void (interrupt far *SW_I00_V) (void); /* Int 00 address */
- void (interrupt far *SW_I23_V) (void); /* Int 23 address*/
- int res;
- #if 0
- union REGS r;
- unsigned char Save;
-
- r.x.ax = 0x3300;
- intdos (&r, &r);
- Save = r.h.al;
- fprintf (stderr, "Break Status: %s (%u)\n", Save ? "on" : "off", Save);
-
- r.x.ax = 0x3301;
- r.h.dl = 1;
- intdos (&r, &r);
- fprintf (stderr, "Break Status: %s (%u)\n", r.h.al ? "on" : "off", r.h.al);
- #endif
-
- /*
- * Save current vectors
- */
-
- SW_I00_V = _dos_getvect (0x00);
- SW_I23_V = _dos_getvect (0x23);
-
- /*
- * Set In shell flag for Interrupt 23, and set to new interrupts
- */
-
- SW_I23_InShell = 0;
- _dos_setvect (0x23, SW_Int23);
- _dos_setvect (0x00, SW_I00_V);
-
- res = SA_spawn (environ);
-
- /*
- * Restore interrupt vectors
- */
-
- _dos_setvect (0x23, SW_I23_V);
-
- #if 0
- r.x.ax = 0x3300;
- intdos (&r, &r);
- fprintf (stderr, "Break Status: %s (%u)\n", r.h.al ? "on" : "off", r.h.al);
- r.x.ax = 0x3301;
- r.h.dl = Save;
- intdos (&r, &r);
- #endif
-
- /*
- * Check for an interrupt
- */
-
- if (SW_intr)
- raise (SIGINT);
-
- return res;
- }
- #endif
-
- /* Set up command line. If the EXTENDED_LINE variable is set, we create
- * a temporary file, write the argument list (one entry per line) to the
- * this file and set the command line to @<filename>. If NOSWAPPING, we
- * execute the program because I have to modify the argument line
- */
-
- static int near BuildCommandLine (char *path, char **argv)
- {
- char **pl = argv;
- int res, fd;
- bool found;
- char *ep;
- char *new_args[3];
-
- /* Translate process name to MSDOS format */
-
- if (GenerateFullExecutablePath (path) == (char *)NULL)
- return -1;
-
- /* Extended command line processing */
-
- Extend_file = (char *)NULL; /* Set no file */
- found = ((ExecProcessingMode.Flags & EP_UNIXMODE) ||
- (ExecProcessingMode.Flags & EP_DOSMODE)) ? TRUE : FALSE;
-
- if ((*(++pl) != (char *)NULL) && found)
- {
- char **pl1 = pl;
-
- /* Check parameters don't contain a re-direction parameter */
-
- while (*pl1 != (char *)NULL)
- {
- if (**(pl1++) == '@')
- {
- found = FALSE;
- break;
- }
- }
-
- /* If we find it - create a temporary file and write the stuff */
-
- if ((found) &&
- ((fd = open (Extend_file = GenerateTemporaryFileName (),
- O_CMASK, 0600)) >= 0))
- {
- Extend_file = strdup (Extend_file);
-
- /* Copy to end of list */
-
- while (*pl != (char *)NULL)
- {
- if (!WriteToExtendedFile (fd, *(pl++)))
- return -1;
- }
-
- /* Completed write OK */
-
- close (fd);
-
- /* Set up DOS_CommandLine[1] to contain the filename */
-
- memset (DOS_CommandLine, 0, CMD_LINE_MAX);
- DOS_CommandLine[1] = ' ';
- DOS_CommandLine[2] = '@';
- strcpy (&DOS_CommandLine[3], Extend_file);
- DOS_CommandLine[0] = (char)(strlen (Extend_file) + 2);
-
- /* Correctly terminate DOS_CommandLine in no swap mode */
-
- #ifndef OS2
- if (!(ExecProcessingMode.Flags & EP_NOSWAP) &&
- (Swap_Mode != SWAP_OFF))
- DOS_CommandLine[DOS_CommandLine[0] + 2] = 0x0d;
- #endif
-
- /* If the name in the file is in upper case - use \ for separators */
-
- if (ExecProcessingMode.Flags & EP_DOSMODE)
- ConvertPathToFormat (&DOS_CommandLine[2]);
-
- /* OK we are ready to execute */
-
- #ifndef OS2
- if ((ExecProcessingMode.Flags & EP_NOSWAP) ||
- (Swap_Mode == SWAP_OFF))
- {
- #endif
- new_args[0] = *argv;
- new_args[1] = &DOS_CommandLine[1];
- new_args[2] = (char *)NULL;
-
- return StartTheProcess (path, new_args);
- #ifndef OS2
- }
-
- else
- return 0;
- #endif
- }
- }
-
- /* Check length of Parameter list */
-
- res = 0;
- DOS_CommandLine[0] = 0;
- DOS_CommandLine[1] = 0x0d;
-
- /* Skip the first parameter and get the length of the rest */
-
- if (*argv != (char *)NULL)
- {
- *(ep = DOS_CommandLine + 1) = 0;
-
- while (*pl != (char *)NULL)
- {
- res += WhiteSpaceLength (*pl, &found);
-
- if (res >= CMD_LINE_MAX)
- {
- errno = E2BIG;
- return -1;
- }
-
- if (found)
- strcat (strcat (strcat (ep, " \""), *(pl++)), "\"");
-
- else
- strcat (strcat (ep, " "), *(pl++));
- }
-
- DOS_CommandLine[res + 1] = 0x0d;
- }
-
- /* Terminate the line and insert the line length */
-
- DOS_CommandLine[0] = (char)res;
-
- /* If swapping disabled - just execute it */
-
- return StartTheProcess (path, argv);
- }
-
- /*
- * Convert the executable path to the full path name
- */
-
- static char * near GenerateFullExecutablePath (char *path)
- {
- char cpath[PATH_MAX + 4];
- char npath[PATH_MAX + NAME_MAX + 4];
- char n1path[PATH_MAX + 4];
- char *p;
- int drive;
-
- /* Get path in DOS format */
-
- ConvertPathToFormat (path);
-
- #ifndef OS2
- strupr (path);
- #else
- if (!IsHPFSFileSystem (path))
- strupr (path);
- #endif
-
- /* Get the current path */
-
- getcwd (cpath, PATH_MAX + 3);
- strcpy (npath, cpath);
-
- /* In current directory ? */
-
- if ((p = strrchr (path, '\\')) == (char *)NULL)
- {
- p = path;
-
- /* Check for a:program case */
-
- if (*(p + 1) == ':')
- {
- p += 2;
-
- /* Get the path of the other drive */
-
- _getdcwd (tolower (*path) - 'a' + 1, npath, PATH_MAX + 3);
- }
- }
-
- /* In root directory */
-
- else if ((p - path) == 0)
- {
- ++p;
- strcpy (npath, "/");
- *npath = *path;
- *npath = *cpath;
- }
-
- else if (((p - path) == 2) && (*(path + 1) == ':'))
- {
- ++p;
- strcpy (npath, "/");
- *npath = *path;
- }
-
- /* Find the directory */
-
- else
- {
- *(p++) = 0;
-
- /* Change to the directory containing the executable */
-
- drive = (*(path + 1) == ':') ? tolower (*path) - 'a' + 1 : 0;
-
- /* Save the current directory on this drive */
-
- _getdcwd (drive, n1path, PATH_MAX + 3);
-
- /* Find the directory we want */
-
- if (chdir (path) < 0)
- return (char *)NULL;
-
- _getdcwd (drive, npath, PATH_MAX + 3); /* Save its full name */
- chdir (n1path); /* Restore the original */
-
- /* Restore our original directory */
-
- if (chdir (cpath) < 0)
- return (char *)NULL;
- }
-
- if (npath[strlen (npath) - 1] != '\\')
- strcat (npath, "\\");
-
- strcat (npath, p);
- return strcpy (path, npath);
- }
-
- /*
- * Write to the Extended File
- */
-
- static bool near WriteToExtendedFile (int fd, char *string)
- {
- char *sp = string;
- char *cp = string;
- bool WriteOk = TRUE;
- int Length;
-
- if (strlen (string))
- {
-
- /* Write the string, converting newlines to backslash newline */
-
- while (WriteOk && (cp != (char *)NULL))
- {
- if ((cp = strchr (sp, '\n')) != (char *)NULL)
- *cp = 0;
-
- if ((Length = strlen (sp)) && (write (fd, sp, Length) != Length))
- WriteOk = FALSE;
-
- if (WriteOk && (cp != (char *)NULL))
- WriteOk = (write (fd, "\\\n", 2) == 2) ? TRUE : FALSE;
-
- sp = cp + 1;
- }
- }
-
- if (WriteOk && (write (fd, "\n", 1) == 1))
- return TRUE;
-
- close (fd);
- ClearExtendedLineFile ();
- errno = ENOSPC;
- return FALSE;
- }
-
- /* Check string for white space */
-
- static size_t near WhiteSpaceLength (char *s, bool *wsf)
- {
- char *os = s;
-
- *wsf = FALSE;
-
- while (*s)
- {
- if (isspace (*s))
- *wsf = TRUE;
-
- ++s;
- }
-
- return (size_t)(s - os) + (*wsf ? 3 : 1);
- }
-
- /*
- * Execute or spawn the process
- */
-
- static int near StartTheProcess (char *path, char **argv)
- {
- #ifdef OS2
- void (*sig_int)(); /* Interrupt signal */
- int RetVal;
- USHORT usType;
- STARTDATA stdata;
- #endif
-
- /* Is this a start session option */
-
- #ifndef OS2
- return ((ExecProcessingMode.Flags & EP_NOSWAP) || (Swap_Mode == SWAP_OFF))
- ? spawnve (P_WAIT, path, argv, environ) : 0;
- #else
-
- /* In OS/2, we need the type of the program because PM programs have to be
- * started in a session (or at least that was the only way I could get them
- * to work).
- */
-
- if (DosQAppType (path, &usType))
- {
- errno = ENOENT;
- return -1;
- }
-
- /* In OS/2, need to set signal to default so child will process it */
-
- else
- {
- sig_int = signal (SIGINT, SIG_DFL);
-
- if ((usType & 3) == WINDOWAPI)
- {
- stdata.Length = sizeof (STARTDATA);
- stdata.Related = FALSE;
- stdata.FgBg = FALSE;
- stdata.TraceOpt = 0;
- stdata.PgmTitle = (char *)NULL;
- stdata.TermQ = 0;
- stdata.Environment = (char *)NULL; /* Build Env */
- stdata.InheritOpt = 0;
- stdata.SessionType = 3;
- stdata.IconFile = (char *)NULL;
- stdata.PgmHandle = 0L;
- stdata.PgmControl = 8;
- stdata.InitXPos = 0;
- stdata.InitYPos = 0;
- stdata.InitXSize = 100;
- stdata.InitYSize = 100;
-
- RetVal = StartTheSession (&stdata, path, argv)
-
- if (stdata.Environment != (char *)NULL)
- free (stdata.Environment);
-
- if (stdata.PgmInputs != (char *)NULL)
- free (stdata.PgmInputs);
- }
-
- else
- RetVal = spawnve (P_WAIT, path, argv, environ);
-
- signal (SIGINT, sig_int);
- }
-
- return RetVal;
- #endif
- }
-
- /*
- * Convert path format to/from UNIX
- */
-
- static char * near ConvertPathToFormat (char *path)
- {
- char *s = path;
-
- while ((path = strchr (path, '/')) != (char *)NULL)
- *path = '\\';
-
- return s;
- }
-
- #ifdef OS2
- static int near StartTheSession (STARTDATA *SessionData, char *path,
- char **argv)
- {
- USHORT usType;
- USHORT idSession;
- USHORT pid;
-
- /* Ensure we always start a PM session in PM */
-
- if (DosQAppType (path, &usType))
- {
- errno = ENOENT;
- return -1;
- }
-
- if ((usType & 3) == WINDOWAPI)
- SessionData->SessionType = 3;
-
- SessionData->PgmName = path;
-
- if ((SessionData->Environment = BuildOS2String (environ, 0)) == (char *)NULL)
- return -1;
-
- if ((SessionData->PgmInputs = BuildOS2String (&argv[1], 0)) == (char *)NULL)
- return -1;
-
- if (!(usType = DosStartSession (SessionData, &idSession, &pid)))
- return 0;
-
- else
- {
- errno = ENOENT;
- return -1;
- }
- }
- #endif
-
- /*
- * Build the OS2 format <value>\0<value>\0 etc \0
- */
-
- static char * near BuildOS2String (char **Array, char sep)
- {
- int i = 0;
- int Length = 0;
- char *Output;
- char *sp, *cp;
-
- while ((sp = Array[i++]) != (char *)NULL)
- Length += strlen (sp) + 1;
-
- Length += 2;
-
- if ((Output = malloc (Length)) == (char *)NULL)
- return (char *)NULL;
-
- i = 0;
- sp = Output;
-
- /* Build the string */
-
- while ((cp = Array[i++]) != (char *)NULL)
- {
- while (*sp = *(cp++))
- ++sp;
-
- *(sp++) = sep;
- }
-
- *sp = 0;
- return Output;
- }
-
- /*
- * Get and process configuration line:
- *
- * <field> = <field> <field> # comment
- *
- * return the number of fields found.
- */
-
- static int ExtractFieldsFromLine (LineFields *fd)
- {
- char *cp;
- int fieldno;
-
- if (fgets (fd->Line, fd->LineLength - 1, fd->FP) == (char *)NULL)
- {
- fclose (fd->FP);
- return -1;
- }
-
- /* Remove the EOL */
-
- if ((cp = strchr (fd->Line, '\n')) != (char *)NULL)
- *cp = 0;
-
- /* Remove the comments at end */
-
- if ((cp = strchr (fd->Line, '#')) != (char *)NULL)
- *cp = 0;
-
- /* Extract the fields */
-
- cp = fd->Line;
- for (fieldno = 0; fieldno < MAX_LINEFIELDS; fieldno++)
- {
- while (isspace (*cp))
- ++cp;
-
- if (!*cp)
- return fieldno;
-
- fd->Field[fieldno] = cp;
-
- /* First field must be followed by equals */
-
- if (!fieldno)
- {
- while (!isspace (*cp) && *cp && (*cp != '='))
- ++cp;
-
- if (*cp && (*cp != '='))
- {
- *(cp++) = 0;
-
- while (isspace (*cp))
- ++cp;
- }
-
- if (*cp != '=')
- return fieldno + 1;
- }
-
- /* Process second and third fields */
-
- else
- {
- while (!isspace (*cp) && *cp)
- ++cp;
- }
-
- *(cp++) = 0;
- }
-
- return fieldno;
- }
-
- /*
- * For multiple model support, we need to transfer to command lines
- * to the swapper in far space
- */
-
- #ifndef OS2
- static void near SetUpSwapper (void)
- {
- /* Transfer path name */
-
- _fstrcpy (path_line, DOS_CommandPath);
-
- /* Transfer command line */
-
- _fmemcpy (cmd_line, DOS_CommandLine, CMD_LINE_MAX);
- }
- #endif
-
- /*
- * Test program
- */
-
- #ifdef TEST
- int main (int argc, char **argv)
- {
- int i;
-
- for (i = 1; i < argc; i++)
- printf ("Result = %d\n", system (argv[i]));
-
- return 0;
- }
- #endif
-