diff --git a/books/bookvol7.pamphlet b/books/bookvol7.pamphlet index 9dcb878..7d7cb57 100644 --- a/books/bookvol7.pamphlet +++ b/books/bookvol7.pamphlet @@ -194,9 +194,7871 @@ November 10, 2003 ((iHy)) \pagenumbering{arabic} \setcounter{chapter}{0} % Chapter 1 \chapter{Overview} -This book contains the hyperdoc routines for Axiom. -\chapter{Support Routines} -\chapter{Hyperdoc} + +This book covers 5 top level commands that make up the Axiom Hyperdoc +browser. The primary command is the hypertex command which can be run +as a standalone program to browse the Axiom documentation. It can also +be run by Axiom to enable lookup of information in the Axiom runtime. + +\section{hypertex} +\begin{verbatim} +Usage: hypertex [-s] +\end{verbatim} + +\section{htsearch} +Construct a page with a menu of references to the word. +The syntax of the command is: +\begin{verbatim} +Usage: htsearch word +\end{verbatim} + +\section{spadbuf} +\begin{verbatim} +Usage: spadbuf page_name [completion_files] +\end{verbatim} + +\section{hthits} +\begin{verbatim} +Usage: hthits pattern htdb-file +\end{verbatim} + +\section{ex2ht} +\begin{verbatim} +Usage: ex2ht exfile.ht ... +\end{verbatim} + +\section{htadd} +HyperDoc database file manager +\begin{verbatim} +Usage: htadd [-s|-l|-f db-directory] [-d|-n] filenames +\end{verbatim} + +\chapter{The Hyperdoc Browser} +\section{addfile.h} +<>= +#ifndef _ADDFILE_H_ +#define _ADDFILE_H_ 1 + +extern char *gDatabasePath; + +#endif +@ +\section{addfile.c} +<>= +#define _ADDFILE_C +#include "debug.h" + +<> +<> + +#include +#include + +#include "all-hyper-proto.h1" + + +char *gDatabasePath = NULL; + +static int +strpostfix(char *s, char *t) +{ + int slen = strlen(s), tlen = strlen(t); + + if (tlen > slen) + return 0; + while (tlen > 0) + if (s[--slen] != t[--tlen]) + return 0; + return 1; +} + +/* extend_ht : just checks the name and adds a .ht if needed */ + +void +extend_ht(char *name) +{ + + if (!strpostfix(name, ".ht") && !strpostfix(name, ".pht")) + strcat(name, ".ht"); + return; +} + +#define cwd(n) ((n[0] == '.' && n[1] == '/')?(1):(0)) + +/* + * This procedure is sent a filename, and from it tries to build the full + * filename, this it returns in the fullname variable. If the file is not + * found, then it returns a -1. The fname is the fullpath name for the file, + * including the .ht extension. The aname is the filename minus the added .ht + * extension, and the pathname. + */ + +static int +build_ht_filename(char *fname, char *aname, char *name) +{ + char cdir[256]; + char *c_dir; + char *HTPATH; + char *trace; + char *trace2; + int ht_file; + + if (cwd(name)) { + /* user wants to use the current working directory */ + c_dir = (char *) getcwd(cdir, 254); + strcpy(fname, c_dir); + + /* Now add the rest of the filename */ + strcat(fname, "/"); + strcat(fname, &name[2]); + + /** now copy the actual file name to addname **/ + for (trace = &name[strlen(name)]; trace != name && + (*trace != '/'); trace--); + if (trace == name) { + fprintf(stderr, "ht_open_file: Didn't expect a filename like %s\n", + name); + exit(-1); + } + trace++; + strcpy(aname, trace); + + /** add the .ht extension if needed **/ + extend_ht(aname); + extend_ht(fname); + + /* Now just try to access the file */ + return (access(fname, R_OK)); + } + else if (pathname(name)) { + /* filename already has the path specified */ + strcpy(fname, name); + + /** now copy the actual file name to addname **/ + for (trace = &name[strlen(name)]; trace != name && + (*trace != '/'); trace--); + if (trace == name) { + fprintf(stderr, "ht_open_file: Didn't expect a filename like %s\n", + name); + exit(-1); + } + trace++; + strcpy(aname, trace); + + /** add the .ht extension if needed **/ + extend_ht(aname); + extend_ht(fname); + + /* Now just try to access the file */ + return (access(fname, R_OK)); + } + else {/** If not I am going to have to append path names to it **/ + HTPATH = (char *) getenv("HTPATH"); + if (HTPATH == NULL) { + /** The user does not have a HTPATH, so I will use the the directory + $AXIOM/doc/hypertex/pages/ as the default path ***/ + char *spad = (char *) getenv("AXIOM"); + if (spad == NULL) { + fprintf(stderr, + "ht_file_open:Cannot find ht data base: setenv HTPATH or AXIOM\n"); + exit(-1); + } + HTPATH = (char *) halloc(1024 * sizeof(char), "HTPATH"); + strcpy(HTPATH, spad); + strcat(HTPATH, "/doc/hypertex/pages"); + } + + /** Now that I have filled HTPATH, I should try to open a file by the + given name **/ + strcpy(aname, name); + extend_ht(aname); + for (ht_file = -1, trace2 = HTPATH; + ht_file == -1 && *trace2 != '\0';) { + for (trace = fname; *trace2 != '\0' && (*trace2 != ':');) + *trace++ = *trace2++; + *trace++ = '/'; + *trace = 0; + if (!strcmp(fname, "./")) { + /** The person wishes me to check the current directory too **/ + getcwd(fname, 256); + strcat(fname, "/"); + } + if (*trace2) + trace2++; + strcat(fname, aname); + ht_file = access(fname, R_OK); + } + return (ht_file); + } +} + +static int +pathname(char *name) +{ + while (*name) + if (*name++ == '/') + return 1; + + return 0; +} + +/** This procedure opens the proper HT file **/ + +FILE * +ht_file_open(char *fname, char *aname, char *name) +{ + FILE *ht_fp; + int ret_value; + + ret_value = build_ht_filename(fname, aname, name); + if (ret_value == -1) { + fprintf(stderr, "ht_file_open: Unknown file %s\n", fname); + exit(-1); + } + + ht_fp = fopen(fname, "r"); + if (ht_fp == NULL) { + perror("ht_file_open"); + exit(-1); + } + return (ht_fp); +} + +/* + * This function is responsible for actually opening the database file. For the + * moment it gets the $AXIOM environment variable, and appends to it + * "doc/hypertex/ht.db", and then opens it + */ + +/* + * Modified on 12/3/89 to take a second argument. This argument tells the + * open routine whether it is reading the db file, or writing it. If writing + * is true, then I should check to insure I have proper write access. + * -JMW + */ + +/* + * Modified again on 12/9/89 so that it now uses HTPATH as the path name. Now + * it initially loads up the path name into a static variable. Then upon + * every trip, it gets the next ht.db found. It returns NULL when no ht.db is + * found. -JMW + */ + + +FILE * +db_file_open(char *db_file) +{ + static char *db_path_trace = NULL; + char *db_file_trace; + FILE *db_fp; + char *spad; + + /* + * The first time through is the only time this could be true. If so, then + * create the default HTPATH for gDatabasePath. + */ +/* fprintf(stderr,"addfile:db_file_open: entered db_file=%s\n",db_file);*/ + if (gDatabasePath == NULL) { + gDatabasePath = (char *) getenv("HTPATH"); + if (gDatabasePath == NULL) { + spad = (char *) getenv("AXIOM"); + if (spad == NULL) { +/* fprintf(stderr, + "addfile:db_file_open: Cannot find ht data base path:\n");*/ + exit(-1); + } + gDatabasePath = (char *) halloc(sizeof(char) * 1024, "db_file_open"); + strcpy(gDatabasePath, spad); + strcat(gDatabasePath, "/doc/hypertex/pages"); + } + db_path_trace = gDatabasePath; + } +/*fprintf(stderr,"addfile:db_file_open: db_path_trace=%s\n",db_path_trace);*/ + /* + * Now Loop until I find one with okay filename + */ + + for (db_fp = NULL; db_fp == NULL && *db_path_trace != '\0';) { + for (db_file_trace = db_file; *db_path_trace != ':' && + *db_path_trace != '\0'; db_path_trace++) + *db_file_trace++ = *db_path_trace; + *db_file_trace = '\0'; + strcat(db_file_trace, "/ht.db"); +/*fprintf(stderr,"addfile:db_file_open: db_file_trace=%s\n",db_file_trace);*/ +/*fprintf(stderr,"addfile:db_file_open: db_file=%s\n",db_file);*/ + + db_fp = fopen(db_file, "r"); + + if (*db_path_trace != '\0') + db_path_trace++; + } +/* if (db_fp == NULL) + fprintf(stderr,"addfile:db_file_open: exit (null)\n"); + else + fprintf(stderr,"addfile:db_file_open: exit opened\n"); +*/ + return (db_fp); +} + + +FILE * +temp_file_open(char *temp_db_file) +{ + FILE *temp_db_fp; + + /** Just make the name and open it **/ + + strcpy(temp_db_file, temp_dir); + strcat(temp_db_file, "ht2.db" /* db_file_name */ ); + temp_db_fp = fopen(temp_db_file, "w"); + + if (temp_db_fp == NULL) { + perror("temp_file_open"); + exit(-1); + } + return temp_db_fp; +} +@ +\section{cond.c} +<>= +/****************************************************************************** + * + * cond.c: Routines for handling "cond" nodes. + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _COND_C +#include "debug.h" + +<> + +#include "all-hyper-proto.h1" +#include "sockio-c.h1" + + +void +insert_cond(char *label, char *cond) +{ + CondNode *condnode = (CondNode *) hash_find(gWindow->fCondHashTable, label); + + /* + * This routine creates a new cond node and inserts it into the + * current cond table + */ + if (condnode) { + fprintf(stderr, "Error: \\%s is declared twice \n", label); + print_page_and_filename(); + jump(); + } + condnode = alloc_condnode(); + condnode->label = halloc(strlen(label) + 1, "Condnode->label"); + condnode->cond = halloc(strlen(cond) + 1, "Condnode->cond"); + strcpy(condnode->label, label); + strcpy(condnode->cond, cond); + hash_insert(gWindow->fCondHashTable, (char *) condnode, condnode->label); +} + +void +change_cond(char *label, char *newcond) +{ + CondNode *condnode = (CondNode *) hash_find(gWindow->fCondHashTable, label); + + if (condnode == NULL) { + fprintf(stderr, "Error: Tried to set an uncreated cond %s\n", label); + } + else { + free(condnode->cond); + condnode->cond = halloc(strlen(newcond) + 1, "Condnode->cond"); + strcpy(condnode->cond, newcond); + } +} + +static int +check_memostack(TextNode *node) +{ + char *buffer; + int stackp = gWindow->fMemoStackIndex; + int found = 0; + HyperDocPage *page; + + buffer = print_to_string(node->data.node); + + /* + * Once we have done that much, search down the stack for the + * proper page + */ + + while (!found && stackp > 0) { + page = gWindow->fMemoStack[--stackp]; + if (!strcmp(page->name, buffer)) + found = 1; + } + return found; +} + +int +check_condition(TextNode *node) +{ + CondNode *cond; + InputBox *box; + int ret_val; + + /* checks the condition presented and returns a 1 or a 0 */ + switch (node->type) { + case Cond: + cond = (CondNode *) hash_find(gWindow->fCondHashTable, node->data.text); + if (!strcmp("0", cond->cond)) + return 0; + else + return 1; + case Boxcond: + box = (InputBox *) hash_find(gWindow->page->box_hash, node->data.text); + return (box->picked); + case Haslisp: + if (spad_socket != NULL) { + ret_val = send_int(spad_socket, TestLine); + return (ret_val + 1); + } + else + return 0; + case Hasup: + return need_up_button; + case Hasreturn: + return gWindow->fMemoStackIndex; + case Hasreturnto: + return (check_memostack(node)); + case Lastwindow: + return (gSessionHashTable.num_entries == 1 || gParentWindow == gWindow); + default: + return 0; + } +} +@ +\section{debug.c} +<>= +#define _DEBUG_C +#include "debug.h" + +#ifdef free +#undef free +hfree(char *p) { + free(p); +} +#endif + +@ +\section{dialog.h} +<>= +#ifndef _DIALOG_H_ +#define _DIALOG_H_ 1 + +<> + +#endif +@ +\section{dialog.c} +<>= +/****************************************************************************** + * + * dialog.c: + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _DIALOG_C +#include "debug.h" + +<> +<> +<> +<> +<> + +#include + +#define min(x,y) ( (xfMainWindow); + XUnmapSubwindows(gXDisplay, gWindow->fScrollWindow); + XFlush(gXDisplay); + show_page(gWindow->page); +} + +static char * +mystrncpy(char *buff1, char *buff2, int n) +{ + /* + * copies the characters from buff1 to buff2 starting at position buff2 + + * n and buff1 + n + */ + + int i; + + for (i = n - 1; i >= 0; i--) + *(buff1 + i) = *(buff2 + i); + return buff2; +} + +static void +inc_line_numbers(LineStruct *line) +{ + for (; line != NULL; line = line->next) + line->line_number++; +} + +static void +dec_line_numbers(LineStruct *line) +{ + for (; line != NULL; line = line->next) + line->line_number--; + return; +} + +static void +decrease_line_numbers(LineStruct *line, int am) +{ + for (; line != NULL; line = line->next) + line->line_number -= am; +} + +static void +overwrite_buffer(char *buffer, InputItem *item) +{ + LineStruct *newline; + LineStruct *addline = item->curr_line; + /*int bufflen = strlen(buffer);*/ + int nl = 0; + int cursor_y; + int size = item->size; + + /* add a single character */ + + cursor_y = (addline->line_number - 1) * line_height; + if (addline->buff_pntr == size) { + clear_cursor(item); + if (addline->len <= size) { + nl = 1; + addline->buffer[size] = '_'; + addline->buffer[size + 1] = 0; + addline->len = size + 1; + newline = (LineStruct *) alloc_inputline(size + 2); + newline->line_number = addline->line_number + 1; + inc_line_numbers(addline->next); + newline->next = addline->next; + newline->prev = addline; + if (addline->next) + addline->next->prev = newline; + addline->next = newline; + item->num_lines++; + cursor_y += line_height; + item->curr_line = addline = newline; + } + else { + item->curr_line = addline = addline->next; + } + addline->len = 1; + addline->buff_pntr = 1; + addline->buffer[0] = buffer[0]; + } + else { + addline->buffer[addline->buff_pntr] = buffer[0]; + clear_cursor(item); + if (++addline->buff_pntr > addline->len) + addline->len++; + } + + /* now set up the current line */ + if (item->curr_line->buff_pntr >= item->size && + item->curr_line->next != NULL && !item->curr_line->next->len) { + /* I should actually be on the next line */ + item->curr_line->buffer[item->size] = '_'; + item->curr_line->len = item->size + 1; + XDrawString(gXDisplay, item->win, gWindow->fInputGC, start_x, + cursor_y + start_y, + addline->buffer, + addline->len); + item->curr_line = item->curr_line->next; + item->curr_line->buff_pntr = 0; + item->curr_line->changed = 1; + } + + if (!nl) { + XDrawString(gXDisplay, item->win, gWindow->fInputGC, start_x, + cursor_y + start_y, + addline->buffer, + addline->len); + draw_cursor(item); + } + else + redraw_win(); +} + +/* + * This routine takes the current line and moves it num forward. The + * only way I have to move any other lines forward is if this line has length + * > size + */ + +static int +move_sym_forward(LineStruct *line, int num, int size, InputItem *sym) +{ + LineStruct *newline; + int diff; + int nl = 0; + + if (line->len > size) { + nl = move_sym_forward(line->next, num, size, sym); + strncpy(line->next->buffer, + &line->buffer[sym->size - num], line->len); + strncpy(&line->buffer[num], + line->buffer, num); + line->changed = 1; + return nl; + } + else { + if (line->len + num > size) { + diff = line->len + num - size; + newline = alloc_inputline(size); + newline->len = diff; + newline->line_number = line->line_number++; + inc_line_numbers(line->next); + sym->num_lines++; + newline->next = line->next; + newline->prev = line; + if (line->next) + line->next->prev = newline; + line->next = newline; + strncpy(newline->buffer, &line->buffer[size - diff], diff); + strncpy(&line->buffer[num], line->buffer, num); + line->buffer[size] = '_'; + line->buffer[size + 1] = 0; + line->len = size + 1; + return 1; + } + else { + strncpy(&line->buffer[num], line->buffer, line->len); + line->len += num; + line->changed = 1; + return 0; + } + } +} + +static void +clear_cursorline(InputItem *sym) +{ + XCharStruct extents; + int dir, asc, des; + int cursor_y; + + XTextExtents(gInputFont, sym->curr_line->buffer, + sym->curr_line->buff_pntr, + &dir, &asc, &des, &extents); + cursor_y = (sym->curr_line->line_number - 1) * line_height; + sym->cursor_x = start_x + extents.width; + XClearArea(gXDisplay, sym->win, sym->cursor_x, cursor_y, + gWindow->width, line_height, False); + XDrawString(gXDisplay, sym->win, gWindow->fInputGC, start_x, cursor_y + start_y, + sym->curr_line->buffer, + sym->curr_line->len); +} + +static void +insert_buffer(char *buffer, InputItem *sym) +{ + /*int num = strlen(buffer);*/ + LineStruct *line = sym->curr_line; + LineStruct *newline; + int nl = 0; + int size = sym->size; + + if (line->len < size) { + /* they will all fit where I am so just copy them forward */ + line->len++; + mystrncpy(&(line->buffer[line->buff_pntr + 1]), + &(line->buffer[line->buff_pntr]), + line->len - line->buff_pntr + 1); + line->buffer[line->buff_pntr] = buffer[0]; + clear_cursorline(sym); + line->buff_pntr++; + draw_cursor(sym); + return; + } + + if (line->len > sym->size) { + nl = move_sym_forward(line->next, 1, size, sym); + if (line->buff_pntr > size) { + line->changed = 1; + line = line->next; + line->buffer[0] = buffer[0]; + line->len++; + line->buff_pntr = 1; + line->changed = 1; + } + else { + line->next->buffer[0] = line->buffer[size - 1]; + line->changed = 1; + strncpy(&line->buffer[line->buff_pntr + 1], + &line->buffer[line->buff_pntr], size - line->buff_pntr - 1); + line->buffer[line->buff_pntr++] = buffer[0]; + line->changed = 1; + if (line->buff_pntr >= size) { + sym->curr_line = line->next; + sym->curr_line->buff_pntr = 0; + } + } + } + else { + nl = 1; + newline = alloc_inputline(size); + newline->line_number = line->line_number + 1; + inc_line_numbers(line->next); + sym->num_lines++; + newline->next = line->next; + newline->prev = line; + if (line->next) + line->next->prev = newline; + line->next = newline; + + /* + * was line->buff_pntr++; + */ + if (line->buff_pntr >= size) { + /* we are the leaders of the line */ + newline->buff_pntr = 1; + newline->buffer[0] = buffer[0]; + newline->len = 1; + sym->curr_line = newline; + } + else { + /* we are not the leaders */ + newline->buffer[0] = line->buffer[size - 1]; + newline->len = 1; + strncpy(&line->buffer[line->buff_pntr + 1], + &line->buffer[line->buff_pntr], size - line->buff_pntr); + if (line->buff_pntr < size - 1) { + line->buffer[line->buff_pntr++] = buffer[0]; + } + else { + line->buffer[line->buff_pntr] = buffer[0]; + newline->buff_pntr = 0; + sym->curr_line = newline; + } + + } + line->buffer[size] = '_'; + line->buffer[size + 1] = 0; + line->len = size + 1; + } + if (nl) + redraw_win(); + else + update_inputsymbol(sym); + +} + +void +add_buffer_to_sym(char *buffer,InputItem *sym) +{ + if (gInInsertMode) + insert_buffer(buffer, sym); + else + overwrite_buffer(buffer, sym); +} + +void +draw_inputsymbol(InputItem *sym) +{ + int y_spot = start_y; + LineStruct *cline; + XCharStruct extents; + int dir, asc, des; + + +#if 0 + int cursor_y; + cursor_y = (sym->curr_line->line_number - 1) * line_height; +#endif + + XClearWindow(gXDisplay, sym->win); + + XTextExtents(gInputFont, sym->curr_line->buffer, + sym->curr_line->buff_pntr, + &dir, &asc, &des, &extents); + sym->cursor_x = start_x + extents.width; + + /* + * While the list of input strings is not NULL, I should just keep + * drawing them + */ + for (cline = sym->lines; cline != NULL; + cline = cline->next, y_spot += line_height) { + /* Now I should draw the initial string ** */ + cline->changed = 0; + XDrawString(gXDisplay, sym->win, gWindow->fInputGC, start_x, y_spot, + cline->buffer, + cline->len); + + } + if (gWindow->page->current_item == sym) + draw_cursor(sym); +} + +void +update_inputsymbol(InputItem *sym) +{ + int y_spot = start_y; + LineStruct *cline; + XCharStruct extents; + int dir, asc, des; + /*int cleared = 0;*/ + int clear_y; + int clear_width; + int clear_height; + +#if 0 + int cursor_y; + cursor_y = (sym->curr_line->line_number - 1) * line_height; +#endif + + clear_width = (sym->size + 1) * gInputFont->max_bounds.width + 10; + clear_height = line_height; + clear_y = 0; + + + XTextExtents(gInputFont, sym->curr_line->buffer, + sym->curr_line->buff_pntr, + &dir, &asc, &des, &extents); + sym->cursor_x = start_x + extents.width; + + /* + * While the list of input strings is not NULL, I should just keep + * drawing them + */ + for (cline = sym->lines; cline != NULL; + cline = cline->next, y_spot += line_height, clear_y += line_height) + /* Now I should draw the initial string ** */ + if (cline->changed) { + cline->changed = 0; + XClearArea(gXDisplay, sym->win, 0, clear_y, + clear_width, clear_height, False); + XDrawString(gXDisplay, sym->win, gWindow->fInputGC, start_x, y_spot, + cline->buffer, + cline->len); + } + draw_cursor(sym); +} + + +static void +draw_cursor(InputItem *sym) +{ + int cursor_y; + XCharStruct extents; + int dir, asc, des; + + + cursor_y = (sym->curr_line->line_number - 1) * line_height; + XTextExtents(gInputFont, sym->curr_line->buffer, + sym->curr_line->buff_pntr, + &dir, &asc, &des, &extents); + sym->cursor_x = start_x + extents.width; + /* now draw the cursor */ + if (gInInsertMode) { + XFillRectangle(gXDisplay, sym->win, gWindow->fInputGC, + sym->cursor_x, + out_cursor_y + cursor_y, + out_cursor_width, + out_cursor_height); + + /* Now draw the character currently under the cursor */ + + XDrawString(gXDisplay, sym->win, gWindow->fCursorGC, + sym->cursor_x, cursor_y + start_y, + &sym->curr_line->buffer[sym->curr_line->buff_pntr], + 1); + } + else + XFillRectangle(gXDisplay, sym->win, gWindow->fInputGC, + sym->cursor_x, + in_cursor_y + cursor_y, + in_cursor_width, + in_cursor_height); +} + +static void +move_cursor_home(InputItem *sym) +{ + LineStruct *trace = sym->curr_line; + + /* now move the cursor to the beginning of the current line */ + clear_cursor(sym); + for (; trace && trace->prev && trace->prev->len > sym->size;) + trace = trace->prev; + sym->curr_line = trace; + trace->buff_pntr = 0; + draw_cursor(sym); +} + +static void +move_cursor_end(InputItem *sym) +{ + LineStruct *trace = sym->curr_line; + + /* now move the cursor to the beginning of the current line */ + clear_cursor(sym); + for (; trace && trace->next && trace->len > sym->size;) + trace = trace->next; + sym->curr_line = trace; + trace->buff_pntr = trace->len; + draw_cursor(sym); +} + +static void +move_cursor_forward(InputItem *sym) +{ + if (sym->curr_line->buff_pntr == sym->curr_line->len && + !sym->curr_line->next) { + BeepAtTheUser(); + return; + } + + + if (sym->curr_line->buff_pntr == sym->curr_line->len || + sym->curr_line->buff_pntr == sym->size - 1) + { + + /* I have to move down to a new line */ + + if (sym->curr_line->next == NULL) { + /* now where to move */ + BeepAtTheUser(); + return; + } + + /* move down line */ + + clear_cursor(sym); + sym->curr_line = sym->curr_line->next; + sym->curr_line->buff_pntr = 0; + } + else { + clear_cursor(sym); + sym->curr_line->buff_pntr++; + } + + draw_cursor(sym); +} + +static void +move_cursor_down(InputItem *sym) +{ + int bp = sym->curr_line->buff_pntr; + /*int size = sym->size;*/ + LineStruct *trace; + + /* get to the end of the current line */ + + for (trace = sym->curr_line; trace->len > sym->size; trace = trace->next) + ; + + if (!trace->next) + BeepAtTheUser(); + else { + clear_cursor(sym); + sym->curr_line = trace->next; + if (bp > sym->curr_line->len) + sym->curr_line->buff_pntr = sym->curr_line->len; + else + sym->curr_line->buff_pntr = bp; + draw_cursor(sym); + } +} + +static void +move_cursor_up(InputItem *sym) +{ + int bp = sym->curr_line->buff_pntr; + /*int size = sym->size;*/ + LineStruct *trace; + + /* get to the end of the current line */ + for (trace = sym->curr_line; + trace->prev && trace->prev->len > sym->size; + trace = trace->prev) + ; + + if (!trace->prev) + BeepAtTheUser(); + else { + clear_cursor(sym); + sym->curr_line = trace->prev; + if (bp > sym->curr_line->len) + sym->curr_line->buff_pntr = sym->curr_line->len; + else + sym->curr_line->buff_pntr = bp; + draw_cursor(sym); + } +} + +static void +clear_cursor(InputItem *sym) +{ + XCharStruct extents; + int dir, asc, des; + int cursor_y; + + XTextExtents(gInputFont, sym->curr_line->buffer, + sym->curr_line->buff_pntr, + &dir, &asc, &des, &extents); + cursor_y = (sym->curr_line->line_number - 1) * line_height; + sym->cursor_x = start_x + extents.width; + XClearArea(gXDisplay, sym->win, sym->cursor_x, cursor_y, + in_cursor_width, line_height, False); + + XDrawString(gXDisplay, sym->win, gWindow->fInputGC, + start_x, cursor_y + start_y, + sym->curr_line->buffer, + sym->curr_line->len); +} + +static void +move_cursor_backward(InputItem *sym) +{ + if (sym->curr_line->buff_pntr == 0) { + if (sym->curr_line->prev == NULL) { + /* now where to move */ + BeepAtTheUser(); + return; + } + else { + clear_cursor(sym); + /* move up to the previous line */ + sym->curr_line = sym->curr_line->prev; + if (sym->curr_line->len > sym->size) + sym->curr_line->buff_pntr = sym->size - 1; + else + sym->curr_line->buff_pntr = sym->curr_line->len; + } + } + else { /* just slide back a char. on the current + * line */ + clear_cursor(sym); + sym->curr_line->buff_pntr--; + } + draw_cursor(sym); +} + +static char +move_rest_back(LineStruct *line, int size) +{ + char c = '\000'; + + if (line != NULL && line->len != 0) + c = line->buffer[0]; + else + return c; + + while (line->next != NULL && line->len > size) { + strncpy(line->buffer, &(line->buffer[1]), size - 1); + line->buffer[size - 1] = line->next->buffer[0]; + line->changed = 1; + line = line->next; + } + + /* + * once I get here I should be one the last line, so I can just copy all + * the characters back one and then return from whence I came *** + */ + if (line->len > 0) { + line->changed = 1; + if (line->len > 1) + strncpy(line->buffer, &(line->buffer[1]), line->len - 1); + line->buffer[--line->len] = 0; + if (line->len == 0) { + /* I have to fix the previous line */ + line->prev->len = size; + line->prev->buffer[size] = 0; + } + } + return c; +} + +static void +delete_rest_of_line(InputItem *sym) +{ + LineStruct *curr_line = sym->curr_line; + LineStruct *line=NULL; + LineStruct *trash; + LineStruct *trace; + int num_changed = 0, i; + + if (curr_line->len > sym->size) { + for (line = curr_line->next, num_changed = 0; + line != NULL && line->len > 0 && line->len > sym->size; + line = line->next, num_changed++) { + line->len = 0; + line->buffer[0] = 0; + line->changed = 1; + } + num_changed++; + } + + if (num_changed == 0 && curr_line->buff_pntr == curr_line->len) { + if (curr_line->len == 0 && curr_line->next) { + curr_line->next->prev = curr_line->prev; + if (curr_line->prev) + curr_line->prev->next = curr_line->next; + else + sym->lines = curr_line->next; + dec_line_numbers(curr_line->next); + sym->num_lines--; + sym->curr_line = curr_line->next; + sym->curr_line->buff_pntr = 0; + free(curr_line->buffer); + free(curr_line); + redraw_win(); + } + else + BeepAtTheUser(); + return; + } + + curr_line->len = curr_line->buff_pntr; + + /* curr_line->buffer[curr_line->len] = NULL; */ + + for (i = curr_line->len; i <= sym->size + 2; i++) + curr_line->buffer[i] = 0; + + curr_line->changed = 1; + + if (num_changed) { + /* I should get rid of all these lines */ + trace = curr_line->next; + curr_line->next = line->next; + if (line->next) + line->next->prev = curr_line; + for (; trace && trace != line->next;) { + trash = trace; + trace = trace->next; + free(trash->buffer); + free(trash); + } + decrease_line_numbers(curr_line->next, num_changed); + sym->num_lines -= num_changed; + redraw_win(); + } + else + update_inputsymbol(sym); +} + +static void +back_over_eoln(InputItem *sym) +{ + /* + * This routine is very similar to a tough enter except it starts + * combining lines with sym->curr_line->pre + */ + + char buff[1024]; + LineStruct *trace; + LineStruct *last = NULL; + char *tr = buff; + int bp; + int size = sym->size; + + /* copy all the stuff into the buffer */ + for (trace = sym->curr_line; + trace->len > sym->size; trace = trace->next) + for (bp = 0; bp < size; bp++) + *tr++ = trace->buffer[bp]; + + /* copy the last line */ + for (bp = 0; bp < trace->len; bp++) + *tr++ = trace->buffer[bp]; + trace->len = 0; + *tr = 0; + + /* Now that I have the buffer, let's put it back where it belongs. */ + last = trace; + for (trace = sym->curr_line; trace != last; trace = trace->next); + trace = sym->curr_line = sym->curr_line->prev; + trace->buff_pntr = trace->len; + trace->changed = 1; + for (bp = trace->len, tr = buff; bp < size && *tr; bp++) + trace->buffer[bp] = *tr++; + + if (!*tr) { + trace->len = bp; + } + else { + trace->len = size + 1; + trace->buffer[size] = '_'; + trace->buffer[size + 1] = 0; + for (trace = trace->next; *tr;) { + for (bp = 0; bp < size && *tr; bp++) + trace->buffer[bp] = *tr++; + if (*tr) { + trace->len = size + 1; + trace->changed = 1; + trace->buffer[size + 1] = 0; + trace->buffer[size] = '_'; + trace = trace->next; + } + else { + trace->len = bp; + trace->buffer[bp] = 0; + } + } + } + /* Now once I am here, let me see if I can bag a line */ + if (last->len == 0) { + /* rid myself of this line */ + last->prev->next = last->next; + if (last->next) + last->next->prev = last->prev; + dec_line_numbers(last->next); + sym->num_lines--; + free(last->buffer); + free(last); + redraw_win(); + } + else + update_inputsymbol(sym); + +} + +static int +move_back_one_char(InputItem *sym) +{ + char c = '\000', d = '\000'; + int dl = 0; + + /* This routine moves all the characters back one */ + LineStruct *line = sym->curr_line; + + if (line->len > sym->size) + c = move_rest_back(line->next, sym->size); + + line->changed = 1; + + if (line->buff_pntr == 0) { /* I am at the front of the line */ + if (line->prev == 0) { + BeepAtTheUser(); + return 0; + } + else if (line->prev->len <= sym->size) { + back_over_eoln(sym); + return 1; + } + else if (line->len > 0) { + d = line->buffer[0]; + if (line->len <= sym->size) { + strncpy(line->buffer, &(line->buffer[1]), line->len - 1); + if (c == 0) { + line->len--; + line->buffer[line->len] = 0; + } + else + line->buffer[line->len - 1] = c; + } + else { + strncpy(line->buffer, &(line->buffer[1]), sym->size - 2); + if (c == 0) { + line->buffer[sym->size - 1] = 0; + line->len--; + } + else { + line->buffer[sym->size - 1] = c; + } + } + } + else { + /* the line is just going to be thrown away */ + if (line->next) + line->next->prev = line->prev; + line->prev->next = line->next; + dec_line_numbers(line->next); + sym->num_lines--; + free(line->buffer); + free(line); + dl = 1; + } + c = d; + sym->curr_line = line = line->prev; + line->changed = 1; + line->buff_pntr = sym->size; + } + + + if (line->len <= sym->size) { + strncpy(&line->buffer[line->buff_pntr - 1], + &(line->buffer[line->buff_pntr]), + line->len - line->buff_pntr); + if (c == 0) + line->buffer[--line->len] = 0; + else + line->buffer[line->len - 1] = c; + } + else { + strncpy(&(line->buffer[line->buff_pntr - 1]), + &(line->buffer[line->buff_pntr]), + sym->size - line->buff_pntr); + if (c == 0) { + line->buffer[sym->size - 1] = 0; + line->len = sym->size - 1; + } + else { + if (line->next->len == 0) { + line->buffer[sym->size] = 0; + line->len = sym->size; + } + line->buffer[sym->size - 1] = c; + } + } + line->buff_pntr--; + if (dl) + redraw_win(); + else + update_inputsymbol(sym); + return 1; +} + +static void +back_over_char(InputItem *sym) +{ + if (move_back_one_char(sym)) + update_inputsymbol(sym); +} + +static void +delete_eoln(InputItem *sym) +{ + /* much the same as back_over eoln except my perspective has changed */ + char buff[1024]; + LineStruct *trace; + LineStruct *last = 0; + char *tr = buff; + int bp; + int size = sym->size; + + /* copy all the stuff into the buffer */ + for (trace = sym->curr_line->next; + trace->len > sym->size; trace = trace->next) + for (bp = 0; bp < size; bp++) + *tr++ = trace->buffer[bp]; + + /* copy the last line */ + for (bp = 0; bp < trace->len; bp++) + *tr++ = trace->buffer[bp]; + trace->len = 0; + *tr = 0; + + /* Now that I have the buffer, let's put it back where it belongs. */ + last = trace; + trace = sym->curr_line; + trace->changed = 1; + for (bp = trace->len, tr = buff; bp < size && *tr; bp++) + trace->buffer[bp] = *tr++; + + if (!*tr) + trace->len = bp; + else { + trace->len = size + 1; + trace->buffer[size] = '_'; + trace->buffer[size + 1] = 0; + for (trace = trace->next; *tr;) { + for (bp = 0; bp < size && *tr; bp++) + trace->buffer[bp] = *tr++; + if (*tr) { + trace->len = size + 1; + trace->changed = 1; + trace->buffer[size + 1] = 0; + trace->buffer[size] = '_'; + trace = trace->next; + } + else { + trace->len = bp; + trace->buffer[bp] = 0; + } + } + } + /* Now once I am here, let me see if I can bag a line */ + if (last->len == 0) { + /* rid myself of this line */ + last->prev->next = last->next; + if (last->next) + last->next->prev = last->prev; + dec_line_numbers(last->next); + sym->num_lines--; + free(last->buffer); + free(last); + redraw_win(); + } + else + update_inputsymbol(sym); + +} + +static int +delete_one_char(InputItem *sym) +{ + char c = '\000'; + + /* This routine moves all the characters back one */ + LineStruct *line = sym->curr_line; + + if (line->len > sym->size) + c = move_rest_back(line->next, sym->size); + + if (c == 0 && line->len == line->buff_pntr) { + if (line->next == 0) { + BeepAtTheUser(); + return 0; + } + else { + delete_eoln(sym); + return 1; + } + } + + /* + * let me just try to do the copy and put the stupid character c if it + * exists at the end + */ + if (line->len <= sym->size) { + strncpy(&line->buffer[line->buff_pntr], + &(line->buffer[line->buff_pntr + 1]), + line->len - line->buff_pntr); + if (c == 0) + line->buffer[--line->len] = 0; + else + line->buffer[line->len - 1] = c; + } + else { + strncpy(&(line->buffer[line->buff_pntr]), + &(line->buffer[line->buff_pntr + 1]), + sym->size - line->buff_pntr); + if (c == 0) { + line->buffer[sym->size - 1] = 0; + line->len = sym->size - 1; + } + else { + if (line->next->len == 0) { + line->buffer[sym->size] = 0; + line->len = sym->size; + } + line->buffer[sym->size - 1] = c; + } + } + line->changed = 1; + return 1; +} + +static void +delete_char(InputItem *sym) +{ + if (delete_one_char(sym)) + update_inputsymbol(sym); +} + +static void +tough_enter(InputItem *sym) +{ + char buff[1024]; + + /* + * This routine takes all the characters from the current cursor + * on, and copies them into a temp buffer, from which they are recopied + * back starting at the next line. + */ + + LineStruct *trace; + LineStruct *last = 0; + LineStruct *newline; + char *tr = buff; + int bp = sym->curr_line->buff_pntr; + int size = sym->size; + + /* Copy the stuff from the current line */ + for (; bp < size; bp++) + *tr++ = sym->curr_line->buffer[bp]; + + /* now get the stuff from the rest of the lines */ + for (trace = sym->curr_line->next; + trace->len > sym->size; trace = trace->next) + for (bp = 0; bp < size; bp++) + *tr++ = trace->buffer[bp]; + + /* copy the last line */ + for (bp = 0; bp < trace->len; bp++) + *tr++ = trace->buffer[bp]; + *tr = 0; + + /* Now that I have the buffer, let's put it back where it belongs. */ + last = trace; + trace = sym->curr_line; + trace->len = trace->buff_pntr; + trace->buffer[trace->len] = 0; + trace->changed = 1; + + tr = buff; + for (trace = trace->next; trace != last; trace = trace->next) { + for (bp = 0; bp < size; bp++) + trace->buffer[bp] = *tr++; + trace->len = size + 1; + trace->buffer[size + 1] = 0; + trace->buffer[size] = '_'; + trace->changed = 1; + } + + /* Once I am here, I should be able to copy this last line */ + for (bp = 0; bp < size && *tr; bp++) + trace->buffer[bp] = *tr++; + trace->changed = 1; + + /* If I still have more to copy, then do so onto a new line */ + if (*tr) { + trace->len = size + 1; + trace->buffer[size + 1] = 0; + trace->buffer[size] = '_'; + newline = alloc_inputline(size); + sym->num_lines++; + newline->line_number = last->line_number + 1; + inc_line_numbers(newline->next); + for (bp = 0; *tr; bp++) + newline->buffer[bp] = *tr++; + newline->len = bp; + newline->next = last->next; + newline->prev = last; + last->next = newline; + if (newline->next) + newline->next->prev = newline; + } + else { + trace->len = bp; + trace->buffer[bp] = 0; + } + /* Last but not least change the curr_line */ + sym->curr_line = sym->curr_line->next; + sym->curr_line->buff_pntr = 0; +} + +static void +enter_new_line(InputItem *sym) +{ + LineStruct *newline; + LineStruct *trace; + LineStruct *prev; + LineStruct *line = sym->curr_line; + int bp = line->buff_pntr; + int l = line->len; + int size = sym->size; + + /* + * At this point the user has hit a return. Let me just be naive, and + * take everything from the current spot on, and put it on a new line + */ + + if (bp == 0) { + if (line->prev->len > size) { + /* just add a return to the end of the last line */ + prev = line->prev; + prev->buffer[size] = 0; + prev->len = size; + prev->changed = 1; + } + else { + newline = alloc_inputline(size); + newline->next = sym->curr_line; + newline->prev = sym->curr_line->prev; + line->prev = newline; + sym->num_lines++; + if (newline->prev) + newline->prev->next = newline; + newline->len = newline->buff_pntr = 0; + newline->line_number = line->line_number; + if (sym->curr_line == sym->lines) + sym->lines = newline; + for (trace = newline->next; trace != 0; trace = trace->next) + trace->line_number++; + } + } + else if (bp == size && + line->len > size) { + /* line->next; */ + newline = alloc_inputline(size); + if (line->next) + line->next->prev = newline; + newline->prev = sym->curr_line; + line->next = newline; + newline->len = 0; + newline->buff_pntr = 0; + sym->num_lines++; + sym->curr_line = newline; + newline->line_number = newline->prev->line_number + 1; + for (trace = newline->next; trace != 0; trace = trace->next) + trace->line_number++; + } + else { + if (line->len > size) + tough_enter(sym); + else { + newline = alloc_inputline(size); + strncpy(newline->buffer, &sym->curr_line->buffer[bp], l - bp); + sym->curr_line->len = bp; + sym->curr_line->buffer[bp] = '\0'; + newline->next = sym->curr_line->next; + if (sym->curr_line->next) + sym->curr_line->next->prev = newline; + newline->prev = sym->curr_line; + sym->curr_line->next = newline; + newline->len = l - bp; + newline->buff_pntr = 0; + sym->num_lines++; + sym->curr_line = newline; + newline->line_number = newline->prev->line_number + 1; + for (trace = newline->next; trace != 0; trace = trace->next) + trace->line_number++; + } + } + redraw_win(); +} + +void +dialog(XEvent *event, KeySym keysym, char *buffer) +{ + InputItem *item; + + item = gWindow->page->current_item; + if (item == 0) { + if (!((keysym >= XK_Shift_L) && (keysym <= XK_Hyper_R))) + /** if something other than a modifier key was hit **/ + BeepAtTheUser(); + return; + } + + + /* + * First check if the user had hit an enter key + */ + + if ((keysym == XK_Return) || (keysym == XK_KP_Enter)) + enter_new_line(item); + /* + * Else did the user actual type a character I can understand + */ + + else if (((keysym >= XK_KP_Space) && (keysym <= XK_KP_9)) + || ((keysym >= XK_space) && (keysym <= XK_asciitilde))) + { + /* only handle normal keys */ + + if (event->xkey.state & UnsupportedModMask) + BeepAtTheUser(); + else + add_buffer_to_sym(buffer, item); + } + + else if ((keysym >= XK_Shift_L) && (keysym <= XK_Hyper_R)) + ; + + /* + * do nothing, a modifier was hit + */ + + else if ((keysym >= XK_F2) && (keysym <= XK_F35)) { + + /* + * A function key was hit + */ + + if (strlen(buffer) == 0) + BeepAtTheUser(); + else + /* If I got characters then add it to the buffer */ + + add_buffer_to_sym(buffer, item); + } + else + switch (keysym) { + case XK_Escape: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else { + move_cursor_home(item); + delete_rest_of_line(item); + } + break; + case XK_F1: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else { + gWindow->page->helppage = alloc_string(InputAreaHelpPage); + helpForHyperDoc(); + } + break; + case XK_Up: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else + move_cursor_up(item); + break; + case XK_Down: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else + move_cursor_down(item); + break; + case XK_Delete: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else + delete_char(item); + break; + case XK_BackSpace: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else + back_over_char(item); + break; + case XK_Left: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else + move_cursor_backward(item); + break; + case XK_Right: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else + move_cursor_forward(item); + break; + case XK_Insert: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else { + gInInsertMode = ((gInInsertMode) ? (0) : (1)); + item->curr_line->changed = 1; + update_inputsymbol(item); + } + break; + case XK_Home: + if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else + move_cursor_home(item); + break; + case XK_End: + if (event->xkey.state & ControlMask) + /* delete from here to the end of the line */ + + delete_rest_of_line(item); + else if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else + move_cursor_end(item); + break; + default: + BeepAtTheUser(); + break; + } +} +@ +\section{display.h} +<>= +#ifndef _DISPLAY_H_ +#define _DISPLAY_H_ 1 + +<> + +extern short int gDisplayRegion; +extern int gRegionOffset; + +#endif +@ +\section{display.c} +<>= +/****************************************************************************** + * + * display.c: HyperDoc functions to format and display a page. + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ + +/* + * Notes: + * Display is performed in two steps. First the page is formatted + * assuming that we have an infinitely long window. In this stage + * we compute and store the coordinates of every text node. Next + * the page is actually drawn on the screen. In this process we + * use the value of page->y_off as an offset into the scrolling + * region to compute what is actually to be displayed on the page. + */ +#define _DISPLAY_C +#include "debug.h" + + +<> +<> +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + + +extern ItemStack *gTopOfItemStack; +short int gDisplayRegion = 0; +int gRegionOffset = 0; + + +/* Display a HyperDoc page in the top-level window */ + +void +show_page(HyperDocPage *page) +{ + XWindowChanges wc; + int doShowScrollBars = 1; + + init_top_group(); + + /* Clear the areas so we can rewrite the page */ + + XClearWindow(gXDisplay, gWindow->fMainWindow); + XClearWindow(gXDisplay, gWindow->fScrollWindow); + + /* Free the active button list */ + + free_button_list(page->s_button_list); + page->s_button_list = NULL; + free_button_list(page->button_list); + page->button_list = NULL; + + /* The compute the text extents */ + compute_title_extent(page); + compute_header_extent(page); + compute_footer_extent(page); + compute_scrolling_extent(page); + + /* + * Now that we have all the extents computed, reconfigure and map the + * scroll window + */ + + if (page->scrolling) { + int width, height; + calculateScrollBarMeasures(); + wc.x = 0; + wc.y = page->top_scroll_margin + scroll_top_margin; + + wc.height = gWindow->scrollheight; + if (gWindow->page->scrolling->height <= gWindow->scrollheight) { + gWindow->page->scroll_off = 0; + wc.width = gWindow->width; + } + else + wc.width = gWindow->width - gScrollbarWidth; + + getScrollBarMinimumSize(&width, &height); + if (height > wc.height) { + wc.height = gWindow->scrollheight = 1; + doShowScrollBars = 0; + } + else + gWindow->scrollwidth = wc.width; + + if (doShowScrollBars) { + XConfigureWindow(gXDisplay, gWindow->fScrollWindow, CWX | CWY | CWHeight | CWWidth, &wc); + XMapWindow(gXDisplay, gWindow->fScrollWindow); + } + else { + XUnmapWindow(gXDisplay, gWindow->fScrollWindow); + hideScrollBars(gWindow); + } + } + /* clear the group stack */ + + while (pop_group_stack() >= 0) + ; + + /* Now start displaying all the text */ + + gWindow->fDisplayedWindow = gWindow->fMainWindow; + gRegionOffset = 0; + y_off = 0; + gDisplayRegion = Header; + show_text(page->header->next, Endheader); + + if (doShowScrollBars && page->scrolling) { + /* Show the footer */ + if (page->footer->next) { + gDisplayRegion = Footer; + gRegionOffset = gWindow->page->bot_scroll_margin + + (!((gWindow->page->page_flags & NOLINES)) ? ((int) line_height / 2) : (0)); + show_text(page->footer->next, Endfooter); + /* Show the scrolling region */ + if (page->scrolling->next) + gDisplayRegion = Scrolling; + gRegionOffset = 0; + gWindow->fDisplayedWindow = gWindow->fScrollWindow; + y_off = gWindow->page->scroll_off; + show_text(page->scrolling->next, Endscrolling); + showScrollBars(gWindow); + } + drawScrollLines(); + } + if (gTopOfItemStack != NULL) { + fprintf(stderr, "warning: unbalanced \\beginitems .. \\enditems\n"); + gTopOfItemStack = NULL; + } + showTitleBar(); + XFlush(gXDisplay); +} + +void +expose_page(HyperDocPage *page) +{ + int width, height, doShowScrollBars = 1; + init_top_group(); + + /* + * Now start displaying all the text + */ + + y_off = 0; + gWindow->fDisplayedWindow = gWindow->fMainWindow; + gRegionOffset = 0; + gDisplayRegion = Header; + show_text(page->header->next, Endheader); + getScrollBarMinimumSize(&width, &height); + + /* + * Now see If I have anything left to display + */ + if (page->scrolling) { + if (page->footer->next) { + gDisplayRegion = Footer; + gRegionOffset = gWindow->page->bot_scroll_margin + + (!((gWindow->page->page_flags & NOLINES)) ? ((int) line_height / 2) : (0)); + show_text(page->footer->next, Endfooter); + } + + if (height > gWindow->scrollheight) { + gWindow->scrollheight = 1; + doShowScrollBars = 0; + XUnmapWindow(gXDisplay, gWindow->fScrollWindow); + hideScrollBars(gWindow); + } + + if (page->scrolling->next) { + gRegionOffset = page->top_scroll_margin; + gDisplayRegion = Scrolling; + gRegionOffset = 0; + gWindow->fDisplayedWindow = gWindow->fScrollWindow; + y_off = gWindow->page->scroll_off; + show_text(page->scrolling->next, Endscrolling); + if (doShowScrollBars) + showScrollBars(gWindow); + } + if (doShowScrollBars) + drawScrollLines(); + } + showTitleBar(); + XFlush(gXDisplay); +} + +void +scroll_page(HyperDocPage *page) +{ + init_top_group(); + /* free the active button list */ + free_button_list(page->s_button_list); + page->s_button_list = NULL; + /** Clear the scrolling area */ + XUnmapSubwindows(gXDisplay, gWindow->fScrollWindow); + gDisplayRegion = Scrolling; + gRegionOffset = 0; + gWindow->fDisplayedWindow = gWindow->fScrollWindow; + y_off = gWindow->page->scroll_off; + show_text(page->scrolling->next, Endscrolling); + moveScroller(gWindow); + XFlush(gXDisplay); +} + +void +paste_page(TextNode *node) +{ + int width, height; + int old_off = gWindow->page->scroll_off; + + /* free the active button list */ + free_button_list(gWindow->page->s_button_list); + gWindow->page->s_button_list = NULL; + free_button_list(gWindow->page->button_list); + gWindow->page->button_list = NULL; + XUnmapSubwindows(gXDisplay, gWindow->fScrollWindow); + + init_top_group(); + + /* recompute the extent of the scrolling region */ + + compute_scrolling_extent(gWindow->page); + + calculateScrollBarMeasures(); + getScrollBarMinimumSize(&width, &height); + + /* get ready to show the scrolling area */ + gRegionOffset = 0; + y_off = gWindow->page->scroll_off; + gDisplayRegion = Scrolling; + gWindow->fDisplayedWindow = gWindow->fScrollWindow; + if (gWindow->page->scroll_off == old_off) { + XClearArea(gXDisplay, gWindow->fScrollWindow, 0, + node->y - line_height + gRegionOffset + y_off, + gWindow->width, + gWindow->scrollheight - node->y + line_height - y_off, + False); + XFlush(gXDisplay); + } + else + XClearWindow(gXDisplay, gWindow->fScrollWindow); + + show_text(gWindow->page->scrolling->next, Endscrolling); + XFlush(gXDisplay); + hideScrollBars(gWindow); + + if (height > gWindow->scrollheight) { + gWindow->scrollheight = 1; + XUnmapWindow(gXDisplay, gWindow->fScrollWindow); + } + else { + showScrollBars(gWindow); + drawScrollLines(); + /* moveScroller(); */ + } + XFlush(gXDisplay); +} +@ +\section{event.h} +<>= +#ifndef _EVENT_H_ +#define _EVENT_H_ 1 + +<> + +extern Window gActiveWindow; +extern int gNeedIconName; + +#endif +@ +\section{event.c} +<>= +#define _EVENT_C +#include "debug.h" + + +<> + +#include +#include +#include +#include +#include +#include +#include + +#ifdef SGIplatform +#include +#endif + +<> +<> +<> +<> +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" +#include "sockio-c.h1" + +jmp_buf env; +Window gActiveWindow; +int motion = 0; +int gNeedIconName = 0; +unsigned long bigmask= 0xffffffff; +static HyperLink *gSavedInputAreaLink = NULL; + + + +/* + * This is the main X loop. It keeps grabbing events. Since the only way the + * window can die is through an event, it never actually end. One of the + * subroutines it calls is responsible for killing everything + */ + +void +mainEventLoop(void) +{ + XEvent event; + int Xcon; + fd_set rd, dum1, dum2; + motion = 0; + gActiveWindow = -1; + set_error_handlers(); + Xcon = ConnectionNumber(gXDisplay); + + while (1) { + /*fprintf(stderr,"event:mainEventLoop: loop top\n");*/ + while (gSessionHashTable.num_entries == 0) + pause(); + + /* XFlush(gXDisplay); */ + + if (!motion) + init_cursor_states(); + motion = 0; + + if (!spad_socket == 0) { + FD_ZERO(&rd); + FD_ZERO(&dum1); + FD_ZERO(&dum2); + FD_CLR(0, &dum1); + FD_CLR(0, &dum2); + FD_CLR(0, &rd); + FD_SET(spad_socket->socket, &rd); + FD_SET(Xcon, &rd); + if (!session_server == 0) { + FD_SET(session_server->socket, &rd); + } + if (XEventsQueued(gXDisplay, QueuedAlready)) { + XNextEvent(gXDisplay, &event); + handle_event(&event); + } + else { + select(FD_SETSIZE,(void *)&rd,(void *)&dum1,(void *)&dum2,NULL); + if (FD_ISSET(Xcon, &rd) || + XEventsQueued(gXDisplay, QueuedAfterFlush)) { + XNextEvent(gXDisplay, &event); + handle_event(&event); + } + else if FD_ISSET + (spad_socket->socket, &rd) + /* + * Axiom Socket do what handle_event does The 100 is + * $SpadStuff in hypertex.boot + */ + { + if (100 == get_int(spad_socket)) { + set_window(gParentWindow->fMainWindow); + make_busy_cursors(); + get_new_window(); + } + } + /* + * Session Socket Telling us about the death of a spadbuf + * (plus maybe more later) service_session_socket in + * spadint.c + */ + else + if (session_server && FD_ISSET(session_server->socket, &rd)) { + service_session_socket(); + } + } + } + else { + XNextEvent(gXDisplay, &event); + handle_event(&event); + } + } +} + +static void +handle_event(XEvent * event) +{ + XWindowAttributes wa; +/* fprintf(stderr,"event:handle_event entered\n");*/ + set_window(event->xany.window); + if (event->type == MotionNotify) { +/* fprintf(stderr,"event:handle_event type=MotionNotify\n");*/ + handle_motion_event((XMotionEvent *)event); + motion = 1; + return; + } + make_busy_cursors(); + switch (event->type) { + case DestroyNotify: +/* fprintf(stderr,"event:handle_event type=DestroyNotify\n");*/ + break; + case Expose: +/* fprintf(stderr,"event:handle_event type=Expose\n");*/ + XGetWindowAttributes(gXDisplay, gWindow->fMainWindow, &wa); + if ((gWindow->width == 0 && gWindow->height == 0) || + (wa.width != gWindow->width || wa.height != gWindow->height)) { + gWindow->width = wa.width; + gWindow->height = wa.height; + display_page(gWindow->page); + gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; + } + else /** just redraw the thing **/ + expose_page(gWindow->page); + XFlush(gXDisplay); + clear_exposures(gWindow->fMainWindow); + clear_exposures(gWindow->fScrollWindow); + break; + case ButtonPress: +/* fprintf(stderr,"event:handle_event type=ButtonPress\n");*/ + handle_button(event->xbutton.button, (XButtonEvent *)event); + XFlush(gXDisplay); + if (gWindow) { + while (XCheckTypedWindowEvent(gXDisplay, gWindow->fMainWindow, + Expose, event)); + while (XCheckTypedWindowEvent(gXDisplay, gWindow->fScrollWindow, + Expose, event)); + } + break; + case KeyPress: +/* fprintf(stderr,"event:handle_event type=KeyPress\n");*/ + handle_key(event); + if (gWindow) { + while (XCheckTypedWindowEvent(gXDisplay, gWindow->fMainWindow, + Expose, event)); + while (XCheckTypedWindowEvent(gXDisplay, gWindow->fScrollWindow, + Expose, event)); + } + break; + case MapNotify: +/* fprintf(stderr,"event:handle_event type=MapNotify\n");*/ + create_window(); + break; + + case SelectionNotify: +/* fprintf(stderr,"event:handle_event type=SelectionNotify\n");*/ + /* this is in response to a previous request in an input area */ + if ( gSavedInputAreaLink ) { + XSelectionEvent *pSelEvent; + Atom dataProperty; + pSelEvent = (XSelectionEvent *) event; + dataProperty = XInternAtom(gXDisplay, "PASTE_SELECTION", False); + /* change the input focus */ + + /* change_input_focus(gSavedInputAreaLink); */ + + /* try to get the selection as a window property */ + + if ( pSelEvent->requestor == gWindow->fMainWindow && + pSelEvent->selection == XA_PRIMARY && + /* pSelEvent->time == CurrentTime && */ + pSelEvent->target == XA_STRING && + pSelEvent->property == dataProperty ) + { + Atom actual_type; + int actual_format; + unsigned long nitems, leftover; + char *pSelection = NULL; + + if (Success == XGetWindowProperty(gXDisplay, + gWindow->fMainWindow, + pSelEvent->property, 0L, 100000000L, True, + AnyPropertyType, &actual_type, &actual_format, + &nitems, &leftover, (unsigned char **) &pSelection) ) + { + char *pBuffer; + InputItem *item = gSavedInputAreaLink->reference.string; + + for (pBuffer = pSelection; *pBuffer; ++pBuffer) + add_buffer_to_sym(pBuffer, item); + + XFree(pSelection); + } + } + + /* clear the link info */ + + gSavedInputAreaLink = NULL; + } + break; + + default: +/* fprintf(stderr,"event:handle_event type=default\n");*/ + break; + } + +} + +static void +create_window(void) +{ + XWindowAttributes wa; + + XGetWindowAttributes(gXDisplay, gWindow->fMainWindow, &wa); + + gWindow->width = wa.width; + gWindow->height = wa.height; + display_page(gWindow->page); + gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; + + /* then select for the events I normally would like to catch */ + XSelectInput(gXDisplay, gWindow->fMainWindow, ButtonPress | KeyPressMask | + PointerMotionMask | + ExposureMask /* | EnterWindowMask | LeaveWindowMask */ ); + XSelectInput(gXDisplay, gWindow->fScrollWindow, ExposureMask); + +} + +/* + * This routine is called when the quitbutton is hit. For the moment I am + * just going to leave it all behind + */ + +void +quitHyperDoc(void) +{ + HyperDocPage *page; + + if (gSessionHashTable.num_entries == 1 || gParentWindow == gWindow) { + if (!strcmp(gWindow->page->name, "ProtectedQuitPage")){ + exitHyperDoc(); + } + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, "ProtectedQuitPage"); + if (page == NULL) { + fprintf(stderr, "Unknown page name %s\n", "ProtectedQuitPage"); + exitHyperDoc(); + return; + } + if (gWindow->fDownLinkStackIndex == MaxDownlinkDepth) + fprintf(stderr, "exceeded maximum link nesting level\n"); + else + gWindow->fDownLinkStack[gWindow->fDownLinkStackIndex++] = gWindow->page; + gWindow->page = page; + display_page(gWindow->page); + gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; + } + else + exitHyperDoc(); +} + + +/* + * find_page takes as an argument the HyperDoc for a page name and returns + * the associated page + */ + +static HyperDocPage * +find_page(TextNode * node) +{ + char *page_name; + HyperDocPage *page; + + /* try and find the page name */ + page_name = print_to_string(node); + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, page_name); + + if (page == NULL) { + /* try to find the unknown page */ + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, "UnknownPage"); + if (page == NULL) { + /* Yikes, Even that could not be found */ + fprintf(stderr, "Unknown page name %s\n", page_name); + } + else { + if (page->type == UnloadedPageType) + page->type = UlUnknownPage; + else + page->type = UnknownPage; + } + } + return page; +} + +/* + * These are macros for taking care of the downlink stack, and the memolink + * stack. + */ + +#define NotSpecial(t) ((t == Quitbutton || t == Returnbutton || \ + t == Upbutton || t == UnknownPage || \ + t == UlUnknownPage || t == ErrorPage) ?(0):(1)) + +/* pushes a page onto the down link stack */ + +static void +downlink(void) +{ + if (gWindow->fDownLinkStackIndex == MaxDownlinkDepth) + fprintf(stderr, "exceeded maximum link nesting level\n"); + else + gWindow->fDownLinkStack[gWindow->fDownLinkStackIndex++] = gWindow->page; +} + +static void +memolink(void) +{ + if (gWindow->fMemoStackIndex == MaxMemoDepth) + fprintf(stderr, "exceeded maximum link nesting level\n"); + else { + gWindow->fMemoStack[gWindow->fMemoStackIndex] = gWindow->page; + gWindow->fDownLinkStackTop[gWindow->fMemoStackIndex++] = gWindow->fDownLinkStackIndex; + } +} + +static void +killAxiomPage(HyperDocPage * page) +{ + char command[512]; + + sprintf(command, "(|htpDestroyPage| '%s)", page->name); + send_lisp_command(command); +} + +static void +kill_page(HyperDocPage * page) +{ + page->scroll_off = 0; + if (page->type == SpadGen) { + hash_delete(gWindow->fPageHashTable, page->name); + killAxiomPage(page); + free_page(page); + } +} + +/* pops the memo stack */ + +static HyperDocPage * +returnlink(void) +{ + int i; + + if (gWindow->fMemoStackIndex == 0) { + BeepAtTheUser(); + return NULL; + } + else { + kill_page(gWindow->page); + for (i = gWindow->fDownLinkStackIndex - 1; + i >= gWindow->fDownLinkStackTop[gWindow->fMemoStackIndex - 1]; + i--) + { + kill_page(gWindow->fDownLinkStack[i]); + } + gWindow->fDownLinkStackIndex = + gWindow->fDownLinkStackTop[--gWindow->fMemoStackIndex]; + return (gWindow->fMemoStack[gWindow->fMemoStackIndex]); + } +} + +/* pops a page if it can from the downlink stack */ + +static HyperDocPage * +uplink(void) +{ + if (gWindow->fDownLinkStackIndex == 0) + return returnlink(); + else { + kill_page(gWindow->page); + return (gWindow->fDownLinkStack[--gWindow->fDownLinkStackIndex]); + } +} + +static void +windowlink_handler(TextNode * node) +{ + char *page_name; + + /* first try and find the page */ + page_name = print_to_string(node); + + if (init_top_window(page_name) == -1) { + return; + } +/* gWindow->fWindowHashTable = gWindow->page->fLinkHashTable;*/ +} + +void +make_window_link(char *name) +{ + if (init_top_window(name) != -1) +{}/* gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; */ +} + + +static void +lispwindowlink_handler(HyperLink * link) +{ + + /* + * Since we are popping up a new window, then we had better change all + * the cursors right away. We won't get another chance at it. + */ + + if (init_top_window(NULL) != -1) { + HyperDocPage *page = NULL; + int frame = gWindow->fAxiomFrame; + + page = issue_server_command(link); + gWindow->fAxiomFrame = frame; + gWindow->page = page; +/* gWindow->fWindowHashTable = gWindow->page->fLinkHashTable;*/ + } +} + +static HyperDocPage * +paste_button(PasteNode * paste) +{ + HyperDocPage *page = NULL; + int pastewhere=paste->where; + + + if ( paste->end_node ==NULL || paste->begin_node==NULL || paste->arg_node==NULL ){ + BeepAtTheUser(); + return NULL; + } + + page=parse_patch(paste); +/* paste has changed after this call so use pastewhere*/ + + if (pastewhere && page ) { + if (0 == strcmp(page->name, "ErrorPage")) + page = NULL; + } + else + BeepAtTheUser(); + + return page; +} + +void +helpForHyperDoc(void) +{ + HyperDocPage *page = NULL; + + /* do not do anything if we are already at the "no more help" page */ + + if (0 == strcmp(gWindow->page->name, NoMoreHelpPage)) + return; + + /* if no help page recorded, use the standard "no more help" page */ + + if (!gWindow->page->helppage) + gWindow->page->helppage = alloc_string(NoMoreHelpPage); + + /* if we are on the main help page, use "no more help" page */ + + if (0 == strcmp(gWindow->page->name, TopLevelHelpPage)) + gWindow->page->helppage = alloc_string(NoMoreHelpPage); + + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, gWindow->page->helppage); + + if (page) + make_window_link(gWindow->page->helppage); + else + BeepAtTheUser(); +} + +static HyperLink * +findButtonInList(HDWindow * window, int x, int y) +{ + ButtonList *bl; + + if (!window || window->page->type == UnloadedPageType) + return NULL; + for (bl = window->page->s_button_list; bl != NULL; bl = bl->next) + if (x >= bl->x0 && x <= bl->x1 && y >= bl->y0 && y <= bl->y1) + return bl->link; + for (bl = window->page->button_list; bl != NULL; bl = bl->next) + if (x >= bl->x0 && x <= bl->x1 && y >= bl->y0 && y <= bl->y1) + return bl->link; + return NULL; +} + +static HyperLink * +get_hyper_link(XButtonEvent * event) +{ + HyperLink *l1, *l2; + + l1 = (HyperLink *) hash_find(gWindow->fWindowHashTable, (char *)&(event->window)); + if (l1) + return l1; + l2 = findButtonInList(gWindow, event->x, event->y); + return l2; +} + +/* + * Handle a button pressed event. window is the subwindow in which the event + * occured, and button is the button which was pressed + */ + +static void +handle_button(int button, XButtonEvent * event) +{ + HyperLink *link; + HyperDocPage *page = NULL; + char *page_name; + + /* find page name from sub-window handle */ + + link = get_hyper_link(event); + + if (link == NULL) { /* user clicked on an inactive area */ +/* BeepAtTheUser(); */ /* I always thought this was annoying. RSS */ + return; + } + + switch (link->type) { + case Pastebutton: + page = paste_button(link->reference.paste); + break; + case Link: + page_name = print_to_string(link->reference.node); + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, page_name); + break; + case Helpbutton: + helpForHyperDoc(); + page = NULL; + break; + case Scrollbar: + scrollScroller(event); + break; + case Scrollupbutton: + scrollUp(); + break; + case Scrolldownbutton: + scrollDown(); + break; + + case Inputstring: + /* We must be changing input focus or getting a selection */ + + change_input_focus(link); + if ( button == Button2 ) { + XConvertSelection(gXDisplay, XA_PRIMARY, XA_STRING, + XInternAtom(gXDisplay, "PASTE_SELECTION", False), + gWindow->fMainWindow, CurrentTime); + gSavedInputAreaLink = link; + } + break; + + case SimpleBox: + page = NULL; + toggle_input_box(link); + break; + case Radiobox: + page = NULL; + toggle_radio_box(link); + break; + case Quitbutton: + quitHyperDoc(); + break; + case Returnbutton: /* pop memo information */ + page = returnlink(); + break; + case Upbutton: /* pop downlink information */ + page = uplink(); + break; + case Downlink: + page = find_page(link->reference.node); + if (page && NotSpecial(page->type)) + downlink(); + break; + case Memolink: + page = find_page(link->reference.node); + if (page && NotSpecial(page->type)) + memolink(); + break; + case Windowlink: + page = find_page(link->reference.node); + if (page && NotSpecial(page->type)) { + windowlink_handler(link->reference.node); + gNeedIconName = 1; + page = NULL; + } + break; + case Lispwindowlink: + lispwindowlink_handler(link); + gNeedIconName = 1; + page = NULL; + break; + case LispMemoLink: + case Spadmemolink: + page = issue_server_command(link); + if (page && NotSpecial(page->type)) + memolink(); + break; + case LispDownLink: + case Spaddownlink: + page = issue_server_command(link); + if (page && NotSpecial(page->type)) + downlink(); + break; + case Spadlink: + case Lisplink: + page = issue_server_command(link); + break; + case Lispcommand: + case Qspadcall: + case Spadcall: + page = issue_server_command(link); + break; + case Lispcommandquit: + case Spadcallquit: + case Qspadcallquit: + page = issue_server_command(link); + exitHyperDoc(); + break; + case Spadcommand: + case Spadgraph: + case Spadsrc: + issue_spadcommand(gWindow->page, link->reference.node, + button == Button1, link->type); + break; + case Unixlink: + page = issue_unixlink(link->reference.node); + if (page && NotSpecial(page->type)) { + downlink(); + } + break; + case Unixcommand: + issue_unixcommand(link->reference.node); + break; + default: + break; + } + + if (page) { + switch (page->type) { /* check for special button types */ + case Quitbutton: + exitHyperDoc(); + return; + case Returnbutton: + gWindow->page = returnlink(); + break; + case Upbutton: + gWindow->page = uplink(); + break; + case ErrorPage: + case UnknownPage: + case UlUnknownPage: + if (page->type == UlUnknownPage) + page->type = UnloadedPageType; + downlink(); + gWindow->page = page; + break; + default: /* a normal link */ + gWindow->page = page; + break; + } + if (link->type != Pastebutton) + display_page(gWindow->page); + gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; /* reset the window hash */ + } +} + + +void +exitHyperDoc(void) +{ + XEvent event; + + + if (gSessionHashTable.num_entries == 1 || gParentWindow == gWindow) { + free_hd_window(gWindow); + exit(0); + } + hash_delete(&gSessionHashTable, (char *)&gWindow->fMainWindow); + + /* + * Now we quickly want to flush all the events associated with this + * window from existence + */ + + XFlush(gXDisplay); + while (XCheckWindowEvent(gXDisplay, gWindow->fMainWindow, bigmask, &event)) { + } + while (XCheckWindowEvent(gXDisplay, gWindow->fScrollWindow,bigmask, &event)) { + } + while (XCheckWindowEvent(gXDisplay, gWindow->fDisplayedWindow, bigmask, &event)) { + } + while (XCheckWindowEvent(gXDisplay, gWindow->fScrollUpWindow, bigmask, &event)) { + } + while (XCheckWindowEvent(gXDisplay, gWindow->fScrollDownWindow, bigmask, &event)) { + } + while (XCheckWindowEvent(gXDisplay, gWindow->scrollbar, bigmask, &event)) { + } + while (XCheckWindowEvent(gXDisplay, gWindow->scroller, bigmask, &event)) { + } + + XDestroyWindow(gXDisplay, gWindow->fMainWindow); + free_hd_window(gWindow); + gWindow = NULL; + gActiveWindow = -1; + XFlush(gXDisplay); +} + +static int +set_window(Window window) +{ + Window root, parent, *children, grandparent,myarg; + HDWindow *htw; + unsigned int nchildren; + int st; + + myarg=window; + nchildren = 0; + htw = (HDWindow *) hash_find(&gSessionHashTable, (char *)&myarg); + if (htw != NULL) { + gWindow = htw; + return 1; + } + st = XQueryTree(gXDisplay, myarg, &root, &parent, &children, &nchildren); + if (st==0) goto ERROR; + if (nchildren > 0) + XFree(children); + htw = (HDWindow *) hash_find(&gSessionHashTable, (char *)&parent); + if (htw != NULL) { + gWindow = htw; + return 1; + + } + else { + /* check for a grandparent */ + st = XQueryTree(gXDisplay, parent, &root, &grandparent, &children, &nchildren); + if (st==0) goto ERROR; + if (nchildren > 0) + XFree(children); + htw = (HDWindow *) hash_find(&gSessionHashTable, (char *)&grandparent); + if (htw != NULL) { + gWindow = htw; + return 1; + } + } + + /* + * fprintf(stderr, "window(%d) and it's parent(%d) aren't in + * gSessionHashTable\n", window, parent); + + we never found that window. this happens if (not iff) we exit from + an unfocused non-main window under certain wm's and click-to-type. the program returns here with + the window handle that was just destroyed. So let's set the global gWindow + to the main window. + */ + +ERROR: + gWindow=gParentWindow; + return 0; +} + +/* + * This procedure whips thru the stack and clears all expose events for the + * given routine + */ +static void +clear_exposures(Window w) +{ + XEvent report; + + XFlush(gXDisplay); + while (XCheckTypedWindowEvent(gXDisplay, w, Expose, &report)); +} +void +get_new_window(void) +{ + + int val; + char buf[128]; + int frame; + Window wid; + HDWindow *htw; + HyperDocPage *hpage; + + + /* + * If I am going to try and start a new window, then I should make sure I + * have a coonection to listen on + * + * BUT This code is entered when a socket selects + * + * if (spad_socket == NULL) { spad_socket = + * connect_to_local_server(SpadServer, MenuServer, 10); if (spad_socket + * == NULL) { fprintf(stderr, "Get_new_window: Couldn't Connect to + * SpadServer\n"); return -1; } } + * + */ + + + frame = get_int(spad_socket); + val = get_int(spad_socket); + switch (val) { + case StartPage: + init_top_window(NULL); + val = get_int(spad_socket); + init_scanner(); + input_type = FromSpadSocket; + input_string = ""; + gWindow->page = parse_page_from_socket(); + gWindow->fAxiomFrame = frame; + XFlush(gXDisplay); + break; + case LinkToPage: + get_string_buf(spad_socket, buf, 128); + if (init_top_window(buf) == -1) { + fprintf(stderr, "get_new_window: Did not find page %s\n", buf); + /* return -1; */ + } + gWindow->fAxiomFrame = frame; + break; + case PopUpPage: + val = get_int(spad_socket); + init_form_window(NULL, val); + send_int(spad_socket, gWindow->fMainWindow); + init_scanner(); + input_type = FromSpadSocket; + input_string = ""; + gWindow->page = parse_page_from_socket(); + compute_form_page(gWindow->page); + + XMapWindow(gXDisplay, gWindow->fMainWindow); + + gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; + gWindow->fAxiomFrame = frame; + XFlush(gXDisplay); + break; + case PopUpNamedPage: + val = get_int(spad_socket); + get_string_buf(spad_socket, buf, 128); + + if (init_form_window(buf, val) == -1) { + send_int(spad_socket, -1); + break; + } + load_page(gWindow->page); + compute_form_page(gWindow->page); + + XMapWindow(gXDisplay, gWindow->fMainWindow); + + gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; + gWindow->fAxiomFrame = frame; + XFlush(gXDisplay); + send_int(spad_socket, gWindow->fMainWindow); + /* fprintf(stderr, "Window Id was %d\n", gWindow->fMainWindow); */ + break; + case ReplaceNamedPage: + wid = (Window) get_int(spad_socket); + get_string_buf(spad_socket, buf, 128); + + htw = (HDWindow *) hash_find(&gSessionHashTable,(char *)&wid); + if (htw == NULL) break; + hpage = (HyperDocPage *) hash_find(gWindow->fPageHashTable, buf); + if (hpage == NULL) break; + gWindow = htw; + gWindow->page = hpage; + display_page(gWindow->page); + gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; + clear_exposures(gWindow->fMainWindow); + clear_exposures(gWindow->fScrollWindow); + XFlush(gXDisplay); + break; + case ReplacePage: + wid = (Window) get_int(spad_socket); + set_window(wid); + init_scanner(); + input_type = FromSpadSocket; + input_string = ""; + gWindow->page = parse_page_from_socket(); + display_page(gWindow->page); + gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; + clear_exposures(gWindow->fMainWindow); + clear_exposures(gWindow->fScrollWindow); + XFlush(gXDisplay); + break; + case KillPage: + /* Here the user wishes to kill the page */ + wid = (Window) get_int(spad_socket); + htw = (HDWindow *) hash_find(&gSessionHashTable,(char *)&wid); + if (htw !=NULL) { + gWindow = htw; + exitHyperDoc(); + break; + } + break; + } + } +static void +set_cursor(HDWindow *window,Cursor state) +{ + if (state == gBusyCursor) + XDefineCursor(gXDisplay, window->fMainWindow, gBusyCursor); + else if (state == gActiveCursor) + XDefineCursor(gXDisplay, window->fMainWindow, gActiveCursor); + else + XDefineCursor(gXDisplay, window->fMainWindow, gNormalCursor); + XFlush(gXDisplay); +} + +static void +change_cursor(Cursor state, HDWindow *window) +{ + if (window->fDisplayedCursor == state) + return; + window->fDisplayedCursor = state; + set_cursor(window, state); +} + +static void +handle_motion_event(XMotionEvent *event) +{ + if (!gWindow) + return; + if (findButtonInList(gWindow, event->x, event->y) != NULL) + change_cursor(gActiveCursor, gWindow); + else + change_cursor(gNormalCursor, gWindow); +} + +static void +init_cursor_state(HDWindow *window) +{ + if (window) { + int x, y, rx, ry, but; + Window r, c; + + XQueryPointer(gXDisplay, window->fMainWindow, + &r, &c, &rx, &ry, &x, &y,(unsigned int *) &but); + if (findButtonInList(window, x, y) != NULL) + change_cursor(gActiveCursor, window); + else + change_cursor(gNormalCursor, window); + } +} + +static void +init_cursor_states(void) +{ + hash_map(&gSessionHashTable,(MappableFunction) init_cursor_state); +} + + +static void +make_busy_cursor(HDWindow *window) +{ + change_cursor(gBusyCursor, window); +} + +static void +make_busy_cursors(void) +{ + hash_map(&gSessionHashTable, (MappableFunction)make_busy_cursor); +} + +static int +HyperDocErrorHandler(Display *display, XErrorEvent *xe) +{ + if (xe->request_code != 15) { + char buf[1024]; + + XGetErrorText(display, xe->error_code, buf, sizeof(buf)); + + fprintf(stderr, "error code = %d\n", xe->error_code); + fprintf(stderr, "major op code = %d\n", xe->request_code); + fprintf(stderr, "minor op code = %d\n", xe->minor_code); + fprintf(stderr, "XID = %ld\n", xe->resourceid); + fprintf(stderr, "%s\n", buf); + + if (xe->request_code != 15) + exit(-1); + } + return(0); +} + + + +static void +set_error_handlers(void) +{ + XSetErrorHandler(HyperDocErrorHandler); +} +@ +\section{ex2ht.c} +<>= +/* ex2ht creates a cover page for structured HyperDoc example pages */ + + +#define _EX2HT_C +#include "debug.h" +#include +#include +#include +#include +#include +#include +#include + + + +#if defined(SUN4OS5platform)||defined(SGIplatform) +/* can't find a prototype anywhere */ +extern int utimes(const char *, const struct timeval [2]); +#endif + + +#define MaxLineLength 512 +#define MaxFiles 100 + +char *files[MaxFiles]; +int numFiles = 0; +struct timeval latest_date[2] ={{0,0},{0,0}}; + +#include "ex2ht.h1" + + +int +main(int argc, char **argv) +{ + int i; + + if (argc == 1) { + fprintf(stderr, "usage: %s exfile.ht ...\n", argv[0]); + return (-1); + } + openCoverPage(); + for (i = 1; i < argc; i++) + exToHt(argv[i]); + closeCoverPage(); + for (i = 0; i < numFiles; i++) + addFile(files[i]); + closeCoverFile(); + return 0; +} + +char * +allocString(char *s) +{ + char *t = (char *) malloc(strlen(s) + 1); + + strcpy(t, s); + return t; +} + +char * +strPrefix(char *prefix, char *s) +{ + while (*prefix != '\0' && *prefix == *s) { + prefix++; + s++; + } + if (*prefix == '\0') + return s; + return NULL; +} + +char * +getExTitle(FILE *inFile, char *line) +{ + char *title; + + while (fgets(line, MaxLineLength, inFile) != NULL) + if ((title = strPrefix("% Title: ", line))) { + title[strlen(title) - 1] = '\0'; + return title; + } + fprintf(stderr, "No Title title line in the file!\n"); + return NULL; +} + +void +exToHt(char *filename) +{ + char line[MaxLineLength], *line2; + char *title, *pagename; + FILE *inFile = fopen(filename, "r"); + FILE *outFile; + int len, i; + struct timeval tvp; + struct stat buf; + + if (inFile == NULL) { + fprintf(stderr, "couldn't open %s for reading.\n", filename); + return; + } + strcpy(line, "Menu"); + strcat(line, filename); + len = strlen(line); + for (i = 0; i < len; i++) + if (line[i] == '.') { + line[i] = '\0'; + break; + } + outFile = fopen(line, "w"); + if (outFile == NULL) { + fprintf(stderr, "couldn't open %s for writing.\n", line); + return; + } + pagename = allocString(line); + title = getExTitle(inFile, line); + if (title == NULL) { + return; + } + files[numFiles++] = pagename; + emitCoverLink(pagename, title); + emitHeader(outFile, pagename, title); + while (fgets(line, MaxLineLength, inFile) != NULL) { + if ((line2 = strPrefix("\\begin{page}{", line))) + emitMenuEntry(line2, outFile); + else if ((line2 = strPrefix("\\spadcommand{", line))) + emitSpadCommand(line2, "\\spadcommand{", outFile); + else if ((line2 = strPrefix("\\spadpaste{", line))) + emitSpadCommand(line2, "\\spadpaste{", outFile); + else if ((line2 = strPrefix("\\example{", line))) + emitSpadCommand(line2, "\\example{", outFile); + else if ((line2 = strPrefix("\\graphpaste{", line))) + emitSpadCommand(line2, "\\graphpaste{", outFile); + } + emitFooter(outFile); + fclose(inFile); + fclose(outFile); + stat(filename,&buf); + tvp.tv_sec =buf.st_mtime; + tvp.tv_usec =0; + if timercmp(&tvp,&latest_date[1],>){ + latest_date[1].tv_sec=buf.st_mtime; + } +} + +void +emitHeader(FILE *outFile, char *pageName, char *pageTitle) +{ + fprintf(outFile, "\\begin{page}{%s}{%s}\n", pageName, pageTitle); + fprintf(outFile, "\\beginscroll\\beginmenu\n"); +} + +void +emitFooter(FILE *outFile) +{ + fprintf(outFile, "\\endmenu\\endscroll\\end{page}\n"); +} + +/* s is pageName}{title} */ +void +emitMenuEntry(char *line, FILE *outFile) +{ + char pageName[MaxLineLength], title[MaxLineLength]; + char *p = pageName, *t = title; + + while (*line != '}') + *p++ = *line++; + *p = '\0'; + line++; + while (*line != '}') + *t++ = *line++; + *t = '\0'; + fprintf(outFile, "\\menudownlink%s}{%s}\n", title, pageName); +} + +void +emitSpadCommand(char *line, char *prefix, FILE *outFile) +{ + int braceCount = 1; + char command[MaxLineLength], *t = command; + + while (1) { + if (*line == '}') + braceCount--; + if (braceCount == 0) + break; + if (*line == '{') + braceCount++; + *t++ = *line++; + } + *t = '\0'; + fprintf(outFile, "%s%s}\n", prefix, command); +} + +/* cover page functions */ + +FILE *coverFile; + +void +openCoverPage(void) +{ + coverFile = fopen("coverex.ht", "w"); + if (coverFile == NULL) { + fprintf(stderr, "couldn't open coverex.ht for writing\n"); + exit(-1); + } + fprintf(coverFile, "%% DO NOT EDIT! Created by ex2ht.\n\n"); + fprintf(coverFile, "\\begin{page}{ExampleCoverPage}{Examples Of AXIOM Commands}\n"); + fprintf(coverFile, "\\beginscroll\\table{\n"); +} + +void +closeCoverPage(void) +{ + fprintf(coverFile, "}\\endscroll\\end{page}\n\n"); +} + +void +closeCoverFile(void) +{ + fclose(coverFile); +#ifdef HP9platform + times("coverex.ht",latest_date); +#else + utimes("coverex.ht",latest_date); +#endif +} + +void +emitCoverLink(char *name, char *title) +{ + fprintf(coverFile, "{\\downlink{%s}{%s}}\n", title, name); +} + +void +addFile(char *filename) +{ + FILE *file = fopen(filename, "r"); + int c; + + if (file == NULL) { + fprintf(stderr, "Couln't open %s for reading\n", filename); + exit(-1); + } + while ((c = getc(file)) != EOF) + putc(c, coverFile); + putc('\n', coverFile); + fclose(file); + unlink(filename); +} +@ +\section{extent1.c} +<>= +/****************************************************************************** + * + * extent1.h: HyperDoc extent computation routines + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _EXTENT1_C +#include "debug.h" + + +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + + +/* + * Now we declare all the values which are shared among the extent routines + * and the showing routines + */ + +int noop_count; + +TextNode *link_node = NULL; +TextNode *paste_node = NULL; +TextNode *spad_node = NULL; +TextNode *if_node = NULL; + + +short int gExtentRegion; + + +short int gInDesc; +short int gInLine; /* true iff there have been words printed */ +short int gInItem; /* true iff we are in a \item */ +short int gInAxiomCommand; /* true iff we are in a \spadcommand */ +short int gInTable; + +/* Variables for the formatting state */ + +int right_margin_space; +int right_margin; +int indent; +int item_indent; +int text_x; +int text_y; +int y_off; +int scroll_bot; +int need_scroll_up_button; +int need_scroll_down_button; +int item_space; +int present_line_height; +int past_line_height; +int line_height; /* space between lines */ +int normal_text_height; /* space between lines */ +int space_width; /* the maximum width of a character */ +int word_off_height; /* the diff between text height and */ + +TextNode *gLineNode; + +/* + * Computes the extent of the input string or box + */ + +static void +compute_input_extent(TextNode * node) +{ + InputItem *item; + int t_width; + int num_lines; + + /* search the symbol table for the proper entry */ + + item = node->link->reference.string; + num_lines = item->num_lines; + + /* + * Once we have gotten this far, we should just be able to calculate the + * width using the normal font + */ + + t_width = (item->size + 1) * gInputFont->max_bounds.width + 10; + + if (gInLine) + text_x += inter_word_space; + + if (text_x + t_width > right_margin) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + + /* now figure out the height of the current window */ + + node->height = line_height * (num_lines); + node->y = text_y - line_height + node->height - 1; + if (node->height > present_line_height) + present_line_height = plh(node->height); + node->width = t_width; + gInLine = 1; + text_x += t_width; +} + +static void +compute_punctuation_extent(TextNode * node) +{ + int twidth; + int nextwidth; + int incwidth; + + node->height = normal_text_height; + node->width = strlen(node->data.text); + incwidth = twidth = XTextWidth(gTopOfGroupStack->cur_font, node->data.text, + node->width); + + /* always check to see if there was some space in front of us */ + + if (gInLine && (node->space & FRONTSPACE)) + twidth += inter_word_space; + + /* + * now calcualte the width of the next one if it needs to be considered + */ + + if (!(node->space & BACKSPACE)) + nextwidth = total_width(node->next, Endtokens); + else + nextwidth = 0; + + if ((!(node->space & BACKSPACE)) && + (text_x + twidth + nextwidth > right_margin) && gInLine) { + start_newline(present_line_height, node); + if (gInAxiomCommand) { + text_x = indent + spadcom_indent; + } + else + text_x = indent; + } + + if (node->space & FRONTSPACE) + text_x += inter_word_space; + + node->x = text_x; + + /* + * Now try to see if we should leave space after myself. Always leave + * space when there is space + */ + + if (node->space & BACKSPACE) { + switch (node->data.text[0]) { + case '.': + case '?': + case '!': + text_x += term_punct_space; + break; + } + } + + text_x += incwidth; + node->y = text_y - word_off_height; + gInLine = 1; +} + +static void +compute_word_extent(TextNode * node) +{ + int twidth; + int nextwidth; + int incwidth; + + node->height = normal_text_height; + node->width = strlen(node->data.text); + incwidth = twidth = XTextWidth(gTopOfGroupStack->cur_font, node->data.text, + node->width); + + /* + * Now if we should drop some space in front of me, then add it to twidth + */ + + if (gInLine && node->space) + twidth += inter_word_space; + + /* + * Now what we should do is find all the things after us that have no + * space in front and add there width on. + */ + + nextwidth = total_width(node->next, Endtokens); + + + /* + * Should we start a new line? + */ + + if (text_x + twidth + nextwidth > right_margin && gInLine) { + start_newline(present_line_height, node); + if (gInAxiomCommand) { + text_x = indent + spadcom_indent; + } + else + text_x = indent; + } + + /* + * Now see if we am on the beginning of a line, and if not add some space + * if we need to + */ + + if (gInLine && node->space) + text_x += inter_word_space; + + node->x = text_x; + node->y = text_y - word_off_height; + text_x += incwidth; + gInLine = 1; +} + +static void +compute_verbatim_extent(TextNode *node) +{ + node->height = normal_text_height; + node->width = strlen(node->data.text); + + node->x = text_x; + node->y = text_y - word_off_height; + gInLine = 1; + return; +} + +static void +compute_spadsrctxt_extent(TextNode *node) +{ + node->height = normal_text_height; + node->width = strlen(node->data.text); + + if (gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + node->y = text_y - word_off_height; + gInLine = 1; + return; +} + +static void +compute_dash_extent(TextNode *node) +{ + int num_dashes; + int twidth; + int nextwidth; + + node->height = normal_text_height; + + num_dashes = strlen(node->data.text); + + if (num_dashes > 1) + twidth = node->width = num_dashes * dash_width; + else + twidth = node->width = XTextWidth(gTopOfGroupStack->cur_font, + node->data.text, 1); + + if (gInLine && node->space) + twidth += inter_word_space; + + /* + * Now what we should do is find all the things after us that have no + * space in front and add there width on. + */ + + nextwidth = total_width(node->next, Endtokens); + + /* + * Should we start a new line? + */ + + if (text_x + twidth + nextwidth > right_margin) { + start_newline(present_line_height, node); + if (gInAxiomCommand) { + text_x = indent + spadcom_indent; + } + else + text_x = indent; + } + + /* + * Now see if we am on the beginning of a line, and if not add some space + * if we need to + */ + + if (gInLine && node->space) + text_x += inter_word_space; + + node->x = text_x; + if (num_dashes > 1) + node->y = text_y - dash_y; + else + node->y = text_y - word_off_height; + text_x += node->width; + gInLine = 1; + return; +} + +void +compute_text_extent(TextNode *node) +{ + for (; node != NULL; node = node->next) { + switch (node->type) { + case Endpastebutton: + endpastebutton_extent(node); + break; + case Paste: + compute_paste_extent(node); + break; + case Endpaste: + if (gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + break; + case Pastebutton: + compute_pastebutton_extent(node); + break; + case Ifcond: + compute_ifcond_extent(node); + break; + case Fi: + break; + case Endif: + if (if_node == NULL) { + return; + } + else + endif_extent(node); + break; + case Endcenter: + start_newline(present_line_height, node->next); + pop_group_stack(); + text_x = indent; + break; + case Pound: + case Macro: + /* check to see if we had space in front of me, if so add it */ + + if (node->space && gInLine) + text_x += inter_word_space; + break; + case Punctuation: + compute_punctuation_extent(node); + break; + case Endmath: + break; + case Endverbatim: + if (gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + break; + case Spadsrctxt: + compute_spadsrctxt_extent(node); + break; + case Math: + compute_word_extent(node); + break; + case Verbatim: + compute_verbatim_extent(node); + break; + case WindowId: + case Word: + case Lsquarebrace: + case Rsquarebrace: + compute_word_extent(node); + break; + case Dash: + compute_dash_extent(node); + break; + case HSpace: + node->height = line_height; + node->x = text_x; + node->y = text_y; + if (gInLine) { + text_x += + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1); + } + break; + case VSpace: + node->height = line_height; + node->x = text_x; + node->y = text_y + present_line_height;; + text_y += + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1) + + present_line_height; + past_line_height = (node->data.node != NULL ? + atoi(node->data.node->data.text) : 1) + + present_line_height; + + present_line_height = line_height; + break; + case Space: + node->height = line_height; + node->x = text_x; + node->y = text_y; + text_x += (gTopOfGroupStack->cur_font->max_bounds.width) * + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1); + break; + case Tab: + node->height = line_height; + text_x = indent + (gTopOfGroupStack->cur_font->max_bounds.width) * + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1); + gInLine = 0; + break; + case Par: + node->height = line_height; + if (gInItem) + text_x = indent; + else + text_x = indent + paragraph_space; + if (gInLine) { + start_newline(present_line_height, node); + } + break; + case Newline: + if (gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + break; + case Horizontalline: + if (gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + node->height = line_height; + gInLine = 0; + node->y = text_y - line_height / 2; + node->x = text_x; + start_newline(present_line_height, node); + break; + case Center: + compute_center_extent(node); + break; + case Box: + compute_box_extent(node); + break; + case Mbox: + compute_mbox_extent(node); + break; + case Beginitems: + case Begintitems: + compute_begin_items_extent(node); + break; + case Enditems: + case Endtitems: + pop_item_stack(); + if (gInLine) { + start_newline(present_line_height, node); + } + text_x = indent; + break; + case Titem: + if (gInLine) { + start_newline(present_line_height, node); + } + text_x = indent - item_space; + break; + case Item: + compute_item_extent(node); + break; + case Mitem: + compute_mitem_extent(node); + break; + case Upbutton: + case Returnbutton: + case Memolink: + case Downlink: + case Link: + case Windowlink: + compute_button_extent(node); + break; + case Unixlink: + case Lisplink: + case Lispwindowlink: + case Spadcall: + case Spadcallquit: + case Qspadcall: + case Qspadcallquit: + case LispDownLink: + case LispMemoLink: + case Lispcommand: + case Lispcommandquit: + case Spadlink: + case Spaddownlink: + case Spadmemolink: + case Unixcommand: + compute_button_extent(node); + break; + case Endbutton: + endbutton_extent(node); + break; + case Endlink: + if (link_node == NULL) + return; + else + endbutton_extent(node); + break; + case Spadsrc: + compute_spadsrc_extent(node); + break; + case Spadcommand: + case Spadgraph: + compute_spadcommand_extent(node); + break; + case Endspadsrc: + end_spadsrc_extent(node); + break; + case Endspadcommand: + end_spadcommand_extent(node); + break; + case Indent: + indent = left_margin + + atoi(node->data.node->data.text) * + (gTopOfGroupStack->cur_font->max_bounds.width); + if (!gInLine) + text_x = indent; + break; + case Indentrel: + indent += atoi(node->data.node->data.text) * + (gTopOfGroupStack->cur_font->max_bounds.width); + if (!gInLine) + text_x = indent; + break; + case Group: + push_group_stack(); + node->y = text_y; + if (gInLine && node->space) + text_x += inter_word_space; + break; + case Endgroup: + pop_group_stack(); + break; + case Tableitem: + push_group_stack(); + node->y = text_y; + if (gInLine && node->space) + text_x += inter_word_space; + break; + case Endtableitem: + pop_group_stack(); + return; + case Controlbitmap: + case Inputbitmap: + if (node->width == -1) + insert_bitmap_file(node); + compute_image_extent(node); + break; + case Inputpixmap: + if (node->width == -1) + insert_pixmap_file(node); + compute_image_extent(node); + break; + case Table: + compute_table_extent(&node); + break; + case BoldFace: + compute_bf_extent(node); + break; + case Emphasize: + compute_em_extent(node); + break; + case It: + compute_it_extent(node); + break; + case Rm: + case Sl: + case Tt: + compute_rm_extent(node); + break; + case Inputstring: + compute_input_extent(node); + break; + case SimpleBox: + case Radiobox: + compute_ir_extent(node); + break; + case Endbox: + text_x += box_width; + break; + case Endmacro: + case Endparameter: + break; + case Description: + bf_top_group(); + break; + case Enddescription: + pop_group_stack(); + if (gInDesc) + return; + break; + case Endscrolling: + + /* + * What we should do here is if we am in the middle of a line, we + * should end it here an now. + */ + + if (gInLine) + start_newline(present_line_height, node); + break; + case Noop: + noop_count++; + break; + case Endinputbox: + case Endheader: + case Endtitle: + case Endfooter: + case Rbrace: + case Free: + case Bound: + case Beep: + case 0: + break; + default: + fprintf(stderr, "Compute_text_extent: Unknown node type %d\n", + node->type); + break; + } + } +} + +static void +compute_begin_items_extent(TextNode * node) +{ + int store_x, store_y, lh; + + /* + * This routine pushes the current item_stack, and then tries to set the + * item_indent, and the indent level. It checks for an optional argument + * to begin{items} and if found uses its width. + */ + if (gInLine) { + start_newline(present_line_height, node); + } + store_x = text_x, store_y = text_y, lh = present_line_height; + text_x = indent; + push_item_stack(); + gInItem++; + item_indent = indent; + if (node->data.node != NULL) { + /* we have a desc */ + gInDesc = 1; + compute_text_extent(node->data.node); + gInDesc = 0; + item_space = text_width(node->data.node, Enddescription); + text_x = store_x; + text_y = store_y; + present_line_height = lh; + indent = item_indent + item_space; + } + else + indent = item_indent + 30; + gInLine = 0; +} + +static void +compute_item_extent(TextNode * node) +{ + if (gInLine) + start_newline(present_line_height, node); + text_x = item_indent; +} + +static void +compute_mitem_extent(TextNode *node) +{ + if (gInLine) { + start_newline(present_line_height, node); + } + text_x = item_indent; +} + +static void +endif_extent(TextNode *node) +{ + /* + * This node has the responsibilty for updating text_x and text_y so that + * they are the maxaimum width of teh else and then statements + */ + + text_x = if_node->x; + text_y = if_node->y; + if_node = NULL; +} + +static void +compute_ifcond_extent(TextNode *node) +{ + TextNode *condnode = node->data.ifnode->cond; + TextNode *tln = gLineNode; + int store_x = text_x, store_y = text_y, lh = present_line_height; + int then_x, then_y; + + /* + * This routine checks the value of the condition and swaps in the else + * or the then depending + */ + + /* + * we have to compute the maximum width and height of the rest of the + * text and stuff + */ + push_group_stack(); + if (gInLine && node->space) + text_x += inter_word_space; + compute_text_extent(node->data.ifnode->thennode); + then_x = text_x; + then_y = text_y; + text_x = store_x; + text_y = store_y; + present_line_height = lh; + gLineNode = tln; + if (gInLine && node->space) + text_x += inter_word_space; + compute_text_extent(node->data.ifnode->elsenode); + /* Now choose the best one that is biggest and put it into ifnode */ + if (then_y > text_y) { + node->y = then_y; + node->x = then_x; + } + else if (text_y > then_y) { + node->y = text_y; + node->x = text_x; + } + else if (text_x > then_x) { + node->y = text_y; + node->x = text_x; + } + else { + node->y = then_y; + node->x = then_x; + } + /* restore everything */ + text_x = store_x; + text_y = store_y; + present_line_height = lh; + gLineNode = tln; + node->width = 0; + + if_node = node; + if (gInLine && node->space) + text_x += inter_word_space; + if (check_condition(condnode)) { + node->next = node->data.ifnode->thennode; + } + else { + node->next = node->data.ifnode->elsenode; + } + pop_group_stack(); +} + +static void +compute_center_extent(TextNode * node) +{ + if (gInLine) + start_newline(present_line_height, node); + + center_top_group(); + + if (gLineNode) + text_x = indent; + else { + fprintf(stderr, "(HyperDoc) Internal error: unexpected state in compute_center_extent.\n"); + exit(-1); + } +} + +static void +compute_bf_extent(TextNode *node) +{ + if (gInLine && node->space) + text_x += inter_word_space; + node->x = text_x; + node->y = text_y; + bf_top_group(); +} + +static void +compute_em_extent(TextNode *node) +{ + if (gInLine && node->space) + text_x += inter_word_space; + node->x = text_x; + node->y = text_y; + if (gTopOfGroupStack->cur_font == gEmFont) + rm_top_group(); + else + em_top_group(); +} + +static void +compute_it_extent(TextNode *node) +{ + if (gInLine && node->space) + text_x += inter_word_space; + node->x = text_x; + node->y = text_y; +} + +static void +compute_rm_extent(TextNode *node) +{ + if (gInLine && node->space) + text_x += inter_word_space; + node->x = text_x; + node->y = text_y; + rm_top_group(); +} + +static void +compute_button_extent(TextNode *node) +{ + int twidth; + /*int store_x = text_x;*/ + /*int store_y = text_y;*/ + /*int lh = present_line_height;*/ + + push_active_group(); + + /* First see if we should leave a little space in front of myself * */ + if (gInLine && node->space) + text_x += inter_word_space; + + twidth = text_width(node->next, Endbutton); + if (gInLine && node->space) + text_x += inter_word_space; + if (text_x + twidth > right_margin && gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + node->y = text_y; + link_node = node; +} + +static void +endbutton_extent(TextNode *node) +{ + int temp; + int height; + int twidth; + int y; + int maxx; + + maxx = max_x(link_node, Endbutton); + link_node->width = twidth = text_width(link_node->next, Endbutton); + height = link_node->y; + temp = text_height(link_node->next, Endbutton); + link_node->height = temp - link_node->y + line_height; + + if (gInLine) + y = text_y; + else + y = text_y - past_line_height; + if (y > height) { + link_node->y = temp; /* height + link_node->height - + * normal_text_height; */ + link_node->width = maxx - indent; + if (gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + } + else { + link_node->width = twidth; + link_node->y = text_y + link_node->height - line_height; + } + pop_group_stack(); + link_node = NULL; +} + +static void +compute_pastebutton_extent(TextNode *node) +{ + int twidth; + + push_active_group(); + + /* + First see if we should leave a little space in front of myself * */ + + if (gInLine && node->space) + text_x += inter_word_space; + + twidth = text_width(node->next, Endpastebutton); + if (gInLine && node->space) + text_x += inter_word_space; + if (text_x + twidth > right_margin && gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + node->y = text_y; + paste_node = node; + return; +} + +static void +endpastebutton_extent(TextNode *node) +{ + int temp; + int height; + int twidth; + + paste_node->width = twidth = text_width(paste_node->next, Endpastebutton); + height = paste_node->y; + temp = text_height(paste_node->next, Endpastebutton); + paste_node->height = temp - paste_node->y + line_height; + if (text_y > height) { + paste_node->y = temp; + paste_node->width = right_margin - indent; + if (gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + } + else { + paste_node->width = twidth; + paste_node->y = text_y + paste_node->height - line_height; + } + pop_group_stack(); + paste_node = NULL; + gInLine = 1; +} + +static void +compute_paste_extent(TextNode *node) +{ + if (gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + node->y = text_y; + node->height = line_height; +} + +/* Compute the text extent of a spadcommand node */ + +static void +compute_spadcommand_extent(TextNode *node) +{ + /* + * From now on if there is an example which will take over a line, then + * it will start and end with a newline + */ + + /*int height;*/ + int t_width; + /*int store_x = text_x;*/ + /*int store_y = text_y;*/ + /*int lh = present_line_height;*/ + + gInAxiomCommand = 1; + + push_spad_group(); + + /* Check to see if we should space in front of myself */ + if (gInLine && node->space) + text_x += inter_word_space; + t_width = text_width(node->next, Endspadcommand); + if (gInLine && ((text_x + t_width) > right_margin)) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + node->y = text_y; + spad_node = node; + +} + +static void +compute_spadsrc_extent(TextNode *node) +{ + /* + * From now on if there is an example which will take over a line, then + * it will start and end with a newline + */ + + /*int store_x = text_x;*/ + /*int store_y = text_y;*/ + /*int lh = present_line_height;*/ + + gInAxiomCommand = 1; + + push_spad_group(); + + if (gInLine) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + node->y = text_y; + spad_node = node; + +} + +static void +end_spadcommand_extent(TextNode *node) +{ + int temp; + int height; + int twidth; + int maxx; + /*int y = (gInLine) ? (text_y) : (text_y - past_line_height);*/ + + maxx = max_x(spad_node, Endspadcommand); + twidth = spad_node->width = text_width(spad_node->next, Endspadcommand); + height = spad_node->y; + temp = text_height(spad_node->next, Endspadcommand); + + spad_node->height = temp - height + line_height; + if (text_y > height && gInLine) { + spad_node->y = temp; + spad_node->width = maxx - indent; + start_newline(present_line_height, node); + text_x = indent; + } + else { + spad_node->width = twidth; + spad_node->y = text_y - line_height + spad_node->height; + } + pop_group_stack(); + gInAxiomCommand = 0; + spad_node = NULL; +} + +static void +end_spadsrc_extent(TextNode *node) +{ + int temp; + int height; + int twidth; + int maxx; + int y = (gInLine) ? (text_y) : (text_y - past_line_height); + + maxx = max_x(spad_node, Endspadsrc); + + twidth = spad_node->width = text_width(spad_node->next, Endspadsrc); + height = spad_node->y; + temp = text_height(spad_node->next, Endspadsrc); + spad_node->height = temp - height + line_height; + if (y > height && gInLine) { + spad_node->y = temp; + spad_node->width = maxx - indent; + start_newline(present_line_height, node); + text_x = indent; + } + else { + spad_node->width = twidth; + spad_node->y = text_y - line_height + spad_node->height; + } + pop_group_stack(); + gInAxiomCommand = 0; + spad_node = NULL; +} + +static void +compute_mbox_extent(TextNode *node) +{ + + node->width = text_width(node->next, Endmbox); + if (node->space) + text_x += inter_word_space; + if (text_x + node->width > right_margin) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + node->y = text_y; +} + +static void +compute_box_extent(TextNode *node) +{ + int t_width; + + /* + * First thing we do is see if we need to skip some space in front of the + * word + */ + + if (gInLine && node->space) + text_x += inter_word_space; + + /* Calculate the actual width of the box */ + + t_width = text_width(node->next, Endbox) + 2 * box_width; + + if (text_x + t_width > right_margin) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + text_x = text_x + box_width; + node->y = text_y - 2; + node->width = t_width; + node->height = line_height - 2; + gInLine = 1; +} + +static void +compute_ir_extent(TextNode *node) +{ + int t_width; + + /* + * First thing we do is see if we need to skip some space in front of the + * word + */ + + if (gInLine && node->space) + text_x += inter_word_space; + + /* Calculate the actual width of the box */ + + t_width = node->width; + + if (text_x + t_width > right_margin) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + if (node->height > line_height) { + node->height = present_line_height = plh(node->height + inter_line_space); + node->y = text_y + node->height - normal_text_height; + } + else { + node->y = text_y - line_height + node->height; + } + gInLine = 1; + text_x += node->width; +} + +/* read a bitmap file into memory */ + +static void +compute_image_extent(TextNode *node) +{ + if (text_x + node->width > right_margin) { + start_newline(present_line_height, node); + text_x = indent; + } + node->x = text_x; + if (node->height > line_height) { + present_line_height = plh(node->height + inter_line_space); + node->y = text_y + node->height - line_height; + } + else { + node->y = text_y - line_height + node->height; + } + text_x += node->width; + gInLine = 1; +} + +/* + * compute the coordinates of the entries in a table + */ + +static void +compute_table_extent(TextNode **node) +{ + int num_cols, num_lines; + int max_width = 0, node_width, col_width; + int x, y, num_entries = 0,/* n=0, */ screen_width, table_top; + TextNode *front = *node; + TextNode *tn; + + gInTable = 1; + front->x = text_x; + front->y = text_y; + for (tn = front->next; tn->type != Endtable; num_entries++, tn = tn->next) { + /* Now we need to scan the table group by group */ + node_width = text_width(tn->next, Endtableitem); + if (node_width > max_width) + max_width = node_width; + /* Get to the beginning og the next group */ + for (; tn->type != Endtableitem; tn = tn->next); + } + col_width = max_width + min_inter_column_space; + screen_width = gWindow->width - right_margin_space - indent; + num_cols = screen_width / col_width; + if (num_cols == 0) + num_cols = 1; + num_lines = num_entries / num_cols; + if (num_entries % num_cols != 0) + ++num_lines; + if (gInLine) { + start_newline(present_line_height, *node); + } + table_top = text_y; + num_cols = num_entries / num_lines; + if (num_entries % num_lines != 0) + ++num_cols; + col_width = screen_width / num_cols; + for (tn = front->next, x = 0; x < num_cols; x++) + for (y = 0; y < num_lines && tn->type != Endtable; y++) { + if (num_cols == 1 && y > 0) + text_y += line_height; + else + text_y = table_top + y * line_height; + text_x = indent + x * col_width; + gInLine = 0; + compute_text_extent(tn->next); + for (; tn->type != Endtableitem; tn = tn->next); + tn = tn->next; + } + front->height = num_lines * line_height; + front->width = screen_width; + text_x = indent; + if (num_cols == 1) + text_y += line_height; + else + text_y = table_top + front->height; + *node = tn; + gInLine = 0; +} + +void +compute_title_extent(HyperDocPage *page) +{ + right_margin_space = non_scroll_right_margin_space; + page->title->height = twheight + gWindow->border_width; + page->title->x = gWindow->border_width + 2 * twwidth + (int) gWindow->border_width / 2; + gLineNode = page->title->next; + init_title_extents(page); + text_y = top_margin + line_height; + compute_text_extent(page->title->next); + page->title->height = max(text_height(page->title->next, Endtitle), + twheight); +} + +void +compute_header_extent(HyperDocPage *page) +{ + + /* + * Hopefully we will soon be able to actually compute the needed height + * for the header here + */ + + int ty; /* UNUSED */ + + gExtentRegion = Header; + right_margin_space = non_scroll_right_margin_space; + init_extents(); + ty = text_y = 3 * top_margin + line_height + max(page->title->height, twheight); + gLineNode = page->header->next; + compute_text_extent(page->header->next); + page->header->height = text_height(page->header->next, Endheader); + if (page->header->height) { + page->header->height += 1 / 2 * line_height; + page->top_scroll_margin = (gInLine) ? text_y : text_y - past_line_height; + if (!(page->page_flags & NOLINES)) + page->top_scroll_margin += (int) line_height / 2; + page->top_scroll_margin += gWindow->border_width + 2 * top_margin; + } + else { + page->top_scroll_margin = page->title->height + gWindow->border_width + + 2 * scroll_top_margin; + } +} + +void +compute_footer_extent(HyperDocPage * page) +{ + if (page->footer) { + gExtentRegion = Footer; + right_margin_space = non_scroll_right_margin_space; + init_extents(); + present_line_height = line_height; + text_y = line_height; + gLineNode = page->footer->next; + compute_text_extent(page->footer->next); + page->footer->height = text_height(page->footer->next, Endfooter); + if (page->footer->height) { + if ((!page->page_flags & NOLINES)) + page->footer->height += (int) line_height / 2; + page->bot_scroll_margin = gWindow->height - + page->footer->height - bottom_margin + - gWindow->border_width + top_margin; + } + else + page->bot_scroll_margin = gWindow->height; + } +} + +void +compute_scrolling_extent(HyperDocPage *page) +{ + /* Check to see if there is a scrolling region */ + + if (!page->scrolling) { + return; + } + noop_count = 0; + + /* If there is then compute all the proper locations */ + gExtentRegion = Scrolling; + right_margin_space = non_scroll_right_margin_space + gScrollbarWidth; + init_extents(); + text_y = line_height; + gLineNode = page->scrolling->next; + compute_text_extent(page->scrolling->next); + + /* + * the following is an attempt to fix the bug where one cannot scroll + * down to a bitmap that is opened at the bottom of a page. + */ + + /* + * TTT trial if(!gInLine) + */ + if (0) { + text_y = text_y - past_line_height; + } + else if (present_line_height > line_height) + text_y = text_y + present_line_height - line_height; + page->scrolling->height = text_y; + +} +@ +\section{extent2.c} +<>= +/****************************************************************************** + * + * extent2.h: HyperDoc extent computation routines + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _EXTENT2_C +#include "debug.h" + + +<> +<> +<> + +#include "all-hyper-proto.h1" +#include "pixmap.h1" + + +static int cur_height = 0; +static int max_x_value = 0; + +/* + * start_newline updates the current header node, and also allocates if needed + * memory for the next Line Header. It also assigns the first TextNode on the + * line to the structure, because this is the last time I will be able to do + * this + */ + +void +start_newline(int distance, TextNode * node) +{ + if (gLineNode != NULL) { + if (gTopOfGroupStack->center) + center_nodes(gLineNode, node); + gLineNode = node; + } + text_y += distance; + past_line_height = distance; + present_line_height = line_height; + gInLine = 0; +} + +/* + * center_nodes goes through and centers all the text between the two + * given nodes. + */ + +static void +center_nodes(TextNode * begin_node, TextNode * end_node) +{ + int begin_x, end_x, wmid_x, offset, mid_x; + TextNode *node; + + end_x = text_x; + begin_x = x_value(begin_node); + mid_x = (int) (end_x + begin_x) / 2; + wmid_x = (int) (right_margin + indent) / 2; + + if (mid_x > wmid_x) + offset = 0; + else + offset = wmid_x - mid_x; + + for (node = begin_node; node != end_node; node = node->next) + if (node->x > 0) + node->x += offset; +} + +static int +punctuation_width(TextNode * node) +{ + int twidth, width = strlen(node->data.text); + + twidth = XTextWidth(gTopOfGroupStack->cur_font, node->data.text, width); + + /* check to see if there was some space in front */ + + if (gInLine && (node->space & FRONTSPACE)) + twidth += inter_word_space; + +# if 0 + if (node->space & BACKSPACE) { + switch (node->data.text[0]) { + case '.': + case '?': + case '!': + twidth += term_punct_space; + break; + } + } +#endif + + return twidth; +} + +static int +input_string_width(TextNode * node) +{ + InputItem *item; + int t_width; + + /** search the symbol table for the proper entry **/ + + item = node->link->reference.string; + + /** Once I have gotten this far, I should just be able to calculate + the width using the normal font **/ + + t_width = (item->size + 1) * gInputFont->max_bounds.width + 10; + return t_width; + +} + +static int +word_width(TextNode * node) +{ + int twidth, len = strlen(node->data.text); + + twidth = XTextWidth(gTopOfGroupStack->cur_font, node->data.text, len); + if (node->space & FRONTSPACE) + twidth += inter_word_space; + + return twidth; +} + +static int +verbatim_width(TextNode * node) +{ + int twidth, len = strlen(node->data.text); + + twidth = XTextWidth(gTopOfGroupStack->cur_font, node->data.text, len); + if (node->space) + twidth += inter_word_space; + + return twidth; +} + +static int +width_of_dash(TextNode * node) +{ + int num_dashes, twidth; + + num_dashes = strlen(node->data.text); + if (num_dashes > 1) + twidth = node->width = num_dashes * dash_width; + else + twidth = node->width = XTextWidth(gTopOfGroupStack->cur_font, + node->data.text, 1); + if (node->space) + twidth += inter_word_space; + return twidth; +} + +/* + * return the gWindow->width in pixels of the given text node, when + * displayed + */ + +int +text_width(TextNode * node, int Ender) +{ + int twidth = 0, num_words; + + for (num_words = 0; node != NULL; num_words++, node = node->next) { + if (Ender == Endtokens) { + if (node->type == Endtokens) + return twidth; + } + else if (node->type == Ender) + return twidth; + + switch (node->type) { + case Macro: + case Pound: + if (node->space && gInLine) + twidth += inter_word_space; + break; + case Punctuation: + twidth += punctuation_width(node); + break; + case Dash: + if (gInLine && node->space) + twidth += inter_word_space; + twidth += width_of_dash(node); + break; + case Verbatim: + case Spadsrctxt: + twidth += verbatim_width(node); + break; + case Lsquarebrace: + case Rsquarebrace: + case Word: + twidth += word_width(node); + break; + case Box: + twidth += 2 * box_space; + break; + case Link: + case Downlink: + case Memolink: + case Windowlink: + case LispMemoLink: + case Lispwindowlink: + case Lisplink: + case Unixlink: + case Spadcall: + case Spadcallquit: + case Qspadcall: + case Qspadcallquit: + case LispDownLink: + case Lispcommand: + case Lispcommandquit: + case Spadlink: + case Spaddownlink: + case Spadmemolink: + case Unixcommand: + case Upbutton: + case Returnbutton: + case Description: + push_active_group(); + break; + case Endbutton: + case Endspadcommand: + case Enddescription: + pop_group_stack(); + break; + case Endlink: + pop_group_stack(); + break; + case Inputstring: + twidth += input_string_width(node); + break; + case SimpleBox: + case Radiobox: + twidth += node->width + ((node->space) ? inter_word_space : 0); + break; + case Spadcommand: + case Spadgraph: + push_spad_group(); + break; + case VSpace: + break; + case HSpace: + twidth += + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1); + break; + case Space: + twidth += (gTopOfGroupStack->cur_font->max_bounds.width) * + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1); + break; + case Tab: + twidth = (gTopOfGroupStack->cur_font->max_bounds.width) * + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1); + break; + case Table: + twidth = gWindow->width - left_margin - right_margin_space; + break; + case Tableitem: + case Group: + twidth += (node->space) ? inter_word_space : 0; + push_group_stack(); + break; + case BoldFace: + if (node->space) + twidth += inter_word_space; + bf_top_group(); + break; + case Emphasize: + if (node->space) + twidth += inter_word_space; + if (gTopOfGroupStack->cur_font == gRmFont) + em_top_group(); + else + rm_top_group(); + break; + case It: + if (node->space) + twidth += inter_word_space; + em_top_group(); + break; + case Rm: + case Sl: + case Tt: + if (node->space) + twidth += inter_word_space; + rm_top_group(); + break; + case Endgroup: + pop_group_stack(); + break; + case Controlbitmap: + case Inputbitmap: + if (node->width == -1) + insert_bitmap_file(node); + twidth += node->width; + break; + case Inputpixmap: + if (node->width == -1) + insert_pixmap_file(node); + twidth += node->width; + break; + case Mbox: + case Indent: + case Endmacro: + case Free: + case Bound: + case Beep: + case Item: + case Titem: + case Beginitems: + case Noop: + case Endinputbox: + case Fi: + case Ifcond: + case Endif: + case Begintitems: + case Enditems: + case Endtitems: + case Endtableitem: + case Endtable: + case Endparameter: + case Endbox: + case Endheader: + case Endfooter: + case Endscrolling: + case Endverbatim: + case Endspadsrc: + break; + case Newline: + /* WOw, I guess I should ertunr a really big number */ + twidth += gWindow->width; + break; + default: + + /* + * fprintf(stderr, "Unknown nodetype %d in text_width\n", + * node->type); + */ + break; + } + } + return twidth; +} + +/* + * total_width traces through the nodes, until it finds a blank space. It is + * used by compute_word_extent, and compute_punctuation extent to determine + * How far we go before we actually see white space. + */ + +int +total_width(TextNode * node, int Ender) +{ + int twidth = 0; + + for (; (node != NULL); node = node->next) { + if (Ender == Endtokens) { + if (node->type >= Endtokens) + return twidth; + } + else if (node->type == Ender) + return twidth; + + /* + * The first thing we check for is to see if there was space in front + * of the current node, if so we are done + */ + + if (node->space) + return twidth; + + /*** Else depending on the node type ***/ + + switch (node->type) { + case Noop: + case Endinputbox: + case Pound: + case Ifcond: + case Fi: + case Endif: + break; + case Rsquarebrace: + case Punctuation: + case Word: + case Dash: + twidth += XTextWidth(gTopOfGroupStack->cur_font, node->data.text, + strlen(node->data.text)); + break; + case Box: + case Link: + case Downlink: + case Memolink: + case Windowlink: + case LispMemoLink: + case Lispwindowlink: + case Lisplink: + case Unixlink: + case Spadcall: + case Spadcallquit: + case Qspadcall: + case Qspadcallquit: + case LispDownLink: + case Lispcommand: + case Lispcommandquit: + case Spadlink: + case Spaddownlink: + case Spadmemolink: + case Unixcommand: + case Inputstring: + case SimpleBox: + case Radiobox: + case Upbutton: + case Returnbutton: + case Spadcommand: + case Spadgraph: + case VSpace: + case HSpace: + case Space: + case Table: + case Group: + case Controlbitmap: + case Inputbitmap: + case Inputpixmap: + case Free: + case Beep: + case Bound: + case Lsquarebrace: + case BoldFace: + case Emphasize: + case It: + case Rm: + case Sl: + case Tt: + case Newline: + case Verbatim: + case Spadsrctxt: + return twidth; + default: + break; + } + } + return twidth; +} + +/* + * init_extents initialize some text size variables + */ + +void +init_extents(void) +{ + present_line_height = line_height; + gInLine = 0; + gInItem = 0; + gInAxiomCommand = 0; + item_indent = 0; + gInDesc = 0; + indent = left_margin; + text_x = indent; + gTopOfGroupStack->cur_font = gRmFont; + gTopOfGroupStack->cur_color = gRmColor; + right_margin = gWindow->width - right_margin_space; + clear_item_stack(); +} + +/* + * init_title_extents initialize some title text size variables + */ + +void +init_title_extents(HyperDocPage * page) +{ + present_line_height = line_height; + gInLine = 0; + gInAxiomCommand = 0; + item_indent = 0; + gInDesc = 0; + indent = left_margin + page->title->x; + text_x = indent; + gTopOfGroupStack->cur_font = gRmFont; + gTopOfGroupStack->cur_color = gRmColor; + right_margin = gWindow->width - right_margin_space - gWindow->border_width - + 2 * twwidth; + clear_item_stack(); +} + +/* + * init_text initialize some text size variables + */ + +void +init_text(void) +{ + normal_text_height = gRmFont->ascent + gRmFont->descent; + line_height = gRmFont->ascent + gRmFont->descent + inter_line_space; + word_off_height = line_height - normal_text_height; + space_width = gRmFont->max_bounds.width; +} + +/* + * text_height returns the height of a piece of formatted text in pixels + */ + +int +text_height(TextNode * node, int Ender) +{ + cur_height = 0; + return text_height1(node, Ender); +} + +/* + * text_height1 is the recursive part of text_height + */ + +static int +text_height1(TextNode * node, int Ender) +{ + for (; node != NULL; node = node->next) { + if (Ender == Endtokens) { + if (node->type > -Endtokens) + return cur_height; + } + else if (node->type == Ender) + return cur_height; + switch (node->type) { + case Center: + case Downlink: + case Link: + case Spadcommand: + case Spadgraph: + case Upbutton: + case Returnbutton: + case Windowlink: + case Memolink: + case Lispwindowlink: + case Lisplink: + case Unixlink: + case Spadcall: + case Spadcallquit: + case Qspadcall: + case Qspadcallquit: + case LispDownLink: + case LispMemoLink: + case Lispcommand: + case Lispcommandquit: + case Spadlink: + case Spaddownlink: + case Spadmemolink: + case Unixcommand: + case SimpleBox: + case Radiobox: + case Group: + case Box: + case Controlbitmap: + case Inputbitmap: + case Inputpixmap: + case Horizontalline: + case Punctuation: + case Lsquarebrace: + case Rsquarebrace: + case Word: + case Verbatim: + case Math: + case Spadsrctxt: + case Dash: + case Inputstring: + cur_height = max(node->y, cur_height); + break; + case Mbox: + case Macro: + case Pound: + case Emphasize: + case BoldFace: + case It: + case Rm: + case Sl: + case Tt: + case Endparameter: + case Description: + case Enddescription: + case Noop: + case Fi: + case Ifcond: + case Endif: + case Endinputbox: + case Tab: + case Newline: + case Space: + case VSpace: + case HSpace: + case Beginitems: + case Begintitems: + case Endtitems: + case Titem: + case Enditems: + case Endtable: + case Endtableitem: + case Item: + case Par: + case Beep: + case Free: + case Bound: + case Endgroup: + case Endcenter: + case Endbutton: + case Endmacro: + case Tableitem: + case Endlink: + case Endspadcommand: + case Indent: + case Indentrel: + case Endbox: + case Endmbox: + case Table: + case Endverbatim: + case Endmath: + case Spadsrc: + case Endspadsrc: + break; + case Beginscroll: + case Endscroll: + break; + case Endscrolling: + return cur_height; + default: + + /* + * fprintf(stderr, "Text_height1: Unknown Node Type %d\n", + * node->type); + */ + break; + } + } + return cur_height; +} + +/* + * max_x returns the height of a piece of formatted text in pixels + */ + +int +max_x(TextNode * node, int Ender) +{ + max_x_value = 0; + for (; node != NULL; node = node->next) { + if (Ender == Endtokens) { + if (node->type >= Endtokens) + return max_x_value; + } + else if (node->type == Ender) + return max_x_value; + switch (node->type) { + case Lsquarebrace: + case Rsquarebrace: + case Word: + max_x_value = max(max_x_value, node->x + word_width(node)); + break; + case Verbatim: + case Spadsrctxt: + max_x_value = max(max_x_value, node->x + verbatim_width(node)); + break; + case Punctuation: + max_x_value = max(max_x_value, node->x + punctuation_width(node)); + break; + case Dash: + max_x_value = max(max_x_value, node->x + width_of_dash(node)); + break; + case HSpace: + max_x_value = max(max_x_value, node->x + + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1)); + break; + case Space: + max_x_value = max(max_x_value, node->x + + (gTopOfGroupStack->cur_font->max_bounds.width) * + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1)); + break; + case Group: + push_group_stack(); + break; + case BoldFace: + bf_top_group(); + break; + case Emphasize: + if (gTopOfGroupStack->cur_font == gRmFont) + em_top_group(); + else + rm_top_group(); + break; + case It: + em_top_group(); + break; + case Rm: + case Sl: + case Tt: + rm_top_group(); + break; + case Endgroup: + pop_group_stack(); + break; + case Controlbitmap: + case Inputbitmap: + if (node->width == -1) + insert_bitmap_file(node); + max_x_value = max(max_x_value, node->x + node->width); + break; + case Inputpixmap: + if (node->width == -1) + insert_pixmap_file(node); + max_x_value = max(max_x_value, node->y + node->width); + break; + default: + break; + } + } + return cur_height; +} + +static int +x_value(TextNode * node) +{ + for (; node != NULL; node = node->next) { + switch (node->type) { + case Controlbitmap: + case Inputbitmap: + case Inputpixmap: + case Lsquarebrace: + case Rsquarebrace: + case Word: + case Verbatim: + case Spadsrctxt: + case Dash: + case Punctuation: + case VSpace: + case HSpace: + case Horizontalline: + case Box: + case Downlink: + case Link: + case Lispwindowlink: + case Lisplink: + case Unixlink: + case Spadcall: + case Spadcallquit: + case Qspadcall: + case Qspadcallquit: + case LispDownLink: + case LispMemoLink: + case Lispcommand: + case Lispcommandquit: + case Spadlink: + case Spaddownlink: + case Spadmemolink: + case Spadcommand: + case Spadgraph: + case Unixcommand: + case Space: + case SimpleBox: + case Radiobox: + return node->x; + default: +#ifdef DEBUG + fprintf(stderr, "X_value did not know x value of type %d\n", node->type); +#endif + return x_value(node->next); + } + } + return 0; +} + +/* + * trailing_space computes the length of the trailing spaces of a node + */ + +int +trailing_space(TextNode * node) +{ + int space = 0; + + for (; node->type < Endtokens; node = node->next); + if (node->type == Space) + space += inter_word_space * + (node->data.node != NULL ? atoi(node->data.node->data.text) : 1); + return space; +} + +/* + * insert_bitmap_file reads a bitmap file into memory + */ + +void +insert_bitmap_file(TextNode * node) +{ + char *filename = node->data.text; + int bm_width, bm_height; + XImage *im; + ImageStruct *image; + + if (*filename == ' ') + filename++; + if (node->image.pm == 0) { + if ( + ((image = (ImageStruct *) hash_find(&gImageHashTable, filename)) == NULL) + || (getenv("HTCACHE"))) { + + /* + * read the bitmap if not already in memory or if the environment + * variable HTCACHE is set (NAG addition). + */ + + im = HTReadBitmapFile(gXDisplay, gXScreenNumber, filename, + &bm_width, &bm_height); + + /** now add the image to the gImageHashTable **/ + image = (ImageStruct *) halloc(sizeof(ImageStruct), "ImageStruct"); + image->image.xi = im; + image->width = image->image.xi->width; + image->height = image->image.xi->height; + image->filename = (char *) halloc(sizeof(char) * strlen(filename) +1,"Image Filename"); + /* strcpy(image->filename, filename); */ + sprintf(image->filename, "%s", filename); + hash_insert(&gImageHashTable, (char *)image, image->filename); + } + node->width = image->width; + node->height = image->height; + node->image.xi = image->image.xi; + } +} + +/* + * insert_pixmap_file reads a pixmap file into memory + */ + +void +insert_pixmap_file(TextNode * node) +{ + char *filename = node->data.text; + int bm_width, bm_height, ret_val; + XImage *xi; + ImageStruct *image; + + if (*filename == ' ') + filename++; + if (node->image.xi == 0) { + if ((image = (ImageStruct *) hash_find(&gImageHashTable, filename)) == NULL) { + ret_val = read_pixmap_file(gXDisplay, gXScreenNumber, filename, &xi, + &bm_width, &bm_height); + switch (ret_val) { + case(-1): + gSwitch_to_mono = 1; + return; + case BitmapFileInvalid: + fprintf(stderr, "File %s contains invalid bitmap data\n", filename); + return; + case BitmapOpenFailed: + fprintf(stderr, "couldn't open bitmap file %s\n", filename); + return; + case BitmapNoMemory: + fprintf(stderr, "not enough memory to store bitmap\n"); + return; + } + image = (ImageStruct *) halloc(sizeof(ImageStruct), "ImageStruct"); + image->width = bm_width; + image->height = bm_height; + image->filename = (char *) halloc(sizeof(char) * strlen(filename) +1, + "insert_pixmap--filename"); + /* strcpy(image->filename, filename); */ + sprintf(image->filename, "%s", filename); + image->image.xi = xi; + hash_insert(&gImageHashTable, (char *)image, image->filename); + } + node->width = image->width; + node->height = plh(image->height + inter_line_space); + node->image.xi = image->image.xi; + } +} + +/* + * plh calculates the closet value of line_height > height + */ + +int +plh(int height) +{ + int rheight = height; + + if (gExtentRegion == Scrolling) { + for (rheight = line_height; rheight < height; rheight += line_height) + ; + } + return rheight; +} +@ +\section{extent.h} +<>= +#ifndef _EXTENT_H_ +#define _EXTENT_H_ 1 + +<> + +/* + * This file contains global macros extern declarations for the extent + * computation routines found in extent1.c and extent2.c. + */ + +/* + * Definitions of standard text formatting dimensions, etc. + * dimensions given in pixels + */ + +#define left_margin 20 +#define non_scroll_right_margin_space 20 +#define scroll_right_margin_space 40 +#define bottom_margin 15 +#define top_margin 5 +#define scroll_top_margin top_margin +#define scrollingTopMargin 5 +#define inter_line_space 5 +#define inter_word_space 5 +#define term_punct_space 5 +#define paragraph_space 30 +#define box_space 3 +#define horiz_line_space 3 +#define spadcom_indent 30 +#define min_inter_column_space 10 +#define box_width 3 +#define dash_width 5 +#define dash_y 4 + + +/* next two from display.h. Reorg! */ + +extern short int gDisplayRegion; +extern int gRegionOffset; + +#define not_in_scroll (!(gDisplayRegion == Scrolling)) + +#define visible(y, h) \ + (not_in_scroll || ((y) + gRegionOffset + gWindow->page->scroll_off \ + <= gWindow->scrollheight && \ + (y) + gRegionOffset + gWindow->page->scroll_off - (h) >= 0)) + +#define pix_visible(y, h) \ + (not_in_scroll || ((y) + gRegionOffset + gWindow->page->scroll_off - h + \ + line_height < gWindow->page->bot_scroll_margin \ + - gWindow->page->top_scroll_margin && \ + (y) + gRegionOffset + gWindow->page->scroll_off >= 0)) + +#define above(y) ((y) + gWindow->page->scroll_off < gWindow->page->top_scroll_margin) +#define below(y) ((y) + gWindow->page->scroll_off >= gWindow->page->bot_scroll_margin) + + +/* Variables for the formatting state */ + +extern int right_margin_space; +extern int right_margin; +extern int indent; +extern int item_indent; +extern int text_x; +extern int text_y; +extern int y_off; +extern int scroll_bot; +extern int need_scroll_up_button; +extern int need_scroll_down_button; +extern int item_space; +extern int present_line_height; +extern int past_line_height; +extern int line_height; /* space between lines */ +extern int normal_text_height; /* space between lines */ +extern int space_width; /* the maximum width of a character */ +extern int word_off_height; /* the diff between text height and */ + + +/* + * externs from extent1.c + */ + +extern short int gExtentRegion; + +extern short int gInAxiomCommand; /* true iff we are in a \spadcommand */ +extern short int gInDesc; +extern short int gInItem; /* true iff we are in a \item */ +extern short int gInLine; /* true iff there have been words printed */ +extern short int gInTable; + +extern TextNode *gLineNode; + +#endif +@ +\section{form\_ext.c} +<>= +#define _FORM_EXT_C +#include "debug.h" + +<> +<> +<> + +#include "all-hyper-proto.h1" + + + +/* + * A few routines used to help with form extents + */ + +void +compute_form_page(HyperDocPage *page) +{ + + /* + * To solve the problem of improperly nested \em, I will have to keep and + * always initialize the top of the stack + */ + while (pop_group_stack() >= 0); + + /* + * The compute the text extents + */ + form_header_extent(page); + form_footer_extent(page); + form_scrolling_extent(page); + gWindow->height = window_height(gWindow->page); + +} + +/* + * A simple function that returns the width needed to store show the number + * of columns given + */ +int +window_width(int cols) +{ + return (left_margin + cols * space_width + non_scroll_right_margin_space); +} + + +static int +window_height(HyperDocPage *page) +{ + int temp; + + temp = page->header->height + top_margin + bottom_margin; + + if (page->scrolling) + temp += page->scrolling->height + page->footer->height; + + return (temp); +} + + +static void +form_header_extent(HyperDocPage *page) +{ + + /* + * Hopefully I will soon be able to actually compute the needed height + * for the header here + */ + gExtentRegion = Header; + right_margin_space = non_scroll_right_margin_space; + init_extents(); + text_y = top_margin + line_height; + compute_text_extent(page->header->next); + page->header->height = (gInLine) ? text_y : text_y - past_line_height; + if (!(page->page_flags & NOLINES)) + page->header->height += (int) line_height / 2; + page->header->height += gWindow->border_width; +} + +static void +form_footer_extent(HyperDocPage *page) +{ + if (page->footer) { + gExtentRegion = Footer; + right_margin_space = non_scroll_right_margin_space; + init_extents(); + + compute_text_extent(page->footer->next); + + /* + * I inserted the 2nd arg to text_height below because it + * was missing. Perhaps there is a better value for it. + */ + + page->footer->height = text_height(page->footer->next, + page->footer->next->type); + if ((!page->page_flags & NOLINES)) + page->footer->height += (int) line_height / 2; + } +} + +static void +form_scrolling_extent(HyperDocPage *page) +{ + + /* + * Check to see if there is a scrolling region + */ + + if (page->scrolling) { + /* + * If there is then compute all the proper locations + */ + + gExtentRegion = Scrolling; + right_margin_space = non_scroll_right_margin_space + gScrollbarWidth; + init_extents(); + text_y = line_height; + compute_text_extent(page->scrolling->next); + if (!gInLine) + text_y = text_y - past_line_height; + else if (present_line_height > line_height) + text_y = text_y + present_line_height - line_height; + page->scrolling->height = text_y; + } +} + + + +@ +\section{group.h} +<>= +#ifndef _GROUP_H_ +#define _GROUP_H_ 1 + +<> + +extern GroupItem *gTopOfGroupStack; + +#endif +@ +\section{group.c} +<>= +/****************************************************************************** + * + * group.c: Routines for managing the HyperDoc group stack. + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _GROUP_C +#include "debug.h" + + +<> +<> + +#include "all-hyper-proto.h1" + +GroupItem *gTopOfGroupStack = NULL; + + + +int +pop_group_stack(void) +{ + /* This routine pops the top of the current group stack */ + GroupItem *junk; + + /* + * If the the stack has only a single item, then pop it anyway so the + * user can see the problem + */ + if (! gTopOfGroupStack->next) + return -1; + + /* Else, Pop the thing */ + + junk = gTopOfGroupStack; + gTopOfGroupStack = gTopOfGroupStack->next; + junk->next = NULL; + + free(junk); + + /* Now change the font to the cur_font and the cur_color */ + + change_text(gTopOfGroupStack->cur_color, gTopOfGroupStack->cur_font); + return 1; + +} + +void +push_group_stack(void) +{ + /* + * This routine makes room by pushing a new item on the stack + */ + GroupItem *newgp; + + newgp = (GroupItem *) halloc(sizeof(GroupItem), "Push Group Stack"); + newgp->cur_font = gTopOfGroupStack->cur_font; + newgp->cur_color = gTopOfGroupStack->cur_color; + newgp->center = gTopOfGroupStack->center; + newgp->next = gTopOfGroupStack; + + gTopOfGroupStack = newgp; +} + +void +init_group_stack(void) +{ + gTopOfGroupStack = (GroupItem *) halloc(sizeof(GroupItem), "Push Group Stack"); + gTopOfGroupStack->center = 0; + gTopOfGroupStack->next = NULL; + gTopOfGroupStack->cur_color = 0; + gTopOfGroupStack->cur_font = NULL; +} + +void +em_top_group(void) +{ + if (! gTopOfGroupStack->next) + push_group_stack(); + gTopOfGroupStack->cur_color = gEmColor; + gTopOfGroupStack->cur_font = gEmFont; + change_text(gTopOfGroupStack->cur_color, gTopOfGroupStack->cur_font); +} + +void +rm_top_group(void) +{ + if (! gTopOfGroupStack->next) + push_group_stack(); + gTopOfGroupStack->cur_color = gRmColor; + gTopOfGroupStack->cur_font = gRmFont; + change_text(gTopOfGroupStack->cur_color, gTopOfGroupStack->cur_font); + +} + +void +line_top_group(void) +{ + if (! gTopOfGroupStack->next) + push_group_stack(); + gTopOfGroupStack->cur_color = gBorderColor; + gTopOfGroupStack->cur_font = gRmFont; + change_text(gTopOfGroupStack->cur_color, gTopOfGroupStack->cur_font); + +} + +void +bf_top_group(void) +{ + /* + * Just in case the person is tryin a \em without a grouping + */ + + if (! gTopOfGroupStack->next) + push_group_stack(); + gTopOfGroupStack->cur_color = gBfColor; + gTopOfGroupStack->cur_font = gBfFont; + change_text(gTopOfGroupStack->cur_color, gTopOfGroupStack->cur_font); +} + +void +tt_top_group(void) +{ + if (! gTopOfGroupStack->next) + push_group_stack(); + gTopOfGroupStack->cur_color = gTtColor; + gTopOfGroupStack->cur_font = gTtFont; + change_text(gTopOfGroupStack->cur_color, gTopOfGroupStack->cur_font); +} + +void +push_active_group(void) +{ + push_group_stack(); + gTopOfGroupStack->cur_font = gActiveFont; + gTopOfGroupStack->cur_color = gActiveColor; + change_text(gTopOfGroupStack->cur_color, gTopOfGroupStack->cur_font); +} + +void +push_spad_group(void) +{ + push_group_stack(); + gTopOfGroupStack->cur_font = gAxiomFont; + gTopOfGroupStack->cur_color = gAxiomColor; + change_text(gTopOfGroupStack->cur_color, gTopOfGroupStack->cur_font); +} + +void +init_top_group(void) +{ + /* clear the group stack */ + while (pop_group_stack() >= 0) + ; + + /* then set the colors to be normal */ + + gTopOfGroupStack->cur_color = gRmColor; + gTopOfGroupStack->cur_font = gRmFont; + change_text(gTopOfGroupStack->cur_color, gTopOfGroupStack->cur_font); +} + +void +center_top_group(void) +{ + push_group_stack(); + gTopOfGroupStack->center = 1; +} + +GroupItem * +copy_group_stack(void) +{ + GroupItem *newgp = NULL; + GroupItem *first = NULL; + GroupItem *prev = NULL; + GroupItem *trace = gTopOfGroupStack; + + while (trace) { + newgp = (GroupItem *) halloc(sizeof(GroupItem), "Copy Group Stack"); + newgp->cur_font = trace->cur_font; + newgp->cur_color = trace->cur_color; + newgp->center = trace->center; + if (!first) + first = newgp; + else + prev->next = newgp; + prev = newgp; + trace = trace->next; + } + if (newgp) + newgp->next = NULL; + return first; +} + +void +free_group_stack(GroupItem *g) +{ + GroupItem *trace = g; + + while (trace) { + GroupItem *junk = trace; + trace = trace->next; + free(junk); + } +} +@ +\section{halloc.c} +<>= +#define _HALLOC_C +#include "debug.h" +#include +#include +#if !defined(BSDplatform) +#include +#endif + +FILE *fp; + +#include "halloc.h1" + +/* allocate memory and bomb if none left (HyperDoc alloc) */ + +char * +halloc(int bytes, char *msg) +{ + static char buf[200]; + char *result; + +#ifdef DEBUG + static int first = 1; + + if (first) { + fp = fopen("/tmp/hallocs", "w"); + first = 0; + } +#endif + result = (char *) malloc(bytes); +#ifdef DEBUG + fprintf(fp, "%d\tAlocating %d Bytes for %s\n", result,bytes, msg); +#endif + if (result == NULL) { + sprintf(buf, "Ran out of memory allocating %s.\b", msg); + fprintf(stderr, "%s\n", buf); + exit(-1); + } + return result; +} +@ +\section{hash.c} +<>= +#define _HASH_C +#include "debug.h" + +#include +#include +#include +#include "hash.h" + +#include "hash.h1" +#include "halloc.h1" + +/* initialize a hash table */ + +void +hash_init(HashTable *table, int size, EqualFunction equal, + HashcodeFunction hash_code) +{ + int i; + + table->table = + (HashEntry **) halloc(size * sizeof(HashEntry *), "HashEntry"); + for (i = 0; i < size; i++) + table->table[i] = NULL; + table->size = size; + table->equal = equal; + table->hash_code = hash_code; + table->num_entries = 0; +} + +void +free_hash(HashTable *table, FreeFunction free_fun) +{ + if (table) { + int i; + + for (i = 0; i < table->size; i++) { + HashEntry *e, *next; + + for (e = table->table[i]; e != NULL;) { + next = e->next; + (*free_fun) (e->data); + (*e).data=0; + free(e); + e = next; + } + } + free(table->table); + } +} + +/* insert an entry into a hash table */ + +void +hash_insert(HashTable *table, char *data, char *key) +{ + HashEntry *entry = (HashEntry *) halloc(sizeof(HashEntry), "HashEntry"); + int code; + + entry->data = data; + entry->key = key; + code = (*table->hash_code) (key, table->size) % table->size; +#ifdef DEBUG + fprintf(stderr, "Hash value = %d\n", code); +#endif + entry->next = table->table[code]; + table->table[code] = entry; + table->num_entries++; +} + +char * +hash_find(HashTable *table, char *key) +{ + HashEntry *entry; + int code = table->hash_code(key, table->size) % table->size; + + for (entry = table->table[code]; entry != NULL; entry = entry->next) + if ((*table->equal) (entry->key, key)) + return entry->data; + return NULL; +} + +char * +hash_replace(HashTable *table, char *data, char *key) +{ + HashEntry *entry; + int code = table->hash_code(key, table->size) % table->size; + + for (entry = table->table[code]; entry != NULL; entry = entry->next) + if ((*table->equal) (entry->key, key)) { + entry->data = data; + return entry->data; + } + return NULL; +} + +void +hash_delete(HashTable *table, char *key) +{ + HashEntry **entry; + int code = table->hash_code(key, table->size) % table->size; + + for (entry = &table->table[code]; *entry != NULL; entry = &((*entry)->next)) + if ((*table->equal) ((*entry)->key, key)) { + *entry = (*entry)->next; + table->num_entries--; + return; + } +} + +void +hash_map(HashTable *table, MappableFunction func) +{ + int i; + HashEntry *e; + + if (table == NULL) + return; + for (i = 0; i < table->size; i++) + for (e = table->table[i]; e != NULL; e = e->next) + (*func) (e->data); +} + +HashEntry * +hash_copy_entry(HashEntry *e) +{ + HashEntry *ne; + + if (e == NULL) + return e; + ne = (HashEntry *) halloc(sizeof(HashEntry), "HashEntry"); + ne->data = e->data; + ne->key = e->key; + ne->next = hash_copy_entry(e->next); + return ne; +} + +/* copy a hash table */ +HashTable * +hash_copy_table(HashTable *table) +{ + HashTable *nt = (HashTable *) halloc(sizeof(HashTable), "copy hash table"); + int i; + + nt->size = table->size; + nt->num_entries = table->num_entries; + nt->equal = table->equal; + nt->hash_code = table->hash_code; + nt->table = (HashEntry **) halloc(nt->size * sizeof(HashEntry *), + "copy table"); + for (i = 0; i < table->size; i++) + nt->table[i] = hash_copy_entry(table->table[i]); + return nt; +} + +/* hash code function for strings */ +int +string_hash(char *s, int size) +{ + int c = 0; + char *p =s; + + + while (*p) + c += *p++; + return c % size; +} + +/* test strings for equality */ + +int +string_equal(char *s1, char *s2) +{ + return (strcmp(s1, s2) == 0); +} + +/* make a fresh copy of the given string */ +char * +alloc_string(char *str) +{ + char * result; + result = halloc(strlen(str)+1,"String"); + strcpy(result,str); + return (result); +} +@ +\section{htadd.c} +The [[htadd]] function can manipulate the database of hypertex pages. +To rebuild the hypertex database changes to the [[$AXIOM/doc/hypertex]] +subdirectory and type: +\begin{verbatim} +htadd -f pages -n pages/* +\end{verbatim} +This will create a file called [[pages/ht.db]] which contains entries +similar to: +\begin{verbatim} + algebra.ht 1102052108 +\page AlgebraPage 216 9 +\page NumberTheoryPage 763 28 + ALIST.ht 1102052108 +\newcommand AssociationListXmpTitle 140 3 +\newcommand AssociationListXmpNumber 195 4 +\page AssociationListXmpPage 313 7 + ALIST.pht 1102052108 +\patch AssociationListXmpPagePatch1 0 1 +\patch AssociationListXmpPageEmpty1 447 11 +... +\end{verbatim} +<>= +/* HyperDoc database file manager */ + + +#define _HTADD_C +<> +#include +#include +#include + +<> + +#include "htadd.h1" +#include "addfile.h1" +#include "halloc.h1" +#include "hash.h1" +#include "hterror.h1" +#include "lex.h1" + + + + +/* + * These are variables that htadd needs to have declared because it shares + * the lexical analyzer with HyperDoc + */ + +int gTtFontIs850=0; +HDWindow *gWindow = NULL; +extern int line_number; /* keeps track of which line a page starts on + * in a file. This way someone can start + * including a line number counter into + * HyperDoc. */ +/* for compatibility with HyperDoc */ +Sock *spad_socket = NULL; +Sock *session_server = NULL; +int MenuServerOpened; +Display *gXDisplay; +int gXScreenNumber; +int fresh = 0; + +#define Delete 1 +#define System 2 +#define Current 4 +#define Named 8 + +#define usage "usage: htadd [-s|-l|-f db-directory] [-d|-n] filenames" + + +int +main(int argc, char **argv) +{ + /*int i;*/ + char db_dir[256]; /* the directory where the db file is */ + char dbfilename[256]; /* the database filename */ + char *filenames[1000]; /* the files to be added */ + char **fnames = filenames; + short flag; /* flag for deleting or adding */ + + parse_args(argv, db_dir, filenames, &flag); + + if (!filenames[0]) { + fprintf(stderr, "%s\n", usage); + return -1; + } + + parser_init(); + + build_db_filename(flag, db_dir, dbfilename); + + if (fresh) + unlink(dbfilename); + + if (flag & Delete) + while (*fnames) + delete_file(dbfilename, *fnames++); + else + while (*fnames) + add_file(dbfilename, *fnames++, fresh); + return 0; +} + +/* + * This routine parses the command line arguments. It parses + * the command line arguments. It returns a flag which tells the calling + * routine what database file to use, and whether or not to delete files. + */ + + +static void +parse_args(char **argv, char *db_dir, char **filenames, short *fl) +{ + *fl = 0; + + while (*++argv) { + if (!strcmp(*argv, "-d")) + *fl |= Delete; + else if (!strcmp(*argv, "-s")) { + if (*fl & Current || *fl & Named) { + fprintf(stderr, "%s\n", usage); + exit(-1); + } + *fl |= System; + } + else if (!strcmp(*argv, "-n")) { + fresh = 1; + } + else if (!strcmp(*argv, "-l")) { + if (*fl & System || *fl & Named) { + fprintf(stderr, "%s\n", usage); + exit(-1); + } + *fl |= Current; + } + else if (!strcmp(*argv, "-f")) { + if (*fl & System || *fl & Current) { + fprintf(stderr, "%s\n", usage); + exit(-1); + } + *fl |= Named; + strcpy(db_dir, *++argv); + } + else + *filenames++ = *argv; + } + + *filenames = NULL; +} + + + +static int +writable(struct stat buff) +{ +#ifdef DEBUG + unsigned short uid = geteuid(), gid = getegid(); + + fprintf(stderr, "Uid = %d and Gid = %d\n", uid, gid); +#endif + + /* + * Checks the status structure sent against the user id, and goup id + */ + if ((buff.st_uid == geteuid()) && (buff.st_mode & S_IWUSR)) + return 1; + else if ((buff.st_gid == getegid()) && (buff.st_mode & S_IWGRP)) + return 1; + else if ((buff.st_mode & S_IWOTH)) + return 1; + return 0; +} + +/* check to see if the user has permission */ + +/* + * This procedure builds the db filename. Subsequently, it is passed onto all + * the add files that are called. + */ + + +static int +build_db_filename(short flag, char *db_dir, char *dbfilename) +{ + int ret_status; + struct stat buff; + char *SPAD; + char path[256]; + + + if (flag & System) { + SPAD = (char *) getenv("AXIOM"); + if (SPAD == NULL) { + fprintf(stderr, + "Build_db_filename: Defaulting on $AXIOM\n"); + SPAD = (char *) def_spad; + } + sprintf(dbfilename, "%s/doc/hypertex/pages/%s", SPAD, db_file_name); + sprintf(path, "%s/doc/hypertex/pages", SPAD); + } + else if (flag & Named) { + sprintf(dbfilename, "%s/%s", db_dir, db_file_name); + strcpy(path, db_dir); + } + else { /* use the current directory */ + sprintf(dbfilename, "./%s", db_file_name); + sprintf(path, "./"); + } +/* fprintf(stderr,"htadd:build_db_filename:dbfilename=%s\n",dbfilename);*/ + /* Now see if I can write to the file */ + ret_status = stat(dbfilename, &buff); + if (ret_status == -1) { + if (errno == ENOENT) { + /* If the file does not exist, then check it's path */ + ret_status = stat(path, &buff); + } + if (ret_status == -1) { + perror("build_db_file"); + exit(-1); + } + } + + /* check the status */ + + if (writable(buff)) + return 1; + + fprintf(stderr, "build_db_filename: Database file name is not writable\n"); + exit(-1); + return 0; +} + + +/*** + + This procedure now works as follows: + (1) It adds the files to the db_file without full pathnames. + Two names are going to be used when adding a file - + addname <-- The name without any paths + fullname <-- The name with a path prepended to it + (2) If the user specifies a pathname, then it is the path name that + is used. If the user does not dpecify a path name, then possible + paths are found as follows: + (i) If the user has an environment variable HTPATH set, the + paths mentioned are used. + (ii) If not, then the $AXIOM environment variable is used. +****/ + +static void +add_file(char *dbname, char *name, int fresh) +{ + char fullname[256]; + char temp_db_file[256]; + FILE *db_fp = NULL; + FILE *temp_db_fp = NULL; + FILE *ht_fp = NULL; + char addname[100]; + /*char *HTPATH;*/ + /*char *trace;*/ + /*char *spad;*/ + + + /** First thing I should do is find the proper file and open it **/ + ht_fp = ht_file_open(fullname, addname, name); + + /* + * Now I should try to open the two database files. The one to work with, + * and the temporary one; Send it a 1 so it checks for write access + */ + if (fresh) { + if ((db_fp = fopen(dbname, "a")) == NULL) { + fprintf(stderr, "Can't open database: %s file for appending\n", dbname); + exit(-1); + } + } + else { + if ((db_fp = fopen(dbname, "r")) == NULL) { + } + } + if (!fresh) + temp_db_fp = temp_file_open(temp_db_file); + + /** Now actually update the file by adding the changes ***/ + update_db(db_fp, temp_db_fp, ht_fp, addname, fullname, fresh); + + if (!fresh) + fclose(temp_db_fp); + fclose(ht_fp); + if (db_fp != NULL) + fclose(db_fp); + if (!fresh) { + copy_file(temp_db_file, dbname); + unlink(temp_db_file); + } +} + +static void +update_db(FILE *db, FILE *temp_db, FILE *new_file, + char *addname, char *fullname, int fresh) +{ + char *fname; + int c, file_there = 0, mtime; + + if (fresh) { + add_new_pages(db, new_file, addname, fullname); + return; + } + if (db == NULL) { + add_new_pages(temp_db, new_file, addname, fullname); + return; + } + init_scanner(); + cfile = db; + c = get_char(); + do { + if (c == '\t') { + get_filename(); + fname = alloc_string(token.id); + get_token(); + mtime = atoi(token.id); + if (strcmp(fname, addname) == 0) { + save_scanner_state(); + add_new_pages(temp_db, new_file, addname, fullname); + restore_scanner_state(); + file_there = 1; + while ((c = get_char()) != EOF) { + if (c == '\t') + break; + } + } + else { + fprintf(temp_db, "\t%s %d", fname, mtime); + while ((c = get_char()) != EOF) { + if (c == '\t') + break; + putc(c, temp_db); + } + } + free(fname); + } + else + c = get_char(); + } while (c != EOF); + if (!file_there) { + add_new_pages(temp_db, new_file, addname, fullname); + } +} + +#define Special(t) (( t == Page || t == NewCommand || t == Patch )?(1):(0)) +#define ptype(c, t) (strcpy(c, t)); + +static void +add_new_pages(FILE *temp_db, FILE *new_file, char *addname, char *fullname) +{ + char type[15]; + int pos; + int present_type; + int pages = 0; + struct stat fstats; + + stat(fullname, &fstats); + fprintf(temp_db, "\t%s %d\n", addname, (int)fstats.st_mtime); + cfile = new_file; + init_scanner(); + while (get_token() != EOF) { + if (Special(token.type)) { + ptype(type, token.id); + present_type = token.type; + pos = keyword_fpos; + get_token(); + if (token.type != Lbrace) { + fprintf(stderr, "missing left brace after a page, macro or patch \ + declaration\n"); + fprintf(stderr, "In the file %s on line %d\n", fullname, line_number); + exit(-1); + } + get_token(); + if (present_type == Page && token.type != Word) { + fprintf(stderr, "missing page name after \\begin{page}\n"); + fprintf(stderr, "In the file %s on line %d\n", fullname, line_number); + exit(-1); + } + else if (present_type == Macro && token.type != Macro) { + fprintf(stderr, "Expected a \\macro name after newcommand, got %s\n", + token.id); + fprintf(stderr, "In the file %s on line %d\n", fullname, line_number); + exit(-1); + } + else if (present_type == Patch && token.type != Word) { + fprintf(stderr, "Missing patch name after a \\begin{patch}\n"); + fprintf(stderr, "In the file %s on line %d\n", fullname, line_number); + exit(-1); + } + fprintf(temp_db, "\\%s %s %d %d\n", type, + token.id, pos, line_number); + pages++; + } + } + printf("Added %3d pages and/or macros from %s\n", pages, addname); +} + +static void +copy_file(char *f1, char *f2) +{ + FILE *fp1, *fp2; + int c; + + fp1 = fopen(f1, "r"); + fp2 = fopen(f2, "w"); + while ((c = getc(fp1)) != EOF) { + putc(c, fp2); + } + fclose(fp2); + fclose(fp1); +} + + + +#define whitespace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define delim(c) \ + (whitespace(c) ) + + +static void +get_filename(void) +{ + int c, ws; + static char buffer[256]; + char *buf = buffer; + + do { + keyword_fpos = fpos; + c = get_char(); + ws = whitespace(c); + } while (ws); + switch (c) { + case EOF: + fprintf(stderr, "Error trying to read ht.db, unexpected EOF\n"); + exit(-1); + case '%': + case '\\': + case '{': + case '}': + fprintf(stderr, "Error unexpexted character %c\n",c); + exit(-1); + default: + do { + *buf++ = c; + } while ((c = get_char()) != EOF && !delim(c)); + unget_char(c); + *buf = '\0'; + token.type = Word; + token.id = buffer; + break; + } +} + +static int +delete_file(char *dbname, char *name) +{ + char temp_db_file[256]; + FILE *db_fp, *temp_db_fp; + char dname[256]; + + + strcpy(dname, name); + extend_ht(dname); + + /* Open both the tmp database and the real one */ + if ((db_fp = fopen(dbname, "r")) == NULL) { + fprintf(stderr, "database file is empty, nothing to delete\n"); + return 1; + } + + temp_db_fp = temp_file_open(temp_db_file); + + /** Now actually update the file by deleting the pages */ + delete_db(db_fp, temp_db_fp, dname); + + fclose(temp_db_fp); + if (db_fp != NULL) + fclose(db_fp); + copy_file(temp_db_file, dbname); + unlink(temp_db_file); + return 0; +} + +static void +delete_db(FILE *db, FILE *temp_db, char *name) +{ + char *fname; + int c/*, file_there = 0*/, mtime; + + init_scanner(); + cfile = db; + c = get_char(); + do { + if (c == '\t') { + get_filename(); + fname = alloc_string(token.id); + get_token(); + mtime = atoi(token.id); + if (strcmp(fname, name) == 0) { + while ((c = get_char()) != EOF) { + if (c == '\t') + break; + } + } + else { + fprintf(temp_db, "\t%s %d", fname, mtime); + while ((c = get_char()) != EOF) { + if (c == '\t') + break; + putc(c, temp_db); + } + } + free(fname); + } + else + c = get_char(); + } while (c != EOF); +} +@ +\section{hterror.h} +<>= +#define HTCONDNODE 1 /* unrecognized condition node */ +#define KEYTYPE 2 /* unrecognized keyword found in lex.c */ +#define Numerrors 2 + +#ifdef HTERROR +char *errmess[] = { + "place holder", + "parsing condition node", + "unrecognized keyword" }; +#endif +@ +\section{hterror.c} +<>= +#define _HTERROR_C +#define HTERROR + +#include "debug.h" + +<> +<> + +#include "all-hyper-proto.h1" + +char ebuffer[128]; +jmp_buf jmpbuf; + +/* + * This file is the error handling routine in AXIOM. The main routine is + * called htperror(): arguments: msg - like perror it accepts an error + * message to be printed errno - the errno which occurred. This is so an + * appropriate error message can be printed. + * + * The prints out the page name, and then the filename in which the error + * occurred. If possible it also tries to print out the next ten tokens. + */ + +void +jump(void) +{ + if (gWindow == NULL) + exit(-1); + longjmp(jmpbuf, 1); + fprintf(stderr, "(HyperDoc) Long Jump failed, Exiting\n"); + exit(-1); +} + +void +print_page_and_filename(void) +{ + char obuff[128]; + + if (gPageBeingParsed->type == Normal) { + + /* + * Now try to inform the user as close to possible where the error + * occurred + */ + sprintf(obuff, "(HyperDoc) While parsing %s on line %d\n\tin the file %s\n", + gPageBeingParsed->name, line_number, + gPageBeingParsed->filename); + } + else if (gPageBeingParsed->type == SpadGen) { + sprintf(obuff, "While parsing %s from the Spad socket\n", + gPageBeingParsed->name); + } + else if (gPageBeingParsed->type == Unixfd) { + sprintf(obuff, "While parsing %s from a Unixpipe\n", + gPageBeingParsed->name); + } + else { + /* Unknown page type */ + sprintf(obuff, "While parsing %s\n", gPageBeingParsed->name); + } + fprintf(stderr, "%s", obuff); +} + + +void +print_next_ten_tokens(void) +{ + int i; + int v; + + fprintf(stderr, "Trying to print the next ten tokens\n"); + for (i = 0; i < 10; i++) { + v = get_token(); + if (v == EOF) + break; + print_token(); + } + fprintf(stderr, "\n"); +} + +/* print out a token value */ +void +print_token(void) +{ + if (token.type == Word) + printf("%s ", token.id); + else { + token_name(token.type); + printf("\\%s ", ebuffer); + } + fflush(stdout); +} + + +void +token_name(int type) +{ + if (type <= NumberUserTokens) + strcpy(ebuffer, token_table[type]); + else { + switch (type) { + case Lbrace: + strcpy(ebuffer, "{"); + break; + case Rbrace: + strcpy(ebuffer, "}"); + break; + case Macro: + strcpy(ebuffer, token.id); + break; + case Group: + strcpy(ebuffer, "{"); + break; + case Pound: + strcpy(ebuffer, "#"); + break; + case Lsquarebrace: + strcpy(ebuffer, "["); + break; + case Rsquarebrace: + strcpy(ebuffer, "]"); + break; + case Punctuation: + strcpy(ebuffer, token.id); + break; + case Dash: + strcpy(ebuffer, token.id); + break; + case Verbatim: + strcpy(ebuffer, "\\begin{verbatim}"); + break; + case Scroll: + strcpy(ebuffer, "\\begin{scroll}"); + break; + case Dollar: + strcpy(ebuffer, "$"); + break; + case Percent: + strcpy(ebuffer, "%"); + break; + case Carrot: + strcpy(ebuffer, "^"); + break; + case Underscore: + strcpy(ebuffer, "_"); + break; + case Tilde: + strcpy(ebuffer, "~"); + break; + case Cond: + sprintf(ebuffer, "\\%s", token.id); + break; + case Icorrection: + strcpy(ebuffer, "\\/"); + break; + case Paste: + strcpy(ebuffer, "\\begin{paste}"); + break; + case Patch: + strcpy(ebuffer, "\\begin{patch}"); + break; + default: + sprintf(ebuffer, " %d ", type); + } + /*return 1;*/ + } +} +void +htperror(char *msg, int errno) +{ + char obuff[256]; + + /* The first thing I do is create the error message */ + + if (errno <= Numerrors) { + sprintf(obuff, "%s:%s\n", msg, errmess[errno]); + } + else { + sprintf(obuff, "%s:\n", msg); + fprintf(stderr, "Unknown error type %d\n", errno); + } + fprintf(stderr, "%s", obuff); + + print_page_and_filename(); + + print_next_ten_tokens(); +} +@ +\section{hthits.c} + +This source file implements HyperDoc's ability to scan files for a +given pattern. For that purpose it needs a ``regex'' for string +pattern matching. + +This source file used to rely on [[]], +which was originally part of the X/Open System Interface and Headers +Issue 2. However, since then, it has been withdrawn and no longer +always available on newer platfroms. Consequently, +we need to use a different, portable regex library. The POSIX +definition provides one, namely through [[]]. That is what we +use now. Its availability is tested at configure time. + +<>= +/* + * hthits pattern htdb-file + * + * Scan HyperDoc files for a given pattern. + * + * The output contains lines of the form: + * + * page-name`title`n + * + * The title and body of each page are scanned but the name is not. It is + * possible that the title matches but not any lines. The number of matches + * in the page (n) is given last. + * + * SMW Feb 91 + */ +#define _HTHITS_C + +#include "debug.h" + +#include +#include +#include +#include +#include +#include +#include + +/* + * For fixed-size arrays. + */ +#define MAX_HTDB_LINE 1024 +#define MAX_ENTRY_TYPE 30 /* I.e. \page \newcommand \patch ... */ +#define MAX_ENTRY_NAME 1024 /* E.g. DifferentialCalculusPage */ +#define MAX_COMP_REGEX 1024 + +typedef struct pgInfo { + char name[MAX_ENTRY_NAME]; + long start, size; +} PgInfo ; + +#include "hthits.h1" + +/* + * Global variables set according to the command line. + */ + +char *progName; +char *pattern; +char *htdbFName; +int gverifydates=0; +regex_t reg_pattern; + +int +main(int argc,char ** argv) +{ + cmdline(argc, argv); + + regcomp(®_pattern, pattern, REG_NEWLINE); + + handleHtdb(); + return(0); +} + +void +cmdline(int argc,char ** argv) +{ + progName = argv[0]; + + if (argc != 3) { + fprintf(stderr, "Usage: %s pattern htdb-file\n", progName); + exit(1); + } + + pattern = argv[1]; + htdbFName = argv[2]; +} + +void +handleHtdb(void) +{ + FILE *htdbFile; + int c; + + htdbFile = fopen(htdbFName, "r"); + if (htdbFile == NULL) + badDB(); + + while ((c = getc(htdbFile)) != EOF) { + if (c != '\t') + badDB(); + ungetc(c, htdbFile); + + handleFile(htdbFile); + } + fclose(htdbFile); +} + + +void +handleFile(FILE *htdbFile) +{ + static PgInfo *pgInfoV = 0; + static int pgInfoC = 0; + + char htdbLine[MAX_HTDB_LINE]; + char htfname[MAX_HTDB_LINE]; + time_t httime; + long htsize; + struct stat htstat; + + long fstart, fend; + int rc, i, npages; + + char entname[MAX_ENTRY_NAME], enttype[MAX_ENTRY_TYPE]; + long entoffset, entlineno; + + fgets(htdbLine, MAX_HTDB_LINE, htdbFile); + + sscanf(htdbLine, " %s %ld", htfname, &httime); + + /* + * 1. Verify file: get size and check modification time. + */ + rc = stat(htfname, &htstat); + if (rc == -1) { + fprintf(stderr, "%s: Cannot access %s\n", progName, htfname); + exit(1); + } + if (gverifydates && (htstat.st_mtime != httime)) { + + fprintf(stderr, "%s: Out of date file %s\n", progName, htfname); + exit(1); + } + htsize = htstat.st_size; + + /* + * 2. Count the pages in the file. + */ + npages = 0; + fstart = ftell(htdbFile); + fend = ftell(htdbFile); + + while (fgets(htdbLine, MAX_HTDB_LINE, htdbFile) != NULL) { + if (htdbLine[0] == '\t') + break; + if (!strncmp(htdbLine, "\\page", 5)) + npages++; + fend = ftell(htdbFile); + } + + /* + * 3. Find offset and size of each \page (skipping \newcommands etc.) + */ + if (npages > pgInfoC) { + if (pgInfoV) + free(pgInfoV); + + pgInfoC = npages; + pgInfoV = (PgInfo *) + malloc(npages * sizeof(PgInfo)); + + if (!pgInfoV) { + fprintf(stderr, "%s: out of memory\n", progName); + exit(1); + } + } + + fseek(htdbFile, fstart, 0); + + for (i = 0; fgets(htdbLine, MAX_HTDB_LINE, htdbFile) != NULL;) { + if (htdbLine[0] == '\t') + break; + + sscanf(htdbLine, "%s %s %ld %ld", + enttype, entname, &entoffset, &entlineno); + + if (i > 0 && pgInfoV[i - 1].size == -1) + pgInfoV[i - 1].size = entoffset - pgInfoV[i - 1].start; + + if (!strcmp(enttype, "\\page")) { + strncpy(pgInfoV[i].name, entname, MAX_ENTRY_NAME); + pgInfoV[i].start = entoffset; + pgInfoV[i].size = -1; + + i++; + } + } + if (i > 0 && pgInfoV[i - 1].size == -1) + pgInfoV[i - 1].size = htsize - pgInfoV[i - 1].start; + + if (i != npages) + badDB(); + + /* + * 4. Position database input to read next file-description + */ + fseek(htdbFile, fend, 0); + + /* + * 5. Process the pages of the file. + */ + handleFilePages(htfname, npages, pgInfoV); +} + +void +handleFilePages(char *fname, int pgc, PgInfo *pgv) +{ + FILE *infile; + int i; + + infile = fopen(fname, "r"); + if (infile == NULL) { + fprintf(stderr, "%s: Cannot read file %s\n", progName, fname); + exit(1); + } + + + for (i = 0; i < pgc; i++) + handlePage(infile, pgv + i); + + fclose(infile); + +} + +void +handlePage(FILE *infile,PgInfo * pg) +{ + static char *pgBuf = 0; + static int pgBufSize = 0; + + char *title, *body; + + if (pg->size > pgBufSize - 1) { + if (pgBuf) + free(pgBuf); + pgBufSize = pg->size + 20000; + pgBuf = (char *)malloc(pgBufSize); + + if (!pgBuf) { + fprintf(stderr,"%s: Out of memory\n", progName); + exit(1); + } + } + + fseek(infile, pg->start, 0); + fread(pgBuf, pg->size, 1, infile); + pgBuf[pg->size] = 0; + + splitpage(pgBuf, &title, &body); + /*untexbuf(title);*/ + untexbuf(body); + +#ifdef DEBUG + printf("-------------- %s -------------\n%s", pg->name, pgBuf); + printf("============== %s =============\n", title); + printf("%s", body); +#endif + + searchPage(pg->name, title, body); + +} + +void +searchPage(char *pgname,char * pgtitle,char * pgbody) +{ + char *bodyrest; + regmatch_t match_pos; + int nhits = 0; + + if (!regexec(®_pattern, pgtitle, 1, &match_pos, 0)) + nhits++; + + bodyrest = pgbody; + while (!regexec(®_pattern, bodyrest, 1, &match_pos, 0)) { + nhits++; + bodyrest += match_pos.rm_eo; + } + if (nhits) { + printf("\\newsearchresultentry{%d}{%s}",nhits, pgtitle); + squirt(pgname, strlen(pgname)); + printf("\n"); + } +} + +/* + * Given string s and length n, output ` followed by the first n characters + * of s with ` and newline converted to blanks. This function destructively + * modifies s. + */ + +void +squirt(char *s, int n) +{ + register char *t, *e; + int c; + + c = s[n]; + + for (t = s, e = s + n; t < e; t++) + if (*t == '`' || *t == '\n') + *t = ' '; + + if (s[n] != 0) { + s[n] = 0; + } + printf("{%.*s}", n, s); + s[n] = c; +} + +/* + * Any newlines and separator characters in the title are changed to blanks. + */ +void +splitpage(char *buf, char **ptitle, char **pbody) +{ + int n, depth, tno; + char *s; + + switch (buf[1]) { + case 'p': + tno = 2; + break; /* \page{Name}{Title} */ + case 'b': + tno = 3; + break; /* \begin{page}{Name}{Title} */ + default: + fprintf(stderr, "%s: Invalid page format: %s\n", progName, buf); + exit(1); + } + + n = 0; + depth = 0; + + for (s = buf; *s; s++) { + if (*s == '{') + if (++depth == 1 && ++n == tno) + *ptitle = s + 1; + if (*s == '}') + if (depth-- == 1 && n == tno) { + *s = 0; + *pbody = s + 1; + break; + } + } +} + + +void +untexbuf(register char *s) +{ + register char *d = s; + + while (*s) + switch (*s) { + case '\\': + *d++ = ' '; + s++; + if (*s != '%') + while (isalpha(*s)) + s++; + break; + case '%': + *d++ = ' '; + s++; + while (*s && *s != '\n') + s++; + break; + case '{': + case '}': + case '#': + *d++ = ' '; + s++; + break; + default: + *d++ = *s++; + } + *d = 0; +} + +void +badDB(void) +{ + fprintf(stderr, "%s: bad database file %s\n", progName, htdbFName); + exit(1); +} + +void +regerr(int code) +{ + fprintf(stderr, "%s: regular expression error %d for \"%s\"\n", + progName, code, pattern); +} +@ +\section{htinp.c} +<>= +#define _HTINP_C +#include "debug.h" + +#include +#include +#include + +<> +<> +<> +<> +#include "bsdsignal.h" + +#include "all-hyper-proto.h1" +#include "sockio-c.h1" +#include "bsdsignal.h1" + +extern char **input_file_list; +extern int input_file_count; +extern int make_patch_files; +extern int kill_spad; +extern jmp_buf jmpbuf; + + +#define MaxInputFiles 256 +char *active_file_list[MaxInputFiles]; +int num_active_files = 0; +char *inactive_file_list[MaxInputFiles]; +int num_inactive_files = 0; +int include_bf = 0; +char buf_for_record_commands[256]; + + + +void +make_record(void) +{ + int i; + for (i=0;ifPageHashTable; + make_input_file_list(); + for (i = 0; i < table->size; i++) + for (entry = table->table[i]; entry != NULL; entry = entry->next) + make_the_input_file((UnloadedPage *) entry->data); + if (kill_spad){ + i = connect_spad(); + if (i != NotConnected && i != SpadBusy) + send_int(spad_socket, KillLispSystem); + } +} + +static char * +make_input_file_name(char *buf, char *filename) +{ + char *b, *c; + + strcpy(buf, filename); + for (b = buf + strlen(buf) - 1; b != buf && *b != '/'; b--); + if (b != buf) + b = b + 1; + for (c = b; *c != '.' || c[1] != 'h' || c[2] != 't'; c++); + strcpy(c, ".input"); + return b; +} + +static char * +make_paste_file_name(char *buf, char *filename) +{ + char *b, *c; + + strcpy(buf, filename); + for (b = buf + strlen(buf) - 1; b != buf && *b != '/'; b--); + if (b != buf) + b = b + 1; + for (c = b; *c != '.' || c[1] != 'h' || c[2] != 't'; c++); + strcpy(c, ".pht"); + return b; +} + +static void +make_the_input_file(UnloadedPage *page) +{ + char buf[1024], *b; + + if (!page->fpos.name) + return; + b = make_input_file_name(buf, page->fpos.name); + if (inListAndNewer(b, page->fpos.name)) { + printf("parsing: %s\n", page->name); + if (setjmp(jmpbuf)) { + printf("Syntax error!\n"); + } + else { + load_page((HyperDocPage *)page); + make_input_file_from_page(gWindow->page); + } + } +} + +int example_number; + +static void +make_input_file_from_page(HyperDocPage *page) +{ + TextNode *node; + int starting_file = 1,/* i,*/ /*len,*/ ret_val; + char *buf, buf2[1024], buf3[1024]; + char *b, *c, *com; + FILE *file = NULL; + FILE *pfile = NULL; + static HyperDocPage *op = NULL; + + if (op == page) + return; + op = page; + if (page == NULL) + return; + b = make_input_file_name(buf2, page->filename); + c = make_paste_file_name(buf3, page->filename); + if (inListAndNewer(b, page->filename)) { + /* open and prepare the input file */ + file = fopen(b, "a"); + if (file == NULL) { + fprintf(stderr, "couldn't open output file %s\n", b); + exit(-1); + } + fprintf(file, "\n-- Input for page %s\n", page->name); + fprintf(file, ")clear all\n\n"); + + for (node = page->scrolling; node != NULL; node = node->next) + if (node->type == Spadcommand || node->type == Spadgraph + || node->type == Spadsrc) { + if (starting_file) { + example_number = 1; + if (make_patch_files) { + send_lisp_command("(|clearCmdAll|)"); + send_lisp_command("(|resetWorkspaceVariables|)"); + send_lisp_command("(setq $linelength 55)"); + send_lisp_command("(|setOutputCharacters| '(default))"); + send_lisp_command("(setq |$printLoadMsgs| NIL)"); + send_lisp_command("(setq |$UserLevel| '|development|)"); + send_lisp_command("(verbos 0)"); + } + if (make_patch_files) { + pfile = fopen(c, "a"); + if (pfile == NULL) { + fprintf(stderr, "couldn't open output file %s\n", c); + exit(-1); + } + } + starting_file = 0; + } + else + example_number++; + buf = print_to_string(node->next); + com = alloc_string(buf); + fprintf(file, "%s\n", buf); + fflush(file); + fprintf(stderr, "writing:\t%s\n", buf); + include_bf = 1; + buf = print_to_string(node->next); + include_bf = 0; + if (make_patch_files) { + if (node->type == Spadcommand || node->type == Spadsrc) + print_paste(pfile, com, buf, page->name, node->type); + else + print_graph_paste(pfile, com, buf, page->name, node->type); + } + } + if (!starting_file && make_patch_files) { + ret_val = fclose(pfile); + if (ret_val == -1) { + fprintf(stderr, "couldn't close file %s\n", b); + exit(-1); + } + } + ret_val = fclose(file); + if (ret_val == -1) { + fprintf(stderr, "couldn't close file %s\n", b); + exit(-1); + } + } +} + +char * +strCopy(char *s) +{ + char *b = halloc(strlen(s) + 1,"String"); + + strcpy(b, s); + return b; +} + +static int +inListAndNewer(char *inputFile, char *htFile) +{ + int ret_val, found = 0, i; + struct stat htBuf, inputBuf; + + for (i = 0; i < num_active_files; i++) { + if (strcmp(active_file_list[i], inputFile) == 0) { + found = 1; + break; + } + } + if (found) + return 1; + found = 0; + for (i = 0; i < num_inactive_files; i++) + if (strcmp(inactive_file_list[i], inputFile) == 0) { + found = 1; + break; + } + if (found) + return 0; + found = 0; + for (i = 0; i < input_file_count; i++) + if (strcmp(input_file_list[i], inputFile) == 0) { + found = 1; + break; + } + if (!found) { + inactive_file_list[num_inactive_files++] = strCopy(inputFile); + return 0; + } + ret_val = stat(inputFile, &inputBuf); + if (ret_val == -1) { + active_file_list[num_active_files++] = input_file_list[i]; + printf("making %s\n", inputFile); + return 1; + } + ret_val = stat(htFile, &htBuf); + if (ret_val == -1) { + inactive_file_list[num_inactive_files++] = strCopy(inputFile); + return 0; + } + ret_val = htBuf.st_mtime > inputBuf.st_mtime; + ret_val = 1; + if (ret_val) { + active_file_list[num_active_files++] = input_file_list[i]; + printf("making %s\n", inputFile); + unlink(inputFile); + } + else + inactive_file_list[num_inactive_files++] = input_file_list[i]; + return ret_val; +} + +static void +make_input_file_list(void) +{ + int i; + char buf[256], *name; + + for (i = 0; i < input_file_count; i++) { + name = make_input_file_name(buf, input_file_list[i]); + input_file_list[i] = (char *) halloc(strlen(name) + 1,"Input Filename"); + strcpy(input_file_list[i], name); + } +} + +void +print_paste_line(FILE *pfile,char *str) +{ + char *free = "\\free", *bound = "\\bound", *f = free, *b = bound; + int justSaw = 0; + + for (; *str; str++) { + if (*f == '\0') + justSaw = 2; + if (*b == '\0') + justSaw = 2; + if (*b == *str) + b++; + else + b = bound; + if (*f == *str) + f++; + else + f = free; + if (*str == '%' || *str == '{' || *str == '}' || *str == '#') { + if (*str == '{' && justSaw) + justSaw--; + else if (*str == '}' && justSaw) + justSaw--; + else + putc('\\', pfile); + } + putc(*str, pfile); + } +} + + + +void +get_spad_output(FILE *pfile,char *command,int com_type) +{ + int n, i; + char buf[1024]; + + send_command(command, com_type); + n = get_int(spad_socket); + for (i = 0; i < n; i++) { + get_string_buf(spad_socket, buf, 1024); + fprintf(pfile, "%s\n", buf); + } + unescape_string(command); +} + +/* + * THEMOS says: There is a problem here in that we issue the (|close|) and + * then go on. If this is the last command ,we will soon send a SIGTERM and + * the whole thing will collapse maybe BEFORE the writing out has finished. + * Fix: Call a Lisp function that checks (with \axiomOp{key} ps and grep) the + * health of the viewport. We do this after the (|close|). + */ +void +get_graph_output(char *command,char *pagename,int com_type) +{ + int n, i; + char buf[1024]; + + send_command(command, com_type); + n = get_int(spad_socket); + for (i = 0; i < n; i++) { + get_string_buf(spad_socket, buf, 1024); + } + unescape_string(command); + sprintf(buf, "(|processInteractive| '(|write| |%s| \"%s%d\" \"image\") NIL)", "%", + pagename, example_number); + send_lisp_command(buf); + send_lisp_command("(|setViewportProcess|)"); + send_lisp_command("(|processInteractive| '(|close| (|%%| -3)) NIL)"); + send_lisp_command("(|waitForViewport|)"); + get_int(spad_socket); +} +static void +send_command(char *command,int com_type) +{ + char buf[1024]; + + if (com_type != Spadsrc) { + escape_string(command); + sprintf(buf, "(|parseAndEvalToHypertex| '\"%s\")", command); + send_lisp_command(buf); + } + else { + FILE *f; + char name[512], str[512]/*, *c*/; + + sprintf(name, "/tmp/hyper%s.input", getenv("SPADNUM")); + f = fopen(name, "w"); + if (f == NULL) { + fprintf(stderr, "Can't open temporary input file %s\n", name); + return; + } + fprintf(f, "%s", command); + fclose(f); + sprintf(str, "(|parseAndEvalToHypertex| '\")read %s\")", name); + send_lisp_command(str); + } +} + +static void +print_paste(FILE *pfile,char *realcom,char *command, + char *pagename,int com_type) +{ + fprintf(pfile, "\\begin{patch}{%sPatch%d}\n", pagename, example_number); + fprintf(pfile, "\\begin{paste}{%sFull%d}{%sEmpty%d}\n", + pagename, example_number, pagename, example_number); + fprintf(pfile, "\\pastebutton{%sFull%d}{\\hidepaste}\n", + pagename, example_number); + fprintf(pfile, "\\tab{5}\\spadcommand{"); + print_paste_line(pfile, command); + fprintf(pfile, "}\n"); + fprintf(pfile, "\\indentrel{3}\\begin{verbatim}\n"); + get_spad_output(pfile, realcom, com_type); + fprintf(pfile, "\\end{verbatim}\n"); + fprintf(pfile, "\\indentrel{-3}\\end{paste}\\end{patch}\n\n"); + + fprintf(pfile, "\\begin{patch}{%sEmpty%d}\n", pagename, example_number); + fprintf(pfile, "\\begin{paste}{%sEmpty%d}{%sPatch%d}\n", + pagename, example_number, pagename, example_number); + fprintf(pfile, "\\pastebutton{%sEmpty%d}{\\showpaste}\n", + pagename, example_number); + fprintf(pfile, "\\tab{5}\\spadcommand{"); + print_paste_line(pfile, command); + fprintf(pfile, "}\n"); + fprintf(pfile, "\\end{paste}\\end{patch}\n\n"); + fflush(pfile); +} +static void +print_graph_paste(FILE *pfile,char *realcom, + char *command,char *pagename,int com_type) +{ + fprintf(pfile, "\\begin{patch}{%sPatch%d}\n", pagename, example_number); + fprintf(pfile, "\\begin{paste}{%sFull%d}{%sEmpty%d}\n", + pagename, example_number, pagename, example_number); + fprintf(pfile, "\\pastebutton{%sFull%d}{\\hidepaste}\n", + pagename, example_number); + fprintf(pfile, "\\tab{5}\\spadgraph{"); + print_paste_line(pfile, command); + fprintf(pfile, "}\n"); + fprintf(pfile, "\\center{\\unixcommand{\\inputimage{\\env{AXIOM}"); + fprintf(pfile, "/doc/viewports/%s%d.view/image}}", + pagename,example_number); + fprintf(pfile, "{viewalone\\space{1} \\env{AXIOM}"); + fprintf(pfile,"/doc/viewports/%s%d}}\n", pagename, example_number); + get_graph_output(realcom, pagename, com_type); + fprintf(pfile, "\\end{paste}\\end{patch}\n\n"); + + fprintf(pfile, "\\begin{patch}{%sEmpty%d}\n", pagename, example_number); + fprintf(pfile, "\\begin{paste}{%sEmpty%d}{%sPatch%d}\n", + pagename, example_number, pagename, example_number); + fprintf(pfile, "\\pastebutton{%sEmpty%d}{\\showpaste}\n", + pagename, example_number); + fprintf(pfile, "\\tab{5}\\spadgraph{"); + print_paste_line(pfile, command); + fprintf(pfile, "}\n"); + fprintf(pfile, "\\end{paste}\\end{patch}\n\n"); + fflush(pfile); +} +@ \section{hyper.h} The [[hypertex]] function, of which this is the top level, is a browser for Axiom information. It works off a database of pages. The pages are @@ -219,7 +8081,6 @@ default. This can be over-ridden by setting the [[HTPATH]] shell variable to point to the desired directory containing the pages and the ht.db file. <>= -<> #ifndef _HYPER_H_ #define _HYPER_H_ 1 @@ -233,7 +8094,7 @@ the ht.db file. #include #include "com.h" -#include "token.h" +<> #include "hash.h" #define boolean unsigned short int @@ -775,7 +8636,7 @@ typedef struct parameter_list_type { #include "debug.h" -#include "hyper.h" +<> #include #include @@ -783,10 +8644,10 @@ typedef struct parameter_list_type { #include #include -#include "keyin.h" -#include "initx.h" -#include "event.h" -#include "parse-aux.h" +<> +<> +<> +<> #include "bsdsignal.h" #include "all-hyper-proto.h1" @@ -1133,12 +8994,15 @@ make_server_connections(void) */ if (open_server(MenuServerName) == -2) { - fprintf(stderr, "(HyperDoc) Warning: Not connected to AXIOM Server!\n"); - MenuServerOpened = 0; + fprintf(stderr, "(HyperDoc) Warning: Not connected to AXIOM Server!\n"); + MenuServerOpened = 0; + } + else { + /* In order to allow hyperdoc restarts from the console we clean up + * the socket on exit */ + atexit(&clean_socket); + MenuServerOpened = 1; } - else - MenuServerOpened = 1; - /* * If I have opened the MenuServer socket, then I should also try to open @@ -1213,46 +9077,11070 @@ make_server_connections(void) } } @ -\section{License} -<>= +\section{initx.h} +<>= +#ifndef _INITX_H_ +#define _INITX_H_ 1 + +<> +extern int gBorderColor; + +#endif +@ +\section{initx.c} +<>= +/**************************************************************** + * + * initx.h: HyperDoc X Window window initialization code + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ + +/* #define DEBUG 1 */ + +#define _INITX_C +#include "debug.h" + +<> + +#include +#include +#include +#include +#include +#include + +#ifdef SUN4OS5platform +extern int gethostname(char *, int ); +#endif + +#define ht_icon_width 40 +#define ht_icon_height 40 +#define ht_icon_x_hot -1 +#define ht_icon_y_hot -1 +static char ht_icon_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, + 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xef, 0x7b, 0x3c, 0xe7, 0xff, + 0xef, 0x7f, 0x7e, 0xff, 0xff, 0xe7, 0xef, 0xe7, 0xfe, 0xe7, 0x6e, 0xe7, + 0xe7, 0xde, 0xe7, 0x7e, 0xe7, 0xff, 0x0e, 0xe7, 0x3c, 0xe7, 0x07, 0x0e, + 0xe7, 0x3c, 0xf7, 0xcf, 0x0e, 0xf7, 0x18, 0x7f, 0xfe, 0x1f, 0x00, 0x1c, + 0x3f, 0x7c, 0x1f, 0x00, 0x0e, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x07, 0x00, + 0x00, 0x00, 0x87, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x00, 0x00, 0x00, 0x77, 0x3e, 0xdc, 0x00, 0x00, 0x77, 0x7f, 0xfe, + 0x00, 0x00, 0xf7, 0xe3, 0xef, 0x00, 0x00, 0xf7, 0xe3, 0xc7, 0x00, 0x00, + 0xf7, 0xe3, 0x07, 0x00, 0x00, 0xf7, 0xe3, 0x07, 0x00, 0x00, 0xf7, 0xe3, + 0xcf, 0x00, 0x80, 0x7f, 0x7f, 0xfe, 0x00, 0x80, 0x3f, 0x3e, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" +#include "util.h1" + +#include "spadcolors.h" +#include "spadcolors.h1" + + +#define mouseBitmap_width 16 +#define mouseBitmap_height 16 +#define mouseBitmap_x_hot 8 +#define mouseBitmap_y_hot 0 +static char mouseBitmap_bits[] = { + 0x00, 0x01, 0x00, 0x01, 0x80, 0x02, 0x40, 0x04, 0xc0, 0x06, 0x20, 0x08, + 0x20, 0x08, 0x30, 0x18, 0x50, 0x14, 0x58, 0x34, 0x90, 0x12, 0x20, 0x08, + 0xc0, 0x47, 0x00, 0x21, 0x80, 0x10, 0x00, 0x0f}; +#define mouseMask_width 16 +#define mouseMask_height 16 +static char mouseMask_bits[] = { + 0x00, 0x01, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xc0, 0x07, 0xe0, 0x0f, + 0xe0, 0x0f, 0xf0, 0x1f, 0xf0, 0x1f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, + 0xc0, 0x47, 0x00, 0x21, 0x80, 0x10, 0x00, 0x0f}; + +static GContext server_font; +unsigned long *spadColors; +int scrn; /* used in spad_colors */ + +extern int received_window_request; /* true iff Spad wants a pop-up */ +extern int in_next_event; /* true when in XNextEvent */ + +extern int gTtFontIs850; + +#define MIN_WINDOW_SIZE 300 + + +int gActiveColor, + gAxiomColor, + gBackgroundColor, + gBfColor, + gControlBackgroundColor, + gControlForegroundColor, + gEmColor, + gInputBackgroundColor, + gInputForegroundColor, + gItColor, + gRmColor, + gSlColor, + gTtColor; + +XFontStruct *gAxiomFont, + *gActiveFont, + *gBfFont, + *gEmFont, + *gInputFont, + *gItFont, + *gRmFont, + *gSlFont, + *gTitleFont, + *gTtFont; + +XrmDatabase rDB; +int gBorderColor; /* The Border Color */ + +/* Initialize the X Window System */ + +void +initializeWindowSystem(void) +{ + char *display_name = NULL; + XColor fg, bg; +#if 0 + XColor rgbdef; +#endif + Colormap cmap; + Pixmap mousebits, mousemask; +/* fprintf(stderr,"initx:initializeWindowSystem:entered\n");*/ + /* Try to open the display */ +/* fprintf(stderr,"initx:initializeWindowSystem:XOpenDisplay\n");*/ + if ((gXDisplay = XOpenDisplay(display_name)) == NULL) { + fprintf(stderr, "(HyperDoc) Cannot connect to the X11 server!\n"); + exit(-1); + } + + /* Get the screen */ +/* fprintf(stderr,"initx:initializeWindowSystem:DefaultScreen\n");*/ + gXScreenNumber = scrn = DefaultScreen(gXDisplay); +/* fprintf(stderr,"initx:initializeWindowSystem:XGContextFromGC\n");*/ + server_font =XGContextFromGC(DefaultGC(gXDisplay, gXScreenNumber)); + + /* Get the cursors we need. */ + +/* fprintf(stderr,"initx:initializeWindowSystem:DefaultColormap\n");*/ + cmap = DefaultColormap(gXDisplay, gXScreenNumber); +/* fprintf(stderr,"initx:initializeWindowSystem:WhitePixel\n");*/ + fg.pixel = WhitePixel(gXDisplay,gXScreenNumber); +/* fprintf(stderr,"initx:initializeWindowSystem:XQueryColor\n");*/ + XQueryColor(gXDisplay, cmap, &fg ); +/* fprintf(stderr,"initx:initializeWindowSystem:BlackPixel\n");*/ + bg.pixel = BlackPixel(gXDisplay,gXScreenNumber); +/* fprintf(stderr,"initx:initializeWindowSystem:XQueryColor2\n");*/ + XQueryColor(gXDisplay, cmap, &bg ); +#if 0 + XAllocNamedColor(gXDisplay, cmap, "Black", &fg, &rgbdef); + XAllocNamedColor(gXDisplay, cmap, "White", &bg, &rgbdef); +#endif + +#ifdef USE_BORING_OLD_CURSORS + gActiveCursor = XCreateFontCursor(gXDisplay, XC_circle); + gNormalCursor = XCreateFontCursor(gXDisplay, XC_dot); +#else +/* fprintf(stderr,"initx:initializeWindowSystem:XCreateBitmapFromData 1\n");*/ + mousebits = XCreateBitmapFromData(gXDisplay, + RootWindow(gXDisplay, gXScreenNumber), + mouseBitmap_bits, mouseBitmap_width,mouseBitmap_height); +/* fprintf(stderr,"initx:initializeWindowSystem:XCreateBitmapFromData 2\n");*/ + mousemask = XCreateBitmapFromData(gXDisplay, + RootWindow(gXDisplay, gXScreenNumber), + mouseMask_bits, mouseMask_width,mouseMask_height); +/* fprintf(stderr,"initx:initializeWindowSystem:XCreateBitmapFromData 2\n");*/ + gActiveCursor = XCreatePixmapCursor(gXDisplay, + mousebits, mousemask, &fg, &bg, + mouseBitmap_x_hot,mouseBitmap_y_hot); + +/* fprintf(stderr,"initx:initializeWindowSystem:XCreateFontCursor\n");*/ + gNormalCursor = XCreateFontCursor(gXDisplay, XC_left_ptr); +#endif + +/* fprintf(stderr,"initx:initializeWindowSystem:XCreateFontCursor 2\n");*/ + gBusyCursor = XCreateFontCursor(gXDisplay, XC_watch); + + /* Now initialize all the colors and fonts */ + +/* fprintf(stderr,"initx:initializeWindowSystem:ingItColors_and_fonts\n");*/ + ingItColors_and_fonts(); +/* fprintf(stderr,"initx:initializeWindowSystem:init_text\n");*/ + init_text(); +/* fprintf(stderr,"initx:initializeWindowSystem:exited\n");*/ + +} + /* -Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. -All rights reserved. + * This routine is responsible for initializing a HyperDoc Window. At this + * point, all the fonts have been loaded, and X has been initialized. All I + * need worry about is starting up the window, and creating some of its + * children. + */ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. +/* + * init_top_window tries to start up a window with the page name. If the + * page name is NULL, + * it doesn't try to find it in the Hash Table, but rather just allocates a + * page of no name + */ - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. +int +init_top_window(char *name) +{ + HyperDocPage *page; + XSetWindowAttributes wa; /* The X attributes structure */ + HDWindow *old_win = gWindow; - - Neither the name of The Numerical ALgorithms Group Ltd. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. + gWindow = alloc_hd_window(); -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + if (name == NULL) { + /** Then allocate an empty page, and assign it to gWindow->page */ + page = alloc_page((char *) NULL); + } + else { + /* Try to find the page in the page hash table */ + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, name); + if (page == NULL) { + fprintf(stderr, "(HyperDoc) Couldn\'t find page %s in page hash table \n", + name); + if (gParentWindow == NULL) + /* Gaak, This is a start up error */ + exit(-1); + else { + gWindow = old_win; + return -1; + } + } + } + + /* First allocate memory for the new window structure */ + gWindow->page = page; + + if (old_win == NULL) + open_window(0); + else + open_window(old_win->fMainWindow); + + get_GCs(gWindow); + XMapWindow(gXDisplay, gWindow->fMainWindow); + hash_insert(&gSessionHashTable, (char *)gWindow,(char *) &gWindow->fMainWindow); + + change_text(gRmColor, gRmFont); + wa.background_pixel = gBackgroundColor; + XChangeWindowAttributes(gXDisplay, gWindow->fMainWindow, CWBackPixel, &wa); + XChangeWindowAttributes(gXDisplay, gWindow->fScrollWindow, CWBackPixel,&wa); + return 1; +} + +/* Create and initialize a form HyperDoc window */ + +static void +open_form_window(void) +{ + int x, y, width, height; + unsigned int fwidth = 0, fheight = 0; + unsigned int xadder = 0, yadder = 0; + /*char *window_name = "HyperDoc";*/ + /*char *icon_name = "HT";*/ + XrmValue value; + char *str_type[50]; + XSizeHints size_hints; + int userSpecified = 0; + + char userdefaults[50], progdefaults[50]; + + strcpy(progdefaults, "=950x450+0+0"); + if (XrmGetResource(rDB, "Axiom.hyperdoc.FormGeometry", + "Axiom.hyperdoc.FormGeometry", str_type, &value) == True) + { + strncpy(userdefaults, value.addr, (int) value.size); + userSpecified = 1; + } + else + strcpy(userdefaults, progdefaults); + + XGeometry(gXDisplay, gXScreenNumber, userdefaults, progdefaults, + 0, fwidth, fheight, xadder, yadder, + &x, &y, &width, &height); + + gWindow->border_width = get_border_properties(); + + gWindow->width = 1; + gWindow->height = 1; + + gWindow->fMainWindow = XCreateSimpleWindow(gXDisplay, RootWindow(gXDisplay, gXScreenNumber), + x, y, width, height, gWindow->border_width, + gBorderColor, + WhitePixel(gXDisplay, gXScreenNumber)); + gWindow->fScrollWindow = XCreateSimpleWindow(gXDisplay, gWindow->fMainWindow, + 1, 1, 1, 1, 0, + BlackPixel(gXDisplay, gXScreenNumber), + WhitePixel(gXDisplay, gXScreenNumber)); + makeScrollBarWindows(); + makeTitleBarWindows(); + + set_name_and_icon(); + + XSelectInput(gXDisplay, gWindow->fScrollWindow, PointerMotionMask); + XSelectInput(gXDisplay, gWindow->fMainWindow, StructureNotifyMask | PointerMotionMask); + XDefineCursor(gXDisplay, gWindow->fMainWindow, gNormalCursor); + + /* now give the window manager some hints */ + + size_hints.flags = 0; + + size_hints.min_width = width; + size_hints.min_height = height; + size_hints.flags |= PMinSize; + + size_hints.width = width; + size_hints.height = height; + size_hints.flags |= (userSpecified ? USSize : PSize); + + size_hints.x = x; + size_hints.y = y; + size_hints.flags |= (userSpecified ? USPosition : PPosition); + + XSetNormalHints(gXDisplay, gWindow->fMainWindow, &size_hints); + XFlush(gXDisplay); +} + + +int +init_form_window(char *name, int cols) +{ + XSetWindowAttributes wa; /* The X attributes structure */ + + /* First allocate memory for the new window structure */ + + gWindow = alloc_hd_window(); + open_form_window(); + gWindow->width = window_width(cols); + + if (name == NULL) { + /** Then allocate an empty page, and assign it to gWindow->page */ + gWindow->page = alloc_page((char *) NULL); + } + else { + /* Try to find the page in the page hash table */ + gWindow->page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, name); + if (gWindow->page == NULL) { + fprintf(stderr, "Couldn't find page %s\n", name); + return (-1); + } + } + + get_GCs(gWindow); + hash_insert(&gSessionHashTable, (char *)gWindow,(char *) &gWindow->fMainWindow); + + wa.background_pixel = gBackgroundColor; + XChangeWindowAttributes(gXDisplay, gWindow->fMainWindow, CWBackPixel, &wa); + XChangeWindowAttributes(gXDisplay, gWindow->fScrollWindow, CWBackPixel,&wa); + return 1; +} + + +static void +set_name_and_icon(void) +{ + char *icon_name = "HyperDoc"; + char *s; + Pixmap icon_pixmap; + XWMHints wmhints; + XClassHint ch; + + ch.res_name = "HyperDoc"; + ch.res_class = gArgv[0]; + for (s = gArgv[0] + strlen(gArgv[0]) - 1; s != gArgv[0]; s--) { + if (*s == '/') { + ch.res_class = s + 1; + break; + } + } + XSetClassHint(gXDisplay, gWindow->fMainWindow, &ch); + + XStoreName(gXDisplay, gWindow->fMainWindow, "HyperDoc"); + + /* define and assign the pixmap for the icon */ + icon_pixmap = XCreateBitmapFromData(gXDisplay, gWindow->fMainWindow, ht_icon_bits, + ht_icon_width, ht_icon_height); + wmhints.icon_pixmap = icon_pixmap; + wmhints.flags = IconPixmapHint; + + XSetWMHints(gXDisplay, gWindow->fMainWindow, &wmhints); + + /* name the icon */ + XSetIconName(gXDisplay, gWindow->fMainWindow, icon_name); +} + +static int +get_border_properties(void) +{ + char *bwidth; + /*char *bc = NULL;*/ + int bw; + /*XColor color_def, color_db;*/ + Colormap cmap; + /*int ret_val;*/ + + + bwidth = "2"; /* XGetDefault(gXDisplay, "Axiom.hyperdoc", "BorderWidth") */ + + if (bwidth == NULL) + bw = 1; + else { + bw = atoi(bwidth); + if (bw < 1) { + fprintf(stderr, + "%s: The line width value must be greater than zero\n", "Axiom.hyperdoc"); + bw = 1; + } + } + + /* Now try to find the user preferred border color */ + + if (DisplayPlanes(gXDisplay, gXScreenNumber) == 1) + gBorderColor = BlackPixel(gXDisplay, gXScreenNumber); + else { + cmap = DefaultColormap(gXDisplay, gXScreenNumber); + gBorderColor = get_color("BorderColor", "Foreground", + BlackPixel(gXDisplay, gXScreenNumber), &cmap); + } + return bw; +} + + +/* Create and initialize the HyperDoc window */ + +static void +open_window(Window w) +{ + int x = 0, y = 0; + /*int border_width = 2;*/ + unsigned int width = 1; + unsigned int height = 1; + unsigned int fwidth = 0, fheight = 0; + unsigned int xadder = 0, yadder = 0; + char *str_type[50]; + XrmValue value; + + char userdefaults[50], progdefaults[50]; + + strcpy(progdefaults, "=700x450+0+0"); + if (XrmGetResource(rDB, "Axiom.hyperdoc.Geometry", + "Axiom.hyperdoc.Geometry", str_type, &value) == True) + { + strncpy(userdefaults, value.addr, (int) value.size); + } + else + strcpy(userdefaults, progdefaults); + + XGeometry(gXDisplay, gXScreenNumber, userdefaults, progdefaults, + 0, fwidth, fheight, xadder, yadder, + &x, &y, ( int *)&width,( int *) &height); + + gWindow->border_width = get_border_properties(); + + gWindow->fMainWindow = XCreateSimpleWindow(gXDisplay, RootWindow(gXDisplay, gXScreenNumber), + x, y, width, height, gWindow->border_width, + gBorderColor, + WhitePixel(gXDisplay, gXScreenNumber)); + + gWindow->fScrollWindow = XCreateSimpleWindow(gXDisplay, gWindow->fMainWindow, + 1, 1, 1, 1, 0, + gBorderColor, + WhitePixel(gXDisplay, gXScreenNumber)); + + + makeScrollBarWindows(); + makeTitleBarWindows(); + + /* Now set all the little properties for the top level window */ + + set_name_and_icon(); + set_size_hints(w); + XSelectInput(gXDisplay, gWindow->fScrollWindow, PointerMotionMask); + XSelectInput(gXDisplay, gWindow->fMainWindow, StructureNotifyMask | PointerMotionMask); + XDefineCursor(gXDisplay, gWindow->fMainWindow, gNormalCursor); +} + +/*** + This routine gets and sets the size for a new window. If the w paramter + is null, it means that this is the initial window. Thus the user + preferences are checked. If this is not the first window, then the + window w is used as a guidline, and the new window is placed on top of + it. + ***/ + +static void +set_size_hints(Window w) +{ + int x, y; + unsigned int width, height; + char userdefaults[50]; + char progdefaults[50]; + char *str_type[50]; + unsigned int fwidth = 0, fheight = 0; + unsigned int xadder = 0, yadder = 0; + int geo = 0; /* return flag from XGetGeometry */ + unsigned int depth, bw=0; + Window root; + XSizeHints size_hints; + XPoint xp; + XrmValue value; + + size_hints.flags = 0; + + strcpy(progdefaults, "=600x450+0+0"); + + if (w) { + /* + * The window should be queried for it's size and position. Then the + * new window should be given almost the same locations + */ + + if (XGetGeometry(gXDisplay, w, &root, &x, &y, &width, &height, &bw, &depth)) + { + xp = getWindowPositionXY(gXDisplay, w); + x = xp.x + 40; + y = xp.y + 40; + if (x < 0) + x = 0; + if (y < 0) + y = 0; + size_hints.flags |= (USSize | USPosition); + } + else { + fprintf(stderr, "(HyperDoc) Error Querying window configuration: %ld.\n", w); + x = y = 0; + width = 600; + height = 450; + size_hints.flags |= (PSize | PPosition); + } + } + else { + /* this is the first window, so lets try to find a nice spot for it */ + + if (XrmGetResource(rDB, "Axiom.hyperdoc.Geometry", "Axiom.hyperdoc.Geometry", + str_type, &value) == True) + { + strncpy(userdefaults, value.addr, (int) value.size); + geo = XParseGeometry(userdefaults, &x, &y, &width, &height); + } + else + strcpy(userdefaults, progdefaults); + + size_hints.flags |= (geo & (WidthValue | HeightValue)) ? USSize : PSize; + size_hints.flags |= (geo & (XValue | YValue)) ? USPosition : PPosition; + + geo = XGeometry(gXDisplay, gXScreenNumber, userdefaults, progdefaults, + bw, fwidth, fheight, xadder, yadder, + &x, &y, (int *)&width, (int *)&height); + } + + size_hints.x = x; + size_hints.y = y; + size_hints.width = width; + size_hints.height = height; + + getTitleBarMinimumSize(&(size_hints.min_width), &(size_hints.min_height)); +#if 0 + size_hints.min_width = MIN_WINDOW_SIZE; + size_hints.min_height = MIN_WINDOW_SIZE; +#endif + size_hints.flags |= PMinSize; + + XSetNormalHints(gXDisplay, gWindow->fMainWindow, &size_hints); + /* just in case a hint isn't enough ... */ + XFlush(gXDisplay); +/* XMoveResizeWindow(gXDisplay, gWindow->fMainWindow, x, y, width, height); */ +} + +#define stipple_width 4 +#define stipple_height 4 +static char stipple_bits[] = { + 0xff, 0xff, 0xff, 0xff}; +Pixmap stipple; + +/* Create the graphics contexts to be used for all drawing operations */ + +static void +get_GCs(HDWindow *window) +{ + /*unsigned long valuemask = 0;*/ + XGCValues values; + + values.background = gBackgroundColor; + window->fStandardGC = XCreateGC(gXDisplay, window->fMainWindow, GCBackground, &values); + + XSetLineAttributes(gXDisplay, window->fStandardGC, window->border_width, + LineSolid, CapButt, JoinMiter); + + + /* create the stipple for the gc */ + + stipple = XCreateBitmapFromData(gXDisplay, + RootWindow(gXDisplay, gXScreenNumber), + stipple_bits, stipple_width, stipple_height); + + values.background = gInputBackgroundColor; + values.foreground = gInputForegroundColor; + + values.font = gInputFont->fid; + + if (values.font == server_font ) + window->fInputGC = XCreateGC(gXDisplay, window->fMainWindow, + GCBackground | GCForeground, &values); + else { + window->fInputGC = XCreateGC(gXDisplay, window->fMainWindow, + GCBackground | GCForeground | GCFont, &values); + } + + window->fCursorGC = XCreateGC(gXDisplay, window->fMainWindow, 0, NULL); + + if (values.font != server_font) + XSetFont(gXDisplay, window->fCursorGC, gInputFont->fid); + + XSetBackground(gXDisplay, window->fCursorGC, gInputForegroundColor); + XSetForeground(gXDisplay, window->fCursorGC, gInputBackgroundColor); + + window->fControlGC = XCreateGC(gXDisplay, window->fMainWindow, 0, NULL); + XSetBackground(gXDisplay, window->fControlGC, gControlBackgroundColor); + XSetForeground(gXDisplay, window->fControlGC, gControlForegroundColor); +} + +/* Load a font and store the information in the font_info parameter */ + +static void +load_font(XFontStruct **font_info, char *fontname) +{ + if ((*font_info = XLoadQueryFont(gXDisplay, fontname)) == NULL) { + fprintf(stderr, "(HyperDoc) Cannot load font %s ; using default.\n", + fontname); + + if ((*font_info = XQueryFont(gXDisplay, + XGContextFromGC(DefaultGC(gXDisplay, gXScreenNumber)))) == NULL) + { + fprintf(stderr, "(HyperDoc) Cannot get default font ; exiting.\n"); + exit(-1); + } + } +} + + +/* + * This routine initializes all the colors and fonts that the user wishes to + * use. It checks for all the following properties in $HOME/.Xdefaults. + * + * Axiom.hyperdoc.ActiveColor: + * Axiom.hyperdoc.Background: + * Axiom.hyperdoc.EmphasizeColor: + * Axiom.hyperdoc.EmphasizeFont: + * Axiom.hyperdoc.Foreground: + * Axiom.hyperdoc.InputBackground: + * Axiom.hyperdoc.InputForeground: + * Axiom.hyperdoc.SpadColor: + * Axiom.hyperdoc.SpadFont: + */ + +static void +ingItColors_and_fonts(void) +{ + char property[256]; + char *prop = &property[0]; + char *str_type[50]; + XrmValue value; + Colormap cmap; + int ts; + + /** get the color map for the display **/ +/* fprintf(stderr,"initx:ingItColors_and_fonts:entered\n");*/ + +/* fprintf(stderr,"initx:ingItColors_and_fonts:DefaultColorMap\n");*/ + cmap = DefaultColormap(gXDisplay, gXScreenNumber); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:init_group_stack\n");*/ + init_group_stack(); + + + /** then start getting the fonts **/ + +/* fprintf(stderr,"initx:ingItColors_and_fonts:mergeDatabases\n");*/ + mergeDatabases(); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:XrmGetResource\n");*/ + if (XrmGetResource(rDB, "Axiom.hyperdoc.RmFont", + "Axiom.hyperdoc.Font", str_type, &value) == True) + (void) strncpy(prop, value.addr, (int) value.size); + else + (void) strcpy(prop, RmFontDefault); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:load_font 1\n");*/ + load_font(&gRmFont, prop); +/* fprintf(stderr,"initx:ingItColors_and_fonts:load_font 2\n");*/ + load_font(&gInputFont, prop); + + +/* fprintf(stderr,"initx:ingItColors_and_fonts:XrmGetResource 2\n");*/ + if (XrmGetResource(rDB, "Axiom.hyperdoc.TtFont", + "Axiom.hyperdoc.Font", str_type, &value) == True) + (void) strncpy(prop, value.addr, (int) value.size); + else + (void) strcpy(prop, TtFontDefault); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:load_font 3\n");*/ + load_font(&gTtFont, prop); +/* fprintf(stderr,"initx:ingItColors_and_fonts:is_it_850\n");*/ + gTtFontIs850=is_it_850(gTtFont); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:XrmGetResource 5\n");*/ + if (XrmGetResource(rDB, "Axiom.hyperdoc.ActiveFont", + "Axiom.hyperdoc.Font", str_type, &value) == True) + (void) strncpy(prop, value.addr, (int) value.size); + else + (void) strcpy(prop, ActiveFontDefault); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:load_font 4\n");*/ + load_font(&gActiveFont, prop); + + /* maintain backwards compatibility */ + +/* fprintf(stderr,"initx:ingItColors_and_fonts:XrmGetResource 6\n");*/ + if (XrmGetResource(rDB, "Axiom.hyperdoc.AxiomFont", + "Axiom.hyperdoc.Font", str_type, &value) == True) + (void) strncpy(prop, value.addr, (int) value.size); + else { + if (XrmGetResource(rDB, "Axiom.hyperdoc.SpadFont", + "Axiom.hyperdoc.Font", str_type, &value) == True) + { + (void) strncpy(prop, value.addr, (int) value.size); + } + else { + (void) strcpy(prop, AxiomFontDefault); + } + } + +/* fprintf(stderr,"initx:ingItColors_and_fonts:load_font 5\n");*/ + load_font(&gAxiomFont, prop); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:XrmGetResource 7\n");*/ + if (XrmGetResource(rDB, "Axiom.hyperdoc.EmphasizeFont", + "Axiom.hyperdoc.Font", str_type, &value) == True) + { + (void) strncpy(prop, value.addr, (int) value.size); + } + else { + (void) strcpy(prop, EmphasizeFontDefault); + } +/* fprintf(stderr,"initx:ingItColors_and_fonts:load_font 6\n");*/ + load_font(&gEmFont, prop); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:XrmGetResource 8\n");*/ + if (XrmGetResource(rDB, "Axiom.hyperdoc.BoldFont", + "Axiom.hyperdoc.Font", str_type, &value) == True) + { + (void) strncpy(prop, value.addr, (int) value.size); + } + else { + (void) strcpy(prop, BoldFontDefault); + } +/* fprintf(stderr,"initx:ingItColors_and_fonts:load_font 7\n");*/ + load_font(&gBfFont, prop); + + + /* + * If we are on a monochrome screen, then we ignore user preferences, and + * set the foreground and background as I wish + */ + +/* fprintf(stderr,"initx:ingItColors_and_fonts:DisplayPlanes\n");*/ + if (DisplayPlanes(gXDisplay, gXScreenNumber) == 1) { + gActiveColor = gAxiomColor + = gControlBackgroundColor + = gInputBackgroundColor + = gBfColor + = gEmColor + = gRmColor + = gSlColor + = gTtColor + = BlackPixel(gXDisplay, gXScreenNumber); + + gBackgroundColor = gInputForegroundColor + = gControlForegroundColor + = WhitePixel(gXDisplay, gXScreenNumber); + } + else { + + /* + * If I have gotten here, then we must be on a color screen, so see + * what the user likes, and set it up + */ + +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 1\n");*/ + gRmColor = + get_color("RmColor", "Foreground", + BlackPixel(gXDisplay, gXScreenNumber), &cmap); +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 2\n");*/ + gBackgroundColor = + get_color("Background", "Background", + WhitePixel(gXDisplay, gXScreenNumber), &cmap); +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 3\n");*/ + gActiveColor = + get_color("ActiveColor", "Foreground", + BlackPixel(gXDisplay, gXScreenNumber), &cmap); + + /* + * for next two, I want name arg = class arg, ie do not want + * Background and Foreground. + */ + +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 4\n");*/ + gControlBackgroundColor = get_color("ControlBackground", + "ControlBackground", WhitePixel(gXDisplay, gXScreenNumber), &cmap); +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 5\n");*/ + gControlForegroundColor = get_color("ControlForeground", + "ControlForeground", BlackPixel(gXDisplay, gXScreenNumber), &cmap); + + /* maintain backwards compatibility */ + +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 6\n");*/ + gAxiomColor = get_color("AxiomColor", "Foreground", 0, &cmap); +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 7\n");*/ + if (gAxiomColor == 0) + gAxiomColor = get_color("SpadColor", "Foreground", + BlackPixel(gXDisplay, gXScreenNumber), &cmap); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 8\n");*/ + gInputBackgroundColor = + get_color("InputBackground", "Foreground", gRmColor, &cmap); +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 9\n");*/ + gInputForegroundColor = + get_color("InputForeground", "Background", gBackgroundColor, &cmap); + +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 10\n");*/ + gEmColor = + get_color("EmphasizeColor", "Foreground", gRmColor, &cmap); +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 11\n");*/ + gTtColor = + get_color("TtColor", "Foreground", gRmColor, &cmap); +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 12\n");*/ + gSlColor = + get_color("EmphasizeColor", "Foreground", gRmColor, &cmap); +/* fprintf(stderr,"initx:ingItColors_and_fonts:get_color 13\n");*/ + gBfColor = + get_color("BoldColor", "Foreground", gRmColor, &cmap); + } + +/* fprintf(stderr,"initx:ingItColors_and_fonts:makeColors\n");*/ + makeColors(gXDisplay, gXScreenNumber, &cmap, &spadColors, &ts); + /* + * Now set the current color and font, so I never have to do it again + */ + + gTopOfGroupStack->cur_color = gRmColor; + gTopOfGroupStack->cur_font = gRmFont; +/* fprintf(stderr,"initx:ingItColors_and_fonts:exited\n");*/ +} + +void +change_text(int color, XFontStruct *font) +{ + if (font) { + XGCValues gcv; + gcv.foreground = color; + gcv.background = gBackgroundColor; + + XChangeGC(gXDisplay, gWindow->fStandardGC, GCForeground | GCBackground , &gcv); + + if (font->fid != server_font) + XSetFont(gXDisplay, gWindow->fStandardGC, font->fid); + } +} + +/* + * This routine checks the .Xdefaults file of the user for the + * specified color. If found it allocates a place in the color map for it. If + * not found, or if an error occurrs, it writes an error message, and + * uses the given default value + */ + +static int +get_color(char *name, char *class, int def, Colormap *map) +{ + char fullname[256]; + char fullclass[256]; + char property[256]; + char *prop = &property[0]; + char *str_type[50]; + XrmValue value; + int ret_val; + XColor color_def, color_db; + +#ifdef DEBUG + printf("get_color: %s %s %d -> ", name, class, def); +#endif + + strcpy(fullname, "Axiom.hyperdoc."); + strcat(fullname, name); + strcpy(fullclass,"Axiom.hyperdoc."); + strcat(fullclass,class); + + if (XrmGetResource(rDB, fullname, fullclass, str_type, &value) == True) { + (void) strncpy(prop, value.addr, (int) value.size); + ret_val = XAllocNamedColor(gXDisplay, *map, prop, &color_def, &color_db); + if (ret_val) { +#ifdef DEBUG + printf("%d\n", color_def.pixel); +#endif + return (color_def.pixel); + } + else { + fprintf(stderr, + "(HyperDoc) Defaulting on color for %s. Unknown color is %s.\n", + name, prop); +#ifdef DEBUG + printf("%d\n", def); +#endif + return (def); + } + } + else { +#ifdef DEBUG + printf("%d\n", def); +#endif + return (def); + } +} + + +static void +mergeDatabases(void) +{ + XrmDatabase homeDB, serverDB, applicationDB; + char filenamebuf[1024]; + char *filename = &filenamebuf[0]; + char *classname = "Axiom"; + char name[255]; + +/* fprintf(stderr,"initx:mergeDatabases:entered\n");*/ +/* fprintf(stderr,"initx:mergeDatabases:XrmInitialize\n");*/ + (void) XrmInitialize(); + (void) strcpy(name, "/usr/lib/X11/app-defaults/"); + (void) strcat(name, classname); +/* fprintf(stderr,"initx:mergeDatabases:XrmGetFileDatabase name=%s\n",name);*/ + applicationDB = XrmGetFileDatabase(name); +/* fprintf(stderr,"initx:mergeDatabases:XrmMergeDatabases\n");*/ + (void) XrmMergeDatabases(applicationDB, &rDB); + +/* fprintf(stderr,"initx:mergeDatabases:XrmGetStringDatabase\n");*/ + if (XResourceManagerString(gXDisplay) != NULL) { + serverDB = XrmGetStringDatabase(XResourceManagerString(gXDisplay)); + } + else { + (void) strcpy(filename, getenv("HOME")); + (void) strcat(filename, "/.Xdefaults"); +/* fprintf(stderr,"initx:mergeDatabases:XrmGetFileDatase\n");*/ + serverDB = XrmGetFileDatabase(filename); + } +/* fprintf(stderr,"initx:mergeDatabases:XrmMergeDatabases 2\n");*/ + XrmMergeDatabases(serverDB, &rDB); + if (getenv("XENVIRONMENT") == NULL) { + int len; + + (void) strcpy(filename, getenv("HOME")); + (void) strcat(filename, "/.Xdefaults-"); + len = strlen(filename); + (void) gethostname(filename + len, 1024 - len); + } + else { + (void) strcpy(filename, getenv("XENVIRONMENT")); + } +/* fprintf(stderr,"initx:mergeDatabases:filename=%s\n",filename);*/ + homeDB = XrmGetFileDatabase(filename); +/* fprintf(stderr,"initx:mergeDatabases:XrmMergeDatabases 3\n");*/ + XrmMergeDatabases(homeDB, &rDB); +} + + + +int +is_it_850(XFontStruct *fontarg) +{ + char *s; + int i,val; + static struct { + char *name; + Atom format; + Atom atom; + } proptbl = { "CHARSET_ENCODING", XA_ATOM }; + proptbl.atom = XInternAtom(gXDisplay,proptbl.name,0); + for (i=0;in_properties;i++) + { + if (fontarg->properties[i].name != proptbl.atom) continue; + + +/* return 1 if it is 850 */ + + s = XGetAtomName(gXDisplay,(Atom)fontarg->properties[i].card32); + val = !( strcmp("850",s) * strcmp("ibm-850",s)); + XFree(s); + return( val ); + } + return(0); +} + +@ +\section{input.c} +<>= +#define _INPUT_C +#include "debug.h" + +<> +<> +<> + +#include "all-hyper-proto.h1" + + +void +fill_box(Window w,ImageStruct * image) +{ + XClearWindow(gXDisplay, w); + XPutImage(gXDisplay, w, gWindow->fControlGC, + image->image.xi, 0, 0, 0, 0, + image->width, + image->height); +} + +void +toggle_input_box(HyperLink *link) +{ + InputBox *box; + + box = link->reference.box; + + if (box->picked) { + box->picked = 0; + unpick_box(box); + } + else { + box->picked = 1; + pick_box(box); + } + +} +void +toggle_radio_box(HyperLink *link) +{ + InputBox *box; + + box = link->reference.box; + + if (box->picked) { + + /* + * box->picked = 0; unpick_box(box); + */ + } + else { + /* the first thing I do is clear his buddies */ + clear_rbs(box->rbs->boxes); + box->picked = 1; + pick_box(box); + } +} + +static void +clear_rbs(InputBox *list) +{ + InputBox *trace = list; + + while (trace && !trace->picked) + trace = trace->next; + + if (trace != NULL) { + trace->picked = 0; + unpick_box(trace); + } +} +void +change_input_focus(HyperLink *link) +{ + InputItem *new_item = link->reference.string; + InputItem *old_item = gWindow->page->current_item; + XWindowChanges wc; + + /** first thing I should do is see if the user has clicked in the same + window that I am in ****/ + if (old_item == new_item) + return; + + /** Now change the current pointer **/ + gWindow->page->current_item = new_item; + + /** Now I have to change the border width of the selected input window **/ + wc.border_width = 1; + XConfigureWindow(gXDisplay, new_item->win, + CWBorderWidth, + &wc); + + wc.border_width = 0; + XConfigureWindow(gXDisplay, new_item->win, + CWBorderWidth, + &wc); + update_inputsymbol(old_item); + update_inputsymbol(new_item); +} +void +next_input_focus(void) +{ + InputItem *old_item = gWindow->page->current_item, *new_item, *trace; + + if (gWindow->page->current_item == NULL || + (gWindow->page->current_item->next == NULL + && gWindow->page->current_item == gWindow->page->input_list)) { + BeepAtTheUser(); + return; + } + + /* + * Now I should find the new item + */ + new_item = NULL; + trace = old_item->next; + + if (trace == NULL) + new_item = gWindow->page->input_list; + else + new_item = trace; + + gWindow->page->current_item = new_item; + draw_inputsymbol(old_item); + draw_inputsymbol(new_item); +} +void +prev_input_focus(void) +{ + InputItem *old_item = gWindow->page->current_item, *new_item, *trace; + + if (gWindow->page->current_item == NULL) { + BeepAtTheUser(); + return; + } + + /* + * Now I should find the new item + */ + new_item = NULL; + trace = gWindow->page->input_list; + + if (trace == old_item) { + + /* + * I started at the front of the list, so move forward until I hit + * the end + */ + while (trace->next != NULL) + trace = trace->next; + new_item = trace; + } + else { + while (trace->next != old_item) + trace = trace->next; + new_item = trace; + } + + gWindow->page->current_item = new_item; + draw_inputsymbol(old_item); + draw_inputsymbol(new_item); + +} + +InputItem * +return_item(char *name) +{ + InputItem *list; + + list = gWindow->page->input_list; + while (list != NULL) { + if (!strcmp(name, list->name)) + return list; + list = list->next; + } + return NULL; +} +int +delete_item(char *name) +{ + InputItem *list; + InputItem *prev = NULL; + + list = gWindow->page->input_list; + while (list != NULL) { + if (!strcmp(name, list->name)) { + if (prev) + prev->next = list->next; + else + gWindow->page->input_list = list->next; + if (gWindow->page->current_item == list) + gWindow->page->current_item = gWindow->page->input_list; + free_input_item(list, 1); + free(list); + return 1; + } + prev = list; + list = list->next; + } + fprintf(stderr, "Can't delete input item %s\n", name); + return 0; +} + +@ +\section{item.c} +<>= +#define _ITEM_C +#include "debug.h" +<> + +#include "all-hyper-proto.h1" + +/* + * Here are structures needed for manipulating the item stack + */ +ItemStack *gTopOfItemStack = NULL; + + +void +push_item_stack(void) +{ + ItemStack *is = (ItemStack *) halloc(sizeof(ItemStack), "Item stack"); + + is->indent = indent; + is->item_indent = item_indent; + is->next = gTopOfItemStack; + is->in_item = gInItem; + gTopOfItemStack = is; + return; +} +void +clear_item_stack(void) +{ + ItemStack *is = gTopOfItemStack, *chuck; + + while (is != NULL) { + chuck = is; + is = is->next; + free(chuck); + } + return; +} +void +pop_item_stack(void) +{ + ItemStack *chuck; + + if (gTopOfItemStack == NULL) { + fprintf(stderr, "Tried to pop an empty item stack\n"); + return; + } + chuck = gTopOfItemStack; + gTopOfItemStack = gTopOfItemStack->next; + indent = chuck->indent; + item_indent = chuck->item_indent; + gInItem = chuck->in_item; + free(chuck); +} + +ItemStack * +copy_item_stack(void) +{ + ItemStack *new = NULL; + ItemStack *prev = NULL; + ItemStack *trace = gTopOfItemStack; + ItemStack *first = NULL; + + while (trace) { + new = (ItemStack *) halloc(sizeof(ItemStack), "Item stack"); + new->indent = trace->indent; + new->item_indent = trace->item_indent; + new->in_item = gInItem; + if (!first) + first = new; + else + prev->next = new; + prev = new; + trace = trace->next; + } + if (new) + new->next = NULL; + return first; +} + +void +free_item_stack(ItemStack *is) +{ + ItemStack *junk = NULL; + ItemStack *trace = is; + + while (trace) { + junk = trace; + trace = trace->next; + free(junk); + } +} +@ +\section{keyin.h} +<>= +#ifndef _KEYIN_H_ +#define _KEYIN_H_ 1 + +extern int in_cursor_height; +extern int in_cursor_width; +extern int out_cursor_height; +extern int out_cursor_width; +extern int in_cursor_y; +extern int out_cursor_y; +extern int start_x; +extern int start_y; +extern int simple_box_width; + +extern int gInInsertMode; + +extern unsigned int ModifiersMask; +extern unsigned int UnsupportedModMask; + + +#endif +@ +\section{keyin.c} +<>= +/****************************************************************************** + * + * keyin.c: + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _KEYIN_C +#include "debug.h" + + +<> +<> +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" +#include + + +#define min(x,y) ( (xxkey.state & ShiftMask) { + name = gWindow->page->name; + filename = gWindow->page->filename; + sprintf(buffer, "htadd -l %s\n", filename); + system(buffer); + filehandle = (FILE *) hash_find(&gFileHashTable, filename); + fclose(filehandle); + hash_delete(&gFileHashTable, filename); + gWindow->fMacroHashTable = + (HashTable *) halloc(sizeof(HashTable), "macro hash"); + hash_init( + gWindow->fMacroHashTable, + MacroHashSize, + (EqualFunction ) string_equal, + (HashcodeFunction) string_hash); + gWindow->fPatchHashTable = (HashTable *) halloc(sizeof(HashTable), "patch hash"); + hash_init( + gWindow->fPatchHashTable, + PatchHashSize, + (EqualFunction ) string_equal, + (HashcodeFunction) string_hash); + gWindow->fPasteHashTable = (HashTable *) halloc(sizeof(HashTable), "paste hash"); + hash_init(gWindow->fPasteHashTable, + PasteHashSize, + (EqualFunction ) string_equal, + (HashcodeFunction) string_hash); + gWindow->fCondHashTable = (HashTable *) halloc(sizeof(HashTable), "cond hash"); + hash_init( + gWindow->fCondHashTable, + CondHashSize, + (EqualFunction ) string_equal, + (HashcodeFunction) string_hash); + gWindow->fPageHashTable = (HashTable *) halloc(sizeof(HashTable), "page hash"); + hash_init( + gWindow->fPageHashTable, + PageHashSize, + (EqualFunction ) string_equal, + (HashcodeFunction) string_hash); + make_special_pages(gWindow->fPageHashTable); + read_ht_db( + gWindow->fPageHashTable, + gWindow->fMacroHashTable, + gWindow->fPatchHashTable); + gWindow->page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, name); + if (gWindow->page == NULL) { + fprintf(stderr, "lose...gWindow->page for %s is null\n", name); + exit(-1); + } + display_again = 1; + } + break; + case XK_F9: + make_window_link(KeyDefsHelpPage); + break; + case XK_Tab: + if (event->xkey.state & ShiftMask) + prev_input_focus(); + else if (event->xkey.state & ModifiersMask) + BeepAtTheUser(); + else + next_input_focus(); + break; + case XK_Return: + if (!(event->xkey.state & ShiftMask)) { + next_input_focus(); + break; + } + + /* next ones fall through to input area handling */ + + case XK_Escape: + if (!gWindow->page->current_item) + break; + case XK_F1: + if (!gWindow->page->current_item) { + gWindow->page->helppage = alloc_string(NoMoreHelpPage); + helpForHyperDoc(); + break; + } + case XK_Home: + if (!gWindow->page->current_item) { + scrollToFirstPage(); + break; + } + case XK_Up: + if (!gWindow->page->current_item) { + scrollUp(); + break; + } + case XK_Down: + if (!gWindow->page->current_item) { + scrollDown(); + break; + } + + default: + display_again = 0; + dialog(event, keysym, key_buffer); + XFlush(gXDisplay); + break; + } + + if (display_again) { + display_page(gWindow->page); + gWindow->fWindowHashTable = gWindow->page->fLinkHashTable; + } +} + +/* + * This routine returns the modifier mask associated + * to a key symbol + */ + +static unsigned int +get_modifier_mask(KeySym sym) +{ + unsigned int i, mask; + XModifierKeymap *mod; + KeyCode kcode; + const int masks[8] = { + ShiftMask, LockMask, ControlMask, + Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask + }; + + mod = XGetModifierMapping(gXDisplay); + kcode = XKeysymToKeycode(gXDisplay,sym); + + if (mod) { + for (i = 0; i < (8 * mod->max_keypermod); i++){ + if (!mod->modifiermap[i]) continue; + else if (kcode == mod->modifiermap[i]){ + mask = masks[i / mod->max_keypermod]; + XFreeModifiermap(mod); + return mask; + } + } + XFreeModifiermap(mod); + } + return 0; +} + + + +/* + * This routine initializes some of the variables needed by the input + * strings, and boxes. + */ + +void +init_keyin(void) +{ + char *prop; + unsigned int nlm; + + nlm = get_modifier_mask(XK_Num_Lock); + UnsupportedModMask &= ~nlm; + ModifiersMask &= ~nlm; + + /* + * First set all the values for when the active cursor is in the window + */ + + in_cursor_height = 2; + in_cursor_y = gInputFont->max_bounds.ascent + + gInputFont->max_bounds.descent; + in_cursor_width = gInputFont->max_bounds.width; + + /* + * Now for when the cursor is empty + */ + + out_cursor_height = gInputFont->max_bounds.ascent + + gInputFont->max_bounds.descent; + out_cursor_y = 2; + out_cursor_width = in_cursor_width; + + start_x = 5; + + start_y = gInputFont->max_bounds.ascent; + + /* + * Find out How big I should make the simple boxes + */ + + simple_box_width = XTextWidth(gInputFont, "X", 1) + 5; + + prop = XGetDefault(gXDisplay, gArgv[0], "ProtectedQuit"); + + if (prop == NULL) { + protected_quit = (char *) halloc(strlen("ProtectedPage") + 1, + "protected_quit"); + strcpy(protected_quit, "ProtectedPage"); + } + else { + protected_quit = (char *) halloc(strlen(prop) + 1, "protected_quit"); + strcpy(protected_quit, prop); + } + + +} +@ +\section{dumpToken function} +We need a function to print the token object for debugging. + +To use this function the caller provides its own name and the +token to be printed. For instance, a call would look like: +\begin{verbatim} +dumpToken("fnname",token) +\end{verbatim} +There is no return value. +<>= +void +dumpToken(char *caller, Token t) +{ fprintf(stderr,"%s:dumpToken type=%s id=%s\n", + caller,token_table[t.type],t.id); +} + +@ + +\section{lex.h} +<>= +#ifndef _LEX_H_ +#define _LEX_H_ 1 + +<> + +extern HyperDocPage *gPageBeingParsed; + +extern short int gInSpadsrc; +extern short int gInVerbatim; + +#endif +@ +\section{lex.c} +<>= +/* + * Lexical analyzer stuff. Exported functions: parser_init() -- + * initialize the parser tables with keywords init_scanner() -- + * initialize scanner for reading a new page get_token() -- + * sets the "token" variable to be the next -- token in the current input + * stream save_scanner_state( ) -- save the current state of scanner so + * that -- the scanner input mode may be switched restore_scanner_state() -- + * undo the saved state + * + * Note: The scanner reads from three seperate input locations depending on the + * value of the variable "input_type". If this variable is: + * + * FromFile -- it read from the file pointed to by "cfile". FromString + * -- It reads from the string "input_string". FromSpadSocket -- It reads + * from the socket pointed to by spad_socket FromFD -- It reads from a + * file descriptor + * + * + * New variable useAscii -- tells us if we we should translate + * graphics characters on the fly + * initialised in init_scanner + * + */ +#define _LEX_C +#include "debug.h" + +int useAscii; + +#define PARSER 1 + +<> +<> +<> + +#include "all-hyper-proto.h1" +#include "sockio-c.h1" + + +#include +#include + +extern int gTtFontIs850; + + +StateNode *top_state_node; +HyperDocPage *gPageBeingParsed; /* page currently being parsed */ +extern jmp_buf jmpbuf; +extern char ebuffer[]; +short int gInSpadsrc = 0; +short int gInVerbatim; + +/* Parser variables */ +long fpos; /* Position of pointer in file in characters */ +long page_start_fpos; /* where the current pages fpos started */ +long keyword_fpos; /* fpos of beginning of most recent keyword */ +Token token; /* most recently read token */ +int last_token; /* most recently read token for unget_token */ +int input_type; /* indicates where to read input */ +char *input_string; /* input string read when from_string is true */ +int last_ch; /* last character read, for unget_char */ +int last_command; /* the last socket command */ +int keyword; /* the last command was a keyword, or a group */ +int cfd; /* current file decriptor */ +FILE *cfile; /* currently active file pointer */ +FILE *unixfd; +int line_number; + +char sock_buf[1024]; /* buffer for socket input */ + +#define TokenHashSize 100 + +static HashTable tokenHashTable; /* hash table of parser tokens */ + +<> + +/* initialize the parser keyword hash table */ +void +parser_init(void) +{ + int i; + Token *toke; + + /* First I initialize the hash table for the tokens */ + + hash_init( + &tokenHashTable, + TokenHashSize, + (EqualFunction)string_equal, + (HashcodeFunction)string_hash); + for (i = 2; i <= NumberUserTokens; i++) { + toke = (Token *) halloc(sizeof(Token), "Token"); + toke->type = i; + toke->id = token_table[i]; + hash_insert(&tokenHashTable, (char *)toke, toke->id); + } + +} + +/* initialize the lexical scanner to read from a file */ +void +init_scanner(void) +{ + if (getenv("HTASCII")) { + useAscii = (strcmp(getenv("HTASCII"), "yes") == 0); + } + else { + if(gTtFontIs850==1) useAscii = 0; + else useAscii = 1; + } + keyword = 0; + last_ch = NoChar; + last_token = 0; + input_type = FromFile; + fpos = 0; + keyword_fpos = 0; + last_command = -1; + line_number = 1; +} + +/* + * variables to save current state of scanner. Currently only one level of + * saving is allowed. In the future we should allow nested saves + */ + +/* save the current state of the scanner */ +void +save_scanner_state(void) +{ + StateNode *new_item = (StateNode *) halloc((sizeof(StateNode)), "StateNode"); + + new_item->page_start_fpos = page_start_fpos; + new_item->fpos = fpos; + new_item->keyword_fpos = keyword_fpos; + new_item->last_ch = last_ch; + new_item->last_token = last_token; + new_item->token = token; + new_item->input_type = input_type; + new_item->input_string = input_string; + new_item->cfile = cfile; + new_item->next = top_state_node; + new_item->keyword = keyword; + top_state_node = new_item; +} + +/* restore the saved scanner state */ +void +restore_scanner_state(void) +{ + StateNode *x = top_state_node; + + if (top_state_node == NULL) { + fprintf(stderr, "Restore Scanner State: State empty\n"); + exit(-1); + } + top_state_node = top_state_node->next; + page_start_fpos = x->page_start_fpos; + fpos = x->fpos; + keyword_fpos = x->keyword_fpos; + last_ch = x->last_ch; + last_token = x->last_token; + token = x->token; + input_type = x->input_type; + input_string = x->input_string; + cfile = x->cfile; + keyword = x->keyword; + if (cfile != NULL) + fseek(cfile, fpos + page_start_fpos, 0); + /** Once that is done, lets throw away some memory **/ + free(x); +} + +/* return the character to the input stream. */ +void +unget_char(int c) +{ + if (c == '\n') + line_number--; + last_ch = c; +} + +int +get_char(void) +{ + int c; + + c = get_char1(); + if (useAscii) { + switch (c) { + case 'Ä': + c = '-'; + break; + case 'Ú': + c = '+'; + break; + case 'Ã': + c = '['; + break; + case 'À': + c = '+'; + break; + case 'Â': + c = '-'; + break; + case 'Å': + c = '+'; + break; + case 'Á': + c = '-'; + break; + case '¿': + c = '+'; + break; + case '´': + c = ']'; + break; + case 'Ù': + c = '+'; + break; + case '³': + c = '|'; + break; + default: + break; + } + } + return c; +} + +char * read_again = 0; + +/* return the next character in the input stream */ +static int +get_char1(void) +{ + int c; + int cmd; + + if (last_ch != NoChar) { + c = last_ch; + last_ch = NoChar; + if (c == '\n') + line_number++; + return c; + } + switch (input_type) { + case FromUnixFD: + c = getc(unixfd); + if (c == '\n') + line_number++; + return c; + case FromString: + c = (*input_string ? *input_string++ : EOF); + if (c == '\n') + line_number++; + return c; + case FromFile: + c = getc(cfile); + fpos++; + if (c == '\n') + line_number++; + return c; + case FromSpadSocket: +AGAIN: + if (*input_string) { + /* this should never happen for the first character */ + c = *input_string++; + if (c == '\n') + line_number++; + return c; + } + if (last_command == EndOfPage) + return EOF; + if (read_again == NULL) { + last_command = cmd = get_int(spad_socket); + if (cmd == EndOfPage) + return EOF; +#ifndef HTADD + if (cmd == SpadError) + spad_error_handler(); +#endif + } + read_again = get_string_buf(spad_socket, sock_buf, 1023); + /* this will be null if this is the last time*/ + input_string = sock_buf; + goto AGAIN; + default: + fprintf(stderr, "Get Char: Unknown type of input: %d\n", input_type); + return -1; + } +} + + +#define special(c) ((c) == '{' || (c) == '}' || (c) == '#' || (c) == '%' || \ + (c) == '\\' || (c) == '[' || (c) == ']' || (c) == '_' || \ + (c) == ' ' || (c) == '$' || (c) == '~' || (c) == '^' || \ + (c) == '&') + +#define punctuation(c) ((c)== '`' || (c) == '\'' || (c) == ',' || \ + (c) == '.' || (c) == '?' || (c) == '"' || \ + (c) == ';' || (c) == ':' || (c) == '-') + +#define whitespace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define delim(c) \ + (whitespace(c) || special(c) || punctuation(c)) + + + +Token unget_toke; + +/* return current token to the input stream */ +void +unget_token(void) +{ + last_token = 1; + unget_toke.type = token.type; + unget_toke.id = alloc_string(token.id - 1); +} + + +int +get_token(void) +{ + int c, ws; + int nls = 0; + static int seen_white = 0; + static char buffer[1024]; + char *buf = buffer; + + if (last_token) { + last_token = 0; + token.type = unget_toke.type; + strcpy(buffer, unget_toke.id); + free(unget_toke.id); + token.id = buffer + 1; + if (token.type == EOF) + return EOF; + else + return 0; + } + seen_white = nls = 0; + do { + c = get_char(); + ws = whitespace(c); + if (ws) + seen_white++; + if (c == '\n') { + if (nls) { + token.type = Par; + return 0; + } + else + nls++; + } + } while (ws); + + /* first character of string indicates number of spaces before token */ + + if (!keyword) + *buf++ = seen_white; + else + *buf++ = 0; + + keyword = 0; + if (input_type != FromSpadSocket && c == '%') { + while ((c = get_char()) != '\n' && c != EOF); +/* trying to fix the comment problem: a comment line forces words on either side together*/ +/* try returning the eol */ + unget_char(c); + return get_token(); + } + if (input_type == FromFile && c == '$') { + token.type = Dollar; + return 0; + } + switch (c) { + case EOF: + token.type = -1; + return EOF; + case '\\': + keyword_fpos = fpos - 1; + c = get_char(); + if (!isalpha(c)) { + *buf++ = c; + token.type = Word; + *buf = '\0'; + seen_white = 0; + } + else { + do { + *buf++ = c; + } while ((c = get_char()) != EOF && isalpha(c)); + + unget_char(c); + *buf = '\0'; + keyword = 1; + token.id = buffer + 1; + return (keyword_type()); + } + break; + case '{': + token.type = Lbrace; + break; + case '}': + token.type = Rbrace; + break; + case '[': + token.type = Lsquarebrace; + *buf++ = c; + *buf = '\0'; + token.id = buffer + 1; + break; + case ']': + token.type = Rsquarebrace; + *buf++ = c; + *buf = '\0'; + token.id = buffer + 1; + break; + case '#': + token.type = Pound; + + /* + * if I get a pound then what I do is parse until I get something + * that is not an integer + */ + c = get_char(); + while (isdigit(c) && (c != EOF)) { + *buf++ = c; + c = get_char(); + } + unget_char(c); + *buf = '\0'; + token.id = buffer + 1; + break; + case '`': + case '\'': + case ',': + case '.': + case '!': + case '?': + case '"': + case ':': + case ';': + token.type = Punctuation; + *buf++ = c; + *buf = '\0'; + /** Now I should set the buffer[0] as my flag for whether I had + white-space in front of me, and whether I had white space + behind me **/ + if (buffer[0]) + buffer[0] = FRONTSPACE; + c = get_char(); + if (whitespace(c)) + buffer[0] |= BACKSPACE; + unget_char(c); + token.id = buffer + 1; + break; + case '-': + do { + *buf++ = c; + } while (((c = get_char()) != EOF) && (c == '-')); + unget_char(c); + *buf = '\0'; + token.type = Dash; + token.id = buffer + 1; + break; + default: + do { + *buf++ = c; + } while ((c = get_char()) != EOF && !delim(c)); + unget_char(c); + *buf = '\0'; + token.type = Word; + token.id = buffer + 1; + break; + } +/* dumpToken("get_token",token);*/ + return 0; +} + + +/* + * Here are the structures and stuff needed for the begin and end routines. + * The stack stores the begin types that have been seen and the end + * pops them off and checks to insure that they are reversed properly. + */ + +typedef struct be_struct { + int type; + char *id; + struct be_struct *next; +} BeStruct; + +BeStruct *top_be_stack; + + +void +push_be_stack(int type,char * id) +{ + BeStruct *be = (BeStruct *) halloc(sizeof(BeStruct), "BeginENd stack"); + + if (gWindow != NULL) { + be->type = type; + be->next = top_be_stack; + be->id = alloc_string(id); + top_be_stack = be; + } + return; +} +void +check_and_pop_be_stack(int type,char * id) +{ + BeStruct *x; + + /* + * this routine pops the be stack and compares types. If they are + * the same then I am okay and return a 1. Else I return a two and try to + * print a meaningful message + */ + if (gWindow == NULL) + return; + if (top_be_stack == NULL) { /* tried to pop when I shouldn't have */ + fprintf(stderr, "Unexpected \\end{%s} \n", token.id); + print_page_and_filename(); + print_next_ten_tokens(); + jump(); + } + x = top_be_stack; + if (x->type == type) { + top_be_stack = top_be_stack->next; + free(x->id); + free(x); + return; + } + /* else I didn't have a match. Lets try to write a sensible message */ + fprintf(stderr, "\\begin{%s} ended with \\end{%s} \n", x->id, id); + print_page_and_filename(); + print_next_ten_tokens(); + jump(); +} + +int +clear_be_stack(void) +{ + BeStruct *x = top_be_stack, *y; + + top_be_stack = NULL; + while (x != NULL) { + y = x->next; + free(x); + x = y; + } + return 1; +} + +int +be_type(char *which) +{ + Token store; + + get_expected_token(Lbrace); + get_expected_token(Word); + switch (token.id[0]) { + case 't': + if (!strcmp(token.id, "titems")) { + token.type = Begintitems; + } + else { + return -1; + } + break; + case 'p': + if (!strcmp(token.id, "page")) { + token.type = Page; + } + else if (!strcmp(token.id, "paste")) { + token.type = Paste; + } + else if (!strcmp(token.id, "patch")) { + token.type = Patch; + } + else { + return -1; + } + break; + case 'v': /* possibly a verbatim mode */ + if (!strcmp(token.id, "verbatim")) { + token.type = Verbatim; + } + else { + return -1; + } + break; + case 's': /* possibly a scroll mode */ + if (!strcmp("scroll", token.id)) { + token.type = Beginscroll; + } + else if (!strcmp(token.id, "spadsrc")) { + token.type = Spadsrc; + } + else { + return -1; + } + break; + case 'i': /* possibly a item */ + if (!strcmp("items", token.id)) { + token.type = Beginitems; + } + else { + return -1; + } + break; + default: + return -1; + } + store.type = token.type; + /* store.id = alloc_string(token.id); */ + get_expected_token(Rbrace); + token.type = store.type; + + /* + * strcpy(token.id, store.id); free(store.id); + */ + return 0; + +} +int +begin_type(void) +{ + /*Token store;*/ + int ret_val; + + /* + * This routine parses a statement of the form \begin{word}. Once it has + * read the word it tries to assign it a type. Once that is done it sends + * the word id, and the type to push_be_stack and then returns the type. + * For the moment I amnot even going to use a has_table, although in the + * future this may be needed + */ + ret_val = be_type("begin"); + if (ret_val == -1) { + if (gWindow == NULL || gInVerbatim) + return 1; + else { + fprintf(stderr, "Unknown begin type \\begin{%s} \n", token.id); + print_page_and_filename(); + print_next_ten_tokens(); + jump(); + } + } + else { + if (gWindow != NULL && !gInVerbatim && token.type != Verbatim + && token.type != Spadsrc) { + /* Now here I should push the needed info and then get */ + push_be_stack(token.type, token.id); + } + return 1; + } + return 1; +} + + +int +end_type(void) +{ + int ret; + + /* + * This routine gets the end type just as the begin_type routine does, + * But then it checks to see if recieved the proper end_type. By a clever + * trick, the proper end type is 3000 + type. When environments this will + * have to change + */ + ret = be_type("end"); + if (ret == -1) { + /* unrecognized end token */ + if (gWindow == NULL || gInVerbatim) { + return 1; + } + else { + fprintf(stderr, "Unknown begin type \\begin{%s} \n", token.id); + print_page_and_filename(); + print_next_ten_tokens(); + jump(); + } + } + else { + if (gWindow != NULL && !gInVerbatim) { + check_and_pop_be_stack(token.type, token.id); + token.type += 3000; + return 1; + } + else { + if (gWindow != NULL && ((gInVerbatim && token.type == Verbatim) || + (gInSpadsrc && token.type == Spadsrc))) { + check_and_pop_be_stack(token.type, token.id); + token.type += 3000; + return 1; + } + else { + token.type += 3000; + return 1; + } + } + } + return 1; +} + + + +static int +keyword_type(void) +{ + Token *token_ent; + + /* first check to see if it is a reserved token */ + token_ent = (Token *) hash_find(&tokenHashTable, token.id); + if (token_ent != NULL) { + token.type = token_ent->type; + + /* + * if I am a keyword I also have to check to see if I am a begin or + * an end + */ + if (token.type == Begin) + return begin_type(); + if (token.type == End) + return end_type(); + /* next check to see if it is a macro */ + } + else if (gWindow != NULL) { + if (hash_find(gWindow->fMacroHashTable, token.id) != NULL) + token.type = Macro; + else if (gPageBeingParsed->box_hash != NULL && + hash_find(gPageBeingParsed->box_hash, token.id) != NULL) + { + token.type = Boxcond; + } + else if (hash_find(gWindow->fCondHashTable, token.id) != NULL) + token.type = Cond; + else /* We have no idea what we've got */ + token.type = Unkeyword; + } + else { /* We am probably in htadd so just return. It + * is only concerned with pages anyway */ + token.type = Unkeyword; + } + return 0; +} + +/* read a token, and report a syntax error if it has the wrong type */ +void +get_expected_token(int type) +{ + get_token(); + if (token.type != type) { + token_name(type); + fprintf(stderr, "syntax error: expected a %s\n", ebuffer); + if (token.type == EOF) { + print_page_and_filename(); + fprintf(stderr, "Unexpected EOF\n"); + } + else { + token_name(token.type); + fprintf(stderr, "not a %s\n", ebuffer); + print_page_and_filename(); + print_next_ten_tokens(); + } + longjmp(jmpbuf, 1); + fprintf(stderr, "Could not jump to Error Page\n"); + exit(-1); + } +} + + +#ifndef HTADD +static void +spad_error_handler(void) +{ + /* fprintf(stderr, "got a spad error\n"); */ + longjmp(jmpbuf, 1); + fprintf(stderr, "(HyperDoc) Fatal Error: Could not jump to Error Page.\n"); + exit(-1); +} + +extern int still_reading, str_len; +void +reset_connection(void) +{ + if (spad_socket) { + FD_CLR(spad_socket->socket, &socket_mask); + purpose_table[spad_socket->purpose] = NULL; + close(spad_socket->socket); + spad_socket->socket = 0; + spad_socket = NULL; + if (input_string) + input_string[0] = '\0'; + read_again = 0; + str_len = 0; + still_reading = 0; + connect_spad(); + } +} +#endif + + +/* returns true if spad is currently computing */ +int +spad_busy(void) +{ + if (session_server == NULL) + return 1; + send_int(session_server, QuerySpad); + return get_int(session_server); +} + +/* connect to AXIOM , return 0 if succesful, 1 if not */ +int +connect_spad(void) +{ + if (!MenuServerOpened) { + fprintf(stderr, "(HyperDoc) Warning: Not connected to AXIOM Server!\n"); + LoudBeepAtTheUser(); + return NotConnected; + } + if (spad_socket == NULL) { + spad_socket = connect_to_local_server(SpadServer, MenuServer, Forever); + if (spad_socket == NULL) { + fprintf(stderr, "(HyperDoc) Warning: Could not connect to AXIOM Server!\n"); + LoudBeepAtTheUser(); + return NotConnected; + } + } + /* if (spad_busy()) return SpadBusy; */ + return Connected; +} +@ +\section{macro.c} +<>= +#define _MACRO_C +#include "debug.h" + +<> +<> +<> + +#include "all-hyper-proto.h1" + + +/* #define DEBUG 1 */ +extern FILE *cfile; + + +/* + * This routine keeps scanning until it reaches it pops off 1 more + * right brace then left brace + */ +void +scan_HyperDoc(void) +{ + HDWindow *twin = gWindow; + int ret_val; + int number_of_left_braces = 1; + + gWindow = NULL; + while (number_of_left_braces) { + ret_val = get_token(); + if (ret_val == EOF && number_of_left_braces) { + fprintf(stderr, "Scan_Hypertex: Unexpected End of File\n"); + longjmp(jmpbuf, 1); + } + switch (token.type) { + case Page: + fprintf(stderr, "scan_HyperDoc: Unexpected Page Declaration\n"); + break; + case NewCommand: + fprintf(stderr, "scan_HyperDoc: Unexpected Macro Declaration\n"); + break; + case Lbrace: + number_of_left_braces++; + break; + case Endpatch: + case Rbrace: + number_of_left_braces--; + break; + default: + break; + } + } + gWindow = twin; +} + +int +number(char *str) +{ + char *t = str; + + while (*t) + if (!isdigit(*t++)) + return 0; + return 1; +} + +/* Parse a given macro given the pointer to the unlaoded macro ** */ + +static char * +load_macro(MacroStore *macro) +{ + int ret_val; + long start_fpos; + int size = 0; + char *trace; + char *macro_buff; + + save_scanner_state(); + cfile = find_fp(macro->fpos); + + + init_scanner(); + + /** First thing I should do is make sure that the name is correct ***/ + get_expected_token(NewCommand); + get_expected_token(Lbrace); + get_expected_token(Macro); + if (strcmp(token.id, macro->name)) { + /** WOW, Somehow I had the location of the wrong macro **/ + fprintf(stderr, "Expected macro name %s got insted %s in load_macro\n", + macro->name, token.id); + longjmp(jmpbuf, 1); + } + get_expected_token(Rbrace); + + /** Next I should check to see if I have any parameters **/ + get_token(); + if (token.type == Lsquarebrace) { + /** The person is telling me the number of macros he is going to use **/ + get_expected_token(Word); + if (!number(token.id)) { + fprintf(stderr, "load_macro: Expected A Value Instead Got %s\n", + token.id); + longjmp(jmpbuf, 1); + } + /** if it is a number, then I should store it in the parameter number + member of the macro structure **/ + macro->number_parameters = atoi(token.id); +#ifdef DEBUG + fprintf(stderr, + "The number of parameters is %d\n", macro->number_parameters); +#endif + get_expected_token(Rsquarebrace); + get_token(); + } + else + macro->number_parameters = 0; + + /*** Now I should be able to check the token, and insure that I have read + a leftbrace, then the string will follow ****/ + if (token.type != Lbrace) { + /** The macro is not in a group, uh oh **/ + fprintf(stderr, "load_macro:Expected a Left Brace got type %d\n", + token.type); + longjmp(jmpbuf, 1); + } + start_fpos = fpos; + scan_HyperDoc(); + ret_val = fseek(cfile, macro->fpos.pos + start_fpos, 0); + size = fpos - start_fpos; + macro_buff = (char *) halloc((size + 1) * sizeof(char), "Macro_buf"); + for (size = 0, trace = macro_buff; size < fpos - (start_fpos) - 1; size++) + *trace++ = getc(cfile); + *trace = '\0'; + macro->loaded = 1; + restore_scanner_state(); + return macro_buff; +} + + +/** Here are the functions and declarations for the parameter stack **/ +ParameterList parameters = NULL; + +ParameterList +init_parameter_elem(int number) +{ + ParameterList new; + int count; + + /** allocate the space neeeded **/ + new = (ParameterList) halloc(sizeof(struct parameter_list_type), + "ParameterList"); + /** now allocate the memeory for the pointers to the parameters **/ + if (number) { + new->list = (char **) halloc(number * sizeof(char *), "Parameter List"); + + /** initialize my pointers **/ + for (count = 0; count < number; count++) + (new->list)[count] = NULL; + } + new->number = number; + return new; +} + +int +push_parameters(ParameterList new) +{ + + if (new == NULL) { + fprintf(stderr, "Tried pushing a null list onto the parameter stack\n"); + longjmp(jmpbuf, 1); + } + + new->next = parameters; + parameters = new; + return 1; +} +int +pop_parameters(void) +{ + /** Simply pops the top of the parameter list, being good and freeing + all the memory **/ + ParameterList old; + int count; + + if (!parameters) { + return 0; + } + + old = parameters; + parameters = old->next; + + /** Free the parameter text and pointers **/ + if (old->number >0) { + for (count = 0; count < old->number; count++) + if ( (old->list)[count] ) free((char *) (old->list)[count]); + free(old->list); + } + + free(old); /** free the parameter **/ + + return 1; +} + +int +parse_macro(void) +{ + + /* + * This routine loads a macro if needed, and then parses it from the + * string + */ + MacroStore *macro; + int s; + + curr_node->type = Macro; + curr_node->space = token.id[-1]; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + macro = (MacroStore *) hash_find(gWindow->fMacroHashTable, token.id); + if (macro != NULL) { + if (!macro->loaded) + macro->macro_string = load_macro(macro); + get_parameter_strings(macro->number_parameters, macro->name); + parse_from_string(macro->macro_string); + if (gEndedPage) { + s = curr_node->type; + curr_node->type = Endmacro; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + curr_node->type = s; + } + else + curr_node->type = Endmacro; + if (pop_parameters()) + return 1; + else { + fprintf(stderr, + "parse_macro: Tried to pop an empty paramter stack\n"); + longjmp(jmpbuf, 1); + } + } + else { + fprintf(stderr, "parse_macro: Unknown keyword %s\n", token.id); + longjmp(jmpbuf, 1); + } +} + +#define numeric(c) ((c >= '0' && c <= '9')?1:0) + +static void +get_parameter_strings(int number,char * macro_name) +{ + static char buffer[4096]; + char *buffer_pntr; + int count; + int lbrace_counter; + char c; + int size; + ParameterList new = init_parameter_elem(number); + int pnum; + char pnum_chars[5]; + int pc; + + if (!number) { /* nothing to be done */ + push_parameters(new); + return; + } + for (count = 0; count < number; count++) { + get_token(); + if (token.type != Lbrace) { + /** The macro is not in a group, uh oh **/ + fprintf(stderr, "Wrong number of arguments to the macro %s\n", + macro_name); + jump(); + } + for (lbrace_counter = 1, buffer_pntr = buffer; + lbrace_counter;) { + switch (c = get_char()) { + case EOF: + fprintf(stderr, "GetParameterStrings: Unexpected EOF\n"); + longjmp(jmpbuf, 1); + case '}': + lbrace_counter--; + if (lbrace_counter) + *buffer_pntr++ = c; + break; + case '{': + lbrace_counter++; + *buffer_pntr++ = c; + break; + case '#': + /* uh oh, I have a paramter reference inside a paramter */ + /* get the number */ + if (parameters == NULL) { + *buffer_pntr++ = c; + break; + } + if ( + ((buffer_pntr > buffer + 1) && + *(buffer_pntr - 1) == '\\' && + *(buffer_pntr - 2) != '\\') || + ((buffer_pntr > buffer) && + *(buffer_pntr - 1) == '\\')) { + /* I had a \# */ + *buffer_pntr++ = c; + } + else { + c = get_char(); + for (pc = 0; numeric(c); pc++) { + pnum_chars[pc] = c; + c = get_char(); + } + unget_char(c); + pnum_chars[pc] = '\0'; + pnum = atoi(pnum_chars); + pc = 0; + /* Now copy the paramter */ + while ((parameters->list)[pnum - 1][pc] != '\0') + *buffer_pntr++ = (parameters->list)[pnum - 1][pc++]; + } + break; + default: + *buffer_pntr++ = c; + break; + } + } + *buffer_pntr = '\0'; + /*** Now add it to the current parameter list **/ + size = strlen(buffer) + 1; + new->list[count] = (char *) halloc(size, "Parameter Strings"); + strcpy(new->list[count], buffer); + } + push_parameters(new); + return ; +} +void +parse_parameters(void) +{ + int value; + + if (!number(token.id)) { + fprintf(stderr, + "Parse_parameter: Error Expected a number, got %s instead\n", + token.id); + longjmp(jmpbuf, 1); + } + + if ((value = atoi(token.id)) > parameters->number) { + /** had a bad parameter number **/ + fprintf(stderr, + "Parse_parameter: Had a bad parameter number %d\n", value); + longjmp(jmpbuf, 1); + } + + parse_from_string((parameters->list)[value - 1]); + curr_node->type = Endparameter; + return; +} +@ +\section{mem.h} +<>= +#ifndef _MEM_H_ +#define _MEM_H_ 1 + +<> + + +#endif +@ +\section{mem.c} +<>= +/****************************************************************************** + * + * mem.c: HyperDoc Memory Management Routines. + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _MEM_C +#include "debug.h" + + +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + + + +extern HashTable init_page_hash; +extern HashTable init_macro_hash; +extern HashTable init_patch_hash; + + +static void +free_if_non_NULL(void *p) +{ + if (p){ + free(p); + } +} + + +/* allocate an HDWindow Structure and initialize it */ + +HDWindow * +alloc_hd_window(void) +{ + HDWindow *w = (HDWindow *) halloc(sizeof(HDWindow), "HDWindow"); + /*char haslisp[10];*/ + + w->fMemoStack = (HyperDocPage **) + halloc(MaxMemoDepth * sizeof(HyperDocPage *), "Memo Stack"); + w->fDownLinkStack = (HyperDocPage **) + halloc(MaxDownlinkDepth * sizeof(HyperDocPage *), "downlink stack"); + w->fDownLinkStackTop = + (int *) halloc(MaxDownlinkDepth * sizeof(int), "top downlink stack"); + w->fAxiomFrame = 0; + init_page_structs(w); + + /* Now I initialize the hash tables for the page */ + w->fCondHashTable = (HashTable *) halloc(sizeof(HashTable), "cond hash"); + hash_init( + w->fCondHashTable, + CondHashSize, + (EqualFunction) string_equal, + (HashcodeFunction) string_hash); + + w->fPasteHashTable = (HashTable *) halloc(sizeof(HashTable), "paste hash"); + hash_init( + w->fPasteHashTable, + PasteHashSize, + (EqualFunction) string_equal, + (HashcodeFunction) string_hash); + w->fPageHashTable = hash_copy_table(&init_page_hash); + w->fPatchHashTable = hash_copy_table(&init_patch_hash); + w->fMacroHashTable = hash_copy_table(&init_macro_hash); + + gWindow = w; + /*sprintf(haslisp, "%1d\0", MenuServerOpened);*/ + make_special_pages(w->fPageHashTable); + w->fDisplayedCursor = 0; + return w; +} + +void +free_hd_window(HDWindow *w) +{ + if (w) { + free(w->fMemoStack); + free(w->fDownLinkStack); + free(w->fDownLinkStackTop); + /* + free(w->fWindowHashTable); will be taken care of by freeing + free_hash(w->fPageHashTable, free_page); below + cf free_page + */ + free_hash(w->fMacroHashTable, (FreeFunction)dont_free); + free_hash(w->fPasteHashTable, (FreeFunction)dont_free); + free_hash(w->fPatchHashTable, (FreeFunction)dont_free); + + free_hash(w->fCondHashTable, (FreeFunction)free_cond); + free_hash(w->fPageHashTable, (FreeFunction)free_page); + free(w->fPageHashTable); + free(w->fPatchHashTable); + free(w->fMacroHashTable); + XFreeGC(gXDisplay, w->fStandardGC); + XFreeGC(gXDisplay, w->fInputGC); + XFreeGC(gXDisplay, w->fCursorGC); + XFreeGC(gXDisplay, w->fControlGC); + free(w); + } +} + + +/* Allocate an empty text node */ + +TextNode * +alloc_node(void) +{ + TextNode *temp_node; + + temp_node = (TextNode *) halloc(sizeof(TextNode), "Text Node"); + temp_node->type = 0; + temp_node->space = 0; + temp_node->height = 0; + temp_node->width = 0; + temp_node->x = -1; + temp_node->y = -1; + temp_node->data.node = NULL; + temp_node->next = NULL; + temp_node->link = NULL; + temp_node->image.pm = 0; + return temp_node; +} + +void +free_node(TextNode *node, short int des) +{ + + if (node == NULL) + return; + + switch (node->type) { + case Paste: + free_pastearea(node, des); + free_node(node->next, des); + break; + case Pastebutton: + free_pastebutton(node, des); + free_node(node->next, des); + break; + case Ifcond: + free_node(node->data.ifnode->cond, des); + free_node(node->data.ifnode->thennode, des); + free_node(node->data.ifnode->elsenode, des); + break; + case Dash: + case Lsquarebrace: + case Word: + case WindowId: + case Punctuation: + case Lbrace: + case Rbrace: + case SimpleBox: + case Verbatim: + case Math: + case Spadsrctxt: + case Spadsrc: + free_if_non_NULL(node->data.text); + free_node(node->next, des); + break; + case Inputstring: + if (des) + delete_item(node->data.text); + free_if_non_NULL(node->data.text); + free_node(node->next, des); + break; + case It: + case Sl: + case Tt: + case Rm: + case Emphasize: + case Beep: + case BoldFace: + case Par: + case Newline: + case Horizontalline: + case Item: + case Beginscroll: + case Endscroll: + case Group: + case Table: + case Macro: + case Pound: + case Center: + case Box: + case Mbox: + case Tableitem: + case Scrollingnode: + case Headernode: + case Titlenode: + case Footernode: + case Controlbitmap: + case Fi: + case Description: + case Rsquarebrace: + case Endpaste: + case Endpastebutton: + free_node(node->next, des); + break; + case Inputbitmap: + case Inputpixmap: + free_if_non_NULL(node->data.text); + free_node(node->next, des); + break; + case Quitbutton: + case Helpbutton: + case Upbutton: + case Returnbutton: + if (des && node->link->win) { + hash_delete(gWindow->page->fLinkHashTable,(char *) &node->link->win); + XDestroyWindow(gXDisplay, node->link->win); + } + free_if_non_NULL(node->link); + free_node(node->next, des); + break; + case Memolink: + case Downlink: + case Windowlink: + case Link: + case Lisplink: + case Lispwindowlink: + case Spadcall: + case Spadcallquit: + case LispMemoLink: + case Lispcommand: + case Lispcommandquit: + case LispDownLink: + case Unixlink: + case Spadlink: + case Spadmemolink: + case Spaddownlink: + case Unixcommand: + case Spadcommand: + case Spadgraph: + if (des && node->link->win) { + hash_delete(gWindow->page->fLinkHashTable,(char *) &node->link->win); + XDestroyWindow(gXDisplay, node->link->win); + } + /* TTT don't free the link before freeing nodes off it */ + /* free_node(node->link->reference.node);*/ + free_if_non_NULL(node->link); + free_node(node->next, des); + break; + case Free: + case Indent: + case Indentrel: + case HSpace: + case Space: + case VSpace: + case Button: + case Bound: + case Tab: + free_node(node->next, des); + free_node(node->data.node, des); + break; + case End: + case Endcenter: + case Endlink: + case Endgroup: + case Endbox: + case Endmbox: + case Endspadcommand: + case Endpix: + case Endmacro: + case Endparameter: + case Endtable: + case Endtableitem: + case Noop: + case Endinputbox: + case Enddescription: + case Endif: + case Endtitems: + case Enditems: + case Endverbatim: + case Endmath: + case Endspadsrc: + free_node(node->next, des); + break; + case Endheader: + case Endtitle: + case Endfooter: + case Endscrolling: + case Endarg: + break; + case Endbutton: + case Beginitems: + free_if_non_NULL(node->data.text); + free_node(node->next, des); + break; + + default: + + /* printf("don't know how to free type %d\n", node->type); */ + return; + } + free(node); +} + +IfNode * +alloc_ifnode(void) +{ + IfNode *tempif; + + tempif = (IfNode *) halloc(sizeof(struct if_node), "IfNode"); + tempif->thennode = tempif->elsenode = tempif->cond = NULL; + return tempif; +} + +CondNode * +alloc_condnode(void) +{ + CondNode *temp; + + temp = (CondNode *) halloc(sizeof(struct cond_node), "Cond Node"); + temp->cond = temp->label = NULL; + return temp; +} + +static void +free_cond(CondNode *cond) +{ + if (cond) { + free(cond->label); + if (cond->cond) + free(cond->cond); + free(cond); + } +} + +/* Allocate a new HyperDoc page */ + +HyperDocPage * +alloc_page(char *name) +{ + HyperDocPage *page; + + page = (HyperDocPage *) halloc(sizeof(HyperDocPage), "HyperDocPage"); + page->name = name; + page->header = page->scrolling = page->footer = page->title = NULL; + page->scroll_off = 0; + page->sock = NULL; + page->box_hash = page->depend_hash = NULL; + page->fLinkHashTable = (HashTable *) halloc(sizeof(HashTable), "Page->fLinkHashTable"); + page->input_list = page->current_item = NULL; + page->page_flags = 0000000; + page->filename = NULL; + page->helppage = alloc_string(TopLevelHelpPage); + page->radio_boxes = NULL; + page->button_list = NULL; + page->s_button_list = NULL; + return page; +} + +void +free_page(HyperDocPage *page) +{ + /* + * This routine now checks for an environment variable NOFREE. If found + * it returns. + */ + + if (page == NULL) + return; + + switch (page->type) { + case UlUnknownPage: + case UnknownPage: + case ErrorPage: + case Unixfd: + case SpadGen: + case Normal: + + /* + * if(page->name) free(page->name); if(page->filename) + * free(page->filename); + */ + free_node(page->scrolling, 0); + free_node(page->header, 0); + free_node(page->footer, 0); + free_node(page->title, 0); + free_button_list(page->s_button_list); + free_button_list(page->button_list); +/* + if (page->sock != NULL) + free(page->sock); */ + free_hash(page->depend_hash, (FreeFunction)free_depend); + /* TTT line below causes freeing of freed memory and freed memory reads + links should have been freed by the recursive free_node's above (cf.free_node) + this is apparently because we are called from free_hd_window + and we had made a call to free w->fWindowHashTable which is made + to point to the same thing + so we do it HERE not THERE + */ + free_hash(page->fLinkHashTable, (FreeFunction)dont_free); + free_hash(page->box_hash, (FreeFunction)free_input_box); + free_input_list(page->input_list); + free_radio_boxes(page->radio_boxes); + free(page->helppage); + free(page); + break; + case UnloadedPageType: + break; + default: + /* fprintf(stderr, "Unknown Page type: %d\n", page->type); */ + break; + } +} + +static void +free_paste(PasteNode *paste, short int des) +{ + if (paste) { + free_group_stack(paste->group); + free_item_stack(paste->item_stack); + free_node(paste->arg_node, des); + free(paste); + } +} + +static void +free_pastebutton(TextNode *node, short int des) +{ + /* + * if I am freeing from within parse patch, then I have to do some + * special things first + */ + + + /* the following seems to be unused */ + if (gActiveWindow == node->link->win) + gActiveWindow = -1; + + + + if (des) { + PasteNode *paste; + paste = (PasteNode *) hash_find(gWindow->fPasteHashTable, node->data.text); + + if (!paste->haspaste) { + /* squash this thing */ + + hash_delete(gWindow->fPasteHashTable, (char *)node->data.text); + free_paste(paste, des); + hash_delete(gWindow->page->fLinkHashTable,(char *) &node->link->win); + + XDestroyWindow(gXDisplay, node->link->win); + } + else + paste->hasbutton = 0; + } + + free_if_non_NULL(node->data.text); + +} + +static void +free_pastearea(TextNode *node, short int des) +{ + if (des) { + PasteNode *paste; + paste = (PasteNode *) hash_find(gWindow->fPasteHashTable, node->data.text); + if (paste) { + if (!paste->hasbutton) { + /* squash this thing */ + hash_delete(gWindow->fPasteHashTable, node->data.text); + free_paste(paste, des); + } + else + paste->haspaste = 0; + } + } + + free_if_non_NULL(node->data.text); +} + + +void +free_string(char *str) +{ + free_if_non_NULL(str); +} + +static void +free_depend(SpadcomDepend *sd) +{ + free_if_non_NULL((char *) sd); +} + +static void +dont_free(void *link) +{ + return; +} + +#if 0 +----------- NOT USED +static void +free_link(HyperLink *link) +{ + printf("Link type %d\n",link->type); + free_if_non_NULL((char *) link); +} +----------- NOT USED +#endif + +static void +free_lines(LineStruct *lines) +{ + if (lines->prev != NULL) + lines->prev->next = NULL; + while (lines != NULL) { + LineStruct *del; + del = lines; + lines = lines->next; + free(del->buffer); + free(del); + } +} + +void +free_input_item(InputItem *sym, short int des) +{ + free_if_non_NULL(sym->name); + free_lines(sym->lines); + if (des) + XDestroyWindow(gXDisplay, sym->win); +} + +void +free_input_list(InputItem *il) +{ + while (il) { + InputItem *trash = il; + il = il->next; + free_input_item(trash, 0); + free(trash); + } +} + +static void +free_input_box(InputBox *box) +{ + if (box) { + free_if_non_NULL(box->name); + free(box); + } +} + +static void +free_radio_boxes(RadioBoxes *radio) +{ + if (radio) { + free_radio_boxes(radio->next); + free_if_non_NULL(radio->name); + free(radio); + } +} + +#if 0 +--------------- NOT USED +static void +free_image(ImageStruct *image) +{ + free(image->image.xi->data); + free(image->image.xi); + free(image); +} +--------------- NOT USED +#endif + +#if 0 +--------------- NOT USED +static void +free_macro(MacroStore *macro) +{ + if (macro) { + free(macro->name); + if (macro->macro_string) + free(macro->macro_string); + free(macro); + } +} +--------------- NOT USED +#endif + + + +LineStruct * +alloc_inputline(int size) +{ + int i; + LineStruct *line = + (LineStruct *) halloc(sizeof(LineStruct), "Line Structure"); + + line->prev = line->next = NULL; + line->buffer = (char *) halloc(sizeof(char) * size + 2, "symbol buffer"); + for (i = 0; i < size + 2; i++) + line->buffer[i] = 0; + line->buff_pntr = line->len = 0; + return line; +} + +PasteNode * +alloc_paste_node(char *name) +{ + PasteNode *pastenode = + (PasteNode *) halloc(sizeof(PasteNode), "PasteNode"); + + pastenode->group = NULL; + pastenode->item_stack = NULL; + pastenode->arg_node = NULL; + pastenode->end_node = NULL; + pastenode->name = alloc_string(name); + pastenode->haspaste = pastenode->hasbutton = 0; + return pastenode; +} + +PatchStore * +alloc_patchstore(void) +{ + PatchStore *p = (PatchStore *) halloc(sizeof(PatchStore), "PatchStore"); + + p->loaded = 0; + p->string = NULL; + return p; +} + +void +free_patch(PatchStore *p) +{ + if (p) { + if (p->name) + free(p->name); + if (p->fpos.name) + free(p->fpos.name); + if (p->string) + free(p->string); + free(p); + } +} + +InputBox * +alloc_inputbox(void) +{ + InputBox *box = (InputBox *) halloc(sizeof(InputBox), "InputBox"); + + box->picked = 0; + box->next = NULL; + box->rbs = NULL; + return box; +} + +RadioBoxes * +alloc_rbs(void) +{ + RadioBoxes *newrb = (RadioBoxes *) halloc(sizeof(RadioBoxes), "Radio Boxes"); + + newrb->next = NULL; + newrb->boxes = NULL; + return newrb; +} + +ButtonList * +alloc_button_list(void) +{ + ButtonList *newbl = (ButtonList *) halloc(sizeof(ButtonList), "Button List"); + + newbl->link = NULL; + newbl->x0 = newbl->y0 = newbl->x1 = newbl->y1 = 0; + newbl->next = NULL; + return newbl; +} + +void +free_button_list(ButtonList *bl) +{ + while (bl) { + ButtonList *nbl = bl->next; + free(bl); + bl = nbl; + } +} + + +/* resizable static buffers */ + +#define BufferSlop 0 + +char * +resizeBuffer(int size, char *oldBuf, int *oldSize) +{ + char *newBuf; + int newSize; + + if (size <= *oldSize) + return oldBuf; + + newSize = size + BufferSlop; + newBuf = (char *) halloc(newSize,"Buffer"); + memset(newBuf,'\0',newSize); + if (oldBuf) { + memcpy(newBuf, oldBuf, *oldSize); + free(oldBuf); + } + *oldSize = newSize; + + return newBuf; +} +@ +\section{parse-aux.h} +<>= +#ifndef _PARSE_AUX_H_ +#define _PARSE_AUX_H_ 1 + +<> + +#endif @ -<<*>>= -<> -<> +\section{parse-aux.c} +<>= +#define _PARSE_AUX_C +#include "debug.h" + +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + + +extern FILE *cfile; +extern int make_input_file; +extern int gverify_dates; + +InputBox *rb_list; +InputBox *end_rb_list; + +HashTable ht_gFileHashTable; + +#define htfhSize 100 + +/* Hash functions for active link windows */ + +int +window_equal(Window *w1, Window *w2) +{ + return *w1 == *w2; +} + +/* hash code for a window */ + +int +window_code(Window *w, int size) +{ + return (*w) % size; +} + +char * +window_id(Window w) +{ + char *ret; + char buff[32]; + int length; + + sprintf(buff, "%ld", w); + length = strlen(buff); + ret = (char *) halloc(length * sizeof(char) + 1, "windowid"); + strcpy(ret, buff); + return (ret); +} + +/* + * This procedure reads the ht database. It makes repeated calls to + * db_file_open, and while the returned pointer is not null, it continues to + * read the presented data base files + */ +void +read_ht_db(HashTable *page_hash, HashTable *macro_hash, HashTable *patch_hash) +{ + FILE *db_fp; + char db_file[256]; + int i = 0; + + gDatabasePath = NULL; + + hash_init( + page_hash, + PageHashSize, + (EqualFunction) string_equal, + (HashcodeFunction) string_hash); + hash_init( + macro_hash, + MacroHashSize, + (EqualFunction) string_equal, + (HashcodeFunction) string_hash); + hash_init( + patch_hash, + PatchHashSize, + (EqualFunction) string_equal, + (HashcodeFunction) string_hash); + + /* Lets initialize the FileHashTable */ + hash_init( + &ht_gFileHashTable, + htfhSize, + (EqualFunction) string_equal, + (HashcodeFunction) string_hash); + + while ((db_fp = db_file_open(db_file)) != NULL) { + i++; + read_ht_file(page_hash, macro_hash, patch_hash, db_fp, db_file); + fclose(db_fp); + } + + if (!i) { + fprintf(stderr, + "(HyperDoc) read_ht_db: No %s file found\n", db_file_name); + exit(-1); + } + + free_hash(&ht_gFileHashTable, (FreeFunction)free_string); +} + +/* + * This procedure reads a single HyperDoc database file. It is passed an already + * initilaized file pointer. It reads the whole file, updating the + * page hash, or the macro hash only when a previous entry with the same name + * is not found + */ + +static void +read_ht_file(HashTable *page_hash, HashTable *macro_hash, + HashTable *patch_hash, FILE *db_fp, char *db_file) +{ + char filename[256]; + char *fullname = filename; + UnloadedPage *page; + MacroStore *macro; + PatchStore *patch; + int pages = 0, c, mtime, ret_val; + struct stat fstats; + /*short time_ok = 1;*/ +/* fprintf(stderr,"parse-aux:read_ht_file: dp_file=%s\n",db_file);*/ + cfile = db_fp; + init_scanner(); + ret_val = strlen(db_file) - 1; + for (; ret_val >= 0; ret_val--) + if (db_file[ret_val] == '/') { + db_file[ret_val] = '\0'; + break; + } + c = getc(db_fp); + do { + if (c == '\t') { + get_filename(); + fullname = alloc_string(token.id); + if (fullname[0] != '/') { + strcpy(filename, db_file); + strcat(filename, "/"); + strcat(filename, fullname); + free(fullname); + fullname = alloc_string(filename); + } + + /* + * Until I get a filename that I have not seen before, just keep + * reading + */ + while (hash_find(&ht_gFileHashTable, fullname) != NULL) { + do { + c = getc(db_fp); + } while ((c != EOF) && (c != '\t')); + if (c == EOF) + return; + get_filename(); + fullname = alloc_string(token.id); + if (fullname[0] != '/') { + strcpy(filename, db_file); + strcat(filename, "/"); + strcat(filename, fullname); + free(fullname); + fullname = alloc_string(filename); + } + } +/* fprintf(stderr,"parse-aux:read_ht_file: fullname=%s\n",fullname);*/ + /* If I got here, then I must have a good filename */ + hash_insert(&ht_gFileHashTable, fullname, fullname); + + ret_val = stat(fullname, &fstats); + if (ret_val == -1) { + char buffer[300]; + + sprintf(buffer, "(HyperDoc) read_ht_db: Unable To Open %s :", fullname); + perror(buffer); + exit(-1); + } + get_token(); + mtime = atoi(token.id); + if (gverify_dates & (fstats.st_mtime > mtime)) { + fprintf(stderr, "(HyperDoc) read_ht_file: HyperDoc file %s has been updated\n", + + fullname); + fprintf(stderr, "(HyperDoc) Issue htadd %s to update database\n", fullname); + exit(-1); + } + while ((c = getc(db_fp)) != EOF) { + if (c == '\t') + break; + ungetc(c, db_fp); + get_token(); + switch (token.type) { + case Page: + get_token(); + + /* + * now check to see if the page has already been + * loaded + */ + page = (UnloadedPage *) halloc(sizeof(UnloadedPage), + "UnloadedPage"); + page->fpos.name = alloc_string(fullname); + page->name = alloc_string(token.id); + get_token(); + if (hash_find(page_hash, page->name) != NULL) { + fprintf(stderr, "(HyperDoc) Page name %s occurred twice\n", page->name); + fprintf(stderr, "(HyperDoc) The Version in %s is being ignored \n", + page->fpos.name); + free(page); + get_token(); + break; + } + page->fpos.pos = atoi(token.id); + get_token(); + page->fpos.ln = atoi(token.id); + page->type = UnloadedPageType; + hash_insert(page_hash, (char *)page, page->name); + pages++; + break; + case NewCommand: + get_token(); + macro = (MacroStore *) halloc(sizeof(MacroStore), "MacroStore"); + macro->fpos.name = alloc_string(fullname); + macro->name = alloc_string(token.id); + macro->macro_string = NULL; + get_token(); + if (hash_find(macro_hash, macro->name) != NULL) { + if (strcmp(macro->name, "localinfo") != 0) { + fprintf(stderr, "(HyperDoc) Macro name %s occurred twice\n", + macro->name); + fprintf(stderr, "(HyperDoc) The Version in %s is being ignored \n", + macro->fpos.name); + } + get_token(); + free(macro); + break; + } + macro->fpos.pos = atoi(token.id); + get_token(); + macro->fpos.ln = atoi(token.id); + macro->loaded = 0; + hash_insert(macro_hash, (char *)macro, macro->name); + break; + case Patch: + get_token(); + patch = (PatchStore *) alloc_patchstore(); + patch->fpos.name = alloc_string(fullname); + patch->name = alloc_string(token.id); + get_token(); + patch->fpos.pos = atoi(token.id); + get_token(); + patch->fpos.ln = atoi(token.id); + if (hash_find(patch_hash, patch->name) != NULL) { + fprintf(stderr, "(HyperDoc) Patch name %s occurred twice\n", patch->name); + fprintf(stderr, "(HyperDoc) The version in %s is being ignored \n", + patch->fpos.name); + free_patch(patch); + break; + } + hash_insert(patch_hash, (char *)patch, patch->name); + break; + default: + fprintf(stderr, "(HyperDoc) read_ht_db: Unknown type %s in ht.db\n", token.id); + exit(-1); + break; + } + } + } + else + c = getc(db_fp); + } while (c != EOF); +/* fprintf(stderr, + "parse-aux:read_ht_file:read %d pages from database\n", pages); */ +} + + +/* create an unmapped input-only window for an active screen area */ + +HyperLink * +make_link_window(TextNode *link_node, int type, int isSubWin) +{ + HyperLink *link; + XSetWindowAttributes at; + + if (make_input_file) + switch (type) { + case Downlink: + case Memolink: + case Windowlink:{ + char *name; + HyperDocPage *p; + + name = print_to_string(link_node); + p = (HyperDocPage *) hash_find(gWindow->fPageHashTable, name); + if (!p) + printf("undefined link to %s\n", name); + break; + } + } + else { + link = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"); + if (link == NULL) { + fprintf(stderr, "(HyperDoc) Ran out of memory allocating a hypertext link!\n"); + exit(-1); + } + at.cursor = gActiveCursor; + at.event_mask = ButtonPress; + if (isSubWin) + link->win = XCreateWindow(gXDisplay, gWindow->fDisplayedWindow, 0, 0, 100, 100, 0, + 0, InputOnly, CopyFromParent, + CWEventMask | CWCursor, &at); + else + link->win = 0; + link->type = type; + link->x = link->y = 0; + link->reference.node = link_node; + hash_insert(gLinkHashTable, (char *)link,(char *)&link->win); + return link; + } + return 0; +} + +HyperLink * +make_paste_window(PasteNode *paste) +{ + HyperLink *link; + XSetWindowAttributes at; + + if (!make_input_file) { + link = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"); + if (link == NULL) { + fprintf(stderr, "(HyperDoc) Ran out of memory allocating a hypertext link!\n"); + exit(-1); + } + at.cursor = gActiveCursor; + at.event_mask = ButtonPress; + link->win = XCreateWindow(gXDisplay, gWindow->fDisplayedWindow, + 0, 0, 100, 100, 0, + 0, InputOnly, CopyFromParent, + CWEventMask | CWCursor, &at); + link->type = Pastebutton; + link->x = link->y = 0; + link->reference.paste = paste; + hash_insert(gLinkHashTable, (char *)link,(char *) &link->win); + return link; + } + return 0; +} + + + +/* create a HyperDoc page structure with the given type and name */ + +static HyperDocPage * +make_special_page(int type, char *name) +{ + HyperDocPage *page = alloc_page(name); + + if (page == NULL) { + fprintf(stderr, "(HyperDoc) Ran out of memory allocating page.\n"); + exit(-1); + } + page->type = type; + free(page->fLinkHashTable); + page->fLinkHashTable = NULL; + return page; +} + + +/* insert the special button page types into the page hash table */ + +void +make_special_pages(HashTable *pageHashTable) +{ + hash_insert(pageHashTable, (char *)make_special_page(Quitbutton, "QuitPage"), + "QuitPage"); + hash_insert(pageHashTable, (char *)make_special_page(Returnbutton, "ReturnPage"), + "ReturnPage"); + hash_insert(pageHashTable, (char *)make_special_page(Upbutton, "UpPage"), + "UpPage"); +} + + +/* Here is where I put the item into the pages linked list */ + +/* Parse the \bound{varlist} command, and add vars to dependency table */ + +void +add_dependencies(void) +{ + TextNode *bound_node = curr_node; + TextNode *node; + SpadcomDepend *depend; + + if (cur_spadcom == NULL) { + fprintf(stderr, "(HyperDoc) \\bound occuring outside a \\spadcom\n"); + print_page_and_filename(); + exit(-1); + } + curr_node->type = Bound; + curr_node->data.node = alloc_node(); + curr_node = curr_node->data.node; + get_expected_token(Lbrace); + parse_HyperDoc(); + curr_node->type = Endarg; + curr_node = bound_node; + + if (gPageBeingParsed->depend_hash == NULL) { + gPageBeingParsed->depend_hash = + (HashTable *) halloc(sizeof(HashTable), "Hash Table"); + hash_init( + gPageBeingParsed->depend_hash, + DependHashSize, + (EqualFunction) string_equal, + (HashcodeFunction) string_hash); + } + for (node = bound_node->data.node; node->type != Endarg; node = node->next) { + if (node->type == Word) { + depend = (SpadcomDepend *) halloc(sizeof(SpadcomDepend), "SpadcomDepend"); + depend->label = alloc_string(node->data.text); + depend->spadcom = cur_spadcom; + depend->executed = 0; + hash_insert(gPageBeingParsed->depend_hash, (char *)depend, depend->label); + } + } +} + +/* Returns true iff the TextNode contains a single integer */ + +int +is_number(char * str) +{ + char *s; + + for (s = str; *s != '\0'; s++) { + if (!(isdigit(*s) || *s == '-')) + return 0; + } + return 1; +} +void +parser_error(char *str) +{ + /** this procedure is called by the parser when an error occurs. It prints + the error message, followed by the next 10 tokens to ease finding the + error for the user. *****/ + + int i, v; + + fprintf(stderr, " %s\n", str); + fprintf(stderr, "Here are the next 10 tokens:\n"); + for (i = 0; i < 10; i++) { + v = get_token(); + if (v == EOF) + break; + print_token(); + } + fprintf(stderr, "\n"); + exit(-1); +} + + +#define whitespace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define delim(c) \ + (whitespace(c)) + + +/* advance token to the next token in the input stream. */ +int +get_filename(void) +{ + int c, ws; + static int seen_white = 0; /*UNUSED */ + static char buffer[256]; + char *buf = buffer; + + if (last_token) { + last_token = 0; + return 0; + } + do { + keyword_fpos = fpos; + c = get_char(); + ws = whitespace(c); + if (ws) + seen_white = 1; + } while (ws); + switch (c) { + case EOF: + fprintf(stderr, "(HyperDoc) Error trying to read %s, unexpected end-of-file.\n",db_file_name); + exit(-1); + case '%': + case '\\': + case '{': + case '}': + fprintf(stderr, "(HyperDoc) Error unexpected character %c.\n",c); + exit(-1); + default: + do { + *buf++ = c; + } while ((c = get_char()) != EOF && !delim(c)); + unget_char(c); + *buf = '\0'; + token.type = Word; + token.id = buffer; + seen_white = 0; + break; + } + return 1; +} + +char * +get_input_string(void) +{ + char *string; + TextNode *string_node,*save_node; + + save_node = curr_node; + /* Get the nodes that make up the string */ + string_node = alloc_node(); + curr_node = string_node; + parse_HyperDoc(); + curr_node->type = Endarg; + + /* Once here we print to string to get the actual name */ + string = print_to_string(string_node); + free_node(string_node, 0); + curr_node=save_node; + return string; +} + +/* + * tries to determine if there is an optional argument for where I should be + * parsing from. If so it then tries to determine which + */ +int +get_where(void) +{ + int tw; + + get_token(); + if (token.type != Word) + return -1; + + /* Now try to determine if it is a good type */ + if (!strcmp(token.id, "lisp")) { + tw = FromSpadSocket; + } + else if (!strcmp(token.id, "unix")) { + tw = FromUnixFD; + } + else if (!strcmp(token.id, "ht")) { + tw = FromFile; + } + else { + return -1; + } + + /* now check to see if I got a closing square brace */ + get_token(); + if (token.type != Rsquarebrace) + return -1; + + return tw; +} + + +FILE * +find_fp(FilePosition fp) +{ + FILE *lfile; + char fullname[256], addname[256]; + int ret_val; + + /* find the source file in the file hash table, if not there, open it */ + lfile = (FILE *) hash_find(&gFileHashTable, fp.name); + if (lfile == NULL) { + lfile = ht_file_open(fullname, addname, fp.name); + hash_insert(&gFileHashTable, (char *)lfile, fp.name); + } + + /* seek to beginning fp.pos */ + ret_val = fseek(lfile, fp.pos, 0); + if (ret_val == -1) { + perror("fseeking to a page"); + longjmp(jmpbuf, 1); + } + + /* now set some global values */ + page_start_fpos = fp.pos; + line_number = fp.ln; + return lfile; +} +@ +\section{parse-input.c} +<>= +#define _PARSE_INPUT_C +/*** + Contains all the code needed to parse input items, + InputString + SimpleBox + RadioBox. + ****/ + +#include "debug.h" + +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + +/* create an unmapped input window for getting strings * */ +extern int make_input_file; + +HyperLink * +make_input_window(InputItem * item) +{ + HyperLink *link; + XSetWindowAttributes at; + + if (!make_input_file) { + link = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"); + if (link == NULL) { + fprintf(stderr, "Ran out of memory allocating a hyper link!\n"); + exit(-1); + } + at.cursor = gActiveCursor; + at.background_pixel = gInputBackgroundColor; + at.border_pixel = gActiveColor; + link->win = XCreateWindow(gXDisplay, gWindow->fDisplayedWindow, 0, 0, 100, 100, 0, + 0, InputOutput, CopyFromParent, + CWCursor | CWBackPixel | CWBorderPixel, &at); + XSelectInput(gXDisplay, link->win, ButtonPressMask); + link->type = Inputstring; + link->x = link->y = 0; + /** This way when I click in an input window, I need only use reference + to get a pointer to the item ***/ + link->reference.string = item; + hash_insert(gLinkHashTable,(char *) link,(char *) &link->win); + + return link; + } + return 0; +} + +/* create an unmapped input window for boxes */ +HyperLink * +make_box_window(InputBox * box, int type) +{ + HyperLink *link = 0; + XSetWindowAttributes at; + + if (!make_input_file) { + link = (HyperLink *) halloc(sizeof(HyperLink), "Make_box_window"); + if (link == NULL) { + fprintf(stderr, "Ran out of memory allocating a hyper link!\n"); + exit(-1); + } + at.cursor = gActiveCursor; + at.background_pixel = gInputBackgroundColor; + link->win = XCreateWindow(gXDisplay, gWindow->fDisplayedWindow, + 0, 0, 100, 100, 0, + 0, InputOutput, CopyFromParent, + CWCursor | CWBackPixel, &at); + XSelectInput(gXDisplay, link->win, ButtonPressMask); + link->type = type; + link->x = link->y = 0; + /** This way when I click in an input window, I need only use reference + to get a pointer to the item ***/ + link->reference.box = box; + hash_insert(gLinkHashTable, (char *)link,(char *) &link->win); + } + + return link; +} + +void +initialize_default(InputItem *item,char * buff) +{ + LineStruct *newline; + LineStruct *curr_line; + int size = item->size; + int bp; + + item->curr_line = item->lines = alloc_inputline(size); + curr_line = item->lines; + item->num_lines = 1; + curr_line->line_number = 1; + /* while I still have lines to fill */ + for (bp = 0; *buff;) { + if (*buff == '\n') { + curr_line->len = bp; + curr_line->buffer[bp] = 0; + newline = alloc_inputline(size); + newline->line_number = ++(item->num_lines); + curr_line->next = newline; + newline->prev = curr_line; + curr_line = newline; + bp = 0; + buff++; + } + else if (bp == size) { + curr_line->len = size + 1; + curr_line->buffer[size] = '_'; + curr_line->buffer[size + 1] = 0; + newline = alloc_inputline(size); + newline->line_number = ++(item->num_lines); + curr_line->next = newline; + newline->prev = curr_line; + bp = 0; + curr_line = newline; + } + else { + curr_line->buffer[bp++] = *buff++; + } + } + curr_line->buff_pntr = curr_line->len = bp; + item->curr_line = curr_line; +} + + + +/* Parse the input string statement * */ +void +parse_inputstring(void) +{ + TextNode *input_node = curr_node; + char *name; + InputItem *item; + int size; + char *default_value; + + gStringValueOk = 0; + + /* first get the name */ + input_node->type = token.type; + get_expected_token(Lbrace); + name = get_input_string(); + input_node->data.text = alloc_string(name); + /* now get the width */ + get_expected_token(Lbrace); + get_expected_token(Word); + get_expected_token(Rbrace); + size = atoi(token.id); + if (size < 0) { + fprintf(stderr, "Illegal size in Input string\n"); + longjmp(jmpbuf, 1); + } + + /* get the default value */ + get_expected_token(Lbrace); + default_value = get_input_string(); + + /** now I need to malloc space for the input stuff **/ + item = (InputItem *) halloc(sizeof(InputItem), "InputItem"); + + /* Now store all the string info */ + item->name = (char *) + halloc((strlen(input_node->data.text) + 1) * (sizeof(char)),"parse_inputstring"); + strcpy(item->name, input_node->data.text); + item->size = size; + item->entered = 0; + item->next = NULL; + initialize_default(item, default_value); + + /** Now that I have all the structures made, lets make the window, and + add the item to the list ****/ + + input_node->link = make_input_window(item); + if (!make_input_file) + item->win = input_node->link->win; /* TTT */ + insert_item(item); + gStringValueOk = 1; + curr_node = input_node; + return ; +} + +void +parse_simplebox(void) +{ + InputBox *box; + char *name; + short int picked = 0; + char *filename; + TextNode *input_box = curr_node; + + gStringValueOk = 0; + + /* set the type and space fields */ + input_box->type = SimpleBox; + input_box->space = token.id[-1]; + + /* IS it selected? */ + get_token(); + if (token.type == Lsquarebrace) { + get_expected_token(Word); + if (!is_number(token.id)) { + fprintf(stderr, + "parse_simple_box: Expected a value not %s\n", token.id); + print_page_and_filename(); + jump(); + } + else if (!strcmp(token.id, "1")) + picked = 1; + else if (!strcmp(token.id, "0")) + picked = 0; + else { + fprintf(stderr, "parse_simple_box: Unexpected Value %s\n", token.id); + print_page_and_filename(); + jump(); + } + get_expected_token(Rsquarebrace); + get_token(); + } + + if (token.type != Lbrace) { + token_name(token.type); + fprintf(stderr, "parse_inputbox was expecting a { not a %s\n", ebuffer); + print_page_and_filename(); + jump(); + } + + name = get_input_string(); + if (gPageBeingParsed->box_hash && hash_find(gPageBeingParsed->box_hash, name)) { + fprintf(stderr, "Input box name %s is not unique \n", name); + print_page_and_filename(); + jump(); + } + + box = alloc_inputbox(); + box->name = alloc_string(name); + input_box->data.text = alloc_string(name); + box->picked = picked; + + /* Get the filename for the selected and unselected bitmaps */ + get_expected_token(Lbrace); + filename = get_input_string(); + if (!make_input_file) + box->selected = insert_image_struct(filename); + get_expected_token(Lbrace); + filename = get_input_string(); + if (!make_input_file) { + box->unselected = insert_image_struct(filename); + /* set the width and height for the maximaum of the two */ + input_box->height = max(box->selected->height, box->unselected->height); + input_box->width = max(box->selected->width, box->unselected->width); + /* Make the window and stuff */ + input_box->link = make_box_window(box, SimpleBox); + box->win = input_box->link->win; + + /* Now add the box to the box_has table for this window */ + if (gPageBeingParsed->box_hash == NULL) { + gPageBeingParsed->box_hash = (HashTable *) halloc(sizeof(HashTable), + "Box Hash"); + hash_init( + gPageBeingParsed->box_hash, + BoxHashSize, + (EqualFunction) string_equal, + (HashcodeFunction) string_hash); + } + hash_insert(gPageBeingParsed->box_hash, (char *)box, box->name); + } + + /* reset the curr_node and then return */ + curr_node = input_box; + gStringValueOk = 1; + return; +} +void +parse_radiobox(void) +{ + InputBox *box; + char *name; + char *group_name; + short int picked = 0; + TextNode *input_box = curr_node; + + gStringValueOk = 0; + + /* set the type and space fields */ + input_box->type = Radiobox; + input_box->space = token.id[-1]; + + /* IS it selected? */ + get_token(); + if (token.type == Lsquarebrace) { + get_expected_token(Word); + if (!is_number(token.id)) { + fprintf(stderr, + "parse_simple_box: Expected a value not %s\n", token.id); + print_page_and_filename(); + jump(); + } + else if (!strcmp(token.id, "1")) + picked = 1; + else if (!strcmp(token.id, "0")) + picked = 0; + else { + fprintf(stderr, "parse_simple_box: Unexpected Value %s\n", token.id); + print_page_and_filename(); + jump(); + } + get_expected_token(Rsquarebrace); + get_token(); + } + + if (token.type != Lbrace) { + token_name(token.type); + fprintf(stderr, "parse_inputbox was expecting a { not a %s\n", ebuffer); + print_page_and_filename(); + jump(); + } + + name = get_input_string(); + if (gPageBeingParsed->box_hash && hash_find(gPageBeingParsed->box_hash, name)) { + fprintf(stderr, "Input box name %s is not unique \n", name); + print_page_and_filename(); + jump(); + } + + box = alloc_inputbox(); + box->name = alloc_string(name); + input_box->data.text = alloc_string(name); + box->picked = picked; + + /* Now what I need to do is get the group name */ + get_token(); + if (token.type != Lbrace) { + token_name(token.type); + fprintf(stderr, "parse_inputbox was expecting a { not a %s\n", ebuffer); + print_page_and_filename(); + jump(); + } + group_name = get_input_string(); + + /* + * Now call a routine which searches the radio box list for the current + * group name, and if found adds this box to it + */ + add_box_to_rb_list(group_name, box); + + input_box->width = box->rbs->width; + input_box->height = box->rbs->height; + /* Make the window and stuff */ + input_box->link = make_box_window(box, Radiobox); + if (!make_input_file) + box->win = input_box->link->win; /* TTT */ + + + /* Now add the box to the box_has table for this window */ + if (gPageBeingParsed->box_hash == NULL) { + gPageBeingParsed->box_hash = (HashTable *) halloc(sizeof(HashTable), + "Box Hash"); + hash_init( + gPageBeingParsed->box_hash, + BoxHashSize, + (EqualFunction) string_equal, + (HashcodeFunction) string_hash); + } + hash_insert(gPageBeingParsed->box_hash, (char *)box, box->name); + + /* reset the curr_node and then return */ + curr_node = input_box; + gStringValueOk = 1; + return; +} +static void +add_box_to_rb_list(char *name,InputBox *box) +{ + RadioBoxes *trace = gPageBeingParsed->radio_boxes; + InputBox *list; + /*int found = 0;*/ + + while (trace != NULL && strcmp(trace->name, name)) + trace = trace->next; + + if (!trace) { + fprintf(stderr, "Tried to add a radio box to a non-existent group %s\n", + name); + print_page_and_filename(); + jump(); + } + + /* now add the box to the list */ + list = trace->boxes; + box->next = list; + trace->boxes = box; + + if (box->picked && check_others(box->next)) { + fprintf(stderr, "Only a single radio button can be picked\n"); + print_page_and_filename(); + box->picked = 0; + } + box->selected = trace->selected; + box->unselected = trace->unselected; + box->rbs = trace; + + return; +} +static int +check_others(InputBox *list) +{ + InputBox *trace = list; + + while (trace != NULL && !trace->picked) + trace = trace->next; + + if (trace != NULL) + return 1; + else + return 0; +} + + +/* inserts an item into the current input list */ +static void +insert_item(InputItem *item) +{ + InputItem *trace = gPageBeingParsed->input_list; + + if (gPageBeingParsed->current_item == NULL) { + gPageBeingParsed->current_item = item; + } + if (trace == NULL) { + /** Insert at the front of the list **/ + gPageBeingParsed->input_list = item; + return; + } + else { + /** find the end of the list **/ + while (trace->next != NULL) + trace = trace->next; + trace->next = item; + return; + } +} + +InputItem *save_item; + +void +init_paste_item(InputItem *item) +{ + InputItem *trace = gPageBeingParsed->input_list; + + if (!item) { + gPageBeingParsed->input_list = NULL; + gPageBeingParsed->current_item = NULL; + save_item = NULL; + } + else { + save_item = item->next; + trace->next = NULL; + } +} +void +repaste_item(void) +{ + InputItem *trace; + + if (save_item) { + for (trace = gPageBeingParsed->input_list; trace && trace->next != NULL; + trace = trace->next); + if (trace) { + trace->next = save_item; + } + else { + gWindow->page->input_list = save_item; + gWindow->page->current_item = save_item; + } + } + save_item = NULL; +} + +InputItem * +current_item(void) +{ + InputItem *trace = gPageBeingParsed->input_list; + + if (trace) { + for (; trace->next != NULL; trace = trace->next); + return trace; + } + else + return NULL; +} +int +already_there(char *name) +{ + RadioBoxes *trace = gPageBeingParsed->radio_boxes; + + while (trace && strcmp(trace->name, name)) + trace = trace->next; + + if (trace) + return 1; + else + return 0; +} +void +parse_radioboxes(void) +{ + TextNode *return_node = curr_node; + RadioBoxes *newrb; + char *fname; + + /* I really don't need this node, it just sets up some parsing stuff */ + return_node->type = Noop; + + newrb = alloc_rbs(); + + get_token(); + if (token.type != Lbrace) { + token_name(token.type); + fprintf(stderr, "\\radioboxes was expecting a name not %s\n", ebuffer); + print_page_and_filename(); + jump(); + } + + newrb->name = alloc_string(get_input_string()); + + /* quick search for the name in the current list */ + if (already_there(newrb->name)) { + free(newrb->name); + free(newrb); + fprintf(stderr, "Tried to redefine radioboxes %s\n", newrb->name); + print_page_and_filename(); + jump(); + } + /* now I have to get the selected and unslected bitmaps */ + get_token(); + if (token.type != Lbrace) { + token_name(token.type); + fprintf(stderr, "\\radioboxes was expecting a name not %s\n", ebuffer); + print_page_and_filename(); + jump(); + } + fname = get_input_string(); + if (!make_input_file) + newrb->selected = insert_image_struct(fname); + + get_token(); + if (token.type != Lbrace) { + token_name(token.type); + fprintf(stderr, "\\radioboxes was expecting a name not %s\n", ebuffer); + print_page_and_filename(); + jump(); + } + fname = get_input_string(); + if (!make_input_file) { + newrb->unselected = insert_image_struct(fname); + newrb->height = max(newrb->selected->height, newrb->unselected->height); + newrb->width = max(newrb->selected->width, newrb->unselected->width); + /* now add the thing to the current list of radio boxes */ + } + newrb->next = gPageBeingParsed->radio_boxes; + gPageBeingParsed->radio_boxes = newrb; + + curr_node = return_node; + return; +} +@ +\section{parse.h} +<>= +#ifndef _PARSE_H_ +#define _PARSE_H_ 1 + +<> + +#ifdef SUNplatform +#include +#endif + +#include +#include +#include +#include +<> + +#include + +extern jmp_buf jmpbuf; +extern int vbuff; + +extern TextNode *cur_spadcom; /* spad command being parsed *** */ +extern TextNode *curr_node; +extern long page_start_fpos;/* tells the character position of the start + * of the page, needed to find the current + * position when restoring the scanner */ + +/* + * Default sizes of hash tables + */ + +#define LinkHashSize 25 +#define DependHashSize 20 + +extern HashTable *gLinkHashTable; /* the hash table of active link windows */ + +/* + * Flags and defines for the modes the parser can be in + */ + +#define AllMode 0 +#define NoVerticalMode 1 +#define SimpleMode 2 + +extern short int gParserMode; + +/* + * Flags and defines for telling us what part of the page is being parsed. + */ + +extern short int gParserRegion; +extern short int gStringValueOk; +extern boolean gEndedPage; + +extern int line_number; + +/* + * Things for handling macro parameters + */ + + + +extern ParameterList parameters; + + +/* + * The error buffer + */ + +extern char ebuffer[]; + +#endif +@ +\section{parse.c} +<>= +#define _PARSE_C +#include "debug.h" + +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + + + +TextNode *curr_node; /* current node being parsed. It is to be the + * next one filled */ +HashTable *gLinkHashTable; /* the hash table of active link windows */ +TextNode *cur_spadcom; /* The current AXIOM command */ + +short int gParserMode; /* Parser mode flag */ +short int gParserRegion; /* Parser Region flag scrolling etc */ +short int gStringValueOk; /* is a string or box value ok */ +boolean gEndedPage; + +extern int example_number; /* sequence example number */ + + +int ret_val; /* The return value from get_token */ + +HyperDocPage *cur_page; + +char *replace_page; /* true if dynamic page is link to static one */ + +/* + * These routines are used for storing an restoring the parser mode. When + * I start to parse from string, or from a macro, I need to restore the + * parser mode and region once done. These routines do that + * + */ + +typedef struct mr_stack { + /** The structure for storing parser mode and region **/ + short int fParserMode; + short int fParserRegion; + struct mr_stack *fNext; +} MR_Stack; + +MR_Stack *top_mr_stack = NULL; /** Declaration for the stack **/ + +static void +Push_MR(void) +{ + MR_Stack *newStackItem = (MR_Stack *) halloc(sizeof(MR_Stack), "Mode Region Stack"); + + newStackItem->fParserMode = gParserMode; + newStackItem->fParserRegion = gParserRegion; + newStackItem->fNext = top_mr_stack; + top_mr_stack = newStackItem; +} + +static void +Pop_MR(void) +{ + MR_Stack *old = top_mr_stack; + + if (old == NULL) { + fprintf(stderr, "(HyperDoc) Parser Error: Tried to pop empty MR Stack\n"); + exit(-1); + } + else { + gParserMode = old->fParserMode; + gParserRegion = old->fParserRegion; + top_mr_stack = old->fNext; + free(old); + } +} + +void +load_page(HyperDocPage *page) +{ + if (page->type == UnloadedPageType) { + HyperDocPage *new_page; + init_scanner(); + new_page = format_page((UnloadedPage *)page); + gWindow->page = new_page; + /* free(page); */ + page = new_page; + } +} + +HyperDocPage *formatpage; + +/* Display a HyperDoc page with the given name, parsing it if needed */ + +void +display_page(HyperDocPage *page) +{ + HyperDocPage *new_page; + + XUnmapSubwindows(gXDisplay, gWindow->fMainWindow); + XUnmapSubwindows(gXDisplay, gWindow->fScrollWindow); + XFlush(gXDisplay); + + if (setjmp(jmpbuf)) { + + /* + * since I did not finish formatting the page, let me get rid of what + * I had + */ + free_page(formatpage); + /* Replace the buggy page with what I started with */ + hash_replace(gWindow->fPageHashTable, (char *)page, formatpage->name); + if (!strcmp(formatpage->name, "ErrorPage")) { + fprintf(stderr, "(HyperDoc) Oops the error page is buggy\n"); + exit(-1); + } + gWindow->page = page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, "ErrorPage"); + if (page == NULL) { + fprintf(stderr, "(HyperDoc) No error page found, exiting\n"); + exit(-1); + } + reset_connection(); + } + if (page->type == UnloadedPageType || page->type == ErrorPage) { + /* Gack! (page should be a union!) */ + init_scanner(); + new_page = format_page((UnloadedPage *)page); + gWindow->page = new_page; + /* free(page); */ + page = new_page; + } + show_page(page); +} + + +/* Parse a given HyperDoc Page, from the top */ + +static HyperDocPage * +format_page(UnloadedPage *ulpage) +{ + /*int ret_val;*/ + HyperDocPage *page = alloc_page(ulpage->name); + + /* + * In case of an error I will have to get at this page so I can free the + * waisted memory + */ + formatpage = page; + page->type = Normal; + hash_replace(gWindow->fPageHashTable, (char *)page, ulpage->name); + + cfile = find_fp(ulpage->fpos); + + + page->filename = alloc_string(ulpage->fpos.name); + parse_page(page); + return page; +} + +/* parse the HyperDoc statements in the given string */ + +void +parse_from_string(char *str) +{ + save_scanner_state(); + last_ch = NoChar; + last_token = 0; + input_string = str; + input_type = FromString; + parse_HyperDoc(); + restore_scanner_state(); +} + +static void +parse_title(HyperDocPage *page) +{ + TextNode *node; + + Push_MR(); + gParserRegion = Title; + get_expected_token(Lbrace); + node = alloc_node(); + page->title = node; + node->type = Titlenode; + node->next = alloc_node(); + node = node->next; + node->type = Center; + node->next = alloc_node(); + curr_node = node->next; + parse_HyperDoc(); + curr_node->type = Endcenter; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + curr_node->type = Endtitle; + curr_node->next = NULL; + if (gNeedIconName) { + char *title = print_to_string(page->title); + + XSetIconName(gXDisplay, gWindow->fMainWindow, title); + gNeedIconName = 0; + } + if (token.type != Rbrace) { + fprintf(stderr, "(HyperDoc) Parse title was expecting a closing brace\n"); + print_page_and_filename(); + jump(); + } + linkTitleBarWindows(); + Pop_MR(); +} + +static void +parse_header(HyperDocPage *page) +{ + TextNode *node; + + Push_MR(); + gParserRegion = Header; + node = alloc_node(); + page->header = node; + node->type = Headernode; + node->next = alloc_node(); + curr_node = node->next; + parse_HyperDoc(); +} + +/* + * parse a page from the top level + */ + +static void +init_parse_page(HyperDocPage *page) +{ + gEndedPage = gInDesc = gStringValueOk = gInIf = + gInButton = gInOptional = gInVerbatim = gInPaste = gInItems = + gInSpadsrc = FALSE; + example_number = 1; + cur_page = page; + gParserMode = AllMode; + /* Now I should set the input list to be null */ + free_input_list(page->input_list); + page->input_list = page->current_item = NULL; + + init_top_group(); + clear_be_stack(); + + cur_spadcom = NULL; + gLinkHashTable = page->fLinkHashTable; + hash_init( + gLinkHashTable, + LinkHashSize, + (EqualFunction) window_equal, + (HashcodeFunction) window_code); + gPageBeingParsed = page; + +} + +void +init_parse_patch(HyperDocPage *page) +{ + gEndedPage = gInDesc = gStringValueOk = gInIf = + gInButton = gInOptional = gInVerbatim = gInPaste = gInItems = + gInSpadsrc = FALSE; + gParserMode = AllMode; + gParserRegion = Scrolling; + + init_top_group(); + clear_be_stack(); + + cur_spadcom = NULL; + gLinkHashTable = page->fLinkHashTable; + gPageBeingParsed = page; +} + +#define end_page(t) ((t == Page || t == NewCommand ||t == Endpage)?1:0) + +static void +parse_page(HyperDocPage *page) +{ + init_parse_page(page); + + /* Get the name of the page */ + + get_expected_token(Page); + get_expected_token(Lbrace); + get_expected_token(Word); + if (page->name == NULL) + page->name = alloc_string(token.id); + get_expected_token(Rbrace); + /* parse the title */ + gWindow->fDisplayedWindow = gWindow->fMainWindow; + parse_title(page); + + /* + * Now start parsing the header region + */ + parse_header(page); +} + +char *ExpectedBeginScroll = +"Parser Error: Unexpected new page, expecting a begin scroll\n", *ExpectedEndScroll = +"Parser Error: Unexpected new page, expected an end scroll\n"; + +/* + * The general HyperDoc parsing function. expects to see anything. This + * function will parse until it sees either: 1) A new page starting 2) An end + * of file 3) a closing bracket "}" + */ + +void +parse_HyperDoc(void) +{ + TextNode *node = NULL /*, *save_node = NULL, *arg_node = NULL*/ ; + + for(;;) { + ret_val = get_token(); + + if (ret_val == EOF) + return; + + switch (token.type) { + case Spadsrc: + parse_spadsrc(curr_node); + break; + case Helppage: + parse_help(); + break; + case Endpatch: + case Endpaste: + case Rbrace: + return; + case Paste: + parse_paste(); + break; + case Pastebutton: + parse_pastebutton(); + break; + case Endpage: + case NewCommand: + case Page: + end_a_page(); + return; + case EndScroll: + token.type = Endscroll; + case Endscroll: + start_footer(); + break; + case Beginscroll: + start_scrolling(); + break; + case Thispage: /* it really is just a word */ + curr_node->type = Word; + curr_node->data.text = alloc_string(gPageBeingParsed->name); + break; + case Icorrection: + node->type = Noop; + break; + case Newcond: + parse_newcond(); + break; + case Setcond: + parse_setcond(); + break; + case Dollar: + parse_verbatim(Math); + break; + case Verbatim: + parse_verbatim(Verbatim); + break; + case Ifcond: + parse_ifcond(); + break; + case Fi: + if (gInIf) + return; + else { + curr_node->type = Noop; + /* Oops I had a problem parsing this puppy */ + fprintf(stderr, "(HyperDoc) \\fi found without macthing if?\n"); + longjmp(jmpbuf, 1); + fprintf(stderr, "(HyperDoc) Longjmp failed -- Exiting \n"); + exit(-1); + } + case Else: + if (gInIf) + return; + else { + /* Oops I had a problem parsing this puppy */ + curr_node->type = Noop; + fprintf(stderr, "(HyperDoc) \\else found without macthing if?\n"); + longjmp(jmpbuf, 1); + fprintf(stderr, "(HyperDoc) Longjmp failed -- Exiting \n"); + exit(-1); + } + case Macro: + parse_macro(); + break; + case Env: + /** In this case, get the environment value, and make it a word **/ + parse_env(curr_node); + break; + case WindowId: + curr_node->type = WindowId; + curr_node->space = token.id[-1]; + curr_node->data.text = window_id(gWindow->fMainWindow); + break; + case Punctuation: + case Word: + case Lsquarebrace: + case Dash: + curr_node->type = token.type; + curr_node->space = token.id[-1]; + curr_node->data.text = alloc_string(token.id); + break; + case Pagename: + { + char *str; + + curr_node->type = Word; + curr_node->space = 0; + str = halloc(strlen(cur_page->name) + 1, "parse"); + sprintf(str, "%s", cur_page->name); + curr_node->data.text = alloc_string(str); + break; + } + case Examplenumber: + { + char *str; + + curr_node->type = Word; + curr_node->space = 0; + str = halloc(5, "parse"); + sprintf(str, "%d", example_number); + curr_node->data.text = alloc_string(str); + break; + } + case Rsquarebrace: + if (gInOptional) + return; + else { + curr_node->type = token.type; + curr_node->space = token.id[-1]; + curr_node->data.text = alloc_string(token.id); + } + break; + case EndTitems: + token.type = Endtitems; + case Endtitems: + if (gParserMode != AllMode) { + curr_node->type = Noop; + fprintf(stderr, "(HyperDoc) Found a bad token %s\n", token_table[token.type]); + longjmp(jmpbuf, 1); + } + else { + curr_node->type = token.type; + break; + } + case EndItems: + token.type = Enditems; + case Enditems: + gInItems--; + case Horizontalline: + case Par: + case Newline: + case Titem: + if (gParserMode != AllMode) { + curr_node->type = Noop; + fprintf(stderr, "(HyperDoc) Found a bad token %s\n", token_table[token.type]); + longjmp(jmpbuf, 1); + } + else { + curr_node->type = token.type; + break; + } + case Begintitems: + case Beginitems: + if (gParserMode != AllMode) { + curr_node->type = Noop; + fprintf(stderr, "(HyperDoc) Found a bad token %s\n", token_table[token.type]); + longjmp(jmpbuf, 1); + } + else { + parse_begin_items(); + break; + } + case Item: + parse_item(); + break; + case Mitem: + parse_mitem(); + break; + case VSpace: + case Tab: + case HSpace: + case Indent: + case Indentrel: + parse_value1(); + break; + case Space: + parse_value2(); + break; + case Lbrace: + curr_node->type = Group; + curr_node->space = token.id[-1]; + push_group_stack(); + node = alloc_node(); + curr_node->next = node; + curr_node = curr_node->next; + parse_HyperDoc(); + curr_node->type = Endgroup; + pop_group_stack(); + break; + case Upbutton: + case Returnbutton: + case Link: + case Downlink: + case Memolink: + case Windowlink: + parse_button(); + break; + case Unixlink: + case LispMemoLink: + case LispDownLink: + case Lisplink: + case Lispcommand: + case Lispcommandquit: + case Spadlink: + case Spaddownlink: + case Spadmemolink: + case Unixcommand: + case Spadcall: + case Spadcallquit: + case Qspadcall: + case Qspadcallquit: + case Lispwindowlink: + parse_command(); + break; + case Controlbitmap: + case Inputbitmap: + case Inputpixmap: + case Inputimage: + parse_input_pix(); + break; + case Box: + parse_box(); + break; + case Mbox: + parse_mbox(); + break; + case Free: + parse_free(); + break; + case Center: + parse_centerline(); + break; + case Bound: + add_dependencies(); + break; + case Spadcommand: + case Spadgraph: + parse_spadcommand(curr_node); + break; + case Table: + parse_table(); + break; + case Beep: + case Emphasize: + case BoldFace: + case Rm: + case It: + case Tt: + case Sl: + curr_node->type = token.type; + curr_node->space = token.id[-1]; + break; + case Inputstring: + parse_inputstring(); + break; + case SimpleBox: + parse_simplebox(); + break; + case BoxValue: + case StringValue: + if (!gStringValueOk) { + strcpy(ebuffer,"(HyperDoc): Unexpected Value Command:"); + strcat(ebuffer, token.id); + + parser_error(ebuffer); + curr_node->type = Noop; + longjmp(jmpbuf, 1); + } + curr_node->type = token.type; + curr_node->space = token.id[-1]; + get_expected_token(Lbrace); + get_expected_token(Word); + curr_node->data.text = alloc_string(token.id); + get_expected_token(Rbrace); + break; + case NoLines: + gPageBeingParsed->page_flags |= NOLINES; + break; + case Pound: + curr_node->type = Pound; + curr_node->space = token.id[-1]; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + parse_parameters(); + break; + case Radiobox: + parse_radiobox(); + break; + case Radioboxes: + parse_radioboxes(); + break; + case Replacepage: + parse_replacepage(); + break; + default: + fprintf(stderr, "(HyperDoc) Keyword not currently supported: %s\n", token.id); + print_page_and_filename(); + curr_node->type = Noop; + break; + } + if (gEndedPage) + return; + if (curr_node->type != Noop) { + node = alloc_node(); + curr_node->next = node; + curr_node = node; + } + } +} + + +/* parse a page from a socket source */ + +HyperDocPage * +parse_page_from_socket(void) +{ + HyperDocPage *page = alloc_page((char *) NULL); + HyperDocPage *hpage; + + init_scanner(); + input_type = FromSpadSocket; + input_string = ""; + cur_spadcom = NULL; + gLinkHashTable = page->fLinkHashTable; + hash_init( + gLinkHashTable, + LinkHashSize, + (EqualFunction) window_equal, + (HashcodeFunction) window_code); + gPageBeingParsed = page; + replace_page = NULL; + if (setjmp(jmpbuf)) { + /* Ooops, somewhere I had an error */ + free_page(page); + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, "ErrorPage"); + reset_connection(); + } + else { + parse_page(page); + page->type = SpadGen; + page->filename = NULL; + /* just for kicks, let me add this thing to the hash file */ + hpage = (HyperDocPage *) hash_find(gWindow->fPageHashTable, page->name); + if (hpage) + hash_replace(gWindow->fPageHashTable, (char *)page, page->name); + else { + hash_insert(gWindow->fPageHashTable, (char *)page, page->name); + } + } + if (replace_page != NULL) { + free_page(page); + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, replace_page); + if (page == NULL) + fprintf(stderr, "(HyperDoc) Unknown page: %s\n", replace_page); + } + return page; +} + +HyperDocPage * +parse_page_from_unixfd(void) +{ + HyperDocPage *page = alloc_page((char *) NULL); + + init_scanner(); + input_type = FromUnixFD; + cur_spadcom = NULL; + gLinkHashTable = page->fLinkHashTable; + hash_init( + gLinkHashTable, + LinkHashSize, + (EqualFunction) window_equal, + (HashcodeFunction) window_code); + gPageBeingParsed = page; + if (setjmp(jmpbuf)) { + /* Ooops, somewhere I had an error */ + free_page(page); + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, "ErrorPage"); + reset_connection(); + } + else { + parse_page(page); + page->type = Unixfd; + page->filename = NULL; + } + return page; + +} + +static void +start_scrolling(void) +{ + + /* + * if I am here than I had a begin scroll. This means I should end the + * header, and then start parsing the footer + */ + + if (gParserRegion != Header) { + curr_node->type = Noop; + fprintf(stderr, "(HyperDoc) Parser Error: Unexpected BeginScrollFound\n"); + longjmp(jmpbuf, 1); + fprintf(stderr, "(HyperDoc) Longjump failed exiting\n"); + } + curr_node->type = Endheader; + curr_node->next = NULL; + Pop_MR(); + + Push_MR(); + gParserRegion = Scrolling; + gWindow->fDisplayedWindow = gWindow->fScrollWindow; + curr_node = alloc_node(); + gPageBeingParsed->scrolling = curr_node; + curr_node->type = Scrollingnode; +} + +static void +start_footer(void) +{ + /* + * This ends the parsing of the scrolling region, and then starts to + * parse the footer + */ + + if (gParserRegion != Scrolling) { + curr_node->type = Noop; + fprintf(stderr, "(HyperDoc) Parser Error: Unexpected Endscroll Found\n"); + print_page_and_filename(); + longjmp(jmpbuf, 1); + fprintf(stderr, "(HyperDoc) Longjump failed exiting\n"); + } + + curr_node->type = Endscrolling; + curr_node->next = NULL; + Pop_MR(); + linkScrollBars(); + + Push_MR(); + gParserRegion = Footer; + curr_node = alloc_node(); + curr_node->type = Footernode; + gPageBeingParsed->footer = curr_node; + gWindow->fDisplayedWindow = gWindow->fMainWindow; +} + +static void +end_a_page(void) +{ + if (gParserRegion == Scrolling) { + fprintf(stderr, "%s\n", + "(HyperDoc) end_a_page: Unexpected End of Page occurred \ + inside a \beginscroll"); + print_page_and_filename(); + jump(); + } + gEndedPage = TRUE; + if (gParserRegion == Footer) { + /* the person had all the regions, I basically just have to leave */ + curr_node->type = Endscrolling; + curr_node->next = NULL; + Pop_MR(); + } + else if (gParserRegion == Header) { + /* person had a header. So just end it and return */ + curr_node->type = Endheader; + curr_node->next = NULL; + Pop_MR(); + gPageBeingParsed->scrolling = NULL; + gPageBeingParsed->footer = NULL; + } +} + +static void +parse_replacepage(void) +{ + get_expected_token(Lbrace); + get_token(); + replace_page = alloc_string(token.id); + get_expected_token(Rbrace); +} +@ +\section{parse-paste.h} +<>= +#ifndef _PARSE_PASTE_H_ +#define _PARSE_PASTE_H_ 1 + +<> + +extern short int gInPaste; + +#endif +@ +\section{parse-paste.c} +<>= +/****************************************************************************** + * + * parse_paste.c: HyperDoc routines for paste-in areas. + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _PARSE_PASTE_C +#include "debug.h" + + +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + + +extern FILE *cfile; +short int gInPaste; + + +void +parse_paste(void) +{ + TextNode *pn = curr_node; + PasteNode *paste; + int where; + + if (gParserRegion != Scrolling) { + fprintf(stderr, "(HyperDoc) Paste areas are only allowed in the scrolling area:"); + print_page_and_filename(); + jump(); + } + gInPaste++; + + /* now I need to get the name */ + get_token(); + if (token.type != Lbrace) { + fprintf(stderr, "(HyperDoc) A paste area needs a name:\n"); + print_next_ten_tokens(); + print_page_and_filename(); + jump(); + } + pn->data.text = alloc_string(get_input_string()); + pn->type = Paste; + + /* + * now see if there is already an entry in the hash_table for this thing, + * if not create it and put it there. + */ + paste = (PasteNode *) hash_find(gWindow->fPasteHashTable, pn->data.text); + if (paste == 0) { + paste = alloc_paste_node(pn->data.text); + hash_insert(gWindow->fPasteHashTable, (char *)paste, paste->name); + } + else if (paste->haspaste) { + fprintf(stderr, "(HyperDoc) Tried to redefine paste area %s\n", paste->name); + print_page_and_filename(); + /* jump(); */ + } + paste->haspaste = 1; + paste->paste_item = current_item(); + get_token(); + if (token.type == Lsquarebrace) { + /* user wishes to specify a where to send the command */ + where = get_where(); + if (where == -1) { + paste->where = -1; + fprintf(stderr, "(HyperDoc) \\begin{paste} was expecting [lisp|unix|ht]\n"); + print_next_ten_tokens(); + print_page_and_filename(); + jump(); + } + else + paste->where = where; + get_token(); + } + else + paste->where = FromFile; + + /* now try to get the command argument or page name */ + if (token.type != Lbrace) { + paste->where = 0; + fprintf(stderr, "(HyperDoc) \\begin{paste} was expecting an argument\n"); + print_next_ten_tokens(); + print_page_and_filename(); + jump(); + } + paste->arg_node = alloc_node(); + curr_node = paste->arg_node; + parse_HyperDoc(); + curr_node->type = Endarg; + + gWindow->fDisplayedWindow = gWindow->fScrollWindow; + + /* Now try to find the displaying text */ + pn->next = alloc_node(); + curr_node = pn->next; + parse_HyperDoc(); + curr_node->type = Endpaste; + paste->end_node = curr_node; + + paste->begin_node = pn; + gInPaste--; +} + +void +parse_pastebutton(void) +{ + PasteNode *paste; + TextNode *pb; + + /* + * this routine parse a \pastebutton expression. The syntax is + * \pastebutton{name} + */ + pb = curr_node; + pb->type = Pastebutton; + + /* first thing I should do is get the name */ + get_token(); + if (token.type != Lbrace) { + fprintf(stderr, "(HyperDoc) \\pastebutton needs a name\n"); + print_page_and_filename(); + print_next_ten_tokens(); + jump(); + } + pb->data.text = alloc_string(get_input_string()); + + /* + * now I should see if the paste area has already been parsed, and if not + * I should create a spot in the hash table for it + */ + paste = (PasteNode *) hash_find(gWindow->fPasteHashTable, pb->data.text); + if (paste == 0) { + paste = alloc_paste_node(pb->data.text); + hash_insert(gWindow->fPasteHashTable,(char *) paste, paste->name); + } + else if (paste->hasbutton) { + fprintf(stderr, "(HyperDoc) Tried to redefine paste area %s\n", paste->name); + print_page_and_filename(); + /* jump(); */ + } + paste->hasbutton = 1; + + /* Now we need to parse the HyperDoc and for the displayed text */ + + get_token(); + if (token.type != Lbrace) { + fprintf(stderr, "(HyperDoc) \\pastebutton was expecting a { \n"); + print_page_and_filename(); + print_next_ten_tokens(); + jump(); + } + pb->next = alloc_node(); + curr_node = pb->next; + parse_HyperDoc(); + curr_node->type = Endpastebutton; + + /* once that is done I need only make the window for this link */ + pb->link = make_paste_window(paste); +} + + +/* + * this routine is responsible for parsing a patch from a file. To do this I + * guess er will init_scanner, then parse, the parsed piece of text + * will replace the current PasteNode which will be squashed down to + * nothing, and then discarded. + */ + +HyperDocPage * +parse_patch(PasteNode *paste) +{ + TextNode *new; + TextNode *end_node; + TextNode *begin_node; + TextNode *arg_node; + TextNode *throw; + TextNode *next_node; + InputItem *paste_item = paste->paste_item; + int where = paste->where; + GroupItem *g = paste->group; + ItemStack *is = paste->item_stack; + PatchStore *patch; + char *patch_name; + int ret_value = 1; + + /* prepare to throw away the current paste node */ + end_node = paste->end_node; + next_node = end_node->next; + begin_node = paste->begin_node; + arg_node = paste->arg_node; + throw = begin_node->next; + + /* now read the new stuff and add it in between all this stuff */ + + switch (where) { + case FromFile: + patch_name = print_to_string(arg_node); + patch = (PatchStore *) hash_find(gWindow->fPatchHashTable, patch_name); + if (!patch) { + fprintf(stderr, "(HyperDoc) Unknown patch name %s\n", patch_name); + BeepAtTheUser(); + return 0; + } + if (!patch->loaded) + load_patch(patch); + input_type = FromString; + input_string = patch->string; + break; + case FromSpadSocket: + input_type = FromSpadSocket; + ret_value = issue_serverpaste(arg_node); + if (ret_value < 0) { + paste->where = where; + paste->end_node = end_node; + paste->arg_node = arg_node; + paste->group = g; + paste->item_stack = is; + paste->haspaste = 1; + return 0; + } + break; + case FromUnixFD: + input_type = FromUnixFD; + issue_unixpaste(arg_node); + break; + default: + fprintf(stderr, "(HyperDoc) \\parsebutton error: Unknown where\n"); + exit(-1); + break; + } + + paste->where = 0; + paste->end_node = paste->arg_node = paste->begin_node = 0; + paste->group = 0; + paste->item_stack = 0; + paste->haspaste = 0; + paste->paste_item = 0; + + + /* set the jump buffer in case it is needed */ + if (setjmp(jmpbuf)) { + /*** OOOPS, an error occurred ****/ + fprintf(stderr, "(HyperDoc) Had an error parsing a patch: Goodbye!\n"); + exit(-1); + } + + + end_node->next = 0; + free_node(throw, 1); + + init_parse_patch(gWindow->page); + init_paste_item(paste_item); + get_token(); + if (token.type != Patch) { + fprintf(stderr, "(HyperDoc) Pastebutton %s was expecting a patch\n", + paste->name); + jump(); + } + if (input_type == FromString) { + get_token(); + if (token.type != Lbrace) { + token_name(token.type); + fprintf(stderr, "(HyperDoc) Unexpected %s \n", ebuffer); + print_page_and_filename(); + jump(); + } + + get_token(); + if (token.type != Word) { + token_name(token.type); + fprintf(stderr, "(HyperDoc) Unexpected %s \n", ebuffer); + print_page_and_filename(); + jump(); + } + + get_token(); + if (token.type != Rbrace) { + token_name(token.type); + fprintf(stderr, "(HyperDoc) Unexpected %s \n", ebuffer); + print_page_and_filename(); + jump(); + } + } + new = alloc_node(); + curr_node = new; + parse_HyperDoc(); + + /* Once I am back, I need only reallign all the text structures */ + curr_node->type = Noop; + curr_node->next = next_node; + begin_node->next = new; + begin_node->type = Noop; + free(begin_node->data.text); + begin_node->data.text = 0; + + gWindow->fDisplayedWindow = gWindow->fScrollWindow; + + repaste_item(); + + paste_page(begin_node); + + /* so now I should just be able to disappear */ + return gWindow->page; +} + +static void +load_patch(PatchStore *patch) +{ + long start_fpos; + int size = 0; + int limsize; + char *trace; + + + save_scanner_state(); + cfile = find_fp(patch->fpos); + + init_scanner(); + + /** First thing I should do is make sure that the name is correct ***/ + start_fpos = fpos; + get_expected_token(Patch); + get_expected_token(Lbrace); + get_expected_token(Word); + if (strcmp(token.id, patch->name)) { + /** WOW, Somehow I had the location of the wrong macro **/ + fprintf(stderr, "(HyperDoc) Expected patch name %s: got instead %s in load_patch\n", + patch->name, token.id); + jump(); + } + get_expected_token(Rbrace); + + scan_HyperDoc(); + fseek(cfile, patch->fpos.pos + start_fpos, 0); + limsize = fpos - start_fpos + 1; + patch->string = (char *) halloc((limsize + 1) * sizeof(char), "Patch String"); + for (size = 1, trace = patch->string; size < limsize; size++) + *trace++ = getc(cfile); + *trace = '\0'; + patch->loaded = 1; + restore_scanner_state(); +} + + +@ +\section{parse-types.h} +<>= +#ifndef _PARSE_TYPES_H_ +#define _PARSE_TYPES_H_ 1 + +<> + +extern boolean gInButton; +extern boolean gInIf; +extern boolean gInItems; +extern boolean gInOptional; + + +#endif +@ +\section{parse-types.c} +<>= +/****************************************************************************** + * + * parse_types.h: HyperDoc parsing routines for node types. + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _PARSE_TYPES_C +#include "debug.h" + +<> +<> +<> +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + +boolean gInButton = FALSE; +boolean gInIf = FALSE; +boolean gInItems = FALSE; +boolean gInOptional = FALSE; + +void +parse_ifcond(void) +{ + TextNode *ifnode = curr_node; + TextNode *endif; + TextNode *condnode; + + /* + * parse a conditional. At first I am just going to parse if + * fi + */ + if (gInIf) { + curr_node->type = Noop; + fprintf(stderr, "\\if found within \\if \n"); + longjmp(jmpbuf, 1); + fprintf(stderr, "Longjump failed, Exiting\n"); + exit(-1); + } + gInIf++; + curr_node->type = Ifcond; + curr_node->space = token.id[-1]; + curr_node->data.ifnode = alloc_ifnode(); + /* Now get the cond node I hope */ + + condnode = curr_node->data.ifnode->cond = alloc_node(); + curr_node = condnode; + parse_condnode(); + + endif = alloc_node(); + endif->type = Endif; + ifnode->data.ifnode->thennode = alloc_node(); + curr_node = ifnode->data.ifnode->thennode; + parse_HyperDoc(); + if (token.type == Fi) { + curr_node->type = Fi; + curr_node->next = endif; + ifnode->data.ifnode->elsenode = endif; + } + else if (token.type == Else) { + /* first finish up the then part */ + curr_node->type = Fi; + curr_node->next = endif; + /* the go and parse the else part */ + ifnode->data.ifnode->elsenode = alloc_node(); + curr_node = ifnode->data.ifnode->elsenode; + parse_HyperDoc(); + if (token.type != Fi) { + token_name(token.type); + curr_node->type = Noop; + fprintf(stderr, "Expected a \\fi not a %s", ebuffer); + longjmp(jmpbuf, 1); + fprintf(stderr, "Longjump failed, Exiting\n"); + exit(-1); + } + curr_node->type = Fi; + curr_node->next = endif; + } + else { + curr_node->type = Noop; + token_name(token.type); + fprintf(stderr, "Expected a \\fi not a %s", ebuffer); + longjmp(jmpbuf, 1); + fprintf(stderr, "Longjump failed, Exiting\n"); + exit(-1); + } + ifnode->next = ifnode->data.ifnode->thennode; + ifnode->width = -1; /* A flag for compute if extents */ + curr_node = endif; + gInIf--; +} + +static void +parse_condnode(void) +{ + get_token(); + + switch (token.type) { + case Cond: + curr_node->type = Cond; + curr_node->data.text = alloc_string(token.id); + break; + case Haslisp: + case Hasreturn: + case Lastwindow: + case Hasup: + curr_node->type = token.type; + break; + case Boxcond: + curr_node->type = Boxcond; + curr_node->data.text = alloc_string(token.id); + break; + case Hasreturnto: + parse_hasreturnto(); + break; + default: + { + char eb[128]; + token_name(token.type); + sprintf(eb, "Unexpected Token %s\n", eb); + htperror(eb, HTCONDNODE); + } + break; + } +} + +static void +parse_hasreturnto(void) +{ + TextNode *hrt = curr_node, *arg_node = alloc_node(); + + curr_node->type = Hasreturnto; + curr_node = arg_node; + get_expected_token(Lbrace); + parse_HyperDoc(); + curr_node->type = Endarg; + hrt->data.node = arg_node; + curr_node = hrt; +} + +void +parse_newcond(void) +{ + char label[256]; + + get_expected_token(Lbrace); + get_expected_token(Unkeyword); + strcpy(label, token.id); + get_expected_token(Rbrace); + insert_cond(label, "0"); + curr_node->type = Noop; +} + +void +parse_setcond(void) +{ + char label[256], cond[256]; + + get_expected_token(Lbrace); + get_expected_token(Cond); + strcpy(label, token.id); + get_expected_token(Rbrace); + get_expected_token(Lbrace); + get_expected_token(Word); + strcpy(cond, token.id); + get_expected_token(Rbrace); + change_cond(label, cond); + curr_node->type = Noop; +} + +void +parse_begin_items(void) +{ + TextNode *bi = curr_node; + + /* + * This procedure parses a begin item. It sets the current + * node and sees if there is an optional argument for the itemspace + */ + + bi->type = token.type; + get_token(); + if (token.type == Lsquarebrace) { + bi->data.node = alloc_node(); + curr_node = bi->data.node; + gInOptional++; + parse_HyperDoc(); + gInOptional--; + curr_node->type = Enddescription; + if (token.type != Rsquarebrace) { + fprintf(stderr, "(HyperDoc) Optional arguments must end with ].\n"); + print_next_ten_tokens(); + print_page_and_filename(); + jump(); + } + curr_node = bi; + } + else + unget_token(); + gInItems++; +} + +void +parse_item(void) +{ + if (!gInItems) { + fprintf(stderr, "\\item found outside an items environment\n"); + print_page_and_filename(); + print_next_ten_tokens(); + jump(); + } + curr_node->type = Item; + get_token(); + if (token.type == Lsquarebrace) { + /* I should parse the optional argument */ + curr_node->next = alloc_node(); + curr_node = curr_node->next; + curr_node->type = Description; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + gInOptional++; + parse_HyperDoc(); + gInOptional--; + curr_node->type = Enddescription; + if (token.type != Rsquarebrace) { + fprintf(stderr, "(HyperDoc) Optional arguments must end with ].\n"); + print_next_ten_tokens(); + print_page_and_filename(); + jump(); + } + } + else { + unget_token(); + } +} + +void +parse_mitem(void) +{ + if (!gInItems) { + fprintf(stderr, "\\mitem found outside an items environment\n"); + print_page_and_filename(); + print_next_ten_tokens(); + jump(); + } + curr_node->type = Mitem; +} + +char *vbuf = NULL; +int vbuf_size = 0; + +#define VbufSlop 10 +#define resizeVbuf()\ + if (size == vbuf_size) { \ + vbuf = resizeBuffer(size + VbufSlop, vbuf, &vbuf_size); \ + vb = vbuf + size; \ + } + +#define new_verb_node() \ + resizeVbuf(); \ + *vb = '\0'; \ + curr_node->data.text = alloc_string(vbuf); \ + curr_node->next = alloc_node(); \ + curr_node = curr_node->next; \ + curr_node->type = Newline; \ + curr_node->next = alloc_node(); \ + curr_node = curr_node->next; \ + curr_node->type = type; \ + if (*end_string == '\n') es = end_string+1; \ + else es = end_string; \ + size = 0; \ + vb = vbuf; + +void +parse_verbatim(int type) +{ + int size = 0, c; + char *end_string, *vb = vbuf, *es; + + curr_node->type = type; + if (token.id[-1]) + curr_node->space = 1; + if (type == Spadsrctxt) { + es = end_string = "\n\\end{spadsrc}"; + } + else if (type == Math) + es = end_string = "$"; + else + es = end_string = "\\end{verbatim}"; + while ((c = get_char()) != EOF) { + resizeVbuf(); + size++; + if (c == '\n') { + new_verb_node(); + continue; + } + *vb++ = c; + if (*es++ != c) + es = end_string; + if (!*es) + break; + } + if (c == EOF) { + fprintf(stderr, "parse_verbatim: Unexpected EOF found\n"); + longjmp(jmpbuf, 1); + } + resizeVbuf(); + if (*end_string == '\n') + es = end_string + 1; + else + es = end_string; + vbuf[size - strlen(es)] = '\0'; + if (*vbuf) { + curr_node->data.text = alloc_string(vbuf); + curr_node->next = alloc_node(); + curr_node = curr_node->next; + } + if (type == Spadsrctxt) + curr_node->type = Endspadsrc; + else if (type == Math) + curr_node->type = Endmath; + else + curr_node->type = Endverbatim; +} + +void +parse_input_pix(void) +{ + TextNode *pixnode; + char *filename; + + pixnode = curr_node; + pixnode->type = token.type; + pixnode->space = token.id[-1]; + pixnode->width = -1; + get_expected_token(Lbrace); + filename = get_input_string(); + pixnode->data.text = alloc_string(filename); + curr_node = pixnode; + if (pixnode->type == Inputimage) { + char f[256]; + char *p; + + if ((gXDisplay && DisplayPlanes(gXDisplay, gXScreenNumber) == 1) || gSwitch_to_mono ==1) { + pixnode->type = Inputbitmap; + strcpy(f, pixnode->data.text); + strcat(f, ".bm"); + p=pixnode->data.text; + pixnode->data.text = alloc_string(f); + free(p); + } + else { + pixnode->type = Inputpixmap; + strcpy(f, pixnode->data.text); +#ifdef OLD + strcat(f, ".pm"); +#endif + strcat(f, ".xpm.Z"); + p=pixnode->data.text; + pixnode->data.text = alloc_string(f); + free(p); + } + } +} + +void +parse_centerline(void) +{ + curr_node->type = token.type; + curr_node->space = token.id[-1]; + curr_node->width = -1; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + get_expected_token(Lbrace); + parse_HyperDoc(); + if (token.type != Rbrace) { + curr_node->type = Noop; + fprintf(stderr, "(HyperdDoc) \\centerline was expecting a }\n"); + print_page_and_filename(); + print_next_ten_tokens(); + longjmp(jmpbuf, 1); + } + curr_node->type = Endcenter; +} + +void +parse_command(void) +{ + TextNode *link_node, *save_node, *arg_node; + + gInButton++; + if (gParserMode == SimpleMode) { + curr_node->type = Noop; + fprintf(stderr, "Parser Error token %s unexpected\n", + token_table[token.type]); + longjmp(jmpbuf, 1); + } + gStringValueOk = 1; + + /* set the values for the current node */ + curr_node->type = token.type; + curr_node->space = token.id[-1]; + + /* now parse for the label */ + link_node = curr_node; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + get_expected_token(Lbrace); + parse_HyperDoc(); + curr_node->type = Endbutton; + save_node = curr_node; + arg_node = alloc_node(); + curr_node = arg_node; + get_expected_token(Lbrace); + parse_HyperDoc(); + curr_node->type = Endarg; + link_node->link = make_link_window(arg_node, link_node->type, 0); + gStringValueOk = 0; + curr_node = save_node; + gInButton--; +} + +void +parse_button(void) +{ + TextNode *link_node, *save_node; + + gInButton++; + if (gParserMode == SimpleMode) { + curr_node->type = Noop; + fprintf(stderr, "Parser Error token %s unexpected\n", + token_table[token.type]); + longjmp(jmpbuf, 1); + } + /* fill the node */ + curr_node->type = token.type; + curr_node->space = token.id[-1]; + + /* the save the current node for creating the link and stuff */ + link_node = curr_node; + + /* then parse the label */ + curr_node->next = alloc_node(); + curr_node = curr_node->next; + get_expected_token(Lbrace); + parse_HyperDoc(); + curr_node->type = Endbutton; + + /* now try to get the argument node */ + save_node = curr_node; + get_expected_token(Lbrace); + save_node->data.node = alloc_node(); + curr_node = save_node->data.node; + parse_HyperDoc(); + curr_node->type = Endarg; + + /* + * buffer[0] = '\0'; print_to_string(arg_node, buffer + 1); + */ + link_node->link = + make_link_window(save_node->data.node, link_node->type, 0); + curr_node = save_node; + gInButton--; +} + +extern int example_number; + +void +parse_spadcommand(TextNode *spad_node) +{ + /*TextNode *node = NULL;*/ + + example_number++; + gInButton++; + spad_node->type = token.type; + spad_node->space = token.id[-1]; + get_expected_token(Lbrace); + cur_spadcom = curr_node; + + spad_node->next = alloc_node(); + curr_node = spad_node->next; + parse_HyperDoc(); + curr_node->type = Endspadcommand; + cur_spadcom = NULL; + spad_node->link = make_link_window(spad_node->next, spad_node->type, 1); + gInButton--; +} + +void +parse_spadsrc(TextNode *spad_node) +{ + char buf[512], *c = buf; + int ch, start_opts = 0; + /*TextNode *node = NULL;*/ + + example_number++; + gInButton++; + gInSpadsrc++; + spad_node->type = Spadsrc; + spad_node->space = token.id[-1]; + + cur_spadcom = curr_node; + spad_node->next = alloc_node(); + curr_node = spad_node->next; + + do { + ch = get_char(); + if (ch == ']') + start_opts = 0; + if (start_opts) + *c++ = ch; + if (ch == '[') + start_opts = 1; + } while (ch != '\n'); + *c = '\0'; + parse_verbatim(Spadsrctxt); + parse_from_string(buf); + + curr_node->type = Endspadsrc; + cur_spadcom = NULL; + spad_node->link = make_link_window(spad_node->next, Spadsrc, 1); + gInButton--; + gInSpadsrc--; +} + +void +parse_env(TextNode *node) +{ + char *env; + char buff[256]; + char *buff_pntr = &buff[1]; + int noEnv = 0; + + get_expected_token(Lbrace); + get_expected_token(Word); + env = getenv(token.id); + + if (env == NULL) { + /** The environment variable was not found **/ + + fprintf(stderr, "(HyperDoc) Warning: environment variable \'%s\' was not found.\n", + token.id); + + env = halloc(1, "string"); + env[0] = '\0'; + noEnv = 1; + } + + buff[0] = token.id[-1]; + strcpy(buff_pntr, env); + + if (noEnv) + free(env); + + node->data.text = alloc_string(buff_pntr); + node->type = Word; + + get_expected_token(Rbrace); +} + +/* + * This parse_value routine accepts an empty {} but makes it a zero instead + * of a one. Thus \indent{} is equivelant to \indent{0} + */ + +void +parse_value1(void) +{ + TextNode *value_node, *ocn = curr_node; + char *s; + + curr_node->type = token.type; + curr_node->space = token.id[-1]; + + value_node = alloc_node(); + value_node->type = Word; + curr_node->data.node = value_node; + get_expected_token(Lbrace); + s = get_input_string(); + if (!is_number(s)) { + fprintf(stderr, + "Parser Error: parse for value was expecting a numeric value\n"); + strcpy(value_node->data.text, "0"); + } + else { + value_node->data.text = alloc_string(s); + } + curr_node = ocn; +} + +/* + * This command accepts an empty argument command. Thus \space{} is + * equivelant \space{1} + */ + +void +parse_value2(void) +{ + TextNode *value_node, *ocn = curr_node; + char *s; + + curr_node->type = token.type; + curr_node->space = token.id[-1]; + + value_node = alloc_node(); + value_node->type = Word; + curr_node->data.node = value_node; + get_expected_token(Lbrace); + s = get_input_string(); + if (!is_number(s)) { + fprintf(stderr, + "Parser Error: parse for value was expecting a numeric value\n"); + strcpy(value_node->data.text, "1"); + } + else { + value_node->data.text = alloc_string(s); + } + curr_node = ocn; +} + + +/* parse a \table sommand */ + +void +parse_table(void) +{ + TextNode *tn = curr_node; + + if (gParserMode != AllMode) { + curr_node->type = Noop; + fprintf(stderr, "Parser Error token %s unexpected\n", + token_table[token.type]); + longjmp(jmpbuf, 1); + } + curr_node->type = Table; + get_expected_token(Lbrace); + curr_node->next = alloc_node(); + curr_node = curr_node->next; + + get_token(); + if (token.type == Lbrace) { + while (token.type != Rbrace) { + curr_node->type = Tableitem; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + parse_HyperDoc(); + curr_node->type = Endtableitem; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + get_token(); + } + curr_node->type = Endtable; + } + else { /* a patch for SG for empty tables */ + if (token.type != Rbrace) { + token_name(token.type); + fprintf(stderr, + "Unexpected Token %s found while parsing a table\n", + ebuffer); + print_page_and_filename(); + jump(); + } + tn->type = Noop; + tn->next = NULL; + free(curr_node); + curr_node = tn; + } +} + +void +parse_box(void) +{ + curr_node->type = token.type; + curr_node->space = token.id[-1]; + curr_node->width = -1; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + get_expected_token(Lbrace); + parse_HyperDoc(); + curr_node->type = Endbox; +} + +void +parse_mbox(void) +{ + curr_node->type = token.type; + curr_node->space = token.id[-1]; + curr_node->width = -1; + curr_node->next = alloc_node(); + curr_node = curr_node->next; + get_expected_token(Lbrace); + parse_HyperDoc(); + curr_node->type = Endbox; +} + +void +parse_free(void) +{ + TextNode *free_node = curr_node; + + curr_node->type = token.type; + curr_node->space = token.id[-1]; + curr_node->width = -1; + curr_node->data.node = alloc_node(); + curr_node = curr_node->data.node; + get_expected_token(Lbrace); + parse_HyperDoc(); + curr_node->type = Endarg; + curr_node = free_node; +} + +void +parse_help(void) +{ + curr_node->type = Noop; + get_token(); + if (token.type != Lbrace) { + token_name(token.type); + fprintf(stderr,"\\helppage was expecting a { and not a %s\n", ebuffer); + print_page_and_filename(); + jump(); + } + +/* before we clobber this pointer we better free the contents (cf. alloc_page) */ + free(gPageBeingParsed->helppage); + gPageBeingParsed->helppage = alloc_string(get_input_string()); + + if (token.type != Rbrace) { + token_name(token.type); + fprintf(stderr, "\\helppage was expecting a } and not a %s\n", + ebuffer); + print_page_and_filename(); + jump(); + } +} +@ +\section{readbitmap.c} +\subsection{zzopen change} +The [[zzopen]] function used to be called [[zopen]] but this name has +been picked up by Unix so we change it globally. +<>= + if (!(fd = zzopen(filename, "r"))) { + fprintf(stderr, "ReadBitmapFile: File >%s< not found\n", filename); + exit(-1); + } + +@ +\subsection{readbitmap.c} +<>= +#define _READBITMAP_C + +#include "debug.h" +<> + +#include "all-hyper-proto.h1" +#include "pixmap.h1" + +#define MAXLINE 256 + +/* + * This file was produced by J.M. Wiley with some help from the bitmap editor + * routine. It reads in a bitmap file, and calls XCreatePixmapFromBitmapData + * to transform it into a Pixmap. He did this because the routine + * XReadBitmapFile does not seeem to work to well (whatecer that means). + */ + +XImage * +HTReadBitmapFile(Display *display,int screen,char * filename, + int *width, int *height) +{ + XImage *image; + FILE *fd; + char Line[256], Buff[256]; + int num_chars; + char *ptr; + int rch; + int version; + int padding, chars_line, file_chars_line, file_chars; + int bytes; + int x_hot, y_hot; + + + image = XCreateImage(display, DefaultVisual(display, screen), 1, + XYBitmap, 0, NULL, 0, 0, 8, 0); + + + (image)->byte_order = LSBFirst; /* byte_order */ + (image)->bitmap_unit = 8; /* bitmap-unit */ + (image)->bitmap_bit_order = LSBFirst; /* bitmap-bit-order */ + +<> + /* + * Once it is open, lets get the width and height + */ + + if ((read_w_and_h(fd, (unsigned int *)width,(unsigned int *) height)) < 0) { + fprintf(stderr, "ReadBitmapFile: Bad file format in %s\n", filename); + exit(-1); + } + + + /* + * Now get the next line, and see if it is hot spots or bits + */ + if (fgets(Line, MAXLINE, fd) == NULL) { + fprintf(stderr, "ReadBitmapFile: Bad file format in %s\n", filename); + exit(-1); + } + + /* + * Now check the first character to see if it is a # or an s + */ + + if (Line[0] == '#') { + if ((read_hot(fd, Line, &x_hot, &y_hot)) < 0) { + fprintf(stderr, "ReadBitmapFile: Bad file format in %s\n", filename); + exit(-1); + } + } + + (image)->width = *width; + (image)->height = *height; + + /* + * figure out what version + */ + + if (sscanf(Line, "static short %s = {", Buff) == 1) + version = 10; + else if (sscanf(Line, "static unsigned char %s = {", Buff) == 1) + version = 11; + else if (sscanf(Line, "static char %s = {", Buff) == 1) + version = 11; + else { + fprintf(stderr, "ReadBitmapFile: Bad file format in %s\n", filename); + exit(-1); + } + + padding = 0; + if ((*width % 16) && ((*width % 16) < 9) && (version == 10)) + padding = 1; + + (image)->bytes_per_line = chars_line = (*width + 7) / 8; + file_chars_line = chars_line + padding; + + num_chars = chars_line * (*height); + file_chars = file_chars_line * (*height); + (image)->data = (char *) halloc((image)->bytes_per_line * (image)->height, + "Read Pixmap--Image data"); + + /* + * Since we are just holding the first line of the declaration, we can + * just start reading from fd + */ + + if (version == 10) + for (bytes = 0, ptr = (image)->data; bytes < file_chars; (bytes += 2)) { + if (fscanf(fd, " 0x%x%*[,}]%*[ \n]", &rch) != 1) { + fprintf(stderr, "ReadBitmapFile: Bad file format in %s\n", filename); + exit(-1); + } + *(ptr++) = rch & 0xff; + if (!padding || ((bytes + 2) % file_chars_line)) + *(ptr++) = rch >> 8; + } + else + for (bytes = 0, ptr = (image)->data; bytes < file_chars; bytes++, ptr++) { + if (fscanf(fd, " 0x%x%*[,}]%*[ \n]", &rch) != 1) { + fprintf(stderr, "ReadBitmapFile: Bad file format in %s\n", filename); + exit(-1); + } + *ptr = rch; + } + + fclose(fd); + + return image; +} + +static int +read_hot(FILE *fd,char Line[],int *x_hot,int *y_hot) +{ + char Buff[256]; + + /* + * Works much the same as get width and height, just new variables + */ + + if (sscanf(Line, "#define %s %d", Buff, x_hot) != 2) + return -1; + + if (fgets(Line, MAXLINE, fd) == NULL) + return -1; + + if (sscanf(Line, "#define %s %d", Buff, y_hot) != 2) + return -1; + + if (fgets(Line, MAXLINE, fd) == NULL) + return -1; + return 1; +} + +static int +read_w_and_h(FILE *fd,unsigned int *width,unsigned int *height) +{ + char Line[256], Buff[256]; + + if (fgets(Line, MAXLINE, fd) == NULL) + return -1; + + /* + * Once we have the line, scan it for the width + */ + + if (sscanf(Line, "#define %s %d", Buff, width) != 2) + return -1; + + /* + * Hopefully we have the width, now get the height the same way + */ + + if (fgets(Line, MAXLINE, fd) == NULL) + return -1; + + + /* + * Once we have the line, scan it for the height + */ + + if (sscanf(Line, "#define %s %d", Buff, height) != 2) + return -1; + + return 1; +} + + +/* read a bitmap file into memory */ + +ImageStruct * +insert_image_struct(char *filename) +{ + int bm_width, bm_height; + XImage *im; + ImageStruct *image; + + if (*filename == ' ') + filename++; + if ((image = (ImageStruct *) hash_find(&gImageHashTable, filename)) == NULL) { + im = HTReadBitmapFile(gXDisplay, gXScreenNumber, filename, + &bm_width, &bm_height); + + /* + * now add the image to the gImageHashTable + */ + + image = (ImageStruct *) halloc(sizeof(ImageStruct), "ImageStruct"); + image->image.xi = im; + image->width = image->image.xi->width; + image->height = image->image.xi->height; + image->filename = (char *) halloc(sizeof(char) * strlen(filename) +1, + "insert_image--filename"); + + /* strcpy(image->filename, filename); */ + + sprintf(image->filename, "%s", filename); + hash_insert(&gImageHashTable,(char *) image, image->filename); + } + return image; +} +@ +\section{scrollbar.h} +<>= +#ifndef _SCROLLBAR_H_ +#define _SCROLLBAR_H_ 1 + +<> + +extern int gScrollbarWidth; + +#endif +@ +\section{scrollbar.c} +<>= +/****************************************************************************** + * + * scrollbar.c: HyperDoc Scrollbar routines + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _SCROLLBAR_C +#include "debug.h" + +<> +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + +/************************************************************************* + Scrollbar Comments 10/08/89 + + The scrollbar is displayed on the side of the HyperDoc display, if needed. + It is composed of four windows + + fScrollUpWindow -- the arrowed box at the top of the scrollbar. Scrolls the + window up a line at a time. + fScrollDownWindow -- Located at the bottom of the window, it is used to scroll + down a single line at a time. + scrollbar -- this is the window which does the variable scrolling. It + houses the actual scroller. + scroller -- This is the scroller inside the scroll bar. + + The procedure below, makes all these windows, and also makes three bitmaps, + sup -- The up arrow for the fScrollUpWindow. + sdown -- the down arrow for the fScrollDownWindow. + scroller -- the scroller stipple. + It then fills the window with the proper Pixmap background. + + The scrollbar and scroller works as follows. The size of the scroller is + calculated as + + size of scroller size of visible text + ----------------- === ------------------------------ . + size of scrollbar size of whole scrolling region + + The top of the scroller shows the relative position in the page of + the top of the scrolling region. This way the user knows how far + down the page he or she has moved. + When the user clicks in the scrollbar, the center of the + scroller, if possible, is placed at the point of the click. + + See the routines + showScrollBars -- to see how the scroll bars are actually realized. + moveScroller -- to see how the scroller is moved when the user scrolls + + + **************************************************************************/ + +static int ch(int height); +static void changeWindowBackgroundPixmap(Window window, Pixmap pixmap); + +static Pixmap sup = 0, sdown = 0, sup_pressed = 0, sdown_pressed = 0, scroller = 0, scrollbar_pix = 0; + +#define sdown3d_width 21 +#define sdown3d_height 21 +static char sdown3d_bits[] = { + 0xaa, 0xaa, 0x0a, 0x55, 0x55, 0x15, 0x02, 0x00, 0x0c, 0x51, 0x55, 0x15, + 0xaa, 0xaa, 0x0e, 0x51, 0x5f, 0x15, 0xaa, 0xae, 0x0e, 0x51, 0x5f, 0x15, + 0xaa, 0xae, 0x0e, 0x51, 0x5f, 0x15, 0xea, 0xff, 0x0e, 0xd1, 0x7f, 0x15, + 0xaa, 0xbf, 0x0e, 0x51, 0x5f, 0x15, 0xaa, 0xae, 0x0e, 0x51, 0x55, 0x15, + 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x15, 0xfe, 0xff, 0x0f, 0x55, 0x55, 0x15, + 0xaa, 0xaa, 0x0a}; +#define sdown3dpr_width 21 +#define sdown3dpr_height 21 +static char sdown3dpr_bits[] = { + 0xaa, 0xaa, 0x0a, 0x55, 0x55, 0x15, 0xfe, 0xff, 0x0f, 0x55, 0x55, 0x11, + 0xae, 0xaa, 0x0a, 0x55, 0x55, 0x11, 0xae, 0xbe, 0x0a, 0x55, 0x5d, 0x11, + 0xae, 0xbe, 0x0a, 0x55, 0x5d, 0x11, 0xae, 0xbe, 0x0a, 0xd5, 0xff, 0x11, + 0xae, 0xff, 0x0a, 0x55, 0x7f, 0x11, 0xae, 0xbe, 0x0a, 0x55, 0x5d, 0x11, + 0xae, 0xaa, 0x0a, 0x55, 0x55, 0x11, 0x06, 0x00, 0x08, 0x55, 0x55, 0x15, + 0xaa, 0xaa, 0x0a}; + +#define sup3d_width 21 +#define sup3d_height 21 +static char sup3d_bits[] = { + 0xaa, 0xaa, 0x0a, 0x55, 0x55, 0x15, 0x02, 0x00, 0x0c, 0x51, 0x55, 0x15, + 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x15, 0xaa, 0xae, 0x0e, 0x51, 0x5f, 0x15, + 0xaa, 0xbf, 0x0e, 0xd1, 0x7f, 0x15, 0xea, 0xff, 0x0e, 0x51, 0x5f, 0x15, + 0xaa, 0xae, 0x0e, 0x51, 0x5f, 0x15, 0xaa, 0xae, 0x0e, 0x51, 0x5f, 0x15, + 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x15, 0xfa, 0xff, 0x0f, 0x55, 0x55, 0x15, + 0xaa, 0xaa, 0x0a}; +#define sup3dpr_width 21 +#define sup3dpr_height 21 +static char sup3dpr_bits[] = { + 0xaa, 0xaa, 0x0a, 0x55, 0x55, 0x15, 0xfe, 0xff, 0x0f, 0x55, 0x55, 0x11, + 0xae, 0xaa, 0x0a, 0x55, 0x55, 0x11, 0xae, 0xaa, 0x0a, 0x55, 0x5d, 0x11, + 0xae, 0xbe, 0x0a, 0x55, 0x7f, 0x11, 0xae, 0xff, 0x0a, 0xd5, 0xff, 0x11, + 0xae, 0xbe, 0x0a, 0x55, 0x5d, 0x11, 0xae, 0xbe, 0x0a, 0x55, 0x5d, 0x11, + 0xae, 0xbe, 0x0a, 0x55, 0x55, 0x11, 0x06, 0x00, 0x08, 0x55, 0x55, 0x15, + 0xaa, 0xaa, 0x0a}; + +#define sup_width sup3d_width +#define sup_height sup3d_height +#define sup_bits sup3d_bits + +#define sdown_width sdown3d_width +#define sdown_height sdown3d_height +#define sdown_bits sdown3d_bits + +#define BACKCOLOR gControlBackgroundColor +#define FORECOLOR gControlForegroundColor + +#define scroller_width 2 +#define scroller_height 2 +static char scroller_bits[] = { + 0x01, 0x02}; + + + +static int supheight = sup_height; +static int supwidth = sup_width; + +#define scrollbar_pix_width 3 +#define scrollbar_pix_height 3 +static char scrollbar_pix_bits[] = {0x00, 0x03, 0x00}; + + + +int gScrollbarWidth = sup_width + 2; + + + +void +makeScrollBarWindows(void) +{ + XSetWindowAttributes at; + + at.cursor = gActiveCursor; + at.event_mask = ButtonPress; + /** create the bitmaps **/ + if (supwidth != sdown_width || supheight != sdown_height) { + fprintf(stderr, + "Scrollbar error, up and down pointers must have the same dimensions\n"); + exit(-1); + } + + if (sup == 0) + sup = XCreatePixmapFromBitmapData( + gXDisplay, + RootWindow(gXDisplay, gXScreenNumber), + sup_bits, supwidth, supheight, + FORECOLOR, BACKCOLOR, + DefaultDepth(gXDisplay, gXScreenNumber)); + + if (sdown == 0) + sdown = XCreatePixmapFromBitmapData( + gXDisplay, + RootWindow(gXDisplay, gXScreenNumber), + sdown_bits, sdown_width, sdown_height, + FORECOLOR, BACKCOLOR, + DefaultDepth(gXDisplay, gXScreenNumber)); + + sup_pressed = XCreatePixmapFromBitmapData( + gXDisplay, + RootWindow(gXDisplay, gXScreenNumber), + sup3dpr_bits, sup3dpr_width, sup3dpr_height, + FORECOLOR, BACKCOLOR, + DefaultDepth(gXDisplay, gXScreenNumber)); + sdown_pressed = XCreatePixmapFromBitmapData( + gXDisplay, + RootWindow(gXDisplay, gXScreenNumber), + sdown3dpr_bits, sdown3dpr_width, sdown3dpr_height, + FORECOLOR, BACKCOLOR, + DefaultDepth(gXDisplay, gXScreenNumber)); + + gWindow->fScrollUpWindow = XCreateSimpleWindow(gXDisplay, gWindow->fMainWindow, + 1, 1, supwidth, supheight, + gWindow->border_width, + gBorderColor, + BACKCOLOR); + + gWindow->fScrollDownWindow = XCreateSimpleWindow(gXDisplay, gWindow->fMainWindow, + 1, 1, sdown_width, sdown_height, + gWindow->border_width, + gBorderColor, + BACKCOLOR); + + gWindow->scrollbar = XCreateSimpleWindow(gXDisplay, gWindow->fMainWindow, + 1, 1, 1, 1, + gWindow->border_width, + gBorderColor, + BACKCOLOR); + gWindow->scroller = XCreateSimpleWindow(gXDisplay, gWindow->scrollbar, + 1, 1, 1, 1, 0, + gBorderColor, + BACKCOLOR); + +#ifdef DEBUG + fprintf(stderr, "Changing Window Attributes in scrollbar.c #2\n"); +#endif + + at.background_pixmap = sup; + XChangeWindowAttributes(gXDisplay, gWindow->fScrollUpWindow, + CWBackPixmap | CWEventMask | CWCursor, &at); + + at.background_pixmap = sdown; + XChangeWindowAttributes(gXDisplay, gWindow->fScrollDownWindow, + CWBackPixmap | CWEventMask | CWCursor, &at); + + XChangeWindowAttributes(gXDisplay, gWindow->scrollbar, + CWEventMask | CWCursor, &at); + + + if (scroller == 0) + scroller = XCreatePixmapFromBitmapData(gXDisplay, + RootWindow(gXDisplay, gXScreenNumber), + scroller_bits, scroller_width, + scroller_height, + FORECOLOR, + BACKCOLOR, + DefaultDepth(gXDisplay, gXScreenNumber)); + if (scrollbar_pix == 0) + scrollbar_pix = XCreatePixmapFromBitmapData(gXDisplay, + RootWindow(gXDisplay, gXScreenNumber), + scrollbar_pix_bits, + scrollbar_pix_width, + scrollbar_pix_height, + FORECOLOR, + BACKCOLOR, + DefaultDepth(gXDisplay, gXScreenNumber)); + + at.background_pixmap = scroller; + XChangeWindowAttributes(gXDisplay, gWindow->scroller, + CWBackPixmap | CWCursor, &at); + at.background_pixmap = scrollbar_pix; + XChangeWindowAttributes(gXDisplay, gWindow->scrollbar, + CWBackPixmap, &at); +} + +static void +drawScroller3DEffects(HDWindow * hdWindow, int x1, int y1, int x2, int y2) +{ + XClearWindow(gXDisplay, hdWindow->scroller); + + /* draw right "black" line */ + + XDrawLine(gXDisplay, hdWindow->scroller, hdWindow->fControlGC, + x2 - 3, y1 + 2, x2 - 3, y2 - 3); + + /* draw bottom "black" line */ + + XDrawLine(gXDisplay, hdWindow->scroller, hdWindow->fControlGC, + x1 + 2, y2 - 3, x2 - 3, y2 - 3); + + /* flip foreground and background colors */ + + XSetBackground(gXDisplay, hdWindow->fControlGC, gControlForegroundColor); + XSetForeground(gXDisplay, hdWindow->fControlGC, gControlBackgroundColor); + + /* draw top "white" line */ + + XDrawLine(gXDisplay, hdWindow->scroller, hdWindow->fControlGC, + x1 + 2, y1 + 2, x2 - 3, y1 + 2); + + /* draw left "white" line */ + + XDrawLine(gXDisplay, hdWindow->scroller, hdWindow->fControlGC, + x1 + 2, y1 + 2, x1 + 2, y2 - 3); + + /* reset colors */ + + XSetBackground(gXDisplay, hdWindow->fControlGC, gControlBackgroundColor); + XSetForeground(gXDisplay, hdWindow->fControlGC, gControlForegroundColor); +} + +void +showScrollBars(HDWindow * hdWindow) +{ + XWindowChanges wc; + /*int src_x = 0, src_y = 0;*/ + /*unsigned int width = supwidth, height = supheight;*/ + /*int dest_x = 0, dest_y = 0;*/ + + /* see if we even need scroll bars */ + + if (hdWindow->page->scrolling->height <= hdWindow->scrollheight) + return; + + wc.x = hdWindow->scrollx; + wc.y = hdWindow->scrollupy; + wc.height = supheight; + wc.width = supwidth; + XConfigureWindow(gXDisplay, hdWindow->fScrollUpWindow, CWX | CWY | CWHeight + | CWWidth, &wc); + wc.y = hdWindow->scrolldowny; + XConfigureWindow(gXDisplay, hdWindow->fScrollDownWindow, + CWX | CWY | CWHeight | CWWidth, + &wc); + wc.height = hdWindow->fScrollBarHeight; + wc.y = hdWindow->scrollbary; + XConfigureWindow(gXDisplay, hdWindow->scrollbar, + CWX | CWY | CWHeight | CWWidth, + &wc); + wc.x = 0; + wc.y = hdWindow->fScrollerTopPos; + wc.width = supwidth; + wc.height = hdWindow->fScrollerHeight; + XConfigureWindow(gXDisplay, hdWindow->scroller, + CWX | CWY | CWHeight | CWWidth, + &wc); + + /* + * Now we map the windows, since the bitmaps are the backgrounds for the + * windows, we need to worry about redrawing them. + */ + + XMapWindow(gXDisplay, hdWindow->fScrollUpWindow); + XMapWindow(gXDisplay, hdWindow->fScrollDownWindow); + XMapWindow(gXDisplay, hdWindow->scrollbar); + XMapWindow(gXDisplay, hdWindow->scroller); + + drawScroller3DEffects(hdWindow, 0, 0, wc.width, wc.height); +} + + +/************************************************************************ + + Moves the scroller to its proper place within the scrollbar. It + calculates how far down the page we are, and then moves the scroller + accordingly + + **************************************************************************/ + +void +moveScroller(HDWindow * hdWindow) +{ + XWindowChanges wc; + + /** moves the scroller to it's proper place **/ + + int t = (int) (hdWindow->fScrollBarHeight * (-hdWindow->page->scroll_off)); + hdWindow->fScrollerTopPos = (int) (t / hdWindow->page->scrolling->height); + wc.x = 0; + wc.y = hdWindow->fScrollerTopPos; + wc.width = supwidth; + wc.height = hdWindow->fScrollerHeight; + XConfigureWindow(gXDisplay, hdWindow->scroller, + CWX | CWY | CWHeight | CWWidth, + &wc); + drawScroller3DEffects(hdWindow, 0, 0, wc.width, wc.height); +} + +#define tophalf(y) ((y % 2 == 0)?(y/2):(y/2) + 1) +#define bothalf(y) (y/2) + +void +drawScrollLines(void) +{ + /* Checks the page_flags to see if we need a top, or a bottom line. */ + /* These are the horizontal lines framing a scrolling region when the */ + /* scrolling region is not the entire window. */ + + if (!(gWindow->page->page_flags & NOLINES)) { + line_top_group(); + if (gWindow->page->header->height) { + XDrawLine(gXDisplay, gWindow->fMainWindow, gWindow->fStandardGC, + 0, + gWindow->page->top_scroll_margin - tophalf(gWindow->border_width) + - 2 * scroll_top_margin, + gWindow->scrollwidth, + gWindow->page->top_scroll_margin - tophalf(gWindow->border_width) + - 2 * scroll_top_margin); + } + if (gWindow->page->footer->height) { + XDrawLine(gXDisplay, gWindow->fMainWindow, gWindow->fStandardGC, + 0, + gWindow->page->bot_scroll_margin + bothalf(gWindow->border_width) - 1, + gWindow->scrollwidth, + gWindow->page->bot_scroll_margin + bothalf(gWindow->border_width) - 1); + } + pop_group_stack(); + } +} + + +/* + * Calculates all the measures for the scrollbars + */ + +void +calculateScrollBarMeasures(void) +{ + int t; + + /* + * The scrollhieght is the height of the scrolling region visible in the + * HT window. Notice how it is a multiple of line height. This was needed + * to make everything scroll nicely. + */ + + gWindow->scrollheight = gWindow->page->bot_scroll_margin - + gWindow->page->top_scroll_margin - scroll_top_margin; + gWindow->scrollheight = gWindow->scrollheight - gWindow->scrollheight % line_height; + + /* + * Now do a quick check to see if I really need a scroll bar, and if not, + * just return right away + */ + + if (gWindow->scrollheight >= gWindow->page->scrolling->height) { + gWindow->page->scroll_off = 0; + return; + } + + /* + * The height of the scrollbar region, extends form the top page margin + * all the way to the bottom, excluding the room needed for the up and + * down windows + */ + + gWindow->fScrollBarHeight = gWindow->page->bot_scroll_margin - + gWindow->page->top_scroll_margin - 2 * supheight - + 2 * gWindow->border_width; + + gWindow->scrollupy = gWindow->page->top_scroll_margin - gWindow->border_width; + gWindow->scrollupy -= 2 * scroll_top_margin; + gWindow->scrolldowny = gWindow->page->bot_scroll_margin + - supheight - gWindow->border_width; + gWindow->scrollbary = gWindow->scrollupy + supheight + gWindow->border_width; + gWindow->scrollx = gWindow->width - supwidth - gWindow->border_width; + + /* + * the scroller height is calculated from the following formula + * + * fScrollerHeight scrollheight -------------- == + * --------- ------------- fScrollBarHeight + * page->scrolling_height + * + */ + + gWindow->fScrollerHeight = 1 + 2 * scroll_top_margin + /** possible integer error correction **/ + (int) (gWindow->fScrollBarHeight * gWindow->scrollheight / gWindow->page->scrolling->height); + + /* + * Check the scroll offset, to see if it is too Large + */ + + if (-(gWindow->page->scroll_off) > + (gWindow->page->scrolling->height - gWindow->scrollheight)) + gWindow->page->scroll_off = + -(gWindow->page->scrolling->height - gWindow->scrollheight); + + /* + * Then move the top of the scroller to it's proper position + */ + + gWindow->fScrollBarHeight += 2 * scroll_top_margin; + t = (int) (gWindow->fScrollBarHeight * (-gWindow->page->scroll_off)); + gWindow->fScrollerTopPos = (int) (t / (gWindow->page->scrolling->height)); +} + +void +linkScrollBars(void) +{ + HyperLink *uplink = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"); + HyperLink *downlink = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"); + HyperLink *barlink = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"); + + uplink->win = gWindow->fScrollUpWindow; + downlink->win = gWindow->fScrollDownWindow; + barlink->win = gWindow->scrollbar; + uplink->type = Scrollupbutton; + downlink->type = Scrolldownbutton; + barlink->type = Scrollbar; + barlink->x = barlink->y = 0; + uplink->x = uplink->y = 0; + downlink->x = downlink->y = 0; + uplink->reference.node = NULL; + downlink->reference.node = NULL; + hash_insert(gLinkHashTable, (char *)uplink,(char *) &uplink->win); + hash_insert(gLinkHashTable, (char *)barlink,(char *) &barlink->win); + hash_insert(gLinkHashTable, (char *)downlink,(char *) &downlink->win); +} + +void +scrollUp(void) +{ + + if (gWindow->page->scroll_off == 0); /* BeepAtTheUser(); *//* The + * beeping annoyed me. RSS */ + else { + changeWindowBackgroundPixmap(gWindow->fScrollUpWindow, sup_pressed); + + gWindow->page->scroll_off += line_height; /* Scroll a line */ + if (gWindow->page->scroll_off > 0) + gWindow->page->scroll_off = 0; + XCopyArea(gXDisplay, gWindow->fScrollWindow, gWindow->fScrollWindow, gWindow->fStandardGC, + 0, 0, + gWindow->scrollwidth, gWindow->scrollheight - line_height + 1, + 0, line_height); + XClearArea(gXDisplay, gWindow->fScrollWindow, 0, 0, + gWindow->scrollwidth, + line_height, False); + scroll_page(gWindow->page); + + changeWindowBackgroundPixmap(gWindow->fScrollUpWindow, sup); + } + +} + +void +scrollUpPage(void) +{ + if (gWindow->page->scroll_off == 0); /* BeepAtTheUser(); */ + else { + /* Scroll a page */ + + gWindow->page->scroll_off += ch(gWindow->scrollheight) - line_height; + if (gWindow->page->scroll_off > 0) + gWindow->page->scroll_off = 0; + + XClearWindow(gXDisplay, gWindow->fScrollWindow); + scroll_page(gWindow->page); + } +} + +void +scrollToFirstPage(void) +{ + if (gWindow->page->scroll_off == 0); /* BeepAtTheUser(); */ + else { + gWindow->page->scroll_off = 0; + XClearWindow(gXDisplay, gWindow->fScrollWindow); + scroll_page(gWindow->page); + } +} + +void +scrollDown(void) +{ + + if (-(gWindow->page->scroll_off) >= + (gWindow->page->scrolling->height - gWindow->scrollheight)) { + ; /* BeepAtTheUser(); */ + } + else { + changeWindowBackgroundPixmap(gWindow->fScrollDownWindow, sdown_pressed); + + gWindow->page->scroll_off -= line_height; /* Scroll a line */ + + XCopyArea(gXDisplay, gWindow->fScrollWindow, gWindow->fScrollWindow, gWindow->fStandardGC, + 0, line_height, + gWindow->scrollwidth, gWindow->scrollheight - line_height + 1, + 0, 0); + XClearArea(gXDisplay, gWindow->fScrollWindow, 0, + gWindow->scrollheight - line_height, + gWindow->scrollwidth, + line_height, False); + scroll_page(gWindow->page); + + changeWindowBackgroundPixmap(gWindow->fScrollDownWindow, sdown); + } +} + + +void +scrollDownPage(void) +{ + if (gWindow->page->scrolling == NULL || (-(gWindow->page->scroll_off) >= + (gWindow->page->scrolling->height - gWindow->scrollheight))) { + ; /* BeepAtTheUser(); */ + } + else { + gWindow->page->scroll_off -= ch(gWindow->scrollheight) - line_height; + + if (-(gWindow->page->scroll_off) > + (gWindow->page->scrolling->height - gWindow->scrollheight)) + gWindow->page->scroll_off = - + (gWindow->page->scrolling->height - gWindow->scrollheight); + + XClearWindow(gXDisplay, gWindow->fScrollWindow); + + scroll_page(gWindow->page); + } +} + +void +scrollScroller(XButtonEvent * event) +{ + + /* + * This routine checks to see where in the window the button press + * occured. It then tries to move the scroller so that the top of the + * scroller is at the spot of the event + */ + + int y = event->y; + int top = y; + + if (top < 0) { + top = 0; + if (gWindow->fScrollerTopPos == 0) + return; + gWindow->page->scroll_off = 0; + } + else if ((top + gWindow->fScrollerHeight) > gWindow->fScrollBarHeight) { + top = gWindow->fScrollBarHeight - gWindow->fScrollerHeight; + if (top == gWindow->fScrollerTopPos) + return; + gWindow->page->scroll_off = + -(gWindow->page->scrolling->height - gWindow->scrollheight); + gWindow->page->scroll_off -= gWindow->page->scroll_off % line_height; + } + else { /** top is in an ok spot **/ + int t; + + t = -(gWindow->page->scrolling->height) * top; + t = t / (gWindow->fScrollBarHeight); + if (gWindow->page->scroll_off == (t -= t % line_height)) + return; + gWindow->page->scroll_off = t; + gWindow->fScrollerTopPos = top; + } + XClearWindow(gXDisplay, gWindow->fScrollWindow); + scroll_page(gWindow->page); +} + + +void +hideScrollBars(HDWindow * hdWindow) +{ + XUnmapWindow(gXDisplay, hdWindow->fScrollDownWindow); + XUnmapWindow(gXDisplay, hdWindow->fScrollUpWindow); + XUnmapWindow(gXDisplay, hdWindow->scrollbar); + XUnmapWindow(gXDisplay, hdWindow->scroller); +} + +void +getScrollBarMinimumSize(int *width, int *height) +{ + (*width) = sup_width + 4; + (*height) = sup_height + sdown_height + 5; +} + +static int +ch(int height) +{ + /*int rheight;*/ + int rem = height % line_height; + + if (rem == 0) + return height; + return height - rem + line_height; +} + +static void +changeWindowBackgroundPixmap(Window window, Pixmap pixmap) +{ + if (pixmap) { + XSetWindowAttributes at; + + at.background_pixmap = pixmap; + XChangeWindowAttributes(gXDisplay, window, CWBackPixmap, &at); + XClearWindow(gXDisplay, window); + } +} +@ +\section{search.h} +Construct a page with a menu of references to the word. +The syntax of the command is: +\begin{verbatim} +htsearch word +\end{verbatim} +<>= +#!/bin/sh + +htbindir=$AXIOM/lib +htpagedir=$AXIOM/doc/hypertex/pages + + +if test -z "$1" +then + echo ""|$htbindir/presea case=1 - +else +( cd $htpagedir; $htbindir/hthits "$1" $htpagedir/ht.db | sort -r -n -k 1.22 | $htbindir/presea case=0 expr="$1" -) +fi @ +This is part of 'presea' which is is run on output + of 'hthits'. 'hthits' outputs looks like: +\begin{verbatim} + \newsearchresultentry{1}{Asp24 Example Code}{Asp24ExampleCode} + \newsearchresultentry{1}{Asp27 Example Code}{Asp27ExampleCode} + .... +\end{verbatim} +after splitting on ``[[{]]'' the first field is [['\newsearchresultentry']] +and the second is number of occurences of search term in the page. The +test for [['j >= 2']] is just to tolerate garbage. presea is supposed +to count the number of matches and put it in the header for search +results. The previous version reported no matches in the header. +This used to read: +\begin{verbatim} + a[n] = $0; + n=n+1; + j=split($0,b,"{"); + m=m+substr(b[j],1,length(b[j])-1); +\end{verbatim} +<>= +#!/bin/awk -f +BEGIN {n=0;m=0 +} + +{ + a[n] = $0; + n=n+1; + j=split($0,b,"{"); + if (j >= 2) + m=m+substr(b[2],1,length(b[2])-1); +} + +END { + printf ("\\begin{page}{staticsearchpage}"); + if (case==1) + printf ("{No matches found}\n") + else if ( n==0 || m==0 ) + printf ("{No matches found for {\\em %s}}\n",expr) + else + printf ("{%d matches found in %d pages for {\\em %s}}\n",m,n,expr); + printf ("Matches\\tab{8}in Page\n"); + printf "\\beginscroll\n"; + printf "\\beginmenu\n"; + for(i=0;i>= +#ifndef _SHOW_TYPES_H_ +#define _SHOW_TYPES_H_ 1 + +<> + +#endif +@ +\section{show-types.c} +<>= +/****************************************************************************** + * + * show_types.c: Show the various types of things that can show up in text + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _SHOW_TYPES_C +#include "debug.h" + + +<> +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + + + +/* + * Display the page whose extent has been computed, using the actual size of + * the window, and y_off to determine clipped areas + */ + +void +show_text(TextNode *node, int Ender) +{ + /*int twidth, len;*/ + /*int otext_x, otext_y, t;*/ + /*XFontStruct *old_font;*/ + /*int old_color;*/ + + for (; node != NULL; node = node->next) { + switch (node->type) { + case 0: + case Beginitems: + case Begintitems: + case Bound: + case Center: + case Free: + case HSpace: + case Indent: + case Indentrel: + case Item: + case Macro: + case Mbox: + case Newline: + case Noop: + case Par: + case Pound: + case Rbrace: + case Space: + case Tab: + case Table: + case Titem: + case VSpace: + break; + + case Dash: + case Fi: + case Ifcond: + if (visible(node->y, node->height)) { + if (strlen(node->data.text) > 1) { + XDrawLine(gXDisplay, gWindow->fDisplayedWindow, gWindow->fStandardGC, node->x, + node->y + gRegionOffset + y_off + - gTopOfGroupStack->cur_font->descent - + word_off_height, + node->x + node->width, + node->y + gRegionOffset + y_off - word_off_height - + gTopOfGroupStack->cur_font->descent); + } + else { + XDrawString(gXDisplay, gWindow->fDisplayedWindow, gWindow->fStandardGC, node->x, node->y + + gRegionOffset - gTopOfGroupStack->cur_font->descent + y_off, + node->data.text, 1); + } + } + else { + if (above(node->y)) + need_scroll_up_button = 1; + else if (below(node->y)) + need_scroll_down_button = 1; + } + break; + + case Lsquarebrace: + case Math: + case Punctuation: + case Rsquarebrace: + case Spadsrctxt: + case WindowId: + case Word: + if (visible(node->y, node->height)) + XDrawString(gXDisplay, gWindow->fDisplayedWindow, gWindow->fStandardGC, node->x, node->y + + gRegionOffset - gTopOfGroupStack->cur_font->descent + y_off, + node->data.text, node->width); + else { + if (above(node->y)) + need_scroll_up_button = 1; + else if (below(node->y)) + need_scroll_down_button = 1; + } + break; + + case Verbatim: + push_group_stack(); + tt_top_group(); + if (visible(node->y, node->height)) + XDrawString(gXDisplay, gWindow->fDisplayedWindow, gWindow->fStandardGC, node->x, node->y + + gRegionOffset - gTopOfGroupStack->cur_font->descent + y_off, + node->data.text, node->width); + else { + if (above(node->y)) + need_scroll_up_button = 1; + else if (below(node->y)) + need_scroll_down_button = 1; + } + pop_group_stack(); + break; + + case Horizontalline: + if (visible(node->y, node->height)) { + line_top_group(); + XDrawLine(gXDisplay, gWindow->fDisplayedWindow, gWindow->fStandardGC, 0, + node->y + gRegionOffset + y_off, + gWindow->width, + node->y + gRegionOffset + y_off); + pop_group_stack(); + } + else { + if (above(node->y)) + need_scroll_up_button = 1; + else if (below(node->y)) + need_scroll_down_button = 1; + } + break; + + case Box: + if (visible(node->y, node->height)) + XDrawRectangle(gXDisplay, gWindow->fDisplayedWindow, gWindow->fStandardGC, + node->x, + node->y + gRegionOffset + y_off - node->height, + node->width, + node->height); + else { + if (above(node->y)) + need_scroll_up_button = 1; + else if (below(node->y)) + need_scroll_down_button = 1; + } + break; + + + case Downlink: + case Link: + case LispDownLink: + case LispMemoLink: + case Lispcommand: + case Lispcommandquit: + case Lisplink: + case Lispwindowlink: + case Memolink: + case Qspadcall: + case Qspadcallquit: + case Returnbutton: + case Spadcall: + case Spadcallquit: + case Spaddownlink: + case Spadlink: + case Spadmemolink: + case Unixcommand: + case Unixlink: + case Upbutton: + case Windowlink: + if (pix_visible(node->y, node->height)) + show_link(node); + break; + + case Spadcommand: + case Spadgraph: + case Spadsrc: + show_spadcommand(node); + break; + + case Pastebutton: + if (visible(node->y, node->height)) + show_pastebutton(node); + break; + + case Paste: + show_paste(node); + break; + + case Group: + case Tableitem: + push_group_stack(); + break; + + case Controlbitmap: + show_image(node, gWindow->fControlGC); + break; + + case Inputbitmap: + show_image(node, gWindow->fStandardGC); + break; + + case Inputpixmap: + show_image(node, gWindow->fStandardGC); + break; + + case BoldFace: + bf_top_group(); + break; + + case Emphasize: + if (gTopOfGroupStack->cur_font == gRmFont) + em_top_group(); + else + rm_top_group(); + break; + + case It: + em_top_group(); + break; + + case Sl: + case Rm: + rm_top_group(); + break; + + case Tt: + tt_top_group(); + break; + + case Inputstring: + show_input(node); + break; + + case Radiobox: + case SimpleBox: + show_simple_box(node); + break; + + case Beep: + LoudBeepAtTheUser(); + break; + + case Description: + bf_top_group(); + break; + + case Endspadsrc: + case Endspadcommand: + gInAxiomCommand = 1; + case Endtableitem: + case Enddescription: + case Endpastebutton: + case Endlink: + case Endbutton: + case Endgroup: + pop_group_stack(); + case Endverbatim: + case Endmath: + case Endbox: + case Endtable: + case Endmbox: + case Endparameter: + case Endpaste: + case Endinputbox: + case Endcenter: + case Endmacro: + case Endif: + case Endtitems: + case Enditems: + + /* + * Now since I can show specific regions of the text, then at + * this point I should check to see if I am the end + */ + if (node->type == Ender) + return; + break; + case Endfooter: + case Endscrolling: + case Endheader: + case Endtitle: + + /* + * regardless of what ender I have, I always terminate showing + * with one of these + */ + return; + default: + fprintf(stderr, "Show_text: Unknown Node Type %d\n", node->type); + break; + } + } +} + +static void +show_link(TextNode *node) +{ + /* XFontStruct *old_font;*/ + XWindowChanges wc; + /*int twidth, boxwidth, old_color;*/ + int active; + + switch (node->type) { + case Upbutton: + if (!need_up_button) { + XClearArea(gXDisplay, gWindow->fDisplayedWindow, node->x, + node->y - node->height + gRegionOffset, + node->width, node->height, 0); + active = 0; + } + else + active = 1; + break; + case Returnbutton: + if (!need_return_button) { + XClearArea(gXDisplay, gWindow->fDisplayedWindow, node->x, + node->y - node->height + gRegionOffset, + node->width, node->height, 0); + active = 0; + } + else + active = 1; + break; + case Helpbutton: + if (!need_help_button) { + XClearArea(gXDisplay, gWindow->fDisplayedWindow, node->x, + node->y - node->height + gRegionOffset, + node->width, node->height, 0); + active = 0; + } + else + active = 1; + break; + default: + active = 1; + break; + } + + if (active) { + ButtonList *bl = alloc_button_list(); + + push_active_group(); + wc.x = node->x; + wc.y = node->y - node->height + y_off + gRegionOffset; + wc.height = node->height; + wc.width = node->width - trailing_space(node->next); + bl->x0 = wc.x; + bl->y0 = wc.y; + bl->x1 = bl->x0 + wc.width; + bl->y1 = bl->y0 + wc.height; + bl->link = node->link; + if (!not_in_scroll) { + bl->y0 += gWindow->page->top_scroll_margin + scroll_top_margin; + bl->y1 += gWindow->page->top_scroll_margin + scroll_top_margin; + bl->next = gWindow->page->s_button_list; + gWindow->page->s_button_list = bl; + } + else { + bl->next = gWindow->page->button_list; + gWindow->page->button_list = bl; + } + } + else + rm_top_group(); +} + +static void +show_paste(TextNode *node) +{ + PasteNode *paste; + + if (!(paste = (PasteNode *) hash_find(gWindow->fPasteHashTable, + node->data.text))) + return; + + /* + * Once I have got this far, then I had better save the current group + * stack and the item stack + */ + if (paste->group) + free_group_stack(paste->group); + paste->group = (GroupItem *) copy_group_stack(); + if (paste->item_stack) + free_item_stack(paste->item_stack); + paste->item_stack = (ItemStack *) copy_item_stack(); +} + +static void +show_pastebutton(TextNode *node) +{ + /*XFontStruct *old_font;*/ + XWindowChanges wc; + /*int twidth, boxwidth, old_color;*/ + /*int active;*/ + + push_active_group(); + wc.x = node->x; + wc.y = node->y - node->height + y_off + gRegionOffset; + wc.height = node->height; + wc.width = node->width - trailing_space(node->next); +#ifdef DEBUG + fprintf(stderr, "Configure in show_link %d %d %d %d\n", + wc.x, wc.y, wc.width, wc.height); +#endif + XConfigureWindow(gXDisplay, node->link->win, + CWX | CWY | CWHeight | CWWidth, &wc); + XMapWindow(gXDisplay, node->link->win); +} + +/* display an input string window */ + +static void +show_input(TextNode *node) +{ + /*XFontStruct *old_font;*/ + XWindowChanges wc; + /*int twidth, boxwidth, old_color;*/ + /*Window root, child;*/ + /*int root_x, root_y, win_x, win_y, buttons;*/ + InputItem *item; + char *inpbuffer; + + item = node->link->reference.string; + inpbuffer = item->curr_line->buffer; + + wc.border_width = 0; + wc.x = node->x; + wc.y = node->y + gRegionOffset + y_off - node->height + 2; + wc.height = node->height - 2; + wc.width = node->width; + if (pix_visible(node->y, node->height)) { + XConfigureWindow(gXDisplay, node->link->win, + CWX | CWY | CWHeight | CWWidth | CWBorderWidth, + &wc); + XMapWindow(gXDisplay, node->link->win); + } + XFlush(gXDisplay); + draw_inputsymbol(item); +} + +static void +show_simple_box(TextNode *node) +{ + XWindowChanges wc; + InputBox *box; + + /* first configure the box size properly */ + box = node->link->reference.box; + wc.x = node->x; + wc.y = node->y + gRegionOffset + y_off - node->height; + wc.height = ((box->picked) ? + (box->selected->height) : (box->unselected->height)); + wc.width = node->width; + if (visible(node->y + gTopOfGroupStack->cur_font->ascent, node->height)) { + XConfigureWindow(gXDisplay, node->link->win, CWX | CWY | CWHeight | CWWidth, + &wc); + XMapWindow(gXDisplay, node->link->win); + if (box->picked) + pick_box(box); + else + unpick_box(box); + } +} + +/* display a spad command node */ + +static void +show_spadcommand(TextNode *node) +{ + XWindowChanges wc; + + gInAxiomCommand = 1; + + push_spad_group(); + wc.x = node->x; + if (node->type == Spadsrc) + wc.y = node->y + gRegionOffset + y_off - 2 * node->height; + else + wc.y = node->y + gRegionOffset + y_off - node->height; + wc.height = node->height; + wc.width = node->width; +#ifdef DEBUG + fprintf(stderr, "Spadcommand configured %d x %d -- (%d, %d)\n", + wc.width, wc.height, wc.x, wc.y); +#endif + XConfigureWindow(gXDisplay, node->link->win, + CWX | CWY | CWHeight | CWWidth, &wc); + XMapWindow(gXDisplay, node->link->win); +} + + +/* display a pixmap */ + +static void +show_image(TextNode *node, GC gc) +{ + int src_x, src_y, src_width, src_height, dest_x, dest_y, ret_val; + + if (!pix_visible(node->y, node->height)) + return; + if (node->image.xi == NULL) + return; + + dest_x = node->x; + src_x = 0; + src_y = 0; + dest_y = node->y + gRegionOffset - node->height + y_off; + need_scroll_up_button = 1; + if (node->width > (right_margin - node->x)) + src_width = right_margin - node->x; + else + src_width = node->width; + + if (gDisplayRegion != Scrolling) { + src_y = 0; + src_height = node->image.xi->height; + } + else { + /* I may have only a partial image */ + if (dest_y < 0) { /* the top is cut off */ + src_y = -dest_y; + dest_y = 0; + src_height = node->image.xi->height - src_y; + } + else if (dest_y + node->image.xi->height > gWindow->scrollheight) { + /* the bottom is cut off */ + src_y = 0; + src_height = gWindow->scrollheight - dest_y; + } + else { /* the whole thing is visible */ + src_y = 0; + src_height = node->image.xi->height; + } + } + + ret_val = XPutImage(gXDisplay, gWindow->fDisplayedWindow, gc, + node->image.xi, src_x, src_y, dest_x, dest_y, + src_width, src_height); + + switch (ret_val) { + case BadDrawable: + fprintf(stderr, "(HyperDoc: show_image) bad drawable\n"); + break; + case BadGC: + fprintf(stderr, "(HyperDoc: show_image) bad GC"); + break; + case BadMatch: + fprintf(stderr, "(HyperDoc: show_image) bad match"); + break; + case BadValue: +#ifndef HP9platform + fprintf(stderr, "(HyperDoc: show_image) bad value"); +#endif /* HP complains about this*/ + break; + } +} +@ +\section{spadbuf.c} +<>= +#define _SPADBUF_C +#include "debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SGIplatform +#include +#endif + +#include "bsdsignal.h" +#include "edible.h" +#include "com.h" + +#include "spadbuf.h1" +#include "bsdsignal.h1" +#include "sockio-c.h1" +#include "edin.h1" +#include "wct.h1" +#include "prt.h1" +#include "cursor.h1" +#include "fnct-key.h1" + + + +unsigned char _INTR, _QUIT, _ERASE, _KILL, _EOF, _EOL, _RES1, _RES2; +int contNum; /* do reading and all the other fun stuff + * depend on this for all there ioctl's */ +int num_read; + +/* + * Here are the term structures I need for setting and resetting the terminal + * characteristics. + */ +struct termios oldbuf; /* the initial settings */ +struct termios canonbuf; /* set it to be canonical */ +struct termios childbuf; + +short INS_MODE; /* Flag for insert mode */ +short ECHOIT; /* Flag for echoing */ +short PTY; +int MODE; /* Am I in cbreak, raw, or canonical */ + +char in_buff[1024]; /* buffer for storing characters read + until they are processed */ +char buff[MAXLINE]; /* Buffers for collecting input and */ +int buff_flag[MAXLINE]; /* flags for whether buff chars + are printing or non-printing */ +int (*old_handler) (); +Sock *session_sock, *menu_sock; +char *buff_name = NULL; /* name for the aixterm */ + +/* + * This routine used to be used to send sigint onto spad, but now they go + * through just fine on their own reinstated for AIX V3.2 + */ + +static void +spadbuf_inter_handler(int sig) +{ + send_signal(session_sock, SIGUSR2); +} + +static void +spadbuf_function_chars(void) +{ + /** once I have that get the special characters ****/ + _INTR = oldbuf.c_cc[VINTR]; + _QUIT = oldbuf.c_cc[VQUIT]; + _ERASE = oldbuf.c_cc[VERASE]; + _KILL = oldbuf.c_cc[VKILL]; + _EOF = oldbuf.c_cc[VEOF]; + _EOL = oldbuf.c_cc[VEOL]; + return; +} + +/* act as terminal session for sock connected to stdin + and stdout of another process */ +static void +interp_io(void) +{ + char buf[1024]; + fd_set rd; + int len, command; + + while (1) { + FD_ZERO(&rd); + FD_SET(menu_sock->socket, &rd); + FD_SET(session_sock->socket, &rd); + FD_SET(1, &rd); + len = sselect(FD_SETSIZE, &rd, 0, 0, NULL); + if (len == -1) { + perror("stdio select"); + return; + } + if (FD_ISSET(session_sock->socket, &rd)) { + len = sread(session_sock, buf, 1024, "stdio"); + if (len == -1) + return; + else { + write(1, buf, len); + } + } + if (FD_ISSET(menu_sock->socket, &rd)) { + command = get_int(menu_sock); + switch (command) { + case -1: + exit(0); + case ReceiveInputLine: + get_string_buf(menu_sock, in_buff, 1024); + num_read = strlen(in_buff); + clear_buff(); + do_reading(); + break; + case TestLine: + break; + default: + break; + } + } + if (FD_ISSET(1, &rd)) { + num_read = read(0, in_buff, 1024); + do_reading(); + } + } +} + +static void +init_parent(void) +{ + + /** get the original termio settings, so I never have to check again **/ + if (tcgetattr(0,&oldbuf) == -1) { + perror("Clef Trying to get terms initial settings"); + exit(-1); + } + + /** get the settings for my different modes ***/ + if (tcgetattr(0,&canonbuf) == -1) { + perror("Clef Getting terminal settings"); + exit(-1); + } + + /*** set the buffer to read before an eoln is typed ***/ + canonbuf.c_lflag &= ~(ICANON | ECHO | ISIG); + canonbuf.c_lflag |= ISIG; + + /*** Accordingly tell it we want every character ***/ + canonbuf.c_cc[VMIN] = 1; /* we want every character */ + canonbuf.c_cc[VTIME] = 1; /* these may require tweaking */ + + if (tcsetattr(0, TCSAFLUSH, &canonbuf) == -1) { + perror("Spadbuf setting parent to canon"); + exit(0); + } + + /* + * This routine is in edin.c and sets the users preferences for function + * keys. In order to use it I have to set childbuf to be the same as + * oldbuf + */ + + + spadbuf_function_chars(); + INS_MODE = 0; + ECHOIT = 1; + Cursor_shape(2); +} + +int +main(int argc,char ** argv) +{ + /*int name_found;*/ + /*FILE *junk;*/ + FILE *fopen(); + + /* + * Modified on 6/13/90 for the command line completion abiltities of + * Since I am only calling this program from within spadint, I decided + * that the usage should be + * + * spadbuf page_name [completion_ files] + * + */ + if (argc < 2) { + fprintf(stderr, "Usage : spadbuf page_name [completion_files] \n"); + exit(-1); + } + buff_name = *++argv; + + while (*++argv) { + load_wct_file(*argv); + } + skim_wct(); + + session_sock = connect_to_local_server(SessionServer, InterpWindow, Forever); + menu_sock = connect_to_local_server(MenuServerName, InterpWindow, Forever); + + bsdSignal(SIGINT, spadbuf_inter_handler,RestartSystemCalls); + + /* + * set contNum so it is pointing down the socket to the childs + */ + contNum = session_sock->socket; + send_string(menu_sock, buff_name); + init_parent(); + define_function_keys(); + init_reader(); + PTY = 0; + interp_io(); + return(1); +} + + + +@ +\section{spadint.c} +<>= +/* Still a problem with close_client */ + +/* Communication interface for external AXIOM buffers */ +#define _SPADINT_C +#include "debug.h" + +#include + +<> +<> +<> +#include "bsdsignal.h" + +#include "all-hyper-proto.h1" +#include "sockio-c.h1" +#include "bsdsignal.h1" + + +typedef struct sock_list { /* linked list of Sock */ + Sock Socket; + struct sock_list *next; +} Sock_List; + +Sock_List *plSock = (Sock_List *) 0; +Sock *spad_socket = (Sock *) 0; /* to_server socket for SpadServer */ + +/* issue a AXIOM command to the buffer associated with a page */ +void +issue_spadcommand(HyperDocPage *page, TextNode *command, + int immediate, int type) +{ + char *buf; + int ret_val; + + ret_val = connect_spad(); + if (ret_val == NotConnected || ret_val == SpadBusy) + return; + + if (page->sock == NULL) + start_user_buffer(page); + ret_val = send_int(page->sock, TestLine); + if (ret_val == -1) { + page->sock = NULL; + clear_execution_marks(page->depend_hash); + issue_spadcommand(page, command, immediate, type); + return; + } + issue_dependent_commands(page, command, type); + ret_val = send_int(page->sock, ReceiveInputLine); + buf = print_to_string(command); + if (immediate) { + buf[strlen(buf) + 1] = '\0'; + buf[strlen(buf)] = '\n'; + } + if (type == Spadsrc) + send_pile(page->sock, buf); + else + send_string(page->sock, buf); + mark_as_executed(page, command, type); + gIsEndOfOutput = 0; +} +static void +send_pile(Sock *sock,char * str) +{ + FILE *f; + char name[512], command[512]; + + sprintf(name, "/tmp/hyper%s.input", getenv("SPADNUM")); + f = fopen(name, "w"); + if (f == NULL) { + fprintf(stderr, "Can't open temporary input file %s\n", name); + return; + } + fprintf(f, "%s", str); + fclose(f); + sprintf(command, ")read %s\n", name); + send_string(sock, command); +} +static void +issue_dependent_commands(HyperDocPage *page, TextNode *command,int type) +{ + TextNode *node, *depend_label; + SpadcomDepend *depend; + int end_type = (type == Spadcommand || type == Spadgraph) ? + (Endspadcommand) : (Endspadsrc); + + for (node = command->next; node->type != end_type; + node = node->next) + if (node->type == Free) + for (depend_label = node->data.node; depend_label != NULL; + depend_label = depend_label->next) + if (depend_label->type == Word) { + depend = (SpadcomDepend *) + hash_find(page->depend_hash, depend_label->data.text); + if (depend == NULL) { + fprintf(stderr, "Error: dependency on undefined label: %s\n", + depend_label->data.text); + continue; + } + if (!depend->executed) { + issue_spadcommand(page, depend->spadcom->next, 1, + depend->spadcom->type); + while (!gIsEndOfOutput) + pause(); + sleep(1); + } + } +} +static void +mark_as_executed(HyperDocPage *page, TextNode *command,int type) +{ + TextNode *node, *depend_label; + SpadcomDepend *depend; + int end_type = (type == Spadcommand || type == Spadgraph) + ? (Endspadcommand) : (Endspadsrc); + + for (node = command; node->type != end_type; node = node->next) + if (node->type == Bound) + for (depend_label = node->data.node; depend_label != NULL; + depend_label = depend_label->next) + if (depend_label->type == Word) { + depend = (SpadcomDepend *) + hash_find(page->depend_hash, depend_label->data.text); + if (depend == NULL) { + fprintf(stderr, "No dependency entry for label: %s\n", + depend_label->data.text); + continue; + } + depend->executed = 1; + } +} + +/* start a spad buffer for the page associated with the give */ +static void +start_user_buffer(HyperDocPage *page) +{ + char buf[1024], *title; + char *SPAD; + char spadbuf[250]; + char complfile[250]; + int ret_val; + + SPAD = (char *) getenv("AXIOM"); + if (SPAD == NULL) { + sprintf(SPAD, "/spad/mnt/rios"); + } + sprintf(spadbuf, "%s/lib/spadbuf", SPAD); + sprintf(complfile, "%s/lib/command.list", SPAD); + title = print_to_string(page->title); + if (access(complfile, R_OK) == 0) + + /* + * TTT says : why not invoke with "-name axiomclient" and set any + * defaults in the usual way + */ +#ifdef RIOSplatform + sprintf(buf, + "aixterm -sb -sl 500 -name axiomclient -n '%s' -T '%s' -e %s %s %s&", + title, title, spadbuf, page->name, complfile); + else + sprintf(buf, + "aixterm -sb -sl 500 -name axiomclient -n '%s' -T '%s' -e %s %s&", + title, title, spadbuf, page->name); +#else +#ifdef SUNplatform + sprintf(buf, + "xterm -sb -sl 500 -name axiomclient -n '%s' -T '%s' -e %s %s %s&", + title, title, spadbuf, page->name, complfile); + else + sprintf(buf, + "xterm -sb -sl 500 -name axiomclient -n '%s' -T '%s' -e %s %s&", + title, title, spadbuf, page->name); +#else + sprintf(buf, + "xterm -sb -sl 500 -name axiomclient -n '%s' -T '%s' -e %s %s %s&", + title, title, spadbuf, page->name, complfile); + else + sprintf(buf, + "xterm -sb -sl 500 -name axiomclient -n '%s' -T '%s' -e %s '%s'&", + title, title, spadbuf, page->name); +#endif +#endif + ret_val = system(buf); + if (ret_val == -1 || ret_val == 127) { + + /* + * perror("running the xterm spadbuf program"); exit(-1); + */ + } + accept_menu_server_connection(page); + sleep(2); +} + +/* Clears the execution marks in a hash table when a buffer has been killed */ +static void +clear_execution_marks(HashTable *depend_hash) +{ + int i; + HashEntry *h; + SpadcomDepend *depend; + + if (depend_hash == 0) + return; + for (i = 0; i < depend_hash->size; i++) + for (h = depend_hash->table[i]; h != NULL; h = h->next) { + depend = (SpadcomDepend *) h->data; + depend->executed = 0; + } +} + +Sock * +accept_menu_connection(Sock *server_sock) +{ + int sock_fd /*, session, ret_code*/; + Sock_List *pls; + /*Sock local_sock;*/ + + /* Could only be InterpWindow */ + + pls = (Sock_List *) halloc(sizeof(Sock_List),"SockList"); + sock_fd = accept(server_sock->socket, 0, 0); + if (sock_fd == -1) { + perror("session : accepting connection"); + return 0; + } + (pls->Socket).socket = sock_fd; + get_socket_type((Sock *) pls); + +#ifdef DEBUG + fprintf(stderr, + "session: accepted InterpWindow , fd = %d\n", sock_fd); +#endif + + + /* put new item at head of list */ + + if (plSock == (Sock_List *) 0) { + plSock = pls; + plSock->next = (Sock_List *) 0; + } + else { + pls->next = plSock; + plSock = pls; + } + + /* need to maintain socket_mask since we roll our own accept */ + + FD_SET(plSock->Socket.socket, &socket_mask); + return (Sock *) plSock; +} + +static void +accept_menu_server_connection(HyperDocPage *page) +{ + + /* + * TTT thinks this code should just provide a Sock to the page. The only + * client assumed is a spadbuf. Since spadbuf was invoked with the page + * name, it just passes it back here as a check (get_string line). + */ + int ret_code/*, i*/; + fd_set rd; + Sock *sock; + char *buf_name; + HyperDocPage *npage; + + if (page->sock != NULL) + return; + while (1) { + rd = server_mask; + ret_code = sselect(FD_SETSIZE, &rd, 0, 0, NULL); + if (ret_code == -1) { + perror("Session manager select"); + continue; + } + + if (server[1].socket > 0 && FD_ISSET(server[1].socket, &rd)) { + sock = accept_menu_connection(server + 1); + if (sock == 0) + return; + if (sock->purpose == InterpWindow) { + buf_name = get_string(sock); + npage = (HyperDocPage *) + hash_find(gWindow->fPageHashTable, buf_name); + if (npage == NULL) { + + /* + * Lets just try using the current page TTT doesn't know + * why this could be detrimental + * + * fprintf(stderr, "connecting spadbuf to unknown page: + * %s\n", buf_name); + */ + page->sock = sock; + return; + } + else { + + /* + * For some reason npage and page may be different TTT + * thinks this happens when a dynamic page has the same + * name as an existing static page. + */ + npage->sock = sock; + page->sock = sock; + } + if (!strcmp(buf_name, page->name)) { + return; + } + } + } + } +} + + +/* + * This procedure takes a HyperDoc node, and expands it into string + */ + +char *p2sBuf = NULL; +int p2sBufSize = 0; + +/* + * This routine takes a text node and creates a string out of it. This is for + * use with things such as spad commands. There are a very limited set of + * node types it can handle, so be careful + */ + +char * +print_to_string(TextNode *command) +{ + int len = 0; + + print_to_string1(command, &len); + p2sBuf = resizeBuffer(len, p2sBuf, &p2sBufSize); + return print_to_string1(command, NULL); +} + +/* +see the code in ht-util.boot + $funnyQuote := char 127 + $funnyBacks := char 128 +*/ +#define funnyEscape(c) ((c) == '"' ? '\177' : ((c) == '\\' ? '\200' : c)) +#define funnyUnescape(c) ((c) == '\177' ? '"' : ((c) == '\200' ? '\\' : c)) +#define storeChar(ch) if (sizeBuf) (*sizeBuf)++; else *c++ = (ch) +#define storeString(str) for (s=str;*s;s++) {storeChar(*s);} + +extern int include_bf; + +char * +print_to_string1(TextNode *command,int * sizeBuf) +{ + char *c = p2sBuf; + char *s; + InputItem *item; + LineStruct *curr_line; + int lcount; + InputBox *box; + int num_spaces; + int count; + TextNode *node; + + /* + * Init the stack of text nodes, things are pushed on here when I trace + * through a nodes data.node. This way I always no where my next is. + */ + + for (node = command; node != NULL;) { + switch (node->type) { + case Newline: + storeChar('\n'); + node = node->next; + break; + case Ifcond: + if (check_condition(node->data.ifnode->cond)) + node = node->data.ifnode->thennode; + else + node = node->data.ifnode->elsenode; + break; + case Endarg: + case Endspadcommand: + case Endspadsrc: + case Endpix: + storeChar('\0'); + return p2sBuf; + case Endverbatim: + case Endif: + case Fi: + case Endmacro: + case Endparameter: + case Rbrace: + case Endgroup: + node = node->next; + break; + case Punctuation: + + /* + * Simply copy the piece of text + */ + if (node->space & FRONTSPACE) { storeChar(' '); } + for (s = node->data.text; *s; s++) { storeChar(*s); } + node = node->next; + break; + case WindowId: + + /* + * Simply copy the piece of text + */ + if (node->space) { storeChar(' '); } + for (s = node->data.text; *s; s++) { storeChar(*s); } + storeChar(' '); + node = node->next; + break; + case Verbatim: + case Spadsrctxt: + + /* + * Simply copy the piece of text + */ + if (node->space) { storeChar(' '); } + for (s = node->data.text; *s; s++) { storeChar(*s); } + + /* + * now add the eol + */ + + /* + * if(node->next && node->next->type != Endspadsrc) + * storeChar('\n'); + */ + node = node->next; + break; + case Dash: + case Rsquarebrace: + case Lsquarebrace: + case Word: + + /* + * Simply copy the piece of text + */ + if (node->space) { storeChar(' '); } + for (s = node->data.text; *s; s++) { storeChar(*s); } + node = node->next; + break; + case BoxValue: + box = + (InputBox *) hash_find(gWindow->page->box_hash, node->data.text); + if (box == NULL) { + fprintf(stderr, + "Print_to_string:Box %s Has no symbol table entry\n", + node->data.text); + exit(-1); + } + storeChar(' '); + if (box->picked) { + storeChar('t'); + } + else { + storeChar('n'); + storeChar('i'); + storeChar('l'); + } + node = node->next; + break; + case StringValue: + item = return_item(node->data.text); + if (item != NULL) { + if (node->space) + storeChar(' '); + curr_line = item->lines; + while (curr_line != NULL) { + for (lcount = 0, s = curr_line->buffer; *s && lcount < item->size; + s++, lcount++) { + storeChar(funnyUnescape(*s)); + } + if (curr_line->len <= item->size && curr_line->next) + storeChar('\n'); + curr_line = curr_line->next; + } + } + else if ((box = (InputBox *) hash_find(gWindow->page->box_hash, + node->data.text)) != NULL) { + if (node->space) { storeChar(' '); } + if (box->picked) { + storeChar('t'); + } + else { + storeChar('n'); + storeChar('i'); + storeChar('l'); + } + } + else { + fprintf(stderr, "Error, Symbol %s has no symbol table entry\n", + node->data.text); + exit(-1); + } + node = node->next; + break; + case Space: + num_spaces = (node->data.node != NULL ? + atoi(node->data.node->data.text) : 1); + for (count = 0; count < num_spaces; count++) + storeChar(' '); + node = node->next; + break; + case Titlenode: + case Endtitle: + case Center: + case Endcenter: + case BoldFace: + case Emphasize: + case Indentrel: + node = node->next; + break; + case Bound: + if (include_bf) { + int len, i; + TextNode *n2 = node->data.node; + + storeChar('\\'); + storeChar('b'); + storeChar('o'); + storeChar('u'); + storeChar('n'); + storeChar('d'); + storeChar('{'); + for (; n2->type != Endarg; n2 = n2->next) { + if (n2->type == Word) { + len = strlen(n2->data.text); + for (i = 0; i < len; i++) + storeChar(n2->data.text[i]); + storeChar(' '); + } + } + storeChar('}'); + } + node = node->next; + break; + case Free: + if (include_bf) { + int len, i; + TextNode *n2 = node->data.node; + + storeChar('\\'); + storeChar('f'); + storeChar('r'); + storeChar('e'); + storeChar('e'); + storeChar('{'); + for (; n2->type != Endarg; n2 = n2->next) { + if (n2->type == Word) { + len = strlen(n2->data.text); + for (i = 0; i < len; i++) + storeChar(n2->data.text[i]); + storeChar(' '); + } + } + storeChar('}'); + } + node = node->next; + break; + case Macro: + node = node->next; + break; + case Pound: + if (node->space) { storeChar(' '); } + node = node->next; + break; + case Group: + node = node->next; + break; + case Indent: + num_spaces = (node->data.node != NULL ? + atoi(node->data.node->data.text) : 1); + for (count = 0; count < num_spaces; count++) + storeChar(' '); + node = node->next; + break; + default: + fprintf(stderr, + "Print_to_string: Unrecognized Keyword Type %d\n", + node->type); + node=node->next; + break; + } + } + storeChar('\0'); + return p2sBuf; +} + +/* + * Send a lisp or spad command to the AXIOM server for execution , if + * type is link, then we wait for a HyperDoc card to be returned + */ + +HyperDocPage * +issue_server_command(HyperLink *link) +{ + TextNode *command = (TextNode *) link->reference.node; + int ret_val; + char *buf; + HyperDocPage *page; + + ret_val = connect_spad(); + if (ret_val == NotConnected) { + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, "SpadNotConnectedPage"); + if (page == NULL) + fprintf(stderr, "No SpadNotConnectedPage found\n"); + return page; + } + if (ret_val == SpadBusy) { + page = (HyperDocPage *) hash_find(gWindow->fPageHashTable, "SpadBusyPage"); + if (page == NULL) + fprintf(stderr, "No SpadBusyPage found\n"); + return page; + } + switch_frames(); + switch (link->type) { + case Qspadcall: + case Qspadcallquit: + case Spadlink: + case Spaddownlink: + case Spadmemolink: + send_int(spad_socket, QuietSpadCommand); + break; + case Spadcall: + case Spadcallquit: + send_int(spad_socket, SpadCommand); + break; + default: + send_int(spad_socket, LispCommand); + break; + } + buf = print_to_string(command); + send_string(spad_socket, buf); + if (link->type == Lispcommand || link->type == Spadcall + || link->type == Spadcallquit || link->type == Qspadcallquit + || link->type == Qspadcall || link->type == Lispcommandquit) + return NULL; + page = parse_page_from_socket(); + return page; +} + +int +issue_serverpaste(TextNode *command) +{ + char *buf; + int ret_val; + + ret_val = connect_spad(); + if (ret_val == NotConnected || ret_val == SpadBusy) + return 1; + switch_frames(); + send_int(spad_socket, LispCommand); + buf = print_to_string(command); + send_string(spad_socket, buf); + return 1; +} + +/* + * issue a unix command + */ +void +issue_unixcommand(TextNode *node) +{ + char *buf; + char *copy; + + + buf = print_to_string(node); + copy =(char *) halloc((strlen(buf)+2)*sizeof(char),"Unixcommand"); + strcpy(copy,buf); + copy[strlen(buf) + 1] = '\0'; + copy[strlen(buf)] = '&'; + system(copy); + free(copy); + return; +} + +HyperDocPage * +issue_unixlink(TextNode *node) +{ + HyperDocPage *page; + char *buf; + + buf = print_to_string(node); + if ((unixfd = popen(buf, "r")) == NULL) { + fprintf(stderr, "Error popening %s\n", buf); + exit(-1); + } + bsdSignal(SIGUSR2,SIG_IGN,0); + page = parse_page_from_unixfd(); + bsdSignal(SIGUSR2,sigusr2_handler,0); + return page; +} + +int +issue_unixpaste(TextNode *node) +{ + char *buf; + + buf = print_to_string(node); + if ((unixfd = popen(buf, "r")) == NULL) { + fprintf(stderr, "Error popening %s\n", buf); + exit(-1); + } + return 1; +} + + +/* + * called when session_server selects + */ +void +service_session_socket(void) +{ + int cmd, pid; + + cmd = get_int(session_server); + switch (cmd) { + case CloseClient: + pid = get_int(session_server); + if (pid != -1) + close_client(pid); + break; + default: + fprintf(stderr, + "(HyperDoc) Unknown command from SessionServer %d\n", cmd); + break; + } +} + + +/* + * let spad know which frame to issue command via + */ +static void +switch_frames(void) +{ + if (session_server == NULL) { + fprintf(stderr, "(HyperDoc) No session manager connected!\n"); + return; + } + if (gWindow->fAxiomFrame == -1) { + fprintf(stderr, "(HyperDoc) No AXIOM frame associated with top level window!\n"); + return; + } + send_int(session_server, SwitchFrames); + send_int(session_server, gWindow->fAxiomFrame); +} +void +send_lisp_command(char *command) +{ + int ret_val; + + ret_val = connect_spad(); + if (ret_val == NotConnected || ret_val == SpadBusy) { + return; + } + send_int(spad_socket, LispCommand); + send_string(spad_socket, command); +} +void +escape_string(char *s) +{ + char *st; + + for (st = s; *st; st++) + *st = funnyEscape(*st); +} +void +unescape_string(char *s) +{ + char *st; + + for (st = s; *st; st++) + *st = funnyUnescape(*st); +} +static void +close_client(int pid) +{ + /*int i;*/ + Sock_List *pSock, *locSock; + + /* + * just need to drop the list item + */ + + if (plSock == (Sock_List *) 0) + return; + + /* + * first check head + */ + + if ((plSock->Socket.pid == pid)) { + locSock = plSock; + if ((*plSock).next == (Sock_List *) 0) { + plSock = (Sock_List *) 0; + } + else { + plSock = plSock->next; + } + free(locSock); + } + + /* + * now check the rest + */ + + else { + for (pSock = plSock; pSock->next != (Sock_List *) 0; pSock = pSock->next) + if (pSock->next->Socket.pid == pid) { + locSock = pSock->next; + if (pSock->next->next == (Sock_List *) 0) { + pSock->next = (Sock_List *) 0; + } + else { + pSock->next = pSock->next->next; + } + free(locSock); + break; + } + } +} + + + +char * +print_source_to_string(TextNode *command) +{ + int len = 0; + + print_source_to_string1(command, &len); + p2sBuf = resizeBuffer(len, p2sBuf, &p2sBufSize); + return print_source_to_string1(command, NULL); +} +char * +print_source_to_string1(TextNode *command,int * sizeBuf) +{ + char *c = p2sBuf; + char *s; + InputItem *item; + LineStruct *curr_line; + int lcount; + InputBox *box; + int num_spaces; + int count; + TextNode *node; + + /* + print out HyperDoc source for what you see + */ + + for (node = command; node != NULL;) { + switch (node->type) { + case Newline: + storeString("\\newline\n"); + node = node->next; + break; + case Par: + storeString("\n\n"); + node = node->next; + break; + case Indentrel: + storeString("\\indentrel{"); + storeString(node->data.node->data.text); + storeChar('}'); + node = node->next; + break; + case Tab: + storeString("\\tab{"); + storeString(node->data.node->data.text); + storeChar('}'); + node = node->next; + break; + case Ifcond: + if (check_condition(node->data.ifnode->cond)) + node = node->data.ifnode->thennode; + else + node = node->data.ifnode->elsenode; + break; + case Endarg: + case Endspadsrc: + case Endpix: + case Endbutton: + storeChar('}'); + node = node->next; + break; + case Endverbatim: + case Endif: + case Fi: + case Endmacro: + case Endparameter: + case Rbrace: + node = node->next; + break; + case Punctuation: + + /* + * Simply copy the piece of text + */ + if (node->space & FRONTSPACE) { storeChar(' '); } + for (s = node->data.text; *s; s++) { storeChar(*s); } + node = node->next; + break; + case WindowId: + storeString("\\windowid "); + node = node->next; + break; + case Verbatim: + case Spadsrctxt: + if (node->space) { storeChar(' '); } + for (s = node->data.text; *s; s++) { storeChar(*s); } + node = node->next; + break; + case Dash: + case Rsquarebrace: + case Lsquarebrace: + case Word: + if (node->space) { storeChar(' '); } + for (s = node->data.text; *s; s++) { storeChar(*s); } + node = node->next; + break; + case BoxValue: + box = (InputBox *) hash_find(gWindow->page->box_hash, node->data.text); + if (box == NULL) { + fprintf(stderr, "Print_to_string:Box %s Has no symbol table entry\n", + node->data.text); + exit(-1); + } + storeChar(' '); + if (box->picked) { + storeChar('t'); + } + else { + storeChar('n'); + storeChar('i'); + storeChar('l'); + } + node = node->next; + break; + case StringValue: + item = return_item(node->data.text); + if (item != NULL) { + if (node->space) { storeChar(' '); } + curr_line = item->lines; + while (curr_line != NULL) { + for (lcount = 0, s = curr_line->buffer; + *s && lcount < item->size; + s++, lcount++) { + storeChar(funnyUnescape(*s)); + } + if (curr_line->len <= item->size && curr_line->next) + storeChar('\n'); + curr_line = curr_line->next; + } + } + else if ((box = (InputBox *) hash_find(gWindow->page->box_hash, + node->data.text)) != NULL) { + if (node->space) { storeChar(' '); } + if (box->picked) { + storeChar('t'); + } + else { + storeChar('n'); + storeChar('i'); + storeChar('l'); + } + } + else { + fprintf(stderr, "Error, Symbol %s has no symbol table entry\n", + node->data.text); + exit(-1); + } + node = node->next; + break; + case Space: + num_spaces = (node->data.node != NULL ? + atoi(node->data.node->data.text) : 1); + for (count = 0; count < num_spaces; count++) + storeChar(' '); + node = node->next; + break; + case Emphasize: + storeString("\\em "); + node = node->next; + break; + case BoldFace: + storeString("\\bf "); + node = node->next; + break; + case Sl: + storeString("\\it "); + node = node->next; + break; + case Rm: + storeString("\\rm "); + node = node->next; + break; + case It: + storeString("\\it "); + node = node->next; + break; + case Tt: + storeString("\\tt "); + node = node->next; + break; + case Group: +/* skip {} */ + if (node->next->type==Endgroup){ + node=node->next->next; + break; + } + storeChar('{'); + node = node->next; + break; + case Endgroup: + storeChar('}'); + node = node->next; + break; + case Box: + storeString("\\box{"); + node = node->next; + break; + case Endbox: + storeChar('}'); + node = node->next; + break; + case Center: + storeString("\\center{"); + node = node->next; + break; + case Endcenter: + storeString("}"); + storeChar('\n'); + node = node->next; + break; + case Titlenode: + case Endtitle: + node = node->next; + break; + case Bound: + { + TextNode *n2 = node->data.node; + + storeString("\\bound{"); + for (; n2->type != Endarg; n2 = n2->next) { + if (n2->type == Word) { + storeString(n2->data.text); + storeChar(' '); + } + } + storeChar('}'); + } + node = node->next; + break; + case Free: + { + TextNode *n2 = node->data.node; + + storeString("\\free{"); + for (; n2->type != Endarg; n2 = n2->next) { + if (n2->type == Word) { + storeString(n2->data.text); + storeChar(' '); + } + } + storeChar('}'); + } + node = node->next; + break; + case Macro: + storeChar(' '); + node = node->next; + break; + case Pound: + if (node->space) { storeChar(' '); } + node = node->next; + break; + case Indent: + num_spaces = (node->data.node != NULL ? + atoi(node->data.node->data.text) : 1); + for (count = 0; count < num_spaces; count++) + storeChar(' '); + node = node->next; + break; + case Inputbitmap: + storeString("\\inputbitmap{"); + storeString(node->data.text); + storeString("}\n"); + node = node->next; + break; + case Endscrolling: + storeString("\\end{scroll}\n"); + node = node->next; + break; + case Scrollingnode: + storeString("\\begin{scroll}\n"); + storeString("% This is the scrolling area\n"); + node = node->next; + break; + case Horizontalline: + storeString("\\horizontalline\n"); + node = node->next; + break; + case Endtable: + storeChar('}'); + node = node->next; + break; + case Table: + storeString("\\table{"); + node = node->next; + break; + case Tableitem: + storeChar('{'); + node = node->next; + break; + case Endtableitem: + storeChar('}'); + node = node->next; + break; + case Beginitems: + storeString("\\begin{items}"); + node = node->next; + break; + case Item: + storeString("\n\\item"); + node = node->next; + break; + case Enditems: + storeString("\n\\end{items}"); + node = node->next; + break; +/*** LINKS ***/ +/* all these guys are ended by Endbutton +we close the brace then */ + case Spadlink: + storeString("\\fauxspadlink{"); + node = node->next; + break; + case Unixlink: + storeString("\\fauxunixlink{"); + node = node->next; + break; + case Lisplink: + storeString("\\fauxlisplink{"); + node = node->next; + break; + case Link: + storeString("\\fauxlink{"); + node = node->next; + break; + case LispDownLink: + storeString("\\fauxlispdownlink{"); + node = node->next; + break; + case LispMemoLink: + storeString("\\fauxlispmemolink{"); + node = node->next; + break; + case Memolink: + storeString("\\fauxmemolink{"); + node = node->next; + break; + case Windowlink: + storeString("\\fauxwindowlink{"); + node = node->next; + break; + case Downlink: + storeString("\\fauxdownlink{"); + node = node->next; + break; +/** END OF LINKS **/ + case Unixcommand: + storeString("\\unixcommand{"); + node = node->next; + break; + case Lispcommand: + storeString("\\lispcommand{"); + node = node->next; + break; + case Spadgraph: + storeString("\\spadgraph{"); + node = node->next; + break; + case Spadcommand: + storeString("\\spadcommand{"); + node = node->next; + break; + case Endspadcommand: + storeChar('}'); + node = node->next; + break; + case Footernode: + storeString("% This is the footer\n"); + node = node->next; + break; + case Endfooter: + storeString("% This is the end of the footer\n"); + node = node->next; + break; + case Endheader: + storeString("% This is the end of the header\n"); + node = node->next; + break; + case Headernode: + storeString("% This is the header\n"); + node = node->next; + break; + default: + fprintf(stderr, + "Print_to_string: Unrecognized Keyword Type %d\n", + node->type); + node=node->next; + break; + } + } + storeChar('\0'); + return p2sBuf; +} +@ +\section{titlebar.h} +<>= +#ifndef _TITLEBAR_H_ +#define _TITLEBAR_H_ 1 + +<> + +extern int twwidth, twheight; /* the width and height for all windows in the */ + /* title bar */ + +#endif +@ +\section{titlebar.c} +<>= +/****************************************************************************** + * + * titlebar.c: Produces HyperDoc titlebar + * + * Copyright The Numerical Algorithms Group Limited 1991, 1992, 1993. + * + ****************************************************************************/ +#define _TITLEBAR_C +#include "debug.h" + +#include + +<> +<> +<> +<> +<> +<> + +#include "all-hyper-proto.h1" + +extern int y_off; /* y offset for scrolling regions */ + +/* Images for the title bar windows */ + +static XImage *tw1image = NULL, + *tw2image = NULL, + *tw3image = NULL, + *tw4image = NULL, + *noopimage = NULL; + +static char *tw1file = "exit3d.bitmap"; +static char *tw2file = "help3d.bitmap"; +static char *tw3file = "home3d.bitmap"; +static char *tw4file = "up3d.bitmap"; +static char *noopfile = "noop3d.bitmap"; + +#define BACKCOLOR gControlBackgroundColor +#define BUTTGC fControlGC + +int twwidth, twheight; /* the width and height for all windows in the */ + /* title bar */ + +void +makeTitleBarWindows(void) +{ + XSetWindowAttributes at; + unsigned long valuemask = 0L; + + /* read the images if we don't have them already */ + + if (tw1image == NULL) + readTitleBarImages(); + + /* set the window attributes */ + + at.cursor = gActiveCursor; + valuemask |= CWCursor; + at.event_mask = ButtonPress; + valuemask |= CWEventMask; + + /* create the windows for the buttons */ + + gWindow->fTitleBarButton1 = XCreateSimpleWindow(gXDisplay, gWindow->fMainWindow, + 1, 1, twwidth, twheight, + 0, gBorderColor, BACKCOLOR); + XChangeWindowAttributes(gXDisplay, gWindow->fTitleBarButton1, valuemask, &at); + + gWindow->fTitleBarButton2 = XCreateSimpleWindow(gXDisplay, gWindow->fMainWindow, + 1, 1, twwidth, twheight, + 0, gBorderColor, BACKCOLOR); + XChangeWindowAttributes(gXDisplay, gWindow->fTitleBarButton2, valuemask, &at); + + gWindow->fTitleBarButton3 = XCreateSimpleWindow(gXDisplay, gWindow->fMainWindow, + 1, 1, twwidth, twheight, + 0, gBorderColor, BACKCOLOR); + XChangeWindowAttributes(gXDisplay, gWindow->fTitleBarButton3, valuemask, &at); + + gWindow->fTitleBarButton4 = XCreateSimpleWindow(gXDisplay, gWindow->fMainWindow, + 1, 1, twwidth, twheight, + 0, gBorderColor, BACKCOLOR); + XChangeWindowAttributes(gXDisplay, gWindow->fTitleBarButton4, valuemask, &at); +} + +void +showTitleBar(void) +{ + XWindowChanges wc; + int height, hbw = (int) gWindow->border_width / 2; + XImage *image; + + /* + * the first thing we do is pop up all the windows and + * place them properly + */ + + if (gWindow->page->title->height != twheight) + height = gWindow->page->title->height; + else + height = twheight; + + push_active_group(); + + /* configure and map button number 1 */ + + wc.x = 0; + wc.y = 0; + wc.height = twheight; + wc.width = twwidth; + XConfigureWindow(gXDisplay, gWindow->fTitleBarButton1, CWX | CWY | CWHeight | CWWidth, &wc); + XMapWindow(gXDisplay, gWindow->fTitleBarButton1); + + image = tw1image; + XPutImage(gXDisplay, gWindow->fTitleBarButton1, gWindow->BUTTGC, + image, 0, 0, 0, 0, + image->width, + image->height); + + /* configure and map button number 2 */ + + wc.x += twwidth + gWindow->border_width; + XConfigureWindow(gXDisplay, gWindow->fTitleBarButton2, CWX | CWY | CWHeight | CWWidth, &wc); + XMapWindow(gXDisplay, gWindow->fTitleBarButton2); + + image = need_help_button ? tw2image : noopimage; + XPutImage(gXDisplay, gWindow->fTitleBarButton2, gWindow->BUTTGC, + image, 0, 0, 0, 0, + image->width, + image->height); + + /* configure and map button number 4 */ + + wc.x = gWindow->width - twwidth; + XConfigureWindow(gXDisplay, gWindow->fTitleBarButton4, CWX | CWY | CWHeight | CWWidth, &wc); + XMapWindow(gXDisplay, gWindow->fTitleBarButton4); + + image = need_up_button ? tw4image : noopimage; + XPutImage(gXDisplay, gWindow->fTitleBarButton4, gWindow->BUTTGC, + image, 0, 0, 0, 0, + image->width, + image->height); + + /* configure and map button number 3 */ + + wc.x = wc.x - twwidth - gWindow->border_width; + XConfigureWindow(gXDisplay, gWindow->fTitleBarButton3, CWX | CWY | CWHeight | CWWidth, &wc); + XMapWindow(gXDisplay, gWindow->fTitleBarButton3); + + image = need_return_button ? tw3image : noopimage; + XPutImage(gXDisplay, gWindow->fTitleBarButton3, gWindow->BUTTGC, + image, 0, 0, 0, 0, + image->width, + image->height); + + gWindow->fDisplayedWindow = gWindow->fMainWindow; + gDisplayRegion = Title; + gRegionOffset = 0; + y_off = 0; + + pop_group_stack(); + + show_text(gWindow->page->title->next, Endheader); + + /* Now draw the box around the title */ + + line_top_group(); + + XDrawLine(gXDisplay, gWindow->fMainWindow, gWindow->fStandardGC, 0, height + hbw, + gWindow->width, height + hbw); + + pop_group_stack(); + +} + +void +linkTitleBarWindows(void) +{ + HyperLink *tw1link = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"), + *tw2link = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"), + *tw3link = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"), + *tw4link = (HyperLink *) halloc(sizeof(HyperLink), "HyperLink"); + + tw1link->win = gWindow->fTitleBarButton1; + tw1link->type = Quitbutton; + tw1link->reference.node = NULL; + tw1link->x = tw1link->y = 0; + + tw2link->win = gWindow->fTitleBarButton2; + tw2link->type = Helpbutton; + tw2link->reference.node = NULL; + tw2link->x = tw2link->y = 0; + + tw3link->win = gWindow->fTitleBarButton3; + tw3link->type = Returnbutton; + tw3link->reference.node = NULL; + tw3link->x = tw3link->y = 0; + + tw4link->win = gWindow->fTitleBarButton4; + tw4link->type = Upbutton; + tw4link->reference.node = NULL; + tw4link->x = tw4link->y = 0; + + hash_insert(gLinkHashTable, (char *)tw1link,(char *) &tw1link->win); + hash_insert(gLinkHashTable, (char *)tw2link,(char *) &tw2link->win); + hash_insert(gLinkHashTable, (char *)tw3link,(char *) &tw3link->win); + hash_insert(gLinkHashTable, (char *)tw4link,(char *) &tw4link->win); +} + +static void +readTitleBarImages(void) +{ + int w, h; + char filename[128]; + char *axiomEnvVar = NULL; + + axiomEnvVar = getenv("AXIOM"); + + if (axiomEnvVar) + sprintf(filename, "%s/doc/hypertex/bitmaps/%s", axiomEnvVar, tw1file); + else + sprintf(filename, "%s", tw1file); + tw1image = HTReadBitmapFile(gXDisplay, gXScreenNumber, filename, + &twwidth, &twheight); + + if (axiomEnvVar) + sprintf(filename, "%s/doc/hypertex/bitmaps/%s", axiomEnvVar, tw2file); + else + sprintf(filename, "%s", tw2file); + tw2image = HTReadBitmapFile(gXDisplay, gXScreenNumber, filename, + &w, &h); + twwidth = ((twwidth >= w) ? (twwidth) : (w)); + + if (axiomEnvVar) + sprintf(filename, "%s/doc/hypertex/bitmaps/%s", axiomEnvVar, tw3file); + else + sprintf(filename, "%s", tw3file); + tw3image = HTReadBitmapFile(gXDisplay, gXScreenNumber, filename, + &w, &h); + twwidth = ((twwidth >= w) ? (twwidth) : (w)); + + if (axiomEnvVar) + sprintf(filename, "%s/doc/hypertex/bitmaps/%s", axiomEnvVar, tw4file); + else + sprintf(filename, "%s", tw4file); + tw4image = HTReadBitmapFile(gXDisplay, gXScreenNumber, filename, + &w, &h); + twwidth = ((twwidth >= w) ? (twwidth) : (w)); + + + if (axiomEnvVar) + sprintf(filename, "%s/doc/hypertex/bitmaps/%s", axiomEnvVar, noopfile); + else + sprintf(filename, "%s", noopfile); + noopimage = HTReadBitmapFile(gXDisplay, gXScreenNumber, filename, + &twwidth, &twheight); +} + +void +getTitleBarMinimumSize(int *width, int *height) +{ + (*width) = 4 * twwidth + 40; + (*height) = twheight + 2; +} +@ +\section{token.h} +<>= +#ifndef _TOKEN_H_ +#define _TOKEN_H_ 1 + +/* + Here are a couple of flags added for whitespace stuff. They tell + punctuation if there was space in front of it or not +*/ + +#define FRONTSPACE 0001 +#define BACKSPACE 0002 + +/* HyperDoc parser tokens */ + +typedef struct toke { + int type; /* token type. One of those listed below */ + char *id; /* string value if type == Identifier */ +} Token; + +/* + User tokens. ie, these can be found on a page +*/ + +#define Word 1 +#define Page 2 +#define Lispcommandquit 3 +#define BoldFace 4 +#define Link 5 +#define Downlink 6 +#define Beginscroll 7 +#define Spadcommand 8 +#define NoLines 9 +#define Env 10 +#define Par 11 +#define Center 12 +#define Begin 13 +#define Beginitems 14 +#define Item 15 +#define Table 16 +#define Box 17 +#define Tab 18 +#define Space 19 +#define Indent 20 +#define Horizontalline 21 +#define Newline 22 +#define Enditems 23 +#define Returnbutton 24 +#define Memolink 25 +#define Upbutton 26 +#define Endscroll 27 +#define Thispage 28 +#define Returnto 29 +#define Free 30 +#define Bound 31 +#define Lisplink 32 +#define Unixlink 33 +#define Mbox 34 +#define Inputstring 35 +#define StringValue 36 +#define Spadlink 37 +#define Inputbitmap 38 +#define Inputpixmap 39 +#define Unixcommand 40 +#define Emphasize 41 +#define Lispcommand 42 +#define LispMemoLink 43 +#define LispDownLink 44 +#define Spadcall 45 +#define Spadcallquit 46 +#define Spaddownlink 47 +#define Spadmemolink 48 +#define Qspadcall 49 +#define Qspadcallquit 50 +#define SimpleBox 51 +#define Radioboxes 52 +#define BoxValue 53 +#define VSpace 54 +#define HSpace 55 +#define NewCommand 56 +#define WindowId 57 +#define Beep 58 +#define Quitbutton 59 +#define Begintitems 60 +#define Titem 61 +#define End 62 +#define It 63 +#define Sl 64 +#define Tt 65 +#define Rm 66 +#define Ifcond 67 +#define Else 68 +#define Fi 69 +#define Newcond 70 +#define Setcond 71 +#define Button 72 +#define Windowlink 73 +#define Haslisp 74 +#define Hasup 75 +#define Hasreturn 76 +#define Hasreturnto 77 +#define Lastwindow 78 +#define Endtitems 79 +#define Lispwindowlink 80 +#define Beginpile 81 +#define Endpile 82 +#define Nextline 83 +#define Pastebutton 84 +#define Color 85 +#define Helppage 86 +#define Patch 87 +#define Radiobox 88 +#define ifrecond 89 +#define Math 90 +#define Mitem 91 +#define Pagename 92 +#define Examplenumber 93 +#define Replacepage 94 +#define Inputimage 95 +#define Spadgraph 96 +#define Indentrel 97 +#define Controlbitmap 98 + +#define NumberUserTokens 98 + + +extern char *token_table[]; + +#ifdef PARSER +char *token_table[] = { + "", /* Dummy token name */ + "word", + "page", + "lispcommandquit", + "bf", + "link", + "downlink", + "beginscroll", + "spadcommand", + "nolines", + "env", + "par", + "centerline", + "begin", + "beginitems", + "item", + "table", + "fbox", + "tab", + "space", + "indent", + "horizontalline", + "newline", + "enditems", + "returnbutton", + "memolink", + "upbutton", + "endscroll", + "thispage", + "returnto", + "free", + "bound", + "lisplink", + "unixlink", + "mbox", + "inputstring", + "stringvalue", + "spadlink", + "inputbitmap", + "inputpixmap", + "unixcommand", + "em", + "lispcommand", + "lispmemolink", + "lispdownlink", + "spadcall", + "spadcallquit", + "spaddownlink", + "spadmemolink", + "qspadcall", + "qspadcallquit", + "inputbox", + "radioboxes", + "boxvalue", + "vspace", + "hspace", + "newcommand", + "windowid", + "beep", + "quitbutton", + "begintitems", + "titem", + "end", + "it", + "sl", + "tt", + "rm", + "ifcond", + "else", + "fi", + "newcond", + "setcond" , + "button", + "windowlink", + "haslisp", + "hasup", + "hasreturn", + "hasreturnto", + "lastwindow", + "endtitems", + "lispwindowlink", + "beginpile", + "endpile", + "nextline", + "pastebutton", + "color", + "helppage", + "patch", + "radiobox", + "ifrecond", + "math", + "mitem", + "pagename", + "examplenumber", + "replacepage", + "inputimage", + "spadgraph", + "indentrel", + "controlbitmap" + }; +#endif + + +/* places from which input may be read */ +#define FromFile 1 +#define FromString 2 +#define FromSpadSocket 3 +#define FromUnixFD 4 + +extern FILE *unixfd; + +/* + * Here are the system tokens. These are used internally to help + * with parsing and displaying of text + */ + +#define SystemTokens 1001 +#define Lbrace 1001 +#define Rbrace 1002 +#define Macro 1003 +#define Group 1004 +#define Scrollbar 1005 +#define Pound 1006 +#define Lsquarebrace 1007 +#define Rsquarebrace 1008 +#define Punctuation 1009 +#define Dash 1010 +#define Tableitem 1011 +#define Scrollingnode 1012 +#define Headernode 1013 +#define Footernode 1014 +#define Verbatim 1015 +#define Scroll 1016 +#define Dollar 1017 +#define Percent 1018 +#define Carrot 1019 +#define Underscore 1020 +#define Tilde 1021 +#define Cond 1022 +#define Noop 1023 +#define Description 1024 +#define Icorrection 1025 +#define Boxcond 1026 +#define Unkeyword 1027 +#define Titlenode 1028 +#define Paste 1029 +#define Spadsrc 1030 +#define Helpbutton 1031 +#define Spadsrctxt 1032 + + +/* + * Here are the tokens used to mark the end to some sort of group of + * tokens. ie, the tokens found in a centerline command + */ + +#define Endtokens 2000 +#define End1 2001 +#define End2 2002 +#define Endbutton 2003 +#define Endlink 2004 +#define Endheader 2005 +#define Endfooter 2006 +#define Endscrolling 2007 +#define Endgroup 2008 +#define Endarg 2009 +#define Endbox 2010 +#define Endmbox 2011 +#define Endspadcommand 2012 +#define Endpix 2013 +#define Endmacro 2014 +#define Endparameter 2015 +#define Endtable 2016 +#define Endtableitem 2017 +#define End3 2018 +#define Endif 2019 +#define Enddescription 2020 +#define Endinputbox 2021 +#define Endtitle 2022 +#define Endpastebutton 2023 + +#define Endtypes 3000 +#define Endpage 3002 +#define EndScroll 3007 /* had to use a S because Endscroll is + already a keyword */ + +#define Endcenter 3012 +#define EndItems 3014 /* Same thing here as EndScroll except + with the i */ +#define EndTitems 3060 /* Ibid for the T */ +#define Endpatch 3087 +#define Endverbatim 4015 +#define Endmath 4016 +#define Endpaste 4029 +#define Endspadsrc 4030 + +#endif +@ +\chapter{The Bitmaps} +\section{ht\_icon} +<>= +#define ht_icon_width 40 +#define ht_icon_height 40 +#define ht_icon_x_hot -1 +#define ht_icon_y_hot -1 +static char ht_icon_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, + 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xef, 0x7b, 0x3c, 0xe7, 0xff, + 0xef, 0x7f, 0x7e, 0xff, 0xff, 0xe7, 0xef, 0xe7, 0xfe, 0xe7, 0x6e, 0xe7, + 0xe7, 0xde, 0xe7, 0x7e, 0xe7, 0xff, 0x0e, 0xe7, 0x3c, 0xe7, 0x07, 0x0e, + 0xe7, 0x3c, 0xf7, 0xcf, 0x0e, 0xf7, 0x18, 0x7f, 0xfe, 0x1f, 0x00, 0x1c, + 0x3f, 0x7c, 0x1f, 0x00, 0x0e, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x07, 0x00, + 0x00, 0x00, 0x87, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x00, 0x00, 0x00, 0x77, 0x3e, 0xdc, 0x00, 0x00, 0x77, 0x7f, 0xfe, + 0x00, 0x00, 0xf7, 0xe3, 0xef, 0x00, 0x00, 0xf7, 0xe3, 0xc7, 0x00, 0x00, + 0xf7, 0xe3, 0x07, 0x00, 0x00, 0xf7, 0xe3, 0x07, 0x00, 0x00, 0xf7, 0xe3, + 0xcf, 0x00, 0x80, 0x7f, 0x7f, 0xfe, 0x00, 0x80, 0x3f, 0x3e, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +@ +\section{exit.bitmap} +<>= +#define exit_width 60 +#define exit_height 30 +#define exit_x_hot -1 +#define exit_y_hot -1 +static char exit_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xcf, 0x3f, + 0xcf, 0x03, 0xc0, 0xff, 0x3f, 0x00, 0x8e, 0x3f, 0x8e, 0x03, 0x80, 0xff, + 0x3f, 0x00, 0x1e, 0x1f, 0x8f, 0x07, 0x80, 0xff, 0x3f, 0xfe, 0x1f, 0x1f, + 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0xfe, 0x3f, 0x8e, 0x8f, 0x7f, 0xfc, 0xff, + 0x3f, 0xfe, 0x3f, 0x8e, 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0xfe, 0x7f, 0xc4, + 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0xfe, 0x7f, 0xc4, 0x8f, 0x7f, 0xfc, 0xff, + 0x3f, 0xfe, 0xff, 0xe0, 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0x80, 0xff, 0xe0, + 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0x00, 0xff, 0xf1, 0x8f, 0x7f, 0xfc, 0xff, + 0x3f, 0x00, 0xff, 0xf1, 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0xfe, 0xff, 0xe0, + 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0xfe, 0xff, 0xe0, 0x8f, 0x7f, 0xfc, 0xff, + 0x3f, 0xfe, 0x7f, 0xc4, 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0xfe, 0x7f, 0xc4, + 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0xfe, 0x3f, 0x8e, 0x8f, 0x7f, 0xfc, 0xff, + 0x3f, 0xfe, 0x3f, 0x8e, 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0xfe, 0x1f, 0x1f, + 0x8f, 0x7f, 0xfc, 0xff, 0x3f, 0x00, 0x1f, 0x1f, 0x8f, 0x7f, 0xfc, 0xff, + 0x3f, 0x00, 0x8e, 0x3f, 0x8e, 0x7f, 0xfc, 0xff, 0x7f, 0x00, 0x9e, 0x7f, + 0x9e, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +@ +\section{help2.bitmap} +<>= +#define help2_width 60 +#define help2_height 30 +#define help2_x_hot -1 +#define help2_y_hot -1 +static char help2_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x9f, 0x07, 0xf0, + 0xfc, 0x0f, 0xf0, 0xff, 0x1f, 0x1f, 0x07, 0xe0, 0xf8, 0x0f, 0xe0, 0xff, + 0x1f, 0x1f, 0x07, 0xe0, 0xf8, 0x0f, 0xc0, 0xff, 0x1f, 0x1f, 0xc7, 0xff, + 0xf8, 0x8f, 0x87, 0xff, 0x1f, 0x1f, 0xc7, 0xff, 0xf8, 0x8f, 0x8f, 0xff, + 0x1f, 0x1f, 0xc7, 0xff, 0xf8, 0x8f, 0x8f, 0xff, 0x1f, 0x1f, 0xc7, 0xff, + 0xf8, 0x8f, 0x8f, 0xff, 0x1f, 0x1f, 0xc7, 0xff, 0xf8, 0x8f, 0x8f, 0xff, + 0x1f, 0x1f, 0xc7, 0xff, 0xf8, 0x8f, 0x8f, 0xff, 0x1f, 0x00, 0x07, 0xf8, + 0xf8, 0x8f, 0x87, 0xff, 0x1f, 0x00, 0x07, 0xf0, 0xf8, 0x0f, 0xc0, 0xff, + 0x1f, 0x00, 0x07, 0xf0, 0xf8, 0x0f, 0xe0, 0xff, 0x1f, 0x1f, 0xc7, 0xff, + 0xf8, 0x0f, 0xf0, 0xff, 0x1f, 0x1f, 0xc7, 0xff, 0xf8, 0x8f, 0xff, 0xff, + 0x1f, 0x1f, 0xc7, 0xff, 0xf8, 0x8f, 0xff, 0xff, 0x1f, 0x1f, 0xc7, 0xff, + 0xf8, 0x8f, 0xff, 0xff, 0x1f, 0x1f, 0xc7, 0xff, 0xf8, 0x8f, 0xff, 0xff, + 0x1f, 0x1f, 0xc7, 0xff, 0xf8, 0x8f, 0xff, 0xff, 0x1f, 0x1f, 0xc7, 0xff, + 0xf8, 0x8f, 0xff, 0xff, 0x1f, 0x1f, 0x07, 0xf0, 0x00, 0x8f, 0xff, 0xff, + 0x1f, 0x1f, 0x07, 0xe0, 0x00, 0x8e, 0xff, 0xff, 0x3f, 0x3f, 0x0f, 0xe0, + 0x01, 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +@ +\section{return3.bitmap} +<>= +#define return3_width 60 +#define return3_height 30 +#define return3_x_hot -1 +#define return3_y_hot -1 +static char return3_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x9f, 0x0f, 0xf8, + 0xfc, 0x79, 0x00, 0xff, 0x1f, 0x1f, 0x07, 0xf0, 0xf8, 0x71, 0x00, 0xfe, + 0x1f, 0x1f, 0x07, 0xe0, 0xf0, 0x70, 0x00, 0xfe, 0x1f, 0x1f, 0xc7, 0xe3, + 0xf0, 0x70, 0xfc, 0xff, 0x1f, 0x1f, 0xc7, 0xe3, 0xf0, 0x70, 0xfc, 0xff, + 0x1f, 0x1f, 0xc7, 0xe3, 0x60, 0x70, 0xfc, 0xff, 0x1f, 0x1f, 0xc7, 0xe3, + 0x60, 0x70, 0xfc, 0xff, 0x1f, 0x1f, 0xc7, 0xe3, 0x00, 0x70, 0xfc, 0xff, + 0x1f, 0x1f, 0xc7, 0xe3, 0x08, 0x71, 0xfc, 0xff, 0x1f, 0x00, 0xc7, 0xe3, + 0x08, 0x71, 0x80, 0xff, 0x1f, 0x00, 0xc7, 0xe3, 0x98, 0x71, 0x00, 0xff, + 0x1f, 0x00, 0xc7, 0xe3, 0x98, 0x71, 0x00, 0xff, 0x1f, 0x1f, 0xc7, 0xe3, + 0xf8, 0x71, 0xfc, 0xff, 0x1f, 0x1f, 0xc7, 0xe3, 0xf8, 0x71, 0xfc, 0xff, + 0x1f, 0x1f, 0xc7, 0xe3, 0xf8, 0x71, 0xfc, 0xff, 0x1f, 0x1f, 0xc7, 0xe3, + 0xf8, 0x71, 0xfc, 0xff, 0x1f, 0x1f, 0xc7, 0xe3, 0xf8, 0x71, 0xfc, 0xff, + 0x1f, 0x1f, 0xc7, 0xe3, 0xf8, 0x71, 0xfc, 0xff, 0x1f, 0x1f, 0xc7, 0xe3, + 0xf8, 0x71, 0xfc, 0xff, 0x1f, 0x1f, 0x07, 0xe0, 0xf8, 0x71, 0x00, 0xff, + 0x1f, 0x1f, 0x0f, 0xe0, 0xf8, 0x71, 0x00, 0xfe, 0x3f, 0x3f, 0x1f, 0xf0, + 0xf9, 0xf3, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +@ +\section{up3.bitmap} +<>= +#define up3_width 60 +#define up3_height 30 +static char up3_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x7f, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, + 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x01, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xe0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xe0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +@ +\section{noop.bitmap} +<>= +#define noop_width 60 +#define noop_height 30 +#define noop_x_hot -1 +#define noop_y_hot -1 +static char noop_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +@ +\section{exit3d.bitmap} +<>= +#define exit3d.bitmap_width 60 +#define exit3d.bitmap_height 30 +static char exit3d.bitmap_bits[] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0xd1, 0xff, 0x55, 0x55, + 0x5d, 0x55, 0x55, 0x07, 0xaa, 0xff, 0xaa, 0xaa, 0xbe, 0xaa, 0xaa, 0x0e, + 0xd1, 0xd7, 0x55, 0x55, 0x5f, 0xd5, 0x55, 0x07, 0xaa, 0xab, 0xaa, 0xaa, + 0xae, 0xea, 0xaa, 0x0e, 0xd1, 0x57, 0x55, 0x55, 0x55, 0xf5, 0x55, 0x07, + 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0x0e, 0xd1, 0x77, 0x7d, 0x5f, + 0x5f, 0xfd, 0x5f, 0x07, 0xaa, 0xbf, 0xbe, 0xae, 0xbe, 0xfa, 0xaf, 0x0e, + 0xd1, 0x7f, 0x7d, 0x57, 0x5d, 0xf5, 0x55, 0x07, 0xaa, 0xab, 0xfa, 0xab, + 0xbe, 0xea, 0xaa, 0x0e, 0xd1, 0x57, 0xf5, 0x55, 0x5d, 0xf5, 0x55, 0x07, + 0xaa, 0xab, 0xea, 0xab, 0xbe, 0xea, 0xaa, 0x0e, 0xd1, 0x57, 0xd5, 0x57, + 0x5d, 0xf5, 0x55, 0x07, 0xaa, 0xab, 0xea, 0xaf, 0xbe, 0xea, 0xaa, 0x0e, + 0xd1, 0xd7, 0x75, 0x5f, 0x5d, 0xf5, 0x55, 0x07, 0xaa, 0xff, 0xba, 0xbe, + 0xbe, 0xea, 0xaf, 0x0e, 0xd1, 0xff, 0x7d, 0x5f, 0x7f, 0xd5, 0x57, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, + 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05}; +@ +\section{help3d.bitmap} +<>= +#define help3d.bitmap_width 60 +#define help3d.bitmap_height 30 +static char help3d.bitmap_bits[] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0xd1, 0xf7, 0x55, 0x55, + 0x5f, 0x55, 0x55, 0x07, 0xaa, 0xeb, 0xaa, 0xaa, 0xbe, 0xaa, 0xaa, 0x0e, + 0xd1, 0xf7, 0x55, 0x55, 0x5d, 0x55, 0x55, 0x07, 0xaa, 0xeb, 0xaa, 0xaa, + 0xbe, 0xaa, 0xaa, 0x0e, 0xd1, 0xf7, 0x55, 0x55, 0x5d, 0x55, 0x55, 0x07, + 0xaa, 0xeb, 0xaa, 0xaa, 0xbe, 0xaa, 0xaa, 0x0e, 0xd1, 0xf7, 0xf5, 0x57, + 0x5d, 0xdd, 0x57, 0x07, 0xaa, 0xff, 0xfa, 0xaf, 0xbe, 0xfa, 0xaf, 0x0e, + 0xd1, 0xff, 0x7d, 0x5f, 0x5d, 0x7d, 0x5f, 0x07, 0xaa, 0xeb, 0xbe, 0xae, + 0xbe, 0xba, 0xbe, 0x0e, 0xd1, 0xf7, 0xfd, 0x5f, 0x5d, 0x7d, 0x5d, 0x07, + 0xaa, 0xeb, 0xfe, 0xaf, 0xbe, 0xba, 0xbe, 0x0e, 0xd1, 0xf7, 0x5d, 0x55, + 0x5d, 0x7d, 0x5d, 0x07, 0xaa, 0xeb, 0xbe, 0xaa, 0xbe, 0xba, 0xbe, 0x0e, + 0xd1, 0xf7, 0x7d, 0x5d, 0x5d, 0x7d, 0x5f, 0x07, 0xaa, 0xeb, 0xfa, 0xaf, + 0xbe, 0xfa, 0xaf, 0x0e, 0xd1, 0xf7, 0xf5, 0x57, 0x7f, 0xfd, 0x57, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x7d, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0x0e, + 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05}; +@ +\section{home3d.bitmap} +<>= +#define home3d.bitmap_width 60 +#define home3d.bitmap_height 30 +static char home3d.bitmap_bits[] = { + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xef, 0xab, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0xd7, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xaa, 0xef, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0xd7, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0xaa, 0xef, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, + 0x51, 0xd7, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xef, 0xeb, 0xaf, + 0xbb, 0xeb, 0xaf, 0x0e, 0x51, 0xff, 0xf5, 0xdf, 0xff, 0xf7, 0x5f, 0x07, + 0xaa, 0xff, 0xfb, 0xae, 0xbb, 0xfb, 0xbe, 0x0e, 0x51, 0xd7, 0x7d, 0xdd, + 0xff, 0x7f, 0x5d, 0x07, 0xaa, 0xef, 0xbb, 0xbe, 0xbb, 0xfb, 0xbf, 0x0e, + 0x51, 0xd7, 0x7d, 0xdd, 0xff, 0xff, 0x5f, 0x07, 0xaa, 0xef, 0xbb, 0xbe, + 0xbb, 0xbb, 0xaa, 0x0e, 0x51, 0xd7, 0x7d, 0xdd, 0xff, 0x7f, 0x55, 0x07, + 0xaa, 0xef, 0xfb, 0xae, 0xbb, 0xfb, 0xba, 0x0e, 0x51, 0xd7, 0xf5, 0xdf, + 0xff, 0xf7, 0x5f, 0x07, 0xaa, 0xef, 0xeb, 0xaf, 0xbb, 0xeb, 0xaf, 0x0e, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a}; +@ +\section{up3d.bitmap} +<>= +#define up3_width 60 +#define up3_height 30 +static char up3_bits[] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xfa, + 0xab, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0xfd, 0x57, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xff, 0xbf, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0xd5, 0xff, + 0x7f, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xfa, 0xff, 0xff, 0xab, 0xaa, 0x0e, + 0x51, 0x55, 0xfd, 0xff, 0xff, 0x57, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xff, + 0xbf, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0xd5, 0xff, 0x7f, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xff, 0xbf, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0xd5, 0xff, + 0x7f, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xff, 0xbf, 0xaa, 0xaa, 0x0e, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, + 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05}; +@ +\section{noop3d.bitmap} +<>= +#define noop_width 60 +#define noop_height 30 +static char noop_bits[] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, + 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x07, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, + 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05}; +@ +\section{Makefile} +<<*>>= +BOOK=${SPD}/books/bookvol7.pamphlet +IN=${SRC}/hyper + +# this is the intermediate place +MID= ${INT}/hyper + +# this is the intermediate place +MIDOBJ= ${OBJ}/${SYS}/hyper + +# this is where to put the various commands +OUT= ${MNT}/${SYS}/bin +OUTLIB= ${MNT}/${SYS}/lib + +# this is where the include files live +INC= ${SRC}/include + +# this is where we hid the libspad library +LIB= ${OBJ}/${SYS}/lib + +# this is where the hypertex documentation files are +HYPER=${MNT}/${SYS}/doc/hypertex + +# this is where the hyperdoc pages are +PAGES=${HYPER}/pages + +CFLAGS= ${CCF} -I${MID} +LDFLAGS= -L${LIB} -lspad ${LDF} + +HTADD=${OUT}/htadd + +HYPER_OBJS = \ + ${MIDOBJ}/addfile.o ${MIDOBJ}/cond.o ${MIDOBJ}/dialog.o \ + ${MIDOBJ}/display.o ${MIDOBJ}/event.o ${MIDOBJ}/extent1.o \ + ${MIDOBJ}/extent2.o ${MIDOBJ}/form-ext.o ${MIDOBJ}/group.o \ + ${MIDOBJ}/halloc.o ${MIDOBJ}/hash.o ${MIDOBJ}/hterror.o \ + ${MIDOBJ}/htinp.o ${MIDOBJ}/hyper.o ${MIDOBJ}/initx.o \ + ${MIDOBJ}/input.o ${MIDOBJ}/item.o ${MIDOBJ}/keyin.o \ + ${MIDOBJ}/lex.o ${MIDOBJ}/macro.o ${MIDOBJ}/mem.o \ + ${MIDOBJ}/parse.o ${MIDOBJ}/parse-aux.o ${MIDOBJ}/parse-input.o \ + ${MIDOBJ}/parse-paste.o ${MIDOBJ}/parse-types.o \ + ${MIDOBJ}/readbitmap.o ${MIDOBJ}/scrollbar.o \ + ${MIDOBJ}/show-types.o ${MIDOBJ}/spadint.o \ + ${MIDOBJ}/titlebar.o + +EX2HT_OBJS=${MIDOBJ}/ex2ht.o + +HTADD_OBJS = \ + ${MIDOBJ}/addfile.o ${MIDOBJ}/halloc.o ${MIDOBJ}/hash.o \ + ${MIDOBJ}/htadd.o ${MIDOBJ}/hterror.o ${MIDOBJ}/lex.o + +HTHITS_OBJS = ${MIDOBJ}/hthits.o + +SPADBUF_OBJS = ${MIDOBJ}/spadbuf.o + +OBJS= \ + ${HYPER_OBJS} ${EX2HT_OBJS} ${HTADD_OBJS} \ + ${HTHITS_OBJS} ${SPADBUF_OBJS} ${MIDOBJ}/debug.o + +SCRIPTS=${OUTLIB}/htsearch ${OUTLIB}/presea + +BINFILES= ${OUT}/hypertex ${OUT}/htadd ${OUT}/htsearch ${OUTLIB}/spadbuf \ + ${OUTLIB}/hthits ${OUTLIB}/ex2ht + +all: ${OBJS} ${SCRIPTS} ${BINFILES} \ + ${PAGES}/ht.db ${HYPER}/rootpage.xhtml \ + ${HYPER}/axbook \ + ${HYPER}/bigbayou.png ${HYPER}/doctitle.png + @cp ${IN}/bitmaps/* ${HYPER}/bitmaps + @ echo 155 finished ${IN} + +clean: + @echo skipping ${MNT}/${SYS}/doc/bookvol11.dvi + @echo 156 cleaning ${SRC}/hyper + +${HYPER}/rootpage.xhtml: ${IN}/bookvol11.pamphlet + @ echo 150 making ${HYPER}/xhtml from ${IN}/bookvol11.pamphlet + ( cd ${HYPER} ; \ + cp ${IN}/bookvol11.pamphlet . ; \ + ${TANGLE} -t8 bookvol11.pamphlet >Makefile.pages ; \ + make -j 10 -f Makefile.pages ; \ + rm -f Makefile.pages ; \ + rm -f bookvol11.pamphlet ) + +${HYPER}/bigbayou.png: ${IN}/bigbayou.png + @ echo 151 making ${HYPER}/bigbayou.png from ${IN}/bigbayou.png + @ cp ${IN}/bigbayou.png ${HYPER}/bigbayou.png + +${HYPER}/doctitle.png: ${IN}/doctitle.png + @ echo 152 making ${HYPER}/doctitle.png from ${IN}/doctitle.png + @ cp ${IN}/doctitle.png ${HYPER}/doctitle.png + +${HYPER}/axbook: ${IN}/axbook.tgz + @ echo 154 making ${HYPER}/axbook/xhtml from ${IN}/axbook.tgz + @( cd ${HYPER} ; tar -zxf ${IN}/axbook.tgz ) + + +${MIDOBJ}/addfile.o: ${BOOK} + @ echo 3 making ${MIDOBJ}/addfile.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"addfile.c" ${BOOK} >addfile.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/addfile.c ) + +${MIDOBJ}/cond.o: ${BOOK} + @ echo 17 making ${MIDOBJ}/cond.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"cond.c" ${BOOK} >cond.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/cond.c ) + +${MIDOBJ}/debug.o: ${BOOK} + @ echo 20 making ${MIDOBJ}/debug.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"debug.c" ${BOOK} >debug.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/debug.c ) + +${MIDOBJ}/dialog.o: ${BOOK} + @ echo 24 making ${MIDOBJ}/dialog.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"dialog.c" ${BOOK} >dialog.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/dialog.c ) + +${MIDOBJ}/display.o: ${BOOK} + @ echo 28 making ${MIDOBJ}/display.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"display.c" ${BOOK} >display.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/display.c ) + +${MIDOBJ}/event.o: ${BOOK} + @ echo 32 making ${MIDOBJ}/event.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"event.c" ${BOOK} >event.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/event.c ) + +${MIDOBJ}/ex2ht.o: ${BOOK} + @ echo 35 making ${MIDOBJ}/ex2ht.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"ex2ht.c" ${BOOK} >ex2ht.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/ex2ht.c ) + +${MIDOBJ}/extent1.o: ${BOOK} + @ echo 39 making ${MIDOBJ}/extent1.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"extent1.c" ${BOOK} >extent1.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/extent1.c ) + +${MIDOBJ}/extent2.o: ${BOOK} + @ echo 42 making ${MIDOBJ}/extent2.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"extent2.c" ${BOOK} >extent2.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/extent2.c ) + +${MIDOBJ}/form-ext.o: ${BOOK} + @ echo 45 making ${MIDOBJ}/form-ext.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"form-ext.c" ${BOOK} >form-ext.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/form-ext.c ) + +${MIDOBJ}/group.o: ${BOOK} + @ echo 49 making ${MIDOBJ}/group.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"group.c" ${BOOK} >group.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/group.c ) + +${MIDOBJ}/halloc.o: ${BOOK} + @ echo 52 making ${MIDOBJ}/halloc.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"halloc.c" ${BOOK} >halloc.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/halloc.c ) + +${MIDOBJ}/hash.o: ${BOOK} + @ echo 55 making ${MIDOBJ}/hash.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"hash.c" ${BOOK} >hash.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/hash.c ) + +${MIDOBJ}/htadd.o: ${BOOK} + @ echo 58 making ${MIDOBJ}/htadd.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"htadd.c" ${BOOK} >htadd.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/htadd.c ) + +${MIDOBJ}/hterror.o: ${BOOK} + @ echo 62 making ${MIDOBJ}/hterror.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"hterror.c" ${BOOK} >hterror.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/hterror.c ) + +${MIDOBJ}/hthits.o: ${BOOK} + @ echo 65 making ${MIDOBJ}/hthits.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"hthits.c" ${BOOK} >hthits.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/hthits.c ) + +${MIDOBJ}/htinp.o: ${BOOK} + @ echo 68 making ${MIDOBJ}/htinp.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"htinp.c" ${BOOK} >htinp.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/htinp.c ) + +${MIDOBJ}/hyper.o: ${BOOK} + @ echo 72 making ${MIDOBJ}/hyper.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"hyper.c" ${BOOK} >hyper.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/hyper.c ) + +${MIDOBJ}/initx.o: ${BOOK} + @ echo 76 making ${MIDOBJ}/initx.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"initx.c" ${BOOK} >initx.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/initx.c ) + +${MIDOBJ}/input.o: ${BOOK} + @ echo 79 making ${MIDOBJ}/input.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"input.c" ${BOOK} >input.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/input.c ) + +${MIDOBJ}/item.o: ${BOOK} + @ echo 82 making ${MIDOBJ}/item.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"item.c" ${BOOK} >item.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/item.c ) + +${MIDOBJ}/keyin.o: ${BOOK} + @ echo 86 making ${MIDOBJ}/keyin.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"keyin.c" ${BOOK} >keyin.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/keyin.c ) + +${MIDOBJ}/lex.o: ${BOOK} + @ echo 90 making ${MIDOBJ}/lex.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"lex.c" ${BOOK} >lex.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/lex.c ) + +${MIDOBJ}/macro.o: ${BOOK} + @ echo 93 making ${MIDOBJ}/macro.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"macro.c" ${BOOK} >macro.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/macro.c ) + +${MIDOBJ}/mem.o: ${BOOK} + @ echo 97 making ${MIDOBJ}/mem.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"mem.c" ${BOOK} >mem.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/mem.c ) + +${PAGES}/ht.db: ${IN}/pages/*.ht ${IN}/pages/*.pht + @echo 149 making ${PAGES} from ${SRC}/pages directory + @ mkdir -p ${PAGES} + @ ( cd ${IN}; cp -pr pages/*.ht ${PAGES} ) + @ ( cd ${IN} ; cp -pr pages/*.pht ${PAGES} ) + @ (cd ${PAGES} ; \ + rm -f ht.db ; \ + rm -f *~ ; \ + ${HTADD} *.ht *.pht ) + @ (cd ${IN} ; cp -pr bitmaps ${HYPER} ) + @ (cd ${IN} ; cp -pr viewports ${MNT}/${SYS}/doc ) + +${MIDOBJ}/parse.o: ${BOOK} + @ echo 101 making ${MIDOBJ}/parse.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"parse.c" ${BOOK} >parse.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/parse.c ) + +${MIDOBJ}/parse-aux.o: ${BOOK} + @ echo 105 making ${MIDOBJ}/parse-aux.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"parse-aux.c" ${BOOK} >parse-aux.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/parse-aux.c ) + +${MIDOBJ}/parse-input.o: ${BOOK} + @ echo 108 making ${MIDOBJ}/parse-input.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"parse-input.c" ${BOOK} >parse-input.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/parse-input.c ) + +${MIDOBJ}/parse-paste.o: ${BOOK} + @ echo 112 making ${MIDOBJ}/parse-paste.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"parse-paste.c" ${BOOK} >parse-paste.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/parse-paste.c ) + +${MIDOBJ}/parse-types.o: ${BOOK} + @ echo 116 making ${MIDOBJ}/parse-types.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"parse-types.c" ${BOOK} >parse-types.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/parse-types.c ) + +${MIDOBJ}/readbitmap.o: ${BOOK} + @ echo 119 making ${MIDOBJ}/readbitmap.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"readbitmap.c" ${BOOK} >readbitmap.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/readbitmap.c ) + +${MIDOBJ}/scrollbar.o: ${BOOK} + @ echo 123 making ${MIDOBJ}/scrollbar.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"scrollbar.c" ${BOOK} >scrollbar.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/scrollbar.c ) + +${OUTLIB}/htsearch: ${BOOK} + @echo 125 making ${OUTLIB}/htsearch from ${BOOK} + @${TANGLE} -R"htsearch" ${BOOK} >${OUTLIB}/htsearch + @chmod a+x ${OUTLIB}/htsearch + +${OUTLIB}/presea: ${BOOK} + @echo 126 making ${OUTLIB}/presea from ${BOOK} + @${TANGLE} -R"presea" ${BOOK} >${OUTLIB}/presea + @chmod a+x ${OUTLIB}/presea + +${MIDOBJ}/show-types.o: ${BOOK} + @ echo 130 making ${MIDOBJ}/show-types.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"show-types.c" ${BOOK} >show-types.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/show-types.c ) + +${MIDOBJ}/spadbuf.o: ${BOOK} + @ echo 133 making ${MIDOBJ}/spadbuf.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"spadbuf.c" ${BOOK} >spadbuf.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/spadbuf.c ) + +${MIDOBJ}/spadint.o: ${BOOK} + @ echo 136 making ${MIDOBJ}/spadint.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"spadint.c" ${BOOK} >spadint.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/spadint.c ) + +${MIDOBJ}/titlebar.o: ${BOOK} + @ echo 140 making ${MIDOBJ}/titlebar.o from ${BOOK} + @ (cd ${MID} ; ${TANGLE} -R"titlebar.c" ${BOOK} >titlebar.c ) + @ ( cd ${MIDOBJ} ; \ + ${CC} -I${INC} -I${MID} -c ${CFLAGS} ${MID}/titlebar.c ) + +${OUTLIB}/ex2ht: ${EX2HT_OBJS} + @ echo 143 linking ${OUTLIB}/ex2ht + @ ${CC} ${EX2HT_OBJS} -o ${OUTLIB}/ex2ht ${LDFLAGS} + +${OUT}/htadd: ${HTADD_OBJS} ${LIB}/sockio-c.o ${LIB}/bsdsignal.o + @ echo 144 linking ${OUT}/htadd + @ ${CC} ${HTADD_OBJS} -o ${OUT}/htadd ${LIB}/sockio-c.o \ + ${LIB}/bsdsignal.o ${LDFLAGS} + +${OUTLIB}/hthits: ${HTHITS_OBJS} + @ echo 145 linking ${OUTLIB}/hthits + @ ${CC} ${HTHITS_OBJS} -o ${OUTLIB}/hthits ${LDFLAGS} + +${OUT}/htsearch: ${OUTLIB}/htsearch ${OUTLIB}/presea + @ echo 147 making ${OUT}/htsearch + @ cp -p ${OUTLIB}/htsearch ${OUT}/htsearch + @ cp -p ${OUTLIB}/presea ${OUT}/presea + + +${OUT}/hypertex: ${HYPER_OBJS} ${LIB}/sockio-c.o ${LIB}/pixmap.o \ + ${LIB}/spadcolors.o ${LIB}/util.o ${LIB}/bsdsignal.o + @ echo 146 linking ${OUT}/hypertex + @ (cd ${OUT} ; \ + ${CC} -g ${HYPER_OBJS} -o ${OUT}/hypertex ${LIB}/sockio-c.o \ + ${LIB}/pixmap.o ${LIB}/spadcolors.o ${LIB}/util.o \ + ${LIB}/bsdsignal.o ${LDFLAGS} -lX11 -lm -L${LIB} ) + +${OUTLIB}/spadbuf: ${SPADBUF_OBJS} ${LIB}/sockio-c.o ${LIB}/bsdsignal.o \ + ${LIB}/wct.o ${LIB}/edin.o ${LIB}/prt.o ${LIB}/cursor.o \ + ${LIB}/fnct-key.o + @ echo 148 making ${OUTLIB}/spadbuf + @ (cd ${OUTLIB} ; \ + ${CC} ${SPADBUF_OBJS} -o ${OUTLIB}/spadbuf ${LIB}/sockio-c.o \ + ${LIB}/bsdsignal.o ${LIB}/wct.o ${LIB}/edin.o ${LIB}/prt.o \ + ${LIB}/cursor.o ${LIB}/fnct-key.o ${LDFLAGS} ) + + +@ \eject \begin{thebibliography}{99} \bibitem{1} Jenks, R.J. and Sutor, R.S. @@ -1263,8 +20151,8 @@ ISBN 0-387-97855-0 Center for the Study of Language and Information ISBN 0-937073-81-4 Stanford CA (1992) -\bibitem{3} Page, William, ``The Axiom Wiki Website''\\ -{\bf http://wiki.axiom-developer.org} +\bibitem{3} Daly, Timothy, ``The Axiom Wiki Website''\\ +{\bf http://axiom.axiom-developer.org} \bibitem{4} Watt, Stephen, ``Aldor'',\\ {\bf http://www.aldor.org} \bibitem{5} Lamport, Leslie, ``Latex -- A Document Preparation System'', diff --git a/changelog b/changelog index e4f1b86..5c784cb 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,6 @@ +20080609 tpd src/Makefile make hypertex (use bookvol7) +20080609 tpd books/bookvol7 make hypertex +20080608 tpd books/Makefile call makeindex on bookvol8 20080608 tpd src/Makefile remove src/graph (use bookvol8) 20080608 tpd books/bookvol8 remove src/graph (use bookvol8) 20080608 tpd src/graph/gdraws/Makefile deleted, (use bookvol8) diff --git a/src/Makefile.pamphlet b/src/Makefile.pamphlet index 5644071..39f7ae3 100644 --- a/src/Makefile.pamphlet +++ b/src/Makefile.pamphlet @@ -145,8 +145,8 @@ smanclean: ${SRC}/sman/Makefile \subsection{The hyper directory} Hyperdoc is the Axiom document browser. <>= -hyperdir: ${SRC}/hyper/Makefile - @echo 13 making ${SRC}/hyper +hyperdir: ${SPD}/books/bookvol7.pamphlet + @echo 13 making hyperdoc from bookvol7 @mkdir -p ${INT}/hyper @mkdir -p ${OBJ}/${SYS}/hyper @mkdir -p ${OBJ}/${SYS}/bin @@ -154,25 +154,9 @@ hyperdir: ${SRC}/hyper/Makefile @mkdir -p ${MNT}/${SYS}/doc/hypertex/bitmaps @mkdir -p ${MNT}/${SYS}/doc/hypertex/pages @mkdir -p ${MNT}/${SYS}/doc/src/hyper - @(cd hyper ; ${ENV} ${MAKE} ) - -${SRC}/hyper/Makefile: ${SRC}/hyper/Makefile.pamphlet - @echo 14 making ${SRC}/hyper/Makefile from \ - ${SRC}/hyper/Makefile.pamphlet - @( cd hyper ; \ - ${DOCUMENT} ${NOISE} Makefile ; \ - cp Makefile.dvi ${MNT}/${SYS}/doc/src/hyper.Makefile.dvi ) - -hyperdocument: ${SRC}/hyper/Makefile - @echo 15 documenting ${SRC}/hyper - @mkdir -p ${INT}/doc/src/hyper - @( cd hyper ; ${ENV} ${MAKE} document ) - -hyperclean: ${SRC}/hyper/Makefile - @echo 16 cleaning ${SRC}/hyper - @( cd hyper ; ${ENV} ${MAKE} clean ) - @rm -f ${SRC}/hyper/Makefile - @rm -f ${SRC}/hyper/Makefile.dvi + @(cd ${INT}/hyper ; \ + ${TANGLE} -t8 ${SPD}/books/bookvol7.pamphlet >Makefile ; \ + ${ENV} ${MAKE} ) @ \subsection{The share directory}