-bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName,
- bool fallback)
-{
- wxLogTrace(wxT("--- Parsing mailcap file '%s' ---"), strFileName.c_str());
-
- wxTextFile file(strFileName);
- if ( !file.Open() )
- return FALSE;
-
- // 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 wxChar *pc = file[nLine].c_str();
-
- // skip whitespace
- while ( wxIsspace(*pc) )
- pc++;
-
- // comment or empty string?
- if ( *pc == wxT('#') || *pc == wxT('\0') )
- continue;
-
- // no, do parse
-
- // what field are we currently in? The first 2 are fixed and there may
- // be an arbitrary number of other fields -- currently, we are not
- // interested in any of them, but we should parse them as well...
- enum
- {
- Field_Type,
- Field_OpenCmd,
- Field_Other
- } currentToken = Field_Type;
-
- // the flags and field values on the current line
- bool needsterminal = FALSE,
- copiousoutput = FALSE;
- wxString strType,
- strOpenCmd,
- strPrintCmd,
- strTest,
- strDesc,
- curField; // accumulator
- for ( bool cont = TRUE; cont; pc++ ) {
- switch ( *pc ) {
- case wxT('\\'):
- // interpret the next character literally (notice that
- // backslash can be used for line continuation)
- if ( *++pc == wxT('\0') ) {
- // fetch the next line.
-
- // pc currently points to nowhere, but after the next
- // pc++ in the for line it will point to the beginning
- // of the next line in the file
- pc = file[++nLine].c_str() - 1;
- }
- else {
- // just a normal character
- curField += *pc;
- }
- break;
-
- case wxT('\0'):
- cont = FALSE; // end of line reached, exit the loop
-
- // fall through
-
- case wxT(';'):
- // store this field and start looking for the next one
-
- // trim whitespaces from both sides
- curField.Trim(TRUE).Trim(FALSE);
-
- switch ( currentToken ) {
- case Field_Type:
- strType = curField;
- if ( strType.Find(wxT('/')) == wxNOT_FOUND ) {
- // we interpret "type" as "type/*"
- strType += wxT("/*");
- }
-
- currentToken = Field_OpenCmd;
- break;
-
- case Field_OpenCmd:
- strOpenCmd = curField;
-
- currentToken = Field_Other;
- break;
-
- case Field_Other:
- {
- // "good" mailcap entry?
- bool ok = TRUE;
-
- // is this something of the form foo=bar?
- const wxChar *pEq = wxStrchr(curField, wxT('='));
- if ( pEq != NULL ) {
- wxString lhs = curField.BeforeFirst(wxT('=')),
- rhs = curField.AfterFirst(wxT('='));
-
- lhs.Trim(TRUE); // from right
- rhs.Trim(FALSE); // from left
-
- if ( lhs == wxT("print") )
- strPrintCmd = rhs;
- else if ( lhs == wxT("test") )
- strTest = rhs;
- else if ( lhs == wxT("description") ) {
- // it might be quoted
- if ( rhs[0u] == wxT('"') &&
- rhs.Last() == wxT('"') ) {
- strDesc = wxString(rhs.c_str() + 1,
- rhs.Len() - 2);
- }
- else {
- strDesc = rhs;
- }
- }
- else if ( lhs == wxT("compose") ||
- lhs == wxT("composetyped") ||
- lhs == wxT("notes") ||
- lhs == wxT("edit") )
- ; // ignore
- else
- ok = FALSE;
-
- }
- else {
- // no, it's a simple flag
- // TODO support the flags:
- // 1. create an xterm for 'needsterminal'
- // 2. append "| $PAGER" for 'copiousoutput'
- if ( curField == wxT("needsterminal") )
- needsterminal = TRUE;
- else if ( curField == wxT("copiousoutput") )
- copiousoutput = TRUE;
- else if ( curField == wxT("textualnewlines") )
- ; // ignore
- else
- ok = FALSE;
- }
-
- if ( !ok )
- {
- // we don't understand this field, but
- // Netscape stores info in it, so don't warn
- // about it
- if ( curField.Left(16u) != "x-mozilla-flags=" )
- {
- // don't flood the user with error
- // messages if we don't understand
- // something in his mailcap, but give
- // them in debug mode because this might
- // be useful for the programmer
- wxLogDebug
- (
- wxT("Mailcap file %s, line %d: "
- "unknown field '%s' for the "
- "MIME type '%s' ignored."),
- strFileName.c_str(),
- nLine + 1,
- curField.c_str(),
- strType.c_str()
- );
- }
- }
- }
-
- // it already has this value
- //currentToken = Field_Other;
- break;
-
- default:
- wxFAIL_MSG(wxT("unknown field type in mailcap"));
- }
-
- // next token starts immediately after ';'
- curField.Empty();
- break;
-
- default:
- curField += *pc;
- }
- }
-
- // check that we really read something reasonable
- if ( currentToken == Field_Type || currentToken == Field_OpenCmd ) {
- wxLogWarning(_("Mailcap file %s, line %d: incomplete entry "
- "ignored."),
- strFileName.c_str(), nLine + 1);
- }
- else {
- MailCapEntry *entry = new MailCapEntry(strOpenCmd,
- strPrintCmd,
- strTest);
-
- // NB: because of complications below (we must get entries priority
- // right), we can't use AddMailcapInfo() here, unfortunately.
- strType.MakeLower();
- int nIndex = m_aTypes.Index(strType);
- if ( nIndex == wxNOT_FOUND ) {
- // new file type
- m_aTypes.Add(strType);
-
- m_aEntries.Add(entry);
- m_aExtensions.Add(wxT(""));
- m_aDescriptions.Add(strDesc);
- }
- else {
- // 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 {
- 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??
- m_aDescriptions[nIndex] = strDesc;
- }
- }
- }
-
- // 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;
-}