home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_144 / 8.ddi / TVHELP.ZIP / TVHC.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  29.8 KB  |  1,001 lines

  1. /*-----------------------------------------------------------------------*/
  2. /*                                                                       */
  3. /*            Turbo Vision 1.0                                           */
  4. /*            Turbo Vision Help Compiler Source File                     */
  5. /*            Copyright (c) 1991 by Borland International                */
  6. /*                                                                       */
  7. /*-----------------------------------------------------------------------*/
  8.  
  9. /*===== TVHC ============================================================*/
  10. /*  Turbo Vision help file compiler documentation.                       */
  11. /*=======================================================================*/
  12. /*                                                                       */
  13. /*    Refer to DEMOHELP.TXT for an example of a help source file.        */
  14. /*                                                                       */
  15. /*    This program takes a help script and produces a help file (.HLP)   */
  16. /*    and a help context file (.H).  The format for the help file is     */
  17. /*    very simple.  Each context is given a symbolic name (i.e FileOpen) */
  18. /*    which is then put in the context file (i.e. hcFileOpen).  The text */
  19. /*    following the topic line is put into the help file.  Since the     */
  20. /*    help file can be resized, some of the text will need to be wrapped */
  21. /*    to fit into the window.  If a line of text is flush left with      */
  22. /*    no preceeding white space, the line will be wrapped.  All adjacent */
  23. /*    wrappable lines are wrapped as a paragraph.  If a line begins with */
  24. /*    a space it will not be wrapped. For example, the following is a    */
  25. /*    help topic for a File|Open menu item.                              */
  26. /*                                                                       */
  27. /*       |.topic FileOpen                                                */
  28. /*       |  File|Open                                                    */
  29. /*       |  ---------                                                    */
  30. /*       |This menu item will bring up a dialog...                       */
  31. /*                                                                       */
  32. /*    The "File|Open" will not be wrapped with the "----" line since     */
  33. /*    they both begin with a space, but the "This menu..." line will     */
  34. /*    be wrapped.                                                        */
  35. /*      The syntax for a ".topic" line is:                               */
  36. /*                                                                       */
  37. /*        .topic symbol[=number][, symbol[=number][...]]                 */
  38. /*                                                                       */
  39. /*    Note a topic can have multiple symbols that define it so that one  */
  40. /*    topic can be used by multiple contexts.  The number is optional    */
  41. /*    and will be the value of the hcXXX context in the context file     */
  42. /*    Once a number is assigned all following topic symbols will be      */
  43. /*    assigned numbers in sequence.  For example,                        */
  44. /*                                                                       */
  45. /*       .topic FileOpen=3, OpenFile, FFileOpen                          */
  46. /*                                                                       */
  47. /*    will produce the follwing help context number definitions,         */
  48. /*                                                                       */
  49. /*        hcFileOpen  = 3;                                               */
  50. /*        hcOpenFile  = 4;                                               */
  51. /*        hcFFileOpen = 5;                                               */
  52. /*                                                                       */
  53. /*    Cross references can be imbedded in the text of a help topic which */
  54. /*    allows the user to quickly access related topics.  The format for  */
  55. /*    a cross reference is as follows,                                   */
  56. /*                                                                       */
  57. /*        {text[:alias]}                                                 */
  58. /*                                                                       */
  59. /*    The text in the brackets is highlighted by the help viewer.  This  */
  60. /*    text can be selected by the user and will take the user to the     */
  61. /*    topic by the name of the text.  Sometimes the text will not be     */
  62. /*    the same as a topic symbol.  In this case you can use the optional */
  63. /*    alias syntax.  The symbol you wish to use is placed after the text */
  64. /*    after a ':'. The following is a paragraph of text using cross      */
  65. /*    references,                                                        */
  66. /*                                                                       */
  67. /*      |The {file open dialog:FileOpen} allows you specify which        */
  68. /*       |file you wish to view.  If it also allow you to navigate       */
  69. /*       |directories.  To change to a given directory use the           */
  70. /*      |{change directory dialog:ChDir}.                                */
  71. /*                                                                       */
  72. /*    The user can tab or use the mouse to select more information about */
  73. /*    the "file open dialog" or the "change directory dialog". The help  */
  74. /*    compiler handles forward references so a topic need not be defined */
  75. /*    before it is referenced.  If a topic is referenced but not         */
  76. /*    defined, the compiler will give a warning but will still create a  */
  77. /*    useable help file.  If the undefined reference is used, a message  */
  78. /*    ("No help available...") will appear in the help window.           */
  79. /*=======================================================================*/
  80.  
  81. #define Uses_fpstream
  82. #define Uses_TSortedCollection
  83. #include <tv.h>
  84.  
  85. #if !defined( __TVHC_H )
  86. #include "Tvhc.h"
  87. #endif  // __TVHC_H
  88.  
  89. #if !defined( __STRING_H )
  90. #include <string.h>
  91. #endif  // __STRING_H
  92.  
  93. #if !defined( __LIMITS_H )
  94. #include <limits.h>
  95. #endif  // __LIMITS_H
  96.  
  97. #if !defined __DOS_H
  98. #include <dos.h>
  99. #endif  // __DOS_H
  100.  
  101. #if !defined( __DIR_H )
  102. #include <dir.h>
  103. #endif  // __DIR_H
  104.  
  105. #if !defined( __IO_H )
  106. #include <io.h>
  107. #endif  // __IO_H
  108.  
  109. #if !defined( __CTYPE_H )
  110. #include <ctype.h>
  111. #endif  // __CTYPE_H
  112.  
  113. #if !defined( __STDLIB_H )
  114. #include <stdlib.h>
  115. #endif  // __STDLIB_H
  116.  
  117. #if !defined( __FSTREAM_H )
  118. #include <fstream.h>
  119. #endif  // __FSTREAM_H
  120.  
  121. #if !defined( __STRSTREA_H )
  122. #include <strstrea.h>
  123. #endif  // __STRSTREA_H
  124.  
  125. #if !defined( __ERRNO_H )
  126. #include <errno.h>
  127. #endif  // __ERRNO_H
  128.  
  129. #if !defined( __CONIO_H )
  130. #include <conio.h>
  131. #endif  // __CONIO_H
  132.  
  133. //======================= File Management ===============================//
  134.  
  135. TProtectedStream::TProtectedStream( char *aFileName, ushort aMode ) :
  136.     fstream( aFileName, aMode )
  137. {
  138.     strcpy(fileName, aFileName);
  139.     mode = aMode;
  140. }
  141.  
  142. void error(char *text);
  143.  
  144. //----- replaceExt(fileName, nExt, force) -------------------------------//
  145. //  Replace the extension of the given file with the given extension.    //
  146. //  If an extension already exists Force indicates if it should be       //
  147. //  replaced anyway.                                                     //
  148. //-----------------------------------------------------------------------//
  149.  
  150. char *replaceExt( char *fileName, char *nExt, Boolean force )
  151. {
  152.     char dir[MAXPATH]; 
  153.     char name[MAXFILE];
  154.     char ext[MAXEXT];
  155.     char drive[MAXDRIVE];
  156.     char buffer[MAXPATH];
  157.     ostrstream os(buffer, MAXPATH);
  158.  
  159.     fnsplit(fileName, drive, dir, name, ext);
  160.     if (force || (strlen(ext) == 0))
  161.         {
  162.         os << dir << name << nExt << ends;
  163.         return os.str();
  164.         }
  165.     else
  166.         return fileName;
  167. }
  168.  
  169. //----- fExist(fileName) ------------------------------------------------/
  170. //  Returns true if the file exists false otherwise.                     /
  171. //-----------------------------------------------------------------------/
  172.  
  173. Boolean fExists(char *fileName)
  174. {
  175.     struct ffblk ffblk;
  176.  
  177.     if (findfirst(fileName,&ffblk,0))
  178.         return(False);
  179.     else
  180.         return(True);
  181. }
  182.  
  183. //======================== Line Management ==============================//
  184. //----- getLine(s) ------------------------------------------------------//
  185. //  Returns the next line out of the stream.                             //
  186. //-----------------------------------------------------------------------//
  187.  
  188. char *getLine( fstream& s)
  189. {
  190.     if (s.eof())
  191.         {
  192.         strcpy(line, "\x1A");
  193.         return line;
  194.         }
  195.     if (!lineInBuffer)
  196.         s.getline(line, MAXSTRSIZE, '\n');
  197.     lineInBuffer = False;
  198.     ++lineCount;
  199.     return line;
  200. }
  201.  
  202. //----- unGetLine(s) ----------------------------------------------------//
  203. //  Return given line into the stream.                                   //
  204. //-----------------------------------------------------------------------//
  205.  
  206. void unGetLine( char *s )
  207. {
  208.     strcpy(line,s);
  209.     lineInBuffer = True;
  210.     --lineCount;
  211. }
  212.  
  213. //========================= Error routines ==============================//
  214.  
  215. //----- prntMsg(text) ---------------------------------------------------//
  216. //  Used by Error and Warning to print the message.                      //
  217. //-----------------------------------------------------------------------//
  218.  
  219. void prntMsg( char *pref, char *text )
  220. {
  221.     if (lineCount > 0)
  222.         cout << pref << ": " << helpName << "("
  223.              << lineCount << "): " << text << "\n";
  224.     else
  225.         cout << pref << ": " << helpName << " "
  226.              << text << "\n";
  227. }
  228.  
  229. //----- error(text) -----------------------------------------------------//
  230. //  Used to indicate an error.  Terminates the program                   //
  231. //-----------------------------------------------------------------------//
  232.  
  233. void error( char *text )
  234. {
  235.     prntMsg("Error", text);
  236.     exit(1);
  237. }
  238.  
  239. //----- warning(text) ---------------------------------------------------//
  240. //  Used to indicate an warning.                                         //
  241. //-----------------------------------------------------------------------//
  242.  
  243. void warning( char *text )
  244. {
  245.     prntMsg("Warning", text);
  246. }
  247.  
  248. //====================== Topic Reference Management =====================//
  249.  
  250. void disposeFixUps( TFixUp *&p )
  251. {
  252.     TFixUp *q;
  253.  
  254.     while (p != 0)
  255.         {
  256.         q = p->next;
  257.         delete p;
  258.         p = q;
  259.         }
  260. }
  261.  
  262. //----- TRefTable -------------------------------------------------------//
  263. //  TRefTable is a collection of TReference pointers used as a symbol    //
  264. //  table. If the topic has not been seen, a forward reference is        //
  265. //  inserted and a fix-up list is started.  When the topic is seen all   //
  266. //  forward references are resolved.  If the topic has been seen already //
  267. //  the value it has is used.                                            //
  268. //-----------------------------------------------------------------------//
  269.  
  270. TRefTable::TRefTable( ccIndex aLimit, ccIndex aDelta ) :
  271.      TSortedCollection( aLimit, aDelta )
  272. {
  273. }
  274.  
  275. int TRefTable::compare( void *key1, void *key2 )
  276. {
  277.     int compValue;
  278.  
  279.  
  280.     compValue = strcmp( (char *)key1, (char *)key2 );
  281.     if (compValue > 0)
  282.         return 1;
  283.     else if (compValue < 0)
  284.         return (-1);
  285.     else
  286.         return(0);
  287. }
  288.  
  289. void TRefTable::freeItem( void *item )
  290. {
  291.     TReference *ref;
  292.  
  293.     ref = (TReference *) item;
  294.     if (ref->resolved == False)
  295.         disposeFixUps(ref->val.fixUpList);
  296.     delete ref->topic;
  297.     delete ref;
  298. }
  299.  
  300. TReference *TRefTable::getReference( char *topic )
  301. {
  302.     TReference *ref;
  303.     int i;
  304.  
  305.     if (search(topic, i))
  306.         ref = (TReference *) at(i);
  307.     else
  308.         {
  309.         ref =  new TReference;
  310.         ref->topic =  newStr(topic);
  311.         ref->resolved = False;
  312.         ref->val.fixUpList = 0;
  313.         insert(ref);
  314.         }
  315.     return(ref);
  316. }
  317.  
  318. void* TRefTable::keyOf( void *item )
  319. {
  320.     return(((TReference *)item)->topic);
  321. }
  322.  
  323. //----- initRefTable ---------------------------------------------------//
  324. //  Make sure the reference table is initialized.                       //
  325. //----------------------------------------------------------------------//
  326.  
  327. void initRefTable()
  328. {
  329.     if (refTable == 0)
  330.         refTable = new TRefTable(5,5);
  331. }
  332.  
  333. //---- RecordReference -------------------------------------------------//
  334. //  Record a reference to a topic to the given stream.  This routine    //
  335. //  handles forward references.                                         //
  336. //----------------------------------------------------------------------//
  337.  
  338. void recordReference( char *topic, opstream& s )
  339. {
  340.     int i;
  341.     TReference *ref;
  342.     TFixUp *fixUp;
  343.  
  344.     initRefTable();
  345.     ref = refTable->getReference(topic);
  346.     if (ref->resolved == True)
  347.         s << ref->val.value;
  348.     else
  349.         {
  350.         fixUp =  new TFixUp;
  351.         fixUp->pos = s.tellp();
  352.         i = -1;
  353.         s << i;
  354.         fixUp->next = ref->val.fixUpList;
  355.         ref->val.fixUpList = fixUp;
  356.         }
  357. }
  358.  
  359. void doFixUps( TFixUp *p, ushort value, fpstream& s )
  360. {
  361.     long pos;
  362.  
  363.     for(pos = s.tellg(); (p != 0); p = p->next)
  364.         {
  365.         s.seekp(p->pos);
  366.         s << value;
  367.         }
  368.     s.seekp(pos);
  369. }
  370.  
  371. //----- resolveReference -----------------------------------------------//
  372. //  Resolve a reference to a topic to the given stream.  This function  //
  373. //  handles forward references.                                         //
  374. //----------------------------------------------------------------------//
  375.  
  376. void resolveReference( char *topic, ushort value, fpstream& s )
  377. {
  378.     TReference *ref;
  379.     char bufStr[MAXSIZE];
  380.  
  381.     initRefTable();
  382.     ref = refTable->getReference(topic);
  383.     if (ref->resolved )
  384.         {
  385.         strcpy(bufStr,"Redefinition of ");
  386.         strcat(bufStr,ref->topic);
  387.         error(bufStr);
  388.         }
  389.     else
  390.         {
  391.         doFixUps(ref->val.fixUpList,value,s);
  392.         disposeFixUps(ref->val.fixUpList);
  393.         ref->resolved = True;
  394.         ref->val.value = value;
  395.         }
  396. }
  397.  
  398. //======================= Help file parser =============================//
  399.  
  400. void skipWhite( char *line,int& i )
  401. {
  402.     while (i <= strlen(line) && (line[i] == ' ') || (line[i] == 8))
  403.         ++i;
  404. }
  405.  
  406. int checkForValidChar( char ch )
  407. {
  408.     if (isalnum(ch) || (ch  == '_'))
  409.         return(0);
  410.     return(-1);
  411. }
  412.  
  413.  
  414. void skipToNonWord( char *line, int& i )
  415. {
  416.     while (i <= strlen(line) && (!checkForValidChar(line[i])))
  417.         ++i;
  418. }
  419.  
  420. //----- getWord --------------------------------------------------------//
  421. //   Extract the next word from the given line at offset i.             //
  422. //----------------------------------------------------------------------//
  423.  
  424. char *getWord( char *line, int &i )
  425. {
  426.     int j;
  427.     char *strptr;
  428.     char getword[MAXSIZE];
  429.  
  430.     skipWhite(line,i);
  431.     j = i;
  432.     if (j > strlen(line))
  433.         strcpy(getword,"");
  434.     else
  435.         {
  436.         ++i;
  437.         if (!checkForValidChar(line[j]))
  438.             skipToNonWord(line, i);
  439.         strptr = line + j;
  440.         strncpy(getword,strptr,i - j);
  441.         getword[i-j] = '\0';
  442.         }
  443.     return getword;
  444. }
  445.  
  446. //---- topicDefinition -------------------------------------------------//
  447. //  Extracts the next topic definition from the given line at i.        //
  448. //----------------------------------------------------------------------//
  449.  
  450. TTopicDefinition::TTopicDefinition( char *aTopic, ushort aValue )
  451. {
  452.     topic = newStr(aTopic);
  453.     value = aValue;
  454.     next = 0;
  455. }
  456.  
  457. TTopicDefinition::~TTopicDefinition()
  458. {
  459.     delete topic;
  460.     if (next != 0)
  461.         delete next;
  462. }
  463.  
  464. int is_numeric(char *str)
  465. {
  466.     int i;
  467.  
  468.     for(i = 0; i < strlen(str); ++i)
  469.         if (!isdigit(str[i]))
  470.             return 0;
  471.     return 1;
  472. }
  473.  
  474. TTopicDefinition *topicDefinition( char *line, int& i )
  475. {
  476.     int j;
  477.     char topic[MAXSTRSIZE], w[MAXSTRSIZE], *endptr;
  478.     static int helpCounter = 2; //1 is hcDragging
  479.  
  480.     strcpy(topic,getWord(line, i));
  481.     if (strlen(topic) == 0)
  482.         {
  483.         error("Expected topic definition");
  484.         return(0);
  485.         }
  486.     else
  487.         {
  488.         j = i;
  489.         strcpy(w,getWord(line, j));
  490.         if (strcmp(w,"=") == 0)
  491.             {
  492.             i = j;
  493.             strcpy(w,getWord(line, i));
  494.             if (!is_numeric(w))
  495.                 error("Expected numeric");
  496.             else
  497.                 helpCounter = (int) strtol(w, &endptr,10);
  498.             }
  499.         else
  500.             ++helpCounter;
  501.         return(new TTopicDefinition(topic, helpCounter));
  502.         }
  503. }
  504.  
  505. //---- topicDefinitionList----------------------------------------------//
  506. //  Extracts a list of topic definitions from the given line at i.      //
  507. //----------------------------------------------------------------------//
  508.  
  509. TTopicDefinition *topicDefinitionList( char *line, int &i )
  510. {
  511.     int j;
  512.     char w[MAXSTRSIZE];
  513.     TTopicDefinition *topicList, *p;
  514.  
  515.     j = i;
  516.     topicList = 0;
  517.     do  {
  518.         i = j;
  519.         p = topicDefinition(line, i);
  520.         if (p == 0 )
  521.             {
  522.             if (topicList != 0)
  523.                 delete topicList; 
  524.             return(0);
  525.             }
  526.         p->next = topicList;
  527.         topicList = p;
  528.         j = i;
  529.         strcpy(w,getWord(line, j));
  530.         } while ( strcmp(w,",") == 0);
  531.     return(topicList);
  532. }
  533.  
  534. //---- topicHeader -----------------------------------------------------//
  535. //  Parse a Topic header                                                //
  536. //----------------------------------------------------------------------//
  537.  
  538. TTopicDefinition *topicHeader( char *line )
  539. {
  540.     int i;
  541.     char w[75];
  542.  
  543.     i = 0;
  544.     strcpy(w, getWord(line, i));
  545.     if (strcmp(w, commandChar) != 0)
  546.         return(0);
  547.     strcpy(w, getWord(line, i));
  548.     strupr(w);
  549.     if (strcmp(w, "TOPIC") == 0)
  550.         return topicDefinitionList(line, i);
  551.     else
  552.         {
  553.         error("TOPIC expected");
  554.         return(0);
  555.         }
  556. }
  557.  
  558. void addToBuffer( char *line, Boolean wrapping )
  559. {
  560.     uchar *bufptr;
  561.  
  562.     bufptr = &buffer[ofs];
  563.     ofs += strlen(line);
  564.     if( ofs > bufferSize )
  565.         error("Text too long");
  566.     strcpy((char *)bufptr, line);
  567.     bufptr += (strlen(line));
  568.     if (wrapping == False)
  569.         *bufptr = '\n';
  570.     else
  571.         *bufptr = ' ';
  572.     ofs++;
  573. }
  574.  
  575.  
  576. void addXRef( char *xRef, int offset, uchar length, TCrossRefNode *&xRefs )
  577. {
  578.     TCrossRefNode *p, *pp, *prev;
  579.  
  580.     p =  new TCrossRefNode;
  581.     p->topic = newStr(xRef);
  582.     p->offset = offset;
  583.     p->length = length;
  584.     p->next = 0;
  585.     if (xRefs == 0)
  586.         xRefs = p;
  587.     else
  588.         {
  589.         pp = xRefs;
  590.         prev = pp;
  591.         while (pp != 0)
  592.             {
  593.             prev = pp;
  594.             pp = pp->next;
  595.             }
  596.         prev->next = p;
  597.         }
  598. }
  599.  
  600. void replaceSpacesWithFF( char *line, int start, uchar length )
  601. {
  602.     int i;
  603.  
  604.     for(i = start; i <= (start + length); ++i)
  605.         if (line[i] == ' ')
  606.             line[i] = 0xFF;
  607. }
  608.  
  609. void strdel(char *string, int pos, int len)
  610. {
  611.     char tempstr[MAXSTRSIZE];
  612.     char *strptr;
  613.  
  614.     strncpy(tempstr, string, pos);
  615.     tempstr[pos] = 0;
  616.     strptr = string + pos + len;
  617.     strcat(tempstr, strptr);
  618.     strcpy(string, tempstr);
  619. }
  620.  
  621. void scanForCrossRefs( char *line, int& offset, TCrossRefNode *&xRefs )
  622. {
  623.     int i;
  624.     char begXRef = '{';
  625.     char endXRef = '}';
  626.     char aliasCh = ':';
  627.     char *begPtr, *endPtr, *aliasPtr, *tempPtr;
  628.     int begPos, endPos, aliasPos;
  629.     char xRef[75];
  630.  
  631.     i = 0;
  632.     do  {
  633.         if ((begPtr = strchr(line+i,begXRef)) == 0)
  634.             i = 0;
  635.         else
  636.             {
  637.             begPos = (int)(begPtr - (line+i));
  638.             i += begPos + 1;
  639.             if (line[i + 1] == begXRef)
  640.                 {
  641.                 strdel(line, i, 1);
  642.                 ++i;
  643.                 }
  644.             else
  645.                 {
  646.                 if ((endPtr = strchr(line+i,endXRef)) == 0)
  647.                     {
  648.                     error("Unterminated topic reference.");
  649.                     ++i;
  650.                     }
  651.                 else
  652.                     {
  653.                     endPos = (int)(endPtr - (line + i));
  654.                     aliasPtr = strchr(line+i, aliasCh);
  655.                     if ((aliasPtr == 0) || (aliasPtr > endPtr))
  656.                         {
  657.                         tempPtr = line + i;
  658.                         strncpy(xRef, tempPtr, endPos);
  659.                         xRef[endPos] = 0;
  660.                         addXRef(xRef, (offset + ofs + i), endPos, xRefs);
  661.                         }
  662.                     else
  663.                         {
  664.                         aliasPos = (int)(aliasPtr - (line + i));
  665.                         tempPtr = line ;
  666.                         tempPtr += aliasPos+i+1;
  667.                         strncpy(xRef, tempPtr, (endPos - aliasPos -1));
  668.                         xRef[endPos - aliasPos -1] = 0;
  669.                         addXRef(xRef, (offset + ofs + i), (aliasPos), xRefs);
  670.                         strdel(line, (i + aliasPos), (endPos - aliasPos));
  671.                         endPtr = aliasPtr;
  672.                         endPos = aliasPos;
  673.                         }
  674.                     replaceSpacesWithFF(line, i, endPos -1);
  675.                     strdel(line, i + endPos, 1);
  676.                     strdel(line, i-1, 1);
  677.                     i += (endPos - 2);
  678.                     }
  679.                 }
  680.             }
  681.  
  682.         } while (i != 0);
  683. }
  684.  
  685.  
  686. Boolean isEndParagraph( State state )
  687. {
  688.     int flag;
  689.     int wrapping = 1;
  690.     int notWrapping = 2;
  691.  
  692.     flag =
  693.           ((line[0] == 0) ||
  694.            (line[0] == commandChar[0]) ||
  695.        (line[0] == 26) ||
  696.            ((line[0] ==  ' ') && (state == wrapping)) ||
  697.            ((line[0] != ' ') && (state == notWrapping)));
  698.     if (flag)
  699.         return(True);
  700.     else
  701.         return(False);
  702. }
  703.  
  704. //---- readParagraph ----------------------------------------------------//
  705. // Read a paragraph of the screen.  Returns the paragraph or 0 if the    //
  706. // paragraph was not found in the given stream.  Searches for cross      //
  707. // references and updates the xRefs variable.                            //
  708. //-----------------------------------------------------------------------//
  709.  
  710. TParagraph *readParagraph( fstream& textFile, int& offset, TCrossRefNode *&xRefs )
  711. {
  712.     State state;
  713.     Boolean flag;
  714.     char line[MAXSTRSIZE];
  715.     TParagraph *p;
  716.  
  717.     ofs = 0;
  718.     state = undefined;
  719.     strcpy(line, getLine(textFile));
  720.     while (strlen(line) == 0)
  721.         {
  722.         flag = (state == wrapping)? True: False;
  723.         addToBuffer(line, flag);
  724.         strcpy(line, getLine(textFile));
  725.         }
  726.  
  727.     if (isEndParagraph(state) == True)
  728.         {
  729.         unGetLine(line);
  730.         return(0);
  731.         }
  732.     while (isEndParagraph(state) == False)
  733.         {
  734.         if (state == undefined )
  735.             if (line[0] == ' ')
  736.                 state = notWrapping;
  737.             else
  738.                 state = wrapping;
  739.         scanForCrossRefs(line, offset, xRefs);
  740.         flag = (state == wrapping)? True: False;
  741.         addToBuffer(line, flag);
  742.         strcpy(line, getLine(textFile));
  743.         }
  744.     unGetLine(line);
  745.     p = new TParagraph;
  746.     p->size = ofs;
  747.     p->wrap = (state == wrapping)? True: False;
  748.     p->text = new char[ofs];
  749.     memmove(p->text, buffer, ofs);
  750.     p->next = 0;
  751.     offset += ofs;
  752.     return(p);
  753. }
  754.  
  755. void far handleCrossRefs( opstream& s, int xRefValue )
  756. {
  757.     TCrossRefNode *p;
  758.  
  759.     for(p = xRefs; (xRefValue > 0) ; --xRefValue)
  760.         {
  761.         if (p != 0)
  762.             p = p->next;
  763.         }
  764.     if (p != 0)
  765.         recordReference((p->topic), s);
  766. }
  767.  
  768. void skipBlankLines( fstream& s )
  769. {
  770.     char line[256];
  771.  
  772.     line[0] = 0;
  773.     while (line[0] == 0)
  774.         strcpy(line,getLine(s));
  775.     unGetLine(line);
  776. }
  777.  
  778. int xRefCount()
  779. {
  780.     int i;
  781.     TCrossRefNode *p;
  782.  
  783.     i = 0;
  784.     for (p=xRefs; (p != 0); p=p->next)
  785.         ++i;
  786.     return(i);
  787. }
  788.  
  789. void disposeXRefs( TCrossRefNode  *p )
  790. {
  791.     TCrossRefNode *q;
  792.  
  793.     while (p != 0) 
  794.         {
  795.         q = p;
  796.         p = p->next;
  797.         delete q->topic;
  798.         delete q;
  799.         }
  800. }
  801.  
  802. void recordTopicDefinitions( TTopicDefinition *p, THelpFile& helpFile )
  803. {
  804.     while (p != 0)
  805.         {
  806.         resolveReference(p->topic, p->value, *(helpFile.stream));
  807.         helpFile.recordPositionInIndex(p->value);
  808.         p = p->next;
  809.         }
  810. }
  811.  
  812. //---- readTopic -------------------------------------------------------//
  813. // Read a topic from the source file and write it to the help file      //
  814. //----------------------------------------------------------------------//
  815.  
  816. void readTopic( fstream& textFile, THelpFile& helpFile )
  817. {
  818.     TParagraph *p;
  819.     THelpTopic *topic;
  820.     TTopicDefinition *topicDef;
  821.     int i, j, offset;
  822.     TCrossRef ref;
  823.     TCrossRefNode  *refNode;
  824.  
  825.     // Get screen command
  826.     skipBlankLines(textFile);
  827.     strcpy(line, getLine(textFile));
  828.  
  829.     topicDef = topicHeader(line);
  830.  
  831.     topic = new THelpTopic;
  832.  
  833.     // read paragraphs
  834.     xRefs = 0;
  835.     offset = 0;
  836.     p = readParagraph(textFile, offset, xRefs);
  837.     while (p != 0)
  838.         {
  839.         topic->addParagraph(p);
  840.         p = readParagraph(textFile, offset, xRefs);
  841.         }
  842.  
  843.     i = xRefCount();
  844.     topic->setNumCrossRefs(i);
  845.     refNode = xRefs;
  846.     for( j = 0; j < i; ++j)
  847.         {
  848.         ref.offset = refNode->offset;
  849.         ref.length = refNode->length;
  850.         ref.ref = j;
  851.         topic->setCrossRef(j, ref);
  852.         refNode = refNode->next;
  853.         }
  854.  
  855.     recordTopicDefinitions(topicDef, helpFile);
  856.  
  857.     crossRefHandler = handleCrossRefs;
  858.     helpFile.putTopic(topic);
  859.  
  860.     
  861.     if (topic != 0)
  862.     delete topic;
  863.     if (topicDef != 0)
  864.     delete topicDef;
  865.     disposeXRefs(xRefs);
  866.     
  867.     skipBlankLines(textFile);
  868. }
  869.  
  870. void far doWriteSymbol(void *p, void *p1)
  871. {
  872.     int numBlanks, i;
  873.     ostrstream os(line, MAXSTRSIZE);
  874.  
  875.     TProtectedStream *symbFile = (TProtectedStream *)p1;
  876.     if (((TReference *)p)->resolved )
  877.         {
  878.         os << "  hc" << (char *)((TReference *)p)->topic;
  879.         numBlanks = 20 - strlen((char *)((TReference *)p)->topic);
  880.         for (i = 0; i < numBlanks; ++i)
  881.             os << ' ';
  882.         os << " = " << ((TReference *)p)->val.value << ","<< ends;
  883.         *symbFile << os.str() << "\n";
  884.         }
  885.     else
  886.         {
  887.         os << "Unresolved forward reference \""
  888.            << ((TReference *)p)->topic << "\"" << ends;
  889.         warning(os.str());
  890.         }
  891. }
  892.  
  893. //---- writeSymbFile ---------------------------------------------------//
  894. // Write the .H file containing all screen titles as constants.         //
  895. //----------------------------------------------------------------------//
  896.  
  897. void writeSymbFile( TProtectedStream *symbFile )
  898. {
  899.     char header1[] = "const\n";
  900.  
  901.     *symbFile << header1;
  902.     refTable->forEach(doWriteSymbol, symbFile);
  903.     symbFile->seekp(-3L, ios::end);
  904.     *symbFile << ";\n";
  905.  
  906. }
  907.  
  908. //---- processtext -----------------------------------------------------//
  909. // Compile the given stream, and output a help file.                    //
  910. //----------------------------------------------------------------------//
  911.  
  912. void processText( TProtectedStream& textFile,
  913.                   fpstream& helpFile,
  914.                   TProtectedStream& symbFile )
  915. {
  916.     THelpFile *helpRez;
  917.  
  918.     helpRez =  new THelpFile(helpFile);
  919.  
  920.     while (!textFile.eof()) 
  921.         readTopic(textFile, *helpRez);
  922.     writeSymbFile(&symbFile);
  923.     delete helpRez;
  924. }
  925.  
  926. //---- checkOverwrite --------------------------------------------------//
  927. // Check whether the output file name exists.  If it does, ask whether  //
  928. // it's ok to overwrite it.                                             //
  929. //----------------------------------------------------------------------//
  930.  
  931. void checkOverwrite( char *fName )
  932. {
  933.     if (fExists(fName))
  934.         {
  935.         cerr << "File already exists: " << fName << ".  Overwrite? (y/n) ";
  936.         char ch = getch();
  937.         cerr << ch << endl;
  938.         if( toupper(ch) != 'Y' )
  939.             exit(1);
  940.         }
  941. }
  942.  
  943. //========================== Program Block ==========================//
  944.  
  945. int main(int argc, char **argv)
  946. {
  947.     char textName[MAXPATH];
  948.     char symbName[MAXPATH];
  949.     fpstream* helpStrm;
  950.  
  951.     // Banner messages
  952.     char initialText[] = "Help Compiler  Version 1.0  Copyright (c) 1991"
  953.                          " Borland International.\n";
  954.     char helpText[] =
  955.        "\n  Syntax  TVHC <Help text>[.TXT] [<Help file>[.HLP] [<Symbol file>[.H]]\n"
  956.        "\n"
  957.        "     Help text   = Help file source\n"
  958.        "     Help file   = Compiled help file\n"
  959.        "     Symbol file = An include file containing all the screen names as const's\n";
  960.  
  961.     char bufStr[MAXSTRSIZE];
  962.  
  963.     cout << initialText;
  964.     if (argc < 2)
  965.         {
  966.         cout << helpText;
  967.         exit(1); 
  968.         }
  969.  
  970.     //  Calculate file names
  971.     strcpy(textName,replaceExt(argv[1], ".TXT", False));
  972.     if (!fExists(textName))
  973.         {
  974.         strcpy(bufStr,"File ");
  975.         strcat(bufStr,textName);
  976.         strcat(bufStr," not found.");
  977.         error(bufStr);
  978.         }
  979.  
  980.     if (argc >= 3)
  981.         strcpy(helpName, replaceExt(argv[2], ".HLP", False));
  982.     else
  983.         strcpy(helpName, replaceExt(textName, ".HLP",  True));
  984.  
  985.     checkOverwrite( helpName );
  986.  
  987.     if (argc >= 4)
  988.         strcpy(symbName, replaceExt(argv[3], ".H", False));
  989.     else
  990.         strcpy(symbName, replaceExt(helpName, ".H", True));
  991.  
  992.     checkOverwrite( symbName );
  993.  
  994.     TProtectedStream textStrm(textName, ios::in);
  995.     TProtectedStream symbStrm(symbName, ios::out);
  996.  
  997.     helpStrm =  new fpstream(helpName, ios::out|ios::binary);
  998.     processText(textStrm, *helpStrm, symbStrm);
  999.     return 0;
  1000. }
  1001.