/* chsel - example program providing simple command-line interface for
 * manipulation with the kernel selection buffer. */

/* Note that in the output of chsel get, newlines are returned as ^M (\x0d).
 * This is just how it's stored in the kernel. Should we translate it? */

/* You currently need a kernel patch available at
 * http://pasky.ji.cz/~pasky/dev/kernel/selection.patch */

/* [GPL'd] (c) 2002  Petr Baudis <pasky@ucw.cz> */

#define VERSION	"0.1"

/* This is really not coded nicely, it's rather a dirty hack. Its goal for
 * now is to be as simple and short as possible, so that people can get the
 * general idea. */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>

int
main(int argc, char *argv[]) {
  enum { MODE_GET, MODE_SET } mode;
  char *buffer;
  int len;
  int fd = 0;

  if (argc < 2) {
usage:
    fprintf(stderr, "chsel %s\nUsage: %s {get|set <selection>}\n",
	VERSION, argv[0]);
    return 1;
  }

  if (!strcmp(argv[1], "get"))
    mode = MODE_GET;
  else if (!strcmp(argv[1], "set"))
    mode = MODE_SET;
  else
    goto usage;

  if (mode == MODE_SET && argc != 3)
    goto usage;

  switch (mode) {
    case MODE_SET:
      len = strlen(argv[2]);
      buffer = malloc(len + 1 + sizeof(unsigned int));
      buffer[0] = 13;
      memcpy(buffer + 1, &len, sizeof(unsigned int));
      memcpy(buffer + 1 + sizeof(unsigned int), argv[2], len);

      if (ioctl(fd, TIOCLINUX, buffer) < 0) {
ioctl_error:
	perror("chsel - ioctl()");
	free(buffer);
	return 2;
      }

      break;

    case MODE_GET:
      /* I could do this by simply going directly for 65536, but this limit
       * can change in future and it wouldn't be so demonstrational and
       * educational ;-). --pasky */
      len = 128;
get_loop:
      buffer = malloc(len + 1 + sizeof(unsigned int));
      buffer[0] = 14;
      memcpy(buffer + 1, &len, sizeof(unsigned int));
      
      if ((len = ioctl(fd, TIOCLINUX, buffer)) < 0)
	goto ioctl_error;

      if (len > *((unsigned int *) (buffer + 1))) {
	free(buffer);
	goto get_loop; /* and now with the right buffer len */
      }

      if (*((unsigned int *) (buffer + 1)))
      printf("%*s",
	  *((unsigned int *) (buffer + 1)),
	  buffer + 1 + sizeof(unsigned int));
      free(buffer);

      break;
  }

  return 0;
}
