📄 gridtext.c
字号:
/* GridText.c** CHARACTER GRID HYPERTEXT OBJECT**** (c) COPYRIGHT MIT 1995.** Please first read the full copyright statement in the file COPYRIGH.** @(#) $Id: GridText.c,v 1.54 2002/06/07 11:11:22 kahan Exp $**** This is the definition of the HyperDoc object and the HText interface** which is used in the current Library HTML parser*/#include <assert.h>#include "WWWLib.h"#include "WWWCache.h"#include "WWWApp.h"#include "WWWHTML.h"#include "HTBrowse.h"#include "HTFont.h"#include "GridStyle.h"#include "GridText.h"/* HWL 18/7/94: applied patch from agl@glas2.glas.apc.org (Anton Tropashko) */#ifdef CYRILLIC#include "a_stdio.h"#endif#define MAX_LINE HTScreenWidth /* No point in accumulating more */#define LOADED_LIMIT 40#ifdef CURSES#define DISPLAY_LINES (HTScreenHeight)#define TITLE_LINES 0#else#define DISPLAY_LINES (HTScreenHeight - 2) /* Exclude prompt line */#define TITLE_LINES 1#endifstruct _HTStream { /* only know it as object */ const HTStreamClass * isa; /* ... */};/* From default style sheet:*/extern HTStyleSheet * styleSheet; /* Default or overridden *//* Exports*/ PUBLIC HText * HTMainText = 0; /* Equivalent of main window */PUBLIC HTParentAnchor * HTMainAnchor = 0; /* Anchor for HTMainText */typedef struct _line { struct _line *next; struct _line *prev; short unsigned offset; /* Implicit initial spaces */ short unsigned size; /* Number of characters */ BOOL split_after; /* Can we split after? */ BOOL bullet; /* Do we bullet? */ char data[1]; /* Space for terminator at least! */} HTLine;#define LINE_SIZE(l) (sizeof(HTLine)+(l)) /* allow for terminator */typedef struct _TextAnchor { struct _TextAnchor * next; int number; /* For user interface */ int start; /* Characters */ int extent; /* Characters */ HTChildAnchor * anchor;} TextAnchor;/* Notes on struct _Htext:** next_line is valid iff state is false.** top_of_screen line means the line at the top of the screen** or just under the title if there is one.*/struct _HText { HTParentAnchor * node_anchor; char * title; HTLine * last_line; int lines; /* Number of them */ int chars; /* Number of them */ TextAnchor * first_anchor; /* Singly linked list */ TextAnchor * last_anchor; int last_anchor_number; /* user number */ TextAnchor * current_anchor;/* For Internal use: */ HTStyle * style; /* Current style */ int display_on_the_fly; /* Lines left */ BOOL all_pages; /* Loop on the fly */ int top_of_screen; /* Line number */ HTLine * top_of_screen_line; /* Top */ HTLine * next_line; /* Bottom + 1 */ int permissible_split; /* in last line */ BOOL in_line_1; /* of paragraph */ BOOL stale; /* Must refresh */ HTStream* target; /* Output stream */ HTStreamClass targetClass; /* Output routines */ LineMode * pLm;};PRIVATE HTTabStop tabs_8[] = { { 0, 8 }, {0, 16}, {0, 24}, {0, 32}, {0, 40}, { 0, 48 }, {0, 56}, {0, 64}, {0, 72}, {0, 80}, { 0, 88 }, {0, 96}, {0, 104}, {0, 112}, {0, 120}, { 0, 128 }, {0, 136}, {0, 144}, {0, 152}, {0, 160}, {0, 168}, {0, 176}, {0, 0 } /* Terminate */};#define PUTC(c) (*text->targetClass.put_character)(text->target, c)#define PUTS(s) (*text->targetClass.put_string)(text->target, s)/* Boring static variable used for moving cursor across*/#define SPACES(n) (&space_string[HTScreenWidth - (n)]) /* String containing blank spaces only */PRIVATE char * space_string;PRIVATE HTStyle default_style = { 0, "(Unstyled)", "", (HTFont)0, 1.0, HT_BLACK, 0, 0, 0, 0, 0, HT_LEFT, 1, 0, tabs_8, NO, NO, 0, 0, 0 }; PUBLIC void clear_screen (void); /* Forward */PRIVATE HTList * loaded_texts; /* A list of all those in memory *//* Creation Method** ---------------**** Interactive version***/extern LineMode * Context_getLineMode(HTRequest * request);PUBLIC HText * LMHText_new ( HTRequest * request, HTParentAnchor * anchor, HTStream *outstrm){ HTLine * line; HText * self; if ((self = (HText *) HT_CALLOC(1, sizeof(*self))) == NULL)/* HT_OUTOFMEM("HText"); */ return self; self->pLm = Context_getLineMode(request); if (!loaded_texts) loaded_texts = HTList_new(); HTList_addObject(loaded_texts, self); if (HTList_count(loaded_texts) >= LOADED_LIMIT) { HTTRACE(CACHE_TRACE, "MemoryCache. Freeing off cached doc.\n"); HText_free((HText *)HTList_removeFirstObject(loaded_texts)); } if ((line = self->last_line = (HTLine *) HT_MALLOC(LINE_SIZE(MAX_LINE))) == NULL) HT_OUTOFMEM("HText_New"); line->next = line->prev = line; line->offset = line->size = 0; self->lines = self->chars = 0; self->title = 0; self->first_anchor = self->last_anchor = self->current_anchor = 0; self->style = &default_style; self->top_of_screen = 0; self->node_anchor = anchor; self->last_anchor_number = 0; /* Numbering of them for references */ self->stale = YES; self->target = NULL; HTAnchor_setDocument(anchor, (void *) self); clear_screen(); HTMainText = self; HTMainAnchor = anchor; self->display_on_the_fly = DISPLAY_LINES; self->all_pages = NO; /* One page at a time on the fly */ if (!space_string) { /* Make a blank line */ char *p; if ((space_string = (char *) HT_MALLOC(HTScreenWidth+1)) == NULL) HT_OUTOFMEM("HText_New"); for (p=space_string; p<space_string+HTScreenWidth; p++) *p = ' '; /* Used for printfs later */ space_string[HTScreenWidth] = '\0'; } return self;}/* Creation Method 2** ---------------**** Non-interative OR interactive if stream is NULL** Stream is assumed open and left open.*/PUBLIC HText * LMHText_new2 (HTRequest * request, HTParentAnchor * anchor, HTStream * stream){ HText * me = LMHText_new(request, anchor, stream); if (stream) { me->target = stream; me->targetClass = *stream->isa; /* copy action procedures */ me->all_pages = YES; /* Display whole file on the fly */ } return me;}/* Free a data object** ------------------** Removes the data object from the anchor*/PUBLIC void hyper_free (HText * self){ if (self) { while (1) { /* Free off line array */ HTLine * last = self->last_line; if (last) { last->next->prev = last->prev; last->prev->next = last->next; self->last_line = last->prev; if (last == self->last_line) break; HT_FREE(last); } else break; } while (self->first_anchor) { /* Free off anchor array */ TextAnchor * last = self->first_anchor; self->first_anchor = last->next; HT_FREE(last); } if (self == HTMainText) HTMainText = NULL; HT_FREE(self->last_line); HT_FREE(self); }}/* Free Entire Text** ----------------*/PUBLIC void HText_free (HText * self){ if (self) { HTAnchor_setDocument(self->node_anchor, NULL); hyper_free(self); }}PUBLIC BOOL LMHText_delete (HText * self){ if (self) { HTAnchor_setDocument(self->node_anchor, NULL); hyper_free(self); return YES; } return NO;}/*** Free all registered hypertext documents in memory*/PUBLIC BOOL HText_freeAll (void){ if (loaded_texts) { HTList * cur = loaded_texts; HText * pres; while ((pres = (HText *) HTList_nextObject(cur))) HText_free(pres); HTList_delete(loaded_texts); return YES; } return NO;}/* Display Methods** ---------------*//* Clear the screen (on screen-mode systems)** ----------------*/PUBLIC void clear_screen (void){ if (WWWTRACE) return; /* in trace mode, don't clear trace away */#ifdef CURSES if (w_text != NULL) { wmove(w_text,0,0); wclear(w_text); }#endif /* Not CURSES */ if (HTMainText) HTMainText->stale = YES;}/* Output a line** -------------*/PRIVATE void display_line (HText * text, HTLine * line){#ifdef CURSES int y, x; waddstr(w_text, SPACES(line->offset)); waddstr(w_text, line->data); getyx(w_text, y, x); if (y < DISPLAY_LINES-1) { wmove(w_text, ++y, 0); }#else if (!text->target) {#ifdef CYRILLIC /* HWL 18/7/94: applied patch from agl@glas2.glas.apc.org (Anton Tropashko) */ a_print(SPACES(line->offset),H,stdout); a_print(line->data,H,stdout); fputc('\n',stdout);#else OutputData(LineMode_getView(text->pLm), "%s%s\n", SPACES(line->offset), line->data);#endif } else { PUTS(SPACES(line->offset)); PUTS(line->data); PUTC('\n'); }#endif }/* Output the title line** ---------------------*/PRIVATE void display_title (HText * text){ const char * title = HTAnchor_title(text->node_anchor); char percent[20], format[20]; if (text->lines > (DISPLAY_LINES-1)) {#ifdef NOPE sprintf(percent, " (p%d of %d)", (text->top_of_screen/(DISPLAY_LINES-1)) + 1, (text->lines-1)/(DISPLAY_LINES-1) + 1); sprintf(percent, " (%d%%)", 100*(text->top_of_screen+DISPLAY_LINES-1)/ /* Seen */ (text->lines)); /* Total */#else sprintf(percent, " (%d/%d)", text->top_of_screen+DISPLAY_LINES-1, /* Seen */ text->lines); /* Total */#endif } else { percent[0] = 0; /* Null string */ } sprintf(format, "%%%d.%ds%%s\n", /* Generate format string */ (int)(HTScreenWidth-strlen(percent)), (int)(HTScreenWidth-strlen(percent)) );#ifdef CURSES mvwprintw(w_top, 0, 0, format, title, percent); wrefresh(w_top);#else if (!text->target) OutputData(LineMode_getView(text->pLm), format, title, percent); else { char * line; if ((line = (char *) HT_MALLOC(HTScreenWidth+10)) == NULL) HT_OUTOFMEM("display_titile"); sprintf(line, format, title, percent); PUTS(line); HT_FREE(line); }#endif}/* Fill the screen with blank after the file** --------------------------*/PRIVATE void fill_screen (HText * text, int n){ if (n<=0 || n>1000) return; /* Large value means no pagination */ if (text->target) return;#ifdef CURSES waddstr(w_text, end_mark); wclrtobot(w_text); wrefresh(w_text);#else#ifndef VIOLA if (!text->target) OutputData(LineMode_getView(text->pLm), "%s\n", end_mark); else { PUTS(end_mark); PUTC('\n'); } n--; for (; n; n--) { if (!text->target) OutputData(LineMode_getView(text->pLm), "\n"); else PUTC('\n'); }#endif#endif /* Not CURSES */}/* Output a page** -------------*/PRIVATE void display_page (HText * text, int line_number){ HTLine * line = text->last_line->prev; int i; const char * title = HTAnchor_title(text->node_anchor); int lines_of_text = title ? (DISPLAY_LINES-TITLE_LINES) : DISPLAY_LINES; int last_screen = text->lines - lines_of_text;/* Constrain the line number to be within the document*/ if (text->lines <= lines_of_text) line_number = 0; else if (line_number>last_screen) line_number = last_screen; else if (line_number < 0) line_number = 0; for(i=0, line = text->last_line->next; /* Find line */ i<line_number && (line!=text->last_line); i++, line=line->next) /* Loop */ assert(line->next != NULL); while((line!=text->last_line) && (line->size==0)) { /* Skip blank lines */ assert(line->next != NULL); line = line->next; line_number ++; }/* Can we just scroll to it?*/ #ifndef VM /* No scrolling */ if (!text->stale && (line_number>=text->top_of_screen) && (line_number < text->top_of_screen + DISPLAY_LINES)) { /* Yes */ lines_of_text = line_number - text->top_of_screen; line = text->next_line; text->top_of_screen = line_number;#ifdef CURSES scrollok(w_text, TRUE); for (i = 0; i < lines_of_text; i++) { scroll(w_text); }#endif } else#endif { clear_screen(); /* No */ text->top_of_screen = line_number; if (title) display_title(text); } /* Bug: when we scroll to a part slightly futher down a page which previously fitted all on one screen including the [End], the code below will add an extra [End] to the screen, giving a total of two, one underneath the other.*/ /* print it */ if (line) { for(i=0; (i< lines_of_text) && (line != text->last_line); i++) { assert(line != NULL); display_line(text, line); line = line->next; } fill_screen(text, lines_of_text - i); } text->next_line = line; /* Line after screen */ text->stale = NO; /* Display is up-to-date */}/* Object Building methods** -----------------------**** These are used by a parser to build the text in an object*/PUBLIC void HText_beginAppend (HText * text){ text->permissible_split = 0; text->in_line_1 = YES;}/* Add a new line of text** ----------------------**** On entry,**** split is zero for newline function, else number of characters** before split.** text->display_on_the_fly** may be set to indicate direct output of the finished line.** text->all_pages** if set indicates all pages are to be done on the fly.** On exit,** A new line has been made, justified according to the** current style. Text after the split (if split nonzero)** is taken over onto the next line.**** If display_on_the_fly is set, then it is decremented and** the finished line is displayed.*/#define new_line(text) split_line(text, 0)PRIVATE void split_line (HText * text, int split){ HTStyle * style = text->style; int spare; int indent = (int) (text->in_line_1 ? text->style->indent1st : text->style->leftIndent);/* Make new line*/ HTLine * previous = text->last_line; HTLine * line; if ((line = (HTLine *) HT_MALLOC(LINE_SIZE(MAX_LINE))) == NULL) HT_OUTOFMEM("split_line"); text->lines++; previous->next->prev = line; line->prev = previous; line->next = previous->next; previous->next = line; text->last_line = line; line->size = 0; line->offset = 0;/* Split at required point*/ if (split) { /* Delete space at "split" splitting line */ char * p; previous->data[previous->size] = 0; for (p = &previous->data[split]; *p; p++) if (*p != ' ') break; strcpy(line->data, p); line->size = strlen(line->data); previous->size = split; } while ((previous->size > 0) && (previous->data[previous->size-1] == ' ')) /* Strip trailers */ previous->size--; if ((previous = (HTLine *) HT_REALLOC(previous, LINE_SIZE(previous->size)))==NULL) HT_OUTOFMEM("split_line"); previous->prev->next = previous; /* Link in new line */ previous->next->prev = previous; /* Could be same node of course */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -