HTMLGen.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. /* HTML Generator
  2. * ==============
  3. *
  4. * This version of the HTML object sends HTML markup to the output stream.
  5. *
  6. * Bugs: Line wrapping is not done at all.
  7. * All data handled as PCDATA.
  8. * Should convert old XMP, LISTING and PLAINTEXT to PRE.
  9. *
  10. * It is not obvious to me right now whether the HEAD should be generated
  11. * from the incomming data or the anchor. Currently it is from the former
  12. * which is cleanest.
  13. */
  14. #include <HTUtils.h>
  15. #define BUFFER_SIZE 200 /* Line buffer attempts to make neat breaks */
  16. #define MAX_CLEANNESS 20
  17. /* Implements:
  18. */
  19. #include <HTMLGen.h>
  20. #include <HTMLDTD.h>
  21. #include <HTStream.h>
  22. #include <SGML.h>
  23. #include <HTFormat.h>
  24. #ifdef USE_COLOR_STYLE
  25. #include <LYCharUtils.h>
  26. #include <AttrList.h>
  27. #include <LYHash.h>
  28. #include <LYStyle.h>
  29. #endif
  30. #include <LYGlobalDefs.h>
  31. #include <LYCurses.h>
  32. #include <LYLeaks.h>
  33. #define PUTC(c) (*me->targetClass.put_character)(me->target, c)
  34. /* #define PUTS(s) (*me->targetClass.put_string)(me->target, s) */
  35. #define PUTB(s,l) (*me->targetClass.put_block)(me->target, s, l)
  36. #ifdef USE_COLOR_STYLE
  37. char class_string[TEMPSTRINGSIZE];
  38. static char *Style_className = NULL;
  39. static char myHash[128];
  40. static int hcode;
  41. #endif
  42. /* HTML Object
  43. * -----------
  44. */
  45. struct _HTStream {
  46. const HTStreamClass *isa;
  47. HTStream *target;
  48. HTStreamClass targetClass; /* COPY for speed */
  49. };
  50. struct _HTStructured {
  51. const HTStructuredClass *isa;
  52. HTStream *target;
  53. HTStreamClass targetClass; /* COPY for speed */
  54. char buffer[BUFFER_SIZE + 1]; /* 1for NL */
  55. int buffer_maxchars;
  56. char *write_pointer;
  57. char *line_break[MAX_CLEANNESS + 1];
  58. int cleanness;
  59. BOOL overflowed;
  60. BOOL delete_line_break_char[MAX_CLEANNESS + 1];
  61. BOOL preformatted;
  62. BOOL escape_specials;
  63. BOOL in_attrval;
  64. #ifdef USE_COLOR_STYLE
  65. HText *text;
  66. #endif
  67. };
  68. /* Flush Buffer
  69. * ------------
  70. */
  71. static void flush_breaks(HTStructured * me)
  72. {
  73. int i;
  74. for (i = 0; i <= MAX_CLEANNESS; i++) {
  75. me->line_break[i] = NULL;
  76. }
  77. }
  78. static void HTMLGen_flush(HTStructured * me)
  79. {
  80. (*me->targetClass.put_block) (me->target,
  81. me->buffer,
  82. me->write_pointer - me->buffer);
  83. me->write_pointer = me->buffer;
  84. flush_breaks(me);
  85. me->cleanness = 0;
  86. me->delete_line_break_char[0] = NO;
  87. }
  88. #ifdef USE_COLOR_STYLE
  89. /*
  90. * We need to flush our buffer each time before we effect a color style change,
  91. * this also relies on the subsequent stage not doing any buffering - this is
  92. * currently true, in cases where it matters the target stream should be the
  93. * HTPlain converter. The flushing currently prevents reasonable line breaking
  94. * in lines with tags. Since color styles help visual scanning of displayed
  95. * source lines, and long lines are wrapped in GridText anyway, this is
  96. * probably acceptable (or even A Good Thing - more to see in one screenful).
  97. * The pointer to the HText structure is initialized here before we effect the
  98. * first style change. Getting it from the global HTMainText variable isn't
  99. * very clean, since it relies on the fact that HText_new() has already been
  100. * called for the current stream stack's document by the time we start
  101. * processing the first element; we rely on HTMLGenerator's callers
  102. * (HTMLParsedPresent in particular) to guarantee this when it matters.
  103. * Normally the target stream will have been setup by HTPlainPresent, which
  104. * does what we need in this respect. (A check whether we have the right
  105. * output stream could be done by checking that targetClass.name is
  106. * "PlainPresenter" or similar.)
  107. *
  108. * All special color style handling is only done if LYPreparsedSource is set.
  109. * We could always do it for displaying source generated by an internal
  110. * gateway, but this makes the rule more simple for the user: color styles are
  111. * applied to html source only with the -preparsed flag. - kw
  112. */
  113. static void do_cstyle_flush(HTStructured * me)
  114. {
  115. if (!me->text && LYPreparsedSource) {
  116. me->text = HTMainText;
  117. }
  118. if (me->text) {
  119. HTMLGen_flush(me);
  120. }
  121. }
  122. #endif /* COLOR_STYLE */
  123. /* Weighted optional line break
  124. *
  125. * We keep track of all the breaks for when we chop the line
  126. */
  127. static void allow_break(HTStructured * me, int new_cleanness,
  128. BOOL dlbc)
  129. {
  130. if (dlbc && me->write_pointer == me->buffer)
  131. dlbc = NO;
  132. me->line_break[new_cleanness] =
  133. dlbc ? me->write_pointer - 1 /* Point to space */
  134. : me->write_pointer; /* point to gap */
  135. me->delete_line_break_char[new_cleanness] = dlbc;
  136. if (new_cleanness >= me->cleanness &&
  137. (me->overflowed || me->line_break[new_cleanness] > me->buffer))
  138. me->cleanness = new_cleanness;
  139. }
  140. /* Character handling
  141. * ------------------
  142. *
  143. * The tricky bits are the line break handling. This attempts
  144. * to synchrononise line breaks on sentence or phrase ends. This
  145. * is important if one stores SGML files in a line-oriented code
  146. * repository, so that if a small change is made, line ends don't
  147. * shift in a ripple-through to apparently change a large part of the
  148. * file. We give extra "cleanness" to spaces appearing directly
  149. * after periods (full stops), [semi]colons and commas.
  150. * This should make the source files easier to read and modify
  151. * by hand, too, though this is not a primary design consideration. TBL
  152. */
  153. static void HTMLGen_put_character(HTStructured * me, char c)
  154. {
  155. if (me->escape_specials && UCH(c) < 32) {
  156. if (c == HT_NON_BREAK_SPACE || c == HT_EN_SPACE ||
  157. c == LY_SOFT_HYPHEN) { /* recursion... */
  158. HTMLGen_put_character(me, '&');
  159. HTMLGen_put_character(me, '#');
  160. HTMLGen_put_character(me, 'x');
  161. switch (c) {
  162. case HT_NON_BREAK_SPACE: /* &#xA0; */
  163. HTMLGen_put_character(me, 'A');
  164. HTMLGen_put_character(me, '0');
  165. break;
  166. case HT_EN_SPACE: /* &#x2002; */
  167. HTMLGen_put_character(me, '2');
  168. HTMLGen_put_character(me, '0');
  169. HTMLGen_put_character(me, '0');
  170. HTMLGen_put_character(me, '2');
  171. break;
  172. case LY_SOFT_HYPHEN: /* &#xAD; */
  173. HTMLGen_put_character(me, 'A');
  174. HTMLGen_put_character(me, 'D');
  175. break;
  176. }
  177. c = ';';
  178. }
  179. }
  180. *me->write_pointer++ = c;
  181. if (c == '\n') {
  182. HTMLGen_flush(me);
  183. return;
  184. }
  185. /* Figure our whether we can break at this point
  186. */
  187. if ((!me->preformatted && (c == ' ' || c == '\t'))) {
  188. int new_cleanness = 3;
  189. if (me->write_pointer > (me->buffer + 1)) {
  190. char delims[5];
  191. char *p;
  192. strcpy(delims, ",;:."); /* @@ english bias */
  193. p = strchr(delims, me->write_pointer[-2]);
  194. if (p)
  195. new_cleanness = p - delims + 6;
  196. if (!me->in_attrval)
  197. new_cleanness += 10;
  198. }
  199. allow_break(me, new_cleanness, YES);
  200. }
  201. /*
  202. * Flush buffer out when full, or whenever the line is over the nominal
  203. * maximum and we can break at all
  204. */
  205. if (me->write_pointer >= me->buffer + me->buffer_maxchars ||
  206. (me->overflowed && me->cleanness)) {
  207. if (me->cleanness) {
  208. char line_break_char = me->line_break[me->cleanness][0];
  209. char *saved = me->line_break[me->cleanness];
  210. if (me->delete_line_break_char[me->cleanness])
  211. saved++;
  212. me->line_break[me->cleanness][0] = '\n';
  213. (*me->targetClass.put_block) (me->target,
  214. me->buffer,
  215. me->line_break[me->cleanness] -
  216. me->buffer + 1);
  217. me->line_break[me->cleanness][0] = line_break_char;
  218. { /* move next line in */
  219. char *p = saved;
  220. char *q;
  221. for (q = me->buffer; p < me->write_pointer;)
  222. *q++ = *p++;
  223. }
  224. me->cleanness = 0;
  225. /* Now we have to check whether ther are any perfectly good breaks
  226. * which weren't good enough for the last line but may be good
  227. * enough for the next
  228. */
  229. {
  230. int i;
  231. for (i = 0; i <= MAX_CLEANNESS; i++) {
  232. if (me->line_break[i] != NULL &&
  233. me->line_break[i] > saved) {
  234. me->line_break[i] = me->line_break[i] -
  235. (saved - me->buffer);
  236. me->cleanness = i;
  237. } else {
  238. me->line_break[i] = NULL;
  239. }
  240. }
  241. }
  242. me->delete_line_break_char[0] = 0;
  243. me->write_pointer = me->write_pointer - (saved - me->buffer);
  244. me->overflowed = NO;
  245. } else {
  246. (*me->targetClass.put_block) (me->target,
  247. me->buffer,
  248. me->buffer_maxchars);
  249. me->write_pointer = me->buffer;
  250. flush_breaks(me);
  251. me->overflowed = YES;
  252. }
  253. }
  254. }
  255. /* String handling
  256. * ---------------
  257. */
  258. static void HTMLGen_put_string(HTStructured * me, const char *s)
  259. {
  260. const char *p;
  261. for (p = s; *p; p++)
  262. HTMLGen_put_character(me, *p);
  263. }
  264. static void HTMLGen_write(HTStructured * me, const char *s,
  265. int l)
  266. {
  267. const char *p;
  268. for (p = s; p < (s + l); p++)
  269. HTMLGen_put_character(me, *p);
  270. }
  271. /* Start Element
  272. * -------------
  273. *
  274. * Within the opening tag, there may be spaces and the line may be broken at
  275. * these spaces.
  276. */
  277. static int HTMLGen_start_element(HTStructured * me, int element_number,
  278. const BOOL *present,
  279. const char **value,
  280. int charset GCC_UNUSED,
  281. char **insert GCC_UNUSED)
  282. {
  283. int i;
  284. BOOL was_preformatted = me->preformatted;
  285. HTTag *tag = &HTML_dtd.tags[element_number];
  286. #if defined(USE_COLOR_STYLE)
  287. char *title = NULL;
  288. char *title_tmp = NULL;
  289. if (LYPreparsedSource) {
  290. /*
  291. * Same logic as in HTML_start_element, copied from there. - kw
  292. */
  293. HTSprintf(&Style_className, ";%s", HTML_dtd.tags[element_number].name);
  294. strcpy(myHash, HTML_dtd.tags[element_number].name);
  295. if (class_string[0]) {
  296. int len = strlen(myHash);
  297. sprintf(myHash + len, ".%.*s", (int) sizeof(myHash) - len - 2, class_string);
  298. HTSprintf(&Style_className, ".%s", class_string);
  299. }
  300. class_string[0] = '\0';
  301. strtolower(myHash);
  302. hcode = hash_code(myHash);
  303. strtolower(Style_className);
  304. if (TRACE_STYLE) {
  305. fprintf(tfp, "CSSTRIM:%s -> %d", myHash, hcode);
  306. if (hashStyles[hcode].code != hcode) {
  307. char *rp = strrchr(myHash, '.');
  308. fprintf(tfp, " (undefined) %s\n", myHash);
  309. if (rp) {
  310. int hcd;
  311. *rp = '\0'; /* trim the class */
  312. hcd = hash_code(myHash);
  313. fprintf(tfp, "CSS:%s -> %d", myHash, hcd);
  314. if (hashStyles[hcd].code != hcd)
  315. fprintf(tfp, " (undefined) %s\n", myHash);
  316. else
  317. fprintf(tfp, " ca=%d\n", hashStyles[hcd].color);
  318. }
  319. } else
  320. fprintf(tfp, " ca=%d\n", hashStyles[hcode].color);
  321. }
  322. if (displayStyles[element_number + STARTAT].color > -2) {
  323. CTRACE2(TRACE_STYLE,
  324. (tfp, "CSSTRIM: start_element: top <%s>\n",
  325. HTML_dtd.tags[element_number].name));
  326. do_cstyle_flush(me);
  327. HText_characterStyle(me->text, hcode, 1);
  328. }
  329. }
  330. #endif /* USE_COLOR_STYLE */
  331. me->preformatted = YES; /* free text within tags */
  332. HTMLGen_put_character(me, '<');
  333. HTMLGen_put_string(me, tag->name);
  334. if (present) {
  335. BOOL had_attr = NO;
  336. for (i = 0; i < tag->number_of_attributes; i++) {
  337. if (present[i]) {
  338. had_attr = YES;
  339. HTMLGen_put_character(me, ' ');
  340. allow_break(me, 11, YES);
  341. #ifdef USE_COLOR_STYLE
  342. /*
  343. * Try to mimic HTML_start_element's special handling for
  344. * HTML_LINK. If applicable, color the displayed attribute /
  345. * value pairs differently. - kw
  346. */
  347. if (LYPreparsedSource &&
  348. element_number == HTML_LINK && !title &&
  349. present[HTML_LINK_CLASS] &&
  350. value && *value[HTML_LINK_CLASS] != '\0' &&
  351. !present[HTML_LINK_REV] &&
  352. (present[HTML_LINK_REL] || present[HTML_LINK_HREF])) {
  353. if (present[HTML_LINK_TITLE] && *value[HTML_LINK_TITLE]) {
  354. StrAllocCopy(title, value[HTML_LINK_TITLE]);
  355. LYTrimHead(title);
  356. LYTrimTail(title);
  357. }
  358. if ((!title || *title == '\0') && present[HTML_LINK_REL]) {
  359. StrAllocCopy(title, value[HTML_LINK_REL]);
  360. }
  361. if (title && *title) {
  362. HTSprintf0(&title_tmp, "link.%s.%s",
  363. value[HTML_LINK_CLASS], title);
  364. CTRACE2(TRACE_STYLE,
  365. (tfp, "CSSTRIM:link=%s\n", title_tmp));
  366. do_cstyle_flush(me);
  367. HText_characterStyle(me->text, hash_code(title_tmp), 1);
  368. }
  369. }
  370. #endif
  371. HTMLGen_put_string(me, tag->attributes[i].name);
  372. if (value[i]) {
  373. me->preformatted = was_preformatted;
  374. me->in_attrval = YES;
  375. if (strchr(value[i], '"') == NULL) {
  376. HTMLGen_put_string(me, "=\"");
  377. HTMLGen_put_string(me, value[i]);
  378. HTMLGen_put_character(me, '"');
  379. } else if (strchr(value[i], '\'') == NULL) {
  380. HTMLGen_put_string(me, "='");
  381. HTMLGen_put_string(me, value[i]);
  382. HTMLGen_put_character(me, '\'');
  383. } else { /* attribute value has both kinds of quotes */
  384. const char *p;
  385. HTMLGen_put_string(me, "=\"");
  386. for (p = value[i]; *p; p++) {
  387. if (*p != '"') {
  388. HTMLGen_put_character(me, *p);
  389. } else {
  390. HTMLGen_put_string(me, "&#34;");
  391. }
  392. }
  393. HTMLGen_put_character(me, '"');
  394. }
  395. me->preformatted = YES;
  396. me->in_attrval = NO;
  397. }
  398. }
  399. }
  400. #ifdef USE_COLOR_STYLE
  401. if (had_attr && LYPreparsedSource && element_number == HTML_LINK) {
  402. /*
  403. * Clean up after special HTML_LINK handling - kw
  404. */
  405. if (title && *title) {
  406. do_cstyle_flush(me);
  407. HText_characterStyle(me->text, hash_code(title_tmp), 0);
  408. FREE(title_tmp);
  409. }
  410. FREE(title);
  411. }
  412. #endif
  413. if (had_attr)
  414. allow_break(me, 12, NO);
  415. }
  416. HTMLGen_put_string(me, ">"); /* got rid of \n LJM */
  417. /*
  418. * Make very specific HTML assumption that PRE can't be nested!
  419. */
  420. me->preformatted = (element_number == HTML_PRE) ? YES : was_preformatted;
  421. /*
  422. * Can break after element start.
  423. */
  424. if (!me->preformatted && tag->contents != SGML_EMPTY) {
  425. if (HTML_dtd.tags[element_number].contents == SGML_ELEMENT)
  426. allow_break(me, 15, NO);
  427. else
  428. allow_break(me, 2, NO);
  429. }
  430. #if defined(USE_COLOR_STYLE)
  431. /*
  432. * Same logic as in HTML_start_element, copied from there. - kw
  433. */
  434. /* end really empty tags straight away */
  435. if (LYPreparsedSource && ReallyEmptyTagNum(element_number)) {
  436. CTRACE2(TRACE_STYLE,
  437. (tfp, "STYLE:begin_element:ending EMPTY element style\n"));
  438. do_cstyle_flush(me);
  439. HText_characterStyle(me->text, hcode, STACK_OFF);
  440. TrimColorClass(HTML_dtd.tags[element_number].name,
  441. Style_className, &hcode);
  442. }
  443. #endif /* USE_COLOR_STYLE */
  444. if (element_number == HTML_OBJECT && tag->contents == SGML_LITTERAL) {
  445. /*
  446. * These conditions only approximate the ones used in HTML.c. Let our
  447. * SGML parser know that further content is to be parsed normally not
  448. * literally. - kw
  449. */
  450. if (!present) {
  451. return HT_PARSER_OTHER_CONTENT;
  452. } else if (!present[HTML_OBJECT_DECLARE] &&
  453. !(present[HTML_OBJECT_NAME] &&
  454. value[HTML_OBJECT_NAME] && *value[HTML_OBJECT_NAME])) {
  455. if (present[HTML_OBJECT_SHAPES] ||
  456. !(present[HTML_OBJECT_USEMAP] &&
  457. value[HTML_OBJECT_USEMAP] && *value[HTML_OBJECT_USEMAP]))
  458. return HT_PARSER_OTHER_CONTENT;
  459. }
  460. }
  461. return HT_OK;
  462. }
  463. /* End Element
  464. * -----------
  465. *
  466. * When we end an element, the style must be returned to that in effect before
  467. * that element. Note that anchors (etc?) don't have an associated style, so
  468. * that we must scan down the stack for an element with a defined style. (In
  469. * fact, the styles should be linked to the whole stack not just the top one.)
  470. * TBL 921119
  471. */
  472. static int HTMLGen_end_element(HTStructured * me, int element_number,
  473. char **insert GCC_UNUSED)
  474. {
  475. if (!me->preformatted &&
  476. HTML_dtd.tags[element_number].contents != SGML_EMPTY) {
  477. /*
  478. * Can break before element end.
  479. */
  480. if (HTML_dtd.tags[element_number].contents == SGML_ELEMENT)
  481. allow_break(me, 14, NO);
  482. else
  483. allow_break(me, 1, NO);
  484. }
  485. HTMLGen_put_string(me, "</");
  486. HTMLGen_put_string(me, HTML_dtd.tags[element_number].name);
  487. HTMLGen_put_character(me, '>');
  488. if (element_number == HTML_PRE) {
  489. me->preformatted = NO;
  490. }
  491. #ifdef USE_COLOR_STYLE
  492. /*
  493. * Same logic as in HTML_end_element, copied from there. - kw
  494. */
  495. TrimColorClass(HTML_dtd.tags[element_number].name,
  496. Style_className, &hcode);
  497. if (LYPreparsedSource && !ReallyEmptyTagNum(element_number)) {
  498. CTRACE2(TRACE_STYLE,
  499. (tfp, "STYLE:end_element: ending non-EMPTY style\n"));
  500. do_cstyle_flush(me);
  501. HText_characterStyle(me->text, hcode, STACK_OFF);
  502. }
  503. #endif /* USE_COLOR_STYLE */
  504. return HT_OK;
  505. }
  506. /* Expanding entities
  507. * ------------------
  508. *
  509. */
  510. static int HTMLGen_put_entity(HTStructured * me, int entity_number)
  511. {
  512. int nent = HTML_dtd.number_of_entities;
  513. HTMLGen_put_character(me, '&');
  514. if (entity_number < nent) {
  515. HTMLGen_put_string(me, HTML_dtd.entity_names[entity_number]);
  516. }
  517. HTMLGen_put_character(me, ';');
  518. return HT_OK;
  519. }
  520. /* Free an HTML object
  521. * -------------------
  522. *
  523. */
  524. static void HTMLGen_free(HTStructured * me)
  525. {
  526. (*me->targetClass.put_character) (me->target, '\n');
  527. HTMLGen_flush(me);
  528. (*me->targetClass._free) (me->target); /* ripple through */
  529. #ifdef USE_COLOR_STYLE
  530. FREE(Style_className);
  531. #endif
  532. FREE(me);
  533. }
  534. static void PlainToHTML_free(HTStructured * me)
  535. {
  536. HTMLGen_end_element(me, HTML_PRE, 0);
  537. HTMLGen_free(me);
  538. }
  539. static void HTMLGen_abort(HTStructured * me, HTError e GCC_UNUSED)
  540. {
  541. HTMLGen_free(me);
  542. #ifdef USE_COLOR_STYLE
  543. FREE(Style_className);
  544. #endif
  545. }
  546. static void PlainToHTML_abort(HTStructured * me, HTError e GCC_UNUSED)
  547. {
  548. PlainToHTML_free(me);
  549. }
  550. /* Structured Object Class
  551. * -----------------------
  552. */
  553. static const HTStructuredClass HTMLGeneration = /* As opposed to print etc */
  554. {
  555. "HTMLGen",
  556. HTMLGen_free,
  557. HTMLGen_abort,
  558. HTMLGen_put_character, HTMLGen_put_string, HTMLGen_write,
  559. HTMLGen_start_element, HTMLGen_end_element,
  560. HTMLGen_put_entity
  561. };
  562. /* Subclass-specific Methods
  563. * -------------------------
  564. */
  565. HTStructured *HTMLGenerator(HTStream *output)
  566. {
  567. HTStructured *me = (HTStructured *) malloc(sizeof(*me));
  568. if (me == NULL)
  569. outofmem(__FILE__, "HTMLGenerator");
  570. me->isa = &HTMLGeneration;
  571. me->target = output;
  572. me->targetClass = *me->target->isa; /* Copy pointers to routines for speed */
  573. me->write_pointer = me->buffer;
  574. flush_breaks(me);
  575. me->line_break[0] = me->buffer;
  576. me->cleanness = 0;
  577. me->overflowed = NO;
  578. me->delete_line_break_char[0] = NO;
  579. me->preformatted = NO;
  580. me->in_attrval = NO;
  581. /*
  582. * For what line length should we attempt to wrap ? - kw
  583. */
  584. if (!LYPreparsedSource) {
  585. me->buffer_maxchars = 80; /* work as before - kw */
  586. } else if (dump_output_width > 1) {
  587. me->buffer_maxchars = dump_output_width; /* try to honor -width - kw */
  588. } else if (dump_output_immediately) {
  589. me->buffer_maxchars = 80; /* try to honor -width - kw */
  590. } else {
  591. me->buffer_maxchars = (LYcolLimit - 1);
  592. if (me->buffer_maxchars < 38) /* too narrow, let GridText deal */
  593. me->buffer_maxchars = 40;
  594. }
  595. if (me->buffer_maxchars > 900) /* likely not true - kw */
  596. me->buffer_maxchars = 78;
  597. if (me->buffer_maxchars > BUFFER_SIZE) /* must not be larger! */
  598. me->buffer_maxchars = BUFFER_SIZE - 2;
  599. /*
  600. * If dump_output_immediately is set, there likely isn't anything after
  601. * this stream to interpret the Lynx special chars. Also if they get
  602. * displayed via HTPlain, that will probably make non-breaking space chars
  603. * etc. invisible. So let's translate them to numerical character
  604. * references. For debugging purposes we'll use the new hex format.
  605. */
  606. me->escape_specials = LYPreparsedSource;
  607. #ifdef USE_COLOR_STYLE
  608. me->text = NULL; /* Will be initialized when first needed. - kw */
  609. FREE(Style_className);
  610. class_string[0] = '\0';
  611. #endif /* COLOR_STYLE */
  612. return me;
  613. }
  614. /* Stream Object Class
  615. * -------------------
  616. *
  617. * This object just converts a plain text stream into HTML
  618. * It is officially a structured strem but only the stream bits exist.
  619. * This is just the easiest way of typecasting all the routines.
  620. */
  621. static const HTStructuredClass PlainToHTMLConversion =
  622. {
  623. "plaintexttoHTML",
  624. HTMLGen_free,
  625. PlainToHTML_abort,
  626. HTMLGen_put_character,
  627. HTMLGen_put_string,
  628. HTMLGen_write,
  629. NULL, /* Structured stuff */
  630. NULL,
  631. NULL
  632. };
  633. /* HTConverter from plain text to HTML Stream
  634. * ------------------------------------------
  635. */
  636. HTStream *HTPlainToHTML(HTPresentation *pres GCC_UNUSED,
  637. HTParentAnchor *anchor GCC_UNUSED,
  638. HTStream *sink)
  639. {
  640. HTStructured *me = (HTStructured *) malloc(sizeof(*me));
  641. if (me == NULL)
  642. outofmem(__FILE__, "PlainToHTML");
  643. me->isa = (const HTStructuredClass *) &PlainToHTMLConversion;
  644. /*
  645. * Copy pointers to routines for speed.
  646. */
  647. me->target = sink;
  648. me->targetClass = *me->target->isa;
  649. me->write_pointer = me->buffer;
  650. flush_breaks(me);
  651. me->cleanness = 0;
  652. me->overflowed = NO;
  653. me->delete_line_break_char[0] = NO;
  654. /* try to honor -width - kw */
  655. me->buffer_maxchars = (dump_output_width > 1 ?
  656. dump_output_width : 80);
  657. HTMLGen_put_string(me, "<HTML>\n<BODY>\n<PRE>\n");
  658. me->preformatted = YES;
  659. me->escape_specials = NO;
  660. me->in_attrval = NO;
  661. return (HTStream *) me;
  662. }