/*** *cenvarg.c - OS/2 set up environment, command line blocks * * Copyright (c) 1986-1991, Microsoft Corporation. All rights reserved. * *Purpose: * defines _cenvarg() - setup environment/command line blocks * *Revision History: * 05-20-86 SKS Module created * 10-03-86 SKS Wasn't clearing final null byte in environment block * 10-13-86 SKS Check for environment segment > 32 KB (esp. > 64 KB) * 10-23-86 SKS New format for C_FILE_INFO for Prot-Mode execution * 12-17-86 SKS Support for new command line format * 01-21-87 BCM Removed DCR475 switch, new command line format official * 07-07-87 JCR Corrected bug in ENV_MAX check * 05-24-88 SJM Removed support for ;C_FILE_INFO for Real-Mode execution * 06-01-88 SJM Added support for .cmd files via comname/cmdname * 12-27-88 JCR Added support for _fileinfo option * 03-08-90 GJF Made calling type _CALLTYPE1, added #include * , removed #include and fixed * the copyright. Also, cleaned up the formatting a bit. * 04-02-90 GJF Added const to arg types. * 08-10-90 SBM Compiles cleanly with -W3 * 09-27-90 GJF New-style function declarator. * 12-06-90 GJF Added Win32 support. That is, support for encoding * _osfinfo[] data into _C_FILE_INFO environment variable. * 01-18-91 GJF ANSI naming. * 02-05-91 SRW Removed usage of _C_FILE_INFO to pass binary data * to child process. [_WIN32_] * 05-07-92 SKS Remove code which stripped the extension from a batch * file while building arguments to CMD.EXE. This was * done long ago (1988) for DOS 3.X, I think. * 10-24-92 SKS Remove special code for batch files - not needed on NT * 07-15-93 SRW Added _capture_argv function * *******************************************************************************/ #include #include #include #include #include #include #include #include #define ENV_MAX 32767 /*** *int _cenvarg(argv, envp, argblk, envblk, name) - set up cmd line/environ * *Purpose: * Set up the block forms of the environment and the command line. * If "envp" is null, "_environ" is used instead. * File handle info is passed in the environment if _fileinfo is !0. * *Entry: * char **argv - argument vector * char **envp - environment vector * char **argblk - pointer to pointer set to malloc'ed space for args * char **envblk - pointer to pointer set to malloc'ed space for env * char *name - name of program being invoked * *Exit: * returns 0 if ok, -1 if fails * stores through argblk and envblk * (calls malloc) * *Exceptions: * *******************************************************************************/ int _CALLTYPE1 _cenvarg ( const char * const *argv, const char * const *envp, char **argblk, char **envblk, const char *name ) { REG1 const char * const *vp; REG2 unsigned tmp; REG3 char *cptr; unsigned arg_len; int cfi_len; /* counts the number of file handles in CFI */ /* * Null environment pointer "envp" means use global variable "_environ" */ #ifdef _CRUISER_ int i; /* loop counter */ if (!envp) envp = _environ; #endif /* _CRUISER_ */ /* * Allocate space for command line string * tmp counts the number of bytes in the command line string * including spaces between arguments * An empty string is special -- 2 bytes */ for (vp = argv, tmp = 2; *vp; tmp += strlen(*vp++) + 1) if( tmp > ENV_MAX ) break; /* * Make sure there are not already > 32 KB in strings */ if ((arg_len = tmp) >= ENV_MAX) { *envblk = NULL; errno = E2BIG; _doserrno = E_badenv; return(-1); } /* * Allocate space for the command line plus 2 null bytes */ if ( (*argblk = malloc(tmp)) == NULL) { *envblk = NULL; errno = ENOMEM; _doserrno = E_nomem; return(-1); } /* * Allocate space for environment strings * tmp counts the number of bytes in the environment strings * including nulls between strings * Also add "_C_FILE_INFO=" string */ #ifdef _WIN32_ if (envp) #endif /* _WIN32_ */ for (vp = envp, tmp = 2; *vp; tmp += strlen(*vp++) + 1) if( tmp > ENV_MAX ) break; #ifdef _CRUISER_ if (_fileinfo) for (cfi_len = _nfile; cfi_len && !_osfile[cfi_len-1]; cfi_len--) ; else cfi_len = 0; /* no _C_FILE_INFO */ /* * mode-independent C-FILE-INFO calculation */ if (cfi_len) /* Add 1 (each) for the "=" & null byte */ /* Plus 2 bytes for each value in _osfile */ tmp += /* strlen(_acfinfo) */ CFI_LENGTH + 2 + cfi_len + cfi_len; #else /* ndef _CRUISER_ */ #ifdef _WIN32_ /* ** The _osfile and _osfhnd arrays are passed as binary data in ** dospawn.c */ cfi_len = 0; /* no _C_FILE_INFO */ #else /* ndef _WIN32_ */ #error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! #endif /* _WIN32_ */ #endif /* _CRUISER_ */ #ifdef _WIN32_ if (!envp) *envblk = NULL; else { #endif /* _WIN32_ */ /* * Check for too many strings to be placed in the environment * Increment tmp for final null byte after environment strings * "tmp + arg_len + strlen(name) + 1" must also be < ENV_MAX * Do (long) comparison in case tmp > ENV_MAX from C_FILE_INFO */ if( (long) tmp + arg_len + strlen(name) > ENV_MAX - 1 ) { free(*argblk); *argblk = NULL; errno = E2BIG; _doserrno = E_badenv; return(-1); } /* * Allocate space for the environment strings plus extra null byte */ if( !(*envblk = malloc(tmp)) ) { free(*argblk); *argblk = NULL; errno = ENOMEM; _doserrno = E_nomem; return(-1); } #ifdef _WIN32_ } #endif /* _WIN32_ */ /* * Build the command line by concatenating the argument strings * with spaces between, and two null bytes at the end * NOTE: The argv[0] argument is followed by a null. */ cptr = *argblk; vp = argv; if (!*vp) /* Empty argument list ? */ ++cptr; /* just two null bytes */ else { /* argv[0] must be followed by a null */ strcpy(cptr, *vp); cptr += strlen(*vp++) + 1; } while( *vp ) { strcpy(cptr, *vp); cptr += strlen(*vp++); *cptr++ = ' '; } * cptr = cptr[ -1 ] = '\0'; /* remove extra blank, add double null */ #ifdef _WIN32_ if (envp) { #endif /* _WIN32_ */ /* * Build the environment block by concatenating the environment strings * with nulls between and two null bytes at the end * C_FILE_INFO is stored as if it were an environment string */ cptr = *envblk; vp = envp; if( !(*vp || cfi_len) ) /* No environment strings? */ *cptr++ = '\0'; /* just two null bytes */ while( *vp ) { strcpy(cptr, *vp); cptr += 1 + strlen(*vp++); } #ifdef _CRUISER_ if(cfi_len) { strcpy(cptr,_acfinfo); cptr += /* strlen(_acfinfo) */ CFI_LENGTH; i = cfi_len; for(tmp = 0; i--; ++tmp) { *cptr++ = (char)(((_osfile[tmp] >> 4) & 0xF) + 'A'); *cptr++ = (char)((_osfile[tmp] & 0xF) + 'A'); } *cptr++ = '\0'; } #else /* ndef _CRUISER_ */ #ifdef _WIN32_ /* ** The _osfile and _osfhnd arrays are passed as binary data in ** dospawn.c */ #else /* ndef _WIN32_ */ #error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! #endif /* _WIN32_ */ #endif /* _CRUISER_ */ #ifdef _WIN32_ } #endif /* _WIN32_ */ /* * Extra null terminates the segment */ *cptr = '\0'; return(0); } /*** *int _capture_argv(arglist, static_argv, max_static_entries) - set up argv array * for exec?? functions * *Purpose: * Set up the argv array for the exec?? functions by captures the arguments * from the passed va_list into the static_argv array. If the size of the * static_argv array as specified by the max_static_entries parameter is * not large enough, then allocates a dynamic array to hold the arguments. * Return the address of the final argv array. If NULL then not enough * memory to hold argument array. If different from static_argv parameter * then call must free the return argv array when done with it. * * The scan of the arglist is terminated when a NULL argument is reached. * The terminating NULL parameter is stored in the resulting argv array. * *Entry: * va_list *arglist - pointer to variable length argument list. * char *firstarg - first argument to store in array * char **static_argv - pointer to static argv to use. * size_t max_static_entries - maximum number of entries that can be placed * in static_argv array. * *Exit: * returns NULL if no memory. * Otherwise returns pointer to argv array. * (sometimes calls malloc) * *Exceptions: * *******************************************************************************/ char ** _CALLTYPE1 _capture_argv( va_list *arglist, const char *firstarg, char **static_argv, size_t max_static_entries ) { char ** argv; char * nextarg; size_t i; size_t max_entries; nextarg = (char *)firstarg; argv = static_argv; max_entries = max_static_entries; i = 0; for (;;) { if (i >= max_entries) { if (argv == static_argv) argv = malloc((max_entries * 2) * sizeof(char *)); else argv = realloc(argv, (max_entries * 2) * sizeof(char *)); if (argv == NULL) break; max_entries += max_entries; } argv[ i++ ] = nextarg; if (nextarg == NULL) break; nextarg = va_arg(*arglist, char *); } return argv; }