📄 htndir.c
字号:
/* HTNDir.c** GENERIC NEWS LISTINGS**** (c) COPYRIGHT MIT 1995.** Please first read the full copyright statement in the file COPYRIGH.** @(#) $Id: HTNDir.c,v 2.12 1999/02/22 22:10:11 frystyk Exp $**** Creates listings for all kind of News output.**** Authors:** HF Henrik Frystyk, MIT, <frystyk@w3.org>** MP Maciej Puzio <puzio@zodiac1.mimuw.edu.pl>** History:** Oct 95 HFN written** Mar 96 MP modified heavily *//* Library include files */#include "wwwsys.h"#include "WWWUtil.h"#include "WWWCore.h"#include "WWWHTML.h"#include "HTNews.h"#include "HTNewsLs.h"#include "HTNDir.h" /* Implemented here *//* Macros and other defines */#define PUTC(c) (*target->isa->put_character)(target, c)#define PUTS(s) (*target->isa->put_string)(target, s)#define START(e) (*target->isa->start_element)(target, e, 0, 0)#define END(e) (*target->isa->end_element)(target, e)#define FREE_TARGET (*target->isa->_free)(target)#define DEFAULT_MAXW 80 /* Default line width *//* Type definitions and global variables etc. local to this module */struct _HTStructured { const HTStructuredClass * isa; /* ... */};struct _HTNewsNode { int index; char * name; char * subject; char * from; time_t date; int refs; /* Number of references */ BOOL is_tmplate; /* Added by MP: */ HTList* refNames; /* referee names list */ HTList* refObjects; /* referee objects list */ HTNewsNode * refParent; /* direct parent (referee) */ HTNewsNode * lastChild; /* last child (referer) */ BOOL show; /* show this node on the list? */ BOOL fake; /* create anchor with this node? */ int refChildren; /* number of referers */ int refLevel; /* reference level - to speed sorting */ int minRefIndex; /* minimal index in reference subtree */ int maxRefIndex; /* maximal index in reference subtree */ time_t minRefDate; /* minimal date in reference subtree */ time_t maxRefDate; /* maximal date in reference subtree */};struct _HTNewsDir { HTStructured * target; HTRequest * request; HTNewsDirKey key; /* Key for sorting */ char * name; /* Name of the newsgroup(s) Added by MP */ char * tmplate; HTNewsNode * tmplate_node; int lastLevel; /* Last printed ref level Added by MP. */ HTArray * array; /* Array for sorted listings */ HTArray * cache; /* Only created on request */};PRIVATE int MaxLineW = DEFAULT_MAXW;/* Forward references - added by MP. */PRIVATE void HTNewsDir_addLevelTags (HTNewsDir* dir, int level);PRIVATE HTNewsNode* HTNewsDir_addFakeElement (HTNewsDir* dir, char* subject, char* name);PRIVATE HTNewsNode* HTNewsDir_findNodeNamed (HTNewsDir* dir, char* name);#define FNWS_ANY 0x0000/* Date */#define FNWS_MIN 0x0001#define FNWS_MAX 0x0002/* Fake/not-fake */#define FNWS_ONLYFAKE 0x0010#define FNWS_NOTFAKE 0x0020/* Fake or not-fake with references */#define FNWS_NOTORPHAN 0x0040PRIVATE HTNewsNode* HTNewsDir_findNodeWithSubject (HTNewsDir* dir, char* subject, int which, HTNewsNode* avoidNode);/* ------------------------------------------------------------------------- *//* NODE MANAGEMENT *//* ------------------------------------------------------------------------- */PRIVATE HTNewsNode * HTNewsNode_new (int index, char * subject, char * from, time_t date, char * name, int refs, HTList * refNames){ HTNewsNode * node; if ((node = (HTNewsNode *) HT_CALLOC(1, sizeof(HTNewsNode))) == NULL) HT_OUTOFMEM("HTNewsNode_new"); if (name) StrAllocCopy(node->name, name); if (subject) { StrAllocCopy(node->subject, subject); node->subject = HTStrip(node->subject); } if (from) StrAllocCopy(node->from, from); node->index = index; node->date = date; node->refs = refs; node->refNames = refNames; node->show = (name != NULL); node->fake = (name == NULL); node->minRefIndex = index; node->maxRefIndex = index; node->minRefDate = date; node->maxRefDate = date; return node;}PRIVATE BOOL HTNewsNode_delete (HTNewsNode * node, BOOL cache){ if (node) { if (!cache || node->is_tmplate) HT_FREE(node->name); HT_FREE(node->subject); HT_FREE(node->from); if (node->refNames) { HTList * cur = node->refNames; char * pres; while ((pres = (char *) HTList_nextObject(cur))) HT_FREE(pres); HTList_delete(node->refNames); } if (node->refObjects) HTList_delete(node->refObjects); HT_FREE(node); return YES; } return NO;}/* Added by MP. */PRIVATE BOOL HTNewsNode_isAncestor (HTNewsNode* node, HTNewsNode* refered){ HTNewsNode* p; for (p = refered; p; p = p->refParent) if (p == node) return YES; return NO;}/* Added by MP. */PRIVATE BOOL HTNewsNode_linkRef (HTNewsNode* node, HTNewsNode* referer){ if (node && referer) { node->refChildren++; node->lastChild = referer; node->minRefIndex = (node->minRefIndex != 0 ? HTMIN(node->minRefIndex, referer->index) : referer->index); node->maxRefIndex = (node->maxRefIndex != 0 ? HTMAX(node->maxRefIndex, referer->index) : referer->index); node->minRefDate = (node->minRefDate != 0 ? HTMIN(node->minRefDate, referer->date) : referer->date); node->maxRefDate = (node->maxRefDate != 0 ? HTMAX(node->maxRefDate, referer->date) : referer->date); referer->refParent = node; return YES; } return NO;}/* Added by MP. */PRIVATE int HTNewsNode_refLevel (HTNewsNode* node){ int cnt = 0; HTNewsNode* p; for (p = node->refParent; p && p->show; p = p->refParent) cnt++; return cnt;}/* Added by MP. *//* Returns index field for non-fake nodes, minimal or maximal subtreee *//* index for fake nodes. */PRIVATE time_t HTNewsNode_getIndex (HTNewsNode* node, BOOL minimal){ if (node->index != 0) return node->index; else if (minimal) return node->minRefIndex; else return node->maxRefIndex;}/* Added by MP. *//* Returns date field for non-fake nodes, minimal or maximal subtreee *//* date for fake nodes. */PRIVATE time_t HTNewsNode_getDate (HTNewsNode* node, BOOL minimal){ if (node->date != 0) return node->date; else if (minimal) return node->minRefDate; else return node->maxRefDate;}/* Helper function - added by MP. */PRIVATE char* UnReSubject (char* subject){ if (strlen(subject) >= 3 && strncasecomp(subject, "re:", 3) == 0) { char* p = subject + 3; /* "Re:XXX" */ if (*p == ' ') p ++; /* "Re: XXX" */ return p; } return subject;}/* Added by MP. */PRIVATE void HTNewsNode_setRefInfo_pass1 (HTNewsDir* dir, HTNewsNode* node){ HTList* ptr = node->refNames; char* name = NULL; if (node->fake) return; if (ptr != NULL) name = (char*) HTList_nextObject(ptr); while (ptr != NULL) { HTNewsNode* parent; parent = HTNewsDir_findNodeNamed(dir, name); if (parent) { if (!node->refObjects) node->refObjects = HTList_new(); HTList_addObject (node->refObjects, parent); } name = (char*) HTList_nextObject(ptr); }}/* Added by MP. */PRIVATE void HTNewsNode_setRefInfo_pass2 (HTNewsDir* dir, HTNewsNode* node){ HTNewsNode* maxParent = NULL; HTList* ptr = node->refObjects; HTNewsNode* parent = NULL; if (node->fake) return; if (ptr != NULL) parent = (HTNewsNode*) HTList_nextObject(ptr); while (ptr != NULL) { if (!maxParent || maxParent->date < parent->date) maxParent = parent; parent = (HTNewsNode*) HTList_nextObject(ptr); } if (maxParent) { if (!HTNewsNode_isAncestor(node, maxParent)) /* better be careful */ HTNewsNode_linkRef (maxParent, node); } else { char* refSubject; BOOL re; /* Here is the only place we REALLY have to check for circular */ /* references. It is normally possible that a node refers to */ /* orphan node and both have the same subject. In this situation */ /* we can't make the orphan to refer to it's child. Without checking */ /* for circular references this is likely to happen here. */ refSubject = UnReSubject(node->subject); re = (strcasecomp(refSubject, node->subject) != 0); if (re) parent = HTNewsDir_findNodeWithSubject(dir, refSubject, FNWS_MIN | FNWS_NOTFAKE, node); if (!parent || HTNewsNode_isAncestor(node, parent)) parent = HTNewsDir_findNodeWithSubject(dir, refSubject, FNWS_MIN | FNWS_ONLYFAKE, node); if (!parent && re) { parent = HTNewsDir_findNodeWithSubject(dir, node->subject, FNWS_MIN | FNWS_ONLYFAKE, node); } if (!parent) parent = HTNewsDir_addFakeElement (dir, refSubject, NULL); if (parent) { HTNewsNode_linkRef (parent, node); if (parent->refChildren > 1) /* Multi-children fake node visible */ parent->show = YES; } }}/*** Added by MP.*/#if 0PRIVATE void HTNewsNode_setRefInfo_pass3 (HTNewsDir* dir, HTNewsNode* node){ HTNewsNode* parent = NULL; char* refSubject; BOOL re; if (node->fake || node->refParent) return; /* This is only for nodes not handled in pass 2 */ /* Here is the only place we REALLY have to check for circular */ /* references. It is normally possible that a node refers to */ /* orphan node and both have the same subject. In this situation */ /* we can't make the orphan to refer to it's child. Without checking */ /* for circular references this is likely to happen here. */ refSubject = UnReSubject(node->subject); re = (strcasecomp(refSubject, node->subject) != 0); if (re) parent = HTNewsDir_findNodeWithSubject(dir, refSubject, FNWS_MIN | FNWS_NOTFAKE, node); if (!parent || HTNewsNode_isAncestor(node, parent)) parent = HTNewsDir_findNodeWithSubject(dir, refSubject, FNWS_MIN | FNWS_ONLYFAKE, node); if (!parent && re) { parent = HTNewsDir_findNodeWithSubject(dir, node->subject, FNWS_MIN | FNWS_ONLYFAKE, node); } if (!parent) parent = HTNewsDir_addFakeElement (dir, refSubject, NULL); if (parent) { HTNewsNode_linkRef (parent, node); if (parent->refChildren > 1) /* multi-children fake node visible */ parent->show = YES; }}#elsePRIVATE void HTNewsNode_setRefInfo_pass3 (HTNewsDir* dir, HTNewsNode* node){ if (!node->fake) node->refLevel = HTNewsNode_refLevel(node);}#endif/* Added by MP. */PRIVATE int HTNewsNode_compareRefThread (HTNewsNode* node1, HTNewsNode* node2){ int level1 = node1->refLevel; int level2 = node2->refLevel; int level = HTMAX(level1, level2); int i; HTNewsNode* parent1; HTNewsNode* parent2; int diff = 0; for (i = level; i >= 0; i--) { parent1 = (i < level1 ? parent1->refParent : node1); parent2 = (i < level2 ? parent2->refParent : node2); if (parent1 == parent2) return diff; /* related messages (in same subtree) */ else { time_t date1 = (i > level1 ? 0 : HTNewsNode_getDate(parent1, YES)); time_t date2 = (i > level2 ? 0 : HTNewsNode_getDate(parent2, YES)); diff = date1 - date2; if (diff == 0) { int idx1 = (i > level1 ? 0 : HTNewsNode_getIndex(parent1, YES)); int idx2 = (i > level2 ? 0 : HTNewsNode_getIndex(parent2, YES)); diff = idx1 - idx2; } } } return diff; /* completely unrelated messages */}/*** Output an element in HTML** Returns YES if OK, else NO*/PRIVATE BOOL HTNewsNode_print (HTNewsDir * dir, HTNewsNode * node){ if (node && node->show) { HTStructured *target = dir->target; char * escaped; HTNewsDir_addLevelTags (dir, node->refLevel); /* Added by MP. */ START(HTML_LI); /* Start the anchor and put the subject as anchor text */ /* Changed by MP to allow nodes without names */ if (!node->fake && node->name && node->subject) { escaped = HTEscape(node->name, URL_XPALPHAS); HTStartAnchor(target, NULL, escaped); } if (node->subject) PUTS(node->subject); if (!node->fake && node->name && node->subject) { END(HTML_A); HT_FREE(escaped); } /* From field */ if (node->from) { PUTS (" by "); /* Changed by MP. */ PUTS(node->from); } /* In group listing, put number of groups in the set; added by MP. */ if (node->name && strrchr(node->name, '*')) { char buf[16]; sprintf (buf, " (%d groups)", node->refChildren); PUTS (buf); } } return YES;}/* ------------------------------------------------------------------------- *//* DIRECTORY MANAGEMENT *//* ------------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -