home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / POVHELP.ZIP / source / povhelp.c < prev    next >
C/C++ Source or Header  |  1994-08-20  |  72KB  |  2,397 lines

  1.  
  2.  
  3. /****************************************************************************
  4. *                   POVHELP.C - version 1.0 - 1 July 1994
  5. *
  6. *  This module implements the main DOS help reader.
  7. *
  8. *  from Persistence of Vision Raytracer
  9. *  Copyright 1994 Persistence of Vision Team
  10. *  Copyright 1994 Christopher J. Cason.
  11. *---------------------------------------------------------------------------
  12. *  NOTICE: This source code file is provided so that users may experiment
  13. *  with enhancements to POV-Ray and to port the software to platforms other
  14. *  than those supported by the POV-Ray Team.  There are strict rules under
  15. *  which you are permitted to use this file.  The rules are in the file
  16. *  named POVLEGAL.DOC which should be distributed with this file. If
  17. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  18. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  19. *  Forum.  The latest version of POV-Ray may be found there as well.
  20. *
  21. *  POV-Ray files may also be obtained from ftp.uwa.edu.au in pub/povray.
  22. *
  23. *  This program was written in its entirety by Christopher J. Cason.
  24. *  Its use is freely and permanently granted to the POV-Team and POV users
  25. *  under the conditions specified in POVLEGAL.DOC.
  26. *
  27. *  Author : C. J. Cason (cjcason@yarrow.wt.uwa.edu.au, CIS 100032,1644)
  28. *
  29. *****************************************************************************/
  30.  
  31. /*---------------------------------------------------------------------------*/
  32. /* NOTE : If you're porting this to another architecture, don't forget that  */
  33. /*        the POV-Help database stores words and dwords in LSB-first format. */
  34. /*---------------------------------------------------------------------------*/
  35.  
  36. #include <stdio.h>
  37. #include <mem.h>
  38. #include <string.h>
  39. #include <alloc.h>
  40. #include <stdlib.h>
  41. #include <conio.h>
  42. #include <dos.h>
  43. #include <bios.h>
  44. #include <ctype.h>
  45. #include <dir.h>
  46. #include <stdarg.h>
  47. #include "help.h"
  48.  
  49. #define MAX_REF         512
  50. #define MAX_FRAGMENT    16
  51. #define MAX_LINK        64
  52. #define VSIZE_Y         55
  53. #define VSIZE_X         128
  54. #define MAX_BOOKMARK    32
  55.  
  56. #define TITLE           0x01
  57. #define COPYRIGHT       0x02
  58. #define AUTHOR          0x03
  59. #define FAQ             0x04
  60. #define HELP            0x05
  61. #define CONTENTS        0x100
  62.  
  63. #define PRESERVE        (preserve_formatting || code_fragment || line_drawing)
  64.  
  65. #ifdef max
  66. #undef max
  67. #endif
  68.  
  69. #ifdef min
  70. #undef min
  71. #endif
  72.  
  73. #define max(a,b)        ((int) (a) > (int) (b) ? (a) : (b))
  74. #define min(a,b)        ((int) (a) < (int) (b) ? (a) : (b))
  75.  
  76. #define ISALT(s)        (strcmp (s, "ALT") == 0)
  77. #define ISCTL(s)        (strcmp (s, "CTL") == 0 || strcmp (s, "CTRL") == 0)
  78.  
  79. #define COLUMNS         *(unsigned *) MK_FP (0x40, 0x4a)
  80. #define ROWSIZE         (COLUMNS * 2)
  81.  
  82. typedef struct
  83. {
  84.   unsigned char         start_vx ;
  85.   unsigned char         end_vx ;
  86.   unsigned short        id ;
  87.   unsigned short        start_vy ;
  88.   unsigned short        end_vy ;
  89. } viewer_reference ;
  90.  
  91. typedef struct
  92. {
  93.   unsigned char         start_vx ;
  94.   unsigned char         end_vx ;
  95.   unsigned short        start_vy ;
  96.   unsigned short        end_vy ;
  97.   unsigned short        length ;
  98.   unsigned long         offset ;
  99. } viewer_code_fragment ;
  100.  
  101. typedef struct
  102. {
  103.   /* these first three entries must not be changed/moved */
  104.   unsigned long         section ;
  105.   unsigned long         section_length ;
  106.   char                  is_appendix ;
  107.   char                  number [16] ;
  108.   char                  title [80] ;
  109.   unsigned              index ;
  110. } viewer_toc ;
  111.  
  112. typedef struct
  113. {
  114.   int         line ;
  115.   int         column ;
  116.   short       reference ;
  117.   short       link_number ;
  118.   short       first_line ;
  119.   unsigned    number ;
  120. } bookmark ;
  121.  
  122. int                     line = 0 ;
  123. int                     column = 0 ;
  124. char                    *title ;
  125. char                    blank [VSIZE_X] [2] ;
  126. char                    *reference_strings ;
  127. char                    **reference_string_index ;
  128. char                    *paste_ptr ;
  129. char                    paste_buffer [2048] ;
  130. char                    search_string [33] = "" ;
  131. short                   current_reference = -1 ;
  132. short                   current_code_fragment = -1 ;
  133. short                   link_number = -1 ;
  134. short                   first_line = 0 ;
  135. short                   wsize_y = 15 ;
  136. void far                *pageframe ;
  137. unsigned                x1 ;
  138. unsigned                y1 ;
  139. unsigned                x2 ;
  140. unsigned                y2 ;
  141. unsigned                emshandle ;
  142. unsigned                shell ;
  143. unsigned                base = 0xb800 ;
  144. unsigned                paste = 0 ;
  145. unsigned                home_wanted = 1 ;
  146. unsigned char           attribute = 0x1f ;
  147. unsigned char           reference ;
  148. unsigned char           highlight ;
  149. unsigned char           bold ;
  150. unsigned char           code_fragment ;
  151. unsigned char           heading ;
  152. unsigned char           line_drawing ;
  153. unsigned char           preserve_formatting ;
  154. unsigned char           table ;
  155. unsigned char           list ;
  156. unsigned char           list_entry ;
  157. unsigned char           wsize_x = 75 ;
  158. unsigned char           left_margin ;
  159. unsigned char           right_margin ;
  160. unsigned char           *virtual_screen ;
  161. unsigned char           *toc ;
  162. unsigned char           saved_screen [6600] ;
  163. unsigned char           *section ;
  164. unsigned char           vx ;
  165. unsigned long           links [MAX_LINK] ;
  166. unsigned long           *reference_index ;
  167. unsigned long           target_offset ;
  168. unsigned short          vy ;
  169. unsigned short          reference_count ;
  170. unsigned short          code_fragment_count ;
  171. unsigned short          TOCsize ;
  172. unsigned short          ignore_lines = 0 ;
  173. unsigned short          link_count ;
  174. unsigned short          target_line ;
  175. unsigned short          what_is_where [VSIZE_Y] [2] ;
  176. unsigned short          poppeddown ;
  177. unsigned short          mouseInstalled = 0 ;
  178. unsigned short          justifyOn = 1 ;
  179. unsigned short          current_bookmark = 0 ;
  180. FILE                    *inF ;
  181. bookmark                bookmarks [MAX_BOOKMARK] ;
  182. viewer_toc              tc ;
  183. viewer_reference        *references ;
  184. help_file_header        header ;
  185. viewer_code_fragment    *code_fragments ;
  186.  
  187. extern char             scancodes [] ;
  188. extern unsigned         running ;
  189. extern unsigned         counter ;
  190. extern unsigned         scancode ;
  191. extern unsigned         scanflag ;
  192. extern unsigned         popdown ;
  193.  
  194. void kbinit (void) ;
  195. void deinit (void) ;
  196.  
  197. void gotoxy (int x, int y)
  198. {
  199.   _AH = 0x02 ;
  200.   _DH = --y ;
  201.   _DL = --x ;
  202.   _BH = 0 ;
  203.   geninterrupt (0x10) ;
  204. }
  205.  
  206. unsigned astrlen (unsigned *s, unsigned width)
  207. {
  208.   unsigned    *s1 = s + width ;
  209.  
  210.   while ((char) *--s1 == ' ' && s1 > s) ;
  211.   return ((unsigned) (s1 - s)) ;
  212. }
  213.  
  214. unsigned wordcount (unsigned *s, unsigned width)
  215. {
  216.   unsigned    wc = 0 ;
  217.   unsigned    inword = 0 ;
  218.  
  219.   while (width--)
  220.   {
  221.     if (inword == 0)
  222.     {
  223.       if ((char) *s++ == ' ') continue ;
  224.       inword++ ;
  225.       wc++ ;
  226.     }
  227.     else
  228.     {
  229.       if ((char) *s++ != ' ') continue ;
  230.       inword = 0 ;
  231.     }
  232.   }
  233.   return (wc) ;
  234. }
  235.  
  236. void insertspaces (unsigned howmany, unsigned *s, unsigned width)
  237. {
  238.   unsigned    *s1 = s + width ;
  239.  
  240.   while (howmany--)
  241.   {
  242.     while ((char) *--s1 == ' ' && s1 > s) ;
  243.     if (s1 == s) return ;
  244.     while ((char) *--s1 != ' ' && s1 > s) ;
  245.     if (s1 == s) return ;
  246.     memmove (s1 + 1, s1, (width - (unsigned) (s1 - s) - 1) * 2) ;
  247.   }
  248. }
  249.  
  250. void justify (unsigned *s, unsigned width)
  251. {
  252.   int         needed ;
  253.   unsigned    wc ;
  254.  
  255.   if ((needed = width - astrlen (s, width) - 1) <= 0) return ;
  256.   if ((wc = wordcount (s, width)) == 0) return ;
  257.   while (needed > wc)
  258.   {
  259.     insertspaces (needed, s, width) ;
  260.     needed -= wc ;
  261.   }
  262.   insertspaces (needed, s, width) ;
  263. }
  264.  
  265. unsigned translate_keycode (char *keycode)
  266. {
  267.   char        str [32] ;
  268.   char        *s ;
  269.  
  270.   strncpy (str, keycode, 31) ;
  271.   if ((s = strtok (strupr (str), "-+")) == NULL) return (1) ;
  272.   if (!ISALT (s) && !ISCTL (s)) return (1) ;
  273.   scanflag = ISALT (s) ? ALT : CONTROL ;
  274.   if ((s = strtok (NULL, "-+")) == NULL) return (1) ;
  275.   if (ISALT (s) || ISCTL (s))
  276.   {
  277.     scanflag |= ISALT (s) ? ALT : CONTROL ;
  278.     if ((s = strtok (NULL, "-+")) == NULL) return (1) ;
  279.   }
  280.  
  281.   if (strcmp (strupr (s), "ESC") == 0) s = "\x1b" ;
  282.   if (strlen (s) > 1 || (unsigned char) *s > 0x7f) return (1) ;
  283.  
  284.   scancode = scancodes [*s] ;
  285.   return (0) ;
  286. }
  287.  
  288. void far *emscalloc (unsigned items, unsigned count)
  289. {
  290.   unsigned    i ;
  291.   union REGS  regs ;
  292.  
  293.   if (shell == 0) return (farcalloc (items, count)) ;
  294.  
  295.   for (i = 0 ; i < 4 ; i++)
  296.   {
  297.     regs.h.ah = 0x44 ; /* map EMS page */
  298.     regs.x.dx = emshandle ;
  299.     regs.h.al = i ; /* physical page */
  300.     regs.x.bx = i ; /* logical page */
  301.     int86 (0x67, ®s, ®s) ;
  302.     if (regs.h.ah != 0) return (NULL) ;
  303.   }
  304.  
  305.   return (pageframe) ;
  306. }
  307.  
  308. void emsfree (void *p)
  309. {
  310.   if (shell == 0)
  311.   {
  312.     farfree (p) ;
  313.     return ;
  314.   }
  315. }
  316.  
  317. unsigned emsinit (void)
  318. {
  319.   FILE        *f ;
  320.   union REGS  regs ;
  321.  
  322.   if ((f = fopen ("EMMXXXX0", "r")) == NULL) return (1) ;
  323.   fclose (f) ;
  324.   regs.h.ah = 0x46 ; /* get EMS manager version */
  325.   int86 (0x67, ®s, ®s) ;
  326.   if (regs.h.ah != 0) return (1) ;
  327.   regs.h.ah = 0x40 ; /* get EMS manager status */
  328.   int86 (0x67, ®s, ®s) ;
  329.   if (regs.h.ah != 0) return (1) ;
  330.   regs.h.ah = 0x41 ; /* get EMS page frame */
  331.   int86 (0x67, ®s, ®s) ;
  332.   if (regs.h.ah != 0) return (1) ;
  333.   pageframe = MK_FP (regs.x.bx, 0) ;
  334.   regs.h.ah = 0x43 ; /* get EMS handle and allocate memory */
  335.   regs.x.bx = 4 ;
  336.   int86 (0x67, ®s, ®s) ;
  337.   if (regs.h.ah != 0) return (1) ;
  338.   emshandle = regs.x.dx ;
  339.   return (0) ;
  340. }
  341.  
  342. void emsfinish (void)
  343. {
  344.   union REGS  regs ;
  345.  
  346.   regs.h.ah = 0x45 ; /* release EMS handle and memory */
  347.   regs.x.dx = emshandle ;
  348.   int86 (0x67, ®s, ®s) ;
  349. }
  350.  
  351. unsigned emsstore (unsigned restore)
  352. {
  353.   union REGS            regs ;
  354.   struct SREGS          sregs ;
  355.   static char           store [256] ;
  356.  
  357.   if (restore == 0)
  358.   {
  359.     regs.x.ax = 0x4e00 ; /* get mapping registers */
  360.     regs.x.di = FP_OFF (store) ;
  361.     sregs.es = FP_SEG (store) ;
  362.     int86x (0x67, ®s, ®s, &sregs) ;
  363.     if (regs.h.ah != 0) return (1) ;
  364.   }
  365.   else
  366.   {
  367.     regs.x.ax = 0x4e01 ; /* set mapping registers */
  368.     regs.x.si = FP_OFF (store) ;
  369.     sregs.ds = FP_SEG (store) ;
  370.     int86x (0x67, ®s, ®s, &sregs) ;
  371.     if (regs.h.ah != 0) return (1) ;
  372.   }
  373.   return (0) ;
  374. }
  375.  
  376. void mousestate (unsigned show)
  377. {
  378.   union REGS  regs ;
  379.  
  380.   if (mousestate == 0) return ;
  381.   regs.x.ax = show ? 0x01 : 0x02 ;
  382.   int86 (0x33, ®s, ®s) ;
  383. }
  384.  
  385. void message_printf (char *format, ...)
  386. {
  387.   static char str [140] ;
  388.   char        *s1 = str ;
  389.   char far    *s2 = MK_FP (base, (y2 + 1) * ROWSIZE + x1 * 2) ;
  390.   unsigned    i ;
  391.   va_list     arg_ptr ;
  392.  
  393.   va_start (arg_ptr, format) ;
  394.   vsprintf (str, format, arg_ptr) ;
  395.   va_end (arg_ptr) ;
  396.  
  397.   for (i = 0 ; i < wsize_x - 1 ; i++)
  398.   {
  399.     *s2++ = *s1 ? *s1++ : ' ' ;
  400.     *s2++ = 0x0e ;
  401.   }
  402. }
  403.  
  404. unsigned message_gets (char *prompt, char *s, unsigned length)
  405. {
  406.   char        ch ;
  407.   unsigned    index = strlen (s) ;
  408.   unsigned    changed = 0 ;
  409.  
  410.   while (1)
  411.   {
  412.     message_printf ("%s : %s", prompt, s) ;
  413.     gotoxy (x1 + strlen (prompt) + index + 4, y2 + 2) ;
  414.     while (popdown == 0 && bioskey (0x11) == 0) geninterrupt (0x28) ;
  415.     if (popdown) return (1) ;
  416.     ch = bioskey (0x10) ;
  417.     switch ((unsigned char) ch)
  418.     {
  419.       case '\r'   :
  420.       case '\n'   :
  421.       case '\x1b' : gotoxy (COLUMNS + 1, 50) ;
  422.                     message_printf ("") ;
  423.                     return (ch == 0x1b) ;
  424.       case '\b'   : if (index == 0) break ;
  425.                     s [--index] = '\0' ;
  426.                     changed++ ;
  427.                     break ;
  428.       default     : if (ch < 0x20 || ch > 0x7f) break ;
  429.                     if (index >= length) break ;
  430.                     if (changed++ == 0) index = 0 ;
  431.                     s [index++] = ch ;
  432.                     s [index] = '\0' ;
  433.                     break ;
  434.     }
  435.   }
  436.   return (0) ;
  437. }
  438.  
  439. void localdelay (unsigned milliseconds)
  440. {
  441.   if (shell)
  442.   {
  443.     counter = milliseconds / 55 ;
  444.     while (counter && counter--) ++counter ; /* make compiler happy ; it doesn't understand volatile */
  445.   }
  446.   else
  447.     delay (milliseconds) ;
  448. }
  449.  
  450. unsigned ustrcmp (char *s1, char *s2)
  451. {
  452.   while (*s1 && *s2)
  453.     if (toupper (*s1++) != toupper (*s2++))
  454.       return (1) ;
  455.   return (*s1 || *s2) ;
  456. }
  457.  
  458. void frame (void)
  459. {
  460.   unsigned    x ;
  461.   unsigned    y ;
  462.   unsigned    *ptr ;
  463.  
  464.   x1 = (COLUMNS - wsize_x) / 2 - 1 ;
  465.   y1 = (25 - wsize_y) / 2 - 2 ;
  466.   x2 = x1 + wsize_x + 1 ;
  467.   y2 = y1 + wsize_y + 1 ;
  468.  
  469.   ptr = MK_FP (base, y1 * ROWSIZE + x1 * 2) ;
  470.   for (x = x1 ; x < x2 ; x++) *ptr++ = ('─\x0f') ;
  471.   ptr = MK_FP (base, y2 * ROWSIZE + x1 * 2) ;
  472.   for (x = x1 ; x < x2 ; x++) *ptr++ = ('─\x0f') ;
  473.   ptr = MK_FP (base, (y2 + 2) * ROWSIZE + x1 * 2) ;
  474.   for (x = x1 ; x < x2 ; x++) *ptr++ = ('─\x0f') ;
  475.   for (y = y1 ; y < y2 + 2 ; y++)
  476.   {
  477.     *(unsigned *) MK_FP (base, y * ROWSIZE + x1 * 2) = '│\x0f' ;
  478.     *(unsigned *) MK_FP (base, y * ROWSIZE + x2 * 2) = '│\x0f' ;
  479.   }
  480.   *(unsigned *) MK_FP (base, y1 * ROWSIZE + x1 * 2) = '┌\x0f' ;
  481.   *(unsigned *) MK_FP (base, y1++ * ROWSIZE + x2 * 2) = '┐\x0f' ;
  482.   *(unsigned *) MK_FP (base, y2 * ROWSIZE + x1 * 2) = '├\x0f' ;
  483.   *(unsigned *) MK_FP (base, y2 * ROWSIZE + x2 * 2) = '┤\x0f' ;
  484.   *(unsigned *) MK_FP (base, (y2 + 2) * ROWSIZE + x1++ * 2) = '└\x0f' ;
  485.   *(unsigned *) MK_FP (base, (y2-- + 2) * ROWSIZE + x2-- * 2) = '┘\x0f' ;
  486.   *(unsigned *) MK_FP (base, (y2 + 2) * ROWSIZE + x1++ * 2) = ' \x0f' ;
  487.   *(unsigned *) MK_FP (base, (y2++ + 2) * ROWSIZE + x2++ * 2) = ' \x0f' ;
  488.   y1++ ;
  489.   left_margin = 0 ;
  490.   right_margin = wsize_x ;
  491.   gotoxy (COLUMNS + 1, 50) ;
  492. }
  493.  
  494. void get_line (unsigned line, char *s)
  495. {
  496.   char far    *_s = MK_FP (base, line * ROWSIZE) ;
  497.   unsigned    i ;
  498.  
  499.   for (i = 0 ; i < COLUMNS ; i++)
  500.   {
  501.     *s++ = *_s++ ;
  502.     _s++ ;
  503.   }
  504.   *s++ = '\x00' ;
  505. }
  506.  
  507. void putwindow (unsigned column, unsigned line)
  508. {
  509.   char        *s2 = virtual_screen + line * VSIZE_X * 2 + column * 2 ;
  510.   char far    *s1 = MK_FP (base, (y1 - 1) * ROWSIZE + (x1 - 1) * 2) ;
  511.   unsigned    width2 = VSIZE_X * 2 ;
  512.   unsigned    width1 = wsize_x * 2 ;
  513.   unsigned    count ;
  514.  
  515.   for (count = 0 ; count < wsize_y ; count++)
  516.   {
  517.     memcpy (s1, (line + count < VSIZE_Y) ? (char *) s2 : (char *) blank, width1) ;
  518.     s1 += ROWSIZE ;
  519.     s2 += width2 ;
  520.   }
  521. }
  522.  
  523. void highlight_line (unsigned line, char attribute)
  524. {
  525.   char        *s = MK_FP (base, (y1 + line - 1) * ROWSIZE + (x1 - 1) * 2 + 1) ;
  526.   unsigned    count ;
  527.  
  528.   for (count = wsize_x ; count ; count--, s += 2) *s = attribute ;
  529. }
  530.  
  531. void write_attribute (unsigned x1, unsigned y1, unsigned x2, unsigned y2, char attribute)
  532. {
  533.   char        *s = virtual_screen + y1 * VSIZE_X * 2 + x1 * 2 ;
  534.   unsigned    count = (y2 * VSIZE_X + x2) - (y1 * VSIZE_X + x1) ;
  535.  
  536.   if (y2 < y1) return ;
  537.   if (y2 == y1 && x2 < x1) return ;
  538.   while (count--)
  539.   {
  540.     *++s = attribute ;
  541.     s++ ;
  542.   }
  543. }
  544.  
  545. void clear_attributes (void)
  546. {
  547.   reference = highlight = bold = code_fragment = 0 ;
  548.   heading = line_drawing = preserve_formatting = 0 ;
  549.   table = list = list_entry = 0 ;
  550. }
  551.  
  552. void set_attribute (void)
  553. {
  554.   attribute = 0x1f ;
  555.   if (code_fragment) attribute = 0x1a ;
  556.   if (heading) attribute = 0x1c ;
  557.   if (line_drawing) attribute = 0x1b ;
  558.   if (list_entry) attribute = 0x1e ;
  559.   if (bold) attribute = 0x2f ;
  560.   if (highlight) attribute = 0x1e ;
  561.   if (bold && highlight) attribute = 0x2e ;
  562.   if (reference) attribute = 0x3f ;
  563. }
  564.  
  565. viewer_reference *create_reference (unsigned short id)
  566. {
  567.   if (reference_count == MAX_REF) return (NULL) ;
  568.   references [reference_count].id = id ;
  569.   return (references + reference_count++) ;
  570. }
  571.  
  572. void clear_references (void)
  573. {
  574.   reference_count = 0 ;
  575. }
  576.  
  577. viewer_code_fragment *create_code_fragment (void)
  578. {
  579.   if (code_fragment_count == MAX_FRAGMENT) return (NULL) ;
  580.   return (code_fragments + code_fragment_count++) ;
  581. }
  582.  
  583. void clear_code_fragments (void)
  584. {
  585.   code_fragment_count = 0 ;
  586. }
  587.  
  588. viewer_toc *getTC (unsigned index)
  589. {
  590.   char                  *s ;
  591.   static viewer_toc     result ;
  592.  
  593.   if (index >= header.section_count + header.appendix_count) index = 0 ;
  594.   s = toc + (unsigned) ((unsigned long) TOCsize * index) ;
  595.   memcpy (&result, s, sizeof (TOC_entry)) ;
  596.   s += sizeof (TOC_entry) ;
  597.   strcpy (result.number, s) ;
  598.   strcpy (result.title, s + header.sec_number_len) ;
  599.   result.index = index ;
  600.   return (&result) ;
  601. }
  602.  
  603. viewer_toc *findTCfromOffset (unsigned long offset)
  604. {
  605.   unsigned              i ;
  606.   static viewer_toc     result ;
  607.  
  608.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  609.   {
  610.     result = *getTC (i) ;
  611.     if (result.section > offset) continue ;
  612.     if (result.section + result.section_length <= offset) continue ;
  613.     return (&result) ;
  614.   }
  615.   return (NULL) ;
  616. }
  617.  
  618. char *get_section (viewer_toc *tc, unsigned number)
  619. {
  620.   unsigned              count ;
  621.   unsigned char         *section ;
  622.  
  623.   *tc = *getTC (number) ;
  624.   fseek (inF, tc->section, SEEK_SET) ;
  625.   if (tc->section_length + 1 > 65534U)
  626.   {
  627.     message_printf ("section too big for present allocation code") ;
  628.     localdelay (1000) ;
  629.     return (NULL) ;
  630.   }
  631.   if ((section = emscalloc ((unsigned) tc->section_length + 1, 1)) == NULL)
  632.   {
  633.     message_printf ("error - cannot allocate enough memory for section %s", tc->number) ;
  634.     localdelay (1000) ;
  635.     return (NULL) ;
  636.   }
  637.   if (fread (section, (unsigned) tc->section_length + 1, 1, inF) == 0)
  638.   {
  639.     message_printf ("could not read section") ;
  640.     localdelay (1000) ;
  641.     return (NULL) ;
  642.   }
  643.   count = (unsigned) tc->section_length ;
  644.   while (section [count - 1] == '\n' || section [count - 1] == PARAGRAPH) count-- ;
  645.   section [count] = '\0' ;
  646.   return (section) ;
  647. }
  648.  
  649. unsigned findSection (char *s)
  650. {
  651.   unsigned              i ;
  652.   viewer_toc            result ;
  653.  
  654.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  655.   {
  656.     result = *getTC (i) ;
  657.     if (ustrcmp (s, result.number)) continue ;
  658.     return (i) ;
  659.   }
  660.   return (-1) ;
  661. }
  662.  
  663. unsigned findTitle (char *s)
  664. {
  665.   static char           str [80] ;
  666.   unsigned              i ;
  667.   viewer_toc            result ;
  668.  
  669.   strupr (s) ;
  670.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  671.   {
  672.     result = *getTC (i) ;
  673.     if (ustrcmp (s, result.title)) continue ;
  674.     return (i) ;
  675.   }
  676.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  677.   {
  678.     result = *getTC (i) ;
  679.     strcpy (str, result.title) ;
  680.     strupr (str) ;
  681.     if (strstr (str, s) == NULL) continue ;
  682.     return (i) ;
  683.   }
  684.   return (-1) ;
  685. }
  686.  
  687. unsigned findKeyword (char *s)
  688. {
  689.   unsigned              i ;
  690.  
  691.   for (i = 0 ; i < header.reference_count ; i++)
  692.     if (ustrcmp (s, reference_string_index [i]) == 0)
  693.       return (i) ;
  694.   return (-1) ;
  695. }
  696.  
  697. unsigned virtual_screen_full (void)
  698. {
  699.   return (vy >= VSIZE_Y) ;
  700. }
  701.  
  702. void clear_virtual_screen (void)
  703. {
  704.   char        *s = virtual_screen ;
  705.   unsigned    count = (unsigned) VSIZE_X * VSIZE_Y ;
  706.  
  707.   vx = 0 ;
  708.   vy = 0 ;
  709.   left_margin = 0 ;
  710.   right_margin = wsize_x ;
  711.  
  712.   while (count--)
  713.   {
  714.     *s++ = ' ' ;
  715.     *s++ = attribute ;
  716.   }
  717. }
  718.  
  719. unsigned line_is_blank (unsigned line)
  720. {
  721.   char        *s = virtual_screen + line * VSIZE_X * 2 ;
  722.   unsigned    count = (unsigned) VSIZE_X ;
  723.  
  724.   while (count--)
  725.   {
  726.     if (*s != ' ') return (0) ;
  727.     s += 2 ;
  728.   }
  729.   return (1) ;
  730. }
  731.  
  732. void vputchar (unsigned char ch)
  733. {
  734.   char        *s ;
  735.  
  736.   if (vy >= VSIZE_Y) return ;
  737.  
  738.   switch (ch)
  739.   {
  740.     case '\r' :
  741.          vx = 0 ;
  742.          return ;
  743.  
  744.     case '\n' :
  745.          vx = VSIZE_X ;
  746.          break ;
  747.  
  748.     default :
  749.          if (vx >= VSIZE_X) return ;
  750.          if (ignore_lines) break ;
  751.          s = virtual_screen + (unsigned) vy * VSIZE_X * 2 + vx * 2 ;
  752.          *s++ = ch ;
  753.          *s++ = attribute ;
  754.          break ;
  755.   }
  756.  
  757.   if (++vx >= VSIZE_X)
  758.   {
  759.     if (ch == '\n' || !PRESERVE)
  760.     {
  761.       vx = left_margin ;
  762.       if (ignore_lines)
  763.       {
  764.         --ignore_lines ;
  765.         return ;
  766.       }
  767.       if (++vy >= VSIZE_Y) vy = VSIZE_Y ;
  768.     }
  769.   }
  770. }
  771.  
  772. void vputchar_attr (unsigned char ch, unsigned char attr)
  773. {
  774.   unsigned char         a = attribute ;
  775.  
  776.   attribute = attr ;
  777.   vputchar (ch) ;
  778.   attribute = a ;
  779. }
  780.  
  781. void vputstr (char *s)
  782. {
  783.   while (*s)
  784.     vputchar (*s++) ;
  785. }
  786.  
  787. void cvputstr (char *s, unsigned type)
  788. {
  789.   static char str [256] ;
  790.   char        *s1 = str ;
  791.   unsigned    count ;
  792.  
  793.   for (count = 0 ;; s++)
  794.   {
  795.     if (*s == '\n' || *s == '\0')
  796.     {
  797.       what_is_where [vy] [0] = type ;
  798.       vx = (wsize_x - min (wsize_x, count)) / 2 ;
  799.       for (s1 = str ; count ; count--)
  800.         vputchar (*s1++) ;
  801.       vputchar ('\n') ;
  802.       if (*s == '\0') break ;
  803.       s1 = str ;
  804.       continue ;
  805.     }
  806.     *s1++ = *s ;
  807.     count++ ;
  808.   }
  809. }
  810.  
  811. unsigned pointcount (char *s)
  812. {
  813.   unsigned    count = 0 ;
  814.  
  815.   while (*s)
  816.     if (*s++ == '.')
  817.       count++ ;
  818.   return (count) ;
  819. }
  820.  
  821. void vcachechar (char ch)
  822. {
  823.   char                  *s ;
  824.   static char           str [128] ;
  825.   static unsigned       count = 0 ;
  826.  
  827.   if (ch == '\0' || ch == ' ' || ch == '\t' || ch == '\n' || count == 128)
  828.   {
  829.     if (count / 2 > right_margin - vx)
  830.     {
  831.       if (justifyOn && !list)
  832.         justify ((unsigned *) (virtual_screen + (unsigned) vy * VSIZE_X * 2), wsize_x) ;
  833.       vputchar ('\n') ;
  834.     }
  835.     for (s = str ; count ; count -= 2, s += 2)
  836.       if (*s != ' ' || vx != left_margin)
  837.         vputchar_attr (s [0], s [1]) ;
  838.     if (ch == '\0') return ;
  839.   }
  840.   if (PRESERVE)
  841.   {
  842.     vputchar (ch) ;
  843.     return ;
  844.   }
  845.   str [count++] = ch ;
  846.   str [count++] = attribute ;
  847. }
  848.  
  849. void redraw_references (void)
  850. {
  851.   char                  attribute ;
  852.   unsigned              i ;
  853.   viewer_reference      *r ;
  854.  
  855.   if (current_reference < 0) return ;
  856.   for (i = 0, r = references ; i < reference_count ; i++, r++)
  857.   {
  858.     attribute = i == current_reference ? 0x4f : 0x3f ;
  859.     write_attribute (r->start_vx, r->start_vy, r->end_vx, r->end_vy, attribute) ;
  860.   }
  861. }
  862.  
  863. void redraw_code_fragments (void)
  864. {
  865.   char                  attribute ;
  866.   unsigned              i ;
  867.   viewer_code_fragment  *f ;
  868.  
  869.   if (current_code_fragment < 0) return ;
  870.   for (i = 0, f = code_fragments ; i < code_fragment_count ; i++, f++)
  871.   {
  872.     attribute = i == current_code_fragment ? 0x6f : 0x1a ;
  873.     write_attribute (f->start_vx, f->start_vy, f->end_vx, f->end_vy, attribute) ;
  874.   }
  875. }
  876.  
  877. void format_section (viewer_toc *tc, char *section)
  878. {
  879.   unsigned              id ;
  880.   unsigned              look_for_target = target_offset != 0 ;
  881.   unsigned              escape = 0 ;
  882.   unsigned char         *s ;
  883.   viewer_reference      *r ;
  884.   viewer_code_fragment  *f ;
  885.  
  886.   clear_attributes () ;
  887.   set_attribute () ;
  888.   clear_references () ;
  889.   clear_code_fragments () ;
  890.   clear_virtual_screen () ;
  891.   ignore_lines = first_line ;
  892.   target_line = 0 ;
  893.   if (tc)
  894.   {
  895.     heading++ ;
  896.     set_attribute () ;
  897.     if (tc->is_appendix) vputstr ("APPENDIX ") ;
  898.     vputstr (tc->number) ;
  899.     vx = 17 ;
  900.     vputstr (tc->title) ;
  901.     heading = 0 ;
  902.     vcachechar ('\n') ;
  903.     vcachechar ('\n') ;
  904.     set_attribute () ;
  905.   }
  906.  
  907.   while (*section == '\n' || (unsigned char) *section == PARAGRAPH) section++ ;
  908.  
  909.   for (s = section ; *s ; s++)
  910.   {
  911.     if (virtual_screen_full ())
  912.     {
  913.       if (look_for_target)
  914.       {
  915.         first_line += vy ;
  916.         clear_references () ;
  917.         clear_code_fragments () ;
  918.         clear_virtual_screen () ;
  919.       }
  920.       else
  921.         break ;
  922.     }
  923.  
  924.     if (look_for_target && s - section >= target_offset)
  925.     {
  926.       target_line = vy ;
  927.       look_for_target = 0 ;
  928.     }
  929.  
  930.     if (escape == 0)
  931.     {
  932.       switch (*s)
  933.       {
  934.         case ESCAPE :
  935.              escape++ ;
  936.              break ;
  937.  
  938.         case PARAGRAPH :
  939.              vcachechar ('\n') ;
  940.              vcachechar ('\n') ;
  941.              break ;
  942.  
  943.         case INDENT :
  944.              if (vx > 3) vcachechar ('\n') ;
  945.              vx = 3 ;
  946.              break ;
  947.  
  948.         case REFERENCE :
  949.              id = *++s ;
  950.              id += (unsigned) *++s * 256 ;
  951.              r = create_reference (id) ;
  952.              break ;
  953.  
  954.         case TARGET :
  955.              break ;
  956.  
  957.         case REFERENCE_ON :
  958.              if (r == NULL) break ;
  959.              vcachechar ('\0') ;
  960.              r->start_vx = vx ;
  961.              r->start_vy = vy ;
  962.              reference++ ;
  963.              set_attribute () ;
  964.              break ;
  965.  
  966.         case REFERENCE_OFF :
  967.              if (r == NULL) break ;
  968.              vcachechar ('\0') ;
  969.              r->end_vx = vx ;
  970.              r->end_vy = vy ;
  971.              reference = 0 ;
  972.              r = NULL ;
  973.              set_attribute () ;
  974.              break ;
  975.  
  976.         case HIGHLIGHT_ON :
  977.         case HIGHLIGHT_OFF :
  978.              highlight = *s == HIGHLIGHT_ON ;
  979.              set_attribute () ;
  980.              break ;
  981.  
  982.         case BOLD_ON :
  983.         case BOLD_OFF :
  984.              bold = *s == BOLD_ON ;
  985.              set_attribute () ;
  986.              break ;
  987.  
  988.         case CODE_ON :
  989.              code_fragment++ ;
  990.              set_attribute () ;
  991.              vcachechar ('\0') ;
  992.              if ((f = create_code_fragment ()) == NULL) break ;
  993.              f->start_vx = vx ;
  994.              f->start_vy = vy ;
  995.              f->length = 0 ;
  996.              f->offset = (unsigned long) s + 1 ;
  997.              break ;
  998.  
  999.         case CODE_OFF :
  1000.              code_fragment = 0 ;
  1001.              set_attribute () ;
  1002.              vcachechar ('\0') ;
  1003.              if (f == NULL) break ;
  1004.              f->end_vx = vx ;
  1005.              f->end_vy = vy ;
  1006.              f->length = (unsigned long) ((unsigned long) s - f->offset) - 1 ;
  1007.              f = NULL ;
  1008.              break ;
  1009.  
  1010.         case HEADING_ON :
  1011.         case HEADING_OFF :
  1012.              heading = *s == HEADING_ON ;
  1013.              set_attribute () ;
  1014.              break ;
  1015.  
  1016.         case LINE_ON :
  1017.         case LINE_OFF :
  1018.              line_drawing = *s == LINE_ON ;
  1019.              set_attribute () ;
  1020.              vcachechar ('\0') ;
  1021.              break ;
  1022.  
  1023.         case PRESERVE_ON :
  1024.         case PRESERVE_OFF :
  1025.              preserve_formatting = *s == PRESERVE_ON ;
  1026.              set_attribute () ;
  1027.              vcachechar ('\0') ;
  1028.              break ;
  1029.  
  1030.         case TABLE_ON :
  1031.         case TABLE_OFF :
  1032.              table = *s == TABLE_ON ;
  1033.              set_attribute () ;
  1034.              break ;
  1035.  
  1036.         case LIST_ON :
  1037.              if ((list = *++s) == 1) list++ ;
  1038.              left_margin = list += 2 ;
  1039.              break ;
  1040.  
  1041.         case LIST_OFF :
  1042.              left_margin = list = 0 ;
  1043.              break ;
  1044.  
  1045.         case LIST_ENTRY_ON :
  1046.              list_entry++ ;
  1047.              vcachechar ('\0') ;
  1048.              set_attribute () ;
  1049.              vx = 2 ;
  1050.              break ;
  1051.  
  1052.         case LIST_ENTRY_OFF :
  1053.              list_entry = 0 ;
  1054.              vcachechar ('\0') ;
  1055.              set_attribute () ;
  1056.              vx = left_margin ;
  1057.              while (*s == ' ') s++ ;
  1058.              break ;
  1059.  
  1060.         default :
  1061.              vcachechar (*s) ;
  1062.              break ;
  1063.       }
  1064.     }
  1065.     else
  1066.     {
  1067.       vcachechar (*s) ;
  1068.       escape = 0 ;
  1069.     }
  1070.   }
  1071.   vcachechar ('\0') ;
  1072.   while (vy > 0 && line_is_blank (vy)) vy-- ;
  1073.   if (reference)
  1074.   {
  1075.     reference_count-- ;
  1076.     reference = 0 ;
  1077.   }
  1078.   target_offset = 0 ;
  1079.   redraw_references () ;
  1080.   redraw_code_fragments () ;
  1081. }
  1082.  
  1083. void format_top_menu (unsigned number_to_find)
  1084. {
  1085.   unsigned              i ;
  1086.   unsigned              offset ;
  1087.   viewer_toc            tc ;
  1088.  
  1089.   clear_attributes () ;
  1090.   set_attribute () ;
  1091.   clear_references () ;
  1092.   clear_virtual_screen () ;
  1093.   memset (what_is_where, 0, sizeof (what_is_where)) ;
  1094.   ignore_lines = number_to_find == 0 ? first_line : 32767 ;
  1095.   target_line = 0 ;
  1096.  
  1097.   vputstr ("\r\n") ;
  1098.   attribute = 0x1e ;
  1099.   cvputstr (title, TITLE) ;
  1100.   attribute = 0x1a ;
  1101.  
  1102.   cvputstr ("HELP ON HELP", HELP) ;
  1103.   cvputstr ("COPYRIGHT", COPYRIGHT) ;
  1104.   cvputstr ("AUTHORS", AUTHOR) ;
  1105.   cvputstr ("FREQUENTLY ASKED QUESTIONS", FAQ) ;
  1106.  
  1107.   vputstr ("\r\n") ;
  1108.   attribute = 0x1f ;
  1109.  
  1110.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  1111.   {
  1112.     if (number_to_find)
  1113.       ignore_lines = i < number_to_find ? 32767 : 0 ;
  1114.     if (i == header.section_count)
  1115.     {
  1116.       vputstr ("\r\n") ;
  1117.       attribute = 0x1a ;
  1118.       cvputstr ("*** APPENDICES ***", 0) ;
  1119.       attribute = 0x1f ;
  1120.       vputstr ("\r\n") ;
  1121.     }
  1122.     tc = *getTC (i) ;
  1123.     what_is_where [vy] [0] = CONTENTS ;
  1124.     what_is_where [vy] [1] = i ;
  1125.     offset = pointcount (tc.number) * 3 ;
  1126.     vx = offset ;
  1127.     vputstr (tc.number) ;
  1128.     vx = 17 + offset ;
  1129.     vputstr (tc.title) ;
  1130.     vputstr ("\r\n") ;
  1131.   }
  1132.   while (vy > 0 && line_is_blank (vy)) vy-- ;
  1133. }
  1134.  
  1135. void format_general_text (char *s)
  1136. {
  1137.   clear_attributes () ;
  1138.   set_attribute () ;
  1139.   clear_references () ;
  1140.   clear_virtual_screen () ;
  1141.   memset (what_is_where, 0, sizeof (what_is_where)) ;
  1142.   ignore_lines = first_line ;
  1143.   target_line = 0 ;
  1144.  
  1145.   attribute = 0x1e ;
  1146.   cvputstr (s, 0) ;
  1147.   while (vy > 0 && line_is_blank (vy)) vy-- ;
  1148. }
  1149.  
  1150. void load_links (void)
  1151. {
  1152.   unsigned    child_count ;
  1153.  
  1154.   link_count = 0 ;
  1155.   link_number = -1 ;
  1156.   if (current_reference == -1) return ;
  1157.   fseek (inF, reference_index [references [current_reference].id], SEEK_SET) ;
  1158.   fread (&child_count, 2, 1, inF) ;
  1159.   if (child_count >= MAX_LINK - 1) child_count = MAX_LINK - 1 ;
  1160.   fread (links, 4, link_count = child_count + 1, inF) ;
  1161. }
  1162.  
  1163. void push_context (int number, short first_line, int line, int column, short current_reference, short link_number)
  1164. {
  1165.   bookmark    *bm = bookmarks + current_bookmark ;
  1166.  
  1167. /*message_printf ("saved %d %d %d %d [%d]", number, first_line, line, column, current_bookmark) ;
  1168.   localdelay (1000) ; */
  1169.   if (current_bookmark >= MAX_BOOKMARK)
  1170.   {
  1171.     memcpy (bookmarks, bookmarks + 1, sizeof (bookmarks) - sizeof (bookmark)) ;
  1172.     bm-- ;
  1173.   }
  1174.   else
  1175.     current_bookmark++ ;
  1176.   bm->number = number ;
  1177.   bm->first_line = first_line ;
  1178.   bm->line = line ;
  1179.   bm->column = column ;
  1180.   bm->reference = current_reference ;
  1181.   bm->link_number = link_number ;
  1182. }
  1183.  
  1184. void pop_context (int *number, short *first_line, int *line, int *column, short *current_reference, short *link_number)
  1185. {
  1186.   bookmark    *bm ;
  1187.  
  1188.   if (current_bookmark == 0) return ;
  1189.   bm = bookmarks + --current_bookmark ;
  1190.   if (number) *number = bm->number ;
  1191.   if (first_line) *first_line = bm->first_line ;
  1192.   if (line) *line = bm->line ;
  1193.   if (column) *column = bm->column ;
  1194.   if (current_reference) *current_reference = bm->reference ;
  1195.   if (link_number) *link_number = bm->link_number ;
  1196. /*message_printf ("restored %d %d %d %d [%d]", *number, *first_line, *line, *column, current_bookmark) ;
  1197.   localdelay (1000) ; */
  1198. }
  1199.  
  1200. void display (int *number, unsigned use_link, unsigned use_stack)
  1201. {
  1202.   int                   ch ;
  1203.   short                 reference ;
  1204.   short                 code_fragment ;
  1205.   unsigned              i ;
  1206.   unsigned              child_count ;
  1207.   unsigned              bounce_me = 0 ;
  1208.   unsigned              temp ;
  1209.   viewer_toc            *t ;
  1210.   viewer_reference      *r ;
  1211.   viewer_code_fragment  *f ;
  1212.  
  1213.   /* if use_stack is TRUE, restore our position from the position stack       */
  1214.   /* if use_link is TRUE, 'number' is an index into the reference array       */
  1215.   /* bounce_me is set internally to cause a jump to reference index 'number'  */
  1216.   /* use_link takes precedence over use_stack                                 */
  1217.  
  1218.   while (1)
  1219.   {
  1220.     line = column = 0 ;
  1221.     if (section) emsfree (section) ;
  1222.     if (use_link || bounce_me)
  1223.     {
  1224.       /* link_number is the currently selected link  */
  1225.       link_number = 0 ;
  1226.       fseek (inF, reference_index [*number], SEEK_SET) ;
  1227.       fread (&child_count, 2, 1, inF) ;
  1228.  
  1229.       /* only support MAX_LINK children (links) */
  1230.       if (child_count >= MAX_LINK - 1) child_count = MAX_LINK - 1 ;
  1231.  
  1232.       /* retrieve the actual links from the file  */
  1233.       fread (links, 4, link_count = child_count + 1, inF) ;
  1234.  
  1235.       /* find TOC entry for the section, working it out from the offset */
  1236.       if ((t = findTCfromOffset (links [0])) == NULL)
  1237.       {
  1238.         message_printf ("link 0 [%08lx] not found", links [0]) ;
  1239.         return ;
  1240.       }
  1241.  
  1242.       /* get the section ; the index is assigned to number */
  1243.       section = get_section (&tc, *number = t->index) ;
  1244.  
  1245.       /* no references or code fragments assigned */
  1246.       current_reference = current_code_fragment = -1 ;
  1247.  
  1248.       /* go to the first one */
  1249.       target_offset = links [0] - tc.section ;
  1250.  
  1251.       /* the first line to display is set to 0, so we display the top */
  1252.       first_line = column = 0 ;
  1253.       format_section (&tc, section) ;
  1254.  
  1255.       /* try to keep at least one line above the target if possible */
  1256.       line = target_line == 0 ? target_line : target_line - 1 ;
  1257.  
  1258.       /* if we would go off the end of the window buffer ... */
  1259.       if (line + wsize_y > VSIZE_Y)
  1260.       {
  1261.         first_line += VSIZE_Y / 2 ;
  1262.         line = max (line - VSIZE_Y / 2, 0) ;
  1263.         format_section (&tc, section) ;
  1264.       }
  1265.  
  1266.       /* try to be a bit helpful */
  1267.       message_printf ("link 1 of %d - [+ Next], [- Previous]", link_count) ;
  1268.     }
  1269.     else
  1270.     {
  1271.       /* were we popped down ? (i.e. did they exit with the hot key ?) */
  1272.       if (poppeddown == 0 && use_stack == 0)
  1273.       {
  1274.         /* assume 'number' is a table of contents index */
  1275.         if ((section = get_section (&tc, *number)) == NULL) return ;
  1276.         first_line = 0 ;
  1277.       }
  1278.       else
  1279.       {
  1280.         /* restore lots of hopefully useful stuff */
  1281.         pop_context (number, &first_line, &line, &column, ¤t_reference, &link_number) ;
  1282.         current_code_fragment = -1 ;
  1283.         section = get_section (&tc, *number) ;
  1284.         format_section (&tc, section) ;
  1285.         if (link_number != -1)
  1286.           message_printf ("link %d of %d - [+ Next], [- Previous]", link_number, link_count) ;
  1287.       }
  1288.     }
  1289.     bounce_me = poppeddown = 0 ;
  1290.     format_section (&tc, section) ;
  1291.     current_reference = current_code_fragment = -1 ;
  1292.     while (bounce_me == 0)
  1293.     {
  1294.       /* column and line are the x and y offsets of the upper left corner */
  1295.       putwindow (column, line) ;
  1296.       while (popdown == 0 && bioskey (0x11) == 0) geninterrupt (0x28) ;
  1297.       if (popdown)
  1298.       {
  1299.         emsfree (section) ;
  1300.         section = NULL ;
  1301.         return ;
  1302.       }
  1303.       ch = bioskey (0x10) ;
  1304.       switch ((unsigned char) ch)
  1305.       {
  1306.         case 0x00 :
  1307.         case 0xe0 :
  1308.              switch (ch = (unsigned char) (ch >> 8))
  1309.              {
  1310.                case 0x3b :                            /* F1                   */
  1311.                     push_context (*number, first_line, line, column, current_reference, link_number) ;
  1312.                     if (use_link == 0) link_count = 0 ;
  1313.                     first_line = line = column = 0 ;
  1314.                     emsfree (section) ;
  1315.                     section = get_section (&tc, *number = 0) ;
  1316.                     current_reference = -1 ;
  1317.                     current_code_fragment = -1 ;
  1318.                     format_section (&tc, section) ;
  1319.                     message_printf ("Press BACKSPACE to backtrack") ;
  1320.                     break ;
  1321.  
  1322.                case 0x50 :                              /* down               */
  1323.                     if (line > (int) (vy - wsize_y)) break ;
  1324.                     if (++line + wsize_y > VSIZE_Y)
  1325.                     {
  1326.                       first_line += VSIZE_Y / 2 ;
  1327.                       line = max (line - VSIZE_Y / 2, 0) ;
  1328.                       format_section (&tc, section) ;
  1329.                     }
  1330.                     break ;
  1331.  
  1332.                case 0x48 :                              /* up                 */
  1333.                     if (line == 0 && first_line == 0) break ;
  1334.                     if (--line <= 0 && first_line != 0)
  1335.                     {
  1336.                       first_line = max ((int) first_line - VSIZE_Y / 2, 0) ;
  1337.                       line = VSIZE_Y / 2 ;
  1338.                       format_section (&tc, section) ;
  1339.                     }
  1340.                     break ;
  1341.  
  1342.                case 0x4d :                              /* right              */
  1343.                     if (column < VSIZE_X - wsize_x) column++ ;
  1344.                     break ;
  1345.  
  1346.                case 0x4b :                              /* left               */
  1347.                     if (column) column-- ;
  1348.                     break ;
  1349.  
  1350.                case 0x51 :                              /* page down          */
  1351.                     if (line > (int) (vy - wsize_y)) break ;
  1352.                     if ((line += wsize_y) >= VSIZE_Y - wsize_y)
  1353.                     {
  1354.                       first_line += VSIZE_Y / 2 ;
  1355.                       format_section (&tc, section) ;
  1356.                       line = max (line - VSIZE_Y / 2, 0) ;
  1357.                     }
  1358.                     break ;
  1359.  
  1360.                case 0x49 :                              /* page up            */
  1361.                     if (line < wsize_y)
  1362.                     {
  1363.                       if (first_line < VSIZE_Y / 2)
  1364.                       {
  1365.                         line += first_line ;
  1366.                         first_line = 0 ;
  1367.                       }
  1368.                       else
  1369.                       {
  1370.                         first_line -= VSIZE_Y / 2 ;
  1371.                         line += VSIZE_Y / 2 ;
  1372.                       }
  1373.                       format_section (&tc, section) ;
  1374.                     }
  1375.                     line = line >= wsize_y ? line - wsize_y : 0 ;
  1376.                     break ;
  1377.  
  1378.                case 0x76 :                              /* control-page down  */
  1379.                     if (*number >= header.section_count + header.appendix_count - 1) break ;
  1380.                     first_line = line = column = 0 ;
  1381.                     /* if we used links, don't clear it so 'B' will still work  */
  1382.                     if (use_link == 0) link_count = 0 ;
  1383.                     emsfree (section) ;
  1384.                     section = get_section (&tc, ++*number) ;
  1385.                     current_reference = -1 ;
  1386.                     current_code_fragment = -1 ;
  1387.                     format_section (&tc, section) ;
  1388.                     message_printf ("%s %s %s", tc.is_appendix ? "APPENDIX" : "", tc.number, tc.title) ;
  1389.                     break ;
  1390.  
  1391.                case 0x84 :                              /* control-page up    */
  1392.                     if (*number == 0) break ;
  1393.                     first_line = line = column = 0 ;
  1394.                     /* if we used links, don't clear it so 'B' will still work  */
  1395.                     if (use_link == 0) link_count = 0 ;
  1396.                     emsfree (section) ;
  1397.                     section = get_section (&tc, --*number) ;
  1398.                     current_reference = -1;
  1399.                     current_code_fragment = -1 ;
  1400.                     format_section (&tc, section) ;
  1401.                     message_printf ("%s %s %s", tc.is_appendix ? "APPENDIX" : "", tc.number, tc.title) ;
  1402.                     break ;
  1403.  
  1404.                case 0x0f :                              /* shift-tab          */
  1405.                     if (reference_count == 0) break ;
  1406.                     reference = current_reference ;
  1407.                     for (i = 0, r = references + reference - 1 ; i < reference_count ; i++, r--)
  1408.                     {
  1409.                       if (reference-- < 0)
  1410.                       {
  1411.                         reference = reference_count - 1 ;
  1412.                         r = references + reference ;
  1413.                       }
  1414.                       if (r->start_vx > column + wsize_x - 1) continue ;
  1415.                       if (r->end_vx < column) continue ;
  1416.                       if (r->start_vy > line + wsize_y - 1) continue ;
  1417.                       if (r->end_vy < line) continue ;
  1418.                       break ;
  1419.                     }
  1420.                     if (i == reference_count) break ;
  1421.                     current_reference = reference ;
  1422.                     load_links () ;
  1423.                     message_printf ("%d link(s) for this reference - '+' for first", link_count) ;
  1424.                     redraw_references () ;
  1425.                     break ;
  1426.  
  1427.                case 0xa5 :                              /* Alt-Tab            */
  1428.                     if (code_fragment_count == 0) break ;
  1429.                     code_fragment = current_code_fragment ;
  1430.                     for (i = 0, f = code_fragments + code_fragment + 1 ; i < code_fragment_count ; i++, f++)
  1431.                     {
  1432.                       if (++code_fragment >= code_fragment_count)
  1433.                       {
  1434.                         code_fragment = 0 ;
  1435.                         f = code_fragments ;
  1436.                       }
  1437.                       if (f->start_vx > column + wsize_x - 1) continue ;
  1438.                       if (f->end_vx < column) continue ;
  1439.                       if (f->start_vy > line + wsize_y - 1) continue ;
  1440.                       if (f->end_vy < line) continue ;
  1441.                       break ;
  1442.                     }
  1443.                     if (i == code_fragment_count) break ;
  1444.                     current_code_fragment = code_fragment ;
  1445.                     redraw_code_fragments () ;
  1446.                     break ;
  1447.                   }
  1448.                   break ;
  1449.  
  1450.         case '\t' :
  1451.              if (reference_count == 0) break ;
  1452.              reference = current_reference ;
  1453.              for (i = 0, r = references + reference + 1 ; i < reference_count ; i++, r++)
  1454.              {
  1455.                if (++reference >= reference_count)
  1456.                {
  1457.                  reference = 0 ;
  1458.                  r = references ;
  1459.                }
  1460.                if (r->start_vx > column + wsize_x - 1) continue ;
  1461.                if (r->end_vx < column) continue ;
  1462.                if (r->start_vy > line + wsize_y - 1) continue ;
  1463.                if (r->end_vy < line) continue ;
  1464.                break ;
  1465.              }
  1466.              if (i == reference_count) break ;
  1467.              current_reference = reference ;
  1468.              load_links () ;
  1469.              message_printf ("%d link(s) for this reference - '+' for first", link_count) ;
  1470.              redraw_references () ;
  1471.              break ;
  1472.  
  1473.         case ' ' :
  1474.              if (*number >= header.section_count + header.appendix_count - 1) break ;
  1475.              first_line = line = column = 0 ;
  1476.              /* if we used links, don't clear it so 'B' will still work */
  1477.              if (use_link == 0) link_count = 0 ;
  1478.              emsfree (section) ;
  1479.              section = get_section (&tc, ++*number) ;
  1480.              current_reference = -1 ;
  1481.              current_code_fragment = -1 ;
  1482.              format_section (&tc, section) ;
  1483.              message_printf ("%s %s %s", tc.is_appendix ? "APPENDIX" : "", tc.number, tc.title) ;
  1484.              break ;
  1485.  
  1486.         case 's' :
  1487.         case 'S' :
  1488.              if (message_gets ("Enter search key", search_string, sizeof (search_string) - 1) == 0)
  1489.              {
  1490.                if ((temp = findKeyword (search_string)) < 0xffff)
  1491.                {
  1492.                  push_context (*number, first_line, line, column, -1, link_number) ;
  1493.                  *number = temp ;
  1494.                  bounce_me++ ;
  1495.                }
  1496.                else
  1497.                {
  1498.                  message_printf ("'%s' : not found", search_string) ;
  1499.                  localdelay (1000) ;
  1500.                }
  1501.              }
  1502.              message_printf ("") ;
  1503.              break ;
  1504.  
  1505.         case '+' :
  1506.         case '-' :
  1507.         case '\r' :
  1508.              if (link_count == 0) break ;
  1509.              if ((char) ch == '-')
  1510.              {
  1511.                if (link_number < 0) break ;
  1512.                if (--link_number == -1)
  1513.                {
  1514.                  pop_context (number, &first_line, &line, &column, ¤t_reference, &link_number) ;
  1515.                  current_code_fragment = -1 ;
  1516.                  emsfree (section) ;
  1517.                  section = get_section (&tc, *number) ;
  1518.                  format_section (&tc, section) ;
  1519.                  link_number = -1 ;
  1520.                  message_printf ("%d link(s) for this reference - '+' for first", link_count) ;
  1521.                  break ;
  1522.                }
  1523.              }
  1524.              else
  1525.              {
  1526.                if (link_number == link_count - 1) break ;
  1527.                if (link_number == -1)
  1528.                  push_context (*number, first_line, line, column, current_reference, link_number) ;
  1529.                link_number++ ;
  1530.              }
  1531.              if ((t = findTCfromOffset (links [link_number])) == NULL)
  1532.              {
  1533.                message_printf ("link %d [%08lx] not found", link_number, links [link_number]) ;
  1534.                break ;
  1535.              }
  1536.              emsfree (section) ;
  1537.              section = get_section (&tc, *number = t->index) ;
  1538.              current_reference = -1 ;
  1539.              current_code_fragment = -1 ;
  1540.              target_offset = links [link_number] - tc.section ;
  1541.              first_line = 0 ;
  1542.              format_section (&tc, section) ;
  1543.              line = target_line == 0 ? target_line : target_line - 1 ;
  1544.              column = 0 ;
  1545.              if (line + wsize_y > VSIZE_Y)
  1546.              {
  1547.                first_line += VSIZE_Y / 2 ;
  1548.                line = max (line - VSIZE_Y / 2, 0) ;
  1549.                format_section (&tc, section) ;
  1550.              }
  1551.              message_printf ("link %d of %d - [+ Next], [- Previous]", link_number + 1, link_count) ;
  1552.              break ;
  1553.  
  1554.         case 'j' :
  1555.         case 'J' :
  1556.              justifyOn = !justifyOn ;
  1557.              message_printf ("Justify %s", justifyOn ? "on" : "off") ;
  1558.              format_section (&tc, section) ;
  1559.              break ;
  1560.  
  1561.         case 'p' :
  1562.         case 'P' :
  1563.              if (shell == 0 || current_code_fragment == -1) break ;
  1564.              paste = min (code_fragments [current_code_fragment].length, sizeof (paste_buffer)) ;
  1565.              memcpy (paste_buffer, (char *) code_fragments [current_code_fragment].offset, paste) ;
  1566.              paste_ptr = paste_buffer ;
  1567.              emsfree (section) ;
  1568.              section = NULL ;
  1569.              popdown++ ;
  1570.              return ;
  1571.  
  1572.         case '\b' :
  1573.              if (current_bookmark == 0)
  1574.              {
  1575.                message_printf ("History stack empty") ;
  1576.                localdelay (1000) ;
  1577.                message_printf ("") ;
  1578.                break ;
  1579.              }
  1580.              pop_context (number, &first_line, &line, &column, ¤t_reference, &link_number) ;
  1581.              current_code_fragment = -1 ;
  1582.              emsfree (section) ;
  1583.              section = get_section (&tc, *number) ;
  1584.              format_section (&tc, section) ;
  1585.              link_number = use_link ? 0 : -1 ;
  1586.              message_printf ("Backtracked to section %s", tc.number) ;
  1587.              break ;
  1588.  
  1589.         case '\x1b' :
  1590.              emsfree (section) ;
  1591.              section = NULL ;
  1592.              return ;
  1593.  
  1594.         default :
  1595.              break ;
  1596.       }
  1597.     }
  1598.   }
  1599. }
  1600.  
  1601. void display_text (unsigned what)
  1602. {
  1603.   int                   line = 0 ;
  1604.   int                   column = 0 ;
  1605.   int                   ch ;
  1606.   char                  *text ;
  1607.   char                  *s ;
  1608.   unsigned              i ;
  1609.   unsigned long         offset ;
  1610.   unsigned long         length ;
  1611.  
  1612.   poppeddown = 0 ;
  1613.   switch (what)
  1614.   {
  1615.     case COPYRIGHT :
  1616.          offset = header.copyright ;
  1617.          length = header.copyright_length ;
  1618.          break ;
  1619.  
  1620.     case AUTHOR :
  1621.          offset = header.authors ;
  1622.          length = header.author_length ;
  1623.          break ;
  1624.  
  1625.     default :
  1626.          return ;
  1627.   }
  1628.  
  1629.   first_line = 0 ;
  1630.  
  1631.   if (length > 65534U)
  1632.   {
  1633.     message_printf ("section too big for present allocation code") ;
  1634.     localdelay (1000) ;
  1635.     return ;
  1636.   }
  1637.   if ((text = emscalloc ((unsigned) length + 1, 1)) == NULL)
  1638.   {
  1639.     message_printf ("cannot allocate memory for text") ;
  1640.     localdelay (1000) ;
  1641.     return ;
  1642.   }
  1643.   fseek (inF, offset, SEEK_SET) ;
  1644.   if (fread (text, (unsigned) length + 1, 1, inF) == 0)
  1645.   {
  1646.     message_printf ("could not read text") ;
  1647.     localdelay (1000) ;
  1648.     emsfree (text) ;
  1649.     return ;
  1650.   }
  1651.   text [(unsigned) length] = 0 ;
  1652.  
  1653.   for (s = text, i = (unsigned) length ; i ; i--, s++)
  1654.     if (*s == '\0')
  1655.       *s = '\n' ;
  1656.  
  1657.   if (what == AUTHOR)
  1658.     format_general_text (text) ;
  1659.   else
  1660.     format_section (NULL, text) ;
  1661.  
  1662.   message_printf (what == AUTHOR ? "List of Authors" : "Copyright information") ;
  1663.  
  1664.   while (1)
  1665.   {
  1666.     putwindow (column, line) ;
  1667.     while (popdown == 0 && bioskey (0x11) == 0) geninterrupt (0x28) ;
  1668.     if (popdown)
  1669.     {
  1670.       emsfree (text) ;
  1671.       return ;
  1672.     }
  1673.     switch ((char) (ch = bioskey (0x10)))
  1674.     {
  1675.       case 0x00 :
  1676.       case 0xe0 :
  1677.            switch (ch >> 8)
  1678.            {
  1679.              case 0x50 :                              /* down                 */
  1680.                   if (line > (int) (vy - wsize_y)) break ;
  1681.                   if (++line + wsize_y > VSIZE_Y)
  1682.                   {
  1683.                     first_line += VSIZE_Y / 2 ;
  1684.                     line = max (line - VSIZE_Y / 2, 0) ;
  1685.                     if (what == AUTHOR)
  1686.                       format_general_text (text) ;
  1687.                     else
  1688.                       format_section (NULL, text) ;
  1689.                   }
  1690.                   break ;
  1691.  
  1692.              case 0x48 :                              /* up                   */
  1693.                   if (line == 0 && first_line == 0) break ;
  1694.                   if (--line == 0 && first_line != 0)
  1695.                   {
  1696.                     first_line = max ((int) first_line - VSIZE_Y / 2, 0) ;
  1697.                     line = VSIZE_Y / 2 ;
  1698.                     if (what == AUTHOR)
  1699.                       format_general_text (text) ;
  1700.                     else
  1701.                       format_section (NULL, text) ;
  1702.                   }
  1703.                   break ;
  1704.  
  1705.              case 0x4d :                              /* right                */
  1706.                   if (column < VSIZE_X - wsize_x) column++ ;
  1707.                   break ;
  1708.  
  1709.              case 0x4b :                              /* left                 */
  1710.                   if (column) column-- ;
  1711.                   break ;
  1712.  
  1713.              case 0x51 :                              /* page down            */
  1714.                   if (line > (int) (vy - wsize_y)) break ;
  1715.                   if ((line += wsize_y) >= VSIZE_Y - wsize_y)
  1716.                   {
  1717.                     first_line += VSIZE_Y / 2 ;
  1718.                     if (what == AUTHOR)
  1719.                       format_general_text (text) ;
  1720.                     else
  1721.                       format_section (NULL, text) ;
  1722.                     line = max (line - VSIZE_Y / 2, 0) ;
  1723.                   }
  1724.                   break ;
  1725.  
  1726.              case 0x49 :                              /* page up              */
  1727.                   if (line < wsize_y)
  1728.                   {
  1729.                     if (first_line < VSIZE_Y / 2)
  1730.                     {
  1731.                       line += first_line ;
  1732.                       first_line = 0 ;
  1733.                     }
  1734.                     else
  1735.                     {
  1736.                       first_line -= VSIZE_Y / 2 ;
  1737.                       line += VSIZE_Y / 2 ;
  1738.                     }
  1739.                     if (what == AUTHOR)
  1740.                       format_general_text (text) ;
  1741.                     else
  1742.                       format_section (NULL, text) ;
  1743.                   }
  1744.                   line = line >= wsize_y ? line - wsize_y : 0 ;
  1745.                   break ;
  1746.            }
  1747.            break ;
  1748.  
  1749.       case '\x1b' :
  1750.            emsfree (text) ;
  1751.            return ;
  1752.  
  1753.       default :
  1754.            break ;
  1755.     }
  1756.   }
  1757. }
  1758.  
  1759. void display_top_menu (int *number)
  1760. {
  1761.   int                   column = 0 ;
  1762.   int                   ch ;
  1763.   int                   temp ;
  1764.   unsigned              selection ;
  1765.   viewer_toc            tc ;
  1766.   static int            selected_line = 0 ;
  1767.   static int            line = 0 ;
  1768.   static int            local_first_line = 0 ;
  1769.  
  1770.   poppeddown = 0 ;
  1771.   first_line = local_first_line ;
  1772.   format_top_menu (0) ;
  1773.   while (selected_line < VSIZE_Y && what_is_where [selected_line] [0] < COPYRIGHT) selected_line++ ;
  1774.   if (selected_line >= wsize_y)
  1775.   {
  1776.     selected_line = wsize_y - 1 ;
  1777.     if (line <= (int) (vy - wsize_y))
  1778.     {
  1779.       if (++line + wsize_y > VSIZE_Y)
  1780.       {
  1781.         local_first_line = first_line += VSIZE_Y / 2 ;
  1782.         line = max (line - VSIZE_Y / 2, 0) ;
  1783.         format_top_menu (0) ;
  1784.       }
  1785.     }
  1786.   }
  1787.   while (1)
  1788.   {
  1789.     putwindow (column, line) ;
  1790.     selection = what_is_where [line + selected_line] [0] ;
  1791.     *number = what_is_where [line + selected_line] [1] ;
  1792.     switch (selection)
  1793.     {
  1794.       case AUTHOR :
  1795.            message_printf ("Press ENTER to list Authors") ;
  1796.            break ;
  1797.  
  1798.       case COPYRIGHT :
  1799.            message_printf ("Press ENTER for Copyright details") ;
  1800.            break ;
  1801.  
  1802.       case FAQ :
  1803.            message_printf ("Press ENTER to read FAQ") ;
  1804.            break ;
  1805.  
  1806.       case HELP :
  1807.            message_printf ("Press ENTER or F1 for HELP") ;
  1808.            break ;
  1809.  
  1810.       case CONTENTS :
  1811.            tc = *getTC (*number) ;
  1812.            message_printf ("%s", tc.title) ;
  1813.            break ;
  1814.  
  1815.       default :
  1816.            message_printf ("") ;
  1817.            break ;
  1818.     }
  1819.     highlight_line (selected_line, selection > TITLE ? 0x4f : 0x3f) ;
  1820.     while (popdown == 0 && bioskey (0x11) == 0) geninterrupt (0x28) ;
  1821.     if (popdown)
  1822.     {
  1823.       popdown = 0 ;
  1824.       return ;
  1825.     }
  1826.     switch ((char) (ch = bioskey (0x10)))
  1827.     {
  1828.       case 0x00 :
  1829.       case 0xe0 :
  1830.            switch (ch >> 8)
  1831.            {
  1832.              case 0x50 :                              /* down                 */
  1833.                   if (++selected_line < wsize_y) break ;
  1834.                   selected_line = wsize_y - 1 ;
  1835.                   if (line > (int) (vy - wsize_y)) break ;
  1836.                   if (++line + wsize_y > VSIZE_Y)
  1837.                   {
  1838.                     local_first_line = first_line += VSIZE_Y / 2 ;
  1839.                     line = max (line - VSIZE_Y / 2, 0) ;
  1840.                     format_top_menu (0) ;
  1841.                   }
  1842.                   break ;
  1843.  
  1844.              case 0x48 :                              /* up                   */
  1845.                   if (--selected_line >= 0) break ;
  1846.                   selected_line = 0 ;
  1847.                   if (line == 0 && first_line == 0) break ;
  1848.                   if (--line == 0 && first_line != 0)
  1849.                   {
  1850.                     local_first_line = first_line = max ((int) first_line - VSIZE_Y / 2, 0) ;
  1851.                     line = VSIZE_Y / 2 ;
  1852.                     format_top_menu (0) ;
  1853.                   }
  1854.                   selected_line = 0 ;
  1855.                   break ;
  1856.  
  1857.              case 0x4d :                              /* right                */
  1858.                   if (column < VSIZE_X - wsize_x) column++ ;
  1859.                   break ;
  1860.  
  1861.              case 0x4b :                              /* left                 */
  1862.                   if (column) column-- ;
  1863.                   break ;
  1864.  
  1865.              case 0x51 :                              /* page down            */
  1866.                   if (line > (int) (vy - wsize_y)) break ;
  1867.                   if ((line += wsize_y) >= VSIZE_Y - wsize_y)
  1868.                   {
  1869.                     local_first_line = first_line += VSIZE_Y / 2 ;
  1870.                     format_top_menu (0) ;
  1871.                     line = max (line - VSIZE_Y / 2, 0) ;
  1872.                   }
  1873.                   break ;
  1874.  
  1875.              case 0x49 :                              /* page up              */
  1876.                   if (line < wsize_y)
  1877.                   {
  1878.                     if (first_line < VSIZE_Y / 2)
  1879.                     {
  1880.                       line += first_line ;
  1881.                       first_line = 0 ;
  1882.                     }
  1883.                     else
  1884.                     {
  1885.                       local_first_line = first_line -= VSIZE_Y / 2 ;
  1886.                       line += VSIZE_Y / 2 ;
  1887.                     }
  1888.                     format_top_menu (0) ;
  1889.                   }
  1890.                   line = line >= wsize_y ? line - wsize_y : 0 ;
  1891.                   break ;
  1892.  
  1893.              case 0x3b :                              /* F1                   */
  1894.                   if ((*number = findTitle ("HELP ON HELP")) == -1) break ;
  1895.                   message_printf ("Press SPACE for next section") ;
  1896.                   display (number, 0, 0) ;
  1897.                   first_line = local_first_line ;
  1898.                   format_top_menu (0) ;
  1899.                   break ;
  1900.            }
  1901.            break ;
  1902.  
  1903.       case '\r' :
  1904.            switch (selection)
  1905.            {
  1906.              case AUTHOR :
  1907.              case COPYRIGHT :
  1908.                   display_text (selection) ;
  1909.                   if (popdown)
  1910.                   {
  1911.                     popdown = 0 ;
  1912.                     return ;
  1913.                   }
  1914.                   break ;
  1915.  
  1916.              case FAQ :
  1917.                   if ((*number = findTitle ("FREQUENTLY ASKED QUESTIONS")) == -1) break ;
  1918.                   message_printf ("Press SPACE for next section") ;
  1919.                   display (number, 0, 0) ;
  1920.                   if (popdown) return ;
  1921.                   break ;
  1922.  
  1923.              case HELP :
  1924.                   if ((*number = findTitle ("HELP ON HELP")) == -1) break ;
  1925.                   message_printf ("Press SPACE for next section") ;
  1926.                   display (number, 0, 0) ;
  1927.                   if (popdown) return ;
  1928.                   break ;
  1929.  
  1930.              case CONTENTS :
  1931.                   display (number, 0, 0) ;
  1932.                   if (popdown) return ;
  1933.                   break ;
  1934.            }
  1935.            first_line = local_first_line ;
  1936.            format_top_menu (0) ;
  1937.            break ;
  1938.  
  1939.       case 's' :
  1940.       case 'S' :
  1941.            if (message_gets ("Enter search key", search_string, sizeof (search_string) - 1) == 0)
  1942.            {
  1943.              if ((temp = findKeyword (search_string)) != -1)
  1944.              {
  1945.                display (&temp, 1, 0) ;
  1946.                break ;
  1947.              }
  1948.              else
  1949.              {
  1950.                message_printf ("'%s' : not found", search_string) ;
  1951.                localdelay (1000) ;
  1952.              }
  1953.            }
  1954.            message_printf ("") ;
  1955.            break ;
  1956.  
  1957.       case '\x1b' :
  1958.            return ;
  1959.  
  1960.       default :
  1961.            break ;
  1962.     }
  1963.   }
  1964. }
  1965.  
  1966. unsigned load_strings (void)
  1967. {
  1968.   char        *s ;
  1969.   char        str [81] ;
  1970.   unsigned    i ;
  1971.   unsigned    count ;
  1972.  
  1973.   if ((reference_strings = farcalloc ((unsigned) header.reference_string_length, 1)) == NULL) return (1) ;
  1974.   if ((reference_string_index = farcalloc (header.reference_count * 4, 1)) == NULL) return (1) ;
  1975.   s = reference_strings ;
  1976.   for (i = 0 ; i < header.reference_count ; i++)
  1977.   {
  1978.     fseek (inF, reference_index [i], SEEK_SET) ;
  1979.     fread (&count, 2, 1, inF) ;
  1980.     fseek (inF, (count + 1) * 4, SEEK_CUR) ;
  1981.     if (fgets (str, 80, inF) == NULL) break ;
  1982.     strcpy (s, str) ;
  1983.     reference_string_index [i] = s ;
  1984.     s += strlen (str) + 1 ;
  1985.   }
  1986.   return (0) ;
  1987. }
  1988.  
  1989. void init (void)
  1990. {
  1991.   if ((references = calloc (sizeof (viewer_reference), MAX_REF)) == NULL)
  1992.   {
  1993.     printf ("cannot allocate memory for references\r\n") ;
  1994.     exit (1) ;
  1995.   }
  1996.   if ((code_fragments = calloc (sizeof (viewer_code_fragment), MAX_FRAGMENT)) == NULL)
  1997.   {
  1998.     printf ("cannot allocate memory for code fragments\r\n") ;
  1999.     exit (1) ;
  2000.   }
  2001.   if ((virtual_screen = calloc (VSIZE_X * 2, VSIZE_Y)) == NULL)
  2002.   {
  2003.     printf ("cannot allocate memory for virtual display\r\n") ;
  2004.     exit (1) ;
  2005.   }
  2006.   clear_virtual_screen () ;
  2007.   memcpy (blank, virtual_screen, VSIZE_X * 2) ;
  2008.   if ((toc = malloc ((unsigned) header.table_of_contents_length)) == NULL)
  2009.   {
  2010.     printf ("cannot allocate memory for table of contents\r\n") ;
  2011.     exit (1) ;
  2012.   }
  2013.   TOCsize = sizeof (TOC_entry) + header.sec_number_len + header.sec_title_len ;
  2014.   if ((reference_index = malloc ((unsigned) header.reference_index_length)) == NULL)
  2015.   {
  2016.     printf ("cannot allocate memory for reference index\r\n") ;
  2017.     exit (1) ;
  2018.   }
  2019.   fseek (inF, header.reference_index, SEEK_SET) ;
  2020.   if (fread (reference_index, (unsigned) header.reference_index_length, 1, inF) == 0)
  2021.   {
  2022.     printf ("could not read reference index\r\n") ;
  2023.     exit (1) ;
  2024.   }
  2025.   if ((title = calloc ((unsigned) header.title_length + 1, 1)) == NULL)
  2026.   {
  2027.     printf ("cannot allocate memory for title\r\n") ;
  2028.     exit (1) ;
  2029.   }
  2030.   fseek (inF, header.title, SEEK_SET) ;
  2031.   if (fread (title, (unsigned) header.title_length + 1, 1, inF) == 0)
  2032.   {
  2033.     printf ("could not read title\r\n") ;
  2034.     exit (1) ;
  2035.   }
  2036.   title [(unsigned) header.title_length] = 0 ;
  2037.   if (load_strings ())
  2038.   {
  2039.     printf ("could not load reference strings\r\n") ;
  2040.     exit (1) ;
  2041.   }
  2042. }
  2043.  
  2044. void popup (void)
  2045. {
  2046.   int                   number = -1 ;
  2047.   int                   i ;
  2048.   char                  x ;
  2049.   char                  y ;
  2050.   char                  *s = "" ;
  2051.   char                  ch ;
  2052.   unsigned              keyword_found = 0 ;
  2053.   union REGS            regs ;
  2054.   static char           str [133] ;
  2055.  
  2056.   mousestate (0) ;
  2057.   regs.h.ah = 0x03 ;
  2058.   regs.h.bh = 0 ;
  2059.   int86 (0x10, ®s, ®s) ;
  2060.   x = regs.h.dl ;
  2061.   y = regs.h.dh ;
  2062.   if (x < 0 || x > COLUMNS) x = 0 ;
  2063.   if (y < 0 || y > 50) y = 0 ;
  2064.  
  2065.   if (poppeddown == 0)
  2066.   {
  2067.     get_line (y, str) ;
  2068.     for (i = x ; i < COLUMNS && isalnum (str [i]) == 0 && str [i] != ' ' ; i++) ;
  2069.     while (--i >= 0)
  2070.     {
  2071.       if (isalnum (str [i])) continue ;
  2072.       switch (str [i])
  2073.       {
  2074.         case '_' :
  2075.         case '.' : continue ;
  2076.       }
  2077.       break ;
  2078.     }
  2079.     s = str + i + 1 ;
  2080.     while (++i < COLUMNS)
  2081.     {
  2082.       if (isalnum (str [i])) continue ;
  2083.       switch (str [i])
  2084.       {
  2085.         case '_' :
  2086.         case '.' : continue ;
  2087.       }
  2088.       break ;
  2089.     }
  2090.  
  2091.     str [i] = '\0' ;
  2092.   }
  2093.  
  2094.   memcpy (saved_screen, MK_FP (base, 0), sizeof (saved_screen)) ;
  2095.   frame () ;
  2096.   if (emsstore (0))
  2097.   {
  2098.     message_printf ("error in saving EMS page mapping") ;
  2099.     localdelay (1000) ;
  2100.     memcpy (MK_FP (base, 0), saved_screen, sizeof (saved_screen)) ;
  2101.     gotoxy (x, y) ;
  2102.     mousestate (1) ;
  2103.     return ;
  2104.   }
  2105.   if (*s)
  2106.   {
  2107.     if ((number = findKeyword (s)) != -1) keyword_found++ ;
  2108.     if (keyword_found == 0)
  2109.       if ((number = findKeyword (s + 1)) != -1)
  2110.         keyword_found++ ;
  2111.     if (keyword_found == 0)
  2112.     {
  2113.       ch = s [strlen (s) - 1] ;
  2114.       s [strlen (s) - 1] = '\0' ;
  2115.       if ((number = findKeyword (s)) != -1) keyword_found++ ;
  2116.       s [strlen (s)] = ch ;
  2117.     }
  2118.     if (keyword_found == 0)
  2119.     {
  2120.       if (number == -1) number = findTitle (s) ;
  2121.       if (number == -1) number = findSection (s) ;
  2122.     }
  2123.   }
  2124.  
  2125.   if (number != -1 || poppeddown)
  2126.   {
  2127.     message_printf (poppeddown ? "" : "searching on '%s'", s) ;
  2128.     display (&number, keyword_found, poppeddown) ;
  2129.     if (popdown == 0) display_top_menu (&number) ;
  2130.   }
  2131.   else
  2132.     display_top_menu (&number) ;
  2133.  
  2134.   if ((poppeddown = popdown) != 0)
  2135.     push_context (number, first_line, line, column, current_reference, link_number) ;
  2136.  
  2137.   if (emsstore (1))
  2138.   {
  2139.     for (i = 0 ; i < 5 ; i++)
  2140.     {
  2141.       message_printf ("WARNING !!! error in restoring EMS page mapping") ;
  2142.       localdelay (500) ;
  2143.       message_printf ("*** memory corruption possible !!! ***") ;
  2144.       localdelay (500) ;
  2145.     }
  2146.   }
  2147.   memcpy (MK_FP (base, 0), saved_screen, sizeof (saved_screen)) ;
  2148.  
  2149.   regs.h.ah = 0x02 ;
  2150.   regs.h.bh = 0 ;
  2151.   regs.h.dl = x ;
  2152.   regs.h.dh = y ;
  2153.   int86 (0x10, ®s, ®s) ;
  2154.   mousestate (1) ;
  2155. }
  2156.  
  2157. void Help (void)
  2158. {
  2159.   printf ("\r\nPOVHELP : POV-Help reader for DOS\r\n\n") ;
  2160.   printf ("-i        : set input file name (default HELP.PHE)\r\n") ;
  2161.   printf ("-w        : set width of window\r\n") ;
  2162.   printf ("-h        : set height of window\r\n") ;
  2163.   printf ("-ph[n]    : send HOME key after each CR when pasting. default is -ph1\r\n") ;
  2164.   printf ("-j[-]     : justify ON (default), -j- to turn off\r\n") ;
  2165.   printf ("-sX.Y     : go to section X.Y\r\n") ;
  2166.   printf ("-tABC     : go to first section with ABC in its title\r\n") ;
  2167.   printf ("-nn       : go to the nth section (first = 0)\r\n") ;
  2168.   printf ("-kALT-H   : set hotkey to ALT-H [CTRL, CTRL-ALT, A-Z, 0-9 permitted]\r\n") ;
  2169.   printf ("-eXYZ.EXE : run program XYZ.EXE (all subsequent params are passed to XYZ)\r\n") ;
  2170.   printf ("ABC       : jump to first reference for keyword ABC\r\n") ;
  2171.   printf ("\r\n") ;
  2172.   printf ("POV-Help was written by Christopher J. Cason (cjcason@yarrow.wt.uwa.edu.au).\r\n") ;
  2173.   printf ("Converters are available which translate POV-Help databases to other formats\r\n") ;
  2174.   printf ("such as Postscript, LaTeX, RTF, Windows Help, HTML, etc.\r\n") ;
  2175.   printf ("The format of the POV-Help database is documentaed and freely available.\r\n") ;
  2176.   printf ("\r\n") ;
  2177.   printf ("POV-Help is free. It may not be sold. See POVLEGAL.DOC for details.\r\n") ;
  2178.   printf ("The POV-Help suite of programs is copyright (c) 1994 C. Cason and the POV-Team.\r\n") ;
  2179. }
  2180.  
  2181. unsigned main (unsigned argc, char *argv [])
  2182. {
  2183.   int                   number = -1 ;
  2184.   char                  *s1 = "HELP.PHE" ;
  2185.   char                  gotoSection [16] = "" ;
  2186.   char                  gotoTitle [80] = "" ;
  2187.   char                  gotoKeyword [80] = "" ;
  2188.   char                  execName [128] = "" ;
  2189.   char                  keycode [32] = "ALT-ESC" ;
  2190.   char                  path [80] ;
  2191.   char                  drive [8] ;
  2192.   char                  dir [80] ;
  2193.   char                  name [16] ;
  2194.   char                  ext [8] ;
  2195.   char                  ch ;
  2196.   unsigned              copyExec = 0 ;
  2197.   unsigned              keyword_found = 0 ;
  2198.   union REGS            regs ;
  2199.  
  2200.   regs.h.ah = 0x0f ;
  2201.   int86 (0x10, ®s, ®s) ;
  2202.   if ((regs.h.al & 0x7f) == 0x07) base = 0xb000 ;
  2203.  
  2204.   regs.x.ax = 0x21 ;
  2205.   int86 (0x33, ®s, ®s) ;
  2206.   mouseInstalled = regs.x.ax == 0xffff ;
  2207.  
  2208.   if ((inF = fopen (s1, "rb")) == NULL)
  2209.   {
  2210.     fnsplit (*argv, drive, dir, name, ext) ;
  2211.     fnmerge (path, drive, dir, "HELP", ".PHE") ;
  2212.     s1 = path ;
  2213.   }
  2214.   else
  2215.     fclose (inF) ;
  2216.  
  2217.   while (++argv, --argc)
  2218.   {
  2219.     if (copyExec == 0 && (**argv == '-' || **argv == '+'))
  2220.     {
  2221.       switch (toupper ((*argv) [1]))
  2222.       {
  2223.         case 'I' :
  2224.              s1 = *argv + 2 ;
  2225.              break ;
  2226.  
  2227.         case 'J' :
  2228.              justifyOn = (*argv) [2] != '-' ;
  2229.              break ;
  2230.  
  2231.         case 'N' :
  2232.              number = atoi (*argv + 2) ;
  2233.              break ;
  2234.  
  2235.         case 'W' :
  2236.              if (atoi (*argv + 2) == 0)
  2237.              {
  2238.                printf ("\r\n'%s' : invalid argument\r\n", *argv) ;
  2239.                Help () ;
  2240.                return (0) ;
  2241.              }
  2242.              wsize_x = max (25, min (127, atoi (*argv + 2))) ;
  2243.              break ;
  2244.  
  2245.         case 'H' :
  2246.              if ((*argv) [2] == '\0')
  2247.              {
  2248.                Help () ;
  2249.                return (0) ;
  2250.              }
  2251.              if (atoi (*argv + 2) == 0)
  2252.              {
  2253.                printf ("\r\n'%s' : invalid argument\r\n", *argv) ;
  2254.                Help () ;
  2255.                return (0) ;
  2256.              }
  2257.              wsize_y = max (5, min (21, atoi (*argv + 2))) ;
  2258.              break ;
  2259.  
  2260.         case 'S' :
  2261.              strncpy (gotoSection, *argv + 2, 15) ;
  2262.              break ;
  2263.  
  2264.         case 'T' :
  2265.              strncpy (gotoTitle, *argv + 2, 79) ;
  2266.              break ;
  2267.  
  2268.         case 'E' :
  2269.              strncpy (execName, *argv + 2, 127) ;
  2270.              fnsplit (execName, NULL, NULL, name, ext) ;
  2271.              if (strcmp (strupr (name), "EDIT") == 0 && strcmp (strupr (ext), ".COM") == 0)
  2272.              {
  2273.                printf ("\x07WARNING : POV-Help has a known incompatibility with DOS'S EDIT.COM\r\n") ;
  2274.                printf ("          If this is the program you are trying to run, your system may crash.\r\n") ;
  2275.                printf ("Continue ? [y/N] : ") ;
  2276.                ch = getchar () ;
  2277.                if (toupper (ch) != 'Y') return (1) ;
  2278.                printf ("\r\n") ;
  2279.              }
  2280.              copyExec++ ;
  2281.              break ;
  2282.  
  2283.         case 'K' :
  2284.              strncpy (keycode, *argv + 2, 32) ;
  2285.              break ;
  2286.  
  2287.         case 'P' :
  2288.              if (toupper ((*argv) [2]) == 'H') home_wanted = 1 ;
  2289.              if (isdigit ((*argv) [3])) home_wanted = '0' - (*argv) [3] ;
  2290.              break ;
  2291.  
  2292.         case '?' :
  2293.              Help () ;
  2294.              return (0) ;
  2295.  
  2296.         default :
  2297.              printf ("unknown option '%s' [povhelp -? for help]\r\n", *argv) ;
  2298.              return (1) ;
  2299.       }
  2300.     }
  2301.     else
  2302.       if (copyExec)
  2303.       {
  2304.         strncat (execName, " ", 127) ;
  2305.         strncat (execName, *argv, 127) ;
  2306.       }
  2307.       else
  2308.         strncpy (gotoKeyword, *argv, 79) ;
  2309.   }
  2310.  
  2311.   if (keycode [0] != '\0')
  2312.   {
  2313.     if (translate_keycode (keycode))
  2314.     {
  2315.       printf ("invalid keycode string, '%s'\r\n", keycode) ;
  2316.       return (1) ;
  2317.     }
  2318.   }
  2319.  
  2320.   if ((inF = fopen (s1, "rb")) == NULL)
  2321.   {
  2322.     printf ("could not open input file '%s'\r\n", s1) ;
  2323.     return (1) ;
  2324.   }
  2325.   if (fread (&header, sizeof (help_file_header), 1, inF) == 0)
  2326.   {
  2327.     printf ("could not read header\r\n") ;
  2328.     return (1) ;
  2329.   }
  2330.  
  2331.   if (memcmp (header.signature, "POV-Help", 8) != 0)
  2332.   {
  2333.     printf ("header ID failed consistency check\r\n") ;
  2334.     return (1) ;
  2335.   }
  2336.  
  2337.   if (header.reader_version > VERSION)
  2338.   {
  2339.     printf ("version error ! database is not compatible [needs version %d.%d of reader]\r\n",
  2340.              header.reader_version / 100, header.reader_version % 100) ;
  2341.     return (1) ;
  2342.   }
  2343.  
  2344.   init () ;
  2345.  
  2346.   fseek (inF, header.table_of_contents, SEEK_SET) ;
  2347.   if (fread (toc, (unsigned) header.table_of_contents_length, 1, inF) == 0)
  2348.   {
  2349.     printf ("could not read table of contents\r\n") ;
  2350.     return (1) ;
  2351.   }
  2352.  
  2353.   if (*gotoTitle) number = findTitle (gotoTitle) ;
  2354.   if (*gotoSection) number = findSection (gotoSection) ;
  2355.   if (*gotoKeyword)
  2356.     if ((number = findKeyword (gotoKeyword)) != -1) keyword_found++ ;
  2357.  
  2358.   if (number < 0 && execName [0])
  2359.   {
  2360.     shell++ ;
  2361.     if (emsinit ())
  2362.     {
  2363.       printf ("could not initialise/allocate EMS for shell mode\r\n") ;
  2364.       return (1) ;
  2365.     }
  2366.     printf ("POV-Help v%d.%d - loading '%s' [use %s to pop up]\r\n",
  2367.              VERSION / 100, VERSION % 100, execName, keycode) ;
  2368.     kbinit () ;
  2369.     if (system (execName)) printf ("[could not execute command '%s']\r\n", execName) ;
  2370.     deinit () ;
  2371.     printf ("POV-Help - finished. (c) Christopher J. Cason/POV-Team 1994\r\n") ;
  2372.     emsfinish () ;
  2373.     shell-- ;
  2374.   }
  2375.   else
  2376.   {
  2377.     mousestate (0) ;
  2378.     clrscr () ;
  2379.     frame () ;
  2380.     if (number >= 0) display (&number, keyword_found, 0) ;
  2381.     display_top_menu (&number) ;
  2382.     gotoxy (1, 23) ;
  2383.     printf ("POV-Help v%d.%d - finished. (c) Christopher J. Cason/POV-Team 1994\r\n",
  2384.             VERSION / 100, VERSION % 100) ;
  2385.     mousestate (1) ;
  2386.   }
  2387.  
  2388.   farfree (reference_string_index) ;
  2389.   farfree (reference_strings) ;
  2390.   free (toc) ;
  2391.   free (virtual_screen) ;
  2392.   free (code_fragments) ;
  2393.   free (references) ;
  2394.   free (title) ;
  2395.   fclose (inF) ;
  2396.   return (0) ;
  2397. }