diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/GridText.c | 630 | ||||
-rw-r--r-- | src/GridText.h | 5 | ||||
-rw-r--r-- | src/HTAlert.c | 37 | ||||
-rw-r--r-- | src/HTML.c | 175 | ||||
-rw-r--r-- | src/HTML.h | 3 | ||||
-rw-r--r-- | src/HTNestedList.h | 2 | ||||
-rw-r--r-- | src/LYCharUtils.c | 29 | ||||
-rw-r--r-- | src/LYCurses.c | 13 | ||||
-rw-r--r-- | src/LYForms.c | 2 | ||||
-rw-r--r-- | src/LYGlobalDefs.h | 2 | ||||
-rw-r--r-- | src/LYHistory.c | 6 | ||||
-rw-r--r-- | src/LYKeymap.c | 10 | ||||
-rw-r--r-- | src/LYKeymap.h | 4 | ||||
-rw-r--r-- | src/LYLeaks.c | 348 | ||||
-rw-r--r-- | src/LYLocal.c | 20 | ||||
-rw-r--r-- | src/LYMain.c | 27 | ||||
-rw-r--r-- | src/LYMainLoop.c | 164 | ||||
-rw-r--r-- | src/LYMap.c | 2 | ||||
-rw-r--r-- | src/LYOptions.c | 2 | ||||
-rw-r--r-- | src/LYPrettySrc.c | 112 | ||||
-rw-r--r-- | src/LYPrettySrc.h | 21 | ||||
-rw-r--r-- | src/LYPrint.c | 7 | ||||
-rw-r--r-- | src/LYReadCFG.c | 27 | ||||
-rw-r--r-- | src/LYStrings.c | 154 | ||||
-rw-r--r-- | src/LYStrings.h | 5 | ||||
-rw-r--r-- | src/LYUtils.c | 100 | ||||
-rw-r--r-- | src/TRSTable.c | 229 | ||||
-rw-r--r-- | src/TRSTable.h | 10 | ||||
-rw-r--r-- | src/UCAuto.c | 8 | ||||
-rw-r--r-- | src/UCdomap.c | 2 | ||||
-rw-r--r-- | src/chrtrans/cp1253_uni.tbl | 4 | ||||
-rw-r--r-- | src/chrtrans/cp869_uni.tbl | 4 | ||||
-rw-r--r-- | src/chrtrans/iso07_uni.tbl | 13 | ||||
-rw-r--r-- | src/makefile.dos | 16 | ||||
-rw-r--r-- | src/makefile.in | 5 |
35 files changed, 1725 insertions, 473 deletions
diff --git a/src/GridText.c b/src/GridText.c index 6b89dc21..8aae54af 100644 --- a/src/GridText.c +++ b/src/GridText.c @@ -92,6 +92,7 @@ struct _HTStream { /* only know it as object */ #define TITLE_LINES 1 #define IS_UTF_EXTRA(ch) (text->T.output_utf8 && \ ((unsigned char)(ch)&0xc0) == 0x80) +/* a test in compact form: how many extra UTF-8 chars after initial? - kw */ #define UTF8_XNEGLEN(c) (c&0xC0? 0 :c&32? 1 :c&16? 2 :c&8? 3 :c&4? 4 :c&2? 5:0) #define UTF_XLEN(c) UTF8_XNEGLEN(((char)~(c))) @@ -144,12 +145,22 @@ PUBLIC int LYsb_end = -1; #if defined(USE_COLOR_STYLE) #define MAX_STYLES_ON_LINE 64 +#ifdef OLD_HTSTYLECHANGE typedef 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; +#else + /*try to fit in 2 shorts*/ +typedef struct _stylechange { + unsigned int direction:2; /* on or off */ + unsigned int horizpos: (sizeof(short)*CHAR_BIT-2); + /* horizontal position of this change */ + unsigned short style; /* which style to change to */ +} HTStyleChange; +#endif #endif typedef struct _line { @@ -161,12 +172,134 @@ typedef struct _line { BOOL bullet; /* Do we bullet? */ BOOL expansion_line; /* TEXTAREA edit new line flag */ #if defined(USE_COLOR_STYLE) +#ifdef OLD_HTSTYLECHANGE HTStyleChange styles[MAX_STYLES_ON_LINE]; +#else + HTStyleChange* styles; +#endif int numstyles; #endif char data[1]; /* Space for terminator at least! */ } HTLine; +#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE) +typedef struct _HTStyleChangePool { + HTStyleChange data[4092]; + struct _HTStyleChangePool* next; + int free_items; +} HTStyleChangePool; + +/*these are used when current line is being aggregated. */ +HTStyleChange stylechanges_buffers[2][MAX_STYLES_ON_LINE]; +int stylechanges_buffers_free;/*this is an index of the free buffer. + Can be 0 or 1*/ + +/* These are generic macors for any pools (provided those structures have the +same members as HTStyleChangePool). Pools are used for allocation of groups of +objects of the same type T. Pools are represented as a list of structures of +type P (called pool chunks here). Structure P has an array of N objects of +type T named 'data' (the number N in the array can be chosen arbitrary), +pointer to the next pool chunk named 'pool', and the number of free items in +that pool chunk named 'free_items'. Here is a definition of the structure P: + struct P + { + T data[N]; + struct P* next; + int free_items; + }; + It's recommended that sizeof(P) be memory page size minus 32 in order malloc'd +chunks to fit in machine page size. + Allocation of 'n' items in the pool is implemented by decrementing member +'free_items' by 'n' if 'free_items' >= 'n', or allocating a new pool chunk and +allocating 'n' items in that new chunk. It's the task of the programmer to +assert that 'n' is <= N. Only entire pool may be freed - this limitation makes +allocation algorithms trivial and fast - so the use of pools is limited to +objects that are freed in batch, that are not deallocated not in the batch, and +not reallocated. + Pools greatly reduce memory fragmentation and memory allocation/deallocation +speed due to the simple algorithms used. Due to the fact that memory is +'allocated' in array, alignment overhead is minimal. Allocating strings in a +pool provided their length will never exceed N and is much smaller than N seems +to be very efficient. + + Pool are referenced by pointer to the chunk that contains free slots. Macros +that allocate memory in pools update that pointer if needed. + There are 3 macros that deal with pools - POOL_NEW, POOL_FREE and +ALLOC_IN_POOL. + Here is a description of those macros as C++ functions (with names mentioned +above and with use of C++ references) + +void ALLOC_IN_POOL( P*& pool, pool_type, int toalloc, T*& ptr) + - allocates 'toalloc' items in the pool of type 'pool_type' pointed by + 'pool', sets the pointer 'ptr' to the "allocated" memory and updates 'pool' + if necessary. Sets 'ptr' to NULL if fails. + +void POOL_NEW( pool_type , P*& ptr) + Initializes a pool of type 'pool_type' pointed by 'ptr', updating 'ptr'. + Sets 'ptr' to NULL if fails. + +void POOL_FREE( pool_type , P* ptr) + Frees a pool of type 'pool_type' pointed by ptr. + + - VH */ + +/* +void ALLOC_IN_POOL( P*& pool, pool_type, int toalloc, T*& ptr) + - allocates 'toalloc' items in the pool of type 'pool_type' pointed by + 'pool', sets the pointer 'ptr' to the "allocated" memory and updates 'pool' + if necessary. Sets 'ptr' to NULL if fails. +*/ +#define ALLOC_IN_POOL(pool,pool_type,toalloc,ptr) \ +if (!pool) \ + ptr = NULL; \ +else { \ + if ((pool)->free_items > toalloc) { \ + (pool)->free_items -= toalloc; \ + ptr = (pool)->data + (pool)->free_items; \ + } else { \ + pool_type* newpool = (pool_type*)malloc(sizeof(pool_type)); \ + if (!newpool) { \ + ptr = NULL; \ + } else { \ + newpool->next = pool; \ + newpool->free_items = sizeof newpool->data/ \ + sizeof newpool->data[0] - toalloc; \ + pool = newpool; \ + ptr = newpool->data + sizeof newpool->data/sizeof newpool->data[0] - toalloc; \ + } \ + } \ +} +/* +void POOL_NEW( pool_type , P*& ptr) + Initializes a pool of type 'pool_type' pointed by 'ptr', updating 'ptr'. + Sets 'ptr' to NULL if fails. +*/ +#define POOL_NEW(pool_type,ptr) \ + { \ + pool_type* newpool = (pool_type*)malloc(sizeof(pool_type)); \ + if (!newpool) { \ + ptr = NULL; \ + } else { \ + newpool->next = NULL; \ + newpool->free_items = sizeof newpool->data/sizeof newpool->data[0]; \ + ptr = newpool; \ + } \ + } +/* +void POOL_FREE( pool_type , P* ptr) + Frees a pool of type 'pool_type' pointed by ptr. +*/ +#define POOL_FREE(pool_type,xptr) \ + { \ + pool_type* ptr = xptr; \ + do { \ + pool_type* prevpool = ptr; \ + ptr = ptr->next; \ + FREE(prevpool); \ + } while (ptr); \ + } +#endif + #define LINE_SIZE(l) (sizeof(HTLine)+(l)) /* Allow for terminator */ typedef struct _TextAnchor { @@ -245,6 +378,7 @@ struct _HText { BOOL stale; /* Must refresh */ BOOL page_has_target; /* has target on screen */ BOOL has_utf8; /* has utf-8 on screen or line */ + BOOL had_utf8; /* had utf-8 when last displayed */ #ifdef DISP_PARTIAL int first_lineno_last_disp_partial; int last_lineno_last_disp_partial; @@ -267,6 +401,9 @@ struct _HText { HTStream * target; /* Output stream */ HTStreamClass targetClass; /* Output routines */ +#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE) + HTStyleChangePool* styles_pool; +#endif }; PRIVATE void HText_AddHiddenLink PARAMS((HText *text, TextAnchor *textanchor)); @@ -552,6 +689,22 @@ PUBLIC HText * HText_new ARGS1( CTRACE((tfp, "GridText: VMTotal = %d\n", VMTotal)); #endif /* VMS && VAXC && !__DECC */ + /* + * If the previously shown text had UTF-8 characters on screen, + * remember this in the newly created object. Do this now, before + * the previous object may become invalid. - kw + */ + if (HTMainText) { + if (HText_hasUTF8OutputSet(HTMainText) && + HTLoadedDocumentEightbit() && + LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8) { + self->had_utf8 = HTMainText->has_utf8; + } else { + self->had_utf8 = HTMainText->has_utf8; + } + HTMainText->has_utf8 = NO; + } + if (!loaded_texts) { loaded_texts = HTList_new(); #ifdef LY_FIND_LEAKS @@ -597,6 +750,13 @@ PUBLIC HText * HText_new ARGS1( line->offset = line->size = 0; #ifdef USE_COLOR_STYLE line->numstyles = 0; +#ifndef OLD_HTSTYLECHANGE + POOL_NEW(HTStyleChangePool,self->styles_pool); + if (!self->styles_pool) + outofmem(__FILE__, "HText_New"); + stylechanges_buffers_free = 0; + line->styles = stylechanges_buffers[0]; +#endif #endif self->Lines = self->chars = 0; self->first_anchor = self->last_anchor = NULL; @@ -757,7 +917,9 @@ PUBLIC void HText_free ARGS1( return; HTAnchor_setDocument(self->node_anchor, (HyperDoc *)0); - +#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE) + POOL_FREE(HTStyleChangePool,self->styles_pool); +#endif while (YES) { /* Free off line array */ HTLine * l = self->last_line; if (l) { @@ -967,13 +1129,13 @@ PRIVATE int display_line ARGS4( if (case_sensitive) cp_tgt = LYno_attr_mbcs_strstr(data, target, - text->T.output_utf8, + text->T.output_utf8, YES, &HitOffset, &LenNeeded); else cp_tgt = LYno_attr_mbcs_case_strstr(data, target, - text->T.output_utf8, + text->T.output_utf8, YES, &HitOffset, &LenNeeded); if (cp_tgt) { @@ -1001,13 +1163,13 @@ PRIVATE int display_line ARGS4( if (case_sensitive) cp_tgt = LYno_attr_mbcs_strstr(data, target, - text->T.output_utf8, + text->T.output_utf8, YES, &HitOffset, &LenNeeded); else cp_tgt = LYno_attr_mbcs_case_strstr(data, target, - text->T.output_utf8, + text->T.output_utf8, YES, &HitOffset, &LenNeeded); if (cp_tgt) { @@ -1135,7 +1297,7 @@ PRIVATE int display_line ARGS4( #endif /* SHOW_WHEREIS_TARGETS */ #endif /* USE_COLOR_STYLE */ i++; - if (text->T.output_utf8 && !isascii(buffer[0])) { + if (text->T.output_utf8 && !isascii((unsigned char)buffer[0])) { text->has_utf8 = YES; if ((*buffer & 0xe0) == 0xc0) { utf_extra = 1; @@ -1168,7 +1330,7 @@ PRIVATE int display_line ARGS4( buffer[1] = '\0'; data += utf_extra; utf_extra = 0; - } else if (HTCJK != NOCJK && !isascii(buffer[0])) { + } else if (HTCJK != NOCJK && !isascii((unsigned char)buffer[0])) { /* * For CJK strings, by Masanobu Kimura. */ @@ -1677,7 +1839,14 @@ PRIVATE void display_page ARGS3( if (line) { #if defined(USE_COLOR_STYLE) && defined(SHOW_WHEREIS_TARGETS) char *data; - int offset, HitOffset, LenNeeded; + int offset, LenNeeded; +#endif +#ifdef DISP_PARTIAL + if (display_partial || + line_number != text->first_lineno_last_disp_partial) + text->has_utf8 = NO; +#else + text->has_utf8 = NO; #endif for (i = 0; i < (display_lines); i++) { /* @@ -1722,13 +1891,13 @@ PRIVATE void display_page ARGS3( (case_sensitive ? (cp = LYno_attr_mbcs_strstr(data, target, - text->T.output_utf8, - &HitOffset, + text->T.output_utf8, YES, + NULL, &LenNeeded)) != NULL : (cp = LYno_attr_mbcs_case_strstr(data, target, - text->T.output_utf8, - &HitOffset, + text->T.output_utf8, YES, + NULL, &LenNeeded)) != NULL) && ((int)line->offset + LenNeeded) < LYcols) { int itmp = 0; @@ -1767,7 +1936,7 @@ PRIVATE void display_page ARGS3( /* * Output all the printable target chars. */ - if (text->T.output_utf8 && !isascii(tmp[0])) { + if (text->T.output_utf8 && !isascii((unsigned char)tmp[0])) { if ((*tmp & 0xe0) == 0xc0) { utf_extra = 1; } else if ((*tmp & 0xf0) == 0xe0) { @@ -1799,7 +1968,7 @@ PRIVATE void display_page ARGS3( tmp[1] = '\0'; written += (utf_extra + 1); utf_extra = 0; - } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + } else if (HTCJK != NOCJK && !isascii((unsigned char)tmp[0])) { /* * For CJK strings, by Masanobu Kimura. */ @@ -2072,11 +2241,12 @@ PRIVATE void display_page ARGS3( } #endif /* DISP_PARTIAL */ - if (text->has_utf8) { + if (text->has_utf8 || text->had_utf8) { /* * For other than ncurses, repainting is taken care of * by touching lines in display_line and highlight. - kw 1999-10-07 */ + text->had_utf8 = text->has_utf8; clearok(curscr, TRUE); } else if (HTCJK != NOCJK) { /* @@ -2087,7 +2257,6 @@ PRIVATE void display_page ARGS3( /*clearok(curscr, TRUE);*/ } refresh(); - } @@ -2107,13 +2276,18 @@ PUBLIC void HText_beginAppend ARGS1( /* LYcols_cu is the notion that the display library has of the screen width. Normally it is the same as LYcols, but there may be a - difference via SLANG_MBCS_HACK. LYcols_cu is used to try to prevent - that the display library wraps or truncates a line with UTF-8 chars - when it shouldn't. - kw */ + difference via SLANG_MBCS_HACK. Checks of the line length (as the + non-UTF-8-aware display library would see it) against LYcols_cu are + is used to try to prevent that lines with UTF-8 chars get wrapped + by the library when they shouldn't. + If there is no display library involved, i.e. dump_output_immediately, + no such limit should be imposed. LYcols*6 should be just as good + as any other large value. (But don't use INT_MAX or something close + to it to, avoid over/underflow.) - kw */ #ifdef USE_SLANG -#define LYcols_cu SLtt_Screen_Cols +#define LYcols_cu (dump_output_immediately ? LYcols*6 : SLtt_Screen_Cols) #else -#define LYcols_cu LYcols +#define LYcols_cu (dump_output_immediately ? LYcols*6 : LYcols) #endif /* Add a new line of text @@ -2147,6 +2321,7 @@ PRIVATE void split_line ARGS2( #endif int indent = text->in_line_1 ? text->style->indent1st : text->style->leftIndent; + short alignment; TextAnchor * a; int CurLine = text->Lines; int HeadTrim = 0; @@ -2166,7 +2341,9 @@ PRIVATE void split_line ARGS2( HTLine * line = (HTLine *)LY_CALLOC(1, LINE_SIZE(MAX_LINE)+2); if (line == NULL) outofmem(__FILE__, "split_line_1"); - +#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE) + line->styles = stylechanges_buffers[stylechanges_buffers_free = (stylechanges_buffers_free + 1) &1]; +#endif ctrl_chars_on_this_line = 0; /*reset since we are going to a new line*/ utfxtra_on_this_line = 0; /*reset too, we'll count them*/ text->LastChar = ' '; @@ -2219,6 +2396,7 @@ PRIVATE void split_line ARGS2( ctrl_chars_on_this_line++; } + alignment = style->alignment; /* * Split at required point */ @@ -2251,9 +2429,9 @@ PRIVATE void split_line ARGS2( (HeadTrim || text->first_anchor || underline_on || bold_on || - text->style->alignment != HT_LEFT || - text->style->wordWrap || text->style->freeFormat || - text->style->spaceBefore || text->style->spaceAfter)) || + alignment != HT_LEFT || + style->wordWrap || style->freeFormat || + style->spaceBefore || style->spaceAfter)) || *p == LY_SOFT_HYPHEN) { p++; HeadTrim++; @@ -2383,9 +2561,9 @@ PRIVATE void split_line ARGS2( #endif (ctrl_chars_on_this_line || HeadTrim || text->first_anchor || underline_on || bold_on || - text->style->alignment != HT_LEFT || - text->style->wordWrap || text->style->freeFormat || - text->style->spaceBefore || text->style->spaceAfter)) { + alignment != HT_LEFT || + style->wordWrap || style->freeFormat || + style->spaceBefore || style->spaceAfter)) { /* * Strip trailers. */ @@ -2562,6 +2740,12 @@ PRIVATE void split_line ARGS2( if (temp == NULL) outofmem(__FILE__, "split_line_2"); memcpy(temp, previous, LINE_SIZE(previous->size)); +#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE) + ALLOC_IN_POOL((text->styles_pool),HTStyleChangePool,previous->numstyles,temp->styles); + memcpy(temp->styles, previous->styles, sizeof(HTStyleChange)*previous->numstyles); + if (!temp->styles) + outofmem(__FILE__, "split_line_2"); +#endif FREE(previous); previous = temp; @@ -2581,8 +2765,8 @@ PRIVATE void split_line ARGS2( #ifdef EXP_JUSTIFY_ELTS this_line_was_splitted || #endif - (style->alignment == HT_CENTER || - style->alignment == HT_RIGHT) || text->stbl) { + (alignment == HT_CENTER || + alignment == HT_RIGHT) || text->stbl) { /* Calculate spare character positions if needed */ for (cp = previous->data; *cp; cp++) { if (*cp == LY_UNDERLINE_START_CHAR || @@ -2600,7 +2784,9 @@ PRIVATE void split_line ARGS2( spare = (LYcols-1) - (int)style->rightIndent - indent + ctrl_chars_on_previous_line - previous->size; - if (spare > 0 && text->T.output_utf8 && ctrl_chars_on_previous_line) { + + if (spare > 0 && !dump_output_immediately && + text->T.output_utf8 && ctrl_chars_on_previous_line) { utfxtra_on_previous_line -= utfxtra_on_this_line; if (utfxtra_on_previous_line) { int spare_cu = (LYcols_cu-1) - @@ -2611,13 +2797,30 @@ PRIVATE void split_line ARGS2( * mishandled by the display library towards the left * if this would make them fit. The resulting display * will not be as intended, but this is better than - * having them split by curses. (But that may still - * happen anyway by curses space movement optimization). + * having them split by curses. (Curses cursor movement + * optimization may still cause wrong positioning within + * the line, in particular after a sequence of spaces). * - kw */ if (spare_cu < spare) { if (spare_cu >= 0) { - spare = spare_cu; + if (alignment == HT_CENTER && + (int)(previous->offset + indent + spare/2 + + previous->size) + - ctrl_chars_on_previous_line + + utfxtra_on_previous_line <= (LYcols_cu - 1)) + /* do nothing - it still fits - kw */; + else { + spare = spare_cu; + if (alignment == HT_CENTER) { + /* + * Can't move towars center all the way, + * but at least make line contents appear + * as far right as possible. - kw + */ + alignment = HT_RIGHT; + } + } } else if (indent + (int)previous->offset + spare_cu >= 0) { /* subtract overdraft from effective indentation */ indent += (int)previous->offset + spare_cu; @@ -2636,7 +2839,10 @@ PRIVATE void split_line ARGS2( * its row should really end here, or on one of the following * lines with no more characters added after the break. * We don't know whether a cell has been started, so ignore - * errors here. - kw + * errors here. + * This call is down here because we need the + * ctrl_chars_on_previous_line, which have just been re- + * counted above. - kw */ Stbl_lineBreak(text->stbl, text->Lines - 1, @@ -2848,7 +3054,7 @@ PRIVATE void split_line ARGS2( *jp = ' '; /* substitute it */ continue; } - if (text->T.output_utf8 && !isascii(c)) { + if (text->T.output_utf8 && !isascii((unsigned char)c)) { int utf_extra = 0; if ((c & 0xe0) == 0xc0) { utf_extra = 1; @@ -2877,7 +3083,9 @@ PRIVATE void split_line ARGS2( jline = (HTLine *)LY_CALLOC(1, LINE_SIZE(previous->size+spare)); if (jline == NULL) outofmem(__FILE__, "split_line_1"); - +#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE) + jline->styles = previous->styles; +#endif jdata = jline->data; /* @@ -2943,8 +3151,9 @@ PRIVATE void split_line ARGS2( jline->styles[i].style = previous->styles[i].style; jline->styles[i].direction = previous->styles[i].direction; +#ifdef OLD_HTSTYLECHANGE jline->styles[i].previous = previous->styles[i].previous; - +#endif /*there are stylechanges with hpos > line length */ jline->styles[i].horizpos = (hpos > previous->size) ? previous->size + spare @@ -3539,10 +3748,15 @@ PUBLIC void HText_appendCharacter ARGS2( } if (text->T.output_utf8) { + /* + * Some extra checks for UTF-8 output here to make sure + * memory is not overrun. For a non-first char, append + * to the line here and return. - kw + */ if (IS_UTF_EXTRA(ch)) { if ((line->size > (MAX_LINE-1)) || (indent + (int)(line->offset + line->size) + - utfx - ctrl_chars_on_this_line + + utfxtra_on_this_line - ctrl_chars_on_this_line + ((line->size > 0) && (int)(line->data[line->size-1] == LY_SOFT_HYPHEN ? @@ -3570,11 +3784,11 @@ PUBLIC void HText_appendCharacter ARGS2( utfxtra_on_this_line++; ctrl_chars_on_this_line++; return; - } else if (ch & 0x80) { + } else if (ch & 0x80) { /* a first char of UTF-8 sequence - kw */ if ((line->size > (MAX_LINE-7)) -#if 0 /* the equivalent should already happen below */ +#if 0 /* the equivalent check should already happen below */ || (indent + (int)(line->offset + line->size) + - utfx - ctrl_chars_on_this_line + + utfxtra_on_this_line - ctrl_chars_on_this_line + ((line->size > 0) && (int)(line->data[line->size-1] == LY_SOFT_HYPHEN ? @@ -3722,7 +3936,7 @@ PUBLIC void HText_appendCharacter ARGS2( } return; } /* if tab */ - else if (text->source && text == HTMainText) { + else if ( (text->source || dont_wrap_pre) && text == HTMainText) { /* * If we're displaying document source, wrap long lines to keep all of * the source visible. @@ -4440,6 +4654,7 @@ PUBLIC void HText_cancelStbl ARGS1( Stbl_free(me->stbl); me->stbl = NULL; } + /* Start simple table handling */ PUBLIC void HText_startStblTABLE ARGS2( @@ -4458,6 +4673,7 @@ PUBLIC void HText_startStblTABLE ARGS2( CTRACE((tfp, "startStblTABLE: failed.\n")); } } + /* Finish simple table handling */ PUBLIC void HText_endStblTABLE ARGS1( @@ -4478,6 +4694,7 @@ PUBLIC void HText_endStblTABLE ARGS1( Stbl_free(me->stbl); me->stbl = NULL; } + /* Start simple table row */ PUBLIC void HText_startStblTR ARGS2( @@ -4489,6 +4706,7 @@ PUBLIC void HText_startStblTR ARGS2( if (Stbl_addRowToTable(me->stbl, alignment, me->Lines) < 0) HText_cancelStbl(me); /* give up */ } + /* Finish simple table row */ PUBLIC void HText_endStblTR ARGS1( @@ -4498,11 +4716,13 @@ PUBLIC void HText_endStblTR ARGS1( return; /* should this do something?? */ } -/* Finish simple table cell + +/* Start simple table cell */ -PUBLIC void HText_startStblTD ARGS4( +PUBLIC void HText_startStblTD ARGS5( HText *, me, int, colspan, + int, rowspan, short, alignment, BOOL, isheader) { @@ -4510,10 +4730,11 @@ PUBLIC void HText_startStblTD ARGS4( return; if (colspan <= 0) colspan = 1; - if (Stbl_addCellToTable(me->stbl, colspan, alignment, isheader, + if (Stbl_addCellToTable(me->stbl, colspan, rowspan, alignment, isheader, me->Lines, HText_LastLineSize(me,FALSE)) < 0) HText_cancelStbl(me); /* give up */ } + /* Finish simple table cell */ PUBLIC void HText_endStblTD ARGS1( @@ -4526,6 +4747,45 @@ PUBLIC void HText_endStblTD ARGS1( HText_cancelStbl(me); /* give up */ } +/* Remember COL info / Start a COLGROUP and remember info +*/ +PUBLIC void HText_startStblCOL ARGS4( + HText *, me, + int, span, + short, alignment, + BOOL, isgroup) +{ + if (!me || !me->stbl) + return; + if (span <= 0) + span = 1; + if (Stbl_addColInfo(me->stbl, span, alignment, isgroup) < 0) + HText_cancelStbl(me); /* give up */ +} + +/* Finish a COLGROUP +*/ +PUBLIC void HText_endStblCOLGROUP ARGS1( + HText *, me) +{ + if (!me || !me->stbl) + return; + if (Stbl_finishColGroup(me->stbl) < 0) + HText_cancelStbl(me); /* give up */ +} + +/* Start a THEAD / TFOOT / TBODY - remember its alignment info +*/ +PUBLIC void HText_startStblRowGroup ARGS2( + HText *, me, + short, alignment) +{ + if (!me || !me->stbl) + return; + if (Stbl_addRowGroup(me->stbl, alignment) < 0) + HText_cancelStbl(me); /* give up */ +} + /* Anchor handling ** --------------- */ @@ -6091,12 +6351,12 @@ PUBLIC BOOL HText_getFirstTargetInLine ARGS7( if ((case_sensitive ? (cp = LYno_attr_mbcs_strstr(LineData, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL : (cp = LYno_attr_mbcs_case_strstr(LineData, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL) && (LineOffset + LenNeeded) < LYcols) { @@ -6560,9 +6820,6 @@ PUBLIC BOOL HText_select ARGS1( HText *, text) { if (text != HTMainText) { - HTMainText = text; - HTMainAnchor = text->node_anchor; - /* * Reset flag for whereis search string - cannot be true here * since text is not our HTMainText. - kw @@ -6580,6 +6837,21 @@ PUBLIC BOOL HText_select ARGS1( } #endif /* DISP_PARTIAL */ + if (HTMainText) { + if (HText_hasUTF8OutputSet(HTMainText) && + HTLoadedDocumentEightbit() && + LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8) { + text->had_utf8 = HTMainText->has_utf8; + } else { + text->had_utf8 = NO; + } + HTMainText->has_utf8 = NO; + text->has_utf8 = NO; + } + + HTMainText = text; + HTMainAnchor = text->node_anchor; + /* * Make this text the most current in the loaded texts list. - FM */ @@ -7094,17 +7366,18 @@ PUBLIC void print_wwwfile_to_fd ARGS2( line = HTMainText->last_line->next; for (;; line = line->next) { if (!first - && line->data[0] != LY_SOFT_NEWLINE) + && line->data[0] != LY_SOFT_NEWLINE && line->data[1] != LY_SOFT_NEWLINE) { + /* data[0] can be LY_*START_CHAR, so LY_SOFT_NEWLINE can be in [1] - VH */ fputc('\n',fp); - first = FALSE; - - /* - * Add news-style quotation if requested. - FM - */ - if (is_reply) { - fputc('>',fp); + /* + * Add news-style quotation if requested. - FM + */ + if (is_reply) { + fputc('>',fp); + } } + first = FALSE; /* * Add offset. */ @@ -7218,7 +7491,8 @@ PUBLIC void print_crawl_to_fd ARGS3( for (;; line = line->next) { if (!first - && line->data[0] != LY_SOFT_NEWLINE) + && line->data[0] != LY_SOFT_NEWLINE && line->data[1] != LY_SOFT_NEWLINE) + /* data[0] can be LY_*START_CHAR, so LY_SOFT_NEWLINE can be in [1] - VH */ fputc('\n',fp); first = FALSE; /* @@ -7611,7 +7885,7 @@ PUBLIC void user_message ARGS2( return; } - HTSprintf(&temp, message, (argument == 0) ? "" : argument); + HTSprintf0(&temp, message, (argument == 0) ? "" : argument); statusline(temp); @@ -9492,6 +9766,7 @@ PUBLIC int HText_SubmitForm ARGS4( BOOLEAN SemiColon = FALSE; char *Boundary = NULL; char *MultipartContentType = NULL; + char *content_type_out = NULL; int target_cs = -1; CONST char *out_csname; CONST char *target_csname = NULL; @@ -9731,20 +10006,21 @@ PUBLIC int HText_SubmitForm ARGS4( } else { /* * We are submitting POST content to a server, - * so load the post_content_type element. - FM + * so load content_type_out. This will be put in + * the post_content_type element if all goes well. - FM, kw */ if (SemiColon == TRUE) { - StrAllocCopy(doc->post_content_type, + StrAllocCopy(content_type_out, "application/sgml-form-urlencoded"); } else if (PlainText == TRUE) { - StrAllocCopy(doc->post_content_type, + StrAllocCopy(content_type_out, "text/plain"); } else if (Boundary != NULL) { - StrAllocCopy(doc->post_content_type, + StrAllocCopy(content_type_out, "multipart/form-data; boundary="); - StrAllocCat(doc->post_content_type, Boundary); + StrAllocCat(content_type_out, Boundary); } else { - StrAllocCopy(doc->post_content_type, + StrAllocCopy(content_type_out, "application/x-www-form-urlencoded"); } @@ -9775,8 +10051,8 @@ PUBLIC int HText_SubmitForm ARGS4( strcmp(target_csname, "iso-8859-1"))) || (!HTMainText->node_anchor->charset && target_cs != UCLYhndl_for_unspec)) { - StrAllocCat(doc->post_content_type, "; charset="); - StrAllocCat(doc->post_content_type, target_csname); + StrAllocCat(content_type_out, "; charset="); + StrAllocCat(content_type_out, target_csname); } } } else { @@ -10097,7 +10373,7 @@ PUBLIC int HText_SubmitForm ARGS4( if ((fd = fopen(val_used, "rb")) == 0) { /* We can't open the file, what do we do? */ HTAlert("Can't open file for uploading"); - return 0; + goto exit_disgracefully; } StrAllocCopy(escaped2, ""); while ((bytes = fread(buffer, sizeof(char), 45, fd)) != 0) { @@ -10109,12 +10385,12 @@ PUBLIC int HText_SubmitForm ARGS4( /* We got an error reading the file, what do we do? */ HTAlert("Short read from file, problem?"); fclose(fd); - return 0; + goto exit_disgracefully; } fclose(fd); - /* we need to modify the mime-type here */ - /* could use LYGetFileInfo for that and for other - headers that should be transmitted - kw */ + /* we need to modify the mime-type here - rp */ + /* Note: could use LYGetFileInfo for that and for + other headers that should be transmitted - kw */ HTSprintf(&query, "%s%s%s%s%s", @@ -10486,9 +10762,9 @@ PUBLIC int HText_SubmitForm ARGS4( (HText_getTitle() ? HText_getTitle() : "")), query, - doc->post_content_type); + content_type_out); FREE(query); - FREE(doc->post_content_type); + FREE(content_type_out); return 0; } else { _statusline(SUBMITTING_FORM); @@ -10496,6 +10772,8 @@ PUBLIC int HText_SubmitForm ARGS4( if (submit_item->submit_method == URL_POST_METHOD || Boundary) { StrAllocCopy(doc->post_data, query); + FREE(doc->post_content_type); + doc->post_content_type = content_type_out; /* don't free c_t_out */ CTRACE((tfp,"GridText - post_data: %s\n",doc->post_data)); StrAllocCopy(doc->address, submit_item->submit_action); FREE(query); @@ -10504,9 +10782,22 @@ PUBLIC int HText_SubmitForm ARGS4( StrAllocCopy(doc->address, query); FREE(doc->post_data); FREE(doc->post_content_type); + FREE(content_type_out); FREE(query); return 1; } +#ifdef EXP_FILE_UPLOAD +exit_disgracefully: + FREE(escaped1); + FREE(escaped2); + FREE(previous_blanks); + FREE(copied_name_used); + FREE(copied_val_used); + FREE(MultipartContentType); + FREE(query); + FREE(content_type_out); + return 0; +#endif } PUBLIC void HText_DisableCurrentForm NOARGS @@ -11640,6 +11931,7 @@ PUBLIC int HText_ExtEditForm ARGS1( TextAnchor *start_anchor = NULL; TextAnchor *end_anchor = NULL; BOOLEAN firstanchor = TRUE; + BOOLEAN wrapalert = FALSE; char ed_offset[10]; int start_line = 0; @@ -11661,7 +11953,10 @@ PUBLIC int HText_ExtEditForm ARGS1( char *cp; int match_tag = 0; int newlines = 0; - int len; + int len, len0, len_in; + int wanted_fieldlen_wrap = -1; /* not yet asked; 0 means don't. */ + char *skip_at = NULL; + int skip_num = 0, i; CTRACE((tfp, "GridText: entered HText_ExtEditForm()\n")); @@ -11780,15 +12075,27 @@ PUBLIC int HText_ExtEditForm ARGS1( ((size = stat_info.st_size) == 0)) { size = 0; ebuf = (char *) calloc (1, 1); + if (!ebuf) + outofmem(__FILE__, "HText_ExtEditForm"); } else { ebuf = (char *) calloc (size + 1, (sizeof(char))); + if (!ebuf) { + /* + * This could be huge - don't exit if we don't have enough + * memory for it. With some luck, the user may be even able + * to recover the file manually from the temp space while + * the lynx session is not over. - kw + */ + free(ed_temp); + HTAlwaysAlert(NULL, MEMORY_EXHAUSTED_FILE); + return 0; + } fp = fopen (ed_temp, "r"); size = fread (ebuf, 1, size, fp); fclose (fp); + ebuf[size] = '\0'; /* Terminate! - kw */ } - if (ebuf == 0) - outofmem(__FILE__, "HText_ExtEditForm"); /* * Nuke any blank lines from the end of the edited data. @@ -11805,24 +12112,111 @@ PUBLIC int HText_ExtEditForm ARGS1( outofmem(__FILE__, "HText_ExtEditForm"); anchor_ptr = start_anchor; + if (anchor_ptr->input_field->size <= 4 || + anchor_ptr->input_field->size >= MAX_LINE) + wanted_fieldlen_wrap = 0; - len = 0; + len = len_in = 0; lp = ebuf; while ((line_cnt <= orig_cnt) || (*lp) || ((len != 0) && (*lp == '\0'))) { + if (skip_at) { + len0 = skip_at - lp; + strncpy(line, lp, len0); + line[len0] = '\0'; + lp = skip_at + skip_num; + skip_at = NULL; + skip_num = 0; + } else { + len0 = 0; + } + line[len0] = '\0'; + if ((cp = strchr (lp, '\n')) != 0) - len = cp - lp; + len = len_in = cp - lp; else - len = strlen (lp); + len = len_in = strlen (lp); + + + if (wanted_fieldlen_wrap < 0 && !wrapalert && + len0+len >= anchor_ptr->input_field->size && + (cp = strchr(lp, ' ')) != NULL && + (cp-lp) < anchor_ptr->input_field->size - 1) { + LYFixCursesOn("ask for confirmation:"); + erase(); /* don't show previous state */ + if (HTConfirmDefault(gettext("Wrap lines to fit displayed area?"), + NO)) { + wanted_fieldlen_wrap = anchor_ptr->input_field->size - 1; + } else { + wanted_fieldlen_wrap = 0; + } + } + if (wanted_fieldlen_wrap > 0 && len0+len > wanted_fieldlen_wrap) { + for (i = wanted_fieldlen_wrap-len0; + i+len0 >= wanted_fieldlen_wrap/4; i--) { + if (isspace((unsigned char)lp[i])) { + len = i + 1; + cp = lp + i; + if (cp[1] != '\n' && + isspace((unsigned char)cp[1]) && + !isspace((unsigned char)cp[2])) { + len++; + cp++; + } + if (!isspace((unsigned char)cp[1])) { + while (*cp && *cp != '\r' && *cp != '\n' && + (cp - lp) <= len + (3 * wanted_fieldlen_wrap/4)) + cp++; /* search for next line break */ + if (*cp == '\r' && cp[1] == '\n') + cp++; + if (*cp == '\n' && + (cp[1] == '\r' || cp[1] == '\n' || + !isspace((unsigned char)cp[1]))) { + *cp = ' '; + while (isspace((unsigned char)*(cp-1))) { + skip_num++; + cp--; + } + skip_at = cp; + } + } + break; + } + } + } + if (wanted_fieldlen_wrap > 0 && len0+len > wanted_fieldlen_wrap) { + i = len-1; + while (len0+i+1 > wanted_fieldlen_wrap && + isspace((unsigned char)lp[i])) + i--; + if (len0+i+1 > wanted_fieldlen_wrap) + len = wanted_fieldlen_wrap - len0; + } - if (len >= MAX_LINE - 1) - len = MAX_LINE - 1; + if (len0+len >= MAX_LINE) { + if (!wrapalert) { + LYFixCursesOn("show alert:"); + HTAlert(gettext("Very long lines have been wrapped!")); + wrapalert = TRUE; + } + /* + * First try to find a space character for wrapping - kw + */ + for (i = MAX_LINE - len0 - 1; i > 0; i--) { + if (isspace((unsigned char)lp[i])) { + len = i; + break; + } + } + if (len0+len >= MAX_LINE) + len = MAX_LINE - len0 - 1; + } - strncpy (line, lp, len); - *(line + len) = '\0'; + strncat (line, lp, len); + *(line + len0+len) = '\0'; - cleanup_line_for_textarea (line, len); + cleanup_line_for_textarea (line, len0+len); /* * If there are more lines in the edit buffer than were in the @@ -11844,7 +12238,7 @@ PUBLIC int HText_ExtEditForm ARGS1( * Keep track of 1st blank line in any trailing blank lines, for * later cursor repositioning. */ - if (len > 0) + if (len0+len > 0) exit_line = 0; else if (exit_line == 0) exit_line = anchor_ptr->line_num; @@ -11853,7 +12247,7 @@ PUBLIC int HText_ExtEditForm ARGS1( * And do the next line of edited text, for the next anchor ... */ lp += len; - if (*lp) lp++; + if (*lp && isspace((unsigned char)*lp)) lp++; end_anchor = anchor_ptr; anchor_ptr = anchor_ptr->next; @@ -12013,6 +12407,7 @@ PUBLIC int HText_InsertFile ARGS1( TextAnchor *prev_anchor = NULL; TextAnchor *end_anchor = NULL; BOOLEAN firstanchor = TRUE; + BOOLEAN truncalert = FALSE; FormInfo *form = form_link->form; char *areaname = form->name; @@ -12096,6 +12491,7 @@ PUBLIC int HText_InsertFile ARGS1( size = fread (fbuf, 1, size, fp); fclose (fp); FREE(fn); + fbuf[size] = '\0'; /* Terminate! - kw */ } @@ -12248,6 +12644,15 @@ PUBLIC int HText_InsertFile ARGS1( else len = strlen (lp); + if (len >= MAX_LINE) { + if (!truncalert) { + HTAlert(gettext("Very long lines have been truncated!")); + truncalert = TRUE; + } + len = MAX_LINE - 1; + if (lp[len]) + lp[len+1] = '\0'; /* prevent next iteration */ + } strncpy (line, lp, len); *(line + len) = '\0'; @@ -12422,7 +12827,7 @@ PRIVATE void redraw_part_of_line ARGS4( default: i++; - if (text->T.output_utf8 && !isascii(buffer[0])) { + if (text->T.output_utf8 && !isascii((unsigned char)buffer[0])) { if ((*buffer & 0xe0) == 0xc0) { utf_extra = 1; } else if ((*buffer & 0xf0) == 0xe0) { @@ -12454,7 +12859,7 @@ PRIVATE void redraw_part_of_line ARGS4( buffer[1] = '\0'; data += utf_extra; utf_extra = 0; - } else if (HTCJK != NOCJK && !isascii(buffer[0])) { + } else if (HTCJK != NOCJK && !isascii((unsigned char)buffer[0])) { /* * For CJK strings, by Masanobu Kimura. */ @@ -12574,7 +12979,7 @@ PRIVATE void move_to_glyph ARGS10( if (i > (int)LYcols - 1) i = (int)LYcols - 1; - linkvlen = hightext ? LYmbcsstrlen(hightext, utf_flag) : 0; + linkvlen = hightext ? LYmbcsstrlen(hightext, utf_flag, YES) : 0; /* * Scan through the data, making sure that we do not @@ -12593,13 +12998,13 @@ PRIVATE void move_to_glyph ARGS10( if (case_sensitive) cp_tgt = LYno_attr_mbcs_strstr(sdata, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded); else cp_tgt = LYno_attr_mbcs_case_strstr(sdata, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded); if (cp_tgt) { @@ -12629,9 +13034,9 @@ PRIVATE void move_to_glyph ARGS10( if (data && hightext && i >= XP && !incurlink) { /* - * We reached the position of link itself, and highlight is + * We reached the position of link itself, and hightext is * non-NULL. We switch data from being a pointer into the HTLine - * to be a pointer into hightext. Normally (as long as this + * to being a pointer into hightext. Normally (as long as this * routine is applied to normal hyperlink anchors) the text in * hightext will be identical to that part of the HTLine that * data was already pointing to, except that special attribute @@ -12648,7 +13053,7 @@ PRIVATE void move_to_glyph ARGS10( data = hightext; len = strlen(hightext); end_of_data = hightext + len; - XP += linkvlen; + XP += linkvlen; /* from now on XP includes hightext chars */ incurlink = YES; if (cp_tgt) { if (flag && i_after_tgt >= XP) @@ -12725,13 +13130,13 @@ PRIVATE void move_to_glyph ARGS10( else if (case_sensitive) cp_tgt = LYno_attr_mbcs_strstr(sdata, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded); else cp_tgt = LYno_attr_mbcs_case_strstr(sdata, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded); if (cp_tgt) { @@ -12852,10 +13257,21 @@ PRIVATE void move_to_glyph ARGS10( * drawing needs to be turned on now. - kw */ #if defined(SHOW_WHEREIS_TARGETS) - if (incurlink) { - if (intarget && flag && i == XP - 1 && - i_after_tgt > i) + if (incurlink && intarget && flag && i_after_tgt > i) { + if (i == XP - 1) { + i_after_tgt = i; + } else if (i == XP - 2 && HTCJK != NOCJK && + !isascii((unsigned char)buffer[0])) { i_after_tgt = i; + cp_tgt = NULL; + if (drawing) { + if (drawingtarget) { + LYstopTargetEmphasis(); + drawingtarget = NO; + lynx_start_link_color (flag, inU); + } + } + } } if (cp_tgt && i >= i_start_tgt && sdata > cp_tgt) { if (!intarget || @@ -12952,7 +13368,7 @@ PRIVATE void move_to_glyph ARGS10( buffer[1] = '\0'; sdata += utf_extra; data += utf_extra; utf_extra = 0; - } else if (HTCJK != NOCJK && !isascii(buffer[0])) { + } else if (HTCJK != NOCJK && !isascii((unsigned char)buffer[0])) { /* * For CJK strings, by Masanobu Kimura. */ @@ -13006,10 +13422,12 @@ PRIVATE void move_to_glyph ARGS10( if (hadutf8) { #ifdef USE_SLANG SLsmg_touch_lines(YP, 1); -#elif defined(NCURSES_VERSION) - touchline(stdscr, YP, 1); #else - touchwin(stdscr); +#if defined(NCURSES_VERSION) + wredrawln(stdscr, YP, 1); +#else + touchline(stdscr, YP, 1); /* or something else? */ +#endif #endif } } diff --git a/src/GridText.h b/src/GridText.h index 190d97fa..1f82ec73 100644 --- a/src/GridText.h +++ b/src/GridText.h @@ -202,8 +202,11 @@ extern void HText_startStblTABLE PARAMS((HText *, short)); extern void HText_endStblTABLE PARAMS((HText *)); extern void HText_startStblTR PARAMS((HText *, short)); extern void HText_endStblTR PARAMS((HText *)); -extern void HText_startStblTD PARAMS((HText *, int, short, BOOL)); +extern void HText_startStblTD PARAMS((HText *, int, int, short, BOOL)); extern void HText_endStblTD PARAMS((HText *)); +extern void HText_startStblCOL PARAMS((HText *, int, short, BOOL)); +extern void HText_endStblCOLGROUP PARAMS((HText *)); +extern void HText_startStblRowGroup PARAMS((HText *, short)); /* forms stuff */ extern void HText_beginForm PARAMS(( diff --git a/src/HTAlert.c b/src/HTAlert.c index 5a86f666..99d8ad43 100644 --- a/src/HTAlert.c +++ b/src/HTAlert.c @@ -440,6 +440,32 @@ PUBLIC BOOL HTLastConfirmCancelled NOARGS */ PUBLIC int HTConfirmDefault ARGS2(CONST char *, Msg, int, Dft) { +/* Meta-note: don't move the following note from its place right + in front of the first gettext(). As it is now, it should + automatically appear in generated lynx.pot files. - kw + */ + +/* NOTE TO TRANSLATORS: If you provide a translation for "yes", lynx + * will take the first byte of the translation as a positive response + * to Yes/No questions. If you provide a translation for "no", lynx + * will take the first byte of the translation as a negative response + * to Yes/No questions. For both, lynx will also try to show the + * first byte in the prompt as a character, instead of (y) or (n), + * respectively. This will not work right for multibyte charsets! + * Don't translate "yes" and "no" for CJK character sets (or translate + * them to "yes" and "no"). For a translation using UTF-8, don't + * translate if the translation would begin with anything but a 7-bit + * (US_ASCII) character. That also means do not translate if the + * translation would begin with anything but a 7-bit character, if + * you use a single-byte character encoding (a charset like ISO-8859-n) + * but anticipate that the message catalog may be used re-encoded in + * UTF-8 form. + * For translations using other character sets, you may also wish to + * leave "yes" and "no" untranslated, if using (y) and (n) is the + * preferred behavior. + * Lynx will also accept y Y n N as responses unless there is a conflict + * with the first letter of the "yes" or "no" translation. + */ char *msg_yes = gettext("yes"); char *msg_no = gettext("no"); int result = -1; @@ -455,6 +481,13 @@ PUBLIC int HTConfirmDefault ARGS2(CONST char *, Msg, int, Dft) result = NO; } else { char *msg = NULL; + char fallback_y = 'y'; /* English letter response as fallback */ + char fallback_n = 'n'; /* English letter response as fallback */ + + if (fallback_y == *msg_yes || fallback_y == *msg_no) + fallback_y = '\0'; /* conflict or duplication, don't use */ + if (fallback_n == *msg_yes || fallback_n == *msg_no) + fallback_n = '\0'; /* conflict or duplication, don't use */ if (Dft == DFT_CONFIRM) HTSprintf0(&msg, "%s (%c/%c) ", Msg, *msg_yes, *msg_no); @@ -481,6 +514,10 @@ PUBLIC int HTConfirmDefault ARGS2(CONST char *, Msg, int, Dft) result = YES; } else if (TOUPPER(c) == TOUPPER(*msg_no)) { result = NO; + } else if (fallback_y && TOLOWER(c) == fallback_y) { + result = YES; + } else if (fallback_n && TOLOWER(c) == fallback_n) { + result = NO; } else if (Dft != DFT_CONFIRM) { result = Dft; break; diff --git a/src/HTML.c b/src/HTML.c index 464a05b1..f9374c96 100644 --- a/src/HTML.c +++ b/src/HTML.c @@ -109,7 +109,7 @@ PRIVATE HTStyleSheet * styleSheet = NULL; /* Application-wide */ /* Module-wide style cache */ -PRIVATE HTStyle *styles[HTML_ELEMENTS+HTML_EXTRA_ELEMENTS]; +PRIVATE HTStyle *styles[HTML_ELEMENTS+LYNX_HTML_EXTRA_ELEMENTS]; /* adding 24 nested list styles */ /* and 3 header alignment styles */ /* and 3 div alignment styles */ @@ -682,7 +682,7 @@ PUBLIC void HTML_write ARGS3(HTStructured *, me, CONST char*, s, int, l) string (resolution of relative URLs etc.). This variable only used locally here, don't confuse with LYinternal_flag which is for overriding non-caching similar to LYoverride_no_cache. - kw */ -#define CHECK_FOR_INTERN(s) intern_flag = (s && (*s=='#' || *s=='\0')) ? TRUE : FALSE; +#define CHECK_FOR_INTERN(flag,s) flag = (s && (*s=='#' || *s=='\0')) ? TRUE : FALSE /* Last argument to pass to HTAnchor_findChildAndLink() calls, just an abbreviation. - kw */ @@ -690,7 +690,7 @@ PUBLIC void HTML_write ARGS3(HTStructured *, me, CONST char*, s, int, l) #else /* !DONT_TRACK_INTERNAL_LINKS */ -#define CHECK_FOR_INTERN(s) /* do nothing */ ; +#define CHECK_FOR_INTERN(flag,s) /* do nothing */ ; #define INTERN_LT (HTLinkType *)NULL #endif /* DONT_TRACK_INTERNAL_LINKS */ @@ -712,11 +712,11 @@ static int hcode; PRIVATE void HTMLSRC_apply_markup ARGS4( HTStructured *, context, - HTlexem, lexem, + HTlexeme, lexeme, BOOL, start, int, tag_charset) { - HT_tagspec* ts = *( ( start ? lexem_start : lexem_end ) + lexem); + HT_tagspec* ts = *( ( start ? lexeme_start : lexeme_end ) + lexeme); while (ts) { #ifdef USE_COLOR_STYLE @@ -727,7 +727,7 @@ PRIVATE void HTMLSRC_apply_markup ARGS4( force_classname = TRUE; } #endif - CTRACE((tfp,ts->start ? "SRCSTART %d\n" : "SRCSTOP %d\n",(int)lexem)); + CTRACE((tfp,ts->start ? "SRCSTART %d\n" : "SRCSTOP %d\n",(int)lexeme)); if (ts->start) HTML_start_element( context, @@ -791,7 +791,7 @@ PRIVATE void LYStartArea ARGS5( tag_charset, 0); } -PRIVATE void LYHandleFIG ARGS9( +PRIVATE void LYHandleFIG ARGS10( HTStructured *, me, CONST BOOL*, present, CONST char **, value, @@ -800,7 +800,8 @@ PRIVATE void LYHandleFIG ARGS9( CONST char *, id, CONST char *, src, BOOL, convert, - BOOL, start) + BOOL, start, + BOOL *, intern_flag GCC_UNUSED) { if (start == TRUE) { me->inFIG = TRUE; @@ -828,7 +829,7 @@ PRIVATE void LYHandleFIG ARGS9( if (clickable_images && src && src != '\0') { char *href = NULL; StrAllocCopy(href, src); - CHECK_FOR_INTERN(href); + CHECK_FOR_INTERN(*intern_flag,href); LYLegitimizeHREF(me, &href, TRUE, TRUE); if (*href) { char *temp = NULL; @@ -933,7 +934,7 @@ PRIVATE int HTML_start_element ARGS6( int dest_char_set = UCLYhndl_for_unrec; HTParentAnchor *dest = NULL; /* An anchor's destination */ BOOL dest_ismap = FALSE; /* Is dest an image map script? */ - BOOL UseBASE = TRUE; /* Resoved vs. BASE if present? */ + BOOL UseBASE = TRUE; /* Resolved vs. BASE if present? */ HTChildAnchor *ID_A = NULL; /* HTML_foo_ID anchor */ int url_type = 0, i = 0; char *cp = NULL; @@ -1310,7 +1311,7 @@ PRIVATE int HTML_start_element ARGS6( intern_flag = FALSE; #endif if (present && present[HTML_LINK_HREF]) { - CHECK_FOR_INTERN(value[HTML_LINK_HREF]); + CHECK_FOR_INTERN(intern_flag,value[HTML_LINK_HREF]); /* * Prepare to do housekeeping on the reference. - FM */ @@ -1762,7 +1763,7 @@ PRIVATE int HTML_start_element ARGS6( if (present && present[HTML_FRAME_SRC] && value[HTML_FRAME_SRC] && *value[HTML_FRAME_SRC] != '\0') { StrAllocCopy(href, value[HTML_FRAME_SRC]); - CHECK_FOR_INTERN(href); + CHECK_FOR_INTERN(intern_flag,href); url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE); /* @@ -1837,7 +1838,7 @@ PRIVATE int HTML_start_element ARGS6( if (present && present[HTML_IFRAME_SRC] && value[HTML_IFRAME_SRC] && *value[HTML_IFRAME_SRC] != '\0') { StrAllocCopy(href, value[HTML_IFRAME_SRC]); - CHECK_FOR_INTERN(href); + CHECK_FOR_INTERN(intern_flag,href); url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE); /* @@ -3031,7 +3032,7 @@ PRIVATE int HTML_start_element ARGS6( if (present[HTML_A_ISMAP]) intern_flag = FALSE; else - CHECK_FOR_INTERN(value[HTML_A_HREF]); + CHECK_FOR_INTERN(intern_flag,value[HTML_A_HREF]); #endif /* * Prepare to do housekeeping on the reference. - FM @@ -3175,20 +3176,24 @@ PRIVATE int HTML_start_element ARGS6( me->inUnderline, me->CurrentA); if (me->inBoldA == TRUE && me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_START_CHAR); -#if defined(NOTUSED_FOTEMODS) || !defined(NO_EMPTY_HREFLESS_A) +#if defined(NOTUSED_FOTEMODS) /* * Close an HREF-less NAMED-ed now if we aren't making their * content bold, and let the check in HTML_end_element() deal * with any dangling end tag this creates. - FM */ -# ifndef NO_EMPTY_HREFLESS_A - if (force_empty_hrefless_a) -# endif - if (href == NULL && me->inBoldA == FALSE) { - SET_SKIP_STACK(HTML_A); - HTML_end_element(me, HTML_A, include); - } -#endif /* NOTUSED_FOTEMODS || !defined(NO_EMPTY_HREFLESS_A)*/ + if (href == NULL && me->inBoldA == FALSE) { + SET_SKIP_STACK(HTML_A); + HTML_end_element(me, HTML_A, include); + } +#else + /*Close an HREF-less NAMED-ed now if force_empty_hrefless_a was + requested - VH*/ + if (href == NULL) { + SET_SKIP_STACK(HTML_A); + HTML_end_element(me, HTML_A, include); + } +#endif FREE(href); break; @@ -3225,7 +3230,7 @@ PRIVATE int HTML_start_element ARGS6( if (present && present[HTML_IMG_USEMAP] && value[HTML_IMG_USEMAP] && *value[HTML_IMG_USEMAP]) { StrAllocCopy(map_href, value[HTML_IMG_USEMAP]); - CHECK_FOR_INTERN(map_href); + CHECK_FOR_INTERN(intern_flag,map_href); url_type = LYLegitimizeHREF(me, &map_href, TRUE, TRUE); /* * If map_href ended up zero-length or otherwise doesn't @@ -3778,7 +3783,7 @@ PRIVATE int HTML_start_element ARGS6( * Resolve the HREF. - FM */ StrAllocCopy(href, value[HTML_AREA_HREF]); - CHECK_FOR_INTERN(href); + CHECK_FOR_INTERN(intern_flag,href); url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE); /* @@ -3888,13 +3893,13 @@ PRIVATE int HTML_start_element ARGS6( present[HTML_FIG_IMAGEMAP], present[HTML_FIG_ID] ? value[HTML_FIG_ID] : NULL, present[HTML_FIG_SRC] ? value[HTML_FIG_SRC] : NULL, - YES, TRUE); + YES, TRUE, &intern_flag); else LYHandleFIG(me, NULL, NULL, 0, 0, NULL, - NULL, YES, TRUE); + NULL, YES, TRUE, &intern_flag); #if 0 me->inFIG = TRUE; if (me->inA) { @@ -3917,7 +3922,7 @@ PRIVATE int HTML_start_element ARGS6( if (clickable_images && present && present[HTML_FIG_SRC] && value[HTML_FIG_SRC] && *value[HTML_FIG_SRC] != '\0') { StrAllocCopy(href, value[HTML_FIG_SRC]); - CHECK_FOR_INTERN(href); + CHECK_FOR_INTERN(intern_flag,href); url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE); if (*href) { /* @@ -4130,7 +4135,7 @@ PRIVATE int HTML_start_element ARGS6( 1 || me->object_ismap, me->object_id, (me->object_data && !me->object_classid) ? value[HTML_OBJECT_DATA] : NULL, - NO, TRUE); + NO, TRUE, &intern_flag); clear_objectdata(me); status = HT_PARSER_OTHER_CONTENT; me->objects_figged_open++; @@ -4150,7 +4155,7 @@ PRIVATE int HTML_start_element ARGS6( present && present[HTML_OVERLAY_SRC] && value[HTML_OVERLAY_SRC] && *value[HTML_OVERLAY_SRC] != '\0') { StrAllocCopy(href, value[HTML_OVERLAY_SRC]); - CHECK_FOR_INTERN(href); + CHECK_FOR_INTERN(intern_flag,href); url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE); if (*href) { /* @@ -4355,7 +4360,7 @@ PRIVATE int HTML_start_element ARGS6( if (clickable_images && present && present[HTML_BGSOUND_SRC] && value[HTML_BGSOUND_SRC] && *value[HTML_BGSOUND_SRC] != '\0') { StrAllocCopy(href, value[HTML_BGSOUND_SRC]); - CHECK_FOR_INTERN(href); + CHECK_FOR_INTERN(intern_flag,href); url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE); if (*href == '\0') { FREE(href); @@ -4469,7 +4474,7 @@ PRIVATE int HTML_start_element ARGS6( if (clickable_images && present && present[HTML_EMBED_SRC] && value[HTML_EMBED_SRC] && *value[HTML_EMBED_SRC] != '\0') { StrAllocCopy(href, value[HTML_EMBED_SRC]); - CHECK_FOR_INTERN(href); + CHECK_FOR_INTERN(intern_flag,href); url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE); if (*href != '\0') { /* @@ -5928,7 +5933,7 @@ PRIVATE int HTML_start_element ARGS6( case HTML_TBODY: HText_endStblTR(me->text); /* - * Not yet implemented. Just check for an ID link. - FM + * Not fully implemented. Just check for an ID link. - FM */ if (me->inA) { SET_SKIP_STACK(HTML_A); @@ -5939,13 +5944,26 @@ PRIVATE int HTML_start_element ARGS6( HTML_end_element(me, HTML_U, include); } UPDATE_STYLE; + if (me->inTABLE) { + if (present && present[HTML_TR_ALIGN] && value[HTML_TR_ALIGN]) { + if (!strcasecomp(value[HTML_TR_ALIGN], "center")) { + stbl_align = HT_CENTER; + } else if (!strcasecomp(value[HTML_TR_ALIGN], "right")) { + stbl_align = HT_RIGHT; + } else if (!strcasecomp(value[HTML_TR_ALIGN], "left") || + !strcasecomp(value[HTML_TR_ALIGN], "justify")) { + stbl_align = HT_LEFT; + } + } + HText_startStblRowGroup(me->text, stbl_align); + } CHECK_ID(HTML_TR_ID); break; case HTML_COL: case HTML_COLGROUP: /* - * Not yet implemented. Just check for an ID link. - FM + * Not fully implemented. Just check for an ID link. - FM */ if (me->inA) { SET_SKIP_STACK(HTML_A); @@ -5955,8 +5973,26 @@ PRIVATE int HTML_start_element ARGS6( SET_SKIP_STACK(HTML_U); HTML_end_element(me, HTML_U, include); } -/* HText_cancelStbl(me->text); we ingnore it instead - kw */ UPDATE_STYLE; + if (me->inTABLE) { + int span = 1; + if (present && present[HTML_COL_SPAN] && + value[HTML_COL_SPAN] && + isdigit((unsigned char)*value[HTML_COL_SPAN])) + span = atoi(value[HTML_COL_SPAN]); + if (present && present[HTML_COL_ALIGN] && value[HTML_COL_ALIGN]) { + if (!strcasecomp(value[HTML_COL_ALIGN], "center")) { + stbl_align = HT_CENTER; + } else if (!strcasecomp(value[HTML_COL_ALIGN], "right")) { + stbl_align = HT_RIGHT; + } else if (!strcasecomp(value[HTML_COL_ALIGN], "left") || + !strcasecomp(value[HTML_COL_ALIGN], "justify")) { + stbl_align = HT_LEFT; + } + } + HText_startStblCOL(me->text, span, stbl_align, + (ElementNumber == HTML_COLGROUP)); + } CHECK_ID(HTML_COL_ID); break; @@ -5978,11 +6014,15 @@ PRIVATE int HTML_start_element ARGS6( */ HTML_put_character(me, ' '); { - int colspan = 1; + int colspan = 1, rowspan = 1; if (present && present[HTML_TD_COLSPAN] && value[HTML_TD_COLSPAN] && isdigit((unsigned char)*value[HTML_TD_COLSPAN])) colspan = atoi(value[HTML_TD_COLSPAN]); + if (present && present[HTML_TD_ROWSPAN] && + value[HTML_TD_ROWSPAN] && + isdigit((unsigned char)*value[HTML_TD_ROWSPAN])) + rowspan = atoi(value[HTML_TD_ROWSPAN]); if (present && present[HTML_TD_ALIGN] && value[HTML_TD_ALIGN]) { if (!strcasecomp(value[HTML_TD_ALIGN], "center")) { stbl_align = HT_CENTER; @@ -5993,7 +6033,7 @@ PRIVATE int HTML_start_element ARGS6( stbl_align = HT_LEFT; } } - HText_startStblTD(me->text, colspan, stbl_align, + HText_startStblTD(me->text, colspan, rowspan, stbl_align, (ElementNumber == HTML_TH)); } me->in_word = NO; @@ -6108,6 +6148,8 @@ PRIVATE int HTML_end_element ARGS3( int status = HT_OK; char *temp = NULL, *cp = NULL; BOOL BreakFlag = FALSE; + BOOL intern_flag = FALSE; + BOOL skip_stack_requested = FALSE; EMIT_IFDEF_EXP_JUSTIFY_ELTS(BOOL reached_awaited_stacked_elt=FALSE;) #ifdef USE_PSRC @@ -6167,6 +6209,7 @@ PRIVATE int HTML_end_element ARGS3( * SGML_EMPTY in HTMLDTD.c. - FM & KW */ if (HTML_dtd.tags[element_number].contents != SGML_EMPTY) { + skip_stack_requested = me->skip_stack > 0; if ((element_number != me->sp[0].tag_number) && me->skip_stack <= 0 && HTML_dtd.tags[HTML_LH].contents != SGML_EMPTY && @@ -6737,7 +6780,7 @@ PRIVATE int HTML_end_element ARGS3( 0, 0, NULL, - NULL, NO, FALSE); + NULL, NO, FALSE, &intern_flag); break; case HTML_OBJECT: @@ -7329,15 +7372,33 @@ End_Object: me->UsePlainSpace = TRUE; if (HTML_dtd.tags[element_number].contents == SGML_LITTERAL) { - TRANSLATE_AND_UNESCAPE_ENTITIES5(&me->textarea.data, - me->UCLYhndl, - current_char_set, - me->UsePlainSpace, me->HiddenValue); + TRANSLATE_AND_UNESCAPE_ENTITIES6(&me->textarea.data, + me->UCLYhndl, + current_char_set, + NO, + me->UsePlainSpace, me->HiddenValue); } else { - TRANSLATE_HTML5(&me->textarea.data, + /* + * This shouldn't have anything to do, normally, but + * just in case... + * There shouldn't be lynx special character codes in + * the chunk ("DTD" flag Tgf_nolyspcl tells SGML.c not + * to generate them). If there were, we could set the + * last parameter ('Back') below to YES, which would + * take them out of the data. + * The data may however contain non break space, soft + * hyphen, or en space etc., in the me->UCLYhndl character + * encoding. If that's a problem, perhaps for the (line + * or other) editor, setting 'Back' to YES should also + * help to always convert them to plain spaces (or drop + * them). - kw + */ + TRANSLATE_HTML7(&me->textarea.data, me->UCLYhndl, current_char_set, - me->UsePlainSpace, me->HiddenValue); + NO, + me->UsePlainSpace, me->HiddenValue, + NO); } data = me->textarea.data; @@ -7600,6 +7661,8 @@ End_Object: break; case HTML_COLGROUP: + if (me->inTABLE) + HText_endStblCOLGROUP(me->text); break; case HTML_TH: @@ -7657,26 +7720,28 @@ End_Object: } #ifdef USE_COLOR_STYLE + if (!skip_stack_requested) { /*don't emit stylechanges if skipped stack element - VH*/ #if !OPT_SCN - TrimColorClass(HTML_dtd.tags[element_number].name, - Style_className, &hcode); + TrimColorClass(HTML_dtd.tags[element_number].name, + Style_className, &hcode); #else # if !OMIT_SCN_KEEPING - FastTrimColorClass(HTML_dtd.tags[element_number].name, - HTML_dtd.tags[element_number].name_len, - Style_className, - &Style_className_end, &hcode); + FastTrimColorClass(HTML_dtd.tags[element_number].name, + HTML_dtd.tags[element_number].name_len, + Style_className, + &Style_className_end, &hcode); # endif #endif - if (!ReallyEmptyTagNum(element_number)) - { - CTRACE((tfp, "STYLE:end_element: ending non-EMPTY style\n")); + if (!ReallyEmptyTagNum(element_number)) + { + CTRACE((tfp, "STYLE:end_element: ending non-EMPTY style\n")); #if !defined(USE_HASH) - HText_characterStyle(me->text, element_number+STARTAT, STACK_OFF); + HText_characterStyle(me->text, element_number+STARTAT, STACK_OFF); #else - HText_characterStyle(me->text, HCODE_TO_STACK_OFF(hcode), STACK_OFF); + HText_characterStyle(me->text, HCODE_TO_STACK_OFF(hcode), STACK_OFF); #endif /* USE_HASH */ + } } #endif /* USE_COLOR_STYLE */ return status; diff --git a/src/HTML.h b/src/HTML.h index 04ea3f32..95bd74f1 100644 --- a/src/HTML.h +++ b/src/HTML.h @@ -34,6 +34,9 @@ #define TRANSLATE_HTML5(s,cs_from,cs_to,p,h) \ LYUCFullyTranslateString(s, cs_from, cs_to, NO, YES, p, h, NO, st_HTML) +#define TRANSLATE_HTML7(s,cs_from,cs_to,spcls,p,h,Back) \ + LYUCFullyTranslateString(s, cs_from, cs_to, NO, spcls, p, h, Back, st_HTML) + /* * Strings from attributes which should be converted to some kind * of "standard" representation (character encoding), was Latin-1, diff --git a/src/HTNestedList.h b/src/HTNestedList.h index f7c0411d..75d83a70 100644 --- a/src/HTNestedList.h +++ b/src/HTNestedList.h @@ -40,6 +40,6 @@ #define HTML_OBJECT_M HTML_ELEMENTS+31 -#define HTML_EXTRA_ELEMENTS 31 +#define LYNX_HTML_EXTRA_ELEMENTS 31 #endif /* HTNESTEDLIST_H */ diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c index b4b54422..e48aaf8b 100644 --- a/src/LYCharUtils.c +++ b/src/LYCharUtils.c @@ -1678,17 +1678,18 @@ PUBLIC char ** LYUCFullyTranslateString ARGS9( /* ** Don't do byte translation ** if original AND target character sets - ** are both iso-8859-1, + ** are both iso-8859-1 (and we are not called to back-translate), ** or if we are in CJK mode. */ - no_bytetrans = (BOOL) ((cs_to <= 0 && cs_from == cs_to) || - HTCJK != NOCJK); - + if (HTCJK != NOCJK) { + no_bytetrans = TRUE; + } else if (cs_to <= 0 && cs_from == cs_to && (!Back || cs_to < 0)) { + no_bytetrans = TRUE; + } else { /* No need to translate or examine the string any further */ - if (!no_bytetrans) no_bytetrans = (BOOL) (!use_lynx_specials && !Back && - UCNeedNotTranslate(cs_from, cs_to)); - + UCNeedNotTranslate(cs_from, cs_to)); + } /* ** Save malloc/calloc overhead in simple case - kw */ @@ -1898,21 +1899,31 @@ PUBLIC char ** LYUCFullyTranslateString ARGS9( state = S_got_outchar; break; } else { - *(unsigned char *)p = (unsigned char)160; code = 160; if (LYCharSet_UC[cs_to].enc == UCT_ENC_8859 || (LYCharSet_UC[cs_to].like8859 & UCT_R_8859SPECL)) { state = S_got_outchar; break; + } else if (!(LYCharSet_UC[cs_from].enc == UCT_ENC_8859 + ||(LYCharSet_UC[cs_from].like8859 & UCT_R_8859SPECL))) { + state = S_check_uni; + break; + } else { + *(unsigned char *)p = (unsigned char)160; } } } else if ((*p) == LY_SOFT_HYPHEN) { - *(unsigned char *)p = (unsigned char)173; code = 173; if (LYCharSet_UC[cs_to].enc == UCT_ENC_8859 || (LYCharSet_UC[cs_to].like8859 & UCT_R_8859SPECL)) { state = S_got_outchar; break; + } else if (!(LYCharSet_UC[cs_from].enc == UCT_ENC_8859 + ||(LYCharSet_UC[cs_from].like8859 & UCT_R_8859SPECL))) { + state = S_check_uni; + break; + } else { + *(unsigned char *)p = (unsigned char)173; } } else if (code < 127 || T.transp) { state = S_got_outchar; diff --git a/src/LYCurses.c b/src/LYCurses.c index 07b2d8d9..e804da1e 100644 --- a/src/LYCurses.c +++ b/src/LYCurses.c @@ -520,14 +520,17 @@ PRIVATE void LYsetWAttr ARGS1(WINDOW *, win) attr = lynx_color_cfg[code].attr; /* - * no_color_video isn't implemented (97/4/14) in ncurses 4.1, but may - * be in SVr4 (which would make this redundant for the latter). + * no_color_video is implemented in ncurses 4.2, but not in other + * flavors of curses. So we check before adding video attributes that + * might conflict with colors. For A_BOLD, check for both the bold and + * standout mask items because standout often uses bold in conjunction + * with another attribute. -TD */ if ((Current_Attr & A_BOLD) && !(NoColorVideo & 33)) { attr |= A_BOLD; } - if ((Current_Attr == A_UNDERLINE) && !(NoColorVideo & 2)) { + if ((Current_Attr & A_UNDERLINE) && !(NoColorVideo & 2)) { attr |= A_UNDERLINE; } @@ -837,7 +840,11 @@ PUBLIC void start_curses NOARGS #endif /* USE_COLOR_TABLE */ } #ifdef __DJGPP__ +#ifdef WATT32 + _eth_init(); +#else else sock_init(); +#endif /* WATT32 */ #endif /* __DJGPP__ */ #endif /* not VMS */ diff --git a/src/LYForms.c b/src/LYForms.c index 70f7486d..6e10025b 100644 --- a/src/LYForms.c +++ b/src/LYForms.c @@ -1134,7 +1134,7 @@ redraw: cmd = LYK_QUIT; #ifndef USE_SLANG } else if (c == MOUSE_KEY) { - if ((cmd = fancy_mouse(form_window, i + 1 + window_offset, &cur_selection)) < 0) + if ((cmd = fancy_mouse(form_window, i + 1 - window_offset, &cur_selection)) < 0) goto redraw; if (cmd == LYK_ACTIVATE) break; diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h index d0f8efbf..dc41af94 100644 --- a/src/LYGlobalDefs.h +++ b/src/LYGlobalDefs.h @@ -396,9 +396,7 @@ extern BOOL ok_justify; extern BOOLEAN with_backspaces; #endif -#ifndef NO_EMPTY_HREFLESS_A extern BOOL force_empty_hrefless_a; -#endif #ifndef NO_NONSTICKY_INPUTS extern BOOL sticky_inputs; diff --git a/src/LYHistory.c b/src/LYHistory.c index de190ef1..9f7a8cca 100644 --- a/src/LYHistory.c +++ b/src/LYHistory.c @@ -148,6 +148,10 @@ PUBLIC BOOLEAN LYwouldPush ARGS2( if (strncmp(docurl, "file://localhost/", 17) != 0 || (ulen = strlen(docurl)) <= strlen(HTML_SUFFIX) || strcmp(docurl + ulen - strlen(HTML_SUFFIX), HTML_SUFFIX) != 0) + /* + * If it is not a local HTML file, it may be a Web page that + * accidentally has the same title. So return TRUE now. - kw + */ return TRUE; } @@ -726,7 +730,7 @@ PUBLIC void LYstore_message2 ARGS2( if (message != NULL) { char *temp = NULL; - HTSprintf(&temp, message, (argument == 0) ? "" : argument); + HTSprintf0(&temp, message, (argument == 0) ? "" : argument); to_stack(temp); } } diff --git a/src/LYKeymap.c b/src/LYKeymap.c index 148479f7..bd5783b5 100644 --- a/src/LYKeymap.c +++ b/src/LYKeymap.c @@ -1167,18 +1167,18 @@ PUBLIC char *key_for_func ARGS1 ( /* * This function returns TRUE if the ch is non-alphanumeric - * and maps to key_name (LYK_foo in the keymap[] array). - FM + * and maps to KeyName (LYK_foo in the keymap[] array). - FM */ PUBLIC BOOL LYisNonAlnumKeyname ARGS2( int, ch, - int, key_name) + int, KeyName) { if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'z') || ch < 0 || ch >= KEYMAP_SIZE) return (FALSE); - return (BOOL) (keymap[ch+1] == key_name); + return (BOOL) (keymap[ch+1] == KeyName); } /* @@ -1186,12 +1186,12 @@ PUBLIC BOOL LYisNonAlnumKeyname ARGS2( * LYK_foo value passed to it as an argument. - FM */ PUBLIC int LYReverseKeymap ARGS1( - int, key_name) + int, KeyName) { int i; for (i = 1; i < KEYMAP_SIZE; i++) { - if (keymap[i] == key_name) { + if (keymap[i] == KeyName) { return(i - 1); } } diff --git a/src/LYKeymap.h b/src/LYKeymap.h index 518864fe..85ffb087 100644 --- a/src/LYKeymap.h +++ b/src/LYKeymap.h @@ -5,9 +5,9 @@ #include <HTUtils.h> #endif -extern BOOLEAN LYisNonAlnumKeyname PARAMS((int ch, int key_name)); +extern BOOLEAN LYisNonAlnumKeyname PARAMS((int ch, int KeyName)); extern char *key_for_func PARAMS((int func)); -extern int LYReverseKeymap PARAMS((int key_name)); +extern int LYReverseKeymap PARAMS((int KeyName)); extern int lookup_keymap PARAMS((int code)); extern int lacname_to_lac PARAMS((CONST char *func)); extern int lkcstring_to_lkc PARAMS((CONST char *src)); diff --git a/src/LYLeaks.c b/src/LYLeaks.c index f4a5954c..d0f7acab 100644 --- a/src/LYLeaks.c +++ b/src/LYLeaks.c @@ -235,6 +235,75 @@ PUBLIC void *LYLeakMalloc ARGS3( } /* +** Purpose: Add information about new allocation to the list, +** after a call to malloc or calloc or an equivalent +** function which may or may not have already created +** a list entry. +** Arguments: vp_malloc The pointer to newly allocate memory. +** Arguments: st_bytes The size of the allocation requested +** in bytes. +** cp_File The file from which the request for +** allocation came from. +** ssi_Line The line number in cp_File where the +** allocation request came from. +** Return Value: void * A pointer to the allocated memory or NULL on +** failure. +** Remarks/Portability/Dependencies/Restrictions: +** If no memory is allocated, then no entry is added to the +** allocation list. +** Revision History: +** 1999-02-08 created, modelled after LYLeakMalloc - kw +*/ +PUBLIC AllocationList *LYLeak_mark_malloced ARGS4( + void *, vp_malloced, + size_t, st_bytes, + CONST char *, cp_File, + CONST short, ssi_Line) +{ + AllocationList *ALp_new = NULL; + /* + * The actual allocation has already been done! + * + * Only on successful allocation do we track any information. + */ + if (vp_malloced != NULL) { + /* + * See if there is already an entry. If so, just + * update the source location info. + */ + ALp_new = FindInList(vp_malloced); + if (ALp_new) { + ALp_new->SL_memory.cp_FileName = cp_File; + ALp_new->SL_memory.ssi_LineNumber = ssi_Line; + return(ALp_new); + } + /* + * Further allocate memory to store the information. + * Just return on failure to allocate more. + */ + ALp_new = (AllocationList *)calloc(1, sizeof(AllocationList)); + + if (ALp_new == NULL) { + return(NULL); + } + /* + * Copy over the relevant information. + */ + ALp_new->vp_Alloced = vp_malloced; + ALp_new->st_Bytes = st_bytes; + ALp_new->SL_memory.cp_FileName = cp_File; + ALp_new->SL_memory.ssi_LineNumber = ssi_Line; + + /* + * Add the new item to the allocation list. + */ + AddToList(ALp_new); + } + + return(ALp_new); +} + +/* ** Purpose: Capture allocations by calloc (stdlib.h) and ** save relevant information in a list. ** Arguments: st_number The number of items to allocate. @@ -390,6 +459,61 @@ PUBLIC void *LYLeakRealloc ARGS4( } /* +** Purpose: Add information about reallocated memory to the list, +** after a call to realloc or an equivalent +** function which has not already created or updated +** a list entry. +** Arguments: ALp_old List entry for previously allocated +** block of memory to resize. If NULL, +** mark_realloced works just like +** mark_malloced. +** vp_realloced The new pointer, after resizing. +** st_newBytes The new size of the chunk of memory. +** cp_File The file to record. +** ssi_Line The line to record. +** Return Value: Pointer to new or updated list entry +** for this memory block. +** NULL on allocation error. +** Revision History: +** 1999-02-11 created kw +*/ +#if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED) +PRIVATE AllocationList *mark_realloced ARGS5( + AllocationList *, ALp_old, + void *, vp_realloced, + size_t, st_newBytes, + CONST char *, cp_File, + CONST short, ssi_Line) +{ + /* + * If there is no list entry for the old allocation, treat this + * as if a new allocation had happened. + */ + if (ALp_old == NULL) { + return(LYLeak_mark_malloced( + vp_realloced, st_newBytes, cp_File, ssi_Line)); + } + + /* + * ALp_old represents the memory block before reallocation. + * Assume that if we get here, there isn't yet a list entry + * for the new, possibly different, address after realloc, + * that is our list hasn't been updated - so we're going to + * do that now. + */ + + if (vp_realloced != NULL) { + ALp_old->vp_Alloced = vp_realloced; + ALp_old->st_Bytes = st_newBytes; + ALp_old->SL_realloc.cp_FileName = cp_File; + ALp_old->SL_realloc.ssi_LineNumber = ssi_Line; + } + + return(ALp_old); +} +#endif /* not LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */ + +/* ** Purpose: Capture all requests to free information and also ** remove items from the allocation list. ** Arguments: vp_Alloced The memory to free. @@ -524,6 +648,230 @@ PUBLIC char * LYLeakSACat ARGS4( return *dest; } +#if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED) +PUBLIC CONST char * leak_cp_File_hack = __FILE__; +PUBLIC short leak_ssi_Line_hack = __LINE__; + +/* +** Purpose: A wrapper around StrAllocVsprintf (the workhorse of +** HTSprintf/HTSprintf0, implemented in HTString.c) that +** tries to make sure that our allocation list is always +** properly updated, whether StrAllocVsprintf itself was +** compiled with memory tracking or not (or even a mixture, +** like tracking the freeing but not the new allocation). +** Some source files can be compiled with LY_FIND_LEAKS_EXTENDED +** in effect while others only have LY_FIND_LEAKS in effect, +** and as long as HTString.c is complied with memory tracking +** (of either kind) string objects allocated by HTSprintf/ +** HTSprintf0 (or otherwise) can be passed around among them and +** manipulated both ways. +** Arguments: dest As for StrAllocVsprintf. +** cp_File The source file of the caller (i.e. the +** caller of HTSprintf/HTSprintf0, hopefully). +** ssi_Line The line of cp_File calling. +** inuse,fmt,ap As for StrAllocVsprintf. +** Return Value: The char pointer to resulting string, as set +** by StrAllocVsprintf, or +** NULL if dest==0 (wrong use!). +** Remarks/Portability/Dependencies/Restrictions: +** The price for generality is severe inefficiency: several +** list lookups are done to be on the safe side. +** We don't get he real allocation size, only a minimum based +** on the string length of the result. So the amount of memory +** leakage may get underestimated. +** If *dest is an invalid pointer value on entry (i.e. was not +** tracked), the program will exit after one last entry is added +** to the allocation list. +** If StrAllocVsprintf fails to return a valid string via the +** indirect string pointer (its first parameter), invalid memory +** access will result and the program will probably terminate +** with a signal. This can happen if, on entry, *dest is NULL +** and fmt is empty or NULL, so just Don't Do That. +** Revision History: +** 1999-02-11 created kw +** 1999-10-15 added comments kw +*/ +PRIVATE char * LYLeakSAVsprintf ARGS6( + char **, dest, + CONST char *, cp_File, + CONST short, ssi_Line, + size_t, inuse, + CONST char *, fmt, + va_list, ap) +{ + AllocationList *ALp_old; + void *vp_oldAlloced; + + CONST char * old_cp_File = __FILE__; + short old_ssi_Line = __LINE__; + + if (!dest) + return NULL; + + vp_oldAlloced = *dest; + if (!vp_oldAlloced) { + StrAllocVsprintf(dest, inuse, fmt, ap); + LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line); + return(*dest); + } else { + void * vp_realloced; + ALp_old = FindInList(vp_oldAlloced); + if (ALp_old == NULL) { + /* + * Track the invalid pointer value and then exit. + * If unable to allocate, just exit. + */ + auto AllocationList *ALp_new = + (AllocationList *)calloc(1, + sizeof(AllocationList)); + + if (ALp_new == NULL) { + exit(-1); + } + + /* + * Set the information up; no need to allocate file name + * since it is a static string. + */ + ALp_new->vp_Alloced = NULL; + ALp_new->vp_BadRequest = vp_oldAlloced; + ALp_new->SL_realloc.cp_FileName = cp_File; + ALp_new->SL_realloc.ssi_LineNumber = ssi_Line; + + /* + * Add the item to the list. + * Exit. + */ + AddToList(ALp_new); + exit(-1); + } + + old_cp_File = ALp_old->SL_memory.cp_FileName; + old_ssi_Line = ALp_old->SL_memory.ssi_LineNumber; + /* + * DO THE REAL WORK, by calling StrAllocVsprintf. + * If result is not NULL, record the information. + */ + StrAllocVsprintf(dest, inuse, fmt, ap); + vp_realloced = (void *)*dest; + if (vp_realloced != NULL) { + AllocationList *ALp_new = FindInList(vp_realloced); + if (!ALp_new) { + /* Look up again, list may have changed! - kw */ + ALp_old = FindInList(vp_oldAlloced); + if (ALp_old == NULL) { + LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line); + return(*dest); + } + mark_realloced(ALp_old, *dest, strlen(*dest) + 1, cp_File, ssi_Line); + return(*dest); + } + if (vp_realloced == vp_oldAlloced) { + ALp_new->SL_memory.cp_FileName = old_cp_File; + ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line; + ALp_new->SL_realloc.cp_FileName = cp_File; + ALp_new->SL_realloc.ssi_LineNumber = ssi_Line; + return(*dest); + } + /* Look up again, list may have changed! - kw */ + ALp_old = FindInList(vp_oldAlloced); + if (ALp_old == NULL) { + ALp_new->SL_memory.cp_FileName = old_cp_File; + ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line; + ALp_new->SL_realloc.cp_FileName = cp_File; + ALp_new->SL_realloc.ssi_LineNumber = ssi_Line; + } else { + ALp_new->SL_memory.cp_FileName = old_cp_File; + ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line; + ALp_new->SL_realloc.cp_FileName = cp_File; + ALp_new->SL_realloc.ssi_LineNumber = ssi_Line; + } + } + return(*dest); + } +} + +/* Note: the following may need updating if HTSprintf in HTString.c + * is changed. - kw */ +#if ANSI_VARARGS +PRIVATE char * LYLeakHTSprintf (char **pstr, CONST char *fmt, ...) +#else +PRIVATE char * LYLeakHTSprintf (va_alist) + va_dcl +#endif +{ + char *str; + size_t inuse = 0; + va_list ap; + LYva_start(ap,fmt); + { +#if !ANSI_VARARGS + char ** pstr = va_arg(ap, char **); + CONST char * fmt = va_arg(ap, CONST char *); +#endif + if (pstr != 0 && *pstr != 0) + inuse = strlen(*pstr); + str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack, + inuse, fmt, &ap); + } + va_end(ap); + return str; +} + +/* Note: the following may need updating if HTSprintf0 in HTString.c + * is changed. - kw */ +#if ANSI_VARARGS +PRIVATE char * LYLeakHTSprintf0 (char **pstr, CONST char *fmt, ...) +#else +PRIVATE char * LYLeakHTSprintf0 (va_alist) + va_dcl +#endif +{ + char *str; + va_list ap; + LYva_start(ap,fmt); + { +#if !ANSI_VARARGS + char ** pstr = va_arg(ap, char **); + CONST char * fmt = va_arg(ap, CONST char *); +#endif + str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack, + 0, fmt, &ap); + } + va_end(ap); + return str; +} + +/* + * HTSprintf and HTSprintf0 will be defined such that they effectively + * call one of the following two functions that store away a copy to + * the File & Line info in temporary hack variables, and then call + * the real function (which is returned here as a function pointer) + * to the regular HTSprintf/HTSprintf0 arguments. + * It's probably a bit inefficient, but that shouldn't be noticeable + * compared to all the time that memory tracking takes up for list + * traversal. - kw + */ +PUBLIC HTSprintflike *Get_htsprintf_fn ARGS2( + CONST char *, cp_File, + CONST short, ssi_Line) +{ + leak_cp_File_hack = cp_File; + leak_ssi_Line_hack = ssi_Line; + return &LYLeakHTSprintf; +} + +PUBLIC HTSprintflike *Get_htsprintf0_fn ARGS2( + CONST char *, cp_File, + CONST short, ssi_Line) +{ + leak_cp_File_hack = cp_File; + leak_ssi_Line_hack = ssi_Line; + return &LYLeakHTSprintf0; +} + +#endif /* not LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */ + /* ** Purpose: Add a new allocation item to the list. ** Arguments: ALp_new The new item to add. diff --git a/src/LYLocal.c b/src/LYLocal.c index 735fccdc..25ce7699 100644 --- a/src/LYLocal.c +++ b/src/LYLocal.c @@ -287,7 +287,7 @@ struct dired_menu { PRIVATE BOOLEAN cannot_stat ARGS1(CONST char *, name) { char *tmpbuf = 0; - HTSprintf(&tmpbuf, gettext("Unable to get status of '%s'."), name); + HTSprintf0(&tmpbuf, gettext("Unable to get status of '%s'."), name); HTAlert(tmpbuf); FREE(tmpbuf); return FALSE; @@ -356,7 +356,7 @@ PRIVATE int move_file ARGS2(char *, source, char *, target) char *msg = 0; char *args[5]; - HTSprintf(&msg, gettext("move %s to %s"), source, target); + HTSprintf0(&msg, gettext("move %s to %s"), source, target); args[0] = "mv"; args[1] = source; args[2] = target; @@ -869,7 +869,7 @@ PRIVATE BOOLEAN create_file ARGS1( */ if (not_already_exists(testpath)) { char *msg = 0; - HTSprintf(&msg,gettext("create %s"),testpath); + HTSprintf0(&msg,gettext("create %s"),testpath); args[0] = "touch"; args[1] = testpath; args[2] = (char *) 0; @@ -914,7 +914,7 @@ PRIVATE BOOLEAN create_directory ARGS1( */ if (not_already_exists(testpath)) { char *msg = 0; - HTSprintf(&msg,"make directory %s",testpath); + HTSprintf0(&msg,"make directory %s",testpath); args[0] = "mkdir"; args[1] = testpath; args[2] = (char *) 0; @@ -1322,7 +1322,7 @@ PRIVATE BOOLEAN permit_location ARGS3( /* * Call chmod(). */ - HTSprintf(&tmpbuf, "chmod %.4o %s", (unsigned int)new_mode, destpath); + HTSprintf0(&tmpbuf, "chmod %.4o %s", (unsigned int)new_mode, destpath); sprintf(amode, "%.4o", (unsigned int)new_mode); args[0] = "chmod"; args[1] = amode; @@ -2090,7 +2090,7 @@ PUBLIC BOOLEAN local_install ARGS3( return 0; /* don't do it */ } args[src] = savepath; - HTSprintf(&tmpbuf, "install %s in %s", savepath, destpath); + HTSprintf0(&tmpbuf, "install %s in %s", savepath, destpath); if (LYExecv(INSTALL_PATH, args, tmpbuf) <= 0) { FREE(tmpbuf); FREE(tmpdest); @@ -2099,7 +2099,7 @@ PUBLIC BOOLEAN local_install ARGS3( count++; } else { char *name; - HTSprintf(&tmpbuf, "install in %s", destpath); + HTSprintf0(&tmpbuf, "install in %s", destpath); while ((name = (char *)HTList_nextObject(tag))) { int err; args[src] = HTfullURL_toFile(name); @@ -2333,7 +2333,7 @@ PRIVATE int LYExecv ARGS3( char *tmpbuf = 0; #ifdef __DJGPP__ stop_curses(); - HTSprintf(&tmpbuf, "%s", path); + HTSprintf0(&tmpbuf, "%s", path); for (n = 1; argv[n] != 0; n++) HTSprintf(&tmpbuf, " %s", argv[n]); HTSprintf(&tmpbuf, "\n"); @@ -2357,7 +2357,7 @@ PRIVATE int LYExecv ARGS3( pid = fork(); /* fork and execute command */ switch (pid) { case -1: - HTSprintf(&tmpbuf, gettext("Unable to %s due to system error!"), msg); + HTSprintf0(&tmpbuf, gettext("Unable to %s due to system error!"), msg); rc = 0; break; /* don't fall thru! - KW */ case 0: /* child */ @@ -2386,7 +2386,7 @@ PRIVATE int LYExecv ARGS3( #endif /* !HAVE_WAITPID */ if (WEXITSTATUS(wstatus) != 0 || WTERMSIG(wstatus) > 0) { /* error return */ - HTSprintf(&tmpbuf, gettext("Probable failure to %s due to system error!"), + HTSprintf0(&tmpbuf, gettext("Probable failure to %s due to system error!"), msg); rc = 0; } diff --git a/src/LYMain.c b/src/LYMain.c index baeb89b8..8c06d910 100644 --- a/src/LYMain.c +++ b/src/LYMain.c @@ -86,11 +86,6 @@ PUBLIC char *syslog_txt = NULL; /* syslog arb text for session */ PUBLIC char *LYCSwingPath = NULL; #endif /* VMS */ -#if HAVE_CUSERID && !defined(_XOPEN_SOURCE) -/*extern char *cuserid();*/ /* workaround for Redhat 6.0 */ - /* for the price of screwing up legitimate systems? Nah. */ -#endif - #ifdef DIRED_SUPPORT PUBLIC BOOLEAN lynx_edit_mode = FALSE; PUBLIC BOOLEAN no_dired_support = FALSE; @@ -444,15 +439,13 @@ PUBLIC BOOL ok_justify = TRUE; PUBLIC BOOLEAN with_backspaces = FALSE; #endif -#ifndef NO_EMPTY_HREFLESS_A PUBLIC BOOL force_empty_hrefless_a = FALSE; -#endif #ifndef NO_NONSTICKY_INPUTS PUBLIC BOOL sticky_inputs = TRUE; +PUBLIC BOOL textfield_stop_at_left_edge=FALSE; #endif -PUBLIC BOOL textfield_stop_at_left_edge=TRUE; #ifdef DISP_PARTIAL PUBLIC BOOLEAN display_partial_flag = TRUE; /* Display document during download */ @@ -1872,8 +1865,12 @@ PUBLIC int main ARGS2( * interruptible (terminal is in raw mode, select() works). -BL */ #ifdef USE_PSRC - if (!dump_output_immediately) - HTMLSRC_init_caches(); /* do it before terminal is initialized*/ + if (!dump_output_immediately) { + HTMLSRC_init_caches(FALSE); /* do it before terminal is initialized*/ +#ifdef LY_FIND_LEAKS + atexit(html_src_clean_data); +#endif + } #endif if (!dump_output_immediately) { @@ -2127,6 +2124,10 @@ PUBLIC void reload_read_cfg NOARGS custom_display_charset = FALSE; memset((char*)charset_subsets, 0, sizeof(charset_subset_t)*MAXCHARSETS); #endif + +#ifdef USE_PSRC + html_src_on_lynxcfg_reload(); +#endif free_lynx_cfg(); /* free downloaders, printers, environments */ /* * Process the configuration file. @@ -2447,6 +2448,7 @@ static int convert_to_fun ARGS1( } } HTOutputFormat = HTAtom_for(outformat); + FREE(outformat); } else { HTOutputFormat = NULL; } @@ -3090,7 +3092,8 @@ with -dump, format output as with -traversal, but to stdout" ), PARSE_SET( "dont_wrap_pre", SET_ARG, &dont_wrap_pre, - "inhibit wrapping of text in <pre> when -dump'ing and -crawl'ing" + "inhibit wrapping of text in <pre> when -dump'ing and \n" + "-crawl'ing, mark wrapped lines in interactive session" ), PARSE_FUN( "dump", FUNCTION_ARG, dump_output_fun, @@ -3147,12 +3150,10 @@ keys (may be incompatible with some curses packages)" "from", TOGGLE_ARG, &LYNoFromHeader, "toggle transmissions of From headers" ), -#ifndef NO_EMPTY_HREFLESS_A PARSE_SET( "force_empty_hrefless_a", SET_ARG, &force_empty_hrefless_a, "force HREF-less 'A' elements to be empy (close them as soon as they are seen)" ), -#endif #if !defined(NO_OPTION_FORMS) && !defined(NO_OPTION_MENU) PARSE_SET( "forms_options", TOGGLE_ARG, &LYUseFormsOptions, diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c index 1c8f18d8..157fe2a7 100644 --- a/src/LYMainLoop.c +++ b/src/LYMainLoop.c @@ -209,6 +209,8 @@ PRIVATE document newdoc; PRIVATE document curdoc; PRIVATE char *traversal_host = NULL; PRIVATE char *traversal_link_to_add = NULL; +PRIVATE char *owner_address = NULL; /* Holds the responsible owner's address */ +PRIVATE char *ownerS_address = NULL; /* Holds owner's address during source fetch */ #ifndef NO_NONSTICKY_INPUTS PRIVATE BOOL textinput_activated = FALSE; @@ -238,6 +240,8 @@ PRIVATE void free_mainloop_variables NOARGS #endif FREE(traversal_host); FREE(traversal_link_to_add); + FREE(owner_address); + FREE(ownerS_address); #ifdef DIRED_SUPPORT clear_tags(); #endif /* DIRED_SUPPORT */ @@ -530,7 +534,8 @@ PRIVATE void do_check_goto_URL ARGS3( } } -PRIVATE void do_check_recall ARGS7( +/* returns FALSE if user cancelled input or URL was invalid, TRUE otherwise */ +PRIVATE BOOL do_check_recall ARGS7( int, ch, char *, user_input_buffer, char **, old_user_input, @@ -540,6 +545,7 @@ PRIVATE void do_check_recall ARGS7( BOOLEAN *, FirstURLRecall) { char *cp; + BOOL ret = FALSE; if (*old_user_input == 0) StrAllocCopy(*old_user_input, ""); @@ -565,6 +571,7 @@ PRIVATE void do_check_recall ARGS7( HTUserMsg2(WWW_ILLEGAL_URL_MESSAGE, user_input_buffer); strcpy(user_input_buffer, *old_user_input); FREE(*old_user_input); + ret = FALSE; break; } } @@ -580,6 +587,7 @@ PRIVATE void do_check_recall ARGS7( strcpy(user_input_buffer, *old_user_input); FREE(*old_user_input); HTInfoMsg(CANCELLED); + ret = FALSE; break; } if (recall && ch == UPARROW) { @@ -623,6 +631,7 @@ PRIVATE void do_check_recall ARGS7( strcpy(user_input_buffer, *old_user_input); FREE(*old_user_input); HTInfoMsg(CANCELLED); + ret = FALSE; break; } continue; @@ -666,14 +675,17 @@ PRIVATE void do_check_recall ARGS7( strcpy(user_input_buffer, *old_user_input); FREE(*old_user_input); HTInfoMsg(CANCELLED); + ret = FALSE; break; } continue; } } else { + ret = TRUE; break; } } + return ret; } PRIVATE void do_cleanup_after_delete NOARGS @@ -809,6 +821,44 @@ PRIVATE int DoTraversal ARGS2( return c; } +#ifndef DONT_TRACK_INTERNAL_LINKS +PRIVATE BOOLEAN check_history NOARGS +{ + CONST char *base; + + if (!curdoc.post_data) + /* + * Normal case - List Page is not associated + * with post data. - kw + */ + return TRUE; + + if (nhist > 0 + && !LYresubmit_posts + && curdoc.post_data + && history[nhist - 1].post_data + && !strcmp(curdoc.post_data, history[nhist - 1].post_data) + && (base = HText_getContentBase()) != 0) { + char *text = strncmp(history[nhist - 1].address, "LYNXIMGMAP:", 11) + ? history[nhist - 1].address + : history[nhist - 1].address + 11; + if (!strncmp(base, text, strlen(base))) { + /* + * Normal case - as best as we can check, the document at the top + * of the history stack seems to be the document the List Page is + * about (or a LYNXIMGMAP derived from it), and LYresubmit_posts is + * not set, so don't prompt here. If we actually have to repeat a + * POST because, against expectations, the underlying document + * isn't cached any more, HTAccess will prompt for confirmation, + * unless we had LYK_NOCACHE -kw + */ + return TRUE; + } + } + return FALSE; +} +#endif + PRIVATE int handle_LYK_ACTIVATE ARGS7( int *, c, int, cmd GCC_UNUSED, @@ -1173,34 +1223,7 @@ gettext("Enctype multipart/form-data not yet supported! Cannot submit.")); */ if ( 0==strcmp(curdoc.address, LYlist_temp_url()) && (LYIsListpageTitle(curdoc.title ? curdoc.title : ""))) { - if (!curdoc.post_data || - /* - * Normal case - List Page is not associated - * with post data. - kw - */ - (!LYresubmit_posts && curdoc.post_data && - history[nhist - 1].post_data && - !strcmp(curdoc.post_data, - history[nhist - 1].post_data) && - HText_getContentBase() && - !strncmp(HText_getContentBase(), - strncmp(history[nhist - 1].address, - "LYNXIMGMAP:", 11) ? - history[nhist - 1].address : - history[nhist - 1].address + 11, - strlen(HText_getContentBase())))) { - /* - * Normal case - as best as we can check, the - * document at the top of the history stack - * seems to be the document the List Page is - * about (or a LYNXIMGMAP derived from it), - * and LYresubmit_posts is not set, so don't - * prompt here. If we actually have to repeat - * a POST because, against expectations, the - * underlying document isn't cached any more, - * HTAccess will prompt for confirmation, - * unless we had LYK_NOCACHE. - kw - */ + if (check_history()) { LYinternal_flag = TRUE; } else { HTLastConfirmCancelled(); /* reset flag */ @@ -1532,13 +1555,13 @@ PRIVATE void handle_LYK_CLEAR_AUTH ARGS2( PRIVATE void handle_LYK_COMMENT ARGS4( BOOLEAN *, refresh_screen, - char *, owner_address, + char **, owner_address_p, int *, old_c, int, real_c) { int c; - if (!owner_address && + if (!*owner_address_p && strncasecomp(curdoc.address, "http", 4)) { if (*old_c != real_c) { *old_c = real_c; @@ -1551,7 +1574,7 @@ PRIVATE void handle_LYK_COMMENT ARGS4( } } else { if (HTConfirmDefault(CONFIRM_COMMENT, NO)) { - if (!owner_address) { + if (!*owner_address_p) { /* * No owner defined, so make a guess and * and offer it to the user. - FM @@ -1585,18 +1608,18 @@ PRIVATE void handle_LYK_COMMENT ARGS4( c = HTConfirmDefault(temp, NO); FREE(temp); if (c == YES) { - StrAllocCopy(owner_address, address); + StrAllocCopy(*owner_address_p, address); FREE(address); } else { FREE(address); return; } } - if (is_url(owner_address) != MAILTO_URL_TYPE) { + if (is_url(*owner_address_p) != MAILTO_URL_TYPE) { /* * The address is a URL. Just follow the link. */ - StrAllocCopy(newdoc.address, owner_address); + StrAllocCopy(newdoc.address, *owner_address_p); newdoc.internal_link = FALSE; } else { /* @@ -1616,15 +1639,15 @@ PRIVATE void handle_LYK_COMMENT ARGS4( } } - if (strchr(owner_address,':')!=NULL) + if (strchr(*owner_address_p,':')!=NULL) /* * Send a reply. The address is after the colon. */ - reply_by_mail(strchr(owner_address,':')+1, + reply_by_mail(strchr(*owner_address_p,':')+1, curdoc.address, (kp ? kp : ""), id); else - reply_by_mail(owner_address, curdoc.address, + reply_by_mail(*owner_address_p, curdoc.address, (kp ? kp : ""), id); FREE(tmptitle); @@ -2368,7 +2391,7 @@ PRIVATE void handle_LYK_DWIMHELP ARGS1( CONST char **, cshelpfile) { /* - * Currently a different help file form the main + * Currently a help file different from the main * 'helpfile' is shown only if current link is a * text input form field. - kw */ @@ -3166,9 +3189,8 @@ PRIVATE void handle_LYK_INDEX_SEARCH ARGS4( } } -PRIVATE BOOLEAN handle_LYK_INFO ARGS3( +PRIVATE BOOLEAN handle_LYK_INFO ARGS2( char *, prev_target, - char *, owner_address, int *, cmd) { /* @@ -4194,7 +4216,7 @@ PRIVATE void handle_LYK_SOFT_DQUOTES NOARGS * seek confirmation if the safe element is not set. - FM */ PRIVATE void handle_LYK_SOURCE ARGS1( - char **, ownerS_address) + char **, ownerS_address_p) { if ((curdoc.post_data != NULL && curdoc.safe != TRUE) && @@ -4211,7 +4233,7 @@ PRIVATE void handle_LYK_SOURCE ARGS1( #endif } else { if (HText_getOwner()) - StrAllocCopy(*ownerS_address, HText_getOwner()); + StrAllocCopy(*ownerS_address_p, HText_getOwner()); LYUCPushAssumed(HTMainAnchor); #ifdef USE_PSRC if (LYpsrc) @@ -4236,7 +4258,7 @@ PRIVATE void handle_LYK_SOURCE ARGS1( HTMark_asSource(); psrc_view = FALSE; #endif - FREE(*ownerS_address); /* not used with source_cache */ + FREE(*ownerS_address_p); /* not used with source_cache */ LYUCPopAssumed(); /* probably a right place here */ HTMLSetCharacterHandling(current_char_set); /* restore now */ @@ -4716,7 +4738,7 @@ PRIVATE void handle_LYK_WHEREIS ARGS3( /* * Force a redraw to ensure highlighting of hits * even when found on the same page, or clearing - * of highlighting is the default search string + * of highlighting if the default search string * was erased without replacement. - FM */ /* @@ -4783,34 +4805,7 @@ PRIVATE void handle_LYK_digit ARGS7( newdoc.internal_link = TRUE; if (LYIsListpageTitle(curdoc.title ? curdoc.title : "") && 0==strcmp(HTLoadedDocumentURL(), LYlist_temp_url())) { - if (!curdoc.post_data || - /* - * Normal case - List Page is not associated - * with post data. - kw - */ - (!LYresubmit_posts && curdoc.post_data && - history[nhist - 1].post_data && - !strcmp(curdoc.post_data, - history[nhist - 1].post_data) && - HText_getContentBase() && - !strncmp(HText_getContentBase(), - strncmp(history[nhist - 1].address, - "LYNXIMGMAP:", 11) ? - history[nhist - 1].address : - history[nhist - 1].address + 11, - strlen(HText_getContentBase())))) { - /* - * Normal case - as best as we can check, the - * document at the top of the history stack - * seems to be the document the List Page is - * about (or a LYNXIMGMAP derived from it), - * and LYresubmit_posts is not set, so don't - * prompt here. If we actually have to repeat - * a POST because, against expectations, the - * underlying document isn't cached any more, - * HTAccess will prompt for confirmation, - * unless we had LYK_NOCACHE. - kw - */ + if (check_history()) { LYinternal_flag = TRUE; } else { HTLastConfirmCancelled(); /* reset flag */ @@ -4984,8 +4979,6 @@ int mainloop NOARGS int arrowup = FALSE, show_help = FALSE; char prev_target[512]; char user_input_buffer[MAX_LINE]; - char *owner_address = NULL; /* Holds the responsible owner's address */ - char *ownerS_address = NULL; /* Holds owner's address during source fetch */ CONST char *cshelpfile = NULL; BOOLEAN first_file = TRUE; BOOLEAN popped_doc = FALSE; @@ -6037,6 +6030,7 @@ try_again: #ifndef NO_NONSTICKY_INPUTS textinput_drawn = FALSE; #endif + refresh_screen = FALSE; HText_pageDisplay(Newline, prev_target); @@ -6621,7 +6615,7 @@ new_cmd: /* case LYK_TO_CLIPBOARD: /* ^S */ { if (put_clip(links[curdoc.link].lname) == 0) { - HTInfoMsg("URL to Clip Borad."); + HTInfoMsg("URL to Clip Board."); } else { HTInfoMsg("Current URL is empty."); } @@ -6765,9 +6759,9 @@ new_cmd: /* if (handle_LYK_GOTO(&ch, user_input_buffer, &temp, &recall, &URLTotal, &URLNum, &FirstURLRecall, &old_c, real_c)) { - do_check_recall (ch, user_input_buffer, &temp, URLTotal, - &URLNum, recall, &FirstURLRecall); - do_check_goto_URL(user_input_buffer, &temp, &force_load); + if (do_check_recall (ch, user_input_buffer, &temp, URLTotal, + &URLNum, recall, &FirstURLRecall)) + do_check_goto_URL(user_input_buffer, &temp, &force_load); } break; @@ -6801,8 +6795,8 @@ new_cmd: /* handle_LYK_WHEREIS(cmd, prev_target, &refresh_screen); break; - case LYK_COMMENT: /* reply by mail */ - handle_LYK_COMMENT(&refresh_screen, owner_address, &old_c, real_c); + case LYK_COMMENT: /* reply by mail */ + handle_LYK_COMMENT(&refresh_screen, &owner_address, &old_c, real_c); break; #ifdef DIRED_SUPPORT @@ -6849,7 +6843,7 @@ new_cmd: /* #endif /* DIRED_SUPPORT && OK_INSTALL */ case LYK_INFO: /* show document info */ - if (handle_LYK_INFO(prev_target, owner_address, &cmd)) + if (handle_LYK_INFO(prev_target, &cmd)) goto new_cmd; break; @@ -6969,9 +6963,9 @@ new_cmd: /* if (handle_LYK_JUMP(c, user_input_buffer, &temp, &recall, &FirstURLRecall, &URLNum, &URLTotal, &ch, &old_c, real_c)) { - do_check_recall (ch, user_input_buffer, &temp, URLTotal, - &URLNum, recall, &FirstURLRecall); - do_check_goto_URL(user_input_buffer, &temp, &force_load); + if (do_check_recall (ch, user_input_buffer, &temp, URLTotal, + &URLNum, recall, &FirstURLRecall)) + do_check_goto_URL(user_input_buffer, &temp, &force_load); } break; diff --git a/src/LYMap.c b/src/LYMap.c index b74c743d..04cc663e 100644 --- a/src/LYMap.c +++ b/src/LYMap.c @@ -533,7 +533,7 @@ PRIVATE int LYLoadIMGmap ARGS4 ( sink, anAnchor); if (!target || target == NULL) { - HTSprintf(&buf, CANNOT_CONVERT_I_TO_O, + HTSprintf0(&buf, CANNOT_CONVERT_I_TO_O, HTAtom_name(format_in), HTAtom_name(format_out)); HTAlert(buf); FREE(buf); diff --git a/src/LYOptions.c b/src/LYOptions.c index ba1e2973..ab88556a 100644 --- a/src/LYOptions.c +++ b/src/LYOptions.c @@ -2592,7 +2592,7 @@ redraw: cmd = LYK_QUIT; #ifndef USE_SLANG } else if (c == MOUSE_KEY) { - if ((cmd = fancy_mouse(form_window, i + 1 + window_offset, &cur_choice)) < 0) + if ((cmd = fancy_mouse(form_window, i + 1 - window_offset, &cur_choice)) < 0) goto redraw; if (cmd == LYK_ACTIVATE) break; diff --git a/src/LYPrettySrc.c b/src/LYPrettySrc.c index f7e5538c..3b279c8b 100644 --- a/src/LYPrettySrc.c +++ b/src/LYPrettySrc.c @@ -6,6 +6,10 @@ #include <LYHash.h> #include <LYPrettySrc.h> + /* This file creates too many "leak detected" entries in Lynx.leaks. */ +#define NO_MEMORY_TRACKING +#include <LYLeaks.h> + #ifdef USE_PSRC BOOL psrc_convert_string = FALSE; PUBLIC BOOL psrc_view = FALSE;/* this is read by SGML_put_character - TRUE @@ -21,7 +25,7 @@ PUBLIC BOOL mark_htext_as_source=FALSE; support), the style cache and markup are created before entering the mainloop. */ PUBLIC BOOL psrcview_no_anchor_numbering = FALSE; -PUBLIC char* HTL_tagspecs[HTL_num_lexems] = { +PRIVATE char* HTL_tagspecs_defaults[HTL_num_lexemes] = { /* these values are defaults. They are also listed in comments of distibution's lynx.cfg.*/ #ifdef USE_COLOR_STYLE @@ -38,26 +42,27 @@ PUBLIC char* HTL_tagspecs[HTL_num_lexems] = { "span.htmlsrc_badattr:!span", "span.htmlsrc_sgmlspecial:!span" #else - "b:!b", - "b:!b", - ":", - "!b:b", - "b:!b", - "b:!b", - ":", - ":", - "b:!b", - ":", - "!b:b", - "b:!b" + "b:!b", /* comment */ + "b:!b", /* tag */ + "b:!b", /* attrib */ + ":", /* attrval */ + "b:!b", /* abracket*/ + "b:!b", /* entity */ + ":", /* href */ + ":", /* entire */ + "b:!b", /* badseq */ + ":", /* badtag */ + ":", /* badattr */ + "b:!b" /* sgmlspec*/ #endif }; +PUBLIC char* HTL_tagspecs[HTL_num_lexemes]; /* these are pointers since tagspec can be empty (the pointer will be NULL in that case) */ -PUBLIC HT_tagspec* lexem_start[HTL_num_lexems]; -PUBLIC HT_tagspec* lexem_end[HTL_num_lexems]; +PUBLIC HT_tagspec* lexeme_start[HTL_num_lexemes]; +PUBLIC HT_tagspec* lexeme_end[HTL_num_lexemes]; PUBLIC int tagname_transform = 2; PUBLIC int attrname_transform = 2; @@ -102,6 +107,9 @@ PRIVATE void append_close_tag ARGS3( subj->present = (BOOL*)calloc( nattr*sizeof (BOOL), 1); subj->value = (char**)calloc( nattr*sizeof (char*), 1); subj->start = FALSE; +#ifdef USE_COLOR_STYLE + subj->class_name = NULL; +#endif if (!*head) { *head = subj; *tail = subj; @@ -150,17 +158,16 @@ PRIVATE void append_open_tag ARGS4( hcode = hash_code_aggregate_lower_str(classname, hcode); StrAllocCopy(subj->class_name, classname); } else { - subj->class_name = ""; + StrAllocCopy(subj->class_name,""); } subj->style = hcode; #endif } - /* returns 1 if incorrect */ PUBLIC int html_src_parse_tagspec ARGS4( char*, ts, - HTlexem, lexem, + HTlexeme, lexeme, BOOL, checkonly, BOOL, isstart) { @@ -172,7 +179,7 @@ PUBLIC int html_src_parse_tagspec ARGS4( char stop = FALSE, after_excl = FALSE; html_src_check_state state = HTSRC_CK_normal; HT_tagspec* head = NULL, *tail = NULL; - HT_tagspec** slot = ( isstart ? lexem_start : lexem_end ) +lexem; + HT_tagspec** slot = ( isstart ? lexeme_start : lexeme_end ) +lexeme; while (!stop) { switch (state) { @@ -190,7 +197,7 @@ PUBLIC int html_src_parse_tagspec ARGS4( default: if (isalpha(*p) || *p == '_') { tagstart = p; - while (*p && ( isalpha(*p) || *p == '_') ) + while (*p && ( isalnum(*p) || *p == '_') ) ++p; tagend = p; state = HTSRC_CK_after_tagname; @@ -243,7 +250,7 @@ PUBLIC int html_src_parse_tagspec ARGS4( char save, save1; if ( isalpha(*p) || *p == '_' ) { classstart = p; - while (*p && ( isalpha(*p) || *p == '_') ) ++p; + while (*p && ( isalnum(*p) || *p == '_') ) ++p; classend = p; save = *classend; *classend = '\0'; @@ -274,26 +281,67 @@ PUBLIC int html_src_parse_tagspec ARGS4( return 0; } -/*it shouldn't fail anyway - since everything is checked before it's called. */ -PUBLIC void HTMLSRC_init_caches NOARGS +/*this will clean the data associated with lexeme 'l' */ +PUBLIC void html_src_clean_item ARGS1( + HTlexeme, l) +{ + int i; + if (HTL_tagspecs[l]) + FREE(HTL_tagspecs[l]); + for(i = 0; i < 2; ++i) { + HT_tagspec* cur,** pts = ( i ? lexeme_start : lexeme_end)+l,*ts = *pts; + *pts = NULL; + while (ts) { + FREE(ts->present); + FREE(ts->value); +#ifdef USE_COLOR_STYLE + if (ts->start) { + FREE(ts->class_name); + } +#endif + cur = ts; + ts = ts->next; + FREE(cur); + } + } +} + +/*this will be registered with atexit*/ +PUBLIC void html_src_clean_data NOARGS +{ + int i; + for (i = 0; i < HTL_num_lexemes; ++i) + html_src_clean_item(i); +} + +PUBLIC void html_src_on_lynxcfg_reload NOARGS +{ + html_src_clean_data(); + HTMLSRC_init_caches(TRUE); +} + +PUBLIC void HTMLSRC_init_caches ARGS1( + BOOL, dont_exit) { int i; char* p; char buf[1000]; - for (i = 0; i < HTL_num_lexems; ++i) { - if (HTL_tagspecs[i]) - strcpy(buf, HTL_tagspecs[i]); - else - buf[0] = '\0'; + for (i = 0; i < HTL_num_lexemes; ++i) { + + strcpy(buf, HTL_tagspecs_defaults[i]); + p = HTL_tagspecs_defaults[i]; + HTL_tagspecs[i] = NULL; + StrAllocCopy(HTL_tagspecs[i],p); + if ((p = strchr(buf, ':')) != 0) *p = '\0'; - if (html_src_parse_tagspec(buf, i, FALSE, TRUE) ) { - fprintf(stderr, "internal error while caching 1st tagspec of %d lexem", i); + if (html_src_parse_tagspec(buf, i, FALSE, TRUE) && !dont_exit ) { + fprintf(stderr, "internal error while caching 1st tagspec of %d lexeme", i); exit_immediately(-1); } - if (html_src_parse_tagspec( p ? p+1 : NULL , i, FALSE, FALSE) ) { - fprintf(stderr, "internal error while caching 2nd tagspec of %d lexem", i); + if (html_src_parse_tagspec( p ? p+1 : NULL , i, FALSE, FALSE) && !dont_exit) { + fprintf(stderr, "internal error while caching 2nd tagspec of %d lexeme", i); exit_immediately(-1); } } diff --git a/src/LYPrettySrc.h b/src/LYPrettySrc.h index e49b3fd8..02a8f75f 100644 --- a/src/LYPrettySrc.h +++ b/src/LYPrettySrc.h @@ -23,8 +23,8 @@ extern BOOL psrc_first_tag; /* this is also used in HTML.c to trigger the extern BOOL mark_htext_as_source; -/* here is a list of lexem codes. */ -typedef enum _HTlexem { +/* here is a list of lexeme codes. */ +typedef enum _HTlexeme { HTL_comm=0, HTL_tag, HTL_attrib, @@ -37,8 +37,8 @@ typedef enum _HTlexem { HTL_badtag, HTL_badattr, HTL_sgmlspecial, - HTL_num_lexems -} HTlexem; + HTL_num_lexemes +} HTlexeme; typedef struct _HT_tagspec { @@ -55,13 +55,16 @@ typedef struct _HT_tagspec BOOL start; /* if true, then this starts element, otherwise - ends */ } HT_tagspec; -extern char* HTL_tagspecs[HTL_num_lexems]; -extern HT_tagspec* lexem_start[HTL_num_lexems]; -extern HT_tagspec* lexem_end[HTL_num_lexems]; +extern char* HTL_tagspecs[HTL_num_lexemes]; +extern HT_tagspec* lexeme_start[HTL_num_lexemes]; +extern HT_tagspec* lexeme_end[HTL_num_lexemes]; -extern int html_src_parse_tagspec PARAMS((char* ts, HTlexem lexem, +extern int html_src_parse_tagspec PARAMS((char* ts, HTlexeme lexeme, BOOL checkonly,BOOL isstart)); -extern void HTMLSRC_init_caches NOPARAMS; +extern void HTMLSRC_init_caches PARAMS((BOOL dont_exit)); +extern void html_src_clean_item PARAMS((HTlexeme l)); +extern void html_src_clean_data NOPARAMS; +extern void html_src_on_lynxcfg_reload NOPARAMS; /* these 2 vars tell what kind of transform should be appiled to tag names and attribute names. 0 - lowercase, 1 - as is, 2 uppercase. */ diff --git a/src/LYPrint.c b/src/LYPrint.c index 03ea1b04..6f660812 100644 --- a/src/LYPrint.c +++ b/src/LYPrint.c @@ -770,12 +770,13 @@ PRIVATE void send_file_to_mail ARGS3( if (keypad_mode) printlist(outfile_fp, FALSE); +#if defined(WIN_EX) || defined(__DJGPP__) #if defined(WIN_EX) /* 1998/08/17 (Mon) 16:29:49 */ - buffer = NULL; if (mail_is_blat) HTSprintf0(&buffer, "%s %s -t \"%s\"", system_mail, my_temp, user_response); else +#endif /* WIN_EX */ HTSprintf0(&buffer, "%s -t \"%s\" -F %s", system_mail, user_response, my_temp); LYCloseTempFP(outfile_fp); /* Close the tmpfile. */ @@ -789,9 +790,9 @@ PRIVATE void send_file_to_mail ARGS3( SetOutputMode( O_BINARY ); LYRemoveTemp(my_temp); /* Delete the tmpfile. */ -#else /* !WIN_EX */ +#else /* !WIN_EX && !__DJGPP__ */ pclose(outfile_fp); -#endif +#endif /* WIN_EX || __DJGPP__ */ #endif /* VMS */ done: /* send_file_to_mail() */ diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c index 2d47628e..e3adb938 100644 --- a/src/LYReadCFG.c +++ b/src/LYReadCFG.c @@ -659,6 +659,20 @@ static int keymap_fun ARGS1( BOOLEAN success = FALSE; int lkc = lkcstring_to_lkc(key); int lec = -1; + /* + * PASS! tries to enter the key into the LYLineEditors + * bindings in a different way from PASS, namely as + * binding that maps to the specific lynx actioncode + * (rather than to LYE_FORM_PASS). That only works + * for lynx keycodes with modifier bit set, and we + * have no documented/official way to specify this + * in the KEYMAP directive, although it can be made + * to work e.g. by specifying a hex value that has the + * modifier bit set. But knowledge about the bit + * pattern of modifiers should remain in internal + * matter subject to change... At any rate, if + * PASS! fails try it the same way as for PASS. - kw + */ if (strcasecomp(efunc, "PASS!") == 0) { if (func) { lec = LYE_FORM_LAC|lacname_to_lac(func); @@ -1090,7 +1104,7 @@ static void html_src_bad_syntax ARGS2( static int parse_html_src_spec ARGS3( - HTlexem, lexem_code, + HTlexeme, lexeme_code, char*, value, char*, option_name) { @@ -1109,16 +1123,17 @@ static int parse_html_src_spec ARGS3( BS(); *ts2 = '\0'; - if ( html_src_parse_tagspec(value, lexem_code, TRUE, TRUE) - || html_src_parse_tagspec(ts2, lexem_code, TRUE, TRUE) ) + CTRACE((tfp,"ReadCFG - parsing tagspec '%s:%s' for option '%s'\n",value,ts2,option_name)); + html_src_clean_item(lexeme_code); + if ( html_src_parse_tagspec(value, lexeme_code, FALSE, TRUE) + || html_src_parse_tagspec(ts2, lexeme_code, FALSE, FALSE) ) { *ts2 = ':'; BS(); } *ts2 = ':'; - HTL_tagspecs[lexem_code] = NULL; - StrAllocCopy(HTL_tagspecs[lexem_code],value); + StrAllocCopy(HTL_tagspecs[lexeme_code],value); #undef BS return 0; } @@ -1253,9 +1268,7 @@ static Config_Type Config_Table [] = PARSE_SET("focus_window", CONF_BOOL, &focus_window), #endif PARSE_SET("force_8bit_toupper", CONF_BOOL, &UCForce8bitTOUPPER), -#ifndef NO_EMPTY_HREFLESS_A PARSE_SET("force_empty_hrefless_a", CONF_BOOL, &force_empty_hrefless_a), -#endif PARSE_SET("force_ssl_cookies_secure", CONF_BOOL, &LYForceSSLCookiesSecure), #if !defined(NO_OPTION_FORMS) && !defined(NO_OPTION_MENU) PARSE_SET("forms_options", CONF_BOOL, &LYUseFormsOptions), diff --git a/src/LYStrings.c b/src/LYStrings.c index a4a7fe29..dd55c262 100644 --- a/src/LYStrings.c +++ b/src/LYStrings.c @@ -263,17 +263,32 @@ PRIVATE int XYdist ARGS5( int, y2, int, dx2) { - int xerr = x2 - x1, yerr = y2 - y1; + int xerr = 3 * (x2 - x1), yerr = 9 * (y2 - y1); if (xerr < 0) - xerr = x1 - x2 - dx2; + xerr = 3 * (x1 - x2 - dx2) + 1; /* pos after string not really in it */ if (xerr < 0) xerr = 0; if (yerr < 0) yerr = -yerr; - if (xerr < 3 && yerr) /* x-distance of 3 better than y-dist of 1 */ - return yerr + 1; - return (xerr + 2)/3 + yerr; /* Subjective factor of distance */ + if (!yerr) /* same line is good */ + return (xerr > 0) ? (xerr*2 - 1) : 0; + if (xerr < 9 && yerr) /* x-dist of 3 cell better than y-dist of 1 cell */ + yerr += (9 - xerr); + return 2 * xerr + yerr; /* Subjective factor; ratio -> approx. 6 / 9 */ +/* +old: (IZ 1999-07-30) + 3 2 2 2 1 1 1 XX XX XX XX XX 0 1 1 1 2 2 2 3 3 + 4\ 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3/ 4 4 + 5 4 4 4\ 3 3 3 3 3 3 3 3 3 3 3 3/ 4 4 4 5 5 + 6 5 5 5 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 6 5 +now: (kw 1999-10-23) +41 35 29|23 17 11 5 XX XX XX XX XX 1 7 13 19 25|31 37 43 49 + 45 39 33\27 24 21 18 18 18 18 18 19 22 25 28/34 40 46 50 + 48 42 36 33 30\27 27 27 27 27 28/31 34 37 43 49 + 51 45 42 39 36 36 36 36 36 37 40 43 46 49 + 51 48 45 45 45 45 45 46 49 52 +*/ } /* Given X and Y coordinates of a mouse event, set mouse_link to the @@ -312,9 +327,9 @@ PRIVATE int set_clicked_link ARGS4( mouse_link = -2; y -= 1 + (LYsb_arrow != 0); if (y < 0) - return INSERT_KEY; + return LAC_TO_LKC0(LYK_UP_TWO); if (y >= h) - return REMOVE_KEY; + return LAC_TO_LKC0(LYK_DOWN_TWO); #ifdef DISP_PARTIAL /* Newline is not defined otherwise */ if (clicks >= 2) { double frac = (1. * y)/(h - 1); @@ -327,13 +342,13 @@ PRIVATE int set_clicked_link ARGS4( } #endif if (y < LYsb_begin) - return PGUP; + return LAC_TO_LKC0(LYK_PREV_PAGE); if (y >= LYsb_end) - return PGDOWN; + return LAC_TO_LKC0(LYK_NEXT_PAGE); mouse_link = -1; /* No action in edit fields */ #endif } else { - int mouse_err = 4, /* subjctv-dist better than this for approx stuff */ + int mouse_err = 29, /* subjctv-dist better than this for approx stuff */ cur_err; /* Loop over the links and see if we can get a match */ @@ -355,6 +370,18 @@ PRIVATE int set_clicked_link ARGS4( /* Check the first line of the link */ if ( links[i].hightext != NULL) { cur_err = XYdist(x, y, links[i].lx, links[i].ly, len); + /* Check the second line */ + if (cur_err > 0 && links[i].hightext2 != NULL) { + /* Note that there is never hightext2 if is_text */ + int cur_err_2 = XYdist(x, y, + links[i].hightext2_offset, + links[i].ly+1, + strlen(links[i].hightext2)); + cur_err = HTMIN(cur_err, cur_err_2); + } + if (cur_err > 0 && is_text) + cur_err--; /* a bit of preference for text fields, + enter field if hit exactly at end - kw */ if (cur_err == 0) { int cury, curx; @@ -390,6 +417,7 @@ PRIVATE int set_clicked_link ARGS4( mouse_link = i; } } +#if 0 /* should not have second line if no first - kw */ /* Check the second line */ if (links[i].hightext2 != NULL) { cur_err = XYdist(x, y, @@ -405,6 +433,7 @@ PRIVATE int set_clicked_link ARGS4( mouse_link = i; } } +#endif } /* * If a link was hit, we must look for a key which will activate @@ -525,10 +554,13 @@ PUBLIC char * LYmbcs_skip_glyphs ARGS3( * LYmbcsstrlen() returns the printable length of a string * that might contain IsSpecial or multibyte (CJK or UTF8) * characters. - FM + * Counts glyph cells if count_gcells is set. (Full-width + * characters in CJK mode count as two.) */ -PUBLIC int LYmbcsstrlen ARGS2( - char *, str, - BOOL, utf_flag) +PUBLIC int LYmbcsstrlen ARGS3( + char *, str, + BOOL, utf_flag, + BOOL, count_gcells) { int i, j, len = 0; @@ -550,10 +582,6 @@ PUBLIC int LYmbcsstrlen ARGS2( i++; j++; } - } else if (!utf_flag && HTCJK != NOCJK && !isascii(str[i]) && - str[(i + 1)] != '\0' && - !IsSpecialAttrChar(str[(i + 1)])) { - i++; } } @@ -1129,26 +1157,43 @@ PRIVATE int read_keymap_file NOARGS PRIVATE void setup_vtXXX_keymap NOARGS { static Keysym_String_List table[] = { - EXTERN_KEY( "\033[A", "^(ku)", UPARROW, KEY_UP ), - EXTERN_KEY( "\033OA", "^(ku)", UPARROW, KEY_UP ), - EXTERN_KEY( "\033[B", "^(kd)", DNARROW, KEY_DOWN ), - EXTERN_KEY( "\033OB", "^(kd)", DNARROW, KEY_DOWN ), - EXTERN_KEY( "\033[C", "^(kr)", RTARROW, KEY_RIGHT ), - EXTERN_KEY( "\033OC", "^(kr)", RTARROW, KEY_RIGHT ), - EXTERN_KEY( "\033[D", "^(kl)", LTARROW, KEY_LEFT ), - EXTERN_KEY( "\033OD", "^(kl)", LTARROW, KEY_LEFT ), - EXTERN_KEY( "\033[1~", "^(@0)", FIND_KEY, KEY_FIND ), - EXTERN_KEY( "\033[2~", "^(kI)", INSERT_KEY, KEY_IC ), - EXTERN_KEY( "\033[3~", "^(kD)", REMOVE_KEY, KEY_DC ), - EXTERN_KEY( "\033[4~", "^(*6)", SELECT_KEY, KEY_SELECT ), - EXTERN_KEY( "\033[5~", "^(kP)", PGUP, KEY_PPAGE ), - EXTERN_KEY( "\033[6~", "^(kN)", PGDOWN, KEY_NPAGE ), - EXTERN_KEY( "\033[8~", "^(@7)", END_KEY, KEY_END ), - EXTERN_KEY( "\033[7~", "^(kh)", HOME, KEY_HOME), - EXTERN_KEY( "\033[28~", "^(k1)", F1, KEY_F(1) ), - EXTERN_KEY( "\033OP", "^(k1)", F1, KEY_F(1) ), - EXTERN_KEY( "\033[OP", "^(k1)", F1, KEY_F(1) ), - EXTERN_KEY( "\033[29~", "^(F6)", DO_KEY, KEY_F(16) ), + INTERN_KEY( "\033[A", UPARROW, KEY_UP ), + INTERN_KEY( "\033OA", UPARROW, KEY_UP ), + INTERN_KEY( "\033[B", DNARROW, KEY_DOWN ), + INTERN_KEY( "\033OB", DNARROW, KEY_DOWN ), + INTERN_KEY( "\033[C", RTARROW, KEY_RIGHT ), + INTERN_KEY( "\033OC", RTARROW, KEY_RIGHT ), + INTERN_KEY( "\033[D", LTARROW, KEY_LEFT ), + INTERN_KEY( "\033OD", LTARROW, KEY_LEFT ), + INTERN_KEY( "\033[1~", FIND_KEY, KEY_FIND ), + INTERN_KEY( "\033[2~", INSERT_KEY, KEY_IC ), + INTERN_KEY( "\033[3~", REMOVE_KEY, KEY_DC ), + INTERN_KEY( "\033[4~", SELECT_KEY, KEY_SELECT ), + INTERN_KEY( "\033[5~", PGUP, KEY_PPAGE ), + INTERN_KEY( "\033[6~", PGDOWN, KEY_NPAGE ), + INTERN_KEY( "\033[7~", HOME, KEY_HOME), + INTERN_KEY( "\033[8~", END_KEY, KEY_END ), + INTERN_KEY( "\033[11~", F1, KEY_F(1) ), + INTERN_KEY( "\033[28~", F1, KEY_F(1) ), + INTERN_KEY( "\033OP", F1, KEY_F(1) ), + INTERN_KEY( "\033[OP", F1, KEY_F(1) ), + INTERN_KEY( "\033[29~", DO_KEY, KEY_F(16) ), +#if defined(USE_SLANG) && !defined(VMS) + INTERN_KEY( "^(ku)", UPARROW, KEY_UP ), + INTERN_KEY( "^(kd)", DNARROW, KEY_DOWN ), + INTERN_KEY( "^(kr)", RTARROW, KEY_RIGHT ), + INTERN_KEY( "^(kl)", LTARROW, KEY_LEFT ), + INTERN_KEY( "^(@0)", FIND_KEY, KEY_FIND ), + INTERN_KEY( "^(kI)", INSERT_KEY, KEY_IC ), + INTERN_KEY( "^(kD)", REMOVE_KEY, KEY_DC ), + INTERN_KEY( "^(*6)", SELECT_KEY, KEY_SELECT ), + INTERN_KEY( "^(kP)", PGUP, KEY_PPAGE ), + INTERN_KEY( "^(kN)", PGDOWN, KEY_NPAGE ), + INTERN_KEY( "^(@7)", END_KEY, KEY_END ), + INTERN_KEY( "^(kh)", HOME, KEY_HOME), + INTERN_KEY( "^(k1)", F1, KEY_F(1) ), + INTERN_KEY( "^(F6)", DO_KEY, KEY_F(16) ), +#endif /* SLANG && !VMS */ }; size_t n; for (n = 0; n < TABLESIZE(table); n++) @@ -3475,8 +3520,13 @@ PUBLIC char * LYno_attr_char_strstr ARGS2( * LYno_attr_mbcs_case_strstr will find the first occurrence of the string * pointed to by tarptr in the string pointed to by chptr. * It takes account of MultiByte Character Sequences (UTF8). - * The physical length of the displayed string up to the end of the target - * string is returned in *nendp if the search is successful. + * The physical lengths of the displayed string up to the start and + * end (= next position after) of the target string are returned in *nstartp + * and *nendp if the search is successful. + * These lengths count glyph cells if count_gcells is set. (Full-width + * characters in CJK mode count as two.) Normally that's what we want. + * They count actual glyphs if count_gcells is unset. (Full-width + * characters in CJK mode count as one.) * It ignores the characters: LY_UNDERLINE_START_CHAR and * LY_UNDERLINE_END_CHAR * LY_BOLD_START_CHAR @@ -3486,10 +3536,11 @@ PUBLIC char * LYno_attr_char_strstr ARGS2( * It assumes UTF8 if utf_flag is set. * It is a case insensitive search. - KW & FM */ -PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5( +PUBLIC char * LYno_attr_mbcs_case_strstr ARGS6( char *, chptr, CONST char *, tarptr, BOOL, utf_flag, + BOOL, count_gcells, int *, nstartp, int *, nendp) { @@ -3547,6 +3598,7 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5( */ tmpchptr++; tmptarptr++; + if (count_gcells) tarlen++; if (*tmptarptr == '\0') { /* * One character match. - FM @@ -3555,13 +3607,13 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5( if (nendp) *nendp = len + tarlen; return(chptr); } - tarlen++; } else { /* * It's not a match, so go back to * seeking a first target match. - FM */ chptr++; + if (count_gcells) len++; continue; } } @@ -3576,6 +3628,7 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5( !IsSpecialAttrChar(*(tmpchptr + 1))) { tmpchptr++; tmptarptr++; + if (count_gcells) tarlen++; } else { break; } @@ -3607,6 +3660,7 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5( *(chptr + 1) != '\0' && !IsSpecialAttrChar(*(chptr + 1))) { chptr++; + if (count_gcells) len++; } len++; } @@ -3620,8 +3674,12 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5( * pointed to by tarptr in the string pointed to by chptr. * It takes account of CJK and MultiByte Character Sequences (UTF8). * The physical lengths of the displayed string up to the start and - * end of the target string are returned in *nstartp and *nendp if - * the search is successful. + * end (= next position after) the target string are returned in *nstartp + * and *nendp if the search is successful. + * These lengths count glyph cells if count_gcells is set. (Full-width + * characters in CJK mode count as two.) Normally that's what we want. + * They count actual glyphs if count_gcells is unset. (Full-width + * characters in CJK mode count as one.) * It ignores the characters: LY_UNDERLINE_START_CHAR and * LY_UNDERLINE_END_CHAR * LY_BOLD_START_CHAR @@ -3631,10 +3689,11 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5( * It assumes UTF8 if utf_flag is set. * It is a case sensitive search. - KW & FM */ -PUBLIC char * LYno_attr_mbcs_strstr ARGS5( +PUBLIC char * LYno_attr_mbcs_strstr ARGS6( char *, chptr, CONST char *, tarptr, BOOL, utf_flag, + BOOL, count_gcells, int *, nstartp, int *, nendp) { @@ -3672,7 +3731,7 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5( * One char target. */ if (nstartp) *nstartp = offset; - if (nendp) *nendp = len + 1; + if (nendp) *nendp = len; return(chptr); } if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) && @@ -3687,6 +3746,7 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5( */ tmpchptr++; tmptarptr++; + if (count_gcells) tarlen++; if (*tmptarptr == '\0') { /* * One character match. - FM @@ -3695,13 +3755,13 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5( if (nendp) *nendp = len + tarlen; return(chptr); } - tarlen++; } else { /* * It's not a match, so go back to * seeking a first target match. - FM */ chptr++; + if (count_gcells) len++; continue; } } @@ -3716,6 +3776,7 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5( !IsSpecialAttrChar(*(tmpchptr + 1))) { tmpchptr++; tmptarptr++; + if (count_gcells) tarlen++; } else { break; } @@ -3746,6 +3807,7 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5( *(chptr + 1) != '\0' && !IsSpecialAttrChar(*(chptr + 1))) { chptr++; + if (count_gcells) len++; } len++; } diff --git a/src/LYStrings.h b/src/LYStrings.h index e836c6a4..ac85f315 100644 --- a/src/LYStrings.h +++ b/src/LYStrings.h @@ -44,17 +44,20 @@ extern char * LYmbcs_skip_glyphs PARAMS(( BOOL utf_flag)); extern int LYmbcsstrlen PARAMS(( char * str, - BOOL utf_flag)); + BOOL utf_flag, + BOOL count_gcells)); extern char * LYno_attr_mbcs_strstr PARAMS(( char * chptr, CONST char * tarptr, BOOL utf_flag, + BOOL count_gcells, int * nstartp, int * nendp)); extern char * LYno_attr_mbcs_case_strstr PARAMS(( char * chptr, CONST char * tarptr, BOOL utf_flag, + BOOL count_gcells, int * nstartp, int * nendp)); extern char * LYno_attr_char_strstr PARAMS(( diff --git a/src/LYUtils.c b/src/LYUtils.c index 4d30777d..de1c7112 100644 --- a/src/LYUtils.c +++ b/src/LYUtils.c @@ -337,7 +337,7 @@ PUBLIC void highlight ARGS3( utf_flag); hlen = strlen(buffer); hLen = ((HTCJK != NOCJK || utf_flag) ? - LYmbcsstrlen(buffer, utf_flag) : hlen); + LYmbcsstrlen(buffer, utf_flag, YES) : hlen); /* * Break out if the first hit in the line @@ -359,12 +359,12 @@ PUBLIC void highlight ARGS3( if ((case_sensitive ? (cp = LYno_attr_mbcs_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL : (cp = LYno_attr_mbcs_case_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL) && (offset + LenNeeded) < LYcols) { @@ -607,12 +607,12 @@ PUBLIC void highlight ARGS3( if ((case_sensitive ? (cp = LYno_attr_mbcs_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL : (cp = LYno_attr_mbcs_case_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL) && (offset + LenNeeded) < LYcols) { @@ -886,12 +886,12 @@ highlight_hit_within_hightext: if ((case_sensitive ? (cp = LYno_attr_mbcs_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL : (cp = LYno_attr_mbcs_case_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL) && (offset + LenNeeded) < LYcols) { @@ -1067,7 +1067,7 @@ highlight_search_hightext2: utf_flag); hlen = strlen(buffer); hLen = ((HTCJK != NOCJK || utf_flag) ? - LYmbcsstrlen(buffer, utf_flag) : hlen); + LYmbcsstrlen(buffer, utf_flag, YES) : hlen); /* * Break out if the first hit in the line @@ -1089,12 +1089,12 @@ highlight_search_hightext2: if ((case_sensitive ? (cp = LYno_attr_mbcs_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL : (cp = LYno_attr_mbcs_case_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL) && (offset + LenNeeded) < LYcols) { @@ -1336,12 +1336,12 @@ highlight_search_hightext2: if ((case_sensitive ? (cp = LYno_attr_mbcs_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL : (cp = LYno_attr_mbcs_case_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL) && (offset + LenNeeded) < LYcols) { @@ -1615,12 +1615,12 @@ highlight_hit_within_hightext2: if ((case_sensitive ? (cp = LYno_attr_mbcs_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL : (cp = LYno_attr_mbcs_case_strstr(data, target, - utf_flag, + utf_flag, YES, &HitOffset, &LenNeeded)) != NULL) && (offset + LenNeeded) < LYcols) { @@ -4665,6 +4665,9 @@ have_VMS_URL: } else if (fixit) { /* RW 1998Mar16 Restore AllocatedString to 'old_string' */ StrAllocCopy(*AllocatedString, old_string); + } else { + /* Return file URL for the file that does not exist */ + StrAllocCat(*AllocatedString, temp); } #ifdef WIN_EX Retry: @@ -6478,10 +6481,10 @@ PUBLIC FILE *LYOpenTempRewrite ARGS3( if (registered) { #ifndef NO_GROUPS writable_exists = HTEditable(fname); /* existing, can write */ -#define CTRACE_EXISTS "exists and is writable" +#define CTRACE_EXISTS "exists and is writable, " #else writable_exists = (BOOL) (stat(fname, &stat_buf) == 0); /* existing, assume can write */ -#define CTRACE_EXISTS "exists" +#define CTRACE_EXISTS "exists, " #endif if (writable_exists) { @@ -6508,46 +6511,25 @@ PUBLIC FILE *LYOpenTempRewrite ARGS3( * This should probably not happen. Make a new one. */ return (LYOpenTemp(fname, suffix, mode)); - } else if (is_ours) { + } else if (!registered) { /* - * Yes, it exists, is writable if we checked, and everything - * looks ok so far. This should be the most regular case. - * We truncate and then append, this avoids having a small - * window in which the file doesn't exist. - kw + * Not registered. It should have been registered at one point + * though, otherwise we wouldn't be called like this. */ -#if HAVE_TRUNCATE - if (truncate(fname, 0) != 0) { - CTRACE((tfp, "... truncate(%s,0) failed: %s\n", - fname, LYStrerror(errno))); - return (LYOpenTemp(fname, suffix, mode)); - } -#endif - return (LYReopenTemp(fname)); - } else if (writable_exists) { + return (LYOpenTemp(fname, suffix, mode)); + } else if (writable_exists && !is_ours) { /* * File exists, writable if we checked, but something is wrong * with it. */ return (LYOpenTemp(fname, suffix, mode)); #ifndef NO_GROUPS - } else if (registered && (lstat(fname, &stat_buf) == 0)) { + } else if (!is_ours && (lstat(fname, &stat_buf) == 0)) { /* * Exists but not writable, and something is wrong with it. */ return (LYOpenTemp(fname, suffix, mode)); #endif - } else if (!registered) { - /* - * Not registered. It should have been registered at one point - * though, otherwise we wouldn't be called like this. - */ - return (LYOpenTemp(fname, suffix, mode)); - } else { - /* - * File does not exist, but is registered as a temp file. - * It must have been removed by some means other than - * LYRemoveTemp. Reuse the name! - */ } while (*mode != '\0') { @@ -6561,6 +6543,38 @@ PUBLIC FILE *LYOpenTempRewrite ARGS3( } } + if (is_ours) { + /* + * Yes, it exists, is writable if we checked, and everything + * looks ok so far. This should be the most regular case. - kw + */ +#if HAVE_TRUNCATE + if (txt == TRUE) { /* limitation of LYReopenTemp. shrug */ + /* + * We truncate and then append, this avoids having a small + * window in which the file doesn't exist. - kw + */ + if (truncate(fname, 0) != 0) { + CTRACE((tfp, "... truncate(%s,0) failed: %s\n", + fname, LYStrerror(errno))); + return (LYOpenTemp(fname, suffix, mode)); + } else { + return (LYReopenTemp(fname)); + } + } +#endif + remove(fname); + + } + + /* We come here in two cases: either the file existed and was + * ours and we just got rid of it. + * Or the file did and does not exist, but is registered as a + * temp file. It must have been removed by some means other than + * LYRemoveTemp. + * In both cases, reuse the name! - kw + */ + if (txt) { switch (wrt) { case 'w': diff --git a/src/TRSTable.c b/src/TRSTable.c index 3545fdb8..7e65fc2f 100644 --- a/src/TRSTable.c +++ b/src/TRSTable.c @@ -17,6 +17,9 @@ #define ROWS_GROWBY 2 #define MAX_STBL_POS (LYcols-1) +/* must be different from HT_ALIGN_NONE and HT_LEFT, HT_CENTER etc.: */ +#define RESERVEDCELL (-2) /* cell's alignment field is overloaded, this + value means cell was reserved by ROWSPAN */ typedef enum { CS_invalid = -1, CS_new = 0, @@ -48,7 +51,8 @@ typedef struct _STable_cellinfo { int pos; /* column where cell starts */ int len; /* number of character positions */ int colspan; /* number of columns to span */ - short alignment; /* one of HT_LEFT, HT_CENTER, HT_RIGHT */ + short alignment; /* one of HT_LEFT, HT_CENTER, HT_RIGHT, + or RESERVEDCELL */ } STable_cellinfo; typedef struct _STable_rowinfo { @@ -69,9 +73,13 @@ struct _STable_info { int maxpos; /* max. of max. cell pos's of any row */ int allocated_rows; /* number of rows allocated */ int allocated_sumcols; /* number of sumcols allocated */ + int ncolinfo; /* number of COL info collected */ STable_cellinfo * sumcols; /* for summary (max len/pos) col info */ STable_rowinfo * rows; short alignment; /* global align attribute for this table */ + short rowgroup_align; /* align default for current group of rows */ + short pending_colgroup_align; + int pending_colgroup_next; STable_states s; }; @@ -103,14 +111,14 @@ struct _STable_info { ** ("justify" is treated as "left") ** - Inheritance of horizontal alignment according to HTML 4.0 (with the ** exception of COLGROUP/COL) -** - COLSPAN >1 (nearly untested) +** - COLSPAN >1 (may work incorrectly for some tables?) +** - ROWSPAN >1 (reserving cells in following rows) ** - Line breaks at start of first cell or at end of last cell are treated ** as if they were not part of the cell and row. This allows us to ** cooperate with one way in which tables have been made friendly to ** browsers without any table support. ** Missing, but can be added: ** - Support for COLGROUP/COL -** - ROWSPAN >1 (reserving cells in following rows) ** - Tables wider than display. The limitation is not here but in GridText.c ** etc. If horizontal scrolling were implemented there, the mechanisms ** here coudl deal with wide tables (just change MAX_STBL_POS code). @@ -140,6 +148,8 @@ PUBLIC struct _STable_info * Stbl_startTABLE ARGS1( STable_info *me = (STable_info *) calloc(1, sizeof(STable_info)); if (me) { me->alignment = alignment; + me->rowgroup_align = HT_ALIGN_NONE; + me->pending_colgroup_align = HT_ALIGN_NONE; me->s.x_td = -1; me->s.icell_core = -1; } @@ -159,9 +169,9 @@ PUBLIC void Stbl_free ARGS1( { if (me && me->allocated_rows && me->rows) { int i; - for (i = 0; i <= me->nrows; i++) + for (i = 0; i < me->allocated_rows; i++) free_rowinfo(me->rows + i); - free(me->rows); + FREE(me->rows); } if (me) FREE(me->sumcols); @@ -171,8 +181,10 @@ PUBLIC void Stbl_free ARGS1( /* * Returns -1 on error, otherwise index of just-added table cell. */ -PRIVATE int Stbl_addCellToRow ARGS7( +PRIVATE int Stbl_addCellToRow ARGS9( STable_rowinfo *, me, + STable_cellinfo *, colinfo, + int, ncolinfo, STable_states *, s, int, colspan, short, alignment, @@ -386,6 +398,10 @@ PRIVATE int Stbl_addCellToRow ARGS7( if (me->ncells > 0 && me->cells[me->ncells - 1].colspan > 1) { me->ncells += me->cells[me->ncells-1].colspan - 1; } + while (me->ncells < me->allocated && + me->cells[me->ncells].alignment == RESERVEDCELL) { + me->ncells++; + } { int growby = 0; while (me->ncells + colspan + 1 > me->allocated + growby) @@ -413,8 +429,17 @@ PRIVATE int Stbl_addCellToRow ARGS7( me->cells[me->ncells].colspan = colspan; me->cells[me->ncells].alignment = (alignment==HT_ALIGN_NONE) ? me->alignment : alignment; - if (me->cells[me->ncells].alignment==HT_ALIGN_NONE) - me->cells[me->ncells].alignment = isheader ? HT_CENTER : HT_LEFT; + + if (alignment != HT_ALIGN_NONE) + me->cells[me->ncells].alignment = alignment; + else { + if (ncolinfo >= me->ncells + 1) + me->cells[me->ncells].alignment = colinfo[me->ncells].alignment; + if (me->cells[me->ncells].alignment==HT_ALIGN_NONE) + me->cells[me->ncells].alignment = me->alignment; + if (me->cells[me->ncells].alignment==HT_ALIGN_NONE) + me->cells[me->ncells].alignment = isheader ? HT_CENTER : HT_LEFT; + } for (i = me->ncells + 1; i < me->ncells + colspan; i++) { me->cells[i].Line = lineno; me->cells[i].pos = *ppos; @@ -427,6 +452,38 @@ PRIVATE int Stbl_addCellToRow ARGS7( return (me->ncells - 1); } +/* returns -1 on error, 0 otherwise */ +/* assumes cells have already been allocated (but may need more) */ +PRIVATE int Stbl_reserveCellsInRow ARGS3( + STable_rowinfo *, me, + int, icell, + int, colspan) +{ + STable_cellinfo *cells; + int i; + int growby = icell + colspan - me->allocated; + if (growby > 0) { + cells = realloc(me->cells, + (me->allocated + growby) + * sizeof(STable_cellinfo)); + if (cells) { + me->allocated += growby; + me->cells = cells; + } else { + return -1; + } + } + for (i = icell; i < icell + colspan; i++) { + me->cells[i].Line = -1; + me->cells[i].pos = -1; + me->cells[i].len = -1; + me->cells[i].colspan = 0; + me->cells[i].alignment = RESERVEDCELL; + } + me->cells[icell].colspan = colspan; + return 0; +} + PRIVATE int Stbl_finishCellInRow ARGS5( STable_rowinfo *, me, STable_states *, s, @@ -827,6 +884,52 @@ PRIVATE int Stbl_finishCellInRow ARGS5( } /* + * Reserve cells, of colspan=spolspan each, in (rowspan-1) rows after + * the current row. + */ +PRIVATE int Stbl_reserveCellsInTable ARGS4( + STable_info *, me, + int, icell, + int, colspan, + int, rowspan) +{ + STable_rowinfo *rows, *row; + int growby; + int i; + if (me->nrows <= 0) + return -1; /* must already have at least one row */ + growby = me->nrows + rowspan - 1 - me->allocated_rows; + if (growby > 0) { + rows = realloc(me->rows, + (me->allocated_rows + growby) + * sizeof(STable_rowinfo)); + if (!rows) + return 0; /* ignore silently, maybe someone said ROWSPAN=9999999 */ + for (i = 0; i < growby; i++) { + row = rows + me->allocated_rows + i; + row->allocated = 0; + row->ncells = 0; + row->fixed_line = NO; + row->cells = NULL; + row->alignment = HT_ALIGN_NONE; + } + me->allocated_rows += growby; + me->rows = rows; + } + for (i = me->nrows; i < me->nrows + rowspan - 1; i++) { + if (!me->rows[i].allocated) { + me->rows[i].cells = calloc(icell + colspan, sizeof(STable_cellinfo)); + if (!me->rows[i].cells) + return 0; /* fail silently */ + else + me->rows[i].allocated = icell + colspan; + } + Stbl_reserveCellsInRow(me->rows + i, icell, colspan); + } + return 0; +} + +/* * Returns -1 on error, otherwise index of just-added table row. */ PUBLIC int Stbl_addRowToTable ARGS3( @@ -891,9 +994,17 @@ PUBLIC int Stbl_addRowToTable ARGS3( me->rows[me->nrows].Line = lineno; if (me->nrows == 0) me->startline = lineno; - me->rows[me->nrows].alignment = - (alignment==HT_ALIGN_NONE) ? me->alignment : alignment; + if (alignment != HT_ALIGN_NONE) + me->rows[me->nrows].alignment = alignment; + else + me->rows[me->nrows].alignment = + (me->rowgroup_align==HT_ALIGN_NONE) ? + me->alignment : me->rowgroup_align; me->nrows++; + if (me->pending_colgroup_next > me->ncolinfo) { + me->ncolinfo = me->pending_colgroup_next; + me->pending_colgroup_next = 0; + } me->rows[me->nrows].Line = -1; /* not yet used */ return (me->nrows - 1); } @@ -977,9 +1088,10 @@ PRIVATE void update_sumcols0 ARGS7( /* * Returns -1 on error, otherwise 0. */ -PUBLIC int Stbl_addCellToTable ARGS6( +PUBLIC int Stbl_addCellToTable ARGS7( STable_info *, me, int, colspan, + int, rowspan, short, alignment, BOOL, isheader, int, lineno, @@ -1000,7 +1112,7 @@ PUBLIC int Stbl_addCellToTable ARGS6( lineno, pos); lastrow = me->rows + (me->nrows - 1); ncells = lastrow->ncells; /* remember what it was before adding cell. */ - icell = Stbl_addCellToRow(lastrow, s, + icell = Stbl_addCellToRow(lastrow, me->sumcols, me->ncolinfo, s, colspan, alignment, isheader, lineno, &pos); if (icell < 0) @@ -1008,6 +1120,12 @@ PUBLIC int Stbl_addCellToTable ARGS6( if (me->nrows == 1 && me->startline < lastrow->Line) me->startline = lastrow->Line; + if (rowspan > 1) { + Stbl_reserveCellsInTable(me, icell, colspan, rowspan); + /* me->rows may now have been realloc'd, make lastrow valid pointer */ + lastrow = me->rows + (me->nrows - 1); + } + { int growby = 0; while (icell + colspan + 1 > me->allocated_sumcols + growby) @@ -1209,6 +1327,89 @@ PUBLIC int Stbl_finishCellInTable ARGS4( return 0; } +/* + * Returns -1 on error, otherwise 0. + */ +PUBLIC int Stbl_addColInfo ARGS4( + STable_info *, me, + int, colspan, + short, alignment, + BOOL, isgroup) +{ + STable_cellinfo *sumcols, *sumcol; + int i, icolinfo; + + if (isgroup) { + if (me->pending_colgroup_next > me->ncolinfo) + me->ncolinfo = me->pending_colgroup_next; + me->pending_colgroup_next = me->ncolinfo + colspan; + me->pending_colgroup_align = alignment; + } else { + for (i = me->pending_colgroup_next - 1; + i >= me->ncolinfo + colspan; i--) + me->sumcols[i].alignment = HT_ALIGN_NONE; + me->pending_colgroup_next = me->ncolinfo + colspan; + } + icolinfo = me->ncolinfo; + if (!isgroup) + me->ncolinfo += colspan; + + { + int growby = 0; + while (icolinfo + colspan + 1 > me->allocated_sumcols + growby) + growby += CELLS_GROWBY; + if (growby) { + if (me->allocated_sumcols == 0) { + sumcols = calloc(growby, sizeof(STable_cellinfo)); + } else { + sumcols = realloc(me->sumcols, + (me->allocated_sumcols + growby) + * sizeof(STable_cellinfo)); + for (i = 0; sumcols && i < growby; i++) { + sumcol = sumcols + me->allocated_sumcols + i; + sumcol->pos = sumcols[me->allocated_sumcols-1].pos; + sumcol->len = 0; + sumcol->colspan = 0; + } + } + if (sumcols) { + me->allocated_sumcols += growby; + me->sumcols = sumcols; + } else { + return -1; + } + } + } + + if (alignment==HT_ALIGN_NONE) + alignment = me->pending_colgroup_align; + for (i = icolinfo; i < icolinfo + colspan; i++) { + me->sumcols[i].alignment = alignment; + } + return 0; +} + +/* + * Returns -1 on error, otherwise 0. + */ +PUBLIC int Stbl_finishColGroup ARGS1( + STable_info *, me) +{ + if (me->pending_colgroup_next > me->ncolinfo) + me->ncolinfo = me->pending_colgroup_next; + me->pending_colgroup_next = 0; + me->pending_colgroup_align = HT_ALIGN_NONE; + return 0; +} + +PUBLIC int Stbl_addRowGroup ARGS2( + STable_info *, me, + short, alignment) +{ + me->rowgroup_align = alignment; + return 0; /* that's all! */ +} + PUBLIC int Stbl_finishTABLE ARGS1( STable_info *, me) { @@ -1285,9 +1486,9 @@ PRIVATE int get_fixup_positions ARGS4( newlen = HTMAX(newlen, sumcols[i].len); if (me->cells[i].len < newlen) { if (me->cells[i].alignment == HT_RIGHT) { - newpos[i] += newlen - me->cells[i].len; + newpos[ip] += newlen - me->cells[i].len; } else { - newpos[i] += (newlen - me->cells[i].len) / 2; + newpos[ip] += (newlen - me->cells[i].len) / 2; } } } diff --git a/src/TRSTable.h b/src/TRSTable.h index 7ef88b45..a1791151 100644 --- a/src/TRSTable.h +++ b/src/TRSTable.h @@ -1,10 +1,16 @@ +#ifndef TRSTABLE_H +#define TRSTABLE_H + typedef struct _STable_info STable_info; extern STable_info * Stbl_startTABLE PARAMS((short)); extern int Stbl_finishTABLE PARAMS((STable_info *)); extern void Stbl_free PARAMS((STable_info *)); extern int Stbl_addRowToTable PARAMS((STable_info *, short, int)); -extern int Stbl_addCellToTable PARAMS((STable_info *, int, short, BOOL, int, int)); +extern int Stbl_addCellToTable PARAMS((STable_info *, int, int, short, BOOL, int, int)); extern int Stbl_finishCellInTable PARAMS((STable_info *, BOOL, int, int)); +extern int Stbl_addColInfo PARAMS((STable_info *, int, short, BOOL)); +extern int Stbl_finishColGroup PARAMS((STable_info *)); +extern int Stbl_addRowGroup PARAMS((STable_info *, short)); #define Stbl_lineBreak(stbl,l,pos) Stbl_finishCellInTable(stbl, NO, l, pos) extern int Stbl_getStartLine PARAMS((STable_info *)); extern int Stbl_getFixupPositions PARAMS(( @@ -13,3 +19,5 @@ extern int Stbl_getFixupPositions PARAMS(( int * oldpos, int * newpos)); extern short Stbl_getAlignment PARAMS((STable_info *)); + +#endif /* TRSTABLE_H */ diff --git a/src/UCAuto.c b/src/UCAuto.c index 87bbd3c7..86e48f22 100644 --- a/src/UCAuto.c +++ b/src/UCAuto.c @@ -374,14 +374,6 @@ PUBLIC void UCChangeTerminalCodepage ARGS2( name = "unknown-8bit"; } - if (status == 1) - HasUmap = Is_Unset; - else if (status < 0) { - if (HasUmap == Is_Set) - HasUmap = Dunno; - name = "unknown-8bit"; - } - if (TransT != lastTransT) { if (TransT == GN_Blat1) { /* diff --git a/src/UCdomap.c b/src/UCdomap.c index d451b167..2fd0d885 100644 --- a/src/UCdomap.c +++ b/src/UCdomap.c @@ -1332,7 +1332,7 @@ PUBLIC int UCReverseTransChar ARGS3( #ifndef UC_NO_SHORTCUTS if (charset_in == charset_out) - return ch_out; + return (unsigned char)ch_out; #endif /* UC_NO_SHORTCUTS */ if (charset_in < 0) return -11; diff --git a/src/chrtrans/cp1253_uni.tbl b/src/chrtrans/cp1253_uni.tbl index 6a08baef..8d3116d8 100644 --- a/src/chrtrans/cp1253_uni.tbl +++ b/src/chrtrans/cp1253_uni.tbl @@ -46,8 +46,8 @@ C1253 0x8E #UNDEFINED 0x8F #UNDEFINED 0x90 #UNDEFINED -0x91 U+2018 #LEFT SINGLE QUOTATION MARK -0x92 U+2019 #RIGHT SINGLE QUOTATION MARK +0x91 U+2018 U+02bd #LEFT SINGLE QUOTATION MARK +0x92 U+2019 U+02bc #RIGHT SINGLE QUOTATION MARK 0x93 U+201C #LEFT DOUBLE QUOTATION MARK 0x94 U+201D #RIGHT DOUBLE QUOTATION MARK 0x95 U+2022 #BULLET diff --git a/src/chrtrans/cp869_uni.tbl b/src/chrtrans/cp869_uni.tbl index a706d2a8..e8941b41 100644 --- a/src/chrtrans/cp869_uni.tbl +++ b/src/chrtrans/cp869_uni.tbl @@ -38,8 +38,8 @@ C869 0x88 U+00b7 #MIDDLE DOT 0x89 U+00ac #NOT SIGN 0x8a U+00a6 #BROKEN BAR -0x8b U+2018 #LEFT SINGLE QUOTATION MARK -0x8c U+2019 #RIGHT SINGLE QUOTATION MARK +0x8b U+2018 U+02bd #LEFT SINGLE QUOTATION MARK +0x8c U+2019 U+02bc #RIGHT SINGLE QUOTATION MARK 0x8d U+0388 #GREEK CAPITAL LETTER EPSILON WITH TONOS 0x8e U+2015 #HORIZONTAL BAR 0x8f U+0389 #GREEK CAPITAL LETTER ETA WITH TONOS diff --git a/src/chrtrans/iso07_uni.tbl b/src/chrtrans/iso07_uni.tbl index 458c2389..3eb3aeb7 100644 --- a/src/chrtrans/iso07_uni.tbl +++ b/src/chrtrans/iso07_uni.tbl @@ -147,8 +147,17 @@ C813 #0x7D U+007D # RIGHT CURLY BRACKET #0x7E U+007E # TILDE 0xA0 U+00A0 # NO-BREAK SPACE -0xA1 U+02BD # MODIFIER LETTER REVERSED COMMA -0xA2 U+02BC # MODIFIER LETTER APOSTROPHE +# +# The following two changed in ISO 8859:1999 +# +# Remap 0xA1 to U+2018 (instead of U+02BD) +# Remap 0xA2 to U+2019 (instead of U+02BC) +# +# Keep the old ones as primary for now. Also added old U+037[12] +# found in existing linux kbd files and in RFC 1345 for compatibility. +# - kw 1999-10-29 +0xA1 U+02BD U+2018 U+0371 # MODIFIER LETTER REVERSED COMMA +0xA2 U+02BC U+2019 U+0372 # MODIFIER LETTER APOSTROPHE 0xA3 U+00A3 # POUND SIGN 0xA6 U+00A6 # BROKEN BAR 0xA7 U+00A7 # SECTION SIGN diff --git a/src/makefile.dos b/src/makefile.dos index 98b57662..6c715a54 100644 --- a/src/makefile.dos +++ b/src/makefile.dos @@ -11,15 +11,23 @@ LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o CFLAGS= $(MCFLAGS) -I. -I.. $(SLANGINC) +# comment this line to suppress DIRED support +DIRED_DEFS = -DDIRED_SUPPORT -DOK_UUDECODE -DOK_TAR -DOK_GZIP -DOK_ZIP + CC = gcc MCFLAGS = -O2 -DHAVE_GETBKGD -DDISP_PARTIAL -DUSE_ZLIB \ -DSOURCE_CACHE -DUSE_PSRC \ -DUSE_EXTERNALS -DCOLOR_CURSES -DNCURSES -DFANCY_CURSES \ -DACCESS_AUTH -DNO_CUSERID -DNOUSERS -DDOSPATH -DNO_TTYTYPE -DNO_UTMP \ - -Ichrtrans -I../WWW/library/implementation \ - -I../curses -I../djgpp/tcplib/include -I../djgpp/tcplib/include/tcp -WWWLIB = ../WWW/library/djgpp/libwww.a ../curses/pdcurses.a ../djgpp/tcplib/obj/libtcp.a -LIBS=-lz + -DEXP_PERSISTENT_COOKIES -DEXP_ADDRLIST_PAGE -DEXP_ALT_BINDINGS \ + -DEXP_FILE_UPLOAD \ + -DWATT32 \ + $(DIRED_DEFS) \ + -I./chrtrans -I../WWW/Library/Implementation \ + -I../curses -I../djgpp/watt32/inc -I../djgpp/watt32/inc/sys +WWWLIB = ../WWW/Library/djgpp/libwww.a ../curses/pdcurses.a ../djgpp/watt32/lib/libwatt.a +LIBS= -lz # -lintl +#INTLFLAGS = -DHAVE_GETTEXT -DHAVE_LIBINTL_H all: lynx diff --git a/src/makefile.in b/src/makefile.in index 89e8ef71..d655a462 100644 --- a/src/makefile.in +++ b/src/makefile.in @@ -110,6 +110,8 @@ clean: distclean: clean +CMN=$(top_srcdir)/WWW/Library/Implementation/ + HTFWriter.o: $(top_srcdir)/userdefs.h HTInit.o: $(top_srcdir)/userdefs.h LYCharSets.o: $(top_srcdir)/userdefs.h @@ -124,6 +126,7 @@ LYShowInfo.o: $(top_builddir)/cfg_defs.h LYTraversal.o: $(top_srcdir)/userdefs.h LYUtils.o: $(top_srcdir)/userdefs.h LYrcFile.o: $(top_srcdir)/userdefs.h +LYLeaks.o: $(CMN)LYLeaks.h $(CMN)HTString.h CHRTR= chrtrans/ @@ -167,8 +170,6 @@ TABLES= \ $(CHRTR)utf8_uni.h \ $(CHRTR)viscii_uni.h -CMN=$(top_srcdir)/WWW/Library/Implementation/ - $(TABLES): -cd chrtrans && $(MAKE) tables |