1 /*
2  * inline.c:
3  * In-line markup.
4  *
5  *  - URLs are turned into links
6  *
7  *  - ___ text ___ URL is turned into a link with the given text
8  *
9  *  - ||| URL alt-text ||| is turned into an <img> tag with the given
10  *    alt-text
11  *
12  *  - *** strong ***
13  *
14  *  - /// emphasis ///
15  *
16  *  - ### cite ###
17  *
18  *  - <>&" are turned into the appropriate HTML escapes.
19  *
20  *  - \\\ is turned into <br>
21  *
22  * Copyright (c) 2003 Chris Lightfoot. All rights reserved.
23  * Email: chris@ex-parrot.com; WWW: http://www.ex-parrot.com/~chris/
24  *
25  */
26 
27 static const char rcsid[] = "$Id: inline.c,v 1.3 2003/06/01 11:39:44 chris Exp $";
28 
29 #include <assert.h>
30 
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "htmlise.h"
35 
inline_markup_words(FILE * fp,char ** words,const size_t nwords)36 static void inline_markup_words(FILE *fp, char **words, const size_t nwords) {
37     size_t i;
38     int in_strong = 0, in_em = 0, in_cite = 0;
39 
40     /* Go through words applying markup. XXX may generate overlapping tags. */
41     for (i = 0; i < nwords; ++i) {
42         size_t j;
43 
44         if (!*words[i])
45             continue;
46         if (strcmp(words[i], "\\\\\\") == 0)
47             fprintf(fp, "<br>");
48         else if (strcmp(words[i], "***") == 0) {
49             if  (in_strong)
50                 fprintf(fp, "</strong>");
51             else
52                 fprintf(fp, "<strong>");
53             in_strong = !in_strong;
54         } else if (strcmp(words[i], "///") == 0) {
55             if (in_em)
56                 fprintf(fp, "</em>");
57             else
58                 fprintf(fp, "<em>");
59             in_em = !in_em;
60         } else if (strcmp(words[i], "###") == 0) {
61             if (in_cite)
62                 fprintf(fp, "</cite>");
63             else
64                 fprintf(fp, "<cite>");
65             in_cite = !in_cite;
66         } else if (strcmp(words[i], "|||") == 0) {
67             /* Image. Can't have markup inside the alt text. */
68             for (j = i + 1; j < nwords && strcmp(words[j], "|||") != 0; ++j);
69             if (j < nwords) {
70                 fprintf(fp, "<img src=\"%s\" alt=\"", words[i + 1]);
71                 i += 2;
72                 while (i < j) {
73                     fprintf(fp, "%s%s", words[i], i < j ? " " : "");
74                     ++i;
75                 }
76 /*                ++i;*/
77                 fprintf(fp, "\">");
78             }
79         } else if (strncmp(words[i], "http://", 7) == 0 || strncmp(words[i], "ftp://", 6) == 0)
80             fprintf(fp, "<a href=\"%s\">%s</a>", words[i], words[i]);
81         else if (strcmp(words[i], "___") == 0) {
82             /* Link. */
83             for (j = i + 2; j < nwords - 1 && strcmp(words[j], "___") != 0; ++j);
84             if (j < nwords - 1) {
85                 int lastc = 0;
86                 size_t l;
87 
88                 fprintf(fp, "<a href=\"%s\">", words[j + 1]);
89 
90                 l = strlen(words[j - 1]) - 1;
91                 if (strchr("\"`'.,;:()[]?!", words[j - 1][l])) {
92                     lastc = words[j - 1][l];
93                     words[j - 1][l] = 0;
94                 }
95 /*
96                 while (i < j) {
97                     size_t l;
98                     if (i == j - 1 && strchr("\"`'.,;:()[]", words[i][l = strlen(words[i]) - 1])) {
99                         lastc = words[i][l];
100                         words[i][l] = 0;
101                     }
102                     fprintf(fp, "%s%s", words[i++], i < j ? " " : "");
103                 }
104                 ++i;
105 */
106 
107                 inline_markup_words(fp, words + i + 1, j - i - 1);
108                 fprintf(fp, "</a>");
109                 if (lastc)
110                     putc(lastc, fp);
111                 i = j + 1;
112             }
113         } else
114             fprintf(fp, "%s", words[i]);
115 
116         if (i < nwords - 1)
117             putc(' ', fp);
118     }
119 
120 }
121 
122 /* emit_as_html STREAM PARAGRAPH
123  * Emit PARAGRAPH to STREAM, converting its text to HTML. */
emit_as_html(FILE * fp,const struct paragraph * P)124 void emit_as_html(FILE *fp, const struct paragraph *P) {
125     static char *buf, **words;
126     static size_t buflen, nwordsalloc;
127     size_t i, n, nwords = 0;
128     const char *p;
129     char *q, *ws, *we;
130 
131     for (i = 0, n = 0; i < P->nlines; ++i)
132         n += strlen(P->lines[i]) + 1;
133 
134     /* Conservative; " (1) -> &quot; (5). */
135     if (!buf || n * 6 + 1 > buflen)
136         buf = realloc(buf, buflen = n * 5 + 1);
137 
138     for (i = 0, q = buf; i < P->nlines; ++i) {
139         for (p = P->lines[i]; *p; ++p) {
140             if (*p == '&') {
141                 strcpy(q, "&amp;");
142                 q += 5;
143             } else if (*p == '<') {
144                 strcpy(q, "&lt;");
145                 q += 4;
146             } else if (*p == '>') {
147                 strcpy(q, "&gt;");
148                 q += 4;
149             } else if (*p == '\"') {
150                 strcpy(q, "&quot;");
151                 q += 6;
152             } else
153                 *q++ = *p;
154         }
155 
156         *q++ = '\n';
157 
158     }
159     *q = 0;
160 
161     /* Break into words. */
162     if (!words)
163         words = malloc((nwordsalloc = 100) * sizeof *words);
164 
165     ws = buf;
166     while (1) {
167         while (*ws && strchr(" \n", *ws)) ++ws;
168         if (!*ws) break;
169 
170         /* End of this word. */
171         we = ws + strcspn(ws, " \n");
172         words[nwords++] = ws;
173         if (*we) {
174             *we = 0;
175             ws = we + 1;
176         } else
177             break;
178 
179         if (nwords == nwordsalloc)
180             words = realloc(words, (nwordsalloc *= 2) * sizeof *words);
181     }
182 
183     inline_markup_words(fp, words, nwords);
184 
185 }
186 
187