home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
editor
/
pminfo
/
pminfo.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-31
|
28KB
|
1,073 lines
/*
Program PM-Info: a program for viewing GNU-style hypertext info
documentation files.
Copyright (C) 1992 Colin Jensen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Contact addresses:
Colin Jensen
email: cjensen@ampex.com or ljensen@netcom.netcom.com
US mail: 4902 Esguerra Terrace, Fremont CA, 94555
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifdef DEBUG
#define BUGME(exp) exp
#else
#define BUGME(exp)
#endif
#include "pminfo.h"
extern char *embedded_text_COPYING[], *embedded_text_Copyrght[];
extern int embedded_text_COPYING_count, embedded_text_Copyrght_count;
BUGME(FILE *fnote;)
#ifdef DEBUG
#define NOTE(id) \
do { fprintf(fnote, #id " is %d\n", id); fflush(fnote); } while(0)
#else
#define NOTE(id)
#endif /* DEBUG */
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define LIMIT(v,a,b) (v) = max((a),min((b),(v)))
extern "C" {
#define INCL_WIN
#define INCL_GPI
#include <os2.h>
}
class StdWin
{
private:
static StdWin *stdwinlist;
StdWin *stdwinlist_next;
static MRESULT ClientWndProcWhack(HWND, USHORT, MPARAM, MPARAM);
MRESULT ClientWndProc(HWND, USHORT, MPARAM, MPARAM);
HWND frame;
public:
HWND window;
virtual MRESULT MsgSize(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgPaint(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgCreate(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgVscroll(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgHscroll(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgButton1Down(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgChar(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgCommand(HWND, USHORT, MPARAM, MPARAM, int *);
StdWin(void);
void Init(HAB, const char *classname, ULONG message_flags,
ULONG frame_flags);
void Destroy(void);
static void StdStartup(HAB *hab, HMQ *hmq);
static void StdMainLoop(HAB hab);
static void StdExit(HAB hab, HMQ hmq);
};
StdWin *StdWin::stdwinlist = NULL;
MRESULT StdWin::MsgCreate(HWND, USHORT, MPARAM, MPARAM, int *)
{
BUGME(fprintf(fnote, "Well, how did I get here?\n");)
return 0;
}
MRESULT StdWin::MsgSize(HWND, USHORT, MPARAM, MPARAM, int *dodefault)
{
*dodefault = 1;
return 0;
}
MRESULT StdWin::MsgPaint(HWND hwnd, USHORT, MPARAM, MPARAM, int *)
{
// By default, draw a blank window
HPS hps = WinBeginPaint(hwnd, NULL, NULL);
GpiErase(hps);
WinEndPaint(hps);
return 0;
}
MRESULT StdWin::MsgVscroll(HWND, USHORT, MPARAM, MPARAM, int *dodefault)
{
*dodefault = 1;
return 0;
}
MRESULT StdWin::MsgHscroll(HWND, USHORT, MPARAM, MPARAM, int *dodefault)
{
*dodefault = 1;
return 0;
}
MRESULT StdWin::MsgChar(HWND, USHORT, MPARAM, MPARAM, int *dodefault)
{
*dodefault = 1;
return 0;
}
MRESULT StdWin::MsgButton1Down(HWND, USHORT, MPARAM, MPARAM, int *dodefault)
{
*dodefault = 1;
return 0;
}
MRESULT StdWin::MsgCommand(HWND, USHORT, MPARAM, MPARAM, int *dodefault)
{
*dodefault = 1;
return 0;
}
StdWin::StdWin(void)
{
}
void StdWin::Init(HAB hab, const char *classname, ULONG message_flags,
ULONG frame_flags)
{
// Insert self into list of event windows
stdwinlist_next = stdwinlist;
stdwinlist = this;
// Register the class with PM
static int is_registered = 0;
if (!is_registered) {
is_registered = 1;
WinRegisterClass(hab, (PSZ)classname, ClientWndProcWhack,
message_flags, 0);
}
// Then instantiate ourself
frame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &frame_flags,
(PSZ)classname, NULL, 0L, 0, ID_RESOURCE, &window);
WinSendMsg(frame, WM_SETICON,
WinQuerySysPointer(HWND_DESKTOP, SPTR_APPICON, FALSE),
NULL);
}
void StdWin::Destroy(void)
{
WinDestroyWindow(frame);
}
MRESULT StdWin::ClientWndProcWhack(HWND window, USHORT msg, MPARAM mp1,
MPARAM mp2)
{
StdWin *target_window;
// Locate ourself in the list of existing windows, and exec ourself
for (target_window = stdwinlist; target_window != NULL;
target_window = target_window->stdwinlist_next) {
if (target_window->window == window)
return target_window->ClientWndProc(window, msg, mp1, mp2);
}
// We really should never fall thru this loop, but just in case
return WinDefWindowProc(window, msg, mp1, mp2);
}
MRESULT StdWin::ClientWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{
int dodefault = 0;
MRESULT result;
switch(msg) {
case WM_CREATE:
BUGME(fprintf(fnote, "Client Proc: CREATE\n");)
result = MsgCreate(hwnd, msg, mp1, mp2, &dodefault);
break;
case WM_SIZE:
BUGME(fprintf(fnote, "Client Proc: SIZE\n");)
result = MsgSize(hwnd, msg, mp1, mp2, &dodefault);
break;
case WM_PAINT:
BUGME(fprintf(fnote, "Client Proc: PAINT\n");)
result = MsgPaint(hwnd, msg, mp1, mp2, &dodefault);
break;
case WM_VSCROLL:
BUGME(fprintf(fnote, "Client Proc: VSCROLL\n");)
result = MsgVscroll(hwnd, msg, mp1, mp2, &dodefault);
break;
case WM_HSCROLL:
BUGME(fprintf(fnote, "Client Proc: HSCROLL\n");)
result = MsgHscroll(hwnd, msg, mp1, mp2, &dodefault);
break;
case WM_BUTTON1DOWN:
BUGME(fprintf(fnote, "Client Proc: Button 1 Down\n");)
result = MsgButton1Down(hwnd, msg, mp1, mp2, &dodefault);
break;
case WM_CHAR:
BUGME(fprintf(fnote, "Client Proc: Char\n");)
result = MsgChar(hwnd, msg, mp1, mp2, &dodefault);
break;
case WM_COMMAND:
BUGME(fprintf(fnote, "Client Proc: Command\n");)
result = MsgCommand(hwnd, msg, mp1, mp2, &dodefault);
break;
default:
//BUGME(fprintf(fnote, "Client Proc: MSG 0x%04X\n", msg);)
dodefault = 1;
}
return (dodefault) ? WinDefWindowProc(hwnd, msg, mp1, mp2) : result;
}
void StdWin::StdStartup(HAB *hab, HMQ *hmq)
{
*hab = WinInitialize(0);
*hmq = WinCreateMsgQueue(*hab, 0);
}
void StdWin::StdMainLoop(HAB hab)
{
QMSG qmsg;
while (WinGetMsg(hab, &qmsg, NULL, 0, 0)) {
WinDispatchMsg(hab, &qmsg);
}
}
void StdWin::StdExit(HAB hab, HMQ hmq)
{
WinDestroyMsgQueue(hmq);
WinTerminate(hab);
}
char *fgetline(FILE *f)
{
char buf[1024];
char *p;
char strcount;
char *dp, *sp;
// Get a line from the input stream
p = fgets(buf, sizeof(buf), f);
if (p == NULL) return NULL;
// Trim off trailing nl and cr
p = buf + strlen(buf) - 1;
while (p >= buf && isspace(*p)) *p-- = '\0';
// Decide how many chars this is, after tab expansion
for (strcount = 0, p = buf; *p != '\0'; p++) {
if (*p == '\t') {
strcount += 8 - ((p - buf) % 8);
} else {
strcount++;
}
}
// Alloc a permanent place for the expanded string
p = (char *) malloc(strcount+1);
// Expand the string into its permanent destination
for (sp = buf, dp = p; *sp != '\0'; sp++) {
if (*sp == '\t') {
strcount = 8 - ((sp - buf) % 8);
while (strcount-- > 0) *dp++ = ' ';
} else {
*dp++ = *sp;
}
}
*dp = '\0';
return p;
}
typedef struct {
char *filename;
long int position;
} SplitRec;
typedef struct splitlist_struct SplitList;
struct splitlist_struct {
SplitList *next;
SplitRec split;
};
SplitList *splitlist_cons(SplitRec split, SplitList *next)
{
SplitList *list = (SplitList *) malloc(sizeof(SplitList));
list->split = split;
list->next = next;
return list;
}
class HistoryList
{
char **const history;
const int size;
int current_size, current_pos;
public:
char *pop();
void push(const char *);
HistoryList(int asize);
};
HistoryList::HistoryList(int asize)
: size(asize),
history(malloc(sizeof(char *) * asize)),
current_size(0),
current_pos(0)
{
}
char *HistoryList::pop(void)
{
if (current_size == 0) return NULL;
current_size--;
if (current_pos == 0) {
current_pos = size-1;
} else {
current_pos--;
}
return history[current_pos];
}
void HistoryList::push(const char *pushval)
{
if (current_size == size) {
/* free entry before filling */
free(history[current_pos]);
} else {
current_size++;
}
history[current_pos++] = strdup(pushval);
if (current_pos >= size) {
current_pos = 0;
}
};
class InfoFile
{
private:
int okval;
int split_file;
SplitList *splitlist;
int tags_table_availible;
SplitList *tags_table;
FILE *infofile;
HistoryList history;
char *most_recent_filename;
void open(const char *);
void getnode_attempt(const char *nodename, char ***page, int *pagelen);
public:
int ok(void) { return okval; }
InfoFile(const char *filename);
~InfoFile(void);
void getnode(const char *nodename, char ***page, int *pagelen);
void get_last_node(char ***page, int *pagelen);
};
void InfoFile::open(const char *filename)
{
if (most_recent_filename != NULL) free(most_recent_filename);
most_recent_filename = strdup(filename);
BUGME(fprintf(fnote, "InfoFile::open(%s)\n", filename);)
infofile = fopen(filename, "rt");
if (infofile == NULL) {
okval = 0;
BUGME(fprintf(fnote, "failed to open\n");)
return;
}
okval = 1;
split_file = 0; /* Hopefully... */
tags_table_availible = 0;
/* See if we can find an indirect table */
BUGME(fprintf(fnote, "Looking to see if we have a split file\n");)
char buf[1024];
char *p;
for(;;) {
p = fgets(buf, sizeof(buf), infofile);
if (p == NULL) return;
if (*p != '\x1F') continue;
p = fgets(buf, sizeof(buf), infofile);
if (p == NULL) return;
const char * const indirect = "Indirect:";
if (strncmp(p, indirect, strlen(indirect))) continue;
/* Drat! It is a split file */
split_file = 1;
break;
}
BUGME(fprintf(fnote, "Split file detected\n");)
char buf2[1024];
int position;
int match;
SplitRec splitrec;
splitlist = NULL;
for(;;) {
p = fgets(buf, sizeof(buf), infofile);
if (p == NULL || *p == '\x1F') break;
match = sscanf(buf, "%[^:]: %d", buf2, &position);
if (match != 2) continue;
splitrec.filename = strdup(buf2);
splitrec.position = position;
splitlist = splitlist_cons(splitrec, splitlist);
}
#ifdef DEBUG
SplitList *sl;
for (sl = splitlist; sl != NULL; sl = sl->next) {
fprintf(fnote, "Subfile ``%s'' at offset %ld\n", sl->split.filename,
sl->split.position);
}
#endif
// Now look for a tags table -- We will need it for large files
BUGME(fprintf(fnote, "Seeking tag table\n");)
fseek(infofile, 0L, SEEK_SET);
for(;;) {
p = fgets(buf, sizeof(buf), infofile);
if (p == NULL) return;
if (*p != '\x1F') continue;
p = fgets(buf, sizeof(buf), infofile);
if (p == NULL) return;
const char * const tag_table_name = "Tag Table:";
if (strncmp(p, tag_table_name, strlen(tag_table_name))) continue;
// Yes, we have a tag table
break;
}
tags_table_availible = 1;
BUGME(fprintf(fnote, "Got a tag table\n");)
tags_table = NULL;
SplitRec tag;
for(;;) {
p = fgets(buf, sizeof(buf), infofile);
if (p == NULL || *p == '\x1F') break;
match = sscanf(buf, "Node: %[^\x7F]\x7F %ld", buf2, &position);
if (match != 2) continue;
tag.filename = strdup(buf2);
tag.position = position;
tags_table = splitlist_cons(tag, tags_table);
}
#ifdef DEBUG
for (sl = tags_table; sl != NULL; sl = sl->next) {
fprintf(fnote, "Node ``%s'' at offset %ld\n", sl->split.filename,
sl->split.position);
}
#endif
}
InfoFile::InfoFile(const char *filename)
: history(32),
most_recent_filename(NULL)
{
open(filename);
}
InfoFile::~InfoFile(void)
{
if (!ok()) return;
fclose(infofile);
}
void InfoFile::getnode_attempt(const char *nodename, char ***page, int *pagelen)
{
char *p, *pnode;
int lines_searched = 0;
char buf[1024];
BUGME(fprintf(fnote, "InfoFile::getnode_attempt(%s, ...)\n", nodename);)
for(;;) {
// Get a line
p = fgets(buf, sizeof(buf), infofile);
if (p == NULL) goto attempt_fail;
lines_searched++;
// Wait until we have a new page
if (*p != '\x1F') continue;
// Get the startup line
p = fgetline(infofile);
if (p == NULL) goto attempt_fail;
lines_searched++;
// If it is not a nodeline, try some more
if (strncmp(p,"File:",5)) {
free(p);
continue;
}
// Get the node name
pnode = strstr(p, "Node:");
if (pnode == NULL) {
free(p);
continue;
}
pnode += 5;
while (isspace(*pnode)) pnode++;
// Give up if wrong name
if (strncmp(pnode, nodename, strlen(nodename))) {
free(p);
continue;
}
// Otherwise, read the page
*page = (char **) malloc(64 * sizeof(char *));
*pagelen = 1;
int page_alloc = 64;
(*page)[0] = p;
for(;;) {
p = fgetline(infofile);
if (p == NULL || *p == '\x1F') break;
if (*pagelen+1 >= page_alloc) {
page_alloc += 64;
*page = (char **) realloc(*page, page_alloc * sizeof(char *));
}
(*page)[(*pagelen)++] = p;
}
return;
}
return;
attempt_fail:
BUGME(fprintf(fnote, "attempt_fail\n");)
*page = NULL;
*pagelen = 0;
}
void InfoFile::get_last_node(char ***page, int *pagelen)
{
char *current, *previous;
*page = NULL;
*pagelen = 0;
current = history.pop();
if (current == NULL) return;
previous = history.pop();
if (previous == NULL) {
history.push(current);
free(current);
return;
}
getnode(previous, page, pagelen);
if (*page == NULL || *pagelen == 0) {
history.push(previous);
history.push(current);
}
free(previous);
free(current);
}
void InfoFile::getnode(const char *anodename, char ***page, int *pagelen)
{
char cpynodename[strlen(anodename)+1];
char *nodename = cpynodename;
while(isspace(*anodename)) anodename++;
char *cpy = nodename;
if (*anodename == '(') {
while (*anodename != '\0' && *anodename != ')') {
*cpy++ = *anodename++;
}
}
while (*anodename != '\0' && strchr("\t\n,.", *anodename) == NULL) {
*cpy++ = *anodename++;
}
*cpy = '\0';
if (cpynodename[0] == '(') {
history.push(cpynodename);
} else {
char tempbuf[strlen(cpynodename)+strlen(most_recent_filename)+3];
sprintf(tempbuf, "(%s)%s", most_recent_filename, cpynodename);
history.push(tempbuf);
}
BUGME(fprintf(fnote, "InfoFile::getnode(\"%s\",...)\n", nodename);)
if (*nodename == '(') {
// Uh-oh. New file
char *tail = strchr(nodename, ')');
if (tail != NULL && tail > nodename + 1) {
char newfilename[tail-nodename];
nodename++;
strncpy(newfilename, nodename, tail-nodename);
newfilename[tail-nodename] = '\0';
nodename = tail+1;
fclose(infofile);
BUGME(fprintf(fnote, "getnode: Opening ``%s''\n", newfilename);)
open(newfilename);
}
}
if (!ok()) {
fail:
BUGME(fprintf(fnote, "getnode: Failed\n");)
BUGME(fflush(fnote);)
*page = NULL;
*pagelen = 0;
return;
}
*page = NULL;
*pagelen = 0;
if (*nodename == '\0') nodename = "Top";
// Goto start of file
if (split_file) {
long min_pos, max_pos;
if (tags_table_availible) {
SplitList *tag;
for (tag = tags_table; tag != NULL; tag = tag->next) {
if (!strcmp(nodename, tag->split.filename)) break;
}
if (tag == NULL) goto fail;
min_pos = tag->split.position - 1024;
if (min_pos < 0) min_pos = 0;
max_pos = tag->split.position + 1024;
}
SplitList *sl;
SplitList *prev = NULL;
for (sl = splitlist; sl != NULL; sl = sl->next) {
BUGME(fprintf(fnote, "Trying %s\n", sl->split.filename);)
if (tags_table_availible) {
BUGME(fprintf(fnote, "Checking bounds: %ld in [%ld,%ld]\n",
sl->split.position, min_pos, max_pos);)
BUGME(fflush(fnote);)
if (prev == NULL) {
if (sl->split.position > max_pos) continue;
} else if (min_pos > prev->split.position) {
// No way - we're past the point of possibility
break;
} else if (sl->split.position > max_pos) {
// No way - we haven't gone far enough yet
prev = sl;
continue;
} // Otherwise, try this node
prev = sl;
}
if (infofile != NULL) fclose(infofile);
infofile = fopen(sl->split.filename, "rt");
if (infofile == NULL) continue;
fseek(infofile, 0, SEEK_SET);
getnode_attempt(nodename, page, pagelen);
if (*page != NULL && *pagelen != 0) break;
}
} else {
fseek(infofile, 0, SEEK_SET);
getnode_attempt(nodename, page, pagelen);
}
if (page == NULL) goto fail;
}
class MyWin: public StdWin
{
int char_width, char_height, char_descender;
int client_height;
int client_char_height;
int scroll_position;
int max_scroll_position;
HWND vscrollbar;
InfoFile info;
char **view;
int view_count;
int view_dynamic;
static char *error_view[];
void recalc_max_scroll_position(void)
{
max_scroll_position = view_count - client_char_height;
if (max_scroll_position < 0) max_scroll_position = 0;
if (scroll_position > max_scroll_position) {
scroll_position = max_scroll_position;
}
NOTE(client_char_height);
NOTE(view_count);
NOTE(max_scroll_position);
NOTE(scroll_position);
}
void recalc_scrollbar(void);
void RuntimeNodeSelect(const char *nodename);
void HeaderNodeSelect(const char *field);
void FreeView(void);
void SelectStaticView(char **static_view, int static_view_count);
void LastNodeSelect();
public:
virtual MRESULT MsgPaint(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgSize(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgCreate(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgVscroll(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgButton1Down(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgChar(HWND, USHORT, MPARAM, MPARAM, int *);
virtual MRESULT MsgCommand(HWND, USHORT, MPARAM, MPARAM, int *);
void SelectLine(int line, int xpos);
void RefreshLine(int line);
void Init(HAB);
void NodeSelect(const char *nodename);
MyWin();
};
char *MyWin::error_view[] = { "Error" };
MyWin::MyWin()
: StdWin(),
info("dir"),
view(NULL)
{
NodeSelect("Top");
}
void MyWin::SelectStaticView(char **static_view, int static_view_count)
{
FreeView();
view = static_view;
view_count = static_view_count;
view_dynamic = 0;
scroll_position = 0;
recalc_max_scroll_position();
recalc_scrollbar();
WinInvalidateRect(window, NULL, FALSE);
}
void MyWin::FreeView(void)
{
if (!view_dynamic) {
view = NULL;
view_count = 0;
view_dynamic = 0;
return;
}
if (view != NULL && view != error_view && view_count > 0) {
for (int i = 0; i < view_count; i++) {
free(view[i]);
}
free(view);
view = NULL;
view_count = 0;
}
}
void MyWin::LastNodeSelect()
{
char **new_view;
int new_count;
info.get_last_node(&new_view, &new_count);
if (new_view == NULL || new_count == 0) return;
FreeView();
view_dynamic = 1;
view = new_view;
view_count = new_count;
scroll_position = 0;
recalc_max_scroll_position();
recalc_scrollbar();
WinInvalidateRect(window, NULL, FALSE);
}
void MyWin::NodeSelect(const char *name)
{
BUGME(fprintf(fnote, "MyWin::NodeSelect(\"%s\")\n", name);)
FreeView();
info.getnode(name, &view, &view_count);
if (view == NULL || view_count == 0) {
view = error_view;
view_count = 1;
view_dynamic = 0;
} else {
view_dynamic = 1;
}
scroll_position = 0;
recalc_max_scroll_position();
}
void MyWin::Init(HAB hab)
{
StdWin::Init(hab, "StdWin", CS_SIZEREDRAW,
FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER | FCF_MINMAX
| FCF_SHELLPOSITION | FCF_TASKLIST | FCF_VERTSCROLL | FCF_MENU
| FCF_ICON);
scroll_position = 0;
}
MRESULT MyWin::MsgChar(HWND, USHORT, MPARAM mp1, MPARAM mp2, int *)
{
if (SHORT1FROMMP(mp1) & KC_CHAR) {
switch(SHORT1FROMMP(mp2)) {
case 't':
case 'T':
RuntimeNodeSelect("Top");
break;
case 'd':
case 'D':
RuntimeNodeSelect("(dir)");
break;
case 'u':
case 'U':
HeaderNodeSelect("Up");
break;
case 'n':
case 'N':
HeaderNodeSelect("Next");
break;
case 'p':
case 'P':
HeaderNodeSelect("Prev");
break;
case 'l':
case 'L':
LastNodeSelect();
break;
}
}
return 0;
}
MRESULT MyWin::MsgCommand(HWND, USHORT, MPARAM mp1, MPARAM, int *dodefault)
{
switch(SHORT1FROMMP(mp1)) {
case IDM_NODE_DIR:
RuntimeNodeSelect("(dir)");
break;
case IDM_NODE_NEXT:
HeaderNodeSelect("Next");
break;
case IDM_NODE_PREVIOUS:
HeaderNodeSelect("Prev");
break;
case IDM_NODE_UP:
HeaderNodeSelect("Up");
break;
case IDM_NODE_LAST:
LastNodeSelect();
break;
case IDM_ABOUT_ABOUT:
SelectStaticView(embedded_text_Copyrght, embedded_text_Copyrght_count);
break;
case IDM_ABOUT_COPYING:
SelectStaticView(embedded_text_COPYING, embedded_text_COPYING_count);
break;
case IDM_ABOUT_WARRANTY:
SelectStaticView(embedded_text_COPYING, embedded_text_COPYING_count);
scroll_position = 277; /* Start of Warantee section */
recalc_max_scroll_position();
recalc_scrollbar();
WinInvalidateRect(window, NULL, FALSE);
break;
default:
*dodefault = 1; /* Just in case */
}
return 0;
}
void MyWin::HeaderNodeSelect(const char *field)
{
if (view == NULL || view_count == 0) return;
char search[strlen(field)+2];
sprintf(search, "%s:", field);
char *nodename = strstr(view[0], search);
if (nodename == NULL) {
// We don't have that particular header in the current node
return;
}
nodename += strlen(search);
while (isspace(*nodename)) nodename++;
RuntimeNodeSelect(nodename);
}
MRESULT MyWin::MsgButton1Down(HWND, USHORT, MPARAM mp1, MPARAM, int *)
{
int x,y;
x = SHORT1FROMMP(mp1);
y = SHORT2FROMMP(mp1);
y = (client_height - y) / char_height;
SelectLine(y + scroll_position, x);
return 0;
}
void MyWin::RefreshLine(int line)
{
WinInvalidateRect(window, NULL, FALSE);
}
void MyWin::SelectLine(int line, int)
{
if (line < 0 || view_count <= line) return;
char *p = view[line];
while (isspace(*p)) p++;
if (*p != '*') return;
p++;
while (isspace(*p)) p++;
if (*p == ':') return;
char nodename[strlen(p)+1+3];
char *semicolon = strchr(p, ':');
if (semicolon == NULL) return;
if (semicolon[1] == ':') {
// menu entry *is* nodename
semicolon--;
while (isspace(*semicolon)) semicolon--;
strncpy(nodename, p, semicolon - p + 1);
nodename[semicolon - p + 1] = '\0';
} else {
p = semicolon+1;
while (isspace(*p)) p++;
char *target = nodename;
// Accept any letters in a filename
if (*p == '(') while (*p != ')' && *p != '\0') {
*target++ = *p++;
}
// Then process the nodename
while (*p != '\0' && strchr("\t\n,.", *p) == NULL) {
*target++ = *p++;
}
*target = '\0';
if (*nodename == '\0') return;
}
BUGME(fprintf(fnote, "Select: Nodename is ``%s''\n", nodename);)
RuntimeNodeSelect(nodename);
}
void MyWin::RuntimeNodeSelect(const char *nodename)
{
NodeSelect(nodename);
recalc_scrollbar();
WinInvalidateRect(window, NULL, FALSE);
}
MRESULT MyWin::MsgVscroll(HWND window, USHORT, MPARAM, MPARAM mp2, int *)
{
SHORT new_scroll_position = scroll_position;
MsgCreate(window, 0, 0, 0, NULL);
switch(SHORT2FROMMP(mp2)) {
case SB_LINEUP:
new_scroll_position--;
break;
case SB_LINEDOWN:
new_scroll_position++;
break;
case SB_PAGEUP:
new_scroll_position -= max(1,client_char_height);
break;
case SB_PAGEDOWN:
new_scroll_position += max(1,client_char_height);
break;
case SB_SLIDERTRACK:
new_scroll_position = SHORT1FROMMP(mp2);
break;
}
LIMIT(new_scroll_position, 0, max_scroll_position);
if (new_scroll_position != scroll_position) {
WinScrollWindow(window, 0,
(new_scroll_position - scroll_position) * char_height,
NULL,NULL,NULL,NULL, SW_INVALIDATERGN);
scroll_position = new_scroll_position;
WinSendMsg(vscrollbar, SBM_SETPOS,
MPFROMSHORT(scroll_position), NULL);
WinUpdateWindow(window);
}
return 0;
}
MRESULT MyWin::MsgPaint(HWND window, USHORT msg, MPARAM mp1, MPARAM mp2, int *ip)
{
MsgCreate(window, msg, mp1, mp2, ip);
RECTL rect;
HPS hps = WinBeginPaint(window, NULL, &rect);
POINTL pt;
int top,bottom;
int i;
GpiErase(hps);
top = (client_height - rect.yTop) / char_height;
bottom = (client_height - rect.yBottom) / char_height + 1;
pt.x = 0;
pt.y = client_height - char_height * (1+top)+ char_descender;
//fprintf(fnote, "Repaint: vpix %d thru %d\n", rect.yTop, rect.yBottom);
BUGME(fprintf(fnote, "Repainting lines %d thru %d\n", top, bottom);)
NOTE(scroll_position);
top += scroll_position;
bottom += scroll_position;
NOTE(top);
NOTE(bottom);
LIMIT(top,scroll_position,view_count);
LIMIT(bottom,scroll_position,view_count);
for (i = top; i < bottom; i++) {
GpiCharStringAt(hps, &pt, strlen(view[i]), (PSZ)view[i]);
pt.y -= char_height;
}
WinEndPaint(hps);
return 0;
}
void MyWin::recalc_scrollbar(void)
{
WinSendMsg(vscrollbar, SBM_SETSCROLLBAR, MPFROM2SHORT(scroll_position, 0),
MPFROM2SHORT(0, max_scroll_position));
WinEnableWindow(vscrollbar, (max_scroll_position == 0) ? FALSE : TRUE);
}
MRESULT MyWin::MsgSize(HWND, USHORT, MPARAM, MPARAM mp2, int *)
{
MsgCreate(window, 0, 0, 0, NULL);
client_height = SHORT2FROMMP(mp2);
client_char_height = client_height / char_height;
recalc_max_scroll_position();
BUGME(fprintf(fnote, "Size: Scrollbar set to %d of %d\n", scroll_position,
max_scroll_position);)
recalc_scrollbar();
NOTE(client_height);
NOTE(client_char_height);
NOTE(max_scroll_position);
return 0;
}
MRESULT MyWin::MsgCreate(HWND window, USHORT, MPARAM, MPARAM, int *)
{
static init = 0;
if (init) return 0;
init = 1;
HPS hps;
FONTMETRICS fm;
BUGME(fprintf(fnote, "MsgCreate:\n");)
hps = WinGetPS(window);
GpiQueryFontMetrics(hps, sizeof(fm), &fm);
char_width = fm.lEmInc;
char_height = fm.lMaxBaselineExt;
char_descender = fm.lMaxDescender;
vscrollbar = WinWindowFromID(WinQueryWindow(window, QW_PARENT),
FID_VERTSCROLL);
NOTE(char_width);
NOTE(char_height);
NOTE(char_descender);
return 0;
}
int main(void)
{
HAB hab;
HMQ hmq;
BUGME(fnote = fopen("note", "wt");)
StdWin::StdStartup(&hab, &hmq);
MyWin win;
win.Init(hab);
QMSG qmsg;
while (WinGetMsg(hab, &qmsg, NULL, 0, 0)) WinDispatchMsg(hab, &qmsg);
win.Destroy();
StdWin::StdExit(hab, hmq);
BUGME(fclose(fnote);)
return 0;
}