X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=buffer.c;h=bfa0dd82b9e74c3202bae2053a6b76462fbc100b;hp=adbc8f649db0e38f2f203b28074508197343766c;hb=9e6ab0152703ad301042ce8810859f41fbee405a;hpb=666a29207bb781f47ec85f6a3c3cdeb554b30c21 diff --git a/buffer.c b/buffer.c index adbc8f6..bfa0dd8 100644 --- a/buffer.c +++ b/buffer.c @@ -12,11 +12,14 @@ #include #include +#include + +#include #include "buffer.h" -#include "lib/mem.h" #include "lib/str.h" +#include "lib/debug.h" /* * Creates and initializes a BUFFER*. If passed an existing BUFFER*, @@ -25,15 +28,15 @@ * Disregards the 'destroy' flag, which seems reserved for caller. * This is bad, but there's no apparent protocol for it. */ -BUFFER *mutt_buffer_init (BUFFER * b) +BUFFER *mutt_buffer_init(BUFFER *b) { if (!b) { - b = mem_malloc (sizeof (BUFFER)); + b = p_new(BUFFER, 1); if (!b) return NULL; } else { - mem_free(&b->data); + p_delete(&b->data); } memset (b, 0, sizeof (BUFFER)); return b; @@ -47,7 +50,7 @@ BUFFER *mutt_buffer_init (BUFFER * b) * Disregards the 'destroy' flag, which seems reserved for caller. * This is bad, but there's no apparent protocol for it. */ -BUFFER *mutt_buffer_from (BUFFER * b, char *seed) +BUFFER *mutt_buffer_from (BUFFER * b, const char *seed) { if (!seed) return NULL; @@ -74,25 +77,200 @@ void mutt_buffer_free (BUFFER ** p) if (!p || !*p) return; - mem_free (&(*p)->data); + p_delete(&(*p)->data); /* dptr is just an offset to data and shouldn't be freed */ - mem_free (p); + p_delete(p); } /* dynamically grows a BUFFER to accomodate s, in increments of 128 bytes. * Always one byte bigger than necessary for the null terminator, and * the buffer is always null-terminated */ -void mutt_buffer_add (BUFFER * buf, const char *s, size_t len) +void mutt_buffer_add (BUFFER *buf, const char *s, size_t len) { size_t offset; if (buf->dptr + len + 1 > buf->data + buf->dsize) { offset = buf->dptr - buf->data; buf->dsize += len < 128 ? 128 : len + 1; - mem_realloc ((void **) &buf->data, buf->dsize); + p_realloc(&buf->data, buf->dsize); buf->dptr = buf->data + offset; } memcpy (buf->dptr, s, len); buf->dptr += len; *(buf->dptr) = '\0'; } + +int mutt_extract_token (BUFFER * dest, BUFFER * tok, int flags) +{ + char ch; + char qc = 0; /* quote char */ + char *pc; + + /* reset the destination pointer to the beginning of the buffer */ + dest->dptr = dest->data; + + SKIPWS (tok->dptr); + while ((ch = *tok->dptr)) { + if (!qc) { + if ((ISSPACE (ch) && !(flags & M_TOKEN_SPACE)) || + (ch == '#' && !(flags & M_TOKEN_COMMENT)) || + (ch == '=' && (flags & M_TOKEN_EQUAL)) || + (ch == ';' && !(flags & M_TOKEN_SEMICOLON)) || + ((flags & M_TOKEN_PATTERN) && strchr ("~=!|", ch))) + break; + } + + tok->dptr++; + + if (ch == qc) + qc = 0; /* end of quote */ + else if (!qc && (ch == '\'' || ch == '"') && !(flags & M_TOKEN_QUOTE)) + qc = ch; + else if (ch == '\\' && qc != '\'') { + if (!*tok->dptr) + return -1; /* premature end of token */ + switch (ch = *tok->dptr++) { + case 'c': + case 'C': + if (!*tok->dptr) + return -1; /* premature end of token */ + mutt_buffer_addch (dest, (toupper ((unsigned char) *tok->dptr) + - '@') & 0x7f); + tok->dptr++; + break; + case 'r': + mutt_buffer_addch (dest, '\r'); + break; + case 'n': + mutt_buffer_addch (dest, '\n'); + break; + case 't': + mutt_buffer_addch (dest, '\t'); + break; + case 'f': + mutt_buffer_addch (dest, '\f'); + break; + case 'e': + mutt_buffer_addch (dest, '\033'); + break; + default: + if (isdigit ((unsigned char) ch) && + isdigit ((unsigned char) *tok->dptr) && + isdigit ((unsigned char) *(tok->dptr + 1))) { + + mutt_buffer_addch (dest, + (ch << 6) + (*tok->dptr << 3) + *(tok->dptr + + 1) - 3504); + tok->dptr += 2; + } + else + mutt_buffer_addch (dest, ch); + } + } + else if (ch == '^' && (flags & M_TOKEN_CONDENSE)) { + if (!*tok->dptr) + return -1; /* premature end of token */ + ch = *tok->dptr++; + if (ch == '^') + mutt_buffer_addch (dest, ch); + else if (ch == '[') + mutt_buffer_addch (dest, '\033'); + else if (isalpha ((unsigned char) ch)) + mutt_buffer_addch (dest, toupper ((unsigned char) ch) - '@'); + else { + mutt_buffer_addch (dest, '^'); + mutt_buffer_addch (dest, ch); + } + } + else if (ch == '`' && (!qc || qc == '"')) { + FILE *fp; + pid_t pid; + char *cmd, *ptr; + size_t expnlen; + BUFFER expn; + int line = 0; + + pc = tok->dptr; + do { + if ((pc = strpbrk (pc, "\\`"))) { + /* skip any quoted chars */ + if (*pc == '\\') + pc += 2; + } + } while (pc && *pc != '`'); + if (!pc) { + debug_print (1, ("mismatched backtics\n")); + return (-1); + } + cmd = str_substrdup (tok->dptr, pc); + if ((pid = mutt_create_filter (cmd, NULL, &fp, NULL)) < 0) { + debug_print (1, ("unable to fork command: %s\n", cmd)); + p_delete(&cmd); + return (-1); + } + p_delete(&cmd); + + tok->dptr = pc + 1; + + /* read line */ + memset (&expn, 0, sizeof (expn)); + expn.data = mutt_read_line (NULL, &expn.dsize, fp, &line); + fclose (fp); + mutt_wait_filter (pid); + + /* if we got output, make a new string consiting of the shell ouptput + plus whatever else was left on the original line */ + /* BUT: If this is inside a quoted string, directly add output to + * the token */ + if (expn.data && qc) { + mutt_buffer_addstr (dest, expn.data); + p_delete(&expn.data); + } + else if (expn.data) { + expnlen = str_len (expn.data); + tok->dsize = expnlen + str_len (tok->dptr) + 1; + ptr = xmalloc(tok->dsize); + memcpy (ptr, expn.data, expnlen); + strcpy (ptr + expnlen, tok->dptr); /* __STRCPY_CHECKED__ */ + if (tok->destroy) + p_delete(&tok->data); + tok->data = ptr; + tok->dptr = ptr; + tok->destroy = 1; /* mark that the caller should destroy this data */ + ptr = NULL; + p_delete(&expn.data); + } + } + else if (ch == '$' && (!qc || qc == '"') + && (*tok->dptr == '{' || isalpha ((unsigned char) *tok->dptr))) { + char *env = NULL, *var = NULL; + + if (*tok->dptr == '{') { + tok->dptr++; + if ((pc = strchr (tok->dptr, '}'))) { + var = str_substrdup (tok->dptr, pc); + tok->dptr = pc + 1; + } + } + else { + for (pc = tok->dptr; isalnum ((unsigned char) *pc) || *pc == '_'; + pc++); + var = str_substrdup (tok->dptr, pc); + tok->dptr = pc; + } + if (var) { + char tmp[STRING]; + if ((env = getenv (var)) || + (mutt_option_value (var, tmp, sizeof (tmp)) && (env = tmp))) + mutt_buffer_addstr (dest, env); + } + p_delete(&var); + } + else + mutt_buffer_addch (dest, ch); + } + mutt_buffer_addch (dest, 0); /* terminate the string */ + SKIPWS (tok->dptr); + return 0; +} +