Rev 227 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/* MS-DOS stdargv Function** MS-DOS stdargv - Copyright (c) 1990,4 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.** $Header: /cvsroot/device/DEVL/UTILS/SH/STDARGV.C,v 1.1 2002/08/02 06:49:33 adamy Exp $** $Log: STDARGV.C,v $* Revision 1.1 2002/08/02 06:49:33 adamy* imported (reference only)** Revision 1.1 2001/07/20 05:55:43 ayoung* WIN32 support** Revision 1.1.1.1 1999/12/02 01:11:12 gordonh* UTIL** Revision 2.9 1994/08/25 20:49:11 istewart* MS Shell 2.3 Release** Revision 2.8 1994/02/01 10:25:20 istewart* Release 2.3 Beta 2, including first NT port** Revision 2.7 1994/01/20 14:51:43 istewart* Release 2.3 Beta 1** Revision 2.6 1994/01/11 17:55:25 istewart* Release 2.3 Beta 0 patches** Revision 2.5 1993/08/25 16:04:22 istewart* Add support for MSC 6 which requires osmajor and osminor to be set up* for MSDOS.** Revision 2.4 1993/06/14 10:59:58 istewart* More changes for 223 beta** Revision 2.3 1993/06/02 09:54:21 istewart* Beta 223 Updates - see Notes file** Revision 2.2 1992/12/14 11:12:37 istewart* BETA 215 Fixes and 2.1 Release** Revision 2.1 1992/11/06 10:03:44 istewart* 214 Beta test updates** Revision 2.0 1992/04/13 17:39:09 Ian_Stewartson* MS-Shell 2.0 Baseline release**** MODULE DEFINITION:** This function expandes the command line parameters in a UNIX like manner.* Wild character *?[] are allowed in file names. @filename causes command lines* to be read from filename. Strings between " or ' are not expanded. All* entries in the array are malloced.** This function replaces the standard Microsoft C5.1 & C6.0 C Run-Time* start up line processing function (_setargv in stdargv.obj).** For OS/2 2.x, this function replaces the standard IBM C Set/2 C Run-Time* start up line processing function (_setuparg in stdargv.obj).** For Turbo C, this function replaces the standard Borland C Run-Time* start up line processing function (_setargv).** For WatCom C, this function replaces the standard WatCom C Run-Time* start up line processing function (__Init_Argv).** To get the OS2 16-bit version, compile with -DOS2* To get the OS2 32-bit version, compile with -D__OS2__* To get the NT 32-bit version, compile with -DWIN32** Author:* Ian Stewartson* Data Logic, Queens House, Greenhill Way* Harrow, Middlesex HA1 1YR, UK.* istewart@datlog.co.uk or ukc!datlog!istewart*/#include <sys/types.h> /* MS-DOS type definitions */#include <sys/stat.h> /* File status definitions */#include <stdio.h> /* Standard I/O delarations */#include <stdlib.h> /* Standard library functions */#include <errno.h> /* Error number declarations */#if defined (OS2) || defined (__OS2__)# define INCL_DOSSESMGR# define INCL_DOSMEMMGR# define INCL_DOSPROCESS# define INCL_DOSMODULEMGR# define INCL_WINSWITCHLIST# include <os2.h> /* OS2 functions declarations */#elif defined (WIN32)# include <windows.h> /* WIN NT functions declarations */#else# include <dos.h> /* DOS functions declarations */# include <bios.h> /* BIOS functions declarations */#endif#include <ctype.h> /* Character type declarations */#include <string.h> /* String library functions */#include <limits.h> /* String library functions */#include <fcntl.h> /* File Control Declarations */#include <dirent.h> /* Direction I/O functions */#include <unistd.h>#include <glob.h> /* Globbing functions *//** DATA DEFINITIONS:*/#define MAX_LINE 160 /* Max line length */#define S_ENTRY sizeof (char *)#ifndef TRUE#define FALSE 0#define TRUE 1#endif/** DATA DECLARATIONS:*/static void _Ex_CommandLine (char *); /* Expand file */static void _Ex_ExpandIndirectFile (char *);static char *_Ex_GetSpace (int, char *); /* Get space */static void _Ex_AddArgument (char *); /* Add argument */static char *_Ex_SkipWhiteSpace (char *); /* Skip spaces */static char *_Ex_ConvertToUnixFormat (char *);static void _Ex_ExpandField (char *); /* Split file name */static void _Ex_FatalError (int, char *, char *);static char *_Ex_ConvertEnvVariables (char *);static char *_EX_OutOfMemory = "%s: %s\n";#if defined (OS2) || defined (__OS2__)static void _Ex_ProcessEMXArguments (char *);static void _Ex_SetUpWindowName (void);#elif defined (WIN32)static void _Ex_SetUpWindowName (void);#endif/** Command Line pointers*/#if defined (__OS2__)# define ARG_ARRAY _argv# define ARG_COUNT _argc# define ENTRY_POINT _setuparg#elif defined (__TURBOC__)# define ARG_ARRAY _C0argv# define ARG_COUNT _C0argc# define ENTRY_POINT _setargv#elif defined (__WATCOMC__)# define ARG_ARRAY ___Argv# define ARG_COUNT ___Argc# define ENTRY_POINT __Init_Argv#else# define ARG_ARRAY __argv# define ARG_COUNT __argc# define ENTRY_POINT _setargv#endifextern void ENTRY_POINT (void);extern char **ARG_ARRAY; /* Current argument address */extern int ARG_COUNT; /* Current argument count */extern bool IsHPFSFileSystem (char *);/** General OS independent start of the command line and program name.*/#if defined (__OS2__) || defined(__WATCOMC__)char *_ACmdLine;char *_APgmName; /* Program name */#else# if defined (OS2)extern ushort far _aenvseg;extern ushort far _acmdln;# endifchar far *_ACmdLine;char far *_APgmName; /* Program name */#endif/** MODULE ABSTRACT: _setargv** UNIX like command line expansion*//** OS/2 2.x (32-bit) version*/#if defined (__OS2__)void ENTRY_POINT (void){char *argvp;APIRET rc;PTIB ptib;PPIB ppib;char *MName;/* Get the command line and program name */if (rc = DosGetInfoBlocks (&ptib, &ppib)){fprintf (stderr, "DosGetInfoBlocks: Cannot find command line (%d)\n",rc);exit (1);}if ((MName = malloc (PATH_MAX + NAME_MAX + 3)) == (char *)NULL)_Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);if (rc = DosQueryModuleName (ppib->pib_hmte, NAME_MAX + PATH_MAX + 2,MName)){fprintf (stderr, "DosQueryModuleName: Cannot get program name (%d)\n",rc);exit (1);}/* Save the program name and process the command line */_APgmName = MName;_Ex_ProcessEMXArguments (ppib->pib_pchcmd);/* Set up the Window name. Give up if it does not work. */_Ex_SetUpWindowName ();_Ex_AddArgument ((char *)NULL);--ARG_COUNT;}#elif defined (OS2)/** OS/2 1.x (16-bit) version*/void ENTRY_POINT (void){# if !defined (M_I86LM) && !defined (__LARGE__)char far *s; /* Temporary string pointer */char buf[MAX_LINE]; /* Temporary space */char *cp;# endifchar far *argvp = (char far *)((((long)_aenvseg) << 16));ushort off = _acmdln;while (--off){if (argvp[off - 1] == 0)break;}/* Add program name */_APgmName = &argvp[off];if (argvp[_acmdln] == 0){# if !defined (M_I86LM) && !defined (__LARGE__)cp = buf;s = _APgmName;while (*(cp++) = *(s++))continue;_Ex_AddArgument (_Ex_ConvertToUnixFormat (buf));# else_Ex_AddArgument (_Ex_ConvertToUnixFormat (_APgmName));# endif}else{argvp += _acmdln;# if !defined (M_I86LM) && !defined (__LARGE__)cp = buf;s = argvp;while (*(cp++) = *(s++))continue;off = strlen (buf);_Ex_AddArgument (_Ex_ConvertToUnixFormat (buf));argvp += off + 1;cp = buf;s = argvp;while (*(cp++) = *(s++))continue;_Ex_CommandLine (buf);# else_Ex_ProcessEMXArguments (argvp);# endif}/* Set up the Window name. Give up if it does not work. */_Ex_SetUpWindowName ();_Ex_AddArgument ((char *)NULL);--ARG_COUNT;}#elif defined (WIN32)/** Windows NT version*/void _cdecl ENTRY_POINT (void){char *cline = GetCommandLine ();char *MName;#ifdef TESTprintf ("Got Command line as |%s|\n", cline);#endif/* Get the command line and program name */if (!*cline){if ((MName = malloc (MAX_PATH)) == (char *)NULL)_Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);if (!GetModuleFileName (0, MName, MAX_PATH)){fprintf (stderr, "GetModuleFileName: Cannot get program name (%ld)\n",GetLastError ());exit (1);}cline = MName;#ifdef TESTprintf ("Got command program name |%s|\n", cline);#endif}/* Save the program name and process the command line */_Ex_CommandLine (_ACmdLine = cline);_Ex_AddArgument ((char *)NULL);_APgmName = _Ex_ConvertToUnixFormat (ARG_ARRAY[0]);/* Set up the Window name. Give up if it does not work. */_Ex_SetUpWindowName ();--ARG_COUNT;}#elif defined (__WATCOMC__)/** WATCOMC version*/void ENTRY_POINT(void){extern void __setenvp(void); /* A WATCOM thing which sets up environ */extern char *_LpPgmName; /* the program name */extern char *_LpCmdLine; /* the raw cmdline */__setenvp();_APgmName = _LpCmdLine;_ACmdLine = _LpPgmName;/* Set up global parameters and expand */ARG_COUNT = 0;_Ex_AddArgument(_Ex_ConvertToUnixFormat(_APgmName));_Ex_CommandLine(_ACmdLine);_Ex_AddArgument((char *)NULL);--ARG_COUNT;}#else/** MSDOS version*/void ENTRY_POINT (void){char far *s; /* Temporary string pointer */union REGS r;# if !defined (M_I86LM) && !defined (__LARGE__)char buf[MAX_LINE]; /* Temporary space */# endif/* Set up pointer to command line */unsigned int envs = *(int far *)((((long)_psp) << 16) + 0x02cL);unsigned int Length;/* For reasons that escape me, MSC 6.0 does sets up _osmajor and _osminor* in the command line parser!*/#if !defined(WIN32)r.h.ah = 0x30;intdos (&r, &r);_osminor = r.h.ah;_osmajor = r.h.al;#endif/* Check the length */_ACmdLine = (char far *)((((long)_psp) << 16) + 0x080L);if ((Length = (unsigned int)*(_ACmdLine++)) > 127)Length = 127;_ACmdLine[Length] = 0;/* Command line can be null or 0x0d terminated - convert to null */if ((s = strchr (_ACmdLine, 0x0d)) != (char *)NULL)*s = 0;#ifdef TESTprintf ("_psp line = <%s>\n", _ACmdLine);#endif/* Set up global parameters and expand */ARG_COUNT = 0;/* Get the program name */if ((_osmajor <= 2) || (envs == 0))s = "unknown";/* In the case of DOS 3+, we look in the environment space */else{s = (char far *)(((long)envs) << 16);while (*s){while (*(s++) != 0)continue;}s += 3;}/* Add the program name */_APgmName = s;# if !defined (M_I86LM) && !defined (__LARGE__)cp = buf;while (*(cp++) = *(s++))continue;_Ex_AddArgument (_Ex_ConvertToUnixFormat (buf));s = _ACmdLine;cp = buf;while (*(cp++) = *(s++))continue;_Ex_CommandLine (buf);# else_Ex_AddArgument (_Ex_ConvertToUnixFormat (s));_Ex_CommandLine (_ACmdLine);# endif_Ex_AddArgument ((char *)NULL);--ARG_COUNT;}#endif/** Expand the DOS Command line*/static void _Ex_CommandLine (argvp)char *argvp; /* Line to expand */{char *spos; /* End of string pointer */char *cpos; /* Start of string pointer */char *tpos;char *fn; /* Extracted file name string *//* Search for next separator */spos = argvp;while (*(cpos = _Ex_SkipWhiteSpace (spos))){/* Extract string argument */if ((*cpos == '"') || (*cpos == '\'')){spos = cpos + 1;do{if ((spos = strchr (spos, *cpos)) != (char *)NULL){spos++;if (spos[-2] != '\\')break;}elsespos = &spos[strlen (cpos)];} while (*spos);fn = _Ex_GetSpace (spos - cpos - 2, cpos + 1);/* Remove escaped characters */tpos = fn;while ((tpos = strchr (tpos, *cpos)) != (char *)NULL)strcpy (tpos - 1, tpos);}/* Extract normal argument */else{spos = cpos;while (!isspace (*spos) && *spos)spos++;fn = _Ex_GetSpace (spos - cpos, cpos);}/* Process argument */if (*cpos != '\'')fn = _Ex_ConvertEnvVariables (fn);switch (*cpos){case '@': /* Expand file */_Ex_ExpandIndirectFile (fn);break;case '"': /* Expand string */case '\'':_Ex_AddArgument (fn);break;default: /* Expand field */_Ex_ExpandField (fn);}free (fn);}}/* Expand an indirect file Argument */static void _Ex_ExpandIndirectFile (file)char *file; /* Expand file name */{FILE *fp; /* File descriptor */char *EoLFound; /* Pointer */int c_maxlen = MAX_LINE;char *line; /* Line buffer */char *eolp;/* If file open fails, expand as a field */#ifdef __OS2__if ((fp = fopen (file + 1, "r")) == NULL)#elseif ((fp = fopen (file + 1, "rt")) == NULL)#endif_Ex_FatalError (errno, "%s: Cannot open re-direct file - %s (%s)\n",file + 1);/* Grab some memory for the line */if ((line = malloc (c_maxlen)) == (char *)NULL)_Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);/* For each line in the file, remove EOF characters and add argument */while (fgets (line, c_maxlen, fp) != (char *)NULL){EoLFound = strchr (line, '\n');eolp = line;/* Handle continuation characters */while (TRUE){/* Check for a continuation character */if (((EoLFound = strchr (eolp, '\n')) != (char *)NULL) &&(*(EoLFound - 1) == '\\')){*(EoLFound - 1) = '\n';*EoLFound = 0;EoLFound = (char *)NULL;}else if (EoLFound == (char *)NULL)EoLFound = strchr (line, 0x1a);if (EoLFound != (char *)NULL)break;/* Find the end of the line */c_maxlen = strlen (line);/* Get some more space */if ((line = realloc (line, c_maxlen + MAX_LINE)) == (char *)NULL)_Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);eolp = &line[c_maxlen];if (fgets (eolp, MAX_LINE, fp) == (char *)NULL)break;}/* Terminate the line and add it to the argument list */if (EoLFound != (char *)NULL)*EoLFound = 0;_Ex_AddArgument (line);}if (ferror(fp))_Ex_FatalError (errno, "%s: %s (%s)\n", file + 1);free (line);fclose (fp);/* Delete tempoary files */if (((line = strrchr (file + 1, '.')) != (char *)NULL) &&(stricmp (line, ".tmp") == 0))unlink (file + 1); /* Delete it */}/* Get space for an argument name */static char *_Ex_GetSpace (length, in_s)int length; /* String length */char *in_s; /* String address */{char *out_s; /* Malloced space address */if ((out_s = malloc (length + 1)) == (char *)NULL)_Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);/* Copy string for specified length */strncpy (out_s, in_s, length);out_s[length] = 0;return (out_s);}/* Append an argument to the array */static void _Ex_AddArgument (Argument)char *Argument; /* Argument to add */{if (ARG_COUNT == 0)ARG_ARRAY = (char **)malloc (50 * S_ENTRY);else if ((ARG_COUNT % 50) == 0)ARG_ARRAY = (char **)localRealloc (ARG_ARRAY, (ARG_COUNT + 50) * S_ENTRY);if (ARG_ARRAY == (char **)NULL)_Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);if (Argument == (char *)NULL)ARG_ARRAY[ARG_COUNT++] = (char *)NULL;elseARG_ARRAY[ARG_COUNT++] = _Ex_GetSpace (strlen (Argument), Argument);}/* Skip over spaces */static char *_Ex_SkipWhiteSpace (a)char *a; /* String start address */{while (isspace(*a))a++;return (a);}/* Convert name to Unix format */static char *_Ex_ConvertToUnixFormat (a)char *a;{char *sp = a;while ((a = strchr (a, '\\')) != (char *)NULL)*(a++) = '/';#if !defined (OS2) && !defined (__OS2__) && !defined (WIN32)return strlwr (sp);#elseif (!IsHPFSFileSystem (sp))strlwr (sp);return sp;#endif}/* Find the location of meta-characters. If no meta, add the argument and* return NULL. If meta characters, return position of end of directory* name. If not multiple directories, return -1*/static void _Ex_ExpandField (file)char *file;{int i = 0;glob_t gp;if (strpbrk (file, "?*[]\\") == (char *)NULL){_Ex_AddArgument (file);return;}if (glob (file, GLOB_NOCHECK, (int (_CDECL *)(char *, int))NULL , &gp))_Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);i = 0;while (i < gp.gl_pathc)_Ex_AddArgument (gp.gl_pathv[i++]);globfree (&gp);}/* Fatal errors */static void _Ex_FatalError (ecode, format, para)int ecode;char *format;char *para;{fprintf (stderr, format, "stdargv", strerror (ecode), para);exit (1);}/* Process Environment - note that field is a malloc'ed field */static char *_Ex_ConvertEnvVariables (field)char *field;{char *sp, *cp, *np, *ep;char save;int b_flag;sp = field;/* Replace any $ strings */while ((sp = strchr (sp, '$')) != (char *)NULL){/* If ${...}, find the terminating } */if (*(cp = ++sp) == '{'){b_flag = 1;++cp;while (*cp && (*cp != '}'))cp++;}/* Else must be $..., find the terminating non-alphanumeric */else{b_flag = 0;while (isalnum (*cp))cp++;}/* Grab the environment variable */if (cp == sp)continue;/* Get its value */save = *cp;*cp = 0;ep = getenv (sp + b_flag);*cp = save;if (ep != (char *)NULL){np = _Ex_GetSpace (strlen(field) - (cp - sp) + strlen (ep) - 1, field);strcpy (&np[sp - field - 1], ep);free (field);strcpy ((sp = &np[strlen(np)]), cp + b_flag);field = np;}}return field;}/** Handle EMX style arguments*/#if defined (OS2) || defined (__OS2__)static void _Ex_ProcessEMXArguments (char *argvp){char *cp;char *s = argvp;_Ex_AddArgument (_Ex_ConvertToUnixFormat (argvp));argvp += strlen (argvp) + 1;_ACmdLine = argvp;#ifdef TESTprintf ("argvp line = <%s>\n", _ACmdLine);#endif/** Add support in OS2 version for Eberhard Mattes EMX interface to commands.*/if ((*argvp) && (*(cp = argvp + strlen (argvp) + 1) == '~') &&(strcmp (s, _Ex_ConvertToUnixFormat (cp + 1)) == 0)){/* Skip over the program name at string 2 to the start of the first* argument at string 3*/argvp += strlen (argvp) + 1;argvp += strlen (argvp) + 1;while (*argvp){cp = (*argvp == '~') ? argvp + 1 : argvp;if (*cp == '@')_Ex_ExpandIndirectFile (cp);else_Ex_AddArgument (cp);argvp += strlen (argvp) + 1;}}else_Ex_CommandLine (argvp);}/** Set up the Window Name*/static void _Ex_SetUpWindowName (void){HSWITCH hswitch;SWCNTRL swctl;char *cp;if (((hswitch = WinQuerySwitchHandle (0, getpid ()))) &&(!WinQuerySwitchEntry (hswitch, &swctl))){if ((cp = strrchr (ARG_ARRAY[0], '/')) == (char *)NULL)cp = ARG_ARRAY[0];else++cp;strncpy (swctl.szSwtitle, cp, MAXNAMEL);swctl.szSwtitle[MAXNAMEL] = 0;if ((cp = strrchr (swctl.szSwtitle, '.')) != (char *)NULL)*cp = 0;WinChangeSwitchEntry (hswitch, &swctl);}}#endif/** Windows NT version*/#ifdef WIN32static void _Ex_SetUpWindowName (void){char *cp;if ((cp = strrchr (ARG_ARRAY[0], '/')) == (char *)NULL)cp = ARG_ARRAY[0];else++cp;SetConsoleTitle (cp);}#endif/** Test main program*/#ifdef TESTint main (int argc, char **argv){int i;printf ("_ACmdLine = <%s>\n", _ACmdLine);for (i = 0; i < argc; i++)printf ("Arg %d = |%s|\n", i, argv[i]);return 0;}#endif