home *** CD-ROM | disk | FTP | other *** search
/ Mega A/V / mega_av.zip / mega_av / GRAPHUTL / FRASR172.ZIP / HELP.C < prev    next >
C/C++ Source or Header  |  1991-06-30  |  37KB  |  1,631 lines

  1.  
  2. /*
  3.  * help.c
  4.  *
  5.  * This module is linked as an overlay, use ENTER_OVLY and EXIT_OVLY.
  6.  *
  7.  *
  8.  * Revision history:
  9.  *
  10.  *   2-26-90  EAN     Initial version.
  11.  *
  12.  *
  13.  */
  14.  
  15.  
  16. #ifndef TEST /* kills all those assert macros in production version */
  17. #define NDEBUG
  18. #endif
  19.  
  20. #define INCLUDE_COMMON    /* include common code in helpcom.h */
  21.  
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <io.h>
  26. #include <fcntl.h>
  27. #include <dos.h>
  28. #include <string.h>
  29. #include <time.h>
  30. #include <assert.h>
  31. #include <sys\types.h>
  32. #include <sys\stat.h>
  33. #include "fractint.h"
  34. #include "helpcom.h"
  35. #include "helpdefs.h"
  36.  
  37.  
  38. #define MAX_HIST       16         /* number of pages we'll remember */
  39.  
  40. #define ALT_F1         1104
  41. #define BACK_TAB     1015
  42. #define BACKSPACE        8
  43.  
  44. #define ACTION_CALL        0         /* values returned by help_topic() */
  45. #define ACTION_PREV        1
  46. #define ACTION_PREV2        2         /* special - go back two topics */
  47. #define ACTION_INDEX        3
  48. #define ACTION_QUIT        4
  49.  
  50. #define F_HIST            (1<<0)   /* flags for help_topic() */
  51. #define F_INDEX         (1<<1)
  52.  
  53. #define MAX_PAGE_SIZE        (80*25)  /* no page of text may be larger */
  54.  
  55. #define TEXT_START_ROW        2         /* start print the help text here */
  56.  
  57.  
  58. typedef struct
  59.    {
  60.    unsigned char r, c;
  61.    int         width;
  62.    unsigned     offset;
  63.    int         topic_num;
  64.    unsigned     topic_off;
  65.    } LINK;
  66.  
  67.  
  68. typedef struct
  69.    {
  70.    int        topic_num;
  71.    unsigned topic_off;
  72.    } LABEL;
  73.  
  74.  
  75. typedef struct
  76.    {
  77.    unsigned     offset;
  78.    unsigned     len;
  79.    int         margin;
  80.    } PAGE;
  81.  
  82.  
  83. typedef struct
  84.    {
  85.    int        topic_num;
  86.    unsigned topic_off;
  87.    int        link;
  88.    } HIST;
  89.  
  90.  
  91. struct help_sig_info
  92.    {
  93.    unsigned long sig;
  94.    int         version;
  95.    unsigned long base;       /* only if added to fractint.exe */
  96.    } ;
  97.  
  98.  
  99. void print_document(char *outfname, int (*msg_func)(int,int), int save_extraseg );
  100. static int print_doc_msg_func(int pnum, int num_pages);
  101.  
  102.  
  103.  
  104. void help_overlay(void) { }
  105.  
  106.  
  107.  
  108. /* stuff from fractint */
  109.  
  110. extern int  lookatmouse;
  111. extern long timer_start;
  112. extern int  helpmode;
  113. extern int  text_type;     /* 0=real color text, 1=640x200x2, 2=??mono?? */
  114. extern int  textcbase;
  115. extern int  textrbase;
  116. extern int  extraseg;
  117. extern int  release;
  118.  
  119. void putstring         (int row, int col, int attr, unsigned char far *msg);
  120. int  putstringcenter (int row, int col, int width, int attr, char far *msg);
  121. void setattr         (int row, int col, int attr, int width);
  122. void movecursor      (int row, int col);
  123. void setclear         (void);
  124. void helptitle         (void);
  125. int  getakey         (void);
  126. int  keypressed      (void);
  127. void stackscreen     (void);
  128. void unstackscreen   (void);
  129. void findpath         (char *filename, char *path);
  130. int  farread         (int handle, void far *buf, unsigned len);
  131. int  farwrite         (int handle, void far *buf, unsigned len);
  132.  
  133.  
  134. static int          help_file = -1; /* help file handle */
  135. static long          base_off;       /* offset to help info in help file */
  136. static int          max_links;      /* max # of links in any page */
  137. static int          max_pages;      /* max # of pages in any topic */
  138. static int          num_label;      /* number of labels */
  139. static int          num_topic;      /* number of topics */
  140. static int          curr_hist = 0;  /* current pos in history */
  141.  
  142. /* these items alloc'ed in init_help... */
  143.  
  144. static long     far *topic_offset;       /* 4*num_topic */
  145. static LABEL     far *label;           /* 4*num_label */
  146. static HIST     far *hist;           /* 6*MAX_HIST (96 bytes) */
  147.  
  148. /* these items alloc'ed only while help is active... */
  149.  
  150. static char      far *buffer;         /* MAX_PAGE_SIZE (2048 bytes) */
  151. static LINK      far *link_table;     /* 10*max_links */
  152. static PAGE      far *page_table;     /* 4*max_pages  */
  153.  
  154.  
  155. static void help_seek(long pos)
  156.    {
  157.    lseek(help_file, base_off+pos, SEEK_SET);
  158.    }
  159.  
  160.  
  161. static void displayc(int row, int col, int color, int ch)
  162.    {
  163.    static char *s = "?";
  164.  
  165.    if (text_type == 1)     /* if 640x200x2 mode */
  166.       {
  167.       /*
  168.        * This is REALLY ugly, but it works.  Non-current links (ones that
  169.        * would be bold if 640x200 supported it) are in upper-case and the
  170.        * current item is inversed.
  171.        *
  172.        */
  173.  
  174.       if (color & INVERSE)
  175.      color = INVERSE;
  176.       else if (color & BRIGHT)
  177.      {
  178.      color = 0;   /* normal */
  179.      if (ch>='a' && ch<='z')
  180.         ch += 'A' - 'a';
  181.      }
  182.       else
  183.      color = 0;   /* normal */
  184.       }
  185.  
  186.    s[0] = ch;
  187.    putstring(row, col, color, s);
  188.    }
  189.  
  190.  
  191. static void display_text(int row, int col, int color, char far *text, unsigned len)
  192.    {
  193.    while (len-- > 0)
  194.       {
  195.       if (*text == CMD_LITERAL)
  196.      {
  197.      ++text;
  198.      --len;
  199.      }
  200.       displayc(row, col++, color, *text++);
  201.       }
  202.    }
  203.  
  204.  
  205. static void display_parse_text(char far *text, unsigned len, int start_margin, int *num_link, LINK far *link)
  206.    {
  207.    char far  *curr;
  208.    int          row, col;
  209.    int          tok;
  210.    int          size,
  211.           width;
  212.  
  213.    textcbase = SCREEN_INDENT;
  214.    textrbase = TEXT_START_ROW;
  215.  
  216.    curr = text;
  217.    row = 0;
  218.    col = 0;
  219.  
  220.    size = width = 0;
  221.  
  222.    if (start_margin >= 0)
  223.       tok = TOK_PARA;
  224.    else
  225.       tok = -1;
  226.  
  227.    while ( 1 )
  228.       {
  229.       switch ( tok )
  230.      {
  231.      case TOK_PARA:
  232.         {
  233.         int indent,
  234.         margin;
  235.  
  236.         if (size > 0)
  237.            {
  238.            ++curr;
  239.            indent = *curr++;
  240.            margin = *curr++;
  241.            len  -= 3;
  242.            }
  243.         else
  244.            {
  245.            indent = start_margin;
  246.            margin = start_margin;
  247.            }
  248.  
  249.         col = indent;
  250.  
  251.         while (1)
  252.            {
  253.            tok = find_token_length(ONLINE, curr, len, &size, &width);
  254.  
  255.            if (tok == TOK_DONE || tok == TOK_NL || tok == TOK_FF )
  256.           break;
  257.  
  258.            if (tok == TOK_PARA)
  259.           {
  260.           col = 0;   /* fake a new-line */
  261.           row++;
  262.           break;
  263.           }
  264.  
  265.            if (tok == TOK_XONLINE || tok == TOK_XDOC)
  266.           {
  267.           curr += size;
  268.           len  -= size;
  269.           continue;
  270.           }
  271.  
  272.            /* now tok is TOK_SPACE or TOK_LINK or TOK_WORD */
  273.  
  274.            if (col+width > SCREEN_WIDTH)
  275.           {         /* go to next line... */
  276.           col = margin;
  277.           ++row;
  278.  
  279.           if ( tok == TOK_SPACE )
  280.              width = 0;   /* skip spaces at start of a line */
  281.           }
  282.  
  283.            if (tok == TOK_LINK)
  284.           {
  285.           display_text(row, col, C_HELP_LINK, curr+7, width);
  286.           if (num_link != NULL)
  287.              {
  288.              link[*num_link].r           = row;
  289.              link[*num_link].c           = col;
  290.              link[*num_link].topic_num = *( (int far *) (curr+1) );
  291.              link[*num_link].topic_off = *( (int far *) (curr+3) );
  292.              link[*num_link].offset    = (unsigned) ((curr+7) - text);
  293.              link[*num_link].width     = width;
  294.              ++(*num_link);
  295.              }
  296.           }
  297.            else if (tok == TOK_WORD )
  298.           display_text(row, col, C_HELP_BODY, curr, width);
  299.  
  300.            col += width;
  301.            curr += size;
  302.            len -= size;
  303.            }
  304.  
  305.         width = size = 0;
  306.         break;
  307.         }
  308.  
  309.      case TOK_CENTER:
  310.         col = find_line_width(ONLINE, curr, len);
  311.         col = (SCREEN_WIDTH-col)/2;
  312.         if (col < 0)
  313.            col = 0;
  314.         break;
  315.  
  316.      case TOK_NL:
  317.         col = 0;
  318.         ++row;
  319.         break;
  320.  
  321.      case TOK_LINK:
  322.         display_text(row, col, C_HELP_LINK, curr+7, width);
  323.         if (num_link != NULL)
  324.            {
  325.            link[*num_link].r     = row;
  326.            link[*num_link].c     = col;
  327.            link[*num_link].topic_num = *( (int far *) (curr+1) );
  328.            link[*num_link].topic_off = *( (int far *) (curr+3) );
  329.            link[*num_link].offset     = (unsigned) ((curr+7) - text);
  330.            link[*num_link].width     = width;
  331.            ++(*num_link);
  332.            }
  333.         break;
  334.  
  335.      case TOK_XONLINE:  /* skip */
  336.      case TOK_FF:        /* ignore */
  337.      case TOK_XDOC:     /* ignore */
  338.      case TOK_DONE:
  339.      case TOK_SPACE:
  340.         break;
  341.  
  342.      case TOK_WORD:
  343.         display_text(row, col, C_HELP_BODY, curr, width);
  344.         break;
  345.      } /* switch */
  346.  
  347.       curr += size;
  348.       len  -= size;
  349.       col  += width;
  350.  
  351.       if (len == 0)
  352.      break;
  353.  
  354.       tok = find_token_length(ONLINE, curr, len, &size, &width);
  355.       } /* while */
  356.  
  357.    textcbase = 0;
  358.    textrbase = 0;
  359.    }
  360.  
  361.  
  362. static void color_link(LINK far *link, int color)
  363.    {
  364.    textcbase = SCREEN_INDENT;
  365.    textrbase = TEXT_START_ROW;
  366.  
  367.    if (text_type == 1)     /* if 640x200x2 mode */
  368.       display_text(link->r, link->c, color, buffer+link->offset, link->width);
  369.    else
  370.       setattr(link->r, link->c, color, link->width);
  371.  
  372.    textcbase = 0;
  373.    textrbase = 0;
  374.    }
  375.  
  376.  
  377.  
  378. /* #define PUT_KEY(name, descrip) putstring(-1,-1,C_HELP_INSTR_KEYS,name), putstring(-1,-1,C_HELP_INSTR," "descrip"  ") */
  379. #define PUT_KEY(name, descrip) putstring(-1,-1,C_HELP_INSTR,name); putstring(-1,-1,C_HELP_INSTR,":"descrip"  ")
  380.  
  381.  
  382. static void helpinstr(void)
  383.    {
  384.    int ctr;
  385.  
  386.    for (ctr=0; ctr<80; ctr++)
  387.      putstring(24, ctr, C_HELP_INSTR, " ");
  388.  
  389.    movecursor(24, 1);
  390.    PUT_KEY("F1",               "Index");
  391.    PUT_KEY("\x18\x19\x1B\x1A", "Select");
  392.    PUT_KEY("Enter",            "Go to");
  393.    PUT_KEY("Backspace",        "Last topic");
  394.    PUT_KEY("Escape",           "Exit help");
  395.    }
  396.  
  397.  
  398. static void printinstr(void)
  399.    {
  400.    int ctr;
  401.  
  402.    for (ctr=0; ctr<80; ctr++)
  403.      putstring(24, ctr, C_HELP_INSTR, " ");
  404.  
  405.    movecursor(24, 1);
  406.    PUT_KEY("Escape", "Abort");
  407.    }
  408.  
  409.  
  410. #undef PUT_KEY
  411.  
  412.  
  413. static void display_page(char far *title, char far *text, unsigned text_len, int page, int num_pages, int start_margin, int *num_link, LINK far *link)
  414.    {
  415.    char temp[9];
  416.  
  417.    helptitle();
  418.    helpinstr();
  419.    setattr(2, 0, C_HELP_BODY, 80*22);
  420.    putstringcenter(1, 0, 80, C_HELP_HDG, title);
  421.    sprintf(temp, "%2d of %d", page+1, num_pages);
  422.    putstring(1, 79-(6 + ((num_pages>=10)?2:1)), C_HELP_INSTR, temp);
  423.  
  424.    if (text != NULL)
  425.       display_parse_text(text, text_len, start_margin, num_link, link);
  426.  
  427.    movecursor(25, 80);     /* hide cursor */
  428.    }
  429.  
  430.  
  431.  
  432. /*
  433.  * int overlap(int a, int a2, int b, int b2);
  434.  *
  435.  * If a, a2, b, and b2 are points on a line, this function returns the
  436.  * distance of intersection between a-->a2 and b-->b2.    If there is no
  437.  * intersection between the lines this function will return a negative number
  438.  * representing the distance between the two lines.
  439.  *
  440.  * There are six possible cases of intersection between the lines:
  441.  *
  442.  *            a              a2
  443.  *            |              |
  444.  *     b     b2    |              |       b     b2
  445.  *     |---(1)---|    |              |       |---(2)---|
  446.  *            |              |
  447.  *        b    |     b2      b       |      b2
  448.  *        |------(3)----|       |------(4)-----|
  449.  *            |              |
  450.  *         b    |              |   b2
  451.  *         |------+--------(5)----------+---|
  452.  *            |              |
  453.  *            |     b       b2      |
  454.  *            |     |--(6)--|       |
  455.  *            |              |
  456.  *            |              |
  457.  *
  458.  */
  459.  
  460.  
  461. static int overlap(int a, int a2, int b, int b2)
  462.    {
  463.    if ( b < a )
  464.       {
  465.       if ( b2 >= a2 )
  466.      return ( a2 - a );           /* case (5) */
  467.  
  468.       return ( b2 - a );           /* case (1), case (3) */
  469.       }
  470.  
  471.    if ( b2 <= a2 )
  472.       return ( b2 - b );           /* case (6) */
  473.  
  474.    return ( a2 - b );               /* case (2), case (4) */
  475.    }
  476.  
  477.  
  478. static int dist(int a, int b)
  479.    {
  480.    int t = a - b;
  481.  
  482.    return (abs(t));
  483.    }
  484.  
  485.  
  486. #ifdef __TURBOC__
  487. #   pragma warn -def /* turn off "Possible use before definition" warning */
  488. #endif
  489.  
  490.  
  491.  
  492.  
  493. static int find_link_updown(LINK far *link, int num_link, int curr_link, int up)
  494.    {
  495.    int         ctr,
  496.          curr_c2,
  497.          best_overlap,
  498.          temp_overlap;
  499.    LINK far *curr,
  500.     far *temp,
  501.     far *best;
  502.    int         temp_dist;
  503.  
  504.    curr    = &link[curr_link];
  505.    best    = NULL;
  506.    curr_c2 = curr->c + curr->width - 1;
  507.  
  508.    for (ctr=0, temp=link; ctr<num_link; ctr++, temp++)
  509.       {
  510.       if ( ctr != curr_link &&
  511.        ( (up && temp->r < curr->r) || (!up && temp->r > curr->r) ) )
  512.      {
  513.      temp_overlap = overlap(curr->c, curr_c2, temp->c, temp->c+temp->width-1);
  514.      /* if >= 3 lines between, prioritize on vertical distance: */
  515.      if ((temp_dist = dist(temp->r, curr->r)) >= 4)
  516.         temp_overlap -= temp_dist * 100;
  517.  
  518.      if (best != NULL)
  519.         {
  520.         if ( best_overlap >= 0 && temp_overlap >= 0 )
  521.            {     /* if they're both under curr set to closest in y dir */
  522.            if ( dist(best->r, curr->r) > temp_dist )
  523.           best = NULL;
  524.            }
  525.         else
  526.            {
  527.            if ( best_overlap < temp_overlap )
  528.           best = NULL;
  529.            }
  530.         }
  531.  
  532.      if (best == NULL)
  533.         {
  534.         best = temp;
  535.         best_overlap = temp_overlap;
  536.         }
  537.      }
  538.       }
  539.  
  540.    return ( (best==NULL) ? -1 : (int)(best-link) );
  541.    }
  542.  
  543.  
  544. static int find_link_leftright(LINK far *link, int num_link, int curr_link, int left)
  545.    {
  546.    int         ctr,
  547.          curr_c2,
  548.          best_c2,
  549.          temp_c2,
  550.          best_dist,
  551.          temp_dist;
  552.    LINK far *curr,
  553.     far *temp,
  554.     far *best;
  555.  
  556.    curr    = &link[curr_link];
  557.    best    = NULL;
  558.    curr_c2 = curr->c + curr->width - 1;
  559.  
  560.    for (ctr=0, temp=link; ctr<num_link; ctr++, temp++)
  561.       {
  562.       temp_c2 = temp->c + temp->width - 1;
  563.  
  564.       if ( ctr != curr_link &&
  565.        ( (left && temp_c2 < curr->c) || (!left && temp->c > curr_c2) ) )
  566.      {
  567.      temp_dist = dist(curr->r, temp->r);
  568.  
  569.      if (best != NULL)
  570.         {
  571.         if ( best_dist == 0 && temp_dist == 0 )  /* if both on curr's line... */
  572.            {
  573.            if ( (  left && dist(curr->c, best_c2) > dist(curr->c, temp_c2) ) ||
  574.             ( !left && dist(curr_c2, best->c) > dist(curr_c2, temp->c) ) )
  575.           best = NULL;
  576.            }
  577.         else
  578.            {
  579.            if ( best_dist >= temp_dist )   /* if temp is closer... */
  580.           best = NULL;
  581.            }
  582.         } /* if (best...) */
  583.  
  584.      if (best == NULL)
  585.         {
  586.         best      = temp;
  587.         best_dist = temp_dist;
  588.         best_c2   = temp_c2;
  589.         }
  590.      }
  591.       } /* for */
  592.  
  593.    return ( (best==NULL) ? -1 : (int)(best-link) );
  594.    }
  595.  
  596.  
  597. #ifdef __TURBOC__
  598. #   pragma warn .def   /* back to default */
  599. #   pragma warn -par   /* now turn off "Parameter not used" warning */
  600. #endif
  601.  
  602.  
  603. static int find_link_key(LINK far *link, int num_link, int curr_link, int key)
  604.    {
  605.    switch (key)
  606.       {
  607.       case TAB:      return ( (curr_link>=num_link-1) ? -1 : curr_link+1 );
  608.       case BACK_TAB: return ( (curr_link<=0)          ? -1 : curr_link-1 );
  609.       default:         assert(0);  return (-1);
  610.       }
  611.    }
  612.  
  613.  
  614. #ifdef __TURBOC__
  615. #   pragma warn .par /* back to default */
  616. #endif
  617.  
  618.  
  619. static int do_move_link(LINK far *link, int num_link, int *curr, int (*f)(LINK far *,int,int,int), int val)
  620.    {
  621.    int t;
  622.  
  623.    if (num_link > 1)
  624.       {
  625.       if ( f == NULL )
  626.      t = val;
  627.       else
  628.      t = (*f)(link, num_link, *curr, val);
  629.  
  630.       if ( t >= 0 && t != *curr )
  631.      {
  632.      color_link(&link[*curr], C_HELP_LINK);
  633.      *curr = t;
  634.      color_link(&link[*curr], C_HELP_CURLINK);
  635.      return (1);
  636.      }
  637.       }
  638.  
  639.    return (0);
  640.    }
  641.  
  642.  
  643. static int help_topic(HIST *curr, HIST *next, int flags)
  644.    {
  645.    int         len;
  646.    int         key;
  647.    int         num_pages;
  648.    int         num_link;
  649.    int         page;
  650.    int         curr_link;
  651.    char      title[81];
  652.    long      where;
  653.    int         draw_page;
  654.    int         action;
  655.  
  656.    where     = topic_offset[curr->topic_num]+2; /* +2 to skip flags */
  657.    curr_link = curr->link;
  658.  
  659.    help_seek(where);
  660.  
  661.    read(help_file, (char *)&num_pages, sizeof(int));
  662.    assert(num_pages>0 && num_pages<=max_pages);
  663.  
  664.    farread(help_file, (char far *)page_table, 6*num_pages);
  665.  
  666.    len = 0;
  667.    read(help_file, (char *)&len, 1);
  668.    assert(len>=0 && len<81);
  669.    read(help_file, (char *)title, len);
  670.    title[len] = '\0';
  671.  
  672.    where += 2 + num_pages*6 + 1 + len + 2;
  673.  
  674.    for(page=0; page<num_pages; page++)
  675.       if (curr->topic_off >= page_table[page].offset &&
  676.       curr->topic_off <  page_table[page].offset+page_table[page].len )
  677.      break;
  678.  
  679.    assert(page < num_pages);
  680.  
  681.    action = -1;
  682.    draw_page = 2;
  683.  
  684.    do
  685.       {
  686.       if (draw_page)
  687.      {
  688.      help_seek(where+page_table[page].offset);
  689.      farread(help_file, buffer, page_table[page].len);
  690.  
  691.      num_link = 0;
  692.      display_page(title, buffer, page_table[page].len, page, num_pages,
  693.               page_table[page].margin, &num_link, link_table);
  694.  
  695.      if (draw_page==2)
  696.         {
  697.         assert(num_link<=0 || (curr_link>=0 && curr_link<num_link));
  698.         }
  699.      else if (draw_page==3)
  700.         curr_link = num_link - 1;
  701.      else
  702.         curr_link = 0;
  703.  
  704.      if (num_link > 0)
  705.         color_link(&link_table[curr_link], C_HELP_CURLINK);
  706.  
  707.      draw_page = 0;
  708.      }
  709.  
  710.       key = getakey();
  711.  
  712.       switch(key)
  713.      {
  714.      case PAGE_DOWN:
  715.         if (page<num_pages-1)
  716.            {
  717.            page++;
  718.            draw_page = 1;
  719.            }
  720.         break;
  721.  
  722.      case PAGE_UP:
  723.         if (page>0)
  724.            {
  725.            page--;
  726.            draw_page = 1;
  727.            }
  728.         break;
  729.  
  730.      case HOME:
  731.         if ( page != 0 )
  732.            {
  733.            page = 0;
  734.            draw_page = 1;
  735.            }
  736.         else
  737.            do_move_link(link_table, num_link, &curr_link, NULL, 0);
  738.         break;
  739.  
  740.      case END:
  741.         if ( page != num_pages-1 )
  742.            {
  743.            page = num_pages-1;
  744.            draw_page = 3;
  745.            }
  746.         else
  747.            do_move_link(link_table, num_link, &curr_link, NULL, num_link-1);
  748.         break;
  749.  
  750.      case TAB:
  751.         if ( !do_move_link(link_table, num_link, &curr_link, find_link_key, key) &&
  752.          page<num_pages-1 )
  753.            {
  754.            ++page;
  755.            draw_page = 1;
  756.            }
  757.         break;
  758.  
  759.      case BACK_TAB:
  760.         if ( !do_move_link(link_table, num_link, &curr_link, find_link_key, key) &&
  761.          page>0 )
  762.            {
  763.            --page;
  764.            draw_page = 3;
  765.            }
  766.         break;
  767.  
  768.      case DOWN_ARROW:
  769.         if ( !do_move_link(link_table, num_link, &curr_link, find_link_updown, 0) &&
  770.          page<num_pages-1 )
  771.            {
  772.            ++page;
  773.            draw_page = 1;
  774.            }
  775.         break;
  776.  
  777.      case UP_ARROW:
  778.         if ( !do_move_link(link_table, num_link, &curr_link, find_link_updown, 1) &&
  779.          page>0 )
  780.            {
  781.            --page;
  782.            draw_page = 3;
  783.            }
  784.         break;
  785.  
  786.      case LEFT_ARROW:
  787.         do_move_link(link_table, num_link, &curr_link, find_link_leftright, 1);
  788.         break;
  789.  
  790.      case RIGHT_ARROW:
  791.         do_move_link(link_table, num_link, &curr_link, find_link_leftright, 0);
  792.         break;
  793.  
  794.      case ESC:       /* exit help */
  795.         action = ACTION_QUIT;
  796.         break;
  797.  
  798.      case BACKSPACE:   /* prev topic */
  799.      case ALT_F1:
  800.         if (flags & F_HIST)
  801.            action = ACTION_PREV;
  802.         break;
  803.  
  804.      case F1:    /* help index */
  805.         if (!(flags & F_INDEX))
  806.            action = ACTION_INDEX;
  807.         break;
  808.  
  809.      case ENTER:
  810.      case ENTER_2:
  811.         if (num_link > 0)
  812.            {
  813.            next->topic_num = link_table[curr_link].topic_num;
  814.            next->topic_off = link_table[curr_link].topic_off;
  815.            action = ACTION_CALL;
  816.            }
  817.         break;
  818.      } /* switch */
  819.       }
  820.    while ( action == -1 );
  821.  
  822.    curr->topic_off = page_table[page].offset;
  823.    curr->link       = curr_link;
  824.  
  825.    return (action);
  826.    }
  827.  
  828.  
  829. int help(int action)
  830.    {
  831.    static char far unknowntopic_msg[] = "Unknown Help Topic";
  832.    HIST      curr;
  833.    int         oldlookatmouse;
  834.    int         oldhelpmode;
  835.    int         flags;
  836.    HIST      next;
  837.  
  838.    ENTER_OVLY(OVLY_HELP);
  839.  
  840.    if (helpmode == -1)     /* is help disabled? */
  841.       {
  842.       EXIT_OVLY;
  843.       return (0);
  844.       }
  845.  
  846.    if (help_file == -1)
  847.       {
  848.       buzzer(2);
  849.       EXIT_OVLY;
  850.       return (0);
  851.       }
  852.  
  853.    buffer = farmemalloc((long)MAX_PAGE_SIZE + sizeof(LINK)*max_links +
  854.             sizeof(PAGE)*max_pages);
  855.  
  856.    if (buffer == NULL)
  857.       {
  858.       buzzer(2);
  859.       EXIT_OVLY;
  860.       return (0);
  861.       }
  862.  
  863.    link_table = (LINK far *)(&buffer[MAX_PAGE_SIZE]);
  864.    page_table = (PAGE far *)(&link_table[max_links]);
  865.  
  866.    oldlookatmouse = lookatmouse;
  867.    lookatmouse = 0;
  868.    timer_start -= clock();
  869.    stackscreen();
  870.  
  871.    if (helpmode >= 0)
  872.       {
  873.       next.topic_num = label[helpmode].topic_num;
  874.       next.topic_off = label[helpmode].topic_off;
  875.       }
  876.    else
  877.       {
  878.       next.topic_num = helpmode;
  879.       next.topic_off = 0;
  880.       }
  881.  
  882.    oldhelpmode = helpmode;
  883.  
  884.    if (curr_hist <= 0)
  885.       action = ACTION_CALL;  /* make sure it isn't ACTION_PREV! */
  886.  
  887.    do
  888.       {
  889.       switch(action)
  890.      {
  891.      case ACTION_PREV2:
  892.         if (curr_hist > 0)
  893.            curr = hist[--curr_hist];
  894.  
  895.         /* fall-through */
  896.  
  897.      case ACTION_PREV:
  898.         if (curr_hist > 0)
  899.            curr = hist[--curr_hist];
  900.         break;
  901.  
  902.      case ACTION_QUIT:
  903.         break;
  904.  
  905.      case ACTION_INDEX:
  906.         next.topic_num = label[HELP_INDEX].topic_num;
  907.         next.topic_off = label[HELP_INDEX].topic_off;
  908.  
  909.         /* fall-through */
  910.  
  911.      case ACTION_CALL:
  912.         curr = next;
  913.         curr.link = 0;
  914.         break;
  915.      } /* switch */
  916.  
  917.       flags = 0;
  918.       if (curr.topic_num == label[HELP_INDEX].topic_num)
  919.      flags |= F_INDEX;
  920.       if (curr_hist > 0)
  921.      flags |= F_HIST;
  922.  
  923.       if ( curr.topic_num >= 0 )
  924.      action = help_topic(&curr, &next, flags);
  925.       else
  926.      {
  927.      if ( curr.topic_num == -100 )
  928.         {
  929.         print_document("FRACTINT.DOC", print_doc_msg_func, 1);
  930.         action = ACTION_PREV2;
  931.         }
  932.  
  933.      else if ( curr.topic_num == -101 )
  934.         action = ACTION_PREV2;
  935.  
  936.      else
  937.         {
  938.         display_page(unknowntopic_msg, NULL, 0, 0, 1, 0, NULL, NULL);
  939.         action = -1;
  940.         while (action == -1)
  941.            {
  942.            switch (getakey())
  943.           {
  944.           case ESC:     action = ACTION_QUIT;    break;
  945.           case ALT_F1:     action = ACTION_PREV;    break;
  946.           case F1:     action = ACTION_INDEX; break;
  947.           } /* switch */
  948.            } /* while */
  949.         }
  950.      } /* else */
  951.  
  952.       if ( action != ACTION_PREV && action != ACTION_PREV2 )
  953.      {
  954.      if (curr_hist >= MAX_HIST)
  955.         {
  956.         int ctr;
  957.  
  958.         for (ctr=0; ctr<MAX_HIST-1; ctr++)
  959.            hist[ctr] = hist[ctr+1];
  960.  
  961.         curr_hist = MAX_HIST-1;
  962.         }
  963.      hist[curr_hist++] = curr;
  964.      }
  965.       }
  966.    while (action != ACTION_QUIT);
  967.  
  968.    farmemfree((unsigned char far *)buffer);
  969.  
  970.    unstackscreen();
  971.    lookatmouse = oldlookatmouse;
  972.    helpmode = oldhelpmode;
  973.    timer_start += clock();
  974.  
  975.    EXIT_OVLY;
  976.    return(0);
  977.    }
  978.  
  979.  
  980.  
  981. static int dos_version(void)
  982.    {
  983.    union REGS r;
  984.  
  985.    r.x.ax = 0x3000;
  986.    intdos(&r, &r);
  987.  
  988.    return (r.h.al*100 + r.h.ah);
  989.    }
  990.  
  991.  
  992. static int exe_path(char *filename, char *path)
  993.    {
  994.    char *ptr;
  995.  
  996.    if (dos_version() >= 300)  /* DOS version 3.00+ ? */
  997.       {
  998. #ifdef __TURBOC__
  999.       strcpy(path, _argv[0]);
  1000. #else  /* assume MSC */
  1001.       extern char **__argv;
  1002.       strcpy(path, __argv[0]);     /* note: __argv may be undocumented in MSC */
  1003. #endif
  1004.  
  1005.       ptr = strrchr(path, '\\');
  1006.       if (ptr == NULL)
  1007.      ptr = path;
  1008.       else
  1009.      ++ptr;
  1010.       strcpy(ptr, filename);
  1011.       return (1);
  1012.       }
  1013.  
  1014.    return (0);
  1015.    }
  1016.  
  1017.  
  1018. static int find_file(char *filename, char *path)
  1019.    {
  1020.    int handle;
  1021.  
  1022.    if ( exe_path(filename, path) )
  1023.       if ( (handle=open(path, O_RDONLY)) != -1)
  1024.      {
  1025.      close(handle);
  1026.      return (1);
  1027.      }
  1028.  
  1029.    findpath(filename,path);
  1030.    return ( (path[0]) ? 1 : 0);
  1031.    }
  1032.  
  1033.  
  1034. static int _read_help_topic(int topic, int off, int len, void far *buf)
  1035.    {
  1036.    static int  curr_topic = -1;
  1037.    static long curr_base;
  1038.    static int  curr_len;
  1039.    int           read_len;
  1040.  
  1041.    if ( topic != curr_topic )
  1042.       {
  1043.       int t;
  1044.  
  1045.       curr_topic = topic;
  1046.  
  1047.       curr_base = topic_offset[topic];
  1048.  
  1049.       curr_base += 2;                   /* skip flags */
  1050.  
  1051.       help_seek(curr_base);
  1052.       read(help_file, (char *)&t, 2);           /* read num_pages */
  1053.       curr_base += 2 + t*6;               /* skip page info */
  1054.  
  1055.       if (t>0)
  1056.      help_seek(curr_base);
  1057.       t = 0;
  1058.       read(help_file, (char *)&t, 1);           /* read title_len */
  1059.       curr_base += 1 + t;               /* skip title */
  1060.  
  1061.       if (t>0)
  1062.      help_seek(curr_base);
  1063.       read(help_file, (char *)&curr_len, 2);   /* read topic len */
  1064.       curr_base += 2;
  1065.       }
  1066.  
  1067.    read_len = (off+len > curr_len) ? curr_len - off : len;
  1068.  
  1069.    if (read_len > 0)
  1070.       {
  1071.       help_seek(curr_base + off);
  1072.       farread(help_file, (char far *)buf, read_len);
  1073.       }
  1074.  
  1075.    return ( curr_len - (off+len) );
  1076.    }
  1077.  
  1078.  
  1079. int read_help_topic(int label_num, int off, int len, void far *buf)
  1080.    /*
  1081.     * reads text from a help topic.  Returns number of bytes from (off+len)
  1082.     * to end of topic.    On "EOF" returns a negative number representing
  1083.     * number of bytes not read.
  1084.     */
  1085.    {
  1086.    int ret;
  1087.  
  1088.    ENTER_OVLY(OVLY_HELP);
  1089.  
  1090.    ret = _read_help_topic(label[label_num].topic_num,
  1091.               label[label_num].topic_off + off, len, buf);
  1092.  
  1093.    EXIT_OVLY;
  1094.  
  1095.    return ( ret );
  1096.    }
  1097.  
  1098.  
  1099. #define PRINT_BUFFER_SIZE  (32767)     /* max. size of help topic in doc. */
  1100. #define TEMP_FILE_NAME       "HELP.$$$"    /* temp file for storing extraseg  */
  1101.                      /*    while printing document        */
  1102. #define MAX_NUM_TOPIC_SEC  (10)      /* max. number of topics under any */
  1103.                      /*    single section (CONTENT)     */
  1104.  
  1105.  
  1106. typedef struct PRINT_DOC_INFO
  1107.    {
  1108.    int         cnum;        /* current CONTENT num */
  1109.    int         tnum;        /* current topic num */
  1110.  
  1111.    long      content_pos;   /* current CONTENT item offset in file */
  1112.    int         num_page;        /* total number of pages in document */
  1113.  
  1114.    int         num_contents,  /* total number of CONTENT entries */
  1115.          num_topic;     /* number of topics in current CONTENT */
  1116.  
  1117.    int         topic_num[MAX_NUM_TOPIC_SEC]; /* topic_num[] for current CONTENT entry */
  1118.  
  1119.    char far *buffer;        /* text buffer */
  1120.  
  1121.    char      id[81];        /* buffer to store id in */
  1122.    char      title[81];     /* buffer to store title in */
  1123.  
  1124.    int       (*msg_func)(int pnum, int num_page);
  1125.  
  1126.    FILE     *file;        /* file to sent output to */
  1127.    int         margin;        /* indent text by this much */
  1128.    int         start_of_line; /* are we at the beginning of a line? */
  1129.    int         spaces;        /* number of spaces in a row */
  1130.    } PRINT_DOC_INFO;
  1131.  
  1132.  
  1133. void print_document(char *outfname, int (*msg_func)(int,int), int save_extraseg );
  1134.  
  1135.  
  1136. static void printerc(PRINT_DOC_INFO *info, int c, int n)
  1137.    {
  1138.    while ( n-- > 0 )
  1139.       {
  1140.       if (c==' ')
  1141.      ++info->spaces;
  1142.  
  1143.       else if (c=='\n' || c=='\f')
  1144.      {
  1145.      info->start_of_line = 1;
  1146.      info->spaces = 0;   /* strip spaces before a new-line */
  1147.      putc(c, info->file);
  1148.      }
  1149.  
  1150.       else
  1151.      {
  1152.      if (info->start_of_line)
  1153.         {
  1154.         info->spaces += info->margin;
  1155.         info->start_of_line = 0;
  1156.         }
  1157.  
  1158.      while (info->spaces > 0)
  1159.         {
  1160.         fputc(' ', info->file);
  1161.         --info->spaces;
  1162.         }
  1163.  
  1164.      fputc(c, info->file);
  1165.      }
  1166.       }
  1167.    }
  1168.  
  1169.  
  1170. static void printers(PRINT_DOC_INFO *info, char far *s, int n)
  1171.    {
  1172.    if (n > 0)
  1173.       {
  1174.       while ( n-- > 0 )
  1175.      printerc(info, *s++, 1);
  1176.       }
  1177.    else
  1178.       {
  1179.       while ( *s != '\0' )
  1180.      printerc(info, *s++, 1);
  1181.       }
  1182.    }
  1183.  
  1184.  
  1185. static int print_doc_get_info(int cmd, PD_INFO *pd, PRINT_DOC_INFO *info)
  1186.    {
  1187.    int t;
  1188.  
  1189.    switch (cmd)
  1190.       {
  1191.       case PD_GET_CONTENT:
  1192.      if ( ++info->cnum >= info->num_contents )
  1193.         return (0);
  1194.  
  1195.      help_seek( info->content_pos );
  1196.  
  1197.      read(help_file, (char *)&t, 2);    /* read flags */
  1198.      info->content_pos += 2;
  1199.      pd->new_page = (t & 1) ? 1 : 0;
  1200.  
  1201.      t = 0;
  1202.      read(help_file, (char *)&t, 1);    /* read id len */
  1203.      assert(t<80);
  1204.      read(help_file, (char *)info->id, t);    /* read the id */
  1205.      info->content_pos += 1 + t;
  1206.      info->id[t] = '\0';
  1207.  
  1208.      t = 0;
  1209.      read(help_file, (char *)&t, 1);    /* read title len */
  1210.      assert(t<80);
  1211.      read(help_file, (char *)info->title, t); /* read the title */
  1212.      info->content_pos += 1 + t;
  1213.      info->title[t] = '\0';
  1214.  
  1215.      t = 0;
  1216.      read(help_file, (char *)&t, 1);    /* read num_topic */
  1217.      assert(t<MAX_NUM_TOPIC_SEC);
  1218.      read(help_file, (char *)info->topic_num, t*2);  /* read topic_num[] */
  1219.      info->num_topic = t;
  1220.      info->content_pos += 1 + t*2;
  1221.  
  1222.      info->tnum = -1;
  1223.  
  1224.      pd->id = info->id;
  1225.      pd->title = info->title;
  1226.      return (1);
  1227.  
  1228.       case PD_GET_TOPIC:
  1229.      if ( ++info->tnum >= info->num_topic )
  1230.         return (0);
  1231.  
  1232.      t = _read_help_topic(info->topic_num[info->tnum], 0, PRINT_BUFFER_SIZE, info->buffer);
  1233.  
  1234.      assert(t <= 0);
  1235.  
  1236.      pd->curr = info->buffer;
  1237.      pd->len  = PRINT_BUFFER_SIZE + t;   /* same as ...SIZE - abs(t) */
  1238.      return (1);
  1239.  
  1240.       case PD_GET_LINK_PAGE:
  1241.      pd->i = *(int far *)(pd->s+4);
  1242.      return ( (pd->i == -1) ? 0 : 1 );
  1243.  
  1244.       case PD_RELEASE_TOPIC:
  1245.      return (1);
  1246.  
  1247.       default:
  1248.      return (0);
  1249.       }
  1250.    }
  1251.  
  1252.  
  1253. static int print_doc_output(int cmd, PD_INFO *pd, PRINT_DOC_INFO *info)
  1254.    {
  1255.    switch (cmd)
  1256.       {
  1257.       case PD_HEADING:
  1258.      {
  1259.      char line[81];
  1260.      char buff[40];
  1261.      int  width = PAGE_WIDTH + PAGE_INDENT;
  1262.      int  keep_going;
  1263.  
  1264.      if ( info->msg_func != NULL )
  1265.         keep_going = (*info->msg_func)(pd->pnum, info->num_page);
  1266.      else
  1267.         keep_going = 1;
  1268.  
  1269.      info->margin = 0;
  1270.  
  1271.      memset(line, ' ', 81);
  1272.      sprintf(buff, "Fractint Version %d.%01d%c",release/100, (release%100)/10,
  1273.                 ( (release%10) ? '0'+(release%10) : ' ') );
  1274.      memmove(line + ( (width-strlen(buff)) / 2)-4, buff, strlen(buff));
  1275.  
  1276.      sprintf(buff, "Page %d", pd->pnum);
  1277.      memmove(line + (width - strlen(buff)), buff, strlen(buff));
  1278.  
  1279.      printerc(info, '\n', 1);
  1280.      printers(info, line, width);
  1281.      printerc(info, '\n', 2);
  1282.  
  1283.      info->margin = PAGE_INDENT;
  1284.  
  1285.      return ( keep_going );
  1286.      }
  1287.  
  1288.       case PD_FOOTING:
  1289.      info->margin = 0;
  1290.      printerc(info, '\f', 1);
  1291.      info->margin = PAGE_INDENT;
  1292.      return (1);
  1293.  
  1294.       case PD_PRINT:
  1295.      printers(info, pd->s, pd->i);
  1296.      return (1);
  1297.  
  1298.       case PD_PRINTN:
  1299.      printerc(info, *pd->s, pd->i);
  1300.      return (1);
  1301.  
  1302.       case PD_PRINT_SEC:
  1303.      info->margin = TITLE_INDENT;
  1304.      if (pd->id[0] != '\0')
  1305.         {
  1306.         printers(info, pd->id, 0);
  1307.         printerc(info, ' ', 1);
  1308.         }
  1309.      printers(info, pd->title, 0);
  1310.      printerc(info, '\n', 1);
  1311.      info->margin = PAGE_INDENT;
  1312.      return (1);
  1313.  
  1314.       case PD_START_SECTION:
  1315.       case PD_START_TOPIC:
  1316.       case PD_SET_SECTION_PAGE:
  1317.       case PD_SET_TOPIC_PAGE:
  1318.       case PD_PERIODIC:
  1319.      return (1);
  1320.  
  1321.       default:
  1322.      return (0);
  1323.       }
  1324.    }
  1325.  
  1326.  
  1327. static int print_doc_msg_func(int pnum, int num_pages)
  1328.    {
  1329.    char temp[10];
  1330.    int    key;
  1331.  
  1332.    if ( pnum == -1 )    /* successful completion */
  1333.       {
  1334.       buzzer(0);
  1335.       putstringcenter(7, 0, 80, C_HELP_LINK, "Done -- Press any key");
  1336.       getakey();
  1337.       return (0);
  1338.       }
  1339.  
  1340.    if ( pnum == -2 )   /* aborted */
  1341.       {
  1342.       buzzer(1);
  1343.       putstringcenter(7, 0, 80, C_HELP_LINK, "Aborted -- Press any key");
  1344.       getakey();
  1345.       return (0);
  1346.       }
  1347.  
  1348.    if (pnum == 0)   /* initialization */
  1349.       {
  1350.       helptitle();
  1351.       printinstr();
  1352.       setattr(2, 0, C_HELP_BODY, 80*22);
  1353.       putstringcenter(1, 0, 80, C_HELP_HDG, "Generating FRACTINT.DOC");
  1354.  
  1355.       putstring(7, 30, C_HELP_BODY, "Completed:");
  1356.  
  1357.       movecursor(25,80);   /* hide cursor */
  1358.       }
  1359.  
  1360.  
  1361.    sprintf(temp, "%d%%", (int)( (100.0 / num_pages) * pnum ) );
  1362.    putstring(7, 41, C_HELP_LINK, temp);
  1363.  
  1364.    while ( keypressed() )
  1365.       {
  1366.       key = getakey();
  1367.       if ( key == ESC )
  1368.      return (0);    /* user abort */
  1369.       }
  1370.  
  1371.    return (1);     /* AOK -- continue */
  1372.    }
  1373.  
  1374. int makedoc_msg_func(int pnum, int num_pages)
  1375.    {
  1376.    if (pnum >= 0)
  1377.       {
  1378.       printf("\rcompleted %d%%", (int)( (100.0 / num_pages) * pnum ) );
  1379.       return (1);
  1380.       }
  1381.    if ( pnum == -2 )
  1382.       printf("\n*** aborted");
  1383.    printf("\n");
  1384.    return (0);
  1385.    }
  1386.  
  1387.  
  1388.  
  1389. void print_document(char *outfname, int (*msg_func)(int,int), int save_extraseg )
  1390.    {
  1391.    static char far err_no_temp[]  = "Unable to create temporary file.\n";
  1392.    static char far err_no_out[]   = "Unable to create output file.\n";
  1393.    static char far err_badwrite[] = "Error writing temporary file.\n";
  1394.    static char far err_badread[]  = "Error reading temporary file.\nSystem may be corrupt!\nSave your image and re-start FRACTINT!\n";
  1395.  
  1396.    PRINT_DOC_INFO info;
  1397.    int          success;
  1398.    int          temp_file = -1;
  1399.    char      far *msg = NULL;
  1400.  
  1401.    ENTER_OVLY(OVLY_HELP);
  1402.  
  1403.    info.buffer = MK_FP(extraseg, 0);
  1404.  
  1405.    help_seek(8L);
  1406.    read(help_file, (char *)&info.num_contents, 2);
  1407.    read(help_file, (char *)&info.num_page, 2);
  1408.  
  1409.    info.cnum = info.tnum = -1;
  1410.    info.content_pos = 12 + num_topic*4 + num_label*4;
  1411.    info.msg_func = msg_func;
  1412.  
  1413.    if ( msg_func != NULL )
  1414.       msg_func(0, info.num_page);   /* initialize */
  1415.  
  1416.    if ( save_extraseg )
  1417.       {
  1418.       if ( (temp_file=open(TEMP_FILE_NAME, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IREAD|S_IWRITE)) == -1 )
  1419.      {
  1420.      msg = err_no_temp;
  1421.      goto ErrorAbort;
  1422.      }
  1423.  
  1424.       if ( farwrite(temp_file, info.buffer, PRINT_BUFFER_SIZE) != PRINT_BUFFER_SIZE )
  1425.      {
  1426.      msg = err_badwrite;
  1427.      goto ErrorAbort;
  1428.      }
  1429.       }
  1430.  
  1431.    if ( (info.file = fopen(outfname, "wt")) == NULL )
  1432.       {
  1433.       msg = err_no_out;
  1434.       goto ErrorAbort;
  1435.       }
  1436.  
  1437.    info.margin = PAGE_INDENT;
  1438.    info.start_of_line = 1;
  1439.    info.spaces = 0;
  1440.  
  1441.    success = process_document((PD_FUNC)print_doc_get_info,
  1442.                   (PD_FUNC)print_doc_output,   &info);
  1443.    fclose(info.file);
  1444.  
  1445.    if ( save_extraseg )
  1446.       {
  1447.       if ( lseek(temp_file, 0L, SEEK_SET) != 0L )
  1448.      {
  1449.      msg = err_badread;
  1450.      goto ErrorAbort;
  1451.      }
  1452.  
  1453.       if ( farread(temp_file, info.buffer, PRINT_BUFFER_SIZE) != PRINT_BUFFER_SIZE )
  1454.      {
  1455.      msg = err_badread;
  1456.      goto ErrorAbort;
  1457.      }
  1458.       }
  1459.  
  1460. ErrorAbort:
  1461.    if (temp_file != -1)
  1462.       {
  1463.       close(temp_file);
  1464.       remove(TEMP_FILE_NAME);
  1465.       temp_file = -1;
  1466.       }
  1467.  
  1468.    if ( msg != NULL )
  1469.       {
  1470.       helptitle();
  1471.       stopmsg(1, msg);
  1472.       }
  1473.  
  1474.    else if ( msg_func != NULL )
  1475.       msg_func((success) ? -1 : -2, info.num_page );
  1476.  
  1477.    EXIT_OVLY;
  1478.    }
  1479.  
  1480.  
  1481. int init_help(void)
  1482.    {
  1483.    struct help_sig_info hs;
  1484.    char         path[81];
  1485.  
  1486.    ENTER_OVLY(OVLY_HELP);
  1487.  
  1488.    help_file = -1;
  1489.  
  1490. #ifdef TEST    /* leave this code out of the release version */
  1491.    /*
  1492.     * We don't worry about using far arrays for errors here since this code
  1493.     * won't be in the release version.
  1494.     */
  1495.  
  1496.    if ( find_file("FRACTINT.HLP", path) )
  1497.       {
  1498.       if ( (help_file = open(path, O_RDONLY|O_BINARY)) != -1 )
  1499.      {
  1500.      read(help_file, (char *)&hs, 6);
  1501.  
  1502.      if ( hs.sig != HELP_SIG )
  1503.         {
  1504.         static char far msg[] = {"Invalid help signature in FRACTINT.HLP!\n"};
  1505.     close(help_file);
  1506.     stopmsg(1, msg);
  1507.         }
  1508.  
  1509.      else if ( hs.version != HELP_VERSION )
  1510.         {
  1511.         static char far msg[] = {"Wrong help version in FRACTINT.HLP!\n"};
  1512.         close(help_file);
  1513.         stopmsg(1, msg);
  1514.         }
  1515.  
  1516.      else
  1517.         base_off = 6;
  1518.      }
  1519.       else
  1520.      {
  1521.          static char far msg[] =
  1522.          {"Help system was unable to open FRACTINT.HLP!\n"};
  1523.      stopmsg(1, msg);
  1524.      }
  1525.       }
  1526.  
  1527. #endif
  1528.  
  1529.    if ( help_file == -1 )
  1530.       {
  1531.       static char far err_no_open[]    = "Help system was unable to open FRACTINT.EXE!\n";
  1532.       static char far err_no_exe[]     = "Help system couldn't find FRACTINT.EXE!\n";
  1533.       static char far err_not_in_exe[] = "Help not found in FRACTINT.EXE!\n";
  1534.       static char far err_wrong_ver[]  = "Wrong help version in FRACTINT.EXE!\n";
  1535.  
  1536.       if ( find_file("FRACTINT.EXE", path) )
  1537.      {
  1538.      if ( (help_file = open(path, O_RDONLY|O_BINARY)) != -1 )
  1539.         {
  1540.         long help_offset;
  1541.         for (help_offset = -10L; help_offset >= -128L; help_offset--)
  1542.            {
  1543.            lseek(help_file, help_offset, SEEK_END);
  1544.            read(help_file, (char *)&hs, 10);
  1545.            if (hs.sig == HELP_SIG)  break;
  1546.            }
  1547.  
  1548.         if ( hs.sig != HELP_SIG )
  1549.            {
  1550.            close(help_file);
  1551.            help_file = -1;
  1552.            stopmsg(1, err_not_in_exe);
  1553.            }
  1554.  
  1555.         else if ( hs.version != HELP_VERSION )
  1556.            {
  1557.            close(help_file);
  1558.            help_file = -1;
  1559.            stopmsg(1, err_wrong_ver);
  1560.            }
  1561.  
  1562.         else
  1563.            base_off = hs.base;
  1564.  
  1565.         }
  1566.      else
  1567.         stopmsg(1, err_no_open);
  1568.      }
  1569.       else
  1570.      stopmsg(1, err_no_exe);
  1571.       }
  1572.  
  1573.    help_seek(0L);
  1574.  
  1575.    read(help_file, (char *)&max_pages, 2);
  1576.    read(help_file, (char *)&max_links, 2);
  1577.    read(help_file, (char *)&num_topic, 2);
  1578.    read(help_file, (char *)&num_label, 2);
  1579.    help_seek(12L);  /* skip num_contents and num_doc_pages */
  1580.  
  1581.    assert(max_pages > 0);
  1582.    assert(max_links >= 0);
  1583.    assert(num_topic > 0);
  1584.    assert(num_label > 0);
  1585.  
  1586.    /* allocate one big chunk for all three arrays */
  1587.  
  1588.    topic_offset = (long far *)farmemalloc(4L*num_topic + 4L*num_label + sizeof(HIST)*MAX_HIST);
  1589.  
  1590.    if (topic_offset == NULL)
  1591.       {
  1592.       static char far err_no_mem[] = "Not enough memory for help system!\n";
  1593.       close(help_file);
  1594.       help_file = -1;
  1595.       stopmsg(1, err_no_mem);
  1596.  
  1597.       EXIT_OVLY;      /* JIC stopmsg continues for some reason? */
  1598.       return (-2);
  1599.       }
  1600.  
  1601.    /* split off the other arrays */
  1602.  
  1603.    label = (LABEL far *)(&topic_offset[num_topic]);
  1604.    hist  = (HIST far *)(&label[num_label]);
  1605.  
  1606.    /* read in the tables... */
  1607.  
  1608.    farread(help_file, topic_offset, num_topic*4);
  1609.    farread(help_file, label, num_label*4);
  1610.  
  1611.    /* finished! */
  1612.  
  1613.    EXIT_OVLY;
  1614.    return (0);    /* success */
  1615.    }
  1616.  
  1617.  
  1618. void end_help(void)
  1619.    {
  1620.    ENTER_OVLY(OVLY_HELP);
  1621.    if (help_file != -1)
  1622.       {
  1623.       close(help_file);
  1624.       farmemfree((unsigned char far *)topic_offset);
  1625.       help_file = -1;
  1626.       }
  1627.    EXIT_OVLY;
  1628.    }
  1629.  
  1630.  
  1631.