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