|
SimpleOpt
|
00001 00196 #ifndef INCLUDED_SimpleOpt 00197 #define INCLUDED_SimpleOpt 00198 00199 // Default the max arguments to a fixed value. If you want to be able to 00200 // handle any number of arguments, then predefine this to 0 and it will 00201 // use an internal dynamically allocated buffer instead. 00202 #ifdef SO_MAX_ARGS 00203 # define SO_STATICBUF SO_MAX_ARGS 00204 #else 00205 # include <stdlib.h> // malloc, free 00206 # include <string.h> // memcpy 00207 # define SO_STATICBUF 50 00208 #endif 00209 00211 typedef enum _ESOError 00212 { 00214 SO_SUCCESS = 0, 00215 00218 SO_OPT_INVALID = -1, 00219 00222 SO_OPT_MULTIPLE = -2, 00223 00226 SO_ARG_INVALID = -3, 00227 00230 SO_ARG_INVALID_TYPE = -4, 00231 00233 SO_ARG_MISSING = -5, 00234 00237 SO_ARG_INVALID_DATA = -6 00238 } ESOError; 00239 00241 enum _ESOFlags 00242 { 00244 SO_O_EXACT = 0x0001, 00245 00248 SO_O_NOSLASH = 0x0002, 00249 00252 SO_O_SHORTARG = 0x0004, 00253 00256 SO_O_CLUMP = 0x0008, 00257 00260 SO_O_USEALL = 0x0010, 00261 00266 SO_O_NOERR = 0x0020, 00267 00272 SO_O_PEDANTIC = 0x0040, 00273 00275 SO_O_ICASE_SHORT = 0x0100, 00276 00278 SO_O_ICASE_LONG = 0x0200, 00279 00282 SO_O_ICASE_WORD = 0x0400, 00283 00285 SO_O_ICASE = 0x0700 00286 }; 00287 00293 typedef enum _ESOArgType { 00296 SO_NONE, 00297 00300 SO_REQ_SEP, 00301 00304 SO_REQ_CMB, 00305 00308 SO_OPT, 00309 00313 SO_MULTI 00314 } ESOArgType; 00315 00317 #define SO_END_OF_OPTIONS { -1, NULL, SO_NONE } 00318 00319 #ifdef _DEBUG 00320 # ifdef _MSC_VER 00321 # include <crtdbg.h> 00322 # define SO_ASSERT(b) _ASSERTE(b) 00323 # else 00324 # include <assert.h> 00325 # define SO_ASSERT(b) assert(b) 00326 # endif 00327 #else 00328 # define SO_ASSERT(b) //!< assertion used to test input data 00329 #endif 00330 00331 // --------------------------------------------------------------------------- 00332 // MAIN TEMPLATE CLASS 00333 // --------------------------------------------------------------------------- 00334 00336 template<class SOCHAR> 00337 class CSimpleOptTempl 00338 { 00339 public: 00341 struct SOption { 00343 int nId; 00344 00348 const SOCHAR * pszArg; 00349 00351 ESOArgType nArgType; 00352 }; 00353 00355 CSimpleOptTempl() 00356 : m_rgShuffleBuf(NULL) 00357 { 00358 Init(0, NULL, NULL, 0); 00359 } 00360 00362 CSimpleOptTempl( 00363 int argc, 00364 SOCHAR * argv[], 00365 const SOption * a_rgOptions, 00366 int a_nFlags = 0 00367 ) 00368 : m_rgShuffleBuf(NULL) 00369 { 00370 Init(argc, argv, a_rgOptions, a_nFlags); 00371 } 00372 00373 #ifndef SO_MAX_ARGS 00374 00375 ~CSimpleOptTempl() { if (m_rgShuffleBuf) free(m_rgShuffleBuf); } 00376 #endif 00377 00399 bool Init( 00400 int a_argc, 00401 SOCHAR * a_argv[], 00402 const SOption * a_rgOptions, 00403 int a_nFlags = 0 00404 ); 00405 00410 inline void SetOptions(const SOption * a_rgOptions) { 00411 m_rgOptions = a_rgOptions; 00412 } 00413 00421 inline void SetFlags(int a_nFlags) { m_nFlags = a_nFlags; } 00422 00424 inline bool HasFlag(int a_nFlag) const { 00425 return (m_nFlags & a_nFlag) == a_nFlag; 00426 } 00427 00444 bool Next(); 00445 00449 void Stop(); 00450 00456 inline ESOError LastError() const { return m_nLastError; } 00457 00463 inline int OptionId() const { return m_nOptionId; } 00464 00470 inline const SOCHAR * OptionText() const { return m_pszOptionText; } 00471 00477 inline SOCHAR * OptionArg() const { return m_pszOptionArg; } 00478 00491 SOCHAR ** MultiArg(int n); 00492 00498 inline int FileCount() const { return m_argc - m_nLastArg; } 00499 00505 inline SOCHAR * File(int n) const { 00506 SO_ASSERT(n >= 0 && n < FileCount()); 00507 return m_argv[m_nLastArg + n]; 00508 } 00509 00511 inline SOCHAR ** Files() const { return &m_argv[m_nLastArg]; } 00512 00513 private: 00514 CSimpleOptTempl(const CSimpleOptTempl &); // disabled 00515 CSimpleOptTempl & operator=(const CSimpleOptTempl &); // disabled 00516 00517 SOCHAR PrepareArg(SOCHAR * a_pszString) const; 00518 bool NextClumped(); 00519 void ShuffleArg(int a_nStartIdx, int a_nCount); 00520 int LookupOption(const SOCHAR * a_pszOption) const; 00521 int CalcMatch(const SOCHAR *a_pszSource, const SOCHAR *a_pszTest) const; 00522 00523 // Find the '=' character within a string. 00524 inline SOCHAR * FindEquals(SOCHAR *s) const { 00525 while (*s && *s != (SOCHAR)'=') ++s; 00526 return *s ? s : NULL; 00527 } 00528 bool IsEqual(SOCHAR a_cLeft, SOCHAR a_cRight, int a_nArgType) const; 00529 00530 inline void Copy(SOCHAR ** ppDst, SOCHAR ** ppSrc, int nCount) const { 00531 #ifdef SO_MAX_ARGS 00532 // keep our promise of no CLIB usage 00533 while (nCount-- > 0) *ppDst++ = *ppSrc++; 00534 #else 00535 memcpy(ppDst, ppSrc, nCount * sizeof(SOCHAR*)); 00536 #endif 00537 } 00538 00539 private: 00540 const SOption * m_rgOptions; 00541 int m_nFlags; 00542 int m_nOptionIdx; 00543 int m_nOptionId; 00544 int m_nNextOption; 00545 int m_nLastArg; 00546 int m_argc; 00547 SOCHAR ** m_argv; 00548 const SOCHAR * m_pszOptionText; 00549 SOCHAR * m_pszOptionArg; 00550 SOCHAR * m_pszClump; 00551 SOCHAR m_szShort[3]; 00552 ESOError m_nLastError; 00553 SOCHAR ** m_rgShuffleBuf; 00554 }; 00555 00556 // --------------------------------------------------------------------------- 00557 // IMPLEMENTATION 00558 // --------------------------------------------------------------------------- 00559 00560 template<class SOCHAR> 00561 bool 00562 CSimpleOptTempl<SOCHAR>::Init( 00563 int a_argc, 00564 SOCHAR * a_argv[], 00565 const SOption * a_rgOptions, 00566 int a_nFlags 00567 ) 00568 { 00569 m_argc = a_argc; 00570 m_nLastArg = a_argc; 00571 m_argv = a_argv; 00572 m_rgOptions = a_rgOptions; 00573 m_nLastError = SO_SUCCESS; 00574 m_nOptionIdx = 0; 00575 m_nOptionId = -1; 00576 m_pszOptionText = NULL; 00577 m_pszOptionArg = NULL; 00578 m_nNextOption = (a_nFlags & SO_O_USEALL) ? 0 : 1; 00579 m_szShort[0] = (SOCHAR)'-'; 00580 m_szShort[2] = (SOCHAR)'\0'; 00581 m_nFlags = a_nFlags; 00582 m_pszClump = NULL; 00583 00584 #ifdef SO_MAX_ARGS 00585 if (m_argc > SO_MAX_ARGS) { 00586 m_nLastError = SO_ARG_INVALID_DATA; 00587 m_nLastArg = 0; 00588 return false; 00589 } 00590 #else 00591 if (m_rgShuffleBuf) { 00592 free(m_rgShuffleBuf); 00593 } 00594 if (m_argc > SO_STATICBUF) { 00595 m_rgShuffleBuf = (SOCHAR**) malloc(sizeof(SOCHAR*) * m_argc); 00596 if (!m_rgShuffleBuf) { 00597 return false; 00598 } 00599 } 00600 #endif 00601 00602 return true; 00603 } 00604 00605 template<class SOCHAR> 00606 bool 00607 CSimpleOptTempl<SOCHAR>::Next() 00608 { 00609 #ifdef SO_MAX_ARGS 00610 if (m_argc > SO_MAX_ARGS) { 00611 SO_ASSERT(!"Too many args! Check the return value of Init()!"); 00612 return false; 00613 } 00614 #endif 00615 00616 // process a clumped option string if appropriate 00617 if (m_pszClump && *m_pszClump) { 00618 // silently discard invalid clumped option 00619 bool bIsValid = NextClumped(); 00620 while (*m_pszClump && !bIsValid && HasFlag(SO_O_NOERR)) { 00621 bIsValid = NextClumped(); 00622 } 00623 00624 // return this option if valid or we are returning errors 00625 if (bIsValid || !HasFlag(SO_O_NOERR)) { 00626 return true; 00627 } 00628 } 00629 SO_ASSERT(!m_pszClump || !*m_pszClump); 00630 m_pszClump = NULL; 00631 00632 // init for the next option 00633 m_nOptionIdx = m_nNextOption; 00634 m_nOptionId = -1; 00635 m_pszOptionText = NULL; 00636 m_pszOptionArg = NULL; 00637 m_nLastError = SO_SUCCESS; 00638 00639 // find the next option 00640 SOCHAR cFirst; 00641 int nTableIdx = -1; 00642 int nOptIdx = m_nOptionIdx; 00643 while (nTableIdx < 0 && nOptIdx < m_nLastArg) { 00644 SOCHAR * pszArg = m_argv[nOptIdx]; 00645 m_pszOptionArg = NULL; 00646 00647 // find this option in the options table 00648 cFirst = PrepareArg(pszArg); 00649 if (pszArg[0] == (SOCHAR)'-') { 00650 // find any combined argument string and remove equals sign 00651 m_pszOptionArg = FindEquals(pszArg); 00652 if (m_pszOptionArg) { 00653 *m_pszOptionArg++ = (SOCHAR)'\0'; 00654 } 00655 } 00656 nTableIdx = LookupOption(pszArg); 00657 00658 // if we didn't find this option but if it is a short form 00659 // option then we try the alternative forms 00660 if (nTableIdx < 0 00661 && !m_pszOptionArg 00662 && pszArg[0] == (SOCHAR)'-' 00663 && pszArg[1] 00664 && pszArg[1] != (SOCHAR)'-' 00665 && pszArg[2]) 00666 { 00667 // test for a short-form with argument if appropriate 00668 if (HasFlag(SO_O_SHORTARG)) { 00669 m_szShort[1] = pszArg[1]; 00670 int nIdx = LookupOption(m_szShort); 00671 if (nIdx >= 0 00672 && (m_rgOptions[nIdx].nArgType == SO_REQ_CMB 00673 || m_rgOptions[nIdx].nArgType == SO_OPT)) 00674 { 00675 m_pszOptionArg = &pszArg[2]; 00676 pszArg = m_szShort; 00677 nTableIdx = nIdx; 00678 } 00679 } 00680 00681 // test for a clumped short-form option string and we didn't 00682 // match on the short-form argument above 00683 if (nTableIdx < 0 && HasFlag(SO_O_CLUMP)) { 00684 m_pszClump = &pszArg[1]; 00685 ++m_nNextOption; 00686 if (nOptIdx > m_nOptionIdx) { 00687 ShuffleArg(m_nOptionIdx, nOptIdx - m_nOptionIdx); 00688 } 00689 return Next(); 00690 } 00691 } 00692 00693 // The option wasn't found. If it starts with a switch character 00694 // and we are not suppressing errors for invalid options then it 00695 // is reported as an error, otherwise it is data. 00696 if (nTableIdx < 0) { 00697 if (!HasFlag(SO_O_NOERR) && pszArg[0] == (SOCHAR)'-') { 00698 m_pszOptionText = pszArg; 00699 break; 00700 } 00701 00702 pszArg[0] = cFirst; 00703 ++nOptIdx; 00704 if (m_pszOptionArg) { 00705 *(--m_pszOptionArg) = (SOCHAR)'='; 00706 } 00707 } 00708 } 00709 00710 // end of options 00711 if (nOptIdx >= m_nLastArg) { 00712 if (nOptIdx > m_nOptionIdx) { 00713 ShuffleArg(m_nOptionIdx, nOptIdx - m_nOptionIdx); 00714 } 00715 return false; 00716 } 00717 ++m_nNextOption; 00718 00719 // get the option id 00720 ESOArgType nArgType = SO_NONE; 00721 if (nTableIdx < 0) { 00722 m_nLastError = (ESOError) nTableIdx; // error code 00723 } 00724 else { 00725 m_nOptionId = m_rgOptions[nTableIdx].nId; 00726 m_pszOptionText = m_rgOptions[nTableIdx].pszArg; 00727 00728 // ensure that the arg type is valid 00729 nArgType = m_rgOptions[nTableIdx].nArgType; 00730 switch (nArgType) { 00731 case SO_NONE: 00732 if (m_pszOptionArg) { 00733 m_nLastError = SO_ARG_INVALID; 00734 } 00735 break; 00736 00737 case SO_REQ_SEP: 00738 if (m_pszOptionArg) { 00739 // they wanted separate args, but we got a combined one, 00740 // unless we are pedantic, just accept it. 00741 if (HasFlag(SO_O_PEDANTIC)) { 00742 m_nLastError = SO_ARG_INVALID_TYPE; 00743 } 00744 } 00745 // more processing after we shuffle 00746 break; 00747 00748 case SO_REQ_CMB: 00749 if (!m_pszOptionArg) { 00750 m_nLastError = SO_ARG_MISSING; 00751 } 00752 break; 00753 00754 case SO_OPT: 00755 // nothing to do 00756 break; 00757 00758 case SO_MULTI: 00759 // nothing to do. Caller must now check for valid arguments 00760 // using GetMultiArg() 00761 break; 00762 } 00763 } 00764 00765 // shuffle the files out of the way 00766 if (nOptIdx > m_nOptionIdx) { 00767 ShuffleArg(m_nOptionIdx, nOptIdx - m_nOptionIdx); 00768 } 00769 00770 // we need to return the separate arg if required, just re-use the 00771 // multi-arg code because it all does the same thing 00772 if ( nArgType == SO_REQ_SEP 00773 && !m_pszOptionArg 00774 && m_nLastError == SO_SUCCESS) 00775 { 00776 SOCHAR ** ppArgs = MultiArg(1); 00777 if (ppArgs) { 00778 m_pszOptionArg = *ppArgs; 00779 } 00780 } 00781 00782 return true; 00783 } 00784 00785 template<class SOCHAR> 00786 void 00787 CSimpleOptTempl<SOCHAR>::Stop() 00788 { 00789 if (m_nNextOption < m_nLastArg) { 00790 ShuffleArg(m_nNextOption, m_nLastArg - m_nNextOption); 00791 } 00792 } 00793 00794 template<class SOCHAR> 00795 SOCHAR 00796 CSimpleOptTempl<SOCHAR>::PrepareArg( 00797 SOCHAR * a_pszString 00798 ) const 00799 { 00800 #ifdef _WIN32 00801 // On Windows we can accept the forward slash as a single character 00802 // option delimiter, but it cannot replace the '-' option used to 00803 // denote stdin. On Un*x paths may start with slash so it may not 00804 // be used to start an option. 00805 if (!HasFlag(SO_O_NOSLASH) 00806 && a_pszString[0] == (SOCHAR)'/' 00807 && a_pszString[1] 00808 && a_pszString[1] != (SOCHAR)'-') 00809 { 00810 a_pszString[0] = (SOCHAR)'-'; 00811 return (SOCHAR)'/'; 00812 } 00813 #endif 00814 return a_pszString[0]; 00815 } 00816 00817 template<class SOCHAR> 00818 bool 00819 CSimpleOptTempl<SOCHAR>::NextClumped() 00820 { 00821 // prepare for the next clumped option 00822 m_szShort[1] = *m_pszClump++; 00823 m_nOptionId = -1; 00824 m_pszOptionText = NULL; 00825 m_pszOptionArg = NULL; 00826 m_nLastError = SO_SUCCESS; 00827 00828 // lookup this option, ensure that we are using exact matching 00829 int nSavedFlags = m_nFlags; 00830 m_nFlags = SO_O_EXACT; 00831 int nTableIdx = LookupOption(m_szShort); 00832 m_nFlags = nSavedFlags; 00833 00834 // unknown option 00835 if (nTableIdx < 0) { 00836 m_nLastError = (ESOError) nTableIdx; // error code 00837 return false; 00838 } 00839 00840 // valid option 00841 m_pszOptionText = m_rgOptions[nTableIdx].pszArg; 00842 ESOArgType nArgType = m_rgOptions[nTableIdx].nArgType; 00843 if (nArgType == SO_NONE) { 00844 m_nOptionId = m_rgOptions[nTableIdx].nId; 00845 return true; 00846 } 00847 00848 if (nArgType == SO_REQ_CMB && *m_pszClump) { 00849 m_nOptionId = m_rgOptions[nTableIdx].nId; 00850 m_pszOptionArg = m_pszClump; 00851 while (*m_pszClump) ++m_pszClump; // must point to an empty string 00852 return true; 00853 } 00854 00855 // invalid option as it requires an argument 00856 m_nLastError = SO_ARG_MISSING; 00857 return true; 00858 } 00859 00860 // Shuffle arguments to the end of the argv array. 00861 // 00862 // For example: 00863 // argv[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8" }; 00864 // 00865 // ShuffleArg(1, 1) = { "0", "2", "3", "4", "5", "6", "7", "8", "1" }; 00866 // ShuffleArg(5, 2) = { "0", "1", "2", "3", "4", "7", "8", "5", "6" }; 00867 // ShuffleArg(2, 4) = { "0", "1", "6", "7", "8", "2", "3", "4", "5" }; 00868 template<class SOCHAR> 00869 void 00870 CSimpleOptTempl<SOCHAR>::ShuffleArg( 00871 int a_nStartIdx, 00872 int a_nCount 00873 ) 00874 { 00875 SOCHAR * staticBuf[SO_STATICBUF]; 00876 SOCHAR ** buf = m_rgShuffleBuf ? m_rgShuffleBuf : staticBuf; 00877 int nTail = m_argc - a_nStartIdx - a_nCount; 00878 00879 // make a copy of the elements to be moved 00880 Copy(buf, m_argv + a_nStartIdx, a_nCount); 00881 00882 // move the tail down 00883 Copy(m_argv + a_nStartIdx, m_argv + a_nStartIdx + a_nCount, nTail); 00884 00885 // append the moved elements to the tail 00886 Copy(m_argv + a_nStartIdx + nTail, buf, a_nCount); 00887 00888 // update the index of the last unshuffled arg 00889 m_nLastArg -= a_nCount; 00890 } 00891 00892 // match on the long format strings. partial matches will be 00893 // accepted only if that feature is enabled. 00894 template<class SOCHAR> 00895 int 00896 CSimpleOptTempl<SOCHAR>::LookupOption( 00897 const SOCHAR * a_pszOption 00898 ) const 00899 { 00900 int nBestMatch = -1; // index of best match so far 00901 int nBestMatchLen = 0; // matching characters of best match 00902 int nLastMatchLen = 0; // matching characters of last best match 00903 00904 for (int n = 0; m_rgOptions[n].nId >= 0; ++n) { 00905 // the option table must use hyphens as the option character, 00906 // the slash character is converted to a hyphen for testing. 00907 SO_ASSERT(m_rgOptions[n].pszArg[0] != (SOCHAR)'/'); 00908 00909 int nMatchLen = CalcMatch(m_rgOptions[n].pszArg, a_pszOption); 00910 if (nMatchLen == -1) { 00911 return n; 00912 } 00913 if (nMatchLen > 0 && nMatchLen >= nBestMatchLen) { 00914 nLastMatchLen = nBestMatchLen; 00915 nBestMatchLen = nMatchLen; 00916 nBestMatch = n; 00917 } 00918 } 00919 00920 // only partial matches or no match gets to here, ensure that we 00921 // don't return a partial match unless it is a clear winner 00922 if (HasFlag(SO_O_EXACT) || nBestMatch == -1) { 00923 return SO_OPT_INVALID; 00924 } 00925 return (nBestMatchLen > nLastMatchLen) ? nBestMatch : SO_OPT_MULTIPLE; 00926 } 00927 00928 // calculate the number of characters that match (case-sensitive) 00929 // 0 = no match, > 0 == number of characters, -1 == perfect match 00930 template<class SOCHAR> 00931 int 00932 CSimpleOptTempl<SOCHAR>::CalcMatch( 00933 const SOCHAR * a_pszSource, 00934 const SOCHAR * a_pszTest 00935 ) const 00936 { 00937 if (!a_pszSource || !a_pszTest) { 00938 return 0; 00939 } 00940 00941 // determine the argument type 00942 int nArgType = SO_O_ICASE_LONG; 00943 if (a_pszSource[0] != '-') { 00944 nArgType = SO_O_ICASE_WORD; 00945 } 00946 else if (a_pszSource[1] != '-' && !a_pszSource[2]) { 00947 nArgType = SO_O_ICASE_SHORT; 00948 } 00949 00950 // match and skip leading hyphens 00951 while (*a_pszSource == (SOCHAR)'-' && *a_pszSource == *a_pszTest) { 00952 ++a_pszSource; 00953 ++a_pszTest; 00954 } 00955 if (*a_pszSource == (SOCHAR)'-' || *a_pszTest == (SOCHAR)'-') { 00956 return 0; 00957 } 00958 00959 // find matching number of characters in the strings 00960 int nLen = 0; 00961 while (*a_pszSource && IsEqual(*a_pszSource, *a_pszTest, nArgType)) { 00962 ++a_pszSource; 00963 ++a_pszTest; 00964 ++nLen; 00965 } 00966 00967 // if we have exhausted the source... 00968 if (!*a_pszSource) { 00969 // and the test strings, then it's a perfect match 00970 if (!*a_pszTest) { 00971 return -1; 00972 } 00973 00974 // otherwise the match failed as the test is longer than 00975 // the source. i.e. "--mant" will not match the option "--man". 00976 return 0; 00977 } 00978 00979 // if we haven't exhausted the test string then it is not a match 00980 // i.e. "--mantle" will not best-fit match to "--mandate" at all. 00981 if (*a_pszTest) { 00982 return 0; 00983 } 00984 00985 // partial match to the current length of the test string 00986 return nLen; 00987 } 00988 00989 template<class SOCHAR> 00990 bool 00991 CSimpleOptTempl<SOCHAR>::IsEqual( 00992 SOCHAR a_cLeft, 00993 SOCHAR a_cRight, 00994 int a_nArgType 00995 ) const 00996 { 00997 // if this matches then we are doing case-insensitive matching 00998 if (m_nFlags & a_nArgType) { 00999 if (a_cLeft >= 'A' && a_cLeft <= 'Z') a_cLeft += 'a' - 'A'; 01000 if (a_cRight >= 'A' && a_cRight <= 'Z') a_cRight += 'a' - 'A'; 01001 } 01002 return a_cLeft == a_cRight; 01003 } 01004 01005 // calculate the number of characters that match (case-sensitive) 01006 // 0 = no match, > 0 == number of characters, -1 == perfect match 01007 template<class SOCHAR> 01008 SOCHAR ** 01009 CSimpleOptTempl<SOCHAR>::MultiArg( 01010 int a_nCount 01011 ) 01012 { 01013 // ensure we have enough arguments 01014 if (m_nNextOption + a_nCount > m_nLastArg) { 01015 m_nLastError = SO_ARG_MISSING; 01016 return NULL; 01017 } 01018 01019 // our argument array 01020 SOCHAR ** rgpszArg = &m_argv[m_nNextOption]; 01021 01022 // Ensure that each of the following don't start with an switch character. 01023 // Only make this check if we are returning errors for unknown arguments. 01024 if (!HasFlag(SO_O_NOERR)) { 01025 for (int n = 0; n < a_nCount; ++n) { 01026 SOCHAR ch = PrepareArg(rgpszArg[n]); 01027 if (rgpszArg[n][0] == (SOCHAR)'-') { 01028 rgpszArg[n][0] = ch; 01029 m_nLastError = SO_ARG_INVALID_DATA; 01030 return NULL; 01031 } 01032 rgpszArg[n][0] = ch; 01033 } 01034 } 01035 01036 // all good 01037 m_nNextOption += a_nCount; 01038 return rgpszArg; 01039 } 01040 01041 01042 // --------------------------------------------------------------------------- 01043 // TYPE DEFINITIONS 01044 // --------------------------------------------------------------------------- 01045 01047 typedef CSimpleOptTempl<char> CSimpleOptA; 01048 01050 typedef CSimpleOptTempl<wchar_t> CSimpleOptW; 01051 01052 #if defined(_UNICODE) 01053 01054 # define CSimpleOpt CSimpleOptW 01055 #else 01056 01057 # define CSimpleOpt CSimpleOptA 01058 #endif 01059 01060 #endif // INCLUDED_SimpleOpt
1.7.3