📄 gridtext.c
字号:
/* Character grid hypertext object** ===============================*/#include "HTUtils.h"#include "tcp.h"#include "HTString.h"#include "HTFont.h"#include "HTAccess.h"#include "HTAnchor.h"#include "HTParse.h"#include "HTTP.h"#include "HTAlert.h"#include "HTCJK.h"#include "UCDefs.h"#include "UCAux.h"#include <assert.h>#include <ctype.h>#ifndef VMS#ifdef SYSLOG_REQUESTED_URLS#include <syslog.h>#endif /* SYSLOG_REQUESTED_URLS */#endif /* !VMS */#include "GridText.h"#include "LYCurses.h"#include "LYUtils.h"#include "LYStrings.h"#include "LYStructs.h"#include "LYGlobalDefs.h"#include "LYGetFile.h"#include "LYSignal.h"#include "LYMail.h"#include "LYList.h"#include "LYCharSets.h"#include "LYCharUtils.h" /* LYUCTranslateBack... */#include "UCMap.h"#ifdef EXP_CHARTRANS_AUTOSWITCH#include "UCAuto.h"#endif /* EXP_CHARTRANS_AUTOSWITCH */#include "LYexit.h"#include "LYLeaks.h"#ifdef USE_COLOR_STYLE#include "AttrList.h"#include "LYHash.h"unsigned int cached_styles[CACHEH][CACHEW];#endif#ifdef USE_COLOR_STYLE_UNUSEDvoid LynxClearScreenCache NOARGS{ int i,j;if (TRACE) fprintf(stderr, "flushing cached screen styles\n"); for (i=0;i<CACHEH;i++) for (j=0;j<CACHEW;j++) cached_styles[i][j]=s_a;}#endif /* USE_COLOR_STYLE */struct _HTStream { /* only know it as object */ CONST HTStreamClass * isa; /* ... */};#define TITLE_LINES 1#define IS_UTF_EXTRA(ch) (text->T.output_utf8 && \ ((unsigned char)(ch)&0xc0) == 0x80)#define FREE(x) if (x) {free(x); x = NULL;}extern BOOL HTPassHighCtrlRaw;extern HTkcode kanji_code;extern HTCJKlang HTCJK;/* Exports*/PUBLIC HText * HTMainText = NULL; /* Equivalent of main window */PUBLIC HTParentAnchor * HTMainAnchor = NULL; /* Anchor for HTMainText */PUBLIC char * HTAppName = "Lynx"; /* Application name */PUBLIC char * HTAppVersion = LYNX_VERSION; /* Application version */PUBLIC int HTFormNumber = 0;PUBLIC int HTFormFields = 0;PUBLIC char * HTCurSelectGroup = NULL; /* Form select group name */PRIVATE int HTCurSelectGroupCharset = -1; /* ... and name's charset */PUBLIC int HTCurSelectGroupType = F_RADIO_TYPE; /* Group type */PUBLIC char * HTCurSelectGroupSize = NULL; /* Length of select */PRIVATE char * HTCurSelectedOptionValue = NULL; /* Select choice */PUBLIC char * checked_box = "[X]";PUBLIC char * unchecked_box = "[ ]";PUBLIC char * checked_radio = "(*)";PUBLIC char * unchecked_radio = "( )";PUBLIC BOOLEAN underline_on = OFF;PUBLIC BOOLEAN bold_on = OFF;#if defined(USE_COLOR_STYLE)#define MAX_STYLES_ON_LINE 64typedef struct _stylechange { int horizpos; /* horizontal position of this change */ int style; /* which style to change to */ int direction; /* on or off */ int previous; /* previous style */} HTStyleChange;#endiftypedef struct _line { struct _line *next; struct _line *prev; int unsigned offset; /* Implicit initial spaces */ int unsigned size; /* Number of characters */ BOOL split_after; /* Can we split after? */ BOOL bullet; /* Do we bullet? */#if defined(USE_COLOR_STYLE) HTStyleChange styles[MAX_STYLES_ON_LINE]; int numstyles;#endif 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 line_pos; /* Position in text */ int extent; /* Characters */ int line_num; /* Place in document */ char * hightext; /* The link text */ char * hightext2; /* A second line*/ int hightext2offset;/* offset from left */ int link_type; /* Normal, internal, or form? */ FormInfo * input_field; /* Info for form links */ BOOL show_anchor; /* Show the anchor? */ BOOL inUnderline; /* context is underlined */ HTChildAnchor * anchor;} TextAnchor;typedef struct _HTTabID { char * name; /* ID value of TAB */ int column; /* Zero-based column value */} HTTabID;/* Notes on struct _Htext:** next_line is valid if 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; HTLine * last_line; int Lines; /* Number of them */ int chars; /* Number of them */ TextAnchor * first_anchor; /* Singly linked list */ TextAnchor * last_anchor; HTList * forms; /* also linked internally */ int last_anchor_number; /* user number */ BOOL source; /* Is the text source? */ BOOL toolbar; /* Toolbar set? */ HTList * tabs; /* TAB IDs */ HTList * hidden_links; /* Content-less links ... */ int hiddenlinkflag; /* ... and how to treat them */ BOOL no_cache; /* Always refresh? */ char LastChar; /* For absorbing white space */ BOOL IgnoreExcess; /* Ignore chars at wrap point *//* For Internal use: */ HTStyle * style; /* Current style */ int display_on_the_fly; /* Lines left */ 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 */ BOOL page_has_target; /* has target on screen */ HTkcode kcode; /* Kanji code? */ enum grid_state { S_text, S_esc, S_dollar, S_paren, S_nonascii_text, S_dollar_paren, S_jisx0201_text } state; /* Escape sequence? */ char kanji_buf; /* Lead multibyte */ int in_sjis; /* SJIS flag */ int halted; /* emergency halt */ BOOL have_8bit_chars; /* Any non-ASCII chars? */ LYUCcharset * UCI; /* node_anchor UCInfo */ int UCLYhndl; /* charset we are fed */ UCTransParams T; HTStream * target; /* Output stream */ HTStreamClass targetClass; /* Output routines */};PRIVATE void HText_AddHiddenLink PARAMS((HText *text, TextAnchor *textanchor));/* * Boring static variable used for moving cursor across */#define UNDERSCORES(n) \ ((n) >= MAX_LINE ? underscore_string : &underscore_string[(MAX_LINE-1)] - (n))/* * Memory leak fixed. * 05-29-94 Lynx 2-3-1 Garrett Arch Blythe * Changed to arrays. */PRIVATE char underscore_string[MAX_LINE + 1];PUBLIC char star_string[MAX_LINE + 1];PRIVATE int ctrl_chars_on_this_line = 0; /* num of ctrl chars in current line */PRIVATE HTStyle default_style = { 0, "(Unstyled)", "", (HTFont)0, 1, HT_BLACK, 0, 0, 0, 0, 0, HT_LEFT, 1, 0, 0, NO, NO, 0, 0, 0 };PRIVATE HTList * loaded_texts = NULL; /* A list of all those in memory */PUBLIC HTList * search_queries = NULL; /* isindex and whereis queries */PRIVATE void free_all_texts NOARGS;PRIVATE int HText_TrueLineSize PARAMS(( HTLine * line, HText * text, BOOL IgnoreSpaces));#ifndef VMS /* VMS has a better way - right? - kw */#define CHECK_FREE_MEM#endif#ifdef CHECK_FREE_MEM/* * text->halted = 1: have set fake 'Z' and output a message * 2: next time when HText_appendCharacter is called * it will append *** MEMORY EXHAUSTED ***, then set * to 3. * 3: normal text output will be suppressed (but not anchors, * form fields etc.) */PRIVATE void HText_halt NOARGS{ if (HTFormNumber > 0) HText_DisableCurrentForm(); if (!HTMainText) return; if (HTMainText->halted < 2) HTMainText->halted = 2;}#define MIN_NEEDED_MEM 5000/* * Check whether factor*min(bytes,MIN_NEEDED_MEM) is available, * or bytes if factor is 0. * MIN_NEEDED_MEM and factor together represent a security margin, * to take account of all the memory allocations where we don't check * and of buffers which may be emptied before HTCheckForInterupt() * is (maybe) called and other things happening, with some chance of * success. * This just tries to malloc() the to-be-checked-for amount of memory, * which might make the situation worse depending how allocation works. * There should be a better way... - kw */PRIVATE BOOL mem_is_avail ARGS2( size_t, factor, size_t, bytes){ void *p; if (bytes < MIN_NEEDED_MEM && factor > 0) bytes = MIN_NEEDED_MEM; if (factor == 0) factor = 1; p = malloc(factor * bytes); if (p) { FREE(p); return YES; } else { return NO; }}/* * Replacement for calloc which checks for "enough" free memory * (with some security margins) and tries various recovery actions * if deemed necessary. - kw */PRIVATE void * LY_check_calloc ARGS2( size_t, nmemb, size_t, size){ int i, n; if (mem_is_avail(4, nmemb * size)) { return (calloc(nmemb, size)); } n = HTList_count(loaded_texts); for (i = n - 1; i > 0; i--) { HText * t = HTList_objectAt(loaded_texts, i); if (t == HTMainText) t = NULL; /* shouldn't happen */ if (TRACE) { fprintf(stderr, "\r *** Emergency freeing document %d/%d for '%s'%s!\n", i + 1, n, ((t && t->node_anchor && t->node_anchor->address) ? t->node_anchor->address : "unknown anchor"), ((t && t->node_anchor && t->node_anchor->post_data) ? " with POST data" : "")); } HTList_removeObjectAt(loaded_texts, i); HText_free(t); if (mem_is_avail(4, nmemb * size)) { return (calloc(nmemb, size)); } } LYFakeZap(YES); if (!HTMainText || HTMainText->halted <= 1) { if (!mem_is_avail(2, nmemb * size)) { HText_halt(); if (mem_is_avail(0, 700)) { HTAlert("Memory exhausted, display interrupted!"); } } else { if ((!HTMainText || HTMainText->halted == 0) && mem_is_avail(0, 700)) { HTAlert("Memory exhausted, will interrupt transfer!"); if (HTMainText) HTMainText->halted = 1; } } } return (calloc(nmemb, size));}#define LY_CALLOC LY_check_calloc#else /* CHECK_FREE_MEM */ /* using the regular calloc */#define LY_CALLOC calloc#endif /* CHECK_FREE_MEM */PRIVATE void HText_getChartransInfo ARGS1( HText *, me){ me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor, UCT_STAGE_HTEXT); if (me->UCLYhndl < 0) { int chndl = current_char_set; HTAnchor_setUCInfoStage(me->node_anchor, chndl, UCT_STAGE_HTEXT, UCT_SETBY_STRUCTURED); me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor, UCT_STAGE_HTEXT); } me->UCI = HTAnchor_getUCInfoStage(me->node_anchor, UCT_STAGE_HTEXT);}PRIVATE void PerFormInfo_free ARGS1( PerFormInfo *, form){ if (form) { FREE(form->accept_cs); FREE(form->thisacceptcs); FREE(form); }}PRIVATE void FormList_delete ARGS1( HTList *, forms){ HTList *cur = forms; PerFormInfo *form; while ((form = (PerFormInfo *)HTList_nextObject(cur)) != NULL) PerFormInfo_free(form); HTList_delete(forms);}/* Creation Method** ---------------*/PUBLIC HText * HText_new ARGS1( HTParentAnchor *, anchor){#if defined(VMS) && defined(VAXC) && !defined(__DECC)#include <lib$routines.h> int status, VMType=3, VMTotal;#endif /* VMS && VAXC && !__DECC */ HTLine * line = NULL; HText * self = (HText *) calloc(1, sizeof(*self)); if (!self) return self;#if defined(VMS) && defined (VAXC) && !defined(__DECC) status = lib$stat_vm(&VMType, &VMTotal); if (TRACE) fprintf(stderr, "GridText: VMTotal = %d\n", VMTotal);#endif /* VMS && VAXC && !__DECC */ if (!loaded_texts) { loaded_texts = HTList_new(); atexit(free_all_texts); } /* * Links between anchors & documents are a 1-1 relationship. If * an anchor is already linked to a document we didn't call * HTuncache_current_document(), e.g., for the showinfo, options, * download, print, etc., temporary file URLs, so we'll check now * and free it before reloading. - Dick Wesseling (ftu@fi.ruu.nl) */ if (anchor->document) { HTList_removeObject(loaded_texts, anchor->document); if (TRACE) fprintf(stderr, "GridText: Auto-uncaching\n") ; ((HText *)anchor->document)->node_anchor = NULL; HText_free((HText *)anchor->document); anchor->document = NULL; } HTList_addObject(loaded_texts, self);#if defined(VMS) && defined(VAXC) && !defined(__DECC) while (HTList_count(loaded_texts) > HTCacheSize && VMTotal > HTVirtualMemorySize) {#else if (HTList_count(loaded_texts) > HTCacheSize) {#endif /* VMS && VAXC && !__DECC */ if (TRACE) fprintf(stderr, "GridText: Freeing off cached doc.\n"); HText_free((HText *)HTList_removeFirstObject(loaded_texts));#if defined(VMS) && defined (VAXC) && !defined(__DECC) status = lib$stat_vm(&VMType, &VMTotal); if (TRACE) fprintf(stderr, "GridText: VMTotal reduced to %d\n", VMTotal);#endif /* VMS && VAXC && !__DECC */ } line = self->last_line = (HTLine *)calloc(1, LINE_SIZE(MAX_LINE)); if (line == NULL) outofmem(__FILE__, "HText_New"); line->next = line->prev = line; line->offset = line->size = 0;#ifdef USE_COLOR_STYLE line->numstyles = 0;#endif self->Lines = self->chars = 0; self->first_anchor = self->last_anchor = NULL; 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->toolbar = NO; self->tabs = NULL; /* * If we are going to render the List Page, always merge in hidden * links to get the numbering consistent if form fields are numbered * and show up as hidden links in the list of links. - kw */ if (anchor->address && !strcmp(anchor->address, LYlist_temp_url())) self->hiddenlinkflag = HIDDENLINKS_MERGE; else self->hiddenlinkflag = LYHiddenLinks; self->hidden_links = NULL; self->no_cache = ((anchor->no_cache || anchor->post_data) ? YES : NO); self->LastChar = '\0'; self->IgnoreExcess = FALSE; if (HTOutputFormat == WWW_SOURCE) self->source = YES; else self->source = NO; HTAnchor_setDocument(anchor, (HyperDoc *)self); HTFormNumber = 0; /* no forms started yet */ HTMainText = self; HTMainAnchor = anchor; self->display_on_the_fly = 0; self->kcode = NOKANJI; self->state = S_text; self->kanji_buf = '\0'; self->in_sjis = 0; self->have_8bit_chars = NO; HText_getChartransInfo(self); UCSetTransParams(&self->T, self->UCLYhndl, self->UCI, current_char_set, &LYCharSet_UC[current_char_set]); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -