aboutsummaryrefslogtreecommitdiffstats
path: root/src/pattern.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/pattern.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/src/pattern.c b/src/pattern.c
new file mode 100644
index 0000000..6912731
--- /dev/null
+++ b/src/pattern.c
@@ -0,0 +1,151 @@
+/**
+ * scrotty — Screenshot program for Linux's TTY
+ *
+ * Copyright © 2014, 2015 Mattias Andrée (maandree@member.fsf.org)
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "common.h"
+#include "pattern.h"
+
+
+
+/**
+ * Duplicate all '%':s in a buffer until the first occurrence of a zero byte.
+ *
+ * @param buf The buffer.
+ * @param n The size of the buffer.
+ * @return -1 if the buffer is too small, otherwise.
+ * the new position of the first zero byte.
+ */
+static ssize_t
+duplicate_percents (char *restrict buf, size_t n)
+{
+ size_t p = 0, pi, pc = 0, i;
+
+ /* Count number of '%':s. */
+ for (i = 0; buf[i]; i++)
+ if (buf[i] == '%')
+ pc++;
+
+ /* Check whether the string will overflow. */
+ if (i + pc > n)
+ return -1;
+
+ /* Duplicate all '%':s. */
+ for (pi = 0; pi < pc; pi++)
+ {
+ p = (size_t)(strchr (buf + p, '%') - buf);
+ memmove (buf + p + 1, buf + p, (i - (p - pi)) * sizeof (char));
+ p += 2;
+ }
+
+ return (ssize_t)(i + pi);
+}
+
+
+/**
+ * Parse and evaluate a --exec argument or filename pattern.
+ *
+ * If `path != NULL` than all non-escaped spaces in
+ * `pattern` will be stored as 255-bytes in `buf`.
+ *
+ * @param buf The output buffer.
+ * @param n The size of `buf`.
+ * @param pattern The pattern to evaluate.
+ * @param fbno The index of the framebuffer.
+ * @param width The width of the image/framebuffer.
+ * @param height The height of the image/framebuffer.
+ * @param path The filename of the saved image, `NULL`
+ * during the evaluation of the filename pattern.
+ * @return Zero on success, -1 on error.
+ */
+int
+evaluate (char *restrict buf, size_t n, const char *restrict pattern,
+ int fbno, long width, long height, const char *restrict path)
+{
+#define P(format, value) r = snprintf (buf + i, n - i, format "%zn", value, &j)
+
+ size_t i = 0;
+ ssize_t j = 0;
+ int percent = 0, backslash = 0, dollar = 0, r;
+ char c;
+ char *fmt;
+ time_t t;
+ struct tm *tm;
+
+ /* Expand '$' and '\'. */
+ while ((i < n) && ((c = *pattern++)))
+ if (dollar)
+ {
+ dollar = 0;
+ if (path == NULL)
+ if ((c == 'f') || (c == 'n'))
+ continue;
+ if (c == 'i') P ("%i", fbno);
+ else if (c == 'f') P ("%s", path);
+ else if (c == 'n') P ("%s", strrchr (path, '/') ? (strrchr (path, '/') + 1) : path);
+ else if (c == 'p') P ("%ju", (uintmax_t)width * (uintmax_t)height);
+ else if (c == 'w') P ("%li", width);
+ else if (c == 'h') P ("%li", height);
+ else if (c == '$') r = 0, j = 1, buf[i] = '$';
+ else if ((r < 0) || (j <= 0))
+ return -1;
+ else if ((c == 'f') || (c == 'n'))
+ if (j = duplicate_percents (buf + i, n - i), j < 0)
+ goto enametoolong;
+ i += (size_t)j;
+ }
+ else if (backslash) buf[i++] = (c == 'n' ? '\n' : c), backslash = 0;
+ else if (percent) buf[i++] = c, percent = 0;
+ else if (c == '%') buf[i++] = c, percent = 1;
+ else if (c == '\\') backslash = 1;
+ else if (c == '$') dollar = 1;
+ else if (c == ' ') buf[i++] = path == NULL ? ' ' : (char)255; /* 255 is not valid in UTF-8. */
+ else buf[i++] = c;
+ if (i >= n)
+ goto enametoolong;
+ buf[i] = '\0';
+
+ /* Check whether there are any '%' to expand. */
+ if (strchr (buf, '%') == NULL)
+ return 0;
+
+ /* Copy the buffer so we can reuse the buffer and use its old content for the format. */
+ fmt = alloca ((strlen (buf) + 1) * sizeof (char));
+ memcpy (fmt, buf, (strlen (buf) + 1) * sizeof (char));
+
+ /* Expand '%'. */
+ t = time (NULL);
+ tm = localtime (&t);
+ if (tm == NULL)
+ goto fail;
+
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+ if (strftime (buf, n, fmt, tm) == 0)
+ goto enametoolong; /* No errors are defined for `strftime`. What else can we do? */
+
+ return 0;
+
+ enametoolong:
+ return errno = ENAMETOOLONG, -1;
+
+ fail:
+ return -1;
+
+#undef P
+}
+