home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Hack-Phreak Scene Programs
/
cleanhpvac.zip
/
cleanhpvac
/
POVHELP.ZIP
/
source
/
povhelp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-20
|
72KB
|
2,397 lines
/****************************************************************************
* POVHELP.C - version 1.0 - 1 July 1994
*
* This module implements the main DOS help reader.
*
* from Persistence of Vision Raytracer
* Copyright 1994 Persistence of Vision Team
* Copyright 1994 Christopher J. Cason.
*---------------------------------------------------------------------------
* NOTICE: This source code file is provided so that users may experiment
* with enhancements to POV-Ray and to port the software to platforms other
* than those supported by the POV-Ray Team. There are strict rules under
* which you are permitted to use this file. The rules are in the file
* named POVLEGAL.DOC which should be distributed with this file. If
* POVLEGAL.DOC is not available or for more info please contact the POV-Ray
* Team Coordinator by leaving a message in CompuServe's Graphics Developer's
* Forum. The latest version of POV-Ray may be found there as well.
*
* POV-Ray files may also be obtained from ftp.uwa.edu.au in pub/povray.
*
* This program was written in its entirety by Christopher J. Cason.
* Its use is freely and permanently granted to the POV-Team and POV users
* under the conditions specified in POVLEGAL.DOC.
*
* Author : C. J. Cason (cjcason@yarrow.wt.uwa.edu.au, CIS 100032,1644)
*
*****************************************************************************/
/*---------------------------------------------------------------------------*/
/* NOTE : If you're porting this to another architecture, don't forget that */
/* the POV-Help database stores words and dwords in LSB-first format. */
/*---------------------------------------------------------------------------*/
#include <stdio.h>
#include <mem.h>
#include <string.h>
#include <alloc.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <bios.h>
#include <ctype.h>
#include <dir.h>
#include <stdarg.h>
#include "help.h"
#define MAX_REF 512
#define MAX_FRAGMENT 16
#define MAX_LINK 64
#define VSIZE_Y 55
#define VSIZE_X 128
#define MAX_BOOKMARK 32
#define TITLE 0x01
#define COPYRIGHT 0x02
#define AUTHOR 0x03
#define FAQ 0x04
#define HELP 0x05
#define CONTENTS 0x100
#define PRESERVE (preserve_formatting || code_fragment || line_drawing)
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#define max(a,b) ((int) (a) > (int) (b) ? (a) : (b))
#define min(a,b) ((int) (a) < (int) (b) ? (a) : (b))
#define ISALT(s) (strcmp (s, "ALT") == 0)
#define ISCTL(s) (strcmp (s, "CTL") == 0 || strcmp (s, "CTRL") == 0)
#define COLUMNS *(unsigned *) MK_FP (0x40, 0x4a)
#define ROWSIZE (COLUMNS * 2)
typedef struct
{
unsigned char start_vx ;
unsigned char end_vx ;
unsigned short id ;
unsigned short start_vy ;
unsigned short end_vy ;
} viewer_reference ;
typedef struct
{
unsigned char start_vx ;
unsigned char end_vx ;
unsigned short start_vy ;
unsigned short end_vy ;
unsigned short length ;
unsigned long offset ;
} viewer_code_fragment ;
typedef struct
{
/* these first three entries must not be changed/moved */
unsigned long section ;
unsigned long section_length ;
char is_appendix ;
char number [16] ;
char title [80] ;
unsigned index ;
} viewer_toc ;
typedef struct
{
int line ;
int column ;
short reference ;
short link_number ;
short first_line ;
unsigned number ;
} bookmark ;
int line = 0 ;
int column = 0 ;
char *title ;
char blank [VSIZE_X] [2] ;
char *reference_strings ;
char **reference_string_index ;
char *paste_ptr ;
char paste_buffer [2048] ;
char search_string [33] = "" ;
short current_reference = -1 ;
short current_code_fragment = -1 ;
short link_number = -1 ;
short first_line = 0 ;
short wsize_y = 15 ;
void far *pageframe ;
unsigned x1 ;
unsigned y1 ;
unsigned x2 ;
unsigned y2 ;
unsigned emshandle ;
unsigned shell ;
unsigned base = 0xb800 ;
unsigned paste = 0 ;
unsigned home_wanted = 1 ;
unsigned char attribute = 0x1f ;
unsigned char reference ;
unsigned char highlight ;
unsigned char bold ;
unsigned char code_fragment ;
unsigned char heading ;
unsigned char line_drawing ;
unsigned char preserve_formatting ;
unsigned char table ;
unsigned char list ;
unsigned char list_entry ;
unsigned char wsize_x = 75 ;
unsigned char left_margin ;
unsigned char right_margin ;
unsigned char *virtual_screen ;
unsigned char *toc ;
unsigned char saved_screen [6600] ;
unsigned char *section ;
unsigned char vx ;
unsigned long links [MAX_LINK] ;
unsigned long *reference_index ;
unsigned long target_offset ;
unsigned short vy ;
unsigned short reference_count ;
unsigned short code_fragment_count ;
unsigned short TOCsize ;
unsigned short ignore_lines = 0 ;
unsigned short link_count ;
unsigned short target_line ;
unsigned short what_is_where [VSIZE_Y] [2] ;
unsigned short poppeddown ;
unsigned short mouseInstalled = 0 ;
unsigned short justifyOn = 1 ;
unsigned short current_bookmark = 0 ;
FILE *inF ;
bookmark bookmarks [MAX_BOOKMARK] ;
viewer_toc tc ;
viewer_reference *references ;
help_file_header header ;
viewer_code_fragment *code_fragments ;
extern char scancodes [] ;
extern unsigned running ;
extern unsigned counter ;
extern unsigned scancode ;
extern unsigned scanflag ;
extern unsigned popdown ;
void kbinit (void) ;
void deinit (void) ;
void gotoxy (int x, int y)
{
_AH = 0x02 ;
_DH = --y ;
_DL = --x ;
_BH = 0 ;
geninterrupt (0x10) ;
}
unsigned astrlen (unsigned *s, unsigned width)
{
unsigned *s1 = s + width ;
while ((char) *--s1 == ' ' && s1 > s) ;
return ((unsigned) (s1 - s)) ;
}
unsigned wordcount (unsigned *s, unsigned width)
{
unsigned wc = 0 ;
unsigned inword = 0 ;
while (width--)
{
if (inword == 0)
{
if ((char) *s++ == ' ') continue ;
inword++ ;
wc++ ;
}
else
{
if ((char) *s++ != ' ') continue ;
inword = 0 ;
}
}
return (wc) ;
}
void insertspaces (unsigned howmany, unsigned *s, unsigned width)
{
unsigned *s1 = s + width ;
while (howmany--)
{
while ((char) *--s1 == ' ' && s1 > s) ;
if (s1 == s) return ;
while ((char) *--s1 != ' ' && s1 > s) ;
if (s1 == s) return ;
memmove (s1 + 1, s1, (width - (unsigned) (s1 - s) - 1) * 2) ;
}
}
void justify (unsigned *s, unsigned width)
{
int needed ;
unsigned wc ;
if ((needed = width - astrlen (s, width) - 1) <= 0) return ;
if ((wc = wordcount (s, width)) == 0) return ;
while (needed > wc)
{
insertspaces (needed, s, width) ;
needed -= wc ;
}
insertspaces (needed, s, width) ;
}
unsigned translate_keycode (char *keycode)
{
char str [32] ;
char *s ;
strncpy (str, keycode, 31) ;
if ((s = strtok (strupr (str), "-+")) == NULL) return (1) ;
if (!ISALT (s) && !ISCTL (s)) return (1) ;
scanflag = ISALT (s) ? ALT : CONTROL ;
if ((s = strtok (NULL, "-+")) == NULL) return (1) ;
if (ISALT (s) || ISCTL (s))
{
scanflag |= ISALT (s) ? ALT : CONTROL ;
if ((s = strtok (NULL, "-+")) == NULL) return (1) ;
}
if (strcmp (strupr (s), "ESC") == 0) s = "\x1b" ;
if (strlen (s) > 1 || (unsigned char) *s > 0x7f) return (1) ;
scancode = scancodes [*s] ;
return (0) ;
}
void far *emscalloc (unsigned items, unsigned count)
{
unsigned i ;
union REGS regs ;
if (shell == 0) return (farcalloc (items, count)) ;
for (i = 0 ; i < 4 ; i++)
{
regs.h.ah = 0x44 ; /* map EMS page */
regs.x.dx = emshandle ;
regs.h.al = i ; /* physical page */
regs.x.bx = i ; /* logical page */
int86 (0x67, ®s, ®s) ;
if (regs.h.ah != 0) return (NULL) ;
}
return (pageframe) ;
}
void emsfree (void *p)
{
if (shell == 0)
{
farfree (p) ;
return ;
}
}
unsigned emsinit (void)
{
FILE *f ;
union REGS regs ;
if ((f = fopen ("EMMXXXX0", "r")) == NULL) return (1) ;
fclose (f) ;
regs.h.ah = 0x46 ; /* get EMS manager version */
int86 (0x67, ®s, ®s) ;
if (regs.h.ah != 0) return (1) ;
regs.h.ah = 0x40 ; /* get EMS manager status */
int86 (0x67, ®s, ®s) ;
if (regs.h.ah != 0) return (1) ;
regs.h.ah = 0x41 ; /* get EMS page frame */
int86 (0x67, ®s, ®s) ;
if (regs.h.ah != 0) return (1) ;
pageframe = MK_FP (regs.x.bx, 0) ;
regs.h.ah = 0x43 ; /* get EMS handle and allocate memory */
regs.x.bx = 4 ;
int86 (0x67, ®s, ®s) ;
if (regs.h.ah != 0) return (1) ;
emshandle = regs.x.dx ;
return (0) ;
}
void emsfinish (void)
{
union REGS regs ;
regs.h.ah = 0x45 ; /* release EMS handle and memory */
regs.x.dx = emshandle ;
int86 (0x67, ®s, ®s) ;
}
unsigned emsstore (unsigned restore)
{
union REGS regs ;
struct SREGS sregs ;
static char store [256] ;
if (restore == 0)
{
regs.x.ax = 0x4e00 ; /* get mapping registers */
regs.x.di = FP_OFF (store) ;
sregs.es = FP_SEG (store) ;
int86x (0x67, ®s, ®s, &sregs) ;
if (regs.h.ah != 0) return (1) ;
}
else
{
regs.x.ax = 0x4e01 ; /* set mapping registers */
regs.x.si = FP_OFF (store) ;
sregs.ds = FP_SEG (store) ;
int86x (0x67, ®s, ®s, &sregs) ;
if (regs.h.ah != 0) return (1) ;
}
return (0) ;
}
void mousestate (unsigned show)
{
union REGS regs ;
if (mousestate == 0) return ;
regs.x.ax = show ? 0x01 : 0x02 ;
int86 (0x33, ®s, ®s) ;
}
void message_printf (char *format, ...)
{
static char str [140] ;
char *s1 = str ;
char far *s2 = MK_FP (base, (y2 + 1) * ROWSIZE + x1 * 2) ;
unsigned i ;
va_list arg_ptr ;
va_start (arg_ptr, format) ;
vsprintf (str, format, arg_ptr) ;
va_end (arg_ptr) ;
for (i = 0 ; i < wsize_x - 1 ; i++)
{
*s2++ = *s1 ? *s1++ : ' ' ;
*s2++ = 0x0e ;
}
}
unsigned message_gets (char *prompt, char *s, unsigned length)
{
char ch ;
unsigned index = strlen (s) ;
unsigned changed = 0 ;
while (1)
{
message_printf ("%s : %s", prompt, s) ;
gotoxy (x1 + strlen (prompt) + index + 4, y2 + 2) ;
while (popdown == 0 && bioskey (0x11) == 0) geninterrupt (0x28) ;
if (popdown) return (1) ;
ch = bioskey (0x10) ;
switch ((unsigned char) ch)
{
case '\r' :
case '\n' :
case '\x1b' : gotoxy (COLUMNS + 1, 50) ;
message_printf ("") ;
return (ch == 0x1b) ;
case '\b' : if (index == 0) break ;
s [--index] = '\0' ;
changed++ ;
break ;
default : if (ch < 0x20 || ch > 0x7f) break ;
if (index >= length) break ;
if (changed++ == 0) index = 0 ;
s [index++] = ch ;
s [index] = '\0' ;
break ;
}
}
return (0) ;
}
void localdelay (unsigned milliseconds)
{
if (shell)
{
counter = milliseconds / 55 ;
while (counter && counter--) ++counter ; /* make compiler happy ; it doesn't understand volatile */
}
else
delay (milliseconds) ;
}
unsigned ustrcmp (char *s1, char *s2)
{
while (*s1 && *s2)
if (toupper (*s1++) != toupper (*s2++))
return (1) ;
return (*s1 || *s2) ;
}
void frame (void)
{
unsigned x ;
unsigned y ;
unsigned *ptr ;
x1 = (COLUMNS - wsize_x) / 2 - 1 ;
y1 = (25 - wsize_y) / 2 - 2 ;
x2 = x1 + wsize_x + 1 ;
y2 = y1 + wsize_y + 1 ;
ptr = MK_FP (base, y1 * ROWSIZE + x1 * 2) ;
for (x = x1 ; x < x2 ; x++) *ptr++ = ('─\x0f') ;
ptr = MK_FP (base, y2 * ROWSIZE + x1 * 2) ;
for (x = x1 ; x < x2 ; x++) *ptr++ = ('─\x0f') ;
ptr = MK_FP (base, (y2 + 2) * ROWSIZE + x1 * 2) ;
for (x = x1 ; x < x2 ; x++) *ptr++ = ('─\x0f') ;
for (y = y1 ; y < y2 + 2 ; y++)
{
*(unsigned *) MK_FP (base, y * ROWSIZE + x1 * 2) = '│\x0f' ;
*(unsigned *) MK_FP (base, y * ROWSIZE + x2 * 2) = '│\x0f' ;
}
*(unsigned *) MK_FP (base, y1 * ROWSIZE + x1 * 2) = '┌\x0f' ;
*(unsigned *) MK_FP (base, y1++ * ROWSIZE + x2 * 2) = '┐\x0f' ;
*(unsigned *) MK_FP (base, y2 * ROWSIZE + x1 * 2) = '├\x0f' ;
*(unsigned *) MK_FP (base, y2 * ROWSIZE + x2 * 2) = '┤\x0f' ;
*(unsigned *) MK_FP (base, (y2 + 2) * ROWSIZE + x1++ * 2) = '└\x0f' ;
*(unsigned *) MK_FP (base, (y2-- + 2) * ROWSIZE + x2-- * 2) = '┘\x0f' ;
*(unsigned *) MK_FP (base, (y2 + 2) * ROWSIZE + x1++ * 2) = ' \x0f' ;
*(unsigned *) MK_FP (base, (y2++ + 2) * ROWSIZE + x2++ * 2) = ' \x0f' ;
y1++ ;
left_margin = 0 ;
right_margin = wsize_x ;
gotoxy (COLUMNS + 1, 50) ;
}
void get_line (unsigned line, char *s)
{
char far *_s = MK_FP (base, line * ROWSIZE) ;
unsigned i ;
for (i = 0 ; i < COLUMNS ; i++)
{
*s++ = *_s++ ;
_s++ ;
}
*s++ = '\x00' ;
}
void putwindow (unsigned column, unsigned line)
{
char *s2 = virtual_screen + line * VSIZE_X * 2 + column * 2 ;
char far *s1 = MK_FP (base, (y1 - 1) * ROWSIZE + (x1 - 1) * 2) ;
unsigned width2 = VSIZE_X * 2 ;
unsigned width1 = wsize_x * 2 ;
unsigned count ;
for (count = 0 ; count < wsize_y ; count++)
{
memcpy (s1, (line + count < VSIZE_Y) ? (char *) s2 : (char *) blank, width1) ;
s1 += ROWSIZE ;
s2 += width2 ;
}
}
void highlight_line (unsigned line, char attribute)
{
char *s = MK_FP (base, (y1 + line - 1) * ROWSIZE + (x1 - 1) * 2 + 1) ;
unsigned count ;
for (count = wsize_x ; count ; count--, s += 2) *s = attribute ;
}
void write_attribute (unsigned x1, unsigned y1, unsigned x2, unsigned y2, char attribute)
{
char *s = virtual_screen + y1 * VSIZE_X * 2 + x1 * 2 ;
unsigned count = (y2 * VSIZE_X + x2) - (y1 * VSIZE_X + x1) ;
if (y2 < y1) return ;
if (y2 == y1 && x2 < x1) return ;
while (count--)
{
*++s = attribute ;
s++ ;
}
}
void clear_attributes (void)
{
reference = highlight = bold = code_fragment = 0 ;
heading = line_drawing = preserve_formatting = 0 ;
table = list = list_entry = 0 ;
}
void set_attribute (void)
{
attribute = 0x1f ;
if (code_fragment) attribute = 0x1a ;
if (heading) attribute = 0x1c ;
if (line_drawing) attribute = 0x1b ;
if (list_entry) attribute = 0x1e ;
if (bold) attribute = 0x2f ;
if (highlight) attribute = 0x1e ;
if (bold && highlight) attribute = 0x2e ;
if (reference) attribute = 0x3f ;
}
viewer_reference *create_reference (unsigned short id)
{
if (reference_count == MAX_REF) return (NULL) ;
references [reference_count].id = id ;
return (references + reference_count++) ;
}
void clear_references (void)
{
reference_count = 0 ;
}
viewer_code_fragment *create_code_fragment (void)
{
if (code_fragment_count == MAX_FRAGMENT) return (NULL) ;
return (code_fragments + code_fragment_count++) ;
}
void clear_code_fragments (void)
{
code_fragment_count = 0 ;
}
viewer_toc *getTC (unsigned index)
{
char *s ;
static viewer_toc result ;
if (index >= header.section_count + header.appendix_count) index = 0 ;
s = toc + (unsigned) ((unsigned long) TOCsize * index) ;
memcpy (&result, s, sizeof (TOC_entry)) ;
s += sizeof (TOC_entry) ;
strcpy (result.number, s) ;
strcpy (result.title, s + header.sec_number_len) ;
result.index = index ;
return (&result) ;
}
viewer_toc *findTCfromOffset (unsigned long offset)
{
unsigned i ;
static viewer_toc result ;
for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
{
result = *getTC (i) ;
if (result.section > offset) continue ;
if (result.section + result.section_length <= offset) continue ;
return (&result) ;
}
return (NULL) ;
}
char *get_section (viewer_toc *tc, unsigned number)
{
unsigned count ;
unsigned char *section ;
*tc = *getTC (number) ;
fseek (inF, tc->section, SEEK_SET) ;
if (tc->section_length + 1 > 65534U)
{
message_printf ("section too big for present allocation code") ;
localdelay (1000) ;
return (NULL) ;
}
if ((section = emscalloc ((unsigned) tc->section_length + 1, 1)) == NULL)
{
message_printf ("error - cannot allocate enough memory for section %s", tc->number) ;
localdelay (1000) ;
return (NULL) ;
}
if (fread (section, (unsigned) tc->section_length + 1, 1, inF) == 0)
{
message_printf ("could not read section") ;
localdelay (1000) ;
return (NULL) ;
}
count = (unsigned) tc->section_length ;
while (section [count - 1] == '\n' || section [count - 1] == PARAGRAPH) count-- ;
section [count] = '\0' ;
return (section) ;
}
unsigned findSection (char *s)
{
unsigned i ;
viewer_toc result ;
for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
{
result = *getTC (i) ;
if (ustrcmp (s, result.number)) continue ;
return (i) ;
}
return (-1) ;
}
unsigned findTitle (char *s)
{
static char str [80] ;
unsigned i ;
viewer_toc result ;
strupr (s) ;
for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
{
result = *getTC (i) ;
if (ustrcmp (s, result.title)) continue ;
return (i) ;
}
for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
{
result = *getTC (i) ;
strcpy (str, result.title) ;
strupr (str) ;
if (strstr (str, s) == NULL) continue ;
return (i) ;
}
return (-1) ;
}
unsigned findKeyword (char *s)
{
unsigned i ;
for (i = 0 ; i < header.reference_count ; i++)
if (ustrcmp (s, reference_string_index [i]) == 0)
return (i) ;
return (-1) ;
}
unsigned virtual_screen_full (void)
{
return (vy >= VSIZE_Y) ;
}
void clear_virtual_screen (void)
{
char *s = virtual_screen ;
unsigned count = (unsigned) VSIZE_X * VSIZE_Y ;
vx = 0 ;
vy = 0 ;
left_margin = 0 ;
right_margin = wsize_x ;
while (count--)
{
*s++ = ' ' ;
*s++ = attribute ;
}
}
unsigned line_is_blank (unsigned line)
{
char *s = virtual_screen + line * VSIZE_X * 2 ;
unsigned count = (unsigned) VSIZE_X ;
while (count--)
{
if (*s != ' ') return (0) ;
s += 2 ;
}
return (1) ;
}
void vputchar (unsigned char ch)
{
char *s ;
if (vy >= VSIZE_Y) return ;
switch (ch)
{
case '\r' :
vx = 0 ;
return ;
case '\n' :
vx = VSIZE_X ;
break ;
default :
if (vx >= VSIZE_X) return ;
if (ignore_lines) break ;
s = virtual_screen + (unsigned) vy * VSIZE_X * 2 + vx * 2 ;
*s++ = ch ;
*s++ = attribute ;
break ;
}
if (++vx >= VSIZE_X)
{
if (ch == '\n' || !PRESERVE)
{
vx = left_margin ;
if (ignore_lines)
{
--ignore_lines ;
return ;
}
if (++vy >= VSIZE_Y) vy = VSIZE_Y ;
}
}
}
void vputchar_attr (unsigned char ch, unsigned char attr)
{
unsigned char a = attribute ;
attribute = attr ;
vputchar (ch) ;
attribute = a ;
}
void vputstr (char *s)
{
while (*s)
vputchar (*s++) ;
}
void cvputstr (char *s, unsigned type)
{
static char str [256] ;
char *s1 = str ;
unsigned count ;
for (count = 0 ;; s++)
{
if (*s == '\n' || *s == '\0')
{
what_is_where [vy] [0] = type ;
vx = (wsize_x - min (wsize_x, count)) / 2 ;
for (s1 = str ; count ; count--)
vputchar (*s1++) ;
vputchar ('\n') ;
if (*s == '\0') break ;
s1 = str ;
continue ;
}
*s1++ = *s ;
count++ ;
}
}
unsigned pointcount (char *s)
{
unsigned count = 0 ;
while (*s)
if (*s++ == '.')
count++ ;
return (count) ;
}
void vcachechar (char ch)
{
char *s ;
static char str [128] ;
static unsigned count = 0 ;
if (ch == '\0' || ch == ' ' || ch == '\t' || ch == '\n' || count == 128)
{
if (count / 2 > right_margin - vx)
{
if (justifyOn && !list)
justify ((unsigned *) (virtual_screen + (unsigned) vy * VSIZE_X * 2), wsize_x) ;
vputchar ('\n') ;
}
for (s = str ; count ; count -= 2, s += 2)
if (*s != ' ' || vx != left_margin)
vputchar_attr (s [0], s [1]) ;
if (ch == '\0') return ;
}
if (PRESERVE)
{
vputchar (ch) ;
return ;
}
str [count++] = ch ;
str [count++] = attribute ;
}
void redraw_references (void)
{
char attribute ;
unsigned i ;
viewer_reference *r ;
if (current_reference < 0) return ;
for (i = 0, r = references ; i < reference_count ; i++, r++)
{
attribute = i == current_reference ? 0x4f : 0x3f ;
write_attribute (r->start_vx, r->start_vy, r->end_vx, r->end_vy, attribute) ;
}
}
void redraw_code_fragments (void)
{
char attribute ;
unsigned i ;
viewer_code_fragment *f ;
if (current_code_fragment < 0) return ;
for (i = 0, f = code_fragments ; i < code_fragment_count ; i++, f++)
{
attribute = i == current_code_fragment ? 0x6f : 0x1a ;
write_attribute (f->start_vx, f->start_vy, f->end_vx, f->end_vy, attribute) ;
}
}
void format_section (viewer_toc *tc, char *section)
{
unsigned id ;
unsigned look_for_target = target_offset != 0 ;
unsigned escape = 0 ;
unsigned char *s ;
viewer_reference *r ;
viewer_code_fragment *f ;
clear_attributes () ;
set_attribute () ;
clear_references () ;
clear_code_fragments () ;
clear_virtual_screen () ;
ignore_lines = first_line ;
target_line = 0 ;
if (tc)
{
heading++ ;
set_attribute () ;
if (tc->is_appendix) vputstr ("APPENDIX ") ;
vputstr (tc->number) ;
vx = 17 ;
vputstr (tc->title) ;
heading = 0 ;
vcachechar ('\n') ;
vcachechar ('\n') ;
set_attribute () ;
}
while (*section == '\n' || (unsigned char) *section == PARAGRAPH) section++ ;
for (s = section ; *s ; s++)
{
if (virtual_screen_full ())
{
if (look_for_target)
{
first_line += vy ;
clear_references () ;
clear_code_fragments () ;
clear_virtual_screen () ;
}
else
break ;
}
if (look_for_target && s - section >= target_offset)
{
target_line = vy ;
look_for_target = 0 ;
}
if (escape == 0)
{
switch (*s)
{
case ESCAPE :
escape++ ;
break ;
case PARAGRAPH :
vcachechar ('\n') ;
vcachechar ('\n') ;
break ;
case INDENT :
if (vx > 3) vcachechar ('\n') ;
vx = 3 ;
break ;
case REFERENCE :
id = *++s ;
id += (unsigned) *++s * 256 ;
r = create_reference (id) ;
break ;
case TARGET :
break ;
case REFERENCE_ON :
if (r == NULL) break ;
vcachechar ('\0') ;
r->start_vx = vx ;
r->start_vy = vy ;
reference++ ;
set_attribute () ;
break ;
case REFERENCE_OFF :
if (r == NULL) break ;
vcachechar ('\0') ;
r->end_vx = vx ;
r->end_vy = vy ;
reference = 0 ;
r = NULL ;
set_attribute () ;
break ;
case HIGHLIGHT_ON :
case HIGHLIGHT_OFF :
highlight = *s == HIGHLIGHT_ON ;
set_attribute () ;
break ;
case BOLD_ON :
case BOLD_OFF :
bold = *s == BOLD_ON ;
set_attribute () ;
break ;
case CODE_ON :
code_fragment++ ;
set_attribute () ;
vcachechar ('\0') ;
if ((f = create_code_fragment ()) == NULL) break ;
f->start_vx = vx ;
f->start_vy = vy ;
f->length = 0 ;
f->offset = (unsigned long) s + 1 ;
break ;
case CODE_OFF :
code_fragment = 0 ;
set_attribute () ;
vcachechar ('\0') ;
if (f == NULL) break ;
f->end_vx = vx ;
f->end_vy = vy ;
f->length = (unsigned long) ((unsigned long) s - f->offset) - 1 ;
f = NULL ;
break ;
case HEADING_ON :
case HEADING_OFF :
heading = *s == HEADING_ON ;
set_attribute () ;
break ;
case LINE_ON :
case LINE_OFF :
line_drawing = *s == LINE_ON ;
set_attribute () ;
vcachechar ('\0') ;
break ;
case PRESERVE_ON :
case PRESERVE_OFF :
preserve_formatting = *s == PRESERVE_ON ;
set_attribute () ;
vcachechar ('\0') ;
break ;
case TABLE_ON :
case TABLE_OFF :
table = *s == TABLE_ON ;
set_attribute () ;
break ;
case LIST_ON :
if ((list = *++s) == 1) list++ ;
left_margin = list += 2 ;
break ;
case LIST_OFF :
left_margin = list = 0 ;
break ;
case LIST_ENTRY_ON :
list_entry++ ;
vcachechar ('\0') ;
set_attribute () ;
vx = 2 ;
break ;
case LIST_ENTRY_OFF :
list_entry = 0 ;
vcachechar ('\0') ;
set_attribute () ;
vx = left_margin ;
while (*s == ' ') s++ ;
break ;
default :
vcachechar (*s) ;
break ;
}
}
else
{
vcachechar (*s) ;
escape = 0 ;
}
}
vcachechar ('\0') ;
while (vy > 0 && line_is_blank (vy)) vy-- ;
if (reference)
{
reference_count-- ;
reference = 0 ;
}
target_offset = 0 ;
redraw_references () ;
redraw_code_fragments () ;
}
void format_top_menu (unsigned number_to_find)
{
unsigned i ;
unsigned offset ;
viewer_toc tc ;
clear_attributes () ;
set_attribute () ;
clear_references () ;
clear_virtual_screen () ;
memset (what_is_where, 0, sizeof (what_is_where)) ;
ignore_lines = number_to_find == 0 ? first_line : 32767 ;
target_line = 0 ;
vputstr ("\r\n") ;
attribute = 0x1e ;
cvputstr (title, TITLE) ;
attribute = 0x1a ;
cvputstr ("HELP ON HELP", HELP) ;
cvputstr ("COPYRIGHT", COPYRIGHT) ;
cvputstr ("AUTHORS", AUTHOR) ;
cvputstr ("FREQUENTLY ASKED QUESTIONS", FAQ) ;
vputstr ("\r\n") ;
attribute = 0x1f ;
for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
{
if (number_to_find)
ignore_lines = i < number_to_find ? 32767 : 0 ;
if (i == header.section_count)
{
vputstr ("\r\n") ;
attribute = 0x1a ;
cvputstr ("*** APPENDICES ***", 0) ;
attribute = 0x1f ;
vputstr ("\r\n") ;
}
tc = *getTC (i) ;
what_is_where [vy] [0] = CONTENTS ;
what_is_where [vy] [1] = i ;
offset = pointcount (tc.number) * 3 ;
vx = offset ;
vputstr (tc.number) ;
vx = 17 + offset ;
vputstr (tc.title) ;
vputstr ("\r\n") ;
}
while (vy > 0 && line_is_blank (vy)) vy-- ;
}
void format_general_text (char *s)
{
clear_attributes () ;
set_attribute () ;
clear_references () ;
clear_virtual_screen () ;
memset (what_is_where, 0, sizeof (what_is_where)) ;
ignore_lines = first_line ;
target_line = 0 ;
attribute = 0x1e ;
cvputstr (s, 0) ;
while (vy > 0 && line_is_blank (vy)) vy-- ;
}
void load_links (void)
{
unsigned child_count ;
link_count = 0 ;
link_number = -1 ;
if (current_reference == -1) return ;
fseek (inF, reference_index [references [current_reference].id], SEEK_SET) ;
fread (&child_count, 2, 1, inF) ;
if (child_count >= MAX_LINK - 1) child_count = MAX_LINK - 1 ;
fread (links, 4, link_count = child_count + 1, inF) ;
}
void push_context (int number, short first_line, int line, int column, short current_reference, short link_number)
{
bookmark *bm = bookmarks + current_bookmark ;
/*message_printf ("saved %d %d %d %d [%d]", number, first_line, line, column, current_bookmark) ;
localdelay (1000) ; */
if (current_bookmark >= MAX_BOOKMARK)
{
memcpy (bookmarks, bookmarks + 1, sizeof (bookmarks) - sizeof (bookmark)) ;
bm-- ;
}
else
current_bookmark++ ;
bm->number = number ;
bm->first_line = first_line ;
bm->line = line ;
bm->column = column ;
bm->reference = current_reference ;
bm->link_number = link_number ;
}
void pop_context (int *number, short *first_line, int *line, int *column, short *current_reference, short *link_number)
{
bookmark *bm ;
if (current_bookmark == 0) return ;
bm = bookmarks + --current_bookmark ;
if (number) *number = bm->number ;
if (first_line) *first_line = bm->first_line ;
if (line) *line = bm->line ;
if (column) *column = bm->column ;
if (current_reference) *current_reference = bm->reference ;
if (link_number) *link_number = bm->link_number ;
/*message_printf ("restored %d %d %d %d [%d]", *number, *first_line, *line, *column, current_bookmark) ;
localdelay (1000) ; */
}
void display (int *number, unsigned use_link, unsigned use_stack)
{
int ch ;
short reference ;
short code_fragment ;
unsigned i ;
unsigned child_count ;
unsigned bounce_me = 0 ;
unsigned temp ;
viewer_toc *t ;
viewer_reference *r ;
viewer_code_fragment *f ;
/* if use_stack is TRUE, restore our position from the position stack */
/* if use_link is TRUE, 'number' is an index into the reference array */
/* bounce_me is set internally to cause a jump to reference index 'number' */
/* use_link takes precedence over use_stack */
while (1)
{
line = column = 0 ;
if (section) emsfree (section) ;
if (use_link || bounce_me)
{
/* link_number is the currently selected link */
link_number = 0 ;
fseek (inF, reference_index [*number], SEEK_SET) ;
fread (&child_count, 2, 1, inF) ;
/* only support MAX_LINK children (links) */
if (child_count >= MAX_LINK - 1) child_count = MAX_LINK - 1 ;
/* retrieve the actual links from the file */
fread (links, 4, link_count = child_count + 1, inF) ;
/* find TOC entry for the section, working it out from the offset */
if ((t = findTCfromOffset (links [0])) == NULL)
{
message_printf ("link 0 [%08lx] not found", links [0]) ;
return ;
}
/* get the section ; the index is assigned to number */
section = get_section (&tc, *number = t->index) ;
/* no references or code fragments assigned */
current_reference = current_code_fragment = -1 ;
/* go to the first one */
target_offset = links [0] - tc.section ;
/* the first line to display is set to 0, so we display the top */
first_line = column = 0 ;
format_section (&tc, section) ;
/* try to keep at least one line above the target if possible */
line = target_line == 0 ? target_line : target_line - 1 ;
/* if we would go off the end of the window buffer ... */
if (line + wsize_y > VSIZE_Y)
{
first_line += VSIZE_Y / 2 ;
line = max (line - VSIZE_Y / 2, 0) ;
format_section (&tc, section) ;
}
/* try to be a bit helpful */
message_printf ("link 1 of %d - [+ Next], [- Previous]", link_count) ;
}
else
{
/* were we popped down ? (i.e. did they exit with the hot key ?) */
if (poppeddown == 0 && use_stack == 0)
{
/* assume 'number' is a table of contents index */
if ((section = get_section (&tc, *number)) == NULL) return ;
first_line = 0 ;
}
else
{
/* restore lots of hopefully useful stuff */
pop_context (number, &first_line, &line, &column, ¤t_reference, &link_number) ;
current_code_fragment = -1 ;
section = get_section (&tc, *number) ;
format_section (&tc, section) ;
if (link_number != -1)
message_printf ("link %d of %d - [+ Next], [- Previous]", link_number, link_count) ;
}
}
bounce_me = poppeddown = 0 ;
format_section (&tc, section) ;
current_reference = current_code_fragment = -1 ;
while (bounce_me == 0)
{
/* column and line are the x and y offsets of the upper left corner */
putwindow (column, line) ;
while (popdown == 0 && bioskey (0x11) == 0) geninterrupt (0x28) ;
if (popdown)
{
emsfree (section) ;
section = NULL ;
return ;
}
ch = bioskey (0x10) ;
switch ((unsigned char) ch)
{
case 0x00 :
case 0xe0 :
switch (ch = (unsigned char) (ch >> 8))
{
case 0x3b : /* F1 */
push_context (*number, first_line, line, column, current_reference, link_number) ;
if (use_link == 0) link_count = 0 ;
first_line = line = column = 0 ;
emsfree (section) ;
section = get_section (&tc, *number = 0) ;
current_reference = -1 ;
current_code_fragment = -1 ;
format_section (&tc, section) ;
message_printf ("Press BACKSPACE to backtrack") ;
break ;
case 0x50 : /* down */
if (line > (int) (vy - wsize_y)) break ;
if (++line + wsize_y > VSIZE_Y)
{
first_line += VSIZE_Y / 2 ;
line = max (line - VSIZE_Y / 2, 0) ;
format_section (&tc, section) ;
}
break ;
case 0x48 : /* up */
if (line == 0 && first_line == 0) break ;
if (--line <= 0 && first_line != 0)
{
first_line = max ((int) first_line - VSIZE_Y / 2, 0) ;
line = VSIZE_Y / 2 ;
format_section (&tc, section) ;
}
break ;
case 0x4d : /* right */
if (column < VSIZE_X - wsize_x) column++ ;
break ;
case 0x4b : /* left */
if (column) column-- ;
break ;
case 0x51 : /* page down */
if (line > (int) (vy - wsize_y)) break ;
if ((line += wsize_y) >= VSIZE_Y - wsize_y)
{
first_line += VSIZE_Y / 2 ;
format_section (&tc, section) ;
line = max (line - VSIZE_Y / 2, 0) ;
}
break ;
case 0x49 : /* page up */
if (line < wsize_y)
{
if (first_line < VSIZE_Y / 2)
{
line += first_line ;
first_line = 0 ;
}
else
{
first_line -= VSIZE_Y / 2 ;
line += VSIZE_Y / 2 ;
}
format_section (&tc, section) ;
}
line = line >= wsize_y ? line - wsize_y : 0 ;
break ;
case 0x76 : /* control-page down */
if (*number >= header.section_count + header.appendix_count - 1) break ;
first_line = line = column = 0 ;
/* if we used links, don't clear it so 'B' will still work */
if (use_link == 0) link_count = 0 ;
emsfree (section) ;
section = get_section (&tc, ++*number) ;
current_reference = -1 ;
current_code_fragment = -1 ;
format_section (&tc, section) ;
message_printf ("%s %s %s", tc.is_appendix ? "APPENDIX" : "", tc.number, tc.title) ;
break ;
case 0x84 : /* control-page up */
if (*number == 0) break ;
first_line = line = column = 0 ;
/* if we used links, don't clear it so 'B' will still work */
if (use_link == 0) link_count = 0 ;
emsfree (section) ;
section = get_section (&tc, --*number) ;
current_reference = -1;
current_code_fragment = -1 ;
format_section (&tc, section) ;
message_printf ("%s %s %s", tc.is_appendix ? "APPENDIX" : "", tc.number, tc.title) ;
break ;
case 0x0f : /* shift-tab */
if (reference_count == 0) break ;
reference = current_reference ;
for (i = 0, r = references + reference - 1 ; i < reference_count ; i++, r--)
{
if (reference-- < 0)
{
reference = reference_count - 1 ;
r = references + reference ;
}
if (r->start_vx > column + wsize_x - 1) continue ;
if (r->end_vx < column) continue ;
if (r->start_vy > line + wsize_y - 1) continue ;
if (r->end_vy < line) continue ;
break ;
}
if (i == reference_count) break ;
current_reference = reference ;
load_links () ;
message_printf ("%d link(s) for this reference - '+' for first", link_count) ;
redraw_references () ;
break ;
case 0xa5 : /* Alt-Tab */
if (code_fragment_count == 0) break ;
code_fragment = current_code_fragment ;
for (i = 0, f = code_fragments + code_fragment + 1 ; i < code_fragment_count ; i++, f++)
{
if (++code_fragment >= code_fragment_count)
{
code_fragment = 0 ;
f = code_fragments ;
}
if (f->start_vx > column + wsize_x - 1) continue ;
if (f->end_vx < column) continue ;
if (f->start_vy > line + wsize_y - 1) continue ;
if (f->end_vy < line) continue ;
break ;
}
if (i == code_fragment_count) break ;
current_code_fragment = code_fragment ;
redraw_code_fragments () ;
break ;
}
break ;
case '\t' :
if (reference_count == 0) break ;
reference = current_reference ;
for (i = 0, r = references + reference + 1 ; i < reference_count ; i++, r++)
{
if (++reference >= reference_count)
{
reference = 0 ;
r = references ;
}
if (r->start_vx > column + wsize_x - 1) continue ;
if (r->end_vx < column) continue ;
if (r->start_vy > line + wsize_y - 1) continue ;
if (r->end_vy < line) continue ;
break ;
}
if (i == reference_count) break ;
current_reference = reference ;
load_links () ;
message_printf ("%d link(s) for this reference - '+' for first", link_count) ;
redraw_references () ;
break ;
case ' ' :
if (*number >= header.section_count + header.appendix_count - 1) break ;
first_line = line = column = 0 ;
/* if we used links, don't clear it so 'B' will still work */
if (use_link == 0) link_count = 0 ;
emsfree (section) ;
section = get_section (&tc, ++*number) ;
current_reference = -1 ;
current_code_fragment = -1 ;
format_section (&tc, section) ;
message_printf ("%s %s %s", tc.is_appendix ? "APPENDIX" : "", tc.number, tc.title) ;
break ;
case 's' :
case 'S' :
if (message_gets ("Enter search key", search_string, sizeof (search_string) - 1) == 0)
{
if ((temp = findKeyword (search_string)) < 0xffff)
{
push_context (*number, first_line, line, column, -1, link_number) ;
*number = temp ;
bounce_me++ ;
}
else
{
message_printf ("'%s' : not found", search_string) ;
localdelay (1000) ;
}
}
message_printf ("") ;
break ;
case '+' :
case '-' :
case '\r' :
if (link_count == 0) break ;
if ((char) ch == '-')
{
if (link_number < 0) break ;
if (--link_number == -1)
{
pop_context (number, &first_line, &line, &column, ¤t_reference, &link_number) ;
current_code_fragment = -1 ;
emsfree (section) ;
section = get_section (&tc, *number) ;
format_section (&tc, section) ;
link_number = -1 ;
message_printf ("%d link(s) for this reference - '+' for first", link_count) ;
break ;
}
}
else
{
if (link_number == link_count - 1) break ;
if (link_number == -1)
push_context (*number, first_line, line, column, current_reference, link_number) ;
link_number++ ;
}
if ((t = findTCfromOffset (links [link_number])) == NULL)
{
message_printf ("link %d [%08lx] not found", link_number, links [link_number]) ;
break ;
}
emsfree (section) ;
section = get_section (&tc, *number = t->index) ;
current_reference = -1 ;
current_code_fragment = -1 ;
target_offset = links [link_number] - tc.section ;
first_line = 0 ;
format_section (&tc, section) ;
line = target_line == 0 ? target_line : target_line - 1 ;
column = 0 ;
if (line + wsize_y > VSIZE_Y)
{
first_line += VSIZE_Y / 2 ;
line = max (line - VSIZE_Y / 2, 0) ;
format_section (&tc, section) ;
}
message_printf ("link %d of %d - [+ Next], [- Previous]", link_number + 1, link_count) ;
break ;
case 'j' :
case 'J' :
justifyOn = !justifyOn ;
message_printf ("Justify %s", justifyOn ? "on" : "off") ;
format_section (&tc, section) ;
break ;
case 'p' :
case 'P' :
if (shell == 0 || current_code_fragment == -1) break ;
paste = min (code_fragments [current_code_fragment].length, sizeof (paste_buffer)) ;
memcpy (paste_buffer, (char *) code_fragments [current_code_fragment].offset, paste) ;
paste_ptr = paste_buffer ;
emsfree (section) ;
section = NULL ;
popdown++ ;
return ;
case '\b' :
if (current_bookmark == 0)
{
message_printf ("History stack empty") ;
localdelay (1000) ;
message_printf ("") ;
break ;
}
pop_context (number, &first_line, &line, &column, ¤t_reference, &link_number) ;
current_code_fragment = -1 ;
emsfree (section) ;
section = get_section (&tc, *number) ;
format_section (&tc, section) ;
link_number = use_link ? 0 : -1 ;
message_printf ("Backtracked to section %s", tc.number) ;
break ;
case '\x1b' :
emsfree (section) ;
section = NULL ;
return ;
default :
break ;
}
}
}
}
void display_text (unsigned what)
{
int line = 0 ;
int column = 0 ;
int ch ;
char *text ;
char *s ;
unsigned i ;
unsigned long offset ;
unsigned long length ;
poppeddown = 0 ;
switch (what)
{
case COPYRIGHT :
offset = header.copyright ;
length = header.copyright_length ;
break ;
case AUTHOR :
offset = header.authors ;
length = header.author_length ;
break ;
default :
return ;
}
first_line = 0 ;
if (length > 65534U)
{
message_printf ("section too big for present allocation code") ;
localdelay (1000) ;
return ;
}
if ((text = emscalloc ((unsigned) length + 1, 1)) == NULL)
{
message_printf ("cannot allocate memory for text") ;
localdelay (1000) ;
return ;
}
fseek (inF, offset, SEEK_SET) ;
if (fread (text, (unsigned) length + 1, 1, inF) == 0)
{
message_printf ("could not read text") ;
localdelay (1000) ;
emsfree (text) ;
return ;
}
text [(unsigned) length] = 0 ;
for (s = text, i = (unsigned) length ; i ; i--, s++)
if (*s == '\0')
*s = '\n' ;
if (what == AUTHOR)
format_general_text (text) ;
else
format_section (NULL, text) ;
message_printf (what == AUTHOR ? "List of Authors" : "Copyright information") ;
while (1)
{
putwindow (column, line) ;
while (popdown == 0 && bioskey (0x11) == 0) geninterrupt (0x28) ;
if (popdown)
{
emsfree (text) ;
return ;
}
switch ((char) (ch = bioskey (0x10)))
{
case 0x00 :
case 0xe0 :
switch (ch >> 8)
{
case 0x50 : /* down */
if (line > (int) (vy - wsize_y)) break ;
if (++line + wsize_y > VSIZE_Y)
{
first_line += VSIZE_Y / 2 ;
line = max (line - VSIZE_Y / 2, 0) ;
if (what == AUTHOR)
format_general_text (text) ;
else
format_section (NULL, text) ;
}
break ;
case 0x48 : /* up */
if (line == 0 && first_line == 0) break ;
if (--line == 0 && first_line != 0)
{
first_line = max ((int) first_line - VSIZE_Y / 2, 0) ;
line = VSIZE_Y / 2 ;
if (what == AUTHOR)
format_general_text (text) ;
else
format_section (NULL, text) ;
}
break ;
case 0x4d : /* right */
if (column < VSIZE_X - wsize_x) column++ ;
break ;
case 0x4b : /* left */
if (column) column-- ;
break ;
case 0x51 : /* page down */
if (line > (int) (vy - wsize_y)) break ;
if ((line += wsize_y) >= VSIZE_Y - wsize_y)
{
first_line += VSIZE_Y / 2 ;
if (what == AUTHOR)
format_general_text (text) ;
else
format_section (NULL, text) ;
line = max (line - VSIZE_Y / 2, 0) ;
}
break ;
case 0x49 : /* page up */
if (line < wsize_y)
{
if (first_line < VSIZE_Y / 2)
{
line += first_line ;
first_line = 0 ;
}
else
{
first_line -= VSIZE_Y / 2 ;
line += VSIZE_Y / 2 ;
}
if (what == AUTHOR)
format_general_text (text) ;
else
format_section (NULL, text) ;
}
line = line >= wsize_y ? line - wsize_y : 0 ;
break ;
}
break ;
case '\x1b' :
emsfree (text) ;
return ;
default :
break ;
}
}
}
void display_top_menu (int *number)
{
int column = 0 ;
int ch ;
int temp ;
unsigned selection ;
viewer_toc tc ;
static int selected_line = 0 ;
static int line = 0 ;
static int local_first_line = 0 ;
poppeddown = 0 ;
first_line = local_first_line ;
format_top_menu (0) ;
while (selected_line < VSIZE_Y && what_is_where [selected_line] [0] < COPYRIGHT) selected_line++ ;
if (selected_line >= wsize_y)
{
selected_line = wsize_y - 1 ;
if (line <= (int) (vy - wsize_y))
{
if (++line + wsize_y > VSIZE_Y)
{
local_first_line = first_line += VSIZE_Y / 2 ;
line = max (line - VSIZE_Y / 2, 0) ;
format_top_menu (0) ;
}
}
}
while (1)
{
putwindow (column, line) ;
selection = what_is_where [line + selected_line] [0] ;
*number = what_is_where [line + selected_line] [1] ;
switch (selection)
{
case AUTHOR :
message_printf ("Press ENTER to list Authors") ;
break ;
case COPYRIGHT :
message_printf ("Press ENTER for Copyright details") ;
break ;
case FAQ :
message_printf ("Press ENTER to read FAQ") ;
break ;
case HELP :
message_printf ("Press ENTER or F1 for HELP") ;
break ;
case CONTENTS :
tc = *getTC (*number) ;
message_printf ("%s", tc.title) ;
break ;
default :
message_printf ("") ;
break ;
}
highlight_line (selected_line, selection > TITLE ? 0x4f : 0x3f) ;
while (popdown == 0 && bioskey (0x11) == 0) geninterrupt (0x28) ;
if (popdown)
{
popdown = 0 ;
return ;
}
switch ((char) (ch = bioskey (0x10)))
{
case 0x00 :
case 0xe0 :
switch (ch >> 8)
{
case 0x50 : /* down */
if (++selected_line < wsize_y) break ;
selected_line = wsize_y - 1 ;
if (line > (int) (vy - wsize_y)) break ;
if (++line + wsize_y > VSIZE_Y)
{
local_first_line = first_line += VSIZE_Y / 2 ;
line = max (line - VSIZE_Y / 2, 0) ;
format_top_menu (0) ;
}
break ;
case 0x48 : /* up */
if (--selected_line >= 0) break ;
selected_line = 0 ;
if (line == 0 && first_line == 0) break ;
if (--line == 0 && first_line != 0)
{
local_first_line = first_line = max ((int) first_line - VSIZE_Y / 2, 0) ;
line = VSIZE_Y / 2 ;
format_top_menu (0) ;
}
selected_line = 0 ;
break ;
case 0x4d : /* right */
if (column < VSIZE_X - wsize_x) column++ ;
break ;
case 0x4b : /* left */
if (column) column-- ;
break ;
case 0x51 : /* page down */
if (line > (int) (vy - wsize_y)) break ;
if ((line += wsize_y) >= VSIZE_Y - wsize_y)
{
local_first_line = first_line += VSIZE_Y / 2 ;
format_top_menu (0) ;
line = max (line - VSIZE_Y / 2, 0) ;
}
break ;
case 0x49 : /* page up */
if (line < wsize_y)
{
if (first_line < VSIZE_Y / 2)
{
line += first_line ;
first_line = 0 ;
}
else
{
local_first_line = first_line -= VSIZE_Y / 2 ;
line += VSIZE_Y / 2 ;
}
format_top_menu (0) ;
}
line = line >= wsize_y ? line - wsize_y : 0 ;
break ;
case 0x3b : /* F1 */
if ((*number = findTitle ("HELP ON HELP")) == -1) break ;
message_printf ("Press SPACE for next section") ;
display (number, 0, 0) ;
first_line = local_first_line ;
format_top_menu (0) ;
break ;
}
break ;
case '\r' :
switch (selection)
{
case AUTHOR :
case COPYRIGHT :
display_text (selection) ;
if (popdown)
{
popdown = 0 ;
return ;
}
break ;
case FAQ :
if ((*number = findTitle ("FREQUENTLY ASKED QUESTIONS")) == -1) break ;
message_printf ("Press SPACE for next section") ;
display (number, 0, 0) ;
if (popdown) return ;
break ;
case HELP :
if ((*number = findTitle ("HELP ON HELP")) == -1) break ;
message_printf ("Press SPACE for next section") ;
display (number, 0, 0) ;
if (popdown) return ;
break ;
case CONTENTS :
display (number, 0, 0) ;
if (popdown) return ;
break ;
}
first_line = local_first_line ;
format_top_menu (0) ;
break ;
case 's' :
case 'S' :
if (message_gets ("Enter search key", search_string, sizeof (search_string) - 1) == 0)
{
if ((temp = findKeyword (search_string)) != -1)
{
display (&temp, 1, 0) ;
break ;
}
else
{
message_printf ("'%s' : not found", search_string) ;
localdelay (1000) ;
}
}
message_printf ("") ;
break ;
case '\x1b' :
return ;
default :
break ;
}
}
}
unsigned load_strings (void)
{
char *s ;
char str [81] ;
unsigned i ;
unsigned count ;
if ((reference_strings = farcalloc ((unsigned) header.reference_string_length, 1)) == NULL) return (1) ;
if ((reference_string_index = farcalloc (header.reference_count * 4, 1)) == NULL) return (1) ;
s = reference_strings ;
for (i = 0 ; i < header.reference_count ; i++)
{
fseek (inF, reference_index [i], SEEK_SET) ;
fread (&count, 2, 1, inF) ;
fseek (inF, (count + 1) * 4, SEEK_CUR) ;
if (fgets (str, 80, inF) == NULL) break ;
strcpy (s, str) ;
reference_string_index [i] = s ;
s += strlen (str) + 1 ;
}
return (0) ;
}
void init (void)
{
if ((references = calloc (sizeof (viewer_reference), MAX_REF)) == NULL)
{
printf ("cannot allocate memory for references\r\n") ;
exit (1) ;
}
if ((code_fragments = calloc (sizeof (viewer_code_fragment), MAX_FRAGMENT)) == NULL)
{
printf ("cannot allocate memory for code fragments\r\n") ;
exit (1) ;
}
if ((virtual_screen = calloc (VSIZE_X * 2, VSIZE_Y)) == NULL)
{
printf ("cannot allocate memory for virtual display\r\n") ;
exit (1) ;
}
clear_virtual_screen () ;
memcpy (blank, virtual_screen, VSIZE_X * 2) ;
if ((toc = malloc ((unsigned) header.table_of_contents_length)) == NULL)
{
printf ("cannot allocate memory for table of contents\r\n") ;
exit (1) ;
}
TOCsize = sizeof (TOC_entry) + header.sec_number_len + header.sec_title_len ;
if ((reference_index = malloc ((unsigned) header.reference_index_length)) == NULL)
{
printf ("cannot allocate memory for reference index\r\n") ;
exit (1) ;
}
fseek (inF, header.reference_index, SEEK_SET) ;
if (fread (reference_index, (unsigned) header.reference_index_length, 1, inF) == 0)
{
printf ("could not read reference index\r\n") ;
exit (1) ;
}
if ((title = calloc ((unsigned) header.title_length + 1, 1)) == NULL)
{
printf ("cannot allocate memory for title\r\n") ;
exit (1) ;
}
fseek (inF, header.title, SEEK_SET) ;
if (fread (title, (unsigned) header.title_length + 1, 1, inF) == 0)
{
printf ("could not read title\r\n") ;
exit (1) ;
}
title [(unsigned) header.title_length] = 0 ;
if (load_strings ())
{
printf ("could not load reference strings\r\n") ;
exit (1) ;
}
}
void popup (void)
{
int number = -1 ;
int i ;
char x ;
char y ;
char *s = "" ;
char ch ;
unsigned keyword_found = 0 ;
union REGS regs ;
static char str [133] ;
mousestate (0) ;
regs.h.ah = 0x03 ;
regs.h.bh = 0 ;
int86 (0x10, ®s, ®s) ;
x = regs.h.dl ;
y = regs.h.dh ;
if (x < 0 || x > COLUMNS) x = 0 ;
if (y < 0 || y > 50) y = 0 ;
if (poppeddown == 0)
{
get_line (y, str) ;
for (i = x ; i < COLUMNS && isalnum (str [i]) == 0 && str [i] != ' ' ; i++) ;
while (--i >= 0)
{
if (isalnum (str [i])) continue ;
switch (str [i])
{
case '_' :
case '.' : continue ;
}
break ;
}
s = str + i + 1 ;
while (++i < COLUMNS)
{
if (isalnum (str [i])) continue ;
switch (str [i])
{
case '_' :
case '.' : continue ;
}
break ;
}
str [i] = '\0' ;
}
memcpy (saved_screen, MK_FP (base, 0), sizeof (saved_screen)) ;
frame () ;
if (emsstore (0))
{
message_printf ("error in saving EMS page mapping") ;
localdelay (1000) ;
memcpy (MK_FP (base, 0), saved_screen, sizeof (saved_screen)) ;
gotoxy (x, y) ;
mousestate (1) ;
return ;
}
if (*s)
{
if ((number = findKeyword (s)) != -1) keyword_found++ ;
if (keyword_found == 0)
if ((number = findKeyword (s + 1)) != -1)
keyword_found++ ;
if (keyword_found == 0)
{
ch = s [strlen (s) - 1] ;
s [strlen (s) - 1] = '\0' ;
if ((number = findKeyword (s)) != -1) keyword_found++ ;
s [strlen (s)] = ch ;
}
if (keyword_found == 0)
{
if (number == -1) number = findTitle (s) ;
if (number == -1) number = findSection (s) ;
}
}
if (number != -1 || poppeddown)
{
message_printf (poppeddown ? "" : "searching on '%s'", s) ;
display (&number, keyword_found, poppeddown) ;
if (popdown == 0) display_top_menu (&number) ;
}
else
display_top_menu (&number) ;
if ((poppeddown = popdown) != 0)
push_context (number, first_line, line, column, current_reference, link_number) ;
if (emsstore (1))
{
for (i = 0 ; i < 5 ; i++)
{
message_printf ("WARNING !!! error in restoring EMS page mapping") ;
localdelay (500) ;
message_printf ("*** memory corruption possible !!! ***") ;
localdelay (500) ;
}
}
memcpy (MK_FP (base, 0), saved_screen, sizeof (saved_screen)) ;
regs.h.ah = 0x02 ;
regs.h.bh = 0 ;
regs.h.dl = x ;
regs.h.dh = y ;
int86 (0x10, ®s, ®s) ;
mousestate (1) ;
}
void Help (void)
{
printf ("\r\nPOVHELP : POV-Help reader for DOS\r\n\n") ;
printf ("-i : set input file name (default HELP.PHE)\r\n") ;
printf ("-w : set width of window\r\n") ;
printf ("-h : set height of window\r\n") ;
printf ("-ph[n] : send HOME key after each CR when pasting. default is -ph1\r\n") ;
printf ("-j[-] : justify ON (default), -j- to turn off\r\n") ;
printf ("-sX.Y : go to section X.Y\r\n") ;
printf ("-tABC : go to first section with ABC in its title\r\n") ;
printf ("-nn : go to the nth section (first = 0)\r\n") ;
printf ("-kALT-H : set hotkey to ALT-H [CTRL, CTRL-ALT, A-Z, 0-9 permitted]\r\n") ;
printf ("-eXYZ.EXE : run program XYZ.EXE (all subsequent params are passed to XYZ)\r\n") ;
printf ("ABC : jump to first reference for keyword ABC\r\n") ;
printf ("\r\n") ;
printf ("POV-Help was written by Christopher J. Cason (cjcason@yarrow.wt.uwa.edu.au).\r\n") ;
printf ("Converters are available which translate POV-Help databases to other formats\r\n") ;
printf ("such as Postscript, LaTeX, RTF, Windows Help, HTML, etc.\r\n") ;
printf ("The format of the POV-Help database is documentaed and freely available.\r\n") ;
printf ("\r\n") ;
printf ("POV-Help is free. It may not be sold. See POVLEGAL.DOC for details.\r\n") ;
printf ("The POV-Help suite of programs is copyright (c) 1994 C. Cason and the POV-Team.\r\n") ;
}
unsigned main (unsigned argc, char *argv [])
{
int number = -1 ;
char *s1 = "HELP.PHE" ;
char gotoSection [16] = "" ;
char gotoTitle [80] = "" ;
char gotoKeyword [80] = "" ;
char execName [128] = "" ;
char keycode [32] = "ALT-ESC" ;
char path [80] ;
char drive [8] ;
char dir [80] ;
char name [16] ;
char ext [8] ;
char ch ;
unsigned copyExec = 0 ;
unsigned keyword_found = 0 ;
union REGS regs ;
regs.h.ah = 0x0f ;
int86 (0x10, ®s, ®s) ;
if ((regs.h.al & 0x7f) == 0x07) base = 0xb000 ;
regs.x.ax = 0x21 ;
int86 (0x33, ®s, ®s) ;
mouseInstalled = regs.x.ax == 0xffff ;
if ((inF = fopen (s1, "rb")) == NULL)
{
fnsplit (*argv, drive, dir, name, ext) ;
fnmerge (path, drive, dir, "HELP", ".PHE") ;
s1 = path ;
}
else
fclose (inF) ;
while (++argv, --argc)
{
if (copyExec == 0 && (**argv == '-' || **argv == '+'))
{
switch (toupper ((*argv) [1]))
{
case 'I' :
s1 = *argv + 2 ;
break ;
case 'J' :
justifyOn = (*argv) [2] != '-' ;
break ;
case 'N' :
number = atoi (*argv + 2) ;
break ;
case 'W' :
if (atoi (*argv + 2) == 0)
{
printf ("\r\n'%s' : invalid argument\r\n", *argv) ;
Help () ;
return (0) ;
}
wsize_x = max (25, min (127, atoi (*argv + 2))) ;
break ;
case 'H' :
if ((*argv) [2] == '\0')
{
Help () ;
return (0) ;
}
if (atoi (*argv + 2) == 0)
{
printf ("\r\n'%s' : invalid argument\r\n", *argv) ;
Help () ;
return (0) ;
}
wsize_y = max (5, min (21, atoi (*argv + 2))) ;
break ;
case 'S' :
strncpy (gotoSection, *argv + 2, 15) ;
break ;
case 'T' :
strncpy (gotoTitle, *argv + 2, 79) ;
break ;
case 'E' :
strncpy (execName, *argv + 2, 127) ;
fnsplit (execName, NULL, NULL, name, ext) ;
if (strcmp (strupr (name), "EDIT") == 0 && strcmp (strupr (ext), ".COM") == 0)
{
printf ("\x07WARNING : POV-Help has a known incompatibility with DOS'S EDIT.COM\r\n") ;
printf (" If this is the program you are trying to run, your system may crash.\r\n") ;
printf ("Continue ? [y/N] : ") ;
ch = getchar () ;
if (toupper (ch) != 'Y') return (1) ;
printf ("\r\n") ;
}
copyExec++ ;
break ;
case 'K' :
strncpy (keycode, *argv + 2, 32) ;
break ;
case 'P' :
if (toupper ((*argv) [2]) == 'H') home_wanted = 1 ;
if (isdigit ((*argv) [3])) home_wanted = '0' - (*argv) [3] ;
break ;
case '?' :
Help () ;
return (0) ;
default :
printf ("unknown option '%s' [povhelp -? for help]\r\n", *argv) ;
return (1) ;
}
}
else
if (copyExec)
{
strncat (execName, " ", 127) ;
strncat (execName, *argv, 127) ;
}
else
strncpy (gotoKeyword, *argv, 79) ;
}
if (keycode [0] != '\0')
{
if (translate_keycode (keycode))
{
printf ("invalid keycode string, '%s'\r\n", keycode) ;
return (1) ;
}
}
if ((inF = fopen (s1, "rb")) == NULL)
{
printf ("could not open input file '%s'\r\n", s1) ;
return (1) ;
}
if (fread (&header, sizeof (help_file_header), 1, inF) == 0)
{
printf ("could not read header\r\n") ;
return (1) ;
}
if (memcmp (header.signature, "POV-Help", 8) != 0)
{
printf ("header ID failed consistency check\r\n") ;
return (1) ;
}
if (header.reader_version > VERSION)
{
printf ("version error ! database is not compatible [needs version %d.%d of reader]\r\n",
header.reader_version / 100, header.reader_version % 100) ;
return (1) ;
}
init () ;
fseek (inF, header.table_of_contents, SEEK_SET) ;
if (fread (toc, (unsigned) header.table_of_contents_length, 1, inF) == 0)
{
printf ("could not read table of contents\r\n") ;
return (1) ;
}
if (*gotoTitle) number = findTitle (gotoTitle) ;
if (*gotoSection) number = findSection (gotoSection) ;
if (*gotoKeyword)
if ((number = findKeyword (gotoKeyword)) != -1) keyword_found++ ;
if (number < 0 && execName [0])
{
shell++ ;
if (emsinit ())
{
printf ("could not initialise/allocate EMS for shell mode\r\n") ;
return (1) ;
}
printf ("POV-Help v%d.%d - loading '%s' [use %s to pop up]\r\n",
VERSION / 100, VERSION % 100, execName, keycode) ;
kbinit () ;
if (system (execName)) printf ("[could not execute command '%s']\r\n", execName) ;
deinit () ;
printf ("POV-Help - finished. (c) Christopher J. Cason/POV-Team 1994\r\n") ;
emsfinish () ;
shell-- ;
}
else
{
mousestate (0) ;
clrscr () ;
frame () ;
if (number >= 0) display (&number, keyword_found, 0) ;
display_top_menu (&number) ;
gotoxy (1, 23) ;
printf ("POV-Help v%d.%d - finished. (c) Christopher J. Cason/POV-Team 1994\r\n",
VERSION / 100, VERSION % 100) ;
mousestate (1) ;
}
farfree (reference_string_index) ;
farfree (reference_strings) ;
free (toc) ;
free (virtual_screen) ;
free (code_fragments) ;
free (references) ;
free (title) ;
fclose (inF) ;
return (0) ;
}