⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 execnt.c

📁 boost库提供标准的C++ API 配合dev c++使用,功能更加强大
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright 1993, 1995 Christopher Seiwald.
 *
 * This file is part of Jam - see jam.c for Copyright information.
 */

/*  This file is ALSO:
 *  (C) Copyright David Abrahams 2001. Permission to copy, use,
 *  modify, sell and distribute this software is granted provided this
 *  copyright notice appears in all copies. This software is provided
 *  "as is" without express or implied warranty, and with no claim as
 *  to its suitability for any purpose.
 */

# include "jam.h"
# include "lists.h"
# include "execcmd.h"
# include <errno.h>
# include <assert.h>
# include <ctype.h>

# ifdef USE_EXECNT

# define WIN32_LEAN_AND_MEAN
# include <windows.h>		/* do the ugly deed */
# include <process.h>

# if !defined( __BORLANDC__ ) && !defined( OS_OS2 )
# define wait my_wait
static int my_wait( int *status );
# endif

/*
 * execnt.c - execute a shell command on Windows NT and Windows 95/98
 *
 * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp().
 * The default is:
 *
 *	/bin/sh -c %		[ on UNIX/AmigaOS ]
 *	cmd.exe /c %		[ on Windows NT ]
 *
 * Each word must be an individual element in a jam variable value.
 *
 * In $(JAMSHELL), % expands to the command string and ! expands to 
 * the slot number (starting at 1) for multiprocess (-j) invocations.
 * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
 * argument.
 *
 * Don't just set JAMSHELL to /bin/sh or cmd.exe - it won't work!
 *
 * External routines:
 *	execcmd() - launch an async command execution
 * 	execwait() - wait and drive at most one execution completion
 *
 * Internal routines:
 *	onintr() - bump intr to note command interruption
 *
 * 04/08/94 (seiwald) - Coherent/386 support added.
 * 05/04/94 (seiwald) - async multiprocess interface
 * 01/22/95 (seiwald) - $(JAMSHELL) support
 * 06/02/97 (gsar)    - full async multiprocess support for Win32
 */

static int intr = 0;
static int cmdsrunning = 0;
static void (*istat)( int );

static int  is_nt_351        = 0;
static int  is_win95         = 1;
static int  is_win95_defined = 0;


static struct
{
	int	pid; /* on win32, a real process handle */
	void	(*func)( void *closure, int status );
	void 	*closure;
	char	*tempfile;

} cmdtab[ MAXJOBS ] = {{0}};


