CTRACE(tfp, "HTGopher: Bad menu item.\n");
CTRACE((tfp, "HTGopher: Bad menu item.\n"));
PRIVATE void parse_menu ARGS2(	CONST char *,		arg GCC_UNUSED,	HTParentAnchor *,	anAnchor){    char gtype;    int ich;    char line[BIG];    char *name = NULL, *selector = NULL;	/* Gopher menu fields */    char *host = NULL;    char *port;    char *p = line;    CONST char *title;    int bytes = 0;    int BytesReported = 0;    char buffer[128];#define TAB		'\t'#define HEX_ESCAPE	'%'    START(HTML_HTML);    PUTC('\n');    START(HTML_HEAD);    PUTC('\n');    START(HTML_TITLE);    if ((title = HTAnchor_title(anAnchor)))	PUTS(title);    else	PUTS(GOPHER_MENU_TITLE);    END(HTML_TITLE);    PUTC('\n');    END(HTML_HEAD);    PUTC('\n');    START(HTML_BODY);    PUTC('\n');    START(HTML_H1);    if ((title = HTAnchor_title(anAnchor)))	PUTS(title);    else	PUTS(GOPHER_MENU_TITLE);    END(HTML_H1);    PUTC('\n');    START(HTML_PRE);    while ((ich=NEXT_CHAR) != EOF) {	if (interrupted_in_htgetcharacter) {	    CTRACE(tfp, "HTGopher: Interrupted in HTGetCharacter, apparently.\n");	    goto end_html;	}	if ((char)ich != LF) {	    *p = ich;		/* Put character in line */	    if (p< &line[BIG-1]) p++;	} else {	    *p++ = '\0';	/* Terminate line */	    bytes += p-line;	/* add size */	    p = line;		/* Scan it to parse it */	    port = 0;		/* Flag "not parsed" */	    CTRACE(tfp, "HTGopher: Menu item: %s\n", line);	    gtype = *p++;	    if (bytes > BytesReported + 1024) {		sprintf(buffer, TRANSFERRED_X_BYTES, bytes);		HTProgress(buffer);		BytesReported = bytes;	    }	    /* Break on line with a dot by itself */	    if ((gtype=='.') && ((*p=='\r') || (*p==0)))		break;	    if (gtype && *p) {		name = p;		selector = strchr(name, TAB);		if (selector) {		    *selector++ = '\0'; /* Terminate name */		    /*		     * Gopher+ Type=0+ objects can be binary, and will		     * have 9 or 5 beginning their selector.  Make sure		     * we don't trash the terminal by treating them as		     * text. - FM		     */		    if (gtype == GOPHER_TEXT && (*selector == GOPHER_BINARY ||						 *selector == GOPHER_PCBINARY))			gtype = *selector;		    host = strchr(selector, TAB);		    if (host) {			*host++ = '\0'; /* Terminate selector */			port = strchr(host, TAB);			if (port) {			    char *junk;			    port[0] = ':';	/* delimit host a la W3 */			    junk = strchr(port, TAB);			    if (junk) *junk++ = '\0';	/* Chop port */			    if ((port[1]=='0') && (!port[2]))				port[0] = '\0'; /* 0 means none */			} /* no port */		    } /* host ok */		} /* selector ok */	    } /* gtype and name ok */	    /* Nameless files are a separator line */	    if (gtype == GOPHER_TEXT) {		int i = strlen(name)-1;		while (name[i] == ' ' && i >= 0)		    name[i--] = '\0';		if (i < 0)		    gtype = GOPHER_INFO;	    }	    if (gtype == GOPHER_WWW) {	/* Gopher pointer to W3 */		PUTS("(HTML) ");		write_anchor(name, selector);	    } else if (gtype == GOPHER_INFO) {	    /* Information or separator line */		PUTS("       ");		PUTS(name);	    } else if (port) {		/* Other types need port */		char *address = 0;		if (gtype == GOPHER_TELNET) {		    PUTS(" (TEL) ");		    if (*selector)			HTSprintf0(&address, "telnet://%s@%s/",					   selector, host);		    else			HTSprintf0(&address, "telnet://%s/", host);		}		else if (gtype == GOPHER_TN3270)		{		    PUTS("(3270) ");		    if (*selector)			HTSprintf0(&address, "tn3270://%s@%s/",				selector, host);		    else			HTSprintf0(&address, "tn3270://%s/", host);		}		else {			/* If parsed ok */		    char *r;		    switch(gtype) {			case GOPHER_TEXT:			    PUTS("(FILE) ");			    break;			case GOPHER_MENU:			    PUTS(" (DIR) ");			    break;			case GOPHER_CSO:			    PUTS(" (CSO) ");			    break;			case GOPHER_PCBINARY:			    PUTS(" (BIN) ");			    break;			case GOPHER_UUENCODED:			    PUTS(" (UUE) ");			    break;			case GOPHER_INDEX:			    PUTS("  (?)  ");			    break;			case GOPHER_BINARY:			    PUTS(" (BIN) ");			    break;			case GOPHER_GIF:			case GOPHER_IMAGE:			case GOPHER_PLUS_IMAGE:			    PUTS(" (IMG) ");			    break;			case GOPHER_SOUND:			case GOPHER_PLUS_SOUND:			    PUTS(" (SND) ");			    break;			case GOPHER_MACBINHEX:			    PUTS(" (HQX) ");			    break;			case GOPHER_HTML:			case GOPHER_CHTML:			    PUTS("(HTML) ");			    break;			case 'm':			    PUTS("(MIME) ");			    break;			case GOPHER_PLUS_MOVIE:			    PUTS(" (MOV) ");			    break;			case GOPHER_PLUS_PDF:			    PUTS(" (PDF) ");			    break;			default:			    PUTS("(UNKN) ");			    break;		    }		    HTSprintf0(&address, "//%s/%c", host, gtype);		    for(r = selector; *r; r++) { /* Encode selector string */			if (acceptable[(unsigned char)*r]) {			    HTSprintf(&address, "%c", *r);			} else {			    HTSprintf(&address, "%c%c%c",				HEX_ESCAPE,	/* Means hex coming */				hex[(TOASCII(*r)) >> 4],				hex[(TOASCII(*r)) & 15]);			}		    }		}		/* Error response from Gopher doesn't deserve to		   be a hyperlink. */		if (strcmp (address, "gopher://error.host:1/0"))		    write_anchor(name, address);		else		    PUTS(name);		FREE(address);	    } else { /* parse error */		CTRACE(tfp, "HTGopher: Bad menu item.\n");		PUTS(line);	    } /* parse error */	    PUTC('\n');	    p = line;	/* Start again at beginning of line */	} /* if end of line */    } /* Loop over characters */end_html:    END(HTML_PRE);    PUTC('\n');    END(HTML_BODY);    PUTC('\n');    END(HTML_HTML);    PUTC('\n');    FREE_TARGET;    return;}