diff options
Diffstat (limited to 'src')
59 files changed, 13173 insertions, 5085 deletions
diff --git a/src/GridText.c b/src/GridText.c index 179cbeed..f7b46419 100644 --- a/src/GridText.c +++ b/src/GridText.c @@ -4,13 +4,7 @@ #include "HTUtils.h" #include "tcp.h" - -#include "LYCurses.h" /* lynx defined curses */ - -#include <assert.h> -#include <ctype.h> #include "HTString.h" -#include "GridText.h" #include "HTFont.h" #include "HTAccess.h" #include "HTAnchor.h" @@ -18,8 +12,19 @@ #include "HTTP.h" #include "HTAlert.h" #include "HTCJK.h" +#include "UCDefs.h" +#include "UCAux.h" + +#include <assert.h> +#include <ctype.h> +#ifndef VMS +#ifdef SYSLOG_REQUESTED_URLS +#include <syslog.h> +#endif /* SYSLOG_REQUESTED_URLS */ +#endif /* !VMS */ -/* lynx specific defines */ +#include "GridText.h" +#include "LYCurses.h" #include "LYUtils.h" #include "LYStrings.h" #include "LYStructs.h" @@ -39,17 +44,12 @@ #include "LYexit.h" #include "LYLeaks.h" -#ifndef VMS -#ifdef SYSLOG_REQUESTED_URLS -#include <syslog.h> -#endif /* SYSLOG_REQUESTED_URLS */ -#endif /* !VMS */ #ifdef USE_COLOR_STYLE #include "AttrList.h" #include "LYHash.h" -unsigned cached_styles[CACHEH][CACHEW]; +unsigned int cached_styles[CACHEH][CACHEW]; #endif @@ -71,6 +71,8 @@ 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) #define FREE(x) if (x) {free(x); x = NULL;} @@ -147,6 +149,7 @@ typedef struct _TextAnchor { int link_type; /* Normal, internal, or form? */ FormInfo * input_field; /* Info for form links */ BOOL show_anchor; /* Show the anchor? */ + BOOL inUnderline; /* context is underlined */ HTChildAnchor * anchor; } TextAnchor; @@ -196,14 +199,15 @@ struct _HText { char kanji_buf; /* Lead multibyte */ int in_sjis; /* SJIS flag */ - HTStream* target; /* Output stream */ - HTStreamClass targetClass; /* Output routines */ #ifdef EXP_CHARTRANS - LYUCcharset * UCI; /* pointer to node_anchor's UCInfo */ - int UCLYhndl; /* tells us what charset we are fed */ - UCTransParams T; - BOOL have_8bit_chars; /* Any non-ASCII characters? */ + BOOL have_8bit_chars; /* Any non-ASCII chars? */ + LYUCcharset * UCI; /* node_anchor UCInfo */ + int UCLYhndl; /* charset we are fed */ + UCTransParams T; #endif + + HTStream * target; /* Output stream */ + HTStreamClass targetClass; /* Output routines */ }; PRIVATE void HText_AddHiddenLink PARAMS((HText *text, TextAnchor *textanchor)); @@ -235,20 +239,24 @@ PRIVATE HTStyle default_style = PRIVATE HTList * loaded_texts = NULL; /* A list of all those in memory */ PUBLIC HTList * search_queries = NULL; /* isindex and whereis queries */ PRIVATE void free_all_texts NOARGS; -PRIVATE int HText_TrueLineSize PARAMS((HTLine *line, HText *text)); +PRIVATE int HText_TrueLineSize PARAMS(( + HTLine * line, + HText * text, + BOOL IgnoreSpaces)); #ifdef EXP_CHARTRANS -PRIVATE void htext_get_chartrans_info ARGS1(HText *, me) +PRIVATE void HText_getChartransInfo ARGS1( + HText *, me) { - me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,UCT_STAGE_HTEXT); + me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor, UCT_STAGE_HTEXT); if (me->UCLYhndl < 0) { int chndl = current_char_set; - HTAnchor_setUCInfoStage(me->node_anchor, chndl, UCT_STAGE_HTEXT, - UCT_SETBY_STRUCTURED); + HTAnchor_setUCInfoStage(me->node_anchor, chndl, + UCT_STAGE_HTEXT, UCT_SETBY_STRUCTURED); me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor, UCT_STAGE_HTEXT); } - me->UCI = HTAnchor_getUCInfoStage(me->node_anchor,UCT_STAGE_HTEXT); + me->UCI = HTAnchor_getUCInfoStage(me->node_anchor, UCT_STAGE_HTEXT); } #endif /* EXP_CHARTRANS */ @@ -348,10 +356,9 @@ PUBLIC HText * HText_new ARGS1( self->kanji_buf = '\0'; self->in_sjis = 0; self->have_8bit_chars = NO; - #ifdef EXP_CHARTRANS - htext_get_chartrans_info(self); - UCSetTransParams(&self->T, + HText_getChartransInfo(self); + UCSetTransParams(&self->T, self->UCLYhndl, self->UCI, current_char_set, &LYCharSet_UC[current_char_set]); @@ -529,7 +536,8 @@ PUBLIC void HText_free ARGS1( #endif /* EXP_CHARTRANS */ if (HTAnchor_delete(self->node_anchor)) /* - * Make sure HTMainAnchor won't point to an invalid structure. - kw + * Make sure HTMainAnchor won't point + * to an invalid structure. - KW */ HTMainAnchor = NULL; } @@ -549,7 +557,7 @@ PRIVATE int display_line ARGS2( HTLine *, line, HText *, text) { - register int i,j; + register int i, j; char buffer[7]; char *data; #ifdef EXP_CHARTRANS @@ -557,14 +565,21 @@ PRIVATE int display_line ARGS2( #endif #ifdef USE_COLOR_STYLE int current_style = 0; - int real_position = 0; #endif + char LastDisplayChar = ' '; + /* + * Set up the multibyte character buffer, + * and clear the line to which we will be + * writing. + */ buffer[0] = buffer[1] = buffer[2] = '\0'; clrtoeol(); - /* make sure that we don't go over the COLS limit on the display! */ - /* add offset */ + /* + * Add offset, making sure that we do not + * go over the COLS limit on the display. + */ j = (int)line->offset; if (j > (int)LYcols - 1) j = (int)LYcols - 1; @@ -572,16 +587,21 @@ PRIVATE int display_line ARGS2( SLsmg_forward (j); i = j; #else +#ifdef USE_COLOR_STYLE + if (line->size == 0) + i = j; + else +#endif for (i = 0; i < j; i++) addch (' '); #endif /* USE_SLANG */ - /* add data */ + /* + * Add the data, making sure that we do not + * go over the COLS limit on the display. + */ data = line->data; i++; -#ifdef USE_COLOR_STYLE - real_position = i; -#endif while ((i < LYcols) && ((buffer[0] = *data) != '\0')) { data++; @@ -600,7 +620,7 @@ PRIVATE int display_line ARGS2( #ifndef USE_COLOR_STYLE case LY_UNDERLINE_START_CHAR: if (dump_output_immediately && use_underscore) { - addch ('_'); + addch('_'); i++; } else { lynx_start_underline_color (); @@ -609,7 +629,7 @@ PRIVATE int display_line ARGS2( case LY_UNDERLINE_END_CHAR: if (dump_output_immediately && use_underscore) { - addch ('_'); + addch('_'); i++; } else { lynx_stop_underline_color (); @@ -626,10 +646,18 @@ PRIVATE int display_line ARGS2( #endif case LY_SOFT_HYPHEN: - if (*data != '\0') { + if (*data != '\0' || + isspace((unsigned char)LastDisplayChar) || + LastDisplayChar == '-') { /* - * Ignore the soft hyphen if it is not - * the last character in the line. - FM + * Ignore the soft hyphen if it is not the last + * character in the line. Also ignore it if it + * first character following the margin, or if it + * is preceded by a white character (we loaded 'M' + * into LastDisplayChar if it was a multibyte + * character) or hyphen, though it should have + * been excluded by HText_appendCharacter() or by + * split_line() in those cases. - FM */ break; } else { @@ -643,46 +671,70 @@ PRIVATE int display_line ARGS2( default: i++; #ifdef EXP_CHARTRANS - if (text->T.output_utf8 && !isascii(buffer[0])) { - if ((*buffer & 0xe0) == 0xc0) { - utf_extra = 1; - } else if ((*buffer & 0xf0) == 0xe0) { - utf_extra = 2; - } else if ((*buffer & 0xf8) == 0xf0) { - utf_extra = 3; - } else if ((*buffer & 0xfc) == 0xf8) { - utf_extra = 4; - } else if ((*buffer & 0xfe) == 0xfc) { - utf_extra = 5; - } else { /* garbage */ - utf_extra = 0; - } - if (strlen(data) < utf_extra) - utf_extra = 0; /* shouldn't happen */ + if (text->T.output_utf8 && !isascii(buffer[0])) { + if ((*buffer & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*buffer & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*buffer & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*buffer & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*buffer & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; } - if (utf_extra) { - strncpy(&buffer[1], data, utf_extra); - buffer[utf_extra+1] = '\0'; - addstr(buffer); - buffer[1] = '\0'; - data += utf_extra; + if (strlen(data) < utf_extra) { + /* + * Shouldn't happen. + */ utf_extra = 0; - } else + } + LastDisplayChar = 'M'; + } + if (utf_extra) { + strncpy(&buffer[1], data, utf_extra); + buffer[utf_extra+1] = '\0'; + addstr(buffer); + buffer[1] = '\0'; + data += utf_extra; + utf_extra = 0; + } else #endif /* EXP_CHARTRANS */ - /* For CJK strings, by Masanobu Kimura */ - if (HTCJK != NOCJK && !isascii(buffer[0])) { + if (HTCJK != NOCJK && !isascii(buffer[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ buffer[1] = *data; data++; - i++; addstr(buffer); buffer[1] = '\0'; + /* + * For now, load 'M' into LastDisplayChar, + * but we should check whether it's white + * and if so, use ' '. I don't know if + * there actually are white CJK characters, + * and we're loading ' ' for multibyte + * spacing characters in this code set, + * but this will become an issue when + * the development code set's multibyte + * character handling is used. - FM + */ + LastDisplayChar = 'M'; } else { addstr(buffer); + LastDisplayChar = buffer[0]; } } /* end of switch */ } /* end of while */ - /* add the return */ + /* + * Add the return. + */ addch('\n'); #ifndef USE_COLOR_STYLE @@ -707,9 +759,6 @@ PRIVATE void display_title ARGS1( { char *title = NULL; char percent[20]; -#ifdef NOTDEFINED - char format[20]; -#endif char *cp = NULL; unsigned char *tmp = NULL; int i = 0, j = 0; @@ -721,6 +770,10 @@ PRIVATE void display_title ARGS1( return; lynx_start_title_color (); +#ifdef USE_COLOR_STYLE +/* turn the TITLE style on */ + LynxChangeStyle(s_title, ABS_ON, 0); +#endif /* USE_COLOR_STYLE */ /* * Load the title field. - FM @@ -731,10 +784,14 @@ PRIVATE void display_title ARGS1( /* * There shouldn't be any \n in the title field, - * but if there is, lets kill it now! + * but if there is, lets kill it now. Also trim + * any trailing spaces. - FM */ if ((cp = strchr(title,'\n')) != NULL) *cp = '\0'; + i = (*title ? (strlen(title) - 1) : 0); + while ((i >= 0) && title[i] == ' ') + title[i--] = '\0'; /* * Generate the page indicator (percent) string. @@ -759,31 +816,14 @@ PRIVATE void display_title ARGS1( ((text->top_of_screen + display_lines)/(display_lines))), total_pages); } else { - strcpy(percent, ""); /* Null string */ + percent[0] = '\0'; /* Null string */ } /* - * Generate format string. + * Generate and display the title string, with page indictator + * if appropriate, preceded by the toolbar token if appropriate, + * and truncated if necessary. - FM & KW */ -#ifdef NOTDEFINED - /* Using this kind of format string, sprintf() didn't always get it - right at least on solaris if the title string contained some 8-bit - characters. - kw - */ - sprintf(format, "%s%%%d.%ds%%s\n", - ((text->top_of_screen > 0 && - HText_hasToolbar(text)) ? - "#" : " "), - (LYcols-2)-strlen(percent), - (LYcols-2)-strlen(percent)); -#endif /* NOTDEFINED */ - - /* - * Generate and display the complete title string. - */ - cp = (char *)calloc(1, (LYcols * 2)); - if (cp == NULL) - outofmem(__FILE__, "display_title"); if (HTCJK != NOCJK) { if (*title && (tmp = (unsigned char *)calloc(1, (strlen(title) + 1)))) { @@ -797,44 +837,44 @@ PRIVATE void display_title ARGS1( tmp[j++] = title[i]; } } + tmp[j] = '\0'; } FREE(title); - title = tmp; + title = (char *)tmp; } } - - move(0,0); + move(0, 0); clrtoeol(); if (text->top_of_screen > 0 && HText_hasToolbar(text)) { addch('#'); } - - i = (LYcols-2)-strlen(percent); - if ((i = (LYcols-1) - strlen(percent) - strlen(title)) > 0) { - move(0,i); + i = (LYcols - 1) - strlen(percent) - strlen(title); + if (i > 0) { + move(0, i); } else { - title[LYcols - 2 - strlen(percent)] = '\0'; - move(0,1); + /* + * Note that this truncation is not taking into + * account the possibility that multibyte + * characters might be present. - FM + */ + title[((LYcols - 2) - strlen(percent))] = '\0'; + move(0, 1); } - sprintf(cp, "%s%s\n", title, percent); -#ifdef USE_COLOR_STYLE -/* turn the TITLE style on */ - LynxChangeStyle(s_title, ABS_ON, 0); - addstr(cp); -/* turn the TITLE style off */ - LynxChangeStyle(s_title, ABS_OFF, 0); -#else - addstr(cp); -#endif - FREE(cp); + addstr(title); + if (percent[0] != '\0') + addstr(percent); + addch('\n'); FREE(title); +#ifdef USE_COLOR_STYLE +/* turn the TITLE style off */ + LynxChangeStyle(s_title, ABS_OFF, 0); +#endif /* USE_COLOR_STYLE */ lynx_stop_title_color (); return; } - /* Output a page ** ------------- */ @@ -853,12 +893,7 @@ PRIVATE void display_page ARGS3( HTAnchor *link_dest, *link_dest_intl = NULL; static int last_nlinks = 0; #ifdef EXP_CHARTRANS - int utf_found = 0; -#ifdef EXP_CHARTRANS_AUTOSWITCH -#ifdef LINUX static int charset_last_displayed = -1; -#endif -#endif #endif /* EXP_CHARTRANS */ lynx_mode = NORMAL_LYNX_MODE; @@ -882,7 +917,7 @@ PRIVATE void display_page ARGS3( tmp[0] = tmp[1] = tmp[2] = '\0'; text->page_has_target = NO; - last_screen = text->Lines - (display_lines-2); + last_screen = text->Lines - (display_lines - 2); line = text->last_line->prev; /* @@ -901,21 +936,26 @@ PRIVATE void display_page ARGS3( assert(line->next != NULL); #ifdef EXP_CHARTRANS -#ifdef EXP_CHARTRANS_AUTOSWITCH -#ifdef LINUX if (LYlowest_eightbit[current_char_set] <= 255 && (current_char_set != charset_last_displayed) && - /* current_char_set has changed since last invocation, - and it's not just 7-bit. - Also we don't want to do this for -dump and -source etc. */ + /* + * current_char_set has changed since last invocation, + * and it's not just 7-bit. + * Also we don't want to do this for -dump and -source etc. + */ LYCursesON) { charset_last_displayed = current_char_set; +#ifdef EXP_CHARTRANS_AUTOSWITCH +#ifdef LINUX + /* + * Currently implemented only for LINUX + */ stop_curses(); if (LYTraceLogFP) /* * Set stderr back to its original value, * because the current UCChangeTerminalCodepage() - * writes escape sequences to stderr. - kw + * writes escape sequences to stderr. - KW */ *stderr = LYOrigStderr; UCChangeTerminalCodepage(current_char_set, @@ -926,9 +966,10 @@ PRIVATE void display_page ARGS3( */ *stderr = *LYTraceLogFP; start_curses(); - } #endif /* LINUX */ #endif /* EXP_CHARTRANS_AUTOSWITCH */ + } + #endif /* EXP_CHARTRANS */ /* @@ -947,163 +988,216 @@ PRIVATE void display_page ARGS3( display_flag=TRUE; /* - * Print it. + * Output the page. */ if (line) { - for (i = 0; i < (display_lines); i++) { + char *data; + int offset, LineOffset, HitOffset, LenNeeded; + for (i = 0; i < (display_lines); i++) { + /* + * Verify and display each line. + */ + assert(line != NULL); + display_line(line, text); + +#if defined(FANCY_CURSES) || defined(USE_SLANG) + /* + * If the target is on this line, recursively + * seek and emphasize it. - FM + */ + data = (char *)line->data; + offset = (int)line->offset; + while ((target && *target) && + (case_sensitive ? + (cp = LYno_attr_mbcs_strstr(data, + target, #ifdef EXP_CHARTRANS - int len_needed; + text->T.output_utf8, +#else + NO, #endif /* EXP_CHARTRANS */ - - assert(line != NULL); - display_line(line, text); - - /* - * If the target is on this line, underline it. - */ - if (strlen(target) > 0 && + &HitOffset, + &LenNeeded)) != NULL : + (cp = LYno_attr_mbcs_case_strstr(data, + target, #ifdef EXP_CHARTRANS - (case_sensitive ? - (cp = LYno_attr_mbcs_strstr(line->data, target, - text->T.output_utf8, - &len_needed)) != NULL : - (cp = LYno_attr_mbcs_case_strstr(line->data, target, - text->T.output_utf8, - &len_needed)) != NULL) && - ((int)line->offset + len_needed) < LYcols + text->T.output_utf8, #else - (case_sensitive ? - (cp = LYno_attr_char_strstr(line->data, target)) != NULL : - (cp = LYno_attr_char_case_strstr(line->data, target)) != NULL) && - ((int)(cp - (char *)line->data) + - (int)line->offset + strlen(target)) < LYcols + NO, #endif /* EXP_CHARTRANS */ - ) { - - int itmp = 0; - int written = 0; - int x_pos=(int)line->offset + (int)(cp - line->data); - int len = strlen(target); + &HitOffset, + &LenNeeded)) != NULL) && + ((int)line->offset + LenNeeded) < LYcols) { + int itmp = 0; + int written = 0; + int x_pos = offset + (int)(cp - data); + int len = strlen(target); #ifdef EXP_CHARTRANS - size_t utf_extra = 0; + size_t utf_extra = 0; #endif /* EXP_CHARTRANS */ + int y; - text->page_has_target = YES; + text->page_has_target = YES; - lynx_start_target_color (); - /* underline string */ - for (; written < len && (tmp[0] = line->data[itmp]) != '\0'; - itmp++) { - if (IsSpecialAttrChar(tmp[0])) { - /* ignore special characters */ - x_pos--; + /* + * Start the emphasis. + */ + LYstartTargetEmphasis(); - } else if (cp == &line->data[itmp]) { - /* first character of target */ - move(i+1, x_pos); + /* + * Output the target characters. + */ + for (; + written < len && (tmp[0] = data[itmp]) != '\0'; + itmp++) { + if (IsSpecialAttrChar(tmp[0])) { + /* + * Ignore special characters. + */ + x_pos--; + + } else if (cp == &data[itmp]) { + /* + * First printable character of target. + */ + move((i + 1), x_pos); #ifdef EXP_CHARTRANS - if (text->T.output_utf8 && !isascii(tmp[0])) { - if ((*tmp & 0xe0) == 0xc0) { - utf_extra = 1; - } else if ((*tmp & 0xf0) == 0xe0) { - utf_extra = 2; - } else if ((*tmp & 0xf8) == 0xf0) { - utf_extra = 3; - } else if ((*tmp & 0xfc) == 0xf8) { - utf_extra = 4; - } else if ((*tmp & 0xfe) == 0xfc) { - utf_extra = 5; - } else { /* garbage */ - utf_extra = 0; + if (text->T.output_utf8 && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&line->data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } } - if (strlen(&line->data[1]) < utf_extra) - utf_extra = 0; /* shouldn't happen */ - } - if (utf_extra) { - strncpy(&tmp[1], &line->data[itmp+1], utf_extra); - tmp[utf_extra+1] = '\0'; - itmp += utf_extra; - addstr(tmp); - tmp[1] = '\0'; - written = written + utf_extra + 1; - utf_extra = 0; - utf_found++; + if (utf_extra) { + strncpy(&tmp[1], &line->data[itmp+1], utf_extra); + tmp[utf_extra+1] = '\0'; + itmp += utf_extra; + addstr(tmp); + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; } else #endif /* EXP_CHARTRANS */ - if (HTCJK != NOCJK && !isascii(tmp[0])) { - /* For CJK strings, by Masanobu Kimura */ - tmp[1] = line->data[++itmp]; - addstr(tmp); - tmp[1] = '\0'; - written += 2; - } else { - addstr(tmp); - written++; - } + if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + addstr(tmp); + tmp[1] = '\0'; + written += 2; + } else { + addstr(tmp); + written++; + } - } else if (&line->data[itmp] > cp) { - /* print all the other target chars */ + } else if (&data[itmp] > cp) { + /* + * Output all the other printable target chars. + */ #ifdef EXP_CHARTRANS - if (text->T.output_utf8 && !isascii(tmp[0])) { - if ((*tmp & 0xe0) == 0xc0) { - utf_extra = 1; - } else if ((*tmp & 0xf0) == 0xe0) { - utf_extra = 2; - } else if ((*tmp & 0xf8) == 0xf0) { - utf_extra = 3; - } else if ((*tmp & 0xfc) == 0xf8) { - utf_extra = 4; - } else if ((*tmp & 0xfe) == 0xfc) { - utf_extra = 5; - } else { /* garbage */ - utf_extra = 0; + if (text->T.output_utf8 && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&line->data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } } - if (strlen(&line->data[1]) < utf_extra) - utf_extra = 0; /* shouldn't happen */ - } - if (utf_extra) { - strncpy(&tmp[1], &line->data[itmp+1], utf_extra); - tmp[utf_extra+1] = '\0'; - itmp += utf_extra; - addstr(tmp); - tmp[1] = '\0'; - written = written + utf_extra + 1; - utf_extra = 0; - utf_found++; + if (utf_extra) { + strncpy(&tmp[1], &line->data[itmp+1], utf_extra); + tmp[utf_extra+1] = '\0'; + itmp += utf_extra; + addstr(tmp); + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; } else #endif /* EXP_CHARTRANS */ - if (HTCJK != NOCJK && !isascii(tmp[0])) { - /* For CJK strings, by Masanobu Kimura */ - tmp[1] = line->data[++itmp]; - addstr(tmp); - tmp[1] = '\0'; - written += 2; - } else { - addstr(tmp); - written++; + if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + addstr(tmp); + tmp[1] = '\0'; + written += 2; + } else { + addstr(tmp); + written++; + } } } - } - lynx_stop_target_color (); - move(i+2, 0); - } + /* + * Stop the emphasis, and reset the offset and + * data pointer for our current position in the + * line. - FM + */ + LYstopTargetEmphasis(); + LYGetYX(y, offset); + data = (char *)&data[itmp]; - /* - * Stop if at the last line. - */ - if (line == text->last_line) { - /* clr remaining lines of display */ - for (i++; i < (display_lines); i++) { - move(i+1,0); - clrtoeol(); + /* + * Adjust the cursor position, should we be at + * the end of the line, or not have another hit + * in it. - FM + */ + move((i + 2), 0); } - break; - } +#endif /* FANCY CURSES || USE_SLANG */ - display_flag=TRUE; - line = line->next; - } + /* + * Stop if this is the last line. Otherwise, make sure + * display_flag is set and process the next line. - FM + */ + if (line == text->last_line) { + /* + * Clear remaining lines of display. + */ + for (i++; i < (display_lines); i++) { + move((i + 1), 0); + clrtoeol(); + } + break; + } + display_flag = TRUE; + line = line->next; + } } text->next_line = line; /* Line after screen */ @@ -1119,17 +1213,20 @@ PRIVATE void display_page ARGS3( if (Anchor_ptr->line_num >= line_number && Anchor_ptr->line_num < line_number+(display_lines)) { - - /* load normal hypertext anchors */ + /* + * Load normal hypertext anchors. + */ if (Anchor_ptr->show_anchor && Anchor_ptr->hightext && - strlen(Anchor_ptr->hightext)>0 && + strlen(Anchor_ptr->hightext) > 0 && (Anchor_ptr->link_type & HYPERTEXT_ANCHOR)) { links[nlinks].hightext = Anchor_ptr->hightext; links[nlinks].hightext2 = Anchor_ptr->hightext2; links[nlinks].hightext2_offset = Anchor_ptr->hightext2offset; + links[nlinks].inUnderline = Anchor_ptr->inUnderline; links[nlinks].anchor_number = Anchor_ptr->number; + links[nlinks].anchor_line_num = Anchor_ptr->line_num; link_dest = HTAnchor_followMainLink( (HTAnchor *)Anchor_ptr->anchor); @@ -1175,7 +1272,7 @@ PRIVATE void display_page ARGS3( } links[nlinks].lx = Anchor_ptr->line_pos; - links[nlinks].ly = (Anchor_ptr->line_num+1)-line_number; + links[nlinks].ly = ((Anchor_ptr->line_num + 1) - line_number); if (link_dest_intl) links[nlinks].type = WWW_INTERN_LINK_TYPE; else @@ -1188,17 +1285,21 @@ PRIVATE void display_page ARGS3( } else if (Anchor_ptr->link_type == INPUT_ANCHOR && Anchor_ptr->input_field->type != F_HIDDEN_TYPE) { - + /* + * Handle form fields. + */ lynx_mode = FORMS_LYNX_MODE; FormInfo_ptr = Anchor_ptr->input_field; links[nlinks].anchor_number = Anchor_ptr->number; + links[nlinks].anchor_line_num = Anchor_ptr->line_num; links[nlinks].form = FormInfo_ptr; links[nlinks].lx = Anchor_ptr->line_pos; - links[nlinks].ly = (Anchor_ptr->line_num+1)-line_number; + links[nlinks].ly = ((Anchor_ptr->line_num + 1) - line_number); links[nlinks].type = WWW_FORM_LINK_TYPE; + links[nlinks].inUnderline = Anchor_ptr->inUnderline; links[nlinks].target = empty_string; StrAllocCopy(links[nlinks].lname, empty_string); @@ -1221,17 +1322,24 @@ PRIVATE void display_page ARGS3( links[nlinks].hightext = FormInfo_ptr->value; } - /* never a second line on form types */ + /* + * Never a second line on form types. + */ links[nlinks].hightext2 = NULL; links[nlinks].hightext2_offset = 0; nlinks++; - /* bold the link after incrementing nlinks */ - highlight(OFF,nlinks-1); + /* + * Bold the link after incrementing nlinks. + */ + highlight(OFF, (nlinks - 1), target); display_flag = TRUE; - } else { /* not showing anchor */ + } else { + /* + * Not showing anchor. + */ if (TRACE && Anchor_ptr->hightext && *Anchor_ptr->hightext) fprintf(stderr, @@ -1280,8 +1388,12 @@ PRIVATE void display_page ARGS3( more_links = TRUE; } - if (!display_flag) /* nothing on the page */ + if (!display_flag) { + /* + * Nothing on the page. + */ addstr("\n Document is empty"); + } if (HTCJK != NOCJK || @@ -1289,7 +1401,9 @@ PRIVATE void display_page ARGS3( text->T.output_utf8 || #endif /* EXP_CHARTRANS */ TRACE) { - /* for non-multibyte curses ;_; */ + /* + * For non-multibyte curses. + */ clearok(curscr, TRUE); } refresh(); @@ -1336,9 +1450,14 @@ PRIVATE void split_line ARGS2( { HTStyle * style = text->style; HTLine * temp; - int spare; + int spare, inew; int indent = text->in_line_1 ? text->style->indent1st : text->style->leftIndent; + TextAnchor * a; + int CurLine = text->Lines; + int HeadTrim = 0; + int SpecialAttrChars = 0; + int TailTrim = 0; /* * Make new line. @@ -1364,19 +1483,102 @@ PRIVATE void split_line ARGS2( #if defined(USE_COLOR_STYLE) || defined(SLCS) #define LastStyle (previous->numstyles-1) line->numstyles = 0; - /* FIXME: RJP - shouldn't use 0xffffffff for largest integer */ - line->styles[0].horizpos = 0xffffffff; - if (previous->numstyles && previous->styles[LastStyle].direction) - { - line->numstyles = 1; - line->styles[0].horizpos = 0; - line->styles[0].direction = ON; - line->styles[0].style = previous->styles[LastStyle].style; - previous->styles[previous->numstyles].style = line->styles[0].style; - previous->styles[previous->numstyles].direction = ABS_OFF; - previous->styles[previous->numstyles].horizpos = previous->size; - previous->numstyles++; + inew = MAX_STYLES_ON_LINE - 1; + spare = previous->numstyles; + while (previous->numstyles && inew >= 0) { + if (previous->numstyles >= 2 && + previous->styles[LastStyle].style + == previous->styles[previous->numstyles-2].style && + previous->styles[LastStyle].horizpos + == previous->styles[previous->numstyles-2].horizpos && + ((previous->styles[LastStyle].direction == STACK_OFF && + previous->styles[previous->numstyles-2].direction == STACK_ON) || + (previous->styles[LastStyle].direction == ABS_OFF && + previous->styles[previous->numstyles-2].direction == ABS_ON) || +#if 0 + (previous->styles[LastStyle].direction == STACK_ON && + previous->styles[previous->numstyles-2].direction == STACK_OFF) || +#endif + (previous->styles[LastStyle].direction == ABS_ON && + previous->styles[previous->numstyles-2].direction == ABS_OFF) + )) { + /* + * Discard pairs of ON/OFF for the same color style, but only + * if they appear at the same position. - kw + */ + previous->numstyles -= 2; + if (spare > previous->numstyles) + spare = previous->numstyles; + } else if (spare > 0 && previous->styles[spare - 1].direction && + previous->numstyles < MAX_STYLES_ON_LINE) { + /* + * The index variable spare walks backwards through the + * list of color style changes on the previous line, trying + * to find an ON change which isn't followed by a + * corresponding OFF. When it finds one, the missing OFF + * change is appended to the end, and an ON change is added + * at the beginning of the current line. The OFF change + * appended to the pervious line may get removed again in + * the next iteration. - kw + */ + line->styles[inew].horizpos = 0; + line->styles[inew].direction = ON; + line->styles[inew].style = previous->styles[spare - 1].style; + inew --; + line->numstyles ++; + previous->styles[previous->numstyles].style = line->styles[inew + 1].style; + + previous->styles[previous->numstyles].direction = ABS_OFF; + previous->styles[previous->numstyles].horizpos = previous->size; + previous->numstyles++; + spare --; + } else if (spare >= 2 && + previous->styles[spare - 1].style == previous->styles[spare - 2].style && + ((previous->styles[spare - 1].direction == STACK_OFF && + previous->styles[spare - 2].direction == STACK_ON) || + (previous->styles[spare - 1].direction == ABS_OFF && + previous->styles[spare - 2].direction == ABS_ON) || + (previous->styles[spare - 1].direction == STACK_ON && + previous->styles[spare - 2].direction == STACK_OFF) || + (previous->styles[spare - 1].direction == ABS_ON && + previous->styles[spare - 2].direction == ABS_OFF) + )) { + /* + * Skip pairs of adjacent ON/OFF or OFF/ON changes. + */ + spare -= 2; + } else if (spare && !previous->styles[spare - 1].direction) { + /* + * Found an OFF change not part of a matched pair. + * Assume it is safer to leave whatever comes before + * it on the previous line alone. Setting spare to 0 + * ensures that it won't be used in a following + * iteration. - kw + */ + spare = 0; + } else { + /* + * Nothing applied, so we are done with the loop. - kw + */ + break; + } } + if (previous->numstyles > 0 && previous->styles[LastStyle].direction) { + if (TRACE) + fprintf(stderr, "%s\n%s%s\n", + "........... Too many character styles on line:", + "........... ", previous->data); + } + if (line->numstyles > 0 && line->numstyles < MAX_STYLES_ON_LINE) { + inew ++; + memmove(line->styles, &line->styles[inew], + line->numstyles * sizeof(line->styles[0])); + } else + if (line->numstyles == 0) + /* FIXME: RJP - shouldn't use 0xffffffff for largest integer */ + line->styles[0].horizpos = 0xffffffff; + if (previous->numstyles == 0) + previous->styles[0].horizpos = 0xffffffff; #endif previous->next = line; text->last_line = line; @@ -1422,8 +1624,10 @@ PRIVATE void split_line ARGS2( * of our new line. - FM */ p = prevdata + split; - while (*p == ' ' || *p == LY_SOFT_HYPHEN) + while (*p == ' ' || *p == LY_SOFT_HYPHEN) { p++; + HeadTrim++; + } plen = strlen(p); /* @@ -1450,6 +1654,7 @@ PRIVATE void split_line ARGS2( linedata[line->size++] = LY_UNDERLINE_START_CHAR; linedata[line->size] = '\0'; ctrl_chars_on_this_line++; + SpecialAttrChars++; } for (i = (plen - 1); i >= 0; i--) { if (p[i] == LY_UNDERLINE_START_CHAR) { @@ -1490,6 +1695,7 @@ PRIVATE void split_line ARGS2( linedata[line->size++] = LY_BOLD_START_CHAR; linedata[line->size] = '\0'; ctrl_chars_on_this_line++; + SpecialAttrChars++;; } for (i = (plen - 1); i >= 0; i--) { if (p[i] == LY_BOLD_START_CHAR) { @@ -1505,8 +1711,7 @@ PRIVATE void split_line ARGS2( if (p[i] == LY_BOLD_START_CHAR || p[i] == LY_BOLD_END_CHAR || #ifdef EXP_CHARTRANS -#define IS_UTFEXTRA(ch) (text->T.output_utf8 && ((unsigned char)(ch)&0xc0) == 0x80) - IS_UTFEXTRA(p[i]) || + IS_UTF_EXTRA(p[i]) || #endif /* EXP_CHARTRANS */ p[i] == LY_SOFT_HYPHEN) { ctrl_chars_on_this_line++; @@ -1533,6 +1738,7 @@ PRIVATE void split_line ARGS2( */ previous->data[previous->size-1] = '\0'; previous->size--; + TailTrim++; } temp = (HTLine *)calloc(1, LINE_SIZE(previous->size)); if (temp == NULL) @@ -1548,7 +1754,6 @@ PRIVATE void split_line ARGS2( * Terminate finished line for printing. */ previous->data[previous->size] = '\0'; - /* * Align left, right or center. @@ -1559,7 +1764,7 @@ PRIVATE void split_line ARGS2( *cp == LY_BOLD_START_CHAR || *cp == LY_BOLD_END_CHAR || #ifdef EXP_CHARTRANS - IS_UTFEXTRA(*cp) || + IS_UTF_EXTRA(*cp) || #endif /* EXP_CHARTRANS */ *cp == LY_SOFT_HYPHEN) ctrl_chars_on_previous_line++; @@ -1589,7 +1794,20 @@ PRIVATE void split_line ARGS2( text->chars = text->chars + previous->size + 1; /* 1 for the line */ text->in_line_1 = NO; /* unless caller sets it otherwise */ - + + /* + * If we split the line, adjust the anchor + * structure values for the new line. - FM + */ + if (split > 0) { + for (a = text->first_anchor; a; a = a->next) { + if (a->line_num == CurLine && a->line_pos >= split) { + a->start += (1 + SpecialAttrChars - HeadTrim - TailTrim); + a->line_pos -= (split - SpecialAttrChars + HeadTrim); + a->line_num = text->Lines; + } + } + } } /* split_line */ @@ -1600,11 +1818,14 @@ PRIVATE void blank_lines ARGS2( HText *, text, int, newlines) { - if (!HText_LastLineSize(text)) { /* No text on current line */ + BOOL IgnoreSpaces = FALSE; + + if (!HText_LastLineSize(text, IgnoreSpaces)) { /* No text on current line */ HTLine * line = text->last_line->prev; while ((line != text->last_line) && - (HText_TrueLineSize(line, text) == 0)) { - if (newlines == 0) break; + (HText_TrueLineSize(line, text, IgnoreSpaces) == 0)) { + if (newlines == 0) + break; newlines--; /* Don't bother: already blank */ line = line->prev; } @@ -1672,12 +1893,6 @@ PUBLIC void HText_appendCharacter ARGS2( if (!text) return; -#ifdef NOTDEFINED - /* Make sure nbsp is handled properly. */ - if ((unsigned char)ch == 160) - ch = HT_NON_BREAK_SPACE; -#endif /* NOTDEFINED */ - /* * Make sure we don't hang on escape sequences. */ @@ -1819,7 +2034,7 @@ PUBLIC void HText_appendCharacter ARGS2( return; } - if (ch != LY_SOFT_HYPHEN && IsSpecialAttrChar(ch)) { + if (IsSpecialAttrChar(ch)) { #ifndef USE_COLOR_STYLE if (ch == LY_UNDERLINE_START_CHAR) { line->data[line->size++] = LY_UNDERLINE_START_CHAR; @@ -1847,6 +2062,29 @@ PUBLIC void HText_appendCharacter ARGS2( bold_on = OFF; ctrl_chars_on_this_line++; return; + } else if (ch == LY_SOFT_HYPHEN) { + int i; + + /* + * Ignore the soft hyphen if it is the first character + * on the line, or if it is preceded by a space or + * hyphen. - FM + */ + if (line->size < 1 || text->permissible_split >= (int)line->size) + return; + + for (i = (text->permissible_split + 1); line->data[i]; i++) { + if (!IsSpecialAttrChar((unsigned char)line->data[i]) && + !isspace((unsigned char)line->data[i]) && + (unsigned char)line->data[i] != '-' && + (unsigned char)line->data[i] != HT_NON_BREAK_SPACE && + (unsigned char)line->data[i] != HT_EM_SPACE) { + break; + } + } + if (line->data[i] == '\0') { + return; + } } #else return; @@ -1854,7 +2092,7 @@ PUBLIC void HText_appendCharacter ARGS2( } #ifdef EXP_CHARTRANS - if (IS_UTFEXTRA(ch)) { + if (IS_UTF_EXTRA(ch)) { line->data[line->size++] = ch; line->data[line->size] = '\0'; ctrl_chars_on_this_line++; @@ -1978,9 +2216,11 @@ check_IgnoreExcess: * Check for end of line. */ if (((indent + (int)line->offset + (int)line->size) + - (int)style->rightIndent - ctrl_chars_on_this_line + - (int)(line->data[line->size] == LY_SOFT_HYPHEN ? - 1 : 0)) >= (LYcols-1)) { + (int)style->rightIndent - ctrl_chars_on_this_line + + ((line->size > 0) && + (int)(line->data[line->size-1] == + LY_SOFT_HYPHEN ? + 1 : 0))) >= (LYcols - 1)) { if (style->wordWrap && HTOutputFormat != WWW_SOURCE) { split_line(text, text->permissible_split); @@ -2064,11 +2304,11 @@ check_IgnoreExcess: if (font & HT_DOUBLE) /* Do again if doubled */ HText_appendCharacter(text, HT_NON_BREAK_SPACE); /* NOT a permissible split */ - } - if (ch == LY_SOFT_HYPHEN) { - ctrl_chars_on_this_line++; - text->permissible_split = (int)line->size; /* Can split here */ + if (ch == LY_SOFT_HYPHEN) { + ctrl_chars_on_this_line++; + text->permissible_split = (int)line->size; /* Can split here */ + } } } @@ -2145,8 +2385,9 @@ PUBLIC void HText_setIgnoreExcess ARGS2( /* Start an anchor field */ -PUBLIC void HText_beginAnchor ARGS2( +PUBLIC int HText_beginAnchor ARGS3( HText *, text, + BOOL, underline, HTChildAnchor *, anc) { char marker[16]; @@ -2158,7 +2399,9 @@ PUBLIC void HText_beginAnchor ARGS2( a->hightext = 0; a->hightext2 = 0; a->start = text->chars + text->last_line->size; + a->inUnderline = underline; + a->line_num = text->Lines; a->line_pos = text->last_line->size; if (text->last_anchor) { text->last_anchor->next = a; @@ -2181,46 +2424,103 @@ PUBLIC void HText_beginAnchor ARGS2( a->link_type = HYPERTEXT_ANCHOR; } - /* if we are doing link_numbering add the link number */ - if (keypad_mode == LINKS_ARE_NUMBERED && a->number > 0) { + /* + * If we are doing link_numbering add the link number. + */ + if ((a->number > 0) && + (keypad_mode == LINKS_ARE_NUMBERED || + keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED)) { sprintf(marker,"[%d]", a->number); HText_appendText(text, marker); a->start = text->chars + text->last_line->size; + a->line_num = text->Lines; a->line_pos = text->last_line->size; } + + return(a->number); } -PUBLIC void HText_endAnchor ARGS1( - HText *, text) +PUBLIC void HText_endAnchor ARGS2( + HText *, text, + int, number) { - TextAnchor * a = text->last_anchor; + TextAnchor *a; + + /* + * The number argument is set to 0 in HTML.c and + * LYCharUtils.c when we want to end the anchor + * for the immediately preceding HText_beginAnchor() + * call. If it's greater than 0, we want to handle + * a particular anchor. This allows us to set links + * for positions indicated by NAME or ID attributes, + * without needing to close any anchor with an HREF + * within which that link might be embedded. - FM + */ + if (number <= 0) { + a = text->last_anchor; + } else { + for (a = text->first_anchor; a; a = a->next) { + if (a->number == number) { + break; + } + } + if (a == NULL) { + /* + * There's no anchor with that number, + * so we'll default to the last anchor, + * and cross our fingers. - FM + */ + a = text->last_anchor; + } + } + if (TRACE) + fprintf(stderr, "HText_endAnchor: number:%d link_type:%d\n", + a->number, a->link_type); + if (a->link_type == INPUT_ANCHOR) { + /* + * Shouldn't happen, but put test here anyway to be safe. - LE + */ + if (TRACE) + fprintf(stderr, + "HText_endAnchor: internal error: last anchor was input field!\n"); + return; + } if (a->number) { /* * If it goes somewhere... */ - int i, j, k; + int i, j, k, l; BOOL remove_numbers_on_empty = - (keypad_mode == LINKS_ARE_NUMBERED && + ((keypad_mode == LINKS_ARE_NUMBERED || + keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) && (LYHiddenLinks != HIDDENLINKS_MERGE || (LYNoISMAPifUSEMAP && HTAnchor_isISMAPScript( HTAnchor_followMainLink((HTAnchor *)a->anchor))))); HTLine *last = text->last_line; HTLine *prev = text->last_line->prev; + int CurBlankExtent = 0; + int BlankExtent = 0; /* * Check if the anchor content has only - * white and special characters. - FM + * white and special characters, starting + * with the content on the last line. - FM */ - a->extent += text->chars + last->size - a->start; + a->extent += (text->chars + last->size) - a->start - + (text->Lines - a->line_num); if (a->extent > last->size) { /* - * It extends over more than one line, so - * set up to check the last line. - FM + * The anchor extends over more than one line, + * so set up to check the entire last line. - FM */ i = last->size; } else { + /* + * The anchor is restricted to the last line, + * so check from the start of the anchor. - FM + */ i = a->extent; } j = (last->size - i); @@ -2233,22 +2533,46 @@ PUBLIC void HText_endAnchor ARGS1( i--; j++; } - if (i == 0 && a->extent > last->size) { - /* - * The last line had only white and special - * characters, and it extends over more than - * one line, so check the next to last. - FM - */ - j = prev->size - a->extent + last->size + 1; + if (i == 0) { + if (a->extent > last->size) { + /* + * The anchor starts on a preceding line, and + * the last line has only white and special + * characters, so declare the entire extent + * of the last line as blank. - FM + */ + CurBlankExtent = BlankExtent = last->size; + } else { + /* + * The anchor starts on the last line, and + * has only white or special characters, so + * declare the anchor's extent as blank. - FM + */ + CurBlankExtent = BlankExtent = a->extent; + } + } + /* + * While the anchor starts on a line preceding + * the one we just checked, and the one we just + * checked has only white and special characters, + * check whether the anchor's content on the + * immediatedly preceding line also has only + * white and special characters. - FM + */ + while (i == 0 && a->extent > CurBlankExtent) { + j = prev->size - a->extent + CurBlankExtent; if (j < 0) { /* - * It extends over more than two lines, - * so check all of the previous line. - FM + * The anchor starts on a preceding line, + * so check all of this line. - FM */ j = 0; i = prev->size; } else { - i = a->extent - last->size - 1; + /* + * The anchor starts on this line. - FM + */ + i = a->extent - CurBlankExtent; } while (j < prev->size) { if (!IsSpecialAttrChar(prev->data[j]) && @@ -2259,42 +2583,25 @@ PUBLIC void HText_endAnchor ARGS1( i--; j++; } - if (i == 0 && a->extent > (last->size + prev->size + 1)) { - /* - * It extends over more than two lines, and the - * last two have only white and special characters, - * so check the second to last line. - FM - */ - prev = prev->prev; - j = prev->size - a->extent + last->size + prev->next->size + 2; - if (j < 0) { + if (i == 0) { + if (a->extent > (CurBlankExtent + prev->size)) { /* - * It extends over more than three lines, - * so check all of the second to last. - FM + * This line has only white and special + * characters, so treat its entire extent + * as blank, and decrement the pointer for + * the line to be analyzed. - FM */ - j = 0; - i = prev->size; + CurBlankExtent += prev->size; + BlankExtent = CurBlankExtent; + prev = prev->prev; } else { - i = a->extent - last->size - prev->next->size - 2; - } - while (j < prev->size) { - if (!IsSpecialAttrChar(prev->data[j]) && - !isspace((unsigned char)prev->data[j]) && - prev->data[j] != HT_NON_BREAK_SPACE && - prev->data[j] != HT_EM_SPACE) - break; - i--; - j++; - } - if (i == 0 && - a->extent > - (last->size + prev->size + prev->prev->size + 2)) { /* - * It extends over more than three lines, and the - * last three have only white and special characters, - * so for now, we'll assume it should be shown. - FM + * The anchor starts on this line, and it + * has only white or special characters, so + * declare the anchor's extent as blank. - FM */ - i = a->extent; + BlankExtent = a->extent; + break; } } } @@ -2305,7 +2612,6 @@ PUBLIC void HText_endAnchor ARGS1( * USEMAP. - FM */ a->show_anchor = NO; - prev = last->prev; /* * If links are numbered, then try to get rid of the @@ -2320,39 +2626,75 @@ PUBLIC void HText_endAnchor ARGS1( * possibly caused by HTML errors. - kw */ if (remove_numbers_on_empty) { - j = (last->size - a->extent - 1); + HTLine *start; + int NumSize = 0; + TextAnchor *anc; + + /* + * Set start->data[j] to the close-square-bracket, + * or to the beginning of the line on which the + * anchor start. - FM + */ + if (prev == last->prev) { + /* + * The anchor starts on the last line. - FM + */ + start = last; + j = (last->size - a->extent - 1); + } else { + /* + * The anchor starts on a previous line. - FM + */ + start = prev; + prev = prev->prev; + j = (start->size - a->extent + CurBlankExtent - 1); + } if (j < 0) j = 0; i = j; - if (last->data[j] == ']') { + + /* + * If start->data[j] is a close-square-bracket, verify + * that it's the end of the numbered bracket, and if so, + * strip the numbered bracket. If start->data[j] is not + * a close-square-bracket, check whether we had a wrap + * and the close-square-bracket is at the end of the + * previous line. If so, strip the numbered bracket + * from that line. - FM + */ + if (start->data[j] == ']') { j--; - while (j >= 0 && isdigit((unsigned char)last->data[j])) + NumSize++; + while (j >= 0 && isdigit((unsigned char)start->data[j])) { j--; - if (j < 0) - j = 0; - if (last->data[j] == '[') { + NumSize++; + } + while (j < 0) { + j++; + NumSize--; + } + if (start->data[j] == '[') { /* - * The numbered bracket is on the last line. - FM + * The numbered bracket is entirely + * on this line. - FM */ - HText_AddHiddenLink(text, a); - a->number = 0; - text->last_anchor_number--; - k = (i + 1); - while (k < last->size) { - if (last->data[k] == LY_UNDERLINE_START_CHAR || - last->data[k] == LY_UNDERLINE_END_CHAR || - last->data[k] == LY_BOLD_START_CHAR || - last->data[k] == LY_BOLD_END_CHAR || - last->data[k] == LY_SOFT_HYPHEN) - ctrl_chars_on_this_line--; - k++; + NumSize++; + k = j + NumSize; + while (k < start->size) + start->data[j++] = start->data[k++]; + if (start != last) + text->chars -= NumSize; + for (anc = a; anc; anc = anc->next) { + anc->start -= NumSize; + anc->line_pos -= NumSize; } - last->size = j; - last->data[j] = '\0'; + start->size = j; + start->data[j++] = '\0'; + while (j < k) + start->data[j++] = '\0'; } else if (prev && prev->size > 1) { - k = (i + 1); - i = prev->size; - j = (prev->size - 1); + k = (i + 1); + j = (prev->size - 1); while ((j >= 0) && (prev->data[j] == LY_BOLD_START_CHAR || prev->data[j] == LY_BOLD_END_CHAR || @@ -2360,92 +2702,107 @@ PUBLIC void HText_endAnchor ARGS1( prev->data[j] == LY_UNDERLINE_END_CHAR || prev->data[j] == LY_SOFT_HYPHEN)) j--; - while (j >= 0 && isdigit((unsigned char)prev->data[j])) + i = (j + 1); + while (j >= 0 && + isdigit((unsigned char)prev->data[j])) { j--; - if (j < 0) - j = 0; + NumSize++; + } + while (j < 0) { + j++; + NumSize--; + } if (prev->data[j] == '[') { /* * The numbered bracket started on the * previous line, and part of it was - * wrapped to the last line. - FM + * wrapped to this line. - FM */ - HText_AddHiddenLink(text, a); - a->number = 0; - text->last_anchor_number--; + NumSize++; + l = (i - j); + while (i < prev->size) + start->data[j++] = start->data[i++]; + text->chars -= l; + for (anc = a; anc; anc = anc->next) { + anc->start -= l; + } prev->size = j; prev->data[j] = '\0'; - text->chars -= (i - j); - while (k < last->size) { - if (last->data[k] == LY_UNDERLINE_START_CHAR || - last->data[k] == LY_UNDERLINE_END_CHAR || - last->data[k] == LY_BOLD_START_CHAR || - last->data[k] == LY_BOLD_END_CHAR || - last->data[k] == LY_SOFT_HYPHEN) - ctrl_chars_on_this_line--; - k++; + while (j < i) + start->data[j++] = '\0'; + j = 0; + i = k; + while (k < start->size) + start->data[j++] = start->data[k++]; + if (start != last) + text->chars -= i; + for (anc = a; anc; anc = anc->next) { + anc->start -= i; + anc->line_pos -= i; } - last->size = 0; - last->data[0] = '\0'; - for (j = 1; j < k; j++) - last->data[j] = '\0'; + start->size = j; + start->data[j++] = '\0'; + while (j < k) + start->data[j++] = '\0'; + } else { + /* + * Shucks! We didn't find the + * numbered bracket. - FM + */ + a->show_anchor = YES; } + } else { + /* + * Shucks! We didn't find the + * numbered bracket. - FM + */ + a->show_anchor = YES; } } else if (prev && prev->size > 2) { - i = (prev->size - 1); - while ((i >= 0) && - (prev->data[i] == LY_BOLD_START_CHAR || - prev->data[i] == LY_BOLD_END_CHAR || - prev->data[i] == LY_UNDERLINE_START_CHAR || - prev->data[i] == LY_UNDERLINE_END_CHAR || - prev->data[i] == LY_SOFT_HYPHEN)) - i--; - if (i < 0) - i = 0; - j = i; - i++; + j = (prev->size - 1); + while ((j >= 0) && + (prev->data[j] == LY_BOLD_START_CHAR || + prev->data[j] == LY_BOLD_END_CHAR || + prev->data[j] == LY_UNDERLINE_START_CHAR || + prev->data[j] == LY_UNDERLINE_END_CHAR || + prev->data[j] == LY_SOFT_HYPHEN)) + j--; + if (j < 0) + j = 0; + i = (j + 1); if ((j > 2) && (prev->data[j] == ']' && isdigit((unsigned char)prev->data[j - 1]))) { - k = (j + 1); j--; - while (j >=0 && isdigit((unsigned char)prev->data[j])) + NumSize++; + k = (j + 1); + while (j >= 0 && + isdigit((unsigned char)prev->data[j])) { j--; - if (j < 0) - j = 0; + NumSize++; + } + while (j < 0) { + j++; + NumSize--; + } if (prev->data[j] == '[') { /* * The numbered bracket is all on the * previous line, and the anchor content * was wrapped to the last line. - FM */ - HText_AddHiddenLink(text, a); - a->number = 0; - text->last_anchor_number--; - while (k < prev->size) { - if (prev->data[k] == LY_UNDERLINE_START_CHAR || - prev->data[k] == LY_UNDERLINE_END_CHAR || - prev->data[k] == LY_BOLD_START_CHAR || - prev->data[k] == LY_BOLD_END_CHAR || - prev->data[k] == LY_SOFT_HYPHEN) + NumSize++; + k = j + NumSize; + while (k < prev->size) prev->data[j++] = prev->data[k++]; - i++; + text->chars -= NumSize; + for (anc = a; anc; anc = anc->next) { + anc->start -= NumSize; } prev->size = j; - prev->data[j] = '\0'; - text->chars -= (i - j); - k = 0; - while (k < last->size) { - if (last->data[k] == LY_UNDERLINE_START_CHAR || - last->data[k] == LY_UNDERLINE_END_CHAR || - last->data[k] == LY_BOLD_START_CHAR || - last->data[k] == LY_BOLD_END_CHAR || - last->data[k] == LY_SOFT_HYPHEN) - ctrl_chars_on_this_line--; - k++; - } - last->data[0] = '\0'; - last->size = 0; + prev->data[j++] = '\0'; + while (j < k) + start->data[j++] = '\0'; } else { /* * Shucks! We didn't find the @@ -2467,22 +2824,38 @@ PUBLIC void HText_endAnchor ARGS1( */ a->show_anchor = YES; } - } else if (LYHiddenLinks != HIDDENLINKS_MERGE) { - HText_AddHiddenLink(text, a); - a->number = 0; - text->last_anchor_number--; } } else { /* - * The anchor content does not contain only - * white and special characters (or extends - * over more than three lines and we're punting, - * for now), so we'll show it as a link. - FM + * The anchor's content does not resticted to only + * white and special characters, so we'll show it + * as a link. - FM */ a->show_anchor = YES; } if (a->show_anchor == NO) { + /* + * The anchor's content is restricted to white + * and special characters, so set it's number + * and extent to zero, decrement the visible + * anchor number counter, and add this anchor + * to the hidden links list. - FM + */ a->extent = 0; + if (LYHiddenLinks != HIDDENLINKS_MERGE) { + a->number = 0; + HText_AddHiddenLink(text, a); + text->last_anchor_number--; + } + } else { + /* + * The anchor's content is not restricted to white + * and special characters, so we'll display the + * content, but shorten it's extent by any trailing + * blank lines we've detected. - FM + */ + a->extent -= ((BlankExtent < a->extent) ? + BlankExtent : 0); } } else { /* @@ -2516,8 +2889,10 @@ PRIVATE void remove_special_attr_chars ARGS1( { register char *cp; - for (cp=buf; *cp != '\0' ; cp++) { - /* don't print underline chars */ + for (cp = buf; *cp != '\0' ; cp++) { + /* + * Don't print underline chars. + */ if (!IsSpecialAttrChar(*cp)) { *buf = *cp, buf++; @@ -2531,59 +2906,65 @@ PRIVATE void remove_special_attr_chars ARGS1( ** This function trims blank lines from the end of the document, and ** then gets the hightext from the text by finding the char position, ** and brings the anchors in line with the text by adding the text -** offset to each of the anchors +** offset to each of the anchors. */ PUBLIC void HText_endAppend ARGS1( HText *, text) { - int cur_line, cur_char; + int cur_line, cur_char, cur_shift; TextAnchor *anchor_ptr; HTLine *line_ptr; unsigned char ch; if (!text) return; + if (TRACE) + fprintf(stderr,"Gridtext: Entering HText_endAppend\n"); + /* + * Create a blank line at the bottom. + */ new_line(text); /* - * Get the first line + * Get the first line. */ line_ptr = text->last_line->next; - cur_char = line_ptr->size;; + cur_char = line_ptr->size; cur_line = 0; + cur_shift = 0; /* * Remove the blank lines at the end of document. */ while (text->last_line->data[0] == '\0' && text->Lines > 2) { - HTLine *next_to_the_last_line; + HTLine *next_to_the_last_line = text->last_line->prev; if (TRACE) fprintf(stderr, "GridText: Removing bottom blank line: %s\n", text->last_line->data); - - next_to_the_last_line = text->last_line->prev; - - /* line_ptr points to the first line */ + /* + * line_ptr points to the first line. + */ next_to_the_last_line->next = line_ptr; line_ptr->prev = next_to_the_last_line; FREE(text->last_line); text->last_line = next_to_the_last_line; text->Lines--; #ifdef NOTUSED_BAD_FOR_SCREEN - if (TRACE) + if (TRACE) { fprintf(stderr, "GridText: New bottom line: %s\n", text->last_line->data); + } #endif } - if (TRACE) - fprintf(stderr,"Gridtext: Entering HText_endAppend\n"); - + /* + * Fix up the anchor structure values and + * create the hightext strings. - FM + */ for (anchor_ptr = text->first_anchor; anchor_ptr; anchor_ptr=anchor_ptr->next) { - re_parse: /* * Find the right line. @@ -2591,17 +2972,17 @@ re_parse: for (; anchor_ptr->start >= cur_char; line_ptr = line_ptr->next, cur_char += line_ptr->size+1, - cur_line++) + cur_line++) { ; /* null body */ - - if (anchor_ptr->start == cur_char) + } + if (anchor_ptr->start == cur_char) { anchor_ptr->line_pos = line_ptr->size; - else - anchor_ptr->line_pos = anchor_ptr->start-(cur_char-line_ptr->size); - + } else { + anchor_ptr->line_pos = anchor_ptr->start - + (cur_char - line_ptr->size); + } if (anchor_ptr->line_pos < 0) anchor_ptr->line_pos = 0; - if (TRACE) fprintf(stderr, "Gridtext: Anchor found on line:%d col:%d\n", cur_line, anchor_ptr->line_pos); @@ -2616,29 +2997,31 @@ re_parse: IsSpecialAttrChar(ch)) { anchor_ptr->line_pos++; anchor_ptr->extent--; + cur_shift++; ch = (unsigned char)line_ptr->data[anchor_ptr->line_pos]; } } - - if (anchor_ptr->extent < 0) + if (anchor_ptr->extent < 0) { anchor_ptr->extent = 0; + } #ifdef NOTUSED_BAD_FOR_SCREEN if (TRACE) fprintf(stderr, "anchor text: '%s' pos: %d\n", line_ptr->data, anchor_ptr->line_pos); #endif /* - * If the link begins with a end of line and we have more - * lines, then start the highlighting on the next line. + * If the link begins with an end of line and we have more + * lines, then start the highlighting on the next line. - FM */ if (anchor_ptr->line_pos >= strlen(line_ptr->data) && cur_line < text->Lines) { - anchor_ptr->start++; - + anchor_ptr->start += (cur_shift + 1); + cur_shift = 0; if (TRACE) fprintf(stderr, "found anchor at end of line\n"); goto re_parse; } + cur_shift = 0; #ifdef NOTUSED_BAD_FOR_SCREEN if (TRACE) fprintf(stderr, "anchor text: '%s' pos: %d\n", @@ -2649,7 +3032,6 @@ re_parse: */ if (line_ptr->data && anchor_ptr->extent > 0 && anchor_ptr->line_pos >= 0) { - StrnAllocCopy(anchor_ptr->hightext, &line_ptr->data[anchor_ptr->line_pos], anchor_ptr->extent); @@ -2663,15 +3045,19 @@ re_parse: */ if (anchor_ptr->extent > strlen(anchor_ptr->hightext)) { HTLine *line_ptr2 = line_ptr->next; - /* double check! */ + /* + * Double check that we have a line pointer, + * and if so, copy into hightext2. + */ if (line_ptr) { - StrnAllocCopy(anchor_ptr->hightext2, line_ptr2->data, - (anchor_ptr->extent - strlen(anchor_ptr->hightext))-1); + StrnAllocCopy(anchor_ptr->hightext2, + line_ptr2->data, + (anchor_ptr->extent - + strlen(anchor_ptr->hightext))); anchor_ptr->hightext2offset = line_ptr2->offset; remove_special_attr_chars(anchor_ptr->hightext2); } } - remove_special_attr_chars(anchor_ptr->hightext); /* @@ -2682,7 +3068,7 @@ re_parse: register int offset = 0, i = 0; for (; i < anchor_ptr->line_pos; i++) #ifdef EXP_CHARTRANS - if (IS_UTFEXTRA(line_ptr->data[i])) + if (IS_UTF_EXTRA(line_ptr->data[i])) offset++; else #endif /* EXP_CHARTRANS */ @@ -2691,15 +3077,19 @@ re_parse: anchor_ptr->line_pos -= offset; } - anchor_ptr->line_pos += line_ptr->offset; /* add the offset */ + /* + * Add the offset, and set the line number. + */ + anchor_ptr->line_pos += line_ptr->offset; anchor_ptr->line_num = cur_line; - - if (TRACE) fprintf(stderr, "GridText: adding link on line %d in HText_endAppend\n", cur_line); + /* + * If this is the last anchor, we're done! + */ if (anchor_ptr == text->last_anchor) break; } @@ -2726,16 +3116,16 @@ PUBLIC HTParentAnchor * HText_nodeAnchor ARGS1( /* GridText specials ** ================= */ -/* Return the anchor with index N -** -** The index corresponds to the number we print in the anchor. -*/ +/* + * HTChildAnchor() returns the anchor with index N. + * The index corresponds to the [number] we print for the anchor. + */ PUBLIC HTChildAnchor * HText_childNumber ARGS1( int, number) { TextAnchor * a; - if (!HTMainText) + if (!(HTMainText && HTMainText->first_anchor) || number <= 0) return (HTChildAnchor *)0; /* Fail */ for (a = HTMainText->first_anchor; a; a = a->next) { @@ -2746,19 +3136,98 @@ PUBLIC HTChildAnchor * HText_childNumber ARGS1( } /* + * HText_FormDescNumber() returns a description of the form field + * with index N. The index corresponds to the [number] we print + * for the field. - FM & LE + */ +PUBLIC void HText_FormDescNumber ARGS2( + int, number, + char **, desc) +{ + TextAnchor * a; + + if (!desc) + return; + + if (!(HTMainText && HTMainText->first_anchor) || number <= 0) { + *desc = "unknown field or link"; + return; + } + + for (a = HTMainText->first_anchor; a; a = a->next) { + if (a->number == number) { + if (!(a->input_field && a->input_field->type)) { + *desc = "unknown field or link"; + return; + } + break; + } + } + + switch (a->input_field->type) { + case F_TEXT_TYPE: + *desc = "text entry field"; + return; + case F_PASSWORD_TYPE: + *desc = "password entry field"; + return; + case F_CHECKBOX_TYPE: + *desc = "checkbox"; + return; + case F_RADIO_TYPE: + *desc = "radio button"; + return; + case F_SUBMIT_TYPE: + *desc = "submit button"; + return; + case F_RESET_TYPE: + *desc = "reset button"; + return; + case F_OPTION_LIST_TYPE: + *desc = "popup menu"; + return; + case F_HIDDEN_TYPE: + *desc = "hidden form field"; + return; + case F_TEXTAREA_TYPE: + *desc = "text entry area"; + return; + case F_RANGE_TYPE: + *desc = "range entry field"; + return; + case F_FILE_TYPE: + *desc = "file entry field"; + return; + case F_TEXT_SUBMIT_TYPE: + *desc = "text-submit field"; + return; + case F_IMAGE_SUBMIT_TYPE: + *desc = "image-submit button"; + return; + case F_KEYGEN_TYPE: + *desc = "keygen field"; + return; + default: + *desc = "unknown form field"; + return; + } +} + +/* * HTGetLinkInfo returns some link info based on the number. * - * If go_line is not NULL, caller requests to know a line number for + * If want_go is not NULL, caller requests to know a line number for * the link indicated by number. It will be returned in *go_line, and * *linknum will be set to an index into the links[] array, to use after * the line in *line has been made the new top screen line. * *hightext and *lname are unchanged. - KW * - * If go_line is NULL, info on the link indicated by number is deposited - * in *hightext and *lname. + * If want_go is 0 and the number doesn't represent an input field, info + * on the link indicated by number is deposited in *hightext and *lname. */ -PUBLIC int HTGetLinkInfo ARGS5( +PUBLIC int HTGetLinkInfo ARGS6( int, number, + int, want_go, int *, go_line, int *, linknum, char **, hightext, @@ -2776,13 +3245,13 @@ PUBLIC int HTGetLinkInfo ARGS5( /* * Count anchors, first on current line if there is more * than one. We have to count all links, including form - * field anchors and others with a->number==0, because + * field anchors and others with a->number == 0, because * they are or will be included in the links[] array. - * The exception are hidden form fields and anchors with + * The exceptions are hidden form fields and anchors with * show_anchor not set, because they won't appear in links[] * and don't count towards nlinks. - KW */ - if ((go_line && a->show_anchor) && + if ((a->show_anchor) && (a->link_type != INPUT_ANCHOR || a->input_field->type != F_HIDDEN_TYPE)) { if (a->line_num == prev_anchor_line) { @@ -2814,7 +3283,7 @@ PUBLIC int HTGetLinkInfo ARGS5( * We found it. Now process it, depending * on what kind of info is requested. - KW */ - if (go_line) { + if (want_go || a->link_type == INPUT_ANCHOR) { if (a->show_anchor == NO) { /* * The number requested has been assigned to an anchor @@ -2876,9 +3345,9 @@ PUBLIC int HTGetLinkInfo ARGS5( link_dest = HTAnchor_followMainLink((HTAnchor *)a->anchor); { char *cp_freeme = NULL; - if (traversal) + if (traversal) { cp_freeme = stub_HTAnchor_address(link_dest); - else { + } else { if (a->link_type == INTERNAL_LINK_ANCHOR) { link_dest_intl = HTAnchor_followTypedLink( (HTAnchor *)a->anchor, LINK_INTERNAL); @@ -2917,6 +3386,91 @@ PUBLIC int HTGetLinkInfo ARGS5( } /* + * This function finds the line indicated by line_num in the + * HText structure indicated by text, and searches that line + * for the first hit with the string indicated by target. If + * there is no hit, FALSE is returned. If there is a hit, then + * a copy of the line starting at that first hit is loaded into + * *data with all IsSpecial characters stripped, it's offset and + * the printable target length (without IsSpecial, or extra CJK + * or utf8 characters) are loaded into *offset and *tLen, and + * TRUE is returned. - FM + */ +PUBLIC BOOL HText_getFirstTargetInLine ARGS7( + HText *, text, + int, line_num, + BOOL, utf_flag, + int *, offset, + int *, tLen, + char **, data, + char *, target) +{ + HTLine *line; + char *LineData; + int LineOffset, HitOffset, LenNeeded, i; + char *cp; + + /* + * Make sure we have an HText structure, that line_num is + * in its range, and that we have a target string. - FM + */ + if (!(text && line_num >= 0 && line_num <= text->Lines && + target && *target)) + return(FALSE); + + /* + * Find the line and set up its data and offset - FM + */ + for (i = 0, line = text->last_line->next; + i < line_num && (line != text->last_line); + i++, line = line->next) { + if (line->next == NULL) { + return(FALSE); + } + } + if (!line && line->data[0]) + return(FALSE); + LineData = (char *)line->data; + LineOffset = (int)line->offset; + + /* + * If the target is on the line, load the offset of + * its first character and the subsequent line data, + * strip any special characters from the loaded line + * data, and return TRUE. - FM + */ + if ((case_sensitive ? + (cp = LYno_attr_mbcs_strstr(LineData, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL : + (cp = LYno_attr_mbcs_case_strstr(LineData, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL) && + (LineOffset + LenNeeded) < LYcols) { + /* + * We had a hit so load the results, + * remove IsSpecial characters from + * the allocated data string, and + * return TRUE. - FM + */ + *offset = (LineOffset + HitOffset); + *tLen = (LenNeeded - HitOffset); + StrAllocCopy(*data, cp); + remove_special_attr_chars(*data); + return(TRUE); + } + + /* + * The line does not contain the target. - FM + */ + return(FALSE); +} + +/* * HText_getNumOfLines returns the number of lines in the * current document. */ @@ -3722,24 +4276,34 @@ PUBLIC void print_crawl_to_fd ARGS3( if (thetitle != NULL)fprintf(fp,"THE_TITLE:%s\n",thetitle);; for (;; line = line->next) { - /* add offset */ + /* + * Add offset. + */ for (i = 0; i < (int)line->offset; i++) fputc(' ',fp); - /* add data */ + /* + * Add data. + */ for (i = 0; line->data[i] != '\0'; i++) if (!IsSpecialAttrChar(line->data[i])) fputc(line->data[i],fp); - /* add the return */ + /* + * Add the return. + */ fputc('\n',fp); if (line == HTMainText->last_line) break; } - /* add the References list if appropriate */ - if (keypad_mode == LINKS_ARE_NUMBERED && !nolist) + /* + * Add the References list if appropriate + */ + if ((nolist == FALSE) && + (keypad_mode == LINKS_ARE_NUMBERED || + keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED)) printlist(fp,FALSE); #ifdef VMS @@ -4173,7 +4737,9 @@ PUBLIC void user_message ARGS2( return; } - /* make sure we don't overun any buffers */ + /* + * Make sure we don't overrun any buffers. + */ LYstrncpy(temp_arg, ((argument == NULL) ? "" : argument), 255); temp_arg[255] = '\0'; temp = (char *)malloc(strlen(message) + strlen(temp_arg) + 1); @@ -4256,20 +4822,22 @@ PUBLIC void HTuncache_current_document NOARGS } #endif /* EXP_CHARTRANS */ if (TRACE) { - fprintf(stderr, "\rHTuncache.. freeing document for %s %s\n", - (htmain_anchor && htmain_anchor->address) ? - htmain_anchor->address : "unknown anchor", - (htmain_anchor && htmain_anchor->post_data) ? - "with POST data" : "" - ); + fprintf(stderr, "\rHTuncache.. freeing document for '%s'%s\n", + ((htmain_anchor && + htmain_anchor->address) ? + htmain_anchor->address : "unknown anchor"), + ((htmain_anchor && + htmain_anchor->post_data) ? + " with POST data" : "")); } HTList_removeObject(loaded_texts, HTMainText); HText_free(HTMainText); HTMainText = NULL; - } else + } else { if (TRACE) { fprintf(stderr, "HTuncache.. HTMainText already is NULL!\n"); } + } } PUBLIC int HTisDocumentSource NOARGS @@ -4372,16 +4940,18 @@ PUBLIC char * HTLoadedDocumentBookmark NOARGS return (NULL); } -PUBLIC int HText_LastLineSize ARGS1( - HText *, text) +PUBLIC int HText_LastLineSize ARGS2( + HText *, text, + BOOL, IgnoreSpaces) { if (!text || !text->last_line || !text->last_line->size) return 0; - return HText_TrueLineSize(text->last_line, text); + return HText_TrueLineSize(text->last_line, text, IgnoreSpaces); } -PUBLIC int HText_PreviousLineSize ARGS1( - HText *, text) +PUBLIC int HText_PreviousLineSize ARGS2( + HText *, text, + BOOL, IgnoreSpaces) { HTLine * line; @@ -4389,24 +4959,45 @@ PUBLIC int HText_PreviousLineSize ARGS1( return 0; if (!(line = text->last_line->prev)) return 0; - return HText_TrueLineSize(line, text); + return HText_TrueLineSize(line, text, IgnoreSpaces); } -PRIVATE int HText_TrueLineSize ARGS2(HTLine *,line, HText *,text) +PRIVATE int HText_TrueLineSize ARGS3( + HTLine *, line, + HText *, text, + BOOL, IgnoreSpaces) { size_t i; int true_size = 0; - if (!line || !line->size) + if (!(line && line->size)) return 0; - for (i = 0; i < line->size; i++) { - if (!IsSpecialAttrChar(line->data[i])) { + if (IgnoreSpaces) { + for (i = 0; i < line->size; i++) { + if (!IsSpecialAttrChar((unsigned char)line->data[i]) && + (!(text && text->T.output_utf8) || + (unsigned char)line->data[i] < 128 || + ((unsigned char)(line->data[i] & 0xc0) == 0xc0)) && + !isspace((unsigned char)line->data[i]) && + (unsigned char)line->data[i] != HT_NON_BREAK_SPACE && + (unsigned char)line->data[i] != HT_EM_SPACE) { #ifdef EXP_CHARTRANS if (!text->T.output_utf8 || (unsigned char)line->data[i] < 128 || ((unsigned char)(line->data[i] & 0xc0) == 0xc0)) #endif /* EXP_CHARTRANS */ - true_size++; + true_size++; + } + } + } else { + for (i = 0; i < line->size; i++) { + if (!IsSpecialAttrChar(line->data[i])) { +#ifdef EXP_CHARTRANS + if (!text->T.output_utf8 || (unsigned char)line->data[i] < 128 || + ((unsigned char)(line->data[i] & 0xc0) == 0xc0)) +#endif /* EXP_CHARTRANS */ + true_size++; + } } } return true_size; @@ -4462,11 +5053,13 @@ PUBLIC int HText_getCurrentColumn ARGS1( HText *, text) { int column = 0; + BOOL IgnoreSpaces = FALSE; if (text) { column = (text->in_line_1 ? (int)text->style->indent1st : (int)text->style->leftIndent) - + HText_LastLineSize(text) + (int)text->last_line->offset; + + HText_LastLineSize(text, IgnoreSpaces) + + (int)text->last_line->offset; } return column; } @@ -4768,7 +5361,86 @@ PUBLIC void HText_beginSelect ARGS3( } /* -** We couln't set the value field for the previous option +** This function returns the number of the option whose +** value currently is being accumulated for a select +** block. - LE && FM +*/ +PUBLIC int HText_getOptionNum ARGS1( + HText *, text) +{ + TextAnchor *a; + OptionType *op; + int n = 1; /* start count at 1 */ + + if (!(text && text->last_anchor)) + return(0); + + a = text->last_anchor; + if (!(a->link_type == INPUT_ANCHOR && a->input_field && + a->input_field->type == F_OPTION_LIST_TYPE)) + return(0); + + for (op = a->input_field->select_list; op; op = op->next) + n++; + if (TRACE) + fprintf(stderr, "HText_getOptionNum: Got number '%d'.\n", n); + return(n); +} + +/* +** This function checks for a numbered option pattern +** as the prefix for an option value. If present, and +** we are in the correct keypad mode, it returns a +** pointer to the actual value, following that prefix. +** Otherwise, it returns the original pointer. +*/ +PRIVATE char * HText_skipOptionNumPrefix ARGS1( + char *, opname) +{ + /* + * Check if we are in the correct keypad mode. + */ + if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) { + /* + * Skip the option number embedded in the option name so the + * extra chars won't mess up cgi scripts processing the value. + * The format is (nnn)__ where nnn is a number and there is a + * minumum of 5 chars (no underscores if (nnn) exceeds 5 chars). + * See HTML.c. If the chars don't exactly match this format, + * just use all of opname. - LE + */ + char *cp = opname; + + if ((cp && *cp && *cp++ == '(') && + *cp && isdigit(*cp++)) { + while (*cp && isdigit(*cp)) + ++cp; + if (*cp && *cp++ == ')') { + int i = (cp - opname); + + while (i < 5) { + if (*cp != '_') + break; + i++; + cp++; + } + if (i < 5 ) { + cp = opname; + } + } else { + cp = opname; + } + } else { + cp = opname; + } + return(cp); + } + + return(opname); +} + +/* +** We couldn't set the value field for the previous option ** tag so we have to do it now. Assume that the last anchor ** was the previous options tag. */ @@ -4779,7 +5451,7 @@ PUBLIC char * HText_setLastOptionValue ARGS5( int, order, BOOLEAN, checked) { - char *cp; + char *cp, *cp1; unsigned char *tmp = NULL; int number = 0, i, j; @@ -4810,6 +5482,26 @@ PUBLIC char * HText_setLastOptionValue ARGS5( while (isspace((unsigned char)*cp) || IsSpecialAttrChar((unsigned char)*cp)) cp++; + if (HTCurSelectGroupType == F_RADIO_TYPE && + LYSelectPopups && + keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) { + /* + * Collapse any space beteen the popup option + * prefix and actual value. - FM + */ + if ((cp1 = HText_skipOptionNumPrefix(cp)) > cp) { + i = 0, j = (cp1 - cp); + while (isspace((unsigned char)cp1[i]) || + IsSpecialAttrChar((unsigned char)cp1[i])) { + i++; + } + if (i > 0) { + while (cp1[i] != '\0') + cp[j++] = cp1[i++]; + cp[j] = '\0'; + } + } + } if (HTCurSelectGroupType == F_CHECKBOX_TYPE) { StrAllocCopy(text->last_anchor->input_field->value, cp); @@ -4896,8 +5588,9 @@ PUBLIC char * HText_setLastOptionValue ARGS5( StrAllocCopy(new_ptr->name, cp); } StrAllocCopy(new_ptr->cp_submit_value, - (submit_value ? submit_value : new_ptr->name)); - + (submit_value ? submit_value : + HText_skipOptionNumPrefix(new_ptr->name))); + if (first_option) { StrAllocCopy(HTCurSelectedOptionValue, new_ptr->name); text->last_anchor->input_field->num_value = 0; @@ -4961,12 +5654,13 @@ PUBLIC char * HText_setLastOptionValue ARGS5( } /* - * Assign a form input anchor - * returns the number of charactors to leave blank - * so that the input field can fit + * Assign a form input anchor. + * Returns the number of charactors to leave + * blank so that the input field can fit. */ -PUBLIC int HText_beginInput ARGS2( +PUBLIC int HText_beginInput ARGS3( HText *, text, + BOOL, underline, InputFieldData *, I) { @@ -4984,6 +5678,7 @@ PUBLIC int HText_beginInput ARGS2( outofmem(__FILE__, "HText_beginInput"); a->start = text->chars + text->last_line->size; + a->inUnderline = underline; a->line_pos = text->last_line->size; @@ -5166,6 +5861,8 @@ PUBLIC int HText_beginInput ARGS2( f->type = F_RANGE_TYPE; } else if (!strcasecomp(I->type,"file")) { f->type = F_FILE_TYPE; + } else if (!strcasecomp(I->type,"keygen")) { + f->type = F_KEYGEN_TYPE; } else { /* * Note that TYPE="scribble" defaults to TYPE="text". - FM @@ -5279,25 +5976,80 @@ PUBLIC int HText_beginInput ARGS2( } /* + * Add numbers to form fields if needed. - LE & FM + */ + switch (f->type) { + /* + * Do not supply number for hidden fields, nor + * for types that are not yet implemented. + */ + case F_HIDDEN_TYPE: + case F_FILE_TYPE: + case F_RANGE_TYPE: + case F_KEYGEN_TYPE: + a->number = 0; + break; + + default: + if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) + a->number = ++(text->last_anchor_number); + else + a->number = 0; + break; + } + if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED && a->number > 0) { + char marker[16]; + + if (f->type != F_OPTION_LIST_TYPE) + /* + * '[' was already put out for a popup menu + * designator. See HTML.c. + */ + HText_appendCharacter(text, '['); + sprintf(marker,"%d]", a->number); + HText_appendText(text, marker); + if (f->type == F_OPTION_LIST_TYPE) + /* + * Add option list designation char. + */ + HText_appendCharacter(text, '['); + a->start = text->chars + text->last_line->size; + a->line_pos = text->last_line->size; + } + + /* * Restrict SIZE to maximum allowable size. */ switch (f->type) { - int MaximumSize; + int MaximumSize; case F_SUBMIT_TYPE: case F_IMAGE_SUBMIT_TYPE: case F_RESET_TYPE: + case F_TEXT_TYPE: + case F_TEXTAREA_TYPE: /* - * For submit and reset buttons, we limit the size - * element to that of one line for the current style - * because that's the most we could highlight on - * overwrites- FM + * For submit and reset buttons, and for text entry + * fields and areas, we limit the size element to that + * of one line for the current style because that's + * the most we could highlight on overwrites, and/or + * handle in the line editor. The actual values for + * text entry lines can be long, and will be scrolled + * horizontally within the editing window. - FM */ MaximumSize = (LYcols - 1) - (int)text->style->leftIndent - (int)text->style->rightIndent; + + /* + * If we are numbering form links, take that into + * account as well. - FM + */ + if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) + MaximumSize -= ((a->number/10) + 3); if (f->size > MaximumSize) f->size = MaximumSize; + /* * Save value for submit/reset buttons so they * will be visible when printing the page. - LE @@ -5305,13 +6057,13 @@ PUBLIC int HText_beginInput ARGS2( I->value = f->value; break; + default: /* - * For all other fields we limit the size element - * to 10 less than the screen width, because either - * they are types with small placeholders, or are a - * type which can be scrolled horizontally within - * an editing window. - FM + * For all other fields we limit the size element to + * 10 less than the screen width, because either they + * are types with small placeholders, and/or are a + * type which is handled via a popup window. - FM */ if (f->size > LYcols-10) f->size = LYcols-10; /* maximum */ @@ -5328,7 +6080,7 @@ PUBLIC int HText_beginInput ARGS2( f->name, ((f->value != NULL) ? f->value : ""), f->size); - + /* * Return the SIZE of the input field. */ @@ -6269,6 +7021,12 @@ PUBLIC BOOL HText_hasNoCacheSet ARGS1( return ((text && text->no_cache) ? TRUE : FALSE); } +PUBLIC BOOL HText_hasUTF8OutputSet ARGS1( + HText *, text) +{ + return ((text && text->T.output_utf8) ? TRUE : FALSE); +} + /* ** Check charset and set the kcode element. - FM */ @@ -6347,7 +7105,9 @@ PUBLIC BOOL HText_AreDifferent ARGS2( CONST char *, full_address) { HTParentAnchor *MTanc; - char *pound; + char *MTaddress; + char *MTpound; + char *TargetPound; /* * Do we have a loaded document and both @@ -6366,67 +7126,76 @@ PUBLIC BOOL HText_AreDifferent ARGS2( /* * Do we have a fragment associated with the target? */ - if ((pound = strchr(full_address, '#')) == NULL) + if ((TargetPound = strchr(full_address, '#')) == NULL) return (TRUE); /* * Always treat client-side image map menus - * as potentially stale. + * as potentially stale, so we'll create a + * fresh menu from the LynxMaps HTList. */ if (!strncasecomp(anchor->address, "LYNXIMGMAP:", 11)) return (TRUE); /* - * Do they differ in the type of request? + * Do the docs differ in the type of request? */ if (MTanc->isHEAD != anchor->isHEAD) return (TRUE); /* - * Are the actual URLs different? + * Are the actual URLs different, after factoring + * out a "LYNXIMGMAP:" leader in the MainText URL + * and its fragment, if present? */ - if (strcmp(MTanc->address, anchor->address)) + MTaddress = (strncasecomp(MTanc->address, + "LYNXIMGMAP:", 11) ? + MTanc->address : (MTanc->address + 11)); + if ((MTpound = strchr(MTaddress, '#')) != NULL) + *MTpound = '\0'; + if (strcmp(MTaddress, anchor->address)) { + if (MTpound != NULL) { + *MTpound = '#'; + } return(TRUE); + } + if (MTpound != NULL) { + *MTpound = '#'; + } /* - * Do the docs have different contents? + * If the MainText is not an image map menu, + * do the docs have different POST contents? */ - if (MTanc->post_data) { - if (anchor->post_data) { - if (strcmp(MTanc->post_data, anchor->post_data)) { - /* - * Both have contents, and they differ. + if (MTaddress == MTanc->address) { + if (MTanc->post_data) { + if (anchor->post_data) { + if (strcmp(MTanc->post_data, anchor->post_data)) { + /* + * Both have contents, and they differ. + */ + return(TRUE); + } + } else { + /* + * The loaded document has content, but the + * target doesn't, so they're different. */ return(TRUE); } - } else { + } else if (anchor->post_data) { /* - * The loaded document has content, but the - * target doesn't, so they're different. - */ - return(TRUE); - } - } else if (anchor->post_data) { - /* * The loaded document does not have content, but * the target does, so they're different. */ return(TRUE); + } } /* - * Are we seeking a position in the loaded document - * based on a fragment? - */ - if (!strncmp(MTanc->address, full_address, (pound - full_address))) - return(FALSE); - - /* - * We'll assume the loaded document and target should be - * treated as different, either because we are reloading, - * or because we had header, META, or other directives not - * to use a cached rendition. - FM + * We'll assume the target is a position in the currently + * displayed document, and thus can ignore any header, META, + * or other directives not to use a cached rendition. - FM */ - return(TRUE); - + return(FALSE); } diff --git a/src/GridText.h b/src/GridText.h index d606c16f..92c2d40f 100644 --- a/src/GridText.h +++ b/src/GridText.h @@ -44,6 +44,7 @@ extern BOOLEAN mustshow; extern int HTVirtualMemorySize; #endif /* VMS && VAXC && !__DECC */ extern HTChildAnchor * HText_childNumber PARAMS((int n)); +extern void HText_FormDescNumber PARAMS((int n, char **desc)); /* Is there any file left? */ @@ -87,10 +88,19 @@ extern BOOL HText_POSTReplyLoaded PARAMS((document *doc)); extern BOOL HTFindPoundSelector PARAMS((char *selector)); extern int HTGetLinkInfo PARAMS(( int number, + int want_go, int * go_line, int * linknum, char ** hightext, char ** lname)); +extern BOOL HText_getFirstTargetInLine PARAMS(( + HText * text, + int line_num, + BOOL utf_flag, + int * offset, + int * tLen, + char ** data, + char * target)); extern int HTisDocumentSource NOPARAMS; extern void HTuncache_current_document NOPARAMS; extern int HText_getTopOfScreen NOPARAMS; @@ -106,8 +116,8 @@ extern char * HTLoadedDocumentCharset NOPARAMS; extern BOOL HTLoadedDocumentEightbit NOPARAMS; extern void HText_setNodeAnchorBookmark PARAMS((CONST char *bookmark)); extern char * HTLoadedDocumentBookmark NOPARAMS; -extern int HText_LastLineSize PARAMS((HText *me)); -extern int HText_PreviousLineSize PARAMS((HText *me)); +extern int HText_LastLineSize PARAMS((HText *me, BOOL IgnoreSpaces)); +extern int HText_PreviousLineSize PARAMS((HText *me, BOOL IgnoreSpaces)); extern void HText_NegateLineOne PARAMS((HText *text)); extern void HText_RemovePreviousLine PARAMS((HText *text)); extern int HText_getCurrentColumn PARAMS((HText *text)); @@ -125,13 +135,17 @@ extern void HText_beginForm PARAMS(( char * title)); extern void HText_endForm PARAMS((HText *text)); extern void HText_beginSelect PARAMS((char *name, BOOLEAN multiple, char *len)); +extern int HText_getOptionNum PARAMS((HText *text)); extern char * HText_setLastOptionValue PARAMS(( HText * text, char * value, char * submit_value, int order, BOOLEAN checked)); -extern int HText_beginInput PARAMS((HText *text, InputFieldData *I)); +extern int HText_beginInput PARAMS(( + HText * text, + BOOL underline, + InputFieldData *I)); extern void HText_SubmitForm PARAMS(( FormInfo * submit_item, document * doc, @@ -163,6 +177,7 @@ extern BOOL HText_hasToolbar PARAMS((HText *text)); extern void HText_setNoCache PARAMS((HText *text)); extern BOOL HText_hasNoCacheSet PARAMS((HText *text)); +extern BOOL HText_hasUTF8OutputSet PARAMS((HText *text)); extern void HText_setKcode PARAMS((HText *text, CONST char *charset)); extern void HText_setBreakPoint PARAMS((HText *text)); diff --git a/src/HTAlert.c b/src/HTAlert.c index 246716e3..78a931e0 100644 --- a/src/HTAlert.c +++ b/src/HTAlert.c @@ -140,11 +140,14 @@ PUBLIC char * HTPromptPassword ARGS1( ** On entry, ** Msg is the prompting message. ** *username and -** *password are char pointers; they are changed +** *password are char pointers which contain default +** or zero-length strings; they are changed ** to point to result strings. +** IsProxy should be TRUE if this is for +** proxy authentication. ** ** If *username is not NULL, it is taken -** to point to a default value. +** to point to a default value. ** Initial value of *password is ** completely discarded. ** @@ -154,40 +157,71 @@ PUBLIC char * HTPromptPassword ARGS1( ** are NOT freed. ** */ -PUBLIC void HTPromptUsernameAndPassword ARGS3( +PUBLIC void HTPromptUsernameAndPassword ARGS4( CONST char *, Msg, char **, username, - char **, password) + char **, password, + BOOL, IsProxy) { - if (authentication_info[0] && authentication_info[1]) { + if ((IsProxy == FALSE && + authentication_info[0] && authentication_info[1]) || + (IsProxy == TRUE && + proxyauth_info[0] && proxyauth_info[1])) { /* - ** -auth parameter gave us both the username and password - ** to use for the first realm, so just use them without - ** any prompting. - FM + ** The -auth or -pauth parameter gave us both the username + ** and password to use for the first realm or proxy server, + ** respectively, so just use them without any prompting. - FM */ - StrAllocCopy(*username, authentication_info[0]); - FREE(authentication_info[0]); - StrAllocCopy(*password, authentication_info[1]); - FREE(authentication_info[1]); + StrAllocCopy(*username, (IsProxy ? + proxyauth_info[0] : authentication_info[0])); + if (IsProxy) { + FREE(proxyauth_info[0]); + } else { + FREE(authentication_info[0]); + } + StrAllocCopy(*password, (IsProxy ? + proxyauth_info[1] : authentication_info[1])); + if (IsProxy) { + FREE(proxyauth_info[1]); + } else { + FREE(authentication_info[1]); + } } else if (dump_output_immediately) { - if (authentication_info[0]) { + /* + * We are not interactive and don't have both the + * username and password from the command line, + * but might have one or the other. - FM + */ + if ((IsProxy == FALSE && authentication_info[0]) || + (IsProxy == TRUE && proxyauth_info[0])) { /* ** Use the command line username. - FM */ - StrAllocCopy(*username, authentication_info[0]); - FREE(authentication_info[0]); + StrAllocCopy(*username, (IsProxy ? + proxyauth_info[0] : authentication_info[0])); + if (IsProxy) { + FREE(proxyauth_info[0]); + } else { + FREE(authentication_info[0]); + } } else { /* ** Default to "WWWuser". - FM */ StrAllocCopy(*username, "WWWuser"); } - if (authentication_info[1]) { + if ((IsProxy == FALSE && authentication_info[1]) || + (IsProxy == TRUE && proxyauth_info[1])) { /* ** Use the command line password. - FM */ - StrAllocCopy(*password, authentication_info[1]); - FREE(authentication_info[1]); + StrAllocCopy(*password, (IsProxy ? + proxyauth_info[1] : authentication_info[1])); + if (IsProxy) { + FREE(proxyauth_info[1]); + } else { + FREE(authentication_info[1]); + } } else { /* ** Default to a zero-length string. - FM @@ -195,30 +229,51 @@ PUBLIC void HTPromptUsernameAndPassword ARGS3( StrAllocCopy(*password, ""); } printf("\n%s\n", USERNAME_PASSWORD_REQUIRED); + } else { - if (authentication_info[0]) { + /* + * We are interactive and don't have both the + * username and password from the command line, + * but might have one or the other. - FM + */ + if ((IsProxy == FALSE && authentication_info[0]) || + (IsProxy == TRUE && proxyauth_info[0])) { /* - ** Offer command line username in the prompt - ** for the first realm. - FM + ** Offer the command line username in the + ** prompt for the first realm. - FM */ - StrAllocCopy(*username, authentication_info[0]); - FREE(authentication_info[0]); + StrAllocCopy(*username, (IsProxy ? + proxyauth_info[0] : authentication_info[0])); + if (IsProxy) { + FREE(proxyauth_info[0]); + } else { + FREE(authentication_info[0]); + } } + /* + * Prompt for confirmation or entry of the username. - FM + */ if (Msg != NULL) { *username = HTPrompt(Msg, *username); } else { *username = HTPrompt(USERNAME_PROMPT, *username); } - if (authentication_info[1]) { + if ((IsProxy == FALSE && authentication_info[1]) || + (IsProxy == TRUE && proxyauth_info[1])) { /* ** Use the command line password for the first realm. - FM */ - StrAllocCopy(*password, authentication_info[1]); - FREE(authentication_info[1]); + StrAllocCopy(*password, (IsProxy ? + proxyauth_info[1] : authentication_info[1])); + if (IsProxy) { + FREE(proxyauth_info[1]); + } else { + FREE(authentication_info[1]); + } } else if (*username != NULL && *username[0] != '\0') { /* - ** If we have a non-zero length username, - ** prompt for the password. - FM + ** We have a non-zero length username, + ** so prompt for the password. - FM */ *password = HTPromptPassword(PASSWORD_PROMPT); } else { @@ -227,7 +282,6 @@ PUBLIC void HTPromptUsernameAndPassword ARGS3( */ StrAllocCopy(*password, ""); } - } } diff --git a/src/HTAlert.h b/src/HTAlert.h index 73013918..ec1d2397 100644 --- a/src/HTAlert.h +++ b/src/HTAlert.h @@ -64,6 +64,8 @@ extern char * HTPromptPassword PARAMS((CONST char * Msg)); ** *username and ** *password are char pointers; they are changed ** to point to result strings. +** IsProxy should be TRUE if this is for +** proxy authentication. ** ** If *username is not NULL, it is taken ** to point to a default value. @@ -79,7 +81,8 @@ extern char * HTPromptPassword PARAMS((CONST char * Msg)); extern void HTPromptUsernameAndPassword PARAMS(( CONST char * Msg, char ** username, - char ** password)); + char ** password, + BOOL IsProxy)); /* Confirm a cookie operation. HTConfirmCookie() diff --git a/src/HTFWriter.c b/src/HTFWriter.c index 24bbb136..3589811b 100644 --- a/src/HTFWriter.c +++ b/src/HTFWriter.c @@ -44,9 +44,6 @@ PUBLIC char * WWW_Download_File=NULL; /* contains the name of the temp file */ PUBLIC char LYCancelDownload=FALSE; /* exported to HTFormat.c in libWWW */ -/* Type mismatch found here - char != BOOLEAN - WSB */ -extern BOOLEAN dump_output_immediately; /* if true dump to stdout and quit */ - #ifdef VMS extern BOOLEAN HadVMSInterrupt; /* flag from cleanup_sig() */ PRIVATE char * FIXED_RECORD_COMMAND = NULL; @@ -224,14 +221,20 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me) FREE(path); FREE(me->anchor->content_encoding); #ifdef EXP_CHARTRANS - /* lock the chartrans info we may possibly have, - so HTCharSetFormat will not apply the default for - local files */ + /* + * Lock the chartrans info we may possibly have, + * so HTCharsetFormat() will not apply the default + * for local files. - KW + */ HTAnchor_copyUCInfoStage(me->anchor, UCT_STAGE_PARSER, UCT_STAGE_MIME, UCT_SETBY_PARSER); #endif + /* + * Now have HTLoadFile() handle the uncompressed + * file as if it were the original reply. - FM + */ status = HTLoadFile(addr, me->anchor, me->output_format, @@ -512,6 +515,7 @@ SaveAndExecute_tempname: FREE(me); return NULL; } + chmod(fnam, 0600); /* * Make command to process file. @@ -522,7 +526,7 @@ SaveAndExecute_tempname: if (me->end_command == NULL) outofmem(__FILE__, "HTSaveAndExecute"); - sprintf (me->end_command, pres->command, fnam, ""); + sprintf(me->end_command, pres->command, fnam, "", "", "", "", "", ""); /* * Make command to delete file. @@ -533,7 +537,7 @@ SaveAndExecute_tempname: if (me->remove_command == NULL) outofmem(__FILE__, "HTSaveAndExecute"); - sprintf (me->remove_command, REMOVE_COMMAND, fnam); + sprintf(me->remove_command, REMOVE_COMMAND, fnam, "", "", "", "", "", ""); StrAllocCopy(anchor->FileCache, fnam); return me; @@ -710,6 +714,7 @@ SaveToFile_tempname: FREE(ret_obj); return NULL; } + chmod(fnam, 0600); /* * Any "application/foo" or other non-"text/foo" types that @@ -731,8 +736,9 @@ SaveToFile_tempname: * sizeof (char),1); if (ret_obj->remove_command == NULL) outofmem(__FILE__, "HTSaveToFile"); - - sprintf (ret_obj->remove_command, REMOVE_COMMAND, fnam); + + sprintf(ret_obj->remove_command, + REMOVE_COMMAND, fnam, "", "", "", "", "", ""); #ifdef VMS if (IsBinary && UseFixedRecords) { @@ -745,7 +751,8 @@ SaveToFile_tempname: * sizeof (char),1); if (FIXED_RECORD_COMMAND == NULL) outofmem(__FILE__, "HTSaveToFile"); - sprintf(FIXED_RECORD_COMMAND, FIXED_RECORD_COMMAND_MASK, fnam); + sprintf(FIXED_RECORD_COMMAND, + FIXED_RECORD_COMMAND_MASK, fnam, "", "", "", "", "", ""); } else { #endif /* VMS */ ret_obj->end_command = (char *)calloc (sizeof(char)*12,1); @@ -909,7 +916,7 @@ PUBLIC HTStream* HTCompressed ARGS3( */ Compressed_tempname: tempname(fnam, NEW_FILE); - if ((cp = strchr(fnam, '.')) != NULL) { + if ((cp = strrchr(fnam, '.')) != NULL) { *cp = '\0'; if (!strcasecomp(anchor->content_type, "text/html")) { #ifdef VMS @@ -970,6 +977,7 @@ Compressed_tempname: FREE(me); return NULL; } + chmod(fnam, 0600); /* * Make command to process file. - FM @@ -978,7 +986,7 @@ Compressed_tempname: strlen(fnam)) * sizeof(char)); if (me->end_command == NULL) outofmem(__FILE__, "HTCompressed"); - sprintf (me->end_command, uncompress_mask, fnam); + sprintf(me->end_command, uncompress_mask, fnam, "", "", "", "", "", ""); FREE(uncompress_mask); /* @@ -988,7 +996,7 @@ Compressed_tempname: strlen(fnam)) * sizeof(char)); if (me->remove_command == NULL) outofmem(__FILE__, "HTCompressed"); - sprintf (me->remove_command, REMOVE_COMMAND, fnam); + sprintf(me->remove_command, REMOVE_COMMAND, fnam, "", "", "", "", "", ""); /* * Save the filename and return the structure. - FM diff --git a/src/HTML.c b/src/HTML.c index f49e0084..2e98ae53 100644 --- a/src/HTML.c +++ b/src/HTML.c @@ -138,24 +138,23 @@ PRIVATE void actually_set_style ARGS1(HTStructured *, me) { if (!me->text) { /* First time through */ #ifdef EXP_CHARTRANS - html_get_chartrans_info(me); + LYGetChartransInfo(me); UCSetTransParams(&me->T, me->UCLYhndl, me->UCI, HTAnchor_getUCLYhndl(me->node_anchor,UCT_STAGE_HTEXT), HTAnchor_getUCInfoStage(me->node_anchor,UCT_STAGE_HTEXT)); #endif /* EXP_CHARTRANS */ - me->text = HText_new2(me->node_anchor, me->target); - HText_beginAppend(me->text); - HText_setStyle(me->text, me->new_style); - me->in_word = NO; - LYCheckForContentBase(me); + me->text = HText_new2(me->node_anchor, me->target); + HText_beginAppend(me->text); + HText_setStyle(me->text, me->new_style); + me->in_word = NO; + LYCheckForContentBase(me); } else { - HText_setStyle(me->text, me->new_style); + HText_setStyle(me->text, me->new_style); } me->old_style = me->new_style; me->style_change = NO; - } /* @@ -522,14 +521,16 @@ PRIVATE void HTML_start_element ARGS5( #endif 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? */ HTChildAnchor *ID_A = NULL; /* HTML_foo_ID anchor */ int url_type = 0, i = 0; BOOL intern_flag = FALSE; char *cp = NULL; + int ElementNumber = element_number; if (LYMapsOnly) { - if (!(element_number == HTML_MAP || element_number == HTML_AREA || - element_number == HTML_BASE)) { + if (!(ElementNumber == HTML_MAP || ElementNumber == HTML_AREA || + ElementNumber == HTML_BASE)) { return; } } @@ -586,7 +587,7 @@ PRIVATE void HTML_start_element ARGS5( fprintf(stderr, " ca=%d\n", hashStyles[hcode].color); } - if (displayStyles[element_number].color > -2) /* actually set */ + if (displayStyles[element_number].color > -1) /* actually set */ { if (TRACE) fprintf(stderr, "CSSTRIM: start_element: top <%s>\n", HTML_dtd.tags[element_number].name); @@ -598,24 +599,16 @@ PRIVATE void HTML_start_element ARGS5( me->inStyle[element_number]=1; /* this is a goodthing(tm) */ #endif - switch (element_number) { + switch (ElementNumber) { case HTML_HTML: if (!me->text) UPDATE_STYLE; - if (me->inUnderline) { /* This block could go away(?) - kw */ - HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); - me->inUnderline = FALSE; - } break; case HTML_HEAD: if (!me->text) UPDATE_STYLE; - if (me->inUnderline) { /* This block could go away(?) - kw */ - HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); - me->inUnderline = FALSE; - } break; case HTML_BASE: @@ -709,10 +702,6 @@ PRIVATE void HTML_start_element ARGS5( if (!me->text) UPDATE_STYLE; HTChunkClear(&me->title); - if (me->inUnderline) { /* This block could go away(?) - kw */ - HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); - me->inUnderline = FALSE; - } break; case HTML_LINK: @@ -966,6 +955,17 @@ PRIVATE void HTML_start_element ARGS5( break; } + if (me->inA) { + /* + * Ugh! The LINK tag, which is a HEAD element, + * is in an Anchor, which is BODY element. All + * we can do is close the Anchor and cross our + * fingers. - FM + */ + SET_SKIP_STACK(HTML_A); + HTML_end_element(me, HTML_A, (char **)&include); + } + /* * Create anchors for the links that simulate * a toolbar. - FM @@ -990,11 +990,12 @@ PRIVATE void HTML_start_element ARGS5( NULL, /* Addresss */ (HTLinkType*)0))) { /* Type */ HText_appendCharacter(me->text, '#'); - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_setLastChar(me->text, ' '); /* absorb white space */ + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); HText_setToolbar(me->text); } - HText_beginAnchor(me->text, me->CurrentA); + HText_beginAnchor(me->text, me->inUnderline, me->CurrentA); if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_START_CHAR); #if USE_COLOR_STYLE @@ -1020,7 +1021,7 @@ PRIVATE void HTML_start_element ARGS5( #endif if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); + HText_endAnchor(me->text, 0); } FREE(href); FREE(title); @@ -1135,10 +1136,6 @@ PRIVATE void HTML_start_element ARGS5( case HTML_BODY: if (!me->text) UPDATE_STYLE; - if (me->inUnderline) { /* This block could go away(?) - kw */ - HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); - me->inUnderline = FALSE; - } LYCheckForID(me, present, value, (int)HTML_BODY_ID); if (HText_hasToolbar(me->text)) HText_appendParagraph(me->text); @@ -1190,6 +1187,10 @@ PRIVATE void HTML_start_element ARGS5( me->inBASE) ? me->base_href : me->node_anchor->address)); + if (me->inA) { + SET_SKIP_STACK(HTML_A); + HTML_end_element(me, HTML_A, (char **)&include); + } me->CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ NULL, /* Tag */ @@ -1203,17 +1204,20 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); HTML_put_character(me, ' '); me->in_word = NO; - HText_beginAnchor(me->text, me->CurrentA); + LYCheckForID(me, present, value, (int)HTML_FRAME_ID); + HText_beginAnchor(me->text, me->inUnderline, me->CurrentA); if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_START_CHAR); HTML_put_string(me, (id_string ? id_string : href)); FREE(href); - FREE(id_string); if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); + HText_endAnchor(me->text, 0); LYEnsureSingleSpace(me); + } else { + LYCheckForID(me, present, value, (int)HTML_FRAME_ID); } + FREE(id_string); break; case HTML_NOFRAMES: @@ -1223,11 +1227,84 @@ PRIVATE void HTML_start_element ARGS5( LYResetParagraphAlignment(me); break; + case HTML_IFRAME: + if (!me->text) + UPDATE_STYLE; + if (present && present[HTML_IFRAME_NAME] && + value[HTML_IFRAME_NAME] && *value[HTML_IFRAME_NAME]) { + StrAllocCopy(id_string, value[HTML_IFRAME_NAME]); + if (current_char_set) + LYExpandString(&id_string); + /* + * Convert any HTML entities or decimal escaping. - FM + */ + LYUnEscapeEntities(id_string, TRUE, FALSE); + LYTrimHead(id_string); + LYTrimTail(id_string); + } + 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); + url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE); + + /* + * Check whether a base tag is in effect. - FM + */ + if ((me->inBASE && *href != '\0' && *href != '#') && + (temp = HTParse(href, me->base_href, PARSE_ALL)) && + *temp != '\0') + /* + * Use reference related to the base. + */ + StrAllocCopy(href, temp); + FREE(temp); + + /* + * Check whether to fill in localhost. - FM + */ + LYFillLocalFileURL((char **)&href, + ((*href != '\0' && *href != '#' && + me->inBASE) ? + me->base_href : me->node_anchor->address)); + + if (me->inA) + HTML_end_element(me, HTML_A, (char **)&include); + me->CurrentA = HTAnchor_findChildAndLink( + me->node_anchor, /* Parent */ + NULL, /* Tag */ + href, /* Addresss */ + INTERN_LT); /* Type */ + LYEnsureDoubleSpace(me); + LYResetParagraphAlignment(me); + if (me->inUnderline == FALSE) + HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR); + HTML_put_string(me, "IFRAME:"); + if (me->inUnderline == FALSE) + HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); + HTML_put_character(me, ' '); + me->in_word = NO; + LYCheckForID(me, present, value, (int)HTML_IFRAME_ID); + HText_beginAnchor(me->text, me->inUnderline, me->CurrentA); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_START_CHAR); + HTML_put_string(me, (id_string ? id_string : href)); + FREE(href); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + HText_endAnchor(me->text, 0); + LYEnsureSingleSpace(me); + } else { + LYCheckForID(me, present, value, (int)HTML_IFRAME_ID); + } + FREE(id_string); + break; + case HTML_BANNER: case HTML_MARQUEE: change_paragraph_style(me, styles[HTML_BANNER]); UPDATE_STYLE; - if (me->sp->tag_number == element_number) + if (me->sp->tag_number == ElementNumber) LYEnsureDoubleSpace(me); if (!HText_hasToolbar(me->text) && (ID_A = HTAnchor_findChildAndLink( @@ -1235,8 +1312,8 @@ PRIVATE void HTML_start_element ARGS5( LYToolbarName, /* Tag */ NULL, /* Addresss */ (HTLinkType*)0))) { /* Type */ - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); HText_setToolbar(me->text); } LYCheckForID(me, present, value, (int)HTML_GEN_ID); @@ -1251,7 +1328,7 @@ PRIVATE void HTML_start_element ARGS5( "HTML: ****** Maximum nesting of %d divisions exceeded!\n", MAX_NESTING); } - if (element_number == HTML_CENTER) { + if (ElementNumber == HTML_CENTER) { me->DivisionAlignments[me->Division_Level] = HT_CENTER; change_paragraph_style(me, styles[HTML_DCENTER]); UPDATE_STYLE; @@ -1302,6 +1379,45 @@ PRIVATE void HTML_start_element ARGS5( i_prior_style = element_number; */ + /* + * Check whether we have an H# in a list, + * and if so, treat it as an LH. - FM + */ + if ((me->List_Nesting_Level >= 0) && + (me->sp[0].tag_number == HTML_UL || + me->sp[0].tag_number == HTML_OL || + me->sp[0].tag_number == HTML_MENU || + me->sp[0].tag_number == HTML_DIR)) { + if (HTML_dtd.tags[HTML_LH].contents == SGML_EMPTY) { + ElementNumber = HTML_LH; + if (!me->text) + UPDATE_STYLE; + } else { + me->new_style = me->sp[0].style; + ElementNumber = me->sp[0].tag_number; + UPDATE_STYLE; + } + /* + * Some authors use H# headers as a substitute for + * FONT, so check if this one immediately followed + * an LI. If so, both me->inP and me->in_word will + * be FALSE (though the line might not be empty due + * to a bullet and/or nbsp) and we can assume it is + * just for a FONT change. We thus will not create + * another line break nor add to the current left + * indentation. - FM + */ + if (!(me->inP == FALSE && me->in_word == NO)) { + HText_appendParagraph(me->text); + HTML_put_character(me, HT_NON_BREAK_SPACE); + HText_setLastChar(me->text, ' '); + me->in_word = NO; + me->inP = FALSE; + } + LYCheckForID(me, present, value, (int)HTML_H_ID); + break; + } + if (present && present[HTML_H_ALIGN] && value[HTML_H_ALIGN] && *value[HTML_H_ALIGN]) { if (!strcasecomp(value[HTML_H_ALIGN], "center")) @@ -1312,7 +1428,7 @@ PRIVATE void HTML_start_element ARGS5( !strcasecomp(value[HTML_H_ALIGN], "justify")) change_paragraph_style(me, styles[HTML_HLEFT]); else - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); } else if (me->Division_Level >= 0) { if (me->DivisionAlignments[me->Division_Level] == HT_CENTER) { change_paragraph_style(me, styles[HTML_HCENTER]); @@ -1322,14 +1438,14 @@ PRIVATE void HTML_start_element ARGS5( change_paragraph_style(me, styles[HTML_HRIGHT]); } } else { - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); } UPDATE_STYLE; LYCheckForID(me, present, value, (int)HTML_H_ID); if ((bold_headers == TRUE || - (element_number == HTML_H1 && bold_H1 == TRUE)) && - (styles[element_number]->font&HT_BOLD)) { + (ElementNumber == HTML_H1 && bold_H1 == TRUE)) && + (styles[ElementNumber]->font&HT_BOLD)) { if (me->inBoldA == FALSE && me->inBoldH == FALSE) { HText_appendCharacter(me->text, LY_BOLD_START_CHAR); } @@ -1375,7 +1491,8 @@ PRIVATE void HTML_start_element ARGS5( * to start a newline, if needed, then fall through * to handle attributes. - FM */ - if (HText_LastLineSize(me->text)) { + if (HText_LastLineSize(me->text, FALSE)) { + HText_setLastChar(me->text, ' '); /* absorb white space */ HText_appendCharacter(me->text, '\r'); } } else if (!(me->inLABEL && !me->inP)) { @@ -1401,8 +1518,8 @@ PRIVATE void HTML_start_element ARGS5( else if (!strcasecomp(value[HTML_P_ALIGN], "right") && !(me->List_Nesting_Level >= 0 && !me->inP)) me->sp->style->alignment = HT_RIGHT; - else if (!strcasecomp(value[HTML_H_ALIGN], "left") || - !strcasecomp(value[HTML_H_ALIGN], "justify")) + else if (!strcasecomp(value[HTML_P_ALIGN], "left") || + !strcasecomp(value[HTML_P_ALIGN], "justify")) me->sp->style->alignment = HT_LEFT; } @@ -1420,7 +1537,8 @@ PRIVATE void HTML_start_element ARGS5( case HTML_BR: UPDATE_STYLE; LYCheckForID(me, present, value, (int)HTML_GEN_ID); - if (LYCollapseBRs == FALSE || HText_LastLineSize(me->text)) { + if ((LYCollapseBRs == FALSE) || + HText_LastLineSize(me->text, FALSE)) { HText_setLastChar(me->text, ' '); /* absorb white space */ HText_appendCharacter(me->text, '\r'); } @@ -1452,9 +1570,10 @@ PRIVATE void HTML_start_element ARGS5( * the last line are blank. - FM */ UPDATE_STYLE; - if (HText_LastLineSize(me->text)) { - HText_appendCharacter(me->text, '\r'); - } else if (!HText_PreviousLineSize(me->text)) { + if (HText_LastLineSize(me->text, FALSE)) { + HText_setLastChar(me->text, ' '); /* absorb white space */ + HText_appendCharacter(me->text, '\r'); + } else if (!HText_PreviousLineSize(me->text, FALSE)) { HText_RemovePreviousLine(me->text); } me->in_word = NO; @@ -1535,8 +1654,9 @@ PRIVATE void HTML_start_element ARGS5( * paragraph separator for other blocks. - FM */ if (me->List_Nesting_Level >= 0 || - me->sp[0].tag_number == HTML_ADDRESS) { - HText_appendCharacter(me->text, '\r'); + me->sp[0].tag_number == HTML_ADDRESS) { + HText_setLastChar(me->text, ' '); /* absorb white space */ + HText_appendCharacter(me->text, '\r'); } else { HText_appendParagraph(me->text); } @@ -1617,7 +1737,8 @@ PRIVATE void HTML_start_element ARGS5( "HTML: Column out of bounds. Using space instead of TAB.\n"); } else { for (i = column; i < target; i++) - HText_appendCharacter(me->text, ' '); + HText_appendCharacter(me->text, ' '); + HText_setLastChar(me->text, ' '); /* absorb white space */ } } me->in_word = NO; @@ -1760,21 +1881,21 @@ PRIVATE void HTML_start_element ARGS5( * or single-quotes. - FM */ if (!(me->Quote_Level & 1)) - HText_appendCharacter(me->text, '"'); + HTML_put_character(me, '"'); else - HText_appendCharacter(me->text, '`'); + HTML_put_character(me, '`'); me->Quote_Level++; break; case HTML_PRE: /* Formatted text */ - if (!HText_PreviousLineSize(me->text)) + if (!HText_PreviousLineSize(me->text, FALSE)) me->inPRE = FALSE; else me->inPRE = TRUE; case HTML_LISTING: /* Litteral text */ case HTML_XMP: case HTML_PLAINTEXT: - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); UPDATE_STYLE; LYCheckForID(me, present, value, (int)HTML_GEN_ID); if (me->comment_end) @@ -1783,17 +1904,17 @@ PRIVATE void HTML_start_element ARGS5( case HTML_BLOCKQUOTE: case HTML_BQ: - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); UPDATE_STYLE; - if (me->sp->tag_number == element_number) + if (me->sp->tag_number == ElementNumber) LYEnsureDoubleSpace(me); LYCheckForID(me, present, value, (int)HTML_BQ_ID); break; case HTML_NOTE: - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); UPDATE_STYLE; - if (me->sp->tag_number == element_number) + if (me->sp->tag_number == ElementNumber) LYEnsureDoubleSpace(me); LYCheckForID(me, present, value, (int)HTML_NOTE_ID); { @@ -1835,9 +1956,9 @@ PRIVATE void HTML_start_element ARGS5( break; case HTML_ADDRESS: - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); UPDATE_STYLE; - if (me->sp->tag_number == element_number) + if (me->sp->tag_number == ElementNumber) LYEnsureDoubleSpace(me); LYCheckForID(me, present, value, (int)HTML_ADDRESS_ID); break; @@ -1895,7 +2016,7 @@ PRIVATE void HTML_start_element ARGS5( LYCheckForID(me, present, value, (int)HTML_GEN_ID); HText_setLastChar(me->text, ' '); /* absorb white space */ if (!me->style_change) { - if (HText_LastLineSize(me->text)) + if (HText_LastLineSize(me->text, FALSE)) HText_appendCharacter(me->text, '\r'); } else { UPDATE_STYLE; @@ -2000,7 +2121,7 @@ PRIVATE void HTML_start_element ARGS5( me->List_Nesting_Level++; if (me->List_Nesting_Level <= 0) { - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); } else if (me->List_Nesting_Level >= 6) { change_paragraph_style(me, styles[HTML_OL6]); @@ -2021,10 +2142,10 @@ PRIVATE void HTML_start_element ARGS5( !(present && present[HTML_UL_TYPE] && value[HTML_UL_TYPE] && 0==strcasecomp(value[HTML_UL_TYPE], "PLAIN"))) { - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); } else { change_paragraph_style(me, styles[HTML_DIR]); - element_number = HTML_DIR; + ElementNumber = HTML_DIR; } } else if (me->List_Nesting_Level >= 6) { @@ -2035,7 +2156,7 @@ PRIVATE void HTML_start_element ARGS5( change_paragraph_style(me, styles[HTML_OL6]); } else { change_paragraph_style(me, styles[HTML_MENU6]); - element_number = HTML_DIR; + ElementNumber = HTML_DIR; } } else { @@ -2048,7 +2169,7 @@ PRIVATE void HTML_start_element ARGS5( } else { change_paragraph_style(me, styles[HTML_MENU1 + me->List_Nesting_Level - 1]); - element_number = HTML_DIR; + ElementNumber = HTML_DIR; } } UPDATE_STYLE; /* update to the new style */ @@ -2060,7 +2181,7 @@ PRIVATE void HTML_start_element ARGS5( me->List_Nesting_Level++; if (me->List_Nesting_Level <= 0) { - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); } else if (me->List_Nesting_Level >= 6) { change_paragraph_style(me, styles[HTML_MENU6]); @@ -2080,6 +2201,7 @@ PRIVATE void HTML_start_element ARGS5( HTML_put_character(me, HT_NON_BREAK_SPACE); HText_setLastChar(me->text, ' '); me->in_word = NO; + me->inP = FALSE; break; case HTML_LI: @@ -2253,9 +2375,9 @@ PRIVATE void HTML_start_element ARGS5( break; case HTML_FN: - change_paragraph_style(me, styles[element_number]); + change_paragraph_style(me, styles[ElementNumber]); UPDATE_STYLE; - if (me->sp->tag_number == element_number) + if (me->sp->tag_number == ElementNumber) LYEnsureDoubleSpace(me); LYCheckForID(me, present, value, (int)HTML_FN_ID); if (me->inUnderline == FALSE) @@ -2416,9 +2538,10 @@ PRIVATE void HTML_start_element ARGS5( if (present[HTML_A_CHARSET] && value[HTML_A_CHARSET] && *value[HTML_A_CHARSET] != '\0') { dest_char_set = UCGetLYhndl_byMIME(value[HTML_A_CHARSET]); - if (dest_char_set < 0) + if (dest_char_set < 0) { dest_char_set = UCLYhndl_for_unrec; } + } if (title != NULL || dest_ismap == TRUE || dest_char_set >= 0) #else if (title != NULL || dest_ismap == TRUE) @@ -2442,7 +2565,8 @@ PRIVATE void HTML_start_element ARGS5( FREE(title); } UPDATE_STYLE; - HText_beginAnchor(me->text, me->CurrentA); + me->CurrentANum = HText_beginAnchor(me->text, + me->inUnderline, me->CurrentA); if (me->inBoldA == TRUE && me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_START_CHAR); #ifdef NOTUSED_FOTEMODS @@ -2451,8 +2575,10 @@ PRIVATE void HTML_start_element ARGS5( * content bold, and let the check in HTML_end_element() deal * with any dangling end tag this creates. - FM */ - if (href == NULL && me->inBoldA == FALSE) + if (href == NULL && me->inBoldA == FALSE) { + SET_SKIP_STACK(HTML_A); HTML_end_element(me, HTML_A, (char **)&include); + } #endif /* NOTUSED_FOTEMODS */ FREE(href); break; @@ -2496,31 +2622,53 @@ PRIVATE void HTML_start_element ARGS5( StrAllocCopy(map_href, value[HTML_IMG_USEMAP]); CHECK_FOR_INTERN(map_href); url_type = LYLegitimizeHREF(me, (char**)&map_href, TRUE, TRUE); - if (*map_href == '\0') { + /* + * If map_href ended up zero-length or otherwise doesn't + * have a hash, it can't be valid, so ignore it. - FM + */ + if (strchr(map_href, '#') == NULL) { FREE(map_href); } } - if (map_href && strchr(map_href, '#')) { + if (map_href) { /* * Check whether a base tag is in effect. - FM */ - if ((me->inBASE && *map_href != '#') && - (temp = HTParse(map_href, me->base_href, PARSE_ALL)) && - *temp != '\0') + if (!url_type && me->inBASE) { /* - * Use reference related to the base. + * If the + * USEMAP value is a lone fragment and LYSeekFragMAPinCur + * is set, we'll use the current document's URL for + * resolving. Otherwise use the BASE. - kw */ - StrAllocCopy(map_href, temp); - FREE(temp); + if ((*map_href == '#' && + LYSeekFragMAPinCur == TRUE)) { + /* + * Use reference related to the current stream. - FM + */ + temp = HTParse(map_href, me->node_anchor->address, + PARSE_ALL); + StrAllocCopy(map_href, temp); + UseBASE = FALSE; + } else { + /* + * Use reference related to the base. - FM + */ + temp = HTParse(map_href, me->base_href, PARSE_ALL); + StrAllocCopy(map_href, temp); + UseBASE = TRUE; + } + FREE(temp); + } /* * Check whether to fill in localhost. - FM */ LYFillLocalFileURL((char **)&map_href, - ((*map_href != '\0' && *map_href != '#' && - me->inBASE) ? - me->base_href : me->node_anchor->address)); + ((UseBASE && me->inBASE) ? + me->base_href : me->node_anchor->address)); + UseBASE = TRUE; /* * If it's not yet a URL, resolve versus @@ -2545,7 +2693,7 @@ PRIVATE void HTML_start_element ARGS5( * Check whether we want to suppress the server-side * ISMAP link if a client-side MAP is present. - FM */ - if (LYNoISMAPifUSEMAP && map_href) { + if (LYNoISMAPifUSEMAP && map_href && dest_ismap) { dest_ismap = FALSE; dest = NULL; } @@ -2700,25 +2848,26 @@ PRIVATE void HTML_start_element ARGS5( */ if (map_href) { if (dest_ismap) { - HTML_put_string(me, "[ISMAP]"); + HTML_put_string(me, "[ISMAP]"); } else if (dest) { - HTML_put_string(me, "[LINK]"); + HTML_put_string(me, "[LINK]"); } if (me->inBoldA == TRUE && me->inBoldH == FALSE) { HText_appendCharacter(me->text, LY_BOLD_END_CHAR); } me->inBoldA = FALSE; - HText_endAnchor(me->text); + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; if (dest_ismap || dest) - HText_appendCharacter(me->text, '-'); + HTML_put_character(me, '-'); if (id_string) { if ((ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ id_string, /* Tag */ NULL, /* Addresss */ (HTLinkType*)0)) != NULL) { /* Type */ - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); } } me->CurrentA = HTAnchor_findChildAndLink( @@ -2734,7 +2883,9 @@ PRIVATE void HTML_start_element ARGS5( HTAnchor_setTitle(dest, title); } } - HText_beginAnchor(me->text, me->CurrentA); + me->CurrentANum = HText_beginAnchor(me->text, + me->inUnderline, + me->CurrentA); if (me->inBoldA == FALSE && me->inBoldH == FALSE) { HText_appendCharacter(me->text, LY_BOLD_START_CHAR); } @@ -2745,8 +2896,9 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text, LY_BOLD_END_CHAR); } me->inBoldA = FALSE; - HText_endAnchor(me->text); - HText_appendCharacter(me->text, '-'); + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; + HTML_put_character(me, '-'); StrAllocCopy(alt_string, ((present && present[HTML_IMG_ISOBJECT]) ? @@ -2758,8 +2910,8 @@ PRIVATE void HTML_start_element ARGS5( id_string, /* Tag */ NULL, /* Addresss */ (HTLinkType*)0)) != NULL) { /* Type */ - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); } } } else if (map_href) { @@ -2771,8 +2923,8 @@ PRIVATE void HTML_start_element ARGS5( id_string, /* Tag */ NULL, /* Addresss */ (HTLinkType*)0)) != NULL) { /* Type */ - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); } } me->CurrentA = HTAnchor_findChildAndLink( @@ -2788,7 +2940,9 @@ PRIVATE void HTML_start_element ARGS5( HTAnchor_setTitle(dest, title); } } - HText_beginAnchor(me->text, me->CurrentA); + me->CurrentANum = HText_beginAnchor(me->text, + me->inUnderline, + me->CurrentA); if (me->inBoldA == FALSE && me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_START_CHAR); me->inBoldA = TRUE; @@ -2797,8 +2951,9 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text, LY_BOLD_END_CHAR); } me->inBoldA = FALSE; - HText_endAnchor(me->text); - HText_appendCharacter(me->text, '-'); + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; + HTML_put_character(me, '-'); StrAllocCopy(alt_string, ((present && present[HTML_IMG_ISOBJECT]) ? @@ -2812,8 +2967,8 @@ PRIVATE void HTML_start_element ARGS5( id_string, /* Tag */ NULL, /* Addresss */ (HTLinkType*)0)) != NULL) { /* Type */ - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); } } } @@ -2827,14 +2982,17 @@ PRIVATE void HTML_start_element ARGS5( href, /* Addresss */ (HTLinkType*)0); /* Type */ FREE(href); - HText_beginAnchor(me->text, me->CurrentA); + me->CurrentANum = HText_beginAnchor(me->text, + me->inUnderline, + me->CurrentA); if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_START_CHAR); HTML_put_string(me, alt_string); if (!me->inA) { if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; HTML_put_character(me, ' '); /* space char may be ignored */ me->in_word = NO; } else { @@ -2855,9 +3013,10 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text, LY_BOLD_END_CHAR); } me->inBoldA = FALSE; - HText_endAnchor(me->text); + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; if (dest_ismap || dest) - HText_appendCharacter(me->text, '-'); + HTML_put_character(me, '-'); } else { HTML_put_character(me, ' '); me->in_word = NO; @@ -2875,7 +3034,9 @@ PRIVATE void HTML_start_element ARGS5( HTAnchor_setTitle(dest, title); } } - HText_beginAnchor(me->text, me->CurrentA); + me->CurrentANum = HText_beginAnchor(me->text, + me->inUnderline, + me->CurrentA); if (me->inBoldA == FALSE && me->inBoldH == FALSE) { HText_appendCharacter(me->text, LY_BOLD_START_CHAR); } @@ -2886,7 +3047,8 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text, LY_BOLD_END_CHAR); } me->inBoldA = FALSE; - HText_endAnchor(me->text); + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; } } else { /* @@ -2904,8 +3066,8 @@ PRIVATE void HTML_start_element ARGS5( id_string, /* Tag */ NULL, /* Addresss */ (HTLinkType*)0)) != NULL) { /* Type */ - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); } } HTML_put_string(me, alt_string); @@ -2924,14 +3086,14 @@ PRIVATE void HTML_start_element ARGS5( case HTML_MAP: /* - * Load id_string if we have an ID or NAME. - FM + * Load id_string if we have a NAME or ID. - FM */ - if (present && present[HTML_MAP_ID] && - value[HTML_MAP_ID] && *value[HTML_MAP_ID]) { - StrAllocCopy(id_string, value[HTML_MAP_ID]); - } else if (present && present[HTML_MAP_NAME] && - value[HTML_MAP_NAME] && *value[HTML_MAP_NAME]) { + if (present && present[HTML_MAP_NAME] && + value[HTML_MAP_NAME] && *value[HTML_MAP_NAME]) { StrAllocCopy(id_string, value[HTML_MAP_NAME]); + } else if (present && present[HTML_MAP_ID] && + value[HTML_MAP_ID] && *value[HTML_MAP_ID]) { + StrAllocCopy(id_string, value[HTML_MAP_ID]); } if (id_string) { LYUnEscapeToLatinOne(&id_string, TRUE); @@ -2948,7 +3110,9 @@ PRIVATE void HTML_start_element ARGS5( * The MAP must be in the current stream, even if it * had a BASE tag, so we'll use its address here, but * still use the BASE, if present, when resolving the - * AREA elements in its content. - FM && KW + * AREA elements in it's content, unless the AREA's + * HREF is a lone fragment and LYSeekFragAREAinCur is + * set. - FM && KW */ StrAllocCopy(me->map_address, me->node_anchor->address); if ((cp = strrchr(me->map_address, '#')) != NULL) @@ -2990,9 +3154,12 @@ PRIVATE void HTML_start_element ARGS5( /* * Check whether a BASE tag is in effect, and use it * for resolving, even though we used this stream's - * address for locating the MAP itself. - FM + * address for locating the MAP itself, unless the + * HREF is a lone fragment and LYSeekFragAREAinCur + * is set. - FM */ - if ((me->inBASE && *href != '\0' && *href != '#') && + if (((me->inBASE && *href != '\0') && + !(*href == '#' && LYSeekFragAREAinCur == TRUE)) && (temp = HTParse(href, me->base_href, PARSE_ALL)) && *temp != '\0') /* @@ -3005,10 +3172,11 @@ PRIVATE void HTML_start_element ARGS5( * Check whether to fill in localhost. - FM */ LYFillLocalFileURL((char **)&href, - ((*href != '\0' && *href != '#' && - me->inBASE) ? - me->base_href : me->node_anchor->address)); - + ((((me->inBASE && *href != '\0') && + !(*href == '#' && + LYSeekFragAREAinCur == TRUE))) + ? + me->base_href : me->node_anchor->address)); if (!(url_type = is_url(href))) { temp = HTParse(href, me->node_anchor->address, PARSE_ALL); if (!(temp && *temp)) { @@ -3090,6 +3258,10 @@ PRIVATE void HTML_start_element ARGS5( me->inFIG = TRUE; if (!me->text) UPDATE_STYLE; + if (me->inA) { + SET_SKIP_STACK(HTML_A); + HTML_end_element(me, HTML_A, (char **)&include); + } if (!present || (present && !present[HTML_FIG_ISOBJECT])) { LYEnsureDoubleSpace(me); @@ -3129,25 +3301,23 @@ PRIVATE void HTML_start_element ARGS5( me->inBASE) ? me->base_href : me->node_anchor->address)); - if ((me->CurrentA = HTAnchor_findChildAndLink( + me->CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ NULL, /* Tag */ href, /* Addresss */ - INTERN_LT))) { /* Type */ - HText_beginAnchor(me->text, me->CurrentA); - if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_START_CHAR); - HTML_put_string(me, - (present[HTML_FIG_ISOBJECT] ? + INTERN_LT); /* Type */ + HText_beginAnchor(me->text, me->inUnderline, me->CurrentA); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_START_CHAR); + HTML_put_string(me, (present[HTML_FIG_ISOBJECT] ? (present[HTML_FIG_IMAGEMAP] ? "(IMAGE)" : "(OBJECT)") : "[FIGURE]")); - if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); - HText_appendCharacter(me->text, '-'); - HTML_put_character(me, ' '); /* space char may be ignored */ - me->in_word = NO; - } + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + HText_endAnchor(me->text, 0); + HTML_put_character(me, '-'); + HTML_put_character(me, ' '); /* space char may be ignored */ + me->in_word = NO; } FREE(href); } @@ -3303,27 +3473,32 @@ PRIVATE void HTML_start_element ARGS5( me->inBASE) ? me->base_href : me->node_anchor->address)); - if ((me->CurrentA = HTAnchor_findChildAndLink( + if (me->inA) { + SET_SKIP_STACK(HTML_A); + HTML_end_element(me, HTML_A, (char **)&include); + } + me->CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ NULL, /* Tag */ href, /* Addresss */ - INTERN_LT))) { /* Type */ - if (!me->text) { - UPDATE_STYLE; - } else { - HTML_put_character(me, ' '); - HText_appendCharacter(me->text, '+'); - } - HText_beginAnchor(me->text, me->CurrentA); - if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_START_CHAR); - HTML_put_string(me, "[OVERLAY]"); - if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); + INTERN_LT); /* Type */ + if (!me->text) { + UPDATE_STYLE; + } else { HTML_put_character(me, ' '); - me->in_word = NO; + HText_appendCharacter(me->text, '+'); } + me->CurrentANum = HText_beginAnchor(me->text, + me->inUnderline, + me->CurrentA); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_START_CHAR); + HTML_put_string(me, "[OVERLAY]"); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + HText_endAnchor(me->text, me->CurrentANum); + HTML_put_character(me, ' '); + me->in_word = NO; } FREE(href); } @@ -3445,19 +3620,30 @@ PRIVATE void HTML_start_element ARGS5( FREE(base); FREE(code); - if ((href && *href) && - (me->CurrentA = HTAnchor_findChildAndLink( + if (href && *href) { + if (me->inA) { + if (me->inBoldA == TRUE && me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + HText_endAnchor(me->text, me->CurrentANum); + HTML_put_character(me, '-'); + } + me->CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ NULL, /* Tag */ href, /* Addresss */ - (HTLinkType*)0))) { /* Type */ - HText_beginAnchor(me->text, me->CurrentA); + (HTLinkType*)0); /* Type */ + me->CurrentANum = HText_beginAnchor(me->text, + me->inUnderline, + me->CurrentA); if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_START_CHAR); HTML_put_string(me, alt_string); - if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); + if (me->inA == FALSE) { + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; + } HTML_put_character(me, ' '); /* space char may be ignored */ me->in_word = NO; } @@ -3510,23 +3696,34 @@ PRIVATE void HTML_start_element ARGS5( if (!me->text) UPDATE_STYLE; - if ((me->CurrentA = HTAnchor_findChildAndLink( + if (me->inA) { + if (me->inBoldA == TRUE && me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + HText_endAnchor(me->text, me->CurrentANum); + HTML_put_character(me, '-'); + } else { + HTML_put_character(me, ' '); /* space char may be ignored */ + me->in_word = NO; + } + me->CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ NULL, /* Tag */ href, /* Addresss */ - INTERN_LT))) { /* Type */ - HTML_put_character(me, ' '); /* space char may be ignored */ - me->in_word = NO; - HText_beginAnchor(me->text, me->CurrentA); - if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_START_CHAR); - HTML_put_string(me, "[BGSOUND]"); + INTERN_LT); /* Type */ + me->CurrentANum = HText_beginAnchor(me->text, + me->inUnderline, + me->CurrentA); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_START_CHAR); + HTML_put_string(me, "[BGSOUND]"); + if (me->inA == FALSE) { if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); - HTML_put_character(me, ' '); /* space char may be ignored */ - me->in_word = NO; + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; } + HTML_put_character(me, ' '); /* space char may be ignored */ + me->in_word = NO; FREE(href); } break; @@ -3616,21 +3813,33 @@ PRIVATE void HTML_start_element ARGS5( me->inBASE) ? me->base_href : me->node_anchor->address)); - if ((me->CurrentA = HTAnchor_findChildAndLink( + if (me->inA) { + if (me->inBoldA == TRUE && me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + HText_endAnchor(me->text, me->CurrentANum); + HTML_put_character(me, '-'); + } + me->CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ NULL, /* Tag */ href, /* Addresss */ - INTERN_LT))) { /* Type */ - HText_beginAnchor(me->text, me->CurrentA); - if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_START_CHAR); - HTML_put_string(me, alt_string); + INTERN_LT); /* Type */ + me->CurrentANum = HText_beginAnchor(me->text, + me->inUnderline, + me->CurrentA); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_START_CHAR); + HTML_put_string(me, alt_string); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + if (me->inA == FALSE) { if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); - HTML_put_character(me, ' '); - me->in_word = NO; + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; } + HTML_put_character(me, ' '); + me->in_word = NO; } FREE(href); } else if (*alt_string) { @@ -3855,9 +4064,21 @@ PRIVATE void HTML_start_element ARGS5( break; case HTML_FIELDSET: + if (!me->text) + UPDATE_STYLE; + LYEnsureDoubleSpace(me); + LYResetParagraphAlignment(me); LYCheckForID(me, present, value, (int)HTML_FIELDSET_ID); break; + case HTML_LEGEND: + if (!me->text) + UPDATE_STYLE; + LYEnsureDoubleSpace(me); + LYResetParagraphAlignment(me); + LYCheckForID(me, present, value, (int)HTML_LEGEND_ID); + break; + case HTML_LABEL: LYCheckForID(me, present, value, (int)HTML_LABEL_ID); break; @@ -3866,20 +4087,41 @@ PRIVATE void HTML_start_element ARGS5( LYCheckForID(me, present, value, (int)HTML_KEYGEN_ID); break; - case HTML_INPUT: + case HTML_BUTTON: { InputFieldData I; int chars; - BOOL UseALTasVALUE = FALSE; - BOOL HaveSRClink = FALSE; - BOOL IsSubmitOrReset = FALSE; + + /* init */ + I.align=NULL; I.accept=NULL; I.checked=NO; I.class=NULL; + I.disabled=NO; I.error=NULL; I.height= NULL; I.id=NULL; + I.lang=NULL; I.max=NULL; I.maxlength=NULL; I.md=NULL; + I.min=NULL; I.name=NULL; I.size=NULL; I.src=NULL; + I.type=NULL; I.value=NULL; I.width=NULL; + + UPDATE_STYLE; + if ((present && present[HTML_BUTTON_TYPE] && + value[HTML_BUTTON_TYPE]) && + (!strcasecomp((char *)value[HTML_BUTTON_TYPE], "submit") || + !strcasecomp((char *)value[HTML_BUTTON_TYPE], "reset"))) { + /* + * It's a button for submitting or resetting a form. - FM + */ + I.type = (char *)value[HTML_BUTTON_TYPE]; + } else { + /* + * Ugh, it's a button for a script. - FM + */ + HTML_put_string(me," [BUTTON] "); + break; + } /* * Make sure we're in a form. */ if (!me->inFORM) { if (TRACE) { - fprintf(stderr, "HTML: INPUT tag not within FORM tag\n"); + fprintf(stderr, "HTML: BUTTON tag not within FORM tag\n"); } else if (!me->inBadHTML) { _statusline(BAD_HTML_USE_TRACE); me->inBadHTML = TRUE; @@ -3893,16 +4135,146 @@ PRIVATE void HTML_start_element ARGS5( */ } - /* Check for unclosed TEXTAREA */ - if (me->inTEXTAREA) { - if (TRACE) { - fprintf(stderr, "HTML: Missing TEXTAREA end tag.\n"); - } else if (!me->inBadHTML) { - _statusline(BAD_HTML_USE_TRACE); - me->inBadHTML = TRUE; - sleep(MessageSecs); + /* + * Before any input field, add a collapsible space if + * we're not in a PRE block, to promote a wrap there + * for any long values that would extent past the right + * margin from our current position in the line. If + * we are in a PRE block, start a new line if the last + * line already is within 6 characters of the wrap point + * for PRE blocks. - FM + */ + if (me->sp[0].tag_number != HTML_PRE && !me->inPRE && + me->sp->style->freeFormat) { + HTML_put_character(me, ' '); + me->in_word = NO; + } else if (HText_LastLineSize(me->text, FALSE) > (LYcols - 7)) { + HTML_put_character(me, '\n'); + me->in_word = NO; + } + HTML_put_character(me, '('); + + if (present && present[HTML_BUTTON_NAME] && value[HTML_BUTTON_NAME]) + I.name = (char *)value[HTML_BUTTON_NAME]; + else + I.name = ""; + + if (present && present[HTML_BUTTON_VALUE] && + value[HTML_BUTTON_VALUE] && *value[HTML_BUTTON_VALUE]) { + /* + * Convert any HTML entities or decimal escaping. - FM + */ + int CurrentCharSet = current_char_set; + BOOL CurrentEightBitRaw = HTPassEightBitRaw; + BOOLEAN CurrentUseDefaultRawMode = LYUseDefaultRawMode; + HTCJKlang CurrentHTCJK = HTCJK; + int len; + + me->UsePlainSpace = TRUE; + if (current_char_set) { + LYExpandString((char **)&value[HTML_BUTTON_VALUE]); + } + LYUnEscapeEntities((char *)value[HTML_BUTTON_VALUE], + me->UsePlainSpace, me->HiddenValue); + I.value = (char *)value[HTML_BUTTON_VALUE]; + /* + * Convert any newlines or tabs to spaces, + * and trim any lead or trailing spaces. - FM + */ + convert_to_spaces(I.value, FALSE); + while (I.value && I.value[0] == ' ') + I.value++; + len = strlen(I.value) - 1; + while (len > 0 && I.value[len] == ' ') + I.value[len--] = '\0'; + me->UsePlainSpace = FALSE; + } + + if (present && present[HTML_BUTTON_DISABLED]) + I.disabled = YES; + + if (present && present[HTML_BUTTON_CLASS] && /* Not yet used. */ + value[HTML_BUTTON_CLASS] && *value[HTML_BUTTON_CLASS]) + I.class = (char *)value[HTML_BUTTON_CLASS]; + + if (present && present[HTML_BUTTON_ID] && + value[HTML_BUTTON_ID] && *value[HTML_BUTTON_ID]) { + I.id = (char *)value[HTML_BUTTON_ID]; + LYCheckForID(me, present, value, (int)HTML_BUTTON_ID); + } + + if (present && present[HTML_BUTTON_LANG] && /* Not yet used. */ + value[HTML_BUTTON_LANG] && *value[HTML_BUTTON_LANG]) + I.lang = (char *)value[HTML_BUTTON_LANG]; + + chars = HText_beginInput(me->text, me->inUnderline, &I); + /* + * Submit and reset buttons have values which don't change, + * so HText_beginInput() sets I.value to the string which + * should be displayed, and we'll enter that instead of + * underscore placeholders into the HText structure to + * see it instead of underscores when dumping or printing. + * We also won't worry about a wrap in PRE blocks, because + * the line editor never is invoked for submit or reset + * buttons. - LE & FM + */ + if (me->sp[0].tag_number == HTML_PRE || + !me->sp->style->freeFormat) { + /* + * We have a submit or reset button in a PRE block, + * so output the entire value from the markup. If + * it extends to the right margin, it will wrap + * there, and only the portion before that wrap will + * be hightlighted on screen display (Yuk!) but we + * may as well show the rest of the full value on + * the next or more lines. - FM + */ + while (I.value[i]) + HTML_put_character(me, I.value[i++]); + } else { + /* + * The submit or reset button is not in a PRE block. + * Note that if a wrap occurs before outputting the + * entire value, the wrapped portion will not be + * highlighted or clearly indicated as part of the + * link for submission or reset (Yuk!). + * We'll replace any spaces in the submit or reset + * button value with nbsp, to promote a wrap at the + * space we ensured would be present before the start + * of the string, as when we use all underscores + * instead of the INPUT's actual value, but we could + * still get a wrap at the right margin, instead, if + * the value is greater than a line width for the + * current style. Also, if chars somehow ended up + * longer than the length of the actual value + * (shouldn't have), we'll continue padding with nbsp + * up to the length of chars. - FM + */ + for (i = 0; I.value[i]; i++) { + HTML_put_character(me, + (I.value[i] == ' ' ? + HT_NON_BREAK_SPACE : I.value[i])); + } + while (i < chars) { + HTML_put_character(me, HT_NON_BREAK_SPACE); } } + HTML_put_character(me, ')'); + if (me->sp[0].tag_number != HTML_PRE && + me->sp->style->freeFormat) { + HTML_put_character(me, ' '); + me->in_word = NO; + } + } + break; + + case HTML_INPUT: + { + InputFieldData I; + int chars; + BOOL UseALTasVALUE = FALSE; + BOOL HaveSRClink = FALSE; + BOOL IsSubmitOrReset = FALSE; /* init */ I.align=NULL; I.accept=NULL; I.checked=NO; I.class=NULL; @@ -3926,15 +4298,14 @@ PRIVATE void HTML_start_element ARGS5( me->sp->style->freeFormat) { HTML_put_character(me, ' '); me->in_word = NO; - } else if (HText_LastLineSize(me->text) > (LYcols - 7)) { + } else if (HText_LastLineSize(me->text, FALSE) > (LYcols - 7)) { HTML_put_character(me, '\n'); me->in_word = NO; } - if (present && present[HTML_INPUT_NAME] && value[HTML_INPUT_NAME]) - I.name = (char *)value[HTML_INPUT_NAME]; - else - I.name = ""; + /* + * Get the TYPE and make sure we can handle it. - FM + */ if (present && present[HTML_INPUT_TYPE] && value[HTML_INPUT_TYPE] && *value[HTML_INPUT_TYPE]) { I.type = (char *)value[HTML_INPUT_TYPE]; @@ -3948,7 +4319,8 @@ PRIVATE void HTML_start_element ARGS5( * Not yet implemented. */ HTML_put_string(me,"[RANGE Input] (Not yet implemented.)"); - HText_DisableCurrentForm(); + if (me->inFORM) + HText_DisableCurrentForm(); if (TRACE) fprintf(stderr, "HTML: Ignoring TYPE=\"range\"\n"); break; @@ -3968,12 +4340,60 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); } - HText_DisableCurrentForm(); + if (me->inFORM) + HText_DisableCurrentForm(); if (TRACE) fprintf(stderr, "HTML: Ignoring TYPE=\"file\"\n"); break; + + } else if (!strcasecomp(I.type, "button")) { + /* + * Ugh, a button for a script. + */ + HTML_put_string(me,"[BUTTON] "); + break; + } + } + + /* + * Check if we're in a form. - FM + */ + if (!me->inFORM) { + if (TRACE) { + fprintf(stderr, "HTML: INPUT tag not within FORM tag\n"); + } else if (!me->inBadHTML) { + _statusline(BAD_HTML_USE_TRACE); + me->inBadHTML = TRUE; + sleep(MessageSecs); } + /* + * We'll process it, since the chances of a crash are + * small, and we probably do have a form started. - FM + * + break; + */ } + + /* + * Check for an unclosed TEXTAREA. + */ + if (me->inTEXTAREA) { + if (TRACE) { + fprintf(stderr, "HTML: Missing TEXTAREA end tag.\n"); + } else if (!me->inBadHTML) { + _statusline(BAD_HTML_USE_TRACE); + me->inBadHTML = TRUE; + sleep(MessageSecs); + } + } + + /* + * Handle the INPUT as for a FORM. - FM + */ + if (present && present[HTML_INPUT_NAME] && value[HTML_INPUT_NAME]) + I.name = (char *)value[HTML_INPUT_NAME]; + else + I.name = ""; if ((present && present[HTML_INPUT_ALT] && value[HTML_INPUT_ALT] && *value[HTML_INPUT_ALT] && I.type && !strcasecomp(I.type, "image")) && @@ -4022,20 +4442,23 @@ PRIVATE void HTML_start_element ARGS5( me->base_href : me->node_anchor->address)); - if ((me->CurrentA = HTAnchor_findChildAndLink( + if (me->inA) { + SET_SKIP_STACK(HTML_A); + HTML_end_element(me, HTML_A, (char **)&include); + } + me->CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ NULL, /* Tag */ href, /* Addresss */ - (HTLinkType*)0))) { /* Type */ - HText_beginAnchor(me->text, me->CurrentA); - if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_START_CHAR); - HTML_put_string(me, "[IMAGE]"); - if (me->inBoldH == FALSE) - HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); - HText_appendCharacter(me->text, '-'); - } + (HTLinkType*)0); /* Type */ + HText_beginAnchor(me->text, me->inUnderline, me->CurrentA); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_START_CHAR); + HTML_put_string(me, "[IMAGE]"); + if (me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + HText_endAnchor(me->text, 0); + HTML_put_character(me, '-'); HaveSRClink = TRUE; } FREE(href); @@ -4147,7 +4570,7 @@ PRIVATE void HTML_start_element ARGS5( value[HTML_INPUT_MD] && *value[HTML_INPUT_MD]) I.md = (char *)value[HTML_INPUT_MD]; - chars = HText_beginInput(me->text, &I); + chars = HText_beginInput(me->text, me->inUnderline, &I); /* * Submit and reset buttons have values which don't change, * so HText_beginInput() sets I.value to the string which @@ -4175,7 +4598,7 @@ PRIVATE void HTML_start_element ARGS5( chars = 0; me->in_word = YES; if (me->sp[0].tag_number != HTML_PRE && - !me->sp->style->freeFormat) { + me->sp->style->freeFormat) { HTML_put_character(me, ' '); me->in_word = NO; } @@ -4190,7 +4613,7 @@ PRIVATE void HTML_start_element ARGS5( chars = 0; me->in_word = YES; if (me->sp[0].tag_number != HTML_PRE && - !me->sp->style->freeFormat) { + me->sp->style->freeFormat) { HTML_put_character(me, ' '); me->in_word = NO; } @@ -4338,8 +4761,8 @@ PRIVATE void HTML_start_element ARGS5( (HTLinkType*)0))) { /* Type */ if (!me->text) UPDATE_STYLE; - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); StrAllocCopy(me->textarea_id, id_string); } else { FREE(me->textarea_id); @@ -4351,9 +4774,24 @@ PRIVATE void HTML_start_element ARGS5( break; case HTML_SELECT: + /* + * Check for an already open SELECT block. - FM + */ + if (me->inSELECT) { + if (TRACE) { + fprintf(stderr, + "HTML: Embedded SELECT start end. Faking SELECT end tag.\n"); + } else if (!me->inBadHTML) { + _statusline(BAD_HTML_USE_TRACE); + me->inBadHTML = TRUE; + sleep(MessageSecs); + } + SET_SKIP_STACK(HTML_SELECT); + HTML_end_element(me, HTML_SELECT, (char **)&include); + } { char *name = NULL; - BOOLEAN multiple=NO; + BOOLEAN multiple = NO; char *size = NULL; /* @@ -4439,7 +4877,7 @@ PRIVATE void HTML_start_element ARGS5( if ((multiple == NO && LYSelectPopups == TRUE) && (me->sp[0].tag_number == HTML_PRE || me->inPRE == TRUE || !me->sp->style->freeFormat) && - HText_LastLineSize(me->text) > (LYcols - 8)) { + HText_LastLineSize(me->text, FALSE) > (LYcols - 8)) { /* * Force a newline when we're using a popup in * a PRE block and are within 7 columns from the @@ -4583,13 +5021,13 @@ PRIVATE void HTML_start_element ARGS5( value[HTML_OPTION_ID], /* Tag */ NULL, /* Addresss */ (HTLinkType*)0)) != NULL) { /* Type */ - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); I.id = (char *)value[HTML_OPTION_ID]; } } - HText_beginInput(me->text, &I); + HText_beginInput(me->text, me->inUnderline, &I); if (HTCurSelectGroupType == F_CHECKBOX_TYPE) { /* @@ -4601,6 +5039,7 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text, '_'); HText_appendCharacter(me->text, ']'); HText_appendCharacter(me->text, ' '); + HText_setLastChar(me->text, ' '); /* absorb white space */ me->in_word = NO; } else if (LYSelectPopups == FALSE) { /* @@ -4612,6 +5051,7 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text, '_'); HText_appendCharacter(me->text, ')'); HText_appendCharacter(me->text, ' '); + HText_setLastChar(me->text, ' '); /* absorb white space */ me->in_word = NO; } } @@ -4634,26 +5074,106 @@ PRIVATE void HTML_start_element ARGS5( StrAllocCopy(me->LastOptionValue, value[HTML_OPTION_VALUE]); else StrAllocCopy(me->LastOptionValue, me->option.data); + + /* + * If this is a popup option, print its option + * for use in selecting option by number. - LE + */ + if (HTCurSelectGroupType == F_RADIO_TYPE && + LYSelectPopups && + keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) { + char marker[8]; + int opnum = HText_getOptionNum(me->text); + + if (opnum > 0 && opnum < 100000) { + sprintf(marker,"(%d)", opnum); + HTML_put_string(me, marker); + for (i = strlen(marker); i < 5; ++i) { + HTML_put_character(me, '_'); + } + } + } } break; case HTML_TABLE: - UPDATE_STYLE; - LYCheckForID(me, present, value, (int)HTML_TABLE_ID); + /* + * Not implemented. Just treat as a division + * with respect to any ALIGN attribute, with + * a default of HT_LEFT. - FM + */ me->inTABLE = TRUE; - break; + if (me->Division_Level < (MAX_NESTING - 1)) { + me->Division_Level++; + } else if (TRACE) { + fprintf(stderr, + "HTML: ****** Maximum nesting of %d divisions/tables exceeded!\n", + MAX_NESTING); + } + if (present && present[HTML_TABLE_ALIGN] && + value[HTML_TABLE_ALIGN] && *value[HTML_TABLE_ALIGN]) { + if (!strcasecomp(value[HTML_TABLE_ALIGN], "center")) { + me->DivisionAlignments[me->Division_Level] = HT_CENTER; + change_paragraph_style(me, styles[HTML_DCENTER]); + UPDATE_STYLE; + me->current_default_alignment = styles[HTML_DCENTER]->alignment; + } else if (!strcasecomp(value[HTML_TABLE_ALIGN], "right")) { + me->DivisionAlignments[me->Division_Level] = HT_RIGHT; + change_paragraph_style(me, styles[HTML_DRIGHT]); + UPDATE_STYLE; + me->current_default_alignment = styles[HTML_DRIGHT]->alignment; + } else { + me->DivisionAlignments[me->Division_Level] = HT_LEFT; + change_paragraph_style(me, styles[HTML_DLEFT]); + UPDATE_STYLE; + me->current_default_alignment = styles[HTML_DLEFT]->alignment; + } + } else { + me->DivisionAlignments[me->Division_Level] = HT_LEFT; + change_paragraph_style(me, styles[HTML_DLEFT]); + UPDATE_STYLE; + me->current_default_alignment = styles[HTML_DLEFT]->alignment; + } + LYCheckForID(me, present, value, (int)HTML_TABLE_ID); + break; case HTML_TR: /* * Not yet implemented. Just start a new row, - * if needed, and check for an ID link. - FM + * if needed, act on an ALIGN attribute if present, + * and check for an ID link. - FM */ UPDATE_STYLE; - if (HText_LastLineSize(me->text)) { + if (HText_LastLineSize(me->text, FALSE)) { + HText_setLastChar(me->text, ' '); /* absorb white space */ HText_appendCharacter(me->text, '\r'); } - LYCheckForID(me, present, value, (int)HTML_TR_ID); me->in_word = NO; + + if (LYoverride_default_alignment(me)) { + me->sp->style->alignment = styles[me->sp[0].tag_number]->alignment; + } else if (me->List_Nesting_Level >= 0 || + ((me->Division_Level < 0) && + (!strcmp(me->sp->style->name, "Normal") || + !strcmp(me->sp->style->name, "Preformatted")))) { + me->sp->style->alignment = HT_LEFT; + } else { + me->sp->style->alignment = me->current_default_alignment; + } + if (present && present[HTML_TR_ALIGN] && value[HTML_TR_ALIGN]) { + if (!strcasecomp(value[HTML_TR_ALIGN], "center") && + !(me->List_Nesting_Level >= 0 && !me->inP)) + me->sp->style->alignment = HT_CENTER; + else if (!strcasecomp(value[HTML_TR_ALIGN], "right") && + !(me->List_Nesting_Level >= 0 && !me->inP)) + me->sp->style->alignment = HT_RIGHT; + else if (!strcasecomp(value[HTML_TR_ALIGN], "left") || + !strcasecomp(value[HTML_TR_ALIGN], "justify")) + me->sp->style->alignment = HT_LEFT; + } + + LYCheckForID(me, present, value, (int)HTML_TR_ID); + me->inP = FALSE; break; case HTML_THEAD: @@ -4711,7 +5231,7 @@ PRIVATE void HTML_start_element ARGS5( } /* end switch */ - if (HTML_dtd.tags[element_number].contents != SGML_EMPTY) { + if (HTML_dtd.tags[ElementNumber].contents != SGML_EMPTY) { if (me->skip_stack > 0) { if (TRACE) fprintf(stderr, @@ -4737,7 +5257,7 @@ PRIVATE void HTML_start_element ARGS5( (me->sp)--; me->sp[0].style = me->new_style; /* Stack new style */ - me->sp[0].tag_number = element_number; + me->sp[0].tag_number = ElementNumber; if (TRACE) fprintf(stderr,"HTML:begin_element: adding style to stack - %s\n", @@ -4746,7 +5266,7 @@ PRIVATE void HTML_start_element ARGS5( #if defined(USE_COLOR_STYLE) /* end empty tags straight away */ - if (HTML_dtd.tags[element_number].contents == SGML_EMPTY) + if (HTML_dtd.tags[ElementNumber].contents == SGML_EMPTY) { if (TRACE) fprintf(stderr, "STYLE:begin_element:ending EMPTY element style\n"); @@ -4766,7 +5286,8 @@ PRIVATE void HTML_start_element ARGS5( { end = start; start = strstr(lookfrom, tmp); - lookfrom = start + 1; + if (start) + lookfrom = start + 1; } while (start); if (end) @@ -4809,6 +5330,7 @@ PRIVATE void HTML_end_element ARGS3( { int i = 0; char *temp = NULL, *cp = NULL; + BOOL BreakFlag = FALSE; #ifdef CAREFUL /* parser assumed to produce good nesting */ if (element_number != me->sp[0].tag_number && @@ -4836,6 +5358,26 @@ PRIVATE void HTML_end_element ARGS3( * SGML_EMPTY in HTMLDTD.c. - FM & KW */ if (HTML_dtd.tags[element_number].contents != SGML_EMPTY) { + if ((element_number != me->sp[0].tag_number) && + me->skip_stack <= 0 && + HTML_dtd.tags[HTML_LH].contents != SGML_EMPTY && + (me->sp[0].tag_number == HTML_UL || + me->sp[0].tag_number == HTML_OL || + me->sp[0].tag_number == HTML_MENU || + me->sp[0].tag_number == HTML_DIR) && + (element_number == HTML_H1 || + element_number == HTML_H2 || + element_number == HTML_H3 || + element_number == HTML_H4 || + element_number == HTML_H6 || + element_number == HTML_H6)) { + /* + * Set the break flag if we're popping + * a dummy HTML_LH substituted for an + * HTML_H# encountered in a list. + */ + BreakFlag = TRUE; + } if (me->skip_stack > 0) { if (TRACE) fprintf(stderr, @@ -4856,6 +5398,33 @@ PRIVATE void HTML_end_element ARGS3( * if an overrun does occur. - FM */ return; + } else if (element_number == HTML_SELECT && + me->sp[0].tag_number != HTML_SELECT) { + /* + * Ignore non-corresponding SELECT tags, since we + * probably popped it and closed the SELECT block + * to deal with markup which amounts to a nested + * SELECT, or an out of order FORM end tag. - FM + */ + return; + } else if ((element_number != me->sp[0].tag_number) && + HTML_dtd.tags[HTML_LH].contents == SGML_EMPTY && + (me->sp[0].tag_number == HTML_UL || + me->sp[0].tag_number == HTML_OL || + me->sp[0].tag_number == HTML_MENU || + me->sp[0].tag_number == HTML_DIR) && + (element_number == HTML_H1 || + element_number == HTML_H2 || + element_number == HTML_H3 || + element_number == HTML_H4 || + element_number == HTML_H6 || + element_number == HTML_H6)) { + /* + * It's an H# for which we substituted + * an HTML_LH, which we've declared as + * SGML_EMPTY, so just return. - FM + */ + return; } else if (me->sp < (me->stack + MAX_NESTING - 1)) { (me->sp)++; if (TRACE) @@ -4868,7 +5437,9 @@ PRIVATE void HTML_end_element ARGS3( "Stack underflow error! Tried to pop off more styles than exist in stack\n"); } } - + if (BreakFlag == TRUE) + return; + /* * Check for unclosed TEXTAREA. - FM */ @@ -4889,10 +5460,6 @@ PRIVATE void HTML_end_element ARGS3( case HTML_HTML: if (!me->text) UPDATE_STYLE; - if (me->inUnderline) { /* This block could go away(?) - kw */ - HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); - me->inUnderline = FALSE; - } if (me->inA || me->inSELECT || me->inTEXTAREA) if (TRACE) { fprintf(stderr, @@ -4907,10 +5474,6 @@ PRIVATE void HTML_end_element ARGS3( case HTML_HEAD: if (!me->text) UPDATE_STYLE; - if (me->inUnderline) { /* This block could go away(?) - kw */ - HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); - me->inUnderline = FALSE; - } if (HText_hasToolbar(me->text)) HText_appendParagraph(me->text); break; @@ -4997,10 +5560,6 @@ PRIVATE void HTML_end_element ARGS3( case HTML_BODY: if (!me->text) UPDATE_STYLE; - if (me->inUnderline) { /* This block could go away(?) - kw */ - HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); - me->inUnderline = FALSE; - } if (me->inA || me->inSELECT || me->inTEXTAREA) if (TRACE) { fprintf(stderr, @@ -5019,6 +5578,7 @@ PRIVATE void HTML_end_element ARGS3( break; case HTML_NOFRAMES: + case HTML_IFRAME: if (!me->text) UPDATE_STYLE; LYEnsureDoubleSpace(me); @@ -5125,7 +5685,8 @@ PRIVATE void HTML_end_element ARGS3( * We're in an ADDRESS. Treat </P> as an instruction * to start a newline, if needed. - kw */ - if (HText_LastLineSize(me->text)) { + if (HText_LastLineSize(me->text, FALSE)) { + HText_setLastChar(me->text, ' '); /* absorb white space */ HText_appendCharacter(me->text, '\r'); } } else { @@ -5261,9 +5822,9 @@ PRIVATE void HTML_end_element ARGS3( * or single-quotes. - FM */ if (!(me->Quote_Level & 1)) - HText_appendCharacter(me->text, '"'); + HTML_put_character(me, '"'); else - HText_appendCharacter(me->text, '\''); + HTML_put_character(me, '\''); break; case HTML_PRE: /* Formatted text */ @@ -5342,7 +5903,8 @@ PRIVATE void HTML_end_element ARGS3( UPDATE_STYLE; if (me->inBoldA == TRUE && me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); + HText_endAnchor(me->text, me->CurrentANum); + me->CurrentANum = 0; me->inBoldA = FALSE; if (me->Underline_Level > 0 && me->inUnderline == FALSE) { HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR); @@ -5380,6 +5942,10 @@ PRIVATE void HTML_end_element ARGS3( me->inFIGwithP = FALSE; me->inFIG = FALSE; change_paragraph_style(me, me->sp->style); /* Often won't really change */ + if (me->List_Nesting_Level >= 0) { + UPDATE_STYLE; + HText_NegateLineOne(me->text); + } break; case HTML_OBJECT: @@ -5781,11 +6347,27 @@ End_Object: break; case HTML_FIELDSET: + if (!me->text) + UPDATE_STYLE; + LYEnsureDoubleSpace(me); + LYResetParagraphAlignment(me); + change_paragraph_style(me, me->sp->style); /* Often won't really change */ + break; + + case HTML_LEGEND: + if (!me->text) + UPDATE_STYLE; + LYEnsureDoubleSpace(me); + LYResetParagraphAlignment(me); + change_paragraph_style(me, me->sp->style); /* Often won't really change */ break; case HTML_LABEL: break; + case HTML_BUTTON: + break; + case HTML_TEXTAREA: { InputFieldData I; @@ -5850,7 +6432,7 @@ End_Object: for (i = 0; i < me->textarea_rows; i++) { I.value = cp; - chars = HText_beginInput(me->text, &I); + chars = HText_beginInput(me->text, me->inUnderline, &I); for (; chars > 0; chars--) HTML_put_character(me, '_'); HText_appendCharacter(me->text, '\r'); @@ -5865,7 +6447,7 @@ End_Object: while (cp) { I.value = cp; - chars = HText_beginInput(me->text, &I); + chars = HText_beginInput(me->text, me->inUnderline, &I); for (chars = atoi(me->textarea_cols); chars>0; chars--) HTML_put_character(me, '_'); HText_appendCharacter(me->text, '\r'); @@ -5937,7 +6519,9 @@ End_Object: * Finish the data off. */ HTChunkTerminate(&me->option); - /* finish the previous option @@@@@ */ + /* + * Finish the previous option. + */ ptr = HText_setLastOptionValue(me->text, me->option.data, me->LastOptionValue, @@ -6006,6 +6590,16 @@ End_Object: case HTML_TABLE: me->inTABLE = FALSE; + if (me->Division_Level >= 0) + me->Division_Level--; + if (me->Division_Level >= 0) + me->sp->style->alignment = + me->DivisionAlignments[me->Division_Level]; + change_paragraph_style(me, me->sp->style); + UPDATE_STYLE; + me->current_default_alignment = me->sp->style->alignment; + if (me->List_Nesting_Level >= 0) + HText_NegateLineOne(me->text); break; /* These TABLE related elements may now not be SGML_EMPTY. - kw */ @@ -6077,7 +6671,8 @@ End_Object: { end = start; start = strstr(lookfrom, tmp); - lookfrom = start + 1; + if (start) + lookfrom = start + 1; } while (start); /* trim the last matching element off the end @@ -6085,6 +6680,7 @@ End_Object: */ if (end) *end='\0'; + hcode=hash_code(lookfrom && *lookfrom ? lookfrom : &tmp[1]); if (TRACE) fprintf(stderr, "CSS:%s (trimmed %s, END_ELEMENT)\n", Style_className, tmp); } @@ -6177,7 +6773,7 @@ PRIVATE void HTML_free ARGS1(HTStructured *, me) HTML_put_string(me, me->comment_end); if (me->text) { /* - * Emphasis containters, A, FONT, and FORM may be declared + * Emphasis containers, A, FONT, and FORM may be declared * SGML_EMPTY in HTMLDTD.c, and SGML_character() in SGML.c * may check for their end tags to call HTML_end_element() * directly (with a check in that to bypass decrementing @@ -6213,6 +6809,24 @@ PRIVATE void HTML_free ARGS1(HTStructured *, me) } /* + * If we're interactive and have hidden links but no visible + * links, add a message informing the user about this and + * suggesting use of the 'l'ist command. - FM + */ + if (!dump_output_immediately && + HText_sourceAnchors(me->text) < 1 && + HText_HiddenLinkCount(me->text) > 0) { + HTML_start_element(me, HTML_P, 0, 0, (char **)&include); + HTML_put_character(me, '['); + HTML_start_element(me, HTML_EM, 0, 0, (char **)&include); + HTML_put_string(me, + "Document has only hidden links. Use the 'l'ist command."); + HTML_end_element(me, HTML_EM, (char **)&include); + HTML_put_character(me, ']'); + HTML_end_element(me, HTML_P, (char **)&include); + } + + /* * Now call the cleanup function. - FM */ HText_endAppend(me->text); @@ -6435,7 +7049,8 @@ PUBLIC HTStructured* HTML_new ARGS3( me->node_anchor = anchor; me->CurrentA = NULL; - me->base_href = NULL;; + me->CurrentANum = 0; + me->base_href = NULL; me->map_address = NULL; me->title.size = 0; @@ -6549,9 +7164,9 @@ PUBLIC HTStructured* HTML_new ARGS3( me->comment_start = NULL; me->comment_end = NULL; -#ifdef EXP_CHARTRANS - html_get_chartrans_info(me); +#ifdef EXP_CHARTRANS + LYGetChartransInfo(me); UCTransParams_clear(&me->T); #endif /* EXP_CHARTRANS */ diff --git a/src/HTML.h b/src/HTML.h index 3593ba8a..8d313e81 100644 --- a/src/HTML.h +++ b/src/HTML.h @@ -50,6 +50,7 @@ struct _HTStructured { HTStreamClass targetClass; /* Output routines */ HTChildAnchor * CurrentA; /* current HTML_A anchor */ + int CurrentANum; /* current HTML_A number */ char * base_href; /* current HTML_BASE href */ char * map_address; /* current HTML_MAP address */ diff --git a/src/LYBookmark.c b/src/LYBookmark.c index caf859a1..c5f26577 100644 --- a/src/LYBookmark.c +++ b/src/LYBookmark.c @@ -347,7 +347,7 @@ PUBLIC void save_bookmark_link ARGS2( if (first_time) { fprintf(fp,"<head>\n"); #ifdef EXP_CHARTRANS - add_META_charset_to_fd(fp, -1); + LYAddMETAcharsetToFD(fp, -1); #endif fprintf(fp,"<title>%s</title>\n</head>\n",BOOKMARK_TITLE); fprintf(fp,"\ diff --git a/src/LYCharSets.c b/src/LYCharSets.c index 016d24c4..b7c84b9d 100644 --- a/src/LYCharSets.c +++ b/src/LYCharSets.c @@ -3,6 +3,8 @@ #include "HTCJK.h" #include "LYGlobalDefs.h" +#include "UCMap.h" +#include "UCDefs.h" #include "LYCharSets.h" #include "LYCharUtils.h" #ifdef EXP_CHARTRANS @@ -27,11 +29,11 @@ PUBLIC BOOLEAN LYHaveCJKCharacterSet = FALSE; extern void UCInit NOARGS; extern int UCInitialized; #else -#ifndef MAX_CHARSETS -#define MAX_CHARSETS +#ifndef MAXCHARSETS +#define MAXCHARSETS #endif -#ifndef MAX_CHARSETSP -#define MAX_CHARSETSP +#ifndef MAXCHARSETSP +#define MAXCHARSETSP #endif #endif /* EXP_CHARTRANS */ @@ -2044,7 +2046,7 @@ PUBLIC char * SevenBitApproximations[] = { /* * Add the array name to LYCharSets */ -PUBLIC char ** LYCharSets[MAX_CHARSETS]={ +PUBLIC char ** LYCharSets[MAXCHARSETS]={ ISO_Latin1, ISO_Latin2, ISO_LatinN, @@ -2060,14 +2062,14 @@ PUBLIC char ** LYCharSets[MAX_CHARSETS]={ Korean, Taipei, SevenBitApproximations, - ISO_Latin1 /* maybe... - kw */ + ISO_Latin1 /* Maybe... - KW */ }; /* * Add the name that the user will see below. * The order of LYCharSets and char_set_names MUST be the same */ -PUBLIC char * LYchar_set_names[MAX_CHARSETSP]={ +PUBLIC char * LYchar_set_names[MAXCHARSETSP]={ "ISO Latin 1 ", "ISO Latin 2 ", "Other ISO Latin ", @@ -2090,20 +2092,19 @@ PUBLIC char * LYchar_set_names[MAX_CHARSETSP]={ PUBLIC int LYNumCharsets = 0; /* will be initialized later by UC_Register... */ -#include <UCDefs.h> /* * Associate additional pieces of info with each of the charsets listed * above. * Will be automatically modified (and extended) by charset translations - * which are loaded using the EXP_CHARTRANS mechanism. + * which are loaded using the chartrans mechanism. * Most important piece of info to put here is a MIME charset name. - * Used for EXP_CHARTRANS. + * Used for chartrans. * The order of LYCharSets and LYCharSet_UC MUST be the same. * * Note that most of the charsets added by the new mechanism in src/chrtrans * don't show up here at all. They don't have to. */ -PUBLIC LYUCcharset LYCharSet_UC[MAX_CHARSETS]= +PUBLIC LYUCcharset LYCharSet_UC[MAXCHARSETS]= { {-1,"iso-8859-1", UCT_ENC_8BIT,UCT_REP_IS_LAT1,UCT_CP_IS_LAT1,UCT_R_LAT1, UCT_R_LAT1}, @@ -2116,14 +2117,16 @@ PUBLIC LYUCcharset LYCharSet_UC[MAX_CHARSETS]= {-1,"macintosh", UCT_ENC_8BIT,0,0, UCT_R_8BIT,UCT_R_ASCII}, {-1,"x-next", UCT_ENC_8BIT,0,0, UCT_R_8BIT,UCT_R_ASCII}, {-1,"koi8-r", UCT_ENC_8BIT,0,0, UCT_R_8BIT,UCT_R_ASCII}, -/* There is no strict correlation for the next five, since the tranfer - * charset gets decoded into Display Char Set by the CJK code (separate - * from EXP_CHARTRANS mechanism). For now, just put something there for - * MIME charset name. */ - {-1,"iso-2022-cn", UCT_ENC_CJK,0,0, UCT_R_8BIT,UCT_R_ASCII}, + /* + * There is no strict correlation for the next five, since the tranfer + * charset gets decoded into Display Char Set by the CJK code (separate + * from EXP_CHARTRANS mechanism). For now, just put something there for + * MIME charset name. + */ + {-1,"euc-cn", UCT_ENC_CJK,0,0, UCT_R_8BIT,UCT_R_ASCII}, {-1,"euc-jp", UCT_ENC_CJK,0,0, UCT_R_8BIT,UCT_R_ASCII}, {-1,"shift_jis", UCT_ENC_CJK,0,0, UCT_R_8BIT,UCT_R_ASCII}, - {-1,"iso-2022-kr", UCT_ENC_CJK,0,0, UCT_R_8BIT,UCT_R_ASCII}, + {-1,"euc-kr", UCT_ENC_CJK,0,0, UCT_R_8BIT,UCT_R_ASCII}, {-1,"big5", UCT_ENC_CJK,0,0, UCT_R_8BIT,UCT_R_ASCII}, {-1,"us-ascii", UCT_ENC_7BIT,UCT_REP_SUBSETOF_LAT1, UCT_CP_SUBSETOF_LAT1, @@ -2133,13 +2136,14 @@ PUBLIC LYUCcharset LYCharSet_UC[MAX_CHARSETS]= #endif #if defined(USE_SLANG) || defined(EXP_CHARTRANS) + /* * Add the code of the the lowest character with the high bit set * that can be directly displayed. * Used by SLANG and for EXP_CHARTRANS. * The order of LYCharSets and LYlowest_eightbit MUST be the same. */ -PUBLIC int LYlowest_eightbit[MAX_CHARSETS]={ +PUBLIC int LYlowest_eightbit[MAXCHARSETS]={ 160, /* ISO Latin 1 */ 160, /* ISO Latin 2 */ 160, /* Other ISO Latin */ @@ -2179,31 +2183,35 @@ PUBLIC void HTMLSetCharacterHandling ARGS1(int,i) #ifdef EXP_CHARTRANS if (LYCharSet_UC[i].enc != UCT_ENC_CJK) { int chndl = 0; + if (UCAssume_MIMEcharset) chndl = UCGetLYhndl_byMIME(UCAssume_MIMEcharset); HTCJK = NOCJK; kanji_code = NOKANJI; - if (i == (chndl < 0 ? 0 : chndl)) + if (i == (chndl < 0 ? 0 : chndl)) { LYRawMode = LYUseDefaultRawMode ? TRUE : FALSE; - else + } else { LYRawMode = LYUseDefaultRawMode ? FALSE : TRUE; - if (LYRawMode) + } + if (LYRawMode) { HTPassEightBitRaw = (LYlowest_eightbit[i] <= 160); - else + } else { HTPassEightBitRaw = FALSE; + } HTPassEightBitNum = ((LYCharSet_UC[i].codepoints & UCT_CP_SUPERSETOF_LAT1) || (LYCharSet_UC[i].like8859 & UCT_R_HIGH8BIT)); - if (LYRawMode || i == chndl) + if (LYRawMode || i == chndl) { HTPassHighCtrlRaw = (LYlowest_eightbit[i] <= 130); - else + } else { HTPassHighCtrlRaw = FALSE; + } HTPassHighCtrlNum = FALSE; } else -#endif +#endif /* EXP_CHARTRANS */ if (!strncmp(LYchar_set_names[i], "ISO Latin 1", 11)) { HTCJK = NOCJK; kanji_code = NOKANJI; @@ -2295,11 +2303,14 @@ PUBLIC void HTMLSetCharacterHandling ARGS1(int,i) #endif /* EXP_CHARTRANS */ #ifdef USE_SLANG - if (LYlowest_eightbit[i] > 191) - /* higher than this may output cntrl chars to screen - kw */ + if (LYlowest_eightbit[i] > 191) { + /* + * Higher than this may output cntrl chars to screen. - KW + */ SLsmg_Display_Eight_Bit = 191; - else + } else { SLsmg_Display_Eight_Bit = LYlowest_eightbit[i]; + } #endif /* USE_SLANG */ return; @@ -2343,11 +2354,11 @@ PUBLIC void HTMLSetUseDefaultRawMode ARGS2(int,i, BOOLEAN,modeflag) } else #endif /* EXP_CHARTRANS */ if (!strncmp(LYchar_set_names[i], "ISO Latin 1", 11) || - !strncmp(LYchar_set_names[i], "Chinese", 7) || - !strncmp(LYchar_set_names[i], "Japanese (EUC)", 14) || - !strncmp(LYchar_set_names[i], "Japanese (SJIS)", 15) || - !strncmp(LYchar_set_names[i], "Korean", 6) || - !strncmp(LYchar_set_names[i], "Taipei (Big5)", 13)) { + !strncmp(LYchar_set_names[i], "Chinese", 7) || + !strncmp(LYchar_set_names[i], "Japanese (EUC)", 14) || + !strncmp(LYchar_set_names[i], "Japanese (SJIS)", 15) || + !strncmp(LYchar_set_names[i], "Korean", 6) || + !strncmp(LYchar_set_names[i], "Taipei (Big5)", 13)) { if (modeflag == TRUE) { LYUseDefaultRawMode = TRUE; } else { @@ -2497,13 +2508,10 @@ PUBLIC CONST char * HTMLGetEntityName ARGS1(int,i) } /* - * Function to return the values of the - * ISO_Latin1 Character Set. It assumes - * the strings have only one character, - * and restores nbsp to 160 and shy to - * 173, but keeps our substitutions for - * characters that are not part of the - * ISO-8859-1 charset. - FM + * Function to return the values of the ISO_Latin1 Character Set. + * It assumes the strings have only one character, and restores + * nbsp to 160 and shy to 173, but keeps our substitutions for + * characters that are not part of the ISO-8859-1 charset. - FM * * Return '\0' to signal that there isn't a one-character * equivalent. Caller must check! and do whatever additional @@ -2527,8 +2535,12 @@ PUBLIC char HTMLGetLatinOneValue ARGS1(int,i) break; default: - if (ch && ISO_Latin1[i][1]) /* Got a string longer than 1 char */ - return '\0'; + if (ch && ISO_Latin1[i][1]) { + /* + * Got a string longer than 1 char. + */ + return '\0'; + } break; } @@ -2546,12 +2558,10 @@ PUBLIC void HTMLUseCharacterSet ARGS1(int,i) HTMLSetHaveCJKCharacterSet(i); return; } + /* - * Initializer, calls initialization function for the - * CHARTRANS handling if compiled in. - kw - * (Also to ensure this module is linked - * if the external model is common block, and the - * module is ever placed in a library. - FM) ?? + * Initializer, calls initialization function for the + * CHARTRANS handling if compiled in. - KW */ PUBLIC int LYCharSetsDeclared NOPARAMS { diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c index cf1ecfb8..14b036ce 100644 --- a/src/LYCharUtils.c +++ b/src/LYCharUtils.c @@ -195,18 +195,35 @@ PUBLIC char * LYUnEscapeEntities ARGS3( ** Check for a numeric or named entity. - FM */ if (*p == '&') { + BOOL isHex = FALSE; + BOOL isDecimal = FALSE; p++; len = strlen(p); /* ** Check for a numeric entity. - FM */ if (*p == '#' && len > 2 && - (unsigned char)*(p+1) < 127 && - isdigit((unsigned char)*(p+1))) { - cp = ++p; + (unsigned char)*(p+1) == 'x' && + (unsigned char)*(p+2) < 127 && + isxdigit((unsigned char)*(p+2))) { + isHex = TRUE; + } else if (*p == '#' && len > 2 && + (unsigned char)*(p+1) < 127 && + isdigit((unsigned char)*(p+1))) { + isDecimal = TRUE; + } + if (isHex || isDecimal) { + if (isHex) { + p += 2; + cp = p; + } else { + cp = ++p; + } while (*p && (unsigned char)*p < 127 && - isdigit((unsigned char)*p)) + (isHex ? isxdigit((unsigned char)*p) : + isdigit((unsigned char)*p))) { p++; + } /* ** Save the terminator and isolate the digit(s). - FM */ @@ -222,7 +239,8 @@ PUBLIC char * LYUnEscapeEntities ARGS3( ** or HTCJK set. ** (4) Is 128 - 159 and we don't have HTPassHighCtrlNum set. */ - if ((sscanf(cp, "%d", &value) != 1) || + if (((isHex ? sscanf(cp, "%x", &value) : + sscanf(cp, "%d", &value)) != 1) || (value > 255 && value != 8194 && value != 8195 && value != 8201 && value != 8211 && value != 8212 && value != 8482) || @@ -240,6 +258,8 @@ PUBLIC char * LYUnEscapeEntities ARGS3( */ *q++ = '&'; *q++ = '#'; + if (isHex) + *q++ = 'x'; if (cpe != '\0') *(p-1) = cpe; p = cp; @@ -292,6 +312,8 @@ PUBLIC char * LYUnEscapeEntities ARGS3( if (hidden) { *q++ = '&'; *q++ = '#'; + if (isHex) + *q++ = 'x'; if (cpe != '\0') *(p-1) = cpe; p = cp; @@ -315,6 +337,8 @@ PUBLIC char * LYUnEscapeEntities ARGS3( if (hidden) { *q++ = '&'; *q++ = '#'; + if (isHex) + *q++ = 'x'; if (cpe != '\0') *(p-1) = cpe; p = cp; @@ -330,11 +354,13 @@ PUBLIC char * LYUnEscapeEntities ARGS3( /* ** For 8482 (trade) use the character reference if it's ** a hidden INPUT, otherwise use whatever the tables have - ** for ™. - FM, kw + ** for ™. - FM & KW */ } else if (value == 8482 && hidden) { *q++ = '&'; *q++ = '#'; + if (isHex) + *q++ = 'x'; if (cpe != '\0') *(p-1) = cpe; p = cp; @@ -345,9 +371,10 @@ PUBLIC char * LYUnEscapeEntities ARGS3( ** use it's value. - FM */ } else if (value < 161 || - (value < 256 && (HTPassEightBitNum || - !strncmp(LYchar_set_names[current_char_set], - "ISO Latin 1", 11)))) { + (value < 256 && + (HTPassEightBitNum || + !strncmp(LYchar_set_names[current_char_set], + "ISO Latin 1", 11)))) { /* ** No conversion needed. */ @@ -363,16 +390,21 @@ PUBLIC char * LYUnEscapeEntities ARGS3( */ } else { CONST char * name; - if (value == 8482) { /* trade mark sign falls through to here -kw */ - name = "trade"; + if (value == 8482) { + /* + ** Trade mark sign falls through to here. - KW + */ + name = "trade"; } else { - value -= 160; - name = HTMLGetEntityName(value); + value -= 160; + name = HTMLGetEntityName(value); } - for(low = 0, high = HTML_dtd.number_of_entities; - high > low; - diff < 0 ? (low = i+1) : (high = i)) { - /* Binary search */ + for (low = 0, high = HTML_dtd.number_of_entities; + high > low; + diff < 0 ? (low = i+1) : (high = i)) { + /* + ** Binary search. + */ i = (low + (high-low)/2); diff = strcmp(HTML_dtd.entity_names[i], name); if (diff == 0) { @@ -413,7 +445,9 @@ PUBLIC char * LYUnEscapeEntities ARGS3( for (low = 0, high = HTML_dtd.number_of_entities; high > low ; diff < 0 ? (low = i+1) : (high = i)) { - /* Binary search */ + /* + ** Binary search. + */ i = (low + (high-low)/2); diff = strcmp(HTML_dtd.entity_names[i], p); if (diff == 0) { @@ -738,7 +772,9 @@ PUBLIC void LYUnEscapeToLatinOne ARGS2( for (low = 0, high = HTML_dtd.number_of_entities; high > low ; diff < 0 ? (low = i+1) : (high = i)) { - /* Binary search */ + /* + ** Binary search. + */ i = (low + (high-low)/2); diff = strcmp(HTML_dtd.entity_names[i], p); if (diff == 0) { @@ -752,31 +788,42 @@ PUBLIC void LYUnEscapeToLatinOne ARGS2( buf[0] = HTMLGetLatinOneValue(i); if (buf[0] == '\0') { /* - ** The entity does not have an 8859-1 representation - ** of exactly one char length. Try to deal with it - ** anyway - either HTEscape the whole mess, or pass - ** through raw. So make sure the ISO_Latin1 table, - ** which is the first table in LYCharSets, has resonable - ** substitution strings! (if it really must have any - ** longer than one char..) -kw + ** The entity does not have an 8859-1 + ** representation of exactly one char length. + ** Try to deal with it anyway - either HTEscape + ** the whole mess, or pass through raw. So + ** make sure the ISO_Latin1 table, which is the + ** first table in LYCharSets, has reasonable + ** substitution strings! (if it really must + ** have any longer than one char) - KW */ - if (!LYCharSets[0][i][0]) /* totally empty, skip - kw */ - /* do nothing */ ; - else if (isURL) { - /* *All* will be HTEscape'd - kw */ - esc = HTEscape(LYCharSets[0][i], URL_XALPHAS); - for (e = 0; esc[e]; e++) - *q++ = esc[e]; - FREE(esc); + if (!LYCharSets[0][i][0]) { + /* + ** Totally empty, skip. - KW + */ + ; /* do nothing */ + } else if (isURL) { + /* + ** All will be HTEscape'd. - KW + */ + esc = HTEscape(LYCharSets[0][i], URL_XALPHAS); + for (e = 0; esc[e]; e++) + *q++ = esc[e]; + FREE(esc); } else { - /* *Nothing* will be HTEscape'd - kw */ - for (e = 0; LYCharSets[0][i][e]; e++) - *q++ = (unsigned char)(LYCharSets[0][i][e]); + /* + ** Nothing will be HTEscape'd. - KW + */ + for (e = 0; LYCharSets[0][i][e]; e++) { + *q++ = + (unsigned char)(LYCharSets[0][i][e]); + } } - } else if ((unsigned char)buf[0] > 159 && isURL == TRUE) { + } else if ((unsigned char)buf[0] > 159 && + isURL == TRUE) { esc = HTEscape(buf, URL_XALPHAS); for (e = 0; esc[e]; e++) - *q++ = esc[e]; + *q++ = esc[e]; FREE(esc); } else { *q++ = buf[0]; @@ -1225,6 +1272,67 @@ PUBLIC void LYFillLocalFileURL ARGS2( return; } +#ifdef EXP_CHARTRANS +/* +** This function writes a line with a META tag to an open file, +** which will specify a charset parameter to use when the file is +** read back in. It is meant for temporary HTML files used by the +** various special pages which may show titles of documents. When those +** files are created, the title strings normally have been translated and +** expanded to the display character set, so we have to make sure they +** don't get translated again. +** If the user has changed the display character set during the lifetime +** of the Lynx session (or, more exactly, during the time the title +** strings to be written were generated), they may now have different +** character encodings and there is currently no way to get it all right. +** To change this, we would have to add a variable for each string which +** keeps track of its character encoding... +** But at least we can try to ensure that reading the file after future +** display character set changes will give reasonable output. +** +** The META tag is not written if the display character set (passed as +** disp_chndl) already corresponds to the charset assumption that +** would be made when the file is read. - KW +*/ +PUBLIC void LYAddMETAcharsetToFD ARGS2( + FILE *, fd, + int, disp_chndl) +{ + if (disp_chndl == -1) + /* + * -1 means use current_char_set. + */ + disp_chndl = current_char_set; + + if (fd == NULL || disp_chndl < 0) + /* + * Should not happen. + */ + return; + + if (UCLYhndl_HTFile_for_unspec == disp_chndl) + /* + * Not need to do, so we don't. + */ + return; + + if (LYCharSet_UC[disp_chndl].enc == UCT_ENC_7BIT) + /* + * There shouldn't be any 8-bit characters in this case. + */ + return; + + /* + * In other cases we don't know because UCLYhndl_for_unspec may + * change during the lifetime of the file (by toggling raw mode + * or changing the display character set), so proceed. + */ + fprintf(fd, "<META %s content=\"text/html;charset=%s\">\n", + "http-equiv=\"content-type\"", + LYCharSet_UC[disp_chndl].MIMEname); +} +#endif /* EXP_CHARTRANS */ + /* ** This function returns OL TYPE="A" strings in ** the range of " A." (1) to "ZZZ." (18278). - FM @@ -1583,72 +1691,28 @@ PUBLIC void LYZero_OL_Counter ARGS1( /* ** This function is used by the HTML Structured object. - kw */ -PUBLIC void html_get_chartrans_info ARGS1(HTStructured *, me) +PUBLIC void LYGetChartransInfo ARGS1( + HTStructured *, me) { - me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,UCT_STAGE_STRUCTURED); + me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor, + UCT_STAGE_STRUCTURED); if (me->UCLYhndl < 0) { int chndl = HTAnchor_getUCLYhndl(me->node_anchor, UCT_STAGE_HTEXT); + if (chndl < 0) { chndl = current_char_set; HTAnchor_setUCInfoStage(me->node_anchor, chndl, UCT_STAGE_HTEXT, - UCT_SETBY_STRUCTURED); + UCT_SETBY_STRUCTURED); } HTAnchor_setUCInfoStage(me->node_anchor, chndl, UCT_STAGE_STRUCTURED, UCT_SETBY_STRUCTURED); me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor, UCT_STAGE_STRUCTURED); } - me->UCI = HTAnchor_getUCInfoStage(me->node_anchor,UCT_STAGE_STRUCTURED); -} - -/* -** This function writes a line with a META tag to an open file, -** which will specify a charset parameter to use when the file is -** read back in. It is meant for temporary HTML files used by the -** various special pages which may show titles of documents. When those -** files are created, the title strings normally have been translated and -** expanded to the display character set, so we have to make sure the -** don't get translated again. -** If the user has changed the display character set during the lifetime -** of the Lynx session (or, more exactly, during the time the title -** strings to be written were generated), the may now have different -** character encodings and there is currently no way to get it all right. -** To change this, we would have to add a variable for each string which -** keeps track of its character encoding... -** But at least we can try to ensure that reading the file after future -** display character set changes will give reasonable output. -** -** The META tag is not written if the display character set (passed as -** disp_chndl) already corresponds to the charset assumption that -** would be made when the file is read. -kw -*/ -PUBLIC void add_META_charset_to_fd ARGS2( - FILE *, fp, - int, disp_chndl - ) -{ - if (disp_chndl == -1) /* -1 means use current_char_set */ - disp_chndl = current_char_set; - if (fp == NULL || disp_chndl < 0) - return; /* should not happen */ - if (UCLYhndl_HTFile_for_unspec == disp_chndl) - return; /* not need to do, so we don't */ - if (LYCharSet_UC[disp_chndl].enc == UCT_ENC_7BIT) - return; /* There shouldn't be any 8-bit characters - in this case. */ - /* - * In other cases we don't know because UCLYhndl_for_unspec may - * change during the lifetime of the file (by toggling raw mode - * or changing the display character set), so proceed. - */ - - fprintf(fp,"<META %s content=\"text/html;charset=%s\">\n", - "http-equiv=\"content-type\"", - LYCharSet_UC[disp_chndl].MIMEname); + me->UCI = HTAnchor_getUCInfoStage(me->node_anchor, UCT_STAGE_STRUCTURED); } #endif /* EXP_CHARTRANS */ - /* ** This function processes META tags in HTML streams. - FM */ @@ -1800,15 +1864,40 @@ PUBLIC void LYHandleMETA ARGS4( * If we didn't get an Expires MIME header, * store it in the anchor element, and if we * haven't yet set no_cache, check whether we - * should. - FM + * should. Note that we don't accept a Date + * header via META tags, because it's likely + * to be untrustworthy, but do check for a + * Date header from a server when making the + * comparsion. - FM */ LYUnEscapeToLatinOne(&content, FALSE); LYTrimHead(content); LYTrimTail(content); StrAllocCopy(me->node_anchor->expires, content); if (me->node_anchor->no_cache == FALSE) { - if ((content[0] == '0' && content[1] == '\0') || - LYmktime(content) <= 0) { + if (!strcmp(content, "0")) { + /* + * The value is zero, which we treat as + * an absolute no-cache directive. - FM + */ + me->node_anchor->no_cache = TRUE; + HText_setNoCache(me->text); + } else if (me->node_anchor->date != NULL) { + /* + * We have a Date header, so check if + * the value is less than or equal to + * that. - FM + */ + if (LYmktime(content, TRUE) <= + LYmktime(me->node_anchor->date, TRUE)) { + me->node_anchor->no_cache = TRUE; + HText_setNoCache(me->text); + } + } else if (LYmktime(content, FALSE) <= 0) { + /* + * We don't have a Date header, and + * the value is in past for us. - FM + */ me->node_anchor->no_cache = TRUE; HText_setNoCache(me->text); } @@ -1833,88 +1922,91 @@ PUBLIC void LYHandleMETA ARGS4( if ((cp = strstr(content, "text/html;")) != NULL && (cp1 = strstr(content, "charset")) != NULL && cp1 > cp) { - BOOL chartrans_ok = NO; - char *cp3 = NULL, *cp4; - int chndl; + BOOL chartrans_ok = NO; + char *cp3 = NULL, *cp4; + int chndl; cp1 += 7; - while (*cp1 == ' ' || *cp1 == '=' || *cp1 == '"') + while (*cp1 == ' ' || *cp1 == '=' || *cp1 == '"') cp1++; #ifdef EXP_CHARTRANS - StrAllocCopy(cp3, cp1); /* copy to mutilate more */ - for (cp4=cp3; (*cp4 != '\0' && *cp4 != '"' && - *cp4 != ';' && *cp4 != ':' && - !WHITE(*cp4)); cp4++) - /* nothing */ ; - *cp4 = '\0'; - cp4 = cp3; - chndl = UCGetLYhndl_byMIME(cp3); - if (chndl < 0) { - if (0==strcmp(cp4, "cn-big5")) { - cp4 += 3; - chndl = UCGetLYhndl_byMIME(cp4); - } - else if (0==strncmp(cp4, "cn-gb", 5)) { - StrAllocCopy(cp3, "gb2312"); - cp4 = cp3; - chndl = UCGetLYhndl_byMIME(cp4); - } - } - if (UCCanTranslateFromTo(chndl, current_char_set)) - { - chartrans_ok = YES; - StrAllocCopy(me->node_anchor->charset, cp4); - HTAnchor_setUCInfoStage(me->node_anchor, chndl, - UCT_STAGE_PARSER, UCT_SETBY_STRUCTURED); - } - else if (chndl < 0) {/* got something but we don't - recognize it */ - chndl = UCLYhndl_for_unrec; - if (UCCanTranslateFromTo(chndl, - current_char_set)) - { - chartrans_ok = YES; - HTAnchor_setUCInfoStage(me->node_anchor, - chndl, - UCT_STAGE_PARSER, UCT_SETBY_STRUCTURED); - } - } - FREE(cp3); - if (chartrans_ok) { - LYUCcharset * p_in = - HTAnchor_getUCInfoStage(me->node_anchor, - UCT_STAGE_PARSER); - LYUCcharset * p_out = - HTAnchor_setUCInfoStage(me->node_anchor, - current_char_set, - UCT_STAGE_HTEXT, UCT_SETBY_DEFAULT); - if (!p_out) /* try again */ - p_out = - HTAnchor_getUCInfoStage(me->node_anchor, - UCT_STAGE_HTEXT); - if (0==strcmp(p_in->MIMEname,"x-transparent")) - { - HTPassEightBitRaw = TRUE; - HTAnchor_setUCInfoStage(me->node_anchor, - HTAnchor_getUCLYhndl(me->node_anchor, - UCT_STAGE_HTEXT), - UCT_STAGE_PARSER, UCT_SETBY_DEFAULT); - } - if (0==strcmp(p_out->MIMEname,"x-transparent")) - { - HTPassEightBitRaw = TRUE; - HTAnchor_setUCInfoStage(me->node_anchor, - HTAnchor_getUCLYhndl(me->node_anchor, - UCT_STAGE_PARSER), - UCT_STAGE_HTEXT, UCT_SETBY_DEFAULT); - } - if (!(p_in->enc & UCT_ENC_CJK) && - (p_in->codepoints & UCT_CP_SUBSETOF_LAT1)){ - HTCJK = NOCJK; - } else if (chndl == current_char_set) { - HTPassEightBitRaw = TRUE; - } - html_get_chartrans_info(me); + StrAllocCopy(cp3, cp1); /* copy to mutilate more */ + for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '"' && + *cp4 != ';' && *cp4 != ':' && + !WHITE(*cp4)); cp4++) { + ; /* do nothing */ + } + *cp4 = '\0'; + cp4 = cp3; + chndl = UCGetLYhndl_byMIME(cp3); + if (chndl < 0) { + if (!strcmp(cp4, "cn-big5")) { + cp4 += 3; + chndl = UCGetLYhndl_byMIME(cp4); + } else if (!strncmp(cp4, "cn-gb", 5)) { + StrAllocCopy(cp3, "gb2312"); + cp4 = cp3; + chndl = UCGetLYhndl_byMIME(cp4); + } + } + if (UCCanTranslateFromTo(chndl, current_char_set)) { + chartrans_ok = YES; + StrAllocCopy(me->node_anchor->charset, cp4); + HTAnchor_setUCInfoStage(me->node_anchor, chndl, + UCT_STAGE_PARSER, + UCT_SETBY_STRUCTURED); + } else if (chndl < 0) { + /* + * Got something but we don't recognize it. + */ + chndl = UCLYhndl_for_unrec; + if (UCCanTranslateFromTo(chndl, current_char_set)) { + chartrans_ok = YES; + HTAnchor_setUCInfoStage(me->node_anchor, chndl, + UCT_STAGE_PARSER, + UCT_SETBY_STRUCTURED); + } + } + FREE(cp3); + if (chartrans_ok) { + LYUCcharset * p_in = + HTAnchor_getUCInfoStage(me->node_anchor, + UCT_STAGE_PARSER); + LYUCcharset * p_out = + HTAnchor_setUCInfoStage(me->node_anchor, + current_char_set, + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + if (!p_out) { + /* + * Try again. + */ + p_out = HTAnchor_getUCInfoStage(me->node_anchor, + UCT_STAGE_HTEXT); + } + if (!strcmp(p_in->MIMEname, "x-transparent")) { + HTPassEightBitRaw = TRUE; + HTAnchor_setUCInfoStage(me->node_anchor, + HTAnchor_getUCLYhndl(me->node_anchor, + UCT_STAGE_HTEXT), + UCT_STAGE_PARSER, + UCT_SETBY_DEFAULT); + } + if (!strcmp(p_out->MIMEname, "x-transparent")) { + HTPassEightBitRaw = TRUE; + HTAnchor_setUCInfoStage(me->node_anchor, + HTAnchor_getUCLYhndl(me->node_anchor, + UCT_STAGE_PARSER), + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + } + if (!(p_in->enc & UCT_ENC_CJK) && + (p_in->codepoints & UCT_CP_SUBSETOF_LAT1)) { + HTCJK = NOCJK; + } else if (chndl == current_char_set) { + HTPassEightBitRaw = TRUE; + } + LYGetChartransInfo(me); } else /* Fall through to old behavior */ #endif /* EXP_CHARTRANS */ if (!strncmp(cp1, "us-ascii", 8) || @@ -2089,6 +2181,20 @@ PUBLIC void LYHandleMETA ARGS4( StrAllocCopy(id_string, cp); *cp = '\0'; } + if (me->inA) { + /* + * Ugh! The META tag, which is a HEAD element, + * is in an Anchor, which is BODY element. All + * we can do is close the Anchor and cross our + * fingers. - FM + */ + if (me->inBoldA == TRUE && me->inBoldH == FALSE) + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + me->inBoldA = FALSE; + HText_endAnchor(me->text, me->CurrentANum); + me->inA = FALSE; + me->CurrentANum = 0; + } me->CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ id_string, /* Tag */ @@ -2108,14 +2214,14 @@ PUBLIC void LYHandleMETA ARGS4( HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); HTML_put_character(me, ' '); me->in_word = NO; - HText_beginAnchor(me->text, me->CurrentA); + HText_beginAnchor(me->text, me->inUnderline, me->CurrentA); if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_START_CHAR); HTML_put_string(me, href); FREE(href); if (me->inBoldH == FALSE) HText_appendCharacter(me->text, LY_BOLD_END_CHAR); - HText_endAnchor(me->text); + HText_endAnchor(me->text, 0); LYEnsureSingleSpace(me); } @@ -2169,6 +2275,333 @@ free_META_copies: FREE(content); } +#ifdef NOTUSED_FOTEMODS +/* next two functions done in HTML.c instead in this code set - + see there. - kw */ +/* +** This function handles P elements in HTML streams. +** If start is TRUE it handles a start tag, and if +** FALSE, an end tag. We presently handle start +** and end tags identically, but this can lead to +** a different number of blank lines between the +** current paragraph and subsequent text when a P +** end tag is present or not in the markup. - FM +*/ +PUBLIC void LYHandleP ARGS5( + HTStructured *, me, + CONST BOOL*, present, + CONST char **, value, + char **, include, + BOOL, start) +{ + if (TRUE) { + /* + * FIG content should be a true block, which like P inherits + * the current style. APPLET is like character elements or + * an ALT attribute, unless it content contains a block element. + * If we encounter a P in either's content, we set flags to treat + * the content as a block. - FM + */ + if (me->inFIG) + me->inFIGwithP = TRUE; + + if (me->inAPPLET) + me->inAPPLETwithP = TRUE; + + UPDATE_STYLE; + if (me->List_Nesting_Level >= 0) { + /* + * We're in a list. Treat P as an instruction to + * create one blank line, if not already present, + * then fall through to handle attributes, with + * the "second line" margins. - FM + */ + if (me->inP) { + if (me->inFIG || me->inAPPLET || + me->inCAPTION || me->inCREDIT || + me->sp->style->spaceAfter > 0 || + me->sp->style->spaceBefore > 0) { + LYEnsureDoubleSpace(me); + } else { + LYEnsureSingleSpace(me); + } + } + } else if (me->sp[0].tag_number == HTML_ADDRESS) { + /* + * We're in an ADDRESS. Treat P as an instruction + * to start a newline, if needed, then fall through + * to handle attributes. - FM + */ + if (HText_LastLineSize(me->text, FALSE)) { + HText_setLastChar(me->text, ' '); /* absorb white space */ + HText_appendCharacter(me->text, '\r'); + } + } else if (!(me->inLABEL && !me->inP)) { + HText_appendParagraph(me->text); + me->inLABEL = FALSE; + } + me->in_word = NO; + + if (LYoverride_default_alignment(me)) { + me->sp->style->alignment = styles[me->sp[0].tag_number]->alignment; + } else if (me->List_Nesting_Level >= 0 || + ((me->Division_Level < 0) && + (!strcmp(me->sp->style->name, "Normal") || + !strcmp(me->sp->style->name, "Preformatted")))) { + me->sp->style->alignment = HT_LEFT; + } else { + me->sp->style->alignment = me->current_default_alignment; + } + if (present && present[HTML_P_ALIGN] && value[HTML_P_ALIGN]) { + if (!strcasecomp(value[HTML_P_ALIGN], "center") && + !(me->List_Nesting_Level >= 0 && !me->inP)) + me->sp->style->alignment = HT_CENTER; + else if (!strcasecomp(value[HTML_P_ALIGN], "right") && + !(me->List_Nesting_Level >= 0 && !me->inP)) + me->sp->style->alignment = HT_RIGHT; + else if (!strcasecomp(value[HTML_P_ALIGN], "left") || + !strcasecomp(value[HTML_P_ALIGN], "justify")) + me->sp->style->alignment = HT_LEFT; + } + + LYCheckForID(me, present, value, (int)HTML_P_ID); + + /* + * Mark that we are starting a new paragraph + * and don't have any of it's text yet. - FM + * + */ + me->inP = FALSE; + } + + return; +} + +/* +** This function handles SELECT elements in HTML streams. +** If start is TRUE it handles a start tag, and if FALSE, +** an end tag. - FM +*/ +PUBLIC void LYHandleSELECT ARGS5( + HTStructured *, me, + CONST BOOL*, present, + CONST char **, value, + char **, include, + BOOL, start) +{ + int i; + + if (start == TRUE) { + char *name = NULL; + BOOLEAN multiple = NO; + char *size = NULL; + + /* + * Initialize the disable attribute. + */ + me->select_disabled = FALSE; + + /* + * Make sure we're in a form. + */ + if (!me->inFORM) { + if (TRACE) { + fprintf(stderr, + "HTML: SELECT start tag not within FORM tag\n"); + } else if (!me->inBadHTML) { + _statusline(BAD_HTML_USE_TRACE); + me->inBadHTML = TRUE; + sleep(MessageSecs); + } + + /* + * Too likely to cause a crash, so we'll ignore it. - FM + */ + return; + } + + /* + * Check for unclosed TEXTAREA. + */ + if (me->inTEXTAREA) { + if (TRACE) { + fprintf(stderr, "HTML: Missing TEXTAREA end tag\n"); + } else if (!me->inBadHTML) { + _statusline(BAD_HTML_USE_TRACE); + me->inBadHTML = TRUE; + sleep(MessageSecs); + } + } + + /* + * Set to know we are in a select tag. + */ + me->inSELECT = TRUE; + + if (!me->text) + UPDATE_STYLE; + if (present && present[HTML_SELECT_NAME] && + value[HTML_SELECT_NAME] && *value[HTML_SELECT_NAME]) + StrAllocCopy(name, value[HTML_SELECT_NAME]); + else + StrAllocCopy(name, ""); + if (present && present[HTML_SELECT_MULTIPLE]) + multiple=YES; + if (present && present[HTML_SELECT_DISABLED]) + me->select_disabled = TRUE; + if (present && present[HTML_SELECT_SIZE] && + value[HTML_SELECT_SIZE] && *value[HTML_SELECT_SIZE]) { +#ifdef NOTDEFINED + StrAllocCopy(size, value[HTML_SELECT_SIZE]); +#else + /* + * Let the size be determined by the number of OPTIONs. - FM + */ + if (TRACE) + fprintf(stderr, + "HTML: Ignoring SIZE=\"%s\" for SELECT.\n", + (char *)value[HTML_SELECT_SIZE]); +#endif /* NOTDEFINED */ + } + + if (me->inBoldH == TRUE && + (multiple == NO || LYSelectPopups == FALSE)) { + HText_appendCharacter(me->text, LY_BOLD_END_CHAR); + me->inBoldH = FALSE; + me->needBoldH = TRUE; + } + if (me->inUnderline == TRUE && + (multiple == NO || LYSelectPopups == FALSE)) { + HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); + me->inUnderline = FALSE; + } + + if ((multiple == NO && LYSelectPopups == TRUE) && + me->sp[0].tag_number == HTML_PRE && + HText_LastLineSize(me->text, FALSE) > (LYcols - 8)) { + /* + * Force a newline when we're using a popup in + * a PRE block and are within 7 columns from the + * right margin. This will allow for the '[' + * popup designater and help avoid a wrap in the + * underscore placeholder for the retracted popup + * entry in the HText structure. - FM + */ + HTML_put_character(me, '\n'); + me->in_word = NO; + } + + LYCheckForID(me, present, value, (int)HTML_SELECT_ID); + + HText_beginSelect(name, multiple, size); + FREE(name); + FREE(size); + + me->first_option = TRUE; + } else { + /* + * Handle end tag. + */ + char *ptr; + if (!me->text) + UPDATE_STYLE; + + /* + * Make sure we had a select start tag. + */ + if (!me->inSELECT) { + if (TRACE) { + fprintf(stderr, "HTML: Unmatched SELECT end tag\n"); + } else if (!me->inBadHTML) { + _statusline(BAD_HTML_USE_TRACE); + me->inBadHTML = TRUE; + sleep(MessageSecs); + } + return; + } + + /* + * Set to know that we are no longer in a select tag. + */ + me->inSELECT = FALSE; + + /* + * Clear the disable attribute. + */ + me->select_disabled = FALSE; + + /* + * Finish the data off. + */ + HTChunkTerminate(&me->option); + /* + * Finish the previous option. + */ + ptr = HText_setLastOptionValue(me->text, + me->option.data, + me->LastOptionValue, + LAST_ORDER, + me->LastOptionChecked); + FREE(me->LastOptionValue); + + me->LastOptionChecked = FALSE; + + if (HTCurSelectGroupType == F_CHECKBOX_TYPE || + LYSelectPopups == FALSE) { + /* + * Start a newline after the last checkbox/button option. + */ + LYEnsureSingleSpace(me); + } else { + /* + * Output popup box with the default option to screen, + * but use non-breaking spaces for output. + */ + if (ptr && + me->sp[0].tag_number == HTML_PRE && strlen(ptr) > 6) { + /* + * The code inadequately handles OPTION fields in PRE tags. + * We'll put up a minimum of 6 characters, and if any + * more would exceed the wrap column, we'll ignore them. + */ + for (i = 0; i < 6; i++) { + if (*ptr == ' ') + HText_appendCharacter(me->text, HT_NON_BREAK_SPACE); + else + HText_appendCharacter(me->text, *ptr); + ptr++; + } + HText_setIgnoreExcess(me->text, TRUE); + } + for (; ptr && *ptr != '\0'; ptr++) { + if (*ptr == ' ') + HText_appendCharacter(me->text, HT_NON_BREAK_SPACE); + else + HText_appendCharacter(me->text, *ptr); + } + /* + * Add end option character. + */ + HText_appendCharacter(me->text, ']'); + HText_setLastChar(me->text, ']'); + me->in_word = YES; + HText_setIgnoreExcess(me->text, FALSE); + } + HTChunkClear(&me->option); + + if (me->Underline_Level > 0 && me->inUnderline == FALSE) { + HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR); + me->inUnderline = TRUE; + } + if (me->needBoldH == TRUE && me->inBoldH == FALSE) { + HText_appendCharacter(me->text, LY_BOLD_START_CHAR); + me->inBoldH = TRUE; + me->needBoldH = FALSE; + } + } +} +#endif /* NOTUSED_FOTEMODS */ + /* ** This function strips white characters and ** generally fixes up attribute values that @@ -2183,6 +2616,8 @@ PUBLIC int LYLegitimizeHREF ARGS4( BOOL, strip_dots) { int url_type = 0; + char *pound = NULL; + char *fragment = NULL; if (!me || !href || *href == NULL || *(*href) == '\0') return(url_type); @@ -2200,7 +2635,23 @@ PUBLIC int LYLegitimizeHREF ARGS4( HTUnEscapeSome(*href, " \r\n\t"); convert_to_spaces(*href, TRUE); } else { + /* + * Collapse spaces in the actual URL, but just + * protect against tabs or newlines in the + * fragment, if present. This seeks to cope + * with atrocities inflicted on the Web by + * authoring tools such as Frontpage. - FM + */ + if ((pound = strchr(*href, '#')) != NULL) { + StrAllocCopy(fragment, pound); + *pound = '\0'; + convert_to_spaces(fragment, FALSE); + } collapse_spaces(*href); + if (fragment != NULL) { + StrAllocCat(*href, fragment); + FREE(fragment); + } } if (*(*href) == '\0') return(url_type); @@ -2245,10 +2696,10 @@ PUBLIC int LYLegitimizeHREF ARGS4( char *temp = NULL, *str = ""; if (((temp = HTParse((me->inBASE ? - me->base_href : me->node_anchor->address), - "", PARSE_PATH + PARSE_PUNCTUATION)) == NULL) || - *temp == '\0' || - strchr(&temp[1], '/') == NULL) { + me->base_href : me->node_anchor->address), + "", PARSE_PATH+PARSE_PUNCTUATION)) == NULL) || + temp[0] == '\0' || + !strchr((char *)&temp[1], '/')) { FREE(temp); temp = *href; if ((me->inBASE ? @@ -2382,8 +2833,8 @@ PUBLIC void LYCheckForID ARGS4( temp, /* Tag */ NULL, /* Addresss */ (void *)0))) { /* Type */ - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); } FREE(temp); } @@ -2412,8 +2863,8 @@ PUBLIC void LYHandleID ARGS2( id, /* Tag */ NULL, /* Addresss */ (void *)0)) != NULL) { /* Type */ - HText_beginAnchor(me->text, ID_A); - HText_endAnchor(me->text); + HText_beginAnchor(me->text, me->inUnderline, ID_A); + HText_endAnchor(me->text, 0); } } @@ -2456,10 +2907,12 @@ PUBLIC void LYEnsureDoubleSpace ARGS1( if (!me || !me->text) return; - if (HText_LastLineSize(me->text)) { + if (HText_LastLineSize(me->text, FALSE)) { + HText_setLastChar(me->text, ' '); /* absorb white space */ HText_appendCharacter(me->text, '\r'); HText_appendCharacter(me->text, '\r'); - } else if (HText_PreviousLineSize(me->text)) { + } else if (HText_PreviousLineSize(me->text, FALSE)) { + HText_setLastChar(me->text, ' '); /* absorb white space */ HText_appendCharacter(me->text, '\r'); } else if (me->List_Nesting_Level >= 0) { HText_NegateLineOne(me->text); @@ -2479,7 +2932,8 @@ PUBLIC void LYEnsureSingleSpace ARGS1( if (!me || !me->text) return; - if (HText_LastLineSize(me->text)) { + if (HText_LastLineSize(me->text, FALSE)) { + HText_setLastChar(me->text, ' '); /* absorb white space */ HText_appendCharacter(me->text, '\r'); } else if (me->List_Nesting_Level >= 0) { HText_NegateLineOne(me->text); diff --git a/src/LYCharUtils.h b/src/LYCharUtils.h index b6b0d892..55433d18 100644 --- a/src/LYCharUtils.h +++ b/src/LYCharUtils.h @@ -27,6 +27,11 @@ extern char *LYFindEndOfComment PARAMS(( extern void LYFillLocalFileURL PARAMS(( char ** href, char * base)); +#ifdef EXP_CHARTRANS +extern void LYAddMETAcharsetToFD PARAMS(( + FILE * fd, + int disp_chndl)); +#endif /* EXP_CHARTRANS */ #ifdef Lynx_HTML_Handler extern int OL_CONTINUE; /* flag for whether CONTINUE is set */ @@ -41,6 +46,16 @@ extern char *LYUppercaseI_OL_String PARAMS(( int seqnum)); extern char *LYLowercaseI_OL_String PARAMS(( int seqnum)); +#ifdef EXP_CHARTRANS +#ifdef HTML_H +extern void LYGetChartransInfo PARAMS(( + HTStructured * me)); +#endif +extern void add_META_charset_to_fd PARAMS(( + FILE * fp, + int disp_chndl)); +#endif /* EXP_CHARTRANS */ + extern void LYHandleMETA PARAMS(( HTStructured * me, CONST BOOL* present, @@ -74,13 +89,4 @@ extern BOOLEAN LYCheckForCSI PARAMS(( char ** url)); #endif /* Lynx_HTML_Handler */ -#ifdef EXP_CHARTRANS -#ifdef HTML_H -extern void html_get_chartrans_info PARAMS((HTStructured * me)); -#endif -extern void add_META_charset_to_fd PARAMS(( - FILE * fp, - int disp_chndl)); -#endif /* EXP_CHARTRANS */ - #endif /* LYCHARUTILS_H */ diff --git a/src/LYCookie.c b/src/LYCookie.c index d43a6664..008797e3 100644 --- a/src/LYCookie.c +++ b/src/LYCookie.c @@ -8,8 +8,13 @@ ** Based on: ** http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-mgmt-05.txt ** +** Updated for: +** http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-man-mec-02.txt +** - FM 1997-07-09 +** ** TO DO: (roughly in order of decreasing priority) - * host_matches() is only lightly tested in the Internet at large. + * A means to specify "always allow" and "never allow" domains via + a configuration file is needed. * Hex escaping isn't considered at all. Any semi-colons, commas, or spaces actually in cookie names or values (i.e., not serving as punctuation for the overall Set-Cookie value) should be hex @@ -29,8 +34,6 @@ collections to bring us back down under the limits, rather than actively removing cookies and/or domains based on age or frequency of use. - * The comments in this file chould contain extracts from the -05 - HTTP State Management draft (URL above). * If the a cookie has the secure flag set, we presently treat only SSL connections as secure. This may need to be expanded for other secure communication protocols that become standarized. @@ -52,6 +55,8 @@ #include "LYStrings.h" #include "LYSystem.h" #include "GridText.h" +#include "LYUtils.h" +#include "LYCharUtils.h" #include "LYCookie.h" #define FREE(x) if (x) {free(x); x = NULL;} @@ -70,24 +75,28 @@ PRIVATE HTList *cookie_list = NULL; PRIVATE int total_cookies = 0; struct _cookie { - char *lynx_id; /* Lynx cookie identifier */ + char *lynxID; /* Lynx cookie identifier */ char *name; /* Name of this cookie */ char *value; /* Value of this cookie */ int version; /* Cookie protocol version (=1) */ char *comment; /* Comment to show to user */ + char *commentURL; /* URL for comment to show to user */ char *domain; /* Domain for which this cookie is valid */ int port; /* Server port from which this cookie was given (usu. 80) */ + char *PortList;/* List of ports for which cookie can be sent */ char *path; /* Path prefix for which this cookie is valid */ int pathlen; /* Length of the path */ int flags; /* Various flags */ - time_t expires; /* The time when this cookie expires */ + time_t expires;/* The time when this cookie expires */ BOOL quoted; /* Was a value quoted in the Set-Cookie header? */ }; typedef struct _cookie cookie; #define COOKIE_FLAG_SECURE 1 /* If set, cookie requires secure links */ -#define COOKIE_FLAG_EXPIRES_SET 2 /* If set, an expiry date was set */ - +#define COOKIE_FLAG_DISCARD 2 /* If set, expire at end of session */ +#define COOKIE_FLAG_EXPIRES_SET 4 /* If set, an expiry date was set */ +#define COOKIE_FLAG_DOMAIN_SET 8 /* If set, an non-default domain was set */ +#define COOKIE_FLAG_PATH_SET 16 /* If set, an non-default path was set */ struct _HTStream { HTStreamClass * isa; @@ -116,12 +125,12 @@ PRIVATE void MemAllocCopy ARGS3( PRIVATE cookie * newCookie NOARGS { cookie *p = (cookie *)calloc(1, sizeof(cookie)); - char lynx_id[64]; + char lynxID[64]; if (p == NULL) outofmem(__FILE__, "newCookie"); - sprintf(lynx_id, "%p", p); - StrAllocCopy(p->lynx_id, lynx_id); + sprintf(lynxID, "%p", p); + StrAllocCopy(p->lynxID, lynxID); p->port = 80; return p; } @@ -130,12 +139,14 @@ PRIVATE void freeCookie ARGS1( cookie *, co) { if (co) { - FREE(co->lynx_id); + FREE(co->lynxID); FREE(co->name); FREE(co->value); FREE(co->comment); + FREE(co->commentURL); FREE(co->domain); FREE(co->path); + FREE(co->PortList); FREE(co); } } @@ -173,6 +184,7 @@ PRIVATE void LYCookieJar_free NOARGS if (co) { HTList_removeObject(cookie_list, co); freeCookie(co); + co = NULL; } cl = next; } @@ -185,7 +197,8 @@ PRIVATE void LYCookieJar_free NOARGS /* ** Compare two hostnames as specified in Section 2 of: -** http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-mgmt-05.txt +** http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-man-mec-02.txt +** - AK & FM */ PRIVATE BOOLEAN host_matches ARGS2( CONST char *, A, @@ -213,7 +226,36 @@ PRIVATE BOOLEAN host_matches ARGS2( } /* -** Store a cookie somewhere in the domain list. +** Compare the current port with a port list as specified in Section 4.3 of: +** http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-man-mec-02.txt +** - FM +*/ +PRIVATE BOOLEAN port_matches ARGS2( + int, port, + CONST char *, list) +{ + char *number = (char *)list; + + if (!(number && isdigit(*number))) + return(FALSE); + + while (*number != '\0') { + if (atoi(number) == port) { + return(TRUE); + } + while (isdigit(*number)) { + number++; + } + while (*number != '\0' && !isdigit(*number)) { + number++; + } + } + + return(FALSE); +} + +/* +** Store a cookie somewhere in the domain list. - AK & FM */ PRIVATE void store_cookie ARGS3( cookie *, co, @@ -226,6 +268,7 @@ PRIVATE void store_cookie ARGS3( int pos; CONST char *ptr; domain_entry *de = NULL; + BOOL Replacement = FALSE; if (co == NULL) return; @@ -241,6 +284,8 @@ PRIVATE void store_cookie ARGS3( fprintf(stderr, "store_cookie: Rejecting because '%s' is not a prefix of '%s'.\n", co->path, path); + freeCookie(co); + co = NULL; return; } /* @@ -256,6 +301,8 @@ PRIVATE void store_cookie ARGS3( fprintf(stderr, "store_cookie: Rejecting because '%s' has no dot.\n", hostname); + freeCookie(co); + co = NULL; return; } @@ -269,6 +316,8 @@ PRIVATE void store_cookie ARGS3( fprintf(stderr, "store_cookie: Rejecting domain '%s'.\n", co->domain); + freeCookie(co); + co = NULL; return; } ptr = strchr((co->domain + 1), '.'); @@ -277,6 +326,8 @@ PRIVATE void store_cookie ARGS3( fprintf(stderr, "store_cookie: Rejecting domain '%s'.\n", co->domain); + freeCookie(co); + co = NULL; return; } @@ -289,6 +340,8 @@ PRIVATE void store_cookie ARGS3( fprintf(stderr, "store_cookie: Rejecting domain '%s' for host '%s'.\n", co->domain, hostname); + freeCookie(co); + co = NULL; return; } @@ -303,6 +356,8 @@ PRIVATE void store_cookie ARGS3( fprintf(stderr, "store_cookie: Rejecting domain '%s' for host '%s'.\n", co->domain, hostname); + freeCookie(co); + co = NULL; return; } } @@ -369,7 +424,7 @@ PRIVATE void store_cookie ARGS3( /* * Check if this cookie matches the one we're inserting. */ - } else if ((c2) && (co->port == c2->port) && + } else if ((c2) && !strcmp(co->domain, c2->domain) && !strcmp(co->path, c2->path) && !strcmp(co->name, c2->name)) { @@ -377,6 +432,7 @@ PRIVATE void store_cookie ARGS3( freeCookie(c2); c2 = NULL; total_cookies--; + Replacement = TRUE; } else if ((c2) && (c2->pathlen) > (co->pathlen)) { pos++; @@ -412,6 +468,15 @@ PRIVATE void store_cookie ARGS3( co = NULL; /* + * If it's a replacement for a cookie that had not expired, + * and never allow has not been set, add it again without + * confirmation. - FM + */ + } else if ((Replacement == TRUE && de) && de->bv != REJECT_ALWAYS) { + HTList_insertObjectAt(cookie_list, co, pos); + total_cookies++; + + /* * Get confirmation if we need it, and add cookie * if confirmed or 'allow' is set to always. - FM */ @@ -425,6 +490,10 @@ PRIVATE void store_cookie ARGS3( } } +/* +** Scan a domain's cookie_list for any cookies we should +** include in a Cookie: request header. - AK & FM +*/ PRIVATE char * scan_cookie_sublist ARGS6( CONST char *, hostname, CONST char *, path, @@ -437,7 +506,10 @@ PRIVATE char * scan_cookie_sublist ARGS6( cookie *co; time_t now = time(NULL); BOOL Quoted = FALSE; + int len = 0; + char crlftab[8]; + sprintf(crlftab, "%c%c%c", CR, LF, '\t'); while (hl) { co = (cookie *)hl->object; next = hl->next; @@ -471,7 +543,7 @@ PRIVATE char * scan_cookie_sublist ARGS6( * Check if we have a unexpired match, and handle if we do. */ if (((co != NULL) && - co->port == port && host_matches(hostname, co->domain)) && + host_matches(hostname, co->domain)) && (co->pathlen == 0 || !strncmp(path, co->path, co->pathlen))) { /* * Skip if the secure flag is set and we don't have @@ -484,6 +556,15 @@ PRIVATE char * scan_cookie_sublist ARGS6( } /* + * Skip if we have a port list and the + * current port is not listed. - FM + */ + if (co->PortList && !port_matches(port, co->PortList)) { + hl = next; + continue; + } + + /* * Start or append to the request header. */ if (header == NULL) { @@ -494,64 +575,64 @@ PRIVATE char * scan_cookie_sublist ARGS6( * first cookie. */ char version[16]; - sprintf(version, "$Version=%i; ", co->version); + sprintf(version, "$Version=\"%i\"; ", co->version); StrAllocCopy(header, version); + len += strlen(header); } } else { /* - * There's already cookie data there, - * so add a separator. + * There's already cookie data there, so add + * a separator (always use a semi-colon for + * "backward compatibility"). - FM */ StrAllocCat(header, "; "); + /* + * Check if we should fold the header. - FM + */ + if (len > 800) { + StrAllocCat(header, crlftab); + len = 0; + } } /* * Include the cookie name=value pair. */ StrAllocCat(header, co->name); StrAllocCat(header, "="); - if (co->quoted && strchr(co->value, ' ')) { + if (co->quoted) { StrAllocCat(header, "\""); - Quoted = TRUE; + len++; } StrAllocCat(header, co->value); - if (Quoted) { + if (co->quoted) { StrAllocCat(header, "\""); - Quoted = FALSE; + len++; } + len += (strlen(co->name) + strlen(co->value) + 1); /* * For Version 1 (or greater) cookies, add - * attributes for the cookie. - FM + * $PATH and/or $DOMAIN attributes for the + * cookie if they were specified via a server + * reply header. - FM */ if (co->version > 0) { - if (co->path) { + if (co->path && (co->flags & COOKIE_FLAG_PATH_SET)) { /* * Append the path attribute. - FM */ - StrAllocCat(header, "; $Path="); - if (co->quoted && strchr(co->path, ' ')) { - StrAllocCat(header, "\""); - Quoted = TRUE; - } + StrAllocCat(header, "; $Path=\""); StrAllocCat(header, co->path); - if (Quoted) { - StrAllocCat(header, "\""); - Quoted = FALSE; - } + StrAllocCat(header, "\""); + len != (strlen(co->path) + 8); } - if (co->domain) { + if (co->domain && (co->flags & COOKIE_FLAG_DOMAIN_SET)) { /* * Append the domain attribute. - FM */ - StrAllocCat(header, "; $Domain="); - if (co->quoted && strchr(co->domain, ' ')) { - StrAllocCat(header, "\""); - Quoted = TRUE; - } + StrAllocCat(header, "; $Domain=\""); StrAllocCat(header, co->domain); - if (Quoted) { - StrAllocCat(header, "\""); - Quoted = FALSE; - } + StrAllocCat(header, "\""); + len != (strlen(co->domain) + 10); } } } @@ -561,63 +642,60 @@ PRIVATE char * scan_cookie_sublist ARGS6( return(header); } -PUBLIC void LYSetCookie ARGS2( - CONST char *, header, - CONST char *, address) +/* +** Process potentially concatenated Set-Cookie2 and/or Set-Cookie +** headers. - FM +*/ +PRIVATE void LYProcessSetCookies ARGS6( + CONST char *, SetCookie, + CONST char *, SetCookie2, + CONST char *, address, + char *, hostname, + char *, path, + int, port) { + char *header = NULL; CONST char *p, *attr_start, *attr_end, *value_start, *value_end; - char *hostname = NULL, *path = NULL, *ptr; - cookie *cur_cookie = NULL; - int port = 80; - int length = 0; + HTList *CombinedCookies = NULL, *cl = NULL; + cookie *cur_cookie = NULL, *co = NULL; + int length = 0, url_type = 0; + int NumCookies = 0; + BOOL MaxAgeAttrSet = FALSE; BOOL Quoted = FALSE; - /* - * Get the hostname, port and path of the address, and report - * the Set-Cookie request if trace mode is on, but set the cookie - * only if LYSetCookies is TRUE. - FM - */ - if (((hostname = HTParse(address, "", PARSE_HOST)) != NULL) && - (ptr = strchr(hostname, ':')) != NULL) { + if (!(SetCookie && *SetCookie) && + !(SetCookie2 && *SetCookie2)) { /* - * Replace default port number. + * Yuk! Garbage in, so nothing out. - FM */ - *ptr = '\0'; - ptr++; - port = atoi(ptr); - } else if (!strncasecomp(address, "https:", 6)) { - port = 443; - } - if (((path = HTParse(address, "", - PARSE_PATH|PARSE_PUNCTUATION)) != NULL) && - (ptr = strrchr(path, '/')) != NULL) { - if (ptr == path) - *(ptr+1) = '\0'; /* Leave a single '/' alone */ - else - *ptr = '\0'; - } - if (TRACE) { - fprintf(stderr, - "LYSetCookie called with host '%s', path '%s',\n and header '%s'%s\n", - (hostname ? hostname : ""), - (path ? path : ""), - (header ? header : ""), - (LYSetCookies ? "" : "\n Ignoring this Set-Cookie request.")); - } - if (LYSetCookies == FALSE) { - FREE(hostname); - FREE(path); return; } /* - * Process the Set-Cookie header value. + * If we have both Set-Cookie and Set-Cookie2 headers, + * and must combine them because the Set-Cookie2 headers + * are not required to have complete cookies if Set-Cookie + * headers are present. So set up a list for the cookies + * we process out of the header(s). Note that if more than + * one instance of a valued attribute for the same cookie + * is encountered, the value for the first instance is + * retained, with preference to that in a Set-Cookie2 + * header. We only accept up to 50 cookies from either + * header, and only if a cookie's values do not exceed + * the 4096 byte limit on overall size. - FM + */ + CombinedCookies = HTList_new(); + + /* + * First process the Set-Cookie2 header, if present, adding + * each cookie to the CombinedCoookies list. - FM */ - p = (char *)header; - while (length <= 4096 && *p) { + p = (SetCookie2 ? SetCookie2 : ""); + while (NumCookies <= 50 && *p) { attr_start = attr_end = value_start = value_end = NULL; -#define SKIP_SPACES while (*p != '\0' && isspace((unsigned char)*p)) p++; - SKIP_SPACES; + while (*p != '\0' && isspace((unsigned char)*p)) { + p++; + } /* * Get the attribute name. */ @@ -626,7 +704,9 @@ PUBLIC void LYSetCookie ARGS2( *p != '=' && *p != ';' && *p != ',') p++; attr_end = p; - SKIP_SPACES; + while (*p != '\0' && isspace((unsigned char)*p)) { + p++; + } /* * Check for an '=' delimiter, or an 'expires' name followed @@ -639,8 +719,12 @@ PUBLIC void LYSetCookie ARGS2( /* * Get the value string. */ - p++; - SKIP_SPACES; + if (*p == '=') { + p++; + } + while (*p != '\0' && isspace((unsigned char)*p)) { + p++; + } /* * Hack alert! We must handle Netscape-style cookies with * "Expires=Mon, 01-Jan-96 13:45:35 GMT" or @@ -651,11 +735,28 @@ PUBLIC void LYSetCookie ARGS2( * looks for a space after the 5th space separator or dash to * mark the end of the value. - FM */ - if ((attr_end - attr_start) == 7 && + if ((attr_end - attr_start) == 7 && !strncasecomp(attr_start, "Expires", 7)) { int spaces = 6; value_start = p; - while (*p != '\0' && *p != ';' && spaces) { + if (isdigit((unsigned char)*p)) { + /* + * No alphabetic day field. - FM + */ + spaces--; + } else { + /* + * Skip the alphabetic day field. - FM + */ + while (*p != '\0' && isalpha((unsigned char)*p)) { + p++; + } + while (*p == ',' || isspace((unsigned char)*p)) { + p++; + } + spaces--; + } + while (*p != '\0' && *p != ';' && *p != ',' && spaces) { p++; if (isspace((unsigned char)*p)) { while (isspace((unsigned char)*(p + 1))) @@ -666,6 +767,62 @@ PUBLIC void LYSetCookie ARGS2( } } value_end = p; + /* + * Hack Alert! The port attribute can take a + * comma separated list of numbers as a value, + * and such values should be quoted, but if + * not, make sure we don't treat a number in + * the list as the start of a new cookie. - FM + */ + } else if ((attr_end - attr_start) == 4 && + !strncasecomp(attr_start, "port", 4) && + isdigit((unsigned char)*p)) { + /* + * The value starts as an unquoted number. + */ + CONST char *cp, *cp1; + value_start = p; + while (1) { + while (isdigit((unsigned char)*p)) + p++; + value_end = p; + while (isspace((unsigned char)*p)) + p++; + if (*p == '\0' || *p == ';') + break; + if (*p == ',') { + cp = (p + 1); + while (*cp != '\0' && isspace((unsigned char)*cp)) + cp++; + if (*cp != '\0' && isdigit((unsigned char)*cp)) { + cp1 = cp; + while (isdigit((unsigned char)*cp1)) + cp1++; + while (*cp != '\0' && isspace((unsigned char)*cp)) + cp1++; + if (*cp1 == '\0' || *cp1 == ',' || *cp1 == ';') { + p = cp; + continue; + } + } + } + while (*p != '\0' && *p != ';' && *p != ',') + p++; + value_end = p; + /* + * Trim trailing spaces. + */ + if ((value_end > value_start) && + isspace((unsigned char)*(value_end - 1))) { + value_end--; + while ((value_end > (value_start + 1)) && + isspace((unsigned char)*value_end) && + isspace((unsigned char)*(value_end - 1))) { + value_end--; + } + } + break; + } } else if (*p == '"') { /* * It's a quoted string. @@ -677,10 +834,9 @@ PUBLIC void LYSetCookie ARGS2( value_end = p; if (*p == '"') p++; - Quoted = TRUE; } else { /* - * Otherwise, it's an unquoted string. + * Otherwise, it's an unquoted string. */ value_start = p; while (*p != '\0' && *p != ';' && *p != ',') @@ -718,42 +874,161 @@ PUBLIC void LYSetCookie ARGS2( if (value_end > value_start) { int value_len = (value_end - value_start); - length += value_len; - if (length > 4096) - break; + if (value_len > 4096) { + value_len = 4096; + } value = (char *)calloc(1, value_len + 1); if (value == NULL) - outofmem(__FILE__, "LYSetCookie"); + outofmem(__FILE__, "LYProcessSetCookies"); LYstrncpy(value, (char *)value_start, value_len); } if (len == 6 && !strncasecomp(attr_start, "secure", 6)) { - known_attr = YES; - if (cur_cookie != NULL) - cur_cookie->flags |= COOKIE_FLAG_SECURE; + if (value == NULL) { + known_attr = YES; + if (cur_cookie != NULL) { + cur_cookie->flags |= COOKIE_FLAG_SECURE; + } + } else { + /* + * If secure has a value, assume someone + * misused it as cookie name. - FM + */ + known_attr = NO; + } + } else if (len == 7 && !strncasecomp(attr_start, "discard", 7)) { + if (value == NULL) { + known_attr = YES; + if (cur_cookie != NULL) { + cur_cookie->flags |= COOKIE_FLAG_DISCARD; + } + } else { + /* + * If discard has a value, assume someone + * used it as a cookie name. - FM + */ + known_attr = NO; + } } else if (len == 7 && !strncasecomp(attr_start, "comment", 7)) { known_attr = YES; - if (cur_cookie != NULL && value) + if (cur_cookie != NULL && value && + /* + * Don't process a repeat comment. - FM + */ + cur_cookie->comment == NULL) { StrAllocCopy(cur_cookie->comment, value); + length += strlen(cur_cookie->comment); + } + } else if (len == 10 && !strncasecomp(attr_start, + "commentURL", 10)) { + known_attr = YES; + if (cur_cookie != NULL && value && + /* + * Don't process a repeat commentURL. - FM + */ + cur_cookie->commentURL == NULL) { + /* + * We should get only absolute URLs as + * values, but will resolve versus the + * request's URL just in case. - FM + */ + cur_cookie->commentURL = HTParse(value, + address, + PARSE_ALL); + /* + * Accept only URLs for servers. - FM + */ + if ((url_type = is_url(cur_cookie->commentURL)) && + (url_type == HTTP_URL_TYPE || + url_type == HTTPS_URL_TYPE || + url_type == FTP_URL_TYPE || + url_type == GOPHER_URL_TYPE || + url_type == HTML_GOPHER_URL_TYPE || + url_type == INDEX_GOPHER_URL_TYPE || + url_type == NEWS_URL_TYPE || + url_type == NNTP_URL_TYPE || + url_type == SNEWS_URL_TYPE || + url_type == WAIS_URL_TYPE || + url_type == CSO_URL_TYPE || + url_type == FINGER_URL_TYPE)) { + length += strlen(cur_cookie->commentURL); + } else { + FREE(cur_cookie->commentURL); + } + } } else if (len == 6 && !strncasecomp(attr_start, "domain", 6)) { known_attr = YES; - if (cur_cookie != NULL && value) + if (cur_cookie != NULL && value && + /* + * Don't process a repeat domain. - FM + */ + !(cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) { + length -= strlen(cur_cookie->domain); StrAllocCopy(cur_cookie->domain, value); + length += strlen(cur_cookie->domain); + cur_cookie->flags |= COOKIE_FLAG_DOMAIN_SET; + } } else if (len == 4 && !strncasecomp(attr_start, "path", 4)) { known_attr = YES; - if (cur_cookie != NULL && value) { + if (cur_cookie != NULL && value && + /* + * Don't process a repeat path. - FM + */ + !(cur_cookie->flags & COOKIE_FLAG_PATH_SET)) { + length -= strlen(cur_cookie->path); StrAllocCopy(cur_cookie->path, value); - cur_cookie->pathlen = strlen(cur_cookie->path); + length += (cur_cookie->pathlen = strlen(cur_cookie->path)); + cur_cookie->flags |= COOKIE_FLAG_PATH_SET; + } + } else if (len == 4 && !strncasecomp(attr_start, "port", 4)) { + if (cur_cookie != NULL && value && + /* + * Don't process a repeat port. - FM + */ + cur_cookie->PortList == NULL) { + char *cp = value; + while ((*cp != '\0') && + (isdigit((unsigned char)*cp) || + *cp == ',' || *cp == ' ')) { + cp++; + } + if (*cp == '\0') { + StrAllocCopy(cur_cookie->PortList, value); + length += strlen(cur_cookie->PortList); + known_attr = YES; + } else { + known_attr = NO; + } + } else if (cur_cookie != NULL) { + /* + * Don't process a repeat port. - FM + */ + if (cur_cookie->PortList == NULL) { + char temp[256]; + sprintf(temp, "%d", port); + StrAllocCopy(cur_cookie->PortList, temp); + length += strlen(cur_cookie->PortList); + } + known_attr = YES; } } else if (len == 7 && !strncasecomp(attr_start, "version", 7)) { known_attr = YES; - if (cur_cookie != NULL && value) { + if (cur_cookie != NULL && value && + /* + * Don't process a repeat version. - FM + */ + cur_cookie->version < 1) { int temp = strtol(value, NULL, 10); - if (errno != -ERANGE) + if (errno != -ERANGE) { cur_cookie->version = temp; + } } } else if (len == 7 && !strncasecomp(attr_start, "max-age", 7)) { known_attr = YES; - if (cur_cookie != NULL && value) { + if (cur_cookie != NULL && value && + /* + * Don't process a repeat max-age. - FM + */ + !MaxAgeAttrSet) { int temp = strtol(value, NULL, 10); cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET; if (errno == -ERANGE) { @@ -762,50 +1037,478 @@ PUBLIC void LYSetCookie ARGS2( cur_cookie->expires = (time(NULL) + temp); if (TRACE) fprintf(stderr, - "LYSetCooke: expires %ld, %s", + "LYSetCookie: expires %ld, %s", (long) cur_cookie->expires, ctime(&cur_cookie->expires)); } + MaxAgeAttrSet = TRUE; } } else if (len == 7 && !strncasecomp(attr_start, "expires", 7)) { /* - * Convert an 'expires' attribute value for Version 0 - * cookies, or for Version 1 if we haven't received a - * 'max-age', to the equivalent of a Version 1 (or greater) - * 'max-age' value added to 'time(NULL)'. Note that - * 'expires' should not be used in Version 1 cookies, - * but, as explained below, it might be used for "backward - * compatibility", and, in turn, ill-informed people - * surely would start using it instead of, rather than - * in addition to, 'max-age'. - FM + * Convert an 'expires' attribute value if we haven't + * received a 'max-age'. Note that 'expires' should not + * be used in Version 1 cookies, but it might be used for + * "backward compatibility", and, in turn, ill-informed + * people surely would start using it instead of, rather + * than in addition to, 'max-age'. - FM */ - if (((cur_cookie) && cur_cookie->version < 1) || - ((cur_cookie) && - !(cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET))) { + known_attr = YES; + if ((cur_cookie != NULL && !MaxAgeAttrSet) && + !(cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET)) { known_attr = YES; if (value) { cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET; - cur_cookie->expires = LYmktime(value); + cur_cookie->expires = LYmktime(value, FALSE); if (cur_cookie->expires > 0) { if (TRACE) fprintf(stderr, - "LYSetCooke: expires %ld, %s", + "LYSetCookie: expires %ld, %s", (long) cur_cookie->expires, ctime(&cur_cookie->expires)); } } } + } + + /* + * If none of the above comparisions succeeded, and we have + * a value, then we have an unknown pair of the form 'foo=bar', + * which means it's time to create a new cookie. If we don't + * have a non-zero-length value, assume it's an error or a + * new, unknown attribute which doesn't take a value, and + * ignore it. - FM + */ + if (!known_attr && value_end > value_start) { + /* + * If we've started a cookie, and it's not too big, + * save it in the CombinedCookies list. - FM + */ + if (length <= 4096 && cur_cookie != NULL) { + /* + * Assume version 1 if not set to that or higher. - FM + */ + if (cur_cookie->version < 1) { + cur_cookie->version = 1; + } + HTList_appendObject(CombinedCookies, cur_cookie); + } + /* + * Start a new cookie. - FM + */ + cur_cookie = newCookie(); + length = 0; + NumCookies++; + MemAllocCopy(&(cur_cookie->name), attr_start, attr_end); + length += strlen(cur_cookie->name); + MemAllocCopy(&(cur_cookie->value), value_start, value_end); + length += strlen(cur_cookie->value); + StrAllocCopy(cur_cookie->domain, hostname); + length += strlen(cur_cookie->domain); + StrAllocCopy(cur_cookie->path, path); + length += (cur_cookie->pathlen = strlen(cur_cookie->path)); + cur_cookie->port = port; + MaxAgeAttrSet = FALSE; + cur_cookie->quoted = TRUE; + } + FREE(value); + } + } + + /* + * Add any final SetCookie2 cookie to the CombinedCookie list + * if we are within the length limit. - FM + */ + if (NumCookies <= 50 && length <= 4096 && cur_cookie != NULL) { + if (cur_cookie->version < 1) { + cur_cookie->version = 1; + } + HTList_appendObject(CombinedCookies, cur_cookie); + } else if (cur_cookie != NULL) { + if (TRACE) { + fprintf(stderr, + "LYProcessSetCookies: Rejecting Set-Cookie2: %s=%s\n", + (cur_cookie->name ? cur_cookie->name : "[no name]"), + (cur_cookie->value ? cur_cookie->value : "[no value]")); + fprintf(stderr, + " due to excessive %s%s%s\n", + (length > 4096 ? "length" : ""), + (length > 4096 && NumCookies > 50 ? " and " : ""), + (NumCookies > 50 ? "number!\n" : "!\n")); + } + freeCookie(cur_cookie); + cur_cookie = NULL; + } + + /* + * Now process the Set-Cookie header, if present, checking the + * CombinedCookies list for a corresponding cookie and supplementing + * that if one is present, otherwise, adding the new cookie. - FM + */ + length = 0; + NumCookies = 0; + cur_cookie = NULL; + p = (SetCookie ? SetCookie : ""); + while (NumCookies <= 50 && *p) { + attr_start = attr_end = value_start = value_end = NULL; + while (*p != '\0' && isspace((unsigned char)*p)) { + p++; + } + /* + * Get the attribute name. + */ + attr_start = p; + while (*p != '\0' && !isspace((unsigned char)*p) && + *p != '=' && *p != ';' && *p != ',') + p++; + attr_end = p; + while (*p != '\0' && isspace((unsigned char)*p)) { + p++; + } + + /* + * Check for an '=' delimiter, or an 'expires' name followed + * by white, since Netscape's bogus parser doesn't require + * an '=' delimiter, and 'expires' attributes are being + * encountered without them. - FM + */ + if (*p == '=' || + !strncasecomp(attr_start, "Expires", 7)) { + /* + * Get the value string. + */ + if (*p == '=') { + p++; + } + while (*p != '\0' && isspace((unsigned char)*p)) { + p++; + } + /* + * Hack alert! We must handle Netscape-style cookies with + * "Expires=Mon, 01-Jan-96 13:45:35 GMT" or + * "Expires=Mon, 1 Jan 1996 13:45:35 GMT". + * No quotes, but there are spaces. Argh... + * Anyway, we know it will have at least 3 space separators + * within it, and two dashes or two more spaces, so this code + * looks for a space after the 5th space separator or dash to + * mark the end of the value. - FM + */ + if ((attr_end - attr_start) == 7 && + !strncasecomp(attr_start, "Expires", 7)) { + int spaces = 6; + value_start = p; + if (isdigit((unsigned char)*p)) { + /* + * No alphabetic day field. - FM + */ + spaces--; + } else { + /* + * Skip the alphabetic day field. - FM + */ + while (*p != '\0' && isalpha((unsigned char)*p)) { + p++; + } + while (*p == ',' || isspace((unsigned char)*p)) { + p++; + } + spaces--; + } + while (*p != '\0' && *p != ';' && *p != ',' && spaces) { + p++; + if (isspace((unsigned char)*p)) { + while (isspace((unsigned char)*(p + 1))) + p++; + spaces--; + } else if (*p == '-') { + spaces--; + } + } + value_end = p; + /* + * Hack Alert! The port attribute can take a + * comma separated list of numbers as a value, + * and such values should be quoted, but if + * not, make sure we don't treat a number in + * the list as the start of a new cookie. - FM + */ + } else if ((attr_end - attr_start) == 4 && + !strncasecomp(attr_start, "port", 4) && + isdigit((unsigned char)*p)) { /* - * If it's a version 1 (or greater) cookie, then you - * really can set a cookie named 'expires', so we - * perhaps shouldn't set known_attr. However, an - * -06 draft, which hopefully will be shot down as - * bogus, suggests adding (invalidly) 'expires' - * headers for "backward compatibility". So, we'll - * set known-attr, to ignore it, and hope it works - * out. - FM + * The value starts as an unquoted number. + */ + CONST char *cp, *cp1; + value_start = p; + while (1) { + while (isdigit((unsigned char)*p)) + p++; + value_end = p; + while (isspace((unsigned char)*p)) + p++; + if (*p == '\0' || *p == ';') + break; + if (*p == ',') { + cp = (p + 1); + while (*cp != '\0' && isspace((unsigned char)*cp)) + cp++; + if (*cp != '\0' && isdigit((unsigned char)*cp)) { + cp1 = cp; + while (isdigit((unsigned char)*cp1)) + cp1++; + while (*cp != '\0' && isspace((unsigned char)*cp)) + cp1++; + if (*cp1 == '\0' || *cp1 == ',' || *cp1 == ';') { + p = cp; + continue; + } + } + } + while (*p != '\0' && *p != ';' && *p != ',') + p++; + value_end = p; + /* + * Trim trailing spaces. + */ + if ((value_end > value_start) && + isspace((unsigned char)*(value_end - 1))) { + value_end--; + while ((value_end > (value_start + 1)) && + isspace((unsigned char)*value_end) && + isspace((unsigned char)*(value_end - 1))) { + value_end--; + } + } + break; + } + } else if (*p == '"') { + /* + * It's a quoted string. */ + p++; + value_start = p; + while (*p != '\0' && *p != '"') + p++; + value_end = p; + if (*p == '"') + p++; + Quoted = TRUE; + } else { + /* + * Otherwise, it's an unquoted string. + */ + value_start = p; + while (*p != '\0' && *p != ';' && *p != ',') + p++; + value_end = p; + /* + * Trim trailing spaces. + */ + if ((value_end > value_start) && + isspace((unsigned char)*(value_end - 1))) { + value_end--; + while ((value_end > (value_start + 1)) && + isspace((unsigned char)*value_end) && + isspace((unsigned char)*(value_end - 1))) { + value_end--; + } + } + } + } + + /* + * Check for a separator character, and skip it. + */ + if (*p == ';' || *p == ',') + p++; + + /* + * Now, we can handle this attribute/value pair. + */ + if (attr_end > attr_start) { + int len = (attr_end - attr_start); + BOOLEAN known_attr = NO; + char *value = NULL; + + if (value_end > value_start) { + int value_len = (value_end - value_start); + + if (value_len > 4096) { + value_len = 4096; + } + value = (char *)calloc(1, value_len + 1); + if (value == NULL) + outofmem(__FILE__, "LYProcessSetCookie"); + LYstrncpy(value, (char *)value_start, value_len); + } + if (len == 6 && !strncasecomp(attr_start, "secure", 6)) { + if (value == NULL) { + known_attr = YES; + if (cur_cookie != NULL) { + cur_cookie->flags |= COOKIE_FLAG_SECURE; + } + } else { + /* + * If secure has a value, assume someone + * misused it as cookie name. - FM + */ + known_attr = NO; + } + } else if (len == 7 && !strncasecomp(attr_start, "discard", 7)) { + if (value == NULL) { + known_attr = YES; + if (cur_cookie != NULL) { + cur_cookie->flags |= COOKIE_FLAG_DISCARD; + } + } else { + /* + * If discard has a value, assume someone + * used it as a cookie name. - FM + */ + known_attr = NO; + } + } else if (len == 7 && !strncasecomp(attr_start, "comment", 7)) { + known_attr = YES; + if (cur_cookie != NULL && value && + /* + * Don't process a repeat comment. - FM + */ + cur_cookie->comment == NULL) { + StrAllocCopy(cur_cookie->comment, value); + length += strlen(cur_cookie->comment); + } + } else if (len == 10 && !strncasecomp(attr_start, + "commentURL", 10)) { + known_attr = YES; + if (cur_cookie != NULL && value && + /* + * Don't process a repeat commentURL. - FM + */ + cur_cookie->commentURL == NULL) { + /* + * We should get only absolute URLs as + * values, but will resolve versus the + * request's URL just in case. - FM + */ + cur_cookie->commentURL = HTParse(value, + address, + PARSE_ALL); + /* + * Accept only URLs for servers. - FM + */ + if ((url_type = is_url(cur_cookie->commentURL)) && + (url_type == HTTP_URL_TYPE || + url_type == HTTPS_URL_TYPE || + url_type == FTP_URL_TYPE || + url_type == GOPHER_URL_TYPE || + url_type == HTML_GOPHER_URL_TYPE || + url_type == INDEX_GOPHER_URL_TYPE || + url_type == NEWS_URL_TYPE || + url_type == NNTP_URL_TYPE || + url_type == SNEWS_URL_TYPE || + url_type == WAIS_URL_TYPE || + url_type == CSO_URL_TYPE || + url_type == FINGER_URL_TYPE)) { + length += strlen(cur_cookie->commentURL); + } else { + FREE(cur_cookie->commentURL); + } + } + } else if (len == 6 && !strncasecomp(attr_start, "domain", 6)) { + known_attr = YES; + if (cur_cookie != NULL && value && + /* + * Don't process a repeat domain. - FM + */ + !(cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) { + length -= strlen(cur_cookie->domain); + StrAllocCopy(cur_cookie->domain, value); + length += strlen(cur_cookie->domain); + cur_cookie->flags |= COOKIE_FLAG_DOMAIN_SET; + } + } else if (len == 4 && !strncasecomp(attr_start, "path", 4)) { known_attr = YES; + if (cur_cookie != NULL && value && + /* + * Don't process a repeat path. - FM + */ + !(cur_cookie->flags & COOKIE_FLAG_PATH_SET)) { + length -= strlen(cur_cookie->path); + StrAllocCopy(cur_cookie->path, value); + length += (cur_cookie->pathlen = strlen(cur_cookie->path)); + cur_cookie->flags |= COOKIE_FLAG_PATH_SET; + } + } else if (len == 4 && !strncasecomp(attr_start, "port", 4)) { + if (cur_cookie != NULL && value && + /* + * Don't process a repeat port. - FM + */ + cur_cookie->PortList == NULL) { + char *cp = value; + while ((*cp != '\0') && + (isdigit((unsigned char)*cp) || + *cp == ',' || *cp == ' ')) { + cp++; + } + if (*cp == '\0') { + StrAllocCopy(cur_cookie->PortList, value); + length += strlen(cur_cookie->PortList); + known_attr = YES; + } else { + known_attr = NO; + } + } else if (cur_cookie != NULL) { + /* + * Don't process a repeat port. - FM + */ + if (cur_cookie->PortList == NULL) { + char temp[256]; + sprintf(temp, "%d", port); + StrAllocCopy(cur_cookie->PortList, temp); + length += strlen(cur_cookie->PortList); + } + known_attr = YES; + } + } else if (len == 7 && !strncasecomp(attr_start, "version", 7)) { + known_attr = YES; + if (cur_cookie != NULL && value && + /* + * Don't process a repeat version. - FM + */ + cur_cookie->version < 0) { + int temp = strtol(value, NULL, 10); + if (errno != -ERANGE) { + cur_cookie->version = temp; + } + } + } else if (len == 7 && !strncasecomp(attr_start, "max-age", 7)) { + known_attr = YES; + if ((cur_cookie != NULL) && !MaxAgeAttrSet && value) { + int temp = strtol(value, NULL, 10); + cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET; + if (errno == -ERANGE) { + cur_cookie->expires = (time_t)0; + } else { + cur_cookie->expires = (time(NULL) + temp); + } + MaxAgeAttrSet = TRUE; + } + } else if (len == 7 && !strncasecomp(attr_start, "expires", 7)) { + /* + * Convert an 'expires' attribute value if we haven't + * received a 'max-age'. Note that 'expires' should not + * be used in Version 1 cookies, but it might be used for + * "backward compatibility", and, in turn, ill-informed + * people surely would start using it instead of, rather + * than in addition to, 'max-age'. - FM + */ + known_attr = YES; + if ((cur_cookie != NULL) && !(MaxAgeAttrSet) && + !(cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET)) { + if (value) { + cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET; + cur_cookie->expires = LYmktime(value, FALSE); + } + } } /* @@ -817,81 +1520,406 @@ PUBLIC void LYSetCookie ARGS2( * ignore it. - FM */ if (!known_attr && value_end > value_start) { - store_cookie(cur_cookie, hostname, path); - cur_cookie = newCookie(); - length += len; - if (length > 4096) { - FREE(value); - break; + if (cur_cookie) { + if (SetCookie2 != NULL) { + /* + * If we had a Set-Cookie2 header, make sure + * the version is at least 1, and mark it for + * quoting. - FM + */ + if (cur_cookie->version < 1) { + cur_cookie->version = 1; + } + cur_cookie->quoted = TRUE; + } + cl = CombinedCookies; + while (NULL != (co = (cookie *)HTList_nextObject(cl))) { + /* + * Check whether the cookie from the Set-Cookie2 + * header has the same name and value as this one + * from the Set-Cookie header. If they both had a + * domain attribute, make sure those match, and + * similarly if they both had a path attribute. - FM + */ + if ((!strcmp(co->name, cur_cookie->name) && + !strcmp(co->value, cur_cookie->value)) && + !(((co->flags & COOKIE_FLAG_DOMAIN_SET) && + (cur_cookie->flags & + COOKIE_FLAG_DOMAIN_SET)) && + strcmp(co->domain, cur_cookie->domain)) && + !(((co->flags & COOKIE_FLAG_PATH_SET) && + (cur_cookie->flags & + COOKIE_FLAG_PATH_SET)) && + strcmp(co->path, cur_cookie->path))) { + /* + * If the Set-Cookie2 header didn't include + * a domain attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_DOMAIN_SET) && + (cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) { + StrAllocCopy(co->domain, cur_cookie->domain); + co->flags |= COOKIE_FLAG_DOMAIN_SET; + } + /* + * If the Set-Cookie2 header didn't include + * a path attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_PATH_SET) && + (cur_cookie->flags & COOKIE_FLAG_PATH_SET)) { + StrAllocCopy(co->path, cur_cookie->path); + co->pathlen = cur_cookie->pathlen; + co->flags |= COOKIE_FLAG_DOMAIN_SET; + } + /* + * If the Set-Cookie2 header didn't include + * a comment attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!co->comment && cur_cookie->comment) { + StrAllocCopy(co->comment, + cur_cookie->comment); + } + /* + * If the Set-Cookie2 header didn't include + * a commentURL attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!co->commentURL && cur_cookie->commentURL) { + StrAllocCopy(co->commentURL, + cur_cookie->commentURL); + } + /* + * If the Set-Cookie2 header didn't include + * a port attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!co->PortList && cur_cookie->PortList) { + StrAllocCopy(co->PortList, + cur_cookie->PortList); + } + /* + * If the Set-Cookie2 header didn't include + * a secure attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_SECURE) && + (cur_cookie->flags & COOKIE_FLAG_SECURE)) { + co->flags |= COOKIE_FLAG_SECURE; + } + /* + * If the Set-Cookie2 header didn't set an + * expiration and the Set-Cookie header did, + * add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_EXPIRES_SET) && + (cur_cookie->flags & + COOKIE_FLAG_EXPIRES_SET)) { + co->expires = cur_cookie->expires; + co->flags |= COOKIE_FLAG_EXPIRES_SET; + } + /* + * If the Set-Cookie2 header didn't set + * discard and the Set-Cookie header did, + * add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_DISCARD) && + (cur_cookie->flags & COOKIE_FLAG_DISCARD)) { + co->flags |= COOKIE_FLAG_DISCARD; + } + /* + * If the cookie from the Set-Cookie2 header + * has a lower version than this cookie, use + * this cookie's version (though it should + * not have a version number). - FM + */ + if (co->version < cur_cookie->version) { + co->version = cur_cookie->version; + } + freeCookie(cur_cookie); + cur_cookie = NULL; + break; + } + } + if (co == NULL) { + HTList_appendObject(CombinedCookies, cur_cookie); + } } + cur_cookie = newCookie(); + length = 0; + MemAllocCopy(&(cur_cookie->name), attr_start, attr_end); + length += strlen(cur_cookie->name); + MemAllocCopy(&(cur_cookie->value), value_start, value_end); + length += strlen(cur_cookie->value); StrAllocCopy(cur_cookie->domain, hostname); + length += strlen(cur_cookie->domain); StrAllocCopy(cur_cookie->path, path); - cur_cookie->pathlen = strlen(cur_cookie->path); + length += (cur_cookie->pathlen = strlen(cur_cookie->path)); cur_cookie->port = port; - MemAllocCopy(&(cur_cookie->name), attr_start, attr_end); - MemAllocCopy(&(cur_cookie->value), value_start, value_end); + MaxAgeAttrSet = FALSE; cur_cookie->quoted = Quoted; Quoted = FALSE; } FREE(value); } - if (TRACE) { - fprintf(stderr, "LYSetCookie: attr=value pair: "); - if (attr_start == attr_end) { - fprintf(stderr, "[No attr]"); - } else { - CONST char *i; - - for (i = attr_start; i < attr_end; i++) - putc(*i, stderr); + } + + /* + * Handle the final Set-Cookie cookie if within length limit. - FM + */ + if (NumCookies <= 50 && length <= 4096 && cur_cookie != NULL) { + if (SetCookie2 != NULL) { + if (cur_cookie->version < 1) { + cur_cookie->version = 1; } - fprintf(stderr, "="); - if (value_start >= value_end) { - fprintf(stderr, "[No value]"); - } else { - CONST char *i; + cur_cookie->quoted = TRUE; + } + cl = CombinedCookies; + while (NULL != (co = (cookie *)HTList_nextObject(cl))) { + /* + * Check whether the cookie from the Set-Cookie2 + * header has the same name and value as this one + * from the Set-Cookie header. If they both had a + * domain attribute, make sure those match, and + * similarly if they both had a path attribute. - FM + */ + if ((!strcmp(co->name, cur_cookie->name) && + !strcmp(co->value, cur_cookie->value)) && + !(((co->flags & COOKIE_FLAG_DOMAIN_SET) && + (cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) && + strcmp(co->domain, cur_cookie->domain)) && + !(((co->flags & COOKIE_FLAG_PATH_SET) && + (cur_cookie->flags & COOKIE_FLAG_PATH_SET)) && + strcmp(co->path, cur_cookie->path))) { + /* + * If the Set-Cookie2 header didn't include + * a domain attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_DOMAIN_SET) && + (cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) { + StrAllocCopy(co->domain, cur_cookie->domain); + co->flags |= COOKIE_FLAG_DOMAIN_SET; + } + /* + * If the Set-Cookie2 header didn't include + * a path attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_PATH_SET) && + (cur_cookie->flags & COOKIE_FLAG_PATH_SET)) { + StrAllocCopy(co->path, cur_cookie->path); + co->pathlen = cur_cookie->pathlen; + co->flags |= COOKIE_FLAG_DOMAIN_SET; + } + /* + * If the Set-Cookie2 header didn't include + * a comment attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!co->comment && cur_cookie->comment) { + StrAllocCopy(co->comment, cur_cookie->comment); + } + /* + * If the Set-Cookie2 header didn't include + * a commentURL attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!co->commentURL && cur_cookie->commentURL) { + StrAllocCopy(co->commentURL, cur_cookie->commentURL); + } + /* + * If the Set-Cookie2 header didn't include + * a port attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!co->PortList && cur_cookie->PortList) { + StrAllocCopy(co->PortList, cur_cookie->PortList); + } + /* + * If the Set-Cookie2 header didn't include + * a secure attribute and the Set-Cookie + * header did, add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_SECURE) && + (cur_cookie->flags & COOKIE_FLAG_SECURE)) { + co->flags |= COOKIE_FLAG_SECURE; + } + /* + * If the Set-Cookie2 header didn't set an + * expiration and the Set-Cookie header did, + * add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_EXPIRES_SET) && + (cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET)) { + co->expires = cur_cookie->expires; + co->flags |= COOKIE_FLAG_EXPIRES_SET; + } + /* + * If the Set-Cookie2 header didn't set + * discard and the Set-Cookie header did, + * add it. - FM + */ + if (!(co->flags & COOKIE_FLAG_DISCARD) && + (cur_cookie->flags & COOKIE_FLAG_DISCARD)) { + co->flags |= COOKIE_FLAG_DISCARD; + } + /* + * If the cookie from the Set-Cookie2 header + * has a lower version than this cookie, use + * this cookie's version (though it should + * not have a version number). - FM + */ + if (co->version < cur_cookie->version) { + co->version = cur_cookie->version; + } + freeCookie(cur_cookie); + cur_cookie = NULL; + break; + } + } + if (co == NULL) { + HTList_appendObject(CombinedCookies, cur_cookie); + } + } else if (cur_cookie != NULL) { + if (TRACE) { + fprintf(stderr, + "LYProcessSetCookies: Rejecting Set-Cookie: %s=%s\n", + (cur_cookie->name ? cur_cookie->name : "[no name]"), + (cur_cookie->value ? cur_cookie->value : "[no value]")); + fprintf(stderr, + " due to excessive %s%s%s\n", + (length > 4096 ? "length" : ""), + (length > 4096 && NumCookies > 50 ? " and " : ""), + (NumCookies > 50 ? "number!\n" : "!\n")); + } + freeCookie(cur_cookie); + cur_cookie = NULL; + } - for (i = value_start; i < value_end; i++) - putc(*i, stderr); + /* + * OK, now we can actually store any cookies + * in the CombinedCookies list. - FM + */ + cl = CombinedCookies; + while (NULL != (co = (cookie *)HTList_nextObject(cl))) { + if (TRACE) { + fprintf(stderr, "LYProcessSetCookie: attr=value pair: '%s=%s'\n", + (co->name ? co->name : "[no name]"), + (co->value ? co->value : "[no value]")); + if (co->expires > 0) { + fprintf(stderr, " expires: %i, %s\n", + co->expires, + ctime(&co->expires)); + } + } + if (!strncasecomp(address, "https:", 6) && + LYForceSSLCookiesSecure == TRUE && + !(co->flags & COOKIE_FLAG_SECURE)) { + co->flags |= COOKIE_FLAG_SECURE; + if (TRACE) { + fprintf(stderr, + " Forced the 'secure' flag on.\n"); } - fprintf(stderr, "\n"); } + store_cookie(co, hostname, path); } + HTList_delete(CombinedCookies); + CombinedCookies = NULL; + + return; +} + +/* +** Entry function for handling Set-Cookie: and/or Set-Cookie2: +** reply headers. They may have been concatenated as comma +** separated lists in HTTP.c or HTMIME.c. - FM +*/ +PUBLIC void LYSetCookie ARGS3( + CONST char *, SetCookie, + CONST char *, SetCookie2, + CONST char *, address) +{ + BOOL BadHeaders = FALSE; + char *hostname = NULL, *path = NULL, *ptr; + int port = 80; /* - * Store the final cookie if within length limit. - FM + * Get the hostname, port and path of the address, and report + * the Set-Cookie request if trace mode is on, but set the cookie + * only if LYSetCookies is TRUE. - FM */ - if (length <= 4096 && cur_cookie != NULL) { - /* - * Force the secure flag on if it's not set but this - * is an https URL. This ensures that cookies from - * https servers will not be shared with ones for - * http (non-SSL) servers and thus be transmitted - * unencrypted, and is redundant with the current, - * blanket port restriction. However, this seemed - * a side-effect rather than conscious intent within - * the port restriction. A port attribute is likely - * to be added, and we can independently regulate - * sharing based on port versus scheme, with user - * configuration and run time options, "when the - * time is right". - FM + if (((hostname = HTParse(address, "", PARSE_HOST)) != NULL) && + (ptr = strchr(hostname, ':')) != NULL) { + /* + * Replace default port number. */ - if (!strncasecomp(address, "https:", 6) && - !(cur_cookie->flags & COOKIE_FLAG_SECURE)) { - cur_cookie->flags |= COOKIE_FLAG_SECURE; - if (TRACE) - fprintf(stderr, "LYSetCookie: Forced the 'secure' flag on.\n"); + *ptr = '\0'; + ptr++; + port = atoi(ptr); + } else if (!strncasecomp(address, "https:", 6)) { + port = 443; + } + if (((path = HTParse(address, "", + PARSE_PATH|PARSE_PUNCTUATION)) != NULL) && + (ptr = strrchr(path, '/')) != NULL) { + if (ptr == path) { + *(ptr+1) = '\0'; /* Leave a single '/' alone */ + } else { + *ptr = '\0'; } - store_cookie(cur_cookie, hostname, path); - } else { - if (TRACE) - fprintf(stderr, "LYSetCookie: Rejecting cookie due to length!\n"); - freeCookie(cur_cookie); } + if (!(SetCookie && *SetCookie) && + !(SetCookie2 && *SetCookie2)) { + /* + * Yuk, something must have gone wrong in + * HTMIME.c or HTTP.c because both SetCookie + * and SetCookie2 are NULL or zero-length. - FM + */ + BadHeaders = TRUE; + } + if (TRACE) { + fprintf(stderr, + "LYSetCookie called with host '%s', path '%s',\n", + (hostname ? hostname : ""), + (path ? path : "")); + if (SetCookie) { + fprintf(stderr, " and Set-Cookie: '%s'\n", + (SetCookie ? SetCookie : "")); + } + if (SetCookie2) { + fprintf(stderr, " and Set-Cookie2: '%s'\n", + (SetCookie2 ? SetCookie2 : "")); + } + if (LYSetCookies == FALSE || BadHeaders == TRUE) { + fprintf(stderr, + " Ignoring this Set-Cookie/Set-Cookie2 request.\n"); + } + } + + /* + * We're done if LYSetCookies is off or we have bad headers. - FM + */ + if (LYSetCookies == FALSE || BadHeaders == TRUE) { + FREE(hostname); + FREE(path); + return; + } + + /* + * Process the header(s). + */ + LYProcessSetCookies(SetCookie, SetCookie2, address, hostname, path, port); FREE(hostname); FREE(path); + return; } +/* +** Entry function from creating a Cookie: request header +** if needed. - AK & FM +*/ PUBLIC char * LYCookie ARGS4( CONST char *, hostname, CONST char *, path, @@ -946,9 +1974,9 @@ PUBLIC char * LYCookie ARGS4( return(header); /* - * If we set a header, perhaps all the cookies have - * expired and we deleted the last of them above, so - * check if we should delete and NULL the domain_list. - FM + * If we didn't set a header, perhaps all the cookies have + * expired and we deleted the last of them above, so check + * if we should delete and NULL the domain_list. - FM */ if (domain_list) { if (HTList_isEmpty(domain_list)) { @@ -972,7 +2000,7 @@ PUBLIC char * LYCookie ARGS4( ** Semantics: ** LYNXCOOKIE:/ Create and load the Cookie Jar Page. ** LYNXCOOKIE://domain Manipulate the domain. -** LYNXCOOKIE://domain/lynx_id Delete cookie with lynx_id in domain. +** LYNXCOOKIE://domain/lynxID Delete cookie with lynxID in domain. ** ** New functions can be added as extensions to the path, and/or by ** assigning meanings to ;parameters, a ?searchpart, and/or #fragments. @@ -987,11 +2015,12 @@ PRIVATE int LYHandleCookies ARGS4 ( HTStream *target = NULL; char buf[1024]; char *domain = NULL; - char *lynx_id = NULL; + char *lynxID = NULL; HTList *dl, *cl, *next; domain_entry *de; cookie *co; - char *name = NULL, *value = NULL, *path = NULL, *comment = NULL; + char *name = NULL, *value = NULL, *path = NULL; + char *comment = NULL, *Address = NULL, *Title = NULL; int ch; #ifdef VMS extern BOOLEAN HadVMSInterrupt; @@ -1017,12 +2046,12 @@ PRIVATE int LYHandleCookies ARGS4 ( } else { /* * If there is a path string (not just a slash) in the - * LYNXCOOKIE: URL, that's a cookie's lynx_id and this + * LYNXCOOKIE: URL, that's a cookie's lynxID and this * is a request to delete it from the Cookie Jar. - FM */ - if ((lynx_id = HTParse(arg, "", PARSE_PATH)) != NULL) { - if (*lynx_id == '\0') { - FREE(lynx_id); + if ((lynxID = HTParse(arg, "", PARSE_PATH)) != NULL) { + if (*lynxID == '\0') { + FREE(lynxID); } } } @@ -1041,11 +2070,11 @@ PRIVATE int LYHandleCookies ARGS4 ( if (!strcmp(domain, de->domain)) { /* * We found the domain. Check - * whether a lynx_id is present. - FM + * whether a lynxID is present. - FM */ - if (lynx_id) { + if (lynxID) { /* - * Seek and delete the cookie with this lynx_id + * Seek and delete the cookie with this lynxID * in the domain's cookie list. - FM */ for (cl = de->cookie_list; cl != NULL; cl = cl->next) { @@ -1054,7 +2083,7 @@ PRIVATE int LYHandleCookies ARGS4 ( * First object is always empty. - FM */ continue; - if (!strcmp(lynx_id, co->lynx_id)) { + if (!strcmp(lynxID, co->lynxID)) { /* * We found the cookie. * Delete it if confirmed. - FM @@ -1322,13 +2351,13 @@ Delete_all_cookies_in_domain: StrAllocCopy(value, NO_VALUE); } sprintf(buf, "<DD><A HREF=\"LYNXCOOKIE://%s/%s\">%s=%s</A>\n", - de->domain, co->lynx_id, name, value); + de->domain, co->lynxID, name, value); FREE(name); FREE(value); (*target->isa->put_block)(target, buf, strlen(buf)); /* - * Show the path, port, and secure setting. - FM + * Show the path, port, secure and discard setting. - FM */ if (co->path) { StrAllocCopy(path, co->path); @@ -1343,14 +2372,29 @@ Delete_all_cookies_in_domain: (*target->isa->put_block)(target, buf, strlen(buf)); /* - * Show the Maximum Gobble Date. - FM + * Show the list of acceptable ports, if present. - FM */ - sprintf(buf, "<DD><EM>Maximum Gobble Date:</EM> %s%s", - ((co->expires > 0) ? - ctime(&co->expires) : END_OF_SESSION), - ((co->expires > 0) ? - "" : "\n")); - (*target->isa->put_block)(target, buf, strlen(buf)); + if (co->PortList) { + sprintf(buf, "<DD>PortList=\"%s\"\n", co->PortList); + (*target->isa->put_block)(target, buf, strlen(buf)); + } + + /* + * Show the commentURL, if we have one. - FM + */ + if (co->commentURL) { + StrAllocCopy(Address, co->commentURL); + LYEntify(&Address, FALSE); + StrAllocCopy(Title, co->commentURL); + LYEntify(&Title, TRUE); + sprintf(buf, + "<DD>CommentURL: <A href=\"%s\">%s</A>\n", + Address, + Title); + FREE(Address); + FREE(Title); + (*target->isa->put_block)(target, buf, strlen(buf)); + } /* * Show the comment, if we have one. - FM @@ -1358,10 +2402,24 @@ Delete_all_cookies_in_domain: if (co->comment) { StrAllocCopy(comment, co->comment); LYEntify(&comment, TRUE); - sprintf(buf, "<DD><EM>Comment:</EM> %s\n", comment); + sprintf(buf, "<DD>Comment: %s\n", comment); FREE(comment); (*target->isa->put_block)(target, buf, strlen(buf)); } + + /* + * Show the Maximum Gobble Date. - FM + */ + sprintf(buf, "<DD><EM>Maximum Gobble Date:</EM> %s%s", + ((co->expires > 0 && + !(co->flags & COOKIE_FLAG_DISCARD)) + ? + ctime(&co->expires) : END_OF_SESSION), + ((co->expires > 0 && + !(co->flags & COOKIE_FLAG_DISCARD)) + ? + "" : "\n")); + (*target->isa->put_block)(target, buf, strlen(buf)); } sprintf(buf, "</DT>\n"); (*target->isa->put_block)(target, buf, strlen(buf)); diff --git a/src/LYCookie.h b/src/LYCookie.h index abc8a018..9900a017 100644 --- a/src/LYCookie.h +++ b/src/LYCookie.h @@ -3,7 +3,8 @@ #define LYCOOKIES_H extern void LYSetCookie PARAMS(( - CONST char * header, + CONST char * SetCookie, + CONST char * SetCookie2, CONST char * address)); extern char *LYCookie PARAMS(( CONST char * hostname, diff --git a/src/LYCurses.c b/src/LYCurses.c index 968c23d5..1424417e 100644 --- a/src/LYCurses.c +++ b/src/LYCurses.c @@ -52,10 +52,14 @@ PRIVATE int Current_Attr; #ifdef USE_SLANG PUBLIC unsigned int Lynx_Color_Flags = 0; +PRIVATE int Current_Attr; PUBLIC BOOLEAN FullRefresh = FALSE; PUBLIC int curscr = 0; #ifdef SLANG_MBCS_HACK -PUBLIC int PHYSICAL_SLtt_Screen_Cols = 10;/* will be set by size_change - kw */ +/* + * Will be set by size_change. - KW + */ +PUBLIC int PHYSICAL_SLtt_Screen_Cols = 10; #endif /* SLANG_MBCS_HACK */ PUBLIC void LY_SLrefresh NOARGS @@ -84,14 +88,14 @@ PUBLIC void VTHome NOARGS } #endif /* VMS */ -PUBLIC void lynx_add_attr ARGS1( +PUBLIC void LYaddAttr ARGS1( int, a) { Current_Attr |= a; SLsmg_set_color(Current_Attr); } -PUBLIC void lynx_sub_attr ARGS1( +PUBLIC void LYsubAttr ARGS1( int, a) { Current_Attr &= ~a; @@ -264,6 +268,14 @@ PUBLIC void curses_w_style ARGS4(WINDOW*,win,int,style,int,dir,int,previous) return; case STACK_ON: /* remember the current attributes */ + if (last_ptr > 127) { + if (TRACE) + fprintf(stderr,"........... %s (0x%x) %s\r\n", + "attribute cache FULL, dropping last", + last_styles[last_ptr], + "in LynxChangStyle(curses_w_style)"); + last_ptr--; + } #ifndef _NCURSES_H last_styles[last_ptr++] = getattrs(stdscr); #else @@ -334,7 +346,7 @@ PUBLIC void curses_style ARGS3(int,style,int,dir,int,previous) curses_w_style(stdscr, style, dir, previous); } -#if UNUSED +#ifdef NOT_USED void attribute ARGS2(int,style,int,dir) { curses_style(style, dir, 0); @@ -380,7 +392,7 @@ PRIVATE struct { * Map the SGR attributes (0-7) into ANSI colors, modified with the actual BOLD * attribute we'll get 16 colors. */ -PRIVATE void lynx_set_wattr ARGS1(WINDOW *, win) +PRIVATE void LYsetWAttr ARGS1(WINDOW *, win) { if (lynx_uses_color) { int code = 0; @@ -484,31 +496,9 @@ PUBLIC void lynx_set_color ARGS1(int, a) PUBLIC void lynx_standout ARGS1(int, flag) { if (flag) - lynx_add_attr(A_REVERSE); + LYaddAttr(A_REVERSE); else - lynx_sub_attr(A_REVERSE); -} - -PUBLIC void lynx_add_wattr ARGS2(WINDOW *, win, int, a) -{ - Current_Attr |= a; - lynx_set_wattr(win); -} - -PUBLIC void lynx_add_attr ARGS1(int, a) -{ - lynx_add_wattr (stdscr, a); -} - -PUBLIC void lynx_sub_wattr ARGS2(WINDOW *, win, int, a) -{ - Current_Attr &= ~a; - lynx_set_wattr(win); -} - -PUBLIC void lynx_sub_attr ARGS1(int, a) -{ - lynx_sub_wattr (stdscr, a); + LYsubAttr(A_REVERSE); } PRIVATE void lynx_init_colors NOARGS @@ -619,8 +609,8 @@ PUBLIC void start_curses NOARGS SLtty_set_suspend_state(1); #endif /* _WINDOWS */ #ifdef SIGTSTP - if (!no_suspend) - signal(SIGTSTP, sl_suspend); + if (!no_suspend) + signal(SIGTSTP, sl_suspend); #endif /* SIGTSTP */ signal(SIGINT, cleanup_sig); #endif /* !VMS */ @@ -631,7 +621,7 @@ PUBLIC void start_curses NOARGS #ifdef VMS /* - * If we are VMS then do initscr() everytime start_curses() + * If we are VMS then do initsrc() everytime start_curses() * is called! */ initscr(); /* start curses */ @@ -743,10 +733,6 @@ PUBLIC void stop_curses NOARGS #endif #if defined (DOSPATH) && !defined (USE_SLANG) clrscr(); -/* - clear(); - refresh(); -*/ #else /* @@ -764,16 +750,18 @@ PUBLIC void stop_curses NOARGS LYCursesON = FALSE; +#if defined(SIGTSTP) && defined(USE_SLANG) #ifndef VMS -#ifdef SIGTSTP if (!no_suspend) signal(SIGTSTP, SIG_DFL); -#endif /* SIGTSTP */ +#endif /* !VMS */ +#endif /* SIGTSTP && USE_SLANG */ + +#ifndef VMS signal(SIGINT, SIG_DFL); #endif /* !VMS */ } - #ifdef VMS /* * Check terminal type, start curses & setup terminal. @@ -807,7 +795,8 @@ PUBLIC BOOLEAN setup ARGS1( */ dump_output_immediately = TRUE; LYcols = 80; - keypad_mode = LINKS_ARE_NUMBERED; + if (keypad_mode == NUMBERS_AS_ARROWS) + keypad_mode = LINKS_ARE_NUMBERED; status = mainloop(); (void) signal (SIGHUP, SIG_DFL); (void) signal (SIGTERM, SIG_DFL); @@ -841,6 +830,10 @@ PUBLIC BOOLEAN setup ARGS1( LYlines = LINES; LYcols = COLS; + if (LYlines <= 0) + LYlines = 24; + if (LYcols <= 0) + LYcols = 80; return(TRUE); } @@ -903,6 +896,10 @@ PUBLIC BOOLEAN setup ARGS1( LYlines = LINES; LYcols = COLS; + if (LYlines <= 0) + LYlines = 24; + if (LYcols <= 0) + LYcols = 80; return(1); } @@ -926,8 +923,60 @@ PRIVATE int dumbterm ARGS1( dumb = TRUE; return(dumb); } + +#ifdef FANCY_CURSES +#ifndef USE_COLOR_STYLE +#if USE_COLOR_TABLE +PUBLIC void LYaddWAttr ARGS2( + WINDOW *, win, + int, a) +{ + Current_Attr |= a; + LYsetWAttr(win); +} + +PUBLIC void LYaddAttr ARGS1( + int, a) +{ + LYaddWAttr(stdscr, a); +} + +PUBLIC void LYsubWAttr ARGS2( + WINDOW *, win, + int, a) +{ + Current_Attr &= ~a; + LYsetWAttr(win); +} + +PUBLIC void LYsubAttr ARGS1( + int, a) +{ + LYsubWAttr(stdscr, a); +} +#endif +#endif /* USE_COLOR_STYLE */ +#endif /* FANCY_CURSES */ #endif /* VMS */ +PUBLIC void LYstartTargetEmphasis NOARGS +{ +#if defined(FANCY_CURSES) || defined(USE_SLANG) + start_bold(); + start_reverse(); +#endif /* FANCY_CURSES || USE_SLANG */ + start_underline(); +} + +PUBLIC void LYstopTargetEmphasis NOARGS +{ + stop_underline(); +#if defined(FANCY_CURSES) || defined(USE_SLANG) + stop_reverse(); + stop_bold(); +#endif /* FANCY_CURSES || USE_SLANG */ +} + #ifdef VMS /* * Cut-down termio -- @@ -1471,7 +1520,9 @@ PUBLIC void lynx_stop_title_color NOARGS { } -PUBLIC void lynx_start_link_color ARGS1(int, flag) +PUBLIC void lynx_start_link_color ARGS2( + int, flag, + int, pending) { if (flag) { /* makes some terminals work wrong because @@ -1480,26 +1531,48 @@ PUBLIC void lynx_start_link_color ARGS1(int, flag) */ /* start_bold(); */ start_reverse(); -#if defined(USE_SLANG) || defined(FANCY_CURSES) +#if defined(USE_SLANG) + if (SLtt_Use_Ansi_Colors) + start_underline (); +#endif /* USE_SLANG */ +#if defined(FANCY_CURSES) start_underline (); #endif /* USE_SLANG */ } else { start_bold(); + /* + * Make sure when flag is OFF that "unhighlighted" links + * will be underlined if appropriate. - LE & FM + */ + if (pending) + start_underline(); } } -PUBLIC void lynx_stop_link_color ARGS1(int, flag) +PUBLIC void lynx_stop_link_color ARGS2( + int, flag, + int, pending) { #ifdef USE_COLOR_STYLE LynxChangeStyle(flag == ON ? s_alink : s_a, ABS_OFF, 0); #else if (flag) { stop_reverse(); -#if defined(USE_SLANG) || defined(FANCY_CURSES) +#if defined(USE_SLANG) + if (SLtt_Use_Ansi_Colors) + stop_underline (); +#endif /* USE_SLANG */ +#if defined(FANCY_CURSES) stop_underline (); #endif /* USE_SLANG */ - } else + } else { stop_bold(); + /* + * If underlining was turned on above, turn it off. - LE & FM + */ + if (pending) + stop_underline(); + } #endif } diff --git a/src/LYCurses.h b/src/LYCurses.h index 82efadc9..8ea9ce78 100644 --- a/src/LYCurses.h +++ b/src/LYCurses.h @@ -30,7 +30,7 @@ #ifdef VMS #define FANCY_CURSES -#endif +#endif /* VMS */ /* * CR may be defined before the curses.h include occurs. @@ -108,6 +108,8 @@ extern int LYcols; /* replaces COLS */ extern void start_curses NOPARAMS; extern void stop_curses NOPARAMS; extern BOOLEAN setup PARAMS((char *terminal)); +extern void LYstartTargetEmphasis NOPARAMS; +extern void LYstopTargetEmphasis NOPARAMS; #ifdef VMS extern void VMSexit(); @@ -121,21 +123,21 @@ extern void VMSbox PARAMS((WINDOW *win, int height, int width)); #endif /* VMS */ #if defined(USE_COLOR_STYLE) -extern void curses_css PARAMS((char * name,int dir)); -extern void curses_style PARAMS((int style,int dir,int previous)); -extern void curses_w_style PARAMS((WINDOW* win,int style,int dir,int previous)); -extern void setHashStyle PARAMS((int style,int color,int cattr,int mono,char* element)); -extern void setStyle PARAMS((int style,int color,int cattr,int mono)); -extern void wcurses_css PARAMS((WINDOW * win,char* name,int dir)); +extern void curses_css PARAMS((char * name, int dir)); +extern void curses_style PARAMS((int style, int dir, int previous)); +extern void curses_w_style PARAMS((WINDOW* win, int style, int dir, int previous)); +extern void setHashStyle PARAMS((int style, int color, int cattr, int mono, char* element)); +extern void setStyle PARAMS((int style, int color, int cattr, int mono)); +extern void wcurses_css PARAMS((WINDOW * win, char* name, int dir)); #define LynxChangeStyle curses_style #else -extern int slang_style PARAMS((int style,int dir,int previous)); +extern int slang_style PARAMS((int style, int dir, int previous)); #define LynxChangeStyle slang_style #endif /* USE_COLOR_STYLE */ #if USE_COLOR_TABLE -extern void lynx_add_attr PARAMS((int a)); -extern void lynx_sub_attr PARAMS((int a)); +extern void LYaddAttr PARAMS((int a)); +extern void LYsubAttr PARAMS((int a)); extern void lynx_setup_colors NOPARAMS; extern unsigned int Lynx_Color_Flags; #endif @@ -147,18 +149,20 @@ extern unsigned int Lynx_Color_Flags; #define SL_LYNX_USE_COLOR 1 #define SL_LYNX_USE_BLINK 2 -#define start_bold() lynx_add_attr(1) -#define start_reverse() lynx_add_attr(2) -#define start_underline() lynx_add_attr(4) -#define stop_bold() lynx_sub_attr(1) -#define stop_reverse() lynx_sub_attr(2) -#define stop_underline() lynx_sub_attr(4) +#define start_bold() LYaddAttr(1) +#define start_reverse() LYaddAttr(2) +#define start_underline() LYaddAttr(4) +#define stop_bold() LYsubAttr(1) +#define stop_reverse() LYsubAttr(2) +#define stop_underline() LYsubAttr(4) #ifdef FANCY_CURSES #undef FANCY_CURSES #endif /* FANCY_CURSES */ -/* Map some curses functions to slang functions. */ +/* + * Map some curses functions to slang functions. + */ #define stdscr NULL #ifdef SLANG_MBCS_HACK extern int PHYSICAL_SLtt_Screen_Cols; @@ -203,80 +207,109 @@ extern void VTHome NOPARAMS; #ifdef FANCY_CURSES #ifdef VMS +/* + * For VMS curses, [w]setattr() and [w]clrattr() + * add and subtract, respectively, the attributes + * _UNDERLINE, _BOLD, _REVERSE, and _BLINK. - FM + */ #ifdef UNDERLINE_LINKS -#define start_bold() setattr(_UNDERLINE) -#define stop_bold() clrattr(_UNDERLINE) -#define start_underline() setattr(_BOLD) -#define stop_underline() clrattr(_BOLD) +#define start_bold() setattr(_UNDERLINE) +#define stop_bold() clrattr(_UNDERLINE) +#define start_underline() setattr(_BOLD) +#define stop_underline() clrattr(_BOLD) #else /* not UNDERLINE_LINKS */ -#define start_bold() setattr(_BOLD) -#define stop_bold() clrattr(_BOLD) -#define start_underline() setattr(_UNDERLINE) -#define stop_underline() clrattr(_UNDERLINE) +#define start_bold() setattr(_BOLD) +#define stop_bold() clrattr(_BOLD) +#define start_underline() setattr(_UNDERLINE) +#define stop_underline() clrattr(_UNDERLINE) #endif /* UNDERLINE_LINKS */ -#define start_reverse() setattr(_REVERSE) -#define wstart_reverse(a) wsetattr(a,_REVERSE) -#define wstop_underline(a) wclrattr(a,_UNDERLINE) -#define stop_reverse() clrattr(_REVERSE) -#define wstop_reverse(a) wclrattr(a,_REVERSE) +#define start_reverse() setattr(_REVERSE) +#define wstart_reverse(a) wsetattr(a, _REVERSE) +#define wstop_underline(a) wclrattr(a, _UNDERLINE) +#define stop_reverse() clrattr(_REVERSE) +#define wstop_reverse(a) wclrattr(a, _REVERSE) -#else /* NOT VMS: */ +#else /* Not VMS: */ +/* + * For Unix FANCY_FANCY curses we interpose + * our own functions to add or subtract the + * A_foo attributes. - FM + */ #if USE_COLOR_TABLE -extern void lynx_add_wattr PARAMS((WINDOW *, int)); -extern void lynx_sub_wattr PARAMS((WINDOW *, int)); -extern void lynx_set_color PARAMS((int)); -extern void lynx_standout PARAMS((int)); +extern void LYaddWAttr PARAMS((WINDOW *win, int a)); +extern void LYaddAttr PARAMS((int a)); +extern void LYsubWAttr PARAMS((WINDOW *win, int a)); +extern void LYsubAttr PARAMS((int a)); +extern void LYaddWAttr PARAMS((WINDOW *win, int a)); +extern void LYsubWAttr PARAMS((WINDOW *win, int a)); +extern void lynx_set_color PARAMS((int a)); +extern void lynx_standout PARAMS((int a)); extern int lynx_chg_color PARAMS((int, int, int)); #undef standout -#define standout() lynx_standout(TRUE) +#define standout() lynx_standout(TRUE) #undef standend -#define standend() lynx_standout(FALSE) +#define standend() lynx_standout(FALSE) #else -#define lynx_add_attr attrset -#define lynx_add_wattr wattrset -#define lynx_sub_attr attroff -#define lynx_sub_wattr wattroff +#define LYaddAttr attrset +#define LYaddWAttr wattrset +#define LYsubAttr attroff +#define LYsubWAttr wattroff #endif #ifdef UNDERLINE_LINKS -#define start_bold() lynx_add_attr(A_UNDERLINE) -#define stop_bold() lynx_sub_attr(A_UNDERLINE) -#define start_underline() lynx_add_attr(A_BOLD) -#define stop_underline() lynx_sub_attr(A_BOLD) +#define start_bold() LYaddAttr(A_UNDERLINE) +#define stop_bold() LYsubAttr(A_UNDERLINE) +#define start_underline() LYaddAttr(A_BOLD) +#define stop_underline() LYsubAttr(A_BOLD) #else /* not UNDERLINE_LINKS: */ -#define start_bold() lynx_add_attr(A_BOLD) -#define stop_bold() lynx_sub_attr(A_BOLD) -#define start_underline() lynx_add_attr(A_UNDERLINE) -#define stop_underline() lynx_sub_attr(A_UNDERLINE) +#define start_bold() LYaddAttr(A_BOLD) +#define stop_bold() LYsubAttr(A_BOLD) +#define start_underline() LYaddAttr(A_UNDERLINE) +#define stop_underline() LYsubAttr(A_UNDERLINE) #endif /* UNDERLINE_LINKS */ #if defined(SNAKE) && defined(HP_TERMINAL) -#define start_reverse() lynx_add_wattr(stdscr,A_DIM) -#define wstart_reverse(a) lynx_add_wattr(a,A_DIM) -#define stop_reverse() lynx_sub_wattr(stdscr,A_DIM) -#define wstop_reverse(a) lynx_sub_wattr(a,A_DIM) +#define start_reverse() LYaddWAttr(stdscr, A_DIM) +#define wstart_reverse(a) LYaddWAttr(a, A_DIM) +#define stop_reverse() LYsubWAttr(stdscr, A_DIM) +#define wstop_reverse(a) LYsubWAttr(a, A_DIM) #else -#define start_reverse() lynx_add_attr(A_REVERSE) -#define wstart_reverse(a) lynx_add_wattr(a,A_REVERSE) -#define stop_reverse() lynx_sub_attr(A_REVERSE) -#define wstop_reverse(a) lynx_sub_wattr(a,A_REVERSE) +#define start_reverse() LYaddAttr(A_REVERSE) +#define wstart_reverse(a) LYaddWAttr(a, A_REVERSE) +#define stop_reverse() LYsubAttr(A_REVERSE) +#define wstop_reverse(a) LYsubWAttr(a, A_REVERSE) #endif /* SNAKE && HP_TERMINAL */ #endif /* VMS */ #else /* Not FANCY_CURSES: */ -#define start_bold() standout() -#define start_underline() /* nothing */ -#define start_reverse() standout() -#define wstart_reverse(a) wstandout(a) -#define stop_bold() standend() -#define stop_underline() /* nothing */ -#define stop_reverse() standend() -#define wstop_reverse(a) wstandend(a) +/* + * We only have [w]standout() and [w]standin(), + * so we'll use them synonymously for bold and + * reverse, and ignore underline. - FM + */ +#define start_bold() standout() +#define start_underline() 1 /* nothing */ +#define start_reverse() standout() +#define wstart_reverse(a) wstandout(a) +#define stop_bold() standend() +#define stop_underline() 1 /* nothing */ +#define stop_reverse() standend() +#define wstop_reverse(a) wstandend(a) #endif /* FANCY_CURSES */ #endif /* USE_SLANG */ +#ifdef USE_SLANG +#define LYGetYX(y, x) y = SLsmg_get_row(), x = SLsmg_get_column() +#else +#ifdef getyx +#define LYGetYX(y, x) getyx(stdscr, y, x) +#else +#define LYGetYX(y, x) y = stdscr->_cury, x = stdscr->_curx +#endif /* getyx */ +#endif /* USE_SLANG */ + extern void lynx_enable_mouse PARAMS((int)); extern void lynx_start_underline_color NOPARAMS; extern void lynx_stop_underline_color NOPARAMS; @@ -284,8 +317,8 @@ extern void lynx_start_bold_color NOPARAMS; extern void lynx_stop_bold_color NOPARAMS; extern void lynx_start_title_color NOPARAMS; extern void lynx_stop_title_color NOPARAMS; -extern void lynx_start_link_color PARAMS((int)); -extern void lynx_stop_link_color PARAMS((int)); +extern void lynx_start_link_color PARAMS((int flag, int pending)); +extern void lynx_stop_link_color PARAMS((int flag, int pending)); extern void lynx_stop_target_color NOPARAMS; extern void lynx_start_target_color NOPARAMS; extern void lynx_start_status_color NOPARAMS; @@ -298,5 +331,4 @@ extern void lynx_start_radio_color NOPARAMS; extern void lynx_stop_radio_color NOPARAMS; extern void lynx_stop_all_colors NOPARAMS; - #endif /* LYCURSES_H */ diff --git a/src/LYDownload.c b/src/LYDownload.c index 32a3bf00..53758e9a 100644 --- a/src/LYDownload.c +++ b/src/LYDownload.c @@ -27,13 +27,11 @@ /* * LYDownload takes a URL and downloads it using a user selected * download program - */ - -/* it parses an incoming link that looks like + * + * It parses an incoming link that looks like * * LYNXDOWNLOAD://Method=<#>/File=<STRING>/SugFile=<STRING> */ - #ifdef VMS #define COPY_COMMAND "copy/nolog/noconf %s %s" PUBLIC BOOLEAN LYDidRename = FALSE; @@ -41,14 +39,15 @@ PUBLIC BOOLEAN LYDidRename = FALSE; PRIVATE char LYValidDownloadFile[256] = "\0"; -PUBLIC void LYDownload ARGS1(char *,line) +PUBLIC void LYDownload ARGS1( + char *, line) { - char *Line = NULL, *method, *file, *sug_file = NULL; + char *Line = NULL, *method, *file, *theFile, *sug_file = NULL; int method_number; int count; - char buffer[256]; - char command[256]; - char *cp; + char buffer[512]; + char command[512]; + char *cp, *cp1; lynx_html_item_type *download_command = 0; int c, len; FILE *fp; @@ -68,7 +67,7 @@ PUBLIC void LYDownload ARGS1(char *,line) * the download options menu. - FM */ if (LYValidDownloadFile[0] == '\0') { - goto failed; + goto failed; } /* @@ -77,18 +76,25 @@ PUBLIC void LYDownload ARGS1(char *,line) */ StrAllocCopy(Line, line); - /* parse out the sug_file, Method and the File */ + /* + * Parse out the sug_file, Method and the File. + */ if ((sug_file = (char *)strstr(Line, "SugFile=")) != NULL) { *(sug_file-1) = '\0'; - /* go past "SugFile=" */ + /* + * Go past "SugFile=". + */ sug_file += 8; } if ((file = (char *)strstr(Line, "File=")) == NULL) goto failed; *(file-1) = '\0'; - /* go past "File=" */ + /* + * Go past "File=". + */ file += 5; + /* * Make sure that the file string is the one from * the last displayed download options menu. - FM @@ -97,7 +103,6 @@ PUBLIC void LYDownload ARGS1(char *,line) goto failed; } - #ifdef DIRED_SUPPORT if (!strncmp(file, "file://localhost", 16)) file += 16; @@ -108,45 +113,50 @@ PUBLIC void LYDownload ARGS1(char *,line) if ((method = (char *)strstr(Line, "Method=")) == NULL) goto failed; - /* go past "Method=" */ + /* + * Go past "Method=". + */ method += 7; method_number = atoi(method); - - /* set up the sug_filenames recall buffer */ + /* + * Set up the sug_filenames recall buffer. + */ FnameTotal = (sug_filenames ? HTList_count(sug_filenames) : 0); recall = ((FnameTotal >= 1) ? RECALL : NORECALL); FnameNum = FnameTotal; - if (method_number < 0) { - /* write to local file */ + /* + * Write to local file. + */ _statusline(FILENAME_PROMPT); -retry: +retry: if (sug_file) - strcpy(buffer, sug_file); + LYstrncpy(buffer, sug_file, ((sizeof(buffer)/2) - 1)); else *buffer = '\0'; check_recall: - if ((ch = LYgetstr(buffer, VISIBLE, sizeof(buffer), recall)) < 0 || + if ((ch = LYgetstr(buffer, + VISIBLE, (sizeof(buffer)/2), recall)) < 0 || *buffer == '\0' || ch == UPARROW || ch == DNARROW) { if (recall && ch == UPARROW) { - if (FirstRecall) { + if (FirstRecall) { FirstRecall = FALSE; /* - * Use the last Fname in the list. - FM + * Use the last Fname in the list. - FM */ FnameNum = 0; } else { /* - * Go back to the previous Fname in the list. - FM + * Go back to the previous Fname in the list. - FM */ FnameNum++; } if (FnameNum >= FnameTotal) { /* - * Reset the FirstRecall flag, - * and use sug_file or a blank. - FM + * Reset the FirstRecall flag, + * and use sug_file or a blank. - FM */ FirstRecall = TRUE; FnameNum = FnameTotal; @@ -218,13 +228,26 @@ check_recall: goto retry; } } + /* + * Cancel if the user entered "/dev/null" on Unix, + * or an "nl:" path (case-insensitive) on VMS. - FM + */ +#ifdef VMS + if (!strncasecomp(buffer, "nl:", 3) || + !strncasecomp(buffer, "/nl/", 4)) +#else + if (!strcmp(buffer, "/dev/null")) +#endif /* VMS */ + { + goto cancelled; + } if ((cp = strchr(buffer, '~'))) { *(cp++) = '\0'; strcpy(command, buffer); if ((len = strlen(command)) > 0 && command[len-1] == '/') command[len-1] = '\0'; #ifdef DOSPATH - strcat(command, HTDOS_wwwName((char *)Home_Dir())); + strcat(command, HTDOS_wwwName((char *)Home_Dir())); #else #ifdef VMS strcat(command, HTVMS_wwwName((char *)Home_Dir())); @@ -253,16 +276,18 @@ check_recall: else cp = NULL; if (cp) { - sprintf(command,"%s/%s", cp, buffer); + sprintf(command, "%s/%s", cp, buffer); #ifdef DOSPATH - strcpy(buffer, HTDOS_name(command)); + strcpy(buffer, HTDOS_name(command)); #else strcpy(buffer, command); #endif } #endif /* VMS */ - /* see if it already exists */ + /* + * See if it already exists. + */ if ((fp = fopen(buffer, "r")) != NULL) { fclose(fp); @@ -294,7 +319,9 @@ check_recall: } } - /* see if we can write to it */ + /* + * See if we can write to it. + */ if ((fp = fopen(buffer, "w")) != NULL) { fclose(fp); remove(buffer); @@ -314,15 +341,23 @@ check_recall: * Try rename() first. - FM */ if (TRACE) - fprintf(stderr, "command: rename(%s,%s)\n", file, buffer); + fprintf(stderr, "command: rename(%s, %s)\n", file, buffer); if (rename(file, buffer)) { /* * Failed. Use spawned COPY_COMMAND. - FM */ + if (TRACE) + fprintf(stderr, " FAILED!\n"); sprintf(command, COPY_COMMAND, file, buffer); if (TRACE) - fprintf(stderr, "FAILED!\ncommand: %s\n", command); + fprintf(stderr, "command: %s\n", command); + fflush(stderr); + fflush(stdout); + stop_curses(); system(command); + fflush(stdout); + fflush(stderr); + start_curses(); } else { /* * We don't have the temporary file (it was renamed to @@ -335,20 +370,29 @@ check_recall: /* * Prevent spoofing of the shell. */ - cp = quote_pathname(buffer); - sprintf(command,"%s %s %s", COPY_PATH, file, cp); + cp = quote_pathname(file); + cp1 = quote_pathname(buffer); + sprintf(command, "%s %s %s", COPY_PATH, cp, cp1); FREE(cp); + FREE(cp1); if (TRACE) - fprintf(stderr,"command: %s\n",command); + fprintf(stderr, "command: %s\n", command); + fflush(stderr); + fflush(stdout); + stop_curses(); system(command); + fflush(stdout); + fflush(stderr); + start_curses(); #endif /* VMS */ + chmod(buffer, 0600); } else { /* * Use configured download commands. */ buffer[0] = '\0'; - for (count = 0, download_command = downloaders; + for (count = 0, download_command=downloaders; count < method_number; count++, download_command = download_command->next) ; /* null body */ @@ -460,6 +504,19 @@ check_recall: goto again; } } + /* + * Cancel if the user entered "/dev/null" on Unix, + * or an "nl:" path (case-insensitive) on VMS. - FM + */ +#ifdef VMS + if (!strncasecomp(buffer, "nl:", 3) || + !strncasecomp(buffer, "/nl/", 4)) +#else + if (!strcmp(buffer, "/dev/null")) +#endif /* VMS */ + { + goto cancelled; + } SecondS = TRUE; } @@ -471,14 +528,18 @@ check_recall: * putting both names on the command line. */ #ifdef VMS - sprintf(command, download_command->command, file, buffer); + sprintf(command, download_command->command, file, buffer, + "", "", "", "", "", "", "", "", "", ""); #else /* Unix: */ /* * Prevent spoofing of the shell. */ - cp = quote_pathname(buffer); - sprintf(command, download_command->command, file, cp); + cp = quote_pathname(file); + cp1 = quote_pathname(buffer); + sprintf(command, download_command->command, cp, cp1, + "", "", "", "", "", "", "", "", "", ""); FREE(cp); + FREE(cp1); #endif /* VMS */ } else { @@ -487,11 +548,14 @@ check_recall: goto failed; } - stop_curses(); if (TRACE) fprintf(stderr, "command: %s\n", command); + stop_curses(); + fflush(stderr); + fflush(stdout); system(command); - fflush(stdout); + fflush(stderr); + fflush(stdout); start_curses(); /* don't remove(file); */ } @@ -525,18 +589,17 @@ cancelled: sleep(InfoSecs); FREE(Line); return; - } /* - * LYdownload_options writes out the current download choices to a file - * so that the user can select printers in the same way that - * they select all other links - * download links look like + * LYdownload_options writes out the current download choices to + * a file so that the user can select printers in the same way that + * they select all other links. Download links look like: * LYNXDOWNLOAD://Method=<#>/File=<STRING>/SugFile=<STRING> */ - -PUBLIC int LYdownload_options ARGS2(char **,newfile, char *,data_file) +PUBLIC int LYdownload_options ARGS2( + char **, newfile, + char *, data_file) { static char tempfile[256]; static BOOLEAN first = TRUE; @@ -560,20 +623,21 @@ PUBLIC int LYdownload_options ARGS2(char **,newfile, char *,data_file) #endif /* VMS */ } - - /* get a suggested filename */ + /* + * Get a suggested filename. + */ StrAllocCopy(sug_filename, *newfile); change_sug_filename(sug_filename); - if ((fp0 = fopen(tempfile,"w")) == NULL) { + if ((fp0 = fopen(tempfile, "w")) == NULL) { HTAlert(CANNOT_OPEN_TEMP); return(-1); } chmod(tempfile, 0600); LYstrncpy(LYValidDownloadFile, - data_file, - (sizeof(LYValidDownloadFile) - 1)); + data_file, + (sizeof(LYValidDownloadFile) - 1)); StrAllocCopy(*newfile, download_filename); LYforce_no_cache = TRUE; /* don't cache this doc */ @@ -589,7 +653,9 @@ PUBLIC int LYdownload_options ARGS2(char **,newfile, char *,data_file) if(!no_disk_save && !child_lynx) #ifdef DIRED_SUPPORT - /* disable save to disk option for local files */ + /* + * Disable save to disk option for local files. + */ if (!lynx_edit_mode) #endif /* DIRED_SUPPORT */ fprintf(fp0," \ @@ -601,31 +667,29 @@ PUBLIC int LYdownload_options ARGS2(char **,newfile, char *,data_file) else fprintf(fp0," Save to disk disabled.\n"); - if(downloaders != NULL) { - - for(count = 0, cur_download = downloaders; cur_download != NULL; - cur_download = cur_download->next, count++) { - - if(!no_download || cur_download->always_enabled) { + if (downloaders != NULL) { + for (count = 0, cur_download = downloaders; cur_download != NULL; + cur_download = cur_download->next, count++) { + if (!no_download || cur_download->always_enabled) { fprintf(fp0," \ <a href=\"LYNXDOWNLOAD://Method=%d/File=%s/SugFile=%s\">", - count,data_file,sug_filename); - + count,data_file, sug_filename); fprintf(fp0, (cur_download->name ? cur_download->name : "No Name Given")); fprintf(fp0,"</a>\n"); } } } else { - fprintf(fp0, "\n \ -No other download methods have been defined yet. You may define\n \ + fprintf(fp0, "\n\ +No other download methods have been defined yet. You may define\n\ an unlimited number of download methods using the lynx.cfg file.\n"); - } fprintf(fp0, "</pre>\n</body>\n"); fclose(fp0); - /* free off temp copy */ + /* + * Free off temp copy. + */ FREE(sug_filename); return(0); diff --git a/src/LYEdit.c b/src/LYEdit.c index 98940c4e..38346c90 100644 --- a/src/LYEdit.c +++ b/src/LYEdit.c @@ -23,46 +23,50 @@ #define FREE(x) if (x) {free(x); x = NULL;} /* - * in edit mode invoke either emacs, vi, pico, jove, jed or the default - * editor to display and edit the current file - * emacs, vi, pico, jove and jed will open the file to the same line that - * the screen cursor is on when editing is invoked - * returns FALSE if file uneditable + * In edit mode invoke either emacs, vi, pico, jove, jed sedt or the + * default editor to display and edit the current file. + * For emacs, vi, pico, jove and jed, Lynx will open the file to the + * same line that the screen cursor is on when editing is invoked. + * Returns FALSE if file is uneditable. */ - -PUBLIC int edit_current_file ARGS3(char *,newfile, int,cur, int,lineno) +PUBLIC int edit_current_file ARGS3( + char *, newfile, + int, cur, + int, lineno) { + char command[512]; + char *filename = NULL; + char *colon, *number_sign; + FILE *fp; - char command[512]; - char *filename = NULL; - char *colon, *number_sign; - FILE *fp; + /* + * If its a remote file then we can't edit it. + */ + if (!LYisLocalFile(newfile)) { + _statusline(CANNOT_EDIT_REMOTE_FILES); + sleep(MessageSecs); + return FALSE; + } - /* - * If its a remote file then we can't edit it. - */ - if(!LYisLocalFile(newfile)) { - _statusline(CANNOT_EDIT_REMOTE_FILES); - sleep(MessageSecs); - return FALSE; - } + /* + * If there's a fragment, trim it. - FM + */ + number_sign = strchr(newfile, '#'); + if (number_sign) + *number_sign = '\0'; - number_sign = strchr(newfile,'#'); - if(number_sign) - *number_sign = '\0'; - - /* - * On Unix, first try to open it as a completely referenced file, - * then via the path alone. - * - * On VMS, only try the path. - */ + /* + * On Unix, first try to open it as a completely referenced file, + * then via the path alone. + * + * On VMS, only try the path. + */ #if !defined (VMS) && !defined (DOSPATH) - colon = strchr(newfile,':'); - StrAllocCopy(filename, colon+1); - HTUnEscape(filename); - if((fp = fopen(filename,"r")) == NULL) { - FREE(filename); + colon = strchr(newfile, ':'); + StrAllocCopy(filename, (colon + 1)); + HTUnEscape(filename); + if ((fp = fopen(filename, "r")) == NULL) { + FREE(filename); #endif /* !VMS */ filename = HTParse(newfile,"",PARSE_PATH+PARSE_PUNCTUATION); HTUnEscape(filename); @@ -73,20 +77,20 @@ PUBLIC int edit_current_file ARGS3(char *,newfile, int,cur, int,lineno) if ((fp = fopen(HTDOS_name(filename),"r")) == NULL) { #else #ifdef VMS - if ((fp = fopen(HTVMS_name("",filename),"r")) == NULL) { + if ((fp = fopen(HTVMS_name("", filename), "r")) == NULL) { #else - if ((fp = fopen(filename,"r")) == NULL) { + if ((fp = fopen(filename, "r")) == NULL) { #endif /* VMS */ #endif /* DOSPATH */ - HTAlert(COULD_NOT_ACCESS_FILE); - FREE(filename); - goto failure; - } -#if !defined (VMS) && !defined (DOSPATH) + HTAlert(COULD_NOT_ACCESS_FILE); + FREE(filename); + goto failure; } +#if !defined (VMS) && !defined (DOSPATH) + } #endif /* !VMS */ - fclose(fp); - + fclose(fp); + #if defined(VMS) || defined(CANT_EDIT_UNWRITABLE_FILES) /* * Don't allow editing if user lacks append access. @@ -95,54 +99,87 @@ PUBLIC int edit_current_file ARGS3(char *,newfile, int,cur, int,lineno) if ((fp = fopen(HTDOS_name("",filename),"a")) == NULL) { #else #ifdef VMS - if ((fp = fopen(HTVMS_name("",filename),"a")) == NULL) { + if ((fp = fopen(HTVMS_name("", filename), "a")) == NULL) { #else - if ((fp = fopen(filename,"a")) == NULL) { + if ((fp = fopen(filename, "a")) == NULL) { #endif /* VMS */ #endif /* DOSPATH */ - _statusline(NOAUTH_TO_EDIT_FILE); - sleep(MessageSecs); - goto failure; - } - fclose(fp); + _statusline(NOAUTH_TO_EDIT_FILE); + sleep(MessageSecs); + goto failure; + } + fclose(fp); #endif /* VMS || CANT_EDIT_UNWRITABLE_FILES */ + /* + * Make sure cur is at least zero. - FM + */ + if (cur < 0) { + cur = 0; + } + + /* + * Set up the command for the editor. - FM + */ #ifdef VMS - sprintf(command,"%s %s",editor, HTVMS_name("",filename)); + if ((strstr(editor, "sedt") || strstr(editor, "SEDT")) && + ((lineno - 1) + (nlinks ? links[cur].ly : 0)) > 0) { + sprintf(command, "%s %s -%d", + editor, + HTVMS_name("", filename), + ((lineno - 1) + (nlinks ? links[cur].ly : 0))); + } else { + sprintf(command, "%s %s", editor, HTVMS_name("", filename)); + } #else - if (strstr(editor,"emacs") || strstr(editor,"vi") || - strstr(editor, "pico") || strstr(editor,"jove") || - strstr(editor, "jed")) - sprintf(command,"%s +%d \"%s\"",editor, lineno+links[cur].ly, + if (strstr(editor, "emacs") || strstr(editor, "vi") || + strstr(editor, "pico") || strstr(editor, "jove") || + strstr(editor, "jed")) + sprintf(command, "%s +%d \"%s\"", + editor, + (lineno + (nlinks ? links[cur].ly : 0)), #ifdef DOSPATH - HTDOS_name(filename)); + HTDOS_name(filename)); #else filename); #endif /* DOSPATH */ - else - sprintf(command,"%s \"%s\"",editor, + else + sprintf(command, "%s \"%s\"", editor, #ifdef DOSPATH HTDOS_name(filename)); #else filename); #endif /* DOSPATH */ #endif /* VMS */ - if (TRACE) { - fprintf(stderr, "LYEdit: %s\n",command); - sleep(MessageSecs); - } - FREE(filename); + if (TRACE) { + fprintf(stderr, "LYEdit: %s\n", command); + sleep(MessageSecs); + } + FREE(filename); - stop_curses(); - system(command); - start_curses(); + /* + * Invoke the editor. - FM + */ + fflush(stderr); + fflush(stdout); + stop_curses(); + system(command); + fflush(stdout); + fflush(stderr); + start_curses(); - if(number_sign) - *number_sign = '#'; - return TRUE; + /* + * Restore the fragment if there was one. - FM + */ + if (number_sign) + *number_sign = '#'; + return TRUE; failure: - if(number_sign) - *number_sign = '#'; - return FALSE; + /* + * Restore the fragment if there was one. - FM + */ + if (number_sign) + *number_sign = '#'; + return FALSE; } diff --git a/src/LYExtern.c b/src/LYExtern.c index 7ec3f5d8..cbe7ac3d 100644 --- a/src/LYExtern.c +++ b/src/LYExtern.c @@ -15,7 +15,6 @@ See lynx.cfg for other info. */ -#ifdef USE_EXTERNALS #include "tcp.h" #include "LYGlobalDefs.h" #include "LYUtils.h" @@ -23,6 +22,7 @@ #include "LYLeaks.h" +#ifdef USE_EXTERNALS #define FREE(x) if (x) {free(x); x = NULL;} void run_external(char * c) diff --git a/src/LYExtern.h b/src/LYExtern.h index be9d1562..09983b47 100644 --- a/src/LYExtern.h +++ b/src/LYExtern.h @@ -1,10 +1,10 @@ -#ifndef EXTERNALS_H +#ifndef EXTERNALS_H #define EXTERNALS_H #ifndef LYSTRUCTS_H -#include "LYStructs.h" -#endif /* LYSTRUCTS_H */ +#include "LYStructs.h" +#endif /* LYSTRUCTS_H */ -void run_external(char * c); +void run_external PARAMS((char * c)); -#endif /* EXTERNALS_H */ +#endif /* EXTERNALS_H */ diff --git a/src/LYForms.c b/src/LYForms.c index 281612bc..83f41bf0 100644 --- a/src/LYForms.c +++ b/src/LYForms.c @@ -6,7 +6,7 @@ #include "LYCurses.h" #include "GridText.h" #include "LYUtils.h" -#include "LYStructs.h" /* includes HTForms.h */ +#include "LYStructs.h" /* includes HTForms.h */ #include "LYStrings.h" #include "LYGlobalDefs.h" #include "LYKeymap.h" @@ -33,18 +33,29 @@ extern HTCJKlang HTCJK; -PRIVATE int form_getstr PARAMS((struct link * form_link)); -PRIVATE int popup_options PARAMS((int cur_selection, OptionType *list, - int ly, int lx, int width, - int i_length, int disabled)); - -PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, - document *,newdoc, BOOLEAN *,refresh_screen, - char *,link_name, char *,link_value) +PRIVATE int form_getstr PARAMS(( + struct link * form_link)); +PRIVATE int popup_options PARAMS(( + int cur_selection, + OptionType * list, + int ly, + int lx, + int width, + int i_length, + int disabled)); + +PUBLIC int change_form_link ARGS6( + struct link *, form_link, + int, mode, + document *, newdoc, + BOOLEAN *, refresh_screen, + char *, link_name, + char *, link_value) { extern BOOL reloading; FormInfo *form = form_link->form; - int c=DO_NOTHING; + int c = DO_NOTHING; + int OrigNumValue; /* * If there is no form to perform action on, don't do anything. @@ -53,13 +64,15 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, return(c); } - /* move to the link position */ + /* + * Move to the link position. + */ move(form_link->ly, form_link->lx); switch(form->type) { case F_CHECKBOX_TYPE: if (form->disabled == YES) - break; + break; if (form->num_value) { form_link->hightext = unchecked_box; form->num_value = 0; @@ -71,66 +84,99 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, case F_OPTION_LIST_TYPE: if (!form->select_list) { - HTAlert(BAD_HTML_NO_POPUP); + HTAlert(BAD_HTML_NO_POPUP); c = DO_NOTHING; break; } if (form->disabled == YES) { - int dummy; + int dummy; dummy = popup_options(form->num_value, form->select_list, form_link->ly, form_link->lx, form->size, form->size_l, form->disabled); - c = 12; /* CTRL-L for repaint */ - break; +#if defined(FANCY_CURSES) || defined(USE_SLANG) + if (!enable_scrollback) +#if defined(VMS) && !defined(USE_SLANG) + c = DO_NOTHING; +#else + c = 23; /* CTRL-W for repaint */ +#endif /* VMS && !USE_SLANG */ + else +#endif /* FANCY_CURSES || USE_SLANG */ + c = 12; /* CTRL-L for repaint */ + break; } + OrigNumValue = form->num_value; form->num_value = popup_options(form->num_value, form->select_list, form_link->ly, form_link->lx, form->size, form->size_l, form->disabled); { - OptionType * opt_ptr=form->select_list; + OptionType * opt_ptr = form->select_list; int i; - for (i = 0; i < form->num_value; i++, opt_ptr = opt_ptr->next) + for (i = 0; i < form->num_value; i++, opt_ptr = opt_ptr->next) ; /* null body */ - form->value = opt_ptr->name; /* set the name */ - form->cp_submit_value = opt_ptr->cp_submit_value; /* set the value */ + /* + * Set the name. + */ + form->value = opt_ptr->name; + /* + * Set the value. + */ + form->cp_submit_value = opt_ptr->cp_submit_value; } - c = 12; /* CTRL-L for repaint */ +#if defined(FANCY_CURSES) || defined(USE_SLANG) + if (!enable_scrollback && form->num_value == OrigNumValue) +#if defined(VMS) && !defined(USE_SLANG) + c = DO_NOTHING; +#else + c = 23; /* CTRL-W for repaint */ +#endif /* VMS && !USE_SLANG */ + else +#endif /* FANCY_CURSES || USE_SLANG */ + c = 12; /* CTRL-L for repaint */ break; case F_RADIO_TYPE: if (form->disabled == YES) - break; - /* radio buttons must have one and - * only one down at a time! + break; + /* + * Radio buttons must have one and + * only one down at a time! */ if (form->num_value) { _statusline(NEED_CHECKED_RADIO_BUTTON); sleep(MessageSecs); - } else { + } else { int i; - /* run though list of the links on the screen and - * unselect any that are selected. :) + /* + * Run though list of the links on the screen and + * unselect any that are selected. :) */ lynx_start_radio_color (); - for (i = 0; i < nlinks; i++) - if (links[i].type == WWW_FORM_LINK_TYPE && - links[i].form->type == F_RADIO_TYPE && - links[i].form->number == form->number && - /* if it has the same name and its on */ - !strcmp(links[i].form->name, form->name) && - links[i].form->num_value ) - { + for (i = 0; i < nlinks; i++) { + if (links[i].type == WWW_FORM_LINK_TYPE && + links[i].form->type == F_RADIO_TYPE && + links[i].form->number == form->number && + /* + * If it has the same name and its on... + */ + !strcmp(links[i].form->name, form->name) && + links[i].form->num_value) { move(links[i].ly, links[i].lx); addstr(unchecked_radio); links[i].hightext = unchecked_radio; } + } lynx_stop_radio_color (); - /* will unselect other button and select this one */ + /* + * Will unselect other button and select this one. + */ HText_activateRadioButton(form); - /* now highlight this one */ + /* + * Now highlight this one. + */ form_link->hightext = checked_radio; } break; @@ -139,28 +185,28 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, case F_TEXTAREA_TYPE: case F_PASSWORD_TYPE: c = form_getstr(form_link); - if (form->type == F_PASSWORD_TYPE) - form_link->hightext = STARS(strlen(form->value)); + if (form->type == F_PASSWORD_TYPE) + form_link->hightext = STARS(strlen(form->value)); else - form_link->hightext = form->value; + form_link->hightext = form->value; break; case F_RESET_TYPE: if (form->disabled == YES) - break; + break; HText_ResetForm(form); - *refresh_screen = TRUE; + *refresh_screen = TRUE; break; - + case F_TEXT_SUBMIT_TYPE: c = form_getstr(form_link); if (form->disabled == YES && - (c == '\r' || c == '\n')) { - c = '\t'; + (c == '\r' || c == '\n')) { + c = '\t'; break; } if (c == '\r' || c == '\n') { - form_link->hightext = form->value; + form_link->hightext = form->value; if (!form->submit_action || *form->submit_action == '\0') { _statusline(NO_FORM_ACTION); sleep(MessageSecs); @@ -172,41 +218,43 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, break; } else { if (form->no_cache && - form->submit_method != URL_MAIL_METHOD) { - LYforce_no_cache = TRUE; + form->submit_method != URL_MAIL_METHOD) { + LYforce_no_cache = TRUE; reloading = TRUE; } - HText_SubmitForm(form, newdoc, link_name, form->value); + HText_SubmitForm(form, newdoc, link_name, form->value); } - if (form->submit_method == URL_MAIL_METHOD) + if (form->submit_method == URL_MAIL_METHOD) { *refresh_screen = TRUE; - else { - /* returns new document URL */ - newdoc->link = 0; + } else { + /* + * Returns new document URL. + */ + newdoc->link = 0; newdoc->internal_link = FALSE; } c = DO_NOTHING; break; } else { - form_link->hightext = form->value; + form_link->hightext = form->value; } break; case F_SUBMIT_TYPE: case F_IMAGE_SUBMIT_TYPE: if (form->disabled == YES) - break; + break; if (form->no_cache && - form->submit_method != URL_MAIL_METHOD) { + form->submit_method != URL_MAIL_METHOD) { LYforce_no_cache = TRUE; reloading = TRUE; } HText_SubmitForm(form, newdoc, link_name, link_value); if (form->submit_method == URL_MAIL_METHOD) - *refresh_screen = TRUE; + *refresh_screen = TRUE; else { - /* returns new document URL */ - newdoc->link = 0; + /* returns new document URL */ + newdoc->link = 0; newdoc->internal_link = FALSE; } break; @@ -215,76 +263,116 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, return(c); -} - -#ifdef USE_SLANG -#define GetYX(y,x) y = SLsmg_get_row(), x = SLsmg_get_column() -#else -#ifdef getyx -#define GetYX(y,x) getyx(stdscr,y,x) -#else -#define GetYX(y,x) y = stdscr->_cury, x = stdscr->_curx -#endif /* getyx */ -#endif /* USE_SLANG */ - -PRIVATE int form_getstr ARGS1(struct link *, form_link) +} +PRIVATE int form_getstr ARGS1( + struct link *, form_link) { FormInfo *form = form_link->form; + char *value = form->value; int ch; int far_col; - int max_length = (form->maxlength ? form->maxlength : 1023); + int max_length; int startcol, startline; BOOL HaveMaxlength = FALSE; + int action; #ifdef VMS - extern BOOLEAN HadVMSInterrupt;/* Flag from cleanup_sig() AST */ + extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */ #endif EditFieldData MyEdit; - BOOLEAN Edited = FALSE; /* Value might be updated? */ - - /* get the initial position of the cursor */ - GetYX(startline, startcol); + BOOLEAN Edited = FALSE; /* Value might be updated? */ - if (startcol + form->size > LYcols-1) - far_col = LYcols-1; + /* + * Get the initial position of the cursor. + */ + LYGetYX(startline, startcol); + if ((startcol + form->size) > (LYcols - 1)) + far_col = (LYcols - 1); else - far_col = startcol + form->size; + far_col = (startcol + form->size); - /* Print panned line */ + /* + * Make sure the form field value does not exceed our buffer. - FM + */ + max_length = ((form->maxlength > 0 && + form->maxlength < sizeof(MyEdit.buffer)) ? + form->maxlength : + (sizeof(MyEdit.buffer) - 1)); + if (strlen(form->value) > max_length) { + /* + * We can't fit the entire value into the editing buffer, + * so enter as much of the tail as fits. - FM + */ + value += (strlen(form->value) - max_length); + if (!form->disabled && + !(form->submit_method == URL_MAIL_METHOD && no_mail)) { + /* + * If we can edit it, report that we are using the tail. - FM + */ + _statusline(FORM_VALUE_TOO_LONG); + sleep(MessageSecs); + switch(form->type) { + case F_PASSWORD_TYPE: + statusline(FORM_LINK_PASSWORD_MESSAGE); + break; + case F_TEXT_SUBMIT_TYPE: + if (form->submit_method == URL_MAIL_METHOD) { + statusline(FORM_LINK_TEXT_SUBMIT_MAILTO_MSG); + } else if (form->no_cache) { + statusline(FORM_LINK_TEXT_RESUBMIT_MESSAGE); + } else { + statusline(FORM_LINK_TEXT_SUBMIT_MESSAGE); + } + break; + case F_TEXT_TYPE: + case F_TEXTAREA_TYPE: + statusline(FORM_LINK_TEXT_MESSAGE); + break; + default: + break; + } + move(startline, startcol); + } + } - LYSetupEdit(&MyEdit, form->value, max_length, far_col-startcol); - MyEdit.pad='_'; + /* + * Print panned line + */ + LYSetupEdit(&MyEdit, value, max_length, (far_col - startcol)); + MyEdit.pad = '_'; MyEdit.hidden = (form->type == F_PASSWORD_TYPE); LYRefreshEdit(&MyEdit); - /* And go for it.. */ - + /* + * And go for it! + */ for (;;) { again: - ch = LYgetch(); + ch = LYgetch(); #ifdef VMS - if (HadVMSInterrupt) { + if (HadVMSInterrupt) { HadVMSInterrupt = FALSE; ch = 7; } #endif /* VMS */ /* - * Filter out global navigation keys that should not be passed - * to line editor, and LYK_REFRESH. + * Filter out global navigation keys that should not be passed + * to line editor, and LYK_REFRESH. */ - if (EditBinding(ch) == LYE_ENTER) + action = EditBinding(ch); + if (action == LYE_ENTER) break; - if (EditBinding(ch) == LYE_AIX && HTCJK == NOCJK) + if (action == LYE_AIX && HTCJK == NOCJK) break; - if (EditBinding(ch) == LYE_TAB) - { + if (action == LYE_TAB) { ch = (int)('\t'); break; - } - if (EditBinding(ch) == LYE_ABORT) + } + if (action == LYE_ABORT) { return(DO_NOTHING); + } if (keymap[ch + 1] == LYK_REFRESH) goto breakfor; switch (ch) { @@ -298,31 +386,24 @@ again: case FIND_KEY: case SELECT_KEY: #endif /* NOTDEFINED */ - goto breakfor; + goto breakfor; /* - * Left arrrow in column 0 deserves special treatment here, - * else you can get trapped in a form without submit button! + * Left arrrow in column 0 deserves special treatment here, + * else you can get trapped in a form without submit button! */ case LTARROW: - if (MyEdit.pos==0) { - int c='Y'; /* Go back immediately if no changes */ - if (strcmp(MyEdit.buffer, form->value)) { - _statusline(PREV_DOC_QUERY); - c=LYgetch(); + if (MyEdit.pos == 0) { + int c = 'Y'; /* Go back immediately if no changes */ + if (strcmp(MyEdit.buffer, value)) { + _statusline(PREV_DOC_QUERY); + c = LYgetch(); } if (TOUPPER(c) == 'Y') { -#ifdef NOTDEFINED - /* - * Why not just keep what we have?? - * We don't erase the other fields either?? - */ - StrAllocCopy(form->value, ""); -#endif /* NOTDEFINED */ return(ch); } else { - if (form->disabled == YES) - _statusline(ARROWS_OR_TAB_TO_MOVE); + if (form->disabled == YES) + _statusline(ARROWS_OR_TAB_TO_MOVE); else _statusline(ENTER_TEXT_ARROWS_OR_TAB); } @@ -332,9 +413,10 @@ again: default: if (form->disabled == YES) goto again; - /* Make sure the statusline uses editmode help... */ - Edited = TRUE; - LYLineEdit(&MyEdit,ch,TRUE); + /* + * Make sure the statusline uses editmode help. + */ + LYLineEdit(&MyEdit, ch, TRUE); if (MyEdit.strlen >= max_length) { HaveMaxlength = TRUE; } else if (HaveMaxlength && @@ -342,30 +424,91 @@ again: HaveMaxlength = FALSE; _statusline(ENTER_TEXT_ARROWS_OR_TAB); } + if (strcmp(value, MyEdit.buffer)) { + Edited = TRUE; + } LYRefreshEdit(&MyEdit); } } breakfor: if (Edited) { - char *p; - StrAllocCopy(form->value, MyEdit.buffer); + char *p; + + /* + * Load the new value. + */ + if (value == form->value) { + /* + * The previous value did fit in the line buffer, + * so replace it with the new value. - FM + */ + StrAllocCopy(form->value, MyEdit.buffer); + } else { + /* + * Combine the modified tail with the unmodified head. - FM + */ + form->value[(strlen(form->value) - strlen(value))] = '\0'; + StrAllocCat(form->value, MyEdit.buffer); + _statusline(FORM_TAIL_COMBINED_WITH_HEAD); + sleep(MessageSecs); + } /* - * Remove trailing spaces + * Remove trailing spaces * - * Do we really need to do that here? Trailing spaces will only - * be there if user keyed them in. Rather rude to throw away - * their hard earned spaces. Better deal with trailing spaces - * when submitting the form???? + * Do we really need to do that here? Trailing spaces will only + * be there if user keyed them in. Rather rude to throw away + * their hard earned spaces. Better deal with trailing spaces + * when submitting the form???? */ p = &(form->value[strlen(form->value)]); - while ((p != form->value) && (p[-1]==' ')) + while ((p != form->value) && (p[-1] == ' ')) p--; *p = '\0'; } return(ch); } +/* +** This function prompts for an option or page number. +** If a 'g' or 'p' suffix is included, that will be +** loaded into c. Otherwise, c is zeroed. - FM & LE +*/ +PRIVATE int get_popup_option_number ARGS1( + int *, c) +{ + char temp[120]; + + /* + * Load the c argument into the prompt buffer. + */ + temp[0] = *c; + temp[1] = '\0'; + _statusline(SELECT_OPTION_NUMBER); + + /* + * Get the number, possibly with a suffix, from the user. + */ + if (LYgetstr(temp, VISIBLE, sizeof(temp), NORECALL) < 0 || *temp == 0) { + _statusline(CANCELLED); + sleep(InfoSecs); + *c = '\0'; + return(0); + } + + /* + * If we had a 'g' or 'p' suffix, load it into c. + * Otherwise, zero c. Then return the number. + */ + if (strchr(temp, 'g') != NULL || strchr(temp, 'G') != NULL) { + *c = 'g'; + } else if (strchr(temp, 'p') != NULL || strchr(temp, 'P') != NULL) { + *c = 'p'; + } else { + *c = '\0'; + } + return(atoi(temp)); +} /* Use this rather than the 'wprintw()' function to write a blank-padded * string to the given window, since someone's asserted that printw doesn't @@ -378,7 +521,7 @@ breakfor: PRIVATE void paddstr ARGS3( WINDOW *, the_window, int, width, - char *, the_string) + char *, the_string) { width -= strlen(the_string); waddstr(the_window, the_string); @@ -411,10 +554,11 @@ PRIVATE int popup_options ARGS7( OptionType * opt_ptr = list; int window_offset = 0; int display_lines; + int npages; #ifdef VMS extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */ #endif /* VMS */ - static char prev_target[512]; /* Search string buffer */ + static char prev_target[512]; /* Search string buffer */ static char prev_target_buffer[512]; /* Next search buffer */ static BOOL first = TRUE; char *cp; @@ -424,6 +568,8 @@ PRIVATE int popup_options ARGS7( BOOLEAN FirstRecall = TRUE; OptionType * tmp_ptr; BOOLEAN ReDraw = FALSE; + int number; + char buffer[512]; /* * Initialize the search string buffer. - FM @@ -440,17 +586,17 @@ PRIVATE int popup_options ARGS7( /* * Set display_lines based on the user_mode global. */ - if (user_mode==NOVICE_MODE) + if (user_mode == NOVICE_MODE) display_lines = LYlines-4; else - display_lines = LYlines-2; + display_lines = LYlines-2; /* * Counting the number of options to be displayed. * num_options ranges 0...n */ for (; opt_ptr->next; num_options++, opt_ptr = opt_ptr->next) - ; /* null body */ + ; /* null body */ /* * Let's assume for the sake of sanity that ly is the number @@ -473,8 +619,7 @@ PRIVATE int popup_options ARGS7( */ if (!i_length) { i_length = num_options; - } - else { + } else { /* * Otherwise, it is really one number too high. */ @@ -489,18 +634,18 @@ PRIVATE int popup_options ARGS7( bottom = top + i_length + 3; /* - * Hmm... If the bottom goes beyond the number of lines available, + * Hmm... If the bottom goes beyond the number of lines available, */ if (bottom > display_lines) { - /* + /* * Position the window at the top if we have more * options than will fit in the window. */ if (i_length+3 > display_lines) { top = 0; - bottom = top + i_length+3; + bottom = top + i_length+3; if (bottom > display_lines) - bottom = display_lines + 1; + bottom = display_lines + 1; } else { /* * Try to position the window so that the selected option will @@ -522,7 +667,7 @@ PRIVATE int popup_options ARGS7( * Move the window down if it's too high. */ if (bottom < ly + 2) { - bottom = ly + 2; + bottom = ly + 2; if (bottom > display_lines + 1) bottom = display_lines + 1; top = bottom - length - 2; @@ -532,11 +677,13 @@ PRIVATE int popup_options ARGS7( * Set up the overall window, including the boxing characters ('*'), * if it all fits. Otherwise, set up the widest window possible. - FM */ -#ifndef USE_SLANG - if (!(form_window = newwin(bottom - top, width+4, top, lx - 1)) && +#ifdef USE_SLANG + SLsmg_fill_region(top, lx - 1, bottom - top, width + 4, ' '); +#else + if (!(form_window = newwin(bottom - top, width + 4, top, lx - 1)) && !(form_window = newwin(bottom - top, 0, top, 0))) { HTAlert(POPUP_FAILED); - return(orig_selection); + return(orig_selection); } scrollok(form_window, TRUE); #ifdef NCURSES @@ -548,9 +695,7 @@ PRIVATE int popup_options ARGS7( wbkgd(form_window, getbkgd(stdscr)); #endif #endif -#else - SLsmg_fill_region (top, lx - 1, bottom - top, width + 4, ' '); -#endif /* !USE_SLANG */ +#endif /* USE_SLANG */ /* * Set up the window_offset for options. @@ -558,14 +703,20 @@ PRIVATE int popup_options ARGS7( * length ranges from 0...m */ if (cur_selection >= length) { - window_offset = cur_selection - length + 1; + window_offset = cur_selection - length + 1; } + /* + * Compute the number of popup window pages. - FM + */ + npages = ((num_options + 1) > length) ? + (((num_options + 1) + (length - 1))/(length)) + : 1; /* - * OH! I LOVE GOTOs! hack hack hack - * 07-11-94 GAB - * MORE hack hack hack - * 09-05-94 FM + * OH! I LOVE GOTOs! hack hack hack + * 07-11-94 GAB + * MORE hack hack hack + * 09-05-94 FM */ redraw: opt_ptr = list; @@ -574,17 +725,19 @@ redraw: * Display the boxed options. */ for (i = 0; i <= num_options; i++, opt_ptr = opt_ptr->next) { - if (i >= window_offset && i - window_offset < length) { -#ifndef USE_SLANG - wmove(form_window,(i+1)-window_offset,2); - paddstr(form_window, width, opt_ptr->name); + if (i >= window_offset && i - window_offset < length) { +#ifdef USE_SLANG + SLsmg_gotorc(top + ((i + 1) - window_offset), (lx - 1 + 2)); + SLsmg_write_nstring(opt_ptr->name, width); #else - SLsmg_gotorc (top + (i+1)-window_offset, lx - 1 + 2); - SLsmg_write_nstring (opt_ptr->name, width); -#endif /* !USE_SLANG */ + wmove(form_window, ((i + 1) - window_offset), 2); + paddstr(form_window, width, opt_ptr->name); +#endif /* USE_SLANG */ } } -#ifndef USE_SLANG +#ifdef USE_SLANG + SLsmg_draw_box(top, (lx - 1), (bottom - top), (width + 4)); +#else #ifdef VMS VMSbox(form_window, (bottom - top), (width + 4)); #else @@ -597,9 +750,7 @@ redraw: #endif #endif /* VMS */ wrefresh(form_window); -#else - SLsmg_draw_box (top, lx - 1, bottom - top, width + 4); -#endif /* !USE_SLANG */ +#endif /* USE_SLANG */ opt_ptr = NULL; /* @@ -607,39 +758,68 @@ redraw: */ while (cmd != LYK_ACTIVATE) { - /* + /* * Unreverse cur selection. */ if (opt_ptr != NULL) { -#ifndef USE_SLANG - wmove(form_window,(i+1)-window_offset,2); - paddstr(form_window, width, opt_ptr->name); +#ifdef USE_SLANG + SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2)); + SLsmg_write_nstring(opt_ptr->name, width); #else - SLsmg_gotorc (top + (i+1)-window_offset, lx - 1 + 2); - SLsmg_write_nstring (opt_ptr->name, width); -#endif /* !USE_SLANG */ + wmove(form_window, ((i + 1) - window_offset), 2); + paddstr(form_window, width, opt_ptr->name); +#endif /* USE_SLANG */ } - opt_ptr = list; + opt_ptr = list; - for (i = 0; i < cur_selection; i++, opt_ptr = opt_ptr->next) + for (i = 0; i < cur_selection; i++, opt_ptr = opt_ptr->next) ; /* null body */ -#ifndef USE_SLANG - wstart_reverse(form_window); - wmove(form_window,(i+1)-window_offset,2); - paddstr(form_window, width, opt_ptr->name); - wstop_reverse(form_window); - wrefresh(form_window); +#ifdef USE_SLANG + SLsmg_set_color(2); + SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2)); + SLsmg_write_nstring(opt_ptr->name, width); + SLsmg_set_color(0); + /* + * If LYShowCursor is ON, move the cursor to the left + * of the current option, so that blind users, who are + * most likely to have LYShowCursor ON, will have it's + * string spoken or passed to the braille interface as + * each option is made current. Otherwise, move it to + * the bottom, right column of the screen, to "hide" + * the cursor as for the main document, and let sighted + * users rely on the current option's highlighting or + * color without the distraction of a blinking cursor + * in the window. - FM + */ + if (LYShowCursor) + SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 1)); + else + SLsmg_gotorc((LYlines - 1), (LYcols - 1)); + SLsmg_refresh(); #else - SLsmg_set_color (2); - SLsmg_gotorc (top + (i+1)-window_offset, lx - 1 + 2); - SLsmg_write_nstring (opt_ptr->name, width); - SLsmg_set_color (0); - SLsmg_refresh (); -#endif /* !USE_SLANG */ - - c = LYgetch(); + wstart_reverse(form_window); + wmove(form_window, ((i + 1) - window_offset), 2); + paddstr(form_window, width, opt_ptr->name); + wstop_reverse(form_window); + /* + * If LYShowCursor is ON, move the cursor to the left + * of the current option, so that blind users, who are + * most likely to have LYShowCursor ON, will have it's + * string spoken or passed to the braille interface as + * each option is made current. Otherwise, leave it to + * the right of the current option, since we can't move + * it out of the window, and let sighted users rely on + * the highlighting of the current option without the + * distraction of a blinking cursor preceding it. - FM + */ + if (LYShowCursor) + wmove(form_window, ((i + 1) - window_offset), 1); + wrefresh(form_window); +#endif /* USE_SLANG */ + + c = LYgetch(); if (c == 3 || c == 7) /* Control-C or Control-G */ cmd = LYK_QUIT; else @@ -651,35 +831,220 @@ redraw: } #endif /* VMS */ - switch(cmd) { - case LYK_PREV_LINK: + switch(cmd) { + case LYK_F_LINK_NUM: + c = '\0'; + case LYK_1: + case LYK_2: + case LYK_3: + case LYK_4: + case LYK_5: + case LYK_6: + case LYK_7: + case LYK_8: + case LYK_9: + /* + * Get a number from the user, possibly with + * a 'g' or 'p' suffix (which will be loaded + * into c). - FM & LE + */ + number = get_popup_option_number((int *)&c); + + /* + * Check for a 'p' suffix. - FM + */ + if (c == 'p') { + /* + * Treat 1 or less as the first page. - FM + */ + if (number <= 1) { + if (window_offset == 0) { + _statusline(ALREADY_AT_OPTION_BEGIN); + sleep(MessageSecs); + if (disabled) { + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + } else { + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + } + break; + } + window_offset = 0; + cur_selection = 0; + if (disabled) { + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + } else { + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + } + goto redraw; + } + + /* + * Treat a number equal to or greater than the + * number of pages as the last page. - FM + */ + if (number >= npages) { + if (window_offset >= ((num_options - length) + 1)) { + _statusline(ALREADY_AT_OPTION_END); + sleep(MessageSecs); + if (disabled) { + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + } else { + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + } + break; + } + window_offset = ((npages - 1) * length); + if (window_offset > (num_options - length)) { + window_offset = (num_options - length + 1); + } + if (cur_selection < window_offset) + cur_selection = window_offset; + if (disabled) { + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + } else { + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + } + goto redraw; + } + + /* + * We want an intermediate page. - FM + */ + if (((number - 1) * length) == window_offset) { + sprintf(buffer, ALREADY_AT_OPTION_PAGE, number); + _statusline(buffer); + sleep(MessageSecs); + if (disabled) { + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + } else { + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + } + break; + } + cur_selection = window_offset = ((number - 1) * length); + if (disabled) { + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + } else { + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + } + goto redraw; + + } + + /* + * Check for a positive number, which signifies + * that an option should be sought. - FM + */ + if (number > 0) { + /* + * Decrement the number so as to correspond + * with our cur_selection values. - FM + */ + number--; + + /* + * If the number is in range and had no legal + * suffix, select the indicated option. - FM + */ + if (number <= num_options && c == '\0') { + cur_selection = number; + cmd = LYK_ACTIVATE; + break; + } + + /* + * Verify that we had a 'g' suffix, + * and act on the number. - FM + */ + if (c == 'g') { + if (cur_selection == number) { + /* + * The option already is current. - FM + */ + sprintf(buffer, + OPTION_ALREADY_CURRENT, (number + 1)); + _statusline(buffer); + sleep(MessageSecs); + if (disabled) { + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + } else { + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + } + break; + } + + if (number <= num_options) { + /* + * The number is in range and had a 'g' + * suffix, so make it the current option, + * scrolling if needed. - FM + */ + j = (number - cur_selection); + cur_selection = number; + if ((j > 0) && + (cur_selection - window_offset) >= length) { + window_offset += j; + if (window_offset > (num_options - length + 1)) + window_offset = (num_options - length + 1); + } else if ((cur_selection - window_offset) < 0) { + window_offset -= abs(j); + if (window_offset < 0) + window_offset = 0; + } + if (disabled) { + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + } else { + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + } + goto redraw; + } + + /* + * Not in range. - FM + */ + _statusline(BAD_OPTION_NUM_ENTERED); + sleep(MessageSecs); + } + } + + /* + * Restore the popup statusline. - FM + */ + if (disabled) { + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + } else { + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + } + break; + + case LYK_PREV_LINK: case LYK_UP_LINK: if (cur_selection > 0) cur_selection--; /* - * Scroll the window up if neccessary. + * Scroll the window up if necessary. */ if ((cur_selection - window_offset) < 0) { window_offset--; goto redraw; } - break; + break; - case LYK_NEXT_LINK: + case LYK_NEXT_LINK: case LYK_DOWN_LINK: if (cur_selection < num_options) - cur_selection++; + cur_selection++; /* - * Scroll the window down if neccessary + * Scroll the window down if necessary */ if ((cur_selection - window_offset) >= length) { window_offset++; goto redraw; } - break; + break; case LYK_NEXT_PAGE: /* @@ -700,7 +1065,7 @@ redraw: */ window_offset += length; if (window_offset > (num_options - length)) { - window_offset = (num_options - length + 1); + window_offset = (num_options - length + 1); } /* @@ -738,7 +1103,7 @@ redraw: */ window_offset -= length; if (window_offset < 0) { - window_offset = 0; + window_offset = 0; } /* @@ -756,7 +1121,7 @@ redraw: break; case LYK_HOME: - cur_selection = 0; + cur_selection = 0; if (window_offset > 0) { window_offset = 0; goto redraw; @@ -764,80 +1129,80 @@ redraw: break; case LYK_END: - cur_selection = num_options; + cur_selection = num_options; if (window_offset != (num_options - length + 1)) { window_offset = (num_options - length + 1); goto redraw; } break; - case LYK_DOWN_TWO: - cur_selection += 2; + case LYK_DOWN_TWO: + cur_selection += 2; if (cur_selection > num_options) - cur_selection = num_options; + cur_selection = num_options; /* - * Scroll the window down if neccessary. + * Scroll the window down if necessary. */ if ((cur_selection - window_offset) >= length) { window_offset += 2; if (window_offset > (num_options - length + 1)) - window_offset = (num_options - length + 1); + window_offset = (num_options - length + 1); goto redraw; } - break; + break; case LYK_UP_TWO: - cur_selection -= 2; + cur_selection -= 2; if (cur_selection < 0) cur_selection = 0; /* - * Scroll the window up if neccessary. + * Scroll the window up if necessary. */ if ((cur_selection - window_offset) < 0) { window_offset -= 2; if (window_offset < 0) - window_offset = 0; + window_offset = 0; goto redraw; } - break; + break; - case LYK_DOWN_HALF: - cur_selection += (length/2); + case LYK_DOWN_HALF: + cur_selection += (length/2); if (cur_selection > num_options) - cur_selection = num_options; + cur_selection = num_options; /* - * Scroll the window down if neccessary. + * Scroll the window down if necessary. */ if ((cur_selection - window_offset) >= length) { window_offset += (length/2); if (window_offset > (num_options - length + 1)) - window_offset = (num_options - length + 1); + window_offset = (num_options - length + 1); goto redraw; } - break; + break; case LYK_UP_HALF: - cur_selection -= (length/2); + cur_selection -= (length/2); if (cur_selection < 0) cur_selection = 0; /* - * Scroll the window up if neccessary. + * Scroll the window up if necessary. */ if ((cur_selection - window_offset) < 0) { window_offset -= (length/2); if (window_offset < 0) - window_offset = 0; + window_offset = 0; goto redraw; } - break; + break; case LYK_REFRESH: - clearok(curscr, TRUE); - refresh(); + clearok(curscr, TRUE); + refresh(); break; case LYK_NEXT: @@ -857,18 +1222,18 @@ redraw: * of a popup window. - FM */ if ((cp = (char *)HTList_objectAt(search_queries, - 0)) != NULL) { + 0)) != NULL) { strcpy(prev_target_buffer, cp); QueryNum = 0; FirstRecall = FALSE; } } - strcpy(prev_target, prev_target_buffer); + strcpy(prev_target, prev_target_buffer); case LYK_WHEREIS: - if (*prev_target == '\0' ) { + if (*prev_target == '\0' ) { _statusline(ENTER_WHEREIS_QUERY); if ((ch = LYgetstr(prev_target, VISIBLE, - sizeof(prev_target_buffer), + sizeof(prev_target_buffer), recall)) < 0) { /* * User cancelled the search via ^G. - FM @@ -885,14 +1250,14 @@ check_recall: /* * No entry. Simply break. - FM */ - _statusline(CANCELLED); + _statusline(CANCELLED); sleep(InfoSecs); goto restore_popup_statusline; } if (recall && ch == UPARROW) { if (FirstRecall) { - /* + /* * Use the current string or * last query in the list. - FM */ @@ -900,7 +1265,8 @@ check_recall: if (*prev_target_buffer) { for (QueryNum = (QueryTotal - 1); QueryNum > 0; QueryNum--) { - if ((cp=(char *)HTList_objectAt(search_queries, + if ((cp = (char *)HTList_objectAt( + search_queries, QueryNum)) != NULL && !strcmp(prev_target_buffer, cp)) { break; @@ -920,8 +1286,8 @@ check_recall: * Roll around to the last query in the list. - FM */ QueryNum = 0; - if ((cp=(char *)HTList_objectAt(search_queries, - QueryNum)) != NULL) { + if ((cp = (char *)HTList_objectAt(search_queries, + QueryNum)) != NULL) { strcpy(prev_target, cp); if (*prev_target_buffer && !strcmp(prev_target_buffer, prev_target)) { @@ -933,7 +1299,7 @@ check_recall: } else { _statusline(EDIT_A_PREV_QUERY); } - if ((ch=LYgetstr(prev_target, VISIBLE, + if ((ch = LYgetstr(prev_target, VISIBLE, sizeof(prev_target_buffer), recall)) < 0) { /* * User cancelled the search via ^G. - FM @@ -954,14 +1320,15 @@ check_recall: if (*prev_target_buffer) { for (QueryNum = 0; QueryNum < (QueryTotal - 1); QueryNum++) { - if ((cp=(char *)HTList_objectAt(search_queries, - QueryNum)) != NULL && + if ((cp = (char *)HTList_objectAt( + search_queries, + QueryNum)) != NULL && !strcmp(prev_target_buffer, cp)) { break; } } } else { - QueryNum = QueryTotal - 1; + QueryNum = (QueryTotal - 1); } } else { /* @@ -973,9 +1340,9 @@ check_recall: /* * Roll around to the first query in the list. - FM */ - QueryNum = QueryTotal - 1; - if ((cp=(char *)HTList_objectAt(search_queries, - QueryNum)) != NULL) { + QueryNum = (QueryTotal - 1); + if ((cp = (char *)HTList_objectAt(search_queries, + QueryNum)) != NULL) { strcpy(prev_target, cp); if (*prev_target_buffer && !strcmp(prev_target_buffer, prev_target)) { @@ -997,10 +1364,10 @@ check_recall: _statusline(CANCELLED); sleep(InfoSecs); goto restore_popup_statusline; - } + } goto check_recall; } - } + } /* * Replace the search string buffer with the new target. - FM */ @@ -1026,10 +1393,10 @@ check_recall: */ cur_selection += j; /* - * Scroll the window down if neccessary. + * Scroll the window down if necessary. */ if ((cur_selection - window_offset) >= length) { - window_offset += j; + window_offset += j; if (window_offset > (num_options - length + 1)) window_offset = (num_options - length + 1); ReDraw = TRUE; @@ -1066,10 +1433,10 @@ check_recall: j = (cur_selection - j); cur_selection -= j; /* - * Scroll the window up if neccessary. + * Scroll the window up if necessary. */ if ((cur_selection - window_offset) < 0) { - window_offset -= j; + window_offset -= j; if (window_offset < 0) window_offset = 0; ReDraw = TRUE; @@ -1090,7 +1457,7 @@ restore_popup_statusline: */ if (disabled) _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); - else + else _statusline(FORM_LINK_OPTION_LIST_MESSAGE); *prev_target = '\0'; QueryTotal = (search_queries ? HTList_count(search_queries) @@ -1109,7 +1476,7 @@ restore_popup_statusline: cur_selection = orig_selection; cmd = LYK_ACTIVATE; /* to exit */ break; - } + } } #ifndef USE_SLANG @@ -1118,7 +1485,6 @@ restore_popup_statusline: LYsubwindow(0); #endif #endif /* !USE_SLANG */ - refresh(); - return(cur_selection); + return(disabled ? orig_selection : cur_selection); } diff --git a/src/LYGetFile.c b/src/LYGetFile.c index 9abe48d8..3ac5ca37 100644 --- a/src/LYGetFile.c +++ b/src/LYGetFile.c @@ -575,7 +575,7 @@ Try_Redirected_URL: StrAllocCopy(tmp, "http://"); if (TRACE) fprintf(stderr, - "LYGetFile: URL %s\nchanged to ", + "LYGetFile: URL %s\n", doc->address); *cp = '\0'; StrAllocCat(tmp, doc->address+9); @@ -590,7 +590,8 @@ Try_Redirected_URL: StrAllocCat(tmp, cp+8); StrAllocCopy(doc->address, tmp); if (TRACE) - fprintf(stderr, "%s\n",doc->address); + fprintf(stderr, " changed to %s\n", + doc->address); FREE(tmp); url_type = HTTP_URL_TYPE; } @@ -601,36 +602,56 @@ Try_Redirected_URL: url_type == CSO_URL_TYPE) fix_http_urls(doc); WWWDoc.address = doc->address; /* possible reload */ - #ifdef DIRED_SUPPORT lynx_edit_mode = FALSE; +#endif /* DIRED_SUPPORT */ + if (url_type == FILE_URL_TYPE) { - doc->address = LYSanctify(doc->address); - WWWDoc.address = doc->address; - } -#else - if (url_type == FILE_URL_TYPE && - (cp=strstr(doc->address, "/~")) != NULL) { - *cp = '\0'; - cp += 2; - StrAllocCopy(temp, doc->address); + /* + * If a file URL has a '~' as the lead character + * of its first symbolic element, convert the '~' + * to Home_Dir(), then append the rest of of path, + * if present, skipping "user" if "~user" was + * entered, simplifying, and eliminating any + * residual relative elements. - FM + */ + if (((cp = HTParse(doc->address, "", + PARSE_PATH+PARSE_ANCHOR+PARSE_PUNCTUATION)) + != NULL) && + !strncmp(cp, "/~", 2)) { + char *cp1 = strstr(doc->address, "/~"); + char *cp2; + + if (TRACE) + fprintf(stderr, "LYGetFile: URL %s\n", + doc->address); + *cp1 = '\0'; + cp1 += 2; + StrAllocCopy(temp, doc->address); #ifdef DOSPATH StrAllocCat(temp, HTDOS_wwwName((char *)Home_Dir())); #else #ifdef VMS - StrAllocCat(temp, HTVMS_wwwName((char *)Home_Dir())); + StrAllocCat(temp, + HTVMS_wwwName((char *)Home_Dir())); #else - StrAllocCat(temp, Home_Dir()); + StrAllocCat(temp, Home_Dir()); #endif /* VMS */ #endif /* DOSPATH */ - if (*cp) - StrAllocCat(temp, cp); - StrAllocCopy(doc->address, temp); - FREE(temp); - WWWDoc.address = doc->address; + if ((cp2 = strchr(cp1, '/')) != NULL) { + LYTrimRelFromAbsPath(cp2); + StrAllocCat(temp, cp2); + } + StrAllocCopy(doc->address, temp); + FREE(temp); + if (TRACE) + fprintf(stderr, " changed to %s\n", + doc->address); + WWWDoc.address = doc->address; + } + FREE(cp); } -#endif /* DIRED_SUPPORT */ - if (TRACE) + if (TRACE && LYTraceLogFP == NULL) sleep(MessageSecs); user_message(WWW_WAIT_MESSAGE, doc->address); #ifdef NOTDEFINED @@ -645,6 +666,22 @@ Try_Redirected_URL: #endif /* USE_SLANG */ fprintf(stderr,"\n"); } + if ((LYNoRefererHeader == FALSE && + LYNoRefererForThis == FALSE) && + (url_type == HTTP_URL_TYPE || + url_type == HTTPS_URL_TYPE) && + (cp = strchr(HTLoadedDocumentURL(), '?')) != NULL && + strchr(cp, '=') != NULL) { + /* + * Don't send a Referer header if the URL is + * the reply from a form with method GET, in + * case the content has personal data (e.g., + * a password or credit card number) which + * would become visible in logs. - FM + */ + LYNoRefererForThis = TRUE; + } + cp = NULL; if (!HTLoadAbsolute(&WWWDoc)) { /* * Check for redirection. @@ -819,7 +856,7 @@ Try_Redirected_URL: } /* - * The user wants to select a link or a page by number. + * The user wants to select a link or page by number. * If follow_link_number returns DO_LINK_STUFF do_link * will be run immediately following its execution. * If follow_link_number returns DO_GOTOLINK_STUFF @@ -897,10 +934,11 @@ PUBLIC int follow_link_number ARGS4( * in the current document, whether it is displayed * on the screen or not! */ - if ((info = HTGetLinkInfo(*num, - want_go ? &new_top : NULL, - want_go ? &new_link : NULL, - &links[cur].hightext, + if ((info = HTGetLinkInfo(*num, + want_go, + &new_top, + &new_link, + &links[cur].hightext, &links[cur].lname)) == WWW_INTERN_LINK_TYPE) { links[cur].type = WWW_INTERN_LINK_TYPE; return(DO_LINK_STUFF); diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h index 0877cfec..111b2a43 100644 --- a/src/LYGlobalDefs.h +++ b/src/LYGlobalDefs.h @@ -81,6 +81,7 @@ extern BOOLEAN local_exec_on_local_files; /* TRUE to enable local program * /* Values to which keypad_mode can be set */ #define NUMBERS_AS_ARROWS 0 #define LINKS_ARE_NUMBERED 1 +#define LINKS_AND_FORM_FIELDS_ARE_NUMBERED 2 #define HIDDENLINKS_MERGE 0 #define HIDDENLINKS_SEPARATE 1 @@ -97,7 +98,8 @@ extern char star_string[MAX_LINE + 1]; /* from GridText.c */ ((n) >= MAX_LINE ? star_string : &star_string[(MAX_LINE-1)] - (n)) #define DIRNAMESIZE 256 -extern BOOLEAN LYShowCursor; /* show the cursor or hide it */ +extern BOOLEAN LYShowCursor; /* Show the cursor or hide it? */ +extern BOOLEAN LYUseDefShoCur; /* Command line -show_cursor toggle */ extern BOOLEAN LYCursesON; /* start_curses()->TRUE, stop_curses()->FALSE */ extern BOOLEAN LYUserSpecifiedURL; /* URL from a goto or document? */ extern BOOLEAN LYJumpFileURL; /* URL from the jump file shortcuts? */ @@ -235,7 +237,8 @@ extern BOOLEAN no_url_redirection; /* Don't follow URL redirections */ extern char *form_post_data; /* User data for post form */ extern char *form_get_data; /* User data for get form */ extern char *http_error_file; /* Place HTTP status code in this file */ -extern char *authentication_info[2]; /* Id:Password for protected forms */ +extern char *authentication_info[2]; /* Id:Password for protected documents */ +extern char *proxyauth_info[2]; /* Id:Password for protected proxy server */ extern BOOLEAN HEAD_request; /* Do a HEAD request */ extern BOOLEAN scan_for_buried_news_references; extern BOOLEAN bookmark_start; /* Use bookmarks as startfile */ @@ -302,6 +305,9 @@ extern FILE *LYTraceLogFP; /* Pointer for TRACE log */ extern char *LYTraceLogPath; /* Path for TRACE log */ extern BOOLEAN LYUseTraceLog; /* Use a TRACE log? */ extern FILE LYOrigStderr; /* Original stderr pointer */ +extern BOOLEAN LYSeekFragMAPinCur; +extern BOOLEAN LYSeekFragAREAinCur; extern BOOLEAN LYStripDotDotURLs; /* Try to fix ../ in some URLs? */ +extern BOOLEAN LYForceSSLCookiesSecure; #endif /* LYGLOBALDEFS_H */ diff --git a/src/LYHash.c b/src/LYHash.c index 49a0696a..7fbb55ad 100644 --- a/src/LYHash.c +++ b/src/LYHash.c @@ -12,7 +12,7 @@ PUBLIC int hash_table[HASHSIZE]; /* 32K should be big enough */ -#if UNUSED +#ifdef NOT_USED PUBLIC int hash_code_rp ARGS1(char*,string) { char* hash_ptr = string; @@ -27,7 +27,20 @@ PUBLIC int hash_code_rp ARGS1(char*,string) } #endif +/* + * This is the same function as the private HASH_FUNCTION() in HTAnchor.c, + * but with a different value for HASH_SIZE. + */ + +#define HASH_SIZE 8193 /* Arbitrary prime. Memory/speed tradeoff */ + PUBLIC int hash_code ARGS1 (char*, string) { - return HASH_FUNCTION(string); + int hash; + unsigned char *p; + + for (p = (unsigned char *)string, hash = 0; *p; p++) + hash = (int) (hash * 3 + (*(unsigned char *)p)) % HASH_SIZE; + + return hash; } diff --git a/src/LYHash.h b/src/LYHash.h index 474a2cae..b466f2aa 100644 --- a/src/LYHash.h +++ b/src/LYHash.h @@ -19,7 +19,7 @@ typedef struct _hashbucket bucket; #define NOSTYLE -1 extern bucket hashStyles[HASHSIZE]; -extern int hash_code PARAMS((char*)); +extern int hash_code PARAMS((char* string)); extern int hash_table[HASHSIZE]; /* 32K should be big enough */ extern int s_alink, s_a, s_status, diff --git a/src/LYHistory.c b/src/LYHistory.c index b54d8778..741ebe52 100644 --- a/src/LYHistory.c +++ b/src/LYHistory.c @@ -179,12 +179,13 @@ PUBLIC void LYpush ARGS2( } } -#ifdef NOT_USED - /* The following segment not used any more - What's it good for, - anyway?? Doing a pop when a push is requested is confusing, - also to the user. Moreover, the way it was done seems to cause - a memory leak. - kw */ - /* +#ifdef NOTDEFINED +/* +** The following segment not used any more - What's it good for, +** anyway?? Doing a pop when a push is requested is confusing, +** also to the user. Moreover, the way it was done seems to cause +** a memory leak. - KW +*/ /* * If file is identical to one two before it, don't push it. */ if (nhist > 2 && @@ -204,7 +205,7 @@ PUBLIC void LYpush ARGS2( nhist--; return; } -#endif /* NOT_USED */ +#endif /* NOTDEFINED */ /* * OK, push it if we have stack space. @@ -317,8 +318,8 @@ PUBLIC void LYpush ARGS2( } } nhist++; - if (TRACE) { - fprintf(stderr, + if (TRACE) { + fprintf(stderr, "\nLYpush: address:%s\n title:%s\n", doc->address, doc->title); } @@ -404,6 +405,14 @@ PUBLIC int showhistory ARGS1( if (first) { tempname(tempfile, NEW_FILE); + /* + * Make the file a URL now. + */ +#if defined (VMS) || defined (DOSPATH) + sprintf(hist_filename,"file://localhost/%s", tempfile); +#else + sprintf(hist_filename,"file://localhost%s", tempfile); +#endif /* VMS */ first = FALSE; #ifdef VMS } else { @@ -415,26 +424,18 @@ PUBLIC int showhistory ARGS1( HTAlert(CANNOT_OPEN_TEMP); return(-1); } + chmod(tempfile, 0600); - /* - * Make the file a URL now. - */ -#if defined (VMS) || defined (DOSPATH) - sprintf(hist_filename,"file://localhost/%s", tempfile); -#else - sprintf(hist_filename,"file://localhost%s", tempfile); -#endif /* VMS */ StrAllocCopy(*newfile, hist_filename); LYforce_HTML_mode = TRUE; /* force this file to be HTML */ LYforce_no_cache = TRUE; /* force this file to be new */ fprintf(fp0, "<head>\n"); #ifdef EXP_CHARTRANS - add_META_charset_to_fd(fp0, -1); + LYAddMETAcharsetToFD(fp0, -1); #endif fprintf(fp0, "<title>%s</title>\n</head>\n<body>\n", HISTORY_PAGE_TITLE); - fprintf(fp0, "<h1>You have reached the History Page</h1>\n"); fprintf(fp0, "<h2>%s Version %s</h2>\n<pre>", LYNX_NAME, LYNX_VERSION); fprintf(fp0, "<em>You selected:</em>\n"); @@ -501,7 +502,8 @@ PUBLIC BOOLEAN historytarget ARGS1( LYpop_num(number, newdoc); if (newdoc->internal_link && - history[number].intern_seq_start == history[nhist-1].intern_seq_start) { + history[number].intern_seq_start == history[nhist-1].intern_seq_start + && !(LYforce_no_cache == TRUE && LYoverride_no_cache == FALSE)) { LYforce_no_cache = FALSE; LYoverride_no_cache = TRUE; treat_as_intern = TRUE; @@ -567,6 +569,14 @@ PUBLIC int LYShowVisitedLinks ARGS1( if (first) { tempname(tempfile, NEW_FILE); + /* + * Make the file a URL now. + */ +#if defined (VMS) || defined (DOSPATH) + sprintf(vl_filename,"file://localhost/%s", tempfile); +#else + sprintf(vl_filename,"file://localhost%s", tempfile); +#endif /* VMS */ first = FALSE; #ifdef VMS } else { @@ -578,26 +588,18 @@ PUBLIC int LYShowVisitedLinks ARGS1( HTAlert(CANNOT_OPEN_TEMP); return(-1); } + chmod(tempfile, 0600); - /* - * Make the file a URL now. - */ -#if defined (VMS) || defined (DOSPATH) - sprintf(vl_filename,"file://localhost/%s", tempfile); -#else - sprintf(vl_filename,"file://localhost%s", tempfile); -#endif /* VMS */ StrAllocCopy(*newfile, vl_filename); LYforce_HTML_mode = TRUE; /* force this file to be HTML */ LYforce_no_cache = TRUE; /* force this file to be new */ fprintf(fp0, "<head>\n"); #ifdef EXP_CHARTRANS - add_META_charset_to_fd(fp0, -1); + LYAddMETAcharsetToFD(fp0, -1); #endif fprintf(fp0, "<title>%s</title>\n</head>\n<body>\n", VISITED_LINKS_TITLE); - fprintf(fp0, "<h1>You have reached the Visited Links Page</h1>\n"); fprintf(fp0, "<h2>%s Version %s</h2>\n<pre>", LYNX_NAME, LYNX_VERSION); fprintf(fp0, diff --git a/src/LYLeaks.c b/src/LYLeaks.c index 8bdc8694..58edfb32 100644 --- a/src/LYLeaks.c +++ b/src/LYLeaks.c @@ -55,6 +55,7 @@ PUBLIC void LYLeaks NOARGS { if(Fp_leakagesink == NULL) { return; } + chmod(LEAKAGE_SINK, 0600); while(ALp_RunTimeAllocations != NULL) { /* diff --git a/src/LYList.c b/src/LYList.c index 66c02dbb..4d32c649 100644 --- a/src/LYList.c +++ b/src/LYList.c @@ -29,7 +29,7 @@ ** Create a temporary text/html file with a list of links to ** HyperText References in the current document. ** -** On entry +** On entry ** titles Set: if we want titles where available ** Clear: we only get addresses. */ @@ -41,7 +41,9 @@ PUBLIC char * LYlist_temp_url NOARGS return list_filename; } -PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles) +PUBLIC int showlist ARGS2( + char **, newfile, + BOOLEAN, titles) { int cnt; int refs, hidden_links; @@ -49,6 +51,7 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles) static BOOLEAN first = TRUE; FILE *fp0; char *Address = NULL, *Title = NULL, *cp = NULL; + char *desc = "unknown field or link"; refs = HText_sourceAnchors(HTMainText); hidden_links = HText_HiddenLinkCount(HTMainText); @@ -65,7 +68,15 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles) } if (first) { - tempname(tempfile,NEW_FILE); + tempname(tempfile, NEW_FILE); + /* + * Make the file a URL now. + */ +#if defined (VMS) || defined (DOSPATH) + sprintf(list_filename, "file://localhost/%s", tempfile); +#else + sprintf(list_filename, "file://localhost%s", tempfile); +#endif /* VMS */ first = FALSE; #ifdef VMS } else { @@ -78,48 +89,64 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles) sleep(MessageSecs); return(-1); } + chmod(tempfile, 0600); - /* - * Make the file a URL now. - */ -#if defined (VMS) || defined (DOSPATH) - sprintf(list_filename, "file://localhost/%s", tempfile); -#else - sprintf(list_filename, "file://localhost%s", tempfile); -#endif /* VMS */ StrAllocCopy(*newfile, list_filename); - LYforce_HTML_mode = TRUE; /* force this file to be HTML */ - LYforce_no_cache = TRUE; /* force this file to be new */ + LYforce_HTML_mode = TRUE; /* force this file to be HTML */ + LYforce_no_cache = TRUE; /* force this file to be new */ fprintf(fp0, "<head>\n"); #ifdef EXP_CHARTRANS - add_META_charset_to_fd(fp0, -1); + LYAddMETAcharsetToFD(fp0, -1); #endif fprintf(fp0, "<title>%s</title>\n</head>\n<body>\n", LIST_PAGE_TITLE); - fprintf(fp0, "<h1>You have reached the List Page</h1>\n"); fprintf(fp0, "<h2>%s Version %s</h2>\n", LYNX_NAME, LYNX_VERSION); fprintf(fp0, " References in this document:<p>\n"); - fprintf(fp0, "<%s compact>\n", (keypad_mode == LINKS_ARE_NUMBERED) ? - "ul" : "ol"); + if (refs > 0) { + fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ? + "ol" : "ul")); + if (hidden_links > 0) + fprintf(fp0, "<lh><em>Visible links:</em>\n"); + } if (hidden_links > 0) { - fprintf(fp0, "<lh><em>Visible links:</em>\n"); if (LYHiddenLinks == HIDDENLINKS_IGNORE) hidden_links = 0; } - for (cnt=1; cnt<=refs; cnt++) { + for (cnt = 1; cnt <= refs; cnt++) { HTChildAnchor *child = HText_childNumber(cnt); - HTAnchor *dest_intl = HTAnchor_followTypedLink((HTAnchor *)child, + HTAnchor *dest_intl; + HTAnchor *dest; + HTParentAnchor *parent; + char *address; + CONST char *title; + + if (child == 0) { + /* + * child should not be 0 unless form field numbering is on + * and cnt is the number of a form input field. + * HText_FormDescNumber() will set desc to a description + * of what type of input field this is. We'll list it to + * ensure that the link numbers on the list page match the + * numbering in the original document, but won't create a + * forward link to the form. - FM && LE + */ + if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) { + HText_FormDescNumber(cnt, (char **)&desc); + fprintf(fp0, "<li>[%d](<em>%s</em>)</a>\n", cnt, desc); + } + continue; + } + dest_intl = HTAnchor_followTypedLink((HTAnchor *)child, LINK_INTERNAL); - HTAnchor *dest = dest_intl ? + dest = dest_intl ? dest_intl : HTAnchor_followMainLink((HTAnchor *)child); - HTParentAnchor *parent = HTAnchor_parent(dest); - char *address = HTAnchor_address(dest); - CONST char *title = titles ? HTAnchor_title(parent) : NULL; - + parent = HTAnchor_parent(dest); + address = HTAnchor_address(dest); + title = titles ? HTAnchor_title(parent) : NULL; StrAllocCopy(Address, address); FREE(address); LYEntify(&Address, TRUE); @@ -147,10 +174,10 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles) if (hidden_links > 0) { if (refs > 0) fprintf(fp0, "\n</%s>\n\n<p>\n", - (keypad_mode == LINKS_ARE_NUMBERED) ? - "ul" : "ol"); - fprintf(fp0, "<%s compact>\n", (keypad_mode == LINKS_ARE_NUMBERED) ? - "ul" : "ol continue"); + ((keypad_mode == NUMBERS_AS_ARROWS) ? + "ol" : "ul")); + fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ? + "ol continue" : "ul")); fprintf(fp0, "<lh><em>Hidden links:</em>\n"); } @@ -166,24 +193,22 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles) FREE(Address); } - fprintf(fp0,"\n</%s>\n</body>\n", (keypad_mode == LINKS_ARE_NUMBERED) ? - "ul" : "ol"); + fprintf(fp0,"\n</%s>\n</body>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ? + "ol" : "ul")); fclose(fp0); return(0); } - /* printlist - F.Macrides (macrides@sci.wfeb.edu) ** --------- ** Print a text/plain list of HyperText References ** in the current document. ** -** On entry +** On entry ** titles Set: if we want titles where available ** Clear: we only get addresses. */ - PUBLIC void printlist ARGS2( FILE *, fp, BOOLEAN, titles) @@ -194,6 +219,7 @@ PUBLIC void printlist ARGS2( int cnt; int refs, hidden_links; char *address = NULL; + char *desc = "unknown field or link"; refs = HText_sourceAnchors(HTMainText); if (refs <= 0 && LYHiddenLinks != HIDDENLINKS_SEPARATE) @@ -209,12 +235,29 @@ PUBLIC void printlist ARGS2( hidden_links = 0; } for (cnt = 1; cnt <= refs; cnt++) { - HTAnchor *dest = - HTAnchor_followMainLink((HTAnchor *) - HText_childNumber(cnt)); - HTParentAnchor * parent = HTAnchor_parent(dest); - CONST char * title = titles ? HTAnchor_title(parent) : NULL; + HTChildAnchor *child = HText_childNumber(cnt); + HTAnchor *dest; + HTParentAnchor *parent; + CONST char *title; + if (child == 0) { + /* + * child should not be 0 unless form field numbering is on + * and cnt is the number of a form intput field. + * HText_FormDescNumber() will set desc to a description + * of what type of input field this is. We'll list it to + * ensure that the link numbers on the list page match the + * numbering in the original document. - FM && LE + */ + if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) { + HText_FormDescNumber(cnt, (char **)&desc); + fprintf(fp, "%4d. (%s)\n", cnt, desc); + } + continue; + } + dest = HTAnchor_followMainLink((HTAnchor *)child); + parent = HTAnchor_parent(dest); + title = titles ? HTAnchor_title(parent) : NULL; address = HTAnchor_address(dest); fprintf(fp, "%4d. %s%s\n", cnt, ((HTAnchor*)parent != dest) && title ? "in " : "", diff --git a/src/LYLocal.c b/src/LYLocal.c index 3dd45b97..22b66886 100644 --- a/src/LYLocal.c +++ b/src/LYLocal.c @@ -15,9 +15,18 @@ unescaping took place before). Dynamic memory instead of fixed length buffers in a few cases. Other minor changes to make things work as intended. */ +/* Modified Jun-97 Klaus Weide (kweide@tezcat.com) & FM: + Modified the code handling DIRED_MENU to do more careful + checking of the selected file. In addition to "TAG", "FILE", and + "DIR", DIRED_MENU definitions in lynx.cfg now also recognize LINK as + a type. DIRED_MENU definitions with a type field of "LINK" are only + used if the current selection is a symbolic link ("FILE" and "DIR" + definitions are not used in that case). The default menu + definitions have been updated to reflect this change, and to avoid + the showing of menu items whose action would always fail - KW + Cast all code into the Lynx programming style. - FM */ #ifdef DIRED_SUPPORT - #include "HTUtils.h" #include "tcp.h" #include "HTParse.h" @@ -41,35 +50,48 @@ #define FREE(x) if (x) {free(x); x = NULL;} -PRIVATE int my_spawn PARAMS((char *path, char **argv, char *msg)); -PRIVATE char *filename PARAMS((char *prompt, char *buf, int bufsize)); +PRIVATE int my_spawn PARAMS(( + char * path, + char ** argv, + char * msg)); +PRIVATE char *filename PARAMS(( + char * prompt, + char * buf, + int bufsize)); #ifdef OK_PERMIT -PRIVATE BOOLEAN permit_location PARAMS((char * destpath, char * srcpath, - char ** newpath)); +PRIVATE BOOLEAN permit_location PARAMS(( + char * destpath, + char * srcpath, + char ** newpath)); #endif /* OK_PERMIT */ -PRIVATE char *render_item PARAMS((char *s, char *path, char *dir, char *buf, - int bufsize, BOOLEAN url_syntax)); +PRIVATE char *render_item PARAMS(( + char * s, + char * path, + char * dir, + char * buf, + int bufsize, + BOOLEAN url_syntax)); PRIVATE struct dired_menu *menu_head = NULL; struct dired_menu { - int cond; -# define DE_TAG 1 -# define DE_DIR 2 -# define DE_FILE 3 -#define DE_SYMLINK 4 - char *sfx; - char *link; - char *rest; - char *href; - struct dired_menu *next; + int cond; +#define DE_TAG 1 +#define DE_DIR 2 +#define DE_FILE 3 +#define DE_SYMLINK 4 + char *sfx; + char *link; + char *rest; + char *href; + struct dired_menu *next; } defmenu[] = { /* - * The following initializations determine the contents of the f)ull menu - * selection when in dired mode. If any menu entries are defined in the - * configuration file via DIRED_MENU lines, then these default entries - * are discarded entirely. + * The following initializations determine the contents of the f)ull menu + * selection when in dired mode. If any menu entries are defined in the + * configuration file via DIRED_MENU lines, then these default entries + * are discarded entirely. */ { 0, "", "New File", "(in current directory)", "LYNXDIRED://NEW_FILE%d", NULL }, @@ -189,163 +211,171 @@ struct dired_menu { NULL, NULL, NULL } }; -/* Remove all tagged files and directories. */ - +/* + * Remove all tagged files and directories. + */ PRIVATE BOOLEAN remove_tagged NOARGS -{ - int c, ans; - char *cp,*tp; - char tmpbuf[1024]; - char *testpath = NULL; - struct stat dir_info; - int count,i; - HTList *tag; - char *args[5]; - - if (HTList_isEmpty(tagged)) /* should never happen */ - return 0; - - _statusline("Remove all tagged files and directories (y or n): "); - c = LYgetch(); - ans=TOUPPER(c); - - count = 0; - tag = tagged; - while(ans == 'Y' && (cp = (char *)HTList_nextObject(tag)) != NULL) { - if(is_url(cp) == FILE_URL_TYPE) { /* unecessary check */ - tp = cp; - if(!strncmp(tp,"file://localhost",16)) - tp += 16; - else if(!strncmp(tp,"file:",5)) - tp += 5; - StrAllocCopy(testpath,tp); - HTUnEscape(testpath); - if((i = strlen(testpath)) && testpath[i-1] == '/') - testpath[i-1] = '\0'; - -/* check the current status of the path to be deleted */ - - if (stat(testpath,&dir_info) == -1) { - sprintf(tmpbuf,"System error - failed to get status of %s ",testpath); - _statusline(tmpbuf); - sleep(AlertSecs); - return count; - } else { - args[0] = "rm"; - args[1] = "-rf"; - args[2] = testpath; - args[3] = (char *) 0; - sprintf(tmpbuf, "remove %s", testpath); - if (my_spawn(RM_PATH, args, tmpbuf) <= 0) { - FREE(testpath); - return ((count == 0) ? -1 : count); +{ + int c, ans; + char *cp, *tp; + char tmpbuf[1024]; + char *testpath = NULL; + struct stat dir_info; + int count, i; + HTList *tag; + char *args[5]; + + if (HTList_isEmpty(tagged)) /* should never happen */ + return 0; + + _statusline("Remove all tagged files and directories (y or n): "); + c = LYgetch(); + ans = TOUPPER(c); + + count = 0; + tag = tagged; + while (ans == 'Y' && (cp = (char *)HTList_nextObject(tag)) != NULL) { + if (is_url(cp) == FILE_URL_TYPE) { /* unecessary check */ + tp = cp; + if (!strncmp(tp, "file://localhost", 16)) { + tp += 16; + } else if (!strncmp(tp, "file:", 5)) { + tp += 5; } - ++count; - } - } - } - FREE(testpath); - clear_tags(); - return count; + StrAllocCopy(testpath, tp); + HTUnEscape(testpath); + if ((i = strlen(testpath)) && testpath[i-1] == '/') + testpath[(i - 1)] = '\0'; + + /* + * Check the current status of the path to be deleted. + */ + if (stat(testpath,&dir_info) == -1) { + sprintf(tmpbuf, + "System error - failed to get status of '%s'.", + testpath); + _statusline(tmpbuf); + sleep(AlertSecs); + return count; + } else { + args[0] = "rm"; + args[1] = "-rf"; + args[2] = testpath; + args[3] = (char *) 0; + sprintf(tmpbuf, "remove %s", testpath); + if (my_spawn(RM_PATH, args, tmpbuf) <= 0) { + FREE(testpath); + return ((count == 0) ? -1 : count); + } + ++count; + } + } + } + FREE(testpath); + clear_tags(); + return count; } -/* Move all tagged files and directories to a new location. */ -/* Input is current directory. */ -/* The tests in this function can, at best, prevent some user mistakes - - anybody who relies on them for security is seriously misguided. - If a user has enough permissions to move a file somewhere, the same - uid with Lynx & dired can do the same thing. */ - +/* + * Move all tagged files and directories to a new location. + * Input is current directory. + * The tests in this function can, at best, prevent some user mistakes - + * anybody who relies on them for security is seriously misguided. + * If a user has enough permissions to move a file somewhere, the same + * uid with Lynx & dired can do the same thing. + */ PRIVATE BOOLEAN modify_tagged ARGS1( char *, testpath) { - char *cp; - dev_t dev; - ino_t inode; - uid_t owner; - char tmpbuf[1024]; - char *savepath = NULL; - char *srcpath = NULL; - struct stat dir_info; - char *args[5]; - int count = 0; - HTList *tag; - - if (HTList_isEmpty(tagged)) /* should never happen */ - return 0; - - _statusline("Enter new location for tagged items: "); - - tmpbuf[0] = '\0'; - LYgetstr(tmpbuf, VISIBLE, sizeof(tmpbuf), NORECALL); - if (strlen(tmpbuf)) { - -/* determine the ownership of the current location */ - - - /* - * This test used to always fail from the dired menu... - * changed to something that hopefully makes more sense - KW - */ - if (testpath && *testpath && 0!=strcmp(testpath,"/")) { - /* - * testpath passed in and is not empty and not - * a single "/" (which would probably be bogus) - use it - */ - cp = testpath; - } else { - /* - * Prepare to get directory path from one of the tagged files. - */ - cp = HTList_lastObject(tagged); - testpath = NULL; /* won't be needed any more in this function, - set to NULL as a flag */ - if (!cp) /* last resort, should never happen */ - cp = "/"; - } - if (!strncmp(cp,"file://localhost",16)) - cp += 16; - else if (!strncmp(cp,"file:",5)) - cp += 5; - if (testpath==NULL) { - /* - * Get the directory containing the file or subdir. - */ - cp = strip_trailing_slash(cp); - savepath = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION); - } else { - StrAllocCopy(savepath, cp); - } - HTUnEscape(savepath); - if (stat(savepath,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",savepath); - _statusline(tmpbuf); - sleep(AlertSecs); - FREE(savepath); - return 0; - } - -/* save the owner of the current location for later use */ -/* also save the device and inode for location checking */ - - dev = dir_info.st_dev; - inode = dir_info.st_ino; - owner = dir_info.st_uid; - -/* replace ~/ references to the home directory */ - - if (!strncmp(tmpbuf,"~/",2)) { - char *cp1 = NULL; - StrAllocCopy(cp1, (char *)Home_Dir()); - StrAllocCat(cp1, (tmpbuf+1)); - if (strlen(cp1) > (sizeof(tmpbuf)-1)) { - sprintf(tmpbuf, "%s ", "Path too long"); - _statusline(tmpbuf); - sleep(AlertSecs); - FREE(savepath); - FREE(cp1); - return 0; - } + char *cp; + dev_t dev; + ino_t inode; + uid_t owner; + char tmpbuf[1024]; + char *savepath = NULL; + char *srcpath = NULL; + struct stat dir_info; + char *args[5]; + int count = 0; + HTList *tag; + + if (HTList_isEmpty(tagged)) /* should never happen */ + return 0; + + _statusline("Enter new location for tagged items: "); + + tmpbuf[0] = '\0'; + LYgetstr(tmpbuf, VISIBLE, sizeof(tmpbuf), NORECALL); + if (strlen(tmpbuf)) { + /* + * Determine the ownership of the current location. + */ + /* + * This test used to always fail from the dired menu... + * changed to something that hopefully makes more sense - KW + */ + if (testpath && *testpath && 0!=strcmp(testpath,"/")) { + /* + * testpath passed in and is not empty and not a single "/" + * (which would probably be bogus) - use it. + */ + cp = testpath; + } else { + /* + * Prepare to get directory path from one of the tagged files. + */ + cp = HTList_lastObject(tagged); + testpath = NULL; /* Won't be needed any more in this function, + set to NULL as a flag. */ + if (!cp) /* Last resort, should never happen. */ + cp = "/"; + } + if (!strncmp(cp, "file://localhost", 16)) { + cp += 16; + } else if (!strncmp(cp, "file:", 5)) { + cp += 5; + } + if (testpath == NULL) { + /* + * Get the directory containing the file or subdir. + */ + cp = strip_trailing_slash(cp); + savepath = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION); + } else { + StrAllocCopy(savepath, cp); + } + HTUnEscape(savepath); + if (stat(savepath, &dir_info) == -1) { + sprintf(tmpbuf, "Unable to get status of '%s'.", savepath); + _statusline(tmpbuf); + sleep(AlertSecs); + FREE(savepath); + return 0; + } + + /* + * Save the owner of the current location for later use. + * Also save the device and inode for location checking/ + */ + dev = dir_info.st_dev; + inode = dir_info.st_ino; + owner = dir_info.st_uid; + + /* + * Replace ~/ references to the home directory. + */ + if (!strncmp(tmpbuf, "~/", 2)) { + char *cp1 = NULL; + StrAllocCopy(cp1, (char *)Home_Dir()); + StrAllocCat(cp1, (tmpbuf + 1)); + if (strlen(cp1) > (sizeof(tmpbuf) - 1)) { + sprintf(tmpbuf, "%s", "Path too long"); + _statusline(tmpbuf); + sleep(AlertSecs); + FREE(savepath); + FREE(cp1); + return 0; + } strcpy(tmpbuf, cp1); FREE(cp1); } @@ -363,7 +393,7 @@ PRIVATE BOOLEAN modify_tagged ARGS1( /* stat the target location to determine type and ownership */ if (stat(savepath,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",savepath); + sprintf(tmpbuf,"Unable to get status of '%s'.",savepath); _statusline(tmpbuf); sleep(AlertSecs); FREE(savepath); @@ -431,539 +461,582 @@ PRIVATE BOOLEAN modify_tagged ARGS1( return 0; } -/* Modify the name of the specified item. */ +/* + * Modify the name of the specified item. + */ PRIVATE BOOLEAN modify_name ARGS1( char *, testpath) { - char *cp; - char tmpbuf[512]; - char newpath[512]; - char savepath[512]; - struct stat dir_info; - char *args[5]; + char *cp; + char tmpbuf[512]; + char newpath[512]; + char savepath[512]; + struct stat dir_info; + char *args[5]; -/* Determine the status of the selected item. */ + /* + * Determine the status of the selected item. + */ + testpath = strip_trailing_slash(testpath); - testpath = strip_trailing_slash(testpath); + if (stat(testpath, &dir_info) == -1) { + sprintf(tmpbuf, "Unable to get status of '%s'.", testpath); + _statusline(tmpbuf); + sleep(AlertSecs); + } else { + /* + * Change the name of the file or directory. + */ + if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { + cp = "Enter new name for directory: "; + } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { + cp = "Enter new name for file: "; + } else { + _statusline( + "The selected item is not a file or a directory! Request ignored."); + sleep(AlertSecs); + return 0; + } + if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL) + return 0; - if (stat(testpath,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",testpath); - _statusline(tmpbuf); - sleep(AlertSecs); - } else { + /* + * Do not allow the user to also change the location at this time. + */ + if (strchr(tmpbuf, '/') != NULL) { + _statusline("Illegal character \"/\" found! Request ignored."); + sleep(AlertSecs); + } else if (strlen(tmpbuf) && + (cp = strrchr(testpath, '/')) != NULL) { + strcpy(savepath,testpath); + *(++cp) = '\0'; + strcpy(newpath,testpath); + strcat(newpath,tmpbuf); -/* Change the name of the file or directory. */ + /* + * Make sure the destination does not already exist. + */ + if (stat(newpath, &dir_info) == -1) { + if (errno != ENOENT) { + sprintf(tmpbuf, + "Unable to determine status of '%s'.", newpath); + _statusline(tmpbuf); + sleep(AlertSecs); + } else { + sprintf(tmpbuf, "move %s to %s", savepath, newpath); + args[0] = "mv"; + args[1] = savepath; + args[2] = newpath; + args[3] = (char *) 0; + if (my_spawn(MV_PATH, args, tmpbuf) <= 0) + return (-1); + return 1; + } + } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { + _statusline( + "There is already a directory with that name! Request ignored."); + sleep(AlertSecs); + } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { + _statusline( + "There is already a file with that name! Request ignored."); + sleep(AlertSecs); + } else { + _statusline( + "The specified name is already in use! Request ignored."); + sleep(AlertSecs); + } + } + } + return 0; +} - if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { - cp = "Enter new name for directory: "; - } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { - cp = "Enter new name for file: "; - } else { - _statusline( - "The selected item is not a file or a directory! Request ignored. "); - sleep(AlertSecs); - return 0; - } - if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL) - return 0; +/* + * Change the location of a file or directory. + */ +PRIVATE BOOLEAN modify_location ARGS1( + char *, testpath) +{ + int mode; + char *cp; + dev_t dev; + ino_t inode; + uid_t owner; + char tmpbuf[1024]; + char newpath[512]; + char savepath[512]; + struct stat dir_info; + char *args[5]; -/* Do not allow the user to also change the location at this time */ + /* + * Determine the status of the selected item. + */ + testpath = strip_trailing_slash(testpath); - if(strchr(tmpbuf,'/') != NULL) { - _statusline("Illegal character \"/\" found! Request ignored. "); - sleep(AlertSecs); - } else if(strlen(tmpbuf) && (cp = strrchr(testpath,'/')) != NULL) { - strcpy(savepath,testpath); - *++cp = '\0'; - strcpy(newpath,testpath); - strcat(newpath,tmpbuf); + if (stat(testpath, &dir_info) == -1) { + sprintf(tmpbuf, "Unable to get status of '%s'.", testpath); + _statusline(tmpbuf); + sleep(AlertSecs); + return 0; + } -/* Make sure the destination does not already exist. */ + /* + * Change the location of the file or directory. + */ + if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { + cp = "Enter new location for directory: "; + } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { + cp = "Enter new location for file: "; + } else { + _statusline( + "The specified item is not a file or a directory - request ignored."); + sleep(AlertSecs); + return 0; + } + if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL) + return 0; + if (strlen(tmpbuf)) { + strcpy(savepath, testpath); + strcpy(newpath, testpath); - if (stat(newpath,&dir_info) == -1) { - if (errno != ENOENT) { - sprintf(tmpbuf,"Unable to determine status of %s ",newpath); - _statusline(tmpbuf); - sleep(AlertSecs); + /* + * Allow ~/ references to the home directory. + */ + if (!strncmp(tmpbuf,"~/",2)) { + cp = (char *)Home_Dir(); + strcpy(newpath, cp); + strcat(newpath, (tmpbuf + 1)); + strcpy(tmpbuf, newpath); + } + if (tmpbuf[0] != '/') { + if ((cp = strrchr(newpath,'/')) != NULL) { + *++cp = '\0'; + strcat(newpath,tmpbuf); } else { - sprintf(tmpbuf,"move %s to %s",savepath,newpath); - args[0] = "mv"; - args[1] = savepath; - args[2] = newpath; - args[3] = (char *) 0; - if (my_spawn(MV_PATH, args, tmpbuf) <= 0) - return (-1); - return 1; + _statusline("Unexpected failure - unable to find trailing \"/\""); + sleep(AlertSecs); + return 0; } - } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { - _statusline( - "There is already a directory with that name! Request ignored. "); + } else { + strcpy(newpath,tmpbuf); + } + + /* + * Make sure the source and target have the same owner (uid). + */ + dev = dir_info.st_dev; + mode = dir_info.st_mode; + inode = dir_info.st_ino; + owner = dir_info.st_uid; + if (stat(newpath, &dir_info) == -1) { + sprintf(tmpbuf,"Unable to get status of '%s'.",newpath); + _statusline(tmpbuf); sleep(AlertSecs); - } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { + return 0; + } + if ((dir_info.st_mode & S_IFMT) != S_IFDIR) { _statusline( - "There is already a file with that name! Request ignored. "); + "Destination is not a valid directory! Request denied."); sleep(AlertSecs); - } else { + return 0; + } + + /* + * Make sure the source and target are not the same location. + */ + if (dev == dir_info.st_dev && inode == dir_info.st_ino) { _statusline( - "The specified name is already in use! Request ignored. "); + "Source and destination are the same location! Request ignored!"); sleep(AlertSecs); - } - } - } - return 0; -} - -/* Change the location of a file or directory. */ - -PRIVATE BOOLEAN modify_location ARGS1( - char *, testpath) -{ - int mode; - char *cp; - dev_t dev; - ino_t inode; - uid_t owner; - char tmpbuf[1024]; - char newpath[512]; - char savepath[512]; - struct stat dir_info; - char *args[5]; - -/* Determine the status of the selected item. */ - - testpath = strip_trailing_slash(testpath); - - if (stat(testpath,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",testpath); - _statusline(tmpbuf); - sleep(AlertSecs); - return 0; - } - -/* Change the location of the file or directory */ - - if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { - cp = "Enter new location for directory: "; - } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { - cp = "Enter new location for file: "; - } else { - _statusline( - "The specified item is not a file or a directory - request ignored."); - sleep(AlertSecs); - return 0; - } - if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL) - return 0; - if (strlen(tmpbuf)) { - strcpy(savepath,testpath); - strcpy(newpath,testpath); - -/* Allow ~/ references to the home directory. */ - - if (!strncmp(tmpbuf,"~/",2)) { - cp = (char *)Home_Dir(); - strcpy(newpath,cp); - strcat(newpath,tmpbuf+1); - strcpy(tmpbuf,newpath); - } - if (tmpbuf[0] != '/') { - if ((cp = strrchr(newpath,'/')) != NULL) { - *++cp = '\0'; - strcat(newpath,tmpbuf); - } else { - _statusline("Unexpected failure - unable to find trailing \"/\""); + return 0; + } + if (dir_info.st_uid == owner) { + sprintf(tmpbuf,"move %s to %s",savepath,newpath); + args[0] = "mv"; + args[1] = savepath; + args[2] = newpath; + args[3] = (char *) 0; + if (my_spawn(MV_PATH, args, tmpbuf) <= 0) + return (-1); + return 1; + } else { + _statusline("Destination has different owner! Request denied."); sleep(AlertSecs); return 0; - } - } else { - strcpy(newpath,tmpbuf); - } - -/* Make sure the source and target have the same owner (uid) */ - - dev = dir_info.st_dev; - mode = dir_info.st_mode; - inode = dir_info.st_ino; - owner = dir_info.st_uid; - if (stat(newpath,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",newpath); - _statusline(tmpbuf); - sleep(AlertSecs); - return 0; - } - if ((dir_info.st_mode & S_IFMT) != S_IFDIR) { - _statusline( - "Destination is not a valid directory! Request denied. "); - sleep(AlertSecs); - return 0; - } - -/* make sure the source and target are not the same location */ - - if (dev == dir_info.st_dev && inode == dir_info.st_ino) { - _statusline( - "Source and destination are the same location! Request ignored!"); - sleep(AlertSecs); - return 0; - } - if(dir_info.st_uid == owner) { - sprintf(tmpbuf,"move %s to %s",savepath,newpath); - args[0] = "mv"; - args[1] = savepath; - args[2] = newpath; - args[3] = (char *) 0; - if (my_spawn(MV_PATH, args, tmpbuf) <= 0) - return (-1); - return 1; - } else { - _statusline("Destination has different owner! Request denied. "); - sleep(AlertSecs); - return 0; - } - } - return 0; -} - -/* Modify name or location of a file or directory on localhost. */ + } + } + return 0; +} +/* + * Modify name or location of a file or directory on localhost. + */ PUBLIC BOOLEAN local_modify ARGS2( document *, doc, char **, newpath) { - int c, ans; - char *cp; - char testpath[512]; /* a bit ridiculous */ - int count; - - if (!HTList_isEmpty(tagged)) { - cp = doc->address; - if (!strncmp(cp,"file://localhost",16)) - cp += 16; - else if (!strncmp(cp,"file:",5)) - cp += 5; - strcpy(testpath,cp); - HTUnEscapeSome(testpath,"/"); - count = modify_tagged(testpath); + int c, ans; + char *cp; + char testpath[512]; /* a bit ridiculous */ + int count; - if (doc->link > (nlinks-count-1)) doc->link = nlinks-count-1; - doc->link = doc->link < 0 ? 0 : doc->link; + if (!HTList_isEmpty(tagged)) { + cp = doc->address; + if (!strncmp(cp, "file://localhost", 16)) { + cp += 16; + } else if (!strncmp(cp, "file:", 5)) { + cp += 5; + } + strcpy(testpath, cp); + HTUnEscapeSome(testpath, "/"); + count = modify_tagged(testpath); - return count; - } else if (doc->link < 0 || doc->link > nlinks) /* added protection */ - return 0; + if (doc->link > (nlinks-count - 1)) + doc->link = (nlinks-count - 1); + doc->link = (doc->link < 0) ? + 0 : doc->link; -/* Do not allow simultaneous change of name and location as in Unix */ -/* This reduces functionality but reduces difficulty for the novice */ + return count; + } else if (doc->link < 0 || doc->link > nlinks) { + /* + * Added protection. + */ + return 0; + } + /* + * Do not allow simultaneous change of name and location as in Unix. + * This reduces functionality but reduces difficulty for the novice. + */ #ifdef OK_PERMIT - _statusline("Modify name, location, or permission (n, l, or p): "); + _statusline("Modify name, location, or permission (n, l, or p): "); #else - _statusline("Modify name, or location (n or l): "); + _statusline("Modify name, or location (n or l): "); #endif /* OK_PERMIT */ - c = LYgetch(); - ans=TOUPPER(c); - - if (strchr("NLP",ans) != NULL) { - cp = links[doc->link].lname; - if(!strncmp(cp,"file://localhost",16)) - cp += 16; - else if(!strncmp(cp,"file:",5)) - cp += 5; - strcpy(testpath,cp); - HTUnEscape(testpath); - - if (ans == 'N') { - - return(modify_name(testpath)); - - } else if (ans == 'L') { - - if (modify_location(testpath)) { - - if (doc->link == (nlinks-1)) --doc->link; - - return 1; + c = LYgetch(); + ans = TOUPPER(c); + + if (strchr("NLP", ans) != NULL) { + cp = links[doc->link].lname; + if (!strncmp(cp, "file://localhost", 16)) { + cp += 16; + } else if(!strncmp(cp, "file:", 5)) { + cp += 5; } + strcpy(testpath, cp); + HTUnEscape(testpath); + + if (ans == 'N') { + return(modify_name(testpath)); + } else if (ans == 'L') { + if (modify_location(testpath)) { + if (doc->link == (nlinks-1)) + --doc->link; + return 1; + } #ifdef OK_PERMIT - } else if (ans == 'P') { - return(permit_location(NULL, testpath, newpath)); + } else if (ans == 'P') { + return(permit_location(NULL, testpath, newpath)); #endif /* OK_PERMIT */ - - } else { - -/* code for changing ownership needed here */ - - _statusline("This feature not yet implemented! "); - sleep(AlertSecs); - } - } - return 0; + } else { + /* + * Code for changing ownership needed here. + */ + _statusline("This feature not yet implemented!"); + sleep(AlertSecs); + } + } + return 0; } -/* Create a new empty file in the current directory. */ - +/* + * Create a new empty file in the current directory. + */ PRIVATE BOOLEAN create_file ARGS1( char *, current_location) { - char tmpbuf[512]; - char testpath[512]; - struct stat dir_info; - char *args[5]; - char *bad_chars = ".~/"; - - if (filename("Enter name of file to create: ", - tmpbuf, sizeof(tmpbuf)) == NULL) - return 0; - - if (!no_dotfiles && show_dotfiles) { - bad_chars = "~/"; - } + char tmpbuf[512]; + char testpath[512]; + struct stat dir_info; + char *args[5]; + char *bad_chars = ".~/"; - if(strstr(tmpbuf,"//") != NULL) { - _statusline("Illegal redirection \"//\" found! Request ignored."); - sleep(AlertSecs); - } else if(strlen(tmpbuf) && strchr(bad_chars,tmpbuf[0]) == NULL) { - strcpy(testpath,current_location); - if(testpath[strlen(testpath)-1] != '/') - strcat(testpath,"/"); + if (filename("Enter name of file to create: ", + tmpbuf, sizeof(tmpbuf)) == NULL) { + return 0; + } -/* append the target filename to the current location */ + if (!no_dotfiles && show_dotfiles) { + bad_chars = "~/"; + } - strcat(testpath,tmpbuf); + if (strstr(tmpbuf, "//") != NULL) { + _statusline("Illegal redirection \"//\" found! Request ignored."); + sleep(AlertSecs); + } else if (strlen(tmpbuf) && strchr(bad_chars, tmpbuf[0]) == NULL) { + strcpy(testpath,current_location); + if (testpath[(strlen(testpath) - 1)] != '/') { + strcat(testpath,"/"); + } -/* make sure the target does not already exist */ + /* + * Append the target filename to the current location. + */ + strcat(testpath, tmpbuf); - if (stat(testpath,&dir_info) == -1) { - if (errno != ENOENT) { - sprintf(tmpbuf,"Unable to determine status of %s ",testpath); - _statusline(tmpbuf); + /* + * Make sure the target does not already exist + */ + if (stat(testpath, &dir_info) == -1) { + if (errno != ENOENT) { + sprintf(tmpbuf, + "Unable to determine status of '%s'.", testpath); + _statusline(tmpbuf); + sleep(AlertSecs); + return 0; + } + sprintf(tmpbuf,"create %s",testpath); + args[0] = "touch"; + args[1] = testpath; + args[2] = (char *) 0; + if (my_spawn(TOUCH_PATH, args, tmpbuf) <= 0) + return (-1); + return 1; + } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { + _statusline( + "There is already a directory with that name! Request ignored."); sleep(AlertSecs); - return 0; - } - sprintf(tmpbuf,"create %s",testpath); - args[0] = "touch"; - args[1] = testpath; - args[2] = (char *) 0; - if (my_spawn(TOUCH_PATH, args, tmpbuf) <= 0) - return (-1); - return 1; - } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { - _statusline( - "There is already a directory with that name! Request ignored. "); - sleep(AlertSecs); - } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { - _statusline( - "There is already a file with that name! Request ignored. "); - sleep(AlertSecs); - } else { - _statusline( - "The specified name is already in use! Request ignored. "); - sleep(AlertSecs); - } - } - return 0; + } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { + _statusline( + "There is already a file with that name! Request ignored."); + sleep(AlertSecs); + } else { + _statusline( + "The specified name is already in use! Request ignored."); + sleep(AlertSecs); + } + } + return 0; } -/* Create a new directory in the current directory. */ - +/* + * Create a new directory in the current directory. + */ PRIVATE BOOLEAN create_directory ARGS1( char *, current_location) { - char tmpbuf[512]; - char testpath[512]; - struct stat dir_info; - char *args[5]; - char *bad_chars = ".~/"; - - if (filename("Enter name for new directory: ", - tmpbuf, sizeof(tmpbuf)) == NULL) - return 0; - - if (!no_dotfiles && show_dotfiles) { - bad_chars = "~/"; - } - - if(strstr(tmpbuf,"//") != NULL) { - _statusline("Illegal redirection \"//\" found! Request ignored."); - sleep(AlertSecs); - } else if(strlen(tmpbuf) && strchr(bad_chars,tmpbuf[0]) == NULL) { - strcpy(testpath,current_location); + char tmpbuf[512]; + char testpath[512]; + struct stat dir_info; + char *args[5]; + char *bad_chars = ".~/"; - if(testpath[strlen(testpath)-1] != '/') - strcat(testpath,"/"); + if (filename("Enter name for new directory: ", + tmpbuf, sizeof(tmpbuf)) == NULL) { + return 0; + } - strcat(testpath,tmpbuf); + if (!no_dotfiles && show_dotfiles) { + bad_chars = "~/"; + } -/* make sure the target does not already exist */ + if (strstr(tmpbuf, "//") != NULL) { + _statusline("Illegal redirection \"//\" found! Request ignored."); + sleep(AlertSecs); + } else if (strlen(tmpbuf) && strchr(bad_chars, tmpbuf[0]) == NULL) { + strcpy(testpath,current_location); + if (testpath[(strlen(testpath) - 1)] != '/') { + strcat(testpath,"/"); + } + strcat(testpath, tmpbuf); - if (stat(testpath,&dir_info) == -1) { - if (errno != ENOENT) { - sprintf(tmpbuf,"Unable to determine status of %s ",testpath); - _statusline(tmpbuf); + /* + * Make sure the target does not already exist. + */ + if (stat(testpath, &dir_info) == -1) { + if (errno != ENOENT) { + sprintf(tmpbuf, + "Unable to determine status of '%s'.", testpath); + _statusline(tmpbuf); + sleep(AlertSecs); + return 0; + } + sprintf(tmpbuf,"make directory %s",testpath); + args[0] = "mkdir"; + args[1] = testpath; + args[2] = (char *) 0; + if (my_spawn(MKDIR_PATH, args, tmpbuf) <= 0) + return (-1); + return 1; + } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { + _statusline( + "There is already a directory with that name! Request ignored."); sleep(AlertSecs); - return 0; - } - sprintf(tmpbuf,"make directory %s",testpath); - args[0] = "mkdir"; - args[1] = testpath; - args[2] = (char *) 0; - if (my_spawn(MKDIR_PATH, args, tmpbuf) <= 0) - return (-1); - return 1; - } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { - _statusline( - "There is already a directory with that name! Request ignored. "); - sleep(AlertSecs); - } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { - _statusline( - "There is already a file with that name! Request ignored. "); - sleep(AlertSecs); - } else { - _statusline( - "The specified name is already in use! Request ignored. "); - sleep(AlertSecs); - } - } - return 0; + } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { + _statusline( + "There is already a file with that name! Request ignored."); + sleep(AlertSecs); + } else { + _statusline( + "The specified name is already in use! Request ignored."); + sleep(AlertSecs); + } + } + return 0; } -/* Create a file or a directory at the current location. */ - +/* + * Create a file or a directory at the current location. + */ PUBLIC BOOLEAN local_create ARGS1( document *, doc) { - int c, ans; - char *cp; - char testpath[512]; - - _statusline("Create file or directory (f or d): "); - c = LYgetch(); - ans = TOUPPER(c); - - cp = doc->address; - if(!strncmp(cp,"file://localhost",16)) - cp += 16; - else if(!strncmp(cp,"file:",5)) - cp += 5; - strcpy(testpath,cp); - HTUnEscape(testpath); - - if (ans == 'F') - return(create_file(testpath)); - else if (ans == 'D') - return(create_directory(testpath)); - else return 0; + int c, ans; + char *cp; + char testpath[512]; -} + _statusline("Create file or directory (f or d): "); + c = LYgetch(); + ans = TOUPPER(c); -/* Remove a single file or directory. */ + cp = doc->address; + if (!strncmp(cp, "file://localhost", 16)) { + cp += 16; + } else if (!strncmp(cp, "file:", 5)) { + cp += 5; + } + strcpy(testpath,cp); + HTUnEscape(testpath); + + if (ans == 'F') { + return(create_file(testpath)); + } else if (ans == 'D') { + return(create_directory(testpath)); + } else { + return 0; + } +} +/* + * Remove a single file or directory. + */ PRIVATE BOOLEAN remove_single ARGS1( char *, testpath) { - int c; - char *cp; - char tmpbuf[1024]; - struct stat dir_info; - char *args[5]; - -/* lstat first in case its a symbolic link */ - - if (lstat(testpath,&dir_info) == -1 && stat(testpath,&dir_info) == -1) { - sprintf(tmpbuf,"System error - failed to get status of %s. ",testpath); - _statusline(tmpbuf); - sleep(AlertSecs); - return 0; - } - -/* locate the filename portion of the path */ - - if ((cp = strrchr(testpath,'/')) != NULL) { - ++cp; - } else { - cp = testpath; - } - if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { - if(strlen(cp) < 37) - sprintf(tmpbuf,"Remove %s and all of its contents (y or n): ",cp); - else - sprintf(tmpbuf,"Remove directory and all of its contents (y or n): "); - } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { - if(strlen(cp) < 60) - sprintf(tmpbuf,"Remove file %s (y or n): ",cp); - else - sprintf(tmpbuf,"Remove file (y or n): "); - } else if ((dir_info.st_mode & S_IFMT) == S_IFLNK) { - if(strlen(cp) < 50) - sprintf(tmpbuf,"Remove symbolic link %s (y or n): ",cp); - else - sprintf(tmpbuf,"Remove symbolic link (y or n): "); - } else { - sprintf(tmpbuf,"Unable to determine status of %s. ",testpath); - _statusline(tmpbuf); - sleep(AlertSecs); - return 0; - } - _statusline(tmpbuf); - - c = LYgetch(); - if(TOUPPER(c) == 'Y') { - sprintf(tmpbuf,"remove %s",testpath); - args[0] = "rm"; - args[1] = "-rf"; - args[2] = testpath; - args[3] = (char *) 0; - if (my_spawn(RM_PATH, args, tmpbuf) <= 0) - return (-1); - return 1; - } - return 0; -} + int c; + char *cp; + char tmpbuf[1024]; + struct stat dir_info; + char *args[5]; -/* Remove a file or a directory. */ + /* + * lstat() first in case its a symbolic link. + */ + if (lstat(testpath, &dir_info) == -1 && + stat(testpath, &dir_info) == -1) { + sprintf(tmpbuf, + "System error - failed to get status of '%s'.", testpath); + _statusline(tmpbuf); + sleep(AlertSecs); + return 0; + } + + /* + * Locate the filename portion of the path. + */ + if ((cp = strrchr(testpath, '/')) != NULL) { + ++cp; + } else { + cp = testpath; + } + if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { + if (strlen(cp) < 37) { + sprintf(tmpbuf, + "Remove '%s' and all of its contents (y or n): ", cp); + } else { + sprintf(tmpbuf, + "Remove directory and all of its contents (y or n): "); + } + } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { + if (strlen(cp) < 60) { + sprintf(tmpbuf, "Remove file '%s' (y or n): ", cp); + } else { + sprintf(tmpbuf, "Remove file (y or n): "); + } + } else if ((dir_info.st_mode & S_IFMT) == S_IFLNK) { + if (strlen(cp) < 50) { + sprintf(tmpbuf, "Remove symbolic link '%s' (y or n): ", cp); + } else { + sprintf(tmpbuf, "Remove symbolic link (y or n): "); + } + } else { + sprintf(tmpbuf, "Unable to determine status of '%s'.", testpath); + _statusline(tmpbuf); + sleep(AlertSecs); + return 0; + } + _statusline(tmpbuf); + + c = LYgetch(); + if (TOUPPER(c) == 'Y') { + sprintf(tmpbuf,"remove %s",testpath); + args[0] = "rm"; + args[1] = "-rf"; + args[2] = testpath; + args[3] = (char *) 0; + if (my_spawn(RM_PATH, args, tmpbuf) <= 0) + return (-1); + return 1; + } + return 0; +} +/* + * Remove a file or a directory. + */ PUBLIC BOOLEAN local_remove ARGS1( document *, doc) { - char *cp,*tp; - char testpath[512]; - int count,i; - - if (!HTList_isEmpty(tagged)) { - - count = remove_tagged(); - - if (doc->link > (nlinks-count-1)) doc->link = nlinks-count-1; - doc->link = doc->link < 0 ? 0 : doc->link; - - return count; - } else if (doc->link < 0 || doc->link > nlinks) - return 0; - cp = links[doc->link].lname; - if(is_url(cp) == FILE_URL_TYPE) { - tp = cp; - if(!strncmp(tp,"file://localhost",16)) - tp += 16; - else if(!strncmp(tp,"file:",5)) - tp += 5; - strcpy(testpath,tp); - HTUnEscape(testpath); - if((i = strlen(testpath)) && testpath[i-1] == '/') - testpath[i-1] = '\0'; - - if (remove_single(testpath)) { - - if (doc->link == (nlinks-1)) --doc->link; - - return 1; - } - } - return 0; + char *cp, *tp; + char testpath[512]; + int count, i; + + if (!HTList_isEmpty(tagged)) { + count = remove_tagged(); + if (doc->link > (nlinks-count - 1)) + doc->link = (nlinks-count - 1); + doc->link = (doc->link < 0) ? + 0 : doc->link; + return count; + } else if (doc->link < 0 || doc->link > nlinks) { + return 0; + } + cp = links[doc->link].lname; + if (is_url(cp) == FILE_URL_TYPE) { + tp = cp; + if (!strncmp(tp, "file://localhost", 16)) { + tp += 16; + } else if (!strncmp(tp, "file:", 5)) { + tp += 5; + } + strcpy(testpath, tp); + HTUnEscape(testpath); + if ((i = strlen(testpath)) && testpath[i - 1] == '/') + testpath[(i - 1)] = '\0'; + if (remove_single(testpath)) { + if (doc->link == (nlinks - 1)) + --doc->link; + return 1; + } + } + return 0; } #ifdef OK_PERMIT -/* Table of permission strings and chmod values. Makes the code a bit cleaner */ +/* + * Table of permission strings and chmod values. + * Makes the code a bit cleaner. + */ static struct { char *string_mode; /* Key for value below */ long permit_bits; /* Value for chmod/whatever */ @@ -977,20 +1050,22 @@ static struct { {"IROTH", S_IROTH}, {"IWOTH", S_IWOTH}, {"IXOTH", S_IXOTH}, - {NULL, 0} /* Don't include setuid and friends, - use shell access for that */ + {NULL, 0} /* Don't include setuid and friends; + use shell access for that. */ }; #ifndef S_ISDIR -# define S_ISDIR(mode) ((mode&0xF000) == 0x4000) +#define S_ISDIR(mode) ((mode&0xF000) == 0x4000) #endif /* !S_ISDIR */ +/* + * Handle DIRED permissions. + */ PRIVATE BOOLEAN permit_location ARGS3( char *, destpath, char *, srcpath, char **, newpath) { - #ifndef UNIX _statusline("Sorry, don't know how to permit non-UNIX files yet."); sleep(AlertSecs); @@ -1002,21 +1077,24 @@ PRIVATE BOOLEAN permit_location ARGS3( char tmpbuf[LINESIZE]; struct stat dir_info; - if (srcpath) { /* Create form */ + if (srcpath) { + /* + * Create form. + */ FILE *fp0; char print_filename[256]; char * user_filename; struct group * grp; char * group_name; - /* A couple of sanity tests */ - + /* + * A couple of sanity tests. + */ srcpath = strip_trailing_slash(srcpath); - if(strncmp(srcpath,"file://localhost",16) == 0) + if (strncmp(srcpath, "file://localhost", 16) == 0) srcpath += 16; - - if (lstat(srcpath,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",srcpath); + if (lstat(srcpath, &dir_info) == -1) { + sprintf(tmpbuf, "Unable to get status of '%s'.", srcpath); _statusline(tmpbuf); sleep(AlertSecs); return 0; @@ -1031,7 +1109,7 @@ PRIVATE BOOLEAN permit_location ARGS3( user_filename = srcpath; cp = strrchr(srcpath, '/'); if (cp != NULL) { - user_filename = cp + 1; + user_filename = (cp + 1); } if (first) { @@ -1039,17 +1117,20 @@ PRIVATE BOOLEAN permit_location ARGS3( first = FALSE; } - if ((fp0 = fopen(tempfile,"w")) == NULL) { + if ((fp0 = fopen(tempfile, "w")) == NULL) { _statusline("Unable to open permit options file"); sleep(AlertSecs); return(0); } + chmod(tempfile, 0600); - /* make the tempfile a URL */ + /* + * Make the tempfile a URL. + */ strcpy(print_filename, "file://localhost"); strcat(print_filename, tempfile); StrAllocCopy(*newpath, print_filename); - + grp = getgrgid(dir_info.st_gid); if (grp == NULL) { group_name = ""; @@ -1060,7 +1141,9 @@ PRIVATE BOOLEAN permit_location ARGS3( fprintf(fp0, "<Html><Head>\n<Title>%s</Title>\n</Head>\n<Body>\n", PERMIT_OPTIONS_TITLE); fprintf(fp0,"<H1>Permissions for %s</H1>\n", user_filename); - { /* prevent filenames which include '#' or '?' from messing it up */ + { /* + * Prevent filenames which include '#' or '?' from messing it up. + */ char * srcpath_url = HTEscape(srcpath, URL_PATH); fprintf(fp0, "<Form Action=\"LYNXDIRED://PERMIT_LOCATION%s\">\n", srcpath_url); @@ -1070,62 +1153,64 @@ PRIVATE BOOLEAN permit_location ARGS3( fprintf(fp0, "<Ol><Li>Specify permissions below:<Br><Br>\n"); fprintf(fp0, "Owner:<Br>\n"); fprintf(fp0, - "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRUSR\" %s> Read<Br>\n", - dir_info.st_mode & S_IRUSR ? "checked" : ""); + "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRUSR\" %s> Read<Br>\n", + (dir_info.st_mode & S_IRUSR) ? "checked" : ""); fprintf(fp0, - "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWUSR\" %s> Write<Br>\n", - dir_info.st_mode & S_IWUSR ? "checked" : ""); + "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWUSR\" %s> Write<Br>\n", + (dir_info.st_mode & S_IWUSR) ? "checked" : ""); /* - * If restricted, only change eXecute permissions on directories. + * If restricted, only change eXecute permissions on directories. */ if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode)) fprintf(fp0, - "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXUSR\" %s> %s<Br>\n", - dir_info.st_mode & S_IXUSR ? "checked" : "", + "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXUSR\" %s> %s<Br>\n", + (dir_info.st_mode & S_IXUSR) ? "checked" : "", S_ISDIR(dir_info.st_mode) ? "Search" : "Execute"); fprintf(fp0, "Group %s:<Br>\n", group_name); fprintf(fp0, - "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRGRP\" %s> Read<Br>\n", - dir_info.st_mode & S_IRGRP ? "checked" : ""); + "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRGRP\" %s> Read<Br>\n", + (dir_info.st_mode & S_IRGRP) ? "checked" : ""); fprintf(fp0, - "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWGRP\" %s> Write<Br>\n", - dir_info.st_mode & S_IWGRP ? "checked" : ""); + "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWGRP\" %s> Write<Br>\n", + (dir_info.st_mode & S_IWGRP) ? "checked" : ""); /* - * If restricted, only change eXecute permissions on directories. + * If restricted, only change eXecute permissions on directories. */ if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode)) fprintf(fp0, - "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXGRP\" %s> %s<Br>\n", - dir_info.st_mode & S_IXGRP ? "checked" : "", + "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXGRP\" %s> %s<Br>\n", + (dir_info.st_mode & S_IXGRP) ? "checked" : "", S_ISDIR(dir_info.st_mode) ? "Search" : "Execute"); fprintf(fp0, "Others:<Br>\n"); fprintf(fp0, - "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IROTH\" %s> Read<Br>\n", - dir_info.st_mode & S_IROTH ? "checked" : ""); + "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IROTH\" %s> Read<Br>\n", + (dir_info.st_mode & S_IROTH) ? "checked" : ""); fprintf(fp0, - "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWOTH\" %s> Write<Br>\n", - dir_info.st_mode & S_IWOTH ? "checked" : ""); + "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWOTH\" %s> Write<Br>\n", + (dir_info.st_mode & S_IWOTH) ? "checked" : ""); /* - * If restricted, only change eXecute permissions on directories. + * If restricted, only change eXecute permissions on directories. */ if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode)) fprintf(fp0, - "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXOTH\" %s> %s<Br>\n", - dir_info.st_mode & S_IXOTH ? "checked" : "", + "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXOTH\" %s> %s<Br>\n", + (dir_info.st_mode & S_IXOTH) ? "checked" : "", S_ISDIR(dir_info.st_mode) ? "Search" : "Execute"); - fprintf(fp0, "<Br>\n<Li><Input Type=\"submit\" Value=\"Submit\"> form to permit %s %s.\n</Ol>\n</Form>\n", + fprintf(fp0, +"<Br>\n<Li><Input Type=\"submit\" Value=\"Submit\"> \ +form to permit %s %s.\n</Ol>\n</Form>\n", (dir_info.st_mode & S_IFMT) == S_IFDIR ? "directory" : "file", user_filename); fprintf(fp0, "</Body></Html>"); fclose(fp0); - ++LYforce_no_cache; + LYforce_no_cache = TRUE; return(PERMIT_FORM_RESULT); /* Special flag for LYMainLoop */ - } else { /* The form being activated */ + } else { /* The form being activated. */ mode_t new_mode = 0; char *args[5]; char amode[10]; @@ -1135,17 +1220,19 @@ PRIVATE BOOLEAN permit_location ARGS3( cp++; } if (*cp == '\0') { - return(0); /* Nothing to permit */ + return(0); /* Nothing to permit. */ } - *cp++ = '\0'; /* Null terminate file name - and start working on the masks */ + *cp++ = '\0'; /* Null terminate file name and + start working on the masks. */ - HTUnEscape(destpath); /* will now operate only on filename part */ + HTUnEscape(destpath); /* Will now operate only on filename part. */ - /* A couple of sanity tests */ + /* + * A couple of sanity tests. + */ destpath = strip_trailing_slash(destpath); - if (stat(destpath,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",destpath); + if (stat(destpath, &dir_info) == -1) { + sprintf(tmpbuf, "Unable to get status of '%s'.", destpath); _statusline(tmpbuf); sleep(AlertSecs); return 0; @@ -1157,24 +1244,26 @@ PRIVATE BOOLEAN permit_location ARGS3( return 0; } - /* Cycle over permission strings */ + /* + * Cycle over permission strings. + */ while(*cp != '\0') { char *cr = cp; - while(*cr != '\0' && *cr != '&') { /* GET data split by '&' */ + while(*cr != '\0' && *cr != '&') { /* GET data split by '&'. */ cr++; } if (*cr != '\0') { *cr++ = '\0'; } - if (strncmp(cp, "mode=", 5) == 0) { /* Magic string */ + if (strncmp(cp, "mode=", 5) == 0) { /* Magic string. */ int i; for(i = 0; permissions[i].string_mode != NULL; i++) { if (strcmp(permissions[i].string_mode, cp+5) == 0) { /* - * If restricted, only change eXecute - * permissions on directories + * If restricted, only change eXecute + * permissions on directories. */ if (!no_change_exec_perms || strchr(cp+5,'X') == NULL || @@ -1197,8 +1286,10 @@ PRIVATE BOOLEAN permit_location ARGS3( cp = cr; } - /* Call chmod */ - sprintf(tmpbuf,"chmod %.4o %s", new_mode, destpath); + /* + * Call chmod(). + */ + sprintf(tmpbuf, "chmod %.4o %s", new_mode, destpath); sprintf(amode, "%.4o", new_mode); args[0] = "chmod"; args[1] = amode; @@ -1207,318 +1298,302 @@ PRIVATE BOOLEAN permit_location ARGS3( if (my_spawn(CHMOD_PATH, args, tmpbuf) <= 0) { return (-1); } - ++LYforce_no_cache; /* Force update of dired listing */ + LYforce_no_cache = TRUE; /* Force update of dired listing. */ return 1; } #endif /* !UNIX */ } #endif /* OK_PERMIT */ -#ifdef NOTDEFINED -PUBLIC BOOLEAN is_a_file ARGS1( - char *, testname) -{ - char *cp; - char testpath[512]; - struct stat dir_info; - - cp = testname; - if(!strncmp(cp,"file://localhost",16)) - cp += 16; - else if(!strncmp(cp,"file:",5)) - cp += 5; - strcpy(testpath,cp); - HTUnEscape(testpath); - if (stat(testpath,&dir_info) == -1) - return -1; - else - if (((dir_info.st_mode) & S_IFMT) == S_IFREG) - return 1; - else - return 0; -} -#endif /* NOTDEFINED */ - -/* display or remove a tag from a given link */ - +/* + * Display or remove a tag from a given link. + */ PUBLIC void tagflag ARGS2( - int, flag, - int, cur) + int, flag, + int, cur) { - if (nlinks > 0 /*&& links[cur].lx == 3*/) { - move(links[cur].ly,2 /*links[cur].lx-2*/); - stop_reverse(); - if (flag == ON) - addch('+'); - else - addch(' '); + if (nlinks > 0) { + move(links[cur].ly, 2); + stop_reverse(); + if (flag == ON) { + addch('+'); + } else { + addch(' '); + } #if defined(FANCY_CURSES) || defined(USE_SLANG) - if(!LYShowCursor) - move(LYlines-1,LYcols-1); /* get cursor out of the way */ - else + if (!LYShowCursor) + move((LYlines - 1), (LYcols - 1)); /* get cursor out of the way */ + else #endif /* FANCY CURSES || USE_SLANG */ - /* never hide the cursor if there's no FANCY CURSES */ - move(links[cur].ly, links[cur].lx); + /* + * Never hide the cursor if there's no FANCY CURSES. + */ + move(links[cur].ly, links[cur].lx); -/*** - if(flag) -***/ - refresh(); + refresh(); } } +/* + * Handle DIRED tags. + */ PUBLIC void showtags ARGS1( HTList *, t) { int i; HTList *s; - char * name; - - for(i=0;i<nlinks;i++) { - s = t; - while((name = HTList_nextObject(s)) != NULL) { - if(!strcmp(links[i].lname,name)) { - tagflag(ON,i); - break; - } - } - } + char *name; + + for (i = 0; i < nlinks; i++) { + s = t; + while ((name = HTList_nextObject(s)) != NULL) { + if (!strcmp(links[i].lname, name)) { + tagflag(ON, i); + break; + } + } + } } /* -** Perform file management operations for LYNXDIRED URL's. -** Attempt to be consistent. These are (pseudo) URLs - i.e. they should -** be in URL syntax: some bytes will be URL-escaped with '%'. This is -** necessary because these (pseudo) URLs will go through some of the same -** kinds of interpretations and mutilations as real ones: HTParse, stripping -** off #fragments etc. (Some access schemes currently have special rules -** about not escaping parsing '#' "the URL way" built into HTParse, but that -** doesn't look like a clean way.) -*/ + * Perform file management operations for LYNXDIRED URL's. + * Attempt to be consistent. These are (pseudo) URLs - i.e. they should + * be in URL syntax: some bytes will be URL-escaped with '%'. This is + * necessary because these (pseudo) URLs will go through some of the same + * kinds of interpretations and mutilations as real ones: HTParse, stripping + * off #fragments etc. (Some access schemes currently have special rules + * about not escaping parsing '#' "the URL way" built into HTParse, but that + * doesn't look like a clean way.) + */ PUBLIC int local_dired ARGS1( document *, doc) { - char *line_url; /* will point to doc's address, which is a URL */ - char *line = NULL; /* same as line_url, but HTUnEscaped, will be alloced */ - char *cp, *tp, *bp; - char tmpbuf[256]; - char buffer[512]; + char *line_url; /* will point to doc's address, which is a URL */ + char *line = NULL; /* same as line_url, but HTUnEscaped, will be alloced */ + char *cp, *tp, *bp; + char tmpbuf[256]; + char buffer[512]; - line_url = doc->address; - HTUnEscapeSome(line_url,"/"); /* don't mess too much with *doc */ + line_url = doc->address; + HTUnEscapeSome(line_url, "/"); /* don't mess too much with *doc */ - StrAllocCopy(line, line_url); - HTUnEscape(line); /* _file_ (not URL) syntax, for those functions + StrAllocCopy(line, line_url); + HTUnEscape(line); /* _file_ (not URL) syntax, for those functions that need it. DOn't forget to FREE it. */ - /* This causes a SIGSEGV later when StrAllocCopy tries to free tp - * let's make it point to NULL - tp = tmpbuf; - */ - tp = NULL; - if (!strncmp(line,"LYNXDIRED://NEW_FILE",20)) { - if (create_file(&line[20]) > 0) - ++LYforce_no_cache; - } else if (!strncmp(line,"LYNXDIRED://NEW_FOLDER",22)) { - if (create_directory(&line[22]) > 0) - ++LYforce_no_cache; - } else if (!strncmp(line,"LYNXDIRED://INSTALL_SRC",23)) { - local_install(NULL, &line[23], &tp); - StrAllocCopy(doc->address, tp); - FREE(line); - return 0; - } else if (!strncmp(line,"LYNXDIRED://INSTALL_DEST",24)) { - local_install(&line[24], NULL, &tp); - LYpop(doc); - } else if (!strncmp(line,"LYNXDIRED://MODIFY_NAME",23)) { - if (modify_name(&line[23]) > 0) - ++LYforce_no_cache; - } else if (!strncmp(line,"LYNXDIRED://MODIFY_LOCATION",27)) { - if (modify_location(&line[27]) > 0) - ++LYforce_no_cache; - } else if (!strncmp(line,"LYNXDIRED://MOVE_TAGGED",23)) { - if (modify_tagged(&line_url[23]) > 0) - ++LYforce_no_cache; + tp = NULL; + if (!strncmp(line, "LYNXDIRED://NEW_FILE", 20)) { + if (create_file(&line[20]) > 0) + LYforce_no_cache = TRUE; + } else if (!strncmp(line, "LYNXDIRED://NEW_FOLDER", 22)) { + if (create_directory(&line[22]) > 0) + LYforce_no_cache = TRUE; + } else if (!strncmp(line, "LYNXDIRED://INSTALL_SRC", 23)) { + local_install(NULL, &line[23], &tp); + StrAllocCopy(doc->address, tp); + FREE(line); + return 0; + } else if (!strncmp(line, "LYNXDIRED://INSTALL_DEST", 24)) { + local_install(&line[24], NULL, &tp); + LYpop(doc); + } else if (!strncmp(line, "LYNXDIRED://MODIFY_NAME", 23)) { + if (modify_name(&line[23]) > 0) + LYforce_no_cache = TRUE; + } else if (!strncmp(line, "LYNXDIRED://MODIFY_LOCATION", 27)) { + if (modify_location(&line[27]) > 0) + LYforce_no_cache = TRUE; + } else if (!strncmp(line, "LYNXDIRED://MOVE_TAGGED", 23)) { + if (modify_tagged(&line_url[23]) > 0) + LYforce_no_cache = TRUE; #ifdef OK_PERMIT - } else if (!strncmp(line,"LYNXDIRED://PERMIT_SRC",22)) { - permit_location(NULL, &line[22], &tp); - if (tp) /* one of the checks may have failed */ - StrAllocCopy(doc->address, tp); - FREE(line); - return 0; - } else if (!strncmp(line,"LYNXDIRED://PERMIT_LOCATION",27)) { - permit_location(&line_url[27], NULL, &tp); -#endif /* OK_PERMIT */ - } else if (!strncmp(line,"LYNXDIRED://REMOVE_SINGLE",25)) { - if (remove_single(&line[25]) > 0) - ++LYforce_no_cache; - } else if (!strncmp(line,"LYNXDIRED://REMOVE_TAGGED",25)) { - if (remove_tagged()) ++LYforce_no_cache; - } else if (!strncmp(line,"LYNXDIRED://CLEAR_TAGGED",24)) { - clear_tags(); - } else if (!strncmp(line,"LYNXDIRED://UPLOAD",18)) { - /* - * They're written by LYUpload_options() HTUnEscaped, - * don't want to change that for now... so pass through - * without more unescaping. Directory names containing - * '#' will probably fail.. - */ - if (LYUpload(line_url)) ++LYforce_no_cache; - } else { - if (line[strlen(line)-1] == '/') - line[strlen(line)-1] = '\0'; - if ((cp = strrchr(line,'/')) == NULL) { + } else if (!strncmp(line, "LYNXDIRED://PERMIT_SRC", 22)) { + permit_location(NULL, &line[22], &tp); + if (tp) + /* + * One of the checks may have failed. + */ + StrAllocCopy(doc->address, tp); FREE(line); return 0; - } - -/* Construct the appropriate system command taking care to escape all - path references to avoid spoofing the shell. */ + } else if (!strncmp(line, "LYNXDIRED://PERMIT_LOCATION", 27)) { + permit_location(&line_url[27], NULL, &tp); +#endif /* OK_PERMIT */ + } else if (!strncmp(line, "LYNXDIRED://REMOVE_SINGLE", 25)) { + if (remove_single(&line[25]) > 0) + LYforce_no_cache = TRUE; + } else if (!strncmp(line, "LYNXDIRED://REMOVE_TAGGED", 25)) { + if (remove_tagged()) + LYforce_no_cache = TRUE; + } else if (!strncmp(line, "LYNXDIRED://CLEAR_TAGGED", 24)) { + clear_tags(); + } else if (!strncmp(line, "LYNXDIRED://UPLOAD", 18)) { + /* + * They're written by LYUpload_options() HTUnEscaped; + * don't want to change that for now... so pass through + * without more unescaping. Directory names containing + * '#' will probably fail. + */ + if (LYUpload(line_url)) + LYforce_no_cache = TRUE; + } else { + if (line[(strlen(line) - 1)] == '/') + line[strlen(line)-1] = '\0'; + if ((cp = strrchr(line, '/')) == NULL) { + FREE(line); + return 0; + } - *buffer = '\0'; - if (!strncmp(line,"LYNXDIRED://DECOMPRESS",22)) { - tp = quote_pathname(line+22); - sprintf(buffer,"%s %s", UNCOMPRESS_PATH, tp); - FREE(tp); + /* + * Construct the appropriate system command taking care to + * escape all path references to avoid spoofing the shell. + */ + *buffer = '\0'; + if (!strncmp(line, "LYNXDIRED://DECOMPRESS", 22)) { + tp = quote_pathname(line + 22); + sprintf(buffer,"%s %s", UNCOMPRESS_PATH, tp); + FREE(tp); #if defined(OK_UUDECODE) && !defined(ARCHIVE_ONLY) - } else if (!strncmp(line,"LYNXDIRED://UUDECODE",20)) { - tp = quote_pathname(line+20); - sprintf(buffer,"%s %s", UUDECODE_PATH, tp); - _statusline( + } else if (!strncmp(line, "LYNXDIRED://UUDECODE", 20)) { + tp = quote_pathname(line + 20); + sprintf(buffer,"%s %s", UUDECODE_PATH, tp); + _statusline( "Warning! UUDecoded file will exist in the directory you started Lynx."); - sleep(AlertSecs); - FREE(tp); + sleep(AlertSecs); + FREE(tp); #endif /* OK_UUDECODE && !ARCHIVE_ONLY */ #ifdef OK_TAR # ifndef ARCHIVE_ONLY # ifdef OK_GZIP - } else if (!strncmp(line,"LYNXDIRED://UNTAR_GZ",20)) { - tp = quote_pathname(line+20); - *cp++ = '\0'; - cp = quote_pathname(line+20); - sprintf(buffer, "%s -qdc %s | (cd %s; %s -xf -)", - GZIP_PATH, tp, cp, TAR_PATH); - FREE(cp); - FREE(tp); + } else if (!strncmp(line, "LYNXDIRED://UNTAR_GZ", 20)) { + tp = quote_pathname(line+20); + *cp++ = '\0'; + cp = quote_pathname(line + 20); + sprintf(buffer, "%s -qdc %s | (cd %s; %s -xf -)", + GZIP_PATH, tp, cp, TAR_PATH); + FREE(cp); + FREE(tp); # endif /* OK_GZIP */ - } else if (!strncmp(line,"LYNXDIRED://UNTAR_Z",19)) { - tp = quote_pathname(line+19); - *cp++ = '\0'; - cp = quote_pathname(line+19); - sprintf(buffer, "%s %s | (cd %s; %s -xf -)", - ZCAT_PATH, tp, cp, TAR_PATH); - FREE(cp); - FREE(tp); - - } else if (!strncmp(line,"LYNXDIRED://UNTAR",17)) { - tp = quote_pathname(line+17); - *cp++ = '\0'; - cp = quote_pathname(line+17); - sprintf(buffer,"cd %s; %s -xf %s", cp, TAR_PATH, tp); - FREE(cp); - FREE(tp); + } else if (!strncmp(line, "LYNXDIRED://UNTAR_Z", 19)) { + tp = quote_pathname(line + 19); + *cp++ = '\0'; + cp = quote_pathname(line + 19); + sprintf(buffer, "%s %s | (cd %s; %s -xf -)", + ZCAT_PATH, tp, cp, TAR_PATH); + FREE(cp); + FREE(tp); + + } else if (!strncmp(line, "LYNXDIRED://UNTAR", 17)) { + tp = quote_pathname(line + 17); + *cp++ = '\0'; + cp = quote_pathname(line + 17); + sprintf(buffer, "cd %s; %s -xf %s", cp, TAR_PATH, tp); + FREE(cp); + FREE(tp); # endif /* !ARCHIVE_ONLY */ # ifdef OK_GZIP - } else if (!strncmp(line,"LYNXDIRED://TAR_GZ",18)) { - *cp++ = '\0'; - cp = quote_pathname(cp); - tp = quote_pathname(line+18); - sprintf(buffer, "(cd %s; %s -cf - %s) | %s -qc >%s/%s.tar.gz", - tp, TAR_PATH, cp, GZIP_PATH, tp, cp); - FREE(cp); - FREE(tp); + } else if (!strncmp(line, "LYNXDIRED://TAR_GZ", 18)) { + *cp++ = '\0'; + cp = quote_pathname(cp); + tp = quote_pathname(line + 18); + sprintf(buffer, "(cd %s; %s -cf - %s) | %s -qc >%s/%s.tar.gz", + tp, TAR_PATH, cp, GZIP_PATH, tp, cp); + FREE(cp); + FREE(tp); # endif /* OK_GZIP */ - } else if (!strncmp(line,"LYNXDIRED://TAR_Z",17)) { - *cp++ = '\0'; - cp = quote_pathname(cp); - tp = quote_pathname(line+17); - sprintf(buffer, "(cd %s; %s -cf - %s) | %s >%s/%s.tar.Z", - tp, TAR_PATH, cp, COMPRESS_PATH, tp, cp); - FREE(cp); - FREE(tp); - - } else if (!strncmp(line,"LYNXDIRED://TAR",15)) { - *cp++ = '\0'; - cp = quote_pathname(cp); - tp = quote_pathname(line+15); - sprintf(buffer,"(cd %s; %s -cf %s.tar %s)", tp, TAR_PATH, cp, cp); - FREE(cp); - FREE(tp); + } else if (!strncmp(line, "LYNXDIRED://TAR_Z", 17)) { + *cp++ = '\0'; + cp = quote_pathname(cp); + tp = quote_pathname(line + 17); + sprintf(buffer, "(cd %s; %s -cf - %s) | %s >%s/%s.tar.Z", + tp, TAR_PATH, cp, COMPRESS_PATH, tp, cp); + FREE(cp); + FREE(tp); + + } else if (!strncmp(line, "LYNXDIRED://TAR", 15)) { + *cp++ = '\0'; + cp = quote_pathname(cp); + tp = quote_pathname(line + 15); + sprintf(buffer, "(cd %s; %s -cf %s.tar %s)", + tp, TAR_PATH, cp, cp); + FREE(cp); + FREE(tp); #endif /* OK_TAR */ #ifdef OK_GZIP - } else if (!strncmp(line,"LYNXDIRED://GZIP",16)) { - tp = quote_pathname(line+16); - sprintf(buffer,"%s -q %s", GZIP_PATH, tp); - FREE(tp); -# ifndef ARCHIVE_ONLY - } else if (!strncmp(line,"LYNXDIRED://UNGZIP",18)) { - tp = quote_pathname(line+18); - sprintf(buffer,"%s -d %s", GZIP_PATH, tp); - FREE(tp); -# endif /* !ARCHIVE_ONLY */ + } else if (!strncmp(line, "LYNXDIRED://GZIP", 16)) { + tp = quote_pathname(line + 16); + sprintf(buffer, "%s -q %s", GZIP_PATH, tp); + FREE(tp); +#ifndef ARCHIVE_ONLY + } else if (!strncmp(line, "LYNXDIRED://UNGZIP", 18)) { + tp = quote_pathname(line + 18); + sprintf(buffer, "%s -d %s", GZIP_PATH, tp); + FREE(tp); +#endif /* !ARCHIVE_ONLY */ #endif /* OK_GZIP */ #ifdef OK_ZIP - } else if (!strncmp(line,"LYNXDIRED://ZIP",15)) { - tp = quote_pathname(line+15); - *cp++ = '\0'; - bp = quote_pathname(cp); - cp = quote_pathname(line+15); - sprintf(buffer,"cd %s; %s -rq %s.zip %s", cp, ZIP_PATH, tp, bp); - FREE(cp); - FREE(bp); - FREE(tp); -# ifndef ARCHIVE_ONLY - } else if (!strncmp(line,"LYNXDIRED://UNZIP",17)) { - tp = quote_pathname(line+17); - *cp = '\0'; - cp = quote_pathname(line+17); - sprintf(buffer,"cd %s; %s -q %s", cp, UNZIP_PATH, tp); - FREE(cp); - FREE(tp); + } else if (!strncmp(line, "LYNXDIRED://ZIP", 15)) { + tp = quote_pathname(line + 15); + *cp++ = '\0'; + bp = quote_pathname(cp); + cp = quote_pathname(line + 15); + sprintf(buffer, "cd %s; %s -rq %s.zip %s", cp, ZIP_PATH, tp, bp); + FREE(cp); + FREE(bp); + FREE(tp); +#ifndef ARCHIVE_ONLY + } else if (!strncmp(line, "LYNXDIRED://UNZIP", 17)) { + tp = quote_pathname(line + 17); + *cp = '\0'; + cp = quote_pathname(line + 17); + sprintf(buffer, "cd %s; %s -q %s", cp, UNZIP_PATH, tp); + FREE(cp); + FREE(tp); # endif /* !ARCHIVE_ONLY */ #endif /* OK_ZIP */ - } else if (!strncmp(line,"LYNXDIRED://COMPRESS",20)) { - tp = quote_pathname(line+20); - sprintf(buffer,"%s %s",COMPRESS_PATH, tp); - FREE(tp); - } + } else if (!strncmp(line, "LYNXDIRED://COMPRESS", 20)) { + tp = quote_pathname(line + 20); + sprintf(buffer, "%s %s", COMPRESS_PATH, tp); + FREE(tp); + } - if (strlen(buffer)) { - if (strlen(buffer) < 60) - sprintf(tmpbuf,"Executing %s ",buffer); - else - sprintf(tmpbuf, - "Executing system command. This might take a while."); - _statusline(tmpbuf); - stop_curses(); - printf("%s\n", tmpbuf); - fflush(stdout); - system(buffer); + if (strlen(buffer)) { + if (strlen(buffer) < 60) { + sprintf(tmpbuf, "Executing %s ", buffer); + } else { + sprintf(tmpbuf, + "Executing system command. This might take a while."); + } + _statusline(tmpbuf); + stop_curses(); + printf("%s\n", tmpbuf); + fflush(stdout); + system(buffer); #ifdef VMS - extern BOOLEAN HadVMSInterrupt - HadVMSInterrupt = FALSE; + extern BOOLEAN HadVMSInterrupt + HadVMSInterrupt = FALSE; #endif /* VMS */ - start_curses(); - ++LYforce_no_cache; - } - } + start_curses(); + LYforce_no_cache = TRUE; + } + } - FREE(line); - LYpop(doc); - return 0; + FREE(line); + LYpop(doc); + return 0; } -/* Provide a menu of file management options. */ - +/* + * Provide a menu of file management options. + */ PUBLIC int dired_options ARGS2( document *, doc, char **, newfile) @@ -1531,13 +1606,13 @@ PUBLIC int dired_options ARGS2( struct stat dir_info; FILE *fp0; char *cp = NULL; - char * dir_url = NULL; /* will hold URL-escaped path of + char *dir_url = NULL; /* Will hold URL-escaped path of directory from where DIRED_MENU was - invoked (NOT its full URL) */ - char * path_url = NULL; /* will hold URL-escaped path of file + invoked (NOT its full URL). */ + char *path_url = NULL; /* Will hold URL-escaped path of file (or directory) which was selected when DIRED_MENU was invoked (NOT - its full URL) */ + its full URL). */ BOOLEAN nothing_tagged; int count; struct dired_menu *mp; @@ -1550,106 +1625,116 @@ PUBLIC int dired_options ARGS2( } if ((fp0 = fopen(tempfile,"w")) == NULL) { - _statusline("Unable to open file management menu file"); - sleep(AlertSecs); - return(0); + _statusline("Unable to open file management menu file."); + sleep(AlertSecs); + return(0); } + chmod(tempfile, 0600); /* make the tempfile a URL */ StrAllocCopy(*newfile, "file://localhost"); StrAllocCat(*newfile, tempfile); cp = doc->address; - if(!strncmp(cp,"file://localhost",16)) - cp += 16; - else if(!strncmp(cp,"file:",5)) - cp += 5; - strcpy(dir,cp); + if (!strncmp(cp, "file://localhost", 16)) { + cp += 16; + } else if (!strncmp(cp, "file:", 5)) { + cp += 5; + } + strcpy(dir, cp); StrAllocCopy(dir_url, cp); - if (dir_url[strlen(dir_url)-1] == '/') - dir_url[strlen(dir_url)-1] = '\0'; + if (dir_url[(strlen(dir_url) - 1)] == '/') + dir_url[(strlen(dir_url) - 1)] = '\0'; HTUnEscape(dir); - if (dir[strlen(dir)-1] == '/') - dir[strlen(dir)-1] = '\0'; + if (dir[(strlen(dir) - 1)] == '/') + dir[(strlen(dir) - 1)] = '\0'; if (doc->link > -1 && doc->link < (nlinks+1)) { - cp = links[doc->link].lname; - if(!strncmp(cp,"file://localhost",16)) - cp += 16; - else if(!strncmp(cp,"file:",5)) - cp += 5; - strcpy(path,cp); - StrAllocCopy(path_url,cp); - if (*path_url && path_url[1] && path_url[strlen(path_url)-1] == '/') - path_url[strlen(path_url)-1] = '\0'; - HTUnEscape(path); - if (*path && path[1] && path[strlen(path)-1] == '/') - path[strlen(path)-1] = '\0'; - - if (lstat(path,&dir_info) == -1 && stat(path,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",path); - _statusline(tmpbuf); - sleep(AlertSecs); - FREE(dir_url); - FREE(path_url); - return 0; - } + cp = links[doc->link].lname; + if (!strncmp(cp, "file://localhost", 16)) { + cp += 16; + } else if (!strncmp(cp, "file:", 5)) { + cp += 5; + } + strcpy(path, cp); + StrAllocCopy(path_url, cp); + if (*path_url && path_url[1] && path_url[(strlen(path_url) - 1)] == '/') + path_url[(strlen(path_url) - 1)] = '\0'; + HTUnEscape(path); + if (*path && path[1] && path[(strlen(path) - 1)] == '/') + path[(strlen(path) - 1)] = '\0'; + + if (lstat(path, &dir_info) == -1 && stat(path, &dir_info) == -1) { + sprintf(tmpbuf, "Unable to get status of '%s'.", path); + _statusline(tmpbuf); + sleep(AlertSecs); + FREE(dir_url); + FREE(path_url); + return 0; + } } else { - path[0] = '\0'; + path[0] = '\0'; StrAllocCopy(path_url, path); } nothing_tagged = (HTList_isEmpty(tagged)); - fprintf(fp0,"<head>\n<title>%s</title></head>\n<body>\n",DIRED_MENU_TITLE); + fprintf(fp0, + "<head>\n<title>%s</title></head>\n<body>\n", DIRED_MENU_TITLE); - fprintf(fp0,"\n<h1>File Management Options (%s Version %s)</h1>", - LYNX_NAME, LYNX_VERSION); + fprintf(fp0, + "\n<h1>File Management Options (%s Version %s)</h1>", + LYNX_NAME, LYNX_VERSION); - fprintf(fp0,"Current directory is %s <br>\n",dir); + fprintf(fp0, "Current directory is %s<br>\n", dir); - if (nothing_tagged) - if (strlen(path)) - fprintf(fp0,"Current selection is %s <p>\n",path); - else - fprintf(fp0,"Nothing currently selected. <p>\n"); - else { /* write out number of tagged items, and names of first - few of them relative to current (in the DIRED sense) directory */ + if (nothing_tagged) { + if (strlen(path)) { + fprintf(fp0, "Current selection is %s<p>\n", path); + } else { + fprintf(fp0, "Nothing currently selected.<p>\n"); + } + } else { + /* + * Write out number of tagged items, and names of first + * few of them relative to current (in the DIRED sense) + * directory. + */ int n = HTList_count(tagged); - char * cp1 = NULL; - char * cd = NULL; + char *cp1 = NULL; + char *cd = NULL; int i, m; #define NUM_TAGS_TO_WRITE 10 - fprintf(fp0,"Current selection is %d tagged item%s", - n, (n==1 ? ":" : "s:")); + fprintf(fp0, "Current selection is %d tagged item%s", + n, ((n == 1) ? ":" : "s:")); StrAllocCopy(cd, doc->address); HTUnEscapeSome(cd, "/"); - if (*cd && cd[strlen(cd)-1] != '/') + if (*cd && cd[(strlen(cd) - 1)] != '/') StrAllocCat(cd, "/"); m = (n < NUM_TAGS_TO_WRITE) ? n : NUM_TAGS_TO_WRITE; - for (i=1; i <= m; i++) { - cp1 = HTRelative(HTList_objectAt(tagged, i-1), + for (i = 1; i <= m; i++) { + cp1 = HTRelative(HTList_objectAt(tagged, i-1), (*cd ? cd : "file://localhost")); - HTUnEscape(cp1); - LYEntify(&cp1, TRUE); /* _should_ do this everywhere... */ - fprintf(fp0,"%s <br>\n %s", - (i==1 ? "" : " ,"), cp1); - FREE(cp1); + HTUnEscape(cp1); + LYEntify(&cp1, TRUE); /* _should_ do this everywhere... */ + fprintf(fp0, "%s <br>\n %s", + (i == 1 ? "" : " ,"), cp1); + FREE(cp1); } if (n > m) { fprintf(fp0," , ..."); } - fprintf(fp0, " <p>\n"); + fprintf(fp0, "<p>\n"); FREE(cd); } /* - * if menu_head is NULL then use defaults and link them together now + * If menu_head is NULL then use defaults and link them together now. */ if (menu_head == NULL) { - for (mp = defmenu; mp->href != NULL ; mp++) - mp->next = mp + 1; + for (mp = defmenu; mp->href != NULL; mp++) + mp->next = (mp + 1); (--mp)->next = NULL; menu_head = defmenu; } @@ -1670,7 +1755,7 @@ PUBLIC int dired_options ARGS2( continue; if (*mp->sfx && (strlen(path) < strlen(mp->sfx) || - strcmp(mp->sfx, &path[strlen(path)-strlen(mp->sfx)]) != 0)) + strcmp(mp->sfx, &path[(strlen(path) - strlen(mp->sfx))]) != 0)) continue; fprintf(fp0, "<a href=\"%s", render_item(mp->href, path_url, dir_url, buf,2048, YES)); @@ -1681,24 +1766,30 @@ PUBLIC int dired_options ARGS2( } if (uploaders != NULL) { - fprintf(fp0, "<p>Upload to current directory:<p>\n"); - for (count=0, nxt = uploaders; nxt != NULL; nxt = nxt->next, count++) { - fprintf(fp0,"<a href=\"LYNXDIRED://UPLOAD=%d/TO=%s\"> %s </a><br>\n", - count,dir,nxt->name); - } + fprintf(fp0, "<p>Upload to current directory:<p>\n"); + for (count = 0, nxt = uploaders; + nxt != NULL; + nxt = nxt->next, count++) { + fprintf(fp0, + "<a href=\"LYNXDIRED://UPLOAD=%d/TO=%s\"> %s </a><br>\n", + count, dir, nxt->name); + } } - fprintf(fp0,"</body>\n"); + fprintf(fp0, "</body>\n"); fclose(fp0); FREE(dir_url); FREE(path_url); - LYforce_no_cache = 1; + LYforce_no_cache = TRUE; return(0); } +/* + * Execute DIRED command. + */ PRIVATE int my_spawn ARGS3( char *, path, char **, argv, @@ -1718,26 +1809,26 @@ PRIVATE int my_spawn ARGS3( stop_curses(); pid = fork(); /* fork and execute rm */ switch (pid) { - case -1: - sprintf(tmpbuf, "Unable to %s due to system error!", msg); - rc = 0; - break; /* don't fall thru! - KW */ - case 0: /* child */ - execv(path, argv); - exit(-1); /* execv failed, give wait() something to look at */ - default: /* parent */ + case -1: + sprintf(tmpbuf, "Unable to %s due to system error!", msg); + rc = 0; + break; /* don't fall thru! - KW */ + case 0: /* child */ + execv(path, argv); + exit(-1); /* execv failed, give wait() something to look at */ + default: /* parent */ #if defined(NeXT) || defined(AIX4) || defined(sony_news) - while (wait(&wstatus) != pid) - ; /* do nothing */ + while (wait(&wstatus) != pid) + ; /* do nothing */ #else - waitpid(pid, &wstatus, 0); /* wait for child */ + waitpid(pid, &wstatus, 0); /* wait for child */ #endif /* NeXT || AIX4 || sony_news */ - if (WEXITSTATUS(wstatus) != 0 || - WTERMSIG(wstatus) > 0) { /* error return */ - sprintf(tmpbuf, "Probable failure to %s due to system error!", - msg); - rc = 0; - } + if (WEXITSTATUS(wstatus) != 0 || + WTERMSIG(wstatus) > 0) { /* error return */ + sprintf(tmpbuf, "Probable failure to %s due to system error!", + msg); + rc = 0; + } } #ifdef VMS { @@ -1762,133 +1853,141 @@ PRIVATE int my_spawn ARGS3( return(rc); } +/* + * Check DIRED filename. + */ PRIVATE char *filename ARGS3( char *, prompt, char *, buf, int, bufsize) { - char *cp; + char *cp; - _statusline(prompt); + _statusline(prompt); - *buf = '\0'; - LYgetstr(buf, VISIBLE, bufsize, NORECALL); - if(strstr(buf,"../") != NULL) { - _statusline("Illegal filename; request ignored."); - sleep(AlertSecs); - return NULL; - } + *buf = '\0'; + LYgetstr(buf, VISIBLE, bufsize, NORECALL); + if (strstr(buf, "../") != NULL) { + _statusline("Illegal filename; request ignored."); + sleep(AlertSecs); + return NULL; + } - if (no_dotfiles || !show_dotfiles) { - cp = strrchr(buf, '/'); /* find last slash */ - if (cp) - cp += 1; - else - cp = buf; - if (*cp == '.') { - _statusline("Illegal filename; request ignored."); - sleep(AlertSecs); - return NULL; - } - } - return buf; + if (no_dotfiles || !show_dotfiles) { + cp = strrchr(buf, '/'); /* find last slash */ + if (cp) + cp += 1; + else + cp = buf; + if (*cp == '.') { + _statusline("Illegal filename; request ignored."); + sleep(AlertSecs); + return NULL; + } + } + return buf; } -/* Install the specified file or directory. */ - +/* + * Install the specified file or directory. + */ PUBLIC BOOLEAN local_install ARGS3( char *, destpath, char *, srcpath, char **, newpath) { - char tmpbuf[512]; - static char savepath[512]; /* this will be the link that is to be installed */ - struct stat dir_info; - char *args[6]; - HTList *tag; - int count = 0; - int n = 0, src; /* indices into 'args[]' */ - -/* Determine the status of the selected item. */ - - if (srcpath) { - srcpath = strip_trailing_slash(srcpath); - - if(strncmp(srcpath,"file://localhost",16) == 0) - srcpath += 16; - if (stat(srcpath,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",srcpath); - _statusline(tmpbuf); - sleep(AlertSecs); - return 0; - } else if ((dir_info.st_mode & S_IFMT) != S_IFDIR && - (dir_info.st_mode & S_IFMT) != S_IFREG) { - _statusline( - "The selected item is not a file or a directory! Request ignored. "); - sleep(AlertSecs); - return 0; - } - strcpy(savepath, srcpath); - ++LYforce_no_cache; - strcpy(tmpbuf, "file://localhost"); - strcat(tmpbuf, Home_Dir()); - strcat(tmpbuf, "/.installdirs.html"); - StrAllocCopy(*newpath, tmpbuf); - return 0; - } + char tmpbuf[512]; + static char savepath[512]; /* This will be the link that + is to be installed. */ + struct stat dir_info; + char *args[6]; + HTList *tag; + int count = 0; + int n = 0, src; /* indices into 'args[]' */ - destpath = strip_trailing_slash(destpath); - - if (stat(destpath,&dir_info) == -1) { - sprintf(tmpbuf,"Unable to get status of %s ",destpath); - _statusline(tmpbuf); - sleep(AlertSecs); - return 0; - } else if ((dir_info.st_mode & S_IFMT) != S_IFDIR) { - _statusline( - "The selected item is not a directory! Request ignored. "); - sleep(AlertSecs); - return 0; - } else if (0 /*directory not writeable*/) { - _statusline("Install in the selected directory not permitted."); - sleep(AlertSecs); - return 0; - } + /* + * Determine the status of the selected item. + */ + if (srcpath) { + srcpath = strip_trailing_slash(srcpath); + if (strncmp(srcpath, "file://localhost", 16) == 0) + srcpath += 16; + if (stat(srcpath, &dir_info) == -1) { + sprintf(tmpbuf, "Unable to get status of '%s'.", srcpath); + _statusline(tmpbuf); + sleep(AlertSecs); + return 0; + } else if ((dir_info.st_mode & S_IFMT) != S_IFDIR && + (dir_info.st_mode & S_IFMT) != S_IFREG) { + _statusline( + "The selected item is not a file or a directory! Request ignored."); + sleep(AlertSecs); + return 0; + } + strcpy(savepath, srcpath); + LYforce_no_cache = TRUE; + strcpy(tmpbuf, "file://localhost"); + strcat(tmpbuf, Home_Dir()); + strcat(tmpbuf, "/.installdirs.html"); + StrAllocCopy(*newpath, tmpbuf); + return 0; + } + + destpath = strip_trailing_slash(destpath); + + if (stat(destpath,&dir_info) == -1) { + sprintf(tmpbuf,"Unable to get status of '%s'.",destpath); + _statusline(tmpbuf); + sleep(AlertSecs); + return 0; + } else if ((dir_info.st_mode & S_IFMT) != S_IFDIR) { + _statusline( + "The selected item is not a directory! Request ignored."); + sleep(AlertSecs); + return 0; + } else if (0 /*directory not writeable*/) { + _statusline("Install in the selected directory not permitted."); + sleep(AlertSecs); + return 0; + } - statusline("Just a moment, ..."); - args[n++] = "install"; + statusline("Just a moment, ..."); + args[n++] = "install"; #ifdef INSTALL_ARGS - args[n++] = INSTALL_ARGS; -#endif - src = n++; - args[n++] = destpath; - args[n] = (char *) 0; - sprintf(tmpbuf, "install %s", destpath); - tag = tagged; - - if (HTList_isEmpty(tagged)) { - args[src] = savepath; - if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0) - return (-1); - count++; - } else { - char * name; - while ((name = (char *)HTList_nextObject(tag))) { - args[src] = name; - if (strncmp("file://localhost", args[src], 16) == 0) - args[src] = name + 16; - - if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0) - return ((count == 0) ? -1 : count); - count++; - } - clear_tags(); - } - statusline("Installation complete"); - sleep(InfoSecs); - return count; + args[n++] = INSTALL_ARGS; +#endif /* INSTALL_ARGS */ + src = n++; + args[n++] = destpath; + args[n] = (char *)0; + sprintf(tmpbuf, "install %s", destpath); + tag = tagged; + + if (HTList_isEmpty(tagged)) { + args[src] = savepath; + if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0) + return (-1); + count++; + } else { + char *name; + while ((name = (char *)HTList_nextObject(tag))) { + args[src] = name; + if (strncmp("file://localhost", args[src], 16) == 0) + args[src] = (name + 16); + + if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0) + return ((count == 0) ? -1 : count); + count++; + } + clear_tags(); + } + statusline("Installation complete"); + sleep(InfoSecs); + return count; } +/* + * Clear DIRED tags. + */ PUBLIC void clear_tags NOARGS { char *cp = NULL; @@ -1900,6 +1999,9 @@ PUBLIC void clear_tags NOARGS FREE(tagged); } +/* + * Handle DIRED menu item. + */ PUBLIC void add_menu_item ARGS1( char *, str) { @@ -1907,27 +2009,32 @@ PUBLIC void add_menu_item ARGS1( char *cp; /* - * First custom menu definition causes entire default menu to be - * discarded. + * First custom menu definition causes entire default menu to be + * discarded. */ if (menu_head == defmenu) menu_head = NULL; new = (struct dired_menu *)calloc(1, sizeof(*new)); - /* conditional on tagged != NULL ? */ + /* + * Conditional on tagged != NULL ? + */ cp = strchr(str, ':'); *cp++ = '\0'; - if (strcasecomp(str, "tag") == 0) + if (strcasecomp(str, "tag") == 0) { new->cond = DE_TAG; - else if (strcasecomp(str, "dir") == 0) + } else if (strcasecomp(str, "dir") == 0) { new->cond = DE_DIR; - else if (strcasecomp(str, "file") == 0) + } else if (strcasecomp(str, "file") == 0) { new->cond = DE_FILE; - else if (strcasecomp(str, "link") == 0) + } else if (strcasecomp(str, "link") == 0) { new->cond = DE_SYMLINK; + } - /* conditional on matching suffix */ + /* + * Conditional on matching suffix. + */ str = cp; cp = strchr(str, ':'); *cp++ = '\0'; @@ -1953,6 +2060,9 @@ PUBLIC void add_menu_item ARGS1( menu_head = new; } +/* + * Create URL for DIRED HREF value. + */ PRIVATE char * render_item ARGS6( char *, s, char *, path, @@ -1961,19 +2071,18 @@ PRIVATE char * render_item ARGS6( int, bufsize, BOOLEAN, url_syntax) { - char *cp; - char *bp; - char overrun = '\0'; - char *taglist = NULL; + char *cp; + char *bp; + char overrun = '\0'; + char *taglist = NULL; #define BP_INC (bp>buf+bufsize-2 ? &overrun : bp++) /* Buffer overrun could happen for very long - tag list, if %l or %t are used */ - - bp = buf; - while (*s && !overrun) { - if (*s == '%') { - s++; - switch (*s) { + tag list, if %l or %t are used */ + bp = buf; + while (*s && !overrun) { + if (*s == '%') { + s++; + switch (*s) { case '%': *BP_INC = '%'; #ifdef NOTDEFINED @@ -2013,8 +2122,8 @@ PRIVATE char * render_item ARGS6( HTList *cur = tagged; char *name; - while(!overrun && - (name = (char *)HTList_nextObject(cur))!=NULL) { + while (!overrun && + (name = (char *)HTList_nextObject(cur))!=NULL) { if (*s == 'l' && (cp = strrchr(name, '/'))) cp++; else @@ -2041,24 +2150,24 @@ PRIVATE char * render_item ARGS6( #endif /* NOTDEFINED */ *BP_INC =*s; break; - } - } else { - /* - * Other chars come from the lynx.cfg or - * the default. Let's assume there isn't - * anything weird there that needs escaping. - */ - *BP_INC =*s; } - s++; - } - if (overrun & url_syntax) { - sprintf(buf,"Temporary URL or list would be too long."); - _statusline(buf); - sleep(AlertSecs); - bp = buf; /* set to start, will return empty string as URL */ + } else { + /* + * Other chars come from the lynx.cfg or + * the default. Let's assume there isn't + * anything weird there that needs escaping. + */ + *BP_INC =*s; } - *bp = '\0'; - return buf; + s++; + } + if (overrun & url_syntax) { + sprintf(buf,"Temporary URL or list would be too long."); + _statusline(buf); + sleep(AlertSecs); + bp = buf; /* set to start, will return empty string as URL */ + } + *bp = '\0'; + return buf; } #endif /* DIRED_SUPPORT */ diff --git a/src/LYMail.c b/src/LYMail.c index 271d2af3..d85a12ae 100644 --- a/src/LYMail.c +++ b/src/LYMail.c @@ -1,5 +1,7 @@ #include "HTUtils.h" #include "tcp.h" +#include "HTParse.h" +#include "LYGlobalDefs.h" #include "HTAlert.h" #include "LYCurses.h" #include "LYSignal.h" @@ -8,8 +10,6 @@ #include "LYStrings.h" #include "GridText.h" #include "LYSystem.h" -#include "LYGlobalDefs.h" -#include "HTParse.h" #include "LYMail.h" #ifdef EXP_CHARTRANS #include "LYCharSets.h" /* to get current charset for mail header */ @@ -188,6 +188,7 @@ PUBLIC void mailform ARGS4( FREE(address); return; } + chmod(tmpfile, 0600); if (*self) { cp = self; while (*cp == ' ' || *cp == ',') @@ -328,6 +329,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address, FILE *fd, *fp; char *address = NULL; char cmd[512], *cp, *cp0, *cp1; + int i; #if defined(VMS) || defined(DOSPATH) char my_tempfile[256]; char *address_ptr1, *address_ptr2; @@ -382,6 +384,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address, FREE(address); return; } + chmod(tmpfile, 0600); #endif /* VMS */ fprintf(fd, "The link %s :?: %s \n", @@ -454,6 +457,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address, #endif /* SIGTSTP */ exit(-1); } + chmod(TRAVERSE_ERRORS, 0600); } fprintf(ofp, "%s %s in %s\n", @@ -520,6 +524,7 @@ PUBLIC void reply_by_mail ARGS3( HTAlert(MAILTO_URL_TEMPOPEN_FAILED); return; } + chmod(my_tempfile, 0600); subject[0] = '\0'; /* @@ -727,17 +732,22 @@ PUBLIC void reply_by_mail ARGS3( * as display character set... * Don't send a charset if we have a CJK character set * selected, since it may not be appropriate for mail... - * Also don't use an inofficial "x-" charset. - kw + * Also don't use an inofficial "x-" charset. + * Also if the charset would be "us-ascii" (7-bit replacements + * selected, don't send any MIME headers. - kw */ - StrAllocCat(header, "Mime-Version: 1.0\n"); - if (!LYHaveCJKCharacterSet && - strncasecomp(LYCharSet_UC[current_char_set].MIMEname, "x-", 2) - != 0) { - sprintf(buf,"Content-Type: text/plain; charset=%s\n", - LYCharSet_UC[current_char_set].MIMEname); - StrAllocCat(header, buf); + if (strncasecomp(LYCharSet_UC[current_char_set].MIMEname, + "us-ascii", 8) != 0) { + StrAllocCat(header, "Mime-Version: 1.0\n"); + if (!LYHaveCJKCharacterSet && + strncasecomp(LYCharSet_UC[current_char_set].MIMEname, "x-", 2) + != 0) { + sprintf(buf,"Content-Type: text/plain; charset=%s\n", + LYCharSet_UC[current_char_set].MIMEname); + StrAllocCat(header, buf); + } + StrAllocCat(header, "Content-Transfer-Encoding: 8bit\n"); } - StrAllocCat(header, "Content-Transfer-Encoding: 8bit\n"); #endif /* * Put the X-URL and X-Mailer lines in the header. @@ -966,7 +976,9 @@ PUBLIC void reply_by_mail ARGS3( !term_letter && c != 7 && c != 3) c = LYgetch(); if (TOUPPER(c) == 'Y') { - /* the 1 will add the reply ">" in front of every line */ + /* + * The 1 will add the reply "> " in front of every line. + */ print_wwwfile_to_fd(fd, 1); } } diff --git a/src/LYMain.c b/src/LYMain.c index 85d7d55e..b6d4297f 100644 --- a/src/LYMain.c +++ b/src/LYMain.c @@ -4,6 +4,8 @@ #include "HTAccess.h" #include "HTList.h" #include "HTFile.h" +#include "UCMap.h" +#include "UCDefs.h" #ifdef VMS #include "HTVMSUtils.h" #endif /* VMS */ @@ -152,6 +154,7 @@ PUBLIC lynx_html_item_type *externals = NULL; PUBLIC lynx_html_item_type *uploaders = NULL; PUBLIC int port_syntax = 1; PUBLIC BOOLEAN LYShowCursor = SHOW_CURSOR; /* to show or not to show */ +PUBLIC BOOLEAN LYUseDefShoCur = TRUE; /* Command line -show_cursor toggle */ PUBLIC BOOLEAN LYforce_no_cache = FALSE; PUBLIC BOOLEAN LYoverride_no_cache = FALSE; PUBLIC BOOLEAN LYresubmit_posts = ALWAYS_RESUBMIT_POSTS; @@ -289,8 +292,10 @@ PUBLIC BOOLEAN no_url_redirection = FALSE; /* Don't follow URL redirections */ PUBLIC char *form_post_data = NULL; /* User data for post form */ PUBLIC char *form_get_data = NULL; /* User data for get form */ PUBLIC char *http_error_file = NULL; /* Place HTTP status code in this file */ - /* Id:Password for protected forms */ + /* Id:Password for protected documents */ PUBLIC char *authentication_info[2] = {NULL, NULL}; + /* Id:Password for protected proxy servers */ +PUBLIC char *proxyauth_info[2] = {NULL, NULL}; PUBLIC char *MBM_A_subbookmark[MBM_V_MAXFILES+1]; PUBLIC char *MBM_A_subdescript[MBM_V_MAXFILES+1]; @@ -345,7 +350,11 @@ PUBLIC FILE *LYTraceLogFP = NULL; /* Pointer for TRACE log */ PUBLIC char *LYTraceLogPath = NULL; /* Path for TRACE log */ PUBLIC BOOLEAN LYUseTraceLog = USE_TRACE_LOG; /* Use a TRACE log? */ PUBLIC FILE LYOrigStderr; /* Original stderr pointer */ +PUBLIC BOOLEAN LYSeekFragMAPinCur = TRUE; +PUBLIC BOOLEAN LYSeekFragAREAinCur = TRUE; + PUBLIC BOOLEAN LYStripDotDotURLs = FALSE; /* Try to fix ../ in some URLs? */ +PUBLIC BOOLEAN LYForceSSLCookiesSecure = FALSE; /* These are declared in cutil.h for current freeWAIS libraries. - FM */ #ifdef DECLARE_WAIS_LOGFILES @@ -363,6 +372,7 @@ PRIVATE char *terminal = NULL; PRIVATE char *pgm; PRIVATE BOOLEAN number_links = FALSE; PRIVATE BOOLEAN LYPrependBase = FALSE; +PRIVATE HTList *LYStdinArgs = NULL; PRIVATE void parse_arg PARAMS((char **arg, int *i, int argc)); #ifndef VMS @@ -437,6 +447,8 @@ PRIVATE void free_lynx_globals NOARGS FREE(editor); FREE(authentication_info[0]); FREE(authentication_info[1]); + FREE(proxyauth_info[0]); + FREE(proxyauth_info[1]); FREE(lynxjumpfile); FREE(startrealm); FREE(personal_mail_address); @@ -456,31 +468,24 @@ PRIVATE void free_lynx_globals NOARGS char *lynx_lss_file=NULL; #endif -PRIVATE char *make_homedir_lynxrc_filename ARGS1(char *, name) + +/* + * This function frees the LYStdinArgs list. - FM + */ +PRIVATE void LYStdinArgs_free NOARGS { - char *home = NULL; + char *argument; + HTList *cur = LYStdinArgs; - if (name == NULL) - { -#if defined(UNIX) && !defined(DJGPP) - name = "/.lynxrc"; -#else - name = "/lynx.rc"; -#endif - } + if (cur == NULL) + return; -#ifdef DOSPATH - StrAllocCopy(home, HTDOS_wwwName((char *)Home_Dir())); -#else -#ifdef VMS - StrAllocCopy(home, HTVMS_wwwName((char *)Home_Dir())); -#else - StrAllocCopy(home, Home_Dir()); -#endif /* VMS */ -#endif /* DOSPATH */ - - StrAllocCat(home, name); - return home; + while (NULL != (argument = (char *)HTList_nextObject(cur))) { + FREE(argument); + } + HTList_delete(LYStdinArgs); + LYStdinArgs = NULL; + return; } /* @@ -498,29 +503,30 @@ PUBLIC int main ARGS2( char *cp; FILE *fp; char filename[256]; + BOOL LYGetStdinArgs = FALSE; #ifdef _WINDOWS -WSADATA WSAData; - { - int err; - WORD wVerReq; - - _fmode = O_BINARY; - - wVerReq = MAKEWORD(1,1); - - err = WSAStartup(wVerReq, &WSAData); - if (err != 0) - { - printf("No Winsock found, sorry."); - sleep(5); - return; - } - } + WSADATA WSAData; + { + int err; + WORD wVerReq; + + _fmode = O_BINARY; + + wVerReq = MAKEWORD(1,1); + + err = WSAStartup(wVerReq, &WSAData); + if (err != 0) + { + printf("No Winsock found, sorry."); + sleep(5); + return; + } + } #endif /* _WINDOWS */ #ifdef DJGPP - sock_init(); + sock_init(); #endif #ifdef DOSPATH @@ -535,6 +541,15 @@ WSADATA WSAData; pgm = cp + 1; } + /* + * Act on -help NOW, so we only output the help and exit. - FM + */ + for (i = 1; i < argc; i++) { + if (strncmp(argv[i], "-help", 5) == 0) { + parse_arg(&argv[i], &i, argc); + } + } + #ifdef LY_FIND_LEAKS /* * Register the final function to be executed when being exited. @@ -608,6 +623,21 @@ WSADATA WSAData; StrAllocCopy(pref_charset, PREFERRED_CHARSET); StrAllocCopy(system_mail, SYSTEM_MAIL); StrAllocCopy(system_mail_flags, SYSTEM_MAIL_FLAGS); + StrAllocCopy(LYUserAgent, LYNX_NAME); + StrAllocCat(LYUserAgent, "/"); + StrAllocCat(LYUserAgent, LYNX_VERSION); + if (HTLibraryVersion) { + StrAllocCat(LYUserAgent, " libwww-FM/"); + StrAllocCat(LYUserAgent, HTLibraryVersion); + } + StrAllocCopy(LYUserAgentDefault, LYUserAgent); +#ifdef VMS + Define_VMSLogical("LYNX_VERSION", LYNX_VERSION); +#else + StrAllocCopy(lynx_version_putenv_command, "LYNX_VERSION="); + StrAllocCat(lynx_version_putenv_command, LYNX_VERSION); + putenv(lynx_version_putenv_command); +#endif /* VMS */ #ifdef DOSPATH if ((cp = getenv("TEMP")) != NULL) StrAllocCopy(lynx_temp_space, cp); @@ -637,21 +667,20 @@ WSADATA WSAData; StrAllocCopy(lynx_temp_space, temp); FREE(temp); } - StrAllocCopy(LYUserAgent, LYNX_NAME); - StrAllocCat(LYUserAgent, "/"); - StrAllocCat(LYUserAgent, LYNX_VERSION); - if (HTLibraryVersion) { - StrAllocCat(LYUserAgent, " libwww-FM/"); - StrAllocCat(LYUserAgent, HTLibraryVersion); + if ((cp = strstr(lynx_temp_space, "$USER")) != NULL) { + char *cp1; + + if ((cp1 = (char *)getenv("USER")) != NULL) { + *cp = '\0'; + StrAllocCopy(temp, lynx_temp_space); + *cp = '$'; + StrAllocCat(temp, cp1); + cp += 5; + StrAllocCat(temp, cp); + StrAllocCopy(lynx_temp_space, temp); + FREE(temp); + } } - StrAllocCopy(LYUserAgentDefault, LYUserAgent); -#ifdef VMS - Define_VMSLogical("LYNX_VERSION", LYNX_VERSION); -#else - StrAllocCopy(lynx_version_putenv_command, "LYNX_VERSION="); - StrAllocCat(lynx_version_putenv_command, LYNX_VERSION); - putenv(lynx_version_putenv_command); -#endif /* VMS */ #ifdef VMS for (i = 0; lynx_temp_space[i]; i++) lynx_temp_space[i] = TOLOWER(lynx_temp_space[i]); @@ -751,10 +780,163 @@ WSADATA WSAData; StrAllocCopy(lynx_cfg_file, argv[i+1]); i++; } - } else if (strncmp(argv[i], "-help", 5) == 0) { - parse_arg(&argv[i], &i, argc); } } + + /* + * If we have a lone "-" switch for getting arguments from stdin, + * get them NOW, and act on the relevant ones, saving the others + * into an HTList for handling after the other initializations. + * The primary purpose of this feature is to allow for the + * potentially very long command line that can be associated with + * post or get data. The original implementation required that + * the lone "-" be the only command line argument, but that + * precluded its use when the lynx command is aliased with other + * arguments. When interactive, the stdin input is terminated by + * by Control-D on Unix or Control-Z on VMS, and each argument + * is terminated by a RETURN. When the argument is -get_data or + * -post_data, the data are terminate by a "___" string, alone + * on the line (also terminated by RETURN). - FM + */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-") == 0) { + LYGetStdinArgs = TRUE; + } + } + if (LYGetStdinArgs == TRUE) { + char buf[1025]; + + while (fgets(buf, sizeof(buf) - 1, stdin)) { + int j; + + for (j = strlen(buf) - 1; j > 0 && + (buf[j] == CR || buf[j] == LF); j--) { + buf[j] = '\0'; + } + + if (strncmp(buf, "-trace", 6) == 0) { + WWW_TraceFlag = TRUE; + } else if (strncmp(buf, "-tlog", 5) == 0) { + if (LYUseTraceLog) { + LYUseTraceLog = FALSE; + } else { + LYUseTraceLog = TRUE; + } + } else if (strncmp(buf, "-anonymous", 10) == 0) { + if (!LYValidate && !anon_restrictions_set) + parse_restrictions("default"); + anon_restrictions_set = TRUE; + } else if (strcmp(buf, "-validate") == 0) { + /* + * Follow only http URLs. + */ + LYValidate = TRUE; +#ifdef SOCKS + } else if (strncmp(buf, "-nosocks", 8) == 0) { + socks_flag = FALSE; +#endif /* SOCKS */ + } else if (strncmp(buf, "-cfg", 4) == 0) { + if ((cp = strchr(buf,'=')) != NULL) { + StrAllocCopy(lynx_cfg_file, cp+1); + } else { + cp = buf; + while (*cp && !isspace((unsigned char)*cp)) + cp++; + while (*cp && isspace((unsigned char)*cp)) + cp++; + if (*cp) + StrAllocCopy(lynx_cfg_file, cp); + } + } else if (strcmp(buf, "-get_data") == 0) { + /* + * User data for GET form. + */ + char **get_data; + + /* + * On Unix, conflicts with curses when interactive + * so let's force a dump. - CL + * + * On VMS, mods have been made in LYCurses.c to deal + * with potential conflicts, so don't force the dump + * here. - FM + */ +#ifndef VMS + dump_output_immediately = TRUE; + LYcols = 80; +#endif /* VMS */ + + StrAllocCopy(form_get_data, "?"); /* Prime the pump */ + get_data = &form_get_data; + + /* + * Build GET data for later. Stop reading when we see + * a line with "---" as its first three characters. + */ + while (fgets(buf, sizeof(buf), stdin) && + strncmp(buf, "---", 3) != 0) { + int j; + + /* + * Strip line terminators. + */ + for (j = strlen(buf) - 1; j >= 0 && + (buf[j] == CR || buf[j] == LF); j--) { + buf[j] = '\0'; + } + StrAllocCat(*get_data, buf); + } + } else if (strcmp(buf, "-post_data") == 0) { + /* + * User data for POST form. + */ + char **post_data; + + /* + * On Unix, conflicts with curses when interactive + * so let's force a dump. - CL + * + * On VMS, mods have been made in LYCurses.c to deal + * with potential conflicts, so don't force a dump + * here. - FM + */ +#ifndef VMS + dump_output_immediately = TRUE; + LYcols = 80; +#endif /* VMS */ + + post_data = &form_post_data; + + /* + * Build post data for later. Stop reading when we see + * a line with "---" as its first three characters. + */ + while (fgets(buf, sizeof(buf), stdin) && + strncmp(buf, "---", 3) != 0) { + int j; + + /* + * Strip line terminators. + */ + for (j = strlen(buf) - 1; j >= 0 && + (buf[j] == CR || buf[j] == LF); j--) { + buf[j] = '\0'; + } + StrAllocCat(*post_data, buf); + } + } else if (buf[0] != '\0') { + char *argument = NULL; + + if (LYStdinArgs == NULL) { + LYStdinArgs = HTList_new(); + atexit(LYStdinArgs_free); + } + StrAllocCopy(argument, buf); + HTList_appendObject(LYStdinArgs, argument); + } + } + } + #ifdef SOCKS if (socks_flag) SOCKSinit(argv[0]); @@ -825,6 +1007,7 @@ WSADATA WSAData; exit(-1); } #endif /* VMS */ + chmod(LYTraceLogPath, 0600); *stderr = *LYTraceLogFP; fprintf(stderr, "\t\t%s\n\n", LYNX_TRACELOG_TITLE); } @@ -868,21 +1051,6 @@ WSADATA WSAData; StrAllocCopy(lynx_cfg_file, cp); } - /* If we still have no config file, check one in home directory */ - if (NULL == lynx_cfg_file) - { - temp = make_homedir_lynxrc_filename (NULL); - if (temp != NULL) - { - if (NULL != (fp = fopen (temp, "r"))) - { - fclose (fp); - StrAllocCopy (lynx_cfg_file, temp); - } - FREE(temp); - } - } - /* * If we still don't have a configuration file, * use the userdefs.h definition. @@ -897,10 +1065,14 @@ WSADATA WSAData; /* I think this should only be performed if lynx_cfg_file starts with ~/ */ if ((lynx_cfg_file[0] == '~') && (lynx_cfg_file[1] == '/')) { - temp = make_homedir_lynxrc_filename (lynx_cfg_file + 2); - FREE(lynx_cfg_file); - lynx_cfg_file = temp; - temp = NULL; +#ifdef VMS + StrAllocCopy(temp, HTVMS_wwwName((char *)Home_Dir())); +#else + StrAllocCopy(temp, Home_Dir()); +#endif /* VMS */ + StrAllocCat(temp, lynx_cfg_file + 1); + StrAllocCopy(lynx_cfg_file, temp); + FREE(temp); } #endif @@ -1119,37 +1291,25 @@ WSADATA WSAData; LYEnsureAbsoluteURL((char **)&LynxHome, "LynxHome"); /* - * Process arguments - with none, look for the database in STARTDIR, - * starting with STARTFILE. - * - * If a pathname is given, use it as the starting point. Split it - * into directory and file components, 'cd' to the directory, and - * view the file. - * - * If the only argument is '-' then we expect to see the arguments on - * stdin, this is to allow for the potentially very long command line - * that can be associated with post or get data. + * Process any command line arguments not already handled. - FM */ - if (argc == 2 && strcmp(argv[1], "-") == 0) { - char buf[1025]; - char *my_args[2]; - - my_args[0] = buf; - my_args[1] = NULL; - - while (fgets(buf, sizeof(buf) - 1, stdin)) { - int j; - - for (j = strlen(buf) - 1; j > 0 && - (buf[j] == CR || buf[j] == LF); j--) { - buf[j] = '\0'; - } - parse_arg(my_args, NULL, -1); - } - } else { - for (i = 1; i < argc; i++) { - parse_arg(&argv[i], &i, argc); + for (i = 1; i < argc; i++) { + parse_arg(&argv[i], &i, argc); + } + + /* + * Process any stdin-derived arguments for a lone "-" which we've + * loaded into LYStdinArgs. - FM + */ + if (LYStdinArgs != NULL) { + char *argv[2]; + HTList *cur = LYStdinArgs; + + argv[1] = NULL; + while (NULL != (argv[0] = (char *)HTList_nextObject(cur))) { + parse_arg(argv, NULL, -1); } + LYStdinArgs_free(); } #ifndef VMS @@ -1182,7 +1342,7 @@ WSADATA WSAData; if (vi_keys) set_vi_keys(); - if (number_links) + if (number_links && keypad_mode == NUMBERS_AS_ARROWS) keypad_mode = LINKS_ARE_NUMBERED; if (keypad_mode == NUMBERS_AS_ARROWS) set_numbers_as_arrows(); @@ -1198,6 +1358,16 @@ WSADATA WSAData; } /* + * Check the -show_cursor command line toggle. - FM + */ + if (LYUseDefShoCur == FALSE) { + if (LYShowCursor == TRUE) + LYShowCursor = FALSE; + else + LYShowCursor = TRUE; + } + + /* * Disable multiple bookmark support if not interactive, * so it doesn't crash on curses functions, or if the * support was blocked via userdefs.h and/or lynx.cfg, @@ -1422,13 +1592,17 @@ WSADATA WSAData; if (crawl && !number_links) { keypad_mode = NUMBERS_AS_ARROWS; } else if (!nolist) { - keypad_mode = LINKS_ARE_NUMBERED; + if (keypad_mode == NUMBERS_AS_ARROWS) { + keypad_mode = LINKS_ARE_NUMBERED; + } } if (display != NULL && *display != '\0') { LYisConfiguredForX = TRUE; } status = mainloop(); - if (!nolist && keypad_mode == LINKS_ARE_NUMBERED) + if (!nolist && + (keypad_mode == LINKS_ARE_NUMBERED || + keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED)) printlist(stdout,FALSE); #ifndef NOSIGHUP (void) signal(SIGHUP, SIG_DFL); @@ -1464,10 +1638,10 @@ WSADATA WSAData; * LYNXKEYMAP, lynxcgi, LYNXIMGMAP, LYNXCOOKIE */ #ifdef GLOBALREF_IS_MACRO -extern GLOBALREF (HTProtocol,LYLynxKeymap); -extern GLOBALREF (HTProtocol,LYLynxCGI); -extern GLOBALREF (HTProtocol,LYLynxIMGmap); -extern GLOBALREF (HTProtocol,LYLynxCookies); +extern GLOBALREF (HTProtocol, LYLynxKeymap); +extern GLOBALREF (HTProtocol, LYLynxCGI); +extern GLOBALREF (HTProtocol, LYLynxIMGmap); +extern GLOBALREF (HTProtocol, LYLynxCookies); #else GLOBALREF HTProtocol LYLynxKeymap; GLOBALREF HTProtocol LYLynxCGI; @@ -1533,6 +1707,15 @@ PRIVATE void parse_arg ARGS3( return; } + /* + * Skip any lone "-" arguments, because we've loaded + * the stdin input into an HTList structure for + * special handling. - FM + */ + if (strcmp(argv[0], "-") == 0) { + return; + } + switch (TOLOWER(argv[0][1])) { case 'a': @@ -1586,23 +1769,23 @@ PRIVATE void parse_arg ARGS3( } else if (strncmp(argv[0], "-auth", 5) == 0) { /* - * Authentication information for protected forms. + * Authentication information for protected documents. */ char *auth_info = NULL; if (nextarg) { StrAllocCopy(auth_info, cp); - memset(cp, ' ', strlen(cp));/* Let's not show too much */ + memset(cp, ' ', strlen(cp)); /* Let's not show too much */ } if (auth_info != NULL) { - if ((cp = strchr(auth_info, ':')) != NULL) { /* Pw */ + if ((cp = strchr(auth_info, ':')) != NULL) { /* Pw */ *cp++ = '\0'; /* Terminate ID */ if (*cp) { HTUnEscape(cp); StrAllocCopy(authentication_info[1], cp); } } - if (*auth_info) { /* Id */ + if (*auth_info) { /* Id */ HTUnEscape(auth_info); StrAllocCopy(authentication_info[0], auth_info); } @@ -1768,6 +1951,12 @@ PRIVATE void parse_arg ARGS3( break;; #endif /* VMS */ + } else if (strncmp(argv[0], "-force_secure", 13) == 0) { + if (LYForceSSLCookiesSecure) + LYForceSSLCookiesSecure = FALSE; + else + LYForceSSLCookiesSecure = TRUE; + } else if (strncmp(argv[0], "-from", 5) == 0) { if (LYNoFromHeader) LYNoFromHeader = FALSE; @@ -2024,7 +2213,32 @@ PRIVATE void parse_arg ARGS3( break; case 'p': - if (strncmp(argv[0], "-popup", 6) == 0) { + if (strncmp(argv[0], "-pauth", 6) == 0) { + /* + * Authentication information for protected proxy server. - AJL + */ + char *pauth_info = NULL; + + if (nextarg) { + StrAllocCopy(pauth_info, cp); + memset(cp, ' ', strlen(cp)); /* Let's not show too much */ + } + if (pauth_info != NULL) { + if ((cp = strchr(pauth_info, ':')) != NULL) { /* Pw */ + *cp++ = '\0'; /* Terminate ID */ + if (*cp) { + HTUnEscape(cp); + StrAllocCopy(proxyauth_info[1], cp); + } + } + if (*pauth_info) { /* Id */ + HTUnEscape(pauth_info); + StrAllocCopy(proxyauth_info[0], pauth_info); + } + FREE(pauth_info); + } + + } else if (strncmp(argv[0], "-popup", 6) == 0) { LYUseDefSelPop = FALSE; } else if (strcmp(argv[0], "-post_data") == 0) { @@ -2203,10 +2417,7 @@ PRIVATE void parse_arg ARGS3( HTDirAccess = HT_DIR_SELECTIVE; } else if (strncmp(argv[0], "-show_cursor", 12) == 0) { - if (LYShowCursor) - LYShowCursor = FALSE; - else - LYShowCursor = TRUE; + LYUseDefShoCur = FALSE; } else if (strncmp(argv[0], "-soft_dquotes", 13) == 0) { if (soft_dquotes) @@ -2348,11 +2559,11 @@ Output_Help_List: printf(" in double-quotes (\"-\") on VMS)\n"); printf(" -anonymous used to specify the anonymous account\n"); #ifdef EXP_CHARTRANS - printf(" -assume_charset charset for documents that don't specify it\n"); - printf(" -assume_local_charset charset assumed for local files\n"); - printf(" -assume_unrec_charset use this instead of unrecognized charsets\n"); + printf(" -assume_charset=MIMEname charset for documents that don't specify it\n"); + printf(" -assume_local_charset=MIMEname charset assumed for local files\n"); + printf(" -assume_unrec_charset=MIMEname use this instead of unrecognized charsets\n"); #endif /* EXP_CHARTRANS */ - printf(" -auth=id:pw authentication information for protected forms\n"); + printf(" -auth=id:pw authentication information for protected documents\n"); printf(" -base prepend a request URL comment and BASE tag to text/html\n"); printf(" outputs for -source or -mime_header dumps\n"); printf(" -book use the bookmark page as the startfile\n"); @@ -2385,6 +2596,7 @@ Output_Help_List: printf(" -fileversions include all versions of files in local VMS directory\n"); printf(" listings\n"); printf(" -force_html forces the first document to be interpreted as HTML\n"); + printf(" -force_secure toggles forcing of the secure flag for SSL cookies\n"); printf(" -from toggle transmissions of From headers\n"); printf(" -ftp disable ftp access\n"); printf(" -get_data user data for get forms, read from stdin,\n"); @@ -2420,6 +2632,7 @@ Output_Help_List: #endif /* SOCKS */ printf(" -nostatus disable the miscellaneous information messages\n"); printf(" -number_links force numbering of links\n"); + printf(" -pauth=id:pw authentication information for protected proxy server\n"); printf(" -popup toggles handling of single-choice SELECT options via\n"); printf(" popup windows or as lists of radio buttons\n"); printf(" -post_data user data for post forms, read from stdin,\n"); diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c index a721ea4b..e751496b 100644 --- a/src/LYMainLoop.c +++ b/src/LYMainLoop.c @@ -141,6 +141,7 @@ int mainloop NOARGS char *owner_address = NULL; /* Holds the responsible owner's address */ char *ownerS_address = NULL; /* Holds owner's address during source fetch */ BOOLEAN first_file = TRUE; + BOOLEAN popped_doc = FALSE; BOOLEAN refresh_screen = FALSE; BOOLEAN force_load = FALSE; BOOLEAN try_internal = FALSE; @@ -306,19 +307,31 @@ initialize: } try_again: /* - * Push the old file onto the history stack. + * Push the old file onto the history stack if we + * have a current doc and a new address. - FM */ if (curdoc.address && newdoc.address) { - LYpush(&curdoc, ForcePush); - + /* + * Don't actually push if this is a LYNXDOWNLOAD + * URL, because that returns NORMAL even if it + * fails due to a spoof attempt or file access + * problem, and we set the newdoc structure + * elements to the curdoc structure elements + * under case NORMAL. - FM + */ + if (strncmp(newdoc.address, "LYNXDOWNLOAD:", 13)) { + LYpush(&curdoc, ForcePush); + } } else if (!newdoc.address) { /* * If newdoc.address is empty then pop a file * and load it. Force a no_cache override unless - * it's a bookmark file or it has POST content - * and LYresubmit_posts is set. - FM + * it's a bookmark file, or it has POST content + * and LYresubmit_posts is set without safe also + * set. */ LYpop(&newdoc); + popped_doc = TRUE; /* ** If curdoc had been reached via an internal ** (fragment) link from what we now have just @@ -331,7 +344,8 @@ try_again: LYforce_no_cache = FALSE; try_internal = TRUE; } else if ((newdoc.bookmark != NULL) || - (newdoc.post_data != NULL && LYresubmit_posts)) { + (newdoc.post_data != NULL && !newdoc.safe && + LYresubmit_posts)) { LYoverride_no_cache = FALSE; } else { LYoverride_no_cache = TRUE; @@ -466,6 +480,7 @@ try_again: * Do any error logging, if appropriate. */ LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */ + popped_doc = FALSE; /* Was TRUE if popped. - FM */ if (trace_mode_flag == TRUE) { WWW_TraceFlag = TRUE; trace_mode_flag = FALSE; @@ -506,6 +521,7 @@ try_again: #endif /* SIGTSTP */ exit(-1); } + chmod(TRAVERSE_ERRORS, 0600); } fprintf(ofp, "%s %s in %s\n", links[curdoc.link].lname, @@ -555,6 +571,7 @@ try_again: * Not supposed to return any file. */ LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */ + popped_doc = FALSE; /* Was TRUE if popped. - FM */ if (trace_mode_flag == TRUE) { WWW_TraceFlag = TRUE; trace_mode_flag = FALSE; @@ -796,7 +813,7 @@ try_again: FREE(traversal_link_to_add); } if (curdoc.address && curdoc.title && - strncasecomp(curdoc.address, "LYNXIMGMAP:", 11)) + strncmp(curdoc.address, "LYNXIMGMAP:", 11)) /* * Add the address we got to TRAVERSE_FOUND_FILE. */ @@ -804,16 +821,15 @@ try_again: } /* - * If this was a NORMAL download, we still have curdoc, + * If this was a LYNXDOWNLOAD, we still have curdoc, * not a newdoc, so reset the address, title and * positioning elements. - FM */ - if (newdoc.address && curdoc.title && - !strncmp(newdoc.address, "LYNXDOWNLOAD:", 13) && - !strcmp((curdoc.title ? curdoc.title : ""), - DOWNLOAD_OPTIONS_TITLE)) { + if (newdoc.address && curdoc.address && + !strncmp(newdoc.address, "LYNXDOWNLOAD:", 13)) { StrAllocCopy(newdoc.address, curdoc.address); - StrAllocCopy(newdoc.title, curdoc.title); + StrAllocCopy(newdoc.title, (curdoc.title ? + curdoc.title : "")); StrAllocCopy(newdoc.bookmark, curdoc.bookmark); newdoc.line = curdoc.line; newdoc.link = curdoc.link; @@ -828,10 +844,11 @@ try_again: Newline = newdoc.line; /* - * If we are going to a target line, + * If we are going to a target line or + * the first page of a popped document, * override any www_search line result. */ - if (Newline > 1) + if (Newline > 1 || popped_doc == TRUE) www_search_result = -1; /* @@ -899,6 +916,7 @@ try_again: LYPermitURL = FALSE; /* only set for LYValidate */ ForcePush = FALSE; /* only set for some PRINT requests. */ LYforce_HTML_mode = FALSE; + popped_doc = FALSE; } /* end if (STREQ(newdoc.address, curdoc.address) */ @@ -972,7 +990,7 @@ try_again: * Set up the crawl output stuff. */ if (curdoc.address && !lookup(curdoc.address)) { - if (strncasecomp(curdoc.address, "LYNXIMGMAP:", 11)) + if (strncmp(curdoc.address, "LYNXIMGMAP:", 11)) crawl_ok = TRUE; add_to_table(curdoc.address); } @@ -1027,11 +1045,9 @@ try_again: } /* - * If the curdoc.line is different than Newline then there - * must have been a change since last update. Run showpage. - * showpage will put a fresh screen of text out. If this is - * a WWW document then use the WWW routine HText_pageDisplay - * to put the page on the screen. + * If the curdoc.line is different than Newline then there must + * have been a change since last update. Run HText_pageDisplay() + * create a fresh screen of text out. */ if (curdoc.line != Newline) { @@ -1275,7 +1291,10 @@ try_again: links[curdoc.link].type == WWW_FORM_LINK_TYPE && (links[curdoc.link].form->type == F_TEXT_TYPE || links[curdoc.link].form->type == F_TEXTAREA_TYPE))) - highlight(ON, curdoc.link); /* highlight current link */ + /* + * Highlight current link. + */ + highlight(ON, curdoc.link, prev_target); if (traversal) { /* @@ -1287,6 +1306,7 @@ try_again: sprintf(cfile,"lnk%08d.dat",ccount); ccount = ccount + 1; if ((cfp = fopen(cfile,"w")) != NULL) { + chmod(cfile, 0600); print_crawl_to_fd(cfp,curdoc.address,curdoc.title); fclose(cfp); } else { @@ -1336,10 +1356,10 @@ try_again: move(LYlines-1,0); clrtoeol(); addstr(FORM_NOVICELINE_TWO); } - c=change_form_link(&links[curdoc.link], - FORM_UP, &newdoc, &refresh_screen, - links[curdoc.link].form->name, - links[curdoc.link].form->value); + c = change_form_link(&links[curdoc.link], + FORM_UP, &newdoc, &refresh_screen, + links[curdoc.link].form->name, + links[curdoc.link].form->value); if (c == '\n' || c == '\r') #ifdef FASTTAB @@ -1360,6 +1380,7 @@ try_again: * redundant error reporting. */ real_c = c = LYgetch(); /* get user input */ + #ifndef VMS if (c == 3) { /* ^C */ /* @@ -1409,8 +1430,8 @@ new_keyboard_input: (!lookup_reject(links[curdoc.link].lname) && traversal_host && links[curdoc.link].lname && !strncmp(traversal_host, - (strncasecomp(links[curdoc.link].lname, - "LYNXIMGMAP:", 11) + (strncmp(links[curdoc.link].lname, + "LYNXIMGMAP:", 11) ? links[curdoc.link].lname : (links[curdoc.link].lname + 11)), strlen(traversal_host))); @@ -1447,8 +1468,7 @@ new_keyboard_input: } else { StrAllocCopy(traversal_link_to_add, links[curdoc.link].lname); - if (strncasecomp(traversal_link_to_add, - "LYNXIMGMAP:", 11)) + if (strncmp(traversal_link_to_add, "LYNXIMGMAP:", 11)) crawl_ok = TRUE; c = RTARROW; } @@ -1608,7 +1628,7 @@ new_cmd: /* * follow_link_number(), and re-initialize * the new link value. - FM */ - highlight(OFF, curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = newdoc.link; newdoc.link = 0; } @@ -1703,8 +1723,8 @@ new_cmd: /* /* * Don't assume the reloaded document will be the same. - FM */ - newdoc.line=1; - newdoc.link=0; + newdoc.line = 1; + newdoc.link = 0; #else /* * Do assume the reloaded document will be the same. - FM @@ -1721,8 +1741,10 @@ new_cmd: /* _statusline(RELOADING_FORM); sleep(AlertSecs); } - newdoc.line = ((curdoc.line > 0) ? curdoc.line : 1); - newdoc.link = ((curdoc.link > -1) ? curdoc.link : 0); + newdoc.line = ((curdoc.line > 0) ? + curdoc.line : 1); + newdoc.link = ((curdoc.link > -1) ? + curdoc.link : 0); #endif /* NO_ASSUME_SAME_DOC */ FREE(curdoc.address); /* so it doesn't get pushed */ #ifdef VMS @@ -1731,11 +1753,10 @@ new_cmd: /* /* * Reload should force a cache refresh on a proxy. * -- Ari L. <luotonen@dxcern.cern.ch> - */ - /* - but only if this was really a reload requested by + * + * -- but only if this was really a reload requested by * the user, not if we jumped here to handle reloading for - * INLINE_TOGGLE, IMAGE_TOGGLE, RAW_TOGGLE, etc. - * - kw + * INLINE_TOGGLE, IMAGE_TOGGLE, RAW_TOGGLE, etc. - KW */ if (real_cmd == LYK_RELOAD) reloading = TRUE; @@ -1892,7 +1913,7 @@ new_cmd: /* if (more) { Newline += display_lines; } else if (curdoc.link < nlinks-1) { - highlight(OFF,curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = nlinks-1; /* put on last link */ } else if (old_c != real_c) { old_c = real_c; @@ -1905,7 +1926,7 @@ new_cmd: /* if (Newline > 1) { Newline -= display_lines; } else if (curdoc.link > 0) { - highlight(OFF,curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = 0; /* put on first link */ } else if (old_c != real_c) { old_c = real_c; @@ -2013,17 +2034,21 @@ new_cmd: /* case LYK_PREV_LINK: if (curdoc.link > 0) { /* previous link */ - highlight(OFF, curdoc.link); /* unhighlight the current link */ + /* + * Unhighlight current link. + */ + highlight(OFF, curdoc.link, prev_target); curdoc.link--; } else if (!more && curdoc.link==0 && Newline==1) { /* at the top of list */ /* * If there is only one page of data and the user - * goes off the top, then just move the cursor to - * last link on the page. + * goes off the top, then unhighlight the current + * link and just move the cursor to last link on + * the page. */ - highlight(OFF,curdoc.link); /* unhighlight the current link */ + highlight(OFF, curdoc.link, prev_target); curdoc.link = nlinks-1; /* the last link */ } else if (curdoc.line > 1) { /* previous page */ @@ -2042,7 +2067,7 @@ new_cmd: /* case LYK_NEXT_LINK: if (curdoc.link < nlinks-1) { /* next link */ - highlight(OFF, curdoc.link); + highlight(OFF, curdoc.link, prev_target); #ifdef FASTTAB /* * Move to different textarea if TAB in textarea. @@ -2070,7 +2095,7 @@ new_cmd: /* * Move to the top link on the page. */ } else if (!more && Newline == 1 && curdoc.link == nlinks-1) { - highlight(OFF,curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = 0; } else if (more) { /* next page */ @@ -2093,11 +2118,11 @@ new_cmd: /* } } if (newlink > -1) { - highlight(OFF, curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = newlink; #ifdef NOTDEFINED } else if (!more && Newline == 1 && curdoc.link == 0) { - highlight(OFF, curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = (nlinks-1); } else if (more) { /* next page */ Newline += (display_lines); @@ -2116,7 +2141,7 @@ new_cmd: /* * Move to the top link on the page. */ } else if (!more && Newline == 1 && curdoc.link == (nlinks-1)) { - highlight(OFF, curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = 0; #endif /* NOTDEFINED */ @@ -2141,12 +2166,12 @@ new_cmd: /* } if (newlink > -1) { - highlight(OFF, curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = newlink; #ifdef NOTDEFINED } else if (!more && Newline == 1 && curdoc.link == (nlinks-1)) { - highlight(OFF, curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = 0; #endif /* NOTDEFINED */ } else if (more) { /* next page */ @@ -2163,7 +2188,7 @@ new_cmd: /* * Move to the top link on the page. */ } else if (!more && Newline == 1 && curdoc.link == (nlinks-1)) { - highlight(OFF, curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = 0; #endif /* NOTDEFINED */ } else if (more) { /* next page */ @@ -2179,7 +2204,7 @@ new_cmd: /* case LYK_RIGHT_LINK: if (curdoc.link<nlinks-1 && links[curdoc.link].ly == links[curdoc.link+1].ly) { - highlight(OFF,curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link++; } break; @@ -2187,7 +2212,7 @@ new_cmd: /* case LYK_LEFT_LINK: if (curdoc.link>0 && links[curdoc.link].ly == links[curdoc.link-1].ly) { - highlight(OFF,curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link--; } break; @@ -2414,6 +2439,42 @@ new_cmd: /* LYforce_no_cache = FALSE; break; } + /* + * Make sure this isn't a spoof attempt + * via an internal URL. - FM + */ + if (!strncasecomp( + links[curdoc.link].form->submit_action, + "LYNXCOOKIE:", 11) || + !strncasecomp( + links[curdoc.link].form->submit_action, + "LYNXDIRED:", 10) || + !strncasecomp( + links[curdoc.link].form->submit_action, + "LYNXDOWNLOAD:", 13) || + !strncasecomp( + links[curdoc.link].form->submit_action, + "LYNXHIST:", 9) || + !strncasecomp( + links[curdoc.link].form->submit_action, + "LYNXKEYMAP:", 11) || + !strncasecomp( + links[curdoc.link].form->submit_action, + "LYNXIMGMAP:", 11) || + !strncasecomp( + links[curdoc.link].form->submit_action, + "LYNXPRINT:", 10) || + !strncasecomp( + links[curdoc.link].form->submit_action, + "lynxexec:", 9) || + !strncasecomp( + links[curdoc.link].form->submit_action, + "lynxprog:", 9)) { + HTAlert(SPECIAL_ACTION_DISALLOWED); + HTOutputFormat = WWW_PRESENT; + LYforce_no_cache = FALSE; + break; + } #ifdef NOTDEFINED /* We're disabling form inputs instead of using this. - FM */ /* * Check for enctype and let user know we @@ -2435,7 +2496,7 @@ new_cmd: /* LYPermitURL = TRUE; } if (no_filereferer == TRUE && - !strncasecomp(curdoc.address, "file:", 5)) { + !strncmp(curdoc.address, "file:", 5)) { LYNoRefererForThis = TRUE; } } @@ -2464,6 +2525,10 @@ new_cmd: /* break; } } + if (c == 23) { + c = DO_NOTHING; + refresh_screen = TRUE; + } goto new_keyboard_input; } else { /* @@ -2473,8 +2538,8 @@ new_cmd: /* * with restrictions on file URLs. - FM */ if (no_file_url && - !strncasecomp(links[curdoc.link].lname, "file:", 5)) { - if (strncasecomp(curdoc.address, "file:", 5)) { + !strncmp(links[curdoc.link].lname, "file:", 5)) { + if (strncmp(curdoc.address, "file:", 5)) { HTAlert(FILE_SERVED_LINKS_DISALLOWED); break; } else if (curdoc.bookmark != NULL) { @@ -2483,6 +2548,42 @@ new_cmd: /* } } /* + * Make sure this isn't a spoof attempt + * via an internal URL in a non-internal + * document. - FM + */ + if ((!strncmp(links[curdoc.link].lname, + "LYNXCOOKIE:", 11) && + strcmp((curdoc.title ? curdoc.title : ""), + COOKIE_JAR_TITLE)) || +#ifdef DIRED_SUPPORT + (!strncmp(links[curdoc.link].lname, + "LYNXDIRED:", 10) && + strcmp((curdoc.title ? curdoc.title : ""), + DIRED_MENU_TITLE) && + strcmp((curdoc.title ? curdoc.title : ""), + PERMIT_OPTIONS_TITLE) && + strcmp((curdoc.title ? curdoc.title : ""), + UPLOAD_OPTIONS_TITLE)) || +#endif /* DIRED_SUPPORT */ + (!strncmp(links[curdoc.link].lname, + "LYNXDOWNLOAD:", 13) && + strcmp((curdoc.title ? curdoc.title : ""), + DOWNLOAD_OPTIONS_TITLE)) || + (!strncmp(links[curdoc.link].lname, + "LYNXHIST:", 9) && + strcmp((curdoc.title ? curdoc.title : ""), + HISTORY_PAGE_TITLE)) || + (!strncmp(links[curdoc.link].lname, + "LYNXPRINT:", 10) && + strcmp((curdoc.title ? curdoc.title : ""), + PRINT_OPTIONS_TITLE))) { + HTAlert(SPECIAL_VIA_EXTERNAL_DISALLOWED); + HTOutputFormat = WWW_PRESENT; + LYforce_no_cache = FALSE; + break; + } + /* * Follow a normal link or anchor. */ StrAllocCopy(newdoc.address, links[curdoc.link].lname); @@ -2527,7 +2628,7 @@ new_cmd: /* !strcmp(lynxjumpfile, curdoc.address))) { LYUserSpecifiedURL = TRUE; } else if (no_filereferer == TRUE && - !strncasecomp(curdoc.address, "file:", 5)) { + !strncmp(curdoc.address, "file:", 5)) { LYNoRefererForThis = TRUE; } newdoc.link = 0; @@ -2544,7 +2645,7 @@ new_cmd: /* strip_trailing_slash(newdoc.address); } #endif /* DIRED_SUPPORT */ - if (!strncasecomp(curdoc.address, "LYNXCOOKIE:", 11)) { + if (!strncmp(curdoc.address, "LYNXCOOKIE:", 11)) { HTuncache_current_document(); } } @@ -2891,6 +2992,13 @@ check_goto_URL: _statusline(GOTO_WAIS_DISALLOWED); sleep(MessageSecs); + } else if (!strncmp(user_input_buffer, "LYNXCOOKIE:", 11) || + !strncmp(user_input_buffer, "LYNXDIRED:", 10) || + !strncmp(user_input_buffer, "LYNXDOWNLOAD:", 13) || + !strncmp(user_input_buffer, "LYNXPRINT:", 10)) { + _statusline(GOTO_SPECIAL_DISALLOWED); + sleep(MessageSecs); + } else { StrAllocCopy(newdoc.address, user_input_buffer); newdoc.isHEAD = FALSE; @@ -3025,7 +3133,7 @@ check_goto_URL: newdoc.isHEAD = FALSE; newdoc.safe = FALSE; newdoc.internal_link = FALSE; - highlight(OFF,curdoc.link); + highlight(OFF, curdoc.link, prev_target); #ifdef DIRED_SUPPORT if (lynx_edit_mode) HTuncache_current_document(); @@ -3065,13 +3173,13 @@ check_goto_URL: LYRawMode_flag != LYRawMode || LYSelectPopups_flag != LYSelectPopups || ((strcmp(CurrentUserAgent, (LYUserAgent ? - LYUserAgent : "")) || + LYUserAgent : "")) || strcmp(CurrentNegoLanguage, (language ? language : "")) || strcmp(CurrentNegoCharset, (pref_charset ? - pref_charset : "")) - ) && (strncmp(curdoc.address, "http", 4) == 0 || - strncmp(curdoc.address, "lynxcgi:", 8) == 0))) { + pref_charset : ""))) && + (!strncmp(curdoc.address, "http", 4) || + !strncmp(curdoc.address, "lynxcgi:", 8)))) { /* * Check if this is a reply from a POST, and if so, * seek confirmation of reload if the safe element @@ -3086,22 +3194,24 @@ check_goto_URL: } else { LYforce_no_cache = TRUE; StrAllocCopy(newdoc.address, curdoc.address); - if (((strcmp(CurrentNegoLanguage, + if (((strcmp(CurrentUserAgent, (LYUserAgent ? + LYUserAgent : "")) || + strcmp(CurrentNegoLanguage, (language ? language : "")) || strcmp(CurrentNegoCharset, (pref_charset ? pref_charset : ""))) && (strncmp(curdoc.address, "http", 4) == 0 || strncmp(curdoc.address, "lynxcgi:", 8) == 0))) { /* - * An option has changed which may influence - * content negotiation, and the resource is from - * a http or https or lynxcgi URL (the only protocols - * which currently do anything with this information). - * Set reloading=TRUE so that proxy caches will be - * flushed, which is necessary until the time when - * all proxies understand HTTP 1.1 Vary: and all - * Servers properly use it... Treat like - * case LYK_RELOAD (see comments there). - kw + * An option has changed which may influence + * content negotiation, and the resource is from + * a http or https or lynxcgi URL (the only protocols + * which currently do anything with this information). + * Set reloading = TRUE so that proxy caches will be + * flushed, which is necessary until the time when + * all proxies understand HTTP 1.1 Vary: and all + * Servers properly use it... Treat like + * case LYK_RELOAD (see comments there). - KW */ if (HTisDocumentSource()) { HTOutputFormat = WWW_SOURCE; @@ -3109,48 +3219,46 @@ check_goto_URL: HEAD_request = HTLoadedDocumentIsHEAD(); HTuncache_current_document(); #ifdef NO_ASSUME_SAME_DOC - newdoc.line=1; - newdoc.link=0; + newdoc.line = 1; + newdoc.link = 0; #else if (lynx_mode == FORMS_LYNX_MODE) { _statusline(RELOADING_FORM); sleep(AlertSecs); } - newdoc.line = ((curdoc.line > 0) ? curdoc.line : 1); - newdoc.link = ((curdoc.link > -1) ? curdoc.link : 0); + newdoc.line = ((curdoc.line > 0) ? + curdoc.line : 1); + newdoc.link = ((curdoc.link > -1) ? + curdoc.link : 0); #endif /* NO_ASSUME_SAME_DOC */ FREE(curdoc.address); reloading = TRUE; } else if (keypad_mode_flag != keypad_mode || - (user_mode_flag != user_mode && - (user_mode_flag == NOVICE_MODE || - user_mode == NOVICE_MODE)) || - (((HTfileSortMethod_flag != HTfileSortMethod) || + (user_mode_flag != user_mode && + (user_mode_flag == NOVICE_MODE || + user_mode == NOVICE_MODE)) || + (((HTfileSortMethod_flag != HTfileSortMethod) || #ifdef DIRED_SUPPORT - (c != dir_list_style) || + (c != dir_list_style) || #endif /* DIRED_SUPPORT */ - (show_dotfiles_flag != show_dotfiles)) && - (!strncmp(curdoc.address, "file:", 5) || - !strncmp(curdoc.address, "ftp:", 4))) || - LYSelectPopups_flag != LYSelectPopups || - (strcmp(CurrentUserAgent, (LYUserAgent ? - LYUserAgent : "")) && - !strncmp(curdoc.address, "http", 4))) { + (show_dotfiles_flag != show_dotfiles)) && + (!strncmp(curdoc.address, "file:", 5) || + !strncmp(curdoc.address, "ftp:", 4))) || + LYSelectPopups_flag != LYSelectPopups) { HTuncache_current_document(); FREE(curdoc.address); - } else { } } - keypad_mode_flag = keypad_mode; - user_mode_flag = user_mode; - HTfileSortMethod_flag = HTfileSortMethod; - CurrentCharSet_flag = current_char_set; - show_dotfiles_flag = show_dotfiles; - LYRawMode_flag = LYRawMode; - LYSelectPopups_flag = LYSelectPopups; - StrAllocCopy(CurrentUserAgent, (LYUserAgent ? - LYUserAgent : "")); } + keypad_mode_flag = keypad_mode; + user_mode_flag = user_mode; + HTfileSortMethod_flag = HTfileSortMethod; + CurrentCharSet_flag = current_char_set; + show_dotfiles_flag = show_dotfiles; + LYRawMode_flag = LYRawMode; + LYSelectPopups_flag = LYSelectPopups; + StrAllocCopy(CurrentUserAgent, (LYUserAgent ? + LYUserAgent : "")); StrAllocCopy(CurrentNegoLanguage, (language ? language : "")); StrAllocCopy(CurrentNegoCharset, (pref_charset ? @@ -3426,10 +3534,10 @@ check_goto_URL: } } if (curdoc.link < nlinks-1) { - highlight(OFF, curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link++; } else if (!more && Newline == 1 && curdoc.link == nlinks-1) { - highlight(OFF,curdoc.link); + highlight(OFF, curdoc.link, prev_target); curdoc.link = 0; } else if (more) { /* next page */ Newline += (display_lines); @@ -3917,7 +4025,7 @@ check_goto_URL: } if (strcmp((curdoc.title ? curdoc.title : ""), - HISTORY_PAGE_TITLE) && + HISTORY_PAGE_TITLE) && strcmp((curdoc.title ? curdoc.title : ""), SHOWINFO_TITLE) && strcmp((curdoc.title ? curdoc.title : ""), @@ -3934,14 +4042,31 @@ check_goto_URL: DOWNLOAD_OPTIONS_TITLE) && strcmp((curdoc.title ? curdoc.title : ""), COOKIE_JAR_TITLE) && - strcmp((curdoc.title ? curdoc.title : ""), - LIST_PAGE_TITLE)) { + ((nlinks <= 0) || + (links[curdoc.link].lname != NULL && + strncmp(links[curdoc.link].lname, + "LYNXHIST:", 9) && + strncmp(links[curdoc.link].lname, + "LYNXPRINT:", 10) && + strncmp(links[curdoc.link].lname, + "LYNXDIRED:", 10) && + strncmp(links[curdoc.link].lname, + "LYNXDOWNLOAD:", 13) && + strncmp(links[curdoc.link].lname, + "LYNXCOOKIE:", 11) && + strncmp(links[curdoc.link].lname, + "LYNXLIST:", 9)))) { if (nlinks > 0) { if (curdoc.post_data == NULL && - curdoc.bookmark == NULL) { + curdoc.bookmark == NULL && + strcmp((curdoc.title ? curdoc.title : ""), + LIST_PAGE_TITLE) && + strcmp((curdoc.title ? curdoc.title : ""), + VISITED_LINKS_TITLE)) { /* - * Document doesn't have POST content, - * and is not a bookmark file, so we can + * The document doesn't have POST content, + * and is not a bookmark file, nor is the + * list or visited links page, so we can * save either that or the link. - FM */ _statusline(BOOK_D_L_OR_CANCEL); @@ -4109,7 +4234,7 @@ check_add_bookmark_to_self: */ *stderr = *LYTraceLogFP; start_curses(); - refresh_screen = TRUE; /* for a showpage */ + refresh_screen = TRUE; /* for an HText_pageDisplay() */ } else { if (old_c != real_c) { old_c = real_c; @@ -4243,13 +4368,27 @@ check_add_bookmark_to_self: */ LYforce_no_cache = TRUE; - } else if (!strncasecomp(links[curdoc.link].lname, - "data:", 5)) { + } else if (!strncmp(links[curdoc.link].lname, "data:", 5)) { if (old_c != real_c) { old_c = real_c; HTAlert(UNSUPPORTED_DATA_URL); } + } else if (!strncmp(links[curdoc.link].lname, + "LYNXCOOKIE:", 11) || + !strncmp(links[curdoc.link].lname, + "LYNXDIRED:", 10) || + !strncmp(links[curdoc.link].lname, + "LYNXDOWNLOAD:", 13) || + !strncmp(links[curdoc.link].lname, + "LYNXPRINT:", 10) || + !strncmp(links[curdoc.link].lname, + "lynxexec:", 9) || + !strncmp(links[curdoc.link].lname, + "lynxprog:", 9)) { + _statusline(NO_DOWNLOAD_SPECIAL); + sleep(MessageSecs); + } else { /* Not a forms, options or history link */ /* * Follow a normal link or anchor. Note that @@ -4352,6 +4491,7 @@ check_add_bookmark_to_self: break; } #endif /* VMS */ + chmod(LYTraceLogPath, 0600); *stderr = *LYTraceLogFP; fprintf(stderr, "\t\t%s\n\n", LYNX_TRACELOG_TITLE); } @@ -4591,7 +4731,6 @@ check_add_bookmark_to_self: /* * Remember whether we are in dired menu * so we can display the right keymap. - * Don't cache the keymap because it changes. - EF */ if (!no_dired_support) { prev_lynx_edit_mode = lynx_edit_mode; diff --git a/src/LYMap.c b/src/LYMap.c index e4141cf6..f15421cc 100644 --- a/src/LYMap.c +++ b/src/LYMap.c @@ -154,7 +154,7 @@ PUBLIC BOOL LYAddMapElement ARGS4( char *, map, char *, address, char *, title, - BOOL, intern_flag) + BOOL, intern_flag) { LYMapElement *new = NULL; LYImageMap *theMap = NULL; @@ -207,7 +207,6 @@ PUBLIC BOOL LYAddMapElement ARGS4( * with a given address already exists in the LynxMaps * structure. - FM */ -#if UNUSED PUBLIC BOOL LYHaveImageMap ARGS1( char *, address) { @@ -225,7 +224,6 @@ PUBLIC BOOL LYHaveImageMap ARGS1( return FALSE; } -#endif /* LYLoadIMGmap - F.Macrides (macrides@sci.wfeb.edu) ** ------------ @@ -373,8 +371,8 @@ PRIVATE int LYLoadIMGmap ARGS4 ( sprintf(buf,"<h2><em>MAP:</em> %s</h2>\n", MapAddress); (*target->isa->put_block)(target, buf, strlen(buf)); - sprintf(buf, "<%s compact>\n", (keypad_mode == LINKS_ARE_NUMBERED) ? - "ul" : "ol"); + sprintf(buf, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ? + "ol" : "ul")); (*target->isa->put_block)(target, buf, strlen(buf)); cur = theMap->elements; while (NULL != (new=(LYMapElement *)HTList_nextObject(cur))) { @@ -391,8 +389,8 @@ PRIVATE int LYLoadIMGmap ARGS4 ( (*target->isa->put_block)(target, MapTitle, strlen(MapTitle)); (*target->isa->put_block)(target, "</a>\n", 5); } - sprintf(buf,"</%s>\n</body>\n", (keypad_mode == LINKS_ARE_NUMBERED) ? - "ul" : "ol"); + sprintf(buf,"</%s>\n</body>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ? + "ol" : "ul")); (*target->isa->put_block)(target, buf, strlen(buf)); (*target->isa->_free)(target); diff --git a/src/LYNews.c b/src/LYNews.c index 65186f00..917bc137 100644 --- a/src/LYNews.c +++ b/src/LYNews.c @@ -1,9 +1,10 @@ #include "HTUtils.h" #include "tcp.h" +#include "HTParse.h" +#include "HTAccess.h" +#include "HTCJK.h" #include "HTAlert.h" #include "LYCurses.h" -#include "HTAccess.h" -#include "HTParse.h" #include "LYSignal.h" #include "LYStructs.h" #include "LYUtils.h" @@ -13,7 +14,7 @@ #include "LYHistory.h" #include "LYSystem.h" #include "GridText.h" -#include "LYSignal.h" +#include "LYCharSets.h" #include "LYNews.h" #include "LYGlobalDefs.h" @@ -44,14 +45,17 @@ PUBLIC char *LYNewsPost ARGS2( BOOLEAN, followup) { char user_input[1024]; + char CJKinput[1024]; char *cp = NULL; int c = 0; /* user input */ - FILE *fd; + FILE *fd = NULL; char my_tempfile[256]; + FILE *fc = NULL; + char CJKfile[256]; char *postfile = NULL; char *NewsGroups = NULL; char *org = NULL; - FILE *fp; + FILE *fp = NULL; /* * Make sure a non-zero length newspost, newsreply, @@ -63,12 +67,35 @@ PUBLIC char *LYNewsPost ARGS2( /* * Open a temporary file for the headers * and message body. - FM - */ + */ tempname(my_tempfile, NEW_FILE); if ((fd = fopen(my_tempfile, "w")) == NULL) { HTAlert(CANNOT_OPEN_TEMP); return(postfile); } + chmod(my_tempfile, 0600); + + /* + * If we're using a Japanese display character set, + * open a temporary file for a conversion to JIS. - FM + */ + CJKfile[0] = '\0'; + if (!strncmp(LYchar_set_names[current_char_set], "Japanese (EUC)", 14) || + !strncmp(LYchar_set_names[current_char_set], "Japanese (SJIS)", 15)) { + tempname(CJKfile, NEW_FILE); + if ((fc = fopen(CJKfile, "w")) == NULL) { + HTAlert(CANNOT_OPEN_TEMP); + fclose(fd); +#ifdef VMS + while (remove(my_tempfile) == 0) + ; /* loop through all versions */ +#else + remove(my_tempfile); +#endif /* VMS */ + return(postfile); + } + chmod(CJKfile, 0600); + } /* * The newsgroups could be a comma-seperated list. @@ -109,8 +136,8 @@ PUBLIC char *LYNewsPost ARGS2( term_message) { _statusline(NEWS_POST_CANCELLED); sleep(InfoSecs); - fclose(fd); /* close the temp file */ - scrollok(stdscr,FALSE); /* Stop scrolling. */ + fclose(fd); /* Close the temp file. */ + scrollok(stdscr, FALSE); /* Stop scrolling. */ goto cleanup; } fprintf(fd, "%s\n", user_input); @@ -127,20 +154,26 @@ PUBLIC char *LYNewsPost ARGS2( /* * Add the default subject. */ - while (isspace(*cp)) + while (isspace(*cp)) { cp++; - if (strncasecomp(cp, "Re:", 3)) + } + if (strncasecomp(cp, "Re:", 3)) { strcat(user_input, "Re: "); + cp += 3; + while (isspace(*cp)) { + cp++; + } + } strcat(user_input, cp); - cp = NULL; } + cp = NULL; if (LYgetstr(user_input, VISIBLE, sizeof(user_input), NORECALL) < 0 || term_message) { _statusline(NEWS_POST_CANCELLED); sleep(InfoSecs); - fclose(fd); /* close the temp file */ - scrollok(stdscr,FALSE); /* Stop scrolling. */ + fclose(fd); /* Close the temp file. */ + scrollok(stdscr, FALSE); /* Stop scrolling. */ goto cleanup; } fprintf(fd,"%s\n",user_input); @@ -155,17 +188,19 @@ PUBLIC char *LYNewsPost ARGS2( *org != '\0') { StrAllocCat(cp, org); #ifndef VMS - } else if ((fp = fopen("/etc/organization", "r")) != 0) { + } else if ((fp = fopen("/etc/organization", "r")) != NULL) { if (fgets(user_input, sizeof(user_input), fp) != NULL) { - if ((cp = strchr(user_input, '\n')) != NULL) - *cp = '\0'; - if (user_input[0] != '\0') + if ((org = strchr(user_input, '\n')) != NULL) { + *org = '\0'; + } + if (user_input[0] != '\0') { StrAllocCat(cp, user_input); + } } fclose(fp); #endif /* !VMS */ } - strcpy(user_input, cp); + LYstrncpy(user_input, cp, (sizeof(user_input) - 16)); FREE(cp); addstr("\n\n Please provide or edit the Organization: header\n"); if (LYgetstr(user_input, VISIBLE, @@ -173,8 +208,8 @@ PUBLIC char *LYNewsPost ARGS2( term_message) { _statusline(NEWS_POST_CANCELLED); sleep(InfoSecs); - fclose(fd); /* close the temp file */ - scrollok(stdscr,FALSE); /* Stop scrolling. */ + fclose(fd); /* Close the temp file. */ + scrollok(stdscr, FALSE); /* Stop scrolling. */ goto cleanup; } fprintf(fd,"%s\n",user_input); @@ -205,11 +240,15 @@ PUBLIC char *LYNewsPost ARGS2( if (TOUPPER(c) == 'Y') /* * The 1 will add the reply ">" in front of every line. + * We're assuming that if the display character set is + * Japanese and the document did not have a CJK charset, + * any non-EUC or non-SJIS 8-bit characters in it where + * converted to 7-bit equivalents. - FM */ print_wwwfile_to_fd(fd, 1); } - fclose(fd); - scrollok(stdscr,FALSE); /* Stop scrolling. */ + fclose(fd); /* Close the temp file. */ + scrollok(stdscr, FALSE); /* Stop scrolling. */ if (term_message || c == 7 || c == 3) goto cleanup; @@ -244,8 +283,8 @@ PUBLIC char *LYNewsPost ARGS2( term_message) { _statusline(NEWS_POST_CANCELLED); sleep(InfoSecs); - fclose(fd); /* close the temp file */ - scrollok(stdscr,FALSE); /* Stop scrolling. */ + fclose(fd); /* Close the temp file. */ + scrollok(stdscr, FALSE); /* Stop scrolling. */ goto cleanup; } while (!STREQ(user_input,".") && !term_message) { @@ -256,14 +295,14 @@ PUBLIC char *LYNewsPost ARGS2( sizeof(user_input), NORECALL) < 0) { _statusline(NEWS_POST_CANCELLED); sleep(InfoSecs); - fclose(fd); /* close the temp file */ - scrollok(stdscr,FALSE); /* Stop scrolling. */ + fclose(fd); /* Close the temp file. */ + scrollok(stdscr, FALSE); /* Stop scrolling. */ goto cleanup; } } fprintf(fd, "\n"); - fclose(fd); /* close the temp file */ - scrollok(stdscr,FALSE); /* stop scrolling */ + fclose(fd); /* Close the temp file. */ + scrollok(stdscr, FALSE); /* Stop scrolling. */ } /* @@ -302,8 +341,40 @@ PUBLIC char *LYNewsPost ARGS2( fclose(fp); } clear(); /* clear the screen */ - StrAllocCopy(postfile, my_tempfile); - if (!followup) + + /* + * If we are using a Japanese display character + * set, convert the contents of the temp file to + * JIS (nothing should change if it does not, in + * fact, contain EUC or SJIS di-bytes). Otherwise, + * use the temp file as is. - FM + */ + if (CJKfile[0] != '\0') { + if ((fd = fopen(my_tempfile, "r")) != NULL) { + while (fgets(user_input, sizeof(user_input), fd) != NULL) { + TO_JIS((unsigned char *)user_input, + (unsigned char *)CJKinput); + fputs(CJKinput, fc); + } + fclose(fc); + StrAllocCopy(postfile, CJKfile); + fclose(fd); +#ifdef VMS + while (remove(my_tempfile) == 0) + ; /* loop through all versions */ +#else + remove(my_tempfile); +#endif /* VMS */ + fd = fc; + strcpy(my_tempfile, CJKfile); + CJKfile[0] = '\0'; + } else { + StrAllocCopy(postfile, my_tempfile); + } + } else { + StrAllocCopy(postfile, my_tempfile); + } + if (!followup) { /* * If it's not a followup, the current document * most likely is the group listing, so force a @@ -314,6 +385,7 @@ PUBLIC char *LYNewsPost ARGS2( * group listing. - FM */ LYforce_no_cache = TRUE; + } LYStatusLine = (LYlines - 1); statusline(POSTING_TO_NEWS); LYStatusLine = -1; @@ -335,6 +407,15 @@ cleanup: remove(my_tempfile); #endif /* VMS */ } + if (CJKfile[0] != '\0') { +#ifdef VMS + fclose(fc); + while (remove(CJKfile) == 0) + ; /* loop through all versions */ +#else + remove(CJKfile); +#endif /* VMS */ + } FREE(NewsGroups); return(postfile); diff --git a/src/LYOptions.c b/src/LYOptions.c index b26ee2ad..774279d2 100644 --- a/src/LYOptions.c +++ b/src/LYOptions.c @@ -15,9 +15,25 @@ #include "LYrcFile.h" #include "HTAlert.h" #include "LYBookmark.h" +#include "GridText.h" #include "LYLeaks.h" +#ifndef BOXVERT +#ifdef ALT_CHAR_SET +#define BOXVERT 0 /* use alt char set for popup window vertical borders */ +#else +#define BOXVERT '*' /* character for popup window vertical borders */ +#endif +#endif +#ifndef BOXHORI +#ifdef ALT_CHAR_SET +#define BOXHORI 0 /* use alt char set for popup window horizontal borders */ +#else +#define BOXHORI '*' /* character for popup window horizontal borders */ +#endif +#endif + #define FREE(x) if (x) {free(x); x = NULL;} #ifdef VMS @@ -30,8 +46,18 @@ BOOLEAN term_options; PRIVATE void terminate_options PARAMS((int sig)); -PRIVATE int boolean_choice PARAMS((int status, int line, - int column, char **choices)); +PRIVATE int boolean_choice PARAMS(( + int status, + int line, + int column, + char ** choices)); +PRIVATE int popup_choice PARAMS(( + int cur_choice, + int line, + int column, + char ** choices, + int i_length, + int disabled)); #define MAXCHOICES 10 @@ -41,7 +67,7 @@ PRIVATE void option_statusline ARGS1( /* * Make sure we have a pointer to a string. */ - if (text == 0) + if (text == NULL) return; /* @@ -64,7 +90,9 @@ PUBLIC void options NOARGS int itmp; #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */ int response, ch; - /* if the user changes the display I need memory to put it in */ + /* + * If the user changes the display we need memory to put it in. + */ char display_option[256]; #ifndef VMS static char putenv_command[142]; @@ -72,6 +100,7 @@ PUBLIC void options NOARGS char *choices[MAXCHOICES]; int CurrentCharSet = current_char_set; BOOLEAN CurrentRawMode = LYRawMode; + BOOLEAN AddValueAccepted = FALSE; #ifdef DIRED_SUPPORT #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS @@ -132,7 +161,7 @@ draw_options: addstr((LYMultiBookmarks ? (LYMBMAdvanced ? "ADVANCED" : "STANDARD") - : "OFF")); + : "OFF ")); move(L_HOME, B_BOOK); if (LYMultiBookmarks) { addstr("review/edit B)ookmarks files"); @@ -143,10 +172,10 @@ draw_options: move(L_FTPSTYPE, 5); addstr("F)TP sort criteria : "); - addstr((HTfileSortMethod==FILE_BY_NAME ? "By Filename" : - (HTfileSortMethod==FILE_BY_SIZE ? "By Size" : - (HTfileSortMethod==FILE_BY_TYPE ? "By Type" : - "By Date")))); + addstr((HTfileSortMethod == FILE_BY_NAME ? "By Filename" : + (HTfileSortMethod == FILE_BY_SIZE ? "By Size " : + (HTfileSortMethod == FILE_BY_TYPE ? "By Type " : + "By Date ")))); move(L_MAIL_ADDRESS, 5); addstr("P)ersonal mail address : "); @@ -155,7 +184,7 @@ draw_options: move(L_SSEARCH, 5); addstr("S)earching type : "); - addstr(case_sensitive ? "CASE SENSITIVE" : "CASE INSENSITIVE"); + addstr(case_sensitive ? "CASE SENSITIVE " : "CASE INSENSITIVE"); move(L_CHARSET, 5); addstr("display (C)haracter set : "); @@ -163,7 +192,7 @@ draw_options: move(L_RAWMODE, 5); addstr("Raw 8-bit or CJK m(O)de : "); - addstr(LYRawMode ? "ON" : "OFF"); + addstr(LYRawMode ? "ON " : "OFF"); move(L_LANGUAGE, 5); addstr("preferred document lan(G)uage: "); @@ -175,24 +204,31 @@ draw_options: move(L_BOOL_A, B_VIKEYS); addstr("V)I keys: "); - addstr(vi_keys ? "ON" : "OFF"); + addstr(vi_keys ? "ON " : "OFF"); move(L_BOOL_A, B_EMACSKEYS); addstr("e(M)acs keys: "); - addstr(emacs_keys ? "ON" : "OFF"); + addstr(emacs_keys ? "ON " : "OFF"); move(L_BOOL_A, B_SHOW_DOTFILES); addstr("sho(W) dot files: "); - addstr((!no_dotfiles && show_dotfiles) ? "ON" : "OFF"); + addstr((!no_dotfiles && show_dotfiles) ? "ON " : "OFF"); - move(L_SELECT_POPUPS, 5); + move(L_BOOL_B, B_SELECT_POPUPS); addstr("popups for selec(T) fields : "); - addstr(LYSelectPopups ? "ON" : "OFF"); + addstr(LYSelectPopups ? "ON " : "OFF"); + + move(L_BOOL_B, B_SHOW_CURSOR); + addstr("show cursor (@) : "); + addstr(LYShowCursor ? "ON " : "OFF"); - move(L_KEYPAD, 5); - addstr("K)eypad mode : "); - addstr((keypad_mode == NUMBERS_AS_ARROWS) ? "Numbers act as arrows" : - "Links are numbered"); + move(L_KEYPAD, 5); + addstr("K)eypad mode : "); + addstr((keypad_mode == NUMBERS_AS_ARROWS) ? + "Numbers act as arrows " : + ((keypad_mode == LINKS_ARE_NUMBERED) ? + "Links are numbered " : + "Links and form fields are numbered")); move(L_LINEED, 5); addstr("li(N)e edit style : "); @@ -201,16 +237,16 @@ draw_options: #ifdef DIRED_SUPPORT move(L_DIRED, 5); addstr("l(I)st directory style : "); - addstr((dir_list_style == FILES_FIRST) ? "Files first " : - ((dir_list_style == MIXED_STYLE) ? "Mixed style " : - "Directories first ")); + addstr((dir_list_style == FILES_FIRST) ? "Files first " : + ((dir_list_style == MIXED_STYLE) ? "Mixed style " : + "Directories first")); #endif /* DIRED_SUPPORT */ move(L_USER_MODE, 5); addstr("U)ser mode : "); - addstr( (user_mode == NOVICE_MODE) ? "Novice" : + addstr( (user_mode == NOVICE_MODE) ? "Novice " : ((user_mode == INTERMEDIATE_MODE) ? "Intermediate" : - "Advanced")); + "Advanced ")); move(L_USER_AGENT, 5); addstr("user (A)gent : "); @@ -220,12 +256,12 @@ draw_options: move(L_EXEC, 5); addstr("local e(X)ecution links : "); #ifndef NEVER_ALLOW_REMOTE_EXEC - addstr( local_exec ? "ALWAYS ON" : + addstr( local_exec ? "ALWAYS ON " : (local_exec_on_local_files ? "FOR LOCAL FILES ONLY" : - "ALWAYS OFF")); + "ALWAYS OFF ")); #else addstr(local_exec_on_local_files ? "FOR LOCAL FILES ONLY" : - "ALWAYS OFF"); + "ALWAYS OFF "); #endif /* NEVER_ALLOW_REMOTE_EXEC */ #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */ @@ -252,121 +288,124 @@ draw_options: addstr(TO_RETURN_SEGMENT); while (TOUPPER(response) != 'R' && - !LYisNonAlnumKeyname(response, LYK_PREV_DOC) && + !LYisNonAlnumKeyname(response, LYK_PREV_DOC) && response != '>' && !term_options && response != 7 && response != 3) { + if (AddValueAccepted == TRUE) { + option_statusline(VALUE_ACCEPTED); + AddValueAccepted = FALSE; + } + move((LYlines - 2), 0); + lynx_start_prompt_color (); + addstr(COMMAND_PROMPT); + lynx_stop_prompt_color (); - move(LYlines-2, 0); - lynx_start_prompt_color (); - addstr(COMMAND_PROMPT); - lynx_stop_prompt_color (); - - refresh(); - response = LYgetch(); - if (term_options || response == 7 || response == 3) - response = 'R'; - if (LYisNonAlnumKeyname(response, LYK_REFRESH)) { - clearok(curscr, TRUE); - goto draw_options; - } - switch (response) { - case 'e': /* change the editor */ - case 'E': - if (no_editor) { - option_statusline(EDIT_DISABLED); - } else if (system_editor ) { - option_statusline(EDITOR_LOCKED); - } else { - if (editor && *editor) - strcpy(display_option, editor); - else { /* clear the NONE */ - move(L_EDITOR, COL_OPTION_VALUES); - addstr(" "); - *display_option = '\0'; - } - option_statusline(ACCEPT_DATA); - move(L_EDITOR, COL_OPTION_VALUES); - standout(); - ch = LYgetstr(display_option, VISIBLE, - sizeof(display_option), NORECALL); - standend(); - move(L_EDITOR, COL_OPTION_VALUES); - if (term_options || ch == -1) { - addstr((editor && *editor) ? - editor : "NONE"); - } else if (*display_option == '\0') { - FREE(editor); - addstr("NONE"); - } else { - StrAllocCopy(editor, display_option); - addstr(display_option); - } - clrtoeol(); - option_statusline(VALUE_ACCEPTED); - } - response = ' '; - break; + refresh(); + response = LYgetch(); + if (term_options || response == 7 || response == 3) + response = 'R'; + if (LYisNonAlnumKeyname(response, LYK_REFRESH)) { + clearok(curscr, TRUE); + goto draw_options; + } + switch (response) { + case 'e': /* Change the editor. */ + case 'E': + if (no_editor) { + option_statusline(EDIT_DISABLED); + } else if (system_editor ) { + option_statusline(EDITOR_LOCKED); + } else { + if (editor && *editor) + strcpy(display_option, editor); + else { /* clear the NONE */ + move(L_EDITOR, COL_OPTION_VALUES); + addstr(" "); + *display_option = '\0'; + } + option_statusline(ACCEPT_DATA); + move(L_EDITOR, COL_OPTION_VALUES); + standout(); + ch = LYgetstr(display_option, VISIBLE, + sizeof(display_option), NORECALL); + standend(); + move(L_EDITOR, COL_OPTION_VALUES); + if (term_options || ch == -1) { + addstr((editor && *editor) ? + editor : "NONE"); + } else if (*display_option == '\0') { + FREE(editor); + addstr("NONE"); + } else { + StrAllocCopy(editor, display_option); + addstr(display_option); + } + clrtoeol(); + option_statusline(VALUE_ACCEPTED); + } + response = ' '; + break; - case 'd': /* change the display */ - case 'D': - if (display && *display) { - strcpy(display_option, display); - } else { /* clear the NONE */ - move(L_DISPLAY, COL_OPTION_VALUES); - addstr(" "); - *display_option = '\0'; - } - option_statusline(ACCEPT_DATA); - move(L_DISPLAY, COL_OPTION_VALUES); - standout(); - ch = LYgetstr(display_option, VISIBLE, - sizeof(display_option), NORECALL); - standend(); - move(L_DISPLAY, COL_OPTION_VALUES); - if ((term_options || ch == -1) || - (display != NULL && + case 'd': /* Change the display. */ + case 'D': + if (display && *display) { + strcpy(display_option, display); + } else { /* clear the NONE */ + move(L_DISPLAY, COL_OPTION_VALUES); + addstr(" "); + *display_option = '\0'; + } + option_statusline(ACCEPT_DATA); + move(L_DISPLAY, COL_OPTION_VALUES); + standout(); + ch = LYgetstr(display_option, VISIBLE, + sizeof(display_option), NORECALL); + standend(); + move(L_DISPLAY, COL_OPTION_VALUES); + if ((term_options || ch == -1) || + (display != NULL && #ifdef VMS - 0 == strcasecomp(display, display_option))) + !strcasecomp(display, display_option))) #else - 0 == strcmp(display, display_option))) + !strcmp(display, display_option))) #endif /* VMS */ - { - /* - * Cancelled, or a non-NULL display string - * wasn't changed. - FM - */ - addstr((display && *display) ? display : "NONE"); - clrtoeol(); - option_statusline(VALUE_ACCEPTED); - response = ' '; - break; - } else if (*display_option == '\0') { - if ((display == NULL) || - (display != NULL && *display == '\0')) { - /* - * NULL or zero-length display string - * wasn't changed. - FM - */ - addstr("NONE"); - clrtoeol(); - option_statusline(VALUE_ACCEPTED); - response = ' '; - break; - } - } + { + /* + * Cancelled, or a non-NULL display string + * wasn't changed. - FM + */ + addstr((display && *display) ? display : "NONE"); + clrtoeol(); + option_statusline(VALUE_ACCEPTED); + response = ' '; + break; + } else if (*display_option == '\0') { + if ((display == NULL) || + (display != NULL && *display == '\0')) { /* - * Set the new DISPLAY variable. - FM + * NULL or zero-length display string + * wasn't changed. - FM */ + addstr("NONE"); + clrtoeol(); + option_statusline(VALUE_ACCEPTED); + response = ' '; + break; + } + } + /* + * Set the new DISPLAY variable. - FM + */ #ifdef VMS - { - int i; - for (i = 0; display_option[i]; i++) - display_option[i] = TOUPPER(display_option[i]); - Define_VMSLogical(DISPLAY, display_option); - } + { + int i; + for (i = 0; display_option[i]; i++) + display_option[i] = TOUPPER(display_option[i]); + Define_VMSLogical(DISPLAY, display_option); + } #else - sprintf(putenv_command, "DISPLAY=%s", display_option); - putenv(putenv_command); + sprintf(putenv_command, "DISPLAY=%s", display_option); + putenv(putenv_command); #endif /* VMS */ if ((display = getenv(DISPLAY)) != NULL && *display == '\0') { @@ -396,7 +435,7 @@ draw_options: response = ' '; break; - case 'l': + case 'l': /* Change multibookmarks option. */ case 'L': if (LYMBMBlocked) { option_statusline(MULTIBOOKMARKS_DISALLOWED); @@ -410,20 +449,38 @@ draw_options: choices[2] = NULL; StrAllocCopy(choices[2],"ADVANCED"); choices[3] = NULL; - LYMultiBookmarks = boolean_choice(LYMultiBookmarks * - (1 + LYMBMAdvanced), + if (!LYSelectPopups) { + LYMultiBookmarks = boolean_choice((LYMultiBookmarks * + (1 + LYMBMAdvanced)), L_HOME, C_MULTI, choices); - FREE(choices[0]); - FREE(choices[1]); - FREE(choices[2]); + } else { + LYMultiBookmarks = popup_choice((LYMultiBookmarks * + (1 + LYMBMAdvanced)), + L_HOME, (C_MULTI - 1), + choices, + 3, FALSE); + } if (LYMultiBookmarks == 2) { LYMultiBookmarks = TRUE; LYMBMAdvanced = TRUE; } else { LYMBMAdvanced = FALSE; } - +#if defined(VMS) || defined(USE_SLANG) + if (LYSelectPopups) { + move(L_HOME, C_MULTI); + clrtoeol(); + addstr(choices[(LYMultiBookmarks * (1 + LYMBMAdvanced))]); + } +#endif /* VMS || USE_SLANG */ + FREE(choices[0]); + FREE(choices[1]); + FREE(choices[2]); +#if !defined(VMS) && !defined(USE_SLANG) + if (!LYSelectPopups) +#endif /* !VMS && !USE_SLANG */ + { move(L_HOME, B_BOOK); clrtoeol(); if (LYMultiBookmarks) { @@ -433,13 +490,27 @@ draw_options: addstr((bookmark_page && *bookmark_page) ? bookmark_page : "NONE"); } + } response = ' '; + if (LYSelectPopups) { +#if !defined(VMS) || defined(USE_SLANG) + if (term_options) { + term_options = FALSE; + } else { + AddValueAccepted = TRUE; + } + goto draw_options; +#else + term_options = FALSE; +#endif /* !VMS || USE_SLANG */ + } break; - case 'b': /* change the bookmark page location */ + case 'b': /* Change the bookmark page location. */ case 'B': - /* anonymous users should not be allowed to - * change the bookmark page + /* + * Anonymous users should not be allowed to + * change the bookmark page. */ if (!no_bookmark) { if (LYMultiBookmarks) { @@ -447,9 +518,9 @@ draw_options: signal(SIGINT, terminate_options); goto draw_options; } - if (bookmark_page && *bookmark_page) + if (bookmark_page && *bookmark_page) { strcpy(display_option, bookmark_page); - else { /* clear the NONE */ + } else { /* clear the NONE */ move(L_HOME, C_DEFAULT); clrtoeol(); *display_option = '\0'; @@ -487,9 +558,11 @@ draw_options: response = ' '; break; - case 'f': - case 'F': - /* copy strings into choice array */ + case 'f': /* Change ftp directory sorting. */ + case 'F': /* (also local for non-DIRED) */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0],"By Filename"); choices[1] = NULL; @@ -499,19 +572,45 @@ draw_options: choices[3] = NULL; StrAllocCopy(choices[3],"By Date "); choices[4] = NULL; + if (!LYSelectPopups) { HTfileSortMethod = boolean_choice(HTfileSortMethod, - L_FTPSTYPE, -1, choices); + L_FTPSTYPE, -1, + choices); + } else { + HTfileSortMethod = popup_choice(HTfileSortMethod, + L_FTPSTYPE, -1, + choices, + 4, FALSE); +#if defined(VMS) || defined(USE_SLANG) + move(L_FTPSTYPE, COL_OPTION_VALUES); + clrtoeol(); + addstr(choices[HTfileSortMethod]); +#endif /* VMS || USE_SLANG */ + } FREE(choices[0]); FREE(choices[1]); FREE(choices[2]); + FREE(choices[3]); response = ' '; + if (LYSelectPopups) { +#if !defined(VMS) || defined(USE_SLANG) + if (term_options) { + term_options = FALSE; + } else { + AddValueAccepted = TRUE; + } + goto draw_options; +#else + term_options = FALSE; +#endif /* !VMS || USE_SLANG */ + } break; - case 'p': /* change personal mail address for From headers */ + case 'p': /* Change personal mail address for From headers. */ case 'P': - if (personal_mail_address && *personal_mail_address) + if (personal_mail_address && *personal_mail_address) { strcpy(display_option, personal_mail_address); - else { /* clear the NONE */ + } else { /* clear the NONE */ move(L_MAIL_ADDRESS, COL_OPTION_VALUES); addstr(" "); *display_option = '\0'; @@ -539,9 +638,11 @@ draw_options: response = ' '; break; - case 's': + case 's': /* Change case sentitivity for searches. */ case 'S': - /* copy strings into choice array */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0],"CASE INSENSITIVE"); choices[1] = NULL; @@ -554,10 +655,23 @@ draw_options: response = ' '; break; - case 'c': + case 'c': /* Change charset setting. */ case 'C': + if (!LYSelectPopups) { current_char_set = boolean_choice(current_char_set, - L_CHARSET, -1, LYchar_set_names); + L_CHARSET, -1, + LYchar_set_names); + } else { + current_char_set = popup_choice(current_char_set, + L_CHARSET, -1, + LYchar_set_names, + 0, FALSE); +#if defined(VMS) || defined(USE_SLANG) + move(L_CHARSET, COL_OPTION_VALUES); + clrtoeol(); + addstr(LYchar_set_names[current_char_set]); +#endif /* VMS || USE_SLANG */ + } /* * Set the raw 8-bit or CJK mode defaults and * character set if changed. - FM @@ -568,30 +682,47 @@ draw_options: HTMLUseCharacterSet(current_char_set); CurrentCharSet = current_char_set; CurrentRawMode = LYRawMode; +#if !defined(VMS) && !defined(USE_SLANG) + if (!LYSelectPopups) +#endif /* !VMS && !USE_SLANG */ + { move(L_RAWMODE, COL_OPTION_VALUES); clrtoeol(); addstr(LYRawMode ? "ON " : "OFF"); } + } response = ' '; + if (LYSelectPopups) { +#if !defined(VMS) || defined(USE_SLANG) + if (term_options) { + term_options = FALSE; + } else { + AddValueAccepted = TRUE; + } + goto draw_options; +#else + term_options = FALSE; +#endif /* !VMS || USE_SLANG */ + } break; - case 'o': + case 'o': /* Change raw mode setting. */ case 'O': - /* copy strings into choice array */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0], "OFF"); choices[1] = NULL; StrAllocCopy(choices[1], "ON "); choices[2] = NULL; - LYRawMode = boolean_choice(LYRawMode, - L_RAWMODE, -1, choices); + LYRawMode = boolean_choice(LYRawMode, L_RAWMODE, -1, choices); /* * Set the LYUseDefaultRawMode value and character * handling if LYRawMode was changed. - FM */ if (CurrentRawMode != LYRawMode) { - HTMLSetUseDefaultRawMode(current_char_set, - LYRawMode); + HTMLSetUseDefaultRawMode(current_char_set, LYRawMode); HTMLSetCharacterHandling(current_char_set); CurrentRawMode = LYRawMode; } @@ -600,11 +731,11 @@ draw_options: response = ' '; break; - case 'g': /* change language preference */ + case 'g': /* Change language preference. */ case 'G': - if (language && *language) + if (language && *language) { strcpy(display_option, language); - else { /* clear the NONE */ + } else { /* clear the NONE */ move(L_LANGUAGE, COL_OPTION_VALUES); addstr(" "); *display_option = '\0'; @@ -631,11 +762,11 @@ draw_options: response = ' '; break; - case 'h': /* change character set preference */ + case 'h': /* Change charset preference. */ case 'H': - if (pref_charset && *pref_charset) + if (pref_charset && *pref_charset) { strcpy(display_option, pref_charset); - else { /* clear the NONE */ + } else { /* clear the NONE */ move(L_PREF_CHARSET, COL_OPTION_VALUES); addstr(" "); *display_option = '\0'; @@ -662,9 +793,11 @@ draw_options: response = ' '; break; - case 'v': + case 'v': /* Change VI keys setting. */ case 'V': - /* copy strings into choice array */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0],"OFF"); choices[1] = NULL; @@ -673,18 +806,21 @@ draw_options: vi_keys = boolean_choice(vi_keys, L_BOOL_A, C_VIKEYS, choices); - if (vi_keys) + if (vi_keys) { set_vi_keys(); - else + } else { reset_vi_keys(); + } FREE(choices[0]); FREE(choices[1]); response = ' '; break; - case 'M': + case 'M': /* Change emacs keys setting. */ case 'm': - /* copy strings into choice array */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0],"OFF"); choices[1] = NULL; @@ -693,21 +829,24 @@ draw_options: emacs_keys = boolean_choice(emacs_keys, L_BOOL_A, C_EMACSKEYS, choices); - if (emacs_keys) + if (emacs_keys) { set_emacs_keys(); - else + } else { reset_emacs_keys(); + } FREE(choices[0]); FREE(choices[1]); response = ' '; break; - case 'W': + case 'W': /* Change show dotfiles setting. */ case 'w': if (no_dotfiles) { option_statusline(DOTFILE_ACCESS_DISABLED); } else { - /* copy strings into choice array */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0],"OFF"); choices[1] = NULL; @@ -723,52 +862,134 @@ draw_options: response = ' '; break; - case 't': + case 't': /* Change select popups setting. */ case 'T': - /* copy strings into choice array */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0], "OFF"); choices[1] = NULL; StrAllocCopy(choices[1], "ON "); choices[2] = NULL; LYSelectPopups = boolean_choice(LYSelectPopups, - L_SELECT_POPUPS, -1, + L_BOOL_B, + C_SELECT_POPUPS, choices); FREE(choices[0]); FREE(choices[1]); response = ' '; break; - case 'k': + case '@': /* Change show cursor setting. */ + /* + * Copy strings into choice array. + */ + choices[0] = NULL; + StrAllocCopy(choices[0], "OFF"); + choices[1] = NULL; + StrAllocCopy(choices[1], "ON "); + choices[2] = NULL; + LYShowCursor = boolean_choice(LYShowCursor, + L_BOOL_B, + C_SHOW_CURSOR, + choices); + FREE(choices[0]); + FREE(choices[1]); + response = ' '; + break; + + case 'k': /* Change keypad mode. */ case 'K': - /* copy strings into choice array */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; - StrAllocCopy(choices[0],"Numbers act as arrows"); + StrAllocCopy(choices[0], + "Numbers act as arrows "); choices[1] = NULL; - StrAllocCopy(choices[1],"Links are numbered "); + StrAllocCopy(choices[1], + "Links are numbered "); choices[2] = NULL; + StrAllocCopy(choices[2], + "Links and form fields are numbered"); + choices[3] = NULL; + if (!LYSelectPopups) { keypad_mode = boolean_choice(keypad_mode, - L_KEYPAD, -1, choices); - if (keypad_mode == NUMBERS_AS_ARROWS) + L_KEYPAD, -1, + choices); + } else { + keypad_mode = popup_choice(keypad_mode, + L_KEYPAD, -1, + choices, + 3, FALSE); +#if defined(VMS) || defined(USE_SLANG) + move(L_KEYPAD, COL_OPTION_VALUES); + clrtoeol(); + addstr(choices[keypad_mode]); +#endif /* VMS || USE_SLANG */ + } + if (keypad_mode == NUMBERS_AS_ARROWS) { set_numbers_as_arrows(); - else + } else { reset_numbers_as_arrows(); + } FREE(choices[0]); FREE(choices[1]); + FREE(choices[2]); response = ' '; + if (LYSelectPopups) { +#if !defined(VMS) || defined(USE_SLANG) + if (term_options) { + term_options = FALSE; + } else { + AddValueAccepted = TRUE; + } + goto draw_options; +#else + term_options = FALSE; +#endif /* !VMS || USE_SLANG */ + } break; - case 'n': + case 'n': /* Change line editor key bindings. */ case 'N': + if (!LYSelectPopups) { current_lineedit = boolean_choice(current_lineedit, - L_LINEED, -1, LYLineeditNames); + L_LINEED, -1, + LYLineeditNames); + } else { + current_lineedit = popup_choice(current_lineedit, + L_LINEED, -1, + LYLineeditNames, + 0, FALSE); +#if defined(VMS) || defined(USE_SLANG) + move(L_LINEED, COL_OPTION_VALUES); + clrtoeol(); + addstr(LYLineeditNames[current_lineedit]); +#endif /* VMS || USE_SLANG */ + } response = ' '; + if (LYSelectPopups) { +#if !defined(VMS) || defined(USE_SLANG) + if (term_options) { + term_options = FALSE; + } else { + AddValueAccepted = TRUE; + } + goto draw_options; +#else + term_options = FALSE; +#endif /* !VMS || USE_SLANG */ + } break; #ifdef DIRED_SUPPORT - case 'i': + case 'i': /* Change local directory sorting. */ case 'I': - /* copy strings into choice array */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0],"Directories first"); choices[1] = NULL; @@ -776,18 +997,45 @@ draw_options: choices[2] = NULL; StrAllocCopy(choices[2],"Mixed style "); choices[3] = NULL; + if (!LYSelectPopups) { dir_list_style = boolean_choice(dir_list_style, - L_DIRED, -1, choices); + L_DIRED, -1, + choices); + } else { + dir_list_style = popup_choice(dir_list_style, + L_DIRED, -1, + choices, + 3, FALSE); +#if defined(VMS) || defined(USE_SLANG) + move(L_DIRED, COL_OPTION_VALUES); + clrtoeol(); + addstr(choices[dir_list_style]); +#endif /* VMS || USE_SLANG */ + } FREE(choices[0]); FREE(choices[1]); FREE(choices[2]); response = ' '; + if (LYSelectPopups) { +#if !defined(VMS) || defined(USE_SLANG) + if (term_options) { + term_options = FALSE; + } else { + AddValueAccepted = TRUE; + } + goto draw_options; +#else + term_options = FALSE; +#endif /* !VMS || USE_SLANG */ + } break; #endif /* DIRED_SUPPORT */ - case 'u': + case 'u': /* Change user mode. */ case 'U': - /* copy strings into choice array */ + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0],"Novice "); choices[1] = NULL; @@ -795,24 +1043,50 @@ draw_options: choices[2] = NULL; StrAllocCopy(choices[2],"Advanced "); choices[3] = NULL; + if (!LYSelectPopups) { user_mode = boolean_choice(user_mode, - L_USER_MODE, -1, choices); + L_USER_MODE, -1, + choices); + } else { + user_mode = popup_choice(user_mode, + L_USER_MODE, -1, + choices, + 3, FALSE); +#if defined(VMS) || defined(USE_SLANG) + move(L_USER_MODE, COL_OPTION_VALUES); + clrtoeol(); + addstr(choices[user_mode]); +#endif /* VMS || USE_SLANG */ + } FREE(choices[0]); FREE(choices[1]); FREE(choices[2]); - if(user_mode == NOVICE_MODE) - display_lines = LYlines-4; - else + if (user_mode == NOVICE_MODE) { + display_lines = (LYlines - 4); + } else { display_lines = LYlines-2; + } response = ' '; + if (LYSelectPopups) { +#if !defined(VMS) || defined(USE_SLANG) + if (term_options) { + term_options = FALSE; + } else { + AddValueAccepted = TRUE; + } + goto draw_options; +#else + term_options = FALSE; +#endif /* !VMS || USE_SLANG */ + } break; - case 'a': + case 'a': /* Change user agent string. */ case 'A': if (!no_useragent) { - if (LYUserAgent && *LYUserAgent) + if (LYUserAgent && *LYUserAgent) { strcpy(display_option, LYUserAgent); - else { /* clear the NONE */ + } else { /* clear the NONE */ move(L_HOME, COL_OPTION_VALUES); addstr(" "); *display_option = '\0'; @@ -852,22 +1126,29 @@ draw_options: break; #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS - case 'x': /* local exec */ + case 'x': /* Change local exec restriction. */ case 'X': - if (!exec_frozen) { + if (exec_frozen && !LYSelectPopups) { + option_statusline(CHANGE_OF_SETTING_DISALLOWED); + response = ' '; + break; + } #ifndef NEVER_ALLOW_REMOTE_EXEC if (local_exec) { itmp = 2; - } else { + } else #else { #endif /* NEVER_ALLOW_REMOTE_EXEC */ - if (local_exec_on_local_files) + if (local_exec_on_local_files) { itmp= 1; - else + } else { itmp = 0; } - /* copy strings into choice array */ + } + /* + * Copy strings into choice array. + */ choices[0] = NULL; StrAllocCopy(choices[0],"ALWAYS OFF "); choices[1] = NULL; @@ -877,57 +1158,79 @@ draw_options: StrAllocCopy(choices[2],"ALWAYS ON "); choices[3] = NULL; #endif /* NEVER_ALLOW_REMOTE_EXEC */ - itmp = boolean_choice(itmp, L_EXEC, -1, choices); - + if (!LYSelectPopups) { + itmp = boolean_choice(itmp, + L_EXEC, -1, + choices); + } else { + itmp = popup_choice(itmp, + L_EXEC, -1, + choices, + 0, (exec_frozen ? TRUE : FALSE)); +#if defined(VMS) || defined(USE_SLANG) + move(L_EXEC, COL_OPTION_VALUES); + clrtoeol(); + addstr(choices[itmp]); +#endif /* VMS || USE_SLANG */ + } FREE(choices[0]); FREE(choices[1]); #ifndef NEVER_ALLOW_REMOTE_EXEC FREE(choices[2]); #endif /* NEVER_ALLOW_REMOTE_EXEC */ + if (!exec_frozen) { switch(itmp) { case 0: local_exec = FALSE; local_exec_on_local_files = FALSE; - response = ' '; break; case 1: local_exec = FALSE; local_exec_on_local_files = TRUE; - response = ' '; break; #ifndef NEVER_ALLOW_REMOTE_EXEC case 2: local_exec = TRUE; local_exec_on_local_files = FALSE; - response = ' '; break; #endif /* NEVER_ALLOW_REMOTE_EXEC */ } /* end switch */ - } else { - option_statusline(CHANGE_OF_SETTING_DISALLOWED); } response = ' '; + if (LYSelectPopups) { +#if !defined(VMS) || defined(USE_SLANG) + if (exec_frozen || term_options) { + term_options = FALSE; + } else { + AddValueAccepted = TRUE; + } + goto draw_options; +#else + term_options = FALSE; +#endif /* !VMS || USE_SLANG */ + } break; #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */ - case '>': + case '>': /* Save current options to RC file. */ if (!no_option_save) { option_statusline(SAVING_OPTIONS); - if(save_rc()) + if (save_rc()) { option_statusline(OPTIONS_SAVED); - else + } else { HTAlert(OPTIONS_NOT_SAVED); - + } } else { option_statusline(R_TO_RETURN_TO_LYNX); - /* change response so that we don't exit - * the options menu + /* + * Change response so that we don't exit + * the options menu. */ response = ' '; } break; - case 'r': + case 'r': /* Return to document (quit options menu). */ case 'R': break; @@ -949,17 +1252,25 @@ draw_options: * and return it. */ PRIVATE int boolean_choice ARGS4( - int, status, + int, cur_choice, int, line, int, column, char **, choices) { int response = 0; - int respcmd; + int cmd = 0; int number = 0; int col = (column >= 0 ? column : COL_OPTION_VALUES); + int orig_choice = cur_choice; +#ifdef VMS + extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */ +#endif /* VMS */ - for (; choices[number] != NULL; number++) + /* + * Get the number of choices and then make + * number zero-based. + */ + for (number = 0; choices[number] != NULL; number++) ; /* empty loop body */ number--; @@ -970,11 +1281,13 @@ PRIVATE int boolean_choice ARGS4( option_statusline(ANY_KEY_CHANGE_RET_ACCEPT); /* - * Highlight the current selection. + * Highlight the current choice. */ move(line, col); standout(); - addstr(choices[status]); + addstr(choices[cur_choice]); + if (LYShowCursor) + move(line, (col - 1)); refresh(); /* @@ -983,37 +1296,63 @@ PRIVATE int boolean_choice ARGS4( * it can be changed, until the user accepts * the current choice. */ + term_options = FALSE; while (1) { move(line, col); + if (term_options == FALSE) { response = LYgetch(); - if (term_options || response == 7 || response == 3) + } + if (term_options || response == 7 || response == 3) { + /* + * Control-C or Control-G. + */ + response = '\n'; + term_options = TRUE; + cur_choice = orig_choice; + } +#ifdef VMS + if (HadVMSInterrupt) { + HadVMSInterrupt = FALSE; response = '\n'; - if (response != '\n' && response != '\r') { - respcmd = keymap[response+1]; -#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE) - /* does this make sense here? dunno.. - kw */ - if (!respcmd && override[response+1] && !no_dired_support) - respcmd = override[response+1]; -#endif /* DIRED_SUPPORT && OK_OVERRIDE */ - switch (respcmd) { + term_options = TRUE; + cur_choice = orig_choice; + } +#endif /* VMS */ + if ((response != '\n' && response != '\r') && + (cmd = keymap[response+1]) != LYK_ACTIVATE) { + switch (cmd) { + case LYK_HOME: + cur_choice = 0; + break; + + case LYK_END: + cur_choice = number; + break; + + case LYK_REFRESH: + clearok(curscr, TRUE); + refresh(); + break; + + case LYK_QUIT: + case LYK_ABORT: + case LYK_PREV_DOC: + cur_choice = orig_choice; + term_options = TRUE; + break; + case LYK_PREV_PAGE: + case LYK_UP_HALF: case LYK_UP_TWO: case LYK_PREV_LINK: case LYK_UP_LINK: case LYK_LEFT_LINK: - case LYK_PREV_DOC: - if(status == 0) - status = number; /* go back to end */ + if(cur_choice == 0) + cur_choice = number; /* go back to end */ else - status--; - break; - case LYK_END: - status = number; + cur_choice--; break; - case LYK_HOME: - status = 0; - break; case LYK_1: case LYK_2: case LYK_3: @@ -1023,28 +1362,37 @@ PRIVATE int boolean_choice ARGS4( case LYK_7: case LYK_8: case LYK_9: - if((respcmd - LYK_1 + 1) <= number) { - status = respcmd -LYK_1 + 1; + if((cmd - LYK_1 + 1) <= number) { + cur_choice = cmd -LYK_1 + 1; break; } /* else fall through! */ default: - if (status == number) - status = 0; /* go over the top and around */ + if (cur_choice == number) + cur_choice = 0; /* go over the top and around */ else - status++; + cur_choice++; } /* end of switch */ - addstr(choices[status]); + addstr(choices[cur_choice]); + if (LYShowCursor) + move(line, (col - 1)); refresh(); } else { /* - * Unhighlight selection. + * Unhighlight choice. */ move(line, col); standend(); - addstr(choices[status]); + addstr(choices[cur_choice]); + if (term_options) { + term_options = FALSE; + option_statusline(CANCELLED); + sleep(InfoSecs); + option_statusline(""); + } else { option_statusline(VALUE_ACCEPTED); - return(status); + } + return(cur_choice); } } } @@ -1053,10 +1401,14 @@ PRIVATE void terminate_options ARGS1( int, sig) { term_options=TRUE; - /* Reassert the AST */ + /* + * Reassert the AST. + */ signal(SIGINT, terminate_options); #ifdef VMS - /* refresh the screen to get rid of the "interrupt" message */ + /* + * Refresh the screen to get rid of the "interrupt" message. + */ if (!dump_output_immediately) { clearok(curscr, TRUE); refresh(); @@ -1345,3 +1697,1035 @@ draw_bookmark_list: term_options = FALSE; signal(SIGINT, cleanup_sig); } + +/* +** This function prompts for a choice or page number. +** If a 'g' or 'p' suffix is included, that will be +** loaded into c. Otherwise, c is zeroed. - FM +*/ +PRIVATE int get_popup_choice_number ARGS1( + int *, c) +{ + char temp[120]; + + /* + * Load the c argument into the prompt buffer. + */ + temp[0] = *c; + temp[1] = '\0'; + option_statusline(OPTION_CHOICE_NUMBER); + + /* + * Get the number, possibly with a suffix, from the user. + */ + if (LYgetstr(temp, VISIBLE, sizeof(temp), NORECALL) < 0 || + *temp == 0 || term_options) { + option_statusline(CANCELLED); + sleep(InfoSecs); + *c = '\0'; + term_options = FALSE; + return(0); + } + + /* + * If we had a 'g' or 'p' suffix, load it into c. + * Otherwise, zero c. Then return the number. + */ + if (strchr(temp, 'g') != NULL || strchr(temp, 'G') != NULL) { + *c = 'g'; + } else if (strchr(temp, 'p') != NULL || strchr(temp, 'P') != NULL) { + *c = 'p'; + } else { + *c = '\0'; + } + return(atoi(temp)); +} + +/* + * This function offers the choices for values of an + * option via a popup window which functions like + * that for selection of options in a form. - FM + */ +PRIVATE int popup_choice ARGS6( + int, cur_choice, + int, line, + int, column, + char **, choices, + int, i_length, + int, disabled) +{ + int ly = line; + int lx = (column >= 0 ? column : (COL_OPTION_VALUES - 1)); + int c = 0, cmd = 0, i = 0, j = 0; + int orig_choice = cur_choice; +#ifndef USE_SLANG + WINDOW * form_window; +#endif /* !USE_SLANG */ + int num_choices = 0, top, bottom, length = -1, width = 0; + char ** Cptr = choices; + int window_offset = 0; + int DisplayLines = (LYlines - 2); + char Cnum[64]; + int Lnum; + int npages; +#ifdef VMS + extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */ +#endif /* VMS */ + static char prev_target[512]; /* Search string buffer */ + static char prev_target_buffer[512]; /* Next search buffer */ + static BOOL first = TRUE; + char *cp; + int ch = 0, recall; + int QueryTotal; + int QueryNum; + BOOLEAN FirstRecall = TRUE; + BOOLEAN ReDraw = FALSE; + int number; + char buffer[512]; + + /* + * Initialize the search string buffer. - FM + */ + if (first) { + *prev_target_buffer = '\0'; + first = FALSE; + } + *prev_target = '\0'; + QueryTotal = (search_queries ? HTList_count(search_queries) : 0); + recall = ((QueryTotal >= 1) ? RECALL : NORECALL); + QueryNum = QueryTotal; + + /* + * Count the number of choices to be displayed, where + * num_choices ranges from 0 to n, and set width to the + * longest choice string length. Also set Lnum to the + * length for the highest choice number, then decrement + * num_choices so as to be zero-based. The window width + * will be based on the sum of width and Lnum. - FM + */ + for (num_choices = 0; Cptr[num_choices] != NULL; num_choices++) { + if (strlen(Cptr[num_choices]) > width) { + width = strlen(Cptr[num_choices]); + } + } + sprintf(Cnum, "%d: ", num_choices); + Lnum = strlen(Cnum); + num_choices--; + + /* + * Let's assume for the sake of sanity that ly is the number + * corresponding to the line the option is on. + * Let's also assume that cur_choice is the number of the + * choice that should be initially selected, with 0 being + * the first choice. + * So what we have, is the top equal to the current screen line + * subtracting the cur_choice + 1 (the one must be for the top + * line we will draw in a box). If the top goes under 0, then + * consider it 0. + */ + top = ly - (cur_choice + 1); + if (top < 0) + top = 0; + + /* + * Check and see if we need to put the i_length parameter up to + * the number of real choices. + */ + if (i_length < 1) { + i_length = num_choices; + } else { + /* + * Otherwise, it is really one number too high. + */ + i_length--; + } + + /* + * The bottom is the value of the top plus the number of choices + * to view plus 3 (one for the top line, one for the bottom line, + * and one to offset the 0 counted in the num_choices). + */ + bottom = top + i_length + 3; + + /* + * Hmm... If the bottom goes beyond the number of lines available, + */ + if (bottom > DisplayLines) { + /* + * Position the window at the top if we have more + * choices than will fit in the window. + */ + if ((i_length + 3) > DisplayLines) { + top = 0; + bottom = (top + (i_length + 3)); + if (bottom > DisplayLines) + bottom = (DisplayLines + 1); + } else { + /* + * Try to position the window so that the selected choice will + * appear where the choice box currently is positioned. + * It could end up too high, at this point, but we'll move it + * down latter, if that has happened. + */ + top = (DisplayLines + 1) - (i_length + 3); + bottom = (DisplayLines + 1); + } + } + + /* + * This is really fun, when the length is 4, it means 0 to 4, or 5. + */ + length = (bottom - top) - 2; + + /* + * Move the window down if it's too high. + */ + if (bottom < ly + 2) { + bottom = ly + 2; + if (bottom > DisplayLines + 1) + bottom = DisplayLines + 1; + top = bottom - length - 2; + } + + /* + * Set up the overall window, including the boxing characters ('*'), + * if it all fits. Otherwise, set up the widest window possible. - FM + */ +#ifdef USE_SLANG + SLsmg_fill_region(top, lx - 1, bottom - top, (Lnum + width + 4), ' '); +#else + if (!(form_window = newwin(bottom - top, (Lnum + width + 4), + top, (lx - 1))) && + !(form_window = newwin(bottom - top, 0, top, 0))) { + option_statusline(POPUP_FAILED); + return(orig_choice); + } + scrollok(form_window, TRUE); +#endif /* USE_SLANG */ + + /* + * Clear the command line and write + * the popup statusline. - FM + */ + move((LYlines - 2), 0); + clrtoeol(); + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + + /* + * Set up the window_offset for choices. + * cur_choice ranges from 0...n + * length ranges from 0...m + */ + if (cur_choice >= length) { + window_offset = cur_choice - length + 1; + } + + /* + * Compute the number of popup window pages. - FM + */ + npages = ((num_choices + 1) > length) ? + (((num_choices + 1) + (length - 1))/(length)) + : 1; +/* + * OH! I LOVE GOTOs! hack hack hack + */ +redraw: + Cptr = choices; + + /* + * Display the boxed choices. + */ + for (i = 0; i <= num_choices; i++) { + if (i >= window_offset && i - window_offset < length) { + sprintf(Cnum, "%s%d: ", + ((num_choices > 8 && i < 9) ? + " " : ""), + (i + 1)); +#ifdef USE_SLANG + SLsmg_gotorc(top + ((i + 1) - window_offset), (lx - 1 + 2)); + addstr(Cnum); + SLsmg_write_nstring(Cptr[i], width); +#else + wmove(form_window, ((i + 1) - window_offset), 2); + wclrtoeol(form_window); + waddstr(form_window, Cnum); + waddstr(form_window, Cptr[i]); +#endif /* USE_SLANG */ + } + } +#ifdef USE_SLANG + SLsmg_draw_box(top, (lx - 1), (bottom - top), (Lnum + width + 4)); +#else +#ifdef VMS + VMSbox(form_window, (bottom - top), (Lnum + width + 4)); +#else + box(form_window, BOXVERT, BOXHORI); +#endif /* VMS */ + wrefresh(form_window); +#endif /* USE_SLANG */ + Cptr = NULL; + + /* + * Loop on user input. + */ + while (cmd != LYK_ACTIVATE) { + /* + * Unreverse cur choice. + */ + if (Cptr != NULL) { + sprintf(Cnum, "%s%d: ", + ((num_choices > 8 && i < 9) ? + " " : ""), + (i + 1)); +#ifdef USE_SLANG + SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2)); + addstr(Cnum); + SLsmg_write_nstring(Cptr[i], width); +#else + wmove(form_window, ((i + 1) - window_offset), 2); + waddstr(form_window, Cnum); + waddstr(form_window, Cptr[i]); +#endif /* USE_SLANG */ + } + Cptr = choices; + i = cur_choice; + sprintf(Cnum, "%s%d: ", + ((num_choices > 8 && i < 9) ? + " " : ""), + (i + 1)); +#ifdef USE_SLANG + SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2)); + addstr(Cnum); + SLsmg_set_color(2); + SLsmg_write_nstring(Cptr[i], width); + SLsmg_set_color(0); + /* + * If LYShowCursor is ON, move the cursor to the left + * of the current choice, so that blind users, who are + * most likely to have LYShowCursor ON, will have it's + * string spoken or passed to the braille interface as + * each choice is made current. Otherwise, move it to + * the bottom, right column of the screen, to "hide" + * the cursor as for the main document, and let sighted + * users rely on the current choice's highlighting or + * color without the distraction of a blinking cursor + * in the window. - FM + */ + if (LYShowCursor) + SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 1)); + else + SLsmg_gotorc((LYlines - 1), (LYcols - 1)); + SLsmg_refresh(); +#else + wmove(form_window, ((i + 1) - window_offset), 2); + waddstr(form_window, Cnum); + wstart_reverse(form_window); + waddstr(form_window, Cptr[i]); + wstop_reverse(form_window); + /* + * If LYShowCursor is ON, move the cursor to the left + * of the current choice, so that blind users, who are + * most likely to have LYShowCursor ON, will have it's + * string spoken or passed to the braille interface as + * each choice is made current. Otherwise, leave it to + * the right of the current choice, since we can't move + * it out of the window, and let sighted users rely on + * the highlighting of the current choice without the + * distraction of a blinking cursor preceding it. - FM + */ + if (LYShowCursor) + wmove(form_window, ((i + 1) - window_offset), 1); + wrefresh(form_window); +#endif /* USE_SLANG */ + + term_options = FALSE; + c = LYgetch(); + if (term_options || c == 3 || c == 7) { + /* + * Control-C or Control-G + */ + cmd = LYK_QUIT; + } else { + cmd = keymap[c+1]; + } +#ifdef VMS + if (HadVMSInterrupt) { + HadVMSInterrupt = FALSE; + cmd = LYK_QUIT; + } +#endif /* VMS */ + + switch(cmd) { + case LYK_F_LINK_NUM: + c = '\0'; + case LYK_1: + case LYK_2: + case LYK_3: + case LYK_4: + case LYK_5: + case LYK_6: + case LYK_7: + case LYK_8: + case LYK_9: + /* + * Get a number from the user, possibly with + * a 'g' or 'p' suffix (which will be loaded + * into c). - FM & LE + */ + number = get_popup_choice_number((int *)&c); + + /* + * Check for a 'p' suffix. - FM + */ + if (c == 'p') { + /* + * Treat 1 or less as the first page. - FM + */ + if (number <= 1) { + if (window_offset == 0) { + option_statusline(ALREADY_AT_CHOICE_BEGIN); + sleep(MessageSecs); + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + break; + } + window_offset = 0; + cur_choice = 0; + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + goto redraw; + } + + /* + * Treat a number equal to or greater than the + * number of pages as the last page. - FM + */ + if (number >= npages) { + if (window_offset >= ((num_choices - length) + 1)) { + option_statusline(ALREADY_AT_CHOICE_END); + sleep(MessageSecs); + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + break; + } + window_offset = ((npages - 1) * length); + if (window_offset > (num_choices - length)) { + window_offset = (num_choices - length + 1); + } + if (cur_choice < window_offset) + cur_choice = window_offset; + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + goto redraw; + } + + /* + * We want an intermediate page. - FM + */ + if (((number - 1) * length) == window_offset) { + sprintf(buffer, ALREADY_AT_CHOICE_PAGE, number); + option_statusline(buffer); + sleep(MessageSecs); + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + break; + } + cur_choice = window_offset = ((number - 1) * length); + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + goto redraw; + + } + + /* + * Check for a positive number, which signifies + * that a choice should be sought. - FM + */ + if (number > 0) { + /* + * Decrement the number so as to correspond + * with our cur_choice values. - FM + */ + number--; + + /* + * If the number is in range and had no legal + * suffix, select the indicated choice. - FM + */ + if (number <= num_choices && c == '\0') { + cur_choice = number; + cmd = LYK_ACTIVATE; + break; + } + + /* + * Verify that we had a 'g' suffix, + * and act on the number. - FM + */ + if (c == 'g') { + if (cur_choice == number) { + /* + * The choice already is current. - FM + */ + sprintf(buffer, + CHOICE_ALREADY_CURRENT, (number + 1)); + option_statusline(buffer); + sleep(MessageSecs); + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + break; + } + + if (number <= num_choices) { + /* + * The number is in range and had a 'g' + * suffix, so make it the current choice, + * scrolling if needed. - FM + */ + j = (number - cur_choice); + cur_choice = number; + if ((j > 0) && + (cur_choice - window_offset) >= length) { + window_offset += j; + if (window_offset > (num_choices - length + 1)) + window_offset = (num_choices - length + 1); + } else if ((cur_choice - window_offset) < 0) { + window_offset -= abs(j); + if (window_offset < 0) + window_offset = 0; + } + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + goto redraw; + } + + /* + * Not in range. - FM + */ + option_statusline(BAD_CHOICE_NUM_ENTERED); + sleep(MessageSecs); + } + } + + /* + * Restore the popup statusline. - FM + */ + if (disabled) { + option_statusline(CHOICE_LIST_UNM_MSG); + } else { + option_statusline(CHOICE_LIST_MESSAGE); + } + break; + + case LYK_PREV_LINK: + case LYK_UP_LINK: + + if (cur_choice > 0) + cur_choice--; + + /* + * Scroll the window up if necessary. + */ + if ((cur_choice - window_offset) < 0) { + window_offset--; + goto redraw; + } + break; + + case LYK_NEXT_LINK: + case LYK_DOWN_LINK: + if (cur_choice < num_choices) + cur_choice++; + + /* + * Scroll the window down if necessary + */ + if ((cur_choice - window_offset) >= length) { + window_offset++; + goto redraw; + } + break; + + case LYK_NEXT_PAGE: + /* + * Okay, are we on the last page of the choices list? + * If not then, + */ + if (window_offset != (num_choices - length + 1)) { + /* + * Modify the current choice to not be a + * coordinate in the list, but a coordinate + * on the item selected in the window. + */ + cur_choice -= window_offset; + + /* + * Page down the proper length for the list. + * If simply to far, back up. + */ + window_offset += length; + if (window_offset > (num_choices - length)) { + window_offset = (num_choices - length + 1); + } + + /* + * Readjust the current choice to be a choice + * list coordinate rather than window. + * Redraw this thing. + */ + cur_choice += window_offset; + goto redraw; + } + else if (cur_choice < num_choices) { + /* + * Already on last page of the choice list so + * just redraw it with the last item selected. + */ + cur_choice = num_choices; + } + break; + + case LYK_PREV_PAGE: + /* + * Are we on the first page of the choice list? + * If not then, + */ + if (window_offset != 0) { + /* + * Modify the current choice to not be a choice + * list coordinate, but a window coordinate. + */ + cur_choice -= window_offset; + + /* + * Page up the proper length. + * If too far, back up. + */ + window_offset -= length; + if (window_offset < 0) { + window_offset = 0; + } + + /* + * Readjust the current choice. + */ + cur_choice += window_offset; + goto redraw; + } else if (cur_choice > 0) { + /* + * Already on the first page so just + * back up to the first item. + */ + cur_choice = 0; + } + break; + + case LYK_HOME: + cur_choice = 0; + if (window_offset > 0) { + window_offset = 0; + goto redraw; + } + break; + + case LYK_END: + cur_choice = num_choices; + if (window_offset != (num_choices - length + 1)) { + window_offset = (num_choices - length + 1); + goto redraw; + } + break; + + case LYK_DOWN_TWO: + cur_choice += 2; + if (cur_choice > num_choices) + cur_choice = num_choices; + + /* + * Scroll the window down if necessary. + */ + if ((cur_choice - window_offset) >= length) { + window_offset += 2; + if (window_offset > (num_choices - length + 1)) + window_offset = (num_choices - length + 1); + goto redraw; + } + break; + + case LYK_UP_TWO: + cur_choice -= 2; + if (cur_choice < 0) + cur_choice = 0; + + /* + * Scroll the window up if necessary. + */ + if ((cur_choice - window_offset) < 0) { + window_offset -= 2; + if (window_offset < 0) + window_offset = 0; + goto redraw; + } + break; + + case LYK_DOWN_HALF: + cur_choice += (length/2); + if (cur_choice > num_choices) + cur_choice = num_choices; + + /* + * Scroll the window down if necessary. + */ + if ((cur_choice - window_offset) >= length) { + window_offset += (length/2); + if (window_offset > (num_choices - length + 1)) + window_offset = (num_choices - length + 1); + goto redraw; + } + break; + + case LYK_UP_HALF: + cur_choice -= (length/2); + if (cur_choice < 0) + cur_choice = 0; + + /* + * Scroll the window up if necessary. + */ + if ((cur_choice - window_offset) < 0) { + window_offset -= (length/2); + if (window_offset < 0) + window_offset = 0; + goto redraw; + } + break; + + case LYK_REFRESH: + clearok(curscr, TRUE); + refresh(); + break; + + case LYK_NEXT: + if (recall && *prev_target_buffer == '\0') { + /* + * We got a 'n'ext command with no prior query + * specified within the popup window. See if + * one was entered when the popup was retracted, + * and if so, assume that's what's wanted. Note + * that it will become the default within popups, + * unless another is entered within a popup. If + * the within popup default is to be changed at + * that point, use WHEREIS ('/') and enter it, + * or the up- or down-arrow keys to seek any of + * the previously entered queries, regardless of + * whether they were entered within or outside + * of a popup window. - FM + */ + if ((cp = (char *)HTList_objectAt(search_queries, + 0)) != NULL) { + strcpy(prev_target_buffer, cp); + QueryNum = 0; + FirstRecall = FALSE; + } + } + strcpy(prev_target, prev_target_buffer); + case LYK_WHEREIS: + if (*prev_target == '\0' ) { + option_statusline(ENTER_WHEREIS_QUERY); + if ((ch = LYgetstr(prev_target, VISIBLE, + sizeof(prev_target_buffer), + recall)) < 0) { + /* + * User cancelled the search via ^G. - FM + */ + option_statusline(CANCELLED); + sleep(InfoSecs); + goto restore_popup_statusline; + } + } + +check_recall: + if (*prev_target == '\0' && + !(recall && (ch == UPARROW || ch == DNARROW))) { + /* + * No entry. Simply break. - FM + */ + option_statusline(CANCELLED); + sleep(InfoSecs); + goto restore_popup_statusline; + } + + if (recall && ch == UPARROW) { + if (FirstRecall) { + /* + * Use the current string or + * last query in the list. - FM + */ + FirstRecall = FALSE; + if (*prev_target_buffer) { + for (QueryNum = (QueryTotal - 1); + QueryNum > 0; QueryNum--) { + if ((cp = (char *)HTList_objectAt( + search_queries, + QueryNum)) != NULL && + !strcmp(prev_target_buffer, cp)) { + break; + } + } + } else { + QueryNum = 0; + } + } else { + /* + * Go back to the previous query in the list. - FM + */ + QueryNum++; + } + if (QueryNum >= QueryTotal) + /* + * Roll around to the last query in the list. - FM + */ + QueryNum = 0; + if ((cp = (char *)HTList_objectAt(search_queries, + QueryNum)) != NULL) { + strcpy(prev_target, cp); + if (*prev_target_buffer && + !strcmp(prev_target_buffer, prev_target)) { + option_statusline(EDIT_CURRENT_QUERY); + } else if ((*prev_target_buffer && QueryTotal == 2) || + (!(*prev_target_buffer) && + QueryTotal == 1)) { + option_statusline(EDIT_THE_PREV_QUERY); + } else { + option_statusline(EDIT_A_PREV_QUERY); + } + if ((ch = LYgetstr(prev_target, VISIBLE, + sizeof(prev_target_buffer), recall)) < 0) { + /* + * User cancelled the search via ^G. - FM + */ + option_statusline(CANCELLED); + sleep(InfoSecs); + goto restore_popup_statusline; + } + goto check_recall; + } + } else if (recall && ch == DNARROW) { + if (FirstRecall) { + /* + * Use the current string or + * first query in the list. - FM + */ + FirstRecall = FALSE; + if (*prev_target_buffer) { + for (QueryNum = 0; + QueryNum < (QueryTotal - 1); QueryNum++) { + if ((cp = (char *)HTList_objectAt( + search_queries, + QueryNum)) != NULL && + !strcmp(prev_target_buffer, cp)) { + break; + } + } + } else { + QueryNum = (QueryTotal - 1); + } + } else { + /* + * Advance to the next query in the list. - FM + */ + QueryNum--; + } + if (QueryNum < 0) + /* + * Roll around to the first query in the list. - FM + */ + QueryNum = (QueryTotal - 1); + if ((cp = (char *)HTList_objectAt(search_queries, + QueryNum)) != NULL) { + strcpy(prev_target, cp); + if (*prev_target_buffer && + !strcmp(prev_target_buffer, prev_target)) { + option_statusline(EDIT_CURRENT_QUERY); + } else if ((*prev_target_buffer && + QueryTotal == 2) || + (!(*prev_target_buffer) && + QueryTotal == 1)) { + option_statusline(EDIT_THE_PREV_QUERY); + } else { + option_statusline(EDIT_A_PREV_QUERY); + } + if ((ch = LYgetstr(prev_target, VISIBLE, + sizeof(prev_target_buffer), + recall)) < 0) { + /* + * User cancelled the search via ^G. - FM + */ + option_statusline(CANCELLED); + sleep(InfoSecs); + goto restore_popup_statusline; + } + goto check_recall; + } + } + /* + * Replace the search string buffer with the new target. - FM + */ + strcpy(prev_target_buffer, prev_target); + HTAddSearchQuery(prev_target_buffer); + + /* + * Start search at the next choice. - FM + */ + for (j = 1; Cptr[i+j] != NULL; j++) { + sprintf(buffer, "%s%d: %s", + ((num_choices > 8 && (j + i) < 9) ? + " " : ""), + (i + j + 1), + Cptr[i+j]); + if (case_sensitive) { + if (strstr(buffer, prev_target_buffer) != NULL) + break; + } else { + if (LYstrstr(buffer, prev_target_buffer) != NULL) + break; + } + } + if (Cptr[i+j] != NULL) { + /* + * We have a hit, so make that choice the current. - FM + */ + cur_choice += j; + /* + * Scroll the window down if necessary. + */ + if ((cur_choice - window_offset) >= length) { + window_offset += j; + if (window_offset > (num_choices - length + 1)) + window_offset = (num_choices - length + 1); + ReDraw = TRUE; + } + goto restore_popup_statusline; + } + + /* + * If we started at the beginning, it can't be present. - FM + */ + if (cur_choice == 0) { + _user_message(STRING_NOT_FOUND, prev_target_buffer); + sleep(MessageSecs); + goto restore_popup_statusline; + } + + /* + * Search from the beginning to the current choice. - FM + */ + for (j = 0; j < cur_choice; j++) { + sprintf(buffer, "%s%d: %s", + ((num_choices > 8 && j < 9) ? + " " : ""), + (j + 1), + Cptr[j]); + if (case_sensitive) { + if (strstr(buffer, prev_target_buffer) != NULL) + break; + } else { + if (LYstrstr(buffer, prev_target_buffer) != NULL) + break; + } + } + if (j < cur_choice) { + /* + * We have a hit, so make that choice the current. - FM + */ + j = (cur_choice - j); + cur_choice -= j; + /* + * Scroll the window up if necessary. + */ + if ((cur_choice - window_offset) < 0) { + window_offset -= j; + if (window_offset < 0) + window_offset = 0; + ReDraw = TRUE; + } + goto restore_popup_statusline; + } + + /* + * Didn't find it in the preceding choices either. - FM + */ + _user_message(STRING_NOT_FOUND, prev_target_buffer); + sleep(MessageSecs); + +restore_popup_statusline: + /* + * Restore the popup statusline and + * reset the search variables. - FM + */ + if (disabled) + option_statusline(CHOICE_LIST_UNM_MSG); + else + option_statusline(CHOICE_LIST_MESSAGE); + *prev_target = '\0'; + QueryTotal = (search_queries ? HTList_count(search_queries) + : 0); + recall = ((QueryTotal >= 1) ? RECALL : NORECALL); + QueryNum = QueryTotal; + if (ReDraw == TRUE) { + ReDraw = FALSE; + goto redraw; + } + break; + + case LYK_QUIT: + case LYK_ABORT: + case LYK_PREV_DOC: + cur_choice = orig_choice; + term_options = TRUE; + option_statusline(CANCELLED); + sleep(MessageSecs); + cmd = LYK_ACTIVATE; /* to exit */ + break; + } + } +#ifndef USE_SLANG + delwin(form_window); +#endif /* !USE_SLANG */ + + if (disabled || term_options) { + option_statusline(""); + return(orig_choice); + } else { + option_statusline(VALUE_ACCEPTED); + return(cur_choice); + } +} diff --git a/src/LYOptions.h b/src/LYOptions.h index c313d257..5b98fcb3 100644 --- a/src/LYOptions.h +++ b/src/LYOptions.h @@ -7,7 +7,13 @@ extern BOOLEAN term_options; extern void options NOPARAMS; extern void edit_bookmarks NOPARAMS; -/* values for options */ +/* + * Values for the options menu. - FM + * + * L_foo values are the Y coordinates for the menu item. + * B_foo values are the X coordinates for the item's prompt string. + * C_foo values are the X coordinates for the item's value string. + */ #define L_EDITOR 2 #define L_DISPLAY 3 @@ -32,7 +38,12 @@ extern void edit_bookmarks NOPARAMS; #define B_SHOW_DOTFILES 44 #define C_SHOW_DOTFILES 62 -#define L_SELECT_POPUPS 13 +#define L_BOOL_B 13 +#define B_SELECT_POPUPS 5 +#define C_SELECT_POPUPS 36 +#define B_SHOW_CURSOR 44 +#define C_SHOW_CURSOR 62 + #define L_KEYPAD 14 #define L_LINEED 15 diff --git a/src/LYPrint.c b/src/LYPrint.c index 3bd365d7..58d0b1a1 100644 --- a/src/LYPrint.c +++ b/src/LYPrint.c @@ -53,7 +53,8 @@ extern BOOLEAN LYHaveCJKCharacterSet; PRIVATE int remove_quotes PARAMS((char *string)); #endif /* VMS */ -PUBLIC int printfile ARGS1(document *,newdoc) +PUBLIC int printfile ARGS1( + document *, newdoc) { static char tempfile[256]; static BOOLEAN first = TRUE; @@ -330,6 +331,21 @@ PUBLIC int printfile ARGS1(document *,newdoc) goto retry; } } + /* + * Cancel if the user entered "/dev/null" on Unix, + * or an "nl:" path (case-insensitive) on VMS. - FM + */ +#ifdef VMS + if (!strncasecomp(filename, "nl:", 3) || + !strncasecomp(filename, "/nl/", 4)) +#else + if (!strcmp(filename, "/dev/null")) +#endif /* VMS */ + { + _statusline(SAVE_REQUEST_CANCELLED); + sleep(InfoSecs); + break; + } if ((cp = strchr(filename, '~'))) { *(cp++) = '\0'; strcpy(buffer, filename); @@ -367,9 +383,9 @@ PUBLIC int printfile ARGS1(document *,newdoc) cp = NULL; if (cp) #ifdef DOSPATH - sprintf(buffer,"%s/%s", cp, HTDOS_name(filename)); + sprintf(buffer,"%s/%s", cp, HTDOS_name(filename)); #else - sprintf(buffer,"%s/%s", cp, filename); + sprintf(buffer, "%s/%s", cp, filename); #endif else #ifdef DOSPATH @@ -379,8 +395,10 @@ PUBLIC int printfile ARGS1(document *,newdoc) #endif #endif /* VMS */ - /* see if it already exists */ - if ((outfile_fp = fopen(buffer,"r")) != NULL) { + /* + * See if it already exists. + */ + if ((outfile_fp = fopen(buffer, "r")) != NULL) { fclose(outfile_fp); #ifdef VMS _statusline(FILE_EXISTS_HPROMPT); @@ -419,6 +437,7 @@ PUBLIC int printfile ARGS1(document *,newdoc) FnameNum = FnameTotal; goto retry; } + chmod(buffer, 0600); if (HTisDocumentSource()) { /* @@ -498,6 +517,7 @@ PUBLIC int printfile ARGS1(document *,newdoc) HTAlert(UNABLE_TO_OPEN_TEMPFILE); break; } + chmod(tempfile, 0600); /* * Write the contents to a temp file. @@ -553,11 +573,16 @@ PUBLIC int printfile ARGS1(document *,newdoc) /* * Determine which mail headers should be sent. + * Use Content-Type and MIME-Version headers only + * if needed. We need them if we are mailing HTML + * source, or if we have 8-bit characters and will + * be sending Content-Transfer-Encoding to indicate + * this. + * * Send Content-Transfer-Encoding only if the document * has 8-bit characters. Send a charset parameter only * if the document has 8-bit characters and we we seem - * to have a valid charset. Also use Content-Type - * and MIME-Version headers only if needed. - kw + * to have a valid charset. - kw */ use_cte = HTLoadedDocumentEightbit(); #ifdef EXP_CHARTRANS @@ -568,10 +593,11 @@ PUBLIC int printfile ARGS1(document *,newdoc) * Also don't use an inofficial "x-" charset. - kw */ if (!use_cte || LYHaveCJKCharacterSet || - strncasecomp(disp_charset, "x-", 2) == 0) + strncasecomp(disp_charset, "x-", 2) == 0) { disp_charset = NULL; + } #else - disp_charset = HTLoadedDocumentCharset(); + disp_charset = NULL; #endif /* EXP_CHARTRANS */ use_type = (disp_charset || HTisDocumentSource()); use_mime = (use_cte || use_type); @@ -600,19 +626,22 @@ PUBLIC int printfile ARGS1(document *,newdoc) content_location); } else { /* - * Add Content-Type: text/plain if we have 8-bit - * characters and a valid charset for non-source - * documents. - kw - */ + * Add Content-Type: text/plain if we have 8-bit + * characters and a valid charset for non-source + * documents. - KW + */ if (disp_charset != NULL) { fprintf(outfile_fp, "Content-Type: text/plain; charset=%s\n", disp_charset); } } - fprintf(outfile_fp, "X-URL: %s\n", newdoc->address); - fprintf(outfile_fp, "To: %s\nSubject:%s\n\n", + /* + * Add the To, Subject, and X-URL headers. - FM + */ + fprintf(outfile_fp, "To: %s\nSubject: %s\n", user_response, sug_filename); + fprintf(outfile_fp, "X-URL: %s\n\n", newdoc->address); if (HTisDocumentSource()) { /* * Added the document's base as a BASE tag to @@ -774,6 +803,7 @@ PUBLIC int printfile ARGS1(document *,newdoc) HTAlert(FILE_ALLOC_FAILED); break; } + chmod(tempfile, 0600); if (HTisDocumentSource()) { /* @@ -926,17 +956,34 @@ PUBLIC int printfile ARGS1(document *,newdoc) goto again; } } + /* + * Cancel if the user entered "/dev/null" on Unix, + * or an "nl:" path (case-insensitive) on VMS. - FM + */ +#ifdef VMS + if (!strncasecomp(filename, "nl:", 3) || + !strncasecomp(filename, "/nl/", 4)) +#else + if (!strcmp(filename, "/dev/null")) +#endif /* VMS */ + { + _statusline(PRINT_REQUEST_CANCELLED); + sleep(InfoSecs); + break; + } HTAddSugFilename(filename); } #ifdef VMS - sprintf(buffer, cur_printer->command, tempfile, filename); + sprintf(buffer, cur_printer->command, tempfile, filename, + "", "", "", "", "", "", "", "", "", ""); #else /* Unix: */ /* * Prevent spoofing of the shell. */ cp = quote_pathname(filename); - sprintf(buffer, cur_printer->command, tempfile, cp); + sprintf(buffer, cur_printer->command, tempfile, cp, + "", "", "", "", "", "", "", "", "", ""); FREE(cp); #endif /* !VMS */ @@ -975,17 +1022,18 @@ PUBLIC int printfile ARGS1(document *,newdoc) } #ifdef VMS -PRIVATE int remove_quotes ARGS1(char *,string) +PRIVATE int remove_quotes ARGS1( + char *, string) { int i; - for(i=0;string[i]!='\0';i++) - if(string[i]=='"') - string[i]=' '; - else if(string[i]=='&') - string[i]=' '; - else if(string[i]=='|') - string[i]=' '; + for(i = 0; string[i] != '\0'; i++) + if(string[i] == '"') + string[i] = ' '; + else if(string[i] == '&') + string[i] = ' '; + else if(string[i] == '|') + string[i] = ' '; return(0); } @@ -1001,12 +1049,13 @@ PRIVATE int remove_quotes ARGS1(char *,string) * LYNXPRINT://MAIL_FILE/lines=# mail the file * LYNXPRINT://PRINTER/lines=#/number=# print to printer number # */ - -PUBLIC int print_options ARGS2(char **,newfile, int,lines_in_file) +PUBLIC int print_options ARGS2( + char **, newfile, + int, lines_in_file) { static char tempfile[256]; static BOOLEAN first = TRUE; - char *print_filename = NULL; + static char print_filename[256]; char buffer[LINESIZE]; int count; int pages; @@ -1016,7 +1065,12 @@ PUBLIC int print_options ARGS2(char **,newfile, int,lines_in_file) pages = lines_in_file/66 + 1; if (first) { - tempname(tempfile,NEW_FILE); + tempname(tempfile, NEW_FILE); +#if defined (VMS) || defined (DOSPATH) + sprintf(print_filename, "file://localhost/%s", tempfile); +#else + sprintf(print_filename, "file://localhost%s", tempfile); +#endif /* VMS */ first = FALSE; #ifdef VMS } else { @@ -1028,13 +1082,7 @@ PUBLIC int print_options ARGS2(char **,newfile, int,lines_in_file) HTAlert(UNABLE_TO_OPEN_PRINTOP_FILE); return(-1); } - -#if defined (VMS) || defined (DOSPATH) - StrAllocCopy(print_filename, "file://localhost/"); -#else - StrAllocCopy(print_filename, "file://localhost"); -#endif /* VMS */ - StrAllocCat(print_filename, tempfile); + chmod(tempfile, 0600); StrAllocCopy(*newfile, print_filename); LYforce_no_cache = TRUE; diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c index 1ec86c3c..8fdeaa0e 100644 --- a/src/LYReadCFG.c +++ b/src/LYReadCFG.c @@ -653,6 +653,9 @@ PUBLIC void read_cfg ARGS1( #endif /* VMS */ } + } else if (!strncasecomp(buffer, "FORCE_SSL_COOKIES_SECURE:", 25)) { + LYForceSSLCookiesSecure = is_true(buffer+25); + } else if (!strncasecomp(buffer, "ftp_proxy:", 10)) { if (getenv("ftp_proxy") == NULL) { #ifdef VMS @@ -1008,6 +1011,12 @@ PUBLIC void read_cfg ARGS1( } else if (!strncasecomp(buffer, "SCAN_FOR_BURIED_NEWS_REFS:", 26)) { scan_for_buried_news_references = is_true(buffer+26); + } else if (!strncasecomp(buffer, "SEEK_FRAG_AREA_IN_CUR:", 22)) { + LYSeekFragAREAinCur = is_true(buffer+22); + + } else if (!strncasecomp(buffer, "SEEK_FRAG_MAP_IN_CUR:", 21)) { + LYSeekFragMAPinCur = is_true(buffer+21); + } else if (!strncasecomp(buffer, "SET_COOKIES:", 12)) { LYSetCookies = is_true(buffer+12); diff --git a/src/LYSearch.c b/src/LYSearch.c index 495e9e19..d03fc08d 100644 --- a/src/LYSearch.c +++ b/src/LYSearch.c @@ -52,8 +52,7 @@ PRIVATE int check_for_target_in_links ARGS2( * Search the relevant form fields, taking the * case_sensitive setting into account. - FM */ - if ((links[i].form != NULL && links[i].type == WWW_FORM_LINK_TYPE && - links[i].form->value != NULL) && + if ((links[i].form != NULL && links[i].form->value != NULL) && links[i].form->type != F_HIDDEN_TYPE) { if (links[i].form->type == F_PASSWORD_TYPE) { /* @@ -168,7 +167,8 @@ PRIVATE int check_for_target_in_links ARGS2( * */ -PUBLIC BOOL textsearch ARGS3(document *,cur_doc, +PUBLIC BOOL textsearch ARGS3( + document *, cur_doc, char *, prev_target, BOOL, next) { @@ -358,7 +358,7 @@ check_recall: /* * Found in link, changed cur, we're done. */ - highlight(OFF, oldcur); + highlight(OFF, oldcur, prev_target); return(TRUE); } @@ -374,11 +374,11 @@ check_recall: /* * Resume search, this time for all text. * Set www_search_result if string found, - * and position the hit at top of screen. + * and position the hit near top of screen. */ - www_user_search(cur_doc->line+offset, cur_doc, prev_target); + www_user_search((cur_doc->line + offset), cur_doc, prev_target); if (cur_doc->link != oldcur) { - highlight(OFF, oldcur); + highlight(OFF, oldcur, prev_target); return(TRUE); } return(www_search_result > 0); diff --git a/src/LYShowInfo.c b/src/LYShowInfo.c index 23c6b6de..7c17df72 100644 --- a/src/LYShowInfo.c +++ b/src/LYShowInfo.c @@ -37,7 +37,7 @@ PUBLIC int showinfo ARGS4( { static char tempfile[256]; static BOOLEAN first = TRUE; - char *info_url = NULL; + static char info_url[256]; int url_type; FILE *fp0; char *Address = NULL, *Title = NULL; @@ -50,7 +50,15 @@ PUBLIC int showinfo ARGS4( struct group *grp; #endif /* DIRED_SUPPORT */ if (first) { - tempname(tempfile,NEW_FILE); + tempname(tempfile, NEW_FILE); + /* + * Make the temporary file a URL now. + */ +#if defined (VMS) || defined (DOSPATH) + sprintf(info_url, "file://localhost/%s", tempfile); +#else + sprintf(info_url, "file://localhost%s", tempfile); +#endif /* VMS */ first = FALSE; #ifdef VMS } else { @@ -58,28 +66,16 @@ PUBLIC int showinfo ARGS4( #endif /* VMS */ } - - /* - * Make the temporary file a URL now. - */ -#if defined (VMS) || defined (DOSPATH) - StrAllocCopy(info_url,"file://localhost/"); -#else - StrAllocCopy(info_url,"file://localhost"); -#endif /* VMS */ - StrAllocCat(info_url,tempfile); - - if ((fp0 = fopen(tempfile,"w")) == NULL) { + if ((fp0 = fopen(tempfile, "w")) == NULL) { HTAlert(CANNOT_OPEN_TEMP); - FREE(info_url); return(0); } + chmod(tempfile, 0600); /* * Point the address pointer at this Url */ StrAllocCopy(newdoc->address, info_url); - FREE(info_url); if (nlinks > 0 && links[doc->link].lname != NULL && (url_type = is_url(links[doc->link].lname)) != 0 && @@ -94,7 +90,7 @@ PUBLIC int showinfo ARGS4( fprintf(fp0, "<head>\n"); #ifdef EXP_CHARTRANS - add_META_charset_to_fd(fp0, -1); + LYAddMETAcharsetToFD(fp0, -1); #endif fprintf(fp0, "<title>%s</title>\n</head>\n<body>\n", SHOWINFO_TITLE); @@ -297,9 +293,10 @@ PUBLIC int showinfo ARGS4( "<dt> <em>size:</em> %d lines\n", size_of_file); fprintf(fp0, "<dt> <em>mode:</em> %s%s%s\n", - (lynx_mode == FORMS_LYNX_MODE ? "forms mode" : "normal"), - (doc->safe ? ", safe" : ""), - (doc->internal_link ? ", internal link" : "") + (lynx_mode == FORMS_LYNX_MODE ? + "forms mode" : "normal"), + ((lynx_mode == FORMS_LYNX_MODE && doc->safe) ? ", safe" : ""), + (doc->internal_link ? ", internal link" : "") ); fprintf(fp0, "</dl>\n"); /* end of list */ @@ -331,7 +328,7 @@ PUBLIC int showinfo ARGS4( fprintf(fp0, "<dt> <em>Action:</em> %s\n", Address); } if (!(links[doc->link].form->submit_method && - links[doc->link].form->submit_action)) { + links[doc->link].form->submit_action)) { fprintf(fp0,"<dt> (Form field)\n"); } } else { @@ -341,7 +338,8 @@ PUBLIC int showinfo ARGS4( } else { StrAllocCopy(Title, ""); } - fprintf(fp0, "<dt> <em>URL:</em> %s\n", Title); + fprintf(fp0, + "<dt> <em>URL:</em> %s\n", Title); } fprintf(fp0, "</dl>\n"); /* end of list */ diff --git a/src/LYStrings.c b/src/LYStrings.c index f5c88ffd..153e7490 100644 --- a/src/LYStrings.c +++ b/src/LYStrings.c @@ -92,10 +92,13 @@ PRIVATE int set_clicked_link ARGS2(int,x,int,y) /* - * LYstrncpy() terminates strings with a null byte. - * Writes a null byte into the n+1 byte of dst. + * LYstrncpy() terminates strings with a null byte. + * Writes a null byte into the n+1 byte of dst. */ -PUBLIC char * LYstrncpy ARGS3(char *,dst, char *,src, int,n) +PUBLIC char *LYstrncpy ARGS3( + char *, dst, + char *, src, + int, n) { char *val; int len=strlen(src); @@ -110,6 +113,10 @@ PUBLIC char * LYstrncpy ARGS3(char *,dst, char *,src, int,n) *(dst+n) = '\0'; return val; } + +#define IS_NEW_GLYPH(ch) (utf_flag && ((unsigned char)(ch)&0xc0) != 0x80) +#define IS_UTF_EXTRA(ch) (utf_flag && ((unsigned char)(ch)&0xc0) == 0x80) + #ifdef EXP_CHARTRANS /* * LYmbcsstrncpy() terminates strings with a null byte. @@ -118,7 +125,7 @@ PUBLIC char * LYstrncpy ARGS3(char *,dst, char *,src, int,n) * either bytes or glyphs (mbcs sequences) (currently only UTF8). */ PUBLIC char * LYmbcsstrncpy ARGS5(char *,dst, char *,src, int,n_bytes, - int,n_glyphs, int,enc) + int,n_glyphs, int,utf_flag) { char *val = dst; int i_bytes = 0, i_glyphs = 0; @@ -128,15 +135,13 @@ PUBLIC char * LYmbcsstrncpy ARGS5(char *,dst, char *,src, int,n_bytes, if (n_glyphs < 0) n_glyphs = 0; -#define IS_NEW_GLYPH(ch) (enc && ((unsigned char)(ch)&0xc0) != 0x80) - - for (; *src != '\0' && i_bytes < n_bytes; - i_bytes++) { - if (IS_NEW_GLYPH(*src)) + for (; *src != '\0' && i_bytes < n_bytes; i_bytes++) { + if (IS_NEW_GLYPH(*src)) { if (i_glyphs++ >= n_glyphs) { *dst = '\0'; return val; } + } *(dst++) = *(src++); } *dst = '\0'; @@ -145,8 +150,44 @@ PUBLIC char * LYmbcsstrncpy ARGS5(char *,dst, char *,src, int,n_bytes, } #endif /* EXP_CHARTRANS */ -#undef GetChar +/* + * LYmbcsstrlen() returns the printable length of a string + * that might contain IsSpecial or multibyte (CJK or UTF8) + * characters. - FM + */ +PUBLIC int LYmbcsstrlen ARGS2( + char *, str, + BOOL, utf_flag) +{ + int i, j, len = 0; + + if (!str && *str) + return(len); + for (i = 0; str[i] != '\0'; i++) { + if (IsSpecialAttrChar(str[i])) { + continue; + } else { + len++; + } + if (IS_NEW_GLYPH(str[i])) { + j = 0; + while (str[(i + 1)] != '\0' && + !IsSpecialAttrChar(str[(i + 1)]) && + j < 5 && + IS_UTF_EXTRA(str[(i + 1)])) { + i++; + j++; + } + } else if (!utf_flag && HTCJK != NOCJK && !isascii(str[i]) && + str[(i + 1)] != '\0' && + !IsSpecialAttrChar(str[(i + 1)])) { + i++; + } + } + + return(len); +} #undef GetChar #ifdef USE_SLANG @@ -233,9 +274,9 @@ PRIVATE int map_function_to_key ARGS1(char, keysym) #endif /* - * LYgetch() translates some escape sequences and may fake noecho + * LYgetch() translates some escape sequences and may fake noecho. */ -PUBLIC int LYgetch () +PUBLIC int LYgetch NOARGS { int a, b, c, d = -1; @@ -456,10 +497,9 @@ re_read: } #if HAVE_KEYPAD else { - - /* convert keypad() mode keys into Lynx defined keys + /* + * Convert keypad() mode keys into Lynx defined keys. */ - switch(c) { case KEY_DOWN: /* The four arrow keys ... */ c=DNARROW; @@ -563,35 +603,29 @@ re_read: } #endif /* defined(HAVE_KEYPAD) */ - if (c > DO_NOTHING) - /* Don't return raw values for KEYPAD symbols which we may have missed - * in the switch above if they are obviously invalid when used as an - * index into (e.g.) keypad[]. - kw - */ - return (0); - else - return(c); + if (c > DO_NOTHING) { + /* + * Don't return raw values for KEYPAD symbols which we may have + * missed in the switch above if they are obviously invalid when + * used as an index into (e.g.) keypad[]. - KW + */ + return (0); + } else { + return(c); + } } /* - * display the current value of the string and allow the user - * to edit it. - */ - -#ifdef USE_SLANG -#define GetYX(y,x) y = SLsmg_get_row(), x = SLsmg_get_column() -#else -#ifdef getyx -#define GetYX(y,x) getyx(stdscr,y,x) -#else -#define GetYX(y,x) y = stdscr->_cury, x = stdscr->_curx -#endif /* getyx */ -#endif /* USE_SLANG */ +** Display the current value of the string and allow the user +** to edit it. +*/ #define EDREC EditFieldData -/* shorthand to get rid of all most of the "edit->suchandsos" */ +/* + * Shorthand to get rid of all most of the "edit->suchandsos". + */ #define Buf edit->buffer #define Pos edit->pos #define StrLen edit->strlen @@ -600,11 +634,16 @@ re_read: #define DspStart edit->xpan #define Margin edit->margin -PUBLIC void LYSetupEdit ARGS4(EDREC *,edit, char *,old, int,maxstr, int,maxdsp) +PUBLIC void LYSetupEdit ARGS4( + EDREC *, edit, + char *, old, + int, maxstr, + int, maxdsp) { - /* Initialize edit record */ - - GetYX(edit->sy, edit->sx); + /* + * Initialize edit record + */ + LYGetYX(edit->sy, edit->sx); edit->pad = ' '; edit->dirty = TRUE; edit->panon = FALSE; @@ -620,22 +659,42 @@ PUBLIC void LYSetupEdit ARGS4(EDREC *,edit, char *,old, int,maxstr, int,maxdsp) if (DspWdth > 4) /* Else "{}" take up precious screen space */ edit->panon = TRUE; - /* Figure out margins. If too big we do a lot of unnecessary - * scrolling. If too small user doesn't have sufficient look-ahead. - * Let's say 25% for each margin, upper bound is 10 columns. + /* + * Figure out margins. If too big, we do a lot of unnecessary + * scrolling. If too small, user doesn't have sufficient + * look-ahead. Let's say 25% for each margin, upper bound is + * 10 columns. */ Margin = DspWdth/4; if (Margin > 10) Margin = 10; } - strcpy(edit->buffer, old); + + /* + * We expect the called function to pass us a default (old) value + * with a length that is less than or equal to maxstr, and to + * handle any messaging associated with actions to achieve that + * requirement. However, in case the calling function screwed + * up, we'll check it here, and ensure that no buffer overrun can + * occur by loading only as much of the head as fits. - FM + */ + if (strlen(old) >= maxstr) { + strncpy(edit->buffer, old, maxstr); + edit->buffer[maxstr] = '\0'; + StrLen = maxstr; + } else { + strcpy(edit->buffer, old); + } } -PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) +PUBLIC int LYEdit1 ARGS4( + EDREC *, edit, + int, ch, + int, action, + BOOL, maxMessage) { /* returns 0 character processed * ch otherwise */ - int i; int length; @@ -648,15 +707,15 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) switch (action) { case LYE_AIX: /* - * Hex 97. - * Fall through as a character for CJK. - * Otherwise, we treat this as LYE_ENTER. + * Hex 97. + * Fall through as a character for CJK. + * Otherwise, we treat this as LYE_ENTER. */ if (HTCJK == NOCJK) return(ch); case LYE_CHAR: /* - * ch is printable or ISO-8859-1 escape character. + * ch is printable or ISO-8859-1 escape character. */ if (Pos <= (MaxLen) && StrLen < (MaxLen)) { for(i = length; i >= Pos; i--) /* Make room */ @@ -671,8 +730,8 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) case LYE_BACKW: /* - * Backword. - * Definition of word is very naive: 1 or more a/n characters. + * Backword. + * Definition of word is very naive: 1 or more a/n characters. */ while (Pos && !isalnum(Buf[Pos-1])) Pos--; @@ -682,7 +741,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) case LYE_FORWW: /* - * Word forward. + * Word forward. */ while (isalnum(Buf[Pos])) Pos++; /* '\0' is not a/n */ @@ -692,28 +751,28 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) case LYE_ERASE: /* - * Erase the line to start fresh. + * Erase the line to start fresh. */ Buf[0] = '\0'; /* fall through */ case LYE_BOL: /* - * Go to first column. + * Go to first column. */ Pos = 0; break; case LYE_EOL: /* - * Go to last column. + * Go to last column. */ Pos = length; break; case LYE_DELNW: /* - * Delete next word. + * Delete next word. */ { int pos0 = Pos; @@ -725,7 +784,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) case LYE_DELPW: /* - * Delete previous word. + * Delete previous word. */ { int pos0 = Pos; @@ -738,7 +797,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) case LYE_DELN: /* - * Delete next character + * Delete next character */ if (Pos >= length) break; @@ -747,7 +806,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) case LYE_DELP: /* - * Delete preceding character. + * Delete preceding character. */ if (length == 0 || Pos == 0) break; @@ -760,7 +819,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) case LYE_DELC: /* - * Delete current character. + * Delete current character. */ if (length == 0) break; @@ -772,7 +831,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) case LYE_FORW: /* - * Move cursor to the right. + * Move cursor to the right. */ if (Pos < length) Pos++; @@ -780,7 +839,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) case LYE_BACK: /* - * Left-arrow move cursor to the left. + * Left-arrow move cursor to the left. */ if (Pos > 0) Pos--; @@ -805,7 +864,8 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage) } -PUBLIC void LYRefreshEdit ARGS1(EDREC *,edit) +PUBLIC void LYRefreshEdit ARGS1( + EDREC *, edit) { int i; int length; @@ -876,14 +936,14 @@ PUBLIC void LYRefreshEdit ARGS1(EDREC *,edit) } /* - * Erase rest of input area. + * Erase rest of input area. */ - padsize= DspWdth-nrdisplayed; + padsize = DspWdth-nrdisplayed; while (padsize--) addch((unsigned char)edit->pad); /* - * Scrolling indicators. + * Scrolling indicators. */ if (edit->panon) { if ((DspStart + nrdisplayed) < length) { @@ -901,9 +961,14 @@ PUBLIC void LYRefreshEdit ARGS1(EDREC *,edit) } -PUBLIC int LYgetstr ARGS4(char *,inputline, int,hidden, - int,bufsize, int,recall) +PUBLIC int LYgetstr ARGS4( + char *, inputline, + int, hidden, + int, bufsize, + int, recall) { + extern BOOLEAN term_letter; /* Flag from terminate_letter() AST */ + extern BOOLEAN term_options; /* Flag from terminate_options() AST */ extern BOOLEAN term_message; /* Flag from terminate_message() AST */ #ifdef VMS extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */ @@ -912,7 +977,7 @@ PUBLIC int LYgetstr ARGS4(char *,inputline, int,hidden, int ch; EditFieldData MyEdit; - GetYX(y,x); /* Use screen from cursor position to eol */ + LYGetYX(y, x); /* Use screen from cursor position to eol */ MaxStringSize = (bufsize < sizeof(MyEdit.buffer)) ? (bufsize - 1) : (sizeof(MyEdit.buffer) - 1); LYSetupEdit(&MyEdit, inputline, MaxStringSize, (LYcols-1)-x); @@ -943,9 +1008,9 @@ again: /* fall through */ case LYE_AIX: /* - * Hex 97. - * Treat as a character for CJK. - * Otherwise, we treat this as LYE_ENTER. + * Hex 97. + * Treat as a character for CJK. + * Otherwise, we treat this as LYE_ENTER. */ if (HTCJK != NOCJK && ch != '\t') { LYLineEdit(&MyEdit,ch, FALSE); @@ -953,7 +1018,7 @@ again: } case LYE_ENTER: /* - * Terminate the string and return. + * Terminate the string and return. */ strcpy(inputline, MyEdit.buffer); return(ch); @@ -961,7 +1026,7 @@ again: case LYE_ABORT: /* - * Control-C or Control-G aborts. + * Control-C or Control-G aborts. */ inputline[0] = '\0'; return(-1); @@ -974,11 +1039,13 @@ again: } /* - * LYstrstr will find the first occurence of the string pointed to by tarptr - * in the string pointed to by chptr. - * It is a case insensitive search. + * LYstrstr will find the first occurence of the string + * pointed to by tarptr in the string pointed to by chptr. + * It is a case insensitive search. */ -PUBLIC char * LYstrstr ARGS2(char *,chptr, char *,tarptr) +PUBLIC char * LYstrstr ARGS2( + char *, chptr, + char *, tarptr) { register char *tmpchptr, *tmptarptr; @@ -999,16 +1066,19 @@ PUBLIC char * LYstrstr ARGS2(char *,chptr, char *,tarptr) } /* - * LYno_attr_char_case_strstr will find the first occurence of the string - * pointed to by tarptr in the string pointed to by chptr. - * It ignores the characters: LY_UNDERLINE_START_CHAR and - * LY_UNDERLINE_END_CHAR - * LY_BOLD_START_CHAR - * LY_BOLD_END_CHAR - * if present in chptr. - * It is a case insensitive search. + * LYno_attr_char_case_strstr will find the first occurence of the + * string pointed to by tarptr in the string pointed to by chptr. + * It ignores the characters: LY_UNDERLINE_START_CHAR and + * LY_UNDERLINE_END_CHAR + * LY_BOLD_START_CHAR + * LY_BOLD_END_CHAR + * LY_SOFT_HYPHEN + * if present in chptr. + * It is a case insensitive search. */ -PUBLIC char * LYno_attr_char_case_strstr ARGS2(char *,chptr, char *,tarptr) +PUBLIC char * LYno_attr_char_case_strstr ARGS2( + char *, chptr, + char *, tarptr) { register char *tmpchptr, *tmptarptr; @@ -1019,10 +1089,10 @@ PUBLIC char * LYno_attr_char_case_strstr ARGS2(char *,chptr, char *,tarptr) chptr++; for (; *chptr != '\0'; chptr++) { - if (TOUPPER(*chptr) == TOUPPER(*tarptr)) { - - /* see if they line up */ + /* + * See if they line up. + */ tmpchptr = chptr+1; tmptarptr = tarptr+1; @@ -1031,20 +1101,15 @@ PUBLIC char * LYno_attr_char_case_strstr ARGS2(char *,chptr, char *,tarptr) while (1) { if (!IsSpecialAttrChar(*tmpchptr)) { - if (TOUPPER(*tmpchptr) != TOUPPER(*tmptarptr)) break; - tmpchptr++; tmptarptr++; - } else { tmpchptr++; } - if (*tmptarptr == '\0') return(chptr); - if (*tmpchptr == '\0') break; } @@ -1055,16 +1120,19 @@ PUBLIC char * LYno_attr_char_case_strstr ARGS2(char *,chptr, char *,tarptr) } /* - * LYno_attr_char_strstr will find the first occurence of the string - * pointed to by tarptr in the string pointed to by chptr. - * It ignores the characters: LY_UNDERLINE_START_CHAR and - * LY_UNDERLINE_END_CHAR - * LY_BOLD_START_CHAR - * LY_BOLD_END_CHAR - * if present in chptr. - * It is a case sensitive search. + * LYno_attr_char_strstr will find the first occurence of the + * string pointed to by tarptr in the string pointed to by chptr. + * It ignores the characters: LY_UNDERLINE_START_CHAR and + * LY_UNDERLINE_END_CHAR + * LY_BOLD_START_CHAR + * LY_BOLD_END_CHAR + * LY_SOFT_HYPHEN + * if present in chptr. + * It is a case sensitive search. */ -PUBLIC char * LYno_attr_char_strstr ARGS2(char *,chptr, char *,tarptr) +PUBLIC char * LYno_attr_char_strstr ARGS2( + char *, chptr, + char *, tarptr) { register char *tmpchptr, *tmptarptr; @@ -1075,32 +1143,27 @@ PUBLIC char * LYno_attr_char_strstr ARGS2(char *,chptr, char *,tarptr) chptr++; for (; *chptr != '\0'; chptr++) { - if ((*chptr) == (*tarptr)) { - - /* see if they line up */ - tmpchptr = chptr+1; - tmptarptr = tarptr+1; + /* + * See if they line up. + */ + tmpchptr = chptr + 1; + tmptarptr = tarptr + 1; if (*tmptarptr == '\0') /* one char target */ return(chptr); while (1) { if (!IsSpecialAttrChar(*tmpchptr)) { - if ((*tmpchptr) != (*tmptarptr)) break; - tmpchptr++; tmptarptr++; - } else { tmpchptr++; } - if (*tmptarptr == '\0') return(chptr); - if (*tmpchptr == '\0') break; } @@ -1110,9 +1173,6 @@ PUBLIC char * LYno_attr_char_strstr ARGS2(char *,chptr, char *,tarptr) return(NULL); } -#ifdef EXP_CHARTRANS - -#define IS_UTFEXTRA(ch) (utf_flag && ((unsigned char)(ch)&0xc0) == 0x80) /* * LYno_attr_mbcs_case_strstr will find the first occurence of the string * pointed to by tarptr in the string pointed to by chptr. @@ -1122,45 +1182,111 @@ PUBLIC char * LYno_attr_char_strstr ARGS2(char *,chptr, char *,tarptr) * It ignores the characters: LY_UNDERLINE_START_CHAR and * LY_UNDERLINE_END_CHAR * LY_BOLD_START_CHAR - * LY_BOLD_END_CHAR[B + * LY_BOLD_END_CHAR + * LY_SOFT_HYPHEN * if present in chptr. * It assumes UTF8 if utf_flag is set. - * It is a case insensitive search. + * It is a case insensitive search. - KW & FM */ -PUBLIC char * LYno_attr_mbcs_case_strstr ARGS4(char *,chptr, char *,tarptr, - BOOL, utf_flag, int *,nendp) +PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5( + char *, chptr, + char *, tarptr, + BOOL, utf_flag, + int *, nstartp, + int *, nendp) { register char *tmpchptr, *tmptarptr; int len = 0; + int offset; - if (!chptr) + if (!(chptr && tarptr)) return(NULL); + /* + * Skip initial IsSpecial chars. - FM + */ while (IsSpecialAttrChar(*chptr) && *chptr != '\0') chptr++; + /* + * Seek a first target match. - FM + */ for (; *chptr != '\0'; chptr++) { - - if (TOUPPER(*chptr) == TOUPPER(*tarptr)) { + if ((!utf_flag && HTCJK != NOCJK && !isascii(*chptr) && + *chptr == *tarptr && + *(chptr + 1) != '\0' && + !IsSpecialAttrChar(*(chptr + 1))) || + TOUPPER(*chptr) == TOUPPER(*tarptr)) { int tarlen = 0; + offset = len; len++; - /* see if they line up */ - tmpchptr = chptr+1; - tmptarptr = tarptr+1; - - if (*tmptarptr == '\0') { /* one char target */ + /* + * See if they line up. + */ + tmpchptr = (chptr + 1); + tmptarptr = (tarptr + 1); + + if (*tmptarptr == '\0') { + /* + * One char target. + */ + *nstartp = offset; *nendp = len; return(chptr); } + if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) && + *chptr == *tarptr && + *tmpchptr != '\0' && + !IsSpecialAttrChar(*tmpchptr)) { + /* + * Check the CJK mutibyte. - FM + */ + if (*tmpchptr == *tmptarptr) { + /* + * It's a match. Advance to next char. - FM + */ + tmpchptr++; + tmptarptr++; + if (*tmptarptr == '\0') { + /* + * One character match. - FM + */ + *nstartp = offset; + *nendp = len + tarlen; + return(chptr); + } + tarlen++; + } else { + /* + * It's not a match, so go back to + * seeking a first target match. - FM + */ + chptr++; + continue; + } + } + /* + * See if the rest of the target matches. - FM + */ while (1) { if (!IsSpecialAttrChar(*tmpchptr)) { - - if (TOUPPER(*tmpchptr) != TOUPPER(*tmptarptr)) + if (!utf_flag && HTCJK != NOCJK && !isascii(*tmpchptr)) { + if (*tmpchptr == *tmptarptr && + *(tmpchptr + 1) == *(tmptarptr + 1) && + !IsSpecialAttrChar(*(tmpchptr + 1))) { + tmpchptr++; + tmptarptr++; + } else { break; + } + } else if (TOUPPER(*tmpchptr) != TOUPPER(*tmptarptr)) { + break; + } - if (!IS_UTFEXTRA(*tmptarptr)) + if (!IS_UTF_EXTRA(*tmptarptr)) { tarlen++; + } tmpchptr++; tmptarptr++; @@ -1169,17 +1295,23 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS4(char *,chptr, char *,tarptr, } if (*tmptarptr == '\0') { + *nstartp = offset; *nendp = len + tarlen; return(chptr); } - if (*tmpchptr == '\0') + if (*tmpchptr == '\0') { break; } - } else if (!( IS_UTFEXTRA(*chptr) || + } + } else if (!(IS_UTF_EXTRA(*chptr) || IsSpecialAttrChar(*chptr))) { + if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) && + *(chptr + 1) != '\0' && + !IsSpecialAttrChar(*(chptr + 1))) { + chptr++; + } len++; } - } /* end for */ return(NULL); @@ -1188,51 +1320,114 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS4(char *,chptr, char *,tarptr, /* * LYno_attr_mbcs_strstr will find the first occurence of the string * pointed to by tarptr in the string pointed to by chptr. - * It takes account of MultiByte Character Sequences (UTF8). - * The physical lenght of the displayed string up to the end of the target - * string is returned in *nendp if the search is successful. + * 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. * It ignores the characters: LY_UNDERLINE_START_CHAR and * LY_UNDERLINE_END_CHAR * LY_BOLD_START_CHAR * LY_BOLD_END_CHAR + * LY_SOFT_HYPHEN * if present in chptr. * It assumes UTF8 if utf_flag is set. - * It is a case sensitive search. + * It is a case sensitive search. - KW & FM */ -PUBLIC char * LYno_attr_mbcs_strstr ARGS4(char *,chptr, char *,tarptr, - BOOL, utf_flag, int *,nendp) +PUBLIC char * LYno_attr_mbcs_strstr ARGS5( + char *, chptr, + char *, tarptr, + BOOL, utf_flag, + int *, nstartp, + int *, nendp) { register char *tmpchptr, *tmptarptr; int len = 0; + int offset; - if (!chptr) + if (!(chptr && tarptr)) return(NULL); + /* + * Skip initial IsSpecial chars. - FM + */ while (IsSpecialAttrChar(*chptr) && *chptr != '\0') chptr++; + /* + * Seek a first target match. - FM + */ for (; *chptr != '\0'; chptr++) { if ((*chptr) == (*tarptr)) { int tarlen = 0; + offset = len; len++; - /* see if they line up */ - tmpchptr = chptr+1; - tmptarptr = tarptr+1; - - if (*tmptarptr == '\0') { /* one char target */ + /* + * See if they line up. + */ + tmpchptr = (chptr + 1); + tmptarptr = (tarptr + 1); + + if (*tmptarptr == '\0') { + /* + * One char target. + */ + *nstartp = offset; *nendp = len + 1; return(chptr); } + if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) && + *tmpchptr != '\0' && + !IsSpecialAttrChar(*tmpchptr)) { + /* + * Check the CJK mutibyte. - FM + */ + if (*tmpchptr == *tmptarptr) { + /* + * It's a match. Advance to next char. - FM + */ + tmpchptr++; + tmptarptr++; + if (*tmptarptr == '\0') { + /* + * One character match. - FM + */ + *nstartp = offset; + *nendp = len + tarlen; + return(chptr); + } + tarlen++; + } else { + /* + * It's not a match, so go back to + * seeking a first target match. - FM + */ + chptr++; + continue; + } + } + /* + * See if the rest of the target matches. - FM + */ while (1) { if (!IsSpecialAttrChar(*tmpchptr)) { - - if ((*tmpchptr) != (*tmptarptr)) + if (!utf_flag && HTCJK != NOCJK && !isascii(*tmpchptr)) { + if (*tmpchptr == *tmptarptr && + *(tmpchptr + 1) == *(tmptarptr + 1) && + !IsSpecialAttrChar(*(tmpchptr + 1))) { + tmpchptr++; + tmptarptr++; + } else { + break; + } + } else if ((*tmpchptr) != (*tmptarptr)) { break; + } - if (!IS_UTFEXTRA(*tmptarptr)) + if (!IS_UTF_EXTRA(*tmptarptr)) { tarlen++; + } tmpchptr++; tmptarptr++; @@ -1241,60 +1436,73 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS4(char *,chptr, char *,tarptr, } if (*tmptarptr == '\0') { + *nstartp = offset; *nendp = len + tarlen; return(chptr); } - if (*tmpchptr == '\0') + if (*tmpchptr == '\0') { break; } - } else if (!( IS_UTFEXTRA(*chptr) || + } + } else if (!(IS_UTF_EXTRA(*chptr) || IsSpecialAttrChar(*chptr))) { + if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) && + *(chptr + 1) != '\0' && + !IsSpecialAttrChar(*(chptr + 1))) { + chptr++; + } len++; } } /* end for */ return(NULL); } -#endif /* EXP_CHARTRANS */ -/* Allocate a new copy of a string, and returns it -*/ -PUBLIC char * SNACopy ARGS3 (char **,dest, CONST char *,src, int,n) +/* + * Allocate a new copy of a string, and returns it. + */ +PUBLIC char * SNACopy ARGS3( + char **, dest, + CONST char *, src, + int, n) { - FREE(*dest); - if (src) { - *dest = (char *) calloc (1, n + 1); - if (*dest == NULL) { - fprintf(stderr,"Tried to calloc %d bytes\n",n); - outofmem(__FILE__, "SNACopy"); + FREE(*dest); + if (src) { + *dest = (char *)calloc(1, n + 1); + if (*dest == NULL) { + if (TRACE) + fprintf(stderr, "Tried to calloc %d bytes\n", n); + outofmem(__FILE__, "SNACopy"); + } + strncpy (*dest, src, n); + *(*dest + n) = '\0'; /* terminate */ } - strncpy (*dest, src, n); - *(*dest + n) = '\0'; /* terminate */ - } - return *dest; + return *dest; } -/* String Allocate and Concatenate -*/ -PUBLIC char * SNACat ARGS3 (char **,dest, CONST char *,src, int,n) +/* + * String Allocate and Concatenate. + */ +PUBLIC char * SNACat ARGS3( + char **, dest, + CONST char *, src, + int, n) { - if (src && *src) { - if (*dest) { - int length = strlen (*dest); - *dest = (char *) realloc (*dest, length + n + 1); - if (*dest == NULL) - outofmem(__FILE__, "SNACat"); - strncpy (*dest + length, src, n); - *(*dest + length + n) = '\0'; /* terminate */ - } else { - *dest = (char *) calloc (1, strlen(src) + 1); - if (*dest == NULL) - outofmem(__FILE__, "SNACat"); - strncpy (*dest, src, n); - *dest[n] = '\0'; /* terminate */ + if (src && *src) { + if (*dest) { + int length = strlen(*dest); + *dest = (char *)realloc(*dest, length + n + 1); + if (*dest == NULL) + outofmem(__FILE__, "SNACat"); + strncpy(*dest + length, src, n); + *(*dest + length + n) = '\0'; /* terminate */ + } else { + *dest = (char *)calloc(1, strlen(src) + 1); + if (*dest == NULL) + outofmem(__FILE__, "SNACat"); + strncpy(*dest, src, n); + *dest[n] = '\0'; /* terminate */ + } } - } - return *dest; + return *dest; } - - diff --git a/src/LYStrings.h b/src/LYStrings.h index ef1afd39..317406e8 100644 --- a/src/LYStrings.h +++ b/src/LYStrings.h @@ -15,13 +15,21 @@ extern int LYgetstr PARAMS((char *inputline, int hidden, extern char * LYstrstr PARAMS((char *chptr, char *tarptr)); extern char * LYno_attr_char_strstr PARAMS((char *chptr, char *tarptr)); extern char * LYno_attr_char_case_strstr PARAMS((char *chptr, char *tarptr)); -#ifdef EXP_CHARTRANS extern char * LYmbcsstrncpy PARAMS((char *dst, char *src, int n_bytes, int n_glyphs, int enc)); -extern char * LYno_attr_mbcs_strstr PARAMS((char *chptr, char *tarptr, - BOOL utf_flag, int *nendp)); -extern char * LYno_attr_mbcs_case_strstr PARAMS((char *chptr, char *tarptr, - BOOL utf_flag, int *nendp)); +#ifdef EXP_CHARTRANS +extern char * LYno_attr_mbcs_strstr PARAMS(( + char * chptr, + char * tarptr, + BOOL utf_flag, + int * nstartp, + int * nendp)); +extern char * LYno_attr_mbcs_case_strstr PARAMS(( + char * chptr, + char * tarptr, + BOOL utf_flag, + int * nstartp, + int * nendp)); #endif extern char * SNACopy PARAMS((char **dest, CONST char *src, int n)); diff --git a/src/LYStructs.h b/src/LYStructs.h index 2ea0de0d..fc438376 100644 --- a/src/LYStructs.h +++ b/src/LYStructs.h @@ -16,11 +16,13 @@ typedef struct link { char *hightext; char *hightext2; int hightext2_offset; + BOOL inUnderline; /* TRUE when this link is in underlined context. */ int lx; int ly; - int type; /* type of link, Forms, WWW, etc */ - int anchor_number; /* the anchor number within the Gridtext structure */ - struct _FormInfo *form; /* pointer to form info */ + int type; /* Type of link, Forms, WWW, etc. */ + int anchor_number; /* The anchor number within the HText structure. */ + int anchor_line_num;/* The anchor line number in the HText structure. */ + struct _FormInfo *form; /* Pointer to form info. */ } linkstruct; extern linkstruct links[MAXLINKS]; extern int nlinks; diff --git a/src/LYTraversal.c b/src/LYTraversal.c index 1925860c..c9c7627b 100644 --- a/src/LYTraversal.c +++ b/src/LYTraversal.c @@ -32,6 +32,7 @@ PUBLIC BOOLEAN lookup ARGS1(char *,target) exit(-1); } else { fclose(ifp); + chmod(TRAVERSE_FILE, 0600); return(FALSE); } } @@ -69,6 +70,7 @@ PUBLIC void add_to_table ARGS1(char *,target) #endif /* SIGTSTP */ exit(-1); } + chmod(TRAVERSE_FILE, 0600); fprintf(ifp,"%s\n",target); @@ -95,6 +97,7 @@ PUBLIC void add_to_traverse_list ARGS2(char *,fname, char *,prev_link_name) #endif /* SIGTSTP */ exit(-1); } + chmod(TRAVERSE_FOUND_FILE, 0600); fprintf(ifp,"%s %s\n",fname, prev_link_name); @@ -113,6 +116,7 @@ PUBLIC void dump_traversal_history NOARGS perror("unable to open traversal file"); return; } + chmod(TRAVERSE_FILE, 0600); fprintf(ifp, "\n\nTRAVERSAL WAS INTERUPTED\n\n\ here is a list of the history stack so that you may rebuild\n\n"); @@ -144,6 +148,7 @@ PUBLIC void add_to_reject_list ARGS1(char *,target) #endif /* SIGTSTP */ exit(-1); } + chmod(TRAVERSE_REJECT_FILE, 0600); fprintf(ifp,"%s\n",target); diff --git a/src/LYUpload.c b/src/LYUpload.c index d6cbb1c5..48c6f19d 100644 --- a/src/LYUpload.c +++ b/src/LYUpload.c @@ -189,6 +189,7 @@ retry: system(cmd); fflush(stdout); start_curses(); + chmod(buffer, 0600); /* don't remove(file); */ return 1; diff --git a/src/LYUtils.c b/src/LYUtils.c index 37ad23f2..5d22ca60 100644 --- a/src/LYUtils.c +++ b/src/LYUtils.c @@ -1,5 +1,6 @@ #include "HTUtils.h" #include "tcp.h" +#include <ctype.h> #include "HTParse.h" #include "HTAccess.h" #include "HTCJK.h" @@ -10,9 +11,7 @@ #include "LYGlobalDefs.h" #include "LYSignal.h" #include "GridText.h" -#ifdef EXP_CHARTRANS #include "LYCharSets.h" -#endif /* EXP_CHARTRANS */ #ifdef DOSPATH #include "HTDOS.h" @@ -54,6 +53,8 @@ #include "LYStyle.h" #endif +#undef hline /* FIXME: this is a curses feature used as a variable here */ + #ifdef SVR4_BSDSELECT extern int BSDselect PARAMS((int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval * timeout)); @@ -91,22 +92,35 @@ PRIVATE HTList * localhost_aliases = NULL; /* Hosts to treat as local */ PUBLIC HTList * sug_filenames = NULL; /* Suggested filenames */ /* - * highlight (or unhighlight) a given link + * Highlight (or unhighlight) a given link. */ -PUBLIC void highlight ARGS2( +PUBLIC void highlight ARGS3( int, flag, - int, cur) + int, cur, + char *, target) { char buffer[200]; int i; - char tmp[3]; + char tmp[7], *cp; + char *theData = NULL; + char *Data = NULL; + int Offset, HitOffset, tLen; + int LenNeeded; + BOOL TargetEmphasisON = FALSE; +#ifdef EXP_CHARTRANS + BOOL utf_flag = (LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8); +#else +#define utf_flag TRUE +#endif tmp[0] = tmp[1] = tmp[2] = '\0'; - /* Bug in history code can cause -1 to be sent, which will yield - ** an ACCVIO when LYstrncpy() is called with a nonsense pointer. - ** This works around the bug, for now. -- FM - */ + /* + * Bugs in the history code might cause -1 to be sent for cur, which + * yields a crash when LYstrncpy() is called with a nonsense pointer. + * As far as I know, such bugs have been squashed, but if they should + * reappear, this works around them. - FM + */ if (cur < 0) cur = 0; @@ -117,7 +131,7 @@ PUBLIC void highlight ARGS2( #endif move(links[cur].ly, links[cur].lx); #ifndef USE_COLOR_STYLE - lynx_start_link_color (flag == ON); + lynx_start_link_color (flag == ON, links[cur].inUnderline); #else if (flag == ON) { LynxChangeStyle(s_alink, ABS_ON, 0); @@ -125,7 +139,8 @@ PUBLIC void highlight ARGS2( /* the logic is flawed here - no provision is made for links that ** aren't coloured as [s_a] by default - rjp */ - if (cached_styles[LYP][LXP]) { + if (LYP >= 0 && LYP < CACHEH && LXP >= 0 && LXP < CACHEW && + cached_styles[LYP][LXP]) { LynxChangeStyle(cached_styles[LYP][LXP], ABS_ON, 0); } else { @@ -136,75 +151,1519 @@ PUBLIC void highlight ARGS2( if (links[cur].type == WWW_FORM_LINK_TYPE) { int len; - int avail_space = (LYcols-links[cur].lx)-1; + int avail_space = (LYcols - links[cur].lx) - 1; LYstrncpy(buffer, (links[cur].hightext ? - links[cur].hightext : ""), - (avail_space > links[cur].form->size ? + links[cur].hightext : ""), + (avail_space > links[cur].form->size ? links[cur].form->size : avail_space)); - addstr(buffer); + addstr(buffer); len = strlen(buffer); for (; len < links[cur].form->size && len < avail_space; len++) addch('_'); } else { - - /* copy into the buffer only what will fit within the - * width of the screen + /* + * Copy into the buffer only what will fit + * within the width of the screen. */ #ifdef EXP_CHARTRANS - LYmbcsstrncpy(buffer,(links[cur].hightext ? - links[cur].hightext : ""), 199, - LYcols - links[cur].lx - 1, - (LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8)); + LYmbcsstrncpy(buffer, + (links[cur].hightext ? + links[cur].hightext : ""), + (sizeof(buffer) - 1), + ((LYcols - 1) - links[cur].lx), + utf_flag); #else LYstrncpy(buffer, (links[cur].hightext ? links[cur].hightext : ""), LYcols-links[cur].lx-1); +#define LYmbcsstrncpy(dest,src,n,n_glyphs,enc) LYstrncpy(dest, src, n) +#define LYmbcsstrlen(str,utf_flag) strlen(str) #endif /* EXP_CHARTRANS */ addstr(buffer); } - /* display a second line as well */ + /* + * Display a second line as well. + */ if (links[cur].hightext2 && links[cur].ly < display_lines) { - lynx_stop_link_color (flag == ON); + lynx_stop_link_color (flag == ON, links[cur].inUnderline); addch('\n'); - for (i=0; i < links[cur].hightext2_offset; i++) - addch(' '); + for (i = 0; i < links[cur].hightext2_offset; i++) + addch(' '); #ifndef USE_COLOR_STYLE - lynx_start_link_color (flag == ON); + lynx_start_link_color (flag == ON, links[cur].inUnderline); #else LynxChangeStyle(flag == ON ? s_alink : s_a, ABS_ON, 0); #endif for (i = 0; (tmp[0] = links[cur].hightext2[i]) != '\0' && - i+links[cur].hightext2_offset < LYcols; i++) { + i+links[cur].hightext2_offset < LYcols; i++) { if (!IsSpecialAttrChar(links[cur].hightext2[i])) { - /* For CJK strings, by Masanobu Kimura */ + /* + * For CJK strings, by Masanobu Kimura. + */ if (HTCJK != NOCJK && !isascii(tmp[0])) { tmp[1] = links[cur].hightext2[++i]; addstr(tmp); tmp[1] = '\0'; - } else { + } else { addstr(tmp); } } } } - lynx_stop_link_color (flag == ON); + lynx_stop_link_color (flag == ON, links[cur].inUnderline); #if defined(FANCY_CURSES) || defined(USE_SLANG) + /* + * If we have an emphasized WHEREIS hit in the highlighted + * text, restore the emphasis. Note that we never emphasize + * the first and last characters of the highlighted text when + * we are making the link current, so the link attributes for + * the current link will persist at the beginning and end, + * providing an indication to the user that it has been made + * current. Also note that we use HText_getFirstTargetInLine() + * to determine if there's a hit in the HText structure line + * containing the link, and if so, get back a copy of the line + * starting at that first hit (which might be before or after + * our link), and with all IsSpecial characters stripped, so we + * don't need to deal with them here. - FM + */ + if (target && *target && links[cur].type == WWW_LINK_TYPE && + links[cur].hightext && *links[cur].hightext && + HText_getFirstTargetInLine(HTMainText, + links[cur].anchor_line_num, + utf_flag, + (int *)&Offset, + (int *)&tLen, + (char **)&theData, + target)) { + int itmp, written, len, y, offset; + char *data; + int tlen = strlen(target); + int hlen, hLen; + int hline = links[cur].ly, hoffset = links[cur].lx; + size_t utf_extra = 0; + + /* + * Copy into the buffer only what will fit + * up to the right border of the screen. - FM + */ +#ifdef EXP_CHARTRANS + LYmbcsstrncpy(buffer, + (links[cur].hightext ? + links[cur].hightext : ""), + (sizeof(buffer) - 1), + ((LYcols - 1) - links[cur].lx), + utf_flag); +#else + LYstrncpy(buffer, + links[cur].hightext, + ((LYcols - 1) - hoffset)); +#endif /* EXP_CHARTRANS */ + hlen = strlen(buffer); + hLen = ((HTCJK != NOCJK || utf_flag) ? + LYmbcsstrlen(buffer, utf_flag) : hlen); + + /* + * Break out if the first hit in the line + * starts after this link. - FM + */ + if (Offset >= (hoffset + hLen)) { + goto highlight_search_hightext2; + } + + /* + * Recursively skip hits that end before this link, and + * break out if there is no hit beyond those. - FM + */ + Data = theData; + while ((Offset < hoffset) && + ((Offset + tLen) <= hoffset)) { + data = (Data + tlen); + offset = (Offset + tLen); + if ((case_sensitive ? + (cp = LYno_attr_mbcs_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL : + (cp = LYno_attr_mbcs_case_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL) && + (offset + LenNeeded) < LYcols) { + Data = cp; + Offset = (offset + HitOffset); + } else { + goto highlight_search_hightext2; + } + } + data = buffer; + offset = hoffset; + + /* + * If the hit starts before the hightext, and ends + * in or beyond the hightext, restore the emphasis, + * skipping the first and last characters of the + * hightext if we're making the link current. - FM + */ + if ((Offset < offset) && + ((Offset + tLen) > offset)) { + itmp = 0; + written = 0; + len = (tlen - (offset - Offset)); + + /* + * Go to the start of the hightext and + * handle its first character. - FM + */ + move(hline, offset); + tmp[0] = data[itmp]; + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[utf_extra+1] = '\0'; + itmp += utf_extra; + /* + * Start emphasis immediately if we are + * making the link non-current. - FM + */ + if (flag != ON) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Start emphasis immediately if we are + * making the link non-current. - FM + */ + if (flag != ON) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Start emphasis immediately if we are making + * the link non-current. - FM + */ + if (flag != ON) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + written++; + } + itmp++; + /* + * Start emphasis after the first character + * if we are making the link current and this + * is not the last character. - FM + */ + if (!TargetEmphasisON && + data[itmp] != '\0') { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + } + + /* + * Handle the remaining characters. - FM + */ + for (; + written < len && (tmp[0] = data[itmp]) != '\0'; + itmp++) { + /* + * Print all the other target chars, except + * the last character if it is also the last + * character of hightext and we are making + * the link current. - FM + */ + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[(utf_extra + 1)] = '\0'; + itmp += utf_extra; + /* + * Make sure we don't restore emphasis to + * the last character of hightext if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Make sure we don't restore emphasis to + * the last character of hightext if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Make sure we don't restore emphasis to + * the last character of hightext if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + written++; + } + } + + /* + * Stop the emphasis if we haven't already, then + * reset the offset to our current position in + * the line, and if that is beyond the link, or + * or we are making the link current and it is + * the last character of the hightext, we are + * done. - FM + */ + if (TargetEmphasisON) { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + } + LYGetYX(y, offset); + if (offset >= + (hoffset + + (flag == ON ? (hLen - 1) : hLen))) { + goto highlight_search_hightext2; + } + + /* + * See if we have another hit that starts + * within the hightext. - FM + */ + data = (Data + (offset - Offset)); + if ((case_sensitive ? + (cp = LYno_attr_mbcs_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL : + (cp = LYno_attr_mbcs_case_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL) && + (offset + LenNeeded) < LYcols) { + /* + * If the hit starts after the end of the hightext, + * or we are making the link current and the hit + * starts at its last character, we are done. - FM + */ + if ((HitOffset + offset) >= + (hoffset + + (flag == ON ? (hLen - 1) : hLen))) { + goto highlight_search_hightext2; + } + + /* + * Set up the data and offset for the hit, and let + * the code for within hightext hits handle it. - FM + */ + Data = cp; + Offset = (offset + HitOffset); + data = buffer; + offset = hoffset; + goto highlight_hit_within_hightext; + } + goto highlight_search_hightext2; + } + +highlight_hit_within_hightext: + /* + * If we get to here, the hit starts within the + * hightext. If we are making the link current + * and it's the last character in the hightext, + * we are done. Otherwise, move there and start + * restoring the emphasis. - FM + */ + if ((Offset - offset) > + (flag == ON ? (hLen - 1) : hLen)) { + goto highlight_search_hightext2; + } + data += (Offset - offset); + offset = Offset; + itmp = 0; + written = 0; + len = tlen; + + /* + * Go to the start of the hit and + * handle its first character. - FM + */ + move(hline, offset); + tmp[0] = data[itmp]; + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[utf_extra+1] = '\0'; + itmp += utf_extra; + /* + * Start emphasis immediately if we are making + * the link non-current, or we are making it + * current but this is not the first character + * of the hightext. - FM + */ + if (flag != ON || offset > hoffset) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Start emphasis immediately if we are making + * the link non-current, or we are making it + * current but this is not the first character + * of the hightext. - FM + */ + if (flag != ON || offset > hoffset) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Start emphasis immediately if we are making + * the link non-current, or we are making it + * current but this is not the first character + * of the hightext. - FM + */ + if (flag != ON || offset > hoffset) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + written++; + } + itmp++; + /* + * Start emphasis after the first character + * if we are making the link current and this + * is not the last character. - FM + */ + if (!TargetEmphasisON && + data[itmp] != '\0') { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + } + + for (; + written < len && (tmp[0] = data[itmp]) != '\0'; + itmp++) { + /* + * Print all the other target chars, except + * the last character if it is also the last + * character of hightext and we are making + * the link current. - FM + */ + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[utf_extra+1] = '\0'; + itmp += utf_extra; + /* + * Make sure we don't restore emphasis to + * the last character of hightext if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Make sure we don't restore emphasis to + * the last character of hightext if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Make sure we don't restore emphasis to + * the last character of hightext if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + written++; + } + } + + /* + * Stop the emphasis if we haven't already, then reset + * the offset to our current position in the line, and + * if that is beyond the link, or we are making the link + * current and it is the last character in the hightext, + * we are done. - FM + */ + if (TargetEmphasisON) { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + } + LYGetYX(y, offset); + if (offset >= + (hoffset + (flag == ON ? (hLen - 1) : hLen))) { + goto highlight_search_hightext2; + } + + /* + * See if we have another hit that starts + * within the hightext. - FM + */ + data = (Data + (offset - Offset)); + if ((case_sensitive ? + (cp = LYno_attr_mbcs_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL : + (cp = LYno_attr_mbcs_case_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL) && + (offset + LenNeeded) < LYcols) { + /* + * If the hit starts after the end of the hightext, + * or we are making the link current and the hit + * starts at its last character, we are done. - FM + */ + if ((HitOffset + offset) >= + (hoffset + + (flag == ON ? (hLen - 1) : hLen))) { + goto highlight_search_hightext2; + } + + /* + * If the target extends beyond our buffer, emphasize + * everything in the hightext starting at this hit. + * Otherwise, set up the data and offsets, and loop + * back. - FM + */ + if ((HitOffset + (offset + tLen)) >= + (hoffset + hLen)) { + offset = (HitOffset + offset); + data = (buffer + (offset - hoffset)); + move(hline, offset); + itmp = 0; + written = 0; + len = strlen(data); + + /* + * Turn the emphasis back on. - FM + */ + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + for (; + written < len && (tmp[0] = data[itmp]) != '\0'; + itmp++) { + /* + * Print all the other target chars, except + * the last character if it is also the last + * character of hightext and we are making + * the link current. - FM + */ + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[(utf_extra + 1)] = '\0'; + itmp += utf_extra; + /* + * Make sure we don't restore emphasis to + * the last character of hightext if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Make sure we don't restore emphasis to + * the last character of hightext if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Make sure we don't restore emphasis to + * the last character of hightext if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + } else { + addstr(tmp); + } + written++; + } + } + /* + * Turn off the emphasis if we haven't already, + * and then we're done. - FM + */ + if (TargetEmphasisON) { + LYstopTargetEmphasis(); + } + goto highlight_search_hightext2; + } else { + Data = cp; + Offset = (offset + HitOffset); + data = buffer; + offset = hoffset; + goto highlight_hit_within_hightext; + } + } + goto highlight_search_hightext2; + } +highlight_search_hightext2: + if (target && *target && links[cur].type == WWW_LINK_TYPE && + links[cur].hightext2 && *links[cur].hightext2 && + links[cur].ly < display_lines && + HText_getFirstTargetInLine(HTMainText, + (links[cur].anchor_line_num + 1), + utf_flag, + (int *)&Offset, + (int *)&tLen, + (char **)&theData, + target)) { + int itmp, written, len, y, offset; + char *data; + int tlen = strlen(target); + int hlen, hLen; + int hline = (links[cur].ly + 1); + int hoffset = links[cur].hightext2_offset; + size_t utf_extra = 0; + + /* + * Copy into the buffer only what will fit + * up to the right border of the screen. - FM + */ + LYmbcsstrncpy(buffer, + (links[cur].hightext2 ? + links[cur].hightext2 : ""), + (sizeof(buffer) - 1), + ((LYcols - 1) - links[cur].hightext2_offset), + utf_flag); + hlen = strlen(buffer); + hLen = ((HTCJK != NOCJK || utf_flag) ? + LYmbcsstrlen(buffer, utf_flag) : hlen); + + /* + * Break out if the first hit in the line + * starts after this link. - FM + */ + if (Offset >= (hoffset + hLen)) { + goto highlight_search_done; + } + + /* + * Recursively skip hits that end before this link, and + * break out if there is no hit beyond those. - FM + */ + Data = theData; + while ((Offset < hoffset) && + ((Offset + tLen) <= hoffset)) { + data = (Data + tlen); + offset = (Offset + tLen); + if ((case_sensitive ? + (cp = LYno_attr_mbcs_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL : + (cp = LYno_attr_mbcs_case_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL) && + (offset + LenNeeded) < LYcols) { + Data = cp; + Offset = (offset + HitOffset); + } else { + goto highlight_search_done; + } + } + data = buffer; + offset = hoffset; + + /* + * If the hit starts before the hightext2, and ends + * in or beyond the hightext2, restore the emphasis, + * skipping the first and last characters of the + * hightext2 if we're making the link current. - FM + */ + if ((Offset < offset) && + ((Offset + tLen) > offset)) { + itmp = 0; + written = 0; + len = (tlen - (offset - Offset)); + + /* + * Go to the start of the hightext2 and + * handle its first character. - FM + */ + move(hline, offset); + tmp[0] = data[itmp]; + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[utf_extra+1] = '\0'; + itmp += utf_extra; + /* + * Start emphasis immediately if we are + * making the link non-current. - FM + */ + if (flag != ON) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Start emphasis immediately if we are + * making the link non-current. - FM + */ + if (flag != ON) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Start emphasis immediately if we are making + * the link non-current. - FM + */ + if (flag != ON) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + written++; + } + itmp++; + /* + * Start emphasis after the first character + * if we are making the link current and this + * is not the last character. - FM + */ + if (!TargetEmphasisON && + data[itmp] != '\0') { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + } + + /* + * Handle the remaining characters. - FM + */ + for (; + written < len && (tmp[0] = data[itmp]) != '\0'; + itmp++) { + /* + * Print all the other target chars, except + * the last character if it is also the last + * character of hightext2 and we are making + * the link current. - FM + */ + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[(utf_extra + 1)] = '\0'; + itmp += utf_extra; + /* + * Make sure we don't restore emphasis to + * the last character of hightext2 if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Make sure we don't restore emphasis to + * the last character of hightext2 if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Make sure we don't restore emphasis to + * the last character of hightext2 if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + written++; + } + } + + /* + * Stop the emphasis if we haven't already, then + * reset the offset to our current position in + * the line, and if that is beyond the link, or + * or we are making the link current and it is + * the last character of the hightext2, we are + * done. - FM + */ + if (TargetEmphasisON) { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + } + LYGetYX(y, offset); + if (offset >= + (hoffset + + (flag == ON ? (hLen - 1) : hLen))) { + goto highlight_search_done; + } + + /* + * See if we have another hit that starts + * within the hightext2. - FM + */ + data = (Data + (offset - Offset)); + if ((case_sensitive ? + (cp = LYno_attr_mbcs_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL : + (cp = LYno_attr_mbcs_case_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL) && + (offset + LenNeeded) < LYcols) { + /* + * If the hit starts after the end of the hightext2, + * or we are making the link current and the hit + * starts at its last character, we are done. - FM + */ + if ((HitOffset + offset) >= + (hoffset + + (flag == ON ? (hLen - 1) : hLen))) { + goto highlight_search_done; + } + + /* + * Set up the data and offset for the hit, and let + * the code for within hightext2 hits handle it. - FM + */ + Data = cp; + Offset = (offset + HitOffset); + data = buffer; + offset = hoffset; + goto highlight_hit_within_hightext2; + } + goto highlight_search_done; + } + +highlight_hit_within_hightext2: + /* + * If we get to here, the hit starts within the + * hightext2. If we are making the link current + * and it's the last character in the hightext2, + * we are done. Otherwise, move there and start + * restoring the emphasis. - FM + */ + if ((Offset - offset) > + (flag == ON ? (hLen - 1) : hLen)) { + goto highlight_search_done; + } + data += (Offset - offset); + offset = Offset; + itmp = 0; + written = 0; + len = tlen; + + /* + * Go to the start of the hit and + * handle its first character. - FM + */ + move(hline, offset); + tmp[0] = data[itmp]; + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[utf_extra+1] = '\0'; + itmp += utf_extra; + /* + * Start emphasis immediately if we are making + * the link non-current, or we are making it + * current but this is not the first character + * of the hightext2. - FM + */ + if (flag != ON || offset > hoffset) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Start emphasis immediately if we are making + * the link non-current, or we are making it + * current but this is not the first character + * of the hightext2. - FM + */ + if (flag != ON || offset > hoffset) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Start emphasis immediately if we are making + * the link non-current, or we are making it + * current but this is not the first character + * of the hightext2. - FM + */ + if (flag != ON || offset > hoffset) { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + addstr(tmp); + } else { + move(hline, (offset + 1)); + } + written++; + } + itmp++; + /* + * Start emphasis after the first character + * if we are making the link current and this + * is not the last character. - FM + */ + if (!TargetEmphasisON && + data[itmp] != '\0') { + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + } + + for (; + written < len && (tmp[0] = data[itmp]) != '\0'; + itmp++) { + /* + * Print all the other target chars, except + * the last character if it is also the last + * character of hightext2 and we are making + * the link current. - FM + */ + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[utf_extra+1] = '\0'; + itmp += utf_extra; + /* + * Make sure we don't restore emphasis to + * the last character of hightext2 if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Make sure we don't restore emphasis to + * the last character of hightext2 if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Make sure we don't restore emphasis to + * the last character of hightext2 if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + written++; + } + } + + /* + * Stop the emphasis if we haven't already, then reset + * the offset to our current position in the line, and + * if that is beyond the link, or we are making the link + * current and it is the last character in the hightext2, + * we are done. - FM + */ + if (TargetEmphasisON) { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + } + LYGetYX(y, offset); + if (offset >= + (hoffset + (flag == ON ? (hLen - 1) : hLen))) { + goto highlight_search_done; + } + + /* + * See if we have another hit that starts + * within the hightext2. - FM + */ + data = (Data + (offset - Offset)); + if ((case_sensitive ? + (cp = LYno_attr_mbcs_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL : + (cp = LYno_attr_mbcs_case_strstr(data, + target, + utf_flag, + &HitOffset, + &LenNeeded)) != NULL) && + (offset + LenNeeded) < LYcols) { + /* + * If the hit starts after the end of the hightext2, + * or we are making the link current and the hit + * starts at its last character, we are done. - FM + */ + if ((HitOffset + offset) >= + (hoffset + + (flag == ON ? (hLen - 1) : hLen))) { + goto highlight_search_done; + } + + /* + * If the target extends beyond our buffer, emphasize + * everything in the hightext2 starting at this hit. + * Otherwise, set up the data and offsets, and loop + * back. - FM + */ + if ((HitOffset + (offset + tLen)) >= + (hoffset + hLen)) { + offset = (HitOffset + offset); + data = (buffer + (offset - hoffset)); + move(hline, offset); + itmp = 0; + written = 0; + len = strlen(data); + + /* + * Turn the emphasis back on. - FM + */ + LYstartTargetEmphasis(); + TargetEmphasisON = TRUE; + for (; + written < len && (tmp[0] = data[itmp]) != '\0'; + itmp++) { + /* + * Print all the other target chars, except + * the last character if it is also the last + * character of hightext2 and we are making + * the link current. - FM + */ + if (utf_flag && !isascii(tmp[0])) { + if ((*tmp & 0xe0) == 0xc0) { + utf_extra = 1; + } else if ((*tmp & 0xf0) == 0xe0) { + utf_extra = 2; + } else if ((*tmp & 0xf8) == 0xf0) { + utf_extra = 3; + } else if ((*tmp & 0xfc) == 0xf8) { + utf_extra = 4; + } else if ((*tmp & 0xfe) == 0xfc) { + utf_extra = 5; + } else { + /* + * Garbage. + */ + utf_extra = 0; + } + if (strlen(&data[itmp+1]) < utf_extra) { + /* + * Shouldn't happen. + */ + utf_extra = 0; + } + } + if (utf_extra) { + strncpy(&tmp[1], &data[itmp+1], utf_extra); + tmp[(utf_extra + 1)] = '\0'; + itmp += utf_extra; + /* + * Make sure we don't restore emphasis to + * the last character of hightext2 if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + LYGetYX(y, offset); + move(hline, (offset + 1)); + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += (utf_extra + 1); + utf_extra = 0; + } else if (HTCJK != NOCJK && !isascii(tmp[0])) { + /* + * For CJK strings, by Masanobu Kimura. + */ + tmp[1] = data[++itmp]; + /* + * Make sure we don't restore emphasis to + * the last character of hightext2 if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + } else { + addstr(tmp); + } + tmp[1] = '\0'; + written += 2; + } else { + /* + * Make sure we don't restore emphasis to + * the last character of hightext2 if we + * are making the link current. - FM + */ + if (flag == ON && data[(itmp + 1)] == '\0') { + LYstopTargetEmphasis(); + TargetEmphasisON = FALSE; + } else { + addstr(tmp); + } + written++; + } + } + /* + * Turn off the emphasis if we haven't already, + * and then we're done. - FM + */ + if (TargetEmphasisON) { + LYstopTargetEmphasis(); + } + goto highlight_search_done; + } else { + Data = cp; + Offset = (offset + HitOffset); + data = buffer; + offset = hoffset; + goto highlight_hit_within_hightext2; + } + } + goto highlight_search_done; + } +highlight_search_done: + FREE(theData); + if (!LYShowCursor) - move(LYlines-1, LYcols-1); /* get cursor out of the way */ + /* + * Get cursor out of the way. + */ + move((LYlines - 1), (LYcols - 1)); else #endif /* FANCY CURSES || USE_SLANG */ - /* never hide the cursor if there's no FANCY CURSES or SLANG */ - move(links[cur].ly, links[cur].lx - 1); + /* + * Never hide the cursor if there's no FANCY CURSES or SLANG. + */ + move(links[cur].ly, + ((links[cur].lx > 0) ? (links[cur].lx - 1) : 0)); if (flag) refresh(); @@ -213,8 +1672,8 @@ PUBLIC void highlight ARGS2( } /* - * free_and_clear will free a pointer if it is non-zero and - * then set it to zero + * free_and_clear will free a pointer if it + * is non-zero and then set it to zero. */ PUBLIC void free_and_clear ARGS1( char **, pointer) @@ -227,7 +1686,7 @@ PUBLIC void free_and_clear ARGS1( } /* - * Collapse (REMOVE) all spaces in the string. + * Collapse (REMOVE) all spaces in the string. */ PUBLIC void collapse_spaces ARGS1( char *, string) @@ -307,7 +1766,7 @@ PUBLIC char * strip_trailing_slash ARGS1( } /* - * display (or hide) the status line + * Display (or hide) the status line. */ BOOLEAN mustshow = FALSE; @@ -433,7 +1892,7 @@ PUBLIC void statusline ARGS1( int a=(strncmp(buffer, "Alert", 5) || !hashStyles[s_alert].name ? s_status : s_alert); LynxChangeStyle (a, ABS_ON, 1); addstr(buffer); - wbkgdset(stdscr, hashStyles[a].color); + wbkgdset(stdscr, has_color ? hashStyles[a].color : hashStyles[a].mono); clrtoeol(); wbkgdset(stdscr, hashStyles[s_normal].color); LynxChangeStyle (a, ABS_OFF, 0); @@ -608,8 +2067,8 @@ PUBLIC int HTCheckForInterrupt NOARGS } /* - * A file URL for a remote host is an obsolete ftp URL. - * Return YES only if we're certain it's a local file. - FM + * A file URL for a remote host is an obsolete ftp URL. + * Return YES only if we're certain it's a local file. - FM */ PUBLIC BOOLEAN LYisLocalFile ARGS1( char *, filename) @@ -651,8 +2110,8 @@ PUBLIC BOOLEAN LYisLocalFile ARGS1( } /* - * Utility for checking URLs with a host field. - * Return YES only if we're certain it's the local host. - FM + * Utility for checking URLs with a host field. + * Return YES only if we're certain it's the local host. - FM */ PUBLIC BOOLEAN LYisLocalHost ARGS1( char *, filename) @@ -690,7 +2149,7 @@ PUBLIC BOOLEAN LYisLocalHost ARGS1( } /* - * Utility for freeing the list of local host aliases. - FM + * Utility for freeing the list of local host aliases. - FM */ PUBLIC void LYLocalhostAliases_free NOARGS { @@ -709,7 +2168,7 @@ PUBLIC void LYLocalhostAliases_free NOARGS } /* - * Utility for listing hosts to be treated as local aliases. - FM + * Utility for listing hosts to be treated as local aliases. - FM */ PUBLIC void LYAddLocalhostAlias ARGS1( char *, alias) @@ -733,8 +2192,8 @@ PUBLIC void LYAddLocalhostAlias ARGS1( } /* - * Utility for checking URLs with a host field. - * Return YES only if we've listed the host as a local alias. - FM + * Utility for checking URLs with a host field. + * Return YES only if we've listed the host as a local alias. - FM */ PUBLIC BOOLEAN LYisLocalAlias ARGS1( char *, filename) @@ -851,6 +2310,15 @@ PUBLIC int is_url ARGS1( return(0); /* + * Can't be a URL if it starts with a slash. + * So return immediately for this common case, + * also to avoid false positives if there is a + * colon later in the string. - kw + */ + if (*cp == '/') + return(0); + + /* * Can't be a URL if it lacks a colon. */ if (NULL == strchr(cp, ':')) @@ -1235,8 +2703,8 @@ PUBLIC char * quote_pathname ARGS1( } /* - * checks to see if the current process is attached via a terminal in the - * local domain + * Checks to see if the current process is attached + * via a terminal in the local domain. * */ PUBLIC BOOLEAN inlocaldomain NOARGS @@ -1310,7 +2778,7 @@ PUBLIC void size_change ARGS1( LYcols = SLtt_Screen_Cols; #ifdef SLANG_MBCS_HACK PHYSICAL_SLtt_Screen_Cols = LYcols; - SLtt_Screen_Cols = LYcols * 6; + SLtt_Screen_Cols = (LYcols * 6); #endif /* SLANG_MBCS_HACK */ if (sig == 0) /* @@ -1330,7 +2798,7 @@ PUBLIC void size_change ARGS1( #ifdef TIOCGSIZE if (ioctl(0, TIOCGSIZE, &win) == 0) { if (win.ts_lines != 0) { - LYlines = win.ts_lines - 1; + LYlines = win.ts_lines; } if (win.ts_cols != 0) { LYcols = win.ts_cols; @@ -1340,7 +2808,7 @@ PUBLIC void size_change ARGS1( #ifdef TIOCGWINSZ if (ioctl(0, TIOCGWINSZ, &win) == 0) { if (win.ws_row != 0) { - LYlines = win.ws_row - 1; + LYlines = win.ws_row; } if (win.ws_col != 0) { LYcols = win.ws_col; @@ -1365,7 +2833,7 @@ PUBLIC void size_change ARGS1( } /* - * Utility for freeing the list of previous suggested filenames. - FM + * Utility for freeing the list of previous suggested filenames. - FM */ PUBLIC void HTSugFilenames_free NOARGS { @@ -1431,15 +2899,19 @@ PUBLIC void change_sug_filename ARGS1( char *temp, *cp, *cp1, *end; size_t len; #ifdef VMS - char *dot; - int j,k; + char *dot; + int j, k; #endif /* VMS */ - /*** establish the current end of fname ***/ - end = fname + strlen(fname); + /* + * Establish the current end of fname. + */ + end = fname + strlen(fname); - /*** unescape fname ***/ - HTUnEscape(fname); + /* + * Unescape fname. + */ + HTUnEscape(fname); /*** rename any temporary files ***/ temp = (char *)calloc(1, (strlen(lynx_temp_space) + 60)); @@ -1448,196 +2920,249 @@ PUBLIC void change_sug_filename ARGS1( else sprintf(temp, "file://localhost/%sL%d", lynx_temp_space, (int)getpid()); len = strlen(temp); - if (0==strncmp(fname, temp, len)) { - cp = strrchr(fname, '.'); - if (strlen(cp) > (len - 4)) - cp = NULL; - strcpy(temp, (cp ? cp : "")); - strcpy(fname, "temp"); - strcat(fname, temp); - } - FREE(temp); + if (!strncmp(fname, temp, len)) { + cp = strrchr(fname, '.'); + if (strlen(cp) > (len - 4)) + cp = NULL; + strcpy(temp, (cp ? cp : "")); + strcpy(fname, "temp"); + strcat(fname, temp); + } + FREE(temp); - /*** remove everything up the the last_slash if there is one ***/ - if ((cp = strrchr(fname,'/')) != NULL && strlen(cp) > 1) { - cp1=fname; - cp++; /* go past the slash */ - for (; *cp != '\0'; cp++, cp1++) + /* + * Remove everything up the the last_slash if there is one. + */ + if ((cp = strrchr(fname,'/')) != NULL && strlen(cp) > 1) { + cp1 = fname; + /* + * Go past the slash. + */ + cp++; + for (; *cp != '\0'; cp++, cp1++) { *cp1 = *cp; + } + *cp1 = '\0'; + } - *cp1 = '\0'; /* terminate */ - } + /* + * Trim off date-size suffix, if present. + */ + if ((*(end - 1) == ']') && ((cp = strrchr(fname, '[')) != NULL) && + (cp > fname) && *(--cp) == ' ') { + while (*cp == ' ') { + *(cp--) = '\0'; + } + } - /*** Trim off date-size suffix, if present ***/ - if ((*(end - 1) == ']') && ((cp = strrchr(fname, '[')) != NULL) && - (cp > fname) && *(--cp) == ' ') - while (*cp == ' ') - *(cp--) = '\0'; - - /*** Trim off VMS device and/or directory specs, if present ***/ - if ((cp=strchr(fname,'[')) != NULL && - (cp1=strrchr(cp,']')) != NULL && strlen(cp1) > 1) { - cp1++; - for (cp=fname; *cp1 != '\0'; cp1++) - *(cp++) = *cp1; - *cp = '\0'; - } + /* + * Trim off VMS device and/or directory specs, if present. + */ + if ((cp = strchr(fname,'[')) != NULL && + (cp1 = strrchr(cp,']')) != NULL && strlen(cp1) > 1) { + cp1++; + for (cp=fname; *cp1 != '\0'; cp1++) { + *(cp++) = *cp1; + } + *cp = '\0'; + } #ifdef VMS - /*** Replace illegal or problem characters ***/ - dot = fname + strlen(fname); - for (cp = fname; cp < dot; cp++) { - - /** Replace with underscores **/ - if (*cp == ' ' || *cp == '/' || *cp == ':' || - *cp == '[' || *cp == ']' || *cp == '&') - *cp = '_'; - - /** Replace with dashes **/ - else if (*cp == '!' || *cp == '?' || *cp == '\'' || + /* + * Replace illegal or problem characters. + */ + dot = fname + strlen(fname); + for (cp = fname; cp < dot; cp++) { + /* + * Replace with underscores. + */ + if (*cp == ' ' || *cp == '/' || *cp == ':' || + *cp == '[' || *cp == ']' || *cp == '&') { + *cp = '_'; + /* + * Replace with dashes. + */ + } else if (*cp == '!' || *cp == '?' || *cp == '\'' || *cp == ',' || *cp == ':' || *cp == '\"' || *cp == '+' || *cp == '@' || *cp == '\\' || *cp == '(' || *cp == ')' || *cp == '=' || *cp == '<' || *cp == '>' || *cp == '#' || *cp == '%' || *cp == '*' || *cp == '`' || *cp == '~' || *cp == '^' || *cp == '|' || - *cp < ' ' || ((unsigned char)*cp) > 126) - *cp = '-'; + *cp < ' ' || ((unsigned char)*cp) > 126) { + *cp = '-'; + } } - /** Collapse any serial underscores **/ - cp = fname + 1; - j = 0; - while (cp < dot) { - if (fname[j] == '_' && *cp == '_') - cp++; - else - fname[++j] = *cp++; - } - fname[++j] = '\0'; - - /** Collapse any serial dashes **/ - dot = fname + (strlen(fname)); - cp = fname + 1; - j = 0; - while (cp < dot) { - if (fname[j] == '-' && *cp == '-') - cp++; - else - fname[++j] = *cp++; - } - fname[++j] = '\0'; - - /** Trim any trailing or leading **/ - /** underscrores or dashes **/ - cp = fname + (strlen(fname)) - 1; - while (*cp == '_' || *cp == '-') - *cp-- = '\0'; - if (fname[0] == '_' || fname[0] == '-') { - dot = fname + (strlen(fname)); - cp = fname; - while ((*cp == '_' || *cp == '-') && cp < dot) - cp++; - j = 0; - while (cp < dot) - fname[j++] = *cp++; - fname[j] = '\0'; - } + /* + * Collapse any serial underscores. + */ + cp = fname + 1; + j = 0; + while (cp < dot) { + if (fname[j] == '_' && *cp == '_') { + cp++; + } else { + fname[++j] = *cp++; + } + } + fname[++j] = '\0'; - /** Replace all but the last period with _'s, or second **/ - /** to last if last is followed by a terminal Z or z, **/ - /** or GZ or gz, **/ - /** e.g., convert foo.tar.Z to **/ - /** foo.tar_Z **/ - /** or, convert foo.tar.gz to **/ - /** foo.tar-gz **/ - j = strlen(fname) - 1; - if ((dot = strrchr(fname, '.')) != NULL) { - if (TOUPPER(fname[j]) == 'Z') { - if ((fname[j-1] == '.') && - (((cp = strchr(fname, '.')) != NULL) && cp < dot)) { - *dot = '_'; - dot = strrchr(fname, '.'); - } else if (((TOUPPER(fname[j-1]) == 'G') && - fname[j-2] == '.') && - (((cp = strchr(fname, '.')) != NULL) && cp < dot)) { - *dot = '-'; - dot = strrchr(fname, '.'); - } - } - cp = fname; - while ((cp = strchr(cp, '.')) != NULL && cp < dot) - *cp = '_'; - - /** But if the root is > 39 characters, move **/ - /** the period appropriately to the left **/ - while (dot - fname > 39) { - *dot = '\0'; - if ((cp = strrchr(fname, '_')) != NULL) { - *cp = '.'; - *dot = '_'; - } - else if ((cp = strrchr(fname, '-')) != NULL) { - *cp = '.'; - *dot = '_'; - } - else { - *dot = '_'; - j = strlen(fname); - fname[j+1] = '\0'; - while (j > 39) - fname[j--] = fname[j]; - fname[j] = '.'; - } - dot = strrchr(fname, '.'); - } + /* + * Collapse any serial dashes. + */ + dot = fname + (strlen(fname)); + cp = fname + 1; + j = 0; + while (cp < dot) { + if (fname[j] == '-' && *cp == '-') { + cp++; + } else { + fname[++j] = *cp++; + } + } + fname[++j] = '\0'; - /** Make sure the extension is < 40 characters **/ - if ((fname + strlen(fname) - dot) > 39) - *(dot+40) = '\0'; + /* + * Trim any trailing or leading + * underscrores or dashes. + */ + cp = fname + (strlen(fname)) - 1; + while (*cp == '_' || *cp == '-') { + *cp-- = '\0'; + } + if (fname[0] == '_' || fname[0] == '-') { + dot = fname + (strlen(fname)); + cp = fname; + while ((*cp == '_' || *cp == '-') && cp < dot) { + cp++; + } + j = 0; + while (cp < dot) { + fname[j++] = *cp++; + } + fname[j] = '\0'; + } - /** Trim trailing dashes or underscores **/ - j = strlen(fname) - 1; - while (fname[j] == '_' || fname[j] == '-') - fname[j--] = '\0'; - } - else { - /** No period, so put one on the end, or after **/ - /** the 39th character, trimming trailing dashes **/ - /** or underscrores **/ - if (strlen(fname) > 39) - fname[39] = '\0'; - j = strlen(fname) - 1; - while ((fname[j] == '_') || (fname[j] == '-')) - j--; - fname[++j] = '.'; - fname[++j] = '\0'; - } + /* + * Replace all but the last period with _'s, or second + * to last if last is followed by a terminal Z or z, + * or GZ or gz, + * e.g., convert foo.tar.Z to + * foo.tar_Z + * or, convert foo.tar.gz to + * foo.tar-gz + */ + j = strlen(fname) - 1; + if ((dot = strrchr(fname, '.')) != NULL) { + if (TOUPPER(fname[j]) == 'Z') { + if ((fname[j-1] == '.') && + (((cp = strchr(fname, '.')) != NULL) && cp < dot)) { + *dot = '_'; + dot = strrchr(fname, '.'); + } else if (((TOUPPER(fname[j-1]) == 'G') && + fname[j-2] == '.') && + (((cp = strchr(fname, '.')) != NULL) && cp < dot)) { + *dot = '-'; + dot = strrchr(fname, '.'); + } + } + cp = fname; + while ((cp = strchr(cp, '.')) != NULL && cp < dot) { + *cp = '_'; + } + + /* + * But if the root is > 39 characters, move + * the period appropriately to the left. + */ + while (dot - fname > 39) { + *dot = '\0'; + if ((cp = strrchr(fname, '_')) != NULL) { + *cp = '.'; + *dot = '_'; + } else if ((cp = strrchr(fname, '-')) != NULL) { + *cp = '.'; + *dot = '_'; + } else if (*(dot + 1) == '\0') { + j = strlen(fname); + while (j > 39) { + fname[j] = fname[j-1]; + j--; + } + fname[j] = '.'; + } else { + *dot = '.'; + j = 39; + k = 0; + while (dot[k] != '\0') { + fname[j++] = dot[k++]; + } + fname[j] = '\0'; + } + dot = strrchr(fname, '.'); + } + + /* + * Make sure the extension is < 40 characters. + */ + if ((fname + strlen(fname) - dot) > 39) { + *(dot + 40) = '\0'; + } + + /* + * Trim trailing dashes or underscores. + */ + j = (strlen(fname) - 1); + while (fname[j] == '_' || fname[j] == '-') { + fname[j--] = '\0'; + } + } else { + /* + * No period, so put one on the end, or after + * the 39th character, trimming trailing dashes + * or underscrores. + */ + if (strlen(fname) > 39) { + fname[39] = '\0'; + } + j = (strlen(fname) - 1); + while ((fname[j] == '_') || (fname[j] == '-')) { + j--; + } + fname[++j] = '.'; + fname[++j] = '\0'; + } #else /* Not VMS (UNIX): */ - /*** Replace problem characters ***/ - for (cp = fname; *cp != '\0'; cp++) { - switch (*cp) { - case '\'': - case '\"': - case '/': - case ' ': - *cp = '-'; - } - } + /* + * Replace problem characters. + */ + for (cp = fname; *cp != '\0'; cp++) { + switch (*cp) { + case '\'': + case '\"': + case '/': + case ' ': + *cp = '-'; + } + } #endif /* VMS (UNIX) */ - /** Make sure the rest of the original string in nulled. **/ - cp = fname + strlen(fname); - while (cp < end) - *cp++ = '\0'; + /* + * Make sure the rest of the original string in nulled. + */ + cp = fname + strlen(fname); + while (cp < end) { + *cp++ = '\0'; + } return; } /* - * To create standard temporary file names + * To create standard temporary file names. */ PUBLIC void tempname ARGS2( char *, namebuffer, @@ -1779,8 +3304,8 @@ PUBLIC int number2arrows ARGS1( } /* - * parse_restrictions takes a string of comma-separated restrictions - * and sets the corresponding flags to restrict the facilities available + * parse_restrictions takes a string of comma-separated restrictions + * and sets the corresponding flags to restrict the facilities available. */ PRIVATE char *restrict_name[] = { "inside_telnet" , @@ -2132,6 +3657,10 @@ PUBLIC void LYConvertToURL ARGS1( char *old_string = *AllocatedString; char *temp = NULL; char *cp = NULL; +#ifndef VMS + struct stat st; + FILE *fptemp = NULL; +#endif /* !VMS */ if (!old_string || *old_string == '\0') return; @@ -2364,8 +3893,6 @@ have_VMS_URL: * Create a full path to the current default directory. */ char curdir[DIRNAMESIZE]; - struct stat st; - FILE *fptemp = NULL; BOOL is_local = FALSE; #if HAVE_GETCWD getcwd (curdir, DIRNAMESIZE); @@ -2463,12 +3990,11 @@ have_VMS_URL: FREE(temp); if (fptemp) { fclose(fptemp); + fptemp = NULL; } } #endif /* VMS */ } else { - struct stat st; - FILE *fptemp = NULL; /* * Path begins with a slash. Simplify and use it. */ @@ -2482,12 +4008,11 @@ have_VMS_URL: StrAllocCat(*AllocatedString, HTVMS_wwwName((char *)Home_Dir())); #else StrAllocCat(*AllocatedString, "/"); -#endif /* VMS */ } else if ((stat(old_string, &st) > -1) || (fptemp = fopen(old_string, "r")) != NULL) { /* * It is an absolute directory or file - * on the local system. - kw + * on the local system. - KW */ StrAllocCopy(temp, old_string); LYTrimRelFromAbsPath(temp); @@ -2498,12 +4023,15 @@ have_VMS_URL: StrAllocCat(*AllocatedString, cp); FREE(cp); FREE(temp); - if (fptemp) + if (fptemp) { fclose(fptemp); + fptemp = NULL; + } if (TRACE) { fprintf(stderr, "Converted '%s' to '%s'\n", old_string, *AllocatedString); } +#endif /* VMS */ } else if (old_string[1] == '~') { /* * Has a Home_Dir() reference. Handle it @@ -3076,7 +4604,7 @@ PUBLIC void Define_VMSLogical ARGS2( PUBLIC CONST char * Home_Dir NOARGS { - static CONST char *homedir; + static CONST char *homedir = NULL; if (!homedir) { if ((homedir = getenv("HOME")) == NULL) { @@ -3390,17 +4918,22 @@ PUBLIC void LYAddPathToHome ARGS3( /* * This function takes a string in the format * "Mon, 01-Jan-96 13:45:35 GMT" or - * "Mon, 1 Jan 1996 13:45:35 GMT"" + * "Mon, 1 Jan 1996 13:45:35 GMT"" or + * "dd-mm-yyyy" * as an argument, and returns its conversion to clock format * (seconds since 00:00:00 Jan 1 1970), or 0 if the string - * doesn't match the expected pattern. It also returns 0 - * if the time is in the past. It is intended for handling - * 'expires' strings homologously to 'max-age' strings, for - * which 0 is the minimum, and greater values are handled - * as '[max-age seconds] + time(NULL)'. - FM + * doesn't match the expected pattern. It also returns 0 if + * the time is in the past and the "absolute" argument is FALSE. + * It is intended for handling 'expires' strings in Version 0 + * cookies homologously to 'max-age' strings in Version 1 cookies, + * for which 0 is the minimum, and greater values are handled as + * '[max-age seconds] + time(NULL)'. If "absolute" if TRUE, we + * return the clock format value itself, but if anything goes wrong + * when parsing the expected patterns, we still return 0. - FM */ -PUBLIC time_t LYmktime ARGS1( - char *, string) +PUBLIC time_t LYmktime ARGS2( + char *, string, + BOOL, absolute) { char *s; time_t now, clock2; @@ -3418,17 +4951,13 @@ PUBLIC time_t LYmktime ARGS1( fprintf(stderr, "LYmktime: Parsing '%s'\n", s); /* - * Skip the "Day, " field. - FM + * Skip any lead alphabetic "Day, " field and + * seek a numberic day field. - FM */ - while (*s != '\0' && *s != ',') + while (*s != '\0' && !isdigit((unsigned char)*s)) s++; if (*s == '\0') return(0); - s++; - while (*s != '\0' && isspace((unsigned char)*s)) - s++; - if (*s == '\0' || !isdigit((unsigned char)*s)) - return(0); /* * Get the numeric day and convert to an integer. - FM @@ -3446,18 +4975,27 @@ PUBLIC time_t LYmktime ARGS1( /* * Get the month string and convert to an integer. - FM */ - while (*s != '\0' && !isalpha((unsigned char)*s)) + while (*s != '\0' && !isalnum((unsigned char)*s)) s++; if (*s == '\0') return(0); start = s; - while (*s != '\0' && isalpha((unsigned char)*s)) + while (*s != '\0' && isalnum((unsigned char)*s)) s++; - if (*s == '\0' || (s - start) < 3 || (s - start) > 9) + if ((*s == '\0') || + (s - start) < (isdigit((unsigned char)*(s - 1)) ? 2 : 3) || + (s - start) > (isdigit((unsigned char)*(s - 1)) ? 2 : 9)) return(0); - LYstrncpy(temp, start, 3); + LYstrncpy(temp, start, (isdigit((unsigned char)*(s - 1)) ? 2 : 3)); switch (TOUPPER(temp[0])) { - case 'A': + case '0': + case '1': + month = atoi(temp); + if (month < 1 || month > 12) { + return(0); + } + break; + case 'A': if (!strcasecomp(temp, "Apr")) { month = 4; } else if (!strcasecomp(temp, "Aug")) { @@ -3535,8 +5073,6 @@ PUBLIC time_t LYmktime ARGS1( start = s; while (*s != '\0' && isdigit((unsigned char)*s)) s++; - if (*s == '\0') - return(0); if ((s - start) == 4) { LYstrncpy(temp, start, 4); } else if ((s - start) == 2) { @@ -3554,49 +5090,54 @@ PUBLIC time_t LYmktime ARGS1( */ while (*s != '\0' && !isdigit((unsigned char)*s)) s++; - if (*s == '\0') - return(0); - start = s; - while (*s != '\0' && isdigit((unsigned char)*s)) - s++; - if (*s != ':' || (s - start) > 2) - return(0); - LYstrncpy(temp, start, (int)(s - start)); - hour = atoi(temp); + if (*s == '\0') { + hour = 0; + minutes = 0; + seconds = 0; + } else { + start = s; + while (*s != '\0' && isdigit((unsigned char)*s)) + s++; + if (*s != ':' || (s - start) > 2) + return(0); + LYstrncpy(temp, start, (int)(s - start)); + hour = atoi(temp); - /* - * Get the numeric minutes string and convert to an integer. - FM - */ - while (*s != '\0' && !isdigit((unsigned char)*s)) - s++; - if (*s == '\0') - return(0); - start = s; - while (*s != '\0' && isdigit((unsigned char)*s)) - s++; - if (*s != ':' || (s - start) > 2) - return(0); - LYstrncpy(temp, start, (int)(s - start)); - minutes = atoi(temp); + /* + * Get the numeric minutes string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit((unsigned char)*s)) + s++; + if (*s == '\0') + return(0); + start = s; + while (*s != '\0' && isdigit((unsigned char)*s)) + s++; + if (*s != ':' || (s - start) > 2) + return(0); + LYstrncpy(temp, start, (int)(s - start)); + minutes = atoi(temp); - /* - * Get the numeric seconds string and convert to an integer. - FM - */ - while (*s != '\0' && !isdigit((unsigned char)*s)) - s++; - if (*s == '\0') - return(0); - start = s; - while (*s != '\0' && isdigit((unsigned char)*s)) - s++; - if (*s == '\0' || (s - start) > 2) - return(0); - LYstrncpy(temp, start, (int)(s - start)); - seconds = atoi(temp); + /* + * Get the numeric seconds string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit((unsigned char)*s)) + s++; + if (*s == '\0') + return(0); + start = s; + while (*s != '\0' && isdigit((unsigned char)*s)) + s++; + if (*s == '\0' || (s - start) > 2) + return(0); + LYstrncpy(temp, start, (int)(s - start)); + seconds = atoi(temp); + } /* * Convert to clock format (seconds since 00:00:00 Jan 1 1970), - * but then zero it if it's in the past. - FM + * but then zero it if it's in the past and "absolute" is not + * TRUE. - FM */ month -= 3; if (month < 0) { @@ -3609,7 +5150,7 @@ PUBLIC time_t LYmktime ARGS1( (hour * 60 * 60) + (minutes * 60) + seconds); - if (clock2 <= time(NULL)) + if (absolute == FALSE && clock2 <= time(NULL)) clock2 = (time_t)0; if (TRACE && clock2 > 0) fprintf(stderr, @@ -3619,7 +5160,8 @@ PUBLIC time_t LYmktime ARGS1( } #if ! HAVE_PUTENV -/* no putenv on the next so we use this code instead! +/* + * No putenv on the next so we use this code instead! */ /* Copyright (C) 1991 Free Software Foundation, Inc. @@ -3666,7 +5208,9 @@ extern int errno; extern char **environ; -/* Put STRING, which is of the form "NAME=VALUE", in the environment. */ +/* + * Put STRING, which is of the form "NAME=VALUE", in the environment. + */ PUBLIC int putenv ARGS1( CONST char *, string) { diff --git a/src/LYUtils.h b/src/LYUtils.h index 477504d6..557d971c 100644 --- a/src/LYUtils.h +++ b/src/LYUtils.h @@ -8,7 +8,7 @@ #include "HTList.h" #endif /* HTLIST_H */ -extern void highlight PARAMS((int flag, int cur)); +extern void highlight PARAMS((int flag, int cur, char *target)); extern void free_and_clear PARAMS((char **obj)); extern void collapse_spaces PARAMS((char *string)); extern void convert_to_spaces PARAMS((char *string, BOOL condense)); @@ -52,7 +52,7 @@ extern CONST char *Home_Dir NOPARAMS; extern BOOLEAN LYPathOffHomeOK PARAMS((char *fbuffer, int fbuffer_size)); extern void LYAddPathToHome PARAMS(( char *fbuffer, int fbuffer_size, char *fname)); -extern time_t LYmktime PARAMS((char *string)); +extern time_t LYmktime PARAMS((char *string, BOOL absolute)); #if ! HAVE_PUTENV extern int putenv PARAMS((CONST char *string)); #endif /* HAVE_PUTENV */ diff --git a/src/LYrcFile.c b/src/LYrcFile.c index a67a64e8..c462715e 100644 --- a/src/LYrcFile.c +++ b/src/LYrcFile.c @@ -352,6 +352,21 @@ PUBLIC void read_rc NOPARAMS LYSelectPopups = TRUE; /* + * Show cursor. + */ + } else if ((cp = LYstrstr(line_buffer, "show_cursor")) != NULL && + cp-line_buffer < number_sign) { + + if ((cp2 = (char * )strchr(cp, '=')) != NULL) + cp = cp2 + 1; + while (isspace(*cp)) + cp++; /* get rid of spaces */ + if (!strncasecomp(cp, "off", 3)) + LYShowCursor = FALSE; + else + LYShowCursor = TRUE; + + /* * Keypad mode. */ } else if ((cp = LYstrstr(line_buffer, "keypad_mode")) != NULL && @@ -361,8 +376,10 @@ PUBLIC void read_rc NOPARAMS cp = cp2 + 1; while (isspace(*cp)) cp++; /* get rid of spaces */ - if (LYstrstr(cp,"LINKS_ARE_NUMBERED")) + if (LYstrstr(cp, "LINKS_ARE_NUMBERED")) keypad_mode = LINKS_ARE_NUMBERED; + else if (LYstrstr(cp, "LINKS_AND_FORM_FIELDS_ARE_NUMBERED")) + keypad_mode = LINKS_AND_FORM_FIELDS_ARE_NUMBERED; else keypad_mode = NUMBERS_AS_ARROWS; @@ -491,6 +508,7 @@ PUBLIC int save_rc NOPARAMS if ((fp = fopen(rcfile, "w")) == NULL) { return FALSE; } + chmod(rcfile, 0600); /* * Header. @@ -680,6 +698,21 @@ PUBLIC int save_rc NOPARAMS fprintf(fp, "select_popups=%s\n\n", (LYSelectPopups ? "on" : "off")); /* + * Show cursor. + */ + fprintf(fp, "\ +# show_cursor specifies whether to 'hide' the cursor to the right (and\n\ +# bottom, if possible) of the screen, or to place it to the left of the\n\ +# current link in documents, or current option in select popup windows.\n\ +# Positioning the cursor to the left of the current link or option is\n\ +# helpful for speech or braille interfaces, and when the terminal is\n\ +# one which does not distingish the current link based on highlighting\n\ +# or color. A value of \"on\" will set positioning to the left as the\n\ +# default while a value of \"off\" will set 'hiding' of the cursor.\n\ +# The default can be overridden via the -show_cursor command line toggle.\n"); + fprintf(fp, "show_cursor=%s\n\n", (LYShowCursor ? "on" : "off")); + + /* * Keypad mode. */ fprintf(fp, "\ @@ -688,14 +721,28 @@ PUBLIC int save_rc NOPARAMS # 8 = Up Arrow\n\ # 4 = Left Arrow 6 = Right Arrow\n\ # 2 = Down Arrow\n\ +# and the corresponding keyboard numbers will act as arrow keys,\n\ +# regardless of whether numlock is on.\n"); + fprintf(fp, "\ # If keypad_mode is set to \"LINKS_ARE_NUMBERED\", then numbers will\n\ -# appear next to each link and numbers are used to select links.\n\ +# appear next to each link and numbers are used to select links.\n"); + fprintf(fp, "\ +# If keypad_mode is set to \"LINKS_AND_FORM_FIELDS_ARE_NUMBERED\", then\n\ +# numbers will appear next to each link and visible form input field.\n\ +# Numbers are used to select links, or to move the \"current link\" to a\n\ +# form input field or button. In addition, options in popup menus are\n\ +# indexed so that the user may type an option number to select an option in\n\ +# a popup menu, even if the option isn't visible on the screen. Reference\n\ +# lists and output from the list command also enumerate form inputs.\n"); + fprintf(fp, "\ # NOTE: Some fixed format documents may look disfigured when\n\ -# \"LINKS_ARE_NUMBERED\" is enabled.\n"); +# \"LINKS_ARE_NUMBERED\" or \"LINKS_AND_FORM_FIELDS_ARE_NUMBERED\" are\n\ +# enabled.\n"); fprintf(fp, "keypad_mode=%s\n\n", - (keypad_mode==NUMBERS_AS_ARROWS ? - "NUMBERS_AS_ARROWS" : "LINKS_ARE_NUMBERED")); - + ((keypad_mode == NUMBERS_AS_ARROWS) ? "NUMBERS_AS_ARROWS" : + ((keypad_mode == LINKS_ARE_NUMBERED) ? "LINKS_ARE_NUMBERED" : + "LINKS_AND_FORM_FIELDS_ARE_NUMBERED"))); + /* * Lineedit mode. */ diff --git a/src/UCAuto.c b/src/UCAuto.c index cd786b76..b09df4ab 100644 --- a/src/UCAuto.c +++ b/src/UCAuto.c @@ -1,32 +1,43 @@ -#ifdef EXP_CHARTRANS -#ifdef EXP_CHARTRANS_AUTOSWITCH -#ifdef LINUX - -/* This file contains code for changing the Linux console mode. -** Currently some names for font files are hardwired in here. -** You have to change this code if it needs accomodation for your -** system (or get the required files...). +/* +** This file contains code for changing the Linux console mode. +** Currently some names for font files are hardwired in here. +** You have to change this code if it needs accomodation for your +** system (or get the required files...). ** -** Depending on the Display Character Set switched to, and the previous -** one as far as it is known, system("setfont ...") and/or output of -** escape sequences to switch console mode are done. Curses will be -** temporarily suspended while that happens. +** Depending on the Display Character Set switched to, and the previous +** one as far as it is known, system("setfont ...") and/or output of +** escape sequences to switch console mode are done. Curses will be +** temporarily suspended while that happens. ** -** NOTE that the setfont calls will also affect all other virtual consoles. +** NOTE that the setfont calls will also affect all other virtual consoles. ** -** Any ideas how to do this for other systems? +** Any ideas how to do this for other systems? */ -#include "tcp.h" + #include "HTUtils.h" +#include "tcp.h" + #include "UCMap.h" #include "UCDefs.h" #include "UCAuto.h" #include "LYGlobalDefs.h" -typedef enum {Is_Unset, Is_Set, Dunno, Dont_Care} TGen_state_t; -typedef enum {G0, G1} TGNstate_t; -typedef enum -{ +#ifdef EXP_CHARTRANS_AUTOSWITCH + +#ifdef VMS +#define DISPLAY "DECW$DISPLAY" +#else +#define DISPLAY "DISPLAY" +#endif /* VMS */ + +#ifdef LINUX +typedef enum { + Is_Unset, Is_Set, Dunno, Dont_Care +} TGen_state_t; +typedef enum { + G0, G1 +} TGNstate_t; +typedef enum { GN_Blat1, GN_0decgraf, GN_Ucp437, GN_Kuser, GN_dunno, GN_dontCare } TTransT_t; @@ -36,11 +47,17 @@ static char T_setfont_cmd[200] = "\0"; #define SETFONT "setfont" #define NOOUTPUT "2>/dev/null" -PRIVATE void call_setfont ARGS3(char *,font, char *,fnsuffix, char *,umap) +PRIVATE void call_setfont ARGS3( + char *, font, + char *, fnsuffix, + char *, umap) { if (font && *font && umap && *umap && - 0==strcmp(font,T_font_fn) && 0==strcmp(umap,T_umap_fn)) { - return; /* no need to repeat */ + !strcmp(font, T_font_fn) && !strcmp(umap, T_umap_fn)) { + /* + * No need to repeat. + */ + return; } if (font) strcpy(T_font_fn, font); @@ -62,21 +79,21 @@ PRIVATE void call_setfont ARGS3(char *,font, char *,fnsuffix, char *,umap) } else { *T_setfont_cmd = '\0'; } - + if (*T_setfont_cmd) { - - if (TRACE) { - fprintf(stderr, "Executing setfont: '%s'\n", - T_setfont_cmd); - } - + if (TRACE) { + fprintf(stderr, "Executing setfont: '%s'\n", T_setfont_cmd); + } system(T_setfont_cmd); } } -/* This is the thing that actually gets called from display_page(). */ - -PUBLIC void UCChangeTerminalCodepage ARGS2(int, newcs, LYUCcharset *,p) +/* + * This is the thing that actually gets called from display_page(). + */ +PUBLIC void UCChangeTerminalCodepage ARGS2( + int, newcs, + LYUCcharset *, p) { static int lastcs = -1; static char * lastname = NULL; @@ -94,98 +111,128 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(int, newcs, LYUCcharset *,p) char tmpbuf1[100], tmpbuf2[20]; char *cp; -/* Font sizes are currently hardwired here... */ + /* + * Font sizes are currently hardwired here. + */ #define SUFF1 ".f16" #define SUFF2 "-16.psf" #define SUFF3 "-8x16" #define SUFF4 "8x16" -/* use this for output of escape sequences... */ -/* for some reason stdout won't do... maybe needs flush() somewhere.. */ + /* + * Use this for output of escape sequences. + * + * For some reason stdout won't do; maybe needs flush() somewhere. + */ #define ESCOUT stderr - -#ifdef VMS -#define DISPLAY "DECW$DISPLAY" -#else -#define DISPLAY "DISPLAY" -#endif /* VMS */ - if (display || (cp = getenv(DISPLAY)) != NULL) { - /* We won't do anything in an xterm. Better that way... */ + /* + * We won't do anything in an xterm. Better that way... + */ return; } - if (0==strcmp(name,"iso-8859-10")) { - call_setfont("iso10", SUFF1, "iso10.uni"); + if (!strcmp(name, "iso-8859-10")) { + call_setfont("iso10", SUFF1, "iso10.uni"); TransT = GN_Kuser; HasUmap = Is_Set; Utf = Is_Unset; - } else if (0==strncmp(name,"iso-8859-1",10)) { - if ((lastHasUmap==Is_Set) && 0==strcmp(lastname,"cp850")) { - /* cp850 already contains all latin1 characters */ - if (lastTransT != GN_Blat1) + } else if (!strncmp(name, "iso-8859-1", 10)) { + if ((lastHasUmap == Is_Set) && !strcmp(lastname, "cp850")) { + /* + * cp850 already contains all latin1 characters. + */ + if (lastTransT != GN_Blat1) { TransT = GN_Blat1; + } } else { - call_setfont("lat1u", SUFF2, "lat1u.uni"); - /* "setfont lat1u-16.psf -u lat1u.uni" */ + /* + * "setfont lat1u-16.psf -u lat1u.uni" + */ + call_setfont("lat1u", SUFF2, "lat1u.uni"); HasUmap = Is_Set; - if (lastTransT != GN_Blat1) + if (lastTransT != GN_Blat1) { TransT = GN_Blat1; + } } Utf = Is_Unset; - } else if (0==strcmp(name,"iso-8859-2")) { -/* call_setfont("lat2", SUFF2, "lat2.uni"); */ - /* "setfont lat2-16.psf -u lat2.uni" */ - call_setfont("iso02", SUFF1, "iso02.uni"); - /* "setfont iso02.f16 -u iso02.uni" */ + } else if (!strcmp(name, "iso-8859-2")) { +#ifdef NOTDEFINED + /* + * "setfont lat2-16.psf -u lat2.uni" + */ + call_setfont("lat2", SUFF2, "lat2.uni"); */ +#endif /* NOTDEFINED */ + /* + * "setfont iso02.f16 -u iso02.uni" + */ + call_setfont("iso02", SUFF1, "iso02.uni"); TransT = GN_Kuser; HasUmap = Is_Set; Utf = Is_Unset; - } else if (0==strncmp(name,"iso-8859-",9)) { + } else if (!strncmp(name, "iso-8859-", 9)) { sprintf(tmpbuf1, "iso0%s", &name[9]); sprintf(tmpbuf2, "iso0%s%s", &name[9],".uni"); - call_setfont(tmpbuf1,SUFF1, tmpbuf2); - /* "setfont iso0N.f16 -u iso0N.uni" */ + /* + * "setfont iso0N.f16 -u iso0N.uni" + */ + call_setfont(tmpbuf1, SUFF1, tmpbuf2); TransT = GN_Kuser; HasUmap = Is_Set; Utf = Is_Unset; - } else if (0==strcmp(name,"koi8-r")) { - call_setfont("koi8", SUFF3, NULL); + } else if (!strcmp(name, "koi8-r")) { + /* + * "setfont koi8-8x16" + */ + call_setfont("koi8", SUFF3, NULL); TransT = GN_Kuser; HasUmap = Is_Unset; Utf = Is_Unset; - } else if (0==strcmp(name,"cp437")) { - call_setfont("default", SUFF4 , "cp437.uni"); - /* "setfont default8x16 -u cp437.uni" */ + } else if (!strcmp(name, "cp437")) { + /* + * "setfont default8x16 -u cp437.uni" + */ + call_setfont("default", SUFF4, "cp437.uni"); if (TransT == GN_Kuser || TransT == GN_Ucp437) TransT = GN_dontCare; else TransT = GN_Ucp437; HasUmap = Is_Set; Utf = Is_Unset; - } else if (0==strcmp(name,"cp850")) { - call_setfont("cp850" ,SUFF3 , "cp850.uni"); - /* "setfont cp850-8x16 -u cp850.uni" */ + } else if (!strcmp(name, "cp850")) { + /* + * "setfont cp850-8x16 -u cp850.uni" + */ + call_setfont("cp850", SUFF3, "cp850.uni"); TransT = GN_Kuser; HasUmap = Is_Set; Utf = Is_Unset; - } else if (0==strcmp(name,"x-transparent")) { + } else if (!strcmp(name, "x-transparent")) { Utf = Dont_Care; - } else if (0==strcmp(name,"us-ascii")) { + } else if (!strcmp(name, "us-ascii")) { Utf = Dont_Care; - } else if (0==strncmp(name,"mnem",4)) { + } else if (!strncmp(name, "mnem", 4)) { Utf = Dont_Care; } if (TransT != lastTransT) { if (TransT == GN_Blat1) { - fprintf(ESCOUT,"\033(B"); /* switch Linux console to lat1 table */ + /* + * Switch Linux console to lat1 table. + */ + fprintf(ESCOUT, "\033(B"); } else if (TransT == GN_0decgraf) { - fprintf(ESCOUT,"\033(0"); + fprintf(ESCOUT, "\033(0"); } else if (TransT == GN_Ucp437) { - fprintf(ESCOUT,"\033(U"); /* switch Linux console to 437 table? */ + /* + * Switch Linux console to 437 table? + */ + fprintf(ESCOUT, "\033(U"); } else if (TransT == GN_Kuser) { - fprintf(ESCOUT,"\033(K"); /* switch Linux console to user table */ + /* + * Switch Linux console to user table. + */ + fprintf(ESCOUT, "\033(K"); } if (TransT != GN_dunno && TransT != GN_dontCare) { lastTransT = TransT; @@ -200,13 +247,19 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(int, newcs, LYUCcharset *,p) if (p->enc == UCT_ENC_UTF8) { if (lastUtf != Is_Set) { Utf = Is_Set; - fprintf(ESCOUT,"\033%%G"); /* turn Linux console UTF8 mode ON */ + /* + * Turn Linux console UTF8 mode ON. + */ + fprintf(ESCOUT, "\033%%G"); lastUtf = Utf; } return; } else if (lastUtf == Is_Set && Utf != Dont_Care) { Utf = Is_Unset; - fprintf(ESCOUT,"\033%%@"); /* turn Linux console UTF8 mode OFF */ + /* + * Turn Linux console UTF8 mode OFF. + */ + fprintf(ESCOUT, "\033%%@"); lastUtf = Utf; } @@ -216,6 +269,33 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(int, newcs, LYUCcharset *,p) lastcs = newcs; lastname = name; } + +#else /* Not LINUX: */ +/* + * This is the thing that actually gets called from display_page(). + */ +PUBLIC void UCChangeTerminalCodepage ARGS2( + int, newcs, + LYUCcharset *, p) +{ + if (TRACE) { + fprintf(stderr, + "UCChangeTerminalCodepage: Called, but not implemented!"); + } +} #endif /* LINUX */ + +#else /* EXP_CHARTRANS_AUTOSWITCH not defined: */ +/* + * This is the thing that actually gets called from display_page(). + */ +PUBLIC void UCChangeTerminalCodepage ARGS2( + int, newcs, + LYUCcharset *, p) +{ + if (TRACE) { + fprintf(stderr, + "UCChangeTerminalCodepage: Called, but not implemented!"); + } +} #endif /* EXP_CHARTRANS_AUTOSWITCH */ -#endif /* EXP_CHARTRANS */ diff --git a/src/UCAuto.h b/src/UCAuto.h index 3f43e0c7..b4d582c3 100644 --- a/src/UCAuto.h +++ b/src/UCAuto.h @@ -1 +1,7 @@ -extern void UCChangeTerminalCodepage PARAMS((int newcs, LYUCcharset * p)); + +#ifndef UCAUTO_H +#define UCAUTO_H + +extern void UCChangeTerminalCodepage PARAMS((int newcs, LYUCcharset *p)); + +#endif /* UCAUTO_H */ diff --git a/src/UCAux.c b/src/UCAux.c index cca77ebc..db88bbcf 100644 --- a/src/UCAux.c +++ b/src/UCAux.c @@ -1,4 +1,3 @@ -#ifdef EXP_CHARTRANS #include "HTUtils.h" #include "tcp.h" @@ -10,7 +9,8 @@ extern HTCJKlang HTCJK; extern LYUCcharset LYCharSet_UC[]; -PUBLIC BOOL UCCanUniTranslateFrom ARGS1(int, from) +PUBLIC BOOL UCCanUniTranslateFrom ARGS1( + int, from) { if (from < 0) return NO; @@ -21,21 +21,24 @@ PUBLIC BOOL UCCanUniTranslateFrom ARGS1(int, from) return YES; return (LYCharSet_UC[from].UChndl >= 0); } -PUBLIC BOOL UCCanTranslateUniTo ARGS1(int, to) +PUBLIC BOOL UCCanTranslateUniTo ARGS1( + int, to) { if (to < 0) return NO; return YES; /* well at least some characters... */ } -PUBLIC BOOL UCCanTranslateFromTo ARGS2(int, from, int, to) +PUBLIC BOOL UCCanTranslateFromTo ARGS2( + int, from, + int, to) { - if (from==to) + if (from == to) return YES; if (from < 0 || to < 0) return NO; - if (from==0) + if (from == 0) return UCCanTranslateUniTo(to); - if (to==0) + if (to == 0) return UCCanUniTranslateFrom(from); if (LYCharSet_UC[to].enc == UCT_ENC_UTF8) { return (LYCharSet_UC[from].UChndl >= 0); @@ -43,61 +46,62 @@ PUBLIC BOOL UCCanTranslateFromTo ARGS2(int, from, int, to) { char * fromname = LYCharSet_UC[from].MIMEname; char * toname = LYCharSet_UC[to].MIMEname; - if (0==strcmp(fromname,"x-transparent") || - 0==strcmp(toname,"x-transparent")) { + if (!strcmp(fromname, "x-transparent") || + !strcmp(toname, "x-transparent")) { return YES; } if (LYCharSet_UC[from].enc == UCT_ENC_CJK) { if (HTCJK == NOCJK) /* use that global flag, for now */ return NO; - if (HTCJK == JAPANESE && ( - 0==strcmp(fromname,"euc-jp") || - 0==strncmp(fromname,"iso-2022-jp",11) || - 0==strcmp(fromname,"shift_jis") - )) + if (HTCJK == JAPANESE && + (!strcmp(fromname, "euc-jp") || + !strncmp(fromname, "iso-2022-jp",11) || + !strcmp(fromname, "shift_jis"))) return YES; - return NO; /* if not handled by (from==to) above */ + return NO; /* if not handled by (from == to) above */ } - if (0==strcmp(fromname,"koi8-r")) { - /* will try to uses stripping of high bit... */ + if (!strcmp(fromname, "koi8-r")) { + /* + * Will try to uses stripping of high bit... + */ return YES; } - if (0==strcmp(fromname,"koi8-r") || /* from cyrillic */ - 0==strcmp(fromname,"iso-8859-5") || - 0==strcmp(fromname,"koi-8")) { - if (0!=strcmp(toname,"iso-8859-5") && - 0!=strcmp(toname,"koi8-r") && - 0!=strcmp(toname,"iso-8859-2")) + if (!strcmp(fromname, "koi8-r") || /* from cyrillic */ + !strcmp(fromname, "iso-8859-5") || + !strcmp(fromname, "koi-8")) { + if (strcmp(toname, "iso-8859-5") && + strcmp(toname, "koi8-r") && + strcmp(toname, "iso-8859-2")) return NO; } } return (LYCharSet_UC[from].UChndl >= 0); } -/* The idea here is that any stage of the stream pipe which is interested -** in some charset dependent processing will call this function. -** Given input and ouptput charsets, this function will set various flags -** in a UCTransParams structure that _suggest_ to the caller what to do. -** -** Should be called once when a stage starts processing text (and the -** input and output charsets are known), or whenever one of input or -** output charsets has changed (e.g. by SGML.c stage after HTML.c stage -** has processed a META tag). -** The global flags (LYRawMode, HTPassEightBitRaw etc.) are currently -** not taken into account here, it's still up to the caller to do something -** about them. -*/ +/* + * The idea here is that any stage of the stream pipe which is interested + * in some charset dependent processing will call this function. + * Given input and ouptput charsets, this function will set various flags + * in a UCTransParams structure that _suggest_ to the caller what to do. + * + * Should be called once when a stage starts processing text (and the + * input and output charsets are known), or whenever one of input or + * output charsets has changed (e.g. by SGML.c stage after HTML.c stage + * has processed a META tag). + * The global flags (LYRawMode, HTPassEightBitRaw etc.) are currently + * not taken into account here, it's still up to the caller to do something + * about them. + */ PUBLIC void UCSetTransParams ARGS5( UCTransParams *, pT, int, cs_in, CONST LYUCcharset*, p_in, int, cs_out, - CONST LYUCcharset*, p_out - ) + CONST LYUCcharset*, p_out) { - pT->transp = (0==strcmp(p_in->MIMEname,"x-transparent") || - 0==strcmp(p_out->MIMEname,"x-transparent")); + pT->transp = (!strcmp(p_in->MIMEname, "x-transparent") || + !strcmp(p_out->MIMEname, "x-transparent")); if (pT->transp) { pT->do_cjk = FALSE; pT->decode_utf8 = FALSE; @@ -121,23 +125,21 @@ PUBLIC void UCSetTransParams ARGS5( pT->use_raw_char_in = FALSE; /* not used for CJK */ pT->trans_from_uni = FALSE; /* not used for CJK */ } else { - intm_ucs = ( - cs_in == 0 || pT->decode_utf8 || - (p_in->codepoints & (UCT_CP_SUBSETOF_LAT1|UCT_CP_SUBSETOF_UCS2)) - ); + intm_ucs = (cs_in == 0 || pT->decode_utf8 || + (p_in->codepoints & + (UCT_CP_SUBSETOF_LAT1|UCT_CP_SUBSETOF_UCS2))); pT->trans_to_uni = (!intm_ucs && UCCanUniTranslateFrom(cs_in)); - pT->strip_raw_char_in = - ((!intm_ucs || - (p_out->enc==UCT_ENC_7BIT) || - (p_out->repertoire & UCT_REP_SUBSETOF_LAT1)) && - cs_in != cs_out && - 0==strcmp(p_in->MIMEname,"koi8-r")); + pT->strip_raw_char_in = ((!intm_ucs || + (p_out->enc == UCT_ENC_7BIT) || + (p_out->repertoire & + UCT_REP_SUBSETOF_LAT1)) && + cs_in != cs_out && + !strcmp(p_in->MIMEname, "koi8-r")); use_ucs = (intm_ucs || pT->trans_to_uni); pT->do_8bitraw = (!use_ucs); pT->pass_160_173_raw = (!use_ucs && - !(p_in->like8859 & UCT_R_8859SPECL) - ); + !(p_in->like8859 & UCT_R_8859SPECL)); pT->use_raw_char_in = (!pT->output_utf8 && cs_in == cs_out); pT->trans_from_uni = (use_ucs && !pT->do_8bitraw && !pT->use_raw_char_in && @@ -149,46 +151,48 @@ PUBLIC void UCSetTransParams ARGS5( PUBLIC void UCTransParams_clear ARGS1( UCTransParams *, pT) { - pT->transp = FALSE; - pT->do_cjk = FALSE; - pT->decode_utf8 = FALSE; - pT->output_utf8 = FALSE; - pT->do_8bitraw = FALSE; - pT->use_raw_char_in = FALSE; - pT->strip_raw_char_in = FALSE; - pT->pass_160_173_raw = FALSE; - pT->trans_to_uni = FALSE; - pT->trans_from_uni = FALSE; + pT->transp = FALSE; + pT->do_cjk = FALSE; + pT->decode_utf8 = FALSE; + pT->output_utf8 = FALSE; + pT->do_8bitraw = FALSE; + pT->use_raw_char_in = FALSE; + pT->strip_raw_char_in = FALSE; + pT->pass_160_173_raw = FALSE; + pT->trans_to_uni = FALSE; + pT->trans_from_uni = FALSE; } -/* Given an output target HTStream* (can also be a HTStructured* via typecast), -** the target stream's put_character method, and a unicode character, -** CPutUtf8_charstring() will either output the UTF8 encoding of the unicode -** and return YES, or do nothing and return NO (if conversion would be -** unnecessary or the unicode character is considered invalid). -** -** [Could be used more generally, but is currently only used for &#nnnnn -** stuff - generation of UTF8 from 8-bit encoded charsets not yet done -** by SGML.c etc.] -*/ +/* + * Given an output target HTStream* (can also be a HTStructured* via + * typecast), the target stream's put_character method, and a unicode + * character, CPutUtf8_charstring() will either output the UTF8 + * encoding of the unicode and return YES, or do nothing and return + * NO (if conversion would be unnecessary or the unicode character is + * considered invalid). + * + * [Could be used more generally, but is currently only used for &#nnnnn + * stuff - generation of UTF8 from 8-bit encoded charsets not yet done + * by SGML.c etc.] + */ #define PUTC(ch) ((*myPutc)(target, (char)(ch))) #define PUTC2(ch) ((*myPutc)(target,(char)(0x80|(0x3f &(ch))))) PUBLIC BOOL UCPutUtf8_charstring ARGS3( - HTStream *, target, - putc_func_t *, myPutc, - long, code) + HTStream *, target, + putc_func_t *, myPutc, + long, code) { if (code < 128) return NO; /* indicate to caller we didn't handle it */ - else if (code < 0x800L) { + else if (code < 0x800L) { PUTC(0xc0 | (code>>6)); PUTC2(code); - } else if (code < 0x10000L) { + } else if (code < 0x10000L) { PUTC(0xe0 | (code>>12)); PUTC2(code>>6); PUTC2(code); - } else if (code < 0x200000L) { + } else if (code < 0x200000L) { PUTC(0xf0 | (code>>18)); PUTC2(code>>12); PUTC2(code>>6); @@ -199,7 +203,7 @@ PUBLIC BOOL UCPutUtf8_charstring ARGS3( PUTC2(code>>12); PUTC2(code>>6); PUTC2(code); - } else if (code<=0x7fffffffL) { + } else if (code <= 0x7fffffffL) { PUTC(0xfc | (code>>30)); PUTC2(code>>24); PUTC2(code>>18); @@ -210,4 +214,3 @@ PUBLIC BOOL UCPutUtf8_charstring ARGS3( return NO; return YES; } -#endif /* EXP_CHARTRANS */ diff --git a/src/UCdomap.c b/src/UCdomap.c index 473fe181..a443b7f4 100644 --- a/src/UCdomap.c +++ b/src/UCdomap.c @@ -1,32 +1,60 @@ /* * UCmap.c - * - K&R compatibility macros not (yet?) done - + * ======= * * Derived from code in the Linux kernel console driver. * The GNU Public Licence therefore applies, see * the file COPYING in the about_lynx directory * which should come with every Lynx distribution. * - * [ original comment: -kw ] + * [ original comment: - KW ] * * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code) * to font positions. * * aeb, 950210 */ - -#include "chrtrans/UCkd.h" +#include "HTUtils.h" #include "tcp.h" #include "HTMLDTD.h" -#include "HTAAUtil.h" /* defines FREE */ -#include "HTAtom.h" /* for use by UC_setup_LYCharSets_repl() */ + #include "LYGlobalDefs.h" -#include "LYCharSets.h" +#ifdef VMS +#include "[.chrtrans]UCkd.h" +#else +#include "chrtrans/UCkd.h" +#endif /* VMS */ #include "UCdomap.h" #include "UCMap.h" #include "UCDefs.h" +#include "LYCharSets.h" - /* Include hash tables & parameters */ +/* + * Include hash tables & parameters. + */ +#ifdef VMS +#include "[.chrtrans]def7_uni.h" +#include "[.chrtrans]iso01_uni.h" +#include "[.chrtrans]iso02_uni.h" +#include "[.chrtrans]iso03_uni.h" +#include "[.chrtrans]iso04_uni.h" +#include "[.chrtrans]iso05_uni.h" +#include "[.chrtrans]iso07_uni.h" +#include "[.chrtrans]iso09_uni.h" +#include "[.chrtrans]iso10_uni.h" +#include "[.chrtrans]koi8r_uni.h" +#include "[.chrtrans]cp437_uni.h" +#include "[.chrtrans]cp850_uni.h" +#include "[.chrtrans]cp852_uni.h" +#include "[.chrtrans]cp1250_uni.h" +#include "[.chrtrans]cp1252_uni.h" +#include "[.chrtrans]utf8_uni.h" +#include "[.chrtrans]rfc_suni.h" +#include "[.chrtrans]mnemonic_suni.h" +#ifdef NOTDEFINED +#include "[.chrtrans]mnem_suni.h" +#endif /* NOTDEFINED */ +#else #include "chrtrans/def7_uni.h" #include "chrtrans/iso01_uni.h" #include "chrtrans/iso02_uni.h" @@ -45,17 +73,26 @@ #include "chrtrans/utf8_uni.h" #include "chrtrans/rfc_suni.h" #include "chrtrans/mnemonic_suni.h" -/* #include "chrtrans/mnem_suni.h" */ +#ifdef NOTDEFINED +#include "chrtrans/mnem_suni.h" +#endif /* NOTDEFINED */ +#endif /* VMS */ -/* Some of the code below, and some of the comments, left in for - historical reasons. Not all those tables below are currently - really needed (and what with all those hardwired codepoints), - but let's keep them around for now, they may come in handy if we - decide to make more extended use of the mechanisms (including e.g. - for chars < 127...) - kw */ +#define FREE(x) if (x) {free(x); x = NULL;} -static u16 translations[][256] = { - /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ +/* + * Some of the code below, and some of the comments, are left in for + * historical reasons. Not all those tables below are currently + * really needed (and what with all those hardwired codepoints), + * but let's keep them around for now. They may come in handy if we + * decide to make more extended use of the mechanisms (including e.g. + * for chars < 127...). - KW + */ + +PRIVATE u16 translations[][256] = { + /* + * 8-bit Latin-1 mapped to Unicode -- trivial mapping. + */ { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, @@ -90,7 +127,9 @@ static u16 translations[][256] = { 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff }, - /* VT100 graphics mapped to Unicode */ + /* + * VT100 graphics mapped to Unicode. + */ { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, @@ -125,7 +164,9 @@ static u16 translations[][256] = { 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff }, - /* IBM Codepage 437 mapped to Unicode */ + /* + * IBM Codepage 437 mapped to Unicode. + */ { 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c, @@ -160,7 +201,9 @@ static u16 translations[][256] = { 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }, - /* User mapping -- default to codes for direct font mapping */ + /* + * User mapping -- default to codes for direct font mapping. + */ { 0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007, 0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f, @@ -203,13 +246,80 @@ static u16 *UC_translate = NULL; #define MAX_GLYPH 512 /* Max possible glyph value */ -static unsigned char * inv_translate = NULL; -static unsigned char inv_norm_transl[MAX_GLYPH]; -static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL }; +PRIVATE unsigned char * inv_translate = NULL; +PRIVATE unsigned char inv_norm_transl[MAX_GLYPH]; +PRIVATE unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL }; +PRIVATE void set_inverse_transl PARAMS(( + int i)); +PRIVATE u16 *set_translate PARAMS(( + int m)); +#ifdef NOTDEFINED +PRIVATE unsigned char inverse_translate PARAMS((int glyph)); +PRIVATE int con_set_trans_old PARAMS((unsigned char *arg)); +PRIVATE int con_get_trans_old PARAMS((unsigned char *arg)); +PRIVATE int con_set_trans_new PARAMS((u16 *arg)); +PRIVATE int con_get_trans_new PARAMS((u16 *arg)); +#endif /* NOTDEFINED */ +PRIVATE int UC_valid_UC_charset PARAMS(( + int UC_charset_hndl)); +PRIVATE void UC_con_set_trans PARAMS(( + int UC_charset_in_hndl, + int Gn, + int update_flag)); +PRIVATE int con_insert_unipair PARAMS(( + u16 unicode, + u16 fontpos)); +PRIVATE int con_insert_unipair_str PARAMS(( + u16 unicode, + char * replace_str)); PRIVATE void con_clear_unimap NOPARAMS; - -PRIVATE void set_inverse_transl ARGS1(int, i) +PRIVATE void con_clear_unimap_str NOPARAMS; +#ifdef NOTDEFINED +PRIVATE int con_set_unimap PARAMS(( + u16 ct, + struct unipair * list)); +#endif /* NOTDEFINED */ +PRIVATE void con_set_default_unimap NOPARAMS; +PRIVATE int UC_con_set_unimap PARAMS(( + int UC_charset_out_hndl, + int update_flag)); +PRIVATE int UC_con_set_unimap_str PARAMS(( + u16 ct, + struct unipair_str * list)); +#ifdef NOTDEFINED +PRIVATE int con_get_unimap PARAMS(( + u16 ct, + u16 * uct, + struct unipair * list)); +#endif /* NOTDEFINED */ +PRIVATE int conv_uni_to_pc PARAMS(( + long ucs)); +PRIVATE int conv_uni_to_str PARAMS(( + char* outbuf, + int buflen, + long ucs)); +PRIVATE void UCconsole_map_init NOPARAMS; +PRIVATE int UC_MapGN PARAMS(( + int UChndl, + int update_flag)); +PRIVATE int UC_FindGN_byMIME PARAMS(( + char * UC_MIMEcharset)); +PRIVATE void UCreset_allocated_LYCharSets NOPARAMS; +PRIVATE void UCfree_allocated_LYCharSets NOPARAMS; +PRIVATE char ** UC_setup_LYCharSets_repl PARAMS(( + int UC_charset_in_hndl, + int lowest8)); +PRIVATE int UC_Register_with_LYCharSets PARAMS(( + int s, + char * UC_MIMEcharset, + char * UC_LYNXcharset, + int lowest_eightbit)); +PRIVATE void UCcleanup_mem NOPARAMS; + + +PRIVATE void set_inverse_transl ARGS1( + int, i) { int j, glyph; u16 *p = translations[i]; @@ -235,7 +345,7 @@ PRIVATE void set_inverse_transl ARGS1(int, i) } } -u16 *set_translate ARGS1(int, m) +PRIVATE u16 *set_translate ARGS1(int, m) { if (!inverse_translations[m]) set_inverse_transl(m); @@ -251,13 +361,16 @@ u16 *set_translate ARGS1(int, m) * was active, or using Unicode. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ -unsigned char inverse_translate(int glyph) { - if ( glyph < 0 || glyph >= MAX_GLYPH ) +PRIVATE unsigned char inverse_translate ARGS1( + int, glyph) +{ + if (glyph < 0 || glyph >= MAX_GLYPH) { return 0; - else - return ((inv_translate && inv_translate[glyph]) - ? inv_translate[glyph] - : (unsigned char)(glyph & 0xff)); + } else { + return ((inv_translate && inv_translate[glyph]) ? + inv_translate[glyph] : + (unsigned char)(glyph & 0xff)); + } } /* @@ -302,7 +415,8 @@ int con_get_trans_old(unsigned char * arg) return 0; } -int con_set_trans_new(u16 * arg) +PRIVATE int con_set_trans_new ARGS1( + u16 *, arg) { int i; u16 *p = translations[USER_MAP]; @@ -319,7 +433,8 @@ int con_set_trans_new(u16 * arg) return 0; } -int con_get_trans_new(u16 * arg) +PRIVATE int con_get_trans_new ARGS1( + u16 * arg) { int i; u16 *p = translations[USER_MAP]; @@ -336,22 +451,22 @@ int con_get_trans_new(u16 * arg) } #endif /* NOTDEFINED */ - -PRIVATE int -UC_valid_UC_charset ARGS1(int, UC_charset_hndl) +PRIVATE int UC_valid_UC_charset ARGS1( + int, UC_charset_hndl) { return (UC_charset_hndl >= 0 && UC_charset_hndl < UCNumCharsets); } -PRIVATE void -UC_con_set_trans ARGS3(int, UC_charset_in_hndl, int, Gn, int, update_flag) +PRIVATE void UC_con_set_trans ARGS3( + int, UC_charset_in_hndl, + int, Gn, + int, update_flag) { int i, j; u16 *p; u16 *ptrans; - if (!UC_valid_UC_charset(UC_charset_in_hndl)) - { + if (!UC_valid_UC_charset(UC_charset_in_hndl)) { if (TRACE) fprintf(stderr,"UC_con_set_trans: Invalid charset handle %i.\n", UC_charset_in_hndl); @@ -363,23 +478,26 @@ UC_con_set_trans ARGS3(int, UC_charset_in_hndl, int, Gn, int, update_flag) if (p == UC_current_unitable) { /* test whether pointers are equal */ return; /* nothing to be done */ } - /* The font is always 256 characters - so far. */ - + /* + * The font is always 256 characters - so far. + */ con_clear_unimap(); #endif - for ( i = 0 ; i < 256 ; i++ ) - { + for (i = 0; i < 256; i++) { if ((j = UCInfo[UC_charset_in_hndl].unicount[i])) { ptrans[i] = *p; - for ( ; j ; j-- ) + for (; j; j--) { p++; } - else + } else { ptrans[i] = 0xfffd; } - if (update_flag) + } + if (update_flag) { set_inverse_transl(Gn); /* Update inverse translation for this one */ } +} + /* * Unicode -> current font conversion * @@ -408,11 +526,12 @@ static char* **uni_pagedir_str[32] = NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -u16 * UC_current_unitable = NULL; -struct unimapdesc_str *UC_current_unitable_str = NULL; +PRIVATE u16 * UC_current_unitable = NULL; +PRIVATE struct unimapdesc_str *UC_current_unitable_str = NULL; -PRIVATE int -con_insert_unipair ARGS2(u16, unicode, u16, fontpos) +PRIVATE int con_insert_unipair ARGS2( + u16, unicode, + u16, fontpos) { int i, n; u16 **p1, *p2; @@ -442,8 +561,9 @@ con_insert_unipair ARGS2(u16, unicode, u16, fontpos) return 0; } -PRIVATE int -con_insert_unipair_str ARGS2(u16, unicode, char *, replace_str) +PRIVATE int con_insert_unipair_str ARGS2( + u16, unicode, + char *, replace_str) { int i, n; char ***p1, **p2; @@ -480,16 +600,12 @@ con_clear_unimap NOARGS int i, j; u16 **p1; - for ( i = 0 ; i < 32 ; i++ ) - { - if ( (p1 = uni_pagedir[i]) != NULL ) - { - for ( j = 0 ; j < 32 ; j++ ) - { - if ( p1[j] ) - free(p1[j]); + for (i = 0; i < 32; i++) { + if ((p1 = uni_pagedir[i]) != NULL) { + for (j = 0; j < 32; j++) { + FREE(p1[j]); } - free(p1); + FREE(p1); } uni_pagedir[i] = NULL; } @@ -503,16 +619,12 @@ con_clear_unimap_str NOARGS int i, j; char ***p1; - for ( i = 0 ; i < 32 ; i++ ) - { - if ( (p1 = uni_pagedir_str[i]) != NULL ) - { - for ( j = 0 ; j < 32 ; j++ ) - { - if ( p1[j] ) - free(p1[j]); + for (i = 0; i < 32; i++) { + if ((p1 = uni_pagedir_str[i]) != NULL) { + for (j = 0; j < 32; j++) { + FREE(p1[j]); } - free(p1); + FREE(p1); } uni_pagedir_str[i] = NULL; } @@ -574,14 +686,14 @@ PUBLIC int UCLYhndl_HTFile_for_unrec = -1; PUBLIC int UCLYhndl_for_unspec = -1; PUBLIC int UCLYhndl_for_unrec = -1; -PRIVATE int -UC_con_set_unimap ARGS2(int, UC_charset_out_hndl, int, update_flag) +PRIVATE int UC_con_set_unimap ARGS2( + int, UC_charset_out_hndl, + int, update_flag) { int i, j; u16 *p; - if (!UC_valid_UC_charset(UC_charset_out_hndl)) - { + if (!UC_valid_UC_charset(UC_charset_out_hndl)) { if (TRACE) fprintf(stderr,"UC_con_set_unimap: Invalid charset handle %i.\n", UC_charset_out_hndl); @@ -598,9 +710,11 @@ UC_con_set_unimap ARGS2(int, UC_charset_out_hndl, int, update_flag) con_clear_unimap(); - for ( i = 0 ; i < 256 ; i++ ) - for ( j = UCInfo[UC_charset_out_hndl].unicount[i] ; j ; j-- ) + for (i = 0; i < 256; i++) { + for (j = UCInfo[UC_charset_out_hndl].unicount[i]; j; j--) { con_insert_unipair(*(p++), i); + } + } if (update_flag) for ( i = 0 ; i <= 3 ; i++ ) @@ -621,8 +735,13 @@ UC_con_set_unimap_str ARGS2(u16, ct, struct unipair_str *, list) list++; } - /* No inverse translations for replacement strings! */ - if (!err) hashtable_str_contents_valid = 1; + /* + * No inverse translations for replacement strings! + */ + if (!err) { + hashtable_str_contents_valid = 1; + } + return err; } @@ -656,8 +775,8 @@ con_get_unimap ARGS3(u16, ct, u16 *, uct, struct unipair *, list) } #endif -int -conv_uni_to_pc ARGS1(long, ucs) +PRIVATE int conv_uni_to_pc ARGS1( + long, ucs) { int h; u16 **p1, *p2; @@ -688,9 +807,13 @@ conv_uni_to_pc ARGS1(long, ucs) return -4; /* not found */ } -/* Note: contents of outbuf is not changes for negative return value! */ -PRIVATE int -conv_uni_to_str ARGS3(char*, outbuf, int, buflen, long, ucs) +/* + * Note: contents of outbuf is not changes for negative return value! + */ +PRIVATE int conv_uni_to_str ARGS3( + char*, outbuf, + int, buflen, + long, ucs) { char *h; char ***p1, **p2; @@ -722,12 +845,16 @@ conv_uni_to_str ARGS3(char*, outbuf, int, buflen, long, ucs) strncpy (outbuf,h,(size_t) (buflen-1)); return 1; /* ok ! */ } - return -4; /* not found */ + + /* + * Not found. + */ + return -4; } PUBLIC int UCInitialized = 0; /* - * [ original comment: - kw ] + * [ original comment: - KW ] * This is called at sys_setup time, after memory and the console are * initialized. It must be possible to call kmalloc(..., GFP_KERNEL) * from this function, hence the call from sys_setup. @@ -739,12 +866,17 @@ UCconsole_map_init NOARGS UCInitialized = 1; } -/* OK now, finally, some stuff that is more specifically for Lynx: - kw */ - +/* + * OK now, finally, some stuff that is more specifically for Lynx: - KW + */ +#ifdef NOTDEFINED PUBLIC int UCGetcharset_byMIMEname PARAMS((char * UC_MIMEcharset)); PUBLIC int UCGetcharset_byLYNXname PARAMS((char * UC_LYNXcharset)); +#endif /* NOTDEFINED */ -PUBLIC int UCTransUniChar ARGS2(long, unicode, int, charset_out) +PUBLIC int UCTransUniChar ARGS2( + long, unicode, + int, charset_out) { int rc; int UChndl_out; @@ -756,18 +888,25 @@ PUBLIC int UCTransUniChar ARGS2(long, unicode, int, charset_out) ut = UCInfo[UChndl_out].unitable; if (ut != UC_current_unitable) { rc = UC_con_set_unimap(UChndl_out, 1); - if (rc < 0) + if (rc < 0) { return rc; } + } rc = conv_uni_to_pc(unicode); if (rc == -4) rc = conv_uni_to_pc(0xfffd); return rc; } -/* returns string length, or negative value for error. */ -PUBLIC int UCTransUniCharStr ARGS5(char *, outbuf, int, buflen, long, unicode, - int, charset_out, int, chk_single_flag) +/* + * Returns string length, or negative value for error. + */ +PUBLIC int UCTransUniCharStr ARGS5( + char *, outbuf, + int, buflen, + long, unicode, + int, charset_out, + int, chk_single_flag) { int rc, src = 0, ignore_err; int UChndl_out; @@ -784,13 +923,15 @@ if (buflen<2) ut = UCInfo[UChndl_out].unitable; if (ut != UC_current_unitable) { src = UC_con_set_unimap(UChndl_out, 1); - if (src < 0) + if (src < 0) { return src; } + } src = conv_uni_to_pc(unicode); if (src >= 32) { outbuf[0] = src; outbuf[1] = '\0'; - return 1; } + return 1; + } } repl = &(UCInfo[UChndl_out].replacedesc); @@ -809,34 +950,41 @@ if (buflen<2) rc = conv_uni_to_pc(0xfffd); if (rc >= 32) { outbuf[0] = rc; outbuf[1] = '\0'; - return 1; } - else return rc; + return 1; + } + return rc; } return -4; } -int UC_lastautoGN = 0; +PRIVATE int UC_lastautoGN = 0; -PRIVATE int UC_MapGN ARGS2(int, UChndl, int, update_flag) +PRIVATE int UC_MapGN ARGS2( + int, UChndl, + int, update_flag) { int i,Gn,found,lasthndl; found = 0; Gn = -1; for (i=0; i<4 && Gn<0; i++) { - if (UC_GNhandles[i] < 0) + if (UC_GNhandles[i] < 0) { + Gn = i; + } else if (UC_GNhandles[i] == UChndl) { Gn = i; - else if (UC_GNhandles[i] == UChndl) - {Gn = i; found = 1;} + found = 1; } - if (found) return Gn; + } + if (found) + return Gn; if (Gn >= 0) { UCInfo[UChndl].GN = Gn; UC_GNhandles[Gn] = UChndl; - } - else { - if (UC_lastautoGN == GRAF_MAP) + } else { + if (UC_lastautoGN == GRAF_MAP) { Gn = IBMPC_MAP; - else Gn = GRAF_MAP; + } else { + Gn = GRAF_MAP; + } UC_lastautoGN = Gn; lasthndl = UC_GNhandles[Gn]; UCInfo[lasthndl].GN = -1; @@ -847,7 +995,10 @@ PRIVATE int UC_MapGN ARGS2(int, UChndl, int, update_flag) return Gn; } -PUBLIC int UCTransChar ARGS3(char, ch_in, int, charset_in, int, charset_out) +PUBLIC int UCTransChar ARGS3( + char, ch_in, + int, charset_in, + int, charset_out) { int unicode, Gn; int rc; @@ -858,27 +1009,33 @@ PUBLIC int UCTransChar ARGS3(char, ch_in, int, charset_in, int, charset_out) #ifndef UC_NO_SHORTCUTS if (charset_in == charset_out) return (unsigned char)ch_in; -#endif - if (charset_in < 0) return -11; +#endif /* UC_NO_SHORTCUTS */ + if (charset_in < 0) + return -11; if ((UChndl_in = LYCharSet_UC[charset_in].UChndl) < 0) return -11; if ((UChndl_out = LYCharSet_UC[charset_out].UChndl) < 0) return -12; if (!UCInfo[UChndl_in].num_uni) return -11; - if ((Gn = UCInfo[UChndl_in].GN) < 0) - {Gn = UC_MapGN(UChndl_in,0); upd = 1;} + if ((Gn = UCInfo[UChndl_in].GN) < 0) { + Gn = UC_MapGN(UChndl_in,0); + upd = 1; + } ut = UCInfo[UChndl_out].unitable; - if (ut == UC_current_unitable) - {if (upd) set_inverse_transl(Gn);} - else { + if (ut == UC_current_unitable) { + if (upd) { + set_inverse_transl(Gn); + } + } else { rc = UC_con_set_unimap(UChndl_out, 1); - if (rc > 0) + if (rc > 0) { set_inverse_transl(Gn); - else if (rc < 0) + } else if (rc < 0) { return rc; } + } UC_translate = set_translate(Gn); unicode = UC_translate[(unsigned char)ch_in]; rc = conv_uni_to_pc(unicode); @@ -887,7 +1044,9 @@ PUBLIC int UCTransChar ARGS3(char, ch_in, int, charset_in, int, charset_out) return rc; } -PUBLIC long int UCTransToUni ARGS2(char, ch_in, int, charset_in) +PUBLIC long int UCTransToUni ARGS2( + char, ch_in, + int, charset_in) { int unicode, Gn; unsigned char ch_iu; @@ -899,14 +1058,16 @@ PUBLIC long int UCTransToUni ARGS2(char, ch_in, int, charset_in) return ch_iu; if ((unsigned char)ch_in < 128) return ch_iu; -#endif - if (charset_in < 0) return -11; +#endif /* UC_NO_SHORTCUTS */ + if (charset_in < 0) + return -11; if ((UChndl_in = LYCharSet_UC[charset_in].UChndl) < 0) return -11; if (!UCInfo[UChndl_in].num_uni) return -11; - if ((Gn = UCInfo[UChndl_in].GN) < 0) - {Gn = UC_MapGN(UChndl_in,1);} + if ((Gn = UCInfo[UChndl_in].GN) < 0) { + Gn = UC_MapGN(UChndl_in,1); + } UC_translate = set_translate(Gn); unicode = UC_translate[(unsigned char)ch_in]; @@ -925,11 +1086,13 @@ PUBLIC int UCReverseTransChar ARGS3(char, ch_out, int, charset_in, int, charset_ #ifndef UC_NO_SHORTCUTS if (charset_in == charset_out) return ch_out; -#endif - if (charset_in < 0) return -11; +#endif /* UC_NO_SHORTCUTS */ + if (charset_in < 0) + return -11; if ((UChndl_in = LYCharSet_UC[charset_in].UChndl) < 0) return -11; - if (charset_out < 0) return -12; + if (charset_out < 0) + return -12; if ((UChndl_out = LYCharSet_UC[charset_out].UChndl) < 0) return -12; if (!UCInfo[UChndl_in].num_uni) @@ -940,23 +1103,32 @@ PUBLIC int UCReverseTransChar ARGS3(char, ch_out, int, charset_in, int, charset_ if ((Gn = UCInfo[UChndl_in].GN) >= 0) { UC_translate = set_translate(Gn); rc = inv_translate[(unsigned int)ch_out]; - if (rc >= 32) return rc; + if (rc >= 32) { + return rc; } - else { + } else { Gn = UC_MapGN(UChndl_in,1); UC_translate = set_translate(Gn); rc = inv_translate[(unsigned int)ch_out]; - if (rc >= 32) return rc; + if (rc >= 32) { + return rc; + } } } return UCTransChar(ch_out, charset_out, charset_in); } -#endif - -/* returns string length, or negative value for error. */ +#endif /* UNUSED */ -PUBLIC int UCTransCharStr ARGS6(char *, outbuf, int, buflen, char, ch_in, - int, charset_in, int, charset_out, int, chk_single_flag) +/* + * Returns string length, or negative value for error. + */ +PUBLIC int UCTransCharStr ARGS6( + char *, outbuf, + int, buflen, + char, ch_in, + int, charset_in, + int, charset_out, + int, chk_single_flag) { int unicode, Gn; int rc, src = 0, ignore_err; @@ -969,10 +1141,13 @@ if (buflen<2) return -13; #ifndef UC_NO_SHORTCUTS if (chk_single_flag && charset_in == charset_out) { - outbuf[0] = ch_in; outbuf[1] = '\0'; - return 1; } -#endif - if (charset_in < 0) return -11; + outbuf[0] = ch_in; + outbuf[1] = '\0'; + return 1; + } +#endif /* UC_NO_SHORTCUTS */ + if (charset_in < 0) + return -11; if ((UChndl_in = LYCharSet_UC[charset_in].UChndl) < 0) return -11; if ((UChndl_out = LYCharSet_UC[charset_out].UChndl) < 0) @@ -987,19 +1162,21 @@ if (buflen<2) if (chk_single_flag) { ut = UCInfo[UChndl_out].unitable; - if (ut == UC_current_unitable) - {if (upd) set_inverse_transl(Gn);} - else { + if (ut == UC_current_unitable) { + if (upd) set_inverse_transl(Gn); + } else { src = UC_con_set_unimap(UChndl_out, 1); - if (src > 0) + if (src > 0) { set_inverse_transl(Gn); - else if (src < 0) + } else if (src < 0) { return src; } + } src = conv_uni_to_pc(unicode); if (src >= 32) { outbuf[0] = src; outbuf[1] = '\0'; - return 1; } + return 1; + } } repl = &(UCInfo[UChndl_out].replacedesc); @@ -1018,97 +1195,124 @@ if (buflen<2) rc = conv_uni_to_pc(0xfffd); if (rc >= 32) { outbuf[0] = rc; outbuf[1] = '\0'; - return 1; } - else return rc; + return 1; + } else { + return rc; + } } return -4; } -PRIVATE int UC_FindGN_byMIME ARGS1(char *, UC_MIMEcharset) +PRIVATE int UC_FindGN_byMIME ARGS1( + char *, UC_MIMEcharset) { int i; - for (i=0; i<4; i++) - if (!strcmp(UC_MIMEcharset,UC_GNsetMIMEnames[i])) + + for (i = 0; i < 4; i++) { + if (!strcmp(UC_MIMEcharset,UC_GNsetMIMEnames[i])) { return i; + } + } return -1; } -PUBLIC int UCGetRawUniMode_byLYhndl ARGS1(int, i) +PUBLIC int UCGetRawUniMode_byLYhndl ARGS1( + int, i) { - if(i < 0) return 0; + if (i < 0) + return 0; return LYCharSet_UC[i].enc; } -/* Currently the charset name has to match exactly -- not substring - matching as was done before (see HTMIME.c, HTML.c). */ -PUBLIC int UCGetLYhndl_byMIME ARGS1(CONST char *,UC_MIMEcharset) +/* + * Currently the charset name has to match exactly -- not substring + * matching as was done before (see HTMIME.c, HTML.c). + */ +PUBLIC int UCGetLYhndl_byMIME ARGS1( + CONST char *, UC_MIMEcharset) { int i; int LYhndl = -1; - if (!UC_MIMEcharset || !(*UC_MIMEcharset)) return -1; + if (!UC_MIMEcharset || !(*UC_MIMEcharset)) + return -1; - for (i=0; i<MAX_CHARSETS && i<LYNumCharsets && - LYchar_set_names[i] && LYhndl<0; i++) + for (i = 0; + (i < MAXCHARSETS && i < LYNumCharsets && + LYchar_set_names[i] && LYhndl < 0); i++) { if (LYCharSet_UC[i].MIMEname && !strcmp(UC_MIMEcharset,LYCharSet_UC[i].MIMEname)) { LYhndl = i; } - if (LYhndl < 0) { /* not yet found, special treatment - for several CJK charsets etc... cheating here - Also recognize UTF-8 as synonym for UNICODE-1-1-UTF-8 - (The example file for now still uses the long name, - so that's what will be used internally.) */ - if (0==strcmp(UC_MIMEcharset, "utf-8")) + } + if (LYhndl < 0) { + /* + * Not yet found, special treatment for several CJK charsets etc... + * Cheating here. Also recognize UTF-8 as synonym for + * UNICODE-1-1-UTF-8 (The example file for now still uses the + * long name, so that's what will be used internally.). + */ + if (!strcmp(UC_MIMEcharset, "utf-8")) { return UCGetLYhndl_byMIME("unicode-1-1-utf-8"); - if (0==strncmp(UC_MIMEcharset, "iso-2022-jp", 11)) + } + if (!strncmp(UC_MIMEcharset, "iso-2022-jp", 11)) { return UCGetLYhndl_byMIME("euc-jp"); - else if (0==strcmp(UC_MIMEcharset, "euc-kr")) + } else if (!strcmp(UC_MIMEcharset, "euc-kr")) { return UCGetLYhndl_byMIME("iso-2022-kr"); - else if (0==strcmp(UC_MIMEcharset, "gb2312")) + } else if (!strcmp(UC_MIMEcharset, "gb2312")) { return UCGetLYhndl_byMIME("iso-2022-cn"); - else if (0==strcmp(UC_MIMEcharset, "euc-cn")) + } else if (!strcmp(UC_MIMEcharset, "euc-cn")) { return UCGetLYhndl_byMIME("iso-2022-cn"); - else if (0==strcmp(UC_MIMEcharset, "koi-8")) /* accentsoft bogosity */ + } else if (!strcmp(UC_MIMEcharset, "koi-8")) { /* accentsoft bogosity */ return UCGetLYhndl_byMIME("koi8-r"); } + } return LYhndl; /* returns -1 if no charset found by that MIME name */ } -/* function UC_setup_LYCharSets_repl() tries to set up a subtable in - LYCharSets[] appropriate for this new charset, for compatibility - with the "old method". Maybe not nice (maybe not evene necessary - any more), but it works (as far as it goes..). - - We try to be conservative and only allocate new memory for this - if needed. If not needed, just point to SevenBitApproximations[i]. - [Could do the same for ISO_Latin1[] if it's identical to that, but - would make it even *more* messy than it already is...] - This the only function in this file that knows, or cares, about the - HTMLDTD or details of LYCharSets[] subtables (and therefore somewhat - violates the idea that this file should be independent of those). - As in other places, we rely on ISO_Latin1 being the *first* table - in LYCharSets. - kw */ +/* + * Function UC_setup_LYCharSets_repl() tries to set up a subtable in + * LYCharSets[] appropriate for this new charset, for compatibility + * with the "old method". Maybe not nice (maybe not evene necessary + * any more), but it works (as far as it goes..). + * + * We try to be conservative and only allocate new memory for this + * if needed. If not needed, just point to SevenBitApproximations[i]. + * [Could do the same for ISO_Latin1[] if it's identical to that, but + * would make it even *more* messy than it already is...] + * This the only function in this file that knows, or cares, about the + * HTMLDTD or details of LYCharSets[] subtables (and therefore somewhat + * violates the idea that this file should be independent of those). + * As in other places, we rely on ISO_Latin1 being the *first* table + * in LYCharSets. - KW + */ -/* We need to remember which ones were allocated and which are static.*/ -static char** remember_allocated_LYCharSets[MAX_CHARSETS]; +/* + * We need to remember which ones were allocated and which are static. + */ +PRIVATE char ** remember_allocated_LYCharSets[MAXCHARSETS]; PRIVATE void UCreset_allocated_LYCharSets NOARGS { int i=0; - for(;i<MAX_CHARSETS;i++) + for(;i<MAXCHARSETS;i++) remember_allocated_LYCharSets[i]=NULL; } PRIVATE void UCfree_allocated_LYCharSets NOARGS { int i=0; - for(;i<MAX_CHARSETS;i++) - if(remember_allocated_LYCharSets[i]!=NULL) + + for (; i < MAXCHARSETS; i++) { + if (remember_allocated_LYCharSets[i] != NULL) { FREE(remember_allocated_LYCharSets[i]); } + } +} -PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, lowest8) +PRIVATE char ** UC_setup_LYCharSets_repl ARGS2( + int, UC_charset_in_hndl, + int, lowest8) { char ** ISO_Latin1 = LYCharSets[0]; char **p; @@ -1120,7 +1324,10 @@ PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, low int i,j,changed; u16 k; u8 *ti; - /* create a temporary table for reverse lookup of latin1 codes: */ + + /* + * Create a temporary table for reverse lookup of latin1 codes: + */ tp = (char **) malloc(96 * sizeof(char *)); if (!tp) return NULL; for (i=0; i<96; i++) @@ -1135,75 +1342,97 @@ PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, low pp = UCInfo[UC_charset_in_hndl].unitable; - /* Determine if we have any mapping of a Unicode in the range 160-255 - to an allowed code point > 0x80 in our new charset... - Store any mappings found in ti[]. */ - if (UCInfo[UC_charset_in_hndl].num_uni > 0) - for ( i = 0 ; i < 256 ; i++ ) - { + /* + * Determine if we have any mapping of a Unicode in the range 160-255 + * to an allowed code point > 0x80 in our new charset... + * Store any mappings found in ti[]. + */ + if (UCInfo[UC_charset_in_hndl].num_uni > 0) { + for (i = 0; i < 256; i++) { if ((j = UCInfo[UC_charset_in_hndl].unicount[i])) { if ((k = *pp) >= 160 && k < 256 && i >= lowest8) { ti[k-160] = i; } - for ( ; j ; j-- ) + for (; j; j--) { pp++; } } + } + } { u16 ct; struct unipair_str *list; - /* Determine if we have any mapping of a Unicode in the range 160-255 - to a replacement string for our new charset... - Store any mappings found in tp[]. */ + /* + * Determine if we have any mapping of a Unicode in the range + * 160-255 to a replacement string for our new charset... + * Store any mappings found in tp[]. + */ ct = UCInfo[UC_charset_in_hndl].replacedesc.entry_ct; list = UCInfo[UC_charset_in_hndl].replacedesc.entries; - while( ct-- ) - { + while (ct--) { if ((k = list->unicode) >= 160 && k < 256) { tp[k-160] = list->replace_str; } list++; } } - /* Now allocate a new table compatible with LYCharSets[] - and with the HTMLDTD for entitied. - We don't know yet whether we'll keep it around. */ + /* + * Now allocate a new table compatible with LYCharSets[] + * and with the HTMLDTD for entitied. + * We don't know yet whether we'll keep it around. */ p = prepl = (char **) malloc(HTML_dtd.number_of_entities * sizeof(char *)); if (!p) { - FREE(tp); FREE(ti); + FREE(tp); + FREE(ti); return NULL; } changed = 0; for (i=0; i<HTML_dtd.number_of_entities; i++,p++) { - /* For each of those entities, we check what the "old method" - ISO_Latin1[] mapping does with them. If it is nothing we - want to use, just point to the SevenBitApproximations[] string. */ + /* + * For each of those entities, we check what the "old method" + * ISO_Latin1[] mapping does with them. If it is nothing we + * want to use, just point to the SevenBitApproximations[] string. + */ s7 = SevenBitApproximations[i]; s8 = ISO_Latin1[i]; *p = s7; if (s8 && (unsigned char)(*s8) >= 160 && strlen(s8) == 1) { - /* We have an entity that is mapped to one valid eightbit latin1 char*/ + /* + * We have an entity that is mapped to + * one valid eightbit latin1 char. + */ if (ti[(unsigned char)(*s8) - 160] >= lowest8 && - !(s7[0] == ti[(unsigned char)(*s8) - 160] && s7[1] == '\0')) { - /* ...which in turn is mapped, by our "new method", to another - valid eightbit char for this new charset: either to itself... */ - if (ti[(unsigned char)(*s8) - 160] == (unsigned char)(*s8)) + !(s7[0] == ti[(unsigned char)(*s8) - 160] && + s7[1] == '\0')) { + /* + * ...which in turn is mapped, by our "new method", + * to another valid eightbit char for this new + * charset: either to itself... + */ + if (ti[(unsigned char)(*s8) - 160] == (unsigned char)(*s8)) { *p = s8; - else { - /* ...or another byte... */ + } else { + /* + * ...or another byte... + */ #ifdef NOTDEFINED *p = (char *)malloc(2*sizeof(char)); if (!*p) { - FREE(tp); FREE(ti); FREE(prepl); + FREE(tp); + FREE(ti); + FREE(prepl); return NULL; } (*p)[0] = ti[(unsigned char)(*s8) - 160]; (*p)[1] = '\0'; #else - /* use this instead... make those buggers int HTAtoms, so - they will be cleaned up at exit... all for the sake of - preventing memory leaks, sigh */ + /* + * Use this instead... make those buggers + * int HTAtoms, so they will be cleaned up + * at exit... all for the sake of preventing + * memory leaks, sigh. + */ static char dummy[2]; /* one char dummy string */ dummy[0] = ti[(unsigned char)(*s8) - 160]; @@ -1211,11 +1440,12 @@ PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, low #endif /* ! NOTDEFINED */ } changed = 1; - } - else if (tp[(unsigned char)(*s8) - 160] && - 0!=strcmp(s7,tp[(unsigned char)(*s8) - 160])) { - /* ...or which is mapped, by our "new method", to a replacement - string for this new charset. */ + } else if (tp[(unsigned char)(*s8) - 160] && + strcmp(s7, tp[(unsigned char)(*s8) - 160])) { + /* + * ...or which is mapped, by our "new method", + * to a replacement string for this new charset. + */ *p = tp[(unsigned char)(*s8) - 160]; changed = 1; } @@ -1228,9 +1458,12 @@ PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, low } return prepl; } -/* "New method" meets "Old method" ... */ -PRIVATE int UC_Register_with_LYCharSets ARGS4(int, s, +/* + * "New method" meets "Old method" ... + */ +PRIVATE int UC_Register_with_LYCharSets ARGS4( + int, s, char *, UC_MIMEcharset, char *, UC_LYNXcharset, int, lowest_eightbit) @@ -1239,90 +1472,123 @@ PRIVATE int UC_Register_with_LYCharSets ARGS4(int, s, char ** repl; LYhndl = -1; - if (LYNumCharsets == 0) /* initialize here; so whoever changes - LYCharSets.c doesn't have to count... */ - for (i=0; (i<MAX_CHARSETS) && LYchar_set_names[i]; i++) + if (LYNumCharsets == 0) { + /* + * Initialize here; so whoever changes + * LYCharSets.c doesn't have to count... + */ + for (i = 0; (i < MAXCHARSETS) && LYchar_set_names[i]; i++) { LYNumCharsets = i+1; + } + } - /* Do different kinds of searches... after all, this is experimental...*/ - for (i=0; i<MAX_CHARSETS && LYchar_set_names[i] && LYhndl<0; i++) - if (!strcmp(UC_LYNXcharset,LYchar_set_names[i])) + /* + * Do different kinds of searches... + * after all, this is experimental... + */ + for (i = 0; i < MAXCHARSETS && LYchar_set_names[i] && LYhndl < 0; i++) { + if (!strcmp(UC_LYNXcharset,LYchar_set_names[i])) { LYhndl = i; - for (i=0; i<MAX_CHARSETS && LYchar_set_names[i] && LYhndl<0; i++) + } + } + for (i = 0; i < MAXCHARSETS && LYchar_set_names[i] && LYhndl < 0; i++) { if (LYCharSet_UC[i].MIMEname && - !strcmp(UC_MIMEcharset,LYCharSet_UC[i].MIMEname)) + !strcmp(UC_MIMEcharset,LYCharSet_UC[i].MIMEname)) { LYhndl = i; + } + } if (LYhndl < 0) { /* not found */ found = 0; - if (LYNumCharsets >= MAX_CHARSETS) { - if (TRACE) - fprintf(stderr,"UC_Register_with_LYCharSets: Too many. Ignoring %s/%s.", + if (LYNumCharsets >= MAXCHARSETS) { + if (TRACE) { + fprintf(stderr, + "UC_Register_with_LYCharSets: Too many. Ignoring %s/%s.", UC_MIMEcharset,UC_LYNXcharset); + } return -1; } - /* add to LYCharSets.c lists */ - LYhndl = LYNumCharsets; LYNumCharsets ++; + /* + * Add to LYCharSets.c lists. + */ + LYhndl = LYNumCharsets; + LYNumCharsets ++; LYlowest_eightbit[LYhndl] = 999; LYCharSets[LYhndl] = SevenBitApproximations; - /* Hmm, try to be conservative here. */ + /* + * Hmm, try to be conservative here. + */ LYchar_set_names[LYhndl] = UC_LYNXcharset; LYchar_set_names[LYhndl+1] = (char *) 0; - /* Terminating NULL may be looked for by Lynx code */ - } else found = 1; - + /* + * Terminating NULL may be looked for by Lynx code. + */ + } else { + found = 1; + } LYCharSet_UC[LYhndl].UChndl = s; /* Can we just copy the pointer? Hope so... */ LYCharSet_UC[LYhndl].MIMEname = UC_MIMEcharset; LYCharSet_UC[LYhndl].enc = UCInfo[s].enc; - /* @@@ We really SHOULD get more info from the table files, and set - relevant flags in the LYCharSet_UC[] entry with that info... - for now, let's try it without - kw */ - - if (lowest_eightbit < LYlowest_eightbit[LYhndl]) + /* + * @@@ We really SHOULD get more info from the table files, + * and set relevant flags in the LYCharSet_UC[] entry with + * that info... For now, let's try it without. - KW + */ + if (lowest_eightbit < LYlowest_eightbit[LYhndl]) { LYlowest_eightbit[LYhndl] = lowest_eightbit; - else if (lowest_eightbit > LYlowest_eightbit[LYhndl]) + } else if (lowest_eightbit > LYlowest_eightbit[LYhndl]) { UCInfo[s].lowest_eight = LYlowest_eightbit[LYhndl]; + } if (!found && LYhndl > 0) { repl = UC_setup_LYCharSets_repl(s,UCInfo[s].lowest_eight); if (repl) { LYCharSets[LYhndl] = repl; - /* remember to FREE at exit */ + /* + * Remember to FREE at exit. + */ remember_allocated_LYCharSets[LYhndl]=repl; } } return LYhndl; } - -/* This only sets up the structure - no initialization of the tables +/* + * This only sets up the structure - no initialization of the tables * is done here yet. */ -void UC_Charset_Setup ARGS8(char *, UC_MIMEcharset, +PUBLIC void UC_Charset_Setup ARGS8( + char *, UC_MIMEcharset, char *, UC_LYNXcharset, - u8 *, unicount, u16 *, unitable, int, nnuni, - struct unimapdesc_str, replacedesc, int, lowest_eight, + u8 *, unicount, + u16 *, unitable, + int, nnuni, + struct unimapdesc_str, replacedesc, + int, lowest_eight, int, UC_rawuni) { int s, Gn; int i, status = 0, found; - /* Get (new?) slot */ - + /* + * Get (new?) slot. + */ found = -1; for (i=0; i<UCNumCharsets && found<0; i++) { - if (!strcmp(UCInfo[i].MIMEname,UC_MIMEcharset)) + if (!strcmp(UCInfo[i].MIMEname,UC_MIMEcharset)) { found = i; } - if (found >= 0) s = found; - else { - if (UCNumCharsets >= MAX_CHARSETS) - { - if (TRACE) + } + if (found >= 0) { + s = found; + } else { + if (UCNumCharsets >= MAXCHARSETS) { + if (TRACE) { fprintf(stderr,"UC_Charset_Setup: Too many. Ignoring %s/%s.", UC_MIMEcharset,UC_LYNXcharset); + } return; } s = UCNumCharsets; @@ -1340,10 +1606,13 @@ void UC_Charset_Setup ARGS8(char *, UC_MIMEcharset, if (UC_rawuni == UCT_ENC_UTF8) lowest_eight = 128; /* cheat here */ UCInfo[s].lowest_eight = lowest_eight; UCInfo[s].enc = UC_rawuni; - UCInfo[s].LYhndl = UC_Register_with_LYCharSets(s, UC_MIMEcharset, - UC_LYNXcharset, lowest_eight); + UCInfo[s].LYhndl = UC_Register_with_LYCharSets(s, + UC_MIMEcharset, + UC_LYNXcharset, + lowest_eight); UCInfo[s].uc_status = status; - if (found < 0) UCNumCharsets++; + if (found < 0) + UCNumCharsets++; return; } @@ -1353,9 +1622,10 @@ PRIVATE void UCcleanup_mem NOARGS UCfree_allocated_LYCharSets(); con_clear_unimap_str(); con_clear_unimap(); - for (i=1; i<4; i++) /* first one is static! */ + for (i = 1; i < 4; i++) { /* first one is static! */ FREE(inverse_translations[i]); } +} PUBLIC void UCInit NOARGS { @@ -1382,5 +1652,7 @@ PUBLIC void UCInit NOARGS UC_CHARSET_SETUP_unicode_1_1_utf_8; UC_CHARSET_SETUP_mnemonic_ascii_0; UC_CHARSET_SETUP_mnemonic; -/* UC_CHARSET_SETUP_mnem; */ +#ifdef NOTDEFINED + UC_CHARSET_SETUP_mnem; +#endif /* NOTDEFINED */ } diff --git a/src/UCdomap.h b/src/UCdomap.h index 0009f6eb..7ddd835a 100644 --- a/src/UCdomap.h +++ b/src/UCdomap.h @@ -1,5 +1,9 @@ + +#ifndef UCDOMAP_H +#define UCDOMAP_H + /* - * [old comments: - kw ] + * [old comments: - KW ] * consolemap.h * * Interface between console.c, selection.c and UCmap.c @@ -9,26 +13,23 @@ #define IBMPC_MAP 2 #define USER_MAP 3 -#ifndef MAX_CHARSETS -#define MAX_CHARSETS +#ifndef MAXCHARSETS +#define MAXCHARSETS #endif -extern int hashtable_contents_valid; -extern unsigned char inverse_translate PARAMS((int glyph)); -extern u16 *set_translate PARAMS((int m)); -extern int conv_uni_to_pc PARAMS((long ucs)); - -extern int hashtable_str_contents_valid; /* ??? probably no use... */ - /* Some conventions i try to follow (loosely): [a-z]* only internal, names from linux driver code. UC_* to be only known internally. UC[A-Z]* to be exported to other parts of Lynx. -kw */ - -extern void UC_Charset_Setup PARAMS((char * UC_MIMEcharset, char * UC_LYNXcharset, - u8 * unicount, u16 * unitable, int nnuni, - struct unimapdesc_str replacedesc, int lowest_eight, +extern void UC_Charset_Setup PARAMS(( + char * UC_MIMEcharset, + char * UC_LYNXcharset, + u8 * unicount, + u16 * unitable, + int nnuni, + struct unimapdesc_str replacedesc, + int lowest_eight, int UC_rawuni)); char *UC_GNsetMIMEnames[4] = @@ -48,11 +49,11 @@ struct UC_charset { int lowest_eight; int enc; }; -char * UC_charsetMIMEnames[MAX_CHARSETS]; -PUBLIC struct UC_charset UCInfo[MAX_CHARSETS]; +PUBLIC struct UC_charset UCInfo[MAXCHARSETS]; PUBLIC int UCNumCharsets; extern void UCInit NOARGS; +#endif /* UCDOMAP_H */ diff --git a/src/chrtrans/README.tables b/src/chrtrans/README.tables index c9a86605..8e4366d1 100644 --- a/src/chrtrans/README.tables +++ b/src/chrtrans/README.tables @@ -2,13 +2,13 @@ The translation table files in this directory are _examples only_. They were collected from several sources (among them Linux kbd package, ftp://dkuug.dk/, ftp://unicode.org/) and automatically comverted (if applicable), but not checked in detail. The Unicode/UCS2 values -for some of the RFC1345 Mnemonic codes are out of date, a cleanup and +for some of the RFC 1345 Mnemonic codes are out of date, a cleanup and update would be needed for serious use (including removing the mappings from the "private zone" U+E000 etc.). More tranlation files can be easily provided (and new character entities added to HTMLDTD.c), this set is just to test whether the system works -in principle (and also how it behaves with of incomplete data...) +in principle (and also how it behaves with incomplete data...) See the file README.format for a brief explanation of what's in the table files. @@ -18,8 +18,10 @@ doesn't really matter. The auxiliary program makeuctb (MAKE UniCode TaBle) is used to "compile" them into C header files, which can be included by UCdomap.c. -Ideally this should be taken care of by the Makefiles.. - +Ideally, this should be taken care of by the Makefiles. On VMS, use +build-chrtrans.com to compile and link makeuctb.exe and create the +set of .h files from the current set of .tlb files. Thereafter, use +build-header.com to update particular .h files. To make a new chartrans table available to Lynx (and thereby make a new charset known to Lynx) you currently have to manually edit UCdomap.c, in @@ -27,7 +29,11 @@ two places: a) Near the top, you will find a bunch of lines (some may be commented out) + #ifdef VMS + #include "[.chrtrans]<fn>.h" + #else #include "chrtrans/<fn>.h" + #endif /* VMS */ Add or comment out as you wish. (But it's probably safest to leave the first one, referring to "chrtrans/iso01_uni.h", in place...) @@ -50,5 +56,9 @@ named makefile.in before running ./configure, or makefile after running ./configure. (That may be inconvenient, but I didn't want to depend on features than not all makes may have.) Note that for recompiling Lynx, a `make clean' should not be necessary if you have *only* made -changes to the files in src/chrtrans. +changes to the files in src/chrtrans. On VMS, add entries for new +tables to build-chrtrans.com, but you can update the particular file +with build-header.com, then use the top directory's build.com and +answer 'n' to it's prompts about whether to update the WWWlibrary +and chrtrans modules. diff --git a/src/chrtrans/UCkd.h b/src/chrtrans/UCkd.h index 2cc2ebdb..083afe49 100644 --- a/src/chrtrans/UCkd.h +++ b/src/chrtrans/UCkd.h @@ -1,19 +1,22 @@ #ifndef _UC_KD_H #define _UC_KD_H -#include <sys/types.h> - -/* NOTE: THE FOLLOWING #define MAY NEED ADJUSTMENT. - u16 should be an unsigned type of 16 bit length (two octets). - u8 should be an unsigned type of 8 bit length (one octet). - */ +#ifdef NOTDEFINED +#include <sys/types.h> /* Included via tcp.h. */ +#endif /* NOTDEFINED */ + +/* + * NOTE: THE FOLLOWING #define MAY NEED ADJUSTMENT. + * u16 should be an unsigned type of 16 bit length (two octets). + * u8 should be an unsigned type of 8 bit length (one octet). + */ #ifndef u16 #define u16 unsigned short -#endif +#endif /* u16 */ #ifndef u8 #define u8 unsigned char -#endif +#endif /* u8 */ #ifdef NOTDEFINED struct consolefontdesc { @@ -21,7 +24,7 @@ struct consolefontdesc { u_short charheight; /* scan lines per character (1-32) */ char *chardata; /* font data in expanded form */ }; -#endif +#endif /* NOTDEFINED */ typedef char scrnmap_t; #define E_TABSZ 256 diff --git a/src/chrtrans/build-chrtrans.com b/src/chrtrans/build-chrtrans.com new file mode 100644 index 00000000..b9a3d515 --- /dev/null +++ b/src/chrtrans/build-chrtrans.com @@ -0,0 +1,125 @@ +$ v = 'f$verify(0)' +$! BUILD-CHRTRANS.COM +$! +$! Command file to build MAKEUCTB.EXE on VMS systems +$! and then use it to create the chrtrans header files. +$! +$! 28-Jun-1997 F.Macrides macrides@sci.wfeb.edu +$! Initial version, for Lynx v2.7.1+fotemods +$! +$ ON CONTROL_Y THEN GOTO CLEANUP +$ ON ERROR THEN GOTO CLEANUP +$ CHRproc = f$environment("PROCEDURE") +$ CHRwhere = f$parse(CHRproc,,,"DEVICE") + f$parse(CHRproc,,,"DIRECTORY") +$! +$ if p1 .nes. "" +$ then +$ CHRcc_opts = "/DEBUG/NOOPT" +$ CHRlink_opts = "/DEBUG" +$ else +$ CHRcc_opts = "" +$ CHRlink_opts = "" +$ endif +$! +$ Compile_makeuctb: +$!================ +$ v1 = f$verify(1) +$! +$! Compile the Lynx [.SRC.CHRTRANS]makeuctb module. +$! +$ v1 = 'f$verify(0)' +$ IF f$trnlnm("VAXCMSG") .eqs. "DECC$MSG" .or. - + f$trnlnm("DECC$CC_DEFAULT") .eqs. "/DECC" .or. - + f$trnlnm("DECC$CC_DEFAULT") .eqs. "/VAXC" +$ THEN +$ CHRcompiler := "DECC" +$ v1 = f$verify(1) +$! DECC: +$ cc := cc/decc/prefix=all /nomember 'CHRcc_opts'- + /INCLUDE=([-],[--],[--.WWW.Library.Implementation]) +$ v1 = 'f$verify(0)' +$ ELSE +$ IF f$search("gnu_cc:[000000]gcclib.olb") .nes. "" +$ THEN +$ CHRcompiler := "GNUC" +$ v1 = f$verify(1) +$! GNUC: +$ cc := gcc 'cc_opts'/INCLUDE=([-],[--],[--.WWW.Library.Implementation]) +$ v1 = 'f$verify(0)' +$ ELSE +$ CHRcompiler := "VAXC" +$ v1 = f$verify(1) +$! VAXC: +$ cc := cc 'cc_opts'/INCLUDE=([-],[--],[--.WWW.Library.Implementation]) +$ v1 = 'f$verify(0)' +$ ENDIF +$ ENDIF +$! +$ v1 = f$verify(1) +$ cc makeuctb +$ v1 = 'f$verify(0)' +$! +$ Link_makeuctb: +$!============= +$ v1 = f$verify(1) +$! +$! Link the Lynx [.SRC.CHRTRANS]makeuctb module. +$! +$ link/exe=makeuctb.exe'link_opts' makeuctb, - +sys$disk:[-]'CHRcompiler'.opt/opt +$ v1 = 'f$verify(0)' +$! +$ Create_headers: +$!============== +$ v1 = f$verify(1) +$! +$! Create the Lynx [.SRC.CHRTRANS] header files. +$! +$ makeuctb := $'CHRwhere'makeuctb +$ define/user sys$output 'CHRwhere'iso01_uni.h +$ makeuctb iso01_uni.tbl +$ define/user sys$output 'CHRwhere'iso02_uni.h +$ makeuctb iso02_uni.tbl +$ define/user sys$output 'CHRwhere'def7_uni.h +$ makeuctb def7_uni.tbl +$ define/user sys$output 'CHRwhere'iso03_uni.h +$ makeuctb iso03_uni.tbl +$ define/user sys$output 'CHRwhere'iso04_uni.h +$ makeuctb iso04_uni.tbl +$ define/user sys$output 'CHRwhere'iso05_uni.h +$ makeuctb iso05_uni.tbl +$ define/user sys$output 'CHRwhere'iso07_uni.h +$ makeuctb iso07_uni.tbl +$ define/user sys$output 'CHRwhere'iso09_uni.h +$ makeuctb iso09_uni.tbl +$ define/user sys$output 'CHRwhere'iso10_uni.h +$ makeuctb iso10_uni.tbl +$ define/user sys$output 'CHRwhere'koi8r_uni.h +$ makeuctb koi8r_uni.tbl +$ define/user sys$output 'CHRwhere'cp437_uni.h +$ makeuctb cp437_uni.tbl +$ define/user sys$output 'CHRwhere'cp850_uni.h +$ makeuctb cp850_uni.tbl +$ define/user sys$output 'CHRwhere'cp852_uni.h +$ makeuctb cp852_uni.tbl +$ define/user sys$output 'CHRwhere'cp1250_uni.h +$ makeuctb cp1250_uni.tbl +$ define/user sys$output 'CHRwhere'cp1252_uni.h +$ makeuctb cp1252_uni.tbl +$ define/user sys$output 'CHRwhere'utf8_uni.h +$ makeuctb utf8_uni.tbl +$ define/user sys$output 'CHRwhere'mnemonic_suni.h +$ makeuctb mnemonic_suni.tbl +$ define/user sys$output 'CHRwhere'mnem_suni.h +$ makeuctb mnem_suni.tbl +$ define/user sys$output 'CHRwhere'rfc_suni.h +$ makeuctb rfc_suni.tbl +$ v1 = 'f$verify(0)' +$ exit +$! +$ CLEANUP: +$ v1 = 'f$verify(0)' +$ write sys$output "Default directory:" +$ show default +$ v1 = f$verify(v) +$ exit diff --git a/src/chrtrans/build-header.com b/src/chrtrans/build-header.com new file mode 100644 index 00000000..963825dd --- /dev/null +++ b/src/chrtrans/build-header.com @@ -0,0 +1,37 @@ +$ v = 'f$verify(0)' +$! BUILD-HEADER.COM +$! +$! Command file to use MAKEUCTB.EXE on VMS systems for creating +$! a chrtrans header (foo.h) file from a table (foo.tbl) file. +$! Use the file root as P1, e.g.: +$! +$! $ @build-header iso05_uni +$! +$! will create iso05_uni.h from iso05_uni.tbl. +$! +$! 28-Jun-1997 F.Macrides macrides@sci.wfeb.edu +$! Initial version, for Lynx v2.7.1+fotemods +$! +$ ON CONTROL_Y THEN GOTO CLEANUP +$ ON ERROR THEN GOTO CLEANUP +$ CHRproc = f$environment("PROCEDURE") +$ CHRwhere = f$parse(CHRproc,,,"DEVICE") + f$parse(CHRproc,,,"DIRECTORY") +$! +$ Create_header: +$!============= +$ v1 = f$verify(1) +$! +$! Create a Lynx [.SRC.CHRTRANS] header file. +$! +$ makeuctb := $'CHRwhere'makeuctb +$ define/user sys$output 'CHRwhere''P1'.h +$ makeuctb 'P1'.tbl +$ v1 = 'f$verify(0)' +$ exit +$! +$ CLEANUP: +$ v1 = 'f$verify(0)' +$ write sys$output "Default directory:" +$ show default +$ v1 = f$verify(v) +$ exit diff --git a/src/chrtrans/makeuctb.c b/src/chrtrans/makeuctb.c index f5f73066..95ba076d 100644 --- a/src/chrtrans/makeuctb.c +++ b/src/chrtrans/makeuctb.c @@ -1,18 +1,18 @@ /* - * makeuctb.c, derived from conmakehash.c + * makeuctb.c, derived from conmakehash.c * - * [ original comments: - kw ] - * Create arrays for initializing the kernel folded tables (using a hash - * table turned out to be to limiting...) Unfortunately we can't simply - * preinitialize the tables at compile time since kfree() cannot accept - * memory not allocated by kmalloc(), and doing our own memory management - * just for this seems like massive overkill. + * [ original comments: - kw ] + * Create arrays for initializing the kernel folded tables (using a hash + * table turned out to be to limiting...) Unfortunately we can't simply + * preinitialize the tables at compile time since kfree() cannot accept + * memory not allocated by kmalloc(), and doing our own memory management + * just for this seems like massive overkill. * - * Copyright (C) 1995 H. Peter Anvin + * Copyright (C) 1995 H. Peter Anvin * - * This program is a part of the Linux kernel, and may be freely - * copied under the terms of the GNU General Public License (GPL), - * version 2, or at your option any later version. + * This program is a part of the Linux kernel, and may be freely + * copied under the terms of the GNU General Public License (GPL), + * version 2, or at your option any later version. */ #ifdef NOTDEFINED @@ -22,123 +22,143 @@ #include <string.h> #include <ctype.h> #else +#include "HTUtils.h" #include "tcp.h" -#undef exit /* don't try to use LYexit() */ -#endif +/* + * Don't try to use LYexit(). + */ +#ifdef exit +#undef exit +#endif /* exit */ +#endif /* NODEFINED */ #ifndef TOLOWER #define TOLOWER(c) (isupper((unsigned char)c) ? tolower((unsigned char)c) : (c)) -#endif /* ndef TOLOWER */ +#endif /* !TOLOWER */ #include "UCkd.h" #include "UCDefs.h" #define MAX_FONTLEN 256 -/* We don't deal with UCS4 here... -kw */ +/* + * We don't deal with UCS4 here. - KW + */ typedef u16 unicode; -PRIVATE void usage ARGS1(char *, argv0) +PRIVATE void usage ARGS1( + char *, argv0) { - fprintf(stderr, "Usage: \n"); - fprintf(stderr, " %s chartable [charsetmimename] [charsetdisplayname]\n", argv0); - fprintf(stderr, "Utility to convert .tbl into .h files for Lynx compilation.\n"); - exit(EX_USAGE); + fprintf(stderr, "Usage: \n"); + fprintf(stderr, + " %s chartable [charsetmimename] [charsetdisplayname]\n", + argv0); + fprintf(stderr, + "Utility to convert .tbl into .h files for Lynx compilation.\n"); + exit(EX_USAGE); } -PRIVATE int getunicode ARGS1(char **, p0) +PRIVATE int getunicode ARGS1( + char **, p0) { - char *p = *p0; - - while (*p == ' ' || *p == '\t') - p++; - if (*p == '-') - return -2; - else if (*p != 'U' || p[1] != '+' || - !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) || - !isxdigit(p[5]) || isxdigit(p[6])) - return -1; - *p0 = p+6; - return strtol(p+2,0,16); + char *p = *p0; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p == '-') { + return -2; + } else if (*p != 'U' || p[1] != '+' || + !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) || + !isxdigit(p[5]) || isxdigit(p[6])) { + return -1; + } + *p0 = p+6; + return strtol((p + 2), 0, 16); } +/* + * Massive overkill, but who cares? + */ unicode unitable[MAX_FONTLEN][255]; - /* Massive overkill, but who cares? */ int unicount[MAX_FONTLEN]; struct unimapdesc_str themap_str = {0, NULL}; char *tblname; -PRIVATE void addpair_str ARGS2(char *, str, int, un) +PRIVATE void addpair_str ARGS2( + char *, str, + int, un) { - int i; - - - if ( un <= 0xfffe ) - { - /* Initialize the map for replacement strings */ - - if (!themap_str.entry_ct) { - themap_str.entries = + int i; + + if (un <= 0xfffe) { + if (!themap_str.entry_ct) { + /* + * Initialize the map for replacement strings. + */ + themap_str.entries = (struct unipair_str *) malloc (2000 * sizeof (struct unipair_str)); - if (! themap_str.entries) - { + if (!themap_str.entries) { fprintf(stderr, "%s: Out of memory\n", tblname); exit(EX_DATAERR); - } - } - - /* Check it isn't a duplicate */ - - else for ( i = 0 ; i < themap_str.entry_ct ; i++ ) - if ( themap_str.entries[i].unicode == un ) { - themap_str.entries[i].replace_str = str; - return; + } + } else { + /* + * Check that it isn't a duplicate. + */ + for (i = 0 ; i < themap_str.entry_ct; i++) { + if (themap_str.entries[i].unicode == un ) { + themap_str.entries[i].replace_str = str; + return; + } + } } - /* Add to list */ - - if ( themap_str.entry_ct > 1999 ) - { - fprintf(stderr, "ERROR: Only 2000 unicode replacement strings permitted!\n"); - exit(EX_DATAERR); + /* + * Add to list. + */ + if (themap_str.entry_ct > 1999) { + fprintf(stderr, + "ERROR: Only 2000 unicode replacement strings permitted!\n"); + exit(EX_DATAERR); } - - themap_str.entries[themap_str.entry_ct].unicode = un; - themap_str.entries[themap_str.entry_ct].replace_str = str; - themap_str.entry_ct++; + themap_str.entries[themap_str.entry_ct].unicode = un; + themap_str.entries[themap_str.entry_ct].replace_str = str; + themap_str.entry_ct++; } - - /* otherwise: ignore */ + /* otherwise: ignore */ } -PRIVATE void addpair ARGS2(int, fp, int, un) +PRIVATE void addpair ARGS2( + int, fp, + int, un) { - int i; - - if ( un <= 0xfffe ) - { - /* Check it isn't a duplicate */ - - for ( i = 0 ; i < unicount[fp] ; i++ ) - if ( unitable[fp][i] == un ) - return; - - /* Add to list */ - - if ( unicount[fp] > 254 ) - { - fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n"); - exit(EX_DATAERR); + int i; + + if (un <= 0xfffe) { + /* + * Check that it isn't a duplicate. + */ + for (i = 0; i < unicount[fp]; i++) { + if (unitable[fp][i] == un) { + return; + } } - unitable[fp][unicount[fp]] = un; - unicount[fp]++; + /* + * Add to list. + */ + if (unicount[fp] > 254) { + fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n"); + exit(EX_DATAERR); + } + unitable[fp][unicount[fp]] = un; + unicount[fp]++; } - - /* otherwise: ignore */ + /* otherwise: ignore */ } char this_MIMEcharset[UC_MAXLEN_MIMECSNAME +1]; @@ -148,422 +168,463 @@ int this_isDefaultMap = -1; int RawUni = 0; int lowest_eight = 999; -int main ARGS2(int, argc, char **, argv) +PUBLIC int main ARGS2( + int, argc, + char **, argv) { - FILE *ctbl; - char buffer[65536]; - int fontlen; - int i, nuni, nent; - int fp0, fp1, un0, un1; - char *p, *p1; - char *tbuf, ch; - - if ( argc < 2 || argc > 4 ) - usage(argv[0]); - - if ( !strcmp(argv[1],"-") ) - { - ctbl = stdin; - tblname = "stdin"; + FILE *ctbl; + char buffer[65536]; + int fontlen; + int i, nuni, nent; + int fp0, fp1, un0, un1; + char *p, *p1; + char *tbuf, ch; + + if (argc < 2 || argc > 4) { + usage(argv[0]); } - else - { - ctbl = fopen(tblname = argv[1], "r"); - if ( !ctbl ) - { - perror(tblname); - exit(EX_NOINPUT); + + if (!strcmp(argv[1], "-")) { + ctbl = stdin; + tblname = "stdin"; + } else { + ctbl = fopen(tblname = argv[1], "r"); + if (!ctbl) { + perror(tblname); + exit(EX_NOINPUT); } } - /* For now we assume the default font is always 256 characters. */ - fontlen = 256; + /* + * For now we assume the default font is always 256 characters. + */ + fontlen = 256; - /* Initialize table */ - - for ( i = 0 ; i < fontlen ; i++ ) - unicount[i] = 0; + /* + * Initialize table. + */ + for (i = 0; i < fontlen; i++) { + unicount[i] = 0; + } - /* Now we come to the tricky part. Parse the input table. */ + /* + * Now we comes to the tricky part. Parse the input table. + */ + while (fgets(buffer, sizeof(buffer), ctbl) != NULL) { + if ((p = strchr(buffer, '\n')) != NULL) { + *p = '\0'; + } else { + fprintf(stderr, "%s: Warning: line too long\n", tblname); + } - while ( fgets(buffer, sizeof(buffer), ctbl) != NULL ) - { - if ( (p = strchr(buffer, '\n')) != NULL ) - *p = '\0'; - else - fprintf(stderr, "%s: Warning: line too long\n", tblname); + /* + * Syntax accepted: + * <fontpos> <unicode> <unicode> ... + * <fontpos> <unicode range> <unicode range> ... + * <fontpos> idem + * <range> idem + * <range> <unicode range> + * <unicode> :<replace> + * <unicode range> :<replace> + * + * where <range> ::= <fontpos>-<fontpos> + * and <unicode> ::= U+<h><h><h><h> + * and <h> ::= <hexadecimal digit> + * and <replace> any string not containing '\n' or '\0' + */ + p = buffer; + while (*p == ' ' || *p == '\t') { + p++; + } + if (!(*p) || *p == '#') { + /* + * Skip comment or blank line. + */ + continue; + } - p = buffer; + switch (*p) { + /* + * Raw Unicode? I.e. needs some special + * processing. One digit code. + */ + case 'R': + p++; + while (*p == ' ' || *p == '\t') { + p++; + } + RawUni = strtol(p,0,10); + continue; -/* - * Syntax accepted: - * <fontpos> <unicode> <unicode> ... - * <fontpos> <unicode range> <unicode range> ... - * <fontpos> idem - * <range> idem - * <range> <unicode range> - * <unicode> :<replace> - * <unicode range> :<replace> - * - * where <range> ::= <fontpos>-<fontpos> - * and <unicode> ::= U+<h><h><h><h> - * and <h> ::= <hexadecimal digit> - * and <replace> any string not containing '\n' or '\0' - */ + /* + * Is this the default display font? + */ + case 'D': + p++; + while (*p == ' ' || *p == '\t') { + p++; + } + this_isDefaultMap = (*p == '1'); + continue; - while (*p == ' ' || *p == '\t') - p++; - if (!*p || *p == '#') - continue; /* skip comment or blank line */ + case 'M': + p++; + while (*p == ' ' || *p == '\t') { + p++; + } + sscanf(p,"%40s",this_MIMEcharset); + continue; - switch (*p) { - case 'R': /* Raw Unicode? I.e. needs some special - processing. One digit code. */ - p++; - while (*p == ' ' || *p == '\t') - p++; - RawUni = strtol(p,0,10); - continue; + /* + * Display charset name for options screen. + */ + case 'O': + p++; + while (*p == ' ' || *p == '\t') { + p++; + } + for (i = 0; *p && i < UC_MAXLEN_LYNXCSNAME; p++, i++) { + this_LYNXcharset[i] = *p; + } + this_LYNXcharset[i] = '\0'; + continue; + } - case 'D': /* Is this the default display font? */ - p++; - while (*p == ' ' || *p == '\t') - p++; - this_isDefaultMap = (*p == '1'); - continue; - case 'M': - p++; - while (*p == ' ' || *p == '\t') - p++; - sscanf(p,"%40s",this_MIMEcharset); - continue; - case 'O': /* Display charset name for options screen */ - p++; - while (*p == ' ' || *p == '\t') - p++; - for (i=0; *p && i<UC_MAXLEN_LYNXCSNAME; p++,i++) - this_LYNXcharset[i] = *p; - this_LYNXcharset[i] = '\0'; - continue; - } - - if(*p == 'U') - { - un0 = getunicode(&p); - if (un0 < 0) - { - fprintf(stderr, "Bad input line: %s\n", buffer); - exit(EX_DATAERR); - fprintf(stderr, - "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n", - tblname, fp0, fp1); - exit(EX_DATAERR); + if (*p == 'U') { + un0 = getunicode(&p); + if (un0 < 0) { + fprintf(stderr, "Bad input line: %s\n", buffer); + exit(EX_DATAERR); + fprintf(stderr, + "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n", + tblname, fp0, fp1); + exit(EX_DATAERR); } - un1 = un0; - while (*p == ' ' || *p == '\t') - p++; - if (*p == '-') - { - p++; - while (*p == ' ' || *p == '\t') + un1 = un0; + while (*p == ' ' || *p == '\t') { p++; - un1 = getunicode(&p); - if (un1 < 0 || un1 < un0) - { - fprintf(stderr, - "%s: Bad Unicode range U+%x-U+%x\n", - tblname, un0, un1); - fprintf(stderr, "Bad input line: %s\n", buffer); - exit(EX_DATAERR); - } - while (*p == ' ' || *p == '\t') + } + if (*p == '-') { p++; + while (*p == ' ' || *p == '\t') { + p++; + } + un1 = getunicode(&p); + if (un1 < 0 || un1 < un0) { + fprintf(stderr, + "%s: Bad Unicode range U+%x-U+%x\n", + tblname, un0, un1); + fprintf(stderr, "Bad input line: %s\n", buffer); + exit(EX_DATAERR); + } + while (*p == ' ' || *p == '\t') { + p++; + } } - if (*p != ':') - { - fprintf(stderr, "No ':' where expected: %s\n", buffer); - continue; + if (*p != ':') { + fprintf(stderr, "No ':' where expected: %s\n", buffer); + continue; } - tbuf = (char *) malloc (4*strlen(++p) + 1); - if (!(p1 = tbuf)) - { - fprintf(stderr, - "%s: Out of memory\n", tblname); - exit(EX_DATAERR); + tbuf = (char *) malloc (4*strlen(++p) + 1); + if (!(p1 = tbuf)) { + fprintf(stderr, "%s: Out of memory\n", tblname); + exit(EX_DATAERR); } - for(ch = *p; (ch = *p) != '\0'; p++,p1++) - { - if ((unsigned char)ch < 32 || ch == '\\' || ch == '\"' || - (unsigned char)ch >= 127) - { - sprintf(p1,"\\%.3o",(unsigned char)ch); -/* fprintf(stderr,"%s\n",tbuf); */ - p1 += 3; + for (ch = *p; (ch = *p) != '\0'; p++, p1++) { + if ((unsigned char)ch < 32 || ch == '\\' || ch == '\"' || + (unsigned char)ch >= 127) { + sprintf(p1, "\\%.3o", (unsigned char)ch); +/* fprintf(stderr, "%s\n", tbuf); */ + p1 += 3; + } else { + *p1 = ch; } - else - *p1 = ch; } - *p1 = '\0'; - for(i=un0; i<=un1; i++) -/* printf("U+0x%x:%s\n",i,tbuf); */ - addpair_str(tbuf,i); + *p1 = '\0'; + for (i = un0; i <= un1; i++) { +/* printf("U+0x%x:%s\n", i, tbuf); */ + addpair_str(tbuf,i); + } continue; } - fp0 = strtol(p, &p1, 0); - if (p1 == p) - { - fprintf(stderr, "Bad input line: %s\n", buffer); - exit(EX_DATAERR); + fp0 = strtol(p, &p1, 0); + if (p1 == p) { + fprintf(stderr, "Bad input line: %s\n", buffer); + exit(EX_DATAERR); } - p = p1; + p = p1; - while (*p == ' ' || *p == '\t') - p++; - if (*p == '-') - { - p++; - fp1 = strtol(p, &p1, 0); - if (p1 == p) - { - fprintf(stderr, "Bad input line: %s\n", buffer); - exit(EX_DATAERR); + while (*p == ' ' || *p == '\t') { + p++; + } + if (*p == '-') { + p++; + fp1 = strtol(p, &p1, 0); + if (p1 == p) { + fprintf(stderr, "Bad input line: %s\n", buffer); + exit(EX_DATAERR); } - p = p1; - } - else - fp1 = 0; + p = p1; + } else { + fp1 = 0; + } - if ( fp0 < 0 || fp0 >= fontlen ) - { + if (fp0 < 0 || fp0 >= fontlen) { fprintf(stderr, "%s: Glyph number (0x%x) larger than font length\n", tblname, fp0); exit(EX_DATAERR); } - if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) ) - { + if (fp1 && (fp1 < fp0 || fp1 >= fontlen)) { fprintf(stderr, "%s: Bad end of range (0x%x)\n", tblname, fp1); exit(EX_DATAERR); } - if (fp1) - { - /* we have a range; expect the word "idem" or a Unicode range of the - same length */ - while (*p == ' ' || *p == '\t') - p++; - if (!strncmp(p, "idem", 4)) - { - for (i=fp0; i<=fp1; i++) - addpair(i,i); - p += 4; - } - else - { - un0 = getunicode(&p); - while (*p == ' ' || *p == '\t') + if (fp1) { + /* + * We have a range; expect the word "idem" + * or a Unicode range of the same length. + */ + while (*p == ' ' || *p == '\t') { p++; - if (*p != '-') - { - fprintf(stderr, -"%s: Corresponding to a range of font positions, there should be a Unicode range\n", - tblname); - exit(EX_DATAERR); + } + if (!strncmp(p, "idem", 4)) { + for (i = fp0; i <= fp1; i++) { + addpair(i,i); + } + p += 4; + } else { + un0 = getunicode(&p); + while (*p == ' ' || *p == '\t') { + p++; + } + if (*p != '-') { + fprintf(stderr, + "%s: Corresponding to a range of font positions,", + tblname); + fprintf(stderr, + " there should be a Unicode range.\n"); + exit(EX_DATAERR); } - p++; - un1 = getunicode(&p); - if (un0 < 0 || un1 < 0) - { - fprintf(stderr, -"%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n", - tblname, fp0, fp1); - exit(EX_DATAERR); + p++; + un1 = getunicode(&p); + if (un0 < 0 || un1 < 0) { + fprintf(stderr, + "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n", + tblname, fp0, fp1); + exit(EX_DATAERR); } - if (un1 - un0 != fp1 - fp0) - { - fprintf(stderr, -"%s: Unicode range U+%x-U+%x not of the same length as font position range 0x%x-0x%x\n", - tblname, un0, un1, fp0, fp1); - exit(EX_DATAERR); + if (un1 - un0 != fp1 - fp0) { + fprintf(stderr, + "%s: Unicode range U+%x-U+%x not of the same length", + tblname, un0, un1); + fprintf(stderr, + " as font position range 0x%x-0x%x\n", + fp0, fp1); + exit(EX_DATAERR); } - for(i=fp0; i<=fp1; i++) - addpair(i,un0-fp0+i); + for (i = fp0; i <= fp1; i++) { + addpair(i,un0-fp0+i); + } } - } - else - { - /* no range; expect a list of unicode values or unicode ranges - for a single font position, or the word "idem" */ - - while (*p == ' ' || *p == '\t') + } else { + /* + * No range; expect a list of unicode values + * or unicode ranges for a single font position, + * or the word "idem" + */ + while (*p == ' ' || *p == '\t') { p++; - if (!strncmp(p, "idem", 4)) - { + } + if (!strncmp(p, "idem", 4)) { addpair(fp0,fp0); p += 4; } - while ( (un0 = getunicode(&p)) >= 0 ) { + while ((un0 = getunicode(&p)) >= 0) { addpair(fp0, un0); - while (*p == ' ' || *p == '\t') + while (*p == ' ' || *p == '\t') { p++; + } if (*p == '-') { p++; un1 = getunicode(&p); - if (un1 < un0) - { + if (un1 < un0) { fprintf(stderr, "%s: Bad Unicode range 0x%x-0x%x\n", tblname, un0, un1); exit(EX_DATAERR); } - for(un0++; un0 <= un1; un0++) + for (un0++; un0 <= un1; un0++) { addpair(fp0, un0); + } } } } - while (*p == ' ' || *p == '\t') - p++; - if (*p && *p != '#') - fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p); + while (*p == ' ' || *p == '\t') { + p++; + } + if (*p && *p != '#') { + fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p); + } } - /* Okay, we hit EOF, now output hash table */ - - fclose(ctbl); + /* + * Okay, we hit EOF, now output hash table. + */ + fclose(ctbl); - /* Compute total size of Unicode list */ - nuni = 0; - for ( i = 0 ; i < fontlen ; i++ ) - nuni += unicount[i]; - - if (argc >=3 ) - strncpy(this_MIMEcharset,argv[2],UC_MAXLEN_MIMECSNAME); - else if (!this_MIMEcharset || ! *this_MIMEcharset) { - strncpy(this_MIMEcharset,tblname,UC_MAXLEN_MIMECSNAME); - if ((p = strchr(this_MIMEcharset,'.')) != 0) - *p = '\0'; - } - for (p=this_MIMEcharset; *p; p++) - *p = TOLOWER(*p); - if (argc >=4 ) - strncpy(this_LYNXcharset,argv[3],UC_MAXLEN_LYNXCSNAME); - else if (!this_LYNXcharset || ! *this_LYNXcharset) { - strncpy(this_LYNXcharset,this_MIMEcharset,UC_MAXLEN_LYNXCSNAME); - } - if ((i=strlen(this_LYNXcharset)) < UC_LEN_LYNXCSNAME) { - for (;i<UC_LEN_LYNXCSNAME;i++) - this_LYNXcharset[i] = ' '; - this_LYNXcharset[i] = '\0'; - } -/* - fprintf(stderr,"this_MIMEcharset: %s.\n",this_MIMEcharset); - fprintf(stderr,"this_LYNXcharset: %s.\n",this_LYNXcharset); -*/ - if (this_isDefaultMap == -1) - this_isDefaultMap = !strncmp(this_MIMEcharset,"iso-8859-1",10); - fprintf(stderr,"makeuctb: %s: %stranslation map", - this_MIMEcharset, (this_isDefaultMap ? "default " : "")); - if (this_isDefaultMap == 1) - *id_append = '\0'; - else - for (i=0,p=this_MIMEcharset; *p && (i < UC_MAXLEN_ID_APPEND-1); p++,i++) - id_append[i+1] = isalnum(*p) ? *p : '_'; - id_append[i+1] = '\0'; - fprintf(stderr," (%s).\n", id_append); - - - printf("\ + /* + * Compute total size of Unicode list. + */ + nuni = 0; + for (i = 0 ; i < fontlen ; i++) { + nuni += unicount[i]; + } + + if (argc >= 3) { + strncpy(this_MIMEcharset,argv[2],UC_MAXLEN_MIMECSNAME); + } else if (!this_MIMEcharset || !(*this_MIMEcharset)) { + strncpy(this_MIMEcharset,tblname,UC_MAXLEN_MIMECSNAME); + if ((p = strchr(this_MIMEcharset,'.')) != 0) { + *p = '\0'; + } + } + for (p = this_MIMEcharset; *p; p++) { + *p = TOLOWER(*p); + } + if (argc >= 4) { + strncpy(this_LYNXcharset,argv[3],UC_MAXLEN_LYNXCSNAME); + } else if (!this_LYNXcharset || !(*this_LYNXcharset)) { + strncpy(this_LYNXcharset,this_MIMEcharset,UC_MAXLEN_LYNXCSNAME); + } + if ((i = strlen(this_LYNXcharset)) < UC_LEN_LYNXCSNAME) { + for (; i < UC_LEN_LYNXCSNAME; i++) { + this_LYNXcharset[i] = ' '; + } + this_LYNXcharset[i] = '\0'; + } +#ifdef NOTDEFINED + fprintf(stderr,"this_MIMEcharset: %s.\n",this_MIMEcharset); + fprintf(stderr,"this_LYNXcharset: %s.\n",this_LYNXcharset); +#endif /* NOTDEFINED */ + if (this_isDefaultMap == -1) { + this_isDefaultMap = !strncmp(this_MIMEcharset,"iso-8859-1", 10); + } + fprintf(stderr, + "makeuctb: %s: %stranslation map", + this_MIMEcharset, (this_isDefaultMap ? "default " : "")); + if (this_isDefaultMap == 1) { + *id_append = '\0'; + } else { + for (i = 0, p = this_MIMEcharset; + *p && (i < UC_MAXLEN_ID_APPEND-1); + p++, i++) { + id_append[i+1] = isalnum(*p) ? *p : '_'; + } + } + id_append[i+1] = '\0'; + fprintf(stderr, " (%s).\n", id_append); + + printf("\ /*\n\ - * uni_hash.tbl\n\ + * uni_hash.tbl\n\ *\n\ - * Do not edit this file; it was automatically generated by\n\ + * Do not edit this file; it was automatically generated by\n\ *\n\ - * %s %s\n\ + * %s %s\n\ *\n\ */\n\ \n\ static u8 dfont_unicount%s[%d] = \n\ {\n\t", argv[0], argv[1], id_append, fontlen); - for ( i = 0 ; i < fontlen ; i++ ) - { - if (i >= 128 && unicount[i] > 0 && i < lowest_eight) - lowest_eight = i; - printf("%3d", unicount[i]); - if ( i == fontlen-1 ) - printf("\n};\n"); - else if ( i % 8 == 7 ) - printf(",\n\t"); - else - printf(", "); + for (i = 0; i < fontlen; i++) { + if (i >= 128 && unicount[i] > 0 && i < lowest_eight) { + lowest_eight = i; + } + printf("%3d", unicount[i]); + if (i == (fontlen - 1)) { + printf("\n};\n"); + } else if ((i % 8) == 7) { + printf(",\n\t"); + } else { + printf(", "); + } + } + + /* + * If lowest_eightbit is anything else but 999, + * this can't be 7-bit only. + */ + if (lowest_eight != 999 && !RawUni) { + RawUni = UCT_ENC_8BIT; } - /* If lowest_eightbit is anything else but 999, this can't be 7-bit - * only. */ - if (lowest_eight != 999 && !RawUni) - RawUni = UCT_ENC_8BIT; - - if (nuni) - printf("\nstatic u16 dfont_unitable%s[%d] = \n{\n\t", id_append, nuni); - else - printf("\nstatic u16 dfont_unitable%s[1]; /* dummy */\n", id_append); - - fp0 = 0; - nent = 0; - for ( i = 0 ; i < nuni ; i++ ) - { - while ( nent >= unicount[fp0] ) - { - fp0++; - nent = 0; - } - printf("0x%04x", unitable[fp0][nent++]); - if ( i == nuni-1 ) - printf("\n};\n"); - else if ( i % 8 == 7 ) - printf(",\n\t"); - else - printf(", "); + if (nuni) { + printf("\nstatic u16 dfont_unitable%s[%d] = \n{\n\t", + id_append, nuni); + } else { + printf("\nstatic u16 dfont_unitable%s[1]; /* dummy */\n", id_append); } - if (themap_str.entry_ct) - printf("\n\ + fp0 = 0; + nent = 0; + for (i = 0; i < nuni; i++) { + while (nent >= unicount[fp0]) { + fp0++; + nent = 0; + } + printf("0x%04x", unitable[fp0][nent++]); + if (i == (nuni - 1)) { + printf("\n};\n"); + } else if ((i % 8) == 7) { + printf(",\n\t"); + } else { + printf(", "); + } + } + + if (themap_str.entry_ct) { + printf("\n\ static struct unipair_str repl_map%s[%d] = \n\ {\n\t", id_append, themap_str.entry_ct); - else -printf("\n\ + } else { + printf("\n\ /* static struct unipair_str repl_map%s[]; */\n", id_append); + } - for ( i = 0 ; i < themap_str.entry_ct ; i++ ) - { - printf("{0x%x,\"%s\"}", themap_str.entries[i].unicode, - themap_str.entries[i].replace_str); - if ( i == themap_str.entry_ct-1 ) - printf("\n};\n"); - else if ( i % 4 == 3 ) - printf(",\n\t"); - else - printf(", "); + for (i = 0; i < themap_str.entry_ct; i++) { + printf("{0x%x,\"%s\"}", + themap_str.entries[i].unicode, + themap_str.entries[i].replace_str); + if (i == (themap_str.entry_ct - 1)) { + printf("\n};\n"); + } else if ((i % 4) == 3) { + printf(",\n\t"); + } else { + printf(", "); + } } - if (themap_str.entry_ct) - printf("\n\ + if (themap_str.entry_ct) { + printf("\n\ static struct unimapdesc_str dfont_replacedesc%s = {%d,repl_map%s};\n", id_append, themap_str.entry_ct, id_append); - else - printf("\n\ + } else { + printf("\n\ static struct unimapdesc_str dfont_replacedesc%s = {0,NULL};\n",id_append); + } - printf("#define UC_CHARSET_SETUP%s UC_Charset_Setup(\ + printf("#define UC_CHARSET_SETUP%s UC_Charset_Setup(\ \"%s\",\\\n\"%s\",\\\n\ dfont_unicount%s,dfont_unitable%s,%i,\\\n\ dfont_replacedesc%s,%i,%i)\n", id_append, this_MIMEcharset, this_LYNXcharset, id_append, id_append, nuni, id_append, lowest_eight, RawUni); - exit(EX_OK); + exit(EX_OK); } diff --git a/src/chrtrans/mnemonic_suni.tbl b/src/chrtrans/mnemonic_suni.tbl index d2f05d89..7f08408c 100644 --- a/src/chrtrans/mnemonic_suni.tbl +++ b/src/chrtrans/mnemonic_suni.tbl @@ -2,7 +2,7 @@ Mmnemonic #Name as a Display Charset (used on Options screen) -ORFC1345 Mnemonic +ORFC 1345 Mnemonic # U+0020:&SP U+0021:! diff --git a/src/descrip.mms b/src/descrip.mms index 389514f0..6b1316a8 100644 --- a/src/descrip.mms +++ b/src/descrip.mms @@ -1,6 +1,9 @@ ! Make LYNX hypertext browser under VMS ! ===================================== ! +! NOTE: Use [.SRC.CHRTRANS]BUILD-CHRTRANS.COM to create the +! chrtrans header files before using this descrip.mms. +! ! History: ! 1/1/93 creation at KU (Lou montulli@ukanaix.cc.ukans.edu). ! 4/12/93 (seb@lns61.tn.cornell.edu) @@ -21,6 +24,7 @@ ! 07/26/95 FM Separated transport (TOPT) and compiler (COPT) option files. ! 07/29/95 FM Added support for GNUC. ! 02/29/96 FM Added LYMap. +! 06/28/97 FM Added UCAuto, UCAux, and UCdomap. ! ! Instructions: ! Use the correct command line for your TCP/IP implementation: @@ -58,7 +62,7 @@ OBJS = DefaultStyle.obj, GridText.obj, HTAlert.obj, HTFWriter.obj, - LYList.obj, LYMail.obj, LYMain.obj, LYMainLoop.obj, LYMap.obj, - LYNews.obj, LYOptions.obj, LYPrint.obj, LYrcFile.obj, LYReadCFG.obj, - LYSearch.obj, LYShowInfo.obj, LYStrings.obj, LYTraversal.obj, - - LYUpload.obj, LYUtils.obj + LYUpload.obj, LYUtils.obj, UCAuto.obj, UCAux.obj, UCdomap.obj .ifdef WIN_TCP TCP = WIN_TCP |