[comp.sources.x] v03i102: xcutbuf, Part01/01

argv@island.uu.net (Dan Heller) (05/04/89)

Submitted-by: Dave Curry <davy@riacs.edu>
Posting-number: Volume 3, Issue 102
Archive-name: xcutbuf/part01

#!/bin/sh
# xcutbuf is used to manipulate the X11 cut buffers.  You can store stuff
# into the cut buffers, list their contents, and rotate them around.
# This is useful for stuffing the output of commands into the cut buffers,
# making aliases to stick data into the cut buffer, and so on.
#
# This is a shell archive file. Remove everything above this line
# to unbundle. chmod +x "thisfile", then run it: e.g. % thisfile
# SHAR archive format.  Archive created Wed May 3 11:22:23 PDT 1989
# file contains: 
#	xcutbuf.man
#	xcutbuf.c
#	Imakefile
#	patchlevel.h
echo x - xcutbuf.man
sed 's/^X//' > xcutbuf.man <<'+END+OF+xcutbuf.man'
X.TH XCUTBUF 1 "2 May 1989" RIACS
X.SH NAME
Xxcutbuf \- X11 cut buffer manager
X.SH SYNOPSIS
X.B xcutbuf
X[
X.I options
X] [
X.I data...
X]
X.SH DESCRIPTION
X.PP
X.I Xcutbuf
Xallows the manipulation of the X11 cut buffers.
XAll X11 servers provide the user with eight cut buffers,
Xnumbered 0 through 7,
Xwhich can be
Xused to transfer data between different applications.
XUnlike selections,
Xcut buffers do not do any translation of data from one format to another.
XThus,
Xthey are mostly useful only for cutting and pasting text between windows.
X.PP
X.I Xcutbuf
Xallows the user to store data into any cut buffer,
Xlist the sizes of all cut buffers,
Xexamine the contents of one or all of the cut buffers,
Xand to rotate the cut buffers.
XWith no options specified,
X.I xcutbuf
Xwill read data from the command line if supplied,
Xor from the standard input if no data is given,
Xand place the data into cut buffer 0.
XOne (and only one) of the following options may be specified in order
Xto do something other than store data into a cut buffer:
X.IP "\fB-list\fP [\fIbnum\fP]"
XList the size of each of the cut buffers in bytes.
XIf
X.I bnum
Xis specified,
Xthen only the size of that cut buffer will be displayed.
X.IP "\fB-contents\fP [\fIbnum\fP]"
XDisplay the contents of each of the cut buffers.
XIf
X.I bnum
Xis specified,
Xonly the contents of that cut buffer will be displayed.
X.IP "\fB-rotate\fP [\fIn\fP]"
XRotate the cut buffers by
X.I n
Xpositions (default 1).
XThat is,
Xcut buffer
X.I i
Xbecomes
Xcut buffer
X.I i+n
X(modulo 8).
X.PP
XAs mentioned earlier,
X.I xcutbuf
Xcan also be used to load data into any one of the cut buffers.
XThis can be done in one of three ways:
X.IP 1.
XThe data can be specified on the command line following all other options.
XIt will be stored in the cut buffer as words separated by spaces,
Xwith no trailing new line character.
X.IP 2.
XThe
X.B -file
X.I filename
Xoption can be used to tell
X.I xcutbuf
Xto read the contents of
X.I filename
Xand store them into the cut buffer.
X.IP 3.
XIf no data is given on the command line and no file name is specified,
X.I xcutbuf
Xwill read data from the standard input and place it into the cut buffer.
X.PP
XIn addition to the options already discussed,
Xthe following options are also available:
X.IP "\fB-cutbuffer\fP \fIbnum\fP"
XStore data into cut buffer
X.I bnum ,
Xinstead of the default cut buffer (number 0).
X.IP "\fB-display\fP \fIdisplay\fP"
XUse the cut buffers attached to
X.I display .
XThe default display is the one contained in the
X.B \s-1DISPLAY\s0
Xenvironment variable.
X.SH RESOURCES
X.PP
X.I Xcutbuf
Xitself does not use any information from the resource database.
XHowever,
Xother applications may need to be told to use cut buffers instead of the
XX11 selection mechanism.
XThis can be done by modifying the translation tables for the application
Xvia the resource database.
XFor example,
Xto make
X.I xterm
Xuse cut buffer number 0 for cutting and pasting instead of the selection
Xmechanism,
Xthe following would be placed in the resource database:
X.sp
X.ta 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i
X.ft C
X.nf
X	*VT100.Translations: #override\\
X		<Btn2Up>: insert-selection(CUT_BUFFER0)\\n\\
X		<BtnUp>: select-end(CUT_BUFFER0)
X.fi
X.ft
X.PP
XInformation can then be placed into the cut buffers
Xand the data to be pasted can be rotated into cut buffer number 0
Xusing
X.IR xcutbuf .
X.SH SEE ALSO
Xxcutsel(1),
Xxclipboard(1)
X.SH BUGS
X.PP
XArgument parsing is less than robust.
X.PP
XInserting vast quantities of data into the cut buffers will cause
Xthe server to eat up lots of memory.
X.I xcutbuf
Xdoes not prohibit this,
Xbut it's not a good idea.
X.PP
XThe direction of cut buffer rotation in the X server is counter-intuitive.
X.PP
XAttempting to rotate the cut buffers when not all of them have been
Xdefined (had something placed into them) causes an X11 ``BadMatch''
Xprotocol error.
X.SH AUTHOR
XDavid A. Curry, Research Institute for Advanced Computer Science
+END+OF+xcutbuf.man
echo '-rw-rw-r--  1 argv         3855 May  3 11:13 xcutbuf.man    (as sent)'
chmod u=rw,g=rw,o=r xcutbuf.man
ls -l xcutbuf.man
echo x - xcutbuf.c
sed 's/^X//' > xcutbuf.c <<'+END+OF+xcutbuf.c'
X#ifndef lint
Xstatic char *RCSid = "$Header: /u5/davy/progs/xcutbuf/RCS/xcutbuf.c,v 1.1 89/05/02 11:04:47 davy Exp $";
X#endif
X/*
X * xcutbuf - X11 cut buffer manager
X *
X * xcutbuf allows the user to manipulate the X11 cut buffers by storing
X * data in them, examing their contents, and rotating them to bring
X * data into a specific buffer.
X *
X * Usage:
X *	xcutbuf -list [bnum]			list sizes of buffer(s)
X *	xcutbuf -contents [bnum]		list contents of buffer(s)
X *	xcutbuf -rotate [n]			rotate buffers by n
X *	xcutbuf -cutbuffer bnum	-file fname	load file into cutbuffer bnum
X *	xcutbuf -cutbuffer bnum word word word	load words into cutbuffer bnum
X *
X * David A. Curry
X * Research Institute for Advanced Computer Science
X * Mail Stop 230-5
X * NASA Ames Research Center
X * Moffett Field, CA 94035
X * davy@riacs.edu
X *
X * $Log:	xcutbuf.c,v $
X * Revision 1.1  89/05/02  11:04:47  davy
X * Initial revision
X * 
X */
X#include "patchlevel.h"
X#include <X11/Xlib.h>
X#include <X11/Xos.h>
X#include <ctype.h>
X#include <stdio.h>
X
X#define MIN_CUTBUFFER		0
X#define MAX_CUTBUFFER		7
X#define ALL_CUTBUFFERS		(MAX_CUTBUFFER + 1)
X#define DEFAULT_LIST		ALL_CUTBUFFERS
X#define DEFAULT_ROTATE		1
X#define DEFAULT_CUTBUFFER	0
X
Xshort	list = 0;			/* non-zero if listing buffers	*/
Xshort	stuff = 0;			/* non-zero if loading buffers	*/
Xshort	rotate = 0;			/* non-zero if rotating buffers	*/
Xshort	contents = 0;			/* non-zero if showing buffers	*/
X
Xchar	*pname;				/* program name			*/
X
Xmain(argc, argv)
Xchar **argv;
Xint argc;
X{
X	int bnum;
X	Display *display;
X	char *displayname, *filename;
X
X	pname = *argv;
X	bnum = DEFAULT_CUTBUFFER;
X	filename = displayname = NULL;
X
X	/*
X	 * Process arguments as long as they start with "-".  Any
X	 * left over after that are data to be stored in a cut
X	 * buffer.
X	 */
X	while ((--argc > 0) && (**++argv == '-')) {
X		/*
X		 * Set display name.
X		 */
X		if (!strcmp(*argv, "-display")) {
X			if (--argc <= 0)
X				usage();
X
X			displayname = *++argv;
X			continue;
X		}
X
X		/*
X		 * Set cutbuffer number to be stored into.
X		 * Default is DEFAULT_CUTBUFFER.
X		 */
X		if (!strcmp(*argv, "-cutbuffer")) {
X			if (--argc <= 0)
X				usage();
X
X			bnum = atoi(*++argv);
X			continue;
X		}
X
X		/*
X		 * Rotate the cutbuffers by amount in next
X		 * argument.  Default is DEFAULT_ROTATE.
X		 */
X		if (!strcmp(*argv, "-rotate")) {
X			if (--argc < 0)
X				usage();
X
X			if (argc == 0) {
X				rotate = DEFAULT_ROTATE;
X			}
X			else {
X				rotate = atoi(*++argv);
X				CheckBounds(rotate);
X			}
X
X			continue;
X		}
X
X		/*
X		 * Show contents of cutbuffer named in next
X		 * argument.  Default is to show all of them.
X		 */
X		if (!strcmp(*argv, "-contents")) {
X			if (--argc < 0)
X				usage();
X
X			if (argc == 0) {
X				contents = DEFAULT_LIST;
X			}
X			else {
X				contents = atoi(*++argv);
X				CheckBounds(contents);
X			}
X
X			continue;
X		}
X
X		/*
X		 * List size of cut buffer given by next
X		 * argument.  Default is to list all of
X		 * them.
X		 */
X		if (!strcmp(*argv, "-list")) {
X			if (--argc < 0)
X				usage();
X
X			if (argc == 0) {
X				list = DEFAULT_LIST;
X			}
X			else {
X				list = atoi(*++argv);
X				CheckBounds(list);
X			}
X
X			continue;
X		}
X
X		/*
X		 * Load the file named in the next argument.
X		 */
X		if (!strcmp(*argv, "-file")) {
X			if (--argc <= 0)
X				usage();
X
X			filename = *++argv;
X			stuff = 1;
X			continue;
X		}
X
X		usage();
X	}
X
X	/*
X	 * If they didn't specify -contents, -list, or -rotate,
X	 * then we must be stuffing something into a cut buffer.
X	 */
X	if (!contents && !list && !rotate)
X		stuff = 1;
X
X	/*
X	 * Make sure they didn't specify more than one thing.
X	 */
X	if ((contents && rotate) || (contents && stuff) ||
X	    (contents && list) || (stuff && rotate) || (stuff && list)) {
X		fprintf(stderr, "%s: only one of contents, list, stuff, or rotate.\n",
X			pname);
X		exit(1);
X	}
X
X	/*
X	 * Open the display.
X	 */
X	if ((display = XOpenDisplay(displayname)) == NULL) {
X		fprintf(stderr, "%s: cannot open display.\n", pname);
X		exit(1);
X	}
X
X	/*
X	 * Go do our thing.
X	 */
X	if (contents)
X		ListCutBuffers(display, contents, 1);
X	else if (list)
X		ListCutBuffers(display, list, 0);
X	else if (rotate)
X		RotateCutBuffers(display, rotate);
X	else if (stuff)
X		StuffCutBuffers(display, filename, bnum, argc, argv);
X
X	/*
X	 * Close the display.  This has the side effect of flushing
X	 * whatever we did, so that it will take effect.
X	 */
X	XCloseDisplay(display);
X	exit(0);
X}
X
X/*
X * ListCutBuffers - list the size and/or contents of cut buffer bnum.
X */
XListCutBuffers(display, bnum, showcontents)
Xint bnum, showcontents;
XDisplay *display;
X{
X	int nbytes;
X	register char *buffer;
X
X	/*
X	 * If bnum is ALL_CUTBUFFERS, then do this for each one.
X	 * Otherwise, just do it for the one named.
X	 */
X	if (bnum == ALL_CUTBUFFERS) {
X		/*
X		 * For each cut buffer...
X		 */
X		for (bnum = MIN_CUTBUFFER; bnum <= MAX_CUTBUFFER; bnum++) {
X			/*
X			 * Get the contents of the cut buffer.
X			 */
X			buffer = XFetchBuffer(display, &nbytes, bnum);
X
X			/*
X			 * Print out the buffer number.
X			 */
X			printf("Cut Buffer %d%s", bnum,
X				showcontents ? " Contents:" : ":");
X
X			/*
X			 * Print out the size of the cut buffer, and
X			 * if they want the data too, print it also.
X			 */
X			if (nbytes == 0) {
X				printf(" (Empty)\n");
X			}
X			else {
X				if (showcontents) {
X					printf(" (%d bytes)\n", nbytes);
X					PrintBuffer(buffer, nbytes);
X				}
X				else {
X					printf(" %d bytes\n", nbytes);
X				}
X			}
X
X			/*
X			 * Free the X resource we got from XFetchBuffer.
X			 */
X			XFree(buffer);
X		}
X	}
X	else {
X		/*
X		 * Fetch the contents of the cut buffer.
X		 */
X		buffer = XFetchBuffer(display, &nbytes, bnum);
X
X		/*
X		 * Print out the buffer number.
X		 */
X		printf("Cut Buffer %d%s", bnum,
X			showcontents ? " Contents:" : ":");
X
X		/*
X		 * Print out the size of the buffer, and if they
X		 * want the data too, print it also.
X		 */
X		if (nbytes == 0) {
X			printf(" (Empty)\n");
X		}
X		else {
X			if (showcontents) {
X				printf(" (%d bytes)\n", nbytes);
X				PrintBuffer(buffer, nbytes);
X			}
X			else {
X				printf(" %d bytes\n", nbytes);
X			}
X		}
X
X		/*
X		 * Free the X resource we got from XFetchBuffer.
X		 */
X		XFree(buffer);
X	}
X}
X
X/*
X * RotateCutBuffers - rotate the cut buffers by howmuch.
X */
XRotateCutBuffers(display, howmuch)
XDisplay *display;
Xint howmuch;
X{
X	XRotateBuffers(display, howmuch);
X}
X
X/*
X * StuffCutBuffers - stuff data from filename, argv, or standard input into
X *		     cut buffer bnum.
X */
XStuffCutBuffers(display, filename, bnum, argc, argv)
XDisplay *display;
Xchar *filename;
Xint bnum, argc;
Xchar **argv;
X{
X	FILE *fp;
X	int nbytes;
X	char *buffer;
X
X	/*
X	 * Can't specify a file name as well as stuff on the command line.
X	 */
X	if ((argc > 0) && (filename != NULL)) {
X		fprintf(stderr, "%s: cannot specify both filename and data.\n",
X			pname);
X		exit(1);
X	}
X
X	/*
X	 * If there are arguments, use them as the data to put into
X	 * the cut buffer.  Otherwise, read it in from a file or
X	 * standard input.
X	 */
X	if (argc > 0) {
X		LoadBufferFromArgs(argc, argv, &buffer, &nbytes);
X	}
X	else {
X		/*
X		 * If they gave us a file name, open the file and
X		 * read it in.  Otherwise, read standard input.
X		 */
X		if (filename != NULL) {
X			if ((fp = fopen(filename, "r")) == NULL) {
X				fprintf(stderr, "%s: ", pname);
X				perror(filename);
X				exit(1);
X			}
X
X			LoadBufferFromFile(fp, &buffer, &nbytes);
X			fclose(fp);
X		}
X		else {
X			LoadBufferFromFile(stdin, &buffer, &nbytes);
X		}
X	}
X
X	/*
X	 * Store the data in the specified cut buffer.
X	 */
X	XStoreBuffer(display, buffer, nbytes, bnum);
X}
X
X/*
X * LoadBufferFromArgs - load data from the argv array into buffer.
X */
XLoadBufferFromArgs(argc, argv, buffer, nbytes)
Xchar **buffer;
Xchar **argv;
Xint *nbytes;
Xint argc;
X{
X	register char *buf;
X	register int n, nb, size;
X	char *malloc(), *realloc();
X
X	nb = 0;
X	size = BUFSIZ;
X
X	/*
X	 * Allocate some space for the buffer.
X	 */
X	if ((buf = malloc(size)) == NULL) {
X		fprintf(stderr, "%s: out of memory.\n", pname);
X		exit(1);
X	}
X
X	/*
X	 * Copy the arguments, separating them with a space.
X	 */
X	while (argc--) {
X		n = strlen(*argv) + 1;
X
X		/*
X		 * Ooops - not enough room, make the buffer bigger.
X		 */
X		if ((n + nb) >= size) {
X			size += BUFSIZ;
X
X			if ((buf = realloc(buf, size)) == NULL) {
X				fprintf(stderr, "%s: out of memory.\n", pname);
X				exit(1);
X			}
X		}
X
X		/*
X		 * Copy the argument and a space.
X		 */
X		strcat(buf, *argv++);
X		strcat(buf, " ");
X		nb += n;
X	}
X
X	/*
X	 * Lose the trailing space, and return the buffer and
X	 * the number of bytes in it.
X	 */
X	buf[nb - 1] = '\0';
X	*nbytes = nb - 1;
X	*buffer = buf;
X}
X
X/*
X * LoadBufferFromFile - load the contents of the file fp into buffer.
X */
XLoadBufferFromFile(fp, buffer, nbytes)
Xchar **buffer;
Xint *nbytes;
XFILE *fp;
X{
X	register char *buf, *s;
X	register int c, nb, size;
X	char *malloc(), *realloc();
X
X	nb = 0;
X	size = BUFSIZ;
X
X	/*
X	 * Allocate some space for the buffer.
X	 */
X	if ((buf = malloc(size)) == NULL) {
X		fprintf(stderr, "%s: out of memory.\n", pname);
X		exit(1);
X	}
X
X	s = buf;
X
X	/*
X	 * Read until we hit end of file.
X	 */
X	while ((c = getc(fp)) != EOF) {
X		/*
X		 * Ooops - not enough room, make the buffer bigger.
X		 */
X		if (nb >= size) {
X			size += BUFSIZ;
X
X			if ((buf = realloc(buf, size)) == NULL) {
X				fprintf(stderr, "%s: out of memory.\n", pname);
X				exit(1);
X			}
X
X			s = &buf[nb];
X		}
X
X		/*
X		 * Save the character.
X		 */
X		*s++ = (char) c;
X		nb++;
X	}
X
X	/*
X	 * Return the buffer and the size of
X	 * its contents.
X	 */
X	*buffer = buf;
X	*nbytes = nb;
X}
X
X/*
X * PrintBuffer - print the contents of buffer, pretty-printing control chars.
X */
XPrintBuffer(buffer, nbytes)
Xregister char *buffer;
Xregister int nbytes;
X{
X	/*
X	 * While there's data... print it out.
X	 */
X	while (nbytes--) {
X		if ((*buffer < ' ') && (*buffer != '\t') &&
X		    (*buffer != '\n'))
X			printf("^%c", *buffer | 0100);
X		else if (*buffer == 0177)
X			printf("^?");
X		else
X			putchar(*buffer);
X
X		buffer++;
X	}
X
X	/*
X	 * Add a terminating new line if needed.
X	 */
X	if (*--buffer != '\n')
X		putchar('\n');
X}
X
X/*
X * CheckBounds - make sure a buffer number is in range.
X */
XCheckBounds(n)
Xint n;
X{
X	if ((n < MIN_CUTBUFFER) || (n > MAX_CUTBUFFER)) {
X		fprintf(stderr, "%s: cut buffers range from %d to %d.\n",
X			pname, MIN_CUTBUFFER, MAX_CUTBUFFER);
X		exit(1);
X	}
X}
X
X/*
X * usage - print a usage message.
X */
Xusage()
X{
X	fprintf(stderr, "Usage: %s -contents [bnum]\n", pname);
X	fprintf(stderr, "       %s -list [bnum]\n", pname);
X	fprintf(stderr, "       %s -rotate [n]\n", pname);
X	fprintf(stderr, "       %s [-file fname] [-cutbuffer n] [data]\n",
X		pname);
X}
X
+END+OF+xcutbuf.c
echo '-rw-rw-r--  1 argv        10442 May  3 11:13 xcutbuf.c    (as sent)'
chmod u=rw,g=rw,o=r xcutbuf.c
ls -l xcutbuf.c
echo x - Imakefile
sed 's/^X//' > Imakefile <<'+END+OF+Imakefile'
X#
X# $Header: /u5/davy/progs/xcutbuf/RCS/Imakefile,v 1.1 89/05/02 11:04:21 davy Exp $
X#
X# Imakefile for xcutbuf.
X#
X# David A. Curry
X# Research Institute for Advanced Computer Science
X# Mail Stop 230-5
X# NASA Ames Research Center
X# Moffett Field, CA 94035
X# davy@riacs.edu
X#
X# $Log:	Imakefile,v $
X# Revision 1.1  89/05/02  11:04:21  davy
X# Initial revision
X# 
X#
XLOCAL_LIBRARIES = $(XLIB)
X
XSimpleProgramTarget(xcutbuf)
+END+OF+Imakefile
echo '-rw-rw-r--  1 argv          416 May  3 11:12 Imakefile    (as sent)'
chmod u=rw,g=rw,o=r Imakefile
ls -l Imakefile
echo x - patchlevel.h
sed 's/^X//' > patchlevel.h <<'+END+OF+patchlevel.h'
X/*
X * $Header: /u5/davy/progs/xcutbuf/RCS/patchlevel.h,v 1.1 89/05/02 11:04:40 davy Exp $
X *
X * patchlevel.h
X *
X * David A. Curry
X * Research Institute for Advanced Computer Science
X * Mail Stop 230-5
X * NASA Ames Research Center
X * Moffett Field, CA 94035
X * davy@riacs.edu
X *
X * $Log:	patchlevel.h,v $
X * Revision 1.1  89/05/02  11:04:40  davy
X * Initial revision
X * 
X */
X
X#define PatchLevel	0
+END+OF+patchlevel.h
echo '-rw-rw-r--  1 argv          396 May  3 11:12 patchlevel.h    (as sent)'
chmod u=rw,g=rw,o=r patchlevel.h
ls -l patchlevel.h
exit 0