Updated PCI IDs to latest snapshot.
[tangerine.git] / workbench / tools / debug / sashimi / sashimi.c
bloba64b0e7eb02af815b5df88843fe65b621553f0c3
1 /*
2 * $Id$
4 * Sashimi -- intercepts raw serial debugging output on your own machine
6 * Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
7 * Public Domain
9 * :ts=4
12 /****************************************************************************/
14 #define __TIMER_NOLIBBASE__
16 #include <exec/execbase.h>
17 #include <exec/memory.h>
19 #include <devices/timer.h>
21 #include <dos/dosextens.h>
22 #include <dos/rdargs.h>
24 #include <proto/timer.h>
25 #include <proto/exec.h>
26 #include <proto/dos.h>
28 #include <aros/libcall.h>
30 #include <string.h>
31 #include <stddef.h>
32 #include <stdio.h>
34 /****************************************************************************/
36 STRPTR Version = "$VER: Sashimi 1.6 (20.6.1999)\r\n";
38 /****************************************************************************/
40 #define OK (0)
41 #define NOT !
42 #define BUSY NULL
43 #define ZERO ((BPTR)0UL)
45 #define min(a,b) (((a) < (b)) ? (a) : (b))
47 #define NO_ALLOCABS 1
49 /****************************************************************************/
51 enum
53 MODE_Regular,
54 MODE_Recovery
57 /****************************************************************************/
59 #define MILLION 1000000
61 /****************************************************************************/
63 STATIC struct Device * TimerBase;
65 /****************************************************************************/
67 typedef LONG SWITCH;
68 typedef LONG * NUMBER;
69 typedef STRPTR KEY;
71 STATIC struct
73 /* Startup options */
74 KEY Recover; /* Recover any old Sashimi buffer still in memory */
75 SWITCH On; /* Ignored */
76 NUMBER BufferK; /* Buffer size, to the power of two */
77 NUMBER BufferSize; /* Buffer size in bytes */
78 SWITCH NoPrompt; /* Do not show the initial prompt message */
79 SWITCH Quiet; /* Do not produce any output at all */
80 SWITCH AskExit; /* Ask whether to exit the program */
81 SWITCH AskSave; /* Ask for a file to save the buffer to when exiting */
82 SWITCH TimerOn; /* Check the circular buffer every 1/10 of a second */
83 SWITCH Console; /* Open a console window for I/O */
84 KEY Window; /* Console window specifier */
86 /* Runtime options */
87 SWITCH Off; /* Turn Sashimi off */
88 SWITCH Save; /* Save the circular buffer contents */
89 KEY SaveAs; /* Save the circular buffer contents under a specific name */
90 SWITCH Empty; /* Empty the circular buffer */
91 } ShellArguments;
93 STATIC const STRPTR ShellTemplate =
94 "RECOVER/K,"
95 "ON/S,"
96 "BUFK/N,"
97 "BUFFERSIZE/N,"
98 "NOPROMPT/S,"
99 "QUIET/S,"
100 "ASKEXIT/S,"
101 "ASKSAVE/S,"
102 "TIMERON/S,"
103 "CONSOLE/S,"
104 "WINDOW/K,"
105 "OFF/S,"
106 "SAVE/S,"
107 "SAVEAS/K,"
108 "EMPTY/S";
110 /****************************************************************************/
112 /* Eat me */
113 #define COOKIE 0x08021999
115 struct SashimiResource
117 struct Library sr_Library; /* Global link */
118 UWORD sr_Pad; /* Long word alignment */
120 ULONG sr_Cookie; /* Magic marker */
121 APTR sr_PointsToCookie; /* Points back to cookie */
122 ULONG sr_CreatedWhen; /* When exactly was this data structure created? */
124 struct Task * sr_Owner; /* Current owner of the patches */
125 LONG sr_OwnerSigBit;
126 ULONG sr_OwnerSigMask; /* Signal mask to send when a new line is in the buffer. */
128 ULONG sr_FIFOTotalSize; /* Number of bytes allocated for the buffer */
129 ULONG sr_FIFOReadIndex; /* Read index counter */
130 ULONG sr_FIFOWriteIndex; /* Write index counter */
131 ULONG sr_FIFOBytesStored; /* Number of bytes in the FIFO */
132 BOOL sr_FIFOOverrun; /* TRUE if the write index counter has
133 * overrun the read index counter.
135 BOOL sr_FIFOWrapped; /* TRUE if the write index counter has
136 * wrapped around the circular buffer.
138 UBYTE sr_FIFO[1]; /* The message buffer */
141 STATIC const STRPTR SashimiResourceName = "sashimi.resource";
142 STATIC struct SashimiResource * GlobalSashimiResource;
144 /****************************************************************************/
146 #define LVORawIOInit (-84 * LIB_VECTSIZE)
147 #define LVORawMayGetChar (-85 * LIB_VECTSIZE)
148 #define LVORawPutChar (-86 * LIB_VECTSIZE)
150 /****************************************************************************/
152 STATIC APTR OldRawIOInit;
153 STATIC APTR OldRawMayGetChar;
154 STATIC APTR OldRawPutChar;
156 /****************************************************************************/
158 AROS_LH0(void, NewRawIOInit,
159 struct ExecBase *, SysBase, 84, Exec)
161 AROS_LIBFUNC_INIT
163 /* Nothing happens here */
165 AROS_LIBFUNC_EXIT
168 AROS_LH0(LONG, NewRawMayGetChar,
169 struct ExecBase *, SysBase, 85, Exec)
171 AROS_LIBFUNC_INIT
173 /* We always return sort of a confirmation. */
174 return('y');
176 AROS_LIBFUNC_EXIT
179 /****************************************************************************/
181 STATIC LONG
182 GetCharsInFIFO(struct SashimiResource * sr)
184 LONG result;
186 Disable();
188 if(sr->sr_FIFOWrapped)
189 result = sr->sr_FIFOTotalSize;
190 else
191 result = sr->sr_FIFOWriteIndex;
193 Enable();
195 return(result);
198 STATIC VOID
199 EmptyFIFO(struct SashimiResource * sr)
201 Disable();
203 sr->sr_FIFOReadIndex = 0;
204 sr->sr_FIFOWriteIndex = 0;
205 sr->sr_FIFOBytesStored = 0;
206 sr->sr_FIFOOverrun = FALSE;
207 sr->sr_FIFOWrapped = FALSE;
209 Enable();
212 STATIC LONG
213 ReadFIFOChars(struct SashimiResource * sr,UBYTE * buffer,LONG maxChars)
215 LONG result = 0;
217 Disable();
219 if(sr->sr_FIFOBytesStored > 0)
221 LONG howMany;
223 if(maxChars > sr->sr_FIFOBytesStored)
224 maxChars = sr->sr_FIFOBytesStored;
228 /* Find out how many characters can be read
229 * from the FIFO without overrunning the
230 * end of it. We don't read more than these
231 * few characters in one go.
233 howMany = min(maxChars,sr->sr_FIFOTotalSize - sr->sr_FIFOReadIndex);
235 memcpy(buffer,&sr->sr_FIFO[sr->sr_FIFOReadIndex],howMany);
237 result += howMany;
238 buffer += howMany;
239 maxChars -= howMany;
241 sr->sr_FIFOReadIndex = (sr->sr_FIFOReadIndex + howMany) % sr->sr_FIFOTotalSize;
243 while(maxChars > 0);
245 /* Subtract the number of characters we
246 * read in the loop.
248 sr->sr_FIFOBytesStored -= result;
251 Enable();
253 return(result);
256 STATIC VOID
257 StoreFIFOChar(struct SashimiResource * sr,UBYTE c)
259 sr->sr_FIFO[sr->sr_FIFOWriteIndex] = c;
260 sr->sr_FIFOWriteIndex = (sr->sr_FIFOWriteIndex + 1) % sr->sr_FIFOTotalSize;
262 /* If the buffer wraps around, remember it. */
263 if(sr->sr_FIFOWriteIndex == 0)
264 sr->sr_FIFOWrapped = TRUE;
266 /* Check if the circular buffer was overrun */
267 sr->sr_FIFOBytesStored++;
268 if(sr->sr_FIFOBytesStored > sr->sr_FIFOTotalSize)
270 sr->sr_FIFOOverrun = TRUE;
272 /* Move the read index to the same position as
273 * the write index and retain only as many
274 * bytes as would fit into the FIFO.
276 sr->sr_FIFOReadIndex = sr->sr_FIFOWriteIndex;
277 sr->sr_FIFOBytesStored = sr->sr_FIFOTotalSize;
281 /****************************************************************************/
283 AROS_LH1(void, NewRawPutChar,
284 AROS_LHA(UBYTE, c, D0),
285 struct ExecBase *, SysBase, 86, Exec)
287 AROS_LIBFUNC_INIT
289 /* Do not store NUL bytes. */
290 if(c != '\0')
292 STATIC ULONG Position = 0;
294 Disable();
296 /* Filter out extra <cr> characters. */
297 if(c != '\r' || Position > 0)
299 struct SashimiResource * sr = GlobalSashimiResource;
301 /* Store another byte in the buffer */
302 StoreFIFOChar(sr,c);
304 /* Notify Sashimi every time there is an end of line
305 * character in the stream.
307 if(c == '\n' || c == '\r')
308 Signal(sr->sr_Owner,sr->sr_OwnerSigMask);
311 if(c == '\r' || c == '\n')
312 Position = 0;
313 else
314 Position++;
316 Enable();
319 AROS_LIBFUNC_EXIT
322 /****************************************************************************/
324 STATIC VOID
325 RemovePatches(VOID)
327 APTR res;
329 /* We disable the interrupts because the raw I/O routines can
330 * be called from within interrupt code.
332 Disable();
334 /* For every patch planted, remove it and check whether the code
335 * had been patched before. If it has, restore the patch. Note that
336 * this is not bullet proof :(
338 res = SetFunction(&SysBase->LibNode,LVORawIOInit,OldRawIOInit);
339 if(res != AROS_SLIB_ENTRY(NewRawIOInit,Exec))
340 SetFunction(&SysBase->LibNode,LVORawIOInit,res);
342 res = SetFunction(&SysBase->LibNode,LVORawMayGetChar,OldRawMayGetChar);
343 if(res != AROS_SLIB_ENTRY(NewRawMayGetChar,Exec))
344 SetFunction(&SysBase->LibNode,LVORawMayGetChar,res);
346 res = SetFunction(&SysBase->LibNode,LVORawPutChar,OldRawPutChar);
347 if(res != AROS_SLIB_ENTRY(NewRawPutChar,Exec))
348 SetFunction(&SysBase->LibNode,LVORawPutChar,res);
350 Enable();
353 STATIC VOID
354 InstallPatches(VOID)
356 /* We disable the interrupts because the raw I/O routines can
357 * be called from within interrupt code.
359 Disable();
361 OldRawIOInit = SetFunction(&SysBase->LibNode,LVORawIOInit, AROS_SLIB_ENTRY(NewRawIOInit,Exec));
362 OldRawMayGetChar = SetFunction(&SysBase->LibNode,LVORawMayGetChar, AROS_SLIB_ENTRY(NewRawMayGetChar,Exec));
363 OldRawPutChar = SetFunction(&SysBase->LibNode,LVORawPutChar, AROS_SLIB_ENTRY(NewRawPutChar,Exec));
365 Enable();
368 /****************************************************************************/
370 STATIC VOID
371 FreeSashimiResource(struct SashimiResource * sr)
373 if(sr != NULL)
375 FreeSignal(sr->sr_OwnerSigBit);
377 /* Destroy the markers */
378 sr->sr_Cookie = 0;
379 sr->sr_PointsToCookie = NULL;
381 #if NO_ALLOCABS
382 FreeMem(sr,sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk));
383 #else
384 FreeMem(sr,sizeof(*sr) + sr->sr_FIFOTotalSize-1);
385 #endif
389 STATIC LONG
390 RemoveSashimiResource(struct SashimiResource * sr)
392 LONG error = OK;
394 if(sr != NULL)
396 Forbid();
398 /* Allow the resource to be removed only if
399 * there are no customers using it.
401 if(sr->sr_Library.lib_OpenCnt == 0)
402 RemResource(sr);
403 else
404 error = ERROR_OBJECT_IN_USE;
406 Permit();
409 return(error);
412 STATIC LONG
413 AddSashimiResource(ULONG bufferSize,struct SashimiResource ** resourcePtr)
415 struct SashimiResource * sr;
416 LONG error = OK;
418 /* We will do something really tricky; to increase our chances of
419 * allocating an old Sashimi buffer to be recovered, we allocate
420 * the amount of memory needed plus the size of a memory chunk.
421 * Then we release that buffer again and reallocate it with the
422 * size of the memory chunk trailing behind it.
425 Forbid();
427 sr = AllocMem(sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1,MEMF_ANY|MEMF_PUBLIC);
428 #if !NO_ALLOCABS
429 if(sr != NULL)
431 FreeMem(sr,sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1);
432 sr = AllocAbs(sizeof(*sr) + bufferSize-1,(BYTE *)sr + sizeof(struct MemChunk));
434 #endif
435 Permit();
437 if(sr != NULL)
439 struct timeval now;
441 GetSysTime(&now);
443 memset(sr,0,sizeof(*sr)-1);
445 sr->sr_Library.lib_Node.ln_Name = (char *)SashimiResourceName;
446 sr->sr_Library.lib_Node.ln_Type = NT_RESOURCE;
447 sr->sr_Owner = FindTask(NULL);
448 sr->sr_FIFOTotalSize = bufferSize;
449 sr->sr_Cookie = COOKIE;
450 sr->sr_PointsToCookie = &sr->sr_Cookie;
451 sr->sr_CreatedWhen = now.tv_secs;
453 sr->sr_OwnerSigBit = AllocSignal(-1);
454 if(sr->sr_OwnerSigBit != -1)
456 sr->sr_OwnerSigMask = (1UL << sr->sr_OwnerSigBit);
458 Forbid();
460 /* Do not add the resource if it has already been installed. */
461 if(OpenResource((STRPTR)SashimiResourceName) == NULL)
462 AddResource(sr);
463 else
464 error = ERROR_OBJECT_EXISTS;
466 Permit();
468 else
470 error = ERROR_NO_FREE_STORE;
473 else
475 error = ERROR_NO_FREE_STORE;
478 if(error != OK)
480 FreeSashimiResource(sr);
481 sr = NULL;
484 (*resourcePtr) = sr;
486 return(error);
489 /****************************************************************************/
491 STATIC VOID
492 CloseSashimiResource(struct SashimiResource * sr)
494 if(sr != NULL)
496 Forbid();
498 sr->sr_Library.lib_OpenCnt--;
500 Permit();
504 STATIC struct SashimiResource *
505 OpenSashimiResource(VOID)
507 struct SashimiResource * sr;
509 Forbid();
511 sr = OpenResource((STRPTR)SashimiResourceName);
512 if(sr != NULL)
513 sr->sr_Library.lib_OpenCnt++;
515 Permit();
517 return(sr);
520 /****************************************************************************/
522 STATIC LONG
523 SaveBuffer(const STRPTR name,struct SashimiResource * sr,LONG mode)
525 LONG error = OK;
526 STRPTR buffer;
528 /* We allocate a temporary buffer to store the circular
529 * buffer data in.
531 buffer = AllocVec(sr->sr_FIFOTotalSize,MEMF_ANY|MEMF_PUBLIC);
532 if(buffer != NULL)
534 LONG bytesInBuffer;
535 BOOL wrapped;
536 BOOL overrun;
537 BPTR file;
539 if(mode == MODE_Regular)
541 /* Stop interrupts and multitasking for a tick. */
542 Disable();
545 wrapped = sr->sr_FIFOWrapped;
546 overrun = sr->sr_FIFOOverrun;
548 if(wrapped)
550 LONG oldBytes = sr->sr_FIFOTotalSize - sr->sr_FIFOWriteIndex;
552 /* Unwrap the buffer; first copy the old data (following the
553 * write index) then the newer data.
555 memcpy(buffer,&sr->sr_FIFO[sr->sr_FIFOWriteIndex],oldBytes);
556 memcpy(&buffer[oldBytes],sr->sr_FIFO,sr->sr_FIFOWriteIndex);
558 bytesInBuffer = sr->sr_FIFOTotalSize;
560 else
562 memcpy(buffer,sr->sr_FIFO,sr->sr_FIFOWriteIndex);
564 bytesInBuffer = sr->sr_FIFOWriteIndex;
567 if(mode == MODE_Regular)
569 /* Start interrupts and multitasking again. */
570 Enable();
573 /* Write the buffer contents. */
574 file = Open((STRPTR)name,MODE_NEWFILE);
575 if(file != ZERO)
577 if(mode == MODE_Recovery)
579 if(FPrintf(file,"RECOVERY WARNING - Data may have been damaged\n") < 0)
580 error = IoErr();
583 if(error == OK && overrun)
585 if(FPrintf(file,"BUFFER WAS OVERRUN - Data may have been lost\n") < 0)
586 error = IoErr();
589 if(error == OK && wrapped)
591 if(FPrintf(file,"BUFFER WRAPPED - This is the most recent captured data\n\n") < 0)
592 error = IoErr();
595 /* FPrintf() is a buffered I/O routine, this is why we need to flush the
596 * output buffer here. Otherwise, it would be flushed after the Write()
597 * command below is finished and the file is closed. This is not what
598 * we want as that would have the effect of adding the messages above
599 * to the end of the file.
601 if(error == OK)
602 Flush(file);
604 if(error == OK)
606 if(Write(file,buffer,bytesInBuffer) != bytesInBuffer)
607 error = IoErr();
610 Close(file);
612 else
614 error = IoErr();
617 FreeVec(buffer);
619 else
621 error = ERROR_NO_FREE_STORE;
624 return(error);
627 /****************************************************************************/
629 STATIC BOOL
630 Recover(const STRPTR fileName)
632 struct SashimiResource * sr = NULL;
633 APTR allocated = NULL;
634 struct MemHeader * mh;
635 ULONG * start;
636 ULONG * end;
637 BOOL success;
639 Printf("Trying to recover old Sashimi buffer... ");
640 Flush(Output());
642 Forbid();
644 /* Scan the system memory list. */
645 for(mh = (struct MemHeader *)SysBase->MemList.lh_Head ;
646 mh->mh_Node.ln_Succ != NULL ;
647 mh = (struct MemHeader *)mh->mh_Node.ln_Succ)
649 start = (ULONG *)mh->mh_Lower;
650 end = (ULONG *)mh->mh_Upper;
654 /* First look for the cookie... */
655 if(start[0] == COOKIE)
657 /* Then look for the pointer back to it. */
658 if(start[1] == (ULONG)start)
660 /* Unless we don't have a resource pointer
661 * yet, compare the creation times and take
662 * only the latest buffer.
664 if(sr == NULL || start[2] > sr->sr_CreatedWhen)
665 sr = (struct SashimiResource *)((ULONG)start - offsetof(struct SashimiResource,sr_Cookie));
669 while(++start != end);
672 /* Try to allocate the memory the old buffer occupies. */
673 if(sr != NULL)
674 allocated = AllocAbs(sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk),(BYTE *)sr - sizeof(struct MemChunk));
676 Permit();
678 if(sr != NULL)
680 LONG error = OK;
681 LONG numBytes;
683 if(sr->sr_FIFOWrapped)
684 numBytes = sr->sr_FIFOTotalSize;
685 else
686 numBytes = sr->sr_FIFOWriteIndex;
688 Printf("found something (%ld bytes).\n",numBytes);
690 /* If there is anything worth saving, save it. */
691 if(numBytes > 0)
693 error = SaveBuffer(fileName,sr,MODE_Recovery);
694 if(error == OK)
695 Printf("Recovered Sashimi buffer saved as \"%s\".\n",fileName);
696 else
697 PrintFault(error,fileName);
699 else
701 Printf("This is not worth saving.\n");
704 /* If everything went fine so far and
705 * if we are the owner of the buffer,
706 * mark it as invalid.
708 if(error == OK && allocated != NULL)
710 sr->sr_Cookie = 0;
711 sr->sr_PointsToCookie = NULL;
714 success = TRUE;
716 else
718 Printf("sorry.\n");
720 success = FALSE;
723 /* Release the buffer... */
724 if(allocated != NULL)
725 FreeMem(allocated,sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk));
727 return(success);
730 /****************************************************************************/
733 main(int argc,char **argv)
735 int result = RETURN_FAIL;
737 /* Kickstart 2.04 and a Shell window are required. */
738 if(argc > 0)
740 struct RDArgs * rdargs;
742 rdargs = ReadArgs((STRPTR)ShellTemplate,(IPTR *)&ShellArguments,NULL);
743 if(rdargs != NULL)
745 /* Before anything else happens, check if
746 * we should recover any old data.
748 if(ShellArguments.Recover != NULL)
750 if(Recover(ShellArguments.Recover))
751 result = RETURN_OK;
752 else
753 result = RETURN_WARN;
755 else
757 struct SashimiResource * sr = NULL;
758 struct MsgPort * timePort;
759 struct timerequest * timeRequest = NULL;
760 BOOL added = FALSE;
761 BOOL opened = FALSE;
762 LONG error = OK;
763 BPTR oldOutput = ZERO;
764 BPTR newOutput = ZERO;
765 BPTR oldInput = ZERO;
766 BPTR newInput = ZERO;
767 struct MsgPort * oldConsoleTask = NULL;
768 STRPTR saveFile;
770 /* Fill in the save file name, we might need it later. */
771 if(ShellArguments.SaveAs != NULL)
772 saveFile = ShellArguments.SaveAs;
773 else
774 saveFile = "T:sashimi.out";
776 /* Set up the timer.device interface. */
777 timePort = CreateMsgPort();
778 if(timePort != NULL)
780 timeRequest = (struct timerequest *)CreateIORequest(timePort,sizeof(*timeRequest));
781 if(timeRequest != NULL)
783 if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)timeRequest,0) == OK)
784 TimerBase = timeRequest->tr_node.io_Device;
785 else
786 error = ERROR_NO_FREE_STORE; /* Misleading? */
788 else
790 error = ERROR_NO_FREE_STORE;
793 else
795 error = ERROR_NO_FREE_STORE;
798 if(error == OK)
800 /* Try to open the resource, and if that fails, create one. */
801 sr = OpenSashimiResource();
802 if(sr != NULL)
804 opened = TRUE;
806 else
808 ULONG bufferSize;
810 /* The default buffer size is 32K. */
811 bufferSize = 32 * 1024;
813 /* Check for a specific buffer size (power of two). */
814 if(ShellArguments.BufferK != NULL)
815 bufferSize = 1024 * (*ShellArguments.BufferK);
817 /* Check for a specific buffer size. */
818 if(ShellArguments.BufferSize != NULL)
819 bufferSize = (ULONG)(*ShellArguments.BufferSize);
821 /* Don't make the buffer too small. */
822 if(bufferSize < 4096)
823 bufferSize = 4096;
825 /* Add the resource to the public list. Note that
826 * the patches are not installed yet.
828 error = AddSashimiResource(bufferSize,&sr);
829 if(error == OK)
830 added = TRUE;
834 /* Did we get everything we wanted? */
835 if(error != OK)
837 PrintFault(error,"Sashimi");
838 result = RETURN_ERROR;
840 else
842 if(opened)
844 /* Save the current circular buffer contents? */
845 if(ShellArguments.SaveAs != NULL || ShellArguments.Save)
847 LONG error;
849 error = SaveBuffer(saveFile,sr,MODE_Regular);
850 if(error == OK)
851 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
852 else
853 PrintFault(error,saveFile);
856 /* Empty the circular buffer? */
857 if(ShellArguments.Empty)
859 EmptyFIFO(sr);
861 Printf("Sashimi buffer cleared.\n");
864 /* Turn off Sashimi? */
865 if(ShellArguments.Off)
867 struct Task * owner;
869 Forbid();
871 /* We cannot tell Sashimi to quit
872 * if there is a single customer
873 * left, such as us. This is why
874 * we close the resource and
875 * signal Sashimi to quit.
877 owner = sr->sr_Owner;
878 CloseSashimiResource(sr);
879 sr = NULL;
881 Signal(owner,SIGBREAKF_CTRL_C);
883 Permit();
887 if(added && NOT ShellArguments.Off)
889 ULONG signalsReceived,signalsToWaitFor;
890 BOOL done;
892 /* Open a console window? */
893 if(ShellArguments.Console)
895 STRPTR consoleWindow;
896 LONG error = OK;
898 if(ShellArguments.Window != NULL)
899 consoleWindow = ShellArguments.Window;
900 else
901 consoleWindow = "CON:0/20/640/100/Sashimi [Ctrl]+E=Empty [Ctrl]+F=File [Ctrl]+D=Reset console/AUTO/CLOSE/WAIT/INACTIVE";
903 /* Open the window and make it the default
904 * I/O stream.
906 #if 1
907 newInput = Open(consoleWindow,MODE_READWRITE);
908 #else
909 newInput = Open(consoleWindow,MODE_NEWFILE);
910 #endif
911 if(newInput != ZERO)
913 #if 1
914 oldInput = SelectInput(newInput);
915 oldOutput = SelectOutput(newInput);
916 #else
917 oldConsoleTask = SetConsoleTask(((struct FileHandle *)BADDR(newInput))->fh_Type);
918 newOutput = Open("CONSOLE:",MODE_OLDFILE);
919 if(newOutput != ZERO)
921 oldInput = SelectInput(newInput);
922 oldOutput = SelectOutput(newOutput);
924 else
926 error = IoErr();
928 /* Return to the original console task. */
929 SetConsoleTask(oldConsoleTask);
930 oldConsoleTask = NULL;
932 #endif
934 else
936 error = IoErr();
939 if(error != OK)
940 PrintFault(error,consoleWindow);
943 /* Show the banner message. */
944 if(NOT ShellArguments.NoPrompt && NOT ShellArguments.Quiet)
946 struct Process * cli = (struct Process *)FindTask(NULL);
947 LONG maxCli,thisCli = 1,i;
949 /* Find our current CLI process number. */
950 maxCli = MaxCli();
951 for(i = 1 ; i <= maxCli ; i++)
953 if(FindCliProc(i) == cli)
955 thisCli = i;
956 break;
960 Printf("Sashimi installed ([Ctrl]+C or \"Break %ld\" to remove)\n",thisCli);
963 GlobalSashimiResource = sr;
964 InstallPatches();
966 signalsToWaitFor = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D |
967 SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F |
968 sr->sr_OwnerSigMask;
970 /* Start the timer. */
971 if(ShellArguments.TimerOn)
973 signalsToWaitFor |= (1UL << timePort->mp_SigBit);
975 timeRequest->tr_node.io_Command = TR_ADDREQUEST;
976 timeRequest->tr_time.tv_secs = 0;
977 timeRequest->tr_time.tv_micro = MILLION / 10;
979 SendIO((struct IORequest *)timeRequest);
982 done = FALSE;
985 signalsReceived = Wait(signalsToWaitFor);
987 /* Check if we should test the buffer. */
988 if(ShellArguments.TimerOn)
990 if(signalsReceived & (1UL << timePort->mp_SigBit))
992 signalsReceived |= sr->sr_OwnerSigMask;
994 WaitIO((struct IORequest *)timeRequest);
996 /* Restart the timer. */
997 timeRequest->tr_node.io_Command = TR_ADDREQUEST;
998 timeRequest->tr_time.tv_secs = 0;
999 timeRequest->tr_time.tv_micro = MILLION / 10;
1001 SendIO((struct IORequest *)timeRequest);
1005 /* Check if we should test the buffer. */
1006 if(signalsReceived & sr->sr_OwnerSigMask)
1008 if(NOT ShellArguments.Quiet)
1010 UBYTE localBuffer[256];
1011 ULONG moreSignals;
1012 LONG filled;
1014 /* Try to empty the circular buffer. */
1015 while((filled = ReadFIFOChars(sr,localBuffer,sizeof(localBuffer))) > 0)
1017 /* Check if there is a message for us. */
1018 moreSignals = SetSignal(0,SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
1020 /* Save the circular buffer to a file? */
1021 if(moreSignals & SIGBREAKF_CTRL_F)
1023 LONG error;
1025 error = SaveBuffer(saveFile,sr,MODE_Regular);
1026 if(error == OK)
1027 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
1028 else
1029 PrintFault(error,saveFile);
1032 /* Empty the circular buffer? */
1033 if(moreSignals & SIGBREAKF_CTRL_E)
1035 EmptyFIFO(sr);
1037 Printf("Sashimi buffer cleared.\n");
1038 filled = 0;
1041 /* Stop Sashimi? */
1042 if(moreSignals & SIGBREAKF_CTRL_C)
1044 signalsReceived |= SIGBREAKF_CTRL_C;
1045 break;
1048 /* Write the buffer to the file. */
1049 if(filled > 0)
1050 Write(Output(),localBuffer,filled);
1055 /* Save current buffer to file. */
1056 if(signalsReceived & SIGBREAKF_CTRL_F)
1058 LONG error;
1060 error = SaveBuffer(saveFile,sr,MODE_Regular);
1061 if(error == OK)
1062 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
1063 else
1064 PrintFault(error,saveFile);
1067 /* Empty the buffer. */
1068 if(signalsReceived & SIGBREAKF_CTRL_E)
1070 EmptyFIFO(sr);
1072 Printf("Sashimi buffer cleared.\n");
1075 /* Reset the terminal. */
1076 if(signalsReceived & SIGBREAKF_CTRL_D)
1078 Printf("\033c");
1079 Flush(Output());
1082 /* Terminate the program. */
1083 if(signalsReceived & SIGBREAKF_CTRL_C)
1085 BOOL terminate = FALSE;
1087 if(ShellArguments.AskExit)
1089 UBYTE buffer[4];
1091 Printf("\nSashimi: stop signal received -- really exit (y or n)? ");
1092 Flush(Output());
1094 buffer[0] = '\0';
1096 if(FGets(Input(),buffer,sizeof(buffer)-1) != NULL)
1098 if(buffer[0] == 'y' || buffer[0] == 'Y')
1099 terminate = TRUE;
1102 else
1104 terminate = TRUE;
1107 if(terminate)
1109 if(RemoveSashimiResource(sr) == OK)
1111 Printf("Sashimi removed.\n");
1112 done = TRUE;
1117 while(NOT done);
1119 RemovePatches();
1121 /* Stop the timer. */
1122 if(ShellArguments.TimerOn)
1124 if(CheckIO((struct IORequest *)timeRequest) == BUSY)
1125 AbortIO((struct IORequest *)timeRequest);
1127 WaitIO((struct IORequest *)timeRequest);
1130 /* Check if we should and could save the circular buffer. */
1131 if(ShellArguments.AskSave && GetCharsInFIFO(sr) > 0)
1133 UBYTE name[256];
1135 Printf("Enter name to save the buffer, or hit [Return] to cancel: ");
1136 Flush(Output());
1138 name[0] = '\0';
1140 if(FGets(Input(),name,sizeof(name)-1) != NULL)
1142 LONG error;
1143 int i;
1145 for(i = strlen(name)-1 ; i >= 0 ; i--)
1147 if(name[i] == '\n')
1148 name[i] = '\0';
1151 error = SaveBuffer(name,sr,MODE_Regular);
1152 if(error == OK)
1153 Printf("Sashimi buffer saved as \"%s\".\n",name);
1154 else
1155 PrintFault(error,name);
1159 FreeSashimiResource(sr);
1160 sr = NULL;
1163 result = RETURN_OK;
1166 /* Close the resource, if we opened it. */
1167 if(opened)
1168 CloseSashimiResource(sr);
1170 /* Remove and free the resource if we added it. */
1171 if(added)
1173 RemoveSashimiResource(sr);
1174 FreeSashimiResource(sr);
1177 /* Clean up the timer.device interface. */
1178 if(timeRequest != NULL)
1180 if(timeRequest->tr_node.io_Device != NULL)
1181 CloseDevice((struct IORequest *)timeRequest);
1183 DeleteIORequest((struct IORequest *)timeRequest);
1186 DeleteMsgPort(timePort);
1188 /* Reset and clean up the console I/O streams. */
1189 if(oldOutput != ZERO)
1190 SelectOutput(oldOutput);
1192 if(oldInput != ZERO)
1193 SelectInput(oldInput);
1195 if(newOutput != ZERO)
1196 Close(newOutput);
1198 if(oldConsoleTask != NULL)
1199 SetConsoleTask(oldConsoleTask);
1201 if(newInput != ZERO)
1202 Close(newInput);
1205 FreeArgs(rdargs);
1207 else
1209 PrintFault(IoErr(),"Sashimi");
1211 result = RETURN_ERROR;
1215 return(result);