Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / devs / clipboard / clipboard.c
blob3778f65d0ae06da91fb22e126c89bbe84f8c41c0
1 /*
2 Copyright © 1998-2008, 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 #define cb_sprintf(CBBase, buffer, format, ...) \
96 ({ ULONG _args[]={__VA_ARGS__}; APTR bufptr = buffer; RawDoFmt(format, _args, (VOID_FUNC)AROS_ASMSYMNAME(putchr), &bufptr); })
98 #else
100 /* NOTE: Use 68k putch so that we don't bork with 68k localelib - Piru */
101 static const UWORD putch[] = {0x16c0, 0x4e75};
103 #define cb_sprintf(CBBase, buffer, format, ...) \
104 ({ ULONG _args[]={__VA_ARGS__}; RawDoFmt(format, _args, (void (*)(void)) putch, buffer); })
106 #endif
109 /****************************************************************************************/
111 static int GM_UNIQUENAME(Open)
113 LIBBASETYPEPTR CBBase,
114 struct IORequest *ioreq,
115 ULONG unitnum,
116 ULONG flags
119 BPTR tempLock = 0;
120 BOOL found = FALSE; /* Does the unit already exist? */
121 struct Node *tempNode; /* Temporary variable used to see if a unit
122 already exists */
124 D(bug("clipboard.device/open: ioreq 0x%lx unitnum %ld flags 0x%lx\n",ioreq,unitnum,flags));
126 if(unitnum > 255)
128 D(bug("clipboard.device/open: unitnum too large\n"));
129 ioClip(ioreq)->io_Error = IOERR_OPENFAIL;
130 return FALSE;
133 #ifndef __MORPHOS__
134 #warning "You shouldn't check this..only leads to trouble"
135 if (ioreq->io_Message.mn_Length < sizeof(struct IOClipReq))
137 D(bug("clipboard.device/open: IORequest structure passed to OpenDevice is too small!\n"));
138 ioreq->io_Error = IOERR_OPENFAIL;
139 return FALSE;
141 #endif
143 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
145 /* Set up clipboard directory if we are the first opener */
147 if(CBBase->cb_ClipDir == NULL)
149 D(bug("clipboard.device/Checking for CLIPS:\n"));
151 if (!(tempLock = Lock("CLIPS:", ACCESS_READ)))
153 /* CLIPS: is not assigned - revert to ram:Clipboards */
155 D(bug("clipboard.device/CLIPS: not found\n"));
156 D(bug("clipboard.device/Checking for ram:\n"));
158 if (!(tempLock = Lock("ram:", ACCESS_READ)))
160 D(bug("clipboard.device/ram: Not found."));
161 ioreq->io_Error = IOERR_OPENFAIL;
163 else
165 D(bug("clipboard.device/Found ram:\n"));
166 D(bug("clipboard.device/Checking for ram:clipboards\n"));
168 if (!(tempLock = Lock("ram:clipboards", ACCESS_READ)))
170 D(bug("clipboard.device/Not found -- creating ram:Clipboards.\n"));
171 if (!(tempLock = CreateDir("ram:clipboards")))
173 D(bug("clipboard.device/can't create clipboards file\n"));
174 ioreq->io_Error = IOERR_OPENFAIL;
178 CBBase->cb_ClipDir = "ram:clipboards/";
180 else
182 D(bug("clipboard.device/Found CLIPS:\n"));
183 CBBase->cb_ClipDir = "CLIPS:";
186 /* Release the possible lock we have made */
187 UnLock(tempLock);
189 if (ioreq->io_Error)
191 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
192 return FALSE;
196 ForeachNode(&CBBase->cb_UnitList, tempNode)
198 D(bug("clipboard.device/ UnitNode 0x%lx Unit %ld\n",tempNode,tempNode->ln_Type));
199 if(tempNode->ln_Type == unitnum)
201 D(bug("clipboard.device/ found UnitNode\n"));
202 found = TRUE;
203 break;
207 if(found == FALSE)
209 D(bug("clipboard.device/Building unit...\n"));
211 if ((ioreq->io_Unit = (struct Unit *)AllocMem(sizeof(struct ClipboardUnit),
212 MEMF_CLEAR | MEMF_PUBLIC)))
214 CBUn->cu_Head.cu_UnitNum = unitnum;
215 CBUn->cu_Head.cu_Node.ln_Type = unitnum;
216 CBUn->cu_PostID = 0;
217 CBUn->cu_WriteID = 0;
219 NEWLIST((struct List*) &CBUn->cu_PostRequesters);
220 InitSemaphore(&CBUn->cu_UnitLock);
222 /* Construct clipboard unit filename. */
223 cb_sprintf(CBBase, CBUn->cu_clipFilename, "%s%lu", (ULONG) CBBase->cb_ClipDir,
224 unitnum);
226 CBUn->cu_Satisfy.sm_Unit = unitnum;
228 /* Initialization is done, and everything went OK. Add unit to the
229 list of clipboard units. */
230 ADDHEAD((struct List *)&CBBase->cb_UnitList, (struct Node *)CBUn);
232 /* Check if there is already a clipboard file for this unit existing.
233 If yes, then set WriteID to 1 so that CMD_READing works, and
234 also setup clipSize */
236 if ((CBUn->cu_clipFile = Open(CBUn->cu_clipFilename, MODE_OLDFILE)))
238 if (Seek(CBUn->cu_clipFile, 0, OFFSET_END) != -1)
240 CBUn->cu_clipSize = Seek(CBUn->cu_clipFile, 0, OFFSET_BEGINNING);
242 D(bug("clipboard.device/ <%s> clipsize %ld\n",CBUn->cu_clipFilename,CBUn->cu_clipSize));
243 if (CBUn->cu_clipSize != (ULONG)-1)
245 D(bug("clipboard.device/ WriteID set\n"));
246 CBUn->cu_WriteID = 1;
249 Close(CBUn->cu_clipFile);
250 CBUn->cu_clipFile = 0;
252 else
254 D(bug("clipboard.device/no <%s> file\n",CBUn->cu_clipFilename));
257 else
259 D(bug("clipboard.device/Couldn't alloc Unit\n"));
260 ioreq->io_Error = IOERR_OPENFAIL;
264 else
266 ioreq->io_Unit = (struct Unit *)tempNode;
269 if ((ioreq->io_Error == 0) && CBUn)
271 CBUn->cu_OpenCnt++;
273 else if (CBUn && (found == FALSE))
275 FreeMem(CBUn, sizeof(struct ClipboardUnit));
278 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
280 return TRUE;
283 /****************************************************************************************/
285 static int GM_UNIQUENAME(Close)
287 LIBBASETYPEPTR CBBase,
288 struct IORequest *ioreq
291 D(bug("clipboard.device/close:ioreq 0x%lx\n",ioreq));
293 /* Let any following attemps to use the device crash hard. */
294 ioreq->io_Device = (struct Device *)-1;
296 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
298 CBUn->cu_OpenCnt--;
300 D(bug("clipboard.device/close: unitcnt %ld\n",CBUn->cu_OpenCnt));
302 if(CBUn->cu_OpenCnt == 0)
304 D(bug("clipboard.device/close: removeunit\n",ioreq));
305 REMOVE((struct Node *)ioreq->io_Unit);
306 FreeMem(ioreq->io_Unit, sizeof(struct ClipboardUnit));
308 /* Let any following attemps to use the device crash hard. */
309 ioreq->io_Unit = (struct Unit *) -1;
312 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
314 return TRUE;
317 /****************************************************************************************/
319 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
320 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
321 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
323 /****************************************************************************************/
325 AROS_LH1(void, beginio,
326 AROS_LHA(struct IORequest *, ioreq, A1),
327 struct ClipboardBase *, CBBase, 5, Clipboard)
329 AROS_LIBFUNC_INIT
331 ioreq->io_Error = 0;
333 switch (ioreq->io_Command)
335 #if NEWSTYLE_DEVICE
336 case NSCMD_DEVICEQUERY:
337 if(ioClip(ioreq)->io_Length < ((LONG)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
339 ioreq->io_Error = IOERR_BADLENGTH;
341 else
343 struct NSDeviceQueryResult *d;
345 d = (struct NSDeviceQueryResult *)ioClip(ioreq)->io_Data;
347 d->DevQueryFormat = 0;
348 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
349 d->DeviceType = NSDEVTYPE_CLIPBOARD;
350 d->DeviceSubType = 0;
351 d->SupportedCommands = (UWORD *)SupportedCommands;
353 ioClip(ioreq)->io_Actual = sizeof(struct NSDeviceQueryResult);
355 break;
356 #endif
358 case CBD_CHANGEHOOK:
360 D(bug("clipboard.device/Command: CBD_CHANGEHOOK\n"));
362 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
364 /* io_Length is used as a means of specifying if the hook
365 should be added or removed. */
366 switch(ioClip(ioreq)->io_Length)
368 case 0:
369 REMOVE((struct Node *)(ioClip(ioreq)->io_Data));
370 break;
372 case 1:
373 ADDHEAD((struct List *)&CBBase->cb_HookList,
374 (struct Node *)ioClip(ioreq)->io_Data);
375 break;
377 default:
378 ioreq->io_Error = IOERR_BADLENGTH;
379 break;
381 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
382 break;
384 case CMD_WRITE:
386 D(bug("clipboard.device/Command: CMD_WRITE\n"));
388 writeCb(ioreq, CBBase);
389 break;
391 case CMD_READ:
393 D(bug("clipboard.device/Command: CMD_READ\n"));
395 /* Get new ID if this is the beginning of a read operation */
396 if(ioClip(ioreq)->io_ClipID == 0)
398 D(bug("clipboard.device/CMD_READ: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx].\n", FindTask(NULL)));
400 ObtainSemaphore(&CBUn->cu_UnitLock);
402 D(bug("clipboard.device/CMD_READ: Got unit lock.\n"));
404 /* If the last write was actually a POST, we must tell
405 the POSTer to WRITE the clip immediately, and we
406 will wait until he have done so. Then we check
407 again in case somebody managed to sneek in a
408 CBD_POST after the CMD_UPDATE. */
410 while(CBUn->cu_WriteID != 0 &&
411 CBUn->cu_WriteID == CBUn->cu_PostID)
413 struct PostRequest pr = {
414 { NULL, NULL },
415 FindTask(NULL)
418 /* Make sure we are signalled. */
419 ADDTAIL((struct List*) &CBUn->cu_PostRequesters, (struct Node*) &pr);
421 /* A poster reading will deadlock that process
422 * until somebody else writes to the
423 * clipboard. AmigaOS behaves exactly the same so
424 * it's ok. It's just plain stupid anyway. */
426 if (CBUn->cu_PostPort)
428 D(bug("clipboard.device/Command: CMD_READ..notify PostPort 0x%lx\n", CBUn->cu_PostPort));
430 CBUn->cu_Satisfy.sm_ClipID = CBUn->cu_PostID;
431 PutMsg(CBUn->cu_PostPort, (struct Message *)&CBUn->cu_Satisfy);
432 CBUn->cu_PostPort = NULL;
434 else
436 D(bug("clipboard.device/Command: no PostPort [me=%08lx]\n", FindTask(NULL)));
439 Forbid();
440 ReleaseSemaphore(&CBUn->cu_UnitLock);
441 SetSignal(0, SIGF_SINGLE);
442 Wait(SIGF_SINGLE);
443 Permit();
444 D(bug("Got SIGF_SINGLE [me=%08lx]\n",FindTask(NULL)));
445 ObtainSemaphore(&CBUn->cu_UnitLock);
446 D(bug("Got semaphore[me=%08lx]\n",FindTask(NULL)));
448 if(pr.pr_Link.mln_Succ->mln_Succ != NULL)
450 /* Wake up next reader */
451 Signal(((struct PostRequest*) pr.pr_Link.mln_Succ)->pr_Waiter, SIGF_SINGLE);
454 Remove((struct Node*) &pr);
457 CBUn->cu_ReadID++;
458 ioClip(ioreq)->io_ClipID = CBUn->cu_ReadID;
460 CBUn->cu_clipFile = Open(CBUn->cu_clipFilename, MODE_OLDFILE);
462 if(!CBUn->cu_clipFile)
464 D(bug("clipboard.device/CMD_READ: No clip file. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL)));
465 ReleaseSemaphore(&CBUn->cu_UnitLock);
466 ioClip(ioreq)->io_ClipID = -1;
467 ioClip(ioreq)->io_Actual = 0;
468 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
469 break;
472 else if(ioClip(ioreq)->io_ClipID != CBUn->cu_ReadID)
474 D(bug("clipboard.device/CMD_READ: Invalid clip id.\n"));
475 ioClip(ioreq)->io_Actual = 0;
476 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
477 break;
480 readCb(ioreq, CBBase);
482 break;
485 case CMD_UPDATE:
486 D(bug("clipboard.device/Command: CMD_UPDATE\n"));
488 updateCb(ioreq, CBBase);
489 break;
492 case CBD_POST:
493 D(bug("clipboard.device/Command: CBD_POST [me=%08lx]\n", FindTask(NULL)));
494 ObtainSemaphore(&CBUn->cu_UnitLock);
496 CBUn->cu_WriteID++;
497 CBUn->cu_PostID = CBUn->cu_WriteID;
498 CBUn->cu_PostPort = (struct MsgPort *)ioClip(ioreq)->io_Data;
500 ioClip(ioreq)->io_ClipID = CBUn->cu_PostID;
502 ReleaseSemaphore(&CBUn->cu_UnitLock);
504 D(bug("clipboard.device/CBD_POST: Calling monitoring hooks\n"));
506 /* Call monitoring hooks. */
507 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
509 struct Node *tnode;
510 struct ClipHookMsg chmsg;
512 chmsg.chm_Type = 0;
513 chmsg.chm_ChangeCmd = CBD_POST;
514 chmsg.chm_ClipID = CBUn->cu_PostID;
516 ForeachNode(&CBBase->cb_HookList, tnode)
518 D(bug("Calling hook %08x\n",tnode));
519 CallHookA((struct Hook *)tnode, CBUn, &chmsg);
521 D(bug("Done\n"));
523 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
525 D(bug("clipboard.device/CBD_POST: Called monitoring hooks\n"));
527 #if 0
528 // This does not seem to be robust enough; it can lead to
529 // a ping-pong effect. Never mind then.
531 ObtainSemaphore(&CBUn->cu_UnitLock);
533 if(!IsListEmpty((struct List*) &CBUn->cu_PostRequesters))
535 /* Normally, this can never happen. However, if an app
536 deadlocked by posting and then reading, try to make
537 this CBD_POST turn into a CMD_WRITE immediately. */
539 D(bug("clipboard.device/Command: CMD_POST..notify PostPort 0x%lx\n", CBUn->cu_PostPort));
541 CBUn->cu_Satisfy.sm_ClipID = CBUn->cu_PostID;
542 PutMsg(CBUn->cu_PostPort, (struct Message *)&CBUn->cu_Satisfy);
543 CBUn->cu_PostPort = NULL;
546 ReleaseSemaphore(&CBUn->cu_UnitLock);
547 #endif
548 break;
551 case CBD_CURRENTREADID:
552 D(bug("clipboard.device/Command: CBD_CURRENTREADID\n"));
553 ioClip(ioreq)->io_ClipID = CBUn->cu_WriteID;
554 /* NOTE: NOT A BUG! Was PostID. Note that AmigaOS really has a
555 ReadID counter that is *almost* always the same as WriteID. */
556 break;
559 case CBD_CURRENTWRITEID:
560 D(bug("clipboard.device/Command: CBD_CURRENTWRITEID\n"));
561 ioClip(ioreq)->io_ClipID = CBUn->cu_WriteID;
562 break;
565 default:
566 D(bug("clipboard.device/Command: <UNKNOWN> (%d = 0x%x)\n", ioreq->io_Command));
567 ioreq->io_Error = IOERR_NOCMD;
568 break;
570 } /* switch (ioreq->io_Command) */
572 /* If the quick bit is not set, send the message to the port */
573 if(!(ioreq->io_Flags & IOF_QUICK))
575 ReplyMsg(&ioreq->io_Message);
578 AROS_LIBFUNC_EXIT
581 /****************************************************************************************/
583 AROS_LH1(LONG, abortio,
584 AROS_LHA(struct IORequest *, ioreq, A1),
585 struct ClipboardBase *, CBBase, 6, Clipboard)
587 AROS_LIBFUNC_INIT
589 /* Keep compiler happy */
590 (void) ioreq;
591 (void) CBBase;
593 D(bug("clipboard.device/abortio: ioreq 0x%lx\n",ioreq));
594 /* Nothing to abort */
595 return 0;
597 AROS_LIBFUNC_EXIT
600 /****************************************************************************************/
602 static void readCb(struct IORequest *ioreq, struct ClipboardBase *CBBase)
604 /* Is there anything to be read? */
605 if(CBUn->cu_WriteID == 0)
607 D(bug("clipboard.device/readcb: nothing to read. setting IOERR_ABORTED as error and releasing semaphore [me=%08lx]\n", FindTask(NULL)));
608 Close(CBUn->cu_clipFile);
609 CBUn->cu_clipFile = 0;
610 ReleaseSemaphore(&CBUn->cu_UnitLock);
611 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
612 ioClip(ioreq)->io_Actual = 0;
613 ioClip(ioreq)->io_ClipID = -1;
614 return;
617 if(ioClip(ioreq)->io_Offset >= CBUn->cu_clipSize)
619 D(bug("clipboard.device/readCb: detected \"end of file\". Closing clipfile and releasing semaphore [me=%08lx]\n", FindTask(NULL)));
620 Close(CBUn->cu_clipFile);
621 CBUn->cu_clipFile = 0;
622 ReleaseSemaphore(&CBUn->cu_UnitLock);
623 ioClip(ioreq)->io_Actual = 0;
624 ioClip(ioreq)->io_ClipID = -1;
625 return;
628 if (!ioClip(ioreq)->io_Data)
630 ioClip(ioreq)->io_Offset += ioClip(ioreq)->io_Length;
631 ioClip(ioreq)->io_Actual = ioClip(ioreq)->io_Length;
633 else
635 D(bug("clipboard.device/readCb: Doing read Seek() at offset %d.\n",
636 ioClip(ioreq)->io_Offset));
638 Seek(CBUn->cu_clipFile, ioClip(ioreq)->io_Offset, OFFSET_BEGINNING);
640 ioClip(ioreq)->io_Actual = Read(CBUn->cu_clipFile, ioClip(ioreq)->io_Data,
641 ioClip(ioreq)->io_Length);
643 if (ioClip(ioreq)->io_Length >= 4)
645 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
646 ioClip(ioreq)->io_Length,
647 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
648 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
649 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
650 ((UBYTE *)ioClip(ioreq)->io_Data)[3],
651 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
652 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
653 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
654 ((UBYTE *)ioClip(ioreq)->io_Data)[3]));
656 else if (ioClip(ioreq)->io_Length == 2)
658 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x (%c%c)\n",
659 ioClip(ioreq)->io_Length,
660 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
661 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
662 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
663 ((UBYTE *)ioClip(ioreq)->io_Data)[1]));
665 else if (ioClip(ioreq)->io_Length == 1)
667 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x (%c)\n",
668 ioClip(ioreq)->io_Length,
669 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
670 ((UBYTE *)ioClip(ioreq)->io_Data)[0]));
672 else
674 D(bug("clipboard.device/readCb: Did Read nothing: data length = 0 data = 0x%x\n",
675 ioClip(ioreq)->io_Data));
678 ioClip(ioreq)->io_Offset += ioClip(ioreq)->io_Actual;
680 if (ioClip(ioreq)->io_Actual == 0)
682 Close(CBUn->cu_clipFile);
683 CBUn->cu_clipFile = 0;
684 D(bug("clipboard.device/readCb: io_Actual=0. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL)));
685 ReleaseSemaphore(&CBUn->cu_UnitLock);
686 ioClip(ioreq)->io_ClipID = -1;
691 /****************************************************************************************/
693 static void writeCb(struct IORequest *ioreq, struct ClipboardBase *CBBase)
695 D(bug("clipboard.device/writeCb: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx]\n", FindTask(NULL)));
696 ObtainSemaphore(&CBUn->cu_UnitLock);
697 D(bug("clipboard.device/writeCb: Got unit lock.\n"));
699 if(ioClip(ioreq)->io_ClipID == 0 ||
700 ioClip(ioreq)->io_ClipID == CBUn->cu_PostID)
702 /* A new write begins... */
704 CBUn->cu_clipSize = 0;
706 if(ioClip(ioreq)->io_ClipID == 0)
708 CBUn->cu_WriteID++;
709 ioClip(ioreq)->io_ClipID = CBUn->cu_WriteID;
712 /* No more POST writes accepted */
713 CBUn->cu_PostID = 0;
715 if (!(CBUn->cu_clipFile = Open(CBUn->cu_clipFilename, MODE_NEWFILE)))
717 D(bug("clipboard.device/writeCb: Opening clipfile in MODE_NEWFILE failed. Releasing Semaphore [me=%08lx]\n", FindTask(NULL)));
718 ReleaseSemaphore(&CBUn->cu_UnitLock);
719 ioClip(ioreq)->io_Error = IOERR_ABORTED;
720 ioClip(ioreq)->io_Actual = 0;
721 ioClip(ioreq)->io_ClipID = -1;
722 return;
725 D(bug("clipboard.device/writeCb: Opened file %s\n", CBUn->cu_clipFilename));
727 else if(ioClip(ioreq)->io_ClipID == CBUn->cu_WriteID)
729 D(bug("We already have the semaphore. [me=%08lx]\n", FindTask(NULL)));
730 ReleaseSemaphore(&CBUn->cu_UnitLock);
732 /* Continue the previous write */
734 else
736 D(bug("Invalid ClipID. Releasing Semaphore [me=%08lx]\n", FindTask(NULL)));
737 ReleaseSemaphore(&CBUn->cu_UnitLock);
739 /* Error */
740 ioClip(ioreq)->io_Error = IOERR_ABORTED;
741 ioClip(ioreq)->io_Actual = 0;
742 return;
745 if(ioClip(ioreq)->io_Offset > CBUn->cu_clipSize)
747 ULONG len = ioClip(ioreq)->io_Offset - CBUn->cu_clipSize;
748 ULONG buflen = len > WRITEBUFSIZE ? WRITEBUFSIZE : len;
749 UBYTE *buf = AllocMem(buflen, MEMF_CLEAR | MEMF_PUBLIC);
751 Seek(CBUn->cu_clipFile, 0, OFFSET_END);
753 if (buf)
755 while(len)
757 ULONG size = len > WRITEBUFSIZE ? WRITEBUFSIZE : len;
759 Write(CBUn->cu_clipFile, buf, size);
760 len -= size;
762 FreeMem(buf, buflen);
765 Seek(CBUn->cu_clipFile, ioClip(ioreq)->io_Offset, OFFSET_BEGINNING);
767 D(bug("clipboard.device/writeCb: Did Seek(), offset = %d\n", ioClip(ioreq)->io_Offset));
769 if (ioClip(ioreq)->io_Length >= 4)
771 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
772 ioClip(ioreq)->io_Length,
773 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
774 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
775 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
776 ((UBYTE *)ioClip(ioreq)->io_Data)[3],
777 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
778 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
779 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
780 ((UBYTE *)ioClip(ioreq)->io_Data)[3]));
782 else if (ioClip(ioreq)->io_Length == 2)
784 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x (%c%c)\n",
785 ioClip(ioreq)->io_Length,
786 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
787 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
788 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
789 ((UBYTE *)ioClip(ioreq)->io_Data)[1]));
791 else if (ioClip(ioreq)->io_Length == 1)
793 D(bug("clipboard.device/Doing Write: data length = %d data = %02x (%c)\n",
794 ioClip(ioreq)->io_Length,
795 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
796 ((UBYTE *)ioClip(ioreq)->io_Data)[0]));
799 else
801 D(bug("clipboard.device/Doing Write: Not really!!: data length = 0 data = 0x%x\n",
802 ioClip(ioreq)->io_Data));
805 if (ioClip(ioreq)->io_Length)
807 ioClip(ioreq)->io_Actual = Write(CBUn->cu_clipFile, ioClip(ioreq)->io_Data, ioClip(ioreq)->io_Length);
809 else
811 ioClip(ioreq)->io_Actual = 0; /* texteditor.mcc does 0-length writes */
814 if ((LONG)ioClip(ioreq)->io_Actual == -1)
816 D(bug("clipboard.device/writeCb: write failed\n"));
817 Close(CBUn->cu_clipFile);
818 CBUn->cu_clipFile = 0;
819 D(bug("clipboard.device/writeCb: releasing semaphore [me=%08lx]\n", FindTask(NULL)));
820 ReleaseSemaphore(&CBUn->cu_UnitLock);
821 ioClip(ioreq)->io_Error = IOERR_ABORTED;
822 ioClip(ioreq)->io_Actual = 0;
823 ioClip(ioreq)->io_ClipID = -1;
825 else
827 ioClip(ioreq)->io_Offset += ioClip(ioreq)->io_Actual;
828 if(ioClip(ioreq)->io_Offset > CBUn->cu_clipSize)
830 CBUn->cu_clipSize = ioClip(ioreq)->io_Offset;
835 /****************************************************************************************/
837 static void updateCb(struct IORequest *ioreq, struct ClipboardBase *CBBase)
839 if(CBUn->cu_WriteID != 0 && CBUn->cu_WriteID == ioClip(ioreq)->io_ClipID)
841 D(bug("clipboard.device/updateCb: Closing ClipFile\n"));
843 Close(CBUn->cu_clipFile);
844 CBUn->cu_clipFile = 0;
846 if(CBUn->cu_PostRequesters.mlh_Head->mln_Succ != NULL)
848 /* Wake up first reader */
849 D(bug("clipboard.device/updateCb: Waking up %08lx\n", ((struct PostRequest*) CBUn->cu_PostRequesters.mlh_Head)->pr_Waiter));
850 Signal(((struct PostRequest*) CBUn->cu_PostRequesters.mlh_Head)->pr_Waiter, SIGF_SINGLE);
852 D(bug("clipboard.device/updateCb: calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL)));
854 ReleaseSemaphore(&CBUn->cu_UnitLock);
856 D(bug("clipboard.device/updateCb: Calling monitoring hooks\n"));
858 /* Call monitoring hooks. */
859 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
861 struct Node *tnode;
862 struct ClipHookMsg chmsg;
864 chmsg.chm_Type = 0;
865 chmsg.chm_ChangeCmd = CMD_UPDATE;
866 chmsg.chm_ClipID = ioClip(ioreq)->io_ClipID;
868 ForeachNode(&CBBase->cb_HookList, tnode)
870 D(bug("Calling hook %08x\n",tnode));
871 CallHookA((struct Hook *)tnode, CBUn, &chmsg);
873 D(bug("Done\n"));
875 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
877 D(bug("clipboard.device/updateCb: Called monitoring hooks\n"));
879 else
881 ioClip(ioreq)->io_Error = IOERR_ABORTED;
882 ioClip(ioreq)->io_Actual = 0;
885 ioClip(ioreq)->io_ClipID = -1;
887 D(bug("clipboard.device/updateCb: end of function [me=%08lx]\n", FindTask(NULL)));
891 /****************************************************************************************/