home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / cenvarg.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  10KB  |  330 lines

  1. /***
  2. *cenvarg.c - set up environment, command line blocks
  3. *
  4. *       Copyright (c) 1986-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines _cenvarg() - setup environment/command line blocks
  8. *
  9. *******************************************************************************/
  10.  
  11. #include <cruntime.h>
  12. #include <stdio.h>
  13. #include <errno.h>
  14. #include <msdos.h>
  15. #include <stdlib.h>
  16. #include <stdarg.h>
  17. #include <internal.h>
  18. #include <string.h>
  19. #include <awint.h>
  20. #include <tchar.h>
  21. #include <dbgint.h>
  22.  
  23. #define ENV_MAX 32767
  24.  
  25. /* local tchar */
  26. #ifdef WPRFLAG
  27. #define _tenvptr    _wenvptr
  28. #else  /* WPRFLAG */
  29. #define _tenvptr    _aenvptr
  30. #endif  /* WPRFLAG */
  31.  
  32. /***
  33. *int _cenvarg(argv, envp, argblk, envblk, name) - set up cmd line/environ
  34. *
  35. *Purpose:
  36. *       Set up the block forms of  the environment and the command line.
  37. *       If "envp" is null, "_environ" is used instead.
  38. *       File handle info is passed in the environment if _fileinfo is !0.
  39. *
  40. *Entry:
  41. *       _TSCHAR **argv   - argument vector
  42. *       _TSCHAR **envp   - environment vector
  43. *       _TSCHAR **argblk - pointer to pointer set to malloc'ed space for args
  44. *       _TSCHAR **envblk - pointer to pointer set to malloc'ed space for env
  45. *       _TSCHAR *name    - name of program being invoked
  46. *
  47. *Exit:
  48. *       returns 0 if ok, -1 if fails
  49. *       stores through argblk and envblk
  50. *       (calls malloc)
  51. *
  52. *Exceptions:
  53. *
  54. *******************************************************************************/
  55.  
  56. #ifdef WPRFLAG
  57. int __cdecl _wcenvarg (
  58. #else  /* WPRFLAG */
  59. int __cdecl _cenvarg (
  60. #endif  /* WPRFLAG */
  61.         const _TSCHAR * const *argv,
  62.         const _TSCHAR * const *envp,
  63.         _TSCHAR **argblk,
  64.         _TSCHAR **envblk,
  65.         const _TSCHAR *name
  66.         )
  67. {
  68.         REG1 const _TSCHAR * const *vp;
  69.         REG2 unsigned tmp;
  70.         REG3 _TSCHAR *cptr;
  71.         unsigned arg_len;
  72.         int cfi_len;            /* counts the number of file handles in CFI */
  73.  
  74.         /*
  75.          * Null environment pointer "envp" means use global variable,
  76.          * "_environ"
  77.          */
  78.  
  79.         int cwd_start;
  80.         int cwd_end;            /* length of "cwd" strings in environment */
  81.  
  82.         /*
  83.          * Allocate space for command line string
  84.          *  tmp counts the number of bytes in the command line string
  85.          *      including spaces between arguments
  86.          *  An empty string is special -- 2 bytes
  87.          */
  88.  
  89.         for (vp = argv, tmp = 2; *vp; tmp += _tcslen(*vp++) + 1) ;
  90.  
  91.         arg_len = tmp;
  92.  
  93.         /*
  94.          * Allocate space for the command line plus 2 null bytes
  95.          */
  96.  
  97.         if ( (*argblk = _malloc_crt(tmp * sizeof(_TSCHAR))) == NULL)
  98.         {
  99.                 *envblk = NULL;
  100.                 errno = ENOMEM;
  101.                 _doserrno = E_nomem;
  102.                 return(-1);
  103.         }
  104.  
  105.         /*
  106.          * Allocate space for environment strings
  107.          *  tmp counts the number of bytes in the environment strings
  108.          *      including nulls between strings
  109.          *  Also add "_C_FILE_INFO=" string
  110.          */
  111.         if (envp)
  112.                 for (vp = envp, tmp = 2; *vp; tmp += _tcslen(*vp++) + 1) ;
  113.  
  114.         /*
  115.          * The _osfile and _osfhnd arrays are passed as binary data in
  116.          * dospawn.c
  117.          */
  118.         cfi_len = 0;    /* no _C_FILE_INFO */
  119.  
  120.         if (!envp)
  121.                 *envblk = NULL;
  122.         else {
  123.                 /*
  124.                  * Now that we've decided to pass our own environment block,
  125.                  * compute the size of the "current directory" strings to
  126.                  * propagate to the new environment.
  127.                  */
  128.  
  129. #ifdef WPRFLAG
  130.             /*
  131.              * Make sure wide environment exists.
  132.              */
  133.             if (!_wenvptr)
  134.             {
  135.                     if ((_wenvptr = (wchar_t *)__crtGetEnvironmentStringsW()) == NULL)
  136.                     return -1;
  137.             }
  138. #else  /* WPRFLAG */
  139.             if (!_aenvptr)
  140.             {
  141.                     if ((_aenvptr = (char *)__crtGetEnvironmentStringsA()) == NULL)
  142.                     return -1;
  143.             }
  144. #endif  /* WPRFLAG */
  145.  
  146.             /*
  147.                  * search for the first one
  148.                  */
  149.                 for (cwd_start = 0;
  150.                      _tenvptr[cwd_start] != _T('\0') &&
  151.                        _tenvptr[cwd_start] != _T('=');
  152.                      cwd_start += _tcslen(&_tenvptr[cwd_start]) + 1)
  153.                 {
  154.                 }
  155.  
  156.                 /* find the total size of all contiguous ones */
  157.                 cwd_end = cwd_start;
  158.                 while (_tenvptr[cwd_end+0] == _T('=') &&
  159.                        _tenvptr[cwd_end+1] != _T('\0') &&
  160.                        _tenvptr[cwd_end+2] == _T(':') &&
  161.                        _tenvptr[cwd_end+3] == _T('='))
  162.                 {
  163.                         cwd_end += 4 + _tcslen(&_tenvptr[cwd_end+4]) + 1;
  164.                 }
  165.                 tmp += cwd_end - cwd_start;
  166.  
  167.                 /*
  168.                  * Allocate space for the environment strings plus extra null byte
  169.                  */
  170.                 if( !(*envblk = _malloc_crt(tmp * sizeof(_TSCHAR))) )
  171.             {
  172.                         _free_crt(*argblk);
  173.                         *argblk = NULL;
  174.                         errno = ENOMEM;
  175.                         _doserrno = E_nomem;
  176.                         return(-1);
  177.                 }
  178.  
  179.         }
  180.  
  181.         /*
  182.          * Build the command line by concatenating the argument strings
  183.          * with spaces between, and two null bytes at the end.
  184.          * NOTE: The argv[0] argument is followed by a null.
  185.          */
  186.  
  187.         cptr = *argblk;
  188.         vp = argv;
  189.  
  190.         if (!*vp)       /* Empty argument list ? */
  191.                 ++cptr; /* just two null bytes */
  192.         else {          /* argv[0] must be followed by a null */
  193.                 _tcscpy(cptr, *vp);
  194.                 cptr += _tcslen(*vp++) + 1;
  195.         }
  196.  
  197.         while( *vp ) {
  198.                 _tcscpy(cptr, *vp);
  199.                 cptr += _tcslen(*vp++);
  200.                 *cptr++ = ' ';
  201.         }
  202.  
  203.         *cptr = cptr[ -1 ] = _T('\0'); /* remove extra blank, add double null */
  204.  
  205.         /*
  206.          * Build the environment block by concatenating the environment
  207.          * strings with nulls between and two null bytes at the end
  208.          */
  209.  
  210.         cptr = *envblk;
  211.  
  212.         if (envp != NULL) {
  213.                 /*
  214.                  * Copy the "cwd" strings to the new environment.
  215.                  */
  216.                 memcpy(cptr, &_tenvptr[cwd_start], (cwd_end - cwd_start) * sizeof(_TSCHAR));
  217.                 cptr += cwd_end - cwd_start;
  218.  
  219.                 /*
  220.                  * Copy the environment strings from "envp".
  221.                  */
  222.                 vp = envp;
  223.                 while( *vp ) {
  224.                         _tcscpy(cptr, *vp);
  225.                         cptr += 1 + _tcslen(*vp++);
  226.                 }
  227.         }
  228.  
  229.         if (cptr != NULL) {
  230.                 if (cptr == *envblk) {
  231.                         /*
  232.                          * Empty environment block ... this requires two
  233.                          * nulls.
  234.                          */
  235.                         *cptr++ = _T('\0');
  236.                 }
  237.                 /*
  238.                  * Extra null terminates the segment
  239.                  */
  240.                 *cptr = _T('\0');
  241.         }
  242.  
  243. #ifdef WPRFLAG
  244.         _free_crt(_wenvptr);
  245.         _wenvptr = NULL;
  246. #else  /* WPRFLAG */
  247.         _free_crt(_aenvptr);
  248.         _aenvptr = NULL;
  249. #endif  /* WPRFLAG */
  250.         return(0);
  251. }
  252.  
  253.  
  254. #ifndef _M_IX86
  255.  
  256. /***
  257. *int _capture_argv(arglist, static_argv, max_static_entries) - set up argv array
  258. *       for exec?? functions
  259. *
  260. *Purpose:
  261. *       Set up the argv array for the exec?? functions by captures the
  262. *       arguments from the passed va_list into the static_argv array.  If the
  263. *       size of the static_argv array as specified by the max_static_entries
  264. *       parameter is not large enough, then allocates a dynamic array to hold
  265. *       the arguments. Return the address of the final argv array.  If NULL
  266. *       then not enough memory to hold argument array.  If different from
  267. *       static_argv parameter then call must free the return argv array when
  268. *       done with it.
  269. *
  270. *       The scan of the arglist is terminated when a NULL argument is
  271. *       reached. The terminating NULL parameter is stored in the resulting
  272. *       argv array.
  273. *
  274. *Entry:
  275. *       va_list *arglist          - pointer to variable length argument list.
  276. *       _TSCHAR *firstarg            - first argument to store in array
  277. *       _TSCHAR **static_argv        - pointer to static argv to use.
  278. *       size_t max_static_entries - maximum number of entries that can be
  279. *                                   placed in static_argv array.
  280. *
  281. *Exit:
  282. *       returns NULL if no memory.
  283. *       Otherwise returns pointer to argv array.
  284. *       (sometimes calls malloc)
  285. *
  286. *Exceptions:
  287. *
  288. *******************************************************************************/
  289.  
  290. #ifdef WPRFLAG
  291. _TSCHAR ** __cdecl _wcapture_argv(
  292. #else  /* WPRFLAG */
  293. _TSCHAR ** __cdecl _capture_argv(
  294. #endif  /* WPRFLAG */
  295.         va_list *arglist,
  296.         const _TSCHAR *firstarg,
  297.         _TSCHAR **static_argv,
  298.         size_t max_static_entries
  299.         )
  300. {
  301.         _TSCHAR ** argv;
  302.         _TSCHAR * nextarg;
  303.         size_t i;
  304.         size_t max_entries;
  305.  
  306.         nextarg = (_TSCHAR *)firstarg;
  307.         argv = static_argv;
  308.         max_entries = max_static_entries;
  309.         i = 0;
  310.         for (;;) {
  311.             if (i >= max_entries) {
  312.                 if (argv == static_argv)
  313.                     argv = _malloc_crt((max_entries * 2) * sizeof(_TSCHAR *));
  314.                 else
  315.                     argv = _realloc_crt(argv, (max_entries * 2) * sizeof(_TSCHAR *));
  316.  
  317.                 if (argv == NULL) break;
  318.                 max_entries += max_entries;
  319.             }
  320.  
  321.             argv[ i++ ] = nextarg;
  322.             if (nextarg == NULL) break;
  323.             nextarg = va_arg(*arglist, _TSCHAR *);
  324.         }
  325.  
  326.         return argv;
  327. }
  328.  
  329. #endif  /* _M_IX86 */
  330.