- // check what follows this entry
- if ( *pEnd == wxT('"') ) {
- // skip this quote
- pEnd++;
- }
-
- for ( pc = pEnd; wxIsspace(*pc); pc++ )
- ;
-
- // 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 == wxT('\0'),
- nextFieldOnSameLine = FALSE;
- if ( !entryEnded ) {
- nextFieldOnSameLine = ((*pc != wxT('\\')) || (pc[1] != wxT('\0')));
- }
-
- // now see what we got
- if ( strLHS == wxT("type") ) {
- strMimeType = strRHS;
- }
- else if ( strLHS == wxT("desc") ) {
- strDesc = strRHS;
- }
- else if ( strLHS == wxT("exts") ) {
- strExtensions = strRHS;
- }
- else {
- wxLogWarning(_("Unknown field in file %s, line %d: '%s'."),
- strFileName.c_str(), nLine + 1, strLHS.c_str());
- }
-
- if ( !entryEnded ) {
- 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;
- }
- }
-
- // depending on the format (Mosaic or Netscape) either space or comma
- // is used to separate the extensions
- strExtensions.Replace(wxT(","), wxT(" "));
-
- // also deal with the leading dot
- if ( !strExtensions.IsEmpty() && strExtensions[0u] == wxT('.') )
- {
- strExtensions.erase(0, 1);
- }
-
- AddMimeTypeInfo(strMimeType, strExtensions, strDesc);
-
- // 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;
-}
-
-bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName,
- bool fallback)
-{
- wxLogTrace(TRACE_MIME, 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
- bool cont = TRUE;
- while ( cont ) {
- 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 if there is one
- if ( nLine == nLineCount - 1 ) {
- // something is wrong, bail out
- cont = FALSE;
-
- wxLogDebug(wxT("Mailcap file %s, line %d: "
- "'\\' on the end of the last line "
- "ignored."),
- strFileName.c_str(),
- nLine + 1);
- }
- else {
- // pass to the beginning of the next line
- pc = file[++nLine].c_str();
-
- // skip pc++ at the end of the loop
- continue;
- }
- }
- 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.empty() ) {
- // I don't think that this is a valid mailcap
- // entry, but try to interpret it somehow
- strType = _T('*');
- }
-
- 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:
- if ( !curField.empty() ) {
- // "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
- if ( curField == wxT("needsterminal") )
- needsterminal = TRUE;
- else if ( curField == wxT("copiousoutput")) {
- // copiousoutput impies that the
- // viewer is a console program
- needsterminal =
- copiousoutput = TRUE;
- }
- else {
- // unknown flag
- ok = FALSE;
- }
- }
-
- if ( !ok )
- {
- if ( !IsKnownUnimportantField(curField) )
- {
- // 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()
- );
- }
- }
- }
- //else: the field is empty, ignore silently
-
- // 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;
- }
-
- // continue in the same line
- 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 {
- // support for flags:
- // 1. create an xterm for 'needsterminal'
- // 2. append "| $PAGER" for 'copiousoutput'
- //
- // Note that the RFC says that having both needsterminal and
- // copiousoutput is probably a mistake, so it seems that running
- // programs with copiousoutput inside an xterm as it is done now
- // is a bad idea (FIXME)
- if ( copiousoutput ) {
- const wxChar *p = wxGetenv(_T("PAGER"));
- strOpenCmd << _T(" | ") << (p ? p : _T("more"));
- }
-
- if ( needsterminal ) {
- strOpenCmd.Printf(_T("xterm -e sh -c '%s'"),
- strOpenCmd.c_str());
- }
-
- 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() );