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 /****************************************************************************/
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 */
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
)
163 /* Nothing happens here */
168 AROS_LH0(LONG
, NewRawMayGetChar
,
169 struct ExecBase
*, SysBase
, 85, Exec
)
173 /* We always return sort of a confirmation. */
179 /****************************************************************************/
182 GetCharsInFIFO(struct SashimiResource
* sr
)
188 if(sr
->sr_FIFOWrapped
)
189 result
= sr
->sr_FIFOTotalSize
;
191 result
= sr
->sr_FIFOWriteIndex
;
199 EmptyFIFO(struct SashimiResource
* sr
)
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
;
213 ReadFIFOChars(struct SashimiResource
* sr
,UBYTE
* buffer
,LONG maxChars
)
219 if(sr
->sr_FIFOBytesStored
> 0)
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
);
241 sr
->sr_FIFOReadIndex
= (sr
->sr_FIFOReadIndex
+ howMany
) % sr
->sr_FIFOTotalSize
;
245 /* Subtract the number of characters we
248 sr
->sr_FIFOBytesStored
-= result
;
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
)
289 /* Do not store NUL bytes. */
292 STATIC ULONG Position
= 0;
296 /* Filter out extra <cr> characters. */
297 if(c
!= '\r' || Position
> 0)
299 struct SashimiResource
* sr
= GlobalSashimiResource
;
301 /* Store another byte in the buffer */
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')
322 /****************************************************************************/
329 /* We disable the interrupts because the raw I/O routines can
330 * be called from within interrupt code.
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
);
356 /* We disable the interrupts because the raw I/O routines can
357 * be called from within interrupt code.
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
));
368 /****************************************************************************/
371 FreeSashimiResource(struct SashimiResource
* sr
)
375 FreeSignal(sr
->sr_OwnerSigBit
);
377 /* Destroy the markers */
379 sr
->sr_PointsToCookie
= NULL
;
382 FreeMem(sr
,sizeof(*sr
) + sr
->sr_FIFOTotalSize
-1 + sizeof(struct MemChunk
));
384 FreeMem(sr
,sizeof(*sr
) + sr
->sr_FIFOTotalSize
-1);
390 RemoveSashimiResource(struct SashimiResource
* sr
)
398 /* Allow the resource to be removed only if
399 * there are no customers using it.
401 if(sr
->sr_Library
.lib_OpenCnt
== 0)
404 error
= ERROR_OBJECT_IN_USE
;
413 AddSashimiResource(ULONG bufferSize
,struct SashimiResource
** resourcePtr
)
415 struct SashimiResource
* sr
;
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.
427 sr
= AllocMem(sizeof(struct MemChunk
) + sizeof(*sr
) + bufferSize
-1,MEMF_ANY
|MEMF_PUBLIC
);
431 FreeMem(sr
,sizeof(struct MemChunk
) + sizeof(*sr
) + bufferSize
-1);
432 sr
= AllocAbs(sizeof(*sr
) + bufferSize
-1,(BYTE
*)sr
+ sizeof(struct MemChunk
));
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
);
460 /* Do not add the resource if it has already been installed. */
461 if(OpenResource((STRPTR
)SashimiResourceName
) == NULL
)
464 error
= ERROR_OBJECT_EXISTS
;
470 error
= ERROR_NO_FREE_STORE
;
475 error
= ERROR_NO_FREE_STORE
;
480 FreeSashimiResource(sr
);
489 /****************************************************************************/
492 CloseSashimiResource(struct SashimiResource
* sr
)
498 sr
->sr_Library
.lib_OpenCnt
--;
504 STATIC
struct SashimiResource
*
505 OpenSashimiResource(VOID
)
507 struct SashimiResource
* sr
;
511 sr
= OpenResource((STRPTR
)SashimiResourceName
);
513 sr
->sr_Library
.lib_OpenCnt
++;
520 /****************************************************************************/
523 SaveBuffer(const STRPTR name
,struct SashimiResource
* sr
,LONG mode
)
528 /* We allocate a temporary buffer to store the circular
531 buffer
= AllocVec(sr
->sr_FIFOTotalSize
,MEMF_ANY
|MEMF_PUBLIC
);
539 if(mode
== MODE_Regular
)
541 /* Stop interrupts and multitasking for a tick. */
545 wrapped
= sr
->sr_FIFOWrapped
;
546 overrun
= sr
->sr_FIFOOverrun
;
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
;
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. */
573 /* Write the buffer contents. */
574 file
= Open((STRPTR
)name
,MODE_NEWFILE
);
577 if(mode
== MODE_Recovery
)
579 if(FPrintf(file
,"RECOVERY WARNING - Data may have been damaged\n") < 0)
583 if(error
== OK
&& overrun
)
585 if(FPrintf(file
,"BUFFER WAS OVERRUN - Data may have been lost\n") < 0)
589 if(error
== OK
&& wrapped
)
591 if(FPrintf(file
,"BUFFER WRAPPED - This is the most recent captured data\n\n") < 0)
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.
606 if(Write(file
,buffer
,bytesInBuffer
) != bytesInBuffer
)
621 error
= ERROR_NO_FREE_STORE
;
627 /****************************************************************************/
630 Recover(const STRPTR fileName
)
632 struct SashimiResource
* sr
= NULL
;
633 APTR allocated
= NULL
;
634 struct MemHeader
* mh
;
639 Printf("Trying to recover old Sashimi buffer... ");
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. */
674 allocated
= AllocAbs(sizeof(*sr
) + sr
->sr_FIFOTotalSize
-1 + sizeof(struct MemChunk
),(BYTE
*)sr
- sizeof(struct MemChunk
));
683 if(sr
->sr_FIFOWrapped
)
684 numBytes
= sr
->sr_FIFOTotalSize
;
686 numBytes
= sr
->sr_FIFOWriteIndex
;
688 Printf("found something (%ld bytes).\n",numBytes
);
690 /* If there is anything worth saving, save it. */
693 error
= SaveBuffer(fileName
,sr
,MODE_Recovery
);
695 Printf("Recovered Sashimi buffer saved as \"%s\".\n",fileName
);
697 PrintFault(error
,fileName
);
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
)
711 sr
->sr_PointsToCookie
= NULL
;
723 /* Release the buffer... */
724 if(allocated
!= NULL
)
725 FreeMem(allocated
,sizeof(*sr
) + sr
->sr_FIFOTotalSize
-1 + sizeof(struct MemChunk
));
730 /****************************************************************************/
733 main(int argc
,char **argv
)
735 int result
= RETURN_FAIL
;
737 /* Kickstart 2.04 and a Shell window are required. */
740 struct RDArgs
* rdargs
;
742 rdargs
= ReadArgs((STRPTR
)ShellTemplate
,(IPTR
*)&ShellArguments
,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
))
753 result
= RETURN_WARN
;
757 struct SashimiResource
* sr
= NULL
;
758 struct MsgPort
* timePort
;
759 struct timerequest
* timeRequest
= NULL
;
763 BPTR oldOutput
= ZERO
;
764 BPTR newOutput
= ZERO
;
765 BPTR oldInput
= ZERO
;
766 BPTR newInput
= ZERO
;
767 struct MsgPort
* oldConsoleTask
= NULL
;
770 /* Fill in the save file name, we might need it later. */
771 if(ShellArguments
.SaveAs
!= NULL
)
772 saveFile
= ShellArguments
.SaveAs
;
774 saveFile
= "T:sashimi.out";
776 /* Set up the timer.device interface. */
777 timePort
= CreateMsgPort();
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
;
786 error
= ERROR_NO_FREE_STORE
; /* Misleading? */
790 error
= ERROR_NO_FREE_STORE
;
795 error
= ERROR_NO_FREE_STORE
;
800 /* Try to open the resource, and if that fails, create one. */
801 sr
= OpenSashimiResource();
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)
825 /* Add the resource to the public list. Note that
826 * the patches are not installed yet.
828 error
= AddSashimiResource(bufferSize
,&sr
);
834 /* Did we get everything we wanted? */
837 PrintFault(error
,"Sashimi");
838 result
= RETURN_ERROR
;
844 /* Save the current circular buffer contents? */
845 if(ShellArguments
.SaveAs
!= NULL
|| ShellArguments
.Save
)
849 error
= SaveBuffer(saveFile
,sr
,MODE_Regular
);
851 Printf("Sashimi buffer saved as \"%s\".\n",saveFile
);
853 PrintFault(error
,saveFile
);
856 /* Empty the circular buffer? */
857 if(ShellArguments
.Empty
)
861 Printf("Sashimi buffer cleared.\n");
864 /* Turn off Sashimi? */
865 if(ShellArguments
.Off
)
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
);
881 Signal(owner
,SIGBREAKF_CTRL_C
);
887 if(added
&& NOT ShellArguments
.Off
)
889 ULONG signalsReceived
,signalsToWaitFor
;
892 /* Open a console window? */
893 if(ShellArguments
.Console
)
895 STRPTR consoleWindow
;
898 if(ShellArguments
.Window
!= NULL
)
899 consoleWindow
= ShellArguments
.Window
;
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
907 newInput
= Open(consoleWindow
,MODE_READWRITE
);
909 newInput
= Open(consoleWindow
,MODE_NEWFILE
);
914 oldInput
= SelectInput(newInput
);
915 oldOutput
= SelectOutput(newInput
);
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
);
928 /* Return to the original console task. */
929 SetConsoleTask(oldConsoleTask
);
930 oldConsoleTask
= NULL
;
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. */
951 for(i
= 1 ; i
<= maxCli
; i
++)
953 if(FindCliProc(i
) == cli
)
960 Printf("Sashimi installed ([Ctrl]+C or \"Break %ld\" to remove)\n",thisCli
);
963 GlobalSashimiResource
= sr
;
966 signalsToWaitFor
= SIGBREAKF_CTRL_C
| SIGBREAKF_CTRL_D
|
967 SIGBREAKF_CTRL_E
| SIGBREAKF_CTRL_F
|
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
);
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];
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
)
1025 error
= SaveBuffer(saveFile
,sr
,MODE_Regular
);
1027 Printf("Sashimi buffer saved as \"%s\".\n",saveFile
);
1029 PrintFault(error
,saveFile
);
1032 /* Empty the circular buffer? */
1033 if(moreSignals
& SIGBREAKF_CTRL_E
)
1037 Printf("Sashimi buffer cleared.\n");
1042 if(moreSignals
& SIGBREAKF_CTRL_C
)
1044 signalsReceived
|= SIGBREAKF_CTRL_C
;
1048 /* Write the buffer to the file. */
1050 Write(Output(),localBuffer
,filled
);
1055 /* Save current buffer to file. */
1056 if(signalsReceived
& SIGBREAKF_CTRL_F
)
1060 error
= SaveBuffer(saveFile
,sr
,MODE_Regular
);
1062 Printf("Sashimi buffer saved as \"%s\".\n",saveFile
);
1064 PrintFault(error
,saveFile
);
1067 /* Empty the buffer. */
1068 if(signalsReceived
& SIGBREAKF_CTRL_E
)
1072 Printf("Sashimi buffer cleared.\n");
1075 /* Reset the terminal. */
1076 if(signalsReceived
& SIGBREAKF_CTRL_D
)
1082 /* Terminate the program. */
1083 if(signalsReceived
& SIGBREAKF_CTRL_C
)
1085 BOOL terminate
= FALSE
;
1087 if(ShellArguments
.AskExit
)
1091 Printf("\nSashimi: stop signal received -- really exit (y or n)? ");
1096 if(FGets(Input(),buffer
,sizeof(buffer
)-1) != NULL
)
1098 if(buffer
[0] == 'y' || buffer
[0] == 'Y')
1109 if(RemoveSashimiResource(sr
) == OK
)
1111 Printf("Sashimi removed.\n");
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)
1135 Printf("Enter name to save the buffer, or hit [Return] to cancel: ");
1140 if(FGets(Input(),name
,sizeof(name
)-1) != NULL
)
1145 for(i
= strlen(name
)-1 ; i
>= 0 ; i
--)
1151 error
= SaveBuffer(name
,sr
,MODE_Regular
);
1153 Printf("Sashimi buffer saved as \"%s\".\n",name
);
1155 PrintFault(error
,name
);
1159 FreeSashimiResource(sr
);
1166 /* Close the resource, if we opened it. */
1168 CloseSashimiResource(sr
);
1170 /* Remove and free the resource if we added it. */
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
)
1198 if(oldConsoleTask
!= NULL
)
1199 SetConsoleTask(oldConsoleTask
);
1201 if(newInput
!= ZERO
)
1209 PrintFault(IoErr(),"Sashimi");
1211 result
= RETURN_ERROR
;