Intial commit
[profile/ivi/w3m.git] / parsetagx.c
1 /* $Id: parsetagx.c,v 1.18 2006/06/07 03:52:03 inu Exp $ */
2 #include "fm.h"
3 #include "myctype.h"
4 #include "indep.h"
5 #include "Str.h"
6 #include "parsetagx.h"
7 #include "hash.h"
8
9 #include "html.c"
10
11 /* parse HTML tag */
12
13 static int noConv(char *, char **);
14 static int toNumber(char *, int *);
15 static int toLength(char *, int *);
16 static int toAlign(char *, int *);
17 static int toVAlign(char *, int *);
18
19 /* *INDENT-OFF* */
20 static int (*toValFunc[]) () = {
21     noConv,             /* VTYPE_NONE    */
22     noConv,             /* VTYPE_STR     */
23     toNumber,           /* VTYPE_NUMBER  */
24     toLength,           /* VTYPE_LENGTH  */
25     toAlign,            /* VTYPE_ALIGN   */
26     toVAlign,           /* VTYPE_VALIGN  */
27     noConv,             /* VTYPE_ACTION  */
28     noConv,             /* VTYPE_ENCTYPE */
29     noConv,             /* VTYPE_METHOD  */
30     noConv,             /* VTYPE_MLENGTH */
31     noConv,             /* VTYPE_TYPE    */
32 };
33 /* *INDENT-ON* */
34
35 static int
36 noConv(char *oval, char **str)
37 {
38     *str = oval;
39     return 1;
40 }
41
42 static int
43 toNumber(char *oval, int *num)
44 {
45     char *ep;
46     int x;
47
48     x = strtol(oval, &ep, 10);
49
50     if (ep > oval) {
51         *num = x;
52         return 1;
53     }
54     else
55         return 0;
56 }
57
58 static int
59 toLength(char *oval, int *len)
60 {
61     int w;
62     if (!IS_DIGIT(oval[0]))
63         return 0;
64     w = atoi(oval);
65     if (w < 0)
66         return 0;
67     if (w == 0)
68         w = 1;
69     if (oval[strlen(oval) - 1] == '%')
70         *len = -w;
71     else
72         *len = w;
73     return 1;
74 }
75
76 static int
77 toAlign(char *oval, int *align)
78 {
79     if (strcasecmp(oval, "left") == 0)
80         *align = ALIGN_LEFT;
81     else if (strcasecmp(oval, "right") == 0)
82         *align = ALIGN_RIGHT;
83     else if (strcasecmp(oval, "center") == 0)
84         *align = ALIGN_CENTER;
85     else if (strcasecmp(oval, "top") == 0)
86         *align = ALIGN_TOP;
87     else if (strcasecmp(oval, "bottom") == 0)
88         *align = ALIGN_BOTTOM;
89     else if (strcasecmp(oval, "middle") == 0)
90         *align = ALIGN_MIDDLE;
91     else
92         return 0;
93     return 1;
94 }
95
96 static int
97 toVAlign(char *oval, int *valign)
98 {
99     if (strcasecmp(oval, "top") == 0 || strcasecmp(oval, "baseline") == 0)
100         *valign = VALIGN_TOP;
101     else if (strcasecmp(oval, "bottom") == 0)
102         *valign = VALIGN_BOTTOM;
103     else if (strcasecmp(oval, "middle") == 0)
104         *valign = VALIGN_MIDDLE;
105     else
106         return 0;
107     return 1;
108 }
109
110 extern Hash_si tagtable;
111 #define MAX_TAG_LEN 64
112
113 struct parsed_tag *
114 parse_tag(char **s, int internal)
115 {
116     struct parsed_tag *tag = NULL;
117     int tag_id;
118     char tagname[MAX_TAG_LEN], attrname[MAX_TAG_LEN];
119     char *p, *q;
120     int i, attr_id = 0, nattr;
121
122     /* Parse tag name */
123     q = (*s) + 1;
124     p = tagname;
125     if (*q == '/') {
126         *(p++) = *(q++);
127         SKIP_BLANKS(q);
128     }
129     while (*q && !IS_SPACE(*q) && !(tagname[0] != '/' && *q == '/') &&
130            *q != '>' && p - tagname < MAX_TAG_LEN - 1) {
131         *(p++) = TOLOWER(*q);
132         q++;
133     }
134     *p = '\0';
135     while (*q && !IS_SPACE(*q) && !(tagname[0] != '/' && *q == '/') &&
136            *q != '>')
137         q++;
138
139     tag_id = getHash_si(&tagtable, tagname, HTML_UNKNOWN);
140
141     if (tag_id == HTML_UNKNOWN ||
142         (!internal && TagMAP[tag_id].flag & TFLG_INT))
143         goto skip_parse_tagarg;
144
145     tag = New(struct parsed_tag);
146     bzero(tag, sizeof(struct parsed_tag));
147     tag->tagid = tag_id;
148
149     if ((nattr = TagMAP[tag_id].max_attribute) > 0) {
150         tag->attrid = NewAtom_N(unsigned char, nattr);
151         tag->value = New_N(char *, nattr);
152         tag->map = NewAtom_N(unsigned char, MAX_TAGATTR);
153         memset(tag->map, MAX_TAGATTR, MAX_TAGATTR);
154         memset(tag->attrid, ATTR_UNKNOWN, nattr);
155         for (i = 0; i < nattr; i++)
156             tag->map[TagMAP[tag_id].accept_attribute[i]] = i;
157     }
158
159     /* Parse tag arguments */
160     SKIP_BLANKS(q);
161     while (1) {
162        Str value = NULL, value_tmp = NULL;
163         if (*q == '>' || *q == '\0')
164             goto done_parse_tag;
165         p = attrname;
166         while (*q && *q != '=' && !IS_SPACE(*q) &&
167                *q != '>' && p - attrname < MAX_TAG_LEN - 1) {
168             *(p++) = TOLOWER(*q);
169             q++;
170         }
171         *p = '\0';
172         while (*q && *q != '=' && !IS_SPACE(*q) && *q != '>')
173             q++;
174         SKIP_BLANKS(q);
175         if (*q == '=') {
176             /* get value */
177             value_tmp = Strnew();
178             q++;
179             SKIP_BLANKS(q);
180             if (*q == '"') {
181                 q++;
182                 while (*q && *q != '"') {
183                     Strcat_char(value_tmp, *q);
184                     if (!tag->need_reconstruct && is_html_quote(*q))
185                         tag->need_reconstruct = TRUE;
186                     q++;
187                 }
188                 if (*q == '"')
189                     q++;
190             }
191             else if (*q == '\'') {
192                 q++;
193                 while (*q && *q != '\'') {
194                     Strcat_char(value_tmp, *q);
195                     if (!tag->need_reconstruct && is_html_quote(*q))
196                         tag->need_reconstruct = TRUE;
197                     q++;
198                 }
199                 if (*q == '\'')
200                     q++;
201             }
202             else if (*q) {
203                 while (*q && !IS_SPACE(*q) && *q != '>') {
204                    Strcat_char(value_tmp, *q);
205                     if (!tag->need_reconstruct && is_html_quote(*q))
206                         tag->need_reconstruct = TRUE;
207                     q++;
208                 }
209             }
210         }
211         for (i = 0; i < nattr; i++) {
212             if ((tag)->attrid[i] == ATTR_UNKNOWN &&
213                 strcmp(AttrMAP[TagMAP[tag_id].accept_attribute[i]].name,
214                        attrname) == 0) {
215                 attr_id = TagMAP[tag_id].accept_attribute[i];
216                 break;
217             }
218         }
219
220        if (value_tmp) {
221          int j, hidden=FALSE;
222          for (j=0; j<i; j++) {
223            if (tag->attrid[j] == ATTR_TYPE &&
224                strcmp("hidden",tag->value[j]) == 0) {
225              hidden=TRUE;
226              break;
227            }
228          }
229          if ((tag_id == HTML_INPUT || tag_id == HTML_INPUT_ALT) &&
230              attr_id == ATTR_VALUE && hidden) {
231            value = value_tmp;
232          } else {
233            char *x;
234            value = Strnew();
235            for (x = value_tmp->ptr; *x; x++) {
236              if (*x != '\n')
237                Strcat_char(value, *x);
238            }
239          }
240        }
241
242         if (i != nattr) {
243             if (!internal &&
244                 ((AttrMAP[attr_id].flag & AFLG_INT) ||
245                  (value && AttrMAP[attr_id].vtype == VTYPE_METHOD &&
246                   !strcasecmp(value->ptr, "internal")))) {
247                 tag->need_reconstruct = TRUE;
248                 continue;
249             }
250             tag->attrid[i] = attr_id;
251             if (value)
252                 tag->value[i] = html_unquote(value->ptr);
253             else
254                 tag->value[i] = NULL;
255         }
256         else {
257             tag->need_reconstruct = TRUE;
258         }
259     }
260
261   skip_parse_tagarg:
262     while (*q != '>' && *q)
263         q++;
264   done_parse_tag:
265     if (*q == '>')
266         q++;
267     *s = q;
268     return tag;
269 }
270
271 int
272 parsedtag_set_value(struct parsed_tag *tag, int id, char *value)
273 {
274     int i;
275
276     if (!parsedtag_accepts(tag, id))
277         return 0;
278
279     i = tag->map[id];
280     tag->attrid[i] = id;
281     if (value)
282         tag->value[i] = allocStr(value, -1);
283     else
284         tag->value[i] = NULL;
285     tag->need_reconstruct = TRUE;
286     return 1;
287 }
288
289 int
290 parsedtag_get_value(struct parsed_tag *tag, int id, void *value)
291 {
292     int i;
293     if (!parsedtag_exists(tag, id) || !tag->value[i = tag->map[id]])
294         return 0;
295     return toValFunc[AttrMAP[id].vtype] (tag->value[i], value);
296 }
297
298 Str
299 parsedtag2str(struct parsed_tag *tag)
300 {
301     int i;
302     int tag_id = tag->tagid;
303     int nattr = TagMAP[tag_id].max_attribute;
304     Str tagstr = Strnew();
305     Strcat_char(tagstr, '<');
306     Strcat_charp(tagstr, TagMAP[tag_id].name);
307     for (i = 0; i < nattr; i++) {
308         if (tag->attrid[i] != ATTR_UNKNOWN) {
309             Strcat_char(tagstr, ' ');
310             Strcat_charp(tagstr, AttrMAP[tag->attrid[i]].name);
311             if (tag->value[i])
312                 Strcat(tagstr, Sprintf("=\"%s\"", html_quote(tag->value[i])));
313         }
314     }
315     Strcat_char(tagstr, '>');
316     return tagstr;
317 }