Mercurial > projects > pwm
diff pwm-clip.c @ 26:5bdea77d0c1d
Add pwm-clip utility for setting the X11 CLIPBOARD selection
author | Guido Berhoerster <guido+pwm@berhoerster.name> |
---|---|
date | Thu, 21 Sep 2017 09:45:59 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pwm-clip.c Thu Sep 21 09:45:59 2017 +0200 @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2017 Guido Berhoerster <guido+pwm@berhoerster.name> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "compat.h" + +#ifdef HAVE_ERR_H +#include <err.h> +#endif /* HAVE_ERR_H */ +#include <errno.h> +#include <nettle/base64.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#include "util.h" + +#define CHUNK_SIZE 128 + +static char * +base64_encode(const unsigned char *src, size_t size) +{ + char *dst = NULL; + struct base64_encode_ctx b64_ctx; + size_t len = 0; + + dst = xmalloc(BASE64_ENCODE_LENGTH(size) + + BASE64_ENCODE_FINAL_LENGTH); + + base64_encode_init(&b64_ctx); + len += base64_encode_update(&b64_ctx, (unsigned char *)dst, size, src); + len += base64_encode_final(&b64_ctx, (unsigned char *)dst); + dst[len] = '\0'; + + dst = xrealloc(dst, len + 1); + + return (dst); +} + +static void +set_clipboard(const char *s) +{ + char *b64 = NULL; + + b64 = base64_encode((const unsigned char *)s, strlen(s)); + printf("\033]52;c;%s\a\n", b64); + free(b64); +} + +static void +set_clipboard_dcs_tmux(const char *s) +{ + char *b64 = NULL; + + b64 = base64_encode((const unsigned char *)s, strlen(s)); + printf("\033Ptmux;\033\033]52;c;%s\a\033\\", b64); + free(b64); +} + +static void +set_clipboard_dcs_chunked(const char *s) +{ + char *b64 = NULL; + size_t i; + + b64 = base64_encode((const unsigned char *)s, strlen(s)); + + printf("\033P\033]52;c;"); + for (i = 0; b64[i] != '\0'; i++) { + if ((i > 0) && (i % CHUNK_SIZE == 0)) { + printf("\033\\\033P"); + } + putchar(b64[i]); + } + printf("\a\033\\"); + + free(b64); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s\n", getprogname()); +} + +int +main(int argc, char *argv[]) +{ + int status = EXIT_FAILURE; + char *term; + void (*set_clipboard_func)(const char *); + int errflag = 0; + int c; + ssize_t len; + char *s = NULL; + size_t size = 0; + + setprogname(argv[0]); + + term = getenv("TERM"); + if (term == NULL) { + fprintf(stderr, "error: unknown terminal\n"); + goto out; + } else if (strncmp(term, "xterm", strlen("xterm")) == 0) { + set_clipboard_func = set_clipboard; + } else if (strncmp(term, "tmux", strlen("tmux")) == 0) { + set_clipboard_func = set_clipboard_dcs_tmux; + } else if (strncmp(term, "screen", strlen("screen")) == 0) { + if (getenv("TMUX") != NULL) { + set_clipboard_func = set_clipboard_dcs_tmux; + } else { + set_clipboard_func = set_clipboard_dcs_chunked; + } + } else { + fprintf(stderr, "terminal does not support setting " + "X11 CLIPBOARD selection\n"); + goto out; + } + + while (!errflag && (c = getopt(argc, argv, "h")) != -1) { + switch (c) { + case 'h': + usage(); + exit(EXIT_SUCCESS); + default: + errflag = 1; + } + } + if (errflag || (optind + 1 < argc)) { + usage(); + exit(EXIT_USAGE); + } + + errno = 0; + len = getline(&s, &size, stdin); + if (len < 0) { + if (errno == 0) { + fprintf(stderr, "failed to read line\n"); + goto out; + } else { + err(1, "getline"); + } + } + if ((len > 0) && (s[len - 1] == '\n')) { + s[--len] = '\0'; + } + + set_clipboard_func(s); + + status = EXIT_SUCCESS; + +out: + free(s); + + exit(status); +}