home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UDiscussion.cp < prev    next >
Encoding:
Text File  |  1994-03-14  |  11.2 KB  |  420 lines  |  [TEXT/MPS ]

  1. // Copyright © 1992 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // UDiscussion.cp
  3.  
  4. #include "UDiscussion.h"
  5. #include "Tools.h"
  6.  
  7. #ifndef __OSUTILS__
  8. #include <OSUtils.h>
  9. #endif
  10.  
  11. #pragma segment MyGroup
  12.  
  13. #define qIntenseDebugDisc 0
  14. #define qDebugExpandTableEntry qDebug & 0
  15.  
  16. /*
  17.  
  18. The format of the entries in PDiscList's list is as follows:
  19.  
  20.     +==================+
  21.     | CDiscussion      |
  22.     +------------------+
  23.     | msg-ID           |
  24.     +------------------+
  25.     | name             |
  26.     +------------------+
  27.     | article id's     |
  28.     +==================+
  29.  
  30. CDiscussion manages all this!
  31. */
  32.  
  33. void CDiscussion::Initialize(short initialTableSize, short hash)
  34. {
  35.     fLink = 0xCFC;
  36.     GetDateTime(fCreateDateTime);
  37.     fLastActiveDateTime = fCreateDateTime;
  38.     fHash = hash;
  39.     fNoArticles = 0;
  40.     fTableBytesAlloc = initialTableSize;
  41.     fTable[kMsgID].fOffset = sizeof(CDiscussion);
  42.     fTable[kMsgID].fLength = 0;
  43.     fTable[kMsgID].fUsedLength = 0;
  44.     fTable[kName].fOffset = sizeof(CDiscussion);
  45.     fTable[kName].fLength = 0;
  46.     fTable[kName].fUsedLength = 0;
  47.     fTable[kIDTable].fOffset = sizeof(CDiscussion);
  48.     fTable[kIDTable].fLength = 0;
  49.     fTable[kIDTable].fUsedLength = 0;
  50. #if qDebug
  51.     fTable[kMsgID].fFiller = 0;
  52.     fTable[kName].fFiller = 0;
  53.     fTable[kIDTable].fFiller = 0;
  54. #endif
  55. #if qDebugCDiscussion
  56.     fprintf(stderr, "CDiscussion initialized with %hd bytes tablespace\n", initialTableSize);
  57. #endif
  58. #if qIntenseDebugDisc
  59.     fprintf(stderr, "After CDiscussion::Initialize():\n");
  60.     Dump(stderr);
  61. #endif
  62. #if qDebug
  63.     SanityCheck(-1);
  64. #endif
  65. }
  66.  
  67. inline short MakeEven(short x)
  68. {
  69.     return (x + 1) & ~1;
  70. }
  71.  
  72. short CDiscussion::ExpandTableEntry(TableType table, short newUsedSize)
  73. {
  74. #if qDebug
  75. #if qDebugExpandTableEntry
  76.     SanityCheck(-1);
  77. #endif
  78.     if (newUsedSize < 0 || newUsedSize > 300)
  79.     {
  80.         fprintf(stderr, "Bad newUsedSize = %ld\n", newUsedSize);
  81.         ProgramBreak(gEmptyString);
  82.     }
  83. #endif
  84.     short newSize = MakeEven(newUsedSize);
  85.     if (newSize <= fTable[table].fLength)
  86.     {
  87.         fTable[table].fUsedLength = newUsedSize;
  88.         return 0;
  89.     }
  90. #if qDebugCDiscussion
  91.     if (fTable[table].fUsedLength)
  92.         fprintf(stderr, "CDiscussion table needs to grow from %hd to %hd bytes\n", fTable[table].fUsedLength, newUsedSize);
  93. #endif
  94.     short curSizeOfTables = fTable[kMsgID].fLength + fTable[kName].fLength + fTable[kIDTable].fLength;
  95.     short deltaSize = newSize - fTable[table].fLength;
  96. /*
  97. char sss[200];
  98. sprintf(sss, "fTableBytesAlloc = %hd, curSize = %hd, delta = %hd", fTableBytesAlloc, curSizeOfTables, deltaSize);
  99. DebugStr(sss);
  100. */
  101.     if (deltaSize <= 0)
  102.     {
  103. #if qDebug
  104.         ProgramBreak("deltaSize <= 0 (already checked for that!)");
  105. #endif
  106.         return 0; // don't ever want to compact!
  107.     }
  108.     if (curSizeOfTables + deltaSize > fTableBytesAlloc)
  109.     {
  110.         short needed = curSizeOfTables + deltaSize - fTableBytesAlloc;
  111. #if qIntenseDebugDisc
  112.         fprintf(stderr, "DID NOT have enough space for expansion, needed %hd bytes more (have %ld, tablesize: %ld)\n", needed, fTableBytesAlloc, curSizeOfTables);
  113.         if (needed < 0)
  114.         {
  115.             ProgramBreak("********* Needed < 0");
  116.             return 0;
  117.         }
  118. #endif
  119.         return needed;
  120.     }
  121.     if (table < kLastTable)
  122.     {
  123. // DebugStr("Moving tables to give space for this one");
  124.         short fromOffset = fTable[table + 1].fOffset;
  125.         short toOffset = fromOffset + deltaSize;
  126.         short moveSize = 0;
  127.         for (TableType index = TableType(table + 1); index <= kLastTable; index = TableType(index + 1))
  128.         {
  129.             moveSize += fTable[index].fLength;
  130.             fTable[index].fOffset += deltaSize;
  131.         }
  132.         Ptr p = Ptr(this);
  133.         MyBlockMove(p + fromOffset, p + toOffset, moveSize);
  134. #if qDebug
  135.         fTable[table].fLength = newSize; // must too here, otherwise SanityCheck says shit
  136.         SanityCheck(-1);
  137. #endif
  138.     }
  139.     fTable[table].fLength = newSize;
  140. #if qIntenseDebugDisc
  141.     fprintf(stderr, "After CDiscussion::ExpandTableEntry() that changed the tables:\n");
  142.     Dump(stderr);
  143. #endif
  144. #if qDebugExpandTableEntry
  145.     SanityCheck(-1);
  146. #endif
  147.     fTable[table].fUsedLength = newUsedSize;
  148.     return 0;
  149. }
  150.  
  151. short CDiscussion::SetNameFromHOL(HandleOffsetLength hol)
  152. {
  153.     short nameLen = short(hol.fLength);
  154. #if qDebug
  155.     if (nameLen < 0 || nameLen > 250)
  156.         ProgramBreak("Bad nameLen");
  157. #endif
  158.     short spaceNeeded = ExpandTableEntry(kName, nameLen);
  159.     if (spaceNeeded) 
  160.         return spaceNeeded;
  161.     Ptr p = Ptr(this) + fTable[kName].fOffset;
  162.     BytesMove(*hol.fH + hol.fOffset, p, nameLen);
  163. #if qIntenseDebugDisc
  164.     fprintf(stderr, "After CDiscussion::SetNameFromHOL():\n");
  165.     Dump(stderr);
  166. #endif
  167.     return 0;
  168. }
  169.  
  170. short CDiscussion::SetMsgIDFromHOL(HandleOffsetLength hol, short hash)
  171. {
  172. #if qDebug
  173.     if (hol.fLength < 0 || hol.fLength > 250)
  174.         ProgramBreak("Bad MsgID length");
  175. #endif
  176.     short spaceNeeded = ExpandTableEntry(kMsgID, short(hol.fLength));
  177.     if (spaceNeeded) 
  178.         return spaceNeeded;
  179.     Ptr p = Ptr(this) + fTable[kMsgID].fOffset;
  180.     BytesMove(*hol.fH + hol.fOffset, p, hol.fLength);
  181.     fHash = hash;
  182. #if qIntenseDebugDisc
  183.     fprintf(stderr, "After CDiscussion::SetMsgIDFromHOL():\n");
  184.     Dump(stderr);
  185. #endif
  186.     return 0;
  187. }
  188.  
  189. short CDiscussion::AddArticle(long id)
  190. {
  191.     short chunk = (fNoArticles + 8) & ~7; // chunk-size is 8 articles
  192.     short spaceNeeded = ExpandTableEntry(kIDTable, chunk * sizeof(long));
  193.     if (spaceNeeded) 
  194.         return spaceNeeded;
  195.  
  196.     Ptr p = Ptr(this) + fTable[kIDTable].fOffset;
  197.     long *lP = ( (long*) p ) + fNoArticles;
  198.     *lP = id;
  199.     fNoArticles++;
  200.     GetDateTime(fLastActiveDateTime);
  201. #if qIntenseDebugDisc
  202.     fprintf(stderr, "After CDiscussion::AddArticle():\n");
  203.     Dump(stderr);
  204. #endif
  205.     return 0;
  206. }
  207.  
  208. short CDiscussion::AddArticleAsOriginator(long id, 
  209.                     HandleOffsetLength msgIDHol, short hash, ArrayIndex link, HandleOffsetLength nameHol)
  210. {
  211.     short spaceNeeded = SetMsgIDFromHOL(msgIDHol, hash);
  212.     if (spaceNeeded) 
  213.         return spaceNeeded;
  214.  
  215.     spaceNeeded = SetNameFromHOL(nameHol);
  216.     if (spaceNeeded) 
  217.         return spaceNeeded;
  218.     
  219.     short chunk = (fNoArticles + 4) & ~3; // chunk-size is 4 articles
  220.     spaceNeeded = ExpandTableEntry(kIDTable, chunk * sizeof(long));
  221.     if (spaceNeeded) 
  222.         return spaceNeeded;
  223.  
  224.     Ptr p = Ptr(this) + fTable[kIDTable].fOffset;
  225.     MyBlockMove(p, p + sizeof(long), fNoArticles * sizeof(long));
  226.     // insert article as the first one
  227.     long *lP = (long*) p;
  228.     *lP = id;
  229.     fNoArticles++;
  230.     fLink = link;
  231.     GetDateTime(fLastActiveDateTime);
  232. #if qIntenseDebugDisc
  233.     fprintf(stderr, "After CDiscussion::AddArticleAsOriginator():\n");
  234.     Dump(stderr);
  235. #endif
  236.     return 0;
  237. }
  238.  
  239. void CDiscussion::GetName(CStr255 &name)
  240. {
  241. #if qDebug
  242.     if (fTable[kName].fUsedLength < 0 || fTable[kName].fUsedLength > 250)
  243.     {
  244.         Dump(stderr, -1);
  245.         ProgramBreak("Invalid name-length");
  246.     }
  247. #endif
  248.     name.Length() = fTable[kName].fUsedLength;
  249.     Ptr p = Ptr(this) + fTable[kName].fOffset;
  250.     BytesMove(p, &name[1], name.Length() + 1);
  251. }
  252.  
  253. short CDiscussion::GetNoArticles()
  254. {
  255.     return fNoArticles;
  256. }
  257.  
  258. TLongintList *CDiscussion::GetArticleIDList()
  259. {
  260.     TLongintList *list = nil;
  261.     VOLATILE(list);
  262.     FailInfo fi;
  263.     if (fi.Try())
  264.     {
  265.         TLongintList *aList = new TLongintList();
  266.         aList->ILongintList();
  267.         list = aList;
  268.         Ptr p = Ptr(this) + fTable[kIDTable].fOffset;
  269.         list->InsertElementsBefore(1, p, fNoArticles);
  270.         fi.Success();
  271.         return list;
  272.     }
  273.     else // fail
  274.     {
  275.         if (list) list->Free();
  276.         fi.ReSignal();
  277.     }
  278. }
  279.  
  280. long CDiscussion::GetArticleID(long articleIndex)
  281. {
  282.     Ptr p = Ptr(this) + fTable[kIDTable].fOffset;
  283.     long *lP = (long*) p;
  284.     return lP[articleIndex - 1];
  285. }
  286.  
  287. long CDiscussion::GetLastArticleID()
  288. {
  289.     Ptr p = Ptr(this) + fTable[kIDTable].fOffset;
  290.     long *lP = (long*) p;
  291.     return lP[fNoArticles - 1];
  292. }
  293.  
  294. Boolean CDiscussion::CompareMsgID(Ptr p, long len)
  295. {
  296.     if (len != fTable[kMsgID].fUsedLength)
  297.         return false;
  298.     register Ptr p1 = Ptr(this) + fTable[kMsgID].fOffset;
  299.     register Ptr p2 = p;
  300.     register long l = len;
  301.     while (l && *p1++ == *p2++) 
  302.         l--;
  303.     return l == 0;
  304. }
  305.  
  306. short CDiscussion::GetFreeSpace()
  307. {
  308.     return fTableBytesAlloc - (fTable[kMsgID].fLength + fTable[kName].fLength + fTable[kIDTable].fLength);
  309. }
  310.  
  311. void CDiscussion::Dump(FILE *file, long index)
  312. {
  313. #if qDebug
  314.     short freeSpace = GetFreeSpace();
  315.     DateTimeRec creat, active;
  316.     Secs2Date(fCreateDateTime, creat);
  317.     Secs2Date(fLastActiveDateTime, active);
  318.  
  319.     fprintf(file, "CDiscussion at $%lx with index = %ld\n", long(this), index);
  320.     fprintf(file, "  fLink = %ld, fHash = %hd\n", long(fLink), fHash);
  321.     fprintf(file, "  fCreateDateTime     = %hd/%hd-%hd, %hd:%hd:%hd\n", creat.day, creat.month, creat.year, creat.hour, creat.minute, creat.second);
  322.     fprintf(file, "  fLastActiveDateTime = %hd/%hd-%hd, %hd:%hd:%hd\n", active.day, active.month, active.year, active.hour, active.minute, active.second);
  323.     fprintf(file, "  fNoArticle = %hd\n", fNoArticles);
  324.     fprintf(file, "  fTableBytesAlloc = %hd, freeSpace = %hd\n", fTableBytesAlloc, freeSpace);
  325.     fprintf(file, "  kMsgID:   %hd, %hd, %hd  (offset, length, usedLength)\n", 
  326.                                     fTable[kMsgID].fOffset, fTable[kMsgID].fLength, fTable[kMsgID].fUsedLength);
  327.     fprintf(file, "  kName:    %hd, %hd, %hd\n", fTable[kName].fOffset, fTable[kName].fLength, fTable[kName].fUsedLength);
  328.     fprintf(file, "  kIDTable: %hd, %hd, %hd\n", fTable[kIDTable].fOffset, fTable[kIDTable].fLength, fTable[kIDTable].fUsedLength);
  329.     fprintf(file, "  msg-ID: ");
  330.     Ptr p;
  331.     p = Ptr(this) + fTable[kMsgID].fOffset;
  332.     fwrite(p, 1, int(MinMax(0, fTable[kMsgID].fUsedLength, 200)), file);
  333.     fprintf(file, "\n");
  334.     fprintf(file, "  name: ");
  335.     p = Ptr(this) + fTable[kName].fOffset;
  336.     fwrite(p, 1, int(MinMax(0, fTable[kName].fUsedLength, 200)), file);
  337.     fprintf(file, "\n");
  338.     fprintf(file, "  ID's: ");
  339.     p = Ptr(this) + fTable[kIDTable].fOffset;
  340.     long *lP = (long*) p;
  341.     for (short i = 1; i <= fNoArticles; i++)
  342.         fprintf(file, "%6hd", *lP++);
  343.     fprintf(file, "\n\n");
  344. #else
  345.     file = file;
  346.     index = index;
  347. #endif
  348. }
  349.  
  350. Boolean macroValidChar(char ch)
  351. {
  352.     return ch >= 32 || ch == 9 || ch < 0;
  353. }
  354.  
  355. Boolean CDiscussion::SanityCheck(long index)
  356. {
  357.     Boolean isGood = true;
  358. #if qDebug
  359.     if (fTable[kMsgID].fOffset != sizeof(CDiscussion))
  360.     {
  361.         fprintf(stderr, "WRONG: CDiscussion::SanityCheck, found invalid message-ID offset in CDiscussion\n");
  362.         isGood = false;
  363.     }
  364.     if (fTable[kName].fOffset != fTable[kMsgID].fOffset + fTable[kMsgID].fLength)
  365.     {
  366.         fprintf(stderr, "WRONG: CDiscussion::SanityCheck, found invalid disc-name offset in CDiscussion\n");
  367.         isGood = false;
  368.     }
  369.     if (fTable[kIDTable].fOffset != fTable[kName].fOffset + fTable[kName].fLength)
  370.     {
  371.         fprintf(stderr, "WRONG: CDiscussion::SanityCheck, found invalid ID-list offset in CDiscussion\n");
  372.         isGood = false;
  373.     }
  374.     Ptr p;
  375.     short i;
  376.     p = Ptr(this) + fTable[kName].fOffset;
  377.     if (long(p) & 1)
  378.         fprintf(stderr, "WRONG: CDiscussion::SanityCheck, article name at odd address\n");
  379.     for (i = fTable[kName].fUsedLength; i; i--, p++)
  380.     {
  381.         if (!macroValidChar(*p))
  382.         { 
  383.             fprintf(stderr, "WRONG: CDiscussion::SanityCheck, found invalid char %c = %ld in name\n", *p, long(*p)); 
  384.             isGood = false;
  385.         }
  386.     }
  387.     p = Ptr(this) + fTable[kMsgID].fOffset;
  388.     if (long(p) & 1)
  389.         fprintf(stderr, "WRONG: CDiscussion::SanityCheck, article message-ID at odd address\n");
  390.     for (i = fTable[kMsgID].fUsedLength; i; i--, p++)
  391.     {
  392.         if (!macroValidChar(*p))
  393.         {
  394.             fprintf(stderr, "WRONG: CDiscussion::SanityCheck, found invalid char  %c = %ld in MsgID\n", *p, long(*p)); 
  395.             isGood = false;
  396.         }
  397.     }
  398.     p = Ptr(this) + fTable[kIDTable].fOffset;
  399.     if (long(p) & 1)
  400.         fprintf(stderr, "WRONG: CDiscussion::SanityCheck, article ID at odd address\n");
  401.     long *lP = (long*) p;
  402.     for (i = 1; i <= fNoArticles; i++, lP++)
  403.     {
  404.         if (*lP <= 0 || *lP >= 90000)
  405.         { 
  406.             fprintf(stderr, "WRONG: CDiscussion::SanityCheck, found invalid article id\n"); 
  407.             isGood = false;
  408.         }
  409.     }
  410.     if (!isGood)
  411.     {
  412.         Dump(stderr, index);
  413.         ProgramBreak("CDiscussion was BAD");
  414.     }
  415. #else
  416.     index = index;
  417. #endif
  418.     return isGood;
  419. }
  420.