static void
set_is_win95( void )
{
  OSVERSIONINFO  os_info;

  os_info.dwOSVersionInfoSize = sizeof(os_info);
  os_info.dwPlatformId        = VER_PLATFORM_WIN32_WINDOWS;
  GetVersionEx( &os_info );
  
  is_win95         = (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
  is_win95_defined = 1;
  
  /* now, test wether we're running Windows 3.51                */
  /* this is later used to limit the system call command length */
  if (os_info.dwPlatformId ==  VER_PLATFORM_WIN32_NT)
    is_nt_351 = os_info.dwMajorVersion == 3;
}

int maxline()
{
    if (!is_win95_defined)
        set_is_win95();
    
    /* Set the maximum command line length according to the OS */
    return is_nt_351 ? 996
        : is_win95 ? 1023
        : 2047;
}

static char**
string_to_args( const char*  string, int*  pcount )
{
  int    total    = strlen( string );
  int    in_quote = 0,
      num_args = 0; /* was uninitialized -- dwa */
  char*  line;
  char*  p;
  char** arg;
  char** args;

  *pcount = 0;  

  /* do not copy trailing newlines, if any */  
  while ( total > 0 )
  {
      if ( !isspace( string[total - 1] ) )
          break;
      --total;
  }
  
  /* first of all, copy the input string */
  line    = (char*)malloc( total+2 );
  if (!line)
    return 0;
    
  memcpy( line+1, string, total );
  line[0]       = 0;
  line[total+1] = 0;
  
  in_quote = 0;
  for ( p = line+1; p[0]; p++ )
  {
    switch (p[0])
    {
      case '"':
        in_quote = !in_quote;
        break;
        
      case ' ':
      case '\t':
        if (!in_quote)
          p[0]    = 0;
        
      default:
        ;
    }
  }
  
  /* now count the arguments.. */
  for ( p = line; p < line+total+1; p++ )
    if ( !p[0] && p[1] )
      num_args++;
      
  /* allocate the args array */
  /* dwa -- did you really mean to allocate only 2 additional bytes? */
#if 0 /* was like this */
  args = (char**)malloc( num_args*sizeof(char*)+2 );
#endif
  args = (char**)malloc( (num_args + 2) * sizeof(char*) );
  if (!args)
  {
    free( line );
    return 0;
  }
  
  arg = args+1;
  for ( p = line; p < line+total+1; p++ )
    if ( !p[0] && p[1] )
    {
      arg[0] = p+1;
      arg++;
    }
  arg[0]  = 0;
  *pcount = num_args;
  args[0] = line;
  return args+1;
}

static void
free_args( char** args )
{
  free( args[-1] );
  free( args-1 );
}


/* process a "del" or "erase" command under Windows 95/98 */
static int
process_del( char*  command )
{
  char** arg;
  char*  p = command, *q;
  int    wildcard = 0, result = 0;

  /* first of all, skip the command itself */
  if ( p[0] == 'd' )
    p += 3; /* assumes "del..;" */
  else if ( p[0] == 'e' )
    p += 5; /* assumes "erase.." */
  else
    return 1; /* invalid command */

  /* process all targets independently */
  for (;;)
  {
    /* skip leading spaces */
    while ( *p && isspace(*p) )
      p++;
      
    /* exit if we encounter an end of string */
    if (!*p)
      return 0;
      
    /* ignore toggles/flags */
    while (*p == '/')
    {
      p++;
      while ( *p && isalnum(*p) )
          p++;
      while (*p && isspace(*p) )
          ++p;
    }

    
    {
      int  in_quote = 0;
      int  wildcard = 0;
      int  go_on    = 1;
      
      q = p;
      while (go_on)
      {
        switch (*p)
        {
          case '"':
            in_quote = !in_quote;
            break;
          
          case '?':
          case '*':
            if (!in_quote)
              wildcard = 1;
            break;
            
          case '\0':
            if (in_quote)
              return 1;
            /* fall-through */
              
          case ' ':
          case '\t':
            if (!in_quote)
            {
              int    len = p - q;
              int    result;
              char*  line;
              
              /* q..p-1 contains the delete argument */
              if ( len <= 0 )
                return 1;
  
              line = (char*)malloc( len+4+1 );
              if (!line)
                return 1;
                
              strncpy( line, "del ", 4 );
              strncpy( line+4, q, len );
              line[len+4] = '\0';
              
              if ( wildcard )
                result = system( line );
              else
                result = !DeleteFile( line+4 );
  
              free( line );
              if (result)
                return 1;
                
              go_on = 0;
            }
            
          default:
            ;
        }
        p++;
      } /* while (go_on) */
    }
  }
}


/*
 * onintr() - bump intr to note command interruption
 */

void
onintr( int disp )
{
	intr++;
	printf( "...interrupted\n" );
}

#if 0 // the shell is too different from direct invocation; let's
      // always use the shell unless forced.
/*
 * use_bat_file() - return true iff the command demands the use of a
 * .bat file to run it
 */
int use_bat_file(char* command)
{
    char *p = command;
    
    char inquote = 0;

    p += strspn( p, " \t" );

    /* spawnvp can't handle any paths with spaces or quoted filenames with no directory prefix */
    if ( *p == '"' )
    {
        char* q = p + 1 + strcspn( p + 1, "\" /\\" );
        if ( *q == '"' || *q == ' ' )
            return 1;
    }
        
    /* Look for newlines and unquoted i/o redirection */
    do
    {
        p += strcspn( p, "'\n\"<>|" );

        switch (*p)
        {
        case '\n':
            /* skip over any following spaces */
            while( isspace( *p ) )
                ++p;
            /* return true iff there is anything significant following
             * the newline
             */
            if (*p)
                return 1;
            break;
            
        case '"':
        case '\'':
            if (p > command && p[-1] != '\\')
            {
                if (inquote == *p)
                    inquote = 0;
                else if (inquote == 0)
                    inquote = *p;
            }
                
            ++p;
            break;
            
        case '<':
        case '>':
        case '|':
            if (!inquote)
                return 1;
            ++p;
            break;
        }
    }
    while (*p);
    
    return p - command >= MAXLINE;
}
#endif

void execnt_unit_test()
{
#if 0 && !defined(NDEBUG)
    /* vc6 preprocessor is broken, so assert with these strings gets
     * confused. Use a table instead.
     */
    typedef struct test { char* command; int result; } test;
    test tests[] = {
        { "x", 0 },
        { "x\n ", 0 },
        { "x\ny", 1 },
        { "x\n\n y", 1 },
        { "\"x\"", 1 },
        { "\"x y\"", 1 },
        { "\"x/y\"", 0 },
        { "\"x\\y\"", 0 },
        { "echo x > foo.bar", 1 },
        { "echo x < foo.bar", 1 },
        { "echo x \">\" foo.bar", 0 },
        { "echo x \"<\" foo.bar", 0 },
        { "echo x \\\">\\\" foo.bar", 1 },
        { "echo x \\\"<\\\" foo.bar", 1 }
    };
    int i;
    for ( i = 0; i < sizeof(tests)/sizeof(*tests); ++i)
    {
        assert( use_bat_file( tests[i].command ) == tests[i].result );
    }

    {
        char* long_command = malloc(MAXLINE + 10);
        assert( long_command != 0 );
        memset( long_command, 'x', MAXLINE + 9 );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -