grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / tools / debug / sashimi / sashimi.c
blob836a9ceea2f5491a21ab886b7bf65b34ac9cb733
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 #if __WORDSIZE == 64
114 #define COOKIE 0x08021999569fd030ULL
115 #else
116 #define COOKIE 0x08021999UL
117 #endif
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 */
129 LONG sr_OwnerSigBit;
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)
165 AROS_LIBFUNC_INIT
167 /* Nothing happens here */
169 AROS_LIBFUNC_EXIT
172 AROS_LH0(LONG, NewRawMayGetChar,
173 struct ExecBase *, SysBase, 85, Exec)
175 AROS_LIBFUNC_INIT
177 /* We always return sort of a confirmation. */
178 return('y');
180 AROS_LIBFUNC_EXIT
183 /****************************************************************************/
185 STATIC LONG
186 GetCharsInFIFO(struct SashimiResource * sr)
188 LONG result;
190 Disable();
192 if(sr->sr_FIFOWrapped)
193 result = sr->sr_FIFOTotalSize;
194 else
195 result = sr->sr_FIFOWriteIndex;
197 Enable();
199 return(result);
202 STATIC VOID
203 EmptyFIFO(struct SashimiResource * sr)
205 Disable();
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;
213 Enable();
216 STATIC LONG
217 ReadFIFOChars(struct SashimiResource * sr,UBYTE * buffer,LONG maxChars)
219 LONG result = 0;
221 Disable();
223 if(sr->sr_FIFOBytesStored > 0)
225 LONG howMany;
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);
241 result += howMany;
242 buffer += howMany;
243 maxChars -= howMany;
245 sr->sr_FIFOReadIndex = (sr->sr_FIFOReadIndex + howMany) % sr->sr_FIFOTotalSize;
247 while(maxChars > 0);
249 /* Subtract the number of characters we
250 * read in the loop.
252 sr->sr_FIFOBytesStored -= result;
255 Enable();
257 return(result);
260 STATIC VOID
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)
291 AROS_LIBFUNC_INIT
293 /* Do not store NUL bytes. */
294 if(c != '\0')
296 STATIC ULONG Position = 0;
298 Disable();
300 /* Filter out extra <cr> characters. */
301 if(c != '\r' || Position > 0)
303 struct SashimiResource * sr = GlobalSashimiResource;
305 /* Store another byte in the buffer */
306 StoreFIFOChar(sr,c);
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')
316 Position = 0;
317 else
318 Position++;
320 Enable();
323 AROS_LIBFUNC_EXIT
326 /****************************************************************************/
328 STATIC VOID
329 RemovePatches(VOID)
331 APTR res;
333 /* We disable the interrupts because the raw I/O routines can
334 * be called from within interrupt code.
336 Disable();
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
356 RawIOInit();
358 Enable();
361 STATIC VOID
362 InstallPatches(VOID)
364 /* We disable the interrupts because the raw I/O routines can
365 * be called from within interrupt code.
367 Disable();
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));
373 Enable();
376 /****************************************************************************/
378 STATIC VOID
379 FreeSashimiResource(struct SashimiResource * sr)
381 if(sr != NULL)
383 FreeSignal(sr->sr_OwnerSigBit);
385 /* Destroy the markers */
386 sr->sr_Cookie = 0;
387 sr->sr_PointsToCookie = NULL;
389 #if NO_ALLOCABS
390 FreeMem(sr,sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk));
391 #else
392 FreeMem(sr,sizeof(*sr) + sr->sr_FIFOTotalSize-1);
393 #endif
397 STATIC LONG
398 RemoveSashimiResource(struct SashimiResource * sr)
400 LONG error = OK;
402 if(sr != NULL)
404 Forbid();
406 /* Allow the resource to be removed only if
407 * there are no customers using it.
409 if(sr->sr_Library.lib_OpenCnt == 0)
410 RemResource(sr);
411 else
412 error = ERROR_OBJECT_IN_USE;
414 Permit();
417 return(error);
420 STATIC LONG
421 AddSashimiResource(ULONG bufferSize,struct SashimiResource ** resourcePtr)
423 struct SashimiResource * sr;
424 LONG error = OK;
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.
433 Forbid();
435 sr = AllocMem(sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1,MEMF_ANY|MEMF_PUBLIC);
436 #if !NO_ALLOCABS
437 if(sr != NULL)
439 FreeMem(sr,sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1);
440 sr = AllocAbs(sizeof(*sr) + bufferSize-1,(BYTE *)sr + sizeof(struct MemChunk));
442 #endif
443 Permit();
445 if(sr != NULL)
447 struct timeval now;
449 GetSysTime(&now);
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);
466 Forbid();
468 /* Do not add the resource if it has already been installed. */
469 if(OpenResource((STRPTR)SashimiResourceName) == NULL)
470 AddResource(sr);
471 else
472 error = ERROR_OBJECT_EXISTS;
474 Permit();
476 else
478 error = ERROR_NO_FREE_STORE;
481 else
483 error = ERROR_NO_FREE_STORE;
486 if(error != OK)
488 FreeSashimiResource(sr);
489 sr = NULL;
492 (*resourcePtr) = sr;
494 return(error);
497 /****************************************************************************/
499 STATIC VOID
500 CloseSashimiResource(struct SashimiResource * sr)
502 if(sr != NULL)
504 Forbid();
506 sr->sr_Library.lib_OpenCnt--;
508 Permit();
512 STATIC struct SashimiResource *
513 OpenSashimiResource(VOID)
515 struct SashimiResource * sr;
517 Forbid();
519 sr = OpenResource((STRPTR)SashimiResourceName);
520 if(sr != NULL)
521 sr->sr_Library.lib_OpenCnt++;
523 Permit();
525 return(sr);
528 /****************************************************************************/
530 STATIC LONG
531 SaveBuffer(const STRPTR name,struct SashimiResource * sr,LONG mode)
533 LONG error = OK;
534 STRPTR buffer;
536 /* We allocate a temporary buffer to store the circular
537 * buffer data in.
539 buffer = AllocVec(sr->sr_FIFOTotalSize,MEMF_ANY|MEMF_PUBLIC);
540 if(buffer != NULL)
542 LONG bytesInBuffer;
543 BOOL wrapped;
544 BOOL overrun;
545 BPTR file;
547 if(mode == MODE_Regular)
549 /* Stop interrupts and multitasking for a tick. */
550 Disable();
553 wrapped = sr->sr_FIFOWrapped;
554 overrun = sr->sr_FIFOOverrun;
556 if(wrapped)
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;
568 else
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. */
578 Enable();
581 /* Write the buffer contents. */
582 file = Open((STRPTR)name,MODE_NEWFILE);
583 if(file != ZERO)
585 if(mode == MODE_Recovery)
587 if(FPrintf(file,"RECOVERY WARNING - Data may have been damaged\n") < 0)
588 error = IoErr();
591 if(error == OK && overrun)
593 if(FPrintf(file,"BUFFER WAS OVERRUN - Data may have been lost\n") < 0)
594 error = IoErr();
597 if(error == OK && wrapped)
599 if(FPrintf(file,"BUFFER WRAPPED - This is the most recent captured data\n\n") < 0)
600 error = IoErr();
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.
609 if(error == OK)
610 Flush(file);
612 if(error == OK)
614 if(Write(file,buffer,bytesInBuffer) != bytesInBuffer)
615 error = IoErr();
618 Close(file);
620 else
622 error = IoErr();
625 FreeVec(buffer);
627 else
629 error = ERROR_NO_FREE_STORE;
632 return(error);
635 /****************************************************************************/
637 STATIC BOOL
638 Recover(const STRPTR fileName)
640 struct SashimiResource * sr = NULL;
641 APTR allocated = NULL;
642 struct MemHeader * mh;
643 IPTR * start;
644 IPTR * end;
645 BOOL success;
647 Printf("Trying to recover old Sashimi buffer... ");
648 Flush(Output());
650 Forbid();
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. */
681 if(sr != NULL)
682 allocated = AllocAbs(sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk),(BYTE *)sr - sizeof(struct MemChunk));
684 Permit();
686 if(sr != NULL)
688 LONG error = OK;
689 LONG numBytes;
691 if(sr->sr_FIFOWrapped)
692 numBytes = sr->sr_FIFOTotalSize;
693 else
694 numBytes = sr->sr_FIFOWriteIndex;
696 Printf("found something (%ld bytes).\n",numBytes);
698 /* If there is anything worth saving, save it. */
699 if(numBytes > 0)
701 error = SaveBuffer(fileName,sr,MODE_Recovery);
702 if(error == OK)
703 Printf("Recovered Sashimi buffer saved as \"%s\".\n",fileName);
704 else
705 PrintFault(error,fileName);
707 else
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)
718 sr->sr_Cookie = 0;
719 sr->sr_PointsToCookie = NULL;
722 success = TRUE;
724 else
726 Printf("sorry.\n");
728 success = FALSE;
731 /* Release the buffer... */
732 if(allocated != NULL)
733 FreeMem(allocated,sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk));
735 return(success);
738 /****************************************************************************/
741 main(int argc,char **argv)
743 int result = RETURN_FAIL;
745 /* Kickstart 2.04 and a Shell window are required. */
746 if(argc > 0)
748 struct RDArgs * rdargs;
750 rdargs = ReadArgs((STRPTR)ShellTemplate,(IPTR *)&ShellArguments,NULL);
751 if(rdargs != 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))
759 result = RETURN_OK;
760 else
761 result = RETURN_WARN;
763 else
765 struct SashimiResource * sr = NULL;
766 struct MsgPort * timePort;
767 struct timerequest * timeRequest = NULL;
768 BOOL added = FALSE;
769 BOOL opened = FALSE;
770 LONG error = OK;
771 BPTR oldOutput = ZERO;
772 BPTR newOutput = ZERO;
773 BPTR oldInput = ZERO;
774 BPTR newInput = ZERO;
775 struct MsgPort * oldConsoleTask = NULL;
776 STRPTR saveFile;
778 /* Fill in the save file name, we might need it later. */
779 if(ShellArguments.SaveAs != NULL)
780 saveFile = ShellArguments.SaveAs;
781 else
782 saveFile = "T:sashimi.out";
784 /* Set up the timer.device interface. */
785 timePort = CreateMsgPort();
786 if(timePort != NULL)
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;
793 else
794 error = ERROR_NO_FREE_STORE; /* Misleading? */
796 else
798 error = ERROR_NO_FREE_STORE;
801 else
803 error = ERROR_NO_FREE_STORE;
806 if(error == OK)
808 /* Try to open the resource, and if that fails, create one. */
809 sr = OpenSashimiResource();
810 if(sr != NULL)
812 opened = TRUE;
814 else
816 ULONG bufferSize;
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)
831 bufferSize = 4096;
833 /* Add the resource to the public list. Note that
834 * the patches are not installed yet.
836 error = AddSashimiResource(bufferSize,&sr);
837 if(error == OK)
838 added = TRUE;
842 /* Did we get everything we wanted? */
843 if(error != OK)
845 PrintFault(error,"Sashimi");
846 result = RETURN_ERROR;
848 else
850 if(opened)
852 /* Save the current circular buffer contents? */
853 if(ShellArguments.SaveAs != NULL || ShellArguments.Save)
855 LONG error;
857 error = SaveBuffer(saveFile,sr,MODE_Regular);
858 if(error == OK)
859 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
860 else
861 PrintFault(error,saveFile);
864 /* Empty the circular buffer? */
865 if(ShellArguments.Empty)
867 EmptyFIFO(sr);
869 Printf("Sashimi buffer cleared.\n");
872 /* Turn off Sashimi? */
873 if(ShellArguments.Off)
875 struct Task * owner;
877 Forbid();
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);
887 sr = NULL;
889 Signal(owner,SIGBREAKF_CTRL_C);
891 Permit();
895 if(added && NOT ShellArguments.Off)
897 ULONG signalsReceived,signalsToWaitFor;
898 BOOL done;
900 /* Open a console window? */
901 if(ShellArguments.Console)
903 STRPTR consoleWindow;
904 LONG error = OK;
906 if(ShellArguments.Window != NULL)
907 consoleWindow = ShellArguments.Window;
908 else
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
912 * I/O stream.
914 #if 1
915 newInput = Open(consoleWindow,MODE_READWRITE);
916 #else
917 newInput = Open(consoleWindow,MODE_NEWFILE);
918 #endif
919 if(newInput != ZERO)
921 #if 1
922 oldInput = SelectInput(newInput);
923 oldOutput = SelectOutput(newInput);
924 #else
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);
932 else
934 error = IoErr();
936 /* Return to the original console task. */
937 SetConsoleTask(oldConsoleTask);
938 oldConsoleTask = NULL;
940 #endif
942 else
944 error = IoErr();
947 if(error != OK)
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. */
958 maxCli = MaxCli();
959 for(i = 1 ; i <= maxCli ; i++)
961 if(FindCliProc(i) == cli)
963 thisCli = i;
964 break;
968 Printf("Sashimi installed ([Ctrl]+C or \"Break %ld\" to remove)\n",thisCli);
971 GlobalSashimiResource = sr;
972 InstallPatches();
974 signalsToWaitFor = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D |
975 SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F |
976 sr->sr_OwnerSigMask;
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);
990 done = FALSE;
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];
1019 ULONG moreSignals;
1020 LONG filled;
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)
1031 LONG error;
1033 error = SaveBuffer(saveFile,sr,MODE_Regular);
1034 if(error == OK)
1035 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
1036 else
1037 PrintFault(error,saveFile);
1040 /* Empty the circular buffer? */
1041 if(moreSignals & SIGBREAKF_CTRL_E)
1043 EmptyFIFO(sr);
1045 Printf("Sashimi buffer cleared.\n");
1046 filled = 0;
1049 /* Stop Sashimi? */
1050 if(moreSignals & SIGBREAKF_CTRL_C)
1052 signalsReceived |= SIGBREAKF_CTRL_C;
1053 break;
1056 /* Write the buffer to the file. */
1057 if(filled > 0)
1058 Write(Output(),localBuffer,filled);
1063 /* Save current buffer to file. */
1064 if(signalsReceived & SIGBREAKF_CTRL_F)
1066 LONG error;
1068 error = SaveBuffer(saveFile,sr,MODE_Regular);
1069 if(error == OK)
1070 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
1071 else
1072 PrintFault(error,saveFile);
1075 /* Empty the buffer. */
1076 if(signalsReceived & SIGBREAKF_CTRL_E)
1078 EmptyFIFO(sr);
1080 Printf("Sashimi buffer cleared.\n");
1083 /* Reset the terminal. */
1084 if(signalsReceived & SIGBREAKF_CTRL_D)
1086 Printf("\033c");
1087 Flush(Output());
1090 /* Terminate the program. */
1091 if(signalsReceived & SIGBREAKF_CTRL_C)
1093 BOOL terminate = FALSE;
1095 if(ShellArguments.AskExit)
1097 UBYTE buffer[4];
1099 Printf("\nSashimi: stop signal received -- really exit (y or n)? ");
1100 Flush(Output());
1102 buffer[0] = '\0';
1104 if(FGets(Input(),buffer,sizeof(buffer)-1) != NULL)
1106 if(buffer[0] == 'y' || buffer[0] == 'Y')
1107 terminate = TRUE;
1110 else
1112 terminate = TRUE;
1115 if(terminate)
1117 if(RemoveSashimiResource(sr) == OK)
1119 Printf("Sashimi removed.\n");
1120 done = TRUE;
1125 while(NOT done);
1127 RemovePatches();
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)
1141 UBYTE name[256];
1143 Printf("Enter name to save the buffer, or hit [Return] to cancel: ");
1144 Flush(Output());
1146 name[0] = '\0';
1148 if(FGets(Input(),name,sizeof(name)-1) != NULL)
1150 LONG error;
1151 int i;
1153 for(i = strlen(name)-1 ; i >= 0 ; i--)
1155 if(name[i] == '\n')
1156 name[i] = '\0';
1159 error = SaveBuffer(name,sr,MODE_Regular);
1160 if(error == OK)
1161 Printf("Sashimi buffer saved as \"%s\".\n",name);
1162 else
1163 PrintFault(error,name);
1167 FreeSashimiResource(sr);
1168 sr = NULL;
1171 result = RETURN_OK;
1174 /* Close the resource, if we opened it. */
1175 if(opened)
1176 CloseSashimiResource(sr);
1178 /* Remove and free the resource if we added it. */
1179 if(added)
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)
1204 Close(newOutput);
1206 if(oldConsoleTask != NULL)
1207 SetConsoleTask(oldConsoleTask);
1209 if(newInput != ZERO)
1210 Close(newInput);
1213 FreeArgs(rdargs);
1215 else
1217 PrintFault(IoErr(),"Sashimi");
1219 result = RETURN_ERROR;
1223 return(result);