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.