simplify hooks code a lot.
[apps/madmutt.git] / rcparser.y
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or (at
5  *  your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful, but
8  *  WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15  *  MA 02110-1301, USA.
16  *
17  *  Copyright © 2006 Pierre Habouzit
18  */
19
20 %include {
21 #   include <lib-lib/lib-lib.h>
22 #   include "mutt.h"
23 #   include "parse.h"
24 #   include "buffy.h"
25
26     static buffer_t *buffer_merge(buffer_t *A, buffer_t **B)
27     {
28         buffer_addbuf(A, *B);
29         buffer_delete(B);
30         return A;
31     }
32
33     static inline int to_control(int c) {
34         return (toupper((unsigned char)c) - 'A' + 1) & 0x7f;
35     }
36
37     static buffer_t *buffer_escape(buffer_t *buf, const char *s, ssize_t len)
38     {
39         assert (len > 0);
40
41         switch (*s) {
42           case 'c': case 'Z':
43             if (len < 2)
44                 break;
45             buffer_addch(buf, to_control(s[1]));
46             buffer_add(buf, s + 2, len - 2);
47             return buf;
48
49           case 'x':
50             if (len >= 3) {
51                 int i = (hexval(s[1]) << 4) | hexval(s[2]);
52                 if (i >= 0) {
53                     buffer_addch(buf, i);
54                     buffer_add(buf, s + 3, len - 3);
55                     return buf;
56                 }
57             }
58             break;
59
60           case '0': case '1': case '2': case '3':
61             if (len >= 3) {
62                 int i = (octval(s[0]) << 6) | (octval(s[1]) << 3) | octval(s[2]);
63                 if (i >= 0) {
64                     buffer_addch(buf, i);
65                     buffer_add(buf, s + 3, len - 3);
66                     return buf;
67                 }
68             }
69             break;
70
71           case 'e': buffer_addch(buf, '\e'); return buf;
72           case 'f': buffer_addch(buf, '\f'); return buf;
73           case 'n': buffer_addch(buf, '\n'); return buf;
74           case 'r': buffer_addch(buf, '\r'); return buf;
75           case 't': buffer_addch(buf, '\t'); return buf;
76           case 'v': buffer_addch(buf, '\v'); return buf;
77
78           default:
79             break;
80         }
81
82         buffer_add(buf, s, len);
83         return buf;
84     }
85
86     static void substvar(buffer_t *buf, const segment seg)
87     {
88         const char *res;
89         char tmp[STRING];
90         char var[STRING];
91
92         if (m_strncpy(var, sizeof(var), seg.s, seg.len) <= 0)
93             return;
94
95         if ((res = getenv(var))) {
96             buffer_addstr(buf, res);
97             return;
98         }
99         if (mutt_option_value(var, tmp, sizeof(tmp))) {
100             buffer_addstr(buf, tmp);
101         }
102     }
103 }
104
105 %name rcparse
106 %token_prefix RCTK_
107 %token_type  { segment }
108 %start_symbol rc
109 %extra_argument { struct rcstate *state }
110
111 /****************************************************************************/
112 /* Often used                                                               */
113 /****************************************************************************/
114
115 escnl ::= BSLASH NL .                      { state->linenum++; }
116
117 sp ::= SPACE .
118 sp ::= sp SPACE .
119 sp ::= sp escnl SPACE .
120
121 non_nl ::= ATOM|SPACE|BQUOTE|BSLASH|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|SQUOTE|RBRACE .
122 non_nl_star ::= .
123 non_nl_star ::= non_nl_star non_nl .
124
125 to_eol_aux ::= NL .                        { state->linenum++; }
126 to_eol_aux ::= SHARP non_nl_star NL .      { state->linenum++; }
127 to_eol ::= to_eol_aux .
128 to_eol ::= sp to_eol_aux .
129
130 /****************************************************************************/
131 /* Our macro tokens                                                         */
132 /****************************************************************************/
133 /*                                                                       {{{*/
134
135 %type svar { segment }
136 svar(Z) ::= DOLLAR ATOM(B) .               { Z = B; }
137 svar(Z) ::= DOLLAR LBRACE ATOM(B) RBRACE . { Z = B; }
138
139 /* '-quoted tokens */
140 %type sqtok { buffer_t* }
141 %destructor sqtok  { buffer_delete(&$$); }
142 sqtok(Z) ::= .                                 { Z = buffer_new(); }
143 sqtok(Z) ::= sqtok(A) escnl .                  { Z = A; }
144 sqtok(Z) ::= sqtok(A) BSLASH BSLASH|SQUOTE(B) . { buffer_addch(Z = A, *B.s); }
145 sqtok(Z) ::= sqtok(A) BSLASH ATOM|SPACE|BQUOTE|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|RBRACE(B) . {
146     buffer_addch(Z = A, '\\');
147     buffer_add(Z, B.s, B.len);
148 }
149 sqtok(Z) ::= sqtok(A) ATOM|SPACE|BQUOTE|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|RBRACE(B) . {
150     buffer_add(Z = A, B.s, B.len);
151 }
152
153 /* `-quoted tokens */
154 %type bqtok { buffer_t* }
155 %destructor bqtok { buffer_delete(&$$); }
156 bqtok(Z) ::= .                             { Z = buffer_new(); }
157 bqtok(Z) ::= bqtok(A) escnl .              { Z = A; }
158 bqtok(Z) ::= bqtok(A) BSLASH non_nl(B) .   { Z = buffer_escape(A, B.s, B.len); }
159 bqtok(Z) ::= bqtok(A) svar(B) .            { substvar(Z = A, B); }
160 bqtok(Z) ::= bqtok(A) ATOM|SPACE|SHARP|EQUAL|LBRACE|RBRACE|SQUOTE|DQUOTE(B)  . {
161     buffer_add(Z = A, B.s, B.len);
162 }
163
164 /* "-quoted tokens */
165 %type dqtok { buffer_t* }
166 %destructor dqtok { buffer_delete(&$$); }
167 dqtok(Z) ::= .                             { Z = buffer_new(); }
168 dqtok(Z) ::= dqtok(A) escnl .              { Z = A; }
169 dqtok(Z) ::= dqtok(A) BSLASH non_nl(B) .   { Z = buffer_escape(A, B.s, B.len); }
170 dqtok(Z) ::= dqtok(A) svar(B) .            { substvar(Z = A, B); }
171 dqtok(Z) ::= dqtok(A) ATOM|SPACE|SHARP|EQUAL|LBRACE|RBRACE|SQUOTE(B)  . {
172     buffer_add(Z = A, B.s, B.len);
173 }
174 dqtok(Z) ::= dqtok(A) BQUOTE bqtok(B) BQUOTE . { /* XXX */ buffer_merge(Z = A, &B); }
175
176 /* unquoted tokens */
177 %type uqtok { buffer_t* }
178 %destructor uqtok { buffer_delete(&$$); }
179 uqtok(Z) ::= BSLASH non_nl(A) .            { buffer_add(Z = buffer_new(), A.s, A.len); }
180 uqtok(Z) ::= svar(A) .                     { substvar(Z = buffer_new(), A); }
181 uqtok(Z) ::= ATOM|EQUAL|LBRACE|RBRACE(A) . { buffer_add(Z = buffer_new(), A.s, A.len); }
182 uqtok(Z) ::= SQUOTE sqtok(A) SQUOTE .      { Z = A; }
183 uqtok(Z) ::= DQUOTE dqtok(A) DQUOTE .      { Z = A; }
184 uqtok(Z) ::= BQUOTE bqtok(A) BQUOTE .      { /* XXX */ Z = A; }
185
186 /* token accumulator: NEVER USE DIRECTLY */
187 %type tokaux { buffer_t* }
188 %destructor tokaux { abort(); }
189 tokaux(Z) ::= uqtok(A) .                   { Z = A; }
190 tokaux(Z) ::= tokaux(A) escnl .            { Z = A; }
191 tokaux(Z) ::= tokaux(A) uqtok(B) .         { Z = buffer_merge(A, &B); }
192
193 %type token { buffer_t* }
194 %destructor token { buffer_delete(&$$); }
195 token(Z) ::= sp tokaux(A) .                 { Z = A; }
196
197 /*                                                                       }}}*/
198 /****************************************************************************/
199 /* list of tokens                                                           */
200 /****************************************************************************/
201
202 %type simple_list { string_list_t * }
203 %destructor simple_list { string_list_wipe(&$$); }
204 simple_list ::= .
205 simple_list(L) ::= simple_list(A) token(B) . {
206     if (B->len) {
207         L = string_item_new();
208         L->data = buffer_unwrap(&B);
209         L->next = A;
210     } else {
211         L = A;
212         buffer_delete(&B);
213     }
214 }
215
216
217 /****************************************************************************/
218 /* Entry point : the rc lines                                               */
219 /****************************************************************************/
220
221 rc ::= rclines .
222 rclines ::= .
223 rclines ::= rclines rcline .
224
225 rcline ::= to_eol .
226 rcline ::= BIND token token token to_eol .
227 rcline ::= EXEC simple_list to_eol .
228 rcline ::= MACRO token token token to_eol .
229 rcline ::= MACRO token token token token to_eol .
230 rcline ::= PUSH token to_eol .
231 rcline ::= SCORE token token to_eol .
232 rcline ::= UNSCORE simple_list to_eol .
233
234 /* {{{ alias */
235
236 %type atok { buffer_t* }
237 %destructor atok { buffer_delete(&$$); }
238 atok(Z) ::= ATOM|SHARP|DQUOTE|EQUAL|LBRACE|SQUOTE|RBRACE(A) . {
239     buffer_add(Z = buffer_new(), A.s, A.len);
240 }
241 atok(Z) ::= SPACE(A) . {
242     buffer_add(Z = buffer_new(), A.s, A.len);
243 }
244 atok(Z) ::= atok(A) escnl .              { Z = A; }
245 atok(Z) ::= atok(A) BSLASH non_nl(B) .   { Z = buffer_escape(A, B.s, B.len); }
246 atok(Z) ::= atok(A) svar(B) .            { substvar(Z = A, B); }
247 atok(Z) ::= atok(A) BQUOTE bqtok(B) BQUOTE . { /* XXX */ buffer_merge(Z = A, &B); }
248
249 rcline ::= ALIAS token SPACE atok to_eol .
250
251 /* }}} */
252 /* {{{ colors */
253
254 rcline ::= COLOR token token token to_eol .
255 rcline ::= COLOR token token token token to_eol .
256 rcline ::= UNCOLOR token simple_list to_eol .
257 rcline ::= MONO token token to_eol .
258 rcline ::= MONO token token token to_eol .
259 rcline ::= UNMONO token simple_list to_eol .
260
261 /* }}} */
262 /* {{{ hooks */
263
264 rcline ::= ACCOUNT_HOOK token token to_eol .
265 rcline ::= APPEND_HOOK token token to_eol .
266 rcline ::= CHARSET_HOOK token token to_eol .
267 rcline ::= CLOSE_HOOK token token to_eol .
268 rcline ::= CRYPT_HOOK token token to_eol .
269 rcline ::= FCC_HOOK token token to_eol .
270 rcline ::= FCC_SAVE_HOOK token token to_eol .
271 rcline ::= FOLDER_HOOK token token to_eol .
272 rcline ::= ICONV_HOOK token token to_eol .
273 rcline ::= MBOX_HOOK token token to_eol .
274 rcline ::= MESSAGE_HOOK token token to_eol .
275 rcline ::= OPEN_HOOK token token to_eol .
276 rcline ::= PGP_HOOK token token to_eol .
277 rcline ::= REPLY_HOOK token token to_eol .
278 rcline ::= SAVE_HOOK token token to_eol .
279 rcline ::= SEND2_HOOK token token to_eol .
280 rcline ::= SEND_HOOK token token to_eol .
281
282 rcline ::= UNHOOK token to_eol .
283
284 /* }}} */
285 /* {{{ buffy related  */
286
287 mailboxes ::= .
288 mailboxes ::= mailboxes token(A) . {
289     if (A->len) {
290         char buf[_POSIX_PATH_MAX];
291         BUFFY *tmp;
292         int i;
293
294         m_strcpy(buf, sizeof(buf), A->data);
295         mutt_expand_path(buf, sizeof(buf));
296         i = buffy_lookup(buf);
297         if (i < 0) {
298             tmp = p_new(BUFFY, 1);
299             tmp->path = m_strdup(buf);
300             buffy_array_append(&Incoming, tmp);
301         } else {
302             tmp = Incoming.arr[i];
303         }
304
305         tmp->new = 0;
306         tmp->notified = 1;
307         tmp->newly_created = 0;
308     }
309     buffer_delete(&A);
310 }
311 rcline ::= MAILBOXES mailboxes to_eol .
312
313 unmailboxes ::= .
314 unmailboxes ::= unmailboxes token(A) . {
315     if (A->len) {
316         if (A->data[0] == '*' && A->len == 1) {
317             buffy_array_wipe(&Incoming);
318         } else {
319             char buf[_POSIX_PATH_MAX];
320             BUFFY *tmp;
321             int i;
322
323             m_strcpy(buf, sizeof(buf), A->data);
324             mutt_expand_path(buf, sizeof(buf));
325             i = buffy_lookup(buf);
326             tmp = buffy_array_take(&Incoming, i);
327             buffy_delete(&tmp);
328         }
329     }
330     buffer_delete(&A);
331 }
332 rcline ::= UNMAILBOXES unmailboxes to_eol .
333
334 /* }}} */
335 /* {{{ lists (alternative_order, auto_view, hdr_order, mime_lookup */
336
337 rcline ::= ALTERNATIVE_ORDER simple_list(L) to_eol . {
338     string_list_append(&AlternativeOrderList, string_list_rev(L));
339 }
340 rcline ::= AUTO_VIEW         simple_list(L) to_eol . {
341     string_list_append(&AutoViewList, string_list_rev(L));
342 }
343 rcline ::= HDR_ORDER         simple_list(L) to_eol . {
344     string_list_append(&HeaderOrderList, string_list_rev(L));
345 }
346 rcline ::= MIME_LOOKUP       simple_list(L) to_eol . {
347     string_list_append(&MimeLookupList, string_list_rev(L));
348 }
349
350 /* }}} */
351
352 /* vim: set indentexpr= cin: */