view pwm-clip.c @ 34:34ada71ff3e5

Allow local makefile overrides in local.mk
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Wed, 31 Jul 2019 11:21:54 +0200
parents 5bdea77d0c1d
children
line wrap: on
line source

/*
 * 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);
}