/* MS-DOS stdargv Function * * MS-DOS stdargv - 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. * * $Header: /usr/users/istewart/src/shell/sh2.1/RCS/stdargv.c,v 2.2 1992/12/14 11:12:37 istewart Exp $ * * $Log: stdargv.c,v $ * 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). * * To get the OS2 version, compile with -DOS2 * * Author: * Ian Stewartson * Data Logic, Queens House, Greenhill Way * Harrow, Middlesex HA1 1YR, UK. * istewart@datlog.co.uk or ukc!datlog!istewart */ #include /* MS-DOS type definitions */ #include /* File status definitions */ #include /* Standard I/O delarations */ #include /* Standard library functions */ #include /* Error number declarations */ #ifdef OS2 #define INCL_DOSSESMGR #define INCL_DOSMEMMGR #define INCL_DOSPROCESS #define INCL_WINSWITCHLIST #include /* OS2 functions declarations */ #else #include /* DOS functions declarations */ #include /* BIOS functions declarations */ #endif #include /* Character type declarations */ #include /* String library functions */ #include /* String library functions */ #include /* File Control Declarations */ #include /* Direction I/O functions */ #include #include /* Globbing functions */ /* * DATA DEFINITIONS: */ #define MAX_LINE 160 /* Max line length */ #define S_ENTRY sizeof (char *) /* * DATA DECLARATIONS: */ #ifdef MSDOS extern void _setargv (void); 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"; extern char far *_pgmptr; /* Program name */ extern char **__argv; /* Current argument address */ extern int __argc; /* Current argument count */ #ifdef OS2 extern ushort _aenvseg; /* Environment seg */ extern ushort _acmdln; /* Command line offset */ #endif /* * MODULE ABSTRACT: _setargv * * UNIX like command line expansion */ void _setargv () { char far *s; /* Temporary string pointer */ # ifndef M_I86LM char buf[MAX_LINE]; /* Temporary space */ # endif #ifdef OS2 char far *argvp = (char far *)((((long)_aenvseg) << 16)); ushort off = _acmdln; HSWITCH hswitch; SWCNTRL swctl; PIDINFO PidInfo; char *cp; while (--off) { if (argvp[off - 1] == 0) break; } /* Add program name */ _pgmptr = &argvp[off]; if (argvp[_acmdln] == 0) { # ifndef M_I86LM cp = buf; s = _pgmptr; while (*(cp++) = *(s++)) continue; _Ex_AddArgument (_Ex_ConvertToUnixFormat (buf)); # else _Ex_AddArgument (_Ex_ConvertToUnixFormat (_pgmptr)); # endif } else { argvp += _acmdln; # ifndef M_I86LM 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 s = argvp; _Ex_AddArgument (_Ex_ConvertToUnixFormat (argvp)); argvp += strlen (argvp) + 1; /* * 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) { if (*argvp == '~') _Ex_AddArgument (argvp + 1); else _Ex_AddArgument (argvp); argvp += strlen (argvp) + 1; } } else _Ex_CommandLine (argvp); # endif /* Set up the Window name. Give up if it does not work. */ if (!DosGetPID (&PidInfo) && ((hswitch = WinQuerySwitchHandle (0, PidInfo.pid))) && (!WinQuerySwitchEntry (hswitch, &swctl))) { if ((cp = strrchr (__argv[0], '/')) == (char *)NULL) cp = __argv[0]; else ++cp; strncpy (swctl.szSwtitle, cp, MAXNAMEL); swctl.szSwtitle[MAXNAMEL] = 0; if ((cp = strrchr (swctl.szSwtitle, '.')) != (char *)NULL) *cp = 0; WinChangeSwitchEntry (hswitch, &swctl); } } #else /* Set up pointer to command line */ char far *argvp = (char far *)((((long)_psp) << 16) + 0x081L); unsigned int envs = *(int far *)((((long)_psp) << 16) + 0x02cL); /* Command line can be null or 0x0d terminated - convert to null */ s = argvp; while (*s && (*s != 0x0d)) ++s; if (*s == 0x0d) *s = 0; /* Set up global parameters and expand */ __argc = 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 */ _pgmptr = s; # ifndef M_I86LM cp = buf; while (*(cp++) = *(s++)) continue; _Ex_AddArgument (_Ex_ConvertToUnixFormat (buf)); s = argvp; cp = buf; while (*(cp++) = *(s++)) continue; _Ex_CommandLine (buf); # else _Ex_AddArgument (_Ex_ConvertToUnixFormat (s)); _Ex_CommandLine (argvp); # endif #endif _Ex_AddArgument ((char *)NULL); --__argc; } /* * 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 *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)) != NULL) { spos++; if (spos[-2] != '\\') break; } else spos = &spos[strlen (cpos)]; } while (*spos); fn = _Ex_GetSpace (spos - cpos - 2, cpos + 1); } /* 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 */ if ((fp = fopen (file + 1, "rt")) == NULL) { _Ex_ExpandField (file); return; } /* 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 (__argc == 0) __argv = (char **)malloc (50 * S_ENTRY); else if ((__argc % 50) == 0) __argv = (char **)realloc (__argv, (__argc + 50) * S_ENTRY); if (__argv == (char **)NULL) _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL); if (Argument == (char *)NULL) __argv[__argc++] = (char *)NULL; else __argv[__argc++] = _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++) = '/'; #ifndef OS2 return strlwr (sp); #else if (!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 (*)())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; } #endif /* * Test main program */ #ifdef TEST int main (int argc, char **argv) { int i; for (i = 0; i < argc; i++) printf ("Arg %d = |%s|\n", i, argv[i]); return 0; } #endif