From cc385968c4b81d0cee98c164cb870a8759d927bc Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Tue, 23 Mar 1999 17:39:47 +0000
Subject: [PATCH] 1. ReadMailcap/MimeTypes returna bool error code 2.
 'fallback' flag added to ReadMailcap 3, subtle (and very rare) bug with
 mailcap entries order corrected

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1962 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/mimetype.tex |  18 ++++-
 include/wx/mimetype.h      |  12 +++-
 src/common/mimetype.cpp    | 135 +++++++++++++++++++++++++------------
 3 files changed, 117 insertions(+), 48 deletions(-)

diff --git a/docs/latex/wx/mimetype.tex b/docs/latex/wx/mimetype.tex
index 94c7191bb7..bd7275d5b9 100644
--- a/docs/latex/wx/mimetype.tex
+++ b/docs/latex/wx/mimetype.tex
@@ -15,7 +15,7 @@ initialization is needed.
 (system-wide) and .mailcap and .mime.types in the current user's home directory:
 all of these files are searched for and loaded if found by default. However,
 additional functions 
-\helpref{wxMimeTypesManager::ReadMailcap}{wxmimetypesmanagerreadmailcap} and
+\helpref{wxMimeTypesManager::ReadMailcap}{wxmimetypesmanagerreadmailcap} and 
 \helpref{wxMimeTypesManager::ReadMimeTypes}{wxmimetypesmanagerreadmimetypes} are
 provided to load additional files.
 
@@ -123,17 +123,29 @@ necessary to convert the strings to the same case before calling it.
 
 \membersection{wxMimeTypesManager::ReadMailcap}\label{wxmimetypesmanagerreadmailcap}
 
-\func{void}{ReadMailcap}{\param{const wxString\&}{ filename}}
+\func{bool}{ReadMailcap}{\param{const wxString\&}{ filename}, \param{bool}{ fallback = FALSE}}
 
 Load additional file containing information about MIME types and associated
 information in mailcap format. See metamail(1) and mailcap(5) for more
 information.
 
+{\it fallback} parameter may be used to load additional mailcap files without
+overriding the settings found in the standard files: normally, entries from
+files loaded with ReadMailcap will override the entries from files loaded
+previously (and the standard ones are loaded in the very beginning), but this
+will not happen if this parameter is set to TRUE (default is FALSE).
+
+The return value is TRUE if there were no errors in the file or FALSE
+otherwise.
+
 \membersection{wxMimeTypesManager::ReadMimeTypes}\label{wxmimetypesmanagerreadmimetypes}
 
-\func{void}{ReadMimeTypes}{\param{const wxString\&}{ filename}}
+\func{bool}{ReadMimeTypes}{\param{const wxString\&}{ filename}}
 
 Load additional file containing information about MIME types and associated
 information in mime.types file format. See metamail(1) and mailcap(5) for more
 information.
 
+The return value is TRUE if there were no errors in the file or FALSE
+otherwise.
+
diff --git a/include/wx/mimetype.h b/include/wx/mimetype.h
index 18680f3afc..d30eb3c70d 100644
--- a/include/wx/mimetype.h
+++ b/include/wx/mimetype.h
@@ -131,12 +131,18 @@ public:
         // get file type from MIME type (in format <category>/<format>)
     wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
 
-    // other operations
+    // other operations: return TRUE if there were no errors or FALSE if there
+    // were some unreckognized entries (the good entries are always read anyhow)
         // read in additional file (the standard ones are read automatically)
         // in mailcap format (see mimetype.cpp for description)
-    void ReadMailcap(const wxString& filename);
+        //
+        // 'fallback' parameter may be set to TRUE to avoid overriding the
+        // settings from other, previously parsed, files by this one: normally,
+        // the files read most recently would override the older files, but with
+        // fallback == TRUE this won't happen
+    bool ReadMailcap(const wxString& filename, bool fallback = FALSE);
         // read in additional file in mime.types format
-    void ReadMimeTypes(const wxString& filename);
+    bool ReadMimeTypes(const wxString& filename);
 
     // dtor (not virtual, shouldn't be derived from)
     ~wxMimeTypesManager();
diff --git a/src/common/mimetype.cpp b/src/common/mimetype.cpp
index cc3415d7e1..ce234a392f 100644
--- a/src/common/mimetype.cpp
+++ b/src/common/mimetype.cpp
@@ -124,8 +124,8 @@ 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) { }
+    bool ReadMimeTypes(const wxString& filename) { }
 };
 
 #else  // Unix
@@ -220,9 +220,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, "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, "Append()ing to what?" );
+
         // FIXME slooow...
         MailCapEntry *cur;
         for ( cur = next; cur->m_next != NULL; cur = cur->m_next )
@@ -230,9 +248,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, "Append()ing element already in the list?" );
     }
 
 private:
@@ -252,15 +268,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 +302,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; }
 
@@ -492,14 +508,14 @@ wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType)
     return m_impl->GetFileTypeFromMimeType(mimeType);
 }
 
-void wxMimeTypesManager::ReadMailcap(const wxString& filename)
+bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback)
 {
-    m_impl->ReadMailcap(filename);
+    return m_impl->ReadMailcap(filename, fallback);
 }
 
-void wxMimeTypesManager::ReadMimeTypes(const wxString& filename)
+bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename)
 {
-    m_impl->ReadMimeTypes(filename);
+    return m_impl->ReadMimeTypes(filename);
 }
 
 // ============================================================================
@@ -520,9 +536,9 @@ bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const
         // it's the default value of the key
         if ( key.QueryValue("", *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) == '%' &&
@@ -535,7 +551,7 @@ bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const
             }
 
             // we didn't find any '%1'!
-            // @@@ hack: append the filename at the end, hope that it will do
+            // HACK: append the filename at the end, hope that it will do
             *command << " %s";
 
             return TRUE;
@@ -546,7 +562,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() ) {
@@ -676,8 +692,8 @@ 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?
+    // 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 char *szMimeDbase = "MIME\\Database\\Content Type\\";
 
     wxString strKey = szMimeDbase;
@@ -706,7 +722,7 @@ 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) ) {
@@ -887,13 +903,13 @@ 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());
 
     wxTextFile file(strFileName);
     if ( !file.Open() )
-        return;
+        return FALSE;
 
     // the information we extract
     wxString strMimeType, strDesc, strExtensions;
@@ -1050,18 +1066,26 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName)
     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());
 
     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++ ) {
@@ -1256,26 +1280,51 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName)
                 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;
                 }
             }
@@ -1286,6 +1335,8 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName)
                   m_aTypes.Count() == m_aExtensions.Count() &&
                   m_aTypes.Count() == m_aDescriptions.Count() );
     }
+
+    return TRUE;
 }
 
 #endif // OS type
-- 
2.50.0

