X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/86a9c8e02f2a24d6b81009d5a6dd9ef1b6c3ed7e..d9a56bdeaf27254ad19694a0c0c277385f0613c0:/src/common/mimetype.cpp diff --git a/src/common/mimetype.cpp b/src/common/mimetype.cpp index c3cd168992..901d85ffb1 100644 --- a/src/common/mimetype.cpp +++ b/src/common/mimetype.cpp @@ -124,8 +124,10 @@ public: wxFileType *GetFileTypeFromMimeType(const wxString& mimeType); // this are NOPs under Windows - void ReadMailcap(const wxString& filename) { } - void ReadMimeTypes(const wxString& filename) { } + bool ReadMailcap(const wxString& filename, bool fallback = TRUE) + { return TRUE; } + bool ReadMimeTypes(const wxString& filename) + { return TRUE; } }; #else // Unix @@ -220,9 +222,27 @@ public: // operations // prepend this element to the list void Prepend(MailCapEntry *next) { m_next = next; } - // append to the list + // insert into the list at given position + void Insert(MailCapEntry *next, size_t pos) + { + // FIXME slooow... + MailCapEntry *cur; + size_t n = 0; + for ( cur = next; cur != NULL; cur = cur->m_next, n++ ) { + if ( n == pos ) + break; + } + + wxASSERT_MSG( n == pos, _T("invalid position in MailCapEntry::Insert") ); + + m_next = cur->m_next; + cur->m_next = this; + } + // append this element to the list void Append(MailCapEntry *next) { + wxCHECK_RET( next != NULL, _T("Append()ing to what?") ); + // FIXME slooow... MailCapEntry *cur; for ( cur = next; cur->m_next != NULL; cur = cur->m_next ) @@ -230,9 +250,7 @@ public: cur->m_next = this; - // we initialize it in the ctor and there is no reason to both Prepend() - // and Append() one and the same entry - wxASSERT( m_next == NULL ); + wxASSERT_MSG( !m_next, _T("Append()ing element already in the list?") ); } private: @@ -252,15 +270,15 @@ friend class wxFileTypeImpl; // give it access to m_aXXX variables public: // ctor loads all info into memory for quicker access later on - // @@ it would be nice to load them all, but parse on demand only... + // TODO it would be nice to load them all, but parse on demand only... wxMimeTypesManagerImpl(); // implement containing class functions wxFileType *GetFileTypeFromExtension(const wxString& ext); wxFileType *GetFileTypeFromMimeType(const wxString& mimeType); - void ReadMailcap(const wxString& filename); - void ReadMimeTypes(const wxString& filename); + bool ReadMailcap(const wxString& filename, bool fallback = FALSE); + bool ReadMimeTypes(const wxString& filename); // accessors // get the string containing space separated extensions for the given @@ -286,7 +304,7 @@ public: bool GetMimeType(wxString *mimeType) const { *mimeType = m_manager->m_aTypes[m_index]; return TRUE; } bool GetIcon(wxIcon * WXUNUSED(icon)) const - { return FALSE; } // @@ maybe with Gnome/KDE integration... + { return FALSE; } // TODO maybe with Gnome/KDE integration... bool GetDescription(wxString *desc) const { *desc = m_manager->m_aDescriptions[m_index]; return TRUE; } @@ -331,57 +349,57 @@ wxString wxFileType::ExpandCommand(const wxString& command, bool hasFilename = FALSE; wxString str; - for ( const char *pc = command.c_str(); *pc != '\0'; pc++ ) { - if ( *pc == '%' ) { + for ( const wxChar *pc = command.c_str(); *pc != _T('\0'); pc++ ) { + if ( *pc == _T('%') ) { switch ( *++pc ) { - case 's': + case _T('s'): // '%s' expands into file name (quoted because it might // contain spaces) - except if there are already quotes // there because otherwise some programs may get confused // by double double quotes #if 0 - if ( *(pc - 2) == '"' ) + if ( *(pc - 2) == _T('"') ) str << params.GetFileName(); else - str << '"' << params.GetFileName() << '"'; + str << _T('"') << params.GetFileName() << _T('"'); #endif str << params.GetFileName(); hasFilename = TRUE; break; - case 't': + case _T('t'): // '%t' expands into MIME type (quote it too just to be // consistent) - str << '\'' << params.GetMimeType() << '\''; + str << _T('\'') << params.GetMimeType() << _T('\''); break; - case '{': + case _T('{'): { - const char *pEnd = strchr(pc, '}'); + const wxChar *pEnd = wxStrchr(pc, _T('}')); if ( pEnd == NULL ) { wxString mimetype; wxLogWarning(_("Unmatched '{' in an entry for " "mime type %s."), params.GetMimeType().c_str()); - str << "%{"; + str << _T("%{"); } else { wxString param(pc + 1, pEnd - pc - 1); - str << '\'' << params.GetParamValue(param) << '\''; + str << _T('\'') << params.GetParamValue(param) << _T('\''); pc = pEnd; } } break; - case 'n': - case 'F': + case _T('n'): + case _T('F'): // TODO %n is the number of parts, %F is an array containing // the names of temp files these parts were written to // and their mime types. break; default: - wxLogDebug("Unknown field %%%c in command '%s'.", + wxLogDebug(_T("Unknown field %%%c in command '%s'."), *pc, command.c_str()); str << *pc; } @@ -394,7 +412,7 @@ wxString wxFileType::ExpandCommand(const wxString& command, // metamail(1) man page states that if the mailcap entry doesn't have '%s' // the program will accept the data on stdin: so give it to it! if ( !hasFilename && !str.IsEmpty() ) { - str << " < '" << params.GetFileName() << '\''; + str << _T(" < '") << params.GetFileName() << _T('\''); } return str; @@ -451,16 +469,16 @@ wxFileType::GetPrintCommand(wxString *printCmd, bool wxMimeTypesManager::IsOfType(const wxString& mimeType, const wxString& wildcard) { - wxASSERT_MSG( mimeType.Find('*') == wxNOT_FOUND, - "first MIME type can't contain wildcards" ); + wxASSERT_MSG( mimeType.Find(_T('*')) == wxNOT_FOUND, + _T("first MIME type can't contain wildcards") ); // all comparaisons are case insensitive (2nd arg of IsSameAs() is FALSE) - if ( wildcard.BeforeFirst('/').IsSameAs(mimeType.BeforeFirst('/'), FALSE) ) + if ( wildcard.BeforeFirst(_T('/')).IsSameAs(mimeType.BeforeFirst(_T('/')), FALSE) ) { - wxString strSubtype = wildcard.AfterFirst('/'); + wxString strSubtype = wildcard.AfterFirst(_T('/')); - if ( strSubtype == '*' || - strSubtype.IsSameAs(mimeType.AfterFirst('/'), FALSE) ) + if ( strSubtype == _T('*') || + strSubtype.IsSameAs(mimeType.AfterFirst(_T('/')), FALSE) ) { // matches (either exactly or it's a wildcard) return TRUE; @@ -492,41 +510,51 @@ wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType) return m_impl->GetFileTypeFromMimeType(mimeType); } +bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback) +{ + return m_impl->ReadMailcap(filename, fallback); +} + +bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename) +{ + return m_impl->ReadMimeTypes(filename); +} + // ============================================================================ // real (OS specific) implementation // ============================================================================ #ifdef __WXMSW__ -bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const +bool wxFileTypeImpl::GetCommand(wxString *command, const wxChar *verb) const { // suppress possible error messages wxLogNull nolog; wxString strKey; - strKey << m_strFileType << "\\shell\\" << verb << "\\command"; + strKey << m_strFileType << _T("\\shell\\") << verb << _T("\\command"); wxRegKey key(wxRegKey::HKCR, strKey); if ( key.Open() ) { // it's the default value of the key - if ( key.QueryValue("", *command) ) { + if ( key.QueryValue(_T(""), *command) ) { // transform it from '%1' to '%s' style format string - // @@ we don't make any attempt to verify that the string is valid, - // i.e. doesn't contain %2, or second %1 or .... But we do make - // sure that we return a string with _exactly_ one '%s'! + // NB: we don't make any attempt to verify that the string is valid, + // i.e. doesn't contain %2, or second %1 or .... But we do make + // sure that we return a string with _exactly_ one '%s'! size_t len = command->Len(); for ( size_t n = 0; n < len; n++ ) { - if ( command->GetChar(n) == '%' && - (n + 1 < len) && command->GetChar(n + 1) == '1' ) { + if ( command->GetChar(n) == _T('%') && + (n + 1 < len) && command->GetChar(n + 1) == _T('1') ) { // replace it with '%s' - command->SetChar(n + 1, 's'); + command->SetChar(n + 1, _T('s')); return TRUE; } } // we didn't find any '%1'! - // @@@ hack: append the filename at the end, hope that it will do - *command << " %s"; + // HACK: append the filename at the end, hope that it will do + *command << _T(" %s"); return TRUE; } @@ -536,7 +564,7 @@ bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const return FALSE; } -// @@ this function is half implemented +// TODO this function is half implemented bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) { if ( m_ext.IsEmpty() ) { @@ -557,8 +585,8 @@ bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const { // suppress possible error messages wxLogNull nolog; - wxRegKey key(wxRegKey::HKCR, /*m_strFileType*/ "." + m_ext); - if ( key.Open() && key.QueryValue("Content Type", *mimeType) ) { + wxRegKey key(wxRegKey::HKCR, /*m_strFileType*/ _T(".") + m_ext); + if ( key.Open() && key.QueryValue(_T("Content Type"), *mimeType) ) { return TRUE; } else { @@ -569,7 +597,7 @@ bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const bool wxFileTypeImpl::GetIcon(wxIcon *icon) const { wxString strIconKey; - strIconKey << m_strFileType << "\\DefaultIcon"; + strIconKey << m_strFileType << _T("\\DefaultIcon"); // suppress possible error messages wxLogNull nolog; @@ -578,18 +606,18 @@ bool wxFileTypeImpl::GetIcon(wxIcon *icon) const if ( key.Open() ) { wxString strIcon; // it's the default value of the key - if ( key.QueryValue("", strIcon) ) { + if ( key.QueryValue(_T(""), strIcon) ) { // the format is the following: , // NB: icon index may be negative as well as positive and the full // path may contain the environment variables inside '%' - wxString strFullPath = strIcon.BeforeLast(','), - strIndex = strIcon.AfterLast(','); + wxString strFullPath = strIcon.BeforeLast(_T(',')), + strIndex = strIcon.AfterLast(_T(',')); // index may be omitted, in which case BeforeLast(',') is empty and // AfterLast(',') is the whole string if ( strFullPath.IsEmpty() ) { strFullPath = strIndex; - strIndex = "0"; + strIndex = _T("0"); } wxString strExpPath = wxExpandEnvVars(strFullPath); @@ -599,7 +627,7 @@ bool wxFileTypeImpl::GetIcon(wxIcon *icon) const switch ( (int)hIcon ) { case 0: // means no icons were found case 1: // means no such file or it wasn't a DLL/EXE/OCX/ICO/... - wxLogDebug("incorrect registry entry '%s': no such icon.", + wxLogDebug(_T("incorrect registry entry '%s': no such icon."), key.GetName().c_str()); break; @@ -622,7 +650,7 @@ bool wxFileTypeImpl::GetDescription(wxString *desc) const if ( key.Open() ) { // it's the default value of the key - if ( key.QueryValue("", *desc) ) { + if ( key.QueryValue(_T(""), *desc) ) { return TRUE; } } @@ -636,8 +664,8 @@ wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) { // add the leading point if necessary wxString str; - if ( ext[0u] != '.' ) { - str = '.'; + if ( ext[0u] != _T('.') ) { + str = _T('.'); } str << ext; @@ -648,7 +676,7 @@ wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) wxRegKey key(wxRegKey::HKCR, str); if ( key.Open() ) { // it's the default value of the key - if ( key.QueryValue("", strFileType) ) { + if ( key.QueryValue(_T(""), strFileType) ) { // create the new wxFileType object wxFileType *fileType = new wxFileType; fileType->m_impl->SetFileType(strFileType); @@ -666,9 +694,9 @@ wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) wxFileType * wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType) { - // @@@ I don't know of any official documentation which mentions this - // location, but as a matter of fact IE uses it, so why not we? - static const char *szMimeDbase = "MIME\\Database\\Content Type\\"; + // HACK I don't know of any official documentation which mentions this + // location, but as a matter of fact IE uses it, so why not we? + static const wxChar *szMimeDbase = _T("MIME\\Database\\Content Type\\"); wxString strKey = szMimeDbase; strKey << mimeType; @@ -679,7 +707,7 @@ wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType) wxString ext; wxRegKey key(wxRegKey::HKCR, strKey); if ( key.Open() ) { - if ( key.QueryValue("Extension", ext) ) { + if ( key.QueryValue(_T("Extension"), ext) ) { return GetFileTypeFromExtension(ext); } } @@ -696,17 +724,17 @@ wxFileTypeImpl::GetEntry(const wxFileType::MessageParameters& params) const wxString command; MailCapEntry *entry = m_manager->m_aEntries[m_index]; while ( entry != NULL ) { - // notice that an empty command would always succeed (@@ is it ok?) + // notice that an empty command would always succeed (it's ok) command = wxFileType::ExpandCommand(entry->GetTestCmd(), params); - if ( command.IsEmpty() || (system(command) == 0) ) { + if ( command.IsEmpty() || (wxSystem(command) == 0) ) { // ok, passed - wxLogTrace("Test '%s' for mime type '%s' succeeded.", + wxLogTrace(_T("Test '%s' for mime type '%s' succeeded."), command.c_str(), params.GetMimeType().c_str()); break; } else { - wxLogTrace("Test '%s' for mime type '%s' failed.", + wxLogTrace(_T("Test '%s' for mime type '%s' failed."), command.c_str(), params.GetMimeType().c_str()); } @@ -744,8 +772,8 @@ bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) // one extension in the space or comma delimitid list wxString strExt; - for ( const char *p = strExtensions; ; p++ ) { - if ( *p == ' ' || *p == ',' || *p == '\0' ) { + for ( const wxChar *p = strExtensions; ; p++ ) { + if ( *p == _T(' ') || *p == _T(',') || *p == _T('\0') ) { if ( !strExt.IsEmpty() ) { extensions.Add(strExt); strExt.Empty(); @@ -753,13 +781,13 @@ bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) //else: repeated spaces (shouldn't happen, but it's not that // important if it does happen) - if ( *p == '\0' ) + if ( *p == _T('\0') ) break; } - else if ( *p == '.' ) { + else if ( *p == _T('.') ) { // remove the dot from extension (but only if it's the first char) if ( !strExt.IsEmpty() ) { - strExt += '.'; + strExt += _T('.'); } //else: no, don't append it } @@ -776,40 +804,40 @@ wxMimeTypesManagerImpl::wxMimeTypesManagerImpl() { // directories where we look for mailcap and mime.types by default // (taken from metamail(1) sources) - static const char *aStandardLocations[] = + static const wxChar *aStandardLocations[] = { - "/etc", - "/usr/etc", - "/usr/local/etc", - "/etc/mail", - "/usr/public/lib" + _T("/etc"), + _T("/usr/etc"), + _T("/usr/local/etc"), + _T("/etc/mail"), + _T("/usr/public/lib") }; // first read the system wide file(s) for ( size_t n = 0; n < WXSIZEOF(aStandardLocations); n++ ) { wxString dir = aStandardLocations[n]; - wxString file = dir + "/mailcap"; + wxString file = dir + _T("/mailcap"); if ( wxFile::Exists(file) ) { ReadMailcap(file); } - file = dir + "/mime.types"; + file = dir + _T("/mime.types"); if ( wxFile::Exists(file) ) { ReadMimeTypes(file); } } - wxString strHome = getenv("HOME"); + wxString strHome = wxGetenv(_T("HOME")); // and now the users mailcap - wxString strUserMailcap = strHome + "/.mailcap"; + wxString strUserMailcap = strHome + _T("/.mailcap"); if ( wxFile::Exists(strUserMailcap) ) { ReadMailcap(strUserMailcap); } // read the users mime.types - wxString strUserMimeTypes = strHome + "/.mime.types"; + wxString strUserMimeTypes = strHome + _T("/.mime.types"); if ( wxFile::Exists(strUserMimeTypes) ) { ReadMimeTypes(strUserMimeTypes); } @@ -822,8 +850,8 @@ wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) for ( size_t n = 0; n < count; n++ ) { wxString extensions = m_aExtensions[n]; while ( !extensions.IsEmpty() ) { - wxString field = extensions.BeforeFirst(' '); - extensions = extensions.AfterFirst(' '); + wxString field = extensions.BeforeFirst(_T(' ')); + extensions = extensions.AfterFirst(_T(' ')); // consider extensions as not being case-sensitive if ( field.IsSameAs(ext, FALSE /* no case */) ) { @@ -853,12 +881,12 @@ wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType) // then try to find "text/*" as match for "text/plain" (for example) // NB: if mimeType doesn't contain '/' at all, BeforeFirst() will return // the whole string - ok. - wxString strCategory = mimetype.BeforeFirst('/'); + wxString strCategory = mimetype.BeforeFirst(_T('/')); size_t nCount = m_aTypes.Count(); for ( size_t n = 0; n < nCount; n++ ) { - if ( (m_aTypes[n].BeforeFirst('/') == strCategory ) && - m_aTypes[n].AfterFirst('/') == "*" ) { + if ( (m_aTypes[n].BeforeFirst(_T('/')) == strCategory ) && + m_aTypes[n].AfterFirst(_T('/')) == _T("*") ) { index = n; break; } @@ -877,43 +905,53 @@ wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType) } } -void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) +bool wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) { - wxLogTrace("--- Parsing mime.types file '%s' ---", strFileName.c_str()); + wxLogTrace(_T("--- Parsing mime.types file '%s' ---"), strFileName.c_str()); wxTextFile file(strFileName); if ( !file.Open() ) - return; + return FALSE; // the information we extract wxString strMimeType, strDesc, strExtensions; size_t nLineCount = file.GetLineCount(); + const wxChar *pc = NULL; for ( size_t nLine = 0; nLine < nLineCount; nLine++ ) { - // now we're at the start of the line - const char *pc = file[nLine].c_str(); + if ( pc == NULL ) { + // now we're at the start of the line + pc = file[nLine].c_str(); + } + else { + // we didn't finish with the previous line yet + nLine--; + } // skip whitespace - while ( isspace(*pc) ) + while ( wxIsspace(*pc) ) pc++; // comment? - if ( *pc == '#' ) + if ( *pc == _T('#') ) { + // skip the whole line + pc = NULL; continue; + } // detect file format - const char *pEqualSign = strchr(pc, '='); + const wxChar *pEqualSign = wxStrchr(pc, _T('=')); if ( pEqualSign == NULL ) { // brief format // ------------ // first field is mime type - for ( strMimeType.Empty(); !isspace(*pc) && *pc != '\0'; pc++ ) { + for ( strMimeType.Empty(); !wxIsspace(*pc) && *pc != _T('\0'); pc++ ) { strMimeType += *pc; } // skip whitespace - while ( isspace(*pc) ) + while ( wxIsspace(*pc) ) pc++; // take all the rest of the string @@ -930,13 +968,13 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) wxString strLHS(pc, pEqualSign - pc); // eat whitespace - for ( pc = pEqualSign + 1; isspace(*pc); pc++ ) + for ( pc = pEqualSign + 1; wxIsspace(*pc); pc++ ) ; - const char *pEnd; - if ( *pc == '"' ) { + const wxChar *pEnd; + if ( *pc == _T('"') ) { // the string is quoted and ends at the matching quote - pEnd = strchr(++pc, '"'); + pEnd = wxStrchr(++pc, _T('"')); if ( pEnd == NULL ) { wxLogWarning(_("Mime.types file %s, line %d: unterminated " "quoted string."), @@ -944,41 +982,39 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) } } else { - // unquoted stringends at the first space - for ( pEnd = pc; !isspace(*pEnd); pEnd++ ) + // unquoted string ends at the first space + for ( pEnd = pc; !wxIsspace(*pEnd); pEnd++ ) ; } // now we have the RHS (field value) wxString strRHS(pc, pEnd - pc); - // check that it's more or less what we're waiting for, i.e. that - // only '\' is left on the line - if ( *pEnd == '"' ) { + // check what follows this entry + if ( *pEnd == _T('"') ) { // skip this quote pEnd++; } - for ( pc = pEnd; isspace(*pc); pc++ ) + for ( pc = pEnd; wxIsspace(*pc); pc++ ) ; - // only '\\' may be left on the line normally - bool entryEnded = *pc == '\0'; - if ( !entryEnded && ((*pc != '\\') || (*++pc != '\0')) ) { - wxLogWarning(_("Mime.types file %s, line %d: extra characters " - "after the field value ignored."), - strFileName.c_str(), nLine + 1); + // if there is something left, it may be either a '\\' to continue + // the line or the next field of the same entry + bool entryEnded = *pc == _T('\0'), + nextFieldOnSameLine = FALSE; + if ( !entryEnded ) { + nextFieldOnSameLine = ((*pc != _T('\\')) || (pc[1] != _T('\0'))); } - // if there is a trailing backslash entryEnded = FALSE // now see what we got - if ( strLHS == "type" ) { + if ( strLHS == _T("type") ) { strMimeType = strRHS; } - else if ( strLHS == "desc" ) { + else if ( strLHS == _T("desc") ) { strDesc = strRHS; } - else if ( strLHS == "exts" ) { + else if ( strLHS == _T("exts") ) { strExtensions = strRHS; } else { @@ -987,8 +1023,13 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) } if ( !entryEnded ) { - // as we don't reset strMimeType, the next line in this entry + if ( !nextFieldOnSameLine ) + pc = NULL; + //else: don't reset it + + // as we don't reset strMimeType, the next field in this entry // will be interpreted correctly. + continue; } } @@ -996,10 +1037,10 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) // although it doesn't seem to be covered by RFCs, some programs // (notably Netscape) create their entries with several comma // separated extensions (RFC mention the spaces only) - strExtensions.Replace(",", " "); + strExtensions.Replace(_T(","), _T(" ")); // also deal with the leading dot - if ( !strExtensions.IsEmpty() && strExtensions[0] == '.' ) { + if ( !strExtensions.IsEmpty() && strExtensions[0] == _T('.') ) { strExtensions.erase(0, 1); } @@ -1018,36 +1059,47 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) } m_aExtensions[index] += strExtensions; } + + // finished with this line + pc = NULL; } // check our data integriry wxASSERT( m_aTypes.Count() == m_aEntries.Count() && m_aTypes.Count() == m_aExtensions.Count() && m_aTypes.Count() == m_aDescriptions.Count() ); + + return TRUE; } -void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) +bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName, + bool fallback) { - wxLogTrace("--- Parsing mailcap file '%s' ---", strFileName.c_str()); + wxLogTrace(_T("--- Parsing mailcap file '%s' ---"), strFileName.c_str()); wxTextFile file(strFileName); if ( !file.Open() ) - return; + return FALSE; - // see the comments near the end of function for the reason we need this + // see the comments near the end of function for the reason we need these + // variables (search for the next occurence of them) + // indices of MIME types (in m_aTypes) we already found in this file wxArrayInt aEntryIndices; + // aLastIndices[n] is the index of last element in + // m_aEntries[aEntryIndices[n]] from this file + wxArrayInt aLastIndices; size_t nLineCount = file.GetLineCount(); for ( size_t nLine = 0; nLine < nLineCount; nLine++ ) { // now we're at the start of the line - const char *pc = file[nLine].c_str(); + const wxChar *pc = file[nLine].c_str(); // skip whitespace - while ( isspace(*pc) ) + while ( wxIsspace(*pc) ) pc++; // comment or empty string? - if ( *pc == '#' || *pc == '\0' ) + if ( *pc == _T('#') || *pc == _T('\0') ) continue; // no, do parse @@ -1073,10 +1125,10 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) curField; // accumulator for ( bool cont = TRUE; cont; pc++ ) { switch ( *pc ) { - case '\\': + case _T('\\'): // interpret the next character literally (notice that // backslash can be used for line continuation) - if ( *++pc == '\0' ) { + if ( *++pc == _T('\0') ) { // fetch the next line. // pc currently points to nowhere, but after the next @@ -1090,12 +1142,12 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) } break; - case '\0': + case _T('\0'): cont = FALSE; // end of line reached, exit the loop // fall through - case ';': + case _T(';'): // store this field and start looking for the next one // trim whitespaces from both sides @@ -1104,9 +1156,9 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) switch ( currentToken ) { case Field_Type: strType = curField; - if ( strType.Find('/') == wxNOT_FOUND ) { + if ( strType.Find(_T('/')) == wxNOT_FOUND ) { // we interpret "type" as "type/*" - strType += "/*"; + strType += _T("/*"); } currentToken = Field_OpenCmd; @@ -1124,22 +1176,22 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) bool ok = TRUE; // is this something of the form foo=bar? - const char *pEq = strchr(curField, '='); + const wxChar *pEq = wxStrchr(curField, _T('=')); if ( pEq != NULL ) { - wxString lhs = curField.BeforeFirst('='), - rhs = curField.AfterFirst('='); + wxString lhs = curField.BeforeFirst(_T('=')), + rhs = curField.AfterFirst(_T('=')); lhs.Trim(TRUE); // from right rhs.Trim(FALSE); // from left - if ( lhs == "print" ) + if ( lhs == _T("print") ) strPrintCmd = rhs; - else if ( lhs == "test" ) + else if ( lhs == _T("test") ) strTest = rhs; - else if ( lhs == "description" ) { + else if ( lhs == _T("description") ) { // it might be quoted - if ( rhs[0u] == '"' && - rhs.Last() == '"' ) { + if ( rhs[0u] == _T('"') && + rhs.Last() == _T('"') ) { strDesc = wxString(rhs.c_str() + 1, rhs.Len() - 2); } @@ -1147,10 +1199,10 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) strDesc = rhs; } } - else if ( lhs == "compose" || - lhs == "composetyped" || - lhs == "notes" || - lhs == "edit" ) + else if ( lhs == _T("compose") || + lhs == _T("composetyped") || + lhs == _T("notes") || + lhs == _T("edit") ) ; // ignore else ok = FALSE; @@ -1161,11 +1213,11 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) // TODO support the flags: // 1. create an xterm for 'needsterminal' // 2. append "| $PAGER" for 'copiousoutput' - if ( curField == "needsterminal" ) + if ( curField == _T("needsterminal") ) needsterminal = TRUE; - else if ( curField == "copiousoutput" ) + else if ( curField == _T("copiousoutput") ) copiousoutput = TRUE; - else if ( curField == "textualnewlines" ) + else if ( curField == _T("textualnewlines") ) ; // ignore else ok = FALSE; @@ -1180,9 +1232,9 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) // programmer wxLogDebug ( - "Mailcap file %s, line %d: unknown " + _T("Mailcap file %s, line %d: unknown " "field '%s' for the MIME type " - "'%s' ignored.", + "'%s' ignored."), strFileName.c_str(), nLine + 1, curField.c_str(), @@ -1196,7 +1248,7 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) break; default: - wxFAIL_MSG("unknown field type in mailcap"); + wxFAIL_MSG(_T("unknown field type in mailcap")); } // next token starts immediately after ';' @@ -1226,30 +1278,55 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) m_aTypes.Add(strType); m_aEntries.Add(entry); - m_aExtensions.Add(""); + m_aExtensions.Add(_T("")); m_aDescriptions.Add(strDesc); } else { - // modify the existing entry: the entry in one and the same file - // are read in top-to-bottom order, i.e. the entries read first - // should be tried before the entries below. However, the files - // read later should override the settings in the files read - // before, thus we Append() the new entry to the list if it has - // already occured in _this_ file, but Prepend() it if it - // occured in some of the previous ones. - if ( aEntryIndices.Index(nIndex) == wxNOT_FOUND ) { - // first time in this file - aEntryIndices.Add(nIndex); - entry->Prepend(m_aEntries[nIndex]); - m_aEntries[nIndex] = entry; + // modify the existing entry: the entries in one and the same + // file are read in top-to-bottom order, i.e. the entries read + // first should be tried before the entries below. However, + // the files read later should override the settings in the + // files read before (except if fallback is TRUE), thus we + // Insert() the new entry to the list if it has already + // occured in _this_ file, but Prepend() it if it occured in + // some of the previous ones and Append() to it in the + // fallback case + + if ( fallback ) { + // 'fallback' parameter prevents the entries from this + // file from overriding the other ones - always append + MailCapEntry *entryOld = m_aEntries[nIndex]; + if ( entryOld ) + entry->Append(entryOld); + else + m_aEntries[nIndex] = entry; } else { - // not the first time in _this_ file - entry->Append(m_aEntries[nIndex]); + int entryIndex = aEntryIndices.Index(nIndex); + if ( entryIndex == wxNOT_FOUND ) { + // first time in this file + aEntryIndices.Add(nIndex); + aLastIndices.Add(0); + + entry->Prepend(m_aEntries[nIndex]); + m_aEntries[nIndex] = entry; + } + else { + // not the first time in _this_ file + size_t nEntryIndex = (size_t)entryIndex; + MailCapEntry *entryOld = m_aEntries[nIndex]; + if ( entryOld ) + entry->Insert(entryOld, aLastIndices[nEntryIndex]); + else + m_aEntries[nIndex] = entry; + + // the indices were shifted by 1 + aLastIndices[nEntryIndex]++; + } } if ( !strDesc.IsEmpty() ) { - // @@ replace the old one - what else can we do?? + // replace the old one - what else can we do?? m_aDescriptions[nIndex] = strDesc; } } @@ -1260,6 +1337,8 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) m_aTypes.Count() == m_aExtensions.Count() && m_aTypes.Count() == m_aDescriptions.Count() ); } + + return TRUE; } #endif // OS type