2 * Copyright (C) 2009 KJK::Hyperion
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "../../pch.h"
31 #define ARRAYSIZE(X_) (sizeof(X_) / sizeof((X_)[0]))
53 #if defined(_CPPLIB_VER)
55 typedef std::filebuf stdio_filebuf
;
56 #elif defined(__GLIBCXX__)
57 #include <ext/stdio_sync_filebuf.h>
58 typedef __gnu_cxx::stdio_sync_filebuf
<char> stdio_filebuf
;
60 #error Unknown or unsupported C++ standard library
69 HRESULT
dispPropGet(IDispatch
* object
, DISPID dispid
, VARIANTARG
* args
, UINT ccArgs
, VARTYPE vt
, VARIANT
& result
)
73 DISPPARAMS params
= {};
75 params
.cArgs
= ccArgs
;
77 hr
= object
->Invoke(dispid
, IID_NULL
, 0, DISPATCH_PROPERTYGET
| (ccArgs
? DISPATCH_METHOD
: 0), ¶ms
, &result
, NULL
, NULL
);
80 hr
= VariantChangeType(&result
, &result
, 0, vt
);
85 HRESULT
dispPropGet(IDispatch
* object
, const OLECHAR
* name
, VARIANTARG
* args
, UINT ccArgs
, VARTYPE vt
, VARIANT
& result
)
90 hr
= object
->GetIDsOfNames(IID_NULL
, const_cast<OLECHAR
**>(&name
), 1, 0, &dispid
);
93 hr
= dispPropGet(object
, dispid
, args
, ccArgs
, vt
, result
);
98 VARIANT
dispPropGet(HRESULT
& hr
, IDispatch
* object
, DISPID dispid
, VARTYPE vt
)
104 hr
= dispPropGet(object
, dispid
, 0, 0, vt
, ret
);
109 VARIANT
dispPropGet(HRESULT
& hr
, IDispatch
* object
, const OLECHAR
* name
, VARTYPE vt
)
115 hr
= dispPropGet(object
, name
, 0, 0, vt
, ret
);
120 HRESULT
dispInvoke(IDispatch
* object
, DISPID dispid
, VARIANTARG
* args
, UINT ccArgs
, VARTYPE vt
, VARIANT
& result
)
124 DISPPARAMS params
= {};
125 params
.rgvarg
= args
;
126 params
.cArgs
= ccArgs
;
128 hr
= object
->Invoke(dispid
, IID_NULL
, 0, DISPATCH_METHOD
, ¶ms
, &result
, NULL
, NULL
);
131 hr
= VariantChangeType(&result
, &result
, 0, vt
);
136 HRESULT
dispInvoke(IDispatch
* object
, DISPID dispid
, const VARIANTARG
& arg
, VARTYPE vt
, VARIANT
& result
)
138 return dispInvoke(object
, dispid
, const_cast<VARIANTARG
*>(&arg
), 1, vt
, result
);
141 HRESULT
dispInvoke(IDispatch
* object
, DISPID dispid
, VARTYPE vt
, VARIANT
& result
)
143 return dispInvoke(object
, dispid
, NULL
, 0, vt
, result
);
146 HRESULT
dispInvoke(IDispatch
* object
, VARIANTARG
* args
, UINT ccArgs
, VARTYPE vt
, VARIANT
& result
)
148 return dispInvoke(object
, DISPID_VALUE
, args
, ccArgs
, vt
, result
);
151 HRESULT
dispInvoke(IDispatch
* object
, VARTYPE vt
, VARIANT
& result
)
153 return dispInvoke(object
, DISPID_VALUE
, NULL
, 0, vt
, result
);
156 HRESULT
dispInvoke(IDispatch
* object
, const VARIANTARG
& arg
, VARTYPE vt
, VARIANT
& result
)
158 return dispInvoke(object
, DISPID_VALUE
, const_cast<VARIANTARG
*>(&arg
), 1, vt
, result
);
161 HRESULT
dispInvoke(IDispatch
* object
, const OLECHAR
* name
, VARIANTARG
* args
, UINT ccArgs
, VARTYPE vt
, VARIANT
& result
)
166 hr
= object
->GetIDsOfNames(IID_NULL
, const_cast<OLECHAR
**>(&name
), 1, 0, &dispid
);
169 hr
= dispInvoke(object
, dispid
, args
, ccArgs
, vt
, result
);
174 HRESULT
dispInvoke(IDispatch
* object
, const OLECHAR
* name
, const VARIANTARG
& arg
, VARTYPE vt
, VARIANT
& result
)
176 return dispInvoke(object
, name
, const_cast<VARIANTARG
*>(&arg
), 1, vt
, result
);
179 HRESULT
dispInvoke(IDispatch
* object
, const OLECHAR
* name
, VARTYPE vt
, VARIANT
& result
)
181 return dispInvoke(object
, name
, NULL
, 0, vt
, result
);
184 VARIANT
dispInvoke(HRESULT
& hr
, IDispatch
* object
, DISPID dispid
, VARIANTARG
* args
, UINT ccArgs
, VARTYPE vt
)
190 hr
= dispInvoke(object
, dispid
, args
, ccArgs
, vt
, ret
);
195 VARIANT
dispInvoke(HRESULT
& hr
, IDispatch
* object
, const OLECHAR
* name
, VARIANTARG
* args
, UINT ccArgs
, VARTYPE vt
)
201 hr
= dispInvoke(object
, name
, args
, ccArgs
, vt
, ret
);
206 VARIANT
dispInvoke(HRESULT
& hr
, IDispatch
* object
, DISPID dispid
, const VARIANTARG
& arg
, VARTYPE vt
)
208 return dispInvoke(hr
, object
, dispid
, const_cast<VARIANTARG
*>(&arg
), 1, vt
);
211 VARIANT
dispInvoke(HRESULT
& hr
, IDispatch
* object
, DISPID dispid
, VARTYPE vt
)
213 return dispInvoke(hr
, object
, dispid
, NULL
, 0, vt
);
216 VARIANT
dispInvoke(HRESULT
& hr
, IDispatch
* object
, VARIANTARG
* args
, UINT ccArgs
, VARTYPE vt
)
218 return dispInvoke(hr
, object
, DISPID(DISPID_VALUE
), args
, ccArgs
, vt
);
221 VARIANT
dispInvoke(HRESULT
& hr
, IDispatch
* object
, VARTYPE vt
)
223 return dispInvoke(hr
, object
, DISPID(DISPID_VALUE
), NULL
, 0, vt
);
226 VARIANT
dispInvoke(HRESULT
& hr
, IDispatch
* object
, const VARIANTARG
& arg
, VARTYPE vt
)
228 return dispInvoke(hr
, object
, DISPID(DISPID_VALUE
), const_cast<VARIANTARG
*>(&arg
), 1, vt
);
231 VARIANT
dispInvoke(HRESULT
& hr
, IDispatch
* object
, const OLECHAR
* name
, const VARIANTARG
& arg
, VARTYPE vt
)
233 return dispInvoke(hr
, object
, name
, const_cast<VARIANTARG
*>(&arg
), 1, vt
);
236 VARIANT
dispInvoke(HRESULT
& hr
, IDispatch
* object
, const OLECHAR
* name
, VARTYPE vt
)
238 return dispInvoke(hr
, object
, name
, NULL
, 0, vt
);
241 VARIANT
oleString(HRESULT
& hr
, const OLECHAR
* sz
)
249 V_BSTR(&v
) = SysAllocString(sz
);
267 namespace knuth_morris_pratt
274 typename
std::iterator_traits
<Iter
>::iterator_category
iterator_category(const Iter
&)
276 return typename
std::iterator_traits
<Iter
>::iterator_category();
279 template<typename TypeX
, typename TypeY
>
285 template<typename TypeX
>
286 struct type_equals
<TypeX
, TypeX
>
291 template<class Iter
, class diff_type
>
292 void advance_substr(Iter
& pos
, Iter
, diff_type
, diff_type rel
, const std::bidirectional_iterator_tag
&)
294 std::advance(pos
, rel
);
297 template<class Iter
, class diff_type
>
298 void advance_substr(Iter
& pos
, Iter begin
, diff_type absol
, diff_type rel
, const std::forward_iterator_tag
&)
301 std::advance(pos
, rel
);
305 std::advance(pos
, absol
);
309 template<class Iter
, class diff_type
>
310 void advance_substr(Iter
& pos
, Iter begin
, diff_type absol
, diff_type rel
)
312 advance_substr(pos
, begin
, absol
, rel
, iterator_category(pos
));
315 template<class T
, size_t N
>
319 typedef typename
std::iterator_traits
<T
*>::difference_type value_type
;
320 typedef value_type
* pointer
;
321 typedef value_type
& reference
;
322 typedef const value_type
* const_pointer
;
323 typedef const value_type
& const_reference
;
324 typedef typename
std::allocator
<value_type
>::difference_type difference_type
;
325 typedef typename
std::allocator
<value_type
>::size_type size_type
;
328 value_type m_table
[(N
)];
331 static pointer
address(reference r
) { return &r
; }
332 static const_pointer
address(const_reference r
) { return &r
; }
333 static size_type
max_size() { return (N
); }
334 static void construct(pointer p
, const T
& v
) { p
->T(v
); }
335 static void destroy(pointer p
) { p
->~T(); }
336 template<class Other
> struct rebind
{ typedef fixed_table
<Other
, N
> other
; };
338 template<class Other
> pointer
allocate(size_type n
, const Other
* hint
)
345 pointer
allocate(size_type n
)
351 void deallocate(pointer p
, size_type n
) const
353 assert(p
== m_table
);
358 void validate_range_iterator_category(const std::input_iterator_tag
&) { }
359 void validate_substr_iterator_category(const std::forward_iterator_tag
&) { }
361 template<class RangeIter
, class SubstrIter
>
362 RangeIter
search_cornercase_neg(RangeIter
, RangeIter end
, SubstrIter
)
367 template<class RangeIter
, class SubstrIter
>
368 RangeIter
search_cornercase0(RangeIter begin
, RangeIter
, SubstrIter
)
373 template<class RangeIter
, class SubstrIter
>
374 RangeIter
search_cornercase1(RangeIter begin
, RangeIter end
, SubstrIter substrBegin
)
376 RangeIter pos
= std::find(begin
, end
, *substrBegin
);
378 if(type_equals
<typename
std::iterator_traits
<RangeIter
>::iterator_category
, std::input_iterator_tag
>::value
&& pos
!= end
)
384 template<class SubstrIter
, class TableType
, class TableSize
>
385 void search_createtable_dynamic
387 SubstrIter beginSubstr
,
388 typename
std::iterator_traits
<SubstrIter
>::difference_type substrSize
,
393 typedef typename
std::iterator_traits
<SubstrIter
>::difference_type substr_diff_type
;
394 typedef typename
TableType::pointer table_type
;
395 typedef TableSize table_size_type
;
397 substr_diff_type
i(2);
398 SubstrIter pi
= beginSubstr
;
399 std::advance(pi
, substr_diff_type(1));
401 substr_diff_type
j(0);
402 SubstrIter pj
= beginSubstr
;
403 std::advance(pj
, substr_diff_type(0));
405 while(i
< substrSize
)
409 substr_diff_type new_j
= j
;
412 table
[static_cast<table_size_type
>(i
)] = new_j
;
419 substr_diff_type new_j
= table
[i
];
420 details::advance_substr(pj
, beginSubstr
, new_j
, new_j
- j
);
431 template<class D
, class S
, size_t N
>
432 void search_createtable_static
434 const S (& substr
)[N
],
438 typedef std::ptrdiff_t substr_diff_type
;
440 table
[0] = substr_diff_type(-1);
441 table
[1] = substr_diff_type(0);
443 substr_diff_type pos
= 2;
444 substr_diff_type cnd
= 0;
446 while(pos
< static_cast<substr_diff_type
>(N
))
448 if(substr
[pos
- 1] == substr
[cnd
])
450 table
[pos
] = cnd
+ 1;
464 template<class RangeIter
, class SubstrIter
, class Table
, class TableSize
>
467 const RangeIter
& begin
,
468 const RangeIter
& end
,
469 const SubstrIter beginSubstr
,
470 typename
std::iterator_traits
<SubstrIter
>::difference_type substrSize
,
475 details::validate_range_iterator_category(details::iterator_category(begin
));
476 details::validate_substr_iterator_category(details::iterator_category(beginSubstr
));
478 typedef typename
std::iterator_traits
<SubstrIter
>::difference_type substr_diff_type
;
479 typedef Table table_type
;
480 typedef TableSize table_size_type
;
482 // Find the next match
483 substr_diff_type
iSubstr(0); // i
484 RangeIter pCurMatch
= begin
; // m
485 RangeIter pCurElem
= begin
; // m + i
486 SubstrIter pCurSubstrElem
= beginSubstr
; // i
488 while(pCurElem
!= end
)
490 if(*pCurSubstrElem
== *pCurElem
)
494 if(iSubstr
== substrSize
)
496 // For input iterators, we return the end of the match
497 if(type_equals
<typename
std::iterator_traits
<RangeIter
>::iterator_category
, std::input_iterator_tag
>::value
)
498 ++ pCurElem
; // return m + i + 1
499 // For all other iterators, we return the beginning of the match
501 pCurElem
= pCurMatch
; // return m
507 ++ pCurSubstrElem
; // ++ i
511 substr_diff_type table_iSubstr
= table
[static_cast<table_size_type
>(iSubstr
)]; // T[i]
512 substr_diff_type iSubstr_backtracked
= iSubstr
- table_iSubstr
; // i - T[i]
513 assert(iSubstr_backtracked
>= substr_diff_type(0));
515 if(!type_equals
<typename
std::iterator_traits
<RangeIter
>::iterator_category
, std::input_iterator_tag
>::value
)
516 std::advance(pCurMatch
, iSubstr_backtracked
); // m = m + i - T[i]
518 if(iSubstr
> substr_diff_type(0)) // i > 0
520 iSubstr
= table_iSubstr
; // i = T[i]
521 pCurSubstrElem
= beginSubstr
;
522 std::advance(pCurSubstrElem
, iSubstr
); // i = T[i]
525 std::advance(pCurElem
, iSubstr_backtracked
);
534 template<class RangeIter
, class SubstrIter
, class AllocTable
>
535 RangeIter
search(RangeIter begin
, RangeIter end
, SubstrIter beginSubstr
, SubstrIter endSubstr
, AllocTable
& allocTable
)
537 typename
std::iterator_traits
<SubstrIter
>::difference_type substrSize
= std::distance(beginSubstr
, endSubstr
);
540 return knuth_morris_pratt::details::search_cornercase_neg(begin
, end
, beginSubstr
);
543 return knuth_morris_pratt::details::search_cornercase0(begin
, end
, beginSubstr
);
546 return knuth_morris_pratt::details::search_cornercase1(begin
, end
, beginSubstr
);
548 typedef typename
AllocTable::size_type table_size
;
549 typedef typename
AllocTable::pointer table_type
;
551 table_size tableSize
= static_cast<table_size
>(substrSize
);
552 table_type table
= allocTable
.allocate(tableSize
);
554 RangeIter pos
= knuth_morris_pratt::details::search(begin
, end
, beginSubstr
, substrSize
, table
, tableSize
);
556 allocTable
.deallocate(table
, tableSize
);
561 template<class RangeIter
, class SubstrIter
>
562 RangeIter
search(RangeIter begin
, RangeIter end
, SubstrIter beginSubstr
, SubstrIter endSubstr
)
564 std::allocator
<typename
std::iterator_traits
<SubstrIter
>::difference_type
> allocTable
;
565 return knuth_morris_pratt::search(begin
, end
, beginSubstr
, endSubstr
, allocTable
);
568 template<class RangeIter
, class SubstrElem
, size_t N
>
569 RangeIter
search(RangeIter begin
, RangeIter end
, const SubstrElem (& substr
)[(N
)])
572 return knuth_morris_pratt::details::search_cornercase0(begin
, end
, substr
);
575 return knuth_morris_pratt::details::search_cornercase1(begin
, end
, substr
);
577 if((N
) * sizeof(SubstrElem
) <= 4096)
580 knuth_morris_pratt::details::search_createtable_static(substr
, table
);
581 return knuth_morris_pratt::details::search(begin
, end
, substr
, (N
), table
, sizeof(table
));
584 return knuth_morris_pratt::search(begin
, end
, substr
, substr
+ (N
));
591 template<class CharT
, class Traits
, class Alloc
, size_t N
, class ReplIter
>
592 std::basic_string
<CharT
, Traits
, Alloc
> replace(const std::basic_string
<CharT
, Traits
, Alloc
>& str
, const CharT (& substr
)[(N
)], ReplIter replBegin
, ReplIter replEnd
)
597 std::basic_string
<CharT
, Traits
, Alloc
> newStr
;
598 typename
std::basic_string
<CharT
, Traits
, Alloc
>::const_iterator cur
= str
.begin();
599 typename
std::basic_string
<CharT
, Traits
, Alloc
>::const_iterator end
= str
.end();
603 typename
std::basic_string
<CharT
, Traits
, Alloc
>::const_iterator found
= knuth_morris_pratt::search(cur
, end
, *reinterpret_cast<const CharT (*)[(N
) - 1]>(&substr
));
605 newStr
.append(cur
, found
);
610 newStr
.append(replBegin
, replEnd
);
611 advance(cur
, (N
) - 1);
618 template<class CharT
, class Traits
, class Alloc
, size_t N
, size_t M
>
619 std::basic_string
<CharT
, Traits
, Alloc
> replace(const std::basic_string
<CharT
, Traits
, Alloc
>& str
, const CharT (& substr
)[(N
)], const CharT (& repl
)[(M
)])
621 return replace(str
, substr
, repl
, repl
+ ((M
) - 1));
624 template<class CharT
, class Traits
, class Alloc
, size_t N
, class Traits2
, class Alloc2
>
625 std::basic_string
<CharT
, Traits
, Alloc
> replace(const std::basic_string
<CharT
, Traits
, Alloc
>& str
, const CharT (& substr
)[(N
)], const std::basic_string
<CharT
, Traits2
, Alloc2
>& repl
)
627 return replace(str
, substr
, repl
.begin(), repl
.end());
630 template<class CharT
, class Traits
, class Alloc
, size_t M
, class Traits2
, class Alloc2
>
631 std::basic_string
<CharT
, Traits
, Alloc
> replace(const std::basic_string
<CharT
, Traits
, Alloc
>& str
, const std::basic_string
<CharT
, Traits2
, Alloc2
>& substr
, const CharT (& repl
)[(M
)])
633 return replace(str
, substr
.begin(), substr
.end(), repl
, repl
+ ((M
) - 1));
636 template<class CharT
, class Traits
, class Alloc
, class Traits2
, class Alloc2
, class Traits3
, class Alloc3
>
637 std::basic_string
<CharT
, Traits
, Alloc
> replace(const std::basic_string
<CharT
, Traits
, Alloc
>& str
, const std::basic_string
<CharT
, Traits2
, Alloc2
>& substr
, const std::basic_string
<CharT
, Traits3
, Alloc3
>& repl
)
639 return replace(str
, substr
.begin(), substr
.end(), repl
.begin(), repl
.end());
642 template<typename TypeX
, typename TypeY
>
648 template<typename TypeX
>
649 struct type_equals
<TypeX
, TypeX
>
654 template<class InIter
, class Dist
>
655 bool advance_between_impl(InIter
& cur
, const InIter
& begin
, const InIter
& end
, Dist off
, const std::input_iterator_tag
&)
658 for(; off
!= Dist(0) && cur
!= end
; -- off
)
661 return off
== Dist(0);
664 template<class InIter
, class Dist
>
665 bool advance_between_impl(InIter
& cur
, const InIter
& begin
, const InIter
& end
, Dist off
, const std::bidirectional_iterator_tag
&)
668 for(; off
!= Dist(0) && cur
!= end
; -- off
)
671 for(; off
!= Dist(0) && cur
!= begin
; ++ off
)
674 return off
== Dist(0);
677 template<class InIter
, class Dist
>
678 bool advance_between_impl(InIter
& cur
, const InIter
& begin
, const InIter
& end
, Dist off
, const std::random_access_iterator_tag
&)
684 Dist max
= distance(cur
, end
);
685 ret
= off
== max
|| off
< max
;
689 Dist max
= distance(cur
, end
);
690 ret
= abs(off
) == max
|| abs(off
) < max
;
699 template<class InIter
, class Dist
>
700 bool advance_between(InIter
& cur
, const InIter
& begin
, const InIter
& end
, Dist off
)
702 return advance_between_impl(cur
, begin
, end
, off
, typename
std::iterator_traits
<InIter
>::iterator_category());
705 template<class InIter
, class Elem
, class Traits
, class InIterTag
>
706 class range_streambuf_base
: public std::basic_streambuf
<Elem
, Traits
>
709 typedef typename
std::basic_streambuf
<Elem
, Traits
>::int_type int_type
;
710 typedef typename
std::basic_streambuf
<Elem
, Traits
>::pos_type pos_type
;
711 typedef typename
std::basic_streambuf
<Elem
, Traits
>::off_type off_type
;
721 int_type c
= m_ungetc
;
723 if(c
== Traits::eof())
732 m_ungetc
= Traits::eof();
737 int_type
unget_char(int_type c
)
739 if(c
== Traits::eof())
742 if(m_ungetc
== Traits::eof())
745 return Traits::eof();
751 range_streambuf_base(const InIter
& begin
, const InIter
& end
):
754 m_ungetc(Traits::eof()),
755 m_putbackc(Traits::eof())
760 virtual int_type
pbackfail(int_type c
)
764 if(Traits::eq_int_type(c
, Traits::eof()))
766 if(!Traits::eq_int_type(m_putbackc
, Traits::eof()))
767 ret
= unget_char(m_putbackc
);
774 m_putbackc
= Traits::eof();
778 virtual std::streamsize
showmanyc() const
780 return std::streamsize(-1);
783 virtual int_type
underflow()
785 return unget_char(get_char());
788 virtual int_type
uflow()
790 m_putbackc
= get_char();
794 virtual std::streamsize
xsgetn(Elem
* p
, std::streamsize n
)
796 return _Xsgetn_s(p
, std::numeric_limits
<size_t>::max(), n
);
799 virtual std::streamsize
_Xsgetn_s(Elem
* p
, size_t cb
, std::streamsize n
)
804 for(i
= 0, ib
= 0; i
< n
&& ib
< cb
; ++ i
, ++ ib
, ++ p
)
806 int_type c
= get_char();
808 if(c
== Traits::eof())
811 *p
= Traits::to_char_type(c
);
817 m_putbackc
= Traits::eof();
822 virtual pos_type
seekoff(off_type off
, std::ios_base::seekdir dir
, std::ios_base::openmode mode
)
824 if(((off
== 0 && dir
== std::ios_base::end
) || (off
>= 0 && dir
== std::ios_base::cur
)) && !(mode
& std::ios_base::out
))
826 m_ungetc
= Traits::eof();
828 if(dir
== std::ios_base::end
)
831 advance_between(m_cur
, m_cur
, m_end
, off
);
838 template<class InIter
, class Elem
, class Traits
>
839 class range_streambuf_base
<InIter
, Elem
, Traits
, std::forward_iterator_tag
>:
840 public range_streambuf_base
<InIter
, Elem
, Traits
, std::input_iterator_tag
>
843 typedef typename range_streambuf_base
<InIter
, Elem
, Traits
, std::input_iterator_tag
>::int_type int_type
;
844 typedef typename range_streambuf_base
<InIter
, Elem
, Traits
, std::input_iterator_tag
>::pos_type pos_type
;
845 typedef typename range_streambuf_base
<InIter
, Elem
, Traits
, std::input_iterator_tag
>::off_type off_type
;
848 typedef range_streambuf_base
<InIter
, Elem
, Traits
, std::input_iterator_tag
> super
;
852 range_streambuf_base(const InIter
& begin
, const InIter
& end
):
854 range_streambuf_base
<InIter
, Elem
, Traits
, std::input_iterator_tag
>(begin
, end
)
859 virtual pos_type
seekoff(off_type off
, std::ios_base::seekdir dir
, std::ios_base::openmode mode
)
861 if(!(mode
& std::ios_base::out
) && off
>= 0)
863 if(dir
== std::ios_base::beg
)
864 super::m_cur
= m_begin
;
865 else if(dir
!= std::ios_base::cur
)
866 super::m_cur
= super::m_end
;
868 advance_between(super::m_cur
, m_begin
, super::m_end
, off
);
875 template<class InIter
, class Elem
, class Traits
>
876 class range_streambuf_base
<InIter
, Elem
, Traits
, std::bidirectional_iterator_tag
>: public std::basic_streambuf
<Elem
, Traits
>
879 typedef typename
std::basic_streambuf
<Elem
, Traits
>::int_type int_type
;
880 typedef typename
std::basic_streambuf
<Elem
, Traits
>::pos_type pos_type
;
881 typedef typename
std::basic_streambuf
<Elem
, Traits
>::off_type off_type
;
889 range_streambuf_base(const InIter
& begin
, const InIter
& end
):
897 virtual int_type
pbackfail(int_type c
)
899 int_type ret
= Traits::eof();
906 if(Traits::eq_int_type(c
, Traits::eof()) || Traits::eq_int_type(c
, Traits::to_int_type(*prev
)))
909 ret
= Traits::to_int_type(*m_cur
);
916 virtual std::streamsize
showmanyc() const
918 return std::streamsize(-1);
921 virtual int_type
underflow()
926 return Traits::eof();
929 virtual int_type
uflow()
931 int_type c
= Traits::eof();
942 virtual std::streamsize
xsgetn(Elem
* p
, std::streamsize n
)
944 return _Xsgetn_s(p
, std::numeric_limits
<size_t>::max(), n
);
947 virtual std::streamsize
_Xsgetn_s(Elem
* p
, size_t cb
, std::streamsize n
)
952 for(i
= 0, ib
= 0; i
< n
&& ib
< cb
&& m_cur
!= m_end
; ++ i
, ++ ib
, ++ p
, ++ m_cur
)
953 *p
= Traits::to_char_type(*m_cur
);
958 virtual pos_type
seekoff(off_type off
, std::ios_base::seekdir dir
, std::ios_base::openmode mode
)
960 if(mode
& std::ios_base::out
)
963 if(dir
== std::ios_base::beg
)
965 else if(dir
!= std::ios_base::cur
)
968 if(!advance_between(m_cur
, m_begin
, m_end
, off
))
971 return m_cur
- m_begin
;
975 template<class InIter
, class Elem
, class Traits
>
976 class range_streambuf_base
<InIter
, Elem
, Traits
, std::random_access_iterator_tag
>:
977 public range_streambuf_base
<InIter
, Elem
, Traits
, std::bidirectional_iterator_tag
>
980 typedef range_streambuf_base
<InIter
, Elem
, Traits
, std::bidirectional_iterator_tag
> super
;
983 range_streambuf_base(const InIter
& begin
, const InIter
& end
):
984 range_streambuf_base
<InIter
, Elem
, Traits
, std::bidirectional_iterator_tag
>(begin
, end
)
989 virtual std::streamsize
showmanyc() const
991 return distance(super::m_cur
, super::m_end
);
994 virtual std::streamsize
_Xsgetn_s(Elem
* p
, size_t cb
, std::streamsize n
)
996 std::streamsize maxn
= showmanyc();
1001 if(cb
> static_cast<size_t>(n
))
1002 cb
= static_cast<size_t>(n
);
1004 std::copy(super::m_cur
, super::m_cur
+ cb
, p
);
1009 template<class InIter
, class Elem
= typename
std::iterator_traits
<InIter
>::value_type
, class Traits
= typename
std::char_traits
<Elem
> >
1010 class range_streambuf
:
1011 public range_streambuf_base
<InIter
, Elem
, Traits
, typename
std::iterator_traits
<InIter
>::iterator_category
>
1014 range_streambuf(const InIter
& begin
, const InIter
& end
):
1015 range_streambuf_base
<InIter
, Elem
, Traits
, typename
std::iterator_traits
<InIter
>::iterator_category
>(begin
, end
) { }
1020 struct version_tuple
1023 unsigned short m_fields
[4];
1026 version_tuple(): m_fields() {}
1028 version_tuple(unsigned short major
, unsigned short minor
, unsigned short build_major
= 0, unsigned short build_minor
= 0)
1030 m_fields
[0] = major
;
1031 m_fields
[1] = minor
;
1032 m_fields
[2] = build_major
;
1033 m_fields
[3] = build_minor
;
1036 version_tuple(const version_tuple
& That
)
1038 m_fields
[0] = That
.m_fields
[0];
1039 m_fields
[1] = That
.m_fields
[1];
1040 m_fields
[2] = That
.m_fields
[2];
1041 m_fields
[3] = That
.m_fields
[3];
1044 const version_tuple
& operator=(const version_tuple
& That
)
1046 m_fields
[0] = That
.m_fields
[0];
1047 m_fields
[1] = That
.m_fields
[1];
1048 m_fields
[2] = That
.m_fields
[2];
1049 m_fields
[3] = That
.m_fields
[3];
1053 unsigned short get_major() const
1058 unsigned short get_minor() const
1063 unsigned short get_build_major() const
1068 unsigned short get_build_minor() const
1073 bool operator==(const version_tuple
& That
) const
1075 return memcmp(this->m_fields
, That
.m_fields
, sizeof(this->m_fields
)) == 0;
1078 bool operator<(const version_tuple
& That
) const
1080 return std::lexicographical_compare
1082 &(this->m_fields
[0]) + 0,
1083 &(this->m_fields
[0]) + ARRAYSIZE(this->m_fields
),
1084 &(That
.m_fields
[0]) + 0,
1085 &(That
.m_fields
[0]) + ARRAYSIZE(That
.m_fields
)
1089 bool operator<=(const version_tuple
& That
) const
1091 return (*this == That
) || (*this < That
);
1094 bool operator>(const version_tuple
& That
) const
1096 return !(*this <= That
);
1099 bool operator>=(const version_tuple
& That
) const
1101 return !(*this < That
);
1105 template<class Elem
, class Tr
> std::basic_ostream
<Elem
, Tr
>& operator<<(std::basic_ostream
<Elem
, Tr
>& ostr
, const version_tuple
& v
)
1107 std::ios_base::fmtflags flags
= ostr
.flags();
1108 ostr
.flags(std::ios_base::dec
);
1109 ostr
<< v
.get_major();
1110 ostr
<< Tr::to_char_type('.');
1111 ostr
<< v
.get_minor();
1112 ostr
<< Tr::to_char_type('.');
1113 ostr
<< v
.get_build_major();
1114 ostr
<< Tr::to_char_type('.');
1115 ostr
<< v
.get_build_minor();
1120 template<class Elem
, class Tr
> std::basic_istream
<Elem
, Tr
>& operator>>(std::basic_istream
<Elem
, Tr
>& istr
, version_tuple
& v
)
1122 const std::ctype
<Elem
>& ct
= std::use_facet
<std::ctype
<Elem
> >(istr
.getloc());
1123 unsigned short a
= 0, b
= 0, c
= 0, d
= 0;
1126 std::ios_base::fmtflags flags
= istr
.setf(std::ios_base::dec
);
1132 if(ch
== ct
.widen('.'))
1138 if(ch
== ct
.widen('.'))
1144 if(ch
== ct
.widen('.'))
1155 v
= version_tuple(a
, b
, c
, d
);
1166 istr
.setstate(std::ios_base::failbit
);
1170 struct cl_version
: public version_tuple
1176 cl_version(): m_optimizing() {}
1178 cl_version(const version_tuple
& version_number
, bool optimizing
= false):
1179 version_tuple(version_number
), m_optimizing(optimizing
) {}
1183 unsigned short major
,
1184 unsigned short minor
,
1185 unsigned short build_major
= 0,
1186 unsigned short build_minor
= 0,
1187 bool optimizing
= false,
1188 bool analyze
= false
1190 version_tuple(major
, minor
, build_major
, build_minor
), m_optimizing(optimizing
) {}
1192 cl_version(const cl_version
& That
): version_tuple(That
), m_optimizing(That
.m_optimizing
) {}
1194 const cl_version
& operator=(const cl_version
& That
)
1196 version_tuple::operator=(That
);
1197 m_optimizing
= That
.m_optimizing
;
1201 bool is_optimizing() const
1203 return m_optimizing
;
1206 bool operator==(const cl_version
& That
) const
1208 return this->m_optimizing
== That
.m_optimizing
&& this->version_tuple::operator==(That
);
1211 bool operator<(const cl_version
& That
) const
1213 return (!this->m_optimizing
&& That
.m_optimizing
) || this->version_tuple::operator<(That
);
1216 bool operator<=(const cl_version
& That
) const
1218 return (*this == That
) || (*this < That
);
1221 bool operator>(const cl_version
& That
) const
1223 return !(*this <= That
);
1226 bool operator>=(const cl_version
& That
) const
1228 return !(*this < That
);
1231 operator bool() const
1233 return get_major() || get_minor() || get_build_major() || get_build_minor();
1237 struct link_version
: public version_tuple
1242 link_version(const version_tuple
& version_number
): version_tuple(version_number
) {}
1246 unsigned short major
,
1247 unsigned short minor
,
1248 unsigned short build_major
= 0,
1249 unsigned short build_minor
= 0
1251 version_tuple(major
, minor
, build_major
, build_minor
) {}
1253 link_version(const link_version
& That
): version_tuple(That
) {}
1255 const link_version
& operator=(const link_version
& That
)
1257 version_tuple::operator=(That
);
1261 bool operator==(const cl_version
& That
) const
1263 return this->version_tuple::operator==(That
);
1266 bool operator<(const cl_version
& That
) const
1268 return this->version_tuple::operator<(That
);
1271 bool operator<=(const cl_version
& That
) const
1273 return (*this == That
) || (*this < That
);
1276 bool operator>(const cl_version
& That
) const
1278 return !(*this <= That
);
1281 bool operator>=(const cl_version
& That
) const
1283 return !(*this < That
);
1286 operator bool() const
1288 return get_major() || get_minor() || get_build_major() || get_build_minor();
1292 template<typename T
>
1298 template<class Elem
, class Traits
, class Ax
>
1299 std::basic_string
<Elem
, Traits
, Ax
> get_env(const Elem
* name
, const type_holder
<Traits
>&, const type_holder
<Ax
>&)
1302 std::vector
<Elem
, Ax
> value
;
1306 value
.resize(cchValue
);
1308 if(type_equals
<Elem
, CHAR
>::value
)
1309 cchValue
= GetEnvironmentVariableA(reinterpret_cast<const CHAR
*>(name
), reinterpret_cast<CHAR
*>(cchValue
? &(value
[0]) : NULL
), cchValue
);
1310 else if(type_equals
<Elem
, WCHAR
>::value
)
1311 cchValue
= GetEnvironmentVariableW(reinterpret_cast<const WCHAR
*>(name
), reinterpret_cast<WCHAR
*>(cchValue
? &(value
[0]) : NULL
), cchValue
);
1314 return std::basic_string
<Elem
, Traits
, Ax
>();
1316 if(cchValue
<= value
.size())
1320 value
.resize(cchValue
);
1321 return std::basic_string
<Elem
, Traits
, Ax
>(value
.begin(), value
.end());
1324 template<class Traits
, class Ax
, class Elem
>
1325 std::basic_string
<Elem
, Traits
, Ax
> get_env(const Elem
* name
)
1327 return get_env(name
, type_holder
<Traits
>(), type_holder
<Ax
>());
1330 template<class Traits
, class Elem
>
1331 std::basic_string
<Elem
, Traits
> get_env(const Elem
* name
)
1333 return get_env(name
, type_holder
<Traits
>(), type_holder
<typename
std::basic_string
<Elem
>::allocator_type
>());
1336 template<class Elem
>
1337 std::basic_string
<Elem
> get_env(const Elem
* name
)
1339 return get_env(name
, type_holder
<typename
std::basic_string
<Elem
>::traits_type
>(), type_holder
<typename
std::basic_string
<Elem
>::allocator_type
>());
1342 template<class Elem
>
1343 void set_env(const Elem
* name
, const Elem
* value
)
1345 if(type_equals
<Elem
, CHAR
>::value
)
1346 SetEnvironmentVariableA(reinterpret_cast<const CHAR
*>(name
), reinterpret_cast<const CHAR
*>(value
));
1347 else if(type_equals
<Elem
, WCHAR
>::value
)
1348 SetEnvironmentVariableW(reinterpret_cast<const WCHAR
*>(name
), reinterpret_cast<const WCHAR
*>(value
));
1351 template<class CharT
>
1352 FILE * pipe_open(const CharT
* commandLine
, const CharT
* mode
)
1354 if(type_equals
<CharT
, char>::value
)
1355 return _popen(reinterpret_cast<const char *>(commandLine
), reinterpret_cast<const char *>(mode
));
1356 else if(type_equals
<CharT
, wchar_t>::value
)
1357 return _wpopen(reinterpret_cast<const wchar_t *>(commandLine
), reinterpret_cast<const wchar_t *>(mode
));
1362 template<class CharT
, class CharT2
>
1363 FILE * pipe_open_override_path(const CharT
* commandLine
, const CharT
* mode
, const CharT2
* newPath
)
1366 const CharT2 path
[] = { 'P', 'A', 'T', 'H', 0 };
1368 std::basic_string
<CharT2
> oldPath
;
1372 oldPath
= get_env(path
);
1373 set_env(path
, newPath
);
1378 pipe
= pipe_open(commandLine
, mode
);
1386 set_env(path
, oldPath
.c_str());
1392 set_env(path
, oldPath
.c_str());
1397 template<class InIter
, class IsSep
>
1398 std::pair
<InIter
, InIter
> tokenize(InIter begin
, InIter end
, IsSep isSeparator
)
1400 InIter beginToken
= std::find_if(begin
, end
, std::not1(isSeparator
));
1401 InIter endToken
= std::find_if(beginToken
, end
, isSeparator
);
1402 return std::make_pair(beginToken
, endToken
);
1405 std::locale
clocale("C");
1406 const std::ctype
<char>& cctype
= std::use_facet
<std::ctype
<char> >(clocale
);
1408 template<const std::ctype_base::mask Mask
>
1409 struct is_ctype_l
: public std::binary_function
<std::locale
, char, bool>
1412 result_type
operator()(const first_argument_type
& locale
, second_argument_type c
) const
1414 return std::use_facet
<std::ctype
<char> >(locale
).is(Mask
, c
);
1418 typedef is_ctype_l
<std::ctype_base::space
> is_space_l
;
1420 template<const std::ctype_base::mask Mask
>
1421 struct is_ctype
: public std::unary_function
<char, bool>
1424 const std::locale
& m_locale
;
1425 is_ctype_l
<Mask
> m_is_ctype_l
;
1428 is_ctype(const std::locale
& locale
): m_locale(locale
) {}
1430 result_type
operator()(argument_type c
) const
1432 return m_is_ctype_l(m_locale
, c
);
1436 typedef is_ctype
<std::ctype_base::space
> is_space
;
1438 template<class Elem
, size_t N
>
1439 std::pair
<const Elem
*, const Elem
*> string_literal_token(const Elem (& lit
)[N
])
1441 return std::make_pair(lit
, lit
+ ((N
) - 1));
1444 template<class Iter
, class Iter2
>
1445 bool token_equals(const std::pair
<Iter
, Iter
>& tokenX
, const std::pair
<Iter2
, Iter2
>& tokenY
)
1447 return std::distance(tokenX
.first
, tokenX
.second
) == std::distance(tokenY
.first
, tokenY
.second
) && std::equal(tokenX
.first
, tokenX
.second
, tokenY
.first
);
1450 std::pair
<const char *, const char *> GetClArchToken(const std::string
& arch
)
1453 return string_literal_token("80x86");
1454 else if(arch
== "amd64")
1455 return string_literal_token("x64");
1456 else if(arch
== "arm")
1457 return string_literal_token("ARM");
1459 return string_literal_token("");
1462 template<class Elem
>
1463 cl_version
CheckClVersion(const std::string
& arch
, const Elem
* pathOverride
)
1465 stdio_filebuf
clVersionInfoBuf(pipe_open_override_path(_T("cl /nologo- 2>&1 >nul <nul"), _T("rt"), pathOverride
));
1466 std::istream
clVersionInfo(&clVersionInfoBuf
);
1468 std::pair
<const char *, const char *> archToken
= GetClArchToken(arch
);
1470 version_tuple clVersionNumber
;
1471 bool clOptimizing
= false;
1472 bool clTargetArch
= false;
1474 std::string clVersionLine
;
1475 getline(clVersionInfo
, clVersionLine
);
1479 std::pair
<std::string::iterator
, std::string::iterator
> token
= tokenize(clVersionLine
.begin(), clVersionLine
.end(), is_space(clocale
));
1480 token
.first
!= token
.second
;
1481 token
= tokenize(token
.second
, clVersionLine
.end(), is_space(clocale
))
1484 // Is the compiler optimizing?
1485 if(token_equals(token
, string_literal_token("Optimizing")))
1487 clOptimizing
= true;
1491 // Is this the version number?
1492 range_streambuf
<std::string::const_iterator
> tokenBuf(token
.first
, token
.second
);
1493 std::istream
tokenStream(&tokenBuf
);
1495 if(tokenStream
>> clVersionNumber
)
1498 // Does the compiler support the target architecture?
1499 if(token_equals(token
, archToken
))
1501 clTargetArch
= true;
1507 return cl_version(clVersionNumber
, clOptimizing
);
1509 return cl_version();
1512 cl_version
CheckClVersion(const std::string
& arch
)
1514 return CheckClVersion(arch
, (const char *)0);
1517 std::pair
<const _TCHAR
*, const _TCHAR
*> GetLinkArchToken(const std::string
& arch
)
1520 return string_literal_token(_T("X86"));
1521 else if(arch
== "amd64")
1522 return string_literal_token(_T("X64"));
1523 else if(arch
== "arm")
1524 return string_literal_token(_T("ARM"));
1526 return string_literal_token(_T(""));
1529 template<class Elem
>
1530 link_version
CheckLinkVersion(const std::string
& arch
, const Elem
* pathOverride
)
1532 std::pair
<const _TCHAR
*, const _TCHAR
*> archToken
= GetLinkArchToken(arch
);
1534 std::basic_string
<_TCHAR
> linkCmdLine
;
1535 linkCmdLine
.append(_T("link /nologo- /machine:\""));
1536 linkCmdLine
.append(archToken
.first
, archToken
.second
);
1537 linkCmdLine
.append(_T("\" <nul 2>nul"));
1539 stdio_filebuf
linkOutputBuf(pipe_open_override_path(linkCmdLine
.c_str(), _T("rt"), pathOverride
));
1540 std::istream
linkOutput(&linkOutputBuf
);
1542 link_version linkVersion
;
1544 std::string linkOutputLine
;
1546 if(getline(linkOutput
, linkOutputLine
))
1550 std::pair
<std::string::iterator
, std::string::iterator
> token
= tokenize(linkOutputLine
.begin(), linkOutputLine
.end(), is_space(clocale
));
1551 token
.first
!= token
.second
;
1552 token
= tokenize(token
.second
, linkOutputLine
.end(), is_space(clocale
))
1555 range_streambuf
<std::string::const_iterator
> tokenBuf(token
.first
, token
.second
);
1556 std::istream
tokenStream(&tokenBuf
);
1558 version_tuple linkVersionNumber
;
1560 if(tokenStream
>> linkVersionNumber
)
1562 linkVersion
= linkVersionNumber
;
1570 bool linkArchCheckFail
= false;
1572 while(!linkArchCheckFail
&& getline(linkOutput
, linkOutputLine
))
1575 knuth_morris_pratt::search(linkOutputLine
.begin(), linkOutputLine
.end(), "LNK4012") != linkOutputLine
.end() ||
1576 knuth_morris_pratt::search(linkOutputLine
.begin(), linkOutputLine
.end(), "LNK1146") != linkOutputLine
.end();
1579 if(linkArchCheckFail
)
1580 linkVersion
= link_version();
1586 link_version
CheckLinkVersion(const std::string
& arch
)
1588 return CheckLinkVersion(arch
, (const char *)0);
1591 template<class Elem
, class Traits
, class Ax
>
1592 void CharsToString(HRESULT
& hr
, std::basic_string
<Elem
, Traits
, Ax
>& str
, const Elem
* beginChars
, const Elem
* endChars
)
1595 str
= std::basic_string
<Elem
, Traits
, Ax
>(beginChars
, endChars
);
1598 template<class Traits
, class Ax
>
1599 void CharsToString(HRESULT
& hr
, std::basic_string
<CHAR
, Traits
, Ax
>& str
, const WCHAR
* beginChars
, const WCHAR
* endChars
)
1604 UINT cchChars
= endChars
- beginChars
;
1605 int cch
= WideCharToMultiByte(CP_ACP
, 0, beginChars
, cchChars
, NULL
, 0, NULL
, NULL
);
1609 hr
= HRESULT_FROM_WIN32(GetLastError());
1613 CHAR
* psz
= new CHAR
[cch
];
1621 cch
= WideCharToMultiByte(CP_ACP
, 0, beginChars
, cchChars
, psz
, cch
, NULL
, NULL
);
1624 hr
= HRESULT_FROM_WIN32(GetLastError());
1626 str
= std::basic_string
<CHAR
, Traits
, Ax
>(psz
, psz
+ cch
);
1631 template<class Traits
, class Ax
>
1632 void CharsToString(HRESULT
& hr
, std::basic_string
<WCHAR
, Traits
, Ax
>& str
, const CHAR
* beginChars
, const CHAR
* endChars
)
1637 UINT cchChars
= endChars
- beginChars
;
1638 int cch
= MultiByteToWideChar(CP_ACP
, 0, beginChars
, cchChars
, NULL
, 0);
1642 hr
= HRESULT_FROM_WIN32(GetLastError());
1646 WCHAR
* psz
= new WCHAR
[cch
];
1654 cch
= MultiByteToWideChar(CP_ACP
, 0, beginChars
, cchChars
, psz
, cch
);
1657 hr
= HRESULT_FROM_WIN32(GetLastError());
1659 str
= std::basic_string
<WCHAR
, Traits
, Ax
>(psz
, psz
+ cch
);
1664 template<class Elem
, class Traits
, class Ax
>
1665 void BSTRToString(HRESULT
& hr
, std::basic_string
<Elem
, Traits
, Ax
>& str
, BSTR bstr
)
1667 CharsToString(hr
, str
, bstr
, bstr
+ SysStringLen(bstr
));
1670 std::vector
<std::string
> SplitPath(const std::string
& strPath
)
1672 std::vector
<std::string
> path
;
1673 std::string::const_iterator cur
= strPath
.begin();
1674 std::string::const_iterator end
= strPath
.end();
1676 while(!(cur
== end
))
1678 std::string::const_iterator itemBegin
= cur
;
1679 std::string::const_iterator itemEnd
= std::find(cur
, end
, ';');
1681 if(!(itemBegin
== itemEnd
))
1682 path
.push_back(std::string(itemBegin
, itemEnd
));
1693 std::vector
<std::string
> ParsePlatformPath(HRESULT
& hr
, IDispatch
* pPlatform
, BSTR bstrPath
)
1695 std::vector
<std::string
> path
;
1701 VariantInit(&varPath
);
1702 V_VT(&varPath
) = VT_BSTR
;
1703 V_BSTR(&varPath
) = bstrPath
;
1705 VARIANT varRet
= dispInvoke(hr
, pPlatform
, OLESTR("Evaluate"), varPath
, VT_BSTR
);
1707 std::string strPath
;
1708 BSTRToString(hr
, strPath
, V_BSTR(&varRet
));
1710 VariantClear(&varRet
);
1712 path
= SplitPath(strPath
);
1716 VARIANT
GetDTEProjectEngine(HRESULT
& hr
, IDispatch
* pDTE
)
1718 VARIANT varVCProjects
= oleString(hr
, OLESTR("VCProjects"));
1719 VARIANT varVCProjectEngine
= oleString(hr
, OLESTR("VCProjectEngine"));
1720 VARIANT varProjects
= dispInvoke(hr
, pDTE
, OLESTR("GetObject"), varVCProjects
, VT_DISPATCH
);
1721 VARIANT varProjectsProperties
= dispPropGet(hr
, V_DISPATCH(&varProjects
), OLESTR("Properties"), VT_DISPATCH
);
1722 VARIANT varProjectEngineProperty
= dispInvoke(hr
, V_DISPATCH(&varProjectsProperties
), varVCProjectEngine
, VT_DISPATCH
);
1723 VARIANT varRet
= dispPropGet(hr
, V_DISPATCH(&varProjectEngineProperty
), OLESTR("Object"), VT_DISPATCH
);
1724 VariantClear(&varProjectEngineProperty
);
1725 VariantClear(&varProjectsProperties
);
1726 VariantClear(&varProjects
);
1727 VariantClear(&varVCProjectEngine
);
1728 VariantClear(&varVCProjects
);
1732 VARIANT
GetDTEPlatformPath(HRESULT
& hr
, IDispatch
* pDTE
, BSTR bstrPlatformName
, const OLECHAR
* pszPathName
)
1734 VARIANTARG argsProperties
[2] = { oleString(hr
, OLESTR("VCDirectories")), oleString(hr
, OLESTR("Projects")) };
1736 VARIANT varProperties
;
1737 VariantInit(&varProperties
);
1740 hr
= dispPropGet(pDTE
, OLESTR("Properties"), argsProperties
, ARRAYSIZE(argsProperties
), VT_DISPATCH
, varProperties
);
1742 VARIANT varPathName
= oleString(hr
, pszPathName
);
1743 VARIANT varPath
= dispInvoke(hr
, V_DISPATCH(&varProperties
), varPathName
, VT_BSTR
);
1746 VariantInit(&varRet
);
1750 const OLECHAR
* pCur
= V_BSTR(&varPath
);
1751 const OLECHAR
* pEnd
= V_BSTR(&varPath
) + SysStringLen(V_BSTR(&varPath
));
1753 while(!(pCur
== pEnd
))
1755 const OLECHAR
* pBeginName
= pCur
;
1756 const OLECHAR
* pEndName
= std::find(pBeginName
, pEnd
, OLESTR('|'));
1757 const OLECHAR
* pBeginValue
= pEndName
== pEnd
? pEndName
: pEndName
+ 1;
1758 const OLECHAR
* pEndValue
= std::find(pBeginValue
, pEnd
, OLESTR('|'));
1765 BSTR bstrName
= SysAllocStringLen(pBeginName
, pEndName
- pBeginName
);
1769 hr
= VarBstrCmp(bstrName
, bstrPlatformName
, 0, NORM_IGNORECASE
);
1773 BSTR bstrRet
= SysAllocStringLen(pBeginValue
, pEndValue
- pBeginValue
);
1777 V_VT(&varRet
) = VT_BSTR
;
1778 V_BSTR(&varRet
) = bstrRet
;
1784 SysFreeString(bstrName
);
1786 if(FAILED(hr
) || hr
== VARCMP_EQ
)
1797 VariantClear(&varPath
);
1798 VariantClear(&varPathName
);
1799 VariantClear(&varProperties
);
1800 VariantClear(&argsProperties
[1]);
1801 VariantClear(&argsProperties
[0]);
1803 if(SUCCEEDED(hr
) && V_VT(&varRet
) != VT_BSTR
)
1805 VariantClear(&varRet
);
1806 varRet
= oleString(hr
, OLESTR(""));
1812 cl_version msCompilerVersion
;
1813 std::string msCompilerPath
;
1814 std::vector
<std::string
> msCompilerIncludeDirs
; // TODO: use this
1815 std::string msCompilerSource
; // TODO: use this
1817 link_version msLinkerVersion
;
1818 std::string msLinkerPath
;
1819 std::vector
<std::string
> msLinkerLibDirs
; // TODO: use this
1820 std::string msLinkerSource
; // TODO: use this
1822 void ProcessVCPlatform(HRESULT
& hr
, const std::string
& arch
, bool wantCompiler
, bool wantLinker
, IDispatch
* pVCProjectEngine
, IDispatch
* pPlatform
, BSTR bstrPath
, BSTR bstrInclude
, BSTR bstrLib
)
1827 std::basic_string
<OLECHAR
> strPath
= replace(std::basic_string
<OLECHAR
>(bstrPath
, SysStringLen(bstrPath
)), OLESTR("$(PATH)"), OLESTR("%PATH%"));
1830 VariantInit(&varPath
);
1831 V_VT(&varPath
) = VT_BSTR
;
1832 V_BSTR(&varPath
) = SysAllocStringLen(strPath
.c_str(), strPath
.size());
1834 if(!V_BSTR(&varPath
))
1837 VARIANT varRet
= dispInvoke(hr
, pPlatform
, OLESTR("Evaluate"), varPath
, VT_BSTR
);
1841 std::basic_string
<OLECHAR
> strPathOverride
= replace
1843 std::basic_string
<OLECHAR
>(V_BSTR(&varRet
), V_BSTR(&varRet
) + SysStringLen(V_BSTR(&varRet
))),
1845 get_env(OLESTR("PATH"))
1848 cl_version clVersion
;
1849 link_version linkVersion
;
1852 clVersion
= CheckClVersion(arch
, strPathOverride
.c_str());
1855 linkVersion
= CheckLinkVersion(arch
, strPathOverride
.c_str());
1857 // TODO: need a way to choose the desired tools and which version
1858 // BUGBUG: for now, only set the new version if both tools are the highest version yet
1859 if((!wantCompiler
|| (clVersion
&& clVersion
> msCompilerVersion
)) && (!wantLinker
|| (linkVersion
&& linkVersion
> msLinkerVersion
)))
1861 std::string strPath
;
1862 BSTRToString(hr
, strPath
, V_BSTR(&varRet
));
1863 strPath
= replace(strPath
, "%PATH%", "$(PATH)");
1865 std::vector
<std::string
> include
= ParsePlatformPath(hr
, pPlatform
, bstrInclude
);
1866 std::vector
<std::string
> lib
= ParsePlatformPath(hr
, pPlatform
, bstrLib
);
1872 msCompilerVersion
= clVersion
;
1873 msCompilerPath
= strPath
;
1874 msCompilerIncludeDirs
= include
;
1875 //msCompilerSource; // TODO: fill this in
1880 msLinkerVersion
= linkVersion
;
1881 msLinkerPath
= strPath
;
1882 msLinkerLibDirs
= lib
;
1883 //msLinkerSource; // TODO: fill this in
1889 VariantClear(&varPath
);
1890 VariantClear(&varRet
);
1893 bool IsVCPlatformSupported(HRESULT
& hr
, const std::string
& arch
, IDispatch
* pPlatform
)
1897 VARIANT varPlatformName
= dispPropGet(hr
, pPlatform
, OLESTR("Name"), VT_BSTR
);
1901 VARIANT varWin32
= oleString(hr
, OLESTR("Win32"));
1905 hr
= VarBstrCmp(V_BSTR(&varWin32
), V_BSTR(&varPlatformName
), 0, NORM_IGNORECASE
);
1906 ret
= hr
== VARCMP_EQ
;
1909 VariantClear(&varWin32
);
1911 else if(arch
== "amd64")
1913 VARIANT varX64
= oleString(hr
, OLESTR("x64"));
1917 hr
= VarBstrCmp(V_BSTR(&varX64
), V_BSTR(&varPlatformName
), 0, NORM_IGNORECASE
);
1918 ret
= hr
== VARCMP_EQ
;
1921 VariantClear(&varX64
);
1923 else if(arch
== "arm")
1925 VARIANT varARM
= oleString(hr
, OLESTR("ARM"));
1926 VARIANT varARCHFAM
= oleString(hr
, OLESTR("ARCHFAM"));
1927 VARIANT varArchFamily
= dispInvoke(hr
, pPlatform
, OLESTR("GetMacroValue"), varARCHFAM
, VT_BSTR
);
1931 hr
= VarBstrCmp(V_BSTR(&varARM
), V_BSTR(&varArchFamily
), 0, NORM_IGNORECASE
);
1932 ret
= hr
== VARCMP_EQ
;
1935 VariantClear(&varArchFamily
);
1936 VariantClear(&varARCHFAM
);
1937 VariantClear(&varARM
);
1940 VariantClear(&varPlatformName
);
1942 return SUCCEEDED(hr
) && ret
;
1945 void EnumerateVCTools(const std::string
& arch
, bool wantCompiler
, bool wantLinker
, const OLECHAR
* szProductTag
)
1947 size_t cchProductTag
= std::wcslen(szProductTag
);
1950 hr
= OleInitialize(NULL
);
1954 std::basic_string
<TCHAR
> strProductKey
;
1955 CharsToString(hr
, strProductKey
, szProductTag
, szProductTag
+ cchProductTag
);
1959 strProductKey
= TEXT("SOFTWARE\\Microsoft\\") + strProductKey
;
1961 HKEY hkVisualStudio
;
1962 hr
= HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_LOCAL_MACHINE
, strProductKey
.c_str(), 0, KEY_ENUMERATE_SUB_KEYS
, &hkVisualStudio
));
1966 for(DWORD i
= 0; ; ++ i
)
1968 TCHAR szProductVersion
[255 + 1];
1969 DWORD cchProductVersion
= ARRAYSIZE(szProductVersion
);
1971 hr
= HRESULT_FROM_WIN32(RegEnumKeyEx(hkVisualStudio
, i
, szProductVersion
, &cchProductVersion
, NULL
, NULL
, NULL
, NULL
));
1975 std::basic_string
<OLECHAR
> strProductVersion
;
1976 CharsToString(hr
, strProductVersion
, szProductVersion
, szProductVersion
+ cchProductVersion
);
1980 std::basic_string
<OLECHAR
> strDTEProgId(szProductTag
, szProductTag
+ cchProductTag
);
1981 strDTEProgId
+= OLESTR(".DTE.");
1982 strDTEProgId
+= strProductVersion
;
1985 hr
= CLSIDFromProgID(strDTEProgId
.c_str(), &clsidDTE
);
1990 hr
= CoCreateInstance(clsidDTE
, NULL
, CLSCTX_ALL
, IID_IDispatch
, (void **)(void *)&pDTE
);
1994 VARIANT varProjectEngine
= GetDTEProjectEngine(hr
, pDTE
);
1995 VARIANT varPlatforms
= dispPropGet(hr
, V_DISPATCH(&varProjectEngine
), OLESTR("Platforms"), VT_DISPATCH
);
1996 VARIANT varCount
= dispPropGet(hr
, V_DISPATCH(&varPlatforms
), OLESTR("Count"), VT_I4
);
1999 V_VT(&varI
) = VT_I4
;
2001 for(V_I4(&varI
) = 1; V_I4(&varI
) <= V_I4(&varCount
); ++ V_I4(&varI
))
2003 VARIANT varPlatform
= dispInvoke(hr
, V_DISPATCH(&varPlatforms
), varI
, VT_DISPATCH
);
2005 if(IsVCPlatformSupported(hr
, arch
, V_DISPATCH(&varPlatform
)))
2007 VARIANT varPlatformName
= dispPropGet(hr
, V_DISPATCH(&varPlatform
), OLESTR("Name"), VT_BSTR
);
2008 VARIANT varPath
= GetDTEPlatformPath(hr
, pDTE
, V_BSTR(&varPlatformName
), OLESTR("ExecutableDirectories"));
2009 VARIANT varInclude
= GetDTEPlatformPath(hr
, pDTE
, V_BSTR(&varPlatformName
), OLESTR("IncludeDirectories"));
2010 VARIANT varLib
= GetDTEPlatformPath(hr
, pDTE
, V_BSTR(&varPlatformName
), OLESTR("LibraryDirectories"));
2012 ProcessVCPlatform(hr
, arch
, wantCompiler
, wantLinker
, V_DISPATCH(&varProjectEngine
), V_DISPATCH(&varPlatform
), V_BSTR(&varPath
), V_BSTR(&varInclude
), V_BSTR(&varLib
));
2014 VariantClear(&varLib
);
2015 VariantClear(&varInclude
);
2016 VariantClear(&varPath
);
2017 VariantClear(&varPlatformName
);
2020 VariantClear(&varPlatform
);
2023 VariantClear(&varI
);
2024 VariantClear(&varCount
);
2025 VariantClear(&varPlatforms
);
2026 VariantClear(&varProjectEngine
);
2032 // TODO: print an error message here
2037 else if(hr
== HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS
))
2052 const TCHAR
* GetDDKArchPath(const std::string
& arch
)
2056 else if(arch
== "amd64")
2057 return TEXT("amd64");
2062 void EnumerateDDKTools(const std::string
& arch
, bool wantCompiler
, bool wantLinker
)
2064 const TCHAR
* pszArchPath
= GetDDKArchPath(arch
);
2066 if(pszArchPath
== NULL
)
2072 hr
= HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_LOCAL_MACHINE
, TEXT("SOFTWARE\\Microsoft\\WINDDK"), 0, KEY_ENUMERATE_SUB_KEYS
, &hkDDK
));
2076 for(DWORD i
= 0; ; ++ i
)
2078 TCHAR szDDKVersion
[255 + ARRAYSIZE(TEXT("\\Setup"))];
2079 DWORD cchDDKVersion
= ARRAYSIZE(szDDKVersion
);
2081 hr
= HRESULT_FROM_WIN32(RegEnumKeyEx(hkDDK
, i
, szDDKVersion
, &cchDDKVersion
, NULL
, NULL
, NULL
, NULL
));
2085 memcpy(szDDKVersion
+ cchDDKVersion
, TEXT("\\Setup"), sizeof(TEXT("\\Setup")));
2088 hr
= HRESULT_FROM_WIN32(RegOpenKeyEx(hkDDK
, szDDKVersion
, 0, KEY_QUERY_VALUE
, &hkDDKVersion
));
2092 TCHAR szDDKPath
[MAX_PATH
];
2093 DWORD cbDDKPath
= sizeof(szDDKPath
);
2096 hr
= HRESULT_FROM_WIN32(RegQueryValueEx(hkDDKVersion
, TEXT("BUILD"), NULL
, &dwType
, reinterpret_cast<BYTE
*>(szDDKPath
), &cbDDKPath
));
2098 if(SUCCEEDED(hr
) && dwType
== REG_SZ
)
2101 static const TCHAR
* const a_szBinPaths
[] = { TEXT("x86") };
2102 #elif defined(_AMD64_)
2103 // Prefer native tools, fall back on x86 if necessary
2104 static const TCHAR
* const a_szBinPaths
[] = { TEXT("amd64"), TEXT("x86") };
2105 #elif defined(_IA64_)
2106 // Prefer native tools, fall back on x86 if necessary
2107 static const TCHAR
* const a_szBinPaths
[] = { TEXT("ia64"), TEXT("x86") };
2109 szDDKPath
[cbDDKPath
/ sizeof(TCHAR
)] = 0;
2110 std::basic_string
<TCHAR
> strDDKPath(szDDKPath
);
2111 strDDKPath
+= TEXT("\\bin\\");
2113 std::basic_string
<TCHAR
>::size_type cchCutoff
= strDDKPath
.length();
2115 for(unsigned i
= 0; i
< ARRAYSIZE(a_szBinPaths
); ++ i
)
2117 strDDKPath
.resize(cchCutoff
);
2118 strDDKPath
+= a_szBinPaths
[i
];
2119 strDDKPath
+= TEXT("\\");
2120 strDDKPath
+= pszArchPath
;
2122 cl_version clVersion
;
2123 link_version linkVersion
;
2126 clVersion
= CheckClVersion(arch
, strDDKPath
.c_str());
2129 linkVersion
= CheckLinkVersion(arch
, strDDKPath
.c_str());
2131 if((!wantCompiler
|| (clVersion
&& clVersion
> msCompilerVersion
)) && (!wantLinker
|| (linkVersion
&& linkVersion
> msLinkerVersion
)))
2133 std::string strPath
;
2134 CharsToString(hr
, strPath
, strDDKPath
.c_str(), strDDKPath
.c_str() + strDDKPath
.length());
2140 msCompilerVersion
= clVersion
;
2141 msCompilerPath
= strPath
;
2142 msCompilerIncludeDirs
.clear();
2143 //msCompilerSource; // TODO: fill this in
2148 msLinkerVersion
= linkVersion
;
2149 msLinkerPath
= strPath
;
2150 msLinkerLibDirs
.clear();
2151 //msLinkerSource; // TODO: fill this in
2160 RegCloseKey(hkDDKVersion
);
2163 else if(hr
== HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS
))
2177 void DetectEnvironmentVCTools(const std::string
& arch
, bool wantCompiler
, bool wantLinker
)
2179 cl_version clVersion
;
2180 link_version linkVersion
;
2183 clVersion
= CheckClVersion(arch
);
2186 linkVersion
= CheckLinkVersion(arch
);
2188 if((!wantCompiler
|| (clVersion
&& clVersion
> msCompilerVersion
)) && (!wantLinker
|| (linkVersion
&& linkVersion
> msLinkerVersion
)))
2192 msCompilerVersion
= clVersion
;
2193 msCompilerPath
.clear();
2194 msCompilerIncludeDirs
= SplitPath(get_env("INCLUDE"));
2195 msCompilerSource
= "environment";
2200 msLinkerVersion
= linkVersion
;
2201 msLinkerPath
.clear();
2202 msLinkerLibDirs
= SplitPath(get_env("LIB"));
2203 msLinkerSource
= "environment";
2208 void EnumerateMicrosoftTools(const std::string
& arch
, bool wantCompiler
, bool wantLinker
)
2210 DetectEnvironmentVCTools(arch
, wantCompiler
, wantLinker
);
2212 if(!msCompilerVersion
|| !msLinkerVersion
)
2214 EnumerateVCTools(arch
, wantCompiler
, wantLinker
, OLESTR("VisualStudio"));
2215 EnumerateVCTools(arch
, wantCompiler
, wantLinker
, OLESTR("VCExpress"));
2216 EnumerateDDKTools(arch
, wantCompiler
, wantLinker
);
2223 MingwBackend::DetectMicrosoftCompiler ( std::string
& version
, std::string
& path
)
2225 bool wantCompiler
= ProjectNode
.configuration
.Compiler
== MicrosoftC
;
2226 bool wantLinker
= ProjectNode
.configuration
.Linker
== MicrosoftLink
;
2228 if ( wantCompiler
&& !msCompilerVersion
)
2229 EnumerateMicrosoftTools ( Environment::GetArch(), wantCompiler
, wantLinker
);
2231 bool ret
= wantCompiler
&& msCompilerVersion
;
2235 compilerNeedsHelper
= true;
2236 compilerCommand
= "cl";
2238 std::ostringstream compilerVersion
;
2239 compilerVersion
<< msCompilerVersion
;
2240 version
= compilerVersion
.str();
2241 path
= msCompilerPath
;
2248 MingwBackend::DetectMicrosoftLinker ( std::string
& version
, std::string
& path
)
2250 bool wantCompiler
= ProjectNode
.configuration
.Compiler
== MicrosoftC
;
2251 bool wantLinker
= ProjectNode
.configuration
.Linker
== MicrosoftLink
;
2253 if ( wantLinker
&& !msLinkerVersion
)
2254 EnumerateMicrosoftTools ( Environment::GetArch(), wantCompiler
, wantLinker
);
2256 bool ret
= wantLinker
&& msLinkerVersion
;
2260 binutilsNeedsHelper
= msLinkerPath
.length() != 0;
2261 binutilsCommand
= "link";
2263 std::ostringstream linkerVersion
;
2264 linkerVersion
<< msLinkerVersion
;
2265 version
= linkerVersion
.str();
2266 path
= msLinkerPath
;
2274 // TODO? attempt to support Microsoft tools on non-Windows?
2277 #include "../../pch.h"
2282 MingwBackend::DetectMicrosoftCompiler ( std::string
&, std::string
& )
2288 MingwBackend::DetectMicrosoftLinker ( std::string
&, std::string
& )