Really check for fd
[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 "mutt.h"
22 #   include "parse.h"
23
24     static buffer_t *buffer_merge(buffer_t *A, buffer_t **B)
25     {
26         buffer_addbuf(A, *B);
27         buffer_delete(B);
28         return A;
29     }
30
31     static inline int to_control(int c) {
32         return (toupper((unsigned char)c) - 'A' + 1) & 0x7f;
33     }
34
35     static buffer_t *buffer_escape(buffer_t *buf, const char *s, ssize_t len)
36     {
37         assert (len > 0);
38
39         switch (*s) {
40           case 'c': case 'Z':
41             if (len < 2)
42                 break;
43             buffer_addch(buf, to_control(s[1]));
44             buffer_add(buf, s + 2, len - 2);
45             return buf;
46
47           case 'x':
48             if (len >= 3) {
49                 int i = (hexval(s[1]) << 4) | hexval(s[2]);
50                 if (i >= 0) {
51                     buffer_addch(buf, i);
52                     buffer_add(buf, s + 3, len - 3);
53                     return buf;
54                 }
55             }
56             break;
57
58           case '0': case '1': case '2': case '3':
59             if (len >= 3) {
60                 int i = (octval(s[0]) << 6) | (octval(s[1]) << 3) | octval(s[2]);
61                 if (i >= 0) {
62                     buffer_addch(buf, i);
63                     buffer_add(buf, s + 3, len - 3);
64                     return buf;
65                 }
66             }
67             break;
68
69           case 'e': buffer_addch(buf, '\e'); return buf;
70           case 'f': buffer_addch(buf, '\f'); return buf;
71           case 'n': buffer_addch(buf, '\n'); return buf;
72           case 'r': buffer_addch(buf, '\r'); return buf;
73           case 't': buffer_addch(buf, '\t'); return buf;
74           case 'v': buffer_addch(buf, '\v'); return buf;
75
76           default:
77             break;
78         }
79
80         buffer_add(buf, s, len);
81         return buf;
82     }
83
84     static void substvar(buffer_t *buf, const segment seg)
85     {
86         const char *res;
87         char tmp[STRING];
88         char var[STRING];
89
90         if (m_strncpy(var, sizeof(var), seg.s, seg.len) <= 0)
91             return;
92
93         if ((res = getenv(var))) {
94             buffer_addstr(buf, res);
95             return;
96         }
97         if (mutt_option_value(var, tmp, sizeof(tmp))) {
98             buffer_addstr(buf, tmp);
99         }
100     }
101 }
102
103 %name rcparse
104 %token_prefix RCTK_
105 %token_type  { segment }
106 %start_symbol rc
107 %extra_argument { struct rcstate *state }
108
109 /****************************************************************************/
110 /* Often used                                                               */
111 /****************************************************************************/
112
113 escnl ::= BSLASH NL .                      { state->linenum++; }
114
115 sp ::= SPACE .
116 sp ::= sp SPACE .
117 sp ::= sp escnl SPACE .
118
119 non_nl ::= ATOM|SPACE|BQUOTE|BSLASH|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|SQUOTE|RBRACE .
120 non_nl_star ::= .
121 non_nl_star ::= non_nl_star non_nl .
122
123 to_eol_aux ::= NL .                        { state->linenum++; }
124 to_eol_aux ::= SHARP non_nl_star NL .      { state->linenum++; }
125 to_eol ::= to_eol_aux .
126 to_eol ::= sp to_eol_aux .
127
128 /****************************************************************************/
129 /* Our macro tokens                                                         */
130 /****************************************************************************/
131
132 %type svar { segment }
133 svar(Z) ::= DOLLAR ATOM(B) .               { Z = B; }
134 svar(Z) ::= DOLLAR LBRACE ATOM(B) RBRACE . { Z = B; }
135
136 /* '-quoted tokens */
137 %type sqtok { buffer_t* }
138 %destructor sqtok  { buffer_delete(&$$); }
139 sqtok(Z) ::= .                                 { Z = buffer_new(); }
140 sqtok(Z) ::= sqtok(A) escnl .                  { Z = A; }
141 sqtok(Z) ::= sqtok(A) BSLASH BSLASH|SQUOTE(B) . { buffer_addch(Z = A, *B.s); }
142 sqtok(Z) ::= sqtok(A) BSLASH ATOM|SPACE|BQUOTE|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|RBRACE(B) . {
143     buffer_addch(Z = A, '\\');
144     buffer_add(Z, B.s, B.len);
145 }
146 sqtok(Z) ::= sqtok(A) ATOM|SPACE|BQUOTE|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|RBRACE(B) . {
147     buffer_add(Z = A, B.s, B.len);
148 }
149
150 /* `-quoted tokens */
151 %type bqtok { buffer_t* }
152 %destructor bqtok { buffer_delete(&$$); }
153 bqtok(Z) ::= .                             { Z = buffer_new(); }
154 bqtok(Z) ::= bqtok(A) escnl .              { Z = A; }
155 bqtok(Z) ::= bqtok(A) BSLASH non_nl(B) .   { Z = buffer_escape(A, B.s, B.len); }
156 bqtok(Z) ::= bqtok(A) svar(B) .            { substvar(Z = A, B); }
157 bqtok(Z) ::= bqtok(A) ATOM|SPACE|SHARP|EQUAL|LBRACE|RBRACE|SQUOTE|DQUOTE(B)  . {
158     buffer_add(Z = A, B.s, B.len);
159 }
160
161 /* "-quoted tokens */
162 %type dqtok { buffer_t* }
163 %destructor dqtok { buffer_delete(&$$); }
164 dqtok(Z) ::= .                             { Z = buffer_new(); }
165 dqtok(Z) ::= dqtok(A) escnl .              { Z = A; }
166 dqtok(Z) ::= dqtok(A) BSLASH non_nl(B) .   { Z = buffer_escape(A, B.s, B.len); }
167 dqtok(Z) ::= dqtok(A) svar(B) .            { substvar(Z = A, B); }
168 dqtok(Z) ::= dqtok(A) ATOM|SPACE|SHARP|EQUAL|LBRACE|RBRACE|SQUOTE(B)  . {
169     buffer_add(Z = A, B.s, B.len);
170 }
171 dqtok(Z) ::= dqtok(A) BQUOTE bqtok(B) BQUOTE . { /* XXX */ buffer_merge(Z = A, &B); }
172
173 /* unquoted tokens */
174 %type uqtok { buffer_t* }
175 %destructor uqtok { buffer_delete(&$$); }
176 uqtok(Z) ::= BSLASH non_nl(A) .            { buffer_add(Z = buffer_new(), A.s, A.len); }
177 uqtok(Z) ::= svar(A) .                     { substvar(Z = buffer_new(), A); }
178 uqtok(Z) ::= ATOM|EQUAL|LBRACE|RBRACE(A) . { buffer_add(Z = buffer_new(), A.s, A.len); }
179 uqtok(Z) ::= SQUOTE sqtok(A) SQUOTE .      { Z = A; }
180 uqtok(Z) ::= DQUOTE dqtok(A) DQUOTE .      { Z = A; }
181 uqtok(Z) ::= BQUOTE bqtok(A) BQUOTE .      { /* XXX */ Z = A; }
182
183 /* token accumulator */
184 %type token { buffer_t* }
185 %destructor token { buffer_delete(&$$); }
186 token(Z) ::= uqtok(A) .                    { Z = A; }
187 token(Z) ::= token(A) escnl .              { Z = A; }
188 token(Z) ::= token(A) uqtok(B) .           { Z = buffer_merge(A, &B); }
189
190 /****************************************************************************/
191 /* list of tokens                                                           */
192 /****************************************************************************/
193
194 %type simple_list { string_list_t * }
195 %destructor simple_list { string_list_wipe(&$$); }
196 simple_list ::= .
197 simple_list(L) ::= simple_list(A) sp token(B) . {
198     L = string_item_new();
199     L->data = buffer_unwrap(&B);
200     L->next = A;
201 }
202
203
204 /****************************************************************************/
205 /* Entry point : the rc lines                                               */
206 /****************************************************************************/
207
208 rc ::= rclines .
209 rclines ::= .
210 rclines ::= rclines rcline .
211
212 rcline ::= ALTERNATIVE_ORDER simple_list(L) to_eol . {
213     string_list_append(&AlternativeOrderList, string_list_rev(L));
214 }
215 rcline ::= AUTO_VIEW         simple_list(L) to_eol . {
216     string_list_append(&AutoViewList, string_list_rev(L));
217 }
218 rcline ::= HDR_ORDER         simple_list(L) to_eol . {
219     string_list_append(&HeaderOrderList, string_list_rev(L));
220 }
221 rcline ::= MIME_LOOKUP       simple_list(L) to_eol . {
222     string_list_append(&MimeLookupList, string_list_rev(L));
223 }
224
225
226 /* vim: set indentexpr= cin: */