home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / dos / fraktale / frasr192.exe / HELP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-27  |  37.0 KB  |  1,591 lines

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