Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / clipboard / clipboard.c
blob9ff4bff992abe44412df96b5284a22d42255d9fb
1 /*
2 Copyright © 1998-2009, The AROS Development Team. All rights reserved.
3 $Id$
5 Clipboard device.
6 */
8 /****************************************************************************************/
10 #define AROS_ALMOST_COMPATIBLE 1
11 #include <exec/resident.h>
12 #include <devices/clipboard.h>
13 #include <devices/newstyle.h>
14 #include <exec/io.h>
15 #include <exec/initializers.h>
16 #include <proto/exec.h>
17 #include <proto/dos.h>
18 #include <proto/utility.h>
19 #include <clib/alib_protos.h>
20 #include <exec/memory.h>
21 #include <exec/errors.h>
22 #include <exec/lists.h>
23 #include <aros/libcall.h>
24 #include <aros/symbolsets.h>
25 #include "clipboard_intern.h"
26 #define DEBUG 0
27 #include <aros/debug.h>
28 #include <stdlib.h>
29 #include <stdio.h>
31 #include LC_LIBDEFS_FILE
33 /****************************************************************************************/
34 #ifndef __MORPHOS__
35 #define NEWSTYLE_DEVICE 1
36 #endif
38 #define ioClip(x) ((struct IOClipReq *)x)
39 #define CBUn (((struct ClipboardUnit *)ioreq->io_Unit))
41 #define WRITEBUFSIZE 4096
43 /****************************************************************************************/
45 static void readCb(struct IORequest *ioreq, struct ClipboardBase *CBBase);
46 static void writeCb(struct IORequest *ioreq, struct ClipboardBase *CBBase);
47 static void updateCb(struct IORequest *ioreq, struct ClipboardBase *CBBase);
49 /****************************************************************************************/
51 #if NEWSTYLE_DEVICE
53 static const UWORD SupportedCommands[] =
55 CMD_READ,
56 CMD_WRITE,
57 CMD_UPDATE,
58 CBD_CHANGEHOOK,
59 CBD_POST,
60 CBD_CURRENTREADID,
61 CBD_CURRENTWRITEID,
62 NSCMD_DEVICEQUERY,
66 #endif
68 /****************************************************************************************/
70 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR CBBase)
72 InitSemaphore(&CBBase->cb_SignalSemaphore);
73 NEWLIST(&CBBase->cb_UnitList);
74 NEWLIST(&CBBase->cb_HookList);
76 return TRUE;
79 /****************************************************************************************/
80 #ifndef __MORPHOS__
82 /* Putchar procedure needed by RawDoFmt() */
84 AROS_UFH2(void, putchr,
85 AROS_UFHA(UBYTE, chr, D0),
86 AROS_UFHA(STRPTR *, p, A3))
88 AROS_USERFUNC_INIT
89 *(*p)++=chr;
90 AROS_USERFUNC_EXIT
93 /****************************************************************************************/
95 static inline void cb_sprintf(LIBBASETYPEPTR CBBase, char *buffer, const char *format, ...)
97 AROS_SLOWSTACKFORMAT_PRE(format);
98 RawDoFmt(format, AROS_SLOWSTACKFORMAT_ARG(format), (VOID_FUNC)AROS_ASMSYMNAME(putchr), &buffer);
99 AROS_SLOWSTACKFORMAT_POST(format);
102 #else
104 /* NOTE: Use 68k putch so that we don't bork with 68k localelib - Piru */
105 static const UWORD putch[] = {0x16c0, 0x4e75};
107 #define cb_sprintf(CBBase, buffer, format, ...) \
108 ({ ULONG _args[]={__VA_ARGS__}; RawDoFmt(format, _args, (void (*)(void)) putch, buffer); })
110 #endif
113 /****************************************************************************************/
115 static int GM_UNIQUENAME(Open)
117 LIBBASETYPEPTR CBBase,
118 struct IORequest *ioreq,
119 ULONG unitnum,
120 ULONG flags
123 BPTR tempLock = 0;
124 BOOL found = FALSE; /* Does the unit already exist? */
125 struct Node *tempNode; /* Temporary variable used to see if a unit
126 already exists */
128 D(bug("clipboard.device/open: ioreq 0x%lx unitnum %ld flags 0x%lx\n",ioreq,unitnum,flags));
130 if(unitnum > 255)
132 D(bug("clipboard.device/open: unitnum too large\n"));
133 ioClip(ioreq)->io_Error = IOERR_OPENFAIL;
134 return FALSE;
137 #ifndef __MORPHOS__
138 /* FIXME: You shouldn't check this..only leads to trouble */
139 if (ioreq->io_Message.mn_Length < sizeof(struct IOClipReq))
141 D(bug("clipboard.device/open: IORequest structure passed to OpenDevice is too small!\n"));
142 ioreq->io_Error = IOERR_OPENFAIL;
143 return FALSE;
145 #endif
147 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
149 /* Set up clipboard directory if we are the first opener */
151 if(CBBase->cb_ClipDir == NULL)
153 /* Disable dos requesters */
154 struct Process *pr = (struct Process*)FindTask(NULL);
155 APTR oldWindowPtr = pr->pr_WindowPtr;
156 pr->pr_WindowPtr = (APTR)-1;
158 D(bug("clipboard.device/Checking for CLIPS:\n"));
160 if (!(tempLock = Lock("CLIPS:", ACCESS_READ)))
162 /* CLIPS: is not assigned - revert to ram:Clipboards */
164 D(bug("clipboard.device/CLIPS: not found\n"));
165 D(bug("clipboard.device/Checking for ram:\n"));
167 if (!(tempLock = Lock("ram:", ACCESS_READ)))
169 D(bug("clipboard.device/ram: Not found."));
170 ioreq->io_Error = IOERR_OPENFAIL;
172 else
174 D(bug("clipboard.device/Found ram:\n"));
175 D(bug("clipboard.device/Checking for ram:clipboards\n"));
177 if (!(tempLock = Lock("ram:clipboards", ACCESS_READ)))
179 D(bug("clipboard.device/Not found -- creating ram:Clipboards.\n"));
180 if (!(tempLock = CreateDir("ram:clipboards")))
182 D(bug("clipboard.device/can't create clipboards file\n"));
183 ioreq->io_Error = IOERR_OPENFAIL;
187 CBBase->cb_ClipDir = "ram:clipboards/";
189 else
191 D(bug("clipboard.device/Found CLIPS:\n"));
192 CBBase->cb_ClipDir = "CLIPS:";
195 pr->pr_WindowPtr = oldWindowPtr;
197 /* Release the possible lock we have made */
198 UnLock(tempLock);
200 if (ioreq->io_Error)
202 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
203 return FALSE;
207 ForeachNode(&CBBase->cb_UnitList, tempNode)
209 D(bug("clipboard.device/ UnitNode 0x%lx Unit %ld\n",tempNode,tempNode->ln_Type));
210 if(tempNode->ln_Type == unitnum)
212 D(bug("clipboard.device/ found UnitNode\n"));
213 found = TRUE;
214 break;
218 if(found == FALSE)
220 D(bug("clipboard.device/Building unit...\n"));
222 if ((ioreq->io_Unit = (struct Unit *)AllocMem(sizeof(struct ClipboardUnit),
223 MEMF_CLEAR | MEMF_PUBLIC)))
225 CBUn->cu_Head.cu_UnitNum = unitnum;
226 CBUn->cu_Head.cu_Node.ln_Type = unitnum;
227 CBUn->cu_PostID = 0;
228 CBUn->cu_WriteID = 0;
230 NEWLIST((struct List*) &CBUn->cu_PostRequesters);
231 InitSemaphore(&CBUn->cu_UnitLock);
233 /* Construct clipboard unit filename. */
234 cb_sprintf(CBBase, CBUn->cu_clipFilename, "%s%lu", (IPTR)CBBase->cb_ClipDir,
235 (ULONG)unitnum);
237 CBUn->cu_Satisfy.sm_Unit = unitnum;
239 /* Initialization is done, and everything went OK. Add unit to the
240 list of clipboard units. */
241 ADDHEAD((struct List *)&CBBase->cb_UnitList, (struct Node *)CBUn);
243 /* Check if there is already a clipboard file for this unit existing.
244 If yes, then set WriteID to 1 so that CMD_READing works, and
245 also setup clipSize */
247 if ((CBUn->cu_clipFile = Open(CBUn->cu_clipFilename, MODE_OLDFILE)))
249 if (Seek(CBUn->cu_clipFile, 0, OFFSET_END) != -1)
251 CBUn->cu_clipSize = Seek(CBUn->cu_clipFile, 0, OFFSET_BEGINNING);
253 D(bug("clipboard.device/ <%s> clipsize %ld\n",CBUn->cu_clipFilename,CBUn->cu_clipSize));
254 if (CBUn->cu_clipSize != (ULONG)-1)
256 D(bug("clipboard.device/ WriteID set\n"));
257 CBUn->cu_WriteID = 1;
260 Close(CBUn->cu_clipFile);
261 CBUn->cu_clipFile = 0;
263 else
265 D(bug("clipboard.device/no <%s> file\n",CBUn->cu_clipFilename));
268 else
270 D(bug("clipboard.device/Couldn't alloc Unit\n"));
271 ioreq->io_Error = IOERR_OPENFAIL;
275 else
277 ioreq->io_Unit = (struct Unit *)tempNode;
280 if ((ioreq->io_Error == 0) && CBUn)
282 CBUn->cu_OpenCnt++;
284 else if (CBUn && (found == FALSE))
286 FreeMem(CBUn, sizeof(struct ClipboardUnit));
289 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
291 return TRUE;
294 /****************************************************************************************/
296 static int GM_UNIQUENAME(Close)
298 LIBBASETYPEPTR CBBase,
299 struct IORequest *ioreq
302 D(bug("clipboard.device/close:ioreq 0x%lx\n",ioreq));
304 /* Let any following attemps to use the device crash hard. */
305 ioreq->io_Device = (struct Device *)-1;
307 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
309 CBUn->cu_OpenCnt--;
311 D(bug("clipboard.device/close: unitcnt %ld\n",CBUn->cu_OpenCnt));
313 if(CBUn->cu_OpenCnt == 0)
315 D(bug("clipboard.device/close: removeunit\n",ioreq));
316 REMOVE((struct Node *)ioreq->io_Unit);
317 FreeMem(ioreq->io_Unit, sizeof(struct ClipboardUnit));
319 /* Let any following attemps to use the device crash hard. */
320 ioreq->io_Unit = (struct Unit *) -1;
323 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
325 return TRUE;
328 /****************************************************************************************/
330 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
331 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
332 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
334 /****************************************************************************************/
336 AROS_LH1(void, beginio,
337 AROS_LHA(struct IORequest *, ioreq, A1),
338 struct ClipboardBase *, CBBase, 5, Clipboard)
340 AROS_LIBFUNC_INIT
342 ioreq->io_Error = 0;
344 switch (ioreq->io_Command)
346 #if NEWSTYLE_DEVICE
347 case NSCMD_DEVICEQUERY:
348 if(ioClip(ioreq)->io_Length < ((IPTR)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
350 ioreq->io_Error = IOERR_BADLENGTH;
352 else
354 struct NSDeviceQueryResult *d;
356 d = (struct NSDeviceQueryResult *)ioClip(ioreq)->io_Data;
358 d->DevQueryFormat = 0;
359 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
360 d->DeviceType = NSDEVTYPE_CLIPBOARD;
361 d->DeviceSubType = 0;
362 d->SupportedCommands = (UWORD *)SupportedCommands;
364 ioClip(ioreq)->io_Actual = sizeof(struct NSDeviceQueryResult);
366 break;
367 #endif
369 case CBD_CHANGEHOOK:
371 D(bug("clipboard.device/Command: CBD_CHANGEHOOK\n"));
373 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
375 /* io_Length is used as a means of specifying if the hook
376 should be added or removed. */
377 switch(ioClip(ioreq)->io_Length)
379 case 0:
380 REMOVE((struct Node *)(ioClip(ioreq)->io_Data));
381 break;
383 case 1:
384 ADDHEAD((struct List *)&CBBase->cb_HookList,
385 (struct Node *)ioClip(ioreq)->io_Data);
386 break;
388 default:
389 ioreq->io_Error = IOERR_BADLENGTH;
390 break;
392 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
393 break;
395 case CMD_WRITE:
397 D(bug("clipboard.device/Command: CMD_WRITE\n"));
399 writeCb(ioreq, CBBase);
400 break;
402 case CMD_READ:
404 D(bug("clipboard.device/Command: CMD_READ\n"));
406 /* Get new ID if this is the beginning of a read operation */
407 if(ioClip(ioreq)->io_ClipID == 0)
409 D(bug("clipboard.device/CMD_READ: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx].\n", FindTask(NULL)));
411 ObtainSemaphore(&CBUn->cu_UnitLock);
413 D(bug("clipboard.device/CMD_READ: Got unit lock.\n"));
415 /* If the last write was actually a POST, we must tell
416 the POSTer to WRITE the clip immediately, and we
417 will wait until he have done so. Then we check
418 again in case somebody managed to sneek in a
419 CBD_POST after the CMD_UPDATE. */
421 while(CBUn->cu_WriteID != 0 &&
422 CBUn->cu_WriteID == CBUn->cu_PostID)
424 struct PostRequest pr = {
425 { NULL, NULL },
426 FindTask(NULL)
429 /* Make sure we are signalled. */
430 ADDTAIL((struct List*) &CBUn->cu_PostRequesters, (struct Node*) &pr);
432 /* A poster reading will deadlock that process
433 * until somebody else writes to the
434 * clipboard. AmigaOS behaves exactly the same so
435 * it's ok. It's just plain stupid anyway. */
437 if (CBUn->cu_PostPort)
439 D(bug("clipboard.device/Command: CMD_READ..notify PostPort 0x%lx\n", CBUn->cu_PostPort));
441 CBUn->cu_Satisfy.sm_ClipID = CBUn->cu_PostID;
442 PutMsg(CBUn->cu_PostPort, (struct Message *)&CBUn->cu_Satisfy);
443 CBUn->cu_PostPort = NULL;
445 else
447 D(bug("clipboard.device/Command: no PostPort [me=%08lx]\n", FindTask(NULL)));
450 Forbid();
451 ReleaseSemaphore(&CBUn->cu_UnitLock);
452 SetSignal(0, SIGF_SINGLE);
453 Wait(SIGF_SINGLE);
454 Permit();
455 D(bug("Got SIGF_SINGLE [me=%08lx]\n",FindTask(NULL)));
456 ObtainSemaphore(&CBUn->cu_UnitLock);
457 D(bug("Got semaphore[me=%08lx]\n",FindTask(NULL)));
459 if(pr.pr_Link.mln_Succ->mln_Succ != NULL)
461 /* Wake up next reader */
462 Signal(((struct PostRequest*) pr.pr_Link.mln_Succ)->pr_Waiter, SIGF_SINGLE);
465 Remove((struct Node*) &pr);
468 CBUn->cu_ReadID++;
469 ioClip(ioreq)->io_ClipID = CBUn->cu_ReadID;
471 CBUn->cu_clipFile = Open(CBUn->cu_clipFilename, MODE_OLDFILE);
473 if(!CBUn->cu_clipFile)
475 D(bug("clipboard.device/CMD_READ: No clip file. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL)));
476 ReleaseSemaphore(&CBUn->cu_UnitLock);
477 ioClip(ioreq)->io_ClipID = -1;
478 ioClip(ioreq)->io_Actual = 0;
479 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
480 break;
483 else if(ioClip(ioreq)->io_ClipID != CBUn->cu_ReadID)
485 D(bug("clipboard.device/CMD_READ: Invalid clip id.\n"));
486 ioClip(ioreq)->io_Actual = 0;
487 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
488 break;
491 readCb(ioreq, CBBase);
493 break;
496 case CMD_UPDATE:
497 D(bug("clipboard.device/Command: CMD_UPDATE\n"));
499 updateCb(ioreq, CBBase);
500 break;
503 case CBD_POST:
504 D(bug("clipboard.device/Command: CBD_POST [me=%08lx]\n", FindTask(NULL)));
505 ObtainSemaphore(&CBUn->cu_UnitLock);
507 CBUn->cu_WriteID++;
508 CBUn->cu_PostID = CBUn->cu_WriteID;
509 CBUn->cu_PostPort = (struct MsgPort *)ioClip(ioreq)->io_Data;
511 ioClip(ioreq)->io_ClipID = CBUn->cu_PostID;
513 ReleaseSemaphore(&CBUn->cu_UnitLock);
515 D(bug("clipboard.device/CBD_POST: Calling monitoring hooks\n"));
517 /* Call monitoring hooks. */
518 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
520 struct Node *tnode;
521 struct ClipHookMsg chmsg;
523 chmsg.chm_Type = 0;
524 chmsg.chm_ChangeCmd = CBD_POST;
525 chmsg.chm_ClipID = CBUn->cu_PostID;
527 ForeachNode(&CBBase->cb_HookList, tnode)
529 D(bug("Calling hook %08x\n",tnode));
530 CallHookA((struct Hook *)tnode, CBUn, &chmsg);
532 D(bug("Done\n"));
534 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
536 D(bug("clipboard.device/CBD_POST: Called monitoring hooks\n"));
538 #if 0
539 // This does not seem to be robust enough; it can lead to
540 // a ping-pong effect. Never mind then.
542 ObtainSemaphore(&CBUn->cu_UnitLock);
544 if(!IsListEmpty((struct List*) &CBUn->cu_PostRequesters))
546 /* Normally, this can never happen. However, if an app
547 deadlocked by posting and then reading, try to make
548 this CBD_POST turn into a CMD_WRITE immediately. */
550 D(bug("clipboard.device/Command: CMD_POST..notify PostPort 0x%lx\n", CBUn->cu_PostPort));
552 CBUn->cu_Satisfy.sm_ClipID = CBUn->cu_PostID;
553 PutMsg(CBUn->cu_PostPort, (struct Message *)&CBUn->cu_Satisfy);
554 CBUn->cu_PostPort = NULL;
557 ReleaseSemaphore(&CBUn->cu_UnitLock);
558 #endif
559 break;
562 case CBD_CURRENTREADID:
563 D(bug("clipboard.device/Command: CBD_CURRENTREADID\n"));
564 ioClip(ioreq)->io_ClipID = CBUn->cu_WriteID;
565 /* NOTE: NOT A BUG! Was PostID. Note that AmigaOS really has a
566 ReadID counter that is *almost* always the same as WriteID. */
567 break;
570 case CBD_CURRENTWRITEID:
571 D(bug("clipboard.device/Command: CBD_CURRENTWRITEID\n"));
572 ioClip(ioreq)->io_ClipID = CBUn->cu_WriteID;
573 break;
576 default:
577 D(bug("clipboard.device/Command: <UNKNOWN> (%d = 0x%x)\n", ioreq->io_Command));
578 ioreq->io_Error = IOERR_NOCMD;
579 break;
581 } /* switch (ioreq->io_Command) */
583 /* If the quick bit is not set, send the message to the port */
584 if(!(ioreq->io_Flags & IOF_QUICK))
586 ReplyMsg(&ioreq->io_Message);
589 AROS_LIBFUNC_EXIT
592 /****************************************************************************************/
594 AROS_LH1(LONG, abortio,
595 AROS_LHA(struct IORequest *, ioreq, A1),
596 struct ClipboardBase *, CBBase, 6, Clipboard)
598 AROS_LIBFUNC_INIT
600 /* Keep compiler happy */
601 (void) ioreq;
602 (void) CBBase;
604 D(bug("clipboard.device/abortio: ioreq 0x%lx\n",ioreq));
605 /* Nothing to abort */
606 return 0;
608 AROS_LIBFUNC_EXIT
611 /****************************************************************************************/
613 static void readCb(struct IORequest *ioreq, struct ClipboardBase *CBBase)
615 /* Is there anything to be read? */
616 if(CBUn->cu_WriteID == 0)
618 D(bug("clipboard.device/readcb: nothing to read. setting IOERR_ABORTED as error and releasing semaphore [me=%08lx]\n", FindTask(NULL)));
619 Close(CBUn->cu_clipFile);
620 CBUn->cu_clipFile = 0;
621 ReleaseSemaphore(&CBUn->cu_UnitLock);
622 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
623 ioClip(ioreq)->io_Actual = 0;
624 ioClip(ioreq)->io_ClipID = -1;
625 return;
628 if(ioClip(ioreq)->io_Offset >= CBUn->cu_clipSize)
630 D(bug("clipboard.device/readCb: detected \"end of file\". Closing clipfile and releasing semaphore [me=%08lx]\n", FindTask(NULL)));
631 Close(CBUn->cu_clipFile);
632 CBUn->cu_clipFile = 0;
633 ReleaseSemaphore(&CBUn->cu_UnitLock);
634 ioClip(ioreq)->io_Actual = 0;
635 ioClip(ioreq)->io_ClipID = -1;
636 return;
639 if (!ioClip(ioreq)->io_Data)
642 * according to the autodocs, io_Offset is incremented by io_Actual
643 * as if io_Length bytes had been read.
645 if(ioClip(ioreq)->io_Offset + ioClip(ioreq)->io_Length > CBUn->cu_clipSize)
647 /* Cannot read more bytes as there are in the clipboard.
648 * On amigaOS, this can be used to get the current size of the
649 * clipboard content.
651 ioClip(ioreq)->io_Actual = CBUn->cu_clipSize - ioClip(ioreq)->io_Offset;
652 D(bug("clipboard.device/readCb: reached end of clipboard data\n"));
654 else
656 /* we pretend to read the requested length */
657 ioClip(ioreq)->io_Actual = ioClip(ioreq)->io_Length;
660 else
662 D(bug("clipboard.device/readCb: Doing read Seek() at offset %d.\n",
663 ioClip(ioreq)->io_Offset));
665 Seek(CBUn->cu_clipFile, ioClip(ioreq)->io_Offset, OFFSET_BEGINNING);
667 ioClip(ioreq)->io_Actual = Read(CBUn->cu_clipFile, ioClip(ioreq)->io_Data,
668 ioClip(ioreq)->io_Length);
670 if (ioClip(ioreq)->io_Length >= 4)
672 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
673 ioClip(ioreq)->io_Length,
674 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
675 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
676 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
677 ((UBYTE *)ioClip(ioreq)->io_Data)[3],
678 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
679 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
680 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
681 ((UBYTE *)ioClip(ioreq)->io_Data)[3]));
683 else if (ioClip(ioreq)->io_Length == 2)
685 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x (%c%c)\n",
686 ioClip(ioreq)->io_Length,
687 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
688 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
689 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
690 ((UBYTE *)ioClip(ioreq)->io_Data)[1]));
692 else if (ioClip(ioreq)->io_Length == 1)
694 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x (%c)\n",
695 ioClip(ioreq)->io_Length,
696 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
697 ((UBYTE *)ioClip(ioreq)->io_Data)[0]));
699 else
701 D(bug("clipboard.device/readCb: Did Read nothing: data length = 0 data = 0x%x\n",
702 ioClip(ioreq)->io_Data));
707 ioClip(ioreq)->io_Offset += ioClip(ioreq)->io_Actual;
710 * I am not sure, if a Close is the right thing to do, even if io_Data was NULL.
711 * But it should not harm either.
713 if (ioClip(ioreq)->io_Actual == 0)
715 Close(CBUn->cu_clipFile);
716 CBUn->cu_clipFile = 0;
717 D(bug("clipboard.device/readCb: io_Actual=0. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL)));
718 ReleaseSemaphore(&CBUn->cu_UnitLock);
719 ioClip(ioreq)->io_ClipID = -1;
723 /****************************************************************************************/
725 static void writeCb(struct IORequest *ioreq, struct ClipboardBase *CBBase)
727 D(bug("clipboard.device/writeCb: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx]\n", FindTask(NULL)));
728 ObtainSemaphore(&CBUn->cu_UnitLock);
729 D(bug("clipboard.device/writeCb: Got unit lock.\n"));
731 if(ioClip(ioreq)->io_ClipID == 0 ||
732 ioClip(ioreq)->io_ClipID == CBUn->cu_PostID)
734 /* A new write begins... */
736 CBUn->cu_clipSize = 0;
738 if(ioClip(ioreq)->io_ClipID == 0)
740 CBUn->cu_WriteID++;
741 ioClip(ioreq)->io_ClipID = CBUn->cu_WriteID;
744 /* No more POST writes accepted */
745 CBUn->cu_PostID = 0;
747 if (!(CBUn->cu_clipFile = Open(CBUn->cu_clipFilename, MODE_NEWFILE)))
749 D(bug("clipboard.device/writeCb: Opening clipfile in MODE_NEWFILE failed. Releasing Semaphore [me=%08lx]\n", FindTask(NULL)));
750 ReleaseSemaphore(&CBUn->cu_UnitLock);
751 ioClip(ioreq)->io_Error = IOERR_ABORTED;
752 ioClip(ioreq)->io_Actual = 0;
753 ioClip(ioreq)->io_ClipID = -1;
754 return;
757 D(bug("clipboard.device/writeCb: Opened file %s\n", CBUn->cu_clipFilename));
759 else if(ioClip(ioreq)->io_ClipID == CBUn->cu_WriteID)
761 D(bug("We already have the semaphore. [me=%08lx]\n", FindTask(NULL)));
762 ReleaseSemaphore(&CBUn->cu_UnitLock);
764 /* Continue the previous write */
766 else
768 D(bug("Invalid ClipID. Releasing Semaphore [me=%08lx]\n", FindTask(NULL)));
769 ReleaseSemaphore(&CBUn->cu_UnitLock);
771 /* Error */
772 ioClip(ioreq)->io_Error = IOERR_ABORTED;
773 ioClip(ioreq)->io_Actual = 0;
774 return;
777 if(ioClip(ioreq)->io_Offset > CBUn->cu_clipSize)
779 ULONG len = ioClip(ioreq)->io_Offset - CBUn->cu_clipSize;
780 ULONG buflen = len > WRITEBUFSIZE ? WRITEBUFSIZE : len;
781 UBYTE *buf = AllocMem(buflen, MEMF_CLEAR | MEMF_PUBLIC);
783 Seek(CBUn->cu_clipFile, 0, OFFSET_END);
785 if (buf)
787 while(len)
789 ULONG size = len > WRITEBUFSIZE ? WRITEBUFSIZE : len;
791 Write(CBUn->cu_clipFile, buf, size);
792 len -= size;
794 FreeMem(buf, buflen);
797 Seek(CBUn->cu_clipFile, ioClip(ioreq)->io_Offset, OFFSET_BEGINNING);
799 D(bug("clipboard.device/writeCb: Did Seek(), offset = %d\n", ioClip(ioreq)->io_Offset));
801 if (ioClip(ioreq)->io_Length >= 4)
803 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
804 ioClip(ioreq)->io_Length,
805 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
806 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
807 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
808 ((UBYTE *)ioClip(ioreq)->io_Data)[3],
809 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
810 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
811 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
812 ((UBYTE *)ioClip(ioreq)->io_Data)[3]));
814 else if (ioClip(ioreq)->io_Length == 2)
816 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x (%c%c)\n",
817 ioClip(ioreq)->io_Length,
818 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
819 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
820 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
821 ((UBYTE *)ioClip(ioreq)->io_Data)[1]));
823 else if (ioClip(ioreq)->io_Length == 1)
825 D(bug("clipboard.device/Doing Write: data length = %d data = %02x (%c)\n",
826 ioClip(ioreq)->io_Length,
827 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
828 ((UBYTE *)ioClip(ioreq)->io_Data)[0]));
831 else
833 D(bug("clipboard.device/Doing Write: Not really!!: data length = 0 data = 0x%x\n",
834 ioClip(ioreq)->io_Data));
837 if (ioClip(ioreq)->io_Length)
839 ioClip(ioreq)->io_Actual = Write(CBUn->cu_clipFile, ioClip(ioreq)->io_Data, ioClip(ioreq)->io_Length);
841 else
843 ioClip(ioreq)->io_Actual = 0; /* texteditor.mcc does 0-length writes */
846 if ((LONG)ioClip(ioreq)->io_Actual == -1)
848 D(bug("clipboard.device/writeCb: write failed\n"));
849 Close(CBUn->cu_clipFile);
850 CBUn->cu_clipFile = 0;
851 D(bug("clipboard.device/writeCb: releasing semaphore [me=%08lx]\n", FindTask(NULL)));
852 ReleaseSemaphore(&CBUn->cu_UnitLock);
853 ioClip(ioreq)->io_Error = IOERR_ABORTED;
854 ioClip(ioreq)->io_Actual = 0;
855 ioClip(ioreq)->io_ClipID = -1;
857 else
859 ioClip(ioreq)->io_Offset += ioClip(ioreq)->io_Actual;
860 if(ioClip(ioreq)->io_Offset > CBUn->cu_clipSize)
862 CBUn->cu_clipSize = ioClip(ioreq)->io_Offset;
867 /****************************************************************************************/
869 static void updateCb(struct IORequest *ioreq, struct ClipboardBase *CBBase)
871 if(CBUn->cu_WriteID != 0 && CBUn->cu_WriteID == ioClip(ioreq)->io_ClipID)
873 D(bug("clipboard.device/updateCb: Closing ClipFile\n"));
875 Close(CBUn->cu_clipFile);
876 CBUn->cu_clipFile = 0;
878 if(CBUn->cu_PostRequesters.mlh_Head->mln_Succ != NULL)
880 /* Wake up first reader */
881 D(bug("clipboard.device/updateCb: Waking up %08lx\n", ((struct PostRequest*) CBUn->cu_PostRequesters.mlh_Head)->pr_Waiter));
882 Signal(((struct PostRequest*) CBUn->cu_PostRequesters.mlh_Head)->pr_Waiter, SIGF_SINGLE);
884 D(bug("clipboard.device/updateCb: calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL)));
886 ReleaseSemaphore(&CBUn->cu_UnitLock);
888 D(bug("clipboard.device/updateCb: Calling monitoring hooks\n"));
890 /* Call monitoring hooks. */
891 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
893 struct Node *tnode;
894 struct ClipHookMsg chmsg;
896 chmsg.chm_Type = 0;
897 chmsg.chm_ChangeCmd = CMD_UPDATE;
898 chmsg.chm_ClipID = ioClip(ioreq)->io_ClipID;
900 ForeachNode(&CBBase->cb_HookList, tnode)
902 D(bug("Calling hook %08x\n",tnode));
903 CallHookA((struct Hook *)tnode, CBUn, &chmsg);
905 D(bug("Done\n"));
907 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
909 D(bug("clipboard.device/updateCb: Called monitoring hooks\n"));
911 else
913 ioClip(ioreq)->io_Error = IOERR_ABORTED;
914 ioClip(ioreq)->io_Actual = 0;
917 ioClip(ioreq)->io_ClipID = -1;
919 D(bug("clipboard.device/updateCb: end of function [me=%08lx]\n", FindTask(NULL)));
923 /****************************************************************************************/