4 * Sashimi -- intercepts raw serial debugging output on your own machine
6 * Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
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>
34 /****************************************************************************/
36 STRPTR Version
= "$VER: Sashimi 1.6 (20.6.1999)\r\n";
38 /****************************************************************************/
43 #define ZERO ((BPTR)0UL)
45 #define min(a,b) (((a) < (b)) ? (a) : (b))
49 /****************************************************************************/
57 /****************************************************************************/
59 #define MILLION 1000000
61 /****************************************************************************/
63 STATIC
struct Device
* TimerBase
;
65 /****************************************************************************/
68 typedef LONG
* NUMBER
;
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 */
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 */
93 STATIC
const STRPTR ShellTemplate
=
110 /****************************************************************************/
114 #define COOKIE 0x08021999569fd030ULL
116 #define COOKIE 0x08021999UL
119 struct SashimiResource
121 struct Library sr_Library
; /* Global link */
122 UWORD sr_Pad
; /* Long word alignment */
124 IPTR sr_Cookie
; /* Magic marker */
125 APTR sr_PointsToCookie
; /* Points back to cookie */
126 ULONG sr_CreatedWhen
; /* When exactly was this data structure created? */
128 struct Task
* sr_Owner
; /* Current owner of the patches */
130 ULONG sr_OwnerSigMask
; /* Signal mask to send when a new line is in the buffer. */
132 ULONG sr_FIFOTotalSize
; /* Number of bytes allocated for the buffer */
133 ULONG sr_FIFOReadIndex
; /* Read index counter */
134 ULONG sr_FIFOWriteIndex
; /* Write index counter */
135 ULONG sr_FIFOBytesStored
; /* Number of bytes in the FIFO */
136 BOOL sr_FIFOOverrun
; /* TRUE if the write index counter has
137 * overrun the read index counter.
139 BOOL sr_FIFOWrapped
; /* TRUE if the write index counter has
140 * wrapped around the circular buffer.
142 UBYTE sr_FIFO
[1]; /* The message buffer */
145 STATIC
const STRPTR SashimiResourceName
= "sashimi.resource";
146 STATIC
struct SashimiResource
* GlobalSashimiResource
;
148 /****************************************************************************/
150 #define LVORawIOInit (-84 * (WORD)LIB_VECTSIZE)
151 #define LVORawMayGetChar (-85 * (WORD)LIB_VECTSIZE)
152 #define LVORawPutChar (-86 * (WORD)LIB_VECTSIZE)
154 /****************************************************************************/
156 STATIC APTR OldRawIOInit
;
157 STATIC APTR OldRawMayGetChar
;
158 STATIC APTR OldRawPutChar
;
160 /****************************************************************************/
162 AROS_LH0(void, NewRawIOInit
,
163 struct ExecBase
*, SysBase
, 84, Exec
)
167 /* Nothing happens here */
172 AROS_LH0(LONG
, NewRawMayGetChar
,
173 struct ExecBase
*, SysBase
, 85, Exec
)
177 /* We always return sort of a confirmation. */
183 /****************************************************************************/
186 GetCharsInFIFO(struct SashimiResource
* sr
)
192 if(sr
->sr_FIFOWrapped
)
193 result
= sr
->sr_FIFOTotalSize
;
195 result
= sr
->sr_FIFOWriteIndex
;
203 EmptyFIFO(struct SashimiResource
* sr
)
207 sr
->sr_FIFOReadIndex
= 0;
208 sr
->sr_FIFOWriteIndex
= 0;
209 sr
->sr_FIFOBytesStored
= 0;
210 sr
->sr_FIFOOverrun
= FALSE
;
211 sr
->sr_FIFOWrapped
= FALSE
;
217 ReadFIFOChars(struct SashimiResource
* sr
,UBYTE
* buffer
,LONG maxChars
)
223 if(sr
->sr_FIFOBytesStored
> 0)
227 if(maxChars
> sr
->sr_FIFOBytesStored
)
228 maxChars
= sr
->sr_FIFOBytesStored
;
232 /* Find out how many characters can be read
233 * from the FIFO without overrunning the
234 * end of it. We don't read more than these
235 * few characters in one go.
237 howMany
= min(maxChars
,sr
->sr_FIFOTotalSize
- sr
->sr_FIFOReadIndex
);
239 memcpy(buffer
,&sr
->sr_FIFO
[sr
->sr_FIFOReadIndex
],howMany
);
245 sr
->sr_FIFOReadIndex
= (sr
->sr_FIFOReadIndex
+ howMany
) % sr
->sr_FIFOTotalSize
;
249 /* Subtract the number of characters we
252 sr
->sr_FIFOBytesStored
-= result
;
261 StoreFIFOChar(struct SashimiResource
* sr
,UBYTE c
)
263 sr
->sr_FIFO
[sr
->sr_FIFOWriteIndex
] = c
;
264 sr
->sr_FIFOWriteIndex
= (sr
->sr_FIFOWriteIndex
+ 1) % sr
->sr_FIFOTotalSize
;
266 /* If the buffer wraps around, remember it. */
267 if(sr
->sr_FIFOWriteIndex
== 0)
268 sr
->sr_FIFOWrapped
= TRUE
;
270 /* Check if the circular buffer was overrun */
271 sr
->sr_FIFOBytesStored
++;
272 if(sr
->sr_FIFOBytesStored
> sr
->sr_FIFOTotalSize
)
274 sr
->sr_FIFOOverrun
= TRUE
;
276 /* Move the read index to the same position as
277 * the write index and retain only as many
278 * bytes as would fit into the FIFO.
280 sr
->sr_FIFOReadIndex
= sr
->sr_FIFOWriteIndex
;
281 sr
->sr_FIFOBytesStored
= sr
->sr_FIFOTotalSize
;
285 /****************************************************************************/
287 AROS_LH1(void, NewRawPutChar
,
288 AROS_LHA(UBYTE
, c
, D0
),
289 struct ExecBase
*, SysBase
, 86, Exec
)
293 /* Do not store NUL bytes. */
296 STATIC ULONG Position
= 0;
300 /* Filter out extra <cr> characters. */
301 if(c
!= '\r' || Position
> 0)
303 struct SashimiResource
* sr
= GlobalSashimiResource
;
305 /* Store another byte in the buffer */
308 /* Notify Sashimi every time there is an end of line
309 * character in the stream.
311 if(c
== '\n' || c
== '\r')
312 Signal(sr
->sr_Owner
,sr
->sr_OwnerSigMask
);
315 if(c
== '\r' || c
== '\n')
326 /****************************************************************************/
333 /* We disable the interrupts because the raw I/O routines can
334 * be called from within interrupt code.
338 /* For every patch planted, remove it and check whether the code
339 * had been patched before. If it has, restore the patch. Note that
340 * this is not bullet proof :(
342 res
= SetFunction(&SysBase
->LibNode
,LVORawIOInit
,OldRawIOInit
);
343 if(res
!= AROS_SLIB_ENTRY(NewRawIOInit
,Exec
,84))
344 SetFunction(&SysBase
->LibNode
,LVORawIOInit
,res
);
346 res
= SetFunction(&SysBase
->LibNode
,LVORawMayGetChar
,OldRawMayGetChar
);
347 if(res
!= AROS_SLIB_ENTRY(NewRawMayGetChar
,Exec
,85))
348 SetFunction(&SysBase
->LibNode
,LVORawMayGetChar
,res
);
350 res
= SetFunction(&SysBase
->LibNode
,LVORawPutChar
,OldRawPutChar
);
351 if(res
!= AROS_SLIB_ENTRY(NewRawPutChar
,Exec
,86))
352 SetFunction(&SysBase
->LibNode
,LVORawPutChar
,res
);
354 /* make sure IO is re-inited
364 /* We disable the interrupts because the raw I/O routines can
365 * be called from within interrupt code.
369 OldRawIOInit
= SetFunction(&SysBase
->LibNode
,LVORawIOInit
, AROS_SLIB_ENTRY(NewRawIOInit
,Exec
,84));
370 OldRawMayGetChar
= SetFunction(&SysBase
->LibNode
,LVORawMayGetChar
, AROS_SLIB_ENTRY(NewRawMayGetChar
,Exec
,85));
371 OldRawPutChar
= SetFunction(&SysBase
->LibNode
,LVORawPutChar
, AROS_SLIB_ENTRY(NewRawPutChar
,Exec
,86));
376 /****************************************************************************/
379 FreeSashimiResource(struct SashimiResource
* sr
)
383 FreeSignal(sr
->sr_OwnerSigBit
);
385 /* Destroy the markers */
387 sr
->sr_PointsToCookie
= NULL
;
390 FreeMem(sr
,sizeof(*sr
) + sr
->sr_FIFOTotalSize
-1 + sizeof(struct MemChunk
));
392 FreeMem(sr
,sizeof(*sr
) + sr
->sr_FIFOTotalSize
-1);
398 RemoveSashimiResource(struct SashimiResource
* sr
)
406 /* Allow the resource to be removed only if
407 * there are no customers using it.
409 if(sr
->sr_Library
.lib_OpenCnt
== 0)
412 error
= ERROR_OBJECT_IN_USE
;
421 AddSashimiResource(ULONG bufferSize
,struct SashimiResource
** resourcePtr
)
423 struct SashimiResource
* sr
;
426 /* We will do something really tricky; to increase our chances of
427 * allocating an old Sashimi buffer to be recovered, we allocate
428 * the amount of memory needed plus the size of a memory chunk.
429 * Then we release that buffer again and reallocate it with the
430 * size of the memory chunk trailing behind it.
435 sr
= AllocMem(sizeof(struct MemChunk
) + sizeof(*sr
) + bufferSize
-1,MEMF_ANY
|MEMF_PUBLIC
);
439 FreeMem(sr
,sizeof(struct MemChunk
) + sizeof(*sr
) + bufferSize
-1);
440 sr
= AllocAbs(sizeof(*sr
) + bufferSize
-1,(BYTE
*)sr
+ sizeof(struct MemChunk
));
451 memset(sr
,0,sizeof(*sr
)-1);
453 sr
->sr_Library
.lib_Node
.ln_Name
= (char *)SashimiResourceName
;
454 sr
->sr_Library
.lib_Node
.ln_Type
= NT_RESOURCE
;
455 sr
->sr_Owner
= FindTask(NULL
);
456 sr
->sr_FIFOTotalSize
= bufferSize
;
457 sr
->sr_Cookie
= COOKIE
;
458 sr
->sr_PointsToCookie
= &sr
->sr_Cookie
;
459 sr
->sr_CreatedWhen
= now
.tv_secs
;
461 sr
->sr_OwnerSigBit
= AllocSignal(-1);
462 if(sr
->sr_OwnerSigBit
!= -1)
464 sr
->sr_OwnerSigMask
= (1UL << sr
->sr_OwnerSigBit
);
468 /* Do not add the resource if it has already been installed. */
469 if(OpenResource((STRPTR
)SashimiResourceName
) == NULL
)
472 error
= ERROR_OBJECT_EXISTS
;
478 error
= ERROR_NO_FREE_STORE
;
483 error
= ERROR_NO_FREE_STORE
;
488 FreeSashimiResource(sr
);
497 /****************************************************************************/
500 CloseSashimiResource(struct SashimiResource
* sr
)
506 sr
->sr_Library
.lib_OpenCnt
--;
512 STATIC
struct SashimiResource
*
513 OpenSashimiResource(VOID
)
515 struct SashimiResource
* sr
;
519 sr
= OpenResource((STRPTR
)SashimiResourceName
);
521 sr
->sr_Library
.lib_OpenCnt
++;
528 /****************************************************************************/
531 SaveBuffer(const STRPTR name
,struct SashimiResource
* sr
,LONG mode
)
536 /* We allocate a temporary buffer to store the circular
539 buffer
= AllocVec(sr
->sr_FIFOTotalSize
,MEMF_ANY
|MEMF_PUBLIC
);
547 if(mode
== MODE_Regular
)
549 /* Stop interrupts and multitasking for a tick. */
553 wrapped
= sr
->sr_FIFOWrapped
;
554 overrun
= sr
->sr_FIFOOverrun
;
558 LONG oldBytes
= sr
->sr_FIFOTotalSize
- sr
->sr_FIFOWriteIndex
;
560 /* Unwrap the buffer; first copy the old data (following the
561 * write index) then the newer data.
563 memcpy(buffer
,&sr
->sr_FIFO
[sr
->sr_FIFOWriteIndex
],oldBytes
);
564 memcpy(&buffer
[oldBytes
],sr
->sr_FIFO
,sr
->sr_FIFOWriteIndex
);
566 bytesInBuffer
= sr
->sr_FIFOTotalSize
;
570 memcpy(buffer
,sr
->sr_FIFO
,sr
->sr_FIFOWriteIndex
);
572 bytesInBuffer
= sr
->sr_FIFOWriteIndex
;
575 if(mode
== MODE_Regular
)
577 /* Start interrupts and multitasking again. */
581 /* Write the buffer contents. */
582 file
= Open((STRPTR
)name
,MODE_NEWFILE
);
585 if(mode
== MODE_Recovery
)
587 if(FPrintf(file
,"RECOVERY WARNING - Data may have been damaged\n") < 0)
591 if(error
== OK
&& overrun
)
593 if(FPrintf(file
,"BUFFER WAS OVERRUN - Data may have been lost\n") < 0)
597 if(error
== OK
&& wrapped
)
599 if(FPrintf(file
,"BUFFER WRAPPED - This is the most recent captured data\n\n") < 0)
603 /* FPrintf() is a buffered I/O routine, this is why we need to flush the
604 * output buffer here. Otherwise, it would be flushed after the Write()
605 * command below is finished and the file is closed. This is not what
606 * we want as that would have the effect of adding the messages above
607 * to the end of the file.
614 if(Write(file
,buffer
,bytesInBuffer
) != bytesInBuffer
)
629 error
= ERROR_NO_FREE_STORE
;
635 /****************************************************************************/
638 Recover(const STRPTR fileName
)
640 struct SashimiResource
* sr
= NULL
;
641 APTR allocated
= NULL
;
642 struct MemHeader
* mh
;
647 Printf("Trying to recover old Sashimi buffer... ");
652 /* Scan the system memory list. */
653 for(mh
= (struct MemHeader
*)SysBase
->MemList
.lh_Head
;
654 mh
->mh_Node
.ln_Succ
!= NULL
;
655 mh
= (struct MemHeader
*)mh
->mh_Node
.ln_Succ
)
657 start
= (IPTR
*)mh
->mh_Lower
;
658 end
= (IPTR
*)mh
->mh_Upper
;
662 /* First look for the cookie... */
663 if(start
[0] == COOKIE
)
665 /* Then look for the pointer back to it. */
666 if(start
[1] == (IPTR
)start
)
668 /* Unless we don't have a resource pointer
669 * yet, compare the creation times and take
670 * only the latest buffer.
672 if(sr
== NULL
|| start
[2] > sr
->sr_CreatedWhen
)
673 sr
= (struct SashimiResource
*)((IPTR
)start
- offsetof(struct SashimiResource
,sr_Cookie
));
677 while(++start
!= end
);
680 /* Try to allocate the memory the old buffer occupies. */
682 allocated
= AllocAbs(sizeof(*sr
) + sr
->sr_FIFOTotalSize
-1 + sizeof(struct MemChunk
),(BYTE
*)sr
- sizeof(struct MemChunk
));
691 if(sr
->sr_FIFOWrapped
)
692 numBytes
= sr
->sr_FIFOTotalSize
;
694 numBytes
= sr
->sr_FIFOWriteIndex
;
696 Printf("found something (%ld bytes).\n",numBytes
);
698 /* If there is anything worth saving, save it. */
701 error
= SaveBuffer(fileName
,sr
,MODE_Recovery
);
703 Printf("Recovered Sashimi buffer saved as \"%s\".\n",fileName
);
705 PrintFault(error
,fileName
);
709 Printf("This is not worth saving.\n");
712 /* If everything went fine so far and
713 * if we are the owner of the buffer,
714 * mark it as invalid.
716 if(error
== OK
&& allocated
!= NULL
)
719 sr
->sr_PointsToCookie
= NULL
;
731 /* Release the buffer... */
732 if(allocated
!= NULL
)
733 FreeMem(allocated
,sizeof(*sr
) + sr
->sr_FIFOTotalSize
-1 + sizeof(struct MemChunk
));
738 /****************************************************************************/
741 main(int argc
,char **argv
)
743 int result
= RETURN_FAIL
;
745 /* Kickstart 2.04 and a Shell window are required. */
748 struct RDArgs
* rdargs
;
750 rdargs
= ReadArgs((STRPTR
)ShellTemplate
,(IPTR
*)&ShellArguments
,NULL
);
753 /* Before anything else happens, check if
754 * we should recover any old data.
756 if(ShellArguments
.Recover
!= NULL
)
758 if(Recover(ShellArguments
.Recover
))
761 result
= RETURN_WARN
;
765 struct SashimiResource
* sr
= NULL
;
766 struct MsgPort
* timePort
;
767 struct timerequest
* timeRequest
= NULL
;
771 BPTR oldOutput
= ZERO
;
772 BPTR newOutput
= ZERO
;
773 BPTR oldInput
= ZERO
;
774 BPTR newInput
= ZERO
;
775 struct MsgPort
* oldConsoleTask
= NULL
;
778 /* Fill in the save file name, we might need it later. */
779 if(ShellArguments
.SaveAs
!= NULL
)
780 saveFile
= ShellArguments
.SaveAs
;
782 saveFile
= "T:sashimi.out";
784 /* Set up the timer.device interface. */
785 timePort
= CreateMsgPort();
788 timeRequest
= (struct timerequest
*)CreateIORequest(timePort
,sizeof(*timeRequest
));
789 if(timeRequest
!= NULL
)
791 if(OpenDevice(TIMERNAME
,UNIT_VBLANK
,(struct IORequest
*)timeRequest
,0) == OK
)
792 TimerBase
= timeRequest
->tr_node
.io_Device
;
794 error
= ERROR_NO_FREE_STORE
; /* Misleading? */
798 error
= ERROR_NO_FREE_STORE
;
803 error
= ERROR_NO_FREE_STORE
;
808 /* Try to open the resource, and if that fails, create one. */
809 sr
= OpenSashimiResource();
818 /* The default buffer size is 32K. */
819 bufferSize
= 32 * 1024;
821 /* Check for a specific buffer size (power of two). */
822 if(ShellArguments
.BufferK
!= NULL
)
823 bufferSize
= 1024 * (*ShellArguments
.BufferK
);
825 /* Check for a specific buffer size. */
826 if(ShellArguments
.BufferSize
!= NULL
)
827 bufferSize
= (ULONG
)(*ShellArguments
.BufferSize
);
829 /* Don't make the buffer too small. */
830 if(bufferSize
< 4096)
833 /* Add the resource to the public list. Note that
834 * the patches are not installed yet.
836 error
= AddSashimiResource(bufferSize
,&sr
);
842 /* Did we get everything we wanted? */
845 PrintFault(error
,"Sashimi");
846 result
= RETURN_ERROR
;
852 /* Save the current circular buffer contents? */
853 if(ShellArguments
.SaveAs
!= NULL
|| ShellArguments
.Save
)
857 error
= SaveBuffer(saveFile
,sr
,MODE_Regular
);
859 Printf("Sashimi buffer saved as \"%s\".\n",saveFile
);
861 PrintFault(error
,saveFile
);
864 /* Empty the circular buffer? */
865 if(ShellArguments
.Empty
)
869 Printf("Sashimi buffer cleared.\n");
872 /* Turn off Sashimi? */
873 if(ShellArguments
.Off
)
879 /* We cannot tell Sashimi to quit
880 * if there is a single customer
881 * left, such as us. This is why
882 * we close the resource and
883 * signal Sashimi to quit.
885 owner
= sr
->sr_Owner
;
886 CloseSashimiResource(sr
);
889 Signal(owner
,SIGBREAKF_CTRL_C
);
895 if(added
&& NOT ShellArguments
.Off
)
897 ULONG signalsReceived
,signalsToWaitFor
;
900 /* Open a console window? */
901 if(ShellArguments
.Console
)
903 STRPTR consoleWindow
;
906 if(ShellArguments
.Window
!= NULL
)
907 consoleWindow
= ShellArguments
.Window
;
909 consoleWindow
= "CON:0/20/640/100/Sashimi [Ctrl]+E=Empty [Ctrl]+F=File [Ctrl]+D=Reset console/AUTO/CLOSE/WAIT/INACTIVE";
911 /* Open the window and make it the default
915 newInput
= Open(consoleWindow
,MODE_READWRITE
);
917 newInput
= Open(consoleWindow
,MODE_NEWFILE
);
922 oldInput
= SelectInput(newInput
);
923 oldOutput
= SelectOutput(newInput
);
925 oldConsoleTask
= SetConsoleTask(((struct FileHandle
*)BADDR(newInput
))->fh_Type
);
926 newOutput
= Open("CONSOLE:",MODE_OLDFILE
);
927 if(newOutput
!= ZERO
)
929 oldInput
= SelectInput(newInput
);
930 oldOutput
= SelectOutput(newOutput
);
936 /* Return to the original console task. */
937 SetConsoleTask(oldConsoleTask
);
938 oldConsoleTask
= NULL
;
948 PrintFault(error
,consoleWindow
);
951 /* Show the banner message. */
952 if(NOT ShellArguments
.NoPrompt
&& NOT ShellArguments
.Quiet
)
954 struct Process
* cli
= (struct Process
*)FindTask(NULL
);
955 LONG maxCli
,thisCli
= 1,i
;
957 /* Find our current CLI process number. */
959 for(i
= 1 ; i
<= maxCli
; i
++)
961 if(FindCliProc(i
) == cli
)
968 Printf("Sashimi installed ([Ctrl]+C or \"Break %ld\" to remove)\n",thisCli
);
971 GlobalSashimiResource
= sr
;
974 signalsToWaitFor
= SIGBREAKF_CTRL_C
| SIGBREAKF_CTRL_D
|
975 SIGBREAKF_CTRL_E
| SIGBREAKF_CTRL_F
|
978 /* Start the timer. */
979 if(ShellArguments
.TimerOn
)
981 signalsToWaitFor
|= (1UL << timePort
->mp_SigBit
);
983 timeRequest
->tr_node
.io_Command
= TR_ADDREQUEST
;
984 timeRequest
->tr_time
.tv_secs
= 0;
985 timeRequest
->tr_time
.tv_micro
= MILLION
/ 10;
987 SendIO((struct IORequest
*)timeRequest
);
993 signalsReceived
= Wait(signalsToWaitFor
);
995 /* Check if we should test the buffer. */
996 if(ShellArguments
.TimerOn
)
998 if(signalsReceived
& (1UL << timePort
->mp_SigBit
))
1000 signalsReceived
|= sr
->sr_OwnerSigMask
;
1002 WaitIO((struct IORequest
*)timeRequest
);
1004 /* Restart the timer. */
1005 timeRequest
->tr_node
.io_Command
= TR_ADDREQUEST
;
1006 timeRequest
->tr_time
.tv_secs
= 0;
1007 timeRequest
->tr_time
.tv_micro
= MILLION
/ 10;
1009 SendIO((struct IORequest
*)timeRequest
);
1013 /* Check if we should test the buffer. */
1014 if(signalsReceived
& sr
->sr_OwnerSigMask
)
1016 if(NOT ShellArguments
.Quiet
)
1018 UBYTE localBuffer
[256];
1022 /* Try to empty the circular buffer. */
1023 while((filled
= ReadFIFOChars(sr
,localBuffer
,sizeof(localBuffer
))) > 0)
1025 /* Check if there is a message for us. */
1026 moreSignals
= SetSignal(0,SIGBREAKF_CTRL_C
|SIGBREAKF_CTRL_E
|SIGBREAKF_CTRL_F
);
1028 /* Save the circular buffer to a file? */
1029 if(moreSignals
& SIGBREAKF_CTRL_F
)
1033 error
= SaveBuffer(saveFile
,sr
,MODE_Regular
);
1035 Printf("Sashimi buffer saved as \"%s\".\n",saveFile
);
1037 PrintFault(error
,saveFile
);
1040 /* Empty the circular buffer? */
1041 if(moreSignals
& SIGBREAKF_CTRL_E
)
1045 Printf("Sashimi buffer cleared.\n");
1050 if(moreSignals
& SIGBREAKF_CTRL_C
)
1052 signalsReceived
|= SIGBREAKF_CTRL_C
;
1056 /* Write the buffer to the file. */
1058 Write(Output(),localBuffer
,filled
);
1063 /* Save current buffer to file. */
1064 if(signalsReceived
& SIGBREAKF_CTRL_F
)
1068 error
= SaveBuffer(saveFile
,sr
,MODE_Regular
);
1070 Printf("Sashimi buffer saved as \"%s\".\n",saveFile
);
1072 PrintFault(error
,saveFile
);
1075 /* Empty the buffer. */
1076 if(signalsReceived
& SIGBREAKF_CTRL_E
)
1080 Printf("Sashimi buffer cleared.\n");
1083 /* Reset the terminal. */
1084 if(signalsReceived
& SIGBREAKF_CTRL_D
)
1090 /* Terminate the program. */
1091 if(signalsReceived
& SIGBREAKF_CTRL_C
)
1093 BOOL terminate
= FALSE
;
1095 if(ShellArguments
.AskExit
)
1099 Printf("\nSashimi: stop signal received -- really exit (y or n)? ");
1104 if(FGets(Input(),buffer
,sizeof(buffer
)-1) != NULL
)
1106 if(buffer
[0] == 'y' || buffer
[0] == 'Y')
1117 if(RemoveSashimiResource(sr
) == OK
)
1119 Printf("Sashimi removed.\n");
1129 /* Stop the timer. */
1130 if(ShellArguments
.TimerOn
)
1132 if(CheckIO((struct IORequest
*)timeRequest
) == BUSY
)
1133 AbortIO((struct IORequest
*)timeRequest
);
1135 WaitIO((struct IORequest
*)timeRequest
);
1138 /* Check if we should and could save the circular buffer. */
1139 if(ShellArguments
.AskSave
&& GetCharsInFIFO(sr
) > 0)
1143 Printf("Enter name to save the buffer, or hit [Return] to cancel: ");
1148 if(FGets(Input(),name
,sizeof(name
)-1) != NULL
)
1153 for(i
= strlen(name
)-1 ; i
>= 0 ; i
--)
1159 error
= SaveBuffer(name
,sr
,MODE_Regular
);
1161 Printf("Sashimi buffer saved as \"%s\".\n",name
);
1163 PrintFault(error
,name
);
1167 FreeSashimiResource(sr
);
1174 /* Close the resource, if we opened it. */
1176 CloseSashimiResource(sr
);
1178 /* Remove and free the resource if we added it. */
1181 RemoveSashimiResource(sr
);
1182 FreeSashimiResource(sr
);
1185 /* Clean up the timer.device interface. */
1186 if(timeRequest
!= NULL
)
1188 if(timeRequest
->tr_node
.io_Device
!= NULL
)
1189 CloseDevice((struct IORequest
*)timeRequest
);
1191 DeleteIORequest((struct IORequest
*)timeRequest
);
1194 DeleteMsgPort(timePort
);
1196 /* Reset and clean up the console I/O streams. */
1197 if(oldOutput
!= ZERO
)
1198 SelectOutput(oldOutput
);
1200 if(oldInput
!= ZERO
)
1201 SelectInput(oldInput
);
1203 if(newOutput
!= ZERO
)
1206 if(oldConsoleTask
!= NULL
)
1207 SetConsoleTask(oldConsoleTask
);
1209 if(newInput
!= ZERO
)
1217 PrintFault(IoErr(),"Sashimi");
1219 result
= RETURN_ERROR
;