--- mutt-1.5.8/PATCHES~ never +++ mutt-1.5.8/PATCHES Tue Mar 8 21:13:31 CST 2005 @@ -1,0 +1 @@ +patch-1.5.8.dgc.stack.1 diff -Pur mutt-1.5.8-base/globals.h mutt-1.5.8/globals.h --- mutt-1.5.8-base/globals.h Sat Feb 12 14:01:02 2005 +++ mutt-1.5.8/globals.h Tue Mar 8 19:50:46 2005 @@ -138,6 +138,10 @@ WHERE LIST *MimeLookupList INITVAL(0); WHERE LIST *UnIgnore INITVAL(0); +WHERE LIST *StackA INITVAL(0); +WHERE LIST *StackB INITVAL(0); +WHERE LIST *StackC INITVAL(0); + WHERE RX_LIST *Alternates INITVAL(0); WHERE RX_LIST *UnAlternates INITVAL(0); WHERE RX_LIST *MailLists INITVAL(0); diff -Pur mutt-1.5.8-base/init.c mutt-1.5.8/init.c --- mutt-1.5.8-base/init.c Sat Feb 12 13:06:16 2005 +++ mutt-1.5.8/init.c Tue Mar 8 19:50:46 2005 @@ -105,6 +105,116 @@ return (-1); } +/* Given variable "s", render its value as a string. + * Static storage ok: this should be copied by caller. + * The goal is to return something that can be set in + * a .muttrc file as a value for the variable. */ +static char * render_variable(char *s) +{ + int idx; + static char buf[STRING]; /* for printing numbers & addrs */ + + if (s == NULL) + return NULL; + + if ((idx = mutt_option_index (s)) == -1) + return NULL; + + switch (MuttVars[idx].type) + { + case DT_BOOL: /* boolean option */ + return MuttVars[idx].data ? "yes" : "no"; + + case DT_NUM: /* a number */ + snprintf(buf, sizeof(buf), "%lu", MuttVars[idx].data); + return buf; + + case DT_STR: /* a string */ + case DT_PATH: /* a pathname */ + return (*((char **) MuttVars[idx].data)); + + case DT_QUAD: /* quad-option (yes/no/ask-yes/ask-no) */ + switch (MuttVars[idx].data) + { + case M_YES: + return "yes"; + case M_NO: + return "no"; + case M_ASKYES: + return "ask-yes"; + case M_ASKNO: + return "ask-no"; + } + return "no"; + + case DT_SORT: /* sorting methods */ + return mutt_getnamebyvalue(MuttVars[idx].data, SortMethods); + + case DT_RX: /* regular expressions */ + if (*((REGEXP **)MuttVars[idx].data)) + return (*((REGEXP **)MuttVars[idx].data))->pattern; + + case DT_MAGIC: /* mailbox type */ + switch (MuttVars[idx].data) + { + case M_MBOX: + return "mbox"; + case M_MMDF: + return "MMDF"; + case M_MH: + return "MH"; + case M_MAILDIR: + return "Maildir"; + } + return NULL; + + case DT_SYN: /* synonym for another variable */ + return render_variable((char *)MuttVars[idx].data); + + case DT_ADDR: /* e-mail address */ + *buf = '\0'; + rfc822_write_address (buf, sizeof (buf), + *((ADDRESS **) MuttVars[idx].data), 0); + return buf; + } + + return NULL; +} + +/* pop top item from stack */ +static int stack_pop (LIST **st, char *buf, int size) +{ + LIST *prev, *top; + + if (buf && size) + *buf = '\0'; + + prev = NULL; + top = *st; + if (top == NULL) + return -1; + + while (top->next) + { + prev = top; + top = top->next; + } + + if (buf) + strncpy(buf, top->data, size); + + safe_free(&top->data); + safe_free(&top); + + if (prev) + prev->next = NULL; + else + *st = NULL; + + return 0; +} + + int mutt_extract_token (BUFFER *dest, BUFFER *tok, int flags) { char ch; @@ -281,6 +391,38 @@ mutt_buffer_addstr (dest, env); FREE (&var); } + else if (ch == '$' && (!qc || qc == '"') && *tok->dptr == '[') + { + char *var = NULL; + char val[STRING]; + + tok->dptr++; + if ((pc = strchr (tok->dptr, ']'))) + { + var = mutt_substrdup (tok->dptr, pc); + tok->dptr = pc + 1; + } + + if (!ascii_strcasecmp(var, "a")) + { + if (stack_pop(&StackA, val, sizeof(val)) != -1) + mutt_buffer_addstr (dest, NONULL(val)); + } + else if (!ascii_strcasecmp(var, "b")) + { + if (stack_pop(&StackB, val, sizeof(val)) != -1) + mutt_buffer_addstr (dest, NONULL(val)); + } + else if (!ascii_strcasecmp(var, "c")) + { + if (stack_pop(&StackC, val, sizeof(val)) != -1) + mutt_buffer_addstr (dest, NONULL(val)); + } + else + mutt_buffer_addstr (dest, NONULL(render_variable(var))); + + FREE (&var); + } else mutt_buffer_addch (dest, ch); } @@ -1721,6 +1863,182 @@ mutt_expand_path (path, sizeof (path)); return (source_rc (path, err)); } + +static int parse_stack (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) +{ + LIST **st, *top, *prev, *new; + char *stname; + int exch = 0, clear = 0, pop = 0, dup = 0, query = 0; + + if (!MoreArgs(s)) + { + strfcpy (err->data, _("stack: no stack identified"), err->dsize); + return -1; + } + + mutt_extract_token(tmp, s, 0); + stname = tmp->data; + if (*stname == '%') + { + exch = 1; + ++stname; + } + else if (*stname == '-') + { + pop = 1; + ++stname; + } + else if (*stname == '+') + { + dup = 1; + ++stname; + } + else if (*stname == '=') + { + clear = 1; + ++stname; + } + else if (*stname == '?') + { + query = 1; + ++stname; + } + + if (!ascii_strcasecmp(stname, "a")) + st = &StackA; + else if (!ascii_strcasecmp(stname, "b")) + st = &StackB; + else if (!ascii_strcasecmp(stname, "c")) + st = &StackC; + else + { + snprintf (err->data, err->dsize, _("stack: \"%s\" not a valid stack"), + NONULL(stname)); + return -1; + } + + /* query stack depth/contents */ + if (query) + { + int n = 0; + char *s = NULL; + + top = *st; + if (top == NULL) + { + s = NULL; + n = 0; + } + else + { + do { + s = top->data; + ++n; + } while ((top = top->next)); + } + + if (n) + snprintf (err->data, err->dsize, _("stack \"%s\": depth %d, top \"%s\""), + stname, n, NONULL(s)); + else + snprintf (err->data, err->dsize, _("stack \"%s\": depth %d"), stname, n); + + return 0; + } + + /* remove all items from stack */ + if (clear) + { + mutt_free_list(st); + return 0; + } + + /* duplicate top item on stack */ + if (dup) + { + top = *st; + if (top == NULL) + { + strfcpy (err->data, _("stack: nothing to duplicate"), err->dsize); + return -1; + } + + while (top->next) + top = top->next; + + new = safe_malloc(sizeof(LIST)); + new->data = safe_strdup((char *)top->data); + new->next = NULL; + top->next = new; + return 0; + } + + if (pop) + { + if (stack_pop(st, NULL, 0) == -1) + { + strfcpy (err->data, _("stack: nothing to remove"), err->dsize); + return -1; + } + return 0; + } + + /* swap top two items on stack */ + if (exch) + { + void *save; + + prev = NULL; + top = *st; + while (top->next) + { + prev = top; + top = top->next; + } + + if (!prev || !top) + { + strfcpy (err->data, _("stack: not enough items to exchange"), err->dsize); + return -1; + } + + /* cheaper to swap data instead of list ptrs */ + save = prev->data; + prev->data = top->data; + top->data = save; + return 0; + } + + /* store remaining args */ + if (!MoreArgs(s)) + { + snprintf (err->data, err->dsize, + _("stack: nothing to push onto stack %s"), stname); + return -1; + } + + while (MoreArgs(s)) + { + mutt_extract_token(tmp, s, 0); + new = safe_malloc(sizeof(LIST)); + new->data = safe_strdup(tmp->data); + new->next = NULL; + + top = *st; + if (top == NULL) + { + *st = new; + } + else { + while (top->next) + top = top->next; + top->next = new; + } + } + + return 0; +} + /* line command to execute diff -Pur mutt-1.5.8-base/init.h mutt-1.5.8/init.h --- mutt-1.5.8-base/init.h Sat Feb 12 14:01:10 2005 +++ mutt-1.5.8/init.h Tue Mar 8 19:52:26 2005 @@ -2895,6 +2895,7 @@ static int parse_unmy_hdr (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_subscribe (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_unsubscribe (BUFFER *, BUFFER *, unsigned long, BUFFER *); +static int parse_stack (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_alternates (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_unalternates (BUFFER *, BUFFER *, unsigned long, BUFFER *); @@ -2954,6 +2955,7 @@ { "source", parse_source, 0 }, { "spam", parse_spam_list, M_SPAM }, { "nospam", parse_spam_list, M_NOSPAM }, + { "stack", parse_stack, 0 }, { "subscribe", parse_subscribe, 0 }, { "toggle", parse_set, M_SET_INV }, { "unalias", parse_unalias, 0 },