This is eTDocInfo.m in view mode; [Download] [Up]
{\rtf0\ansi{\fonttbl\f0\fmodern Courier;\f1\ftech Symbol;\f3\fnil Times-Roman;\f4\fswiss Helvetica;\f2\fmodern Ohlfs;} \margl40 \margr40 {\colortbl;\red0\green0\blue0;} \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i0\ulnone\fs24\fc0\cf0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \i \b FILENAME \b0 : \b\i0 eTDocInfo.m\ \b0 // \i \b SUMMARY \b0 : \b\i0 Required persistent interface for ALL eText documents \b0 \ // \b\i SUPERCLASS \b0 : \i0 \b Object:HashTable:NXStringTable:eTDocInfo \b0 \ // \b\i PROTOCOLS \b0 : \i0 \b <ComponentWriting,ComponentReading,InspectableTarget> \b0 \ // \b\i INTERFACE \b0 : \i0 \b None \b0 \ // \b\i AUTHOR \b0 : \b\i0 Rohit Khare \b0 \ // \b\i COPYRIGHT \b0 : \f1\i0 Ó \f0\b 1993,94 California Institure of Technology, eText Project\ \b0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b\i Implementation Comments \b0\i0 \ \pard\tx520\tx1060\tx1580\tx2120\tx2640\tx3180\tx3720\tx4240\tx4780\tx5300\fc1\cf1 // \i eTDocInfo \i0 s are descendants of \i StringTable \i0 s,\ // so they can be extended indefinitely to support dictionary\ // attributes. Future applications may replace the string table\ // with a bTree, allowing for more powerful indexing and the\ // ability to browse eText document collections without loading\ // all the \i .etDocInfo \i0 s. \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc1\cf1 \ \fc0\cf0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b\i HISTORY \b0\i0 \ // 12/23/94: \b Changed readComponent to cache the "latest" docPath \b0 \ // 12/23/94: \b Overhauled taggingFont system to handle "missing" fonts \b0 \ // 12/08/94: \b Patched Kelsey's HTML generation bugs. \b0 \ // 10/30/94: \b Fixed tag font default registration, added +aliases for tags. \b0 \ // 10/30/94: \b Modified to support <InspectableTarget> \b0 \ // 10/29/94: \b search/regex package rewritten \i \ \b0\i0 // 10/27/94: \b -isVirgin added to public API. \i \ \b0\i0 // 10/04/94: \b -free bug; NXStrTab was free()ing NXAtoms. (was in init/rcfpth) \i \ \b0\i0 // 10/04/94: \b Added eTDoc ivar by analogy to path[] and eTComponents. \i \ \b0\i0 // 10/03/94: \b Added <ComponentWriting>, docInfoTable. \i \ \b0\i0 // 10/01/94: \b Reorganized into categories: eText and eDraw. \b0 \ // 09/30/94: \b Revamped for eText5; renamed eTDocInfo \b0 \ // 07/20/94: \b Added LaTeX support. \b0 \ // 07/10/94: \b Added support for HTML header/trailer writing \b0 \ // 01/11/94: \b Added Agent field. \b0 \ // 01/11/94: \b Added flexible "bindery" methods for extension of navinfo data \b0 \ // 01/10/94: \b Created. See Actors/eTNavinfo \b0 \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Imported Interfaces \b0 \ //\ #import " \b eTDocInfo.h \b0 "\ #import " \b eTDocInfoUI.h \b0 "\ #import " \b Kludges \b0 .subproj/ \b regexpr.h \b0 "\ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b "Class" Variable \b0 \ //\ \b HashTable \b0 * \b docInfoTable \b0 ;\ \ \i @implementation eTDocInfo\ \i0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Class Management \b0 \ //\ + \b initialize \b0 \{\ char key[MAXPATHLEN];\ \ \b docInfoTable \b0 = [[ \b HashTable \b0 alloc] \b initKeyDesc \b0 :"i"];\ \ \fc1\cf1 sprintf(key, "%s%s", \b H1 \b0 , TAGNAME);\ [userModel defaultValue:" \f3\b\fs60\fc0\cf0 Times-Bold \f0\b0\fs24\fc1\cf1 " for:key];\ sprintf(key, "%s%s", \b H1 \b0 , TAGSIZE);\ [userModel defaultValue:" \b 30.0 \b0 " for:key];\ \fc0\cf0 \ \fc1\cf1 sprintf(key, "%s%s", \b H2 \b0 , TAGNAME);\ [userModel defaultValue:" \f3\fs48\fc0\cf0 Times-Roman \f0\fs24\fc1\cf1 " for:key];\ sprintf(key, "%s%s", \b H2 \b0 , TAGSIZE);\ [userModel defaultValue:" \b 24.0 \b0 " for:key];\ \fc0\cf0 \ \fc1\cf1 sprintf(key, "%s%s", \b H3 \b0 , TAGNAME);\ [userModel defaultValue:" \f3\b\fs36\fc0\cf0 Times-Bold \f0\b0\fs24\fc1\cf1 " for:key];\ sprintf(key, "%s%s", \b H3 \b0 , TAGSIZE);\ [userModel defaultValue:" \b 18.0 \b0 " for:key];\ \ sprintf(key, "%s%s", \b H4 \b0 , TAGNAME);\ [userModel defaultValue:" \f3\fs36\fc0\cf0 Times-Roman \f0\fs24\fc1\cf1 " for:key];\ sprintf(key, "%s%s", \b H4 \b0 , TAGSIZE);\ [userModel defaultValue:" \b 18.0 \b0 " for:key];\ \ sprintf(key, "%s%s", \b H5 \b0 , TAGNAME);\ [userModel defaultValue:" \f3\b\fs20\fc0\cf0 Times-Bold \f0\b0\fs24\fc1\cf1 " for:key];\ sprintf(key, "%s%s", \b H5 \b0 , TAGSIZE);\ [userModel defaultValue:" \b 10.0 \b0 " for:key];\ \fc0\cf0 \ \fc1\cf1 sprintf(key, "%s%s", \b H6 \b0 , TAGNAME);\ [userModel defaultValue:" \f3\fs20\fc0\cf0 Times-Roman \f0\fs24\fc1\cf1 " for:key];\ sprintf(key, "%s%s", \b H6 \b0 , TAGSIZE);\ [userModel defaultValue:" \b 10.0 \b0 " for:key];\ \fc0\cf0 \ \fc1\cf1 sprintf(key, "%s%s", \b QT \b0 , TAGNAME);\ [userModel defaultValue:" \f4\fs28\fc0\cf0 Helvetica \f0\fs24\fc1\cf1 " for:key];\ sprintf(key, "%s%s", \b QT \b0 , TAGSIZE);\ [userModel defaultValue:" \b 14.0 \b0 " for:key];\ \fc0\cf0 \ \fc1\cf1 sprintf(key, "%s%s", \b BODY \b0 , TAGNAME);\ [userModel defaultValue:" \f3\fs28\fc0\cf0 Times-Roman \f0\fs24\fc1\cf1 " for:key];\ sprintf(key, "%s%s", \b BODY \b0 , TAGSIZE);\ [userModel defaultValue:" \b 14.0 \b0 " for:key];\ \fc0\cf0 \ return self;\ \}\ + ( \b HashTable \b0 *) \b docInfoTable \b0 \{\ return docInfoTable;\ \}\ + \b findDocInfo \b0 :(long) \b aDocID \b0 \{\ return [ \b docInfoTable \b0 valueForKey: \b aDocID \b0 ]; \ \}\ \ // \i Later, twiddling bits \b inside \b0 NXStrTab, I see that it is\ \i0 // \i initialized to %-*, in contravention of the docs. \i0 \ //\ // \i For debugging purposes only: I suspect StrTab's munching me.\ \i0 // \b\i Well, NXStringTable IS munching me!!!!! \b0\i0 \ // \i If the current value is == NXUniqueString(aValue), it tries \i0 \ // \i to \b free \b0 the old \b NXAtom \b0 !!!!! So that triggers random lossage\ \i0 // \i everywhere... the fix here is evil and expensive, so be it.\ \i0 // \i NeXT engineering will burn for this (unless they have some\ \i0 // \i extra-special magic on tap in Mecca...) \i0 \ \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0\cf0 - (void *)insertKey:(const void *)aKey value:(void *)aValue\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 \{\ NXAtom key,value;\ \ key = NXUniqueString(aKey);\ value = NXUniqueString(aValue);\ \b\fs36 [self removeKey:key];\ \b0\fs24 return [super insertKey:key value:value];\ \}\ \ - \b init \b0 \{\ \b char \b0 \b idStr \b0 [9], buf[MAXPATHLEN];\ struct \b passwd \b0 * \b p \b0 ;\ \ [super \b initKeyDesc \b0 :"%" \b valueDesc \b0 :"%"];\ \b readOnly \b0 = \b NO \b0 ;\ \b virgin \b0 = \b YES \b0 ;\ \b docPath \b0 [0] = ' \b \\0 \b0 ';\ \b etDoc \b0 = \b nil \b0 ;\ \ docID = 0;\ while ((docID == \b 0 \b0 ) || ([docInfoTable \b isKey \b0 : \b docID \b0 ]))\ \b docID \b0 = [NXApp \b uniqueID \b0 ];\ [docInfoTable \b insertKey \b0 :docID \b value \b0 :self];\ \b sprintf \b0 ( \b idStr \b0 ," \b %x \b0 ", \b docID \b0 );\ [self \b insertKey \b0 : \b DOCID \b0 \b value \b0 :(char *)NXUniqueString( \b idStr \b0 )];\ [self \b setDocTitle \b0 : \b "Untitled Document" \b0 ];\ [self \b setType \b0 : \b eTEXT \b0 ]; // \i eTextDoc type extension \i0 \ [self \b initTagFields \b0 ]; // \i eTextDoc init extension \i0 \ p = \b getpwuid \b0 ( \b getuid \b0 ());\ [self \b setAuthor \b0 :p->pw_gecos ? \b p->pw_gecos \b0 : " \b Author's Name \b0 "];\ [self \b setAgent \b0 :""];\ [self \b setParent \b0 :""];\ [self \b setPeers \b0 :""];\ [self \b setKeywords \b0 :""];\ sprintf(buf, "\{\\\\rtf0\\\\ansi\{\\\\fonttbl\\\\f1\\\\fnil Times-Roman;\\\\f2\\\\fswiss Helvetica;\}\\n\\\\margl40\\n\\\\margr40\\n\\\\pard\\\\tx520\\\\tx1060\\\\tx1600\\\\tx2120\\\\tx2660\\\\tx3200\\\\tx3720\\\\tx4260\\\\tx4800\\\\tx5320\\\\f1\\\\b0\\\\ulnone\\\\fs24\\\\fc0\\\\cf0 Rich-Text \\n\\\\b comments\\n\\\\b0 about this document\\n \b --%s \b0 \\n\}\\n", [NXApp \b date \b0 ]);\ [self \b setRTFComments \b0 :buf]; // \f3 Rich Text \i comments \i0 about this document \f0 \ [self \b insertKey \b0 : \b MDFYDATE \b0 \b value \b0 :NXUniqueString([NXApp \b date \b0 ])]; \ return self;\ \}\ - \b free \b0 \{\ // \i If another docInfo is already registered with its key, \b OR \b0\i0 \ // \i If this docInfo is a virgin (no saves) \i0 \ // \i Then (remove it from the table) free it\ \ \i0 if ( \b virgin \b0 && ([ \b docInfoTable \b0 valueForKey: \b docID \b0 ] == \b self \b0 )) \{\ [docInfoTable \b removeKey \b0 : \b docID \b0 ];\ \}\ if ( \b virgin \b0 || ([ \b docInfoTable \b0 valueForKey: \b docID \b0 ] != \b self \b0 ))\{\ [self \b empty \b0 ]; // \i Memory leak, but these are reusable NXAtoms anyway \i0 \ return self = [super \b free \b0 ];\ \}\ return \b self \b0 ;\ \}\ \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b <ComponentReading, ComponentWriting> \b0 \ //\ - \b writeComponentToPath \b0 :(NXAtom)path \b inFormat \b0 :(int) theFormat \{\ char \b docInfoPath \b0 [MAXPATHLEN];\ \ sprintf( \b docInfoPath \b0 , " \b %s/%s \b0 ", path, \b DOCINFOFILE \b0 );\ [self \b insertKey \b0 : \b MDFYDATE \b0 \b value \b0 :NXUniqueString([NXApp \b date \b0 ])]; \ [self \b writeToFile \b0 :docInfoPath];\ [ \b etDoc \b0 \b registerComponent \b0 : \b DOCINFOFILE \b0 ];\ \b virgin \b0 = \b NO \b0 ;\ return self;\ \}\ - \b readComponentFromPath \b0 :(NXAtom)path \{\ char \b docInfoPath \b0 [MAXPATHLEN]; id aDI;\ \ if ([docInfoTable \b valueForKey \b0 : \b docID \b0 ] == \b self \b0 )\ [docInfoTable \b removeKey \b0 : \b docID \b0 ]; // \i init: registered the untitled ID \i0 \ strncpy( \b docPath \b0 , \b path \b0 , MAXPATHLEN);\ \ // \i OK, we have an etfd path, try concatenating DOCINFOFILE \i0 .\ sprintf( \b docInfoPath \b0 , "%s/%s", \b docPath \b0 , \b DOCINFOFILE \b0 );\ if ( \b access \b0 (docInfoPath, R_OK | F_OK)) \{\ // \i backward-compatibility with PR1 documents \i0 .\ sprintf( \b docInfoPath \b0 , "%s/%s", \b docPath \b0 , \b NAVINFOFILE1 \b0 );\ if ( \b access \b0 (docInfoPath, R_OK | F_OK)) \{\ // \i backward-compatibility with PR2 documents \i0 .\ sprintf( \b docInfoPath \b0 , "%s/%s", \b docPath \b0 , \b NAVINFOFILE2 \b0 );\ if ( \b access \b0 (docInfoPath, R_OK | F_OK)) \{\ // \i Last-Ditch check: is path itself the file? [etApp openFile] \i0 \ strncpy( \b docInfoPath \b0 , \b path \b0 , MAXPATHLEN);\ strncpy( \b docPath \b0 , \b docInfoPath \b0 , MAXPATHLEN);\ * \b rindex \b0 ( \b docPath \b0 , ' \b / \b0 ') = ' \b \\0 \b0 ';\ \}\ \}\ \}\ if ( \b access \b0 (docInfoPath, R_OK | F_OK)) \{\ [NXApp \b delayedFree \b0 :self];\ return nil;\ \}\ if ( \b ! \b0 [self \b readFromFile \b0 :docInfoPath]) \{\ [NXApp \b delayedFree \b0 :self];\ return nil;\ \}\ // \i Quick Patch for pre-5.0 documents\ \i0 if ([self \b isKey \b0 :" \b title \b0 "] && \ ([self \b docTitle \b0 ] == NXUniqueString(" \b Untitled Document \b0 ")))\ [self \b setDocTitle \b0 :[self \b valueForStringKey \b0 :" \b title \b0 "]];\ \b sscanf \b0 ([self valueForStringKey: \b DOCID \b0 ], " \b %x \b0 ", \b &docID \b0 );\ aDI = [ \b docInfoTable \b0 valueForKey: \b docID \b0 ];\ if (!aDI)\{\ [docInfoTable \b insertKey \b0 :docID \b value \b0 :self];\ \} else if (aDI != self)\{\ id \b realInfo \b0 ;\ \ [NXApp \b delayedFree \b0 :self];\ \b realInfo \b0 = [ \b docInfoTable \b0 valueForKey: \b docID \b0 ];\ [realInfo \b setDocPath \b0 :path];\ return \b realInfo \b0 ;\ \}\ \b virgin \b0 = \b NO \b0 ;\ return self;\ \}\ \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Accessor Methods \b0 \ //\ - \b setDoc \b0 : newDoc \b \b0 \{\ // \i What about (un)registerNotification: ? \i0 \ \b etDoc \b0 = \b newDoc \b0 ;\ if ( \b etDoc \b0 ) [etDoc \b registerNotification \b0 :self];\ return self;\ \} \ - \b etDoc \b0 \{\ return \b etDoc \b0 ;\ \}\ \ - ( \b long \b0 ) \b docID \b0 \{\ return \b docID \b0 ;\ \} \ - (NXAtom) \b docIDStr \b0 \{\ return [self \b valueForStringKey \b0 : \b DOCID \b0 ];\ \}\ \ - (NXAtom) \b docTitle \b0 \{\ return [self \b valueForStringKey \b0 : \b DOCTITLE \b0 ];\ \}\ - \b setDocTitle \b0 :(const char *) newTitle \{\ if (index(newTitle, '/')) \{\ char patched[MAXPATHLEN];\ char *i;\ \ strcpy(patched, newTitle);\ for (i = patched; *i; i++)\ if (*i = '/') *i = '_';\ [self \b insertKey \b0 : \b DOCTITLE \b0 \b value \b0 :NXUniqueString( \b patched \b0 )];\ \} else \{\ [self \b insertKey \b0 : \b DOCTITLE \b0 \b value \b0 :NXUniqueString( \b newTitle \b0 )];\ \}\ return self;\ \}\ \ - (NXAtom) \b docType \b0 \{\ return [self \b valueForStringKey \b0 : \b DOCTYPE \b0 ];\ \}\ - \b setType \b0 :(const char *) newType \{\ [self \b insertKey \b0 : \b DOCTYPE \b0 \b value \b0 :NXUniqueString( \b newType \b0 )]; \ return self;\ \}\ \ - (NXAtom) \b author \b0 \{\ return [self \b valueForStringKey \b0 : \b AUTHOR \b0 ];\ \}\ - \b setAuthor \b0 :(const char *) newAuthor \{\ [self \b insertKey \b0 : \b AUTHOR \b0 \b value \b0 :NXUniqueString( \b newAuthor \b0 )]; \ return self;\ \}\ \ - (NXAtom) \b agent \b0 \{\ return [self \b valueForStringKey \b0 : \b AGENT \b0 ];\ \}\ - \b setAgent \b0 :(const char *) newAgent \{\ [self \b insertKey \b0 : \b AGENT \b0 \b value \b0 :NXUniqueString( \b newAgent \b0 )]; \ return self;\ \}\ \ - ( \b long \b0 ) \b parentID \b0 \{\ long \b pID \b0 ; int success;\ \ success = \b sscanf \b0 ([self \b parent \b0 ]," \b %x \b0 ", \b &pID \b0 );\ \b return \b0 (success ? \b pID \b0 : \b 0 \b0 );\ \}\ - (NXAtom) \b parent \b0 \{\ return [self \b valueForStringKey \b0 : \b PARENT \b0 ];\ \}\ - \b setParent \b0 :(const char *) newParent \{\ [self \b insertKey \b0 : \b PARENT \b0 \b value \b0 :NXUniqueString( \b newParent \b0 )]; \ return self;\ \}\ - \b setParentID \b0 :( \b long \b0 ) newParentID \{\ char newParent[64];\ \ \b sprintf \b0 (newParent, " \b %x \b0 ", \b newParentID \b0 );\ [self \b insertKey \b0 : \b PARENT \b0 \b value \b0 :NXUniqueString( \b newParent \b0 )]; \ return self;\ \}\ \ - (NXAtom) \b peers \b0 \{\ return [self \b valueForStringKey \b0 : \b PEERS \b0 ];\ \}\ - \b setPeers \b0 :(const char *) newPeers \{\ [self \b insertKey \b0 : \b PEERS \b0 \b value \b0 :NXUniqueString( \b newPeers \b0 )]; \ return self;\ \}\ - \b addPeerID \b0 :( \b long \b0 ) newPeerID \{\ char newPeers[MAXPATHLEN]; // \i Long enough? C Programmer's Disease. \i0 \ \ \b strncpy \b0 ( \b newPeers \b0 , [self \b peers \b0 ], MAXPATHLEN);\ \b sprintf \b0 (newPeers, " \b %x \b0 ", \b newPeerID \b0 );\ [self \b insertKey \b0 : \b PEERS \b0 \b value \b0 :NXUniqueString( \b newPeers \b0 )]; \ return self;\ \}\ \ - (NXAtom) \b keywords \b0 \{\ return [self \b valueForStringKey \b0 : \b KEYWORDS \b0 ];\ \}\ - \b setKeywords \b0 :(const char *) newKeywords \{\ [self \b insertKey \b0 : \b KEYWORDS \b0 \b value \b0 :NXUniqueString( \b newKeywords \b0 )]; \ return self;\ \}\ \ - (NXAtom) \b rtfComments \b0 \{ // \i RTF source of comment field\ \i0 return [self \b valueForStringKey \b0 : \b COMMENTS \b0 ];\ \}\ - \b setRTFComments \b0 :(const char *) newComments \{\ [self \b insertKey \b0 : \b COMMENTS \b0 \b value \b0 :NXUniqueString( \b newComments \b0 )]; \ return self;\ \}\ - (const char *) \b comments \b0 \{ // \i ASCII contents of comment field\ \i0 \b static \b0 char \b comments \b0 [MAXPATHLEN];\ NXStream * \b stream \b0 ;\ id \b theText \b0 = [NXApp \b sharedText \b0 ];\ const char * \b rtfSrc \b0 ;\ \i \ \i0 \b rtfSrc \b0 = [self \b rtfComments \b0 ];\ \b stream \b0 = \b NXOpenMemory \b0 ( \b rtfSrc \b0 , \b strlen \b0 (rtfSrc), \b NX_READONLY \b0 );\ [ \b theText \b0 \b readRichText \b0 :stream];\ \b NXClose \b0 (stream);\ [ \b theText \b0 \b getSubstring \b0 : \b comments \b0 start:0 length:MAXPATHLEN-1];\ \b comments \b0 [MAXPATHLEN-1]=0;\ \b return \b0 \b comments \b0 ;\ \}\ \ - (NXAtom) \b lastModifyDate \b0 \{\ return [self \b valueForStringKey \b0 : \b MDFYDATE \b0 ];\ \}\ \ - (NXAtom) \b valueOf \b0 : (NXAtom) \b theQuery \b0 \{\ \b NXAtom \b0 tmp = [self \b valueForStringKey \b0 : \b theQuery \b0 ];\ \b return \b0 (tmp ? \b tmp \b0 : NXUniqueString \b ("") \b0 );\ \}\ - \b bindKey \b0 :(const char *) \b newKey \b0 \b to \b0 : (const char *) \b newVal \b0 \{\ [self \b insertKey \b0 :NXUniqueString( \b newKey \b0 ) \b value \b0 :NXUniqueString( \b newVal \b0 )];\ return self;\ \}\ \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Runtime Properties \b0 \ //\ - (const char *) \b docPath \b0 \{\ return \b docPath \b0 ;\ \} \ - \b setDocPath \b0 :(const char *) newPath\ \{\ \b if \b0 (!strncmp([self \b docTitle \b0 ], " \b Untitled \b0 ", 8))\{ // \i Matches "Untitled*"\ \i0 char \b tmp \b0 [MAXPATHLEN]; // \i C Programmer's Disease \i0 \ \b strncpy \b0 ( \b tmp \b0 , \b rindex \b0 ( \b newPath \b0 , ' \b / \b0 ')+1, MAXPATHLEN);\ if (rindex(tmp, '.')) *rindex(tmp, '.')= 0; \ [self \b setDocTitle \b0 : \b tmp \b0 ];\ \}\ \b strncpy \b0 ( \b docPath \b0 , \b newPath \b0 , MAXPATHLEN); \ // \i how do we tell eTDocInfoUI its info has been invalidated?\ \i0 if ([ \b inspector \b0 \b currentObj \b0 ] == self) \{\ [ \b inspector \b0 \b refresh \b0 ];\ \}\ return self;\ \}\ \ - (BOOL) \b readOnly \b0 \{\ if ( \b !access \b0 ( \b docPath \b0 , \b F_OK \b0 ))\ return \b readOnly \b0 \b | \b0 = (BOOL) \b access \b0 ( \b docPath \b0 , \b W_OK \b0 );\ return \b readOnly \b0 ;\ \}\ - \b setReadOnly \b0 :(BOOL) newState \{\ if ( \b !access \b0 ( \b docPath \b0 , \b F_OK \b0 ))\ \b readOnly \b0 = newState | \b access \b0 ( \b docPath \b0 , \b W_OK \b0 );\ else\ \b readOnly \b0 = newState;\ return self;\ \}\ \ - (BOOL) \b isVirgin \b0 \{\ return \b virgin \b0 ;\}\ - (id < \b Inspectable \b0 >) \b inspectableDelegate \b0 \{\ return [[ \b eTDocInfoUI \b0 new] \b setDocInfo \b0 : \b self \b0 ]; \}\ \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0\cf0 \ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Query/Regex Matching \b0 \ //\ - ( \b BOOL \b0 ) \b searchFor \b0 :(NXAtom) \b regex \b0 \b in \b0 :(NXAtom) \b field \b0 \{\ BOOL \b found \b0 = \b NO \b0 ; char *err;\ BOOL di, pa, dti, dty, au, ag, pe, kw, co; // \i field masks \i0 \ \ if (!field || (*field == '\\0') || !regex) return \b NO \b0 ; // \i error case \i0 \ if (!strcmp( \b regex \b0 , \b ANYFIELD \b0 )) return \b YES \b0 ; // \i special case, "*" in any field \i0 \ if (err = ylo_ \b re_comp \b0 ( \b field \b0 )) // \i re_comp is static\ \i0 \{NXLogError("FieldSpec: %s",err); return \b NO \b0 ;\}\ \b di \b0 = ylo_re_exec( \b DOCID \b0 );\ \b pa \b0 = ylo_re_exec( \b PARENT \b0 );\ \b dti \b0 = ylo_re_exec( \b DOCTITLE \b0 );\ \b dty \b0 = ylo_re_exec( \b DOCTYPE \b0 );\ \b au \b0 = ylo_re_exec( \b AUTHOR \b0 );\ \b ag \b0 = ylo_re_exec( \b AGENT \b0 );\ \b pe \b0 = ylo_re_exec( \b PEERS \b0 );\ \b kw \b0 = ylo_re_exec( \b KEYWORDS \b0 );\ \b co \b0 = ylo_re_exec( \b COMMENTS \b0 );\ if (regex && (*regex == 0)) ylo_re_comp("^$"); // \i rule 11, man ed(1) \i0 \ else if (err = ylo_ \b re_comp \b0 ( \b regex \b0 )) // \i re_comp is static\ \i0 \{NXLogError("QuerySpec: %s",err); return \b NO \b0 ;\}\ if (!found && \b di \b0 ) found |= ylo_re_exec([self \b docIDStr \b0 ]);\ if (!found && \b pa \b0 ) found |= ylo_re_exec([self \b parent \b0 ]);\ if (!found && \b dti \b0 )found |= ylo_re_exec([self \b docTitle \b0 ]);\ if (!found && \b dty \b0 )found |= ylo_re_exec([self \b docType \b0 ]);\ if (!found && \b au \b0 ) found |= ylo_re_exec([self \b author \b0 ]);\ if (!found && \b ag \b0 ) found |= ylo_re_exec([self \b agent \b0 ]);\ if (!found && \b pe \b0 ) found |= ylo_re_exec([self \b peers \b0 ]);\ if (!found && \b kw \b0 ) found |= ylo_re_exec([self \b keywords \b0 ]);\ // \i Note that we search the RTF-coded comments field \i0 \ // \i -- not the ascii-filtered version \i0 \ if (!found && \b co \b0 ) found |= ylo_re_exec([self \b rtfComments \b0 ]);\ \b return found \b0 ;\ \}\ \ \i @end\ \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0\cf0 \ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\i0\fc0\cf0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Text-specific Extensions \b0 \ //\ \i @implementation eTDocInfo(eText) \i0 \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Generating Indexes \b0 \ //\ - \b setEmitTrailer \b0 :( \b BOOL \b0 )newState \{\ [self insertKey: \b TRAILER \b0 value: \b (newState ? "YES" : "NO") \b0 ]; \ return self;\ \}\ - ( \b BOOL \b0 ) \b emitTrailer \b0 \{\ NXAtom defVal = [self valueForStringKey: \b TRAILER \b0 ];\ if (!defVal || !strcmp(defVal, " \b YES \b0 ")) return \b YES \b0 ;\ return \b NO \b0 ;\}\ \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Tagging Fonts \b0 \ //\ - \b initTagFields \b0 \{\ int i;\ NXAtom tags[8] = \{H1, H2, H3, H4, H5, H6, QT, BODY\};\ for(i=0; i<8; i++)\ [self \b setTag \b0 :tags[i] to:[self \b tagFont \b0 :tags[i]]];\ [self \b setEmitTrailer \b0 : \b YES \b0 ];\ return self;\ \}\ - \b setTag \b0 :(const char *)tagType \b to \b0 : ( \b Font \b0 *)newFont \{\ char \b tagName \b0 [MAXPATHLEN];\ char \b tagSize \b0 [MAXPATHLEN];\ char \b fontSize \b0 [MAXPATHLEN];\ \ sprintf( \b tagName \b0 , " \b %s%s \b0 ", \b tagType \b0 , \b TAGNAME \b0 );\ sprintf( \b tagSize \b0 , " \b %s%s \b0 ", \b tagType \b0 , \b TAGSIZE \b0 );\ sprintf( \b fontSize \b0 , " \b %f \b0 ", [newFont \b pointSize \b0 ]);\ [self \b bindKey \b0 :NXUniqueString(tagName) \b to \b0 :NXUniqueString([ \b newFont \b0 \b name \b0 ])];\ [self \b bindKey \b0 :NXUniqueString(tagSize) \b to \b0 :NXUniqueString( \b fontSize \b0 )];\ return self;\ \}\ // \i The following table is used to cache errors in \b tagFont \b0 and \b defaultTagFont \b0\i0 .\ static id \b errTab \b0 = nil;\ \ - \b tagFont \b0 :(const char *)tagType \{\ char \b tagName \b0 [MAXPATHLEN];\ char \b tagSize \b0 [MAXPATHLEN];\ const char * \b fontName \b0 ;\ const char * \b fontSizeStr \b0 ;\ float \b fontSize \b0 ;\ id \b theFont \b0 ;\ \ sprintf( \b tagName \b0 , " \b %s%s \b0 ", \b tagType \b0 , \b TAGNAME \b0 );\ sprintf( \b tagSize \b0 , " \b %s%s \b0 ", \b tagType \b0 , \b TAGSIZE \b0 );\ \b fontName \b0 = [self \b valueOf \b0 : \b tagName \b0 ];\ \b fontSizeStr \b0 = [self \b valueOf \b0 : \b tagSize \b0 ];\ if (!(*fontName && *fontSizeStr)) \{\ fontName = [ \b userModel \b0 stringQuery: \b tagName \b0 ];\ fontSizeStr = [ \b userModel \b0 stringQuery: \b tagSize \b0 ];\ \}\ \b sscanf \b0 (fontSizeStr,"%f",& \b fontSize \b0 );\ \b theFont \b0 = [Font \b newFont \b0 : \b fontName \b0 \b size \b0 : \b fontSize \b0 \b matrix \b0 : \b NX_FLIPPEDMATRIX \b0 ];\ if ( \b !theFont \b0 ) \{\ if (!errTab) \{errTab = [[HashTable alloc] initKeyDesc:"%"];\}\ if (![errTab isKey:fontName])\{\ \b NXLogError \b0 ("Can't find %s font for the %s doc tag!", \b fontName \b0 , \b tagType \b0 );\ [errTab insertKey:fontName value:nil];\ \}\ // \i Can we figure out if the fonts were supposed to be italic, bold, etc? \i0 \ \b theFont \b0 =[Font \b newFont \b0 : \b "Courier" \b0 \b size \b0 : \b fontSize \b0 \b matrix \b0 : \b NX_FLIPPEDMATRIX \b0 ];\ \}\ return \b theFont; \b0 \ \}\ - \b registerTag \b0 :(const char *)tagType \b to \b0 : ( \b Font \b0 *)newFont \{\ return [eTDocInfo \b registerTag \b0 :tagType \b to \b0 :newFont];\}\ + \b registerTag \b0 :(const char *)tagType \b to \b0 : ( \b Font \b0 *)newFont \{\ char \b tagName \b0 [MAXPATHLEN];\ char \b tagSize \b0 [MAXPATHLEN];\ char \b fontSize \b0 [MAXPATHLEN];\ \ sprintf( \b tagName \b0 , " \b %s%s \b0 ", \b tagType \b0 , \b TAGNAME \b0 );\ sprintf( \b tagSize \b0 , " \b %s%s \b0 ", \b tagType \b0 , \b TAGSIZE \b0 );\ sprintf( \b fontSize \b0 , " \b %f \b0 ", [newFont \b pointSize \b0 ]);\ [ \b userModel \b0 \b bindKey \b0 :tagName \b to \b0 :[ \b newFont \b0 \b name \b0 ]];\ [ \b userModel \b0 \b bindKey \b0 :tagSize \b to \b0 : \b fontSize \b0 ];\ return self;\ \}\ - \b defaultTagFont \b0 :(const char *)tagType \{\ return [eTDocInfo \b defaultTagFont \b0 :tagType];\}\ + \b defaultTagFont \b0 :(const char *)tagType \{\ char \b tagName \b0 [MAXPATHLEN];\ char \b tagSize \b0 [MAXPATHLEN];\ const char * \b fontName \b0 ;\ const char * \b fontSizeStr \b0 ;\ float \b fontSize \b0 ;\ id \b theFont \b0 ;\ \ \ sprintf( \b tagName \b0 , " \b %s%s \b0 ", \b tagType \b0 , \b TAGNAME \b0 );\ sprintf( \b tagSize \b0 , " \b %s%s \b0 ", \b tagType \b0 , \b TAGSIZE \b0 );\ fontName = [ \b userModel \b0 stringQuery: \b tagName \b0 ];\ fontSizeStr = [ \b userModel \b0 stringQuery: \b tagSize \b0 ];\ \b sscanf \b0 (fontSizeStr,"%f",& \b fontSize \b0 );\ \b theFont \b0 = [Font \b newFont \b0 : \b fontName \b0 \b size \b0 : \b fontSize \b0 \b matrix \b0 : \b NX_FLIPPEDMATRIX \b0 ];\ if ( \b !theFont \b0 ) \{\ if (!errTab) \{errTab = [[HashTable alloc] initKeyDesc:"%"];\}\ if (![errTab isKey:fontName])\{\ \b NXLogError \b0 ("Can't find %s font for the %s default!", \b fontName \b0 , \b tagType \b0 );\ [errTab insertKey:fontName value:nil];\ \}\ // \i Can we figure out if the fonts were supposed to be italic, bold, etc? \i0 \ \b theFont \b0 =[Font \b newFont \b0 : \b "Courier" \b0 \b size \b0 : \b fontSize \b0 \b matrix \b0 : \b NX_FLIPPEDMATRIX \b0 ];\ \}\ return \b theFont; \b0 \ \}\ \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Alternate Formats \b0 \ //\ - \b writeHTMLHeader \b0 :( \b NXStream \b0 *)s // \i required \i0 \ \{\ char tmp[MAXPATHLEN];\ long aDocID;\ id theDocInfo;\ id docInfoList;\ NXAtom peers;\ int i;\ \ NXPrintf(s,"< \b HEAD \b0 >\\n< \b TITLE \b0 >% \b v \b0 </ \b TITLE \b0 >\\n",[self \b docTitle \b0 ]);\ \ strcpy( \b tmp \b0 , [self \b parent \b0 ]);\ \b sscanf \b0 (tmp, "%x", & \b aDocID \b0 );\ \b theDocInfo \b0 = [ \b docInfoTable \b0 valueForKey: \b aDocID \b0 ];\ if ( \b theDocInfo \b0 ) \{\ strcpy( \b tmp \b0 , [theDocInfo \b docPath \b0 ]);\ *rindex(tmp,' \b . \b0 ')= \b 0 \b0 ;\ NXPrintf(s,"< \b LINK HREF \b0 =\\"../% \b V. \b0 " \b\fc1\cf1 HTMD_EXT \b0\fc0\cf0 " \b /"HTML_INDEX" \b0 \\" \b REL \b0 =\\" \b Parent \b0 \\" \b TITLE \b0 =\\"% \b v \b0 \\">\\n", \b rindex \b0 (tmp,' \b / \b0 ')+1,[theDocInfo \b docTitle \b0 ]);\ \}\ \ docInfoList = [[NXApp \b navigator \b0 ] \b query \b0 :[self \b docIDStr \b0 ] \b field \b0 : \b PARENT \b0 ];\ i = [docInfoList count];\ for (;i;i--) \{\ strcpy( \b tmp \b0 , [[ \b docInfoList \b0 objectAt:(i-1)] \b docPath \b0 ]);\ *rindex(tmp,'.')=0;\ NXPrintf(s,"< \b LINK HREF \b0 =\\"../ \b %V. \b0 " \b\fc1\cf1 HTMD_EXT \b0\fc0\cf0 " \b /"HTML_INDEX" \b0 \\" REL=\\" \b Child \b0 \\" \b TITLE \b0 =\\"% \b v \b0 \\">\\n", rindex(tmp,'/')+1,[[ \b docInfoList \b0 objectAt:(i-1)] \b docTitle] \b0 );\ \}\ \ // if ([self \b parent \b0 ] != \b NXUniqueString \b0 ( \b "" \b0 )) \{\ docInfoList = [[NXApp \b navigator \b0 ] \b query \b0 :[self \b parent \b0 ] \b field \b0 : \b PARENT \b0 ];\ i = [docInfoList count];\ for (;i;i--) \{\ if ([ \b docInfoList \b0 objectAt:(i-1)] != \b self \b0 ) \{\ strcpy( \b tmp \b0 , [[ \b docInfoList \b0 objectAt:(i-1)] \b docPath \b0 ]);\ *rindex(tmp,'.')=0;\ NXPrintf(s,"< \b LINK HREF \b0 =\\"../ \b %V. \b0 " \b\fc1\cf1 HTMD_EXT \b0\fc0\cf0 " \b /"HTML_INDEX" \b0 \\" REL=\\" \b Sibling \b0 \\" \b TITLE \b0 =\\"% \b v \b0 \\">\\n", rindex(tmp,'/')+1,[[ \b docInfoList \b0 objectAt:(i-1)] \b docTitle] \b0 );\ \}\ \}\ // \}\ \ // \i continue for "peer" documents \i0 \ // \i for peers, we get a list of doc IDs that are space-separated \i0 \ i=0; \b peers \b0 = [self peers];\ \b while \b0 (peers[i] && (1 == \b sscanf \b0 (peers+i," \b %x \b0 ",& \b aDocID \b0 ))) \{\ theDocInfo = [ \b docInfoTable \b0 valueForKey: \b docID \b0 ];\ if ( \b theDocInfo \b0 ) \{\ \b strcpy \b0 (tmp, [theDocInfo \b docPath \b0 ]);\ *rindex(tmp,'.')=0;\ NXPrintf(s,"< \b LINK HREF \b0 =\\"../% \b V. \b0 " \b\fc1\cf1 HTMD_EXT \b0\fc0\cf0 " \b /"HTML_INDEX" \b0 \\" REL=\\" \b Peer \b0 \\" \b TITLE \b0 =\\"% \b v \b0 \\">\\n", rindex(tmp,'/')+1,[theDocInfo \b docTitle] \b0 );\ \}\ while(peers[i] && (peers[i] != ' ')) \b i++ \b0 ; // \i skip ahead \i0 \ while(peers[i] == ' ') \b i++ \b0 ; // \i skip ahead \i0 \ \}\ \ NXPrintf(s," \b </HEAD> \b0 \\n");\ return self;\ \}\ \ - \b writeHTMLTrailer \b0 :( \b NXStream \b0 *)s // \i optional; user-preference \i0 \ \{\ char tmp[MAXPATHLEN];\ long aDocID;\ id theDocInfo;\ id docInfoList;\ NXAtom peers;\ int i;\ \ // \i we should try to check the user's preferences here \i0 \ if ( \b ![self emitTrailer] \b0 ) \b return \b0 self;\ \ // \i write HR, then parent, peers, then author, date, then\ \i0 NXPrintf(s,"\\n\\n \b <!-- TRAILER --> \b0 \\n< \b HR \b0 >\\n< \b DL COMPACT \b0 >\\n");\ \ \b sscanf \b0 (tmp, "%x", & \b aDocID \b0 );\ \b theDocInfo \b0 = [ \b docInfoTable \b0 valueForKey: \b aDocID \b0 ];\ if ( \b theDocInfo \b0 ) \{\ strcpy( \b tmp \b0 , [theDocInfo \b docPath \b0 ]);\ *rindex(tmp,' \b . \b0 ')= \b 0 \b0 ;\ NXPrintf(s,"\\n \b <DT>Go Up (Parent):</DT> \b0 \\n \b <DD>[<A HREF \b0 =\\"../% \b V. \b0 " \b\fc1\cf1 HTMD_EXT \b0\fc0\cf0 " \b /"HTML_INDEX" \b0 \\">%v< \b /A \b0 > \b ] \b0 \\n", \b rindex \b0 (tmp,' \b / \b0 ')+1,[theDocInfo \b docTitle] \b0 );\ \}\ \ docInfoList = [[NXApp \b navigator \b0 ] \b query \b0 :[self \b docIDStr \b0 ] \b field \b0 : \b PARENT \b0 ];\ i = [docInfoList count];\ if( \b i \b0 ) NXPrintf(s,"\\n< \b DT \b0 > \b For More Details (Children): \b0 < \b /DT \b0 >< \b DD \b0 >\\n");;\ for (;i;i--) \{\ strcpy( \b tmp \b0 , [[ \b docInfoList \b0 objectAt:(i-1)] \b docPath \b0 ]);\ *rindex(tmp,'.')=0;\ NXPrintf(s,"\\n \b [ \b0 < \b A HREF \b0 =\\"../% \b V. \b0 " \b\fc1\cf1 HTMD_EXT \b0\fc0\cf0 " \b /"HTML_INDEX" \b0 \\">%v< \b /A \b0 > \b ] \b0 \\n", rindex(tmp,'/')+1,[[ \b docInfoList \b0 objectAt:(i-1)] \b docTitle] \b0 );\ \}\ \ // \i for peers, we get a list of doc IDs that are space-separated \i0 \ i=0; \b peers \b0 = [self peers];\ if( \b strlen \b0 ( \b peers \b0 )) NXPrintf(s,"\\n< \b DT \b0 > \b See Also (Peers): \b0 < \b /DT \b0 >< \b DD \b0 >\\n");;\ \b while \b0 (peers[i] && (1 == \b sscanf \b0 (peers+i," \b %x \b0 ",& \b aDocID \b0 ))) \{\ theDocInfo = [ \b docInfoTable \b0 valueForKey: \b aDocID \b0 ];\ if ( \b theDocInfo \b0 ) \{\ \b strcpy \b0 (tmp, [theDocInfo \b docPath \b0 ]);\ *rindex(tmp,'.')=0;\ NXPrintf(s,"\\n \b [ \b0 < \b A HREF \b0 =\\"../% \b V. \b0 " \b\fc1\cf1 HTMD_EXT \b0\fc0\cf0 " \b /"HTML_INDEX" \b0 \\">%v< \b /A \b0 > \b ] \b0 \\n", \b rindex \b0 (tmp,' \b / \b0 ')+1,[theDocInfo \b docTitle] \b0 );\ \}\ while(peers[i] && (peers[i] != ' ')) \b i++ \b0 ; // \i skip ahead \i0 \ while(peers[i] == ' ') \b i++ \b0 ; // \i skip ahead \i0 \ \}\ \ // if ([self \b parent \b0 ] != \b NXUniqueString \b0 ( \b "" \b0 )) \{\ docInfoList = [[NXApp \b navigator \b0 ] \b query \b0 :[self \b parent \b0 ] \b field \b0 : \b PARENT \b0 ];\ i = [docInfoList count];\ if( \b i > 1 \b0 ) NXPrintf(s,"\\n< \b DT \b0 > \b See Also (Siblings): \b0 < \b /DT \b0 >< \b DD \b0 >\\n");;\ for (;i;i--) \{\ if ([ \b docInfoList \b0 objectAt:(i-1)] != \b self \b0 ) \{\ strcpy( \b tmp \b0 , [[ \b docInfoList \b0 objectAt:(i-1)] \b docPath \b0 ]);\ *rindex(tmp,'.')=0;\ NXPrintf(s,"\\n \b [ \b0 < \b A HREF \b0 =\\"../% \b V. \b0 " \b\fc1\cf1 HTMD_EXT \b0\fc0\cf0 " \b /"HTML_INDEX " \b0 \\">%v< \b /A \b0 > \b ] \b0 \\n", rindex(tmp,'/')+1,[[ \b docInfoList \b0 objectAt:(i-1)] \b docTitle] \b0 );\ \}\ \}\ // \}\ NXPrintf(s," \b </DL> \b0 \\n");\ \ // 12/2 commented out per ernie's request && shortened\ NXPrintf(s,"< \b HR \b0 >< \b ADDRESS \b0 >< \b A HREF \b0 =\\" \b %V \b0 \\"> \b %v \b0 < \b /A \b0 > was converted on \b %v \b0 by < \b A HREF \b0 =\\" \b http://www.etext.caltech.edu/eTextEngine/ \b0 \\">the <I> \i eText Engine \i0 </I>, version 5, release % \b v \b0 < \b /A \b0 >< \b /ADDRESS \b0 >\\n", \b DOCINFOFILE, \b0 [self \b docTitle \b0 ], [NXApp \b date \b0 ], [NXApp \b versionStr \b0 ]);\ return self;\ \}\ \ - \b writeLaTeXHeader \b0 :( \b NXStream \b0 *)s\ \{ \ NXPrintf(s, "\\n\\\\ \b author \b0 \{%w\}\\n\\\\ \b title \b0 \{%w\}\\n\\\\ \b maketitle \b0 \\n",[self \b author \b0 ], [self \b docTitle \b0 ]);\ return self;\ \}\ \ \i @end\ \ \i0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Draw-specific Extensions \b0 \ // \i \ @implementation eTDocInfo(eDraw)\ \ \i0 // \i eventually, indexing information for Draw type documents goes here.\ \ @end }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.