home *** CD-ROM | disk | FTP | other *** search
- /* clip.c
- * Written by David N. Junod - August 28, 1990.
- * Main routines for CF (ClipFile).
- *
- * CF was written so that I could quickly, an easily, access (test) the
- * clipboard while writing the clipboard routines for rexxutil.library
- * (and the clipboard example for AmigaMail).
- *
- * BTW---This program isn't written in my usual style. This time around I
- * went for using as many of the SAS/C functions as possible.
- *
- */
-
- #include <exec/types.h>
- #include <exec/libraries.h>
- #include <exec/memory.h>
- #include <exec/ports.h>
- #include <dos/dos.h>
- #include <dos/notify.h>
- #include <devices/clipboard.h>
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <fcntl.h>
- #include <error.h>
-
- #include "cf.h"
- #include "cf_protos.h"
-
- /* So that we can check OS versions... */
- extern struct Library *SysBase;
-
- /* IO file name buffer */
- char name[256];
-
- /* File notification file name buffer */
- char notify[256];
-
- /* Disable Lattice/SASC CTRL-C handling */
- int CXBRK (void)
- {
- return (0);
- }
-
- int chkabort (void)
- {
- return (0);
- }
-
- void main (int argc, char **argv)
- {
- /* Make sure we were called from the Shell */
- if (argc > 0)
- {
- LONG unit = PRIMARY_CLIP;
- UBYTE idbuff[6] = {NULL};
- int fh = -1; /* File handle */
- int mode = 0; /* File access mode */
- int prot = 0; /* File protection mode */
- int acs = 0; /* Access mode */
- int next = 1; /* Option counter */
- unsigned int count; /* Bytes read/written */
- unsigned int length; /* Bytes to transfer */
- char option; /* Option pointer */
- char *odata; /* Option data pointer */
- BOOL cook = TRUE; /* Do we process the buffer? */
- struct MsgPort *mp; /* Notification message port */
- char opts[] = "urwn"; /* Options that require data */
-
- for (next = 1; (odata = argopt (argc, argv, opts, &next, &option)) != NULL;)
- {
- switch (toupper(option))
- {
- case '?':
- case 'H':
- help ();
- break;
-
- case 'F':
- cook = FALSE;
- break;
-
- case 'Q':
- cook = FALSE;
- acs = CF_QUERY;
- break;
-
- case 'C':
- cook = FALSE;
- acs = CF_CLEAR;
- break;
-
- case 'N':
- if (SysBase->lib_Version < 36)
- fprintf (stderr, "-n option requires AmigaOS 2.0\n");
- else
- {
- if (*odata)
- {
- /* Remember the notification name */
- strcpy (notify, odata);
-
- /* Set the access mode */
- acs = CF_NOTIFY;
- }
- else
- {
- fprintf (stderr, "-n option requires a file name\n");
- exit (5);
- }
- }
- break;
-
- case 'U':
- if (*odata)
- {
- unit = (LONG) atoi (odata);
-
- if (unit < 0L || unit > 255L)
- {
- fprintf (stderr, "Clipboard unit must range from 0 to 255\n");
- exit (5);
- }
- }
- else
- {
- fprintf (stderr, "-u option requires a number from 0 to 255\n");
- exit (5);
- }
- break;
-
- case 'R':
- if (*odata)
- {
- strcpy (name, odata);
-
- if (access (name, 4) == -1)
- {
- fprintf (stderr, "Can't read file %s\n", name);
- exit (5);
- }
-
- /* Set the access mode */
- mode = O_RDONLY;
- acs = CF_READ;
- }
- else
- {
- fprintf (stderr, "-r option requires a name\n");
- exit (5);
- }
- break;
-
- case 'W':
- if (*odata)
- {
- strcpy (name, odata);
-
- if ((access (name, 0) == 0) &&
- (access (name, 2) == -1))
- {
- fprintf (stderr, "Can't write to file %s\n", name);
- exit (5);
- }
-
- /* Set the access mode */
- mode = O_WRONLY | O_CREAT | O_TRUNC;
- acs = CF_WRITE;
- }
- else
- {
- fprintf (stderr, "-r option requires a name\n");
- exit (5);
- }
- break;
-
- default:
- fprintf (stderr, "%c is not a supported option\n", option);
- exit (5);
- break;
- }
- }
-
- /* See if help is needed */
- if ((argc == 2 && (strcmp (argv[1], "?") == 0)) || next < argc)
- help ();
-
- /* Do we need to open/create a file? */
- if (acs == CF_READ || acs == CF_WRITE)
- {
- /* Open/create the file */
- if ((fh = open (name, mode, prot)) == -1)
- {
- /* Display why we failed */
- perror ("CF; open");
-
- /* Clear the access flag */
- acs = 0;
- }
- }
-
- /* Attempt to open the designated clipboard unit */
- if (CBOpen (unit) == 0L)
- {
- struct Buffer *buff = NULL;
-
- switch (acs)
- {
- case 0: /* Just browsing, thanks */
- if (buff = CBRead (cook))
- {
- if (cook && (buff->b_Type == 0))
- printf ("%s\n", (STRPTR) buff->b_Buff);
- else
- printf ("Contents are %s\n",
- PrintID (buff->b_Type, idbuff));
- }
- else
- printf ("clipboard is empty\n");
- break;
-
- case CF_QUERY:
- if (buff = CBRead (cook))
- printf ("%s, %ld\n",
- PrintID (buff->b_Type, idbuff), buff->b_ClipID);
- else
- printf ("empty\n");
- break;
-
- case CF_READ:
- if (buff = fillbuffer (fh))
- CBWrite (buff);
- break;
-
- case CF_WRITE:
- if (buff = CBRead (cook))
- {
- /* Compute number of bytes to write */
- length = buff->b_Size - sizeof (struct Buffer);
-
- /* Write the buffer */
- count = write (fh, (char *) buff->b_Buff, length);
- }
- break;
-
- case CF_NOTIFY:
- /* Create a message port */
- if (mp = CreatePort (NULL, NULL))
- {
- struct NotifyRequest *nr;
- LONG msize;
-
- /* Calculate size of allocation */
- msize = sizeof (struct NotifyRequest);
-
- /* Allocate the notification request record */
- if (nr = (struct NotifyRequest *) AllocMem (msize, MEMF_CLEAR))
- {
- /* Fill in the notification request */
- nr->nr_Name = notify;
- nr->nr_stuff.nr_Msg.nr_Port = mp;
- nr->nr_Flags = NRF_SEND_MESSAGE | NRF_WAIT_REPLY;
-
- /* Start the notification */
- StartNotify (nr);
-
- /* Handle notification messages */
- HandleNotify (mp);
-
- /* Say that we're not interested any longer */
- EndNotify (nr);
-
- /* Free the notification request */
- FreeMem ((APTR) nr, msize);
- }
- else
- fprintf (stderr, "Couldn't allocate notify request\n");
-
- /* Delete our message port */
- DeletePort (mp);
- }
- else
- fprintf (stderr, "Couldn't create message port\n");
-
- break;
-
- case CF_CLEAR:
- CBClear();
- break;
- }
-
- /* Free the temporary buffer */
- freebuffer (buff);
-
- /* Close the clipboard */
- CBClose ();
- }
-
- /* See if we opened a file */
- if (fh != -1)
- {
- /* Close the file, and change the file mode if we created the file */
- if ((close (fh) == 0) && (mode == O_WRONLY))
- {
- if (chmod (name, S_IWRITE | S_IREAD))
- perror ("PF; chmod");
- }
- }
- }
- }
-
- VOID HandleNotify (struct MsgPort * mp)
- {
- LONG sigbits;
- BOOL going = TRUE;
-
- /* Build the signal bits that we're going to wait on */
- sigbits = (1L << mp->mp_SigBit) | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F;
-
- /* Loop until we get a signal or error */
- while (going)
- {
- struct NotifyMessage *nmsg;
- LONG sigsr;
-
- /* Wait for a message to come in */
- sigsr = Wait (sigbits);
-
- /* See if we got a ^C signal */
- if (sigsr & SIGBREAKF_CTRL_C)
- {
- printf ("process watching %s aborted\n", notify);
-
- /* Signal the end... */
- going = FALSE;
- }
-
- /* See if we got a ^F signal */
- if (sigsr & SIGBREAKF_CTRL_F)
- printf ("watching %s\n", notify);
-
- /* See if we have a file notification message */
- if (sigsr & (1L << mp->mp_SigBit))
- {
- int fh, i, error;
-
- /* Get each notification message and reply to it */
- while (nmsg = (struct NotifyMessage *) GetMsg (mp))
- ReplyMsg ((struct Message *) nmsg);
-
- /* For some reason, DPaint does something with the file twice,
- * if it already exists, so wait around until we have read
- * access to the file. So, when getting notification on a
- * DPaint brush, we'll actually get two messages. */
- for (i = 0, error = (-1); (error == (-1) && i < 100); i++)
- if ((error = access (notify, 4)) == (-1))
- Delay (10);
-
- /* Open the file */
- if ((fh = open (notify, O_RDONLY, 0)) == -1)
- {
- /* Build the error string */
- sprintf (name, "CF; %s", notify);
-
- /* Display why we failed */
- perror (name);
-
- /* Don't continue */
- going = FALSE;
- }
- else
- {
- struct Buffer *buff;
-
- /* Get contents of the file */
- if (buff = fillbuffer (fh))
- {
- /* Write the buffer to the clipboard */
- CBWrite (buff);
-
- /* Free the temporary buffer */
- freebuffer (buff);
- }
-
- /* Close the file */
- close (fh);
- }
- }
- }
- }
-
- void help (void)
- {
-
- printf ("CF (ClipFile) version 1.0\n");
- printf ("Written by David N. Junod\n");
- printf ("\n");
- printf ("-h Display this message\n");
- printf ("-u <unit> Clipboard unit, ranging from 0 to 255.\n");
- printf ("-r <file> Place the contents of <file> into the clipboard.\n");
- printf ("-w <file> Place the contents of the clipboard into <file>.\n");
- printf ("-f Don't convert FTXT form to ASCII\n");
- printf ("-q Query clipboard unit contents type\n");
- printf ("-c Clear the clipboard unit\n");
- printf ("-n <file> Watch the named file and place it into the clipboard\n");
- printf (" whenever it changes. Must send a break signal to shutdown\n");
- printf (" the process\n");
-
- exit (0);
- }
-
- struct Buffer *fillbuffer (int fh)
- {
- struct Buffer *buff = NULL;
- long msize = NULL;
- long count, length;
-
- /* Make sure we have a file handle */
- if (fh >= 0)
- {
- /* Find out how big the file is */
- if ((length = lseek (fh, 0L, 2)) >= 0L)
- {
- /* Seek back to the beginning */
- lseek (fh, 0L, 0);
-
- /* Calculate the size of the buffer */
- msize = sizeof (struct Buffer) + length;
-
- /* Allocate the buffer */
- if (buff = (struct Buffer *) AllocMem (msize, MEMF_CLEAR))
- {
- buff->b_Size = msize;
- buff->b_Type = 0;
-
- /* Point the buffer at the right place */
- buff->b_Buff = (VOID *) ((buff) + 1);
-
- /* Fill in the buffer */
- if ((count = read (fh, (char *) buff->b_Buff, length)) == -1)
- {
- /* Display error message */
- perror ("CF; read");
-
- /* Discard buffer */
- FreeMem ((APTR) buff, msize);
- buff = NULL;
- }
- else
- {
- LONG *buffer;
-
- buffer = (LONG *) buff->b_Buff;
- if (buffer[0] == ID_FORM)
- buff->b_Type = buffer[2];
- else if (count == 0L)
- buff->b_Type = ID_FTXT;
- }
- }
- }
- }
-
- return (buff);
- }
-