📄 htmlgen.c
字号:
/* HTML Generator** ==============**** This version of the HTML object sends HTML markup to the output stream.**** Bugs: Line wrapping is not done at all.** All data handled as PCDATA.** Should convert old XMP, LISTING and PLAINTEXT to PRE.**** It is not obvious to me right now whether the HEAD should be generated** from the incomming data or the anchor. Currently it is from the former** which is cleanest.*/#include <HTUtils.h>#define BUFFER_SIZE 200 /* Line buffer attempts to make neat breaks */#define MAX_CLEANNESS 20/* Implements:*/#include <HTMLGen.h>#include <HTMLDTD.h>#include <HTStream.h>#include <SGML.h>#include <HTFormat.h>#ifdef USE_COLOR_STYLE#include <LYCharUtils.h>#include <AttrList.h>#include <LYHash.h>#include <LYStyle.h>#endif#include <LYGlobalDefs.h>#include <LYLeaks.h>#define PUTC(c) (*me->targetClass.put_character)(me->target, c)/* #define PUTS(s) (*me->targetClass.put_string)(me->target, s) */#define PUTB(s,l) (*me->targetClass.put_block)(me->target, s, l)#ifdef USE_COLOR_STYLEPUBLIC char class_string[TEMPSTRINGSIZE];static char *Style_className = NULL;static char myHash[128];static int hcode;#endif/* HTML Object** -----------*/struct _HTStream { CONST HTStreamClass * isa; HTStream * target; HTStreamClass targetClass; /* COPY for speed */};struct _HTStructured { CONST HTStructuredClass * isa; HTStream * target; HTStreamClass targetClass; /* COPY for speed */ char buffer[BUFFER_SIZE+1]; /* 1for NL */ int buffer_maxchars; char * write_pointer; char * line_break [MAX_CLEANNESS+1]; int cleanness; BOOL overflowed; BOOL delete_line_break_char[MAX_CLEANNESS+1]; BOOL preformatted; BOOL escape_specials; BOOL in_attrval;#ifdef USE_COLOR_STYLE HText * text;#endif};/* Flush Buffer** ------------*/PRIVATE void flush_breaks ARGS1( HTStructured *, me){ int i; for (i=0; i<= MAX_CLEANNESS; i++) { me->line_break[i] = NULL; }}PRIVATE void HTMLGen_flush ARGS1( HTStructured *, me){ (*me->targetClass.put_block)(me->target, me->buffer, me->write_pointer - me->buffer); me->write_pointer = me->buffer; flush_breaks(me); me->cleanness = 0; me->delete_line_break_char[0] = NO;}#ifdef USE_COLOR_STYLE/* * We need to flush our buffer each time before we effect a color style * change, this also relies on the subsequent stage not doing any * buffering - this is currently true, in cases where it matters the * target stream should be the HTPlain converter. * The flushing currently prevents reasonable line breaking in lines * with tags. Since color styles help visual scanning of displayed * source lines, and long lines are wrapped in GridText anyway, this * is probably acceptable (or even A Good Thing - more to see in one * screenful). * The pointer to the HText structure is initialized here before * we effect the first style change. Getting it from the global * HTMainText variable isn't very clean, since it relies on the fact * that HText_new() has already been called for the current stream * stack's document by the time we start processing the first element; * we rely on HTMLGenerator's callers (HTMLParsedPresent in particular) * to guarantee this when it matters. Normally the target stream will * have been setup by HTPlainPresent, which does what we need in this * respect. (A check whether we have the right output stream could be * done by checking that targetClass.name is "PlainPresenter" or similar.) * * All special color style handling is only done if LYPreparsedSource * is set. We could always do it for displaying source generated by * an internal gateway, but this makes the rule more simple for the * user: color styles are applied to html source only with the * -preparsed flag. - kw */PRIVATE void do_cstyle_flush ARGS1( HTStructured *, me){ if (!me->text && LYPreparsedSource) { me->text = HTMainText; } if (me->text) { HTMLGen_flush(me); }}#endif /* COLOR_STYLE *//* Weighted optional line break**** We keep track of all the breaks for when we chop the line*/PRIVATE void allow_break ARGS3( HTStructured *, me, int, new_cleanness, BOOL, dlbc){ if (dlbc && me->write_pointer == me->buffer) dlbc = NO; me->line_break[new_cleanness] = dlbc ? me->write_pointer - 1 /* Point to space */ : me->write_pointer ; /* point to gap */ me->delete_line_break_char[new_cleanness] = dlbc; if (new_cleanness >= me->cleanness && (me->overflowed || me->line_break[new_cleanness] > me->buffer)) me->cleanness = new_cleanness;}/* Character handling** ------------------**** The tricky bits are the line break handling. This attempts** to synchrononise line breaks on sentence or phrase ends. This** is important if one stores SGML files in a line-oriented code** repository, so that if a small change is made, line ends don't** shift in a ripple-through to apparently change a large part of the** file. We give extra "cleanness" to spaces appearing directly** after periods (full stops), [semi]colons and commas.** This should make the source files easier to read and modify** by hand, too, though this is not a primary design consideration. TBL*/PRIVATE void HTMLGen_put_character ARGS2( HTStructured *, me, char, c){ if (me->escape_specials && UCH(c) < 32) { if (c == HT_NON_BREAK_SPACE || c == HT_EN_SPACE || c == LY_SOFT_HYPHEN) { /* recursion... */ HTMLGen_put_character(me, '&'); HTMLGen_put_character(me, '#'); HTMLGen_put_character(me, 'x'); switch(c) { case HT_NON_BREAK_SPACE: /*   */ HTMLGen_put_character(me, 'A'); HTMLGen_put_character(me, '0'); break; case HT_EN_SPACE: /*   */ HTMLGen_put_character(me, '2'); HTMLGen_put_character(me, '0'); HTMLGen_put_character(me, '0'); HTMLGen_put_character(me, '2'); break; case LY_SOFT_HYPHEN: /* ­ */ HTMLGen_put_character(me, 'A'); HTMLGen_put_character(me, 'D'); break; } c = ';'; } } *me->write_pointer++ = c; if (c == '\n') { HTMLGen_flush(me); return; } /* Figure our whether we can break at this point */ if ((!me->preformatted && (c == ' ' || c == '\t'))) { int new_cleanness = 3; if (me->write_pointer > (me->buffer + 1)) { char delims[5]; char * p; strcpy(delims, ",;:."); /* @@ english bias */ p = strchr(delims, me->write_pointer[-2]); if (p) new_cleanness = p - delims + 6; if (!me->in_attrval) new_cleanness += 10; } allow_break(me, new_cleanness, YES); } /* * Flush buffer out when full, or whenever the line is over * the nominal maximum and we can break at all */ if (me->write_pointer >= me->buffer + me->buffer_maxchars || (me->overflowed && me->cleanness)) { if (me->cleanness) { char line_break_char = me->line_break[me->cleanness][0]; char * saved = me->line_break[me->cleanness]; if (me->delete_line_break_char[me->cleanness]) saved++; me->line_break[me->cleanness][0] = '\n'; (*me->targetClass.put_block)(me->target, me->buffer, me->line_break[me->cleanness] - me->buffer + 1); me->line_break[me->cleanness][0] = line_break_char; { /* move next line in */ char * p = saved; char *q; for (q = me->buffer; p < me->write_pointer; ) *q++ = *p++; } me->cleanness = 0; /* Now we have to check whether ther are any perfectly good breaks ** which weren't good enough for the last line but may be ** good enough for the next */ { int i; for(i=0; i <= MAX_CLEANNESS; i++) { if (me->line_break[i] != NULL && me->line_break[i] > saved) { me->line_break[i] = me->line_break[i] - (saved-me->buffer); me->cleanness = i; } else { me->line_break[i] = NULL; } } } me->delete_line_break_char[0] = 0; me->write_pointer = me->write_pointer - (saved-me->buffer); me->overflowed = NO; } else { (*me->targetClass.put_block)(me->target, me->buffer, me->buffer_maxchars); me->write_pointer = me->buffer; flush_breaks(me); me->overflowed = YES; } }}/* String handling** ---------------*/PRIVATE void HTMLGen_put_string ARGS2( HTStructured *, me, CONST char *, s){ CONST char * p; for (p = s; *p; p++) HTMLGen_put_character(me, *p);}PRIVATE void HTMLGen_write ARGS3( HTStructured *, me, CONST char *, s, int, l){ CONST char * p; for (p = s; p < (s + l); p++) HTMLGen_put_character(me, *p);}/* Start Element** -------------**** Within the opening tag, there may be spaces** and the line may be broken at these spaces.*/PRIVATE int HTMLGen_start_element ARGS6( HTStructured *, me, int, element_number, CONST BOOL*, present, CONST char **, value, int, charset GCC_UNUSED, char **, insert GCC_UNUSED){ int i; BOOL was_preformatted = me->preformatted; HTTag * tag = &HTML_dtd.tags[element_number];#if defined(USE_COLOR_STYLE) char *title = NULL; char *title_tmp = NULL; if (LYPreparsedSource) { /* * Same logic as in HTML_start_element, copied from there. - kw */ HTSprintf (&Style_className, ";%s", HTML_dtd.tags[element_number].name); strcpy (myHash, HTML_dtd.tags[element_number].name); if (class_string[0]) { int len = strlen(myHash); sprintf (myHash + len, ".%.*s", (int) sizeof(myHash) - len - 2, class_string); HTSprintf (&Style_className, ".%s", class_string); } class_string[0] = '\0'; strtolower(myHash); hcode = hash_code(myHash); strtolower(Style_className); if (TRACE_STYLE) { fprintf(tfp, "CSSTRIM:%s -> %d", myHash, hcode); if (hashStyles[hcode].code!=hcode) { char *rp = strrchr(myHash, '.'); fprintf(tfp, " (undefined) %s\n", myHash); if (rp) { int hcd; *rp = '\0'; /* trim the class */ hcd = hash_code(myHash); fprintf(tfp, "CSS:%s -> %d", myHash, hcd); if (hashStyles[hcd].code!=hcd) fprintf(tfp, " (undefined) %s\n", myHash); else fprintf(tfp, " ca=%d\n", hashStyles[hcd].color); } } else fprintf(tfp, " ca=%d\n", hashStyles[hcode].color); } if (displayStyles[element_number + STARTAT].color > -2) /* actually set */ { CTRACE2(TRACE_STYLE, (tfp, "CSSTRIM: start_element: top <%s>\n", HTML_dtd.tags[element_number].name)); do_cstyle_flush(me); HText_characterStyle(me->text, hcode, 1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -