First version of a simple Tcl robot.
[tclrobot.git] / hswitch.c
1 /*
2  * $Id: hswitch.c,v 1.1.1.1 1996/08/06 14:04:23 adam Exp $
3  */
4 #include <assert.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <ctype.h>
8
9 #include "tclrobot.h"
10
11 #define TAG_MAX_LEN 32
12
13 #define SPACECHR " \t\r\n\f"
14
15 static int skipSpace (const char *cp)
16 {
17     int i = 0;
18     while (strchr (SPACECHR, cp[i]))
19         i++;
20     return i;
21 }
22
23 static int skipTag (const char *cp, char *dst)
24 {
25     int i;
26
27     for (i=0; i<TAG_MAX_LEN-1 && cp[i] && !strchr (SPACECHR "/>=", cp[i]); i++)
28         dst[i] = tolower(cp[i]);
29     dst[i] = '\0';
30     return i;
31 }
32
33 static int skipParm (const char *cp, char *name, char **value)
34 {
35     int i = skipTag (cp, name);   
36     *value = NULL;
37     if (!i)
38         return skipSpace (cp);
39     i += skipSpace (cp + i);
40     if (cp[i] == '=')
41     {
42         int v0, v1;
43         i++;
44         i += skipSpace (cp + i);
45         if (cp[i] == '\"')
46         {
47             v0 = ++i;
48             while (cp[i] != '\"' && cp[i])
49                 i++; 
50             v1 = i;
51             if (cp[i])
52                 i++;
53         }
54         else
55         {
56             v0 = i;
57             while (cp[i] && !strchr (SPACECHR ">", cp[i]))
58                 i++;
59             v1 = i;
60         }
61         *value = malloc (v1 - v0 + 1);
62         memcpy (*value, cp + v0, v1-v0);
63         (*value)[v1-v0] = '\0';
64     }
65     i += skipSpace (cp + i);
66     return i;
67 }
68
69 struct tagParm {
70     char name[TAG_MAX_LEN];
71     char *value;
72     struct tagParm *next;
73 };
74
75 struct tagInfo {
76     int level;
77     char *pattern;
78     char *code;
79
80     char name[TAG_MAX_LEN];
81     const char *body_start;
82     struct tagParm *tagParms;
83 };
84
85 static int tagLookup (struct tagInfo *tags, int tagNo, const char *tagString)
86 {
87     int i;
88     for (i = 0; i<tagNo; i++)
89         if (!strcmp (tags[i].pattern, tagString))
90              return i;
91     return -1;
92 }
93
94 static int tagStart (struct tagInfo *tag, const char *tagString,
95                      const char *cp)
96 {
97     int i;
98     char parm_name[TAG_MAX_LEN];
99     char *parm_value;
100     struct tagParm **nParms;
101
102     if (tag && !tag->level)
103     {
104         strcpy (tag->name, tagString);
105         tag->tagParms = NULL;
106         nParms = &tag->tagParms;
107     }
108
109     i = skipSpace (cp);
110     while (cp[i] && cp[i] != '>')
111     {
112         int nor =  skipParm (cp+i, parm_name, &parm_value);
113         i += nor;
114         if (nor && tag && !tag->level)
115         {
116             *nParms = malloc (sizeof(**nParms));
117             assert (*nParms);
118             (*nParms)->next = NULL;
119             strcpy ((*nParms)->name, parm_name);
120             (*nParms)->value = parm_value;
121         }
122         else
123         {
124             if (!nor)
125                 i++;
126             free (parm_value);
127         }
128     }
129     if (cp[i])
130         i++;
131     if (tag)
132     {
133         if (!tag->level)
134             tag->body_start = cp+i;
135         ++(tag->level);
136     }
137     return i;
138 }
139
140 static int tagEnd (Tcl_Interp *interp, struct tagInfo *tag,
141                    const char *tagString, const char *cp, const char *body_end)
142 {
143     int i = 0;
144
145     if (cp[i] == '>')
146         i++;
147
148     if (tag && tag->level)
149     {
150         -- (tag->level);
151         if (!tag->level)
152         {
153             struct tagParm *tp = tag->tagParms;
154             char *value = malloc (body_end - tag->body_start + 1);
155
156             assert (value);
157             memcpy (value, tag->body_start, body_end - tag->body_start);
158             value[body_end - tag->body_start] = '\0';
159             Tcl_SetVar (interp, "body", value, 0);
160             free (value);
161             while (tp)
162             {
163                 char vname[TAG_MAX_LEN+30];
164                 struct tagParm *tp0 = tp;
165                 
166                 sprintf (vname, "parm(%s)", tp->name);
167
168                 Tcl_SetVar (interp, vname, tp->value ? tp->value : "",0);
169                 tp = tp->next;
170                 free (tp0);
171             }
172             Tcl_Eval (interp, tag->code);
173         }
174     }
175     return i;
176 }
177
178 int htmlSwitch (ClientData clientData, Tcl_Interp *interp,
179                 int argc, char **argv)
180 {
181     struct tagInfo *tags;
182     int noTags;
183     const char *cp;
184     int i, argi = 1;
185
186     cp = argv[argi++];
187     noTags = (argc - argi)/2;
188     if (noTags < 1)
189     {
190         interp->result =
191             "wrong # args: should be ?switches? string pattern body ...";
192         return TCL_ERROR;
193     }
194     tags = malloc (sizeof(*tags) * noTags);
195     assert (tags);
196     for (i = 0; i<noTags; i++)
197     {
198         tags[i].level = 0;
199         tags[i].pattern = argv[argi++];
200         tags[i].code = argv[argi++];
201     }
202     while (*cp)
203     {
204         if (cp[0] == '<' && cp[1] != '/')     /* start tag */
205         {
206             char tagStr[TAG_MAX_LEN];
207             int tagI;
208
209             cp++;
210             cp += skipTag (cp, tagStr);
211             tagI = tagLookup (tags, noTags, tagStr);
212             cp += tagStart (tagI >= 0 ? tags+tagI : NULL, tagStr, cp);
213         }
214         else if (cp[0] == '<')                /* end tag */
215         {
216             char tagStr[TAG_MAX_LEN];
217             const char *body_end = cp;
218             int tagI;
219
220             cp += 2;
221             cp += skipTag (cp, tagStr);
222             tagI = tagLookup (tags, noTags, tagStr);
223             cp += tagEnd (interp, tagI >= 0 ? tags+tagI : NULL,
224                           tagStr, cp, body_end);
225         }
226         else                                  /* no tag */
227             cp++;
228     }
229     free (tags);
230     return TCL_OK;
231 }
232
233