home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tv20os2.zip / src / helpbase.cpp < prev    next >
C/C++ Source or Header  |  1999-05-19  |  14KB  |  676 lines

  1. /*
  2.  * helpbase.cc
  3.  *
  4.  * Turbo Vision - Version 2.0
  5.  *
  6.  * Copyright (c) 1994 by Borland International
  7.  * All Rights Reserved.
  8.  *
  9.  * Modified by Sergio Sigala <ssigala@globalnet.it>
  10.  */
  11.  
  12. #define Uses_TStreamableClass
  13. #define Uses_TPoint
  14. #define Uses_TStreamable
  15. #define Uses_ipstream
  16. #define Uses_opstream
  17. #define Uses_fpstream
  18. #define Uses_TRect
  19. #include <tvision/tv.h>
  20.  
  21. #if !defined( __HELP_H )
  22. #include "tvision/helpbase.h"
  23. #endif  // __HELP_H
  24.  
  25. #if !defined( __UTIL_H )
  26. #include "tvision/util.h"
  27. #endif  // __UTIL_H
  28.  
  29. #include <ctype.h>
  30. #include <limits.h>
  31. #include <string.h>
  32. #include <sys/stat.h>
  33. #include <io.h>
  34.  
  35. TCrossRefHandler crossRefHandler = notAssigned;
  36.  
  37. // THelpTopic
  38.  
  39. const char * const THelpTopic::name = "THelpTopic";
  40.  
  41. void THelpTopic::write( opstream& os )
  42. {
  43.     writeParagraphs( os );
  44.     writeCrossRefs( os );
  45.  
  46. }
  47.  
  48. void *THelpTopic::read( ipstream& is )
  49. {
  50.     readParagraphs( is );
  51.     readCrossRefs( is );
  52.     width = 0;
  53.     lastLine = INT_MAX;
  54.     return this;
  55. }
  56.  
  57. TStreamable *THelpTopic::build()
  58. {
  59.     return new THelpTopic( streamableInit );
  60. }
  61.  
  62.  
  63. TStreamableClass RHelpTopic( THelpTopic::name,
  64.                                   THelpTopic::build,
  65.                                   __DELTA(THelpTopic)
  66.                                 );
  67.  
  68. THelpTopic::THelpTopic() : TObject()
  69. {
  70.     paragraphs = 0;
  71.     numRefs = 0;
  72.     crossRefs = 0;
  73.     width = 0;
  74.     lastOffset = 0;
  75.     lastLine = INT_MAX;
  76.     lastParagraph = 0;
  77. };
  78.  
  79. void THelpTopic::readParagraphs( ipstream& s )
  80. {
  81.     int  i;
  82.     ushort size;
  83.     TParagraph **pp;
  84.     int temp;
  85.  
  86.     s >> i;
  87.     pp = ¶graphs;
  88.     while ( i > 0)
  89.     {
  90.         s >> size;
  91.         *pp = new TParagraph;
  92.         (*pp)->text = new char[size];
  93.         (*pp)->size = (ushort) size;
  94.     s >> temp;
  95.         (*pp)->wrap = Boolean(temp);
  96.         s.readBytes((*pp)->text, (*pp)->size);
  97.         pp = &((*pp)->next);
  98.         --i;
  99.     }
  100.     *pp = 0;
  101. }
  102.  
  103. void THelpTopic::readCrossRefs( ipstream& s )
  104. {
  105.     int i;
  106.     TCrossRef *crossRefPtr;
  107.  
  108.     s >> numRefs;
  109.     crossRefs = new TCrossRef[numRefs];
  110.     for (i = 0; i < numRefs; ++i)
  111.         {
  112.         crossRefPtr = (TCrossRef *)crossRefs + i;
  113.  
  114.     /*
  115.      * SS: TCrossRef size is 9 bytes (int, int, char), but
  116.      * sizeof(TCrossRef) is rounded to 12.
  117.      */
  118.     s >> crossRefPtr->ref;        /* int */
  119.     s >> crossRefPtr->offset;    /* int */
  120.     s >> crossRefPtr->length;    /* char */
  121. //        s.readBytes(crossRefPtr, sizeof(TCrossRef));
  122.         }
  123. }
  124.  
  125. void THelpTopic::disposeParagraphs()
  126. {
  127.     TParagraph *p, *t;
  128.  
  129.     p = paragraphs;
  130.     while (p != 0)
  131.         {
  132.         t = p;
  133.         p = p->next;
  134.         delete t->text;
  135.         delete t;
  136.         }
  137. }
  138.  
  139.  
  140. THelpTopic::~THelpTopic()
  141. {
  142.     TCrossRef *crossRefPtr;
  143.  
  144.     disposeParagraphs();
  145.     if (crossRefs != 0)
  146.        {
  147.        crossRefPtr = (TCrossRef *)crossRefs;
  148.  
  149.     /* SS: prevent anachronistic stuff */
  150.  
  151.     delete [] crossRefPtr;
  152. //       delete [numRefs] crossRefPtr;
  153.        }
  154. }
  155.  
  156. void THelpTopic::addCrossRef( TCrossRef ref )
  157. {
  158.     TCrossRef *p;
  159.     TCrossRef *crossRefPtr;
  160.  
  161.     p =  new TCrossRef[numRefs+1];
  162.     if (numRefs > 0)
  163.         {
  164.         crossRefPtr = crossRefs;
  165.         memmove(p, crossRefPtr, numRefs * sizeof(TCrossRef));
  166.  
  167.     /* SS: prevent anachronistic stuff */
  168.  
  169.     delete [] crossRefPtr;
  170. //        delete [numRefs] crossRefPtr;
  171.         }
  172.     crossRefs = p;
  173.     crossRefPtr = crossRefs + numRefs;
  174.     *crossRefPtr = ref;
  175.     ++numRefs;
  176. }
  177.  
  178.  
  179. void THelpTopic::addParagraph( TParagraph *p )
  180. {
  181.     TParagraph  *pp, *back;
  182.  
  183.     if (paragraphs == 0)
  184.         paragraphs = p;
  185.     else
  186.         {
  187.         pp = paragraphs;
  188.         back = pp;
  189.         while (pp != 0)
  190.             {
  191.             back = pp;
  192.             pp = pp->next;
  193.             }
  194.         back->next = p;
  195.         }
  196.     p->next = 0;
  197. }
  198.  
  199. void THelpTopic::getCrossRef( int i, TPoint& loc, uchar& length,
  200.          int& ref )
  201. {
  202.     int oldOffset, curOffset, offset, paraOffset;
  203.     TParagraph *p;
  204.     int line;
  205.     TCrossRef *crossRefPtr;
  206.  
  207.     paraOffset = 0;
  208.     curOffset = 0;
  209.     oldOffset = 0;
  210.     line = 0;
  211.     crossRefPtr = crossRefs + i;
  212.     offset = crossRefPtr->offset;
  213.     p = paragraphs;
  214.     while (paraOffset + curOffset < offset)
  215.         {
  216.         char lbuf[256];
  217.  
  218.         oldOffset = paraOffset + curOffset;
  219.         wrapText(p->text, p->size, curOffset, p->wrap, lbuf, sizeof(lbuf));
  220.         ++line;
  221.         if (curOffset >= p->size)
  222.             {
  223.             paraOffset += p->size;
  224.             p = p->next;
  225.             curOffset = 0;
  226.             }
  227.         }
  228.     loc.x = offset - oldOffset - 1;
  229.     loc.y = line;
  230.     length = crossRefPtr->length;
  231.     ref = crossRefPtr->ref;
  232. }
  233.  
  234. char *THelpTopic::getLine( int line, char *buffer, int buflen )
  235. {
  236.     int offset, i;
  237.     TParagraph *p;
  238.  
  239.     if (lastLine < line)
  240.         {
  241.         i = line;
  242.         line -= lastLine;
  243.         lastLine = i;
  244.         offset = lastOffset;
  245.         p = lastParagraph;
  246.         }
  247.     else
  248.         {
  249.         p = paragraphs;
  250.         offset = 0;
  251.         lastLine = line;
  252.         }
  253.     buffer[0] = 0;
  254.     while (p != 0)
  255.     {
  256.         while (offset < p->size)
  257.         {
  258.             char lbuf[256];
  259.  
  260.             --line;
  261.             strncpy(buffer, wrapText(p->text, p->size, offset, p->wrap, lbuf, sizeof(lbuf)), buflen);
  262.             if (line == 0)
  263.                 {
  264.                 lastOffset = offset;
  265.                 lastParagraph = p;
  266.                 return buffer;
  267.                 }
  268.         }
  269.         p = p->next;
  270.         offset = 0;
  271.     }
  272.     buffer[0] = 0;
  273.     return buffer;
  274. }
  275.  
  276. int THelpTopic::getNumCrossRefs()
  277. {
  278.     return numRefs;
  279. }
  280.  
  281. int THelpTopic::numLines()
  282. {
  283.     int offset, lines;
  284.     TParagraph *p;
  285.  
  286.     offset = 0;
  287.     lines = 0;
  288.     p = paragraphs;
  289.     while (p != 0)
  290.         {
  291.         offset = 0;
  292.         while (offset < p->size)
  293.             {
  294.             char lbuf[256];
  295.             ++lines;
  296.             wrapText(p->text, p->size, offset, p->wrap, lbuf, sizeof(lbuf));
  297.             }
  298.         p = p->next;
  299.         }
  300.     return lines;
  301. }
  302.  
  303. void THelpTopic::setCrossRef( int i, TCrossRef& ref )
  304. {
  305.     TCrossRef *crossRefPtr;
  306.  
  307.     if (i < numRefs)
  308.         {
  309.         crossRefPtr = crossRefs + i;
  310.         *crossRefPtr = ref;
  311.         }
  312. }
  313.  
  314.  
  315. void THelpTopic::setNumCrossRefs( int i )
  316. {
  317.     TCrossRef  *p, *crossRefPtr;
  318.  
  319.     if (numRefs == i)
  320.         return;
  321.     p = new TCrossRef[i];
  322.     if (numRefs > 0)
  323.         {
  324.         crossRefPtr = crossRefs;
  325.         if (i > numRefs)
  326.             memmove(p, crossRefPtr, numRefs * sizeof(TCrossRef));
  327.         else
  328.             memmove(p, crossRefPtr, i * sizeof(TCrossRef));
  329.  
  330.     /* SS: prevent anachronistic stuff */
  331.  
  332.         delete [] crossRefPtr;
  333. //        delete [numRefs] crossRefPtr;
  334.         }
  335.     crossRefs = p;
  336.     numRefs = i;
  337. }
  338.  
  339.  
  340. void THelpTopic::setWidth( int aWidth )
  341. {
  342.     width = aWidth;
  343. }
  344.  
  345. void THelpTopic::writeParagraphs( opstream& s )
  346. {
  347.     int i;
  348.     TParagraph  *p;
  349.     int temp;
  350.  
  351.     p = paragraphs;
  352.     for (i = 0; p != 0; ++i)
  353.         p = p->next;
  354.     s << i;
  355.     for(p = paragraphs; p != 0; p = p->next)
  356.         {
  357.         s << p->size;
  358.         temp = int(p->wrap);
  359.         s << temp;
  360.         s.writeBytes(p->text, p->size);
  361.         }
  362. }
  363.  
  364.  
  365. void THelpTopic::writeCrossRefs( opstream& s )
  366. {
  367.     int i;
  368.     TCrossRef *crossRefPtr;
  369.  
  370.     s << numRefs;
  371.     if (crossRefHandler == notAssigned)
  372.         {
  373.         for(i = 0; i < numRefs; ++i)
  374.             {
  375.             crossRefPtr = crossRefs + i;
  376.             s << crossRefPtr->ref << crossRefPtr->offset << crossRefPtr->length;
  377.             }
  378.         }
  379.     else
  380.         for (i = 0; i < numRefs; ++i)
  381.             {
  382.             crossRefPtr = crossRefs + i;
  383.             (*crossRefHandler)(s, crossRefPtr->ref);
  384.             s << crossRefPtr->offset << crossRefPtr->length;
  385.             }
  386. }
  387.  
  388. Boolean isBlank( char ch )
  389. {
  390.     if (isspace((uchar)ch))
  391.         return True;
  392.     else
  393.         return False;
  394. }
  395.  
  396. int scan( char *p, int offset, char c)
  397. {
  398.     char *temp1, *temp2;
  399.  
  400.     temp1 = p + offset;
  401.     temp2 = strchr(temp1, c);
  402.     if (temp2 == 0)
  403.        return 256;
  404.     else
  405.        {
  406.        if ((int)(temp2 - temp1) <= 256 )
  407.          return (int) (temp2 - temp1) + 1;
  408.        else
  409.          return 256;
  410.        }
  411. }
  412.  
  413. void textToLine( void *text, int offset, int length, char *line )
  414. {
  415.     strncpy(line, (char *)text+offset, length);
  416.     line[length] = 0;
  417. }
  418.  
  419. char *THelpTopic::wrapText( char *text, int size, int& offset, Boolean wrap,
  420.                             char *lineBuf, int lineBufLen )
  421. {
  422.     int i;
  423.  
  424.     i = scan(text, offset, '\n');
  425.     if (i + offset > size )
  426.         i = size - offset;
  427.     if ((i >= width) && (wrap == True))
  428.         {
  429.         i = offset + width;
  430.         if (i > size)
  431.             i = size;
  432.         else
  433.             {
  434.             while((i > offset) && !(isBlank(text[i])))
  435.                 --i;
  436. /*
  437.             if (i == offset)
  438.                 i = offset + width;
  439.             else
  440.                 ++i;
  441. */
  442.             if( i == offset )
  443.                 {
  444.                 i = offset + width;
  445.                 while( (i < size) && !isBlank(text[i]) )
  446.                     ++i;
  447.                 if( i < size )
  448.                     ++i;
  449.                 }
  450.             else
  451.                 ++i;
  452.             }
  453.         if (i == offset)
  454.             i = offset + width;
  455.         i -= offset;
  456.         }
  457.     textToLine(text, offset, min(i,lineBufLen), lineBuf);
  458.     if (lineBuf[min(strlen(lineBuf) - 1, lineBufLen)] == '\n')
  459.         lineBuf[min(strlen(lineBuf) - 1, lineBufLen)] = 0;
  460.     offset += min(i,lineBufLen);
  461.     return lineBuf;
  462. }
  463.  
  464. // THelpIndex
  465.  
  466. const char * const THelpIndex::name = "THelpIndex";
  467.  
  468. void THelpIndex::write( opstream& os )
  469. {
  470.     long *indexArrayPtr;
  471.  
  472.     os << size;
  473.     for (int i = 0; i < size; ++i)
  474.         {
  475.         indexArrayPtr = index + i;
  476.         os << *indexArrayPtr;
  477.         }
  478. }
  479.  
  480. void *THelpIndex::read( ipstream& is )
  481. {
  482.     long *indexArrayPtr;
  483.  
  484.     is >> size;
  485.     if (size == 0)
  486.         index = 0;
  487.     else
  488.         {
  489.         index =  new long[size];
  490.         for(int i = 0; i < size; ++i)
  491.             {
  492.             indexArrayPtr = index + i;
  493.             is >> *indexArrayPtr;
  494.             }
  495.         }
  496.     return this;
  497. }
  498.  
  499. TStreamable *THelpIndex::build()
  500. {
  501.     return new THelpIndex( streamableInit );
  502. }
  503.  
  504. TStreamableClass RHelpIndex( THelpIndex::name,
  505.                                   THelpIndex::build,
  506.                                   __DELTA(THelpIndex)
  507.                             );
  508.  
  509. THelpIndex::~THelpIndex()
  510. {
  511.     /* SS: prevent anachronistic stuff */
  512.  
  513.     delete [] index;
  514. //    delete [size] index;
  515. }
  516.  
  517.  
  518. THelpIndex::THelpIndex(void): TObject ()
  519. {
  520.     size = 0;
  521.     index = 0;
  522. }
  523.  
  524. long THelpIndex::position(int i)
  525. {
  526.     long *indexArrayPtr;
  527.  
  528.     if (i < size)
  529.         {
  530.         indexArrayPtr = index + i;
  531.         return (*indexArrayPtr);
  532.         }
  533.     else
  534.         return -1;
  535. }
  536.  
  537. void THelpIndex::add( int i, long val )
  538. {
  539.     int delta = 10;
  540.     long *p;
  541.     int newSize;
  542.     long *indexArrayPtr;
  543.  
  544.     if (i >= size)
  545.         {
  546.         newSize = (i + delta) / delta * delta;
  547.         p = new long[newSize];
  548.         if (p != 0)
  549.             {
  550.             memmove(p, index, size * sizeof(long));
  551.             memset(p+size, 0xFF, (newSize - size) * sizeof(long));
  552.             }
  553.         if (size > 0)
  554.             {
  555.         /* SS: prevent anachronistic stuff */
  556.  
  557.             delete [] index;
  558. //            delete [size] index;
  559.             }
  560.         index = p;
  561.         size = newSize;
  562.         }
  563.     indexArrayPtr = index + i;
  564.     *indexArrayPtr = val;
  565. }
  566.  
  567. // THelpFile
  568.  
  569. THelpFile::THelpFile( fpstream&  s )
  570. {
  571.     long magic;
  572.     int handle;
  573.     long size;
  574.  
  575.     magic = 0;
  576.     s.seekg(0);
  577.     handle = s.rdbuf()->fd();
  578.     size = filelength(handle);
  579.     s.seekg(0);
  580. //    if (size > sizeof(magic)) /* XXX */
  581.     if (size > (long)sizeof(magic)) /* XXX */
  582.         s >> magic;
  583.     if (magic != magicHeader)
  584.         {
  585.         indexPos = 12;
  586.         s.seekg(indexPos);
  587.         index =  new THelpIndex;
  588.         modified = True;
  589.         }
  590.     else
  591.         {
  592.         s.seekg(8);
  593.         s >> indexPos;
  594.         s.seekg(indexPos);
  595.         s >> index;
  596.         modified = False;
  597.         }
  598.     stream = &s;
  599. }
  600.  
  601. THelpFile::~THelpFile(void)
  602. {
  603.     long magic, size;
  604.     int handle;
  605.  
  606.     if (modified == True)
  607.         {
  608.         stream->seekp(indexPos);
  609.         *stream << index;
  610.         stream->seekp(0);
  611.         magic = magicHeader;
  612.         handle = stream->rdbuf()->fd();
  613. //
  614. // note: at this time, a bug in filelength leaves the seek pointer at
  615. //       the end of file, so we must save and restore the seek pointer
  616. //       around the call; this can be removed when filelength is fixed.
  617. //
  618.   streampos sp=stream->tellp();
  619.         size = filelength(handle) - 8;
  620.   stream->seekp(sp);
  621.         *stream << magic;
  622.         *stream << size;
  623.         *stream << indexPos;
  624.         }
  625.     delete stream;
  626.     delete index;
  627. }
  628.  
  629. THelpTopic *THelpFile::getTopic( int i )
  630. {
  631.     long pos;
  632.     THelpTopic *topic = 0;
  633.  
  634.     pos = index->position(i);
  635.     if (pos > 0 )
  636.         {
  637.         stream->seekg(pos);
  638.         *stream >> topic;
  639.         return topic;
  640.         }
  641.     else return(invalidTopic());
  642. }
  643.  
  644. THelpTopic *THelpFile::invalidTopic()
  645. {
  646.     THelpTopic *topic;
  647.     TParagraph *para;
  648.  
  649.     topic =  new THelpTopic;
  650.     para =  new TParagraph;
  651.     para->text = newStr(invalidContext);
  652.     para->size = strlen(invalidContext);
  653.     para->wrap = False;
  654.     para->next = 0;
  655.     topic->addParagraph(para);
  656.     return topic;
  657. }
  658.  
  659. void THelpFile::recordPositionInIndex( int i )
  660. {
  661.     index->add(i, indexPos);
  662.     modified = True;
  663. }
  664.  
  665. void THelpFile::putTopic( THelpTopic *topic )
  666. {
  667.     stream->seekp(indexPos);
  668.     *stream << topic;
  669.     indexPos = stream->tellp();
  670.     modified = True;
  671. }
  672.  
  673. void notAssigned( opstream& , int )
  674. {
  675. }
  676.