#ifndef __MacOsVersion_H__ #define __MacOsVersion_H__ #include "../cpp_foundation/XStringArray.h" #include "Utils.h" const XString8 getSuffixForMacOsVersion(int LoaderType); class AbstractMacOsVersion { public: static const int nbMaxElement = 5; // if you modify, update the initializer/ XString8 lastError = ""_XS8; // to silence warning effc++ protected: int versionsNumber[nbMaxElement] = { -1, -1, -1, -1, -1 }; public: AbstractMacOsVersion() {}; AbstractMacOsVersion(int _versionsNumber[nbMaxElement]) { size_t idx; for ( idx=0 ; idx < nbMaxElement && _versionsNumber[idx] != -1 ; idx++ ) versionsNumber[idx] = _versionsNumber[idx]; for ( ; idx < nbMaxElement ; idx++ ) if ( _versionsNumber[idx] != -1 ) panic("MacOsVersion::ctor _versionsNumber[%zu] != -1", idx); }; int nbElement() const { int idx; for ( idx=0 ; idx < nbMaxElement && versionsNumber[idx] != -1 ; idx++ ) {}; return idx; } int lastElement() const { int idx; for ( idx=1 ; idx < nbMaxElement && versionsNumber[idx] != -1 ; idx++ ) {}; return versionsNumber[idx-1]; } void setEmpty() { lastError.setEmpty(); for ( size_t idx=0 ; idx < nbMaxElement ; idx++ ) versionsNumber[idx] = -1; } bool isEmpty() const { return versionsNumber[0] == -1; } bool notEmpty() const { return !isEmpty(); } template int elementAt(IntegralType i) const { if (i < 0) { panic("MacOsVersion::elementAt : i < 0. System halted\n"); } if ( (unsigned_type(IntegralType))i >= nbMaxElement ) { panic("MacOsVersion::elementAt : i >= nbMaxElement. System halted\n"); } return versionsNumber[(unsigned_type(IntegralType))i]; } template XString8 asString(IntegralType i) const { if (i <= 0) { panic("MacOsVersion::asString : i < 0. System halted\n"); } if ( (unsigned_type(IntegralType))i > nbMaxElement ) { panic("MacOsVersion::asString : i > nbMaxElement. System halted\n"); } if ( versionsNumber[0] == -1 ) return NullXString8; XString8 returnValue; if ( versionsNumber[0] == -2 ) { returnValue.S8Printf("x"); }else{ returnValue.S8Printf("%d", versionsNumber[0]); } for ( size_t idx=1 ; idx < (unsigned_type(IntegralType))i && versionsNumber[idx] != -1 ; idx++ ) { if ( versionsNumber[idx] == -2 ) { returnValue.S8Catf(".x"); }else{ returnValue.S8Catf(".%d", versionsNumber[idx]); } } return returnValue; } XString8 asString() const { return asString(nbMaxElement); } }; class MacOsVersionPattern : public AbstractMacOsVersion { public: MacOsVersionPattern() : AbstractMacOsVersion() {}; MacOsVersionPattern(int _versionsNumber[nbMaxElement]) : AbstractMacOsVersion(_versionsNumber) {}; template MacOsVersionPattern(const XStringClass& versionAsString) { this->takeValueFrom(versionAsString); } template // MacOsVersionPattern& operator = ( const XStringClass& versionAsString) MacOsVersionPattern& takeValueFrom(const XStringClass& versionAsString) { setEmpty(); // we call our own setEmpty although we already are empty (this is a ctor). That's because in case of nbMaxElement is increased and there is a missing value in versionsNumber array initializer. size_t currentElementIdx = 0; int* currentElementPtr = &versionsNumber[currentElementIdx]; size_t idx; for ( idx=0 ; idx < versionAsString.length(); idx++ ) { if ( *currentElementPtr == -2 ) { if ( versionAsString[idx] == 'x' || versionAsString[idx] == 'X' ) { // ok. we allow multiple following x. }else if ( versionAsString[idx] == '.' ) { currentElementIdx += 1; if ( currentElementIdx >= nbMaxElement ) { setEmpty(); lastError.S8Printf("Version number cannot be more than %d numbers.", nbMaxElement); return *this; } currentElementPtr = &versionsNumber[currentElementIdx]; }else{ setEmpty(); lastError.S8Printf("Version number wildcard ('x') must be followed by a dot."); return *this; } }else if ( *currentElementPtr == -1 ) { if ( versionAsString[idx] == 'x' || versionAsString[idx] == 'X' ) { *currentElementPtr = -2; }else if ( IS_DIGIT(versionAsString[idx]) ) { *currentElementPtr = ((int)versionAsString[idx]) - '0'; // safe cast because versionAsString[idx] is a digit. }else { setEmpty(); lastError.S8Printf("Version number must be numbers separated with one dot."); return *this; } }else{ if ( versionAsString[idx] == '.' ) { currentElementIdx += 1; if ( currentElementIdx >= nbMaxElement ) { setEmpty(); lastError.S8Printf("Version number cannot be more than %d numbers.", nbMaxElement); return *this; } currentElementPtr = &versionsNumber[currentElementIdx]; }else if ( IS_DIGIT(versionAsString[idx]) ) { *currentElementPtr = *currentElementPtr * 10 + ((int)versionAsString[idx]) - '0'; // safe cast because versionAsString[idx] is a digit. }else{ setEmpty(); lastError.S8Printf("Version number must be numbers separated with one dot."); return *this; } } } return *this; } template MacOsVersionPattern& operator = ( const CharType* p) { return *this = LString8(p); } MacOsVersionPattern(const MacOsVersionPattern& other) { lastError = other.lastError; memcpy(versionsNumber, other.versionsNumber, sizeof(versionsNumber)); } MacOsVersionPattern& operator = ( const MacOsVersionPattern& other) { lastError = other.lastError; memcpy(versionsNumber, other.versionsNumber, sizeof(versionsNumber)); return *this; } }; class MacOsVersion : public AbstractMacOsVersion { public: MacOsVersion() : AbstractMacOsVersion() {}; MacOsVersion(int _versionsNumber[nbMaxElement]) : AbstractMacOsVersion(_versionsNumber) {}; template MacOsVersion(const XStringClass& versionAsString) { this->takeValueFrom(versionAsString); } template // MacOsVersion& operator = ( const XStringClass& versionAsString) MacOsVersion& takeValueFrom(const XStringClass& versionAsString) { setEmpty(); // we call our own setEmpty although we already are empty (this is a ctor). That's because in case of nbMaxElement is increased and there is a missing value in versionsNumber array initializer. size_t currentElementIdx = 0; int* currentElementPtr = &versionsNumber[currentElementIdx]; for ( size_t idx=0 ; idx < versionAsString.length(); idx++ ) { if ( *currentElementPtr == -1 ) { if ( !IS_DIGIT(versionAsString[idx]) ) { setEmpty(); lastError.S8Printf("Version number must be numbers separated with one dot."); return *this; } *currentElementPtr = ((int)versionAsString[idx]) - '0'; // safe cast because versionAsString[idx] is a digit. }else{ if ( versionAsString[idx] == '.' ) { currentElementIdx += 1; if ( currentElementIdx >= nbMaxElement ) { setEmpty(); lastError.S8Printf("Version number cannot be more than %d numbers.", nbMaxElement); return *this; } currentElementPtr = &versionsNumber[currentElementIdx]; }else if ( IS_DIGIT(versionAsString[idx]) ) { *currentElementPtr = *currentElementPtr * 10 + ((int)versionAsString[idx]) - '0'; // safe cast because versionAsString[idx] is a digit. }else{ setEmpty(); lastError.S8Printf("Version number must be numbers separated with one dot."); return *this; } } } return *this; } template MacOsVersion& operator = ( const CharType* p) { return *this = LString8(p); } MacOsVersion(const MacOsVersion& other) { lastError = other.lastError; memcpy(versionsNumber, other.versionsNumber, sizeof(versionsNumber)); } MacOsVersion& operator = ( const MacOsVersion& other) { lastError = other.lastError; memcpy(versionsNumber, other.versionsNumber, sizeof(versionsNumber)); return *this; } bool match(const MacOsVersionPattern& pattern) const { // int nbMax = nbElemen() <= pattern.nbMaxElement ? nbMaxElement : pattern.nbMaxElement; int idx; for ( idx=0 ; idx < nbMaxElement && versionsNumber[idx] != -1 && pattern.elementAt(idx) != -1 ; idx++ ) { if ( pattern.elementAt(idx) == -2 ) continue; if ( versionsNumber[idx] == pattern.elementAt(idx) ) continue; return false; } if ( idx >= nbMaxElement ) return true; // the whole pattern was macthed => ok. if ( versionsNumber[idx] == -1 ) { // self is shorter than pattern if ( pattern.elementAt(idx) == -1 ) return true; // pattern and self are the same length, and they matched. if ( pattern.nbElement() == idx+1 && pattern.lastElement() == -2 ) return true; }else{ // pattern is short then self if ( pattern.lastElement() == -2 ) return true; } return false; } bool operator ==(const MacOsVersion &other) const { for ( size_t idx=0 ; idx < nbMaxElement ; idx++ ) { if ( versionsNumber[idx] != other.elementAt(idx) ) return false; } return true; }; bool operator !=(const MacOsVersion &other) const { return ! ( *this == other); } bool operator <(const MacOsVersion &other) const { for ( size_t idx=0 ; idx < nbMaxElement ; idx++ ) { if ( versionsNumber[idx] < other.elementAt(idx) ) return true; if ( versionsNumber[idx] > other.elementAt(idx) ) return false; } return false; // here, means it's equal }; bool operator >=(const MacOsVersion &other) const { return ! ( *this < other); } bool operator >(const MacOsVersion &other) const { for ( size_t idx=0 ; idx < nbMaxElement ; idx++ ) { if ( versionsNumber[idx] > other.elementAt(idx) ) return true; if ( versionsNumber[idx] < other.elementAt(idx) ) return false; } return false; // here, means it's equal }; bool operator <=(const MacOsVersion &other) const { return ! ( *this > other); } }; extern MacOsVersion nullMacOsVersion; #endif // __MacOsVersion_H__