aboutsummaryrefslogtreecommitdiffstats
path: root/src/scrotty.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/scrotty.c551
1 files changed, 309 insertions, 242 deletions
diff --git a/src/scrotty.c b/src/scrotty.c
index 7a0e31b..8a45b24 100644
--- a/src/scrotty.c
+++ b/src/scrotty.c
@@ -74,69 +74,77 @@ static const char* inttable[] =
/**
- * `argv[0]` from `main`
+ * `argv[0]` from `main`.
*/
-static const char* execname;
+static const char *execname;
/**
* Arguments for `convert`,
* the output file should be printed into `convert_args[2]`.
* `NULL` is `convert` shall not be used.
*/
-static char** convert_args = NULL;
+static char **convert_args = NULL;
/**
* Create an PNM-file that is sent to `convert` for convertion
- * to a compressed format, or directly to a file
+ * to a compressed format, or directly to a file.
*
- * @param fbname The framebuffer device
- * @param width The width of the image
- * @param height The height of the image
+ * @param fbname The framebuffer device.
+ * @param width The width of the image.
+ * @param height The height of the image.
* @param fd The file descriptor connected to `convert`'s stdin
- * @return Zero on success, -1 on error
+ * @return Zero on success, -1 on error.
*/
-static int save_pnm(const char* fbpath, long width, long height, int fd)
+static int
+save_pnm (const char *fbpath, long width, long height, int fd)
{
char buf[PATH_MAX];
- FILE* file;
- int saved_errno, fbfd, r, g, b;
+ FILE *file = NULL;
+ int fbfd = 1;
+ int r, g, b;
ssize_t got, off;
+ uint32_t *pixel;
+ int saved_errno;
/* Open the framebuffer device for reading. */
- if (fbfd = open(fbpath, O_RDONLY), fbfd < 0)
- return -1;
+ fbfd = open (fbpath, O_RDONLY);
+ if (fbfd == -1)
+ goto fail;
/* Create a FILE*, for writing, for the image file. */
- file = fdopen(fd, "w");
+ file = fdopen (fd, "w");
if (file == NULL)
- return saved_errno = errno, close(fbfd), errno = saved_errno, -1;
+ goto fail;
/* The PNM image should begin with `P3\n%{width} %{height}\n%{colour max=255}\n`.
('\n' and ' ' can be exchanged at will.) */
- fprintf(file, "P3\n%li %li\n255\n", width, height);
+ if (fprintf (file, "P3\n%li %li\n255\n", width, height) < 0)
+ goto fail;
/* Convert raw framebuffer data into an PNM image. */
for (off = 0;;)
{
/* Read data from the framebuffer, we may have up to 3 bytes buffered. */
- got = read(fbfd, buf + off, sizeof(buf) - (size_t)off * sizeof(char));
+ got = read (fbfd, buf + off, sizeof (buf) - (size_t)off * sizeof (char));
if (got < 0)
- return saved_errno = errno, fclose(file), close(fbfd), errno = saved_errno, -1;
- if (got += off, got == 0)
+ goto fail;
+ if (got == 0)
break;
+ got += off;
/* Convert read pixels. */
for (off = 0; off < got; off += 4)
{
/* A pixel in the framebuffer is formatted as `%{blue}%{green}%{red}%{x}`
in big-endian binary, or `%{x}%{red}%{green}%{blue}` in little-endian binary. */
- uint32_t* pixel = (uint32_t*)(buf + off);
+ pixel = (uint32_t *)(buf + off);
r = (*pixel >> 16) & 255;
g = (*pixel >> 8) & 255;
b = (*pixel >> 0) & 255;
/* A pixel in the PNM image is formatted as `%{red} %{green} %{blue} ` in text. */
- fprintf(file, "%s%s%s", inttable[r], inttable[g], inttable[b]);
+ if (fprintf (file, "%s%s%s", inttable[r], inttable[g], inttable[b]) < 0)
+ goto fail;
}
/* If we read a whole number of pixels, reset the buffer, otherwise,
@@ -144,7 +152,7 @@ static int save_pnm(const char* fbpath, long width, long height, int fd)
if (off != got)
{
off -= 4;
- memcpy(buf, buf + off, (size_t)(got - off) * sizeof(char));
+ memcpy (buf, buf + off, (size_t)(got - off) * sizeof (char));
off = got - off;
}
else
@@ -152,74 +160,89 @@ static int save_pnm(const char* fbpath, long width, long height, int fd)
}
/* Close files and return successfully. */
- fflush(file);
- fclose(file);
- close(fbfd);
+ fflush (file);
+ fclose (file);
+ close (fbfd);
return 0;
+
+ fail:
+ saved_errno = errno;
+ if (file != NULL)
+ fclose (file);
+ if (fbfd >= 0)
+ close (fbfd);
+ errno = saved_errno;
+ return -1;
}
/**
- * Create an image of a framebuffer
+ * Create an image of a framebuffer.
*
- * @param fbname The framebuffer device
- * @param imgname The pathname of the output image
- * @param width The width of the image
- * @param height The height of the image
- * @return Zero on success, -1 on error
+ * @param fbname The framebuffer device.
+ * @param imgname The pathname of the output image.
+ * @param width The width of the image.
+ * @param height The height of the image.
+ * @return Zero on success, -1 on error.
*/
-static int save(const char* fbpath, const char* imgpath, long width, long height)
+static int
+save (const char *fbpath, const char *imgpath, long width, long height)
{
- int pipe_rw[2];
- pid_t pid, reaped;
- int saved_errno, status, fd;
+ int pipe_rw[2] = { -1, -1 };
+ pid_t pid;
+ int status;
+ int fd = -1;
+ int saved_errno;
if (convert_args == NULL)
goto no_convert;
/* Create a pipe that for sending data into the `convert` program. */
- if (pipe(pipe_rw) < 0)
- return -1;
+ if (pipe (pipe_rw) < 0)
+ goto fail;
/* Fork the process, the child will exec. `convert`. */
- if (pid = fork(), pid == -1)
- return saved_errno = errno, close(pipe_rw[0]), close(pipe_rw[1]), errno = saved_errno, -1;
+ pid = fork ();
+ if (pid == -1)
+ goto fail;
/* Child process: */
if (pid == 0)
{
/* Close the write-end of the pipe. */
- close(pipe_rw[1]);
+ close (pipe_rw[1]);
/* Turn the read-end of the into stdin. */
if (pipe_rw[0] != STDIN_FILENO)
{
- close(STDIN_FILENO);
- dup2(pipe_rw[0], STDIN_FILENO);
- close(pipe_rw[0]);
+ close (STDIN_FILENO);
+ if (dup2 (pipe_rw[0], STDIN_FILENO) == -1)
+ goto child_fail;
+ close (pipe_rw[0]);
}
/* Exec. `convert` to convert the PNM-image we create to a compressed image. */
- sprintf(convert_args[2], "%s", imgpath);
- execvp("convert", convert_args);
+ sprintf (convert_args[2], "%s", imgpath);
+ execvp ("convert", convert_args);
+
+ child_fail:
perror(execname);
- exit(1);
+ _exit(1);
}
/* Parent process: */
/* Close the read-end of the pipe. */
- close(pipe_rw[0]);
+ close (pipe_rw[0]), pipe_rw[0] = -1;
/* Create a PNM-image of the framebuffer. */
- if (save_pnm(fbpath, width, height, pipe_rw[1]) < 0)
- return saved_errno = errno, close(pipe_rw[1]), errno = saved_errno, -1;
+ if (save_pnm (fbpath, width, height, pipe_rw[1]) < 0)
+ goto fail;
/* Close the write-end of the pipe. */
- close(pipe_rw[1]);
+ close (pipe_rw[1]), pipe_rw[1] = -1;
/* Wait for `convert` to exit. */
- for (reaped = 0; reaped != pid;)
- if (reaped = waitpid(pid, &status, 0), reaped < 0)
- return -1;
+ if (waitpid (pid, &status, 0) < 0)
+ goto fail;
/* Return successfully if and only if `convert` did. */
return status == 0 ? 0 : -1;
@@ -229,65 +252,88 @@ static int save(const char* fbpath, const char* imgpath, long width, long height
no_convert:
/* Open output file. */
- if (fd = open(imgpath, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), fd == -1)
- return -1;
+ if (fd = open (imgpath, O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), fd == -1)
+ goto fail;
/* Save image. */
- if (save_pnm(fbpath, width, height, fd) < 0)
- return saved_errno = errno, close(fd), errno = saved_errno, -1;
+ if (save_pnm (fbpath, width, height, fd) < 0)
+ goto fail;
- close(fd);
+ close (fd);
return 0;
+
+ fail:
+ saved_errno = errno;
+ if (pipe_rw[0] >= 0)
+ close (pipe_rw[0]);
+ if (pipe_rw[1] >= 0)
+ close (pipe_rw[1]);
+ if (fd >= 0)
+ close (fd);
+ errno = saved_errno;
+ return -1;
}
/**
- * Get the dimensions of the framebuffer
+ * Get the dimensions of the framebuffer.
*
- * @param fbno The number of the framebuffer
- * @param width Output parameter for the width of the image
- * @param height Output parameter for the height of the image
- * @return Zero on success, -1 on error
+ * @param fbno The number of the framebuffer.
+ * @param width Output parameter for the width of the image.
+ * @param height Output parameter for the height of the image.
+ * @return Zero on success, -1 on error.
*/
-static int measure(int fbno, long* width, long* height)
+static int
+measure (int fbno, long *width, long *height)
{
char buf[PATH_MAX];
- char* delim;
- int sizefd, saved_errno;
+ char *delim;
+ int sizefd = -1;
ssize_t got;
+ int saved_errno;
/* Open the file with the framebuffer's dimensions. */
- sprintf(buf, SYSDIR "/class/graphics/fb%i/virtual_size", fbno);
- if (sizefd = open(buf, O_RDONLY), sizefd < 0)
- return -1;
+ sprintf (buf, SYSDIR "/class/graphics/fb%i/virtual_size", fbno);
+ sizefd = open (buf, O_RDONLY);
+ if (sizefd == -1)
+ goto fail;
/* Get the dimensions of the framebuffer. */
- if (got = read(sizefd, buf, sizeof(buf) / sizeof(char) - 1), got < 0)
- return saved_errno = errno, close(sizefd), errno = saved_errno, -1;
- close(sizefd);
+ got = read (sizefd, buf, sizeof (buf) / sizeof (char) - 1);
+ if (got < 0)
+ goto fail;
+ close (sizefd);
/* The read content is formated as `%{width},%{height}\n`,
convert it to `%{width}\0%{height}\0` and parse it. */
buf[got] = '\0';
- delim = strchr(buf, ',');
+ delim = strchr (buf, ',');
*delim++ = '\0';
- *width = atol(buf);
- *height = atol(delim);
+ *width = atol (buf);
+ *height = atol (delim);
return 0;
+
+ fail:
+ saved_errno = errno;
+ if (sizefd >= 0)
+ close (sizefd);
+ errno = saved_errno;
+ return -1;
}
/**
- * Duplicate all '%':s in a buffer until the first occurrence of a zero byte
+ * 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
+ * @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)
+static ssize_t
+duplicate_percents (char *restrict buf, size_t n)
{
size_t p = 0, pi, pc = 0, i;
@@ -303,8 +349,8 @@ static ssize_t duplicate_percents(char* restrict buf, size_t n)
/* 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 = (size_t)(strchr (buf + p, '%') - buf);
+ memmove (buf + p + 1, buf + p, (i - (p - pi)) * sizeof (char));
p += 2;
}
@@ -313,24 +359,24 @@ static ssize_t duplicate_percents(char* restrict buf, size_t n)
/**
- * Parse and evaluate a --exec argument or filename pattern
+ * 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
+ * @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.
*/
-static int evaluate(char* restrict buf, size_t n, const char* restrict pattern,
- int fbno, long width, long height, const char* restrict path)
+static 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)
+#define P(format, value) r = snprintf (buf + i, n - i, format "%zn", value, &j)
size_t i = 0;
ssize_t j = 0;
@@ -349,20 +395,20 @@ static int evaluate(char* restrict buf, size_t n, const char* restrict pattern,
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);
+ 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
continue;
if ((r < 0) || (j <= 0))
return -1;
if ((c == 'f') || (c == 'n'))
- if (j = duplicate_percents(buf + i, n - i), j < 0)
- return errno = ENAMETOOLONG, -1;
+ 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;
@@ -374,30 +420,37 @@ static int evaluate(char* restrict buf, size_t n, const char* restrict pattern,
else buf[i++] = c;
if (i >= n)
- return errno = ENAMETOOLONG, -1;
+ goto enametoolong;
}
buf[i] = '\0';
/* Check whether there are any '%' to expand. */
- if (strchr(buf, '%') == NULL)
+ 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));
+ fmt = alloca ((strlen (buf) + 1) * sizeof (char));
+ memcpy (fmt, buf, (strlen (buf) + 1) * sizeof (char));
/* Expand '%'. */
- t = time(NULL);
- localtime_r(&t, &tm);
+ t = time (NULL);
+ localtime_r (&t, &tm);
+#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
- if (strftime(buf, n, fmt, &tm) == 0)
+#endif
+ if (strftime (buf, n, fmt, &tm) == 0)
+ goto enametoolong; /* No errors are defined for `strftime`. */
+#ifdef __GNUC__
# pragma GCC diagnostic pop
- return errno = ENAMETOOLONG, -1;
+#endif
return 0;
-#undef p
+ enametoolong:
+ return errno = ENAMETOOLONG, -1;
+
+#undef P
}
@@ -407,12 +460,13 @@ static int evaluate(char* restrict buf, size_t n, const char* restrict pattern,
* @param flatten_args The arguments to run, 255 delimits the arguments
* @return Zero on success -1 on error
*/
-static int exec_image(char* flatten_args)
+static int
+exec_image (char *flatten_args)
{
- char** args;
- char* arg;
+ char **args;
+ char *arg;
size_t i, arg_count = 1;
- pid_t pid, reaped;
+ pid_t pid;
int status;
/* Count arguments. */
@@ -421,39 +475,37 @@ static int exec_image(char* flatten_args)
arg_count++;
/* Allocate argument array. */
- args = alloca((arg_count + 1) * sizeof(char*));
+ args = alloca ((arg_count + 1) * sizeof (char*));
/* Unflatten argument array. */
for (arg = flatten_args, i = 0;;)
{
args[i++] = arg;
- arg = strchr(arg, 255);
+ arg = strchr (arg, 255);
if (arg == NULL)
break;
*arg++ = '\0';
}
args[i] = NULL;
-
+
/* Fork process. */
- pid = fork();
+ pid = fork ();
if (pid == -1)
return -1;
/* Child process: */
if (pid == 0)
{
- execvp(*args, args);
- perror(execname);
- exit(1);
- return -1;
+ execvp (*args, args);
+ perror (execname);
+ _exit (1);
}
/* Parent process: */
/* Wait for child to exit. */
- for (reaped = 0; reaped != pid;)
- if (reaped = waitpid(pid, &status, 0), reaped < 0)
- return -1;
+ if (waitpid(pid, &status, 0) < 0)
+ return -1;
/* Return successfully if and only if `the child` did. */
return status == 0 ? 0 : -1;
@@ -461,54 +513,55 @@ static int exec_image(char* flatten_args)
/**
- * Take a screenshot of a framebuffer
+ * Take a screenshot of a framebuffer.
*
- * @param fbno The number of the framebuffer
- * @param raw Save in PNM rather than in PNG?
- * @param filepattern The pattern for the filename, `NULL` for default
+ * @param fbno The number of the framebuffer.
+ * @param raw Save in PNM rather than in PNG?.
+ * @param filepattern The pattern for the filename, `NULL` for default.
* @param execpattern The pattern for the command to run to
- * process the image, `NULL` for default
- * @return Zero on success, -1 on error, 1 if the framebuffer does not exist
+ * process the image, `NULL` for default.
+ * @return Zero on success, -1 on error, 1 if the framebuffer does not exist.
*/
-static int save_fb(int fbno, int raw, const char* filepattern, const char* execpattern)
+static int
+save_fb (int fbno, int raw, const char *filepattern, const char *execpattern)
{
char fbpath[PATH_MAX];
char imgpath[PATH_MAX];
- char* execargs = NULL;
- char* old;
+ char *execargs = NULL;
+ void *new;
long width, height;
size_t size = PATH_MAX;
int i, saved_errno;
/* Get pathname for framebuffer, and stop if we have read all existing ones. */
- sprintf(fbpath, DEVDIR "/fb%i", fbno);
- if (access(fbpath, F_OK))
+ sprintf (fbpath, DEVDIR "/fb%i", fbno);
+ if (access (fbpath, F_OK))
return 1;
/* Get the size of the framebuffer. */
- if (measure(fbno, &width, &height) < 0)
- return -1;
+ if (measure (fbno, &width, &height) < 0)
+ goto fail;
/* Get output pathname. */
if (filepattern == NULL)
{
- sprintf(imgpath, "fb%i.%s", fbno, (raw ? "pnm" : "png"));
- if (access(imgpath, F_OK) == 0)
+ sprintf (imgpath, "fb%i.%s", fbno, (raw ? "pnm" : "png"));
+ if (access (imgpath, F_OK) == 0)
for (i = 2;; i++)
{
- sprintf(imgpath, "fb%i.%s.%i", fbno, (raw ? "pnm" : "png"), i);
- if (access(imgpath, F_OK))
+ sprintf (imgpath, "fb%i.%s.%i", fbno, (raw ? "pnm" : "png"), i);
+ if (access (imgpath, F_OK))
break;
}
}
else
- if (evaluate(imgpath, (size_t)PATH_MAX, filepattern, fbno, width, height, NULL) < 0)
+ if (evaluate (imgpath, (size_t)PATH_MAX, filepattern, fbno, width, height, NULL) < 0)
return -1;
/* Take a screenshot of the current framebuffer. */
- if (save(fbpath, imgpath, width, height) < 0)
- return -1;
- fprintf(stderr, "Saved framebuffer %i to %s\n", fbno, imgpath);
+ if (save (fbpath, imgpath, width, height) < 0)
+ goto fail;
+ fprintf (stderr, "Saved framebuffer %i to %s\n", fbno, imgpath);
/* Should we run a command over the image? */
if (execpattern == NULL)
@@ -516,82 +569,87 @@ static int save_fb(int fbno, int raw, const char* filepattern, const char* execp
/* Get execute arguments. */
retry:
- execargs = realloc(old = execargs, size * sizeof(char));
+ new = realloc (execargs, size * sizeof (char));
if (execargs == NULL)
- return saved_errno = errno, free(old), errno = saved_errno, -1;
- if (evaluate(execargs, size, execpattern, fbno, width, height, imgpath) < 0)
+ goto fail;
+ execargs = new;
+ if (evaluate (execargs, size, execpattern, fbno, width, height, imgpath) < 0)
{
if ((errno != ENAMETOOLONG) || ((size >> 8) <= PATH_MAX))
- return -1;
+ goto fail;
size <<= 1;
goto retry;
}
/* Run command over image. */
- i = exec_image(execargs);
+ if (exec_image (execargs) < 0)
+ goto fail;
+ free (execargs);
+ return 0;
+
+ fail:
saved_errno = errno;
- free(execargs);
- return errno = saved_errno, i;
+ free (execargs);
+ errno = saved_errno;
+ return -1;
}
-#define p(...) if (printf(__VA_ARGS__) < 0) return -1;
-
-
/**
- * Print usage information
+ * Print usage information.
*
- * @return Zero on success, -1 on error
+ * @return Zero on success, -1 on error.
*/
-static int print_help(void)
+static int
+print_help(void)
{
- p("SYNOPSIS\n");
- p("\t%s [options...] [filename-pattern] [-- options-for-convert...]\n", execname);
- p("\n");
- p("OPTIONS\n");
- p("\t--help Print usage information.\n");
- p("\t--version Print program name and version.\n");
- p("\t--copyright Print copyright information.\n");
- p("\t--raw Save in PNM rather than in PNG.\n");
- p("\t--exec CMD Command to run for each saved image.\n");
- p("\n");
- p("SPECIAL STRINGS\n");
- p("\tBoth the --exec and filename-pattern parameters can take format specifiers\n");
- p("\tthat are expanded by scrotty when encountered. There are two types of format\n");
- p("\tspecifier. Characters preceded by a '%%' are interpretted by strftime(3).\n");
- p("\tSee `man strftime` for examples. These options may be used to refer to the\n");
- p("\tcurrent date and time. The second kind are internal to scrotty and are prefixed\n");
- p("\tby '$' or '\\'. The following specifiers are recognised:\n");
- p("\n");
- p("\t\n");
- p("\t$i framebuffer index\n");
- p("\t$f image filename/pathname (ignored when used in filename-pattern)\n");
- p("\t$n image filename (ignored when used in filename-pattern)\n");
- p("\t$p image width multiplied by image height\n");
- p("\t$w image width\n");
- p("\t$h image height\n");
- p("\t$$ expands to a literal '$'\n");
- p("\t\\n expands to a new line\n");
- p("\t\\\\ expands to a literal '\\'\n");
- p("\t\\ expands to a literal ' ' (the string is a backslash followed by a space)\n");
- p("\n");
- p("\tA space that is not prefixed by a backslash in --exec is interpreted as an\n");
- p("\targument delimiter. This is the case even at the beginning and end of the\n");
- p("\tstring and if a space was the previous character in the string.\n");
- p("\n");
- return 0;
+ return printf ("SYNOPSIS\n"
+ "\t%s [options...] [filename-pattern] [-- options-for-convert...]\n"
+ "\n"
+ "OPTIONS\n"
+ "\t--help Print usage information.\n"
+ "\t--version Print program name and version.\n"
+ "\t--copyright Print copyright information.\n"
+ "\t--raw Save in PNM rather than in PNG.\n"
+ "\t--exec CMD Command to run for each saved image.\n"
+ "\n"
+ "SPECIAL STRINGS\n"
+ "\tBoth the --exec and filename-pattern parameters can take format specifiers\n"
+ "\tthat are expanded by scrotty when encountered. There are two types of format\n"
+ "\tspecifier. Characters preceded by a '%%' are interpretted by strftime(3).\n"
+ "\tSee `man strftime` for examples. These options may be used to refer to the\n"
+ "\tcurrent date and time. The second kind are internal to scrotty and are prefixed\n"
+ "\tby '$' or '\\'. The following specifiers are recognised:\n"
+ "\n"
+ "\t\n"
+ "\t$i framebuffer index\n"
+ "\t$f image filename/pathname (ignored when used in filename-pattern)\n"
+ "\t$n image filename (ignored when used in filename-pattern)\n"
+ "\t$p image width multiplied by image height\n"
+ "\t$w image width\n"
+ "\t$h image height\n"
+ "\t$$ expands to a literal '$'\n"
+ "\t\\n expands to a new line\n"
+ "\t\\\\ expands to a literal '\\'\n"
+ "\t\\ expands to a literal ' ' (the string is a backslash followed by a space)\n"
+ "\n"
+ "\tA space that is not prefixed by a backslash in --exec is interpreted as an\n"
+ "\targument delimiter. This is the case even at the beginning and end of the\n"
+ "\tstring and if a space was the previous character in the string.\n"
+ "\n",
+ execname) < 0 ? -1 : 0;
}
/**
- * Print program name and version
+ * Print program name and version.
*
- * @return Zero on success, -1 on error
+ * @return Zero on success, -1 on error.
*/
-static int print_version(void)
+static int
+print_version (void)
{
- p("%s %s\n", PROGRAM_NAME, PROGRAM_VERSION);
- return 0;
+ return printf ("%s %s\n", PROGRAM_NAME, PROGRAM_VERSION) < 0 ? -1 : 0;
}
@@ -600,30 +658,28 @@ static int print_version(void)
*
* @return Zero on success, -1 on error
*/
-static int print_copyright(void)
+static int
+print_copyright (void)
{
- p("scrotty -- Screenshot program for Linux's TTY\n");
- p("Copyright (C) 2014, 2015 Mattias Andrée (maandree@member.fsf.org)\n");
- p("\n");
- p("This program is free software: you can redistribute it and/or modify\n");
- p("it under the terms of the GNU General Public License as published by\n");
- p("the Free Software Foundation, either version 3 of the License, or\n");
- p("(at your option) any later version.\n");
- p("\n");
- p("This program is distributed in the hope that it will be useful,\n");
- p("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
- p("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
- p("GNU General Public License for more details.\n");
- p("\n");
- p("You should have received a copy of the GNU General Public License\n");
- p("along with this program. If not, see <http://www.gnu.org/licenses/>.\n");
- return 0;
+ return printf ("scrotty -- Screenshot program for Linux's TTY\n"
+ "Copyright (C) 2014, 2015 Mattias Andrée (maandree@member.fsf.org)\n"
+ "\n"
+ "This program is free software: you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation, either version 3 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program. If not, see <http://www.gnu.org/licenses/>.\n"
+ ) < 0 ? -1 : 0;
}
-#undef p
-
-
/**
* Take a screenshot of all framebuffers
*
@@ -631,48 +687,52 @@ static int print_copyright(void)
* @param argv Command line arguments
* @return Zero on and only on success
*/
-int main(int argc, char* argv[])
+int main
+(int argc, char *argv[])
{
+#define EXIT_USAGE(MSG) \
+ return fprintf (stderr, "%s: %s. Type `%s --help` for help.\n", execname, MSG, execname), 1
+
int fbno, r, i, dash = argc, exec = -1, help = 0;
int raw = 0, version = 0, copyright = 0, filepattern = -1;
static char convert_args_0[] = "convert";
static char convert_args_1[] = DEVDIR "/stdin";
static char convert_args_2[PATH_MAX];
- execname = *argv;
+ execname = argc ? *argv : "scrotty";
/* Parse command line. */
for (i = 1; i < argc; i++)
{
- if (!strcmp(argv[i], "--help")) help = 1;
- else if (!strcmp(argv[i], "--version")) version = 1;
- else if (!strcmp(argv[i], "--copyright")) copyright = 1;
- else if (!strcmp(argv[i], "--raw")) raw = 1;
- else if (!strcmp(argv[i], "--exec")) exec = ++i;
- else if (!strcmp(argv[i], "--"))
+ if (!strcmp (argv[i], "--help")) help = 1;
+ else if (!strcmp (argv[i], "--version")) version = 1;
+ else if (!strcmp (argv[i], "--copyright")) copyright = 1;
+ else if (!strcmp (argv[i], "--raw")) raw = 1;
+ else if (!strcmp (argv[i], "--exec")) exec = ++i;
+ else if (!strcmp (argv[i], "--"))
{
dash = i + 1;
break;
}
else if ((argv[i][0] == '-') || (filepattern != -1))
- return fprintf(stderr, "Unrecognised option. Type `%s --help` for help.\n", execname), 1;
+ EXIT_USAGE ("Unrecognised option.");
else
filepattern = i;
}
/* Check that --exec is valid. */
if (exec == argc)
- return fprintf(stderr, "--exec has no argument. Type `%s --help` for help.\n", execname), 1;
+ EXIT_USAGE ("--exec has no argument.");
- /* Was --help, --version or --copyright used? */
- if (help) return -(print_help());
- if (version) return -(print_version());
- if (copyright) return -(print_copyright());
+ /* Was --help, --version, or --copyright used? */
+ if (help) return -(print_help ());
+ if (version) return -(print_version ());
+ if (copyright) return -(print_copyright ());
/* Create arguments for `convert`. */
if ((!raw) || (dash < argc))
{
- convert_args = alloca((size_t)(4 + (argc - dash)) * sizeof(char*));
+ convert_args = alloca ((size_t)(4 + (argc - dash)) * sizeof (char*));
convert_args[0] = convert_args_0;
convert_args[1] = convert_args_1;
convert_args[2] = convert_args_2;
@@ -684,13 +744,20 @@ int main(int argc, char* argv[])
/* Take a screenshot of each framebuffer. */
for (fbno = 0;; fbno++)
{
- r = save_fb(fbno, raw,
- (filepattern < 0 ? NULL : argv[filepattern]),
- (exec < 0 ? NULL : argv[exec]));
- if (r < 0) return perror(execname), 1;
- if (r > 0) break;
+ r = save_fb (fbno, raw,
+ (filepattern < 0 ? NULL : argv[filepattern]),
+ (exec < 0 ? NULL : argv[exec]));
+ if (r < 0)
+ goto fail;
+ if (r > 0)
+ break;
}
return 0;
+
+ fail:
+ return perror (execname), 1;
+
+#undef EXIT_USAGE
}