~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: Vincent Ladeuil
  • Date: 2010-02-10 16:41:09 UTC
  • mto: (5029.2.1 integration2)
  • mto: This revision was merged to the branch mainline in revision 5031.
  • Revision ID: v.ladeuil+lp@free.fr-20100210164109-q5wluu91am3vsf6d
Use a set() for conflicts_related to stay O(1).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
21
21
 
22
22
import glob
23
23
import os
 
24
import re
24
25
import struct
25
26
import sys
26
27
 
27
 
from bzrlib import cmdline
28
28
 
29
29
# Windows version
30
30
if sys.platform == 'win32':
522
522
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
523
523
 
524
524
 
525
 
def _command_line_to_argv(command_line, single_quotes_allowed=False):
526
 
    """Convert a Unicode command line into a list of argv arguments.
527
 
 
528
 
    It performs wildcard expansion to make wildcards act closer to how they
529
 
    work in posix shells, versus how they work by default on Windows. Quoted
530
 
    arguments are left untouched.
531
 
 
532
 
    :param command_line: The unicode string to split into an arg list.
533
 
    :param single_quotes_allowed: Whether single quotes are accepted as quoting
534
 
                                  characters like double quotes. False by
535
 
                                  default.
536
 
    :return: A list of unicode strings.
537
 
    """
538
 
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
539
 
    # Now that we've split the content, expand globs if necessary
 
525
 
 
526
class UnicodeShlex(object):
 
527
    """This is a very simplified version of shlex.shlex.
 
528
 
 
529
    The main change is that it supports non-ascii input streams. The internal
 
530
    structure is quite simplified relative to shlex.shlex, since we aren't
 
531
    trying to handle multiple input streams, etc. In fact, we don't use a
 
532
    file-like api either.
 
533
    """
 
534
 
 
535
    def __init__(self, uni_string):
 
536
        self._input = uni_string
 
537
        self._input_iter = iter(self._input)
 
538
        self._whitespace_match = re.compile(u'\s').match
 
539
        self._word_match = re.compile(u'\S').match
 
540
        self._quote_chars = u'"'
 
541
        # self._quote_match = re.compile(u'[\'"]').match
 
542
        self._escape_match = lambda x: None # Never matches
 
543
        self._escape = '\\'
 
544
        # State can be
 
545
        #   ' ' - after whitespace, starting a new token
 
546
        #   'a' - after text, currently working on a token
 
547
        #   '"' - after ", currently in a "-delimited quoted section
 
548
        #   "\" - after '\', checking the next char
 
549
        self._state = ' '
 
550
        self._token = [] # Current token being parsed
 
551
 
 
552
    def _get_token(self):
 
553
        # Were there quote chars as part of this token?
 
554
        quoted = False
 
555
        quoted_state = None
 
556
        for nextchar in self._input_iter:
 
557
            if self._state == ' ':
 
558
                if self._whitespace_match(nextchar):
 
559
                    # if self._token: return token
 
560
                    continue
 
561
                elif nextchar in self._quote_chars:
 
562
                    self._state = nextchar # quoted state
 
563
                elif self._word_match(nextchar):
 
564
                    self._token.append(nextchar)
 
565
                    self._state = 'a'
 
566
                else:
 
567
                    raise AssertionError('wtttf?')
 
568
            elif self._state in self._quote_chars:
 
569
                quoted = True
 
570
                if nextchar == self._state: # End of quote
 
571
                    self._state = 'a' # posix allows 'foo'bar to translate to
 
572
                                      # foobar
 
573
                elif self._state == '"' and nextchar == self._escape:
 
574
                    quoted_state = self._state
 
575
                    self._state = nextchar
 
576
                else:
 
577
                    self._token.append(nextchar)
 
578
            elif self._state == self._escape:
 
579
                if nextchar == '\\':
 
580
                    self._token.append('\\')
 
581
                elif nextchar == '"':
 
582
                    self._token.append(nextchar)
 
583
                else:
 
584
                    self._token.append('\\' + nextchar)
 
585
                self._state = quoted_state
 
586
            elif self._state == 'a':
 
587
                if self._whitespace_match(nextchar):
 
588
                    if self._token:
 
589
                        break # emit this token
 
590
                    else:
 
591
                        continue # no token to emit
 
592
                elif nextchar in self._quote_chars:
 
593
                    # Start a new quoted section
 
594
                    self._state = nextchar
 
595
                # escape?
 
596
                elif (self._word_match(nextchar)
 
597
                      or nextchar in self._quote_chars
 
598
                      # or whitespace_split?
 
599
                      ):
 
600
                    self._token.append(nextchar)
 
601
                else:
 
602
                    raise AssertionError('state == "a", char: %r'
 
603
                                         % (nextchar,))
 
604
            else:
 
605
                raise AssertionError('unknown state: %r' % (self._state,))
 
606
        result = ''.join(self._token)
 
607
        self._token = []
 
608
        if not quoted and result == '':
 
609
            result = None
 
610
        return quoted, result
 
611
 
 
612
    def __iter__(self):
 
613
        return self
 
614
 
 
615
    def next(self):
 
616
        quoted, token = self._get_token()
 
617
        if token is None:
 
618
            raise StopIteration
 
619
        return quoted, token
 
620
 
 
621
 
 
622
def _command_line_to_argv(command_line):
 
623
    """Convert a Unicode command line into a set of argv arguments.
 
624
 
 
625
    This does wildcard expansion, etc. It is intended to make wildcards act
 
626
    closer to how they work in posix shells, versus how they work by default on
 
627
    Windows.
 
628
    """
 
629
    s = UnicodeShlex(command_line)
 
630
    # Now that we've split the content, expand globs
540
631
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
541
632
    #       '**/' style globs
542
633
    args = []
550
641
 
551
642
if has_ctypes and winver != 'Windows 98':
552
643
    def get_unicode_argv():
553
 
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
554
 
        GetCommandLineW = prototype(("GetCommandLineW",
555
 
                                     ctypes.windll.kernel32))
556
 
        command_line = GetCommandLineW()
557
 
        if command_line is None:
558
 
            raise ctypes.WinError()
 
644
        LPCWSTR = ctypes.c_wchar_p
 
645
        INT = ctypes.c_int
 
646
        POINTER = ctypes.POINTER
 
647
        prototype = ctypes.WINFUNCTYPE(LPCWSTR)
 
648
        GetCommandLine = prototype(("GetCommandLineW",
 
649
                                    ctypes.windll.kernel32))
 
650
        prototype = ctypes.WINFUNCTYPE(POINTER(LPCWSTR), LPCWSTR, POINTER(INT))
 
651
        command_line = GetCommandLine()
559
652
        # Skip the first argument, since we only care about parameters
560
653
        argv = _command_line_to_argv(command_line)[1:]
561
654
        if getattr(sys, 'frozen', None) is None: