/* KPilot ** ** Copyright (C) 2002-2003 by Reinhold Kainhofer ** ** The doc converter synchronizes text files on the PC with DOC databases on the Palm */ /* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program in a file called COPYING; if not, write to ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ** MA 02110-1301, USA. */ /* ** Bug reports and questions can be sent to kde-pim@kde.org */ #include "options.h" #include "DOC-converter.moc" #include #include #include #include #include #include #include #include "pilotDOCHead.h" #include "pilotDOCEntry.h" #include "pilotDOCBookmark.h" #define min(a,b) (a= 0 && found -1) { ++found; if (found>=from && found=0) { fBookmarks.append(new docBookmark(/*bmkName.left(16)*/rx.cap(capSubexpression), pos)); } else { // TODO: use the subexpressions from the regexp for the bmk name ($1..$9) (given as separate regexp) TQString bmkText(bmkName); for (int i=0; i<=rx.numCaptures(); ++i) { bmkText.replace(CSL1("$%1").tqarg(i), rx.cap(i)); bmkText.replace(CSL1("\\%1").tqarg(i), rx.cap(i)); } fBookmarks.append(new docBookmark(bmkText.left(16), pos)); } ++nr; } ++pos; } } return nr; } /********************************************************************* C O N S T R U C T O R *********************************************************************/ DOCConverter::DOCConverter(TQObject *parent, const char *name):TQObject(parent,name) { FUNCTIONSETUP; docdb=0L; eSortBookmarks=eSortNone; fBookmarks.setAutoDelete( TRUE ); } DOCConverter::~DOCConverter() { FUNCTIONSETUP; } /********************************************************************* S Y N C S T R U C T U R E *********************************************************************/ void DOCConverter::setTXTpath(TQString path, TQString file) { TQDir dr(path); TQFileInfo pth(dr, file); if (!file.isEmpty()) txtfilename = pth.absFilePath(); } void DOCConverter::setTXTpath(TQString filename) { if (!filename.isEmpty()) txtfilename = filename; } void DOCConverter::setPDB(PilotDatabase * dbi) { if (dbi) docdb = dbi; } TQString DOCConverter::readText() { FUNCTIONSETUP; if (txtfilename.isEmpty()) return TQString(); TQFile docfile(txtfilename); if (!docfile.open(IO_ReadOnly)) { emit logError(i18n("Unable to open text file %1 for reading.").tqarg(txtfilename)); return TQString(); } TQTextStream docstream(&docfile); TQString doc = docstream.read(); docfile.close(); return doc; } int DOCConverter::findBmkEndtags(TQString &text, bmkList&fBmks) { FUNCTIONSETUP; // Start from the end of the text int pos = text.length() - 1, nr=0; bool doSearch=true; while (pos >= 0/* && doSearch*/) { DEBUGKPILOT<<"Current character is \'"< while (text[pos].isSpace() && pos >= 0) { DEBUGKPILOT<<"Skipping whitespaces at the end of the file"< is assumed to belong to the text, so there are no more bookmarks. if (pos < 0 || text[pos] != '>') { DEBUGKPILOT<<"Current character \'"<. Finish searching for bookmarks."<, now looking for the opening <"< 0) { // DEBUGKPILOT<<"pos="<"<")); rx.setMinimal(TRUE); int pos = 0; while (pos >= 0) { pos = rx.search(text, pos); if (pos >= 0) { fBmks.append(new docBookmark(rx.cap(1), pos+1)); ++nr; text = text.remove(pos, rx.matchedLength()); } } return nr; } int DOCConverter::findBmkFile(TQString &, bmkList &fBmks) { FUNCTIONSETUP; int nr=0; TQString bmkfilename = txtfilename; if (bmkfilename.endsWith(CSL1(".txt"))){ bmkfilename.remove(bmkfilename.length()-4, 4); } TQString oldbmkfilename=bmkfilename; bmkfilename+=CSL1(BMK_SUFFIX); TQFile bmkfile(bmkfilename); if (!bmkfile.open(IO_ReadOnly)) { bmkfilename=oldbmkfilename+CSL1(PDBBMK_SUFFIX); bmkfile.setName(bmkfilename); if (!bmkfile.open(IO_ReadOnly)) { DEBUGKPILOT<<"Unable to open bookmarks file "<dbPathName()<,,,, // For an explanation see: http://home.kc.rr.com/krzysztow/PalmPilot/MakeDocJ/index.html if (fieldnr>0){ DEBUGKPILOT<<"Working on bookmark \""<1) { TQString name(bmkinfo[1]); DEBUGKPILOT<<"Bookmark \""<1) { TQString patt(bmkinfo[1]); TQString name(patt); if (fieldnr>2) { int cap=bmkinfo[2].toInt(&ok); if (ok) { bmk=new docRegExpBookmark(patt, cap); } else { name=bmkinfo[2]; bmk=new docRegExpBookmark(patt, name); } } else{ bmk=new docRegExpBookmark(patt, name); } // The third entry in the line (optional) denotes the index of a capture subexpression (if an integer) or the bookmark text as regexp (if a string) DEBUGKPILOT<<"RegExp Bookmark, pattern="<from=1; bmk->to=1; } else { if (fieldnr>3) { bool ok; int tmp=bmkinfo[3].toInt(&ok); if (ok) bmk->from=tmp; if (fieldnr>4) { tmp=bmkinfo[4].toInt(&ok); if (ok) bmk->to=tmp; } } } fBmks.append(bmk); bmk=0L; } else { DEBUGKPILOT<<"Could not allocate bookmark "<1) pattern=bmkinfo[1]; if (fieldnr>2) bookmark=bmkinfo[2]; DEBUGKPILOT<<"RegExp Bookmark, pattern="< in the text. We have to delete them immediately, otherwise the later bookmarks will be off. if (fBmkTypes & eBmkInline) { findBmkInline(text, fBookmarks); } // end: Inline Bookmarks // Read in regular expressions and positions from an external file (doc-filename with extension .bmk) if (fBmkTypes & eBmkFile) { findBmkFile(text, fBookmarks); } // Process the bookmarks: find the occurrences of the regexps, and sort them if requested: bmkSortedList pdbBookmarks; pdbBookmarks.setAutoDelete(TRUE); docBookmark*bmk; for (bmk = fBookmarks.first(); bmk; bmk = fBookmarks.next()) { bmk->findMatches(text, pdbBookmarks); } switch (eSortBookmarks) { case eSortName: docBookmark::compare_pos=false; // qHeapSort(pdbBookmarks); pdbBookmarks.sort(); break; case eSortPos: docBookmark::compare_pos=true; pdbBookmarks.sort(); break; case eSortNone: default: break; } #ifdef DEBUG DEBUGKPILOT << "Bookmarks: "<bmkName.left(20)<<" at position "<position<isOpen()) { emit logError(i18n("Unable to open palm doc database %1").tqarg(docdb->dbPathName()) ); return false; } // Clean the whole database, otherwise the records would be just appended! docdb->deleteRecord(0, true); // Header record for the doc file format PilotDOCHead docHead; docHead.position=0; docHead.recordSize=4096; docHead.spare=0; docHead.storyLen=text.length(); docHead.version=compress?DOC_COMPRESSED:DOC_UNCOMPRESSED; docHead.numRecords=(int)( (text.length()-1)/docHead.recordSize)+1; PilotRecord*rec=docHead.pack(); docdb->writeRecord(rec); KPILOT_DELETE(rec); DEBUGKPILOT << "Write header record: length="<readRecordByIndex(0); if (!headerRec) { emit logError(i18n("Unable to read database header for database %1.").tqarg(docdb->dbPathName())); KPILOT_DELETE(docdb); return false; } PilotDOCHead header(headerRec); KPILOT_DELETE(headerRec); DEBUGKPILOT<<"Database "<dbPathName()<<" has "<recordCount()<readRecordByIndex(i); if (rec) { PilotDOCEntry recText(rec, header.version==DOC_COMPRESSED); doctext.append(recText.getText()); DEBUGKPILOT<<"Record "<dbPathName())); } } // After the document records possibly come a few bookmark records, so read them in and put them in a separate bookmark file. // for the ztxt conduit there might be annotations after the bookmarks, so the upper bound needs to be adapted. int upperBmkRec=docdb->recordCount(); bmkSortedList bmks; bmks.setAutoDelete(TRUE); for (int i=header.numRecords+1; ireadRecordByIndex(i); if (rec) { PilotDOCBookmark bookie(rec); docBookmark*bmk=new docBookmark(TQString::tqfromLatin1(bookie.bookmarkName), bookie.pos); bmks.append(bmk); KPILOT_DELETE(rec); } else { emit logMessage(i18n("Could not read bookmark record #%1 from Database %2").tqarg(i).tqarg(docdb->dbPathName())); } } // TODO: Sort the list of bookmarks according to their position docBookmark::compare_pos=true; bmks.sort(); if ((fBmkTypes & eBmkFile) && (bmks.count()>0)) { TQString bmkfilename = docfile.name(); if (bmkfilename.endsWith(CSL1(".txt"))){ bmkfilename.remove(bmkfilename.length()-4, 4); } bmkfilename+=CSL1(PDBBMK_SUFFIX); TQFile bmkfile(bmkfilename); if (!bmkfile.open(IO_WriteOnly)) { emit logError(i18n("Unable to open file %1 for the bookmarks of %2.") .tqarg(bmkfilename).tqarg(docdb ->dbPathName())); } else { DEBUGKPILOT<<"Writing "<position<<", "<bmkName<position, TQString(CSL1("<*") + bmk->bmkName + CSL1("*>"))); } } // Finally, write the actual text out to the file. TQTextStream docstream(&docfile); docstream<cleanup(); // reset all records to unchanged. I don't know if this is really such a wise idea? docdb->resetSyncFlags(); return true; }