/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
- #pragma implementation "mimetype.h"
+#pragma implementation "mimetype.h"
#endif
-// ============================================================================
-// declarations
-// ============================================================================
-
-// ----------------------------------------------------------------------------
-// headers
-// ----------------------------------------------------------------------------
-
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
- #pragma hdrstop
+ #pragma hdrstop
#endif
-// wxWindows
#ifndef WX_PRECOMP
- #include "wx/string.h"
- #include "wx/icon.h"
+ #include "wx/defs.h"
+#endif
+
+#if (wxUSE_FILE && wxUSE_TEXTFILE) || defined(__WXMSW__)
+
+#ifndef WX_PRECOMP
+ #include "wx/string.h"
+ #include "wx/icon.h"
#endif //WX_PRECOMP
+// Doesn't compile in WIN16 mode
+#ifndef __WIN16__
+
#include "wx/log.h"
+#include "wx/file.h"
#include "wx/intl.h"
#include "wx/dynarray.h"
#include "wx/confbase.h"
bool GetDescription(wxString *desc) const;
bool GetOpenCommand(wxString *openCmd,
const wxFileType::MessageParameters&) const
- { return GetCommand(openCmd, "open"); }
+ { return GetCommand(openCmd, _T("open")); }
bool GetPrintCommand(wxString *printCmd,
const wxFileType::MessageParameters&) const
- { return GetCommand(printCmd, "print"); }
+ { return GetCommand(printCmd, _T("print")); }
private:
// helper function
- bool GetCommand(wxString *command, const char *verb) const;
+ bool GetCommand(wxString *command, const wxChar *verb) const;
wxString m_strFileType, m_ext;
};
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
// * compose and composetyped fields are used to determine the program to be
// called to create a new message pert in the specified format (unused).
//
-// Parameter/filename xpansion:
+// Parameter/filename xpansion:
// * %s is replaced with the (full) file name
// * %t is replaced with MIME type/subtype of the entry
// * for multipart type only %n is replaced with the nnumber of parts and %F is
// comments. Each record has one of two following forms:
// a) for "brief" format:
// <mime type> <space separated list of extensions>
-// b) for "expanded" format:
+// b) for "expanded" format:
// type=<mime type> \ desc="<description>" \ exts="ext"
//
// We try to autodetect the format of mime.types: if a non-comment line starts
// 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 )
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:
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
bool GetExtensions(wxArrayString& extensions);
bool GetMimeType(wxString *mimeType) const
{ *mimeType = m_manager->m_aTypes[m_index]; return TRUE; }
- bool GetIcon(wxIcon *icon) const
- { return FALSE; } // @@ maybe with Gnome/KDE integration...
+ bool GetIcon(wxIcon * WXUNUSED(icon)) const
+ { return FALSE; } // TODO maybe with Gnome/KDE integration...
bool GetDescription(wxString *desc) const
{ *desc = m_manager->m_aDescriptions[m_index]; return TRUE; }
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
+ // 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;
}
// 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;
// wxMimeTypesManager
// ----------------------------------------------------------------------------
+bool wxMimeTypesManager::IsOfType(const wxString& mimeType,
+ const wxString& wildcard)
+{
+ 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(_T('/')).IsSameAs(mimeType.BeforeFirst(_T('/')), FALSE) )
+ {
+ wxString strSubtype = wildcard.AfterFirst(_T('/'));
+
+ if ( strSubtype == _T("*") ||
+ strSubtype.IsSameAs(mimeType.AfterFirst(_T('/')), FALSE) )
+ {
+ // matches (either exactly or it's a wildcard)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
wxMimeTypesManager::wxMimeTypesManager()
{
m_impl = new wxMimeTypesManagerImpl;
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;
}
return FALSE;
}
-// @@ this function is half implemented
+// TODO this function is half implemented
bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
{
if ( m_ext.IsEmpty() ) {
{
// suppress possible error messages
wxLogNull nolog;
- wxRegKey key(wxRegKey::HKCR, m_strFileType);
- 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 {
bool wxFileTypeImpl::GetIcon(wxIcon *icon) const
{
wxString strIconKey;
- strIconKey << m_strFileType << "\\DefaultIcon";
+ strIconKey << m_strFileType << _T("\\DefaultIcon");
// suppress possible error messages
wxLogNull nolog;
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: <full path to file>, <icon index>
// NB: icon index may be negative as well as positive and the full
// path may contain the environment variables inside '%'
- wxString strFullPath = strIcon.Before(','),
- strIndex = strIcon.Right(',');
+ wxString strFullPath = strIcon.BeforeLast(_T(',')),
+ strIndex = strIcon.AfterLast(_T(','));
- // index may be omitted, in which case Before(',') is empty and
- // Right(',') is the whole string
+ // 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);
- int nIndex = atoi(strIndex);
+ int nIndex = wxAtoi(strIndex);
HICON hIcon = ExtractIcon(GetModuleHandle(NULL), strExpPath, nIndex);
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;
if ( key.Open() ) {
// it's the default value of the key
- if ( key.QueryValue("", *desc) ) {
+ if ( key.QueryValue(_T(""), *desc) ) {
return TRUE;
}
}
{
// add the leading point if necessary
wxString str;
- if ( ext[0u] != '.' ) {
- str = '.';
+ if ( ext[0u] != _T('.') ) {
+ str = _T('.');
}
str << 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);
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;
wxString ext;
wxRegKey key(wxRegKey::HKCR, strKey);
if ( key.Open() ) {
- if ( key.QueryValue("Extension", ext) ) {
+ if ( key.QueryValue(_T("Extension"), ext) ) {
return GetFileTypeFromExtension(ext);
}
}
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());
}
// 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();
//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
}
{
// 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);
}
wxFileType *
wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
{
- wxFAIL_MSG("not implemented (must parse mime.types)");
+ size_t count = m_aExtensions.GetCount();
+ for ( size_t n = 0; n < count; n++ ) {
+ wxString extensions = m_aExtensions[n];
+ while ( !extensions.IsEmpty() ) {
+ wxString field = extensions.BeforeFirst(_T(' '));
+ extensions = extensions.AfterFirst(_T(' '));
+
+ // consider extensions as not being case-sensitive
+ if ( field.IsSameAs(ext, FALSE /* no case */) ) {
+ // found
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->Init(this, n);
+
+ return fileType;
+ }
+ }
+ }
+ // not found
return NULL;
}
// first look for an exact match
int index = m_aTypes.Index(mimetype);
- if ( index == NOT_FOUND ) {
+ if ( index == wxNOT_FOUND ) {
// then try to find "text/*" as match for "text/plain" (for example)
- // NB: if mimeType doesn't contain '/' at all, Left() will return the
- // whole string - ok.
- wxString strCategory = mimetype.Left('/');
+ // NB: if mimeType doesn't contain '/' at all, BeforeFirst() will return
+ // the whole string - ok.
+ wxString strCategory = mimetype.BeforeFirst(_T('/'));
size_t nCount = m_aTypes.Count();
for ( size_t n = 0; n < nCount; n++ ) {
- if ( (m_aTypes[n].Before('/') == strCategory ) &&
- m_aTypes[n].Right('/') == "*" ) {
+ if ( (m_aTypes[n].BeforeFirst(_T('/')) == strCategory ) &&
+ m_aTypes[n].AfterFirst(_T('/')) == _T("*") ) {
index = n;
break;
}
}
}
- if ( index != NOT_FOUND ) {
+ if ( index != wxNOT_FOUND ) {
wxFileType *fileType = new wxFileType;
fileType->m_impl->Init(this, index);
}
}
-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
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."),
}
}
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 {
}
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;
}
}
+ // 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(_T(","), _T(" "));
+
+ // also deal with the leading dot
+ if ( !strExtensions.IsEmpty() && strExtensions[0] == _T('.') ) {
+ strExtensions.erase(0, 1);
+ }
+
int index = m_aTypes.Index(strMimeType);
- if ( index == NOT_FOUND ) {
+ if ( index == wxNOT_FOUND ) {
// add a new entry
m_aTypes.Add(strMimeType);
m_aEntries.Add(NULL);
}
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
} currentToken = Field_Type;
// the flags and field values on the current line
- bool needsterminal = false,
- copiousoutput = false;
+ bool needsterminal = FALSE,
+ copiousoutput = FALSE;
wxString strType,
strOpenCmd,
strPrintCmd,
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
}
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
switch ( currentToken ) {
case Field_Type:
strType = curField;
- if ( strType.Find('/') == NOT_FOUND ) {
+ if ( strType.Find(_T('/')) == wxNOT_FOUND ) {
// we interpret "type" as "type/*"
- strType += "/*";
+ strType += _T("/*");
}
currentToken = Field_OpenCmd;
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.Left('='),
- rhs = curField.After('=');
+ 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);
}
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;
// 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;
{
// don't flood the user with error messages
// if we don't understand something in his
- // mailcap
+ // mailcap, but give them in debug mode
+ // because this might be useful for the
+ // programmer
wxLogDebug
(
- _("Mailcap file %s, line %d: unknown "
- "field '%s' for the MIME type "
- "'%s' ignored."),
+ _T("Mailcap file %s, line %d: unknown "
+ "field '%s' for the MIME type "
+ "'%s' ignored."),
strFileName.c_str(),
nLine + 1,
curField.c_str(),
break;
default:
- wxFAIL_MSG("unknown field type in mailcap");
+ wxFAIL_MSG(_T("unknown field type in mailcap"));
}
// next token starts immediately after ';'
strType.MakeLower();
int nIndex = m_aTypes.Index(strType);
- if ( nIndex == NOT_FOUND ) {
+ if ( nIndex == wxNOT_FOUND ) {
// new file type
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) == NOT_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;
}
}
m_aTypes.Count() == m_aExtensions.Count() &&
m_aTypes.Count() == m_aDescriptions.Count() );
}
+
+ return TRUE;
}
-#endif // OS type
+#endif
+ // OS type
-/* vi: set cin tw=80 ts=4 sw=4: */
+#endif
+ // wxUSE_FILE && wxUSE_TEXTFILE
+#endif
+ // __WIN16__