html.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * Emit html. Keep track of tags so that user doesn't have to.
  3. */
  4. #include "a.h"
  5. typedef struct Tag Tag;
  6. struct Tag
  7. {
  8. Tag *next;
  9. Rune *id;
  10. Rune *open;
  11. Rune *close;
  12. };
  13. Tag *tagstack;
  14. Tag *tagset;
  15. int hidingset;
  16. static Rune*
  17. closingtag(Rune *s)
  18. {
  19. Rune *t;
  20. Rune *p0, *p;
  21. t = runemalloc(sizeof(Rune));
  22. if(s == nil)
  23. return t;
  24. for(p=s; *p; p++){
  25. if(*p == Ult){
  26. p++;
  27. if(*p == '/'){
  28. while(*p && *p != Ugt)
  29. p++;
  30. goto close;
  31. }
  32. p0 = p;
  33. while(*p && !isspacerune(*p) && *p != Uspace && *p != Ugt)
  34. p++;
  35. t = runerealloc(t, 1+(p-p0)+2+runestrlen(t)+1);
  36. runemove(t+(p-p0)+3, t, runestrlen(t)+1);
  37. t[0] = Ult;
  38. t[1] = '/';
  39. runemove(t+2, p0, p-p0);
  40. t[2+(p-p0)] = Ugt;
  41. }
  42. if(*p == Ugt && p>s && *(p-1) == '/'){
  43. close:
  44. for(p0=t+1; *p0 && *p0 != Ult; p0++)
  45. ;
  46. runemove(t, p0, runestrlen(p0)+1);
  47. }
  48. }
  49. return t;
  50. }
  51. void
  52. html(Rune *id, Rune *s)
  53. {
  54. Rune *es;
  55. Tag *t, *tt, *next;
  56. br();
  57. hideihtml(); /* br already did, but be paranoid */
  58. for(t=tagstack; t; t=t->next){
  59. if(runestrcmp(t->id, id) == 0){
  60. for(tt=tagstack;; tt=next){
  61. next = tt->next;
  62. free(tt->id);
  63. free(tt->open);
  64. out(tt->close);
  65. outrune('\n');
  66. free(tt->close);
  67. free(tt);
  68. if(tt == t){
  69. tagstack = next;
  70. goto cleared;
  71. }
  72. }
  73. }
  74. }
  75. cleared:
  76. if(s == nil || s[0] == 0)
  77. return;
  78. out(s);
  79. outrune('\n');
  80. es = closingtag(s);
  81. if(es[0] == 0){
  82. free(es);
  83. return;
  84. }
  85. if(runestrcmp(id, L("-")) == 0){
  86. out(es);
  87. outrune('\n');
  88. free(es);
  89. return;
  90. }
  91. t = emalloc(sizeof *t);
  92. t->id = erunestrdup(id);
  93. t->close = es;
  94. t->next = tagstack;
  95. tagstack = t;
  96. }
  97. void
  98. closehtml(void)
  99. {
  100. Tag *t, *next;
  101. br();
  102. hideihtml();
  103. for(t=tagstack; t; t=next){
  104. next = t->next;
  105. out(t->close);
  106. outrune('\n');
  107. free(t->id);
  108. free(t->close);
  109. free(t);
  110. }
  111. }
  112. static void
  113. rshow(Tag *t, Tag *end)
  114. {
  115. if(t == nil || t == end)
  116. return;
  117. rshow(t->next, end);
  118. out(t->open);
  119. }
  120. void
  121. ihtml(Rune *id, Rune *s)
  122. {
  123. Tag *t, *tt, **l;
  124. for(t=tagset; t; t=t->next){
  125. if(runestrcmp(t->id, id) == 0){
  126. if(s && t->open && runestrcmp(t->open, s) == 0)
  127. return;
  128. for(l=&tagset; (tt=*l); l=&tt->next){
  129. if(!hidingset)
  130. out(tt->close);
  131. if(tt == t)
  132. break;
  133. }
  134. *l = t->next;
  135. free(t->id);
  136. free(t->close);
  137. free(t->open);
  138. free(t);
  139. if(!hidingset)
  140. rshow(tagset, *l);
  141. goto cleared;
  142. }
  143. }
  144. cleared:
  145. if(s == nil || s[0] == 0)
  146. return;
  147. t = emalloc(sizeof *t);
  148. t->id = erunestrdup(id);
  149. t->open = erunestrdup(s);
  150. t->close = closingtag(s);
  151. if(!hidingset)
  152. out(s);
  153. t->next = tagset;
  154. tagset = t;
  155. }
  156. void
  157. hideihtml(void)
  158. {
  159. Tag *t;
  160. if(hidingset)
  161. return;
  162. hidingset = 1;
  163. for(t=tagset; t; t=t->next)
  164. out(t->close);
  165. }
  166. void
  167. showihtml(void)
  168. {
  169. if(!hidingset)
  170. return;
  171. hidingset = 0;
  172. rshow(tagset, nil);
  173. }
  174. int
  175. e_lt(void)
  176. {
  177. return Ult;
  178. }
  179. int
  180. e_gt(void)
  181. {
  182. return Ugt;
  183. }
  184. int
  185. e_at(void)
  186. {
  187. return Uamp;
  188. }
  189. int
  190. e_tick(void)
  191. {
  192. return Utick;
  193. }
  194. int
  195. e_btick(void)
  196. {
  197. return Ubtick;
  198. }
  199. int
  200. e_minus(void)
  201. {
  202. return Uminus;
  203. }
  204. void
  205. r_html(Rune *name)
  206. {
  207. Rune *id, *line, *p;
  208. id = copyarg();
  209. line = readline(HtmlMode);
  210. for(p=line; *p; p++){
  211. switch(*p){
  212. case '<':
  213. *p = Ult;
  214. break;
  215. case '>':
  216. *p = Ugt;
  217. break;
  218. case '&':
  219. *p = Uamp;
  220. break;
  221. case ' ':
  222. *p = Uspace;
  223. break;
  224. }
  225. }
  226. if(name[0] == 'i')
  227. ihtml(id, line);
  228. else
  229. html(id, line);
  230. free(id);
  231. free(line);
  232. }
  233. char defaultfont[] =
  234. ".ihtml f1\n"
  235. ".ihtml f\n"
  236. ".ihtml f <span style=\"font-size: \\n(.spt\">\n"
  237. ".if \\n(.f==2 .ihtml f1 <i>\n"
  238. ".if \\n(.f==3 .ihtml f1 <b>\n"
  239. ".if \\n(.f==4 .ihtml f1 <b><i>\n"
  240. ".if \\n(.f==5 .ihtml f1 <tt>\n"
  241. ".if \\n(.f==6 .ihtml f1 <tt><i>\n"
  242. "..\n"
  243. ;
  244. void
  245. htmlinit(void)
  246. {
  247. addraw(L("html"), r_html);
  248. addraw(L("ihtml"), r_html);
  249. addesc('<', e_lt, CopyMode);
  250. addesc('>', e_gt, CopyMode);
  251. addesc('\'', e_tick, CopyMode);
  252. addesc('`', e_btick, CopyMode);
  253. addesc('-', e_minus, CopyMode);
  254. addesc('@', e_at, CopyMode);
  255. ds(L("font"), L(defaultfont));
  256. }