/* * helpcom.h * * * Common #defines, structures and code for HC.C and HELP.C * */ #ifndef HELPCOM_H #define HELPCOM_H /* * help file signature * If you get a syntax error, remove the LU from the end of the number. */ #define HELP_SIG (0xAFBC1823LU) /* * commands imbedded in the help text */ #define CMD_LITERAL 1 /* next char taken literally */ #define CMD_PARA 2 /* paragraph start code */ #define CMD_LINK 3 /* hot-link start/end code */ #define CMD_FF 4 /* force a form-feed */ #define CMD_XONLINE 5 /* exclude from online help on/off */ #define CMD_XDOC 6 /* exclude from printed document on/off */ #define CMD_CENTER 7 /* center this line */ #define CMD_SPACE 8 /* next byte is count of spaces */ #define MAX_CMD 8 /* * on-line help dimensions */ #define SCREEN_WIDTH (78) #define SCREEN_DEPTH (22) #define SCREEN_INDENT (1) /* * printed document dimensions */ #define PAGE_WIDTH (72) /* width of printed text */ #define PAGE_INDENT (2) /* indent all text by this much */ #define TITLE_INDENT (1) /* indent titles by this much */ #define PAGE_RDEPTH (59) /* the total depth (inc. heading) */ #define PAGE_HEADING_DEPTH (3) /* depth of the heading */ #define PAGE_DEPTH (PAGE_RDEPTH-PAGE_HEADING_DEPTH) /* depth of text */ /* * Document page-break macros. Goto to next page if this close (or closer) * to end of page when starting a CONTENT, TOPIC, or at a BLANK line. */ #define CONTENT_BREAK (7) /* start of a "DocContent" entry */ #define TOPIC_BREAK (4) /* start of each topic under a DocContent entry */ #define BLANK_BREAK (2) /* a blank line */ /* * tokens returned by find_token_length */ #define TOK_DONE (0) /* len == 0 */ #define TOK_SPACE (1) /* a run of spaces */ #define TOK_LINK (2) /* an entire link */ #define TOK_PARA (3) /* a CMD_PARA */ #define TOK_NL (4) /* a new-line ('\n') */ #define TOK_FF (5) /* a form-feed (CMD_FF) */ #define TOK_WORD (6) /* a word */ #define TOK_XONLINE (7) /* a CMD_XONLINE */ #define TOK_XDOC (8) /* a CMD_XDOC */ #define TOK_CENTER (9) /* a CMD_CENTER */ /* * modes for find_token_length() and find_line_width() */ #define ONLINE 1 #define DOC 2 /* * struct PD_INFO used by process_document() */ typedef struct { /* used by process_document -- look but don't touch! */ int pnum, lnum; /* PD_GET_TOPIC is allowed to change these */ char far *curr; unsigned len; /* PD_GET_CONTENT is allowed to change these */ char far *id; char far *title; int new_page; /* general parameters */ char far *s; int i; } PD_INFO; /* * Commands passed to (*get_info)() and (*output)() by process_document() */ enum PD_COMMANDS { /* commands sent to pd_output */ PD_HEADING, /* call at the top of each page */ PD_FOOTING, /* called at the end of each page */ PD_PRINT, /* called to send text to the printer */ PD_PRINTN, /* called to print a char n times */ PD_PRINT_SEC, /* called to print the section title line */ PD_START_SECTION, /* called at the start of each section */ PD_START_TOPIC, /* called at the start of each topic */ PD_SET_SECTION_PAGE, /* set the current sections page number */ PD_SET_TOPIC_PAGE, /* set the current topics page number */ PD_PERIODIC, /* called just before curr is incremented to next token */ /* commands sent to pd_get_info */ PD_GET_CONTENT, PD_GET_TOPIC, PD_RELEASE_TOPIC, PD_GET_LINK_PAGE } ; typedef int (*PD_FUNC)(int cmd, PD_INFO *pd, VOIDPTR info); int _find_token_length(char far *curr, unsigned len, int *size, int *width); int find_token_length(int mode, char far *curr, unsigned len, int *size, int *width); int find_line_width(int mode, char far *curr, unsigned len); int process_document(PD_FUNC get_info, PD_FUNC output, VOIDPTR info); /* * Code common to both HC.C and HELP.C (in Fractint). * #include INCLUDE_COMMON once for each program */ #endif #ifdef INCLUDE_COMMON #ifndef XFRACT #define getint(ptr) (*(int far *)(ptr)) #define setint(ptr,n) (*(int far *)(ptr)) = n #else /* Get an int from an unaligned pointer * This routine is needed because this program uses unaligned 2 byte * pointers all over the place. */ getint(ptr) char *ptr; { int s; bcopy(ptr,&s,sizeof(int)); return s; } /* Set an int to an unaligned pointer */ void setint(ptr, n) int n; char *ptr; { bcopy(&n,ptr,sizeof(int)); } #endif static int is_hyphen(char far *ptr) /* true if ptr points to a real hyphen */ { /* checkes for "--" and " -" */ if ( *ptr != '-' ) return (0); /* that was easy! */ --ptr; return ( *ptr!=' ' && *ptr!='-' ); } int _find_token_length(register char far *curr, unsigned len, int *size, int *width) { register int _size = 0; register int _width = 0; int tok; if (len == 0) tok = TOK_DONE; else { switch ( *curr ) { case ' ': /* it's a run of spaces */ tok = TOK_SPACE; while ( *curr == ' ' && _size < (int)len ) { ++curr; ++_size; ++_width; } break; case CMD_SPACE: tok = TOK_SPACE; ++curr; ++_size; _width = *curr; ++curr; ++_size; break; case CMD_LINK: tok = TOK_LINK; _size += 1+3*sizeof(int); /* skip CMD_LINK + topic_num + topic_off + page_num */ curr += 1+3*sizeof(int); while ( *curr != CMD_LINK ) { if ( *curr == CMD_LITERAL ) { ++curr; ++_size; } ++curr; ++_size; ++_width; assert(_size < len); } ++_size; /* skip ending CMD_LINK */ break; case CMD_PARA: tok = TOK_PARA; _size += 3; /* skip CMD_PARA + indent + margin */ break; case CMD_XONLINE: tok = TOK_XONLINE; ++_size; break; case CMD_XDOC: tok = TOK_XDOC; ++_size; break; case CMD_CENTER: tok = TOK_CENTER; ++_size; break; case '\n': tok = TOK_NL; ++_size; break; case CMD_FF: tok = TOK_FF; ++_size; break; default: /* it must be a word */ tok = TOK_WORD; for(;;) { if ( _size >= (int)len ) break; else if ( *curr == CMD_LITERAL ) { curr += 2; _size += 2; _width += 1; } else if ( *curr == '\0' ) { assert(0); } else if ((unsigned)*curr <= MAX_CMD || *curr == ' ' || *curr == '\n') break; else if ( *curr == '-' ) { ++curr; ++_size; ++_width; if ( is_hyphen(curr-1) ) break; } else { ++curr; ++_size; ++_width; } } break; } /* switch */ } if (size != NULL) *size = _size; if (width != NULL) *width = _width; return (tok); } int find_token_length(int mode, char far *curr, unsigned len, int *size, int *width) { int tok; int t; int _size; tok = _find_token_length(curr, len, &t, width); if ( (tok == TOK_XONLINE && mode == ONLINE) || (tok == TOK_XDOC && mode == DOC) ) { _size = 0; for(;;) { curr += t; len -= t; _size += t; tok = _find_token_length(curr, len, &t, NULL); if ( (tok == TOK_XONLINE && mode == ONLINE) || (tok == TOK_XDOC && mode == DOC) || (tok == TOK_DONE) ) break; } _size += t; } else _size = t; if (size != NULL ) *size = _size; return (tok); } int find_line_width(int mode, char far *curr, unsigned len) { int size = 0, width = 0, lwidth = 0, done = 0, tok; do { tok = find_token_length(mode, curr, len, &size, &width); switch(tok) { case TOK_DONE: case TOK_PARA: case TOK_NL: case TOK_FF: done = 1; break; case TOK_XONLINE: case TOK_XDOC: case TOK_CENTER: curr += size; len -= size; break; default: /* TOK_SPACE, TOK_LINK or TOK_WORD */ lwidth += width; curr += size; len -= size; break; } } while ( !done ); return (lwidth); } #define DO_PRINTN(ch,n) ( pd.s = &(ch), pd.i = (n), output(PD_PRINTN, &pd, info) ) #define DO_PRINT(str,n) ( pd.s = (str), pd.i = (n), output(PD_PRINT, &pd, info) ) int process_document(PD_FUNC get_info, PD_FUNC output, VOIDPTR info) { int skip_blanks; int tok; int size, width; int col; char page_text[10]; PD_INFO pd; char nl = '\n', sp = ' '; int first_section, first_topic; pd.pnum = 1; pd.lnum = 0; col = 0; output(PD_HEADING, &pd, info); first_section = 1; while ( get_info(PD_GET_CONTENT, &pd, info) ) { if ( !output(PD_START_SECTION, &pd, info) ) return (0); if ( pd.new_page && pd.lnum != 0 ) { if ( !output(PD_FOOTING, &pd, info) ) return (0); ++pd.pnum; pd.lnum = 0; if ( !output(PD_HEADING, &pd, info) ) return (0); } else { if ( pd.lnum+2 > PAGE_DEPTH-CONTENT_BREAK ) { if ( !output(PD_FOOTING, &pd, info) ) return (0); ++pd.pnum; pd.lnum = 0; if ( !output(PD_HEADING, &pd, info) ) return (0); } else if (pd.lnum > 0) { if ( !DO_PRINTN(nl, 2) ) return (0); pd.lnum += 2; } } if ( !output(PD_SET_SECTION_PAGE, &pd, info) ) return (0); if ( !first_section ) { if ( !output(PD_PRINT_SEC, &pd, info) ) return (0); ++pd.lnum; } col = 0; first_topic = 1; while ( get_info(PD_GET_TOPIC, &pd, info) ) { if ( !output(PD_START_TOPIC, &pd, info) ) return (0); skip_blanks = 0; col = 0; if ( !first_section ) /* do not skip blanks for DocContents */ { while (pd.len > 0) { tok = find_token_length(DOC, pd.curr, pd.len, &size, NULL); if (tok != TOK_XDOC && tok != TOK_XONLINE && tok != TOK_NL && tok != TOK_DONE ) break; pd.curr += size; pd.len -= size; } if ( first_topic && pd.len != 0 ) { if ( !DO_PRINTN(nl, 1) ) return (0); ++pd.lnum; } } if ( pd.lnum > PAGE_DEPTH-TOPIC_BREAK ) { if ( !output(PD_FOOTING, &pd, info) ) return (0); ++pd.pnum; pd.lnum = 0; if ( !output(PD_HEADING, &pd, info) ) return (0); } else if ( !first_topic ) { if ( !DO_PRINTN(nl, 1) ) return (0); pd.lnum++; } if ( !output(PD_SET_TOPIC_PAGE, &pd, info) ) return (0); do { if ( !output(PD_PERIODIC, &pd, info) ) return (0); tok = find_token_length(DOC, pd.curr, pd.len, &size, &width); switch ( tok ) { case TOK_PARA: { int indent, margin; unsigned holdlen = 0; char far *holdcurr = 0; int in_link = 0; ++pd.curr; indent = *pd.curr++; margin = *pd.curr++; pd.len -= 3; if ( !DO_PRINTN(sp, indent) ) return (0); col = indent; for(;;) { if ( !output(PD_PERIODIC, &pd, info) ) return (0); tok = find_token_length(DOC, pd.curr, pd.len, &size, &width); if ( tok == TOK_NL || tok == TOK_FF ) break; if ( tok == TOK_DONE ) { if (in_link == 0) { col = 0; ++pd.lnum; if ( !DO_PRINTN(nl, 1) ) return (0); break; } else if (in_link == 1) { tok = TOK_SPACE; width = 1; size = 0; ++in_link; } else if (in_link == 2) { tok = TOK_WORD; width = strlen(page_text); col += 8 - width; size = 0; pd.curr = page_text; ++in_link; } else if (in_link == 3) { pd.curr = holdcurr; pd.len = holdlen; in_link = 0; continue; } } if ( tok == TOK_PARA ) { col = 0; /* fake a nl */ ++pd.lnum; if ( !DO_PRINTN(nl, 1) ) return (0); break; } if (tok == TOK_XONLINE || tok == TOK_XDOC ) { pd.curr += size; pd.len -= size; continue; } if ( tok == TOK_LINK ) { pd.s = pd.curr+1; if ( get_info(PD_GET_LINK_PAGE, &pd, info) ) { in_link = 1; sprintf(page_text, "(p. %d)", pd.i); } else in_link = 3; holdcurr = pd.curr + size; holdlen = pd.len - size; pd.len = size - 2 - 3*sizeof(int); pd.curr += 1 + 3*sizeof(int); continue; } /* now tok is TOK_SPACE or TOK_WORD */ if (col+width > PAGE_WIDTH) { /* go to next line... */ if ( !DO_PRINTN(nl, 1) ) return (0); if ( ++pd.lnum >= PAGE_DEPTH ) { if ( !output(PD_FOOTING, &pd, info) ) return (0); ++pd.pnum; pd.lnum = 0; if ( !output(PD_HEADING, &pd, info) ) return (0); } if ( tok == TOK_SPACE ) width = 0; /* skip spaces at start of a line */ if ( !DO_PRINTN(sp, margin) ) return (0); col = margin; } if (width > 0) { if (tok == TOK_SPACE) { if ( !DO_PRINTN(sp, width) ) return (0); } else { if ( !DO_PRINT(pd.curr, (size==0) ? width : size) ) return (0); } } col += width; pd.curr += size; pd.len -= size; } skip_blanks = 0; width = size = 0; break; } case TOK_NL: if (skip_blanks && col == 0) break; ++pd.lnum; if ( pd.lnum >= PAGE_DEPTH || (col == 0 && pd.lnum >= PAGE_DEPTH-BLANK_BREAK) ) { if ( col != 0 ) /* if last wasn't a blank line... */ { if ( !DO_PRINTN(nl, 1) ) return (0); } if ( !output(PD_FOOTING, &pd, info) ) return (0); ++pd.pnum; pd.lnum = 0; skip_blanks = 1; if ( !output(PD_HEADING, &pd, info) ) return (0); } else { if ( !DO_PRINTN(nl, 1) ) return (0); } col = 0; break; case TOK_FF: if (skip_blanks) break; if ( !output(PD_FOOTING, &pd, info) ) return (0); col = 0; pd.lnum = 0; ++pd.pnum; if ( !output(PD_HEADING, &pd, info) ) return (0); break; case TOK_CENTER: width = (PAGE_WIDTH - find_line_width(DOC,pd.curr,pd.len)) / 2; if ( !DO_PRINTN(sp, width) ) return (0); break; case TOK_LINK: skip_blanks = 0; if ( !DO_PRINT(pd.curr+1+3*sizeof(int), size-3*sizeof(int)-2) ) return (0); pd.s = pd.curr+1; if ( get_info(PD_GET_LINK_PAGE, &pd, info) ) { width += 9; sprintf(page_text, " (p. %d)", pd.i); if ( !DO_PRINT(page_text, strlen(page_text)) ) return (0); } break; case TOK_WORD: skip_blanks = 0; if ( !DO_PRINT(pd.curr, size) ) return (0); break; case TOK_SPACE: skip_blanks = 0; if ( !DO_PRINTN(sp, width) ) return (0); break; case TOK_DONE: case TOK_XONLINE: /* skip */ case TOK_XDOC: /* ignore */ break; } /* switch */ pd.curr += size; pd.len -= size; col += width; } while (pd.len > 0); get_info(PD_RELEASE_TOPIC, &pd, info); first_topic = 0; } /* while */ first_section = 0; } /* while */ if ( !output(PD_FOOTING, &pd, info) ) return (0); return (1); } #undef DO_PRINT #undef DO_PRINTN #undef INCLUDE_COMMON #endif /* #ifdef INCLUDE_COMMON */