/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * Copyright © 2006 Pierre Habouzit */ %include { # include # include "mutt.h" # include "parse.h" # include "buffy.h" static buffer_t *buffer_merge(buffer_t *A, buffer_t **B) { buffer_addbuf(A, *B); buffer_delete(B); return A; } static inline int to_control(int c) { return (toupper((unsigned char)c) - 'A' + 1) & 0x7f; } static buffer_t *buffer_escape(buffer_t *buf, const char *s, ssize_t len) { assert (len > 0); switch (*s) { case 'c': case 'Z': if (len < 2) break; buffer_addch(buf, to_control(s[1])); buffer_add(buf, s + 2, len - 2); return buf; case 'x': if (len >= 3) { int i = (hexval(s[1]) << 4) | hexval(s[2]); if (i >= 0) { buffer_addch(buf, i); buffer_add(buf, s + 3, len - 3); return buf; } } break; case '0': case '1': case '2': case '3': if (len >= 3) { int i = (octval(s[0]) << 6) | (octval(s[1]) << 3) | octval(s[2]); if (i >= 0) { buffer_addch(buf, i); buffer_add(buf, s + 3, len - 3); return buf; } } break; case 'e': buffer_addch(buf, '\e'); return buf; case 'f': buffer_addch(buf, '\f'); return buf; case 'n': buffer_addch(buf, '\n'); return buf; case 'r': buffer_addch(buf, '\r'); return buf; case 't': buffer_addch(buf, '\t'); return buf; case 'v': buffer_addch(buf, '\v'); return buf; default: break; } buffer_add(buf, s, len); return buf; } static void substvar(buffer_t *buf, const segment seg) { const char *res; char tmp[STRING]; char var[STRING]; if (m_strncpy(var, sizeof(var), seg.s, seg.len) <= 0) return; if ((res = getenv(var))) { buffer_addstr(buf, res); return; } if (mutt_option_value(var, tmp, sizeof(tmp))) { buffer_addstr(buf, tmp); } } } %name rcparse %token_prefix RCTK_ %token_type { segment } %start_symbol rc %extra_argument { struct rcstate *state } /****************************************************************************/ /* Often used */ /****************************************************************************/ escnl ::= BSLASH NL . { state->linenum++; } sp ::= SPACE . sp ::= sp SPACE . sp ::= sp escnl SPACE . non_nl ::= ATOM|SPACE|BQUOTE|BSLASH|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|SQUOTE|RBRACE . non_nl_star ::= . non_nl_star ::= non_nl_star non_nl . to_eol_aux ::= NL . { state->linenum++; } to_eol_aux ::= SHARP non_nl_star NL . { state->linenum++; } to_eol ::= to_eol_aux . to_eol ::= sp to_eol_aux . /****************************************************************************/ /* Our macro tokens */ /****************************************************************************/ /* {{{*/ %type svar { segment } svar(Z) ::= DOLLAR ATOM(B) . { Z = B; } svar(Z) ::= DOLLAR LBRACE ATOM(B) RBRACE . { Z = B; } /* '-quoted tokens */ %type sqtok { buffer_t* } %destructor sqtok { buffer_delete(&$$); } sqtok(Z) ::= . { Z = buffer_new(); } sqtok(Z) ::= sqtok(A) escnl . { Z = A; } sqtok(Z) ::= sqtok(A) BSLASH BSLASH|SQUOTE(B) . { buffer_addch(Z = A, *B.s); } sqtok(Z) ::= sqtok(A) BSLASH ATOM|SPACE|BQUOTE|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|RBRACE(B) . { buffer_addch(Z = A, '\\'); buffer_add(Z, B.s, B.len); } sqtok(Z) ::= sqtok(A) ATOM|SPACE|BQUOTE|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|RBRACE(B) . { buffer_add(Z = A, B.s, B.len); } /* `-quoted tokens */ %type bqtok { buffer_t* } %destructor bqtok { buffer_delete(&$$); } bqtok(Z) ::= . { Z = buffer_new(); } bqtok(Z) ::= bqtok(A) escnl . { Z = A; } bqtok(Z) ::= bqtok(A) BSLASH non_nl(B) . { Z = buffer_escape(A, B.s, B.len); } bqtok(Z) ::= bqtok(A) svar(B) . { substvar(Z = A, B); } bqtok(Z) ::= bqtok(A) ATOM|SPACE|SHARP|EQUAL|LBRACE|RBRACE|SQUOTE|DQUOTE(B) . { buffer_add(Z = A, B.s, B.len); } /* "-quoted tokens */ %type dqtok { buffer_t* } %destructor dqtok { buffer_delete(&$$); } dqtok(Z) ::= . { Z = buffer_new(); } dqtok(Z) ::= dqtok(A) escnl . { Z = A; } dqtok(Z) ::= dqtok(A) BSLASH non_nl(B) . { Z = buffer_escape(A, B.s, B.len); } dqtok(Z) ::= dqtok(A) svar(B) . { substvar(Z = A, B); } dqtok(Z) ::= dqtok(A) ATOM|SPACE|SHARP|EQUAL|LBRACE|RBRACE|SQUOTE(B) . { buffer_add(Z = A, B.s, B.len); } dqtok(Z) ::= dqtok(A) BQUOTE bqtok(B) BQUOTE . { /* XXX */ buffer_merge(Z = A, &B); } /* unquoted tokens */ %type uqtok { buffer_t* } %destructor uqtok { buffer_delete(&$$); } uqtok(Z) ::= BSLASH non_nl(A) . { buffer_add(Z = buffer_new(), A.s, A.len); } uqtok(Z) ::= svar(A) . { substvar(Z = buffer_new(), A); } uqtok(Z) ::= ATOM|EQUAL|LBRACE|RBRACE(A) . { buffer_add(Z = buffer_new(), A.s, A.len); } uqtok(Z) ::= SQUOTE sqtok(A) SQUOTE . { Z = A; } uqtok(Z) ::= DQUOTE dqtok(A) DQUOTE . { Z = A; } uqtok(Z) ::= BQUOTE bqtok(A) BQUOTE . { /* XXX */ Z = A; } /* token accumulator: NEVER USE DIRECTLY */ %type tokaux { buffer_t* } %destructor tokaux { abort(); } tokaux(Z) ::= uqtok(A) . { Z = A; } tokaux(Z) ::= tokaux(A) escnl . { Z = A; } tokaux(Z) ::= tokaux(A) uqtok(B) . { Z = buffer_merge(A, &B); } %type token { buffer_t* } %destructor token { buffer_delete(&$$); } token(Z) ::= sp tokaux(A) . { Z = A; } /* }}}*/ /****************************************************************************/ /* list of tokens */ /****************************************************************************/ %type simple_list { string_list_t * } %destructor simple_list { string_list_wipe(&$$); } simple_list ::= . simple_list(L) ::= simple_list(A) token(B) . { if (B->len) { L = string_item_new(); L->data = buffer_unwrap(&B); L->next = A; } else { L = A; buffer_delete(&B); } } /****************************************************************************/ /* Entry point : the rc lines */ /****************************************************************************/ rc ::= rclines . rclines ::= . rclines ::= rclines rcline . rcline ::= to_eol . rcline ::= BIND token token token to_eol . rcline ::= EXEC simple_list to_eol . rcline ::= MACRO token token token to_eol . rcline ::= MACRO token token token token to_eol . rcline ::= PUSH token to_eol . rcline ::= SCORE token token to_eol . rcline ::= UNSCORE simple_list to_eol . /* {{{ alias */ %type atok { buffer_t* } %destructor atok { buffer_delete(&$$); } atok(Z) ::= ATOM|SHARP|DQUOTE|EQUAL|LBRACE|SQUOTE|RBRACE(A) . { buffer_add(Z = buffer_new(), A.s, A.len); } atok(Z) ::= SPACE(A) . { buffer_add(Z = buffer_new(), A.s, A.len); } atok(Z) ::= atok(A) escnl . { Z = A; } atok(Z) ::= atok(A) BSLASH non_nl(B) . { Z = buffer_escape(A, B.s, B.len); } atok(Z) ::= atok(A) svar(B) . { substvar(Z = A, B); } atok(Z) ::= atok(A) BQUOTE bqtok(B) BQUOTE . { /* XXX */ buffer_merge(Z = A, &B); } rcline ::= ALIAS token SPACE atok to_eol . /* }}} */ /* {{{ colors */ rcline ::= COLOR token token token to_eol . rcline ::= COLOR token token token token to_eol . rcline ::= UNCOLOR token simple_list to_eol . rcline ::= MONO token token to_eol . rcline ::= MONO token token token to_eol . rcline ::= UNMONO token simple_list to_eol . /* }}} */ /* {{{ hooks */ rcline ::= ACCOUNT_HOOK token token to_eol . rcline ::= APPEND_HOOK token token to_eol . rcline ::= CHARSET_HOOK token token to_eol . rcline ::= CLOSE_HOOK token token to_eol . rcline ::= CRYPT_HOOK token token to_eol . rcline ::= FCC_HOOK token token to_eol . rcline ::= FCC_SAVE_HOOK token token to_eol . rcline ::= FOLDER_HOOK token token to_eol . rcline ::= ICONV_HOOK token token to_eol . rcline ::= MBOX_HOOK token token to_eol . rcline ::= MESSAGE_HOOK token token to_eol . rcline ::= OPEN_HOOK token token to_eol . rcline ::= PGP_HOOK token token to_eol . rcline ::= REPLY_HOOK token token to_eol . rcline ::= SAVE_HOOK token token to_eol . rcline ::= SEND2_HOOK token token to_eol . rcline ::= SEND_HOOK token token to_eol . rcline ::= UNHOOK token to_eol . /* }}} */ /* {{{ buffy related */ mailboxes ::= . mailboxes ::= mailboxes token(A) . { if (A->len) { char buf[_POSIX_PATH_MAX]; BUFFY *tmp; int i; m_strcpy(buf, sizeof(buf), A->data); mutt_expand_path(buf, sizeof(buf)); i = buffy_lookup(buf); if (i < 0) { tmp = p_new(BUFFY, 1); tmp->path = m_strdup(buf); buffy_array_append(&Incoming, tmp); } else { tmp = Incoming.arr[i]; } tmp->new = 0; tmp->notified = 1; tmp->newly_created = 0; } buffer_delete(&A); } rcline ::= MAILBOXES mailboxes to_eol . unmailboxes ::= . unmailboxes ::= unmailboxes token(A) . { if (A->len) { if (A->data[0] == '*' && A->len == 1) { buffy_array_wipe(&Incoming); } else { char buf[_POSIX_PATH_MAX]; BUFFY *tmp; int i; m_strcpy(buf, sizeof(buf), A->data); mutt_expand_path(buf, sizeof(buf)); i = buffy_lookup(buf); tmp = buffy_array_take(&Incoming, i); buffy_delete(&tmp); } } buffer_delete(&A); } rcline ::= UNMAILBOXES unmailboxes to_eol . /* }}} */ /* {{{ lists (alternative_order, auto_view, hdr_order, mime_lookup */ rcline ::= ALTERNATIVE_ORDER simple_list(L) to_eol . { string_list_append(&AlternativeOrderList, string_list_rev(L)); } rcline ::= AUTO_VIEW simple_list(L) to_eol . { string_list_append(&AutoViewList, string_list_rev(L)); } rcline ::= HDR_ORDER simple_list(L) to_eol . { string_list_append(&HeaderOrderList, string_list_rev(L)); } rcline ::= MIME_LOOKUP simple_list(L) to_eol . { string_list_append(&MimeLookupList, string_list_rev(L)); } /* }}} */ /* vim: set indentexpr= cin: */